char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somadd skills extension for loading skillsa4e772a

main
5.4 KiB140 linesraw
1import { assertEquals, assertRejects } from "@std/assert";
2import { BACKGROUND_CONTEXT as context } from "@earendil-works/chord/context";
3import { FileError, getOrThrow } from "@earendil-works/pi-durable/env";
4import { tempDir } from "@berry/util";
5import { Bundles, MAX_BUNDLE_BYTES } from "./bundles.ts";
6import { hostEnvironment, targetEnvironment, writeSkill } from "./testing.ts";
7
8Deno.test("host bundles preserve binary assets, empty directories, and resource-only versions on new targets", async () => {
9  await using home = await tempDir();
10  await using target = await tempDir();
11  const host = hostEnvironment(home.path);
12  const main = await writeSkill(
13    host,
14    `${home.path}/.config/berry/skills`,
15    "review",
16    "Read references/checklist.txt.",
17  );
18  const directory = main.slice(0, -"/SKILL.md".length);
19  getOrThrow(
20    await host.writeFile(`${directory}/references/checklist.txt`, "original checklist", context),
21  );
22  getOrThrow(
23    await host.writeFile(`${directory}/assets/data.bin`, new Uint8Array([0, 255, 128]), context),
24  );
25  getOrThrow(await host.createDir(`${directory}/empty`, { recursive: true }, context));
26  await Deno.symlink("checklist.txt", `${directory}/references/alias.txt`);
27  const bundles = new Bundles(host);
28  const first = await bundles.capture(directory, context);
29  const env = targetEnvironment(target.path);
30  const copied = await bundles.materialize(first.id, env, context);
31  assertEquals(
32    [...getOrThrow(await env.readBinaryFile(`${copied}/assets/data.bin`, context))],
33    [0, 255, 128],
34  );
35  assertEquals(
36    getOrThrow(await env.readTextFile(`${copied}/references/alias.txt`, context)),
37    "original checklist",
38  );
39  assertEquals(getOrThrow(await env.fileInfo(`${copied}/empty`, context)).kind, "directory");
40
41  getOrThrow(
42    await host.writeFile(`${directory}/references/checklist.txt`, "updated checklist", context),
43  );
44  const second = await bundles.capture(directory, context);
45  const updated = await bundles.materialize(second.id, env, context);
46  assertEquals(first.content, second.content);
47  assertEquals(
48    getOrThrow(await env.readTextFile(`${updated}/references/checklist.txt`, context)),
49    "updated checklist",
50  );
51  getOrThrow(await host.remove(directory, { recursive: true }, context));
52  await using other = await tempDir();
53  const next = targetEnvironment(other.path);
54  const historical = await new Bundles(hostEnvironment(home.path)).materialize(
55    first.id,
56    next,
57    context,
58  );
59  assertEquals(
60    getOrThrow(await next.readTextFile(`${historical}/references/checklist.txt`, context)),
61    "original checklist",
62  );
63});
64
65Deno.test("bundle capture refuses escaping symlinks and cycles rather than copying unrelated host files", async () => {
66  await using home = await tempDir();
67  const host = hostEnvironment(home.path);
68  const main = await writeSkill(
69    host,
70    `${home.path}/.config/berry/skills`,
71    "review",
72    "instructions",
73  );
74  const directory = main.slice(0, -"/SKILL.md".length);
75  await Deno.writeTextFile(`${home.path}/private.txt`, "not part of the skill");
76  await Deno.symlink(`${home.path}/private.txt`, `${directory}/escape.txt`);
77  const bundles = new Bundles(host);
78  await assertRejects(() => bundles.capture(directory, context), Error, "escapes");
79  await Deno.remove(`${directory}/escape.txt`);
80  await Deno.symlink(directory, `${directory}/cycle`);
81  await assertRejects(() => bundles.capture(directory, context), Error, "cycle");
82});
83
84Deno.test("oversized resource bundles fail before publication", async () => {
85  await using home = await tempDir();
86  const host = hostEnvironment(home.path);
87  const main = await writeSkill(
88    host,
89    `${home.path}/.config/berry/skills`,
90    "review",
91    "instructions",
92  );
93  const directory = main.slice(0, -"/SKILL.md".length);
94  await Deno.writeTextFile(`${directory}/large.bin`, "");
95  await Deno.truncate(`${directory}/large.bin`, MAX_BUNDLE_BYTES + 1);
96  await assertRejects(() => new Bundles(host).capture(directory, context), Error, "size limit");
97});
98
99Deno.test("an interrupted copy can be retried concurrently without exposing partial bundles", async () => {
100  await using home = await tempDir();
101  await using target = await tempDir();
102  const host = hostEnvironment(home.path);
103  const main = await writeSkill(
104    host,
105    `${home.path}/.config/berry/skills`,
106    "review",
107    "instructions",
108  );
109  const directory = main.slice(0, -"/SKILL.md".length);
110  getOrThrow(
111    await host.writeFile(`${directory}/references/checklist.txt`, "complete checklist", context),
112  );
113  const bundles = new Bundles(host);
114  const snapshot = await bundles.capture(directory, context);
115  const env = targetEnvironment(target.path);
116  const write = env.writeFile;
117  env.writeFile = (path, content, context) =>
118    path.endsWith("/checklist.txt")
119      ? Promise.resolve({ ok: false, error: new FileError("unknown", "Transfer interrupted") })
120      : write(path, content, context);
121  await assertRejects(
122    () => bundles.materialize(snapshot.id, env, context),
123    Error,
124    "Transfer interrupted",
125  );
126  env.writeFile = write;
127  const paths = await Promise.all([
128    bundles.materialize(snapshot.id, env, context),
129    bundles.materialize(snapshot.id, env, context),
130  ]);
131  assertEquals(paths[0], paths[1]);
132  assertEquals(
133    getOrThrow(await env.readTextFile(`${paths[0]}/references/checklist.txt`, context)),
134    "complete checklist",
135  );
136  assertEquals(
137    getOrThrow(await env.readTextFile(`${paths[0]}/SKILL.md`, context)),
138    snapshot.content,
139  );
140});