Remove GSD planning IDs (milestone/slice/task) from conventional commit
subject lines and place them in machine-parseable git trailers instead.
Skip auto-commits for lifecycle-only unit types that only touch .gsd/ files.
Resolvesgsd-build/gsd-2#2553
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/250b4775-2d82-4329-9ccc-504b857428da
* feat(doctor): worktree lifecycle checks, cleanup consolidation, enhanced /worktree list
Phase 1: Worktree lifecycle doctor checks
- worktree_branch_merged: detect worktrees fully merged into main (auto-fixable)
- worktree_stale: warn on worktrees with no commits in 14+ days
- worktree_dirty: warn on stale worktrees with uncommitted changes
- worktree_unpushed: warn on stale worktrees with unpushed commits
- New worktree-health.ts module with shared helpers for status computation
Phase 2: Fold cleanup into doctor
- legacy_slice_branches now fixable (was info-only, doctor fix deletes them)
- snapshot_ref_bloat check added to doctor (was only in /gsd cleanup snapshots)
- /gsd cleanup worktrees wired up as convenience entry point
Phase 3: Enhanced /worktree list
- Shows inline health status per worktree (merge status, dirty files, age, etc)
- Color-coded: green for safe-to-remove, yellow for stale/dirty, dim for active
New git primitives: nativeIsAncestor, nativeLastCommitEpoch, nativeUnpushedCount
* fix: close gaps — rewire cleanup to doctor, add tests
- Rewire handleCleanupBranches to delegate to doctor fix (branch issues)
- Rewire handleCleanupSnapshots to delegate to doctor fix (snapshot issues)
- Remove duplicate cleanup logic from commands-maintenance.ts
- Fix safeToRemove: merged+clean is sufficient (unpushed irrelevant when merged)
- Add 10 new doctor-git tests: worktree_branch_merged detection/fix/no-false-positive, legacy_slice_branches fixable
- Add 21 new worktree-health tests: merged, dirty, unpushed, stale, format
Total: 178 tests pass across 4 suites, 0 failures
* fix(ci): escape glob pattern in JSDoc comment, clean up duplicate comment
* fix: narrow cleanup scope and protect quick branches
* fix(test): trim leading spaces from git branch output assertion
run() calls .trim() so git branch output has no leading spaces.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: replace recursive auto-dispatch with linear autoLoop, delete ~3k lines of dead code
Replace the complex recursive dispatch system (dispatchNextUnit, reentrancy
guards, stall detection, idempotency tracking, skip-depth machinery) with a
simple linear while(s.active) loop in auto-loop.ts.
Key changes:
- New auto-loop.ts with autoLoop(), runUnit(), resolveAgentEnd()
- Deleted auto-idempotency.ts, auto-stuck-detection.ts, session-lock.ts,
mechanical-completion.ts, progress-score.ts, auto-constants.ts, unit-id.ts
- Extracted WorktreeResolver class for worktree path resolution
- Added auto-worktree-sync.ts for worktree synchronization
- Simplified auto.ts from ~1400 lines to ~400 lines
- Fixed 9 TypeScript errors (NotifyCtx type widening, capture typing)
- Comprehensive test coverage: 32 auto-loop tests + worktree resolver/DB tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address 6 audit findings in auto-loop refactor
1. CRITICAL: Move pendingResolve to AutoSession + queue orphaned agent_end
events instead of silently dropping them. Prevents permanent stalls when
error-recovery sendMessage retries fire between loop iterations.
2. HIGH: Scope pendingResolve per-session via _activeSession ref, preventing
concurrent /gsd auto sessions from corrupting each other's promises.
3. HIGH: Replace console.log in dispatchHookUnit with debugLog to prevent
hook prompt content (potentially containing secrets) from leaking to stdout.
4. HIGH: Restore parked milestone handling in state.ts — Phase 1 skips
parked milestones so they don't satisfy depends_on, Phase 2 registers
them as 'parked' status. Add 'parked' to MilestoneRegistryEntry type.
5. MEDIUM: Restore queuePhaseActive parameter in shouldBlockContextWrite
and re-export setQueuePhaseActive for guided-flow-queue.ts consumers.
6. MEDIUM: Add MAX_LOOP_ITERATIONS (500) lifetime cap to autoLoop to prevent
runaway loops when units alternate between IDs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve build breakers, add correctness fixes, and graduated recovery
Build breakers (CRITICAL):
- Restore unit-id.ts (deleted but still imported by complexity-classifier.ts, metrics.ts)
- Restore progress-score.ts (deleted but still imported by commands.ts, dashboard-overlay.ts, doctor.ts)
- Rewrite worktree-sync-milestones.test.ts to use new syncProjectRootToWorktree API
Correctness fixes (MEDIUM):
- Cap pendingAgentEndQueue to 3 entries to prevent unbounded growth from stale events
- Add milestoneId path traversal validation in WorktreeResolver
- Clear depthVerificationDone on session_start to prevent cross-session leaks in RPC mode
- Add verification gate for non-hook sidecar units (triage, quick-tasks)
- Remove dead handleAgentEnd import from index.ts
Graduated recovery (Jeremy's feedback):
- Blanket try/catch around loop body — one bad iteration no longer kills the session
- Graduated stuck recovery: at count 3 try artifact verification + cache invalidation,
at count 5 hard stop (was: binary stop at 5 with no recovery attempt)
- Graduated error recovery: 1st error retries, 2nd invalidates caches, 3rd stops
Test results: 32/32 auto-loop, 28/28 worktree-resolver, 11/11 sidecar-queue, tsc clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restore copyWorktreeDb/reconcileWorktreeDb exports and fix loadToolApiKeys import
Two missing exports caused ~90% of the 120 pre-existing test failures:
1. copyWorktreeDb + reconcileWorktreeDb — imported by auto-worktree.ts but
never added to gsd-db.ts. Restored with the original implementations.
2. loadToolApiKeys — moved to commands-config.ts but index.ts still imported
from commands.ts. Fixed the import path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move loadToolApiKeys import to commands-config.js
loadToolApiKeys was moved to commands-config.ts but index.ts still
imported it from commands.ts, causing runtime failures in all tests
that transitively load the extension entry point.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: fix provider error assertion on windows
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Move mutable .gsd/ state from inside the project directory to
~/.gsd/projects/<repo-hash>/, replacing it with a symlink. All worktrees
share the same external state — eliminating the entire bidirectional
sync layer (~370 lines) that was the source of 15+ bug fixes.
Key changes:
- repo-identity.ts: repoIdentity(), externalGsdRoot(), ensureGsdSymlink()
- gsdRoot() resolves through symlinks via realpathSync
- migrate-external.ts: automatic migration with atomic rollback
- resource-version.ts: kept utilities from deleted sync module
- Worktree detection uses git metadata (.git file) instead of path parsing
- gitignore simplified to single .gsd entry
- Doctor checks for failed_migration and broken_symlink
Deleted: auto-worktree-sync.ts, copyWorktreeDb, reconcileWorktreeDb,
reconcilePlanCheckboxes, copyPlanningArtifacts, dual state derivation.
Net: -1271 lines across 38 files. 0 sync ops per dispatch cycle.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add barrel files for remote-questions, ttsr, and shared extensions
Centralizes public API surface for three extension directories behind
index.ts barrel files. External consumers now import from the barrel
instead of reaching into internal module files, reducing coupling and
making future refactors safer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: rename barrel files to mod.ts to avoid extension loader auto-discovery
The extension loader auto-discovers extensions by looking for index.ts files
inside extensions/*/ directories. remote-questions/ and shared/ are utility
directories, not extensions — their index.ts barrel files caused load failures.
Renamed to mod.ts which the loader ignores, and updated all import 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>
Move resolveGitHeadPath() and nudgeGitBranchCache() to worktree.ts as
the canonical shared location. Both auto-worktree.ts and
worktree-command.ts now import from worktree.ts instead of defining
their own copies.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add worktree post-create hook for environment setup (#597)
Add git.worktree_post_create preference — a script path that GSD
runs after creating any worktree (both auto-mode and manual /worktree).
The script receives SOURCE_DIR and WORKTREE_DIR as environment
variables, enabling users to copy .env files, symlink asset
directories, or run other setup commands that git worktrees don't
inherit from the main tree.
Implementation:
- Add worktree_post_create field to GitPreferences interface
- Add validation in validatePreferences (must be non-empty string)
- Add runWorktreePostCreateHook() in auto-worktree.ts — resolves
relative paths against project root, runs with 30s timeout,
failure is non-fatal (warning only)
- Integrate hook call in createAutoWorktree() (auto-mode path)
- Integrate hook call in worktree-command.ts (manual /worktree path)
- Update docs/configuration.md with full usage guide and example
hook script
- Update preferences-reference.md with field documentation
Example configuration:
git:
worktree_post_create: .gsd/hooks/post-worktree-create
Example hook script:
#!/bin/bash
cp "$SOURCE_DIR/.env" "$WORKTREE_DIR/.env"
ln -sf "$SOURCE_DIR/assets" "$WORKTREE_DIR/assets"
Closes#597
* fix: use Node.js scripts in hook tests for Windows compatibility
Replace bash hook scripts with cross-platform Node.js scripts in
worktree-post-create-hook.test.ts. On macOS/Linux, scripts use
#!/usr/bin/env node shebang. On Windows, generates batch files
that invoke node -e. Fixes windows-portability CI failures.
* fix: Windows CI failures in worktree post-create hook tests
- Use path.isAbsolute() instead of startsWith("/") to detect absolute
paths on Windows (fixes double-path bug like C:\...\C:\...)
- Add .bat extension to hook scripts on Windows so they are recognized
as executable by cmd.exe
- Extract isWin constant and hookPath() helper for consistent
platform-aware test setup
Fixes 3 failing tests in windows-portability CI job:
- executes hook script with correct env vars
- supports absolute hook paths
- hook can copy files from source to worktree
* fix: adopt main's help command and error message in commands.ts
The auto-merge missed main's addition of the help handler, showHelp
function, and updated description/subcommands array. Added them
manually and updated the visualizer help text to reflect 7-tab TUI.
* fix: write Windows hook scripts as .bat + companion .js file
The previous approach embedded multi-line JavaScript in a node -e "..."
argument inside the .bat file. cmd.exe splits on newlines, so each JS
line was interpreted as a separate batch command ('const' is not
recognized...).
Now writes the JS code to a companion .js file and the .bat invokes
it with `node "%~dp0<file>.js"`, which works reliably on Windows.
---------
Co-authored-by: TÂCHES <afromanguy@me.com>
* docs(M004): context, requirements, and roadmap
* chore(M004): record integration branch
* chore(M004/S01): auto-commit after research-slice
* docs(S01): add slice plan
* chore(M004/S01/T01): auto-commit after execute-task
* chore(M004/S01/T02): auto-commit after execute-task
* chore(M004/S01): auto-commit after complete-slice
* chore(M004/S01): auto-commit after reassess-roadmap
* chore(M004/S02): auto-commit after research-slice
* docs(S02): add slice plan
* chore(M004/S02/T01): auto-commit after execute-task
* chore(M004/S02/T02): auto-commit after execute-task
* chore(M004/S02): auto-commit after complete-slice
* docs(M004): reassess roadmap after S02
* chore(M004/S03): auto-commit after research-slice
* docs(S03): add slice plan
* chore(M004/S03/T01): auto-commit after execute-task
* chore(M004/S03/T02): auto-commit after execute-task
* chore(M004/S03/T03): auto-commit after execute-task
* chore(M004/S03): auto-commit after complete-slice
* chore(M004): record integration branch
* chore(M004/S04): auto-commit after research-slice
* docs(S04): add slice plan
* chore: update state to executing S04
* chore(M004/S04/T01): auto-commit after execute-task
* chore(M004/S04/T02): auto-commit after execute-task
* chore(M004/S04): auto-commit after complete-slice
* docs(M004): reassess roadmap after S04
* chore(M004/S05): auto-commit after research-slice
* docs(S05): add slice plan
* chore(M004/S05/T01): auto-commit after execute-task
* chore(M004/S05/T02): auto-commit after execute-task
* chore(M004/S05): auto-commit after complete-slice
* chore(M004/S05): auto-commit after reassess-roadmap
* chore(M004/S06): auto-commit after research-slice
* docs(S06): add slice plan
* chore: update STATE.md for S06 execution
* chore(M004/S06/T01): auto-commit after execute-task
* chore(M004/S06/T02): auto-commit after execute-task
* chore(M004/S06): auto-commit after complete-slice
* chore(M004/S06): auto-commit after reassess-roadmap
* chore(M004/S07): auto-commit after research-slice
* docs(S07): add slice plan
* chore(M004/S07/T01): auto-commit after execute-task
* chore(M004/S07): auto-commit after complete-slice
* chore(M004): auto-commit after complete-milestone
* docs(M004): milestone summary and state update
* fix: path traversal guard, ATTACH allowlist, restore deleted export-html
- db-writer.ts: validate saveArtifactToDb path stays within .gsd/ using
resolve() to prevent directory traversal via LLM tool input
- gsd-db.ts: replace single-quote-only ATTACH guard with strict character
allowlist regex for worktree DB path validation
- Restore accidentally deleted pkg/dist/core/export-html/ templates
(removed in b30baeb7 during S04/T01 auto-execution)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove .gsd/ from tracking — private project work docs
.gsd/ contains personal planning artifacts, not public source code.
Replace granular runtime gitignore rules with blanket .gsd/ ignore.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve 4 strict typecheck errors for tsconfig.extensions.json
- gsd-db.ts: cast origEmit.apply return to boolean
- md-importer.ts: double-cast Requirement to Record<string, unknown>
- gsd-inspect.test.ts: remove extraneous arg from report()
- md-importer.test.ts: nullish coalesce on optional chain to boolean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update compression test to accept DB-aware helper pattern
The context-compression test checks auto-prompts.ts source for
inlineGsdRootFile calls, but M004 replaces these with DB-aware
helpers (inlineRequirementsFromDb etc). Accept either pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use single-quote blocklist instead of path allowlist for ATTACH guard
Allowlist regex broke on Windows temp paths containing tildes (RUNNER~1),
parens, and other valid OS path chars. The only actual injection vector
for ATTACH DATABASE '...' is a single quote breaking the SQL literal.
Block that one char instead of trying to enumerate all valid path chars.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* revert: restore .gsd/ tracking and original gitignore rules
The blanket .gsd/ ignore was incorrect — GSD users need planning
files tracked. Restore main's granular runtime-only gitignore and
re-add all .gsd/ planning files from main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use double quotes in git commit message for Windows compatibility
Single quotes in shell commands don't work on Windows PowerShell.
The commit message 'add gsd dir' was split into separate pathspecs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(M001/S01): ID generation and config plumbing
Tasks:
- chore(M001/S01/T02): auto-commit after execute-task
- chore(M001/S01): auto-commit after plan-slice
- docs(S01): add slice plan
Branch: gsd/M001/S01
* feat(M001/S02): Regex hardening and backwards compat
Tasks:
- chore(M001/S02/T02): auto-commit after execute-task
- chore(M001/S02/T01): auto-commit after execute-task
- chore: untrack .gsd/ runtime files from git index
- docs(S02): add slice plan
Branch: gsd/M001/S02
* docs(M001/S03): UX — wizard toggle and documentation
Tasks:
- chore(M001/S03/T01): auto-commit after execute-task
- docs(S03): add slice plan
Branch: gsd/M001/S03
* test(M001/S04): Integration tests and end-to-end verification
Tasks:
- chore(M001/S04/T02): auto-commit after execute-task
- chore(M001/S04/T01): auto-commit after execute-task
- docs(S04): add slice plan
Branch: gsd/M001/S04
* chore(M001): record integration branch
* chore(M002): record integration branch
* docs(M002/S01): Format swap — production code, tests, and docs
Tasks:
- chore(gsd/M002/S01): auto-commit after pre-switch
- chore(M002/S01/T01): auto-commit after execute-task
- chore: untrack .gsd/ runtime files from git index
- docs(S01): add slice plan
Branch: gsd/M002/S01
* chore(M002): auto-commit after complete-milestone
* Updated to document that we don't automatically always squash to main if you started on a different branch (like a dev or feature branch)
* fix: replace vitest import with node:test in regex-hardening test
The test imported from 'vitest' which isn't installed, causing
ERR_MODULE_NOT_FOUND and failing the CI unit test step. All other
test files use node:test. Swapped the import and removed the
vitest conditional wrapper.
* chore: untrack .gsd/ (already gitignored)
* docs: fix stale 'main' references in merge comments and prompts
The slice merge code correctly resolves to the integration branch
(which may be a feature branch, worktree branch, etc.), but comments,
JSDoc, and prompt templates still said 'main' as if it were always
the literal main branch.
Updated git-service.ts, worktree.ts, system.md, and
guided-complete-slice.md to say 'integration branch' with a clear
explanation of what that means.
* Fixed preferences.md case mismatch; Added fallback for backwards compat
* Updated preferences file example to show new unique_milestone_ids setting
* Updated readme to explain best practice for working in teams
---------
Co-authored-by: TÂCHES <afromanguy@me.com>
Vendor all 4 Pi packages (tui, ai, agent-core, coding-agent) from
pi-mono v0.57.1 as @gsd/* workspace packages under packages/. This
replaces the compiled npm dependency (@mariozechner/pi-coding-agent)
and patch-package workflow, giving direct source access for
modifications.
- Copy Pi source from pi-mono v0.57.1 into packages/
- Create workspace package.json + tsconfig.json for each package
- Rename ~240 imports from @mariozechner/pi-* to @gsd/pi-*
- Apply existing patches as source edits (setModel persist, VT input)
- Remove @mariozechner/pi-coding-agent dep and patch-package
- Update build pipeline to build packages in dependency order
- Add pi-upstream git remote for future selective syncing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: worktree branch namespacing and fresh-start flow
- Namespace slice branches by worktree name (gsd/<wt>/<M>/<S>) to prevent
git checkout conflicts when multiple worktrees work on the same milestone
- getMainBranch() returns worktree/<name> inside a worktree so slice merges
target the worktree branch instead of main (which is checked out elsewhere)
- Add continue/fresh-start prompt when creating a worktree with existing milestones
- Restyle all worktree command output with consistent semantic color palette
- Add parseSliceBranch() and SLICE_BRANCH_RE for robust branch name parsing
- Fix duplicate getCurrentBranch import in auto.ts
- Add 40-assertion integration test covering full worktree lifecycle
* fix: branch slice from current branch, not main
ensureSliceBranch always branched from getMainBranch() (main/master),
but planning artifacts (CONTEXT, ROADMAP, etc.) may only exist on the
working branch (e.g. "developer"). The slice branch would lose all
planning artifacts, causing deriveState to see pre-planning and the
rebuildState post-hook to overwrite STATE.md with a blank state.
Now branches from the current branch when it is not itself a slice
branch. Falls back to main when on a slice branch to avoid chaining.
Adds regression tests for both cases.
Merge improvements:
- Auto-detect current worktree: /worktree merge (bare) and /worktree merge main
work from inside a worktree without specifying the worktree name
- Full repo diffs: preview and LLM prompt show all changed files, not just .gsd/
- Accurate preview: direct diff (main vs branch) shows actual merge impact
- Per-file line stats: +N/-N shown for each file in merge preview
- CWD fix: chdir to main tree before dispatching merge to prevent broken CWD
after worktree cleanup
- Prompt includes explicit paths so the LLM knows where to read/write
Create/switch:
- /worktree create <name> works as alias for create-or-switch behavior
- Guard against creating a worktree when the branch is already in use
Remove:
- /worktree remove <name> validates the name exists before attempting removal
- /worktree remove <name> confirms before deleting
- /worktree remove all removes every worktree after confirmation prompt
Reload resilience:
- Detects if CWD is inside a worktree on extension init and restores
originalCwd tracking, surviving /reload without losing worktree state
Command descriptions:
- /worktree shows '(also /wt)' in description
- /wt shows 'Alias for /worktree'