issue-flow 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dist/agent-TB6W7PT7.js +30 -0
  2. package/dist/{analyze-556KCJKZ.js → analyze-6M3KEOX7.js} +22 -22
  3. package/dist/{apply-WVV7G7WN.js → apply-ADB3ZK7W.js} +14 -14
  4. package/dist/{bench-UBFGKUHR.js → bench-FM7I7EIV.js} +23 -23
  5. package/dist/{chunk-YA6FWFYW.js → chunk-2SUFAE6X.js} +53 -11
  6. package/dist/chunk-2SUFAE6X.js.map +1 -0
  7. package/dist/{chunk-DBEMD34J.js → chunk-32JSYXEK.js} +8 -8
  8. package/dist/chunk-3R27MJ5R.js +25 -0
  9. package/dist/chunk-3R27MJ5R.js.map +1 -0
  10. package/dist/{chunk-QZOBR6YF.js → chunk-6YQT3SSM.js} +4 -4
  11. package/dist/chunk-6YQT3SSM.js.map +1 -0
  12. package/dist/{chunk-OGVWJO4S.js → chunk-7F7LGMVO.js} +3 -3
  13. package/dist/{chunk-X6GY3CM2.js → chunk-A4H7P7T7.js} +102 -102
  14. package/dist/chunk-A4H7P7T7.js.map +1 -0
  15. package/dist/{chunk-OGN2NX57.js → chunk-ANI2NTR4.js} +9 -9
  16. package/dist/{chunk-VK65RNFA.js → chunk-B3TSS7BT.js} +3 -3
  17. package/dist/chunk-D6ZBGJ3L.js +321 -0
  18. package/dist/chunk-D6ZBGJ3L.js.map +1 -0
  19. package/dist/{chunk-MXCOSPLJ.js → chunk-DGRTJD5R.js} +3 -3
  20. package/dist/{chunk-ROIIEVZH.js → chunk-DUS5ZNKL.js} +474 -361
  21. package/dist/chunk-DUS5ZNKL.js.map +1 -0
  22. package/dist/{chunk-VTF4RWS5.js → chunk-DV7HUC4Z.js} +7 -7
  23. package/dist/{chunk-OOX3RMD3.js → chunk-E6KXCV3T.js} +4 -4
  24. package/dist/{chunk-OLUOZLU5.js → chunk-HJBF4WD2.js} +1653 -1071
  25. package/dist/chunk-HJBF4WD2.js.map +1 -0
  26. package/dist/{chunk-4FUWWBTP.js → chunk-HLAPOUEM.js} +8 -8
  27. package/dist/{chunk-J2LJB2OH.js → chunk-HY5HLFDU.js} +630 -571
  28. package/dist/chunk-HY5HLFDU.js.map +1 -0
  29. package/dist/{chunk-QVLIIGBU.js → chunk-ICM463EO.js} +60 -13
  30. package/dist/chunk-ICM463EO.js.map +1 -0
  31. package/dist/{chunk-KV2K7MK2.js → chunk-ISZ54SVE.js} +9 -9
  32. package/dist/{chunk-GV2DABNZ.js → chunk-KZ5EY5XX.js} +12 -12
  33. package/dist/{chunk-SW2MF47D.js → chunk-KZXQWC7U.js} +19 -19
  34. package/dist/{chunk-2H43OVTU.js → chunk-LPWPFIIB.js} +11 -11
  35. package/dist/{chunk-EPFC4LHT.js → chunk-MI5TREN3.js} +9 -9
  36. package/dist/{chunk-R42YHLDV.js → chunk-PPZ3K4YM.js} +2 -2
  37. package/dist/{chunk-H3EYBJZU.js → chunk-QMIQR7EE.js} +10 -10
  38. package/dist/{chunk-FKWYD44M.js → chunk-QPGEFLMY.js} +2 -2
  39. package/dist/chunk-RCZJQUTC.js +196 -0
  40. package/dist/chunk-RCZJQUTC.js.map +1 -0
  41. package/dist/{chunk-NQCR3HSU.js → chunk-RNFUVKC3.js} +3 -3
  42. package/dist/{chunk-G5LACAXO.js → chunk-RYOUZ6EK.js} +2 -2
  43. package/dist/{chunk-BSBJXPLC.js → chunk-SGTTR4XW.js} +10 -10
  44. package/dist/{chunk-GVOZ6NDO.js → chunk-SOM4QA6C.js} +3 -3
  45. package/dist/{chunk-73TS2H42.js → chunk-UK4E2FUA.js} +132 -34
  46. package/dist/chunk-UK4E2FUA.js.map +1 -0
  47. package/dist/{chunk-PGN2VX4Y.js → chunk-UWDCIFTP.js} +7 -7
  48. package/dist/{chunk-MCLPSL6B.js → chunk-VE3IYNDN.js} +3 -3
  49. package/dist/{chunk-IAMIBZRF.js → chunk-WCCZJL7W.js} +2 -2
  50. package/dist/{chunk-SVDEWOUD.js → chunk-XZUEFTUP.js} +6 -6
  51. package/dist/{chunk-GPLP7EPL.js → chunk-YII4U7ZD.js} +10 -10
  52. package/dist/{chunk-GPLP7EPL.js.map → chunk-YII4U7ZD.js.map} +1 -1
  53. package/dist/{chunk-WLJVL25O.js → chunk-YUNBOUQH.js} +6 -6
  54. package/dist/{chunk-WNROH2YE.js → chunk-YVPZUN6X.js} +2 -2
  55. package/dist/{chunk-Q2TZA6AC.js → chunk-Z5O2XBWA.js} +14 -14
  56. package/dist/cli.js +57 -49
  57. package/dist/cli.js.map +1 -1
  58. package/dist/{config-UE7IP36J.js → config-KGZUPAUP.js} +13 -13
  59. package/dist/{conventions-Z3QC2NSG.js → conventions-RYN7OXJN.js} +15 -15
  60. package/dist/{diagnostics-2Z5HFQOO.js → diagnostics-HTCWF7F4.js} +7 -7
  61. package/dist/execute-QL3ZQIAP.js +37 -0
  62. package/dist/{generate-PB4L7V5N.js → generate-CX6KNHZS.js} +22 -22
  63. package/dist/{git-7MUOGVRG.js → git-A2IP32PQ.js} +2 -2
  64. package/dist/init-PDVQDRS6.js +24 -0
  65. package/dist/{operations-QDJAFZUN.js → operations-CAKIT2BO.js} +15 -15
  66. package/dist/{permissions-XVXXENVP.js → permissions-G4XCAESF.js} +4 -4
  67. package/dist/plan-PRORGS3L.js +34 -0
  68. package/dist/{policy-6WQZB6B2.js → policy-WX6O2JID.js} +14 -14
  69. package/dist/pr-27RMQI5F.js +39 -0
  70. package/dist/pr-review-VNESMAMT.js +32 -0
  71. package/dist/prd-ZNC4T5BS.js +33 -0
  72. package/dist/{ps-CX7756QG.js → ps-76L6ZAZL.js} +12 -12
  73. package/dist/{recorder-RK6XZYF3.js → recorder-N7U66HCO.js} +7 -7
  74. package/dist/{registry-POSB35Q4.js → registry-XLHHYLTR.js} +5 -5
  75. package/dist/{resume-OQJZV3JH.js → resume-VLWIE264.js} +39 -38
  76. package/dist/{resume-OQJZV3JH.js.map → resume-VLWIE264.js.map} +1 -1
  77. package/dist/review-7CREJDKB.js +35 -0
  78. package/dist/routing-VCDYHSXA.js +33 -0
  79. package/dist/run-3MPORLF5.js +56 -0
  80. package/dist/{session-publisher-VVXOCJ2S.js → session-publisher-KAJQRHNZ.js} +3 -2
  81. package/dist/{state-manager-TIC73GQY.js → state-manager-UPHO2EA2.js} +4 -4
  82. package/dist/state-manager-UPHO2EA2.js.map +1 -0
  83. package/dist/{usage-WDDNSIHP.js → usage-U7QNGCPK.js} +12 -12
  84. package/dist/{web-IPGY52AK.js → web-HUNDHCJ4.js} +20 -18
  85. package/dist/{web-IPGY52AK.js.map → web-HUNDHCJ4.js.map} +1 -1
  86. package/package.json +6 -5
  87. package/web/AGENTS.md +10 -11
  88. package/web/public/app.css +38 -0
  89. package/web/public/app.js +277 -56
  90. package/dist/agent-PMWCDWOW.js +0 -30
  91. package/dist/chunk-73TS2H42.js.map +0 -1
  92. package/dist/chunk-7Z4Y3VKM.js +0 -26
  93. package/dist/chunk-7Z4Y3VKM.js.map +0 -1
  94. package/dist/chunk-AOAQU7PD.js +0 -180
  95. package/dist/chunk-AOAQU7PD.js.map +0 -1
  96. package/dist/chunk-J2LJB2OH.js.map +0 -1
  97. package/dist/chunk-OLUOZLU5.js.map +0 -1
  98. package/dist/chunk-QVLIIGBU.js.map +0 -1
  99. package/dist/chunk-QZOBR6YF.js.map +0 -1
  100. package/dist/chunk-ROIIEVZH.js.map +0 -1
  101. package/dist/chunk-X6GY3CM2.js.map +0 -1
  102. package/dist/chunk-YA6FWFYW.js.map +0 -1
  103. package/dist/execute-QYLJ5L4T.js +0 -36
  104. package/dist/init-XBERAZ4O.js +0 -24
  105. package/dist/plan-RXOW32KY.js +0 -34
  106. package/dist/pr-3WFYAVA7.js +0 -39
  107. package/dist/pr-review-RK63ZEMM.js +0 -32
  108. package/dist/prd-LRV6IW3E.js +0 -33
  109. package/dist/review-AEFISJZD.js +0 -35
  110. package/dist/routing-EA5NJGNU.js +0 -94
  111. package/dist/routing-EA5NJGNU.js.map +0 -1
  112. package/dist/run-HSC7R33Y.js +0 -55
  113. /package/dist/{agent-PMWCDWOW.js.map → agent-TB6W7PT7.js.map} +0 -0
  114. /package/dist/{analyze-556KCJKZ.js.map → analyze-6M3KEOX7.js.map} +0 -0
  115. /package/dist/{apply-WVV7G7WN.js.map → apply-ADB3ZK7W.js.map} +0 -0
  116. /package/dist/{bench-UBFGKUHR.js.map → bench-FM7I7EIV.js.map} +0 -0
  117. /package/dist/{chunk-DBEMD34J.js.map → chunk-32JSYXEK.js.map} +0 -0
  118. /package/dist/{chunk-OGVWJO4S.js.map → chunk-7F7LGMVO.js.map} +0 -0
  119. /package/dist/{chunk-OGN2NX57.js.map → chunk-ANI2NTR4.js.map} +0 -0
  120. /package/dist/{chunk-VK65RNFA.js.map → chunk-B3TSS7BT.js.map} +0 -0
  121. /package/dist/{chunk-MXCOSPLJ.js.map → chunk-DGRTJD5R.js.map} +0 -0
  122. /package/dist/{chunk-VTF4RWS5.js.map → chunk-DV7HUC4Z.js.map} +0 -0
  123. /package/dist/{chunk-OOX3RMD3.js.map → chunk-E6KXCV3T.js.map} +0 -0
  124. /package/dist/{chunk-4FUWWBTP.js.map → chunk-HLAPOUEM.js.map} +0 -0
  125. /package/dist/{chunk-KV2K7MK2.js.map → chunk-ISZ54SVE.js.map} +0 -0
  126. /package/dist/{chunk-GV2DABNZ.js.map → chunk-KZ5EY5XX.js.map} +0 -0
  127. /package/dist/{chunk-SW2MF47D.js.map → chunk-KZXQWC7U.js.map} +0 -0
  128. /package/dist/{chunk-2H43OVTU.js.map → chunk-LPWPFIIB.js.map} +0 -0
  129. /package/dist/{chunk-EPFC4LHT.js.map → chunk-MI5TREN3.js.map} +0 -0
  130. /package/dist/{chunk-R42YHLDV.js.map → chunk-PPZ3K4YM.js.map} +0 -0
  131. /package/dist/{chunk-H3EYBJZU.js.map → chunk-QMIQR7EE.js.map} +0 -0
  132. /package/dist/{chunk-FKWYD44M.js.map → chunk-QPGEFLMY.js.map} +0 -0
  133. /package/dist/{chunk-NQCR3HSU.js.map → chunk-RNFUVKC3.js.map} +0 -0
  134. /package/dist/{chunk-G5LACAXO.js.map → chunk-RYOUZ6EK.js.map} +0 -0
  135. /package/dist/{chunk-BSBJXPLC.js.map → chunk-SGTTR4XW.js.map} +0 -0
  136. /package/dist/{chunk-GVOZ6NDO.js.map → chunk-SOM4QA6C.js.map} +0 -0
  137. /package/dist/{chunk-PGN2VX4Y.js.map → chunk-UWDCIFTP.js.map} +0 -0
  138. /package/dist/{chunk-MCLPSL6B.js.map → chunk-VE3IYNDN.js.map} +0 -0
  139. /package/dist/{chunk-IAMIBZRF.js.map → chunk-WCCZJL7W.js.map} +0 -0
  140. /package/dist/{chunk-SVDEWOUD.js.map → chunk-XZUEFTUP.js.map} +0 -0
  141. /package/dist/{chunk-WLJVL25O.js.map → chunk-YUNBOUQH.js.map} +0 -0
  142. /package/dist/{chunk-WNROH2YE.js.map → chunk-YVPZUN6X.js.map} +0 -0
  143. /package/dist/{chunk-Q2TZA6AC.js.map → chunk-Z5O2XBWA.js.map} +0 -0
  144. /package/dist/{config-UE7IP36J.js.map → config-KGZUPAUP.js.map} +0 -0
  145. /package/dist/{conventions-Z3QC2NSG.js.map → conventions-RYN7OXJN.js.map} +0 -0
  146. /package/dist/{diagnostics-2Z5HFQOO.js.map → diagnostics-HTCWF7F4.js.map} +0 -0
  147. /package/dist/{execute-QYLJ5L4T.js.map → execute-QL3ZQIAP.js.map} +0 -0
  148. /package/dist/{generate-PB4L7V5N.js.map → generate-CX6KNHZS.js.map} +0 -0
  149. /package/dist/{git-7MUOGVRG.js.map → git-A2IP32PQ.js.map} +0 -0
  150. /package/dist/{init-XBERAZ4O.js.map → init-PDVQDRS6.js.map} +0 -0
  151. /package/dist/{operations-QDJAFZUN.js.map → operations-CAKIT2BO.js.map} +0 -0
  152. /package/dist/{permissions-XVXXENVP.js.map → permissions-G4XCAESF.js.map} +0 -0
  153. /package/dist/{plan-RXOW32KY.js.map → plan-PRORGS3L.js.map} +0 -0
  154. /package/dist/{policy-6WQZB6B2.js.map → policy-WX6O2JID.js.map} +0 -0
  155. /package/dist/{pr-3WFYAVA7.js.map → pr-27RMQI5F.js.map} +0 -0
  156. /package/dist/{pr-review-RK63ZEMM.js.map → pr-review-VNESMAMT.js.map} +0 -0
  157. /package/dist/{prd-LRV6IW3E.js.map → prd-ZNC4T5BS.js.map} +0 -0
  158. /package/dist/{ps-CX7756QG.js.map → ps-76L6ZAZL.js.map} +0 -0
  159. /package/dist/{recorder-RK6XZYF3.js.map → recorder-N7U66HCO.js.map} +0 -0
  160. /package/dist/{registry-POSB35Q4.js.map → registry-XLHHYLTR.js.map} +0 -0
  161. /package/dist/{review-AEFISJZD.js.map → review-7CREJDKB.js.map} +0 -0
  162. /package/dist/{run-HSC7R33Y.js.map → routing-VCDYHSXA.js.map} +0 -0
  163. /package/dist/{session-publisher-VVXOCJ2S.js.map → run-3MPORLF5.js.map} +0 -0
  164. /package/dist/{state-manager-TIC73GQY.js.map → session-publisher-KAJQRHNZ.js.map} +0 -0
  165. /package/dist/{usage-WDDNSIHP.js.map → usage-U7QNGCPK.js.map} +0 -0
