issue-flow 0.15.0 → 0.17.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 (169) hide show
  1. package/dist/agent-TB6W7PT7.js +30 -0
  2. package/dist/{analyze-O2PYDIFK.js → analyze-6M3KEOX7.js} +22 -22
  3. package/dist/{apply-SSU6QCD4.js → apply-ADB3ZK7W.js} +14 -14
  4. package/dist/{bench-ODFPAGW6.js → bench-FM7I7EIV.js} +23 -23
  5. package/dist/{chunk-BMHGRYL6.js → chunk-2SUFAE6X.js} +67 -24
  6. package/dist/chunk-2SUFAE6X.js.map +1 -0
  7. package/dist/{chunk-QRCGW2ZO.js → chunk-32JSYXEK.js} +8 -8
  8. package/dist/chunk-3R27MJ5R.js +25 -0
  9. package/dist/chunk-3R27MJ5R.js.map +1 -0
  10. package/dist/{chunk-MGCOQU6N.js → chunk-6YQT3SSM.js} +4 -4
  11. package/dist/chunk-6YQT3SSM.js.map +1 -0
  12. package/dist/{chunk-A35HE4V7.js → chunk-7F7LGMVO.js} +3 -3
  13. package/dist/{chunk-RPXDBX6R.js → chunk-A4H7P7T7.js} +102 -102
  14. package/dist/chunk-A4H7P7T7.js.map +1 -0
  15. package/dist/{chunk-2ZAM45PZ.js → chunk-ANI2NTR4.js} +9 -9
  16. package/dist/{chunk-ZPIVCM7Q.js → chunk-B3TSS7BT.js} +3 -3
  17. package/dist/chunk-C5TL7T4V.js +27 -0
  18. package/dist/chunk-C5TL7T4V.js.map +1 -0
  19. package/dist/chunk-D6ZBGJ3L.js +321 -0
  20. package/dist/chunk-D6ZBGJ3L.js.map +1 -0
  21. package/dist/{chunk-ZXPASFHG.js → chunk-DGRTJD5R.js} +3 -3
  22. package/dist/{chunk-6QYMSNVA.js → chunk-DUS5ZNKL.js} +476 -362
  23. package/dist/chunk-DUS5ZNKL.js.map +1 -0
  24. package/dist/{chunk-VR34TXHF.js → chunk-DV7HUC4Z.js} +7 -7
  25. package/dist/{chunk-6SRE4KD7.js → chunk-E6KXCV3T.js} +4 -4
  26. package/dist/{chunk-HGSYD57B.js → chunk-HJBF4WD2.js} +1656 -1070
  27. package/dist/chunk-HJBF4WD2.js.map +1 -0
  28. package/dist/{chunk-PCN7ZQND.js → chunk-HLAPOUEM.js} +8 -8
  29. package/dist/{chunk-WM3Y7Q4A.js → chunk-HY5HLFDU.js} +630 -571
  30. package/dist/chunk-HY5HLFDU.js.map +1 -0
  31. package/dist/{chunk-XDKGA6UX.js → chunk-ICM463EO.js} +64 -14
  32. package/dist/chunk-ICM463EO.js.map +1 -0
  33. package/dist/{chunk-MEFY4B7T.js → chunk-ISZ54SVE.js} +9 -9
  34. package/dist/{chunk-ARWNYXFL.js → chunk-KZ5EY5XX.js} +12 -12
  35. package/dist/{chunk-ZFIXEYUJ.js → chunk-KZXQWC7U.js} +32 -20
  36. package/dist/chunk-KZXQWC7U.js.map +1 -0
  37. package/dist/{chunk-KAHQ6F5C.js → chunk-LPWPFIIB.js} +11 -11
  38. package/dist/{chunk-FK4IDY6P.js → chunk-MI5TREN3.js} +9 -9
  39. package/dist/{chunk-UNQYMR3H.js → chunk-PPZ3K4YM.js} +2 -2
  40. package/dist/{chunk-F4OK7KEP.js → chunk-QMIQR7EE.js} +10 -10
  41. package/dist/{chunk-AYYMW33T.js → chunk-QPGEFLMY.js} +2 -2
  42. package/dist/chunk-RCZJQUTC.js +196 -0
  43. package/dist/chunk-RCZJQUTC.js.map +1 -0
  44. package/dist/{chunk-MROS3SKL.js → chunk-RNFUVKC3.js} +3 -3
  45. package/dist/{chunk-RWEXK55D.js → chunk-RYOUZ6EK.js} +2 -2
  46. package/dist/{chunk-6E2PEBFT.js → chunk-SGTTR4XW.js} +10 -10
  47. package/dist/{chunk-XQHFC62U.js → chunk-SOM4QA6C.js} +3 -3
  48. package/dist/{chunk-5ZKBIXET.js → chunk-UK4E2FUA.js} +132 -34
  49. package/dist/chunk-UK4E2FUA.js.map +1 -0
  50. package/dist/{chunk-6FXOU2KR.js → chunk-UWDCIFTP.js} +7 -7
  51. package/dist/{chunk-XG2NYDRA.js → chunk-VE3IYNDN.js} +3 -3
  52. package/dist/{chunk-3BWZO4YI.js → chunk-WCCZJL7W.js} +2 -2
  53. package/dist/{chunk-NVZMBXTE.js → chunk-XZUEFTUP.js} +6 -6
  54. package/dist/{chunk-TBDP6QPJ.js → chunk-YII4U7ZD.js} +10 -10
  55. package/dist/{chunk-TBDP6QPJ.js.map → chunk-YII4U7ZD.js.map} +1 -1
  56. package/dist/{chunk-4RXYFWP7.js → chunk-YUNBOUQH.js} +6 -6
  57. package/dist/{chunk-GSZCQUCY.js → chunk-YVPZUN6X.js} +2 -2
  58. package/dist/{chunk-XRLRKTQA.js → chunk-Z5O2XBWA.js} +14 -14
  59. package/dist/cli.js +61 -52
  60. package/dist/cli.js.map +1 -1
  61. package/dist/{config-UMP6DBJB.js → config-KGZUPAUP.js} +13 -13
  62. package/dist/{conventions-DKH7AE4T.js → conventions-RYN7OXJN.js} +15 -15
  63. package/dist/{diagnostics-GOGCLTRS.js → diagnostics-HTCWF7F4.js} +7 -7
  64. package/dist/execute-QL3ZQIAP.js +37 -0
  65. package/dist/{generate-AGBT7EHX.js → generate-CX6KNHZS.js} +22 -22
  66. package/dist/{git-AC542GU2.js → git-A2IP32PQ.js} +2 -2
  67. package/dist/init-PDVQDRS6.js +24 -0
  68. package/dist/{operations-JQYK2EMT.js → operations-CAKIT2BO.js} +15 -15
  69. package/dist/{permissions-6HL52K54.js → permissions-G4XCAESF.js} +4 -4
  70. package/dist/plan-PRORGS3L.js +34 -0
  71. package/dist/{policy-IMRXGG7X.js → policy-WX6O2JID.js} +14 -14
  72. package/dist/pr-27RMQI5F.js +39 -0
  73. package/dist/pr-review-VNESMAMT.js +32 -0
  74. package/dist/prd-ZNC4T5BS.js +33 -0
  75. package/dist/{ps-KUUZ6TUL.js → ps-76L6ZAZL.js} +12 -12
  76. package/dist/{recorder-BJ2KIAWT.js → recorder-N7U66HCO.js} +7 -7
  77. package/dist/{registry-SB7XTMGE.js → registry-XLHHYLTR.js} +5 -5
  78. package/dist/{resume-QNLQSCR5.js → resume-VLWIE264.js} +40 -38
  79. package/dist/{resume-QNLQSCR5.js.map → resume-VLWIE264.js.map} +1 -1
  80. package/dist/review-7CREJDKB.js +35 -0
  81. package/dist/routing-VCDYHSXA.js +33 -0
  82. package/dist/run-3MPORLF5.js +56 -0
  83. package/dist/{session-publisher-T7EI3CIP.js → session-publisher-KAJQRHNZ.js} +3 -2
  84. package/dist/{state-manager-ZEPWTCA6.js → state-manager-UPHO2EA2.js} +4 -4
  85. package/dist/state-manager-UPHO2EA2.js.map +1 -0
  86. package/dist/{usage-QL563I7F.js → usage-U7QNGCPK.js} +12 -12
  87. package/dist/{web-PPSMNTQ6.js → web-HUNDHCJ4.js} +21 -18
  88. package/dist/{web-PPSMNTQ6.js.map → web-HUNDHCJ4.js.map} +1 -1
  89. package/package.json +6 -5
  90. package/web/AGENTS.md +15 -11
  91. package/web/public/app.css +51 -0
  92. package/web/public/app.js +325 -56
  93. package/web/public/index.html +6 -2
  94. package/dist/agent-AT64RXTA.js +0 -30
  95. package/dist/chunk-5ZKBIXET.js.map +0 -1
  96. package/dist/chunk-6QYMSNVA.js.map +0 -1
  97. package/dist/chunk-7Z4Y3VKM.js +0 -26
  98. package/dist/chunk-7Z4Y3VKM.js.map +0 -1
  99. package/dist/chunk-BMHGRYL6.js.map +0 -1
  100. package/dist/chunk-HGSYD57B.js.map +0 -1
  101. package/dist/chunk-MGCOQU6N.js.map +0 -1
  102. package/dist/chunk-RPXDBX6R.js.map +0 -1
  103. package/dist/chunk-WM3Y7Q4A.js.map +0 -1
  104. package/dist/chunk-XDKGA6UX.js.map +0 -1
  105. package/dist/chunk-XLVGPXNL.js +0 -180
  106. package/dist/chunk-XLVGPXNL.js.map +0 -1
  107. package/dist/chunk-ZFIXEYUJ.js.map +0 -1
  108. package/dist/execute-E3BRMDAQ.js +0 -35
  109. package/dist/init-LLBVJNPE.js +0 -24
  110. package/dist/plan-HSLWDJEZ.js +0 -34
  111. package/dist/pr-6TCZXG6K.js +0 -39
  112. package/dist/pr-review-6MWJO2NP.js +0 -32
  113. package/dist/prd-D6YDYAFX.js +0 -33
  114. package/dist/review-3KJ4BH2V.js +0 -35
  115. package/dist/routing-TN7GLMGU.js +0 -94
  116. package/dist/routing-TN7GLMGU.js.map +0 -1
  117. package/dist/run-5EHIFF2V.js +0 -54
  118. /package/dist/{agent-AT64RXTA.js.map → agent-TB6W7PT7.js.map} +0 -0
  119. /package/dist/{analyze-O2PYDIFK.js.map → analyze-6M3KEOX7.js.map} +0 -0
  120. /package/dist/{apply-SSU6QCD4.js.map → apply-ADB3ZK7W.js.map} +0 -0
  121. /package/dist/{bench-ODFPAGW6.js.map → bench-FM7I7EIV.js.map} +0 -0
  122. /package/dist/{chunk-QRCGW2ZO.js.map → chunk-32JSYXEK.js.map} +0 -0
  123. /package/dist/{chunk-A35HE4V7.js.map → chunk-7F7LGMVO.js.map} +0 -0
  124. /package/dist/{chunk-2ZAM45PZ.js.map → chunk-ANI2NTR4.js.map} +0 -0
  125. /package/dist/{chunk-ZPIVCM7Q.js.map → chunk-B3TSS7BT.js.map} +0 -0
  126. /package/dist/{chunk-ZXPASFHG.js.map → chunk-DGRTJD5R.js.map} +0 -0
  127. /package/dist/{chunk-VR34TXHF.js.map → chunk-DV7HUC4Z.js.map} +0 -0
  128. /package/dist/{chunk-6SRE4KD7.js.map → chunk-E6KXCV3T.js.map} +0 -0
  129. /package/dist/{chunk-PCN7ZQND.js.map → chunk-HLAPOUEM.js.map} +0 -0
  130. /package/dist/{chunk-MEFY4B7T.js.map → chunk-ISZ54SVE.js.map} +0 -0
  131. /package/dist/{chunk-ARWNYXFL.js.map → chunk-KZ5EY5XX.js.map} +0 -0
  132. /package/dist/{chunk-KAHQ6F5C.js.map → chunk-LPWPFIIB.js.map} +0 -0
  133. /package/dist/{chunk-FK4IDY6P.js.map → chunk-MI5TREN3.js.map} +0 -0
  134. /package/dist/{chunk-UNQYMR3H.js.map → chunk-PPZ3K4YM.js.map} +0 -0
  135. /package/dist/{chunk-F4OK7KEP.js.map → chunk-QMIQR7EE.js.map} +0 -0
  136. /package/dist/{chunk-AYYMW33T.js.map → chunk-QPGEFLMY.js.map} +0 -0
  137. /package/dist/{chunk-MROS3SKL.js.map → chunk-RNFUVKC3.js.map} +0 -0
  138. /package/dist/{chunk-RWEXK55D.js.map → chunk-RYOUZ6EK.js.map} +0 -0
  139. /package/dist/{chunk-6E2PEBFT.js.map → chunk-SGTTR4XW.js.map} +0 -0
  140. /package/dist/{chunk-XQHFC62U.js.map → chunk-SOM4QA6C.js.map} +0 -0
  141. /package/dist/{chunk-6FXOU2KR.js.map → chunk-UWDCIFTP.js.map} +0 -0
  142. /package/dist/{chunk-XG2NYDRA.js.map → chunk-VE3IYNDN.js.map} +0 -0
  143. /package/dist/{chunk-3BWZO4YI.js.map → chunk-WCCZJL7W.js.map} +0 -0
  144. /package/dist/{chunk-NVZMBXTE.js.map → chunk-XZUEFTUP.js.map} +0 -0
  145. /package/dist/{chunk-4RXYFWP7.js.map → chunk-YUNBOUQH.js.map} +0 -0
  146. /package/dist/{chunk-GSZCQUCY.js.map → chunk-YVPZUN6X.js.map} +0 -0
  147. /package/dist/{chunk-XRLRKTQA.js.map → chunk-Z5O2XBWA.js.map} +0 -0
  148. /package/dist/{config-UMP6DBJB.js.map → config-KGZUPAUP.js.map} +0 -0
  149. /package/dist/{conventions-DKH7AE4T.js.map → conventions-RYN7OXJN.js.map} +0 -0
  150. /package/dist/{diagnostics-GOGCLTRS.js.map → diagnostics-HTCWF7F4.js.map} +0 -0
  151. /package/dist/{execute-E3BRMDAQ.js.map → execute-QL3ZQIAP.js.map} +0 -0
  152. /package/dist/{generate-AGBT7EHX.js.map → generate-CX6KNHZS.js.map} +0 -0
  153. /package/dist/{git-AC542GU2.js.map → git-A2IP32PQ.js.map} +0 -0
  154. /package/dist/{init-LLBVJNPE.js.map → init-PDVQDRS6.js.map} +0 -0
  155. /package/dist/{operations-JQYK2EMT.js.map → operations-CAKIT2BO.js.map} +0 -0
  156. /package/dist/{permissions-6HL52K54.js.map → permissions-G4XCAESF.js.map} +0 -0
  157. /package/dist/{plan-HSLWDJEZ.js.map → plan-PRORGS3L.js.map} +0 -0
  158. /package/dist/{policy-IMRXGG7X.js.map → policy-WX6O2JID.js.map} +0 -0
  159. /package/dist/{pr-6TCZXG6K.js.map → pr-27RMQI5F.js.map} +0 -0
  160. /package/dist/{pr-review-6MWJO2NP.js.map → pr-review-VNESMAMT.js.map} +0 -0
  161. /package/dist/{prd-D6YDYAFX.js.map → prd-ZNC4T5BS.js.map} +0 -0
  162. /package/dist/{ps-KUUZ6TUL.js.map → ps-76L6ZAZL.js.map} +0 -0
  163. /package/dist/{recorder-BJ2KIAWT.js.map → recorder-N7U66HCO.js.map} +0 -0
  164. /package/dist/{registry-SB7XTMGE.js.map → registry-XLHHYLTR.js.map} +0 -0
  165. /package/dist/{review-3KJ4BH2V.js.map → review-7CREJDKB.js.map} +0 -0
  166. /package/dist/{run-5EHIFF2V.js.map → routing-VCDYHSXA.js.map} +0 -0
  167. /package/dist/{session-publisher-T7EI3CIP.js.map → run-3MPORLF5.js.map} +0 -0
  168. /package/dist/{state-manager-ZEPWTCA6.js.map → session-publisher-KAJQRHNZ.js.map} +0 -0
  169. /package/dist/{usage-QL563I7F.js.map → usage-U7QNGCPK.js.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveIssuePaths
4
- } from "./chunk-VR34TXHF.js";
4
+ } from "./chunk-DV7HUC4Z.js";
5
5
  import {
6
6
  formatDuration,
7
7
  printWarning
8
- } from "./chunk-NVZMBXTE.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-GSZCQUCY.js";
16
+ } from "./chunk-YVPZUN6X.js";
17
17
  import {
18
18
  DEFAULT_TELEMETRY_CONFIG
19
- } from "./chunk-TBDP6QPJ.js";
19
+ } from "./chunk-YII4U7ZD.js";
20
20
  import {
21
21
  parseCodexUsage,
22
22
  parseUsage
23
- } from "./chunk-XQHFC62U.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-XDKGA6UX.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-UMP6DBJB.js");
1634
+ const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-KGZUPAUP.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-UMP6DBJB.js");
1740
+ const { loadAgentConfig: loadAgentConfig2 } = await import("./config-KGZUPAUP.js");
1657
1741
  const config = await loadAgentConfig2();
