Remove the version-match early return in initResources() that skipped
resource sync when versions matched. This allowed the runtime at
~/.gsd/agent/extensions/ to drift from the bundled resources when
individual files were manually copied or leftover from a newer version.
Also adds rmSync of bundled subdirectories before each cpSync to remove
stale files that exist only in the runtime. User-created extension
directories are preserved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cacheKey() used length + first/last 100 chars, which collides when a
checkbox changes [ ] → [x] mid-file (same length, same endpoints).
verifyExpectedArtifact() only cleared the path cache, not the parse
cache, so parseRoadmap() returned stale data with done=false.
- Add clearParseCache() to verifyExpectedArtifact alongside clearPathCache
- Include middle 100-char sample in cacheKey to prevent interior collisions
- Add regression test for the cache collision scenario
* feat: add git.commit_docs setting to keep .gsd/ local-only (#501)
Adds a new `commit_docs` boolean to git preferences. When set to `false`:
- The entire `.gsd/` directory is added to `.gitignore`
- `smartStage()` excludes all `.gsd/` files from commits
- Bootstrap init skips the "chore: init gsd" commit
- `writeIntegrationBranch()` skips committing metadata
- The self-heal that removes blanket `.gsd/` patterns is bypassed
This allows users in corporate environments or mixed teams to use GSD
without polluting the shared git repository with planning artifacts.
Closes#501
* feat: add commit_docs toggle to preferences wizard
Adds "Track .gsd/ planning docs in git" to the /gsd prefs wizard,
allowing users to toggle commit_docs interactively alongside other
git settings like main_branch.
The guided flow's "Create roadmap" path never set pendingAutoStart,
so checkAutoStartAfterDiscuss() always returned false after planning
completed. Auto-mode stalled at "Milestone planned" instead of
proceeding to slice research/execution.
Three fixes:
- Set pendingAutoStart when choice === "plan" in showSmartEntry
- Relax Gate 1 to accept ROADMAP.md (plan path) or CONTEXT.md (discuss path)
- Add STATE.md write instruction to guided-plan-milestone prompt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix two editor input bugs:
1. Arrow key cursor movement not visually updating (fixes#464)
The layout cache key only included {width, textVersion}. Cursor-only
moves don't change textVersion, so stale cached layout was returned
and the diff renderer skipped repaint. Added cursorLine and cursorCol
to the cache key so cursor movements invalidate the cache.
2. Shift+Enter not inserting newlines in non-kitty terminals (Zed, VS Code, etc.)
The /terminal-setup command configures terminals to send ESC+CR (\x1b\r)
for Shift+Enter. But the followUp app action (bound to alt+enter) was
intercepting \x1b\r in CustomEditor.handleInput before the editor's
newLine handler could see it — because in non-kitty terminals, \x1b\r
matches alt+enter. Now when kitty protocol is not active and \x1b\r is
received, the followUp match is skipped so it falls through to newLine.
Alt+Enter followUp still works in kitty-protocol terminals (iTerm2,
Ghostty, Kitty, WezTerm) where the key combos are distinguishable.
Co-authored-by: TÂCHES <afromanguy@me.com>
* fix(undo): use invalidateAllCaches to prevent stale state after undo
After deleting summary files and modifying PLAN files, only
invalidateStateCache() was called. Path and parse caches remained
stale, causing deriveState() to return incorrect results — showing
undone tasks as still complete.
* perf: optimize hot-path lookups, cache clearing, and error resilience
- Replace O(n) Array.includes() with Set-based O(1) lookups in
persistCompletedKey, findCommitsForUnit, and extractCommitShas
- Skip unnecessary cache invalidation for hook units in
verifyExpectedArtifact (moved clearPathCache after hook early-return)
- Avoid redundant disk writes in removePersistedKey when key not present
- Single-pass partition for conflicted files in reconcileMergeState
instead of two separate filter passes
- Wrap undo git operations in try/finally to guarantee cache
invalidation even on partial failure
- Surface auto-start errors to user via ui.notify instead of
swallowing silently (was debug-only logging)
* chore: add PR template and bug report issue template
Standardize PR descriptions and bug reports with structured templates
to improve consistency across contributors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: simplify PR template — replace milestone/slice with target branch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: rename section to 'Release context'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use execFileSync for git commands to handle paths with spaces
execSync builds a shell command string via string interpolation, so any
path containing spaces (e.g. 'Current Projects/my-repo') gets word-split
by the shell into multiple arguments. This caused 'git worktree add' to
fail with a usage error whenever the repo was in a directory with spaces.
Switch all three git runner functions to execFileSync, which takes args
as an array and bypasses the shell entirely. Paths are passed as discrete
arguments and never subject to word-splitting or other shell expansions.
Affected files:
- worktree-manager.ts: runGit()
- git-service.ts: runGit()
- native-git-bridge.ts: gitExec()
* fix: restore pre-merge check command execution
* ci: add extension type-checking to CI pipeline and prepublishOnly
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve remaining extension type errors after merge
- Use cred.type === "api_key" for proper union narrowing in loadToolApiKeys
- Fix optional level parameter in provider-error-pause test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add "success" to notify type union across ExtensionUIContext, interactive
mode, and RPC mode implementations. Fix null safety for readFileSync and
contextUsage.percent in auto.ts. Add discriminated union narrowing for
dispatch results. Add string type guards for select() return values in
commands.ts. Align ProviderErrorPauseUI notify signature. Simplify
AuthStorage return type.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds `/gsd steer <change>` command that registers user overrides in
`.gsd/OVERRIDES.md`. Active overrides are injected into all prompts.
A `rewrite-docs` dispatch unit propagates overrides across plan docs.
Addresses all review concerns from PR #409:
- resolveAllOverrides wired into handleAgentEnd
- Circuit breaker (max 3 attempts, then force-resolve)
- verifyExpectedArtifact validates OVERRIDES.md state
- Milestone-only unitId when no active slice
- Test temp dirs cleaned up
- Remove extraneous argument in auto-worktree report() call
- Replace vitest imports with node:test in integration-mixed-milestones and unique-milestone-ids
- Cast deprecated merge_to_main references as any in preferences-git tests
- Type pre-dispatch hook arrays as PreDispatchHookConfig[] in preferences-hooks tests
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add missing parameters (signal, onUpdate, ctx) to tool execute signatures
and details property to return objects to satisfy AgentToolResult<T> type.
Fix string-to-boolean type mismatch on display property in sendMessage calls.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Export TOOL_KEYS constant and add loadToolApiKeys() function to load
API keys from ~/.gsd/agent/auth.json into environment variables.
Called in session_start handler so tool-based extensions (Context7,
Brave Search, Jina, Tavily, Groq) work immediately without requiring
/gsd config.
Detect prerelease versions (containing -next.) and publish npm packages
with --tag next instead of --tag latest, keeping stable users unaffected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(auto): add missing import for resolveSkillDiscoveryMode
Used at line 687 but not imported, causing "resolveSkillDiscoveryMode is
not defined" crash on auto-mode startup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(auto): add workingDirectory to all auto-mode prompt templates
Six prompt templates (reassess-roadmap, complete-milestone, replan-slice,
run-uat, research-milestone, plan-milestone) were missing the working
directory directive. Without it, the LLM infers the main repo path from
system context and cd's there instead of staying in the worktree. This
causes artifacts to be written to the wrong location, preventing the
dispatch loop from detecting completion and triggering infinite
re-dispatches of the same unit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(auto): detect mid-session resource updates and stop gracefully
Templates are read from disk on each dispatch but extension code is
loaded once at startup. If resources are re-synced mid-session (via
/gsd:update, npm update, or dev copy-resources), templates may expect
variables the in-memory code doesn't provide, causing a crash.
Add a syncedAt timestamp to managed-resources.json. Auto-mode captures
this at startup and checks before each dispatch. If resources changed,
it stops with a clear message instead of crashing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add workingDirectory to prompt template test fixtures
Tests that load prompt templates via loadPromptFromWorktree now pass the
workingDirectory variable, matching the updated templates that include
the {{workingDirectory}} directive.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After deleting summary files and modifying PLAN files, only
invalidateStateCache() was called. Path and parse caches remained
stale, causing deriveState() to return incorrect results — showing
undone tasks as still complete.
Four fixes to auto-recovery logic that caused silent failures or
inconsistent state:
1. skipExecuteTask: return false when checkbox regex doesn't match the
plan format, so callers fall through to other recovery strategies
instead of assuming success (lines 252-255)
2. verifyExpectedArtifact: fail verification on corrupt/unparseable
roadmap instead of silently passing. Prevents advancing past an
incomplete complete-slice when the roadmap file is malformed (line 152)
3. removePersistedKey: use atomic tmp+rename write (matching
persistCompletedKey) to prevent completed-units.json corruption
on crash mid-write (line 293)
4. selfHealRuntimeRecords: use verifyExpectedArtifact instead of bare
existsSync for execute-task healing, so tasks with summary but
unchecked plan checkbox aren't incorrectly marked complete (line 374)
Co-authored-by: TÂCHES <afromanguy@me.com>
The progress bar in the auto-mode widget was snapshot-based — only
updated at dispatch time via updateSliceProgressCache(). During
long-running units (especially after the worktree architecture in
PR #506), the bar appeared frozen even as tasks completed on disk.
Add a 5-second interval inside the widget that re-reads the roadmap
and plan files from disk, so slice/task progress reflects reality
without waiting for the next unit dispatch.
Closes#549
#536 changed git.isolation from deprecated to an active setting.
Update the test to verify it passes through correctly instead of
expecting a deprecation warning. Add separate test for the still-
deprecated git.merge_to_main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce typed error hierarchy (GSDError with stable error codes) for
programmatic error matching and crash diagnostics. Convert
MergeConflictError to extend GSDError. Capture error references in the
most impactful silent catch blocks across crash-recovery, auto-recovery,
and activity-log — errors remain non-fatal but are no longer discarded.
Closes#525
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three independent caches (state, path, parse) required manual coordination
on every dispatch cycle. Forgetting any one caused stale reads (#431).
Add a single invalidateAllCaches() in cache.ts that clears all three,
and replace grouped call sites in auto.ts and tests.
Individual clear functions are preserved for callers that legitimately
only need to clear one cache.
Closes#527
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the 130-line if-else chain in dispatchNextUnit with a
declarative DispatchRule[] table in auto-dispatch.ts.
Each rule maps a GSD state to the unit type, unit ID, and prompt
builder. Rules are evaluated in order; first match wins. The table
is inspectable, testable per-rule, and extensible without modifying
orchestration code.
- auto-dispatch.ts: 258 lines, 12 named rules
- auto.ts dispatch section: 130 lines → 20 lines
- Updated auto-draft-pause test to verify rules in new location
- 123/123 tests pass, zero TypeScript errors
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validates parsed preferences against known keys and expected types.
Unknown keys produce warnings instead of being silently ignored.
Previously unvalidated fields (budget_enforcement, context_pause_threshold,
models, auto_supervisor, notifications, remote_questions) are now
type-checked. Warnings surface through LoadedGSDPreferences so callers
can inspect validation results.
Closes#522
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three fixes for slice transition crashes and git isolation regression:
1. dispatch-guard reads from disk instead of git branch — prevents
false blockers when roadmap state is committed on milestone branch
but not yet on the integration branch (#530).
2. Auto-resolve .gsd/ state file conflicts during milestone merge and
in the mid-merge safety check. STATE.md, completed-units.json, and
auto.lock diverge between branches during normal operation — always
prefer the milestone branch version. Only escalate non-.gsd conflicts
to MergeConflictError (#530).
3. Restore git.isolation preference with two values (#531):
- "worktree" (default): creates milestone worktrees for isolated work
- "branch": works directly in the project root, skipping worktree
creation — for submodule-heavy repos where worktrees fail
The branchless worktree architecture remains the default. Branch mode
simply gates worktree entry points so no worktree is ever created.