The DB-backed planning migration (#2280) moved 6 core modules to DB-primary
queries but left no fallback when DB is unavailable, breaking 19 tests in CI.
Source fixes: add file-based fallbacks in auto-direct-dispatch, auto-prompts,
auto-worktree, dispatch-guard, reactive-graph, visualizer-data, workspace-index,
and skill-health. Windows fixes: CRLF normalization, EPERM retry on rmSync,
path normalization. Enable --experimental-test-isolation=process to prevent
cross-test DB state leakage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: surface real doctor issue details in progress score widget
Previously the progress score traffic light (green/yellow/red) only
showed generic labels like "2 consecutive error units" or "Health
trend declining". The actual doctor issue descriptions were computed
in auto-post-unit but discarded before reaching the widget — only
aggregate counts were stored in HealthSnapshot.
Now the full data flows through:
- HealthSnapshot stores issue details (code, message, severity,
unitId) and fix descriptions alongside the counts
- recordHealthSnapshot() accepts optional issue/fix arrays
(backwards compatible — existing callers unchanged)
- getLatestHealthIssues() and getLatestHealthFixes() retrieve the
most recent details for display
- computeProgressScore() surfaces up to 5 real issue messages
(errors first) and up to 3 recent fixes as ProgressSignals
when the level is yellow or red
- Dashboard overlay renders signal details with ✓/✗/· icons
below the traffic light when degraded
This gives real-time visibility into what the auto-doctor is
detecting and fixing, without requiring manual /gsd doctor runs
or opening the full dashboard to investigate.
* feat: integrate doctor health data into visualizer and HTML reports
Phase 2b: close visibility gaps across visualizer and export surfaces.
Persistence (doctor.ts):
- Enrich DoctorHistoryEntry with issue details (severity, code,
message, unitId) and fix descriptions
- appendDoctorHistory now persists up to 10 issues per entry and
all fix descriptions to doctor-history.jsonl
- Export DoctorHistoryEntry type for consumers
Data layer (visualizer-data.ts):
- Add VisualizerDoctorEntry and VisualizerProgressScore types
- Extend HealthInfo with doctorHistory (last 20 persisted entries)
and progressScore (current in-memory traffic light)
- loadHealth reads doctor-history.jsonl synchronously and snapshots
current progress score when health data exists
TUI visualizer (visualizer-views.ts):
- Health tab now shows "Progress Score" section with traffic light
icon, summary, and all signal details (✓/✗/· prefixed)
- Health tab now shows "Doctor History" section with timestamped
entries, issue messages, and applied fixes
HTML export (export-html.ts):
- Health section includes progress score with colored indicator
and signal breakdown
- Health section includes "Doctor Run History" table with
timestamps, error/warning/fix counts, issue codes, expandable
issue messages, and fix descriptions
* feat: fill remaining health gaps — scope tagging, level notifications, human-readable logs
Gap fills:
Per-milestone/slice scope tagging:
- HealthSnapshot now stores scope (e.g. "M001/S02") from the
doctor run's unit context
- DoctorHistoryEntry persists scope to doctor-history.jsonl
- Visualizer and HTML reports display scope tags per entry
State transition notifications:
- setLevelChangeCallback() registers a handler for progress level
changes (green→yellow, yellow→red, red→green, etc.)
- auto-start.ts wires the callback to ctx.ui.notify on start
- auto.ts clears it on stop
- Notifications include the triggering issue message
Human-readable formatting throughout:
- formatHealthSummary() uses full words: "2 errors, 3 warnings ·
trend degrading · 1 fix applied · 1 of 5 consecutive errors
before escalation · latest: Missing PLAN.md for S03"
- DoctorHistoryEntry stores a human-readable summary field
built from error counts, fix counts, and top issue message
- Visualizer doctor history shows summary instead of "2E 1W 0F"
- HTML export doctor table uses summary column with scope tags
- Post-unit notification says what was fixed ("Doctor: rebuilt
STATE.md; cleared stale lock") instead of "applied 2 fix(es)"
Test updates:
- formatHealthSummary assertions updated for new readable format
* fix: default UAT type to artifact-driven to prevent unnecessary auto-mode pauses (#1651)
When a UAT file has no `## UAT Type` section, `extractUatType()` returns
`undefined`. The fallback was `"human-experience"`, causing `pauseAfterDispatch:
true` in the auto-dispatch rule. Since doctor-generated UAT placeholders never
include a UAT Type section and LLM-executed UATs are always artifact-driven,
the correct default is `"artifact-driven"`.
Closes#1649
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove duplicate doctorScope declaration (CI build fix)
* fix: resolve PR1644 regressions in health views and post-unit hook
---------
Co-authored-by: TÂCHES <afromanguy@me.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR #1527 fixed metrics.ts but missed several other paths that still
reach shared/mod.js → ui.js → @gsd/pi-tui during report generation
via native dynamic import() (which bypasses jiti alias resolution).
Remaining chains fixed:
- preferences.ts, preferences-validation.ts, export.ts, forensics.ts,
migrate/parsers.ts: import from shared/format-utils.js directly
- state.ts, visualizer-data.ts, files.ts: import from milestone-ids.js
instead of guided-flow.js (which pulls in shared/mod.js)
- files.ts: import checkExistingEnvKeys from new env-utils.ts instead
of get-secrets-from-user.ts (which imports @gsd/pi-tui)
New file: env-utils.ts extracts the pure checkExistingEnvKeys function.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add park/discard actions for in-progress milestones
Users could not discard, park, or skip milestones once work had begun.
The wizard only offered "Go auto" and "View status" for milestones with
a roadmap, trapping users with stale or deprioritized milestones.
This adds:
- Park mechanism: PARKED.md marker file in milestone directory.
deriveState() transparently skips parked milestones when finding the
active one. Parked milestones do NOT satisfy depends_on for downstream
milestones, preventing accidental unblocking.
- "Milestone actions" submenu in all four active-milestone wizard
branches (roadmap-exists, planning, summarizing, executing). Offers
Park / Discard / Skip / Back with clean navigation.
- /gsd park [id] and /gsd unpark [id] CLI subcommands for direct access.
- New module milestone-actions.ts with parkMilestone(), unparkMilestone(),
discardMilestone(), isParked(), getParkedReason() — keeps guided-flow
and commands thin.
- 14 tests (36 assertions) covering state derivation, dependency
semantics, park/unpark round-trip, discard with queue-order pruning,
and edge cases (all-parked, no-roadmap park, progress counts).
Files changed:
types.ts — Add 'parked' to MilestoneRegistryEntry.status
milestone-actions.ts — NEW: park/unpark/discard core logic
state.ts — Skip parked in getActiveMilestoneId + deriveState
guided-flow.ts — Milestone actions submenu in 4 wizard branches
commands.ts — /gsd park and /gsd unpark subcommands + help
guided-flow-queue.ts — Parked count in queue summary
visualizer-data.ts — Add 'parked' to VisualizerMilestone.status
park-milestone.test.ts — NEW: comprehensive test suite
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add edge case tests for park/discard milestone interactions
Covers 9 critical scenarios (31 assertions):
- Discard breaks depends_on chain → system correctly blocks
- Park blocks depends_on chain
- Queue order survives discards (QUEUE-ORDER.json pruned)
- Park all + discard all → clean pre-planning state
- Mixed states coexist (complete + parked + active + pending)
- Park then discard same milestone
- Discard milestone that has deps on others
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address critical review findings for park/discard feature
Fixes 7 issues found by adversarial code review:
1. CRITICAL: auto-mode crashed with "Unexpected: N incomplete" error when
all milestones were parked. Filter now excludes 'parked' status, and
pre-planning phase is recognized as a valid stop condition.
2. Merge-to-main was skipped when parked milestones existed — same
incomplete filter now excludes parked.
3. Completed milestones could be parked, corrupting depends_on
satisfaction. parkMilestone() now guards against SUMMARY.md existence.
4. Escape during park reason picker silently parked with literal
"not_yet" as reason. Now properly cancels the operation.
5. Parked milestones lost their human-readable title in registry
(showed ID instead). Phase 1 now caches roadmap for parked
milestones too, for title extraction.
6. GSD_MILESTONE_LOCK bypassed parked check — parallel workers locked
to a parked milestone now correctly return null.
7. Parked milestones were eligible for parallel execution, wasting
worker slots. parallel-eligibility now skips parked milestones.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: complete parked status display across all surfaces
- Visualizer: parked milestones show pause glyph (yellow) instead of
pending dot
- Doctor: parked milestones show pause emoji in registry report
- HTML export: add .dot-parked CSS (yellow), parked legend entry,
collapse parked milestone details by default
- Queue reorder: exclude parked milestones from movable list
Closes all remaining cosmetic findings from adversarial review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: TUI dashboard cleanup, dedup, and feature improvements
- Extract shared format-utils.ts: formatDuration, padRight, joinColumns,
centerLine, fitColumns, sparkline, stripAnsi — eliminating 3× duplication
across dashboard-overlay, visualizer-views, and auto-dashboard
- Use shared STATUS_GLYPH/STATUS_COLOR from ui.ts consistently across all
overlay and view files instead of hardcoded Unicode glyphs
- Fix redundant dynamic import('node:fs') in visualizer-data.ts (statSync
already imported at top level)
- Replace (entry as any) casts with proper SessionMessageEntry type narrowing
- Add mtime-based file content cache for visualizer data loader to avoid
re-parsing unchanged roadmap/plan files on every refresh
- Increase visualizer refresh interval from 2s to 5s (with mtime cache,
unchanged files are effectively free)
- Fix sparkline to use loop-based max instead of Math.max(...values) to
avoid stack overflow on large arrays
- Add ETA/time-remaining estimate to progress widget and dashboard overlay
based on average unit duration from metrics ledger
- Show warning glyph for budget-pressured units in completed units list
(continueHereFired units now show ⚠ instead of ✓)
- Add terminal resize (SIGWINCH) handling to both overlays — invalidates
cache and re-renders on window size change
- Fix dispose race in dashboard overlay close path — now calls dispose()
before onClose() to prevent timer callbacks firing after teardown
- Add 23 unit tests for format-utils.ts (including 100k-element sparkline)
- Add 2 tests for estimateTimeRemaining
- Add source-contract tests for resize handler and shared imports
* fix: use STATUS_GLYPH.warning instead of STATUS_GLYPH.statusWarning
STATUS_GLYPH is keyed by ProgressStatus ("warning"), not by GLYPH
property name ("statusWarning"). Fixes typecheck failure in CI.
YAML frontmatter parsers can return Date objects for ISO date strings
instead of plain strings. This caused a TypeError when calling
.localeCompare() on a Date object in the changelog sort.
Wrap completedAt with String() at both assignment and sort to handle
both native and JS parser paths safely.
* feat: add workflow visualizer TUI overlay with 4-tab interactive view
Add `/gsd visualize` command that opens a full-screen TUI overlay with
four tabs: Progress (milestone/slice/task tree), Dependencies (ASCII
dep graph), Metrics (cost/token bar charts), and Timeline (chronological
execution history). Supports Tab/1-4 switching, per-tab scrolling, and
auto-refresh every 2s. Opt-in auto-trigger hint after milestone
completion via `auto_visualize` preference.
New files:
- visualizer-data.ts: async data loader aggregating state + metrics
- visualizer-views.ts: 4 pure view renderers
- visualizer-overlay.ts: overlay class with tab/scroll/cache management
- tests/visualizer-views.test.ts: 21 assertions on view renderers
- tests/visualizer-data.test.ts: 33 source contract assertions
Modified:
- commands.ts: register "visualize" subcommand + handler
- auto.ts: milestone completion hint when auto_visualize enabled
- preferences.ts: add auto_visualize preference key
* feat: expand workflow visualizer with 8 new features across 7 tabs
Add critical path analysis, risk heatmap, cost projections, Gantt
timeline, live agent activity, diff/changelog, search/filter, and
export capabilities to the workflow visualizer overlay.
- Critical path: O(V+E) topological sort + longest path algorithm
with slack computation for milestones and slices
- Risk heatmap: colored block grid with legend and summary counts
- Cost projections: avg cost/slice, burn rate, sparkline, budget warnings
- Gantt timeline: horizontal bars with phase coloring and time axis
(falls back to list view on narrow terminals)
- Agent activity: real-time status, progress bar, completion rate
- Changelog: parsed SUMMARY files with mtime-based caching
- Search/filter: / enters filter mode, f cycles field, supports
keyword/status/risk filtering
- Export: standalone writeExportFile() + m/j/s keys for
markdown/JSON/snapshot export from overlay
Tab bar expanded from 4 to 7 tabs. 146 new test assertions across
4 test files. All 604 tests pass with zero regressions.
* fix: update help text to reflect 7-tab visualizer