@earendil-works/pi-durable 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +21 -5
  3. package/dist/env/decode.d.ts +16 -0
  4. package/dist/env/decode.d.ts.map +1 -0
  5. package/dist/env/decode.js +28 -0
  6. package/dist/env/decode.js.map +1 -0
  7. package/dist/env/index.d.ts +155 -3
  8. package/dist/env/index.d.ts.map +1 -1
  9. package/dist/env/index.js +2 -0
  10. package/dist/env/index.js.map +1 -1
  11. package/dist/env/line-scan.d.ts +13 -0
  12. package/dist/env/line-scan.d.ts.map +1 -0
  13. package/dist/env/line-scan.js +147 -0
  14. package/dist/env/line-scan.js.map +1 -0
  15. package/dist/env/node-watch.d.ts +29 -0
  16. package/dist/env/node-watch.d.ts.map +1 -0
  17. package/dist/env/node-watch.js +431 -0
  18. package/dist/env/node-watch.js.map +1 -0
  19. package/dist/env/node.d.ts +11 -2
  20. package/dist/env/node.d.ts.map +1 -1
  21. package/dist/env/node.js +284 -21
  22. package/dist/env/node.js.map +1 -1
  23. package/dist/harness/agent.d.ts +2 -1
  24. package/dist/harness/agent.d.ts.map +1 -1
  25. package/dist/harness/agent.js +5 -0
  26. package/dist/harness/agent.js.map +1 -1
  27. package/dist/harness/compaction.d.ts.map +1 -1
  28. package/dist/harness/compaction.js +2 -0
  29. package/dist/harness/compaction.js.map +1 -1
  30. package/dist/harness/generation.d.ts.map +1 -1
  31. package/dist/harness/generation.js +8 -5
  32. package/dist/harness/generation.js.map +1 -1
  33. package/dist/harness/harness.d.ts.map +1 -1
  34. package/dist/harness/harness.js +4 -1
  35. package/dist/harness/harness.js.map +1 -1
  36. package/dist/harness/output.d.ts +13 -6
  37. package/dist/harness/output.d.ts.map +1 -1
  38. package/dist/harness/output.js +61 -16
  39. package/dist/harness/output.js.map +1 -1
  40. package/dist/harness/provider.d.ts +14 -0
  41. package/dist/harness/provider.d.ts.map +1 -0
  42. package/dist/harness/provider.js +30 -0
  43. package/dist/harness/provider.js.map +1 -0
  44. package/dist/harness/tool.d.ts.map +1 -1
  45. package/dist/harness/tool.js +12 -4
  46. package/dist/harness/tool.js.map +1 -1
  47. package/dist/harness/types.d.ts +24 -3
  48. package/dist/harness/types.d.ts.map +1 -1
  49. package/dist/harness/types.js.map +1 -1
  50. package/dist/harness/view.d.ts +1 -1
  51. package/dist/harness/view.d.ts.map +1 -1
  52. package/dist/harness/view.js +8 -1
  53. package/dist/harness/view.js.map +1 -1
  54. package/dist/index.d.ts +3 -2
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +2 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/testing/env-conformance.d.ts +7 -0
  59. package/dist/testing/env-conformance.d.ts.map +1 -0
  60. package/dist/testing/env-conformance.js +397 -0
  61. package/dist/testing/env-conformance.js.map +1 -0
  62. package/dist/testing/index.d.ts +3 -2
  63. package/dist/testing/index.d.ts.map +1 -1
  64. package/dist/testing/index.js +2 -1
  65. package/dist/testing/index.js.map +1 -1
  66. package/dist/testing/runner.d.ts +4 -2
  67. package/dist/testing/runner.d.ts.map +1 -1
  68. package/dist/testing/runner.js +9 -0
  69. package/dist/testing/runner.js.map +1 -1
  70. package/dist/testing/types.d.ts +18 -0
  71. package/dist/testing/types.d.ts.map +1 -1
  72. package/dist/testing/types.js.map +1 -1
  73. package/dist/tools/bash.d.ts +2 -1
  74. package/dist/tools/bash.d.ts.map +1 -1
  75. package/dist/tools/bash.js +5 -2
  76. package/dist/tools/bash.js.map +1 -1
  77. package/dist/tools/image.d.ts +10 -0
  78. package/dist/tools/image.d.ts.map +1 -1
  79. package/dist/tools/image.js +39 -0
  80. package/dist/tools/image.js.map +1 -1
  81. package/dist/tools/read.d.ts.map +1 -1
  82. package/dist/tools/read.js +148 -75
  83. package/dist/tools/read.js.map +1 -1
  84. package/dist/truncate.d.ts +9 -0
  85. package/dist/truncate.d.ts.map +1 -1
  86. package/dist/truncate.js +12 -4
  87. package/dist/truncate.js.map +1 -1
  88. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-conformance.js","sourceRoot":"","sources":["../../src/testing/env-conformance.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT, withAbortSignal } from \"@earendil-works/chord/context\";\nimport {\n\ttype ExecutionEnv,\n\ttype FileInfo,\n\tgetOrThrow,\n\ttype Result,\n\ttype ShellOutputInfo,\n\ttype WatchChange,\n\ttype WatchTarget,\n} from \"../env/index.ts\";\nimport type { EnvConformanceCase, EnvConformanceOptions } from \"./types.ts\";\n\nconst context = BACKGROUND_CONTEXT;\nconst decoder = new TextDecoder();\nconst encoder = new TextEncoder();\n\ntype EnvTest = (env: ExecutionEnv) => Promise<void>;\n\nfunction abortedContext(): Context {\n\tconst controller = new AbortController();\n\tcontroller.abort();\n\treturn withAbortSignal(controller.signal, BACKGROUND_CONTEXT);\n}\n\nfunction errorCode(result: Result<unknown, { code: string }>): string | undefined {\n\treturn result.ok ? undefined : result.error.code;\n}\n\nasync function readAll(\n\tenv: ExecutionEnv,\n\tpath: string,\n\tmaxEntries: number,\n): Promise<{ pages: FileInfo[][]; done: boolean }> {\n\tconst reader = getOrThrow(await env.openDirReader(path, context));\n\tconst pages: FileInfo[][] = [];\n\ttry {\n\t\tfor (let page = 0; page < 1000; page++) {\n\t\t\tconst next = getOrThrow(await reader.next(maxEntries, context));\n\t\t\tpages.push(next.entries);\n\t\t\tif (next.done) return { pages, done: true };\n\t\t}\n\t\treturn { pages, done: false };\n\t} finally {\n\t\tawait reader.close(context);\n\t}\n}\n\n/** Whether a change reports `path`: an overflow, or a reported path at or above it. */\nfunction covers(change: WatchChange, path: string): boolean {\n\tif (\"overflow\" in change) return true;\n\tif (!(\"paths\" in change)) return false;\n\treturn change.paths.some(\n\t\t(reported) => path === reported || path.startsWith(`${reported}/`) || path.startsWith(`${reported}\\\\`),\n\t);\n}\n\n/** Watch `targets` while `run` changes files, with a helper that waits for a change reporting a path. */\nasync function watching(\n\tenv: ExecutionEnv,\n\ttargets: readonly WatchTarget[],\n\trun: (helpers: {\n\t\treadonly changes: WatchChange[];\n\t\t/** Wait up to three seconds for a change, after the call, that reports `path`. */\n\t\texpectChange(path: string, change: () => Promise<void>): Promise<void>;\n\t\tabsolute(path: string): Promise<string>;\n\t}) => Promise<void>,\n): Promise<void> {\n\tconst changes: WatchChange[] = [];\n\tconst watcher = getOrThrow(await env.watch(targets, (change) => changes.push(change), context));\n\ttry {\n\t\tconst absolute = async (path: string) => getOrThrow(await env.absolutePath(path, context));\n\t\tawait run({\n\t\t\tchanges,\n\t\t\tabsolute,\n\t\t\tasync expectChange(path, change) {\n\t\t\t\tconst target = await absolute(path);\n\t\t\t\tconst from = changes.length;\n\t\t\t\tawait change();\n\t\t\t\tconst deadline = Date.now() + 3000;\n\t\t\t\twhile (!changes.slice(from).some((entry) => covers(entry, target))) {\n\t\t\t\t\tif (Date.now() > deadline) {\n\t\t\t\t\t\tthrow new Error(`No change reported ${target}; got ${JSON.stringify(changes.slice(from))}`);\n\t\t\t\t\t}\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 20));\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t} finally {\n\t\tawait watcher.close(context);\n\t}\n}\n\n/**\n * Creates runner-independent cases for an `ExecutionEnv`. `withEnv` must call and await its callback exactly once per\n * case with an environment whose `cwd` is a fresh, empty, writable directory.\n */\nexport function createEnvConformance(options: EnvConformanceOptions): readonly EnvConformanceCase[] {\n\tconst assert = options.assertions;\n\tconst shell = options.shell ?? [\"sh\", \"-c\"];\n\tconst symlinks = options.symlinks ?? true;\n\tconst createCase = (name: string, test: EnvTest, timeoutMs?: number): EnvConformanceCase => ({\n\t\tname,\n\t\t...(timeoutMs === undefined ? {} : { timeoutMs }),\n\t\trun: () => options.withEnv(test),\n\t});\n\t// Watch cases wait up to three seconds per step, longer than test runners allow by default.\n\tconst watchCase = (name: string, test: EnvTest): EnvConformanceCase => createCase(name, test, 30_000);\n\tconst execCollect = async (env: ExecutionEnv, command: string | readonly string[], cwd?: string) => {\n\t\tconst output: Record<ShellOutputInfo[\"stream\"], string> = { stdout: \"\", stderr: \"\" };\n\t\tconst result = await env.exec(\n\t\t\tcommand,\n\t\t\t{\n\t\t\t\t...(cwd === undefined ? {} : { cwd }),\n\t\t\t\tonOutput: (text, _context, info) => {\n\t\t\t\t\toutput[info.stream] += text;\n\t\t\t\t},\n\t\t\t},\n\t\t\tcontext,\n\t\t);\n\t\treturn { result, ...output };\n\t};\n\n\tconst cases: EnvConformanceCase[] = [\n\t\tcreateCase(\"binary reader reads byte ranges of the opened file\", async (env) => {\n\t\t\tgetOrThrow(await env.writeFile(\"data.txt\", \"hello world\", context));\n\t\t\tconst reader = getOrThrow(await env.openBinaryReader(\"data.txt\", undefined, context));\n\t\t\tconst info = getOrThrow(await reader.info(context));\n\t\t\tassert.partialDeepEqual(info, { name: \"data.txt\", kind: \"file\", size: 11 });\n\t\t\tassert.strictEqual(decoder.decode(getOrThrow(await reader.read(0, 5, context))), \"hello\");\n\t\t\tassert.strictEqual(decoder.decode(getOrThrow(await reader.read(6, 100, context))), \"world\");\n\t\t\tassert.strictEqual(getOrThrow(await reader.read(11, 4, context)).length, 0);\n\t\t\tassert.strictEqual(getOrThrow(await reader.read(50, 1, context)).length, 0);\n\t\t\tassert.strictEqual(getOrThrow(await reader.read(3, 0, context)).length, 0);\n\t\t\tassert.strictEqual(errorCode(await reader.read(-1, 1, context)), \"invalid\");\n\t\t\tassert.strictEqual(errorCode(await reader.read(0, 1.5, context)), \"invalid\");\n\t\t\tassert.strictEqual(errorCode(await reader.read(0, 1, abortedContext())), \"aborted\");\n\t\t\tawait reader.close(context);\n\t\t\tawait reader.close(context);\n\t\t\tassert.strictEqual(errorCode(await reader.read(0, 1, context)), \"invalid\");\n\t\t\tassert.strictEqual(errorCode(await reader.info(context)), \"invalid\");\n\t\t}),\n\n\t\tcreateCase(\"binary reader scans lines like decoding the whole file\", async (env) => {\n\t\t\t// A byte-order mark, an invalid sequence before a newline, an empty line, a later U+FEFF, and no final newline.\n\t\t\tconst bytes = Uint8Array.from([\n\t\t\t\t0xef, 0xbb, 0xbf, 0x61, 0x0a, 0xe2, 0x82, 0x0a, 0x0a, 0xef, 0xbb, 0xbf, 0x62, 0x0a, 0xc3, 0xa9,\n\t\t\t]);\n\t\t\tgetOrThrow(await env.writeFile(\"lines.txt\", bytes, context));\n\t\t\tconst lines = new TextDecoder().decode(bytes).split(\"\\n\");\n\t\t\tconst reader = getOrThrow(await env.openBinaryReader(\"lines.txt\", undefined, context));\n\t\t\ttry {\n\t\t\t\tconst ranges: [number, number | undefined][] = [\n\t\t\t\t\t[0, undefined],\n\t\t\t\t\t[0, 1],\n\t\t\t\t\t[1, 3],\n\t\t\t\t\t[2, 3],\n\t\t\t\t\t[3, undefined],\n\t\t\t\t\t[4, 9],\n\t\t\t\t];\n\t\t\t\tfor (const [startLine, endLine] of ranges) {\n\t\t\t\t\tconst scan = getOrThrow(\n\t\t\t\t\t\tawait reader.scanLines({ startLine, ...(endLine === undefined ? {} : { endLine }) }, context),\n\t\t\t\t\t);\n\t\t\t\t\tconst selected = lines.slice(startLine, endLine);\n\t\t\t\t\tconst range = (from: number, to: number) =>\n\t\t\t\t\t\tnew TextDecoder(\"utf-8\", { ignoreBOM: from > 0 }).decode(bytes.subarray(from, to));\n\t\t\t\t\tassert.strictEqual(scan.newlines, lines.length - 1);\n\t\t\t\t\tassert.strictEqual(range(scan.start, scan.end), selected.join(\"\\n\"));\n\t\t\t\t\tassert.strictEqual(scan.selectedBytes, encoder.encode(selected.join(\"\\n\")).length);\n\t\t\t\t\tassert.strictEqual(range(scan.start, scan.firstLineEnd), lines[startLine]);\n\t\t\t\t\tassert.strictEqual(scan.firstLineBytes, encoder.encode(lines[startLine]).length);\n\t\t\t\t}\n\t\t\t\tassert.partialDeepEqual(getOrThrow(await reader.scanLines({ startLine: 9 }, context)), {\n\t\t\t\t\tstart: bytes.length,\n\t\t\t\t\tend: bytes.length,\n\t\t\t\t\tselectedBytes: 0,\n\t\t\t\t});\n\t\t\t\tassert.strictEqual(errorCode(await reader.scanLines({ startLine: 2, endLine: 2 }, context)), \"invalid\");\n\t\t\t} finally {\n\t\t\t\tawait reader.close(context);\n\t\t\t}\n\t\t}),\n\n\t\tcreateCase(\"binary reader keeps reading the file it opened after a rename\", async (env) => {\n\t\t\tgetOrThrow(await env.writeFile(\"a.txt\", \"one\", context));\n\t\t\tconst reader = getOrThrow(await env.openBinaryReader(\"a.txt\", undefined, context));\n\t\t\ttry {\n\t\t\t\tgetOrThrow(await env.renameFile(\"a.txt\", \"b.txt\", context));\n\t\t\t\tgetOrThrow(await env.writeFile(\"a.txt\", \"two\", context));\n\t\t\t\tassert.strictEqual(decoder.decode(getOrThrow(await reader.read(0, 10, context))), \"one\");\n\t\t\t} finally {\n\t\t\t\tawait reader.close(context);\n\t\t\t}\n\t\t}),\n\n\t\tcreateCase(\"binary reader refuses directories, missing files and aborted opens\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"dir\", undefined, context));\n\t\t\tgetOrThrow(await env.writeFile(\"file.txt\", \"x\", context));\n\t\t\tassert.strictEqual(errorCode(await env.openBinaryReader(\"dir\", undefined, context)), \"is_directory\");\n\t\t\tassert.strictEqual(errorCode(await env.openBinaryReader(\"missing.txt\", undefined, context)), \"not_found\");\n\t\t\tassert.strictEqual(errorCode(await env.openBinaryReader(\"file.txt\", undefined, abortedContext())), \"aborted\");\n\t\t}),\n\n\t\tcreateCase(\"directory reader pages every entry exactly once\", async (env) => {\n\t\t\tconst names = [\"a.txt\", \"b.txt\", \"c.txt\", \"d.txt\", \"e.txt\"];\n\t\t\tfor (const name of names) getOrThrow(await env.writeFile(name, name, context));\n\t\t\tgetOrThrow(await env.createDir(\"sub\", undefined, context));\n\t\t\tconst { pages, done } = await readAll(env, \".\", 2);\n\t\t\tassert.ok(done, \"directory reader reached the end\");\n\t\t\tfor (const page of pages) assert.ok(page.length <= 2, \"page within maxEntries\");\n\t\t\tconst entries = pages.flat();\n\t\t\tassert.deepEqual(entries.map((entry) => entry.name).sort(), [...names, \"sub\"].sort());\n\t\t\tassert.strictEqual(entries.find((entry) => entry.name === \"sub\")?.kind, \"directory\");\n\t\t\tassert.partialDeepEqual(\n\t\t\t\tentries.find((entry) => entry.name === \"a.txt\"),\n\t\t\t\t{ kind: \"file\", size: 5 },\n\t\t\t);\n\t\t}),\n\n\t\tcreateCase(\"directory reader reports the end and refuses use after close\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"empty\", undefined, context));\n\t\t\tconst reader = getOrThrow(await env.openDirReader(\"empty\", context));\n\t\t\tassert.deepEqual(getOrThrow(await reader.next(10, context)), { entries: [], done: true });\n\t\t\tassert.deepEqual(getOrThrow(await reader.next(10, context)), { entries: [], done: true });\n\t\t\tassert.strictEqual(errorCode(await reader.next(0, context)), \"invalid\");\n\t\t\tassert.strictEqual(errorCode(await reader.next(1, abortedContext())), \"aborted\");\n\t\t\tawait reader.close(context);\n\t\t\tawait reader.close(context);\n\t\t\tassert.strictEqual(errorCode(await reader.next(1, context)), \"invalid\");\n\t\t}),\n\n\t\tcreateCase(\"directory reader refuses missing paths and files\", async (env) => {\n\t\t\tgetOrThrow(await env.writeFile(\"file.txt\", \"x\", context));\n\t\t\tassert.strictEqual(errorCode(await env.openDirReader(\"missing\", context)), \"not_found\");\n\t\t\tconst file = await env.openDirReader(\"file.txt\", context);\n\t\t\tassert.strictEqual(errorCode(file), \"not_directory\");\n\t\t\tassert.strictEqual(errorCode(await env.openDirReader(\".\", abortedContext())), \"aborted\");\n\t\t}),\n\n\t\tcreateCase(\"directory reader skips entries removed during enumeration\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"dir\", undefined, context));\n\t\t\tfor (const name of [\"x\", \"y\", \"z\"]) getOrThrow(await env.writeFile(`dir/${name}`, name, context));\n\t\t\tconst reader = getOrThrow(await env.openDirReader(\"dir\", context));\n\t\t\ttry {\n\t\t\t\tfor (const name of [\"x\", \"y\", \"z\"]) getOrThrow(await env.remove(`dir/${name}`, undefined, context));\n\t\t\t\tconst entries: FileInfo[] = [];\n\t\t\t\tfor (let page = 0; page < 10; page++) {\n\t\t\t\t\tconst next = getOrThrow(await reader.next(10, context));\n\t\t\t\t\tentries.push(...next.entries);\n\t\t\t\t\tif (next.done) break;\n\t\t\t\t}\n\t\t\t\tassert.deepEqual(entries, []);\n\t\t\t} finally {\n\t\t\t\tawait reader.close(context);\n\t\t\t}\n\t\t}),\n\n\t\twatchCase(\"watch reports a missing file's creation, changes, replacement and removal\", async (env) => {\n\t\t\tawait watching(env, [{ path: \"AGENTS.md\" }], async ({ expectChange }) => {\n\t\t\t\tawait expectChange(\"AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"AGENTS.md\", \"one\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"AGENTS.md\", \"two!\", context));\n\t\t\t\t});\n\t\t\t\t// Editors replace a file by renaming a new one over it.\n\t\t\t\tawait expectChange(\"AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"AGENTS.md.tmp\", \"three\", context));\n\t\t\t\t\tgetOrThrow(await env.renameFile(\"AGENTS.md.tmp\", \"AGENTS.md\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"AGENTS.md\", \"four\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.remove(\"AGENTS.md\", undefined, context));\n\t\t\t\t});\n\t\t\t});\n\t\t}),\n\n\t\twatchCase(\"watch reports a missing target whose ancestors are created\", async (env) => {\n\t\t\tawait watching(env, [{ path: \"a/b/c/AGENTS.md\" }], async ({ expectChange }) => {\n\t\t\t\tawait expectChange(\"a/b/c/AGENTS.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"a/b/c/AGENTS.md\", \"x\", context));\n\t\t\t\t});\n\t\t\t});\n\t\t}),\n\n\t\twatchCase(\"watch follows directories created together with their contents\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"skills\", undefined, context));\n\t\t\tawait watching(env, [{ path: \"skills\", recursive: true }], async ({ expectChange }) => {\n\t\t\t\t// Written before any watcher on the new directories can exist.\n\t\t\t\tawait expectChange(\"skills/a/b/SKILL.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"skills/a/b/SKILL.md\", \"one\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"skills/a/b/SKILL.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"skills/a/b/SKILL.md\", \"two!\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"skills/a/b/c/SKILL.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"skills/a/b/c/SKILL.md\", \"deeper\", context));\n\t\t\t\t});\n\t\t\t});\n\t\t}),\n\n\t\twatchCase(\"watch keeps watching a path whose parent is renamed and recreated\", async (env) => {\n\t\t\tgetOrThrow(await env.writeFile(\"proj/.pi/skills/x.md\", \"x\", context));\n\t\t\tawait watching(env, [{ path: \"proj/.pi/skills\", recursive: true }], async ({ expectChange }) => {\n\t\t\t\tawait expectChange(\"proj/.pi/skills\", async () => {\n\t\t\t\t\tgetOrThrow(await env.renameFile(\"proj/.pi\", \"proj/old\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"proj/.pi/skills/y.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"proj/.pi/skills/y.md\", \"y\", context));\n\t\t\t\t});\n\t\t\t\tawait expectChange(\"proj/.pi/skills/y.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.writeFile(\"proj/.pi/skills/y.md\", \"yy\", context));\n\t\t\t\t});\n\t\t\t});\n\t\t}),\n\n\t\twatchCase(\"watch skips excluded entries and reports a rename out of them\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"skills\", undefined, context));\n\t\t\tconst targets: WatchTarget[] = [\n\t\t\t\t{ path: \"skills\", recursive: true, exclude: { hidden: true, names: [\"node_modules\"] } },\n\t\t\t];\n\t\t\tawait watching(env, targets, async ({ changes, expectChange, absolute }) => {\n\t\t\t\tgetOrThrow(await env.writeFile(\"skills/node_modules/dep/SKILL.md\", \"dep\", context));\n\t\t\t\tgetOrThrow(await env.writeFile(\"skills/.SKILL.md.tmp\", \"draft\", context));\n\t\t\t\tawait expectChange(\"skills/SKILL.md\", async () => {\n\t\t\t\t\tgetOrThrow(await env.renameFile(\"skills/.SKILL.md.tmp\", \"skills/SKILL.md\", context));\n\t\t\t\t});\n\t\t\t\tconst hidden = [await absolute(\"skills/node_modules\"), await absolute(\"skills/.SKILL.md.tmp\")];\n\t\t\t\tfor (const change of changes) {\n\t\t\t\t\tif (!(\"paths\" in change)) continue;\n\t\t\t\t\tfor (const path of change.paths) {\n\t\t\t\t\t\tassert.ok(\n\t\t\t\t\t\t\t!hidden.some((excluded) => path === excluded || path.startsWith(excluded)),\n\t\t\t\t\t\t\t`excluded ${path}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}),\n\n\t\twatchCase(\"watch stops reporting once closed\", async (env) => {\n\t\t\tconst changes: WatchChange[] = [];\n\t\t\tconst watcher = getOrThrow(await env.watch([{ path: \"file.txt\" }], (change) => changes.push(change), context));\n\t\t\tassert.ok(watcher.mode === \"native\" || watcher.mode === \"polling\", \"watcher reports its mode\");\n\t\t\tawait watcher.close(context);\n\t\t\tawait watcher.close(context);\n\t\t\tgetOrThrow(await env.writeFile(\"file.txt\", \"x\", context));\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 300));\n\t\t\tassert.deepEqual(changes, []);\n\t\t}),\n\n\t\tcreateCase(\"argv exec passes arguments to the program without shell parsing\", async (env) => {\n\t\t\tconst hostile = \"it's $(touch pwned) `touch pwned` *; touch pwned\";\n\t\t\tconst { result, stdout } = await execCollect(env, [\n\t\t\t\t...shell,\n\t\t\t\t'printf \"%s|%s\" \"$1\" \"$2\"',\n\t\t\t\t\"argv0\",\n\t\t\t\thostile,\n\t\t\t\t\"a b\",\n\t\t\t]);\n\t\t\tassert.strictEqual(getOrThrow(result).exitCode, 0);\n\t\t\tassert.strictEqual(stdout, `${hostile}|a b`);\n\t\t\tassert.strictEqual(getOrThrow(await env.exists(\"pwned\", context)), false);\n\t\t}),\n\n\t\tcreateCase(\"exec reports the stream of every chunk in both forms\", async (env) => {\n\t\t\tconst script = \"printf out; printf err >&2; printf more\";\n\t\t\tconst argv = await execCollect(env, [...shell, script]);\n\t\t\tassert.strictEqual(getOrThrow(argv.result).exitCode, 0);\n\t\t\tassert.strictEqual(argv.stdout, \"outmore\");\n\t\t\tassert.strictEqual(argv.stderr, \"err\");\n\t\t\tconst string = await execCollect(env, script);\n\t\t\tassert.strictEqual(getOrThrow(string.result).exitCode, 0);\n\t\t\tassert.strictEqual(string.stdout, \"outmore\");\n\t\t\tassert.strictEqual(string.stderr, \"err\");\n\t\t}),\n\n\t\tcreateCase(\"argv exec honors cwd and exit codes\", async (env) => {\n\t\t\tgetOrThrow(await env.createDir(\"sub\", undefined, context));\n\t\t\tconst made = await execCollect(env, [...shell, \"printf x > made.txt; exit 3\"], \"sub\");\n\t\t\tassert.strictEqual(getOrThrow(made.result).exitCode, 3);\n\t\t\tassert.strictEqual(getOrThrow(await env.readTextFile(\"sub/made.txt\", context)), \"x\");\n\t\t}),\n\n\t\tcreateCase(\"argv exec reports missing programs and empty argv as spawn errors\", async (env) => {\n\t\t\tassert.strictEqual(\n\t\t\t\terrorCode(await env.exec([\"pi-durable-conformance-missing-program\"], undefined, context)),\n\t\t\t\t\"spawn_error\",\n\t\t\t);\n\t\t\tassert.strictEqual(errorCode(await env.exec([], undefined, context)), \"spawn_error\");\n\t\t}),\n\n\t\tcreateCase(\"windowed exec keeps the exact tail and counts what it skips\", async (env) => {\n\t\t\tconst lines = 2000;\n\t\t\tconst window = { maxBytes: 200, maxLines: 5, minIntervalMs: 0, bytesPerSecond: 1_000_000_000 };\n\t\t\tlet bytes = 0;\n\t\t\tlet newlines = 0;\n\t\t\tlet tail = \"\";\n\t\t\tconst result = await env.exec(\n\t\t\t\t[...shell, `i=0; while [ $i -lt ${lines} ]; do echo line-$i; i=$((i+1)); done`],\n\t\t\t\t{\n\t\t\t\t\twindow,\n\t\t\t\t\tonOutput: (text, _context, info) => {\n\t\t\t\t\t\tif (info.skipped !== undefined) {\n\t\t\t\t\t\t\tbytes += info.skipped.bytes;\n\t\t\t\t\t\t\tnewlines += info.skipped.newlines;\n\t\t\t\t\t\t\tconst after = encoder.encode(text).length;\n\t\t\t\t\t\t\tconst afterNewlines = text.split(\"\\n\").length - 1;\n\t\t\t\t\t\t\tassert.ok(\n\t\t\t\t\t\t\t\tafter > window.maxBytes || afterNewlines > window.maxLines,\n\t\t\t\t\t\t\t\t\"a skip is followed by more than the window\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\ttail = \"\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbytes += encoder.encode(text).length;\n\t\t\t\t\t\tnewlines += text.split(\"\\n\").length - 1;\n\t\t\t\t\t\ttail += text;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tassert.strictEqual(getOrThrow(result).exitCode, 0);\n\t\t\tconst expected = Array.from({ length: lines }, (_, index) => `line-${index}\\n`);\n\t\t\tassert.strictEqual(bytes, expected.join(\"\").length);\n\t\t\tassert.strictEqual(newlines, lines);\n\t\t\tassert.ok(tail.endsWith(expected.slice(-window.maxLines).join(\"\")), \"the delivered output ends with the tail\");\n\t\t}),\n\n\t\tcreateCase(\"argv exec distinguishes timeout from abort\", async (env) => {\n\t\t\tconst timedOut = await env.exec([...shell, \"sleep 2\"], { timeout: 0.1 }, context);\n\t\t\tassert.strictEqual(errorCode(timedOut), \"timeout\");\n\t\t\tconst controller = new AbortController();\n\t\t\tconst running = env.exec([...shell, \"sleep 2\"], undefined, withAbortSignal(controller.signal, context));\n\t\t\tsetTimeout(() => controller.abort(), 100);\n\t\t\tassert.strictEqual(errorCode(await running), \"aborted\");\n\t\t}),\n\t];\n\n\tif (symlinks) {\n\t\tcases.push(\n\t\t\tcreateCase(\"binary reader follows symlinks unless noFollow refuses the final one\", async (env) => {\n\t\t\t\tgetOrThrow(await env.writeFile(\"target.txt\", \"target\", context));\n\t\t\t\tgetOrThrow(await env.createDir(\"sub\", undefined, context));\n\t\t\t\tgetOrThrow(await env.writeFile(\"sub/inner.txt\", \"inner\", context));\n\t\t\t\tconst linked = await env.exec(\n\t\t\t\t\t[...shell, \"ln -s target.txt link.txt && ln -s sub dirlink\"],\n\t\t\t\t\tundefined,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(getOrThrow(linked).exitCode, 0);\n\n\t\t\t\tconst followed = getOrThrow(await env.openBinaryReader(\"link.txt\", undefined, context));\n\t\t\t\tassert.strictEqual(decoder.decode(getOrThrow(await followed.read(0, 10, context))), \"target\");\n\t\t\t\tawait followed.close(context);\n\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\terrorCode(await env.openBinaryReader(\"link.txt\", { noFollow: true }, context)),\n\t\t\t\t\t\"invalid\",\n\t\t\t\t);\n\n\t\t\t\t// Only the final component is refused; earlier symlinked directories still resolve.\n\t\t\t\tconst inner = getOrThrow(await env.openBinaryReader(\"dirlink/inner.txt\", { noFollow: true }, context));\n\t\t\t\tassert.strictEqual(decoder.decode(getOrThrow(await inner.read(0, 10, context))), \"inner\");\n\t\t\t\tawait inner.close(context);\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn cases;\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  export { createExpectAssertions, type ExpectLike } from "./assertions.ts";
