issue-flow 0.11.0 → 0.12.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 (118) hide show
  1. package/README.md +1 -1
  2. package/dist/{analyze-7B5TORNK.js → analyze-OEET7KGE.js} +17 -11
  3. package/dist/analyze-OEET7KGE.js.map +1 -0
  4. package/dist/{apply-WUJHDD7A.js → apply-ZIA3C52S.js} +6 -4
  5. package/dist/{apply-WUJHDD7A.js.map → apply-ZIA3C52S.js.map} +1 -1
  6. package/dist/{chunk-6N7LZZ5U.js → chunk-3QHK4YQA.js} +204 -107
  7. package/dist/chunk-3QHK4YQA.js.map +1 -0
  8. package/dist/chunk-42PJFMAR.js +605 -0
  9. package/dist/chunk-42PJFMAR.js.map +1 -0
  10. package/dist/{chunk-PL6CNMVS.js → chunk-4JSOYE4G.js} +105 -19
  11. package/dist/chunk-4JSOYE4G.js.map +1 -0
  12. package/dist/chunk-56KS3TFQ.js +703 -0
  13. package/dist/chunk-56KS3TFQ.js.map +1 -0
  14. package/dist/{chunk-AAY6KM7N.js → chunk-73ATPIYX.js} +160 -154
  15. package/dist/chunk-73ATPIYX.js.map +1 -0
  16. package/dist/{chunk-MKD2D7WE.js → chunk-A4SLHOW7.js} +70 -13
  17. package/dist/chunk-A4SLHOW7.js.map +1 -0
  18. package/dist/chunk-BAUPQXPE.js +173 -0
  19. package/dist/chunk-BAUPQXPE.js.map +1 -0
  20. package/dist/{chunk-HC2MT7BX.js → chunk-BYZDPR7N.js} +14 -581
  21. package/dist/chunk-BYZDPR7N.js.map +1 -0
  22. package/dist/chunk-CD5ULRVC.js +615 -0
  23. package/dist/chunk-CD5ULRVC.js.map +1 -0
  24. package/dist/chunk-DIDUVL6O.js +1365 -0
  25. package/dist/chunk-DIDUVL6O.js.map +1 -0
  26. package/dist/{chunk-47VIN33V.js → chunk-EZATO3DW.js} +7 -5
  27. package/dist/{chunk-47VIN33V.js.map → chunk-EZATO3DW.js.map} +1 -1
  28. package/dist/{chunk-JW7WLSZ6.js → chunk-FADTCQGM.js} +48 -12
  29. package/dist/chunk-FADTCQGM.js.map +1 -0
  30. package/dist/{chunk-GANSDJV7.js → chunk-FJP3UQGD.js} +15 -13
  31. package/dist/chunk-FJP3UQGD.js.map +1 -0
  32. package/dist/chunk-KMMASOA6.js +134 -0
  33. package/dist/chunk-KMMASOA6.js.map +1 -0
  34. package/dist/{chunk-HQYXVIH6.js → chunk-LAFNLLQP.js} +3 -3
  35. package/dist/chunk-LWRSMTTZ.js +18 -0
  36. package/dist/chunk-LWRSMTTZ.js.map +1 -0
  37. package/dist/{chunk-MSPUB635.js → chunk-M5UCXTIT.js} +15 -12
  38. package/dist/chunk-M5UCXTIT.js.map +1 -0
  39. package/dist/chunk-M66SJHQQ.js +206 -0
  40. package/dist/chunk-M66SJHQQ.js.map +1 -0
  41. package/dist/{chunk-OBLVLIUS.js → chunk-MJULIKQU.js} +42 -6
  42. package/dist/chunk-MJULIKQU.js.map +1 -0
  43. package/dist/{chunk-RKTEV6EG.js → chunk-NS6R37II.js} +4 -4
  44. package/dist/{run-H75MD5BQ.js → chunk-NTMMF5UD.js} +515 -544
  45. package/dist/chunk-NTMMF5UD.js.map +1 -0
  46. package/dist/{chunk-UBIQXCVE.js → chunk-QCPGHBSZ.js} +16 -13
  47. package/dist/chunk-QCPGHBSZ.js.map +1 -0
  48. package/dist/{chunk-LVKQ2AKT.js → chunk-TSOLWK7Y.js} +8 -6
  49. package/dist/chunk-TSOLWK7Y.js.map +1 -0
  50. package/dist/{chunk-VCKX262Z.js → chunk-XQUSIEKA.js} +13 -10
  51. package/dist/chunk-XQUSIEKA.js.map +1 -0
  52. package/dist/chunk-Y5ZDJ4PJ.js +76 -0
  53. package/dist/chunk-Y5ZDJ4PJ.js.map +1 -0
  54. package/dist/cli.js +156 -26
  55. package/dist/cli.js.map +1 -1
  56. package/dist/{config-4THHOXNN.js → config-PRJGWW7J.js} +15 -3
  57. package/dist/execute-XBNVL753.js +18 -0
  58. package/dist/{generate-6RA2MFJB.js → generate-EGB4KV2B.js} +18 -11
  59. package/dist/generate-EGB4KV2B.js.map +1 -0
  60. package/dist/init-AJHCXJBP.js +10 -0
  61. package/dist/operations-BYT626KQ.js +365 -0
  62. package/dist/operations-BYT626KQ.js.map +1 -0
  63. package/dist/plan-QOZ3RIO6.js +21 -0
  64. package/dist/{policy-XQW5NUIE.js → policy-6S4GFC76.js} +6 -4
  65. package/dist/{policy-XQW5NUIE.js.map → policy-6S4GFC76.js.map} +1 -1
  66. package/dist/pr-EBBHD2ZX.js +26 -0
  67. package/dist/pr-review-VVMW5PO4.js +20 -0
  68. package/dist/prd-JQSZF7PR.js +21 -0
  69. package/dist/resume-PPCNQVVV.js +221 -0
  70. package/dist/resume-PPCNQVVV.js.map +1 -0
  71. package/dist/review-3F6MARWH.js +19 -0
  72. package/dist/run-RXE5GDQO.js +36 -0
  73. package/dist/run-RXE5GDQO.js.map +1 -0
  74. package/dist/state-manager-2EDVDBAR.js +34 -0
  75. package/dist/state-manager-2EDVDBAR.js.map +1 -0
  76. package/dist/{web-ANQQTTRD.js → web-EF5WIIGG.js} +13 -8
  77. package/dist/{web-ANQQTTRD.js.map → web-EF5WIIGG.js.map} +1 -1
  78. package/package.json +1 -1
  79. package/prompts/pr.md +11 -4
  80. package/web/public/app.js +12 -0
  81. package/dist/analyze-7B5TORNK.js.map +0 -1
  82. package/dist/chunk-3BOHTH4V.js +0 -58
  83. package/dist/chunk-3BOHTH4V.js.map +0 -1
  84. package/dist/chunk-6N7LZZ5U.js.map +0 -1
  85. package/dist/chunk-AAY6KM7N.js.map +0 -1
  86. package/dist/chunk-GANSDJV7.js.map +0 -1
  87. package/dist/chunk-HC2MT7BX.js.map +0 -1
  88. package/dist/chunk-HDV3YDTG.js +0 -52
  89. package/dist/chunk-HDV3YDTG.js.map +0 -1
  90. package/dist/chunk-JW7WLSZ6.js.map +0 -1
  91. package/dist/chunk-LVKQ2AKT.js.map +0 -1
  92. package/dist/chunk-MKD2D7WE.js.map +0 -1
  93. package/dist/chunk-MSPUB635.js.map +0 -1
  94. package/dist/chunk-OBLVLIUS.js.map +0 -1
  95. package/dist/chunk-PL6CNMVS.js.map +0 -1
  96. package/dist/chunk-UBIQXCVE.js.map +0 -1
  97. package/dist/chunk-VCKX262Z.js.map +0 -1
  98. package/dist/chunk-VQ5VN7DF.js +0 -1018
  99. package/dist/chunk-VQ5VN7DF.js.map +0 -1
  100. package/dist/execute-5OEKLM5X.js +0 -15
  101. package/dist/generate-6RA2MFJB.js.map +0 -1
  102. package/dist/init-PRMOTQ7N.js +0 -9
  103. package/dist/plan-KENR6MJ3.js +0 -17
  104. package/dist/pr-KDGKG4BP.js +0 -21
  105. package/dist/pr-review-CAMAB7KO.js +0 -17
  106. package/dist/prd-V3MWDIHK.js +0 -17
  107. package/dist/review-7LN47SAN.js +0 -15
  108. package/dist/run-H75MD5BQ.js.map +0 -1
  109. /package/dist/{chunk-HQYXVIH6.js.map → chunk-LAFNLLQP.js.map} +0 -0
  110. /package/dist/{chunk-RKTEV6EG.js.map → chunk-NS6R37II.js.map} +0 -0
  111. /package/dist/{config-4THHOXNN.js.map → config-PRJGWW7J.js.map} +0 -0
  112. /package/dist/{execute-5OEKLM5X.js.map → execute-XBNVL753.js.map} +0 -0
  113. /package/dist/{init-PRMOTQ7N.js.map → init-AJHCXJBP.js.map} +0 -0
  114. /package/dist/{plan-KENR6MJ3.js.map → plan-QOZ3RIO6.js.map} +0 -0
  115. /package/dist/{pr-KDGKG4BP.js.map → pr-EBBHD2ZX.js.map} +0 -0
  116. /package/dist/{pr-review-CAMAB7KO.js.map → pr-review-VVMW5PO4.js.map} +0 -0
  117. /package/dist/{prd-V3MWDIHK.js.map → prd-JQSZF7PR.js.map} +0 -0
  118. /package/dist/{review-7LN47SAN.js.map → review-3F6MARWH.js.map} +0 -0
