62 new tests across 6 files covering the modules introduced in the v2
single-writer discipline layer that had no test coverage:
- write-intercept.test.ts (15): isBlockedStateFile path matching for
STATE.md (blocked) vs other .gsd/ files (allowed), BLOCKED_WRITE_ERROR
- sync-lock.test.ts (7): acquireSyncLock/releaseSyncLock including
lock file creation, round-trip, and stale lock override
- workflow-events.test.ts (15): appendEvent (creates dir, valid JSONL,
deterministic hash), readEvents (empty, parse, skip corrupted),
findForkPoint (edge cases), compactMilestoneEvents (archive/truncate)
- workflow-manifest.test.ts (8): snapshotState, writeManifest,
readManifest (null/parse/version guard), bootstrapFromManifest
round-trip restore
- workflow-projections.test.ts (17): renderPlanContent pure function —
H1/Goal/Demo/Tasks structure, [x]/[ ] checkboxes, Estimate/Files/
Verify/Duration sublines, task ordering
- post-mutation-hook.test.ts (5): regression — verifies that after
handleCompleteTask, event-log.jsonl and state-manifest.json are
both written by the post-mutation hook; also confirms hook failures
are non-fatal (handler still returns success)
All 62 tests pass. Zero regressions introduced.
Ports the single-writer state architecture from PRs #2288–#2293 onto the
current upstream codebase (schema v10, polymorphic engine). Original PRs
were based on a pre-v5 schema with incompatible column names and predated
the WorkflowEngine interface refactor.
New files:
- workflow-events.ts: append-only event log (.gsd/event-log.jsonl)
- workflow-manifest.ts: full DB snapshot after every mutation (crash recovery)
- workflow-projections.ts: renders PLAN/ROADMAP/SUMMARY/STATE.md from DB
- workflow-migration.ts: migrates legacy markdown projects into DB
- workflow-reconcile.ts: event log replay for diverged worktrees
- workflow-logger.ts: structured error/warning accumulation
- sync-lock.ts: advisory lock for concurrent worktree syncs
- write-intercept.ts: blocks direct writes to STATE.md
- auto-artifact-paths.ts: central artifact path registry
Modified:
- All 8 tool handlers (complete-task, complete-slice, plan-slice, etc.)
now wrap mutations in atomic transactions + emit event log + write
manifest + regenerate markdown projections after every command
- state.ts: telemetry counters for DB vs filesystem derivation paths
- register-hooks.ts: write-intercept wired into tool_call hook
- doctor.ts/doctor-checks.ts/doctor-types.ts: engine health checks,
fixable:false on completion-state issues, removed placeholder stubs
- auto.ts + supporting files: removed completedUnits tracking globally,
removed unit-runtime record reads/writes, removed inline doctor runs
- auto-post-unit.ts: detectRogueFileWrites (6 unit types), removed
doctor health tracking block, added regenerateIfMissing on retry
- 3 prompts updated to use gsd_* tool API instead of direct file edits
ADR-004: GSD had multiple writers racing to edit the same markdown files
concurrently, causing race conditions, stale reads, and corrupt state.
The single-writer discipline layer makes markdown files derived artifacts
(generated from DB after every command) rather than authoritative sources.
Supersedes closed PRs: #2288, #2289, #2290, #2291, #2292, #2293
AI assistance: implemented with Claude Code (GSD/Claude).
Two bugs in ensureLinuxReady():
1. Branch ordering: "ModuleNotFoundError: No module named 'sounddevice'"
contains the word "sounddevice", so the portaudio branch matched first,
producing the misleading "install libportaudio2" message even when
libportaudio2 was already installed.
2. No venv auto-creation: On PEP 668 systems (Ubuntu 23.10+), system pip
is blocked. The code trusted speech-recognizer.py to self-install deps,
but its pip install also fails. Now ensureLinuxReady() auto-creates
~/.gsd/voice-venv when the sounddevice module is missing.
Fixes:
- Extract diagnoseSounddeviceError() with correct branch ordering
(check "No module"/"ModuleNotFoundError" BEFORE "sounddevice")
- Add ensureVoiceVenv() to auto-create venv with sounddevice+requests
- Refactor into linux-ready.ts for testability
- Add 20 unit tests covering all error diagnosis paths and venv creation
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When no preferences.md exists, getIsolationMode() and
shouldUseWorktreeIsolation() defaulted to "worktree", which requires
git branch infrastructure (milestone/<MID> branches) that isn't
automatically set up. This caused milestone-complete to fail with
"branch doesn't exist" when users worked directly on main without
configuring preferences.
Change the default to "none" (work on current branch) across all five
locations: getIsolationMode(), shouldUseWorktreeIsolation(),
MODE_DEFAULTS for solo/team, doctor.ts, and doctor-checks.ts.
Worktree isolation is now explicit opt-in via preferences.md.
Closes#2480
* fix(gsd): add worktree lifecycle events to journal
* fix(gsd): widen source scan window in merge-conflict test
The journal event additions in _mergeWorktreeMode pushed the
MergeConflictError re-throw past the 5000-char scan window used
by merge-conflict-stops-loop.test.ts. Increase to 6000 to
accommodate the added emitJournalEvent calls.
* fix(gsd): restore cwd before temp dir cleanup in journal test
On Windows, rmSync fails with EPERM when the process cwd is inside
the directory being deleted. Save and restore the original cwd in
afterEach before cleanup.
* feat(gsd): add workflow-logger for structured operational error/warning accumulation
Adds workflow-logger.ts — a centralized in-memory accumulator for operational
warnings and errors across the GSD engine pipeline.
Key additions vs the standalone/workflow-logger branch:
- Fix hasWarnings() to filter severity === "warn" (was returning _buffer.length > 0,
incorrectly returning true for error-only buffers)
- Add hasAnyIssues() for callers that want to check for either severity
- Add drainAndSummarize() atomic helper to prevent the drain-before-summarize footgun
- Document singleton safety requirement: callers must _resetLogs() per unit
- Document always-on stderr policy (intentional, unlike debug-logger opt-in)
- Move test from engine/ to tests/ to match project test discovery glob
- Expand test suite from 15 to 32 cases: stderr output, context handling,
hasWarnings with errors-only buffer, drainAndSummarize, double-drain,
warnings-only summarize, formatForNotification context exclusion,
buffer limit robustness, ISO timestamp validation
* feat(gsd): wire workflow-logger into engine, tool, manifest, and reconcile paths
Routes 34 previously silent/raw-stderr error and warning sites through the
structured workflow-logger so the auto-loop can drain and surface root causes.
Changes by component:
tool (12 sites) — bootstrap/db-tools.ts
All 12 gsd_* tool handler catch blocks replaced from process.stderr.write
to logError("tool", ...) with { tool, error } context.
engine (9 sites) — auto/phases.ts (7), auto/run-unit.ts (2)
7 silent catches in phases.ts annotated with logWarning("engine", ...):
health gate, milestone merge, completed-units archive, STATE.md rebuild,
baseline char count, prompt reorder failure, disk flush.
2 silent catches in run-unit.ts: chdir and clearQueue failures.
manifest (8 sites) — db-writer.ts
nextDecisionId, saveDecisionToDb, updateRequirementInDb, saveArtifactToDb
error paths replaced with logError("manifest", ...).
Shrinkage guard replaced with logWarning("manifest", ...).
reconcile (5 sites) — auto-worktree.ts (2), worktree-manager.ts (3)
Post-create hook failure, teardown directory persistence, stale worktree
removal, submodule stash, stash failure — all replaced with
logWarning("reconcile", ...) with { worktree } context.
No control flow changed. TypeScript clean. 32/32 tests pass.
* fix(gsd): use info.name instead of global name in auto-worktree logWarning call
Two changes:
1. pruneActivityLogs: when retentionDays is 0, skip mtime comparison and
unconditionally remove all files except highest-seq. On Windows, NTFS
timestamp resolution meant freshly-created files could have mtime >=
Date.now() at cutoff calculation, so none were pruned.
2. CI: remove the push-to-main gate on windows-portability so it runs on
PRs too — catches Windows failures before merge instead of after.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(web): make web UI mobile responsive
Fixes#2274
Add mobile-first responsive design to the GSD web UI:
- Viewport meta tag via Next.js Viewport export
- Collapsible sidebar as slide-out drawer on mobile with hamburger menu
- Milestone explorer as right-side drawer on mobile with bottom bar toggle
- Responsive header: hide project label, scope badge, beta badge on small screens
- Dashboard: responsive grid (1col mobile -> 2col sm -> 4col xl), responsive padding
- Status bar: hide secondary info on small screens, responsive text sizing
- Touch-friendly 44px minimum tap targets on mobile nav items
- Mobile CSS utilities in globals.css (overlay, drawer transitions)
- 19 structural tests verifying responsive classes exist in key components
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ci: retrigger after stale check
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the user's home directory is a git repo (e.g. dotfile managers like
yadm), isInheritedRepo() found ~/.gsd and concluded that subdirectories
were part of an existing GSD project — loading the wrong project state.
Extract isProjectGsd() to distinguish a project .gsd (symlink to external
state, or legacy directory) from the global ~/.gsd state directory by
comparing against the resolved GSD_HOME path.
Fixes#2393
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After migration to DB-backed state, milestones on disk that were never
imported into the DB became invisible. deriveStateFromDb now scans the
milestones directory and injects synthetic entries for any disk-only
milestones, then re-sorts to maintain canonical order.
Fixes#2416
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dispatch-time writeUnitRuntimeRecord call in runUnitPhase did not
reset recoveryAttempts, so the counter from a prior execution's timeout
carried over to subsequent dispatches. This caused re-dispatched units
to be instantly skipped (recoveryAttempts >= maxRecoveryAttempts) with
no steering message or second chance.
Add `recoveryAttempts: 0` to the dispatch-time runtime record write so
each execution starts with its full recovery budget.
Fixes#2322
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Worktree teardown with --force destroyed uncommitted changes in
submodule directories. Now detects .gitmodules, checks submodule
status for uncommitted changes, and stashes them before removal.
When submodules have dirty state, attempts non-force removal first.
Fixes#2337
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When bootstrapAutoSession finds a survivor milestone branch and the
derived state phase is "complete", recovery was skipped entirely because
the survivor branch detection only triggered for phase === "pre-planning".
This left the milestone worktree/branch alive and routed bootstrap into
showSmartEntry instead of running finalization (merge, cleanup).
Changes:
- Broaden survivor branch detection to also check phase === "complete"
- Add explicit finalization path: when hasSurvivorBranch && phase ===
"complete", call resolver.mergeAndExit() to run the pending merge and
worktree cleanup, then re-derive state so the normal flow continues
- After finalization, clear hasSurvivorBranch so the "all milestones
complete" or "next milestone" path runs correctly
Fixes#2358
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collects a snapshot of all milestones (status, dependencies, slice progress,
queue order) and dispatches a prompt that turns Claude into a reorganization
assistant. Supports reordering, parking, unparking, discarding, adding
milestones, and updating dependencies through conversation.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The completed-units-metrics-sync source-scanning test used a 700-char
window that was too small when Windows CRLF line endings inflated byte
offsets, causing the archive keyword check to miss by ~2 chars.
Widens the window to 1200 chars and lowercases the comparison so
"Archive" and "cpSync" match regardless of case or line ending style.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add `full_plan_md` TEXT column to the tasks table, following the
established `full_summary_md` pattern. When populated,
`renderTaskPlanFromDb()` writes the stored markdown directly instead
of regenerating a minimal version from individual DB fields.
- DB schema: add `full_plan_md` column (migration v11)
- `TaskPlanningRecord` / `upsertTaskPlanning`: accept and persist `fullPlanMd`
- `renderTaskPlanFromDb`: prefer `full_plan_md` when non-empty
- plan-task, plan-slice, replan-slice tools: pass `fullPlanMd` through
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add inline rendering to gsd_decision_save, gsd_requirement_update,
gsd_summary_save, and gsd_milestone_generate_id so the TUI shows
meaningful context during and after tool execution instead of generic
static labels.
Before: '⏳ Save Decision' (no context)
After: '⏳ decision_save [architecture] Use SQLite — better-sqlite3'
'✓ Decision D042 saved → DECISIONS.md'
Follows the established pattern from context7 and search-the-web:
{toolTitle bold name} {accent primary arg} {muted/dim metadata}
Closes#2236
stopAuto Step 4 previously always called exitMilestone(preserveBranch: true),
which preserved the worktree branch but never merged it back. When auto-mode
stopped after complete-milestone, the code stayed stranded on the worktree branch.
Now checks if the milestone has a SUMMARY file (completion signal) and calls
mergeAndExit instead, so completed milestone code reaches main.
Fixes#2317
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new `/gsd mcp` slash command that shows configured MCP servers,
their connection status, and available tools. Supports two subcommands:
- `/gsd mcp status` (default) — overview of all servers
- `/gsd mcp check <server>` — detailed info for a specific server
Exports a `getConnectionStatus()` helper from the mcp-client extension
so the command can query live connection state.
Fixes#1489
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Doctor flagged missing_slice_dir and missing_tasks_dir as ERROR for
slices with status "pending" — slices that plan-milestone inserted but
haven't been dispatched yet. These directories are created lazily by
ensurePreconditions() at dispatch time, so their absence is expected.
Preserve the DB status field in the slice mapping and skip directory
checks entirely for pending slices.
Closes#2446
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(gsd): migrate completion/validation prompts to DB-backed tools and fix pipeline inconsistencies (#2444)
- Create gsd_validate_milestone tool (handler + DB registration) using assessments table
- Update complete-milestone.md to use gsd_complete_milestone instead of manual file writes
- Update validate-milestone.md to use gsd_validate_milestone + gsd_reassess_roadmap for remediation
- Add buildSkillActivationBlock() to 4 missing prompt builders (complete-milestone, validate-milestone, run-uat, reassess-roadmap)
- Remove dead completedSliceSummaryPath variable from reassess-roadmap builder
- Remove dead "degraded fallback" sections from replan-slice.md and reassess-roadmap.md
- Fix plan-slice.md double-tool instruction (gsd_plan_slice already persists tasks)
- Fix inconsistent commit/write instructions in complete-milestone.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update tests for new tool registration and prompt changes
- Add gsd_validate_milestone to tool-naming RENAME_MAP (24→26 tools)
- Update prompt-contracts assertions for removed fallback text and singular DB tool phrasing
- Restore {{roadmapPath}}, {{assessmentPath}}, {{planPath}}, {{replanPath}} template vars in prompts for context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restore {{milestoneSummaryPath}} template var in complete-milestone prompt
Test expects the milestone summary path reference in the prompt content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a file already exists on disk and the new content is <50% of the
existing file size, skip the disk write and store the existing file
content in the DB instead. This prevents data loss when research prompts
write full content via `write` then `gsd_summary_save` is called with
an abbreviated summary.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MergeConflictError from squash merge was caught silently in
worktree-resolver's mergeAndExit, so the auto loop retried the
merge forever. Now:
1. worktree-resolver re-throws MergeConflictError after cleanup
2. auto/phases.ts catches it at all 3 mergeAndExit call sites
3. On conflict, stops the loop with a clear error message
Fixes#2330
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: complete offline mode support for local-only model setups
- Add isLocalModel() to detect localhost/127.0.0.1/0.0.0.0/::1/unix sockets
- Add isAllLocalChain() to verify all registry models are local
- Validate --offline flag rejects remote models with clear error
- Auto-enable PI_OFFLINE when all configured models are local
- Return dummy API key for local models to skip auth validation
- Filter web search results in offline mode (chat-controller + tool-execution)
- Add ECONNREFUSED/ENOTFOUND/ENETUNREACH to INFRA_ERROR_CODES for immediate
failure (no retry) when network is intentionally unavailable
- Add comprehensive test suite (17 tests)
Fixes#2341
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(test): update infra-error test for new offline-mode error codes
The offline mode feature added ECONNREFUSED, ENOTFOUND, and ENETUNREACH
to INFRA_ERROR_CODES but the test still asserted size === 6. Update the
count to 9 and add detection tests for the three new codes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
classifyProviderError now recognizes terminated, connection reset, connection
refused, fetch failed, and other network errors as transient. These get a 15s
backoff delay and auto-resume instead of being treated as permanent failures
requiring manual intervention.
Fixes#2309
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs fixed:
1. completed-units.json was wiped to [] on milestone transition, losing all
tracking data. Now archived to completed-units-{MID}.json before reset.
2. metrics.json was never synced between worktree and project root. Added to
syncStateToProjectRoot, syncWorktreeStateBack, and syncGsdStateToWorktree
file lists.
Fixes#2313
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added parseEstimateMinutes() to parse estimate strings like "30m", "2h",
"1h30m" into minutes. startUnitSupervision now looks up the task estimate
from the DB and scales soft/hard timeouts accordingly. A 30m task gets 3x
the default timeout, a 2h task gets 12x. Idle timeout is not scaled
because idle is idle regardless of task size.
Also added taskEstimate field to SupervisionContext interface for explicit
estimate passing from callers.
Fixes#2243
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three bugs prevented auto_pr from ever creating a PR:
1. auto_pr was gated on `pushed` flag which requires auto_push to also be
true. Changed condition to `!nothingToCommit` so auto_pr works independently.
2. phases.ts called createDraftPR AFTER mergeAndExit (when we're back on main
and the milestone branch may not exist on remote). Removed duplicate PR
creation from phases.ts — it's already handled inside mergeMilestoneToMain.
3. createDraftPR in git-service.ts lacked --head and --base parameters, so
gh would create a PR from whatever branch was current. Added optional
opts parameter with head/base support.
Fixes#2302
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gsd_milestone_generate_id creates a minimal DB row (status: 'queued')
via INSERT OR IGNORE when generating an ID. This ensures milestones
created via /gsd queue or multi-milestone discuss are visible to the
state machine from the moment they get an ID, rather than relying on
the safety-net reconciliation in deriveStateFromDb().
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(gsd): reconcile disk-only milestones into DB in deriveStateFromDb
Milestones created via /gsd queue (or by complete-milestone writing a
next CONTEXT.md) are never inserted into the DB because the migration
guard in auto-start.ts only runs when gsd.db does not yet exist.
deriveStateFromDb() called getAllMilestones() (DB-only) with no disk
fallback, so these queued milestones were invisible to the state machine.
When all DB-tracked milestones completed, phase='complete' fired and
auto-mode stopped even though untracked milestones existed on disk.
Fix: add an incremental disk→DB reconciliation step inside
deriveStateFromDb() that compares findMilestoneIds() against DB rows
and calls insertMilestone() (INSERT OR IGNORE) for any non-ghost
directory that has no DB row. Re-queries only when rows were inserted.
Adds a regression test that reproduces the exact scenario from #2416:
M001 complete in DB, M002 queued on disk only → before fix phase was
'complete', after fix phase is 'pre-planning' with both milestones
visible in the registry.
Closes#2416
* fix: add missing closing brace for describe block in test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Jeremy McSpadden <jeremy@fluxlabs.net>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
parsePreferencesMarkdown emitted a console.warn every time preferences
were loaded with an unrecognized format, spamming stderr on each call
to loadEffectiveGSDPreferences. Gate the warning behind a warn-once
flag so it prints at most once per process.
Fixes#2373
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(system-context): inject global ~/.gsd/agent/KNOWLEDGE.md into system prompt
Reads ~/.gsd/agent/KNOWLEDGE.md (global) alongside the existing project
.gsd/KNOWLEDGE.md and merges both into the [KNOWLEDGE] block. Global
section appears first so project entries can override or refine global
rules. Emits a startup warning when the global file exceeds 4 KB to
keep system prompt size in check.
Extracted loading logic into loadKnowledgeBlock() for testability.
Five new unit tests cover: empty state, project-only, global-only,
merged order, and size threshold.
Closes#2316
* fix(test): relax derive-state-db perf threshold from 1ms to 10ms
The <1ms assertion was intermittently failing on loaded CI runners
(observed: 1.054ms). 10ms still validates the in-memory cache path
is fast while being robust across shared CI environments.
---------
Co-authored-by: TÂCHES <afromanguy@me.com>
* fix(gsd-db): add PRAGMA busy_timeout and foreign_keys
Concurrent worktrees sharing a WAL-mode DB get immediate SQLITE_BUSY
errors without a retry window. Add busy_timeout = 5000ms for file-backed
DBs. Enable foreign_keys per-connection so FK constraints declared in
the schema are actually enforced — prevents orphaned rows in slices,
tasks, verification_evidence, etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(prompts): replace direct file writes with DB tool calls
plan-milestone.md single-slice fast path instructed mkdir + direct file
writes, bypassing gsd_plan_slice. discuss.md instructed writing
ROADMAP.md directly instead of calling gsd_plan_milestone. Both create
state where the DB has no knowledge of planning artifacts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(recover): wrap delete + repopulate in single transaction
handleRecover deleted hierarchy rows inside a transaction, then called
migrateHierarchyToDb() outside it. A crash mid-repopulate left a
partially populated DB. Wrap both operations in one dbTransaction()
call for atomicity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(tools): add rollback on render failure
plan-milestone and plan-slice committed DB transactions then rendered
markdown — if rendering failed, DB had planning data with no file on
disk. db-writer functions (saveDecisionToDb, updateRequirementInDb,
saveArtifactToDb) had the same issue: DB upsert before disk write with
no rollback. Add rollback logic matching the complete-task.ts pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(gsd): add gsd_complete_milestone tool and rogue detection gaps
Task and slice completion had DB-backed tools but milestone completion
used direct file writes. Add gsd_complete_milestone following the same
pattern: validate all slices complete, update DB status in transaction,
render SUMMARY.md, rollback on failure.
Extend detectRogueFileWrites() to cover reassess-roadmap (ASSESSMENT.md),
plan-task (T##-PLAN.md), and REPLAN.md — previously undetected bypass
paths.
Replace regex checkbox fallback in retry state-reset with explicit
failure + stderr log. Direct markdown mutation on DB-unavailable
reintroduced the pattern the migration eliminated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(gsd): update stale comments, add legacy markers, DB-first queries
- state.ts: update module header and deriveState docstring to reflect
DB-primary architecture. Add DB-first query to getActiveMilestoneId()
with filesystem fallback. Add LEGACY marker on _deriveStateImpl().
- commands-maintenance.ts: add DB query before parseRoadmap() for stale
branch cleanup.
- prompts: replace "toggles the checkbox" language with DB-accurate
descriptions in execute-task.md and complete-slice.md.
- auto-recovery.ts: add LEGACY markers on !isDbAvailable() fallback
branches.
- gsd-db.ts: add DEAD CODE annotations on sequence column definitions
(no tool exposes sequence — always defaults to 0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(tools): preserve DB rows on render failure instead of rolling back
The plan-milestone and plan-slice handlers were rolling back DB rows when
file rendering failed, destroying parse-visible state needed for debugging.
DB rows now persist on render failure. Also guard rollback references to
non-existent tables (slice_planning, task_planning, milestone_planning).
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(core): add generic native post-install hooks for package install
* feat(core): add before/after install/remove lifecycle hooks
* refactor(core): remove postInstall alias from lifecycle hook fallback
* feat(core): complete authMode support for keyless providers
The initial authMode implementation fixed model-registry, sdk, and
fallback-resolver but missed agent-session.ts (6 callsites) and
compaction-orchestrator.ts (2 callsites) that block externalCli
providers at runtime.
Architecture: separate readiness gating from credential retrieval.
- isProviderRequestReady(): authMode-aware readiness check
- getApiKey()/getApiKeyForProvider(): return undefined for
externalCli/none providers instead of triggering auth errors
- All 8 callsites in agent-session and compaction-orchestrator
now gate on readiness, not key presence
- Downstream signatures (compaction, branch-summarization) accept
apiKey: string | undefined
- Replaced hardcoded ollama exception in discoverModels with
isProviderRequestReady
Zero behavioral change for classic apiKey/oauth providers.
* feat(core): add isReady callback for provider readiness verification
Extensions can now provide an isReady() callback when registering any
provider. isProviderRequestReady() calls it before default auth checks,
allowing providers to verify actual reachability (CLI authenticated,
API key valid, service online) rather than relying solely on credential
presence.
* test(core): expand authMode test coverage
Cover all four auth modes (apiKey, oauth, externalCli, none),
isReady callback behavior, getProviderAuthMode defaults,
isProviderRequestReady for each mode, getAvailable filtering,
and getApiKey early-return for keyless providers.
* chore: remove provider-api-bridge files from this branch
These files implement GSD core → provider-api wiring (deps + tool
registry) and belong in a separate PR. Reverts register-extension.ts
to upstream state.
Windows CI runners hold git file locks that prevent rmSync from removing
temp repos in finally blocks. Wrap cleanup in try-catch so a cleanup
failure doesn't fail the actual test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>