148 lines
3.8 KiB
TypeScript
148 lines
3.8 KiB
TypeScript
import type { GatewayBrowserClient } from "../gateway";
|
|
import type { SkillStatusReport } from "../types";
|
|
|
|
export type SkillsState = {
|
|
client: GatewayBrowserClient | null;
|
|
connected: boolean;
|
|
skillsLoading: boolean;
|
|
skillsReport: SkillStatusReport | null;
|
|
skillsError: string | null;
|
|
skillsBusyKey: string | null;
|
|
skillEdits: Record<string, string>;
|
|
skillMessages: SkillMessageMap;
|
|
};
|
|
|
|
export type SkillMessage = {
|
|
kind: "success" | "error";
|
|
message: string;
|
|
};
|
|
|
|
export type SkillMessageMap = Record<string, SkillMessage>;
|
|
|
|
type LoadSkillsOptions = {
|
|
clearMessages?: boolean;
|
|
};
|
|
|
|
function setSkillMessage(state: SkillsState, key: string, message?: SkillMessage) {
|
|
if (!key.trim()) return;
|
|
const next = { ...state.skillMessages };
|
|
if (message) next[key] = message;
|
|
else delete next[key];
|
|
state.skillMessages = next;
|
|
}
|
|
|
|
function getErrorMessage(err: unknown) {
|
|
if (err instanceof Error) return err.message;
|
|
return String(err);
|
|
}
|
|
|
|
export async function loadSkills(state: SkillsState, options?: LoadSkillsOptions) {
|
|
if (options?.clearMessages && Object.keys(state.skillMessages).length > 0) {
|
|
state.skillMessages = {};
|
|
}
|
|
if (!state.client || !state.connected) return;
|
|
if (state.skillsLoading) return;
|
|
state.skillsLoading = true;
|
|
state.skillsError = null;
|
|
try {
|
|
const res = (await state.client.request("skills.status", {})) as
|
|
| SkillStatusReport
|
|
| undefined;
|
|
if (res) state.skillsReport = res;
|
|
} catch (err) {
|
|
state.skillsError = getErrorMessage(err);
|
|
} finally {
|
|
state.skillsLoading = false;
|
|
}
|
|
}
|
|
|
|
export function updateSkillEdit(
|
|
state: SkillsState,
|
|
skillKey: string,
|
|
value: string,
|
|
) {
|
|
state.skillEdits = { ...state.skillEdits, [skillKey]: value };
|
|
}
|
|
|
|
export async function updateSkillEnabled(
|
|
state: SkillsState,
|
|
skillKey: string,
|
|
enabled: boolean,
|
|
) {
|
|
if (!state.client || !state.connected) return;
|
|
state.skillsBusyKey = skillKey;
|
|
state.skillsError = null;
|
|
try {
|
|
await state.client.request("skills.update", { skillKey, enabled });
|
|
await loadSkills(state);
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "success",
|
|
message: enabled ? "Skill enabled" : "Skill disabled",
|
|
});
|
|
} catch (err) {
|
|
const message = getErrorMessage(err);
|
|
state.skillsError = message;
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "error",
|
|
message,
|
|
});
|
|
} finally {
|
|
state.skillsBusyKey = null;
|
|
}
|
|
}
|
|
|
|
export async function saveSkillApiKey(state: SkillsState, skillKey: string) {
|
|
if (!state.client || !state.connected) return;
|
|
state.skillsBusyKey = skillKey;
|
|
state.skillsError = null;
|
|
try {
|
|
const apiKey = state.skillEdits[skillKey] ?? "";
|
|
await state.client.request("skills.update", { skillKey, apiKey });
|
|
await loadSkills(state);
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "success",
|
|
message: "API key saved",
|
|
});
|
|
} catch (err) {
|
|
const message = getErrorMessage(err);
|
|
state.skillsError = message;
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "error",
|
|
message,
|
|
});
|
|
} finally {
|
|
state.skillsBusyKey = null;
|
|
}
|
|
}
|
|
|
|
export async function installSkill(
|
|
state: SkillsState,
|
|
skillKey: string,
|
|
name: string,
|
|
installId: string,
|
|
) {
|
|
if (!state.client || !state.connected) return;
|
|
state.skillsBusyKey = skillKey;
|
|
state.skillsError = null;
|
|
try {
|
|
const result = (await state.client.request("skills.install", {
|
|
name,
|
|
installId,
|
|
timeoutMs: 120000,
|
|
})) as { ok?: boolean; message?: string };
|
|
await loadSkills(state);
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "success",
|
|
message: result?.message ?? "Installed",
|
|
});
|
|
} catch (err) {
|
|
const message = getErrorMessage(err);
|
|
state.skillsError = message;
|
|
setSkillMessage(state, skillKey, {
|
|
kind: "error",
|
|
message,
|
|
});
|
|
} finally {
|
|
state.skillsBusyKey = null;
|
|
}
|
|
}
|