@@ -1 +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, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { classify } from '../resilience/errors.js';\nimport type { TaskPlan } from '../types.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\nfunction cap(records: ExecutionRecord[], max: number): ExecutionRecord[] {\n if (records.length <= max) return records;\n discardedCount += records.length - max;\n return records.slice(records.length - max);\n}\n\nasync function mutate(tasksPath: string, update: (plan: TaskPlan) => TaskPlan): Promise<void> {\n const plan = await loadTaskPlan(tasksPath);\n await saveTaskPlan(tasksPath, update(plan));\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 await mutate(ctx.tasksPath, (plan) => ({\n ...plan,\n executions: cap([...(plan.executions ?? []), record], cfg.maxExecutions),\n }));\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 await mutate(ctx.tasksPath, (plan) => {\n const records = [...(plan.executions ?? [])];\n if (records.length === 0) return plan;\n const index = records.length - 1;\n const current = records[index];\n if (current === undefined) return plan;\n records[index] = { ...current, verdict };\n return { ...plan, executions: records };\n });\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 await mutate(ctx.tasksPath, (plan) => {\n const records = [...(plan.executions ?? [])];\n const index = records.findIndex((record) => record.id === input.id);\n if (index === -1) return plan;\n const current = records[index];\n if (current === undefined) return plan;\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 records[index] = {\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 = records[index] ?? null;\n return { ...plan, executions: records };\n });\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' | '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;\n actual?: 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":[]}
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, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { classify } from '../resilience/errors.js';\nimport type { TaskPlan } from '../types.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\nfunction cap(records: ExecutionRecord[], max: number): ExecutionRecord[] {\n if (records.length <= max) return records;\n discardedCount += records.length - max;\n return records.slice(records.length - max);\n}\n\nasync function mutate(tasksPath: string, update: (plan: TaskPlan) => TaskPlan): Promise<void> {\n const plan = await loadTaskPlan(tasksPath);\n await saveTaskPlan(tasksPath, update(plan));\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 await mutate(ctx.tasksPath, (plan) => ({\n ...plan,\n executions: cap([...(plan.executions ?? []), record], cfg.maxExecutions),\n }));\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 await mutate(ctx.tasksPath, (plan) => {\n const records = [...(plan.executions ?? [])];\n if (records.length === 0) return plan;\n const index = records.length - 1;\n const current = records[index];\n if (current === undefined) return plan;\n records[index] = { ...current, verdict };\n return { ...plan, executions: records };\n });\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 await mutate(ctx.tasksPath, (plan) => {\n const records = [...(plan.executions ?? [])];\n const index = records.findIndex((record) => record.id === input.id);\n if (index === -1) return plan;\n const current = records[index];\n if (current === undefined) return plan;\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 records[index] = {\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 = records[index] ?? null;\n return { ...plan, executions: records };\n });\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":[]}
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- NullPublisher
4
- } from "./chunk-ROIIEVZH.js";
5
2
  import {
6
3
  getBaseBranch,
7
4
  getCommitsSince,
@@ -12,10 +9,13 @@ import {
12
9
  normalizeRemoteUrl,
13
10
  run,
14
11
  stripRemoteUrlCredentials
15
- } from "./chunk-WNROH2YE.js";
12
+ } from "./chunk-YVPZUN6X.js";
13
+ import {
14
+ NullPublisher
15
+ } from "./chunk-DUS5ZNKL.js";
16
16
  import {
17
17
  isoNow
18
- } from "./chunk-GVOZ6NDO.js";
18
+ } from "./chunk-SOM4QA6C.js";
19
19
 
