gsd-pi 2.26.0 → 2.27.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 (171) hide show
  1. package/README.md +43 -6
  2. package/dist/cli.js +4 -2
  3. package/dist/headless.d.ts +3 -0
  4. package/dist/headless.js +136 -8
  5. package/dist/help-text.js +3 -0
  6. package/dist/loader.js +33 -4
  7. package/dist/resources/extensions/bg-shell/index.ts +19 -2
  8. package/dist/resources/extensions/bg-shell/process-manager.ts +45 -0
  9. package/dist/resources/extensions/bg-shell/types.ts +21 -1
  10. package/dist/resources/extensions/gsd/auto/session.ts +224 -0
  11. package/dist/resources/extensions/gsd/auto-budget.ts +32 -0
  12. package/dist/resources/extensions/gsd/auto-dashboard.ts +63 -10
  13. package/dist/resources/extensions/gsd/auto-direct-dispatch.ts +229 -0
  14. package/dist/resources/extensions/gsd/auto-dispatch.ts +23 -10
  15. package/dist/resources/extensions/gsd/auto-model-selection.ts +179 -0
  16. package/dist/resources/extensions/gsd/auto-observability.ts +74 -0
  17. package/dist/resources/extensions/gsd/auto-prompts.ts +0 -1
  18. package/dist/resources/extensions/gsd/auto-timeout-recovery.ts +262 -0
  19. package/dist/resources/extensions/gsd/auto-tool-tracking.ts +54 -0
  20. package/dist/resources/extensions/gsd/auto-unit-closeout.ts +46 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +207 -0
  22. package/dist/resources/extensions/gsd/auto.ts +977 -1551
  23. package/dist/resources/extensions/gsd/commands.ts +3 -3
  24. package/dist/resources/extensions/gsd/dashboard-overlay.ts +47 -72
  25. package/dist/resources/extensions/gsd/doctor-proactive.ts +9 -4
  26. package/dist/resources/extensions/gsd/export-html.ts +1001 -0
  27. package/dist/resources/extensions/gsd/export.ts +49 -1
  28. package/dist/resources/extensions/gsd/git-service.ts +6 -0
  29. package/dist/resources/extensions/gsd/gitignore.ts +4 -1
  30. package/dist/resources/extensions/gsd/guided-flow.ts +24 -5
  31. package/dist/resources/extensions/gsd/index.ts +54 -1
  32. package/dist/resources/extensions/gsd/native-git-bridge.ts +30 -2
  33. package/dist/resources/extensions/gsd/observability-validator.ts +21 -0
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.ts +231 -20
  35. package/dist/resources/extensions/gsd/preferences.ts +62 -1
  36. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -3
  37. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  38. package/dist/resources/extensions/gsd/reports.ts +510 -0
  39. package/dist/resources/extensions/gsd/roadmap-slices.ts +1 -1
  40. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +178 -0
  41. package/dist/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +54 -0
  42. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +59 -0
  43. package/dist/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +185 -0
  44. package/dist/resources/extensions/gsd/state.ts +30 -0
  45. package/dist/resources/extensions/gsd/templates/task-summary.md +9 -0
  46. package/dist/resources/extensions/gsd/tests/auto-dashboard.test.ts +13 -0
  47. package/dist/resources/extensions/gsd/tests/continue-here.test.ts +81 -0
  48. package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -0
  49. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +1 -0
  50. package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +1 -0
  51. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +10 -1
  52. package/dist/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +132 -0
  53. package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +14 -0
  54. package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +1 -0
  55. package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +1 -1
  56. package/dist/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +61 -0
  57. package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +51 -1
  58. package/dist/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +331 -0
  59. package/dist/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +298 -0
  60. package/dist/resources/extensions/gsd/tests/parallel-merge.test.ts +465 -0
  61. package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +39 -10
  62. package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +71 -0
  63. package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +42 -0
  64. package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +9 -9
  65. package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +743 -0
  66. package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +965 -0
  67. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +1 -1
  68. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +44 -10
  69. package/dist/resources/extensions/gsd/tests/worktree.test.ts +3 -1
  70. package/dist/resources/extensions/gsd/types.ts +38 -0
  71. package/dist/resources/extensions/gsd/verification-evidence.ts +183 -0
  72. package/dist/resources/extensions/gsd/verification-gate.ts +567 -0
  73. package/dist/resources/extensions/gsd/visualizer-data.ts +25 -3
  74. package/dist/resources/extensions/gsd/visualizer-overlay.ts +31 -21
  75. package/dist/resources/extensions/gsd/visualizer-views.ts +15 -66
  76. package/dist/resources/extensions/search-the-web/tool-search.ts +26 -0
  77. package/dist/resources/extensions/shared/format-utils.ts +85 -0
  78. package/dist/resources/extensions/shared/tests/format-utils.test.ts +153 -0
  79. package/dist/resources/extensions/subagent/index.ts +46 -1
  80. package/dist/resources/extensions/subagent/isolation.ts +9 -6
  81. package/package.json +1 -1
  82. package/packages/pi-ai/dist/providers/openai-completions.js +7 -4
  83. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  84. package/packages/pi-ai/src/providers/openai-completions.ts +7 -4
  85. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  86. package/packages/pi-coding-agent/dist/core/lsp/client.js +7 -0
  87. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  89. package/packages/pi-coding-agent/dist/core/lsp/config.js +9 -2
  90. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  91. package/packages/pi-coding-agent/src/core/lsp/client.ts +8 -0
  92. package/packages/pi-coding-agent/src/core/lsp/config.ts +9 -2
  93. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  94. package/packages/pi-tui/dist/components/editor.js +1 -1
  95. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  96. package/packages/pi-tui/src/components/editor.ts +3 -1
  97. package/scripts/link-workspace-packages.cjs +22 -6
  98. package/src/resources/extensions/bg-shell/index.ts +19 -2
  99. package/src/resources/extensions/bg-shell/process-manager.ts +45 -0
  100. package/src/resources/extensions/bg-shell/types.ts +21 -1
  101. package/src/resources/extensions/gsd/auto/session.ts +224 -0
  102. package/src/resources/extensions/gsd/auto-budget.ts +32 -0
  103. package/src/resources/extensions/gsd/auto-dashboard.ts +63 -10
  104. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +229 -0
  105. package/src/resources/extensions/gsd/auto-dispatch.ts +23 -10
  106. package/src/resources/extensions/gsd/auto-model-selection.ts +179 -0
  107. package/src/resources/extensions/gsd/auto-observability.ts +74 -0
  108. package/src/resources/extensions/gsd/auto-prompts.ts +0 -1
  109. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +262 -0
  110. package/src/resources/extensions/gsd/auto-tool-tracking.ts +54 -0
  111. package/src/resources/extensions/gsd/auto-unit-closeout.ts +46 -0
  112. package/src/resources/extensions/gsd/auto-worktree-sync.ts +207 -0
  113. package/src/resources/extensions/gsd/auto.ts +977 -1551
  114. package/src/resources/extensions/gsd/commands.ts +3 -3
  115. package/src/resources/extensions/gsd/dashboard-overlay.ts +47 -72
  116. package/src/resources/extensions/gsd/doctor-proactive.ts +9 -4
  117. package/src/resources/extensions/gsd/export-html.ts +1001 -0
  118. package/src/resources/extensions/gsd/export.ts +49 -1
  119. package/src/resources/extensions/gsd/git-service.ts +6 -0
  120. package/src/resources/extensions/gsd/gitignore.ts +4 -1
  121. package/src/resources/extensions/gsd/guided-flow.ts +24 -5
  122. package/src/resources/extensions/gsd/index.ts +54 -1
  123. package/src/resources/extensions/gsd/native-git-bridge.ts +30 -2
  124. package/src/resources/extensions/gsd/observability-validator.ts +21 -0
  125. package/src/resources/extensions/gsd/parallel-orchestrator.ts +231 -20
  126. package/src/resources/extensions/gsd/preferences.ts +62 -1
  127. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -3
  128. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  129. package/src/resources/extensions/gsd/reports.ts +510 -0
  130. package/src/resources/extensions/gsd/roadmap-slices.ts +1 -1
  131. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +178 -0
  132. package/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +54 -0
  133. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +59 -0
  134. package/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +185 -0
  135. package/src/resources/extensions/gsd/state.ts +30 -0
  136. package/src/resources/extensions/gsd/templates/task-summary.md +9 -0
  137. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +13 -0
  138. package/src/resources/extensions/gsd/tests/continue-here.test.ts +81 -0
  139. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -0
  140. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +1 -0
  141. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +1 -0
  142. package/src/resources/extensions/gsd/tests/derive-state.test.ts +10 -1
  143. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +132 -0
  144. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +14 -0
  145. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +1 -0
  146. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +1 -1
  147. package/src/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +61 -0
  148. package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +51 -1
  149. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +331 -0
  150. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +298 -0
  151. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +465 -0
  152. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +39 -10
  153. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +71 -0
  154. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +42 -0
  155. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +9 -9
  156. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +743 -0
  157. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +965 -0
  158. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +1 -1
  159. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +44 -10
  160. package/src/resources/extensions/gsd/tests/worktree.test.ts +3 -1
  161. package/src/resources/extensions/gsd/types.ts +38 -0
  162. package/src/resources/extensions/gsd/verification-evidence.ts +183 -0
  163. package/src/resources/extensions/gsd/verification-gate.ts +567 -0
  164. package/src/resources/extensions/gsd/visualizer-data.ts +25 -3
  165. package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -21
  166. package/src/resources/extensions/gsd/visualizer-views.ts +15 -66
  167. package/src/resources/extensions/search-the-web/tool-search.ts +26 -0
  168. package/src/resources/extensions/shared/format-utils.ts +85 -0
  169. package/src/resources/extensions/shared/tests/format-utils.test.ts +153 -0
  170. package/src/resources/extensions/subagent/index.ts +46 -1
  171. package/src/resources/extensions/subagent/isolation.ts +9 -6
