Commit graph

1372 commits

Author SHA1 Message Date
Tom Boucher
ebe59a987f fix: use shell: true for LSP spawn on Windows to resolve .cmd executables (#1233)
On Windows, executables like npx, tsc, and typescript-language-server
are .cmd batch scripts. Node.js's spawn() can't find them without
shell: true because it looks for exact binary names, not .cmd wrappers.
This caused ENOENT crashes during auto-mode when the LSP tried to
spawn npx tsc --noEmit for TypeScript diagnostics.

Added shell: true conditional on process.platform === 'win32' in the
LSP client's spawn call. Unix platforms are unaffected.

Fixes #1222
2026-03-18 13:55:23 -06:00
Tom Boucher
11d962abb4 feat: add model health indicator to auto-mode progress widget (#1232)
Adds a traffic-light health indicator to the progress widget:
  🟢 progressing, 🟡 struggling, 🔴 stuck

Uses existing health tracker signals. No separate summary model needed.

Fixes #1221
2026-03-18 13:55:09 -06:00
Tom Boucher
99fdaa6ad8 fix: increase headless new-milestone timeout and limit investigation scope (#1230)
Two issues with headless new-milestone:

1. Default 300s timeout is too short — codebase investigation + artifact
   writing for a new milestone regularly exceeds 5 minutes. Bumped to
   600s (10 min) when the default hasn't been explicitly overridden.

2. The discuss-headless prompt's 'Investigate' step had no guidance on
   how much time to spend scouting. LLMs would exhaustively explore the
   codebase (50+ tool calls) before writing any artifacts, running out
   of time. Added 'brief' qualifier and 5-6 tool call budget with a
   note that the research phase does deeper investigation later.

The commit_docs: false preference is already respected — the prompt
correctly says 'Do not commit' when commit_docs is false, and
ensureGitignore idempotently skips when .gsd/ is already in .gitignore.

Fixes #1227
2026-03-18 13:54:34 -06:00
Tom Boucher
8c1f98bc3f fix: clean untracked .gsd/ files before squash-merge to prevent failure (#1239)
syncStateToProjectRoot copies .gsd/ files to the project root during
worktree execution. When .gsd/ is gitignored, these remain untracked.
Git refuses squash-merge because 'untracked working tree files would
be overwritten by merge.'

Added git clean -fd .gsd/ after autoCommitDirtyState and before the
branch checkout/merge sequence. This removes the untracked copies
without affecting tracked files.

Fixes #1237
2026-03-18 13:54:06 -06:00
TÂCHES
8ac58d88f0 feat: simplify auto pipeline — merge research into planning, mechanical completion (ADR-003) (#1235)
Reduces auto-mode session count from ~30 to ~16 per milestone by:

1. Merging research into planning: plan-milestone and plan-slice prompts
   now include exploration instructions instead of depending on separate
   research sessions. All profiles default skip_research/skip_slice_research.

2. Mechanical completion: new mechanical-completion.ts deterministically
   aggregates task summaries into slice/milestone artifacts (SUMMARY, UAT,
   VALIDATION, roadmap checkboxes) post-verification, eliminating LLM
   sessions for complete-slice and validate-milestone.

3. Reassess opt-in: reassess-roadmap now requires explicit
   reassess_after_slice: true instead of firing by default.

4. Reduced context inlining: plan prompts reference PROJECT/REQUIREMENTS/
   DECISIONS by path instead of inlining full content.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:53:51 -06:00
Tom Boucher
97d589c200 fix: graceful fallback when native addon is unavailable on unsupported platforms (#1225)
* fix: graceful fallback when native addon is unavailable on unsupported platforms

On platforms without a pre-built native binary (e.g., win32-arm64),
the native loader threw at import time, crashing the entire application.

Now returns a Proxy object that:
- Allows the import to succeed (no startup crash)
- Throws per-function when a native function is actually called
- Individual consumers (GSD parser bridge, fuzzy find, autocomplete)
  already wrap native calls in try/catch and fall back to JS
  implementations

Also exports nativeAvailable boolean for consumers that want to check
upfront. Prints a one-line warning to stderr on startup.

GSD is now fully functional on unsupported platforms — just slower for
file parsing, grep, and fuzzy search.

Fixes #1223

* fix: remove __nativeUnavailable from exported type to fix TS2352 cast errors

The __nativeUnavailable boolean property on the native type caused
TS2352 errors in consumers that cast native as Record<string, Function>
(ast/index.ts, diff/index.ts, gsd-parser/index.ts).

Replaced with a module-level _loadedSuccessfully flag and exported
nativeAvailable boolean. The proxy no longer needs a sentinel property.
2026-03-18 13:28:01 -06:00
TÂCHES
ec5cf03ae8 feat: add create-gsd-extension skill (#1229)
Self-contained skill for building GSD extensions (TypeScript modules that add
tools, commands, event hooks, custom UI, and providers).

Structure:
- SKILL.md: Router with essential principles (87 lines)
- 3 workflows: create, add capability, debug
- 16 references: complete domain knowledge extracted from extending-pi and
  pi-ui-tui docs (lifecycle, events, API surface, custom tools, commands, UI,
  rendering, state management, compaction, model/provider management, remote
  execution, packaging, mode behavior, gotchas)
- 2 templates: basic skeleton and stateful tool with rendering

Coverage:
- All 25 extending-pi docs
- All relevant pi-ui-tui docs (architecture, components, overlays, keyboard,
  theming, performance, common mistakes)
- GSD-specific paths (~/.gsd not ~/.pi)
- Zero external references — fully self-contained
2026-03-18 13:26:28 -06:00
Tom Boucher
1e76459813 fix: replace ambiguous double-question in discussion reflection step (#1226)
The plain-text fallback for depth verification asked 'Did I capture
that correctly? Anything I missed?' — two yes/no questions where a
short affirmative maps to opposite intents (yes = confirmed vs yes =
missed something).

Changed to: 'Did I capture that correctly? If not, tell me what I
missed.' — one question, then an instruction, following the pattern
established in #963.

Fixes #1224
2026-03-18 13:26:06 -06:00
TÂCHES
b9b72180da feat: add built-in skill authoring system (ADR-003) (#1228)
Port the create-agent-skills skill from ~/.claude/skills/ to bundled
resources with GSD-specific adaptations: dual directory support
(~/.gsd/agent/skills/ global, .pi/agent/skills/ project-local),
auto-discovery integration, /reload activation, and telemetry/health
references. 25 files: 1 router SKILL.md, 9 workflows, 13 references,
2 templates.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:16:56 -06:00
Jeremy McSpadden
1e82411dcb feat(prefs): two-step provider→model picker in preferences wizard (#1218)
Replace the flat model list with a two-step selection: pick provider
first, then pick a model within that provider. Models are sorted
alphabetically within each group. Adds a "(type manually)" escape
hatch for arbitrary model IDs.
2026-03-18 12:26:49 -06:00
Tom Boucher
36d62e048c fix: kill non-persistent bg processes between auto-mode units (#1217)
Background processes spawned during one task (e.g., Vite dev servers
for browser-based verification) were not cleaned up when the unit
completed. The orphaned server kept the port bound, causing the next
unit's dev server launch to fail or conflict. This led to stuck-loop
anomalies, cost spikes from timeout recovery retries, and port conflicts.

Added killSessionProcesses() to bg-shell process-manager — kills all
alive, non-persistent processes using SIGTERM. Called in auto-post-unit
after pruneDeadProcesses(). Processes with persistAcrossSessions: true
are preserved.

Fixes #1209 (orphaned processes part; the subagent bundled-extension-paths
bug is already fixed on main since a2a701b1)
2026-03-18 12:26:34 -06:00
Tom Boucher
0bce301cba docs: update README for v2.29.0 release (#1213)
- What's New section updated from v2.28 to v2.29 with all new features
- Node.js requirement updated: >=20.6.0 → >=22.0.0 (24 LTS recommended)
- Added /gsd logs to commands table
- Added searchExcludeDirs to configuration table
- Added Remote Questions and Dynamic Model Routing to docs listing
- Updated bundled extensions count 14 → 16, added Remote Questions
  and Universal Config entries
- Verification enforcement section updated to mention advisory mode
  for auto-discovered checks
2026-03-18 12:26:24 -06:00
TÂCHES
28c741c196 refactor: replace MCPorter with native MCP client (#1210)
* refactor: replace MCPorter CLI with native MCP client using @modelcontextprotocol/sdk

MCPorter is a third-party global CLI that fails to install on many systems,
producing error noise on every startup. Replace it with a native extension
that uses the already-bundled @modelcontextprotocol/sdk Client class directly.

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

* docs: update README extension table from MCPorter to MCP Client

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

* fix: add .js suffix to MCP SDK subpath imports for NodeNext resolution

The SDK wildcard export (./*) requires .js suffix for TypeScript NodeNext
module resolution. Also add .js-suffixed virtual module keys so jiti
resolves them correctly in compiled Bun binaries.

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-18 12:26:16 -06:00
Jeremy McSpadden
d3780c9bdb fix: Two-column dashboard layout with task checklist (#1195)
* feat(dashboard): two-column layout with task checklist

Redesign the auto-mode progress widget to use the full terminal width
with a two-column layout:

Left column (~55%): task checklist with done/active/pending glyphs
Right column (~45%): progress bar, ETA, next step, token stats, model

Additional changes:
- Merge project name, slice, and action into a single context line
- Tighten spacing (single spaces, compact hint separator)
- Collapse 5 blank separator lines down to 2
- Cache task details (id, title, done) in slice progress cache
- Footer merges pwd and keybinding hints onto one line

* refactor(dashboard): swap columns — stats left, tasks right

Move progress/ETA/tokens/model to the left column (45%) and task
checklist to the right column (55%) for better visual scanning.

* feat(dashboard): fixed-width right column with narrow fallback

Peg the task checklist to a fixed 44-char right column so it stays
readable at any width. The left column (stats/progress) flexes to
fill remaining space. Below 80 cols, falls back to single-column
stacked layout.

Also adds scripts/preview-dashboard.ts — a visual test harness
that renders the widget with mock data at any terminal width:
  npx tsx scripts/preview-dashboard.ts [width]

* refactor(dashboard): swap columns — tasks left, stats right

Move task checklist back to the left column (fixed 44 chars) and
progress/ETA/tokens/model to the right column (flexes to fill).
Narrow fallback (<80 cols) stacks tasks then progress inline.

* refactor(dashboard): stats left, tasks pegged right with growing gap

Both columns are fixed width (44 chars each). The gap between them
grows as the terminal widens, keeping the task checklist anchored to
the right edge. At narrow widths (<80), falls back to single-column
with stats then tasks stacked.

* refactor(dashboard): move task column to middle, adjacent to stats

Both columns are now fixed-width and adjacent (44 + 3 + 44 = 91 chars).
Empty space flows to the right instead of between columns. The layout
stays stable regardless of terminal width.

* refactor(dashboard): flex left column, fixed right with gap

Left column now flexes to fill available space — no more truncation
on wide terminals. Right column (task checklist) stays fixed at 44
chars with a 5-char gap before the divider. Min width for two-column
mode raised to 100.
2026-03-18 12:26:02 -06:00
Jeremy McSpadden
b0c3ab5781 feat: workflow templates — right-sized workflows for every task type (#1185)
* feat: add workflow templates — named workflow shapes for different types of work

Introduces `/gsd start <template>` and `/gsd templates` commands with 8 built-in
workflow templates: bugfix, small-feature, spike, hotfix, refactor, security-audit,
dep-upgrade, and full-project. Each template defines purpose-specific phases so
work gets the right level of ceremony instead of forcing everything through the
full milestone pipeline or /gsd quick.

Includes auto-detection from natural language, --dry-run preview, state tracking
for resume support, git branch management, and artifact directory organization.

* fix: guard workflow templates against concurrent auto-mode sessions

Block /gsd start when auto-mode is active to prevent git branch conflicts
and competing message dispatch. When auto-mode is paused, allow templates
to run with an informational notice.

* feat: add workflow resume and in-progress detection

- /gsd start resume — resumes the most recent in-progress workflow
- /gsd start (no args) — shows in-progress workflow if one exists
- STATE.json tracks artifactDir and completedAt for lifecycle management
- Scans .gsd/workflows/*/STATE.json to find unfinished workflows

* chore: remove copyright headers per project conventions
2026-03-18 12:25:28 -06:00
TÂCHES
0fdf52625b refactor: extend json-persistence utility and migrate top JSON I/O callsites (#1216)
Add writeJsonFileAtomic to json-persistence.ts for atomic write-to-tmp-then-rename.
Migrate 5 files from raw JSON.parse(readFileSync(...)) to loadJsonFileOrNull/writeJsonFileAtomic/saveJsonFile:
- session-status-io.ts: all read/write/signal functions
- auto-worktree-sync.ts: readResourceVersion
- auto-recovery.ts: persistCompletedKey, removePersistedKey, loadPersistedKeys
- commands-logs.ts: metrics summary read
- queue-order.ts: loadQueueOrder, saveQueueOrder

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 12:06:01 -06:00
TÂCHES
3a0999c6db refactor: deduplicate dispatchDoctorHeal — keep single copy in commands-handlers.ts (#1211)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 12:05:41 -06:00
TÂCHES
93edbc20d2 refactor: remove facade re-exports from auto.ts — import directly from source modules (#1214)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:58:49 -06:00
TÂCHES
f78ec37f1b refactor: extract shared HTTP client for remote-questions adapters (#1212)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:58:43 -06:00
github-actions[bot]
d57b117aea release: v2.29.0 2026-03-18 17:44:12 +00:00
TÂCHES
b3e2a3b558 refactor: extract numeric validation helpers in prefs wizard (#1205)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:35:23 -06:00
TÂCHES
d94a7f1a5d refactor: deduplicate projectRoot() and dispatchDoctorHeal() between commands.ts and commands-handlers.ts (#1203)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:32:31 -06:00
Tom Boucher
e45bff419d fix(ci): add npm publish to prod-release and prevent mid-deploy cancellation (#1208)
Two issues in the pipeline:

1. cancel-in-progress: true could cancel a running deployment when a
   new push arrives. Deployments should never be interrupted mid-flight.
   Changed back to false.

2. The prod-release job bumps the version, commits, and tags — but never
   publishes the release version to npm. The dev-publish step publishes
   @dev, test-verify promotes to @next, but @latest was never updated.
   Users running 'npm install -g gsd-pi' would get stale versions.

Added 'Build release' and 'Publish release to npm @latest' steps after
the git tag push, with idempotent guard for already-published versions.
2026-03-18 11:31:42 -06:00
Lex Christopherson
a0a341e3d3 fix(ci): use env var for Discord webhook secret in if-condition
GitHub Actions doesn't allow secrets context in if expressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:26:51 -06:00
TÂCHES
f824bd2007 refactor: extract shared JSON persistence utility, migrate metrics + routing-history + unit-runtime (#1206)
Eliminates repeated try/catch JSON file load/save boilerplate across three
modules by introducing loadJsonFile, loadJsonFileOrNull, and saveJsonFile
in a shared json-persistence.ts utility.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:25:32 -06:00
TÂCHES
ba6a7d5ee9 chore: remove unused preferences-hooks.ts re-export facade (#1207)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:25:28 -06:00
TÂCHES
0b8254bfa0 refactor: remove commands.ts re-exports, import directly from submodules (#1204)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:23:54 -06:00
Tom Boucher
0f97f938f7 feat: add searchExcludeDirs setting for @ file autocomplete blacklist (#1202)
Implements the directory blacklist feature from #660 (incomplete items 3-4).

Users can now configure directories to exclude from the @ file picker
and fuzzy search via settings.json:

  { "searchExcludeDirs": ["node_modules", ".git", "dist", "build"] }

Changes:
- settings-manager.ts: added searchExcludeDirs setting with get/set
- autocomplete.ts (pi-tui): CombinedAutocompleteProvider accepts
  excludeDirs option, filters excluded directory names in both
  readdir-based and native fuzzy search paths
- interactive-mode.ts: passes searchExcludeDirs to the provider

The native fd fuzzy search already respects .gitignore. This setting
covers directories that aren't gitignored but shouldn't appear in
autocomplete (e.g., large vendor dirs, build outputs in projects
without comprehensive .gitignore).

Fixes #1190
2026-03-18 11:23:40 -06:00
TÂCHES
3c50cbb504 refactor: extract frontmatter body extraction into shared helper (#1201)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:23:32 -06:00
TÂCHES
97b7c0b18a Merge pull request #1200 from gsd-build/fix/unit-runtime-sanitization
fix: broaden unit-runtime path sanitization
2026-03-18 11:22:03 -06:00
TÂCHES
5c45f9e4c8 cleanup: remove dead widgets and identity function (#1199)
Delete thinking-widget.ts and progress-widget.ts (fully implemented
but never imported anywhere) and remove the buildDirName identity
function from paths.ts.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:20:56 -06:00
TÂCHES
0b22394496 fix: complete shared barrel exports and add import-claude to help text (#1198)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:20:25 -06:00
TÂCHES
9cbd179bf9 refactor: deduplicate projectRoot() — single source in commands.ts (#1197)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:20:14 -06:00
TÂCHES
f99189d410 refactor: extract PER_REQUEST_TIMEOUT_MS to shared types (#1196)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:20:04 -06:00
TÂCHES
45247b7dd2 feat(ci): automate prod-release with version bump, changelog, and tag push (#1194)
When the prod environment gate is approved, the pipeline now automatically
determines the semver bump from conventional commits, generates a changelog
entry, bumps all package versions, commits + tags + pushes (triggering
build-native.yml for npm @latest), creates a GitHub Release, and posts
to Discord.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:17:43 -06:00
Lex Christopherson
05bd7089f3 fix: broaden unit-runtime path sanitization to strip all unsafe characters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:15:33 -06:00
TÂCHES
5a36c131a9 fix: detect stale bundled resources via content fingerprint (#1193)
initResources() only re-synced when the GSD version changed. This meant
same-version content fixes (e.g. the subagent bundled-extension-paths.js
import fix in a2a701b1) never reached ~/.gsd/agent/extensions/ because
the version-only check saw 2.28.0 == 2.28.0 and skipped the sync.

Add a lightweight content fingerprint (sha256 of file paths + sizes) to
the managed-resources.json manifest. On startup, if the version matches
but the fingerprint doesn't, resources are re-synced. This covers:

- npm link dev workflows where source changes without version bumps
- hotfixes within a release that change bundled extension content
- upgrades from manifests without contentHash (treated as stale)

Cost: ~1ms of stat calls on ~100 files — no file reads needed.
2026-03-18 11:06:09 -06:00
Tom Boucher
1236919c39 fix: include promptGuidelines in customPrompt path of buildSystemPrompt (#1187)
When buildSystemPrompt() receives a customPrompt (as GSD's contract
provides), it returned early without appending promptGuidelines from
extension-registered tools. The tool definitions still reached the
API's tools parameter, but without prompt guidance the model didn't
know when to prefer them — causing subagent tools to be silently
ignored in favor of async_bash/bg_shell.

Added promptGuidelines append after date/time in the customPrompt
path, matching the behavior of the non-custom path.

Fixes #1184
2026-03-18 10:55:16 -06:00
Tom Boucher
60508c2ec2 fix: prevent branch-mode merge fallback from firing in worktree isolation (#1183)
The milestone merge dispatcher in dispatchNextUnit had two 'else if'
blocks that matched when !isInAutoWorktree() && getIsolationMode() !== 'none'.
In worktree mode, if isInAutoWorktree() returned false (e.g., after cwd
was changed back to project root), the branch-mode fallback fired and
ran 'git checkout main' — which fails because main is already checked
out at the project root.

Changed the condition from 'getIsolationMode() !== "none"' to
'getIsolationMode() === "branch"' so the branch-mode merge path only
fires when the user explicitly configured branch isolation. Worktree
mode now correctly falls through without attempting an invalid checkout.

Both instances (all-complete path and milestone-transition path) are fixed.

Fixes #1179
2026-03-18 10:54:28 -06:00
Tom Boucher
c442e2d97e fix: treat auto-discovered verification failures as advisory, not blocking (#1188)
When the verification gate auto-discovers commands from package.json
(typecheck, lint, test), failures on pre-existing errors create a doom
loop: execute → fail → auto-fix → still fails → retry exhausted → pause.
The agent can't fix pre-existing lint/test errors it didn't introduce.

Now, when discoverySource is 'package-json', gate failures are logged
as warnings and the task proceeds without triggering the retry loop.
Explicitly configured checks (via preferences or task plan verify field)
still trigger the full retry cycle.

This preserves the safety of user-configured verification while
preventing auto-discovered checks from blocking on inherited tech debt.

Fixes #1186
2026-03-18 10:54:16 -06:00
Lex Christopherson
5b36754a19 fix(ci): remove @latest npm promotion from pipeline
Dev-stamped versions (2.28.0-dev.xxx) should never be promoted to
@latest on npm. Stable releases are handled by the publish-version
workflow. The pipeline promotes @dev → @next only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:45:39 -06:00
Lex Christopherson
119c8d74b4 fix(ci): skip GitHub release creation when tag already exists
Multiple pipeline runs for the same base version produce identical
release tags, causing E422. Check if release exists before creating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:27:48 -06:00
Tom Boucher
4c98d3e708 fix: handle Windows non-ASCII paths in cpSync with copyFileSync fallback (#1181)
Node.js's cpSync fails on Windows when the path contains non-ASCII
characters (e.g. C:\Users\Görloff) due to the \\?\ extended-length path
prefix not handling Unicode correctly. This affects both the build
script (copy-assets.cjs) and the runtime resource sync (resource-loader.ts).

Added a try/catch fallback: when cpSync throws, fall back to a manual
recursive copy using copyFileSync which handles non-ASCII paths correctly.

Changed files:
- src/resource-loader.ts: syncResourceDir() catches cpSync failure and
  falls back to copyDirRecursive()
- packages/pi-coding-agent/scripts/copy-assets.cjs: all cpSync calls
  wrapped in safeCpSync() with the same fallback

Fixes #1178
2026-03-18 10:13:37 -06:00
TÂCHES
58903093cd fix: non-blocking verification gate for auto-discovered commands (#1177)
* fix: make package-json discovered verification commands non-blocking (advisory only)

Auto-discovered commands from package.json scripts (typecheck, lint, test) are
advisory: their failures are logged as warnings but do not block the gate or
trigger retries. Only explicitly configured preference commands and task-plan
verify commands remain blocking.

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

* fix: add missing blocking field to verification-evidence test fixtures

The previous commit added `blocking: boolean` to VerificationCheck but
only updated verification-gate.test.ts. The evidence test file had 26
VerificationCheck literals missing the new required field.

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-18 10:13:28 -06:00
Tom Boucher
8d04ec19fd fix: add defensive guards against undefined .filter() in auto-mode dispatch/recovery (#1180)
Auto-mode crashed with 'Cannot read properties of undefined (reading
filter)' during partial execute-task recovery when derived state was
structurally incomplete.

Added ?? [] fallback guards on all .filter()/.find()/.map() calls
that access state.registry, roadmap.slices, or similar derived arrays
in the dispatch and recovery paths:

- auto.ts: 3 state.registry.filter() calls
- auto-recovery.ts: 1 roadmap.slices.find() call
- auto-start.ts: 1 state.registry.filter() call

These are belt-and-suspenders guards — the parsers always return arrays,
but crash recovery can encounter partially written or corrupt state files
where the parsers return unexpected shapes.

Fixes #1176
2026-03-18 10:07:22 -06:00
Tom Boucher
8281a2ea75 fix: sync living docs (DECISIONS/REQUIREMENTS/PROJECT/KNOWLEDGE) between worktree and project root (#1173)
syncStateToProjectRoot() copied STATE.md, milestone directories,
completed-units.json, and runtime records — but not the four root-level
living documents. When agents updated these during slice execution in a
worktree, a new session would read stale copies from the project root,
losing decisions, requirement status changes, project descriptions, and
accumulated knowledge.

Added bidirectional sync for DECISIONS.md, REQUIREMENTS.md, PROJECT.md,
and KNOWLEDGE.md:
- Worktree → project root: in syncStateToProjectRoot() after runtime records
- Project root → worktree: in syncProjectRootToWorktree() before milestone sync

Fixes #1168
2026-03-18 10:07:06 -06:00
Tom Boucher
a1ef04a5f3 fix: route needs-discussion phase to interactive flow instead of stopping (#1175)
When a milestone has CONTEXT-DRAFT.md (phase: needs-discussion), the
dispatch table returned 'stop' — which made auto-mode exit. Running
/gsd again would re-enter auto → dispatch → stop → loop indefinitely.

The guided-flow already has a complete interactive handler for
needs-discussion (discuss from draft / start fresh / skip), but it was
never reached from the auto-mode entry path.

Added an early check in dispatchNextUnit: if phase is needs-discussion,
stop auto-mode gracefully and route to showSmartEntry() which handles
the discussion flow correctly.

Fixes #1170
2026-03-18 10:06:48 -06:00
Copilot
0a974c9765 Fix validate-milestone skip loop: align artifact check with state machine (#1113)
* Initial plan

* Fix validate-milestone skip loop: verify terminal verdict in artifact check

When verifyExpectedArtifact checked validate-milestone units, it only
verified the VALIDATION file existed on disk. But deriveState requires the
verdict to be terminal (pass/needs-attention/needs-remediation) before
advancing past validating-milestone. If the file existed with malformed
frontmatter or an unrecognized verdict, the artifact check passed (causing
skip) while deriveState stayed in validating-milestone, creating a hard
skip loop that hit the lifetime cap.

Now verifyExpectedArtifact reads the VALIDATION file content and calls
isValidationTerminal() to confirm the verdict matches what deriveState
expects. Non-terminal validations are treated as incomplete artifacts,
triggering re-run instead of skip.

Adds 3 new tests for the tightened verification.

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>

* Address review feedback: clarify comments and add unrecognized verdict test

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
2026-03-18 10:05:29 -06:00
Lex Christopherson
43634c4ba3 fix: run resource-skew check before early TTY gate
The early TTY check blocked the resource-skew detection test which
runs gsd with piped stdin. Move exitIfManagedResourcesAreNewer()
before the TTY gate so version mismatch errors surface in non-TTY
environments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:01:01 -06:00
Lex Christopherson
7cf97bcd98 fix: move TTY check before heavy initialization to prevent process hang
The no-TTY check at the end of cli.ts ran after full session/extension
initialization, which opens handles that prevent process.exit(1) from
completing promptly (15s hang on Node 24). Move the check right after
arg parsing, before any heavy initialization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:54:19 -06:00