issue-flow 0.7.7 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +16 -0
  2. package/dist/{analyze-2RVGY5OK.js → analyze-VSWAEVN3.js} +6 -6
  3. package/dist/{chunk-WO6ERABE.js → chunk-57MH6RYJ.js} +106 -7
  4. package/dist/chunk-57MH6RYJ.js.map +1 -0
  5. package/dist/{chunk-6UTVPKNF.js → chunk-66ZGYXTH.js} +53 -9
  6. package/dist/chunk-66ZGYXTH.js.map +1 -0
  7. package/dist/{chunk-WGDLUPSF.js → chunk-DP43WJY4.js} +75 -11
  8. package/dist/chunk-DP43WJY4.js.map +1 -0
  9. package/dist/{chunk-ZYBYMEWG.js → chunk-DTNM3LTO.js} +33 -10
  10. package/dist/chunk-DTNM3LTO.js.map +1 -0
  11. package/dist/{chunk-KHTLN54U.js → chunk-JGKPSWOA.js} +2 -2
  12. package/dist/{chunk-EYVXLRRD.js → chunk-KXAG24DD.js} +219 -3
  13. package/dist/chunk-KXAG24DD.js.map +1 -0
  14. package/dist/{chunk-XPW46TI5.js → chunk-M37YZYDO.js} +3 -3
  15. package/dist/{chunk-G37JNQKB.js → chunk-M72ZEPWD.js} +2 -2
  16. package/dist/{chunk-RUTDK6ZF.js → chunk-MTJQOOMG.js} +105 -4
  17. package/dist/chunk-MTJQOOMG.js.map +1 -0
  18. package/dist/{chunk-OPIDR2DC.js → chunk-NB6WKTBL.js} +2 -2
  19. package/dist/chunk-TJMZWRS6.js +265 -0
  20. package/dist/chunk-TJMZWRS6.js.map +1 -0
  21. package/dist/{chunk-6IOPYFUM.js → chunk-TLSIK656.js} +6 -6
  22. package/dist/{chunk-JOK7VXRV.js → chunk-VNKSMWDN.js} +17 -3
  23. package/dist/chunk-VNKSMWDN.js.map +1 -0
  24. package/dist/{chunk-6L2BPOE3.js → chunk-WHEU55ZP.js} +7 -7
  25. package/dist/{chunk-EOTULFWV.js → chunk-X7XBF5TS.js} +6 -6
  26. package/dist/cli.js +91 -29
  27. package/dist/cli.js.map +1 -1
  28. package/dist/{config-OAZG7KIK.js → config-J5DW6HSY.js} +3 -3
  29. package/dist/execute-Z2DKGVLR.js +14 -0
  30. package/dist/{generate-BEJF3SVJ.js → generate-ERDPOTKX.js} +6 -6
  31. package/dist/init-UY6ZCIFT.js +9 -0
  32. package/dist/plan-REMAMCX4.js +16 -0
  33. package/dist/pr-KERP52TI.js +20 -0
  34. package/dist/pr-review-IU4N3TEK.js +16 -0
  35. package/dist/prd-SHVQW6RM.js +16 -0
  36. package/dist/review-L5F77QAC.js +14 -0
  37. package/dist/run-BRBFHVUO.js +1860 -0
  38. package/dist/run-BRBFHVUO.js.map +1 -0
  39. package/dist/{web-3SBYL7QJ.js → web-WQISLO66.js} +4 -4
  40. package/package.json +1 -1
  41. package/prompts/execute.md +2 -2
  42. package/prompts/plan.md +10 -1
  43. package/prompts/pr.md +9 -4
  44. package/web/CLAUDE.md +70 -8
  45. package/web/public/app.css +444 -0
  46. package/web/public/app.js +573 -17
  47. package/web/public/index.html +50 -0
  48. package/dist/chunk-3E6KASSE.js +0 -123
  49. package/dist/chunk-3E6KASSE.js.map +0 -1
  50. package/dist/chunk-6UTVPKNF.js.map +0 -1
  51. package/dist/chunk-EYVXLRRD.js.map +0 -1
  52. package/dist/chunk-JOK7VXRV.js.map +0 -1
  53. package/dist/chunk-RUTDK6ZF.js.map +0 -1
  54. package/dist/chunk-WGDLUPSF.js.map +0 -1
  55. package/dist/chunk-WO6ERABE.js.map +0 -1
  56. package/dist/chunk-ZYBYMEWG.js.map +0 -1
  57. package/dist/execute-AOEM52CD.js +0 -14
  58. package/dist/init-TBC3WI74.js +0 -9
  59. package/dist/plan-YDZYB2BO.js +0 -16
  60. package/dist/pr-SIXMJIZF.js +0 -16
  61. package/dist/pr-review-AY56ZPJR.js +0 -16
  62. package/dist/prd-MBSSBLGO.js +0 -16
  63. package/dist/review-2MDDHZ4X.js +0 -14
  64. package/dist/run-SEB6F3W4.js +0 -733
  65. package/dist/run-SEB6F3W4.js.map +0 -1
  66. /package/dist/{analyze-2RVGY5OK.js.map → analyze-VSWAEVN3.js.map} +0 -0
  67. /package/dist/{chunk-KHTLN54U.js.map → chunk-JGKPSWOA.js.map} +0 -0
  68. /package/dist/{chunk-XPW46TI5.js.map → chunk-M37YZYDO.js.map} +0 -0
  69. /package/dist/{chunk-G37JNQKB.js.map → chunk-M72ZEPWD.js.map} +0 -0
  70. /package/dist/{chunk-OPIDR2DC.js.map → chunk-NB6WKTBL.js.map} +0 -0
  71. /package/dist/{chunk-6IOPYFUM.js.map → chunk-TLSIK656.js.map} +0 -0
  72. /package/dist/{chunk-6L2BPOE3.js.map → chunk-WHEU55ZP.js.map} +0 -0
  73. /package/dist/{chunk-EOTULFWV.js.map → chunk-X7XBF5TS.js.map} +0 -0
  74. /package/dist/{config-OAZG7KIK.js.map → config-J5DW6HSY.js.map} +0 -0
  75. /package/dist/{execute-AOEM52CD.js.map → execute-Z2DKGVLR.js.map} +0 -0
  76. /package/dist/{generate-BEJF3SVJ.js.map → generate-ERDPOTKX.js.map} +0 -0
  77. /package/dist/{init-TBC3WI74.js.map → init-UY6ZCIFT.js.map} +0 -0
  78. /package/dist/{plan-YDZYB2BO.js.map → plan-REMAMCX4.js.map} +0 -0
  79. /package/dist/{pr-SIXMJIZF.js.map → pr-KERP52TI.js.map} +0 -0
  80. /package/dist/{pr-review-AY56ZPJR.js.map → pr-review-IU4N3TEK.js.map} +0 -0
  81. /package/dist/{prd-MBSSBLGO.js.map → prd-SHVQW6RM.js.map} +0 -0
  82. /package/dist/{review-2MDDHZ4X.js.map → review-L5F77QAC.js.map} +0 -0
  83. /package/dist/{web-3SBYL7QJ.js.map → web-WQISLO66.js.map} +0 -0
package/README.md CHANGED
@@ -85,10 +85,18 @@ npx issue-flow run 42 --mode manual
85
85
 
86
86
  # Watch the run live in the browser (see "Web Monitoring" below)
87
87
  npx issue-flow run 42 --web
