@tangle-network/agent-runtime 0.23.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/executor.ts","../src/mcp/worktree.ts","../src/mcp/in-process-executor.ts","../src/mcp/bin-helpers.ts","../src/mcp/delegates.ts","../src/mcp/server.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Delegation executors — the layer between MCP delegates and the sandbox\n * substrate. Each executor exposes a {@link LoopSandboxClient} the kernel\n * consumes plus a placement tag so the trace pipeline can correlate workers\n * with their physical placement.\n *\n * Two implementations ship in-box:\n *\n * - {@link createSiblingSandboxExecutor} — every delegation spawns a fresh\n * sandbox sibling to the caller. Default when the MCP server runs as a\n * standalone CLI mounted outside a fleet.\n *\n * - {@link createFleetWorkspaceExecutor} — delegations dispatch onto machines\n * in the caller's existing fleet so worker diffs land directly on the\n * caller's filesystem (the fleet's shared workspace). Selected when the\n * parent sandbox passes `TANGLE_FLEET_ID` into the MCP server's env.\n */\n\nimport type { CreateSandboxOptions, SandboxInstance } from '@tangle-network/sandbox'\nimport type { LoopSandboxClient, LoopSandboxPlacement } from '../loops'\n\n/** @experimental */\nexport interface DelegationExecutor {\n /** Sandbox client the kernel calls. Returned with `describePlacement` set. */\n readonly client: LoopSandboxClient\n /** Best-effort one-liner used in stderr boot logs and diagnostics. */\n describe(): string\n}\n\n/** @experimental */\nexport interface SiblingSandboxExecutorOptions {\n client: LoopSandboxClient\n}\n\n/**\n * Wrap a raw sandbox SDK client so the kernel emits\n * `loop.iteration.dispatch` events with `{ placement: 'sibling', sandboxId }`.\n *\n * The returned client `.create()` delegates to the underlying client; the\n * only added behavior is a `describePlacement` tag the kernel reads.\n *\n * @experimental\n */\nexport function createSiblingSandboxExecutor(\n options: SiblingSandboxExecutorOptions,\n): DelegationExecutor {\n const underlying = options.client\n const client: LoopSandboxClient = {\n create(opts?: CreateSandboxOptions): Promise<SandboxInstance> {\n return underlying.create(opts)\n },\n describePlacement(box: SandboxInstance): LoopSandboxPlacement {\n return { kind: 'sibling', sandboxId: readId(box) }\n },\n }\n return {\n client,\n describe(): string {\n return 'sibling-sandbox (each delegation = fresh sandbox via client.create)'\n },\n }\n}\n\n/**\n * Minimal `SandboxFleet` surface the fleet executor calls. Declared\n * structurally so tests can pass an in-memory stub without instantiating the\n * sandbox SDK.\n *\n * @experimental\n */\nexport interface FleetHandle {\n readonly fleetId: string\n /** Machine ids in dispatch-eligible order. The executor round-robins. */\n readonly ids: ReadonlyArray<string>\n /** Resolve a machine id to its `SandboxInstance` — that machine is mounted\n * on the fleet's shared workspace, so any diff the worker writes lands on\n * every other fleet machine's filesystem too. */\n sandbox(machineId: string): Promise<SandboxInstance>\n}\n\n/** @experimental */\nexport interface FleetWorkspaceExecutorOptions {\n fleet: FleetHandle\n /**\n * Override the machine-selection policy. Default = round-robin across\n * `fleet.ids`, skipping the optional `excludeMachineIds` set (typically the\n * coordinator machine the MCP server is running on).\n */\n selectMachine?: (call: { callIndex: number; ids: ReadonlyArray<string> }) => string\n /**\n * Machine ids to skip during default round-robin. Set to the caller's own\n * machineId so workers don't compete with the orchestrator on the same VM.\n */\n excludeMachineIds?: ReadonlyArray<string>\n}\n\n/**\n * Build an executor that resolves each delegated iteration to an existing\n * machine in `fleet`. The fleet's shared-workspace policy means the worker\n * machine sees the caller's filesystem — diffs land in-place with no\n * cross-sandbox copy step.\n *\n * @experimental\n */\nexport function createFleetWorkspaceExecutor(\n options: FleetWorkspaceExecutorOptions,\n): DelegationExecutor {\n const fleet = options.fleet\n const exclude = new Set(options.excludeMachineIds ?? [])\n let callIndex = 0\n // machineId-by-sandboxId, populated as we resolve machines so\n // `describePlacement` can recover the assignment from the SandboxInstance\n // the kernel hands back.\n const placementBySandboxId = new Map<string, { machineId: string }>()\n\n const client: LoopSandboxClient = {\n async create(): Promise<SandboxInstance> {\n const ids = fleet.ids.filter((id) => !exclude.has(id))\n if (ids.length === 0) {\n throw new Error(\n `agent-runtime: fleet ${fleet.fleetId} has no eligible worker machines (ids=[${fleet.ids.join(',')}], excluded=[${[...exclude].join(',')}])`,\n )\n }\n const selector = options.selectMachine\n const machineId = selector ? selector({ callIndex, ids }) : ids[callIndex % ids.length]\n callIndex += 1\n if (typeof machineId !== 'string' || machineId.length === 0) {\n throw new Error('agent-runtime: fleet executor selectMachine returned an empty machine id')\n }\n const box = await fleet.sandbox(machineId)\n const sandboxId = readId(box)\n if (sandboxId) placementBySandboxId.set(sandboxId, { machineId })\n return box\n },\n describePlacement(box: SandboxInstance): LoopSandboxPlacement {\n const sandboxId = readId(box)\n const recorded = sandboxId ? placementBySandboxId.get(sandboxId) : undefined\n return {\n kind: 'fleet',\n sandboxId,\n fleetId: fleet.fleetId,\n machineId: recorded?.machineId,\n }\n },\n }\n\n return {\n client,\n describe(): string {\n const excluded = exclude.size > 0 ? ` (excluded=[${[...exclude].join(',')}])` : ''\n return `fleet-workspace (fleetId=${fleet.fleetId}, machines=[${fleet.ids.join(',')}]${excluded})`\n },\n }\n}\n\nfunction readId(box: SandboxInstance): string | undefined {\n const raw = (box as unknown as { id?: unknown }).id\n return typeof raw === 'string' && raw.length > 0 ? raw : undefined\n}\n","/**\n * @experimental\n *\n * Git worktree helpers for the in-process delegation executor. Each\n * delegation runs in its own worktree so multiple parallel harness\n * subprocesses (claude / codex / opencode in a 3-way fanout) don't clobber\n * each other's edits on the shared workspace.\n *\n * Worktrees live under `<repoRoot>/.coder-variants/<runId>/`. After the\n * harness exits + the diff is captured, the worktree is removed.\n *\n * All operations spawn `git` via `child_process.spawn` synchronously\n * (via a `runGit` helper). Stays narrow on purpose: no working-tree\n * staging, no commits, no rebases.\n */\n\nimport { spawn } from 'node:child_process'\n\n/** @experimental */\nexport interface WorktreeHandle {\n /** Absolute path to the worktree directory. */\n path: string\n /** SHA the worktree was created at. */\n baseSha: string\n /** Branch name created for this worktree (typically `delegate/<runId>`). */\n branch: string\n}\n\n/** @experimental */\nexport interface CreateWorktreeOptions {\n /** Absolute path to the main git checkout. */\n repoRoot: string\n /** Unique id for the worktree path + branch. Use the delegation run id. */\n runId: string\n /** Parent directory the worktree lives under. Defaults to `.coder-variants`. */\n variantsDir?: string\n /** Override the base ref (default `HEAD`). */\n baseRef?: string\n /** Test seam — inject a custom git runner. */\n runGit?: GitRunner\n}\n\n/** @experimental */\nexport interface DiffOptions {\n /** Worktree to diff. */\n worktree: WorktreeHandle\n /** What to compare against. Default `worktree.baseSha`. */\n baseRef?: string\n /** Test seam. */\n runGit?: GitRunner\n}\n\n/** @experimental */\nexport interface DiffResult {\n patch: string\n stats: {\n filesChanged: number\n insertions: number\n deletions: number\n }\n}\n\n/** @experimental */\nexport interface RemoveWorktreeOptions {\n worktree: WorktreeHandle\n repoRoot: string\n /** Force removal even if dirty (default true; the loser of a fanout has uncommitted changes). */\n force?: boolean\n /** Test seam. */\n runGit?: GitRunner\n}\n\n/** Pluggable git runner (sync) — replaceable in tests. */\nexport type GitRunner = (\n args: ReadonlyArray<string>,\n opts: { cwd: string },\n) => { stdout: string; stderr: string; exitCode: number }\n\nasync function runGitAsync(\n args: ReadonlyArray<string>,\n cwd: string,\n runner?: GitRunner,\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n if (runner) return runner(args, { cwd })\n return new Promise((resolve, reject) => {\n const proc = spawn('git', args, { cwd, stdio: 'pipe' })\n let stdout = ''\n let stderr = ''\n proc.stdout?.on('data', (c) => {\n stdout += String(c)\n })\n proc.stderr?.on('data', (c) => {\n stderr += String(c)\n })\n proc.on('error', reject)\n proc.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? -1 }))\n })\n}\n\nfunction ensureGitOk(\n step: string,\n result: { stdout: string; stderr: string; exitCode: number },\n): void {\n if (result.exitCode !== 0) {\n throw new Error(\n `worktree: git ${step} failed (exit ${result.exitCode}): ${result.stderr.slice(0, 400)}`,\n )\n }\n}\n\n/** @experimental */\nexport async function createWorktree(options: CreateWorktreeOptions): Promise<WorktreeHandle> {\n const variants = options.variantsDir ?? '.coder-variants'\n const baseRef = options.baseRef ?? 'HEAD'\n const branch = `delegate/${options.runId}`\n const path = `${options.repoRoot.replace(/\\/+$/, '')}/${variants}/${options.runId}`\n\n const headSha = await runGitAsync(['rev-parse', baseRef], options.repoRoot, options.runGit)\n ensureGitOk(`rev-parse ${baseRef}`, headSha)\n\n const add = await runGitAsync(\n ['worktree', 'add', '-b', branch, path, baseRef],\n options.repoRoot,\n options.runGit,\n )\n ensureGitOk(`worktree add ${path}`, add)\n\n return { path, baseSha: headSha.stdout.trim(), branch }\n}\n\n/** @experimental */\nexport async function captureWorktreeDiff(options: DiffOptions): Promise<DiffResult> {\n const baseRef = options.baseRef ?? options.worktree.baseSha\n const patch = await runGitAsync(['diff', baseRef], options.worktree.path, options.runGit)\n // No `ensureGitOk` here — diff returns 0 even when there are no changes.\n\n // Stats: `git diff --shortstat` produces e.g. \" 3 files changed, 42 insertions(+), 10 deletions(-)\".\n const shortstat = await runGitAsync(\n ['diff', '--shortstat', baseRef],\n options.worktree.path,\n options.runGit,\n )\n const stats = parseShortstat(shortstat.stdout)\n return { patch: patch.stdout, stats }\n}\n\nfunction parseShortstat(text: string): DiffResult['stats'] {\n // `text` is the raw stdout of `git diff --shortstat`. Empty when no\n // changes. Parse defensively — the format is stable but we don't trust\n // it for type-safety.\n const out = { filesChanged: 0, insertions: 0, deletions: 0 }\n const filesMatch = text.match(/(\\d+)\\s+files?\\s+changed/)\n if (filesMatch?.[1]) out.filesChanged = Number(filesMatch[1])\n const insertMatch = text.match(/(\\d+)\\s+insertions?/)\n if (insertMatch?.[1]) out.insertions = Number(insertMatch[1])\n const deleteMatch = text.match(/(\\d+)\\s+deletions?/)\n if (deleteMatch?.[1]) out.deletions = Number(deleteMatch[1])\n return out\n}\n\n/** @experimental */\nexport async function removeWorktree(options: RemoveWorktreeOptions): Promise<void> {\n const force = options.force ?? true\n const args = ['worktree', 'remove']\n if (force) args.push('--force')\n args.push(options.worktree.path)\n const result = await runGitAsync(args, options.repoRoot, options.runGit)\n // Don't ensureGitOk — partial-removal scenarios are tolerable; the\n // worktree dir may already be gone (caller deleted it manually).\n if (result.exitCode !== 0 && !/not a working tree/.test(result.stderr)) {\n // Best-effort branch cleanup so the next run can reuse the runId.\n await runGitAsync(\n ['branch', '-D', options.worktree.branch],\n options.repoRoot,\n options.runGit,\n ).catch(() => undefined)\n }\n // Always attempt branch removal — the worktree-remove sometimes leaves\n // the branch behind even when the directory is gone.\n await runGitAsync(\n ['branch', '-D', options.worktree.branch],\n options.repoRoot,\n options.runGit,\n ).catch(() => undefined)\n}\n","/**\n * @experimental\n *\n * In-process delegation executor — when `agent-runtime-mcp` is running\n * inside a sandbox whose image carries the local coding-harness CLIs\n * (claude / codex / opencode), delegations spawn the harness AS A\n * SUBPROCESS against a git worktree on the SAME filesystem instead of\n * provisioning a sibling sandbox.\n *\n * Why: zero provisioning latency, worker diffs land in-place, multi-harness\n * fanout = N parallel subprocesses in N parallel worktrees.\n *\n * Selection:\n * - env `AGENT_RUNTIME_IN_SANDBOX=1` (set by the parent harness at MCP\n * server launch) → in-process executor\n * - env `TANGLE_FLEET_ID=...` → fleet executor (Phase 2.5)\n * - neither → sibling sandbox executor (default)\n *\n * Multi-harness rotation: pass `harnesses: ['claude', 'codex', 'opencode']`\n * to round-robin across calls. A `runLoop` + `FanoutVote(n: 3)` against this\n * executor produces three parallel iterations, each running a different\n * harness on its own worktree.\n *\n * Architecture:\n *\n * client.create() → returns a fake SandboxInstance whose streamPrompt:\n * 1. createWorktree() — git worktree add /workspace/.coder-variants/<id>\n * 2. runLocalHarness() — spawn claude/codex/opencode subprocess\n * 3. captureWorktreeDiff() — git diff HEAD → patch + stats\n * 4. run testCmd + typecheckCmd if specified (the executor doesn't\n * own these — caller wires via task-extractor callback)\n * 5. emit ONE SandboxEvent { type: 'result', data: { result: CoderOutput } }\n * 6. removeWorktree() in finally\n */\n\nimport { randomUUID } from 'node:crypto'\nimport type { CreateSandboxOptions, SandboxEvent, SandboxInstance } from '@tangle-network/sandbox'\nimport type { LoopSandboxClient, LoopSandboxPlacement } from '../loops'\nimport type { DelegationExecutor } from './executor'\nimport { type LocalHarness, runLocalHarness } from './local-harness'\nimport {\n captureWorktreeDiff,\n createWorktree,\n type GitRunner,\n removeWorktree,\n type WorktreeHandle,\n} from './worktree'\n\n/** @experimental */\nexport interface InProcessExecutorOptions {\n /**\n * Absolute path to the git repo (the workspace inside the sandbox). The\n * executor creates worktrees under `<repoRoot>/.coder-variants/`.\n */\n repoRoot: string\n /**\n * Harnesses to round-robin across calls. With one entry every delegation\n * uses that harness; with three you get fanout diversity for free.\n * Default `['claude']`.\n */\n harnesses?: ReadonlyArray<LocalHarness>\n /**\n * Optional per-delegation test command. Run with `cwd = worktree.path`\n * after the harness exits. The exit code populates\n * `CoderOutput.testResult.passed`.\n */\n testCmd?: string\n /**\n * Optional per-delegation typecheck command. Same shape as `testCmd`.\n */\n typecheckCmd?: string\n /** Wall-clock cap per harness subprocess (ms). Default 5min. */\n harnessTimeoutMs?: number\n /** Wall-clock cap per test/typecheck subprocess (ms). Default 2min. */\n postCheckTimeoutMs?: number\n /** Test seam — override the git runner used by the worktree helpers. */\n runGit?: GitRunner\n /**\n * Test seam — override the harness runner. Defaults to spawning the real\n * CLI via `runLocalHarness`. Tests inject a stub that returns a scripted\n * `LocalHarnessResult`.\n */\n runHarness?: typeof runLocalHarness\n /**\n * Test seam — override the post-check runner. Defaults to spawning the\n * configured `testCmd` / `typecheckCmd` via `child_process.spawn`.\n */\n runPostCheck?: (\n cmd: string,\n cwd: string,\n signal?: AbortSignal,\n ) => Promise<{ exitCode: number; stdout: string; stderr: string }>\n}\n\n/** @experimental */\nexport interface InProcessExecutorDescribePlacement extends LoopSandboxPlacement {\n /**\n * Worktree path in the parent sandbox's filesystem. Set so trace\n * consumers can correlate dispatch events with on-disk artifacts after\n * the worker exits.\n */\n worktreePath?: string\n /** Which harness handled this delegation. */\n harness?: LocalHarness\n}\n\ninterface VirtualSandbox extends SandboxInstance {\n __inProcess: {\n runId: string\n harness: LocalHarness\n worktree?: WorktreeHandle\n }\n}\n\nconst DEFAULT_HARNESS_TIMEOUT_MS = 5 * 60 * 1000\nconst DEFAULT_POSTCHECK_TIMEOUT_MS = 2 * 60 * 1000\n\n/**\n * Build an in-process executor.\n *\n * Returns a {@link DelegationExecutor} whose `client.create()` returns a\n * minimal \"virtual\" SandboxInstance — the kernel calls `streamPrompt(msg)`\n * on it, which runs the local harness on a worktree and emits one\n * `result` event whose `data.result` is a `CoderOutput`-shaped record.\n *\n * Pairs with `coderProfile`'s event parser (it walks the event list\n * back-to-front for the first `type === 'result'`).\n *\n * @experimental\n */\nexport function createInProcessExecutor(options: InProcessExecutorOptions): DelegationExecutor {\n const harnesses =\n options.harnesses && options.harnesses.length > 0\n ? [...options.harnesses]\n : (['claude'] as const)\n const runHarness = options.runHarness ?? runLocalHarness\n const runPostCheck = options.runPostCheck ?? defaultRunPostCheck\n\n let callIndex = 0\n\n const client: LoopSandboxClient = {\n async create(_opts?: CreateSandboxOptions): Promise<SandboxInstance> {\n const runId = randomUUID()\n const harness = harnesses[callIndex % harnesses.length] as LocalHarness\n callIndex += 1\n\n const virtual: VirtualSandbox = {\n // Synthesize the minimum SandboxInstance surface the kernel touches.\n // We CAST through unknown because SandboxInstance is a `declare class`\n // with private fields; we're producing a structural subtype that\n // satisfies the kernel's narrow usage (`box.id`, `box.streamPrompt`).\n id: `in-process-${runId}`,\n __inProcess: { runId, harness },\n // eslint-disable-next-line require-yield\n async *streamPrompt(\n this: VirtualSandbox,\n message: string | unknown[],\n promptOpts?: { signal?: AbortSignal },\n ): AsyncGenerator<SandboxEvent> {\n const taskPrompt =\n typeof message === 'string'\n ? message\n : message\n .map((p) =>\n typeof p === 'object' && p && 'text' in p\n ? String((p as { text: unknown }).text)\n : '',\n )\n .join('\\n')\n\n let worktree: WorktreeHandle | undefined\n try {\n worktree = await createWorktree({\n repoRoot: options.repoRoot,\n runId,\n runGit: options.runGit,\n })\n this.__inProcess.worktree = worktree\n\n // Yield a dispatch-equivalent event so traces see the placement.\n yield {\n type: 'in_process.harness.started',\n data: {\n runId,\n harness,\n worktreePath: worktree.path,\n command: harness,\n },\n }\n\n const harnessResult = await runHarness({\n harness,\n cwd: worktree.path,\n taskPrompt,\n timeoutMs: options.harnessTimeoutMs ?? DEFAULT_HARNESS_TIMEOUT_MS,\n signal: promptOpts?.signal,\n })\n\n yield {\n type: 'in_process.harness.ended',\n data: {\n runId,\n exitCode: harnessResult.exitCode,\n durationMs: harnessResult.durationMs,\n killedBySignal: harnessResult.killedBySignal,\n timedOut: harnessResult.timedOut,\n stdoutBytes: harnessResult.stdout.length,\n stderrBytes: harnessResult.stderr.length,\n },\n }\n\n // Capture diff regardless of exit code — a failed run can still\n // leave a partial diff worth inspecting.\n const diff = await captureWorktreeDiff({ worktree, runGit: options.runGit })\n\n // Optional post-checks. Each runs in the WORKTREE so it sees the\n // harness's edits.\n const testCheck = options.testCmd\n ? await runPostCheck(options.testCmd, worktree.path, promptOpts?.signal).catch(\n (err) => ({\n exitCode: -1,\n stdout: '',\n stderr: err instanceof Error ? err.message : String(err),\n }),\n )\n : { exitCode: 0, stdout: '', stderr: '' }\n const typecheckCheck = options.typecheckCmd\n ? await runPostCheck(options.typecheckCmd, worktree.path, promptOpts?.signal).catch(\n (err) => ({\n exitCode: -1,\n stdout: '',\n stderr: err instanceof Error ? err.message : String(err),\n }),\n )\n : { exitCode: 0, stdout: '', stderr: '' }\n\n const coderOutput = {\n branch: worktree.branch,\n patch: diff.patch,\n testResult: {\n passed: !options.testCmd || testCheck.exitCode === 0,\n output: tail(testCheck.stderr || testCheck.stdout, 4000),\n },\n typecheckResult: {\n passed: !options.typecheckCmd || typecheckCheck.exitCode === 0,\n output: tail(typecheckCheck.stderr || typecheckCheck.stdout, 4000),\n },\n diffStats: diff.stats,\n reviewerNotes:\n harnessResult.exitCode === 0\n ? undefined\n : `harness ${harness} exited ${harnessResult.exitCode}${harnessResult.timedOut ? ' (timed out)' : ''}`,\n }\n\n // The terminal event the coderProfile parser looks for.\n yield {\n type: 'result',\n data: {\n result: coderOutput,\n source: 'in-process-executor',\n harness,\n runId,\n },\n }\n } finally {\n if (worktree) {\n await removeWorktree({\n worktree,\n repoRoot: options.repoRoot,\n runGit: options.runGit,\n }).catch(() => undefined)\n }\n }\n },\n } as unknown as VirtualSandbox\n\n return virtual\n },\n describePlacement(box: SandboxInstance): InProcessExecutorDescribePlacement {\n const sandboxId = (box as unknown as { id?: string }).id\n const meta = (box as VirtualSandbox).__inProcess\n return {\n kind: 'sibling',\n sandboxId,\n worktreePath: meta?.worktree?.path,\n harness: meta?.harness,\n }\n },\n }\n\n return {\n client,\n describe(): string {\n return `in-process (repoRoot=${options.repoRoot}, harnesses=[${harnesses.join(',')}]${\n options.testCmd ? `, testCmd=\"${options.testCmd}\"` : ''\n }${options.typecheckCmd ? `, typecheckCmd=\"${options.typecheckCmd}\"` : ''})`\n },\n }\n}\n\nasync function defaultRunPostCheck(\n cmd: string,\n cwd: string,\n signal?: AbortSignal,\n): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n const { spawn } = await import('node:child_process')\n return new Promise((resolve, reject) => {\n // Run via sh -c so multi-word commands (\"pnpm test\") and shell features work.\n const child = spawn('sh', ['-c', cmd], { cwd, stdio: 'pipe' })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (c) => {\n stdout += String(c)\n })\n child.stderr?.on('data', (c) => {\n stderr += String(c)\n })\n if (signal) {\n const onAbort = () => {\n if (!child.killed) child.kill('SIGTERM')\n }\n if (signal.aborted) onAbort()\n else signal.addEventListener('abort', onAbort, { once: true })\n }\n const killTimer = setTimeout(() => {\n if (!child.killed) child.kill('SIGTERM')\n }, DEFAULT_POSTCHECK_TIMEOUT_MS)\n if (typeof (killTimer as { unref?: () => void }).unref === 'function') {\n ;(killTimer as { unref: () => void }).unref()\n }\n child.on('error', (err) => {\n clearTimeout(killTimer)\n reject(err)\n })\n child.on('close', (code) => {\n clearTimeout(killTimer)\n resolve({ exitCode: code ?? -1, stdout, stderr })\n })\n })\n}\n\nfunction tail(text: string, max: number): string {\n if (text.length <= max) return text\n return text.slice(text.length - max)\n}\n","/**\n * @experimental\n *\n * Helpers extracted from `bin.ts` so the env-detection + executor-selection\n * logic is unit-testable without spawning a subprocess. The bin imports from\n * here; tests import from here directly.\n */\n\nimport type { LoopSandboxClient } from '../loops'\nimport {\n createFleetWorkspaceExecutor,\n createSiblingSandboxExecutor,\n type DelegationExecutor,\n type FleetHandle,\n} from './executor'\nimport { createInProcessExecutor } from './in-process-executor'\nimport type { LocalHarness } from './local-harness'\n\n/** @experimental */\nexport interface DetectExecutorArgs {\n sandboxClient: LoopSandboxClient\n /** Raw env (defaults to `process.env`). Pass an explicit map for tests. */\n env?: Record<string, string | undefined>\n /**\n * Override how a fleet handle is resolved from the client + fleet id. The\n * default reads `client.fleets.get(fleetId)` and validates the returned\n * shape against the structural `FleetHandle` contract.\n */\n resolveFleet?: (client: LoopSandboxClient, fleetId: string) => Promise<FleetHandle>\n}\n\n/**\n * Pick the right executor for an MCP server invocation based on env vars.\n *\n * - `TANGLE_FLEET_ID` set → fleet-workspace placement; resolves the handle\n * via `sandboxClient.fleets.get(...)`.\n * - Otherwise → sibling-sandbox placement; each delegation creates a fresh\n * sandbox via `sandboxClient.create(...)`.\n *\n * Fails loud (throws) when fleet mode is requested but the SDK shape is\n * incompatible — the operator chose fleet semantics, silently degrading to\n * sibling mode would lie about workspace topology.\n *\n * @experimental\n */\nexport async function detectExecutor(args: DetectExecutorArgs): Promise<DelegationExecutor> {\n const env = args.env ?? process.env\n\n // In-process (Phase 2.8): parent harness sets AGENT_RUNTIME_IN_SANDBOX=1\n // and points us at the workspace root. Highest-priority — when this is\n // set, delegations spawn local harness CLIs on git worktrees in the\n // SAME filesystem instead of provisioning sibling sandboxes.\n if (env.AGENT_RUNTIME_IN_SANDBOX === '1') {\n const repoRoot = env.AGENT_RUNTIME_REPO_ROOT?.trim()\n if (!repoRoot) {\n throw new Error(\n 'agent-runtime-mcp: AGENT_RUNTIME_IN_SANDBOX=1 requires AGENT_RUNTIME_REPO_ROOT to point at the workspace root',\n )\n }\n return createInProcessExecutor({\n repoRoot,\n harnesses: parseHarnesses(env.AGENT_RUNTIME_LOCAL_HARNESSES),\n testCmd: env.AGENT_RUNTIME_TEST_CMD?.trim() || undefined,\n typecheckCmd: env.AGENT_RUNTIME_TYPECHECK_CMD?.trim() || undefined,\n })\n }\n\n const fleetId = parseFleetId(env.TANGLE_FLEET_ID)\n if (!fleetId) {\n return createSiblingSandboxExecutor({ client: args.sandboxClient })\n }\n const resolveFleet = args.resolveFleet ?? defaultResolveFleet\n const fleet = await resolveFleet(args.sandboxClient, fleetId)\n const excludeMachineIds = parseList(env.TANGLE_FLEET_EXCLUDE_MACHINES)\n return createFleetWorkspaceExecutor({\n fleet,\n excludeMachineIds,\n })\n}\n\nconst KNOWN_HARNESSES: ReadonlyArray<LocalHarness> = ['claude', 'codex', 'opencode']\n\nfunction parseHarnesses(raw: string | undefined): ReadonlyArray<LocalHarness> | undefined {\n if (!raw) return undefined\n const parts = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n if (parts.length === 0) return undefined\n for (const part of parts) {\n if (!KNOWN_HARNESSES.includes(part as LocalHarness)) {\n throw new Error(\n `agent-runtime-mcp: AGENT_RUNTIME_LOCAL_HARNESSES contains unknown harness \"${part}\". Expected: ${KNOWN_HARNESSES.join(', ')}.`,\n )\n }\n }\n return parts as LocalHarness[]\n}\n\ninterface FleetsApi {\n get(fleetId: string): Promise<unknown>\n}\n\nasync function defaultResolveFleet(\n sandboxClient: LoopSandboxClient,\n fleetId: string,\n): Promise<FleetHandle> {\n const fleets = (sandboxClient as unknown as { fleets?: FleetsApi }).fleets\n if (!fleets || typeof fleets.get !== 'function') {\n throw new Error(\n 'agent-runtime-mcp: the configured sandbox client does not expose `.fleets.get`; upgrade @tangle-network/sandbox to >= 0.2.1 or unset TANGLE_FLEET_ID.',\n )\n }\n const raw = await fleets.get(fleetId)\n if (!raw || typeof raw !== 'object') {\n throw new Error(`agent-runtime-mcp: fleets.get(${fleetId}) returned no handle`)\n }\n const handle = raw as Partial<FleetHandle>\n if (typeof handle.fleetId !== 'string' || !Array.isArray(handle.ids)) {\n throw new Error(\n `agent-runtime-mcp: fleet handle for ${fleetId} is missing fleetId/ids — incompatible sandbox SDK shape`,\n )\n }\n if (typeof handle.sandbox !== 'function') {\n throw new Error(\n `agent-runtime-mcp: fleet handle for ${fleetId} is missing sandbox(machineId) — incompatible sandbox SDK shape`,\n )\n }\n return handle as FleetHandle\n}\n\nfunction parseFleetId(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction parseList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const list = raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n return list.length > 0 ? list : undefined\n}\n","/**\n * @experimental\n *\n * Delegate factories — the layer between MCP tool handlers and the\n * underlying `runLoop` runners.\n *\n * The MCP server is profile-agnostic: it owns the task queue + feedback\n * store + transport. Each `*Delegate` is the closure that the queue\n * invokes when a task runs. Consumers can override either delegate to\n * inject custom drivers, mocks, fleet-aware dispatchers, etc.\n *\n * The default coder delegate is wired here because we own\n * `coderProfile` / `multiHarnessCoderFanout`. The default researcher\n * delegate is **not** wired in this file — `agent-knowledge` cannot be\n * imported from `agent-runtime` without inducing a cycle. Consumers\n * pass `researcherDelegate` explicitly when constructing the server.\n */\n\nimport type { LoopSandboxClient } from '../loops'\nimport { runLoop } from '../loops'\nimport { coderProfile, multiHarnessCoderFanout } from '../profiles/coder'\nimport { createSiblingSandboxExecutor, type DelegationExecutor } from './executor'\nimport type {\n CoderTask,\n DelegateCodeArgs,\n DelegateResearchArgs,\n DelegationProgress,\n ResearchOutputShape,\n} from './types'\n\n/** @experimental */\nexport interface DelegateRunCtx {\n signal: AbortSignal\n report(progress: DelegationProgress): void\n}\n\n/** @experimental */\nexport type CoderDelegate = (\n args: DelegateCodeArgs,\n ctx: DelegateRunCtx,\n) => Promise<import('../profiles/coder').CoderOutput>\n\n/** @experimental */\nexport type ResearcherDelegate = (\n args: DelegateResearchArgs,\n ctx: DelegateRunCtx,\n) => Promise<ResearchOutputShape>\n\n/** @experimental */\nexport interface CreateDefaultCoderDelegateOptions {\n /**\n * Execution placement. Pass a {@link DelegationExecutor} (sibling or fleet)\n * to control where worker iterations land. `sandboxClient` is a\n * convenience shorthand that wraps the client in a sibling executor — pass\n * one or the other, not both.\n */\n executor?: DelegationExecutor\n /**\n * Convenience shorthand for sibling placement. Equivalent to\n * `executor: createSiblingSandboxExecutor({ client: sandboxClient })`.\n */\n sandboxClient?: LoopSandboxClient\n /** Default `['claude-code', 'codex', 'opencode/zai-coding-plan/glm-5.1']` when variants > 1. */\n fanoutHarnesses?: string[]\n /** Hard cap on the kernel's per-batch concurrency. Default 4. */\n maxConcurrency?: number\n}\n\n/**\n * Build a coder delegate that drives `runLoop` against the project's\n * sandbox client + coder profile. When `args.variants > 1` it switches\n * to the multi-harness fanout topology.\n *\n * @experimental\n */\nexport function createDefaultCoderDelegate(\n options: CreateDefaultCoderDelegateOptions,\n): CoderDelegate {\n const executor = resolveExecutor(options)\n const sandboxClient = executor.client\n const fanoutHarnesses = options.fanoutHarnesses\n const maxConcurrency = options.maxConcurrency ?? 4\n return async (args, ctx) => {\n const task: CoderTask = {\n goal: buildCoderGoal(args),\n repoRoot: args.repoRoot,\n testCmd: args.config?.testCmd,\n typecheckCmd: args.config?.typecheckCmd,\n forbiddenPaths: args.config?.forbiddenPaths,\n maxDiffLines: args.config?.maxDiffLines,\n }\n const variants = Math.max(1, Math.trunc(args.variants ?? 1))\n ctx.report({ iteration: 0, phase: 'starting' })\n if (variants <= 1) {\n const { agentRunSpec, output, validator } = coderProfile({ task })\n const result = await runLoop({\n driver: singleShotDriver,\n agentRun: agentRunSpec,\n output,\n validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: 1,\n maxConcurrency,\n })\n const winner = result.winner\n if (!winner) {\n throw new Error('coder delegate produced no winner')\n }\n ctx.report({ iteration: 1, phase: 'completed' })\n return winner.output\n }\n const fanout = multiHarnessCoderFanout(\n fanoutHarnesses && fanoutHarnesses.length > 0\n ? { harnesses: fanoutHarnesses.slice(0, variants) }\n : { harnesses: undefined },\n )\n const agentRuns = fanout.agentRuns.slice(0, variants)\n const result = await runLoop({\n driver: fanout.driver,\n agentRuns,\n output: fanout.output,\n validator: fanout.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: variants,\n maxConcurrency: Math.min(maxConcurrency, variants),\n })\n const winner = result.winner\n if (!winner) {\n throw new Error('coder delegate fanout produced no winner')\n }\n ctx.report({ iteration: agentRuns.length, phase: 'completed' })\n return winner.output\n }\n}\n\nfunction buildCoderGoal(args: DelegateCodeArgs): string {\n if (!args.contextHint) return args.goal\n return [args.goal, '', '## Context', args.contextHint].join('\\n')\n}\n\nfunction resolveExecutor(options: CreateDefaultCoderDelegateOptions): DelegationExecutor {\n if (options.executor && options.sandboxClient) {\n throw new Error('createDefaultCoderDelegate: pass exactly one of `executor` or `sandboxClient`')\n }\n if (options.executor) return options.executor\n if (options.sandboxClient) {\n return createSiblingSandboxExecutor({ client: options.sandboxClient })\n }\n throw new Error('createDefaultCoderDelegate: `executor` or `sandboxClient` is required')\n}\n\n/**\n * Single-shot driver — plan one task on iteration 0, stop after one\n * iteration. Used by the coder delegate when `variants <= 1`. Keeps the\n * runLoop kernel-level accounting (timing, cost, trace emission) while\n * skipping fanout/refine topology overhead.\n */\nconst singleShotDriver = {\n name: 'mcp-single-shot',\n async plan<Task>(task: Task, history: ReadonlyArray<unknown>): Promise<Task[]> {\n return history.length === 0 ? [task] : []\n },\n decide(history: ReadonlyArray<unknown>): 'pick-winner' | 'fail' {\n return history.length > 0 ? 'pick-winner' : 'fail'\n },\n}\n","/**\n * @experimental\n *\n * Stdio JSON-RPC MCP server exposing the 5 delegation tools to sandbox\n * coding-harness agents (claude-code, codex, opencode, ...).\n *\n * The server is transport-bound but topology-free: tool execution is\n * delegated to handler functions composed from a queue, a feedback\n * store, and per-profile run delegates. Consumers wire those at\n * construction time. The `agent-runtime-mcp` bin spins up a default\n * configuration for the common case (real sandbox client + coder).\n *\n * Wire protocol: line-delimited JSON-RPC 2.0 over stdio. Each line is\n * one request; each response is one line. `tools/list` and `tools/call`\n * mirror the MCP 2024-11-05 spec; we do not pull in\n * `@modelcontextprotocol/sdk` to keep the dependency footprint zero.\n */\n\nimport { createInterface, type Interface as ReadlineInterface } from 'node:readline'\nimport { Readable, Writable } from 'node:stream'\nimport type { CoderDelegate, ResearcherDelegate } from './delegates'\nimport { type FeedbackStore, InMemoryFeedbackStore } from './feedback-store'\nimport { DelegationTaskQueue } from './task-queue'\nimport {\n createDelegateCodeHandler,\n DELEGATE_CODE_DESCRIPTION,\n DELEGATE_CODE_INPUT_SCHEMA,\n DELEGATE_CODE_TOOL_NAME,\n} from './tools/delegate-code'\nimport {\n createDelegateFeedbackHandler,\n DELEGATE_FEEDBACK_DESCRIPTION,\n DELEGATE_FEEDBACK_INPUT_SCHEMA,\n DELEGATE_FEEDBACK_TOOL_NAME,\n} from './tools/delegate-feedback'\nimport {\n createDelegateResearchHandler,\n DELEGATE_RESEARCH_DESCRIPTION,\n DELEGATE_RESEARCH_INPUT_SCHEMA,\n DELEGATE_RESEARCH_TOOL_NAME,\n} from './tools/delegate-research'\nimport {\n createDelegationHistoryHandler,\n DELEGATION_HISTORY_DESCRIPTION,\n DELEGATION_HISTORY_INPUT_SCHEMA,\n DELEGATION_HISTORY_TOOL_NAME,\n} from './tools/delegation-history'\nimport {\n createDelegationStatusHandler,\n DELEGATION_STATUS_DESCRIPTION,\n DELEGATION_STATUS_INPUT_SCHEMA,\n DELEGATION_STATUS_TOOL_NAME,\n} from './tools/delegation-status'\n\n/** @experimental */\nexport interface McpServerOptions {\n /** Required to enable delegate_code. */\n coderDelegate?: CoderDelegate\n /**\n * Required to enable delegate_research. The substrate cannot ship a\n * default — wire one that closes over your `runLoop` + a\n * researcher profile (typically `@tangle-network/agent-knowledge`'s\n * `researcherProfile` / `multiHarnessResearcherFanout`).\n */\n researcherDelegate?: ResearcherDelegate\n /** Override the default in-memory feedback store. */\n feedbackStore?: FeedbackStore\n /** Override the default in-memory task queue. */\n queue?: DelegationTaskQueue\n /** Server display name surfaced via `initialize`. Default `'agent-runtime-mcp'`. */\n serverName?: string\n /** Server version surfaced via `initialize`. Default = the package version baked at build time. */\n serverVersion?: string\n}\n\n/** @experimental */\nexport interface McpToolDescriptor {\n name: string\n description: string\n inputSchema: Record<string, unknown>\n handler: (raw: unknown) => Promise<unknown>\n}\n\n/** @experimental */\nexport interface McpServer {\n /** Tools currently registered (depend on which delegates were wired). */\n readonly tools: ReadonlyMap<string, McpToolDescriptor>\n /** The underlying queue — exposed so tests can introspect it. */\n readonly queue: DelegationTaskQueue\n /** The feedback store — exposed for the same reason. */\n readonly feedbackStore: FeedbackStore\n /** Handle a single parsed JSON-RPC message. Returns the response object (or `null` for notifications). */\n handle(message: JsonRpcMessage): Promise<JsonRpcResponse | null>\n /** Drive the server on a stdio-shaped transport until `stop()` is called. */\n serve(transport?: McpTransport): Promise<void>\n /** Stop a `serve` call. Subsequent requests are rejected. */\n stop(): void\n}\n\n/** @experimental */\nexport interface McpTransport {\n input: NodeJS.ReadableStream\n output: NodeJS.WritableStream\n}\n\n/** @experimental */\nexport interface JsonRpcMessage {\n jsonrpc: '2.0'\n id?: number | string | null\n method: string\n params?: unknown\n}\n\n/** @experimental */\nexport interface JsonRpcResponse {\n jsonrpc: '2.0'\n id: number | string | null\n result?: unknown\n error?: { code: number; message: string; data?: unknown }\n}\n\nconst PROTOCOL_VERSION = '2024-11-05'\nconst DEFAULT_SERVER_NAME = 'agent-runtime-mcp'\nconst DEFAULT_SERVER_VERSION = '0.22.0'\n\n/** @experimental */\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const queue = options.queue ?? new DelegationTaskQueue()\n const feedbackStore = options.feedbackStore ?? new InMemoryFeedbackStore()\n const serverName = options.serverName ?? DEFAULT_SERVER_NAME\n const serverVersion = options.serverVersion ?? DEFAULT_SERVER_VERSION\n\n const tools = new Map<string, McpToolDescriptor>()\n\n if (options.coderDelegate) {\n tools.set(DELEGATE_CODE_TOOL_NAME, {\n name: DELEGATE_CODE_TOOL_NAME,\n description: DELEGATE_CODE_DESCRIPTION,\n inputSchema: DELEGATE_CODE_INPUT_SCHEMA as unknown as Record<string, unknown>,\n handler: createDelegateCodeHandler({ queue, delegate: options.coderDelegate }),\n })\n }\n if (options.researcherDelegate) {\n tools.set(DELEGATE_RESEARCH_TOOL_NAME, {\n name: DELEGATE_RESEARCH_TOOL_NAME,\n description: DELEGATE_RESEARCH_DESCRIPTION,\n inputSchema: DELEGATE_RESEARCH_INPUT_SCHEMA as unknown as Record<string, unknown>,\n handler: createDelegateResearchHandler({ queue, delegate: options.researcherDelegate }),\n })\n }\n tools.set(DELEGATE_FEEDBACK_TOOL_NAME, {\n name: DELEGATE_FEEDBACK_TOOL_NAME,\n description: DELEGATE_FEEDBACK_DESCRIPTION,\n inputSchema: DELEGATE_FEEDBACK_INPUT_SCHEMA as unknown as Record<string, unknown>,\n handler: createDelegateFeedbackHandler({ queue, store: feedbackStore }),\n })\n tools.set(DELEGATION_STATUS_TOOL_NAME, {\n name: DELEGATION_STATUS_TOOL_NAME,\n description: DELEGATION_STATUS_DESCRIPTION,\n inputSchema: DELEGATION_STATUS_INPUT_SCHEMA as unknown as Record<string, unknown>,\n handler: createDelegationStatusHandler({ queue }),\n })\n tools.set(DELEGATION_HISTORY_TOOL_NAME, {\n name: DELEGATION_HISTORY_TOOL_NAME,\n description: DELEGATION_HISTORY_DESCRIPTION,\n inputSchema: DELEGATION_HISTORY_INPUT_SCHEMA as unknown as Record<string, unknown>,\n handler: createDelegationHistoryHandler({ queue }),\n })\n\n let stopped = false\n let activeReadline: ReadlineInterface | undefined\n\n async function handle(message: JsonRpcMessage): Promise<JsonRpcResponse | null> {\n if (stopped) {\n return rpcError(message.id ?? null, -32099, 'server stopped')\n }\n if (message.method === 'initialize') {\n return rpcResult(message.id ?? null, {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: { tools: {} },\n serverInfo: { name: serverName, version: serverVersion },\n })\n }\n if (message.method === 'notifications/initialized') {\n // MCP clients send this after the handshake; it has no id and expects\n // no response.\n return null\n }\n if (message.method === 'tools/list') {\n return rpcResult(message.id ?? null, {\n tools: [...tools.values()].map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n })\n }\n if (message.method === 'tools/call') {\n const params = (message.params ?? {}) as { name?: unknown; arguments?: unknown }\n const name = typeof params.name === 'string' ? params.name : ''\n const tool = tools.get(name)\n if (!tool) {\n return rpcError(message.id ?? null, -32601, `unknown tool: ${name}`)\n }\n try {\n const output = await tool.handler(params.arguments ?? {})\n return rpcResult(message.id ?? null, {\n content: [{ type: 'text', text: JSON.stringify(output) }],\n structuredContent: output,\n isError: false,\n })\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n const code = err instanceof TypeError || err instanceof RangeError ? -32602 : -32000\n return rpcError(message.id ?? null, code, reason)\n }\n }\n if (message.id === undefined || message.id === null) return null\n return rpcError(message.id, -32601, `unknown method: ${message.method}`)\n }\n\n async function serve(transport?: McpTransport): Promise<void> {\n const input = transport?.input ?? process.stdin\n const output = transport?.output ?? process.stdout\n const rl = createInterface({ input, crlfDelay: Number.POSITIVE_INFINITY })\n activeReadline = rl\n return new Promise<void>((resolve, reject) => {\n rl.on('line', (line) => {\n const trimmed = line.trim()\n if (!trimmed) return\n let parsed: JsonRpcMessage | undefined\n try {\n parsed = JSON.parse(trimmed) as JsonRpcMessage\n } catch (err) {\n writeResponse(output, rpcError(null, -32700, `parse error: ${(err as Error).message}`))\n return\n }\n if (!parsed || parsed.jsonrpc !== '2.0' || typeof parsed.method !== 'string') {\n writeResponse(output, rpcError(parsed?.id ?? null, -32600, 'invalid request'))\n return\n }\n void handle(parsed).then((response) => {\n if (response) writeResponse(output, response)\n })\n })\n rl.on('close', () => resolve())\n rl.on('error', (err) => reject(err))\n if (stopped) {\n rl.close()\n resolve()\n }\n })\n }\n\n function stop(): void {\n stopped = true\n activeReadline?.close()\n activeReadline = undefined\n }\n\n return {\n tools,\n queue,\n feedbackStore,\n handle,\n serve,\n stop,\n }\n}\n\nfunction rpcResult(id: number | string | null, result: unknown): JsonRpcResponse {\n return { jsonrpc: '2.0', id, result }\n}\n\nfunction rpcError(\n id: number | string | null,\n code: number,\n message: string,\n data?: unknown,\n): JsonRpcResponse {\n return {\n jsonrpc: '2.0',\n id,\n error: data === undefined ? { code, message } : { code, message, data },\n }\n}\n\nfunction writeResponse(output: NodeJS.WritableStream, response: JsonRpcResponse): void {\n output.write(`${JSON.stringify(response)}\\n`)\n}\n\n/**\n * In-process pair of `Readable` + `Writable` streams suitable for driving\n * `server.serve(...)` from a test. Returns the agent-side stream (the\n * client writes to it) and the server-side stream (the test reads from it).\n *\n * @experimental\n */\nexport function createInProcessTransport(): {\n transport: McpTransport\n clientWrite(line: string): void\n clientClose(): void\n readServer(): Promise<JsonRpcResponse[]>\n} {\n const responses: JsonRpcResponse[] = []\n const input = new Readable({ read() {} })\n const output = new Writable({\n write(chunk, _enc, cb) {\n const text = chunk.toString('utf8')\n for (const line of text.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n responses.push(JSON.parse(trimmed) as JsonRpcResponse)\n } catch {\n // Non-JSON output should never appear; drop it silently in the\n // test transport rather than crashing.\n }\n }\n cb()\n },\n })\n return {\n transport: { input, output },\n clientWrite(line: string) {\n input.push(`${line}\\n`)\n },\n clientClose() {\n input.push(null)\n },\n async readServer() {\n // Yield to the event loop a few times so async handlers drain.\n for (let i = 0; i < 5; i += 1) await new Promise((r) => setImmediate(r))\n return [...responses]\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CO,SAAS,6BACd,SACoB;AACpB,QAAM,aAAa,QAAQ;AAC3B,QAAM,SAA4B;AAAA,IAChC,OAAO,MAAuD;AAC5D,aAAO,WAAW,OAAO,IAAI;AAAA,IAC/B;AAAA,IACA,kBAAkB,KAA4C;AAC5D,aAAO,EAAE,MAAM,WAAW,WAAW,OAAO,GAAG,EAAE;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,WAAmB;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AA2CO,SAAS,6BACd,SACoB;AACpB,QAAM,QAAQ,QAAQ;AACtB,QAAM,UAAU,IAAI,IAAI,QAAQ,qBAAqB,CAAC,CAAC;AACvD,MAAI,YAAY;AAIhB,QAAM,uBAAuB,oBAAI,IAAmC;AAEpE,QAAM,SAA4B;AAAA,IAChC,MAAM,SAAmC;AACvC,YAAM,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AACrD,UAAI,IAAI,WAAW,GAAG;AACpB,cAAM,IAAI;AAAA,UACR,wBAAwB,MAAM,OAAO,0CAA0C,MAAM,IAAI,KAAK,GAAG,CAAC,gBAAgB,CAAC,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC;AAAA,QAC1I;AAAA,MACF;AACA,YAAM,WAAW,QAAQ;AACzB,YAAM,YAAY,WAAW,SAAS,EAAE,WAAW,IAAI,CAAC,IAAI,IAAI,YAAY,IAAI,MAAM;AACtF,mBAAa;AACb,UAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GAAG;AAC3D,cAAM,IAAI,MAAM,0EAA0E;AAAA,MAC5F;AACA,YAAM,MAAM,MAAM,MAAM,QAAQ,SAAS;AACzC,YAAM,YAAY,OAAO,GAAG;AAC5B,UAAI,UAAW,sBAAqB,IAAI,WAAW,EAAE,UAAU,CAAC;AAChE,aAAO;AAAA,IACT;AAAA,IACA,kBAAkB,KAA4C;AAC5D,YAAM,YAAY,OAAO,GAAG;AAC5B,YAAM,WAAW,YAAY,qBAAqB,IAAI,SAAS,IAAI;AACnE,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,SAAS,MAAM;AAAA,QACf,WAAW,UAAU;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAmB;AACjB,YAAM,WAAW,QAAQ,OAAO,IAAI,eAAe,CAAC,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,OAAO;AAChF,aAAO,4BAA4B,MAAM,OAAO,eAAe,MAAM,IAAI,KAAK,GAAG,CAAC,IAAI,QAAQ;AAAA,IAChG;AAAA,EACF;AACF;AAEA,SAAS,OAAO,KAA0C;AACxD,QAAM,MAAO,IAAoC;AACjD,SAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,IAAI,MAAM;AAC3D;;;AChJA,SAAS,aAAa;AA8DtB,eAAe,YACb,MACA,KACA,QAC+D;AAC/D,MAAI,OAAQ,QAAO,OAAO,MAAM,EAAE,IAAI,CAAC;AACvC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,MAAM,OAAO,MAAM,EAAE,KAAK,OAAO,OAAO,CAAC;AACtD,QAAI,SAAS;AACb,QAAI,SAAS;AACb,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAM;AAC7B,gBAAU,OAAO,CAAC;AAAA,IACpB,CAAC;AACD,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAM;AAC7B,gBAAU,OAAO,CAAC;AAAA,IACpB,CAAC;AACD,SAAK,GAAG,SAAS,MAAM;AACvB,SAAK,GAAG,SAAS,CAAC,SAAS,QAAQ,EAAE,QAAQ,QAAQ,UAAU,QAAQ,GAAG,CAAC,CAAC;AAAA,EAC9E,CAAC;AACH;AAEA,SAAS,YACP,MACA,QACM;AACN,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI;AAAA,MACR,iBAAiB,IAAI,iBAAiB,OAAO,QAAQ,MAAM,OAAO,OAAO,MAAM,GAAG,GAAG,CAAC;AAAA,IACxF;AAAA,EACF;AACF;AAGA,eAAsB,eAAe,SAAyD;AAC5F,QAAM,WAAW,QAAQ,eAAe;AACxC,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,SAAS,YAAY,QAAQ,KAAK;AACxC,QAAM,OAAO,GAAG,QAAQ,SAAS,QAAQ,QAAQ,EAAE,CAAC,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAEjF,QAAM,UAAU,MAAM,YAAY,CAAC,aAAa,OAAO,GAAG,QAAQ,UAAU,QAAQ,MAAM;AAC1F,cAAY,aAAa,OAAO,IAAI,OAAO;AAE3C,QAAM,MAAM,MAAM;AAAA,IAChB,CAAC,YAAY,OAAO,MAAM,QAAQ,MAAM,OAAO;AAAA,IAC/C,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,cAAY,gBAAgB,IAAI,IAAI,GAAG;AAEvC,SAAO,EAAE,MAAM,SAAS,QAAQ,OAAO,KAAK,GAAG,OAAO;AACxD;AAGA,eAAsB,oBAAoB,SAA2C;AACnF,QAAM,UAAU,QAAQ,WAAW,QAAQ,SAAS;AACpD,QAAM,QAAQ,MAAM,YAAY,CAAC,QAAQ,OAAO,GAAG,QAAQ,SAAS,MAAM,QAAQ,MAAM;AAIxF,QAAM,YAAY,MAAM;AAAA,IACtB,CAAC,QAAQ,eAAe,OAAO;AAAA,IAC/B,QAAQ,SAAS;AAAA,IACjB,QAAQ;AAAA,EACV;AACA,QAAM,QAAQ,eAAe,UAAU,MAAM;AAC7C,SAAO,EAAE,OAAO,MAAM,QAAQ,MAAM;AACtC;AAEA,SAAS,eAAe,MAAmC;AAIzD,QAAM,MAAM,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,EAAE;AAC3D,QAAM,aAAa,KAAK,MAAM,0BAA0B;AACxD,MAAI,aAAa,CAAC,EAAG,KAAI,eAAe,OAAO,WAAW,CAAC,CAAC;AAC5D,QAAM,cAAc,KAAK,MAAM,qBAAqB;AACpD,MAAI,cAAc,CAAC,EAAG,KAAI,aAAa,OAAO,YAAY,CAAC,CAAC;AAC5D,QAAM,cAAc,KAAK,MAAM,oBAAoB;AACnD,MAAI,cAAc,CAAC,EAAG,KAAI,YAAY,OAAO,YAAY,CAAC,CAAC;AAC3D,SAAO;AACT;AAGA,eAAsB,eAAe,SAA+C;AAClF,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,OAAO,CAAC,YAAY,QAAQ;AAClC,MAAI,MAAO,MAAK,KAAK,SAAS;AAC9B,OAAK,KAAK,QAAQ,SAAS,IAAI;AAC/B,QAAM,SAAS,MAAM,YAAY,MAAM,QAAQ,UAAU,QAAQ,MAAM;AAGvE,MAAI,OAAO,aAAa,KAAK,CAAC,qBAAqB,KAAK,OAAO,MAAM,GAAG;AAEtE,UAAM;AAAA,MACJ,CAAC,UAAU,MAAM,QAAQ,SAAS,MAAM;AAAA,MACxC,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,EAAE,MAAM,MAAM,MAAS;AAAA,EACzB;AAGA,QAAM;AAAA,IACJ,CAAC,UAAU,MAAM,QAAQ,SAAS,MAAM;AAAA,IACxC,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,EAAE,MAAM,MAAM,MAAS;AACzB;;;ACrJA,SAAS,kBAAkB;AA+E3B,IAAM,6BAA6B,IAAI,KAAK;AAC5C,IAAM,+BAA+B,IAAI,KAAK;AAevC,SAAS,wBAAwB,SAAuD;AAC7F,QAAM,YACJ,QAAQ,aAAa,QAAQ,UAAU,SAAS,IAC5C,CAAC,GAAG,QAAQ,SAAS,IACpB,CAAC,QAAQ;AAChB,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,eAAe,QAAQ,gBAAgB;AAE7C,MAAI,YAAY;AAEhB,QAAM,SAA4B;AAAA,IAChC,MAAM,OAAO,OAAwD;AACnE,YAAM,QAAQ,WAAW;AACzB,YAAM,UAAU,UAAU,YAAY,UAAU,MAAM;AACtD,mBAAa;AAEb,YAAM,UAA0B;AAAA;AAAA;AAAA;AAAA;AAAA,QAK9B,IAAI,cAAc,KAAK;AAAA,QACvB,aAAa,EAAE,OAAO,QAAQ;AAAA;AAAA,QAE9B,OAAO,aAEL,SACA,YAC8B;AAC9B,gBAAM,aACJ,OAAO,YAAY,WACf,UACA,QACG;AAAA,YAAI,CAAC,MACJ,OAAO,MAAM,YAAY,KAAK,UAAU,IACpC,OAAQ,EAAwB,IAAI,IACpC;AAAA,UACN,EACC,KAAK,IAAI;AAElB,cAAI;AACJ,cAAI;AACF,uBAAW,MAAM,eAAe;AAAA,cAC9B,UAAU,QAAQ;AAAA,cAClB;AAAA,cACA,QAAQ,QAAQ;AAAA,YAClB,CAAC;AACD,iBAAK,YAAY,WAAW;AAG5B,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,gBACA,cAAc,SAAS;AAAA,gBACvB,SAAS;AAAA,cACX;AAAA,YACF;AAEA,kBAAM,gBAAgB,MAAM,WAAW;AAAA,cACrC;AAAA,cACA,KAAK,SAAS;AAAA,cACd;AAAA,cACA,WAAW,QAAQ,oBAAoB;AAAA,cACvC,QAAQ,YAAY;AAAA,YACtB,CAAC;AAED,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,MAAM;AAAA,gBACJ;AAAA,gBACA,UAAU,cAAc;AAAA,gBACxB,YAAY,cAAc;AAAA,gBAC1B,gBAAgB,cAAc;AAAA,gBAC9B,UAAU,cAAc;AAAA,gBACxB,aAAa,cAAc,OAAO;AAAA,gBAClC,aAAa,cAAc,OAAO;AAAA,cACpC;AAAA,YACF;AAIA,kBAAM,OAAO,MAAM,oBAAoB,EAAE,UAAU,QAAQ,QAAQ,OAAO,CAAC;AAI3E,kBAAM,YAAY,QAAQ,UACtB,MAAM,aAAa,QAAQ,SAAS,SAAS,MAAM,YAAY,MAAM,EAAE;AAAA,cACrE,CAAC,SAAS;AAAA,gBACR,UAAU;AAAA,gBACV,QAAQ;AAAA,gBACR,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,cACzD;AAAA,YACF,IACA,EAAE,UAAU,GAAG,QAAQ,IAAI,QAAQ,GAAG;AAC1C,kBAAM,iBAAiB,QAAQ,eAC3B,MAAM,aAAa,QAAQ,cAAc,SAAS,MAAM,YAAY,MAAM,EAAE;AAAA,cAC1E,CAAC,SAAS;AAAA,gBACR,UAAU;AAAA,gBACV,QAAQ;AAAA,gBACR,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,cACzD;AAAA,YACF,IACA,EAAE,UAAU,GAAG,QAAQ,IAAI,QAAQ,GAAG;AAE1C,kBAAM,cAAc;AAAA,cAClB,QAAQ,SAAS;AAAA,cACjB,OAAO,KAAK;AAAA,cACZ,YAAY;AAAA,gBACV,QAAQ,CAAC,QAAQ,WAAW,UAAU,aAAa;AAAA,gBACnD,QAAQ,KAAK,UAAU,UAAU,UAAU,QAAQ,GAAI;AAAA,cACzD;AAAA,cACA,iBAAiB;AAAA,gBACf,QAAQ,CAAC,QAAQ,gBAAgB,eAAe,aAAa;AAAA,gBAC7D,QAAQ,KAAK,eAAe,UAAU,eAAe,QAAQ,GAAI;AAAA,cACnE;AAAA,cACA,WAAW,KAAK;AAAA,cAChB,eACE,cAAc,aAAa,IACvB,SACA,WAAW,OAAO,WAAW,cAAc,QAAQ,GAAG,cAAc,WAAW,iBAAiB,EAAE;AAAA,YAC1G;AAGA,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,MAAM;AAAA,gBACJ,QAAQ;AAAA,gBACR,QAAQ;AAAA,gBACR;AAAA,gBACA;AAAA,cACF;AAAA,YACF;AAAA,UACF,UAAE;AACA,gBAAI,UAAU;AACZ,oBAAM,eAAe;AAAA,gBACnB;AAAA,gBACA,UAAU,QAAQ;AAAA,gBAClB,QAAQ,QAAQ;AAAA,cAClB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,YAC1B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IACA,kBAAkB,KAA0D;AAC1E,YAAM,YAAa,IAAmC;AACtD,YAAM,OAAQ,IAAuB;AACrC,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,cAAc,MAAM,UAAU;AAAA,QAC9B,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAmB;AACjB,aAAO,wBAAwB,QAAQ,QAAQ,gBAAgB,UAAU,KAAK,GAAG,CAAC,IAChF,QAAQ,UAAU,cAAc,QAAQ,OAAO,MAAM,EACvD,GAAG,QAAQ,eAAe,mBAAmB,QAAQ,YAAY,MAAM,EAAE;AAAA,IAC3E;AAAA,EACF;AACF;AAEA,eAAe,oBACb,KACA,KACA,QAC+D;AAC/D,QAAM,EAAE,OAAAA,OAAM,IAAI,MAAM,OAAO,eAAoB;AACnD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,UAAM,QAAQA,OAAM,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,KAAK,OAAO,OAAO,CAAC;AAC7D,QAAI,SAAS;AACb,QAAI,SAAS;AACb,UAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM;AAC9B,gBAAU,OAAO,CAAC;AAAA,IACpB,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM;AAC9B,gBAAU,OAAO,CAAC;AAAA,IACpB,CAAC;AACD,QAAI,QAAQ;AACV,YAAM,UAAU,MAAM;AACpB,YAAI,CAAC,MAAM,OAAQ,OAAM,KAAK,SAAS;AAAA,MACzC;AACA,UAAI,OAAO,QAAS,SAAQ;AAAA,UACvB,QAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAC/D;AACA,UAAM,YAAY,WAAW,MAAM;AACjC,UAAI,CAAC,MAAM,OAAQ,OAAM,KAAK,SAAS;AAAA,IACzC,GAAG,4BAA4B;AAC/B,QAAI,OAAQ,UAAqC,UAAU,YAAY;AACrE;AAAC,MAAC,UAAoC,MAAM;AAAA,IAC9C;AACA,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,mBAAa,SAAS;AACtB,aAAO,GAAG;AAAA,IACZ,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,mBAAa,SAAS;AACtB,cAAQ,EAAE,UAAU,QAAQ,IAAI,QAAQ,OAAO,CAAC;AAAA,IAClD,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,KAAK,MAAc,KAAqB;AAC/C,MAAI,KAAK,UAAU,IAAK,QAAO;AAC/B,SAAO,KAAK,MAAM,KAAK,SAAS,GAAG;AACrC;;;AC3SA,eAAsB,eAAe,MAAuD;AAC1F,QAAM,MAAM,KAAK,OAAO,QAAQ;AAMhC,MAAI,IAAI,6BAA6B,KAAK;AACxC,UAAM,WAAW,IAAI,yBAAyB,KAAK;AACnD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,wBAAwB;AAAA,MAC7B;AAAA,MACA,WAAW,eAAe,IAAI,6BAA6B;AAAA,MAC3D,SAAS,IAAI,wBAAwB,KAAK,KAAK;AAAA,MAC/C,cAAc,IAAI,6BAA6B,KAAK,KAAK;AAAA,IAC3D,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,aAAa,IAAI,eAAe;AAChD,MAAI,CAAC,SAAS;AACZ,WAAO,6BAA6B,EAAE,QAAQ,KAAK,cAAc,CAAC;AAAA,EACpE;AACA,QAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAM,QAAQ,MAAM,aAAa,KAAK,eAAe,OAAO;AAC5D,QAAM,oBAAoB,UAAU,IAAI,6BAA6B;AACrE,SAAO,6BAA6B;AAAA,IAClC;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,IAAM,kBAA+C,CAAC,UAAU,SAAS,UAAU;AAEnF,SAAS,eAAe,KAAkE;AACxF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IACX,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,gBAAgB,SAAS,IAAoB,GAAG;AACnD,YAAM,IAAI;AAAA,QACR,8EAA8E,IAAI,gBAAgB,gBAAgB,KAAK,IAAI,CAAC;AAAA,MAC9H;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,eAAe,oBACb,eACA,SACsB;AACtB,QAAM,SAAU,cAAoD;AACpE,MAAI,CAAC,UAAU,OAAO,OAAO,QAAQ,YAAY;AAC/C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,MAAM,OAAO,IAAI,OAAO;AACpC,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,MAAM,iCAAiC,OAAO,sBAAsB;AAAA,EAChF;AACA,QAAM,SAAS;AACf,MAAI,OAAO,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,GAAG,GAAG;AACpE,UAAM,IAAI;AAAA,MACR,uCAAuC,OAAO;AAAA,IAChD;AAAA,EACF;AACA,MAAI,OAAO,OAAO,YAAY,YAAY;AACxC,UAAM,IAAI;AAAA,MACR,uCAAuC,OAAO;AAAA,IAChD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,KAA6C;AACjE,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,UAAU,IAAI,KAAK;AACzB,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAEA,SAAS,UAAU,KAA+C;AAChE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,IACV,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,OAAO;AACjB,SAAO,KAAK,SAAS,IAAI,OAAO;AAClC;;;ACrEO,SAAS,2BACd,SACe;AACf,QAAM,WAAW,gBAAgB,OAAO;AACxC,QAAM,gBAAgB,SAAS;AAC/B,QAAM,kBAAkB,QAAQ;AAChC,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,SAAO,OAAO,MAAM,QAAQ;AAC1B,UAAM,OAAkB;AAAA,MACtB,MAAM,eAAe,IAAI;AAAA,MACzB,UAAU,KAAK;AAAA,MACf,SAAS,KAAK,QAAQ;AAAA,MACtB,cAAc,KAAK,QAAQ;AAAA,MAC3B,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,cAAc,KAAK,QAAQ;AAAA,IAC7B;AACA,UAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,YAAY,CAAC,CAAC;AAC3D,QAAI,OAAO,EAAE,WAAW,GAAG,OAAO,WAAW,CAAC;AAC9C,QAAI,YAAY,GAAG;AACjB,YAAM,EAAE,cAAc,QAAQ,UAAU,IAAI,aAAa,EAAE,KAAK,CAAC;AACjE,YAAMC,UAAS,MAAM,QAAQ;AAAA,QAC3B,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,EAAE,eAAe,QAAQ,IAAI,OAAO;AAAA,QACzC,eAAe;AAAA,QACf;AAAA,MACF,CAAC;AACD,YAAMC,UAASD,QAAO;AACtB,UAAI,CAACC,SAAQ;AACX,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AACA,UAAI,OAAO,EAAE,WAAW,GAAG,OAAO,YAAY,CAAC;AAC/C,aAAOA,QAAO;AAAA,IAChB;AACA,UAAM,SAAS;AAAA,MACb,mBAAmB,gBAAgB,SAAS,IACxC,EAAE,WAAW,gBAAgB,MAAM,GAAG,QAAQ,EAAE,IAChD,EAAE,WAAW,OAAU;AAAA,IAC7B;AACA,UAAM,YAAY,OAAO,UAAU,MAAM,GAAG,QAAQ;AACpD,UAAM,SAAS,MAAM,QAAQ;AAAA,MAC3B,QAAQ,OAAO;AAAA,MACf;AAAA,MACA,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB;AAAA,MACA,KAAK,EAAE,eAAe,QAAQ,IAAI,OAAO;AAAA,MACzC,eAAe;AAAA,MACf,gBAAgB,KAAK,IAAI,gBAAgB,QAAQ;AAAA,IACnD,CAAC;AACD,UAAM,SAAS,OAAO;AACtB,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,QAAI,OAAO,EAAE,WAAW,UAAU,QAAQ,OAAO,YAAY,CAAC;AAC9D,WAAO,OAAO;AAAA,EAChB;AACF;AAEA,SAAS,eAAe,MAAgC;AACtD,MAAI,CAAC,KAAK,YAAa,QAAO,KAAK;AACnC,SAAO,CAAC,KAAK,MAAM,IAAI,cAAc,KAAK,WAAW,EAAE,KAAK,IAAI;AAClE;AAEA,SAAS,gBAAgB,SAAgE;AACvF,MAAI,QAAQ,YAAY,QAAQ,eAAe;AAC7C,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AACA,MAAI,QAAQ,SAAU,QAAO,QAAQ;AACrC,MAAI,QAAQ,eAAe;AACzB,WAAO,6BAA6B,EAAE,QAAQ,QAAQ,cAAc,CAAC;AAAA,EACvE;AACA,QAAM,IAAI,MAAM,uEAAuE;AACzF;AAQA,IAAM,mBAAmB;AAAA,EACvB,MAAM;AAAA,EACN,MAAM,KAAW,MAAY,SAAkD;AAC7E,WAAO,QAAQ,WAAW,IAAI,CAAC,IAAI,IAAI,CAAC;AAAA,EAC1C;AAAA,EACA,OAAO,SAAyD;AAC9D,WAAO,QAAQ,SAAS,IAAI,gBAAgB;AAAA,EAC9C;AACF;;;ACrJA,SAAS,uBAA4D;AACrE,SAAS,UAAU,gBAAgB;AAsGnC,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAGxB,SAAS,gBAAgB,UAA4B,CAAC,GAAc;AACzE,QAAM,QAAQ,QAAQ,SAAS,IAAI,oBAAoB;AACvD,QAAM,gBAAgB,QAAQ,iBAAiB,IAAI,sBAAsB;AACzE,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,gBAAgB,QAAQ,iBAAiB;AAE/C,QAAM,QAAQ,oBAAI,IAA+B;AAEjD,MAAI,QAAQ,eAAe;AACzB,UAAM,IAAI,yBAAyB;AAAA,MACjC,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,SAAS,0BAA0B,EAAE,OAAO,UAAU,QAAQ,cAAc,CAAC;AAAA,IAC/E,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,oBAAoB;AAC9B,UAAM,IAAI,6BAA6B;AAAA,MACrC,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,SAAS,8BAA8B,EAAE,OAAO,UAAU,QAAQ,mBAAmB,CAAC;AAAA,IACxF,CAAC;AAAA,EACH;AACA,QAAM,IAAI,6BAA6B;AAAA,IACrC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS,8BAA8B,EAAE,OAAO,OAAO,cAAc,CAAC;AAAA,EACxE,CAAC;AACD,QAAM,IAAI,6BAA6B;AAAA,IACrC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS,8BAA8B,EAAE,MAAM,CAAC;AAAA,EAClD,CAAC;AACD,QAAM,IAAI,8BAA8B;AAAA,IACtC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS,+BAA+B,EAAE,MAAM,CAAC;AAAA,EACnD,CAAC;AAED,MAAI,UAAU;AACd,MAAI;AAEJ,iBAAe,OAAO,SAA0D;AAC9E,QAAI,SAAS;AACX,aAAO,SAAS,QAAQ,MAAM,MAAM,QAAQ,gBAAgB;AAAA,IAC9D;AACA,QAAI,QAAQ,WAAW,cAAc;AACnC,aAAO,UAAU,QAAQ,MAAM,MAAM;AAAA,QACnC,iBAAiB;AAAA,QACjB,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,QAC1B,YAAY,EAAE,MAAM,YAAY,SAAS,cAAc;AAAA,MACzD,CAAC;AAAA,IACH;AACA,QAAI,QAAQ,WAAW,6BAA6B;AAGlD,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,WAAW,cAAc;AACnC,aAAO,UAAU,QAAQ,MAAM,MAAM;AAAA,QACnC,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU;AAAA,UACxC,MAAM,KAAK;AAAA,UACX,aAAa,KAAK;AAAA,UAClB,aAAa,KAAK;AAAA,QACpB,EAAE;AAAA,MACJ,CAAC;AAAA,IACH;AACA,QAAI,QAAQ,WAAW,cAAc;AACnC,YAAM,SAAU,QAAQ,UAAU,CAAC;AACnC,YAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAC7D,YAAM,OAAO,MAAM,IAAI,IAAI;AAC3B,UAAI,CAAC,MAAM;AACT,eAAO,SAAS,QAAQ,MAAM,MAAM,QAAQ,iBAAiB,IAAI,EAAE;AAAA,MACrE;AACA,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,aAAa,CAAC,CAAC;AACxD,eAAO,UAAU,QAAQ,MAAM,MAAM;AAAA,UACnC,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,EAAE,CAAC;AAAA,UACxD,mBAAmB;AAAA,UACnB,SAAS;AAAA,QACX,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,cAAM,OAAO,eAAe,aAAa,eAAe,aAAa,SAAS;AAC9E,eAAO,SAAS,QAAQ,MAAM,MAAM,MAAM,MAAM;AAAA,MAClD;AAAA,IACF;AACA,QAAI,QAAQ,OAAO,UAAa,QAAQ,OAAO,KAAM,QAAO;AAC5D,WAAO,SAAS,QAAQ,IAAI,QAAQ,mBAAmB,QAAQ,MAAM,EAAE;AAAA,EACzE;AAEA,iBAAe,MAAM,WAAyC;AAC5D,UAAM,QAAQ,WAAW,SAAS,QAAQ;AAC1C,UAAM,SAAS,WAAW,UAAU,QAAQ;AAC5C,UAAM,KAAK,gBAAgB,EAAE,OAAO,WAAW,OAAO,kBAAkB,CAAC;AACzE,qBAAiB;AACjB,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,SAAG,GAAG,QAAQ,CAAC,SAAS;AACtB,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,CAAC,QAAS;AACd,YAAI;AACJ,YAAI;AACF,mBAAS,KAAK,MAAM,OAAO;AAAA,QAC7B,SAAS,KAAK;AACZ,wBAAc,QAAQ,SAAS,MAAM,QAAQ,gBAAiB,IAAc,OAAO,EAAE,CAAC;AACtF;AAAA,QACF;AACA,YAAI,CAAC,UAAU,OAAO,YAAY,SAAS,OAAO,OAAO,WAAW,UAAU;AAC5E,wBAAc,QAAQ,SAAS,QAAQ,MAAM,MAAM,QAAQ,iBAAiB,CAAC;AAC7E;AAAA,QACF;AACA,aAAK,OAAO,MAAM,EAAE,KAAK,CAAC,aAAa;AACrC,cAAI,SAAU,eAAc,QAAQ,QAAQ;AAAA,QAC9C,CAAC;AAAA,MACH,CAAC;AACD,SAAG,GAAG,SAAS,MAAM,QAAQ,CAAC;AAC9B,SAAG,GAAG,SAAS,CAAC,QAAQ,OAAO,GAAG,CAAC;AACnC,UAAI,SAAS;AACX,WAAG,MAAM;AACT,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,OAAa;AACpB,cAAU;AACV,oBAAgB,MAAM;AACtB,qBAAiB;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,UAAU,IAA4B,QAAkC;AAC/E,SAAO,EAAE,SAAS,OAAO,IAAI,OAAO;AACtC;AAEA,SAAS,SACP,IACA,MACA,SACA,MACiB;AACjB,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,OAAO,SAAS,SAAY,EAAE,MAAM,QAAQ,IAAI,EAAE,MAAM,SAAS,KAAK;AAAA,EACxE;AACF;AAEA,SAAS,cAAc,QAA+B,UAAiC;AACrF,SAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,CAAI;AAC9C;AASO,SAAS,2BAKd;AACA,QAAM,YAA+B,CAAC;AACtC,QAAM,QAAQ,IAAI,SAAS,EAAE,OAAO;AAAA,EAAC,EAAE,CAAC;AACxC,QAAM,SAAS,IAAI,SAAS;AAAA,IAC1B,MAAM,OAAO,MAAM,IAAI;AACrB,YAAM,OAAO,MAAM,SAAS,MAAM;AAClC,iBAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,CAAC,QAAS;AACd,YAAI;AACF,oBAAU,KAAK,KAAK,MAAM,OAAO,CAAoB;AAAA,QACvD,QAAQ;AAAA,QAGR;AAAA,MACF;AACA,SAAG;AAAA,IACL;AAAA,EACF,CAAC;AACD,SAAO;AAAA,IACL,WAAW,EAAE,OAAO,OAAO;AAAA,IAC3B,YAAY,MAAc;AACxB,YAAM,KAAK,GAAG,IAAI;AAAA,CAAI;AAAA,IACxB;AAAA,IACA,cAAc;AACZ,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,IACA,MAAM,aAAa;AAEjB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK,EAAG,OAAM,IAAI,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;AACvE,aAAO,CAAC,GAAG,SAAS;AAAA,IACtB;AAAA,EACF;AACF;","names":["spawn","result","winner"]}
@@ -0,0 +1,207 @@
1
+ import { FindingSubject, AnalystFinding } from '@tangle-network/agent-eval';
2
+ import { I as ImprovementAdapter } from './types-D_MXrmJP.js';
3
+
4
+ /**
5
+ * `AgentSurfaces` — declarative map of the mutable file/directory paths
6
+ * the self-improvement loop can edit on behalf of an agent.
7
+ *
8
+ * The substrate uses this map to resolve every parsed `FindingSubject`
9
+ * (from agent-eval) to a real on-disk path. No per-vertical glue;
10
+ * no fabricated paths; no silent `existsSync(...)` skips that hide
11
+ * misconfiguration from the operator.
12
+ *
13
+ * Surfaces are validated at `defineAgent` time — missing paths fail
14
+ * loud with a list of every offender. A surface that's not needed
15
+ * (e.g. an agent with no RAG corpora) is simply omitted; the loop
16
+ * refuses to route those subjects rather than fabricating a target.
17
+ */
18
+
19
+ /**
20
+ * Surface declarations. Every path is repo-relative (or absolute) at
21
+ * `defineAgent` time. At resolution time, paths are joined against the
22
+ * agent's `repoRoot`.
23
+ *
24
+ * `systemPrompt`, `tools`, `personas` are DIRECTORIES; the loop appends
25
+ * `<section>.md`, `<tool>/README.md`, `<persona-id>.yaml` etc.
26
+ * `rubric`, `outputSchema` are SINGLE FILES; the loop edits them in
27
+ * place.
28
+ *
29
+ * `knowledge` is the agent-knowledge root (typically `.agent-knowledge`);
30
+ * `applyKnowledgeWriteBlocks` writes pages relative to it.
31
+ *
32
+ * Optional surfaces (`scaffolding`, `memory`, `rag`, `outputSchema`)
33
+ * can be omitted — the loop will reject findings targeting them with a
34
+ * clear log message instead of fabricating a path.
35
+ */
36
+ interface AgentSurfaces {
37
+ /** Directory containing one markdown file per system-prompt section. */
38
+ systemPrompt: string;
39
+ /** Directory containing one subdir per tool (`<tool>/README.md`). */
40
+ tools: string;
41
+ /** Single file (TypeScript module) defining the rubric weights + dimensions. */
42
+ rubric: string;
43
+ /** Knowledge-base root; typically `.agent-knowledge`. */
44
+ knowledge: string;
45
+ /** Directory containing one YAML/JSON file per persona. */
46
+ personas: string;
47
+ /** Optional: directory containing scaffolding rules (precondition checks, retry policies). */
48
+ scaffolding?: string;
49
+ /** Optional: memory store path (JSONL / SQLite / DB). */
50
+ memory?: string;
51
+ /** Optional: directory containing RAG corpora (`<corpus>/<doc-id>.md`). */
52
+ rag?: string;
53
+ /** Optional: single file defining the output schema (Zod / JSON Schema). */
54
+ outputSchema?: string;
55
+ }
56
+ interface ResolvedSurface {
57
+ /** Absolute filesystem path the operator can `cat` / `vim`. */
58
+ absolutePath: string;
59
+ /** Repo-relative path for PR descriptions, diffs, audit logs. */
60
+ repoRelativePath: string;
61
+ /** Whether the path currently exists on disk. */
62
+ exists: boolean;
63
+ /** The substrate's intent: edit an existing file or create a new one. */
64
+ intent: 'edit-existing' | 'create-new';
65
+ }
66
+ /**
67
+ * Resolve a parsed `FindingSubject` to the file path the substrate
68
+ * should edit (or create) on disk.
69
+ *
70
+ * Returns `null` when:
71
+ * - the subject targets a surface the agent didn't declare
72
+ * (e.g. `rag:*` when `surfaces.rag` is undefined), OR
73
+ * - the subject is a `cluster` (failure-mode emits these as evidence,
74
+ * not actionable mutations — they don't route to a file).
75
+ *
76
+ * Returns a `ResolvedSurface` with `intent: 'create-new'` when the
77
+ * subject names a path that doesn't yet exist (e.g. a new wiki page).
78
+ * The caller chooses whether to honour the create — for tightly-managed
79
+ * surfaces like `systemPrompt` it's usually a contract violation
80
+ * (the analyst named a section that doesn't exist); for `knowledge`
81
+ * it's the whole point.
82
+ */
83
+ declare function resolveSubjectPath(subject: FindingSubject, surfaces: AgentSurfaces, repoRoot: string): ResolvedSurface | null;
84
+ /**
85
+ * Validate that every declared surface exists on disk under `repoRoot`.
86
+ *
87
+ * Returns an array of `SurfaceValidationIssue` — empty when all required
88
+ * surfaces resolve. `defineAgent` throws with the issues rendered, so
89
+ * a misconfigured manifest fails at startup (not at the first finding
90
+ * the loop produces 20 minutes later).
91
+ */
92
+ interface SurfaceValidationIssue {
93
+ surface: keyof AgentSurfaces;
94
+ path: string;
95
+ reason: 'missing' | 'not-directory' | 'not-file';
96
+ }
97
+ declare function validateSurfaces(surfaces: AgentSurfaces, repoRoot: string): ReadonlyArray<SurfaceValidationIssue>;
98
+ declare function renderSurfaceIssues(issues: ReadonlyArray<SurfaceValidationIssue>, repoRoot: string): string;
99
+
100
+ /**
101
+ * Substrate-default `ImprovementAdapter` — surfaces-driven, LLM-drafted
102
+ * patches, optional auto-apply or PR-open.
103
+ *
104
+ * This is the one ImprovementAdapter every vertical agent uses. The
105
+ * substrate parses each finding's `subject` via
106
+ * `parseFindingSubject` (agent-eval), resolves it to a real file path
107
+ * via the agent's `AgentSurfaces`, reads the current content, and asks
108
+ * an LLM to draft a unified-diff patch given the finding + current
109
+ * content + per-kind editing-discipline rules.
110
+ *
111
+ * Auto-apply gates on the source-finding's confidence and the
112
+ * autoApply.improvement policy. Two modes:
113
+ * `write` — apply the patch in-place via `git apply -p0`. Operator
114
+ * reviews via `git diff`.
115
+ * `open-pr` — write to a branch, commit, push, open a PR via `gh`.
116
+ * Operator reviews via the PR UI.
117
+ *
118
+ * Fail-loud rules:
119
+ * - Findings whose subject doesn't parse → counted in `errors`.
120
+ * - Findings whose subject targets an undeclared surface → counted in
121
+ * `errors` with the offending kind in the message.
122
+ * - Findings whose target path doesn't exist AND the kind isn't a
123
+ * create-new variant (`new-tool`, `knowledge.wiki`) → counted in
124
+ * `errors` with the resolved path in the message.
125
+ * - LLM drafts that fail JSON-schema validation → counted in
126
+ * `errors` with the schema issue.
127
+ *
128
+ * No silent skips. Every dropped finding has a recorded reason the
129
+ * loop's report surfaces.
130
+ */
131
+
132
+ interface SurfaceImprovementEdit {
133
+ /** Stable id derived from the source finding so re-proposals are idempotent. */
134
+ id: string;
135
+ /** The finding that produced this edit — for revert + audit trail. */
136
+ sourceFindingId: string;
137
+ /** Parsed subject; included so the apply step doesn't re-parse. */
138
+ subject: FindingSubject;
139
+ /** Resolved on-disk target. */
140
+ target: ResolvedSurface;
141
+ /** SHA-256 of the current file content the patch was drafted against. */
142
+ baseSha256: string;
143
+ /** Unified-diff patch the LLM drafted (relative to `target.absolutePath`). */
144
+ patch: string;
145
+ /** One-line summary the operator sees in the report / PR title. */
146
+ summary: string;
147
+ /** Multi-line rationale for the PR body — finding context + LLM reasoning. */
148
+ rationale: string;
149
+ /** Carry-forward from the finding so the apply gate can check the threshold. */
150
+ confidence: number;
151
+ /** Carry-forward severity for prioritization. */
152
+ severity: AnalystFinding['severity'];
153
+ }
154
+ interface CreateSurfaceImprovementAdapterOpts {
155
+ surfaces: AgentSurfaces;
156
+ repoRoot: string;
157
+ /**
158
+ * LLM-draft callback. Given a finding + current file content + the
159
+ * resolved target, returns a unified-diff patch + summary + rationale.
160
+ *
161
+ * Required — the substrate doesn't ship a hardcoded prompt; the agent
162
+ * author picks the model (Haiku for cheap routine drafts, Sonnet for
163
+ * substantive prompt rewrites, etc.) via this callback.
164
+ */
165
+ draftPatch: (input: DraftPatchInput) => Promise<DraftPatchOutput>;
166
+ /**
167
+ * Apply mode:
168
+ * `write` — `git apply` in-place; operator reviews via `git diff`
169
+ * `open-pr` — branch + commit + push + `gh pr create`
170
+ * `none` — never apply; collect proposals for the report only
171
+ *
172
+ * The `apply` method honours this even when the loop calls it; the
173
+ * effective behaviour is also gated on the per-finding confidence
174
+ * threshold via `runAnalystLoop`'s `autoApply` policy.
175
+ */
176
+ mode?: 'write' | 'open-pr' | 'none';
177
+ /** When `mode === 'open-pr'`, the base branch new PRs target. Default: `main`. */
178
+ baseBranch?: string;
179
+ /** Required for `mode === 'open-pr'` — the GH owner/repo (`tangle-network/tax-agent`). */
180
+ ghRepo?: string;
181
+ /**
182
+ * When the resolved target doesn't exist, allow the substrate to
183
+ * CREATE the file (for `knowledge.wiki`, `new-tool` subjects). Default
184
+ * true for those kinds, false for `system-prompt` / `rubric` / etc.
185
+ * (named sections that don't exist are a contract violation, not a
186
+ * scaffolding opportunity).
187
+ */
188
+ allowCreateForKinds?: ReadonlyArray<FindingSubject['kind']>;
189
+ }
190
+ interface DraftPatchInput {
191
+ finding: AnalystFinding;
192
+ subject: FindingSubject;
193
+ target: ResolvedSurface;
194
+ /** Current file content (empty string when `intent === 'create-new'`). */
195
+ currentContent: string;
196
+ }
197
+ interface DraftPatchOutput {
198
+ /** Unified diff against the current file content. Empty string skips this finding. */
199
+ patch: string;
200
+ /** One-line summary for the operator. */
201
+ summary: string;
202
+ /** Multi-line rationale for the PR body. */
203
+ rationale: string;
204
+ }
205
+ declare function createSurfaceImprovementAdapter(opts: CreateSurfaceImprovementAdapterOpts): ImprovementAdapter<SurfaceImprovementEdit>;
206
+
207
+ export { type AgentSurfaces as A, type CreateSurfaceImprovementAdapterOpts as C, type DraftPatchInput as D, type ResolvedSurface as R, type SurfaceImprovementEdit as S, type DraftPatchOutput as a, type SurfaceValidationIssue as b, createSurfaceImprovementAdapter as c, resolveSubjectPath as d, renderSurfaceIssues as r, validateSurfaces as v };
@@ -0,0 +1,120 @@
1
+ import { AnalystFinding } from '@tangle-network/agent-eval';
2
+ import { L as LocalHarness, r as runLocalHarness } from './local-harness-KrdFTY5R.js';
3
+ import { LabeledScenarioStore, WorktreeAdapter, ImprovementDriver } from '@tangle-network/agent-eval/campaign';
4
+ import { S as SurfaceImprovementEdit } from './improvement-adapter-CaZxFxTd.js';
5
+ import { I as ImprovementAdapter } from './types-D_MXrmJP.js';
6
+ import 'node:child_process';
7
+
8
+ /**
9
+ * @experimental
10
+ *
11
+ * `improvementDriver` — the ONE reflective/agentic improvement driver for
12
+ * agent-eval's improvement loop. It implements `ImprovementDriver` and owns
13
+ * the candidate lifecycle (worktree create → generate → finalize/discard,
14
+ * × populationSize); it delegates the only thing that genuinely varies — HOW
15
+ * a candidate change is produced — to a pluggable `CandidateGenerator`.
16
+ *
17
+ * There is no separate "analyst driver" vs "autoresearch driver": those are
18
+ * the SAME driver at two settings of a dial.
19
+ * - cheap reflective path → `reflectiveGenerator` (shots=1, no sandbox;
20
+ * applies pre-drafted patches)
21
+ * - full agentic path → `agenticGenerator` (shots=N, sandbox runLoop;
22
+ * an agent reads code + report and edits)
23
+ * Both emit changes into a worktree the driver finalizes into a
24
+ * `CodeSurface{ worktreeRef }` the loop measures on the holdout. See
25
+ * agent-eval's `docs/design/self-improvement-engine.md`.
26
+ */
27
+
28
+ /** The byte-producing seam — the ONE thing that differs between the cheap
29
+ * reflective path and the full agentic path. A generator makes (uncommitted)
30
+ * changes inside `worktreePath`; the driver commits them via the worktree
31
+ * adapter's `finalize`. */
32
+ interface CandidateGenerator {
33
+ kind: string;
34
+ generate(args: {
35
+ /** The candidate worktree — a fresh checkout of baseRef. Write changes here. */
36
+ worktreePath: string;
37
+ /** Phase-2 research report (analyst findings + diff), opaque. */
38
+ report: unknown;
39
+ /** Findings resolved from the report or the loop context. */
40
+ findings: AnalystFinding[];
41
+ /** Handle to all captured data, to ground the change. */
42
+ dataset?: LabeledScenarioStore;
43
+ /** DEPTH: max iterations the generator may take (agentic uses this; the
44
+ * reflective generator ignores it). */
45
+ maxShots: number;
46
+ signal: AbortSignal;
47
+ }): Promise<{
48
+ applied: boolean;
49
+ summary: string;
50
+ }>;
51
+ }
52
+ interface ImprovementDriverOptions {
53
+ worktree: WorktreeAdapter;
54
+ generator: CandidateGenerator;
55
+ /** Base ref candidate worktrees fork from. Default `main`. */
56
+ baseRef?: string;
57
+ }
58
+ declare function improvementDriver(opts: ImprovementDriverOptions): ImprovementDriver<AnalystFinding>;
59
+
60
+ /**
61
+ * @experimental
62
+ *
63
+ * `agenticGenerator` — the full-agentic `CandidateGenerator`: the
64
+ * `shots=N, sandbox=on` setting of the one `improvementDriver`. It runs a real
65
+ * coding harness (claude / codex / opencode) inside the candidate worktree the
66
+ * driver already created, letting the agent read the codebase + the research
67
+ * report and make the change in place. The driver then commits the worktree
68
+ * into a `CodeSurface`.
69
+ *
70
+ * Mechanism: identical to the proven Phase-2.8 in-process executor — spawn the
71
+ * harness as a subprocess with `cwd` = the worktree, on the same filesystem,
72
+ * so edits land in place (no sandbox-mount round-trip). `runLocalHarness` is
73
+ * the verified primitive. The OUTER sandbox is the improvement loop's own
74
+ * execution context; the generator does not nest a second sandbox per
75
+ * candidate (which would reintroduce a host↔sandbox worktree-transport
76
+ * problem that does not need solving here).
77
+ *
78
+ * `maxShots` is the DEPTH dial: the harness runs once; if it produced no change
79
+ * (the worktree stays clean), the generator refines the prompt and retries, up
80
+ * to `maxShots` times. A harness that already changed files returns on shot 1.
81
+ */
82
+
83
+ interface AgenticGeneratorOptions {
84
+ /** Local coding harness to run in the worktree. Default `claude`. */
85
+ harness?: LocalHarness;
86
+ /** Per-shot wall-clock timeout (ms). Default = `runLocalHarness` default (5m). */
87
+ timeoutMs?: number;
88
+ /** Build the harness task prompt from the report + findings. Override for
89
+ * domain phrasing; the default turns findings into a concrete coder task. */
90
+ buildPrompt?: (args: {
91
+ report: unknown;
92
+ findings: AnalystFinding[];
93
+ }) => string;
94
+ /** Test seam — inject the harness runner (defaults to `runLocalHarness`). */
95
+ runHarness?: typeof runLocalHarness;
96
+ /** Test seam — inject the worktree-dirty check (defaults to `git status`). */
97
+ isDirty?: (worktreePath: string) => boolean;
98
+ }
99
+ declare function agenticGenerator(opts?: AgenticGeneratorOptions): CandidateGenerator;
100
+
101
+ /**
102
+ * @experimental
103
+ *
104
+ * `reflectiveGenerator` — the cheap, no-sandbox `CandidateGenerator`. It drafts
105
+ * surface edits via the existing improvement adapter (`proposeFromFindings`,
106
+ * one LLM patch per finding) and applies them as ONE coherent improvement into
107
+ * the candidate worktree. `maxShots` is ignored — reflection is single-shot by
108
+ * construction (the patches are already drafted).
109
+ *
110
+ * This is the `shots=1, sandbox=off` setting of the one improvement driver.
111
+ * The `agenticGenerator` (sandbox runLoop) is the `shots=N, sandbox=on`
112
+ * setting — both plug into the same `improvementDriver`.
113
+ */
114
+
115
+ interface ReflectiveGeneratorOptions {
116
+ improvementAdapter: ImprovementAdapter<SurfaceImprovementEdit>;
117
+ }
118
+ declare function reflectiveGenerator(opts: ReflectiveGeneratorOptions): CandidateGenerator;
119
+
120
+ export { type AgenticGeneratorOptions, type CandidateGenerator, type ImprovementDriverOptions, type ReflectiveGeneratorOptions, agenticGenerator, improvementDriver, reflectiveGenerator };
@@ -0,0 +1,161 @@
1
+ import {
2
+ runLocalHarness
3
+ } from "./chunk-GLR25NG7.js";
4
+ import "./chunk-DGUM43GV.js";
5
+
6
+ // src/improvement/agentic-generator.ts
7
+ import { spawnSync } from "child_process";
8
+ function agenticGenerator(opts = {}) {
9
+ const harness = opts.harness ?? "claude";
10
+ const buildPrompt = opts.buildPrompt ?? defaultBuildPrompt;
11
+ const run = opts.runHarness ?? runLocalHarness;
12
+ const dirty = opts.isDirty ?? worktreeDirty;
13
+ return {
14
+ kind: `agentic:${harness}`,
15
+ async generate({ worktreePath, report, findings, maxShots, signal }) {
16
+ let prompt = buildPrompt({ report, findings });
17
+ const shots = Math.max(1, maxShots);
18
+ for (let shot = 0; shot < shots; shot++) {
19
+ if (signal.aborted) break;
20
+ await run({
21
+ harness,
22
+ cwd: worktreePath,
23
+ taskPrompt: prompt,
24
+ timeoutMs: opts.timeoutMs,
25
+ signal
26
+ });
27
+ if (dirty(worktreePath)) {
28
+ return { applied: true, summary: summarize(findings) };
29
+ }
30
+ prompt = refine(prompt);
31
+ }
32
+ return { applied: false, summary: "" };
33
+ }
34
+ };
35
+ }
36
+ function defaultBuildPrompt(args) {
37
+ const lines = [
38
+ "You are improving this codebase based on an evaluation analysis.",
39
+ "Make the smallest set of edits that addresses the findings below, then stop.",
40
+ "Do not change unrelated code. Do not commit \u2014 leave changes in the working tree.",
41
+ "",
42
+ "Findings:"
43
+ ];
44
+ for (const f of args.findings) {
45
+ const where = f.subject ? ` [${f.subject}]` : "";
46
+ lines.push(`- (${f.severity})${where} ${f.claim}`);
47
+ if (f.recommended_action) lines.push(` \u2192 ${f.recommended_action}`);
48
+ }
49
+ return lines.join("\n");
50
+ }
51
+ function refine(prompt) {
52
+ return `${prompt}
53
+
54
+ NOTE: your previous attempt left the working tree unchanged. Make the concrete file edits now.`;
55
+ }
56
+ function summarize(findings) {
57
+ if (findings.length === 0) return "agentic improvement";
58
+ if (findings.length === 1) return `agentic: ${truncate(findings[0].claim, 64)}`;
59
+ return `agentic: ${findings.length} findings addressed`;
60
+ }
61
+ function truncate(s, n) {
62
+ return s.length <= n ? s : `${s.slice(0, n - 1)}\u2026`;
63
+ }
64
+ function worktreeDirty(worktreePath) {
65
+ const result = spawnSync("git", ["status", "--porcelain"], {
66
+ cwd: worktreePath,
67
+ encoding: "utf-8"
68
+ });
69
+ if (result.error) {
70
+ throw new Error(
71
+ `agenticGenerator: git status failed to spawn in ${worktreePath}: ${result.error.message}`
72
+ );
73
+ }
74
+ if (result.status !== 0) {
75
+ throw new Error(
76
+ `agenticGenerator: git status exited ${result.status} in ${worktreePath}: ${result.stderr.trim()}`
77
+ );
78
+ }
79
+ return result.stdout.trim().length > 0;
80
+ }
81
+
82
+ // src/improvement/improvement-driver.ts
83
+ function improvementDriver(opts) {
84
+ const baseRef = opts.baseRef ?? "main";
85
+ return {
86
+ kind: `improvement:${opts.generator.kind}`,
87
+ async propose(ctx) {
88
+ const findings = resolveFindings(ctx);
89
+ if (findings.length === 0 && ctx.report === void 0) return [];
90
+ const surfaces = [];
91
+ for (let i = 0; i < ctx.populationSize; i++) {
92
+ if (ctx.signal.aborted) break;
93
+ const wt = await opts.worktree.create({
94
+ baseRef,
95
+ label: `${opts.generator.kind}-gen${ctx.generation}-cand${i}`
96
+ });
97
+ try {
98
+ const { applied, summary } = await opts.generator.generate({
99
+ worktreePath: wt.path,
100
+ report: ctx.report,
101
+ findings,
102
+ dataset: ctx.dataset,
103
+ maxShots: ctx.maxImprovementShots ?? 1,
104
+ signal: ctx.signal
105
+ });
106
+ if (!applied) {
107
+ await opts.worktree.discard(wt);
108
+ continue;
109
+ }
110
+ surfaces.push(await opts.worktree.finalize(wt, summary));
111
+ } catch (err) {
112
+ await opts.worktree.discard(wt).catch(() => {
113
+ });
114
+ throw err;
115
+ }
116
+ }
117
+ return surfaces;
118
+ }
119
+ };
120
+ }
121
+ function resolveFindings(ctx) {
122
+ const report = ctx.report;
123
+ if (report && typeof report === "object" && "findings" in report) {
124
+ const f = report.findings;
125
+ if (Array.isArray(f) && f.length > 0) return f;
126
+ }
127
+ return ctx.findings;
128
+ }
129
+
130
+ // src/improvement/reflective-generator.ts
131
+ import { spawnSync as spawnSync2 } from "child_process";
132
+ function reflectiveGenerator(opts) {
133
+ return {
134
+ kind: "reflective",
135
+ async generate({ worktreePath, findings }) {
136
+ const batch = await opts.improvementAdapter.proposeFromFindings(findings);
137
+ if (batch.edits.length === 0) return { applied: false, summary: "" };
138
+ let applied = 0;
139
+ for (const edit of batch.edits) {
140
+ if (applyPatch(edit.patch, worktreePath)) applied++;
141
+ }
142
+ if (applied === 0) return { applied: false, summary: "" };
143
+ const summary = batch.edits.length === 1 ? batch.edits[0].summary : `analyst: ${applied} surface edit${applied === 1 ? "" : "s"}`;
144
+ return { applied: true, summary };
145
+ }
146
+ };
147
+ }
148
+ function applyPatch(patch, cwd) {
149
+ const result = spawnSync2("git", ["apply", "--whitespace=fix", "-p0", "-"], {
150
+ cwd,
151
+ input: patch,
152
+ encoding: "utf-8"
153
+ });
154
+ return result.status === 0;
155
+ }
156
+ export {
157
+ agenticGenerator,
158
+ improvementDriver,
159
+ reflectiveGenerator
160
+ };
161
+ //# sourceMappingURL=improvement.js.map