1658
1742
  defaultProvider = config.provider;
1659
1743
  defaultModel = config.model;
@@ -1669,12 +1753,16 @@ 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;
@@ -1732,167 +1820,7 @@ function installHint(id) {
1732
1820
  return "Install Claude Code: https://docs.anthropic.com/en/docs/claude-code";
1733
1821
  }
1734
1822
 
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-BJ2KIAWT.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
- }
1823
+ // src/config/layers.ts
1896
1824
  function mergeConfigLayers(layers) {
1897
1825
  const merged = {};
1898
1826
  for (const layer of [
@@ -1911,9 +1839,14 @@ function mergeConfigLayers(layers) {
1911
1839
  }
1912
1840
  return merged;
1913
1841
  }
1914
- var webCliOverrides = {};
1915
- function setWebCliOverrides(overrides) {
1916
- webCliOverrides = overrides;
1842
+ function dropNullish(layer) {
1843
+ const result = {};
1844
+ for (const [key, value] of Object.entries(layer ?? {})) {
1845
+ if (value !== void 0 && value !== null) {
1846
+ result[key] = value;
1847
+ }
1848
+ }
1849
+ return result;
1917
1850
  }
1918
1851
  var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
1919
1852
  function parseBooleanEnv(value) {
@@ -1931,139 +1864,357 @@ function readNumberEnv(env, name, warn) {
1931
1864
  }
1932
1865
  return parsed;
1933
1866
  }
1934
- function readWebConfigEnv(env, warn) {
1867
+
1868
+ // src/config/agent.ts
1869
+ var agentCliOverrides = {};
1870
+ var cachedAgentConfig;
1871
+ function setAgentCliOverrides(overrides) {
1872
+ agentCliOverrides = overrides;
1873
+ cachedAgentConfig = void 0;
1874
+ }
1875
+ function getAgentCliOverrides() {
1876
+ return agentCliOverrides;
1877
+ }
1878
+ function readAgentEnv(env, warn) {
1935
1879
  const layer = {};
1936
- if (env.ISSUE_FLOW_WEB !== void 0) {
1937
- layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
1880
+ if (env.ISSUE_FLOW_AGENT !== void 0) {
1881
+ if (isAgentProviderId(env.ISSUE_FLOW_AGENT)) {
1882
+ layer.provider = env.ISSUE_FLOW_AGENT;
1883
+ } else {
1884
+ warn(
1885
+ `Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor or antigravity.`
1886
+ );
1887
+ }
1938
1888
  }
1939
- const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
1940
- if (port !== void 0) {
1941
- layer.port = port;
1889
+ if (env.ISSUE_FLOW_AGENT_MODEL !== void 0 && env.ISSUE_FLOW_AGENT_MODEL !== "") {
1890
+ layer.model = env.ISSUE_FLOW_AGENT_MODEL;
1942
1891
  }
1943
- if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
1944
- layer.host = env.ISSUE_FLOW_WEB_HOST;
1892
+ const codex = {};
1893
+ if (env.ISSUE_FLOW_CODEX_SANDBOX !== void 0) {
1894
+ if (env.ISSUE_FLOW_CODEX_SANDBOX === "read-only" || env.ISSUE_FLOW_CODEX_SANDBOX === "workspace-write" || env.ISSUE_FLOW_CODEX_SANDBOX === "danger-full-access") {
1895
+ codex.sandbox = env.ISSUE_FLOW_CODEX_SANDBOX;
1896
+ } else {
1897
+ warn(`Ignoring ISSUE_FLOW_CODEX_SANDBOX="${env.ISSUE_FLOW_CODEX_SANDBOX}".`);
1898
+ }
1945
1899
  }
1946
- const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
1947
- if (refresh !== void 0) {
1948
- layer.refreshSeconds = refresh;
1900
+ if (env.ISSUE_FLOW_CODEX_REASONING_EFFORT !== void 0) {
1901
+ const effort = env.ISSUE_FLOW_CODEX_REASONING_EFFORT;
1902
+ if (effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh") {
1903
+ codex.reasoningEffort = effort;
1904
+ } else {
1905
+ warn(`Ignoring ISSUE_FLOW_CODEX_REASONING_EFFORT="${effort}".`);
1906
+ }
1949
1907
  }
1950
- const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
1951
- if (logLimit !== void 0) {
1952
- layer.logLimit = logLimit;
1908
+ if (env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG !== void 0) {
1909
+ codex.ignoreUserConfig = parseBooleanEnv(env.ISSUE_FLOW_CODEX_IGNORE_USER_CONFIG);
1953
1910
  }
1911
+ if (Object.keys(codex).length > 0) layer.codex = codex;
1912
+ const cursor = {};
1913
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX !== void 0) {
1914
+ if (env.ISSUE_FLOW_CURSOR_SANDBOX === "enabled" || env.ISSUE_FLOW_CURSOR_SANDBOX === "disabled") {
1915
+ cursor.sandbox = env.ISSUE_FLOW_CURSOR_SANDBOX;
1916
+ } else {
1917
+ warn(`Ignoring ISSUE_FLOW_CURSOR_SANDBOX="${env.ISSUE_FLOW_CURSOR_SANDBOX}".`);
1918
+ }
1919
+ }
1920
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE !== void 0) {
1921
+ if (env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "global" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "project" || env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE === "none") {
1922
+ cursor.permissionsFile = env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE;
1923
+ } else {
1924
+ warn(
1925
+ `Ignoring ISSUE_FLOW_CURSOR_PERMISSIONS_FILE="${env.ISSUE_FLOW_CURSOR_PERMISSIONS_FILE}".`
1926
+ );
1927
+ }
1928
+ }
1929
+ if (Object.keys(cursor).length > 0) layer.cursor = cursor;
1930
+ const antigravity = {};
1931
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EFFORT !== void 0) {
1932
+ const effort = env.ISSUE_FLOW_ANTIGRAVITY_EFFORT;
1933
+ if (effort === "low" || effort === "medium" || effort === "high") {
1934
+ antigravity.effort = effort;
1935
+ } else {
1936
+ warn(`Ignoring ISSUE_FLOW_ANTIGRAVITY_EFFORT="${effort}".`);
1937
+ }
1938
+ }
1939
+ if (env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX !== void 0) {
1940
+ antigravity.sandbox = parseBooleanEnv(env.ISSUE_FLOW_ANTIGRAVITY_SANDBOX);
1941
+ }
1942
+ if (env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT !== void 0) {
1943
+ antigravity.executeTimeout = env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT;
1944
+ }
1945
+ if (Object.keys(antigravity).length > 0) layer.antigravity = antigravity;
1954
1946
  return layer;
1955
1947
  }
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) {
1948
+ function readAgentKey(raw, label, warn) {
1949
+ if (raw === void 0) return {};
1950
+ const parsed = agentConfigInputSchema.safeParse(raw);
1951
+ if (!parsed.success) {
1964
1952
  warn(
1965
- `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
1953
+ `Ignoring "agent" key of ${label}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
1966
1954
  );
1967
1955
  return {};
1968
1956
  }
1969
- return result.data;
1957
+ const phases = parsePhasesInput(
1958
+ raw !== null && typeof raw === "object" && "phases" in raw ? raw.phases : void 0,
1959
+ warn
1960
+ );
1961
+ return {
1962
+ ...parsed.data.provider !== void 0 ? { provider: parsed.data.provider } : {},
1963
+ ...parsed.data.model !== void 0 ? { model: parsed.data.model } : {},
1964
+ ...parsed.data.claude !== void 0 ? { claude: parsed.data.claude } : {},
1965
+ ...parsed.data.codex !== void 0 ? { codex: parsed.data.codex } : {},
1966
+ ...parsed.data.cursor !== void 0 ? { cursor: parsed.data.cursor } : {},
1967
+ ...parsed.data.antigravity !== void 0 ? { antigravity: parsed.data.antigravity } : {},
1968
+ ...Object.keys(phases).length > 0 ? { phases } : {}
1969
+ };
1970
1970
  }
1971
- async function loadWebConfig(options = {}) {
1971
+ function pickOrigin(layers) {
1972
+ let current = "default";
1973
+ for (const layer of layers) {
1974
+ if (layer.value !== void 0) current = layer.origin;
1975
+ }
1976
+ return current;
1977
+ }
1978
+ function mergeAgentBlockLayers(layers) {
1979
+ let merged = {};
1980
+ let any = false;
1981
+ for (const layer of layers) {
1982
+ if (layer.block === void 0) continue;
1983
+ any = true;
1984
+ merged = {
1985
+ ...merged,
1986
+ ...dropUndefinedBlock(layer.block),
1987
+ claude: { ...merged.claude, ...layer.block.claude },
1988
+ codex: { ...merged.codex, ...layer.block.codex },
1989
+ cursor: { ...merged.cursor, ...layer.block.cursor },
1990
+ antigravity: { ...merged.antigravity, ...layer.block.antigravity }
1991
+ };
1992
+ }
1993
+ return any ? merged : void 0;
1994
+ }
1995
+ function dropUndefinedBlock(block) {
1996
+ const result = {};
1997
+ if (block.provider !== void 0) result.provider = block.provider;
1998
+ if (block.model !== void 0) result.model = block.model;
1999
+ if (block.claude !== void 0) result.claude = block.claude;
2000
+ if (block.codex !== void 0) result.codex = block.codex;
2001
+ if (block.cursor !== void 0) result.cursor = block.cursor;
2002
+ if (block.antigravity !== void 0) result.antigravity = block.antigravity;
2003
+ return result;
2004
+ }
2005
+ async function loadAgentConfig(options = {}) {
2006
+ const canCache = options.cli === void 0 && options.env === void 0 && options.projectRoot === void 0 && options.globalRoot === void 0 && options.warn === void 0;
2007
+ if (canCache && cachedAgentConfig !== void 0) return cachedAgentConfig;
1972
2008
  const warn = options.warn ?? printWarning;
1973
- const cli = options.cli ?? webCliOverrides;
2009
+ const cli = options.cli ?? agentCliOverrides;
1974
2010
  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;
2011
+ const globalFile = await loadGlobalConfig({
2012
+ env,
2013
+ globalRoot: options.globalRoot,
2014
+ warn
2015
+ });
2016
+ const globalLayer = readAgentKey(globalFile.agent, GLOBAL_CONFIG_FILENAME, warn);
2017
+ const projectFile = await readProjectConfigFile(options.projectRoot, warn);
2018
+ const projectLayer = readAgentKey(projectFile?.agent, PROJECT_CONFIG_FILENAME, warn);
2019
+ const envLayer = readAgentEnv(env, warn);
2020
+ const provider = cli.forceProvider ?? cli.provider ?? envLayer.provider ?? projectLayer.provider ?? globalLayer.provider ?? "claude";
2021
+ const model = cli.forceModel ?? cli.model ?? envLayer.model ?? projectLayer.model ?? globalLayer.model ?? null;
2022
+ const claude = mergeConfigLayers({
2023
+ global: globalLayer.claude,
2024
+ project: projectLayer.claude,
2025
+ env: envLayer.claude,
2026
+ cli: cli.claude
2027
+ });
2028
+ const codex = mergeConfigLayers({
2029
+ global: globalLayer.codex,
2030
+ project: projectLayer.codex,
2031
+ env: envLayer.codex,
2032
+ cli: cli.codex
2033
+ });
2034
+ const cursor = mergeConfigLayers({
2035
+ global: globalLayer.cursor,
2036
+ project: projectLayer.cursor,
2037
+ env: envLayer.cursor,
2038
+ cli: cli.cursor
2039
+ });
2040
+ const antigravity = mergeConfigLayers({
2041
+ global: globalLayer.antigravity,
2042
+ project: projectLayer.antigravity,
2043
+ env: envLayer.antigravity,
2044
+ cli: cli.antigravity
2045
+ });
2046
+ const phases = {};
2047
+ const phaseOrigins = {};
2048
+ for (const phase of AGENT_PHASES) {
2049
+ const block = mergeAgentBlockLayers([
2050
+ { origin: "global", block: globalLayer.phases?.[phase] },
2051
+ { origin: "project", block: projectLayer.phases?.[phase] },
2052
+ { origin: "env", block: envLayer.phases?.[phase] },
2053
+ { origin: "cli", block: cli.phases?.[phase] }
2054
+ ]);
2055
+ if (block && Object.keys(block).length > 0) {
2056
+ phases[phase] = block;
2057
+ phaseOrigins[phase] = {
2058
+ provider: block.provider !== void 0 ? pickOrigin([
2059
+ { origin: "global", value: globalLayer.phases?.[phase]?.provider },
2060
+ { origin: "project", value: projectLayer.phases?.[phase]?.provider },
2061
+ { origin: "env", value: envLayer.phases?.[phase]?.provider },
2062
+ { origin: "cli", value: cli.phases?.[phase]?.provider }
2063
+ ]) : void 0,
2064
+ model: block.model !== void 0 ? pickOrigin([
2065
+ { origin: "global", value: globalLayer.phases?.[phase]?.model },
2066
+ { origin: "project", value: projectLayer.phases?.[phase]?.model },
2067
+ { origin: "env", value: envLayer.phases?.[phase]?.model },
2068
+ { origin: "cli", value: cli.phases?.[phase]?.model }
2069
+ ]) : void 0
2070
+ };
2071
+ }
1981
2072
  }
1982
- warn(
1983
- `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
1984
- );
1985
- return webConfigSchema.parse({});
2073
+ setTrackedOrigins({
2074
+ provider: pickOrigin([
2075
+ { origin: "default", value: "claude" },
2076
+ { origin: "global", value: globalLayer.provider },
2077
+ { origin: "project", value: projectLayer.provider },
2078
+ { origin: "env", value: envLayer.provider },
2079
+ { origin: "cli", value: cli.forceProvider ?? cli.provider }
2080
+ ]),
2081
+ model: pickOrigin([
2082
+ { origin: "default", value: void 0 },
2083
+ { origin: "global", value: globalLayer.model },
2084
+ { origin: "project", value: projectLayer.model },
2085
+ { origin: "env", value: envLayer.model },
2086
+ { origin: "cli", value: cli.forceModel ?? cli.model }
2087
+ ]),
2088
+ phases: phaseOrigins
2089
+ });
2090
+ const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2091
+ if (canCache) cachedAgentConfig = resolved;
2092
+ return resolved;
1986
2093
  }
1987
- var issuesCliOverrides = {};
1988
- function setIssuesCliOverrides(overrides) {
1989
- issuesCliOverrides = overrides;
2094
+
2095
+ // src/config/dependencies.ts
2096
+ function getInstallHint(pkg) {
2097
+ const os = platform();
2098
+ if (os === "darwin") {
2099
+ return `brew install ${pkg}`;
2100
+ }
2101
+ if (os === "linux") {
2102
+ return `apt install ${pkg} (or your distro's package manager)`;
2103
+ }
2104
+ if (os === "win32") {
2105
+ return `winget install ${pkg} (or choco install ${pkg})`;
2106
+ }
2107
+ return `install ${pkg} using your system package manager`;
1990
2108
  }
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 {};
2109
+ async function validateDependencies() {
2110
+ const errors = [];
2111
+ const gitResult = await run("git", ["--version"]);
2112
+ if (gitResult.exitCode !== 0) {
2113
+ errors.push(` - git (install with: ${getInstallHint("git")})`);
1996
2114
  }
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 {};
2115
+ const agent = await loadAgentConfig();
2116
+ const needed = /* @__PURE__ */ new Set([agent.provider]);
2117
+ for (const phase of AGENT_PHASES) {
2118
+ const provider = agent.phases[phase]?.provider;
2119
+ if (provider !== void 0) needed.add(provider);
2003
2120
  }
2004
- return result.data;
2121
+ for (const id of needed) {
2122
+ const { command, args } = runnerFor(id).versionCommand();
2123
+ const result = await run(command, args);
2124
+ if (result.exitCode !== 0) {
2125
+ errors.push(` - ${command} (${installHint(id)})`);
2126
+ }
2127
+ }
2128
+ return errors;
2005
2129
  }
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;
2130
+
2131
+ // src/config/engine.ts
2132
+ import { join as join3 } from "path";
2133
+ var DEFAULTS = {
2134
+ retryLimit: 10,
2135
+ retryForever: false,
2136
+ backoffBaseSeconds: 30,
2137
+ backoffMaxSeconds: 900
2138
+ };
2139
+ function createConfig(options) {
2140
+ return {
2141
+ issueNumber: options.issueNumber,
2142
+ maxIterations: options.maxIterations,
2143
+ retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,
2144
+ retryForever: options.retryForever ?? DEFAULTS.retryForever,
2145
+ backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,
2146
+ backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,
2147
+ // Left absent (rather than defaulted to an empty string) so the execute
2148
+ // prompt keeps its historical commit format unless a queue asks otherwise.
2149
+ ...options.commitScope === void 0 ? {} : { commitScope: options.commitScope },
2150
+ storiesPerIteration: options.storiesPerIteration ?? 1
2151
+ };
2152
+ }
2153
+ async function resolvePaths(config, scriptDir) {
2154
+ const projectRoot = await getProjectRoot();
2155
+ if (config.issueNumber) {
2156
+ const issuePaths = await resolveIssuePaths(config.issueNumber, { projectRoot });
2157
+ return {
2158
+ prdFile: issuePaths.tasksFile,
2159
+ progressFile: issuePaths.progressFile,
2160
+ archiveDir: issuePaths.archiveDir,
2161
+ lastBranchFile: issuePaths.lastBranchFile,
2162
+ projectRoot
2163
+ };
2014
2164
  }
2015
- warn(
2016
- `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2017
- );
2018
- return issuesConfigSchema.parse({});
2165
+ const base = scriptDir ?? projectRoot;
2166
+ const standalone = {
2167
+ prdFile: join3(base, "prd.json"),
2168
+ progressFile: join3(base, "progress.txt"),
2169
+ archiveDir: join3(base, "archive"),
2170
+ lastBranchFile: join3(base, ".last-branch"),
2171
+ projectRoot
2172
+ };
2173
+ const { bindTelemetry } = await import("./recorder-N7U66HCO.js");
2174
+ bindTelemetry({ tasksPath: standalone.prdFile });
2175
+ return standalone;
2019
2176
  }
2020
- function readPrReviewConfigEnv(env) {
2021
- const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
2022
- return publisher === void 0 ? {} : { publisher };
2177
+
2178
+ // src/config/issues.ts
2179
+ var issuesCliOverrides = {};
2180
+ function setIssuesCliOverrides(overrides) {
2181
+ issuesCliOverrides = overrides;
2023
2182
  }
2024
- async function readPrReviewConfigFile(projectRoot, warn) {
2183
+ async function readIssuesConfigFile(projectRoot, warn) {
2025
2184
  const file = await readProjectConfigFile(projectRoot, warn);
2026
- const prReview = file?.prReview;
2027
- if (prReview === void 0) {
2185
+ const issues = file?.issues;
2186
+ if (issues === void 0) {
2028
2187
  return {};
2029
2188
  }
2030
- const result = prReviewConfigSchema.partial().safeParse(prReview);
2189
+ const result = issuesConfigSchema.partial().safeParse(issues);
2031
2190
  if (!result.success) {
2032
2191
  warn(
2033
- `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2192
+ `Ignoring "issues" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2034
2193
  );
2035
2194
  return {};
2036
2195
  }
2037
2196
  return result.data;
2038
2197
  }
2039
- async function loadPrReviewConfig(options = {}) {
2198
+ async function loadIssuesConfig(options = {}) {
2040
2199
  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);
2200
+ const cli = options.cli ?? issuesCliOverrides;
2201
+ const fileLayer = await readIssuesConfigFile(options.projectRoot, warn);
2202
+ const merged = { ...fileLayer, ...cli };
2203
+ const result = issuesConfigSchema.safeParse(merged);
2046
2204
  if (result.success) {
2047
2205
  return result.data;
2048
2206
  }
2049
2207
  warn(
2050
- `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2208
+ `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2051
2209
  );
2052
- return prReviewConfigSchema.parse({});
2210
+ return issuesConfigSchema.parse({});
2053
2211
  }
2212
+
2213
+ // src/config/policy.ts
2054
2214
  var policyCliOverrides = {};
2055
2215
  function setPolicyCliOverrides(overrides) {
2056
2216
  policyCliOverrides = overrides;
2057
2217
  }
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
2218
  function readPolicyConfigEnv(env, warn) {
2068
2219
  const layer = {};
2069
2220
  if (env.ISSUE_FLOW_POLICY !== void 0) {
@@ -2159,77 +2310,44 @@ async function loadPolicyConfig(options = {}) {
2159
2310
  );
2160
2311
  return policyConfigSchema.parse({});
2161
2312
  }
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 {};
2313
+
2314
+ // src/config/pr-review.ts
2315
+ function readPrReviewConfigEnv(env) {
2316
+ const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
2317
+ return publisher === void 0 ? {} : { publisher };
2170
2318
  }
2171
- function readTelemetryEnv(env, warn) {
2172
- const layer = {};
2173
- if (env.ISSUE_FLOW_TELEMETRY !== void 0) {
2174
- layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY);
2319
+ async function readPrReviewConfigFile(projectRoot, warn) {
2320
+ const file = await readProjectConfigFile(projectRoot, warn);
2321
+ const prReview = file?.prReview;
2322
+ if (prReview === void 0) {
2323
+ return {};
2175
2324
  }
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) };
2325
+ const result = prReviewConfigSchema.partial().safeParse(prReview);
2326
+ if (!result.success) {
2327
+ warn(
2328
+ `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2329
+ );
2330
+ return {};
2180
2331
  }
2181
- return layer;
2332
+ return result.data;
2182
2333
  }
2183
- async function loadTelemetryConfig(options = {}) {
2334
+ async function loadPrReviewConfig(options = {}) {
2184
2335
  const warn = options.warn ?? printWarning;
2185
2336
  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
- };
2337
+ const fileLayer = await readPrReviewConfigFile(options.projectRoot, warn);
2338
+ const envLayer = readPrReviewConfigEnv(env);
2339
+ const merged = { ...fileLayer, ...envLayer, ...options.cli ?? {} };
2340
+ const result = prReviewConfigSchema.safeParse(merged);
2341
+ if (result.success) {
2342
+ return result.data;
2343
+ }
2344
+ warn(
2345
+ `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2346
+ );
2347
+ return prReviewConfigSchema.parse({});
2232
2348
  }
2349
+
2350
+ // src/config/resilience.ts
2233
2351
  var resilienceCliOverrides = {};
2234
2352
  function setResilienceCliOverrides(overrides) {
2235
2353
  resilienceCliOverrides = overrides;
@@ -2398,231 +2516,125 @@ async function initResilienceConfig(options = {}) {
2398
2516
  }
2399
2517
  return activeResilienceConfig;
2400
2518
  }
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;
2519
+
2520
+ // src/config/routing.ts
2521
+ var routingCliOverrides = {};
2522
+ function setRoutingCliOverrides(overrides) {
2523
+ routingCliOverrides = overrides;
2479
2524
  }
2480
- function readAgentKey(raw, label, warn) {
2481
- if (raw === void 0) return {};
2482
- const parsed = agentConfigInputSchema.safeParse(raw);
2483
- if (!parsed.success) {
2525
+ async function loadRoutingConfig(options = {}) {
2526
+ const warn = options.warn ?? printWarning;
2527
+ const global = options.global ?? (await loadGlobalConfig({
2528
+ env: options.env ?? process.env,
2529
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2530
+ warn
2531
+ })).routing;
2532
+ const file = await readProjectConfigFile(options.projectRoot, warn);
2533
+ const raw = file?.routing;
2534
+ const parsedResult = routingConfigInputSchema.safeParse(raw ?? {});
2535
+ if (!parsedResult.success) {
2484
2536
  warn(
2485
- `Ignoring "agent" key of ${label}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
2537
+ `Ignoring "routing" key of ${PROJECT_CONFIG_FILENAME}: ${parsedResult.error.issues[0]?.message ?? "invalid value"}.`
2486
2538
  );
2487
- return {};
2488
2539
  }
2489
- const phases = parsePhasesInput(
2490
- raw !== null && typeof raw === "object" && "phases" in raw ? raw.phases : void 0,
2491
- warn
2540
+ const project = parsedResult.success ? parsedResult.data : {};
2541
+ const cli = options.cli ?? routingCliOverrides;
2542
+ const result = routingConfigSchema.safeParse({
2543
+ ...global,
2544
+ ...project,
2545
+ ...cli,
2546
+ escalation: {
2547
+ ...global?.escalation,
2548
+ ...project.escalation,
2549
+ ...cli.escalation
2550
+ },
2551
+ ceilings: {
2552
+ ...global?.ceilings,
2553
+ ...project.ceilings,
2554
+ ...cli.ceilings
2555
+ }
2556
+ });
2557
+ if (result.success) return result.data;
2558
+ warn(
2559
+ `Invalid routing configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2492
2560
  );
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
- };
2561
+ return routingConfigSchema.parse({});
2502
2562
  }
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;
2563
+
2564
+ // src/config/telemetry.ts
2565
+ function parseTelemetryLayer(value, source, warn) {
2566
+ if (value === void 0) return {};
2567
+ const result = telemetryConfigInputSchema.safeParse(value);
2568
+ if (result.success) return result.data;
2569
+ warn(
2570
+ `Ignoring "telemetry" key of ${source}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2571
+ );
2572
+ return {};
2509
2573
  }
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
- };
2574
+ function readTelemetryEnv(env, warn) {
2575
+ const layer = {};
2576
+ if (env.ISSUE_FLOW_TELEMETRY !== void 0) {
2577
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY);
2524
2578
  }
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;
2579
+ const max = readNumberEnv(env, "ISSUE_FLOW_TELEMETRY_MAX_EXECUTIONS", warn);
2580
+ if (max !== void 0) layer.maxExecutions = max;
2581
+ if (env.ISSUE_FLOW_TELEMETRY_ESTIMATE !== void 0) {
2582
+ layer.pricing = { estimate: parseBooleanEnv(env.ISSUE_FLOW_TELEMETRY_ESTIMATE) };
2583
+ }
2584
+ return layer;
2536
2585
  }
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;
2586
+ async function loadTelemetryConfig(options = {}) {
2540
2587
  const warn = options.warn ?? printWarning;
2541
- const cli = options.cli ?? agentCliOverrides;
2542
2588
  const env = options.env ?? process.env;
2543
- const globalFile = await loadGlobalConfig({
2589
+ const globalFile = options.global ?? (await loadGlobalConfig({
2544
2590
  env,
2545
- globalRoot: options.globalRoot,
2591
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
2546
2592
  warn
2547
- });
2548
- const globalLayer = readAgentKey(globalFile.agent, GLOBAL_CONFIG_FILENAME, warn);
2593
+ })).telemetry;
2549
2594
  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
2595
+ const project = parseTelemetryLayer(projectFile?.telemetry, PROJECT_CONFIG_FILENAME, warn);
2596
+ const envLayer = readTelemetryEnv(env, warn);
2597
+ const pricing = mergeConfigLayers({
2598
+ defaults: DEFAULT_TELEMETRY_CONFIG.pricing,
2599
+ global: globalFile?.pricing,
2600
+ project: project.pricing,
2601
+ env: envLayer.pricing
2577
2602
  });
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
+ const overrides = {
2604
+ ...DEFAULT_TELEMETRY_CONFIG.pricing.overrides,
2605
+ ...globalFile?.pricing?.overrides,
2606
+ ...project.pricing?.overrides,
2607
+ ...envLayer.pricing?.overrides
2608
+ };
2609
+ const scalars = mergeConfigLayers({
2610
+ defaults: {
2611
+ enabled: DEFAULT_TELEMETRY_CONFIG.enabled,
2612
+ maxExecutions: DEFAULT_TELEMETRY_CONFIG.maxExecutions
2613
+ },
2614
+ global: {
2615
+ ...globalFile?.enabled === void 0 ? {} : { enabled: globalFile.enabled },
2616
+ ...globalFile?.maxExecutions === void 0 ? {} : { maxExecutions: globalFile.maxExecutions }
2617
+ },
2618
+ project: {
2619
+ ...project.enabled === void 0 ? {} : { enabled: project.enabled },
2620
+ ...project.maxExecutions === void 0 ? {} : { maxExecutions: project.maxExecutions }
2621
+ },
2622
+ env: {
2623
+ ...envLayer.enabled === void 0 ? {} : { enabled: envLayer.enabled },
2624
+ ...envLayer.maxExecutions === void 0 ? {} : { maxExecutions: envLayer.maxExecutions }
2603
2625
  }
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
2626
  });
2622
- const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2623
- if (canCache) cachedAgentConfig = resolved;
2624
- return resolved;
2627
+ return {
2628
+ enabled: scalars.enabled ?? DEFAULT_TELEMETRY_CONFIG.enabled,
2629
+ maxExecutions: scalars.maxExecutions ?? DEFAULT_TELEMETRY_CONFIG.maxExecutions,
2630
+ pricing: {
2631
+ estimate: pricing.estimate ?? DEFAULT_TELEMETRY_CONFIG.pricing.estimate,
2632
+ overrides
2633
+ }
2634
+ };
2625
2635
  }
2636
+
2637
+ // src/config/verify.ts
2626
2638
  var verifyCliOverrides = {};
2627
2639
  function setVerifyCliOverrides(overrides) {
2628
2640
  verifyCliOverrides = overrides;
@@ -2652,23 +2664,73 @@ async function loadVerifyConfig(options = {}) {
2652
2664
  );
2653
2665
  return verifyConfigSchema.parse({});
2654
2666
  }
2655
- var routingCliOverrides = {};
2656
- function setRoutingCliOverrides(overrides) {
2657
- routingCliOverrides = overrides;
2667
+
2668
+ // src/config/web.ts
2669
+ var webCliOverrides = {};
2670
+ function setWebCliOverrides(overrides) {
2671
+ webCliOverrides = overrides;
2658
2672
  }
2659
- async function loadRoutingConfig(options = {}) {
2673
+ function readWebConfigEnv(env, warn) {
2674
+ const layer = {};
2675
+ if (env.ISSUE_FLOW_WEB !== void 0) {
2676
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
2677
+ }
2678
+ const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
2679
+ if (port !== void 0) {
2680
+ layer.port = port;
2681
+ }
2682
+ if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
2683
+ layer.host = env.ISSUE_FLOW_WEB_HOST;
2684
+ }
2685
+ const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
2686
+ if (refresh !== void 0) {
2687
+ layer.refreshSeconds = refresh;
2688
+ }
2689
+ const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
2690
+ if (logLimit !== void 0) {
2691
+ layer.logLimit = logLimit;
2692
+ }
2693
+ return layer;
2694
+ }
2695
+ async function readWebConfigFile(projectRoot, warn) {
2696
+ const file = await readProjectConfigFile(projectRoot, warn);
2697
+ const web = file?.web;
2698
+ if (web === void 0) {
2699
+ return {};
2700
+ }
2701
+ const result = webConfigSchema.partial().safeParse(web);
2702
+ if (!result.success) {
2703
+ warn(
2704
+ `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
2705
+ );
2706
+ return {};
2707
+ }
2708
+ return result.data;
2709
+ }
2710
+ async function loadWebConfig(options = {}) {
2660
2711
  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({});
2712
+ const cli = options.cli ?? webCliOverrides;
2713
+ const env = options.env ?? process.env;
2714
+ const fileLayer = await readWebConfigFile(options.projectRoot, warn);
2715
+ const envLayer = readWebConfigEnv(env, warn);
2716
+ const merged = { ...fileLayer, ...envLayer, ...cli };
2717
+ const result = webConfigSchema.safeParse(merged);
2718
+ if (result.success) {
2719
+ return result.data;
2720
+ }
2721
+ warn(
2722
+ `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
2723
+ );
2724
+ return webConfigSchema.parse({});
2669
2725
  }
2670
2726
 
2727
+ // src/config.ts
2728
+ var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
2729
+
2671
2730
  export {
2731
+ PROJECT_CONFIG_FILENAME,
2732
+ GLOBAL_CONFIG_FILENAME,
2733
+ loadGlobalConfig,
2672
2734
  getShutdownSignal,
2673
2735
  onShutdown,
2674
2736
  installShutdownHandlers,
@@ -2680,39 +2742,36 @@ export {
2680
2742
  runnerFor,
2681
2743
  ensureHarnessVersion,
2682
2744
  probeAgent,
2745
+ mergeConfigLayers,
2746
+ setAgentCliOverrides,
2747
+ getAgentCliOverrides,
2748
+ loadAgentConfig,
2749
+ getInstallHint,
2750
+ validateDependencies,
2683
2751
  DEFAULTS,
2684
2752
  createConfig,
2685
2753
  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
2754
  setIssuesCliOverrides,
2696
2755
  loadIssuesConfig,
2697
- loadPrReviewConfig,
2698
2756
  setPolicyCliOverrides,
2699
2757
  loadPolicyConfig,
2700
- loadTelemetryConfig,
2758
+ loadPrReviewConfig,
2701
2759
  setResilienceCliOverrides,
2702
2760
  loadResilienceConfig,
2703
2761
  getActiveResilienceConfig,
2704
2762
  setActiveResilienceConfig,
2705
2763
  initResilienceConfig,
2706
- setAgentCliOverrides,
2707
- getAgentCliOverrides,
2708
- loadAgentConfig,
2709
- setVerifyCliOverrides,
2710
- loadVerifyConfig,
2711
2764
  setRoutingCliOverrides,
2712
2765
  loadRoutingConfig,
2766
+ loadTelemetryConfig,
2767
+ setVerifyCliOverrides,
2768
+ loadVerifyConfig,
2769
+ setWebCliOverrides,
2770
+ loadWebConfig,
2771
+ WEB_CONFIG_FILENAME,
2713
2772
  resolveAgentFor,
2714
2773
  parseAgentPhaseFlag,
2715
2774
  describeRunAgents,
2716
2775
  hasExplicitAgentSelection
2717
2776
  };
2718
- //# sourceMappingURL=chunk-WM3Y7Q4A.js.map
2777
+ //# sourceMappingURL=chunk-HY5HLFDU.js.map