fix(x): skill catalog advertises the post-reorg path; legacy path stays an alias

The bundled-skill CATALOG_PREFIX still pointed at the deleted
src/application/assistant/skills tree, so the system prompt and the
loadSkill example advertised paths that no longer exist — while the
real post-reorg path (src/runtime/assembly/skills) was NOT a
resolvable alias, so a model referencing the actual source tree got
'Skill not found'.

The new path is now canonical in the catalog and tool description;
the old prefix is kept as a loadSkill alias because agent snapshots
baked before the reorg still carry it. Regression test pins both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ramnique Singh 2026-07-10 16:17:07 +05:30
parent a3d2ddf34c
commit 24fb0d38e5
3 changed files with 21 additions and 4 deletions

View file

@ -103,7 +103,7 @@ describe("skills index (disk skill merge layer)", () => {
const skills = await loadSkillsIndex();
const resolved = skills.resolveSkill("meeting-prep");
expect(resolved?.catalogPath).toBe("src/application/assistant/skills/meeting-prep/skill.ts");
expect(resolved?.catalogPath).toBe("src/runtime/assembly/skills/meeting-prep/skill.ts");
expect(resolved?.content).not.toContain("DISK CONTENT MARKER");
const catalog = skills.buildSkillCatalog();
@ -178,7 +178,7 @@ describe("capability activation boundary", () => {
summary: "a genuine model-activated skill",
content: "guidance",
tools: ["file-readText"],
catalogPath: "src/application/assistant/skills/real-skill/skill.ts",
catalogPath: "src/runtime/assembly/skills/real-skill/skill.ts",
};
const mixed = [model, eager];
@ -199,6 +199,18 @@ describe("capability activation boundary", () => {
expect(catalog).toContain(id);
}
});
it("resolves bundled skills by the advertised path and by the pre-reorg legacy path", async () => {
// The catalog advertises the post-reorg source path; agent snapshots baked
// before the move still reference the old application/assistant prefix.
// Both must resolve to the same skill.
const { resolveSkill } = await loadSkillsIndex();
const advertised = resolveSkill("src/runtime/assembly/skills/meeting-prep/skill.ts");
const legacy = resolveSkill("src/application/assistant/skills/meeting-prep/skill.ts");
expect(advertised?.id).toBe("meeting-prep");
expect(legacy?.id).toBe("meeting-prep");
expect(legacy?.content).toBe(advertised?.content);
});
});
describe("availability (catalog visibility)", () => {

View file

@ -31,7 +31,10 @@ import appsSkill from "./apps/skill.js";
import slackSkill from "./slack/skill.js";
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
const CATALOG_PREFIX = "src/application/assistant/skills";
const CATALOG_PREFIX = "src/runtime/assembly/skills";
// Pre-reorg home of the bundled skills. Agent snapshots baked before the move
// carry loadSkill references under this prefix, so it stays a resolvable alias.
const LEGACY_CATALOG_PREFIX = "src/application/assistant/skills";
// console.log(liveNoteSkill);
@ -355,6 +358,8 @@ for (const entry of bundledEntries) {
`skills/${entry.id}/skill.js`,
`${CATALOG_PREFIX}/${entry.id}/skill.ts`,
`${CATALOG_PREFIX}/${entry.id}/skill.js`,
`${LEGACY_CATALOG_PREFIX}/${entry.id}/skill.ts`,
`${LEGACY_CATALOG_PREFIX}/${entry.id}/skill.js`,
absoluteTs,
absoluteJs,
];

View file

@ -39,7 +39,7 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
loadSkill: {
description: "Load a Rowboat skill definition into context by fetching its guidance string",
inputSchema: z.object({
skillName: z.string().describe("Skill identifier or path (e.g., 'workflow-run-ops' or 'src/application/assistant/skills/workflow-run-ops/skill.ts')"),
skillName: z.string().describe("Skill identifier or path (e.g., 'workflow-run-ops' or 'src/runtime/assembly/skills/workflow-run-ops/skill.ts')"),
}),
execute: async ({ skillName }: { skillName: string }) => {
const resolved = resolveSkill(skillName);