From 2ca6f8759a72e44d79657b28345ddda826c0a305 Mon Sep 17 00:00:00 2001 From: Eric Siebeneich Date: Thu, 24 Sep 2026 10:34:30 -0500 Subject: [PATCH 1/4] ignore the .work-items folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c7233d8..7fd9038 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ coverage/ .DS_Store .wireit/ .codegraph/ +.work-items/ clanker-cleanroom.images.json From 7bb5697f8a875f9b8823eb21eedf42b2dcfdc21a Mon Sep 17 00:00:00 2001 From: bdd-workflow Date: Thu, 24 Sep 2026 10:48:23 -0500 Subject: [PATCH 2/4] =?UTF-8?q?bdd:=20GH-11=20=E2=80=94=20Accept=20large?= =?UTF-8?q?=20prompts=20over=20stdin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/binding.command.spec.ts | 23 +- .../clanker-cleanroom-claude/src/binding.ts | 3 +- .../src/binding.command.spec.ts | 22 +- .../clanker-cleanroom-cursor/src/binding.ts | 3 +- .../src/agents/docker.spec.ts | 14 ++ .../clanker-cleanroom/src/agents/docker.ts | 12 +- .../src/agents/run-bound.stdin-prompt.spec.ts | 229 ++++++++++++++++++ .../clanker-cleanroom/src/agents/run-bound.ts | 1 + .../clanker-cleanroom/src/agents/types.ts | 2 + 9 files changed, 296 insertions(+), 13 deletions(-) create mode 100644 packages/clanker-cleanroom/src/agents/run-bound.stdin-prompt.spec.ts diff --git a/packages/clanker-cleanroom-claude/src/binding.command.spec.ts b/packages/clanker-cleanroom-claude/src/binding.command.spec.ts index bba3bac..3e085c2 100644 --- a/packages/clanker-cleanroom-claude/src/binding.command.spec.ts +++ b/packages/clanker-cleanroom-claude/src/binding.command.spec.ts @@ -95,6 +95,15 @@ describe("claudeBinding.command", () => { includes_resume_flag, }, }); + + test("omits the raw prompt from argv so the CLI reads it from stdin", { + when: { + building_claude_command, + }, + then: { + command_omits_raw_prompt, + }, + }); }); function oauth_token_credentials(this: Context) { @@ -121,6 +130,10 @@ function building_docker_args_with_session(this: Context) { this.args = dockerArgs(this.credentials, { sessionId: "sess-claude-1" }); } +function building_claude_command(this: Context) { + this.args = claudeBinding.command({ prompt: "Create a README" }); +} + function dockerArgs( credentials: ClaudeCredentials, options: { model?: string; sessionId?: string } = {}, @@ -214,20 +227,22 @@ function invokes_claude_headless_with_json_output(this: Context) { expect(this.args).toContain("stream-json"); expect(this.args).toContain("--verbose"); expect(this.args).toContain("--dangerously-skip-permissions"); - expect(this.args.at(-2)).toBe("--"); - expect(this.args.at(-1)).toBe("Create a README"); + expect(this.args.includes("Create a README")).toBe(false); +} + +function command_omits_raw_prompt(this: Context) { + expect(this.args.includes("Create a README")).toBe(false); + expect(this.args.at(-1)).not.toBe("--"); } function includes_model_flag(this: Context) { const modelIndex = this.args.indexOf("--model"); expect(modelIndex).toBeGreaterThan(-1); expect(this.args[modelIndex + 1]).toBe("sonnet"); - expect(this.args.indexOf("--")).toBeGreaterThan(modelIndex); } function includes_resume_flag(this: Context) { const resumeIndex = this.args.indexOf("--resume"); expect(resumeIndex).toBeGreaterThan(-1); expect(this.args[resumeIndex + 1]).toBe("sess-claude-1"); - expect(this.args.indexOf("--")).toBeGreaterThan(resumeIndex); } diff --git a/packages/clanker-cleanroom-claude/src/binding.ts b/packages/clanker-cleanroom-claude/src/binding.ts index f0e6d06..7f1c6eb 100644 --- a/packages/clanker-cleanroom-claude/src/binding.ts +++ b/packages/clanker-cleanroom-claude/src/binding.ts @@ -17,7 +17,7 @@ export const claudeBinding: AgentBinding = { trajectoryKind: "claude", adaptEvents: adaptClaudeEvents, sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH, - command: ({ prompt, model, sessionId }) => { + command: ({ model, sessionId }) => { const claudeArgs = [ "claude", "-p", @@ -32,7 +32,6 @@ export const claudeBinding: AgentBinding = { if (model !== undefined && model !== "") { claudeArgs.push("--model", model); } - claudeArgs.push("--", prompt); return claudeArgs; }, prepare: async () => { diff --git a/packages/clanker-cleanroom-cursor/src/binding.command.spec.ts b/packages/clanker-cleanroom-cursor/src/binding.command.spec.ts index c67a2a0..2c9c314 100644 --- a/packages/clanker-cleanroom-cursor/src/binding.command.spec.ts +++ b/packages/clanker-cleanroom-cursor/src/binding.command.spec.ts @@ -46,6 +46,15 @@ describe("cursorBinding.command", () => { includes_resume_flag, }, }); + + test("omits the raw prompt from argv so the CLI reads it from stdin", { + when: { + building_cursor_command, + }, + then: { + command_omits_raw_prompt, + }, + }); }); function building_docker_args(this: Context) { @@ -60,6 +69,10 @@ function building_docker_args_with_session(this: Context) { this.args = dockerArgs({ sessionId: "sess-cursor-1" }); } +function building_cursor_command(this: Context) { + this.args = cursorBinding.command({ prompt: "Create a README" }); +} + function dockerArgs(options: { model?: string; sessionId?: string } = {}): string[] { return buildDockerRunArgs({ image: "clanker-cleanroom/cursor", @@ -115,19 +128,22 @@ function invokes_agent_with_json_output(this: Context) { expect(this.args).toContain("--output-format"); expect(this.args).toContain("stream-json"); expect(this.args).toContain("--force"); - expect(this.args.at(-1)).toBe("Create a README"); + expect(this.args.includes("Create a README")).toBe(false); +} + +function command_omits_raw_prompt(this: Context) { + expect(this.args.includes("Create a README")).toBe(false); + expect(this.args.at(-1)).not.toBe("--"); } function includes_model_flag(this: Context) { const modelIndex = this.args.indexOf("--model"); expect(modelIndex).toBeGreaterThan(-1); expect(this.args[modelIndex + 1]).toBe("composer-2"); - expect(this.args.indexOf("--")).toBeGreaterThan(modelIndex); } function includes_resume_flag(this: Context) { const resumeIndex = this.args.indexOf("--resume"); expect(resumeIndex).toBeGreaterThan(-1); expect(this.args[resumeIndex + 1]).toBe("sess-cursor-1"); - expect(this.args.indexOf("--")).toBeGreaterThan(resumeIndex); } diff --git a/packages/clanker-cleanroom-cursor/src/binding.ts b/packages/clanker-cleanroom-cursor/src/binding.ts index e012a9f..cab2849 100644 --- a/packages/clanker-cleanroom-cursor/src/binding.ts +++ b/packages/clanker-cleanroom-cursor/src/binding.ts @@ -19,7 +19,7 @@ export const cursorBinding: AgentBinding = { trajectoryKind: "cursor", adaptEvents: adaptCursorEvents, sessionDataPath: CONTAINER_SESSION_PATH, - command: ({ prompt, model, sessionId }) => { + command: ({ model, sessionId }) => { const agentArgs = ["agent", "-p", "--force", "--output-format", "stream-json"]; if (sessionId !== undefined && sessionId !== "") { agentArgs.push("--resume", sessionId); @@ -27,7 +27,6 @@ export const cursorBinding: AgentBinding = { if (model !== undefined && model !== "") { agentArgs.push("--model", model); } - agentArgs.push("--", prompt); return agentArgs; }, prepare: async () => { diff --git a/packages/clanker-cleanroom/src/agents/docker.spec.ts b/packages/clanker-cleanroom/src/agents/docker.spec.ts index fc23fd7..20057a6 100644 --- a/packages/clanker-cleanroom/src/agents/docker.spec.ts +++ b/packages/clanker-cleanroom/src/agents/docker.spec.ts @@ -47,6 +47,15 @@ describe("buildDockerRunArgs", () => { has_name_and_labels, }, }); + + test("enables interactive stdin so the prompt can be piped into the container", { + when: { + building_args, + }, + then: { + enables_interactive_stdin, + }, + }); }); function building_args(this: Context) { @@ -145,3 +154,8 @@ function has_name_and_labels(this: Context) { expect(this.args).toContain("clanker.root=clanker-root"); expect(this.args).toContain("clanker.parent=clanker-parent"); } + +function enables_interactive_stdin(this: Context) { + expect(this.args[0]).toBe("run"); + expect(this.args).toContain("-i"); +} diff --git a/packages/clanker-cleanroom/src/agents/docker.ts b/packages/clanker-cleanroom/src/agents/docker.ts index ddd87fe..1b86f2b 100644 --- a/packages/clanker-cleanroom/src/agents/docker.ts +++ b/packages/clanker-cleanroom/src/agents/docker.ts @@ -20,11 +20,19 @@ export const runDocker: DockerRunner = (args, options = {}) => return; } + const input = options.input; const child = spawn("docker", args, { - stdio: ["ignore", "pipe", "pipe"], + stdio: [input !== undefined ? "pipe" : "ignore", "pipe", "pipe"], env: { ...process.env, ...options.env }, }); + if (input !== undefined && child.stdin !== null) { + child.stdin.on("error", () => { + // Ignore EPIPE if the container exits before consuming all input. + }); + child.stdin.end(input); + } + let stdout = ""; let stderr = ""; let settled = false; @@ -107,7 +115,7 @@ function createAbortError(): Error { } export function buildDockerRunArgs(options: BuildDockerRunArgsOptions): string[] { - const args = ["run", "--rm", "--user", `${options.uid}:${options.gid}`]; + const args = ["run", "--rm", "-i", "--user", `${options.uid}:${options.gid}`]; if (options.name !== undefined && options.name !== "") { args.push("--name", options.name); diff --git a/packages/clanker-cleanroom/src/agents/run-bound.stdin-prompt.spec.ts b/packages/clanker-cleanroom/src/agents/run-bound.stdin-prompt.spec.ts new file mode 100644 index 0000000..82a38c8 --- /dev/null +++ b/packages/clanker-cleanroom/src/agents/run-bound.stdin-prompt.spec.ts @@ -0,0 +1,229 @@ +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { describe, expect } from "vitest"; +import test, { withAspect } from "vitest-gwt"; + +import { CONTAINER_OUTPUT } from "./base/constants.js"; +import { runBoundAgent } from "./run-bound.js"; +import { TRAJECTORY_FILE } from "./trajectory/index.js"; +import type { AgentBinding, DockerRunOptions, DockerRunner } from "./types.js"; + +const KIB = 1024; +const PROMPT_MARKER = "PROMPT_MARKER_"; + +describe("runBoundAgent prompt over stdin", () => { + withAspect(a_temp_output_host, remove_temp_output_host); + + test("delivers a small prompt through docker run -i stdin, not argv", { + given: { + binding_without_prompt_on_argv, + docker_succeeds_writing_trajectory, + small_prompt, + }, + when: { + running_bound_agent_with_prompt, + }, + then: { + docker_run_is_interactive, + prompt_is_piped_on_docker_stdin, + prompt_bytes_are_absent_from_docker_argv, + every_argv_element_is_under_128_kib, + }, + }); + + test("delivers a ~120 KB prompt through docker run -i stdin, not argv", { + given: { + binding_without_prompt_on_argv, + docker_succeeds_writing_trajectory, + prompt_of_120_kib, + }, + when: { + running_bound_agent_with_prompt, + }, + then: { + docker_run_is_interactive, + prompt_is_piped_on_docker_stdin, + prompt_bytes_are_absent_from_docker_argv, + every_argv_element_is_under_128_kib, + }, + }); + + test("delivers a 128 KB prompt through docker run -i stdin, not argv", { + given: { + binding_without_prompt_on_argv, + docker_succeeds_writing_trajectory, + prompt_of_128_kib, + }, + when: { + running_bound_agent_with_prompt, + }, + then: { + docker_run_is_interactive, + prompt_is_piped_on_docker_stdin, + prompt_bytes_are_absent_from_docker_argv, + every_argv_element_is_under_128_kib, + }, + }); + + test("delivers a ~130 KB prompt through docker run -i stdin, not argv", { + given: { + binding_without_prompt_on_argv, + docker_succeeds_writing_trajectory, + prompt_of_130_kib, + }, + when: { + running_bound_agent_with_prompt, + }, + then: { + docker_run_is_interactive, + prompt_is_piped_on_docker_stdin, + prompt_bytes_are_absent_from_docker_argv, + every_argv_element_is_under_128_kib, + }, + }); + + test("delivers a ~200 KB prompt through docker run -i stdin, not argv", { + given: { + binding_without_prompt_on_argv, + docker_succeeds_writing_trajectory, + prompt_of_200_kib, + }, + when: { + running_bound_agent_with_prompt, + }, + then: { + docker_run_is_interactive, + prompt_is_piped_on_docker_stdin, + prompt_bytes_are_absent_from_docker_argv, + every_argv_element_is_under_128_kib, + }, + }); +}); + +type Context = { + binding: AgentBinding; + dockerRunner: DockerRunner; + dockerArgs: string[]; + dockerOptions: DockerRunOptions; + outputHost: string; + prompt: string; +}; + +type DockerRunOptionsWithInput = DockerRunOptions & { + input?: string; +}; + +async function a_temp_output_host(this: Context) { + this.outputHost = await mkdtemp(join(tmpdir(), "clanker-stdin-out-")); +} + +async function remove_temp_output_host(this: Context) { + if (this.outputHost === undefined || this.outputHost === "") { + return; + } + await rm(this.outputHost, { recursive: true, force: true }); +} + +function binding_without_prompt_on_argv(this: Context) { + this.binding = { + image: "test/image", + displayName: "TestAgent", + trajectoryKind: "test", + adaptEvents: () => [], + command: () => ["tool", "-p", "--force"], + prepare: async () => ({}), + parseResult: () => ({ + durationMs: 1, + costUsd: null, + usage: { + inputTokens: null, + outputTokens: null, + cacheReadTokens: null, + cacheWriteTokens: null, + }, + }), + }; +} + +function docker_succeeds_writing_trajectory(this: Context) { + this.dockerArgs = []; + this.dockerOptions = {}; + this.dockerRunner = async (args, options = {}) => { + this.dockerArgs = args; + this.dockerOptions = options; + await mkdir(this.outputHost, { recursive: true }); + await writeFile( + join(this.outputHost, TRAJECTORY_FILE), + `${JSON.stringify({ type: "result", result: "ok" })}\n`, + ); + return { exitCode: 0, stdout: "", stderr: "" }; + }; +} + +function small_prompt(this: Context) { + this.prompt = `${PROMPT_MARKER}small`; +} + +function prompt_of_120_kib(this: Context) { + this.prompt = sized_prompt(120 * KIB); +} + +function prompt_of_128_kib(this: Context) { + this.prompt = sized_prompt(128 * KIB); +} + +function prompt_of_130_kib(this: Context) { + this.prompt = sized_prompt(130 * KIB); +} + +function prompt_of_200_kib(this: Context) { + this.prompt = sized_prompt(200 * KIB); +} + +async function running_bound_agent_with_prompt(this: Context) { + await runBoundAgent( + this.binding, + { + workspace: "/tmp/ws", + prompt: this.prompt, + image: "test/image", + uid: 1, + gid: 1, + ioVolumes: [ + { host: "/tmp/in", container: "/agent/input", mode: "ro" }, + { host: this.outputHost, container: CONTAINER_OUTPUT }, + ], + }, + this.dockerRunner, + ); +} + +function docker_run_is_interactive(this: Context) { + expect(this.dockerArgs).toContain("-i"); +} + +function prompt_is_piped_on_docker_stdin(this: Context) { + const options = this.dockerOptions as DockerRunOptionsWithInput; + expect(options.input).toBe(this.prompt); +} + +function prompt_bytes_are_absent_from_docker_argv(this: Context) { + for (const arg of this.dockerArgs) { + expect(arg.includes(PROMPT_MARKER)).toBe(false); + expect(arg).not.toBe(this.prompt); + } +} + +function every_argv_element_is_under_128_kib(this: Context) { + const maxArgBytes = 128 * KIB; + for (const arg of this.dockerArgs) { + expect(Buffer.byteLength(arg, "utf8")).toBeLessThan(maxArgBytes); + } +} + +function sized_prompt(byteLength: number): string { + const prefix = PROMPT_MARKER; + return prefix + "x".repeat(byteLength - prefix.length); +} diff --git a/packages/clanker-cleanroom/src/agents/run-bound.ts b/packages/clanker-cleanroom/src/agents/run-bound.ts index 5916919..6d3454c 100644 --- a/packages/clanker-cleanroom/src/agents/run-bound.ts +++ b/packages/clanker-cleanroom/src/agents/run-bound.ts @@ -122,6 +122,7 @@ export async function runBoundAgent( try { result = await dockerRunner(args, { env, + input: options.prompt, ...(signal !== undefined ? { signal } : {}), containerName, }); diff --git a/packages/clanker-cleanroom/src/agents/types.ts b/packages/clanker-cleanroom/src/agents/types.ts index 455bef3..f849d5d 100644 --- a/packages/clanker-cleanroom/src/agents/types.ts +++ b/packages/clanker-cleanroom/src/agents/types.ts @@ -62,6 +62,8 @@ export type DockerRunOptions = { signal?: AbortSignal; /** Name passed to `docker run --name`; required for reliable abort cleanup. */ containerName?: string; + /** Bytes written to `docker run -i` stdin (e.g. the agent prompt). */ + input?: string; }; export type DockerRunner = (args: string[], options?: DockerRunOptions) => Promise; From 370f5db329be23b3a5398eb0fc19788fb70f09e5 Mon Sep 17 00:00:00 2001 From: Eric Siebeneich Date: Mon, 12 Oct 2026 13:50:36 -0500 Subject: [PATCH 3/4] Add @clanker-cleanroom/plugin-agentfield for AgentField integration. Expose agent.clanker() via a prototype patch so cleanroom agents record harness-style usage on the control plane. --- .github/workflows/publish.yml | 8 +- PUBLISHING.md | 23 +- README.md | 13 +- .../README.md | 56 + .../package.json | 143 +++ .../src/clanker.spec.ts | 259 +++++ .../src/clanker.ts | 129 ++ .../src/index.ts | 13 + .../src/install.spec.ts | 33 + .../src/install.ts | 39 + .../src/map-result.spec.ts | 86 ++ .../src/map-result.ts | 97 ++ .../src/options.ts | 23 + .../src/record-usage.spec.ts | 151 +++ .../src/record-usage.ts | 66 ++ .../src/register.ts | 3 + .../src/schema.ts | 58 + .../tsconfig.json | 22 + .../vite.config.ts | 35 + pnpm-lock.yaml | 1033 ++++++++++++++++- 20 files changed, 2251 insertions(+), 39 deletions(-) create mode 100644 packages/clanker-cleanroom-plugin-agentfield/README.md create mode 100644 packages/clanker-cleanroom-plugin-agentfield/package.json create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/clanker.spec.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/clanker.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/index.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/install.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/map-result.spec.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/map-result.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/options.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/record-usage.spec.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/record-usage.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/register.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/src/schema.ts create mode 100644 packages/clanker-cleanroom-plugin-agentfield/tsconfig.json create mode 100644 packages/clanker-cleanroom-plugin-agentfield/vite.config.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bf4ac21..456c63d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -69,7 +69,8 @@ jobs: packages/agent-gwt/package.json \ packages/clanker-cleanroom/package.json \ packages/clanker-cleanroom-cursor/package.json \ - packages/clanker-cleanroom-claude/package.json + packages/clanker-cleanroom-claude/package.json \ + packages/clanker-cleanroom-plugin-agentfield/package.json do jq --arg v "${{ steps.version.outputs.prerelease }}" '.version = $v' "${pkg}" > "${pkg}.tmp" mv "${pkg}.tmp" "${pkg}" @@ -91,6 +92,7 @@ jobs: clanker-cleanroom \ @clanker-cleanroom/cursor \ @clanker-cleanroom/claude \ + @clanker-cleanroom/plugin-agentfield \ agent-gwt do pnpm --filter "${filter}" publish \ @@ -156,6 +158,7 @@ jobs: clanker-cleanroom \ @clanker-cleanroom/cursor \ @clanker-cleanroom/claude \ + @clanker-cleanroom/plugin-agentfield \ agent-gwt do cd "${workdir}" @@ -171,6 +174,7 @@ jobs: | if .dependencies["clanker-cleanroom"] then .dependencies["clanker-cleanroom"] = $v else . end | if .dependencies["@clanker-cleanroom/cursor"] then .dependencies["@clanker-cleanroom/cursor"] = $v else . end | if .dependencies["@clanker-cleanroom/claude"] then .dependencies["@clanker-cleanroom/claude"] = $v else . end + | if .dependencies["@clanker-cleanroom/plugin-agentfield"] then .dependencies["@clanker-cleanroom/plugin-agentfield"] = $v else . end ' staged/package/package.json > staged/package/package.json.tmp mv staged/package/package.json.tmp staged/package/package.json err="$(mktemp)" @@ -212,6 +216,7 @@ jobs: packages/clanker-cleanroom/package.json packages/clanker-cleanroom-cursor/package.json packages/clanker-cleanroom-claude/package.json + packages/clanker-cleanroom-plugin-agentfield/package.json ) for pkg in "${packages[@]}"; do if [[ ! -f "${pkg}" ]]; then @@ -236,3 +241,4 @@ jobs: npm dist-tag rm clanker-cleanroom "${PR_TAG}" || true npm dist-tag rm @clanker-cleanroom/cursor "${PR_TAG}" || true npm dist-tag rm @clanker-cleanroom/claude "${PR_TAG}" || true + npm dist-tag rm @clanker-cleanroom/plugin-agentfield "${PR_TAG}" || true diff --git a/PUBLISHING.md b/PUBLISHING.md index c7221ef..6581f79 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -2,24 +2,26 @@ CI publishes via [npm trusted publishers](https://docs.npmjs.com/trusted-publishers) (OIDC) from [`.github/workflows/publish.yml`](.github/workflows/publish.yml). There is no `NPM_TOKEN` secret. -This repo is a pnpm workspace with four publishable packages: +This repo is a pnpm workspace with five publishable packages: -| Package | Path | -| --------------------------- | -------------------------------------------------------------------------- | -| `clanker-cleanroom` | [`packages/clanker-cleanroom`](packages/clanker-cleanroom) | -| `@clanker-cleanroom/cursor` | [`packages/clanker-cleanroom-cursor`](packages/clanker-cleanroom-cursor) | -| `@clanker-cleanroom/claude` | [`packages/clanker-cleanroom-claude`](packages/clanker-cleanroom-claude) | -| `agent-gwt` | [`packages/agent-gwt`](packages/agent-gwt) | +| Package | Path | +| -------------------------------------- | ------------------------------------------------------------------------------------------ | +| `clanker-cleanroom` | [`packages/clanker-cleanroom`](packages/clanker-cleanroom) | +| `@clanker-cleanroom/cursor` | [`packages/clanker-cleanroom-cursor`](packages/clanker-cleanroom-cursor) | +| `@clanker-cleanroom/claude` | [`packages/clanker-cleanroom-claude`](packages/clanker-cleanroom-claude) | +| `@clanker-cleanroom/plugin-agentfield` | [`packages/clanker-cleanroom-plugin-agentfield`](packages/clanker-cleanroom-plugin-agentfield) | +| `agent-gwt` | [`packages/agent-gwt`](packages/agent-gwt) | -**Versions stay in sync** across five `package.json` files: +**Versions stay in sync** across six `package.json` files: 1. Root [`package.json`](package.json) (canonical for CI bumps) 2. [`packages/agent-gwt/package.json`](packages/agent-gwt/package.json) 3. [`packages/clanker-cleanroom/package.json`](packages/clanker-cleanroom/package.json) 4. [`packages/clanker-cleanroom-cursor/package.json`](packages/clanker-cleanroom-cursor/package.json) 5. [`packages/clanker-cleanroom-claude/package.json`](packages/clanker-cleanroom-claude/package.json) +6. [`packages/clanker-cleanroom-plugin-agentfield/package.json`](packages/clanker-cleanroom-plugin-agentfield/package.json) -CI publishes in dependency order: `clanker-cleanroom` → agent packages → `agent-gwt`. +CI publishes in dependency order: `clanker-cleanroom` → agent packages → `plugin-agentfield` → `agent-gwt`. ## One-time setup @@ -33,12 +35,13 @@ pnpm run lint && pnpm run test && pnpm run build pnpm --filter clanker-cleanroom publish --access public --ignore-scripts pnpm --filter @clanker-cleanroom/cursor publish --access public --ignore-scripts pnpm --filter @clanker-cleanroom/claude publish --access public --ignore-scripts +pnpm --filter @clanker-cleanroom/plugin-agentfield publish --access public --ignore-scripts pnpm --filter agent-gwt publish --access public --ignore-scripts ``` ### 2. Configure the trusted publisher (each package) -On [npmjs.com](https://www.npmjs.com) → package → Settings → Trusted Publisher, for **each** of the four packages: +On [npmjs.com](https://www.npmjs.com) → package → Settings → Trusted Publisher, for **each** of the five packages: | Field | Value | | -------------------- | --------------------------------------------------- | diff --git a/README.md b/README.md index dff814f..b5dadbf 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,13 @@ pnpm monorepo: -| Package | Role | -| ------------------------------------------------- | ----------------------------------------------------- | -| [`clanker-cleanroom`](packages/clanker-cleanroom) | Build/run agent Docker images with workspace bindings | -| [`agent-gwt`](packages/agent-gwt) | GWT step functions for repeatable agent tests | +| Package | Role | +| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| [`clanker-cleanroom`](packages/clanker-cleanroom) | Build/run agent Docker images with workspace bindings | +| [`@clanker-cleanroom/cursor`](packages/clanker-cleanroom-cursor) | Cursor binding + Docker image | +| [`@clanker-cleanroom/claude`](packages/clanker-cleanroom-claude) | Claude Code binding + Docker image | +| [`@clanker-cleanroom/plugin-agentfield`](packages/clanker-cleanroom-plugin-agentfield) | `agent.clanker()` bridge into `@agentfield/sdk` with usage auditing | +| [`agent-gwt`](packages/agent-gwt) | GWT step functions for repeatable agent tests | ```bash pnpm install @@ -14,4 +17,4 @@ pnpm run test pnpm run lint ``` -See [packages/clanker-cleanroom/README.md](packages/clanker-cleanroom/README.md) and [packages/agent-gwt/README.md](packages/agent-gwt/README.md) for usage. +See [packages/clanker-cleanroom/README.md](packages/clanker-cleanroom/README.md), [packages/clanker-cleanroom-plugin-agentfield/README.md](packages/clanker-cleanroom-plugin-agentfield/README.md), and [packages/agent-gwt/README.md](packages/agent-gwt/README.md) for usage. diff --git a/packages/clanker-cleanroom-plugin-agentfield/README.md b/packages/clanker-cleanroom-plugin-agentfield/README.md new file mode 100644 index 0000000..ae55203 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/README.md @@ -0,0 +1,56 @@ +# @clanker-cleanroom/plugin-agentfield + +Monkeypatches `@agentfield/sdk` `Agent` with `agent.clanker(prompt, options)` so cleanroom coding agents run inside AgentField reasoners and record harness-style usage into the control-plane audit rollup. + +## Install + +```bash +pnpm add @clanker-cleanroom/plugin-agentfield clanker-cleanroom @agentfield/sdk +# plus the agent(s) you use: +pnpm add @clanker-cleanroom/cursor # and/or @clanker-cleanroom/claude +``` + +## Usage + +```ts +import { Agent } from "@agentfield/sdk"; +import "@clanker-cleanroom/cursor/register"; +import "@clanker-cleanroom/plugin-agentfield/register"; + +const agent = new Agent({ + nodeId: "fixer", + aiConfig: { provider: "openai", model: "gpt-4o" }, +}); + +agent.reasoner("fix", async () => { + const result = await agent.clanker("Fix the failing test and leave a short summary", { + agent: "cursor", + workspace: "/tmp/ws", + model: "auto", + }); + + return { summary: result.text, costUsd: result.costUsd }; +}); +``` + +Or call `installClanker()` / the free `clanker(prompt, options)` helper from the package root instead of the `/register` side-effect. + +## Options + +| Field | Type | Required | Role | +| --- | --- | --- | --- | +| `agent` | `string` | yes | Stock name (`cursor`, `claude`) or registry tag (`cursor:node`) | +| `workspace` | `string` | yes | Host workspace mounted at `/workspace` | +| `model` | `string` | no | Forwarded to the cleanroom agent | +| `image` | `string` | no | Docker image override | +| `remaps` | `Remaps` | no | Nested DooD path remaps | +| `signal` | `AbortSignal` | no | Cancel the in-flight run | +| `schema` | Zod / `{ parse }` | no | Structured output via `.agentfield_output.json` in the workspace | + +Returns an AgentField `HarnessResult`. Token/cost usage is recorded on the current execution's `CostTracker` with `source: "harness"` and `harness: "clanker_"` when an execution context is active. + +## Prerequisites + +1. Docker (same as `clanker-cleanroom`) +2. Built/registered cleanroom images and bindings for the agents you call +3. Host credentials for those agents diff --git a/packages/clanker-cleanroom-plugin-agentfield/package.json b/packages/clanker-cleanroom-plugin-agentfield/package.json new file mode 100644 index 0000000..e850e70 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/package.json @@ -0,0 +1,143 @@ +{ + "name": "@clanker-cleanroom/plugin-agentfield", + "version": "0.2.8", + "description": "AgentField plugin: agent.clanker() via clanker-cleanroom with harness-style usage auditing", + "keywords": [ + "agent", + "agentfield", + "cleanroom", + "clanker", + "docker", + "harness" + ], + "homepage": "https://github.com/improving/agent-gwt#readme", + "bugs": { + "url": "https://github.com/improving/agent-gwt/issues" + }, + "license": "MIT", + "author": "Eric Siebeneich (https://github.com/improving)", + "repository": { + "type": "git", + "url": "git+https://github.com/improving/agent-gwt.git", + "directory": "packages/clanker-cleanroom-plugin-agentfield" + }, + "files": [ + "lib", + "src", + "!**/*.spec.ts" + ], + "type": "module", + "main": "./lib/index.cjs", + "module": "./lib/index.mjs", + "types": "./lib/index.d.cts", + "exports": { + ".": { + "import": { + "types": "./lib/index.d.mts", + "default": "./lib/index.mjs" + }, + "require": { + "types": "./lib/index.d.cts", + "default": "./lib/index.cjs" + } + }, + "./register": { + "import": { + "types": "./lib/register.d.mts", + "default": "./lib/register.mjs" + }, + "require": { + "types": "./lib/register.d.cts", + "default": "./lib/register.cjs" + } + }, + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "wireit", + "test": "wireit", + "lint": "wireit", + "test:coverage": "wireit", + "prepublishOnly": "wireit" + }, + "wireit": { + "build": { + "command": "vp pack", + "files": [ + "src/**/*.ts", + "tsconfig.json", + "vite.config.ts", + "!src/**/*.spec.ts" + ], + "output": [ + "lib/**" + ], + "dependencies": [ + "../clanker-cleanroom:build" + ] + }, + "lint": { + "command": "vp lint src && tsc --noEmit -p tsconfig.json", + "files": [ + "src/**/*.ts", + "tsconfig.json", + "vite.config.ts" + ], + "dependencies": [ + "../clanker-cleanroom:build" + ] + }, + "test": { + "command": "vitest run", + "files": [ + "src/**/*.ts", + "vite.config.ts" + ], + "dependencies": [ + "../clanker-cleanroom:build" + ] + }, + "test:coverage": { + "command": "vitest run --coverage", + "files": [ + "src/**/*.ts", + "vite.config.ts" + ], + "output": [ + "coverage/**" + ], + "dependencies": [ + "../clanker-cleanroom:build" + ] + }, + "prepublishOnly": { + "dependencies": [ + "lint", + "test", + "build" + ] + } + }, + "dependencies": { + "clanker-cleanroom": "workspace:*" + }, + "peerDependencies": { + "@agentfield/sdk": "^0.1.141" + }, + "devDependencies": { + "@agentfield/sdk": "^0.1.141", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plus": "catalog:", + "vitest": "catalog:", + "vitest-gwt": "catalog:", + "wireit": "catalog:", + "zod": "^3.22.4" + }, + "packageManager": "pnpm@11.22.0" +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/clanker.spec.ts b/packages/clanker-cleanroom-plugin-agentfield/src/clanker.spec.ts new file mode 100644 index 0000000..c1b7a52 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/clanker.spec.ts @@ -0,0 +1,259 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +import { CostTracker, ExecutionContext, usageSummaryOrNull } from "@agentfield/sdk"; +import { + AgentAbortError, + emptyTokenUsage, + type AgentRunResult, + type RunAgentOptions, + type Trajectory, +} from "clanker-cleanroom"; +import { describe, expect } from "vitest"; +import test from "vitest-gwt"; +import { z } from "zod"; + +import { clanker, type CleanroomAgentLike } from "./clanker.js"; +import { OUTPUT_FILENAME } from "./schema.js"; + +type Context = { + workspace: string; + result?: Awaited>; + tracker?: CostTracker; + mock?: MockAgent; +}; + +class MockAgent implements CleanroomAgentLike { + runImpl: (options: RunAgentOptions) => Promise = async () => ({ + durationMs: 100, + costUsd: 0.25, + usage: { + inputTokens: 5, + outputTokens: 7, + cacheReadTokens: null, + cacheWriteTokens: null, + }, + }); + + trajectoryImpl: () => Promise = async () => + ({ + provider: "cursor", + events: [ + { kind: "assistant", text: "done", raw: {} }, + { + kind: "result", + text: "done", + isError: false, + durationMs: 100, + costUsd: 0.25, + raw: {}, + }, + ], + sessionId: () => "sess-1", + result: () => ({ + kind: "result" as const, + text: "done", + isError: false, + durationMs: 100, + costUsd: 0.25, + raw: {}, + }), + assistantMessages: () => ["done"], + toolCalls: () => [], + }) satisfies Trajectory; + + sessionIdImpl: () => string | null = () => "sess-1"; + + async run(options: RunAgentOptions): Promise { + return this.runImpl(options); + } + + async trajectory(): Promise { + return this.trajectoryImpl(); + } + + sessionId(): string | null { + return this.sessionIdImpl(); + } +} + +describe("clanker", () => { + test("maps metrics and records usage under an execution context", { + given: { + temp_workspace, + mock_agent, + active_execution, + }, + when: { + running_clanker, + }, + then: { + result_mapped, + usage_recorded, + }, + }); + + test("returns result without throwing when no execution context", { + given: { + temp_workspace, + mock_agent, + }, + when: { + running_clanker, + }, + then: { + result_mapped, + }, + }); + + test("sets isError on abort and preserves abort metrics", { + given: { + temp_workspace, + mock_agent_that_aborts, + }, + when: { + running_clanker, + }, + then: { + result_is_error_with_abort_cost, + }, + }); + + test("validates schema output from the workspace", { + given: { + temp_workspace, + mock_agent_writing_schema_output, + }, + when: { + running_clanker_with_schema, + }, + then: { + parsed_matches_schema, + }, + }); + + test("fails when schema output is missing", { + given: { + temp_workspace, + mock_agent, + }, + when: { + running_clanker_with_schema, + }, + then: { + result_is_schema_error, + }, + }); +}); + +function temp_workspace(this: Context) { + this.workspace = fs.mkdtempSync(path.join(os.tmpdir(), "plugin-agentfield-")); +} + +function mock_agent(this: Context) { + this.mock = new MockAgent(); +} + +function mock_agent_that_aborts(this: Context) { + this.mock = new MockAgent(); + this.mock.runImpl = async () => { + throw new AgentAbortError({ + durationMs: 50, + costUsd: 0.11, + usage: { + inputTokens: 1, + outputTokens: 2, + cacheReadTokens: null, + cacheWriteTokens: null, + }, + }); + }; +} + +function mock_agent_writing_schema_output(this: Context) { + this.mock = new MockAgent(); + this.mock.runImpl = async (options) => { + fs.writeFileSync( + path.join(options.workspace, OUTPUT_FILENAME), + JSON.stringify({ summary: "ok", ok: true }), + "utf8", + ); + return { + durationMs: 10, + costUsd: null, + usage: emptyTokenUsage(), + }; + }; +} + +function active_execution(this: Context) { + this.tracker = new CostTracker(); +} + +async function running_clanker(this: Context) { + const run = () => + clanker( + "do the thing", + { agent: "cursor", workspace: this.workspace, model: "auto" }, + { createAgent: () => this.mock! }, + ); + + if (this.tracker) { + const fakeCtx = { + costTracker: this.tracker, + metadata: { reasonerId: "fix", executionId: "exec-1" }, + } as ExecutionContext; + this.result = await ExecutionContext.run(fakeCtx, run); + } else { + this.result = await run(); + } +} + +async function running_clanker_with_schema(this: Context) { + this.result = await clanker( + "do the thing", + { + agent: "cursor", + workspace: this.workspace, + schema: z.object({ summary: z.string(), ok: z.boolean() }), + }, + { createAgent: () => this.mock! }, + ); +} + +function result_mapped(this: Context) { + expect(this.result?.isError).toBe(false); + expect(this.result?.text).toBe("done"); + expect(this.result?.costUsd).toBe(0.25); + expect(this.result?.inputTokens).toBe(5); + expect(this.result?.outputTokens).toBe(7); + expect(this.result?.sessionId).toBe("sess-1"); + expect(this.result?.numTurns).toBe(1); +} + +function usage_recorded(this: Context) { + const summary = usageSummaryOrNull(this.tracker); + expect(summary?.entries).toHaveLength(1); + expect(summary?.entries[0]).toMatchObject({ + source: "harness", + harness: "clanker_cursor", + cost_usd: 0.25, + }); +} + +function result_is_error_with_abort_cost(this: Context) { + expect(this.result?.isError).toBe(true); + expect(this.result?.costUsd).toBe(0.11); + expect(this.result?.errorMessage).toContain("aborted"); +} + +function parsed_matches_schema(this: Context) { + expect(this.result?.isError).toBe(false); + expect(this.result?.parsed).toEqual({ summary: "ok", ok: true }); +} + +function result_is_schema_error(this: Context) { + expect(this.result?.isError).toBe(true); + expect(this.result?.failureType).toBe("schema"); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/clanker.ts b/packages/clanker-cleanroom-plugin-agentfield/src/clanker.ts new file mode 100644 index 0000000..c1f17e3 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/clanker.ts @@ -0,0 +1,129 @@ +import type { HarnessResult } from "@agentfield/sdk"; +import { + Agent as CleanroomAgent, + AgentAbortError, + emptyTokenUsage, + isAbortError, + type AgentRunResult, + type RunAgentOptions, + type Trajectory, +} from "clanker-cleanroom"; + +import { mapRunToHarnessResult } from "./map-result.js"; +import type { ClankerOptions } from "./options.js"; +import { recordClankerUsage } from "./record-usage.js"; +import { buildPromptSuffix, parseAndValidate } from "./schema.js"; + +/** Minimal cleanroom agent surface used by {@link clanker} (overridable in tests). */ +export type CleanroomAgentLike = { + run: (options: RunAgentOptions) => Promise; + trajectory: () => Promise; + sessionId: () => string | null; +}; + +export type ClankerDeps = { + createAgent?: (name: string) => CleanroomAgentLike; +}; + +async function loadTrajectory(agent: CleanroomAgentLike): Promise { + try { + return await agent.trajectory(); + } catch { + return null; + } +} + +function emptyRunResult(): AgentRunResult { + return { + durationMs: null, + costUsd: null, + usage: emptyTokenUsage(), + }; +} + +/** + * Run a clanker-cleanroom agent and return an AgentField {@link HarnessResult}. + * Records harness-style usage onto the current execution when present. + */ +export async function clanker( + prompt: string, + options: ClankerOptions, + deps: ClankerDeps = {}, +): Promise { + const createAgent = + deps.createAgent ?? ((name: string): CleanroomAgentLike => new CleanroomAgent(name)); + const agent: CleanroomAgentLike = createAgent(options.agent); + + const effectivePrompt = + options.schema === undefined ? prompt : `${prompt}${buildPromptSuffix(options.workspace)}`; + + const startedAt = Date.now(); + let run: AgentRunResult; + let isError = false; + let errorMessage: string | undefined; + let failureType: HarnessResult["failureType"] | undefined; + + try { + run = await agent.run({ + workspace: options.workspace, + prompt: effectivePrompt, + ...(options.model !== undefined ? { model: options.model } : {}), + ...(options.image !== undefined ? { image: options.image } : {}), + ...(options.remaps !== undefined ? { remaps: options.remaps } : {}), + ...(options.signal !== undefined ? { signal: options.signal } : {}), + }); + } catch (error: unknown) { + isError = true; + errorMessage = error instanceof Error ? error.message : String(error); + if (error instanceof AgentAbortError || isAbortError(error)) { + failureType = "none"; + const abortResult = + error instanceof AgentAbortError + ? error.result + : ((error as { result?: AgentRunResult }).result ?? emptyRunResult()); + run = abortResult; + } else { + run = emptyRunResult(); + } + } + + const trajectory = await loadTrajectory(agent); + const sessionId = agent.sessionId(); + + let parsed: unknown | undefined; + if (options.schema !== undefined && !isError) { + const validated = parseAndValidate(options.workspace, options.schema); + if (validated === null) { + isError = true; + errorMessage = "Schema validation failed after parse and cosmetic repair attempts."; + failureType = "schema"; + } else { + parsed = validated; + } + } + + const result = mapRunToHarnessResult({ + run, + trajectory, + sessionId, + durationMsOverride: nullToDuration(run.durationMs, startedAt), + isError, + ...(errorMessage !== undefined ? { errorMessage } : {}), + ...(failureType !== undefined ? { failureType } : {}), + ...(parsed !== undefined ? { parsed } : {}), + }); + + recordClankerUsage(result, { + agent: options.agent, + ...(options.model !== undefined ? { model: options.model } : {}), + }); + + return result; +} + +function nullToDuration(durationMs: number | null, startedAt: number): number { + if (typeof durationMs === "number" && Number.isFinite(durationMs)) { + return durationMs; + } + return Math.max(0, Date.now() - startedAt); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/index.ts b/packages/clanker-cleanroom-plugin-agentfield/src/index.ts new file mode 100644 index 0000000..7dbef33 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/index.ts @@ -0,0 +1,13 @@ +export type { ClankerOptions, ParseableSchema } from "./options.js"; +export type { CleanroomAgentLike, ClankerDeps } from "./clanker.js"; +export { clanker } from "./clanker.js"; +export { installClanker } from "./install.js"; +export { harnessNameForAgent, recordClankerUsage } from "./record-usage.js"; +export { + OUTPUT_FILENAME, + buildPromptSuffix, + getOutputPath, + parseAndValidate, + readOutputFile, +} from "./schema.js"; +export { mapRunToHarnessResult } from "./map-result.js"; diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts b/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts new file mode 100644 index 0000000..1fe4fd5 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts @@ -0,0 +1,33 @@ +import { Agent } from "@agentfield/sdk"; +import { describe, expect } from "vitest"; +import test from "vitest-gwt"; + +import { installClanker } from "./install.js"; + +type Context = { + first?: typeof Agent.prototype.clanker; + second?: typeof Agent.prototype.clanker; +}; + +describe("installClanker", () => { + test("adds clanker to the prototype and is idempotent", { + when: { + installing_twice, + }, + then: { + method_exists_and_is_stable, + }, + }); +}); + +function installing_twice(this: Context) { + installClanker(); + this.first = Agent.prototype.clanker; + installClanker(); + this.second = Agent.prototype.clanker; +} + +function method_exists_and_is_stable(this: Context) { + expect(typeof this.first).toBe("function"); + expect(this.second).toBe(this.first); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/install.ts b/packages/clanker-cleanroom-plugin-agentfield/src/install.ts new file mode 100644 index 0000000..b412783 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/install.ts @@ -0,0 +1,39 @@ +import { Agent, type HarnessResult } from "@agentfield/sdk"; + +import { clanker } from "./clanker.js"; +import type { ClankerOptions } from "./options.js"; + +const INSTALLED = Symbol.for("@clanker-cleanroom/plugin-agentfield.installed"); + +type AgentConstructor = typeof Agent; + +type AgentPrototype = { + clanker?: (prompt: string, options: ClankerOptions) => Promise; + [INSTALLED]?: boolean; +}; + +/** + * Monkeypatch {@link Agent}.prototype with `clanker(prompt, options)`. + * Idempotent — safe to call more than once. + */ +export function installClanker(AgentClass: AgentConstructor = Agent): void { + const proto = AgentClass.prototype as AgentPrototype; + if (proto[INSTALLED]) { + return; + } + + proto.clanker = function clankerMethod( + this: Agent, + prompt: string, + options: ClankerOptions, + ): Promise { + return clanker(prompt, options); + }; + proto[INSTALLED] = true; +} + +declare module "@agentfield/sdk" { + interface Agent { + clanker(prompt: string, options: ClankerOptions): Promise; + } +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/map-result.spec.ts b/packages/clanker-cleanroom-plugin-agentfield/src/map-result.spec.ts new file mode 100644 index 0000000..afb4fdf --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/map-result.spec.ts @@ -0,0 +1,86 @@ +import type { Trajectory } from "clanker-cleanroom"; +import { describe, expect } from "vitest"; +import test from "vitest-gwt"; + +import { mapRunToHarnessResult } from "./map-result.js"; + +type Context = { + result?: ReturnType; +}; + +describe("mapRunToHarnessResult", () => { + test("maps tokens, cost, session, and turns from trajectory", { + when: { + mapping_a_successful_run, + }, + then: { + harness_fields_populated, + }, + }); +}); + +function mapping_a_successful_run(this: Context) { + const trajectory = { + provider: "claude", + events: [ + { kind: "assistant", text: "working", raw: {} }, + { + kind: "tool", + phase: "completed", + callId: "1", + name: "Bash", + args: {}, + result: "ok", + raw: {}, + }, + { kind: "assistant", text: "done", raw: {} }, + { + kind: "result", + text: "done", + isError: false, + durationMs: 200, + costUsd: 1.5, + raw: {}, + }, + ], + sessionId: () => "abc", + result: () => ({ + kind: "result" as const, + text: "done", + isError: false, + durationMs: 200, + costUsd: 1.5, + raw: {}, + }), + assistantMessages: () => ["working", "done"], + toolCalls: () => [], + } satisfies Trajectory; + + this.result = mapRunToHarnessResult({ + run: { + durationMs: 200, + costUsd: 1.5, + usage: { + inputTokens: 3, + outputTokens: 4, + cacheReadTokens: 1, + cacheWriteTokens: 2, + }, + }, + trajectory, + sessionId: "abc", + }); +} + +function harness_fields_populated(this: Context) { + expect(this.result?.text).toBe("done"); + expect(this.result?.costUsd).toBe(1.5); + expect(this.result?.inputTokens).toBe(3); + expect(this.result?.outputTokens).toBe(4); + expect(this.result?.cacheReadTokens).toBe(1); + expect(this.result?.cacheCreationTokens).toBe(2); + expect(this.result?.totalTokens).toBe(7); + expect(this.result?.sessionId).toBe("abc"); + expect(this.result?.numTurns).toBe(3); + expect(this.result?.messages.length).toBe(4); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/map-result.ts b/packages/clanker-cleanroom-plugin-agentfield/src/map-result.ts new file mode 100644 index 0000000..728b2e8 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/map-result.ts @@ -0,0 +1,97 @@ +import { + createHarnessResult, + type HarnessResult, +} from "@agentfield/sdk"; +import type { AgentRunResult, Trajectory, TrajectoryEvent } from "clanker-cleanroom"; + +function nullToUndefined(value: number | null | undefined): number | undefined { + return typeof value === "number" && Number.isFinite(value) ? value : undefined; +} + +function eventToMessage(event: TrajectoryEvent): Record { + const { raw, ...rest } = event; + return { + ...rest, + ...(raw !== undefined ? { raw } : {}), + }; +} + +function countTurns(trajectory: Trajectory | null): number { + if (trajectory === null) { + return 0; + } + let turns = 0; + for (const event of trajectory.events) { + if (event.kind === "assistant") { + turns += 1; + } else if (event.kind === "tool" && event.phase === "completed") { + turns += 1; + } + } + return turns; +} + +function resultText(run: AgentRunResult, trajectory: Trajectory | null): string | undefined { + const resultEvent = trajectory?.result(); + if (resultEvent !== undefined && resultEvent !== null && resultEvent.text.length > 0) { + return resultEvent.text; + } + const assistants = trajectory?.assistantMessages() ?? []; + const last = assistants.at(-1); + if (last !== undefined && last.length > 0) { + return last; + } + void run; + return undefined; +} + +export type MapRunToHarnessInput = { + run: AgentRunResult; + trajectory: Trajectory | null; + sessionId: string | null; + durationMsOverride?: number; + isError?: boolean; + errorMessage?: string; + failureType?: HarnessResult["failureType"]; + parsed?: unknown; +}; + +export function mapRunToHarnessResult(input: MapRunToHarnessInput): HarnessResult { + const { run, trajectory, sessionId } = input; + const inputTokens = nullToUndefined(run.usage.inputTokens); + const outputTokens = nullToUndefined(run.usage.outputTokens); + const cacheReadTokens = nullToUndefined(run.usage.cacheReadTokens); + const cacheCreationTokens = nullToUndefined(run.usage.cacheWriteTokens); + const totalTokens = + inputTokens !== undefined || outputTokens !== undefined + ? (inputTokens ?? 0) + (outputTokens ?? 0) + : undefined; + + const messages = + trajectory === null ? [] : trajectory.events.map((event) => eventToMessage(event)); + + const resultTextValue = resultText(run, trajectory); + const durationMs = + input.durationMsOverride ?? + nullToUndefined(run.durationMs) ?? + nullToUndefined(trajectory?.result()?.durationMs) ?? + 0; + + return createHarnessResult({ + ...(resultTextValue !== undefined ? { result: resultTextValue } : {}), + ...(input.parsed !== undefined ? { parsed: input.parsed } : {}), + isError: input.isError ?? false, + ...(input.errorMessage !== undefined ? { errorMessage: input.errorMessage } : {}), + ...(input.failureType !== undefined ? { failureType: input.failureType } : {}), + ...(nullToUndefined(run.costUsd) !== undefined ? { costUsd: run.costUsd! } : {}), + numTurns: countTurns(trajectory), + durationMs, + sessionId: sessionId ?? "", + messages, + ...(inputTokens !== undefined ? { inputTokens } : {}), + ...(outputTokens !== undefined ? { outputTokens } : {}), + ...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}), + ...(cacheCreationTokens !== undefined ? { cacheCreationTokens } : {}), + ...(totalTokens !== undefined ? { totalTokens } : {}), + }); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/options.ts b/packages/clanker-cleanroom-plugin-agentfield/src/options.ts new file mode 100644 index 0000000..700a9b9 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/options.ts @@ -0,0 +1,23 @@ +import type { Remaps } from "clanker-cleanroom"; + +/** Schema with a Zod-like `parse` (Zod 3/4 or compatible). */ +export type ParseableSchema = { + parse: (value: unknown) => unknown; +}; + +export type ClankerOptions = { + /** Stock name (`cursor`, `claude`) or registry tag (`cursor:node`). */ + agent: string; + /** Host workspace mounted at `/workspace`. */ + workspace: string; + model?: string; + /** Override the agent's default Docker image. */ + image?: string; + remaps?: Remaps; + signal?: AbortSignal; + /** + * When set, appends AgentField-style OUTPUT REQUIREMENTS and validates + * `.agentfield_output.json` written into {@link workspace}. + */ + schema?: ParseableSchema | unknown; +}; diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.spec.ts b/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.spec.ts new file mode 100644 index 0000000..33d0c2c --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.spec.ts @@ -0,0 +1,151 @@ +import { + CostTracker, + createHarnessResult, + ExecutionContext, + usageSummaryOrNull, +} from "@agentfield/sdk"; +import { describe, expect } from "vitest"; +import test from "vitest-gwt"; + +import { harnessNameForAgent, recordClankerUsage } from "./record-usage.js"; + +type Context = { + tracker: CostTracker; + harnessName?: string; +}; + +describe("harnessNameForAgent", () => { + test("prefixes and sanitizes agent names", { + when: { + naming_cursor_node, + }, + then: { + name_is_clanker_cursor_node, + }, + }); +}); + +describe("recordClankerUsage", () => { + test("records harness entry when execution context is active", { + given: { + active_execution_with_tracker, + }, + when: { + recording_usage_with_cost_and_tokens, + }, + then: { + tracker_has_harness_entry, + }, + }); + + test("skips empty metrics", { + given: { + active_execution_with_tracker, + }, + when: { + recording_empty_usage, + }, + then: { + tracker_is_empty, + }, + }); + + test("no-ops without execution context", { + when: { + recording_usage_without_context, + }, + then: { + does_not_throw, + }, + }); +}); + +function naming_cursor_node(this: Context) { + this.harnessName = harnessNameForAgent("cursor:node"); +} + +function name_is_clanker_cursor_node(this: Context) { + expect(this.harnessName).toBe("clanker_cursor_node"); +} + +function active_execution_with_tracker(this: Context) { + this.tracker = new CostTracker(); +} + +function recording_usage_with_cost_and_tokens(this: Context) { + const fakeCtx = { + costTracker: this.tracker, + metadata: { reasonerId: "fix", executionId: "exec-1" }, + } as ExecutionContext; + + ExecutionContext.run(fakeCtx, () => { + recordClankerUsage( + createHarnessResult({ + costUsd: 0.42, + inputTokens: 10, + outputTokens: 20, + totalTokens: 30, + numTurns: 2, + durationMs: 100, + sessionId: "sess", + }), + { agent: "cursor", model: "auto" }, + ); + }); +} + +function tracker_has_harness_entry(this: Context) { + const summary = usageSummaryOrNull(this.tracker); + expect(summary).not.toBeNull(); + expect(summary!.entries).toHaveLength(1); + expect(summary!.entries[0]).toMatchObject({ + source: "harness", + harness: "clanker_cursor", + model: "auto", + reasoner: "fix", + cost_usd: 0.42, + input_tokens: 10, + output_tokens: 20, + total_tokens: 30, + }); +} + +function recording_empty_usage(this: Context) { + const fakeCtx = { + costTracker: this.tracker, + metadata: { reasonerId: "fix", executionId: "exec-1" }, + } as ExecutionContext; + + ExecutionContext.run(fakeCtx, () => { + recordClankerUsage( + createHarnessResult({ + numTurns: 0, + durationMs: 0, + sessionId: "", + }), + { agent: "cursor" }, + ); + }); +} + +function tracker_is_empty(this: Context) { + expect(this.tracker.callCount).toBe(0); + expect(usageSummaryOrNull(this.tracker)).toBeNull(); +} + +function recording_usage_without_context(this: Context) { + recordClankerUsage( + createHarnessResult({ + costUsd: 1, + numTurns: 1, + durationMs: 1, + sessionId: "x", + inputTokens: 1, + }), + { agent: "claude" }, + ); +} + +function does_not_throw(this: Context) { + expect(true).toBe(true); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.ts b/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.ts new file mode 100644 index 0000000..a10bca3 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/record-usage.ts @@ -0,0 +1,66 @@ +import { + deriveProvider, + ExecutionContext, + type HarnessResult, +} from "@agentfield/sdk"; + +/** Sanitize a cleanroom agent name for the harness field (`cursor:node` → `clanker_cursor_node`). */ +export function harnessNameForAgent(agentName: string): string { + const sanitized = agentName.replaceAll(/[^a-zA-Z0-9]+/g, "_").replaceAll(/^_|_$/g, ""); + return `clanker_${sanitized || "agent"}`; +} + +/** + * Record a clanker run into the current execution's CostTracker. + * Mirrors AgentField's private `recordHarnessUsage`: skip empty entries, never throw. + */ +export function recordClankerUsage( + result: HarnessResult, + options: { agent: string; model?: string }, +): void { + try { + const current = ExecutionContext.getCurrent(); + const tracker = current?.costTracker; + if (!tracker) { + return; + } + + const inputTokens = result.inputTokens ?? 0; + const outputTokens = result.outputTokens ?? 0; + const cacheRead = result.cacheReadTokens ?? 0; + const cacheCreation = result.cacheCreationTokens ?? 0; + const reportedTotal = result.totalTokens ?? 0; + const cost = + typeof result.costUsd === "number" && Number.isFinite(result.costUsd) ? result.costUsd : null; + + if ( + !inputTokens && + !outputTokens && + !cacheRead && + !cacheCreation && + !reportedTotal && + cost === null + ) { + return; + } + + const modelName = String(result.model ?? options.model ?? options.agent); + + tracker.record({ + model: modelName, + inputTokens, + outputTokens, + totalTokens: reportedTotal || inputTokens + outputTokens, + costUsd: cost, + reasonerName: current.metadata.reasonerId ?? null, + source: "harness", + provider: deriveProvider(modelName), + harness: harnessNameForAgent(options.agent), + cacheReadTokens: cacheRead, + cacheCreationTokens: cacheCreation, + costSource: cost !== null ? "provider" : null, + }); + } catch { + // Best effort — never let usage recording fail the clanker call. + } +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/register.ts b/packages/clanker-cleanroom-plugin-agentfield/src/register.ts new file mode 100644 index 0000000..bda1db0 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/register.ts @@ -0,0 +1,3 @@ +import { installClanker } from "./install.js"; + +installClanker(); diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/schema.ts b/packages/clanker-cleanroom-plugin-agentfield/src/schema.ts new file mode 100644 index 0000000..16f6e03 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/src/schema.ts @@ -0,0 +1,58 @@ +import fs from "node:fs"; +import path from "node:path"; + +export const OUTPUT_FILENAME = ".agentfield_output.json"; + +type ParseableSchema = { + parse: (value: unknown) => unknown; +}; + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function hasParse(value: unknown): value is ParseableSchema { + return isRecord(value) && typeof value.parse === "function"; +} + +export function getOutputPath(workspace: string): string { + return path.join(workspace, OUTPUT_FILENAME); +} + +export function buildPromptSuffix(workspace: string): string { + const outputPath = getOutputPath(workspace); + return ( + `\n\nOUTPUT REQUIREMENTS:\n` + + `When you are finished, write a single JSON object to ${outputPath} ` + + `that satisfies the caller's schema. Do not wrap it in markdown. ` + + `The file must be valid JSON.` + ); +} + +export function readOutputFile(workspace: string): unknown | null { + const outputPath = getOutputPath(workspace); + if (!fs.existsSync(outputPath)) { + return null; + } + try { + const raw = fs.readFileSync(outputPath, "utf8"); + return JSON.parse(raw) as unknown; + } catch { + return null; + } +} + +export function parseAndValidate(workspace: string, schema: unknown): unknown | null { + const data = readOutputFile(workspace); + if (data === null) { + return null; + } + if (!hasParse(schema)) { + return data; + } + try { + return schema.parse(data); + } catch { + return null; + } +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/tsconfig.json b/packages/clanker-cleanroom-plugin-agentfield/tsconfig.json new file mode 100644 index 0000000..eeb8dea --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "rootDir": "./src", + "declaration": true, + "sourceMap": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ES2022", + "skipLibCheck": true, + "noUncheckedIndexedAccess": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "exactOptionalPropertyTypes": true, + "types": ["node"] + }, + "include": ["./src"] +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/vite.config.ts b/packages/clanker-cleanroom-plugin-agentfield/vite.config.ts new file mode 100644 index 0000000..864b8e3 --- /dev/null +++ b/packages/clanker-cleanroom-plugin-agentfield/vite.config.ts @@ -0,0 +1,35 @@ +import { defineConfig } from "vite-plus"; + +export default defineConfig({ + pack: { + entry: { + index: "src/index.ts", + register: "src/register.ts", + }, + format: ["esm", "cjs"], + dts: true, + sourcemap: true, + outDir: "lib", + platform: "node", + root: "src", + }, + lint: { + ignorePatterns: ["lib/**", "coverage/**"], + overrides: [ + { + files: ["**/*.spec.ts"], + rules: { + "unicorn/no-thenable": "off", + }, + }, + ], + }, + test: { + include: ["src/**/*.spec.ts"], + coverage: { + provider: "v8", + include: ["src/**/*.ts"], + exclude: ["src/**/*.spec.ts"], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b621e0..d494c3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,10 +41,10 @@ importers: devDependencies: vite-plus: specifier: 'catalog:' - version: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) vitest: specifier: 'catalog:' - version: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) packages/agent-gwt: dependencies: @@ -72,10 +72,10 @@ importers: version: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' vite-plus: specifier: 'catalog:' - version: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) vitest: specifier: 'catalog:' - version: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) vitest-gwt: specifier: 'catalog:' version: 4.1.4(vitest@4.1.11) @@ -103,10 +103,10 @@ importers: version: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' vite-plus: specifier: 'catalog:' - version: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) vitest: specifier: 'catalog:' - version: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) vitest-gwt: specifier: 'catalog:' version: 4.1.4(vitest@4.1.11) @@ -134,10 +134,10 @@ importers: version: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' vite-plus: specifier: 'catalog:' - version: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) vitest: specifier: 'catalog:' - version: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) vitest-gwt: specifier: 'catalog:' version: 4.1.4(vitest@4.1.11) @@ -165,10 +165,10 @@ importers: version: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' vite-plus: specifier: 'catalog:' - version: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) vitest: specifier: 'catalog:' - version: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) vitest-gwt: specifier: 'catalog:' version: 4.1.4(vitest@4.1.11) @@ -176,8 +176,124 @@ importers: specifier: 'catalog:' version: 0.14.13 + packages/clanker-cleanroom-plugin-agentfield: + dependencies: + clanker-cleanroom: + specifier: workspace:* + version: link:../clanker-cleanroom + devDependencies: + '@agentfield/sdk': + specifier: ^0.1.141 + version: 0.1.141(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0) + '@types/node': + specifier: 'catalog:' + version: 26.4.0 + '@vitest/coverage-v8': + specifier: 'catalog:' + version: 4.1.11(@vitest/browser@4.1.11)(vitest@4.1.11) + typescript: + specifier: 'catalog:' + version: 7.0.2 + vite: + specifier: 'catalog:' + version: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' + vite-plus: + specifier: 'catalog:' + version: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + vitest: + specifier: 'catalog:' + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest-gwt: + specifier: 'catalog:' + version: 4.1.4(vitest@4.1.11) + wireit: + specifier: 'catalog:' + version: 0.14.13 + zod: + specifier: ^3.22.4 + version: 3.25.76 + packages: + '@agentfield/sdk@0.1.141': + resolution: {integrity: sha512-sU7Zb/jQ0M7y8x5vWLXRJpvyGTZ2gcxJcNlAVn4m02feVe/hnwRIQhwsl4QEEsyU3drNWPk/A9fOMVBUxvp4Vw==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@anthropic-ai/claude-agent-sdk': '*' + peerDependenciesMeta: + '@anthropic-ai/claude-agent-sdk': + optional: true + + '@ai-sdk/anthropic@3.0.129': + resolution: {integrity: sha512-97IV+oX8c3MAdqFgFYTXuumlcs5htg7w1Lye1pr+rFoNzNX/uSUdP56t0bhyeDvvD6TlZroBqgD5VnHrmYr0IA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/cohere@3.0.68': + resolution: {integrity: sha512-Mo2lOa8DAN5RQwL5MLTh/BT4KTgtYnLKuzNDzT7U4q5jzn0GX149J1UFhlZKajVA4fLme2g8n4jjS9Q1mOP5DA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/deepseek@2.0.71': + resolution: {integrity: sha512-2uLtZBgONfzEP7tZOg23sBzi33n1/gcW1zLNNw96/PLt9vdqDYIkGQnKRd6F+/0Wwy77jVulU+gzpiudk3f0UQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/gateway@3.0.212': + resolution: {integrity: sha512-iTJSim/6LuSxiG3RF0FWU7bEQ8dF6EplcWci5Km4Vc8SUcR8vxFuC7T/pfCutW00pI/3WYsHm8RCQ5141/Xykw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/google@3.0.131': + resolution: {integrity: sha512-wztgK14qFScRr+xRoDU/bc1H+Q218GbSSBeiTc5pyQoxtkUOp0EdBFF8aswS/aHIs55JCQIjmlJ65Z7Bh5biNA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/groq@3.0.72': + resolution: {integrity: sha512-XZjv3yIGkUNHRoIo/jb5HGOJwTcXw6th5M5SSoV7s0YN9LmC4BKt3bWPcbJQwSLSka+N+xqVGwbBBo5unewBuw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/mistral@3.0.70': + resolution: {integrity: sha512-0vkrpXtF2rX4N5VmBIwt98VM3Ar3D7p1WIKATSUoQZ6Hu4BwXaN3GrmgEu6hQUMG+NE3spF6ptMCKyyYENj09w==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/openai-compatible@2.0.81': + resolution: {integrity: sha512-L14Jd0lAFKNM42l9TxlpwkNiyMlSvSvGySLc9GN4FB0qOo4/WmYOeLyn/CPhghIr0K4O6vH1y0nChxGljq2ccg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/openai@3.0.125': + resolution: {integrity: sha512-nTpvcroTmK+XPOHQ3qq4VkRuzP7AOHU2o909JkjRFEJ9SxZZ9UtMPyefm9SLh7G/8A1fjp7lormr6ReUHXqixw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.57': + resolution: {integrity: sha512-89a7sPvZqXsP3PigcAQLWntu/duIVEcN/RyChAB+j6p3C7NwW767sVttvL8r0+BetTg63uAXQoYHCZZueQKBSw==} + engines: {node: '>=18.17'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@3.0.18': + resolution: {integrity: sha512-IpefF5ssZVOZCD4Wu7zxt6PwZoGT2HLVjxpJ10Bjx6EAmRfLYJPjyrfxb0RYDlwvXnDb9nkQ7Do/oJVDuRFzew==} + engines: {node: '>=18'} + + '@ai-sdk/xai@3.0.139': + resolution: {integrity: sha512-epoKIfuCcmQh6uVn90OESeWmr7mqPJ3YtXNXStdpRvXLVqPmo47pnDUW/AH1vyvZ+6gsKg9TbSGVvyGeFQyHlg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -232,6 +348,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + '@oxc-project/runtime@0.146.0': resolution: {integrity: sha512-lbXHIpZ1MmK6zuw5txlMdIZ2waLVUIU5Gnm3sEuwJOiqDfQfbtjeHscatmeBoxbv8+If9LFM6PGh/3DcDWYIYw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -672,6 +792,10 @@ packages: cpu: [x64] os: [win32] + '@vercel/oidc@3.2.0': + resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} + engines: {node: '>= 20'} + '@vitest/browser-preview@4.1.11': resolution: {integrity: sha512-iPKSE6Ibayey6HFgK1V1/aHgyhx7HSRk1YMi+lnBZGmlIiNV5Uc7xRkD9Su8RDylTxDECK23t7kTHdRKoqSYDQ==} peerDependencies: @@ -954,6 +1078,20 @@ packages: '@yuku-toolchain/types@0.5.43': resolution: {integrity: sha512-kSpvPntnXw5+lYjO71ffBEnQ5ycQ74KGIYknh0TS4xeyCuBkOqxyJumxZkMhLBBUCLjDAbx2+Icnr3Zh4ftjpQ==} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ai@6.0.303: + resolution: {integrity: sha512-4HE3naLXgRLN4XOoEJaPHfIz7/hO0A21ltUG5DM3NDrGVTrqhnfs7s3ItwHtiWazCDOIuc4cCE4MgiuEvVryCw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -969,6 +1107,9 @@ packages: aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -976,6 +1117,12 @@ packages: ast-v8-to-istanbul@1.0.5: resolution: {integrity: sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} @@ -984,6 +1131,10 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + body-parser@1.20.8: + resolution: {integrity: sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + brace-expansion@5.0.9: resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} engines: {node: 20 || >=22} @@ -992,6 +1143,18 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -1000,13 +1163,61 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1014,16 +1225,68 @@ packages: dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@2.3.2: resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} + engines: {node: '>=18.0.0'} + expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.7.1: + resolution: {integrity: sha512-2FXbqkygil3mZiXzEtM0IjE/UBmBNot0J1GEVrJT4JbrvwOSoEtqtO+wHbiMQELWe1eNvHoYRg2dkjOid+6JkA==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@4.22.3: + resolution: {integrity: sha512-Bdcs4+3qlpVlx2NRn6fgX2Ue2/gGRaPeawebgclM0ERSCqDpA+owF1fdPwjJUTAJWMTuAaxjDf+hzb0/4eKvvw==} + engines: {node: '>= 0.10.0'} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -1044,15 +1307,55 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + + follow-redirects@1.16.1: + resolution: {integrity: sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1063,9 +1366,44 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.7.3: + resolution: {integrity: sha512-A1kdq/tSb5QjvKvAMgIoEvDBIgL7qaqVP/jkvSwYYRZ9iEzvPpopxp2wQfu3SuZRHtpHNxMn8Fs0bS+gf5Xmwg==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -1094,6 +1432,9 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + js-jsonl@1.1.1: resolution: {integrity: sha512-VkkV3ac6N6tRaK32NIaXStzs9l3py/XK5pCbTEyiUt5Ch5We3H8ZcrSQndQ4TyIisfKMIjvoiTNWsb7mhQcZZw==} @@ -1103,6 +1444,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} @@ -1194,31 +1538,77 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + oxfmt@0.64.0: resolution: {integrity: sha512-XZ4GFBN/PLbXKq+0zrgpQfPKYuJlUuj+nzZJY7UpIbFMNyefNLCdN9EwViycNqnYcv0wrn0jXcQLlqJp8RCKBg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1249,6 +1639,13 @@ packages: vite-plus: optional: true + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -1278,9 +1675,29 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + proxy-addr@2.0.8: + resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} + engines: {node: '>= 0.10'} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -1299,11 +1716,44 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1321,6 +1771,10 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@4.2.0: resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} @@ -1351,10 +1805,18 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + typescript@7.0.2: resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} engines: {node: '>=16.20.0'} @@ -1363,6 +1825,22 @@ packages: undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + undici@6.29.0: + resolution: {integrity: sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==} + engines: {node: '>=18.17'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vite-plus@0.3.0: resolution: {integrity: sha512-GNWbWuWD37frCSFrz6MLzUo62bTv5IOJozHEgZYOkxsLkuQtTwm4TowzpfoGrSsfwhAAtfPd/sK1Y0+v1SwhZA==} engines: {node: ^20.19.0 || ^22.18.0 || >=24.11.0} @@ -1450,8 +1928,115 @@ packages: yuku-parser@0.5.48: resolution: {integrity: sha512-OWBfhrpgK9+/4+IXG9oT8Bao4AhViQA7vdyNNH7EUg8dQYgwa70XtIBWTpCEme1P1ECyoDNYkn0wT63f8XRcVA==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + snapshots: + '@agentfield/sdk@0.1.141(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@ai-sdk/anthropic': 3.0.129(zod@3.25.76) + '@ai-sdk/cohere': 3.0.68(zod@3.25.76) + '@ai-sdk/deepseek': 2.0.71(zod@3.25.76) + '@ai-sdk/google': 3.0.131(zod@3.25.76) + '@ai-sdk/groq': 3.0.72(zod@3.25.76) + '@ai-sdk/mistral': 3.0.70(zod@3.25.76) + '@ai-sdk/openai': 3.0.125(zod@3.25.76) + '@ai-sdk/xai': 3.0.139(zod@3.25.76) + ai: 6.0.303(zod@3.25.76) + axios: 1.20.0(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0) + dotenv: 16.6.1 + express: 4.22.3(supports-color@7.2.0) + express-rate-limit: 8.7.1(express@4.22.3(supports-color@7.2.0))(supports-color@7.2.0) + jose: 5.10.0 + ws: 8.21.3 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + + '@ai-sdk/anthropic@3.0.129(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/cohere@3.0.68(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/deepseek@2.0.71(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/gateway@3.0.212(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + '@vercel/oidc': 3.2.0 + zod: 3.25.76 + + '@ai-sdk/google@3.0.131(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/groq@3.0.72(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/mistral@3.0.70(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/openai-compatible@2.0.81(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/openai@3.0.125(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/provider-utils@4.0.57(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.18 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.1.1 + undici: 6.29.0 + zod: 3.25.76 + + '@ai-sdk/provider@3.0.18': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/xai@3.0.139(zod@3.25.76)': + dependencies: + '@ai-sdk/openai-compatible': 2.0.81(zod@3.25.76) + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + zod: 3.25.76 + '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -1498,6 +2083,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.2 + '@opentelemetry/api@1.9.1': {} + '@oxc-project/runtime@0.146.0': {} '@oxc-project/types@0.146.0': {} @@ -1732,12 +2319,14 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true + '@vercel/oidc@3.2.0': {} + '@vitest/browser-preview@4.1.11(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(vitest@4.1.11)': dependencies: '@testing-library/dom': 10.4.1 '@testing-library/user-event': 14.6.6(@testing-library/dom@10.4.1) '@vitest/browser': 4.1.11(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(vitest@4.1.11) - vitest: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) transitivePeerDependencies: - bufferutil - msw @@ -1753,7 +2342,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) ws: 8.21.3 transitivePeerDependencies: - bufferutil @@ -1773,7 +2362,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) optionalDependencies: '@vitest/browser': 4.1.11(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(vitest@4.1.11) @@ -1931,6 +2520,25 @@ snapshots: '@yuku-toolchain/types@0.5.43': {} + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + agent-base@6.0.2(supports-color@7.2.0): + dependencies: + debug: 4.4.3(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + ai@6.0.303(zod@3.25.76): + dependencies: + '@ai-sdk/gateway': 3.0.212(zod@3.25.76) + '@ai-sdk/provider': 3.0.18 + '@ai-sdk/provider-utils': 4.0.57(zod@3.25.76) + '@opentelemetry/api': 1.9.1 + zod: 3.25.76 + ansi-regex@5.0.1: {} ansi-styles@5.2.0: {} @@ -1944,6 +2552,8 @@ snapshots: dependencies: dequal: 2.0.3 + array-flatten@1.1.1: {} + assertion-error@2.0.1: {} ast-v8-to-istanbul@1.0.5: @@ -1952,10 +2562,39 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 + asynckit@0.4.0: {} + + axios@1.20.0(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + follow-redirects: 1.16.1(debug@4.4.3(supports-color@7.2.0)) + form-data: 4.0.6 + https-proxy-agent: 5.0.1(supports-color@7.2.0) + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + balanced-match@4.0.4: {} binary-extensions@2.3.0: {} + body-parser@1.20.8(supports-color@7.2.0): + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9(supports-color@7.2.0) + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.16.0 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -1964,6 +2603,18 @@ snapshots: dependencies: fill-range: 7.1.1 + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + chai@6.2.2: {} chokidar@3.6.0: @@ -1978,22 +2629,131 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-signature@1.0.7: {} + + cookie@0.7.2: {} + + debug@2.6.9(supports-color@7.2.0): + dependencies: + ms: 2.0.0 + optionalDependencies: + supports-color: 7.2.0 + + debug@4.4.3(supports-color@7.2.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + dequal@2.0.3: {} + destroy@1.2.0: {} + detect-libc@2.1.2: {} dom-accessibility-api@0.5.16: {} + dotenv@16.6.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@2.3.2: {} + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + escape-html@1.0.3: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 + etag@1.8.1: {} + + eventsource-parser@3.1.1: {} + expect-type@1.4.0: {} + express-rate-limit@8.7.1(express@4.22.3(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + debug: 4.4.3(supports-color@7.2.0) + express: 4.22.3(supports-color@7.2.0) + ip-address: 10.7.3 + transitivePeerDependencies: + - supports-color + + express@4.22.3(supports-color@7.2.0): + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.8(supports-color@7.2.0) + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9(supports-color@7.2.0) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2(supports-color@7.2.0) + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.8 + qs: 6.16.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2(supports-color@7.2.0) + serve-static: 1.16.3(supports-color@7.2.0) + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2014,21 +2774,106 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@1.3.2(supports-color@7.2.0): + dependencies: + debug: 2.6.9(supports-color@7.2.0) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + follow-redirects@1.16.1(debug@4.4.3(supports-color@7.2.0)): + optionalDependencies: + debug: 4.4.3(supports-color@7.2.0) + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} gwt-runner@3.0.0: {} has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + html-escaper@2.0.2: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@5.0.1(supports-color@7.2.0): + dependencies: + agent-base: 6.0.2(supports-color@7.2.0) + debug: 4.4.3(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + ip-address@10.7.3: {} + + ipaddr.js@1.9.1: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -2054,6 +2899,8 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + jose@5.10.0: {} + js-jsonl@1.1.1: dependencies: '@sindresorhus/is': 4.6.0 @@ -2062,6 +2909,8 @@ snapshots: js-tokens@4.0.0: {} + json-schema@0.4.0: {} + jsonc-parser@3.3.1: {} lightningcss-android-arm64@1.33.0: @@ -2129,22 +2978,50 @@ snapshots: dependencies: semver: 7.8.5 + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + merge2@1.4.1: {} + methods@1.1.2: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.2 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + mrmime@2.0.1: {} + ms@2.0.0: {} + + ms@2.1.3: {} + nanoid@3.3.18: {} + negotiator@0.6.3: {} + normalize-path@3.0.0: {} + object-inspect@1.13.4: {} + obug@2.1.4: {} - oxfmt@0.64.0(vite-plus@0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)): + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + oxfmt@0.64.0(vite-plus@0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -2167,7 +3044,7 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.64.0 '@oxfmt/binding-win32-ia32-msvc': 0.64.0 '@oxfmt/binding-win32-x64-msvc': 0.64.0 - vite-plus: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + vite-plus: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) oxlint-tsgolint@7.0.2001: optionalDependencies: @@ -2178,7 +3055,7 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 7.0.2001 '@oxlint-tsgolint/win32-x64': 7.0.2001 - oxlint@1.79.0(oxlint-tsgolint@7.0.2001)(vite-plus@0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)): + oxlint@1.79.0(oxlint-tsgolint@7.0.2001)(vite-plus@0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.79.0 '@oxlint/binding-android-arm64': 1.79.0 @@ -2200,7 +3077,11 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.79.0 '@oxlint/binding-win32-x64-msvc': 1.79.0 oxlint-tsgolint: 7.0.2001 - vite-plus: 0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + vite-plus: 0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2) + + parseurl@1.3.3: {} + + path-to-regexp@0.1.13: {} pathe@2.0.3: {} @@ -2230,8 +3111,29 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 + proxy-addr@2.0.8: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + proxy-from-env@2.1.0: {} + + qs@6.16.0: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + queue-microtask@1.2.3: {} + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + react-is@17.0.2: {} readdirp@3.6.0: @@ -2246,8 +3148,69 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + semver@7.8.5: {} + send@0.19.2(supports-color@7.2.0): + dependencies: + debug: 2.6.9(supports-color@7.2.0) + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.3(supports-color@7.2.0): + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -2262,6 +3225,8 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@4.2.0: {} supports-color@7.2.0: @@ -2285,8 +3250,15 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + totalist@3.0.1: {} + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + typescript@7.0.2: optionalDependencies: '@typescript/typescript-aix-ppc64': 7.0.2 @@ -2312,7 +3284,15 @@ snapshots: undici-types@8.3.0: {} - vite-plus@0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2): + undici@6.29.0: {} + + unpipe@1.0.0: {} + + utils-merge@1.0.1: {} + + vary@1.1.2: {} + + vite-plus@0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2): dependencies: '@oxc-project/types': 0.146.0 '@oxlint/plugins': 1.79.0 @@ -2326,10 +3306,10 @@ snapshots: '@vitest/spy': 4.1.11 '@vitest/utils': 4.1.11 '@voidzero-dev/vite-plus-core': 0.3.0(@types/node@26.4.0)(typescript@7.0.2) - oxfmt: 0.64.0(vite-plus@0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)) - oxlint: 1.79.0(oxlint-tsgolint@7.0.2001)(vite-plus@0.3.0(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)) + oxfmt: 0.64.0(vite-plus@0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)) + oxlint: 1.79.0(oxlint-tsgolint@7.0.2001)(vite-plus@0.3.0(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(typescript@7.0.2)) oxlint-tsgolint: 7.0.2001 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.3.0 '@voidzero-dev/vite-plus-darwin-x64': 0.3.0 @@ -2373,9 +3353,9 @@ snapshots: vitest-gwt@4.1.4(vitest@4.1.11): dependencies: gwt-runner: 3.0.0 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) + vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) - vitest@4.1.11(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)): + vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(@vitest/browser-preview@4.1.11)(@vitest/coverage-v8@4.1.11)(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)): dependencies: '@vitest/expect': 4.1.11 '@vitest/mocker': 4.1.11(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)) @@ -2398,6 +3378,7 @@ snapshots: vite: '@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2)' why-is-node-running: 2.3.0 optionalDependencies: + '@opentelemetry/api': 1.9.1 '@types/node': 26.4.0 '@vitest/browser-preview': 4.1.11(@voidzero-dev/vite-plus-core@0.3.0(@types/node@26.4.0)(typescript@7.0.2))(vitest@4.1.11) '@vitest/coverage-v8': 4.1.11(@vitest/browser@4.1.11)(vitest@4.1.11) @@ -2450,3 +3431,9 @@ snapshots: '@yuku-parser/binding-linux-x64-musl': 0.5.48 '@yuku-parser/binding-win32-arm64': 0.5.48 '@yuku-parser/binding-win32-x64': 0.5.48 + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} From 2595bbb21faba352f050304f1acfa3d4c238e9d6 Mon Sep 17 00:00:00 2001 From: Eric Siebeneich Date: Wed, 14 Oct 2026 11:52:20 -0500 Subject: [PATCH 4/4] Forward optional deps through agent.clanker. Stock install dropped the third argument, so createAgent could not stage /agent/input and /agent/output from AgentField reasoners. --- .../README.md | 4 +- .../src/install.spec.ts | 47 ++++++++++++++++++- .../src/install.ts | 19 ++++++-- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/packages/clanker-cleanroom-plugin-agentfield/README.md b/packages/clanker-cleanroom-plugin-agentfield/README.md index ae55203..098a21e 100644 --- a/packages/clanker-cleanroom-plugin-agentfield/README.md +++ b/packages/clanker-cleanroom-plugin-agentfield/README.md @@ -33,7 +33,9 @@ agent.reasoner("fix", async () => { }); ``` -Or call `installClanker()` / the free `clanker(prompt, options)` helper from the package root instead of the `/register` side-effect. +Or call `installClanker()` / the free `clanker(prompt, options, deps?)` helper from the package root instead of the `/register` side-effect. + +Optional third argument `deps` is forwarded the same way on both `agent.clanker` and free `clanker` — pass `{ createAgent }` to reuse a staged cleanroom `Agent` (for `/agent/input` + `/agent/output`). ## Options diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts b/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts index 1fe4fd5..0469781 100644 --- a/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts +++ b/packages/clanker-cleanroom-plugin-agentfield/src/install.spec.ts @@ -1,12 +1,15 @@ import { Agent } from "@agentfield/sdk"; -import { describe, expect } from "vitest"; +import { describe, expect, vi } from "vitest"; import test from "vitest-gwt"; +import * as clankerModule from "./clanker.js"; import { installClanker } from "./install.js"; type Context = { first?: typeof Agent.prototype.clanker; second?: typeof Agent.prototype.clanker; + createAgent?: ReturnType; + clankerSpy?: ReturnType; }; describe("installClanker", () => { @@ -18,6 +21,19 @@ describe("installClanker", () => { method_exists_and_is_stable, }, }); + + test("forwards optional deps to free clanker", { + given: { + installed_clanker, + spy_on_free_clanker, + }, + when: { + calling_agent_clanker_with_deps, + }, + then: { + free_clanker_received_deps, + }, + }); }); function installing_twice(this: Context) { @@ -31,3 +47,32 @@ function method_exists_and_is_stable(this: Context) { expect(typeof this.first).toBe("function"); expect(this.second).toBe(this.first); } + +function installed_clanker() { + installClanker(); +} + +function spy_on_free_clanker(this: Context) { + this.clankerSpy = vi.spyOn(clankerModule, "clanker").mockResolvedValue({ + text: "", + isError: false, + } as Awaited>); +} + +async function calling_agent_clanker_with_deps(this: Context) { + this.createAgent = vi.fn(); + await Agent.prototype.clanker!( + "prompt", + { agent: "cursor", workspace: "/tmp/ws" }, + { createAgent: this.createAgent as never }, + ); +} + +function free_clanker_received_deps(this: Context) { + expect(this.clankerSpy).toHaveBeenCalledWith( + "prompt", + { agent: "cursor", workspace: "/tmp/ws" }, + { createAgent: this.createAgent }, + ); + this.clankerSpy?.mockRestore(); +} diff --git a/packages/clanker-cleanroom-plugin-agentfield/src/install.ts b/packages/clanker-cleanroom-plugin-agentfield/src/install.ts index b412783..c73d4ac 100644 --- a/packages/clanker-cleanroom-plugin-agentfield/src/install.ts +++ b/packages/clanker-cleanroom-plugin-agentfield/src/install.ts @@ -1,6 +1,6 @@ import { Agent, type HarnessResult } from "@agentfield/sdk"; -import { clanker } from "./clanker.js"; +import { clanker, type ClankerDeps } from "./clanker.js"; import type { ClankerOptions } from "./options.js"; const INSTALLED = Symbol.for("@clanker-cleanroom/plugin-agentfield.installed"); @@ -8,12 +8,16 @@ const INSTALLED = Symbol.for("@clanker-cleanroom/plugin-agentfield.installed"); type AgentConstructor = typeof Agent; type AgentPrototype = { - clanker?: (prompt: string, options: ClankerOptions) => Promise; + clanker?: ( + prompt: string, + options: ClankerOptions, + deps?: ClankerDeps, + ) => Promise; [INSTALLED]?: boolean; }; /** - * Monkeypatch {@link Agent}.prototype with `clanker(prompt, options)`. + * Monkeypatch {@link Agent}.prototype with `clanker(prompt, options, deps?)`. * Idempotent — safe to call more than once. */ export function installClanker(AgentClass: AgentConstructor = Agent): void { @@ -26,14 +30,19 @@ export function installClanker(AgentClass: AgentConstructor = Agent): void { this: Agent, prompt: string, options: ClankerOptions, + deps?: ClankerDeps, ): Promise { - return clanker(prompt, options); + return clanker(prompt, options, deps); }; proto[INSTALLED] = true; } declare module "@agentfield/sdk" { interface Agent { - clanker(prompt: string, options: ClankerOptions): Promise; + clanker( + prompt: string, + options: ClankerOptions, + deps?: ClankerDeps, + ): Promise; } }