issue-flow 0.17.0 → 0.19.1

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 (239) hide show
  1. package/README.md +34 -100
  2. package/dist/agent-EWKA7357.js +32 -0
  3. package/dist/{analyze-6M3KEOX7.js → analyze-Z7ODC27F.js} +42 -41
  4. package/dist/analyze-Z7ODC27F.js.map +1 -0
  5. package/dist/{apply-ADB3ZK7W.js → apply-VNSWQS6O.js} +22 -24
  6. package/dist/apply-VNSWQS6O.js.map +1 -0
  7. package/dist/artifacts-AMJQJFFV.js +82 -0
  8. package/dist/artifacts-AMJQJFFV.js.map +1 -0
  9. package/dist/{bench-FM7I7EIV.js → bench-ZJEIACUK.js} +42 -42
  10. package/dist/{chunk-RYOUZ6EK.js → chunk-23VHVVKW.js} +3 -3
  11. package/dist/chunk-2EYLOS5I.js +99 -0
  12. package/dist/chunk-2EYLOS5I.js.map +1 -0
  13. package/dist/{chunk-ANI2NTR4.js → chunk-2EZW4X57.js} +28 -25
  14. package/dist/chunk-2EZW4X57.js.map +1 -0
  15. package/dist/{chunk-E6KXCV3T.js → chunk-2Q6PG3MT.js} +15 -15
  16. package/dist/chunk-2Q6PG3MT.js.map +1 -0
  17. package/dist/{chunk-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
  18. package/dist/{chunk-LPWPFIIB.js → chunk-2YYP7AE6.js} +14 -16
  19. package/dist/{chunk-LPWPFIIB.js.map → chunk-2YYP7AE6.js.map} +1 -1
  20. package/dist/chunk-3JD25HHJ.js +278 -0
  21. package/dist/chunk-3JD25HHJ.js.map +1 -0
  22. package/dist/{chunk-ISZ54SVE.js → chunk-46S7APLQ.js} +41 -17
  23. package/dist/chunk-46S7APLQ.js.map +1 -0
  24. package/dist/chunk-6AOZCWN2.js +21 -0
  25. package/dist/chunk-6AOZCWN2.js.map +1 -0
  26. package/dist/{chunk-QPGEFLMY.js → chunk-7CMVL4X6.js} +7 -7
  27. package/dist/chunk-7MJGYPHF.js +1571 -0
  28. package/dist/chunk-7MJGYPHF.js.map +1 -0
  29. package/dist/chunk-7ZZUSMBJ.js +35 -0
  30. package/dist/chunk-7ZZUSMBJ.js.map +1 -0
  31. package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
  32. package/dist/{chunk-DGRTJD5R.js → chunk-DXH4TQRB.js} +7 -7
  33. package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
  34. package/dist/chunk-E2H3JV2E.js.map +1 -0
  35. package/dist/{chunk-YUNBOUQH.js → chunk-ERAG5IQB.js} +8 -8
  36. package/dist/{chunk-D6ZBGJ3L.js → chunk-F2NFJ27Z.js} +130 -36
  37. package/dist/chunk-F2NFJ27Z.js.map +1 -0
  38. package/dist/{chunk-SOM4QA6C.js → chunk-GD7JZMSJ.js} +93 -18
  39. package/dist/chunk-GD7JZMSJ.js.map +1 -0
  40. package/dist/{chunk-YII4U7ZD.js → chunk-HEHHQU4G.js} +70 -81
  41. package/dist/chunk-HEHHQU4G.js.map +1 -0
  42. package/dist/{chunk-KZ5EY5XX.js → chunk-HHXWAWU6.js} +159 -114
  43. package/dist/chunk-HHXWAWU6.js.map +1 -0
  44. package/dist/{chunk-SGTTR4XW.js → chunk-HWWB22HC.js} +152 -100
  45. package/dist/chunk-HWWB22HC.js.map +1 -0
  46. package/dist/chunk-IMB6FA2F.js +673 -0
  47. package/dist/chunk-IMB6FA2F.js.map +1 -0
  48. package/dist/{chunk-6YQT3SSM.js → chunk-IQYXXFRC.js} +22 -6
  49. package/dist/chunk-IQYXXFRC.js.map +1 -0
  50. package/dist/chunk-J6VJ5M2U.js +1201 -0
  51. package/dist/chunk-J6VJ5M2U.js.map +1 -0
  52. package/dist/{chunk-B3TSS7BT.js → chunk-KDQRNVBZ.js} +3 -3
  53. package/dist/{chunk-A4H7P7T7.js → chunk-LRWIP7QS.js} +41 -26
  54. package/dist/chunk-LRWIP7QS.js.map +1 -0
  55. package/dist/{chunk-DV7HUC4Z.js → chunk-LYC57OXF.js} +20 -117
  56. package/dist/chunk-LYC57OXF.js.map +1 -0
  57. package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
  58. package/dist/chunk-MAJ6QDRL.js.map +1 -0
  59. package/dist/{chunk-HJBF4WD2.js → chunk-MHA7Q3KU.js} +288 -108
  60. package/dist/chunk-MHA7Q3KU.js.map +1 -0
  61. package/dist/{chunk-UK4E2FUA.js → chunk-MQTVMB7W.js} +103 -76
  62. package/dist/chunk-MQTVMB7W.js.map +1 -0
  63. package/dist/chunk-NP47HRX2.js +136 -0
  64. package/dist/chunk-NP47HRX2.js.map +1 -0
  65. package/dist/{chunk-MI5TREN3.js → chunk-NYDAHE3Y.js} +52 -46
  66. package/dist/chunk-NYDAHE3Y.js.map +1 -0
  67. package/dist/{chunk-UWDCIFTP.js → chunk-P7ZYOC23.js} +41 -57
  68. package/dist/chunk-P7ZYOC23.js.map +1 -0
  69. package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
  70. package/dist/{chunk-2SUFAE6X.js → chunk-PHPAK2L6.js} +44 -33
  71. package/dist/{chunk-2SUFAE6X.js.map → chunk-PHPAK2L6.js.map} +1 -1
  72. package/dist/{chunk-PPZ3K4YM.js → chunk-PRGPSNGA.js} +2 -2
  73. package/dist/{chunk-32JSYXEK.js → chunk-RGFMQFX7.js} +9 -23
  74. package/dist/{chunk-32JSYXEK.js.map → chunk-RGFMQFX7.js.map} +1 -1
  75. package/dist/{chunk-YVPZUN6X.js → chunk-TJVX42KY.js} +335 -38
  76. package/dist/chunk-TJVX42KY.js.map +1 -0
  77. package/dist/{chunk-RCZJQUTC.js → chunk-UDRAD7MF.js} +60 -27
  78. package/dist/chunk-UDRAD7MF.js.map +1 -0
  79. package/dist/{chunk-HY5HLFDU.js → chunk-UHDXXLYH.js} +148 -135
  80. package/dist/chunk-UHDXXLYH.js.map +1 -0
  81. package/dist/{chunk-RNFUVKC3.js → chunk-UPAAZU4W.js} +30 -13
  82. package/dist/chunk-UPAAZU4W.js.map +1 -0
  83. package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
  84. package/dist/{chunk-HLAPOUEM.js → chunk-WB2FVIUS.js} +44 -12
  85. package/dist/chunk-WB2FVIUS.js.map +1 -0
  86. package/dist/{chunk-VE3IYNDN.js → chunk-WPHC6JBR.js} +9 -9
  87. package/dist/chunk-WPHC6JBR.js.map +1 -0
  88. package/dist/{chunk-KZXQWC7U.js → chunk-XHCP6ZNO.js} +201 -64
  89. package/dist/chunk-XHCP6ZNO.js.map +1 -0
  90. package/dist/{chunk-7F7LGMVO.js → chunk-XKR3VD2Z.js} +12 -12
  91. package/dist/{chunk-7F7LGMVO.js.map → chunk-XKR3VD2Z.js.map} +1 -1
  92. package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
  93. package/dist/chunk-XNK5UN2D.js.map +1 -0
  94. package/dist/{chunk-Z5O2XBWA.js → chunk-XQLNZW7I.js} +40 -30
  95. package/dist/chunk-XQLNZW7I.js.map +1 -0
  96. package/dist/{chunk-QMIQR7EE.js → chunk-ZAYATXJD.js} +32 -316
  97. package/dist/chunk-ZAYATXJD.js.map +1 -0
  98. package/dist/cli.js +128 -60
  99. package/dist/cli.js.map +1 -1
  100. package/dist/compat-YPDZB34U.js +24 -0
  101. package/dist/{config-KGZUPAUP.js → config-56B4OHZE.js} +20 -17
  102. package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
  103. package/dist/{conventions-RYN7OXJN.js → conventions-DW2CM5I3.js} +20 -16
  104. package/dist/{conventions-RYN7OXJN.js.map → conventions-DW2CM5I3.js.map} +1 -1
  105. package/dist/db-5NU77PJA.js +264 -0
  106. package/dist/db-5NU77PJA.js.map +1 -0
  107. package/dist/diagnostics-UCTS2VUF.js +25 -0
  108. package/dist/execute-R7AVOLNG.js +38 -0
  109. package/dist/{generate-CX6KNHZS.js → generate-O7GUXLN4.js} +46 -43
  110. package/dist/generate-O7GUXLN4.js.map +1 -0
  111. package/dist/{git-A2IP32PQ.js → git-LCG45YXD.js} +2 -3
  112. package/dist/history-6GSURU3H.js +101 -0
  113. package/dist/history-6GSURU3H.js.map +1 -0
  114. package/dist/init-DD6DBRC5.js +28 -0
  115. package/dist/{operations-CAKIT2BO.js → operations-HU5ZFEBA.js} +78 -52
  116. package/dist/operations-HU5ZFEBA.js.map +1 -0
  117. package/dist/{permissions-G4XCAESF.js → permissions-NNNSRC4P.js} +5 -6
  118. package/dist/plan-XR6B7EM3.js +38 -0
  119. package/dist/{policy-WX6O2JID.js → policy-RFJOJQL6.js} +17 -15
  120. package/dist/{policy-WX6O2JID.js.map → policy-RFJOJQL6.js.map} +1 -1
  121. package/dist/pr-OSCNJCOO.js +42 -0
  122. package/dist/pr-review-IKIYHFBO.js +33 -0
  123. package/dist/prd-HFDZJJQR.js +37 -0
  124. package/dist/{ps-76L6ZAZL.js → ps-AKRHGPSR.js} +26 -15
  125. package/dist/ps-AKRHGPSR.js.map +1 -0
  126. package/dist/{recorder-N7U66HCO.js → recorder-T7426CKV.js} +11 -7
  127. package/dist/registry-DWRKD65A.js +17 -0
  128. package/dist/repository-TABBRW2C.js +80 -0
  129. package/dist/resume-GDXKK5XP.js +278 -0
  130. package/dist/resume-GDXKK5XP.js.map +1 -0
  131. package/dist/review-JJHMQA2O.js +38 -0
  132. package/dist/routing-FPNUVE7T.js +35 -0
  133. package/dist/run-RLCURLLL.js +61 -0
  134. package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
  135. package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
  136. package/dist/{state-manager-UPHO2EA2.js → state-manager-IGNTD4AB.js} +9 -4
  137. package/dist/state-manager-IGNTD4AB.js.map +1 -0
  138. package/dist/{usage-U7QNGCPK.js → usage-XW27AL5K.js} +69 -63
  139. package/dist/usage-XW27AL5K.js.map +1 -0
  140. package/dist/web-NCDBVZ5Y.js +205 -0
  141. package/dist/web-NCDBVZ5Y.js.map +1 -0
  142. package/package.json +20 -7
  143. package/prompts/analyze.md +16 -19
  144. package/prompts/execute.md +73 -144
  145. package/prompts/generate.md +23 -10
  146. package/prompts/plan.md +32 -60
  147. package/prompts/pr-review.md +58 -40
  148. package/prompts/pr.md +50 -16
  149. package/prompts/prd.md +26 -19
  150. package/prompts/review.md +41 -18
  151. package/web/AGENTS.md +115 -7
  152. package/web/public/app.css +393 -245
  153. package/web/public/app.js +212 -143
  154. package/web/public/index.html +106 -78
  155. package/dist/agent-TB6W7PT7.js +0 -30
  156. package/dist/analyze-6M3KEOX7.js.map +0 -1
  157. package/dist/apply-ADB3ZK7W.js.map +0 -1
  158. package/dist/chunk-6YQT3SSM.js.map +0 -1
  159. package/dist/chunk-A4H7P7T7.js.map +0 -1
  160. package/dist/chunk-ANI2NTR4.js.map +0 -1
  161. package/dist/chunk-CRGIQFUQ.js.map +0 -1
  162. package/dist/chunk-D6ZBGJ3L.js.map +0 -1
  163. package/dist/chunk-DV7HUC4Z.js.map +0 -1
  164. package/dist/chunk-E6KXCV3T.js.map +0 -1
  165. package/dist/chunk-HAKDLR6N.js.map +0 -1
  166. package/dist/chunk-HJBF4WD2.js.map +0 -1
  167. package/dist/chunk-HLAPOUEM.js.map +0 -1
  168. package/dist/chunk-HY5HLFDU.js.map +0 -1
  169. package/dist/chunk-ICM463EO.js.map +0 -1
  170. package/dist/chunk-ISZ54SVE.js.map +0 -1
  171. package/dist/chunk-KZ5EY5XX.js.map +0 -1
  172. package/dist/chunk-KZXQWC7U.js.map +0 -1
  173. package/dist/chunk-MI5TREN3.js.map +0 -1
  174. package/dist/chunk-QMIQR7EE.js.map +0 -1
  175. package/dist/chunk-RCZJQUTC.js.map +0 -1
  176. package/dist/chunk-RNFUVKC3.js.map +0 -1
  177. package/dist/chunk-SGTTR4XW.js.map +0 -1
  178. package/dist/chunk-SOM4QA6C.js.map +0 -1
  179. package/dist/chunk-UK4E2FUA.js.map +0 -1
  180. package/dist/chunk-UWDCIFTP.js.map +0 -1
  181. package/dist/chunk-VE3IYNDN.js.map +0 -1
  182. package/dist/chunk-WCCZJL7W.js +0 -141
  183. package/dist/chunk-WCCZJL7W.js.map +0 -1
  184. package/dist/chunk-XEYH6ZZI.js +0 -289
  185. package/dist/chunk-XEYH6ZZI.js.map +0 -1
  186. package/dist/chunk-XZUEFTUP.js +0 -243
  187. package/dist/chunk-XZUEFTUP.js.map +0 -1
  188. package/dist/chunk-YII4U7ZD.js.map +0 -1
  189. package/dist/chunk-YVPZUN6X.js.map +0 -1
  190. package/dist/chunk-Z5O2XBWA.js.map +0 -1
  191. package/dist/diagnostics-HTCWF7F4.js +0 -23
  192. package/dist/execute-QL3ZQIAP.js +0 -37
  193. package/dist/generate-CX6KNHZS.js.map +0 -1
  194. package/dist/init-PDVQDRS6.js +0 -24
  195. package/dist/operations-CAKIT2BO.js.map +0 -1
  196. package/dist/plan-PRORGS3L.js +0 -34
  197. package/dist/pr-27RMQI5F.js +0 -39
  198. package/dist/pr-review-VNESMAMT.js +0 -32
  199. package/dist/prd-ZNC4T5BS.js +0 -33
  200. package/dist/ps-76L6ZAZL.js.map +0 -1
  201. package/dist/registry-XLHHYLTR.js +0 -15
  202. package/dist/resume-VLWIE264.js +0 -244
  203. package/dist/resume-VLWIE264.js.map +0 -1
  204. package/dist/review-7CREJDKB.js +0 -35
  205. package/dist/routing-VCDYHSXA.js +0 -33
  206. package/dist/run-3MPORLF5.js +0 -56
  207. package/dist/usage-U7QNGCPK.js.map +0 -1
  208. package/dist/web-HUNDHCJ4.js +0 -172
  209. package/dist/web-HUNDHCJ4.js.map +0 -1
  210. /package/dist/{agent-TB6W7PT7.js.map → agent-EWKA7357.js.map} +0 -0
  211. /package/dist/{bench-FM7I7EIV.js.map → bench-ZJEIACUK.js.map} +0 -0
  212. /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
  213. /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
  214. /package/dist/{chunk-QPGEFLMY.js.map → chunk-7CMVL4X6.js.map} +0 -0
  215. /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
  216. /package/dist/{chunk-DGRTJD5R.js.map → chunk-DXH4TQRB.js.map} +0 -0
  217. /package/dist/{chunk-YUNBOUQH.js.map → chunk-ERAG5IQB.js.map} +0 -0
  218. /package/dist/{chunk-B3TSS7BT.js.map → chunk-KDQRNVBZ.js.map} +0 -0
  219. /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
  220. /package/dist/{chunk-PPZ3K4YM.js.map → chunk-PRGPSNGA.js.map} +0 -0
  221. /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
  222. /package/dist/{config-KGZUPAUP.js.map → compat-YPDZB34U.js.map} +0 -0
  223. /package/dist/{contract-JH2WBIO6.js.map → config-56B4OHZE.js.map} +0 -0
  224. /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
  225. /package/dist/{execute-QL3ZQIAP.js.map → diagnostics-UCTS2VUF.js.map} +0 -0
  226. /package/dist/{git-A2IP32PQ.js.map → execute-R7AVOLNG.js.map} +0 -0
  227. /package/dist/{init-PDVQDRS6.js.map → git-LCG45YXD.js.map} +0 -0
  228. /package/dist/{permissions-G4XCAESF.js.map → init-DD6DBRC5.js.map} +0 -0
  229. /package/dist/{plan-PRORGS3L.js.map → permissions-NNNSRC4P.js.map} +0 -0
  230. /package/dist/{pr-27RMQI5F.js.map → plan-XR6B7EM3.js.map} +0 -0
  231. /package/dist/{pr-review-VNESMAMT.js.map → pr-OSCNJCOO.js.map} +0 -0
  232. /package/dist/{prd-ZNC4T5BS.js.map → pr-review-IKIYHFBO.js.map} +0 -0
  233. /package/dist/{recorder-N7U66HCO.js.map → prd-HFDZJJQR.js.map} +0 -0
  234. /package/dist/{registry-XLHHYLTR.js.map → recorder-T7426CKV.js.map} +0 -0
  235. /package/dist/{review-7CREJDKB.js.map → registry-DWRKD65A.js.map} +0 -0
  236. /package/dist/{routing-VCDYHSXA.js.map → repository-TABBRW2C.js.map} +0 -0
  237. /package/dist/{run-3MPORLF5.js.map → review-JJHMQA2O.js.map} +0 -0
  238. /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-FPNUVE7T.js.map} +0 -0
  239. /package/dist/{state-manager-UPHO2EA2.js.map → run-RLCURLLL.js.map} +0 -0
