issue-flow 0.16.0 → 0.18.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 (168) hide show
  1. package/dist/agent-HMZTXCRT.js +30 -0
  2. package/dist/{analyze-556KCJKZ.js → analyze-Q4ONIWRZ.js} +22 -22
  3. package/dist/{apply-WVV7G7WN.js → apply-EEFPY2W4.js} +14 -14
  4. package/dist/{bench-UBFGKUHR.js → bench-WWWXLTFH.js} +23 -23
  5. package/dist/{chunk-GV2DABNZ.js → chunk-34OCSKOB.js} +12 -12
  6. package/dist/chunk-3R27MJ5R.js +25 -0
  7. package/dist/chunk-3R27MJ5R.js.map +1 -0
  8. package/dist/{chunk-PGN2VX4Y.js → chunk-45WZ6GMI.js} +32 -48
  9. package/dist/chunk-45WZ6GMI.js.map +1 -0
  10. package/dist/{chunk-H3EYBJZU.js → chunk-62GVVZQO.js} +10 -10
  11. package/dist/{chunk-GPLP7EPL.js → chunk-6K2LCFG6.js} +10 -10
  12. package/dist/{chunk-GPLP7EPL.js.map → chunk-6K2LCFG6.js.map} +1 -1
  13. package/dist/{chunk-OGVWJO4S.js → chunk-7F7LGMVO.js} +3 -3
  14. package/dist/{chunk-X6GY3CM2.js → chunk-7UMMFOL2.js} +104 -104
  15. package/dist/chunk-7UMMFOL2.js.map +1 -0
  16. package/dist/{chunk-OLUOZLU5.js → chunk-CWSQVHVV.js} +1691 -1075
  17. package/dist/chunk-CWSQVHVV.js.map +1 -0
  18. package/dist/{chunk-MXCOSPLJ.js → chunk-DGRTJD5R.js} +3 -3
  19. package/dist/{chunk-ROIIEVZH.js → chunk-DUS5ZNKL.js} +474 -361
  20. package/dist/chunk-DUS5ZNKL.js.map +1 -0
  21. package/dist/{chunk-BSBJXPLC.js → chunk-E4I6MMHD.js} +10 -10
  22. package/dist/{chunk-QZOBR6YF.js → chunk-ECU7YO7S.js} +4 -4
  23. package/dist/chunk-ECU7YO7S.js.map +1 -0
  24. package/dist/{chunk-EPFC4LHT.js → chunk-EG2MGDP5.js} +9 -9
  25. package/dist/chunk-HOAHMERN.js +229 -0
  26. package/dist/chunk-HOAHMERN.js.map +1 -0
  27. package/dist/{chunk-QVLIIGBU.js → chunk-ICM463EO.js} +60 -13
  28. package/dist/chunk-ICM463EO.js.map +1 -0
  29. package/dist/{chunk-4FUWWBTP.js → chunk-KMCS76ZW.js} +8 -8
  30. package/dist/{chunk-SW2MF47D.js → chunk-KRAGAUKD.js} +19 -19
  31. package/dist/{chunk-OOX3RMD3.js → chunk-LGHND47K.js} +4 -4
  32. package/dist/{chunk-VTF4RWS5.js → chunk-LI35PIIS.js} +7 -7
  33. package/dist/{chunk-Q2TZA6AC.js → chunk-LTH6XYZ3.js} +14 -14
  34. package/dist/{chunk-YA6FWFYW.js → chunk-NEWNXZ65.js} +62 -11
  35. package/dist/chunk-NEWNXZ65.js.map +1 -0
  36. package/dist/{chunk-2H43OVTU.js → chunk-OODXFCQV.js} +11 -11
  37. package/dist/{chunk-KV2K7MK2.js → chunk-PMLE7KAQ.js} +20 -12
  38. package/dist/chunk-PMLE7KAQ.js.map +1 -0
  39. package/dist/{chunk-R42YHLDV.js → chunk-PPZ3K4YM.js} +2 -2
  40. package/dist/{chunk-J2LJB2OH.js → chunk-QF7VEL3M.js} +739 -579
  41. package/dist/chunk-QF7VEL3M.js.map +1 -0
  42. package/dist/{chunk-VK65RNFA.js → chunk-QJ44VG5G.js} +3 -3
  43. package/dist/{chunk-FKWYD44M.js → chunk-QPGEFLMY.js} +2 -2
  44. package/dist/{chunk-NQCR3HSU.js → chunk-RNFUVKC3.js} +3 -3
  45. package/dist/{chunk-G5LACAXO.js → chunk-RYOUZ6EK.js} +2 -2
  46. package/dist/{chunk-MCLPSL6B.js → chunk-SA6HXL4Y.js} +3 -3
  47. package/dist/{chunk-GVOZ6NDO.js → chunk-SOM4QA6C.js} +3 -3
  48. package/dist/{chunk-73TS2H42.js → chunk-TZYINKCC.js} +154 -34
  49. package/dist/chunk-TZYINKCC.js.map +1 -0
  50. package/dist/{chunk-DBEMD34J.js → chunk-V7QOIQYC.js} +8 -8
  51. package/dist/{chunk-IAMIBZRF.js → chunk-WCCZJL7W.js} +2 -2
  52. package/dist/{chunk-OGN2NX57.js → chunk-XUEMATVY.js} +9 -9
  53. package/dist/{chunk-SVDEWOUD.js → chunk-XZUEFTUP.js} +6 -6
  54. package/dist/{chunk-WLJVL25O.js → chunk-YUNBOUQH.js} +6 -6
  55. package/dist/{chunk-WNROH2YE.js → chunk-YVPZUN6X.js} +2 -2
  56. package/dist/chunk-ZVZMWNCG.js +415 -0
  57. package/dist/chunk-ZVZMWNCG.js.map +1 -0
  58. package/dist/cli.js +57 -49
  59. package/dist/cli.js.map +1 -1
  60. package/dist/{config-UE7IP36J.js → config-LEBZZCJP.js} +13 -13
  61. package/dist/{conventions-Z3QC2NSG.js → conventions-XOT6YW5L.js} +15 -15
  62. package/dist/{diagnostics-2Z5HFQOO.js → diagnostics-HTCWF7F4.js} +7 -7
  63. package/dist/execute-LELOSR5T.js +37 -0
  64. package/dist/{generate-PB4L7V5N.js → generate-JGW5JSKB.js} +22 -22
  65. package/dist/{git-7MUOGVRG.js → git-A2IP32PQ.js} +2 -2
  66. package/dist/init-TO6MUXO4.js +26 -0
  67. package/dist/{operations-QDJAFZUN.js → operations-O4FORFIH.js} +15 -15
  68. package/dist/{permissions-XVXXENVP.js → permissions-G4XCAESF.js} +4 -4
  69. package/dist/plan-OXAT344Q.js +34 -0
  70. package/dist/{policy-6WQZB6B2.js → policy-U5NBFAO5.js} +14 -14
  71. package/dist/pr-UZHNKKZC.js +39 -0
  72. package/dist/pr-review-Q4ACAWDM.js +32 -0
  73. package/dist/prd-6CYEMLDY.js +33 -0
  74. package/dist/{ps-CX7756QG.js → ps-76L6ZAZL.js} +12 -12
  75. package/dist/{recorder-RK6XZYF3.js → recorder-2BAKPBRA.js} +7 -7
  76. package/dist/{registry-POSB35Q4.js → registry-XLHHYLTR.js} +5 -5
  77. package/dist/{resume-OQJZV3JH.js → resume-URCU6CIJ.js} +39 -38
  78. package/dist/{resume-OQJZV3JH.js.map → resume-URCU6CIJ.js.map} +1 -1
  79. package/dist/review-LVZT2TMW.js +35 -0
  80. package/dist/routing-EK6RBZM4.js +33 -0
  81. package/dist/run-2RXJCJKT.js +56 -0
  82. package/dist/{session-publisher-VVXOCJ2S.js → session-publisher-KAJQRHNZ.js} +3 -2
  83. package/dist/{state-manager-TIC73GQY.js → state-manager-UPHO2EA2.js} +4 -4
  84. package/dist/state-manager-UPHO2EA2.js.map +1 -0
  85. package/dist/{usage-WDDNSIHP.js → usage-KTMYXAPF.js} +12 -12
  86. package/dist/{web-IPGY52AK.js → web-B5UPHHR5.js} +20 -18
  87. package/dist/{web-IPGY52AK.js.map → web-B5UPHHR5.js.map} +1 -1
  88. package/package.json +6 -5
  89. package/web/AGENTS.md +125 -18
  90. package/web/public/app.css +420 -234
  91. package/web/public/app.js +371 -80
  92. package/web/public/index.html +106 -78
  93. package/dist/agent-PMWCDWOW.js +0 -30
  94. package/dist/chunk-73TS2H42.js.map +0 -1
  95. package/dist/chunk-7Z4Y3VKM.js +0 -26
  96. package/dist/chunk-7Z4Y3VKM.js.map +0 -1
  97. package/dist/chunk-AOAQU7PD.js +0 -180
  98. package/dist/chunk-AOAQU7PD.js.map +0 -1
  99. package/dist/chunk-J2LJB2OH.js.map +0 -1
  100. package/dist/chunk-KV2K7MK2.js.map +0 -1
  101. package/dist/chunk-OLUOZLU5.js.map +0 -1
  102. package/dist/chunk-PGN2VX4Y.js.map +0 -1
  103. package/dist/chunk-QVLIIGBU.js.map +0 -1
  104. package/dist/chunk-QZOBR6YF.js.map +0 -1
  105. package/dist/chunk-ROIIEVZH.js.map +0 -1
  106. package/dist/chunk-X6GY3CM2.js.map +0 -1
  107. package/dist/chunk-YA6FWFYW.js.map +0 -1
  108. package/dist/execute-QYLJ5L4T.js +0 -36
  109. package/dist/init-XBERAZ4O.js +0 -24
  110. package/dist/plan-RXOW32KY.js +0 -34
  111. package/dist/pr-3WFYAVA7.js +0 -39
  112. package/dist/pr-review-RK63ZEMM.js +0 -32
  113. package/dist/prd-LRV6IW3E.js +0 -33
  114. package/dist/review-AEFISJZD.js +0 -35
  115. package/dist/routing-EA5NJGNU.js +0 -94
  116. package/dist/routing-EA5NJGNU.js.map +0 -1
  117. package/dist/run-HSC7R33Y.js +0 -55
  118. /package/dist/{agent-PMWCDWOW.js.map → agent-HMZTXCRT.js.map} +0 -0
  119. /package/dist/{analyze-556KCJKZ.js.map → analyze-Q4ONIWRZ.js.map} +0 -0
  120. /package/dist/{apply-WVV7G7WN.js.map → apply-EEFPY2W4.js.map} +0 -0
  121. /package/dist/{bench-UBFGKUHR.js.map → bench-WWWXLTFH.js.map} +0 -0
  122. /package/dist/{chunk-GV2DABNZ.js.map → chunk-34OCSKOB.js.map} +0 -0
  123. /package/dist/{chunk-H3EYBJZU.js.map → chunk-62GVVZQO.js.map} +0 -0
  124. /package/dist/{chunk-OGVWJO4S.js.map → chunk-7F7LGMVO.js.map} +0 -0
  125. /package/dist/{chunk-MXCOSPLJ.js.map → chunk-DGRTJD5R.js.map} +0 -0
  126. /package/dist/{chunk-BSBJXPLC.js.map → chunk-E4I6MMHD.js.map} +0 -0
  127. /package/dist/{chunk-EPFC4LHT.js.map → chunk-EG2MGDP5.js.map} +0 -0
  128. /package/dist/{chunk-4FUWWBTP.js.map → chunk-KMCS76ZW.js.map} +0 -0
  129. /package/dist/{chunk-SW2MF47D.js.map → chunk-KRAGAUKD.js.map} +0 -0
  130. /package/dist/{chunk-OOX3RMD3.js.map → chunk-LGHND47K.js.map} +0 -0
  131. /package/dist/{chunk-VTF4RWS5.js.map → chunk-LI35PIIS.js.map} +0 -0
  132. /package/dist/{chunk-Q2TZA6AC.js.map → chunk-LTH6XYZ3.js.map} +0 -0
  133. /package/dist/{chunk-2H43OVTU.js.map → chunk-OODXFCQV.js.map} +0 -0
  134. /package/dist/{chunk-R42YHLDV.js.map → chunk-PPZ3K4YM.js.map} +0 -0
  135. /package/dist/{chunk-VK65RNFA.js.map → chunk-QJ44VG5G.js.map} +0 -0
  136. /package/dist/{chunk-FKWYD44M.js.map → chunk-QPGEFLMY.js.map} +0 -0
  137. /package/dist/{chunk-NQCR3HSU.js.map → chunk-RNFUVKC3.js.map} +0 -0
  138. /package/dist/{chunk-G5LACAXO.js.map → chunk-RYOUZ6EK.js.map} +0 -0
  139. /package/dist/{chunk-MCLPSL6B.js.map → chunk-SA6HXL4Y.js.map} +0 -0
  140. /package/dist/{chunk-GVOZ6NDO.js.map → chunk-SOM4QA6C.js.map} +0 -0
  141. /package/dist/{chunk-DBEMD34J.js.map → chunk-V7QOIQYC.js.map} +0 -0
  142. /package/dist/{chunk-IAMIBZRF.js.map → chunk-WCCZJL7W.js.map} +0 -0
  143. /package/dist/{chunk-OGN2NX57.js.map → chunk-XUEMATVY.js.map} +0 -0
  144. /package/dist/{chunk-SVDEWOUD.js.map → chunk-XZUEFTUP.js.map} +0 -0
  145. /package/dist/{chunk-WLJVL25O.js.map → chunk-YUNBOUQH.js.map} +0 -0
  146. /package/dist/{chunk-WNROH2YE.js.map → chunk-YVPZUN6X.js.map} +0 -0
  147. /package/dist/{config-UE7IP36J.js.map → config-LEBZZCJP.js.map} +0 -0
  148. /package/dist/{conventions-Z3QC2NSG.js.map → conventions-XOT6YW5L.js.map} +0 -0
  149. /package/dist/{diagnostics-2Z5HFQOO.js.map → diagnostics-HTCWF7F4.js.map} +0 -0
  150. /package/dist/{execute-QYLJ5L4T.js.map → execute-LELOSR5T.js.map} +0 -0
  151. /package/dist/{generate-PB4L7V5N.js.map → generate-JGW5JSKB.js.map} +0 -0
  152. /package/dist/{git-7MUOGVRG.js.map → git-A2IP32PQ.js.map} +0 -0
  153. /package/dist/{init-XBERAZ4O.js.map → init-TO6MUXO4.js.map} +0 -0
  154. /package/dist/{operations-QDJAFZUN.js.map → operations-O4FORFIH.js.map} +0 -0
  155. /package/dist/{permissions-XVXXENVP.js.map → permissions-G4XCAESF.js.map} +0 -0
  156. /package/dist/{plan-RXOW32KY.js.map → plan-OXAT344Q.js.map} +0 -0
  157. /package/dist/{policy-6WQZB6B2.js.map → policy-U5NBFAO5.js.map} +0 -0
  158. /package/dist/{pr-3WFYAVA7.js.map → pr-UZHNKKZC.js.map} +0 -0
  159. /package/dist/{pr-review-RK63ZEMM.js.map → pr-review-Q4ACAWDM.js.map} +0 -0
  160. /package/dist/{prd-LRV6IW3E.js.map → prd-6CYEMLDY.js.map} +0 -0
  161. /package/dist/{ps-CX7756QG.js.map → ps-76L6ZAZL.js.map} +0 -0
  162. /package/dist/{recorder-RK6XZYF3.js.map → recorder-2BAKPBRA.js.map} +0 -0
  163. /package/dist/{registry-POSB35Q4.js.map → registry-XLHHYLTR.js.map} +0 -0
  164. /package/dist/{review-AEFISJZD.js.map → review-LVZT2TMW.js.map} +0 -0
  165. /package/dist/{run-HSC7R33Y.js.map → routing-EK6RBZM4.js.map} +0 -0
  166. /package/dist/{session-publisher-VVXOCJ2S.js.map → run-2RXJCJKT.js.map} +0 -0
  167. /package/dist/{state-manager-TIC73GQY.js.map → session-publisher-KAJQRHNZ.js.map} +0 -0
  168. /package/dist/{usage-WDDNSIHP.js.map → usage-KTMYXAPF.js.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveIssuePaths
4
- } from "./chunk-VTF4RWS5.js";
4
+ } from "./chunk-LI35PIIS.js";
5
5
  import {
6
6
  formatDuration,
7
7
  printWarning
8
- } from "./chunk-SVDEWOUD.js";
8
+ } from "./chunk-XZUEFTUP.js";
9
9
  import {
10
10
  getGlobalRoot
11
11
  } from "./chunk-HAKDLR6N.js";