2
- export { registerStorageConformance, type StorageConformanceRunner } from "./runner.ts";
2
+ export { createEnvConformance } from "./env-conformance.ts";
3
+ export { registerEnvConformance, registerStorageConformance, type StorageConformanceRunner } from "./runner.ts";
3
4
  export { STORAGE_MEMORY_SCALES, STORAGE_READ_BENCHMARKS, STORAGE_WRITE_BENCHMARKS, type StorageBenchmarkDataset, type StorageBenchmarkScale, type StorageReadBenchmark, type StorageWriteBenchmark, seedStorageBenchmark, seedStorageWriteBenchmark, storageBenchmarkPrimaryRecordCount, TIMING_SCALE, } from "./storage-benchmark.ts";
4
5
  export { createStorageConformance } from "./storage-conformance.ts";
5
- export type { StorageConformanceAssertions, StorageConformanceCase, StorageConformanceOptions, StorageConformanceProvider, } from "./types.ts";
6
+ export type { EnvConformanceAssertions, EnvConformanceCase, EnvConformanceOptions, EnvConformanceProvider, StorageConformanceAssertions, StorageConformanceCase, StorageConformanceOptions, StorageConformanceProvider, } from "./types.ts";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,yBAAyB,EACzB,kCAAkC,EAClC,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EACX,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC1B,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAChH,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,yBAAyB,EACzB,kCAAkC,EAClC,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EACX,wBAAwB,EACxB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC1B,MAAM,YAAY,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export { createExpectAssertions } from "./assertions.js";
2
- export { registerStorageConformance } from "./runner.js";
2
+ export { createEnvConformance } from "./env-conformance.js";
3
+ export { registerEnvConformance, registerStorageConformance } from "./runner.js";
3
4
  export { STORAGE_MEMORY_SCALES, STORAGE_READ_BENCHMARKS, STORAGE_WRITE_BENCHMARKS, seedStorageBenchmark, seedStorageWriteBenchmark, storageBenchmarkPrimaryRecordCount, TIMING_SCALE, } from "./storage-benchmark.js";