@@ -1,13 +1,288 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- classify,
4
- requiresHumanAction
5
- } from "./chunk-XEYH6ZZI.js";
6
2
 
7
3
  // src/utils/shell.ts
8
- import { basename } from "path";
4
+ import { basename } from "node:path";
9
5
  import { execa } from "execa";
10
6
 
7
+ // src/resilience/errors.ts
8
+ var RETRYABLE_KINDS = /* @__PURE__ */ new Set([
9
+ "network",
10
+ "timeout",
11
+ "stalled",
12
+ "rate_limit",
13
+ "provider_down",
14
+ "provider_crash"
15
+ ]);
16
+ var HUMAN_ACTION_KINDS = /* @__PURE__ */ new Set([
17
+ "authentication",
18
+ "configuration",
19
+ "repository_state",
20
+ "task_execution"
21
+ ]);
22
+ function isRetryableKind(kind) {
23
+ return RETRYABLE_KINDS.has(kind);
24
+ }
25
+ function requiresHumanAction(kind) {
26
+ return HUMAN_ACTION_KINDS.has(kind);
27
+ }
28
+ var ClassifiedError = class extends Error {
29
+ failure;
30
+ action;
31
+ constructor(message, failure, action) {
32
+ super(message);
33
+ this.name = "ClassifiedError";
34
+ this.failure = failure;
35
+ this.action = action;
36
+ }
37
+ };
38
+ function failureOf(error) {
39
+ return error instanceof ClassifiedError ? error.failure : null;
40
+ }
41
+ function actionOf(error) {
42
+ return error instanceof ClassifiedError ? error.action ?? null : null;
43
+ }
44
+ var ERRNO_KINDS = {
45
+ ENOTFOUND: "network",
46
+ EAI_AGAIN: "network",
47
+ ECONNRESET: "network",
48
+ ECONNREFUSED: "network",
49
+ ECONNABORTED: "network",
50
+ EHOSTUNREACH: "network",
51
+ ENETUNREACH: "network",
52
+ ENETDOWN: "network",
53
+ EPIPE: "network",
54
+ ETIMEDOUT: "timeout",
55
+ ENOENT: "configuration",
56
+ EACCES: "configuration",
57
+ EPERM: "configuration"
58
+ };
59
+ function kindFromErrno(errno) {
60
+ if (!errno) return void 0;
61
+ return ERRNO_KINDS[errno.toUpperCase()];
62
+ }
63
+ function kindFromHttpStatus(status, lowered) {
64
+ if (status === void 0 || status < 400) return void 0;
65
+ if (status === 429) return "rate_limit";
66
+ if (status === 401) return "authentication";
67
+ if (status === 403)
68
+ return matchesAny(lowered, RATE_LIMIT_PATTERNS) ? "rate_limit" : "authentication";
69
+ if (status === 408) return "timeout";
70
+ if (status >= 500) return "provider_down";
71
+ return "configuration";
72
+ }
73
+ var CRASH_SIGNALS = /* @__PURE__ */ new Set(["SIGKILL", "SIGABRT", "SIGSEGV", "SIGBUS"]);
74
+ function kindFromTermination(signal) {
75
+ if (signal.stalled === true) return "stalled";
76
+ if (signal.timedOut === true) return "timeout";
77
+ const name = signal.signal?.toUpperCase();
78
+ if (!name) return void 0;
79
+ if (name === "SIGTERM") return "timeout";
80
+ if (CRASH_SIGNALS.has(name)) return "provider_crash";
81
+ return void 0;
82
+ }
83
+ var EXIT_CODE_KINDS = {
84
+ 75: "provider_down",
85
+ // EX_TEMPFAIL
86
+ 126: "configuration",
87
+ // found, not executable
88
+ 127: "configuration",
89
+ // command not found
90
+ 137: "provider_crash",
91
+ // 128 + SIGKILL, typically the OOM killer
92
+ 139: "provider_crash"
93
+ // 128 + SIGSEGV
94
+ };
95
+ function kindFromExitCode(exitCode) {
96
+ if (exitCode === null || exitCode === void 0) return void 0;
97
+ return EXIT_CODE_KINDS[exitCode];
98
+ }
99
+ var RATE_LIMIT_PATTERNS = [
100
+ "rate limit",
101
+ "rate-limit",
102
+ "ratelimit",
103
+ "too many requests",
104
+ "http 429"
105
+ ];
106
+ var TEXT_RULES = [
107
+ { kind: "rate_limit", patterns: RATE_LIMIT_PATTERNS },
108
+ {
109
+ kind: "authentication",
110
+ patterns: [
111
+ "authentication failed",
112
+ "authentication_error",
113
+ "gh auth login",
114
+ "not logged into",
115
+ "bad credentials",
116
+ "invalid api key",
117
+ "invalid_api_key",
118
+ "token expired",
119
+ "expired token",
120
+ "unauthorized",
121
+ "http 401",
122
+ "http 403"
123
+ ]
124
+ },
125
+ {
126
+ kind: "network",
127
+ patterns: [
128
+ "connection reset",
129
+ "connection refused",
130
+ "connection aborted",
131
+ "network error",
132
+ "network unavailable",
133
+ "temporary failure",
134
+ "econnreset",
135
+ "econnrefused",
136
+ "enotfound",
137
+ "eai_again",
138
+ "socket hang up",
139
+ // What Go prints, and therefore what `gh` prints: its network errors
140
+ // never mention "connection reset", they mention the resolver.
141
+ "no such host",
142
+ "dial tcp",
143
+ "i/o timeout",
144
+ "tls handshake timeout",
145
+ "server misbehaving",
146
+ "error connecting to"
147
+ ]
148
+ },
149
+ // Before the timeout rule: a stall *is* a kind of timeout, and the specific
150
+ // reading is the useful one — it has its own budget and its own escalation.
151
+ { kind: "stalled", patterns: ["produced no output for", "(stalled)"] },
152
+ { kind: "timeout", patterns: ["timed out", "timeout", "etimedout"] },
153
+ {
154
+ kind: "provider_down",
155
+ patterns: [
156
+ "service unavailable",
157
+ "temporarily unavailable",
158
+ "overloaded",
159
+ "bad gateway",
160
+ "gateway timeout",
161
+ "internal server error",
162
+ "http 500",
163
+ "http 502",
164
+ "http 503",
165
+ "http 504"
166
+ ]
167
+ },
168
+ {
169
+ kind: "provider_crash",
170
+ patterns: ["segmentation fault", "core dumped", "out of memory", "killed by signal"]
171
+ },
172
+ {
173
+ kind: "repository_state",
174
+ patterns: [
175
+ "unmerged paths",
176
+ "needs merge",
177
+ "automatic merge failed",
178
+ "rebase in progress",
179
+ "you are in the middle of",
180
+ "cherry-pick is in progress",
181
+ "not a git repository"
182
+ ]
183
+ },
184
+ {
185
+ kind: "configuration",
186
+ patterns: [
187
+ "command not found",
188
+ "unknown flag",
189
+ "unknown option",
190
+ "no such file or directory",
191
+ "permission check failed",
192
+ "user denied permission",
193
+ "waiting for human input",
194
+ "status: waiting",
195
+ "below the minimum",
196
+ "prompt exceeds",
197
+ "nativetimeout",
198
+ "agy is not installed"
199
+ ]
200
+ },
201
+ {
202
+ kind: "task_execution",
203
+ patterns: [
204
+ "test failed",
205
+ "tests failed",
206
+ "failed tests",
207
+ "failing test",
208
+ "assertion failed",
209
+ "assertionerror",
210
+ "expect(received)",
211
+ "typecheck failed",
212
+ "npm err! test failed",
213
+ "lint failed",
214
+ "build failed",
215
+ "compilation failed",
216
+ "syntaxerror",
217
+ "typeerror",
218
+ "referenceerror",
219
+ // What a runner actually prints: "Tests 3 failed | 41 passed",
220
+ // "Test Files 1 failed (12)", "Tests: 2 failed, 8 total".
221
+ /\b\d+\s+failed\b/
222
+ ]
223
+ }
224
+ ];
225
+ function matchesAny(lowered, patterns) {
226
+ return patterns.some(
227
+ (pattern) => typeof pattern === "string" ? lowered.includes(pattern) : pattern.test(lowered)
228
+ );
229
+ }
230
+ function kindFromText(lowered) {
231
+ if (!lowered) return void 0;
232
+ for (const rule of TEXT_RULES) {
233
+ if (matchesAny(lowered, rule.patterns)) return rule.kind;
234
+ }
235
+ return void 0;
236
+ }
237
+ var RETRY_AFTER_IN_TEXT = /retry[\s-]?after:?\s*(\d+)/i;
238
+ function parseRetryAfter(value, now) {
239
+ if (value === void 0) return void 0;
240
+ if (typeof value === "number")
241
+ return Number.isFinite(value) && value >= 0 ? value * 1e3 : void 0;
242
+ const trimmed = value.trim();
243
+ if (trimmed === "") return void 0;
244
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
245
+ const at = Date.parse(trimmed);
246
+ if (Number.isNaN(at)) return void 0;
247
+ return at > now ? at - now : void 0;
248
+ }
249
+ function resolveRetryAfterMs(signal, text, now) {
250
+ const explicit = parseRetryAfter(signal.retryAfter, now);
251
+ if (explicit !== void 0) return explicit;
252
+ const inText = RETRY_AFTER_IN_TEXT.exec(text);
253
+ return inText ? Number(inText[1]) * 1e3 : void 0;
254
+ }
255
+ function combineOutput(signal) {
256
+ return [signal.stderr, signal.stdout].filter((part) => part && part.trim() !== "").join("\n");
257
+ }
258
+ function describe(signal, text) {
259
+ const trimmed = text.trim();
260
+ if (trimmed !== "") return trimmed;
261
+ if (signal.errno) return `${signal.source} failed with ${signal.errno}`;
262
+ if (signal.httpStatus !== void 0)
263
+ return `${signal.source} responded HTTP ${signal.httpStatus}`;
264
+ if (signal.timedOut === true) return `${signal.source} timed out`;
265
+ if (signal.signal) return `${signal.source} was terminated by ${signal.signal}`;
266
+ if (signal.exitCode !== null && signal.exitCode !== void 0) {
267
+ return `${signal.source} exited with code ${signal.exitCode}`;
268
+ }
269
+ return `${signal.source} failed for an unreported reason`;
270
+ }
271
+ function classify(signal, options = {}) {
272
+ const now = options.now?.() ?? Date.now();
273
+ const text = combineOutput(signal);
274
+ const lowered = text.toLowerCase();
275
+ const kind = kindFromErrno(signal.errno) ?? kindFromHttpStatus(signal.httpStatus, lowered) ?? kindFromTermination(signal) ?? kindFromExitCode(signal.exitCode) ?? kindFromText(lowered) ?? "unknown";
276
+ const retryAfterMs = resolveRetryAfterMs(signal, text, now);
277
+ return {
278
+ kind,
279
+ message: describe(signal, text),
280
+ retryable: isRetryableKind(kind),
281
+ source: signal.source,
282
+ ...retryAfterMs === void 0 ? {} : { retryAfterMs }
283
+ };
284
+ }
285
+
11
286
  // src/resilience/policy.ts
