Commit graph

1397 commits

Author SHA1 Message Date
Tom Boucher
01d7200e7b fix: copy mcp.json into auto-mode worktrees (#2791) (#3251)
Add mcp.json to ROOT_STATE_FILES and copyPlanningArtifacts so MCP
server configurations are available inside worktrees.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:51:37 -06:00
Tom Boucher
01aea09f74 fix: add gsd_requirement_save and upsert path for requirement updates (#3249)
* fix: add gsd_requirement_save tool and upsert path for gsd_requirement_update (#2919)

gsd_requirement_update returned not_found for all requirements because
requirements written to REQUIREMENTS.md were never inserted into the DB,
and no create path existed. This adds:

- saveRequirementToDb() + nextRequirementId() in db-writer.ts (symmetric
  to saveDecisionToDb/nextDecisionId)
- gsd_requirement_save tool in db-tools.ts with auto-assigned IDs
- Upsert behavior in updateRequirementInDb() — creates a skeleton row
  when the requirement ID is not in the DB instead of throwing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add null check before reverting requirement on disk write failure

The `existing` variable from `getRequirementById` can be null when the
requirement was newly created (not previously in DB). Guard the revert
call to avoid passing null to `upsertRequirement`.

Fixes TypeScript error: 'Requirement | null' is not assignable to 'Requirement'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:51:26 -06:00
Tom Boucher
341a211be2 fix: use authoritative milestone status in web roadmap (#2807) (#3258)
* fix: use authoritative milestone status in web roadmap instead of slice heuristics (#2807)

The roadmap view was deriving milestone status from slice completion
flags, which disagrees with the actual GSD state model when milestones
have lifecycle states (complete/active/pending/parked) or validation
verdicts that differ from what slice progress implies.

Add status and validationVerdict fields to WorkspaceMilestoneTarget,
populate them from the state registry and VALIDATION files, and update
getMilestoneStatus() to prefer the authoritative status with a fallback
to the old heuristic for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add .js import extension and slice type annotations in workspace-status

Fixes TS2835 (missing .js extension for NodeNext resolution) and TS7006
(implicit any on slice callback parameters) that caused CI build failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: extract workspace types to .ts file to avoid jsx resolution error

Move WorkspaceTaskTarget, WorkspaceSliceTarget, WorkspaceMilestoneTarget,
and RiskLevel to workspace-types.ts so that workspace-status.ts (a plain
.ts file) can import them without requiring --jsx. The .tsx store file
re-exports the types for backward compatibility.

Fixes TS6142 in CI for PR #3258.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:50:57 -06:00
Tom Boucher
50fbd0a837 fix(docs): use ~/.pi/agent/extensions/ for community extension install path (#3131) (#3259)
Community extensions must be placed in ~/.pi/agent/extensions/, not
~/.gsd/agent/extensions/ which is reserved for bundled extensions synced
from the gsd-pi package. Extensions placed in the wrong path are silently
ignored by the loader.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:50:25 -06:00
Tom Boucher
d25dbb15fd fix: add disk→DB slice reconciliation in deriveStateFromDb (#2533) (#3262)
Slices defined in ROADMAP.md but missing from the SQLite database caused
permanent "No slice eligible — check dependency ordering" blocks. The
dependency resolver only considered DB rows, so disk-only slices were
invisible. This adds a reconciliation step (mirroring the existing
milestone reconciliation) that parses each milestone's ROADMAP.md,
compares against getMilestoneSlices(), and inserts missing slices with
correct status based on SUMMARY file presence.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:50:13 -06:00
Tom Boucher
0964c97931 fix: run forensics duplicate detection before investigation (#2704) (#3260)
Move the dedup check from after the Investigation Protocol to before it,
so already-known bugs are caught before spending tokens on deep source
analysis. The DEDUP_PROMPT_SECTION now acts as a pre-investigation gate
with a decision to skip full investigation when a match is found.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:50:06 -06:00
Tom Boucher
da135e9334 fix: persist forensics report context across follow-up turns (#2941) (#3261)
The forensics prompt was sent as a one-shot message via sendMessage()
with triggerTurn: true, causing context loss on follow-up turns. Now
writes an active-forensics.json marker to .gsd/runtime/ so that
buildBeforeAgentStartResult() can re-inject the forensics prompt on
subsequent turns, mirroring how guided task execution context works.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:49:50 -06:00
Tom Boucher
603839d7f8 fix: eliminate 3 recurring doctor audit false positives (#3105) (#3264)
Bug 1: orphaned worktree check now skips directories that only contain
doctor artifacts (.gsd/doctor-history.jsonl), preventing the circular
false positive where appendDoctorHistory recreates the dir it reports.

Bug 2: blocker_discovered_no_replan check now skips when all tasks are
done, treating the blocker as implicitly resolved and breaking the
deadlock with stale_replan_file.

Bug 3: parsePlan now scans the full body for task checkboxes after the
Tasks section, finding T02+ entries that appear after interleaved
detail headings (## Steps, ## Must-Haves).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:48:26 -06:00
Tom Boucher
795e160cc3 fix: treat ghost milestones as ineligible for parallel execution (#2501) (#3268)
Milestones with no registry entry (ghost directories with no planning
files) were falling through to eligible status due to the fallback
`entry?.status ?? "pending"` combined with empty deps. Now explicitly
classified as ineligible with "no planning data" reason before any
status/dep checks run.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:48:15 -06:00
Tom Boucher
81e303a483 fix: attempt VACUUM recovery when initSchema fails with corrupt freelist (#2519) (#3270)
When a file-backed database has a corrupted freelist, DDL operations
fail with "database disk image is malformed" even though integrity_check
passes. This adds VACUUM recovery to openDatabase() before re-throwing,
matching SQLite's documented recovery strategy for freelist corruption.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:47:13 -06:00
Tom Boucher
eab13c0ef5 fix: resolve db_unavailable loop in worktree/symlink layouts (#2517) (#3271)
Three fixes for the auto-mode regression where db_unavailable causes
infinite artifact-retry re-dispatch loops:

1. resolveProjectRootDbPath now handles /.gsd/projects/<hash>/worktrees/
   paths (symlink-resolved layout) in addition to /.gsd/worktrees/
2. ensureDbOpen emits structured diagnostics (resolvedPath, cwd, error)
   instead of silently returning false
3. Post-unit artifact retry skips when isDbAvailable() is false, treating
   DB infra failure as fatal instead of entering a retry loop

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:47:01 -06:00
Tom Boucher
7b72e1132c fix: correct OAuth fallback request shape for google_search (#2963) (#3272)
The searchWithOAuth() function sent a request body that the Cloud Code
Assist API rejected with 400 INVALID_ARGUMENT. Two issues:

1. URL was missing ?alt=sse query parameter (endpoint returns SSE format)
2. Request body was missing the required userAgent field

Also adds regression tests that capture the fetch call and assert the
request URL and body match the Cloud Code Assist wire contract.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:46:38 -06:00
Tom Boucher
37ec08d23c fix: prevent UAT stuck-loop and orphaned worktree after milestone completion (#3065)
Bug 1 -- UAT stuck-loop: syncProjectRootToWorktree used force:false for
all milestone files, which preserved stale ASSESSMENT files in the
worktree. When the project root had a passing verdict but the worktree
retained a FAIL copy (or lost it during DB rebuild), checkNeedsRunUat
found no passing verdict and re-dispatched run-uat indefinitely (x9).

Fix: after the additive-only safeCopyRecursive, walk ASSESSMENT files in
the project root and force-overwrite the worktree copy when the source
contains a verdict field. This is safe because ASSESSMENT verdicts are
only ever overwritten in a forward direction (FAIL -> PASS on retry).

Bug 2 -- Orphaned worktree: removeWorktree silently swallowed failures
from git worktree remove when untracked files (UAT-RESULT, ASSESSMENT)
blocked removal. The .git/worktrees/<name> internal directory held a
lock that also prevented the rmSync fallback from working.

Fix: after both native removal attempts fail, explicitly remove the git
internal .git/worktrees/<name> directory first, then retry rmSync on
the worktree filesystem directory. Log a warning with manual cleanup
instructions if the final attempt also fails.

Closes #2821

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:36:01 -06:00
Tom Boucher
47c1b9cd7f fix(mcp): handle server names with spaces in mcp_discover (#3037)
getServerConfig now trims whitespace and performs case-insensitive
matching so that names like "langgraph Code" resolve correctly.
getOrConnect uses config.name as the canonical cache key to prevent
duplicate connections from variant casing.

Closes #3029

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:29:14 -06:00
Tom Boucher
74c585074f fix(gsd): detect markdown body verdicts and guard plan-milestone against completed slices (#2960) (#3035)
Two fixes for the state corruption chain reported in #2960:

1. extractVerdict() now detects verdicts in markdown body patterns
   (e.g., **Verdict:** PASS) when YAML frontmatter is absent, preventing
   the state machine from looping on validating-milestone when LLMs write
   VALIDATION.md manually.

2. handlePlanMilestone() now refuses to re-plan a milestone that has
   completed slices, preventing INSERT OR IGNORE from shadowing completed
   work after worktree recreation or DB resync.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 13:28:51 -06:00
TÂCHES
8d0a81ff89 Merge pull request #2925 from gsd-build/fix/2923-double-startauto-race
fix(auto): guard startAuto() against concurrent invocation
2026-03-27 19:45:38 -06:00
Lex Christopherson
86f97885cc fix(auto): guard startAuto() against concurrent invocation (#2923)
checkAutoStartAfterDiscuss() fire-and-forgets startAuto() when a
milestone is ready. The headless runner then chains `/gsd auto`,
calling startAuto() a second time. Two concurrent auto-loops on the
same AutoSession singleton corrupt shared state (counters, dispatch
maps), causing planning/execution to never run after research.

Add an early `s.active` check at the top of startAuto() so the second
call no-ops. Add source-scanning test to enforce the guard exists.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:35:10 -06:00
NilsR0711
79da90edde fix(auto-dispatch): widen operational verification gate regex (fixes #2866) (#2898)
Three defects in the completing-milestone dispatch guard caused false
positive blocks on valid validation output:

1. Single-line constraint: [^\n]* stopped at newlines, missing verdicts
   on subsequent lines. Fixed with [\s\S]{0,500}? (bounded lazy match).

2. Missing keywords: 'satisfied' and 'partially' were absent from the
   alternation. LLMs commonly write 'PARTIALLY SATISFIED' or 'FULLY
   SATISFIED'. Added both.

3. Markdown bold delimiters: **Operational** blocked [\s:] after the
   word. The new [\s\S] class handles any character including *.

Also adds SATISFIED to the structuredMatch includes check, and  to
the prose regex (overlaps with #2862).

Includes 8 regression test cases covering multi-line formats, satisfied
keyword variants, markdown bold tables, and checkmark emoji.
2026-03-27 18:10:10 -06:00
Jordan Gaytan
558b1f2081 fix(parallel): three bugs preventing reliable parallel worker execution (#2801)
Bug 1 — Workers exit immediately (#2792):
spawnWorker() used `--print "/gsd auto"` which calls session.prompt()
that returns immediately when ctx.newSession() resets the session inside
the auto-loop. Changed to `headless --json auto` which uses an RPC
client that keeps the process alive until auto-mode completes.

Bug 2 — Dispatch guard blocks parallel workers (#2797):
getPriorSliceCompletionBlocker() checked ALL milestones in queue order,
blocking M012 when M011 had incomplete slices. When GSD_MILESTONE_LOCK
is set, the guard now only checks intra-milestone slice dependencies.
Added test covering cross-milestone bypass + intra-milestone preservation.

Bug 3 — Orphaned RPC children on stop (#2798):
stopParallel() gave only 750ms for SIGTERM before SIGKILL. The headless
parent needs ~1500ms to cascade shutdown to its RPC child via
client.stop(). Increased to 3000ms to prevent orphaned processes holding
auto.lock.

Updated tests:
- dispatch-guard.test.ts: new test for GSD_MILESTONE_LOCK bypass
- parallel-worker-monitoring.test.ts: updated spawn args assertion
2026-03-27 18:10:02 -06:00
mastertyko
6918fb76c6 fix(gsd): parse raw YAML under preference headings (#2794)
Accept raw YAML blocks beneath markdown preference headings while preserving legacy heading-list parsing.

Closes #2787
2026-03-27 18:09:48 -06:00
mastertyko
c88a9d2d4f fix(gsd): persist verification classes in milestone validation (#2820) 2026-03-27 18:09:39 -06:00
drkthng
6dd02bb3ce fix(gsd): guard reconcileWorktreeDb against same-file ATTACH corruption (#2825)
When worktrees use shared-WAL mode (R012), the worktree DB path resolves
to the same physical file as the project root DB via symlink. Calling
reconcileWorktreeDb() ATTACHes this WAL-mode file to itself, corrupting
the database with 'database disk image is malformed'.

Fix 1 — auto-worktree.ts mergeMilestoneToMain(): skip reconciliation
when isSamePath() confirms both DB paths resolve to the same file.

Fix 2 — gsd-db.ts reconcileWorktreeDb(): defence-in-depth realpathSync
guard inside the function itself, before the ATTACH statement.

Fix 3 — auto/infra-errors.ts: classify 'database disk image is
malformed' as SQLITE_CORRUPT infrastructure error so the auto-loop
stops immediately instead of burning 3 retries on a guaranteed failure.

Regression tests verify:
1. Same-file via symlink returns zero (no ATTACH)
2. Identical string paths return zero
3. Genuinely different DBs still reconcile normally
4. Malformed DB message classified as infra error
5. Transient SQLITE_BUSY is not falsely classified

Closes #2823
2026-03-27 18:08:13 -06:00
TÂCHES
44dd06fe66 Merge pull request #2868 from jeremymcs/fix/model-override-unittype-mapping
fix(model-routing): use honest unitTypes for discuss dispatches
2026-03-27 17:40:08 -06:00
TÂCHES
8a35b2308f Merge pull request #2887 from mastertyko/fix/subagent-project-agents-dir
fix(gsd): discover project subagents in .gsd
2026-03-27 17:39:36 -06:00
TÂCHES
f9dd134933 Merge pull request #2904 from mastertyko/fix/auto-resume-cold-db-bootstrap
fix(gsd): resume cold auto bootstrap from db
2026-03-27 17:39:07 -06:00
TÂCHES
ac85f28822 Merge pull request #2915 from gsd-build/fix/headless-completed-status
fix(headless): match "completed" status from RPC v2
2026-03-27 17:16:00 -06:00
Lex Christopherson
8870d84012 fix(headless): match "completed" status from RPC v2 in exit code mapper
mapStatusToExitCode only handled "complete" but RPC v2 emits "completed",
causing all headless sessions to falsely timeout and restart.

Also emits milestone-ready notification in checkAutoStartAfterDiscuss so
headless parent can detect and chain into auto-mode.

Closes #2914

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:04:31 -06:00
mastertyko
09de02adee fix(gsd): resume cold auto bootstrap from db
Open the project database before the first auto bootstrap derive so cold-start resume uses DB-backed slice state instead of stale markdown fallback state.

Also recognize glyph completion markers in roadmap tables and lock the new bootstrap ordering with regression coverage.

Closes #2841
2026-03-27 22:58:16 +01:00
mastertyko
6843d39971 fix(gsd): preserve first auto unit model after session reset
Auto-mode selected the correct unit model in runUnitPhase, but a fresh session could drop that selection before the first prompt was sent.

Persist the applied unit model on AutoSession, restore it immediately after newSession(), and cover the seam with a regression test that proves the model is re-applied before dispatch.

Closes #2853
2026-03-27 22:58:16 +01:00
mastertyko
142da7823a fix(gsd): prefer PREFERENCES.md in worktrees (#2796)
Keep auto-worktree sync and initial seeding aligned with the repo's canonical preferences filename while retaining the lowercase legacy fallback for older repos and case-sensitive filesystems.
2026-03-27 14:52:30 -06:00
Iouri Goussev
b6e105b058 perf(test): compile unit tests with esbuild, reclassify integration tests, fix node_modules symlink (#2809)
* fix(test): wire src/resources/extensions/shared/tests/ into test:unit runner

The test:unit glob excluded src/resources/extensions/shared/tests/ entirely,
leaving format-utils.test.ts (and any future tests there) silently unfired.

- Add shared/tests/*.test.ts to the test:unit glob in package.json
- Export newestSrcMtime from ensure-workspace-builds.cjs (require.main guard
  prevents side-effects on require) so the staleness logic can be tested
- Add src/tests/ensure-workspace-builds.test.ts covering newestSrcMtime:
  non-existent dir, no .ts files, single file, max of multiple, recursion,
  node_modules skip

Closes #2808

* perf(test): compile unit tests with esbuild and fix dist-test/node_modules

Replace per-file --experimental-strip-types with a single esbuild compilation
step (scripts/compile-tests.mjs) that compiles all src/ TypeScript to dist-test/
in ~3s, then runs the pre-compiled JS. Eliminates ~1.7s Node startup overhead
per test file.

- scripts/compile-tests.mjs: esbuild compilation, asset copy, .ts→.js rewrite,
  stale file cleanup; creates dist-test/node_modules symlink so resource-loader.ts
  resolves gsdNodeModules to a real path (fixes node-modules-symlink test failure)
- scripts/dist-test-resolve.mjs: ESM loader hook for @gsd/* bare specifiers and
  .ts→.js fallback rewriting at runtime
- .gitignore: exclude dist-test/ from version control
- package.json: add test:compile script; update test:unit to compile-then-run;
  update test:integration globs to cover new integration/ subdirectories
- worker-registry.ts: unref() cleanup timer so it does not keep the Node process
  alive after tests complete

Closes #2858

* fix(test): update relative imports in tests/integration/ after directory move

When tests were moved from tests/ to tests/integration/ in the previous
commit, relative imports weren't updated. ../foo now resolves one level
too shallow.

Fix all 117 import paths across 43 test files:
- ../foo → ../../foo (source files at gsd/ level)
- ../../get-secrets-from-user.ts → ../../../ (at extensions/ level)
- ../../subagent/worker-registry.ts → ../../../ (at extensions/ level)
- ./marketplace-test-fixtures.js → ../marketplace-test-fixtures.ts
- ./test-helpers.ts → ../test-helpers.ts

typecheck:extensions now passes with zero errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(integration): set 10-minute timeout for integration test runner

build job takes ~7min on main. Without a global timeout, hanging tests
block the suite indefinitely. --test-timeout=600000 caps each test at 10min.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert "test(integration): set 10-minute timeout for integration test runner"

This reverts commit be77ead77d369ad8569292ae6b69ba56435f5433.

* fix(test): correct formatDuration(0) edge case and docker test root path

- formatDuration(0) now returns '0s' instead of '0ms' by guarding the
  sub-second branch with ms > 0
- docker-template.test.ts root path goes ../../.. from dist-test/src/tests/
  to reach project root instead of landing in dist-test/
- replace require() calls in skill-health.ts and visualizer-overlay.ts
  with proper ES module imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): correct relative import paths in integration tests

All affected tests were one directory level off — importing from ../web/
and ../resources/ when the correct paths are ../../web/ and ../../resources/.
Tests live at src/tests/integration/, not src/tests/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): add esbuild to root devDeps and wire dist-test-resolve hook

P1: esbuild was only in web/package.json — compile-tests.mjs requires it
at the root node_modules path, so CI failed on clean installs.

P2: dist-test-resolve.mjs existed but was never loaded; @gsd/* imports in
compiled tests resolved to installed workspace packages instead of freshly
compiled dist-test output. Add --import to test:unit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(deps): align esbuild version with lock file (0.25.12)

^0.27.4 didn't satisfy the existing lock file entry. Use the version
already present so npm ci passes without regenerating the lock file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): correct all relative import depths in src/tests/integration/

Tests in src/tests/integration/ need 3 levels up (../../..) to reach
project-root dirs (web/, packages/) and 2 levels up (../..) to reach
src-level dirs (src/web/, src/cli-web-branch.ts).

Fixes:
- ../../web/lib/ → ../../../web/lib/   (Next.js app, not src/web/)
- ../../web/app/ → ../../../web/app/
- ../../packages/ → ../../../packages/
- ../cli-web-branch.ts → ../../cli-web-branch.ts
- ../web-mode.ts → ../../web-mode.ts
- ../resources/extensions/ → ../../resources/extensions/
- ci_monitor ROOT path: 2 levels up → 3 levels up
- web-responsive WEB_ROOT: 2 levels up → 3 levels up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(test): use dot reporter for test:unit to reduce noise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(test): switch test:unit reporter to tap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(test): compact test reporter — silent on pass, failures + summary only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(test): include shared/tests in test:coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): correct path depths in tests moved to integration/

Tests moved from tests/ to tests/integration/ need one extra ../
to reach the same source files. Also fix web component paths — those
files live at web/ not src/web/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): fix web component paths in web-session-parity-contract

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): use process.cwd() for project root in docker-template test

Resolving relative to __dirname breaks under test:coverage which runs
source files directly from src/tests/ — needs ../.. not ../../..
(the extra level only exists in the compiled dist-test/ output).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: retrigger CI

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:51:49 -06:00
Jordan Gaytan
48279ae5a4 feat(parallel): /gsd parallel watch — native TUI overlay for worker monitoring (#2806)
* feat(parallel): add /gsd parallel watch command and Ctrl+Alt+P overlay

Integrates the parallel worker monitor as a native pi-tui overlay that
renders inside the GSD session, matching the existing dashboard overlay
pattern (GSDDashboardOverlay / Ctrl+Alt+G).

Three integration points:
- /gsd parallel watch — opens the live monitor overlay
- Ctrl+Alt+P — keyboard shortcut (same pattern as Ctrl+Alt+G for status)
- Tab completion: 'watch' added to parallel subcommand completions

The overlay (ParallelMonitorOverlay) provides:
- Per-worker panels: health dot, phase label, slice/task progress bars
- Event feed: recent task completions from worktree SQLite DBs
- Cost tracking: status.json with NDJSON fallback for respawned workers
- Heartbeat: orchestrator timestamp or file mtime proxy
- Scrollable: arrow keys / j/k, ESC/q to close
- 5s auto-refresh via setInterval

Reuses all data-reading logic from the standalone scripts/parallel-monitor.mjs
(merged in #2799) but renders through the pi-tui theme system instead of
raw ANSI codes. Follows the same overlay registration pattern as the
GSD dashboard (register-shortcuts.ts + handlers/core.ts).

* fix(parallel): align overlay with Component interface, add tests

- Add invalidate() method required by Component interface
- Fix handleInput signature: void return, not boolean
- Fix Key usage: Key.escape/Key.down/Key.up (constants, not functions)
- Fix render signature: single width arg, not (width, height)
- Add resize listener cleanup in dispose()
- Add parallel-monitor-overlay.test.ts (satisfies require-tests CI gate)

* fix(parallel): use spawnSync for cross-platform path safety

Replace execSync template literals with spawnSync array args for sqlite3
calls. Paths with spaces or special chars broke on Windows because
execSync interpolates into a shell string. spawnSync passes args directly
to the process, bypassing shell interpretation.

Fixes cross-platform-filesystem-safety.test.ts assertion.
2026-03-27 14:51:18 -06:00
mastertyko
447a57ae0f fix(gsd): resume auto-mode after transient provider pause (#2822)
Transient provider recovery previously sent a hidden continue message after the backoff timer elapsed, but the auto loop had already exited. Resume the paused session through startAuto() instead so the timer actually restarts auto-mode, and cover the resumed, duplicate-resume, and missing-base-path cases with regression tests.

Closes #2813
2026-03-27 14:50:40 -06:00
Jeremy McSpadden
b8d4f03747 fix(parallel): resolve session lock contention and 3 related parallel-mode bugs (#2184) (#2800)
Per-milestone lock isolation prevents workers from contending on shared
.gsd/auto.lock. Budget ceiling scoped to current session for parallel
workers. Symlink sync skip prevents ERR_FS_CP_EINVAL. Planning artifacts
copied to worktree so workers can find their roadmap.

Closes #2184
2026-03-27 14:48:35 -06:00
mastertyko
a0b9a85a20 fix(gsd): preserve auto start model through discuss (#2837) 2026-03-27 14:47:14 -06:00
mastertyko
2c0f2b3893 fix(gsd): discover project subagents in .gsd
Prefer the documented .gsd/agents location for project-local subagents while keeping a legacy fallback to .pi/agents so existing workarounds continue to function. Add a regression test covering both paths.

Closes #2864
2026-03-27 21:41:45 +01:00
TÂCHES
1d5590c19a feat: headless text mode observability + skip UAT pause (#2867)
* feat: headless text mode shows tool calls + skip UAT pause in headless

Text mode observability:
- Tool calls always visible with summarized args (path, command, pattern)
- Tool errors surfaced even in non-verbose mode
- Cost updates shown periodically
- Empty [status] lines suppressed (setStatus/setWidget are TUI-only)
- Empty notify messages suppressed

UAT pause skip:
- Set GSD_HEADLESS=1 env var when spawning RPC child process
- auto-dispatch checks GSD_HEADLESS and skips pauseAfterDispatch for UAT
- Headless runs no longer stall waiting for human UAT verification

* test: add formatProgress unit tests for headless text mode

16 tests covering tool call display, arg summarization, cost formatting,
empty status suppression, and notify filtering.

* ci: retrigger
2026-03-27 12:13:17 -06:00
Jeremy
c622eec0e1 fix(model-routing): use honest unitTypes for discuss dispatches and map all auto-dispatch phases
Discuss dispatches in guided-flow.ts were aliased to "plan-milestone"/"plan-slice"
unitTypes, causing the planning model preference to silently override the user's
active model. This was discovered when a user configured Codex as their model but
got switched to Opus during discuss phases because models.planning was set.

Changes:
- Add "discuss" and "validation" keys to GSDModelConfig/GSDModelConfigV2
- Map discuss-milestone/discuss-slice to models.discuss (falls back to planning)
- Map reassess-roadmap/rewrite-docs/gate-evaluate/validate-milestone to
  models.validation (falls back to planning)
- Map reactive-execute to models.execution, complete-milestone to models.completion
- Fix 15 dispatchWorkflow calls in guided-flow.ts to use honest unitTypes
- Add discuss-slice to LIFECYCLE_ONLY_UNITS, artifact paths, metrics phase
  classification, complexity tiers, and all dashboard/overlay label functions

Closes #2865
2026-03-27 12:48:11 -05:00
mastertyko
36930694e4 fix(gsd): use project root for prior-slice dispatch guard (#2863)
Resolve the prior-slice completion guard against originalBasePath when auto-mode is running in a worktree. This keeps completed upstream milestones from blocking new dispatches because their SUMMARY state lives at the project root, not the stale worktree snapshot.

Closes #2838

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-03-27 11:29:03 -06:00
Lex Christopherson
8e1d523f4e feat: headless text mode shows tool calls + skip UAT pause in headless
Text mode observability:
- Tool calls now always visible with summarized args (path, command, pattern)
- Tool errors surfaced even in non-verbose mode
- Cost updates shown periodically ($0.05 4.2k in / 1.1k out)
- Empty [status] lines suppressed (setStatus/setWidget are TUI-only)
- Empty notify messages suppressed

UAT pause skip:
- Set GSD_HEADLESS=1 env var when spawning RPC child process
- auto-dispatch checks GSD_HEADLESS and skips pauseAfterDispatch for UAT
- Headless runs no longer stall waiting for human UAT verification
2026-03-27 11:06:43 -06:00
mastertyko
27f66100e5 fix(gsd): include queue context in milestone planning prompts (#2846)
* test(integration): suppress npm pack buffer overflows

* fix(gsd): include queue context in milestone planning prompts
2026-03-27 09:55:19 -06:00
mastertyko
2bc92afa6b fix(bg-shell): recover from deleted cwd in timers (#2850)
* test(integration): suppress npm pack buffer overflows

* fix(bg-shell): recover from deleted cwd in timers
2026-03-27 09:54:31 -06:00
mastertyko
905ee092ce fix(gsd): enable dynamic routing without models section (#2851)
* test(integration): suppress npm pack buffer overflows

* fix(gsd): enable dynamic routing without models section
2026-03-27 09:53:51 -06:00
mastertyko
9ce6e02bd8 fix: hydrate collected secrets for current session (#2788)
secure_env_collect previously persisted secrets to their destination but left the running Node process unchanged. Extensions like Context7 read process.env directly, so newly collected keys did not work until restart.

Hydrate process.env as soon as a secret is successfully applied, and cover the regression through collectSecretsFromManifest so the current session can use the key immediately.

Closes #2685
2026-03-26 20:33:20 -06:00
TÂCHES
9823fd2d2d fix: resolve stash pop conflicts and stop swallowing merge errors (#2780)
* fix: resolve stash pop conflicts and stop swallowing merge errors

After a squash merge, `git stash pop` can conflict on `.gsd/` state files,
leaving them in UU state that permanently blocks all subsequent milestone
merges. The post-commit stash pop catch block now detects `.gsd/` conflicts,
auto-resolves them by accepting the HEAD version (matching the existing
merge-time policy), and drops the stash when safe.

In phases.ts, three catch blocks only handled MergeConflictError and silently
continued on any other error, allowing auto-mode to advance to the next
milestone with unmerged work. All three now stop auto-mode and return a
"merge-failed" break result for non-conflict errors.

Closes #2766

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add regression tests for stash pop conflict and error handling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use correct LogComponent type in stash pop handler

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: join file array for logWarning in stash pop handler

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:16:42 -06:00
TÂCHES
f4736f47ae fix: treat any extracted verdict as terminal in isValidationTerminal (#2774)
* fix: treat any extracted verdict as terminal in isValidationTerminal

If the LLM writes a VALIDATION file with an unrecognized verdict like
`fail`, the allowlist in isValidationTerminal() returned false, keeping
the state machine in validating-milestone phase and re-dispatching
validate-milestone indefinitely (14+ times observed).

Any non-null verdict from extractVerdict() means validation completed.
Only return false when no verdict could be parsed.

Closes #2769

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add regression tests for isValidationTerminal with fail verdict

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: update existing test to match new any-verdict-is-terminal behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:09:00 -06:00
TÂCHES
d80927f50d fix: guard activeMilestone.id access in discuss and headless paths (#2776)
* fix: guard activeMilestone.id access in discuss and headless paths

When upstream state corruption (#2772, #2770) produces an activeMilestone
object with undefined id, the existing `!state.activeMilestone` guard
passes (truthy object), and the undefined id propagates to SQLite where
better-sqlite3 throws "Missing named parameter 'mid'".

Strengthen guards at three call sites to check `!state.activeMilestone?.id`
so corrupted state falls through to the no-milestone recovery path.

Closes #2773

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add regression tests for activeMilestone.id guard

Covers the #2773 fix where a malformed activeMilestone object with
id: undefined bypassed the old truthiness check and caused a crash
in discuss and headless paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:05:19 -06:00
TÂCHES
6af72210d1 fix: clean up zombie parallel workers stuck in error state (#2782)
* fix: clean up zombie parallel workers stuck in error state

refreshWorkerStatuses() set worker.state = "error" for dead workers but
never removed them or deactivated the orchestrator, leaving zombies in
memory forever. restoreRuntimeState() short-circuited on state?.active
without verifying any workers were actually alive.

Two fixes:
1. refreshWorkerStatuses() now checks if all workers are terminal after
   the status sweep — if so, deactivates the orchestrator and removes
   the persisted state file.
2. restoreRuntimeState() now verifies at least one worker is in a
   non-terminal state before returning true. If all workers are dead,
   it clears the stale cached state and falls through to restoreState()
   which handles proper cleanup.

Closes #2736

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add regression tests for zombie worker cleanup

Covers #2736: verifies refreshWorkerStatuses() deactivates orchestrator
when all workers reach terminal states, and restoreRuntimeState() clears
stale cached state instead of returning true with only dead workers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:04:46 -06:00
TÂCHES
be7466d99f fix: relax milestone validation gate to accept prose evidence (#2779)
* fix: relax milestone validation gate to accept prose evidence

The completion gate at auto-dispatch.ts required exact "MET"/"N/A"
substrings that renderValidationMarkdown() never emits, causing a
deadlock where no validation output could satisfy the gate. The gate
now accepts either the structured template format (MET/N/A table) or
prose evidence patterns (e.g., "Operational: verified", "Operational
checks confirmed") that the validation agent naturally produces.

Closes #2739

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add tests for relaxed validation gate patterns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:04:43 -06:00
TÂCHES
ce23da6718 fix: write milestone reports to project root instead of worktree (#2778)
* fix: write milestone reports to project root instead of worktree

During worktree isolation, s.basePath points to the temporary worktree
directory. Reports written there are silently lost when the worktree is
cleaned up. Use s.originalBasePath (falling back to s.basePath when not
in a worktree) so reports persist in the actual project directory.

Closes #2751

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add regression test for milestone report path resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:04:40 -06:00