4
5
  export { createStorageConformance } from "./storage-conformance.js";
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAmB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAiC,MAAM,aAAa,CAAC;AACxF,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EAKxB,oBAAoB,EACpB,yBAAyB,EACzB,kCAAkC,EAClC,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["export { createExpectAssertions, type ExpectLike } from \"./assertions.ts\";\nexport { registerStorageConformance, type StorageConformanceRunner } from \"./runner.ts\";\nexport {\n\tSTORAGE_MEMORY_SCALES,\n\tSTORAGE_READ_BENCHMARKS,\n\tSTORAGE_WRITE_BENCHMARKS,\n\ttype StorageBenchmarkDataset,\n\ttype StorageBenchmarkScale,\n\ttype StorageReadBenchmark,\n\ttype StorageWriteBenchmark,\n\tseedStorageBenchmark,\n\tseedStorageWriteBenchmark,\n\tstorageBenchmarkPrimaryRecordCount,\n\tTIMING_SCALE,\n} from \"./storage-benchmark.ts\";\nexport { createStorageConformance } from \"./storage-conformance.ts\";\nexport type {\n\tStorageConformanceAssertions,\n\tStorageConformanceCase,\n\tStorageConformanceOptions,\n\tStorageConformanceProvider,\n} from \"./types.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAmB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAiC,MAAM,aAAa,CAAC;AAChH,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EAKxB,oBAAoB,EACpB,yBAAyB,EACzB,kCAAkC,EAClC,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["export { createExpectAssertions, type ExpectLike } from \"./assertions.ts\";\nexport { createEnvConformance } from \"./env-conformance.ts\";\nexport { registerEnvConformance, registerStorageConformance, type StorageConformanceRunner } from \"./runner.ts\";\nexport {\n\tSTORAGE_MEMORY_SCALES,\n\tSTORAGE_READ_BENCHMARKS,\n\tSTORAGE_WRITE_BENCHMARKS,\n\ttype StorageBenchmarkDataset,\n\ttype StorageBenchmarkScale,\n\ttype StorageReadBenchmark,\n\ttype StorageWriteBenchmark,\n\tseedStorageBenchmark,\n\tseedStorageWriteBenchmark,\n\tstorageBenchmarkPrimaryRecordCount,\n\tTIMING_SCALE,\n} from \"./storage-benchmark.ts\";\nexport { createStorageConformance } from \"./storage-conformance.ts\";\nexport type {\n\tEnvConformanceAssertions,\n\tEnvConformanceCase,\n\tEnvConformanceOptions,\n\tEnvConformanceProvider,\n\tStorageConformanceAssertions,\n\tStorageConformanceCase,\n\tStorageConformanceOptions,\n\tStorageConformanceProvider,\n} from \"./types.ts\";\n"]}
@@ -1,10 +1,12 @@
1
1
  import { type ExpectLike } from "./assertions.ts";