88
+
89
+ # Continue User Story numbering from the last used in this project
90
+ npx issue-flow run 42 --continue
91
+
92
+ # Force User Story numbering to start at a specific number
93
+ npx issue-flow run 42 --start-us 27
88
94
  ```
89
95
 
90
96
  Executes all phases in order: **init** → **analyze** → **prd** → **plan** → **execute** → **review** → **pr**. Automatically resumes from the last incomplete phase if pipeline state exists. On review failure, its findings are saved verbatim to `lastReviewFindings` in `tasks.json`, and a correction cycle (re-execute + re-review) runs up to `maxCorrectionCycles`. The re-execute step reads `lastReviewFindings` and treats the issue as unresolved even if every user story already has `passes: true`, until the findings are addressed and the field is cleared back to `null`.
91
97
 
98
+ `--continue` and `--start-us <n>` control User Story (`US-NNN`) numbering continuity across `plan` runs of the same project — see [`plan`](#plan----convert-prd-to-task-plan) below.
99
+
92
100
  ### `init` -- Check prerequisites
93
101
 
94
102
  ```bash
@@ -117,10 +125,18 @@ Generates a Product Requirements Document from the issue analysis. Reads `analys
117
125
 
118
126
  ```bash
119
127
  npx issue-flow plan 42
128
+
129
+ # Continue User Story numbering from the last used in this project
130
+ npx issue-flow plan 42 --continue
131
+
132
+ # Force numbering to start at a specific number, ignoring history
133
+ npx issue-flow plan 42 --start-us 27
120
134
  ```
121
135
 
122
136
  Converts the PRD into a structured `~/.issue-flow/…/issues/42/tasks.json` with ordered user stories, acceptance criteria, and pipeline state. Validates the output with zod schemas.
123
137
 
138
+ `US-NNN` numbering continues automatically across `plan` runs of the same project: the highest number already used in any of the project's `tasks.json` files is recovered and the next story continues from there, falling back to `US-001` when the project has no history yet. `--continue` names that automatic recovery explicitly; `--start-us <n>` forces a specific starting number instead, ignoring history — the two flags are mutually exclusive. The decision is always printed to the terminal and recorded in the project's `metadata.json` (`userStoryNumbering`) for audit. See the root [README](https://github.com/fabioassuncao/issue-flow#user-story-numbering-continuity) for the full cascade.
139
+
124
140
  ### `execute` -- Run the story execution loop
125
141
 
126
142
  ```bash
@@ -2,20 +2,20 @@
2
2
  import {
3
3
  issuePlaceholders,
4
4
  resolveCommandIssue
5
- } from "./chunk-EYVXLRRD.js";
5
+ } from "./chunk-KXAG24DD.js";
6
6
  import {
7
7
  runHeadless
8
- } from "./chunk-KHTLN54U.js";
8
+ } from "./chunk-JGKPSWOA.js";
9
9
  import {
10
10
  publishPhaseMetrics
11
- } from "./chunk-ZYBYMEWG.js";
11
+ } from "./chunk-DTNM3LTO.js";
12
12
  import {
13
13
  applyPlaceholders,
14
14
  loadPrompt
15
15
  } from "./chunk-SLHZPB3C.js";
16
16
  import {
17
17
  resolveIssuePaths
18
- } from "./chunk-RUTDK6ZF.js";
18
+ } from "./chunk-MTJQOOMG.js";
19
19
  import {
20
20
  getGlobalTimeout,
21
21
  loadTaskPlan,
@@ -23,7 +23,7 @@ import {
23
23
  printInfo,
24
24
  printSuccess,
25
25
  saveTaskPlan
26
- } from "./chunk-WO6ERABE.js";
26
+ } from "./chunk-57MH6RYJ.js";
27
27
 
28
28
  // src/commands/analyze.ts
