From 6a0e9de55f5fa6bfcdcf784c53f5fa788443e14e Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Mon, 28 Sep 2026 18:31:43 +0000 Subject: [PATCH 1/6] Add an Atomic SDK harness for the hosted Planner HARNESS=atomic embeds Atomic 0.9.23 in the server process through its headless SDK (createAgentSession, ModelRuntime, DefaultResourceLoader, and in-memory session and settings managers). It does not spawn the atomic CLI, use RPC mode, or alias Pi's runtime. Each harness session owns one Atomic AgentSession in a private temporary directory. Every shipped Atomic package is off, the tool allowlist holds only the host tools and a result tool, and the loader discovers no extensions, skills, prompt templates, or context files. A per-turn hook replaces the whole system prompt, so the model never sees Atomic's coding-agent preamble. The adapter fails the turn before any model request if the live session reports an extra extension, tool, context file, skill, prompt template, or system prompt. It checks the tools offered to the model again before every model request. Host tools round-trip through submitToolResult and settle on abort. Structured output uses a terminating result tool enabled only from the turn's JSON response format, which captures the calling model's arguments without a second inference. An unrecognized provider/model fails the turn instead of letting Atomic pick another model, and MODEL is now required for HARNESS=atomic as it is for Pi. HARNESS_AUTH is required and is either auto or ai-gateway. auto copies the host's Atomic login into memory and is refused off loopback; ai-gateway accepts only vercel-ai-gateway models. Credentials are never written to disk. The Pi auth checks now share the same table with unchanged messages. Docs cover selection, trust, credentials, and Atomic's caveats. Assistant-workflow: ralph (run 0cfa5220-f488-43ef-8bb5-2f54cf5141f2) Assistant-model: Claude Opus 5.5 Assistant-duration: 30m converged, estimated 65m Assistant-verification: bun test passed: 1683 pass, 2 PostgreSQL skips, 0 fail, including the atomic contract suite and the unchanged copilot-sdk and pi suites Assistant-verification: bun run types passed: all workspaces and E2E Assistant-verification: bun run ci passed: dprint, oxlint with no errors, tokens Assistant-verification: bun run fix passed: only formatting changes, inspected Assistant-verification: mutation checks passed: turning builtins back on, enabling skill discovery, or offering the result tool on plain turns each fail the atomic suite Assistant-verification: agent-browser E2E passed: a real Chopin server with HARNESS=atomic and a local stub model ran an @chopin turn that called read_plan and streamed the reply into Chat; the model was offered exactly PLANNER_TOOL_NAMES and Chopin's Planner prompt Assistant-verification: qlty smells passed: no blocking findings; complexity warnings match the Copilot adapter's closure shape User-preference: Build the Atomic harness on Atomic's headless SDK, which separates runtime from hosts Co-authored-by: Alex Lavaee --- .env.example | 6 +- README.md | 7 +- apps/server/package.json | 1 + apps/server/src/config.test.ts | 13 + apps/server/src/config.ts | 9 +- .../src/harness/atomic.contract.test.ts | 489 ++++++++++++++ .../server/src/harness/atomic/adapter.test.ts | 165 +++++ apps/server/src/harness/atomic/adapter.ts | 618 ++++++++++++++++++ apps/server/src/harness/harnesses.test.ts | 24 +- apps/server/src/harness/harnesses.ts | 32 +- .../src/storage/postgres/startup.test.ts | 2 +- bun.lock | 534 ++++++++++++++- docs/architecture.md | 6 +- docs/hosted-agent.md | 33 +- docs/self-hosting.md | 134 +++- package.json | 1 + 16 files changed, 1983 insertions(+), 91 deletions(-) create mode 100644 apps/server/src/harness/atomic.contract.test.ts create mode 100644 apps/server/src/harness/atomic/adapter.test.ts create mode 100644 apps/server/src/harness/atomic/adapter.ts diff --git a/.env.example b/.env.example index 157b61ea..845f169c 100644 --- a/.env.example +++ b/.env.example @@ -6,7 +6,9 @@ DATABASE_URL=postgresql://chopin:chopin@127.0.0.1:5432/chopin?sslmode=disable AGENT=on # With HARNESS=pi, use an ID from Pi's catalog, preferably provider-qualified # (for example github-copilot/gpt-5.6-luna); Pi silently substitutes its default -# model for an ID it does not know, including gpt-6-luna. +# model for an ID it does not know, including gpt-6-luna. HARNESS=atomic requires +# a provider/model ID from Atomic's catalog (for example +# vercel-ai-gateway/anthropic/claude-sonnet-4.6) and fails a turn on any other. MODEL=gpt-6-luna HARNESS=copilot-sdk # Auth mode forwarded to the selected harness. The current copilot-sdk adapter @@ -14,6 +16,8 @@ HARNESS=copilot-sdk # such as "auto" require SERVER_HOST to bind only to loopback. HARNESS=pi # requires this to be set explicitly (auto, openai, anthropic, custom, or # ai-gateway); only ai-gateway is allowed on a non-loopback SERVER_HOST. +# HARNESS=atomic requires auto (the host's Atomic login and environment keys, +# loopback only) or ai-gateway (AI_GATEWAY_API_KEY, any bind). #HARNESS_AUTH= BACKGROUND_JOBS=on WEB_RESEARCH=on diff --git a/README.md b/README.md index f1542666..50f436a6 100644 --- a/README.md +++ b/README.md @@ -72,14 +72,15 @@ and tool vocabulary remain optimized for planning. - The first eligible person to invoke the Planner or start a model-backed research request supplies the GitHub App user token used for that channel and, under the default `copilot-sdk` harness, the Copilot entitlement. With - `HARNESS=pi`, model access comes from the operator's `HARNESS_AUTH` instead. + `HARNESS=pi` or `HARNESS=atomic`, model access comes from the operator's + `HARNESS_AUTH` instead. A server restart clears every session and releases that ownership. A returning browser in local device mode can restore a new session, but does not reclaim Planner ownership. - Document and Chat context, along with repository material selected by the Planner, is sent to the harness's model provider during a turn (GitHub - Copilot by default; under `HARNESS=pi`, the provider chosen by - `HARNESS_AUTH`). Model-backed background jobs also send job-specific private + Copilot by default; under `HARNESS=pi` or `HARNESS=atomic`, the provider + chosen by `HARNESS_AUTH`). Model-backed background jobs also send job-specific private material, including context loaded during execution, to isolated workers on the same harness. The public research worker receives only the exact submitted brief, but may derive or refine the queries it sends diff --git a/apps/server/package.json b/apps/server/package.json index d5bf7113..9ff841f0 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -14,6 +14,7 @@ "@ai-sdk/harness-pi": "catalog:harness", "@ai-sdk/mcp": "catalog:harness", "@ai-sdk/sandbox-just-bash": "catalog:harness", + "@bastani/atomic": "catalog:harness", "@earendil-works/pi-coding-agent": "catalog:harness", "@chopin/dialect": "workspace:*", "@chopin/protocol": "workspace:*", diff --git a/apps/server/src/config.test.ts b/apps/server/src/config.test.ts index 23e66c49..396c1634 100644 --- a/apps/server/src/config.test.ts +++ b/apps/server/src/config.test.ts @@ -113,6 +113,19 @@ describe("configuration", () => { .toMatchObject({ harness: "pi", model: "openai/gpt-5.6" }); }); + it("requires an explicit provider/model MODEL under the atomic harness", () => { + expect(() => configured({ HARNESS: "atomic", HARNESS_AUTH: "auto" })) + .toThrow("MODEL is required when HARNESS=atomic"); + expect(configured({ + HARNESS: "atomic", + HARNESS_AUTH: "ai-gateway", + MODEL: "vercel-ai-gateway/anthropic/claude-sonnet-4.6", + })).toMatchObject({ + harness: "atomic", + model: "vercel-ai-gateway/anthropic/claude-sonnet-4.6", + }); + }); + it("requires a valid PostgreSQL URL", () => { expect(() => configured({ DATABASE_URL: undefined })).toThrow("DATABASE_URL is required"); expect(() => configured({ DATABASE_URL: "https://database.test" })).toThrow("PostgreSQL URL"); diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index e5b13483..d4b3da51 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -48,12 +48,15 @@ export type Config = { const DEFAULT_PORT = 8787; const DEFAULT_MODEL = "gpt-6-luna"; -/** The default is a Copilot model ID. Pi resolves IDs against its own catalog, - * so a Pi deployment must name its model rather than inherit one Pi lacks. */ +/** The default is a Copilot model ID. Pi and Atomic resolve IDs against their + * own catalogs, so those deployments must name a model rather than inherit one + * the catalog lacks. */ function model(harness: string): string { let configured = process.env.MODEL; if (configured) return configured; - if (harness === "pi") throw new Error("MODEL is required when HARNESS=pi"); + if (harness === "pi" || harness === "atomic") { + throw new Error(`MODEL is required when HARNESS=${harness}`); + } return DEFAULT_MODEL; } export function harnessSelection(): Pick { diff --git a/apps/server/src/harness/atomic.contract.test.ts b/apps/server/src/harness/atomic.contract.test.ts new file mode 100644 index 00000000..202297d0 --- /dev/null +++ b/apps/server/src/harness/atomic.contract.test.ts @@ -0,0 +1,489 @@ +import { HarnessCapabilityUnsupportedError } from "@ai-sdk/harness"; +import { HarnessAgent } from "@ai-sdk/harness/agent"; +import { createJustBashNetworkSandboxSession } from "@ai-sdk/sandbox-just-bash"; +import { Output, tool } from "ai"; +import { afterAll, describe, expect, it } from "bun:test"; +import { z } from "zod"; +import { mkdir, mkdtemp, readdir, readFile, rm, stat, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { + ATOMIC_DEFAULT_SYSTEM_PROMPT, + ATOMIC_RESULT_INSTRUCTION, + ATOMIC_RESULT_TOOL_NAME, + createAtomicAdapter, +} from "./atomic/adapter"; +import { harnessContract } from "./contract"; +import { startStubModelServer } from "./pi/model-stub"; + +import type { HarnessV1StartOptions, HarnessV1StreamPart } from "@ai-sdk/harness"; +import type { ToolSet } from "ai"; +import type { AtomicSettings } from "./atomic/adapter"; +import type { StubTurn } from "./pi/model-stub"; + +let stub = startStubModelServer((prompt, hasPriorToolResult): StubTurn => { + if (prompt === "again") { + return { kind: "tool", name: ATOMIC_RESULT_TOOL_NAME, arguments: '{"answer":"again"}' }; + } + if (hasPriorToolResult) return { kind: "text", text: "Done." }; + if (prompt === "tools") return { kind: "tool", name: "first_host", arguments: "{}" }; + if (prompt === "output" || prompt === "rogue") { + return { kind: "tool", name: ATOMIC_RESULT_TOOL_NAME, arguments: '{"answer":"yes"}' }; + } + if (prompt === "abort") return { kind: "hold" }; + if (prompt === "bash") return { kind: "tool", name: "bash", arguments: '{"command":"id"}' }; + return { kind: "text", text: "The Atomic stub model answered." }; +}); +afterAll(stub.stop); + +const STUB_MODEL = { + id: "stub-model", + name: "Stub Model", + reasoning: false, + input: ["text" as const], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128_000, + maxTokens: 4_096, +}; + +/** `ai-gateway` never reads the host login; the stub is a provider registered by code. */ +function createStubAtomic(overrides: Partial = {}) { + return createAtomicAdapter({ + auth: "ai-gateway", + model: "stub/stub-model", + providers: { + stub: { + baseUrl: stub.baseUrl, + apiKey: "stub-key", + api: "openai-completions", + models: [STUB_MODEL], + }, + }, + ...overrides, + }); +} + +harnessContract("atomic", createStubAtomic, createJustBashNetworkSandboxSession); + +async function run(prompt: string, options: { + structured?: boolean; + instructions?: string; + tools?: ToolSet; + model?: string; + harness?: ReturnType; +} = {}) { + let tools = options.tools ?? {}; + let agent = new HarnessAgent({ + harness: options.harness ?? createStubAtomic(), + tools, + activeTools: Object.keys(tools), + permissionMode: "allow-reads", + ...(options.instructions ? { instructions: options.instructions } : {}), + prepareCall: call => ({ ...call, model: options.model ?? call.model }), + ...(options.structured + ? { output: Output.object({ schema: z.object({ answer: z.string() }) }) } + : {}), + }); + let session = await agent.createSession({ + sandboxSession: await createJustBashNetworkSandboxSession(), + }); + try { + let result = await agent.stream({ session, prompt }); + let parts: { type: string; toolName?: string; output?: unknown }[] = []; + for await (let part of result.fullStream) { + parts.push({ + type: part.type, + ...("toolName" in part ? { toolName: part.toolName } : {}), + ...(part.type === "tool-result" ? { output: part.output } : {}), + }); + } + return { + output: options.structured ? await result.output : undefined, + text: await result.text, + parts, + resultToolParts: parts.filter(part => part.toolName === ATOMIC_RESULT_TOOL_NAME).length, + }; + } finally { + await session.destroy(); + } +} + +describe("atomic turns", () => { + it("answers a plain text turn with exactly the neutral system prompt and no tools", async () => { + stub.requests.length = 0; + let result = await run("plain"); + expect(result.text).toBe("The Atomic stub model answered."); + expect(stub.requests).toHaveLength(1); + expect(stub.requests[0]!.system).toBe(ATOMIC_DEFAULT_SYSTEM_PROMPT); + expect(stub.requests[0]!.toolNames).toEqual([]); + }); + + it("uses the turn instructions verbatim as the whole system prompt", async () => { + stub.requests.length = 0; + await run("plain", { instructions: "You are Chopin's Planner." }); + expect(stub.requests[0]!.system).toBe("You are Chopin's Planner."); + }); + + it("round-trips a host tool through submitToolResult", async () => { + stub.requests.length = 0; + let executed = 0; + let result = await run("tools", { + tools: { + first_host: tool({ + inputSchema: z.object({}), + execute: async () => { + executed++; + return { found: true }; + }, + }), + }, + }); + expect(executed).toBe(1); + expect(result.text).toBe("Done."); + expect(stub.requests.map(request => request.hasPriorToolResult)).toEqual([false, true]); + expect(stub.requests[0]!.toolNames).toEqual(["first_host"]); + expect(result.parts.filter(part => part.toolName === "first_host")).toEqual([ + { type: "tool-call", toolName: "first_host" }, + { type: "tool-result", toolName: "first_host", output: { found: true } }, + ]); + }); + + it("refuses a hallucinated Atomic built-in without running it or streaming it", async () => { + stub.requests.length = 0; + let result = await run("bash"); + expect(result.text).toBe("Done."); + expect(result.parts.filter(part => part.toolName)).toEqual([]); + expect(stub.requests.map(request => request.hasPriorToolResult)).toEqual([false, true]); + }); + + it("keeps one Atomic conversation across structured turns on a session", async () => { + stub.requests.length = 0; + let agent = new HarnessAgent({ + harness: createStubAtomic(), + activeTools: [], + output: Output.object({ schema: z.object({ answer: z.string() }) }), + }); + let session = await agent.createSession({ + sandboxSession: await createJustBashNetworkSandboxSession(), + }); + try { + expect((await agent.generate({ session, prompt: "output" })).output).toEqual({ + answer: "yes", + }); + expect((await agent.generate({ session, prompt: "again" })).output).toEqual({ + answer: "again", + }); + } finally { + await session.destroy(); + } + expect(stub.requests.map(request => [request.prompt, request.hasPriorToolResult])).toEqual([ + ["output", false], + ["again", true], + ]); + }); +}); + +describe("atomic HarnessV1 lifecycle", () => { + const HOST_TOOL = { name: "first_host", inputSchema: { type: "object" as const } }; + + function recorder() { + let parts: HarnessV1StreamPart[] = []; + let called = Promise.withResolvers(); + return { + parts, + called: called.promise, + emit(part: HarnessV1StreamPart) { + parts.push(part); + if (part.type === "tool-call") called.resolve(part.toolCallId); + }, + }; + } + + async function start() { + return createStubAtomic().doStart({ + sessionId: crypto.randomUUID(), + sandboxSession: {} as HarnessV1StartOptions["sandboxSession"], + sessionWorkDir: "/workspace", + }); + } + + it("settles a pending host tool on abort and ignores a late result", async () => { + let session = await start(); + let first = recorder(); + let controller = new AbortController(); + try { + let control = await session.doPromptTurn({ + prompt: "tools", + skills: [], + tools: [HOST_TOOL], + abortSignal: controller.signal, + emit: first.emit, + }); + let toolCallId = await first.called; + controller.abort(); + await control.done; + await control.submitToolResult({ toolCallId, output: "late" }); + expect(first.parts.map(part => part.type)).not.toContain("tool-result"); + expect(first.parts.map(part => part.type)).not.toContain("finish"); + } finally { + await session.doDestroy(); + } + }); + + it("continues a live turn on a new stream and finishes it there", async () => { + let session = await start(); + let first = recorder(); + let second = recorder(); + try { + await session.doPromptTurn({ + prompt: "tools", + skills: [], + tools: [HOST_TOOL], + emit: first.emit, + }); + let toolCallId = await first.called; + let control = await session.doContinueTurn({ + skills: [], + tools: [HOST_TOOL], + emit: second.emit, + }); + await control.submitToolResult({ toolCallId, output: "ok" }); + await control.done; + expect(second.parts.map(part => part.type)).toEqual([ + "tool-result", + "text-start", + "text-delta", + "text-end", + "finish-step", + "finish", + ]); + await expect( + session.doContinueTurn({ skills: [], tools: [HOST_TOOL], emit: second.emit }), + ).rejects.toBeInstanceOf(HarnessCapabilityUnsupportedError); + } finally { + await session.doDestroy(); + } + }); + + it("rebuilds the Atomic session for a new tool set without losing the conversation", async () => { + stub.requests.length = 0; + let session = await start(); + let first = recorder(); + try { + let control = await session.doPromptTurn({ + prompt: "tools", + skills: [], + tools: [HOST_TOOL], + emit: first.emit, + }); + await control.submitToolResult({ toolCallId: await first.called, output: "ok" }); + await control.done; + let next = await session.doPromptTurn({ + prompt: "plain", + skills: [], + tools: [{ name: "second_host", inputSchema: { type: "object" } }], + emit: () => {}, + }); + await next.done; + } finally { + await session.doDestroy(); + } + expect(stub.requests.map(request => [request.prompt, request.toolNames])).toEqual([ + ["tools", ["first_host"]], + ["tools", ["first_host"]], + ["plain", ["second_host"]], + ]); + expect(stub.requests.at(-1)!.hasPriorToolResult).toBe(true); + }); + + it("stops into a resume state it will not pretend to restore", async () => { + let session = await start(); + let state = await session.doStop(); + expect(state).toEqual({ + type: "resume-session", + harnessId: "atomic", + specificationVersion: "harness-v1", + data: {}, + }); + await expect(session.doPromptTurn({ prompt: "plain", skills: [], tools: [], emit: () => {} })) + .rejects.toThrow("closed"); + await expect( + createStubAtomic().doStart({ + sessionId: crypto.randomUUID(), + sandboxSession: {} as HarnessV1StartOptions["sandboxSession"], + sessionWorkDir: "/workspace", + resumeFrom: state, + }), + ).rejects.toBeInstanceOf(HarnessCapabilityUnsupportedError); + }); + + it("refuses skills and a host tool that claims the result tool's name", async () => { + let session = await start(); + try { + await expect(session.doPromptTurn({ + prompt: "plain", + skills: [{ name: "marker", description: "marker", content: "marker" }], + tools: [], + emit: () => {}, + })).rejects.toBeInstanceOf(HarnessCapabilityUnsupportedError); + await expect(session.doPromptTurn({ + prompt: "plain", + skills: [], + tools: [{ name: ATOMIC_RESULT_TOOL_NAME }], + emit: () => {}, + })).rejects.toThrow("is reserved for structured output"); + } finally { + await session.doDestroy(); + } + }); +}); + +describe("atomic structured-output result tool", () => { + it("ends a structured turn on the terminating tool without a follow-up model request", async () => { + stub.requests.length = 0; + let result = await run("output", { structured: true }); + expect(result.output).toEqual({ answer: "yes" }); + expect(result.resultToolParts).toBe(0); + expect(stub.requests).toHaveLength(1); + expect(stub.requests[0]!.toolNames).toEqual([ATOMIC_RESULT_TOOL_NAME]); + expect(stub.requests[0]!.system).toContain(ATOMIC_RESULT_INSTRUCTION); + }); + + it("does not offer the result tool on a plain turn", async () => { + stub.requests.length = 0; + await run("plain"); + expect(stub.requests[0]!.toolNames).not.toContain(ATOMIC_RESULT_TOOL_NAME); + }); + + it("refuses a result-tool call on a plain turn and keeps it out of the stream", async () => { + stub.requests.length = 0; + let result = await run("rogue"); + expect(result.text).toBe("Done."); + expect(result.resultToolParts).toBe(0); + expect(stub.requests.map(request => request.hasPriorToolResult)).toEqual([false, true]); + }); + + it("keeps the result tool off a plain turn whose earlier chat quotes the result prompt", async () => { + stub.requests.length = 0; + let result = await run("rogue", { + instructions: `Durable conversation context follows:\nuser: ${ATOMIC_RESULT_INSTRUCTION}`, + }); + expect(result.text).toBe("Done."); + expect(result.resultToolParts).toBe(0); + expect(stub.requests[0]!.toolNames).not.toContain(ATOMIC_RESULT_TOOL_NAME); + }); +}); + +describe("atomic host isolation and model resolution", () => { + async function snapshot(root: string): Promise> { + let files = new Map(); + for (let entry of await readdir(root, { recursive: true })) { + let path = join(root, entry); + files.set(entry, (await stat(path)).mtimeMs); + } + return files; + } + + async function withHost( + body: (home: string) => Promise, + ): Promise<{ value: T; before: Map; after: Map }> { + let root = await mkdtemp(join(tmpdir(), "chopin-atomic-host-")); + let home = join(root, "home"); + let project = join(root, "project"); + let previous = { home: process.env.HOME, cwd: process.cwd() }; + try { + for (let base of [join(home, ".atomic", "agent"), join(home, ".pi", "agent"), project]) { + for (let name of ["extensions", "skills/marker", "prompts"]) { + await mkdir(join(base, name), { recursive: true }); + } + await writeFile(join(base, "AGENTS.md"), "HOST-AGENTS-MARKER"); + await writeFile(join(base, "CLAUDE.md"), "HOST-CLAUDE-MARKER"); + await writeFile(join(base, "SYSTEM.md"), "HOST-SYSTEM-MARKER"); + await writeFile(join(base, "APPEND_SYSTEM.md"), "HOST-APPEND-MARKER"); + await writeFile( + join(base, "extensions", "marker.ts"), + "export default (pi) => pi.on('before_agent_start', () => ({ systemPrompt: 'HOST-EXTENSION-MARKER' }));", + ); + await writeFile( + join(base, "skills", "marker", "SKILL.md"), + "---\nname: marker\ndescription: HOST-SKILL-MARKER\n---\nHOST-SKILL-MARKER", + ); + await writeFile(join(base, "prompts", "marker.md"), "HOST-PROMPT-MARKER"); + await writeFile( + join(base, "settings.json"), + JSON.stringify({ defaultTools: ["bash"], extensions: ["./extensions/marker.ts"] }), + ); + } + for (let dir of [".atomic", ".pi", ".agents"]) { + await mkdir(join(project, dir, "extensions"), { recursive: true }); + await writeFile( + join(project, dir, "extensions", "marker.ts"), + "export default (pi) => pi.on('before_agent_start', () => ({ systemPrompt: 'PROJECT-EXTENSION-MARKER' }));", + ); + } + await writeFile( + join(home, ".atomic", "agent", "auth.json"), + JSON.stringify({ stub: { type: "api_key", key: "host-login-key" } }), + ); + process.env.HOME = home; + process.chdir(project); + let before = await snapshot(root); + let value = await body(home); + return { value, before, after: await snapshot(root) }; + } finally { + process.chdir(previous.cwd); + if (previous.home === undefined) delete process.env.HOME; + else process.env.HOME = previous.home; + await rm(root, { recursive: true, force: true }); + } + } + + it("keeps host context files, skills, prompts, extensions, and settings out of the turn", async () => { + stub.requests.length = 0; + let { value, before, after } = await withHost(() => run("plain")); + expect(value.text).toBe("The Atomic stub model answered."); + expect(stub.requests).toHaveLength(1); + expect(stub.requests[0]!.system).toBe(ATOMIC_DEFAULT_SYSTEM_PROMPT); + expect(stub.requests[0]!.toolNames).toEqual([]); + expect(after).toEqual(before); + }); + + it("uses the host login in auto mode without writing credentials to disk", async () => { + stub.requests.length = 0; + let { value, before, after } = await withHost(async home => { + let harness = createAtomicAdapter({ + auth: "auto", + model: "stub/stub-model", + providers: { + stub: { baseUrl: stub.baseUrl, api: "openai-completions", models: [STUB_MODEL] }, + }, + }); + let text = (await run("plain", { harness })).text; + let auth = await readFile(join(home, ".atomic", "agent", "auth.json"), "utf8"); + return { text, auth }; + }); + expect(value.text).toBe("The Atomic stub model answered."); + expect(JSON.parse(value.auth)).toEqual({ stub: { type: "api_key", key: "host-login-key" } }); + expect(after).toEqual(before); + }); + + it("fails the turn when Atomic does not recognize the requested model", async () => { + stub.requests.length = 0; + await expect(run("plain", { model: "stub/not-a-model" })).rejects.toThrow( + "Atomic does not recognize model stub/not-a-model", + ); + await expect(run("plain", { model: "gpt-6-luna" })).rejects.toThrow( + "Atomic does not recognize model gpt-6-luna", + ); + expect(stub.requests).toHaveLength(0); + }); + + it("refuses non-gateway models under the ai-gateway auth mode", async () => { + stub.requests.length = 0; + await expect(run("plain", { model: "anthropic/claude-sonnet-4-5" })).rejects.toThrow( + "HARNESS_AUTH ai-gateway allows only vercel-ai-gateway models", + ); + expect(stub.requests).toHaveLength(0); + }); +}); diff --git a/apps/server/src/harness/atomic/adapter.test.ts b/apps/server/src/harness/atomic/adapter.test.ts new file mode 100644 index 00000000..0e4fd3a5 --- /dev/null +++ b/apps/server/src/harness/atomic/adapter.test.ts @@ -0,0 +1,165 @@ +import { expect, test } from "bun:test"; + +import { + ATOMIC_DEFAULT_SYSTEM_PROMPT, + ATOMIC_RESULT_INSTRUCTION, + ATOMIC_RESULT_TOOL_NAME, + atomicTurnExtension, + createAtomicAdapter, + hostLeak, + resolveModel, + turnSystemPrompt, +} from "./adapter"; + +import type { ExtensionAPI } from "@bastani/atomic"; +import type { AtomicAuthMode, TurnPolicy } from "./adapter"; + +type Handler = (event: Record) => unknown; + +function fakeExtensionApi(policy: TurnPolicy) { + let tools: { name: string; execute: (...args: unknown[]) => Promise }[] = []; + let handlers = new Map(); + let active: string[] = []; + let api = { + registerTool(tool: { name: string; execute: (...args: unknown[]) => Promise }) { + tools.push(tool); + }, + on(event: string, handler: Handler) { + handlers.set(event, handler); + }, + setActiveTools(names: string[]) { + active = [...names]; + }, + }; + atomicTurnExtension(policy)(api as unknown as ExtensionAPI); + return { + tools, + get active() { + return active; + }, + start: () => handlers.get("before_agent_start")!({ type: "before_agent_start" }), + call: (toolName: string) => handlers.get("tool_call")!({ type: "tool_call", toolName }), + }; +} + +test("registers one result tool that terminates the turn and records its arguments", async () => { + let policy: TurnPolicy = { hostNames: [], structured: true, systemPrompt: "System." }; + let atomic = fakeExtensionApi(policy); + expect(atomic.tools.map(tool => tool.name)).toEqual([ATOMIC_RESULT_TOOL_NAME]); + let result = await atomic.tools[0]!.execute("call-1", { answer: "yes" }); + expect(result).toMatchObject({ details: { answer: "yes" }, terminate: true }); + expect(policy.result).toEqual({ value: { answer: "yes" } }); +}); + +test("applies the turn's tools and exact system prompt when the agent starts", () => { + let policy: TurnPolicy = { hostNames: ["first_host"], structured: true, systemPrompt: "Plan." }; + let atomic = fakeExtensionApi(policy); + expect(atomic.start()).toEqual({ systemPrompt: "Plan." }); + expect(atomic.active).toEqual(["first_host", ATOMIC_RESULT_TOOL_NAME]); + + policy.structured = false; + policy.systemPrompt = `Plan.\n\nuser: ${ATOMIC_RESULT_INSTRUCTION}`; + expect(atomic.start()).toEqual({ systemPrompt: policy.systemPrompt }); + expect(atomic.active).toEqual(["first_host"]); +}); + +test("blocks the result tool off structured turns and anything outside the turn", () => { + let policy: TurnPolicy = { hostNames: ["first_host"], structured: false, systemPrompt: "S." }; + let atomic = fakeExtensionApi(policy); + expect(atomic.call(ATOMIC_RESULT_TOOL_NAME)).toMatchObject({ block: true }); + expect(atomic.call("bash")).toMatchObject({ block: true }); + expect(atomic.call("first_host")).toBeUndefined(); + policy.structured = true; + expect(atomic.call(ATOMIC_RESULT_TOOL_NAME)).toBeUndefined(); +}); + +test("builds the system prompt from instructions and the structured response format", () => { + expect(turnSystemPrompt(undefined, undefined)).toBe(ATOMIC_DEFAULT_SYSTEM_PROMPT); + expect(turnSystemPrompt("", { type: "text" })).toBe(ATOMIC_DEFAULT_SYSTEM_PROMPT); + expect(turnSystemPrompt("Summarize.", undefined)).toBe("Summarize."); + let schema = { type: "object", properties: { answer: { type: "string" } } }; + let prompt = turnSystemPrompt("Summarize.", { + type: "json", + schema, + description: "One answer.", + }); + expect(prompt).toStartWith("Summarize.\n\n"); + expect(prompt).toContain(ATOMIC_RESULT_INSTRUCTION); + expect(prompt).toContain("One answer."); + expect(prompt).toContain(JSON.stringify(schema)); + expect(turnSystemPrompt(undefined, { type: "json" })).toStartWith(ATOMIC_RESULT_INSTRUCTION); +}); + +test("resolves provider/model exactly and never substitutes a default", () => { + let known = new Map([ + ["stub/stub-model", { provider: "stub", id: "stub-model" }], + ["anthropic/claude", { provider: "anthropic", id: "claude" }], + ["vercel-ai-gateway/anthropic/claude", { + provider: "vercel-ai-gateway", + id: "anthropic/claude", + }], + ]); + let runtime = { + getModel: (provider: string, id: string) => known.get(`${provider}/${id}`) as never, + }; + let auto = { auth: "auto" as AtomicAuthMode }; + let gateway = { auth: "ai-gateway" as AtomicAuthMode, providers: { stub: {} as never } }; + + expect(resolveModel(runtime, auto, "anthropic/claude")).toMatchObject({ id: "claude" }); + expect(resolveModel(runtime, gateway, "vercel-ai-gateway/anthropic/claude")) + .toMatchObject({ id: "anthropic/claude" }); + expect(resolveModel(runtime, gateway, "stub/stub-model")).toMatchObject({ id: "stub-model" }); + expect(() => resolveModel(runtime, auto, undefined)).toThrow("needs a model"); + for (let name of ["gpt-6-luna", "/claude", "stub/other", "anthropic/"]) { + expect(() => resolveModel(runtime, auto, name)) + .toThrow(`Atomic does not recognize model ${name}`); + } + expect(() => resolveModel(runtime, gateway, "anthropic/claude")) + .toThrow("HARNESS_AUTH ai-gateway allows only vercel-ai-gateway models, not anthropic/claude"); +}); + +test("reports every way a built session exceeds the turn", () => { + function session(options: { + tools?: string[]; + agentsFiles?: number; + skills?: number; + prompts?: number; + append?: string[]; + systemPrompt?: string; + }) { + return { + getAllTools: () => + (options.tools ?? ["first_host", ATOMIC_RESULT_TOOL_NAME]).map(name => ({ name })), + resourceLoader: { + getAgentsFiles: () => ({ agentsFiles: Array(options.agentsFiles ?? 0) }), + getSkills: () => ({ skills: Array(options.skills ?? 0) }), + getPrompts: () => ({ prompts: Array(options.prompts ?? 0) }), + getAppendSystemPrompt: () => options.append ?? [], + getSystemPrompt: () => options.systemPrompt ?? ATOMIC_DEFAULT_SYSTEM_PROMPT, + }, + } as never; + } + expect(hostLeak(session({}), 1, ["first_host"])).toBeUndefined(); + expect(hostLeak(session({}), 6, ["first_host"])).toBe("6 extensions"); + expect(hostLeak(session({ tools: ["first_host", ATOMIC_RESULT_TOOL_NAME, "bash"] }), 1, [ + "first_host", + ])).toBe(`tools first_host, ${ATOMIC_RESULT_TOOL_NAME}, bash`); + expect(hostLeak( + session({ agentsFiles: 1, skills: 2, prompts: 1, append: ["x"], systemPrompt: "Host" }), + 1, + ["first_host"], + )).toBe( + "context files; skills; prompt templates; appended system prompts; a host system prompt", + ); +}); + +test("declares no built-ins and refuses an undefined auth mode", () => { + let harness = createAtomicAdapter({ auth: "ai-gateway" }); + expect(harness.harnessId).toBe("atomic"); + expect(harness.builtinTools).toEqual({}); + expect(harness.supportsBuiltinToolFiltering).toBe(true); + expect(() => createAtomicAdapter({ auth: "direct" as AtomicAuthMode })) + .toThrow("HARNESS_AUTH direct is not a supported atomic authentication mode"); + expect(() => createAtomicAdapter({ auth: undefined as unknown as AtomicAuthMode })) + .toThrow("is not a supported atomic authentication mode"); +}); diff --git a/apps/server/src/harness/atomic/adapter.ts b/apps/server/src/harness/atomic/adapter.ts new file mode 100644 index 00000000..9d37dc9b --- /dev/null +++ b/apps/server/src/harness/atomic/adapter.ts @@ -0,0 +1,618 @@ +/** + * Chopin's Atomic `HarnessV1` adapter. + * + * Embeds Atomic in-process through its headless SDK. Each harness session owns + * one Atomic `AgentSession` with every shipped builtin package off, no Atomic + * coding tools, an inert resource loader, and in-memory session, settings, and + * credential stores. The model is offered only the host tools `HarnessAgent` + * passes for the turn, plus a terminating result tool on structured turns. The + * tool set is checked before every prompt and before every model request, and a + * mismatch fails the turn. + */ + +import { HarnessCapabilityUnsupportedError } from "@ai-sdk/harness"; +import { + AuthStorage, + createAgentSession, + DefaultResourceLoader, + FileAuthStorageBackend, + getAgentConfigPaths, + ModelRuntime, + SessionManager, + SettingsManager, +} from "@bastani/atomic"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import type { + HarnessV1, + HarnessV1PromptControl, + HarnessV1PromptTurnOptions, + HarnessV1ResponseFormat, + HarnessV1ResumeSessionState, + HarnessV1Session, + HarnessV1StartOptions, + HarnessV1StreamPart, + HarnessV1ToolSpec, +} from "@ai-sdk/harness"; +import type { + AgentSession, + AgentSessionEvent, + ExtensionAPI, + ExtensionFactory, + ToolDefinition, +} from "@bastani/atomic"; + +export const ATOMIC_AUTH_MODES = ["auto", "ai-gateway"] as const; + +export type AtomicAuthMode = (typeof ATOMIC_AUTH_MODES)[number]; + +export const ATOMIC_RESULT_TOOL_NAME = "chopin_submit_atomic_result"; + +export const ATOMIC_RESULT_INSTRUCTION = + `When you have the final answer for this turn, call the ${ATOMIC_RESULT_TOOL_NAME} tool exactly ` + + "once with the required fields instead of replying in plain text."; + +/** Replaces Atomic's coding-agent preamble on turns that bring no instructions. */ +export const ATOMIC_DEFAULT_SYSTEM_PROMPT = + "Respond to the user's message. Use only the tools this turn provides."; + +const GATEWAY_PROVIDER = "vercel-ai-gateway"; +const OPERATION_TIMEOUT_MS = 10_000; +const BUILTINS_OFF = { + workflows: false, + subagents: false, + mcp: false, + "web-access": false, + intercom: false, +}; +const SETTINGS = { + compaction: { enabled: false }, + sessionSummary: { enabled: false }, + cacheWarming: "off" as const, +}; +const ZERO_USAGE = { + inputTokens: { + total: undefined, + noCache: undefined, + cacheRead: undefined, + cacheWrite: undefined, + }, + outputTokens: { total: undefined, text: undefined, reasoning: undefined }, +}; + +type ProviderConfig = Parameters[1]; +type Model = NonNullable>; +type ToolOutcome = { output: unknown; isError?: boolean }; + +export type AtomicSettings = { + auth: AtomicAuthMode; + /** Model, as `provider/model`, for turns that name none. */ + model?: string; + /** Providers registered by code rather than discovered from the host. */ + providers?: Record; +}; + +export class ToolBoundaryError extends Error { + constructor(message: string) { + super(message); + this.name = "ToolBoundaryError"; + } +} + +/** What the turn extension enforces; the adapter rewrites it before each turn. */ +export type TurnPolicy = { + hostNames: string[]; + structured: boolean; + systemPrompt: string; + result?: { value: unknown }; +}; + +/** + * Registers the terminating result tool and applies the per-turn policy: the + * active tools and the exact system prompt. `structured` comes only from the + * turn's response format, never from prompt text, so quoted chat cannot switch + * the result tool on. + */ +export function atomicTurnExtension(policy: TurnPolicy): ExtensionFactory { + return (atomic: ExtensionAPI): void => { + atomic.registerTool({ + name: ATOMIC_RESULT_TOOL_NAME, + label: "Submit result", + description: "Submit the final structured result for this turn.", + parameters: { type: "object", additionalProperties: true } as ToolDefinition["parameters"], + maxResultSizeChars: Infinity, + async execute(_toolCallId, params) { + policy.result = { value: params }; + return { + content: [{ type: "text", text: "Result received." }], + details: params, + terminate: true, + }; + }, + }); + atomic.on("before_agent_start", () => { + atomic.setActiveTools(activeNames(policy)); + return { systemPrompt: policy.systemPrompt }; + }); + atomic.on("tool_call", event => { + if (activeNames(policy).includes(event.toolName)) return; + return { block: true, reason: `${event.toolName} is not available in this turn.` }; + }); + }; +} + +function activeNames(policy: TurnPolicy): string[] { + return policy.structured ? [...policy.hostNames, ATOMIC_RESULT_TOOL_NAME] : [...policy.hostNames]; +} + +export function turnSystemPrompt( + instructions: string | undefined, + responseFormat: HarnessV1ResponseFormat | undefined, +): string { + let result = responseFormat?.type === "json" + ? [ + ATOMIC_RESULT_INSTRUCTION, + responseFormat.description, + `The ${ATOMIC_RESULT_TOOL_NAME} arguments must match this JSON schema: ${ + JSON.stringify(responseFormat.schema ?? { type: "object" }) + }`, + ].filter(Boolean).join("\n") + : undefined; + return [instructions, result].filter(Boolean).join("\n\n") || ATOMIC_DEFAULT_SYSTEM_PROMPT; +} + +/** Looks up `provider/model` without letting Atomic substitute a default. */ +export function resolveModel( + runtime: Pick, + settings: Pick, + requested: string | undefined, +): Model { + if (!requested) throw new Error("Atomic needs a model named as provider/model."); + let slash = requested.indexOf("/"); + let provider = requested.slice(0, slash); + let model = slash > 0 ? runtime.getModel(provider, requested.slice(slash + 1)) : undefined; + if (!model) throw new Error(`Atomic does not recognize model ${requested}`); + if ( + settings.auth === "ai-gateway" && provider !== GATEWAY_PROVIDER + && !Object.hasOwn(settings.providers ?? {}, provider) + ) { + throw new Error( + `HARNESS_AUTH ai-gateway allows only ${GATEWAY_PROVIDER} models, not ${requested}`, + ); + } + return model; +} + +/** + * Credentials live only in memory. `auto` copies the host's Atomic login once, + * read without a lock file, so a token refresh can never be written back. + */ +async function createRuntime(settings: AtomicSettings): Promise { + let login = {}; + if (settings.auth === "auto") { + let paths = getAgentConfigPaths("auth.json"); + let content = new FileAuthStorageBackend(paths[0], paths).read(); + if (content) login = JSON.parse(content); + } + let runtime = await ModelRuntime.create({ + credentials: AuthStorage.inMemory(login), + modelsPath: null, + allowModelNetwork: false, + }); + for (let [id, config] of Object.entries(settings.providers ?? {})) { + runtime.registerProvider(id, config); + } + return runtime; +} + +function unsupported(capability: string): HarnessCapabilityUnsupportedError { + return new HarnessCapabilityUnsupportedError({ + harnessId: "atomic", + message: `Atomic adapter does not support ${capability}.`, + }); +} + +function bounded(operation: Promise, message: string): Promise { + let timer: ReturnType | undefined; + return Promise.race([ + operation, + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error(message)), OPERATION_TIMEOUT_MS); + }), + ]).finally(() => clearTimeout(timer)); +} + +function promptText(prompt: HarnessV1PromptTurnOptions["prompt"]): string { + if (typeof prompt === "string") return prompt; + if (typeof prompt.content === "string") return prompt.content; + return prompt.content.map(part => { + if (part.type !== "text") throw unsupported(`${part.type} prompt parts`); + return part.text; + }).join("\n\n"); +} + +function sameNames(actual: readonly string[], expected: readonly string[]): boolean { + let left = [...actual].sort(); + let right = [...expected].sort(); + return left.length === right.length && left.every((name, index) => name === right[index]); +} + +/** What a freshly built session exposes beyond the turn extension and the host tools, if anything. */ +export function hostLeak( + session: Pick, + extensions: number, + hostNames: readonly string[], +): string | undefined { + let resources = session.resourceLoader; + let tools = session.getAllTools().map(tool => tool.name); + let found = [ + extensions !== 1 && `${extensions} extensions`, + !sameNames(tools, [...hostNames, ATOMIC_RESULT_TOOL_NAME]) && `tools ${tools.join(", ")}`, + resources.getAgentsFiles().agentsFiles.length > 0 && "context files", + resources.getSkills().skills.length > 0 && "skills", + resources.getPrompts().prompts.length > 0 && "prompt templates", + resources.getAppendSystemPrompt().length > 0 && "appended system prompts", + resources.getSystemPrompt() !== ATOMIC_DEFAULT_SYSTEM_PROMPT && "a host system prompt", + ].filter(Boolean); + return found.length > 0 ? found.join("; ") : undefined; +} + +function serialize(output: unknown): string { + return typeof output === "string" ? output : JSON.stringify(output ?? null); +} + +type Run = { + emit: (part: HarnessV1StreamPart) => void; + pending: Map void>; + blocks: Map; + stopped: boolean; + failure?: Error; + last?: { stopReason: string; errorMessage?: string }; + stop: () => void; + done: Promise; +}; + +function control(run: Run): HarnessV1PromptControl { + return { + async submitToolResult({ toolCallId, output, isError }) { + run.pending.get(toolCallId)?.({ output, isError }); + }, + async submitToolApproval() { + // The adapter emits no approval requests; there is nothing to answer. + }, + done: run.done, + }; +} + +function listen(run: Run, signal: AbortSignal | undefined): void { + if (!signal) return; + if (signal.aborted) run.stop(); + else signal.addEventListener("abort", run.stop, { once: true }); + void run.done.catch(() => {}).finally(() => signal.removeEventListener("abort", run.stop)); +} + +/** Host-process `HarnessV1` implementation over `@bastani/atomic`. */ +export function createAtomicAdapter( + settings: AtomicSettings, +): HarnessV1 & { shutdown(): Promise } { + if (!ATOMIC_AUTH_MODES.includes(settings.auth)) { + throw new Error(`HARNESS_AUTH ${settings.auth} is not a supported atomic authentication mode`); + } + let runtime: Promise | undefined; + let open = new Set(); + + return { + specificationVersion: "harness-v1", + harnessId: "atomic", + builtinTools: {}, + supportsBuiltinToolFiltering: true, + + async doStart(startOptions: HarnessV1StartOptions): Promise { + if (startOptions.resumeFrom || startOptions.continueFrom) { + throw unsupported("resuming an in-memory session"); + } + let directory: string | undefined; + let sessionManager: SessionManager | undefined; + let settingsManager = SettingsManager.inMemory(SETTINGS); + let policy: TurnPolicy = { + hostNames: [], + structured: false, + systemPrompt: ATOMIC_DEFAULT_SYSTEM_PROMPT, + }; + let live: { session: AgentSession; signature: string; release: () => void } | undefined; + let current: Run | undefined; + let closed: Promise | undefined; + + function hostTool(spec: HarnessV1ToolSpec): ToolDefinition { + return { + name: spec.name, + label: spec.name, + description: spec.description ?? "", + parameters: (spec.inputSchema ?? { type: "object" }) as ToolDefinition["parameters"], + maxResultSizeChars: Infinity, + async execute(toolCallId, params, signal) { + let run = current; + if (!run || run.stopped || signal?.aborted) throw new Error("The turn was aborted."); + let settled = Promise.withResolvers(); + let abort = () => settled.resolve({ output: "The turn was aborted.", isError: true }); + run.pending.set(toolCallId, settled.resolve); + signal?.addEventListener("abort", abort, { once: true }); + run.emit({ + type: "tool-call", + toolCallId, + toolName: spec.name, + input: JSON.stringify(params ?? {}), + }); + let outcome = await settled.promise; + signal?.removeEventListener("abort", abort); + run.pending.delete(toolCallId); + if (run.stopped || signal?.aborted) throw new Error("The turn was aborted."); + run.emit({ + type: "tool-result", + toolCallId, + toolName: spec.name, + result: (outcome.output ?? null) as NonNullable, + isError: outcome.isError, + }); + if (outcome.isError) throw new Error(serialize(outcome.output)); + return { content: [{ type: "text", text: serialize(outcome.output) }], details: {} }; + }, + }; + } + + function observe(session: AgentSession, event: AgentSessionEvent): void { + let run = current; + if (!run) return; + if (event.type === "turn_start") { + let offered = session.agent.state.tools.map(tool => tool.name); + if (!sameNames(offered, activeNames(policy))) { + run.failure ??= new ToolBoundaryError( + `Atomic offered unexpected tools: ${offered.join(", ") || "none"}.`, + ); + run.stop(); + } + if (run.stopped) session.agent.abort(); + return; + } + if (!("message" in event) || event.message.role !== "assistant") return; + if (event.type === "message_start") { + run.blocks.clear(); + } else if (event.type === "message_end") { + for (let block of run.blocks.values()) { + run.emit({ type: `${block.kind}-end`, id: block.id }); + } + run.blocks.clear(); + run.last = event.message; + } else if (event.type === "message_update" && !policy.structured) { + let update = event.assistantMessageEvent; + let kind = update.type.startsWith("text_") + ? "text" as const + : update.type.startsWith("thinking_") + ? "reasoning" as const + : undefined; + if (!kind || !("contentIndex" in update)) return; + let block = run.blocks.get(update.contentIndex); + if (!block) { + block = { id: crypto.randomUUID(), kind }; + run.blocks.set(update.contentIndex, block); + run.emit({ type: `${kind}-start`, id: block.id }); + } + if (update.type === "text_delta" || update.type === "thinking_delta") { + run.emit({ type: `${kind}-delta`, id: block.id, delta: update.delta }); + } else if (update.type === "text_end" || update.type === "thinking_end") { + run.emit({ type: `${kind}-end`, id: block.id }); + run.blocks.delete(update.contentIndex); + } + } + } + + async function prepare(turn: HarnessV1PromptTurnOptions): Promise { + if (turn.skills.length > 0) throw unsupported("skills"); + let hostNames = turn.tools.map(spec => spec.name); + if (hostNames.includes(ATOMIC_RESULT_TOOL_NAME)) { + throw new Error( + `Host tool name ${ATOMIC_RESULT_TOOL_NAME} is reserved for structured output.`, + ); + } + let models = await (runtime ??= createRuntime(settings)); + let model = resolveModel(models, settings, turn.model ?? settings.model); + let signature = JSON.stringify(turn.tools); + if (live && live.signature !== signature) { + live.release(); + await live.session.dispose(); + live = undefined; + } + policy.hostNames = hostNames; + policy.structured = false; + if (!live) { + directory ??= await mkdtemp(join(tmpdir(), "chopin-atomic-planner-")); + sessionManager ??= SessionManager.inMemory(directory); + let loader = new DefaultResourceLoader({ + cwd: directory, + agentDir: directory, + settingsManager, + noExtensions: true, + noSkills: true, + noPromptTemplates: true, + noThemes: true, + noContextFiles: true, + systemPrompt: ATOMIC_DEFAULT_SYSTEM_PROMPT, + appendSystemPrompt: [], + extensionFactories: [atomicTurnExtension(policy)], + }); + await loader.reload(); + let created = await createAgentSession({ + cwd: directory, + agentDir: directory, + modelRuntime: models, + model, + fallbackModels: [], + sessionManager, + settingsManager, + resourceLoader: loader, + builtins: BUILTINS_OFF, + tools: [...hostNames, ATOMIC_RESULT_TOOL_NAME], + customTools: turn.tools.map(hostTool), + }); + let session = created.session; + let leak = hostLeak(session, created.extensionsResult.extensions.length, hostNames); + if (leak || closed) { + await session.dispose(); + throw leak + ? new ToolBoundaryError(`Atomic session is not isolated: ${leak}.`) + : new Error("Atomic session is closed."); + } + let registered = session.getAllTools().map(tool => tool.name); + console.log(`[agent] ${registered.length} tools: ${registered.sort().join(", ")}`); + live = { + session, + signature, + release: session.subscribe(event => observe(session, event)), + }; + } else if ( + live.session.model?.provider !== model.provider || live.session.model.id !== model.id + ) { + await live.session.setModel(model); + } + return live.session; + } + + async function close(): Promise { + open.delete(handle); + let run = current; + if (run) { + run.stop(); + await bounded(run.done, "Atomic turn did not stop.").catch(() => {}); + } + try { + if (live) { + live.release(); + await bounded(live.session.dispose(), "Atomic session disposal timed out."); + } + } finally { + live = undefined; + if (directory) await rm(directory, { recursive: true, force: true }); + } + } + + async function stopped(): Promise { + await (closed ??= close()); + return { + type: "resume-session", + harnessId: "atomic", + specificationVersion: "harness-v1", + data: {}, + }; + } + + let handle: HarnessV1Session = { + sessionId: startOptions.sessionId, + isResume: false, + + async doPromptTurn(turn: HarnessV1PromptTurnOptions): Promise { + if (closed) throw new Error("Atomic session is closed."); + if (current) throw new Error("Atomic session already has an active turn."); + let text = promptText(turn.prompt); + let agent = await prepare(turn); + let structured = turn.responseFormat?.type === "json"; + let expected = structured + ? [...policy.hostNames, ATOMIC_RESULT_TOOL_NAME] + : policy.hostNames; + agent.setActiveToolsByName(expected); + if (!sameNames(agent.getActiveToolNames(), expected)) { + throw new ToolBoundaryError( + `Atomic active tools do not match the turn: ${ + agent.getActiveToolNames().join(", ") + }.`, + ); + } + policy.structured = structured; + policy.systemPrompt = turnSystemPrompt(turn.instructions, turn.responseFormat); + policy.result = undefined; + + let run: Run = { + emit: turn.emit, + pending: new Map(), + blocks: new Map(), + stopped: false, + stop: () => { + if (run.stopped) return; + run.stopped = true; + for (let resolve of run.pending.values()) { + resolve({ output: "The turn was aborted.", isError: true }); + } + run.pending.clear(); + void bounded(agent.abort(), "Atomic abort timed out.").catch(() => {}); + }, + done: Promise.resolve(), + }; + current = run; + run.done = (async () => { + try { + if (!run.stopped) { + run.emit({ type: "stream-start", modelId: agent.model?.id }); + await agent.prompt(text, { expandPromptTemplates: false }); + } + if (run.failure) throw run.failure; + if (run.stopped) return; + if (run.last?.stopReason === "error" || run.last?.stopReason === "aborted") { + throw new Error(run.last.errorMessage ?? "Atomic turn failed."); + } + if (structured) { + if (!policy.result) { + throw new Error("Atomic turn ended without a structured result."); + } + let id = crypto.randomUUID(); + run.emit({ type: "text-start", id }); + run.emit({ type: "text-delta", id, delta: JSON.stringify(policy.result.value) }); + run.emit({ type: "text-end", id }); + } + run.emit({ + type: "finish-step", + finishReason: { unified: "stop", raw: undefined }, + usage: ZERO_USAGE, + }); + run.emit({ + type: "finish", + finishReason: { unified: "stop", raw: undefined }, + totalUsage: ZERO_USAGE, + }); + } finally { + if (current === run) current = undefined; + } + })(); + listen(run, turn.abortSignal); + return control(run); + }, + + async doContinueTurn(turn): Promise { + let run = current; + if (!run) throw unsupported("continuing a turn that is no longer running"); + run.emit = turn.emit; + listen(run, turn.abortSignal); + return control(run); + }, + + async doCompact() { + throw unsupported("compaction"); + }, + async doSuspendTurn() { + throw unsupported("suspending a turn"); + }, + doDetach: stopped, + doStop: stopped, + async doDestroy() { + await (closed ??= close()); + }, + }; + open.add(handle); + return handle; + }, + + async shutdown() { + await Promise.allSettled([...open].map(session => session.doDestroy())); + }, + }; +} diff --git a/apps/server/src/harness/harnesses.test.ts b/apps/server/src/harness/harnesses.test.ts index fc7a62b5..95360422 100644 --- a/apps/server/src/harness/harnesses.test.ts +++ b/apps/server/src/harness/harnesses.test.ts @@ -4,8 +4,8 @@ import { harnesses, harnessFor, registerCredential, shutdownHarnesses } from "./ afterEach(shutdownHarnesses); -it("selects the tested Copilot SDK and Pi harnesses", () => { - expect(Object.keys(harnesses)).toEqual(["copilot-sdk", "pi"]); +it("selects the tested Copilot SDK, Pi, and Atomic harnesses", () => { + expect(Object.keys(harnesses)).toEqual(["copilot-sdk", "pi", "atomic"]); expect(harnessFor({ harness: "copilot-sdk" }).harnessId).toBe("copilot-sdk"); expect(() => harnessFor({ harness: "not-installed" })).toThrow("Unknown harness: not-installed"); }); @@ -46,6 +46,26 @@ it("refuses every Pi auth mode but ai-gateway on a non-loopback bind", () => { .toBe("pi"); }); +it("requires an explicit, Atomic-supported auth mode and refuses direct or unknown modes", () => { + expect(() => harnessFor({ harness: "atomic", host: "127.0.0.1" })) + .toThrow("HARNESS_AUTH is required for harness atomic"); + for (let harnessAuth of ["direct", "openai", "custom", "bogus"]) { + expect(() => harnessFor({ harness: "atomic", harnessAuth, host: "127.0.0.1" })) + .toThrow(`HARNESS_AUTH ${harnessAuth} is not a supported atomic authentication mode`); + } + expect(harnessFor({ harness: "atomic", harnessAuth: "auto", host: "::1" }).harnessId) + .toBe("atomic"); +}); + +it("refuses Atomic's host-login auto mode on a non-loopback bind but accepts ai-gateway", () => { + for (let host of ["0.0.0.0", "::", "192.168.1.2", "localhost.example"]) { + expect(() => harnessFor({ harness: "atomic", harnessAuth: "auto", host })) + .toThrow("HARNESS_AUTH for atomic on a non-loopback SERVER_HOST must be ai-gateway"); + } + expect(harnessFor({ harness: "atomic", harnessAuth: "ai-gateway", host: "0.0.0.0" }).harnessId) + .toBe("atomic"); +}); + it("registers credentials per session without reuse or rewriting", () => { let token = "session-token"; let release = registerCredential("session-id", () => token); diff --git a/apps/server/src/harness/harnesses.ts b/apps/server/src/harness/harnesses.ts index bf47951b..408d6f64 100644 --- a/apps/server/src/harness/harnesses.ts +++ b/apps/server/src/harness/harnesses.ts @@ -1,7 +1,9 @@ +import { ATOMIC_AUTH_MODES, createAtomicAdapter } from "./atomic/adapter"; import { createCopilotSdk } from "./copilot-sdk/adapter"; import { createPiAdapter } from "./pi/adapter"; import type { HarnessV1 } from "@ai-sdk/harness"; +import type { AtomicAuthMode } from "./atomic/adapter"; const credentials = new Map string | undefined; @@ -14,9 +16,17 @@ function createPiHarness(settings: { auth?: string }): HarnessV1 & { shutdown(): return createPiAdapter({ auth: settings.auth as never }); } +function createAtomicHarness( + settings: { auth?: string }, +): HarnessV1 & { shutdown(): Promise } { + // Like Pi, Atomic takes neither a GitHub credential nor a credit limit. + return createAtomicAdapter({ auth: settings.auth as AtomicAuthMode }); +} + export const harnesses = { "copilot-sdk": createCopilotSdk, pi: createPiHarness, + atomic: createAtomicHarness, } satisfies Record< string, (settings: { @@ -41,6 +51,13 @@ function loopback(host: string): boolean { * Pi was never told to isolate. */ const PI_AUTH_MODES = new Set(["auto", "openai", "anthropic", "custom", "ai-gateway"]); +/** Harnesses whose auth modes are validated explicitly; only `ai-gateway` + * avoids a host login and may serve a non-loopback bind. */ +const AUTH_MODES = new Map>([ + ["pi", PI_AUTH_MODES], + ["atomic", new Set(ATOMIC_AUTH_MODES)], +]); + export function harnessFor(config: { harness: string; harnessAuth?: string; @@ -51,15 +68,20 @@ export function harnessFor(config: { } let auth = config.harnessAuth; let isLoopback = loopback(config.host ?? "127.0.0.1"); - if (config.harness === "pi") { + let modes = AUTH_MODES.get(config.harness); + if (modes) { if (!auth) { - throw new Error("HARNESS_AUTH is required for harness pi"); + throw new Error(`HARNESS_AUTH is required for harness ${config.harness}`); } - if (!PI_AUTH_MODES.has(auth)) { - throw new Error(`HARNESS_AUTH ${auth} is not a supported pi authentication mode`); + if (!modes.has(auth)) { + throw new Error( + `HARNESS_AUTH ${auth} is not a supported ${config.harness} authentication mode`, + ); } if (!isLoopback && auth !== "ai-gateway") { - throw new Error("HARNESS_AUTH for pi on a non-loopback SERVER_HOST must be ai-gateway"); + throw new Error( + `HARNESS_AUTH for ${config.harness} on a non-loopback SERVER_HOST must be ai-gateway`, + ); } } else if (auth && auth !== "direct" && auth !== "ai-gateway" && !isLoopback) { throw new Error("HARNESS_AUTH requires a loopback SERVER_HOST"); diff --git a/apps/server/src/storage/postgres/startup.test.ts b/apps/server/src/storage/postgres/startup.test.ts index 4e3d9493..6a9e991c 100644 --- a/apps/server/src/storage/postgres/startup.test.ts +++ b/apps/server/src/storage/postgres/startup.test.ts @@ -121,7 +121,7 @@ if (database) { replacement.kill("SIGTERM"); expect(await replacement.exited).toBe(0); await storage.close(); - }); + }, 20_000); }); } else { describe("postgres server lifecycle", () => { diff --git a/bun.lock b/bun.lock index 669bf6c7..ccdb8191 100644 --- a/bun.lock +++ b/bun.lock @@ -27,6 +27,7 @@ "@ai-sdk/harness-pi": "catalog:harness", "@ai-sdk/mcp": "catalog:harness", "@ai-sdk/sandbox-just-bash": "catalog:harness", + "@bastani/atomic": "catalog:harness", "@chopin/dialect": "workspace:*", "@chopin/protocol": "workspace:*", "@chopin/question": "workspace:*", @@ -229,6 +230,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", + "@bastani/atomic": "0.9.23", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7", @@ -380,6 +382,28 @@ "@base-ui/utils": ["@base-ui/utils@0.3.2", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.12", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ=="], + "@bastani/atomic": ["@bastani/atomic@0.9.23", "", { "dependencies": { "@bastani/atomic-natives": "0.9.23", "@bastani/pi-ai": "0.9.23", "@dbos-inc/dbos-sdk": "4.25.14", "@earendil-works/pi-agent-core": "0.87.1", "@earendil-works/pi-client": "0.87.1", "@earendil-works/pi-protocol": "0.87.1", "@earendil-works/pi-tui": "0.87.1", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.6.0", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "embedded-postgres": "18.4.0-beta.17", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "pg": "8.22.0", "proper-lockfile": "4.1.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-h859zFfHSrxDZMalN0+6mkIcR0dXm99koTTkX7zYjj0Sdkl0uHyQZKsh7Eqqn7BIIJRxVqqRaejOhKjxqlaSlQ=="], + + "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.23", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.23", "@bastani/atomic-natives-darwin-x64": "0.9.23", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.23", "@bastani/atomic-natives-linux-arm64-musl": "0.9.23", "@bastani/atomic-natives-linux-x64-gnu": "0.9.23", "@bastani/atomic-natives-linux-x64-musl": "0.9.23", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.23", "@bastani/atomic-natives-win32-x64-msvc": "0.9.23" } }, "sha512-zd4w/nEIc0hDlZWkmCCncG7/befEHtXo4uxIXNVNlKzTzdAgdUdq6VcMutvVsXK8v2kMGvHNdLkQO6hF/l050Q=="], + + "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v0PjvsXlWEn4nTaVjJ/TvMHg0hRJlNPkQ6ET+kcVP/m8IHLfzqa0w9pFKVV6Ez0lymQwQbFr2OUbe4zEBf7jvw=="], + + "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-lOK1Eq0WQSj/PKesTayqdr1e/aOfE/vth81yvUfdt2AyI4QyrTJuVV4q72jBWEVhkLhhy4ql/6rDwEYGby5QVA=="], + + "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-fZ6qz1FvALylPrQCtuMEn0jH1PRLywpvdSPXEqMqFRFx7ST1DFjatSUBHNb3pv0nj52jDDTVOLZUCmjECSv2MQ=="], + + "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-cxAraZvtxuzi+qB8stflP/v5F0zOo7kFcbrYbzPRHS+uL6Uc+gAVeLJYsrTaWuTH+aN6HVpwXn+Q+4F8KU6l1Q=="], + + "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.23", "", { "os": "linux", "cpu": "x64" }, "sha512-7gwkDf4PCVEi2pRPIouxcFSdNnwACd5U1lvNle8/V2utcGRz/NlKnqxG+Ic8jYUafyzPgpS9xshUQoDIVo1KSw=="], + + "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.23", "", { "os": "linux", "cpu": "x64" }, "sha512-/KUQPXbVKJ1/jWQ9BjN0LqZE8j4rsIIZKHwy6LEpJ83eoHOwjJsHf9o2LPTRl3cEHHPECxME21ySJ/TTl1PIuw=="], + + "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ha0u9yelInx7F/5HKXArjLRWbKCqJDvx+Zl30JSTZoikL4GNKmZbVzrD20ZKT9N7XMZezbAb3SzElmeFElU82Q=="], + + "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.23", "", { "os": "win32", "cpu": "x64" }, "sha512-YMsQXBj5KHTK+dDwuTTzoQyi1kmKGEBlP8HMZeQ746CJZuoC8ekw2yzM5xogwudPEJw6KBtbqmO9lw0B7y0VXA=="], + + "@bastani/pi-ai": ["@bastani/pi-ai@0.9.23", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-Z7s6dEeuQRj08avCqltxTcf+LRTYek1TZ3/tbSJxH8WELH/yNOzkIzcuSpcYzOZ7hrWFzwAB1AaKDITSgUSwpA=="], + "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], @@ -474,6 +498,8 @@ "@codemirror/view": ["@codemirror/view@6.43.6", "", { "dependencies": { "@codemirror/state": "^6.7.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA=="], + "@dbos-inc/dbos-sdk": ["@dbos-inc/dbos-sdk@4.25.14", "", { "dependencies": { "commander": "^12.0.0", "pg": "^8.11.3", "serialize-error": "^8.1.0", "superjson": "^1.13.3", "ws": "^8.18.1", "yaml": "^2.8.3" }, "bin": { "dbos": "dist/src/cli/cli.js", "dbos-sdk": "dist/src/cli/cli.js" } }, "sha512-vBGuqlZQExzCiBpr6mW04BckqWi3n3+VLAv5p/odVfY3DGqDxxEscDXGDiUiFXYlaORkZa70GTnmzx8RVWxpzQ=="], + "@dprint/darwin-arm64": ["@dprint/darwin-arm64@0.50.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4d08INZlTxbPW9LK9W8+93viN543/qA2Kxn4azVnPW/xCb2Im03UqJBz8mMm3nJZdtNnK3uTVG3ib1VW+XJisw=="], "@dprint/darwin-x64": ["@dprint/darwin-x64@0.50.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZXWPBwdLojhdBATq+bKwJvB7D8bIzrD6eR/Xuq9UYE7evQazUiR069d9NPF0iVuzTo6wNf9ub9SXI7qDl11EGA=="], @@ -494,15 +520,35 @@ "@earendil-works/chord": ["@earendil-works/chord@0.85.1", "", { "dependencies": { "esbuild": "0.28.1" } }, "sha512-VDlkEC3dhCzQ5fcyH1OhG19dq+6jCn+rqc/iXFivwDYGR5anwo2RCiXij9PpHhqNR5GuhhE+Er69Zi1Sn4eY6w=="], - "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.85.1", "", { "dependencies": { "@earendil-works/chord": "^0.85.1", "@earendil-works/pi-ai": "^0.85.1", "@earendil-works/pi-telemetry": "^0.85.1", "diff": "8.0.4", "ignore": "7.0.5", "typebox": "1.3.7", "yaml": "2.9.0" } }, "sha512-hIXIP3eAWueAYiAl8aMvWCvvZ8Q5gT3Dip5bE5uJyIGh4+YlWRjtMLI4BaeoXoSs93zndjue61u1B/vhefLnuA=="], + "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "@earendil-works/pi-ai": "^0.87.1", "@earendil-works/pi-telemetry": "^0.87.1", "diff": "8.0.4", "ignore": "7.0.8", "typebox": "1.3.27", "yaml": "2.9.0" } }, "sha512-Zev3B0HK7YS5A4EZQ2XnEqiJuirx6QBiltJ+LpmjV5a/+2IU0cfKtIfnkNkORK707XOvKBY2WRtk7cAwHpbh2Q=="], "@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.74.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.91.1", "@aws-sdk/client-bedrock-runtime": "^3.1030.0", "@google/genai": "^1.40.0", "@mistralai/mistralai": "^2.2.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "openai": "6.26.0", "partial-json": "^0.1.7", "typebox": "^1.1.24" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-ukQBHGDm20k9ZUS2cGjNN9vDJp/48r35xmvgSx3paCaC06r2N/PLuRZoJmwQ1ZM7f8T3072odv9YPWn+77w0LA=="], + "@earendil-works/pi-client": ["@earendil-works/pi-client@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "@earendil-works/pi-protocol": "^0.87.1" } }, "sha512-x8dfZ7ppAao9SDnZvD5/DErVdq2fI7hg4lFj7qEhtgo6wimrRafGSLsqLklFVjb6kxU2W3j9F4RZz0rRcb0cwA=="], + "@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.85.1", "", { "dependencies": { "@earendil-works/chord": "^0.85.1", "@earendil-works/pi-agent-core": "^0.85.1", "@earendil-works/pi-ai": "^0.85.1", "@earendil-works/pi-tui": "^0.85.1", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "grok-mermaid": "0.2.2", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", "undici": "8.9.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "pi": "dist/bundle/cli.js" } }, "sha512-FGRN+OHbWaefBPGaTggAdLjrIHW+s2PzLyglz/5dfLzb9of7uuXMXYC0fJIeZTw+shS32o2cuQ9jF7YSDuL/oQ=="], - "@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.85.1", "", {}, "sha512-Bg/YN6kA7Swja/NQxka8xFdecb4E/auIEGF2G5A25EaQXhRnPj300/7/KpgsDDMYUzHTDAv4RyUxaQPJKW81Rw=="], + "@earendil-works/pi-protocol": ["@earendil-works/pi-protocol@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "typebox": "1.3.27" } }, "sha512-48WVjryAIiKOJXnKgO15h2MT/oeH5uf0S4DykcVj3ZrxMTDSGxcUaS5VtvHtFQ1rZSSIjkVcblE13k0GksBuoQ=="], + + "@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.87.1", "", {}, "sha512-MC6TRQH5lgMXpcN+Vku2WMI2T8BsiUPzMQHGo81uqFZD3/9O79WWJAysEDGuzduP6R4tvtgwMLwmqIxynM10JQ=="], + + "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.87.1", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.11" } }, "sha512-YEH2vRyOeiO7hhN6j6AE6YwKSq2Kz2f3XR8bj1TbR+aGE/JsnY1hLPMI2pvaZfRM1n9Y00tejxFQ4zbzvF7nkQ=="], + + "@embedded-postgres/darwin-arm64": ["@embedded-postgres/darwin-arm64@18.4.0-beta.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Kg1ZMNFzkVIJs3g4V2UYEc5X005km9rGinxFBH8R1sOU2Rblvz4pt2Uf93Pu8Rk273Ue9HIdrbMPpgUqwjUi0Q=="], - "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.85.1", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.5" } }, "sha512-OIzw9efInmO4WOBnD4TxcTdBjmzvYJpzslkgoUro946nEGoYWg5rwv1p4fDt3/JvMx9QybryUCUwlm7j8Dreig=="], + "@embedded-postgres/darwin-x64": ["@embedded-postgres/darwin-x64@18.4.0-beta.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-4tShSYWMxUQTSWoQAdLnHISvRj6L9gTch9/31ASJPg6wgyN64LDRwMcOINEWybM7N0ropJ3nTYhFT3UX1bKY5Q=="], + + "@embedded-postgres/linux-arm": ["@embedded-postgres/linux-arm@18.4.0-beta.17", "", { "os": "linux", "cpu": "arm" }, "sha512-VuD1nFasN7yG57zpJcp6MBXM0nXqGfb8GBQV+f1FGJ17+VMNYLIFLhFp99UlY4xnWG74FQC4NPYw8eCwSTJ6qg=="], + + "@embedded-postgres/linux-arm64": ["@embedded-postgres/linux-arm64@18.4.0-beta.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-TIzjtGnDGSD/LbdW0OWCEcbI+YVT0WKSfSr20TCkkP4UR8zeKe+QCZbO0/CM4hS9EWyZ4cDebjRvpRc3iMi6wg=="], + + "@embedded-postgres/linux-ia32": ["@embedded-postgres/linux-ia32@18.4.0-beta.17", "", { "os": "linux", "cpu": "ia32" }, "sha512-aSRe4kknqRHuedtpo/rDIaqa8r9VrKIgW9p5FkJyIFqUUkIkxRqND1dg8xrDRREcSUXRJKS0x+j/AuxflgYIfg=="], + + "@embedded-postgres/linux-ppc64": ["@embedded-postgres/linux-ppc64@18.4.0-beta.17", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zO2RRUFdKRPplrdhmglG39VXJZzDXu3P3ONAG1sFPhGh89vbk24Btd5P7uOmQLIpWehzL0s+UqUWoeE/ZUKvgw=="], + + "@embedded-postgres/linux-x64": ["@embedded-postgres/linux-x64@18.4.0-beta.17", "", { "os": "linux", "cpu": "x64" }, "sha512-jVw/MdDtIX/vICH/DKIe6/mHpiCggdx6QVyza4vt/NbcZFsL0KhwglF6F1Koqx3gRBZ9XtN+vi63EsqSyqOSxA=="], + + "@embedded-postgres/windows-x64": ["@embedded-postgres/windows-x64@18.4.0-beta.17", "", { "os": "win32", "cpu": "x64" }, "sha512-AwRerliA4IGWyW5jWBvHt5vidVUSB0QQW9Tt2y7ScnmifnCb/awfxZr4BkBSTv+gNt8Djcddqs+xSF5Z6/CkTg=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], @@ -794,10 +840,12 @@ "@modelcontextprotocol/ext-apps": ["@modelcontextprotocol/ext-apps@1.7.5", "", { "dependencies": { "@standard-schema/spec": "^1.1.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.29.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-TjPH2S2y5UEGKhmI6+XGFuqfqOV4ppe1x6DA3txnUaEWkgtA4G5vo14jGKFZmegdkZ1H4QMLyujLvoU1BEdnAg=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.30.1", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.30.0", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA=="], "@mongodb-js/zstd": ["@mongodb-js/zstd@7.0.0", "", { "dependencies": { "node-addon-api": "^8.5.0", "prebuild-install": "^7.1.3" } }, "sha512-mQ2s0pYYiav+tzCDR05Zptem8Ey2v8s11lri5RKGhTtL4COVCvVCk5vtyRYNT+9L8qSfyOqqefF9UtnW8mC5jA=="], + "@mozilla/readability": ["@mozilla/readability@0.6.0", "", {}, "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ=="], + "@nodable/entities": ["@nodable/entities@3.0.0", "", {}, "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw=="], "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], @@ -1024,7 +1072,7 @@ "@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], "@smithy/signature-v4": ["@smithy/signature-v4@5.7.4", "", { "dependencies": { "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ=="], @@ -1176,6 +1224,8 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + "@typesafe-ai/sdk": ["@typesafe-ai/sdk@0.6.0", "", {}, "sha512-IddX+Q0XM+VagOUZFeP7wZjaO4SHMdvnh2zEBdrZZnXedWI3BNK1lKhMx3ayrkFWvVLbVcUHJy6AVZlY+e6Jaw=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260304.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260304.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260304.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260304.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260304.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260304.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260304.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260304.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-Xj0ZeHEy+yJ/bIg6psPwl0POvBf1j5u7IZAXsUqgvgWbMIvdM9JOGmhpifcj6j28LcXM6GTvXUoXwlatxJ73Qg=="], "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260304.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TnTUxYt+dShRSoeOldx7VlKoEG+bvPHnyPEBImlNc7c3WP0AHYyNHrNg6EbLbzkOorARtd06J3Vk+XYzkrRzZg=="], @@ -1200,6 +1250,8 @@ "@workflow/serde": ["@workflow/serde@4.1.0", "", {}, "sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ=="], + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.15", "", {}, "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="], @@ -1222,6 +1274,8 @@ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + "axe-core": ["axe-core@4.13.0", "", {}, "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], @@ -1238,6 +1292,8 @@ "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], + "boolbase": ["boolbase@2.0.0", "", {}, "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA=="], + "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], "brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], @@ -1264,7 +1320,7 @@ "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "chalk": ["chalk@6.0.0", "", {}, "sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -1302,6 +1358,10 @@ "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + "copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], @@ -1312,8 +1372,14 @@ "css-in-js-utils": ["css-in-js-utils@3.1.0", "", { "dependencies": { "hyphenate-style-name": "^1.0.3" } }, "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A=="], + "css-select": ["css-select@7.0.0", "", { "dependencies": { "boolbase": "^2.0.0", "css-what": "^8.0.0", "domhandler": "^6.0.1", "domutils": "^4.0.2", "nth-check": "^3.0.1" } }, "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g=="], + "css-tree": ["css-tree@1.1.3", "", { "dependencies": { "mdn-data": "2.0.14", "source-map": "^0.6.1" } }, "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q=="], + "css-what": ["css-what@8.0.0", "", {}, "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw=="], + + "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "cytoscape": ["cytoscape@3.34.0", "", {}, "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg=="], @@ -1420,12 +1486,24 @@ "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], + "dingbat-to-unicode": ["dingbat-to-unicode@1.0.2", "", {}, "sha512-R0bRerYzy/EZP6QzD3Hkl6JjUDA1Mnn+pd928w0nWjPzihnbAR6dcjGJGiRyznj5E4S1duEKzWrTqw02DPcdzg=="], + + "dom-serializer": ["dom-serializer@3.1.1", "", { "dependencies": { "domelementtype": "^3.0.0", "domhandler": "^6.0.0", "entities": "^8.0.0" } }, "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@6.0.1", "", { "dependencies": { "domelementtype": "^3.0.0" } }, "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg=="], + "dompurify": ["dompurify@3.4.12", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg=="], + "domutils": ["domutils@4.0.2", "", { "dependencies": { "dom-serializer": "^3.0.0", "domelementtype": "^3.0.0", "domhandler": "^6.0.0" } }, "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA=="], + "downshift": ["downshift@7.6.2", "", { "dependencies": { "@babel/runtime": "^7.14.8", "compute-scroll-into-view": "^2.0.4", "prop-types": "^15.7.2", "react-is": "^17.0.2", "tslib": "^2.3.0" }, "peerDependencies": { "react": ">=16.12.0" } }, "sha512-iOv+E1Hyt3JDdL9yYcOgW7nZ7GQ2Uz6YbggwXvKUSleetYhU2nXD482Rz6CzvM4lvI1At34BYruKAL4swRGxaA=="], "dprint": ["dprint@0.50.2", "", { "optionalDependencies": { "@dprint/darwin-arm64": "0.50.2", "@dprint/darwin-x64": "0.50.2", "@dprint/linux-arm64-glibc": "0.50.2", "@dprint/linux-arm64-musl": "0.50.2", "@dprint/linux-riscv64-glibc": "0.50.2", "@dprint/linux-x64-glibc": "0.50.2", "@dprint/linux-x64-musl": "0.50.2", "@dprint/win32-arm64": "0.50.2", "@dprint/win32-x64": "0.50.2" }, "bin": { "dprint": "bin.js" } }, "sha512-+0Fzg+17jsMMUouK00/Fara5YtGOuE76EAJINHB8VpkXHd0n00rMXtw/03qorOgz23eo8Y0UpYvNZBJJo3aNtw=="], + "duck": ["duck@0.1.12", "", { "dependencies": { "underscore": "^1.13.1" } }, "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], @@ -1434,6 +1512,8 @@ "electron-to-chromium": ["electron-to-chromium@1.5.396", "", {}, "sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ=="], + "embedded-postgres": ["embedded-postgres@18.4.0-beta.17", "", { "dependencies": { "async-exit-hook": "^2.0.1", "pg": "^8.7.3" }, "optionalDependencies": { "@embedded-postgres/darwin-arm64": "^18.4.0-beta.17", "@embedded-postgres/darwin-x64": "^18.4.0-beta.17", "@embedded-postgres/linux-arm": "^18.4.0-beta.17", "@embedded-postgres/linux-arm64": "^18.4.0-beta.17", "@embedded-postgres/linux-ia32": "^18.4.0-beta.17", "@embedded-postgres/linux-ppc64": "^18.4.0-beta.17", "@embedded-postgres/linux-x64": "^18.4.0-beta.17", "@embedded-postgres/windows-x64": "^18.4.0-beta.17" } }, "sha512-ORT/A1YiO6ecpRHpyIIBgyCR/8ASqqYZuFw11aX9PkqTX3FUM5+9sNOXY1mGIixxsm2TWSIA5WghJEk7A5ZxVw=="], + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], @@ -1468,6 +1548,8 @@ "eventsource-parser": ["eventsource-parser@3.1.1", "", {}, "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ=="], + "exifr": ["exifr@7.1.3", "", {}, "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw=="], + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], @@ -1528,6 +1610,8 @@ "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], "google-auth-library": ["google-auth-library@10.9.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw=="], @@ -1538,7 +1622,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "grok-mermaid": ["grok-mermaid@0.2.2", "", {}, "sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA=="], + "grok-mermaid": ["grok-mermaid@0.2.3", "", {}, "sha512-/4KopAbsjvuRP9MdPtlDjOHUmUVEohOX73JNcsWpzAtFxh+bq5+Dhb6gzvRieLDwIPQIR3/vy8V1NNTuz4Zsmg=="], "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], @@ -1560,10 +1644,14 @@ "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], + "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + "http-errors": ["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" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], @@ -1578,7 +1666,9 @@ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "ignore": ["ignore@7.0.8", "", {}, "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q=="], + + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], "impeccable": ["impeccable@4.1.0", "", { "optionalDependencies": { "@impeccable/cli-darwin-arm64": "0.1.5", "@impeccable/cli-darwin-x64": "0.1.5", "@impeccable/cli-linux-arm64": "0.1.5", "@impeccable/cli-linux-x64": "0.1.5", "@impeccable/cli-windows-x64": "0.1.5" }, "bin": { "impeccable": "cli/bin/cli.js" } }, "sha512-hnfdoUK/Xg3qPtL0/5xzh92qKOtmREOZloCmFgnC1nYh3M81ihwCQEL2QWKntYl8qg1OG+jQ7wubR634PgTDIw=="], @@ -1608,6 +1698,8 @@ "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + "is-in-ssh": ["is-in-ssh@1.0.0", "", {}, "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw=="], + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], @@ -1616,8 +1708,12 @@ "is-unsafe": ["is-unsafe@2.0.2", "", {}, "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ=="], + "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], + "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "isomorphic.js": ["isomorphic.js@0.2.5", "", {}, "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw=="], @@ -1646,6 +1742,8 @@ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "jszip": ["jszip@3.10.2", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ=="], + "just-bash": ["just-bash@2.14.5", "", { "dependencies": { "diff": "^8.0.2", "fast-xml-parser": "^5.7.3", "file-type": "^21.2.0", "ini": "^6.0.0", "minimatch": "^10.1.1", "modern-tar": "^0.7.3", "papaparse": "^5.5.3", "quickjs-emscripten": "^0.32.0", "re2js": "^1.2.1", "seek-bzip": "^2.0.0", "smol-toml": "^1.6.0", "sprintf-js": "^1.1.3", "sql.js": "^1.13.0", "turndown": "^7.2.2", "yaml": "^2.8.2" }, "optionalDependencies": { "@mongodb-js/zstd": "^7.0.0", "node-liblzma": "^2.0.3" }, "bin": { "just-bash": "dist/bin/just-bash.js", "just-bash-shell": "dist/bin/shell/shell.js" } }, "sha512-MCBGnRlDeZ/MM7mcw+ZuSGFMBsggajrmKz6e/hrOAN7syvVZkjiY+Vh2wyCwN/CdcnAX5SxbiQB51n5nrQuX+g=="], "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], @@ -1668,6 +1766,8 @@ "lib0": ["lib0@0.2.117", "", { "dependencies": { "isomorphic.js": "^0.2.4" }, "bin": { "0serve": "bin/0serve.js", "0gentesthtml": "bin/gentesthtml.js", "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js" } }, "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw=="], + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], @@ -1692,6 +1792,8 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + "linkedom": ["linkedom@0.18.13", "", { "dependencies": { "css-select": "^7.0.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.1.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw=="], + "lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], @@ -1700,16 +1802,22 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "lop": ["lop@0.4.2", "", { "dependencies": { "duck": "^0.1.12", "option": "~0.2.1", "underscore": "^1.13.1" } }, "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw=="], + "lru-cache": ["lru-cache@11.5.3", "", {}, "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg=="], "lru_map": ["lru_map@0.4.1", "", {}, "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "mammoth": ["mammoth@1.13.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "argparse": "~1.0.3", "base64-js": "^1.5.1", "dingbat-to-unicode": "^1.0.1", "jszip": "^3.7.1", "lop": "^0.4.2", "underscore": "^1.13.1", "xmlbuilder": "^10.0.0" }, "bin": { "mammoth": "bin/mammoth" } }, "sha512-2cawcYFcP7ISfXbBcL9lmVgTNWo88v/52ND1gnywHtVT/pX0//puPnf0iMPV9ZgmuvNOE+zkIhDgZ9M2c2dDDg=="], + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], "marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], + "markit-ai": ["markit-ai@0.5.3", "", { "dependencies": { "chalk": "^5.6.2", "commander": "^14.0.3", "exifr": "^7.1.3", "fast-xml-parser": "^5.5.9", "jszip": "^3.10.1", "mammoth": "^1.9.0", "mupdf": "^1.27.0", "music-metadata": "^11.12.3", "rss-parser": "^3.13.0", "turndown": "^7.2.0", "turndown-plugin-gfm": "^1.0.2" }, "bin": { "markit": "dist/main.js" } }, "sha512-h4nhn6a/SNXEdc3kLVtL37TspxjUNCNL0OM7LRWxd389ZByI/B7bjNNgxFdVAT0O+H7ZekSwLdVe/lws1l2AZQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "mdast-util-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="], @@ -1748,7 +1856,7 @@ "mdn-data": ["mdn-data@2.0.14", "", {}, "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="], - "media-typer": ["media-typer@1.1.1", "", {}, "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ=="], + "media-typer": ["media-typer@2.0.0", "", {}, "sha512-kOy3OxT2HH39N70UnKgu4NWDZjLOz8W/mfyvniHjRH/DrL3f2pOfvWQ4p60offbbtDAnXWp0v9LfMIqMec269Q=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], @@ -1832,10 +1940,12 @@ "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], "modern-tar": ["modern-tar@0.7.7", "", {}, "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ=="], @@ -1844,6 +1954,10 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mupdf": ["mupdf@1.28.1", "", {}, "sha512-Gi11Ow2G1SlrXKJNZBL1eAIGFVih5+4ZKqjptamTVaj/5hnlrcVrVbyb7lHE2lfFKdxZPyv9ZtfOOq7XgjzEig=="], + + "music-metadata": ["music-metadata@11.16.1", "", { "dependencies": { "@borewit/text-codec": "^0.2.2", "@tokenizer/token": "^0.3.0", "content-type": "^2.1.0", "debug": "^4.4.3", "file-type": "^21.3.4", "media-typer": "^2.0.0", "strtok3": "^10.3.5", "token-types": "^6.1.2", "uint8array-extras": "^1.5.0", "win-guid": "^0.2.1" } }, "sha512-uR/mHK6eyfl8h3jVCobF5b38Mfg1IDJMiBxIVbmm5F+G1OXEFcUpQHveO84tJBAqvY93GCRY2R4kDyx7s06Rug=="], + "nano-css": ["nano-css@5.6.2", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "css-tree": "^1.1.2", "csstype": "^3.1.2", "fastest-stable-stringify": "^2.0.2", "inline-style-prefixer": "^7.0.1", "rtl-css-js": "^1.16.1", "stacktrace-js": "^2.0.2", "stylis": "^4.3.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw=="], "nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], @@ -1866,6 +1980,8 @@ "node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="], + "nth-check": ["nth-check@3.0.1", "", { "dependencies": { "boolbase": "^2.0.0" } }, "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], @@ -1878,16 +1994,22 @@ "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], - "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + "open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="], "openai": ["openai@6.26.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA=="], + "option": ["option@0.2.4", "", {}, "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A=="], + "oxlint": ["oxlint@1.51.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.51.0", "@oxlint/binding-android-arm64": "1.51.0", "@oxlint/binding-darwin-arm64": "1.51.0", "@oxlint/binding-darwin-x64": "1.51.0", "@oxlint/binding-freebsd-x64": "1.51.0", "@oxlint/binding-linux-arm-gnueabihf": "1.51.0", "@oxlint/binding-linux-arm-musleabihf": "1.51.0", "@oxlint/binding-linux-arm64-gnu": "1.51.0", "@oxlint/binding-linux-arm64-musl": "1.51.0", "@oxlint/binding-linux-ppc64-gnu": "1.51.0", "@oxlint/binding-linux-riscv64-gnu": "1.51.0", "@oxlint/binding-linux-riscv64-musl": "1.51.0", "@oxlint/binding-linux-s390x-gnu": "1.51.0", "@oxlint/binding-linux-x64-gnu": "1.51.0", "@oxlint/binding-linux-x64-musl": "1.51.0", "@oxlint/binding-openharmony-arm64": "1.51.0", "@oxlint/binding-win32-arm64-msvc": "1.51.0", "@oxlint/binding-win32-ia32-msvc": "1.51.0", "@oxlint/binding-win32-x64-msvc": "1.51.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.15.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-g6DNPaV9/WI9MoX2XllafxQuxwY1TV++j7hP8fTJByVBuCoVtm3dy9f/2vtH/HU40JztcgWF4G7ua+gkainklQ=="], + "p-limit": ["p-limit@7.3.3", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ=="], + "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + "papaparse": ["papaparse@5.7.0", "", {}, "sha512-qBGxg/7Q3Kl9Wfhrz2Z74UnvnHTXLNG6jmKJFeBvP2+y4lV7So+7SR62+Zd47JvdrCkX+nDcnr0ObPzek/+6RA=="], "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], @@ -1904,8 +2026,26 @@ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "pg": ["pg@8.22.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.15.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA=="], + + "pg-cloudflare": ["pg-cloudflare@1.4.1", "", {}, "sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ=="], + + "pg-connection-string": ["pg-connection-string@2.14.1", "", {}, "sha512-qR3kGNPBLpCNtz0evbKA0Y/MRFXwSSdT+pTJvYp/bXTcReZbvX1kzF0IyTc1QnxqF7AZbOeBhNL8R5mYQZV/MA=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.14.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw=="], + + "pg-protocol": ["pg-protocol@1.16.1", "", {}, "sha512-p9VOFMiHB/ZbJATetbg+99PxssTVSQRnyuPSQ67mN1+1KBOjZaZ83ZQzltnxPhJwSsC3nwVjJ10DVJlerbFzLg=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + "pi-mcp-adapter": ["pi-mcp-adapter@2.12.1", "", { "dependencies": { "@modelcontextprotocol/client": "2.0.0-beta.5", "@modelcontextprotocol/ext-apps": "^1.2.2", "@modelcontextprotocol/sdk": "^1.29.0", "cross-spawn": "^7.0.6", "open": "^10.2.0", "recheck": "^4.5.0", "smol-toml": "^1.6.1", "zod": "^3.25.0 || ^4.0.0" }, "peerDependencies": { "@earendil-works/pi-ai": "*", "@earendil-works/pi-tui": "*", "typebox": "*" }, "optionalPeers": ["@earendil-works/pi-ai", "@earendil-works/pi-tui", "typebox"], "bin": { "pi-mcp-adapter": "cli.js" } }, "sha512-lB0ANetzF0ld+l8ibgF6KcT7bj1LKvhgKig9LHMvr1DEBark6xZ36Jeb+JLib49/M03sBaCH5s3Jcmcy/OO5wg=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -1926,8 +2066,20 @@ "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "powershell-utils": ["powershell-utils@0.2.1", "", {}, "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A=="], + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], @@ -1938,6 +2090,8 @@ "proxy-addr": ["proxy-addr@2.0.8", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ=="], + "proxy-agent-negotiate": ["proxy-agent-negotiate@1.1.0", "", { "peerDependencies": { "kerberos": "^2.0.0" }, "optionalPeers": ["kerberos"] }, "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ=="], + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], "qs": ["qs@6.16.0", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA=="], @@ -1972,7 +2126,7 @@ "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "recheck": ["recheck@4.5.0", "", { "dependencies": { "synckit": "0.9.2" }, "optionalDependencies": { "recheck-jar": "4.5.0", "recheck-linux-x64": "4.5.0", "recheck-macos-arm64": "4.5.0", "recheck-macos-x64": "4.5.0", "recheck-windows-x64": "4.5.0" } }, "sha512-kPnbOV6Zfx9a25AZ++28fI1q78L/UVRQmmuazwVRPfiiqpMs+WbOU69Shx820XgfKWfak0JH75PUvZMFtRGSsw=="], @@ -2010,6 +2164,8 @@ "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + "rss-parser": ["rss-parser@3.13.0", "", { "dependencies": { "entities": "^2.0.3", "xml2js": "^0.5.0" } }, "sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w=="], + "rtl-css-js": ["rtl-css-js@1.16.1", "", { "dependencies": { "@babel/runtime": "^7.1.2" } }, "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg=="], "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], @@ -2020,20 +2176,26 @@ "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sax": ["sax@1.6.1", "", {}, "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q=="], + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], "seek-bzip": ["seek-bzip@2.0.0", "", { "dependencies": { "commander": "^6.0.0" }, "bin": { "seek-bunzip": "bin/seek-bunzip", "seek-table": "bin/seek-bzip-table" } }, "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg=="], - "semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + "serialize-error": ["serialize-error@8.1.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ=="], + "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -2066,6 +2228,8 @@ "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], "sql.js": ["sql.js@1.14.2", "", {}, "sha512-3ZGPovObMFrdw79zrUHbfdE/DLIsy8jdNdssmMSQuRAymedU6q84asPt0kgiqrdMYlPegDItiIMfmIXzZnYFcw=="], @@ -2082,7 +2246,7 @@ "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], @@ -2100,6 +2264,8 @@ "stylis": ["stylis@4.4.0", "", {}, "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA=="], + "superjson": ["superjson@1.13.3", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg=="], + "synckit": ["synckit@0.9.2", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw=="], "tabbable": ["tabbable@6.5.0", "", {}, "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA=="], @@ -2140,13 +2306,21 @@ "turndown": ["turndown@7.2.4", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ=="], + "turndown-plugin-gfm": ["turndown-plugin-gfm@1.0.2", "", {}, "sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg=="], + + "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], + "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], "typebox": ["typebox@1.3.7", "", {}, "sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg=="], + "uhyphen": ["uhyphen@0.2.0", "", {}, "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], - "undici": ["undici@8.9.0", "", {}, "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA=="], + "underscore": ["underscore@1.13.8", "", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="], + + "undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="], "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], @@ -2168,6 +2342,8 @@ "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + "unpdf": ["unpdf@1.8.1", "", { "peerDependencies": { "@napi-rs/canvas": "^0.1.69 || ^1.0.0" }, "optionalPeers": ["@napi-rs/canvas"] }, "sha512-xkURhy2SoGpOIH0a1gLHNkASPIQYonadDJs2AQwPEfUakafeD9EA1WTWWsaR++gfTCXJpV27W7tU1nXuk82UKQ=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], @@ -2216,14 +2392,22 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "win-guid": ["win-guid@0.2.1", "", {}, "sha512-gEIQU4mkgl2OPeoNrWflcJFJ3Ae2BPd4eCsHHA/XikslkIVms/nHhvnvzIZV7VLmBvtFlDOzLt9rrZT+n6D67A=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], "ws": ["ws@8.21.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw=="], - "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + "wsl-utils": ["wsl-utils@1.0.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.2.0" } }, "sha512-c16PKLIRxBYpR3jSWsdS7SFp0COm5SOQdiFjY818dYFHJbMGuLBszpF07LBWmOS1uzrHa9VGdynsEgoeKy0oOQ=="], "xml-naming": ["xml-naming@0.3.0", "", {}, "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ=="], + "xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + + "xmlbuilder": ["xmlbuilder@10.1.1", "", {}, "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + "y-protocols": ["y-protocols@1.0.7", "", { "dependencies": { "lib0": "^0.2.85" }, "peerDependencies": { "yjs": "^13.0.0" } }, "sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -2232,6 +2416,8 @@ "yjs": ["yjs@13.6.31", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-Eq+5BRfbeGyqGVrTJL3bEcr8gKkxPuyuoHmAwpk52fDb8kOVMrfVSTRPd6yiGgX5Fskb96qCRjzjbRjrL4YEnw=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], @@ -2242,37 +2428,79 @@ "@ai-sdk/provider-utils/undici": ["undici@7.30.0", "", {}, "sha512-dkrQXeHSaoamnItlYbmzG0wFYrM0ZwDxCIg0A7aKjTyyhh9svRzCNFEzV+Vm05/yehjCzjDZ31KXfGEjYSztDQ=="], - "@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], - - "@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1138.0", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw=="], - "@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@bastani/atomic/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "@bastani/atomic/typebox": ["typebox@1.3.27", "", {}, "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA=="], + + "@bastani/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.124.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-cN5O8i9UVxHeOQAzj/XjshWXG8KiibJDw9OGpH2Z/eR3n/RBxdoLxDJOcfqAJWvjaMDFfHTBADU04hWRJVkDyA=="], + + "@bastani/pi-ai/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1127.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-node": "^3.972.82", "@aws-sdk/eventstream-handler-node": "^3.972.34", "@aws-sdk/middleware-eventstream": "^3.972.29", "@aws-sdk/middleware-websocket": "^3.972.52", "@aws-sdk/token-providers": "3.1127.0", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA=="], + + "@bastani/pi-ai/@google/genai": ["@google/genai@2.21.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-+PDtco2/Z0ONdzCGekCoCT+O1VJS9xJQNN4XzQpXG/t3El/SWWMkCWlFRO1KmivOHPa4Q0VjUYu1HBKCZ/v33Q=="], + + "@bastani/pi-ai/http-proxy-agent": ["http-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig=="], + + "@bastani/pi-ai/https-proxy-agent": ["https-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA=="], + + "@bastani/pi-ai/openai": ["openai@7.19.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "undici": ">=5 <9", "ws": "^8.21.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "undici", "ws", "zod"] }, "sha512-MX2s3u2L5racTO0CC/SWpCOasJQBCJrqLKXK+l82cAhdeF8mPMBEe/gxMm0ZFa2xpKpOFLRjxv5afYEZbBXmbQ=="], + + "@bastani/pi-ai/typebox": ["typebox@1.3.27", "", {}, "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA=="], + "@chevrotain/cst-dts-gen/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], "@chevrotain/gast/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "@dbos-inc/dbos-sdk/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + + "@dbos-inc/dbos-sdk/yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], + "@earendil-works/chord/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.85.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.123.0", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@earendil-works/pi-telemetry": "^0.85.1", "@google/genai": "1.52.0", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.40.0", "partial-json": "0.1.7", "typebox": "1.3.7" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ=="], + "@earendil-works/pi-agent-core/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.87.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "^0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "6.40.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-X/3PfQBnnoeVdO9Cv8zHghUMglzlgNZYGNzoPnbRoGnHl3Rw3TlA2UKSUB7BRHUOxMryHXYa8dnjWZlbRheDZA=="], "@earendil-works/pi-agent-core/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + "@earendil-works/pi-agent-core/typebox": ["typebox@1.3.27", "", {}, "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA=="], + "@earendil-works/pi-ai/typebox": ["typebox@1.3.34", "", {}, "sha512-wbnzrXXDW8xEFHDZZs2jo1MkhaYlKAY4FRhpBc1+2LF1fZVBGCXGdLEhA/Z/NBbgzJMFfeM8m7elKPa/+KxaUQ=="], + "@earendil-works/pi-client/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + + "@earendil-works/pi-coding-agent/@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.85.1", "", { "dependencies": { "@earendil-works/chord": "^0.85.1", "@earendil-works/pi-ai": "^0.85.1", "@earendil-works/pi-telemetry": "^0.85.1", "diff": "8.0.4", "ignore": "7.0.5", "typebox": "1.3.7", "yaml": "2.9.0" } }, "sha512-hIXIP3eAWueAYiAl8aMvWCvvZ8Q5gT3Dip5bE5uJyIGh4+YlWRjtMLI4BaeoXoSs93zndjue61u1B/vhefLnuA=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.85.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.123.0", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@earendil-works/pi-telemetry": "^0.85.1", "@google/genai": "1.52.0", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.40.0", "partial-json": "0.1.7", "typebox": "1.3.7" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.85.1", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.5" } }, "sha512-OIzw9efInmO4WOBnD4TxcTdBjmzvYJpzslkgoUro946nEGoYWg5rwv1p4fDt3/JvMx9QybryUCUwlm7j8Dreig=="], + + "@earendil-works/pi-coding-agent/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "@earendil-works/pi-coding-agent/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], - "@earendil-works/pi-tui/marked": ["marked@18.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w=="], + "@earendil-works/pi-coding-agent/grok-mermaid": ["grok-mermaid@0.2.2", "", {}, "sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA=="], + + "@earendil-works/pi-coding-agent/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@earendil-works/pi-coding-agent/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@earendil-works/pi-coding-agent/semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="], + + "@earendil-works/pi-coding-agent/undici": ["undici@8.9.0", "", {}, "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA=="], + + "@earendil-works/pi-protocol/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + + "@earendil-works/pi-protocol/typebox": ["typebox@1.3.27", "", {}, "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA=="], + + "@earendil-works/pi-tui/marked": ["marked@18.0.11", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="], @@ -2286,6 +2514,8 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "body-parser/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], "body-parser/iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], @@ -2300,26 +2530,54 @@ "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="], + "dom-serializer/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], + + "dom-serializer/entities": ["entities@8.1.0", "", {}, "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA=="], + + "domhandler/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], + + "domutils/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], + + "ecdsa-sig-formatter/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "happy-dom/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], - "just-bash/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + "htmlparser2/domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - "just-bash/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + "htmlparser2/domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "just-bash/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], "just-bash/yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], + "jwa/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "jws/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "mammoth/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "markit-ai/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "markit-ai/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "mermaid/katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="], "micromark-extension-math/katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="], - "negotiator/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], + "music-metadata/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], - "node-abi/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "negotiator/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "pi-mcp-adapter/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.30.1", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA=="], + + "pi-mcp-adapter/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], @@ -2328,18 +2586,34 @@ "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "rss-parser/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "seek-bzip/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="], "stacktrace-gps/source-map": ["source-map@0.5.6", "", {}, "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA=="], + "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "tunnel-agent/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "type-is/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], + "type-is/media-typer": ["media-typer@1.1.1", "", {}, "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ=="], + "unidiff/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], "uvu/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], "vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + "xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + + "@bastani/pi-ai/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1127.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ=="], + + "@bastani/pi-ai/http-proxy-agent/agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + + "@bastani/pi-ai/https-proxy-agent/agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + "@earendil-works/chord/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], "@earendil-works/chord/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], @@ -2392,28 +2666,222 @@ "@earendil-works/chord/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.123.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-Y9oX9mPNGZClHQOFqrWRk43Srcu/UHuPq3rfxxOq7JgW0gi+lJA2MAOK4Ul3k/+AUrwRWFJvd0tK3oC0Pw25dw=="], + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="], + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.124.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-cN5O8i9UVxHeOQAzj/XjshWXG8KiibJDw9OGpH2Z/eR3n/RBxdoLxDJOcfqAJWvjaMDFfHTBADU04hWRJVkDyA=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1127.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-node": "^3.972.82", "@aws-sdk/eventstream-handler-node": "^3.972.34", "@aws-sdk/middleware-eventstream": "^3.972.29", "@aws-sdk/middleware-websocket": "^3.972.52", "@aws-sdk/token-providers": "3.1127.0", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@google/genai": ["@google/genai@2.21.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-+PDtco2/Z0ONdzCGekCoCT+O1VJS9xJQNN4XzQpXG/t3El/SWWMkCWlFRO1KmivOHPa4Q0VjUYu1HBKCZ/v33Q=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/http-proxy-agent": ["http-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/https-proxy-agent": ["https-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA=="], "@earendil-works/pi-agent-core/@earendil-works/pi-ai/openai": ["openai@6.40.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"] }, "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA=="], + "@earendil-works/pi-client/@earendil-works/chord/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], + + "@earendil-works/pi-coding-agent/@earendil-works/pi-agent-core/@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.85.1", "", {}, "sha512-Bg/YN6kA7Swja/NQxka8xFdecb4E/auIEGF2G5A25EaQXhRnPj300/7/KpgsDDMYUzHTDAv4RyUxaQPJKW81Rw=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.123.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-Y9oX9mPNGZClHQOFqrWRk43Srcu/UHuPq3rfxxOq7JgW0gi+lJA2MAOK4Ul3k/+AUrwRWFJvd0tK3oC0Pw25dw=="], "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.85.1", "", {}, "sha512-Bg/YN6kA7Swja/NQxka8xFdecb4E/auIEGF2G5A25EaQXhRnPj300/7/KpgsDDMYUzHTDAv4RyUxaQPJKW81Rw=="], + + "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/openai": ["openai@6.40.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"] }, "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA=="], + "@earendil-works/pi-coding-agent/@earendil-works/pi-tui/marked": ["marked@18.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], + + "bl/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="], + "htmlparser2/domutils/dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "mammoth/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "pi-mcp-adapter/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + + "tar-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], + + "@earendil-works/pi-agent-core/@earendil-works/chord/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1127.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/http-proxy-agent/agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/https-proxy-agent/agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], + + "@earendil-works/pi-client/@earendil-works/chord/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="], "@earendil-works/pi-coding-agent/@earendil-works/pi-ai/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], + + "@earendil-works/pi-protocol/@earendil-works/chord/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], + + "bl/readable-stream/string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "htmlparser2/domutils/dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "tar-stream/readable-stream/string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], } } diff --git a/docs/architecture.md b/docs/architecture.md index 3f6964f5..dd109b3c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -33,7 +33,8 @@ and [Self-hosting](self-hosting.md) for deployment. blocks starting research from a child; the API may accept the request, but publication validation rejects linking a grandchild. - The **Planner** is the current name of Chopin's hosted document agent, backed - by GitHub Copilot by default or by Pi under `HARNESS=pi`. + by GitHub Copilot by default, by Pi under `HARNESS=pi`, or by an in-process + Atomic session under `HARNESS=atomic`. - A **coding agent** is an external MCP client that creates, revises, or implements a document from its own local workspace. @@ -53,7 +54,7 @@ flowchart LR C[Local coding agent] -->|Bearer-authenticated MCP| S S --> P[(PostgreSQL)] S --> G[GitHub API] - S --> A[Harness model provider: Copilot or Pi] + S --> A[Harness model provider: Copilot, Pi, or Atomic] S --> W[Built web client] ``` @@ -473,6 +474,7 @@ Treat these as implementation work, not guarantees to build new behavior upon. `apps/server/src/harness/session.ts`, and `apps/server/src/harness/github-tools.ts` - Copilot SDK adapter: `apps/server/src/harness/copilot-sdk/adapter.ts` +- Atomic SDK adapter: `apps/server/src/harness/atomic/adapter.ts` - Channel routes and IDs: `apps/server/src/channels/` - Research requests and child publication: `apps/server/src/research/service.ts` - Inline request state and anchored children: `apps/web/src/research-requests.ts` diff --git a/docs/hosted-agent.md b/docs/hosted-agent.md index 89f7e8b0..fae44c3c 100644 --- a/docs/hosted-agent.md +++ b/docs/hosted-agent.md @@ -12,21 +12,22 @@ that is an implementation limitation, not the document model's boundary. Chopin runs the Planner through `@ai-sdk/harness`: `HARNESS` selects one adapter from a code-owned map, defaulting to `copilot-sdk`, a host-process adapter over -`@github/copilot-sdk`. `pi`, over `@ai-sdk/harness-pi`, is a second reviewed -adapter and requires an explicit `HARNESS_AUTH`. The harness owns the agent -loop and model; Chopin owns every tool the Planner can call. See -[Self-hosting](self-hosting.md) for `HARNESS`/`HARNESS_AUTH` selection and -adapter trust. +`@github/copilot-sdk`. `pi`, over `@ai-sdk/harness-pi`, and `atomic`, which +embeds Atomic's headless SDK (`@bastani/atomic`) in the server process, are +further reviewed adapters. Both require an explicit `HARNESS_AUTH`. The +harness owns the agent loop and model; Chopin owns every tool the Planner can +call. See [Self-hosting](self-hosting.md) for `HARNESS`/`HARNESS_AUTH` +selection and adapter trust. ## Ownership The first eligible editor to invoke the Planner or start a model-backed research request supplies the GitHub App user access token for that channel and, under the default `copilot-sdk` harness, the Copilot entitlement. Under `HARNESS=pi` -the owner supplies only the GitHub token; model access comes from the -operator's `HARNESS_AUTH` mode. The user must pass instance admission and have -repository push or administration access. Ownership is assigned atomically in -storage and guarded by a generation token. +and `HARNESS=atomic` the owner supplies only the GitHub token; model access +comes from the operator's `HARNESS_AUTH` mode. The user must pass instance +admission and have repository push or administration access. Ownership is +assigned atomically in storage and guarded by a generation token. That process-local login owns the channel's model usage until it expires, logs out, the server restarts, or the authenticated reset API releases it. The @@ -64,6 +65,19 @@ Under `HARNESS=pi`, Chopin patches `@ai-sdk/harness-pi` 1.0.128 so Pi does not load `AGENTS.md` or `CLAUDE.md` context files from the host filesystem. See [Self-hosting](self-hosting.md#choose-and-trust-a-harness). +Under `HARNESS=atomic`, each harness session owns one in-process Atomic +`AgentSession`. It is built with every shipped Atomic package disabled +(workflows, subagents, MCP, web access, and Intercom). It has no Atomic coding +tools, and its resource loader discovers no extensions, skills, prompt +templates, themes, or context files. Its working and configuration directory is +an empty private temporary directory, and its session, settings, and +credentials stay in memory. A per-turn hook replaces the whole system prompt +with the turn's instructions, so the model never receives Atomic's +coding-agent preamble. The adapter fails the turn before any model request +when the live session reports an extension, tool, context file, skill, prompt +template, or system prompt beyond that set. It checks the tools offered to the +model again before every model request. + Available capabilities are: - Chopin document, question, relationship, and implementation-graph tools (with @@ -213,6 +227,7 @@ current production interface lets a person approve the draft. See - Planner session lifecycle: `apps/server/src/harness/session.ts` - Host-executed GitHub MCP tools: `apps/server/src/harness/github-tools.ts` - Copilot SDK adapter: `apps/server/src/harness/copilot-sdk/adapter.ts` +- Atomic SDK adapter: `apps/server/src/harness/atomic/adapter.ts` - Planner prompt and document tools: `apps/server/src/agent/planner.ts` and `apps/server/src/agent/tools.ts` - Repository-fixed tools: `apps/server/src/agent/repository.ts` diff --git a/docs/self-hosting.md b/docs/self-hosting.md index 11ca1e07..e51eb5bd 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -57,14 +57,15 @@ bearer tokens and browser sessions traverse it. Chopin runs its hosted agent through `@ai-sdk/harness`. `HARNESS` selects one adapter from a code-owned map: the default is `copilot-sdk`, a host-process -wrapper over `@github/copilot-sdk`, and `pi` is a second reviewed adapter over -`@ai-sdk/harness-pi`. Adding an adapter to that map is a reviewed trust -decision, not a runtime plugin choice: an adapter's `builtinTools` and -`supportsBuiltinToolFiltering` are self-declarations, and Chopin's contract -suite checks those declarations and the tools a session actually receives, -but it cannot prove what the underlying runtime does internally. Only -adapters that ship in this repository and pass that suite belong in -`harnesses`. +wrapper over `@github/copilot-sdk`; `pi` is a second reviewed adapter over +`@ai-sdk/harness-pi`; and `atomic` embeds Atomic's headless SDK +(`@bastani/atomic`) in the server process. Adding an adapter to that map is a +reviewed trust decision, not a runtime plugin choice: an adapter's +`builtinTools` and `supportsBuiltinToolFiltering` are self-declarations, and +Chopin's contract suite checks those declarations and the tools a session +actually receives, but it cannot prove what the underlying runtime does +internally. Only adapters that ship in this repository and pass that suite +belong in `harnesses`. For `copilot-sdk`, `direct` and `ai-gateway` are explicit `HARNESS_AUTH` modes that may be used on any bind. A mode that could fall back to a subscription @@ -114,6 +115,74 @@ it. The Pi contract suite (`apps/server/src/harness/pi.contract.test.ts`) covers this against the real Pi agent loop; run it before bumping `@ai-sdk/harness-pi` or `@earendil-works/pi-coding-agent`. +`HARNESS=atomic` runs Atomic 0.9.23 in the Chopin server process through its +headless SDK (`createAgentSession()`). It does not spawn the `atomic` CLI, use +RPC mode, or substitute Atomic for Pi's runtime. Each harness session owns one +in-memory Atomic `AgentSession` whose only tools are Chopin's host tools; see +[Hosted agent](hosted-agent.md#runtime-isolation) for the isolation it +enforces. + +`HARNESS=atomic` requires an explicit `HARNESS_AUTH`, either `auto` or +`ai-gateway`. Unset, `direct`, and every other value are refused at startup. + +- `auto` copies the host operator's Atomic login into memory when the first + turn starts: `$ATOMIC_CODING_AGENT_DIR/auth.json` when that variable is set, + otherwise `~/.atomic/agent/auth.json` over the legacy `~/.pi/agent/auth.json`. + It also resolves provider keys from the process environment, such as + `ANTHROPIC_API_KEY`, and ambient cloud credentials, such as an AWS profile or + Google application default credentials. Because every admitted writer's turns + would use the operator's own subscription or keys, `auto` is refused unless + `SERVER_HOST` is loopback-only. +- `ai-gateway` starts without stored credentials, reads `AI_GATEWAY_API_KEY`, + and accepts only `vercel-ai-gateway` models. It is the only mode allowed on a + non-loopback bind. + +The adapter never writes credentials to disk. It reads the host login without a +lock file, keeps refreshed OAuth tokens in memory, and neither reads nor writes +Atomic's `models.json` or `models-store.json`. + +Under `atomic`, `MODEL` is required and must name a `provider/model` from +Atomic's catalog: for example `vercel-ai-gateway/anthropic/claude-sonnet-4.6` +under `ai-gateway`, or `github-copilot/gpt-6-luna` under `auto` with a GitHub +Copilot login. An integration that passes Atomic a failed model lookup gets +another model without warning. This adapter looks the model up itself and +fails the turn before any model request. + +Structured output uses the same approach as Pi: an inline Atomic extension +registers a terminating result tool, enabled only for a turn that requests +structured output and blocked on every other turn. The tool records the calling +model's own arguments. The adapter does not use Atomic's +`createStructuredOutputTool`, which infers the answer again with a second model +call. The Atomic contract suite +(`apps/server/src/harness/atomic.contract.test.ts`) covers isolation, model +resolution, host tools, structured output, and abort against Atomic's real +agent loop. Run it before bumping `@bastani/atomic`. + +Atomic caveats: + +- Atomic's SDK defaults suit a local coding agent, not Chopin. By default it + enables its shipped packages, including a mandatory Intercom, and its coding + tools. It discovers host resources, gives turns without instructions a + coding-agent system prompt, and saves tool results over 50,000 characters to a + temporary file. The adapter overrides each default and fails closed on the + ones it can observe, but a new Atomic release can add a default the suite does + not check. +- Sessions live only in memory. `doStop` returns a state the adapter refuses to + resume, so a session never survives a restart. Chopin does not resume + harness sessions. +- Compaction, suspending a turn, and skills are unsupported. Atomic's automatic + retries remain on. +- Under `auto`, refreshing an OAuth token in memory can rotate the refresh token + stored by the host CLI, which may then ask the operator to sign in again. + `auto` also runs `!command` API-key entries in `auth.json` to resolve them. +- There is no per-session credit limit like Copilot's, so a worker's + `maxAiCredits` does not apply. Use the provider's spend limits. +- `@bastani/atomic` adds more than 250 MB of installed dependencies on Linux + x64, including glibc and musl native modules and the embedded PostgreSQL + that only Atomic workflows use. Expect a larger image. +- Atomic depends on `typebox` 1.3.27 while Chopin pins 1.3.7. Host tool schemas + pass to Atomic as plain JSON Schema, so the two versions never meet. + For a reviewed adapter that consumes a shared operator key, every admitted writer's turns would bill that key. Chopin adds no billing quotas of its own in this revision, across jobs or users; use the model provider's spend limits and @@ -131,7 +200,7 @@ turns of its job stage, not as a platform-wide budget; see - A GitHub App owned by the deployment. - At least one user with repository push or administration access. - For `copilot-sdk`, an active Copilot entitlement for each user who may own a - hosted agent session. For `pi`, model credentials for the chosen + hosted agent session. For `pi` or `atomic`, model credentials for the chosen `HARNESS_AUTH` mode instead. ## Register the GitHub App @@ -169,28 +238,28 @@ Store production values in the deployment's secret manager or an owner-readable environment file outside the source tree. Do not bake `.env` or credentials into the image. -| Variable | Default | Meaning | -| ------------------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `STORAGE_DRIVER` | `postgres` | Storage adapter. `postgres` is currently the only accepted value. | -| `DATABASE_URL` | required | `postgres:` or `postgresql:` connection URL. It is not printed by Chopin. | -| `APP_ORIGIN` | required | Exact public origin, without credentials, path, query, fragment, or trailing slash. HTTPS is required unless the host is loopback. | -| `GITHUB_APP_SLUG` | required | Lowercase slug from the App's public URL. | -| `GITHUB_APP_CLIENT_ID` | required | OAuth client ID, not the numeric GitHub App ID. | -| `GITHUB_APP_CLIENT_SECRET` | required (hosted) | OAuth client secret used for user-token exchange and refresh. Unused when `AUTH_MODE=local`. | -| `GITHUB_ALLOWED_USERS` | empty | Comma-separated admitted GitHub logins. | -| `GITHUB_ALLOWED_ORGANIZATIONS` | empty | Comma-separated organizations whose active members are admitted. | -| `SESSION_ENCRYPTION_KEY` | required | Exactly 64 hexadecimal characters. Encrypts the OAuth attempt cookie in hosted mode; local mode requires the configured key but uses separate unpredictable, HttpOnly attempt and browser-binding cookies. | -| `AUTH_MODE` | `hosted` | Set `local` for loopback device-flow sign-in with persisted credentials (see [Authentication](authentication.md#local-device-flow-sign-in)). Any other value fails startup. | -| `CHOPIN_LOCAL_CREDENTIALS_DIR` | platform default | Local mode only. Overrides the plaintext-fallback credential directory (default `~/.config/chopin` on Linux, `~/Library/Application Support/Chopin` on macOS, `%APPDATA%\Chopin` on Windows). Must resolve outside the repository and process working directory. | -| `SERVER_HOST` | `127.0.0.1` | Source-process bind address. The image sets `0.0.0.0`, which local mode refuses. A `HARNESS_AUTH` mode that falls back to a host-logged-in subscription is refused unless this stays loopback-only. | -| `PORT` | `8787` | Source-process HTTP and WebSocket port. The supplied image and health check expect internal port 8787. | -| `MODEL` | `gpt-6-luna` | Model requested for hosted agent sessions. Required under `HARNESS=pi`. | -| `HARNESS` | `copilot-sdk` | Adapter name selected from Chopin's harness map (`copilot-sdk` or `pi`). An unknown name refuses at startup. | -| `HARNESS_AUTH` | unset | Auth mode forwarded to the selected adapter. For `copilot-sdk`, `direct` and `ai-gateway` are allowed on any bind and `auto` requires a loopback-only `SERVER_HOST`; the adapter does not otherwise consume it. For `pi`, it is required: `auto`, `openai`, `anthropic`, and `custom` require a loopback-only `SERVER_HOST`, only `ai-gateway` is allowed otherwise, and `direct` is always refused. | -| `AGENT` | on | Set exactly `off` to prevent hosted agent turns, disable the entire background-job runner, and avoid Copilot CLI startup. | -| `BACKGROUND_JOBS` | on | Set exactly `off` to disable background job scheduling. `AGENT=off` disables the entire runner. | -| `WEB_RESEARCH` | on | Set exactly `off` to disable new public-web research while retaining durable requests, artifacts, and other jobs. | -| `COPILOT_CLI_PATH` | automatic | Advanced override for the Copilot CLI executable. Applies only to the `copilot-sdk` adapter. | +| Variable | Default | Meaning | +| ------------------------------ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `STORAGE_DRIVER` | `postgres` | Storage adapter. `postgres` is currently the only accepted value. | +| `DATABASE_URL` | required | `postgres:` or `postgresql:` connection URL. It is not printed by Chopin. | +| `APP_ORIGIN` | required | Exact public origin, without credentials, path, query, fragment, or trailing slash. HTTPS is required unless the host is loopback. | +| `GITHUB_APP_SLUG` | required | Lowercase slug from the App's public URL. | +| `GITHUB_APP_CLIENT_ID` | required | OAuth client ID, not the numeric GitHub App ID. | +| `GITHUB_APP_CLIENT_SECRET` | required (hosted) | OAuth client secret used for user-token exchange and refresh. Unused when `AUTH_MODE=local`. | +| `GITHUB_ALLOWED_USERS` | empty | Comma-separated admitted GitHub logins. | +| `GITHUB_ALLOWED_ORGANIZATIONS` | empty | Comma-separated organizations whose active members are admitted. | +| `SESSION_ENCRYPTION_KEY` | required | Exactly 64 hexadecimal characters. Encrypts the OAuth attempt cookie in hosted mode; local mode requires the configured key but uses separate unpredictable, HttpOnly attempt and browser-binding cookies. | +| `AUTH_MODE` | `hosted` | Set `local` for loopback device-flow sign-in with persisted credentials (see [Authentication](authentication.md#local-device-flow-sign-in)). Any other value fails startup. | +| `CHOPIN_LOCAL_CREDENTIALS_DIR` | platform default | Local mode only. Overrides the plaintext-fallback credential directory (default `~/.config/chopin` on Linux, `~/Library/Application Support/Chopin` on macOS, `%APPDATA%\Chopin` on Windows). Must resolve outside the repository and process working directory. | +| `SERVER_HOST` | `127.0.0.1` | Source-process bind address. The image sets `0.0.0.0`, which local mode refuses. A `HARNESS_AUTH` mode that falls back to a host-logged-in subscription is refused unless this stays loopback-only. | +| `PORT` | `8787` | Source-process HTTP and WebSocket port. The supplied image and health check expect internal port 8787. | +| `MODEL` | `gpt-6-luna` | Model requested for hosted agent sessions. Required under `HARNESS=pi` and `HARNESS=atomic`; under `atomic` it must be `provider/model` from Atomic's catalog. | +| `HARNESS` | `copilot-sdk` | Adapter name selected from Chopin's harness map (`copilot-sdk`, `pi`, or `atomic`). An unknown name refuses at startup. | +| `HARNESS_AUTH` | unset | Auth mode forwarded to the selected adapter. For `copilot-sdk`, `direct` and `ai-gateway` are allowed on any bind and `auto` requires a loopback-only `SERVER_HOST`; the adapter does not otherwise consume it. For `pi`, it is required: `auto`, `openai`, `anthropic`, and `custom` require a loopback-only `SERVER_HOST`, only `ai-gateway` is allowed otherwise, and `direct` is always refused. For `atomic`, it is required and must be `auto`, which requires a loopback-only `SERVER_HOST`, or `ai-gateway`; every other value is refused. | +| `AGENT` | on | Set exactly `off` to prevent hosted agent turns, disable the entire background-job runner, and avoid Copilot CLI startup. | +| `BACKGROUND_JOBS` | on | Set exactly `off` to disable background job scheduling. `AGENT=off` disables the entire runner. | +| `WEB_RESEARCH` | on | Set exactly `off` to disable new public-web research while retaining durable requests, artifacts, and other jobs. | +| `COPILOT_CLI_PATH` | automatic | Advanced override for the Copilot CLI executable. Applies only to the `copilot-sdk` adapter. | See [Background jobs and workers](background-jobs.md) for the combined `AGENT`, `BACKGROUND_JOBS`, and `WEB_RESEARCH` behavior and recovery model. @@ -365,7 +434,8 @@ After the first deployment: 5. Create a channel with a user who has push or administration access. 6. Open the channel in a second browser and verify presence and live edits. 7. Send one `@chopin` request to verify model access (the owner's Copilot - entitlement for `copilot-sdk`, or the `HARNESS_AUTH` credentials for `pi`) + entitlement for `copilot-sdk`, or the `HARNESS_AUTH` credentials for `pi` or + `atomic`) and the hosted agent runtime. 8. Connect a local coding agent and call `list_documents` if MCP is part of the deployment's intended surface. diff --git a/package.json b/package.json index ca38be76..84ed5f7f 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", + "@bastani/atomic": "0.9.23", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7", From 0d291f25a80a47c854ca7f0a18410c5b17a0622b Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Mon, 28 Sep 2026 18:49:46 +0000 Subject: [PATCH 2/6] Keep the Atomic harness research notes The ralph run's research stage mapped Atomic's SDK onto HarnessV1: event translation, host tool round trips, the tool boundary, auth modes, and caveats such as no cross-process resume and oversized tool result truncation. Keep it with the branch so review can continue on another machine. The run was stopped during its first review round. Both reviewers had no blocking findings; reviewer B noted one doc nit: self-hosting.md names only ATOMIC_CODING_AGENT_DIR, but Atomic also honors legacy PI_CODING_AGENT_DIR for the auto-mode auth.json path. The Docker build could not be verified on this machine because its Docker Desktop network fails TLS to registry.npmjs.org (npm.pkg.github.com and api.github.com still work), so bun install inside the image cannot fetch the new lockfile entries. Assistant-workflow: ralph (run 0cfa5220-f488-43ef-8bb5-2f54cf5141f2) Assistant-model: Claude Opus 5.5 Assistant-duration: 72m abandoned, estimated 90m Assistant-verification: docker build unavailable: container TLS to registry.npmjs.org fails with UNKNOWN_CERTIFICATE_VERIFICATION_ERROR on this Docker Desktop host User-preference: Stop the workflow and hand off when the local environment blocks verification; continue on another machine Co-authored-by: Alex Lavaee --- ...-to-chopin-s-hosted-planner-built-direc.md | 433 ++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 research/2026-09-28-keepcontext-add-an-atomic-harness-adapter-to-chopin-s-hosted-planner-built-direc.md diff --git a/research/2026-09-28-keepcontext-add-an-atomic-harness-adapter-to-chopin-s-hosted-planner-built-direc.md b/research/2026-09-28-keepcontext-add-an-atomic-harness-adapter-to-chopin-s-hosted-planner-built-direc.md new file mode 100644 index 00000000..2af2d1a8 --- /dev/null +++ b/research/2026-09-28-keepcontext-add-an-atomic-harness-adapter-to-chopin-s-hosted-planner-built-direc.md @@ -0,0 +1,433 @@ +# Research report: adding an `atomic` Planner harness to Chopin on the Atomic SDK + +The research is done and the design is feasible. I ran a scratch spike against the installed Atomic 0.9.23 and the repo's own model stub, in `/tmp/atomic-spike/` outside the repository. It confirmed the in-process design: `createAgentSession()` with a custom `DefaultResourceLoader`, in-memory session and settings managers, and a `ModelRuntime` using `AuthStorage.inMemory()`. I changed no repository files. + +The SDK does **not** give most of the guarantees by default. The adapter has to set them explicitly and check them itself. Five problems need handling, and each has an SDK option or hook that solves it: + +1. **Unknown models fall back silently.** Passing `model: undefined` makes Atomic pick the first available model with no `modelFallbackMessage`. The adapter must look the model up itself and fail the turn. +2. **An empty system prompt brings in Atomic's coding-assistant prompt.** That text includes an Atomic docs section. The adapter must always force the exact per-turn system prompt. +3. **`prompt()` does not reject on abort or model error.** It resolves normally; the failure only shows on the last assistant message and `agent.state.errorMessage`. +4. **A host tool that ignores its abort signal makes `abort()` and `prompt()` hang.** The adapter must settle pending host-tool promises when the turn aborts. +5. **Large tool results are written to disk.** Results over 50,000 characters are saved to a temp file and the model gets only a preview and a path. Host tools should set `maxResultSizeChars: Infinity`. + +No `bun patch` looks necessary. Every safety need maps to a supported option or extension hook. + +## Contract amendments received + +None. No steering or follow-up messages arrived during this stage. The launch objective and acceptance criteria are the whole contract. + +## Compatibility posture + +`breaking_changes_allowed: false` for the existing `copilot-sdk` and `pi` harnesses. The acceptance criteria say not to regress them. This is an addition to the code-owned `harnesses` map. Existing behaviour that must stay the same: + +- `harnessFor` validation for `copilot-sdk` and `pi`. +- The `harnessContract` suite in `contract.ts`, which the other adapters also run. +- The `PLANNER_TOOL_NAMES` boundary in `chat/service.ts`. +- The Pi patch and Pi's result tool. + +--- + +## 1. Codebase facts (verified this session) + +### Harness selection — `apps/server/src/harness/harnesses.ts` + +- The map is `harnesses = { "copilot-sdk": createCopilotSdk, pi: createPiHarness }`. Its `satisfies` type is `(settings: {credentials, limits, auth?}) => HarnessV1` (lines 17-27). +- The cached singleton is `selected: HarnessV1 & { shutdown(): Promise }` (line 31). `shutdownHarnesses()` calls `selected?.shutdown()` (lines 89-93). +- `loopback()` accepts `localhost`, `::1`, `[::1]` and `127.x.x.x` (lines 33-37). +- Pi auth modes are `PI_AUTH_MODES = {auto, openai, anthropic, custom, ai-gateway}` (line 42). `harnessFor` for Pi (lines 54-63) does three things: + - requires `HARNESS_AUTH`; + - rejects unknown modes; + - allows only `ai-gateway` on a non-loopback host. +- Every other harness goes through the generic rule: an auth value other than `direct` or `ai-gateway` needs loopback (lines 64-66). An `atomic` branch is needed, or `atomic` will silently use the generic rule. +- `createPiHarness` forwards only `auth` (lines 11-15). The Atomic factory should follow the same pattern; credit `limits` are Copilot-specific. + +### Tests to update — `harnesses.test.ts` + +- Line 8 pins `Object.keys(harnesses)` to `["copilot-sdk", "pi"]`. It must become `["copilot-sdk", "pi", "atomic"]`, or whatever order registration uses. +- Add the Atomic auth-mode and loopback matrix in the same style as the Pi tests at lines 28-47. + +### Shared contract — `apps/server/src/harness/contract.ts` + +`harnessContract(name, createHarness, createSandboxSession?)` has three tests: + +1. **Tools boundary** (prompt `"tools"`, host tools `first_host` and `second_host`): + - the turn sees exactly the host tools; + - `builtinTools` is empty, or `supportsBuiltinToolFiltering` is true with `builtinToolFiltering: {mode:"allow", toolNames:[]}`; + - no non-host `tool-call`/`tool-result` events appear; + - destroy runs once. +2. **Structured output** (prompt `"output"`, `Output.object({answer: string})`): `result.output` parses and `responseFormat.type === "json"` is forwarded. +3. **Abort** (prompt `"abort"`): `abortSignal` is forwarded as the same object; after abort `hasUnfinishedTurn()` is false; destroy is idempotent. + +The suite does **not** test a plain text turn, and it does not force a host-tool round trip. Criterion 6 requires both, so `atomic.contract.test.ts` needs extra cases. Recommendation: script the stub so `"tools"` makes a call to `first_host` and then returns text, and add an explicit `"plain"` text test. `contract.ts` is shared with `copilot-sdk` and `pi`; changing it risks regressing them. + +### Pi reference — `apps/server/src/harness/pi.contract.test.ts` and `pi/model-stub.ts` + +- **The stub:** + - It is an OpenAI-completions SSE server. + - It is scripted by the last user message and `hasPriorToolResult`, which is true when any message has `role: "tool"`. + - It supports `text`, `tool` and `hold` turns; `hold` closes the response on request abort. + - It records `prompt`, `system`, `toolNames` and `hasPriorToolResult` for each request. +- **Pi's extra tests** can be copied almost directly: + - one model request on a structured turn; + - no result tool offered on a plain turn; + - a rogue result-tool call is blocked and kept out of the stream; + - quoted earlier chat does not enable the tool; + - host `AGENTS.md` isolation; + - an unknown model fails with no model request. +- **Stub caveat (seen in the spike):** `hasPriorToolResult` scans the whole history. An Atomic session keeps multi-turn history, so any later turn in a session that already made a tool call gets `"Done."`. Each contract case uses a fresh `HarnessAgent` session, so that is fine. Multi-turn unit tests need a fresh session per scenario or a stub keyed differently. + +### Pi's result-tool approach — `apps/server/src/harness/pi/adapter.ts` + +- `piResultToolExtension(state)` (lines 53-80): + - registers a `Type.Object({}, {additionalProperties:true})` tool that returns `terminate: true`; + - on `before_agent_start`, adds or removes the tool from the active set based on `state.structured`; + - on `tool_call`, blocks the tool when the turn is not structured. +- `runOutputTurn` (lines 106-191): + - reserves the result tool's name; + - hides the result tool's parts; + - in JSON mode drops prose, reasoning and inner `finish-step`s; + - on `finish`, emits `text-start`/`text-delta`/`text-end` with the JSON and one synthetic `finish-step`; + - rejects `done` when no result or an invalid result arrived. +- The extension is typed against Pi's `ExtensionAPI` from `@earendil-works/pi-coding-agent`. Atomic's `ExtensionAPI` has the same members (`registerTool`, `on("before_agent_start")`, `on("tool_call")`, `getActiveTools`, `setActiveTools`) but they are different TypeScript types (`dist/core/extensions/api-types.d.ts:54,71,77,146,150`). +- Recommendation: write an Atomic-typed twin of the extension, or share only the name, instruction text and stream-suppression helpers. Forcing one generic type over two different overload sets is likely to fight `tsgo`. + +### Copilot reference — `apps/server/src/harness/copilot-sdk/adapter.ts` + +- **Host tools** (lines 180-212): the handler emits `tool-call`, parks a resolver keyed by `toolCallId`, then on `submitToolResult` emits `tool-result` and throws when `isError` is set. +- **Terminal result tool** (lines 214-231): it emits the JSON as text. +- **Fail-closed check** (lines 107-138): `assertHostOnly` compares live tool metadata with exactly the host names and logs `[agent] N tools: …`. AGENTS.md "Diagnostics" expects this kind of log. +- **Abort** (lines 435-447): resolves every pending tool with an error, then settles. +- **Unsupported methods** (lines 472-476): continue, suspend, detach and stop throw `HarnessCapabilityUnsupportedError`. Criterion 1 requires the Atomic adapter to go further; see §3. +- **Defaults:** `builtinTools: {}` and `supportsBuiltinToolFiltering: true` (lines 279-280). The Atomic adapter should declare the same. + +### How Chopin uses harnesses (subagent report, spot-checked) + +- **Planner:** `service.ts:891-901` and `session.ts` open **one HarnessAgent session per chat turn** and destroy it in `finally` (I read `service.ts:1020-1060`). +- **Workers:** + - The summary worker runs **several `generate` turns on one worker session** with `output` (I read `document-summary.ts:225-260`). + - Research workers use `structuredAgent`, which has `output` plus an optional `web_search` host tool (`agents.ts:94-125`). + - So the Atomic adapter must support multi-turn sessions and a host-tool round trip inside a structured turn. +- **`translate()`** (`chat/service.ts` ~1156-1272): + - a `tool-call` outside `PLANNER_TOOL_NAMES` aborts the turn with a boundary failure; + - `tool-approval-request` aborts; + - `error` parts are posted to chat. +- Nothing in Chopin calls `continueStream`, `stop`, `detach` or `doCompact` in production (grep of `apps/server/src`). Continue and stop are required only by the contract. +- **`config.ts:49-58`:** `DEFAULT_MODEL = "gpt-6-luna"`, and `MODEL` is required only for `HARNESS=pi`. In the spike, Atomic's catalog contains `github-copilot/gpt-6-luna`, but a bare `gpt-6-luna` has no provider. Mirroring the Pi rule for `atomic` is my proposal; it is not a contract clause. + +### Packages + +- The root `package.json` `catalogs.harness` has no `@bastani/atomic`. Add `"@bastani/atomic": "0.9.23"` there and `"@bastani/atomic": "catalog:harness"` in `apps/server/package.json`. +- `bun.lock` has no `@bastani` entries. `node_modules/.bun/@bastani+atomic@0.9.20-alpha.5` is stale, left over from an older branch; the lockfile will be regenerated. +- `npm view` confirms `latest = 0.9.23`, published 2026-09-27. It depends on `typebox 1.3.27`, while Chopin's catalog pins `1.3.7`. TypeBox's `TSchema` is an empty interface (`typebox/build/type/types/schema.d.mts:1`), so the mismatch should be type-compatible, but that is unverified in `tsgo`. +- The package is 41 MB unpacked, with heavy dependencies: `embedded-postgres`, `@dbos-inc/dbos-sdk`, `pg`, platform natives for linux-x64/arm64 gnu/musl, darwin and win32. There is no `postinstall`. Expect a noticeably larger Docker image; the `oven/bun` Debian base should use the gnu natives. + +### Lint and format + +- `.oxlintrc.json` restricts `@github/copilot-sdk` imports to `harness/copilot-sdk/`. A matching restriction for `@bastani/atomic` to `harness/atomic/` would follow convention; that is my proposal, not a requirement. +- `dprint.json` sets tabs, width 100 and double quotes. +- `bun run ci` runs `dprint check && oxlint && bun scripts/check-tokens.ts`; the token check only inspects CSS. + +### History + +- Branch `backup/main-before-atomic-rewind` (commit `49419cf`) holds an earlier Atomic SDK backend, from before the move to the `HarnessAgent` architecture: + - `apps/server/src/agent/atomic.ts` and `events.ts`; + - an inert custom `ResourceLoader`, `builtins` all false, an `AMBIENT` tool denylist; + - `resolveAtomicModel` built on `runtime.getModel`; + - an `abortEpoch` guard so an abort is not reported as a provider error. + It is useful prior art, but it was written against 0.9.20-alpha.5 and a Copilot-shaped event bridge. +- Relevant `User-preference` trailers: + - "Prefer an upstream-supported extension point over working around third-party adapter races" (`a3ab603`); + - "Patch pinned dependencies with bun patch when the upstream adapter exposes no option for a needed safety fix" (`c9d8a9f`); + - "Record third-party harness limitations as documented caveats rather than patching dependencies" (`2c83ef3`). +- Trailers are formatted as in `0943098` and `45889b6`: `Assistant-model`, `Assistant-workflow`, one `Assistant-verification: : ` per check, and `Co-authored-by: Alex Lavaee `. +- Comparable harness-adapter durations from the `harness-stack` records: 95m (Pi admit), 92m, 70m, 61m, 30m, 28m (blocked). The median is about 65m over 6 records. Most ran over their estimates. + +--- + +## 2. Atomic SDK 0.9.23 facts + +Paths are under `/home/alexlavaee/.bun/install/global/node_modules/@bastani/atomic/dist/`. + +### Session assembly — `core/sdk.js`, `core/sdk-types.d.ts` + +- **`builtins`:** + - Shipped packages are on unless a key is explicitly `false` (`sdk-types.d.ts:11-14`). + - A custom `resourceLoader` is wrapped in `BuiltinResourceLoader`, which adds the shipped packages whatever the loader's `no*` flags say (`sdk.js:161-164`). + - Intercom is **mandatory**: it is added by `withMandatoryResourceLoader` unless `builtins.intercom === false` (`sdk.js:165-167`, `mandatory-resource-loader.js:11-27`). + - Spike ("loose" mode, with the tools allowlist but default builtins): the active tools stayed limited to the allowlist, but all five builtin extension bundles loaded and ran their startup code, and the run was much slower. So all five keys must be `false`; an allowlist alone is not enough. +- **Tools** (`sdk.js:238-243`, `agent-session-tool-registry.js:17-37,80-85`): + - `tools` omitted: the default coding tools are active, plus every extension tool. Spike "notools" mode listed read, bash, kill, edit, write, find, search, ask_user_question, todo, workflow, subagent, web_search, code_search, fetch_content, get_search_content, intercom and mcp. + - `tools: [...]`: only the named tools are even registered, and **both custom and extension tools must be named**. Every registered allowed tool is re-activated whenever the registry refreshes. + - `noTools: "all"` exposes nothing. + - A custom tool named `intercom` is dropped. +- **Model:** there is no lookup when `model` is passed. When it is `undefined`, `findInitialModel` silently picks a preferred or first-available model (`sdk.js:182-211`). + - Spike: `runtime.getModel("stub","nope")` returned `undefined`. Passing that through produced a session on `stub/stub-model` with `modelFallbackMessage: undefined`. +- **Defaults to override:** + - `fallbackModels` defaults to `settings.fallbackModels`. `SettingsManager.inMemory` makes that `[]`; pass `fallbackModels: []` explicitly anyway. + - `agentDir` defaults to `$ATOMIC_CODING_AGENT_DIR` → `$PI_CODING_AGENT_DIR` → `~/.atomic/agent`. + - Creation always calls `modelRuntime.refresh({allowNetwork:false})`. +- **`systemPromptTransform`** exists but applies only at construction. +- **`createStructuredOutputTool`** runs a second `streamSimple` request (`core/tools/structured-output.js:60-71`). Do not use it; criterion 4 forbids it. + +### Resource loader — `core/resource-loader-reload.js`, `resource-loader-types.d.ts:113-167` + +- The flags `noExtensions`, `noSkills`, `noPromptTemplates`, `noThemes` and `noContextFiles` gate discovery (`reload.js:204-211, 224, 259-261, 276-278, 297-299, 314-322`). +- `additional*Paths` and CLI paths still load when the flags are set. Leave them empty. +- `extensionFactories` load even with `noExtensions`. +- `SYSTEM.md` and `APPEND_SYSTEM.md` are discovered unless `systemPrompt` or `appendSystemPrompt` is given (`reload.js:329-341`). Pass `appendSystemPrompt: []`. +- **Empty system prompt trap:** `systemPrompt: ""` is not nullish, so discovery is skipped, but `buildSystemPromptSections` treats `""` as missing (`system-prompt.js:105-115`). The result is Atomic's default preamble: "expert coding assistant…", the tools list, the guidelines, and an "Atomic documentation" section. + - Spike with `SPIKE_SP=""`: "Atomic documentation" and "expert coding assistant" were both present. + - HarnessAgent turns with no `instructions`, including all three shared contract cases, hit this unless the adapter forces the prompt. +- Even with a custom prompt, Atomic adds ``, `` and `` sections (`system-prompt.js:139-141`). +- **Forcing the prompt:** a `before_agent_start` handler that returns `{systemPrompt}` sets `forceSystemPrompt` (`extensions/runner-events.js:324`). Spike: the model received exactly `"FORCED-TURN-PROMPT"` on every turn. This is the upstream-supported hook for per-turn instructions without reloading resources. + +### Isolation checked in the spike + +- **Setup:** a temporary `HOME` containing `~/.atomic/agent/{AGENTS.md, SYSTEM.md, APPEND_SYSTEM.md, settings.json (defaultTools, fallbackModels), extensions/evil.ts, skills/, prompts/}`, `~/.pi/agent/AGENTS.md` and `~/.agents/skills`. The working directory held `AGENTS.md`, `CLAUDE.md`, `.atomic/extensions`, `.pi/extensions` and `.agents/skills`. +- **Configuration:** `DefaultResourceLoader` with all `no*` flags, `systemPrompt`, `appendSystemPrompt: []` and one inline factory; `SettingsManager.inMemory`; `SessionManager.inMemory(cwd)`; all five builtins `false`; `tools: [host, RESULT]`. +- **Results:** + - The only extension was ``. + - Active and registered tools were exactly the host tool and the result tool. + - No marker text reached the system prompt the stub received. + - **No files were created or modified under the temporary `HOME` or cwd** (`find -newer marker` was empty). + +### Events — spike traces + +| Scenario | Event sequence | +| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Plain turn | `agent_start turn_start message_start/end:system message_start/end:user message_start:assistant message_update:text_start/text_delta/text_end message_end:assistant:stop turn_end agent_end agent_settled` | +| Host tool | `…message_update:toolcall_start/delta/end message_end:assistant:toolUse tool_execution_start:host_a tool_execution_end:host_a message_start/end:toolResult turn_end turn_start …text… agent_end` — two model requests | +| Terminating tool | one model request; `tool_execution_*:RESULT`, then `agent_end` with no second assistant message; the last message is a `toolResult` | +| Blocked result tool on a plain turn | `tool_execution_start/end:RESULT:err`, then the model continues — these parts must be kept out of the stream | +| Hallucinated `bash` | `tool_execution_start/end:bash:err`, "tool not found" handled inside Atomic | +| Abort | `prompt()` **resolved** without throwing; `agent.state.errorMessage = "Request aborted"`; last assistant `stopReason: "aborted"`; `agent_end` still fires | + +- **Abort during a pending host tool:** + - If `execute` honours `signal`, abort settles in about 200 ms with `errorMessage "The operation was aborted."` and `tool_execution_end:err`. + - If `execute` ignores `signal`, **`abort()` and `prompt()` hang** (killed by a 20 s timeout). +- **Other facts:** + - `AgentToolResult` has no `isError`. A throw from `execute` becomes `isError`. + - `tool_call` handler errors **block** execution, which fails closed (`agent-session-tool-hooks.js:13-33`). + - `before_agent_start` handler errors are only reported through `emitError` and **do not fail the turn** (`extensions/runner.js:655`). Fail-closed checks therefore belong in the adapter, not in a throwing hook. +- **Other prompt paths:** + - `prompt()` runs `/…` text as an extension command, and expands skill and template syntax, unless `expandPromptTemplates: false` (`agent-session-prompt.js:93-103, 143-147`). Pass `false`. + - Missing auth throws before any request (`agent-session-prompt.js:187-200`). +- **Oversized results:** results over `DEFAULT_MAX_RESULT_SIZE_CHARS = 50_000` (`core/tools/tool-limits.js:17`) are persisted to a session temp directory. An in-memory `SessionManager` has an empty session dir, so the OS temp dir is used. The model then receives a preview and a path it cannot read (`agent-session-tool-hooks.js:69`, `tools/oversized-tool-result.js:276-313`). Setting `maxResultSizeChars: Infinity` on host `ToolDefinition`s opts out. + +### Settings defaults that matter (`core/settings-manager-basic-accessors.js`) + +| Setting | Default | Effect | +| ------------------------ | ----------------- | --------------------------------------------- | +| `compaction.enabled` | `true` | Extra summarization model calls | +| `retry.enabled` | `true`, 3 retries | Automatic retries | +| `cacheWarming` | `"streaming"` | Extra cache-refresh requests to the provider | +| `sessionSummary.enabled` | `true` | Skipped in SDK "print" mode, per the subagent | + +Suggested in-memory settings: `{ compaction: {enabled:false}, cacheWarming: "off", sessionSummary: {enabled:false} }`, plus explicit `fallbackModels: []`. Keeping `retry` on is a judgement call. + +### Auth — `core/model-runtime.js:86-117`, `core/auth-storage*.js`, `@bastani/pi-ai/dist/env-api-keys.js` + +- `ModelRuntime.create({ credentials?, authPath?, modelsPath?: string|null, refreshOnCreate?, allowModelNetwork? })` has no `providers` option. Register custom providers with `runtime.registerProvider(id, {baseUrl, apiKey, api:"openai-completions", models:[…]})`; this worked in the spike. +- **Default credentials** are file-backed and layered: `~/.atomic/agent/auth.json` and `~/.pi/agent/auth.json`. `FileAuthStorageBackend.withLock` makes the parent directory. OAuth and key updates write `auth.json` atomically (`auth-storage.js:30-122`, `auth-storage-backends.js:20-80`). `readStoredCredential` also goes through `withLock`. +- **`AuthStorage.inMemory(data)`** never touches disk. `modelsPath: null` avoids `models.json` and `models-store.json`. +- **Environment keys still resolve with in-memory credentials.** Spike with `ANTHROPIC_API_KEY=dummy` and `AI_GATEWAY_API_KEY=dummy2`: `hasConfiguredAuth("anthropic")` and `("vercel-ai-gateway")` were true; without them both were false. +- pi-ai also treats ambient **AWS profile/IAM** credentials (for `amazon-bedrock`) and **gcloud ADC** at `~/.config/gcloud/…` (for `google-vertex`) as configured auth. Those are host-logged-in cloud credentials even in an "env-only" mode. +- `ReadOnlyAuthStorage` exists (`auth-storage.js:123`) but is **not exported** from the package root. `getAgentConfigPaths` and `AuthStorage` are exported (`index.d.ts:14,16`). +- The Harness auth vocabulary is `HarnessV1Authentication = 'auto' | 'ai-gateway' | C | Record` (`@ai-sdk/harness/src/v1/harness-authentication.ts:15-24`). + +--- + +## 3. Implementation guidance + +These are proposals. Where the contract does not fix a choice, it is marked **(decision)**. + +### Files + +- `apps/server/src/harness/atomic/adapter.ts`: `createAtomicAdapter(settings)` returning `HarnessV1 & { shutdown(): Promise }`, with `harnessId: "atomic"`, `builtinTools: {}` and `supportsBuiltinToolFiltering: true`. +- An optional `apps/server/src/harness/atomic/auth.ts` for mode handling. +- `apps/server/src/harness/atomic/adapter.test.ts`. +- `apps/server/src/harness/atomic.contract.test.ts`, importing `../pi/model-stub` or `./pi/model-stub`. +- `harnesses.ts`: `atomic: createAtomicHarness`, forwarding only `auth`, plus an `atomic` branch in `harnessFor`. Also update `harnesses.test.ts`. +- `package.json` catalog and `apps/server/package.json`; regenerate `bun.lock`. +- Optional: `config.ts` and `config.test.ts` to require `MODEL` for `atomic`; an `.oxlintrc.json` import restriction. + +### Session creation + +- Create the Atomic session lazily on the first turn, or in `doStart`. Each HarnessV1 session owns one `AgentSession`. +- Options: + - `cwd`: a fresh `mkdtemp` directory removed in `doDestroy`. Do not use the sandbox's virtual `sessionWorkDir` or `process.cwd()`. + - `agentDir`: that same empty temp directory. + - `modelRuntime`: built per the auth mode. + - `model`: the resolved model; `thinkingLevel: "off"` or a setting **(decision)**. + - `fallbackModels: []`. + - `sessionManager: SessionManager.inMemory(cwd)`; `settingsManager: SettingsManager.inMemory({...})` per §2. + - `builtins: { workflows:false, subagents:false, mcp:false, "web-access":false, intercom:false }`. + - `tools: [...hostNames, RESULT_TOOL]`. + - `customTools`: host tools defined with `defineTool`, `Type.Unsafe(spec.inputSchema ?? {type:"object"})` and `maxResultSizeChars: Infinity`. +- The loader is `new DefaultResourceLoader({ cwd, agentDir, settingsManager: SettingsManager.inMemory({}), noExtensions, noSkills, noPromptTemplates, noThemes, noContextFiles: true, systemPrompt: , appendSystemPrompt: [], extensionFactories: [resultToolExtension(state)] })`. +- **Rebuild or refuse** **(decision):** if a later turn changes the host tool set, the session must be rebuilt, because only allowlisted tools are registered. Pi rebuilds on a tool-signature change; Copilot uses a fresh session per turn. Model changes can use `session.setModel` after checking. + +### Fail-closed checks + +Before every `prompt()`, and throw before any model request if a check fails: + +- `created.extensionsResult.extensions` must be exactly the one inline factory. +- The names from `session.getAllTools()` must equal `host ∪ {RESULT}`. +- After `setActiveToolsByName(expected)`, `getActiveToolNames()` must equal `expected`, where `expected = structured ? [...host, RESULT] : host`. +- `session.model` must match the requested provider and id. +- Log `[agent] N tools: …` like Copilot does. + +During the turn: treat `tool_execution_start` for a name outside `host ∪ {RESULT}` as a boundary event. **(decision):** either abort with an `error` part, or let Atomic's "tool not found" stand and never emit it. The spike shows Atomic already refuses unknown names without running anything, and emitting it would make `chat/service.ts` abort the turn anyway. + +### Per-turn prompt and structured output + +- The result extension, following `piResultToolExtension`, uses `on("before_agent_start")` to: + 1. `setActiveTools(expected)`; + 2. return `{ systemPrompt: }`. +- `on("tool_call")` blocks `RESULT` unless `state.structured`. +- The adapter sets `state.structured` from `turn.responseFormat?.type === "json"`, never from prompt text. It reserves the `RESULT` name against host tools, as Pi and Copilot do. +- `RESULT.execute(id, params)` captures `params` in adapter state and returns `terminate: true`. +- On `agent_end`, if a result was captured, emit `text-start`/`text-delta(JSON.stringify(params))`/`text-end`, then `finish-step` and `finish`. If not, reject `done` with "Atomic turn ended without a structured result." +- In JSON mode, drop prose and reasoning, as both existing adapters do. +- The spike confirmed one model request for a structured turn. Keep the Pi-style result-tool schema, `Type.Object({}, {additionalProperties:true})` with the schema written into the instruction, or use `Type.Unsafe(responseFormat.schema)` with a rebuild when the schema changes **(decision)**. Either way HarnessAgent validates host-side. +- Workers need a `web_search` round trip inside a structured turn to keep working. The name `web_search` no longer collides with anything once `web-access` is off. + +### Stream translation (only what `translate()` and HarnessAgent consume) + +- `message_update` with `text_start`/`text_delta`/`text_end` on assistant messages maps to `text-start`/`text-delta`/`text-end` with a stable id per content block. `thinking_*` maps to `reasoning-*` (optional). Ignore `system`, `user` and `toolResult` messages. +- **Host tool round trip:** inside `execute`: + 1. emit `tool-call {toolCallId, toolName, input: JSON.stringify(params)}`; + 2. park a resolver, and race it against `signal`, **mandatory** per the spike; + 3. on `submitToolResult`, emit `tool-result {…, result, isError}`; + 4. return `{content:[{type:"text", text: serialize(output)}]}`, or throw when `isError`. + Never emit parts for `RESULT` or for blocked or unknown tools. +- At the end of `prompt()`, inspect the last assistant message: + - `stopReason: "aborted"`, or the abort signal is set: settle quietly or with an abort error. The HarnessAgent `settleFailure` path turns it into an `abort` part, and `hasUnfinishedTurn` is false. + - `stopReason: "error"` or `agent.state.errorMessage` set: emit an `error` part and reject `done`. + - Otherwise emit `finish-step` and `finish` with `stop`. Usage can come from the assistant message's `usage` or be zeroed as Copilot does. + - `prompt()` preflight throws, such as missing auth, reject `done`. +- **Abort:** + - `turn.abortSignal` calls `session.abort()`; + - settle every pending resolver with an error; + - bound the wait as Copilot's `bounded()` does; + - ignore late `submitToolResult` calls. + +### Remaining lifecycle + +- **`doContinueTurn`:** the in-process equivalent of Pi's live-turn path (§4): if a turn is active, re-point `emit` and return the live control. Otherwise **(decision)**: throw `HarnessCapabilityUnsupportedError`, or run `session.agent.continue()`. `agent` is reachable, but `continue()` is not part of the public session surface. +- **`doStop` / `doDetach`:** tear down and return `{type:"resume-session", harnessId:"atomic", specificationVersion:"harness-v1", data:{}}`, with `isResume: false`. The in-memory session cannot resume across processes, so document that as a caveat. +- **`doSuspendTurn`:** a lossy `continue-turn` or unsupported **(decision)**. +- **`doCompact`:** unsupported, since compaction is off. +- **`doDestroy`:** idempotent — abort, settle pending tools, `session.dispose()`, remove the temp dir. +- **`shutdown()`:** dispose live sessions or no-op. There is no global Atomic runtime unless one shared `ModelRuntime` is kept. +- **`skills`:** Chopin always passes `[]`. Rejecting non-empty skills keeps the "no skills" guarantee explicit **(decision)**. + +### `HARNESS_AUTH` for `atomic` (decision; evidence above) + +Proposal, following the Pi pattern and the `HarnessV1Authentication` vocabulary. `HARNESS_AUTH` is required; unknown values are refused. + +| Mode | Credentials | Allowed bind | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `auto` | A snapshot of the host Atomic login loaded into `AuthStorage.inMemory(...)` — not the file-backed store, so a refresh cannot write to disk — plus environment keys | Loopback only | +| `ai-gateway` | `AuthStorage.inMemory()`, `modelsPath: null`, `AI_GATEWAY_API_KEY`; resolved models should be restricted to provider `vercel-ai-gateway`, because other env keys and ambient AWS/GCP credentials would otherwise be picked up | Any | +| env-key mode (optional, e.g. `direct`) | In-memory credentials with named provider environment keys | Any only if `amazon-bedrock`/`google-vertex` ambient credentials are refused; otherwise loopback | + +- Reading the host login snapshot without writes means reading the JSON from `getAgentConfigPaths("auth.json")` yourself. `AuthStorage.create` and `readStoredCredential` go through `withLock`: that makes a directory and a lock file but writes no credentials. +- Refresh-token rotation that stays in memory may invalidate the host CLI's stored refresh token. Record that as a caveat. +- `api_key` entries using `!command` run a shell command when resolved. Caveat for `auto`. + +### Model resolution (criterion 3) + +- Take `turn.model`, falling back to an adapter `settings.model` for tests. +- Require `provider/id` and call `runtime.getModel(provider, id)`. If it is missing, throw `Atomic does not recognize model ` **before** any request, matching Pi's wording. +- Never pass `undefined` to `createAgentSession`, because that is exactly the silent fallback. +- When no model is given at all: fail **(decision)**. The contract suite needs the stub adapter to set a default model. + +--- + +## 4. Testing and verification + +### `atomic.contract.test.ts` + +- Stub script: + - `"tools"` → a call to `first_host`, then `"Done."`; + - `"output"`/`"rogue"` → a call to `RESULT` with `{"answer":"yes"}`; + - `"abort"` → hold; + - anything else → text. +- Adapter setup: `auth` set to an isolated in-memory configuration, plus a registered `stub` provider (`apiKey:"stub-key"`, `api:"openai-completions"`) and `model: "stub/stub-model"`. +- Cases: + - `harnessContract("atomic", …, createJustBashNetworkSandboxSession)`; + - a plain text turn; + - a host round trip, asserting two requests with `hasPriorToolResult` `[false, true]` and `tool-call`/`tool-result` for `first_host`; + - one request for a structured turn, with `RESULT` offered; + - `RESULT` not offered on a plain turn; + - rogue `RESULT` blocked and hidden; + - quoted instruction text does not enable `RESULT`; + - host `AGENTS.md`, `SYSTEM.md`, `APPEND_SYSTEM.md` and skills stay out of the `system` the stub saw, using a temporary cwd or `HOME` and agent dir; + - an unknown model rejects with zero stub requests; + - the tool boundary: the active and registered tool names equal the host tools, and the system prompt contains no "Atomic documentation" or "expert coding assistant" text on a turn without instructions; + - abort during a pending host tool completes. + +### `atomic/adapter.test.ts` + +Unit tests in the style of `pi/adapter.test.ts`, using a fake extension API or a fake session: + +- result-tool state switching; +- the stream-suppression helper; +- `done` rejections: no result, invalid result, error `stopReason`; +- the reserved result-tool name; +- the auth-mode and settings mapping. + +### `harnesses.test.ts` + +- the map keys include `atomic`; +- missing, unknown and loopback cases for each Atomic mode. + +### Gates + +Run in this order, recording one `Assistant-verification` line per command: + +1. `bun run fix`, then inspect the diff; +2. `bun test`, with `bun test apps/server/src/harness` first for speed; +3. `bun run types`; +4. `bun run ci`. + +Past records show about 1,566 passing tests plus 2 PostgreSQL skips as the baseline. E2E is not required, but the Docker job in CI will pick up the larger dependency tree; `docker build` locally is optional. + +--- + +## 5. Documentation to update + +- **`docs/hosted-agent.md`:** + - lines 13-19: the harness list; + - lines 21-36: ownership — under `atomic`, the owner supplies only the GitHub token and model access comes from `HARNESS_AUTH`; + - lines 46-67: runtime isolation — builtins off, inert loader, forced system prompt, fail-closed tool check; + - the code map near line 209. +- **`docs/self-hosting.md`:** + - lines 56-122, "Choose and trust a harness": the Atomic auth modes and loopback rule, `MODEL` as `provider/id`, the result tool, caveats; + - line 131 onward: prerequisites; + - the environment table rows for `MODEL`, `HARNESS`, `HARNESS_AUTH` and `SERVER_HOST`; + - the sample environment and startup checks. +- **Also:** `.env.example` lines 5-17, `docs/architecture.md` (lines 6, 36, 56, 112-124, 473-477 name "Copilot or Pi"), and `README.md` lines 73-84 and 104. +- **AGENTS.md** does not list harnesses by name. The "Harness and Planner" failure traps (lines 280-299) should gain an Atomic entry: the empty-prompt preamble, abort-signal hangs, and `prompt()` resolving on abort. + +**Atomic caveats to document:** + +- the silent model fallback, which the adapter guards; +- the default coding-agent preamble when no prompt is given; +- the mandatory Intercom unless disabled; +- the 50 KB tool-result spill to temp files; +- environment and ambient cloud credentials are read even in isolated mode; +- `auto` refresh stays in memory and can rotate the host token; +- no resume across processes; +- no Copilot-style per-session credit limit, so workers' `maxAiCredits` is ignored; +- the package size; +- `typebox` 1.3.7 vs 1.3.27. + +## 6. Open items and limits + +- I did not verify `tsgo` compatibility of Chopin's `typebox` 1.3.7 schemas with Atomic's `ToolDefinition`, or that `bun install` resolves 0.9.23 cleanly in this workspace. +- I did not trace the exact OAuth refresh call site that writes `auth.json` in the file-backed mode. +- I did not observe how HarnessAgent reacts to a `tool-call` emitted from inside `execute` while other parallel calls in the same batch are pending. Atomic schedules "shared" tool calls concurrently; add a test with two host calls in one message. +- I did not test `session.agent.continue()` for `doContinueTurn`. +- I did not write the research-codebase skill's `research/docs/` file, to keep the repository untouched for the implementation commit. This message is the artifact. From 2fe6d9af0c845bdcf76120c13120bc4160458b91 Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Mon, 28 Sep 2026 13:57:49 -0700 Subject: [PATCH 3/6] Name the legacy Pi agent directory for Atomic auto auth Atomic reads PI_CODING_AGENT_DIR when ATOMIC_CODING_AGENT_DIR is unset, so the auto-mode auth.json lookup lists both variables in precedence order. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: source check passed: @bastani/atomic 0.9.23 dist/config.js getEnvValue prefers ATOMIC_CODING_AGENT_DIR, then PI_CODING_AGENT_DIR, and a set variable disables the ~/.pi fallback Assistant-verification: dprint ci passed: bun run ci Co-authored-by: Alex Lavaee --- docs/self-hosting.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/self-hosting.md b/docs/self-hosting.md index e51eb5bd..248c0b53 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -127,7 +127,8 @@ enforces. - `auto` copies the host operator's Atomic login into memory when the first turn starts: `$ATOMIC_CODING_AGENT_DIR/auth.json` when that variable is set, - otherwise `~/.atomic/agent/auth.json` over the legacy `~/.pi/agent/auth.json`. + then `$PI_CODING_AGENT_DIR/auth.json` for the legacy variable, otherwise + `~/.atomic/agent/auth.json` over the legacy `~/.pi/agent/auth.json`. It also resolves provider keys from the process environment, such as `ANTHROPIC_API_KEY`, and ambient cloud credentials, such as an AWS profile or Google application default credentials. Because every admitted writer's turns From 1105347ebe8214601700522c4bc2f5fb9832a515 Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Mon, 28 Sep 2026 22:44:15 -0700 Subject: [PATCH 4/6] Upgrade the Atomic harness to 0.9.24-alpha.1 The release keeps the same five builtin packages, so BUILTINS_OFF still covers every one and the Planner session stays isolated to Chopin's host tools. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: bun test passed: 1688 pass, 2 PostgreSQL skips, 0 fail, including the atomic contract and isolation suites Assistant-verification: bun run types passed: all workspaces and E2E Assistant-verification: bun run ci passed: dprint, oxlint, tokens, type scale, Impeccable baseline Assistant-verification: source check passed: @bastani/atomic 0.9.24-alpha.1 dist/builtin lists intercom, mcp, subagents, web-access, workflows, matching BUILTINS_OFF Co-authored-by: Alex Lavaee --- bun.lock | 30 +++++++++++++++++------------- docs/self-hosting.md | 2 +- package.json | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/bun.lock b/bun.lock index ccdb8191..9b28a173 100644 --- a/bun.lock +++ b/bun.lock @@ -230,7 +230,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", - "@bastani/atomic": "0.9.23", + "@bastani/atomic": "0.9.24-alpha.1", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7", @@ -382,27 +382,27 @@ "@base-ui/utils": ["@base-ui/utils@0.3.2", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.12", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ=="], - "@bastani/atomic": ["@bastani/atomic@0.9.23", "", { "dependencies": { "@bastani/atomic-natives": "0.9.23", "@bastani/pi-ai": "0.9.23", "@dbos-inc/dbos-sdk": "4.25.14", "@earendil-works/pi-agent-core": "0.87.1", "@earendil-works/pi-client": "0.87.1", "@earendil-works/pi-protocol": "0.87.1", "@earendil-works/pi-tui": "0.87.1", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.6.0", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "embedded-postgres": "18.4.0-beta.17", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "pg": "8.22.0", "proper-lockfile": "4.1.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-h859zFfHSrxDZMalN0+6mkIcR0dXm99koTTkX7zYjj0Sdkl0uHyQZKsh7Eqqn7BIIJRxVqqRaejOhKjxqlaSlQ=="], + "@bastani/atomic": ["@bastani/atomic@0.9.24-alpha.1", "", { "dependencies": { "@bastani/atomic-natives": "0.9.24-alpha.1", "@bastani/pi-ai": "0.9.24-alpha.1", "@dbos-inc/dbos-sdk": "4.25.14", "@earendil-works/pi-agent-core": "0.87.1", "@earendil-works/pi-client": "0.87.1", "@earendil-works/pi-protocol": "0.87.1", "@earendil-works/pi-tui": "0.87.1", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.6.0", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "embedded-postgres": "18.4.0-beta.17", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "pg": "8.23.0", "proper-lockfile": "4.1.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-KYrHqDsUEhyZ8rXg3kvWPeV8X44/Gf7W/cIXXP3q3K27MmKNyqiQ8F2y0ssDvY4y4ZjMxzUv52HledSnsFTq2w=="], - "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.23", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.23", "@bastani/atomic-natives-darwin-x64": "0.9.23", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.23", "@bastani/atomic-natives-linux-arm64-musl": "0.9.23", "@bastani/atomic-natives-linux-x64-gnu": "0.9.23", "@bastani/atomic-natives-linux-x64-musl": "0.9.23", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.23", "@bastani/atomic-natives-win32-x64-msvc": "0.9.23" } }, "sha512-zd4w/nEIc0hDlZWkmCCncG7/befEHtXo4uxIXNVNlKzTzdAgdUdq6VcMutvVsXK8v2kMGvHNdLkQO6hF/l050Q=="], + "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.24-alpha.1", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.24-alpha.1", "@bastani/atomic-natives-darwin-x64": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-arm64-musl": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-x64-gnu": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-x64-musl": "0.9.24-alpha.1", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.24-alpha.1", "@bastani/atomic-natives-win32-x64-msvc": "0.9.24-alpha.1" } }, "sha512-jaQHzlzBcFoyVR5jj+bpaKgoCz8BzrfeISk+PExXHUjGHpUH98M9VtTErk6ytRogV1YP8Z53jdobqpX87Gi95g=="], - "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v0PjvsXlWEn4nTaVjJ/TvMHg0hRJlNPkQ6ET+kcVP/m8IHLfzqa0w9pFKVV6Ez0lymQwQbFr2OUbe4zEBf7jvw=="], + "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.24-alpha.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hntKcTgjFHDzotDSu8czfI3XL0rjv8ZTmmGRqaJhGDbW7VKpIkZ5khOEl/A86Uu89tsT09Kw9M1WZxO1YalzJw=="], - "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-lOK1Eq0WQSj/PKesTayqdr1e/aOfE/vth81yvUfdt2AyI4QyrTJuVV4q72jBWEVhkLhhy4ql/6rDwEYGby5QVA=="], + "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.24-alpha.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/LC/wALhgmj/Xuf9IFW+R4OZLrQqwBUlHHmd9cH/3KQsSXUS1jeAL+cd5BwmPAP9ugRxGHP4GodP5JnnFhi61A=="], - "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-fZ6qz1FvALylPrQCtuMEn0jH1PRLywpvdSPXEqMqFRFx7ST1DFjatSUBHNb3pv0nj52jDDTVOLZUCmjECSv2MQ=="], + "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.24-alpha.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-3g0gt/oXQsNKIC0IaQlJwCP86xiXi76lIl6McxpoNM1vHX+o5BOCIX0Ah6qtdlsSc2iuafImWy9FRqFRwTbzCA=="], - "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-cxAraZvtxuzi+qB8stflP/v5F0zOo7kFcbrYbzPRHS+uL6Uc+gAVeLJYsrTaWuTH+aN6HVpwXn+Q+4F8KU6l1Q=="], + "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.24-alpha.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-3rJDvT9chlGTSuLLOT/pSFrYbmv+UmTMUu1NOi16nHz9UyoCZiida9EGyzkSVByt9Py+RnqXaCk+Yr2iW4jn8w=="], - "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.23", "", { "os": "linux", "cpu": "x64" }, "sha512-7gwkDf4PCVEi2pRPIouxcFSdNnwACd5U1lvNle8/V2utcGRz/NlKnqxG+Ic8jYUafyzPgpS9xshUQoDIVo1KSw=="], + "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.24-alpha.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eyd7fc1oQPZLIF1eJwvf73QsgAcAYtXfJ1VoE1fOPcP3jWWRusbItuBi2lFWMSP/8jacQDxDJh0jWsh3pyEuyg=="], - "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.23", "", { "os": "linux", "cpu": "x64" }, "sha512-/KUQPXbVKJ1/jWQ9BjN0LqZE8j4rsIIZKHwy6LEpJ83eoHOwjJsHf9o2LPTRl3cEHHPECxME21ySJ/TTl1PIuw=="], + "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.24-alpha.1", "", { "os": "linux", "cpu": "x64" }, "sha512-45AKuQIx7jWDAN5YpJLiiFg/eH6pkZ12SRs8kBDOhHfE8BBnJM+Cgs40CS61uoY1Z4VqDx+yHrQ0e33euUVaqw=="], - "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ha0u9yelInx7F/5HKXArjLRWbKCqJDvx+Zl30JSTZoikL4GNKmZbVzrD20ZKT9N7XMZezbAb3SzElmeFElU82Q=="], + "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.24-alpha.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-plfCBL5uaNEHH/LKlu7dc+DAA8uoh1PUvOUGopOgaP1pWeJAjGurB09zy1wCTBboHzaIAPT3GIF6wPyFBVDVlw=="], - "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.23", "", { "os": "win32", "cpu": "x64" }, "sha512-YMsQXBj5KHTK+dDwuTTzoQyi1kmKGEBlP8HMZeQ746CJZuoC8ekw2yzM5xogwudPEJw6KBtbqmO9lw0B7y0VXA=="], + "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.24-alpha.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ODEXhle6rXJiBSH8wtjTmN0xJ5edpU76SvEbcdmCLpHJ92j7oWBg8fMTAninkjcX5pl8Kw5c87RK35GsFKuUWA=="], - "@bastani/pi-ai": ["@bastani/pi-ai@0.9.23", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-Z7s6dEeuQRj08avCqltxTcf+LRTYek1TZ3/tbSJxH8WELH/yNOzkIzcuSpcYzOZ7hrWFzwAB1AaKDITSgUSwpA=="], + "@bastani/pi-ai": ["@bastani/pi-ai@0.9.24-alpha.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-hRsS16AcvOvI/SEZhAMYfnPIQf4ycxuFQJb7AjzK3BuosKnHJudjLjKR+ah9+C4O87IzwPpZSChVTfsAv7/Z4w=="], "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], @@ -2030,7 +2030,7 @@ "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], - "pg": ["pg@8.22.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.15.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA=="], + "pg": ["pg@8.23.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.16.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg=="], "pg-cloudflare": ["pg-cloudflare@1.4.1", "", {}, "sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ=="], @@ -2460,6 +2460,8 @@ "@dbos-inc/dbos-sdk/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "@dbos-inc/dbos-sdk/pg": ["pg@8.22.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.15.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA=="], + "@dbos-inc/dbos-sdk/yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], "@earendil-works/chord/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], @@ -2540,6 +2542,8 @@ "ecdsa-sig-formatter/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "embedded-postgres/pg": ["pg@8.22.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.15.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA=="], + "happy-dom/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "htmlparser2/domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], diff --git a/docs/self-hosting.md b/docs/self-hosting.md index 248c0b53..99a5ecef 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -115,7 +115,7 @@ it. The Pi contract suite (`apps/server/src/harness/pi.contract.test.ts`) covers this against the real Pi agent loop; run it before bumping `@ai-sdk/harness-pi` or `@earendil-works/pi-coding-agent`. -`HARNESS=atomic` runs Atomic 0.9.23 in the Chopin server process through its +`HARNESS=atomic` runs Atomic 0.9.24-alpha.1 in the Chopin server process through its headless SDK (`createAgentSession()`). It does not spawn the `atomic` CLI, use RPC mode, or substitute Atomic for Pi's runtime. Each harness session owns one in-memory Atomic `AgentSession` whose only tools are Chopin's host tools; see diff --git a/package.json b/package.json index 84ed5f7f..fff3906c 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", - "@bastani/atomic": "0.9.23", + "@bastani/atomic": "0.9.24-alpha.1", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7", From 1f3a838f17aa4865d0c78c4136be2a98810b4d14 Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Thu, 1 Oct 2026 08:38:07 -0700 Subject: [PATCH 5/6] Remove the working directory when a session closes during setup Closing an Atomic session while its first turn was still setting up ran cleanup before the working directory existed; setup then created it, saw the session closed, and stopped without deleting it. Delete the directory on that closed path, in a finally so a failed dispose still removes it. Reported by Maggie Appleton in review. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: fail-before/pass-after passed: the new lifecycle test left a chopin-atomic-planner directory behind without the fix and passes with it Assistant-verification: bun test passed: 1824 pass, 2 PostgreSQL skips, 0 fail Assistant-verification: bun run types passed: all workspaces Assistant-verification: bun run ci passed: dprint, oxlint, tokens, design contract, design record, Impeccable (no new findings) Co-authored-by: Alex Lavaee --- apps/server/src/harness/atomic.contract.test.ts | 12 ++++++++++++ apps/server/src/harness/atomic/adapter.ts | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/server/src/harness/atomic.contract.test.ts b/apps/server/src/harness/atomic.contract.test.ts index 202297d0..9a87841c 100644 --- a/apps/server/src/harness/atomic.contract.test.ts +++ b/apps/server/src/harness/atomic.contract.test.ts @@ -208,6 +208,18 @@ describe("atomic HarnessV1 lifecycle", () => { }); } + it("leaves no working directory behind when closed while its first turn is still setting up", async () => { + let planners = async () => + new Set((await readdir(tmpdir())).filter(name => name.startsWith("chopin-atomic-planner-"))); + let before = await planners(); + let session = await start(); + let turn = session.doPromptTurn({ prompt: "plain", skills: [], tools: [], emit: () => {} }); + await session.doDestroy(); + await expect(turn).rejects.toThrow("Atomic session is closed."); + let left = [...await planners()].filter(name => !before.has(name)); + expect(left).toEqual([]); + }); + it("settles a pending host tool on abort and ignores a late result", async () => { let session = await start(); let first = recorder(); diff --git a/apps/server/src/harness/atomic/adapter.ts b/apps/server/src/harness/atomic/adapter.ts index 9d37dc9b..f74712f5 100644 --- a/apps/server/src/harness/atomic/adapter.ts +++ b/apps/server/src/harness/atomic/adapter.ts @@ -459,7 +459,15 @@ export function createAtomicAdapter( let session = created.session; let leak = hostLeak(session, created.extensionsResult.extensions.length, hostNames); if (leak || closed) { - await session.dispose(); + try { + await session.dispose(); + } finally { + // Closing during setup ran cleanup before this directory existed. + if (closed && directory) { + await rm(directory, { recursive: true, force: true }); + directory = undefined; + } + } throw leak ? new ToolBoundaryError(`Atomic session is not isolated: ${leak}.`) : new Error("Atomic session is closed."); From a390374b3c646f613702ca0d97ccf500e6d354f4 Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Thu, 1 Oct 2026 09:16:20 -0700 Subject: [PATCH 6/6] Upgrade the Atomic harness to 0.9.25 0.9.25 is the stable release that rolls up the 0.9.25 prereleases, including SDK workflow run control and the native MCP client. It ships the same five builtin packages, so BUILTINS_OFF still turns off each one for the isolated Planner. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: bun test passed: 1824 pass, 2 PostgreSQL skips, 0 fail Assistant-verification: bun run types passed: all workspaces Assistant-verification: bun run ci passed: dprint, oxlint, tokens, design contract, design record, Impeccable (no new findings) Assistant-verification: source check passed: @bastani/atomic 0.9.25 dist/builtin lists intercom, mcp, subagents, web-access, workflows Co-authored-by: Alex Lavaee --- bun.lock | 48 +++++++++++++++++++++++--------------------- docs/self-hosting.md | 2 +- package.json | 2 +- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/bun.lock b/bun.lock index 9b28a173..c83d381c 100644 --- a/bun.lock +++ b/bun.lock @@ -230,7 +230,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", - "@bastani/atomic": "0.9.24-alpha.1", + "@bastani/atomic": "0.9.25", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7", @@ -382,27 +382,25 @@ "@base-ui/utils": ["@base-ui/utils@0.3.2", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.12", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ=="], - "@bastani/atomic": ["@bastani/atomic@0.9.24-alpha.1", "", { "dependencies": { "@bastani/atomic-natives": "0.9.24-alpha.1", "@bastani/pi-ai": "0.9.24-alpha.1", "@dbos-inc/dbos-sdk": "4.25.14", "@earendil-works/pi-agent-core": "0.87.1", "@earendil-works/pi-client": "0.87.1", "@earendil-works/pi-protocol": "0.87.1", "@earendil-works/pi-tui": "0.87.1", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.6.0", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "embedded-postgres": "18.4.0-beta.17", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "pg": "8.23.0", "proper-lockfile": "4.1.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-KYrHqDsUEhyZ8rXg3kvWPeV8X44/Gf7W/cIXXP3q3K27MmKNyqiQ8F2y0ssDvY4y4ZjMxzUv52HledSnsFTq2w=="], + "@bastani/atomic": ["@bastani/atomic@0.9.25", "", { "dependencies": { "@bastani/atomic-natives": "0.9.25", "@bastani/pi-ai": "0.9.25", "@dbos-inc/dbos-sdk": "4.25.14", "@earendil-works/pi-agent-core": "0.99.2", "@earendil-works/pi-client": "0.99.2", "@earendil-works/pi-codemode": "0.99.2", "@earendil-works/pi-protocol": "0.99.2", "@earendil-works/pi-tui": "0.99.2", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.6.0", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "embedded-postgres": "18.4.0-beta.17", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "pg": "8.23.0", "proper-lockfile": "4.1.2", "quickjs-wasi": "3.6.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-yj/MX60cSZ2QIN+4Lmxgt7S0a/Ol06ZpH7tHsflVC36hzVl2K5a+AXWjd5KwnwGlP1ZJlvd3yr+pw+/9bwmBlw=="], - "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.24-alpha.1", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.24-alpha.1", "@bastani/atomic-natives-darwin-x64": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-arm64-musl": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-x64-gnu": "0.9.24-alpha.1", "@bastani/atomic-natives-linux-x64-musl": "0.9.24-alpha.1", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.24-alpha.1", "@bastani/atomic-natives-win32-x64-msvc": "0.9.24-alpha.1" } }, "sha512-jaQHzlzBcFoyVR5jj+bpaKgoCz8BzrfeISk+PExXHUjGHpUH98M9VtTErk6ytRogV1YP8Z53jdobqpX87Gi95g=="], + "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.25", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.25", "@bastani/atomic-natives-darwin-x64": "0.9.25", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.25", "@bastani/atomic-natives-linux-arm64-musl": "0.9.25", "@bastani/atomic-natives-linux-x64-gnu": "0.9.25", "@bastani/atomic-natives-linux-x64-musl": "0.9.25", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.25", "@bastani/atomic-natives-win32-x64-msvc": "0.9.25" } }, "sha512-M2OipXIzjIZJ0/DQm28zvzlI2wJ8poWBgCe9UKMLV2tBKItzxvIp85hEjUVir8ZbTOlAKpeAC83laTVmdaQ2FQ=="], - "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.24-alpha.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hntKcTgjFHDzotDSu8czfI3XL0rjv8ZTmmGRqaJhGDbW7VKpIkZ5khOEl/A86Uu89tsT09Kw9M1WZxO1YalzJw=="], + "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.25", "", { "os": "darwin", "cpu": "arm64" }, "sha512-puuAEWVuQzpttskalJ3/LWb4gBp8yrWK+CFaSm7kDyJ7Y9XOmG90+xDpFXfT8uw9FkpsD9Ucjnh9/pBuBFzq+A=="], - "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.24-alpha.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/LC/wALhgmj/Xuf9IFW+R4OZLrQqwBUlHHmd9cH/3KQsSXUS1jeAL+cd5BwmPAP9ugRxGHP4GodP5JnnFhi61A=="], + "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.25", "", { "os": "darwin", "cpu": "x64" }, "sha512-YrhDtamBaWwzyMmslN9lSpPPOy7H2rcKE7xDa7akY5Fwxj7D7WwqsDHHAK0Qm8BIXkh1Ca4biaNh3FXMHtoLsw=="], - "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.24-alpha.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-3g0gt/oXQsNKIC0IaQlJwCP86xiXi76lIl6McxpoNM1vHX+o5BOCIX0Ah6qtdlsSc2iuafImWy9FRqFRwTbzCA=="], + "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.25", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZGj95QTWjp14qtXyeL+qO5pF4LA7E+n7noacBOrQ9ryjc92YMCr5Z1e6NRm9Gmxc1uvb56LkxOGSgblR2jMUfA=="], - "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.24-alpha.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-3rJDvT9chlGTSuLLOT/pSFrYbmv+UmTMUu1NOi16nHz9UyoCZiida9EGyzkSVByt9Py+RnqXaCk+Yr2iW4jn8w=="], + "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.25", "", { "os": "linux", "cpu": "arm64" }, "sha512-YeXRi/3avBYfMXu8q5PG3YhXK8LUkMKiyQRnqROnbiDIoF+YqFwxHLrjTfZpDDAd/CIN+Zqt2ySeA6FpVIkQtA=="], - "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.24-alpha.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eyd7fc1oQPZLIF1eJwvf73QsgAcAYtXfJ1VoE1fOPcP3jWWRusbItuBi2lFWMSP/8jacQDxDJh0jWsh3pyEuyg=="], + "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.25", "", { "os": "linux", "cpu": "x64" }, "sha512-cCkTXcQAAv55w8f0ffOZ3A5p18vLu8b6YqjOUhrnNerrBzp+E96QXLQX3dyXqEf/4FVgzLz06DRXCTSZrQ1hXA=="], - "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.24-alpha.1", "", { "os": "linux", "cpu": "x64" }, "sha512-45AKuQIx7jWDAN5YpJLiiFg/eH6pkZ12SRs8kBDOhHfE8BBnJM+Cgs40CS61uoY1Z4VqDx+yHrQ0e33euUVaqw=="], + "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.25", "", { "os": "linux", "cpu": "x64" }, "sha512-g2Y7MKUldwdlKmtzb3TZmuqfcsOOLBdoX2GIWZ0mnbEyk8NqpZjGWUgC4gbfF2SvwWW/aSd4PK4jeKkSzpEy0w=="], - "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.24-alpha.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-plfCBL5uaNEHH/LKlu7dc+DAA8uoh1PUvOUGopOgaP1pWeJAjGurB09zy1wCTBboHzaIAPT3GIF6wPyFBVDVlw=="], + "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.25", "", { "os": "win32", "cpu": "arm64" }, "sha512-SMTJP0zwi/wKVIqRYvEoQX2hHEZ4V8bLJIhaiqsGn6yL7JHl9bw+uGqQ4krLbOZ+8+fPI4zi0ub6N7l+5zOp9Q=="], - "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.24-alpha.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ODEXhle6rXJiBSH8wtjTmN0xJ5edpU76SvEbcdmCLpHJ92j7oWBg8fMTAninkjcX5pl8Kw5c87RK35GsFKuUWA=="], - - "@bastani/pi-ai": ["@bastani/pi-ai@0.9.24-alpha.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-hRsS16AcvOvI/SEZhAMYfnPIQf4ycxuFQJb7AjzK3BuosKnHJudjLjKR+ah9+C4O87IzwPpZSChVTfsAv7/Z4w=="], + "@bastani/pi-ai": ["@bastani/pi-ai@0.9.25", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "0.99.2", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-flPqKzaybHi7Aucvh8qFdhYduYpRVpvkgnRHlOecOhwbtSb4kjdztuhqtll7sr3k/lE0Q/CW0LsTbhEtphyH4g=="], "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], @@ -520,19 +518,21 @@ "@earendil-works/chord": ["@earendil-works/chord@0.85.1", "", { "dependencies": { "esbuild": "0.28.1" } }, "sha512-VDlkEC3dhCzQ5fcyH1OhG19dq+6jCn+rqc/iXFivwDYGR5anwo2RCiXij9PpHhqNR5GuhhE+Er69Zi1Sn4eY6w=="], - "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "@earendil-works/pi-ai": "^0.87.1", "@earendil-works/pi-telemetry": "^0.87.1", "diff": "8.0.4", "ignore": "7.0.8", "typebox": "1.3.27", "yaml": "2.9.0" } }, "sha512-Zev3B0HK7YS5A4EZQ2XnEqiJuirx6QBiltJ+LpmjV5a/+2IU0cfKtIfnkNkORK707XOvKBY2WRtk7cAwHpbh2Q=="], + "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.99.2", "", { "dependencies": { "@earendil-works/chord": "^0.99.2", "@earendil-works/pi-ai": "^0.99.2", "@earendil-works/pi-telemetry": "^0.99.2", "diff": "8.0.4", "ignore": "7.0.8", "typebox": "1.3.27", "yaml": "2.9.0" } }, "sha512-VX0QMcg8HKBsv1bYP2NwmutBYa44OrwmtqR6Dq7QC3Ln8X/IlpHhUxB5L1JgnXNUUkTm8Wg/HZhzS797NBDMCQ=="], "@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.74.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.91.1", "@aws-sdk/client-bedrock-runtime": "^3.1030.0", "@google/genai": "^1.40.0", "@mistralai/mistralai": "^2.2.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "openai": "6.26.0", "partial-json": "^0.1.7", "typebox": "^1.1.24" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-ukQBHGDm20k9ZUS2cGjNN9vDJp/48r35xmvgSx3paCaC06r2N/PLuRZoJmwQ1ZM7f8T3072odv9YPWn+77w0LA=="], - "@earendil-works/pi-client": ["@earendil-works/pi-client@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "@earendil-works/pi-protocol": "^0.87.1" } }, "sha512-x8dfZ7ppAao9SDnZvD5/DErVdq2fI7hg4lFj7qEhtgo6wimrRafGSLsqLklFVjb6kxU2W3j9F4RZz0rRcb0cwA=="], + "@earendil-works/pi-client": ["@earendil-works/pi-client@0.99.2", "", { "dependencies": { "@earendil-works/chord": "^0.99.2", "@earendil-works/pi-protocol": "^0.99.2" } }, "sha512-j8dc4gOC3ExalNZqJODfmaT3Ei2nQNMFKDe4KbyGSMbByD/fbKXjbNeQLy2H0aG3L9fZJc4bZh+cR10D3XTfQQ=="], + + "@earendil-works/pi-codemode": ["@earendil-works/pi-codemode@0.99.2", "", { "dependencies": { "quickjs-wasi": "3.6.2" } }, "sha512-PVxNGu4l7LI92MvwUbaY3trjznU1Mlp2OMGwHwCWzLsjG7/lDa8xf6ei+Gws7VCt+Ri1tO+nFVl9KV2EeX7HWg=="], "@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.85.1", "", { "dependencies": { "@earendil-works/chord": "^0.85.1", "@earendil-works/pi-agent-core": "^0.85.1", "@earendil-works/pi-ai": "^0.85.1", "@earendil-works/pi-tui": "^0.85.1", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "grok-mermaid": "0.2.2", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", "undici": "8.9.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "pi": "dist/bundle/cli.js" } }, "sha512-FGRN+OHbWaefBPGaTggAdLjrIHW+s2PzLyglz/5dfLzb9of7uuXMXYC0fJIeZTw+shS32o2cuQ9jF7YSDuL/oQ=="], - "@earendil-works/pi-protocol": ["@earendil-works/pi-protocol@0.87.1", "", { "dependencies": { "@earendil-works/chord": "^0.87.1", "typebox": "1.3.27" } }, "sha512-48WVjryAIiKOJXnKgO15h2MT/oeH5uf0S4DykcVj3ZrxMTDSGxcUaS5VtvHtFQ1rZSSIjkVcblE13k0GksBuoQ=="], + "@earendil-works/pi-protocol": ["@earendil-works/pi-protocol@0.99.2", "", { "dependencies": { "@earendil-works/chord": "^0.99.2", "typebox": "1.3.27" } }, "sha512-ry9hfwZy06sEjsQFsQJXptJ9EO5w8wxBUYVNNSo1WwkHVeItu5lTtCBAC80i9oRlTaSb2rXLjuuh+NWILhFw8g=="], - "@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.87.1", "", {}, "sha512-MC6TRQH5lgMXpcN+Vku2WMI2T8BsiUPzMQHGo81uqFZD3/9O79WWJAysEDGuzduP6R4tvtgwMLwmqIxynM10JQ=="], + "@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.99.2", "", {}, "sha512-WThYU4XM6jjjzH4FzLdreN7QAPS9SDdokL0W0Ldheg1ssCIJkfpK7PgebFm7/PoQub7OiXx+SRF6B/oF7z7lXA=="], - "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.87.1", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.11" } }, "sha512-YEH2vRyOeiO7hhN6j6AE6YwKSq2Kz2f3XR8bj1TbR+aGE/JsnY1hLPMI2pvaZfRM1n9Y00tejxFQ4zbzvF7nkQ=="], + "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.99.2", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.11" } }, "sha512-IOcNnd390NCIwBEKeOiBK/bvaR7Z+vEsvB5TtKsFdsY/vAZE6qRHbQqt6jpTefTiKPfQlwG8eS1BU42DeG2v4w=="], "@embedded-postgres/darwin-arm64": ["@embedded-postgres/darwin-arm64@18.4.0-beta.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Kg1ZMNFzkVIJs3g4V2UYEc5X005km9rGinxFBH8R1sOU2Rblvz4pt2Uf93Pu8Rk273Ue9HIdrbMPpgUqwjUi0Q=="], @@ -2100,6 +2100,8 @@ "quickjs-emscripten-core": ["quickjs-emscripten-core@0.32.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.32.0" } }, "sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg=="], + "quickjs-wasi": ["quickjs-wasi@3.6.2", "", {}, "sha512-FCqGtGOrMgzUiIrMNMA2YnsOxCNwo31dzqXvclXUC6xeT35NJLKXQJsvbeCTjvoFAwZgEAPg8U6+KAPDGXn8Mg=="], + "range-parser": ["range-parser@1.3.0", "", {}, "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], @@ -2466,9 +2468,9 @@ "@earendil-works/chord/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], - "@earendil-works/pi-agent-core/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + "@earendil-works/pi-agent-core/@earendil-works/chord": ["@earendil-works/chord@0.99.2", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-2dJWiNsOJm/ioBl1fhpJmw0hIjFUhM0CAteEnVkiVG0Kg4LimR7Asq8PfjclEvrbCPsDntzy7rGKhTZObI9TZw=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.87.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "^0.87.1", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "6.40.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-X/3PfQBnnoeVdO9Cv8zHghUMglzlgNZYGNzoPnbRoGnHl3Rw3TlA2UKSUB7BRHUOxMryHXYa8dnjWZlbRheDZA=="], + "@earendil-works/pi-agent-core/@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.99.2", "", { "dependencies": { "@anthropic-ai/sdk": "0.124.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "^0.99.2", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-9RFOEdY+ZTJ1AI+UuAFs4RM0tF2Tje/R/CEv9gWTJHt0iTu8XHZs64U/EIZxNSllFmec/4HfwsOxYj1qQek9bg=="], "@earendil-works/pi-agent-core/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], @@ -2476,7 +2478,7 @@ "@earendil-works/pi-ai/typebox": ["typebox@1.3.34", "", {}, "sha512-wbnzrXXDW8xEFHDZZs2jo1MkhaYlKAY4FRhpBc1+2LF1fZVBGCXGdLEhA/Z/NBbgzJMFfeM8m7elKPa/+KxaUQ=="], - "@earendil-works/pi-client/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + "@earendil-works/pi-client/@earendil-works/chord": ["@earendil-works/chord@0.99.2", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-2dJWiNsOJm/ioBl1fhpJmw0hIjFUhM0CAteEnVkiVG0Kg4LimR7Asq8PfjclEvrbCPsDntzy7rGKhTZObI9TZw=="], "@earendil-works/pi-coding-agent/@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.85.1", "", { "dependencies": { "@earendil-works/chord": "^0.85.1", "@earendil-works/pi-ai": "^0.85.1", "@earendil-works/pi-telemetry": "^0.85.1", "diff": "8.0.4", "ignore": "7.0.5", "typebox": "1.3.7", "yaml": "2.9.0" } }, "sha512-hIXIP3eAWueAYiAl8aMvWCvvZ8Q5gT3Dip5bE5uJyIGh4+YlWRjtMLI4BaeoXoSs93zndjue61u1B/vhefLnuA=="], @@ -2498,7 +2500,7 @@ "@earendil-works/pi-coding-agent/undici": ["undici@8.9.0", "", {}, "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA=="], - "@earendil-works/pi-protocol/@earendil-works/chord": ["@earendil-works/chord@0.87.1", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-bg7IkJGFcEaMqqYgOGUiq5Ky9RghpRfrlZ8I/v/1b4bBZ02A7t3E+6uhPRbadwWb/kWsnVFbZsqOKRN4a3LLCg=="], + "@earendil-works/pi-protocol/@earendil-works/chord": ["@earendil-works/chord@0.99.2", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-2dJWiNsOJm/ioBl1fhpJmw0hIjFUhM0CAteEnVkiVG0Kg4LimR7Asq8PfjclEvrbCPsDntzy7rGKhTZObI9TZw=="], "@earendil-works/pi-protocol/typebox": ["typebox@1.3.27", "", {}, "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA=="], @@ -2682,7 +2684,7 @@ "@earendil-works/pi-agent-core/@earendil-works/pi-ai/https-proxy-agent": ["https-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA=="], - "@earendil-works/pi-agent-core/@earendil-works/pi-ai/openai": ["openai@6.40.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"] }, "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA=="], + "@earendil-works/pi-agent-core/@earendil-works/pi-ai/openai": ["openai@7.19.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "undici": ">=5 <9", "ws": "^8.21.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "undici", "ws", "zod"] }, "sha512-MX2s3u2L5racTO0CC/SWpCOasJQBCJrqLKXK+l82cAhdeF8mPMBEe/gxMm0ZFa2xpKpOFLRjxv5afYEZbBXmbQ=="], "@earendil-works/pi-client/@earendil-works/chord/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], diff --git a/docs/self-hosting.md b/docs/self-hosting.md index 99a5ecef..d7602dc2 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -115,7 +115,7 @@ it. The Pi contract suite (`apps/server/src/harness/pi.contract.test.ts`) covers this against the real Pi agent loop; run it before bumping `@ai-sdk/harness-pi` or `@earendil-works/pi-coding-agent`. -`HARNESS=atomic` runs Atomic 0.9.24-alpha.1 in the Chopin server process through its +`HARNESS=atomic` runs Atomic 0.9.25 in the Chopin server process through its headless SDK (`createAgentSession()`). It does not spawn the `atomic` CLI, use RPC mode, or substitute Atomic for Pi's runtime. Each harness session owns one in-memory Atomic `AgentSession` whose only tools are Chopin's host tools; see diff --git a/package.json b/package.json index fff3906c..04b4633f 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@ai-sdk/harness-pi": "1.0.128", "@ai-sdk/mcp": "2.0.60", "@ai-sdk/sandbox-just-bash": "1.0.126", - "@bastani/atomic": "0.9.24-alpha.1", + "@bastani/atomic": "0.9.25", "@earendil-works/pi-coding-agent": "0.85.1", "ai": "7.0.116", "typebox": "1.3.7",