issue-flow 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/README.md +43 -97
  2. package/dist/agent-4DHRKZ2Z.js +32 -0
  3. package/dist/{analyze-Q4ONIWRZ.js → analyze-UEJ2R3H5.js} +42 -41
  4. package/dist/analyze-UEJ2R3H5.js.map +1 -0
  5. package/dist/{apply-EEFPY2W4.js → apply-QDYNQMUX.js} +22 -24
  6. package/dist/apply-QDYNQMUX.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-RNRXVEFK.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-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
  14. package/dist/{chunk-XUEMATVY.js → chunk-37O2FMAN.js} +28 -25
  15. package/dist/chunk-37O2FMAN.js.map +1 -0
  16. package/dist/chunk-44RF3VFG.js +717 -0
  17. package/dist/chunk-44RF3VFG.js.map +1 -0
  18. package/dist/chunk-6AOZCWN2.js +21 -0
  19. package/dist/chunk-6AOZCWN2.js.map +1 -0
  20. package/dist/chunk-7MJGYPHF.js +1571 -0
  21. package/dist/chunk-7MJGYPHF.js.map +1 -0
  22. package/dist/{chunk-SA6HXL4Y.js → chunk-7WBUEBD5.js} +9 -9
  23. package/dist/chunk-7WBUEBD5.js.map +1 -0
  24. package/dist/chunk-7ZZUSMBJ.js +35 -0
  25. package/dist/chunk-7ZZUSMBJ.js.map +1 -0
  26. package/dist/{chunk-QJ44VG5G.js → chunk-ADH6RJNX.js} +3 -3
  27. package/dist/{chunk-34OCSKOB.js → chunk-AKL5UPR6.js} +159 -114
  28. package/dist/chunk-AKL5UPR6.js.map +1 -0
  29. package/dist/{chunk-7F7LGMVO.js → chunk-BTBJ5UOO.js} +12 -12
  30. package/dist/{chunk-7F7LGMVO.js.map → chunk-BTBJ5UOO.js.map} +1 -1
  31. package/dist/{chunk-HOAHMERN.js → chunk-CLZ6RRZL.js} +21 -21
  32. package/dist/chunk-DBLXLKGU.js +1201 -0
  33. package/dist/chunk-DBLXLKGU.js.map +1 -0
  34. package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
  35. package/dist/chunk-DZ3DZ3EN.js +278 -0
  36. package/dist/chunk-DZ3DZ3EN.js.map +1 -0
  37. package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
  38. package/dist/chunk-E2H3JV2E.js.map +1 -0
  39. package/dist/{chunk-45WZ6GMI.js → chunk-EORDSKWZ.js} +17 -17
  40. package/dist/chunk-EORDSKWZ.js.map +1 -0
  41. package/dist/{chunk-LTH6XYZ3.js → chunk-EYKPWHT7.js} +40 -30
  42. package/dist/chunk-EYKPWHT7.js.map +1 -0
  43. package/dist/{chunk-OODXFCQV.js → chunk-FU2FQ4JE.js} +14 -16
  44. package/dist/{chunk-OODXFCQV.js.map → chunk-FU2FQ4JE.js.map} +1 -1
  45. package/dist/{chunk-V7QOIQYC.js → chunk-G442RDFX.js} +9 -23
  46. package/dist/{chunk-V7QOIQYC.js.map → chunk-G442RDFX.js.map} +1 -1
  47. package/dist/{chunk-QPGEFLMY.js → chunk-I64N6RL6.js} +7 -7
  48. package/dist/{chunk-KRAGAUKD.js → chunk-JBYXJOJJ.js} +201 -64
  49. package/dist/chunk-JBYXJOJJ.js.map +1 -0
  50. package/dist/{chunk-SOM4QA6C.js → chunk-JCR5C5A7.js} +93 -18
  51. package/dist/chunk-JCR5C5A7.js.map +1 -0
  52. package/dist/{chunk-RNFUVKC3.js → chunk-K5NM26NV.js} +30 -13
  53. package/dist/chunk-K5NM26NV.js.map +1 -0
  54. package/dist/{chunk-YVPZUN6X.js → chunk-KUA6KBBD.js} +335 -38
  55. package/dist/chunk-KUA6KBBD.js.map +1 -0
  56. package/dist/{chunk-KMCS76ZW.js → chunk-KUL64XUF.js} +44 -12
  57. package/dist/chunk-KUL64XUF.js.map +1 -0
  58. package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
  59. package/dist/chunk-MAJ6QDRL.js.map +1 -0
  60. package/dist/{chunk-DGRTJD5R.js → chunk-MML2G7IC.js} +7 -7
  61. package/dist/chunk-NP47HRX2.js +136 -0
  62. package/dist/chunk-NP47HRX2.js.map +1 -0
  63. package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
  64. package/dist/{chunk-ECU7YO7S.js → chunk-PM5YWJYO.js} +22 -6
  65. package/dist/chunk-PM5YWJYO.js.map +1 -0
  66. package/dist/{chunk-E4I6MMHD.js → chunk-PXPTIXJF.js} +154 -101
  67. package/dist/chunk-PXPTIXJF.js.map +1 -0
  68. package/dist/{chunk-CWSQVHVV.js → chunk-QJHZ3HYJ.js} +248 -102
  69. package/dist/chunk-QJHZ3HYJ.js.map +1 -0
  70. package/dist/{chunk-LI35PIIS.js → chunk-RDPK7LYK.js} +20 -117
  71. package/dist/chunk-RDPK7LYK.js.map +1 -0
  72. package/dist/{chunk-PMLE7KAQ.js → chunk-RMIBLFG3.js} +30 -14
  73. package/dist/chunk-RMIBLFG3.js.map +1 -0
  74. package/dist/{chunk-62GVVZQO.js → chunk-T736DSZI.js} +32 -316
  75. package/dist/chunk-T736DSZI.js.map +1 -0
  76. package/dist/{chunk-TZYINKCC.js → chunk-UDUUUFQF.js} +57 -29
  77. package/dist/chunk-UDUUUFQF.js.map +1 -0
  78. package/dist/{chunk-NEWNXZ65.js → chunk-V7GETODQ.js} +36 -28
  79. package/dist/{chunk-NEWNXZ65.js.map → chunk-V7GETODQ.js.map} +1 -1
  80. package/dist/{chunk-PPZ3K4YM.js → chunk-VHQMMY2D.js} +2 -2
  81. package/dist/{chunk-ZVZMWNCG.js → chunk-VJ3PF6B7.js} +50 -16
  82. package/dist/chunk-VJ3PF6B7.js.map +1 -0
  83. package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
  84. package/dist/{chunk-6K2LCFG6.js → chunk-WB4FA2EH.js} +70 -81
  85. package/dist/chunk-WB4FA2EH.js.map +1 -0
  86. package/dist/{chunk-LGHND47K.js → chunk-WQSGL5LX.js} +22 -16
  87. package/dist/chunk-WQSGL5LX.js.map +1 -0
  88. package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
  89. package/dist/chunk-XNK5UN2D.js.map +1 -0
  90. package/dist/{chunk-7UMMFOL2.js → chunk-Y2KOWABB.js} +39 -24
  91. package/dist/chunk-Y2KOWABB.js.map +1 -0
  92. package/dist/{chunk-QF7VEL3M.js → chunk-YC24E66P.js} +568 -158
  93. package/dist/chunk-YC24E66P.js.map +1 -0
  94. package/dist/{chunk-EG2MGDP5.js → chunk-Z6RCKCVB.js} +52 -46
  95. package/dist/chunk-Z6RCKCVB.js.map +1 -0
  96. package/dist/{chunk-YUNBOUQH.js → chunk-ZPGNVBWY.js} +8 -8
  97. package/dist/cli.js +132 -62
  98. package/dist/cli.js.map +1 -1
  99. package/dist/compat-OJG76J4I.js +24 -0
  100. package/dist/{config-LEBZZCJP.js → config-6YTWPDBK.js} +20 -17
  101. package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
  102. package/dist/{conventions-XOT6YW5L.js → conventions-5UPOTU42.js} +20 -16
  103. package/dist/{conventions-XOT6YW5L.js.map → conventions-5UPOTU42.js.map} +1 -1
  104. package/dist/db-QAZG4LQD.js +264 -0
  105. package/dist/db-QAZG4LQD.js.map +1 -0
  106. package/dist/diagnostics-YEFB42E5.js +25 -0
  107. package/dist/execute-QCT64D37.js +38 -0
  108. package/dist/{generate-JGW5JSKB.js → generate-QATMDKOK.js} +46 -43
  109. package/dist/generate-QATMDKOK.js.map +1 -0
  110. package/dist/{git-A2IP32PQ.js → git-XGOECXWG.js} +2 -3
  111. package/dist/history-NBPUZVGQ.js +101 -0
  112. package/dist/history-NBPUZVGQ.js.map +1 -0
  113. package/dist/init-4LB2YKWP.js +28 -0
  114. package/dist/{operations-O4FORFIH.js → operations-RUQP2Y2F.js} +78 -52
  115. package/dist/operations-RUQP2Y2F.js.map +1 -0
  116. package/dist/{permissions-G4XCAESF.js → permissions-QZPUUBSO.js} +5 -6
  117. package/dist/plan-2NMSHTMD.js +38 -0
  118. package/dist/{policy-U5NBFAO5.js → policy-RKKFF5A2.js} +17 -15
  119. package/dist/{policy-U5NBFAO5.js.map → policy-RKKFF5A2.js.map} +1 -1
  120. package/dist/pr-QKFO5HI3.js +42 -0
  121. package/dist/pr-review-H2BFD6F2.js +33 -0
  122. package/dist/prd-ET6XKYRS.js +37 -0
  123. package/dist/{ps-76L6ZAZL.js → ps-UIKSOUAQ.js} +26 -15
  124. package/dist/ps-UIKSOUAQ.js.map +1 -0
  125. package/dist/{recorder-2BAKPBRA.js → recorder-LOU3PTIE.js} +11 -7
  126. package/dist/registry-HV7M6MAH.js +17 -0
  127. package/dist/repository-RCRR6RDE.js +80 -0
  128. package/dist/resume-BWJZGBLZ.js +278 -0
  129. package/dist/resume-BWJZGBLZ.js.map +1 -0
  130. package/dist/review-2MTZLNSS.js +38 -0
  131. package/dist/routing-RM5ABHHD.js +35 -0
  132. package/dist/run-XMACQBRJ.js +61 -0
  133. package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
  134. package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
  135. package/dist/{state-manager-UPHO2EA2.js → state-manager-SRN4VJSX.js} +9 -4
  136. package/dist/state-manager-SRN4VJSX.js.map +1 -0
  137. package/dist/{usage-KTMYXAPF.js → usage-JOODVE5O.js} +69 -63
  138. package/dist/usage-JOODVE5O.js.map +1 -0
  139. package/dist/web-TLMWJ2BM.js +205 -0
  140. package/dist/web-TLMWJ2BM.js.map +1 -0
  141. package/package.json +22 -8
  142. package/prompts/analyze.md +16 -19
  143. package/prompts/execute.md +73 -144
  144. package/prompts/generate.md +23 -10
  145. package/prompts/plan.md +32 -60
  146. package/prompts/pr-review.md +58 -40
  147. package/prompts/pr.md +50 -16
  148. package/prompts/prd.md +26 -19
  149. package/prompts/review.md +41 -18
  150. package/web/public/app.js +111 -112
  151. package/dist/agent-HMZTXCRT.js +0 -30
  152. package/dist/analyze-Q4ONIWRZ.js.map +0 -1
  153. package/dist/apply-EEFPY2W4.js.map +0 -1
  154. package/dist/chunk-34OCSKOB.js.map +0 -1
  155. package/dist/chunk-45WZ6GMI.js.map +0 -1
  156. package/dist/chunk-62GVVZQO.js.map +0 -1
  157. package/dist/chunk-6K2LCFG6.js.map +0 -1
  158. package/dist/chunk-7UMMFOL2.js.map +0 -1
  159. package/dist/chunk-CRGIQFUQ.js.map +0 -1
  160. package/dist/chunk-CWSQVHVV.js.map +0 -1
  161. package/dist/chunk-E4I6MMHD.js.map +0 -1
  162. package/dist/chunk-ECU7YO7S.js.map +0 -1
  163. package/dist/chunk-EG2MGDP5.js.map +0 -1
  164. package/dist/chunk-HAKDLR6N.js.map +0 -1
  165. package/dist/chunk-ICM463EO.js.map +0 -1
  166. package/dist/chunk-KMCS76ZW.js.map +0 -1
  167. package/dist/chunk-KRAGAUKD.js.map +0 -1
  168. package/dist/chunk-LGHND47K.js.map +0 -1
  169. package/dist/chunk-LI35PIIS.js.map +0 -1
  170. package/dist/chunk-LTH6XYZ3.js.map +0 -1
  171. package/dist/chunk-PMLE7KAQ.js.map +0 -1
  172. package/dist/chunk-QF7VEL3M.js.map +0 -1
  173. package/dist/chunk-RNFUVKC3.js.map +0 -1
  174. package/dist/chunk-SA6HXL4Y.js.map +0 -1
  175. package/dist/chunk-SOM4QA6C.js.map +0 -1
  176. package/dist/chunk-TZYINKCC.js.map +0 -1
  177. package/dist/chunk-WCCZJL7W.js +0 -141
  178. package/dist/chunk-WCCZJL7W.js.map +0 -1
  179. package/dist/chunk-XEYH6ZZI.js +0 -289
  180. package/dist/chunk-XEYH6ZZI.js.map +0 -1
  181. package/dist/chunk-XUEMATVY.js.map +0 -1
  182. package/dist/chunk-XZUEFTUP.js +0 -243
  183. package/dist/chunk-XZUEFTUP.js.map +0 -1
  184. package/dist/chunk-YVPZUN6X.js.map +0 -1
  185. package/dist/chunk-ZVZMWNCG.js.map +0 -1
  186. package/dist/diagnostics-HTCWF7F4.js +0 -23
  187. package/dist/execute-LELOSR5T.js +0 -37
  188. package/dist/generate-JGW5JSKB.js.map +0 -1
  189. package/dist/init-TO6MUXO4.js +0 -26
  190. package/dist/operations-O4FORFIH.js.map +0 -1
  191. package/dist/plan-OXAT344Q.js +0 -34
  192. package/dist/pr-UZHNKKZC.js +0 -39
  193. package/dist/pr-review-Q4ACAWDM.js +0 -32
  194. package/dist/prd-6CYEMLDY.js +0 -33
  195. package/dist/ps-76L6ZAZL.js.map +0 -1
  196. package/dist/registry-XLHHYLTR.js +0 -15
  197. package/dist/resume-URCU6CIJ.js +0 -244
  198. package/dist/resume-URCU6CIJ.js.map +0 -1
  199. package/dist/review-LVZT2TMW.js +0 -35
  200. package/dist/routing-EK6RBZM4.js +0 -33
  201. package/dist/run-2RXJCJKT.js +0 -56
  202. package/dist/usage-KTMYXAPF.js.map +0 -1
  203. package/dist/web-B5UPHHR5.js +0 -172
  204. package/dist/web-B5UPHHR5.js.map +0 -1
  205. /package/dist/{agent-HMZTXCRT.js.map → agent-4DHRKZ2Z.js.map} +0 -0
  206. /package/dist/{bench-WWWXLTFH.js.map → bench-RNRXVEFK.js.map} +0 -0
  207. /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
  208. /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
  209. /package/dist/{chunk-QJ44VG5G.js.map → chunk-ADH6RJNX.js.map} +0 -0
  210. /package/dist/{chunk-HOAHMERN.js.map → chunk-CLZ6RRZL.js.map} +0 -0
  211. /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
  212. /package/dist/{chunk-QPGEFLMY.js.map → chunk-I64N6RL6.js.map} +0 -0
  213. /package/dist/{chunk-DGRTJD5R.js.map → chunk-MML2G7IC.js.map} +0 -0
  214. /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
  215. /package/dist/{chunk-PPZ3K4YM.js.map → chunk-VHQMMY2D.js.map} +0 -0
  216. /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
  217. /package/dist/{chunk-YUNBOUQH.js.map → chunk-ZPGNVBWY.js.map} +0 -0
  218. /package/dist/{config-LEBZZCJP.js.map → compat-OJG76J4I.js.map} +0 -0
  219. /package/dist/{contract-JH2WBIO6.js.map → config-6YTWPDBK.js.map} +0 -0
  220. /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
  221. /package/dist/{execute-LELOSR5T.js.map → diagnostics-YEFB42E5.js.map} +0 -0
  222. /package/dist/{git-A2IP32PQ.js.map → execute-QCT64D37.js.map} +0 -0
  223. /package/dist/{init-TO6MUXO4.js.map → git-XGOECXWG.js.map} +0 -0
  224. /package/dist/{permissions-G4XCAESF.js.map → init-4LB2YKWP.js.map} +0 -0
  225. /package/dist/{plan-OXAT344Q.js.map → permissions-QZPUUBSO.js.map} +0 -0
  226. /package/dist/{pr-UZHNKKZC.js.map → plan-2NMSHTMD.js.map} +0 -0
  227. /package/dist/{pr-review-Q4ACAWDM.js.map → pr-QKFO5HI3.js.map} +0 -0
  228. /package/dist/{prd-6CYEMLDY.js.map → pr-review-H2BFD6F2.js.map} +0 -0
  229. /package/dist/{recorder-2BAKPBRA.js.map → prd-ET6XKYRS.js.map} +0 -0
  230. /package/dist/{registry-XLHHYLTR.js.map → recorder-LOU3PTIE.js.map} +0 -0
  231. /package/dist/{review-LVZT2TMW.js.map → registry-HV7M6MAH.js.map} +0 -0
  232. /package/dist/{routing-EK6RBZM4.js.map → repository-RCRR6RDE.js.map} +0 -0
  233. /package/dist/{run-2RXJCJKT.js.map → review-2MTZLNSS.js.map} +0 -0
  234. /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-RM5ABHHD.js.map} +0 -0
  235. /package/dist/{state-manager-UPHO2EA2.js.map → run-XMACQBRJ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routing/models.ts","../src/routing/policy.ts","../src/routing/priors.ts","../src/routing/analyze.ts","../src/routing/capabilities.ts","../src/routing/score.ts","../src/routing/decide.ts"],"sourcesContent":["import type { AgentCapabilities } from '../agents/types.js';\n\nexport const MODEL_CATALOG_VERSION = '3';\n\nexport type ModelTier = 'fast' | 'mid' | 'strong';\n\nexport interface ModelEntry {\n id: string | null;\n tier: ModelTier;\n relativeCost: number;\n relativeLatency: number;\n}\n\n/**\n * Deliberately hand-maintained. Harnesses do not expose a stable price/tier API,\n * so relative values are more durable than USD prices and keep the router pure.\n */\nexport const MODEL_CATALOG: Record<string, readonly ModelEntry[]> = {\n 'claude-code': [\n { id: 'haiku', tier: 'fast', relativeCost: 1, relativeLatency: 1 },\n { id: 'sonnet', tier: 'mid', relativeCost: 3.5, relativeLatency: 1.5 },\n { id: 'opus', tier: 'strong', relativeCost: 8, relativeLatency: 2.2 },\n ],\n 'codex-cli': [\n { id: 'gpt-5.6-luna', tier: 'fast', relativeCost: 1, relativeLatency: 1 },\n { id: 'gpt-5.6-terra', tier: 'mid', relativeCost: 3, relativeLatency: 1.45 },\n { id: 'gpt-5.6-sol', tier: 'strong', relativeCost: 7, relativeLatency: 2.1 },\n ],\n 'cursor-cli': [\n { id: 'auto-fast', tier: 'fast', relativeCost: 1, relativeLatency: 1 },\n { id: 'auto', tier: 'mid', relativeCost: 3, relativeLatency: 1.5 },\n { id: 'auto-strong', tier: 'strong', relativeCost: 7, relativeLatency: 2.1 },\n ],\n 'antigravity-cli': [\n { id: 'gemini-3.5-flash-low', tier: 'fast', relativeCost: 1, relativeLatency: 1 },\n { id: 'gemini-3.5-flash-medium', tier: 'mid', relativeCost: 2.5, relativeLatency: 1.4 },\n { id: 'gemini-3.5-pro-high', tier: 'strong', relativeCost: 6, relativeLatency: 2 },\n ],\n // OpenCode Go: relative cost tracks 5h quota intensity, kept in the 1–8\n // band so preferredTier still wins over raw request-count ratios.\n 'opencode-cli': [\n { id: 'opencode-go/mimo-v2.5', tier: 'fast', relativeCost: 1, relativeLatency: 1 },\n { id: 'opencode-go/qwen3.8-flash', tier: 'mid', relativeCost: 2.5, relativeLatency: 1.3 },\n { id: 'opencode-go/gpt-5.6-luna', tier: 'strong', relativeCost: 5, relativeLatency: 1.8 },\n ],\n};\n\nconst DEFAULT_ONLY: readonly ModelEntry[] = [\n { id: null, tier: 'mid', relativeCost: 1, relativeLatency: 1 },\n];\n\nexport function modelsFor(harness: string, capabilities: AgentCapabilities): readonly ModelEntry[] {\n if (!capabilities.modelSelection) return DEFAULT_ONLY;\n return MODEL_CATALOG[harness] ?? DEFAULT_ONLY;\n}\n\nexport function modelForTier(harness: string, tier: ModelTier): ModelEntry | null {\n return MODEL_CATALOG[harness]?.find((entry) => entry.tier === tier) ?? null;\n}\n","import type { AgentPhase, AgentProviderId } from '../agents/types.js';\nimport { type ModelTier, modelForTier } from './models.js';\nimport type { ExecutionTarget } from './types.js';\n\nexport const RECOMMENDED_POLICY_VERSION = '2';\n\nexport type OptimizeFor = 'cost-speed' | 'time-to-correct' | 'quality' | 'balanced';\n\n/**\n * Phase objectives for the opinionated policy. Affinity is a soft prior /\n * tie-break — never an eligibility filter that eliminates other harnesses.\n */\nexport interface RecommendedPolicyEntry {\n preferredTier: ModelTier;\n optimizeFor: OptimizeFor;\n escalateTo?: ModelTier;\n independentFrom?: AgentPhase;\n /** When true (default), conditional providers may win if no ready peer exists. */\n allowConditional?: boolean;\n /** Soft harness affinity for scoring — not a hard pin. */\n affinityHarness?: string;\n}\n\n/** The token-economy guidance from docs/agents.md, made executable and reviewable. */\nexport const RECOMMENDED_POLICY: Record<AgentPhase, RecommendedPolicyEntry> = {\n analyze: {\n preferredTier: 'fast',\n optimizeFor: 'cost-speed',\n affinityHarness: 'codex-cli',\n },\n generate: {\n preferredTier: 'mid',\n optimizeFor: 'balanced',\n affinityHarness: 'claude-code',\n },\n prd: {\n preferredTier: 'mid',\n optimizeFor: 'balanced',\n affinityHarness: 'claude-code',\n },\n plan: {\n preferredTier: 'fast',\n optimizeFor: 'cost-speed',\n affinityHarness: 'codex-cli',\n },\n execute: {\n preferredTier: 'mid',\n escalateTo: 'strong',\n optimizeFor: 'time-to-correct',\n affinityHarness: 'claude-code',\n },\n review: {\n preferredTier: 'strong',\n optimizeFor: 'quality',\n independentFrom: 'execute',\n affinityHarness: 'codex-cli',\n },\n pr: {\n preferredTier: 'fast',\n optimizeFor: 'cost-speed',\n affinityHarness: 'codex-cli',\n },\n 'pr-review': {\n preferredTier: 'strong',\n optimizeFor: 'quality',\n affinityHarness: 'codex-cli',\n },\n};\n\nconst PROVIDERS: Record<string, AgentProviderId> = {\n 'claude-code': 'claude',\n 'codex-cli': 'codex',\n 'cursor-cli': 'cursor',\n 'antigravity-cli': 'antigravity',\n 'opencode-cli': 'opencode',\n};\n\nexport function recommendedFor(phase: AgentPhase): RecommendedPolicyEntry {\n return RECOMMENDED_POLICY[phase];\n}\n\n/**\n * Illustrative affinity target for `routing explain`. The live decision may\n * pick a different harness when readiness or score says so.\n */\nexport function recommendedTarget(phase: AgentPhase): ExecutionTarget | null {\n const entry = recommendedFor(phase);\n const harness = entry.affinityHarness;\n if (harness === undefined) return null;\n const model = modelForTier(harness, entry.preferredTier);\n const provider = PROVIDERS[harness];\n if (model === null || provider === undefined) return null;\n return { harness, provider, model: model.id, tier: entry.preferredTier };\n}\n","import type { ModelTier } from './models.js';\nimport type { TaskClass } from './types.js';\n\n/** Bump when a cell's provenance changes. */\nexport const PRIORS_VERSION = '3';\n\n/**\n * Cold-start priors. Provenance: author judgement on 2026-08-30 from the\n * #79 baseline and the #76 capability matrix — not measured affinity.\n * `opencode-cli` stays conservative: intra-OpenCode model choice lives in\n * `opencode-go.ts`, not in these harness priors.\n */\ntype HarnessPriors = Record<string, Record<ModelTier, number>>;\n\nfunction tiers(mid: number): Record<ModelTier, number> {\n return { fast: Math.max(0, mid - 0.25), mid, strong: Math.min(1, mid + 0.12) };\n}\n\nfunction harnesses(values: Record<string, number>): HarnessPriors {\n return Object.fromEntries(Object.entries(values).map(([harness, mid]) => [harness, tiers(mid)]));\n}\n\nexport const PRIORS: Record<TaskClass, HarnessPriors> = {\n bugfix: harnesses({\n 'claude-code': 0.7,\n 'codex-cli': 0.95,\n 'cursor-cli': 0.65,\n 'antigravity-cli': 0.6,\n 'opencode-cli': 0.55,\n }),\n feature: harnesses({\n 'claude-code': 0.85,\n 'codex-cli': 0.8,\n 'cursor-cli': 0.7,\n 'antigravity-cli': 0.65,\n 'opencode-cli': 0.6,\n }),\n refactor: harnesses({\n 'claude-code': 0.75,\n 'codex-cli': 0.9,\n 'cursor-cli': 0.65,\n 'antigravity-cli': 0.6,\n 'opencode-cli': 0.55,\n }),\n docs: harnesses({\n 'claude-code': 0.8,\n 'codex-cli': 0.7,\n 'cursor-cli': 0.75,\n 'antigravity-cli': 0.7,\n 'opencode-cli': 0.65,\n }),\n test: harnesses({\n 'claude-code': 0.7,\n 'codex-cli': 0.9,\n 'cursor-cli': 0.65,\n 'antigravity-cli': 0.6,\n 'opencode-cli': 0.55,\n }),\n infra: harnesses({\n 'claude-code': 0.8,\n 'codex-cli': 0.75,\n 'cursor-cli': 0.6,\n 'antigravity-cli': 0.55,\n 'opencode-cli': 0.5,\n }),\n analysis: harnesses({\n 'claude-code': 0.95,\n 'codex-cli': 0.6,\n 'cursor-cli': 0.7,\n 'antigravity-cli': 0.65,\n 'opencode-cli': 0.6,\n }),\n};\n\nexport function priorFor(taskClass: TaskClass, harness: string, tier: ModelTier): number {\n return PRIORS[taskClass][harness]?.[tier] ?? 0.5;\n}\n","import type { RiskLevel, TaskClass, TaskSignals } from './types.js';\n\nconst RISK_PATHS = [/auth/i, /migrat/i, /infra/i, /\\.github\\//i, /permission/i, /secret/i];\n\nexport interface AnalyzedTask {\n taskClass: TaskClass;\n risk: RiskLevel;\n}\n\n/** Deterministic. No model, no I/O. Every class is reachable. */\nexport function analyzeTask(signals: TaskSignals = {}): AnalyzedTask {\n const hay = [\n signals.title ?? '',\n signals.body ?? '',\n ...(signals.labels ?? []),\n ...(signals.paths ?? []),\n ]\n .join(' ')\n .toLowerCase();\n\n const taskClass = classify(hay, signals);\n const risk = RISK_PATHS.some((pattern) =>\n (signals.paths ?? []).some((path) => pattern.test(path)),\n )\n ? 'high'\n : /security|auth|migrat/.test(hay)\n ? 'high'\n : /refactor|large|epic/.test(hay)\n ? 'medium'\n : 'low';\n\n return { taskClass, risk };\n}\n\nfunction classify(hay: string, signals: TaskSignals): TaskClass {\n if (/\\bdocs?\\b|readme|changelog/.test(hay)) return 'docs';\n if (/\\btest|spec|coverage/.test(hay)) return 'test';\n if (/\\bcie?|deploy|infra|workflow|docker/.test(hay)) return 'infra';\n if (/\\banaly[sz]e|investigat|research/.test(hay)) return 'analysis';\n if (/\\bbug|fix|regres+ion|crash/.test(hay)) return 'bugfix';\n if (/\\brefactor|cleanup|extract/.test(hay)) return 'refactor';\n if (/\\bfeat|feature|add |implement/.test(hay)) return 'feature';\n if ((signals.labels ?? []).some((label) => /bug/i.test(label))) return 'bugfix';\n if ((signals.labels ?? []).some((label) => /enhancement|feature/i.test(label))) return 'feature';\n return 'feature';\n}\n","import type { ProviderReadiness } from '../agents/availability.js';\nimport type { AgentCapabilities, AgentPhase } from '../agents/types.js';\n\nexport interface EligibilityInput {\n harness: string;\n capabilities: AgentCapabilities;\n phase: AgentPhase;\n requiresExtraDirectories: boolean;\n readiness?: ProviderReadiness | null;\n /** Default true. When false, conditional/unverified providers are ineligible. */\n allowConditional?: boolean;\n}\n\nexport interface Eligibility {\n eligible: boolean;\n reasonCodes: string[];\n}\n\n/**\n * Restriction missing (`toolAllowlist`) is ignored. Enablement missing\n * (`extraDirectories`) is ineligible when the phase needs addDirs.\n * Readiness is injected by the caller — this module stays pure.\n */\nexport function filterEligible(input: EligibilityInput): Eligibility {\n const reasons: string[] = [];\n let eligible = true;\n\n if (input.requiresExtraDirectories && input.capabilities.extraDirectories === 'none') {\n reasons.push('MISSING_CAPABILITY:extraDirectories');\n reasons.push('CAPABILITY_MISMATCH');\n eligible = false;\n }\n\n const readiness = input.readiness;\n if (readiness !== undefined && readiness !== null) {\n if (!readiness.installed) {\n reasons.push('PROVIDER_NOT_INSTALLED');\n eligible = false;\n } else if (\n readiness.cooldownUntil !== null &&\n Date.parse(readiness.cooldownUntil) > Date.parse(readiness.observedAt)\n ) {\n reasons.push('PROVIDER_COOLDOWN');\n eligible = false;\n } else if (readiness.authentication === 'failed') {\n reasons.push('AUTHENTICATION_FAILED');\n reasons.push('PROVIDER_UNAVAILABLE');\n eligible = false;\n } else if (readiness.state === 'unavailable') {\n reasons.push('PROVIDER_UNAVAILABLE');\n eligible = false;\n } else if (readiness.authentication === 'unverified' || readiness.state === 'conditional') {\n reasons.push('AUTHENTICATION_UNVERIFIED');\n reasons.push('READINESS_CONDITIONAL');\n if (input.allowConditional === false) {\n reasons.push('PROVIDER_UNAVAILABLE');\n eligible = false;\n }\n } else {\n reasons.push('READINESS_CONFIRMED');\n }\n\n const modelAccess = readiness.models[0]?.access;\n if (modelAccess === 'denied') {\n reasons.push('MODEL_NOT_ACCESSIBLE');\n eligible = false;\n } else if (modelAccess === 'unverified') {\n reasons.push('MODEL_ACCESS_UNVERIFIED');\n }\n }\n\n return { eligible, reasonCodes: reasons };\n}\n","import type { ModelTier } from './models.js';\nimport { priorFor } from './priors.js';\nimport type { Candidate, RoutingProfile, TaskClass } from './types.js';\n\nexport const DELTA = 0.2;\nexport const MIN_SAMPLE_SIZE = 8;\n\nexport const PROFILE_WEIGHTS: Record<\n RoutingProfile,\n { quality: number; cost: number; latency: number }\n> = {\n economy: { quality: 0.5, cost: 0.4, latency: 0.1 },\n balanced: { quality: 0.6, cost: 0.25, latency: 0.15 },\n quality: { quality: 0.85, cost: 0.05, latency: 0.1 },\n speed: { quality: 0.45, cost: 0.1, latency: 0.45 },\n};\n\nexport interface ScoreInput {\n harness: string;\n provider: string;\n model?: string | null;\n tier: ModelTier;\n relativeCost: number;\n relativeLatency: number;\n eligible: boolean;\n reasonCodes: string[];\n taskClass: TaskClass;\n learned?: number;\n samples?: number;\n profile?: RoutingProfile;\n /** Observed cost status from #78; catalog-relative cost is always available. */\n costStatus?: 'reported' | 'estimated' | 'unknown';\n readinessState?: 'ready' | 'conditional' | 'unavailable' | null;\n preferredTierMatch?: boolean;\n affinityMatch?: boolean;\n}\n\nexport function clampLearned(value: number): number {\n return Math.max(-DELTA, Math.min(DELTA, value));\n}\n\nfunction readinessMultiplier(state: ScoreInput['readinessState']): number {\n if (state === 'ready') return 1;\n if (state === 'conditional') return 0.72;\n if (state === 'unavailable') return 0;\n return 1;\n}\n\nexport function scoreCandidates(inputs: readonly ScoreInput[]): Candidate[] {\n const profile = inputs[0]?.profile ?? 'balanced';\n const scored: Candidate[] = inputs.map((input) => {\n const prior = priorFor(input.taskClass, input.harness, input.tier);\n const samples = input.samples ?? 0;\n const rawLearned = samples >= MIN_SAMPLE_SIZE ? (input.learned ?? 0) : 0;\n const learned = clampLearned(rawLearned);\n const weights = PROFILE_WEIGHTS[profile];\n // This is catalog-relative ordering, not observed USD. An unknown reported\n // cost still contributes no measured-cost signal; the declared tier order\n // remains available to economy/balanced profiles.\n const costScore = 1 / input.relativeCost;\n const latencyScore = 1 / input.relativeLatency;\n const preferenceBonus =\n (input.preferredTierMatch === true ? 0.12 : 0) + (input.affinityMatch === true ? 0.08 : 0);\n const score = input.eligible\n ? ((prior + learned) * weights.quality +\n costScore * weights.cost +\n latencyScore * weights.latency +\n preferenceBonus) *\n readinessMultiplier(input.readinessState)\n : 0;\n const reasonCodes = [...input.reasonCodes];\n if (input.eligible && samples === 0) reasonCodes.push('COLD_START');\n if (input.eligible && learned > 0) reasonCodes.push('HIGH_HISTORICAL_SUCCESS');\n return {\n harness: input.harness,\n provider: input.provider,\n model: input.model ?? null,\n tier: input.tier,\n relativeCost: input.relativeCost,\n relativeLatency: input.relativeLatency,\n eligible: input.eligible,\n prior,\n learned,\n samples,\n score,\n reasonCodes,\n };\n });\n\n return scored.sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n return a.harness.localeCompare(b.harness);\n });\n}\n\nexport function pickSelected(candidates: readonly Candidate[]): Candidate {\n const eligible = candidates.filter((candidate) => candidate.eligible);\n if (eligible.length === 0) {\n throw new Error(\n `No eligible routing candidate: ${candidates.map((c) => `${c.harness} (${c.reasonCodes.join(',')})`).join('; ')}`,\n );\n }\n return eligible[0] as Candidate;\n}\n","import type { ReadinessSnapshot } from '../agents/availability.js';\nimport type { AgentPhase } from '../agents/types.js';\nimport {\n ANTIGRAVITY_CAPABILITIES,\n CLAUDE_CAPABILITIES,\n CODEX_CAPABILITIES,\n CURSOR_CAPABILITIES,\n OPENCODE_CAPABILITIES,\n} from '../agents/types.js';\nimport { analyzeTask } from './analyze.js';\nimport { filterEligible } from './capabilities.js';\nimport { MODEL_CATALOG_VERSION, modelsFor } from './models.js';\nimport { OPENCODE_GO_POLICY_VERSION, resolveOpenCodeGoModel } from './opencode-go.js';\nimport { RECOMMENDED_POLICY_VERSION, recommendedFor } from './policy.js';\nimport { PRIORS_VERSION } from './priors.js';\nimport { pickSelected, scoreCandidates } from './score.js';\nimport type { RoutingDecision, RoutingMode, RoutingProfile, TaskSignals } from './types.js';\n\nconst CAPS = {\n 'claude-code': CLAUDE_CAPABILITIES,\n 'codex-cli': CODEX_CAPABILITIES,\n 'cursor-cli': CURSOR_CAPABILITIES,\n 'antigravity-cli': ANTIGRAVITY_CAPABILITIES,\n 'opencode-cli': OPENCODE_CAPABILITIES,\n} as const;\n\nconst PROVIDER: Record<string, string> = {\n 'claude-code': 'claude',\n 'codex-cli': 'codex',\n 'cursor-cli': 'cursor',\n 'antigravity-cli': 'antigravity',\n 'opencode-cli': 'opencode',\n};\n\nexport function decideRouting(input: {\n signals?: TaskSignals;\n phase: AgentPhase;\n actualHarness: string;\n actualProvider?: string;\n actualModel?: string | null;\n mode: RoutingMode;\n profile?: RoutingProfile;\n requiresExtraDirectories?: boolean;\n skipScore?: boolean;\n policy?: 'recommended';\n /** Injected inventory — router stays pure (no probes). */\n readiness?: ReadinessSnapshot | null;\n correctionCycle?: number;\n}): RoutingDecision | null {\n if (input.mode === 'off') return null;\n const analyzed = analyzeTask(input.signals ?? {});\n const profile = input.profile ?? 'balanced';\n const policyVersion = `${PRIORS_VERSION}:${MODEL_CATALOG_VERSION}:${input.policy === 'recommended' ? RECOMMENDED_POLICY_VERSION : 'adaptive'}:${OPENCODE_GO_POLICY_VERSION}`;\n\n if (input.skipScore) {\n return {\n policyVersion,\n profile,\n taskClass: analyzed.taskClass,\n risk: analyzed.risk,\n mode: input.mode,\n candidates: [],\n selected: {\n harness: input.actualHarness,\n provider: input.actualProvider ?? PROVIDER[input.actualHarness] ?? input.actualHarness,\n model: input.actualModel ?? null,\n },\n actual: {\n harness: input.actualHarness,\n provider: input.actualProvider ?? PROVIDER[input.actualHarness] ?? input.actualHarness,\n model: input.actualModel ?? null,\n },\n reasonCodes: ['EXPLICIT_CONFIG'],\n };\n }\n\n const recommendation = input.policy === 'recommended' ? recommendedFor(input.phase) : null;\n const allowConditional = recommendation?.allowConditional !== false;\n\n const scored = scoreCandidates(\n (Object.keys(CAPS) as (keyof typeof CAPS)[]).flatMap((harness) => {\n const providerId = PROVIDER[harness] as\n | 'claude'\n | 'codex'\n | 'cursor'\n | 'antigravity'\n | 'opencode';\n const readiness =\n input.readiness === undefined || input.readiness === null\n ? null\n : (input.readiness.providers[providerId] ?? null);\n const eligibility = filterEligible({\n harness,\n capabilities: CAPS[harness],\n phase: input.phase,\n requiresExtraDirectories: input.requiresExtraDirectories === true,\n readiness,\n allowConditional,\n });\n return modelsFor(harness, CAPS[harness]).map((model) => {\n const reasonCodes = [...eligibility.reasonCodes];\n const preferredTierMatch =\n recommendation !== null && model.tier === recommendation.preferredTier;\n const affinityMatch = recommendation !== null && recommendation.affinityHarness === harness;\n if (preferredTierMatch) reasonCodes.push('RECOMMENDED_POLICY');\n if (affinityMatch) reasonCodes.push('HARNESS_AFFINITY');\n if (model.tier === 'fast' && analyzed.risk !== 'high') {\n reasonCodes.push('CHEAPER_TIER_SUFFICIENT');\n }\n if (model.tier === 'strong' && (analyzed.risk === 'high' || profile === 'quality')) {\n reasonCodes.push('STRONGER_TIER_FOR_RISK');\n }\n return {\n harness,\n provider: providerId,\n model: model.id,\n tier: model.tier,\n relativeCost: model.relativeCost,\n relativeLatency: model.relativeLatency,\n eligible: eligibility.eligible,\n reasonCodes,\n taskClass: analyzed.taskClass,\n profile,\n readinessState: readiness?.state ?? null,\n preferredTierMatch,\n affinityMatch,\n };\n });\n }),\n );\n const selected = pickSelected(scored);\n if (selected.harness === 'opencode-cli') {\n const go = resolveOpenCodeGoModel({\n phase: input.phase,\n taskClass: analyzed.taskClass,\n risk: analyzed.risk,\n profile,\n correctionCycle: input.correctionCycle,\n });\n selected.model = go.model;\n selected.reasonCodes.push(...go.reasonCodes);\n }\n return {\n policyVersion,\n profile,\n taskClass: analyzed.taskClass,\n risk: analyzed.risk,\n mode: input.mode,\n candidates: scored,\n selected: {\n harness: selected.harness,\n provider: selected.provider,\n model: selected.model ?? null,\n tier: selected.tier,\n },\n actual: {\n harness: input.actualHarness,\n provider: input.actualProvider ?? PROVIDER[input.actualHarness] ?? input.actualHarness,\n model: input.actualModel ?? null,\n },\n reasonCodes: selected.reasonCodes.includes('COLD_START')\n ? ['HIGH_PRIOR', ...selected.reasonCodes]\n : selected.reasonCodes,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/verify/contract.ts
4
- import { existsSync } from "fs";
5
- import { readFile } from "fs/promises";
6
- import { join } from "path";
4
+ import { existsSync } from "node:fs";
5
+ import { readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
7
  var DISCOVERABLE = ["typecheck", "lint", "test"];
8
8
  async function discoverFromMakefile(cwd) {
9
9
  const makePath = join(cwd, "Makefile");
@@ -74,4 +74,4 @@ async function discoverFromPackage(cwd) {
74
74
  export {
75
75
  resolveContract
76
76
  };
77
- //# sourceMappingURL=chunk-L6HSKTQE.js.map
77
+ //# sourceMappingURL=chunk-W7LZLJAF.js.map
@@ -1,23 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  redactFailureMessage
4
- } from "./chunk-PPZ3K4YM.js";
5
- import {
6
- isoNow,
7
- loadTaskPlan,
8
- saveTaskPlan
9
- } from "./chunk-SOM4QA6C.js";
10
- import {
11
- classify
12
- } from "./chunk-XEYH6ZZI.js";
4
+ } from "./chunk-VHQMMY2D.js";
13
5
  import {
14
6
  getTelemetrySessionId,
15
7
  setTelemetrySessionId
16
8
  } from "./chunk-P3LRUNC6.js";
9
+ import {
10
+ isoNow
11
+ } from "./chunk-JCR5C5A7.js";
12
+ import {
13
+ ensurePlanRepository,
14
+ getPlanRepository,
15
+ loadExecution,
16
+ saveExecution
17
+ } from "./chunk-7MJGYPHF.js";
18
+ import {
19
+ classify
20
+ } from "./chunk-KUA6KBBD.js";
17
21
 
18
22
  // src/telemetry/recorder.ts
19
- import { randomUUID } from "crypto";
20
- import { hostname } from "os";
23
+ import { randomUUID } from "node:crypto";
24
+ import { hostname } from "node:os";
21
25
 
22
26
  // src/telemetry/pricing.ts
23
27
  var PRICING_TABLE_VERSION = "2026-08-30";
@@ -137,22 +141,13 @@ function resetTelemetryState() {
137
141
  async function resolveConfig(ctx) {
138
142
  if (ctx.config !== void 0) return ctx.config;
139
143
  try {
140
- const { loadTelemetryConfig } = await import("./config-LEBZZCJP.js");
144
+ const { loadTelemetryConfig } = await import("./config-6YTWPDBK.js");
141
145
  ctx.config = await loadTelemetryConfig();
142
146
  return ctx.config;
143
147
  } catch {
144
148
  return DEFAULT_TELEMETRY_CONFIG;
145
149
  }
146
150
  }
147
- function cap(records, max) {
148
- if (records.length <= max) return records;
149
- discardedCount += records.length - max;
150
- return records.slice(records.length - max);
151
- }
152
- async function mutate(tasksPath, update) {
153
- const plan = await loadTaskPlan(tasksPath);
154
- await saveTaskPlan(tasksPath, update(plan));
155
- }
156
151
  function usageFromClaude(usage) {
157
152
  if (usage === void 0 || usage === null) return null;
158
153
  const next = { source: "provider" };
@@ -200,11 +195,10 @@ async function beginExecution(input) {
200
195
  ...input.routingDecision === void 0 || input.routingDecision === null ? {} : { routingDecision: input.routingDecision }
201
196
  };
202
197
  try {
203
- await mutate(ctx.tasksPath, (plan) => ({
204
- ...plan,
205
- executions: cap([...plan.executions ?? [], record], cfg.maxExecutions)
206
- }));
207
- const { getSessionPublisher } = await import("./session-publisher-KAJQRHNZ.js");
198
+ const repository = getPlanRepository(ctx.tasksPath) ?? await ensurePlanRepository(ctx.tasksPath);
199
+ if (repository === null) return null;
200
+ await saveExecution(repository, record);
201
+ const { getSessionPublisher } = await import("./session-publisher-Q5TNEZPX.js");
208
202
  getSessionPublisher().publish({
209
203
  type: "execution:update",
210
204
  at: record.startedAt,
@@ -231,15 +225,13 @@ async function attachVerdict(verdict) {
231
225
  const ctx = context;
232
226
  if (ctx === null || verdict == null) return;
233
227
  try {
234
- await mutate(ctx.tasksPath, (plan) => {
235
- const records = [...plan.executions ?? []];
236
- if (records.length === 0) return plan;
237
- const index = records.length - 1;
238
- const current = records[index];
239
- if (current === void 0) return plan;
240
- records[index] = { ...current, verdict };
241
- return { ...plan, executions: records };
242
- });
228
+ const repository = getPlanRepository(ctx.tasksPath);
229
+ if (repository === void 0) return;
230
+ const plan = await import("./repository-RCRR6RDE.js").then(
231
+ ({ loadStoredPlan }) => loadStoredPlan(repository)
232
+ );
233
+ const current = plan.executions?.at(-1);
234
+ if (current !== void 0) await saveExecution(repository, { ...current, verdict });
243
235
  } catch {
244
236
  }
245
237
  }
@@ -269,53 +261,50 @@ async function endExecution(input) {
269
261
  };
270
262
  const completed = { value: null };
271
263
  try {
272
- await mutate(ctx.tasksPath, (plan) => {
273
- const records = [...plan.executions ?? []];
274
- const index = records.findIndex((record) => record.id === input.id);
275
- if (index === -1) return plan;
276
- const current = records[index];
277
- if (current === void 0) return plan;
278
- const started = Date.parse(current.startedAt);
279
- const finishedAt = isoNow();
280
- const modelResolved = input.modelResolved ?? current.agent.model.resolved;
281
- const modelKey = modelResolved ?? current.agent.model.requested;
282
- records[index] = {
283
- ...current,
284
- agent: {
285
- ...current.agent,
286
- harnessVersion: input.harnessVersion ?? current.agent.harnessVersion,
287
- providerSessionId: input.providerSessionId ?? current.agent.providerSessionId,
288
- model: {
289
- ...current.agent.model,
290
- resolved: modelResolved,
291
- source: input.modelSource ?? (modelResolved ? current.agent.model.source === "unavailable" ? "provider" : current.agent.model.source : current.agent.model.source)
292
- }
293
- },
294
- finishedAt,
295
- durationMs: Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,
296
- ...timingFromUsage(
297
- Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,
298
- input.usage
299
- ),
264
+ const repository = getPlanRepository(ctx.tasksPath);
265
+ if (repository === void 0) return;
266
+ const current = await loadExecution(repository, input.id);
267
+ if (current === null) return;
268
+ const started = Date.parse(current.startedAt);
269
+ const finishedAt = isoNow();
270
+ const modelResolved = input.modelResolved ?? current.agent.model.resolved;
271
+ const modelKey = modelResolved ?? current.agent.model.requested;
272
+ const record = {
273
+ ...current,
274
+ agent: {
275
+ ...current.agent,
276
+ harnessVersion: input.harnessVersion ?? current.agent.harnessVersion,
277
+ providerSessionId: input.providerSessionId ?? current.agent.providerSessionId,
278
+ model: {
279
+ ...current.agent.model,
280
+ resolved: modelResolved,
281
+ source: input.modelSource ?? (modelResolved ? current.agent.model.source === "unavailable" ? "provider" : current.agent.model.source : current.agent.model.source)
282
+ }
283
+ },
284
+ finishedAt,
285
+ durationMs: Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,
286
+ ...timingFromUsage(
287
+ Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,
288
+ input.usage
289
+ ),
290
+ usage,
291
+ cost: resolveCost({
292
+ reportedUsd: input.reportedUsd ?? input.usage?.costUsd,
300
293
  usage,
301
- cost: resolveCost({
302
- reportedUsd: input.reportedUsd ?? input.usage?.costUsd,
303
- usage,
304
- modelKey,
305
- estimate: cfg.pricing.estimate,
306
- overrides: cfg.pricing.overrides
307
- }),
308
- status,
309
- failure,
310
- owner: null,
311
- ...input.storyIds === void 0 ? {} : { storyIds: input.storyIds },
312
- ...input.stopReason === void 0 ? {} : { stopReason: input.stopReason }
313
- };
314
- completed.value = records[index] ?? null;
315
- return { ...plan, executions: records };
316
- });
294
+ modelKey,
295
+ estimate: cfg.pricing.estimate,
296
+ overrides: cfg.pricing.overrides
297
+ }),
298
+ status,
299
+ failure,
300
+ owner: null,
301
+ ...input.storyIds === void 0 ? {} : { storyIds: input.storyIds },
302
+ ...input.stopReason === void 0 ? {} : { stopReason: input.stopReason }
303
+ };
304
+ completed.value = record;
305
+ await saveExecution(repository, record);
317
306
  if (completed.value !== null) {
318
- const { getSessionPublisher } = await import("./session-publisher-KAJQRHNZ.js");
307
+ const { getSessionPublisher } = await import("./session-publisher-Q5TNEZPX.js");
319
308
  getSessionPublisher().publish({
320
309
  type: "execution:update",
321
310
  at: completed.value.finishedAt ?? isoNow(),
@@ -359,4 +348,4 @@ export {
359
348
  endExecution,
360
349
  recordInvocation
361
350
  };
362
- //# sourceMappingURL=chunk-6K2LCFG6.js.map
351
+ //# sourceMappingURL=chunk-WB4FA2EH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/telemetry/recorder.ts","../src/telemetry/pricing.ts","../src/telemetry/types.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { hostname } from 'node:os';\nimport type { ClaudeUsage } from '../core/metrics.js';\nimport { isoNow } from '../core/state-manager.js';\nimport { classify } from '../resilience/errors.js';\nimport {\n ensurePlanRepository,\n getPlanRepository,\n loadExecution,\n saveExecution,\n} from '../storage/db/repository.js';\nimport { resolveCost } from './pricing.js';\nimport { redactFailureMessage } from './redact.js';\nimport { getTelemetrySessionId, setTelemetrySessionId } from './session-id.js';\nimport {\n DEFAULT_TELEMETRY_CONFIG,\n type ExecutionPurpose,\n type ExecutionRecord,\n type ExecutionStatus,\n type ExecutionTrigger,\n type NormalizedUsage,\n type StopReason,\n type TelemetryConfig,\n} from './types.js';\n\nexport interface TelemetryContext {\n tasksPath: string;\n sessionId?: string | null;\n config?: TelemetryConfig;\n}\n\nlet context: TelemetryContext | null = null;\nlet discardedCount = 0;\n\nexport function bindTelemetry(next: TelemetryContext | null): void {\n context = next;\n}\n\nexport function getTelemetryContext(): TelemetryContext | null {\n return context;\n}\n\nexport function discardedExecutionCount(): number {\n return discardedCount;\n}\n\nexport function resetTelemetryState(): void {\n context = null;\n discardedCount = 0;\n setTelemetrySessionId(null);\n}\n\nasync function resolveConfig(ctx: TelemetryContext): Promise<TelemetryConfig> {\n if (ctx.config !== undefined) return ctx.config;\n try {\n const { loadTelemetryConfig } = await import('../config.js');\n ctx.config = await loadTelemetryConfig();\n return ctx.config;\n } catch {\n return DEFAULT_TELEMETRY_CONFIG;\n }\n}\n\nexport function usageFromClaude(usage: ClaudeUsage | null | undefined): NormalizedUsage | null {\n if (usage === undefined || usage === null) return null;\n const next: NormalizedUsage = { source: 'provider' };\n if (usage.inputTokens !== undefined) next.inputTokens = usage.inputTokens;\n if (usage.outputTokens !== undefined) next.outputTokens = usage.outputTokens;\n if (usage.cacheReadTokens !== undefined) next.cacheReadTokens = usage.cacheReadTokens;\n if (usage.cacheCreationTokens !== undefined) next.cacheCreationTokens = usage.cacheCreationTokens;\n return next;\n}\n\nexport interface BeginExecutionInput {\n purpose: ExecutionPurpose;\n attempt?: number;\n trigger?: ExecutionTrigger;\n triggerReason?: ExecutionRecord['triggerReason'];\n harness: string;\n provider?: string | null;\n harnessVersion?: string | null;\n modelRequested?: string | null;\n modelResolved?: string | null;\n modelSource?: ExecutionRecord['agent']['model']['source'];\n iteration?: number;\n correctionCycle?: number;\n storyIds?: string[];\n routingDecision?: ExecutionRecord['routingDecision'];\n}\n\nexport async function beginExecution(input: BeginExecutionInput): Promise<string | null> {\n const ctx = context;\n if (ctx === null) return null;\n const cfg = await resolveConfig(ctx);\n if (!cfg.enabled) return null;\n\n const id = randomUUID();\n const record: ExecutionRecord = {\n id,\n sessionId: ctx.sessionId ?? getTelemetrySessionId(),\n purpose: input.purpose,\n attempt: input.attempt ?? 1,\n trigger: input.trigger ?? 'initial',\n triggerReason: input.triggerReason ?? null,\n agent: {\n harness: input.harness,\n provider: input.provider ?? null,\n harnessVersion: input.harnessVersion ?? null,\n model: {\n requested: input.modelRequested ?? null,\n resolved: input.modelResolved ?? null,\n source: input.modelSource ?? (input.modelResolved ? 'provider' : 'unavailable'),\n },\n providerSessionId: null,\n },\n startedAt: isoNow(),\n finishedAt: null,\n durationMs: null,\n usage: null,\n cost: { status: 'unknown', reason: 'not_reported' },\n status: 'running',\n failure: null,\n owner: { pid: process.pid, host: hostname() },\n ...(input.iteration === undefined ? {} : { iteration: input.iteration }),\n ...(input.correctionCycle === undefined ? {} : { correctionCycle: input.correctionCycle }),\n ...(input.storyIds === undefined ? {} : { storyIds: input.storyIds }),\n ...(input.routingDecision === undefined || input.routingDecision === null\n ? {}\n : { routingDecision: input.routingDecision }),\n };\n\n try {\n const repository =\n getPlanRepository(ctx.tasksPath) ?? (await ensurePlanRepository(ctx.tasksPath));\n if (repository === null) return null;\n await saveExecution(repository, record as unknown as { id: string } & Record<string, unknown>);\n const { getSessionPublisher } = await import('../core/session-publisher.js');\n getSessionPublisher().publish({\n type: 'execution:update',\n at: record.startedAt,\n execution: record,\n });\n return id;\n } catch {\n return null;\n }\n}\n\n/** Wall clock vs CLI envelope: startup the harness does not report. */\nexport function timingFromUsage(\n wallClockMs: number | null,\n usage: ClaudeUsage | null | undefined,\n): Pick<\n ExecutionRecord,\n 'cliDurationMs' | 'harnessStartupMs' | 'apiDurationMs' | 'ttftMs' | 'numTurns'\n> {\n const cli = usage?.cliDurationMs;\n const cliDurationMs = cli === undefined ? null : cli;\n const harnessStartupMs =\n wallClockMs !== null && cli !== undefined ? Math.max(0, wallClockMs - cli) : null;\n return {\n cliDurationMs,\n harnessStartupMs,\n apiDurationMs: usage?.apiDurationMs ?? null,\n ttftMs: usage?.ttftMs ?? null,\n numTurns: usage?.numTurns ?? null,\n };\n}\n\nexport async function attachVerdict(verdict: ExecutionRecord['verdict']): Promise<void> {\n const ctx = context;\n if (ctx === null || verdict == null) return;\n try {\n const repository = getPlanRepository(ctx.tasksPath);\n if (repository === undefined) return;\n const plan = await import('../storage/db/repository.js').then(({ loadStoredPlan }) =>\n loadStoredPlan(repository),\n );\n const current = plan.executions?.at(-1);\n if (current !== undefined) await saveExecution(repository, { ...current, verdict });\n } catch {\n // Observational: a failed write must never change the invocation outcome.\n }\n}\n\nexport interface EndExecutionInput {\n id: string;\n status?: ExecutionStatus;\n usage?: ClaudeUsage | null;\n reportedUsd?: number | null;\n error?: string | null;\n exitCode?: number | null;\n storyIds?: string[];\n cancelled?: boolean;\n timedOut?: boolean;\n modelResolved?: string | null;\n modelSource?: ExecutionRecord['agent']['model']['source'];\n harnessVersion?: string | null;\n providerSessionId?: string | null;\n stopReason?: StopReason | null;\n}\n\nexport async function endExecution(input: EndExecutionInput): Promise<void> {\n const ctx = context;\n if (ctx === null) return;\n const cfg = await resolveConfig(ctx);\n if (!cfg.enabled) return;\n\n const usage = usageFromClaude(input.usage);\n const timedOut = input.timedOut === true || /\\btimed out\\b/i.test(input.error ?? '');\n const cancelled = input.cancelled === true;\n let status: ExecutionStatus = input.status ?? 'completed';\n if (input.status === undefined) {\n if (cancelled) status = 'cancelled';\n else if (timedOut) status = 'timeout';\n else if (input.error) status = 'failed';\n }\n\n const failure =\n status === 'completed'\n ? null\n : {\n kind: classify({\n source: 'agent',\n stdout: input.error ?? '',\n exitCode: input.exitCode,\n timedOut,\n }).kind,\n message: redactFailureMessage(input.error ?? status),\n exitCode: input.exitCode ?? null,\n };\n\n const completed: { value: ExecutionRecord | null } = { value: null };\n try {\n const repository = getPlanRepository(ctx.tasksPath);\n if (repository === undefined) return;\n const current = (await loadExecution(repository, input.id)) as ExecutionRecord | null;\n if (current === null) return;\n const started = Date.parse(current.startedAt);\n const finishedAt = isoNow();\n const modelResolved = input.modelResolved ?? current.agent.model.resolved;\n const modelKey = modelResolved ?? current.agent.model.requested;\n const record: ExecutionRecord = {\n ...current,\n agent: {\n ...current.agent,\n harnessVersion: input.harnessVersion ?? current.agent.harnessVersion,\n providerSessionId: input.providerSessionId ?? current.agent.providerSessionId,\n model: {\n ...current.agent.model,\n resolved: modelResolved,\n source:\n input.modelSource ??\n (modelResolved\n ? current.agent.model.source === 'unavailable'\n ? 'provider'\n : current.agent.model.source\n : current.agent.model.source),\n },\n },\n finishedAt,\n durationMs: Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,\n ...timingFromUsage(\n Number.isFinite(started) ? Math.max(0, Date.now() - started) : null,\n input.usage,\n ),\n usage,\n cost: resolveCost({\n reportedUsd: input.reportedUsd ?? input.usage?.costUsd,\n usage,\n modelKey,\n estimate: cfg.pricing.estimate,\n overrides: cfg.pricing.overrides,\n }),\n status,\n failure,\n owner: null,\n ...(input.storyIds === undefined ? {} : { storyIds: input.storyIds }),\n ...(input.stopReason === undefined ? {} : { stopReason: input.stopReason }),\n };\n completed.value = record;\n await saveExecution(repository, record as unknown as { id: string } & Record<string, unknown>);\n if (completed.value !== null) {\n const { getSessionPublisher } = await import('../core/session-publisher.js');\n getSessionPublisher().publish({\n type: 'execution:update',\n at: completed.value.finishedAt ?? isoNow(),\n execution: completed.value,\n });\n }\n } catch {\n // Observational: a failed write must never change the invocation outcome.\n }\n}\n\nexport async function recordInvocation<T>(\n input: BeginExecutionInput,\n invoke: () => Promise<T>,\n finish: (result: T) => EndExecutionInput,\n): Promise<T> {\n const id = await beginExecution(input);\n try {\n const result = await invoke();\n if (id !== null) {\n await endExecution({ ...finish(result), id });\n }\n return result;\n } catch (err) {\n if (id !== null) {\n await endExecution({\n id,\n status: 'failed',\n error: err instanceof Error ? err.message : String(err),\n });\n }\n throw err;\n }\n}\n","import { isoNow } from '../core/state-manager.js';\nimport type { CostRecord, NormalizedUsage, PricingSnapshot, TelemetryConfig } from './types.js';\n\nexport const PRICING_TABLE_VERSION = '2026-08-30';\n\ninterface PricingRow {\n inputPerMillion: number;\n outputPerMillion: number;\n cacheReadPerMillion?: number;\n cacheWritePerMillion?: number;\n}\n\n/** Microdollars-per-million would be more precise; dollars keep the snapshot readable. */\nconst TABLE: Record<string, PricingRow> = {\n 'claude-sonnet-4': {\n inputPerMillion: 3,\n outputPerMillion: 15,\n cacheReadPerMillion: 0.3,\n cacheWritePerMillion: 3.75,\n },\n 'claude-sonnet-4-5': {\n inputPerMillion: 3,\n outputPerMillion: 15,\n cacheReadPerMillion: 0.3,\n cacheWritePerMillion: 3.75,\n },\n 'claude-opus-4': {\n inputPerMillion: 15,\n outputPerMillion: 75,\n cacheReadPerMillion: 1.5,\n cacheWritePerMillion: 18.75,\n },\n 'gpt-5': { inputPerMillion: 1.25, outputPerMillion: 10 },\n 'gpt-5.1': { inputPerMillion: 1.25, outputPerMillion: 10 },\n};\n\n/** Aliases a harness accepts in place of a model id. */\nconst ALIASES: Record<string, string> = {\n sonnet: 'claude-sonnet-4-5',\n opus: 'claude-opus-4',\n};\n\n/**\n * Map a resolved model id onto a table key.\n *\n * What reaches here is whatever the harness reported: a dated snapshot\n * (`claude-sonnet-4-5-20250929`), a vendor-prefixed id\n * (`anthropic/claude-sonnet-4-5`) or a configured alias (`sonnet`). An exact\n * lookup misses all three, and the estimate silently degrades to `unknown`.\n * An override is always honoured under the key the user wrote.\n */\nexport function normalizeModelKey(modelKey: string): string {\n const lower = modelKey.trim().toLowerCase();\n const withoutVendor = lower.slice(lower.lastIndexOf('/') + 1);\n const withoutSnapshot = withoutVendor.replace(/-\\d{8}$/, '').replace(/-latest$/, '');\n return ALIASES[withoutSnapshot] ?? withoutSnapshot;\n}\n\nfunction rowFor(\n modelKey: string,\n overrides: TelemetryConfig['pricing']['overrides'],\n): PricingRow | null {\n const normalized = normalizeModelKey(modelKey);\n const override = overrides[modelKey] ?? overrides[normalized];\n const base = TABLE[modelKey] ?? TABLE[normalized];\n if (override === undefined && base === undefined) return null;\n return {\n inputPerMillion: override?.inputPerMillion ?? base?.inputPerMillion ?? 0,\n outputPerMillion: override?.outputPerMillion ?? base?.outputPerMillion ?? 0,\n cacheReadPerMillion: override?.cacheReadPerMillion ?? base?.cacheReadPerMillion,\n cacheWritePerMillion: override?.cacheWritePerMillion ?? base?.cacheWritePerMillion,\n };\n}\n\nfunction dollars(tokens: number | undefined, perMillion: number | undefined): number {\n if (tokens === undefined || perMillion === undefined) return 0;\n return (tokens * perMillion) / 1_000_000;\n}\n\nexport function resolveCost(options: {\n reportedUsd?: number | null;\n usage: NormalizedUsage | null;\n modelKey: string | null;\n estimate: boolean;\n overrides?: TelemetryConfig['pricing']['overrides'];\n}): CostRecord {\n if (options.reportedUsd !== undefined && options.reportedUsd !== null) {\n return { status: 'reported', amount: options.reportedUsd, currency: 'USD' };\n }\n if (!options.estimate) {\n return { status: 'unknown', reason: 'not_reported' };\n }\n if (options.modelKey === null || options.modelKey === '') {\n return { status: 'unknown', reason: 'unknown_model' };\n }\n const row = rowFor(options.modelKey, options.overrides ?? {});\n if (row === null) {\n return { status: 'unknown', reason: 'unknown_model' };\n }\n if (options.usage === null || options.usage.source === 'unavailable') {\n return { status: 'unknown', reason: 'not_reported' };\n }\n const amount =\n dollars(options.usage.inputTokens, row.inputPerMillion) +\n dollars(options.usage.outputTokens, row.outputPerMillion) +\n dollars(options.usage.cacheReadTokens, row.cacheReadPerMillion) +\n dollars(options.usage.cacheCreationTokens, row.cacheWritePerMillion);\n const pricing: PricingSnapshot = {\n tableVersion: PRICING_TABLE_VERSION,\n modelKey: options.modelKey,\n inputPerMillion: row.inputPerMillion,\n outputPerMillion: row.outputPerMillion,\n capturedAt: isoNow(),\n ...(row.cacheReadPerMillion === undefined\n ? {}\n : { cacheReadPerMillion: row.cacheReadPerMillion }),\n ...(row.cacheWritePerMillion === undefined\n ? {}\n : { cacheWritePerMillion: row.cacheWritePerMillion }),\n };\n return { status: 'estimated', amount, currency: 'USD', pricing };\n}\n\nexport function estimateCost(\n usage: NormalizedUsage,\n modelKey: string,\n overrides: TelemetryConfig['pricing']['overrides'] = {},\n): CostRecord {\n return resolveCost({ usage, modelKey, estimate: true, overrides });\n}\n","import type { FailureKind } from '../resilience/errors.js';\n\nexport const EXECUTION_PURPOSES = [\n 'analyze',\n 'generate',\n 'prd',\n 'plan',\n 'execute',\n 'review',\n 'pr',\n 'pr-review',\n 'verify',\n] as const;\n\nexport type ExecutionPurpose = (typeof EXECUTION_PURPOSES)[number];\n\nexport type ExecutionTrigger = 'initial' | 'retry' | 'fallback' | 'correction' | 'escalation';\n\nexport type ExecutionStatus =\n | 'running'\n | 'completed'\n | 'failed'\n | 'timeout'\n | 'cancelled'\n | 'interrupted';\n\nexport type StopReason =\n | 'completed'\n | 'failed'\n | 'timeout'\n | 'cancelled'\n | 'max_attempts'\n | 'max_cost'\n | 'max_duration';\n\nexport type VerdictStatus = 'passed' | 'failed' | 'unverified';\n\nexport interface NormalizedUsage {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n reasoningTokens?: number;\n details?: Record<string, number>;\n source: 'provider' | 'unavailable';\n}\n\nexport interface PricingSnapshot {\n tableVersion: string;\n modelKey: string;\n inputPerMillion: number;\n outputPerMillion: number;\n cacheReadPerMillion?: number;\n cacheWritePerMillion?: number;\n capturedAt: string;\n}\n\nexport type CostRecord =\n | { status: 'reported'; amount: number; currency: 'USD' }\n | { status: 'estimated'; amount: number; currency: 'USD'; pricing: PricingSnapshot }\n | {\n status: 'unknown';\n reason: 'not_reported' | 'no_pricing' | 'unknown_model' | 'subscription' | 'zero_rated';\n };\n\nexport interface ExecutionAgent {\n harness: string;\n provider: string | null;\n harnessVersion?: string | null;\n model: {\n requested: string | null;\n resolved: string | null;\n source: 'provider' | 'config' | 'routing' | 'unavailable';\n };\n providerSessionId: string | null;\n}\n\nexport interface ExecutionOwner {\n pid: number;\n host: string;\n}\n\nexport interface ExecutionVerdict {\n status: VerdictStatus;\n level?: string | null;\n independence?: string | null;\n}\n\nexport interface RoutingDecision {\n selected: string | { harness: string; provider: string; model?: string | null; tier?: string };\n actual?: string | { harness: string; provider: string; model?: string | null; tier?: string };\n candidates?: unknown[];\n reasonCodes?: string[];\n [key: string]: unknown;\n}\n\nexport interface ExecutionRecord {\n id: string;\n sessionId: string | null;\n purpose: ExecutionPurpose;\n attempt: number;\n trigger: ExecutionTrigger;\n triggerReason: FailureKind | null;\n agent: ExecutionAgent;\n startedAt: string;\n finishedAt: string | null;\n durationMs: number | null;\n /** Envelope duration when the CLI reports it. */\n cliDurationMs?: number | null;\n /** wallClock − cliDuration: startup the CLI does not see. */\n harnessStartupMs?: number | null;\n /** Envelope `duration_api_ms` when reported. */\n apiDurationMs?: number | null;\n /** Time to first output, when reported. */\n ttftMs?: number | null;\n numTurns?: number | null;\n usage: NormalizedUsage | null;\n cost: CostRecord;\n status: ExecutionStatus;\n failure: {\n kind: FailureKind;\n message: string;\n exitCode: number | null;\n } | null;\n stopReason?: StopReason | null;\n iteration?: number;\n /** Correction cycle active when this invocation started; 0 is the initial pass. */\n correctionCycle?: number;\n storyIds?: string[];\n owner?: ExecutionOwner | null;\n routingDecision?: RoutingDecision | null;\n verdict?: ExecutionVerdict | null;\n}\n\nexport interface CostTotals {\n reported: number;\n estimated: number;\n unknownExecutions: number;\n}\n\nexport interface ExecutionSummary {\n count: number;\n discarded: number;\n byStatus: Partial<Record<ExecutionStatus, number>>;\n usage: {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n reasoningTokens: number;\n };\n totalCost: CostTotals;\n}\n\nexport interface TelemetryConfig {\n enabled: boolean;\n maxExecutions: number;\n pricing: {\n estimate: boolean;\n overrides: Record<string, Partial<PricingSnapshot>>;\n };\n}\n\nexport const DEFAULT_TELEMETRY_CONFIG: TelemetryConfig = {\n enabled: true,\n maxExecutions: 500,\n pricing: { estimate: false, overrides: {} },\n};\n"],"mappings":"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","names":[]}
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  loadPolicyConfig,
4
4
  mergeConfigLayers
5
- } from "./chunk-QF7VEL3M.js";
5
+ } from "./chunk-YC24E66P.js";
6
6
  import {
7
7
  printWarning
8
- } from "./chunk-XZUEFTUP.js";
8
+ } from "./chunk-DBLXLKGU.js";
9
9
  import {
10
10
  getProjectRoot,
11
11
  run
12
- } from "./chunk-YVPZUN6X.js";
12
+ } from "./chunk-KUA6KBBD.js";
13
13
 
14
14
  // src/conventions/git/types.ts
15
15
  var CHANGE_TYPES = [
@@ -40,7 +40,13 @@ var DEFAULT_LABEL_TYPE_MAP = {
40
40
  architecture: "feat",
41
41
  investigation: "chore"
42
42
  };
43
- var FORBIDDEN_PROVIDER_NAMES = ["claude", "codex", "cursor", "antigravity"];
43
+ var FORBIDDEN_PROVIDER_NAMES = [
44
+ "claude",
45
+ "codex",
46
+ "cursor",
47
+ "antigravity",
48
+ "opencode"
49
+ ];
44
50
  function isChangeType(value) {
45
51
  return CHANGE_TYPES.includes(value);
46
52
  }
@@ -351,14 +357,14 @@ function issueReferenceLines(input) {
351
357
  }
352
358
 
353
359
  // src/policy/resolve.ts
354
- import { isAbsolute, normalize, sep as sep2 } from "path";
360
+ import { isAbsolute, normalize, sep as sep2 } from "node:path";
355
361
 
356
362
  // src/policy/discovery.ts
357
- import { readdir, readFile, stat } from "fs/promises";
358
- import { join, relative, sep } from "path";
363
+ import { readdir, readFile, stat } from "node:fs/promises";
364
+ import { join, relative, sep } from "node:path";
359
365
 
360
366
  // src/policy/parsers/docs.ts
361
- import { posix } from "path";
367
+ import { posix } from "node:path";
362
368
  function classifyDocument(fileName) {
363
369
  switch (fileName.toLowerCase()) {
364
370
  case "agents.md":
@@ -543,7 +549,7 @@ function parseIssueTypes(payload) {
543
549
  }
544
550
 
545
551
  // src/policy/parsers/templates.ts
546
- import { basename, extname } from "path";
552
+ import { basename, extname } from "node:path";
547
553
 
548
554
  // src/policy/parsers/issue-forms.ts
549
555
  function emptyTemplateMetadata() {
@@ -1417,14 +1423,14 @@ async function resolvePolicy(root, scope, options) {
1417
1423
  discoverGitConventions(root)
1418
1424
  ]
1419
1425
  );
1420
- const wantsOrgTemplates = toggles.issueTemplates && templateDiscovery.templates.length === 0;
1426
+ const wantsOrgTemplates = options.remote !== false && toggles.issueTemplates && templateDiscovery.templates.length === 0;
1421
1427
  const [baseBranch, slug] = await Promise.all([
1422
- discoverBaseBranch(root, options.exec),
1423
- toggles.issueTypes || wantsOrgTemplates ? discoverGitHubSlug(root, options.exec) : Promise.resolve(null)
1428
+ options.remote === false ? Promise.resolve({ baseBranch: null, sources: [] }) : discoverBaseBranch(root, options.exec),
1429
+ options.remote !== false && toggles.issueTypes || wantsOrgTemplates ? discoverGitHubSlug(root, options.exec) : Promise.resolve(null)
1424
1430
  ]);
1425
1431
  const [labels, issueTypes, orgTemplates, orgForms] = await Promise.all([
1426
- toggles.labels ? discoverLabels(root, options.exec) : Promise.resolve({ labels: [], sources: [disabledSource("labels")] }),
1427
- toggles.issueTypes ? discoverIssueTypes(root, slug?.owner ?? null, options.exec) : Promise.resolve({ types: [], sources: [disabledSource("issue-types")] }),
1432
+ options.remote !== false && toggles.labels ? discoverLabels(root, options.exec) : Promise.resolve({ labels: [], sources: [disabledSource("labels")] }),
1433
+ options.remote !== false && toggles.issueTypes ? discoverIssueTypes(root, slug?.owner ?? null, options.exec) : Promise.resolve({ types: [], sources: [disabledSource("issue-types")] }),
1428
1434
  wantsOrgTemplates ? discoverOrganizationTemplates(root, slug, options.exec) : Promise.resolve({ templates: [], sources: [] }),
1429
1435
  // Two calls, because GitHub answers the two kinds of organization default
1430
1436
  // through different surfaces: `issueTemplates` covers markdown templates and
@@ -1533,7 +1539,7 @@ async function loadRepositoryPolicy(options = {}) {
1533
1539
  if (options.cache === false) {
1534
1540
  return resolvePolicy(root, scope, options);
1535
1541
  }
1536
- const key = `${root}\0${scope ?? ""}`;
1542
+ const key = `${root}\0${scope ?? ""}\0${options.remote !== false}`;
1537
1543
  const cached = cache.get(key);
1538
1544
  if (cached !== void 0) {
1539
1545
  return cached;
@@ -1559,4 +1565,4 @@ export {
1559
1565
  issueReferenceLines,
1560
1566
  loadRepositoryPolicy
1561
1567
  };
1562
- //# sourceMappingURL=chunk-LGHND47K.js.map
1568
+ //# sourceMappingURL=chunk-WQSGL5LX.js.map