issue-flow 0.14.0 → 0.16.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.
- package/dist/{agent-OX3KPHE4.js → agent-PMWCDWOW.js} +12 -12
- package/dist/{analyze-WIND2SEB.js → analyze-556KCJKZ.js} +20 -20
- package/dist/{apply-JNOI2LR4.js → apply-WVV7G7WN.js} +12 -12
- package/dist/{bench-B4VZON7E.js → bench-UBFGKUHR.js} +18 -18
- package/dist/{chunk-2IQ6M4ZE.js → chunk-2H43OVTU.js} +11 -11
- package/dist/{chunk-PHW2YV6N.js → chunk-4FUWWBTP.js} +6 -6
- package/dist/{chunk-CGKLE6WR.js → chunk-73TS2H42.js} +14 -14
- package/dist/{chunk-LEW4QM74.js → chunk-AOAQU7PD.js} +2 -2
- package/dist/{chunk-WB2X37MO.js → chunk-BSBJXPLC.js} +8 -8
- package/dist/chunk-C5TL7T4V.js +27 -0
- package/dist/chunk-C5TL7T4V.js.map +1 -0
- package/dist/{chunk-76MMPJ53.js → chunk-DBEMD34J.js} +6 -6
- package/dist/{chunk-SZMHCEYV.js → chunk-EPFC4LHT.js} +9 -9
- package/dist/{chunk-3WFZETIM.js → chunk-FKWYD44M.js} +2 -2
- package/dist/{chunk-JN6D3MY6.js → chunk-G5LACAXO.js} +2 -2
- package/dist/{chunk-67YIU2VB.js → chunk-GPLP7EPL.js} +6 -6
- package/dist/{chunk-6BENHR2I.js → chunk-GV2DABNZ.js} +12 -12
- package/dist/{chunk-J3SOTUVI.js → chunk-GVOZ6NDO.js} +2 -2
- package/dist/{chunk-PZTWU277.js → chunk-H3EYBJZU.js} +7 -7
- package/dist/{chunk-3BWZO4YI.js → chunk-IAMIBZRF.js} +2 -2
- package/dist/{chunk-QJ5UZAH5.js → chunk-J2LJB2OH.js} +10 -10
- package/dist/{chunk-F6TOYSYY.js → chunk-KV2K7MK2.js} +9 -9
- package/dist/{chunk-REO3PXXO.js → chunk-MCLPSL6B.js} +3 -3
- package/dist/{chunk-OOVG2KBY.js → chunk-MXCOSPLJ.js} +2 -2
- package/dist/{chunk-KT7JKOXB.js → chunk-NQCR3HSU.js} +3 -3
- package/dist/{chunk-QD4VOILZ.js → chunk-OGN2NX57.js} +9 -9
- package/dist/{chunk-KMRFRXIT.js → chunk-OGVWJO4S.js} +3 -3
- package/dist/{chunk-X44FKNKP.js → chunk-OLUOZLU5.js} +42 -34
- package/dist/chunk-OLUOZLU5.js.map +1 -0
- package/dist/{chunk-RVO7L4FX.js → chunk-OOX3RMD3.js} +4 -4
- package/dist/{chunk-UJ3L2MS7.js → chunk-PGN2VX4Y.js} +6 -6
- package/dist/{chunk-QZVKRDJY.js → chunk-Q2TZA6AC.js} +11 -11
- package/dist/{chunk-LBGHI4S2.js → chunk-QVLIIGBU.js} +8 -3
- package/dist/chunk-QVLIIGBU.js.map +1 -0
- package/dist/{chunk-BRCNQXYQ.js → chunk-QZOBR6YF.js} +4 -4
- package/dist/{chunk-G5EK2XRN.js → chunk-R42YHLDV.js} +2 -2
- package/dist/{chunk-6QYMSNVA.js → chunk-ROIIEVZH.js} +3 -2
- package/dist/chunk-ROIIEVZH.js.map +1 -0
- package/dist/{chunk-TYRNTSPJ.js → chunk-SVDEWOUD.js} +4 -4
- package/dist/{chunk-B72RQZBV.js → chunk-SW2MF47D.js} +35 -20
- package/dist/chunk-SW2MF47D.js.map +1 -0
- package/dist/{chunk-V7MO5EDS.js → chunk-VK65RNFA.js} +3 -3
- package/dist/{chunk-QK7WUO7A.js → chunk-VTF4RWS5.js} +6 -6
- package/dist/{chunk-PBTA3QQX.js → chunk-WLJVL25O.js} +4 -4
- package/dist/{chunk-BEZ5BA5U.js → chunk-WNROH2YE.js} +2 -2
- package/dist/{chunk-OR43364P.js → chunk-X6GY3CM2.js} +3 -3
- package/dist/chunk-YA6FWFYW.js +891 -0
- package/dist/chunk-YA6FWFYW.js.map +1 -0
- package/dist/cli.js +61 -69
- package/dist/cli.js.map +1 -1
- package/dist/{config-HMFMCY2M.js → config-UE7IP36J.js} +11 -11
- package/dist/{conventions-NJF2OPVQ.js → conventions-Z3QC2NSG.js} +13 -13
- package/dist/{diagnostics-THH42ZMP.js → diagnostics-2Z5HFQOO.js} +6 -6
- package/dist/execute-QYLJ5L4T.js +36 -0
- package/dist/{generate-FW5C6NP7.js → generate-PB4L7V5N.js} +20 -20
- package/dist/{git-W72QQ6GT.js → git-7MUOGVRG.js} +2 -2
- package/dist/init-XBERAZ4O.js +24 -0
- package/dist/{operations-BCFOBH42.js → operations-QDJAFZUN.js} +13 -13
- package/dist/{permissions-4AKNQZHK.js → permissions-XVXXENVP.js} +3 -3
- package/dist/plan-RXOW32KY.js +34 -0
- package/dist/{policy-DT6Q6ZVM.js → policy-6WQZB6B2.js} +12 -12
- package/dist/pr-3WFYAVA7.js +39 -0
- package/dist/pr-review-RK63ZEMM.js +32 -0
- package/dist/prd-LRV6IW3E.js +33 -0
- package/dist/{ps-RFORTCUD.js → ps-CX7756QG.js} +10 -10
- package/dist/{recorder-KCCPMKQG.js → recorder-RK6XZYF3.js} +5 -5
- package/dist/{registry-GLPXOMFG.js → registry-POSB35Q4.js} +5 -5
- package/dist/{resume-M5RLKP4I.js → resume-OQJZV3JH.js} +37 -36
- package/dist/{resume-M5RLKP4I.js.map → resume-OQJZV3JH.js.map} +1 -1
- package/dist/review-AEFISJZD.js +35 -0
- package/dist/{routing-NNT5WKGX.js → routing-EA5NJGNU.js} +12 -12
- package/dist/run-HSC7R33Y.js +55 -0
- package/dist/{session-publisher-T7EI3CIP.js → session-publisher-VVXOCJ2S.js} +2 -2
- package/dist/{state-manager-GQH32C44.js → state-manager-TIC73GQY.js} +3 -3
- package/dist/{usage-V2CHE5PY.js → usage-WDDNSIHP.js} +10 -10
- package/dist/{web-EA3KGNFN.js → web-IPGY52AK.js} +21 -59
- package/dist/{web-EA3KGNFN.js.map → web-IPGY52AK.js.map} +1 -1
- package/package.json +1 -1
- package/web/AGENTS.md +9 -0
- package/web/public/app.css +13 -0
- package/web/public/app.js +77 -10
- package/web/public/index.html +6 -2
- package/dist/chunk-6QYMSNVA.js.map +0 -1
- package/dist/chunk-B72RQZBV.js.map +0 -1
- package/dist/chunk-LBGHI4S2.js.map +0 -1
- package/dist/chunk-LFEQIZLB.js +0 -558
- package/dist/chunk-LFEQIZLB.js.map +0 -1
- package/dist/chunk-X44FKNKP.js.map +0 -1
- package/dist/execute-KFNNZZHI.js +0 -35
- package/dist/init-HTN4V67Q.js +0 -24
- package/dist/plan-SIZLGA4V.js +0 -34
- package/dist/pr-OMWCGUOW.js +0 -39
- package/dist/pr-review-N24CZPKR.js +0 -32
- package/dist/prd-5OFTZAHJ.js +0 -33
- package/dist/review-YM4JAABY.js +0 -35
- package/dist/run-PZUKHPQK.js +0 -54
- /package/dist/{agent-OX3KPHE4.js.map → agent-PMWCDWOW.js.map} +0 -0
- /package/dist/{analyze-WIND2SEB.js.map → analyze-556KCJKZ.js.map} +0 -0
- /package/dist/{apply-JNOI2LR4.js.map → apply-WVV7G7WN.js.map} +0 -0
- /package/dist/{bench-B4VZON7E.js.map → bench-UBFGKUHR.js.map} +0 -0
- /package/dist/{chunk-2IQ6M4ZE.js.map → chunk-2H43OVTU.js.map} +0 -0
- /package/dist/{chunk-PHW2YV6N.js.map → chunk-4FUWWBTP.js.map} +0 -0
- /package/dist/{chunk-CGKLE6WR.js.map → chunk-73TS2H42.js.map} +0 -0
- /package/dist/{chunk-LEW4QM74.js.map → chunk-AOAQU7PD.js.map} +0 -0
- /package/dist/{chunk-WB2X37MO.js.map → chunk-BSBJXPLC.js.map} +0 -0
- /package/dist/{chunk-76MMPJ53.js.map → chunk-DBEMD34J.js.map} +0 -0
- /package/dist/{chunk-SZMHCEYV.js.map → chunk-EPFC4LHT.js.map} +0 -0
- /package/dist/{chunk-3WFZETIM.js.map → chunk-FKWYD44M.js.map} +0 -0
- /package/dist/{chunk-JN6D3MY6.js.map → chunk-G5LACAXO.js.map} +0 -0
- /package/dist/{chunk-67YIU2VB.js.map → chunk-GPLP7EPL.js.map} +0 -0
- /package/dist/{chunk-6BENHR2I.js.map → chunk-GV2DABNZ.js.map} +0 -0
- /package/dist/{chunk-J3SOTUVI.js.map → chunk-GVOZ6NDO.js.map} +0 -0
- /package/dist/{chunk-PZTWU277.js.map → chunk-H3EYBJZU.js.map} +0 -0
- /package/dist/{chunk-3BWZO4YI.js.map → chunk-IAMIBZRF.js.map} +0 -0
- /package/dist/{chunk-QJ5UZAH5.js.map → chunk-J2LJB2OH.js.map} +0 -0
- /package/dist/{chunk-F6TOYSYY.js.map → chunk-KV2K7MK2.js.map} +0 -0
- /package/dist/{chunk-REO3PXXO.js.map → chunk-MCLPSL6B.js.map} +0 -0
- /package/dist/{chunk-OOVG2KBY.js.map → chunk-MXCOSPLJ.js.map} +0 -0
- /package/dist/{chunk-KT7JKOXB.js.map → chunk-NQCR3HSU.js.map} +0 -0
- /package/dist/{chunk-QD4VOILZ.js.map → chunk-OGN2NX57.js.map} +0 -0
- /package/dist/{chunk-KMRFRXIT.js.map → chunk-OGVWJO4S.js.map} +0 -0
- /package/dist/{chunk-RVO7L4FX.js.map → chunk-OOX3RMD3.js.map} +0 -0
- /package/dist/{chunk-UJ3L2MS7.js.map → chunk-PGN2VX4Y.js.map} +0 -0
- /package/dist/{chunk-QZVKRDJY.js.map → chunk-Q2TZA6AC.js.map} +0 -0
- /package/dist/{chunk-BRCNQXYQ.js.map → chunk-QZOBR6YF.js.map} +0 -0
- /package/dist/{chunk-G5EK2XRN.js.map → chunk-R42YHLDV.js.map} +0 -0
- /package/dist/{chunk-TYRNTSPJ.js.map → chunk-SVDEWOUD.js.map} +0 -0
- /package/dist/{chunk-V7MO5EDS.js.map → chunk-VK65RNFA.js.map} +0 -0
- /package/dist/{chunk-QK7WUO7A.js.map → chunk-VTF4RWS5.js.map} +0 -0
- /package/dist/{chunk-PBTA3QQX.js.map → chunk-WLJVL25O.js.map} +0 -0
- /package/dist/{chunk-BEZ5BA5U.js.map → chunk-WNROH2YE.js.map} +0 -0
- /package/dist/{chunk-OR43364P.js.map → chunk-X6GY3CM2.js.map} +0 -0
- /package/dist/{config-HMFMCY2M.js.map → config-UE7IP36J.js.map} +0 -0
- /package/dist/{conventions-NJF2OPVQ.js.map → conventions-Z3QC2NSG.js.map} +0 -0
- /package/dist/{diagnostics-THH42ZMP.js.map → diagnostics-2Z5HFQOO.js.map} +0 -0
- /package/dist/{execute-KFNNZZHI.js.map → execute-QYLJ5L4T.js.map} +0 -0
- /package/dist/{generate-FW5C6NP7.js.map → generate-PB4L7V5N.js.map} +0 -0
- /package/dist/{git-W72QQ6GT.js.map → git-7MUOGVRG.js.map} +0 -0
- /package/dist/{init-HTN4V67Q.js.map → init-XBERAZ4O.js.map} +0 -0
- /package/dist/{operations-BCFOBH42.js.map → operations-QDJAFZUN.js.map} +0 -0
- /package/dist/{permissions-4AKNQZHK.js.map → permissions-XVXXENVP.js.map} +0 -0
- /package/dist/{plan-SIZLGA4V.js.map → plan-RXOW32KY.js.map} +0 -0
- /package/dist/{policy-DT6Q6ZVM.js.map → policy-6WQZB6B2.js.map} +0 -0
- /package/dist/{pr-OMWCGUOW.js.map → pr-3WFYAVA7.js.map} +0 -0
- /package/dist/{pr-review-N24CZPKR.js.map → pr-review-RK63ZEMM.js.map} +0 -0
- /package/dist/{prd-5OFTZAHJ.js.map → prd-LRV6IW3E.js.map} +0 -0
- /package/dist/{ps-RFORTCUD.js.map → ps-CX7756QG.js.map} +0 -0
- /package/dist/{recorder-KCCPMKQG.js.map → recorder-RK6XZYF3.js.map} +0 -0
- /package/dist/{registry-GLPXOMFG.js.map → registry-POSB35Q4.js.map} +0 -0
- /package/dist/{review-YM4JAABY.js.map → review-AEFISJZD.js.map} +0 -0
- /package/dist/{routing-NNT5WKGX.js.map → routing-EA5NJGNU.js.map} +0 -0
- /package/dist/{run-PZUKHPQK.js.map → run-HSC7R33Y.js.map} +0 -0
- /package/dist/{session-publisher-T7EI3CIP.js.map → session-publisher-VVXOCJ2S.js.map} +0 -0
- /package/dist/{state-manager-GQH32C44.js.map → state-manager-TIC73GQY.js.map} +0 -0
- /package/dist/{usage-V2CHE5PY.js.map → usage-WDDNSIHP.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/session-state.ts","../src/core/session-publisher.ts"],"sourcesContent":["import { mkdir, rename, utimes, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { stripVTControlCharacters } from 'node:util';\nimport type { FailureKind } from '../resilience/errors.js';\nimport { setTelemetrySessionId } from '../telemetry/session-id.js';\nimport type { ExecutionRecord } from '../telemetry/types.js';\nimport type { StoryStage, UserStory, UserStoryStatus } from '../types.js';\n\n/**\n * Session state publishing layer for the optional web monitoring mode.\n *\n * Instrumentation points call publish() with SessionEvents; a pure reducer\n * folds each event into an in-memory SessionSnapshot that any surface\n * (file, HTTP endpoint, future webhooks) can consume in a single format.\n *\n * Monitoring must never affect the pipeline: publish() is synchronous and\n * never throws, and all publisher I/O failures are swallowed after a\n * single warning.\n */\n\nexport type SessionLogLevel = 'info' | 'warn' | 'error';\nexport type SessionStatus = 'idle' | 'running' | 'completed' | 'failed';\nexport type SessionPhaseStatus = 'pending' | 'running' | 'completed' | 'failed';\n\n/** Default max entries retained in the logs ring buffer. */\nexport const DEFAULT_LOG_LIMIT = 200;\n\n/** Default minimum interval between FilePublisher disk writes. */\nexport const DEFAULT_THROTTLE_MS = 1000;\n\n/** Default interval for touching a live session file without rewriting it. */\nexport const DEFAULT_SESSION_HEARTBEAT_MS = 10_000;\n\nexport type SessionEvent =\n | {\n type: 'session:start';\n at: string;\n sessionId: string;\n /** `null` for local identifiers that are not numbers. */\n issueNumber: number | null;\n issueUrl?: string;\n branch?: string;\n baseBranch?: string;\n phases: string[];\n environment?: SessionEnvironment;\n configuration?: SessionConfigurationSnapshot;\n branchCreated?: boolean | null;\n startCommit?: string | null;\n }\n | {\n /**\n * Structural data of the Issue being worked on, published once the\n * provider has resolved it. Merged over the `issue` section instead of\n * replacing it, so the number and the URL that came with `session:start`\n * survive an origin that reports neither.\n */\n type: 'issue:update';\n at: string;\n number: number | null;\n url?: string;\n title: string | null;\n /** Issue body, published whole — no truncation. */\n description: string | null;\n labels: string[];\n state: string | null;\n }\n | { type: 'phase:start'; at: string; phase: string }\n | {\n type: 'phase:end';\n at: string;\n phase: string;\n success: boolean;\n error?: string;\n harnessExecutionMs?: number | null;\n orchestrationOverheadMs?: number | null;\n harnessStartupMs?: number | null;\n ttftMs?: number | null;\n attemptCount?: number | null;\n retryDurationMs?: number | null;\n }\n | {\n type: 'iteration:start';\n at: string;\n iteration: number;\n /**\n * Id of the story `execute` is about to work on, computed by\n * `core/engine.ts` with the same \"highest priority, `passes: false`\"\n * rule `prompts/execute.md` gives the agent. Optional so a caller that\n * cannot determine it (or an older build) is still a valid event —\n * `applyEvent` simply skips the `executing`/`pending` transition then.\n */\n storyId?: string;\n }\n | { type: 'iteration:end'; at: string; iteration: number }\n | {\n type: 'retry';\n at: string;\n attempt: number;\n delaySeconds?: number;\n reason?: string;\n /**\n * What the resilience layer classified the failure as. Optional so an\n * event written by an older build — or by a caller with nothing but a\n * message — stays valid; the reducer only counts retries either way.\n */\n kind?: FailureKind;\n }\n | {\n type: 'agent:attempt';\n at: string;\n attempt: number;\n provider: string;\n model?: string | null;\n primaryProvider: string;\n }\n | {\n type: 'failover';\n at: string;\n from: string;\n to: string;\n reason: FailureKind | null;\n cooldownUntil?: string | null;\n }\n | {\n type: 'agent:result';\n at: string;\n provider: string;\n success: boolean;\n failureKind?: FailureKind;\n cooldownUntil?: string | null;\n }\n | { type: 'agent:activity'; at: string; provider: string }\n | { type: 'stories:update'; at: string; stories: UserStory[] }\n | { type: 'activity'; at: string; story?: string; tool?: string; detail?: string }\n | { type: 'log'; at: string; level: SessionLogLevel; message: string }\n | {\n type: 'process:output';\n at: string;\n phase: string;\n executionId: string | null;\n provider: string;\n stream: 'stdout' | 'stderr' | 'combined';\n message: string;\n }\n | { type: 'execution:update'; at: string; execution: ExecutionRecord }\n | { type: 'correction:cycle'; at: string; cycle: number; maxCycles: number }\n | {\n type: 'metrics:update';\n at: string;\n /**\n * Where the metrics land:\n * - `phase`: the named phase plus the issue-wide aggregate;\n * - `iteration`: one execute-loop pass — same targets as `phase`;\n * - `story`: the story alone, never the phase nor the aggregate (the\n * iteration event of the same cycle already counted those tokens).\n */\n scope: 'phase' | 'iteration' | 'story';\n phase?: string;\n storyId?: string;\n iteration?: number;\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n costUsd?: number;\n durationSeconds?: number;\n }\n | {\n /**\n * One publication feeds both the `git` section (branch, base, commits)\n * and the `repository` section (identity and location). They come from\n * the same collection pass, so extending this event keeps `branch`\n * consistent across the two instead of racing a second event.\n *\n * Every field is optional: `undefined` means \"not collected in this\n * publication\" and leaves the snapshot untouched, while an explicit\n * `null` means \"collected and unavailable\" and is written as-is.\n */\n type: 'git:update';\n at: string;\n branch?: string;\n baseBranch?: string;\n branchCreated?: boolean | null;\n commits?: SessionCommit[];\n pullRequests?: SessionPullRequest[];\n /** `owner/repo`, derived from the origin remote. */\n repositoryName?: string | null;\n remoteUrl?: string | null;\n headCommit?: string | null;\n repositoryRoot?: string | null;\n }\n | { type: 'session:end'; at: string; status: 'completed' | 'failed'; error?: string }\n | {\n type: 'verify:end';\n at: string;\n verdict: 'passed' | 'failed' | 'unverified';\n level: string;\n independence: string | null;\n executionId: string | null;\n };\n\nexport interface SessionEnvironment {\n node: string;\n platform: string;\n /** Winning agent provider for the run. `null` on snapshots from earlier releases. */\n agent: string | null;\n /** Winning model for the run. `null` when unset or on older snapshots. */\n model: string | null;\n}\n\nexport interface SessionLogEntry {\n at: string;\n level: SessionLogLevel;\n message: string;\n}\n\nexport interface SessionProcessLogEntry {\n at: string;\n phase: string;\n executionId: string | null;\n provider: string;\n stream: 'stdout' | 'stderr' | 'combined';\n message: string;\n}\n\nexport interface SessionConfigurationValue {\n value: string | null;\n source: 'default' | 'global' | 'project' | 'env' | 'cli' | 'fallback';\n}\n\nexport interface SessionPhaseConfiguration {\n phase: string;\n provider: SessionConfigurationValue;\n model: SessionConfigurationValue;\n}\n\nexport interface SessionConfigurationSnapshot {\n precedence: string[];\n defaultProvider: SessionConfigurationValue;\n defaultModel: SessionConfigurationValue;\n phases: SessionPhaseConfiguration[];\n fallbacks: string[];\n overrides: string[];\n}\n\nexport interface SessionStageHistoryEntry {\n at: string;\n stage: StoryStage;\n detail: string | null;\n}\n\n/**\n * Token/cost counters attached to a phase or a story.\n *\n * `null` means \"never reported\" — the `claude` CLI does not always return\n * usage data, and a metric that was never observed must stay distinguishable\n * from an observed zero.\n */\nexport interface SessionUsageSnapshot {\n inputTokens: number | null;\n outputTokens: number | null;\n cacheReadTokens: number | null;\n cacheCreationTokens: number | null;\n costUsd: number | null;\n}\n\n/** Issue-wide totals, accumulated from phase- and iteration-scoped metrics. */\nexport interface SessionMetricsSnapshot {\n totalInputTokens: number | null;\n totalOutputTokens: number | null;\n totalCacheReadTokens: number | null;\n totalCacheCreationTokens: number | null;\n totalCostUsd: number | null;\n}\n\nexport interface SessionPhaseSnapshot extends SessionUsageSnapshot {\n name: string;\n status: SessionPhaseStatus;\n startedAt: string | null;\n endedAt: string | null;\n durationSeconds: number | null;\n error: string | null;\n /** Sum of invocation walls for this phase. */\n harnessExecutionMs: number | null;\n /** Phase wall minus harnessExecutionMs, when both are known. */\n orchestrationOverheadMs: number | null;\n /** Wall clock − CLI `duration_ms`. */\n harnessStartupMs: number | null;\n /** Time to first output, when the harness reports it. */\n ttftMs: number | null;\n attemptCount: number | null;\n retryDurationMs: number | null;\n}\n\nexport interface SessionStorySnapshot extends SessionUsageSnapshot {\n id: string;\n title: string;\n priority: number;\n passes: boolean;\n /**\n * When the story flipped to passing during this session; null for stories\n * that were already passing at session start (their duration is unknown).\n */\n completedAt: string | null;\n /** Wall-clock seconds attributed to the story, or null when unknown. */\n durationSeconds: number | null;\n /**\n * Board-style status, recomputed on every reduction by\n * {@link deriveStoryStatus}. Observational: the pipeline keeps deciding what\n * to execute from `passes`.\n */\n status: UserStoryStatus;\n /** IDs of the stories this one depends on, as declared in the plan. */\n dependencies: string[];\n /** The plan's description; empty string when the plan carries none. */\n description: string;\n /** The plan's acceptance criteria; empty when the plan carries none. */\n acceptanceCriteria: string[];\n /**\n * Fine-grained execution stage, derived only from real pipeline events —\n * see {@link StoryStage} and the `applyEvent` cases for `iteration:start`,\n * `stories:update`, `phase:start`/`phase:end` (phase `'review'`) and\n * `correction:cycle`. Unlike `status`, this is not a post-hoc derivation\n * recomputed on every reduction: it is set directly, event by event, like\n * `completedAt`.\n */\n stage: StoryStage;\n /** ISO timestamp of the event that produced the current `stage`. */\n stageSince: string | null;\n /** Short human detail for the current stage (e.g. a correction cycle). */\n stageDetail: string | null;\n /** Append-only transition history retained in the snapshot for the drawer. */\n history: SessionStageHistoryEntry[];\n}\n\nexport interface SessionActivity {\n story: string | null;\n tool: string | null;\n detail: string | null;\n since: string;\n}\n\n/** Live resilience state for the current agent invocation. */\nexport interface SessionResilienceSnapshot {\n attempt: number;\n provider: string | null;\n model: string | null;\n lastFailureKind: FailureKind | null;\n cooldownUntil: string | null;\n lastActivityAt: string | null;\n}\n\nexport interface SessionCommit {\n hash: string;\n subject: string;\n committedAt?: string | null;\n storyId?: string | null;\n}\n\nexport interface SessionPullRequest {\n number: number;\n url: string;\n title: string;\n}\n\n/**\n * The Issue under execution, as far as the session knows it.\n *\n * `number`/`url` come with `session:start`; the remaining fields arrive with\n * `issue:update`, once the provider has resolved the Issue. Everything is\n * nullable because a run may start before (or without) that resolution —\n * `null` means \"not reported\", never \"empty\".\n */\nexport interface SessionIssueSnapshot {\n number: number | null;\n url: string | null;\n title: string | null;\n /** Issue body in full; the consumer decides how to fold it. */\n description: string | null;\n labels: string[];\n /** Provider lifecycle state ('open' / 'closed' for the built-ins). */\n state: string | null;\n}\n\n/**\n * Where the run is happening: which repository, which checkout, which commit.\n *\n * Fed by `git:update` (see `publishGitState`). Every field is nullable because\n * each source is independent and failure-tolerant — no remote configured, a\n * repository with no commits yet or a missing git binary all show up as\n * `null` instead of failing the publication.\n */\nexport interface SessionRepositorySnapshot {\n /** `owner/repo`, derived from the origin remote; null without one. */\n name: string | null;\n remoteUrl: string | null;\n branch: string | null;\n /** Abbreviated hash of HEAD. */\n headCommit: string | null;\n /** Absolute path of the working directory the pipeline runs from. */\n root: string | null;\n}\n\nexport interface SessionSnapshot {\n schemaVersion: 1;\n sessionId: string | null;\n readOnly: true;\n capabilities: string[];\n issue: SessionIssueSnapshot;\n status: SessionStatus;\n startedAt: string | null;\n updatedAt: string | null;\n endedAt: string | null;\n elapsedSeconds: number | null;\n estimatedRemainingSeconds: number | null;\n progress: {\n percent: number;\n phasesCompleted: number;\n phasesTotal: number;\n storiesCompleted: number;\n storiesTotal: number;\n };\n currentPhase: string | null;\n currentActivity: SessionActivity | null;\n phases: SessionPhaseSnapshot[];\n stories: SessionStorySnapshot[];\n metrics: SessionMetricsSnapshot;\n execution: {\n iteration: number;\n retries: number;\n correctionCycle: number;\n maxCorrectionCycles: number | null;\n };\n executions: ExecutionRecord[];\n processLogs: SessionProcessLogEntry[];\n configuration: SessionConfigurationSnapshot | null;\n resilience: SessionResilienceSnapshot;\n git: {\n branch: string | null;\n baseBranch: string | null;\n branchCreated: boolean | null;\n startCommit: string | null;\n commits: SessionCommit[];\n };\n repository: SessionRepositorySnapshot;\n pullRequests: SessionPullRequest[];\n logs: SessionLogEntry[];\n errors: SessionLogEntry[];\n warnings: SessionLogEntry[];\n lastError: { message: string; at: string } | null;\n nextSteps: string[];\n environment: SessionEnvironment | null;\n /** Acceptance-contract verdict. `null` until a contract has run. */\n verification: {\n verdict: 'passed' | 'failed' | 'unverified' | null;\n level: string | null;\n independence: string | null;\n } | null;\n}\n\nexport interface SessionReducerOptions {\n /** Max entries retained in the logs ring buffer. */\n logLimit?: number;\n}\n\n/** Fresh, all-null usage counters for a new phase or story entry. */\nfunction emptyUsage(): SessionUsageSnapshot {\n return {\n inputTokens: null,\n outputTokens: null,\n cacheReadTokens: null,\n cacheCreationTokens: null,\n costUsd: null,\n };\n}\n\nfunction emptyPhaseTiming(): Pick<\n SessionPhaseSnapshot,\n | 'harnessExecutionMs'\n | 'orchestrationOverheadMs'\n | 'harnessStartupMs'\n | 'ttftMs'\n | 'attemptCount'\n | 'retryDurationMs'\n> {\n return {\n harnessExecutionMs: null,\n orchestrationOverheadMs: null,\n harnessStartupMs: null,\n ttftMs: null,\n attemptCount: null,\n retryDurationMs: null,\n };\n}\n\nfunction emptyMetrics(): SessionMetricsSnapshot {\n return {\n totalInputTokens: null,\n totalOutputTokens: null,\n totalCacheReadTokens: null,\n totalCacheCreationTokens: null,\n totalCostUsd: null,\n };\n}\n\nexport function createInitialSnapshot(): SessionSnapshot {\n return {\n schemaVersion: 1,\n sessionId: null,\n readOnly: true,\n capabilities: [],\n issue: { number: null, url: null, title: null, description: null, labels: [], state: null },\n status: 'idle',\n startedAt: null,\n updatedAt: null,\n endedAt: null,\n elapsedSeconds: null,\n estimatedRemainingSeconds: null,\n progress: {\n percent: 0,\n phasesCompleted: 0,\n phasesTotal: 0,\n storiesCompleted: 0,\n storiesTotal: 0,\n },\n currentPhase: null,\n currentActivity: null,\n phases: [],\n stories: [],\n metrics: emptyMetrics(),\n execution: { iteration: 0, retries: 0, correctionCycle: 0, maxCorrectionCycles: null },\n executions: [],\n processLogs: [],\n configuration: null,\n resilience: {\n attempt: 0,\n provider: null,\n model: null,\n lastFailureKind: null,\n cooldownUntil: null,\n lastActivityAt: null,\n },\n git: {\n branch: null,\n baseBranch: null,\n branchCreated: null,\n startCommit: null,\n commits: [],\n },\n repository: { name: null, remoteUrl: null, branch: null, headCommit: null, root: null },\n pullRequests: [],\n logs: [],\n errors: [],\n warnings: [],\n lastError: null,\n nextSteps: [],\n environment: null,\n verification: null,\n };\n}\n\ntype MetricsUpdateEvent = Extract<SessionEvent, { type: 'metrics:update' }>;\n\n/**\n * Add a reported delta to an accumulator. `undefined` means \"not reported\":\n * it leaves the accumulator untouched, so a metric the CLI never returned\n * stays null instead of collapsing to zero.\n */\nfunction accumulate(current: number | null, delta: number | undefined): number | null {\n return delta === undefined ? current : (current ?? 0) + delta;\n}\n\n/** Fold the event's token/cost fields into a phase or story entry. */\nfunction accumulateUsage<T extends SessionUsageSnapshot>(target: T, event: MetricsUpdateEvent): T {\n return {\n ...target,\n inputTokens: accumulate(target.inputTokens, event.inputTokens),\n outputTokens: accumulate(target.outputTokens, event.outputTokens),\n cacheReadTokens: accumulate(target.cacheReadTokens, event.cacheReadTokens),\n cacheCreationTokens: accumulate(target.cacheCreationTokens, event.cacheCreationTokens),\n costUsd: accumulate(target.costUsd, event.costUsd),\n };\n}\n\n/**\n * Pick between a reported value and the one already in the snapshot.\n * Unlike `??`, an explicitly reported `null` wins: only `undefined` — the\n * absence of the field on the event — keeps the previous value.\n */\nfunction reported<T>(value: T | undefined, previous: T): T {\n return value === undefined ? previous : value;\n}\n\n/**\n * Seconds between two ISO timestamps, or null when either is unparsable.\n */\nfunction secondsBetween(from: string | null, to: string): number | null {\n if (from === null) return null;\n const fromMs = Date.parse(from);\n const toMs = Date.parse(to);\n if (Number.isNaN(fromMs) || Number.isNaN(toMs)) return null;\n return Math.max(0, Math.round((toMs - fromMs) / 1000));\n}\n\nfunction computePercent(phasesCompleted: number, phasesTotal: number): number {\n if (phasesTotal === 0) return 0;\n return Math.round((phasesCompleted / phasesTotal) * 100);\n}\n\n/**\n * Estimated seconds until all stories pass: average duration of the stories\n * completed during this session × pending stories. Durations are the gaps\n * between consecutive completions (the first is measured from startedAt).\n * Published as null with fewer than two samples.\n */\nfunction estimateRemainingSeconds(snapshot: SessionSnapshot): number | null {\n const completions = snapshot.stories\n .map((story) => (story.completedAt === null ? Number.NaN : Date.parse(story.completedAt)))\n .filter((ms) => !Number.isNaN(ms))\n .sort((a, b) => a - b);\n if (completions.length < 2) return null;\n\n const startMs = snapshot.startedAt === null ? Number.NaN : Date.parse(snapshot.startedAt);\n const boundaries = Number.isNaN(startMs) ? completions : [startMs, ...completions];\n const durations: number[] = [];\n for (let i = 1; i < boundaries.length; i++) {\n durations.push(Math.max(0, boundaries[i] - boundaries[i - 1]));\n }\n if (durations.length === 0) return null;\n\n const averageMs = durations.reduce((sum, d) => sum + d, 0) / durations.length;\n const pending = snapshot.stories.filter((story) => !story.passes).length;\n return Math.round((averageMs * pending) / 1000);\n}\n\n/**\n * Remaining pipeline phases, in order. The phase list originates from the\n * session:start event, whose caller passes PIPELINE_PHASES (or\n * PIPELINE_PHASES_NO_BRANCH in --no-branch mode) from src/core/pipeline.ts.\n */\nfunction deriveNextSteps(snapshot: SessionSnapshot): string[] {\n if (snapshot.status === 'completed') return [];\n return snapshot.phases.filter((phase) => phase.status === 'pending').map((phase) => phase.name);\n}\n\n/**\n * Board status of a single story, in a fixed order that makes the derivation\n * idempotent — recomputing it over its own result yields the same value:\n *\n * 1. `passes: true` → `done` (execution is the only authority on completion);\n * 2. already `in_review` → kept, since nothing here can produce or clear it;\n * 3. the story owns the current activity → `in_progress`;\n * 4. otherwise → `backlog`.\n *\n * `in_review` is therefore never derived: it only enters through an explicit\n * `status` in tasks.json, and leaves when the story starts passing.\n */\nfunction deriveStoryStatus(\n story: SessionStorySnapshot,\n activeStory: string | null,\n): UserStoryStatus {\n if (story.passes) return 'done';\n if (story.status === 'in_review') return 'in_review';\n if (activeStory !== null && activeStory === story.id) return 'in_progress';\n return 'backlog';\n}\n\n/** Recompute every story's status; entries that do not change keep identity. */\nfunction deriveStoryStatuses(snapshot: SessionSnapshot): SessionStorySnapshot[] {\n const activeStory = snapshot.currentActivity?.story ?? null;\n return snapshot.stories.map((story) => {\n const status = deriveStoryStatus(story, activeStory);\n return status === story.status ? story : { ...story, status };\n });\n}\n\n/**\n * Fold a SessionEvent into a SessionSnapshot. Pure: never mutates the input\n * and performs no I/O. Unknown event types return the snapshot unchanged.\n *\n * errors/warnings are derived slices of the logs ring buffer, recomputed on\n * each reduction — they are never accumulated separately. The same applies\n * to estimatedRemainingSeconds, nextSteps and each story's status.\n */\nexport function reduceSessionEvent(\n snapshot: SessionSnapshot,\n event: SessionEvent,\n options?: SessionReducerOptions,\n): SessionSnapshot {\n const next = applyEvent(snapshot, event, options);\n if (next === snapshot) return snapshot;\n\n const elapsedSeconds = secondsBetween(next.startedAt, event.at) ?? next.elapsedSeconds;\n return {\n ...next,\n updatedAt: event.at,\n elapsedSeconds,\n stories: deriveStoryStatuses(next),\n estimatedRemainingSeconds: estimateRemainingSeconds(next),\n errors: next.logs.filter((entry) => entry.level === 'error'),\n warnings: next.logs.filter((entry) => entry.level === 'warn'),\n nextSteps: deriveNextSteps(next),\n };\n}\n\n/**\n * Stages that describe a finished story. A run that ends — successfully or\n * not — must never leave a story on any other stage, or the panel keeps\n * claiming it is executing long after the process is gone.\n */\nfunction isTerminalStage(stage: StoryStage): boolean {\n return stage === 'done' || stage === 'failed';\n}\n\nfunction transitionStory(\n story: SessionStorySnapshot,\n stage: StoryStage,\n at: string,\n detail: string | null,\n): SessionStorySnapshot {\n if (story.stage === stage && story.stageDetail === detail) return story;\n return {\n ...story,\n stage,\n stageSince: at,\n stageDetail: detail,\n history: [...story.history, { at, stage, detail }],\n };\n}\n\n/**\n * `stage`/`stageSince`/`stageDetail` for one story, on one `stories:update`.\n *\n * This event owns exactly one transition — `awaiting_review` the moment a\n * story flips to `passes: true` (or is first seen already passing, since its\n * real completion moment is unknown either way). Everything else is a\n * carry-over: a still-`passes: false` story keeps whatever `iteration:start`\n * last gave it (defaulting to `'pending'` the very first time it is ever\n * seen), and a story already passing before this event is left exactly as it\n * was — `phase:start`/`phase:end` (review) and `correction:cycle` own every\n * transition past `awaiting_review`.\n */\nfunction deriveStageOnStoriesUpdate(\n story: UserStory,\n before: SessionStorySnapshot | undefined,\n at: string,\n): Pick<SessionStorySnapshot, 'stage' | 'stageSince' | 'stageDetail'> {\n if (!story.passes) {\n return {\n stage: before?.stage ?? 'pending',\n stageSince: before?.stageSince ?? at,\n stageDetail: before?.stageDetail ?? null,\n };\n }\n if (before?.passes) {\n return { stage: before.stage, stageSince: before.stageSince, stageDetail: before.stageDetail };\n }\n return { stage: 'awaiting_review', stageSince: at, stageDetail: null };\n}\n\nfunction applyEvent(\n snapshot: SessionSnapshot,\n event: SessionEvent,\n options?: SessionReducerOptions,\n): SessionSnapshot {\n switch (event.type) {\n case 'session:start': {\n setTelemetrySessionId(event.sessionId);\n const initial = createInitialSnapshot();\n return {\n ...initial,\n sessionId: event.sessionId,\n issue: { ...initial.issue, number: event.issueNumber, url: event.issueUrl ?? null },\n status: 'running',\n startedAt: event.at,\n progress: {\n ...initial.progress,\n phasesTotal: event.phases.length,\n },\n phases: event.phases.map((name) => ({\n name,\n status: 'pending' as const,\n startedAt: null,\n endedAt: null,\n durationSeconds: null,\n error: null,\n ...emptyPhaseTiming(),\n ...emptyUsage(),\n })),\n git: {\n branch: event.branch ?? null,\n baseBranch: event.baseBranch ?? null,\n branchCreated: event.branchCreated ?? null,\n startCommit: event.startCommit ?? null,\n commits: [],\n },\n // The branch is the one piece of repository identity the session\n // already knows here; the rest waits for publishGitState. Seeding it\n // keeps git.branch and repository.branch consistent for a poll that\n // lands before the first git:update.\n repository: { ...initial.repository, branch: event.branch ?? null },\n configuration: event.configuration ?? null,\n environment: event.environment\n ? {\n node: event.environment.node,\n platform: event.environment.platform,\n agent: event.environment.agent ?? null,\n model: event.environment.model ?? null,\n }\n : null,\n };\n }\n\n case 'issue:update':\n return {\n ...snapshot,\n issue: {\n ...snapshot.issue,\n // Merge, not replacement: the run may know a number and a URL that\n // the provider does not report (a local Issue mirroring a remote\n // one), and enriching the section must never erase them.\n number: event.number ?? snapshot.issue.number,\n url: event.url ?? snapshot.issue.url,\n title: event.title,\n description: event.description,\n labels: event.labels,\n state: event.state,\n },\n };\n\n case 'phase:start': {\n const known = snapshot.phases.some((p) => p.name === event.phase);\n const phases = known\n ? snapshot.phases.map((p) =>\n p.name === event.phase\n ? {\n ...p,\n status: 'running' as const,\n startedAt: event.at,\n endedAt: null,\n error: null,\n }\n : p,\n )\n : [\n ...snapshot.phases,\n {\n name: event.phase,\n status: 'running' as const,\n startedAt: event.at,\n endedAt: null,\n durationSeconds: null,\n error: null,\n ...emptyPhaseTiming(),\n ...emptyUsage(),\n },\n ];\n // The `execute` phase only completes (and `review` only starts) once\n // every story already passes — a pipeline invariant — so entering\n // `review` safely moves every passing story to 'in_review' in one go;\n // there is never a not-yet-passing story to skip over here.\n const stories =\n event.phase === 'review'\n ? snapshot.stories.map((story) =>\n story.passes ? transitionStory(story, 'in_review', event.at, null) : story,\n )\n : snapshot.stories;\n return {\n ...snapshot,\n currentPhase: event.phase,\n phases,\n stories,\n progress: known ? snapshot.progress : { ...snapshot.progress, phasesTotal: phases.length },\n };\n }\n\n case 'phase:end': {\n const phases = snapshot.phases.map((p) =>\n p.name === event.phase\n ? {\n ...p,\n status: event.success ? ('completed' as const) : ('failed' as const),\n endedAt: event.at,\n durationSeconds: secondsBetween(p.startedAt, event.at),\n error: event.error ? stripVTControlCharacters(event.error) : null,\n harnessExecutionMs: event.harnessExecutionMs ?? p.harnessExecutionMs,\n orchestrationOverheadMs: event.orchestrationOverheadMs ?? p.orchestrationOverheadMs,\n harnessStartupMs: event.harnessStartupMs ?? p.harnessStartupMs,\n ttftMs: event.ttftMs ?? p.ttftMs,\n attemptCount: event.attemptCount ?? p.attemptCount,\n retryDurationMs: event.retryDurationMs ?? p.retryDurationMs,\n }\n : p,\n );\n const phasesCompleted = phases.filter((p) => p.status === 'completed').length;\n // Success moves every passing story to 'done'. Failure (the correction\n // loop gave up after maxCorrectionCycles) closes every story that is not\n // already 'done' as 'failed' — including the ones that never reached\n // `passes`, which are precisely the stories the issue calls failed. A\n // phase that fails outside `review` closes the same non-terminal stages,\n // so nothing is left frozen on 'executing' after the run stops.\n const stories = !event.success\n ? snapshot.stories.map((story) =>\n isTerminalStage(story.stage) ? story : transitionStory(story, 'failed', event.at, null),\n )\n : event.phase === 'review'\n ? snapshot.stories.map((story) =>\n story.passes ? transitionStory(story, 'done', event.at, null) : story,\n )\n : snapshot.stories;\n return {\n ...snapshot,\n currentPhase: snapshot.currentPhase === event.phase ? null : snapshot.currentPhase,\n currentActivity: null,\n phases,\n stories,\n progress: {\n ...snapshot.progress,\n phasesCompleted,\n percent: computePercent(phasesCompleted, snapshot.progress.phasesTotal),\n },\n };\n }\n\n case 'iteration:start': {\n // The story matching storyId becomes 'executing'; every other\n // not-yet-passing story becomes 'pending' (a story that was already\n // 'executing' in a previous iteration but lost the turn reverts here).\n // Passing stories are untouched — this event owns only the\n // execute-loop's own pending/executing transition, never review or\n // correction. No-op branches (`return story`) avoid needless object\n // churn when the stage is already correct.\n const storyId = event.storyId;\n const stories = snapshot.stories.map((story) => {\n if (story.passes) return story;\n if (story.id === storyId) {\n return transitionStory(story, 'executing', event.at, null);\n }\n return transitionStory(story, 'pending', event.at, null);\n });\n return {\n ...snapshot,\n execution: { ...snapshot.execution, iteration: event.iteration },\n stories,\n // Finally populates the `story` field of the activity payload during\n // execute — today this phase never publishes an `activity` event at\n // all (no streaming), so `currentActivity` stays whatever an earlier\n // phase left it at. Left untouched when storyId is absent (every\n // story already passes, or the caller could not determine one).\n currentActivity:\n storyId !== undefined\n ? { story: storyId, tool: null, detail: null, since: event.at }\n : snapshot.currentActivity,\n };\n }\n\n case 'iteration:end':\n return { ...snapshot, currentActivity: null };\n\n case 'retry':\n return {\n ...snapshot,\n execution: { ...snapshot.execution, retries: snapshot.execution.retries + 1 },\n };\n\n case 'agent:attempt':\n return {\n ...snapshot,\n resilience: {\n ...snapshot.resilience,\n attempt: event.attempt,\n provider: event.provider,\n model: event.model ?? null,\n lastActivityAt: event.at,\n },\n };\n\n case 'failover':\n return {\n ...snapshot,\n resilience: {\n ...snapshot.resilience,\n provider: event.to,\n lastFailureKind: event.reason,\n cooldownUntil: event.cooldownUntil ?? null,\n lastActivityAt: event.at,\n },\n };\n\n case 'agent:result':\n return {\n ...snapshot,\n resilience: {\n ...snapshot.resilience,\n provider: event.provider,\n lastFailureKind: event.failureKind ?? snapshot.resilience.lastFailureKind,\n cooldownUntil: event.cooldownUntil ?? null,\n lastActivityAt: event.at,\n },\n };\n\n case 'agent:activity':\n return {\n ...snapshot,\n resilience: {\n ...snapshot.resilience,\n provider: event.provider,\n lastActivityAt: event.at,\n },\n };\n\n case 'stories:update': {\n const previous = new Map(snapshot.stories.map((story) => [story.id, story]));\n const stories = event.stories.map((story) => {\n const before = previous.get(story.id);\n // Stamp the flip to passing; stories already passing when first seen\n // keep null (completed before this session, duration unknown).\n const completedAt = !story.passes\n ? null\n : before && !before.passes\n ? event.at\n : (before?.completedAt ?? null);\n // stories:update rebuilds the array from the plan on every publish, so\n // metrics already attributed to a story must be carried over here or\n // the next update would wipe them.\n const stage = deriveStageOnStoriesUpdate(story, before, event.at);\n const history = before?.history ?? [];\n const stageChanged = before !== undefined && before.stage !== stage.stage;\n return {\n id: story.id,\n title: story.title,\n priority: story.priority,\n passes: story.passes,\n completedAt,\n // Seed only: deriveStoryStatus() recomputes it right after, so an\n // explicit 'done' in the plan on a story with passes: false is not\n // honoured — `passes` remains the single source of truth. The plan's\n // value survives just for 'in_review', which no derivation produces.\n status: story.status ?? before?.status ?? 'backlog',\n dependencies: story.dependencies ?? [],\n // Required on UserStory, so the plan is always the source — no\n // carry-over from `before` the way the accumulated fields need.\n description: story.description,\n acceptanceCriteria: story.acceptanceCriteria,\n durationSeconds: before?.durationSeconds ?? null,\n inputTokens: before?.inputTokens ?? null,\n outputTokens: before?.outputTokens ?? null,\n cacheReadTokens: before?.cacheReadTokens ?? null,\n cacheCreationTokens: before?.cacheCreationTokens ?? null,\n costUsd: before?.costUsd ?? null,\n ...stage,\n history: stageChanged\n ? [...history, { at: event.at, stage: stage.stage, detail: stage.stageDetail }]\n : history,\n };\n });\n return {\n ...snapshot,\n stories,\n progress: {\n ...snapshot.progress,\n storiesCompleted: stories.filter((s) => s.passes).length,\n storiesTotal: stories.length,\n },\n };\n }\n\n case 'activity': {\n const story = event.story ?? null;\n const tool = event.tool ?? null;\n const detail = event.detail ?? null;\n const current = snapshot.currentActivity;\n // Same activity repeated: keep `since` so the UI can show \"for how long\".\n const since =\n current && current.story === story && current.tool === tool && current.detail === detail\n ? current.since\n : event.at;\n return {\n ...snapshot,\n currentActivity: { story, tool, detail, since },\n resilience: { ...snapshot.resilience, lastActivityAt: event.at },\n };\n }\n\n case 'log': {\n const limit = options?.logLimit ?? DEFAULT_LOG_LIMIT;\n const entry: SessionLogEntry = {\n at: event.at,\n level: event.level,\n message: stripVTControlCharacters(event.message),\n };\n const logs = [...snapshot.logs, entry].slice(-Math.max(1, limit));\n return { ...snapshot, logs };\n }\n\n case 'process:output': {\n const limit = options?.logLimit ?? DEFAULT_LOG_LIMIT;\n const entry: SessionProcessLogEntry = {\n at: event.at,\n phase: event.phase,\n executionId: event.executionId,\n provider: event.provider,\n stream: event.stream,\n message: stripVTControlCharacters(event.message),\n };\n return {\n ...snapshot,\n processLogs: [...snapshot.processLogs, entry].slice(-Math.max(1, limit)),\n };\n }\n\n case 'execution:update': {\n const index = snapshot.executions.findIndex((entry) => entry.id === event.execution.id);\n const executions = [...snapshot.executions];\n if (index === -1) executions.push(event.execution);\n else executions[index] = event.execution;\n return { ...snapshot, executions };\n }\n\n case 'git:update':\n return {\n ...snapshot,\n git: {\n branch: event.branch ?? snapshot.git.branch,\n baseBranch: event.baseBranch ?? snapshot.git.baseBranch,\n branchCreated: reported(event.branchCreated, snapshot.git.branchCreated),\n startCommit: snapshot.git.startCommit,\n commits: event.commits ?? snapshot.git.commits,\n },\n repository: {\n // `undefined` is \"not collected\", so the previous value stands; an\n // explicit `null` is \"collected and unavailable\" and overwrites it.\n name: reported(event.repositoryName, snapshot.repository.name),\n remoteUrl: reported(event.remoteUrl, snapshot.repository.remoteUrl),\n branch: event.branch ?? snapshot.repository.branch,\n headCommit: reported(event.headCommit, snapshot.repository.headCommit),\n root: reported(event.repositoryRoot, snapshot.repository.root),\n },\n pullRequests: event.pullRequests ?? snapshot.pullRequests,\n };\n\n case 'correction:cycle': {\n // Correction is pipeline-wide, not per-story: commands/run.ts re-runs\n // the whole execute+review cycle on a review failure, with no notion\n // of which story a finding belongs to — so every passing story moves\n // to 'in_correction' together, carrying the cycle count as a readable\n // stageDetail.\n const stageDetail = `Cycle ${event.cycle}/${event.maxCycles}`;\n const stories = snapshot.stories.map((story) =>\n story.passes ? transitionStory(story, 'in_correction', event.at, stageDetail) : story,\n );\n return {\n ...snapshot,\n execution: {\n ...snapshot.execution,\n correctionCycle: event.cycle,\n maxCorrectionCycles: event.maxCycles,\n },\n stories,\n };\n }\n\n case 'metrics:update': {\n if (event.scope === 'story') {\n // Story metrics are a rateio of the iteration that completed them;\n // the iteration-scoped event already fed the phase and the aggregate,\n // so counting them again here would double the totals.\n if (event.storyId === undefined) return snapshot;\n if (!snapshot.stories.some((s) => s.id === event.storyId)) return snapshot;\n return {\n ...snapshot,\n stories: snapshot.stories.map((story) =>\n story.id === event.storyId\n ? {\n ...accumulateUsage(story, event),\n durationSeconds: accumulate(story.durationSeconds, event.durationSeconds),\n }\n : story,\n ),\n };\n }\n\n // phase and iteration scopes both land on the named phase. An event for\n // a phase the snapshot never saw is ignored rather than appended: it\n // would show up as a phantom entry in the UI.\n if (event.phase === undefined) return snapshot;\n if (!snapshot.phases.some((p) => p.name === event.phase)) return snapshot;\n return {\n ...snapshot,\n // durationSeconds is deliberately untouched here: phase:start and\n // phase:end remain the single source of a phase's wall-clock time.\n phases: snapshot.phases.map((phase) =>\n phase.name === event.phase ? accumulateUsage(phase, event) : phase,\n ),\n metrics: {\n totalInputTokens: accumulate(snapshot.metrics.totalInputTokens, event.inputTokens),\n totalOutputTokens: accumulate(snapshot.metrics.totalOutputTokens, event.outputTokens),\n totalCacheReadTokens: accumulate(\n snapshot.metrics.totalCacheReadTokens,\n event.cacheReadTokens,\n ),\n totalCacheCreationTokens: accumulate(\n snapshot.metrics.totalCacheCreationTokens,\n event.cacheCreationTokens,\n ),\n totalCostUsd: accumulate(snapshot.metrics.totalCostUsd, event.costUsd),\n },\n };\n }\n\n case 'verify:end':\n return {\n ...snapshot,\n verification: {\n verdict: event.verdict,\n level: event.level,\n independence: event.independence,\n },\n };\n\n case 'session:end':\n return {\n ...snapshot,\n status: event.status,\n endedAt: event.at,\n currentPhase: null,\n currentActivity: null,\n // Close every non-terminal stage: the run is over, so nothing can be\n // 'executing'/'in_review'/'in_correction' any more. A story that never\n // reached `passes` on a run that did not complete is exactly what the\n // 'failed' stage means; anything else settles as 'done'.\n stories: snapshot.stories.map((story) => {\n if (isTerminalStage(story.stage)) return story;\n const stage =\n event.status === 'completed' && story.passes ? ('done' as const) : ('failed' as const);\n return transitionStory(story, stage, event.at, null);\n }),\n lastError: event.error\n ? { message: stripVTControlCharacters(event.error), at: event.at }\n : snapshot.lastError,\n };\n\n default:\n return snapshot;\n }\n}\n\nexport interface SessionPublisher {\n /**\n * Publish an event. Synchronous, never throws, never returns a promise —\n * safe to call from any instrumentation point without affecting execution.\n */\n publish(event: SessionEvent): void;\n /** Current in-memory snapshot. */\n snapshot(): SessionSnapshot;\n /** Monotonic counter, bumped on every applied event (basis for ETags). */\n version(): number;\n /** Force any pending output to be written. Never rejects. */\n flush(): Promise<void>;\n /** Flush and release resources. Never rejects. */\n close(): Promise<void>;\n}\n\n/**\n * Default publisher when monitoring is off: every call is a no-op, so each\n * instrumentation point costs a method call that returns immediately.\n */\nexport class NullPublisher implements SessionPublisher {\n private readonly empty = createInitialSnapshot();\n\n publish(_event: SessionEvent): void {}\n\n snapshot(): SessionSnapshot {\n return this.empty;\n }\n\n version(): number {\n return 0;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n}\n\nexport interface MemoryPublisherOptions extends SessionReducerOptions {\n /** Called at most once, on the first internal failure. */\n onWarn?: (message: string) => void;\n /**\n * When false, log events are dropped before reaching the snapshot, so no\n * log line is ever published (session.json or HTTP). Default true.\n */\n includeLogs?: boolean;\n}\n\n/**\n * In-memory publisher: reduces events over a snapshot and tracks a monotonic\n * version. Base class for publishers with an output surface (file, HTTP).\n */\nexport class MemoryPublisher implements SessionPublisher {\n protected state: SessionSnapshot = createInitialSnapshot();\n protected versionCounter = 0;\n private warned = false;\n private readonly onWarn: (message: string) => void;\n private readonly reducerOptions: SessionReducerOptions;\n private readonly includeLogs: boolean;\n\n constructor(options: MemoryPublisherOptions = {}) {\n this.onWarn = options.onWarn ?? ((message) => process.stderr.write(`${message}\\n`));\n this.reducerOptions = { logLimit: options.logLimit };\n this.includeLogs = options.includeLogs ?? true;\n }\n\n publish(event: SessionEvent): void {\n if (event.type === 'log' && !this.includeLogs) return;\n try {\n this.state = reduceSessionEvent(this.state, event, this.reducerOptions);\n this.versionCounter++;\n this.afterPublish(event);\n } catch (err) {\n this.warnOnce(err);\n }\n }\n\n /** Hook for subclasses; runs inside publish()'s try/catch. */\n protected afterPublish(_event: SessionEvent): void {}\n\n snapshot(): SessionSnapshot {\n return this.state;\n }\n\n version(): number {\n return this.versionCounter;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n\n protected warnOnce(err: unknown): void {\n if (this.warned) return;\n this.warned = true;\n const message = err instanceof Error ? err.message : String(err);\n try {\n this.onWarn(\n `issue-flow: web monitoring hit an error (will keep retrying silently): ${message}`,\n );\n } catch {\n // Even a failing warn callback must not propagate to the pipeline.\n }\n }\n}\n\nexport interface FilePublisherOptions extends MemoryPublisherOptions {\n /** Minimum interval between disk writes (ms). Default 1000. */\n throttleMs?: number;\n /** Interval between mtime-only heartbeats (ms). Zero disables it. Default 10000. */\n heartbeatMs?: number;\n}\n\n/**\n * Publisher that mirrors the snapshot to issues/N/session.json.\n *\n * Writes are atomic (write-to-temp + rename) and throttled; terminal events\n * (phase:end, session:end) force an immediate write. All I/O failures are\n * swallowed after a single warning.\n */\nexport class FilePublisher extends MemoryPublisher {\n private readonly filePath: string;\n private readonly throttleMs: number;\n private timer: NodeJS.Timeout | null = null;\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private lastWriteStartedAt = 0;\n private lastWrittenVersion = 0;\n private writeChain: Promise<void> = Promise.resolve();\n private closed = false;\n\n constructor(filePath: string, options: FilePublisherOptions = {}) {\n super(options);\n this.filePath = filePath;\n this.throttleMs = options.throttleMs ?? DEFAULT_THROTTLE_MS;\n const heartbeatMs = options.heartbeatMs ?? DEFAULT_SESSION_HEARTBEAT_MS;\n if (heartbeatMs > 0) {\n this.heartbeatTimer = setInterval(() => this.enqueueHeartbeat(), heartbeatMs);\n this.heartbeatTimer.unref();\n }\n }\n\n protected override afterPublish(event: SessionEvent): void {\n if (this.closed) return;\n const terminal =\n event.type === 'phase:end' || event.type === 'session:end' || event.type === 'verify:end';\n this.scheduleWrite(terminal);\n }\n\n private scheduleWrite(force: boolean): void {\n if (force) {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n this.enqueueWrite();\n return;\n }\n if (this.timer !== null) return;\n const wait = Math.max(0, this.throttleMs - (Date.now() - this.lastWriteStartedAt));\n if (wait === 0) {\n this.enqueueWrite();\n return;\n }\n this.timer = setTimeout(() => {\n this.timer = null;\n this.enqueueWrite();\n }, wait);\n this.timer.unref();\n }\n\n private enqueueWrite(): void {\n this.lastWriteStartedAt = Date.now();\n this.writeChain = this.writeChain.then(async () => {\n const version = this.versionCounter;\n if (version === this.lastWrittenVersion) return;\n const payload = `${JSON.stringify(this.state, null, 2)}\\n`;\n try {\n await atomicWriteFile(this.filePath, payload);\n this.lastWrittenVersion = version;\n } catch (err) {\n this.warnOnce(err);\n }\n });\n }\n\n /**\n * Keep directory-based discovery alive without changing snapshot content or\n * its content-derived ETag. The write chain serializes the touch with atomic\n * snapshot replacement, and no heartbeat is attempted before the first file\n * has been written successfully.\n */\n private enqueueHeartbeat(): void {\n if (this.closed) return;\n this.writeChain = this.writeChain.then(async () => {\n if (this.closed || this.lastWrittenVersion === 0) return;\n const now = new Date();\n try {\n await utimes(this.filePath, now, now);\n } catch (err) {\n this.warnOnce(err);\n }\n });\n }\n\n override async flush(): Promise<void> {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.versionCounter !== this.lastWrittenVersion) {\n this.enqueueWrite();\n }\n await this.writeChain;\n }\n\n override async close(): Promise<void> {\n if (this.heartbeatTimer !== null) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n this.closed = true;\n await this.flush();\n }\n}\n\n/**\n * Atomic write: write to a temp file next to the target, then rename. The\n * same-directory temp keeps the rename on a single filesystem (rename is\n * atomic; no EXDEV fallback needed, unlike an os.tmpdir() temp on Linux\n * tmpfs) and leaves nothing behind. The FilePublisher write chain is the\n * single writer, so the fixed .tmp name never races.\n *\n * The target directory (issues/N/) may not exist yet the first time a fresh\n * issue publishes — pipeline phases create it lazily, and this can be the\n * very first write. mkdir recursive is idempotent, so it's cheap to ensure\n * on every write rather than relying on call order elsewhere.\n */\nasync function atomicWriteFile(path: string, content: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpFile = `${path}.tmp`;\n await writeFile(tmpFile, content, 'utf-8');\n await rename(tmpFile, path);\n}\n","import { NullPublisher, type SessionPublisher } from './session-state.js';\n\n/**\n * Global slot for the active SessionPublisher, following the same pattern as\n * setVerbose in verbose.ts. Instrumentation points (logger, engine, headless)\n * read the slot via getSessionPublisher(); run.ts installs a MemoryPublisher\n * for every run and a FilePublisher on top when web monitoring is enabled.\n * The default NullPublisher makes every instrumentation point a no-op\n * before a run (or a standalone command) installs a publisher.\n */\n\nconst NULL_PUBLISHER = new NullPublisher();\n\nlet _publisher: SessionPublisher = NULL_PUBLISHER;\n\n/**\n * Install the active session publisher. Pass undefined to reset to the\n * default NullPublisher.\n */\nexport function setSessionPublisher(publisher: SessionPublisher | undefined): void {\n _publisher = publisher ?? NULL_PUBLISHER;\n}\n\nexport function getSessionPublisher(): SessionPublisher {\n return _publisher;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/execute.ts","../src/core/engine.ts","../src/ui/progress.ts","../src/ui/summary.ts","../src/ui/text.ts","../src/core/executor.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { createConfig, loadWebConfig, resolvePaths, validateDependencies } from '../config.js';\nimport { runEngine } from '../core/engine.js';\nimport { getSessionPublisher, setSessionPublisher } from '../core/session-publisher.js';\nimport { FilePublisher, NullPublisher } from '../core/session-state.js';\nimport { allStoriesPass, isoNow, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { resolveIssuePaths } from '../storage/resolve.js';\nimport { printError } from '../ui/logger.js';\nimport { ensureWebMonitor } from '../web/lock.js';\n\nexport interface ExecuteOptions {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n /**\n * Conventional-commit scope for the stories of this issue (`issue-71`).\n * Only the multi-issue queue sets it — see `EngineConfig.commitScope`.\n */\n commitScope?: string;\n}\n\nexport async function runExecute(\n positionalMaxIter: number | undefined,\n options: ExecuteOptions,\n): Promise<number> {\n const errors = await validateDependencies();\n if (errors.length > 0) {\n printError('The following required tools are not installed:');\n for (const err of errors) {\n console.log(err);\n }\n return 1;\n }\n\n const maxIterations = options.maxIterations ?? positionalMaxIter;\n\n const config = createConfig({\n issueNumber: options.issue,\n maxIterations,\n retryLimit: options.retryLimit,\n retryForever: options.retryForever,\n commitScope: options.commitScope,\n });\n\n const paths = await resolvePaths(config);\n const webConfig = await loadWebConfig();\n const inheritedPublisher = getSessionPublisher();\n let standalonePublisher: FilePublisher | null = null;\n\n // `run` owns the publisher when it delegates to this command. A direct\n // `execute --issue N --web` has no owner, so install the same file-backed\n // surface here and tear down only what this invocation created.\n if (\n webConfig.enabled &&\n config.issueNumber !== undefined &&\n inheritedPublisher instanceof NullPublisher\n ) {\n const issuePaths = await resolveIssuePaths(config.issueNumber, {\n projectRoot: paths.projectRoot,\n });\n standalonePublisher = new FilePublisher(issuePaths.sessionFile, {\n logLimit: webConfig.logLimit,\n includeLogs: webConfig.includeLogs,\n });\n setSessionPublisher(standalonePublisher);\n const numericIssue = /^\\d+$/.test(config.issueNumber) ? Number(config.issueNumber) : null;\n standalonePublisher.publish({\n type: 'session:start',\n at: isoNow(),\n sessionId: randomUUID(),\n issueNumber: numericIssue,\n phases: ['execute'],\n });\n standalonePublisher.publish({ type: 'phase:start', at: isoNow(), phase: 'execute' });\n await ensureWebMonitor({\n publisher: standalonePublisher,\n port: webConfig.port,\n host: webConfig.host,\n refreshSeconds: webConfig.refreshSeconds,\n });\n }\n\n let exitCode: number | null = null;\n try {\n exitCode = await runEngine(config, paths);\n\n // Update pipeline state if all stories pass\n if (exitCode === 0 && config.issueNumber) {\n try {\n const plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan.pipeline.executionCompleted = true;\n await saveTaskPlan(paths.prdFile, plan);\n }\n } catch {\n // Non-critical — engine already handled state\n }\n }\n\n return exitCode;\n } finally {\n if (standalonePublisher !== null) {\n const success = exitCode === 0;\n standalonePublisher.publish({\n type: 'phase:end',\n at: isoNow(),\n phase: 'execute',\n success,\n ...(success ? {} : { error: 'Execute phase failed' }),\n });\n standalonePublisher.publish({\n type: 'session:end',\n at: isoNow(),\n status: success ? 'completed' : 'failed',\n });\n await standalonePublisher.close();\n setSessionPublisher(undefined);\n }\n }\n}\n","import { existsSync } from 'node:fs';\nimport { cp, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { resolveAgentFor } from '../agents/resolve.js';\nimport { getActiveResilienceConfig, loadGlobalConfig } from '../config.js';\nimport { archiveFolderName, type ChangeType, commitMessage } from '../conventions/git/index.js';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { classify } from '../resilience/errors.js';\nimport type { RetryPolicy } from '../resilience/policy.js';\nimport { resolvePolicy } from '../resilience/policy.js';\nimport { fixedBackoffPolicy, withRetry } from '../resilience/retry.js';\nimport type { ClaudeResult, EngineConfig, ResolvedPaths, TaskPlan, UserStory } from '../types.js';\nimport { printError, printInfo, printRetry, printSuccess, printWarning } from '../ui/logger.js';\nimport { printIterationHeader } from '../ui/progress.js';\nimport { printStartupHeader, printSummaryBox } from '../ui/summary.js';\nimport { committedStoryIds, getBaseBranch, isWorkingTreeClean } from '../utils/git.js';\nimport { applyAcceptanceToPlan, resolveIssueDir, runAcceptanceGate } from '../verify/gate.js';\nimport { executeClaude } from './executor.js';\nimport { divideUsage } from './metrics.js';\nimport { applyPlaceholders, loadPrompt } from './prompt-resolver.js';\nimport {\n EXECUTE_PHASE,\n elapsedSecondsSince,\n getPhaseUsageTotals,\n publishIterationMetrics,\n publishStoryMetrics,\n} from './session-metrics.js';\nimport { getSessionPublisher } from './session-publisher.js';\nimport { getShutdownSignal } from './shutdown.js';\nimport {\n allStoriesPass,\n applyStoryMetrics,\n clearLastError,\n hasPendingCorrection,\n initializeState,\n isoNow,\n loadTaskPlan,\n markIssueCompleted,\n markIssueInProgress,\n saveTaskPlan,\n selectActiveStory,\n setLastError,\n trimErrorMessage,\n} from './state-manager.js';\nimport {\n getInactivityTimeout,\n getOutputCallback,\n getStoryStageCallback,\n getStoryUpdateCallback,\n isVerbose,\n} from './verbose.js';\n\n/**\n * Emit a message through the output callback if available, otherwise console.log.\n * Used for bare console.log calls in engine functions so they route through listr2.\n */\nfunction emitLog(message: string): void {\n const cb = getOutputCallback();\n if (cb) {\n // Skip empty lines in listr2 context — they don't render meaningfully\n if (message) {\n cb(message);\n }\n } else {\n console.log(message);\n }\n}\n\n/** What one pass of the execute loop produces, retry or not. */\ninterface ExecuteAttempt {\n result: ClaudeResult;\n /** When the attempt started, for `clearLastError`. */\n startedAt: string;\n /** How long the attempt took, for the metrics split across stories. */\n seconds: number;\n /** The stories as they were before the agent ran, for attribution. */\n storiesBefore: UserStory[];\n}\n\n/**\n * The execute loop's retry budget, unchanged in effect from the hand-rolled\n * loop it replaces: `retryLimit` counts *retries*, so the attempt budget is one\n * more than it, and `retryForever` lifts the count while `backoffMaxSeconds`\n * still caps the wait.\n */\nfunction executeRetryPolicy(config: EngineConfig): RetryPolicy {\n return fixedBackoffPolicy(\n config.retryLimit + 1,\n config.backoffBaseSeconds,\n config.backoffMaxSeconds,\n { retryForever: config.retryForever },\n );\n}\n\n/**\n * Ids of the stories that flipped from `passes: false` to `passes: true`\n * between the two readings of the plan taken around one execute iteration.\n *\n * Stories already passing before the iteration, and stories that only exist in\n * the newer plan, are never attributed: nothing says this iteration paid for\n * them.\n */\nfunction newlyCompletedStoryIds(before: UserStory[], after: UserStory[]): string[] {\n const wasPassing = new Map(before.map((story) => [story.id, story.passes]));\n return after\n .filter((story) => story.passes && wasPassing.get(story.id) === false)\n .map((story) => story.id);\n}\n\nexport interface CommitPlaceholderOptions {\n issueNumber?: string | number | null;\n signoff?: boolean;\n type?: ChangeType;\n}\n\nfunction numericIssue(value: string | number | null | undefined): number | undefined {\n if (value === undefined || value === null || value === '') return undefined;\n const parsed = typeof value === 'number' ? value : Number(value);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/**\n * Commit message formats handed to the execute prompt.\n *\n * Built by `commitMessage()` so Conventional Commits is the default even when\n * the repository declared nothing. A scope is the issue id of a queue, which\n * is what makes `git log` on the shared branch readable per issue.\n */\nexport function commitPlaceholders(\n scope?: string,\n convention?: string | null,\n options?: CommitPlaceholderOptions,\n): Record<string, string> {\n const declared = convention !== undefined && convention !== null && convention !== '';\n const type = options?.type ?? 'feat';\n const issueNumber = numericIssue(options?.issueNumber);\n const resolvedScope = scope === undefined || scope === '' ? undefined : scope;\n\n if (declared && options?.type === undefined) {\n const suffix = resolvedScope === undefined ? '' : `(${resolvedScope})`;\n return {\n __COMMIT_MESSAGE__: commitMessage({\n type,\n scope: resolvedScope,\n subject: '[Story ID] - [Story Title]',\n issueNumber,\n signoff: options?.signoff,\n }).replace(`${type}${suffix}:`, `<type>${suffix}:`),\n __FIX_COMMIT_MESSAGE__: commitMessage({\n type: 'fix',\n scope: resolvedScope,\n subject: 'address review findings',\n issueNumber,\n signoff: options?.signoff,\n }),\n };\n }\n\n return {\n __COMMIT_MESSAGE__: commitMessage({\n type,\n scope: resolvedScope,\n subject: '[Story ID] - [Story Title]',\n issueNumber,\n signoff: options?.signoff,\n }),\n __FIX_COMMIT_MESSAGE__: commitMessage({\n type: 'fix',\n scope: resolvedScope,\n subject: 'address review findings',\n issueNumber,\n signoff: options?.signoff,\n }),\n };\n}\n\n/**\n * The watchdog budget of one iteration, from the process-wide setting.\n *\n * Absent means the default; `0` turns the watchdog off. Reading it here rather\n * than threading it through the engine's config keeps it a single value per\n * process, which is what it is.\n */\nfunction inactivityOptions(): { inactivityTimeoutMs?: number } {\n const configured = getInactivityTimeout();\n return configured === undefined ? {} : { inactivityTimeoutMs: configured };\n}\n\n/**\n * Mark as passing every pending story whose commit is already on the branch.\n *\n * Two conditions, and both are required:\n *\n * - the story's id appears in a commit subject of this branch, which is what\n * the execute prompt writes (`<type>(scope): US-001 - Title`);\n * - the working tree is **clean**, so nothing is half-applied. A dirty tree\n * means work in flight, and adopting a story on that basis would call\n * finished something that is not.\n *\n * Returns the ids it adopted. Never throws: a git that cannot answer, or a plan\n * that cannot be written, leaves the loop doing exactly what it did before.\n */\nasync function adoptCommittedStories(tasksPath: string): Promise<string[]> {\n try {\n const plan = await loadTaskPlan(tasksPath);\n const pending = plan.userStories.filter((story) => !story.passes);\n if (pending.length === 0) return [];\n\n if (!(await isWorkingTreeClean())) return [];\n\n const committed = await committedStoryIds(await getBaseBranch());\n const adopted = pending.filter((story) => committed.has(story.id)).map((story) => story.id);\n if (adopted.length === 0) return [];\n\n await saveTaskPlan(tasksPath, {\n ...plan,\n userStories: plan.userStories.map((story) =>\n adopted.includes(story.id) ? { ...story, passes: true } : story,\n ),\n });\n return adopted;\n } catch {\n return [];\n }\n}\n\n/**\n * Initialize the progress file if it doesn't exist.\n */\nasync function ensureProgressFile(progressFile: string): Promise<void> {\n if (!existsSync(progressFile)) {\n const content = `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`;\n await writeFile(progressFile, content, 'utf-8');\n }\n}\n\n/**\n * Archive previous run artifacts if the branch has changed.\n */\nasync function archiveIfBranchChanged(plan: TaskPlan, paths: ResolvedPaths): Promise<void> {\n const { lastBranchFile, archiveDir, prdFile, progressFile } = paths;\n\n if (!existsSync(lastBranchFile)) {\n return;\n }\n\n const currentBranch = plan.branchName ?? '';\n let lastBranch = '';\n\n try {\n lastBranch = (await readFile(lastBranchFile, 'utf-8')).trim();\n } catch {\n return;\n }\n\n if (currentBranch && lastBranch && currentBranch !== lastBranch) {\n const dateStr = new Date().toISOString().split('T')[0];\n const folderName = archiveFolderName(lastBranch);\n const archiveFolder = join(archiveDir, `${dateStr}-${folderName}`);\n\n printInfo(`Archiving previous run: ${lastBranch}`);\n await mkdir(archiveFolder, { recursive: true });\n\n if (existsSync(prdFile)) {\n await cp(prdFile, join(archiveFolder, 'tasks.json'));\n }\n if (existsSync(progressFile)) {\n await cp(progressFile, join(archiveFolder, 'progress.txt'));\n }\n\n printInfo(` Archived to: ${archiveFolder}`);\n\n // Reset progress file for new run\n await writeFile(\n progressFile,\n `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`,\n 'utf-8',\n );\n }\n}\n\n/**\n * Write the current branch to the last-branch tracking file.\n */\nasync function trackBranch(plan: TaskPlan, lastBranchFile: string): Promise<void> {\n const branch = plan.branchName ?? '';\n if (branch) {\n await writeFile(lastBranchFile, `${branch}\\n`, 'utf-8');\n }\n}\n\n/**\n * Run the issue-flow engine loop.\n *\n * This replicates the full execution flow:\n * 1. Load and initialize task plan state\n * 2. Check for early exit (already complete)\n * 3. Archive previous run if branch changed\n * 4. Resolve prompt\n * 5. Main loop: iterate, execute Claude, handle results\n * 6. Print summary\n */\nexport async function runEngine(config: EngineConfig, paths: ResolvedPaths): Promise<number> {\n // Load task plan\n if (!existsSync(paths.prdFile)) {\n printError(`PRD file not found at ${paths.prdFile}`);\n if (config.issueNumber) {\n emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);\n }\n return 1;\n }\n\n let plan = await loadTaskPlan(paths.prdFile);\n plan = initializeState(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Check if already completed. A pending correction (a failed review whose\n // findings haven't been addressed yet) always overrides this, even though\n // every userStories[].passes is already true — otherwise a correction\n // cycle's re-run of execute would exit here without ever looking at what\n // the review found.\n if (plan.issueStatus === 'completed' && allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog(`Issue already marked complete in ${paths.prdFile}`);\n return 0;\n }\n\n // Warn if marked complete but stories still pending\n if (plan.issueStatus === 'completed' && !allStoriesPass(plan)) {\n printWarning(\n 'Issue marked completed but some stories are still pending. Resetting to in_progress.',\n );\n plan = markIssueInProgress(plan);\n plan = setLastError(\n plan,\n 'invalid_completion_state',\n 'tasks.json claimed the issue was completed before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n }\n\n // Check if all stories already pass\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog('All user stories already pass. Marking issue as completed.');\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n return finishWithAcceptance(config, paths, plan);\n }\n\n // Archive previous run if branch changed\n await archiveIfBranchChanged(plan, paths);\n\n // Track current branch\n await trackBranch(plan, paths.lastBranchFile);\n\n // Initialize progress file\n await ensureProgressFile(paths.progressFile);\n\n // Load prompt template. The root is handed over rather than rediscovered:\n // it was resolved once by `resolvePaths()`, and a second `git rev-parse` here\n // would be a subprocess per run for an answer already in hand.\n const promptTemplate = await loadPrompt('execute', { projectRoot: paths.projectRoot });\n\n // The repository's own conventions, resolved once for the whole loop: they\n // cannot change mid-run, and every iteration renders the same projection.\n const policy = await resolvePolicyPlaceholders({ root: paths.projectRoot });\n const signoff = (await loadGlobalConfig()).commit?.signoff === true;\n\n const executeAgent = await resolveAgentFor('execute');\n printStartupHeader(config, plan, {\n provider: executeAgent.provider,\n model: executeAgent.model,\n ...(executeAgent.codex.reasoningEffort ? { detail: executeAgent.codex.reasoningEffort } : {}),\n });\n\n const startTime = Date.now();\n let i = 0;\n let totalRetryCount = 0;\n\n // Main loop\n while (true) {\n // Check iteration limit\n if (config.maxIterations !== undefined && i >= config.maxIterations) {\n break;\n }\n\n i++;\n\n // Safety net for the crash between a story's commit and the agent writing\n // `passes: true` (scenario I). The commit is the durable fact; the plan is\n // written after it, so a process that died in between leaves work that is\n // done and a plan that says it is not — and the next iteration redoes it on\n // top of a commit that already exists.\n //\n // This never *replaces* the agent's `passes`, which stays the primary\n // source: it only closes the window the agent cannot close itself.\n const adopted = await adoptCommittedStories(paths.prdFile);\n if (adopted.length > 0) {\n printInfo(\n `Adopting ${adopted.join(', ')}: already committed on this branch with a clean tree.`,\n );\n plan = await loadTaskPlan(paths.prdFile);\n if (plan.userStories.every((story) => story.passes) && plan.lastReviewFindings === null) {\n // Everything the loop was going to do is already done.\n break;\n }\n }\n\n // One iteration is one attempt of the Claude CLI, retried in place by the\n // project's single retry executor (`resilience/retry.ts`). A retry costs no\n // iteration budget, exactly as the `i--` it replaces cost none. Everything a\n // retried attempt has to redo — re-reading the plan, republishing\n // `iteration:start`, re-rendering the prompt — lives inside `attempt`,\n // because the loop this used to be written as re-ran all of it too.\n const attempted = await withRetry<ExecuteAttempt>(\n async () => {\n // Re-read plan to get latest state\n plan = await loadTaskPlan(paths.prdFile);\n // Publish the plan before naming its active story. This covers direct\n // `issue-flow execute` runs and resumes that never pass through the\n // plan runner, while retaining the empty-plan no-op contract.\n if (plan.userStories.length > 0) {\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n }\n // Baseline for story attribution: whatever was still pending before the\n // agent ran is what this iteration can claim credit for.\n const storiesBefore = plan.userStories;\n\n // Highest-priority story with passes: false — the same rule\n // prompts/execute.md gives the agent. Computed once, here, and shared by\n // the published event and the verbose terminal header, so every surface\n // agrees on who is active instead of each deriving its own heuristic.\n const activeStoryId = selectActiveStory(plan.userStories)?.id;\n getSessionPublisher().publish({\n type: 'iteration:start',\n at: isoNow(),\n iteration: i,\n storyId: activeStoryId,\n });\n getStoryStageCallback()?.(activeStoryId);\n\n if (isVerbose()) {\n printIterationHeader(i, config.maxIterations, plan.userStories, activeStoryId);\n }\n\n // Apply placeholders to prompt\n const prompt = applyPlaceholders(promptTemplate, {\n __PRD_FILE__: paths.prdFile,\n __PROGRESS_FILE__: paths.progressFile,\n ...policy,\n // The convention comes off the projection above rather than from a second\n // discovery: one resolution per run is the whole point of the cache.\n ...commitPlaceholders(config.commitScope, policy.__COMMIT_CONVENTION__, {\n issueNumber: plan.issueNumber,\n signoff,\n }),\n __STORIES_PER_ITERATION__: String(config.storiesPerIteration ?? 1),\n });\n\n const startedAt = isoNow();\n plan = markIssueInProgress(plan, startedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Execute Claude\n const startedAtMs = Date.now();\n const result = await executeClaude(prompt, {\n ...inactivityOptions(),\n iteration: i,\n correctionCycle: plan.correctionCycle,\n ...(activeStoryId === undefined ? {} : { storyIds: [activeStoryId] }),\n });\n const seconds = elapsedSecondsSince(startedAtMs);\n\n if (result.exitCode !== 0) {\n // A failed iteration still burned tokens: report them on the execute\n // phase, with no attribution to any story.\n publishIterationMetrics(i, result.cost, seconds);\n }\n\n return { result, startedAt, seconds, storiesBefore };\n },\n {\n policy: executeRetryPolicy(config),\n // A `Ctrl+C` during a fifteen-minute backoff must stop in that instant,\n // not fifteen minutes later. `abortableDelay` resolves `false` on the\n // abort, which `withRetry` reports as `aborted` rather than a failure.\n signal: getShutdownSignal(),\n // The exit code and the output are all the evidence the CLI leaves\n // behind, which is exactly what `isTransientFailure()` used to be given\n // here — `classify()` is the same verdict plus the kind.\n evaluate: ({ result }) =>\n result.exitCode === 0\n ? null\n : classify({ source: 'agent', exitCode: result.exitCode, stdout: result.output }),\n onAttempt: async ({ value, attempt, failure, willRetry, delayMs }) => {\n if (failure === null) return;\n\n const errorMessage = trimErrorMessage(value.result.output);\n\n if (!failure.retryable) {\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'fatal_claude_failure', errorMessage);\n if (resolvePolicy(failure.kind, getActiveResilienceConfig()).onExhausted === 'block') {\n plan = {\n ...plan,\n runState: {\n currentPhase: 'execute',\n attempt,\n owner: plan.runState?.owner ?? null,\n status: 'blocked',\n blockedReason: errorMessage,\n lastHeartbeatAt: isoNow(),\n },\n };\n }\n await saveTaskPlan(paths.prdFile, plan);\n return;\n }\n\n // Recorded even on the attempt that spends the last of the budget:\n // the run ends on a transient failure, and the plan has to say so.\n totalRetryCount++;\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'transient_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n if (!willRetry) return;\n\n const delaySeconds = delayMs / 1000;\n getSessionPublisher().publish({\n type: 'retry',\n at: isoNow(),\n attempt,\n delaySeconds,\n reason: 'transient_claude_failure',\n kind: failure.kind,\n });\n\n if (isVerbose()) {\n emitLog('');\n }\n printRetry(\n `Transient Claude failure on iteration ${i} (attempt ${attempt}). Retrying in ${delaySeconds}s.`,\n );\n },\n },\n );\n\n const {\n result,\n seconds: iterationSeconds,\n storiesBefore: storiesBeforeIteration,\n } = attempted.value;\n const iterationStartedAt = attempted.value.startedAt;\n\n if (result.exitCode !== 0) {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n attempted.exhausted\n ? `Exceeded retry limit (${config.retryLimit}) on transient errors`\n : `Claude CLI failed with exit code ${result.exitCode}`,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return result.exitCode;\n }\n\n plan = await loadTaskPlan(paths.prdFile);\n plan = clearLastError(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Notify story progress listeners (e.g., listr2 subtasks)\n const storyUpdateCb = getStoryUpdateCallback();\n if (storyUpdateCb) {\n storyUpdateCb(plan.userStories);\n }\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n\n // Story attribution — an approximation by construction: the CLI reports a\n // single usage for the whole iteration, so the stories that flipped to\n // passing in it split tokens, cost and duration evenly. With none, nothing\n // is attributed and the whole cost stays on the execute phase. Published\n // after stories:update, which rebuilds the stories array.\n const completedStoryIds = newlyCompletedStoryIds(storiesBeforeIteration, plan.userStories);\n if (completedStoryIds.length > 0) {\n const storyShare = divideUsage(result.cost, completedStoryIds.length);\n const storySeconds = Math.round(iterationSeconds / completedStoryIds.length);\n for (const storyId of completedStoryIds) {\n publishStoryMetrics(storyId, storyShare, storySeconds);\n }\n\n // The same shares also land on tasks.json, so the numbers outlive the\n // session and are readable with web monitoring off. Persisting them is\n // observational: a write failure must never change the iteration's\n // outcome, so the plan in memory only advances when the write succeeded.\n const planWithMetrics = applyStoryMetrics(plan, completedStoryIds, storyShare, storySeconds);\n try {\n await saveTaskPlan(paths.prdFile, planWithMetrics);\n plan = planWithMetrics;\n } catch {\n // Metrics are a nice-to-have; the iteration succeeded regardless.\n }\n }\n\n getSessionPublisher().publish({ type: 'iteration:end', at: isoNow(), iteration: i });\n publishIterationMetrics(i, result.cost, iterationSeconds);\n\n // Check for completion signal\n if (result.output.includes('<promise>COMPLETE</promise>')) {\n plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox(\n 'success',\n i,\n totalRetryCount,\n elapsed,\n plan,\n undefined,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return finishWithAcceptance(config, paths, plan);\n }\n\n plan = setLastError(\n plan,\n 'invalid_completion_signal',\n hasPendingCorrection(plan)\n ? 'Claude returned <promise>COMPLETE</promise> while lastReviewFindings was still set.'\n : 'Claude returned <promise>COMPLETE</promise> before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n\n emitLog('');\n printWarning(\n hasPendingCorrection(plan)\n ? 'Claude returned a completion signal, but lastReviewFindings is still set. Ignoring completion and continuing.'\n : 'Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing.',\n );\n }\n\n if (isVerbose()) {\n printSuccess(`Iteration ${i} complete. Continuing...`);\n }\n }\n\n // Reached max iterations\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'incomplete',\n config.maxIterations ?? i,\n totalRetryCount,\n elapsed,\n plan,\n 'Reached max iterations without completing all tasks.',\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return 1;\n}\n\nasync function finishWithAcceptance(\n config: EngineConfig,\n paths: ResolvedPaths,\n plan: TaskPlan,\n): Promise<number> {\n const issueDir = resolveIssueDir(config, paths);\n const outcome = await runAcceptanceGate({\n issueDir,\n cwd: paths.projectRoot,\n addDirs: config.issueNumber === undefined ? undefined : [issueDir],\n skipReviewer: true,\n });\n const applied = applyAcceptanceToPlan(plan, outcome);\n if (applied.failed) {\n await saveTaskPlan(paths.prdFile, applied.plan);\n return 1;\n }\n return 0;\n}\n","import chalk from 'chalk';\nimport { getOutputCallback } from '../core/verbose.js';\nimport type { UserStory } from '../types.js';\nimport { getIcons, useColor, useUnicode } from './logger.js';\n\n/**\n * Print a visual progress bar showing passed/total stories.\n */\nexport function printProgressBar(passed: number, total: number): string {\n const barWidth = 20;\n let pct = 0;\n let filled = 0;\n\n if (total > 0) {\n pct = Math.floor((passed * 100) / total);\n filled = Math.floor((passed * barWidth) / total);\n }\n\n const empty = barWidth - filled;\n const fillChar = useUnicode() ? '\\u2588' : '#';\n const emptyChar = useUnicode() ? '\\u2591' : '-';\n\n const bar = fillChar.repeat(filled) + emptyChar.repeat(empty);\n const text = `${passed}/${total} (${pct}%)`;\n\n if (useColor()) {\n return `${chalk.green(bar)} ${text}`;\n }\n return `${bar} ${text}`;\n}\n\n/**\n * Print the iteration header showing story statuses and progress bar.\n *\n * When a global output callback is set (e.g., inside a listr2 task),\n * output is routed through it instead of console.log.\n *\n * `activeStoryId`, when provided, identifies the story the engine is\n * actually about to work on this iteration (the same id published on\n * `iteration:start` \\u2014 see `core/state-manager.ts`'s `selectActiveStory`),\n * so the header agrees with the session snapshot instead of guessing.\n * Omitted, it falls back to the previous heuristic (\"first non-passing story\n * in array order\"), which existing callers that cannot supply the real id\n * keep relying on.\n */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n activeStoryId?: string,\n): void {\n const icons = getIcons();\n const colored = useColor();\n const cb = getOutputCallback();\n\n const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;\n\n const total = stories.length;\n const passed = stories.filter((s) => s.passes).length;\n\n const lines: string[] = [];\n\n if (colored) {\n lines.push(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n lines.push(`--- ${icons.start} ${iterLabel} ---`);\n }\n\n // Display each story status\n let foundFirstPending = false;\n for (const story of stories) {\n let icon: string;\n let colorFn: (s: string) => string;\n const isActive =\n activeStoryId !== undefined\n ? story.id === activeStoryId\n : !story.passes && !foundFirstPending;\n\n if (story.passes) {\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n } else if (isActive) {\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n foundFirstPending = true;\n } else {\n // Not yet reached\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n }\n\n lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n lines.push(` ${printProgressBar(passed, total)}`);\n\n if (cb) {\n // Send as single output to listr2 task context\n cb(lines.join('\\n'));\n } else {\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n console.log('');\n }\n}\n","import chalk from 'chalk';\nimport { type ClaudeUsage, formatTokens } from '../core/metrics.js';\nimport { groupBy, summarize } from '../telemetry/aggregate.js';\nimport type { EngineConfig, PrReviewRecommendation, TaskPlan } from '../types.js';\nimport {\n formatDuration,\n getIcons,\n getTermWidth,\n printSuccess,\n printWarning,\n useColor,\n useUnicode,\n} from './logger.js';\n\n/**\n * Truncate or pad a string to fit within a given width.\n */\nfunction fitLine(text: string, width: number): string {\n if (text.length > width) {\n return text.substring(0, width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Print a box with border characters around content lines.\n * Lines equal to \"---\" render as separator rows.\n */\nexport function printBox(lines: string[]): void {\n const colored = useColor();\n const unicode = useUnicode();\n const termWidth = getTermWidth();\n\n // Find max content width\n let maxContentWidth = 0;\n for (const line of lines) {\n if (line !== '---' && line.length > maxContentWidth) {\n maxContentWidth = line.length;\n }\n }\n\n // Cap to terminal width (border + padding = 4 chars)\n const available = termWidth - 4;\n if (maxContentWidth > available) {\n maxContentWidth = available;\n }\n if (maxContentWidth < 20) {\n maxContentWidth = 20;\n }\n\n // Box drawing characters\n const tl = unicode ? '\\u256D' : '+';\n const tr = unicode ? '\\u256E' : '+';\n const bl = unicode ? '\\u2570' : '+';\n const br = unicode ? '\\u256F' : '+';\n const h = unicode ? '\\u2500' : '-';\n const v = unicode ? '\\u2502' : '|';\n const sepL = unicode ? '\\u251C' : '+';\n const sepR = unicode ? '\\u2524' : '+';\n\n const hrule = h.repeat(maxContentWidth + 2);\n\n const blue = colored ? chalk.blue : (s: string) => s;\n const _reset = (s: string) => s;\n\n // Top border\n console.log(blue(`${tl}${hrule}${tr}`));\n\n // Content lines\n for (const line of lines) {\n if (line === '---') {\n console.log(blue(`${sepL}${hrule}${sepR}`));\n } else {\n const fitted = fitLine(line, maxContentWidth);\n console.log(`${blue(v)} ${fitted} ${blue(v)}`);\n }\n }\n\n // Bottom border\n console.log(blue(`${bl}${hrule}${br}`));\n}\n\n/**\n * Print the startup header box showing engine configuration.\n */\nexport interface StartupAgentInfo {\n provider: string;\n model?: string | null;\n detail?: string;\n}\n\nexport function printStartupHeader(\n config: EngineConfig,\n plan: TaskPlan,\n agent?: StartupAgentInfo,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const branchName = plan.branchName ?? 'N/A';\n\n const issueLabel = config.issueNumber ? `Issue #${config.issueNumber}` : 'Standalone mode';\n\n const maxIterLabel =\n config.maxIterations !== undefined ? String(config.maxIterations) : 'unlimited';\n\n const retryLabel = config.retryForever\n ? 'unlimited retries'\n : `${config.retryLimit} consecutive retries`;\n\n const lines = [\n `${icons.start} Issue Flow`,\n '---',\n `Issue: ${issueLabel}`,\n `Branch: ${branchName}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${maxIterLabel}`,\n `Retries: ${retryLabel}`,\n ];\n const remaining = storiesTotal - storiesPassing;\n if (remaining > 0) {\n // p50 of execute on the #79 baseline (US-009/US-010 mean, single observation).\n const p50ExecuteSeconds = 518;\n lines.push(\n `Estimate: ~${formatDuration(remaining * p50ExecuteSeconds)} (${remaining} × p50 execute)`,\n );\n }\n if (agent) {\n const model = agent.model ? ` · ${agent.model}` : '';\n const detail = agent.detail ? ` (${agent.detail})` : '';\n lines.push(`Agent: ${agent.provider}${model}${detail}`);\n }\n printBox(lines);\n}\n\n/**\n * Print the final summary box.\n */\nexport function printSummaryBox(\n status: 'success' | 'incomplete' | 'failed',\n iterations: number,\n totalRetries: number,\n elapsedSeconds: number,\n plan: TaskPlan,\n extraInfo?: string,\n /**\n * Tokens and cost spent by this run, already resolved by the caller (the\n * process-owned counters in `core/session-metrics.ts`, never the session\n * snapshot — that one is empty whenever web monitoring is off). Omitted or\n * empty means \"the CLI reported nothing\", and the line is skipped entirely.\n */\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const duration = formatDuration(elapsedSeconds);\n\n let statusIcon: string;\n let statusLabel: string;\n\n switch (status) {\n case 'success':\n statusIcon = icons.success;\n statusLabel = 'Completed';\n break;\n case 'incomplete':\n statusIcon = icons.warn;\n statusLabel = 'Incomplete';\n break;\n case 'failed':\n statusIcon = icons.fail;\n statusLabel = 'Failed';\n break;\n }\n\n const boxLines = [\n `${icons.end} Issue Flow Summary`,\n '---',\n `Status: ${statusIcon} ${statusLabel}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${iterations}`,\n `Duration: ${duration}`,\n ];\n\n boxLines.push(...tokenBoxLines(usage, usageByAgent));\n boxLines.push(...executionCostLines(plan));\n\n boxLines.push(`Retries: ${totalRetries}`);\n\n if (extraInfo) {\n boxLines.push('---');\n boxLines.push(extraInfo);\n }\n\n console.log('');\n printBox(boxLines);\n}\n\n/**\n * What the optional `pr-review` phase produced, as far as the summary cares.\n * `null` in `recommendation` means the verdict could not be recovered from\n * disk — the exit code still told us whether changes were requested.\n */\nexport interface RunSummaryPrReview {\n requestedChanges: boolean;\n recommendation: PrReviewRecommendation | null;\n reportPath: string | null;\n}\n\n/**\n * Everything the final `run` summary prints, already resolved by the caller.\n */\nexport interface RunSummaryInfo {\n issueNumber: string;\n /** 'unknown' when the branch could not be detected. */\n branchName: string;\n /** Pipelines run with --no-branch open no Pull Request. */\n noBranch: boolean;\n storyCount: number;\n elapsedSeconds: number;\n /** 'unknown' when no Pull Request could be resolved. */\n prUrl: string;\n /** Only set when the pr-review phase actually ran. */\n prReview?: RunSummaryPrReview | null;\n /**\n * Tokens and cost of the whole pipeline, from the process-owned counters in\n * `core/session-metrics.ts`. Absent or empty omits the line.\n */\n usage?: ClaudeUsage | null;\n /** When more than one agent ran, the summary prints one Tokens line each. */\n usageByAgent?: Record<string, ClaudeUsage>;\n /** Acceptance-contract verdict. Absent when the contract never ran. */\n verification?: { verdict: 'passed' | 'failed' | 'unverified'; level?: string | null } | null;\n}\n\nfunction executionCostLines(plan: TaskPlan, prefix = 'Cost: '): string[] {\n const records = plan.executions ?? [];\n if (records.length === 0) return [];\n const lines: string[] = [];\n const groups = groupBy(records, 'harness');\n let index = 0;\n const pad = ' '.repeat(prefix.length);\n for (const [harness, summary] of groups) {\n const parts: string[] = [];\n if (summary.totalCost.reported > 0) {\n parts.push(`$${summary.totalCost.reported.toFixed(4)} reported`);\n }\n if (summary.totalCost.estimated > 0) {\n parts.push(`$${summary.totalCost.estimated.toFixed(4)} estimated`);\n }\n if (summary.totalCost.unknownExecutions > 0) {\n parts.push(`${summary.totalCost.unknownExecutions} unknown`);\n }\n if (parts.length === 0) {\n const totals = summarize(records).totalCost;\n if (totals.reported === 0 && totals.estimated === 0) {\n parts.push('not reported');\n }\n }\n if (parts.length === 0) continue;\n lines.push(`${index === 0 ? prefix : pad}${harness} · ${parts.join(' · ')}`);\n index += 1;\n }\n return lines;\n}\n\nfunction tokenBoxLines(\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n): string[] {\n const agents = usageByAgent ? Object.keys(usageByAgent) : [];\n if (agents.length > 1) {\n const lines: string[] = [];\n for (const [index, id] of agents.entries()) {\n const tokens = formatTokens(usageByAgent?.[id]);\n if (tokens === '') continue;\n lines.push(index === 0 ? `Tokens: ${id} · ${tokens}` : ` ${id} · ${tokens}`);\n }\n return lines;\n }\n const tokens = formatTokens(usage);\n return tokens === '' ? [] : [`Tokens: ${tokens}`];\n}\n\nfunction tokenSummaryLines(\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n prefix = ' Tokens: ',\n): string[] {\n const agents = usageByAgent ? Object.keys(usageByAgent) : [];\n if (agents.length > 1) {\n const pad = ' '.repeat(prefix.length);\n const lines: string[] = [];\n for (const [index, id] of agents.entries()) {\n const tokens = formatTokens(usageByAgent?.[id]);\n if (tokens === '') continue;\n lines.push(`${index === 0 ? prefix : pad}${id} · ${tokens}`);\n }\n return lines;\n }\n const tokens = formatTokens(usage);\n return tokens === '' ? [] : [`${prefix}${tokens}`];\n}\n\n/**\n * Detail lines of the final `run` summary (everything below the headline).\n *\n * Kept separate from the printing so the shape is testable without capturing\n * stdout. Without `prReview` the lines are exactly the ones the pipeline has\n * always printed.\n */\nexport function buildRunSummaryLines(info: RunSummaryInfo): string[] {\n const lines = [\n ` Branch: ${info.branchName}${info.noBranch ? ' (current)' : ''}`,\n ` Stories: ${info.storyCount}`,\n ` Duration: ${formatDuration(info.elapsedSeconds)}`,\n ];\n\n lines.push(...tokenSummaryLines(info.usage, info.usageByAgent));\n\n if (!info.noBranch) {\n lines.push(` PR: ${info.prUrl}`);\n }\n\n if (info.verification != null) {\n const label =\n info.verification.verdict === 'passed'\n ? 'passed'\n : info.verification.verdict === 'failed'\n ? 'failed'\n : 'unverified';\n lines.push(` Contract: ${label}`);\n }\n\n const review = info.prReview;\n if (review) {\n // The exit code is the source of truth for the verdict, so a report whose\n // recommendation could not be read still reports REQUEST_CHANGES.\n const verdict =\n review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown');\n lines.push(` Review: ${verdict}`);\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** One issue of a multi-issue queue, as the consolidated summary reports it. */\nexport interface QueueIssueSummary {\n id: string;\n title: string;\n storyCount: number;\n elapsedSeconds: number;\n /** Tokens and cost of this issue alone — never of the whole queue. */\n usage?: ClaudeUsage | null;\n}\n\n/** Everything the consolidated summary of a queue prints. */\nexport interface QueueSummaryInfo {\n /** Identifier of the queue, i.e. of its primary issue. */\n queueId: string;\n /** Branch every issue shared, `null` when the queue ran with --no-branch. */\n branchName: string | null;\n issues: QueueIssueSummary[];\n /** Issues discovered but left out of the run. */\n excluded: { id: string; title: string }[];\n elapsedSeconds: number;\n /** The single consolidated Pull Request, `null` when none was opened. */\n prUrl: string | null;\n /** Tokens and cost of the whole queue. */\n usage?: ClaudeUsage | null;\n /** Verdict of the pr-review phase, when the queue ran it. */\n prReview?: RunSummaryPrReview | null;\n}\n\n/**\n * Detail lines of a queue's final summary.\n *\n * Per-issue lines carry their own duration and cost, which is the visible half\n * of the per-issue metric scoping: what one issue spent is never folded into\n * another's line.\n */\nexport function buildQueueSummaryLines(info: QueueSummaryInfo): string[] {\n const lines: string[] = [];\n\n lines.push(` Branch: ${info.branchName ?? 'current'}`);\n lines.push(` Issues: ${info.issues.length}`);\n\n for (const issue of info.issues) {\n const tokens = formatTokens(issue.usage);\n const title = issue.title === '' ? '' : ` ${issue.title}`;\n lines.push(\n ` #${issue.id}${title} — ${issue.storyCount} stories, ${formatDuration(issue.elapsedSeconds)}` +\n (tokens === '' ? '' : `, ${tokens}`),\n );\n }\n\n lines.push(` Duration: ${formatDuration(info.elapsedSeconds)}`);\n\n const tokens = formatTokens(info.usage);\n if (tokens !== '') {\n lines.push(` Tokens: ${tokens}`);\n }\n if (info.prUrl !== null) {\n lines.push(` PR: ${info.prUrl}`);\n }\n if (info.excluded.length > 0) {\n lines.push(` Skipped: ${info.excluded.map((entry) => `#${entry.id}`).join(', ')}`);\n }\n\n const review = info.prReview;\n if (review) {\n lines.push(\n ` Review: ${review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown')}`,\n );\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** Print the consolidated summary of a multi-issue queue. */\nexport function printQueueSummary(info: QueueSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges === true) {\n printWarning(`Queue finished for issue #${info.queueId}, but the PR review requested changes.`);\n } else {\n printSuccess(`Queue complete for issue #${info.queueId} (${info.issues.length} issues)!`);\n }\n for (const line of buildQueueSummaryLines(info)) {\n console.log(line);\n }\n}\n\n/**\n * Print the final summary of a `run` (the flat listing, not the box used by\n * the execute engine).\n */\nexport function printRunSummary(info: RunSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges) {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the PR review requested changes.`,\n );\n } else if (info.verification?.verdict === 'unverified') {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the acceptance contract is unverified.`,\n );\n } else if (info.verification?.verdict === 'failed') {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the acceptance contract failed.`,\n );\n } else {\n printSuccess(`Pipeline complete for issue #${info.issueNumber}!`);\n }\n for (const line of buildRunSummaryLines(info)) {\n console.log(line);\n }\n}\n","/**\n * Strip the markdown markers that leak into a terminal that cannot render them.\n *\n * Used by the clean view and by failure excerpts. Verbose mode keeps the\n * original text — this is only for the default surface.\n */\nexport function stripMarkdown(text: string): string {\n return text\n .replace(/```[\\s\\S]*?```/g, ' ')\n .replace(/`([^`]+)`/g, '$1')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '$1')\n .replace(/__([^_]+)__/g, '$1')\n .replace(/(?<!\\*)\\*([^*]+)\\*(?!\\*)/g, '$1')\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/^\\s*[-*+]\\s+/gm, '')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim();\n}\n\n/** Last non-empty lines of a failure report, already stripped of markdown. */\nexport function failureExcerpt(output: string, limit = 8): string[] {\n return output\n .split('\\n')\n .map((line) => stripMarkdown(line))\n .filter((line) => line.length > 0)\n .slice(-limit);\n}\n","import { invokeSelectedAgent } from '../agents/invoke.js';\nimport type { ClaudeResult } from '../types.js';\nimport { failureExcerpt } from '../ui/text.js';\nimport { getOutputCallback, isVerbose } from './verbose.js';\n\nexport interface ExecuteClaudeOptions {\n /**\n * Silence tolerated before the agent is considered stuck. `0` disables the\n * watchdog, which is the behaviour every release before it had.\n */\n inactivityTimeoutMs?: number;\n iteration?: number;\n correctionCycle?: number;\n storyIds?: string[];\n}\n\n/**\n * Execute the resolved agent with a prompt piped to stdin.\n *\n * The default (Claude, unconfigured) is still\n * `claude --dangerously-skip-permissions --print --output-format stream-json --verbose`\n * with the prompt on stdin and `timeout: 0`. Callers see `exitCode`, the\n * assistant text as `output`, and usage. On failure the raw diagnostics stay\n * unwrapped so `isTransientFailure()` can read them.\n */\nexport async function executeClaude(\n prompt: string,\n options: ExecuteClaudeOptions = {},\n): Promise<ClaudeResult> {\n let selected: Awaited<ReturnType<typeof invokeSelectedAgent>>;\n try {\n selected = await invokeSelectedAgent({\n prompt,\n phase: 'execute',\n timeout: 0,\n permission: 'autonomous',\n inactivityTimeoutMs: options.inactivityTimeoutMs,\n iteration: options.iteration,\n correctionCycle: options.correctionCycle,\n storyIds: options.storyIds,\n });\n } catch (err) {\n return {\n exitCode: 1,\n output: err instanceof Error ? err.message : String(err),\n cost: null,\n };\n }\n const { run } = selected;\n\n let output: string;\n let cost = run.usage;\n\n if (!run.success || run.exitCode !== 0) {\n output = run.rawOutput || run.error || '';\n cost = null;\n } else {\n output = run.result || run.rawOutput;\n }\n\n emitAgentOutput(output, !(run.success && run.exitCode === 0));\n\n return {\n exitCode: run.exitCode === 0 && run.success ? 0 : run.exitCode === 0 ? 1 : run.exitCode,\n output,\n cost,\n };\n}\n\n/**\n * Clean mode never dumps the agent report. Verbose breaks it line by line.\n * A failure always prints a short excerpt — the user should not need\n * `--verbose` to see why a story stopped.\n */\nfunction emitAgentOutput(output: string, failed: boolean): void {\n const onOutput = getOutputCallback();\n if (!onOutput) return;\n const trimmed = output.trim();\n if (!trimmed) return;\n\n if (isVerbose()) {\n for (const line of trimmed.split('\\n')) {\n if (line.trim()) onOutput(line);\n }\n return;\n }\n\n if (failed) {\n for (const line of failureExcerpt(trimmed)) {\n onOutput(line);\n }\n }\n}\n"],"mappings":"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","names":["chalk","chalk","tokens","result","elapsed","numericIssue"]}
|