coterie 0.1.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.
Files changed (203) hide show
  1. package/README.md +137 -0
  2. package/dist/adapters/base.d.ts +56 -0
  3. package/dist/adapters/base.d.ts.map +1 -0
  4. package/dist/adapters/base.js +176 -0
  5. package/dist/adapters/base.js.map +1 -0
  6. package/dist/adapters/claudeCode.d.ts +11 -0
  7. package/dist/adapters/claudeCode.d.ts.map +1 -0
  8. package/dist/adapters/claudeCode.js +65 -0
  9. package/dist/adapters/claudeCode.js.map +1 -0
  10. package/dist/adapters/codex.d.ts +10 -0
  11. package/dist/adapters/codex.d.ts.map +1 -0
  12. package/dist/adapters/codex.js +51 -0
  13. package/dist/adapters/codex.js.map +1 -0
  14. package/dist/adapters/cursor.d.ts +16 -0
  15. package/dist/adapters/cursor.d.ts.map +1 -0
  16. package/dist/adapters/cursor.js +47 -0
  17. package/dist/adapters/cursor.js.map +1 -0
  18. package/dist/adapters/fake.d.ts +19 -0
  19. package/dist/adapters/fake.d.ts.map +1 -0
  20. package/dist/adapters/fake.js +41 -0
  21. package/dist/adapters/fake.js.map +1 -0
  22. package/dist/adapters/index.d.ts +11 -0
  23. package/dist/adapters/index.d.ts.map +1 -0
  24. package/dist/adapters/index.js +11 -0
  25. package/dist/adapters/index.js.map +1 -0
  26. package/dist/adapters/stream.d.ts +6 -0
  27. package/dist/adapters/stream.d.ts.map +1 -0
  28. package/dist/adapters/stream.js +20 -0
  29. package/dist/adapters/stream.js.map +1 -0
  30. package/dist/chat/configs.d.ts +18 -0
  31. package/dist/chat/configs.d.ts.map +1 -0
  32. package/dist/chat/configs.js +71 -0
  33. package/dist/chat/configs.js.map +1 -0
  34. package/dist/chat/doctor.d.ts +16 -0
  35. package/dist/chat/doctor.d.ts.map +1 -0
  36. package/dist/chat/doctor.js +43 -0
  37. package/dist/chat/doctor.js.map +1 -0
  38. package/dist/chat/finalizer.d.ts +25 -0
  39. package/dist/chat/finalizer.d.ts.map +1 -0
  40. package/dist/chat/finalizer.js +52 -0
  41. package/dist/chat/finalizer.js.map +1 -0
  42. package/dist/chat/preflight.d.ts +37 -0
  43. package/dist/chat/preflight.d.ts.map +1 -0
  44. package/dist/chat/preflight.js +115 -0
  45. package/dist/chat/preflight.js.map +1 -0
  46. package/dist/chat/render.d.ts +21 -0
  47. package/dist/chat/render.d.ts.map +1 -0
  48. package/dist/chat/render.js +113 -0
  49. package/dist/chat/render.js.map +1 -0
  50. package/dist/chat/repl.d.ts +9 -0
  51. package/dist/chat/repl.d.ts.map +1 -0
  52. package/dist/chat/repl.js +275 -0
  53. package/dist/chat/repl.js.map +1 -0
  54. package/dist/chat/trace.d.ts +29 -0
  55. package/dist/chat/trace.d.ts.map +1 -0
  56. package/dist/chat/trace.js +132 -0
  57. package/dist/chat/trace.js.map +1 -0
  58. package/dist/chat/transcript.d.ts +15 -0
  59. package/dist/chat/transcript.d.ts.map +1 -0
  60. package/dist/chat/transcript.js +39 -0
  61. package/dist/chat/transcript.js.map +1 -0
  62. package/dist/cli.d.ts +5 -0
  63. package/dist/cli.d.ts.map +1 -0
  64. package/dist/cli.js +134 -0
  65. package/dist/cli.js.map +1 -0
  66. package/dist/config.d.ts +2 -0
  67. package/dist/config.d.ts.map +1 -0
  68. package/dist/config.js +52 -0
  69. package/dist/config.js.map +1 -0
  70. package/dist/core/annotation.d.ts +22 -0
  71. package/dist/core/annotation.d.ts.map +1 -0
  72. package/dist/core/annotation.js +45 -0
  73. package/dist/core/annotation.js.map +1 -0
  74. package/dist/core/compile.d.ts +3 -0
  75. package/dist/core/compile.d.ts.map +1 -0
  76. package/dist/core/compile.js +9 -0
  77. package/dist/core/compile.js.map +1 -0
  78. package/dist/core/executor.d.ts +32 -0
  79. package/dist/core/executor.d.ts.map +1 -0
  80. package/dist/core/executor.js +73 -0
  81. package/dist/core/executor.js.map +1 -0
  82. package/dist/core/json.d.ts +9 -0
  83. package/dist/core/json.d.ts.map +1 -0
  84. package/dist/core/json.js +49 -0
  85. package/dist/core/json.js.map +1 -0
  86. package/dist/core/llm/base.d.ts +9 -0
  87. package/dist/core/llm/base.d.ts.map +1 -0
  88. package/dist/core/llm/base.js +3 -0
  89. package/dist/core/llm/base.js.map +1 -0
  90. package/dist/core/llm/build.d.ts +16 -0
  91. package/dist/core/llm/build.d.ts.map +1 -0
  92. package/dist/core/llm/build.js +34 -0
  93. package/dist/core/llm/build.js.map +1 -0
  94. package/dist/core/llm/claudeCli.d.ts +20 -0
  95. package/dist/core/llm/claudeCli.d.ts.map +1 -0
  96. package/dist/core/llm/claudeCli.js +57 -0
  97. package/dist/core/llm/claudeCli.js.map +1 -0
  98. package/dist/core/llm/codexCli.d.ts +13 -0
  99. package/dist/core/llm/codexCli.d.ts.map +1 -0
  100. package/dist/core/llm/codexCli.js +30 -0
  101. package/dist/core/llm/codexCli.js.map +1 -0
  102. package/dist/core/llm/cursorCli.d.ts +13 -0
  103. package/dist/core/llm/cursorCli.d.ts.map +1 -0
  104. package/dist/core/llm/cursorCli.js +27 -0
  105. package/dist/core/llm/cursorCli.js.map +1 -0
  106. package/dist/core/llm/index.d.ts +5 -0
  107. package/dist/core/llm/index.d.ts.map +1 -0
  108. package/dist/core/llm/index.js +4 -0
  109. package/dist/core/llm/index.js.map +1 -0
  110. package/dist/core/llm/scripted.d.ts +16 -0
  111. package/dist/core/llm/scripted.d.ts.map +1 -0
  112. package/dist/core/llm/scripted.js +29 -0
  113. package/dist/core/llm/scripted.js.map +1 -0
  114. package/dist/core/progress.d.ts +29 -0
  115. package/dist/core/progress.d.ts.map +1 -0
  116. package/dist/core/progress.js +22 -0
  117. package/dist/core/progress.js.map +1 -0
  118. package/dist/core/registry.d.ts +29 -0
  119. package/dist/core/registry.d.ts.map +1 -0
  120. package/dist/core/registry.js +63 -0
  121. package/dist/core/registry.js.map +1 -0
  122. package/dist/core/spawn.d.ts +19 -0
  123. package/dist/core/spawn.d.ts.map +1 -0
  124. package/dist/core/spawn.js +58 -0
  125. package/dist/core/spawn.js.map +1 -0
  126. package/dist/core/state.d.ts +58 -0
  127. package/dist/core/state.d.ts.map +1 -0
  128. package/dist/core/state.js +3 -0
  129. package/dist/core/state.js.map +1 -0
  130. package/dist/core/timeout.d.ts +13 -0
  131. package/dist/core/timeout.d.ts.map +1 -0
  132. package/dist/core/timeout.js +33 -0
  133. package/dist/core/timeout.js.map +1 -0
  134. package/dist/core/types.d.ts +15 -0
  135. package/dist/core/types.d.ts.map +1 -0
  136. package/dist/core/types.js +3 -0
  137. package/dist/core/types.js.map +1 -0
  138. package/dist/core/validate.d.ts +7 -0
  139. package/dist/core/validate.d.ts.map +1 -0
  140. package/dist/core/validate.js +47 -0
  141. package/dist/core/validate.js.map +1 -0
  142. package/dist/graph.d.ts +4 -0
  143. package/dist/graph.d.ts.map +1 -0
  144. package/dist/graph.js +14 -0
  145. package/dist/graph.js.map +1 -0
  146. package/dist/index.d.ts +18 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +16 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/modes/adversarial.d.ts +3 -0
  151. package/dist/modes/adversarial.d.ts.map +1 -0
  152. package/dist/modes/adversarial.js +42 -0
  153. package/dist/modes/adversarial.js.map +1 -0
  154. package/dist/modes/consensus.d.ts +3 -0
  155. package/dist/modes/consensus.d.ts.map +1 -0
  156. package/dist/modes/consensus.js +47 -0
  157. package/dist/modes/consensus.js.map +1 -0
  158. package/dist/modes/debate.d.ts +3 -0
  159. package/dist/modes/debate.d.ts.map +1 -0
  160. package/dist/modes/debate.js +76 -0
  161. package/dist/modes/debate.js.map +1 -0
  162. package/dist/modes/index.d.ts +7 -0
  163. package/dist/modes/index.d.ts.map +1 -0
  164. package/dist/modes/index.js +7 -0
  165. package/dist/modes/index.js.map +1 -0
  166. package/dist/modes/single.d.ts +3 -0
  167. package/dist/modes/single.d.ts.map +1 -0
  168. package/dist/modes/single.js +42 -0
  169. package/dist/modes/single.js.map +1 -0
  170. package/dist/modes/tournament.d.ts +3 -0
  171. package/dist/modes/tournament.d.ts.map +1 -0
  172. package/dist/modes/tournament.js +48 -0
  173. package/dist/modes/tournament.js.map +1 -0
  174. package/dist/nodes/agentRunner.d.ts +15 -0
  175. package/dist/nodes/agentRunner.d.ts.map +1 -0
  176. package/dist/nodes/agentRunner.js +106 -0
  177. package/dist/nodes/agentRunner.js.map +1 -0
  178. package/dist/nodes/auditor.d.ts +38 -0
  179. package/dist/nodes/auditor.d.ts.map +1 -0
  180. package/dist/nodes/auditor.js +179 -0
  181. package/dist/nodes/auditor.js.map +1 -0
  182. package/dist/nodes/bracket.d.ts +19 -0
  183. package/dist/nodes/bracket.d.ts.map +1 -0
  184. package/dist/nodes/bracket.js +90 -0
  185. package/dist/nodes/bracket.js.map +1 -0
  186. package/dist/nodes/consensusEngine.d.ts +18 -0
  187. package/dist/nodes/consensusEngine.d.ts.map +1 -0
  188. package/dist/nodes/consensusEngine.js +94 -0
  189. package/dist/nodes/consensusEngine.js.map +1 -0
  190. package/dist/nodes/moderator.d.ts +20 -0
  191. package/dist/nodes/moderator.d.ts.map +1 -0
  192. package/dist/nodes/moderator.js +83 -0
  193. package/dist/nodes/moderator.js.map +1 -0
  194. package/dist/nodes/planner.d.ts +17 -0
  195. package/dist/nodes/planner.d.ts.map +1 -0
  196. package/dist/nodes/planner.js +40 -0
  197. package/dist/nodes/planner.js.map +1 -0
  198. package/dist/nodes/supervisor.d.ts +28 -0
  199. package/dist/nodes/supervisor.d.ts.map +1 -0
  200. package/dist/nodes/supervisor.js +75 -0
  201. package/dist/nodes/supervisor.js.map +1 -0
  202. package/package.json +66 -0
  203. package/schemas/coterie.config.schema.json +204 -0
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # coterie
2
+
3
+ A conversational meta-agent for your terminal. You chat like you're talking to a
4
+ single coding assistant, but **every turn runs through a multi-agent coordination
5
+ round** (debate, adversarial review, tournament, consensus, or single) behind the
6
+ scenes — raising the reliability and quality of each response.
7
+
8
+ ```bash
9
+ coterie chat # in any repo — each prompt runs a multi-agent round
10
+ ```
11
+
12
+ ```
13
+ ▲ coterie chat
14
+ mode=adversarial · workdir=. · agents: claude-code, codex, cursor · $0 metered
15
+ modes: single, adversarial, debate, tournament, consensus
16
+ Each turn: agents deliberate, then one finalizer applies edits + replies. /mode to change modes. /help for commands.
17
+
18
+ coterie(adversarial)› add a retry decorator to http.py and cover it with tests
19
+ · implementer (claude-code)
20
+ · auditor (codex)
21
+ · judge → claude-code: tests pass, edge cases covered
22
+
23
+ Added @retry to http.py with exponential backoff + tests in test_http.py.
24
+ ```
25
+
26
+ ## Setup (one-time)
27
+
28
+ Install from npm — puts the `coterie` command on your PATH:
29
+
30
+ ```bash
31
+ npm install -g coterie
32
+ ```
33
+
34
+ <details>
35
+ <summary>Or install from source</summary>
36
+
37
+ ```bash
38
+ git clone https://github.com/cxk280/coterie
39
+ cd coterie/packages/coterie-js
40
+ npm install
41
+ npm run build # compile TypeScript → dist/
42
+ npm link # puts `coterie` on your PATH globally
43
+ ```
44
+ </details>
45
+
46
+ Sign in to **at least two** agent CLIs — Coterie coordinates multiple agents, so
47
+ it needs two to deliberate (any pair), and uses all you have. They run on your
48
+ **subscriptions**, no API keys:
49
+
50
+ ```bash
51
+ claude # sign in to Claude Max, then exit
52
+ codex # sign in with your ChatGPT account
53
+ cursor-agent login # sign in to Cursor
54
+ ```
55
+
56
+ Run `coterie doctor` to see which are ready:
57
+
58
+ ```bash
59
+ coterie doctor # ✓/✗ per agent; exits non-zero until at least two are ready
60
+ ```
61
+
62
+ Coterie keeps no config of binary paths or credentials — it finds each CLI on
63
+ your `PATH` and lets it read its own creds, so it authenticates exactly as your
64
+ shell does. `coterie chat` also runs this check on startup.
65
+
66
+ Then, in any repo you want it to work in:
67
+
68
+ ```bash
69
+ cd ~/my-project
70
+ coterie chat # runs entirely on your subscriptions — $0 metered
71
+ ```
72
+
73
+ ## How it works
74
+
75
+ Each prompt becomes a one-turn coordination round over the **real coding-agent
76
+ CLIs you already have** — any two or more of Claude Code, Codex, and Cursor. The
77
+ mode decides how they cooperate; the synthesized result (and any file edits) is
78
+ the reply. Switch strategies per prompt with `/mode <name>`.
79
+
80
+ Each turn has two phases: the agents **deliberate** in throwaway worktrees (they
81
+ never touch your files), then one **finalizer** agent runs in your workdir,
82
+ applies the edits, and writes the plain-prose reply. So file edits land in *every*
83
+ mode, and you never get raw findings JSON back. The mode shapes the deliberation:
84
+
85
+ | Mode | What the agents do | Best for |
86
+ |---|---|---|
87
+ | `single` | a router picks one agent to attempt it | quick edits, simple asks |
88
+ | `adversarial` | implementer + auditor + judge, with refinement | reliable code changes |
89
+ | `debate` | two agents argue, a moderator + judge decide | decisions, tradeoffs |
90
+ | `tournament` | N agents compete, a bracket judge ranks | best-of-N for critical work |
91
+ | `consensus` | agents review independently, an engine merges agreement | reviews, audits |
92
+
93
+ ## Runs on your subscriptions ($0 metered)
94
+
95
+ Everything runs on your existing logins — the agents on **Claude Max**, **ChatGPT**
96
+ (Codex), and **Cursor Pro**, and the behind-the-scenes coordination (routing /
97
+ judging / moderating) on your **Claude subscription** via `claude -p`. So a full
98
+ turn is **$0 metered** — no setup, no flags. On startup `coterie chat` checks each
99
+ required CLI is installed and signed in, and tells you exactly what to do if not.
100
+
101
+ > **No pay-as-you-go API backend (yet).** Coordination is subscription-only by
102
+ > design, so a session can never run up a surprise metered bill. A pluggable API
103
+ > provider (Anthropic / OpenAI-compatible) may be added later for environments
104
+ > without the subscription CLIs — it's intentionally not wired in today.
105
+
106
+ > **Grok is deferred** for the same reason: unlike Claude / Codex / Cursor it has
107
+ > no subscription-backed headless coding CLI (only the pay-as-you-go xAI API), so
108
+ > it can't join the $0-metered lineup yet.
109
+
110
+ ## Commands
111
+
112
+ `/mode <name>` · `/show` `/hide` (live agent exchanges) · `/clear` · `/help` · `/exit`
113
+
114
+ The agent exchanges stream live by default — each agent's contribution, the
115
+ judge's verdict, what the finalizer changed. `/hide` (or `--quiet`) shows only the
116
+ reply.
117
+
118
+ ```bash
119
+ coterie chat --mode debate --workdir ~/proj # start in a mode, against a repo
120
+ coterie chat --quiet # hide the agent exchanges
121
+ ```
122
+
123
+ ## One-shot (non-conversational)
124
+
125
+ ```bash
126
+ coterie run "find every bug in src/auth.ts" --config examples/consensus.coterie.yaml
127
+ ```
128
+
129
+ ## Test
130
+
131
+ ```bash
132
+ npm test # fast, offline, deterministic — the CI gate
133
+ npm run test:e2e # real-agent end-to-end (spends subscription calls; needs claude + codex signed in)
134
+ ```
135
+
136
+ See the [top-level README](../../README.md) for architecture, the five modes in
137
+ depth, and the full breakdown of the three test layers.
@@ -0,0 +1,56 @@
1
+ /** CLIAdapter contract. Mirrors Python's `adapters/base.py`. */
2
+ export interface AdapterResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exit_code: number;
6
+ files_changed: string[];
7
+ duration_s: number;
8
+ cost_estimate_usd: number | null;
9
+ }
10
+ export interface CLIAdapterCtor {
11
+ adapterName: string;
12
+ new (agent_id: string, opts?: {
13
+ model?: string;
14
+ }): CLIAdapter;
15
+ }
16
+ /** A DOMException-style abort error so callers can detect cancellation via
17
+ * `err.name === "AbortError"` (matches what `fetch`/AbortSignal users expect). */
18
+ export declare function abortError(): Error;
19
+ export declare abstract class CLIAdapter {
20
+ readonly agent_id: string;
21
+ readonly opts: {
22
+ model?: string;
23
+ };
24
+ static readonly adapterName: string;
25
+ /**
26
+ * Env vars stripped from the agent subprocess. Lets an adapter force its CLI
27
+ * onto its own auth (e.g. a subscription session) instead of an API key that
28
+ * Coterie's coordination LLMs need in-process.
29
+ */
30
+ static readonly stripEnv: readonly string[];
31
+ constructor(agent_id: string, opts?: {
32
+ model?: string;
33
+ });
34
+ get model(): string | undefined;
35
+ private subprocessEnv;
36
+ abstract buildCommand(prompt: string, workdir: string, extra: Record<string, unknown>): string[];
37
+ abstract parseResult(stdout: string, stderr: string, exitCode: number): AdapterResult;
38
+ /** Turn one line of the CLI's streaming (NDJSON) output into a short, human
39
+ * -readable progress note (e.g. "→ Read foo.ts", "→ $ npm test"), or null to
40
+ * ignore it. Adapters that run in a streaming format override this; the
41
+ * default (no streaming) yields nothing. */
42
+ streamEvent(_line: string): string | null;
43
+ /** Run the agent CLI asynchronously. Async (vs the old `spawnSync`) is what
44
+ * keeps Node's event loop free during a turn — so the chat trace can stream
45
+ * live, SIGINT is handled, and fan-out agents run concurrently. Honors a
46
+ * timeout and an optional AbortSignal (both kill the child). */
47
+ run(prompt: string, workdir: string, opts?: {
48
+ timeoutMs?: number;
49
+ extra?: Record<string, unknown>;
50
+ signal?: AbortSignal;
51
+ onStream?: (text: string) => void;
52
+ }): Promise<AdapterResult>;
53
+ private spawnCollect;
54
+ protected gitChangedFiles(workdir: string): string[];
55
+ }
56
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAMhE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAC;CAC/D;AAED;mFACmF;AACnF,wBAAgB,UAAU,IAAI,KAAK,CAIlC;AAED,8BAAsB,UAAU;aAWZ,QAAQ,EAAE,MAAM;aAChB,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAX1C,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAEpC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAM;gBAG/B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;IAG/C,IAAI,KAAK,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED,OAAO,CAAC,aAAa;IAQrB,QAAQ,CAAC,YAAY,CACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,EAAE;IAEX,QAAQ,CAAC,WAAW,CAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,aAAa;IAEhB;;;iDAG6C;IAC7C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIzC;;;qEAGiE;IAC3D,GAAG,CACP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;QACJ,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,GACL,OAAO,CAAC,aAAa,CAAC;IAczB,OAAO,CAAC,YAAY;IAuGpB,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;CAWrD"}
@@ -0,0 +1,176 @@
1
+ /** CLIAdapter contract. Mirrors Python's `adapters/base.py`. */
2
+ import { spawn, spawnSync } from "node:child_process";
3
+ import { sleepAwareTimeout } from "../core/timeout.js";
4
+ /** A DOMException-style abort error so callers can detect cancellation via
5
+ * `err.name === "AbortError"` (matches what `fetch`/AbortSignal users expect). */
6
+ export function abortError() {
7
+ const e = new Error("The operation was aborted");
8
+ e.name = "AbortError";
9
+ return e;
10
+ }
11
+ export class CLIAdapter {
12
+ agent_id;
13
+ opts;
14
+ static adapterName;
15
+ /**
16
+ * Env vars stripped from the agent subprocess. Lets an adapter force its CLI
17
+ * onto its own auth (e.g. a subscription session) instead of an API key that
18
+ * Coterie's coordination LLMs need in-process.
19
+ */
20
+ static stripEnv = [];
21
+ constructor(agent_id, opts = {}) {
22
+ this.agent_id = agent_id;
23
+ this.opts = opts;
24
+ }
25
+ get model() {
26
+ return this.opts.model;
27
+ }
28
+ subprocessEnv() {
29
+ const strip = this.constructor.stripEnv;
30
+ if (!strip.length)
31
+ return undefined; // inherit process.env
32
+ const env = { ...process.env };
33
+ for (const key of strip)
34
+ delete env[key];
35
+ return env;
36
+ }
37
+ /** Turn one line of the CLI's streaming (NDJSON) output into a short, human
38
+ * -readable progress note (e.g. "→ Read foo.ts", "→ $ npm test"), or null to
39
+ * ignore it. Adapters that run in a streaming format override this; the
40
+ * default (no streaming) yields nothing. */
41
+ streamEvent(_line) {
42
+ return null;
43
+ }
44
+ /** Run the agent CLI asynchronously. Async (vs the old `spawnSync`) is what
45
+ * keeps Node's event loop free during a turn — so the chat trace can stream
46
+ * live, SIGINT is handled, and fan-out agents run concurrently. Honors a
47
+ * timeout and an optional AbortSignal (both kill the child). */
48
+ async run(prompt, workdir, opts = {}) {
49
+ const argv = this.buildCommand(prompt, workdir, opts.extra ?? {});
50
+ const [cmd, ...args] = argv;
51
+ if (!cmd)
52
+ throw new Error(`Adapter ${this.agent_id} produced an empty command`);
53
+ const t0 = Date.now();
54
+ const { stdout, stderr, code } = await this.spawnCollect(cmd, args, workdir, opts);
55
+ const result = this.parseResult(stdout, stderr, code);
56
+ result.duration_s = (Date.now() - t0) / 1000;
57
+ // Report which files the agent actually touched (so the trace can show
58
+ // "edited X, Y") unless the adapter already computed it.
59
+ if (!result.files_changed?.length)
60
+ result.files_changed = this.gitChangedFiles(workdir);
61
+ return result;
62
+ }
63
+ spawnCollect(cmd, args, workdir, opts) {
64
+ return new Promise((resolve, reject) => {
65
+ if (opts.signal?.aborted)
66
+ return reject(abortError());
67
+ // stdin = /dev/null so the child gets an immediate EOF. Headless agent CLIs
68
+ // (notably `codex exec`) otherwise block forever waiting on stdin — async
69
+ // spawn leaves the stdin pipe open, unlike the old spawnSync which closed it.
70
+ const child = spawn(cmd, args, {
71
+ cwd: workdir,
72
+ env: this.subprocessEnv(),
73
+ stdio: ["ignore", "pipe", "pipe"],
74
+ });
75
+ let stdout = "";
76
+ let stderr = "";
77
+ const cap = 32 * 1024 * 1024;
78
+ // Buffer stdout into whole lines so each NDJSON event can be turned into a
79
+ // live progress note as it streams (without blocking — the loop is free).
80
+ const lineCap = 1024 * 1024;
81
+ let lineBuf = "";
82
+ // True while we're discarding an over-cap, not-yet-terminated line; reset
83
+ // at the next newline so streaming resyncs on the following whole line.
84
+ let lineOverflow = false;
85
+ child.stdout?.on("data", (d) => {
86
+ const s = d.toString();
87
+ if (stdout.length < cap)
88
+ stdout += s;
89
+ if (!opts.onStream)
90
+ return;
91
+ lineBuf += s;
92
+ let nl;
93
+ while ((nl = lineBuf.indexOf("\n")) >= 0) {
94
+ const line = lineBuf.slice(0, nl);
95
+ lineBuf = lineBuf.slice(nl + 1);
96
+ if (lineOverflow) {
97
+ // This newline closes the dropped line; resume on the next one.
98
+ lineOverflow = false;
99
+ continue;
100
+ }
101
+ try {
102
+ const note = this.streamEvent(line);
103
+ if (note)
104
+ opts.onStream(note);
105
+ }
106
+ catch {
107
+ // a malformed line must never break the run
108
+ }
109
+ }
110
+ // Bound the partial-line buffer: a producer that emits a multi-megabyte
111
+ // single line (or never a newline) must not grow it without limit — the
112
+ // authoritative `stdout` is capped, and progress notes are best-effort,
113
+ // so drop the partial line and resync at the next newline.
114
+ if (lineBuf.length > lineCap) {
115
+ lineBuf = "";
116
+ lineOverflow = true;
117
+ }
118
+ });
119
+ child.stderr?.on("data", (d) => {
120
+ if (stderr.length < cap)
121
+ stderr += d.toString();
122
+ });
123
+ // Graceful kill: SIGTERM, then SIGKILL if it doesn't exit in time.
124
+ const hardKill = () => {
125
+ if (!child.killed)
126
+ child.kill("SIGKILL");
127
+ };
128
+ const kill = () => {
129
+ child.kill("SIGTERM");
130
+ setTimeout(hardKill, 2_000).unref();
131
+ };
132
+ const timeoutMs = opts.timeoutMs ?? 600_000;
133
+ let timedOut = false;
134
+ // Sleep-aware: a wall-clock timer would kill a merely-suspended child the
135
+ // instant the machine wakes. This only counts active time.
136
+ const clearTimer = sleepAwareTimeout(timeoutMs, () => {
137
+ timedOut = true;
138
+ kill();
139
+ });
140
+ const onAbort = () => {
141
+ kill();
142
+ cleanup();
143
+ reject(abortError());
144
+ };
145
+ opts.signal?.addEventListener("abort", onAbort, { once: true });
146
+ const cleanup = () => {
147
+ clearTimer();
148
+ opts.signal?.removeEventListener("abort", onAbort);
149
+ };
150
+ child.on("error", (err) => {
151
+ cleanup();
152
+ reject(err);
153
+ });
154
+ child.on("close", (code) => {
155
+ cleanup();
156
+ if (timedOut)
157
+ reject(new Error(`timed out after ${Math.round(timeoutMs / 1000)}s`));
158
+ else
159
+ resolve({ stdout, stderr, code: code ?? 1 });
160
+ });
161
+ });
162
+ }
163
+ gitChangedFiles(workdir) {
164
+ const proc = spawnSync("git", ["status", "--porcelain"], {
165
+ cwd: workdir,
166
+ encoding: "utf8",
167
+ });
168
+ if (proc.status !== 0)
169
+ return [];
170
+ return (proc.stdout ?? "")
171
+ .split("\n")
172
+ .filter((l) => l.trim())
173
+ .map((l) => l.slice(3));
174
+ }
175
+ }
176
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { CLIAdapter, type AdapterResult } from "./base.js";
2
+ export declare class ClaudeCodeAdapter extends CLIAdapter {
3
+ static readonly adapterName = "claude-code";
4
+ static readonly stripEnv: string[];
5
+ buildCommand(prompt: string, _workdir: string, extra?: Record<string, unknown>): string[];
6
+ /** Emit a note for each tool the agent invokes; skip thinking/text/bookkeeping
7
+ * (the final answer is rendered when the run completes). */
8
+ streamEvent(line: string): string | null;
9
+ parseResult(stdout: string, stderr: string, exitCode: number): AdapterResult;
10
+ }
11
+ //# sourceMappingURL=claudeCode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeCode.d.ts","sourceRoot":"","sources":["../../src/adapters/claudeCode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAK3D,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;IAI5C,MAAM,CAAC,QAAQ,CAAC,QAAQ,WAAiD;IAEzE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,EAAE;IAU7F;iEAC6D;IACpD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IASjD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;CA8B7E"}
@@ -0,0 +1,65 @@
1
+ import { CLIAdapter } from "./base.js";
2
+ import { parseJsonLoose, parseNdjson } from "../core/json.js";
3
+ import { toolHint } from "./stream.js";
4
+ import { registerAdapter } from "../core/registry.js";
5
+ export class ClaudeCodeAdapter extends CLIAdapter {
6
+ static adapterName = "claude-code";
7
+ // Run on the user's Claude subscription (OAuth session), not a pay-per-token
8
+ // API key — coordination LLMs use ANTHROPIC_API_KEY in-process, but the agent
9
+ // CLI should bill against the subscription.
10
+ static stripEnv = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
11
+ buildCommand(prompt, _workdir, extra = {}) {
12
+ // acceptEdits lets the agent apply file edits headlessly while still gating
13
+ // riskier tools — safe against an isolated workdir. stream-json (which needs
14
+ // --verbose) emits one NDJSON event per step so we can show live progress.
15
+ const permissionMode = extra.permissionMode ?? "acceptEdits";
16
+ const cmd = ["claude", "-p", prompt, "--output-format", "stream-json", "--verbose", "--permission-mode", permissionMode];
17
+ if (this.model)
18
+ cmd.push("--model", this.model);
19
+ return cmd;
20
+ }
21
+ /** Emit a note for each tool the agent invokes; skip thinking/text/bookkeeping
22
+ * (the final answer is rendered when the run completes). */
23
+ streamEvent(line) {
24
+ const ev = parseJsonLoose(line);
25
+ if (ev?.type !== "assistant")
26
+ return null;
27
+ for (const c of ev.message?.content ?? []) {
28
+ if (c?.type === "tool_use")
29
+ return `→ ${c.name}${toolHint(c.input)}`;
30
+ }
31
+ return null;
32
+ }
33
+ parseResult(stdout, stderr, exitCode) {
34
+ // stdout is an NDJSON stream; the final `result` event carries the answer + cost.
35
+ const events = parseNdjson(stdout);
36
+ const result = events.find((e) => e?.type === "result");
37
+ if (result) {
38
+ const files = events
39
+ .flatMap((e) => (e?.type === "assistant" ? (e.message?.content ?? []) : []))
40
+ .filter((c) => c?.type === "tool_use" && /^(Edit|Write|NotebookEdit)$/.test(c.name))
41
+ .map((c) => c.input?.file_path)
42
+ .filter(Boolean);
43
+ return {
44
+ stdout: result.result ?? stdout,
45
+ stderr,
46
+ exit_code: exitCode,
47
+ files_changed: [...new Set(files)],
48
+ duration_s: 0,
49
+ cost_estimate_usd: result.total_cost_usd ?? null,
50
+ };
51
+ }
52
+ // Fallback: not the expected stream (older CLI / plain JSON / prose).
53
+ const loose = parseJsonLoose(stdout);
54
+ return {
55
+ stdout: loose?.result ?? stdout,
56
+ stderr,
57
+ exit_code: exitCode,
58
+ files_changed: [],
59
+ duration_s: 0,
60
+ cost_estimate_usd: loose?.total_cost_usd ?? null,
61
+ };
62
+ }
63
+ }
64
+ registerAdapter(ClaudeCodeAdapter);
65
+ //# sourceMappingURL=claudeCode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/adapters/claudeCode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { CLIAdapter, type AdapterResult } from "./base.js";
2
+ export declare class CodexAdapter extends CLIAdapter {
3
+ static readonly adapterName = "codex";
4
+ buildCommand(prompt: string, _workdir: string, extra?: Record<string, unknown>): string[];
5
+ /** Each non-message item (a command, a file change, reasoning) is live activity;
6
+ * the final agent_message is the answer, surfaced on completion. */
7
+ streamEvent(line: string): string | null;
8
+ parseResult(stdout: string, stderr: string, exit_code: number): AdapterResult;
9
+ }
10
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAI3D,qBAAa,YAAa,SAAQ,UAAU;IAC1C,MAAM,CAAC,QAAQ,CAAC,WAAW,WAAW;IAEtC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,EAAE;IAU7F;yEACqE;IAC5D,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAajD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa;CAgB9E"}
@@ -0,0 +1,51 @@
1
+ import { CLIAdapter } from "./base.js";
2
+ import { parseJsonLoose, parseNdjson } from "../core/json.js";
3
+ import { registerAdapter } from "../core/registry.js";
4
+ export class CodexAdapter extends CLIAdapter {
5
+ static adapterName = "codex";
6
+ buildCommand(prompt, _workdir, extra = {}) {
7
+ // workspace-write sandboxes edits to the cwd; --skip-git-repo-check lets exec
8
+ // run in a plain (non-git) workdir; --json streams JSONL events for live progress.
9
+ const sandbox = extra.sandbox ?? "workspace-write";
10
+ const cmd = ["codex", "exec", "--skip-git-repo-check", "--json", "-s", sandbox];
11
+ if (this.model)
12
+ cmd.push("--model", this.model);
13
+ cmd.push(prompt);
14
+ return cmd;
15
+ }
16
+ /** Each non-message item (a command, a file change, reasoning) is live activity;
17
+ * the final agent_message is the answer, surfaced on completion. */
18
+ streamEvent(line) {
19
+ const ev = parseJsonLoose(line);
20
+ if (ev?.type !== "item.completed")
21
+ return null;
22
+ const it = ev.item ?? {};
23
+ if (it.type === "agent_message" || it.type === "reasoning")
24
+ return null;
25
+ if (it.command)
26
+ return `→ $ ${String(it.command).replace(/\s+/g, " ").slice(0, 80)}`;
27
+ if (it.type === "file_change" || it.type === "patch") {
28
+ const f = it.path ?? (Array.isArray(it.changes) ? it.changes.map((c) => c.path).join(", ") : "");
29
+ return `→ edit ${String(f).slice(0, 80)}`.trimEnd();
30
+ }
31
+ return `→ ${String(it.type).replace(/_/g, " ")}`;
32
+ }
33
+ parseResult(stdout, stderr, exit_code) {
34
+ // stdout is JSONL; the answer is the last `agent_message` item.
35
+ const events = parseNdjson(stdout);
36
+ const messages = events
37
+ .filter((e) => e?.type === "item.completed" && e.item?.type === "agent_message")
38
+ .map((e) => e.item.text)
39
+ .filter(Boolean);
40
+ return {
41
+ stdout: messages.length ? messages[messages.length - 1] : stdout,
42
+ stderr,
43
+ exit_code,
44
+ files_changed: [],
45
+ duration_s: 0,
46
+ cost_estimate_usd: null,
47
+ };
48
+ }
49
+ }
50
+ registerAdapter(CodexAdapter);
51
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { CLIAdapter, type AdapterResult } from "./base.js";
2
+ /**
3
+ * Cursor's headless agent CLI (`cursor-agent`), run on a Cursor Pro subscription.
4
+ * NB: `cursor-agent` is a separate install from the `cursor` editor launcher; the
5
+ * chat preflight checks for it. Flags verified against cursor-agent's print mode:
6
+ * `-p` non-interactive, `--output-format stream-json` (NDJSON events for live
7
+ * progress), `--force` to apply edits without a confirmation/trust prompt.
8
+ */
9
+ export declare class CursorAdapter extends CLIAdapter {
10
+ static readonly adapterName = "cursor";
11
+ buildCommand(prompt: string, _workdir: string, _extra?: Record<string, unknown>): string[];
12
+ /** Surface tool calls as live activity; skip thinking deltas + the final text. */
13
+ streamEvent(line: string): string | null;
14
+ parseResult(stdout: string, stderr: string, exitCode: number): AdapterResult;
15
+ }
16
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAK3D;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,UAAU;IAC3C,MAAM,CAAC,QAAQ,CAAC,WAAW,YAAY;IAEvC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,EAAE;IAM9F,kFAAkF;IACzE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAWjD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;CAa7E"}
@@ -0,0 +1,47 @@
1
+ import { CLIAdapter } from "./base.js";
2
+ import { parseJsonLoose, parseNdjson } from "../core/json.js";
3
+ import { toolHint } from "./stream.js";
4
+ import { registerAdapter } from "../core/registry.js";
5
+ /**
6
+ * Cursor's headless agent CLI (`cursor-agent`), run on a Cursor Pro subscription.
7
+ * NB: `cursor-agent` is a separate install from the `cursor` editor launcher; the
8
+ * chat preflight checks for it. Flags verified against cursor-agent's print mode:
9
+ * `-p` non-interactive, `--output-format stream-json` (NDJSON events for live
10
+ * progress), `--force` to apply edits without a confirmation/trust prompt.
11
+ */
12
+ export class CursorAdapter extends CLIAdapter {
13
+ static adapterName = "cursor";
14
+ buildCommand(prompt, _workdir, _extra = {}) {
15
+ const cmd = ["cursor-agent", "-p", prompt, "--output-format", "stream-json", "--force"];
16
+ if (this.model)
17
+ cmd.push("--model", this.model);
18
+ return cmd;
19
+ }
20
+ /** Surface tool calls as live activity; skip thinking deltas + the final text. */
21
+ streamEvent(line) {
22
+ const ev = parseJsonLoose(line);
23
+ if (ev?.type !== "assistant")
24
+ return null;
25
+ for (const c of ev.message?.content ?? []) {
26
+ if (c?.type === "tool_call" || c?.type === "tool_use") {
27
+ return `→ ${c.name ?? "tool"}${toolHint(c.input ?? c.args)}`;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+ parseResult(stdout, stderr, exitCode) {
33
+ // stdout is an NDJSON stream; the `result` event carries the final answer.
34
+ const events = parseNdjson(stdout);
35
+ const result = events.find((e) => e?.type === "result");
36
+ return {
37
+ stdout: result?.result ?? stdout,
38
+ stderr,
39
+ exit_code: exitCode,
40
+ files_changed: [],
41
+ duration_s: 0,
42
+ cost_estimate_usd: null,
43
+ };
44
+ }
45
+ }
46
+ registerAdapter(CursorAdapter);
47
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC;IAEvC,YAAY,CAAC,MAAc,EAAE,QAAgB,EAAE,SAAkC,EAAE;QACjF,MAAM,GAAG,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QACxF,IAAI,IAAI,CAAC,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,kFAAkF;IACzE,WAAW,CAAC,IAAY;QAC/B,MAAM,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,EAAE,EAAE,IAAI,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,EAAE,IAAI,KAAK,WAAW,IAAI,CAAC,EAAE,IAAI,KAAK,UAAU,EAAE,CAAC;gBACtD,OAAO,KAAK,CAAC,CAAC,IAAI,IAAI,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/D,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,MAAc,EAAE,MAAc,EAAE,QAAgB;QAC1D,2EAA2E;QAC3E,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC;QACxD,OAAO;YACL,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,MAAM;YAChC,MAAM;YACN,SAAS,EAAE,QAAQ;YACnB,aAAa,EAAE,EAAE;YACjB,UAAU,EAAE,CAAC;YACb,iBAAiB,EAAE,IAAI;SACxB,CAAC;IACJ,CAAC;;AAGH,eAAe,CAAC,aAAa,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** In-process FakeAdapter for tests / offline demos. */
2
+ import { CLIAdapter, type AdapterResult } from "./base.js";
3
+ export declare class FakeAdapterError extends Error {
4
+ }
5
+ export declare class FakeAdapter extends CLIAdapter {
6
+ static readonly adapterName = "fake";
7
+ private static scripts;
8
+ private static invocationsByAgent;
9
+ static script(agent_id: string, results: AdapterResult[]): void;
10
+ static invocationsFor(agent_id: string): Array<{
11
+ prompt: string;
12
+ workdir: string;
13
+ }>;
14
+ static resetAll(): void;
15
+ buildCommand(): string[];
16
+ parseResult(stdout: string, stderr: string, exit_code: number): AdapterResult;
17
+ run(prompt: string, workdir: string): Promise<AdapterResult>;
18
+ }
19
+ //# sourceMappingURL=fake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake.d.ts","sourceRoot":"","sources":["../../src/adapters/fake.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAG3D,qBAAa,gBAAiB,SAAQ,KAAK;CAAG;AAE9C,qBAAa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,QAAQ,CAAC,WAAW,UAAU;IAErC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAsC;IAC5D,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAiE;IAElG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAO/D,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAInF,MAAM,CAAC,QAAQ,IAAI,IAAI;IAKvB,YAAY,IAAI,MAAM,EAAE;IAIxB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa;IAI9D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAa5E"}