2
- import type { StorageConformanceProvider } from "./types.ts";
2
+ import type { EnvConformanceOptions, EnvConformanceProvider, StorageConformanceProvider } from "./types.ts";
3
3
  export interface StorageConformanceRunner {
4
4
  readonly describe: (name: string, suite: () => void) => unknown;
5
5
  readonly expect: ExpectLike;
6
- readonly it: (name: string, test: () => Promise<void>) => unknown;
6
+ readonly it: (name: string, test: () => Promise<void>, timeoutMs?: number) => unknown;
7
7
  }
8
8
  /** Registers the runner-independent cases with a Vitest/Jest-compatible test runner. */
9
9
  export declare function registerStorageConformance(runner: StorageConformanceRunner, name: string, withStorage: StorageConformanceProvider): void;
10
+ /** Registers the runner-independent `ExecutionEnv` cases with a Vitest/Jest-compatible test runner. */
11
+ export declare function registerEnvConformance(runner: StorageConformanceRunner, name: string, withEnv: EnvConformanceProvider, options?: Pick<EnvConformanceOptions, "shell" | "symlinks">): void;
10
12
  //# sourceMappingURL=runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,OAAO,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC;CAClE;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,0BAA0B,GACrC,IAAI,CAQN"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE5G,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,OAAO,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;CACtF;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,0BAA0B,GACrC,IAAI,CAQN;AAED,uGAAuG;AACvG,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,sBAAsB,EAC/B,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,UAAU,CAAM,GAC7D,IAAI,CAKN"}
