issue-flow 0.12.0 → 0.14.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 (197) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-OX3KPHE4.js +30 -0
  3. package/dist/{analyze-OEET7KGE.js → analyze-WIND2SEB.js} +31 -16
  4. package/dist/analyze-WIND2SEB.js.map +1 -0
  5. package/dist/{apply-ZIA3C52S.js → apply-JNOI2LR4.js} +18 -7
  6. package/dist/{apply-ZIA3C52S.js.map → apply-JNOI2LR4.js.map} +1 -1
  7. package/dist/bench-B4VZON7E.js +910 -0
  8. package/dist/bench-B4VZON7E.js.map +1 -0
  9. package/dist/{chunk-FADTCQGM.js → chunk-2IQ6M4ZE.js} +94 -32
  10. package/dist/chunk-2IQ6M4ZE.js.map +1 -0
  11. package/dist/chunk-3BWZO4YI.js +141 -0
  12. package/dist/chunk-3BWZO4YI.js.map +1 -0
  13. package/dist/chunk-3WFZETIM.js +163 -0
  14. package/dist/chunk-3WFZETIM.js.map +1 -0
  15. package/dist/chunk-67YIU2VB.js +362 -0
  16. package/dist/chunk-67YIU2VB.js.map +1 -0
  17. package/dist/{chunk-QCPGHBSZ.js → chunk-6BENHR2I.js} +63 -21
  18. package/dist/chunk-6BENHR2I.js.map +1 -0
  19. package/dist/{chunk-BYZDPR7N.js → chunk-6QYMSNVA.js} +194 -235
  20. package/dist/chunk-6QYMSNVA.js.map +1 -0
  21. package/dist/{chunk-Y5ZDJ4PJ.js → chunk-76MMPJ53.js} +20 -10
  22. package/dist/chunk-76MMPJ53.js.map +1 -0
  23. package/dist/chunk-7Z4Y3VKM.js +26 -0
  24. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  25. package/dist/{chunk-3QHK4YQA.js → chunk-B72RQZBV.js} +346 -119
  26. package/dist/chunk-B72RQZBV.js.map +1 -0
  27. package/dist/chunk-BEZ5BA5U.js +625 -0
  28. package/dist/chunk-BEZ5BA5U.js.map +1 -0
  29. package/dist/chunk-BRCNQXYQ.js +74 -0
  30. package/dist/chunk-BRCNQXYQ.js.map +1 -0
  31. package/dist/chunk-CGKLE6WR.js +1203 -0
  32. package/dist/chunk-CGKLE6WR.js.map +1 -0
  33. package/dist/chunk-CRGIQFUQ.js +83 -0
  34. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  35. package/dist/{chunk-NS6R37II.js → chunk-F6TOYSYY.js} +141 -12
  36. package/dist/chunk-F6TOYSYY.js.map +1 -0
  37. package/dist/chunk-G5EK2XRN.js +25 -0
  38. package/dist/chunk-G5EK2XRN.js.map +1 -0
  39. package/dist/chunk-HAKDLR6N.js +134 -0
  40. package/dist/chunk-HAKDLR6N.js.map +1 -0
  41. package/dist/chunk-J3SOTUVI.js +298 -0
  42. package/dist/chunk-J3SOTUVI.js.map +1 -0
  43. package/dist/chunk-JN6D3MY6.js +30 -0
  44. package/dist/chunk-JN6D3MY6.js.map +1 -0
  45. package/dist/{chunk-LAFNLLQP.js → chunk-KMRFRXIT.js} +5 -5
  46. package/dist/chunk-KT7JKOXB.js +72 -0
  47. package/dist/chunk-KT7JKOXB.js.map +1 -0
  48. package/dist/chunk-L6HSKTQE.js +77 -0
  49. package/dist/chunk-L6HSKTQE.js.map +1 -0
  50. package/dist/chunk-LBGHI4S2.js +1264 -0
  51. package/dist/chunk-LBGHI4S2.js.map +1 -0
  52. package/dist/chunk-LEW4QM74.js +180 -0
  53. package/dist/chunk-LEW4QM74.js.map +1 -0
  54. package/dist/{chunk-FJP3UQGD.js → chunk-LFEQIZLB.js} +115 -20
  55. package/dist/chunk-LFEQIZLB.js.map +1 -0
  56. package/dist/chunk-OOVG2KBY.js +77 -0
  57. package/dist/chunk-OOVG2KBY.js.map +1 -0
  58. package/dist/{chunk-56KS3TFQ.js → chunk-OR43364P.js} +115 -160
  59. package/dist/chunk-OR43364P.js.map +1 -0
  60. package/dist/chunk-P3LRUNC6.js +16 -0
  61. package/dist/chunk-P3LRUNC6.js.map +1 -0
  62. package/dist/{chunk-TSOLWK7Y.js → chunk-PBTA3QQX.js} +8 -7
  63. package/dist/{chunk-TSOLWK7Y.js.map → chunk-PBTA3QQX.js.map} +1 -1
  64. package/dist/{chunk-MJULIKQU.js → chunk-PHW2YV6N.js} +23 -47
  65. package/dist/chunk-PHW2YV6N.js.map +1 -0
  66. package/dist/{chunk-73ATPIYX.js → chunk-PZTWU277.js} +36 -71
  67. package/dist/chunk-PZTWU277.js.map +1 -0
  68. package/dist/{chunk-M5UCXTIT.js → chunk-QD4VOILZ.js} +22 -18
  69. package/dist/chunk-QD4VOILZ.js.map +1 -0
  70. package/dist/chunk-QJ5UZAH5.js +2718 -0
  71. package/dist/chunk-QJ5UZAH5.js.map +1 -0
  72. package/dist/chunk-QK7WUO7A.js +283 -0
  73. package/dist/chunk-QK7WUO7A.js.map +1 -0
  74. package/dist/{chunk-A4SLHOW7.js → chunk-QZVKRDJY.js} +27 -19
  75. package/dist/chunk-QZVKRDJY.js.map +1 -0
  76. package/dist/chunk-REO3PXXO.js +71 -0
  77. package/dist/chunk-REO3PXXO.js.map +1 -0
  78. package/dist/{chunk-EZATO3DW.js → chunk-RVO7L4FX.js} +594 -17
  79. package/dist/chunk-RVO7L4FX.js.map +1 -0
  80. package/dist/{chunk-XQUSIEKA.js → chunk-SZMHCEYV.js} +63 -14
  81. package/dist/chunk-SZMHCEYV.js.map +1 -0
  82. package/dist/chunk-TYRNTSPJ.js +243 -0
  83. package/dist/chunk-TYRNTSPJ.js.map +1 -0
  84. package/dist/chunk-UJ3L2MS7.js +238 -0
  85. package/dist/chunk-UJ3L2MS7.js.map +1 -0
  86. package/dist/chunk-V7MO5EDS.js +120 -0
  87. package/dist/chunk-V7MO5EDS.js.map +1 -0
  88. package/dist/chunk-WB2X37MO.js +415 -0
  89. package/dist/chunk-WB2X37MO.js.map +1 -0
  90. package/dist/{chunk-NTMMF5UD.js → chunk-X44FKNKP.js} +525 -252
  91. package/dist/chunk-X44FKNKP.js.map +1 -0
  92. package/dist/chunk-XEYH6ZZI.js +289 -0
  93. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  94. package/dist/cli.js +267 -44
  95. package/dist/cli.js.map +1 -1
  96. package/dist/{config-PRJGWW7J.js → config-HMFMCY2M.js} +31 -5
  97. package/dist/contract-JH2WBIO6.js +8 -0
  98. package/dist/conventions-NJF2OPVQ.js +146 -0
  99. package/dist/conventions-NJF2OPVQ.js.map +1 -0
  100. package/dist/diagnostics-THH42ZMP.js +23 -0
  101. package/dist/execute-KFNNZZHI.js +35 -0
  102. package/dist/{generate-EGB4KV2B.js → generate-FW5C6NP7.js} +37 -20
  103. package/dist/{generate-EGB4KV2B.js.map → generate-FW5C6NP7.js.map} +1 -1
  104. package/dist/git-W72QQ6GT.js +33 -0
  105. package/dist/init-HTN4V67Q.js +24 -0
  106. package/dist/{operations-BYT626KQ.js → operations-BCFOBH42.js} +27 -15
  107. package/dist/{operations-BYT626KQ.js.map → operations-BCFOBH42.js.map} +1 -1
  108. package/dist/permissions-4AKNQZHK.js +18 -0
  109. package/dist/plan-SIZLGA4V.js +34 -0
  110. package/dist/{policy-6S4GFC76.js → policy-DT6Q6ZVM.js} +20 -6
  111. package/dist/policy-DT6Q6ZVM.js.map +1 -0
  112. package/dist/pr-OMWCGUOW.js +39 -0
  113. package/dist/pr-review-N24CZPKR.js +32 -0
  114. package/dist/pr-review-N24CZPKR.js.map +1 -0
  115. package/dist/prd-5OFTZAHJ.js +33 -0
  116. package/dist/prd-5OFTZAHJ.js.map +1 -0
  117. package/dist/ps-RFORTCUD.js +93 -0
  118. package/dist/ps-RFORTCUD.js.map +1 -0
  119. package/dist/recorder-KCCPMKQG.js +32 -0
  120. package/dist/recorder-KCCPMKQG.js.map +1 -0
  121. package/dist/registry-GLPXOMFG.js +15 -0
  122. package/dist/registry-GLPXOMFG.js.map +1 -0
  123. package/dist/{resume-PPCNQVVV.js → resume-M5RLKP4I.js} +55 -34
  124. package/dist/{resume-PPCNQVVV.js.map → resume-M5RLKP4I.js.map} +1 -1
  125. package/dist/review-YM4JAABY.js +35 -0
  126. package/dist/review-YM4JAABY.js.map +1 -0
  127. package/dist/routing-NNT5WKGX.js +94 -0
  128. package/dist/routing-NNT5WKGX.js.map +1 -0
  129. package/dist/run-PZUKHPQK.js +54 -0
  130. package/dist/run-PZUKHPQK.js.map +1 -0
  131. package/dist/session-publisher-T7EI3CIP.js +11 -0
  132. package/dist/session-publisher-T7EI3CIP.js.map +1 -0
  133. package/dist/{state-manager-2EDVDBAR.js → state-manager-GQH32C44.js} +4 -2
  134. package/dist/state-manager-GQH32C44.js.map +1 -0
  135. package/dist/usage-V2CHE5PY.js +177 -0
  136. package/dist/usage-V2CHE5PY.js.map +1 -0
  137. package/dist/{web-EF5WIIGG.js → web-EA3KGNFN.js} +45 -30
  138. package/dist/web-EA3KGNFN.js.map +1 -0
  139. package/package.json +6 -2
  140. package/prompts/execute.md +7 -8
  141. package/prompts/plan.md +4 -5
  142. package/prompts/pr.md +2 -2
  143. package/web/AGENTS.md +152 -13
  144. package/web/public/app.css +380 -109
  145. package/web/public/app.js +525 -25
  146. package/web/public/index.html +68 -1
  147. package/dist/analyze-OEET7KGE.js.map +0 -1
  148. package/dist/chunk-3QHK4YQA.js.map +0 -1
  149. package/dist/chunk-42PJFMAR.js +0 -605
  150. package/dist/chunk-42PJFMAR.js.map +0 -1
  151. package/dist/chunk-4JSOYE4G.js +0 -368
  152. package/dist/chunk-4JSOYE4G.js.map +0 -1
  153. package/dist/chunk-56KS3TFQ.js.map +0 -1
  154. package/dist/chunk-73ATPIYX.js.map +0 -1
  155. package/dist/chunk-A4SLHOW7.js.map +0 -1
  156. package/dist/chunk-BAUPQXPE.js +0 -173
  157. package/dist/chunk-BAUPQXPE.js.map +0 -1
  158. package/dist/chunk-BYZDPR7N.js.map +0 -1
  159. package/dist/chunk-CD5ULRVC.js +0 -615
  160. package/dist/chunk-CD5ULRVC.js.map +0 -1
  161. package/dist/chunk-DIDUVL6O.js +0 -1365
  162. package/dist/chunk-DIDUVL6O.js.map +0 -1
  163. package/dist/chunk-EZATO3DW.js.map +0 -1
  164. package/dist/chunk-FADTCQGM.js.map +0 -1
  165. package/dist/chunk-FJP3UQGD.js.map +0 -1
  166. package/dist/chunk-LWRSMTTZ.js +0 -18
  167. package/dist/chunk-LWRSMTTZ.js.map +0 -1
  168. package/dist/chunk-M5UCXTIT.js.map +0 -1
  169. package/dist/chunk-M66SJHQQ.js +0 -206
  170. package/dist/chunk-M66SJHQQ.js.map +0 -1
  171. package/dist/chunk-MJULIKQU.js.map +0 -1
  172. package/dist/chunk-NS6R37II.js.map +0 -1
  173. package/dist/chunk-NTMMF5UD.js.map +0 -1
  174. package/dist/chunk-QCPGHBSZ.js.map +0 -1
  175. package/dist/chunk-XQUSIEKA.js.map +0 -1
  176. package/dist/chunk-Y5ZDJ4PJ.js.map +0 -1
  177. package/dist/execute-XBNVL753.js +0 -18
  178. package/dist/init-AJHCXJBP.js +0 -10
  179. package/dist/plan-QOZ3RIO6.js +0 -21
  180. package/dist/policy-6S4GFC76.js.map +0 -1
  181. package/dist/pr-EBBHD2ZX.js +0 -26
  182. package/dist/pr-review-VVMW5PO4.js +0 -20
  183. package/dist/prd-JQSZF7PR.js +0 -21
  184. package/dist/review-3F6MARWH.js +0 -19
  185. package/dist/run-RXE5GDQO.js +0 -36
  186. package/dist/web-EF5WIIGG.js.map +0 -1
  187. /package/dist/{config-PRJGWW7J.js.map → agent-OX3KPHE4.js.map} +0 -0
  188. /package/dist/{chunk-LAFNLLQP.js.map → chunk-KMRFRXIT.js.map} +0 -0
  189. /package/dist/{execute-XBNVL753.js.map → config-HMFMCY2M.js.map} +0 -0
  190. /package/dist/{init-AJHCXJBP.js.map → contract-JH2WBIO6.js.map} +0 -0
  191. /package/dist/{plan-QOZ3RIO6.js.map → diagnostics-THH42ZMP.js.map} +0 -0
  192. /package/dist/{pr-EBBHD2ZX.js.map → execute-KFNNZZHI.js.map} +0 -0
  193. /package/dist/{pr-review-VVMW5PO4.js.map → git-W72QQ6GT.js.map} +0 -0
  194. /package/dist/{prd-JQSZF7PR.js.map → init-HTN4V67Q.js.map} +0 -0
  195. /package/dist/{review-3F6MARWH.js.map → permissions-4AKNQZHK.js.map} +0 -0
  196. /package/dist/{run-RXE5GDQO.js.map → plan-SIZLGA4V.js.map} +0 -0
  197. /package/dist/{state-manager-2EDVDBAR.js.map → pr-OMWCGUOW.js.map} +0 -0
