Commit graph

2007 commits

Author SHA1 Message Date
TÂCHES
874df9bc43 Merge pull request #2566 from jeremymcs/fix/hydrate-remote-tokens-esm
fix(remote-questions): use static ESM import for AuthStorage hydration
2026-03-25 22:14:56 -06:00
TÂCHES
5f8bbbc6e1 fix(auto): align UAT artifact suffix with gsd_slice_complete output (#2592)
* fix(auto): align UAT artifact suffix with gsd_slice_complete output

The auto-mode files referenced UAT-RESULT as the artifact suffix,
but gsd_slice_complete writes files as S##-UAT.md. This mismatch
caused ENOENT errors during validate-milestone dispatch.

Fixes #2564

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

* fix(auto): update test and doc references from UAT-RESULT to UAT

Aligns test assertions and ADR documentation with the corrected
artifact suffix.

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

* fix(auto): replace separate UAT-RESULT file check with in-file verdict check

The original two-file model (UAT spec + UAT-RESULT verdict) never
worked because gsd_slice_complete only writes S##-UAT.md. The blind
string replacement made checkNeedsRunUat always return null by
resolving the same file twice. Now checks for a verdict: line inside
the UAT file content to determine if UAT has been completed.

Also deduplicates a redundant resolveSliceFile call in the verdict
gate and updates tests to verify the single-file verdict model.

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-25 22:12:08 -06:00
TÂCHES
891cde201c Merge pull request #2593 from gsd-build/fix/server-error-credential-backoff-2588
fix(retry-handler): stop treating 5xx as credential-level errors
2026-03-25 22:10:33 -06:00
Lex Christopherson
751288675f fix(retry-handler): stop treating 5xx server errors as credential-level failures
Server errors (500/502/503/504) are server-side failures — rotating
credentials doesn't help. Only rate_limit and quota_exhausted are
meaningfully credential-scoped. This prevents the cascading backoff
where a single 500 backs off the sole API key for 20s, causing all
subsequent retries to fail with "All credentials temporarily backed off".

Closes #2588

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:37 -06:00
TÂCHES
2a39adf5b4 Merge pull request #2591 from gsd-build/fix/lock-heartbeat-retry-v2
fix(session-lock): retry lock file reads before declaring compromise
2026-03-25 22:01:55 -06:00
TÂCHES
0705d65ed5 Merge pull request #2590 from gsd-build/fix/subdir-symlink-2380-v2
fix(gsd): prevent subdirectory .gsd symlink when git-root .gsd exists
2026-03-25 21:56:25 -06:00
Lex Christopherson
b4405cbb35 fix(test): replace stale completedUnits with sessionFile in session-lock test
SessionLockData no longer has a completedUnits field. Use sessionFile
(an actual optional field) for the same assertion coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:56:08 -06:00
TÂCHES
265c2d8ad6 Merge pull request #2589 from gsd-build/fix/eagain-infra-error-code-v2
fix(auto): add EAGAIN to INFRA_ERROR_CODES
2026-03-25 21:54:17 -06:00
Tom Boucher
c09c256f28 fix(session-lock): retry lock file reads before declaring compromise
onCompromised was declaring lock lost when the lock file was temporarily
unreadable (NFS/CIFS latency, macOS APFS snapshot, or concurrent process
briefly holding the file). Add readExistingLockDataWithRetry (3 attempts,
200ms delay) so transient filesystem hiccups do not trigger false-positive
compromise events.

Fixes #2324

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:50:52 -06:00
Tom Boucher
a3250c4103 fix(gsd): prevent ensureGsdSymlink from creating subdirectory .gsd when git-root .gsd exists
When running GSD from a subdirectory (e.g. `cd src/ && gsd`),
ensureGsdSymlink would create a new `.gsd` symlink in the subdirectory
even though a valid `.gsd` already exists at the git root. On macOS
APFS this triggers the `.gsd 2` collision variant problem from #2205.

Add an early guard that detects when projectPath is a plain subdirectory
(not a worktree) of a git repo that already has `.gsd` at its root, and
returns the existing root .gsd target instead of creating a duplicate.

Fixes #2380

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:50:23 -06:00
Tom Boucher
47405dfda7 fix(auto): add EAGAIN to INFRA_ERROR_CODES to stop budget-burning retries
EAGAIN (resource temporarily unavailable) is a resource exhaustion error
that cannot be recovered by retrying, yet it was missing from the infra
error set. This caused auto-mode to keep retrying on EAGAIN failures,
burning LLM budget on guaranteed failures.

Fixes #2359

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:48:32 -06:00
TÂCHES
a53d021864 Merge pull request #2487 from jeremymcs/fix/isolation-mode-downgrade
fix(gsd): downgrade isolation mode when worktree creation fails
2026-03-25 21:46:38 -06:00
TÂCHES
8a533f2521 Merge pull request #2385 from trek-e/fix/queue-429-completed-milestones
fix(gsd): skip file loading for completed milestones in /gsd queue
2026-03-25 21:46:09 -06:00
Jeremy McSpadden
c06e42eec4 fix(remote-questions): use static ESM import for AuthStorage hydration
The hydrateRemoteTokensFromAuth() function used require() to load
AuthStorage from @gsd/pi-coding-agent, but the package is ESM-only
("type": "module" with only an "import" export condition). Node's
require() always throws for ESM packages, and the outer try/catch
silently swallowed the error — making hydration a no-op.

Replace require() with a static ESM import (consistent with every
other extension) and use AuthStorage.create() which resolves the
auth.json path internally via getAgentDir().

Closes #2565
2026-03-25 19:39:09 -05:00
github-actions[bot]
419a74672e release: v2.49.0 2026-03-25 23:24:25 +00:00
TÂCHES
1436d8ed4a Merge pull request #2554 from gsd-build/copilot/clean-up-auto-commit-messages
refactor: move GSD metadata from commit subject scopes to git trailers, remove lifecycle noise
2026-03-25 17:14:49 -06:00
TÂCHES
2a1363b69f Merge pull request #2557 from gsd-build/feat/yolo-auto-mode
feat: add --yolo flag for non-interactive project init
2026-03-25 17:12:49 -06:00
Lex Christopherson
72d737ac8f fix: use full git log in merge tests to match trailer-based milestone IDs
Tests were checking `git log --oneline` for M001, but the refactor moved
milestone IDs from commit subject scopes to git trailers in the body.
Switch to `git log` (full format) so the trailer content is visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:10:10 -06:00
Lex Christopherson
492c339bc2 feat: add --yolo flag to /gsd auto for non-interactive project init
Adds `/gsd auto --yolo <spec-file>` (or `-y`) which reads a spec/PRD/ADR
and creates all milestone artifacts without interactive Q&A gates. Uses
the existing showHeadlessMilestoneCreation path — no changes to
startAuto or bootstrapAutoSession internals.

Rewrites discuss-headless.md to match the full rigor of the interactive
discuss.md prompt: mandatory codebase investigation, focused research
(table stakes, domain standards, omissions), capability contract with
R### traceability, gsd_plan_milestone tool usage, roadmap preview in
chat, multi-milestone manifest tracking, and depth verification audit
trail. The only difference from interactive mode is that all decisions
are made autonomously with assumptions documented.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:08:23 -06:00
copilot-swe-agent[bot]
423eb2fda1 fix: update parallel-merge test assertion for new trailer format
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/250b4775-2d82-4329-9ccc-504b857428da
2026-03-25 22:59:49 +00:00
copilot-swe-agent[bot]
2c82923ca9 refactor: move GSD metadata from commit subject scopes to git trailers
Remove GSD planning IDs (milestone/slice/task) from conventional commit
subject lines and place them in machine-parseable git trailers instead.
Skip auto-commits for lifecycle-only unit types that only touch .gsd/ files.

Resolves gsd-build/gsd-2#2553

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/250b4775-2d82-4329-9ccc-504b857428da
2026-03-25 22:56:48 +00:00
TÂCHES
8f3c716e30 Merge pull request #2551 from gsd-build/copilot/fix-mixed-mode-uat-partial-verdict
fix: verdict gate accepts PARTIAL for mixed/human-experience/live-runtime UATs
2026-03-25 16:54:20 -06:00
copilot-swe-agent[bot]
a909b009fa Initial plan 2026-03-25 22:50:20 +00:00
copilot-swe-agent[bot]
a36e6abaa8 fix: clarify regex alternation in test assertion
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/5a619137-0710-4934-949f-bae63945bf70
2026-03-25 22:35:37 +00:00
copilot-swe-agent[bot]
f2283c9a30 fix: verdict gate accepts PARTIAL for mixed/human-experience/live-runtime UATs
The verdict gate in auto-dispatch.ts now reads the UAT file to determine
the UAT type. For mixed, human-experience, and live-runtime modes,
PARTIAL is accepted as a valid verdict (all automatable checks passed,
human-only checks documented as NEEDS-HUMAN).

The run-uat prompt is updated so that PASS is the correct verdict when
all automatable checks succeed, even if human-only checks remain. PARTIAL
is reserved for when automatable checks themselves are inconclusive.

Fixes gsd-build/gsd-2#1400

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/5a619137-0710-4934-949f-bae63945bf70
2026-03-25 22:34:30 +00:00
copilot-swe-agent[bot]
abb8fe69dc Initial plan 2026-03-25 22:30:17 +00:00
github-actions[bot]
34ce83889d release: v2.48.0 2026-03-25 22:25:06 +00:00
TÂCHES
b44da0b0d6 Merge pull request #2537 from mastertyko/fix/clear-stale-milestone-id-reservations
fix(gsd): clear stale milestone ID reservations at session start
2026-03-25 16:07:06 -06:00
TÂCHES
9cc993f21c Merge pull request #2547 from gsd-build/copilot/update-gsd-forensics-logs-and-journal
Enhance /gsd forensics with journal and activity log awareness
2026-03-25 16:05:01 -06:00
copilot-swe-agent[bot]
aee8973d81 fix: make journal scanning intelligent — limit parsed files, line-count older ones
scanJournalForForensics() previously called queryJournal() which loaded
ALL journal entries from ALL daily files into memory. For long-running
projects this could be thousands of entries and megabytes of data.

Now:
- Only the last 3 daily files are fully JSON-parsed (event counts, flows)
- Older files are line-counted only (no JSON parsing) for totals
- Recent events use a rolling window of 20 (shift, not accumulate)
- Constants MAX_JOURNAL_RECENT_FILES and MAX_JOURNAL_RECENT_EVENTS
  make limits explicit and tunable

Activity log scanning was already intelligent:
- nativeParseJsonlTail with 10MB byte cap
- Only last 5 files scanned
- extractTrace() distills raw JSONL into compact ExecutionTrace structs
- formatReportForPrompt has 30KB hard cap on total output

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/7e7f71ec-0d56-409b-930e-5dff1305ff2a
2026-03-25 21:53:37 +00:00
TÂCHES
9a16119235 Merge pull request #2535 from mastertyko/fix/preflight-context-draft-completed-milestones
fix(auto): skip CONTEXT-DRAFT warning for completed/parked milestones
2026-03-25 15:47:25 -06:00
TÂCHES
bdbad70625 Merge pull request #2538 from jeremymcs/feat/discuss-queued-milestones
feat(discuss): allow /gsd discuss to target queued milestones
2026-03-25 15:47:01 -06:00
TÂCHES
bcca77781b Merge pull request #2540 from mastertyko/fix/forensics-false-positive-error-traces
fix(forensics): filter benign bash exit-code-1 and user skips from error traces
2026-03-25 15:46:24 -06:00
TÂCHES
9a32ea9c17 Merge pull request #2543 from splichy/fix/provider-scoped-stream-routing
fix(model-registry): scope custom provider stream handlers to prevent clobbering built-ins
2026-03-25 15:44:55 -06:00
TÂCHES
0a789396b2 Merge pull request #2544 from gsd-build/feat/external-tool-execution
fix: revert insertChildBefore and clean up external tool rendering
2026-03-25 15:42:49 -06:00
Vojtěch Šplíchal
d56842ab7a fix(model-registry): scope custom provider stream handlers to prevent clobbering built-in API handlers
When a custom provider (e.g. claude-code-cli) registers a streamSimple
handler with the same api type as a built-in (e.g. 'anthropic-messages'),
the global API provider registry was overwritten, routing ALL models of
that api type through the custom handler.

This caused anthropic/claude-opus-4-6 requests to be dispatched through
the Claude Code SDK subprocess instead of the Anthropic API, resulting
in 'Tool not found' errors for Glob, Read, Edit, Bash (SDK tool names
not present in pi's tool registry).

Fix: wrap the registered handler with a model.provider guard so it only
fires for models from the registering provider, delegating to the
previous handler for all other providers.

Closes #2536
2026-03-25 22:33:48 +01:00
Lex Christopherson
b8b92b8481 revert: remove insertChildBefore usage in chat-controller
The insertChildBefore approach doesn't fix tool ordering because the
message component is already live-streaming text when tool_execution
events arrive. Proper fix requires T3 Code-style session-lifetime
architecture. Revert to simple addChild for now.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:30:49 -06:00
mastertyko
c64d3ba65d fix(forensics): filter benign bash exit-code-1 and user skips from error traces
extractTrace() indiscriminately counts all isError tool results as
errors, including grep/rg/find returning exit code 1 (no matches)
and user-interrupt skips. This produces false-positive error-trace
anomalies in forensics reports — in a healthy 10-unit run, 3 units
were flagged with 8 spurious 'errors'.

Add two filters before pushing to the errors array:
- Bash commands with '(no output)' + exit code 1 (normal POSIX grep)
- 'Skipped due to queued user message' (intentional user interrupt)

Real errors (non-zero exit with actual error output, non-bash tool
failures) are still counted as before.

Closes #2539
2026-03-25 22:13:25 +01:00
Jeremy McSpadden
f21537d725 feat(discuss): allow /gsd discuss to target queued milestones
Closes #2307

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 16:05:06 -05:00
mastertyko
aee09a53ec fix(gsd): clear stale milestone ID reservations at session start
The module-level reservedMilestoneIds Set persists across /gsd
invocations within the same Node process. Each cancelled session
reserves an ID that is never claimed, permanently inflating the
next milestone number. Starting /gsd 3 times without completing
produces M011 instead of M009.

Call clearReservedMilestoneIds() at the top of showSmartEntry()
and showHeadlessMilestoneCreation() so stale reservations from
previous cancelled sessions are discarded before generating new IDs.
The function already existed but was never called outside tests.

Closes #2488
2026-03-25 21:47:18 +01:00
Lex Christopherson
263d725ecd fix: render tool calls above text response for external providers
- Add insertChildBefore() to Box component for positional insertion
- In chat controller, insert tool_execution components before the last
  assistant message component (instead of appending after) when tools
  were executed externally
- Simplify agent-loop externalToolExecution path back to basic
  tool_execution_start/end emission
- Toolcall streaming events are filtered in the Claude Code adapter
  to prevent duplicate rendering via message_update

Result: externally-executed tool calls render above the text response,
matching the expected visual flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:38:39 -06:00
mastertyko
e5330ee082 fix(auto): skip CONTEXT-DRAFT warning for completed/parked milestones
The pre-flight milestone queue check in auto-start warns about every
CONTEXT-DRAFT.md it finds, regardless of milestone status. A completed
milestone with a leftover CONTEXT-DRAFT.md triggers a spurious warning
on every session start — noise with no actionable meaning.

Add a status guard that skips completed and parked milestones before
checking for CONTEXT-DRAFT files. When the DB is unavailable, fall back
to the existing warn-on-all behavior (safe default).

Closes #2473
2026-03-25 21:24:44 +01:00
github-actions[bot]
55c8988900 release: v2.47.0 2026-03-25 19:53:13 +00:00
TÂCHES
91c1547856 Merge pull request #2532 from gsd-build/feat/external-tool-execution
feat(agent-core): external tool execution mode for Claude Code CLI
2026-03-25 13:09:21 -06:00
Lex Christopherson
bbea8460b5 fix(claude-code-cli): render tool calls above text response
- Filter toolcall_start/delta/end events from streaming to prevent
  out-of-order rendering in the TUI's accumulated message content
- Collect tool calls from intermediate SDK turns and include them
  BEFORE text content in the final AssistantMessage
- The agent loop's externalToolExecution path emits proper
  tool_execution_start/end events for each intermediate tool call
- Result: tool activity renders above the text response, not below

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:57:47 -06:00
Lex Christopherson
a0ee03d331 feat(agent-core): add externalToolExecution mode for external providers
Adds `externalToolExecution` flag to AgentLoopConfig. When true, the
agent loop emits tool_execution_start/end events for TUI rendering but
skips local tool dispatch. Used by providers that handle tool execution
internally (e.g., Claude Code CLI via Agent SDK).

The flag is dynamically evaluated per-loop via a callback on
AgentOptions, so model switches mid-session are handled correctly.
Providers with authMode "externalCli" automatically use this mode.

Also updates the Claude Code CLI stream adapter to preserve tool call
blocks in the final message instead of stripping them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:57:47 -06:00
TÂCHES
d524454059 Merge pull request #2530 from gsd-build/fix/pr-risk-map-path
fix(ci): update FILE-SYSTEM-MAP.md path in pr-risk-check
2026-03-25 12:49:08 -06:00
TÂCHES
0ded615826 Merge pull request #2528 from gsd-build/copilot/fix-inherited-repo-check
fix: isInheritedRepo() false negative when parent dir has stale .gsd
2026-03-25 12:48:57 -06:00
Lex Christopherson
15d8974611 fix(ci): update FILE-SYSTEM-MAP.md path after docs→docs-internal move
The Mintlify docs migration renamed docs/ to docs-internal/ but
pr-risk-check.mjs still referenced the old path, causing every
PR Risk Report workflow to fail with an empty body.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:44:43 -06:00
copilot-swe-agent[bot]
cc7a0cd7c4 fix: isInheritedRepo false negative when parent has stale .gsd; defense-in-depth local .git check in bootstrap
Fix 1 (auto-start.ts): Replace nativeIsRepo(base) with existsSync(join(base, ".git"))
so bootstrap always creates .git locally even when parent repo makes git rev-parse succeed.

Fix 2 (repo-identity.ts): Start walk-up loop at dirname(normalizedBase) instead of
normalizedBase — finding .gsd at basePath itself is irrelevant to inheritance detection.

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/99fdcddc-7e44-4a64-a1ec-a536806216f6
2026-03-25 18:42:27 +00:00