Commit graph

1541 commits

Author SHA1 Message Date
Copilot
596b941475 Fix health widget false 'Anthropic key missing' when authenticated via GitHub Copilot (#1522)
* Initial plan

* Fix health widget false 'Anthropic key missing' when authenticated via GitHub Copilot

- Use getEnvApiKey() from @gsd/pi-ai for authoritative env var resolution
  (checks ANTHROPIC_OAUTH_TOKEN, COPILOT_GITHUB_TOKEN, GH_TOKEN, etc.)
- Add cross-provider routing: GitHub Copilot auth satisfies Anthropic/OpenAI requirements
- Add github-copilot to modelToProviderId prefix map
- Keep PROVIDER_REGISTRY env var fallback for non-LLM providers (search/tools)
- Add tests for cross-provider routing and multi-env-var detection

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
2026-03-19 23:33:05 -06:00
TÂCHES
e4cd141503 fix(gsd): enforce backtick file paths in task plan IO sections (#1548)
* fix(gsd): enforce backtick file paths in task plan IO sections

The reactive task graph (ADR-004) derives dependencies from backtick-wrapped
file paths in ## Inputs and ## Expected Output sections. Without concrete
paths, the graph is ambiguous and falls back to sequential execution.

Changes:
- task-plan.md template: add comments explaining paths are machine-parsed
- plan-slice.md prompt: explicitly instruct planner to write backtick file
  paths in IO sections, add self-audit check for path presence
- observability-validator.ts: new validation rules missing_output_file_paths
  (warning) and missing_input_file_paths (info) catch plans without paths
- plan-quality-validator.test.ts: 4 new test cases for IO path validation

* fix(ci): increase max_tokens and add JSON parse error handling in ai-triage

max_tokens: 300 was too low, causing truncated JSON responses from Claude
that failed to parse. Bumped to 1024 and added try/catch with raw text
logging for easier debugging.

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-19 23:28:44 -06:00
TÂCHES
567751471a feat(gsd): ADR-004 — derived-graph reactive task execution (#1546)
Add reactive (graph-derived parallel) task execution within slices.
When enabled via preferences, the dispatch table derives a task dependency
graph from IO annotations in task plans and dispatches multiple ready,
non-conflicting tasks in parallel via subagent.

Architecture:
- Graph derivation happens at dispatch time (auto-dispatch.ts)
- A new reactive-execute prompt instructs the agent to use subagent
  parallel mode to dispatch all currently-ready tasks
- The auto-loop treats reactive-execute as a single unit type
- After agent_end, the orchestrator checks which tasks completed and loops

New files:
- reactive-graph.ts: pure graph derivation, ready-set resolution,
  conflict detection, deadlock detection, IO loader, state persistence
- prompts/reactive-execute.md: prompt template for parallel dispatch
- tests/reactive-graph.test.ts: 22 unit tests for graph functions
- tests/reactive-executor.test.ts: 11 integration tests for dispatch
  rules, preferences validation, state persistence, re-entry

Modified files:
- types.ts: TaskIO, DerivedTaskNode, ReactiveExecutionConfig,
  ReactiveExecutionState interfaces
- files.ts: parseTaskPlanIO() extracts IO from task plan sections
- preferences-types.ts: reactive_execution config + known keys
- preferences-validation.ts: validation with range checks
- auto-dispatch.ts: new reactive-execute dispatch rule
- auto-prompts.ts: buildReactiveExecutePrompt()
- auto-recovery.ts: artifact verification for reactive-execute
- auto-post-unit.ts: reactive state cleanup on slice completion

Backward compatible: disabled by default, falls through to sequential
execution when disabled, ambiguous, or only 1 task is ready.
2026-03-19 23:19:46 -06:00
Nathan Roe
39cd932abb feat: add anthropic-vertex provider for Claude on Vertex AI (#1533)
* feat: add anthropic-vertex provider for Claude models on Google Vertex AI

Add a new anthropic-vertex provider that enables using Claude models
(Opus 4.6, Sonnet 4.6, Haiku 4.5) through Google Vertex AI using the
@anthropic-ai/vertex-sdk package. Follows the same pattern as the
existing google/google-vertex provider split.

Detection uses ANTHROPIC_VERTEX_PROJECT_ID (same env var as Claude Code)
with CLOUD_ML_REGION for region selection, falling back to us-central1.

Extracts shared Anthropic utilities into anthropic-shared.ts (message
conversion, tool conversion, param building, stream processing) to
avoid duplication between anthropic.ts and anthropic-vertex.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add full Claude model set for anthropic-vertex provider

Add 200K context window variants for Opus 4.6 and Sonnet 4.6, plus
older models (Sonnet 4.5, Sonnet 4, Opus 4.5, Opus 4.1, Opus 4, Haiku 4.5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add @anthropic-ai/vertex-sdk to root dependencies

Required for the published package to resolve the vertex SDK at runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove unnecessary comments to match codebase style

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove duplicate stream functions after rebase

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Nathan Roe <nathan.roe@carvana.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 23:14:13 -06:00
Jeremy McSpadden
111537f460 docs: fix stale references across documentation (#1543)
* docs: update README for v2.37 — changelog, extensions, stale refs

- Update "What's New" section from v2.33 to v2.37
- Update extensions table: add Async Jobs and GitHub, remove LSP (Pi SDK core)
- Fix extension count in architecture section (12 → 18)
- Remove stale v2.17 version tags from Token Optimization section

* docs: fix stale references across documentation

- commands.md: update version example from v2.28 to v2.37
- troubleshooting.md: fix Node.js requirement from ≥20.6.0 to ≥22.0.0
- skills.md: fix project-local skills path from .pi/ to .gsd/
- CONTRIBUTING.md: fix scope area paths to include packages/ prefix,
  remove incorrect PR #1232 supply chain attack reference
- vscode-extension: fix Node.js requirement, remove hardcoded RPC
  command count (changes over time)

* docs: add troubleshooting for command not found after install

Addresses #1542 — npm global bin directory not in PATH is a common
issue on macOS, especially with Homebrew Node, version managers, or
oh-my-zsh git aliases.

- Add "command not found: gsd" section to troubleshooting.md
- Add callout to getting-started.md install section
2026-03-19 22:14:03 -06:00
github-actions[bot]
65647f83af release: v2.37.1 2026-03-20 04:08:02 +00:00
Jeremy McSpadden
1309e96d5d docs: update README for v2.37 — changelog, extensions, stale refs (#1540)
- Update "What's New" section from v2.33 to v2.37
- Update extensions table: add Async Jobs and GitHub, remove LSP (Pi SDK core)
- Fix extension count in architecture section (12 → 18)
- Remove stale v2.17 version tags from Token Optimization section
2026-03-19 21:55:47 -06:00
Bhumit Chaudhry
e856ac96af Update installation command for gsd-pi to latest version (#1538)
Just a minor edit to make sure the user doesn't have to update after launching
2026-03-19 21:41:00 -06:00
TÂCHES
2822a2954f fix: interactive guard menu for remote auto-mode sessions (#1507) (#1524)
Replace the simple notifyRemoteAutoActive notification with an interactive
guardRemoteSession menu that shows session details and offers actionable
choices (view status, steer, stop, or force start). Guards all auto-mode
entry points: bare /gsd, /gsd next, and /gsd auto.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:32:55 -06:00
Lex Christopherson
2a87687483 fix: use pull_request_target so AI triage has secret access on PRs
pull_request events from forks/branches cannot access repo secrets,
causing 401 auth failures on every PR triage. pull_request_target runs
in the base repo context. Safe because the workflow only reads event
payload data and sparse-checks base branch docs — no PR code executes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:23:27 -06:00
Jeremy McSpadden
71c3b12e70 fix: cmux library directory incorrectly loaded as extension (#1537)
* fix(#1526): auto-mode worktree commits land on main instead of milestone branch

GitServiceImpl.getMainBranch() was designed to detect manual /worktree worktrees
(worktree/<name> branches) but incorrectly applied the same logic to auto-mode
worktrees (milestone/<MID> branches). When no worktree/<name> branch existed,
it fell back to the current branch, which in certain contexts could be main,
causing slice commits to land on main instead of the milestone branch.

Fix: Detect if currently on a milestone/* branch first (auto-mode case) and
return it, before checking for worktree/* branches (manual worktree case).

- Modify getMainBranch() to detect milestone branches first
- Add test verifying getMainBranch() returns correct branch in auto-worktree
- All tests pass, build succeeds

Fixes #1526

* fix: cmux library directory incorrectly loaded as extension

The extension auto-discovery in resolveExtensionEntries() finds
index.js files in subdirectories and treats them as extensions.
The cmux directory has an index.js but it's a utility library
(imported by gsd and subagent extensions), not an extension itself.

Two changes:
1. When a package.json has a "pi" manifest, treat it as authoritative
   and don't fall through to index.ts/index.js auto-detection. This
   lets library directories opt out with "pi": {}.
2. Add package.json to cmux directory with empty pi manifest.
2026-03-19 21:14:25 -06:00
Jeremy McSpadden
aa8d3ee059 fix: separate pi-tui-dependent layout utils to fix report generation (#1527)
Report generation in auto-loop uses native dynamic import() which
bypasses jiti's alias resolution. The import chain
metrics.js → mod.js → ui.js → @gsd/pi-tui failed because Node
cannot resolve @gsd/pi-tui from ~/.gsd/agent/extensions/.

Split ANSI-aware layout helpers (padRight, joinColumns, centerLine,
fitColumns) into layout-utils.ts and keep format-utils.ts pure so
report modules can import formatting functions without pulling in
the @gsd/pi-tui dependency.
2026-03-19 21:14:03 -06:00
Jeremy McSpadden
2fcbb40c09 fix: clarify session lock loss diagnostics (#1535) 2026-03-19 21:13:38 -06:00
Jeremy McSpadden
df76eea764 fix(#1526): auto-mode worktree commits land on main instead of milestone branch (#1534)
GitServiceImpl.getMainBranch() was designed to detect manual /worktree worktrees
(worktree/<name> branches) but incorrectly applied the same logic to auto-mode
worktrees (milestone/<MID> branches). When no worktree/<name> branch existed,
it fell back to the current branch, which in certain contexts could be main,
causing slice commits to land on main instead of the milestone branch.

Fix: Detect if currently on a milestone/* branch first (auto-mode case) and
return it, before checking for worktree/* branches (manual worktree case).

- Modify getMainBranch() to detect milestone branches first
- Add test verifying getMainBranch() returns correct branch in auto-worktree
- All tests pass, build succeeds

Fixes #1526
2026-03-19 21:13:25 -06:00
github-actions[bot]
f83a85eb7c release: v2.37.0 2026-03-20 02:50:52 +00:00
Tom Boucher
7afefc73ac fix: add session-level search budget to prevent unbounded native web search (#1309) (#1529)
The Anthropic API's max_uses resets per request — when pause_turn triggers
a resubmit, the model gets a fresh budget each time. This allowed unlimited
total searches across a research unit, overwhelming the TUI render buffer.

Fix:
- Count web_search_tool_result blocks in conversation history on each
  before_provider_request to track cumulative searches per session
- Cap total native searches at 15 per session (3 full turns of 5)
- Dynamically set max_uses to min(5, remaining) — preserves per-turn cap
  while enforcing session ceiling
- When budget exhausted, omit web_search tool entirely instead of letting
  the model hit max_uses_exceeded repeatedly
- Reset counter on session_start (new agent unit)
- Add web search budget guidance to research prompts (defense in depth)

Tests: 5 new tests covering budget tracking, exhaustion, and reset.
All 35 native-search tests pass.
2026-03-19 20:08:15 -06:00
Jeremy McSpadden
c9d79a829c feat(dashboard): two-column layout with redesigned widget (#1530)
* feat(dashboard): two-column layout with redesigned widget

- Two-column layout: progress bar left, task checklist right
- 4 widget modes: full → small → min → off (cycle with /gsd widget)
- Health indicator and ETA in header line for immediate visibility
- Simplified stats: 3 items (hit rate, cost, context %) instead of 7
- Short PWD (last 2 segments), git worktree name with ⎇ prefix
- Last commit time + message in footer (cached every 15s)
- Preview script with mock data for all modes

* docs: add dashboard widget screenshots for PR #1530

* docs: update dashboard screenshots with wider renders

* docs: wider full-width dashboard screenshots

* feat(dashboard): persist widget_mode in preferences

- Add widget_mode to GSDPreferences and KNOWN_PREFERENCE_KEYS
- Load saved widget_mode from preferences on first access
- Persist to global PREFERENCES.md on /gsd widget change
- Default remains "full" when no preference is set
2026-03-19 20:07:18 -06:00
Jeremy McSpadden
b247c3510e feat: integrate cmux with gsd runtime (#1532) 2026-03-19 20:05:06 -06:00
github-actions[bot]
37d657b949 release: v2.36.0 2026-03-20 01:26:46 +00:00
TÂCHES
d57c6d4e46 fix: preserve user messages during abort with origin-aware queue clearing (#1439) (#1521)
When a user presses Escape during streaming, the abort flow clears all
queued messages indiscriminately. User messages typed during streaming
are silently discarded. This adds a QueueEntry wrapper in the Agent class
to track message origin ("user" vs "system"), so that clearQueue() can
preserve user-typed messages while discarding system-generated ones.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:05:04 -06:00
TÂCHES
816383a399 fix: remove broken SwiftUI skill and add CI reference check (#1476) (#1520)
Remove the bundled SwiftUI skill which had 13+ broken references to a
non-existent `../macos-apps/references/` directory. Add a CI script
that validates all relative .md file references in bundled skills,
preventing this class of bug from shipping again. Fix 5 additional
pre-existing broken references in other skills.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:04:37 -06:00
TÂCHES
69c0f68ac8 fix: wire escalateTier into auto-loop retry path (#1505) (#1519)
When a unit fails and is retried, the model tier is now escalated
(light -> standard -> heavy) if dynamic routing is enabled and
escalate_on_failure is not explicitly disabled. This connects the
existing escalateTier() function, which was fully implemented and
tested but never called at runtime.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:01:25 -06:00
TÂCHES
eb2939760f fix: prevent bare /gsd from stealing session lock from running auto-mode (#1507) (#1517)
Bare /gsd and /gsd next now check for a remote auto-mode session via
readSessionLockData before attempting to start step-mode. If another
process holds the lock, a steering menu is shown instead of competing
for the lock and killing the running session.

Also fixes the guided-flow "all slices discussed" message to detect
active auto-mode and direct users to /gsd status instead of bare /gsd.

Closes #1507

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:59:10 -06:00
TÂCHES
c2d46a951b fix: wire dead token-profile defaults and add /gsd rate command (#1505) (#1516)
- Wire resolveProfileDefaults into loadEffectiveGSDPreferences so
  token_profile: budget actually sets cheaper models and skips phases
- Add /gsd rate <over|ok|under> command to submit user feedback on
  model tier assignments, completing the adaptive routing feedback loop
- Document that models config is required for dynamic routing activation
- Document ceiling behavior when dynamic routing is active
- Document reassess_after_slice as required for reassessment

Closes #1505 (partial — escalateTier wiring deferred to follow-up)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:53:00 -06:00
TÂCHES
5424a169d9 fix: prevent false-positive session lock loss during sleep/event loop stalls (#1512) (#1513)
The onCompromised callback in the retry acquisition path lacked the
elapsed-time suppression that the primary path had, causing unconditional
_lockCompromised=true on benign mtime drift. Additionally, validateSessionLock
now attempts PID-based recovery and re-acquisition before declaring the lock
lost, preventing sessions from stopping when no other process has taken over.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:47:23 -06:00
TÂCHES
c680e2d90c feat: deprecate agent-instructions.md in favor of AGENTS.md / CLAUDE.md (#1492) (#1514)
Replace loadAgentInstructions() with a deprecation warning that fires when
legacy agent-instructions.md files are detected. Pi core already supports
AGENTS.md (with CLAUDE.md fallback) per directory, making the custom GSD
mechanism redundant.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:47:06 -06:00
TÂCHES
bae9cf83ba fix(gsd): filter non-milestone directories from findMilestoneIds (#1494) (#1508)
Directories under .gsd/milestones/ that don't match the M\d+ pattern
(e.g. slices/, temp-backup/) are now excluded instead of being returned
with their raw name. This prevents rogue directories from blocking
auto-mode milestone discovery.

Closes #1494

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:33:24 -06:00
TÂCHES
95f585d183 fix(gsd): accept 'passed' as terminal validation verdict (#1429) (#1509)
isValidationTerminal() now normalizes verdict: passed → pass before
comparison. LLM-generated validation files that write "passed" instead
of "pass" are accepted as terminal, preventing milestones from being
treated as incomplete.

Closes #1429

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:33:15 -06:00
TÂCHES
4c081fa556 feat: AI-powered issue and PR triage via Claude Haiku (#1510)
Adds a GitHub Actions workflow that automatically triages new issues and
PRs using Claude Haiku 4.5. Classifies with type and priority labels,
and flags items that violate VISION.md or CONTRIBUTING.md guidelines
with a `needs-review` label and explanatory comment. No auto-closing —
maintainer makes all final decisions.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:32:54 -06:00
TÂCHES
aa9e1cfea9 fix: add missing imports breaking CI build (#1511)
- Add missing `parseRoadmap` import in `auto-dispatch.ts`
- Add missing `unlinkSync` import in `auto.ts`
- Add missing `syncGsdStateToWorktree` import in `worktree-sync-milestones.test.ts`

All three were dropped during the PR #1419 merge.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:26:31 -06:00
TÂCHES
93fb33de28 docs: add VISION.md, CONTRIBUTING.md, and update PR template (#1506)
Establishes contributor guidelines based on maintainer team discussion.
VISION.md defines project identity, principles, and explicit rejection
criteria. CONTRIBUTING.md covers assign-then-PR workflow, RFC process
for architectural changes, AI disclosure policy, and testing standards.
PR template restructured around TL;DR + What/Why/How format.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:08:23 -06:00
Tom Boucher
8aa71bfb55 fix: prevent ensureGitignore from adding .gsd when tracked in git (#1364) (#1367)
* rfc: GitOps branching & versioning strategy proposal

Proposes a Git-Flow Lite model with automated integration branches:

  main          ← production-ready, tagged releases only
  next          ← integration branch for next minor (PRs target here)
  release/X.Y   ← stabilization branch, only bugfixes allowed
  hotfix/X.Y.Z  ← emergency fixes cherry-picked to release

Includes:
  - RFC document with lifecycle diagrams, migration path, open questions
  - Workflow scaffolds (in docs/proposals/workflows/, NOT .github/):
    - create-release.yml: manual dispatch to cut release branch from next
    - sync-next.yml: auto-sync next branch after version tags
    - backmerge.yml: auto back-merge release fixes to next

This is an experimental proposal requesting community feedback before
any implementation. The workflow files are inert scaffolds — they do
not run in CI.

* fix: prevent ensureGitignore from adding .gsd when tracked in git (#1364)

CRITICAL DATA-LOSS FIX: ensureGitignore() unconditionally added '.gsd' to
.gitignore even when .gsd/ was a real git-tracked directory, causing git to
report ~889 tracked files as deleted.

Root cause: BASELINE_PATTERNS included '.gsd' unconditionally, and the
gitignore modification ran BEFORE migration checks in auto-start.ts.

Changes:
- Add hasGitTrackedGsdFiles() helper using nativeLsFiles to detect tracked
  .gsd/ content
- ensureGitignore() now skips the '.gsd' pattern when .gsd/ has tracked files
- untrackRuntimeFiles() now skips entirely when .gsd/ has tracked files
- migrateToExternalState() aborts when .gsd/ has tracked files
- Reorder auto-start.ts: migration runs BEFORE gitignore modification
- Add 8 regression tests covering all scenarios

Fixes #1364

* fix: break recursive dialog loop when all milestones complete (#1348)

Two interacting bugs:

1. Recursive dialog loop: When all milestones are complete, bootstrapAutoSession
   calls showSmartEntry → sets pendingAutoStart → checkAutoStartAfterDiscuss
   calls startAuto → bootstrapAutoSession → showSmartEntry → infinite loop.
   The discuss workflow completes without producing a milestone directory, so
   phase stays 'complete' and the cycle never breaks.

   Fix: Add a re-entry counter (_consecutiveCompleteBootstraps) that tracks
   how many times bootstrapAutoSession enters the 'complete' branch without
   advancing. After 2 consecutive attempts, break the loop with a warning
   message and return false.

2. Missing _releaseFunction = null in retry lock onCompromised handler:
   The retry lock path in session-lock.ts set _lockCompromised but didn't
   null out _releaseFunction, which could leave a stale reference that
   masks the compromise detection in validateSessionLock().

Fixes #1348

* fix: self-heal stale roadmap checkbox for interrupted complete-slice (#1350)

When complete-slice is interrupted after writing SUMMARY.md and UAT.md but
before flipping the roadmap checkbox, auto-mode enters an infinite loop —
re-launching the same complete-slice unit because the dispatch loop uses
the roadmap checkbox as the sole 'slice done' signal.

Fix: Add a self-heal case in selfHealRuntimeRecords that detects when
SUMMARY + UAT exist but the roadmap checkbox is unchecked, and auto-fixes
the checkbox. This allows the verification to pass and the dispatch loop
to advance.

Fixes #1350

* fix: add EISDIR guard to complete/validate milestone prompts (#1343)

The LLM was passing tasks/ directory paths to the read tool during
milestone completion, causing EISDIR crashes. Added file system safety
instructions to both complete-milestone and validate-milestone prompts
telling the LLM to use ls/find for directory listing, not the read tool.

Fixes #1343

* feat: improve extension conflict messages with removal guidance (#1347)

When a user extension registers tools/commands that now ship as built-ins,
the conflict message now includes '(built-in tool supersedes — consider
removing <path>)' and the log level is downgraded from 'Extension load error'
to 'Extension conflict'.

Changes:
- resource-loader.ts: detect built-in vs user extension conflicts, add hint
- cli.ts: downgrade severity for superseded-tool conflicts

Fixes #1347

* test: fix always-skipped preferences test, add test:marketplace script

- preferences.test.ts: Replace always-skipped getIsolationMode test with
  a filesystem-independent version that validates the default through
  validatePreferences() instead of reading ~/.gsd/preferences.md.
  Reduces skipped count from 3 → 2.

- package.json: Add test:marketplace script for running marketplace
  contract tests (claude-import-tui, plugin-importer-live,
  marketplace-discovery) with GSD_TEST_CLONE_MARKETPLACES=1.
  These tests need external repos and self-skip in unit test runs.

Remaining 2 skips:
- Marketplace contract test suites (need external repos, run via test:marketplace)
- Windows-only tests in validate-directory.test.ts are platform-conditional
  and correctly skip on macOS

* fix: use execFileSync in regression tests for Windows portability

The regression tests used execSync with shell-dependent constructs:
- '&&' command chaining (works in bash/cmd but fragile)
- Single-quoted commit messages (bash-only, cmd.exe splits on spaces)

Replaced with execFileSync via a git() helper that bypasses the shell
entirely. Each git operation is a separate call with proper argument
arrays, eliminating all shell interpretation issues.

Fixes windows-portability CI failure.

* fix: guard milestone completion against missing slice summaries (#1368)

Auto-mode could report a milestone as complete after executing only the
last slice, skipping earlier unexecuted slices. The milestone completion
signal fired based on roadmap checkbox state, which could be stale or
inconsistent after worktree transitions.

Changes:
- auto-dispatch.ts: Added slice SUMMARY file existence check to both
  validating-milestone and completing-milestone dispatch rules. If any
  slice lacks a SUMMARY file, dispatch stops with a diagnostic error
  instead of proceeding to validation/completion.
- validate-milestone.test.ts: Updated tests to create slice summary
  files (required by the new guard).
- file-watcher.test.ts: Fixed flaky 'auth.json change emits auth-changed
  event' test by adding watcher initialization delay and increasing event
  propagation timeout (race condition when run in full suite).

Fixes #1368

* fix: warn on common misspelled preference keys + verify field guidance (#1373, #1341)

#1373: Users setting 'taskIsolation.mode: none' instead of 'git.isolation: none'
got a generic 'unknown key' warning. Added KEY_MIGRATION_HINTS that map common
misspellings (taskIsolation, task_isolation, isolation, manage_gitignore, auto_push,
main_branch) to their correct git.* equivalents with actionable messages.

#1341: Planning agent writes aspirational prose in Verify fields ('Sections 3.1
and 3.2 exist with exact formulas. Zero TBD.') instead of executable commands.
Added explicit verify field rules to the plan template: must be mechanically
executable, with examples of good vs bad patterns for content tasks.

Fixes #1373, partially addresses #1341

* refactor: extract roadmap-mutations.ts + shared test-utils.ts

Consolidation:
- roadmap-mutations.ts: Extracted markSliceDoneInRoadmap() and markTaskDoneInPlan()
  from duplicated implementations in doctor.ts, mechanical-completion.ts, and
  auto-recovery.ts. All three callers used identical regex patterns.
  mechanical-completion.ts and auto-recovery.ts now import the shared utility.
  (doctor.ts deferred — touched by PR #1349)

- test-utils.ts: Shared cross-platform test utilities for GSD extension tests.
  Provides git() helper (execFileSync, no shell), makeTempRepo() with
  core.autocrlf=false, cleanup(), createFile(), safeReadFile(), and
  writeMilestoneFixture(). 12 test files currently define their own versions
  of these helpers — new tests should import from test-utils.ts instead.

Security audit: No injection vectors (sid/tid are alphanumeric from roadmap
parser), no path traversal, no secrets, no new dependencies.

* fix: port conflict false positive on non-Node projects + paused worktree resume (#1381, #1383)

projects without package.json. macOS AirPlay Receiver listens on port 5000,
causing a spurious warning on non-Node projects.
Fix: Skip port checks entirely when no package.json exists. When using
default ports, filter out 5000 on macOS.

in-memory only. Re-entering /gsd started a fresh bootstrap from the project
root instead of the active worktree.
Fix: pauseAuto() now writes paused-session.json to .gsd/runtime/ with
milestoneId, worktreePath, originalBasePath, and stepMode. startAuto()
checks for this file before bootstrap and restores the paused session
context, including worktree re-entry. stopAuto() cleans up the file.

Fixes #1381, #1383

* fix: catch spawn ENOENT in uncaught exception guard + snapshot session lock path (#1384, #1363)

uncaught exception and crashes auto-mode. The EPIPE guard now also catches
ENOENT from spawn syscalls — logs the error and continues instead of
terminating the process.

the lock path differently via gsdRoot() because basePath could be either the
project root or a worktree path. gsdRoot() produces different results for
each, so the lock was written to one path and validated against another.
Fix: Snapshot the resolved lock path (_snapshotLockPath) at acquisition time
and reuse it for all subsequent lock operations within the session.

Fixes #1384, #1363

* fix: suppress false-positive lock compromise + skip migration with active worktrees (#1362, #1337)

because the event loop stall delays the heartbeat mtime update. The handler
now checks elapsed time since acquisition — if within the 30-minute stale
window, it logs a warning and continues instead of setting _lockCompromised.
Real takeovers (past the stale window) still trigger the compromise flag.

even when .gsd/worktrees/ contained active git worktrees with locked
directory handles. This caused EBUSY errors and destructive data loss.
Migration now checks for active worktree directories and skips entirely
if any are found.

Fixes #1362, #1337
2026-03-19 17:06:01 -06:00
TÂCHES
2ea7abcd0c refine: extensions elegance improvements (#1503)
* refine: R1 delete dead wizard-ui.ts

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

* refine: R2 remove dead BgProcess fields (commandHistory, envKeys)

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

* refine: R3 remove no-op acknowledgeDeliveries

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

* refine: R4 remove unused lineDedup tracking

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

* refine: R5 remove unused ProcessEvent types (output, pattern_match)

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

* refine: S1 replace duplicate formatTokens with shared formatTokenCount

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

* refine: R1 remove re-staged wizard-ui.ts

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

* refine: S2 consolidate maskEditorLine into shared/sanitize

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

* refine: S3 add session cleanup to context7 and google-search

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-19 16:59:52 -06:00
Tom Boucher
8e2827646a fix: check project root .env when secrets gate runs in worktree (#1387) (#1470)
In worktree isolation mode, the secrets gate checked for .env at the
worktree path (process.cwd()), but the user's .env lives at the project
root. Keys that existed in the project root's .env were reported as
missing, causing repeated blocking key collection prompts.

Fix: getManifestStatus() now accepts an optional projectRoot parameter.
When provided (worktree mode), it checks both the worktree .env AND the
project root .env. All callers in auto.ts and auto-start.ts updated to
pass s.originalBasePath.

Fixes #1387
2026-03-19 16:57:59 -06:00
Tom Boucher
bc9cfb1992 fix: realign cwd before dispatch + clean stale merge state on failure (#1389) (#1400)
In worktree isolation, process.cwd() drifts when async_bash or background
jobs change directory, causing commits to land on the wrong branch.
Realign cwd to basePath before every dispatch and hook dispatch.

Also clean stale .git/SQUASH_MSG, MERGE_HEAD, MERGE_MSG after failed
squash-merges to prevent subsequent git operations from seeing phantom
merge state.

Adapted to post-M001 architecture: cwd fix in auto-loop.ts runUnit(),
hook cwd fix in auto.ts dispatchHookUnit(), merge cleanup in
worktree-resolver.ts _mergeWorktreeMode().

Co-authored-by: Lex Christopherson <lex@glittercowboy.com>
2026-03-19 16:55:18 -06:00
HyperDev1
c58bf42333 fix: create milestones/ directory in worktree when missing (#1374)
syncGsdStateToWorktree() assumed the milestones/ directory already
existed in the worktree. On a fresh worktree bootstrap this directory
is absent, causing milestone sync to silently skip all entries and
auto-mode to report "All milestones complete" immediately.

Create the directory before iterating if the main repo has milestones
but the worktree does not.

Co-authored-by: Berat Can <berat@hyperlab.games>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:54:19 -06:00
Tom Boucher
f069790d7d fix: inject network_idle warning into hook prompts (#1345) (#1401)
Post-unit hooks that use browser tools can hang indefinitely when the LLM
calls browser_wait_for with condition 'network_idle' against a dev server
with persistent connections (Vite HMR, WebSocket). The networkidle event
never fires because at least one connection stays open.

Fix: Inject a browser safety instruction into every hook prompt warning
against network_idle and recommending selector_visible, text_visible, or
delay as alternatives.

Fixes #1345
2026-03-19 16:54:14 -06:00
Tom Boucher
b720e7e15c fix: verify symlink after migration + fix test failures (#1377) (#1404)
migrateToExternalState() moved .gsd/ to ~/.gsd/projects/<hash>/ and
created a symlink, but never verified the symlink resolved correctly.
On Windows, junction creation can silently fail or resolve to the wrong
target. If the symlink was broken, the backup (.gsd.migrating) was
deleted anyway, losing all project state.

Changes:
- migrate-external.ts: After creating symlink, verify it resolves to the
  expected path and is readable. If verification fails, restore from backup.
- repo-identity-worktree.test.ts: Canonicalize temp dirs with realpathSync
  to fix macOS /var → /private/var mismatch in path assertions.
- resource-loader.ts: Check for agents/ subdir before using dist/resources
  as source — partial builds (tsc without copy-resources) create an
  incomplete dist/resources that's missing agents/ and skills/.

Fixes #1377
2026-03-19 16:54:11 -06:00
TÂCHES
bdeec039c0 fix: validate CWD instead of project root when running from a GSD worktree (#1317) (#1504)
When the user's home directory is a git repo, resolveProjectRoot() correctly
returns $HOME as the main tree root. assertSafeDirectory() then hard-blocks it
with the home-directory guard added in #1053, even though the session is running
from a valid GSD worktree (e.g. ~/.gsd/worktrees/M001) — not from $HOME itself.

Fix: in projectRoot(), detect when CWD diverges from the resolved root (i.e. we
are inside a git worktree) and validate the CWD instead. The worktree path is
never $HOME, so the guard no longer fires. When not in a worktree cwd === root,
preserving the existing behaviour unchanged.

Adds a regression test: validateDirectory() on a ~/.gsd/worktrees/M001 path
must return { safe: true, severity: "ok" }.

Co-authored-by: Jeremy McSpadden <jeremy@fluxlabs.net>
2026-03-19 16:53:34 -06:00
Derek Pearson
5eed57f876 fix(gsd): detect initialized health widget projects (#1432)
* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* fix(gsd extension): make health widget execution-aware

Lead the health widget with current GSD execution state so it explains what the project is doing before surfacing provider and environment diagnostics. Keep issue, budget, and progress details as secondary context and cover the new output with focused widget tests.

* fix(gsd extension): address review feedback on health widget PR

- Replace em dash with ASCII hyphen in headline for terminal safety
- Reformat catch/finally to standard single-line style
- Replace computeProgressScore() status with direct phase labels so
  the status reflects the actual execution phase, not a global health
  aggregate
- Use lightweight milestone-dir scan instead of full detectProjectState()
  to avoid unnecessary filesystem work on the 60s refresh
- Add cache warm-up comment on updateSliceProgressCache call
- Add safety comment on early void refresh() call
- Update test assertions for new phase labels and ASCII separator
2026-03-19 16:50:13 -06:00
Jeremy McSpadden
96b94065ff fix: smarter .gsd root discovery — git-root anchor + walk-up replaces symlink hack (#1386)
* fix: replace symlink-follow in gsdRoot() with git-root-anchored walk-up discovery

The old implementation blindly assumed .gsd lived at basePath and only
followed symlinks as a migration escape hatch. This caused the health
widget to show "No project loaded" when:
- .gsd was moved to a non-default location
- cwd was a subdirectory of the project root
- the session started inside a worktree path

New probe chain in gsdRoot():
  1. basePath/.gsd         — fast path (common case, zero overhead)
  2. git rev-parse root    — anchors to the repo root regardless of cwd
  3. Walk up from basePath — finds .gsd in an ancestor (bounded by git root)
  4. basePath/.gsd         — creation fallback for init/new projects

Key correctness detail: basePath is normalized via realpathSync before
any comparisons, ensuring the git-root boundary check works on macOS
where /var is a symlink to /private/var. Walk-up only runs when inside
a git repo and only when basePath != gitRoot — preventing escape into
unrelated filesystem directories.

Result is cached per-basePath for the process lifetime. All 52 callers
of gsdRoot() benefit with no call-site changes.

Adds tests/paths.test.ts covering all 6 probe cases.

* fix: correct report() call signature in paths.test.ts — takes no arguments

* fix: normalize git output paths and use realpathSync.native for Windows compatibility

- Use path.normalize() on git rev-parse output to convert forward slashes
  to backslashes on Windows, so the git-root boundary check fires correctly
- Use realpathSync.native() instead of realpathSync() to resolve both
  symlinks (macOS /var→/private/var) and 8.3 short names (Windows RUNNER~1)
- Update test tmp() helper to use realpathSync.native so expected paths
  match the resolved paths returned by probeGsdRoot
2026-03-19 16:50:10 -06:00
HyperDev1
fecf32dc1e fix: correct GSD-WORKFLOW.md fallback path and sync to agentDir (#1375)
The fallback path for GSD-WORKFLOW.md still referenced the legacy .pi
directory (~/.pi/GSD-WORKFLOW.md) instead of the correct .gsd/agent
location. This broke workflow dispatch when GSD_WORKFLOW_PATH env var
was not set.

- Update fallback path from ~/.pi/ to ~/.gsd/agent/ in three call sites
  (dispatchWorkflow, dispatchDoctorHeal, handleTriage)
- Sync GSD-WORKFLOW.md to agentDir during initResources() as a fallback
  for alternative entry points that may not set the env var

Co-authored-by: Berat Can <berat@hyperlab.games>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:50:08 -06:00
TÂCHES
ad01d0ada4 Merge pull request #1365 from jbrahy/fix/openai-reasoning-encrypted-content-always-include
fix: always include reasoning.encrypted_content for OpenAI reasoning models
2026-03-19 16:38:24 -06:00
TÂCHES
d3d682cf00 Merge pull request #1359 from jbrahy/fix/loadfile-eisdir-guard
fix: avoid EISDIR crash in GSD file loader
2026-03-19 16:38:11 -06:00
TÂCHES
0028ceef26 Merge pull request #1357 from jbrahy/fix/inspect-open-existing-db
fix: open existing GSD database on /gsd inspect
2026-03-19 16:30:56 -06:00
github-actions[bot]
290b2b2a25 release: v2.35.0 2026-03-19 22:05:29 +00:00
TÂCHES
efc23a2342 Merge pull request #1498 from gsd-build/fix/lsp-get-server-for-file
fix: restore LSP single-server selector export
2026-03-19 15:53:26 -06:00
TÂCHES
cc17d20820 Merge pull request #1457 from frizynn/refactor/agent-session-model-switching
refactor: consolidate model switching logic in agent-session
2026-03-19 15:52:12 -06:00
TÂCHES
45193d5499 Merge pull request #1458 from frizynn/refactor/resource-loader-generics
refactor: consolidate resource-loader duplicate methods into generics
2026-03-19 15:52:01 -06:00
TÂCHES
b5563e18c6 Merge pull request #1459 from frizynn/refactor/shared-lock-utils
refactor: extract shared file lock utilities
2026-03-19 15:51:47 -06:00