20
20
  // src/core/session-git.ts
21
21
  async function listPullRequests(branch, options = {}) {
@@ -112,4 +112,4 @@ export {
112
112
  listPullRequests,
113
113
  publishGitState
114
114
  };
115
- //# sourceMappingURL=chunk-WLJVL25O.js.map
115
+ //# sourceMappingURL=chunk-YUNBOUQH.js.map
@@ -201,7 +201,7 @@ function inferSource(command) {
201
201
  }
202
202
  function diagnoseCommandFailure(command, args, result) {
203
203
  if (result.exitCode === 0) return;
204
- void import("./diagnostics-2Z5HFQOO.js").then(({ writeDiagnostic }) => {
204
+ void import("./diagnostics-HTCWF7F4.js").then(({ writeDiagnostic }) => {
205
205
  writeDiagnostic({
206
206
  level: "warning",
207
207
  message: `Command failed: ${basename(command)}`,
@@ -622,4 +622,4 @@ export {
622
622
  committedStoryIds,
623
623
  isWorkingTreeClean
624
624
  };
625
- //# sourceMappingURL=chunk-WNROH2YE.js.map
625
+ //# sourceMappingURL=chunk-YVPZUN6X.js.map
@@ -1,47 +1,47 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  listPullRequests
4
- } from "./chunk-WLJVL25O.js";
4
+ } from "./chunk-YUNBOUQH.js";
5
5
  import {
6
6
  publishPhaseMetrics,
7
7
  resolvePolicyPlaceholders
8
- } from "./chunk-4FUWWBTP.js";
8
+ } from "./chunk-HLAPOUEM.js";
9
9
  import {
10
10
  applyPlaceholders,
11
11
  loadPrompt
12
- } from "./chunk-OGVWJO4S.js";
12
+ } from "./chunk-7F7LGMVO.js";
13
13
  import {
14
14
  DEFAULT_HEADLESS_TIMEOUT_MS,
15
15
  runHeadless
16
- } from "./chunk-73TS2H42.js";
16
+ } from "./chunk-UK4E2FUA.js";
17
17
  import {
18
18
  loadPrReviewConfig
19
- } from "./chunk-J2LJB2OH.js";
19
+ } from "./chunk-HY5HLFDU.js";
20
20
  import {
21
21
  resolveIssuePaths
22
- } from "./chunk-VTF4RWS5.js";
22
+ } from "./chunk-DV7HUC4Z.js";
23
23
  import {
24
24
  getGlobalTimeout,
25
25
  printError,
26
26
  printInfo,
27
27
  printSuccess,
28
28
  printWarning
29
- } from "./chunk-SVDEWOUD.js";
30
- import {
31
- getSessionPublisher
32
- } from "./chunk-ROIIEVZH.js";
29
+ } from "./chunk-XZUEFTUP.js";
33
30
  import {
34
31
  getCurrentBranch,
35
32
  run
36
- } from "./chunk-WNROH2YE.js";
33
+ } from "./chunk-YVPZUN6X.js";
34
+ import {
35
+ getSessionPublisher
36
+ } from "./chunk-DUS5ZNKL.js";
37
37
  import {
38
38
  isoNow,
39
39
  loadTaskPlan,
40
40
  saveTaskPlan
41
- } from "./chunk-GVOZ6NDO.js";
41
+ } from "./chunk-SOM4QA6C.js";
42
42
  import {
43
43
  writeFileAtomic
44
- } from "./chunk-7Z4Y3VKM.js";
44
+ } from "./chunk-3R27MJ5R.js";
45
45
 