@@ -86,7 +86,7 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
86
86
  { cmd: "stop", desc: "Stop auto mode gracefully" },
87
87
  { cmd: "pause", desc: "Pause auto-mode (preserves state, /gsd auto to resume)" },
88
88
  { cmd: "status", desc: "Progress dashboard" },
89
- { cmd: "visualize", desc: "Open workflow visualizer (progress, deps, metrics, timeline)" },
89
+ { cmd: "visualize", desc: "Open 10-tab workflow visualizer (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)" },
90
90
  { cmd: "queue", desc: "Queue and reorder future milestones" },
91
91
  { cmd: "quick", desc: "Execute a quick task without full planning overhead" },
92
92
  { cmd: "discuss", desc: "Discuss architecture and decisions" },
@@ -603,7 +603,7 @@ function showHelp(ctx: ExtensionCommandContext): void {
603
603
  "",
604
604
  "VISIBILITY",
605
605
  " /gsd status Show progress dashboard (Ctrl+Alt+G)",
606
- " /gsd visualize Interactive 7-tab TUI (progress, deps, metrics, timeline, agent, changes, export)",
606
+ " /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
607
607
  " /gsd queue Show queued/dispatched units and execution order",
608
608
  " /gsd history View execution history [--cost] [--phase] [--model] [N]",
609
609
  "",
@@ -625,7 +625,7 @@ function showHelp(ctx: ExtensionCommandContext): void {
625
625
  "",
626
626
  "MAINTENANCE",
627
627
  " /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
628
- " /gsd export Export milestone/slice results [--json|--markdown]",
628
+ " /gsd export Export milestone/slice results [--json|--markdown|--html]",
629
629
  " /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
630
630
  " /gsd migrate Upgrade .gsd/ structures to new format",
631
631
  " /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
@@ -20,17 +20,9 @@ import {
20
20
  import { loadEffectiveGSDPreferences } from "./preferences.js";
21
21
  import { getActiveWorktreeName } from "./worktree-command.js";
22
22
  import { getWorkerBatches, hasActiveWorkers, type WorkerEntry } from "../subagent/worker-registry.js";
23
-
24
- function formatDuration(ms: number): string {
25
- const s = Math.floor(ms / 1000);
26
- if (s < 60) return `${s}s`;
27
- const m = Math.floor(s / 60);
28
- const rs = s % 60;
29
- if (m < 60) return `${m}m ${rs}s`;
30
- const h = Math.floor(m / 60);
31
- const rm = m % 60;
32
- return `${h}h ${rm}m`;
33
- }
23
+ import { formatDuration, padRight, joinColumns, centerLine, fitColumns } from "../shared/format-utils.js";
24
+ import { STATUS_GLYPH, STATUS_COLOR } from "../shared/ui.js";
25
+ import { estimateTimeRemaining } from "./auto-dashboard.js";
34
26
 
35
27
  function unitLabel(type: string): string {
36
28
  switch (type) {
@@ -48,38 +40,6 @@ function unitLabel(type: string): string {
48
40
  }
49
41
  }
50
42
 
51
- function centerLine(content: string, width: number): string {
52
- const vis = visibleWidth(content);
53
- if (vis >= width) return truncateToWidth(content, width);
54
- const leftPad = Math.floor((width - vis) / 2);
55
- return " ".repeat(leftPad) + content;
56
- }
57
-
58
- function padRight(content: string, width: number): string {
59
- const vis = visibleWidth(content);
60
- return content + " ".repeat(Math.max(0, width - vis));
61
- }
62
-
63
- function joinColumns(left: string, right: string, width: number): string {
64
- const leftW = visibleWidth(left);
65
- const rightW = visibleWidth(right);
66
- if (leftW + rightW + 2 > width) {
67
- return truncateToWidth(`${left} ${right}`, width);
68
- }
69
- return left + " ".repeat(width - leftW - rightW) + right;
70
- }
71
-
72
- function fitColumns(parts: string[], width: number, separator = " "): string {
73
- const filtered = parts.filter(Boolean);
74
- if (filtered.length === 0) return "";
75
- let result = filtered[0];
76
- for (let i = 1; i < filtered.length; i++) {
77
- const candidate = `${result}${separator}${filtered[i]}`;
78
- if (visibleWidth(candidate) > width) break;
79
- result = candidate;
80
- }
81
- return truncateToWidth(result, width);
82
- }
83
43
 
84
44
  export class GSDDashboardOverlay {
85
45
  private tui: { requestRender: () => void };
@@ -95,6 +55,7 @@ export class GSDDashboardOverlay {
95
55
  private loadedDashboardIdentity?: string;
96
56
  private refreshInFlight: Promise<void> | null = null;
97
57
  private disposed = false;
58
+ private resizeHandler: (() => void) | null = null;
98
59
 
99
60
  constructor(
100
61
  tui: { requestRender: () => void },
@@ -106,6 +67,14 @@ export class GSDDashboardOverlay {
106
67
  this.onClose = onClose;
107
68
  this.dashData = getAutoDashboardData();
108
69
 
70
+ // Invalidate cache on terminal resize
71
+ this.resizeHandler = () => {
72
+ if (this.disposed) return;
73
+ this.invalidate();
74
+ this.tui.requestRender();
75
+ };
76
+ process.stdout.on("resize", this.resizeHandler);
77
+
109
78
  this.scheduleRefresh(true);
110
79
 
111
80
  this.refreshTimer = setInterval(() => {
@@ -233,7 +202,7 @@ export class GSDDashboardOverlay {
233
202
 
234
203
  handleInput(data: string): void {
235
204
  if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrlAlt("g"))) {
236
- clearInterval(this.refreshTimer);
205
+ this.dispose();
237
206
  this.onClose();
238
207
  return;
239
208
  }
@@ -332,12 +301,15 @@ export class GSDDashboardOverlay {
332
301
  const worktreeTag = worktreeName
333
302
  ? ` ${th.fg("warning", `⎇ ${worktreeName}`)}`
334
303
  : "";
335
- const elapsed = this.dashData.active || this.dashData.paused
336
- ? th.fg("dim", formatDuration(this.dashData.elapsed))
337
- : isRemote
338
- ? th.fg("dim", `since ${this.dashData.remoteSession!.startedAt.replace("T", " ").slice(0, 19)}`)
339
- : "";
340
- lines.push(row(joinColumns(`${title} ${status}${worktreeTag}`, elapsed, contentWidth)));
304
+ let elapsedParts = "";
305
+ if (this.dashData.active || this.dashData.paused) {
306
+ elapsedParts = th.fg("dim", formatDuration(this.dashData.elapsed));
307
+ const eta = estimateTimeRemaining();
308
+ if (eta) elapsedParts += th.fg("dim", ` · ${eta}`);
309
+ } else if (isRemote) {
310
+ elapsedParts = th.fg("dim", `since ${this.dashData.remoteSession!.startedAt.replace("T", " ").slice(0, 19)}`);
311
+ }
312
+ lines.push(row(joinColumns(`${title} ${status}${worktreeTag}`, elapsedParts, contentWidth)));
341
313
  lines.push(blank());
342
314
 
343
315
  if (this.dashData.currentUnit) {
@@ -435,23 +407,19 @@ export class GSDDashboardOverlay {
435
407
  lines.push(blank());
436
408
 
437
409
  for (const s of mv.slices) {
438
- const icon = s.done ? th.fg("success", "")
439
- : s.active ? th.fg("accent", "▸")
440
- : th.fg("dim", "");
441
- const titleText = s.active ? th.fg("accent", `${s.id}: ${s.title}`)
442
- : s.done ? th.fg("muted", `${s.id}: ${s.title}`)
443
- : th.fg("dim", `${s.id}: ${s.title}`);
410
+ const sliceStatus = s.done ? "done" : s.active ? "active" : "pending";
411
+ const icon = th.fg(STATUS_COLOR[sliceStatus], STATUS_GLYPH[sliceStatus]);
412
+ const titleColor = s.active ? "accent" : s.done ? "muted" : "dim";
413
+ const titleText = th.fg(titleColor, `${s.id}: ${s.title}`);
444
414
  const risk = th.fg("dim", s.risk);
445
415
  lines.push(row(joinColumns(` ${icon} ${titleText}`, risk, contentWidth)));
446
416
 
447
417
  if (s.active && s.tasks.length > 0) {
448
418
  for (const t of s.tasks) {
449
- const tIcon = t.done ? th.fg("success", "")
450
- : t.active ? th.fg("warning", "▸")
451
- : th.fg("dim", "·");
452
- const tTitle = t.active ? th.fg("warning", `${t.id}: ${t.title}`)
453
- : t.done ? th.fg("muted", `${t.id}: ${t.title}`)
454
- : th.fg("dim", `${t.id}: ${t.title}`);
419
+ const taskStatus = t.done ? "done" : t.active ? "active" : "pending";
420
+ const tIcon = th.fg(STATUS_COLOR[taskStatus], STATUS_GLYPH[taskStatus]);
421
+ const tColor = t.active ? "warning" : t.done ? "muted" : "dim";
422
+ const tTitle = th.fg(tColor, `${t.id}: ${t.title}`);
455
423
  lines.push(row(` ${tIcon} ${truncateToWidth(tTitle, contentWidth - 6)}`));
456
424
  }
457
425
  }
@@ -477,18 +445,21 @@ export class GSDDashboardOverlay {
477
445
 
478
446
  const recent = [...this.dashData.completedUnits].reverse().slice(0, 10);
479
447
  for (const u of recent) {
480
- const left = ` ${th.fg("success", "✓")} ${th.fg("muted", unitLabel(u.type))} ${th.fg("muted", u.id)}`;
481
-
482
- // Budget indicators from ledger
448
+ // Budget indicators from ledger use warning glyph for pressured units
483
449
  const ledgerEntry = ledgerLookup.get(`${u.type}:${u.id}`);
450
+ const hadPressure = ledgerEntry?.continueHereFired === true;
451
+ const hadTruncation = (ledgerEntry?.truncationSections ?? 0) > 0;
452
+ const unitGlyph = hadPressure
453
+ ? th.fg(STATUS_COLOR.warning, STATUS_GLYPH.warning)
454
+ : th.fg(STATUS_COLOR.done, STATUS_GLYPH.done);
455
+ const left = ` ${unitGlyph} ${th.fg("muted", unitLabel(u.type))} ${th.fg("muted", u.id)}`;
456
+
484
457
  let budgetMarkers = "";
485
- if (ledgerEntry) {
486
- if (ledgerEntry.truncationSections && ledgerEntry.truncationSections > 0) {
487
- budgetMarkers += th.fg("warning", ` ▼${ledgerEntry.truncationSections}`);
488
- }
489
- if (ledgerEntry.continueHereFired === true) {
490
- budgetMarkers += th.fg("error", " → wrap-up");
491
- }
458
+ if (hadTruncation) {
459
+ budgetMarkers += th.fg("warning", ` ▼${ledgerEntry!.truncationSections}`);
460
+ }
461
+ if (hadPressure) {
462
+ budgetMarkers += th.fg("error", " → wrap-up");
492
463
  }
493
464
 
494
465
  const right = th.fg("dim", formatDuration(u.finishedAt - u.startedAt));
@@ -634,6 +605,10 @@ export class GSDDashboardOverlay {
634
605
  dispose(): void {
635
606
  this.disposed = true;
636
607
  clearInterval(this.refreshTimer);
608
+ if (this.resizeHandler) {
609
+ process.stdout.removeListener("resize", this.resizeHandler);
610
+ this.resizeHandler = null;
611
+ }
637
612
  }
638
613
  }
639
614
 
@@ -173,14 +173,19 @@ export async function preDispatchHealthGate(basePath: string): Promise<PreDispat
173
173
  }
174
174
 
175
175
  // ── STATE.md existence check ──
176
- // If STATE.md is missing, rebuild it now so the next unit has accurate
177
- // context. Non-blocking — if the rebuild throws, dispatch continues anyway.
176
+ // If STATE.md is missing, attempt to rebuild it for the next unit's context.
177
+ // Non-blocking — fresh worktrees won't have it until the first unit completes (#889).
178
178
  try {
179
179
  const stateFile = resolveGsdRootFile(basePath, "STATE");
180
180
  const milestonesDir = join(gsdRoot(basePath), "milestones");
181
181
  if (existsSync(milestonesDir) && !existsSync(stateFile)) {
182
- await rebuildState(basePath);
183
- fixesApplied.push("rebuilt missing STATE.md before dispatch");
182
+ try {
183
+ await rebuildState(basePath);
184
+ fixesApplied.push("rebuilt missing STATE.md before dispatch");
185
+ } catch {
186
+ // Rebuild failed — non-blocking, dispatch continues
187
+ fixesApplied.push("STATE.md missing — will rebuild after first unit completes");
188
+ }
184
189
  }
185
190
  } catch {
186
191
  // Non-fatal — dispatch continues without STATE.md if rebuild fails