fix(skill): pin packaged commands to the shipping package version
The generated skill rewrote `rea-agents@latest` to the version it ships with, so a pinned install no longer needs a local edit that `doctor --skill` reports as stale. Co-Authored-By: OpenCode <opencode@opencode.ai>
This commit is contained in:
1 parent
1ac8389c5c
commit
2793672ee2
3 files changed
+42
-7
No files matched your search
@@ -16,8 +16,12 @@ const check = arguments_.has("--check");
|
||||
const current = (
|
||||
await readFile(join(sourceRoot, "SKILL.md"), "utf8")
|
||||
).replaceAll("\r\n", "\n");
|
||||
const cacheBust = String(Date.now());
|
||||
const { CATALOG_IDENTITY } = await import(
|
||||
`${pathToFileURL(join(root, "dist/catalogIdentity.js")).href}?${String(Date.now())}`
|
||||
`${pathToFileURL(join(root, "dist/catalogIdentity.js")).href}?${cacheBust}`
|
||||
);
|
||||
const { PACKAGE_METADATA } = await import(
|
||||
`${pathToFileURL(join(root, "dist/generatedPackageMetadata.js")).href}?${cacheBust}`
|
||||
);
|
||||
if (/^\s{2}(?:tool_count|catalog_digest):/mu.test(current))
|
||||
throw new Error(
|
||||
@@ -26,10 +30,15 @@ if (/^\s{2}(?:tool_count|catalog_digest):/mu.test(current))
|
||||
const versionLine = /^ {2}version: "[^"\r\n]+"$/mu;
|
||||
if (!versionLine.test(current))
|
||||
throw new Error("Missing authored skill version");
|
||||
const source = current.replace(
|
||||
versionLine,
|
||||
`$&\n tool_count: ${String(CATALOG_IDENTITY.counts.mcp_tools)}`,
|
||||
);
|
||||
// A shipped skill must run the version it ships with, not whatever `@latest` resolves to.
|
||||
const latestSpecifier = `${PACKAGE_METADATA.name}@latest`;
|
||||
const pinnedSpecifier = `${PACKAGE_METADATA.name}@${PACKAGE_METADATA.version}`;
|
||||
const source = current
|
||||
.replace(
|
||||
versionLine,
|
||||
`$&\n tool_count: ${String(CATALOG_IDENTITY.counts.mcp_tools)}`,
|
||||
)
|
||||
.replaceAll(latestSpecifier, pinnedSpecifier);
|
||||
const paths = await filePaths(sourceRoot);
|
||||
// Rebuild this owned output directory so removed references cannot survive a build.
|
||||
if (!check) await rm(outputRoot, { recursive: true, force: true });
|
||||
|
||||
@@ -100,7 +100,7 @@ describe("dependency install freshness", () => {
|
||||
it("checks installed dependencies before restoring a cached build", async () => {
|
||||
const root = await createBuildCacheFixture();
|
||||
const seeded = await runNpm(root, ["run", "build:cached"]);
|
||||
expect(seeded.status, seeded.stderr).toBe(0);
|
||||
expect(seeded.status, `${seeded.stdout}${seeded.stderr}`).toBe(0);
|
||||
|
||||
const rootLock = asRecord(
|
||||
JSON.parse(await readFile(join(root, "package-lock.json"), "utf8")),
|
||||
@@ -189,7 +189,13 @@ const createBuildCacheFixture = async (): Promise<string> => {
|
||||
);
|
||||
await writeFile(
|
||||
join(root, "scripts/cache-fixture-build.mjs"),
|
||||
'import { mkdir, writeFile } from "node:fs/promises"; await mkdir("dist", { recursive: true }); await writeFile("dist/cache-fixture.js", "built"); await writeFile("dist/catalogIdentity.js", "export const CATALOG_IDENTITY = { counts: { mcp_tools: 1 } };\\n");\n',
|
||||
`import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
const { name, version } = JSON.parse(await readFile("package.json", "utf8"));
|
||||
await mkdir("dist", { recursive: true });
|
||||
await writeFile("dist/cache-fixture.js", "built");
|
||||
await writeFile("dist/catalogIdentity.js", "export const CATALOG_IDENTITY = { counts: { mcp_tools: 1 } };\\n");
|
||||
await writeFile("dist/generatedPackageMetadata.js", "export const PACKAGE_METADATA = " + JSON.stringify({ name, version }) + ";\\n");
|
||||
`,
|
||||
);
|
||||
await createNodeModulesLinks(root);
|
||||
await writeFile(
|
||||
|
||||
@@ -26,6 +26,10 @@ async function fixture(eol = "\n") {
|
||||
await mkdir(join(sourceRoot, "references"), { recursive: true });
|
||||
await mkdir(join(root, "dist"));
|
||||
await writeFile(join(root, "package.json"), '{"type":"module"}\n');
|
||||
await writeFile(
|
||||
join(root, "dist/generatedPackageMetadata.js"),
|
||||
'export const PACKAGE_METADATA = { name: "rea-agents", version: "6.2.0" };\n',
|
||||
);
|
||||
await writeFile(join(sourceRoot, "SKILL.md"), authored.replaceAll("\n", eol));
|
||||
await writeFile(
|
||||
join(sourceRoot, "references/guide.md"),
|
||||
@@ -111,6 +115,22 @@ it("rejects missing, stale, and extra packaged references and removes deleted so
|
||||
await f.generate("--check");
|
||||
});
|
||||
|
||||
it("pins authored `@latest` commands to the packaged version", async () => {
|
||||
const f = await fixture();
|
||||
await writeFile(
|
||||
join(f.sourceRoot, "SKILL.md"),
|
||||
authored.replace(
|
||||
"Inspect the caller-selected artifact.",
|
||||
"Run `npx -y rea-agents@latest doctor --json` first.",
|
||||
),
|
||||
);
|
||||
await f.generate();
|
||||
const generated = await readFile(join(f.outputRoot, "SKILL.md"), "utf8");
|
||||
expect(generated).toContain("npx -y rea-agents@6.2.0 doctor --json");
|
||||
expect(generated).not.toContain("rea-agents@latest");
|
||||
await f.generate("--check");
|
||||
});
|
||||
|
||||
it("rejects catalog-dependent metadata in the authored source", async () => {
|
||||
const f = await fixture();
|
||||
await writeFile(
|
||||
|
||||
Reference in new issue
Block a user