@tangle-network/agent-runtime 0.78.0 → 0.79.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/agent.js +4 -3
  2. package/dist/agent.js.map +1 -1
  3. package/dist/{chunk-QJ6BWENI.js → chunk-2DS6T46I.js} +3 -3
  4. package/dist/{chunk-O2UPHN7X.js → chunk-5JAUQZQA.js} +1 -1
  5. package/dist/chunk-5JAUQZQA.js.map +1 -0
  6. package/dist/{chunk-YHS6I2IS.js → chunk-75V2XXYJ.js} +8 -6
  7. package/dist/chunk-75V2XXYJ.js.map +1 -0
  8. package/dist/{chunk-JPURCA2O.js → chunk-LWGVVP2C.js} +2 -2
  9. package/dist/{chunk-OL2SEETC.js → chunk-SONQUREI.js} +2 -2
  10. package/dist/{chunk-OLPH6W3J.js → chunk-TSDKBFZP.js} +53 -144
  11. package/dist/chunk-TSDKBFZP.js.map +1 -0
  12. package/dist/chunk-Z3RRRPRB.js +916 -0
  13. package/dist/chunk-Z3RRRPRB.js.map +1 -0
  14. package/dist/{coordination-Csxsy39a.d.ts → coordination-BoEPhGas.d.ts} +30 -22
  15. package/dist/environment-provider.d.ts +66 -0
  16. package/dist/environment-provider.js +16 -0
  17. package/dist/environment-provider.js.map +1 -0
  18. package/dist/index.d.ts +7 -6
  19. package/dist/index.js +7 -6
  20. package/dist/index.js.map +1 -1
  21. package/dist/lifecycle.d.ts +2 -2
  22. package/dist/lifecycle.js +2 -2
  23. package/dist/{local-harness-BE_h8szs.d.ts → local-harness-DU7yV6mG.d.ts} +1 -1
  24. package/dist/{loop-runner-bin-BTMpf1oY.d.ts → loop-runner-bin-DCr5OMe5.d.ts} +2 -2
  25. package/dist/loop-runner-bin.d.ts +5 -4
  26. package/dist/loop-runner-bin.js +5 -4
  27. package/dist/loops.d.ts +13 -9
  28. package/dist/loops.js +15 -3
  29. package/dist/mcp/bin.js +3 -2
  30. package/dist/mcp/bin.js.map +1 -1
  31. package/dist/mcp/index.d.ts +12 -10
  32. package/dist/mcp/index.js +10 -8
  33. package/dist/mcp/index.js.map +1 -1
  34. package/dist/{mcp-serve-verifier-CT1KLTG_.d.ts → mcp-serve-verifier-BvMAV_8U.d.ts} +1 -1
  35. package/dist/{worktree-DH_Y0brm.d.ts → types-C1sozrte.d.ts} +1 -123
  36. package/dist/worktree-CpptK3oF.d.ts +125 -0
  37. package/dist/{worktree-fanout-DGC7jS7i.d.ts → worktree-fanout-CtQrRDME.d.ts} +3 -2
  38. package/package.json +11 -3
  39. package/dist/chunk-O2UPHN7X.js.map +0 -1
  40. package/dist/chunk-OLPH6W3J.js.map +0 -1
  41. package/dist/chunk-YHS6I2IS.js.map +0 -1
  42. /package/dist/{chunk-QJ6BWENI.js.map → chunk-2DS6T46I.js.map} +0 -0
  43. /package/dist/{chunk-JPURCA2O.js.map → chunk-LWGVVP2C.js.map} +0 -0
  44. /package/dist/{chunk-OL2SEETC.js.map → chunk-SONQUREI.js.map} +0 -0
@@ -486,126 +486,4 @@ interface WidenGate<Out> {
486
486
  readonly judgeExempt?: boolean;
487
487
  }
488
488
 