12
287
  var CONFIG_KEYS = {
13
288
  network: "network",
@@ -138,14 +413,14 @@ function abortableDelay(ms, options = {}) {
138
413
  const { signal } = options;
139
414
  if (signal?.aborted === true) return Promise.resolve(false);
140
415
  if (ms <= 0) return Promise.resolve(true);
141
- return new Promise((resolve) => {
416
+ return new Promise((resolve2) => {
142
417
  const onAbort = () => {
143
418
  clearTimeout(timer);
144
- resolve(false);
419
+ resolve2(false);
145
420
  };
146
421
  const timer = setTimeout(() => {
147
422
  signal?.removeEventListener("abort", onAbort);
148
- resolve(true);
423
+ resolve2(true);
149
424
  }, ms);
150
425
  signal?.addEventListener("abort", onAbort, { once: true });
151
426
  });
@@ -201,7 +476,7 @@ function inferSource(command) {
201
476
  }
202
477
  function diagnoseCommandFailure(command, args, result) {
203
478
  if (result.exitCode === 0) return;
204
- void import("./diagnostics-HTCWF7F4.js").then(({ writeDiagnostic }) => {
479
+ void import("./diagnostics-UCTS2VUF.js").then(({ writeDiagnostic }) => {
205
480
  writeDiagnostic({
206
481
  level: "warning",
207
482
  message: `Command failed: ${basename(command)}`,
@@ -354,6 +629,49 @@ async function run(command, args = [], options) {
354
629
  return result;
355
630
  }
356
631
 
632
+ // src/storage/project-identity.ts
633
+ import { createHash } from "node:crypto";
634
+ import { basename as basename2, resolve } from "node:path";
635
+ var SLUG_MAX_LENGTH = 32;
636
+ var HASH_LENGTH = 12;
637
+ var FALLBACK_SLUG = "project";
638
+ function slugify(name) {
639
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, SLUG_MAX_LENGTH).replace(/-+$/g, "");
640
+ return slug === "" ? FALLBACK_SLUG : slug;
641
+ }
642
+ function normalizeRemoteUrl(url) {
643
+ if (typeof url !== "string") return null;
644
+ const trimmed = url.trim();
645
+ if (trimmed === "") return null;
646
+ let authority;
647
+ let path;
648
+ const scheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.exec(trimmed);
649
+ if (scheme) {
650
+ const rest = trimmed.slice(scheme[0].length);
651
+ const slash = rest.indexOf("/");
652
+ if (slash === -1) return null;
653
+ authority = rest.slice(0, slash);
654
+ path = rest.slice(slash + 1);
655
+ } else {
656
+ const colon = trimmed.indexOf(":");
657
+ if (colon === -1) return null;
658
+ authority = trimmed.slice(0, colon);
659
+ path = trimmed.slice(colon + 1);
660
+ }
661
+ const at = authority.lastIndexOf("@");
662
+ if (at !== -1) authority = authority.slice(at + 1);
663
+ const host = authority.replace(/:\d+$/, "").toLowerCase();
664
+ if (host === "") return null;
665
+ const normalizedPath = path.replace(/[?#].*$/, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
666
+ return normalizedPath === "" ? null : `${host}/${normalizedPath}`;
667
+ }
668
+ function projectIdFromRemote(remote, projectRoot) {
669
+ const seed = remote ? `remote:${remote}` : `path:${resolve(projectRoot)}`;
670
+ const name = remote ? remote.split("/").pop() ?? "" : basename2(resolve(projectRoot));
671
+ const hash = createHash("sha256").update(seed).digest("hex").slice(0, HASH_LENGTH);
672
+ return `${slugify(name)}-${hash}`;
673
+ }
674
+
357
675
  // src/utils/git.ts
358
676
  async function getProjectRoot() {
359
677
  const result = await run("git", ["rev-parse", "--show-toplevel"]);
@@ -421,33 +739,6 @@ async function getHeadCommit(cwd) {
421
739
  const hash = result.stdout.trim();
422
740
  return hash === "" ? null : hash;
423
741
  }
424
- function normalizeRemoteUrl(url) {
425
- if (typeof url !== "string") return null;
426
- const trimmed = url.trim();
427
- if (trimmed === "") return null;
428
- let authority;
429
- let path;
430
- const scheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.exec(trimmed);
431
- if (scheme) {
432
- const rest = trimmed.slice(scheme[0].length);
433
- const slash = rest.indexOf("/");
434
- if (slash === -1) return null;
435
- authority = rest.slice(0, slash);
436
- path = rest.slice(slash + 1);
437
- } else {
438
- const colon = trimmed.indexOf(":");
439
- if (colon === -1) return null;
440
- authority = trimmed.slice(0, colon);
441
- path = trimmed.slice(colon + 1);
442
- }
443
- const at = authority.lastIndexOf("@");
444
- if (at !== -1) authority = authority.slice(at + 1);
445
- const host = authority.replace(/:\d+$/, "").toLowerCase();
446
- if (host === "") return null;
447
- const normalizedPath = path.replace(/[?#].*$/, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
448
- if (normalizedPath === "") return null;
449
- return `${host}/${normalizedPath}`;
450
- }
451
742
  function stripRemoteUrlCredentials(url) {
452
743
  if (typeof url !== "string") return null;
453
744
  const trimmed = url.trim();
@@ -601,6 +892,11 @@ async function isWorkingTreeClean(cwd) {
601
892
  }
602
893
 
603
894
  export {
895
+ requiresHumanAction,
896
+ ClassifiedError,
897
+ failureOf,
898
+ actionOf,
899
+ classify,
604
900
  RETRY_CONFIG_KEYS,
605
901
  resolvePolicy,
606
902
  shouldFailover,
@@ -608,13 +904,14 @@ export {
608
904
  withRetry,
609
905
  fixedBackoffPolicy,
610
906
  run,
907
+ normalizeRemoteUrl,
908
+ projectIdFromRemote,
611
909
  getProjectRoot,
612
910
  getCurrentBranch,
613
911
  localBranchExists,
614
912
  getBaseBranch,
615
913
  getRemoteUrl,
616
914
  getHeadCommit,
617
- normalizeRemoteUrl,
618
915
  stripRemoteUrlCredentials,
619
916
  getCommitsSince,
620
917
  preflightRepository,
@@ -622,4 +919,4 @@ export {
622
919
  committedStoryIds,
623
920
  isWorkingTreeClean
624
921
  };
625
- //# sourceMappingURL=chunk-YVPZUN6X.js.map
922
+ //# sourceMappingURL=chunk-TJVX42KY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/shell.ts","../src/resilience/errors.ts","../src/resilience/policy.ts","../src/resilience/retry.ts","../src/storage/project-identity.ts","../src/utils/git.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { type Options as ExecaOptions, execa } from 'execa';\nimport {\n type ClassifiedFailure,\n classify,\n type FailureSignal,\n type FailureSource,\n} from '../resilience/errors.js';\nimport type { RetryPolicy } from '../resilience/policy.js';\nimport { type RetryPolicyFor, withRetry } from '../resilience/retry.js';\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n /**\n * The classified failure of the last attempt. Only ever set on the retry\n * path, and only when that attempt failed — a caller that passes no `retry`\n * gets exactly the three fields it has always got.\n */\n failure?: ClassifiedFailure;\n /** How many times the command actually ran. Only set on the retry path. */\n attempts?: number;\n}\n\n/** What `onRetryAttempt` is told once an attempt has produced a result. */\nexport interface RunRetryAttempt {\n /** 1-based number of the attempt that just finished. */\n attempt: number;\n result: ExecResult;\n /** `null` when the attempt succeeded. */\n failure: ClassifiedFailure | null;\n /** Whether another attempt follows this one. */\n willRetry: boolean;\n /** The wait before that next attempt; `0` when there is none. */\n delayMs: number;\n}\n\nexport interface RunOptions extends ExecaOptions {\n /** Skip global diagnostics when a non-zero exit is an expected probe result. */\n diagnostics?: boolean;\n /**\n * Opt in to retrying this invocation.\n *\n * Absent — the default, and what every call site of this project did before\n * this option existed — means one `execa` call with `reject: false` and no\n * extra attempt, byte for byte.\n *\n * Only pass a policy for a command whose non-zero exit means *it failed*.\n * A command whose non-zero exit is a legitimate answer (`git rev-parse\n * --verify --quiet`, `gh pr view` on a branch with no PR) is safe anyway —\n * an unclassifiable exit lands on `unknown`, which is not a retryable kind —\n * but the intent is worth being explicit about.\n *\n * A function instead of a policy resolves it from the failure that actually\n * happened, which is how one `gh` call gets the `network` budget for a DNS\n * blip and the `rate_limit` budget for a rate limit.\n */\n retry?: RetryPolicy | RetryPolicyFor;\n /** Overrides the subsystem inferred from `command` (`git`, `gh`). */\n source?: FailureSource;\n /**\n * Cuts a pending backoff short. Named apart from execa's own `cancelSignal`\n * because it governs the wait *between* attempts, not the child process.\n */\n retrySignal?: AbortSignal;\n /** Observe each attempt: log it, publish an event, persist the error. */\n onRetryAttempt?: (info: RunRetryAttempt) => void | Promise<void>;\n}\n\n/* ── which subsystem produced the failure ───────────────────────────────── */\n\nconst SOURCE_BY_COMMAND: Readonly<Record<string, FailureSource>> = {\n git: 'git',\n gh: 'github',\n};\n\nfunction inferSource(command: string): FailureSource {\n return SOURCE_BY_COMMAND[basename(command)] ?? 'internal';\n}\n\nfunction diagnoseCommandFailure(command: string, args: string[], result: ExecResult): void {\n if (result.exitCode === 0) return;\n void import('../storage/diagnostics.js').then(({ writeDiagnostic }) => {\n writeDiagnostic({\n level: 'warning',\n message: `Command failed: ${basename(command)}`,\n context: {\n command: basename(command),\n args,\n exitCode: result.exitCode,\n stderr: result.stderr.slice(0, 4_000),\n },\n });\n });\n}\n\n/* ── git invocations that are never repeated ────────────────────────────── */\n\n/**\n * `git` global options that swallow the token after them, so the subcommand of\n * `git -C /repo push --force` is `push` and not `/repo`.\n */\nconst GIT_GLOBAL_OPTIONS_WITH_VALUE: ReadonlySet<string> = new Set([\n '-C',\n '-c',\n '--git-dir',\n '--work-tree',\n '--namespace',\n '--exec-path',\n '--super-prefix',\n]);\n\n/**\n * git invocations no retry policy may repeat, whatever the caller asked for.\n *\n * `true` means the subcommand is never retried; a list means it is destructive\n * only when one of those tokens is present. This is the second of the Epic's\n * three limits — *no destructive operation is run automatically to fix state* —\n * enforced at the one chokepoint every `git` call of the project goes through.\n *\n * It errs on the side of not retrying: a sequencer operation left half-applied\n * (`rebase`, `cherry-pick`, `merge`, `am`, `revert`) is exactly the state a\n * blind second attempt turns into a lost commit, so those are absolute even\n * though a transient failure of one of them is conceivable.\n */\nconst DESTRUCTIVE_GIT_COMMANDS: Readonly<Record<string, true | readonly string[]>> = {\n rebase: true,\n 'cherry-pick': true,\n revert: true,\n merge: true,\n am: true,\n restore: true,\n 'filter-branch': true,\n gc: true,\n prune: true,\n 'update-ref': true,\n push: ['-f', '--force', '--force-with-lease', '--force-if-includes', '--delete', '--mirror'],\n reset: ['--hard', '--merge', '--keep'],\n clean: ['-f', '--force'],\n checkout: ['-f', '--force', '-B'],\n switch: ['-f', '--force', '--discard-changes'],\n branch: ['-d', '-D', '--delete', '-M'],\n tag: ['-d', '--delete', '-f', '--force'],\n stash: ['drop', 'clear', 'pop'],\n worktree: ['remove', 'prune'],\n submodule: ['deinit'],\n};\n\nfunction gitSubcommand(args: readonly string[]): { name: string; rest: readonly string[] } | null {\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (arg === undefined) continue;\n if (GIT_GLOBAL_OPTIONS_WITH_VALUE.has(arg)) {\n index++;\n continue;\n }\n if (arg.startsWith('-')) continue;\n return { name: arg, rest: args.slice(index + 1) };\n }\n return null;\n}\n\n/**\n * Whether `rest` carries `token`. Long options also match their `=value` form,\n * and a short option also matches bundled into another (`git clean -fd` is\n * `-f -d`), which is how `-f` is actually written in practice.\n */\nfunction hasToken(rest: readonly string[], token: string): boolean {\n if (token.startsWith('--')) {\n return rest.some((arg) => arg === token || arg.startsWith(`${token}=`));\n }\n if (token.startsWith('-')) {\n const letter = token.slice(1);\n return rest.some((arg) => /^-[A-Za-z]+$/.test(arg) && arg.slice(1).includes(letter));\n }\n return rest.includes(token);\n}\n\n/** Whether this invocation may be retried at all, whatever the policy says. */\nexport function isRetryableInvocation(command: string, args: readonly string[]): boolean {\n if (basename(command) !== 'git') return true;\n\n const subcommand = gitSubcommand(args);\n if (subcommand === null) return true;\n\n const rule = DESTRUCTIVE_GIT_COMMANDS[subcommand.name];\n if (rule === undefined) return true;\n if (rule === true) return false;\n\n return !rule.some((token) => hasToken(subcommand.rest, token));\n}\n\n/* ── the failure signal ─────────────────────────────────────────────────── */\n\n/**\n * The fields execa puts on a failed result when `reject: false` is set. They\n * are not on its success type, hence the narrowing: `code` is where the spawn\n * errno lands (`ENOENT`, `ETIMEDOUT`, `ECONNRESET`, `EAI_AGAIN`), and\n * `originalMessage` is the only place the reason shows up when the child never\n * started and therefore wrote nothing to stderr.\n */\ninterface ExecaFailureFields {\n code?: unknown;\n signal?: unknown;\n timedOut?: unknown;\n originalMessage?: unknown;\n shortMessage?: unknown;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n\nfunction toFailureSignal(raw: unknown, result: ExecResult, source: FailureSource): FailureSignal {\n const fields = (raw ?? {}) as ExecaFailureFields;\n const errno = asString(fields.code);\n const signal = asString(fields.signal);\n // A command that never started has an empty stderr; execa's own message is\n // then the only evidence there is, so it stands in for the missing output.\n const stderr =\n result.stderr.trim() !== ''\n ? result.stderr\n : (asString(fields.originalMessage) ?? asString(fields.shortMessage) ?? '');\n\n return {\n source,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr,\n ...(errno === undefined ? {} : { errno }),\n ...(signal === undefined ? {} : { signal }),\n ...(fields.timedOut === true ? { timedOut: true } : {}),\n };\n}\n\n/* ── the executor ───────────────────────────────────────────────────────── */\n\nasync function execOnce(\n command: string,\n args: string[],\n options: ExecaOptions,\n): Promise<{ result: ExecResult; raw: unknown }> {\n const raw = await execa(command, args, {\n reject: false,\n ...options,\n });\n\n return {\n raw,\n result: {\n stdout: raw.stdout?.toString() ?? '',\n stderr: raw.stderr?.toString() ?? '',\n exitCode: raw.exitCode ?? 1,\n },\n };\n}\n\n/**\n * Execute a command with arguments and capture its output.\n * Uses execa which calls execFile internally (no shell injection risk).\n * Does not throw on non-zero exit codes.\n *\n * With `options.retry` it becomes the retrying chokepoint every `gh` and `git`\n * call of the project already passes through: the failure is classified from\n * structured evidence (errno, signal, `timedOut`, exit code — text last) and\n * handed to `withRetry`, the single retry executor. Without it nothing changes.\n */\nexport async function run(\n command: string,\n args: string[] = [],\n options?: RunOptions,\n): Promise<ExecResult> {\n const {\n retry,\n source,\n retrySignal,\n onRetryAttempt,\n diagnostics = true,\n ...execaOptions\n } = options ?? {};\n\n if (retry === undefined || !isRetryableInvocation(command, args)) {\n const result = (await execOnce(command, args, execaOptions)).result;\n if (diagnostics) diagnoseCommandFailure(command, args, result);\n return result;\n }\n\n const failureSource = source ?? inferSource(command);\n\n const outcome = await withRetry(\n async () => {\n const { result, raw } = await execOnce(command, args, execaOptions);\n const failure =\n result.exitCode === 0 ? null : classify(toFailureSignal(raw, result, failureSource));\n return { result, failure };\n },\n {\n policy: retry,\n evaluate: (attempt) => attempt.failure,\n ...(retrySignal === undefined ? {} : { signal: retrySignal }),\n ...(onRetryAttempt === undefined\n ? {}\n : {\n onAttempt: (info) =>\n onRetryAttempt({\n attempt: info.attempt,\n result: info.value.result,\n failure: info.value.failure,\n willRetry: info.willRetry,\n delayMs: info.delayMs,\n }),\n }),\n },\n );\n\n const result = {\n ...outcome.value.result,\n attempts: outcome.attempts,\n ...(outcome.failure === null ? {} : { failure: outcome.failure }),\n };\n if (diagnostics) diagnoseCommandFailure(command, args, result);\n return result;\n}\n","/**\n * Failure taxonomy.\n *\n * Every failure the pipeline reacts to is classified here, from a structured\n * `FailureSignal`, into one `FailureKind`. The point is that the decision to\n * retry stops depending on `String.includes` over an error message: text is the\n * last resort of `classify()`, not its first move.\n *\n * The invariants of this layer — above all, that `task_execution` is never\n * retried here — are in `src/resilience/AGENTS.md`.\n */\n\n/** What went wrong, in the terms the retry policy is written in. */\nexport type FailureKind =\n | 'network'\n | 'timeout'\n | 'stalled'\n | 'rate_limit'\n | 'provider_down'\n | 'provider_crash'\n | 'authentication'\n | 'configuration'\n | 'repository_state'\n | 'task_execution'\n | 'internal'\n | 'unknown';\n\n/** Which subsystem produced the failure. */\nexport type FailureSource = 'agent' | 'github' | 'git' | 'filesystem' | 'internal';\n\n/**\n * The raw evidence of a failure, as the caller observed it.\n *\n * Everything is optional but `source`: a caller hands over what it actually\n * has. `execa` supplies `exitCode`, `signal`, `timedOut` and — on the thrown\n * error — `errno`; an HTTP client supplies `httpStatus` and `retryAfter`.\n */\nexport interface FailureSignal {\n source: FailureSource;\n exitCode?: number | null;\n /** POSIX signal name that terminated the process (`SIGTERM`, `SIGKILL`). */\n signal?: string | null;\n /** `execa`'s own verdict that it killed the child on the configured limit. */\n timedOut?: boolean;\n stdout?: string;\n stderr?: string;\n /** `ENOTFOUND`, `ECONNRESET`, `ETIMEDOUT`, `EAI_AGAIN`… */\n errno?: string;\n httpStatus?: number;\n /** A server's `Retry-After` header: delay in seconds, or an HTTP date. */\n retryAfter?: string | number;\n /** Set by the watchdog when a child produced no output for too long. */\n stalled?: boolean;\n}\n\n/** The verdict. `retryable` is advice; the attempt budget belongs to the policy. */\nexport interface ClassifiedFailure {\n kind: FailureKind;\n message: string;\n retryable: boolean;\n source: FailureSource;\n /** Present only when the server told us how long to wait. */\n retryAfterMs?: number;\n}\n\n/**\n * Kinds worth another attempt: the cause is outside the work being done and is\n * expected to pass on its own.\n */\nconst RETRYABLE_KINDS: ReadonlySet<FailureKind> = new Set<FailureKind>([\n 'network',\n 'timeout',\n 'stalled',\n 'rate_limit',\n 'provider_down',\n 'provider_crash',\n]);\n\n/**\n * Kinds that no configuration may retry. Waiting cannot fix any of them: they\n * need a human, or they belong to a different loop entirely (`task_execution`\n * is the pipeline's own correction cycle — see `AGENTS.md` here).\n */\nconst HUMAN_ACTION_KINDS: ReadonlySet<FailureKind> = new Set<FailureKind>([\n 'authentication',\n 'configuration',\n 'repository_state',\n 'task_execution',\n]);\n\n/** Whether this layer considers `kind` worth retrying at all. */\nexport function isRetryableKind(kind: FailureKind): boolean {\n return RETRYABLE_KINDS.has(kind);\n}\n\n/** Whether `kind` escalates to a human instead of being retried, ever. */\nexport function requiresHumanAction(kind: FailureKind): boolean {\n return HUMAN_ACTION_KINDS.has(kind);\n}\n\n/* ── carrying a verdict through a throw ─────────────────────────────────── */\n\n/**\n * An `Error` that carries its own classification.\n *\n * A `catch` normally flattens a failure back into a string, which is exactly\n * the loss this layer exists to prevent: the caller that has to decide between\n * \"retry\" and \"escalate to a human\" then has nothing but a message again. Any\n * boundary that must throw — a provider, a phase — throws this instead.\n *\n * `action` is what a human has to do, and it is only ever set for a kind that\n * needs one (`gh auth login` for `authentication`). It is written at the throw\n * site because only that site knows which CLI is involved.\n */\nexport class ClassifiedError extends Error {\n readonly failure: ClassifiedFailure;\n readonly action: string | undefined;\n\n constructor(message: string, failure: ClassifiedFailure, action?: string) {\n super(message);\n this.name = 'ClassifiedError';\n this.failure = failure;\n this.action = action;\n }\n}\n\n/** The verdict an error carries, or `null` when it carries none. */\nexport function failureOf(error: unknown): ClassifiedFailure | null {\n return error instanceof ClassifiedError ? error.failure : null;\n}\n\n/** The human action an error asks for, or `null`. */\nexport function actionOf(error: unknown): string | null {\n return error instanceof ClassifiedError ? (error.action ?? null) : null;\n}\n\n/* ── step 1: errno ──────────────────────────────────────────────────────── */\n\nconst ERRNO_KINDS: Readonly<Record<string, FailureKind>> = {\n ENOTFOUND: 'network',\n EAI_AGAIN: 'network',\n ECONNRESET: 'network',\n ECONNREFUSED: 'network',\n ECONNABORTED: 'network',\n EHOSTUNREACH: 'network',\n ENETUNREACH: 'network',\n ENETDOWN: 'network',\n EPIPE: 'network',\n ETIMEDOUT: 'timeout',\n ENOENT: 'configuration',\n EACCES: 'configuration',\n EPERM: 'configuration',\n};\n\nfunction kindFromErrno(errno: string | undefined): FailureKind | undefined {\n if (!errno) return undefined;\n return ERRNO_KINDS[errno.toUpperCase()];\n}\n\n/* ── step 2: HTTP status ────────────────────────────────────────────────── */\n\n/**\n * GitHub reports a secondary rate limit as `403`, not `429`, so the text is\n * consulted before calling a `403` an authentication failure. Everywhere else\n * the status alone decides.\n */\nfunction kindFromHttpStatus(status: number | undefined, lowered: string): FailureKind | undefined {\n if (status === undefined || status < 400) return undefined;\n if (status === 429) return 'rate_limit';\n if (status === 401) return 'authentication';\n if (status === 403)\n return matchesAny(lowered, RATE_LIMIT_PATTERNS) ? 'rate_limit' : 'authentication';\n if (status === 408) return 'timeout';\n if (status >= 500) return 'provider_down';\n return 'configuration';\n}\n\n/* ── step 3: how the process ended ──────────────────────────────────────── */\n\nconst CRASH_SIGNALS: ReadonlySet<string> = new Set(['SIGKILL', 'SIGABRT', 'SIGSEGV', 'SIGBUS']);\n\nfunction kindFromTermination(signal: FailureSignal): FailureKind | undefined {\n if (signal.stalled === true) return 'stalled';\n if (signal.timedOut === true) return 'timeout';\n const name = signal.signal?.toUpperCase();\n if (!name) return undefined;\n if (name === 'SIGTERM') return 'timeout';\n if (CRASH_SIGNALS.has(name)) return 'provider_crash';\n return undefined;\n}\n\n/* ── step 4: exit codes we know the meaning of ──────────────────────────── */\n\n/**\n * Only codes whose meaning is unambiguous. `143` (SIGTERM) is deliberately\n * absent: the Claude CLI handles the signal itself and exits `143` for a\n * user's Ctrl+C just as it does for our timeout, so it decides nothing on its\n * own — `timedOut` or `signal` is what tells the two apart.\n */\nconst EXIT_CODE_KINDS: Readonly<Record<number, FailureKind>> = {\n 75: 'provider_down', // EX_TEMPFAIL\n 126: 'configuration', // found, not executable\n 127: 'configuration', // command not found\n 137: 'provider_crash', // 128 + SIGKILL, typically the OOM killer\n 139: 'provider_crash', // 128 + SIGSEGV\n};\n\nfunction kindFromExitCode(exitCode: number | null | undefined): FailureKind | undefined {\n if (exitCode === null || exitCode === undefined) return undefined;\n return EXIT_CODE_KINDS[exitCode];\n}\n\n/* ── step 5: text, and only as a last resort ────────────────────────────── */\n\nconst RATE_LIMIT_PATTERNS = [\n 'rate limit',\n 'rate-limit',\n 'ratelimit',\n 'too many requests',\n 'http 429',\n] as const;\n\n/**\n * Ordered on purpose. A message is scanned rule by rule and the first hit\n * wins, so the specific causes (rate limit, credentials) are consulted before\n * the generic ones, and `task_execution` comes last: an infrastructure failure\n * surfacing inside a test run is still an infrastructure failure.\n */\ntype TextPattern = string | RegExp;\n\nconst TEXT_RULES: readonly { kind: FailureKind; patterns: readonly TextPattern[] }[] = [\n { kind: 'rate_limit', patterns: RATE_LIMIT_PATTERNS },\n {\n kind: 'authentication',\n patterns: [\n 'authentication failed',\n 'authentication_error',\n 'gh auth login',\n 'not logged into',\n 'bad credentials',\n 'invalid api key',\n 'invalid_api_key',\n 'token expired',\n 'expired token',\n 'unauthorized',\n 'http 401',\n 'http 403',\n ],\n },\n {\n kind: 'network',\n patterns: [\n 'connection reset',\n 'connection refused',\n 'connection aborted',\n 'network error',\n 'network unavailable',\n 'temporary failure',\n 'econnreset',\n 'econnrefused',\n 'enotfound',\n 'eai_again',\n 'socket hang up',\n // What Go prints, and therefore what `gh` prints: its network errors\n // never mention \"connection reset\", they mention the resolver.\n 'no such host',\n 'dial tcp',\n 'i/o timeout',\n 'tls handshake timeout',\n 'server misbehaving',\n 'error connecting to',\n ],\n },\n // Before the timeout rule: a stall *is* a kind of timeout, and the specific\n // reading is the useful one — it has its own budget and its own escalation.\n { kind: 'stalled', patterns: ['produced no output for', '(stalled)'] },\n { kind: 'timeout', patterns: ['timed out', 'timeout', 'etimedout'] },\n {\n kind: 'provider_down',\n patterns: [\n 'service unavailable',\n 'temporarily unavailable',\n 'overloaded',\n 'bad gateway',\n 'gateway timeout',\n 'internal server error',\n 'http 500',\n 'http 502',\n 'http 503',\n 'http 504',\n ],\n },\n {\n kind: 'provider_crash',\n patterns: ['segmentation fault', 'core dumped', 'out of memory', 'killed by signal'],\n },\n {\n kind: 'repository_state',\n patterns: [\n 'unmerged paths',\n 'needs merge',\n 'automatic merge failed',\n 'rebase in progress',\n 'you are in the middle of',\n 'cherry-pick is in progress',\n 'not a git repository',\n ],\n },\n {\n kind: 'configuration',\n patterns: [\n 'command not found',\n 'unknown flag',\n 'unknown option',\n 'no such file or directory',\n 'permission check failed',\n 'user denied permission',\n 'waiting for human input',\n 'status: waiting',\n 'below the minimum',\n 'prompt exceeds',\n 'nativetimeout',\n 'agy is not installed',\n ],\n },\n {\n kind: 'task_execution',\n patterns: [\n 'test failed',\n 'tests failed',\n 'failed tests',\n 'failing test',\n 'assertion failed',\n 'assertionerror',\n 'expect(received)',\n 'typecheck failed',\n 'npm err! test failed',\n 'lint failed',\n 'build failed',\n 'compilation failed',\n 'syntaxerror',\n 'typeerror',\n 'referenceerror',\n // What a runner actually prints: \"Tests 3 failed | 41 passed\",\n // \"Test Files 1 failed (12)\", \"Tests: 2 failed, 8 total\".\n /\\b\\d+\\s+failed\\b/,\n ],\n },\n];\n\nfunction matchesAny(lowered: string, patterns: readonly TextPattern[]): boolean {\n return patterns.some((pattern) =>\n typeof pattern === 'string' ? lowered.includes(pattern) : pattern.test(lowered),\n );\n}\n\nfunction kindFromText(lowered: string): FailureKind | undefined {\n if (!lowered) return undefined;\n for (const rule of TEXT_RULES) {\n if (matchesAny(lowered, rule.patterns)) return rule.kind;\n }\n return undefined;\n}\n\n/* ── Retry-After ────────────────────────────────────────────────────────── */\n\nconst RETRY_AFTER_IN_TEXT = /retry[\\s-]?after:?\\s*(\\d+)/i;\n\n/**\n * `Retry-After` is either a delay in seconds or an HTTP date. Both are\n * accepted; anything else, and a date already in the past, yields nothing\n * rather than a bogus zero.\n */\nfunction parseRetryAfter(value: string | number | undefined, now: number): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value === 'number')\n return Number.isFinite(value) && value >= 0 ? value * 1000 : undefined;\n\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n if (/^\\d+$/.test(trimmed)) return Number(trimmed) * 1000;\n\n const at = Date.parse(trimmed);\n if (Number.isNaN(at)) return undefined;\n return at > now ? at - now : undefined;\n}\n\nfunction resolveRetryAfterMs(signal: FailureSignal, text: string, now: number): number | undefined {\n const explicit = parseRetryAfter(signal.retryAfter, now);\n if (explicit !== undefined) return explicit;\n\n const inText = RETRY_AFTER_IN_TEXT.exec(text);\n return inText ? Number(inText[1]) * 1000 : undefined;\n}\n\n/* ── message ────────────────────────────────────────────────────────────── */\n\nfunction combineOutput(signal: FailureSignal): string {\n return [signal.stderr, signal.stdout].filter((part) => part && part.trim() !== '').join('\\n');\n}\n\n/** The output verbatim when there is any, and a synthesised line when there is not. */\nfunction describe(signal: FailureSignal, text: string): string {\n const trimmed = text.trim();\n if (trimmed !== '') return trimmed;\n if (signal.errno) return `${signal.source} failed with ${signal.errno}`;\n if (signal.httpStatus !== undefined)\n return `${signal.source} responded HTTP ${signal.httpStatus}`;\n if (signal.timedOut === true) return `${signal.source} timed out`;\n if (signal.signal) return `${signal.source} was terminated by ${signal.signal}`;\n if (signal.exitCode !== null && signal.exitCode !== undefined) {\n return `${signal.source} exited with code ${signal.exitCode}`;\n }\n return `${signal.source} failed for an unreported reason`;\n}\n\n/* ── the classifier ─────────────────────────────────────────────────────── */\n\nexport interface ClassifyOptions {\n /** Injectable clock, so an HTTP-date `Retry-After` is testable. */\n now?: () => number;\n}\n\n/**\n * Classify a failure by precedence: errno and HTTP status first (a machine\n * told us), then how the process ended, then an exit code we know the meaning\n * of, and only then the text — which is a heuristic and is treated as one.\n */\nexport function classify(signal: FailureSignal, options: ClassifyOptions = {}): ClassifiedFailure {\n const now = options.now?.() ?? Date.now();\n const text = combineOutput(signal);\n const lowered = text.toLowerCase();\n\n const kind =\n kindFromErrno(signal.errno) ??\n kindFromHttpStatus(signal.httpStatus, lowered) ??\n kindFromTermination(signal) ??\n kindFromExitCode(signal.exitCode) ??\n kindFromText(lowered) ??\n 'unknown';\n\n const retryAfterMs = resolveRetryAfterMs(signal, text, now);\n\n return {\n kind,\n message: describe(signal, text),\n retryable: isRetryableKind(kind),\n source: signal.source,\n ...(retryAfterMs === undefined ? {} : { retryAfterMs }),\n };\n}\n","/**\n * Retry policy: how long to wait, how many times, and what to do when the\n * budget runs out.\n *\n * `errors.ts` answers *what went wrong*; this module answers *what to do about\n * it*. It is pure — no I/O, no clock of its own, no knowledge of phases — so\n * every decision here is reproducible from its arguments. `retry.ts` is the\n * only executor that acts on what this module returns.\n *\n * The run-level state machine lives here too, for the same reason: whether a\n * run may go from `blocked` to `running` is a policy question, and there must\n * be exactly one answer to it in the codebase.\n *\n * The invariants of this layer are in `src/resilience/AGENTS.md`.\n */\n\nimport { type FailureKind, requiresHumanAction } from './errors.js';\n\n/* ── the policy ─────────────────────────────────────────────────────────── */\n\n/** What to do with the provider once a kind keeps failing. */\nexport type FailoverMode = 'never' | 'after_attempts' | 'immediate';\n\n/** What a failure becomes once the attempt budget is spent. */\nexport type ExhaustedAction = 'fail' | 'block';\n\nexport interface RetryPolicy {\n /** `0` means the kind is never retried by this layer. */\n maxAttempts: number;\n initialDelayMs: number;\n /** The ceiling of the backoff — honoured even under `retryForever`. */\n maxDelayMs: number;\n backoffFactor: number;\n jitter: 'none' | 'full';\n retryForever: boolean;\n failover: FailoverMode;\n /** Attempts to burn before `failover: 'after_attempts'` kicks in. */\n failoverAfterAttempts: number;\n onExhausted: ExhaustedAction;\n}\n\n/** A partial policy, as a configuration layer supplies it. */\nexport type RetryPolicyOverride = Partial<RetryPolicy>;\n\n/* ── configuration ──────────────────────────────────────────────────────── */\n\nexport type ResilienceProfile = 'default' | 'continuous';\n\n/**\n * The configuration keys of `resilience.retry`, one per `FailureKind` in the\n * camelCase spelling the JSON uses.\n */\nexport type RetryConfigKey =\n | 'network'\n | 'timeout'\n | 'stalled'\n | 'rateLimit'\n | 'providerDown'\n | 'providerCrash'\n | 'authentication'\n | 'configuration'\n | 'repositoryState'\n | 'taskExecution'\n | 'internal'\n | 'unknown';\n\nconst CONFIG_KEYS: Readonly<Record<FailureKind, RetryConfigKey>> = {\n network: 'network',\n timeout: 'timeout',\n stalled: 'stalled',\n rate_limit: 'rateLimit',\n provider_down: 'providerDown',\n provider_crash: 'providerCrash',\n authentication: 'authentication',\n configuration: 'configuration',\n repository_state: 'repositoryState',\n task_execution: 'taskExecution',\n internal: 'internal',\n unknown: 'unknown',\n};\n\n/** The configuration key `resilience.retry` uses for `kind`. */\nexport function retryConfigKey(kind: FailureKind): RetryConfigKey {\n return CONFIG_KEYS[kind];\n}\n\n/**\n * Every key `resilience.retry` accepts, for the layers that have to iterate\n * them (the schema in `storage/schemas.ts`, the merge in `config.ts`). Derived\n * from `CONFIG_KEYS` rather than written a second time, so a new `FailureKind`\n * cannot reach the configuration surface half-declared.\n */\nexport const RETRY_CONFIG_KEYS: readonly RetryConfigKey[] = Object.values(CONFIG_KEYS);\n\n/**\n * The slice of the `resilience` configuration this module reads. The full key\n * (providers, queue, watchdog, journal, decompose) is a superset of this, and\n * satisfies it structurally.\n */\nexport interface PolicyConfig {\n profile?: ResilienceProfile;\n /**\n * Whether a credential failure may migrate to another provider. Explicit on\n * purpose, never a default: switching provider because the main one lost its\n * credential hides exactly what the user needs to be told.\n */\n failoverOnAuth?: boolean;\n retry?: Partial<Record<RetryConfigKey, RetryPolicyOverride>>;\n}\n\n/* ── the defaults ───────────────────────────────────────────────────────── */\n\nconst SECOND = 1000;\n\nfunction policy(overrides: RetryPolicyOverride): RetryPolicy {\n return {\n maxAttempts: 0,\n initialDelayMs: 0,\n maxDelayMs: 0,\n backoffFactor: 2,\n jitter: 'full',\n retryForever: false,\n failover: 'never',\n failoverAfterAttempts: 2,\n onExhausted: 'fail',\n ...overrides,\n };\n}\n\n/**\n * The table of the PRD, verbatim. Changing a number here changes documented\n * behaviour: `policy.test.ts` asserts this table cell by cell on purpose.\n */\nconst BASE_POLICIES: Readonly<Record<FailureKind, RetryPolicy>> = {\n network: policy({ maxAttempts: 8, initialDelayMs: 2 * SECOND, maxDelayMs: 120 * SECOND }),\n timeout: policy({\n maxAttempts: 2,\n initialDelayMs: 30 * SECOND,\n maxDelayMs: 120 * SECOND,\n failover: 'after_attempts',\n }),\n stalled: policy({\n maxAttempts: 2,\n initialDelayMs: 15 * SECOND,\n maxDelayMs: 15 * SECOND,\n failover: 'after_attempts',\n }),\n rate_limit: policy({\n maxAttempts: 6,\n initialDelayMs: 60 * SECOND,\n maxDelayMs: 900 * SECOND,\n failover: 'after_attempts',\n }),\n provider_down: policy({\n maxAttempts: 4,\n initialDelayMs: 10 * SECOND,\n maxDelayMs: 300 * SECOND,\n failover: 'after_attempts',\n }),\n provider_crash: policy({\n maxAttempts: 3,\n initialDelayMs: 5 * SECOND,\n maxDelayMs: 60 * SECOND,\n failover: 'after_attempts',\n }),\n authentication: policy({ maxAttempts: 0, onExhausted: 'block' }),\n configuration: policy({ maxAttempts: 0 }),\n repository_state: policy({ maxAttempts: 0, onExhausted: 'block' }),\n task_execution: policy({ maxAttempts: 0 }),\n internal: policy({ maxAttempts: 2, initialDelayMs: 5 * SECOND, maxDelayMs: 5 * SECOND }),\n unknown: policy({ maxAttempts: 2, initialDelayMs: 5 * SECOND, maxDelayMs: 5 * SECOND }),\n};\n\n/**\n * The `continuous` profile — autonomous, long-running execution. It only ever\n * *widens* a budget: what is not retryable under `default` is not retryable\n * here either.\n */\nconst CONTINUOUS_OVERRIDES: Readonly<Partial<Record<FailureKind, RetryPolicyOverride>>> = {\n network: { retryForever: true },\n timeout: { maxAttempts: 3 },\n stalled: { maxAttempts: 3 },\n rate_limit: { retryForever: true },\n provider_down: { retryForever: true, failover: 'after_attempts' },\n provider_crash: { maxAttempts: 5 },\n};\n\n/**\n * Resolve the policy of a `FailureKind`: base table → profile → user\n * configuration, in that order.\n *\n * The kinds that need a human (`authentication`, `configuration`,\n * `repository_state`, `task_execution`) are clamped **after** the user layer:\n * no configuration, no profile and no `retryForever` can buy them an attempt.\n * That clamp is the golden rule of `AGENTS.md` made unbypassable.\n */\nexport function resolvePolicy(kind: FailureKind, config: PolicyConfig = {}): RetryPolicy {\n const base = BASE_POLICIES[kind];\n const profile = config.profile === 'continuous' ? CONTINUOUS_OVERRIDES[kind] : undefined;\n const user = config.retry?.[retryConfigKey(kind)];\n\n const resolved: RetryPolicy = { ...base, ...profile, ...user };\n\n if (!requiresHumanAction(kind)) return sanitize(resolved);\n\n return sanitize({\n ...resolved,\n maxAttempts: 0,\n retryForever: false,\n failover:\n kind === 'authentication' && config.failoverOnAuth === true ? resolved.failover : 'never',\n });\n}\n\n/** Guard against a configuration layer supplying a number that breaks the math. */\nfunction sanitize(value: RetryPolicy): RetryPolicy {\n return {\n ...value,\n maxAttempts: Math.max(0, Math.trunc(value.maxAttempts)),\n initialDelayMs: Math.max(0, value.initialDelayMs),\n maxDelayMs: Math.max(0, value.maxDelayMs),\n backoffFactor: value.backoffFactor >= 1 ? value.backoffFactor : 1,\n failoverAfterAttempts: Math.max(1, Math.trunc(value.failoverAfterAttempts)),\n };\n}\n\n/* ── the decisions ──────────────────────────────────────────────────────── */\n\n/**\n * Whether another attempt is allowed after `attemptsMade` attempts have\n * already failed.\n */\nexport function shouldRetry(policy: RetryPolicy, attemptsMade: number): boolean {\n if (policy.maxAttempts <= 0) return false;\n if (policy.retryForever) return true;\n return attemptsMade < policy.maxAttempts;\n}\n\n/** Whether the next attempt should be handed to a different provider. */\nexport function shouldFailover(policy: RetryPolicy, attemptsMade: number): boolean {\n if (policy.failover === 'never') return false;\n if (policy.failover === 'immediate') return true;\n return attemptsMade >= policy.failoverAfterAttempts;\n}\n\nexport interface DelayOptions {\n /** Injectable RNG, so the jitter is deterministic under test. */\n random?: () => number;\n /** What the server asked for, when it asked (`Retry-After`). */\n retryAfterMs?: number;\n}\n\n/**\n * The delay before attempt number `attemptsMade + 1`.\n *\n * `ceiling = min(maxDelayMs, initialDelayMs * backoffFactor^(attemptsMade-1))`,\n * and full jitter — the default — draws uniformly from `[0, ceiling)`. The\n * ceiling applies under `retryForever` exactly as it does otherwise: waiting\n * forever is allowed, hammering is not.\n *\n * A server-supplied `Retry-After` wins outright, un-jittered and uncapped: the\n * point of honouring it is not to come back before it says, and capping it by\n * `maxDelayMs` would do precisely that.\n */\nexport function computeDelayMs(\n policy: RetryPolicy,\n attemptsMade: number,\n options: DelayOptions = {},\n): number {\n if (options.retryAfterMs !== undefined && options.retryAfterMs >= 0) {\n return Math.round(options.retryAfterMs);\n }\n\n const exponent = Math.max(0, attemptsMade - 1);\n const growth = policy.initialDelayMs * policy.backoffFactor ** exponent;\n const ceiling = Math.min(policy.maxDelayMs, growth);\n if (ceiling <= 0) return 0;\n\n if (policy.jitter === 'none') return Math.round(ceiling);\n\n const random = options.random ?? Math.random;\n return Math.round(random() * ceiling);\n}\n\n/* ── the abortable delay ────────────────────────────────────────────────── */\n\n/**\n * Wait `ms`, unless `signal` fires first.\n *\n * Resolves `true` when the full delay elapsed and `false` when it was cut\n * short — a caller that waited fifteen minutes and a caller that was\n * interrupted must not take the same next step. It never throws: an abort is\n * an expected outcome here, not an error.\n */\nexport function abortableDelay(\n ms: number,\n options: { signal?: AbortSignal } = {},\n): Promise<boolean> {\n const { signal } = options;\n if (signal?.aborted === true) return Promise.resolve(false);\n if (ms <= 0) return Promise.resolve(true);\n\n return new Promise((resolve) => {\n const onAbort = () => {\n clearTimeout(timer);\n resolve(false);\n };\n\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve(true);\n }, ms);\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/* ── the run state machine ──────────────────────────────────────────────── */\n\n/**\n * The state of a run — a queued issue in `execution-plan.json`, or the single\n * issue of a `tasks.json`.\n */\nexport type RunStatus =\n | 'queued'\n | 'running'\n | 'waiting'\n | 'retrying'\n | 'paused'\n | 'blocked'\n | 'failed'\n | 'completed'\n | 'cancelled';\n\n/**\n * Every legal transition, in one place.\n *\n * `completed` and `cancelled` are terminal: nothing leaves them. `blocked` has\n * exits, but none the pipeline may take on its own — see `canTransition`.\n */\nexport const RUN_TRANSITIONS: Readonly<Record<RunStatus, readonly RunStatus[]>> = {\n queued: ['running', 'blocked', 'cancelled'],\n running: ['waiting', 'retrying', 'paused', 'blocked', 'failed', 'completed', 'cancelled'],\n waiting: ['running', 'retrying', 'paused', 'blocked', 'failed', 'cancelled'],\n retrying: ['running', 'waiting', 'paused', 'blocked', 'failed', 'cancelled'],\n paused: ['running', 'blocked', 'cancelled'],\n blocked: ['running', 'cancelled'],\n failed: ['running', 'cancelled'],\n completed: [],\n cancelled: [],\n};\n\n/** Nothing leaves these, by anyone. */\nconst TERMINAL_STATUSES: ReadonlySet<RunStatus> = new Set<RunStatus>(['completed', 'cancelled']);\n\n/** Whether `status` is terminal. */\nexport function isTerminalRunStatus(status: RunStatus): boolean {\n return TERMINAL_STATUSES.has(status);\n}\n\n/** Who is attempting the transition. The pipeline is the default. */\nexport type TransitionActor = 'pipeline' | 'human';\n\n/**\n * Whether `from → to` is legal for `actor`.\n *\n * `blocked` exists precisely to stop the machine until someone looks at it, so\n * the pipeline may enter it but never leave it: only `actor: 'human'` — a\n * `resume`, a `cancel` — can. A pipeline able to unblock itself would spin on\n * the same missing credential forever.\n */\nexport function canTransition(\n from: RunStatus,\n to: RunStatus,\n options: { actor?: TransitionActor } = {},\n): boolean {\n if (!RUN_TRANSITIONS[from].includes(to)) return false;\n if (from === 'blocked' && (options.actor ?? 'pipeline') !== 'human') return false;\n return true;\n}\n","/**\n * The single retry executor of the project.\n *\n * `errors.ts` says *what went wrong*, `policy.ts` says *what to do about it*,\n * and this module is the only place that actually does it: one loop, one\n * backoff, one veto. Before it existed the codebase had two independent retry\n * loops — `core/phase-runner.ts` for single-shot phases and the `execute` loop\n * of `core/engine.ts` — with their own counters, their own delays and no way\n * to keep them in step. Both now delegate here.\n *\n * The loop performs no I/O and knows nothing about phases, sessions or\n * publishers: everything observable is handed back through `onAttempt`, so the\n * caller keeps ownership of its own logging, events and persistence.\n *\n * The invariants of this layer are in `src/resilience/AGENTS.md`.\n */\n\nimport { type ClassifiedFailure, requiresHumanAction } from './errors.js';\nimport { abortableDelay, computeDelayMs, type RetryPolicy, shouldRetry } from './policy.js';\n\n/** What `onAttempt` is told once an attempt has produced a value. */\nexport interface RetryAttemptInfo<T> {\n /** 1-based number of the attempt that just finished. */\n attempt: number;\n /** Whatever `fn` returned, failure or not. */\n value: T;\n /** `null` when the attempt succeeded. */\n failure: ClassifiedFailure | null;\n /** Whether another attempt follows this one. */\n willRetry: boolean;\n /** The wait before that next attempt; `0` when there is none. */\n delayMs: number;\n}\n\n/**\n * A policy chosen from the failure that just happened.\n *\n * The kind is only known *after* an attempt, so a call site that spans several\n * kinds — every `gh` invocation is a network failure, a rate limit or an\n * authentication failure depending on the day — hands over the resolver rather\n * than one frozen policy. `resolvePolicy(failure.kind, config)` is what a\n * caller normally passes.\n */\nexport type RetryPolicyFor = (failure: ClassifiedFailure) => RetryPolicy;\n\nexport interface WithRetryOptions<T> {\n /** One policy, or one chosen per classified failure. */\n policy: RetryPolicy | RetryPolicyFor;\n /**\n * The verdict on one attempt's value: `null` for success, a classified\n * failure otherwise.\n *\n * It belongs to the caller because only the caller knows what a failure\n * looks like in its own return type — an exit code, an `ok: false`, a\n * rejected HTTP response. Callers holding structured evidence should build\n * the failure with `classify()` rather than re-deriving it from text.\n */\n evaluate: (value: T, attempt: number) => ClassifiedFailure | null;\n /** Cuts a pending backoff short; see `abortableDelay`. */\n signal?: AbortSignal;\n /**\n * Called once per attempt, before the backoff, with the decision already\n * taken. This is where a caller publishes its `retry` event, prints, or\n * persists an error — awaited, so those writes finish before the wait.\n */\n onAttempt?: (info: RetryAttemptInfo<T>) => void | Promise<void>;\n /** Injectable RNG for the jitter, so a test can assert the exact curve. */\n random?: () => number;\n /** Injectable wait, so a test never sleeps for real. */\n delay?: (ms: number, options: { signal?: AbortSignal }) => Promise<boolean>;\n}\n\nexport interface RetryOutcome<T> {\n /** The value of the last attempt — the successful one, or the final failure. */\n value: T;\n /** How many times `fn` ran. */\n attempts: number;\n /** `null` when the last attempt succeeded. */\n failure: ClassifiedFailure | null;\n /** The failure was retryable and the budget ran out. */\n exhausted: boolean;\n /** `signal` fired during a backoff, so the next attempt never happened. */\n aborted: boolean;\n}\n\n/**\n * Run `fn` until it succeeds, until the policy's budget is spent, or until\n * `signal` fires.\n *\n * Three separate conditions have to hold for another attempt, and all three\n * are checked here rather than by the caller:\n *\n * 1. the failure is retryable at all (`ClassifiedFailure.retryable`);\n * 2. the kind is not one that needs a human — `task_execution`,\n * `authentication`, `configuration` and `repository_state` are vetoed\n * outright, whatever the policy says and even under `retryForever`. This is\n * the golden rule of `AGENTS.md`, enforced a second time here: a caller can\n * hand-build a `RetryPolicy` without going through `resolvePolicy()`, so\n * the clamp there is not on its own enough;\n * 3. the policy still has budget (`shouldRetry`).\n */\nexport async function withRetry<T>(\n fn: (attempt: number) => Promise<T>,\n options: WithRetryOptions<T>,\n): Promise<RetryOutcome<T>> {\n const { policy, evaluate, signal, onAttempt, random } = options;\n const delay = options.delay ?? abortableDelay;\n const policyFor: RetryPolicyFor = typeof policy === 'function' ? policy : () => policy;\n\n for (let attempt = 1; ; attempt++) {\n const value = await fn(attempt);\n const failure = evaluate(value, attempt);\n\n if (failure === null) {\n await onAttempt?.({ attempt, value, failure, willRetry: false, delayMs: 0 });\n return { value, attempts: attempt, failure: null, exhausted: false, aborted: false };\n }\n\n const active = policyFor(failure);\n const eligible = failure.retryable && !requiresHumanAction(failure.kind);\n const willRetry = eligible && shouldRetry(active, attempt);\n const delayMs = willRetry\n ? computeDelayMs(active, attempt, { random, retryAfterMs: failure.retryAfterMs })\n : 0;\n\n await onAttempt?.({ attempt, value, failure, willRetry, delayMs });\n\n if (!willRetry) {\n return { value, attempts: attempt, failure, exhausted: eligible, aborted: false };\n }\n\n if (!(await delay(delayMs, { signal }))) {\n return { value, attempts: attempt, failure, exhausted: false, aborted: true };\n }\n }\n}\n\n/**\n * A fixed policy in the shape the two legacy call sites express their settings\n * in: a number of attempts and a base/max delay in seconds.\n *\n * Deliberately un-jittered. Both call sites have always used a bare\n * `base * 2^(n-1)` and both publish that number in a `retry` event and print\n * it; adding jitter here would change today's behaviour with no configuration\n * asking for it. Jitter arrives with the `resilience` key that configures it.\n */\nexport function fixedBackoffPolicy(\n maxAttempts: number,\n baseSeconds: number,\n maxSeconds: number,\n overrides: Partial<RetryPolicy> = {},\n): RetryPolicy {\n return {\n maxAttempts,\n initialDelayMs: baseSeconds * 1000,\n maxDelayMs: maxSeconds * 1000,\n backoffFactor: 2,\n jitter: 'none',\n retryForever: false,\n failover: 'never',\n failoverAfterAttempts: 2,\n onExhausted: 'fail',\n ...overrides,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { basename, resolve } from 'node:path';\n\nconst SLUG_MAX_LENGTH = 32;\nconst HASH_LENGTH = 12;\nconst FALLBACK_SLUG = 'project';\n\nfunction slugify(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, SLUG_MAX_LENGTH)\n .replace(/-+$/g, '');\n return slug === '' ? FALLBACK_SLUG : slug;\n}\n\n/** Normalize HTTP, SSH and scp-like Git remotes to one stable identity. */\nexport function normalizeRemoteUrl(url: string | null | undefined): string | null {\n if (typeof url !== 'string') return null;\n const trimmed = url.trim();\n if (trimmed === '') return null;\n\n let authority: string;\n let path: string;\n const scheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\//.exec(trimmed);\n if (scheme) {\n const rest = trimmed.slice(scheme[0].length);\n const slash = rest.indexOf('/');\n if (slash === -1) return null;\n authority = rest.slice(0, slash);\n path = rest.slice(slash + 1);\n } else {\n const colon = trimmed.indexOf(':');\n if (colon === -1) return null;\n authority = trimmed.slice(0, colon);\n path = trimmed.slice(colon + 1);\n }\n\n const at = authority.lastIndexOf('@');\n if (at !== -1) authority = authority.slice(at + 1);\n const host = authority.replace(/:\\d+$/, '').toLowerCase();\n if (host === '') return null;\n const normalizedPath = path\n .replace(/[?#].*$/, '')\n .replace(/\\/+/g, '/')\n .replace(/^\\/+|\\/+$/g, '')\n .replace(/\\.git$/i, '')\n .replace(/\\/+$/, '')\n .toLowerCase();\n return normalizedPath === '' ? null : `${host}/${normalizedPath}`;\n}\n\n/** Derive the stable project id from a normalized remote or absolute path. */\nexport function projectIdFromRemote(remote: string | null, projectRoot: string): string {\n const seed = remote ? `remote:${remote}` : `path:${resolve(projectRoot)}`;\n const name = remote ? (remote.split('/').pop() ?? '') : basename(resolve(projectRoot));\n const hash = createHash('sha256').update(seed).digest('hex').slice(0, HASH_LENGTH);\n return `${slugify(name)}-${hash}`;\n}\n","import { type ExecResult, run } from './shell.js';\n\n/**\n * Get the root directory of the current git repository.\n * Throws if not inside a git repository.\n */\nexport async function getProjectRoot(): Promise<string> {\n const result = await run('git', ['rev-parse', '--show-toplevel']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Not inside a git repository. Please run issue-flow from within a git project.',\n );\n }\n\n return result.stdout.trim();\n}\n\n/**\n * Get the current git branch name.\n * Returns an empty string if in detached HEAD state.\n */\nexport async function getCurrentBranch(): Promise<string> {\n const result = await run('git', ['branch', '--show-current']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Failed to detect git branch. Ensure git is installed and you are inside a repository.',\n );\n }\n\n return result.stdout.trim();\n}\n\n/** Whether a local branch exists, without consulting or mutating remotes. */\nexport async function localBranchExists(name: string, cwd?: string): Promise<boolean> {\n if (name.trim() === '') return false;\n const result = await run('git', ['show-ref', '--verify', '--quiet', `refs/heads/${name}`], {\n ...(cwd === undefined ? {} : { cwd }),\n diagnostics: false,\n });\n return result.exitCode === 0;\n}\n\nexport interface CommitInfo {\n hash: string;\n subject: string;\n committedAt?: string | null;\n storyId?: string | null;\n}\n\n/**\n * Get the base branch of the repository: the remote HEAD (origin/HEAD) when\n * available, otherwise the first of main/master that exists locally.\n * Never throws; defaults to 'main'.\n */\nexport async function getBaseBranch(): Promise<string> {\n const remoteHead = await run('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], {\n diagnostics: false,\n });\n if (remoteHead.exitCode === 0) {\n const name = remoteHead.stdout.trim().replace(/^origin\\//, '');\n if (name) return name;\n }\n\n for (const candidate of ['main', 'master']) {\n const check = await run(\n 'git',\n ['rev-parse', '--verify', '--quiet', `refs/heads/${candidate}`],\n { diagnostics: false },\n );\n if (check.exitCode === 0) return candidate;\n }\n\n return 'main';\n}\n\n/**\n * Get the URL of the `origin` remote.\n * Never throws: a missing remote, a non-zero exit code, an empty stdout or a\n * git binary that cannot even be spawned all resolve to `null` — the same\n * discipline as {@link getBaseBranch}, so callers can treat \"no remote\" as an\n * ordinary state instead of an error path.\n *\n * `cwd` selects which repository is queried; omitting it falls back to\n * `process.cwd()`, which is almost never what a caller resolving a specific\n * `projectRoot` wants — pass it explicitly whenever one is available.\n */\nexport async function getRemoteUrl(cwd?: string): Promise<string | null> {\n let result: ExecResult;\n try {\n result = await run('git', ['remote', 'get-url', 'origin'], { cwd, diagnostics: false });\n } catch {\n return null;\n }\n\n if (result.exitCode !== 0) return null;\n\n const url = result.stdout.trim();\n return url === '' ? null : url;\n}\n\n/**\n * Get the abbreviated hash of the current HEAD commit.\n * Never throws, same discipline as {@link getRemoteUrl}: a repository with no\n * commits yet, a non-zero exit code, an empty stdout or a git binary that\n * cannot be spawned all resolve to `null`, so callers can treat \"no HEAD\" as\n * an ordinary state instead of an error path.\n *\n * `cwd` selects which repository is queried; omitting it falls back to\n * `process.cwd()`.\n */\nexport async function getHeadCommit(cwd?: string): Promise<string | null> {\n let result: ExecResult;\n try {\n result = await run('git', ['rev-parse', '--short', 'HEAD'], { cwd, diagnostics: false });\n } catch {\n return null;\n }\n\n if (result.exitCode !== 0) return null;\n\n const hash = result.stdout.trim();\n return hash === '' ? null : hash;\n}\n\n/**\n * Reduce a git remote URL to a canonical `host/path` identity, so that every\n * way of addressing the same repository collapses to the same string:\n *\n * ```\n * https://github.com/org/repo.git -> github.com/org/repo\n * git@github.com:org/repo.git -> github.com/org/repo\n * ssh://git@github.com:22/org/repo.git -> github.com/org/repo\n * https://user:token@github.com/org/repo -> github.com/org/repo\n * https://github.com/Org/Repo/ -> github.com/org/repo\n * ```\n *\n * Pure function: it never shells out, so it is testable without a git\n * repository. Returns `null` when no host and path can be extracted.\n *\n * Known limitation: both host and path are lowercased. Hostnames are\n * case-insensitive by definition, but repository paths are case-sensitive on\n * some self-hosted servers — so `host/org/Repo` and `host/org/repo` normalize\n * to the same identity even if that server considers them distinct. This is a\n * deliberate trade: matching the same repository across clones (where users\n * routinely type the wrong case) matters more than telling apart two repos\n * whose paths differ only by case.\n */\nexport { normalizeRemoteUrl } from '../storage/project-identity.js';\n\n/**\n * Remove Basic-Auth-style credentials (`user:token@`, `user@`) embedded in an\n * `http(s)` remote URL, without touching anything else about it — case, port,\n * the `.git` suffix, query string and trailing slashes are all preserved.\n *\n * Deliberately scoped to `http`/`https`: that is the only place a git remote\n * can carry a real secret (a PAT is routinely embedded as\n * `https://x-access-token:TOKEN@host/...` by CI and automation), and the URL\n * stays a valid, clonable remote once the userinfo is gone. SSH has no\n * equivalent syntax — both `ssh://user@host/path` and the scp-like shorthand\n * `user@host:path` require that user segment to connect at all (it is almost\n * always the fixed, non-secret `git` service account), so this function\n * leaves any other scheme, the scp-like form and local paths untouched.\n *\n * Unlike {@link normalizeRemoteUrl}, which collapses a URL to a lossy\n * `host/path` identity, this keeps the URL \"as configured\" — it exists for\n * surfaces (like the web monitor's `repository.remoteUrl`) that want to show\n * the real remote, minus whatever secret an HTTPS token commonly embeds in\n * it.\n *\n * Pure function, never throws. Returns `null` for a nullish or empty input.\n */\nexport function stripRemoteUrlCredentials(url: string | null | undefined): string | null {\n if (typeof url !== 'string') return null;\n\n const trimmed = url.trim();\n if (trimmed === '') return null;\n\n const httpScheme = /^https?:\\/\\//i.exec(trimmed);\n if (!httpScheme) return trimmed;\n\n const rest = trimmed.slice(httpScheme[0].length);\n const slash = rest.indexOf('/');\n const authority = slash === -1 ? rest : rest.slice(0, slash);\n const remainder = slash === -1 ? '' : rest.slice(slash);\n\n const at = authority.lastIndexOf('@');\n if (at === -1) return trimmed;\n return `${httpScheme[0]}${authority.slice(at + 1)}${remainder}`;\n}\n\n/**\n * List commits on HEAD that are not on the given base branch (base..HEAD),\n * most recent first. Never throws; returns [] when the range cannot be\n * resolved (e.g. unknown base branch or shallow clone).\n */\nexport async function getCommitsSince(base: string): Promise<CommitInfo[]> {\n const result = await run('git', [\n 'log',\n '--pretty=format:%h%x09%cI%x09%s%x09%b%x1e',\n `${base}..HEAD`,\n ]);\n if (result.exitCode !== 0) return [];\n\n if (!result.stdout.includes('\\x1e')) {\n return result.stdout\n .split('\\n')\n .filter((line) => line.trim() !== '')\n .map((line) => {\n const tab = line.indexOf('\\t');\n return tab === -1\n ? { hash: line.trim(), subject: '' }\n : { hash: line.slice(0, tab), subject: line.slice(tab + 1) };\n });\n }\n const records = result.stdout.split('\\x1e');\n return records.flatMap((raw) => {\n const record = raw.trim();\n if (record === '') return [];\n const fields = record.split('\\t');\n const [hash = '', committedAt = '', subject = '', ...bodyParts] = fields;\n const body = bodyParts.join('\\t');\n const storyId = /(?:Story:\\s*|\\[)(US-\\d+)/i.exec(`${subject}\\n${body}`)?.[1] ?? null;\n return [\n {\n hash,\n subject,\n committedAt: committedAt || null,\n storyId: storyId?.toUpperCase() ?? null,\n },\n ];\n });\n}\n\n/* ── repository preflight ───────────────────────────────────────────────── */\n\n/**\n * A repository state that stops the pipeline.\n *\n * The whole point of this type is that it is *reported*, never acted on: the\n * second explicit limit of the resilience Epic is that **no destructive\n * operation is ever run automatically to fix state**. A repository mid-rebase\n * is a person's unfinished work, and an `--abort` issued by a tool at 3am is\n * indistinguishable from data loss.\n */\nexport type PreflightBlockKind =\n | 'rebase_in_progress'\n | 'merge_in_progress'\n | 'cherry_pick_in_progress'\n | 'revert_in_progress'\n | 'unmerged_paths'\n | 'detached_head'\n | 'branch_mismatch'\n | 'dirty_tree';\n\nexport interface PreflightBlock {\n kind: PreflightBlockKind;\n /** What is wrong, in one line. */\n message: string;\n /** The command a human would run. Printed, never executed. */\n suggestion: string;\n}\n\nexport interface PreflightResult {\n ok: boolean;\n blocks: PreflightBlock[];\n /** Current branch, or `null` on a detached HEAD. */\n branch: string | null;\n /** Whether the working tree has uncommitted changes. */\n dirty: boolean;\n}\n\n/** What the caller is about to do, which decides how a dirty tree is read. */\nexport type PreflightIntent =\n | /** Continuing the phase that produced the changes. */ 'resume-same-phase'\n | /** Starting a different phase, or a different issue. */ 'new-phase';\n\nexport interface PreflightOptions {\n /** Branch the plan says this work belongs to. `null` skips the check. */\n expectedBranch?: string | null;\n /** Default `new-phase`, the strict reading. */\n intent?: PreflightIntent;\n cwd?: string;\n}\n\n/** `git rev-parse --verify --quiet <ref>` — exit 0 means the ref exists. */\nasync function refExists(ref: string, cwd?: string): Promise<boolean> {\n const result = await run('git', ['rev-parse', '--verify', '--quiet', ref], {\n ...(cwd === undefined ? {} : { cwd }),\n diagnostics: false,\n });\n return result.exitCode === 0;\n}\n\n/** The in-progress sequencer operations, by the ref each one leaves behind. */\nconst SEQUENCER_REFS: readonly {\n ref: string;\n kind: PreflightBlockKind;\n name: string;\n suggestion: string;\n}[] = [\n {\n ref: 'REBASE_HEAD',\n kind: 'rebase_in_progress',\n name: 'a rebase',\n suggestion: 'git rebase --continue (or git rebase --abort)',\n },\n {\n ref: 'MERGE_HEAD',\n kind: 'merge_in_progress',\n name: 'a merge',\n suggestion: 'git merge --continue (or git merge --abort)',\n },\n {\n ref: 'CHERRY_PICK_HEAD',\n kind: 'cherry_pick_in_progress',\n name: 'a cherry-pick',\n suggestion: 'git cherry-pick --continue (or git cherry-pick --abort)',\n },\n {\n ref: 'REVERT_HEAD',\n kind: 'revert_in_progress',\n name: 'a revert',\n suggestion: 'git revert --continue (or git revert --abort)',\n },\n];\n\n/**\n * Describe the repository and decide whether it is safe to write to it.\n *\n * Every check is a *read*: `rev-parse`, `symbolic-ref`, `diff --name-only`,\n * `status --porcelain`, `branch --show-current`. Nothing here checks anything\n * out, resets anything, aborts anything or stashes anything — not on a resume,\n * not under a continuous profile, not ever. A repository in an ambiguous state\n * escalates to a human, which is the only correct answer for a tool that did\n * not put it there.\n *\n * A **dirty tree is not always a problem**: resuming the phase that produced\n * those changes is exactly the case where uncommitted work is expected. It\n * blocks only when the run is about to move on to something else, where the\n * changes would be carried into work they do not belong to.\n */\nexport async function preflightRepository(\n options: PreflightOptions = {},\n): Promise<PreflightResult> {\n const { cwd, expectedBranch, intent = 'new-phase' } = options;\n const at = cwd === undefined ? {} : { cwd };\n const blocks: PreflightBlock[] = [];\n\n for (const sequencer of SEQUENCER_REFS) {\n if (await refExists(sequencer.ref, cwd)) {\n blocks.push({\n kind: sequencer.kind,\n message: `The repository is in the middle of ${sequencer.name} (${sequencer.ref} is present).`,\n suggestion: sequencer.suggestion,\n });\n }\n }\n\n const unmerged = await run('git', ['diff', '--name-only', '--diff-filter=U'], at);\n const conflicted = unmerged.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line !== '');\n if (conflicted.length > 0) {\n blocks.push({\n kind: 'unmerged_paths',\n message: `${conflicted.length} file(s) still have unresolved conflicts: ${conflicted.slice(0, 5).join(', ')}${conflicted.length > 5 ? ', …' : ''}.`,\n suggestion: 'Resolve them, then git add the files',\n });\n }\n\n // `symbolic-ref -q HEAD` fails on a detached HEAD, which is the whole test.\n const symbolic = await run('git', ['symbolic-ref', '-q', 'HEAD'], at);\n const detached = symbolic.exitCode !== 0;\n const branch = detached ? null : symbolic.stdout.trim().replace(/^refs\\/heads\\//, '');\n\n if (detached) {\n blocks.push({\n kind: 'detached_head',\n message: 'HEAD is detached, so a commit would belong to no branch.',\n suggestion: `git switch ${expectedBranch ?? '<branch>'}`,\n });\n } else if (\n expectedBranch !== undefined &&\n expectedBranch !== null &&\n expectedBranch !== '' &&\n branch !== expectedBranch\n ) {\n blocks.push({\n kind: 'branch_mismatch',\n message: `The plan works on '${expectedBranch}' but the repository is on '${branch}'.`,\n suggestion: `git switch ${expectedBranch}`,\n });\n }\n\n const status = await run('git', ['status', '--porcelain'], at);\n const dirty = status.stdout.trim() !== '';\n if (dirty && intent !== 'resume-same-phase') {\n blocks.push({\n kind: 'dirty_tree',\n message: 'The working tree has uncommitted changes that do not belong to this phase.',\n suggestion: 'Commit or stash them yourself, then run again',\n });\n }\n\n return { ok: blocks.length === 0, blocks, branch, dirty };\n}\n\n/** The report a caller prints when the preflight blocks. Never a fix. */\nexport function describePreflight(result: PreflightResult): string[] {\n return result.blocks.map((block) => `${block.message} Suggested: ${block.suggestion}`);\n}\n\n/* ── story-level idempotence ────────────────────────────────────────────── */\n\n/** A story id as it appears in a commit subject: `feat(issue-63): US-012 - …`. */\nconst STORY_ID_IN_SUBJECT = /\\bUS-\\d+\\b/g;\n\n/**\n * The story ids already committed on this branch.\n *\n * The execute prompt commits one story per commit, with the id in the subject\n * (`<type>(scope): US-001 - Title`), so the branch's own history is a record of\n * what is done — and it is the *only* record that survives a crash between the\n * commit and the agent writing `passes: true` into the plan.\n *\n * Read-only, and deliberately so: this answers a question, it never fixes\n * anything. Never throws — an unreadable history means \"nothing known\", which\n * leaves the engine doing exactly what it did before.\n */\nexport async function committedStoryIds(baseBranch: string, cwd?: string): Promise<Set<string>> {\n const at = cwd === undefined ? {} : { cwd };\n const range = baseBranch === '' ? 'HEAD' : `${baseBranch}..HEAD`;\n const result = await run('git', ['log', range, '--format=%s'], at);\n if (result.exitCode !== 0) return new Set();\n\n const ids = new Set<string>();\n for (const subject of result.stdout.split('\\n')) {\n for (const match of subject.matchAll(STORY_ID_IN_SUBJECT)) {\n ids.add(match[0]);\n }\n }\n return ids;\n}\n\n/** Whether the working tree has no uncommitted change. Never throws. */\nexport async function isWorkingTreeClean(cwd?: string): Promise<boolean> {\n const at = cwd === undefined ? {} : { cwd };\n const result = await run('git', ['status', '--porcelain'], at);\n if (result.exitCode !== 0) return false;\n return result.stdout.trim() === '';\n}\n"],"mappings":"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","names":["policy","resolve","policy","result","basename"]}