46
46
  // src/commands/pr-review.ts
47
47
  import { join as join3 } from "path";
@@ -802,4 +802,4 @@ export {
802
802
  exitCodeFor,
803
803
  runPrReview
804
804
  };
805
- //# sourceMappingURL=chunk-Q2TZA6AC.js.map
805
+ //# sourceMappingURL=chunk-Z5O2XBWA.js.map
package/dist/cli.js CHANGED
@@ -12,27 +12,27 @@ import {
12
12
  setRoutingCliOverrides,
13
13
  setVerifyCliOverrides,
14
14
  setWebCliOverrides
15
- } from "./chunk-J2LJB2OH.js";
16
- import "./chunk-VTF4RWS5.js";
15
+ } from "./chunk-HY5HLFDU.js";
16
+ import "./chunk-DV7HUC4Z.js";
17
17
  import {
18
18
  printError,
19
19
  setGlobalTimeout,
20
20
  setInactivityTimeout,
21
21
  setVerbose
22
- } from "./chunk-SVDEWOUD.js";
23
- import "./chunk-ROIIEVZH.js";
24
- import "./chunk-FKWYD44M.js";
22
+ } from "./chunk-XZUEFTUP.js";
23
+ import "./chunk-QPGEFLMY.js";
25
24
  import "./chunk-HAKDLR6N.js";