489
- /**
490
- * @experimental
491
- *
492
- * The completion-oracle: **settled ⟺ DELIVERED.**
493
- *
494
- * Foreman's one hard lesson (0/18 self-improvement deliverables) — "done" must mean a check
495
- * PASSED, not the agent's say-so. `gateOnDeliverable` wraps an `Executor` so its settlement
496
- * is `valid` ONLY when the deliverable check passes. The child still RUNS and settles (its
497
- * spend is conserved into the pool either way), but a child that ran WITHOUT delivering
498
- * settles `valid:false` — so a keep-best driver never counts it as done, and a gate never
499
- * inflates with self-judged wins.
500
- *
501
- * Dual-purpose by construction:
502
- * - product: the agent fleet only advances on real, checked deliverables.
503
- * - proof: the gate's `valid` is the honest settle — equal-k comparisons can't be gamed by an
504
- * arm that "ran" without producing the artifact.
505
- *
506
- * The check is a DEPLOYABLE oracle — a test command, a state verifier, the commit0 judge —
507
- * read off the child's output, never the model judging itself. A throwing check is
508
- * fail-closed (not delivered), never a crash.
509
- */
510
-
511
- /**
512
- * The deployable completion oracle passed to {@link gateOnDeliverable}: a `check` that
513
- * decides DELIVERED (settles `valid` ⟺ it resolves true) plus an optional `describe` of
514
- * what the spawn was supposed to produce. The check reads the child's output — never the
515
- * model judging itself.
516
- */
517
- interface DeliverableSpec<Out = unknown> {
518
- /** The deployable check that decides DELIVERED. `settled.valid ⟺ this resolves true`. */
519
- check: (out: Out) => boolean | Promise<boolean>;
520
- /** What the spawn was supposed to produce — surfaced in traces/reports. */
521
- describe?: string;
522
- }
523
- /**
524
- * Wrap an `Executor` so its settlement `valid` reflects the deliverable check, not the
525
- * inner verdict. Handles both `execute` shapes (one-shot `Promise<ExecutorResult>` and
526
- * streaming `AsyncIterable<UsageEvent>` + `resultArtifact()`); the check runs once the inner
527
- * executor has produced its output. The inner `score` is preserved; only `valid` is gated.
528
- */
529
- declare function gateOnDeliverable<Out>(inner: Executor<Out>, deliverable: DeliverableSpec<Out>): Executor<Out>;
530
-
531
- /**
532
- * @experimental
533
- *
534
- * Git worktree helpers for the in-process delegation executor. Each
535
- * delegation runs in its own worktree so multiple parallel harness
536
- * subprocesses (claude / codex / opencode in a 3-way fanout) don't clobber
537
- * each other's edits on the shared workspace.
538
- *
539
- * Worktrees live under `<repoRoot>/.agent-worktrees/<runId>/`. After the
540
- * harness exits + the diff is captured, the worktree is removed.
541
- *
542
- * All operations spawn `git` via `child_process.spawn` synchronously
543
- * (via a `runGit` helper). Stays narrow on purpose: no commits, no rebases.
544
- * Diff capture stages all changes (`git add -A`) into the ephemeral worktree's
545
- * index so created (untracked) files appear in the `--cached` diff.
546
- */
547
- /** @experimental */
548
- interface WorktreeHandle {
549
- /** Absolute path to the worktree directory. */
550
- path: string;
551
- /** SHA the worktree was created at. */
552
- baseSha: string;
553
- /** Branch name created for this worktree (typically `delegate/<runId>`). */
554
- branch: string;
555
- }
556
- /** @experimental */
557
- interface CreateWorktreeOptions {
558
- /** Absolute path to the main git checkout. */
559
- repoRoot: string;
560
- /** Unique id for the worktree path + branch. Use the delegation run id. */
561
- runId: string;
562
- /** Parent directory the worktree lives under. Defaults to `.agent-worktrees`. */
563
- variantsDir?: string;
564
- /** Override the base ref (default `HEAD`). */
565
- baseRef?: string;
566
- /** Test seam — inject a custom git runner. */
567
- runGit?: GitRunner;
568
- }
569
- /** @experimental */
570
- interface DiffOptions {
571
- /** Worktree to diff. */
572
- worktree: WorktreeHandle;
573
- /** What to compare against. Default `worktree.baseSha`. */
574
- baseRef?: string;
575
- /** Test seam. */
576
- runGit?: GitRunner;
577
- }
578
- /** @experimental */
579
- interface DiffResult {
580
- patch: string;
581
- stats: {
582
- filesChanged: number;
583
- insertions: number;
584
- deletions: number;
585
- };
586
- }
587
- /** @experimental */
588
- interface RemoveWorktreeOptions {
589
- worktree: WorktreeHandle;
590
- repoRoot: string;
591
- /** Force removal even if dirty (default true; the loser of a fanout has uncommitted changes). */
592
- force?: boolean;
593
- /** Test seam. */
594
- runGit?: GitRunner;
595
- }
596
- /** Pluggable git runner (sync) — replaceable in tests. */
597
- type GitRunner = (args: ReadonlyArray<string>, opts: {
598
- cwd: string;
599
- }) => {
600
- stdout: string;
601
- stderr: string;
602
- exitCode: number;
603
- };
604
- /** @experimental */
605
- declare function createWorktree(options: CreateWorktreeOptions): Promise<WorktreeHandle>;
606
- /** @experimental */
607
- declare function captureWorktreeDiff(options: DiffOptions): Promise<DiffResult>;
608
- /** @experimental */
609
- declare function removeWorktree(options: RemoveWorktreeOptions): Promise<void>;
610
-
611
- export { type AgentSpec as A, type Budget as B, type CreateWorktreeOptions as C, type DiffOptions as D, type ExecutorRegistry as E, type GitRunner as G, type NodeId as N, type RemoveWorktreeOptions as R, type SpawnJournal as S, type TreeView as T, type UsageEvent as U, type WorktreeHandle as W, type DiffResult as a, createWorktree as b, captureWorktreeDiff as c, type Agent as d, type ResultBlobStore as e, type RootHandle as f, type SupervisedResult as g, type Settled as h, type Spend as i, type Scope as j, type Executor as k, type DeliverableSpec as l, type ExecutorFactory as m, type SpawnEvent as n, type Supervisor as o, type ExecutorContext as p, type ExecutorResult as q, removeWorktree as r, type SupervisorOpts as s, type WidenGate as t, gateOnDeliverable as u };
489
+ export type { AgentSpec as A, Budget as B, ExecutorFactory as E, NodeId as N, Runtime as R, SpawnJournal as S, TreeView as T, UsageEvent as U, WidenGate as W, Executor as a, ExecutorRegistry as b, Agent as c, ResultBlobStore as d, RootHandle as e, SupervisedResult as f, Settled as g, Spend as h, Scope as i, SpawnEvent as j, Supervisor as k, ExecutorContext as l, ExecutorResult as m, SupervisorOpts as n };
@@ -0,0 +1,125 @@
1
+ import { a as Executor } from './types-C1sozrte.js';
2
+
3
+ /**
4
+ * @experimental
5
+ *
6
+ * The completion-oracle: **settled ⟺ DELIVERED.**
7
+ *
8
+ * Foreman's one hard lesson (0/18 self-improvement deliverables) — "done" must mean a check
9
+ * PASSED, not the agent's say-so. `gateOnDeliverable` wraps an `Executor` so its settlement
10
+ * is `valid` ONLY when the deliverable check passes. The child still RUNS and settles (its
11
+ * spend is conserved into the pool either way), but a child that ran WITHOUT delivering
12
+ * settles `valid:false` — so a keep-best driver never counts it as done, and a gate never
13
+ * inflates with self-judged wins.
14
+ *
15
+ * Dual-purpose by construction:
16
+ * - product: the agent fleet only advances on real, checked deliverables.
17
+ * - proof: the gate's `valid` is the honest settle — equal-k comparisons can't be gamed by an
18
+ * arm that "ran" without producing the artifact.
19
+ *
20
+ * The check is a DEPLOYABLE oracle — a test command, a state verifier, the commit0 judge —
21
+ * read off the child's output, never the model judging itself. A throwing check is
22
+ * fail-closed (not delivered), never a crash.
23
+ */
24
+
25
+ /**
26
+ * The deployable completion oracle passed to {@link gateOnDeliverable}: a `check` that
27
+ * decides DELIVERED (settles `valid` ⟺ it resolves true) plus an optional `describe` of
28
+ * what the spawn was supposed to produce. The check reads the child's output — never the
29
+ * model judging itself.
30
+ */
31
+ interface DeliverableSpec<Out = unknown> {
32
+ /** The deployable check that decides DELIVERED. `settled.valid ⟺ this resolves true`. */
33
+ check: (out: Out) => boolean | Promise<boolean>;
34
+ /** What the spawn was supposed to produce — surfaced in traces/reports. */
35
+ describe?: string;
36
+ }
37
+ /**
38
+ * Wrap an `Executor` so its settlement `valid` reflects the deliverable check, not the
39
+ * inner verdict. Handles both `execute` shapes (one-shot `Promise<ExecutorResult>` and
40
+ * streaming `AsyncIterable<UsageEvent>` + `resultArtifact()`); the check runs once the inner
41
+ * executor has produced its output. The inner `score` is preserved; only `valid` is gated.
42
+ */
43
+ declare function gateOnDeliverable<Out>(inner: Executor<Out>, deliverable: DeliverableSpec<Out>): Executor<Out>;
44
+
45
+ /**
46
+ * @experimental
47
+ *
48
+ * Git worktree helpers for the in-process delegation executor. Each
49
+ * delegation runs in its own worktree so multiple parallel harness
50
+ * subprocesses (claude / codex / opencode in a 3-way fanout) don't clobber
51
+ * each other's edits on the shared workspace.
52
+ *
53
+ * Worktrees live under `<repoRoot>/.agent-worktrees/<runId>/`. After the
54
+ * harness exits + the diff is captured, the worktree is removed.
55
+ *
56
+ * All operations spawn `git` via `child_process.spawn` synchronously
57
+ * (via a `runGit` helper). Stays narrow on purpose: no commits, no rebases.
58
+ * Diff capture stages all changes (`git add -A`) into the ephemeral worktree's
59
+ * index so created (untracked) files appear in the `--cached` diff.
60
+ */
61
+ /** @experimental */
62
+ interface WorktreeHandle {
63
+ /** Absolute path to the worktree directory. */
64
+ path: string;
65
+ /** SHA the worktree was created at. */
66
+ baseSha: string;
67
+ /** Branch name created for this worktree (typically `delegate/<runId>`). */
68
+ branch: string;
69
+ }
70
+ /** @experimental */
71
+ interface CreateWorktreeOptions {
72
+ /** Absolute path to the main git checkout. */
73
+ repoRoot: string;
74
+ /** Unique id for the worktree path + branch. Use the delegation run id. */
75
+ runId: string;
76
+ /** Parent directory the worktree lives under. Defaults to `.agent-worktrees`. */
77
+ variantsDir?: string;
78
+ /** Override the base ref (default `HEAD`). */
79
+ baseRef?: string;
80
+ /** Test seam — inject a custom git runner. */
81
+ runGit?: GitRunner;
82
+ }
83
+ /** @experimental */
84
+ interface DiffOptions {
85
+ /** Worktree to diff. */
86
+ worktree: WorktreeHandle;
87
+ /** What to compare against. Default `worktree.baseSha`. */
88
+ baseRef?: string;
89
+ /** Test seam. */
90
+ runGit?: GitRunner;
91
+ }
92
+ /** @experimental */
93
+ interface DiffResult {
94
+ patch: string;
95
+ stats: {
96
+ filesChanged: number;
97
+ insertions: number;
98
+ deletions: number;
99
+ };
100
+ }
101
+ /** @experimental */
102
+ interface RemoveWorktreeOptions {
103
+ worktree: WorktreeHandle;
104
+ repoRoot: string;
105
+ /** Force removal even if dirty (default true; the loser of a fanout has uncommitted changes). */
106
+ force?: boolean;
107
+ /** Test seam. */
108
+ runGit?: GitRunner;
109
+ }
110
+ /** Pluggable git runner (sync) — replaceable in tests. */
111
+ type GitRunner = (args: ReadonlyArray<string>, opts: {
112
+ cwd: string;
113
+ }) => {
114
+ stdout: string;
115
+ stderr: string;
116
+ exitCode: number;
117
+ };
118
+ /** @experimental */
119
+ declare function createWorktree(options: CreateWorktreeOptions): Promise<WorktreeHandle>;
120
+ /** @experimental */
121
+ declare function captureWorktreeDiff(options: DiffOptions): Promise<DiffResult>;
122
+ /** @experimental */
123
+ declare function removeWorktree(options: RemoveWorktreeOptions): Promise<void>;
124
+
125
+ export { type CreateWorktreeOptions as C, type DiffOptions as D, type GitRunner as G, type RemoveWorktreeOptions as R, type WorktreeHandle as W, type DiffResult as a, createWorktree as b, captureWorktreeDiff as c, type DeliverableSpec as d, gateOnDeliverable as g, removeWorktree as r };
@@ -1,9 +1,10 @@
1
1
  import { AgentProfile } from '@tangle-network/agent-interface';