@@ -13,14 +13,14 @@ import {
13
13
  RETRY_CONFIG_KEYS,
14
14
  getProjectRoot,
15
15
  run
16
- } from "./chunk-WNROH2YE.js";
16
+ } from "./chunk-YVPZUN6X.js";
17
17
  import {
18
18
  DEFAULT_TELEMETRY_CONFIG
19
- } from "./chunk-GPLP7EPL.js";
19
+ } from "./chunk-6K2LCFG6.js";
20
20
  import {
21
21
  parseCodexUsage,
22
22
  parseUsage
23
- } from "./chunk-GVOZ6NDO.js";
23
+ } from "./chunk-SOM4QA6C.js";
24
24
  import {
25
25
  AGENT_PHASES,
26
26
  ANTIGRAVITY_CAPABILITIES,
@@ -37,17 +37,101 @@ import {
37
37
  policyConfigSchema,
38
38
  prReviewConfigSchema,
39
39
  resilienceConfigSchema,
40
+ routingConfigInputSchema,
40
41
  routingConfigSchema,
41
42
  telemetryConfigInputSchema,
42
43
  verifyConfigSchema,
43
44
  webConfigSchema
44
- } from "./chunk-QVLIIGBU.js";
45
+ } from "./chunk-ICM463EO.js";
45
46
 