26
- import "./chunk-WNROH2YE.js";
27
- import "./chunk-GPLP7EPL.js";
28
- import "./chunk-P3LRUNC6.js";
29
- import "./chunk-R42YHLDV.js";
30
- import "./chunk-GVOZ6NDO.js";
25
+ import "./chunk-YVPZUN6X.js";
26
+ import "./chunk-DUS5ZNKL.js";
27
+ import "./chunk-YII4U7ZD.js";
28
+ import "./chunk-PPZ3K4YM.js";
29
+ import "./chunk-SOM4QA6C.js";
31
30
  import {
32
31
  isAgentProviderId
33
- } from "./chunk-QVLIIGBU.js";
34
- import "./chunk-7Z4Y3VKM.js";
32
+ } from "./chunk-ICM463EO.js";
35
33
  import "./chunk-XEYH6ZZI.js";
34
+ import "./chunk-P3LRUNC6.js";
35
+ import "./chunk-3R27MJ5R.js";
36
36
 
37
37
  // src/cli.ts
38
38
  import { Command, InvalidArgumentError, Option } from "commander";
@@ -353,8 +353,8 @@ withIssueOptions(
353
353
  )
354
354
  ).action(
355
355
  async (options) => {
356
- const { loadIssuesConfig } = await import("./config-UE7IP36J.js");
357
- const { runInit } = await import("./init-XBERAZ4O.js");
356
+ const { loadIssuesConfig } = await import("./config-KGZUPAUP.js");
357
+ const { runInit } = await import("./init-PDVQDRS6.js");
358
358
  const { preferredProvider } = await loadIssuesConfig();
359
359
  const code = await runInit(preferredProvider, {
360
360
  ...options,
@@ -376,7 +376,7 @@ withGlobalOptions(
376
376
  }
377
377
  throw error;
378
378
  }
379
- const { runGenerate } = await import("./generate-PB4L7V5N.js");
379
+ const { runGenerate } = await import("./generate-CX6KNHZS.js");
380
380
  const code = await runGenerate(options.prompt, target);
381
381
  process.exit(code);
382
382
  });
@@ -419,7 +419,7 @@ withUserStoryNumberingOptions(
419
419
  }
420
420
  throw error;
421
421
  }
