Commit graph

1897 commits

Author SHA1 Message Date
TÂCHES
e2eb5cecf2 fix(gsd): handle retentionDays=0 on Windows + run windows-portability on PRs (#2460)
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>
2026-03-25 00:17:22 -06:00
madjack
f4ecf9d11a fix: use Array.from instead of Buffer.from for native processStreamChunk state (#2348)
The napi StreamState fields (utf8Pending, ansiPending) expect plain arrays
(Vec<u8>), not Buffers. Passing Buffer.from() caused 'Given napi value is
not an array on StreamState.utf8Pending' crash on multi-chunk bash output.

Added regression test for multi-chunk state passing.

AI-assisted: This change was authored with Claude (AI pair programming).
2026-03-25 00:08:11 -06:00
Tom Boucher
5b0c24a92c feat(web): make web UI mobile responsive (#2354)
* 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>
2026-03-25 00:07:39 -06:00
Tom Boucher
3522b54618 fix(gsd): isInheritedRepo conflates ~/.gsd with project .gsd when git root is $HOME (#2398)
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>
2026-03-25 00:07:22 -06:00
Tom Boucher
be4037be90 fix: reconcile disk milestones missing from DB in deriveStateFromDb (#2416) (#2422)
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>
2026-03-25 00:06:47 -06:00
Tom Boucher
aa3ac89bf8 fix(auto): reset recoveryAttempts on unit re-dispatch (#2322) (#2424)
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>
2026-03-25 00:06:23 -06:00
Tom Boucher
e115909fd0 fix: detect and preserve submodule state during worktree teardown (#2337) (#2425)
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>
2026-03-25 00:06:04 -06:00
Tom Boucher
fa8e5500ac fix(auto-start): handle survivor branch recovery in phase=complete (#2358) (#2427)
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>
2026-03-25 00:05:39 -06:00
TÂCHES
ea8976d16e feat(gsd): add /gsd rethink command for conversational project reorganization (#2459)
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>
2026-03-25 00:04:24 -06:00
TÂCHES
109f8e4461 fix(gsd): widen test search window for CRLF portability on Windows (#2458)
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>
2026-03-24 23:55:36 -06:00
TÂCHES
c77148632b fix(gsd): preserve rich task plans on DB roundtrip (#2450) (#2453)
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>
2026-03-24 23:40:56 -06:00
mastertyko
98f5daeda8 feat(gsd): add renderCall/renderResult previews to DB tools (#2273)
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
2026-03-24 23:31:56 -06:00
Tom Boucher
58631bba2b fix: merge worktree back to main when stopAuto is called after milestone completion (#2317) (#2430)
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>
2026-03-24 23:21:00 -06:00
madjack
f21ad837ac feat: add timestamps on user and assistant messages (#2368)
Shows absolute timestamps (date + time) on user prompts (right-aligned
above the message) and assistant replies (below the response). Format
is configurable via /settings → Timestamp format:

- date-time-iso: 2026-03-24 10:34 (default)
- date-time-us:  03-24-2026 10:34 AM

Setting persists in settings.json as timestampFormat.

- Added formatTimestamp utility with ISO and US format support
- Updated UserMessageComponent and AssistantMessageComponent
- Added timestampFormat to SettingsManager with getter/setter
- Added to /settings UI for runtime switching
- Unit tests for all format variants including AM/PM edge cases

AI-assisted: This change was authored with Claude (AI pair programming).
2026-03-24 23:18:42 -06:00
TÂCHES
61fcc0fbee Merge pull request #2451 from gsd-build/fix/doctor-pending-slice-false-errors
fix(gsd): skip doctor directory checks for pending slices
2026-03-24 23:18:41 -06:00
Tom Boucher
515fe0295b feat(gsd): add /gsd mcp command for MCP server status and connectivity (#2362)
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>
2026-03-24 23:18:31 -06:00
Lex Christopherson
ed95e70534 fix(gsd): skip doctor directory checks for pending slices (#2446)
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>
2026-03-24 23:14:47 -06:00
TÂCHES
b9ff5d5052 fix(gsd): migrate completion/validation prompts to DB-backed tools (#2449)
* 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>
2026-03-24 23:08:27 -06:00
TÂCHES
9a6a341b57 fix(gsd): prevent saveArtifactToDb from overwriting larger files with truncated content (#2442) (#2447)
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>
2026-03-24 22:36:19 -06:00
Tom Boucher
cf0fe6c571 fix: stop auto loop on real code merge conflicts (#2330) (#2428)
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>
2026-03-24 22:36:06 -06:00
Tom Boucher
df269b3b00 feat: complete offline mode support (#2429)
* 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>
2026-03-24 22:35:45 -06:00
Tom Boucher
17ce3085f9 fix: classify terminated/connection errors as transient in provider error handler (#2309) (#2432)
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>
2026-03-24 22:35:19 -06:00
Tom Boucher
5d0c6311f1 fix: archive completed-units.json on milestone transition and sync metrics.json (#2313) (#2431)
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>
2026-03-24 22:35:01 -06:00
Tom Boucher
81de9f60c5 fix: supervision timeouts now respect task est: annotations (#2243) (#2434)
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>
2026-03-24 22:34:45 -06:00
Tom Boucher
2ddb790141 fix: auto_pr: true now actually creates PRs — fix 3 interacting bugs (#2302) (#2433)
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>
2026-03-24 22:34:14 -06:00
TÂCHES
e39dc7976c fix(gsd): insert DB row when generating milestone ID (#2416)
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>
2026-03-24 22:26:39 -06:00
TÂCHES
c9e6d50004 fix(gsd): reconcile disk-only milestones into DB in deriveStateFromDb (#2416)
* 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>
2026-03-24 22:20:45 -06:00
Tom Boucher
d21db9f398 fix(preferences): deduplicate unrecognized format warning on repeated loads (#2375)
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>
2026-03-24 22:06:37 -06:00
Jeremy McSpadden
e0b3bad2a5 feat(system-context): inject global ~/.gsd/agent/KNOWLEDGE.md into system prompt (#2331)
* 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>
2026-03-24 22:03:00 -06:00
Tom Boucher
cace21cb02 docs(contributing): add testing standards section (#2441)
Codifies node:test patterns, cleanup hooks (beforeEach/afterEach vs
t.after() vs try/finally), template literal fixture guidance, and
test-first requirement for bug fixes. These standards reflect the
patterns established during the 10-PR test modernization effort.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:01:53 -06:00
Tom Boucher
17e172b466 fix: gate auto-mode bootstrap on SQLite availability (#2419) (#2421) 2026-03-24 21:37:19 -06:00
Tom Boucher
6409070225 fix: block /gsd quick when auto-mode is active (#2420) 2026-03-24 21:36:56 -06:00
Tom Boucher
3e68acfa11 docs: sync documentation with codebase through v2.44.0 (#2415) 2026-03-24 21:36:25 -06:00
Tom Boucher
b24594d79f refactor: migrate D-G test files from createTestContext to node:test (#2418) 2026-03-24 21:34:52 -06:00
Tom Boucher
e4d21c40d0 refactor(test): replace try/finally with beforeEach/afterEach in packages tests (#2390) 2026-03-24 21:34:10 -06:00
Tom Boucher
77460942ac refactor(test): migrate gsd/tests s-z from custom harness to node:test (#2397) 2026-03-24 21:33:39 -06:00
Tom Boucher
1fe52a2e8e refactor(test): migrate gsd/tests o-r from custom harness to node:test (#2401) 2026-03-24 21:33:17 -06:00
Tom Boucher
4498dcea32 refactor(test): migrate gsd/tests i-n from custom harness to node:test (#2399) 2026-03-24 21:33:01 -06:00
Tom Boucher
b1782a8678 refactor(test): migrate gsd/tests a-c from custom harness to node:test (#2400) 2026-03-24 21:32:26 -06:00
Tom Boucher
c237c56016 refactor(test): replace try/finally with t.after() in gsd/tests (e-i) (#2396) 2026-03-24 21:31:42 -06:00
Tom Boucher
2223298f76 refactor(test): replace try/finally with t.after() in gsd/tests (a-d) (#2395) 2026-03-24 21:31:29 -06:00
Tom Boucher
30775f4dcc refactor(test): replace try/finally with t.after() in src/tests (o-z) (#2392) 2026-03-24 21:30:29 -06:00
Tom Boucher
99af6b0315 refactor(test): replace try/finally with t.after() in src/tests (a-n) (#2394) 2026-03-24 21:30:00 -06:00
Lex Christopherson
ea0b1e4444 fix(ci): add Rust target for all platforms, not just cross-compilation
macOS x64 builds on ARM64 runners also need the target added explicitly.
Use rustup target add for all matrix entries to avoid Blacksmith's
target rewriting in dtolnay/rust-toolchain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:22:36 -06:00
Lex Christopherson
b80cebfd4a fix(ci): restore Rust target triple and separate cross-compilation setup
Blacksmith migration (#2414) incorrectly rewrote the Rust target triple
aarch64-unknown-linux-gnu to the runner label blacksmith-4vcpu-ubuntu-2404-arm.
Restore the correct Rust target and split cross-compilation target addition
into an explicit rustup command.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:18:31 -06:00
Lex Christopherson
f33e27734b fix(ci): separate cross-compilation target from toolchain install
dtolnay/rust-toolchain resolves Blacksmith runner hostnames as Rust
targets on ARM64 runners. Split target addition into explicit rustup
command for cross-compilation builds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:17:13 -06:00
github-actions[bot]
9e31a6985c release: v2.44.0 2026-03-24 22:09:37 +00:00
blacksmith-sh[bot]
c523d49590 Migrate workflows to Blacksmith (#2414)
Co-authored-by: blacksmith-sh[bot] <157653362+blacksmith-sh[bot]@users.noreply.github.com>
2026-03-24 15:58:30 -06:00
TÂCHES
ebfc63c42b fix: post-migration cleanup — pragmas, rollbacks, tool gaps, stale code (#2410)
* 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>
2026-03-24 15:55:26 -06:00
Jay The Reaper
bc278d12d9 feat(core): support for 'non-api-key' provider extensions like Claude Code CLI (#2382)
* 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.
2026-03-24 15:50:12 -06:00