@@ -1,4 +1,5 @@
1
1
  import { createExpectAssertions } from "./assertions.js";
2
+ import { createEnvConformance } from "./env-conformance.js";
2
3
  import { createStorageConformance } from "./storage-conformance.js";
3
4
  /** Registers the runner-independent cases with a Vitest/Jest-compatible test runner. */
4
5
  export function registerStorageConformance(runner, name, withStorage) {
@@ -11,4 +12,12 @@ export function registerStorageConformance(runner, name, withStorage) {
11
12
  runner.it(testCase.name, testCase.run);
12
13
  });
13
14
  }
15
+ /** Registers the runner-independent `ExecutionEnv` cases with a Vitest/Jest-compatible test runner. */
16
+ export function registerEnvConformance(runner, name, withEnv, options = {}) {
17
+ const cases = createEnvConformance({ ...options, assertions: createExpectAssertions(runner.expect), withEnv });
18
+ runner.describe(name, () => {
19
+ for (const testCase of cases)
20
+ runner.it(testCase.name, testCase.run, testCase.timeoutMs);
21
+ });
22
+ }
14
23
  //# sourceMappingURL=runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAmB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AASpE,wFAAwF;AACxF,MAAM,UAAU,0BAA0B,CACzC,MAAgC,EAChC,IAAY,EACZ,WAAuC;IAEvC,MAAM,KAAK,GAAG,wBAAwB,CAAC;QACtC,UAAU,EAAE,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC;QACjD,WAAW;KACX,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QAC1B,KAAK,MAAM,QAAQ,IAAI,KAAK;YAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { createExpectAssertions, type ExpectLike } from \"./assertions.ts\";\nimport { createStorageConformance } from \"./storage-conformance.ts\";\nimport type { StorageConformanceProvider } from \"./types.ts\";\n\nexport interface StorageConformanceRunner {\n\treadonly describe: (name: string, suite: () => void) => unknown;\n\treadonly expect: ExpectLike;\n\treadonly it: (name: string, test: () => Promise<void>) => unknown;\n}\n\n/** Registers the runner-independent cases with a Vitest/Jest-compatible test runner. */\nexport function registerStorageConformance(\n\trunner: StorageConformanceRunner,\n\tname: string,\n\twithStorage: StorageConformanceProvider,\n): void {\n\tconst cases = createStorageConformance({\n\t\tassertions: createExpectAssertions(runner.expect),\n\t\twithStorage,\n\t});\n\trunner.describe(name, () => {\n\t\tfor (const testCase of cases) runner.it(testCase.name, testCase.run);\n\t});\n}\n"]}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAmB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AASpE,wFAAwF;AACxF,MAAM,UAAU,0BAA0B,CACzC,MAAgC,EAChC,IAAY,EACZ,WAAuC;IAEvC,MAAM,KAAK,GAAG,wBAAwB,CAAC;QACtC,UAAU,EAAE,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC;QACjD,WAAW;KACX,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QAC1B,KAAK,MAAM,QAAQ,IAAI,KAAK;YAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,sBAAsB,CACrC,MAAgC,EAChC,IAAY,EACZ,OAA+B,EAC/B,OAAO,GAAsD,EAAE;IAE/D,MAAM,KAAK,GAAG,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/G,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QAC1B,KAAK,MAAM,QAAQ,IAAI,KAAK;YAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { createExpectAssertions, type ExpectLike } from \"./assertions.ts\";\nimport { createEnvConformance } from \"./env-conformance.ts\";\nimport { createStorageConformance } from \"./storage-conformance.ts\";\nimport type { EnvConformanceOptions, EnvConformanceProvider, StorageConformanceProvider } from \"./types.ts\";\n\nexport interface StorageConformanceRunner {\n\treadonly describe: (name: string, suite: () => void) => unknown;\n\treadonly expect: ExpectLike;\n\treadonly it: (name: string, test: () => Promise<void>, timeoutMs?: number) => unknown;\n}\n\n/** Registers the runner-independent cases with a Vitest/Jest-compatible test runner. */\nexport function registerStorageConformance(\n\trunner: StorageConformanceRunner,\n\tname: string,\n\twithStorage: StorageConformanceProvider,\n): void {\n\tconst cases = createStorageConformance({\n\t\tassertions: createExpectAssertions(runner.expect),\n\t\twithStorage,\n\t});\n\trunner.describe(name, () => {\n\t\tfor (const testCase of cases) runner.it(testCase.name, testCase.run);\n\t});\n}\n\n/** Registers the runner-independent `ExecutionEnv` cases with a Vitest/Jest-compatible test runner. */\nexport function registerEnvConformance(\n\trunner: StorageConformanceRunner,\n\tname: string,\n\twithEnv: EnvConformanceProvider,\n\toptions: Pick<EnvConformanceOptions, \"shell\" | \"symlinks\"> = {},\n): void {\n\tconst cases = createEnvConformance({ ...options, assertions: createExpectAssertions(runner.expect), withEnv });\n\trunner.describe(name, () => {\n\t\tfor (const testCase of cases) runner.it(testCase.name, testCase.run, testCase.timeoutMs);\n\t});\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ExecutionEnv } from "../env/index.ts";
1
2
  import type { Storage } from "../types.ts";
