issue-flow 0.18.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 (233) hide show
  1. package/README.md +34 -100
  2. package/dist/agent-EWKA7357.js +32 -0
  3. package/dist/{analyze-Q4ONIWRZ.js → analyze-Z7ODC27F.js} +42 -41
  4. package/dist/analyze-Z7ODC27F.js.map +1 -0
  5. package/dist/{apply-EEFPY2W4.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-WWWXLTFH.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-XUEMATVY.js → chunk-2EZW4X57.js} +28 -25
  14. package/dist/chunk-2EZW4X57.js.map +1 -0
  15. package/dist/{chunk-LGHND47K.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-OODXFCQV.js → chunk-2YYP7AE6.js} +14 -16
  19. package/dist/{chunk-OODXFCQV.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-PMLE7KAQ.js → chunk-46S7APLQ.js} +30 -14
  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-ZVZMWNCG.js → chunk-F2NFJ27Z.js} +2 -2
  37. package/dist/{chunk-SOM4QA6C.js → chunk-GD7JZMSJ.js} +93 -18
  38. package/dist/chunk-GD7JZMSJ.js.map +1 -0
  39. package/dist/{chunk-6K2LCFG6.js → chunk-HEHHQU4G.js} +70 -81
  40. package/dist/chunk-HEHHQU4G.js.map +1 -0
  41. package/dist/{chunk-34OCSKOB.js → chunk-HHXWAWU6.js} +159 -114
  42. package/dist/chunk-HHXWAWU6.js.map +1 -0
  43. package/dist/{chunk-E4I6MMHD.js → chunk-HWWB22HC.js} +152 -100
  44. package/dist/chunk-HWWB22HC.js.map +1 -0
  45. package/dist/chunk-IMB6FA2F.js +673 -0
  46. package/dist/chunk-IMB6FA2F.js.map +1 -0
  47. package/dist/{chunk-ECU7YO7S.js → chunk-IQYXXFRC.js} +22 -6
  48. package/dist/chunk-IQYXXFRC.js.map +1 -0
  49. package/dist/chunk-J6VJ5M2U.js +1201 -0
  50. package/dist/chunk-J6VJ5M2U.js.map +1 -0
  51. package/dist/{chunk-QJ44VG5G.js → chunk-KDQRNVBZ.js} +3 -3
  52. package/dist/{chunk-7UMMFOL2.js → chunk-LRWIP7QS.js} +39 -24
  53. package/dist/chunk-LRWIP7QS.js.map +1 -0
  54. package/dist/{chunk-LI35PIIS.js → chunk-LYC57OXF.js} +20 -117
  55. package/dist/chunk-LYC57OXF.js.map +1 -0
  56. package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
  57. package/dist/chunk-MAJ6QDRL.js.map +1 -0
  58. package/dist/{chunk-CWSQVHVV.js → chunk-MHA7Q3KU.js} +248 -102
  59. package/dist/chunk-MHA7Q3KU.js.map +1 -0
  60. package/dist/{chunk-TZYINKCC.js → chunk-MQTVMB7W.js} +33 -28
  61. package/dist/chunk-MQTVMB7W.js.map +1 -0
  62. package/dist/chunk-NP47HRX2.js +136 -0
  63. package/dist/chunk-NP47HRX2.js.map +1 -0
  64. package/dist/{chunk-EG2MGDP5.js → chunk-NYDAHE3Y.js} +52 -46
  65. package/dist/chunk-NYDAHE3Y.js.map +1 -0
  66. package/dist/{chunk-45WZ6GMI.js → chunk-P7ZYOC23.js} +16 -16
  67. package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
  68. package/dist/{chunk-NEWNXZ65.js → chunk-PHPAK2L6.js} +28 -26
  69. package/dist/{chunk-NEWNXZ65.js.map → chunk-PHPAK2L6.js.map} +1 -1
  70. package/dist/{chunk-PPZ3K4YM.js → chunk-PRGPSNGA.js} +2 -2
  71. package/dist/{chunk-V7QOIQYC.js → chunk-RGFMQFX7.js} +9 -23
  72. package/dist/{chunk-V7QOIQYC.js.map → chunk-RGFMQFX7.js.map} +1 -1
  73. package/dist/{chunk-YVPZUN6X.js → chunk-TJVX42KY.js} +335 -38
  74. package/dist/chunk-TJVX42KY.js.map +1 -0
  75. package/dist/{chunk-HOAHMERN.js → chunk-UDRAD7MF.js} +21 -21
  76. package/dist/{chunk-QF7VEL3M.js → chunk-UHDXXLYH.js} +39 -127
  77. package/dist/chunk-UHDXXLYH.js.map +1 -0
  78. package/dist/{chunk-RNFUVKC3.js → chunk-UPAAZU4W.js} +30 -13
  79. package/dist/chunk-UPAAZU4W.js.map +1 -0
  80. package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
  81. package/dist/{chunk-KMCS76ZW.js → chunk-WB2FVIUS.js} +44 -12
  82. package/dist/chunk-WB2FVIUS.js.map +1 -0
  83. package/dist/{chunk-SA6HXL4Y.js → chunk-WPHC6JBR.js} +9 -9
  84. package/dist/chunk-WPHC6JBR.js.map +1 -0
  85. package/dist/{chunk-KRAGAUKD.js → chunk-XHCP6ZNO.js} +201 -64
  86. package/dist/chunk-XHCP6ZNO.js.map +1 -0
  87. package/dist/{chunk-7F7LGMVO.js → chunk-XKR3VD2Z.js} +12 -12
  88. package/dist/{chunk-7F7LGMVO.js.map → chunk-XKR3VD2Z.js.map} +1 -1
  89. package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
  90. package/dist/chunk-XNK5UN2D.js.map +1 -0
  91. package/dist/{chunk-LTH6XYZ3.js → chunk-XQLNZW7I.js} +40 -30
  92. package/dist/chunk-XQLNZW7I.js.map +1 -0
  93. package/dist/{chunk-62GVVZQO.js → chunk-ZAYATXJD.js} +32 -316
  94. package/dist/chunk-ZAYATXJD.js.map +1 -0
  95. package/dist/cli.js +127 -59
  96. package/dist/cli.js.map +1 -1
  97. package/dist/compat-YPDZB34U.js +24 -0
  98. package/dist/{config-LEBZZCJP.js → config-56B4OHZE.js} +20 -17
  99. package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
  100. package/dist/{conventions-XOT6YW5L.js → conventions-DW2CM5I3.js} +20 -16
  101. package/dist/{conventions-XOT6YW5L.js.map → conventions-DW2CM5I3.js.map} +1 -1
  102. package/dist/db-5NU77PJA.js +264 -0
  103. package/dist/db-5NU77PJA.js.map +1 -0
  104. package/dist/diagnostics-UCTS2VUF.js +25 -0
  105. package/dist/execute-R7AVOLNG.js +38 -0
  106. package/dist/{generate-JGW5JSKB.js → generate-O7GUXLN4.js} +46 -43
  107. package/dist/generate-O7GUXLN4.js.map +1 -0
  108. package/dist/{git-A2IP32PQ.js → git-LCG45YXD.js} +2 -3
  109. package/dist/history-6GSURU3H.js +101 -0
  110. package/dist/history-6GSURU3H.js.map +1 -0
  111. package/dist/init-DD6DBRC5.js +28 -0
  112. package/dist/{operations-O4FORFIH.js → operations-HU5ZFEBA.js} +78 -52
  113. package/dist/operations-HU5ZFEBA.js.map +1 -0
  114. package/dist/{permissions-G4XCAESF.js → permissions-NNNSRC4P.js} +5 -6
  115. package/dist/plan-XR6B7EM3.js +38 -0
  116. package/dist/{policy-U5NBFAO5.js → policy-RFJOJQL6.js} +17 -15
  117. package/dist/{policy-U5NBFAO5.js.map → policy-RFJOJQL6.js.map} +1 -1
  118. package/dist/pr-OSCNJCOO.js +42 -0
  119. package/dist/pr-review-IKIYHFBO.js +33 -0
  120. package/dist/prd-HFDZJJQR.js +37 -0
  121. package/dist/{ps-76L6ZAZL.js → ps-AKRHGPSR.js} +26 -15
  122. package/dist/ps-AKRHGPSR.js.map +1 -0
  123. package/dist/{recorder-2BAKPBRA.js → recorder-T7426CKV.js} +11 -7
  124. package/dist/registry-DWRKD65A.js +17 -0
  125. package/dist/repository-TABBRW2C.js +80 -0
  126. package/dist/resume-GDXKK5XP.js +278 -0
  127. package/dist/resume-GDXKK5XP.js.map +1 -0
  128. package/dist/review-JJHMQA2O.js +38 -0
  129. package/dist/routing-FPNUVE7T.js +35 -0
  130. package/dist/run-RLCURLLL.js +61 -0
  131. package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
  132. package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
  133. package/dist/{state-manager-UPHO2EA2.js → state-manager-IGNTD4AB.js} +9 -4
  134. package/dist/state-manager-IGNTD4AB.js.map +1 -0
  135. package/dist/{usage-KTMYXAPF.js → usage-XW27AL5K.js} +69 -63
  136. package/dist/usage-XW27AL5K.js.map +1 -0
  137. package/dist/web-NCDBVZ5Y.js +205 -0
  138. package/dist/web-NCDBVZ5Y.js.map +1 -0
  139. package/package.json +20 -7
  140. package/prompts/analyze.md +16 -19
  141. package/prompts/execute.md +73 -144
  142. package/prompts/generate.md +23 -10
  143. package/prompts/plan.md +32 -60
  144. package/prompts/pr-review.md +58 -40
  145. package/prompts/pr.md +50 -16
  146. package/prompts/prd.md +26 -19
  147. package/prompts/review.md +41 -18
  148. package/web/public/app.js +109 -110
  149. package/dist/agent-HMZTXCRT.js +0 -30
  150. package/dist/analyze-Q4ONIWRZ.js.map +0 -1
  151. package/dist/apply-EEFPY2W4.js.map +0 -1
  152. package/dist/chunk-34OCSKOB.js.map +0 -1
  153. package/dist/chunk-62GVVZQO.js.map +0 -1
  154. package/dist/chunk-6K2LCFG6.js.map +0 -1
  155. package/dist/chunk-7UMMFOL2.js.map +0 -1
  156. package/dist/chunk-CRGIQFUQ.js.map +0 -1
  157. package/dist/chunk-CWSQVHVV.js.map +0 -1
  158. package/dist/chunk-E4I6MMHD.js.map +0 -1
  159. package/dist/chunk-ECU7YO7S.js.map +0 -1
  160. package/dist/chunk-EG2MGDP5.js.map +0 -1
  161. package/dist/chunk-HAKDLR6N.js.map +0 -1
  162. package/dist/chunk-ICM463EO.js.map +0 -1
  163. package/dist/chunk-KMCS76ZW.js.map +0 -1
  164. package/dist/chunk-KRAGAUKD.js.map +0 -1
  165. package/dist/chunk-LGHND47K.js.map +0 -1
  166. package/dist/chunk-LI35PIIS.js.map +0 -1
  167. package/dist/chunk-LTH6XYZ3.js.map +0 -1
  168. package/dist/chunk-PMLE7KAQ.js.map +0 -1
  169. package/dist/chunk-QF7VEL3M.js.map +0 -1
  170. package/dist/chunk-RNFUVKC3.js.map +0 -1
  171. package/dist/chunk-SA6HXL4Y.js.map +0 -1
  172. package/dist/chunk-SOM4QA6C.js.map +0 -1
  173. package/dist/chunk-TZYINKCC.js.map +0 -1
  174. package/dist/chunk-WCCZJL7W.js +0 -141
  175. package/dist/chunk-WCCZJL7W.js.map +0 -1
  176. package/dist/chunk-XEYH6ZZI.js +0 -289
  177. package/dist/chunk-XEYH6ZZI.js.map +0 -1
  178. package/dist/chunk-XUEMATVY.js.map +0 -1
  179. package/dist/chunk-XZUEFTUP.js +0 -243
  180. package/dist/chunk-XZUEFTUP.js.map +0 -1
  181. package/dist/chunk-YVPZUN6X.js.map +0 -1
  182. package/dist/diagnostics-HTCWF7F4.js +0 -23
  183. package/dist/execute-LELOSR5T.js +0 -37
  184. package/dist/generate-JGW5JSKB.js.map +0 -1
  185. package/dist/init-TO6MUXO4.js +0 -26
  186. package/dist/operations-O4FORFIH.js.map +0 -1
  187. package/dist/plan-OXAT344Q.js +0 -34
  188. package/dist/pr-UZHNKKZC.js +0 -39
  189. package/dist/pr-review-Q4ACAWDM.js +0 -32
  190. package/dist/prd-6CYEMLDY.js +0 -33
  191. package/dist/ps-76L6ZAZL.js.map +0 -1
  192. package/dist/registry-XLHHYLTR.js +0 -15
  193. package/dist/resume-URCU6CIJ.js +0 -244
  194. package/dist/resume-URCU6CIJ.js.map +0 -1
  195. package/dist/review-LVZT2TMW.js +0 -35
  196. package/dist/routing-EK6RBZM4.js +0 -33
  197. package/dist/run-2RXJCJKT.js +0 -56
  198. package/dist/usage-KTMYXAPF.js.map +0 -1
  199. package/dist/web-B5UPHHR5.js +0 -172
  200. package/dist/web-B5UPHHR5.js.map +0 -1
  201. /package/dist/{agent-HMZTXCRT.js.map → agent-EWKA7357.js.map} +0 -0
  202. /package/dist/{bench-WWWXLTFH.js.map → bench-ZJEIACUK.js.map} +0 -0
  203. /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
  204. /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
  205. /package/dist/{chunk-QPGEFLMY.js.map → chunk-7CMVL4X6.js.map} +0 -0
  206. /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
  207. /package/dist/{chunk-DGRTJD5R.js.map → chunk-DXH4TQRB.js.map} +0 -0
  208. /package/dist/{chunk-YUNBOUQH.js.map → chunk-ERAG5IQB.js.map} +0 -0
  209. /package/dist/{chunk-ZVZMWNCG.js.map → chunk-F2NFJ27Z.js.map} +0 -0
  210. /package/dist/{chunk-QJ44VG5G.js.map → chunk-KDQRNVBZ.js.map} +0 -0
  211. /package/dist/{chunk-45WZ6GMI.js.map → chunk-P7ZYOC23.js.map} +0 -0
  212. /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
  213. /package/dist/{chunk-PPZ3K4YM.js.map → chunk-PRGPSNGA.js.map} +0 -0
  214. /package/dist/{chunk-HOAHMERN.js.map → chunk-UDRAD7MF.js.map} +0 -0
  215. /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
  216. /package/dist/{config-LEBZZCJP.js.map → compat-YPDZB34U.js.map} +0 -0
  217. /package/dist/{contract-JH2WBIO6.js.map → config-56B4OHZE.js.map} +0 -0
  218. /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
  219. /package/dist/{execute-LELOSR5T.js.map → diagnostics-UCTS2VUF.js.map} +0 -0
  220. /package/dist/{git-A2IP32PQ.js.map → execute-R7AVOLNG.js.map} +0 -0
  221. /package/dist/{init-TO6MUXO4.js.map → git-LCG45YXD.js.map} +0 -0
  222. /package/dist/{permissions-G4XCAESF.js.map → init-DD6DBRC5.js.map} +0 -0
  223. /package/dist/{plan-OXAT344Q.js.map → permissions-NNNSRC4P.js.map} +0 -0
  224. /package/dist/{pr-UZHNKKZC.js.map → plan-XR6B7EM3.js.map} +0 -0
  225. /package/dist/{pr-review-Q4ACAWDM.js.map → pr-OSCNJCOO.js.map} +0 -0
  226. /package/dist/{prd-6CYEMLDY.js.map → pr-review-IKIYHFBO.js.map} +0 -0
  227. /package/dist/{recorder-2BAKPBRA.js.map → prd-HFDZJJQR.js.map} +0 -0
  228. /package/dist/{registry-XLHHYLTR.js.map → recorder-T7426CKV.js.map} +0 -0
  229. /package/dist/{review-LVZT2TMW.js.map → registry-DWRKD65A.js.map} +0 -0
  230. /package/dist/{routing-EK6RBZM4.js.map → repository-TABBRW2C.js.map} +0 -0
  231. /package/dist/{run-2RXJCJKT.js.map → review-JJHMQA2O.js.map} +0 -0
  232. /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-FPNUVE7T.js.map} +0 -0
  233. /package/dist/{state-manager-UPHO2EA2.js.map → run-RLCURLLL.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/state-manager.ts","../src/telemetry/reconcile.ts","../src/core/metrics.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { ZodError } from 'zod';\nimport { taskPlanSchema } from '../schemas.js';\nimport { reconcileInterruptedExecutions } from '../telemetry/reconcile.js';\nimport type { LastError, PipelineState, TaskPlan, UserStory } from '../types.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { type ClaudeUsage, sumUsage } from './metrics.js';\n\n/**\n * Get the current ISO timestamp.\n */\nexport function isoNow(): string {\n return new Date().toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Load and parse a tasks.json file.\n * Validates that it has the expected structure.\n */\nexport async function loadTaskPlan(path: string): Promise<TaskPlan> {\n const content = await readFile(path, 'utf-8');\n const raw = JSON.parse(content);\n\n try {\n const parsed = taskPlanSchema.parse(raw) as TaskPlan;\n const reconciled = reconcileInterruptedExecutions(parsed);\n if (reconciled !== parsed) {\n try {\n await saveTaskPlan(path, reconciled);\n } catch {\n // Observational: a failed persist of interrupted status still returns\n // the reconciled plan to this reader.\n }\n }\n return reconciled;\n } catch (err) {\n if (err instanceof ZodError) {\n const issues = err.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`).join('\\n');\n throw new Error(`Invalid tasks.json at ${path}:\\n${issues}`);\n }\n throw err;\n }\n}\n\n/**\n * Save a TaskPlan to disk atomically (write-to-temp + rename).\n * This prevents corruption if the process is interrupted during write.\n */\nexport async function saveTaskPlan(path: string, plan: TaskPlan): Promise<void> {\n await writeFileAtomic(path, `${JSON.stringify(plan, null, 2)}\\n`);\n}\n\n/**\n * Initialize default state fields on a TaskPlan.\n * Fills in missing fields with defaults, matching the Bash script behavior.\n *\n * The opt-in fields (`pullRequest`, `prReview`, `pipeline.prReviewCompleted`)\n * are deliberately absent from the defaults: they ride along on the spread when\n * present and stay out of the file entirely when the phases never ran.\n */\nexport function initializeState(plan: TaskPlan): TaskPlan {\n const defaultPipeline: PipelineState = {\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n };\n\n return {\n ...plan,\n issueStatus: plan.issueStatus ?? 'pending',\n completedAt: plan.completedAt ?? null,\n lastAttemptAt: plan.lastAttemptAt ?? null,\n lastError: plan.lastError ?? null,\n correctionCycle: plan.correctionCycle ?? 0,\n maxCorrectionCycles: plan.maxCorrectionCycles ?? 3,\n lastReviewFindings: plan.lastReviewFindings ?? null,\n pipeline: plan.pipeline ? { ...defaultPipeline, ...plan.pipeline } : defaultPipeline,\n };\n}\n\n/**\n * Whether the issue has a review failure that execute must still address,\n * even if every userStories[].passes is already true.\n */\nexport function hasPendingCorrection(plan: TaskPlan): boolean {\n return Boolean(plan.lastReviewFindings);\n}\n\n/**\n * Check if all user stories have passes=true.\n * Returns false if there are no stories.\n */\nexport function allStoriesPass(plan: TaskPlan): boolean {\n if (plan.userStories.length === 0) {\n return false;\n }\n\n return plan.userStories.every((story) => story.passes === true);\n}\n\n/**\n * The story `execute` should work on next: the highest-priority (lowest\n * `priority` number) story with `passes: false`. This is the exact same rule\n * `prompts/execute.md` gives the agent (\"pick the highest priority user\n * story where `passes: false`\") — kept here as a single, pure, exported\n * helper so the engine's `iteration:start` publication and the terminal\n * renderer read the same computed identity instead of two independent\n * heuristics.\n *\n * Pure: never mutates `stories`. Returns `undefined` when every story\n * already passes (or the plan has none).\n */\nexport function selectActiveStory(stories: readonly UserStory[]): UserStory | undefined {\n return [...stories].filter((story) => !story.passes).sort((a, b) => a.priority - b.priority)[0];\n}\n\n/**\n * Mark a specific story as passing.\n */\nexport function markStoryPassing(plan: TaskPlan, storyId: string): TaskPlan {\n return {\n ...plan,\n userStories: plan.userStories.map((story) =>\n story.id === storyId ? { ...story, passes: true } : story,\n ),\n };\n}\n\n/**\n * Accumulate a usage share (and duration) onto the given stories.\n *\n * Pure, like the rest of this module: returns a new plan and never touches the\n * input. Accumulation is summing and treats `undefined` as \"not reported\": a\n * field neither the story nor the share carries stays absent, so a plan written\n * by a CLI that reports no usage never gains artificial zeros.\n *\n * The share is what `divideUsage()` already split across the stories that\n * completed in the same execute iteration — see core/engine.ts.\n */\nexport function applyStoryMetrics(\n plan: TaskPlan,\n storyIds: string[],\n share: ClaudeUsage,\n durationSeconds?: number,\n): TaskPlan {\n if (storyIds.length === 0) return plan;\n\n const targets = new Set(storyIds);\n\n return {\n ...plan,\n userStories: plan.userStories.map((story) => {\n if (!targets.has(story.id)) return story;\n\n const updated: UserStory = { ...story, ...sumUsage(story, share) };\n if (story.durationSeconds !== undefined || durationSeconds !== undefined) {\n updated.durationSeconds = (story.durationSeconds ?? 0) + (durationSeconds ?? 0);\n }\n return updated;\n }),\n };\n}\n\n/**\n * Mark the issue as in_progress.\n */\nexport function markIssueInProgress(plan: TaskPlan, timestamp?: string): TaskPlan {\n const ts = timestamp ?? isoNow();\n return {\n ...plan,\n issueStatus: 'in_progress',\n completedAt: null,\n lastAttemptAt: ts,\n };\n}\n\n/**\n * Mark the issue as completed.\n */\nexport function markIssueCompleted(plan: TaskPlan): TaskPlan {\n const ts = isoNow();\n return {\n ...plan,\n issueStatus: 'completed',\n completedAt: ts,\n lastAttemptAt: ts,\n lastError: null,\n pipeline: plan.pipeline ? { ...plan.pipeline, executionCompleted: true } : plan.pipeline,\n };\n}\n\n/**\n * Set the lastError field on the task plan.\n */\nexport function setLastError(plan: TaskPlan, category: string, message: string): TaskPlan {\n const ts = isoNow();\n const error: LastError = {\n category,\n message,\n at: ts,\n };\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: error,\n };\n}\n\n/**\n * Clear the lastError field, but only if it was set before the attempt started.\n * This prevents clearing errors that were set during the current attempt.\n */\nexport function clearLastError(plan: TaskPlan, attemptStartedAt: string): TaskPlan {\n const ts = isoNow();\n\n // If the error was set after the attempt started, keep it\n if (plan.lastError && plan.lastError.at > attemptStartedAt) {\n return {\n ...plan,\n lastAttemptAt: ts,\n };\n }\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: null,\n };\n}\n\n/**\n * Trim an error message to at most 8 non-empty lines.\n */\nexport function trimErrorMessage(message: string): string {\n return message\n .split('\\n')\n .filter((line) => line.trim().length > 0)\n .slice(0, 8)\n .join('\\n');\n}\n","import { hostname } from 'node:os';\nimport { isProcessAlive } from '../storage/lock.js';\nimport type { TaskPlan } from '../types.js';\n\nfunction nowIso(): string {\n return new Date().toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Convert orphan `running` records to `interrupted` using the two-signal\n * rule from `storage/lock.ts`: a pid on this host that is gone.\n *\n * A record owned by another host is left `running` — we cannot see that pid.\n */\nexport function reconcileInterruptedExecutions(plan: TaskPlan): TaskPlan {\n if (plan.executions === undefined || plan.executions.length === 0) return plan;\n let changed = false;\n const executions = plan.executions.map((record) => {\n if (record.status !== 'running' || record.finishedAt !== null) return record;\n const owner = record.owner;\n if (owner === undefined || owner === null) {\n changed = true;\n return { ...record, status: 'interrupted' as const, finishedAt: nowIso(), owner: null };\n }\n if (owner.host !== hostname()) return record;\n if (isProcessAlive(owner.pid)) return record;\n changed = true;\n return { ...record, status: 'interrupted' as const, finishedAt: nowIso(), owner: null };\n });\n return changed ? { ...plan, executions } : plan;\n}\n","/**\n * Single source of truth for translating the `claude` CLI JSON output into\n * token/cost metrics.\n *\n * Three call sites consume this (headless json, headless stream-json and the\n * execute-phase executor); keeping the parsing here is what stops them from\n * diverging again the next time the CLI payload changes shape.\n */\n\nexport interface ClaudeUsage {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n costUsd?: number;\n /** Envelope `duration_ms` — request onward, not process startup. */\n cliDurationMs?: number;\n /** Envelope `duration_api_ms` when the harness reports it. */\n apiDurationMs?: number;\n /** Time to first output, when the harness reports it. */\n ttftMs?: number;\n numTurns?: number;\n}\n\n/** Field names of {@link ClaudeUsage}, used by the summing helper. */\nconst USAGE_FIELDS = [\n 'inputTokens',\n 'outputTokens',\n 'cacheReadTokens',\n 'cacheCreationTokens',\n 'costUsd',\n] as const;\n\n/**\n * Coerce a value to a finite number, or undefined when it is absent/unusable.\n * Never throws — malformed payloads simply yield undefined.\n */\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Parse a `claude` CLI result payload into a {@link ClaudeUsage}.\n *\n * Reads the current format (`total_cost_usd` plus a nested `usage` object) and\n * falls back to the legacy flat keys (`cost_usd`, `num_input_tokens`,\n * `num_output_tokens`) when the newer ones are absent.\n *\n * Returns null when the payload carries no recognizable field at all, and a\n * partial object when only some fields are present. Never throws.\n */\n/**\n * Parse a Codex `turn.completed.usage` object.\n *\n * Codex reports `input_tokens` including the cache (Decision 6 of #62), so\n * `inputTokens` is `input_tokens − cached_input_tokens`, clamped at 0. Codex\n * never reports USD; `costUsd` stays absent — \"not reported\", never zero.\n */\nexport function parseCodexUsage(payload: unknown): ClaudeUsage | null {\n if (!isRecord(payload)) return null;\n\n const usage: ClaudeUsage = {};\n const inputTokens = num(payload.input_tokens);\n const cachedInput = num(payload.cached_input_tokens);\n const cacheWrite = num(payload.cache_write_input_tokens);\n const outputTokens = num(payload.output_tokens);\n\n if (inputTokens !== undefined) {\n usage.inputTokens =\n cachedInput !== undefined ? Math.max(0, inputTokens - cachedInput) : inputTokens;\n }\n if (outputTokens !== undefined) usage.outputTokens = outputTokens;\n if (cachedInput !== undefined) usage.cacheReadTokens = cachedInput;\n if (cacheWrite !== undefined) usage.cacheCreationTokens = cacheWrite;\n\n return Object.keys(usage).length > 0 ? usage : null;\n}\n\nexport function parseUsage(payload: unknown): ClaudeUsage | null {\n if (!isRecord(payload)) return null;\n\n const usageRaw = isRecord(payload.usage) ? payload.usage : undefined;\n\n const usage: ClaudeUsage = {};\n\n const inputTokens = usageRaw ? num(usageRaw.input_tokens) : undefined;\n const outputTokens = usageRaw ? num(usageRaw.output_tokens) : undefined;\n const cacheReadTokens = usageRaw ? num(usageRaw.cache_read_input_tokens) : undefined;\n const cacheCreationTokens = usageRaw ? num(usageRaw.cache_creation_input_tokens) : undefined;\n const costUsd = num(payload.total_cost_usd);\n\n // Legacy fallbacks — only consulted when the modern key is missing.\n const legacyInput = num(payload.num_input_tokens);\n const legacyOutput = num(payload.num_output_tokens);\n const legacyCost = num(payload.cost_usd);\n\n const resolvedInput = inputTokens ?? legacyInput;\n const resolvedOutput = outputTokens ?? legacyOutput;\n const resolvedCost = costUsd ?? legacyCost;\n\n if (resolvedInput !== undefined) usage.inputTokens = resolvedInput;\n if (resolvedOutput !== undefined) usage.outputTokens = resolvedOutput;\n if (cacheReadTokens !== undefined) usage.cacheReadTokens = cacheReadTokens;\n if (cacheCreationTokens !== undefined) usage.cacheCreationTokens = cacheCreationTokens;\n if (resolvedCost !== undefined) usage.costUsd = resolvedCost;\n\n const cliDurationMs = num(payload.duration_ms);\n const apiDurationMs = num(payload.duration_api_ms);\n const ttftMs = num(payload.ttft_ms) ?? num(payload.time_to_first_token_ms);\n const numTurns = num(payload.num_turns);\n if (cliDurationMs !== undefined) usage.cliDurationMs = cliDurationMs;\n if (apiDurationMs !== undefined) usage.apiDurationMs = apiDurationMs;\n if (ttftMs !== undefined) usage.ttftMs = ttftMs;\n if (numTurns !== undefined) usage.numTurns = numTurns;\n\n return Object.keys(usage).length > 0 ? usage : null;\n}\n\n/**\n * Sum two usages field by field.\n *\n * `undefined` means \"not reported\", not zero: a field absent on both sides\n * stays absent in the result, while a field present on a single side is\n * carried over untouched.\n */\nexport function sumUsage(\n a: ClaudeUsage | null | undefined,\n b: ClaudeUsage | null | undefined,\n): ClaudeUsage {\n const result: ClaudeUsage = {};\n\n for (const field of USAGE_FIELDS) {\n const left = a?.[field];\n const right = b?.[field];\n if (left === undefined && right === undefined) continue;\n result[field] = (left ?? 0) + (right ?? 0);\n }\n\n return result;\n}\n\n/**\n * Split a usage evenly across `parts`.\n *\n * This is the rateio used when several stories complete in the same execute\n * iteration: the iteration's tokens cannot be attributed to a single story, so\n * each one receives an equal share. Token counts are rounded to integers;\n * the cost keeps full precision.\n *\n * `parts <= 1` (or a non-finite value) returns the usage unchanged. Fields the\n * CLI never reported stay absent — dividing \"not reported\" still yields\n * \"not reported\", never zero.\n */\nexport function divideUsage(usage: ClaudeUsage | null | undefined, parts: number): ClaudeUsage {\n const result: ClaudeUsage = {};\n if (!usage) return result;\n\n const divisor = Number.isFinite(parts) && parts > 1 ? parts : 1;\n\n for (const field of USAGE_FIELDS) {\n const value = usage[field];\n if (value === undefined) continue;\n result[field] = field === 'costUsd' ? value / divisor : Math.round(value / divisor);\n }\n\n return result;\n}\n\n/**\n * Compact token count: `1523` → `1.5k`, `2_400_000` → `2.4M`.\n */\nfunction compactTokens(value: number): string {\n const abs = Math.abs(value);\n if (abs >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (abs >= 1_000) return `${(value / 1_000).toFixed(1)}k`;\n return String(Math.round(value));\n}\n\n/**\n * Human-readable one-liner, e.g. `2 in / 4 out · 15.5k cache · ~$0.1607`.\n *\n * Segments whose data is missing are omitted entirely — callers can rely on an\n * empty string meaning \"no metrics at all\" and skip the line altogether rather\n * than printing zeros or NaN.\n */\nexport function formatTokens(usage: ClaudeUsage | null | undefined): string {\n if (!usage) return '';\n\n const segments: string[] = [];\n\n const io: string[] = [];\n if (usage.inputTokens !== undefined) io.push(`${compactTokens(usage.inputTokens)} in`);\n if (usage.outputTokens !== undefined) io.push(`${compactTokens(usage.outputTokens)} out`);\n if (io.length > 0) segments.push(io.join(' / '));\n\n const cache =\n usage.cacheReadTokens !== undefined || usage.cacheCreationTokens !== undefined\n ? (usage.cacheReadTokens ?? 0) + (usage.cacheCreationTokens ?? 0)\n : undefined;\n if (cache !== undefined) segments.push(`${compactTokens(cache)} cache`);\n\n if (usage.costUsd !== undefined) segments.push(`~$${usage.costUsd.toFixed(4)}`);\n\n return segments.join(' · ');\n}\n\n/**\n * True when the usage carries at least one reported field. Handy for deciding\n * whether a metrics line or event is worth emitting at all.\n */\nexport function hasUsageData(usage: ClaudeUsage | null | undefined): boolean {\n if (!usage) return false;\n return USAGE_FIELDS.some((field) => usage[field] !== undefined);\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/headless.ts","../src/routing/budget.ts","../src/agents/health.ts","../src/agents/routing-application.ts","../src/agents/select.ts","../src/agents/invoke.ts","../src/core/decompose.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport chalk from 'chalk';\nimport { invokeSelectedAgent } from '../agents/invoke.js';\nimport { resolveAgentFor } from '../agents/resolve.js';\nimport type {\n AgentEvent,\n AgentInvocation,\n AgentPermission,\n AgentPhase,\n AgentProviderId,\n AgentRunResult,\n} from '../agents/types.js';\nimport { getActiveResilienceConfig } from '../config.js';\nimport { resolvePolicy } from '../resilience/policy.js';\nimport { withRetry } from '../resilience/retry.js';\nimport { writeDiagnostic } from '../storage/diagnostics.js';\nimport { createSpinner, ElapsedTimer, formatDuration, getIcons, useColor } from '../ui/logger.js';\nimport { DECOMPOSITION_THRESHOLDS, timeoutsByPhase } from './decompose.js';\nimport { type ClaudeUsage, sumUsage } from './metrics.js';\nimport { getSessionPublisher } from './session-publisher.js';\nimport { getShutdownSignal } from './shutdown.js';\nimport { isoNow } from './state-manager.js';\nimport {\n getActivityCallback,\n getInactivityTimeout,\n getOutputCallback,\n isVerbose,\n} from './verbose.js';\n\nexport interface HeadlessOptions {\n prompt: string;\n maxTurns?: number;\n timeout?: number;\n outputFormat?: 'json' | 'text' | 'stream-json';\n allowedTools?: string[];\n /**\n * Extra directories the headless session may read from and write to, passed\n * through as `--add-dir`. Required whenever a prompt points at a path outside\n * the working tree (e.g. the global issue storage under `~/.issue-flow`).\n */\n addDirs?: string[];\n /** Status message displayed as spinner (non-verbose) or header (verbose). */\n statusMessage?: string;\n /** Optional callback for routing verbose output (e.g., through listr2 task.output). */\n onOutput?: (line: string) => void;\n /** Journal-backed identity used to apply the one-time 2× timeout escalation. */\n timeoutHistory?: {\n phase: string;\n journalFiles: string[];\n };\n /** The invoking phase. Defaults to `analyze` only for resolution; argv is unchanged. */\n phase?: AgentPhase;\n /**\n * Semantic permission. Absent means `workspace`, which is the historical\n * `runHeadless` argv (no `--permission-mode`, no `--dangerously-skip-permissions`).\n */\n permission?: AgentPermission;\n /** Pin this invocation to a provider (L2 reviewer). */\n forceProvider?: AgentProviderId;\n /** Telemetry purpose when it is not the phase name (`verify`). */\n purpose?: 'verify';\n correctionCycle?: number;\n storyIds?: string[];\n}\n\nexport type HeadlessCost = ClaudeUsage;\n\nexport interface HeadlessResult {\n success: boolean;\n result: string;\n cost: HeadlessCost | null;\n error: string | null;\n agent?: { provider: AgentProviderId; model: string | null };\n /** The resilience budget was spent inside the facade; an outer artifact retry must not repeat it. */\n retryExhausted?: boolean;\n}\n\nexport const DEFAULT_HEADLESS_TIMEOUT_MS = 900_000;\n\nasync function escalatedTimeout(\n timeoutMs: number,\n history: HeadlessOptions['timeoutHistory'],\n): Promise<number> {\n if (timeoutMs === 0 || history === undefined) return timeoutMs;\n\n const journal = (\n await Promise.all(\n history.journalFiles.map(async (file) => {\n try {\n return await readFile(file, 'utf-8');\n } catch {\n return '';\n }\n }),\n )\n ).join('');\n const timeouts = timeoutsByPhase(journal).get(history.phase) ?? 0;\n if (timeouts < DECOMPOSITION_THRESHOLDS.timeoutsPerPhase) return timeoutMs;\n return Math.min(timeoutMs * 2, Number.MAX_SAFE_INTEGER);\n}\n\nfunction printAgentEvent(event: AgentEvent, onOutput?: (line: string) => void): void {\n const icons = getIcons();\n const colored = useColor();\n const emit = onOutput ?? ((msg: string) => process.stdout.write(`${msg}\\n`));\n\n if (event.kind === 'text') {\n const lines = event.text.split('\\n');\n for (const textLine of lines) {\n if (!textLine.trim()) continue;\n const prefix = colored ? chalk.dim(` ${icons.connector} `) : ` ${icons.connector} `;\n const text = colored ? chalk.dim(textLine) : textLine;\n emit(`${prefix}${text}`);\n }\n return;\n }\n\n getSessionPublisher().publish({\n type: 'activity',\n at: isoNow(),\n tool: event.name,\n detail: event.detail,\n });\n const toolName = event.name.padEnd(12);\n const prefix = colored ? chalk.dim(` ${icons.connector} `) : ` ${icons.connector} `;\n const toolIcon = colored ? chalk.cyan(icons.tool) : icons.tool;\n const toolLabel = colored ? chalk.cyan(toolName) : toolName;\n const contextText = event.detail ? (colored ? chalk.dim(event.detail) : event.detail) : '';\n emit(`${prefix}${toolIcon} ${toolLabel} ${contextText}`);\n}\n\nasync function invokeHeadlessAgent(\n invocation: AgentInvocation,\n): Promise<{ run: AgentRunResult; retryExhausted: boolean }> {\n const config = getActiveResilienceConfig();\n if (config.providers?.failover !== true) {\n return { run: (await invokeSelectedAgent(invocation)).run, retryExhausted: false };\n }\n\n let usage: ClaudeUsage | null = null;\n const outcome = await withRetry(() => invokeSelectedAgent(invocation), {\n policy: (failure) => resolvePolicy(failure.kind, config),\n signal: getShutdownSignal(),\n evaluate: (selected) => selected.failure,\n onAttempt: ({ value, failure, willRetry, delayMs, attempt }) => {\n if (value.run.usage !== null) usage = sumUsage(usage, value.run.usage);\n if (failure === null || !willRetry) return;\n getSessionPublisher().publish({\n type: 'retry',\n at: isoNow(),\n attempt,\n delaySeconds: delayMs / 1000,\n reason: failure.message,\n kind: failure.kind,\n });\n writeDiagnostic({\n level: 'warning',\n message: `Retrying ${invocation.phase} after ${failure.kind}`,\n context: { attempt, delayMs, reason: failure.message },\n fields: { phase: invocation.phase },\n });\n },\n });\n\n return {\n run: usage === null ? outcome.value.run : { ...outcome.value.run, usage },\n retryExhausted: outcome.exhausted,\n };\n}\n\n/**\n * Invoke the resolved agent in headless mode.\n *\n * Each invocation is an isolated session. UI (spinner, verbose header, activity)\n * stays here; argv and stream parsing belong to the runner.\n */\nexport async function runHeadless(options: HeadlessOptions): Promise<HeadlessResult> {\n const {\n prompt,\n maxTurns = 10,\n timeout: configuredTimeout = DEFAULT_HEADLESS_TIMEOUT_MS,\n outputFormat = 'json',\n allowedTools,\n addDirs,\n statusMessage,\n onOutput,\n phase = 'analyze',\n permission = 'workspace',\n forceProvider,\n purpose,\n correctionCycle,\n storyIds,\n } = options;\n const timeout = await escalatedTimeout(configuredTimeout, options.timeoutHistory);\n const settings = await resolveAgentFor(phase);\n\n const verbose = isVerbose();\n const effectiveOnOutput = onOutput ?? getOutputCallback();\n\n if (verbose) {\n const icons = getIcons();\n const colored = useColor();\n const emit = effectiveOnOutput ?? ((msg: string) => process.stdout.write(`${msg}\\n`));\n if (statusMessage) {\n const msg = colored\n ? chalk.blue(`${icons.start} ${statusMessage}`)\n : `${icons.start} ${statusMessage}`;\n emit(msg);\n }\n const connectorLine = colored ? chalk.dim(` ${icons.connector}`) : ` ${icons.connector}`;\n emit(connectorLine);\n\n const startTime = Date.now();\n const { run, retryExhausted } = await invokeHeadlessAgent({\n prompt,\n phase,\n addDirs,\n timeout,\n permission,\n maxTurns,\n allowedTools,\n ...(forceProvider === undefined ? {} : { forceProvider }),\n ...(purpose === undefined ? {} : { purpose }),\n ...(correctionCycle === undefined ? {} : { correctionCycle }),\n ...(storyIds === undefined ? {} : { storyIds }),\n onEvent: (event) => printAgentEvent(event, effectiveOnOutput),\n });\n\n const elapsedSec = Math.floor((Date.now() - startTime) / 1000);\n const durationStr = formatDuration(elapsedSec);\n const doneLine = colored\n ? chalk.dim(` ${icons.connector} ${chalk.italic(`Done in ${durationStr}`)}`)\n : ` ${icons.connector} Done in ${durationStr}`;\n emit(doneLine);\n emit(connectorLine);\n\n return mapHeadlessResult(run, outputFormat, retryExhausted);\n }\n\n const spinner = statusMessage ? createSpinner(statusMessage).start() : null;\n let timer: ElapsedTimer | null = null;\n if (spinner) {\n timer = new ElapsedTimer((elapsed) => {\n spinner.suffixText = useColor() ? chalk.dim(`(${elapsed})`) : `(${elapsed})`;\n }).start();\n }\n\n try {\n const { run, retryExhausted } = await invokeHeadlessAgent({\n prompt,\n phase,\n addDirs,\n timeout,\n permission,\n maxTurns,\n allowedTools,\n inactivityTimeoutMs: getInactivityTimeout(),\n ...(forceProvider === undefined ? {} : { forceProvider }),\n ...(purpose === undefined ? {} : { purpose }),\n ...(correctionCycle === undefined ? {} : { correctionCycle }),\n ...(storyIds === undefined ? {} : { storyIds }),\n onEvent: (event) => {\n if (event.kind === 'text') return;\n getSessionPublisher().publish({\n type: 'activity',\n at: isoNow(),\n tool: event.name,\n detail: event.detail,\n });\n getActivityCallback()?.({ tool: event.name, detail: event.detail });\n },\n });\n\n const elapsed = timer?.stop() ?? 0;\n const dur = useColor()\n ? chalk.dim(` (${formatDuration(elapsed)})`)\n : ` (${formatDuration(elapsed)})`;\n\n if (!run.success) {\n spinner?.fail(`${statusMessage}${dur}`);\n return mapHeadlessResult(run, outputFormat, retryExhausted);\n }\n\n spinner?.succeed(`${statusMessage}${dur}`);\n return mapHeadlessResult(run, outputFormat, retryExhausted);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const catchElapsed = timer?.stop() ?? 0;\n const catchDur = useColor()\n ? chalk.dim(` (${formatDuration(catchElapsed)})`)\n : ` (${formatDuration(catchElapsed)})`;\n spinner?.fail(`${statusMessage}${catchDur}`);\n return {\n success: false,\n result: '',\n cost: null,\n error: message,\n agent: { provider: settings.provider, model: settings.model },\n };\n }\n}\n\nfunction mapHeadlessResult(\n run: {\n success: boolean;\n result: string;\n rawOutput: string;\n usage: ClaudeUsage | null;\n error: string | null;\n agent: { provider: AgentProviderId; model: string | null };\n },\n outputFormat: 'json' | 'text' | 'stream-json',\n retryExhausted = false,\n): HeadlessResult {\n if (outputFormat === 'text') {\n return {\n success: run.success,\n result: run.success ? run.rawOutput || run.result : '',\n cost: null,\n error: run.error,\n agent: run.agent,\n ...(retryExhausted ? { retryExhausted: true } : {}),\n };\n }\n if (!run.success) {\n return {\n success: false,\n result: '',\n cost: null,\n error: run.error,\n agent: run.agent,\n ...(retryExhausted ? { retryExhausted: true } : {}),\n };\n }\n return {\n success: true,\n result: run.result,\n cost: run.usage,\n error: null,\n agent: run.agent,\n ...(retryExhausted ? { retryExhausted: true } : {}),\n };\n}\n","import type { CostRecord, StopReason } from '../telemetry/types.js';\n\nexport interface RoutingCeilings {\n maxCostUsdPerIssue: number | null;\n maxDurationMsPerIssue: number | null;\n maxExecutionsPerIssue: number | null;\n onCeiling: 'block';\n}\n\nexport const DEFAULT_CEILINGS: RoutingCeilings = {\n maxCostUsdPerIssue: null,\n maxDurationMsPerIssue: null,\n maxExecutionsPerIssue: null,\n onCeiling: 'block',\n};\n\nexport interface SpentSnapshot {\n /** Observed reported USD only. `unknown` / `estimated` do not fill this. */\n reportedUsd: number;\n costStatus: CostRecord['status'];\n durationMs: number;\n executions: number;\n}\n\nexport type CeilingBinding = 'cost' | 'duration' | 'executions';\n\nexport type CeilingVerdict =\n | { ok: true; binding: null }\n | {\n ok: false;\n stopReason: Extract<StopReason, 'max_cost' | 'max_duration' | 'max_attempts'>;\n binding: CeilingBinding;\n onCeiling: 'block';\n numbers: { spent: number; ceiling: number };\n /** Which ceiling is actually in force when cost is unknown. */\n enforced: CeilingBinding[];\n };\n\n/**\n * Single choke point. A harness flag is never a substitute: a runner that\n * ignores `--max-budget-usd` still stops here.\n */\nexport function evaluateCeilings(input: {\n ceilings?: Partial<RoutingCeilings> | undefined;\n spent: SpentSnapshot;\n}): CeilingVerdict {\n const ceilings = { ...DEFAULT_CEILINGS, ...input.ceilings };\n const enforced: CeilingBinding[] = [];\n if (ceilings.maxCostUsdPerIssue !== null && input.spent.costStatus === 'reported') {\n enforced.push('cost');\n }\n if (ceilings.maxDurationMsPerIssue !== null) enforced.push('duration');\n if (ceilings.maxExecutionsPerIssue !== null) enforced.push('executions');\n\n if (\n ceilings.maxCostUsdPerIssue !== null &&\n input.spent.costStatus === 'reported' &&\n input.spent.reportedUsd >= ceilings.maxCostUsdPerIssue\n ) {\n return {\n ok: false,\n stopReason: 'max_cost',\n binding: 'cost',\n onCeiling: 'block',\n numbers: { spent: input.spent.reportedUsd, ceiling: ceilings.maxCostUsdPerIssue },\n enforced,\n };\n }\n\n if (\n ceilings.maxDurationMsPerIssue !== null &&\n input.spent.durationMs >= ceilings.maxDurationMsPerIssue\n ) {\n return {\n ok: false,\n stopReason: 'max_duration',\n binding: 'duration',\n onCeiling: 'block',\n numbers: { spent: input.spent.durationMs, ceiling: ceilings.maxDurationMsPerIssue },\n enforced,\n };\n }\n\n if (\n ceilings.maxExecutionsPerIssue !== null &&\n input.spent.executions >= ceilings.maxExecutionsPerIssue\n ) {\n return {\n ok: false,\n stopReason: 'max_attempts',\n binding: 'executions',\n onCeiling: 'block',\n numbers: { spent: input.spent.executions, ceiling: ceilings.maxExecutionsPerIssue },\n enforced,\n };\n }\n\n return { ok: true, binding: null };\n}\n\nexport function spendFromCost(cost: CostRecord): Pick<SpentSnapshot, 'reportedUsd' | 'costStatus'> {\n if (cost.status === 'reported') {\n return { reportedUsd: cost.amount, costStatus: 'reported' };\n }\n return { reportedUsd: 0, costStatus: cost.status };\n}\n\n/** `blocked` is only left by a human — the machine never unblocks a ceiling. */\nexport function canLeaveBlocked(actor: string): boolean {\n return actor === 'human';\n}\n","import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { ClassifiedFailure, FailureKind } from '../resilience/errors.js';\nimport {\n type ProviderHealthRecord,\n type ProvidersHealth,\n providersHealthSchema,\n type ResilienceProvidersConfig,\n} from '../storage/schemas.js';\n\nexport const DEFAULT_PROVIDER_COOLDOWN_MS = 60_000;\nexport const DEFAULT_PROVIDER_MAX_COOLDOWN_MS = 30 * 60_000;\nexport const DEFAULT_PROVIDER_FAILURE_WINDOW_MS = 5 * 60_000;\nexport const DEFAULT_PROVIDER_FAILURES_TO_TRIP = 3;\n\nexport interface ProviderHealthOptions {\n now?: () => number;\n config?: ResilienceProvidersConfig;\n}\n\nexport interface ResolvedProviderHealthConfig {\n cooldownMs: number;\n maxCooldownMs: number;\n failureWindowMs: number;\n failuresToTrip: number;\n}\n\nexport function resolveProviderHealthConfig(\n config: ResilienceProvidersConfig = {},\n): ResolvedProviderHealthConfig {\n return {\n cooldownMs: Math.max(0, config.cooldownMs ?? DEFAULT_PROVIDER_COOLDOWN_MS),\n maxCooldownMs: Math.max(\n config.cooldownMs ?? DEFAULT_PROVIDER_COOLDOWN_MS,\n config.maxCooldownMs ?? DEFAULT_PROVIDER_MAX_COOLDOWN_MS,\n ),\n failureWindowMs: Math.max(1, config.failureWindowMs ?? DEFAULT_PROVIDER_FAILURE_WINDOW_MS),\n failuresToTrip: Math.max(\n 1,\n Math.trunc(config.failuresToTrip ?? DEFAULT_PROVIDER_FAILURES_TO_TRIP),\n ),\n };\n}\n\nfunction emptyHealth(): ProvidersHealth {\n return providersHealthSchema.parse({});\n}\n\nfunction emptyRecord(): ProviderHealthRecord {\n return providersHealthSchema.parse({ providers: { provider: {} } }).providers.provider;\n}\n\nexport async function readProvidersHealth(filePath: string): Promise<ProvidersHealth> {\n try {\n return providersHealthSchema.parse(JSON.parse(await readFile(filePath, 'utf-8')));\n } catch {\n return emptyHealth();\n }\n}\n\nasync function writeProvidersHealth(filePath: string, value: ProvidersHealth): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n const tmp = `${filePath}.tmp-${process.pid}`;\n await writeFile(tmp, `${JSON.stringify(value, null, 2)}\\n`, 'utf-8');\n await rename(tmp, filePath);\n}\n\nasync function updateRecord(\n filePath: string,\n provider: string,\n update: (record: ProviderHealthRecord) => ProviderHealthRecord,\n): Promise<ProviderHealthRecord> {\n const health = await readProvidersHealth(filePath);\n const next = update(health.providers[provider] ?? emptyRecord());\n await writeProvidersHealth(filePath, {\n ...health,\n providers: { ...health.providers, [provider]: next },\n });\n return next;\n}\n\nfunction cooldownDelay(level: number, config: ResolvedProviderHealthConfig): number {\n return Math.min(config.maxCooldownMs, config.cooldownMs * 2 ** Math.max(0, level));\n}\n\nconst BREAKER_KINDS = new Set<FailureKind>([\n 'timeout',\n 'stalled',\n 'provider_down',\n 'provider_crash',\n]);\n\nexport async function recordProviderFailure(\n filePath: string,\n provider: string,\n failure: ClassifiedFailure,\n options: ProviderHealthOptions = {},\n): Promise<ProviderHealthRecord> {\n const nowMs = options.now?.() ?? Date.now();\n const at = new Date(nowMs).toISOString();\n const config = resolveProviderHealthConfig(options.config);\n\n return updateRecord(filePath, provider, (record) => {\n const failures = [\n ...record.failures.filter((entry) => {\n const timestamp = Date.parse(entry.at);\n return Number.isFinite(timestamp) && nowMs - timestamp <= config.failureWindowMs;\n }),\n { at, kind: failure.kind },\n ];\n const consecutiveFailures = record.consecutiveFailures + 1;\n\n if (failure.kind === 'authentication') {\n return {\n ...record,\n status: 'auth_failed',\n failures,\n consecutiveFailures,\n cooldownUntil: null,\n lastFailureKind: failure.kind,\n lastFailureAt: at,\n probeInFlight: false,\n probeStartedAt: null,\n };\n }\n\n if (failure.kind === 'rate_limit') {\n const delay = failure.retryAfterMs ?? cooldownDelay(record.cooldownLevel, config);\n return {\n ...record,\n status: 'rate_limited',\n failures,\n consecutiveFailures,\n cooldownLevel:\n failure.retryAfterMs === undefined ? record.cooldownLevel + 1 : record.cooldownLevel,\n cooldownUntil: new Date(nowMs + delay).toISOString(),\n lastFailureKind: failure.kind,\n lastFailureAt: at,\n probeInFlight: false,\n probeStartedAt: null,\n };\n }\n\n if (BREAKER_KINDS.has(failure.kind)) {\n const recentProviderFailures = failures.filter((entry) =>\n BREAKER_KINDS.has(entry.kind),\n ).length;\n const unavailable =\n record.status === 'half_open' || recentProviderFailures >= config.failuresToTrip;\n const delay = unavailable ? cooldownDelay(record.cooldownLevel, config) : 0;\n return {\n ...record,\n status: unavailable ? 'unavailable' : 'degraded',\n failures,\n consecutiveFailures,\n cooldownLevel: unavailable ? record.cooldownLevel + 1 : record.cooldownLevel,\n cooldownUntil: unavailable ? new Date(nowMs + delay).toISOString() : null,\n lastFailureKind: failure.kind,\n lastFailureAt: at,\n probeInFlight: false,\n probeStartedAt: null,\n };\n }\n\n // Network and task/repository/configuration failures do not describe the\n // provider's health. Keep the breaker state, but retain the diagnosis for\n // audit and dashboard surfaces.\n return {\n ...record,\n lastFailureKind: failure.kind,\n lastFailureAt: at,\n probeInFlight: false,\n probeStartedAt: null,\n };\n });\n}\n\nexport async function recordProviderSuccess(\n filePath: string,\n provider: string,\n options: Pick<ProviderHealthOptions, 'now'> = {},\n): Promise<ProviderHealthRecord> {\n const at = new Date(options.now?.() ?? Date.now()).toISOString();\n return updateRecord(filePath, provider, (record) => ({\n ...record,\n status: 'healthy',\n failures: [],\n consecutiveFailures: 0,\n cooldownLevel: 0,\n cooldownUntil: null,\n lastFailureKind: null,\n lastSuccessAt: at,\n probeInFlight: false,\n probeStartedAt: null,\n }));\n}\n\n/** Open the circuit when retry policy asks for failover before the trip count. */\nexport async function openProviderCircuit(\n filePath: string,\n provider: string,\n options: ProviderHealthOptions = {},\n): Promise<ProviderHealthRecord> {\n const nowMs = options.now?.() ?? Date.now();\n const config = resolveProviderHealthConfig(options.config);\n return updateRecord(filePath, provider, (record) => {\n if (record.status === 'unavailable' || record.status === 'rate_limited') return record;\n const delay = cooldownDelay(record.cooldownLevel, config);\n return {\n ...record,\n status: 'unavailable',\n cooldownLevel: record.cooldownLevel + 1,\n cooldownUntil: new Date(nowMs + delay).toISOString(),\n probeInFlight: false,\n probeStartedAt: null,\n };\n });\n}\n\nexport interface HalfOpenResult {\n acquired: boolean;\n record: ProviderHealthRecord;\n}\n\n/** Atomically enough for the project-level single-run lock: one half-open probe per provider. */\nexport async function acquireHalfOpenProbe(\n filePath: string,\n provider: string,\n options: ProviderHealthOptions = {},\n): Promise<HalfOpenResult> {\n const nowMs = options.now?.() ?? Date.now();\n const at = new Date(nowMs).toISOString();\n const config = resolveProviderHealthConfig(options.config);\n let acquired = false;\n const record = await updateRecord(filePath, provider, (current) => {\n const cooldownUntil = current.cooldownUntil === null ? 0 : Date.parse(current.cooldownUntil);\n if (Number.isFinite(cooldownUntil) && cooldownUntil > nowMs) return current;\n\n const probeStarted = current.probeStartedAt === null ? 0 : Date.parse(current.probeStartedAt);\n const probeIsFresh =\n current.probeInFlight &&\n Number.isFinite(probeStarted) &&\n nowMs - probeStarted < config.cooldownMs;\n if (probeIsFresh) return current;\n\n acquired = true;\n return {\n ...current,\n status: 'half_open',\n cooldownUntil: null,\n probeInFlight: true,\n probeStartedAt: at,\n };\n });\n return { acquired, record };\n}\n","import type { RoutingDecision } from '../routing/types.js';\nimport type { AgentAvailability } from './availability.js';\nimport { probeAgent } from './availability.js';\nimport { runnerFor } from './registry.js';\nimport type { AgentSelection } from './select.js';\nimport type { AgentPhase, AgentProviderId } from './types.js';\nimport { isAgentProviderId } from './types.js';\n\nexport interface RoutingApplicationResult {\n selection: AgentSelection;\n applied: boolean;\n warning: string | null;\n /** Candidates tried before the applied (or final failed) target. */\n fallbackFrom: Array<{ provider: string; model: string | null; reason: string }>;\n}\n\nexport function routingRecommendationLine(\n decision: RoutingDecision | null,\n phase: AgentPhase,\n): string | null {\n if (\n decision === null ||\n decision.mode !== 'recommend' ||\n decision.reasonCodes.includes('EXPLICIT_CONFIG')\n ) {\n return null;\n }\n const tier = decision.selected.tier ? ` (${decision.selected.tier})` : '';\n return `Routing suggests ${decision.selected.provider}:${decision.selected.model ?? 'default'}${tier} for ${phase} (${decision.reasonCodes.join(', ')}) · apply with routing.mode active`;\n}\n\nfunction isAttemptable(availability: AgentAvailability): boolean {\n return (\n availability.installed &&\n availability.authentication !== 'failed' &&\n availability.state !== 'unavailable'\n );\n}\n\n/**\n * Apply an active decision without changing invocation permission. Walks the\n * ranked eligible list when the top target is unavailable; explicit config is\n * never overridden. Fail-open to the original selection when nothing works.\n */\nexport async function applyRoutingDecision(\n original: AgentSelection,\n decision: RoutingDecision | null,\n phase: AgentPhase,\n options: { probe?: (provider: AgentProviderId) => Promise<AgentAvailability> } = {},\n): Promise<RoutingApplicationResult> {\n if (\n decision === null ||\n decision.mode !== 'active' ||\n decision.reasonCodes.includes('EXPLICIT_CONFIG') ||\n original.failover\n ) {\n return { selection: original, applied: false, warning: null, fallbackFrom: [] };\n }\n\n const probe = options.probe ?? probeAgent;\n const ranked = decision.candidates\n .filter((candidate) => candidate.eligible)\n .sort((a, b) => b.score - a.score);\n const fallbackFrom: RoutingApplicationResult['fallbackFrom'] = [];\n\n for (const candidate of ranked) {\n if (!isAgentProviderId(candidate.provider)) {\n fallbackFrom.push({\n provider: candidate.provider,\n model: candidate.model ?? null,\n reason: 'unregistered provider',\n });\n continue;\n }\n if (\n candidate.model !== null &&\n candidate.model !== undefined &&\n !runnerFor(candidate.provider).capabilities.modelSelection\n ) {\n fallbackFrom.push({\n provider: candidate.provider,\n model: candidate.model,\n reason: 'rejects model selection',\n });\n continue;\n }\n\n const availability = await probe(candidate.provider);\n if (!isAttemptable(availability)) {\n fallbackFrom.push({\n provider: candidate.provider,\n model: candidate.model ?? null,\n reason: availability.installed\n ? availability.authentication === 'failed'\n ? 'not authenticated'\n : `state=${availability.state}`\n : 'not installed',\n });\n continue;\n }\n\n const warning =\n fallbackFrom.length > 0\n ? `Routing fell back to ${candidate.provider}:${candidate.model ?? 'default'} for ${phase} after ${fallbackFrom.map((entry) => `${entry.provider} (${entry.reason})`).join(', ')}.`\n : null;\n\n return {\n applied: true,\n warning,\n fallbackFrom,\n selection: {\n ...original,\n primary: candidate.provider,\n provider: candidate.provider,\n settings: {\n ...original.settings,\n provider: candidate.provider,\n model: candidate.model ?? null,\n origin: { provider: 'default', model: 'default' },\n },\n failover: false,\n reason: null,\n cooldownUntil: null,\n },\n };\n }\n\n const tried =\n fallbackFrom.length > 0\n ? fallbackFrom.map((entry) => `${entry.provider} (${entry.reason})`).join(', ')\n : 'no eligible candidates';\n return {\n selection: original,\n applied: false,\n fallbackFrom,\n warning: `Routing found no usable ranked target for ${phase} (${tried}); using ${original.provider}.`,\n };\n}\n","import { getActiveResilienceConfig } from '../config.js';\nimport { getShutdownSignal } from '../core/shutdown.js';\nimport type { FailureKind } from '../resilience/errors.js';\nimport { abortableDelay, resolvePolicy, shouldFailover } from '../resilience/policy.js';\nimport { resolveProjectPaths } from '../storage/resolve.js';\nimport type { ProviderHealthRecord, ResilienceConfig } from '../storage/schemas.js';\nimport {\n acquireHalfOpenProbe,\n openProviderCircuit,\n readProvidersHealth,\n resolveProviderHealthConfig,\n} from './health.js';\nimport { ensureRunnersRegistered, getRegisteredProviders } from './registry.js';\nimport { resolveAgentFor } from './resolve.js';\nimport {\n type AgentPhase,\n type AgentProviderId,\n isAgentProviderId,\n type ResolvedAgentSettings,\n} from './types.js';\n\nexport interface AgentSelection {\n primary: AgentProviderId;\n provider: AgentProviderId;\n settings: ResolvedAgentSettings;\n healthFile: string | null;\n failover: boolean;\n reason: FailureKind | null;\n cooldownUntil: string | null;\n}\n\nexport class AgentSelectionBlockedError extends Error {\n readonly provider: AgentProviderId;\n readonly kind: FailureKind;\n\n constructor(provider: AgentProviderId, kind: FailureKind) {\n super(\n `Authentication failed for agent provider '${provider}' (${kind}); the run is blocked. Authenticate or repair that provider before resuming.`,\n );\n this.name = 'AgentSelectionBlockedError';\n this.provider = provider;\n this.kind = kind;\n }\n}\n\ninterface CandidateVerdict {\n available: boolean;\n waitMs: number | null;\n cooldownUntil: string | null;\n reason: FailureKind | null;\n blocked: boolean;\n}\n\nfunction remainingMs(until: string | null, nowMs: number): number | null {\n if (until === null) return null;\n const parsed = Date.parse(until);\n return Number.isFinite(parsed) ? Math.max(0, parsed - nowMs) : null;\n}\n\nfunction failoverIsDue(\n record: ProviderHealthRecord | undefined,\n config: ResilienceConfig,\n): boolean {\n if (record?.lastFailureKind == null) return false;\n return shouldFailover(resolvePolicy(record.lastFailureKind, config), record.consecutiveFailures);\n}\n\nasync function verdictFor(\n provider: AgentProviderId,\n record: ProviderHealthRecord | undefined,\n options: {\n healthFile: string;\n config: ResilienceConfig;\n primary: boolean;\n nowMs: number;\n },\n): Promise<CandidateVerdict> {\n if (record === undefined || record.status === 'healthy') {\n return { available: true, waitMs: null, cooldownUntil: null, reason: null, blocked: false };\n }\n\n const reason = record.lastFailureKind;\n if (record.status === 'auth_failed') {\n const mayFailover = reason !== null && failoverIsDue(record, options.config);\n return {\n available: false,\n waitMs: null,\n cooldownUntil: null,\n reason,\n blocked: options.primary && !mayFailover,\n };\n }\n\n if (record.status === 'degraded') {\n const due = failoverIsDue(record, options.config);\n const opened = due\n ? await openProviderCircuit(options.healthFile, provider, {\n now: () => options.nowMs,\n config: options.config.providers,\n })\n : record;\n return {\n available: !due,\n waitMs: due ? remainingMs(opened.cooldownUntil, options.nowMs) : null,\n cooldownUntil: opened.cooldownUntil,\n reason,\n blocked: false,\n };\n }\n\n // `half_open` joins the two closed states on purpose: `acquireHalfOpenProbe`\n // is the only place that knows a probe went stale, and a record left\n // `probeInFlight` by a SIGKILLed run is otherwise never reclaimed — the next\n // run just waits on a cooldown that never ends.\n if (\n record.status === 'unavailable' ||\n record.status === 'rate_limited' ||\n record.status === 'half_open'\n ) {\n const waitMs = remainingMs(record.cooldownUntil, options.nowMs);\n if (waitMs !== null && waitMs > 0) {\n return {\n available: false,\n waitMs,\n cooldownUntil: record.cooldownUntil,\n reason,\n blocked: false,\n };\n }\n const probe = await acquireHalfOpenProbe(options.healthFile, provider, {\n now: () => options.nowMs,\n config: options.config.providers,\n });\n return {\n available: probe.acquired,\n waitMs: probe.acquired\n ? null\n : resolveProviderHealthConfig(options.config.providers).cooldownMs,\n cooldownUntil: probe.record.cooldownUntil,\n reason,\n blocked: false,\n };\n }\n\n return { available: true, waitMs: null, cooldownUntil: null, reason, blocked: false };\n}\n\nfunction providerOrder(primary: AgentProviderId, config: ResilienceConfig): AgentProviderId[] {\n ensureRunnersRegistered();\n const registered = getRegisteredProviders();\n const configured = (config.providers?.chain ?? []).filter(isAgentProviderId);\n return [...new Set([primary, ...configured, ...registered])];\n}\n\nfunction settingsFor(\n base: ResolvedAgentSettings,\n provider: AgentProviderId,\n): ResolvedAgentSettings {\n if (provider === base.provider) return base;\n return {\n ...base,\n provider,\n // A model name belongs to the configured primary unless the selected\n // provider is that primary. Passing a Claude alias to Codex (or vice\n // versa) is less useful than letting the fallback use its own default.\n model: null,\n };\n}\n\n/**\n * Select one provider. When every provider is cooling down, wait for the\n * earliest circuit instead of turning a temporary absence into a failed run.\n */\nexport async function selectAgentForInvocation(\n phase: AgentPhase,\n options: {\n config?: ResilienceConfig;\n now?: () => number;\n delay?: (ms: number, options: { signal?: AbortSignal }) => Promise<boolean>;\n } = {},\n): Promise<AgentSelection> {\n const config = options.config ?? getActiveResilienceConfig();\n const base = await resolveAgentFor(phase);\n const failover = config.providers?.failover === true;\n if (!failover) {\n return {\n primary: base.provider,\n provider: base.provider,\n settings: base,\n healthFile: null,\n failover: false,\n reason: null,\n cooldownUntil: null,\n };\n }\n\n let healthFile: string;\n try {\n healthFile = (await resolveProjectPaths()).providersHealthFile;\n } catch {\n return {\n primary: base.provider,\n provider: base.provider,\n settings: base,\n healthFile: null,\n failover: true,\n reason: null,\n cooldownUntil: null,\n };\n }\n\n const delay = options.delay ?? abortableDelay;\n selection: for (;;) {\n const nowMs = options.now?.() ?? Date.now();\n const health = await readProvidersHealth(healthFile);\n const waits: number[] = [];\n let primaryReason: FailureKind | null = null;\n let primaryCooldown: string | null = null;\n\n for (const provider of providerOrder(base.provider, config)) {\n const verdict = await verdictFor(provider, health.providers[provider], {\n healthFile,\n config,\n primary: provider === base.provider,\n nowMs,\n });\n if (provider === base.provider) {\n primaryReason = verdict.reason;\n primaryCooldown = verdict.cooldownUntil;\n }\n if (verdict.blocked && verdict.reason !== null) {\n throw new AgentSelectionBlockedError(provider, verdict.reason);\n }\n if (\n provider === base.provider &&\n !verdict.available &&\n verdict.waitMs !== null &&\n !failoverIsDue(health.providers[provider], config)\n ) {\n if (!(await delay(Math.max(1, verdict.waitMs), { signal: getShutdownSignal() }))) {\n throw new Error('Agent provider selection was interrupted while waiting for cooldown.');\n }\n continue selection;\n }\n if (verdict.available) {\n return {\n primary: base.provider,\n provider,\n settings: settingsFor(base, provider),\n healthFile,\n failover: provider !== base.provider,\n reason: provider === base.provider ? null : primaryReason,\n cooldownUntil: primaryCooldown,\n };\n }\n if (verdict.waitMs !== null) waits.push(verdict.waitMs);\n }\n\n const waitMs = waits.length > 0 ? Math.max(1, Math.min(...waits)) : null;\n if (waitMs === null) {\n throw new Error(\n 'No healthy agent provider is available and none has a cooldown to wait for.',\n );\n }\n if (!(await delay(waitMs, { signal: getShutdownSignal() }))) {\n throw new Error('Agent provider selection was interrupted while waiting for cooldown.');\n }\n }\n}\n","import {\n getActiveResilienceConfig,\n getAgentCliOverrides,\n loadAgentConfig,\n loadRoutingConfig,\n} from '../config.js';\nimport { getSessionPublisher } from '../core/session-publisher.js';\nimport { isoNow } from '../core/state-manager.js';\nimport { type ClassifiedFailure, classify, type FailureKind } from '../resilience/errors.js';\nimport { evaluateCeilings } from '../routing/budget.js';\nimport { decideRouting } from '../routing/decide.js';\nimport { bindDiagnosticContext, writeDiagnostic } from '../storage/diagnostics.js';\nimport type { ProviderHealthRecord } from '../storage/schemas.js';\nimport { beginExecution, endExecution } from '../telemetry/recorder.js';\nimport { redactSecrets } from '../telemetry/redact.js';\nimport type { ExecutionPurpose, ExecutionRecord, ExecutionTrigger } from '../telemetry/types.js';\nimport { printInfo } from '../ui/logger.js';\nimport { resolveAntigravityTimeoutMs } from './antigravity.js';\nimport { probeReadinessInventory } from './availability.js';\nimport { peekHarnessVersion } from './claude.js';\nimport { recordProviderFailure, recordProviderSuccess } from './health.js';\nimport { ensureCursorStorageGrant } from './permissions.js';\nimport { runnerFor } from './registry.js';\nimport { hasExplicitAgentSelection, resolveAgentFor } from './resolve.js';\nimport { applyRoutingDecision, routingRecommendationLine } from './routing-application.js';\nimport { type AgentSelection, selectAgentForInvocation } from './select.js';\nimport type { AgentInvocation, AgentProviderId, AgentRunResult } from './types.js';\n\nasync function selectionForForced(invocation: AgentInvocation): Promise<AgentSelection> {\n const settings = await resolveAgentFor(invocation.phase, {\n cli: { forceProvider: invocation.forceProvider },\n });\n return {\n primary: settings.provider,\n provider: settings.provider,\n settings,\n healthFile: null,\n failover: false,\n reason: null,\n cooldownUntil: null,\n };\n}\n\nconst attempts = new Map<string, number>();\nconst lastFailure = new Map<string, FailureKind>();\nconst issueSpend = {\n reportedUsd: 0,\n durationMs: 0,\n executions: 0,\n sawReported: false,\n};\n\n/** Declared identity of a runner — never inferred from argv or logs. */\nexport function declaredAgentIdentity(provider: AgentProviderId): {\n harness: string;\n vendor: string;\n} {\n switch (provider) {\n case 'claude':\n return { harness: 'claude-code', vendor: 'anthropic' };\n case 'codex':\n return { harness: 'codex-cli', vendor: 'openai' };\n case 'cursor':\n return { harness: 'cursor-cli', vendor: 'cursor' };\n case 'antigravity':\n return { harness: 'antigravity-cli', vendor: 'google' };\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\nfunction triggerOf(\n selection: AgentSelection,\n attempt: number,\n correctionCycle = 0,\n): ExecutionTrigger {\n if (selection.failover) return 'fallback';\n if (attempt > 1) return 'retry';\n if (correctionCycle > 0) return 'correction';\n return 'initial';\n}\n\nexport interface SelectedAgentRun {\n run: AgentRunResult;\n failure: ClassifiedFailure | null;\n selection: AgentSelection;\n attempt: number;\n health: ProviderHealthRecord | null;\n blocked?: { stopReason: string; detail: string; actor: 'human' };\n}\n\nfunction nextAttempt(phase: string): number {\n const attempt = (attempts.get(phase) ?? 0) + 1;\n attempts.set(phase, attempt);\n return attempt;\n}\n\nexport function resetAgentInvocationState(): void {\n attempts.clear();\n lastFailure.clear();\n issueSpend.reportedUsd = 0;\n issueSpend.durationMs = 0;\n issueSpend.executions = 0;\n issueSpend.sawReported = false;\n}\n\n/** One invocation, including provider selection, health persistence and audit events. */\nexport async function invokeSelectedAgent(invocation: AgentInvocation): Promise<SelectedAgentRun> {\n const config = getActiveResilienceConfig();\n let selection =\n invocation.forceProvider === undefined\n ? await selectAgentForInvocation(invocation.phase, { config })\n : await selectionForForced(invocation);\n const originalIdentity = declaredAgentIdentity(selection.provider);\n const routingCfg = await loadRoutingConfig();\n const agentCfg = await loadAgentConfig();\n let readiness = null;\n if (routingCfg.mode === 'recommend' || routingCfg.mode === 'active') {\n try {\n readiness = await probeReadinessInventory({\n cooldowns: selection.cooldownUntil\n ? { [selection.provider]: selection.cooldownUntil }\n : undefined,\n });\n } catch {\n // Inventory is best-effort. A probe failure must not block the run —\n // decideRouting falls back to catalog-only scoring.\n readiness = null;\n }\n }\n const routingDecision = decideRouting({\n phase: invocation.phase,\n actualHarness: originalIdentity.harness,\n actualProvider: selection.provider,\n actualModel: selection.settings.model,\n mode: routingCfg.mode,\n profile: routingCfg.profile,\n policy: routingCfg.policy,\n skipScore: hasExplicitAgentSelection(agentCfg, getAgentCliOverrides(), invocation.phase),\n requiresExtraDirectories: (invocation.addDirs?.length ?? 0) > 0,\n readiness,\n });\n const recommendation = routingRecommendationLine(routingDecision, invocation.phase);\n if (recommendation !== null) printInfo(recommendation);\n const routed = await applyRoutingDecision(selection, routingDecision, invocation.phase);\n selection = routed.selection;\n if (routed.warning !== null) {\n writeDiagnostic({\n level: 'warning',\n message: routed.warning,\n context: { fallbackFrom: routed.fallbackFrom },\n fields: {\n phase: invocation.phase,\n harness: originalIdentity.harness,\n model: selection.settings.model,\n },\n });\n }\n const attempt = nextAttempt(invocation.phase);\n const publisher = getSessionPublisher();\n publisher.publish({\n type: 'agent:attempt',\n at: isoNow(),\n attempt,\n provider: selection.provider,\n model: selection.settings.model,\n primaryProvider: selection.primary,\n });\n if (selection.failover) {\n publisher.publish({\n type: 'failover',\n at: isoNow(),\n from: selection.primary,\n to: selection.provider,\n reason: selection.reason,\n cooldownUntil: selection.cooldownUntil,\n });\n writeDiagnostic({\n level: 'warning',\n message: `Agent failover from ${selection.primary} to ${selection.provider}`,\n context: { reason: selection.reason, cooldownUntil: selection.cooldownUntil },\n fields: {\n phase: invocation.phase,\n harness: selection.provider,\n model: selection.settings.model,\n },\n });\n }\n\n const identity = declaredAgentIdentity(selection.provider);\n const requested = selection.settings.model;\n const recordedRoutingDecision =\n routingDecision !== null && routed.applied\n ? {\n ...routingDecision,\n actual: {\n harness: identity.harness,\n provider: selection.provider,\n model: requested,\n },\n }\n : routingDecision;\n const executionId = await beginExecution({\n purpose: (invocation.purpose ?? invocation.phase) as ExecutionPurpose,\n attempt,\n trigger: triggerOf(selection, attempt, invocation.correctionCycle),\n triggerReason: selection.failover\n ? selection.reason\n : attempt > 1\n ? (lastFailure.get(invocation.phase) ?? null)\n : null,\n harness: identity.harness,\n provider: identity.vendor,\n harnessVersion: peekHarnessVersion(selection.provider) ?? null,\n modelRequested: requested,\n modelResolved: null,\n modelSource: requested ? (routed.applied ? 'routing' : 'config') : 'unavailable',\n ...(invocation.iteration === undefined ? {} : { iteration: invocation.iteration }),\n ...(invocation.correctionCycle === undefined\n ? {}\n : { correctionCycle: invocation.correctionCycle }),\n ...(invocation.storyIds === undefined ? {} : { storyIds: invocation.storyIds }),\n ...(recordedRoutingDecision === null\n ? {}\n : {\n routingDecision: recordedRoutingDecision as unknown as ExecutionRecord['routingDecision'],\n }),\n });\n bindDiagnosticContext({\n executionId,\n phase: invocation.phase,\n harness: identity.harness,\n model: requested,\n story: invocation.storyIds?.join(',') ?? null,\n });\n\n const runner = runnerFor(selection.provider);\n const ceiling = evaluateCeilings({\n ceilings: routingCfg.ceilings,\n spent: {\n reportedUsd: issueSpend.reportedUsd,\n costStatus: issueSpend.sawReported ? 'reported' : 'unknown',\n durationMs: issueSpend.durationMs,\n executions: issueSpend.executions,\n },\n });\n if (!ceiling.ok) {\n const detail = `blocked by ${ceiling.binding} ceiling (${ceiling.numbers.spent} ≥ ${ceiling.numbers.ceiling}). Enforced by Issue Flow, not by a harness flag.`;\n const run = {\n success: false,\n result: '',\n rawOutput: detail,\n exitCode: 1,\n usage: null,\n error: detail,\n agent: { provider: selection.provider, model: selection.settings.model },\n harnessVersion: peekHarnessVersion(selection.provider),\n };\n if (executionId !== null) {\n await endExecution({\n id: executionId,\n status: 'failed',\n error: detail,\n exitCode: 1,\n stopReason: ceiling.stopReason,\n });\n }\n return {\n run,\n failure: null,\n selection,\n attempt,\n health: null,\n blocked: { stopReason: ceiling.stopReason, detail, actor: 'human' },\n };\n }\n if (\n runner.capabilities.nativeTimeout &&\n invocation.timeout === 0 &&\n resolveAntigravityTimeoutMs(invocation, selection.settings) === null\n ) {\n const run = {\n success: false,\n result: '',\n rawOutput:\n 'configuration: provider has nativeTimeout and received timeout: 0 without a ceiling.',\n exitCode: 1,\n usage: null,\n error:\n 'configuration: provider has nativeTimeout and received timeout: 0 without a ceiling. Set agent.antigravity.executeTimeout.',\n agent: { provider: selection.provider, model: selection.settings.model },\n harnessVersion: peekHarnessVersion(selection.provider),\n };\n if (executionId !== null) {\n await endExecution({\n id: executionId,\n status: 'failed',\n error: run.error,\n exitCode: 1,\n });\n }\n const failure = classify({ source: 'agent', exitCode: 1, stdout: run.error });\n return { run, failure, selection, attempt, health: null };\n }\n if (\n (invocation.addDirs?.length ?? 0) > 0 &&\n runner.capabilities.extraDirectories === 'permission-file'\n ) {\n const grant =\n selection.settings.cursor.permissionsFile === 'none'\n ? { skipped: true as const, reason: 'none' as const }\n : await ensureCursorStorageGrant({\n mode: selection.settings.cursor.permissionsFile ?? 'global',\n });\n if ('skipped' in grant && selection.settings.cursor.permissionsFile !== 'none') {\n throw new Error(\n `Phase '${invocation.phase}' needs extraDirectories on '${selection.provider}', which only grants them via a permission file. Run \\`issue-flow agent use cursor\\` or set agent.cursor.permissionsFile.`,\n );\n }\n } else if (\n (invocation.addDirs?.length ?? 0) > 0 &&\n runner.capabilities.extraDirectories === 'none'\n ) {\n throw new Error(\n `Phase '${invocation.phase}' needs extraDirectories, but '${selection.provider}' cannot grant them.`,\n );\n }\n\n let run: AgentRunResult;\n const startedMs = Date.now();\n try {\n run = await runner.run(\n {\n ...invocation,\n onLine: (line) => {\n const sanitized = redactSecrets(line).slice(0, 4_000);\n publisher.publish({\n type: 'agent:activity',\n at: isoNow(),\n provider: selection.provider,\n });\n if (sanitized.trim() !== '') {\n publisher.publish({\n type: 'process:output',\n at: isoNow(),\n phase: invocation.phase,\n executionId,\n provider: selection.provider,\n stream: 'combined',\n message: sanitized,\n });\n writeDiagnostic({\n level: 'debug',\n message: sanitized,\n fields: {\n executionId,\n phase: invocation.phase,\n harness: identity.harness,\n model: selection.settings.model,\n },\n });\n }\n invocation.onLine?.(line);\n },\n },\n selection.settings,\n );\n } catch (err) {\n writeDiagnostic({\n level: 'error',\n message: `Agent invocation threw before producing a result: ${\n err instanceof Error ? err.message : String(err)\n }`,\n exception: err,\n fields: {\n executionId,\n phase: invocation.phase,\n harness: identity.harness,\n model: selection.settings.model,\n },\n });\n if (executionId !== null) {\n await endExecution({\n id: executionId,\n status: 'failed',\n error: err instanceof Error ? err.message : String(err),\n });\n }\n throw err;\n }\n issueSpend.executions += 1;\n issueSpend.durationMs += Math.max(0, Date.now() - startedMs);\n if (run.usage?.costUsd !== undefined) {\n issueSpend.reportedUsd += run.usage.costUsd;\n issueSpend.sawReported = true;\n }\n\n const failure =\n run.success && run.exitCode === 0\n ? null\n : classify({\n source: 'agent',\n exitCode: run.exitCode,\n stdout: run.rawOutput || run.error || '',\n });\n writeDiagnostic({\n level: failure === null ? 'info' : 'error',\n message:\n failure === null\n ? `Agent invocation completed with ${selection.provider}`\n : `Agent invocation failed with ${selection.provider}: ${failure.message}`,\n context: {\n attempt,\n exitCode: run.exitCode,\n failureKind: failure?.kind ?? null,\n trigger: triggerOf(selection, attempt, invocation.correctionCycle),\n },\n fields: {\n executionId,\n phase: invocation.phase,\n harness: identity.harness,\n model: run.agent.model,\n },\n });\n\n if (executionId !== null) {\n await endExecution({\n id: executionId,\n status: failure === null ? 'completed' : failure.kind === 'timeout' ? 'timeout' : 'failed',\n usage: run.usage,\n error: failure === null ? null : (run.error ?? run.rawOutput),\n exitCode: run.exitCode,\n modelResolved: run.agent.model,\n modelSource: run.agent.model\n ? requested\n ? routed.applied\n ? 'routing'\n : 'config'\n : 'provider'\n : requested\n ? routed.applied\n ? 'routing'\n : 'config'\n : 'unavailable',\n harnessVersion: run.harnessVersion ?? peekHarnessVersion(selection.provider) ?? null,\n providerSessionId: run.sessionId ?? null,\n storyIds: invocation.storyIds,\n });\n }\n\n if (failure === null) lastFailure.delete(invocation.phase);\n else lastFailure.set(invocation.phase, failure.kind);\n\n let health: ProviderHealthRecord | null = null;\n if (selection.healthFile !== null) {\n health =\n failure === null\n ? await recordProviderSuccess(selection.healthFile, selection.provider)\n : await recordProviderFailure(selection.healthFile, selection.provider, failure, {\n config: config.providers,\n });\n }\n\n publisher.publish({\n type: 'agent:result',\n at: isoNow(),\n provider: selection.provider,\n success: failure === null,\n ...(failure === null ? {} : { failureKind: failure.kind }),\n cooldownUntil: health?.cooldownUntil ?? null,\n });\n\n if (failure === null) attempts.delete(invocation.phase);\n return { run, failure, selection, attempt, health };\n}\n","import type { TaskPlan, UserStory } from '../types.js';\nimport { parseJournal } from './journal.js';\n\n/**\n * \"This issue is too large\" — detected, reported, and left to a person.\n *\n * A phase that keeps timing out, a plan with thirty stories, five iterations in\n * a row that finish nothing: each of those is ambiguous on its own, and any one\n * of them can also be a slow afternoon. Together they are the same thing said\n * three ways, and what they are saying is that the demand was never one issue.\n *\n * The tool's job here stops at saying so. **Splitting an issue is a product\n * decision**, and the default is a report plus `blocked`, not an act — which is\n * also why a failure that is merely *infrastructural* must never reach this\n * code path: an issue whose run died because the network went down is not too\n * large, and breaking it up would be the worst possible response.\n */\n\n/** The thresholds, in one place, because every one of them is a judgement. */\nexport const DECOMPOSITION_THRESHOLDS = {\n /** Timeouts on the same phase. Two is already a pattern, not bad luck. */\n timeoutsPerPhase: 2,\n /** Stories in the plan. Past this, the plan is a backlog. */\n stories: 15,\n /** Iterations in a row that completed no story. */\n barrenIterations: 5,\n /** Files touched on the branch. */\n filesTouched: 40,\n /** Characters in the issue body. */\n issueBodyChars: 20_000,\n} as const;\n\n/** How many signals have to agree before the report is written. */\nexport const DECOMPOSITION_MIN_SIGNALS = 2;\n\nexport interface DecompositionInput {\n /** Contents of `events.jsonl` (both generations), oldest first. */\n journal?: string;\n plan?: TaskPlan | null;\n /** Body of the issue as the provider resolved it. */\n issueBody?: string;\n /** Files changed on the branch, from `git diff --name-only`. */\n filesTouched?: number;\n /** Whether the execute loop stopped because it ran out of iterations. */\n hitMaxIterations?: boolean;\n}\n\nexport interface DecompositionSignal {\n id: string;\n /** One line a person can act on, naming the number that crossed the line. */\n detail: string;\n}\n\nexport interface DecompositionAssessment {\n signals: DecompositionSignal[];\n /** Two or more signals agreeing. */\n oversized: boolean;\n}\n\n/* ── the signals ────────────────────────────────────────────────────────── */\n\n/** Timeouts per phase, read off the journal. Shared with timeout escalation. */\nexport function timeoutsByPhase(journal: string): Map<string, number> {\n const counts = new Map<string, number>();\n let phase = '(unknown)';\n\n for (const { event } of parseJournal(journal)) {\n if (event.type === 'phase:start') {\n phase = event.phase;\n continue;\n }\n if (event.type !== 'retry') continue;\n const kind = (event as { kind?: string }).kind;\n const reason = (event as { reason?: string }).reason ?? '';\n const timedOut = kind === 'timeout' || kind === 'stalled' || /timed out|stalled/i.test(reason);\n if (!timedOut) continue;\n counts.set(phase, (counts.get(phase) ?? 0) + 1);\n }\n return counts;\n}\n\n/**\n * The longest run of iterations that completed no story.\n *\n * An iteration that finishes nothing is not a failure — the agent may be\n * halfway through a story — but five of them in a row means the unit of work is\n * bigger than the loop was designed for.\n */\nfunction longestBarrenRun(journal: string): number {\n let passing = 0;\n let current = 0;\n let longest = 0;\n\n for (const { event } of parseJournal(journal)) {\n if (event.type === 'iteration:start') {\n current++;\n longest = Math.max(longest, current);\n continue;\n }\n if (event.type !== 'stories:update') continue;\n const nowPassing = event.stories.filter((story) => story.passes).length;\n if (nowPassing > passing) current = 0;\n passing = Math.max(passing, nowPassing);\n }\n return longest;\n}\n\n/**\n * Weigh the evidence.\n *\n * Every signal is a number crossing a documented line, and the report quotes\n * that number: \"this is too big\" is not an argument, and \"the `prd` phase timed\n * out three times\" is.\n */\nexport function assessDecomposition(input: DecompositionInput): DecompositionAssessment {\n const signals: DecompositionSignal[] = [];\n const journal = input.journal ?? '';\n\n for (const [phase, count] of timeoutsByPhase(journal)) {\n if (count >= DECOMPOSITION_THRESHOLDS.timeoutsPerPhase) {\n signals.push({\n id: 'repeated-timeouts',\n detail: `The '${phase}' phase timed out ${count} times (threshold: ${DECOMPOSITION_THRESHOLDS.timeoutsPerPhase}).`,\n });\n }\n }\n\n const stories = input.plan?.userStories.length ?? 0;\n if (stories > DECOMPOSITION_THRESHOLDS.stories) {\n signals.push({\n id: 'story-count',\n detail: `The plan has ${stories} user stories (threshold: ${DECOMPOSITION_THRESHOLDS.stories}).`,\n });\n }\n\n const barren = longestBarrenRun(journal);\n if (barren >= DECOMPOSITION_THRESHOLDS.barrenIterations) {\n signals.push({\n id: 'barren-iterations',\n detail: `${barren} iterations in a row completed no story (threshold: ${DECOMPOSITION_THRESHOLDS.barrenIterations}).`,\n });\n }\n\n const files = input.filesTouched ?? 0;\n if (files > DECOMPOSITION_THRESHOLDS.filesTouched) {\n signals.push({\n id: 'files-touched',\n detail: `${files} files were touched on this branch (threshold: ${DECOMPOSITION_THRESHOLDS.filesTouched}).`,\n });\n }\n\n const body = input.issueBody?.length ?? 0;\n if (body > DECOMPOSITION_THRESHOLDS.issueBodyChars) {\n signals.push({\n id: 'issue-size',\n detail: `The issue body is ${body} characters (threshold: ${DECOMPOSITION_THRESHOLDS.issueBodyChars}).`,\n });\n }\n\n if (input.hitMaxIterations === true) {\n signals.push({\n id: 'max-iterations',\n detail: 'The execute loop stopped because it ran out of iterations, not because it finished.',\n });\n }\n\n return { signals, oversized: signals.length >= DECOMPOSITION_MIN_SIGNALS };\n}\n\n/* ── the report ─────────────────────────────────────────────────────────── */\n\n/** Stories per proposed sub-issue. Small enough to finish in one run. */\nconst STORIES_PER_SUBISSUE = 5;\n\nexport interface ProposedSubIssue {\n title: string;\n stories: UserStory[];\n /** Titles of the sub-issues this one has to wait for. */\n dependsOn: string[];\n}\n\n/**\n * Cut the remaining work into pieces, in priority order.\n *\n * Priority order matters twice: it is the order the execute loop already works\n * in, and it makes each piece depend only on the one before it — which is the\n * only dependency shape that can be derived without understanding the code.\n * Anything cleverer would be a guess dressed as a plan.\n */\nexport function proposeSubIssues(plan: TaskPlan | null | undefined): ProposedSubIssue[] {\n const pending = [...(plan?.userStories ?? [])]\n .filter((story) => !story.passes)\n .sort((a, b) => a.priority - b.priority);\n if (pending.length === 0) return [];\n\n const chunks: ProposedSubIssue[] = [];\n for (let index = 0; index < pending.length; index += STORIES_PER_SUBISSUE) {\n const stories = pending.slice(index, index + STORIES_PER_SUBISSUE);\n const first = stories[0];\n const last = stories[stories.length - 1];\n const range =\n first === undefined || last === undefined || first.id === last.id\n ? (first?.id ?? '')\n : `${first.id}–${last.id}`;\n chunks.push({\n title: `${plan?.description ?? 'Issue'} — part ${chunks.length + 1} (${range})`,\n stories,\n dependsOn: chunks.length === 0 ? [] : [chunks[chunks.length - 1]?.title ?? ''],\n });\n }\n return chunks;\n}\n\nexport interface DecompositionReportInput {\n issueNumber: string;\n assessment: DecompositionAssessment;\n plan: TaskPlan | null | undefined;\n at: string;\n}\n\n/**\n * The report itself: what was detected, what is proposed, and what to do.\n *\n * Written for a person to disagree with. It states each signal with its number,\n * proposes a cut it can justify, and stops — the decision is not the tool's.\n */\nexport function buildDecompositionReport(input: DecompositionReportInput): string {\n const { issueNumber, assessment, plan, at } = input;\n const proposals = proposeSubIssues(plan);\n const lines: string[] = [];\n\n lines.push(`# Issue #${issueNumber} looks larger than one run`, '');\n lines.push(`Detected at ${at}.`, '');\n lines.push(\n 'This is a report, not an action. Nothing has been split, and nothing will be',\n 'without you asking for it.',\n '',\n );\n\n lines.push('## What was detected', '');\n for (const signal of assessment.signals) {\n lines.push(`- **${signal.id}** — ${signal.detail}`);\n }\n lines.push('');\n\n if (proposals.length === 0) {\n lines.push('## Proposed split', '');\n lines.push(\n 'No pending user stories were found, so there is nothing to cut here.',\n 'The signals above are about the run rather than about the plan.',\n '',\n );\n return `${lines.join('\\n')}\\n`;\n }\n\n lines.push('## Proposed split', '');\n lines.push(\n `The ${proposals.reduce((total, proposal) => total + proposal.stories.length, 0)} pending` +\n ` stories, in priority order, cut into ${proposals.length} sub-issues of at most` +\n ` ${STORIES_PER_SUBISSUE}. Each depends on the one before it, which is the only`,\n 'dependency shape that can be derived from the plan alone — read it as a starting',\n 'point, not as an answer.',\n '',\n );\n\n for (const proposal of proposals) {\n lines.push(`### ${proposal.title}`, '');\n if (proposal.dependsOn.length > 0) {\n lines.push(`Depends on: ${proposal.dependsOn.join(', ')}`, '');\n }\n for (const story of proposal.stories) {\n lines.push(`- \\`${story.id}\\` ${story.title}`);\n }\n lines.push('');\n }\n\n lines.push('## What to do next', '');\n lines.push(\n '- Adjust the cut above until it matches how you would actually split the work;',\n '- create the sub-issues (`issue-flow generate \"…\"`) and run them as a queue;',\n '- or decide the issue is fine as it is and re-run it — nothing here blocks that,',\n ' beyond the report you are reading.',\n '',\n );\n\n return `${lines.join('\\n')}\\n`;\n}\n"],"mappings":"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","names":["readFile","run","failure","readFile","prefix"]}
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- MemoryPublisher
4
- } from "./chunk-DUS5ZNKL.js";
5
-
6
- // src/core/journal.ts
7
- import { appendFile, mkdir, rename, stat, unlink } from "fs/promises";
8
- import { dirname } from "path";
9
- var DEFAULT_JOURNAL_MAX_BYTES = 10 * 1024 * 1024;
10
- var JournalPublisher = class extends MemoryPublisher {
11
- filePath;
12
- rotatedPath;
13
- maxFileBytes;
14
- seq = 0;
15
- writeChain = Promise.resolve();
16
- closed = false;
17
- /** Bytes in the current file. `null` until the first write measures it. */
18
- bytes = null;
19
- constructor(filePath, rotatedPath, options = {}) {
20
- super(options);
21
- this.filePath = filePath;
22
- this.rotatedPath = rotatedPath;
23
- this.maxFileBytes = options.maxFileBytes ?? DEFAULT_JOURNAL_MAX_BYTES;
24
- }
25
- afterPublish(event) {
26
- if (this.closed) return;
27
- this.seq++;
28
- const line = `${JSON.stringify({ seq: this.seq, event })}
29
- `;
30
- this.enqueue(line);
31
- }
32
- enqueue(line) {
33
- this.writeChain = this.writeChain.then(async () => {
34
- try {
35
- await this.appendLine(line);
36
- } catch (err) {
37
- this.warnOnce(err);
38
- }
39
- });
40
- }
41
- async appendLine(line) {
42
- const size = Buffer.byteLength(line);
43
- if (this.bytes === null) {
44
- await mkdir(dirname(this.filePath), { recursive: true });
45
- this.bytes = await currentSize(this.filePath);
46
- }
47
- if (this.maxFileBytes > 0 && this.bytes > 0 && this.bytes + size > this.maxFileBytes) {
48
- await this.rotate();
49
- }
50
- await appendFile(this.filePath, line, "utf-8");
51
- this.bytes += size;
52
- }
53
- /**
54
- * Keep exactly one previous generation.
55
- *
56
- * Deliberately not a numbered cascade: two files bound the disk cost at
57
- * `2 * maxFileBytes`, and a run long enough to fill 10 MB twice has already
58
- * put everything a human would look for in the current file. A caller that
59
- * needs full retention sets `maxFileBytes: 0` and rotates on its own terms.
60
- */
61
- async rotate() {
62
- try {
63
- await unlink(this.rotatedPath);
64
- } catch {
65
- }
66
- await rename(this.filePath, this.rotatedPath);
67
- this.bytes = 0;
68
- }
69
- async flush() {
70
- await this.writeChain;
71
- }
72
- async close() {
73
- await this.flush();
74
- this.closed = true;
75
- }
76
- };
77
- async function currentSize(path) {
78
- try {
79
- return (await stat(path)).size;
80
- } catch {
81
- return 0;
82
- }
83
- }
84
- function parseJournal(content) {
85
- const entries = [];
86
- for (const line of content.split("\n")) {
87
- const trimmed = line.trim();
88
- if (trimmed === "") continue;
89
- let parsed;
90
- try {
91
- parsed = JSON.parse(trimmed);
92
- } catch {
93
- continue;
94
- }
95
- if (!isEntry(parsed)) continue;
96
- entries.push(parsed);
97
- }
98
- return entries;
99
- }
100
- function isEntry(value) {
101
- if (typeof value !== "object" || value === null) return false;
102
- const candidate = value;
103
- if (typeof candidate.seq !== "number") return false;
104
- const event = candidate.event;
105
- return typeof event === "object" && event !== null && typeof event.type === "string";
106
- }
107
- var MultiPublisher = class {
108
- members;
109
- primary;
110
- constructor(members) {
111
- if (members.length === 0) {
112
- throw new Error("MultiPublisher needs at least one member");
113
- }
114
- this.members = members;
115
- this.primary = members[0];
116
- }
117
- publish(event) {
118
- for (const member of this.members) {
119
- member.publish(event);
120
- }
121
- }
122
- snapshot() {
123
- return this.primary.snapshot();
124
- }
125
- version() {
126
- return this.primary.version();
127
- }
128
- async flush() {
129
- await Promise.all(this.members.map((member) => member.flush()));
130
- }
131
- async close() {
132
- await Promise.all(this.members.map((member) => member.close()));
133
- }
134
- };
135
-
136
- export {
137
- JournalPublisher,
138
- parseJournal,
139
- MultiPublisher
140
- };
141
- //# sourceMappingURL=chunk-WCCZJL7W.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/journal.ts"],"sourcesContent":["import { appendFile, mkdir, rename, stat, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport {\n createInitialSnapshot,\n MemoryPublisher,\n type MemoryPublisherOptions,\n reduceSessionEvent,\n type SessionEvent,\n type SessionPublisher,\n type SessionReducerOptions,\n type SessionSnapshot,\n} from './session-state.js';\n\n/**\n * Append-only journal of `SessionEvent`s.\n *\n * `session.json` is a *projection*: the reducer folds every event into one\n * snapshot and the events themselves are discarded. That is the right shape for\n * a dashboard and the wrong one for an audit — after a six-hour run, \"what\n * happened at 3am\" has no answer, because the retries, the failures and their\n * order were consumed to produce a single final state.\n *\n * This publisher writes the events instead of the state: one JSON line each, in\n * order, with a monotonic `seq`. It sits **beside** `FilePublisher`, never in\n * its place. The snapshot stays the projection; the journal is the history, and\n * replaying it through `reduceSessionEvent` reproduces the snapshot — which is\n * the property `replayJournal()` and its test exist to keep true.\n *\n * The invariant of `session-state.ts` holds here unchanged: `publish()` is\n * synchronous, never throws, and every I/O failure is swallowed after a single\n * warning. Monitoring never affects the pipeline.\n */\n\n/** One line of `events.jsonl`. */\nexport interface JournalEntry {\n /** 1-based, monotonic within a file *and* across a rotation. */\n seq: number;\n event: SessionEvent;\n}\n\n/** Default ceiling before the journal rotates. */\nexport const DEFAULT_JOURNAL_MAX_BYTES = 10 * 1024 * 1024;\n\nexport interface JournalPublisherOptions extends MemoryPublisherOptions {\n /**\n * Rotate once the file would grow past this. Default 10 MB. `0` disables\n * rotation, which is what a caller that manages its own retention wants.\n */\n maxFileBytes?: number;\n}\n\n/**\n * Publisher that appends every event to `events.jsonl`.\n *\n * Writes are serialized on a promise chain — the same discipline as\n * `FilePublisher` — so lines never interleave and the order on disk is the\n * order of `publish()`. Nothing is throttled: dropping or coalescing events is\n * exactly what the snapshot already does, and the point of the journal is that\n * it does not.\n */\nexport class JournalPublisher extends MemoryPublisher {\n private readonly filePath: string;\n private readonly rotatedPath: string;\n private readonly maxFileBytes: number;\n private seq = 0;\n private writeChain: Promise<void> = Promise.resolve();\n private closed = false;\n /** Bytes in the current file. `null` until the first write measures it. */\n private bytes: number | null = null;\n\n constructor(filePath: string, rotatedPath: string, options: JournalPublisherOptions = {}) {\n super(options);\n this.filePath = filePath;\n this.rotatedPath = rotatedPath;\n this.maxFileBytes = options.maxFileBytes ?? DEFAULT_JOURNAL_MAX_BYTES;\n }\n\n protected override afterPublish(event: SessionEvent): void {\n if (this.closed) return;\n this.seq++;\n const line = `${JSON.stringify({ seq: this.seq, event } satisfies JournalEntry)}\\n`;\n this.enqueue(line);\n }\n\n private enqueue(line: string): void {\n this.writeChain = this.writeChain.then(async () => {\n try {\n await this.appendLine(line);\n } catch (err) {\n this.warnOnce(err);\n }\n });\n }\n\n private async appendLine(line: string): Promise<void> {\n const size = Buffer.byteLength(line);\n\n if (this.bytes === null) {\n await mkdir(dirname(this.filePath), { recursive: true });\n this.bytes = await currentSize(this.filePath);\n }\n\n // Rotate *before* the write that would cross the ceiling, so a line is\n // never split across two files: an entry that cannot be parsed whole is\n // worse than a file slightly under its limit.\n if (this.maxFileBytes > 0 && this.bytes > 0 && this.bytes + size > this.maxFileBytes) {\n await this.rotate();\n }\n\n await appendFile(this.filePath, line, 'utf-8');\n this.bytes += size;\n }\n\n /**\n * Keep exactly one previous generation.\n *\n * Deliberately not a numbered cascade: two files bound the disk cost at\n * `2 * maxFileBytes`, and a run long enough to fill 10 MB twice has already\n * put everything a human would look for in the current file. A caller that\n * needs full retention sets `maxFileBytes: 0` and rotates on its own terms.\n */\n private async rotate(): Promise<void> {\n try {\n await unlink(this.rotatedPath);\n } catch {\n // No previous generation. Nothing to remove.\n }\n await rename(this.filePath, this.rotatedPath);\n this.bytes = 0;\n }\n\n override async flush(): Promise<void> {\n await this.writeChain;\n }\n\n override async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n }\n}\n\n/** Size of `path` in bytes, or `0` when it does not exist yet. */\nasync function currentSize(path: string): Promise<number> {\n try {\n return (await stat(path)).size;\n } catch {\n return 0;\n }\n}\n\n/**\n * Parse the lines of a journal, skipping what cannot be read.\n *\n * A journal is appended to by a live process and read by another, so the last\n * line may well be a partial write. Tolerating it — and any line a newer\n * release wrote in a shape this one does not know — is what makes the file\n * usable at all; the alternative is a reader that throws on a healthy run.\n */\nexport function parseJournal(content: string): JournalEntry[] {\n const entries: JournalEntry[] = [];\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n continue;\n }\n\n if (!isEntry(parsed)) continue;\n entries.push(parsed);\n }\n\n return entries;\n}\n\nfunction isEntry(value: unknown): value is JournalEntry {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as { seq?: unknown; event?: unknown };\n if (typeof candidate.seq !== 'number') return false;\n const event = candidate.event;\n return (\n typeof event === 'object' && event !== null && typeof (event as SessionEvent).type === 'string'\n );\n}\n\n/**\n * Rebuild the snapshot from a journal.\n *\n * This is the reproducibility contract of the file: the same reducer that\n * produced `session.json` live, run over the events in the order they were\n * written, must land on the same state. A journal that cannot do that is a log,\n * not a journal.\n */\nexport function replayJournal(\n content: string,\n options: SessionReducerOptions = {},\n): SessionSnapshot {\n let snapshot = createInitialSnapshot();\n for (const entry of parseJournal(content)) {\n snapshot = reduceSessionEvent(snapshot, entry.event, options);\n }\n return snapshot;\n}\n\n/**\n * Fan one event stream out to several publishers.\n *\n * The journal sits **beside** the snapshot writer, so something has to hold\n * both. It is the composite rather than the journal that does it, because the\n * relationship is symmetric: neither surface owns the other, and dropping\n * either one has to leave the remaining one untouched.\n *\n * `snapshot()` and `version()` answer from the first member, which is the\n * primary surface. A member that fails has already swallowed its own error —\n * that is the contract of every publisher here — so the loop needs no guard of\n * its own beyond `publish()` never throwing.\n */\nexport class MultiPublisher implements SessionPublisher {\n private readonly members: readonly SessionPublisher[];\n private readonly primary: SessionPublisher;\n\n constructor(members: readonly SessionPublisher[]) {\n if (members.length === 0) {\n throw new Error('MultiPublisher needs at least one member');\n }\n this.members = members;\n this.primary = members[0] as SessionPublisher;\n }\n\n publish(event: SessionEvent): void {\n for (const member of this.members) {\n member.publish(event);\n }\n }\n\n snapshot(): SessionSnapshot {\n return this.primary.snapshot();\n }\n\n version(): number {\n return this.primary.version();\n }\n\n async flush(): Promise<void> {\n await Promise.all(this.members.map((member) => member.flush()));\n }\n\n async close(): Promise<void> {\n await Promise.all(this.members.map((member) => member.close()));\n }\n}\n"],"mappings":"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","names":[]}