char-slop/berry
multipurpose self-modifiable agentic harness
git clone https://git.t4t.associates/char-slop/berry
a4e772a
main
1import { assert , assertEquals , assertRejects , assertStringIncludes } from "@std/assert" ; 2import { BACKGROUND_CONTEXT as context } from "@earendil-works/chord/context" ; 3import { getOrThrow } from "@earendil-works/pi-durable/env" ; 4import { rootedEnvironment } from "@berry/api/testing.ts" ; 5import { tempDir } from "@berry/util" ; 6import { discover , MAX_SKILL_BYTES , parseSkill , readSkill } from "./catalog.ts" ; 7import { hostEnvironment , writeSkill } from "./testing.ts" ; 8 9Deno . test ( "discovery combines target project skills, host XDG skills, and target user skills in precedence order" , async () => { 10await usingroot = await tempDir (); 11const env = rootedEnvironment ( root . path , { 12cwd :"/repo/packages/app" , 13variables :{ XDG_CONFIG_HOME :"/settings" }, 14}); 15const host = hostEnvironment ( root . path , { XDG_CONFIG_HOME :` ${ root . path } /host-settings` }); 16getOrThrow ( await env . writeFile ( "/repo/.git" , "gitdir: elsewhere" , context )); 17await writeSkill ( env , "/repo/packages/app/.agents/skills" , "review" , "nearest" ); 18await writeSkill ( env , "/repo/.agents/skills" , "review" , "repository" ); 19await writeSkill ( host , ` ${ root . path } /host-settings/berry/skills` , "review" , "berry host" ); 20await writeSkill ( host , ` ${ root . path } /host-settings/berry/skills` , "release" , "berry release" ); 21await writeSkill ( env , "/settings/berry/skills" , "remote-only" , "ignored target configuration" ); 22await writeSkill ( env , "/home/.agents/skills" , "release" , "shared release" ); 23await writeSkill ( env , "/home/.agents/skills" , "pdf" , "shared pdf" ); 24await writeSkill ( env , "/.agents/skills" , "outside" , "unrelated ancestor" ); 25 26const catalog = await discover ( env , host , context ); 27assertEquals ( catalog . projectRoot , "/repo" ); 28assertEquals ( catalog . skills . map (({ name}) => name ), [ "review" , "release" , "pdf" ]); 29assertEquals ( catalog . skills [ 0 ]. directory , "/repo/packages/app/.agents/skills/review" ); 30assertEquals ( catalog . skills [ 1 ]. directory , ` ${ root . path } /host-settings/berry/skills/release` ); 31assertStringIncludes ( catalog . diagnostics . join ( "\n" ), "shadowed" ); 32 33const untrusted = await discover ( env , host , context , []); 34assertEquals ( untrusted . skills . find (({ name}) => name === "review" )?. scope , "host" ); 35assertEquals ( 36untrusted . skills . find (({ name}) => name === "review" )?. directory , 37` ${ root . path } /host-settings/berry/skills/review` , 38); 39}); 40 41Deno . test ( "outside a repository discovery stays at cwd and uses the host's default configuration" , async () => { 42await usingroot = await tempDir (); 43const env = rootedEnvironment ( root . path , { cwd :"/work/app" }); 44await writeSkill ( env , "/work/app/.agents/skills" , "here" , "local" ); 45await writeSkill ( env , "/work/.agents/skills" , "ancestor" , "unrelated" ); 46const host = hostEnvironment ( root . path ); 47await writeSkill ( host , ` ${ root . path } /.config/berry/skills` , "personal" , "personal" ); 48await writeSkill ( 49env , 50"/home/.config/berry/skills" , 51"remote-only" , 52"ignored target configuration" , 53); 54assertEquals (( await discover ( env , host , context )). skills . map (({ name}) => name ), [ 55"here" , 56"personal" , 57]); 58}); 59 60Deno . test ( "discovery deduplicates symlinks and keeps resource paths relative to the skill directory" , async () => { 61await usingroot = await tempDir (); 62const env = rootedEnvironment ( root . path , { cwd :"/repo" }); 63const location = await writeSkill ( env , "/repo/.agents/skills" , "review" , "linked instructions" ); 64await Deno . symlink ( 65` ${ root . path } /repo/.agents/skills/review` , 66` ${ root . path } /repo/.agents/skills/review-alias` , 67); 68getOrThrow ( await env . createDir ( "/home/.agents" , { recursive :true }, context )); 69await Deno . symlink ( ` ${ root . path } /repo/.agents/skills` , ` ${ root . path } /home/.agents/skills` ); 70const shared = "/repo/shared.md" ; 71getOrThrow ( await env . renameFile ( location , shared , context )); 72await Deno . symlink ( ` ${ root . path } ${ shared } ` , ` ${ root . path } ${ location } ` ); 73 74const catalog = await discover ( env , hostEnvironment ( root . path ), context ); 75assertEquals ( catalog . skills . length , 1 ); 76assertEquals ( catalog . skills [ 0 ]. directory , "/repo/.agents/skills/review" ); 77assert ( ! catalog . diagnostics . some (( line ) => line . includes ( "shadowed" ))); 78}); 79 80Deno . test ( "malformed and oversized skills produce diagnostics without hiding valid skills" , async () => { 81await usingroot = await tempDir (); 82const env = rootedEnvironment ( root . path , { cwd :"/repo" }); 83getOrThrow ( 84await env . writeFile ( "/repo/.agents/skills/broken/SKILL.md" , "---\nname: [\n---\n" , context ), 85); 86const oversized = await writeSkill ( 87env , 88"/repo/.agents/skills" , 89"huge" , 90"x" . repeat ( MAX_SKILL_BYTES ), 91); 92await writeSkill ( env , "/repo/.agents/skills" , "n" . repeat ( 65 ), "invalid name" ); 93await writeSkill ( env , "/repo/.agents/skills" , "valid" , "instructions" ); 94const catalog = await discover ( env , hostEnvironment ( root . path ), context ); 95assertEquals ( catalog . skills . map (({ name}) => name ), [ "valid" ]); 96assertStringIncludes ( catalog . diagnostics . join ( "\n" ), "broken/SKILL.md" ); 97assertStringIncludes ( catalog . diagnostics . join ( "\n" ), "exceeds" ); 98assertStringIncludes ( catalog . diagnostics . join ( "\n" ), "at most 64" ); 99await assertRejects (() => readSkill ( env , oversized , context ), Error , "exceeds" ); 100}); 101 102Deno . test ( "multiline YAML and optional metadata remain compatible with standard skills" , () => { 103const content = 104"---\r\nname: release\r\ndescription: >-\r\n Prepare a release:\r\n verify the changelog.\r\nmetadata:\r\n author: charlotte\r\nallowed-tools: Bash Read\r\n---\r\nHuman prose: keep this spacing.\r\n" ; 105const parsed = parseSkill ( content , "old-directory" ); 106assertEquals ( parsed . description , "Prepare a release: verify the changelog." ); 107assertStringIncludes ( parsed . warnings . join ( "\n" ), "old-directory" ); 108});