2
3
  export interface StorageConformanceAssertions {
3
4
  ok(value: unknown, message?: string): void;
@@ -16,4 +17,21 @@ export interface StorageConformanceCase {
16
17
  readonly name: string;
17
18
  run(): Promise<void>;
18
19
  }
20
+ export type EnvConformanceAssertions = StorageConformanceAssertions;
21
+ /** Calls `use` once with an environment whose `cwd` is a fresh, empty, writable directory, then cleans up. */
22
+ export type EnvConformanceProvider = (use: (env: ExecutionEnv) => Promise<void>) => Promise<void>;
23
+ export interface EnvConformanceOptions {
24
+ readonly assertions: EnvConformanceAssertions;
25
+ readonly withEnv: EnvConformanceProvider;
26
+ /** Program and flag that run a POSIX shell script from the next argument; default `["sh", "-c"]`. */
27
+ readonly shell?: readonly string[];
28
+ /** Whether the shell's `ln -s` creates symbolic links; default true. */
29
+ readonly symlinks?: boolean;
30
+ }
31
+ export interface EnvConformanceCase {
32
+ readonly name: string;
33
+ /** Cases that wait for an environment's watch latency need longer than a test runner's default timeout. */
34
+ readonly timeoutMs?: number;
35
+ run(): Promise<void>;
36
+ }
19
37
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,4BAA4B;IAC5C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACtD,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3D,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E;AAED,MAAM,MAAM,0BAA0B,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErG,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,UAAU,EAAE,4BAA4B,CAAC;IAClD,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC;CACjD;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,4BAA4B;IAC5C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACtD,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3D,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E;AAED,MAAM,MAAM,0BAA0B,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErG,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,UAAU,EAAE,4BAA4B,CAAC;IAClD,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC;CACjD;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,CAAC;AAEpE,8GAA8G;AAC9G,MAAM,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAElG,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,qGAAqG;IACrG,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2GAA2G;IAC3G,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Storage } from \"../types.ts\";\n\nexport interface StorageConformanceAssertions {\n\tok(value: unknown, message?: string): void;\n\tstrictEqual(actual: unknown, expected: unknown): void;\n\tdeepEqual(actual: unknown, expected: unknown): void;\n\tpartialDeepEqual(actual: unknown, expected: unknown): void;\n\tgreaterThan(actual: number, expected: number): void;\n\trejects(operation: Promise<unknown>, messageIncludes: string): Promise<void>;\n}\n\nexport type StorageConformanceProvider = (use: (storage: Storage) => Promise<void>) => Promise<void>;\n\nexport interface StorageConformanceOptions {\n\treadonly assertions: StorageConformanceAssertions;\n\treadonly withStorage: StorageConformanceProvider;\n}\n\nexport interface StorageConformanceCase {\n\treadonly name: string;\n\trun(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ExecutionEnv } from \"../env/index.ts\";\nimport type { Storage } from \"../types.ts\";\n\nexport interface StorageConformanceAssertions {\n\tok(value: unknown, message?: string): void;\n\tstrictEqual(actual: unknown, expected: unknown): void;\n\tdeepEqual(actual: unknown, expected: unknown): void;\n\tpartialDeepEqual(actual: unknown, expected: unknown): void;\n\tgreaterThan(actual: number, expected: number): void;\n\trejects(operation: Promise<unknown>, messageIncludes: string): Promise<void>;\n}\n\nexport type StorageConformanceProvider = (use: (storage: Storage) => Promise<void>) => Promise<void>;\n\nexport interface StorageConformanceOptions {\n\treadonly assertions: StorageConformanceAssertions;\n\treadonly withStorage: StorageConformanceProvider;\n}\n\nexport interface StorageConformanceCase {\n\treadonly name: string;\n\trun(): Promise<void>;\n}\n\nexport type EnvConformanceAssertions = StorageConformanceAssertions;\n\n/** Calls `use` once with an environment whose `cwd` is a fresh, empty, writable directory, then cleans up. */\nexport type EnvConformanceProvider = (use: (env: ExecutionEnv) => Promise<void>) => Promise<void>;\n\nexport interface EnvConformanceOptions {\n\treadonly assertions: EnvConformanceAssertions;\n\treadonly withEnv: EnvConformanceProvider;\n\t/** Program and flag that run a POSIX shell script from the next argument; default `[\"sh\", \"-c\"]`. */\n\treadonly shell?: readonly string[];\n\t/** Whether the shell's `ln -s` creates symbolic links; default true. */\n\treadonly symlinks?: boolean;\n}\n\nexport interface EnvConformanceCase {\n\treadonly name: string;\n\t/** Cases that wait for an environment's watch latency need longer than a test runner's default timeout. */\n\treadonly timeoutMs?: number;\n\trun(): Promise<void>;\n}\n"]}
@@ -19,7 +19,8 @@ export interface BashToolOptions {
19
19
  }
20
20
  /**
21
21
  * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the
22
- * tail within the default limits; the result content is that retained output. Output beyond the limits is spilled to a
22
+ * tail within the default limits; the result content is that retained output. The retained window goes to the
23
+ * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output beyond the limits is spilled to a
23
24
  * file whose path is reported as a diagnostic. A nonzero exit or timeout throws, which makes an error result that still
24
25
  * carries the output and diagnostics.
25
26
  */
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM9E,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtH,MAAM,WAAW,eAAe;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,gBAAgB,CAAC,OAAO,UAAU,CAAC,CA2C7F"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM9E,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtH,MAAM,WAAW,eAAe;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAYD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,gBAAgB,CAAC,OAAO,UAAU,CAAC,CA6C7F"}
@@ -19,7 +19,8 @@ function validateTimeout(timeout) {
19
19
  }
20
20
  /**
21
21
  * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the
22
- * tail within the default limits; the result content is that retained output. Output beyond the limits is spilled to a
22
+ * tail within the default limits; the result content is that retained output. The retained window goes to the
23
+ * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output beyond the limits is spilled to a
23
24
  * file whose path is reported as a diagnostic. A nonzero exit or timeout throws, which makes an error result that still
24
25
  * carries the output and diagnostics.
25
26
  */
@@ -45,8 +46,10 @@ export function createBashTool(options) {
45
46
  env: execution.env,
46
47
  inheritEnv: execution.inheritEnv,
47
48
  ...(timeout === undefined ? {} : { timeout }),
48
- onOutput: (text) => api.output(text),
49
+ onOutput: (text, _context, info) => api.output(text, info.skipped),
49
50
  spill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },
51
+ // An environment may then omit output outside the retained tail and report the omission.
52
+ ...(api.outputWindow === undefined ? {} : { window: api.outputWindow }),
50
53
  }, context);
51
54
  const spillPath = result.ok ? result.value.spillPath : result.error.spillPath;