46
- // src/config.ts
47
+ // src/config/sources.ts
47
48
  import { existsSync } from "fs";
48
- import { readFile as readFile2 } from "fs/promises";
49
+ import { readFile } from "fs/promises";
50
+ import { dirname, join } from "path";
51
+ var PROJECT_CONFIG_FILENAME = ".issue-flow.json";
52
+ function findProjectRootFromCwd(start = process.cwd()) {
53
+ let dir = start;
54
+ while (true) {
55
+ if (existsSync(join(dir, PROJECT_CONFIG_FILENAME)) || existsSync(join(dir, ".git"))) {
56
+ return dir;
57
+ }
58
+ const parent = dirname(dir);
59
+ if (parent === dir) return void 0;
60
+ dir = parent;
61
+ }
62
+ }
63
+ async function readProjectConfigFile(projectRoot, warn) {
64
+ const root = projectRoot ?? findProjectRootFromCwd();
65
+ if (root === void 0) {
66
+ return null;
67
+ }
68
+ const filePath = join(root, PROJECT_CONFIG_FILENAME);
69
+ let raw;
70
+ try {
71
+ raw = await readFile(filePath, "utf-8");
72
+ } catch {
73
+ return null;
74
+ }
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(raw);
78
+ } catch {
79
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: invalid JSON.`);
80
+ return null;
81
+ }
82
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
83
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: expected a JSON object.`);
84
+ return null;
85
+ }
86
+ return parsed;
87
+ }
88
+ var GLOBAL_CONFIG_FILENAME = "config.json";
89
+ async function loadGlobalConfig(options = {}) {
90
+ const warn = options.warn ?? printWarning;
91
+ let root;
92
+ try {
93
+ root = options.globalRoot ?? getGlobalRoot({ env: options.env ?? process.env });
94
+ } catch (err) {
95
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
96
+ return {};
97
+ }
98
+ const filePath = join(root, GLOBAL_CONFIG_FILENAME);
99
+ let raw;
100
+ try {
101
+ raw = await readFile(filePath, "utf-8");
102
+ } catch (err) {
103
+ if (err.code !== "ENOENT") {
104
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
105
+ }
106
+ return {};
107
+ }
108
+ let parsed;
109
+ try {
110
+ parsed = JSON.parse(raw);
111
+ } catch {
112
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: invalid JSON.`);
113
+ return {};
114
+ }
115
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
116
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: expected a JSON object.`);
117
+ return {};
118
+ }
119
+ const config = {};
120
+ for (const [key, value] of Object.entries(parsed)) {
121
+ const result = globalConfigSchema.safeParse({ [key]: value });
122
+ if (!result.success) {
123
+ warn(
124
+ `Ignoring "${key}" key of ${GLOBAL_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
125
+ );
126
+ continue;
127
+ }
128
+ Object.assign(config, result.data);
129
+ }
130
+ return config;
131
+ }
132
+
133
+ // src/config/dependencies.ts
49
134
  import { platform } from "os";
50
- import { dirname, join as join2 } from "path";
51
135
 
52
136
  // src/agents/availability.ts
53
137
  import { execa as execa6 } from "execa";
@@ -981,9 +1065,9 @@ ${stdout}`
981
1065
  };
982
1066
 
983
1067
  // src/agents/codex.ts
984
- import { mkdtemp, readFile, rm } from "fs/promises";
1068
+ import { mkdtemp, readFile as readFile2, rm } from "fs/promises";
985
1069
  import { tmpdir } from "os";
986
- import { join } from "path";
1070
+ import { join as join2 } from "path";
987
1071
  import { execa as execa3 } from "execa";
988
1072
  var BANNED_CODEX_FLAGS = [
989
1073
  "--dangerously-bypass-approvals-and-sandbox",
@@ -1137,8 +1221,8 @@ var CodexRunner = class {
1137
1221
  return { command: "codex", args: ["login", "status"] };
1138
1222
  }
1139
1223
  async run(invocation, settings) {
1140
- const tmp = await mkdtemp(join(tmpdir(), "issue-flow-codex-"));
1141
- const outputFile = join(tmp, "last-message.txt");
1224
+ const tmp = await mkdtemp(join2(tmpdir(), "issue-flow-codex-"));
1225
+ const outputFile = join2(tmp, "last-message.txt");
1142
1226
  const args = buildCodexArgv(invocation, settings, outputFile);
1143
1227
  const agent = { provider: this.id, model: settings.model };
1144
1228
  const base = { agent, harnessVersion: peekHarnessVersion(this.id) };
@@ -1195,7 +1279,7 @@ ${stderr}` : "");
1195
1279
  const parsed = parseCodexStream(collected, invocation.onEvent);
1196
1280
  let lastMessage = "";
1197
1281
  try {
1198
- lastMessage = (await readFile(outputFile, "utf-8")).trimEnd();
1282
+ lastMessage = (await readFile2(outputFile, "utf-8")).trimEnd();
1199
1283
  } catch {
1200
1284
  lastMessage = "";
1201
1285
  }
@@ -1547,7 +1631,7 @@ function dropUndefined(value) {
1547
1631
  return result;
1548
1632
  }
1549
1633
  async function resolveAgentFor(phase, options = {}) {
1550
- const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-UE7IP36J.js");
1634
+ const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-LEBZZCJP.js");
1551
1635
  const config = options.config ?? await loadAgentConfig2();
1552
1636
  const cli = options.cli ?? getAgentCliOverrides2();
1553
1637
  const defaultBlock = {
@@ -1653,7 +1737,7 @@ async function describeRunAgents(phases = AGENT_PHASES) {
1653
1737
  defaultModel = settings.model;
1654
1738
  }
1655
1739
  }
1656
- const { loadAgentConfig: loadAgentConfig2 } = await import("./config-UE7IP36J.js");
1740
+ const { loadAgentConfig: loadAgentConfig2 } = await import("./config-LEBZZCJP.js");
1657
1741
  const config = await loadAgentConfig2();
1658
1742
  defaultProvider = config.provider;
1659
1743
  defaultModel = config.model;
@@ -1669,29 +1753,70 @@ async function describeRunAgents(phases = AGENT_PHASES) {
1669
1753
  byPhase
1670
1754
  };
1671
1755
  }
1672
- function hasExplicitAgentSelection(config, cli) {
1756
+ function hasExplicitAgentSelection(config, cli, phase) {
1673
1757
  if (cli?.forceProvider !== void 0 || cli?.forceModel !== void 0) return true;
1674
- if (cli?.phases && Object.keys(cli.phases).length > 0) return true;
1758
+ if (cli?.phases && (phase === void 0 ? Object.keys(cli.phases).length > 0 : cli.phases[phase] !== void 0)) {
1759
+ return true;
1760
+ }
1675
1761
  if (config.provider !== "claude") return true;
1676
1762
  if (config.model !== null) return true;
1677
- if (Object.keys(config.phases).length > 0) return true;
1763
+ if (phase === void 0 ? Object.keys(config.phases).length > 0 : config.phases[phase] !== void 0) {
1764
+ return true;
1765
+ }
1678
1766
  if (config.claude.ignoreUserConfig !== void 0) return true;
1679
1767
  if (Object.keys(config.codex).length > 0) return true;
1680
1768
  return false;
1681
1769
  }
1682
1770
 
1683
1771
  // src/agents/availability.ts
1772
+ var READINESS_SCHEMA_VERSION = "1";
1773
+ var DEFAULT_READINESS_TTL_MS = 5 * 6e4;
1774
+ var PROVIDER_HARNESS = {
1775
+ claude: "claude-code",
1776
+ codex: "codex-cli",
1777
+ cursor: "cursor-cli",
1778
+ antigravity: "antigravity-cli"
1779
+ };
1780
+ var ALL_PROVIDERS = ["claude", "codex", "cursor", "antigravity"];
1684
1781
  var probeCache = /* @__PURE__ */ new Map();
1782
+ var inventoryCache = null;
1783
+ function deriveState(installed2, authentication, cooldownUntil, nowMs) {
1784
+ if (!installed2) return "unavailable";
1785
+ if (cooldownUntil !== null && Date.parse(cooldownUntil) > nowMs) return "unavailable";
1786
+ if (authentication === "failed") return "unavailable";
1787
+ if (authentication === "unverified") return "conditional";
1788
+ return "ready";
1789
+ }
1790
+ function toAvailability(readiness) {
1791
+ return {
1792
+ id: readiness.provider,
1793
+ installed: readiness.installed,
1794
+ version: readiness.version,
1795
+ authenticated: readiness.installed && readiness.authentication !== "failed",
1796
+ authentication: readiness.authentication,
1797
+ state: readiness.state,
1798
+ detail: readiness.detail,
1799
+ observedAt: readiness.observedAt,
1800
+ expiresAt: readiness.expiresAt,
1801
+ source: readiness.source,
1802
+ cooldownUntil: readiness.cooldownUntil
1803
+ };
1804
+ }
1685
1805
  async function probeAgent(id) {
1686
1806
  const cached = probeCache.get(id);
1687
1807
  if (cached) return cached;
1688
- const pending = probeAgentUncached(id);
1808
+ const pending = probeAgentUncached(id).then(toAvailability);
1689
1809
  probeCache.set(id, pending);
1690
1810
  return pending;
1691
1811
  }
1692
- async function probeAgentUncached(id) {
1812
+ async function probeAgentUncached(id, options = {}) {
1693
1813
  ensureRunnersRegistered();
1694
1814
  const runner = runnerFor(id);
1815
+ const now = options.now?.() ?? /* @__PURE__ */ new Date();
1816
+ const ttlMs = options.ttlMs ?? DEFAULT_READINESS_TTL_MS;
1817
+ const observedAt = now.toISOString();
1818
+ const expiresAt = new Date(now.getTime() + ttlMs).toISOString();
1819
+ const cooldownUntil = options.cooldownUntil ?? null;
1695
1820
  let version = null;
1696
1821
  let installed2 = false;
1697
1822
  try {
@@ -1702,22 +1827,85 @@ async function probeAgentUncached(id) {
1702
1827
  } catch {
1703
1828
  installed2 = false;
1704
1829
  }
1705
- let authenticated = installed2;
1830
+ let authentication = installed2 ? "unverified" : "failed";
1706
1831
  let detail = installed2 ? version ?? "installed" : "not found";
1707
- if (installed2 && runner.authCommand && runner.capabilities.authProbe !== "none") {
1832
+ let source = "probe";
1833
+ if (!installed2) {
1834
+ authentication = "failed";
1835
+ detail = "not found";
1836
+ } else if (runner.authCommand && runner.capabilities.authProbe !== "none") {
1708
1837
  try {
1709
1838
  const { command, args } = runner.authCommand();
1710
1839
  const auth = await execa6(command, args, { reject: false, timeout: 1e4 });
1711
1840
  const text = `${auth.stdout?.toString() ?? ""}
1712
1841
  ${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)`;
1842
+ const ok = runner.capabilities.authProbe === "text" ? !/not logged in|not authenticated|no models available/i.test(text) : auth.exitCode === 0;
1843
+ authentication = ok ? "confirmed" : "failed";
1844
+ detail = ok ? `${version} (authenticated)` : `${version} (not authenticated)`;
1715
1845
  } catch {
1716
- authenticated = false;
1846
+ authentication = "failed";
1717
1847
  detail = `${version} (not authenticated)`;
1718
1848
  }
1849
+ } else {
1850
+ authentication = "unverified";
1851
+ detail = `${version} (auth unverified)`;
1852
+ source = "probe";
1853
+ }
1854
+ const state = deriveState(installed2, authentication, cooldownUntil, now.getTime());
1855
+ if (state === "unavailable" && cooldownUntil !== null && Date.parse(cooldownUntil) > now.getTime()) {
1856
+ detail = `${detail}; cooldown until ${cooldownUntil}`;
1719
1857
  }
1720
- return { id, installed: installed2, version, authenticated, detail };
1858
+ return {
1859
+ provider: id,
1860
+ harness: PROVIDER_HARNESS[id],
1861
+ installed: installed2,
1862
+ authentication,
1863
+ state,
1864
+ models: [
1865
+ {
1866
+ id: null,
1867
+ access: installed2 ? "unverified" : "denied",
1868
+ confidence: "unknown",
1869
+ source: "static-catalog"
1870
+ }
1871
+ ],
1872
+ version,
1873
+ detail,
1874
+ observedAt,
1875
+ expiresAt,
1876
+ source,
1877
+ cooldownUntil
1878
+ };
1879
+ }
1880
+ async function probeReadinessInventory(options = {}) {
1881
+ const now = options.now?.() ?? /* @__PURE__ */ new Date();
1882
+ const ttlMs = options.ttlMs ?? DEFAULT_READINESS_TTL_MS;
1883
+ if (!options.force && inventoryCache !== null && inventoryCache.expiresAtMs > now.getTime()) {
1884
+ return inventoryCache.promise;
1885
+ }
1886
+ const promise = (async () => {
1887
+ const providers = await Promise.all(
1888
+ ALL_PROVIDERS.map(
1889
+ (id) => probeAgentUncached(id, {
1890
+ now: () => now,
1891
+ ttlMs,
1892
+ cooldownUntil: options.cooldowns?.[id] ?? null
1893
+ })
1894
+ )
1895
+ );
1896
+ const byId = Object.fromEntries(providers.map((entry) => [entry.provider, entry]));
1897
+ for (const entry of providers) {
1898
+ probeCache.set(entry.provider, Promise.resolve(toAvailability(entry)));
1899
+ }
1900
+ return {
1901
+ schemaVersion: READINESS_SCHEMA_VERSION,
1902
+ observedAt: now.toISOString(),
1903
+ expiresAt: new Date(now.getTime() + ttlMs).toISOString(),
1904
+ providers: byId
1905
+ };
1906
+ })();
1907
+ inventoryCache = { expiresAtMs: now.getTime() + ttlMs, promise };
1908
+ return promise;
1721
1909
  }
1722
1910
  function installHint(id) {
1723
1911
  if (id === "codex") {
@@ -1732,167 +1920,7 @@ function installHint(id) {
1732
1920
  return "Install Claude Code: https://docs.anthropic.com/en/docs/claude-code";
1733
1921
  }
1734
1922
 
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-RK6XZYF3.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
- }
1923
+ // src/config/layers.ts
1896
1924
  function mergeConfigLayers(layers) {
1897
1925
  const merged = {};
1898
1926
  for (const layer of [
@@ -1911,9 +1939,14 @@ function mergeConfigLayers(layers) {
1911
1939
  }
1912
1940
  return merged;
1913
1941
  }
1914
- var webCliOverrides = {};
1915
- function setWebCliOverrides(overrides) {
1916
- webCliOverrides = overrides;
1942
+ function dropNullish(layer) {
1943
+ const result = {};
1944
+ for (const [key, value] of Object.entries(layer ?? {})) {
1945
+ if (value !== void 0 && value !== null) {
1946
+ result[key] = value;
1947
+ }
1948
+ }
1949
+ return result;
1917
1950
  }
1918
1951
  var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
1919
1952
  function parseBooleanEnv(value) {
@@ -1931,139 +1964,357 @@ function readNumberEnv(env, name, warn) {
1931
1964
  }
1932
1965
  return parsed;
1933
1966
  }
1934
- function readWebConfigEnv(env, warn) {
1967
+
1968
+ // src/config/agent.ts
1969
+ var agentCliOverrides = {};
1970
+ var cachedAgentConfig;
1971
+ function setAgentCliOverrides(overrides) {
1972
+ agentCliOverrides = overrides;
1973
+ cachedAgentConfig = void 0;
1974
+ }
1975
+ function getAgentCliOverrides() {
1976
+ return agentCliOverrides;
1977
+ }
1978
+ function readAgentEnv(env, warn) {
1935
1979
  const layer = {};
1936
- if (env.ISSUE_FLOW_WEB !== void 0) {
1937
- layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
1980
+ if (env.ISSUE_FLOW_AGENT !== void 0) {
1981
+ if (isAgentProviderId(env.ISSUE_FLOW_AGENT)) {
1982
+ layer.provider = env.ISSUE_FLOW_AGENT;
1983
+ } else {
1984
+ warn(
1985
+ `Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor or antigravity.`
1986
+ );
1987
+ }
1938
1988
  }
1939
- const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
1940
- if (port !== void 0) {
1941
- layer.port = port;
1989
+ if (env.ISSUE_FLOW_AGENT_MODEL !== void 0 && env.ISSUE_FLOW_AGENT_MODEL !== "") {
1990
+ layer.model = env.ISSUE_FLOW_AGENT_MODEL;
1942
1991
  }
1943
- if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
1944
- layer.host = env.ISSUE_FLOW_WEB_HOST;
1992
+ const codex = {};
1993
+ if (env.ISSUE_FLOW_CODEX_SANDBOX !== void 0) {
1994
+ if (env.ISSUE_FLOW_CODEX_SANDBOX === "read-only" || env.ISSUE_FLOW_CODEX_SANDBOX === "workspace-write" || env.ISSUE_FLOW_CODEX_SANDBOX === "danger-full-access") {
1995
+ codex.sandbox = env.ISSUE_FLOW_CODEX_SANDBOX;
1996
+ } else {
1997
+ warn(`Ignoring ISSUE_FLOW_CODEX_SANDBOX="${env.ISSUE_FLOW_CODEX_SANDBOX}".`);
1998
+ }
1945
1999
  }
1946
- const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
1947
- if (refresh !== void 0) {
1948
- layer.refreshSeconds = refresh;
2000
+ if (env.ISSUE_FLOW_CODEX_REASONING_EFFORT !== void 0) {
2001
+ const effort = env.ISSUE_FLOW_CODEX_REASONING_EFFORT;
2002
+ if (effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh") {
2003
+ codex.reasoningEffort = effort;
2004
+ } else {
2005
+ warn(`Ignoring ISSUE_FLOW_CODEX_REASONING_EFFORT="${effort}".`);
2006
+ }
1949
2007
  }
1950
- const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
1951
- if (logLimit !== void 0) {
1952
- layer.logLimit = logLimit;
2008
+ if (env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG !== void 0) {
2009
+ codex.ignoreUserConfig = parseBooleanEnv(env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG);
2010
+ }
2011
+ if (Object.keys(codex).length > 0) layer.codex = codex;
2012
+ const cursor = {};
2013
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX !== void 0) {
2014
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX === "enabled" || env.ISSUE_FLOW_CURSOR_SANDBOX === "disabled") {
2015
+ cursor.sandbox = env.ISSUE_FLOW_CURSOR_SANDBOX;
2016
+ } else {
2017
+ warn(`Ignoring ISSUE_FLOW_CURSOR_SANDBOX="${env.ISSUE_FLOW_CURSOR_SANDBOX}".`);
2018
+ }
1953
2019
  }
2020
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE !== void 0) {
2021
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "global" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "project" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "none") {
2022
+ cursor.permissionsFile = env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE;
2023
+ } else {
2024
+ warn(
2025
+ `Ignoring ISSUE_FLOW_CURSOR_PERMISSIONS_FILE="${env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE}".`
2026
+ );
2027
+ }
2028
+ }
2029
+ if (Object.keys(cursor).length > 0) layer.cursor = cursor;
2030
+ const antigravity = {};
2031
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EFFORT !== void 0) {
2032
+ const effort = env.ISSUE_FLOW_ANTIGRAVITY_EFFORT;
2033
+ if (effort === "low" || effort === "medium" || effort === "high") {
2034
+ antigravity.effort = effort;
2035
+ } else {
2036
+ warn(`Ignoring ISSUE_FLOW_ANTIGRAVITY_EFFORT="${effort}".`);
2037
+ }
2038
+ }
2039
+ if (env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX !== void 0) {
2040
+ antigravity.sandbox = parseBooleanEnv(env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX);
2041
+ }
2042
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT !== void 0) {
2043
+ antigravity.executeTimeout = env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT;
2044
+ }
2045
+ if (Object.keys(antigravity).length > 0) layer.antigravity = antigravity;
1954
2046
  return layer;
1955
2047
  }
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) {
2048
+ function readAgentKey(raw, label, warn) {
2049
+ if (raw === void 0) return {};
2050
+ const parsed = agentConfigInputSchema.safeParse(raw);
2051
+ if (!parsed.success) {
1964
2052
  warn(
1965
- `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2053
+ `Ignoring "agent" key of ${label}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
1966
2054
  );
1967
2055
  return {};
1968
2056
  }
1969
- return result.data;
2057
+ const phases = parsePhasesInput(
2058
+ raw !== null && typeof raw === "object" && "phases" in raw ? raw.phases : void 0,
2059
+ warn
2060
+ );
2061
+ return {
2062
+ ...parsed.data.provider !== void 0 ? { provider: parsed.data.provider } : {},
2063
+ ...parsed.data.model !== void 0 ? { model: parsed.data.model } : {},
2064
+ ...parsed.data.claude !== void 0 ? { claude: parsed.data.claude } : {},
2065
+ ...parsed.data.codex !== void 0 ? { codex: parsed.data.codex } : {},
2066
+ ...parsed.data.cursor !== void 0 ? { cursor: parsed.data.cursor } : {},
2067
+ ...parsed.data.antigravity !== void 0 ? { antigravity: parsed.data.antigravity } : {},
2068
+ ...Object.keys(phases).length > 0 ? { phases } : {}
2069
+ };
1970
2070
  }
1971
- async function loadWebConfig(options = {}) {
2071
+ function pickOrigin(layers) {
2072
+ let current = "default";
2073
+ for (const layer of layers) {
2074
+ if (layer.value !== void 0) current = layer.origin;
2075
+ }
2076
+ return current;
2077
+ }
2078
+ function mergeAgentBlockLayers(layers) {
2079
+ let merged = {};
2080
+ let any = false;
2081
+ for (const layer of layers) {
2082
+ if (layer.block === void 0) continue;
2083
+ any = true;
2084
+ merged = {
2085
+ ...merged,
2086
+ ...dropUndefinedBlock(layer.block),
2087
+ claude: { ...merged.claude, ...layer.block.claude },
2088
+ codex: { ...merged.codex, ...layer.block.codex },
2089
+ cursor: { ...merged.cursor, ...layer.block.cursor },
2090
+ antigravity: { ...merged.antigravity, ...layer.block.antigravity }
2091
+ };
2092
+ }
2093
+ return any ? merged : void 0;
2094
+ }
2095
+ function dropUndefinedBlock(block) {
2096
+ const result = {};
2097
+ if (block.provider !== void 0) result.provider = block.provider;
2098
+ if (block.model !== void 0) result.model = block.model;
2099
+ if (block.claude !== void 0) result.claude = block.claude;
2100
+ if (block.codex !== void 0) result.codex = block.codex;
2101
+ if (block.cursor !== void 0) result.cursor = block.cursor;
2102
+ if (block.antigravity !== void 0) result.antigravity = block.antigravity;
2103
+ return result;
2104
+ }
2105
+ async function loadAgentConfig(options = {}) {
2106
+ const canCache = options.cli === void 0 && options.env === void 0 && options.projectRoot === void 0 && options.globalRoot === void 0 && options.warn === void 0;
2107
+ if (canCache && cachedAgentConfig !== void 0) return cachedAgentConfig;
1972
2108
  const warn = options.warn ?? printWarning;
1973
- const cli = options.cli ?? webCliOverrides;
2109
+ const cli = options.cli ?? agentCliOverrides;
1974
2110
  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;
2111
+ const globalFile = await loadGlobalConfig({
2112
+ env,
2113
+ globalRoot: options.globalRoot,
2114
+ warn
2115
+ });
2116
+ const globalLayer = readAgentKey(globalFile.agent, GLOBAL_CONFIG_FILENAME, warn);
2117
+ const projectFile = await readProjectConfigFile(options.projectRoot, warn);
2118
+ const projectLayer = readAgentKey(projectFile?.agent, PROJECT_CONFIG_FILENAME, warn);
2119
+ const envLayer = readAgentEnv(env, warn);
2120
+ const provider = cli.forceProvider ?? cli.provider ?? envLayer.provider ?? projectLayer.provider ?? globalLayer.provider ?? "claude";
2121
+ const model = cli.forceModel ?? cli.model ?? envLayer.model ?? projectLayer.model ?? globalLayer.model ?? null;
2122
+ const claude = mergeConfigLayers({
2123
+ global: globalLayer.claude,
2124
+ project: projectLayer.claude,
2125
+ env: envLayer.claude,
2126
+ cli: cli.claude
2127
+ });
2128
+ const codex = mergeConfigLayers({
2129
+ global: globalLayer.codex,
2130
+ project: projectLayer.codex,
2131
+ env: envLayer.codex,
2132
+ cli: cli.codex
2133
+ });
2134
+ const cursor = mergeConfigLayers({
2135
+ global: globalLayer.cursor,
2136
+ project: projectLayer.cursor,
2137
+ env: envLayer.cursor,
2138
+ cli: cli.cursor
2139
+ });
2140
+ const antigravity = mergeConfigLayers({
2141
+ global: globalLayer.antigravity,
2142
+ project: projectLayer.antigravity,
2143
+ env: envLayer.antigravity,
2144
+ cli: cli.antigravity
2145
+ });
2146
+ const phases = {};
2147
+ const phaseOrigins = {};
2148
+ for (const phase of AGENT_PHASES) {
2149
+ const block = mergeAgentBlockLayers([
2150
+ { origin: "global", block: globalLayer.phases?.[phase] },
2151
+ { origin: "project", block: projectLayer.phases?.[phase] },
2152
+ { origin: "env", block: envLayer.phases?.[phase] },
2153
+ { origin: "cli", block: cli.phases?.[phase] }
2154
+ ]);
2155
+ if (block && Object.keys(block).length > 0) {
2156
+ phases[phase] = block;
2157
+ phaseOrigins[phase] = {
2158
+ provider: block.provider !== void 0 ? pickOrigin([
2159
+ { origin: "global", value: globalLayer.phases?.[phase]?.provider },
2160
+ { origin: "project", value: projectLayer.phases?.[phase]?.provider },
2161
+ { origin: "env", value: envLayer.phases?.[phase]?.provider },
2162
+ { origin: "cli", value: cli.phases?.[phase]?.provider }
2163
+ ]) : void 0,
2164
+ model: block.model !== void 0 ? pickOrigin([
2165
+ { origin: "global", value: globalLayer.phases?.[phase]?.model },
2166
+ { origin: "project", value: projectLayer.phases?.[phase]?.model },
2167
+ { origin: "env", value: envLayer.phases?.[phase]?.model },
2168
+ { origin: "cli", value: cli.phases?.[phase]?.model }
2169
+ ]) : void 0
2170
+ };
2171
+ }
1981
2172
  }
1982
- warn(
1983
- `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
1984
- );
1985
- return webConfigSchema.parse({});
2173
+ setTrackedOrigins({
2174
+ provider: pickOrigin([
2175
+ { origin: "default", value: "claude" },
2176
+ { origin: "global", value: globalLayer.provider },
2177
+ { origin: "project", value: projectLayer.provider },
2178
+ { origin: "env", value: envLayer.provider },
2179
+ { origin: "cli", value: cli.forceProvider ?? cli.provider }
2180
+ ]),
2181
+ model: pickOrigin([
2182
+ { origin: "default", value: void 0 },
2183
+ { origin: "global", value: globalLayer.model },
2184
+ { origin: "project", value: projectLayer.model },
2185
+ { origin: "env", value: envLayer.model },
2186
+ { origin: "cli", value: cli.forceModel ?? cli.model }
2187
+ ]),
2188
+ phases: phaseOrigins
2189
+ });
2190
+ const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2191
+ if (canCache) cachedAgentConfig = resolved;
2192
+ return resolved;
1986
2193
  }
1987
- var issuesCliOverrides = {};
1988
- function setIssuesCliOverrides(overrides) {
1989
- issuesCliOverrides = overrides;
2194
+
2195
+ // src/config/dependencies.ts
2196
+ function getInstallHint(pkg) {
2197
+ const os = platform();
2198
+ if (os === "darwin") {
2199
+ return `brew install ${pkg}`;
2200
+ }
2201
+ if (os === "linux") {
2202
+ return `apt install ${pkg} (or your distro's package manager)`;
2203
+ }
2204
+ if (os === "win32") {
2205
+ return `winget install ${pkg} (or choco install ${pkg})`;
2206
+ }
2207
+ return `install ${pkg} using your system package manager`;
1990
2208
  }
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 {};
2209
+ async function validateDependencies() {
2210
+ const errors = [];
2211
+ const gitResult = await run("git", ["--version"]);
2212
+ if (gitResult.exitCode !== 0) {
2213
+ errors.push(` - git (install with: ${getInstallHint("git")})`);
1996
2214
  }
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 {};
2215
+ const agent = await loadAgentConfig();
2216
+ const needed = /* @__PURE__ */ new Set([agent.provider]);
2217
+ for (const phase of AGENT_PHASES) {
2218
+ const provider = agent.phases[phase]?.provider;
2219
+ if (provider !== void 0) needed.add(provider);
2003
2220
  }
2004
- return result.data;
2221
+ for (const id of needed) {
2222
+ const { command, args } = runnerFor(id).versionCommand();
2223
+ const result = await run(command, args);
2224
+ if (result.exitCode !== 0) {
2225
+ errors.push(` - ${command} (${installHint(id)})`);
2226
+ }
2227
+ }
2228
+ return errors;
2005
2229
  }
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;
2230
+
2231
+ // src/config/engine.ts
2232
+ import { join as join3 } from "path";
2233
+ var DEFAULTS = {
2234
+ retryLimit: 10,
2235
+ retryForever: false,
2236
+ backoffBaseSeconds: 30,
2237
+ backoffMaxSeconds: 900
2238
+ };
2239
+ function createConfig(options) {
2240
+ return {
2241
+ issueNumber: options.issueNumber,
2242
+ maxIterations: options.maxIterations,
2243
+ retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,
2244
+ retryForever: options.retryForever ?? DEFAULTS.retryForever,
2245
+ backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,
2246
+ backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,
2247
+ // Left absent (rather than defaulted to an empty string) so the execute
2248
+ // prompt keeps its historical commit format unless a queue asks otherwise.
2249
+ ...options.commitScope === void 0 ? {} : { commitScope: options.commitScope },
2250
+ storiesPerIteration: options.storiesPerIteration ?? 1
2251
+ };
2252
+ }
2253
+ async function resolvePaths(config, scriptDir) {
2254
+ const projectRoot = await getProjectRoot();
2255
+ if (config.issueNumber) {
2256
+ const issuePaths = await resolveIssuePaths(config.issueNumber, { projectRoot });
2257
+ return {
2258
+ prdFile: issuePaths.tasksFile,
2259
+ progressFile: issuePaths.progressFile,
2260
+ archiveDir: issuePaths.archiveDir,
2261
+ lastBranchFile: issuePaths.lastBranchFile,
2262
+ projectRoot
2263
+ };
2014
2264
  }
2015
- warn(
2016
- `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2017
- );
2018
- return issuesConfigSchema.parse({});
2265
+ const base = scriptDir ?? projectRoot;
2266
+ const standalone = {
2267
+ prdFile: join3(base, "prd.json"),
2268
+ progressFile: join3(base, "progress.txt"),
2269
+ archiveDir: join3(base, "archive"),
2270
+ lastBranchFile: join3(base, ".last-branch"),
2271
+ projectRoot
2272
+ };
2273
+ const { bindTelemetry } = await import("./recorder-2BAKPBRA.js");
2274
+ bindTelemetry({ tasksPath: standalone.prdFile });
2275
+ return standalone;
2019
2276
  }
2020
- function readPrReviewConfigEnv(env) {
2021
- const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
2022
- return publisher === void 0 ? {} : { publisher };
2277
+
2278
+ // src/config/issues.ts
2279
+ var issuesCliOverrides = {};
2280
+ function setIssuesCliOverrides(overrides) {
2281
+ issuesCliOverrides = overrides;
2023
2282
  }
2024
- async function readPrReviewConfigFile(projectRoot, warn) {
2283
+ async function readIssuesConfigFile(projectRoot, warn) {
2025
2284
  const file = await readProjectConfigFile(projectRoot, warn);
2026
- const prReview = file?.prReview;
2027
- if (prReview === void 0) {
2285
+ const issues = file?.issues;
2286
+ if (issues === void 0) {
2028
2287
  return {};
2029
2288
  }
2030
- const result = prReviewConfigSchema.partial().safeParse(prReview);
2289
+ const result = issuesConfigSchema.partial().safeParse(issues);
2031
2290
  if (!result.success) {
2032
2291
  warn(
2033
- `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2292
+ `Ignoring "issues" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2034
2293
  );
2035
2294
  return {};
2036
2295
  }
2037
2296
  return result.data;
2038
2297
  }
2039
- async function loadPrReviewConfig(options = {}) {
2298
+ async function loadIssuesConfig(options = {}) {
2040
2299
  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);
2300
+ const cli = options.cli ?? issuesCliOverrides;
2301
+ const fileLayer = await readIssuesConfigFile(options.projectRoot, warn);
2302
+ const merged = { ...fileLayer, ...cli };
2303
+ const result = issuesConfigSchema.safeParse(merged);
2046
2304
  if (result.success) {
2047
2305
  return result.data;
2048
2306
  }
2049
2307
  warn(
2050
- `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2308
+ `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2051
2309
  );
2052
- return prReviewConfigSchema.parse({});
2310
+ return issuesConfigSchema.parse({});
2053
2311
  }
2312
+
2313
+ // src/config/policy.ts
2054
2314
  var policyCliOverrides = {};
2055
2315
  function setPolicyCliOverrides(overrides) {
2056
2316
  policyCliOverrides = overrides;
2057
2317
  }
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
2318
  function readPolicyConfigEnv(env, warn) {
2068
2319
  const layer = {};
2069
2320
  if (env.ISSUE_FLOW_POLICY !== void 0) {
@@ -2159,77 +2410,44 @@ async function loadPolicyConfig(options = {}) {
2159
2410
  );
2160
2411
  return policyConfigSchema.parse({});
2161
2412
  }
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 {};
2413
+
2414
+ // src/config/pr-review.ts
2415
+ function readPrReviewConfigEnv(env) {
2416
+ const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
2417
+ return publisher === void 0 ? {} : { publisher };
2170
2418
  }
2171
- function readTelemetryEnv(env, warn) {
2172
- const layer = {};
2173
- if (env.ISSUE_FLOW_TELEMETRY !== void 0) {
2174
- layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY);
2419
+ async function readPrReviewConfigFile(projectRoot, warn) {
2420
+ const file = await readProjectConfigFile(projectRoot, warn);
2421
+ const prReview = file?.prReview;
2422
+ if (prReview === void 0) {
2423
+ return {};
2175
2424
  }
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) };
2425
+ const result = prReviewConfigSchema.partial().safeParse(prReview);
2426
+ if (!result.success) {
2427
+ warn(
2428
+ `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2429
+ );
2430
+ return {};
2180
2431
  }
2181
- return layer;
2432
+ return result.data;
2182
2433
  }
2183
- async function loadTelemetryConfig(options = {}) {
2434
+ async function loadPrReviewConfig(options = {}) {
2184
2435
  const warn = options.warn ?? printWarning;
2185
2436
  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
- };
2437
+ const fileLayer = await readPrReviewConfigFile(options.projectRoot, warn);
2438
+ const envLayer = readPrReviewConfigEnv(env);
2439
+ const merged = { ...fileLayer, ...envLayer, ...options.cli ?? {} };
2440
+ const result = prReviewConfigSchema.safeParse(merged);
2441
+ if (result.success) {
2442
+ return result.data;
2443
+ }
2444
+ warn(
2445
+ `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2446
+ );
2447
+ return prReviewConfigSchema.parse({});
2232
2448
  }
2449
+
2450
+ // src/config/resilience.ts
2233
2451
  var resilienceCliOverrides = {};
2234
2452
  function setResilienceCliOverrides(overrides) {
2235
2453
  resilienceCliOverrides = overrides;
@@ -2398,231 +2616,125 @@ async function initResilienceConfig(options = {}) {
2398
2616
  }
2399
2617
  return activeResilienceConfig;
2400
2618
  }
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;
2619
+
2620
+ // src/config/routing.ts
2621
+ var routingCliOverrides = {};
2622
+ function setRoutingCliOverrides(overrides) {
2623
+ routingCliOverrides = overrides;
2479
2624
  }
2480
- function readAgentKey(raw, label, warn) {
2481
- if (raw === void 0) return {};
2482
- const parsed = agentConfigInputSchema.safeParse(raw);
2483
- if (!parsed.success) {
2625
+ async function loadRoutingConfig(options = {}) {
2626
+ const warn = options.warn ?? printWarning;
2627
+ const global = options.global ?? (await loadGlobalConfig({
2628
+ env: options.env ?? process.env,
2629
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2630
+ warn
2631
+ })).routing;
2632
+ const file = await readProjectConfigFile(options.projectRoot, warn);
2633
+ const raw = file?.routing;
2634
+ const parsedResult = routingConfigInputSchema.safeParse(raw ?? {});
2635
+ if (!parsedResult.success) {
2484
2636
  warn(
2485
- `Ignoring "agent" key of ${label}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
2637
+ `Ignoring "routing" key of ${PROJECT_CONFIG_FILENAME}: ${parsedResult.error.issues[0]?.message ?? "invalid value"}.`
2486
2638
  );
2487
- return {};
2488
2639
  }
2489
- const phases = parsePhasesInput(
2490
- raw !== null && typeof raw === "object" && "phases" in raw ? raw.phases : void 0,
2491
- warn
2640
+ const project = parsedResult.success ? parsedResult.data : {};
2641
+ const cli = options.cli ?? routingCliOverrides;
2642
+ const result = routingConfigSchema.safeParse({
2643
+ ...global,
2644
+ ...project,
2645
+ ...cli,
2646
+ escalation: {
2647
+ ...global?.escalation,
2648
+ ...project.escalation,
2649
+ ...cli.escalation
2650
+ },
2651
+ ceilings: {
2652
+ ...global?.ceilings,
2653
+ ...project.ceilings,
2654
+ ...cli.ceilings
2655
+ }
2656
+ });
2657
+ if (result.success) return result.data;
2658
+ warn(
2659
+ `Invalid routing configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2492
2660
  );
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
- };
2661
+ return routingConfigSchema.parse({});
2502
2662
  }
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;
2663
+
2664
+ // src/config/telemetry.ts
2665
+ function parseTelemetryLayer(value, source, warn) {
2666
+ if (value === void 0) return {};
2667
+ const result = telemetryConfigInputSchema.safeParse(value);
2668
+ if (result.success) return result.data;
2669
+ warn(
2670
+ `Ignoring "telemetry" key of ${source}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2671
+ );
2672
+ return {};
2509
2673
  }
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
- };
2674
+ function readTelemetryEnv(env, warn) {
2675
+ const layer = {};
2676
+ if (env.ISSUE_FLOW_TELEMETRY !== void 0) {
2677
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY);
2524
2678
  }
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;
2679
+ const max = readNumberEnv(env, "ISSUE_FLOW_TELEMETRY_MAX_EXECUTIONS", warn);
2680
+ if (max !== void 0) layer.maxExecutions = max;
2681
+ if (env.ISSUE_FLOW_TELEMETRY_ESTIMATE !== void 0) {
2682
+ layer.pricing = { estimate: parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY_ESTIMATE) };
2683
+ }
2684
+ return layer;
2536
2685
  }
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;
2686
+ async function loadTelemetryConfig(options = {}) {
2540
2687
  const warn = options.warn ?? printWarning;
2541
- const cli = options.cli ?? agentCliOverrides;
2542
2688
  const env = options.env ?? process.env;
2543
- const globalFile = await loadGlobalConfig({
2689
+ const globalFile = options.global ?? (await loadGlobalConfig({
2544
2690
  env,
2545
- globalRoot: options.globalRoot,
2691
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2546
2692
  warn
2547
- });
2548
- const globalLayer = readAgentKey(globalFile.agent, GLOBAL_CONFIG_FILENAME, warn);
2693
+ })).telemetry;
2549
2694
  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
2695
+ const project = parseTelemetryLayer(projectFile?.telemetry, PROJECT_CONFIG_FILENAME, warn);
2696
+ const envLayer = readTelemetryEnv(env, warn);
2697
+ const pricing = mergeConfigLayers({
2698
+ defaults: DEFAULT_TELEMETRY_CONFIG.pricing,
2699
+ global: globalFile?.pricing,
2700
+ project: project.pricing,
2701
+ env: envLayer.pricing
2577
2702
  });
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
- };
2703
+ const overrides = {
2704
+ ...DEFAULT_TELEMETRY_CONFIG.pricing.overrides,
2705
+ ...globalFile?.pricing?.overrides,
2706
+ ...project.pricing?.overrides,
2707
+ ...envLayer.pricing?.overrides
2708
+ };
2709
+ const scalars = mergeConfigLayers({
2710
+ defaults: {
2711
+ enabled: DEFAULT_TELEMETRY_CONFIG.enabled,
2712
+ maxExecutions: DEFAULT_TELEMETRY_CONFIG.maxExecutions
2713
+ },
2714
+ global: {
2715
+ ...globalFile?.enabled === void 0 ? {} : { enabled: globalFile.enabled },
2716
+ ...globalFile?.maxExecutions === void 0 ? {} : { maxExecutions: globalFile.maxExecutions }
2717
+ },
2718
+ project: {
2719
+ ...project.enabled === void 0 ? {} : { enabled: project.enabled },
2720
+ ...project.maxExecutions === void 0 ? {} : { maxExecutions: project.maxExecutions }
2721
+ },
2722
+ env: {
2723
+ ...envLayer.enabled === void 0 ? {} : { enabled: envLayer.enabled },
2724
+ ...envLayer.maxExecutions === void 0 ? {} : { maxExecutions: envLayer.maxExecutions }
2603
2725
  }
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
2726
  });
