feat: plugin system + voice-call
This commit is contained in:
@@ -13,6 +13,19 @@ import { CONFIG_DIR, resolveUserPath } from "../utils.js";
|
||||
|
||||
const fsp = fs.promises;
|
||||
|
||||
const SKILLS_SYNC_QUEUE = new Map<string, Promise<unknown>>();
|
||||
|
||||
async function serializeByKey<T>(key: string, task: () => Promise<T>) {
|
||||
const prev = SKILLS_SYNC_QUEUE.get(key) ?? Promise.resolve();
|
||||
const next = prev.then(task, task);
|
||||
SKILLS_SYNC_QUEUE.set(key, next);
|
||||
try {
|
||||
return await next;
|
||||
} finally {
|
||||
if (SKILLS_SYNC_QUEUE.get(key) === next) SKILLS_SYNC_QUEUE.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
export type SkillInstallSpec = {
|
||||
id?: string;
|
||||
kind: "brew" | "node" | "go" | "uv";
|
||||
@@ -649,29 +662,35 @@ export async function syncSkillsToWorkspace(params: {
|
||||
const sourceDir = resolveUserPath(params.sourceWorkspaceDir);
|
||||
const targetDir = resolveUserPath(params.targetWorkspaceDir);
|
||||
if (sourceDir === targetDir) return;
|
||||
const targetSkillsDir = path.join(targetDir, "skills");
|
||||
|
||||
const entries = loadSkillEntries(sourceDir, {
|
||||
config: params.config,
|
||||
managedSkillsDir: params.managedSkillsDir,
|
||||
bundledSkillsDir: params.bundledSkillsDir,
|
||||
});
|
||||
await serializeByKey(`syncSkills:${targetDir}`, async () => {
|
||||
const targetSkillsDir = path.join(targetDir, "skills");
|
||||
|
||||
await fsp.rm(targetSkillsDir, { recursive: true, force: true });
|
||||
await fsp.mkdir(targetSkillsDir, { recursive: true });
|
||||
const entries = loadSkillEntries(sourceDir, {
|
||||
config: params.config,
|
||||
managedSkillsDir: params.managedSkillsDir,
|
||||
bundledSkillsDir: params.bundledSkillsDir,
|
||||
});
|
||||
|
||||
for (const entry of entries) {
|
||||
const dest = path.join(targetSkillsDir, entry.skill.name);
|
||||
try {
|
||||
await fsp.cp(entry.skill.baseDir, dest, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : JSON.stringify(error);
|
||||
console.warn(
|
||||
`[skills] Failed to copy ${entry.skill.name} to sandbox: ${message}`,
|
||||
);
|
||||
await fsp.rm(targetSkillsDir, { recursive: true, force: true });
|
||||
await fsp.mkdir(targetSkillsDir, { recursive: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const dest = path.join(targetSkillsDir, entry.skill.name);
|
||||
try {
|
||||
await fsp.cp(entry.skill.baseDir, dest, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : JSON.stringify(error);
|
||||
console.warn(
|
||||
`[skills] Failed to copy ${entry.skill.name} to sandbox: ${message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function filterWorkspaceSkillEntries(
|
||||
|
||||
Reference in New Issue
Block a user