52
55
  if (spillPath !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { type Static, Type } from \"typebox\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolExecutionApi, ToolRegistration } from \"../harness/types.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from \"../truncate.ts\";\nimport { requireEnv } from \"./env.ts\";\n\nconst MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashExecution {\n\tcommand: string;\n\tcwd: string;\n\tenv: Record<string, string>;\n\tinheritEnv: boolean;\n}\n\nexport type BashPrepare = (execution: BashExecution, api: ToolExecutionApi, context: Context) => void | Promise<void>;\n\nexport interface BashToolOptions {\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n}\n\nfunction validateTimeout(timeout: number | undefined): void {\n\tif (timeout === undefined) return;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\tif (timeout > MAX_TIMEOUT_SECONDS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n}\n\n/**\n * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the\n * tail within the default limits; the result content is that retained output. Output beyond the limits is spilled to a\n * file whose path is reported as a diagnostic. A nonzero exit or timeout throws, which makes an error result that still\n * carries the output and diagnostics.\n */\nexport function createBashTool(options?: BashToolOptions): ToolRegistration<typeof bashSchema> {\n\treturn defineTool({\n\t\tname: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: bashSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tconst { command, timeout } = args;\n\t\t\tvalidateTimeout(timeout);\n\t\t\tconst env = requireEnv(api);\n\t\t\tconst execution: BashExecution = {\n\t\t\t\tcommand: options?.commandPrefix ? `${options.commandPrefix}\\n${command}` : command,\n\t\t\t\tcwd: env.cwd,\n\t\t\t\tenv: {},\n\t\t\t\tinheritEnv: true,\n\t\t\t};\n\t\t\tawait options?.prepare?.(execution, api, context);\n\t\t\tconst result = await env.exec(\n\t\t\t\texecution.command,\n\t\t\t\t{\n\t\t\t\t\tcwd: execution.cwd,\n\t\t\t\t\tenv: execution.env,\n\t\t\t\t\tinheritEnv: execution.inheritEnv,\n\t\t\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t\t\tonOutput: (text) => api.output(text),\n\t\t\t\t\tspill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst spillPath = result.ok ? result.value.spillPath : result.error.spillPath;\n\t\t\tif (spillPath !== undefined) {\n\t\t\t\tapi.diagnostic({ severity: \"info\", code: \"full_output\", message: `Full output: ${spillPath}` });\n\t\t\t}\n\t\t\tif (!result.ok) {\n\t\t\t\tif (result.error.code === \"aborted\" && context.abortSignal?.aborted) throw result.error;\n\t\t\t\tif (result.error.code === \"timeout\") throw new Error(`Command timed out after ${timeout} seconds`);\n\t\t\t\tif (result.error.code === \"aborted\") throw new Error(\"Command aborted\");\n\t\t\t\tthrow result.error;\n\t\t\t}\n\t\t\tif (result.value.exitCode !== 0) throw new Error(`Command exited with code ${result.value.exitCode}`);\n\t\t\treturn {};\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { type Static, Type } from \"typebox\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolExecutionApi, ToolRegistration } from \"../harness/types.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from \"../truncate.ts\";\nimport { requireEnv } from \"./env.ts\";\n\nconst MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashExecution {\n\tcommand: string;\n\tcwd: string;\n\tenv: Record<string, string>;\n\tinheritEnv: boolean;\n}\n\nexport type BashPrepare = (execution: BashExecution, api: ToolExecutionApi, context: Context) => void | Promise<void>;\n\nexport interface BashToolOptions {\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n}\n\nfunction validateTimeout(timeout: number | undefined): void {\n\tif (timeout === undefined) return;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\tif (timeout > MAX_TIMEOUT_SECONDS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n}\n\n/**\n * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the\n * tail within the default limits; the result content is that retained output. The retained window goes to the\n * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output beyond the limits is spilled to a\n * file whose path is reported as a diagnostic. A nonzero exit or timeout throws, which makes an error result that still\n * carries the output and diagnostics.\n */\nexport function createBashTool(options?: BashToolOptions): ToolRegistration<typeof bashSchema> {\n\treturn defineTool({\n\t\tname: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: bashSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tconst { command, timeout } = args;\n\t\t\tvalidateTimeout(timeout);\n\t\t\tconst env = requireEnv(api);\n\t\t\tconst execution: BashExecution = {\n\t\t\t\tcommand: options?.commandPrefix ? `${options.commandPrefix}\\n${command}` : command,\n\t\t\t\tcwd: env.cwd,\n\t\t\t\tenv: {},\n\t\t\t\tinheritEnv: true,\n\t\t\t};\n\t\t\tawait options?.prepare?.(execution, api, context);\n\t\t\tconst result = await env.exec(\n\t\t\t\texecution.command,\n\t\t\t\t{\n\t\t\t\t\tcwd: execution.cwd,\n\t\t\t\t\tenv: execution.env,\n\t\t\t\t\tinheritEnv: execution.inheritEnv,\n\t\t\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t\t\tonOutput: (text, _context, info) => api.output(text, info.skipped),\n\t\t\t\t\tspill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },\n\t\t\t\t\t// An environment may then omit output outside the retained tail and report the omission.\n\t\t\t\t\t...(api.outputWindow === undefined ? {} : { window: api.outputWindow }),\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst spillPath = result.ok ? result.value.spillPath : result.error.spillPath;\n\t\t\tif (spillPath !== undefined) {\n\t\t\t\tapi.diagnostic({ severity: \"info\", code: \"full_output\", message: `Full output: ${spillPath}` });\n\t\t\t}\n\t\t\tif (!result.ok) {\n\t\t\t\tif (result.error.code === \"aborted\" && context.abortSignal?.aborted) throw result.error;\n\t\t\t\tif (result.error.code === \"timeout\") throw new Error(`Command timed out after ${timeout} seconds`);\n\t\t\t\tif (result.error.code === \"aborted\") throw new Error(\"Command aborted\");\n\t\t\t\tthrow result.error;\n\t\t\t}\n\t\t\tif (result.value.exitCode !== 0) throw new Error(`Command exited with code ${result.value.exitCode}`);\n\t\t\treturn {};\n\t\t},\n\t});\n}\n"]}
@@ -1,2 +1,12 @@
1
+ /** Positional reads of a file of `size` bytes. */
2
+ export type ByteSource = {
3
+ readonly size: number;
4
+ read(offset: number, length: number): Promise<Uint8Array>;
5
+ };
6
+ /**
7
+ * `detectSupportedImageMimeType` of a whole file, reading only its header and, for PNG, the chunk headers up to the
8
+ * first `acTL` or `IDAT`.
9
+ */
10
+ export declare function detectSupportedImageMimeTypeOf(source: ByteSource): Promise<string | undefined>;
1
11
  export declare function detectSupportedImageMimeType(buffer: Uint8Array): string | undefined;
2
12
  //# sourceMappingURL=image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/tools/image.ts"],"names":[],"mappings":"AAEA,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAOnF"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/tools/image.ts"],"names":[],"mappings":"AAKA,kDAAkD;AAClD,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1D,CAAC;AAEF;;;GAGG;AACH,wBAAsB,8BAA8B,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIpG;AA0BD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAOnF"}
@@ -1,4 +1,43 @@
1
1
  const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