29
29
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -84,4 +84,4 @@ async function runAnalyze(issue, resolvedIssue) {
84
84
  export {
85
85
  runAnalyze
86
86
  };
87
- //# sourceMappingURL=analyze-2RVGY5OK.js.map
87
+ //# sourceMappingURL=analyze-VSWAEVN3.js.map
@@ -10,6 +10,15 @@ var claudeUsageSchema = z.object({
10
10
  costUsd: z.number().optional()
11
11
  });
12
12
  var userStoryStatusSchema = z.enum(["backlog", "in_progress", "in_review", "done"]);
13
+ var storyStageSchema = z.enum([
14
+ "pending",
15
+ "executing",
16
+ "awaiting_review",
17
+ "in_review",
18
+ "in_correction",
19
+ "done",
20
+ "failed"
21
+ ]);
13
22
  var userStorySchema = z.object({
14
23
  id: z.string(),
15
24
  title: z.string(),
@@ -21,7 +30,10 @@ var userStorySchema = z.object({
21
30
  ...claudeUsageSchema.shape,
22
31
  durationSeconds: z.number().optional(),
23
32
  status: userStoryStatusSchema.optional(),
24
- dependencies: z.array(z.string()).optional()
33
+ dependencies: z.array(z.string()).optional(),
34
+ stage: storyStageSchema.optional(),
35
+ stageSince: z.string().optional(),
36
+ stageDetail: z.string().optional()
25
37
  });
26
38
  var pipelineStateSchema = z.object({
27
39
  analyzeCompleted: z.boolean().optional(),
@@ -138,6 +150,17 @@ var sessionStorySchema = z.object({
138
150
  // image of userStorySchema, where the same two fields are plainly optional.
139
151
  status: userStoryStatusSchema.default("backlog"),
140
152
  dependencies: z.array(z.string()).default([]),
153
+ // Published for the panel's story detail view. Same tolerant default as the
154
+ // fields above: absent (older session.json) and empty resolve to the same
155
+ // value, so the client never has to tell them apart.
156
+ description: z.string().default(""),
157
+ acceptanceCriteria: z.array(z.string()).default([]),
158
+ // Additive like the rest of this schema: a session.json written before
159
+ // `stage` existed parses into 'pending'/null, the same values a fresh
160
+ // snapshot starts a story at.
161
+ stage: storyStageSchema.default("pending"),
162
+ stageSince: z.string().nullable().default(null),
163
+ stageDetail: z.string().nullable().default(null),
141
164
  ...sessionUsageShape
142
165
  });
143
166
  var sessionSnapshotSchema = z.object({
@@ -373,6 +396,22 @@ function reduceSessionEvent(snapshot, event, options) {
373
396
  nextSteps: deriveNextSteps(next)
374
397
  };
375
398
  }
399
+ function isTerminalStage(stage) {
400
+ return stage === "done" || stage === "failed";
401
+ }
402
+ function deriveStageOnStoriesUpdate(story, before, at) {
403
+ if (!story.passes) {
404
+ return {
405
+ stage: before?.stage ?? "pending",
406
+ stageSince: before?.stageSince ?? at,
407
+ stageDetail: before?.stageDetail ?? null
408
+ };
409
+ }
410
+ if (before?.passes) {
411
+ return { stage: before.stage, stageSince: before.stageSince, stageDetail: before.stageDetail };
412
+ }
413
+ return { stage: "awaiting_review", stageSince: at, stageDetail: null };
414
+ }
376
415
  function applyEvent(snapshot, event, options) {
377
416
  switch (event.type) {
378
417
  case "session:start": {
@@ -443,10 +482,14 @@ function applyEvent(snapshot, event, options) {
443
482
  ...emptyUsage()
444
483
  }
445
484
  ];
485
+ const stories = event.phase === "review" ? snapshot.stories.map(
486
+ (story) => story.passes ? { ...story, stage: "in_review", stageSince: event.at, stageDetail: null } : story
487
+ ) : snapshot.stories;
446
488
  return {
447
489
  ...snapshot,
448
490
  currentPhase: event.phase,
449
491
  phases,
492
+ stories,
450
493
  progress: known ? snapshot.progress : { ...snapshot.progress, phasesTotal: phases.length }
451
494
  };
452
495
  }
@@ -461,11 +504,17 @@ function applyEvent(snapshot, event, options) {
461
504
  } : p
462
505
  );
463
506
  const phasesCompleted = phases.filter((p) => p.status === "completed").length;
507
+ const stories = !event.success ? snapshot.stories.map(
508
+ (story) => isTerminalStage(story.stage) ? story : { ...story, stage: "failed", stageSince: event.at, stageDetail: null }
509
+ ) : event.phase === "review" ? snapshot.stories.map(
510
+ (story) => story.passes ? { ...story, stage: "done", stageSince: event.at, stageDetail: null } : story
511
+ ) : snapshot.stories;
464
512
  return {
465
513
  ...snapshot,
466
514
  currentPhase: snapshot.currentPhase === event.phase ? null : snapshot.currentPhase,
467
515
  currentActivity: null,
468
516
  phases,
517
+ stories,
469
518
  progress: {
470
519
  ...snapshot.progress,
471
520
  phasesCompleted,
@@ -473,11 +522,27 @@ function applyEvent(snapshot, event, options) {
473
522
  }
474
523
  };
475
524
  }
476
- case "iteration:start":
525
+ case "iteration:start": {
526
+ const storyId = event.storyId;
527
+ const stories = snapshot.stories.map((story) => {
528
+ if (story.passes) return story;
529
+ if (story.id === storyId) {
530
+ return story.stage === "executing" ? story : { ...story, stage: "executing", stageSince: event.at, stageDetail: null };
531
+ }
532
+ return story.stage === "pending" ? story : { ...story, stage: "pending", stageSince: event.at, stageDetail: null };
533
+ });
477
534
  return {
478
535
  ...snapshot,
479
- execution: { ...snapshot.execution, iteration: event.iteration }
536
+ execution: { ...snapshot.execution, iteration: event.iteration },
537
+ stories,
538
+ // Finally populates the `story` field of the activity payload during
539
+ // execute — today this phase never publishes an `activity` event at
540
+ // all (no streaming), so `currentActivity` stays whatever an earlier
541
+ // phase left it at. Left untouched when storyId is absent (every
542
+ // story already passes, or the caller could not determine one).
543
+ currentActivity: storyId !== void 0 ? { story: storyId, tool: null, detail: null, since: event.at } : snapshot.currentActivity
480
544
  };
545
+ }
481
546
  case "iteration:end":
482
547
  return { ...snapshot, currentActivity: null };
483
548
  case "retry":
@@ -502,12 +567,17 @@ function applyEvent(snapshot, event, options) {
502
567
  // value survives just for 'in_review', which no derivation produces.
503
568
  status: story.status ?? before?.status ?? "backlog",
504
569
  dependencies: story.dependencies ?? [],
570
+ // Required on UserStory, so the plan is always the source — no
571
+ // carry-over from `before` the way the accumulated fields need.
572
+ description: story.description,
573
+ acceptanceCriteria: story.acceptanceCriteria,
505
574
  durationSeconds: before?.durationSeconds ?? null,
506
575
  inputTokens: before?.inputTokens ?? null,
507
576
  outputTokens: before?.outputTokens ?? null,
508
577
  cacheReadTokens: before?.cacheReadTokens ?? null,
509
578
  cacheCreationTokens: before?.cacheCreationTokens ?? null,
510
- costUsd: before?.costUsd ?? null
579
+ costUsd: before?.costUsd ?? null,
580
+ ...deriveStageOnStoriesUpdate(story, before, event.at)
511
581
  };
512
582
  });
513
583
  return {
@@ -557,15 +627,21 @@ function applyEvent(snapshot, event, options) {
557
627
  },
558
628
  pullRequests: event.pullRequests ?? snapshot.pullRequests
559
629
  };
560
- case "correction:cycle":
630
+ case "correction:cycle": {
631
+ const stageDetail = `Cycle ${event.cycle}/${event.maxCycles}`;
632
+ const stories = snapshot.stories.map(
633
+ (story) => story.passes ? { ...story, stage: "in_correction", stageSince: event.at, stageDetail } : story
634
+ );
561
635
  return {
562
636
  ...snapshot,
563
637
  execution: {
564
638
  ...snapshot.execution,
565
639
  correctionCycle: event.cycle,
566
640
  maxCorrectionCycles: event.maxCycles
567
- }
641
+ },
642
+ stories
568
643
  };
644
+ }
569
645
  case "metrics:update": {
570
646
  if (event.scope === "story") {
571
647
  if (event.storyId === void 0) return snapshot;
@@ -611,6 +687,15 @@ function applyEvent(snapshot, event, options) {
611
687
  endedAt: event.at,
612
688
  currentPhase: null,
613
689
  currentActivity: null,
690
+ // Close every non-terminal stage: the run is over, so nothing can be
691
+ // 'executing'/'in_review'/'in_correction' any more. A story that never
692
+ // reached `passes` on a run that did not complete is exactly what the
693
+ // 'failed' stage means; anything else settles as 'done'.
694
+ stories: snapshot.stories.map((story) => {
695
+ if (isTerminalStage(story.stage)) return story;
696
+ const stage = event.status === "completed" && story.passes ? "done" : "failed";
697
+ return { ...story, stage, stageSince: event.at, stageDetail: null };
698
+ }),
614
699
  lastError: event.error ? { message: stripVTControlCharacters(event.error), at: event.at } : snapshot.lastError
615
700
  };
616
701
  default:
@@ -921,6 +1006,9 @@ function allStoriesPass(plan) {
921
1006
  }
922
1007
  return plan.userStories.every((story) => story.passes === true);
923
1008
  }
1009
+ function selectActiveStory(stories) {
1010
+ return [...stories].filter((story) => !story.passes).sort((a, b) => a.priority - b.priority)[0];
1011
+ }
924
1012
  function applyStoryMetrics(plan, storyIds, share, durationSeconds) {
925
1013
  if (storyIds.length === 0) return plan;
926
1014
  const targets = new Set(storyIds);
@@ -1009,6 +1097,13 @@ function setStoryUpdateCallback(callback) {
1009
1097
  function getStoryUpdateCallback() {
1010
1098
  return _onStoryUpdate;
1011
1099
  }
1100
+ var _onStoryStage;
1101
+ function setStoryStageCallback(callback) {
1102
+ _onStoryStage = callback;
1103
+ }
1104
+ function getStoryStageCallback() {
1105
+ return _onStoryStage;
1106
+ }
1012
1107
  var _globalTimeout;
1013
1108
  function setGlobalTimeout(ms) {
1014
1109
  _globalTimeout = ms;
@@ -1164,6 +1259,7 @@ var ElapsedTimer = class {
1164
1259
  };
1165
1260
 
1166
1261
  export {
1262
+ pullRequestRefSchema,
1167
1263
  issueMetadataSchema,
1168
1264
  taskPlanSchema,
1169
1265
  sessionSnapshotSchema,
@@ -1186,6 +1282,7 @@ export {
1186
1282
  initializeState,
1187
1283
  hasPendingCorrection,
1188
1284
  allStoriesPass,
1285
+ selectActiveStory,
1189
1286
  applyStoryMetrics,
1190
1287
  markIssueInProgress,
1191
1288
  markIssueCompleted,
@@ -1198,6 +1295,8 @@ export {
1198
1295
  getOutputCallback,
1199
1296
  setStoryUpdateCallback,
1200
1297
  getStoryUpdateCallback,
1298
+ setStoryStageCallback,
1299
+ getStoryStageCallback,
1201
1300
  setGlobalTimeout,
1202
1301
  getGlobalTimeout,
1203
1302
  useUnicode,
@@ -1213,4 +1312,4 @@ export {
1213
1312
  formatDuration,
1214
1313
  ElapsedTimer
1215
1314
  };
1216
- //# sourceMappingURL=chunk-WO6ERABE.js.map
1315
+ //# sourceMappingURL=chunk-57MH6RYJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schemas.ts","../src/core/session-state.ts","../src/core/session-publisher.ts","../src/core/state-manager.ts","../src/utils/fs.ts","../src/core/metrics.ts","../src/core/verbose.ts","../src/ui/logger.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { ClaudeUsage } from './core/metrics.js';\nimport type { SessionSnapshot } from './core/session-state.js';\nimport type { IssueMetadata, IssuesConfig } from './issues/types.js';\n\n/**\n * Zod schemas for validating tasks.json structure, Issue metadata, headless\n * invocation outputs, the web monitoring session snapshot and the web\n * configuration.\n */\n\n/**\n * Token/cost metrics of a single `claude` invocation, mirroring ClaudeUsage in\n * src/core/metrics.ts. Every field is optional: the CLI only reports what it\n * knows, and an absent field means \"not reported\", never zero.\n */\nexport const claudeUsageSchema = z.object({\n inputTokens: z.number().optional(),\n outputTokens: z.number().optional(),\n cacheReadTokens: z.number().optional(),\n cacheCreationTokens: z.number().optional(),\n costUsd: z.number().optional(),\n}) satisfies z.ZodType<ClaudeUsage>;\n\nexport const userStoryStatusSchema = z.enum(['backlog', 'in_progress', 'in_review', 'done']);\n\n/**\n * Fine-grained execution stage — mirrors `StoryStage` in `src/types.ts`. See\n * that type's doc comment for what each value means and which pipeline event\n * produces it.\n */\nexport const storyStageSchema = z.enum([\n 'pending',\n 'executing',\n 'awaiting_review',\n 'in_review',\n 'in_correction',\n 'done',\n 'failed',\n]);\n\n/**\n * The metrics fields are additive and optional: plans written before they\n * existed keep parsing, and nothing is filled in with artificial zeros.\n *\n * `status` and `dependencies` follow the same rule and are `.optional()` rather\n * than `.default()` on purpose: a legacy plan must not gain a `'backlog'` and an\n * empty array it never declared just because `saveTaskPlan` rewrote it. `stage`\n * and friends follow the exact same treatment — nothing in the pipeline writes\n * them back onto `tasks.json`, so they stay `.optional()` too.\n */\nexport const userStorySchema = z.object({\n id: z.string(),\n title: z.string(),\n description: z.string(),\n acceptanceCriteria: z.array(z.string()),\n priority: z.number().int().positive(),\n passes: z.boolean(),\n notes: z.string(),\n ...claudeUsageSchema.shape,\n durationSeconds: z.number().optional(),\n status: userStoryStatusSchema.optional(),\n dependencies: z.array(z.string()).optional(),\n stage: storyStageSchema.optional(),\n stageSince: z.string().optional(),\n stageDetail: z.string().optional(),\n});\n\nexport const pipelineStateSchema = z.object({\n analyzeCompleted: z.boolean().optional(),\n prdCompleted: z.boolean(),\n jsonCompleted: z.boolean(),\n executionCompleted: z.boolean(),\n reviewCompleted: z.boolean(),\n prCreated: z.boolean(),\n prReviewCompleted: z.boolean().optional(),\n});\n\n/**\n * Pull Request opened by the `pr` phase. Optional on the plan: plans written\n * before the field existed (and runs with `--no-branch`) simply omit it.\n */\nexport const pullRequestRefSchema = z.object({\n number: z.number().int().positive(),\n url: z.string(),\n headBranch: z.string(),\n createdAt: z.string(),\n});\n\nexport const prReviewRecommendationSchema = z.enum([\n 'APPROVE',\n 'APPROVE_WITH_SUGGESTIONS',\n 'REQUEST_CHANGES',\n]);\n\n/**\n * State of the opt-in `pr-review` phase. `enabled` and `rounds` carry defaults\n * so a partially written object still parses instead of invalidating the plan.\n */\nexport const prReviewStateSchema = z.object({\n enabled: z.boolean().default(false),\n pullRequestNumber: z.number().int().positive().optional(),\n rounds: z.number().int().min(0).default(0),\n lastRecommendation: prReviewRecommendationSchema.optional(),\n lastReviewedAt: z.string().optional(),\n});\n\nconst lastErrorSchema = z.object({\n category: z.string(),\n message: z.string(),\n at: z.string(),\n});\n\n/**\n * Persisted metadata for an Issue stored on disk (issues/<id>/metadata.json).\n * `satisfies` keeps this schema in lockstep with the IssueMetadata interface in\n * src/issues/types.ts — changing one without the other fails the typecheck.\n */\nexport const issueMetadataSchema = z.object({\n schemaVersion: z.literal(1),\n id: z.string().min(1),\n number: z.number().int().positive().nullable(),\n source: z.enum(['github', 'local']),\n title: z.string(),\n labels: z.array(z.string()),\n state: z.enum(['open', 'closed']),\n createdAt: z.string(),\n updatedAt: z.string(),\n contentHash: z.string(),\n remote: z\n .object({\n provider: z.enum(['github', 'local']),\n ref: z.string(),\n syncedAt: z.string(),\n syncedContentHash: z.string(),\n })\n .optional(),\n}) satisfies z.ZodType<IssueMetadata>;\n\n/**\n * tasks.json structure. Deliberately permissive: plans written by older\n * versions must keep loading, so `issueUrl` is optional (Issues with no remote\n * have no URL) and `issueNumber` accepts non-numeric local identifiers.\n */\nexport const taskPlanSchema = z.object({\n project: z.string(),\n issueNumber: z.union([z.number().int().positive(), z.string().min(1)]),\n issueUrl: z.string().optional().default(''),\n branchName: z.string(),\n noBranch: z.boolean().optional().default(false),\n description: z.string(),\n issueStatus: z.enum(['pending', 'in_progress', 'completed']),\n completedAt: z.string().nullable(),\n lastAttemptAt: z.string().nullable(),\n lastError: lastErrorSchema.nullable(),\n correctionCycle: z.number().int().min(0),\n maxCorrectionCycles: z.number().int().min(0),\n /**\n * Findings from the most recent failed review, verbatim. Non-null means the\n * issue has a pending correction even if every userStories[].passes is\n * already true — the execute phase must address these before the field is\n * cleared back to null. See core/engine.ts's early-return guards.\n */\n lastReviewFindings: z.string().nullable().optional().default(null),\n pipeline: pipelineStateSchema,\n pullRequest: pullRequestRefSchema.optional(),\n prReview: prReviewStateSchema.optional(),\n userStories: z.array(userStorySchema),\n});\n\nexport const headlessResultSchema = z.object({\n success: z.boolean(),\n result: z.string(),\n cost: claudeUsageSchema.nullable(),\n error: z.string().nullable(),\n});\n\nconst sessionLogEntrySchema = z.object({\n at: z.string(),\n level: z.enum(['info', 'warn', 'error']),\n message: z.string(),\n});\n\n/**\n * Usage counters attached to a phase or a story in the session snapshot.\n * Unlike claudeUsageSchema (a single invocation, optional fields), these are\n * always present and nullable: null means \"never reported\", not zero.\n *\n * They default to null on input so a session.json written before the metrics\n * existed still parses -- absent and null mean the same thing here, and the\n * parsed value keeps the `number | null` shape the snapshot interface declares.\n */\nconst sessionUsageShape = {\n inputTokens: z.number().nullable().default(null),\n outputTokens: z.number().nullable().default(null),\n cacheReadTokens: z.number().nullable().default(null),\n cacheCreationTokens: z.number().nullable().default(null),\n costUsd: z.number().nullable().default(null),\n};\n\nconst sessionPhaseSchema = z.object({\n name: z.string(),\n status: z.enum(['pending', 'running', 'completed', 'failed']),\n startedAt: z.string().nullable(),\n endedAt: z.string().nullable(),\n durationSeconds: z.number().nullable(),\n error: z.string().nullable(),\n ...sessionUsageShape,\n});\n\nconst sessionStorySchema = z.object({\n id: z.string(),\n title: z.string(),\n priority: z.number(),\n passes: z.boolean(),\n completedAt: z.string().nullable(),\n // Also introduced with the metrics, hence the same tolerant default.\n durationSeconds: z.number().nullable().default(null),\n // Snapshot fields are always present on output and defaulted on input, so a\n // session.json written before they existed still parses. This is the mirror\n // image of userStorySchema, where the same two fields are plainly optional.\n status: userStoryStatusSchema.default('backlog'),\n dependencies: z.array(z.string()).default([]),\n // Published for the panel's story detail view. Same tolerant default as the\n // fields above: absent (older session.json) and empty resolve to the same\n // value, so the client never has to tell them apart.\n description: z.string().default(''),\n acceptanceCriteria: z.array(z.string()).default([]),\n // Additive like the rest of this schema: a session.json written before\n // `stage` existed parses into 'pending'/null, the same values a fresh\n // snapshot starts a story at.\n stage: storyStageSchema.default('pending'),\n stageSince: z.string().nullable().default(null),\n stageDetail: z.string().nullable().default(null),\n ...sessionUsageShape,\n});\n\n/**\n * Session snapshot served by the web monitoring mode (session.json and the\n * HTTP endpoint). `satisfies` keeps this schema in lockstep with the\n * SessionSnapshot interface in src/core/session-state.ts — changing one\n * without the other fails the typecheck.\n */\nexport const sessionSnapshotSchema = z.object({\n schemaVersion: z.literal(1),\n sessionId: z.string().nullable(),\n readOnly: z.literal(true),\n capabilities: z.array(z.string()),\n issue: z.object({\n number: z.number().nullable(),\n url: z.string().nullable(),\n // Additive: a session.json written before the Issue section was enriched\n // parses into the same \"not reported\" values createInitialSnapshot() uses.\n title: z.string().nullable().default(null),\n description: z.string().nullable().default(null),\n labels: z.array(z.string()).default([]),\n state: z.string().nullable().default(null),\n }),\n status: z.enum(['idle', 'running', 'completed', 'failed']),\n startedAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n endedAt: z.string().nullable(),\n elapsedSeconds: z.number().nullable(),\n estimatedRemainingSeconds: z.number().nullable(),\n progress: z.object({\n percent: z.number(),\n phasesCompleted: z.number(),\n phasesTotal: z.number(),\n storiesCompleted: z.number(),\n storiesTotal: z.number(),\n }),\n currentPhase: z.string().nullable(),\n currentActivity: z\n .object({\n story: z.string().nullable(),\n tool: z.string().nullable(),\n detail: z.string().nullable(),\n since: z.string(),\n })\n .nullable(),\n phases: z.array(sessionPhaseSchema),\n stories: z.array(sessionStorySchema),\n // The whole aggregate is additive: a snapshot from before it existed parses\n // into the same \"nothing reported\" object the reducer starts from.\n metrics: z\n .object({\n totalInputTokens: z.number().nullable().default(null),\n totalOutputTokens: z.number().nullable().default(null),\n totalCacheReadTokens: z.number().nullable().default(null),\n totalCacheCreationTokens: z.number().nullable().default(null),\n totalCostUsd: z.number().nullable().default(null),\n })\n .default({\n totalInputTokens: null,\n totalOutputTokens: null,\n totalCacheReadTokens: null,\n totalCacheCreationTokens: null,\n totalCostUsd: null,\n }),\n execution: z.object({\n iteration: z.number(),\n retries: z.number(),\n correctionCycle: z.number(),\n maxCorrectionCycles: z.number().nullable(),\n }),\n git: z.object({\n branch: z.string().nullable(),\n baseBranch: z.string().nullable(),\n commits: z.array(z.object({ hash: z.string(), subject: z.string() })),\n }),\n // Additive like the metrics aggregate: a session.json written before the\n // repository section existed parses into the same all-null object\n // createInitialSnapshot() starts from.\n repository: z\n .object({\n name: z.string().nullable().default(null),\n remoteUrl: z.string().nullable().default(null),\n branch: z.string().nullable().default(null),\n headCommit: z.string().nullable().default(null),\n root: z.string().nullable().default(null),\n })\n .default({ name: null, remoteUrl: null, branch: null, headCommit: null, root: null }),\n pullRequests: z.array(z.object({ number: z.number(), url: z.string(), title: z.string() })),\n logs: z.array(sessionLogEntrySchema),\n errors: z.array(sessionLogEntrySchema),\n warnings: z.array(sessionLogEntrySchema),\n lastError: z.object({ message: z.string(), at: z.string() }).nullable(),\n nextSteps: z.array(z.string()),\n environment: z.object({ node: z.string(), platform: z.string() }).nullable(),\n}) satisfies z.ZodType<SessionSnapshot>;\n\n/**\n * Resolved web monitoring configuration. Every field has a default, so\n * parsing a partial object (e.g. the `web` key of .issue-flow.json) fills in\n * the documented defaults.\n */\nexport const webConfigSchema = z.object({\n enabled: z.boolean().default(false),\n port: z.number().int().min(1).max(65535).default(3737),\n host: z.string().min(1).default('0.0.0.0'),\n refreshSeconds: z.number().positive().default(5),\n logLimit: z.number().int().positive().default(200),\n includeLogs: z.boolean().default(true),\n});\n\n/**\n * Resolved Issue provider configuration. Every field has a default that keeps\n * the GitHub-only behaviour, so parsing an empty object yields the exact\n * behaviour of releases without the provider layer.\n */\nexport const issuesConfigSchema = z.object({\n defaultGenerateTarget: z.enum(['github', 'local', 'both']).default('github'),\n preferredProvider: z.enum(['github', 'local']).default('github'),\n conflictPolicy: z.enum(['ask', 'prefer-local', 'prefer-github']).default('ask'),\n requireConfirmation: z.boolean().default(true),\n}) satisfies z.ZodType<IssuesConfig>;\n\n/**\n * Resolved `pr-review` configuration (the `prReview` key of .issue-flow.json).\n *\n * `publisher` selects the implementation `createPrReviewPublisher()` builds. v1\n * ships only the local one, so the enum has a single member on purpose: adding\n * a GitHub adapter is a new entry here plus a new factory, never a change to\n * the phase.\n */\nexport const prReviewConfigSchema = z.object({\n publisher: z.enum(['local']).default('local'),\n});\n\nexport type ValidatedTaskPlan = z.infer<typeof taskPlanSchema>;\nexport type ValidatedIssueMetadata = z.infer<typeof issueMetadataSchema>;\nexport type ValidatedHeadlessResult = z.infer<typeof headlessResultSchema>;\nexport type ValidatedSessionSnapshot = z.infer<typeof sessionSnapshotSchema>;\nexport type WebConfig = z.infer<typeof webConfigSchema>;\nexport type PrReviewConfig = z.infer<typeof prReviewConfigSchema>;\n","import { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { stripVTControlCharacters } from 'node:util';\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\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 }\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 | { type: 'phase:end'; at: string; phase: string; success: boolean; error?: string }\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 | { type: 'retry'; at: string; attempt: number; delaySeconds?: number; reason?: 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 | { 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 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\nexport interface SessionEnvironment {\n node: string;\n platform: string;\n}\n\nexport interface SessionLogEntry {\n at: string;\n level: SessionLogLevel;\n message: string;\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}\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}\n\nexport interface SessionActivity {\n story: string | null;\n tool: string | null;\n detail: string | null;\n since: string;\n}\n\nexport interface SessionCommit {\n hash: string;\n subject: string;\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 git: { branch: string | null; baseBranch: string | null; commits: SessionCommit[] };\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}\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 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 git: { branch: null, baseBranch: null, commits: [] },\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 };\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\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 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 ...emptyUsage(),\n })),\n git: { branch: event.branch ?? null, baseBranch: event.baseBranch ?? null, commits: [] },\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 environment: event.environment ?? 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 ...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\n ? { ...story, stage: 'in_review' as const, stageSince: event.at, stageDetail: null }\n : 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 }\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)\n ? story\n : { ...story, stage: 'failed' as const, stageSince: event.at, stageDetail: null },\n )\n : event.phase === 'review'\n ? snapshot.stories.map((story) =>\n story.passes\n ? { ...story, stage: 'done' as const, stageSince: event.at, stageDetail: null }\n : 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 story.stage === 'executing'\n ? story\n : { ...story, stage: 'executing' as const, stageSince: event.at, stageDetail: null };\n }\n return story.stage === 'pending'\n ? story\n : { ...story, stage: 'pending' as const, stageSince: event.at, stageDetail: 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 '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 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 ...deriveStageOnStoriesUpdate(story, before, event.at),\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 { ...snapshot, currentActivity: { story, tool, detail, since } };\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 'git:update':\n return {\n ...snapshot,\n git: {\n branch: event.branch ?? snapshot.git.branch,\n baseBranch: event.baseBranch ?? snapshot.git.baseBranch,\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\n ? { ...story, stage: 'in_correction' as const, stageSince: event.at, stageDetail }\n : 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 '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 { ...story, stage, stageSince: event.at, stageDetail: 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}\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 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 }\n\n protected override afterPublish(event: SessionEvent): void {\n if (this.closed) return;\n const terminal = event.type === 'phase:end' || event.type === 'session: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 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 await this.flush();\n this.closed = true;\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 FilePublisher\n * when web monitoring is enabled. The default NullPublisher makes every\n * instrumentation point a no-op when monitoring is off.\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","import { readFile } from 'node:fs/promises';\nimport { ZodError } from 'zod';\nimport { taskPlanSchema } from '../schemas.js';\nimport type { LastError, PipelineState, TaskPlan, UserStory } from '../types.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { type ClaudeUsage, sumUsage } from './metrics.js';\n\n/**\n * Get the current ISO timestamp.\n */\nexport function isoNow(): string {\n return new Date().toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Load and parse a tasks.json file.\n * Validates that it has the expected structure.\n */\nexport async function loadTaskPlan(path: string): Promise<TaskPlan> {\n const content = await readFile(path, 'utf-8');\n const raw = JSON.parse(content);\n\n try {\n return taskPlanSchema.parse(raw) as TaskPlan;\n } catch (err) {\n if (err instanceof ZodError) {\n const issues = err.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`).join('\\n');\n throw new Error(`Invalid tasks.json at ${path}:\\n${issues}`);\n }\n throw err;\n }\n}\n\n/**\n * Save a TaskPlan to disk atomically (write-to-temp + rename).\n * This prevents corruption if the process is interrupted during write.\n */\nexport async function saveTaskPlan(path: string, plan: TaskPlan): Promise<void> {\n await writeFileAtomic(path, `${JSON.stringify(plan, null, 2)}\\n`);\n}\n\n/**\n * Initialize default state fields on a TaskPlan.\n * Fills in missing fields with defaults, matching the Bash script behavior.\n *\n * The opt-in fields (`pullRequest`, `prReview`, `pipeline.prReviewCompleted`)\n * are deliberately absent from the defaults: they ride along on the spread when\n * present and stay out of the file entirely when the phases never ran.\n */\nexport function initializeState(plan: TaskPlan): TaskPlan {\n const defaultPipeline: PipelineState = {\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n };\n\n return {\n ...plan,\n issueStatus: plan.issueStatus ?? 'pending',\n completedAt: plan.completedAt ?? null,\n lastAttemptAt: plan.lastAttemptAt ?? null,\n lastError: plan.lastError ?? null,\n correctionCycle: plan.correctionCycle ?? 0,\n maxCorrectionCycles: plan.maxCorrectionCycles ?? 3,\n lastReviewFindings: plan.lastReviewFindings ?? null,\n pipeline: plan.pipeline ? { ...defaultPipeline, ...plan.pipeline } : defaultPipeline,\n };\n}\n\n/**\n * Whether the issue has a review failure that execute must still address,\n * even if every userStories[].passes is already true.\n */\nexport function hasPendingCorrection(plan: TaskPlan): boolean {\n return Boolean(plan.lastReviewFindings);\n}\n\n/**\n * Check if all user stories have passes=true.\n * Returns false if there are no stories.\n */\nexport function allStoriesPass(plan: TaskPlan): boolean {\n if (plan.userStories.length === 0) {\n return false;\n }\n\n return plan.userStories.every((story) => story.passes === true);\n}\n\n/**\n * The story `execute` should work on next: the highest-priority (lowest\n * `priority` number) story with `passes: false`. This is the exact same rule\n * `prompts/execute.md` gives the agent (\"pick the highest priority user\n * story where `passes: false`\") — kept here as a single, pure, exported\n * helper so the engine's `iteration:start` publication and the terminal\n * renderer read the same computed identity instead of two independent\n * heuristics.\n *\n * Pure: never mutates `stories`. Returns `undefined` when every story\n * already passes (or the plan has none).\n */\nexport function selectActiveStory(stories: readonly UserStory[]): UserStory | undefined {\n return [...stories].filter((story) => !story.passes).sort((a, b) => a.priority - b.priority)[0];\n}\n\n/**\n * Mark a specific story as passing.\n */\nexport function markStoryPassing(plan: TaskPlan, storyId: string): TaskPlan {\n return {\n ...plan,\n userStories: plan.userStories.map((story) =>\n story.id === storyId ? { ...story, passes: true } : story,\n ),\n };\n}\n\n/**\n * Accumulate a usage share (and duration) onto the given stories.\n *\n * Pure, like the rest of this module: returns a new plan and never touches the\n * input. Accumulation is summing and treats `undefined` as \"not reported\": a\n * field neither the story nor the share carries stays absent, so a plan written\n * by a CLI that reports no usage never gains artificial zeros.\n *\n * The share is what `divideUsage()` already split across the stories that\n * completed in the same execute iteration — see core/engine.ts.\n */\nexport function applyStoryMetrics(\n plan: TaskPlan,\n storyIds: string[],\n share: ClaudeUsage,\n durationSeconds?: number,\n): TaskPlan {\n if (storyIds.length === 0) return plan;\n\n const targets = new Set(storyIds);\n\n return {\n ...plan,\n userStories: plan.userStories.map((story) => {\n if (!targets.has(story.id)) return story;\n\n const updated: UserStory = { ...story, ...sumUsage(story, share) };\n if (story.durationSeconds !== undefined || durationSeconds !== undefined) {\n updated.durationSeconds = (story.durationSeconds ?? 0) + (durationSeconds ?? 0);\n }\n return updated;\n }),\n };\n}\n\n/**\n * Mark the issue as in_progress.\n */\nexport function markIssueInProgress(plan: TaskPlan, timestamp?: string): TaskPlan {\n const ts = timestamp ?? isoNow();\n return {\n ...plan,\n issueStatus: 'in_progress',\n completedAt: null,\n lastAttemptAt: ts,\n };\n}\n\n/**\n * Mark the issue as completed.\n */\nexport function markIssueCompleted(plan: TaskPlan): TaskPlan {\n const ts = isoNow();\n return {\n ...plan,\n issueStatus: 'completed',\n completedAt: ts,\n lastAttemptAt: ts,\n lastError: null,\n pipeline: plan.pipeline ? { ...plan.pipeline, executionCompleted: true } : plan.pipeline,\n };\n}\n\n/**\n * Set the lastError field on the task plan.\n */\nexport function setLastError(plan: TaskPlan, category: string, message: string): TaskPlan {\n const ts = isoNow();\n const error: LastError = {\n category,\n message,\n at: ts,\n };\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: error,\n };\n}\n\n/**\n * Clear the lastError field, but only if it was set before the attempt started.\n * This prevents clearing errors that were set during the current attempt.\n */\nexport function clearLastError(plan: TaskPlan, attemptStartedAt: string): TaskPlan {\n const ts = isoNow();\n\n // If the error was set after the attempt started, keep it\n if (plan.lastError && plan.lastError.at > attemptStartedAt) {\n return {\n ...plan,\n lastAttemptAt: ts,\n };\n }\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: null,\n };\n}\n\n/**\n * Trim an error message to at most 8 non-empty lines.\n */\nexport function trimErrorMessage(message: string): string {\n return message\n .split('\\n')\n .filter((line) => line.trim().length > 0)\n .slice(0, 8)\n .join('\\n');\n}\n","import { copyFile, mkdtemp, rename, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\n\n/**\n * Write a file atomically (write-to-temp + rename).\n *\n * A crash mid-write leaves the previous content untouched instead of a\n * truncated file, which matters for every artifact the pipeline reloads on the\n * next run (tasks.json, metadata.json).\n */\nexport async function writeFileAtomic(path: string, content: string): Promise<void> {\n const tmpDir = await mkdtemp(join(tmpdir(), 'issue-flow-'));\n const tmpFile = join(tmpDir, basename(path));\n\n await writeFile(tmpFile, content, 'utf-8');\n\n try {\n await rename(tmpFile, path);\n } catch (err: unknown) {\n // EXDEV: rename fails across different devices/drives (common on Windows)\n if ((err as NodeJS.ErrnoException).code === 'EXDEV') {\n await copyFile(tmpFile, path);\n await unlink(tmpFile);\n } else {\n throw err;\n }\n }\n}\n","/**\n * Single source of truth for translating the `claude` CLI JSON output into\n * token/cost metrics.\n *\n * Three call sites consume this (headless json, headless stream-json and the\n * execute-phase executor); keeping the parsing here is what stops them from\n * diverging again the next time the CLI payload changes shape.\n */\n\nexport interface ClaudeUsage {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n costUsd?: number;\n}\n\n/** Field names of {@link ClaudeUsage}, used by the summing helper. */\nconst USAGE_FIELDS = [\n 'inputTokens',\n 'outputTokens',\n 'cacheReadTokens',\n 'cacheCreationTokens',\n 'costUsd',\n] as const;\n\n/**\n * Coerce a value to a finite number, or undefined when it is absent/unusable.\n * Never throws — malformed payloads simply yield undefined.\n */\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Parse a `claude` CLI result payload into a {@link ClaudeUsage}.\n *\n * Reads the current format (`total_cost_usd` plus a nested `usage` object) and\n * falls back to the legacy flat keys (`cost_usd`, `num_input_tokens`,\n * `num_output_tokens`) when the newer ones are absent.\n *\n * Returns null when the payload carries no recognizable field at all, and a\n * partial object when only some fields are present. Never throws.\n */\nexport function parseUsage(payload: unknown): ClaudeUsage | null {\n if (!isRecord(payload)) return null;\n\n const usageRaw = isRecord(payload.usage) ? payload.usage : undefined;\n\n const usage: ClaudeUsage = {};\n\n const inputTokens = usageRaw ? num(usageRaw.input_tokens) : undefined;\n const outputTokens = usageRaw ? num(usageRaw.output_tokens) : undefined;\n const cacheReadTokens = usageRaw ? num(usageRaw.cache_read_input_tokens) : undefined;\n const cacheCreationTokens = usageRaw ? num(usageRaw.cache_creation_input_tokens) : undefined;\n const costUsd = num(payload.total_cost_usd);\n\n // Legacy fallbacks — only consulted when the modern key is missing.\n const legacyInput = num(payload.num_input_tokens);\n const legacyOutput = num(payload.num_output_tokens);\n const legacyCost = num(payload.cost_usd);\n\n const resolvedInput = inputTokens ?? legacyInput;\n const resolvedOutput = outputTokens ?? legacyOutput;\n const resolvedCost = costUsd ?? legacyCost;\n\n if (resolvedInput !== undefined) usage.inputTokens = resolvedInput;\n if (resolvedOutput !== undefined) usage.outputTokens = resolvedOutput;\n if (cacheReadTokens !== undefined) usage.cacheReadTokens = cacheReadTokens;\n if (cacheCreationTokens !== undefined) usage.cacheCreationTokens = cacheCreationTokens;\n if (resolvedCost !== undefined) usage.costUsd = resolvedCost;\n\n return Object.keys(usage).length > 0 ? usage : null;\n}\n\n/**\n * Sum two usages field by field.\n *\n * `undefined` means \"not reported\", not zero: a field absent on both sides\n * stays absent in the result, while a field present on a single side is\n * carried over untouched.\n */\nexport function sumUsage(\n a: ClaudeUsage | null | undefined,\n b: ClaudeUsage | null | undefined,\n): ClaudeUsage {\n const result: ClaudeUsage = {};\n\n for (const field of USAGE_FIELDS) {\n const left = a?.[field];\n const right = b?.[field];\n if (left === undefined && right === undefined) continue;\n result[field] = (left ?? 0) + (right ?? 0);\n }\n\n return result;\n}\n\n/**\n * Split a usage evenly across `parts`.\n *\n * This is the rateio used when several stories complete in the same execute\n * iteration: the iteration's tokens cannot be attributed to a single story, so\n * each one receives an equal share. Token counts are rounded to integers;\n * the cost keeps full precision.\n *\n * `parts <= 1` (or a non-finite value) returns the usage unchanged. Fields the\n * CLI never reported stay absent — dividing \"not reported\" still yields\n * \"not reported\", never zero.\n */\nexport function divideUsage(usage: ClaudeUsage | null | undefined, parts: number): ClaudeUsage {\n const result: ClaudeUsage = {};\n if (!usage) return result;\n\n const divisor = Number.isFinite(parts) && parts > 1 ? parts : 1;\n\n for (const field of USAGE_FIELDS) {\n const value = usage[field];\n if (value === undefined) continue;\n result[field] = field === 'costUsd' ? value / divisor : Math.round(value / divisor);\n }\n\n return result;\n}\n\n/**\n * Compact token count: `1523` → `1.5k`, `2_400_000` → `2.4M`.\n */\nfunction compactTokens(value: number): string {\n const abs = Math.abs(value);\n if (abs >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (abs >= 1_000) return `${(value / 1_000).toFixed(1)}k`;\n return String(Math.round(value));\n}\n\n/**\n * Human-readable one-liner, e.g. `2 in / 4 out · 15.5k cache · ~$0.1607`.\n *\n * Segments whose data is missing are omitted entirely — callers can rely on an\n * empty string meaning \"no metrics at all\" and skip the line altogether rather\n * than printing zeros or NaN.\n */\nexport function formatTokens(usage: ClaudeUsage | null | undefined): string {\n if (!usage) return '';\n\n const segments: string[] = [];\n\n const io: string[] = [];\n if (usage.inputTokens !== undefined) io.push(`${compactTokens(usage.inputTokens)} in`);\n if (usage.outputTokens !== undefined) io.push(`${compactTokens(usage.outputTokens)} out`);\n if (io.length > 0) segments.push(io.join(' / '));\n\n const cache =\n usage.cacheReadTokens !== undefined || usage.cacheCreationTokens !== undefined\n ? (usage.cacheReadTokens ?? 0) + (usage.cacheCreationTokens ?? 0)\n : undefined;\n if (cache !== undefined) segments.push(`${compactTokens(cache)} cache`);\n\n if (usage.costUsd !== undefined) segments.push(`~$${usage.costUsd.toFixed(4)}`);\n\n return segments.join(' · ');\n}\n\n/**\n * True when the usage carries at least one reported field. Handy for deciding\n * whether a metrics line or event is worth emitting at all.\n */\nexport function hasUsageData(usage: ClaudeUsage | null | undefined): boolean {\n if (!usage) return false;\n return USAGE_FIELDS.some((field) => usage[field] !== undefined);\n}\n","let _verbose = false;\n\nexport function setVerbose(enabled: boolean): void {\n _verbose = enabled;\n}\n\nexport function isVerbose(): boolean {\n return _verbose;\n}\n\nlet _onOutput: ((line: string) => void) | undefined;\n\n/**\n * Set a global output callback for routing verbose output (e.g., through listr2 task.output).\n * Pass undefined to clear and fall back to direct stderr writes.\n */\nexport function setOutputCallback(callback: ((line: string) => void) | undefined): void {\n _onOutput = callback;\n}\n\nexport function getOutputCallback(): ((line: string) => void) | undefined {\n return _onOutput;\n}\n\nlet _onStoryUpdate: ((stories: import('../types.js').UserStory[]) => void) | undefined;\n\n/**\n * Set a global callback for story progress updates during engine execution.\n * Called after each iteration with the latest user stories state.\n * Pass undefined to clear.\n */\nexport function setStoryUpdateCallback(\n callback: ((stories: import('../types.js').UserStory[]) => void) | undefined,\n): void {\n _onStoryUpdate = callback;\n}\n\nexport function getStoryUpdateCallback():\n | ((stories: import('../types.js').UserStory[]) => void)\n | undefined {\n return _onStoryUpdate;\n}\n\nlet _onStoryStage: ((storyId: string | undefined) => void) | undefined;\n\n/**\n * Set a global callback for the active story of the current `execute`\n * iteration. Called by `core/engine.ts` alongside every `iteration:start`\n * publication, with the same `storyId` (or `undefined` once every story\n * already passes) — the terminal renderer's only source for \"who is\n * executing right now\", never a second, independently computed heuristic.\n * Pass `undefined` to clear.\n */\nexport function setStoryStageCallback(\n callback: ((storyId: string | undefined) => void) | undefined,\n): void {\n _onStoryStage = callback;\n}\n\nexport function getStoryStageCallback(): ((storyId: string | undefined) => void) | undefined {\n return _onStoryStage;\n}\n\nlet _globalTimeout: number | undefined;\n\nexport function setGlobalTimeout(ms: number): void {\n _globalTimeout = ms;\n}\n\nexport function getGlobalTimeout(): number | undefined {\n return _globalTimeout;\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\nimport { getSessionPublisher } from '../core/session-publisher.js';\nimport type { SessionLogLevel } from '../core/session-state.js';\nimport { isoNow } from '../core/state-manager.js';\nimport { getOutputCallback } from '../core/verbose.js';\n\n/**\n * Detect if unicode output is supported.\n */\nexport function useUnicode(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\n/**\n * Detect if color output is supported.\n */\nexport function useColor(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\nexport interface Icons {\n success: string;\n fail: string;\n pending: string;\n retry: string;\n warn: string;\n start: string;\n end: string;\n notReached: string;\n tool: string;\n connector: string;\n}\n\nexport function getIcons(): Icons {\n if (useUnicode()) {\n return {\n success: '\\u2713',\n fail: '\\u2717',\n pending: '\\u23F3',\n retry: '\\u21BB',\n warn: '\\u26A0',\n start: '\\u25B6',\n end: '\\u25A0',\n notReached: '\\u25CB',\n tool: '\\u25B8',\n connector: '\\u2502',\n };\n }\n return {\n success: '[OK]',\n fail: '[FAIL]',\n pending: '[...]',\n retry: '[RETRY]',\n warn: '[WARN]',\n start: '[START]',\n end: '[END]',\n notReached: '[ ]',\n tool: '>',\n connector: '|',\n };\n}\n\n/**\n * Get the terminal width.\n */\nexport function getTermWidth(): number {\n return process.stdout.columns ?? 80;\n}\n\n/**\n * Emit a line of output. Routes through the global output callback when\n * running inside a listr2 task context, otherwise falls back to console.log.\n *\n * Also forwards the line to the session publisher with its structured level;\n * ANSI codes are stripped by the reducer, so terminal output stays untouched.\n */\nfunction emit(line: string, level: SessionLogLevel = 'info'): void {\n getSessionPublisher().publish({ type: 'log', at: isoNow(), level, message: line });\n const cb = getOutputCallback();\n if (cb) {\n cb(line);\n } else {\n console.log(line);\n }\n}\n\nexport function printSuccess(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.green(`${icons.success} ${message}`));\n } else {\n emit(`${icons.success} ${message}`);\n }\n}\n\nexport function printError(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.red(`${icons.fail} ${message}`), 'error');\n } else {\n emit(`${icons.fail} ${message}`, 'error');\n }\n}\n\nexport function printWarning(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.warn} ${message}`), 'warn');\n } else {\n emit(`${icons.warn} ${message}`, 'warn');\n }\n}\n\nexport function printRetry(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.retry} ${message}`), 'warn');\n } else {\n emit(`${icons.retry} ${message}`, 'warn');\n }\n}\n\nexport function printInfo(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.blue(`${icons.start} ${message}`));\n } else {\n emit(`${icons.start} ${message}`);\n }\n}\n\n/**\n * Create an ora spinner with consistent styling.\n */\nexport function createSpinner(message: string): Ora {\n return ora({\n text: message,\n color: 'blue',\n spinner: 'dots',\n });\n}\n\n/**\n * Format a duration in seconds to a human-readable string.\n */\nexport function formatDuration(totalSeconds: number): string {\n const hours = Math.floor(totalSeconds / 3600);\n const mins = Math.floor((totalSeconds % 3600) / 60);\n const secs = totalSeconds % 60;\n\n if (hours > 0) {\n return `${hours}h ${mins}m ${secs}s`;\n }\n if (mins > 0) {\n return `${mins}m ${secs}s`;\n }\n return `${secs}s`;\n}\n\n/**\n * Timer that calls a callback every second with the formatted elapsed time.\n */\nexport class ElapsedTimer {\n private startTime: number;\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private cleanup = () => this.stop();\n\n constructor(private onTick: (elapsed: string) => void) {\n this.startTime = Date.now();\n }\n\n start(): this {\n this.startTime = Date.now();\n this.intervalId = setInterval(() => {\n const seconds = Math.floor((Date.now() - this.startTime) / 1000);\n this.onTick(formatDuration(seconds));\n }, 1_000);\n // Prevent the timer from keeping the process alive\n if (this.intervalId && typeof this.intervalId === 'object' && 'unref' in this.intervalId) {\n this.intervalId.unref();\n }\n process.on('exit', this.cleanup);\n return this;\n }\n\n getElapsedSeconds(): number {\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n stop(): number {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n process.removeListener('exit', this.cleanup);\n return this.getElapsedSeconds();\n }\n}\n"],"mappings":"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","names":["rename","writeFile"]}