Files
wehub-resource-sync 85453da49f
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:58:35 +08:00

170 lines
6.7 KiB
TypeScript

// Generate (or verify) packages/cli/src/utils/agentDirs.generated.ts — the
// home-relative GLOBAL skills directory for every agent the upstream
// vercel-labs/skills CLI knows about, plus a marker dir that means "this agent
// is installed on this machine".
//
// bun run --cwd packages/cli gen:agent-dirs # write/update (fetches upstream)
// bun run --cwd packages/cli gen:agent-dirs --check # verify only (CI / pre-commit)
// bun packages/cli/scripts/sync-agent-dirs.ts --src <path/to/agents.ts> # offline
//
// Why generated, not hand-maintained: `skills add --global` installs into the
// per-agent dirs encoded in upstream's `src/agents.ts` (~70 agents). We mirror
// the canonical store into those same dirs, so the list must track upstream. The
// `skills` npm package exports nothing importable (CLI-only, bundled dist), so
// we parse the source at a PINNED tag and commit the result — deterministic at
// runtime, no network at install time. Bump SKILLS_REF and re-run on upgrade.
import { readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
// Pin to the upstream release whose dir layout we install against. Bump this
// (and re-run) when the bundled `skills` version moves.
const SKILLS_REPO = "vercel-labs/skills";
const SKILLS_REF = "v1.5.13";
const AGENTS_TS_URL = `https://raw.githubusercontent.com/${SKILLS_REPO}/${SKILLS_REF}/src/agents.ts`;
const here = dirname(fileURLToPath(import.meta.url));
const outPath = join(here, "..", "src", "utils", "agentDirs.generated.ts");
const isCheck = process.argv.includes("--check");
const srcFlag = process.argv.indexOf("--src");
const srcPath = srcFlag !== -1 ? process.argv[srcFlag + 1] : undefined;
// The base directories agents.ts builds globalSkillsDir from. Each is an env
// override with a documented default — the mirror resolves them at runtime so a
// machine with XDG_CONFIG_HOME / CODEX_HOME / CLAUDE_CONFIG_DIR set lands in the
// same place the agent actually reads. We store the base NAME + suffix here
// rather than a frozen path so that resolution stays faithful to upstream.
const BASE_VARS = [
"home",
"configHome",
"codexHome",
"claudeHome",
"vibeHome",
"hermesHome",
"autohandHome",
] as const;
type BaseVar = (typeof BASE_VARS)[number];
interface AgentGlobalDir {
agent: string;
base: BaseVar;
sub: string;
}
function posixJoin(parts: string[]): string {
return parts
.flatMap((p) => p.split("/"))
.filter((s) => s && s !== ".")
.join("/");
}
/** Resolve a globalSkillsDir expression to { base, sub }, or null if none. */
function resolveGlobalExpr(expr: string): { base: BaseVar; sub: string } | null {
const e = expr.trim();
if (e === "undefined") return null; // agent defines no global skills dir
// openclaw's helper falls back to ~/.openclaw/skills when no variant is present.
if (e.startsWith("getOpenClawGlobalSkillsDir")) return { base: "home", sub: ".openclaw/skills" };
const m = e.match(/^join\(([\s\S]+)\)$/);
if (!m) throw new Error(`Unparseable globalSkillsDir: ${expr}`);
const args = m[1]!.split(",").map((a) => a.trim());
const first = args[0]!;
if (!(BASE_VARS as readonly string[]).includes(first)) {
throw new Error(`globalSkillsDir does not start with a known base var: ${expr}`);
}
const segs: string[] = [];
for (const raw of args.slice(1)) {
const lit = raw.match(/^['"]([^'"]*)['"]$/);
if (!lit) throw new Error(`Non-literal segment "${raw}" in globalSkillsDir: ${expr}`);
segs.push(lit[1]!);
}
return { base: first as BaseVar, sub: posixJoin(segs) };
}
function parseAgents(source: string): AgentGlobalDir[] {
const re = /^ {2}(?:"([a-z0-9-]+)"|'([a-z0-9-]+)'|([a-z0-9-]+)):\s*\{/gm;
const blocks: { key: string; pos: number }[] = [];
let m: RegExpExecArray | null;
while ((m = re.exec(source))) blocks.push({ key: m[1] || m[2] || m[3]!, pos: m.index });
if (blocks.length < 60) {
throw new Error(`Parsed only ${blocks.length} agent blocks — upstream layout likely changed`);
}
const out: AgentGlobalDir[] = [];
for (let i = 0; i < blocks.length; i++) {
const seg = source.slice(blocks[i]!.pos, blocks[i + 1] ? blocks[i + 1]!.pos : source.length);
const gd = seg.match(/globalSkillsDir:\s*([\s\S]+?),\n/);
const expr = gd ? gd[1]!.trim().replace(/\s+/g, " ") : "undefined";
const resolved = resolveGlobalExpr(expr);
if (resolved === null) continue; // no global dir (e.g. eve, promptscript)
out.push({ agent: blocks[i]!.key, base: resolved.base, sub: resolved.sub });
}
return out;
}
function render(rows: AgentGlobalDir[]): string {
const lines = rows.map(
(r) =>
` { agent: ${JSON.stringify(r.agent)}, base: ${JSON.stringify(r.base)}, sub: ${JSON.stringify(r.sub)} },`,
);
return `// @generated by packages/cli/scripts/sync-agent-dirs.ts — DO NOT EDIT.
// Source: ${SKILLS_REPO}@${SKILLS_REF} (src/agents.ts). Regenerate with:
// bun run --cwd packages/cli gen:agent-dirs
//
// Each entry is one agent the upstream \`skills\` CLI installs to. The agent's
// GLOBAL skills directory is \`join(<base>, <sub>)\`, where \`base\` is one of the
// env-overridable home dirs below (resolved at runtime by skillsMirror.ts, so
// XDG_CONFIG_HOME / CODEX_HOME / CLAUDE_CONFIG_DIR are honored). Agents with no
// global skills dir upstream (eve, promptscript) are omitted.
/** Env-overridable base dirs, matching upstream agents.ts. */
export type AgentDirBase =
${BASE_VARS.map((b) => ` | ${JSON.stringify(b)}`).join("\n")};
export interface AgentGlobalDir {
/** Upstream agent key. */
agent: string;
/** Base directory the global skills dir is rooted at. */
base: AgentDirBase;
/** POSIX suffix joined onto the resolved base. */
sub: string;
}
export const AGENT_GLOBAL_DIRS: readonly AgentGlobalDir[] = [
${lines.join("\n")}
];
`;
}
async function loadAgentsSource(): Promise<string> {
if (srcPath) return readFileSync(srcPath, "utf8");
const res = await fetch(AGENTS_TS_URL);
if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${AGENTS_TS_URL}`);
return res.text();
}
const source = await loadAgentsSource();
const rows = parseAgents(source);
const next = render(rows);
if (isCheck) {
let current = "";
try {
current = readFileSync(outPath, "utf8");
} catch {
/* missing → drift */
}
if (current !== next) {
console.error(
`agentDirs.generated.ts is out of date (parsed ${rows.length} agents from ${SKILLS_REPO}@${SKILLS_REF}).\n` +
`Run: bun run --cwd packages/cli gen:agent-dirs`,
);
process.exit(1);
}
console.log(`agentDirs.generated.ts is up to date (${rows.length} agents).`);
} else {
writeFileSync(outPath, next, "utf8");
console.log(`Wrote ${rows.length} agents → ${outPath}`);
}