2622
- const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2623
- if (canCache) cachedAgentConfig = resolved;
2624
- return resolved;
2727
+ return {
2728
+ enabled: scalars.enabled ?? DEFAULT_TELEMETRY_CONFIG.enabled,
2729
+ maxExecutions: scalars.maxExecutions ?? DEFAULT_TELEMETRY_CONFIG.maxExecutions,
2730
+ pricing: {
2731
+ estimate: pricing.estimate ?? DEFAULT_TELEMETRY_CONFIG.pricing.estimate,
2732
+ overrides
2733
+ }
2734
+ };
2625
2735
  }
2736
+
2737
+ // src/config/verify.ts
2626
2738
  var verifyCliOverrides = {};
2627
2739
  function setVerifyCliOverrides(overrides) {
2628
2740
  verifyCliOverrides = overrides;
@@ -2652,23 +2764,73 @@ async function loadVerifyConfig(options = {}) {
2652
2764
  );
2653
2765
  return verifyConfigSchema.parse({});
2654
2766
  }
2655
- var routingCliOverrides = {};
2656
- function setRoutingCliOverrides(overrides) {
2657
- routingCliOverrides = overrides;
2767
+
2768
+ // src/config/web.ts
2769
+ var webCliOverrides = {};
2770
+ function setWebCliOverrides(overrides) {
2771
+ webCliOverrides = overrides;
2658
2772
  }
2659
- async function loadRoutingConfig(options = {}) {
2773
+ function readWebConfigEnv(env, warn) {
2774
+ const layer = {};
2775
+ if (env.ISSUE_FLOW_WEB !== void 0) {
2776
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
2777
+ }
2778
+ const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
2779
+ if (port !== void 0) {
2780
+ layer.port = port;
2781
+ }
2782
+ if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
2783
+ layer.host = env.ISSUE_FLOW_WEB_HOST;
2784
+ }
2785
+ const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
2786
+ if (refresh !== void 0) {
2787
+ layer.refreshSeconds = refresh;
2788
+ }
2789
+ const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
2790
+ if (logLimit !== void 0) {
2791
+ layer.logLimit = logLimit;
2792
+ }
2793
+ return layer;
2794
+ }
2795
+ async function readWebConfigFile(projectRoot, warn) {
2796
+ const file = await readProjectConfigFile(projectRoot, warn);
2797
+ const web = file?.web;
2798
+ if (web === void 0) {
2799
+ return {};
2800
+ }
2801
+ const result = webConfigSchema.partial().safeParse(web);
2802
+ if (!result.success) {
2803
+ warn(
2804
+ `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2805
+ );
2806
+ return {};
2807
+ }
2808
+ return result.data;
2809
+ }
2810
+ async function loadWebConfig(options = {}) {
2660
2811
  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({});
2812
+ const cli = options.cli ?? webCliOverrides;
2813
+ const env = options.env ?? process.env;
2814
+ const fileLayer = await readWebConfigFile(options.projectRoot, warn);
2815
+ const envLayer = readWebConfigEnv(env, warn);
2816
+ const merged = { ...fileLayer, ...envLayer, ...cli };
2817
+ const result = webConfigSchema.safeParse(merged);
2818
+ if (result.success) {
2819
+ return result.data;
2820
+ }
2821
+ warn(
2822
+ `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2823
+ );
2824
+ return webConfigSchema.parse({});
2669
2825
  }
2670
2826
 
2827
+ // src/config.ts
2828
+ var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
2829
+
2671
2830
  export {
2831
+ PROJECT_CONFIG_FILENAME,
2832
+ GLOBAL_CONFIG_FILENAME,
2833
+ loadGlobalConfig,
2672
2834
  getShutdownSignal,
2673
2835
  onShutdown,
2674
2836
  installShutdownHandlers,
@@ -2680,39 +2842,37 @@ export {
2680
2842
  runnerFor,
2681
2843
  ensureHarnessVersion,
2682
2844
  probeAgent,
2845
+ probeReadinessInventory,
2846
+ mergeConfigLayers,
2847
+ setAgentCliOverrides,
2848
+ getAgentCliOverrides,
2849
+ loadAgentConfig,
2850
+ getInstallHint,
2851
+ validateDependencies,
2683
2852
  DEFAULTS,
2684
2853
  createConfig,
2685
2854
  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
2855
  setIssuesCliOverrides,
2696
2856
  loadIssuesConfig,
2697
- loadPrReviewConfig,
2698
2857
  setPolicyCliOverrides,
2699
2858
  loadPolicyConfig,
2700
- loadTelemetryConfig,
2859
+ loadPrReviewConfig,
2701
2860
  setResilienceCliOverrides,
2702
2861
  loadResilienceConfig,
2703
2862
  getActiveResilienceConfig,
2704
2863
  setActiveResilienceConfig,
2705
2864
  initResilienceConfig,
2706
- setAgentCliOverrides,
2707
- getAgentCliOverrides,
2708
- loadAgentConfig,
2709
- setVerifyCliOverrides,
2710
- loadVerifyConfig,
2711
2865
  setRoutingCliOverrides,
2712
2866
  loadRoutingConfig,
2867
+ loadTelemetryConfig,
2868
+ setVerifyCliOverrides,
2869
+ loadVerifyConfig,
2870
+ setWebCliOverrides,
2871
+ loadWebConfig,
2872
+ WEB_CONFIG_FILENAME,
2713
2873
  resolveAgentFor,
2714
2874
  parseAgentPhaseFlag,
2715
2875
  describeRunAgents,
2716
2876
  hasExplicitAgentSelection
2717
2877
  };
2718
- //# sourceMappingURL=chunk-J2LJB2OH.js.map
2878
+ //# sourceMappingURL=chunk-QF7VEL3M.js.map