import { assert, assertEquals, assertRejects, assertStringIncludes } from "@std/assert"; import { BACKGROUND_CONTEXT as context } from "@earendil-works/chord/context"; import { getOrThrow } from "@earendil-works/pi-durable/env"; import { rootedEnvironment, testExtension } from "@berry/api/testing.ts"; import { tempDir } from "@berry/util"; import { skillsExtension } from "./mod.ts"; import { activeDirectory, hostEnvironment, targetEnvironment, writeSkill } from "./testing.ts"; Deno.test("project skills require explicit loading or conversation-local trust", async () => { await using root = await tempDir(); const env = rootedEnvironment(root.path, { cwd: "/repo/src" }); getOrThrow(await env.createDir(env.cwd, { recursive: true }, context)); getOrThrow(await env.writeFile("/repo/.jj/repo", "", context)); await writeSkill(env, "/repo/.agents/skills", "release", "Use the release checklist."); const ext = testExtension(skillsExtension(hostEnvironment(root.path)), { env }); assert(!(await ext.prompt()).includes("release")); assertStringIncludes(await ext.command("skills") as string, "explicit loading only"); await assertRejects(() => ext.call("load_skill", { name: "release" }), Error, "not available"); await ext.command("skill", "release"); assertStringIncludes(await ext.prompt(), "Use the release checklist."); await ext.command("unskill", "release"); assert(!(await ext.prompt()).includes("Use the release checklist.")); await ext.command("skills", "trust"); assertStringIncludes(await ext.prompt(), '"name":"release"'); await ext.call("load_skill", { name: "release" }); await ext.command("skills", "untrust"); assertStringIncludes(await ext.prompt(), "Use the release checklist."); await assertRejects(() => ext.call("load_skill", { name: "release" }), Error, "not available"); assertEquals(ext.messages, []); }); Deno.test("activation preserves an exact snapshot, reload replaces it, and resources stay on demand", async () => { await using root = await tempDir(); const env = rootedEnvironment(root.path); const body = "# Review\nHuman prose: keep this spacing.\nRead references/checklist.md.\nRun scripts/check.sh when needed.\n"; const path = await writeSkill(env, "/home/.agents/skills", "review", body); getOrThrow( await env.writeFile( "/home/.agents/skills/review/references/checklist.md", "resource-only text", context, ), ); const ext = testExtension(skillsExtension(hostEnvironment(root.path)), { env }); const acknowledgment = await ext.call("load_skill", { name: "review" }) as string; assert(!acknowledgment.includes(body)); const prompt = await ext.prompt(); assertStringIncludes(prompt, body); assertStringIncludes(prompt, "/home/.agents/skills/review"); assert(!prompt.includes("resource-only text")); await writeSkill(env, "/home/.agents/skills", "review", "Updated instructions."); assertStringIncludes(await ext.prompt(), body); await ext.call("load_skill", { name: "review" }); const reloaded = await ext.prompt(); assert(!reloaded.includes(body)); assertEquals(reloaded.split("Updated instructions.").length - 1, 1); getOrThrow(await env.remove(path, {}, context)); assertStringIncludes(await ext.prompt(), "Updated instructions."); await ext.command("unskill", "review"); assertEquals(await ext.prompt(), ""); }); Deno.test("trust and active resource paths do not transfer to a different repository or machine", async () => { await using root = await tempDir(); const env = rootedEnvironment(root.path, { cwd: "/first" }); getOrThrow(await env.writeFile("/first/.git", "", context)); getOrThrow(await env.writeFile("/second/.git", "", context)); await writeSkill(env, "/first/.agents/skills", "first", "First repository workflow."); await writeSkill(env, "/second/.agents/skills", "second", "Second repository workflow."); const ext = testExtension(skillsExtension(hostEnvironment(root.path)), { env }); await ext.command("skills", "trust"); await ext.call("load_skill", { name: "first" }); env.cwd = "/second"; assertStringIncludes(await ext.prompt(), "First repository workflow."); assert(!(await ext.prompt()).includes('"name":"second"')); await assertRejects(() => ext.call("load_skill", { name: "second" }), Error, "not available"); const other = Object.assign(rootedEnvironment(root.path, { cwd: "/first" }), { name: "other" }); // replay the same history against another machine, as an environment rebind does const first = ext.state.active[0]; assert(first.scope !== "host"); const events = [ { type: "trust" as const, environment: env.name, root: "/first", trusted: true }, { type: "load" as const, skill: first }, ]; const rebound = testExtension(skillsExtension(hostEnvironment(root.path)), { env: other, events, }); assertEquals(await rebound.prompt(), ""); await assertRejects(() => rebound.call("load_skill", { name: "first" }), Error, "not available"); assertStringIncludes(await rebound.command("skills") as string, "paused"); }); Deno.test("parallel loads enforce the aggregate budget without evicting existing skills", async () => { await using root = await tempDir(); const env = rootedEnvironment(root.path); for (const name of ["first", "second", "third"]) { await writeSkill(env, "/home/.agents/skills", name, `${name}\n${"x".repeat(50 * 1024)}`); } const ext = testExtension(skillsExtension(hostEnvironment(root.path)), { env }); const results = await Promise.allSettled( ["first", "second", "third"].map((name) => ext.call("load_skill", { name })), ); assertEquals(results.map(({ status }) => status), ["fulfilled", "fulfilled", "rejected"]); if (results[2].status === "rejected") assertStringIncludes(results[2].reason.message, "Unload"); assertEquals(ext.state.active.map(({ name }) => name), ["first", "second"]); await ext.call("load_skill", { name: "second" }); await ext.command("unskill", "first"); await ext.call("load_skill", { name: "third" }); assertEquals(ext.state.active.map(({ name }) => name), ["second", "third"]); }); Deno.test("host activations follow new environments with their pinned resource version until reloaded", async () => { await using home = await tempDir(); await using target = await tempDir(); await using other = await tempDir(); const host = hostEnvironment(home.path); const main = await writeSkill( host, `${home.path}/.config/berry/skills`, "release", "Read the release checklist.", ); const source = main.slice(0, -"/SKILL.md".length); getOrThrow( await host.writeFile(`${source}/references/checklist.txt`, "original checklist", context), ); const env = targetEnvironment(target.path); const ext = testExtension(skillsExtension(host), { env }); assert(!(await ext.prompt()).includes("original checklist")); await ext.call("load_skill", { name: "release" }); const snapshot = ext.state.active[0]; assert(snapshot.scope === "host"); const directory = await activeDirectory(env, await ext.prompt()); assertEquals( getOrThrow(await env.readTextFile(`${directory}/references/checklist.txt`, context)), "original checklist", ); getOrThrow( await host.writeFile(`${source}/references/checklist.txt`, "updated checklist", context), ); const next = Object.assign(targetEnvironment(other.path), { name: "other" }); const replayed = testExtension(skillsExtension(hostEnvironment(home.path)), { env: next, events: [{ type: "loadHost", skill: snapshot }], }); const prompt = await replayed.prompt(); assertStringIncludes(prompt, "Read the release checklist."); const historical = await activeDirectory(next, prompt); assertEquals( getOrThrow(await next.readTextFile(`${historical}/references/checklist.txt`, context)), "original checklist", ); await replayed.call("load_skill", { name: "release" }); const updated = await activeDirectory(next, await replayed.prompt()); assertEquals( getOrThrow(await next.readTextFile(`${updated}/references/checklist.txt`, context)), "updated checklist", ); }); Deno.test("a failed activation does not poison another queued load", async () => { await using root = await tempDir(); const env = rootedEnvironment(root.path); await writeSkill(env, "/home/.agents/skills", "valid", "Valid workflow."); const ext = testExtension(skillsExtension(hostEnvironment(root.path)), { env }); const results = await Promise.allSettled([ ext.call("load_skill", { name: "missing" }), ext.call("load_skill", { name: "valid" }), ]); assertEquals(results.map(({ status }) => status), ["rejected", "fulfilled"]); assertStringIncludes(await ext.prompt(), "Valid workflow."); });