@@ -0,0 +1,2718 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveIssuePaths
4
+ } from "./chunk-QK7WUO7A.js";
5
+ import {
6
+ formatDuration,
7
+ printWarning
8
+ } from "./chunk-TYRNTSPJ.js";
9
+ import {
10
+ getGlobalRoot
11
+ } from "./chunk-HAKDLR6N.js";
12
+ import {
13
+ RETRY_CONFIG_KEYS,
14
+ getProjectRoot,
15
+ run
16
+ } from "./chunk-BEZ5BA5U.js";
17
+ import {
18
+ DEFAULT_TELEMETRY_CONFIG
19
+ } from "./chunk-67YIU2VB.js";
20
+ import {
21
+ parseCodexUsage,
22
+ parseUsage
23
+ } from "./chunk-J3SOTUVI.js";
24
+ import {
25
+ AGENT_PHASES,
26
+ ANTIGRAVITY_CAPABILITIES,
27
+ CLAUDE_CAPABILITIES,
28
+ CODEX_CAPABILITIES,
29
+ CURSOR_CAPABILITIES,
30
+ agentConfigInputSchema,
31
+ globalConfigSchema,
32
+ isAgentPhase,
33
+ isAgentProviderId,
34
+ issuesConfigSchema,
35
+ parsePhasesInput,
36
+ policyConfigInputSchema,
37
+ policyConfigSchema,
38
+ prReviewConfigSchema,
39
+ resilienceConfigSchema,
40
+ routingConfigSchema,
41
+ telemetryConfigInputSchema,
42
+ verifyConfigSchema,
43
+ webConfigSchema
44
+ } from "./chunk-LBGHI4S2.js";
45
+
46
+ // src/config.ts
47
+ import { existsSync } from "fs";
48
+ import { readFile as readFile2 } from "fs/promises";
49
+ import { platform } from "os";
50
+ import { dirname, join as join2 } from "path";
51
+
52
+ // src/agents/availability.ts
53
+ import { execa as execa6 } from "execa";
54
+
55
+ // src/agents/registry.ts
56
+ import { execa as execa5 } from "execa";
57
+
58
+ // src/agents/antigravity.ts
59
+ import { execa as execa2 } from "execa";
60
+
61
+ // src/core/shutdown.ts
62
+ var SHUTDOWN_GRACE_MS = 15e3;
63
+ var GRACE_POLL_MS = 100;
64
+ var EXIT_CODES = { SIGINT: 130, SIGTERM: 143 };
65
+ var controller = null;
66
+ var installed = false;
67
+ var shuttingDown = false;
68
+ var forced = false;
69
+ var hooks = /* @__PURE__ */ new Set();
70
+ var children = /* @__PURE__ */ new Set();
71
+ function getShutdownSignal() {
72
+ controller ??= new AbortController();
73
+ return controller.signal;
74
+ }
75
+ function onShutdown(hook) {
76
+ hooks.add(hook);
77
+ return () => {
78
+ hooks.delete(hook);
79
+ };
80
+ }
81
+ function registerChild(child) {
82
+ children.add(child);
83
+ return () => {
84
+ children.delete(child);
85
+ };
86
+ }
87
+ function installShutdownHandlers(options = {}) {
88
+ if (installed) return;
89
+ installed = true;
90
+ const listen = options.onSignal ?? ((signal, handler) => {
91
+ process.on(signal, handler);
92
+ });
93
+ for (const signal of ["SIGINT", "SIGTERM"]) {
94
+ listen(signal, () => {
95
+ void beginShutdown(signal, options);
96
+ });
97
+ }
98
+ }
99
+ async function beginShutdown(reason, options = {}) {
100
+ const exit = options.exit ?? ((code) => process.exit(code));
101
+ const notify = options.notify ?? ((message) => process.stderr.write(`${message}
102
+ `));
103
+ if (shuttingDown) {
104
+ forced = true;
105
+ killChildren("SIGKILL");
106
+ exit(EXIT_CODES[reason]);
107
+ return;
108
+ }
109
+ shuttingDown = true;
110
+ getShutdownSignal();
111
+ controller?.abort();
112
+ notify(
113
+ `
114
+ Interrupted. Saving a checkpoint and stopping the agent (press ${reason === "SIGINT" ? "Ctrl+C" : "the signal"} again to quit now)\u2026`
115
+ );
116
+ await runHooks("checkpoint", reason, notify);
117
+ await terminateChildren(options.graceMs ?? SHUTDOWN_GRACE_MS);
118
+ await runHooks("close", reason, notify);
119
+ exit(EXIT_CODES[reason]);
120
+ }
121
+ async function runHooks(phase, reason, notify) {
122
+ for (const hook of [...hooks]) {
123
+ if (hook.phase !== phase) continue;
124
+ try {
125
+ await hook.run(reason);
126
+ } catch (err) {
127
+ notify(
128
+ `issue-flow: a shutdown step failed: ${err instanceof Error ? err.message : String(err)}`
129
+ );
130
+ }
131
+ }
132
+ }
133
+ function killChildren(signal) {
134
+ for (const child of [...children]) {
135
+ try {
136
+ child.kill(signal);
137
+ } catch {
138
+ }
139
+ }
140
+ }
141
+ async function terminateChildren(graceMs) {
142
+ if (children.size === 0) return;
143
+ const pending = [...children];
144
+ let alive = pending.length;
145
+ for (const child of pending) {
146
+ void child.done.then(
147
+ () => {
148
+ alive--;
149
+ },
150
+ () => {
151
+ alive--;
152
+ }
153
+ );
154
+ }
155
+ killChildren("SIGTERM");
156
+ const deadline = Date.now() + graceMs;
157
+ while (alive > 0 && !forced && Date.now() < deadline) {
158
+ await sleep(GRACE_POLL_MS);
159
+ }
160
+ if (alive > 0) killChildren("SIGKILL");
161
+ }
162
+ function sleep(ms) {
163
+ return new Promise((resolve) => {
164
+ const timer = setTimeout(resolve, ms);
165
+ timer.unref?.();
166
+ });
167
+ }
168
+
169
+ // src/core/watchdog.ts
170
+ var DEFAULT_INACTIVITY_TIMEOUT_MS = 6e5;
171
+ var CHECK_DIVISOR = 10;
172
+ var MIN_CHECK_MS = 250;
173
+ var MAX_CHECK_MS = 5e3;
174
+ function checkIntervalFor(timeoutMs) {
175
+ return Math.min(MAX_CHECK_MS, Math.max(MIN_CHECK_MS, Math.floor(timeoutMs / CHECK_DIVISOR)));
176
+ }
177
+ function createWatchdog(options = {}) {
178
+ const timeoutMs = options.inactivityTimeoutMs ?? DEFAULT_INACTIVITY_TIMEOUT_MS;
179
+ const clock = options.clock ?? Date.now;
180
+ const start = options.setInterval ?? ((handler, ms) => setInterval(handler, ms));
181
+ const clear = options.clearInterval ?? ((timer2) => clearInterval(timer2));
182
+ const state = { stalled: false, silentMs: 0 };
183
+ if (timeoutMs <= 0) {
184
+ return {
185
+ beat: () => {
186
+ },
187
+ stop: () => {
188
+ },
189
+ get stalled() {
190
+ return state.stalled;
191
+ },
192
+ get silentMs() {
193
+ return state.silentMs;
194
+ }
195
+ };
196
+ }
197
+ let lastBeat = clock();
198
+ let timer = null;
199
+ let killTimer = null;
200
+ const stop = () => {
201
+ if (timer !== null) {
202
+ clear(timer);
203
+ timer = null;
204
+ }
205
+ if (killTimer !== null) {
206
+ clearTimeout(killTimer);
207
+ killTimer = null;
208
+ }
209
+ };
210
+ const declareStalled = () => {
211
+ state.stalled = true;
212
+ state.silentMs = clock() - lastBeat;
213
+ stop();
214
+ options.onStall?.(state.silentMs);
215
+ const child = options.child;
216
+ if (child === void 0) return;
217
+ child.kill("SIGTERM");
218
+ killTimer = setTimeout(() => {
219
+ child.kill("SIGKILL");
220
+ }, options.graceMs ?? SHUTDOWN_GRACE_MS);
221
+ killTimer.unref?.();
222
+ void child.done.then(
223
+ () => {
224
+ if (killTimer !== null) {
225
+ clearTimeout(killTimer);
226
+ killTimer = null;
227
+ }
228
+ },
229
+ () => {
230
+ }
231
+ );
232
+ };
233
+ timer = start(() => {
234
+ if (state.stalled) return;
235
+ if (clock() - lastBeat > timeoutMs) declareStalled();
236
+ }, checkIntervalFor(timeoutMs));
237
+ timer.unref?.();
238
+ return {
239
+ beat: () => {
240
+ lastBeat = clock();
241
+ },
242
+ stop,
243
+ get stalled() {
244
+ return state.stalled;
245
+ },
246
+ get silentMs() {
247
+ return state.silentMs;
248
+ }
249
+ };
250
+ }
251
+ function describeStall(silentMs, provider = "claude") {
252
+ return `${provider} produced no output for ${Math.round(silentMs / 1e3)}s and was stopped (stalled)`;
253
+ }
254
+
255
+ // src/agents/claude.ts
256
+ import { execa } from "execa";
257
+
258
+ // src/core/stream.ts
259
+ import { createInterface } from "readline";
260
+ async function readClaudeStream(stdout, options = {}) {
261
+ const outcome = { result: "", isError: false, usage: null, events: 0, raw: "" };
262
+ const collected = [];
263
+ const lines = createInterface({ input: stdout });
264
+ for await (const line of lines) {
265
+ options.onLine?.(line);
266
+ if (line.trim() === "") continue;
267
+ outcome.events++;
268
+ collected.push(line);
269
+ let event;
270
+ try {
271
+ event = JSON.parse(line);
272
+ } catch {
273
+ continue;
274
+ }
275
+ if (typeof event !== "object" || event === null) continue;
276
+ const record = event;
277
+ options.onEvent?.(record);
278
+ if (record.type === "result") {
279
+ outcome.result = typeof record.result === "string" ? record.result : "";
280
+ outcome.isError = record.is_error === true;
281
+ outcome.usage = parseUsage(record) ?? outcome.usage;
282
+ }
283
+ }
284
+ outcome.raw = collected.join("\n");
285
+ return outcome;
286
+ }
287
+
288
+ // src/agents/argv.ts
289
+ function pushRepeatedFlag(args, flag, values) {
290
+ if (!values || values.length === 0) return;
291
+ for (const value of values) {
292
+ args.push(flag, value);
293
+ }
294
+ }
295
+ function formatCodexConfigValue(value) {
296
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
297
+ if (/^[A-Za-z0-9_.-]+$/.test(value)) return value;
298
+ return JSON.stringify(value);
299
+ }
300
+
301
+ // src/agents/process.ts
302
+ var TIMEOUT_ATTRIBUTION_RATIO = 0.9;
303
+ function reachedTimeout(timeoutMs, elapsedMs) {
304
+ return timeoutMs > 0 && elapsedMs >= timeoutMs * TIMEOUT_ATTRIBUTION_RATIO;
305
+ }
306
+ function wasTimedOut(proc, timeoutMs, elapsedMs) {
307
+ if (proc.timedOut === true) return true;
308
+ if (!reachedTimeout(timeoutMs, elapsedMs)) return false;
309
+ return proc.signal === "SIGTERM" || proc.signal === "SIGKILL" || proc.exitCode === 143 || proc.exitCode === 137;
310
+ }
311
+ function describeAgentFailure(proc, diagnostics, timeoutMs, elapsedMs, command) {
312
+ if (wasTimedOut(proc, timeoutMs, elapsedMs)) {
313
+ return `Headless invocation timed out after ${formatDuration(Math.round(timeoutMs / 1e3))}. Raise the limit with --timeout <seconds> (0 = no limit).`;
314
+ }
315
+ return diagnostics.trim() || `${command} exited with code ${proc.exitCode ?? "unknown"}`;
316
+ }
317
+
318
+ // src/agents/claude.ts
319
+ var READ_ONLY_DENIED_TOOLS = [
320
+ "Agent",
321
+ "Task",
322
+ "Monitor",
323
+ "NotebookEdit",
324
+ "Edit",
325
+ "Write"
326
+ ];
327
+ function toolContext(name, input) {
328
+ switch (name) {
329
+ case "Read":
330
+ case "Write":
331
+ case "Edit":
332
+ return shortPath(typeof input.file_path === "string" ? input.file_path : void 0);
333
+ case "Glob":
334
+ case "Grep":
335
+ return typeof input.pattern === "string" ? input.pattern : "";
336
+ case "Bash": {
337
+ const cmd = typeof input.command === "string" ? input.command : "";
338
+ return cmd.length > 60 ? `${cmd.substring(0, 57)}...` : cmd;
339
+ }
340
+ default:
341
+ return "";
342
+ }
343
+ }
344
+ function shortPath(filePath) {
345
+ if (!filePath) return "";
346
+ const cwd = process.cwd();
347
+ if (filePath.startsWith(cwd)) return filePath.substring(cwd.length + 1);
348
+ const parts = filePath.split("/");
349
+ return parts.length > 2 ? `.../${parts.slice(-2).join("/")}` : filePath;
350
+ }
351
+ function emitClaudeEvent(event, onEvent) {
352
+ if (!onEvent) return;
353
+ if (event.type !== "assistant") return;
354
+ const message = event.message;
355
+ if (typeof message !== "object" || message === null) return;
356
+ const content = message.content;
357
+ if (!Array.isArray(content)) return;
358
+ for (const block of content) {
359
+ if (typeof block !== "object" || block === null) continue;
360
+ const item = block;
361
+ if (item.type === "text" && item.text) {
362
+ onEvent({ kind: "text", text: item.text });
363
+ }
364
+ if (item.type === "tool_use" && item.name) {
365
+ const detail = item.input ? toolContext(item.name, item.input) : "";
366
+ onEvent({ kind: "tool", name: item.name, ...detail ? { detail } : {} });
367
+ }
368
+ }
369
+ }
370
+ function buildClaudeArgv(invocation, settings) {
371
+ if (invocation.permission === "autonomous") {
372
+ const args2 = [
373
+ "--dangerously-skip-permissions",
374
+ "--print",
375
+ "--output-format",
376
+ "stream-json",
377
+ "--verbose"
378
+ ];
379
+ if (settings.model) args2.push("--model", settings.model);
380
+ if (settings.claude.ignoreUserConfig === true) {
381
+ args2.push("--setting-sources", "project");
382
+ if (settings.claude.strictMcpConfig !== false) {
383
+ args2.push("--strict-mcp-config");
384
+ }
385
+ }
386
+ pushRepeatedFlag(args2, "--add-dir", invocation.addDirs);
387
+ return { args: args2, stdinMode: "prompt" };
388
+ }
389
+ const maxTurns = invocation.maxTurns ?? 10;
390
+ const args = [
391
+ "-p",
392
+ invocation.prompt,
393
+ "--output-format",
394
+ "stream-json",
395
+ "--verbose",
396
+ "--max-turns",
397
+ String(maxTurns)
398
+ ];
399
+ pushRepeatedFlag(args, "--allowedTools", invocation.allowedTools);
400
+ pushRepeatedFlag(args, "--add-dir", invocation.addDirs);
401
+ if (invocation.permission === "read-only") {
402
+ args.push("--permission-mode", "plan");
403
+ const allowed = new Set(invocation.allowedTools ?? []);
404
+ const denied = READ_ONLY_DENIED_TOOLS.filter((tool) => !allowed.has(tool));
405
+ if (denied.length > 0) {
406
+ args.push("--disallowedTools", ...denied);
407
+ }
408
+ }
409
+ if (settings.model) args.push("--model", settings.model);
410
+ if (settings.claude.ignoreUserConfig === true) {
411
+ args.push("--setting-sources", "project");
412
+ if (settings.claude.strictMcpConfig !== false) {
413
+ args.push("--strict-mcp-config");
414
+ }
415
+ }
416
+ return { args, stdinMode: "ignore" };
417
+ }
418
+ var ClaudeCodeRunner = class {
419
+ id = "claude";
420
+ capabilities = CLAUDE_CAPABILITIES;
421
+ versionCommand() {
422
+ return { command: "claude", args: ["--version"] };
423
+ }
424
+ async run(invocation, settings) {
425
+ const { args, stdinMode } = buildClaudeArgv(invocation, settings);
426
+ const execaOptions = {
427
+ reject: false,
428
+ timeout: invocation.timeout,
429
+ stripFinalNewline: false,
430
+ ...stdinMode === "prompt" ? { input: invocation.prompt } : { stdin: "ignore" },
431
+ ...invocation.workingDirectory ? { cwd: invocation.workingDirectory } : {}
432
+ };
433
+ const startTime = Date.now();
434
+ const agent = { provider: this.id, model: settings.model };
435
+ const base = {
436
+ agent,
437
+ harnessVersion: peekHarnessVersion(this.id)
438
+ };
439
+ let cleanup = null;
440
+ try {
441
+ const subprocess = execa("claude", args, execaOptions);
442
+ const unregister = registerChild({
443
+ kill: (signal) => subprocess.kill(signal),
444
+ done: subprocess.then(
445
+ () => void 0,
446
+ () => void 0
447
+ )
448
+ });
449
+ const watchdog = createWatchdog({
450
+ ...invocation.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: invocation.inactivityTimeoutMs },
451
+ child: {
452
+ kill: (signal) => subprocess.kill(signal),
453
+ done: subprocess.then(
454
+ () => void 0,
455
+ () => void 0
456
+ )
457
+ }
458
+ });
459
+ cleanup = () => {
460
+ watchdog.stop();
461
+ unregister();
462
+ };
463
+ let streamed = {
464
+ result: "",
465
+ isError: false,
466
+ usage: null,
467
+ events: 0,
468
+ raw: ""
469
+ };
470
+ if (subprocess.stdout) {
471
+ streamed = await readClaudeStream(subprocess.stdout, {
472
+ onLine: (line) => {
473
+ watchdog.beat();
474
+ invocation.onLine?.(line);
475
+ },
476
+ onEvent: (event) => emitClaudeEvent(event, invocation.onEvent)
477
+ });
478
+ }
479
+ const proc = await subprocess;
480
+ watchdog.stop();
481
+ unregister();
482
+ const stdout = streamed.raw === "" ? proc.stdout?.toString() ?? "" : streamed.raw;
483
+ const stderr = proc.stderr?.toString() ?? "";
484
+ const rawOutput = stdout + (stderr ? `
485
+ ${stderr}` : "");
486
+ const exitCode = proc.exitCode ?? 1;
487
+ const elapsedMs = Date.now() - startTime;
488
+ if (watchdog.stalled) {
489
+ return {
490
+ success: false,
491
+ result: "",
492
+ rawOutput: describeStall(watchdog.silentMs),
493
+ exitCode: exitCode === 0 ? 1 : exitCode,
494
+ usage: null,
495
+ error: describeStall(watchdog.silentMs),
496
+ ...base
497
+ };
498
+ }
499
+ if (exitCode !== 0) {
500
+ return {
501
+ success: false,
502
+ result: "",
503
+ rawOutput,
504
+ exitCode,
505
+ usage: null,
506
+ error: describeAgentFailure(
507
+ proc,
508
+ stderr || stdout,
509
+ invocation.timeout,
510
+ elapsedMs,
511
+ "claude"
512
+ ),
513
+ ...base
514
+ };
515
+ }
516
+ if (streamed.result !== "") {
517
+ return {
518
+ success: !streamed.isError,
519
+ result: streamed.result,
520
+ rawOutput,
521
+ exitCode,
522
+ usage: streamed.usage,
523
+ error: streamed.isError ? streamed.result : null,
524
+ ...base
525
+ };
526
+ }
527
+ try {
528
+ const parsed = JSON.parse(stdout);
529
+ const resultText = typeof parsed.result === "string" ? parsed.result : stdout;
530
+ const isError = parsed.is_error === true;
531
+ return {
532
+ success: !isError,
533
+ result: resultText,
534
+ rawOutput,
535
+ exitCode,
536
+ usage: parseUsage(parsed),
537
+ error: isError ? resultText : null,
538
+ ...base
539
+ };
540
+ } catch {
541
+ return {
542
+ success: true,
543
+ result: rawOutput,
544
+ rawOutput,
545
+ exitCode,
546
+ usage: null,
547
+ error: null,
548
+ ...base
549
+ };
550
+ }
551
+ } catch (err) {
552
+ const message = err instanceof Error ? err.message : String(err);
553
+ const elapsedMs = Date.now() - startTime;
554
+ const timedOut = message.includes("timed out") || message.includes("ETIMEDOUT");
555
+ return {
556
+ success: false,
557
+ result: "",
558
+ rawOutput: message,
559
+ exitCode: 1,
560
+ usage: null,
561
+ error: timedOut ? describeAgentFailure(
562
+ { timedOut: reachedTimeout(invocation.timeout, elapsedMs) },
563
+ message,
564
+ invocation.timeout,
565
+ elapsedMs,
566
+ "claude"
567
+ ) : message,
568
+ ...base
569
+ };
570
+ } finally {
571
+ cleanup?.();
572
+ }
573
+ }
574
+ };
575
+ var harnessVersions = /* @__PURE__ */ new Map();
576
+ function peekHarnessVersion(id) {
577
+ return harnessVersions.has(id) ? harnessVersions.get(id) ?? null : void 0;
578
+ }
579
+ function cacheHarnessVersion(id, version) {
580
+ harnessVersions.set(id, version);
581
+ }
582
+
583
+ // src/agents/antigravity.ts
584
+ var ANTIGRAVITY_MIN_VERSION = "1.1.22";
585
+ var DEFAULT_EXECUTE_TIMEOUT_MS = 4 * 60 * 60 * 1e3;
586
+ var DEFAULT_MAX_PROMPT_BYTES = 1e5;
587
+ var TOOL_NAMES = {
588
+ run_command: "Bash",
589
+ command_status: "Bash",
590
+ view_file: "Read",
591
+ read_resource: "Read",
592
+ write_to_file: "Edit",
593
+ replace_file_content: "Edit",
594
+ multi_replace_file_content: "Edit",
595
+ notebook_edit: "Edit",
596
+ grep_search: "Grep",
597
+ find_by_name: "Glob",
598
+ list_dir: "Glob",
599
+ read_url_content: "WebFetch",
600
+ open_browser_url: "WebFetch"
601
+ };
602
+ function isRecord(value) {
603
+ return typeof value === "object" && value !== null;
604
+ }
605
+ function formatPrintTimeout(ms) {
606
+ const totalSeconds = Math.max(1, Math.round(ms / 1e3));
607
+ const hours = Math.floor(totalSeconds / 3600);
608
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
609
+ const seconds = totalSeconds % 60;
610
+ let out = "";
611
+ if (hours > 0) out += `${hours}h`;
612
+ if (minutes > 0 || hours > 0) out += `${minutes}m`;
613
+ out += `${seconds}s`;
614
+ return out;
615
+ }
616
+ function parseDurationMs(value) {
617
+ if (value === void 0) return DEFAULT_EXECUTE_TIMEOUT_MS;
618
+ if (value === null) return null;
619
+ if (typeof value === "number") return value > 0 ? value : null;
620
+ const trimmed = value.trim();
621
+ if (trimmed === "" || trimmed === "0") return null;
622
+ const match = trimmed.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?$/);
623
+ if (!match || match[0] === "") return null;
624
+ const hours = Number(match[1] ?? 0);
625
+ const minutes = Number(match[2] ?? 0);
626
+ const seconds = Number(match[3] ?? 0);
627
+ const ms = ((hours * 60 + minutes) * 60 + seconds) * 1e3;
628
+ return ms > 0 ? ms : null;
629
+ }
630
+ function resolveAntigravityTimeoutMs(invocation, settings) {
631
+ if (invocation.timeout > 0) return invocation.timeout;
632
+ return parseDurationMs(settings.antigravity.executeTimeout);
633
+ }
634
+ function compareVersions(actual, minimum) {
635
+ const left = actual.replace(/^v/i, "").split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);
636
+ const right = minimum.replace(/^v/i, "").split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);
637
+ const length = Math.max(left.length, right.length);
638
+ for (let i = 0; i < length; i++) {
639
+ const a = left[i] ?? 0;
640
+ const b = right[i] ?? 0;
641
+ if (a > b) return 1;
642
+ if (a < b) return -1;
643
+ }
644
+ return 0;
645
+ }
646
+ function normalizeAntigravityTool(name) {
647
+ if (name.startsWith("call_mcp_tool")) return name;
648
+ return TOOL_NAMES[name] ?? name;
649
+ }
650
+ function parseAntigravityUsage(usage, numTurns) {
651
+ if (!isRecord(usage)) return null;
652
+ if (numTurns === 0) return null;
653
+ const input = usage.input_tokens;
654
+ const output = usage.output_tokens;
655
+ const cacheRead = usage.cache_read_tokens;
656
+ const result = {};
657
+ if (typeof input === "number" && Number.isFinite(input)) result.inputTokens = input;
658
+ if (typeof output === "number" && Number.isFinite(output)) result.outputTokens = output;
659
+ if (typeof cacheRead === "number" && Number.isFinite(cacheRead)) {
660
+ result.cacheReadTokens = cacheRead;
661
+ }
662
+ if (typeof numTurns === "number" && Number.isFinite(numTurns)) result.numTurns = numTurns;
663
+ if (Object.keys(result).length === 0) return null;
664
+ return result;
665
+ }
666
+ function isPermissionDenial(message) {
667
+ return /permission check failed|user denied permission/i.test(message);
668
+ }
669
+ function mainParameter(parameters) {
670
+ for (const key of ["CommandLine", "TargetFile", "Path", "Query", "Url", "url"]) {
671
+ const value = parameters[key];
672
+ if (typeof value === "string" && value !== "") {
673
+ return value.length > 80 ? `${value.slice(0, 77)}...` : value;
674
+ }
675
+ }
676
+ return "";
677
+ }
678
+ function consumeAntigravityEvent(event, onEvent, acc) {
679
+ if (event.event === "init") {
680
+ if (typeof event.conversation_id === "string") acc.sessionId = event.conversation_id;
681
+ return;
682
+ }
683
+ if (event.event === "step_update") {
684
+ const step = isRecord(event.step_update) ? event.step_update : {};
685
+ if (typeof step.text_delta === "string" && step.text_delta !== "") {
686
+ onEvent?.({ kind: "text", text: step.text_delta });
687
+ }
688
+ if (step.step_type === "tool") {
689
+ const rawName = typeof step.tool_name === "string" ? step.tool_name : "tool";
690
+ const info = isRecord(step.tool_info) ? step.tool_info : {};
691
+ const parameters = isRecord(info.parameters) ? info.parameters : {};
692
+ const detail = mainParameter(parameters);
693
+ const name = rawName === "call_mcp_tool" ? mcpToolName(parameters) : normalizeAntigravityTool(rawName);
694
+ if (step.state === "ACTIVE") {
695
+ onEvent?.({ kind: "tool", name, ...detail === "" ? {} : { detail } });
696
+ }
697
+ if (step.state === "ERROR") {
698
+ const err = isRecord(info.error) ? info.error : {};
699
+ const message = typeof err.message === "string" ? err.message : "TOOL_ERROR";
700
+ if (isPermissionDenial(message)) {
701
+ acc.permissionDenied = { tool: rawName, message };
702
+ } else {
703
+ acc.warnings.push(`TOOL_ERROR on ${rawName}: ${message}`);
704
+ }
705
+ }
706
+ }
707
+ return;
708
+ }
709
+ if (event.event === "result") {
710
+ acc.seenResult = true;
711
+ const result = isRecord(event.result) ? event.result : event;
712
+ if (typeof result.conversation_id === "string") acc.sessionId = result.conversation_id;
713
+ if (typeof result.response === "string") acc.result = result.response;
714
+ if (typeof result.error === "string" && result.error !== "") acc.error = result.error;
715
+ if (typeof result.status === "string") {
716
+ acc.status = result.status;
717
+ }
718
+ const numTurns = typeof result.num_turns === "number" ? result.num_turns : void 0;
719
+ acc.usage = parseAntigravityUsage(result.usage, numTurns);
720
+ }
721
+ }
722
+ function mcpToolName(parameters) {
723
+ const server = typeof parameters.server === "string" ? parameters.server : "";
724
+ const tool = typeof parameters.tool === "string" ? parameters.tool : "";
725
+ if (server && tool) return `${server}/${tool}`;
726
+ if (tool) return tool;
727
+ if (server) return server;
728
+ return "call_mcp_tool";
729
+ }
730
+ function parseAntigravityStream(raw, onEvent) {
731
+ const acc = {
732
+ result: "",
733
+ status: null,
734
+ sessionId: null,
735
+ model: null,
736
+ usage: null,
737
+ seenResult: false,
738
+ permissionDenied: null,
739
+ warnings: [],
740
+ error: null
741
+ };
742
+ for (const line of raw.split("\n")) {
743
+ const trimmed = line.trim();
744
+ if (trimmed === "") continue;
745
+ try {
746
+ const event = JSON.parse(trimmed);
747
+ if (!isRecord(event)) continue;
748
+ consumeAntigravityEvent(event, onEvent, acc);
749
+ } catch {
750
+ }
751
+ }
752
+ return acc;
753
+ }
754
+ function maxPromptBytesOf(settings) {
755
+ return settings.maxPromptBytes ?? DEFAULT_MAX_PROMPT_BYTES;
756
+ }
757
+ function buildAntigravityArgv(invocation, settings) {
758
+ const timeoutMs = resolveAntigravityTimeoutMs(invocation, settings);
759
+ if (timeoutMs === null) {
760
+ return {
761
+ error: "configuration: Antigravity has nativeTimeout and received timeout: 0 without a ceiling. Set agent.antigravity.executeTimeout (default 4h)."
762
+ };
763
+ }
764
+ const promptBytes = Buffer.byteLength(invocation.prompt, "utf8");
765
+ const limit = maxPromptBytesOf(settings.antigravity);
766
+ if (promptBytes > limit) {
767
+ return {
768
+ error: `configuration: prompt exceeds Antigravity argv limit (${promptBytes} bytes > ${limit} maxPromptBytes). The promptChannel is argv; shorten the prompt or raise agent.antigravity.maxPromptBytes.`
769
+ };
770
+ }
771
+ const workspace = invocation.workingDirectory ?? process.cwd();
772
+ const args = [
773
+ "-p",
774
+ invocation.prompt,
775
+ "--output-format",
776
+ "stream-json",
777
+ "--print-timeout",
778
+ formatPrintTimeout(timeoutMs),
779
+ "--add-dir",
780
+ workspace,
781
+ "--dangerously-skip-permissions",
782
+ "--disable-slash-commands",
783
+ "--mode",
784
+ invocation.permission === "read-only" ? "plan" : "accept-edits"
785
+ ];
786
+ for (const dir of invocation.addDirs ?? []) {
787
+ args.push("--add-dir", dir);
788
+ }
789
+ if (settings.model) args.push("--model", settings.model);
790
+ if (settings.antigravity.effort) args.push("--effort", settings.antigravity.effort);
791
+ if (settings.antigravity.sandbox === true) args.push("--sandbox");
792
+ return { command: "agy", args };
793
+ }
794
+ function antigravityRunVerdict(input) {
795
+ if (input.parsed.permissionDenied) {
796
+ return {
797
+ success: false,
798
+ error: `configuration: permission check failed for ${input.parsed.permissionDenied.tool}. --dangerously-skip-permissions is required so Antigravity does not finish SUCCESS without writing. ${input.parsed.permissionDenied.message}`
799
+ };
800
+ }
801
+ if (input.parsed.status === "WAITING") {
802
+ return {
803
+ success: false,
804
+ error: "configuration: Antigravity ended waiting for human input (status: WAITING). Headless runs cannot continue from a prompt."
805
+ };
806
+ }
807
+ if (input.parsed.status === "CANCELED" || input.parsed.status === "INTERRUPTED") {
808
+ return { success: false, error: `Antigravity was ${input.parsed.status.toLowerCase()}.` };
809
+ }
810
+ if (!input.parsed.seenResult) {
811
+ return {
812
+ success: false,
813
+ error: "configuration: Antigravity finished without a result event in the stream."
814
+ };
815
+ }
816
+ if (input.parsed.status === "ERROR" || input.parsed.status !== "SUCCESS" || input.exitCode !== 0 || input.timedOut) {
817
+ return {
818
+ success: false,
819
+ error: input.parsed.error ?? `agy exited with code ${input.exitCode}`
820
+ };
821
+ }
822
+ return { success: true, error: null };
823
+ }
824
+ function configurationFailure(agent, message, rawOutput = message) {
825
+ return {
826
+ success: false,
827
+ result: "",
828
+ rawOutput,
829
+ exitCode: 1,
830
+ usage: null,
831
+ error: message,
832
+ agent,
833
+ harnessVersion: peekHarnessVersion("antigravity")
834
+ };
835
+ }
836
+ var AntigravityRunner = class {
837
+ id = "antigravity";
838
+ capabilities = ANTIGRAVITY_CAPABILITIES;
839
+ versionCommand() {
840
+ return { command: "agy", args: ["--version"] };
841
+ }
842
+ async run(invocation, settings) {
843
+ const agent = { provider: this.id, model: settings.model };
844
+ const built = buildAntigravityArgv(invocation, settings);
845
+ if ("error" in built) return configurationFailure(agent, built.error);
846
+ const minimum = settings.antigravity.minVersion ?? ANTIGRAVITY_MIN_VERSION;
847
+ const installed2 = peekHarnessVersion(this.id);
848
+ if (typeof installed2 === "string" && compareVersions(installed2, minimum) < 0) {
849
+ return configurationFailure(
850
+ agent,
851
+ `configuration: agy ${installed2} is below the minimum ${minimum}. Update Antigravity CLI.`
852
+ );
853
+ }
854
+ const { command, args } = built;
855
+ const startTime = Date.now();
856
+ const timeoutMs = resolveAntigravityTimeoutMs(invocation, settings) ?? invocation.timeout;
857
+ let cleanup = null;
858
+ try {
859
+ const subprocess = execa2(command, args, {
860
+ reject: false,
861
+ timeout: timeoutMs > 0 ? timeoutMs : void 0,
862
+ stripFinalNewline: false,
863
+ stdin: "ignore",
864
+ ...invocation.workingDirectory ? { cwd: invocation.workingDirectory } : {}
865
+ });
866
+ const unregister = registerChild({
867
+ kill: (signal) => subprocess.kill(signal),
868
+ done: subprocess.then(
869
+ () => void 0,
870
+ () => void 0
871
+ )
872
+ });
873
+ const watchdog = createWatchdog({
874
+ ...invocation.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: invocation.inactivityTimeoutMs },
875
+ child: {
876
+ kill: (signal) => subprocess.kill(signal),
877
+ done: subprocess.then(
878
+ () => void 0,
879
+ () => void 0
880
+ )
881
+ }
882
+ });
883
+ cleanup = () => {
884
+ watchdog.stop();
885
+ unregister();
886
+ };
887
+ const chunks = [];
888
+ if (subprocess.stdout) {
889
+ subprocess.stdout.on("data", (chunk) => {
890
+ watchdog.beat();
891
+ const text = chunk.toString();
892
+ chunks.push(text);
893
+ invocation.onLine?.(text);
894
+ });
895
+ }
896
+ if (subprocess.stderr) {
897
+ subprocess.stderr.on("data", () => {
898
+ watchdog.beat();
899
+ });
900
+ }
901
+ const proc = await subprocess;
902
+ watchdog.stop();
903
+ unregister();
904
+ const stdout = chunks.join("") || proc.stdout?.toString() || "";
905
+ const stderr = proc.stderr?.toString() ?? "";
906
+ const parsed = parseAntigravityStream(stdout, invocation.onEvent);
907
+ const warningBlock = parsed.warnings.length > 0 ? `
908
+ ${parsed.warnings.join("\n")}` : "";
909
+ const rawOutput = stdout + (stderr ? `
910
+ ${stderr}` : "") + warningBlock;
911
+ const exitCode = proc.exitCode ?? 1;
912
+ const elapsedMs = Date.now() - startTime;
913
+ const timedOut = wasTimedOut(proc, timeoutMs, elapsedMs);
914
+ const stalled = watchdog.stalled;
915
+ const authFailed = /not logged into antigravity|authentication required/i.test(
916
+ `${stderr}
917
+ ${stdout}`
918
+ );
919
+ if (stalled) {
920
+ return {
921
+ success: false,
922
+ result: "",
923
+ rawOutput: describeStall(watchdog.silentMs, "agy"),
924
+ exitCode: 1,
925
+ usage: parsed.usage,
926
+ error: describeStall(watchdog.silentMs, "agy"),
927
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
928
+ sessionId: parsed.sessionId ?? void 0,
929
+ harnessVersion: peekHarnessVersion(this.id)
930
+ };
931
+ }
932
+ if (authFailed) {
933
+ return {
934
+ success: false,
935
+ result: parsed.result,
936
+ rawOutput,
937
+ exitCode: timedOut ? 1 : exitCode,
938
+ usage: parsed.usage,
939
+ error: stderr.trim() || "You are not logged into Antigravity.",
940
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
941
+ sessionId: parsed.sessionId ?? void 0,
942
+ harnessVersion: peekHarnessVersion(this.id)
943
+ };
944
+ }
945
+ const verdict = antigravityRunVerdict({ exitCode, parsed, timedOut });
946
+ if (!verdict.success) {
947
+ return {
948
+ success: false,
949
+ result: parsed.result,
950
+ rawOutput,
951
+ exitCode: timedOut || exitCode === 0 && verdict.error?.startsWith("configuration:") === true ? 1 : exitCode,
952
+ usage: parsed.usage,
953
+ error: timedOut ? describeAgentFailure(proc, stderr || rawOutput, timeoutMs, elapsedMs, command) : verdict.error ?? parsed.error ?? (stderr.trim() || rawOutput),
954
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
955
+ sessionId: parsed.sessionId ?? void 0,
956
+ harnessVersion: peekHarnessVersion(this.id)
957
+ };
958
+ }
959
+ return {
960
+ success: true,
961
+ result: parsed.result,
962
+ rawOutput,
963
+ exitCode,
964
+ usage: parsed.usage,
965
+ error: null,
966
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
967
+ sessionId: parsed.sessionId ?? void 0,
968
+ harnessVersion: peekHarnessVersion(this.id)
969
+ };
970
+ } catch (err) {
971
+ const message = err instanceof Error ? err.message : String(err);
972
+ const missing = /ENOENT|not found|command not found/i.test(message);
973
+ return configurationFailure(
974
+ agent,
975
+ missing ? "configuration: agy is not installed. Install Antigravity CLI: https://antigravity.google/docs/cli/install/" : message
976
+ );
977
+ } finally {
978
+ cleanup?.();
979
+ }
980
+ }
981
+ };
982
+
983
+ // src/agents/codex.ts
984
+ import { mkdtemp, readFile, rm } from "fs/promises";
985
+ import { tmpdir } from "os";
986
+ import { join } from "path";
987
+ import { execa as execa3 } from "execa";
988
+ var BANNED_CODEX_FLAGS = [
989
+ "--dangerously-bypass-approvals-and-sandbox",
990
+ "--dangerously-bypass-hook-trust"
991
+ ];
992
+ function sandboxFor(permission, configured) {
993
+ if (configured === "danger-full-access") return "danger-full-access";
994
+ if (permission === "read-only") return "read-only";
995
+ return "workspace-write";
996
+ }
997
+ function shortPath2(filePath) {
998
+ if (!filePath) return "";
999
+ const cwd = process.cwd();
1000
+ if (filePath.startsWith(cwd)) return filePath.substring(cwd.length + 1);
1001
+ const parts = filePath.split("/");
1002
+ return parts.length > 2 ? `.../${parts.slice(-2).join("/")}` : filePath;
1003
+ }
1004
+ function truncateCommand(command) {
1005
+ return command.length > 60 ? `${command.substring(0, 57)}...` : command;
1006
+ }
1007
+ function buildCodexArgv(invocation, settings, outputFile) {
1008
+ const sandbox = sandboxFor(invocation.permission, settings.codex.sandbox);
1009
+ if (sandbox === "danger-full-access") {
1010
+ printWarning(
1011
+ 'agent.codex.sandbox is "danger-full-access": the Codex sandbox is off for this invocation.'
1012
+ );
1013
+ }
1014
+ const args = [
1015
+ "exec",
1016
+ "--json",
1017
+ "--output-last-message",
1018
+ outputFile,
1019
+ "--sandbox",
1020
+ sandbox,
1021
+ "--color",
1022
+ "never"
1023
+ ];
1024
+ if (invocation.workingDirectory) args.push("--cd", invocation.workingDirectory);
1025
+ pushRepeatedFlag(args, "--add-dir", invocation.addDirs);
1026
+ if (settings.model) args.push("--model", settings.model);
1027
+ if (settings.codex.reasoningEffort) {
1028
+ args.push("-c", `model_reasoning_effort=${settings.codex.reasoningEffort}`);
1029
+ }
1030
+ if (settings.codex.ignoreUserConfig === true) args.push("--ignore-user-config");
1031
+ if (settings.codex.skipGitRepoCheck === true) args.push("--skip-git-repo-check");
1032
+ for (const [key, value] of Object.entries(settings.codex.configOverrides ?? {})) {
1033
+ args.push("-c", `${key}=${formatCodexConfigValue(value)}`);
1034
+ }
1035
+ args.push("-");
1036
+ for (const banned of BANNED_CODEX_FLAGS) {
1037
+ if (args.includes(banned)) {
1038
+ throw new Error(`Internal error: banned Codex flag ${banned} reached argv.`);
1039
+ }
1040
+ }
1041
+ return args;
1042
+ }
1043
+ function emptyCodexState() {
1044
+ return {
1045
+ result: "",
1046
+ lastAgentMessage: "",
1047
+ usage: null,
1048
+ failed: false,
1049
+ error: null,
1050
+ completed: false
1051
+ };
1052
+ }
1053
+ function asRecord(value) {
1054
+ return typeof value === "object" && value !== null ? value : null;
1055
+ }
1056
+ function consumeCodexEvent(event, state, onEvent) {
1057
+ const type = event.type;
1058
+ if (type === "thread.started" && typeof event.thread_id === "string") {
1059
+ state.sessionId = event.thread_id;
1060
+ return;
1061
+ }
1062
+ if (type === "turn.completed") {
1063
+ state.completed = true;
1064
+ state.usage = parseCodexUsage(event.usage) ?? state.usage;
1065
+ return;
1066
+ }
1067
+ if (type === "turn.failed") {
1068
+ state.failed = true;
1069
+ const err = asRecord(event.error);
1070
+ state.error = typeof err?.message === "string" ? err.message : "turn.failed";
1071
+ return;
1072
+ }
1073
+ if (type === "error") {
1074
+ state.failed = true;
1075
+ state.error = typeof event.message === "string" ? event.message : "error";
1076
+ return;
1077
+ }
1078
+ const item = asRecord(event.item);
1079
+ if (!item) return;
1080
+ const itemType = item.type;
1081
+ if (type === "item.completed" && itemType === "agent_message" && typeof item.text === "string") {
1082
+ state.lastAgentMessage = item.text;
1083
+ onEvent?.({ kind: "text", text: item.text });
1084
+ return;
1085
+ }
1086
+ if (type === "item.completed" && itemType === "error" && typeof item.message === "string") {
1087
+ onEvent?.({ kind: "text", text: item.message });
1088
+ return;
1089
+ }
1090
+ if (type === "item.started" && itemType === "command_execution") {
1091
+ const command = typeof item.command === "string" ? item.command : "";
1092
+ onEvent?.({ kind: "tool", name: "Bash", detail: truncateCommand(command) });
1093
+ return;
1094
+ }
1095
+ if (type === "item.started" && itemType === "file_change") {
1096
+ const changes = Array.isArray(item.changes) ? item.changes : [];
1097
+ const first = asRecord(changes[0]);
1098
+ const path = typeof first?.path === "string" ? first.path : "";
1099
+ onEvent?.({ kind: "tool", name: "Edit", detail: shortPath2(path) });
1100
+ return;
1101
+ }
1102
+ if (type === "item.completed" && itemType === "web_search") {
1103
+ const query = typeof item.query === "string" ? item.query : "";
1104
+ onEvent?.({ kind: "tool", name: "WebSearch", ...query ? { detail: query } : {} });
1105
+ return;
1106
+ }
1107
+ if (type === "item.completed" && itemType === "mcp_tool_call") {
1108
+ const server = typeof item.server === "string" ? item.server : "";
1109
+ const tool = typeof item.tool === "string" ? item.tool : "";
1110
+ const name = [server, tool].filter(Boolean).join(".") || "mcp";
1111
+ onEvent?.({ kind: "tool", name });
1112
+ }
1113
+ }
1114
+ function parseCodexStream(lines, onEvent) {
1115
+ const state = emptyCodexState();
1116
+ for (const line of lines) {
1117
+ if (line.trim() === "") continue;
1118
+ let event;
1119
+ try {
1120
+ event = JSON.parse(line);
1121
+ } catch {
1122
+ continue;
1123
+ }
1124
+ const record = asRecord(event);
1125
+ if (!record) continue;
1126
+ consumeCodexEvent(record, state, onEvent);
1127
+ }
1128
+ return state;
1129
+ }
1130
+ var CodexRunner = class {
1131
+ id = "codex";
1132
+ capabilities = CODEX_CAPABILITIES;
1133
+ versionCommand() {
1134
+ return { command: "codex", args: ["--version"] };
1135
+ }
1136
+ authCommand() {
1137
+ return { command: "codex", args: ["login", "status"] };
1138
+ }
1139
+ async run(invocation, settings) {
1140
+ const tmp = await mkdtemp(join(tmpdir(), "issue-flow-codex-"));
1141
+ const outputFile = join(tmp, "last-message.txt");
1142
+ const args = buildCodexArgv(invocation, settings, outputFile);
1143
+ const agent = { provider: this.id, model: settings.model };
1144
+ const base = { agent, harnessVersion: peekHarnessVersion(this.id) };
1145
+ const startTime = Date.now();
1146
+ let cleanup = null;
1147
+ try {
1148
+ const subprocess = execa3("codex", args, {
1149
+ input: invocation.prompt,
1150
+ reject: false,
1151
+ timeout: invocation.timeout,
1152
+ stripFinalNewline: false,
1153
+ ...invocation.workingDirectory ? { cwd: invocation.workingDirectory } : {}
1154
+ });
1155
+ const unregister = registerChild({
1156
+ kill: (signal) => subprocess.kill(signal),
1157
+ done: subprocess.then(
1158
+ () => void 0,
1159
+ () => void 0
1160
+ )
1161
+ });
1162
+ const watchdog = createWatchdog({
1163
+ ...invocation.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: invocation.inactivityTimeoutMs },
1164
+ child: {
1165
+ kill: (signal) => subprocess.kill(signal),
1166
+ done: subprocess.then(
1167
+ () => void 0,
1168
+ () => void 0
1169
+ )
1170
+ }
1171
+ });
1172
+ cleanup = () => {
1173
+ watchdog.stop();
1174
+ unregister();
1175
+ };
1176
+ const collected = [];
1177
+ if (subprocess.stdout) {
1178
+ const { createInterface: createInterface2 } = await import("readline");
1179
+ const lines = createInterface2({ input: subprocess.stdout });
1180
+ for await (const line of lines) {
1181
+ watchdog.beat();
1182
+ invocation.onLine?.(line);
1183
+ if (line.trim() !== "") collected.push(line);
1184
+ }
1185
+ }
1186
+ const proc = await subprocess;
1187
+ watchdog.stop();
1188
+ unregister();
1189
+ const stdout = collected.join("\n");
1190
+ const stderr = proc.stderr?.toString() ?? "";
1191
+ const rawOutput = stdout + (stderr ? `
1192
+ ${stderr}` : "");
1193
+ const exitCode = proc.exitCode ?? 1;
1194
+ const elapsedMs = Date.now() - startTime;
1195
+ const parsed = parseCodexStream(collected, invocation.onEvent);
1196
+ let lastMessage = "";
1197
+ try {
1198
+ lastMessage = (await readFile(outputFile, "utf-8")).trimEnd();
1199
+ } catch {
1200
+ lastMessage = "";
1201
+ }
1202
+ const resultText = lastMessage || parsed.lastAgentMessage;
1203
+ if (watchdog.stalled) {
1204
+ return {
1205
+ success: false,
1206
+ result: "",
1207
+ rawOutput: describeStall(watchdog.silentMs, "codex"),
1208
+ exitCode: exitCode === 0 ? 1 : exitCode,
1209
+ usage: null,
1210
+ error: describeStall(watchdog.silentMs, "codex"),
1211
+ sessionId: parsed.sessionId,
1212
+ ...base
1213
+ };
1214
+ }
1215
+ const failureText = describeAgentFailure(
1216
+ proc,
1217
+ stderr || stdout,
1218
+ invocation.timeout,
1219
+ elapsedMs,
1220
+ "codex"
1221
+ );
1222
+ if (exitCode !== 0 || parsed.failed) {
1223
+ return {
1224
+ success: false,
1225
+ result: resultText,
1226
+ rawOutput,
1227
+ exitCode: exitCode === 0 ? 1 : exitCode,
1228
+ usage: parsed.usage,
1229
+ error: parsed.error ?? failureText,
1230
+ sessionId: parsed.sessionId,
1231
+ ...base
1232
+ };
1233
+ }
1234
+ return {
1235
+ success: parsed.completed && !parsed.failed,
1236
+ result: resultText,
1237
+ rawOutput,
1238
+ exitCode,
1239
+ usage: parsed.usage,
1240
+ error: parsed.failed ? parsed.error : null,
1241
+ sessionId: parsed.sessionId,
1242
+ ...base
1243
+ };
1244
+ } catch (err) {
1245
+ const message = err instanceof Error ? err.message : String(err);
1246
+ const elapsedMs = Date.now() - startTime;
1247
+ const timedOut = message.includes("timed out") || message.includes("ETIMEDOUT");
1248
+ return {
1249
+ success: false,
1250
+ result: "",
1251
+ rawOutput: message,
1252
+ exitCode: 1,
1253
+ usage: null,
1254
+ error: timedOut ? describeAgentFailure(
1255
+ { timedOut: reachedTimeout(invocation.timeout, elapsedMs) },
1256
+ message,
1257
+ invocation.timeout,
1258
+ elapsedMs,
1259
+ "codex"
1260
+ ) : message,
1261
+ ...base
1262
+ };
1263
+ } finally {
1264
+ cleanup?.();
1265
+ await rm(tmp, { recursive: true, force: true }).catch(() => void 0);
1266
+ }
1267
+ }
1268
+ };
1269
+
1270
+ // src/agents/cursor.ts
1271
+ import { execa as execa4 } from "execa";
1272
+ function isRecord2(value) {
1273
+ return typeof value === "object" && value !== null;
1274
+ }
1275
+ function toolName(call) {
1276
+ if (isRecord2(call.readToolCall)) {
1277
+ const args = isRecord2(call.readToolCall.args) ? call.readToolCall.args : {};
1278
+ return { name: "Read", detail: typeof args.path === "string" ? args.path : "" };
1279
+ }
1280
+ if (isRecord2(call.writeToolCall)) {
1281
+ const args = isRecord2(call.writeToolCall.args) ? call.writeToolCall.args : {};
1282
+ return { name: "Edit", detail: typeof args.path === "string" ? args.path : "" };
1283
+ }
1284
+ const key = Object.keys(call).find((name) => name.endsWith("ToolCall"));
1285
+ return { name: key?.replace(/ToolCall$/, "") ?? "tool", detail: "" };
1286
+ }
1287
+ function consumeCursorEvent(event, onEvent) {
1288
+ if (event.type === "system" && event.subtype === "init") {
1289
+ return {
1290
+ sessionId: typeof event.session_id === "string" ? event.session_id : void 0,
1291
+ model: typeof event.model === "string" ? event.model : void 0
1292
+ };
1293
+ }
1294
+ if (event.type === "assistant") {
1295
+ const message = isRecord2(event.message) ? event.message : {};
1296
+ const content = Array.isArray(message.content) ? message.content : [];
1297
+ const texts = [];
1298
+ for (const block of content) {
1299
+ if (isRecord2(block) && typeof block.text === "string") texts.push(block.text);
1300
+ }
1301
+ const text = texts.join("");
1302
+ if (text && onEvent) onEvent({ kind: "text", text });
1303
+ return { text };
1304
+ }
1305
+ if (event.type === "tool_call" && event.subtype === "started") {
1306
+ const call = isRecord2(event.tool_call) ? event.tool_call : {};
1307
+ const { name, detail } = toolName(call);
1308
+ onEvent?.({ kind: "tool", name, ...detail === "" ? {} : { detail } });
1309
+ return {};
1310
+ }
1311
+ if (event.type === "result") {
1312
+ return {
1313
+ result: typeof event.result === "string" ? event.result : "",
1314
+ sessionId: typeof event.session_id === "string" ? event.session_id : void 0,
1315
+ isError: event.is_error === true
1316
+ };
1317
+ }
1318
+ return {};
1319
+ }
1320
+ function parseCursorStream(raw, onEvent) {
1321
+ let result = "";
1322
+ let isError = false;
1323
+ let sessionId = null;
1324
+ let model = null;
1325
+ const texts = [];
1326
+ for (const line of raw.split("\n")) {
1327
+ const trimmed = line.trim();
1328
+ if (trimmed === "") continue;
1329
+ try {
1330
+ const event = JSON.parse(trimmed);
1331
+ if (!isRecord2(event)) continue;
1332
+ const seen = consumeCursorEvent(event, onEvent);
1333
+ if (seen.result !== void 0) result = seen.result;
1334
+ if (seen.isError === true) isError = true;
1335
+ if (seen.sessionId) sessionId = seen.sessionId;
1336
+ if (seen.model) model = seen.model;
1337
+ if (seen.text) texts.push(seen.text);
1338
+ } catch {
1339
+ }
1340
+ }
1341
+ return { result, isError, sessionId, model, text: texts.join("") };
1342
+ }
1343
+ function buildCursorArgv(invocation, settings) {
1344
+ const args = ["-p", "--output-format", "stream-json"];
1345
+ args.push("--workspace", invocation.workingDirectory ?? process.cwd());
1346
+ if (settings.model) args.push("--model", settings.model);
1347
+ if (invocation.permission === "read-only") {
1348
+ args.push("--mode", "plan");
1349
+ } else {
1350
+ args.push("--force");
1351
+ }
1352
+ if (settings.cursor.sandbox !== void 0) {
1353
+ args.push("--sandbox", settings.cursor.sandbox);
1354
+ }
1355
+ if (settings.cursor.approveMcps === true) {
1356
+ args.push("--approve-mcps");
1357
+ }
1358
+ args.push(invocation.prompt);
1359
+ return { command: "cursor-agent", args };
1360
+ }
1361
+ var CursorRunner = class {
1362
+ id = "cursor";
1363
+ capabilities = CURSOR_CAPABILITIES;
1364
+ versionCommand() {
1365
+ return { command: "cursor-agent", args: ["--version"] };
1366
+ }
1367
+ authCommand() {
1368
+ return { command: "cursor-agent", args: ["status"] };
1369
+ }
1370
+ async run(invocation, settings) {
1371
+ const { command, args } = buildCursorArgv(invocation, settings);
1372
+ const startTime = Date.now();
1373
+ const agent = { provider: this.id, model: settings.model };
1374
+ let cleanup = null;
1375
+ try {
1376
+ const subprocess = execa4(command, args, {
1377
+ reject: false,
1378
+ timeout: invocation.timeout,
1379
+ stripFinalNewline: false,
1380
+ stdin: "ignore",
1381
+ ...invocation.workingDirectory ? { cwd: invocation.workingDirectory } : {}
1382
+ });
1383
+ const unregister = registerChild({
1384
+ kill: (signal) => subprocess.kill(signal),
1385
+ done: subprocess.then(
1386
+ () => void 0,
1387
+ () => void 0
1388
+ )
1389
+ });
1390
+ const watchdog = createWatchdog({
1391
+ ...invocation.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: invocation.inactivityTimeoutMs },
1392
+ child: {
1393
+ kill: (signal) => subprocess.kill(signal),
1394
+ done: subprocess.then(
1395
+ () => void 0,
1396
+ () => void 0
1397
+ )
1398
+ }
1399
+ });
1400
+ cleanup = () => {
1401
+ watchdog.stop();
1402
+ unregister();
1403
+ };
1404
+ const chunks = [];
1405
+ if (subprocess.stdout) {
1406
+ subprocess.stdout.on("data", (chunk) => {
1407
+ watchdog.beat();
1408
+ const text = chunk.toString();
1409
+ chunks.push(text);
1410
+ invocation.onLine?.(text);
1411
+ });
1412
+ }
1413
+ if (subprocess.stderr) {
1414
+ subprocess.stderr.on("data", () => {
1415
+ watchdog.beat();
1416
+ });
1417
+ }
1418
+ const proc = await subprocess;
1419
+ watchdog.stop();
1420
+ unregister();
1421
+ const stdout = chunks.join("") || proc.stdout?.toString() || "";
1422
+ const stderr = proc.stderr?.toString() ?? "";
1423
+ const parsed = parseCursorStream(stdout, invocation.onEvent);
1424
+ const rawOutput = stdout + (stderr ? `
1425
+ ${stderr}` : "");
1426
+ const exitCode = proc.exitCode ?? 1;
1427
+ const elapsedMs = Date.now() - startTime;
1428
+ const timedOut = wasTimedOut(proc, invocation.timeout, elapsedMs);
1429
+ const authFailed = /authentication required/i.test(stderr) && stdout.trim() === "";
1430
+ const stalled = watchdog.stalled;
1431
+ const success = exitCode === 0 && parsed.result !== "" && !parsed.isError && !timedOut;
1432
+ if (stalled) {
1433
+ return {
1434
+ success: false,
1435
+ result: "",
1436
+ rawOutput: describeStall(watchdog.silentMs, "cursor-agent"),
1437
+ exitCode: exitCode === 0 ? 1 : exitCode,
1438
+ usage: null,
1439
+ error: describeStall(watchdog.silentMs, "cursor-agent"),
1440
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1441
+ sessionId: parsed.sessionId ?? void 0,
1442
+ harnessVersion: peekHarnessVersion(this.id)
1443
+ };
1444
+ }
1445
+ return {
1446
+ success,
1447
+ result: parsed.result || parsed.text,
1448
+ rawOutput,
1449
+ exitCode: timedOut ? 1 : exitCode,
1450
+ usage: null,
1451
+ error: success ? null : authFailed ? stderr.trim() : describeAgentFailure(
1452
+ proc,
1453
+ stderr || rawOutput,
1454
+ invocation.timeout,
1455
+ elapsedMs,
1456
+ command
1457
+ ),
1458
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1459
+ sessionId: parsed.sessionId ?? void 0,
1460
+ harnessVersion: peekHarnessVersion(this.id)
1461
+ };
1462
+ } catch (err) {
1463
+ const message = err instanceof Error ? err.message : String(err);
1464
+ return {
1465
+ success: false,
1466
+ result: "",
1467
+ rawOutput: message,
1468
+ exitCode: 1,
1469
+ usage: null,
1470
+ error: message,
1471
+ agent,
1472
+ harnessVersion: peekHarnessVersion(this.id)
1473
+ };
1474
+ } finally {
1475
+ cleanup?.();
1476
+ }
1477
+ }
1478
+ };
1479
+
1480
+ // src/agents/registry.ts
1481
+ var runners = /* @__PURE__ */ new Map();
1482
+ function registerRunner(runner) {
1483
+ runners.set(runner.id, runner);
1484
+ }
1485
+ function getRegisteredProviders() {
1486
+ return [...runners.keys()];
1487
+ }
1488
+ function ensureRunnersRegistered() {
1489
+ const registered = new Set(getRegisteredProviders());
1490
+ if (!registered.has("claude")) registerRunner(new ClaudeCodeRunner());
1491
+ if (!registered.has("codex")) registerRunner(new CodexRunner());
1492
+ if (!registered.has("cursor")) registerRunner(new CursorRunner());
1493
+ if (!registered.has("antigravity")) registerRunner(new AntigravityRunner());
1494
+ }
1495
+ function runnerFor(providerId) {
1496
+ ensureRunnersRegistered();
1497
+ const runner = runners.get(providerId);
1498
+ if (runner === void 0) {
1499
+ const available = getRegisteredProviders();
1500
+ const hint = available.length > 0 ? `Available providers: ${available.join(", ")}.` : "No agent runners are registered.";
1501
+ throw new Error(`Unknown agent provider: '${providerId}'. ${hint}`);
1502
+ }
1503
+ return runner;
1504
+ }
1505
+ async function ensureHarnessVersion(providerId) {
1506
+ const cached = peekHarnessVersion(providerId);
1507
+ if (cached !== void 0) return cached;
1508
+ const runner = runnerFor(providerId);
1509
+ const { command, args } = runner.versionCommand();
1510
+ try {
1511
+ const proc = await execa5(command, args, { reject: false, timeout: 1e4 });
1512
+ const version = proc.exitCode === 0 ? proc.stdout?.toString().trim() ?? null : null;
1513
+ cacheHarnessVersion(providerId, version);
1514
+ return version;
1515
+ } catch {
1516
+ cacheHarnessVersion(providerId, null);
1517
+ return null;
1518
+ }
1519
+ }
1520
+
1521
+ // src/agents/origins.ts
1522
+ var trackedOrigins = null;
1523
+ function setTrackedOrigins(origins) {
1524
+ trackedOrigins = origins;
1525
+ }
1526
+ function getTrackedOrigins() {
1527
+ return trackedOrigins;
1528
+ }
1529
+
1530
+ // src/agents/resolve.ts
1531
+ function mergeAgentBlocks(base, overlay) {
1532
+ if (overlay === void 0) return { ...base };
1533
+ return {
1534
+ ...base,
1535
+ ...dropUndefined(overlay),
1536
+ claude: { ...base.claude, ...dropUndefined(overlay.claude ?? {}) },
1537
+ codex: { ...base.codex, ...dropUndefined(overlay.codex ?? {}) },
1538
+ cursor: { ...base.cursor, ...dropUndefined(overlay.cursor ?? {}) },
1539
+ antigravity: { ...base.antigravity, ...dropUndefined(overlay.antigravity ?? {}) }
1540
+ };
1541
+ }
1542
+ function dropUndefined(value) {
1543
+ const result = {};
1544
+ for (const [key, item] of Object.entries(value)) {
1545
+ if (item !== void 0) result[key] = item;
1546
+ }
1547
+ return result;
1548
+ }
1549
+ async function resolveAgentFor(phase, options = {}) {
1550
+ const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-HMFMCY2M.js");
1551
+ const config = options.config ?? await loadAgentConfig2();
1552
+ const cli = options.cli ?? getAgentCliOverrides2();
1553
+ const defaultBlock = {
1554
+ provider: config.provider,
1555
+ model: config.model,
1556
+ claude: config.claude,
1557
+ codex: config.codex,
1558
+ cursor: config.cursor,
1559
+ antigravity: config.antigravity
1560
+ };
1561
+ const phaseBlock = mergeAgentBlocks(config.phases[phase] ?? {}, cli.phases?.[phase]);
1562
+ const merged = mergeAgentBlocks(defaultBlock, phaseBlock);
1563
+ const inspected = await inspectAgentResolution(phase, config, cli);
1564
+ let provider = merged.provider ?? "claude";
1565
+ let model = merged.model ?? null;
1566
+ let providerOrigin = inspected.providerOrigin;
1567
+ let modelOrigin = inspected.modelOrigin;
1568
+ if (cli?.forceProvider !== void 0) {
1569
+ provider = cli.forceProvider;
1570
+ providerOrigin = "cli";
1571
+ }
1572
+ if (cli?.forceModel !== void 0) {
1573
+ model = cli.forceModel;
1574
+ modelOrigin = "cli";
1575
+ }
1576
+ return {
1577
+ provider,
1578
+ model,
1579
+ claude: merged.claude ?? {},
1580
+ codex: merged.codex ?? {},
1581
+ cursor: merged.cursor ?? {},
1582
+ antigravity: merged.antigravity ?? {},
1583
+ origin: { provider: providerOrigin, model: modelOrigin }
1584
+ };
1585
+ }
1586
+ async function inspectAgentResolution(phase, config, cli) {
1587
+ const overlay = config.phases[phase];
1588
+ const provider = overlay?.provider ?? config.provider;
1589
+ const model = overlay?.model !== void 0 ? overlay.model : config.model;
1590
+ let providerOrigin = provider === "claude" && overlay?.provider === void 0 ? "default" : "project";
1591
+ let modelOrigin = model === null && overlay?.model === void 0 ? "default" : "project";
1592
+ const tracked = getTrackedOrigins();
1593
+ if (tracked) {
1594
+ providerOrigin = overlay?.provider !== void 0 ? tracked.phases[phase]?.provider ?? tracked.provider : tracked.provider;
1595
+ modelOrigin = overlay?.model !== void 0 ? tracked.phases[phase]?.model ?? tracked.model : tracked.model;
1596
+ }
1597
+ if (cli?.forceProvider !== void 0) providerOrigin = "cli";
1598
+ if (cli?.forceModel !== void 0) modelOrigin = "cli";
1599
+ return {
1600
+ provider,
1601
+ model,
1602
+ providerOrigin,
1603
+ modelOrigin,
1604
+ claude: { ...config.claude, ...overlay?.claude },
1605
+ codex: { ...config.codex, ...overlay?.codex }
1606
+ };
1607
+ }
1608
+ function parseAgentPhaseFlag(value) {
1609
+ const eq = value.indexOf("=");
1610
+ if (eq <= 0) {
1611
+ throw new Error(
1612
+ `Invalid --agent-phase value "${value}". Expected <phase>=<provider>[:<model>].`
1613
+ );
1614
+ }
1615
+ const phase = value.slice(0, eq);
1616
+ const rest = value.slice(eq + 1);
1617
+ if (!isAgentPhase(phase)) {
1618
+ throw new Error(
1619
+ `Unknown agent phase "${phase}". Valid phases: analyze, generate, prd, plan, execute, review, pr, pr-review.`
1620
+ );
1621
+ }
1622
+ const [providerRaw, ...modelParts] = rest.split(":");
1623
+ if (!providerRaw || !isAgentProviderId(providerRaw)) {
1624
+ throw new Error(
1625
+ `Unknown agent provider "${providerRaw ?? ""}". Valid providers: claude, codex, cursor, antigravity.`
1626
+ );
1627
+ }
1628
+ const model = modelParts.length > 0 ? modelParts.join(":") : void 0;
1629
+ return {
1630
+ phase,
1631
+ block: {
1632
+ provider: providerRaw,
1633
+ ...model ? { model } : {}
1634
+ }
1635
+ };
1636
+ }
1637
+ async function describeRunAgents(phases = AGENT_PHASES) {
1638
+ const target = phases.length > 0 ? phases : AGENT_PHASES;
1639
+ const byPhase = {};
1640
+ let defaultProvider = "claude";
1641
+ let defaultModel = null;
1642
+ const providers = /* @__PURE__ */ new Set();
1643
+ for (const phase of target) {
1644
+ const settings = await resolveAgentFor(phase);
1645
+ byPhase[phase] = {
1646
+ provider: settings.provider,
1647
+ model: settings.model,
1648
+ origin: settings.origin
1649
+ };
1650
+ providers.add(settings.provider);
1651
+ if (phase === target[0]) {
1652
+ defaultProvider = settings.provider;
1653
+ defaultModel = settings.model;
1654
+ }
1655
+ }
1656
+ const { loadAgentConfig: loadAgentConfig2 } = await import("./config-HMFMCY2M.js");
1657
+ const config = await loadAgentConfig2();
1658
+ defaultProvider = config.provider;
1659
+ defaultModel = config.model;
1660
+ const tracked = getTrackedOrigins();
1661
+ return {
1662
+ label: providers.size > 1 ? "misto" : providers.values().next().value ?? defaultProvider,
1663
+ defaultProvider,
1664
+ defaultModel,
1665
+ defaultOrigin: {
1666
+ provider: tracked?.provider ?? (defaultProvider === "claude" ? "default" : "project"),
1667
+ model: tracked?.model ?? (defaultModel === null ? "default" : "project")
1668
+ },
1669
+ byPhase
1670
+ };
1671
+ }
1672
+ function hasExplicitAgentSelection(config, cli) {
1673
+ if (cli?.forceProvider !== void 0 || cli?.forceModel !== void 0) return true;
1674
+ if (cli?.phases && Object.keys(cli.phases).length > 0) return true;
1675
+ if (config.provider !== "claude") return true;
1676
+ if (config.model !== null) return true;
1677
+ if (Object.keys(config.phases).length > 0) return true;
1678
+ if (config.claude.ignoreUserConfig !== void 0) return true;
1679
+ if (Object.keys(config.codex).length > 0) return true;
1680
+ return false;
1681
+ }
1682
+
1683
+ // src/agents/availability.ts
1684
+ var probeCache = /* @__PURE__ */ new Map();
1685
+ async function probeAgent(id) {
1686
+ const cached = probeCache.get(id);
1687
+ if (cached) return cached;
1688
+ const pending = probeAgentUncached(id);
1689
+ probeCache.set(id, pending);
1690
+ return pending;
1691
+ }
1692
+ async function probeAgentUncached(id) {
1693
+ ensureRunnersRegistered();
1694
+ const runner = runnerFor(id);
1695
+ let version = null;
1696
+ let installed2 = false;
1697
+ try {
1698
+ const { command, args } = runner.versionCommand();
1699
+ const proc = await execa6(command, args, { reject: false, timeout: 1e4 });
1700
+ installed2 = proc.exitCode === 0;
1701
+ version = installed2 ? proc.stdout?.toString().trim() || "unknown" : null;
1702
+ } catch {
1703
+ installed2 = false;
1704
+ }
1705
+ let authenticated = installed2;
1706
+ let detail = installed2 ? version ?? "installed" : "not found";
1707
+ if (installed2 && runner.authCommand && runner.capabilities.authProbe !== "none") {
1708
+ try {
1709
+ const { command, args } = runner.authCommand();
1710
+ const auth = await execa6(command, args, { reject: false, timeout: 1e4 });
1711
+ const text = `${auth.stdout?.toString() ?? ""}
1712
+ ${auth.stderr?.toString() ?? ""}`;
1713
+ authenticated = runner.capabilities.authProbe === "text" ? !/not logged in|not authenticated|no models available/i.test(text) : auth.exitCode === 0;
1714
+ detail = authenticated ? `${version} (authenticated)` : `${version} (not authenticated)`;
1715
+ } catch {
1716
+ authenticated = false;
1717
+ detail = `${version} (not authenticated)`;
1718
+ }
1719
+ }
1720
+ return { id, installed: installed2, version, authenticated, detail };
1721
+ }
1722
+ function installHint(id) {
1723
+ if (id === "codex") {
1724
+ return "Install Codex CLI: https://developers.openai.com/codex/noninteractive";
1725
+ }
1726
+ if (id === "cursor") {
1727
+ return "Install Cursor CLI: curl https://cursor.com/install -fsS | bash";
1728
+ }
1729
+ if (id === "antigravity") {
1730
+ return "Install Antigravity CLI: https://antigravity.google/docs/cli/install/";
1731
+ }
1732
+ return "Install Claude Code: https://docs.anthropic.com/en/docs/claude-code";
1733
+ }
1734
+
1735
+ // src/config.ts
1736
+ var DEFAULTS = {
1737
+ retryLimit: 10,
1738
+ retryForever: false,
1739
+ backoffBaseSeconds: 30,
1740
+ backoffMaxSeconds: 900
1741
+ };
1742
+ function createConfig(options) {
1743
+ return {
1744
+ issueNumber: options.issueNumber,
1745
+ maxIterations: options.maxIterations,
1746
+ retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,
1747
+ retryForever: options.retryForever ?? DEFAULTS.retryForever,
1748
+ backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,
1749
+ backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,
1750
+ // Left absent (rather than defaulted to an empty string) so the execute
1751
+ // prompt keeps its historical commit format unless a queue asks otherwise.
1752
+ ...options.commitScope === void 0 ? {} : { commitScope: options.commitScope },
1753
+ storiesPerIteration: options.storiesPerIteration ?? 1
1754
+ };
1755
+ }
1756
+ async function resolvePaths(config, scriptDir) {
1757
+ const projectRoot = await getProjectRoot();
1758
+ if (config.issueNumber) {
1759
+ const issuePaths = await resolveIssuePaths(config.issueNumber, { projectRoot });
1760
+ return {
1761
+ prdFile: issuePaths.tasksFile,
1762
+ progressFile: issuePaths.progressFile,
1763
+ archiveDir: issuePaths.archiveDir,
1764
+ lastBranchFile: issuePaths.lastBranchFile,
1765
+ projectRoot
1766
+ };
1767
+ }
1768
+ const base = scriptDir ?? projectRoot;
1769
+ const standalone = {
1770
+ prdFile: join2(base, "prd.json"),
1771
+ progressFile: join2(base, "progress.txt"),
1772
+ archiveDir: join2(base, "archive"),
1773
+ lastBranchFile: join2(base, ".last-branch"),
1774
+ projectRoot
1775
+ };
1776
+ const { bindTelemetry } = await import("./recorder-KCCPMKQG.js");
1777
+ bindTelemetry({ tasksPath: standalone.prdFile });
1778
+ return standalone;
1779
+ }
1780
+ function getInstallHint(pkg) {
1781
+ const os = platform();
1782
+ if (os === "darwin") {
1783
+ return `brew install ${pkg}`;
1784
+ }
1785
+ if (os === "linux") {
1786
+ return `apt install ${pkg} (or your distro's package manager)`;
1787
+ }
1788
+ if (os === "win32") {
1789
+ return `winget install ${pkg} (or choco install ${pkg})`;
1790
+ }
1791
+ return `install ${pkg} using your system package manager`;
1792
+ }
1793
+ async function validateDependencies() {
1794
+ const errors = [];
1795
+ const gitResult = await run("git", ["--version"]);
1796
+ if (gitResult.exitCode !== 0) {
1797
+ errors.push(` - git (install with: ${getInstallHint("git")})`);
1798
+ }
1799
+ const agent = await loadAgentConfig();
1800
+ const needed = /* @__PURE__ */ new Set([agent.provider]);
1801
+ for (const phase of AGENT_PHASES) {
1802
+ const provider = agent.phases[phase]?.provider;
1803
+ if (provider !== void 0) needed.add(provider);
1804
+ }
1805
+ for (const id of needed) {
1806
+ const { command, args } = runnerFor(id).versionCommand();
1807
+ const result = await run(command, args);
1808
+ if (result.exitCode !== 0) {
1809
+ errors.push(` - ${command} (${installHint(id)})`);
1810
+ }
1811
+ }
1812
+ return errors;
1813
+ }
1814
+ var PROJECT_CONFIG_FILENAME = ".issue-flow.json";
1815
+ var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
1816
+ function findProjectRootFromCwd(start = process.cwd()) {
1817
+ let dir = start;
1818
+ while (true) {
1819
+ if (existsSync(join2(dir, PROJECT_CONFIG_FILENAME)) || existsSync(join2(dir, ".git"))) {
1820
+ return dir;
1821
+ }
1822
+ const parent = dirname(dir);
1823
+ if (parent === dir) return void 0;
1824
+ dir = parent;
1825
+ }
1826
+ }
1827
+ async function readProjectConfigFile(projectRoot, warn) {
1828
+ const root = projectRoot ?? findProjectRootFromCwd();
1829
+ if (root === void 0) {
1830
+ return null;
1831
+ }
1832
+ const filePath = join2(root, PROJECT_CONFIG_FILENAME);
1833
+ let raw;
1834
+ try {
1835
+ raw = await readFile2(filePath, "utf-8");
1836
+ } catch {
1837
+ return null;
1838
+ }
1839
+ let parsed;
1840
+ try {
1841
+ parsed = JSON.parse(raw);
1842
+ } catch {
1843
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: invalid JSON.`);
1844
+ return null;
1845
+ }
1846
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1847
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: expected a JSON object.`);
1848
+ return null;
1849
+ }
1850
+ return parsed;
1851
+ }
1852
+ var GLOBAL_CONFIG_FILENAME = "config.json";
1853
+ async function loadGlobalConfig(options = {}) {
1854
+ const warn = options.warn ?? printWarning;
1855
+ let root;
1856
+ try {
1857
+ root = options.globalRoot ?? getGlobalRoot({ env: options.env ?? process.env });
1858
+ } catch (err) {
1859
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
1860
+ return {};
1861
+ }
1862
+ const filePath = join2(root, GLOBAL_CONFIG_FILENAME);
1863
+ let raw;
1864
+ try {
1865
+ raw = await readFile2(filePath, "utf-8");
1866
+ } catch (err) {
1867
+ if (err.code !== "ENOENT") {
1868
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
1869
+ }
1870
+ return {};
1871
+ }
1872
+ let parsed;
1873
+ try {
1874
+ parsed = JSON.parse(raw);
1875
+ } catch {
1876
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: invalid JSON.`);
1877
+ return {};
1878
+ }
1879
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1880
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: expected a JSON object.`);
1881
+ return {};
1882
+ }
1883
+ const config = {};
1884
+ for (const [key, value] of Object.entries(parsed)) {
1885
+ const result = globalConfigSchema.safeParse({ [key]: value });
1886
+ if (!result.success) {
1887
+ warn(
1888
+ `Ignoring "${key}" key of ${GLOBAL_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
1889
+ );
1890
+ continue;
1891
+ }
1892
+ Object.assign(config, result.data);
1893
+ }
1894
+ return config;
1895
+ }
1896
+ function mergeConfigLayers(layers) {
1897
+ const merged = {};
1898
+ for (const layer of [
1899
+ layers.defaults,
1900
+ layers.discovered,
1901
+ layers.global,
1902
+ layers.project,
1903
+ layers.env,
1904
+ layers.cli
1905
+ ]) {
1906
+ for (const [key, value] of Object.entries(layer ?? {})) {
1907
+ if (value !== void 0) {
1908
+ merged[key] = value;
1909
+ }
1910
+ }
1911
+ }
1912
+ return merged;
1913
+ }
1914
+ var webCliOverrides = {};
1915
+ function setWebCliOverrides(overrides) {
1916
+ webCliOverrides = overrides;
1917
+ }
1918
+ var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
1919
+ function parseBooleanEnv(value) {
1920
+ return !FALSY_ENV_VALUES.has(value.trim().toLowerCase());
1921
+ }
1922
+ function readNumberEnv(env, name, warn) {
1923
+ const raw = env[name];
1924
+ if (raw === void 0) {
1925
+ return void 0;
1926
+ }
1927
+ const parsed = Number(raw);
1928
+ if (!Number.isFinite(parsed)) {
1929
+ warn(`Ignoring ${name}="${raw}": not a number.`);
1930
+ return void 0;
1931
+ }
1932
+ return parsed;
1933
+ }
1934
+ function readWebConfigEnv(env, warn) {
1935
+ const layer = {};
1936
+ if (env.ISSUE_FLOW_WEB !== void 0) {
1937
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
1938
+ }
1939
+ const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
1940
+ if (port !== void 0) {
1941
+ layer.port = port;
1942
+ }
1943
+ if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
1944
+ layer.host = env.ISSUE_FLOW_WEB_HOST;
1945
+ }
1946
+ const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
1947
+ if (refresh !== void 0) {
1948
+ layer.refreshSeconds = refresh;
1949
+ }
1950
+ const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
1951
+ if (logLimit !== void 0) {
1952
+ layer.logLimit = logLimit;
1953
+ }
1954
+ return layer;
1955
+ }
1956
+ async function readWebConfigFile(projectRoot, warn) {
1957
+ const file = await readProjectConfigFile(projectRoot, warn);
1958
+ const web = file?.web;
1959
+ if (web === void 0) {
1960
+ return {};
1961
+ }
1962
+ const result = webConfigSchema.partial().safeParse(web);
1963
+ if (!result.success) {
1964
+ warn(
1965
+ `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
1966
+ );
1967
+ return {};
1968
+ }
1969
+ return result.data;
1970
+ }
1971
+ async function loadWebConfig(options = {}) {
1972
+ const warn = options.warn ?? printWarning;
1973
+ const cli = options.cli ?? webCliOverrides;
1974
+ const env = options.env ?? process.env;
1975
+ const fileLayer = await readWebConfigFile(options.projectRoot, warn);
1976
+ const envLayer = readWebConfigEnv(env, warn);
1977
+ const merged = { ...fileLayer, ...envLayer, ...cli };
1978
+ const result = webConfigSchema.safeParse(merged);
1979
+ if (result.success) {
1980
+ return result.data;
1981
+ }
1982
+ warn(
1983
+ `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
1984
+ );
1985
+ return webConfigSchema.parse({});
1986
+ }
1987
+ var issuesCliOverrides = {};
1988
+ function setIssuesCliOverrides(overrides) {
1989
+ issuesCliOverrides = overrides;
1990
+ }
1991
+ async function readIssuesConfigFile(projectRoot, warn) {
1992
+ const file = await readProjectConfigFile(projectRoot, warn);
1993
+ const issues = file?.issues;
1994
+ if (issues === void 0) {
1995
+ return {};
1996
+ }
1997
+ const result = issuesConfigSchema.partial().safeParse(issues);
1998
+ if (!result.success) {
1999
+ warn(
2000
+ `Ignoring "issues" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2001
+ );
2002
+ return {};
2003
+ }
2004
+ return result.data;
2005
+ }
2006
+ async function loadIssuesConfig(options = {}) {
2007
+ const warn = options.warn ?? printWarning;
2008
+ const cli = options.cli ?? issuesCliOverrides;
2009
+ const fileLayer = await readIssuesConfigFile(options.projectRoot, warn);
2010
+ const merged = { ...fileLayer, ...cli };
2011
+ const result = issuesConfigSchema.safeParse(merged);
2012
+ if (result.success) {
2013
+ return result.data;
2014
+ }
2015
+ warn(
2016
+ `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2017
+ );
2018
+ return issuesConfigSchema.parse({});
2019
+ }
2020
+ function readPrReviewConfigEnv(env) {
2021
+ const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
2022
+ return publisher === void 0 ? {} : { publisher };
2023
+ }
2024
+ async function readPrReviewConfigFile(projectRoot, warn) {
2025
+ const file = await readProjectConfigFile(projectRoot, warn);
2026
+ const prReview = file?.prReview;
2027
+ if (prReview === void 0) {
2028
+ return {};
2029
+ }
2030
+ const result = prReviewConfigSchema.partial().safeParse(prReview);
2031
+ if (!result.success) {
2032
+ warn(
2033
+ `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2034
+ );
2035
+ return {};
2036
+ }
2037
+ return result.data;
2038
+ }
2039
+ async function loadPrReviewConfig(options = {}) {
2040
+ const warn = options.warn ?? printWarning;
2041
+ const env = options.env ?? process.env;
2042
+ const fileLayer = await readPrReviewConfigFile(options.projectRoot, warn);
2043
+ const envLayer = readPrReviewConfigEnv(env);
2044
+ const merged = { ...fileLayer, ...envLayer, ...options.cli ?? {} };
2045
+ const result = prReviewConfigSchema.safeParse(merged);
2046
+ if (result.success) {
2047
+ return result.data;
2048
+ }
2049
+ warn(
2050
+ `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2051
+ );
2052
+ return prReviewConfigSchema.parse({});
2053
+ }
2054
+ var policyCliOverrides = {};
2055
+ function setPolicyCliOverrides(overrides) {
2056
+ policyCliOverrides = overrides;
2057
+ }
2058
+ function dropNullish(layer) {
2059
+ const result = {};
2060
+ for (const [key, value] of Object.entries(layer ?? {})) {
2061
+ if (value !== void 0 && value !== null) {
2062
+ result[key] = value;
2063
+ }
2064
+ }
2065
+ return result;
2066
+ }
2067
+ function readPolicyConfigEnv(env, warn) {
2068
+ const layer = {};
2069
+ if (env.ISSUE_FLOW_POLICY !== void 0) {
2070
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_POLICY);
2071
+ }
2072
+ const budget = readNumberEnv(env, "ISSUE_FLOW_POLICY_CONTEXT_BUDGET", warn);
2073
+ if (budget !== void 0) {
2074
+ layer.contextBudget = budget;
2075
+ }
2076
+ const issues = {};
2077
+ if (env.ISSUE_FLOW_POLICY_ISSUE_TITLE_CONVENTION !== void 0) {
2078
+ issues.titleConvention = env.ISSUE_FLOW_POLICY_ISSUE_TITLE_CONVENTION;
2079
+ }
2080
+ if (Object.keys(issues).length > 0) layer.issues = issues;
2081
+ const pullRequests = {};
2082
+ if (env.ISSUE_FLOW_POLICY_BASE_BRANCH !== void 0) {
2083
+ pullRequests.baseBranch = env.ISSUE_FLOW_POLICY_BASE_BRANCH;
2084
+ }
2085
+ if (env.ISSUE_FLOW_POLICY_PR_TITLE_CONVENTION !== void 0) {
2086
+ pullRequests.titleConvention = env.ISSUE_FLOW_POLICY_PR_TITLE_CONVENTION;
2087
+ }
2088
+ if (Object.keys(pullRequests).length > 0) layer.pullRequests = pullRequests;
2089
+ const git = {};
2090
+ if (env.ISSUE_FLOW_POLICY_BRANCH_CONVENTION !== void 0) {
2091
+ git.branchConvention = env.ISSUE_FLOW_POLICY_BRANCH_CONVENTION;
2092
+ }
2093
+ if (env.ISSUE_FLOW_POLICY_COMMIT_CONVENTION !== void 0) {
2094
+ git.commitConvention = env.ISSUE_FLOW_POLICY_COMMIT_CONVENTION;
2095
+ }
2096
+ if (Object.keys(git).length > 0) layer.git = git;
2097
+ const invalid = Object.entries(layer).find(
2098
+ ([, value]) => typeof value === "object" && value !== null && Object.values(value).includes("")
2099
+ );
2100
+ if (invalid !== void 0) {
2101
+ warn(`Ignoring empty ISSUE_FLOW_POLICY_* value in "${invalid[0]}".`);
2102
+ }
2103
+ return layer;
2104
+ }
2105
+ async function readPolicyConfigFile(projectRoot, warn) {
2106
+ const file = await readProjectConfigFile(projectRoot, warn);
2107
+ const policy = file?.policy;
2108
+ if (policy === void 0) {
2109
+ return {};
2110
+ }
2111
+ const result = policyConfigInputSchema.safeParse(policy);
2112
+ if (!result.success) {
2113
+ warn(
2114
+ `Ignoring "policy" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2115
+ );
2116
+ return {};
2117
+ }
2118
+ return result.data;
2119
+ }
2120
+ async function loadPolicyConfig(options = {}) {
2121
+ const warn = options.warn ?? printWarning;
2122
+ const cli = options.cli ?? policyCliOverrides;
2123
+ const env = options.env ?? process.env;
2124
+ const fileLayer = await readPolicyConfigFile(options.projectRoot, warn);
2125
+ const envLayer = readPolicyConfigEnv(env, warn);
2126
+ const merged = {
2127
+ ...mergeConfigLayers({
2128
+ project: dropNullish({ enabled: fileLayer.enabled, contextBudget: fileLayer.contextBudget }),
2129
+ env: dropNullish({ enabled: envLayer.enabled, contextBudget: envLayer.contextBudget }),
2130
+ cli: dropNullish({ enabled: cli.enabled, contextBudget: cli.contextBudget })
2131
+ }),
2132
+ discovery: mergeConfigLayers({
2133
+ project: dropNullish(fileLayer.discovery),
2134
+ env: dropNullish(envLayer.discovery),
2135
+ cli: dropNullish(cli.discovery)
2136
+ }),
2137
+ issues: mergeConfigLayers({
2138
+ project: dropNullish(fileLayer.issues),
2139
+ env: dropNullish(envLayer.issues),
2140
+ cli: dropNullish(cli.issues)
2141
+ }),
2142
+ pullRequests: mergeConfigLayers({
2143
+ project: dropNullish(fileLayer.pullRequests),
2144
+ env: dropNullish(envLayer.pullRequests),
2145
+ cli: dropNullish(cli.pullRequests)
2146
+ }),
2147
+ git: mergeConfigLayers({
2148
+ project: dropNullish(fileLayer.git),
2149
+ env: dropNullish(envLayer.git),
2150
+ cli: dropNullish(cli.git)
2151
+ })
2152
+ };
2153
+ const result = policyConfigSchema.safeParse(merged);
2154
+ if (result.success) {
2155
+ return result.data;
2156
+ }
2157
+ warn(
2158
+ `Invalid repository policy configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2159
+ );
2160
+ return policyConfigSchema.parse({});
2161
+ }
2162
+ function parseTelemetryLayer(value, source, warn) {
2163
+ if (value === void 0) return {};
2164
+ const result = telemetryConfigInputSchema.safeParse(value);
2165
+ if (result.success) return result.data;
2166
+ warn(
2167
+ `Ignoring "telemetry" key of ${source}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2168
+ );
2169
+ return {};
2170
+ }
2171
+ function readTelemetryEnv(env, warn) {
2172
+ const layer = {};
2173
+ if (env.ISSUE_FLOW_TELEMETRY !== void 0) {
2174
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY);
2175
+ }
2176
+ const max = readNumberEnv(env, "ISSUE_FLOW_TELEMETRY_MAX_EXECUTIONS", warn);
2177
+ if (max !== void 0) layer.maxExecutions = max;
2178
+ if (env.ISSUE_FLOW_TELEMETRY_ESTIMATE !== void 0) {
2179
+ layer.pricing = { estimate: parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY_ESTIMATE) };
2180
+ }
2181
+ return layer;
2182
+ }
2183
+ async function loadTelemetryConfig(options = {}) {
2184
+ const warn = options.warn ?? printWarning;
2185
+ const env = options.env ?? process.env;
2186
+ const globalFile = options.global ?? (await loadGlobalConfig({
2187
+ env,
2188
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2189
+ warn
2190
+ })).telemetry;
2191
+ const projectFile = await readProjectConfigFile(options.projectRoot, warn);
2192
+ const project = parseTelemetryLayer(projectFile?.telemetry, PROJECT_CONFIG_FILENAME, warn);
2193
+ const envLayer = readTelemetryEnv(env, warn);
2194
+ const pricing = mergeConfigLayers({
2195
+ defaults: DEFAULT_TELEMETRY_CONFIG.pricing,
2196
+ global: globalFile?.pricing,
2197
+ project: project.pricing,
2198
+ env: envLayer.pricing
2199
+ });
2200
+ const overrides = {
2201
+ ...DEFAULT_TELEMETRY_CONFIG.pricing.overrides,
2202
+ ...globalFile?.pricing?.overrides,
2203
+ ...project.pricing?.overrides,
2204
+ ...envLayer.pricing?.overrides
2205
+ };
2206
+ const scalars = mergeConfigLayers({
2207
+ defaults: {
2208
+ enabled: DEFAULT_TELEMETRY_CONFIG.enabled,
2209
+ maxExecutions: DEFAULT_TELEMETRY_CONFIG.maxExecutions
2210
+ },
2211
+ global: {
2212
+ ...globalFile?.enabled === void 0 ? {} : { enabled: globalFile.enabled },
2213
+ ...globalFile?.maxExecutions === void 0 ? {} : { maxExecutions: globalFile.maxExecutions }
2214
+ },
2215
+ project: {
2216
+ ...project.enabled === void 0 ? {} : { enabled: project.enabled },
2217
+ ...project.maxExecutions === void 0 ? {} : { maxExecutions: project.maxExecutions }
2218
+ },
2219
+ env: {
2220
+ ...envLayer.enabled === void 0 ? {} : { enabled: envLayer.enabled },
2221
+ ...envLayer.maxExecutions === void 0 ? {} : { maxExecutions: envLayer.maxExecutions }
2222
+ }
2223
+ });
2224
+ return {
2225
+ enabled: scalars.enabled ?? DEFAULT_TELEMETRY_CONFIG.enabled,
2226
+ maxExecutions: scalars.maxExecutions ?? DEFAULT_TELEMETRY_CONFIG.maxExecutions,
2227
+ pricing: {
2228
+ estimate: pricing.estimate ?? DEFAULT_TELEMETRY_CONFIG.pricing.estimate,
2229
+ overrides
2230
+ }
2231
+ };
2232
+ }
2233
+ var resilienceCliOverrides = {};
2234
+ function setResilienceCliOverrides(overrides) {
2235
+ resilienceCliOverrides = overrides;
2236
+ }
2237
+ function mergeResilienceSection(layers) {
2238
+ const merged = mergeConfigLayers({
2239
+ global: layers[0],
2240
+ project: layers[1],
2241
+ env: layers[2],
2242
+ cli: layers[3]
2243
+ });
2244
+ return Object.keys(merged).length > 0 ? merged : void 0;
2245
+ }
2246
+ function mergeResilienceRetry(layers) {
2247
+ const merged = {};
2248
+ for (const key of RETRY_CONFIG_KEYS) {
2249
+ const entry = mergeResilienceSection(layers.map((layer) => layer?.[key]));
2250
+ if (entry !== void 0) {
2251
+ merged[key] = entry;
2252
+ }
2253
+ }
2254
+ return Object.keys(merged).length > 0 ? merged : void 0;
2255
+ }
2256
+ function parseResilienceLayer(value, origin, warn) {
2257
+ const result = resilienceConfigSchema.safeParse(value);
2258
+ if (!result.success) {
2259
+ warn(
2260
+ `Ignoring "resilience" key of ${origin}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2261
+ );
2262
+ return {};
2263
+ }
2264
+ return result.data;
2265
+ }
2266
+ async function readResilienceConfigFile(projectRoot, warn) {
2267
+ const file = await readProjectConfigFile(projectRoot, warn);
2268
+ const resilience = file?.resilience;
2269
+ if (resilience === void 0) {
2270
+ return {};
2271
+ }
2272
+ return parseResilienceLayer(resilience, PROJECT_CONFIG_FILENAME, warn);
2273
+ }
2274
+ function readResilienceConfigEnv(env, warn) {
2275
+ const layer = {};
2276
+ if (env.ISSUE_FLOW_RESILIENCE_PROFILE !== void 0) {
2277
+ layer.profile = env.ISSUE_FLOW_RESILIENCE_PROFILE;
2278
+ }
2279
+ if (env.ISSUE_FLOW_RESILIENCE_FAILOVER_ON_AUTH !== void 0) {
2280
+ layer.failoverOnAuth = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_FAILOVER_ON_AUTH);
2281
+ }
2282
+ const retry = env.ISSUE_FLOW_RESILIENCE_RETRY;
2283
+ if (retry !== void 0) {
2284
+ try {
2285
+ layer.retry = JSON.parse(retry);
2286
+ } catch {
2287
+ warn("Ignoring ISSUE_FLOW_RESILIENCE_RETRY: invalid JSON.");
2288
+ }
2289
+ }
2290
+ const providers = {};
2291
+ if (env.ISSUE_FLOW_RESILIENCE_FAILOVER !== void 0) {
2292
+ providers.failover = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_FAILOVER);
2293
+ }
2294
+ if (env.ISSUE_FLOW_RESILIENCE_PROVIDER_CHAIN !== void 0) {
2295
+ providers.chain = env.ISSUE_FLOW_RESILIENCE_PROVIDER_CHAIN.split(",").map((name) => name.trim()).filter((name) => name !== "");
2296
+ }
2297
+ const cooldown = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_PROVIDER_COOLDOWN_MS", warn);
2298
+ if (cooldown !== void 0) {
2299
+ providers.cooldownMs = cooldown;
2300
+ }
2301
+ const maxCooldown = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_PROVIDER_MAX_COOLDOWN_MS", warn);
2302
+ if (maxCooldown !== void 0) {
2303
+ providers.maxCooldownMs = maxCooldown;
2304
+ }
2305
+ const failureWindow = readNumberEnv(
2306
+ env,
2307
+ "ISSUE_FLOW_RESILIENCE_PROVIDER_FAILURE_WINDOW_MS",
2308
+ warn
2309
+ );
2310
+ if (failureWindow !== void 0) {
2311
+ providers.failureWindowMs = failureWindow;
2312
+ }
2313
+ const failuresToTrip = readNumberEnv(
2314
+ env,
2315
+ "ISSUE_FLOW_RESILIENCE_PROVIDER_FAILURES_TO_TRIP",
2316
+ warn
2317
+ );
2318
+ if (failuresToTrip !== void 0) {
2319
+ providers.failuresToTrip = failuresToTrip;
2320
+ }
2321
+ if (Object.keys(providers).length > 0) layer.providers = providers;
2322
+ const queue = {};
2323
+ if (env.ISSUE_FLOW_RESILIENCE_ON_ISSUE_FAILURE !== void 0) {
2324
+ queue.onIssueFailure = env.ISSUE_FLOW_RESILIENCE_ON_ISSUE_FAILURE;
2325
+ }
2326
+ const maxIssueAttempts = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_MAX_ISSUE_ATTEMPTS", warn);
2327
+ if (maxIssueAttempts !== void 0) {
2328
+ queue.maxIssueAttempts = maxIssueAttempts;
2329
+ }
2330
+ if (Object.keys(queue).length > 0) layer.queue = queue;
2331
+ const inactivity = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_INACTIVITY_TIMEOUT_MS", warn);
2332
+ if (inactivity !== void 0) {
2333
+ layer.watchdog = { inactivityTimeoutMs: inactivity };
2334
+ }
2335
+ const journal = {};
2336
+ if (env.ISSUE_FLOW_RESILIENCE_JOURNAL !== void 0) {
2337
+ journal.enabled = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_JOURNAL);
2338
+ }
2339
+ const journalBytes = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_JOURNAL_MAX_BYTES", warn);
2340
+ if (journalBytes !== void 0) {
2341
+ journal.maxFileBytes = journalBytes;
2342
+ }
2343
+ if (Object.keys(journal).length > 0) layer.journal = journal;
2344
+ if (env.ISSUE_FLOW_RESILIENCE_AUTO_DECOMPOSE !== void 0) {
2345
+ layer.decompose = { auto: parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_AUTO_DECOMPOSE) };
2346
+ }
2347
+ if (Object.keys(layer).length === 0) {
2348
+ return {};
2349
+ }
2350
+ return parseResilienceLayer(layer, "the ISSUE_FLOW_RESILIENCE_* environment", warn);
2351
+ }
2352
+ async function loadResilienceConfig(options = {}) {
2353
+ const warn = options.warn ?? printWarning;
2354
+ const env = options.env ?? process.env;
2355
+ const cli = options.cli ?? resilienceCliOverrides;
2356
+ const globalLayer = options.global ?? (await loadGlobalConfig({
2357
+ env,
2358
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2359
+ warn
2360
+ })).resilience ?? {};
2361
+ const projectLayer = await readResilienceConfigFile(options.projectRoot, warn);
2362
+ const envLayer = readResilienceConfigEnv(env, warn);
2363
+ const layers = [globalLayer, projectLayer, envLayer, cli];
2364
+ const scalars = mergeConfigLayers({
2365
+ global: { profile: globalLayer.profile, failoverOnAuth: globalLayer.failoverOnAuth },
2366
+ project: { profile: projectLayer.profile, failoverOnAuth: projectLayer.failoverOnAuth },
2367
+ env: { profile: envLayer.profile, failoverOnAuth: envLayer.failoverOnAuth },
2368
+ cli: { profile: cli.profile, failoverOnAuth: cli.failoverOnAuth }
2369
+ });
2370
+ const retry = mergeResilienceRetry(layers.map((layer) => layer.retry));
2371
+ const providers = mergeResilienceSection(layers.map((layer) => layer.providers));
2372
+ const queue = mergeResilienceSection(layers.map((layer) => layer.queue));
2373
+ const watchdog = mergeResilienceSection(layers.map((layer) => layer.watchdog));
2374
+ const journal = mergeResilienceSection(layers.map((layer) => layer.journal));
2375
+ const decompose = mergeResilienceSection(layers.map((layer) => layer.decompose));
2376
+ return {
2377
+ ...scalars,
2378
+ ...retry === void 0 ? {} : { retry },
2379
+ ...providers === void 0 ? {} : { providers },
2380
+ ...queue === void 0 ? {} : { queue },
2381
+ ...watchdog === void 0 ? {} : { watchdog },
2382
+ ...journal === void 0 ? {} : { journal },
2383
+ ...decompose === void 0 ? {} : { decompose }
2384
+ };
2385
+ }
2386
+ var activeResilienceConfig = {};
2387
+ function getActiveResilienceConfig() {
2388
+ return activeResilienceConfig;
2389
+ }
2390
+ function setActiveResilienceConfig(config) {
2391
+ activeResilienceConfig = config;
2392
+ }
2393
+ async function initResilienceConfig(options = {}) {
2394
+ try {
2395
+ activeResilienceConfig = await loadResilienceConfig(options);
2396
+ } catch {
2397
+ activeResilienceConfig = {};
2398
+ }
2399
+ return activeResilienceConfig;
2400
+ }
2401
+ var agentCliOverrides = {};
2402
+ var cachedAgentConfig;
2403
+ function setAgentCliOverrides(overrides) {
2404
+ agentCliOverrides = overrides;
2405
+ cachedAgentConfig = void 0;
2406
+ }
2407
+ function getAgentCliOverrides() {
2408
+ return agentCliOverrides;
2409
+ }
2410
+ function readAgentEnv(env, warn) {
2411
+ const layer = {};
2412
+ if (env.ISSUE_FLOW_AGENT !== void 0) {
2413
+ if (isAgentProviderId(env.ISSUE_FLOW_AGENT)) {
2414
+ layer.provider = env.ISSUE_FLOW_AGENT;
2415
+ } else {
2416
+ warn(
2417
+ `Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor or antigravity.`
2418
+ );
2419
+ }
2420
+ }
2421
+ if (env.ISSUE_FLOW_AGENT_MODEL !== void 0 && env.ISSUE_FLOW_AGENT_MODEL !== "") {
2422
+ layer.model = env.ISSUE_FLOW_AGENT_MODEL;
2423
+ }
2424
+ const codex = {};
2425
+ if (env.ISSUE_FLOW_CODEX_SANDBOX !== void 0) {
2426
+ if (env.ISSUE_FLOW_CODEX_SANDBOX === "read-only" || env.ISSUE_FLOW_CODEX_SANDBOX === "workspace-write" || env.ISSUE_FLOW_CODEX_SANDBOX === "danger-full-access") {
2427
+ codex.sandbox = env.ISSUE_FLOW_CODEX_SANDBOX;
2428
+ } else {
2429
+ warn(`Ignoring ISSUE_FLOW_CODEX_SANDBOX="${env.ISSUE_FLOW_CODEX_SANDBOX}".`);
2430
+ }
2431
+ }
2432
+ if (env.ISSUE_FLOW_CODEX_REASONING_EFFORT !== void 0) {
2433
+ const effort = env.ISSUE_FLOW_CODEX_REASONING_EFFORT;
2434
+ if (effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh") {
2435
+ codex.reasoningEffort = effort;
2436
+ } else {
2437
+ warn(`Ignoring ISSUE_FLOW_CODEX_REASONING_EFFORT="${effort}".`);
2438
+ }
2439
+ }
2440
+ if (env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG !== void 0) {
2441
+ codex.ignoreUserConfig = parseBooleanEnv(env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG);
2442
+ }
2443
+ if (Object.keys(codex).length > 0) layer.codex = codex;
2444
+ const cursor = {};
2445
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX !== void 0) {
2446
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX === "enabled" || env.ISSUE_FLOW_CURSOR_SANDBOX === "disabled") {
2447
+ cursor.sandbox = env.ISSUE_FLOW_CURSOR_SANDBOX;
2448
+ } else {
2449
+ warn(`Ignoring ISSUE_FLOW_CURSOR_SANDBOX="${env.ISSUE_FLOW_CURSOR_SANDBOX}".`);
2450
+ }
2451
+ }
2452
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE !== void 0) {
2453
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "global" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "project" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "none") {
2454
+ cursor.permissionsFile = env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE;
2455
+ } else {
2456
+ warn(
2457
+ `Ignoring ISSUE_FLOW_CURSOR_PERMISSIONS_FILE="${env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE}".`
2458
+ );
2459
+ }
2460
+ }
2461
+ if (Object.keys(cursor).length > 0) layer.cursor = cursor;
2462
+ const antigravity = {};
2463
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EFFORT !== void 0) {
2464
+ const effort = env.ISSUE_FLOW_ANTIGRAVITY_EFFORT;
2465
+ if (effort === "low" || effort === "medium" || effort === "high") {
2466
+ antigravity.effort = effort;
2467
+ } else {
2468
+ warn(`Ignoring ISSUE_FLOW_ANTIGRAVITY_EFFORT="${effort}".`);
2469
+ }
2470
+ }
2471
+ if (env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX !== void 0) {
2472
+ antigravity.sandbox = parseBooleanEnv(env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX);
2473
+ }
2474
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT !== void 0) {
2475
+ antigravity.executeTimeout = env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT;
2476
+ }
2477
+ if (Object.keys(antigravity).length > 0) layer.antigravity = antigravity;
2478
+ return layer;
2479
+ }
2480
+ function readAgentKey(raw, label, warn) {
2481
+ if (raw === void 0) return {};
2482
+ const parsed = agentConfigInputSchema.safeParse(raw);
2483
+ if (!parsed.success) {
2484
+ warn(
2485
+ `Ignoring "agent" key of ${label}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
2486
+ );
2487
+ return {};
2488
+ }
2489
+ const phases = parsePhasesInput(
2490
+ raw !== null && typeof raw === "object" && "phases" in raw ? raw.phases : void 0,
2491
+ warn
2492
+ );
2493
+ return {
2494
+ ...parsed.data.provider !== void 0 ? { provider: parsed.data.provider } : {},
2495
+ ...parsed.data.model !== void 0 ? { model: parsed.data.model } : {},
2496
+ ...parsed.data.claude !== void 0 ? { claude: parsed.data.claude } : {},
2497
+ ...parsed.data.codex !== void 0 ? { codex: parsed.data.codex } : {},
2498
+ ...parsed.data.cursor !== void 0 ? { cursor: parsed.data.cursor } : {},
2499
+ ...parsed.data.antigravity !== void 0 ? { antigravity: parsed.data.antigravity } : {},
2500
+ ...Object.keys(phases).length > 0 ? { phases } : {}
2501
+ };
2502
+ }
2503
+ function pickOrigin(layers) {
2504
+ let current = "default";
2505
+ for (const layer of layers) {
2506
+ if (layer.value !== void 0) current = layer.origin;
2507
+ }
2508
+ return current;
2509
+ }
2510
+ function mergeAgentBlockLayers(layers) {
2511
+ let merged = {};
2512
+ let any = false;
2513
+ for (const layer of layers) {
2514
+ if (layer.block === void 0) continue;
2515
+ any = true;
2516
+ merged = {
2517
+ ...merged,
2518
+ ...dropUndefinedBlock(layer.block),
2519
+ claude: { ...merged.claude, ...layer.block.claude },
2520
+ codex: { ...merged.codex, ...layer.block.codex },
2521
+ cursor: { ...merged.cursor, ...layer.block.cursor },
2522
+ antigravity: { ...merged.antigravity, ...layer.block.antigravity }
2523
+ };
2524
+ }
2525
+ return any ? merged : void 0;
2526
+ }
2527
+ function dropUndefinedBlock(block) {
2528
+ const result = {};
2529
+ if (block.provider !== void 0) result.provider = block.provider;
2530
+ if (block.model !== void 0) result.model = block.model;
2531
+ if (block.claude !== void 0) result.claude = block.claude;
2532
+ if (block.codex !== void 0) result.codex = block.codex;
2533
+ if (block.cursor !== void 0) result.cursor = block.cursor;
2534
+ if (block.antigravity !== void 0) result.antigravity = block.antigravity;
2535
+ return result;
2536
+ }
2537
+ async function loadAgentConfig(options = {}) {
2538
+ const canCache = options.cli === void 0 && options.env === void 0 && options.projectRoot === void 0 && options.globalRoot === void 0 && options.warn === void 0;
2539
+ if (canCache && cachedAgentConfig !== void 0) return cachedAgentConfig;
2540
+ const warn = options.warn ?? printWarning;
2541
+ const cli = options.cli ?? agentCliOverrides;
2542
+ const env = options.env ?? process.env;
2543
+ const globalFile = await loadGlobalConfig({
2544
+ env,
2545
+ globalRoot: options.globalRoot,
2546
+ warn
2547
+ });
2548
+ const globalLayer = readAgentKey(globalFile.agent, GLOBAL_CONFIG_FILENAME, warn);
2549
+ const projectFile = await readProjectConfigFile(options.projectRoot, warn);
2550
+ const projectLayer = readAgentKey(projectFile?.agent, PROJECT_CONFIG_FILENAME, warn);
2551
+ const envLayer = readAgentEnv(env, warn);
2552
+ const provider = cli.forceProvider ?? cli.provider ?? envLayer.provider ?? projectLayer.provider ?? globalLayer.provider ?? "claude";
2553
+ const model = cli.forceModel ?? cli.model ?? envLayer.model ?? projectLayer.model ?? globalLayer.model ?? null;
2554
+ const claude = mergeConfigLayers({
2555
+ global: globalLayer.claude,
2556
+ project: projectLayer.claude,
2557
+ env: envLayer.claude,
2558
+ cli: cli.claude
2559
+ });
2560
+ const codex = mergeConfigLayers({
2561
+ global: globalLayer.codex,
2562
+ project: projectLayer.codex,
2563
+ env: envLayer.codex,
2564
+ cli: cli.codex
2565
+ });
2566
+ const cursor = mergeConfigLayers({
2567
+ global: globalLayer.cursor,
2568
+ project: projectLayer.cursor,
2569
+ env: envLayer.cursor,
2570
+ cli: cli.cursor
2571
+ });
2572
+ const antigravity = mergeConfigLayers({
2573
+ global: globalLayer.antigravity,
2574
+ project: projectLayer.antigravity,
2575
+ env: envLayer.antigravity,
2576
+ cli: cli.antigravity
2577
+ });
2578
+ const phases = {};
2579
+ const phaseOrigins = {};
2580
+ for (const phase of AGENT_PHASES) {
2581
+ const block = mergeAgentBlockLayers([
2582
+ { origin: "global", block: globalLayer.phases?.[phase] },
2583
+ { origin: "project", block: projectLayer.phases?.[phase] },
2584
+ { origin: "env", block: envLayer.phases?.[phase] },
2585
+ { origin: "cli", block: cli.phases?.[phase] }
2586
+ ]);
2587
+ if (block && Object.keys(block).length > 0) {
2588
+ phases[phase] = block;
2589
+ phaseOrigins[phase] = {
2590
+ provider: block.provider !== void 0 ? pickOrigin([
2591
+ { origin: "global", value: globalLayer.phases?.[phase]?.provider },
2592
+ { origin: "project", value: projectLayer.phases?.[phase]?.provider },
2593
+ { origin: "env", value: envLayer.phases?.[phase]?.provider },
2594
+ { origin: "cli", value: cli.phases?.[phase]?.provider }
2595
+ ]) : void 0,
2596
+ model: block.model !== void 0 ? pickOrigin([
2597
+ { origin: "global", value: globalLayer.phases?.[phase]?.model },
2598
+ { origin: "project", value: projectLayer.phases?.[phase]?.model },
2599
+ { origin: "env", value: envLayer.phases?.[phase]?.model },
2600
+ { origin: "cli", value: cli.phases?.[phase]?.model }
2601
+ ]) : void 0
2602
+ };
2603
+ }
2604
+ }
2605
+ setTrackedOrigins({
2606
+ provider: pickOrigin([
2607
+ { origin: "default", value: "claude" },
2608
+ { origin: "global", value: globalLayer.provider },
2609
+ { origin: "project", value: projectLayer.provider },
2610
+ { origin: "env", value: envLayer.provider },
2611
+ { origin: "cli", value: cli.forceProvider ?? cli.provider }
2612
+ ]),
2613
+ model: pickOrigin([
2614
+ { origin: "default", value: void 0 },
2615
+ { origin: "global", value: globalLayer.model },
2616
+ { origin: "project", value: projectLayer.model },
2617
+ { origin: "env", value: envLayer.model },
2618
+ { origin: "cli", value: cli.forceModel ?? cli.model }
2619
+ ]),
2620
+ phases: phaseOrigins
2621
+ });
2622
+ const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2623
+ if (canCache) cachedAgentConfig = resolved;
2624
+ return resolved;
2625
+ }
2626
+ var verifyCliOverrides = {};
2627
+ function setVerifyCliOverrides(overrides) {
2628
+ verifyCliOverrides = overrides;
2629
+ }
2630
+ async function readVerifyConfigFile(projectRoot, warn) {
2631
+ const file = await readProjectConfigFile(projectRoot, warn);
2632
+ const verify = file?.verify;
2633
+ if (verify === void 0) return {};
2634
+ const result = verifyConfigSchema.partial().safeParse(verify);
2635
+ if (!result.success) {
2636
+ warn(
2637
+ `Ignoring "verify" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2638
+ );
2639
+ return {};
2640
+ }
2641
+ return result.data;
2642
+ }
2643
+ async function loadVerifyConfig(options = {}) {
2644
+ const warn = options.warn ?? printWarning;
2645
+ const cli = options.cli ?? verifyCliOverrides;
2646
+ const fileLayer = await readVerifyConfigFile(options.projectRoot, warn);
2647
+ const merged = { ...fileLayer, ...cli };
2648
+ const result = verifyConfigSchema.safeParse(merged);
2649
+ if (result.success) return result.data;
2650
+ warn(
2651
+ `Invalid verify configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2652
+ );
2653
+ return verifyConfigSchema.parse({});
2654
+ }
2655
+ var routingCliOverrides = {};
2656
+ function setRoutingCliOverrides(overrides) {
2657
+ routingCliOverrides = overrides;
2658
+ }
2659
+ async function loadRoutingConfig(options = {}) {
2660
+ const warn = options.warn ?? printWarning;
2661
+ const file = await readProjectConfigFile(options.projectRoot, warn);
2662
+ const raw = file?.routing;
2663
+ const parsed = raw === void 0 ? {} : routingConfigSchema.partial().safeParse(raw).data ?? {};
2664
+ const result = routingConfigSchema.safeParse({
2665
+ ...parsed,
2666
+ ...options.cli ?? routingCliOverrides
2667
+ });
2668
+ return result.success ? result.data : routingConfigSchema.parse({});
2669
+ }
2670
+
2671
+ export {
2672
+ getShutdownSignal,
2673
+ onShutdown,
2674
+ installShutdownHandlers,
2675
+ DEFAULT_INACTIVITY_TIMEOUT_MS,
2676
+ peekHarnessVersion,
2677
+ resolveAntigravityTimeoutMs,
2678
+ getRegisteredProviders,
2679
+ ensureRunnersRegistered,
2680
+ runnerFor,
2681
+ ensureHarnessVersion,
2682
+ probeAgent,
2683
+ DEFAULTS,
2684
+ createConfig,
2685
+ resolvePaths,
2686
+ getInstallHint,
2687
+ validateDependencies,
2688
+ PROJECT_CONFIG_FILENAME,
2689
+ WEB_CONFIG_FILENAME,
2690
+ GLOBAL_CONFIG_FILENAME,
2691
+ loadGlobalConfig,
2692
+ mergeConfigLayers,
2693
+ setWebCliOverrides,
2694
+ loadWebConfig,
2695
+ setIssuesCliOverrides,
2696
+ loadIssuesConfig,
2697
+ loadPrReviewConfig,
2698
+ setPolicyCliOverrides,
2699
+ loadPolicyConfig,
2700
+ loadTelemetryConfig,
2701
+ setResilienceCliOverrides,
2702
+ loadResilienceConfig,
2703
+ getActiveResilienceConfig,
2704
+ setActiveResilienceConfig,
2705
+ initResilienceConfig,
2706
+ setAgentCliOverrides,
2707
+ getAgentCliOverrides,
2708
+ loadAgentConfig,
2709
+ setVerifyCliOverrides,
2710
+ loadVerifyConfig,
2711
+ setRoutingCliOverrides,
2712
+ loadRoutingConfig,
2713
+ resolveAgentFor,
2714
+ parseAgentPhaseFlag,
2715
+ describeRunAgents,
2716
+ hasExplicitAgentSelection
2717
+ };
2718
+ //# sourceMappingURL=chunk-QJ5UZAH5.js.map