@@ -0,0 +1,605 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ RETRY_CONFIG_KEYS,
4
+ getGlobalRoot,
5
+ getProjectRoot,
6
+ globalConfigSchema,
7
+ resilienceConfigSchema,
8
+ resolveIssuePaths,
9
+ run
10
+ } from "./chunk-DIDUVL6O.js";
11
+ import {
12
+ printWarning
13
+ } from "./chunk-BYZDPR7N.js";
14
+ import {
15
+ issuesConfigSchema,
16
+ policyConfigInputSchema,
17
+ policyConfigSchema,
18
+ prReviewConfigSchema,
19
+ webConfigSchema
20
+ } from "./chunk-CD5ULRVC.js";
21
+
22
+ // src/config.ts
23
+ import { readFile } from "fs/promises";
24
+ import { platform } from "os";
25
+ import { join } from "path";
26
+ var DEFAULTS = {
27
+ retryLimit: 10,
28
+ retryForever: false,
29
+ backoffBaseSeconds: 30,
30
+ backoffMaxSeconds: 900
31
+ };
32
+ function createConfig(options) {
33
+ return {
34
+ issueNumber: options.issueNumber,
35
+ maxIterations: options.maxIterations,
36
+ retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,
37
+ retryForever: options.retryForever ?? DEFAULTS.retryForever,
38
+ backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,
39
+ backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,
40
+ // Left absent (rather than defaulted to an empty string) so the execute
41
+ // prompt keeps its historical commit format unless a queue asks otherwise.
42
+ ...options.commitScope === void 0 ? {} : { commitScope: options.commitScope }
43
+ };
44
+ }
45
+ async function resolvePaths(config, scriptDir) {
46
+ const projectRoot = await getProjectRoot();
47
+ if (config.issueNumber) {
48
+ const issuePaths = await resolveIssuePaths(config.issueNumber, { projectRoot });
49
+ return {
50
+ prdFile: issuePaths.tasksFile,
51
+ progressFile: issuePaths.progressFile,
52
+ archiveDir: issuePaths.archiveDir,
53
+ lastBranchFile: issuePaths.lastBranchFile,
54
+ projectRoot
55
+ };
56
+ }
57
+ const base = scriptDir ?? projectRoot;
58
+ return {
59
+ prdFile: join(base, "prd.json"),
60
+ progressFile: join(base, "progress.txt"),
61
+ archiveDir: join(base, "archive"),
62
+ lastBranchFile: join(base, ".last-branch"),
63
+ projectRoot
64
+ };
65
+ }
66
+ function getInstallHint(pkg) {
67
+ const os = platform();
68
+ if (os === "darwin") {
69
+ return `brew install ${pkg}`;
70
+ }
71
+ if (os === "linux") {
72
+ return `apt install ${pkg} (or your distro's package manager)`;
73
+ }
74
+ if (os === "win32") {
75
+ return `winget install ${pkg} (or choco install ${pkg})`;
76
+ }
77
+ return `install ${pkg} using your system package manager`;
78
+ }
79
+ async function validateDependencies() {
80
+ const errors = [];
81
+ const gitResult = await run("git", ["--version"]);
82
+ if (gitResult.exitCode !== 0) {
83
+ errors.push(` - git (install with: ${getInstallHint("git")})`);
84
+ }
85
+ const claudeResult = await run("claude", ["--version"]);
86
+ if (claudeResult.exitCode !== 0) {
87
+ errors.push(" - claude (install with: npm install -g @anthropic-ai/claude-code)");
88
+ }
89
+ return errors;
90
+ }
91
+ var PROJECT_CONFIG_FILENAME = ".issue-flow.json";
92
+ var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
93
+ async function readProjectConfigFile(projectRoot, warn) {
94
+ let root = projectRoot;
95
+ if (root === void 0) {
96
+ try {
97
+ root = await getProjectRoot();
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ const filePath = join(root, PROJECT_CONFIG_FILENAME);
103
+ let raw;
104
+ try {
105
+ raw = await readFile(filePath, "utf-8");
106
+ } catch {
107
+ return null;
108
+ }
109
+ let parsed;
110
+ try {
111
+ parsed = JSON.parse(raw);
112
+ } catch {
113
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: invalid JSON.`);
114
+ return null;
115
+ }
116
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
117
+ warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: expected a JSON object.`);
118
+ return null;
119
+ }
120
+ return parsed;
121
+ }
122
+ var GLOBAL_CONFIG_FILENAME = "config.json";
123
+ async function loadGlobalConfig(options = {}) {
124
+ const warn = options.warn ?? printWarning;
125
+ let root;
126
+ try {
127
+ root = options.globalRoot ?? getGlobalRoot({ env: options.env ?? process.env });
128
+ } catch (err) {
129
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
130
+ return {};
131
+ }
132
+ const filePath = join(root, GLOBAL_CONFIG_FILENAME);
133
+ let raw;
134
+ try {
135
+ raw = await readFile(filePath, "utf-8");
136
+ } catch (err) {
137
+ if (err.code !== "ENOENT") {
138
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
139
+ }
140
+ return {};
141
+ }
142
+ let parsed;
143
+ try {
144
+ parsed = JSON.parse(raw);
145
+ } catch {
146
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: invalid JSON.`);
147
+ return {};
148
+ }
149
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
150
+ warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: expected a JSON object.`);
151
+ return {};
152
+ }
153
+ const config = {};
154
+ for (const [key, value] of Object.entries(parsed)) {
155
+ const result = globalConfigSchema.safeParse({ [key]: value });
156
+ if (!result.success) {
157
+ warn(
158
+ `Ignoring "${key}" key of ${GLOBAL_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
159
+ );
160
+ continue;
161
+ }
162
+ Object.assign(config, result.data);
163
+ }
164
+ return config;
165
+ }
166
+ function mergeConfigLayers(layers) {
167
+ const merged = {};
168
+ for (const layer of [
169
+ layers.defaults,
170
+ layers.discovered,
171
+ layers.global,
172
+ layers.project,
173
+ layers.env,
174
+ layers.cli
175
+ ]) {
176
+ for (const [key, value] of Object.entries(layer ?? {})) {
177
+ if (value !== void 0) {
178
+ merged[key] = value;
179
+ }
180
+ }
181
+ }
182
+ return merged;
183
+ }
184
+ var webCliOverrides = {};
185
+ function setWebCliOverrides(overrides) {
186
+ webCliOverrides = overrides;
187
+ }
188
+ var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
189
+ function parseBooleanEnv(value) {
190
+ return !FALSY_ENV_VALUES.has(value.trim().toLowerCase());
191
+ }
192
+ function readNumberEnv(env, name, warn) {
193
+ const raw = env[name];
194
+ if (raw === void 0) {
195
+ return void 0;
196
+ }
197
+ const parsed = Number(raw);
198
+ if (!Number.isFinite(parsed)) {
199
+ warn(`Ignoring ${name}="${raw}": not a number.`);
200
+ return void 0;
201
+ }
202
+ return parsed;
203
+ }
204
+ function readWebConfigEnv(env, warn) {
205
+ const layer = {};
206
+ if (env.ISSUE_FLOW_WEB !== void 0) {
207
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);
208
+ }
209
+ const port = readNumberEnv(env, "ISSUE_FLOW_WEB_PORT", warn);
210
+ if (port !== void 0) {
211
+ layer.port = port;
212
+ }
213
+ if (env.ISSUE_FLOW_WEB_HOST !== void 0) {
214
+ layer.host = env.ISSUE_FLOW_WEB_HOST;
215
+ }
216
+ const refresh = readNumberEnv(env, "ISSUE_FLOW_WEB_REFRESH", warn);
217
+ if (refresh !== void 0) {
218
+ layer.refreshSeconds = refresh;
219
+ }
220
+ const logLimit = readNumberEnv(env, "ISSUE_FLOW_WEB_LOG_LIMIT", warn);
221
+ if (logLimit !== void 0) {
222
+ layer.logLimit = logLimit;
223
+ }
224
+ return layer;
225
+ }
226
+ async function readWebConfigFile(projectRoot, warn) {
227
+ const file = await readProjectConfigFile(projectRoot, warn);
228
+ const web = file?.web;
229
+ if (web === void 0) {
230
+ return {};
231
+ }
232
+ const result = webConfigSchema.partial().safeParse(web);
233
+ if (!result.success) {
234
+ warn(
235
+ `Ignoring "web" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
236
+ );
237
+ return {};
238
+ }
239
+ return result.data;
240
+ }
241
+ async function loadWebConfig(options = {}) {
242
+ const warn = options.warn ?? printWarning;
243
+ const cli = options.cli ?? webCliOverrides;
244
+ const env = options.env ?? process.env;
245
+ const fileLayer = await readWebConfigFile(options.projectRoot, warn);
246
+ const envLayer = readWebConfigEnv(env, warn);
247
+ const merged = { ...fileLayer, ...envLayer, ...cli };
248
+ const result = webConfigSchema.safeParse(merged);
249
+ if (result.success) {
250
+ return result.data;
251
+ }
252
+ warn(
253
+ `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
254
+ );
255
+ return webConfigSchema.parse({});
256
+ }
257
+ var issuesCliOverrides = {};
258
+ function setIssuesCliOverrides(overrides) {
259
+ issuesCliOverrides = overrides;
260
+ }
261
+ async function readIssuesConfigFile(projectRoot, warn) {
262
+ const file = await readProjectConfigFile(projectRoot, warn);
263
+ const issues = file?.issues;
264
+ if (issues === void 0) {
265
+ return {};
266
+ }
267
+ const result = issuesConfigSchema.partial().safeParse(issues);
268
+ if (!result.success) {
269
+ warn(
270
+ `Ignoring "issues" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
271
+ );
272
+ return {};
273
+ }
274
+ return result.data;
275
+ }
276
+ async function loadIssuesConfig(options = {}) {
277
+ const warn = options.warn ?? printWarning;
278
+ const cli = options.cli ?? issuesCliOverrides;
279
+ const fileLayer = await readIssuesConfigFile(options.projectRoot, warn);
280
+ const merged = { ...fileLayer, ...cli };
281
+ const result = issuesConfigSchema.safeParse(merged);
282
+ if (result.success) {
283
+ return result.data;
284
+ }
285
+ warn(
286
+ `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
287
+ );
288
+ return issuesConfigSchema.parse({});
289
+ }
290
+ function readPrReviewConfigEnv(env) {
291
+ const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;
292
+ return publisher === void 0 ? {} : { publisher };
293
+ }
294
+ async function readPrReviewConfigFile(projectRoot, warn) {
295
+ const file = await readProjectConfigFile(projectRoot, warn);
296
+ const prReview = file?.prReview;
297
+ if (prReview === void 0) {
298
+ return {};
299
+ }
300
+ const result = prReviewConfigSchema.partial().safeParse(prReview);
301
+ if (!result.success) {
302
+ warn(
303
+ `Ignoring "prReview" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
304
+ );
305
+ return {};
306
+ }
307
+ return result.data;
308
+ }
309
+ async function loadPrReviewConfig(options = {}) {
310
+ const warn = options.warn ?? printWarning;
311
+ const env = options.env ?? process.env;
312
+ const fileLayer = await readPrReviewConfigFile(options.projectRoot, warn);
313
+ const envLayer = readPrReviewConfigEnv(env);
314
+ const merged = { ...fileLayer, ...envLayer, ...options.cli ?? {} };
315
+ const result = prReviewConfigSchema.safeParse(merged);
316
+ if (result.success) {
317
+ return result.data;
318
+ }
319
+ warn(
320
+ `Invalid PR review configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
321
+ );
322
+ return prReviewConfigSchema.parse({});
323
+ }
324
+ var policyCliOverrides = {};
325
+ function setPolicyCliOverrides(overrides) {
326
+ policyCliOverrides = overrides;
327
+ }
328
+ function dropNullish(layer) {
329
+ const result = {};
330
+ for (const [key, value] of Object.entries(layer ?? {})) {
331
+ if (value !== void 0 && value !== null) {
332
+ result[key] = value;
333
+ }
334
+ }
335
+ return result;
336
+ }
337
+ function readPolicyConfigEnv(env, warn) {
338
+ const layer = {};
339
+ if (env.ISSUE_FLOW_POLICY !== void 0) {
340
+ layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_POLICY);
341
+ }
342
+ const budget = readNumberEnv(env, "ISSUE_FLOW_POLICY_CONTEXT_BUDGET", warn);
343
+ if (budget !== void 0) {
344
+ layer.contextBudget = budget;
345
+ }
346
+ const issues = {};
347
+ if (env.ISSUE_FLOW_POLICY_ISSUE_TITLE_CONVENTION !== void 0) {
348
+ issues.titleConvention = env.ISSUE_FLOW_POLICY_ISSUE_TITLE_CONVENTION;
349
+ }
350
+ if (Object.keys(issues).length > 0) layer.issues = issues;
351
+ const pullRequests = {};
352
+ if (env.ISSUE_FLOW_POLICY_BASE_BRANCH !== void 0) {
353
+ pullRequests.baseBranch = env.ISSUE_FLOW_POLICY_BASE_BRANCH;
354
+ }
355
+ if (env.ISSUE_FLOW_POLICY_PR_TITLE_CONVENTION !== void 0) {
356
+ pullRequests.titleConvention = env.ISSUE_FLOW_POLICY_PR_TITLE_CONVENTION;
357
+ }
358
+ if (Object.keys(pullRequests).length > 0) layer.pullRequests = pullRequests;
359
+ const git = {};
360
+ if (env.ISSUE_FLOW_POLICY_BRANCH_CONVENTION !== void 0) {
361
+ git.branchConvention = env.ISSUE_FLOW_POLICY_BRANCH_CONVENTION;
362
+ }
363
+ if (env.ISSUE_FLOW_POLICY_COMMIT_CONVENTION !== void 0) {
364
+ git.commitConvention = env.ISSUE_FLOW_POLICY_COMMIT_CONVENTION;
365
+ }
366
+ if (Object.keys(git).length > 0) layer.git = git;
367
+ const invalid = Object.entries(layer).find(
368
+ ([, value]) => typeof value === "object" && value !== null && Object.values(value).includes("")
369
+ );
370
+ if (invalid !== void 0) {
371
+ warn(`Ignoring empty ISSUE_FLOW_POLICY_* value in "${invalid[0]}".`);
372
+ }
373
+ return layer;
374
+ }
375
+ async function readPolicyConfigFile(projectRoot, warn) {
376
+ const file = await readProjectConfigFile(projectRoot, warn);
377
+ const policy = file?.policy;
378
+ if (policy === void 0) {
379
+ return {};
380
+ }
381
+ const result = policyConfigInputSchema.safeParse(policy);
382
+ if (!result.success) {
383
+ warn(
384
+ `Ignoring "policy" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
385
+ );
386
+ return {};
387
+ }
388
+ return result.data;
389
+ }
390
+ async function loadPolicyConfig(options = {}) {
391
+ const warn = options.warn ?? printWarning;
392
+ const cli = options.cli ?? policyCliOverrides;
393
+ const env = options.env ?? process.env;
394
+ const fileLayer = await readPolicyConfigFile(options.projectRoot, warn);
395
+ const envLayer = readPolicyConfigEnv(env, warn);
396
+ const merged = {
397
+ ...mergeConfigLayers({
398
+ project: dropNullish({ enabled: fileLayer.enabled, contextBudget: fileLayer.contextBudget }),
399
+ env: dropNullish({ enabled: envLayer.enabled, contextBudget: envLayer.contextBudget }),
400
+ cli: dropNullish({ enabled: cli.enabled, contextBudget: cli.contextBudget })
401
+ }),
402
+ discovery: mergeConfigLayers({
403
+ project: dropNullish(fileLayer.discovery),
404
+ env: dropNullish(envLayer.discovery),
405
+ cli: dropNullish(cli.discovery)
406
+ }),
407
+ issues: mergeConfigLayers({
408
+ project: dropNullish(fileLayer.issues),
409
+ env: dropNullish(envLayer.issues),
410
+ cli: dropNullish(cli.issues)
411
+ }),
412
+ pullRequests: mergeConfigLayers({
413
+ project: dropNullish(fileLayer.pullRequests),
414
+ env: dropNullish(envLayer.pullRequests),
415
+ cli: dropNullish(cli.pullRequests)
416
+ }),
417
+ git: mergeConfigLayers({
418
+ project: dropNullish(fileLayer.git),
419
+ env: dropNullish(envLayer.git),
420
+ cli: dropNullish(cli.git)
421
+ })
422
+ };
423
+ const result = policyConfigSchema.safeParse(merged);
424
+ if (result.success) {
425
+ return result.data;
426
+ }
427
+ warn(
428
+ `Invalid repository policy configuration (${result.error.issues[0]?.message ?? "invalid value"}); using defaults.`
429
+ );
430
+ return policyConfigSchema.parse({});
431
+ }
432
+ var resilienceCliOverrides = {};
433
+ function setResilienceCliOverrides(overrides) {
434
+ resilienceCliOverrides = overrides;
435
+ }
436
+ function mergeResilienceSection(layers) {
437
+ const merged = mergeConfigLayers({
438
+ global: layers[0],
439
+ project: layers[1],
440
+ env: layers[2],
441
+ cli: layers[3]
442
+ });
443
+ return Object.keys(merged).length > 0 ? merged : void 0;
444
+ }
445
+ function mergeResilienceRetry(layers) {
446
+ const merged = {};
447
+ for (const key of RETRY_CONFIG_KEYS) {
448
+ const entry = mergeResilienceSection(layers.map((layer) => layer?.[key]));
449
+ if (entry !== void 0) {
450
+ merged[key] = entry;
451
+ }
452
+ }
453
+ return Object.keys(merged).length > 0 ? merged : void 0;
454
+ }
455
+ function parseResilienceLayer(value, origin, warn) {
456
+ const result = resilienceConfigSchema.safeParse(value);
457
+ if (!result.success) {
458
+ warn(
459
+ `Ignoring "resilience" key of ${origin}: ${result.error.issues[0]?.message ?? "invalid value"}.`
460
+ );
461
+ return {};
462
+ }
463
+ return result.data;
464
+ }
465
+ async function readResilienceConfigFile(projectRoot, warn) {
466
+ const file = await readProjectConfigFile(projectRoot, warn);
467
+ const resilience = file?.resilience;
468
+ if (resilience === void 0) {
469
+ return {};
470
+ }
471
+ return parseResilienceLayer(resilience, PROJECT_CONFIG_FILENAME, warn);
472
+ }
473
+ function readResilienceConfigEnv(env, warn) {
474
+ const layer = {};
475
+ if (env.ISSUE_FLOW_RESILIENCE_PROFILE !== void 0) {
476
+ layer.profile = env.ISSUE_FLOW_RESILIENCE_PROFILE;
477
+ }
478
+ if (env.ISSUE_FLOW_RESILIENCE_FAILOVER_ON_AUTH !== void 0) {
479
+ layer.failoverOnAuth = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_FAILOVER_ON_AUTH);
480
+ }
481
+ const retry = env.ISSUE_FLOW_RESILIENCE_RETRY;
482
+ if (retry !== void 0) {
483
+ try {
484
+ layer.retry = JSON.parse(retry);
485
+ } catch {
486
+ warn("Ignoring ISSUE_FLOW_RESILIENCE_RETRY: invalid JSON.");
487
+ }
488
+ }
489
+ const providers = {};
490
+ if (env.ISSUE_FLOW_RESILIENCE_FAILOVER !== void 0) {
491
+ providers.failover = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_FAILOVER);
492
+ }
493
+ if (env.ISSUE_FLOW_RESILIENCE_PROVIDER_CHAIN !== void 0) {
494
+ providers.chain = env.ISSUE_FLOW_RESILIENCE_PROVIDER_CHAIN.split(",").map((name) => name.trim()).filter((name) => name !== "");
495
+ }
496
+ const cooldown = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_PROVIDER_COOLDOWN_MS", warn);
497
+ if (cooldown !== void 0) {
498
+ providers.cooldownMs = cooldown;
499
+ }
500
+ if (Object.keys(providers).length > 0) layer.providers = providers;
501
+ const queue = {};
502
+ if (env.ISSUE_FLOW_RESILIENCE_ON_ISSUE_FAILURE !== void 0) {
503
+ queue.onIssueFailure = env.ISSUE_FLOW_RESILIENCE_ON_ISSUE_FAILURE;
504
+ }
505
+ const maxIssueAttempts = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_MAX_ISSUE_ATTEMPTS", warn);
506
+ if (maxIssueAttempts !== void 0) {
507
+ queue.maxIssueAttempts = maxIssueAttempts;
508
+ }
509
+ if (Object.keys(queue).length > 0) layer.queue = queue;
510
+ const inactivity = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_INACTIVITY_TIMEOUT_MS", warn);
511
+ if (inactivity !== void 0) {
512
+ layer.watchdog = { inactivityTimeoutMs: inactivity };
513
+ }
514
+ const journal = {};
515
+ if (env.ISSUE_FLOW_RESILIENCE_JOURNAL !== void 0) {
516
+ journal.enabled = parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_JOURNAL);
517
+ }
518
+ const journalBytes = readNumberEnv(env, "ISSUE_FLOW_RESILIENCE_JOURNAL_MAX_BYTES", warn);
519
+ if (journalBytes !== void 0) {
520
+ journal.maxFileBytes = journalBytes;
521
+ }
522
+ if (Object.keys(journal).length > 0) layer.journal = journal;
523
+ if (env.ISSUE_FLOW_RESILIENCE_AUTO_DECOMPOSE !== void 0) {
524
+ layer.decompose = { auto: parseBooleanEnv(env.ISSUE_FLOW_RESILIENCE_AUTO_DECOMPOSE) };
525
+ }
526
+ if (Object.keys(layer).length === 0) {
527
+ return {};
528
+ }
529
+ return parseResilienceLayer(layer, "the ISSUE_FLOW_RESILIENCE_* environment", warn);
530
+ }
531
+ async function loadResilienceConfig(options = {}) {
532
+ const warn = options.warn ?? printWarning;
533
+ const env = options.env ?? process.env;
534
+ const cli = options.cli ?? resilienceCliOverrides;
535
+ const globalLayer = options.global ?? (await loadGlobalConfig({
536
+ env,
537
+ ...options.globalRoot === void 0 ? {} : { globalRoot: options.globalRoot },
538
+ warn
539
+ })).resilience ?? {};
540
+ const projectLayer = await readResilienceConfigFile(options.projectRoot, warn);
541
+ const envLayer = readResilienceConfigEnv(env, warn);
542
+ const layers = [globalLayer, projectLayer, envLayer, cli];
543
+ const scalars = mergeConfigLayers({
544
+ global: { profile: globalLayer.profile, failoverOnAuth: globalLayer.failoverOnAuth },
545
+ project: { profile: projectLayer.profile, failoverOnAuth: projectLayer.failoverOnAuth },
546
+ env: { profile: envLayer.profile, failoverOnAuth: envLayer.failoverOnAuth },
547
+ cli: { profile: cli.profile, failoverOnAuth: cli.failoverOnAuth }
548
+ });
549
+ const retry = mergeResilienceRetry(layers.map((layer) => layer.retry));
550
+ const providers = mergeResilienceSection(layers.map((layer) => layer.providers));
551
+ const queue = mergeResilienceSection(layers.map((layer) => layer.queue));
552
+ const watchdog = mergeResilienceSection(layers.map((layer) => layer.watchdog));
553
+ const journal = mergeResilienceSection(layers.map((layer) => layer.journal));
554
+ const decompose = mergeResilienceSection(layers.map((layer) => layer.decompose));
555
+ return {
556
+ ...scalars,
557
+ ...retry === void 0 ? {} : { retry },
558
+ ...providers === void 0 ? {} : { providers },
559
+ ...queue === void 0 ? {} : { queue },
560
+ ...watchdog === void 0 ? {} : { watchdog },
561
+ ...journal === void 0 ? {} : { journal },
562
+ ...decompose === void 0 ? {} : { decompose }
563
+ };
564
+ }
565
+ var activeResilienceConfig = {};
566
+ function getActiveResilienceConfig() {
567
+ return activeResilienceConfig;
568
+ }
569
+ function setActiveResilienceConfig(config) {
570
+ activeResilienceConfig = config;
571
+ }
572
+ async function initResilienceConfig(options = {}) {
573
+ try {
574
+ activeResilienceConfig = await loadResilienceConfig(options);
575
+ } catch {
576
+ activeResilienceConfig = {};
577
+ }
578
+ return activeResilienceConfig;
579
+ }
580
+
581
+ export {
582
+ DEFAULTS,
583
+ createConfig,
584
+ resolvePaths,
585
+ getInstallHint,
586
+ validateDependencies,
587
+ PROJECT_CONFIG_FILENAME,
588
+ WEB_CONFIG_FILENAME,
589
+ GLOBAL_CONFIG_FILENAME,
590
+ loadGlobalConfig,
591
+ mergeConfigLayers,
592
+ setWebCliOverrides,
593
+ loadWebConfig,
594
+ setIssuesCliOverrides,
595
+ loadIssuesConfig,
596
+ loadPrReviewConfig,
597
+ setPolicyCliOverrides,
598
+ loadPolicyConfig,
599
+ setResilienceCliOverrides,
600
+ loadResilienceConfig,
601
+ getActiveResilienceConfig,
602
+ setActiveResilienceConfig,
603
+ initResilienceConfig
604
+ };
605
+ //# sourceMappingURL=chunk-42PJFMAR.js.map