Commit graph

4537 commits

Author SHA1 Message Date
deseltrus
e6ceb8dfe8 fix: skip verification retry on spawn infra errors (ETIMEDOUT, ENOENT) (#1340) 2026-03-19 07:39:13 -06:00
Jeremy McSpadden
d7bf3d4e72 Improve startup performance with lazy extension loading (#1336) 2026-03-19 07:38:50 -06:00
dan bachelder
b67101c51b fix: keep external GSD state stable in worktrees (#1334) 2026-03-19 07:37:25 -06:00
Tom Boucher
469d2e1e77 ci: upgrade docker/login-action v3 → v4 for Node 24 runtime (#1331) 2026-03-19 07:36:10 -06:00
John Brahy
c47ee71b2d fix: always include reasoning.encrypted_content for OpenAI reasoning models
When using a reasoning model (o1, o3, o4-mini, etc.) without explicitly
setting reasoningEffort or reasoningSummary, the include param was not
set. OpenAI returns a bare rs_... reasoning item ID which gets stored in
thinkingSignature and replayed in the next turn. Since store is false,
OpenAI cannot find the rs_... item server-side and returns a 404.

Fix: move params.include = ["reasoning.encrypted_content"] outside the
reasoningEffort/reasoningSummary guard so it is always set for any
reasoning model. This ensures the encrypted blob is returned and can be
replayed correctly without needing server-side storage.
2026-03-19 02:53:06 -07:00
John Brahy
211520c2d2 updating .gitignore 2026-03-19 02:22:28 -07:00
John Brahy
85265a99ab docs: add structured issue templates 2026-03-19 01:54:22 -07:00
John Brahy
76e7aec0e8 fix(gsd): avoid EISDIR crash in file loader 2026-03-19 01:40:52 -07:00
John Brahy
6fe2280363 fix(gsd): open existing database on inspect 2026-03-19 01:35:28 -07:00
John Brahy
0c83046a51 docs: add guidance for local custom MCP setup 2026-03-19 01:27:37 -07:00
Tom Boucher
d121c8e3b2 fix: stop excluding all .gsd/ from commits — only exclude runtime files (#1326) (#1328)
smartStage() was excluding the entire .gsd/ directory from git staging,
which is correct when .gsd/ is symlinked to external state. But on
Windows (junction links) or projects where .gsd/ is git-tracked (not
gitignored), this caused a mid-milestone behavioral discontinuity:

1. One-time cleanup removes runtime files from the index
2. After cleanup, nativeAddAll() + nativeResetPaths('.gsd/') causes ALL
   .gsd/ files to be unstaged — including milestone artifacts
3. autoCommit returns null (nothing staged) for the rest of the milestone
4. Work continues silently with no commits, no errors, no warnings
5. Worktree teardown loses all uncommitted .gsd/ artifacts

Fix: replace the blanket '.gsd/' exclusion with targeted RUNTIME_EXCLUSION_PATHS.
Milestone artifacts (.gsd/milestones/, preferences.md, DECISIONS.md, etc.)
are now committed normally when they're tracked. When .gsd/ is in .gitignore
(the default), git add -A already skips it — the reset is a harmless no-op.

Updated git-service.test.ts to verify the new behavior: runtime files
excluded, milestone artifacts committed.

Fixes #1326
2026-03-18 22:06:41 -06:00
Jeremy McSpadden
fc56cdf93e fix: handle ECOMPROMISED in uncaughtException guard and align retry onCompromised (#1322) (#1332)
When a GSD session crashes hard (SIGKILL, OOM, etc.) without running its
exit handler, the proper-lockfile OS lock directory (.gsd.lock/) is left
stranded. On the next /gsd auto resume, acquireSessionLock detects the dead
PID, cleans up the stale directory, and re-acquires via the retry path.

10 seconds later, proper-lockfile's update timer fires. Due to a subtle
interaction between the synchronous fs adapter (lockSync / toSyncOptions)
and the setTimeout boundary in Node.js v25+, the ECOMPROMISED error
propagates up through the synchronous callback chain and becomes an
uncaught exception — even though the onCompromised callback sets
_lockCompromised = true without throwing.

The _gsdEpipeGuard uncaughtException handler only handled EPIPE, so it
re-threw ECOMPROMISED, crashing the process. Each crash wrote a new
"interrupted session" record, causing an infinite crash loop on resume.

Two fixes:

1. index.ts: Handle ECOMPROMISED in _gsdEpipeGuard. Exit with code 1
   (non-zero to signal failure) so the process.once("exit") handler runs
   and removes the lock directory, allowing the next session to start clean.

2. session-lock.ts: The retry path's onCompromised was missing
   `_releaseFunction = null`, unlike the primary path. This left the
   release function pointer live after compromise, causing validateSessionLock
   to return true and preventing graceful stop detection. Now matches primary.
2026-03-18 22:06:03 -06:00
github-actions[bot]
d25c174f8b release: v2.33.1 2026-03-19 04:02:21 +00:00
Jeremy McSpadden
15a8807eb3 fix: clean up stale numbered lock files and harden signal/exit handling (#1315) (#1323) 2026-03-18 21:15:47 -06:00
Tom Boucher
7537e30815 fix: worktree sync and home-directory safety check (#1311, #1317) (#1322) 2026-03-18 21:15:36 -06:00
Tom Boucher
0e4db4b709 docs: update README and docs for v2.33.0 release (#1320) 2026-03-18 21:15:11 -06:00
Tom Boucher
68e0672dda test: add regression harness for auto-mode dispatch loop (125 assertions) (#1319) 2026-03-18 21:14:59 -06:00
Jeremy McSpadden
805c7718c4 chore: remove orphaned mcporter extension manifest (#1318) 2026-03-18 21:14:50 -06:00
github-actions[bot]
106f5d8d32 release: v2.33.0 2026-03-19 02:40:54 +00:00
Tom Boucher
6b61b75f3d feat: add live regression test harness for post-build pipeline validation (#1316)
10 tests that run against the installed gsd binary after npm publish:

1. headless query returns valid JSON
2. Empty project → pre-planning phase
3. Milestone with roadmap → planning phase
4. All tasks done → summarizing phase
5. Complete milestone → complete phase
6. Stale auto.lock doesn't block --version
7. Crash recovery query works with stale lock
8. Non-TTY exits quickly with clean error
9. Version skew detected before TTY check
10. --help works (native addon loads or falls back)

Wired into pipeline.yml test-verify job after fixture tests
and before @next promotion.

These catch the state machine / infrastructure bugs from #1308
that unit tests can't reach — they exercise deriveState through
the real gsd binary with real .gsd/ directory structures.

Part of #1308
2026-03-18 20:22:54 -06:00
Tom Boucher
0418458cf9 refactor: extract tryMergeMilestone to eliminate 4 duplicate merge paths in auto.ts (#1314) 2026-03-18 20:04:10 -06:00
Tom Boucher
583e84e932 refactor: dispatch loop hardening — defensive guards, regression tests, lock alignment (#1310) 2026-03-18 20:03:59 -06:00
TÂCHES
e6ab3b6722 refactor: extract parseUnitId() to centralize unit ID parsing (#1282)
Replaces 30+ inline `unitId.split("/")` + destructuring patterns across
16 production files with a single `parseUnitId()` helper that returns
`{ milestone, slice?, task? }`. If the unit ID format ever changes,
only one function needs updating.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:20:08 -06:00
Tom Boucher
afb438164e fix: align retry lock path with primary lock settings to prevent ECOMPROMISED (#1307)
The retry lock acquisition path (from stale lock recovery in #1251)
used a 5-minute stale threshold and no onCompromised handler, while
the primary path used 30 minutes and a graceful flag-based handler.

This mismatch meant locks acquired via the retry path would throw
ECOMPROMISED (uncaught, crashes process) if the event loop stalled
for >5 minutes — which happens during long LLM operations.

Fixed:
- Stale timeout: 300_000 → 1_800_000 (matches primary)
- Added onCompromised handler (sets _lockCompromised flag)
- Added process.on('exit') safety net (matches primary)

Also: reporter is on Node v25.6.1 which is unsupported — GSD requires
Node >=22.0.0 with 24 LTS recommended.

Fixes #1304
2026-03-18 19:15:47 -06:00
Tom Boucher
150575957d fix: skip symlinks in makeTreeWritable to prevent EPERM on NixOS/nix-darwin (#1303)
makeTreeWritable used statSync which follows symlinks. On NixOS and
nix-darwin, ~/.gsd/agent/bin/ contains symlinks to the immutable Nix
store (/run/current-system/sw/bin/). Attempting to chmod those targets
crashed GSD on startup with EPERM.

Changes:
- Use lstatSync instead of statSync — detects symlinks without
  following them
- Skip symlinks entirely (they don't carry own permissions, targets
  may be immutable)
- Added try/catch around chmodSync as safety net for any remaining
  permission errors on unusual filesystems

Secondary analysis: rmSync with force:true already handles symlinks
correctly (removes the link, not the target). cpSync with force:true
replaces symlinks with regular files (desired behavior for resource
sync).

Fixes #1298
2026-03-18 19:15:33 -06:00
TÂCHES
2a2056bcd7 refactor: extract getErrorMessage() helper to eliminate 65 inline duplicates (#1280)
Consolidate the repeated `err instanceof Error ? err.message : String(err)`
pattern into a single `getErrorMessage(err)` utility. Reduces visual noise in
catch blocks across 20 files in the GSD extension.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:12:44 -06:00
TÂCHES
922826ba8a refactor: consolidate DB-fallback inline functions in auto-prompts (#1276)
* refactor: consolidate DB-fallback inline functions in auto-prompts

Extract shared inlineFromDbOrFile() helper that encapsulates the
repeated pattern of checking DB availability, dynamically importing
context-store, running a query, formatting results, and falling back
to the filesystem. The three public functions (inlineDecisionsFromDb,
inlineRequirementsFromDb, inlineProjectFromDb) become thin wrappers
that pass only the differing query/format logic as a callback.

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

* fix: update source-level test to match refactored DB-fallback function name

The context-compression test greps auto-prompts.ts source for
`inlineGsdRootFile(base, "project.md"` which was replaced by
`inlineProjectFromDb(base)` in the consolidation refactor.

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 19:11:01 -06:00
Tom Boucher
8f06a14fb6 docs: update README for v2.32.0 release (#1299) 2026-03-18 18:57:29 -06:00
Tom Boucher
3ae1d54759 fix: handle Windows EPERM on .gsd migration rename with copy+delete fallback (#1296) 2026-03-18 18:57:06 -06:00
Tom Boucher
5660100c66 fix: add actionable recovery guidance to crash info messages (#1295) 2026-03-18 18:56:55 -06:00
Tom Boucher
5351e776d9 fix: resolve main repo root in worktrees for stable identity hash (#1294) 2026-03-18 18:56:43 -06:00
Tom Boucher
f3cf03c067 fix: merge quick-task branch back to original after completion (#1293) 2026-03-18 18:56:30 -06:00
github-actions[bot]
113c5e6518 release: v2.32.0 2026-03-19 00:15:12 +00:00
Jeremy McSpadden
5e7f42c686 feat: always-on health widget and visualizer health tab expansion (#1286) 2026-03-18 18:04:21 -06:00
Jeremy McSpadden
652ac385b7 feat: environment health checks, progress score, and status integration (#1263) 2026-03-18 18:04:14 -06:00
Juan Francisco Lebrero
d4d8d1a81e fix: skip crash recovery when auto.lock was written by current process (#1289) 2026-03-18 18:03:28 -06:00
Juan Francisco Lebrero
a0de87929b fix: load worktree-cli extension modules via jiti instead of static ESM imports (#1285) 2026-03-18 17:51:27 -06:00
Jeremy McSpadden
f6c980db81 fix(gsd): prevent concurrent dispatch during skip chains (#1272) (#1283) 2026-03-18 17:27:05 -06:00
TÂCHES
2f729fe051 refactor: deduplicate knownUnitTypes and STATE_REBUILD_MIN_INTERVAL_MS constants (#1281) 2026-03-18 17:26:06 -06:00
TÂCHES
0141ea21af refactor: extract prompt builder helpers for inlined context and source file lists (#1279) 2026-03-18 17:25:38 -06:00
TÂCHES
1e4ea36f1f refactor: extract createGitService() factory, remove debug logs (#1278) 2026-03-18 17:23:26 -06:00
TÂCHES
a647a2fcb6 refactor: extract dispatchUnit helper, inline dead buildDocsCommitInstruction (#1275) 2026-03-18 17:22:54 -06:00
TÂCHES
0b4510398d refactor: unify unit-type switch statements into lookup map (#1273) 2026-03-18 17:22:41 -06:00
TÂCHES
84b556908c fix: skip non-artifact UAT dispatch in auto-mode (#1277)
* fix(gsd): skip non-artifact UAT dispatch in auto-mode

Non-artifact-driven UATs (human-experience, live-runtime, mixed) were
dispatched only to write a "surfaced-for-human-review" verdict, which
then blocked the verdict gate and killed auto-mode progression. Auto
now only dispatches artifact-driven UATs it can actually execute.

- checkNeedsRunUat returns null for non-artifact-driven UAT types
- Remove pauseAfterDispatch flag (always artifact-driven now)
- Strip human-review template path from run-uat prompt
- Remove dead pause-after-UAT logic from auto.ts
- Add test for non-artifact UAT skip + stale replay guard

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

* fix: update buildRunUatPrompt call in direct dispatch after signature change

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 17:22:20 -06:00
github-actions[bot]
a488de99bb release: v2.31.2 2026-03-18 22:40:20 +00:00
TÂCHES
ce550b2423 fix(gsd): stop replaying completed run-uat units (#1270) 2026-03-18 16:24:50 -06:00
github-actions[bot]
f2b637a596 release: v2.31.1 2026-03-18 22:13:47 +00:00
jpmarques19
ad9d7a1815 fix: prevent false-positive 'Session lock lost' during auto-mode (#1257)
- Add onCompromised handler to prevent uncaught throw in setTimeout
- Increase stale threshold from 5min to 30min for laptop sleep safety
- Release OS lock explicitly in SIGTERM handler
2026-03-18 15:44:14 -06:00
github-actions[bot]
b095e352a7 release: v2.31.0 2026-03-18 21:40:31 +00:00
Lex Christopherson
69efb57355 fix: remove stale git-commit assertion in worktree test after commit_docs removal
The test asserted that captureIntegrationBranch commits metadata to git,
but #1258 intentionally stopped committing .gsd/ artifacts.

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