2
2
  import { AnalystFinding, DefaultVerdict } from '@tangle-network/agent-eval';
3
- import { A as AgentSpec, E as ExecutorRegistry, B as Budget, d as Agent, S as SpawnJournal, e as ResultBlobStore, f as RootHandle, g as SupervisedResult, N as NodeId, h as Settled, i as Spend, j as Scope, G as GitRunner, k as Executor, l as DeliverableSpec } from './worktree-DH_Y0brm.js';
3
+ import { A as AgentSpec, b as ExecutorRegistry, B as Budget, c as Agent, S as SpawnJournal, d as ResultBlobStore, e as RootHandle, f as SupervisedResult, N as NodeId, g as Settled, h as Spend, i as Scope, a as Executor } from './types-C1sozrte.js';
4
4
  import { R as RuntimeHooks, I as Iteration } from './types-BF-MEsQB.js';
5
5
  import { BackendType } from '@tangle-network/sandbox';
6
- import { L as LocalHarness, r as runLocalHarness } from './local-harness-BE_h8szs.js';
6
+ import { G as GitRunner, d as DeliverableSpec } from './worktree-CpptK3oF.js';
7
+ import { L as LocalHarness, r as runLocalHarness } from './local-harness-DU7yV6mG.js';
7
8
 
8
9
  /**
9
10
  * @experimental
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-runtime",
3
- "version": "0.78.0",
3
+ "version": "0.79.1",
4
4
  "description": "Shared task-lifecycle skeleton for agents: a recursive loop kernel for chat turns, one-shot tasks, and multi-attempt loops, with trace capture and eval-gated self-improvement. Domain behavior lives in adapters; scoring and ship-gates in @tangle-network/agent-eval.",
5
5
  "homepage": "https://github.com/tangle-network/agent-runtime#readme",
6
6
  "repository": {
@@ -34,6 +34,11 @@
34
34
  "import": "./dist/loops.js",
35
35
  "default": "./dist/loops.js"
36
36
  },
37
+ "./environment-provider": {
38
+ "types": "./dist/environment-provider.d.ts",
39
+ "import": "./dist/environment-provider.js",
40
+ "default": "./dist/environment-provider.js"
41
+ },
37
42
  "./analyst-loop": {
38
43
  "types": "./dist/analyst-loop.d.ts",
39
44
  "import": "./dist/analyst-loop.js",
@@ -90,7 +95,7 @@
90
95
  "devDependencies": {
91
96
  "@biomejs/biome": "^2.4.15",
92
97
  "@tangle-network/agent-eval": ">=0.100.0 <1.0.0",
93
- "@tangle-network/agent-interface": ">=0.10.0 <1.0.0",
98
+ "@tangle-network/agent-interface": ">=0.14.0 <1.0.0",
94
99
  "@tangle-network/sandbox": ">=0.8.0 <1.0.0",
95
100
  "@types/node": "^25.9.3",
96
101
  "playwright": "^1.61.0",
@@ -119,11 +124,14 @@
119
124
  "packageManager": "pnpm@10.28.0",
120
125
  "peerDependencies": {
121
126
  "@tangle-network/agent-eval": ">=0.97.0 <1.0.0",
122
- "@tangle-network/agent-interface": ">=0.10.0 <1.0.0",
127
+ "@tangle-network/agent-interface": ">=0.14.0 <1.0.0",
123
128
  "@tangle-network/sandbox": ">=0.8.0 <1.0.0",
124
129
  "playwright": "^1.40.0"
125
130
  },
126
131
  "peerDependenciesMeta": {
132
+ "@tangle-network/agent-eval": {
133
+ "optional": true
134
+ },
127
135
  "@tangle-network/agent-interface": {
128
136
  "optional": true
129
137
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/local-harness.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Subprocess wrappers for the local coding-harness CLIs installed in the\n * sandbox image (claude-code, codex, opencode). Used by the in-process\n * delegation executor (`createInProcessExecutor`) so a `delegate_code` call\n * spawns a real harness on a real git worktree instead of provisioning a\n * sibling sandbox.\n *\n * All harness invocations:\n * - run with `cwd` set to the worktree\n * - inherit env from the parent (the MCP server inside the sandbox has\n * the harness's auth already)\n * - capture stdout/stderr\n * - support cancellation via AbortSignal\n * - enforce a wall-clock timeout\n */\n\nimport { type ChildProcess, spawn } from 'node:child_process'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\n\n/** Local coding harness available inside the sandbox. */\nexport type LocalHarness = 'claude' | 'codex' | 'opencode'\n\n/**\n * Default per-harness command + arg shape. `buildArgs` takes ONLY the task prompt and\n * emits the prompt-only invocation (no model, no system prompt) — the historical shape\n * the in-process executor's `streamPrompt` drives. `modelArgs` maps a resolved model to\n * the harness's selector flag (every supported harness takes `-m <model>`). The §1.5\n * profile-aware mapper `harnessInvocation` composes these to thread the full\n * supervisor-authored profile (systemPrompt + model) into argv.\n */\nconst HARNESS_INVOCATIONS: Record<\n LocalHarness,\n {\n command: string\n buildArgs: (taskPrompt: string) => string[]\n /** Map a resolved model to the harness's model-selector flag. */\n modelArgs: (model: string) => string[]\n }\n> = {\n claude: {\n command: 'claude',\n buildArgs: (taskPrompt) => ['--headless', '-p', taskPrompt],\n modelArgs: (model) => ['-m', model],\n },\n codex: {\n command: 'codex',\n buildArgs: (taskPrompt) => ['run', taskPrompt],\n modelArgs: (model) => ['-m', model],\n },\n opencode: {\n command: 'opencode',\n buildArgs: (taskPrompt) => ['run', taskPrompt],\n modelArgs: (model) => ['-m', model],\n },\n}\n\n/** Result of mapping an `AgentProfile` + task prompt onto a harness invocation. */\nexport interface HarnessInvocation {\n command: string\n args: string[]\n}\n\n/**\n * Map a supervisor-authored `AgentProfile` + the per-task prompt onto a concrete harness\n * `command` + `args` (the §1.5 fix). UNLIKE the prompt-only `HARNESS_INVOCATIONS.buildArgs`\n * — which drops both the authored model and the system prompt — this threads the FULL\n * profile payload into argv:\n *\n * - `profile.prompt.systemPrompt` → the PROMPT channel: a portable, harness-agnostic\n * default that prepends the system prompt above the task prompt (`<system>\\n\\n<task>`),\n * so the authored standing instructions reach EVERY harness (none of the three CLIs\n * expose a portable replace-system-prompt flag for a one-shot non-interactive run).\n * - `profile.model.default` → the harness's `-m <model>` selector.\n *\n * The task prompt alone is the floor; an empty/absent profile yields exactly the legacy\n * `buildArgs(taskPrompt)` shape so existing callers are byte-identical.\n */\nexport function harnessInvocation(\n harness: LocalHarness,\n profile: AgentProfile,\n taskPrompt: string,\n): HarnessInvocation {\n const invocation = HARNESS_INVOCATIONS[harness]\n if (!invocation) {\n throw new Error(`harnessInvocation: unknown harness ${String(harness)}`)\n }\n\n const systemPrompt = profile.prompt?.systemPrompt\n const composedPrompt =\n typeof systemPrompt === 'string' && systemPrompt.trim().length > 0\n ? `${systemPrompt}\\n\\n${taskPrompt}`\n : taskPrompt\n\n const args = invocation.buildArgs(composedPrompt)\n\n const model = profile.model?.default\n if (typeof model === 'string' && model.length > 0) {\n args.push(...invocation.modelArgs(model))\n }\n\n return { command: invocation.command, args }\n}\n\n/** @experimental */\nexport interface RunLocalHarnessOptions {\n harness: LocalHarness\n /** Working directory for the subprocess (typically a worktree path). */\n cwd: string\n /** Prompt forwarded as the harness CLI's task argument. */\n taskPrompt: string\n /**\n * Pre-built command + args (e.g. from `harnessInvocation` so the full authored\n * `AgentProfile` — systemPrompt + model — reaches the harness). When set it OVERRIDES the\n * default prompt-only `buildArgs(taskPrompt)` path; `command` defaults to the harness's\n * default binary when only `args` is supplied. When absent the legacy prompt-only shape\n * is used unchanged.\n */\n invocation?: { command?: string; args: ReadonlyArray<string> }\n /** Wall-clock kill deadline (ms). Default 5 min. Subprocess SIGTERMed on expiry. */\n timeoutMs?: number\n /** Caller cancellation. SIGTERM is sent on abort. */\n signal?: AbortSignal\n /** Override env (defaults to inheriting from the parent). */\n env?: NodeJS.ProcessEnv\n /**\n * Test seam — inject a custom spawner so unit tests can mock the\n * subprocess without touching the OS. Defaults to node's `child_process.spawn`.\n */\n spawn?: (\n command: string,\n args: ReadonlyArray<string>,\n opts: {\n cwd: string\n env: NodeJS.ProcessEnv\n stdio: 'pipe'\n },\n ) => ChildProcess\n}\n\n/** @experimental */\nexport interface LocalHarnessResult {\n /** OS exit code. `null` when killed before exit. */\n exitCode: number | null\n /** Concatenated stdout. */\n stdout: string\n /** Concatenated stderr. */\n stderr: string\n /** Set when the process exited via signal (timeout / abort). */\n killedBySignal: NodeJS.Signals | null\n /** Wall-clock duration ms (spawn → exit). */\n durationMs: number\n /** Set when timeoutMs elapsed before exit. */\n timedOut: boolean\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000\n\n/**\n * Spawn a local coding harness CLI as a subprocess + collect its output.\n *\n * NOT responsible for parsing the harness's output or extracting a diff —\n * the in-process executor's `streamPrompt` orchestrates `git diff` against\n * the worktree after this resolves. This function is intentionally narrow:\n * spawn, wait, capture, return.\n *\n * Fails loud — throws when:\n * - `cwd` doesn't exist (subprocess emits ENOENT; surfaced as Error)\n * - the harness binary is not on PATH (ENOENT)\n *\n * Does NOT throw when:\n * - the subprocess exits non-zero (`result.exitCode` carries the code)\n * - the subprocess is aborted / timed out (`result.killedBySignal` /\n * `result.timedOut` carries the reason)\n *\n * @experimental\n */\nexport function runLocalHarness(options: RunLocalHarnessOptions): Promise<LocalHarnessResult> {\n const { harness, cwd, taskPrompt } = options\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const env = options.env ?? process.env\n const spawnImpl = options.spawn ?? spawn\n\n const invocation = HARNESS_INVOCATIONS[harness]\n if (!invocation) {\n return Promise.reject(new Error(`runLocalHarness: unknown harness ${String(harness)}`))\n }\n\n const startedAt = Date.now()\n const command = options.invocation?.command ?? invocation.command\n const args = options.invocation ? [...options.invocation.args] : invocation.buildArgs(taskPrompt)\n\n return new Promise<LocalHarnessResult>((resolve, reject) => {\n let child: ChildProcess\n try {\n child = spawnImpl(command, args, { cwd, env, stdio: 'pipe' })\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)))\n return\n }\n\n // The harness takes its task as an argv arg, not on stdin. Leaving stdin\n // OPEN makes a non-TTY `opencode run` (and likely the other harnesses)\n // BLOCK forever waiting on input — zero output, SIGTERM at the wall cap,\n // empty patch -> \"no candidate passed validation\". Close stdin so the\n // subprocess sees EOF and proceeds (the `cliExecutor` leaf does the same).\n child.stdin?.end()\n\n let stdout = ''\n let stderr = ''\n let timedOut = false\n let settled = false\n\n const timer =\n timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true\n if (!child.killed) child.kill('SIGTERM')\n }, timeoutMs)\n : null\n if (timer && typeof (timer as { unref?: () => void }).unref === 'function') {\n ;(timer as { unref: () => void }).unref()\n }\n\n const onAbort = () => {\n if (!child.killed) child.kill('SIGTERM')\n }\n if (options.signal) {\n if (options.signal.aborted) onAbort()\n else options.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n child.stdout?.on('data', (chunk) => {\n stdout += String(chunk)\n })\n child.stderr?.on('data', (chunk) => {\n stderr += String(chunk)\n })\n\n const finalize = (result: LocalHarnessResult) => {\n if (settled) return\n settled = true\n if (timer) clearTimeout(timer)\n options.signal?.removeEventListener('abort', onAbort)\n resolve(result)\n }\n\n child.on('error', (err) => {\n if (settled) return\n settled = true\n if (timer) clearTimeout(timer)\n options.signal?.removeEventListener('abort', onAbort)\n reject(err)\n })\n\n child.on('close', (code, signal) => {\n finalize({\n exitCode: code,\n stdout,\n stderr,\n killedBySignal: signal,\n durationMs: Date.now() - startedAt,\n timedOut,\n })\n })\n })\n}\n"],"mappings":"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","names":[]}