feat(02-04): add shared skill symlink helper and wire orchestration-to-worker pipeline

- Add ManagedSkillRef type to adapter-utils for cross-package use
- Add createManagedSkillSymlinks() with Windows junction support (D-13)
- Add managedSkills field to worker RunJob and connector config
- Add listRuntimeSkillEntries dependency to orchestration service
- Wire SkillService lazy init in service-graph for runtime skill resolution
- Include prerequisite skill system files from plans 02-01/02-02
This commit is contained in:
ZacharyZhang-NY committed 2026-03-26 00:46:19 -04:00
1 parent c1de05a7f1
commit 3fb9ab86d9
12 files changed
+1867 -4

No files matched your search

@@ -2,6 +2,7 @@ import { spawn, type ChildProcess } from "node:child_process";
import { constants as fsConstants, promises as fs } from "node:fs";
import path from "node:path";
import { StringDecoder } from "node:string_decoder";
import type { ManagedSkillRef } from "./types.js";
/**
* Decode a Buffer as GBK (CP936). Used as a fallback when UTF-8 decoding
@@ -466,3 +467,34 @@ export async function runChildProcess(
.catch(reject);
});
}
/**
* Create symlinks for managed skills in the target directory.
* Per D-13: uses 'junction' type on Windows to avoid Developer Mode requirement.
* Falls back gracefully -- skill injection is best-effort and should not block runs.
*/
export async function createManagedSkillSymlinks(
managedSkills: ManagedSkillRef[],
targetDir: string,
onLog: (stream: "stdout" | "stderr", chunk: string) => Promise<void>,
): Promise<void> {
await fs.mkdir(targetDir, { recursive: true });
const symlinkType = process.platform === "win32" ? ("junction" as const) : undefined;
for (const skill of managedSkills) {
const target = path.join(targetDir, skill.runtimeName);
const existing = await fs.lstat(target).catch(() => null);
if (existing) {
// Remove stale symlink from previous run
await fs.rm(target, { recursive: true, force: true }).catch(() => {});
}
try {
await fs.symlink(skill.sourcePath, target, symlinkType);
await onLog("stderr", `[agent-company] Injected managed skill "${skill.runtimeName}"\n`);
} catch (err) {
await onLog(
"stderr",
`[agent-company] Failed to inject skill "${skill.runtimeName}": ${err instanceof Error ? err.message : String(err)}\n`,
);
}
}
}