422
- const { runPipeline } = await import("./run-HSC7R33Y.js");
422
+ const { runPipeline } = await import("./run-3MPORLF5.js");
423
423
  const code = await runPipeline(
424
424
  issues,
425
425
  options.mode,
@@ -448,7 +448,7 @@ withIssueOptions(
448
448
  program.command("resume").description("Resume an interrupted pipeline from the phase it stopped at").argument("[issue]", "Issue to resume. Omitted: the most recently attempted one").option("--all", "Resume every unfinished issue of this project, in order").option("--mode <mode>", "Execution mode: auto | manual", "auto")
449
449
  )
450
450
  ).action(async (issue, options) => {
451
- const { runResume } = await import("./resume-OQJZV3JH.js");
451
+ const { runResume } = await import("./resume-VLWIE264.js");
452
452
  const code = await runResume(issue, {
453
453
  ...options.all === void 0 ? {} : { all: options.all },
454
454
  ...options.mode === void 0 ? {} : { mode: options.mode }
@@ -458,7 +458,7 @@ withIssueOptions(
458
458
  withGlobalOptions(
459
459
  program.command("status").description("What is running right now, in which phase, and since when").argument("[issue]", "Restrict the report to one issue").option("--json", "Emit the assembled state as JSON")
460
460
  ).action(async (issue, options) => {
461
- const { runStatus } = await import("./operations-QDJAFZUN.js");
461
+ const { runStatus } = await import("./operations-CAKIT2BO.js");
462
462
  process.exit(
463
463
  await runStatus(issue, { ...options.json === void 0 ? {} : { json: options.json } })
464
464
  );
@@ -467,7 +467,7 @@ withGlobalOptions(
467
467
  program.command("usage").description("Aggregate execution telemetry from tasks.json").argument("[issue]", "Restrict the report to one issue").option("--issue <issue>", "Same as the positional argument").option("--since <date>", "Only executions started on or after this ISO date").option("--by <key>", "Group by harness, provider, model, purpose or status").option("--json", "Emit the assembled totals as JSON")
468
468
  ).action(
469
469
  async (issue, options) => {
470
- const { runUsage, USAGE_GROUP_KEYS } = await import("./usage-WDDNSIHP.js");
470
+ const { runUsage, USAGE_GROUP_KEYS } = await import("./usage-U7QNGCPK.js");
471
471
  const by = options.by;
472
472
  if (by !== void 0 && !USAGE_GROUP_KEYS.includes(by)) {
473
473
  printError("Must be one of: harness, provider, model, purpose, status.");
@@ -485,20 +485,20 @@ withGlobalOptions(
485
485
  withGlobalOptions(
486
486
  program.command("ps").description("Every issue-flow run active on this machine").option("--json", "Emit the listing as JSON").option("--watch", "Refresh the listing until interrupted")
487
487
  ).action(async (options) => {
488
- const { runPs } = await import("./ps-CX7756QG.js");
488
+ const { runPs } = await import("./ps-76L6ZAZL.js");
489
489
  process.exit(await runPs(options));
490
490
  });
491
491
  withGlobalOptions(
492
492
  program.command("runs").description("History of the runs of this project, with how each ended")
493
493
  ).action(async () => {
494
- const { runRuns } = await import("./operations-QDJAFZUN.js");
494
+ const { runRuns } = await import("./operations-CAKIT2BO.js");
495
495
  process.exit(await runRuns());
496
496
  });
497
497
  withGlobalOptions(
498
498
  program.command("logs").description("Read the execution journal (events.jsonl), filtered and readable").argument("[issue]", "Issue to read. Omitted: the most recently attempted one").option("--issue <issue>", "Same as the positional argument").option("--follow", "Keep reading as the journal grows").option("--tail <n>", "How many entries to show first (default 50)", parseInteger).option("--kind <kinds>", "Only these event types, comma separated (retry, phase:end, \u2026)")
499
499
  ).action(
500
500
  async (issue, options) => {
501
- const { runLogs } = await import("./operations-QDJAFZUN.js");
501
+ const { runLogs } = await import("./operations-CAKIT2BO.js");
502
502
  const kinds = options.kind === void 0 ? void 0 : options.kind.split(",").map((kind) => kind.trim()).filter((kind) => kind !== "");
503
503
  process.exit(
504
504
  await runLogs(issue ?? options.issue, {
@@ -512,13 +512,13 @@ withGlobalOptions(
512
512
  withGlobalOptions(
513
513
  program.command("pause").description("Ask the running pipeline to stop after writing a checkpoint")
514
514
  ).action(async () => {
515
- const { runPause } = await import("./operations-QDJAFZUN.js");
515
+ const { runPause } = await import("./operations-CAKIT2BO.js");
516
516
  process.exit(await runPause());
517
517
  });
518
518
  withGlobalOptions(
519
519
  program.command("cancel").description("Stop the run and mark the issue so a resume does not pick it up").argument("[issue]", "Issue to cancel. Omitted: the most recently attempted one")
520
520
  ).action(async (issue) => {
521
- const { runCancel } = await import("./operations-QDJAFZUN.js");
521
+ const { runCancel } = await import("./operations-CAKIT2BO.js");
522
522
  process.exit(await runCancel(issue));
523
523
  });
524
524
  withIssueOptions(
@@ -526,7 +526,7 @@ withIssueOptions(
526
526
  program.command("analyze").description("Analyze an issue with the configured agent").argument("<issue>", "Issue number")
527
527
  )
528
528
  ).action(async (issue) => {
529
- const { runAnalyze } = await import("./analyze-556KCJKZ.js");
529
+ const { runAnalyze } = await import("./analyze-6M3KEOX7.js");
530
530
  const code = await runAnalyze(issue);
531
531
  process.exit(code);
532
532
  });
@@ -535,7 +535,7 @@ withIssueOptions(
535
535
  program.command("prd").description("Generate a PRD from an analyzed issue with the configured agent").argument("<issue>", "Issue number")
536
536
  )
537
537
  ).action(async (issue) => {
538
- const { runPrd } = await import("./prd-LRV6IW3E.js");
538
+ const { runPrd } = await import("./prd-ZNC4T5BS.js");
539
539
  const code = await runPrd(issue);
540
540
  process.exit(code);
541
541
  });
@@ -556,7 +556,7 @@ withUserStoryNumberingOptions(
556
556
  }
557
557
  throw error;
558
558
  }
559
- const { runPlan } = await import("./plan-RXOW32KY.js");
559
+ const { runPlan } = await import("./plan-PRORGS3L.js");
560
560
  const code = await runPlan(issue, void 0, numbering);
561
561
  process.exit(code);
562
562
  });
@@ -575,7 +575,7 @@ withWebOptions(
575
575
  ).action(
576
576
  async (positionalMaxIter, options) => {
577
577
  try {
578
- const { runExecute } = await import("./execute-QYLJ5L4T.js");
578
+ const { runExecute } = await import("./execute-QL3ZQIAP.js");
579
579
  const code = await runExecute(positionalMaxIter, options);
580
580
  process.exit(code);
581
581
  } catch (error) {
@@ -589,7 +589,7 @@ withIssueOptions(
589
589
  program.command("review").description("Validate an issue resolution with the configured agent").argument("<issue>", "Issue number")
590
590
  )
591
591
  ).action(async (issue) => {
592
- const { runReview } = await import("./review-AEFISJZD.js");
592
+ const { runReview } = await import("./review-7CREJDKB.js");
593
593
  const code = await runReview(issue);
594
594
  process.exit(code);
595
595
  });
@@ -598,7 +598,7 @@ withIssueOptions(
598
598
  program.command("pr").description("Create a pull request with the configured agent").argument("<issue>", "Issue number")
599
599
  )
600
600
  ).action(async (issue) => {
601
- const { runPr } = await import("./pr-3WFYAVA7.js");
601
+ const { runPr } = await import("./pr-27RMQI5F.js");
602
602
  const code = await runPr(issue);
603
603
  process.exit(code);
604
604
  });
@@ -606,63 +606,71 @@ var webCommand = program.command("web").description("Manage the web monitoring s
606
606
  webCommand.command("serve").description(
607
607
  "Run the web monitor server in the foreground (internal \u2014 spawned detached by --web)"
608
608
  ).option("--port <n>", "Web server port (default: 3737)", parseInteger).option("--host <h>", "Web server host (default: 0.0.0.0)").option("--refresh <s>", "Suggested UI polling interval in seconds", parseInteger).action(async (options) => {
609
- const { runWebServe } = await import("./web-IPGY52AK.js");
609
+ const { runWebServe } = await import("./web-HUNDHCJ4.js");
610
610
  const code = await runWebServe(options);
611
611
  if (code !== 0) {
612
612
  process.exit(code);
613
613
  }
614
614
  });
615
615
  webCommand.command("stop").description("Stop the running web monitor server").action(async () => {
616
- const { runWebStop } = await import("./web-IPGY52AK.js");
616
+ const { runWebStop } = await import("./web-HUNDHCJ4.js");
617
617
  const code = await runWebStop();
618
618
  process.exit(code);
619
619
  });
620
620
  withGlobalOptions(
621
621
  program.command("policy").description("Inspect the policies discovered in this repository and their provenance").option("--scope <dir>", "Resolve the policy for a subdirectory (monorepo)").option("--json", "Emit the resolved policy as JSON")
622
622
  ).action(async (options) => {
623
- const { runPolicy } = await import("./policy-6WQZB6B2.js");
623
+ const { runPolicy } = await import("./policy-WX6O2JID.js");
624
624
  const code = await runPolicy(options);
625
625
  process.exit(code);
626
626
  });
627
627
  var routingCommand = withGlobalOptions(
628
- program.command("routing").description("Inspect the shadow router (records a recommendation, does not act)")
628
+ program.command("routing").description("Inspect and configure adaptive harness/model routing")
629
629
  );
630
- routingCommand.option("--json", "Emit the resolved routing config as JSON").action(async (options) => {
631
- const { runRoutingInspect } = await import("./routing-EA5NJGNU.js");
632
- process.exit(await runRoutingInspect(options));
630
+ routingCommand.option("--json", "Emit the resolved routing config as JSON").action(async (_options, command) => {
631
+ const { runRoutingInspect } = await import("./routing-VCDYHSXA.js");
632
+ process.exit(await runRoutingInspect(command.opts()));
633
+ });
634
+ routingCommand.command("explain").description("Explain the resolved routing target for every phase").option("--json", "Emit JSON").action(async (_options, command) => {
635
+ const { runRoutingExplain } = await import("./routing-VCDYHSXA.js");
636
+ process.exit(await runRoutingExplain(command.optsWithGlobals()));
637
+ });
638
+ routingCommand.command("use").description("Enable an embedded routing policy").argument("<policy>", "Policy name (recommended)").option("--global", "Write ~/.issue-flow/config.json (default)").option("--project", "Write .issue-flow.json instead").action(async (policy, _options, command) => {
639
+ const { runRoutingUse } = await import("./routing-VCDYHSXA.js");
640
+ process.exit(await runRoutingUse(policy, command.optsWithGlobals()));
633
641
  });
634
- routingCommand.command("report").description("Shadow agreement between selected and actual harness").option("--issue <n>", "Issue number").option("--json", "Emit JSON").action(async (options) => {
635
- const { runRoutingReport } = await import("./routing-EA5NJGNU.js");
636
- process.exit(await runRoutingReport(options));
642
+ routingCommand.command("report").description("Shadow agreement between selected and actual harness").option("--issue <n>", "Issue number").option("--json", "Emit JSON").action(async (_options, command) => {
643
+ const { runRoutingReport } = await import("./routing-VCDYHSXA.js");
644
+ process.exit(await runRoutingReport(command.optsWithGlobals()));
637
645
  });
638
646
  var conventionsCommand = withGlobalOptions(
639
647
  program.command("conventions").description("Compute the repository Git convention (branch, commit, PR title)")
640
648
  );
641
649
  conventionsCommand.command("branch").description("Print the deterministic branch name for an issue").option("--issue <n>", "Issue number").option("--title <text>", "Issue title, when the issue cannot be resolved").option("--json", "Emit JSON").action(async (options) => {
642
- const { runConventionsBranch } = await import("./conventions-Z3QC2NSG.js");
650
+ const { runConventionsBranch } = await import("./conventions-RYN7OXJN.js");
643
651
  process.exit(await runConventionsBranch(options));
644
652
  });
645
653
  conventionsCommand.command("commit").description("Print a Conventional Commit message").requiredOption("--type <type>", "Change type (feat, fix, docs, \u2026)").option("--scope <scope>", "Optional scope").requiredOption("--subject <text>", "Commit subject").option("--issue <n>", "Issue number for the Refs trailer").option("--story <id>", "Story id (US-010)").option("--breaking <text>", "Breaking change description").option("--json", "Emit JSON").action(
646
654
  async (options) => {
647
- const { runConventionsCommit } = await import("./conventions-Z3QC2NSG.js");
655
+ const { runConventionsCommit } = await import("./conventions-RYN7OXJN.js");
648
656
  process.exit(await runConventionsCommit(options));
649
657
  }
650
658
  );
651
659
  conventionsCommand.command("pr-title").description("Print the Conventional Commit Pull Request title").option("--issue <n>", "Issue number").option("--title <text>", "Issue title, when the issue cannot be resolved").option("--json", "Emit JSON").action(async (options) => {
652
- const { runConventionsPrTitle } = await import("./conventions-Z3QC2NSG.js");
660
+ const { runConventionsPrTitle } = await import("./conventions-RYN7OXJN.js");
653
661
  process.exit(await runConventionsPrTitle(options));
654
662
  });
655
663
  var agentCommand = withGlobalOptions(
656
664
  program.command("agent").description("Inspect the resolved agent and model for each phase").option("--json", "Emit the resolved agent configuration as JSON")
657
665
  );
658
666
  agentCommand.action(async (options) => {
659
- const { runAgent } = await import("./agent-PMWCDWOW.js");
667
+ const { runAgent } = await import("./agent-TB6W7PT7.js");
660
668
  const code = await runAgent(options);
661
669
  process.exit(code);
662
670
  });
663
671
  agentCommand.command("use").description("Write an agent preference to config.json or .issue-flow.json").argument("<provider>", "claude, codex, cursor or antigravity").option("--model <model>", "Model identifier for this preference").option("--global", "Write to ~/.issue-flow/config.json (default)").option("--project", "Write to .issue-flow.json in the repository").option("--phase <phase>", "Write only the override for this phase").action(
664
672
  async (provider, options) => {
665
- const { runAgentUse } = await import("./agent-PMWCDWOW.js");
673
+ const { runAgentUse } = await import("./agent-TB6W7PT7.js");
666
674
  const code = await runAgentUse(provider, options);
667
675
  process.exit(code);
668
676
  }
@@ -674,7 +682,7 @@ withGlobalOptions(
674
682
  )
675
683
  ).action(
676
684
  async (pr, options) => {
677
- const { runPrReview } = await import("./pr-review-RK63ZEMM.js");
685
+ const { runPrReview } = await import("./pr-review-VNESMAMT.js");
678
686
  const code = await runPrReview(pr, options);
679
687
  process.exit(code);
680
688
  }
@@ -700,7 +708,7 @@ withGlobalOptions(
700
708
  printError("Unknown bench mode. Use 'synthetic' or 'real'.");
701
709
  process.exit(1);
702
710
  }
703
- const { runBench } = await import("./bench-UBFGKUHR.js");
711
+ const { runBench } = await import("./bench-FM7I7EIV.js");
704
712
  process.exit(
705
713
  await runBench({
706
714
  ...options.mode === void 0 ? {} : { mode: options.mode },
@@ -718,13 +726,13 @@ withGlobalOptions(
718
726
  }
719
727
  );
720
728
  program.action(async () => {
721
- const { listLiveRuns } = await import("./registry-POSB35Q4.js");
729
+ const { listLiveRuns } = await import("./registry-XLHHYLTR.js");
722
730
  const runs = await listLiveRuns();
723
731
  if (runs.length === 0) {
724
732
  program.help();
725
733
  return;
726
734
  }
727
- const { runPs } = await import("./ps-CX7756QG.js");
735
+ const { runPs } = await import("./ps-76L6ZAZL.js");
728
736
  process.exit(await runPs());
729
737
  });
730
738
  program.parse();