2
+ /** Bytes every check except the APNG chunk walk needs: BMP reads up to offset 29. */
3
+ const HEADER_BYTES = 32;
4
+ const BLOCK_BYTES = 64 * 1024;
5
+ /**
6
+ * `detectSupportedImageMimeType` of a whole file, reading only its header and, for PNG, the chunk headers up to the
7
+ * first `acTL` or `IDAT`.
8
+ */
9
+ export async function detectSupportedImageMimeTypeOf(source) {
10
+ const header = await source.read(0, HEADER_BYTES);
11
+ if (!startsWith(header, PNG_SIGNATURE))
12
+ return detectSupportedImageMimeType(header);
13
+ return isPng(header) && !(await isAnimatedPngOf(source)) ? "image/png" : undefined;
14
+ }
15
+ /** `isAnimatedPng` over a file read in blocks. */
16
+ async function isAnimatedPngOf(source) {
17
+ let block = new Uint8Array(0);
18
+ let blockStart = 0;
19
+ const bytesAt = async (offset, length) => {
20
+ if (offset < blockStart || offset + length > blockStart + block.length) {
21
+ blockStart = offset;
22
+ block = await source.read(offset, BLOCK_BYTES);
23
+ }
24
+ return block.subarray(offset - blockStart, offset - blockStart + length);
25
+ };
26
+ let offset = PNG_SIGNATURE.length;
27
+ while (offset + 8 <= source.size) {
28
+ const chunkHeader = await bytesAt(offset, 8);
29
+ const chunkLength = readUint32BE(chunkHeader, 0);
30
+ if (startsWithAscii(chunkHeader, 4, "acTL"))
31
+ return true;
32
+ if (startsWithAscii(chunkHeader, 4, "IDAT"))
33
+ return false;
34
+ const nextOffset = offset + 8 + chunkLength + 4;
35
+ if (nextOffset <= offset || nextOffset > source.size)
36
+ return false;
37
+ offset = nextOffset;
38
+ }
39
+ return false;
40
+ }
2
41
  export function detectSupportedImageMimeType(buffer) {
3
42
  if (startsWith(buffer, [0xff, 0xd8, 0xff]))
4
43
  return buffer[3] === 0xf7 ? undefined : "image/jpeg";
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/tools/image.ts"],"names":[],"mappings":"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","sourcesContent":["const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nexport function detectSupportedImageMimeType(buffer: Uint8Array): string | undefined {\n\tif (startsWith(buffer, [0xff, 0xd8, 0xff])) return buffer[3] === 0xf7 ? undefined : \"image/jpeg\";\n\tif (startsWith(buffer, PNG_SIGNATURE)) return isPng(buffer) && !isAnimatedPng(buffer) ? \"image/png\" : undefined;\n\tif (startsWithAscii(buffer, 0, \"GIF87a\") || startsWithAscii(buffer, 0, \"GIF89a\")) return \"image/gif\";\n\tif (startsWithAscii(buffer, 0, \"RIFF\") && startsWithAscii(buffer, 8, \"WEBP\")) return \"image/webp\";\n\tif (startsWithAscii(buffer, 0, \"BM\") && isBmp(buffer)) return \"image/bmp\";\n\treturn undefined;\n}\n\nfunction isPng(buffer: Uint8Array): boolean {\n\treturn (\n\t\tbuffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, \"IHDR\")\n\t);\n}\n\nfunction isAnimatedPng(buffer: Uint8Array): boolean {\n\tlet offset = PNG_SIGNATURE.length;\n\twhile (offset + 8 <= buffer.length) {\n\t\tconst chunkLength = readUint32BE(buffer, offset);\n\t\tconst chunkTypeOffset = offset + 4;\n\t\tif (startsWithAscii(buffer, chunkTypeOffset, \"acTL\")) return true;\n\t\tif (startsWithAscii(buffer, chunkTypeOffset, \"IDAT\")) return false;\n\t\tconst nextOffset = offset + 8 + chunkLength + 4;\n\t\tif (nextOffset <= offset || nextOffset > buffer.length) return false;\n\t\toffset = nextOffset;\n\t}\n\treturn false;\n}\n\nfunction isBmp(buffer: Uint8Array): boolean {\n\tif (buffer.length < 26) return false;\n\tconst declaredFileSize = readUint32LE(buffer, 2);\n\tconst pixelDataOffset = readUint32LE(buffer, 10);\n\tconst dibHeaderSize = readUint32LE(buffer, 14);\n\tif (declaredFileSize !== 0 && declaredFileSize < 26) return false;\n\tif (pixelDataOffset < 14 + dibHeaderSize) return false;\n\tif (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize) return false;\n\n\tlet colorPlanes: number;\n\tlet bitsPerPixel: number;\n\tif (dibHeaderSize === 12) {\n\t\tcolorPlanes = readUint16LE(buffer, 22);\n\t\tbitsPerPixel = readUint16LE(buffer, 24);\n\t} else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {\n\t\tif (buffer.length < 30) return false;\n\t\tcolorPlanes = readUint16LE(buffer, 26);\n\t\tbitsPerPixel = readUint16LE(buffer, 28);\n\t} else {\n\t\treturn false;\n\t}\n\treturn colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);\n}\n\nfunction readUint16LE(buffer: Uint8Array, offset: number): number {\n\treturn (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);\n}\n\nfunction readUint32BE(buffer: Uint8Array, offset: number): number {\n\treturn (\n\t\t(buffer[offset] ?? 0) * 0x1000000 +\n\t\t((buffer[offset + 1] ?? 0) << 16) +\n\t\t((buffer[offset + 2] ?? 0) << 8) +\n\t\t(buffer[offset + 3] ?? 0)\n\t);\n}\n\nfunction readUint32LE(buffer: Uint8Array, offset: number): number {\n\treturn (\n\t\t(buffer[offset] ?? 0) +\n\t\t((buffer[offset + 1] ?? 0) << 8) +\n\t\t((buffer[offset + 2] ?? 0) << 16) +\n\t\t(buffer[offset + 3] ?? 0) * 0x1000000\n\t);\n}\n\nfunction startsWith(buffer: Uint8Array, bytes: number[]): boolean {\n\tif (buffer.length < bytes.length) return false;\n\treturn bytes.every((byte, index) => buffer[index] === byte);\n}\n\nfunction startsWithAscii(buffer: Uint8Array, offset: number, text: string): boolean {\n\tif (buffer.length < offset + text.length) return false;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (buffer[offset + index] !== text.charCodeAt(index)) return false;\n\t}\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/tools/image.ts"],"names":[],"mappings":"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","sourcesContent":["const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n/** Bytes every check except the APNG chunk walk needs: BMP reads up to offset 29. */\nconst HEADER_BYTES = 32;\nconst BLOCK_BYTES = 64 * 1024;\n\n/** Positional reads of a file of `size` bytes. */\nexport type ByteSource = {\n\treadonly size: number;\n\tread(offset: number, length: number): Promise<Uint8Array>;\n};\n\n/**\n * `detectSupportedImageMimeType` of a whole file, reading only its header and, for PNG, the chunk headers up to the\n * first `acTL` or `IDAT`.\n */\nexport async function detectSupportedImageMimeTypeOf(source: ByteSource): Promise<string | undefined> {\n\tconst header = await source.read(0, HEADER_BYTES);\n\tif (!startsWith(header, PNG_SIGNATURE)) return detectSupportedImageMimeType(header);\n\treturn isPng(header) && !(await isAnimatedPngOf(source)) ? \"image/png\" : undefined;\n}\n\n/** `isAnimatedPng` over a file read in blocks. */\nasync function isAnimatedPngOf(source: ByteSource): Promise<boolean> {\n\tlet block: Uint8Array = new Uint8Array(0);\n\tlet blockStart = 0;\n\tconst bytesAt = async (offset: number, length: number): Promise<Uint8Array> => {\n\t\tif (offset < blockStart || offset + length > blockStart + block.length) {\n\t\t\tblockStart = offset;\n\t\t\tblock = await source.read(offset, BLOCK_BYTES);\n\t\t}\n\t\treturn block.subarray(offset - blockStart, offset - blockStart + length);\n\t};\n\tlet offset = PNG_SIGNATURE.length;\n\twhile (offset + 8 <= source.size) {\n\t\tconst chunkHeader = await bytesAt(offset, 8);\n\t\tconst chunkLength = readUint32BE(chunkHeader, 0);\n\t\tif (startsWithAscii(chunkHeader, 4, \"acTL\")) return true;\n\t\tif (startsWithAscii(chunkHeader, 4, \"IDAT\")) return false;\n\t\tconst nextOffset = offset + 8 + chunkLength + 4;\n\t\tif (nextOffset <= offset || nextOffset > source.size) return false;\n\t\toffset = nextOffset;\n\t}\n\treturn false;\n}\n\nexport function detectSupportedImageMimeType(buffer: Uint8Array): string | undefined {\n\tif (startsWith(buffer, [0xff, 0xd8, 0xff])) return buffer[3] === 0xf7 ? undefined : \"image/jpeg\";\n\tif (startsWith(buffer, PNG_SIGNATURE)) return isPng(buffer) && !isAnimatedPng(buffer) ? \"image/png\" : undefined;\n\tif (startsWithAscii(buffer, 0, \"GIF87a\") || startsWithAscii(buffer, 0, \"GIF89a\")) return \"image/gif\";\n\tif (startsWithAscii(buffer, 0, \"RIFF\") && startsWithAscii(buffer, 8, \"WEBP\")) return \"image/webp\";\n\tif (startsWithAscii(buffer, 0, \"BM\") && isBmp(buffer)) return \"image/bmp\";\n\treturn undefined;\n}\n\nfunction isPng(buffer: Uint8Array): boolean {\n\treturn (\n\t\tbuffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, \"IHDR\")\n\t);\n}\n\nfunction isAnimatedPng(buffer: Uint8Array): boolean {\n\tlet offset = PNG_SIGNATURE.length;\n\twhile (offset + 8 <= buffer.length) {\n\t\tconst chunkLength = readUint32BE(buffer, offset);\n\t\tconst chunkTypeOffset = offset + 4;\n\t\tif (startsWithAscii(buffer, chunkTypeOffset, \"acTL\")) return true;\n\t\tif (startsWithAscii(buffer, chunkTypeOffset, \"IDAT\")) return false;\n\t\tconst nextOffset = offset + 8 + chunkLength + 4;\n\t\tif (nextOffset <= offset || nextOffset > buffer.length) return false;\n\t\toffset = nextOffset;\n\t}\n\treturn false;\n}\n\nfunction isBmp(buffer: Uint8Array): boolean {\n\tif (buffer.length < 26) return false;\n\tconst declaredFileSize = readUint32LE(buffer, 2);\n\tconst pixelDataOffset = readUint32LE(buffer, 10);\n\tconst dibHeaderSize = readUint32LE(buffer, 14);\n\tif (declaredFileSize !== 0 && declaredFileSize < 26) return false;\n\tif (pixelDataOffset < 14 + dibHeaderSize) return false;\n\tif (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize) return false;\n\n\tlet colorPlanes: number;\n\tlet bitsPerPixel: number;\n\tif (dibHeaderSize === 12) {\n\t\tcolorPlanes = readUint16LE(buffer, 22);\n\t\tbitsPerPixel = readUint16LE(buffer, 24);\n\t} else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {\n\t\tif (buffer.length < 30) return false;\n\t\tcolorPlanes = readUint16LE(buffer, 26);\n\t\tbitsPerPixel = readUint16LE(buffer, 28);\n\t} else {\n\t\treturn false;\n\t}\n\treturn colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);\n}\n\nfunction readUint16LE(buffer: Uint8Array, offset: number): number {\n\treturn (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);\n}\n\nfunction readUint32BE(buffer: Uint8Array, offset: number): number {\n\treturn (\n\t\t(buffer[offset] ?? 0) * 0x1000000 +\n\t\t((buffer[offset + 1] ?? 0) << 16) +\n\t\t((buffer[offset + 2] ?? 0) << 8) +\n\t\t(buffer[offset + 3] ?? 0)\n\t);\n}\n\nfunction readUint32LE(buffer: Uint8Array, offset: number): number {\n\treturn (\n\t\t(buffer[offset] ?? 0) +\n\t\t((buffer[offset + 1] ?? 0) << 8) +\n\t\t((buffer[offset + 2] ?? 0) << 16) +\n\t\t(buffer[offset + 3] ?? 0) * 0x1000000\n\t);\n}\n\nfunction startsWith(buffer: Uint8Array, bytes: number[]): boolean {\n\tif (buffer.length < bytes.length) return false;\n\treturn bytes.every((byte, index) => buffer[index] === byte);\n}\n\nfunction startsWithAscii(buffer: Uint8Array, offset: number, text: string): boolean {\n\tif (buffer.length < offset + text.length) return false;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (buffer[offset + index] !== text.charCodeAt(index)) return false;\n\t}\n\treturn true;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,KAAK,EAAkB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,gBAAgB,CAAC;AAKvH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;CAC/C,CAAC;AAEF,kHAAkH;AAClH,wBAAgB,cAAc,IAAI,gBAAgB,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,CAsFrF"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAW5C,OAAO,KAAK,EAAkB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAIN,KAAK,gBAAgB,EAGrB,MAAM,gBAAgB,CAAC;AAKxB,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;CAC/C,CAAC;AAmCF,kHAAkH;AAClH,wBAAgB,cAAc,IAAI,gBAAgB,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,CAwBrF"}