The "Extra usage is required for long context requests" error from
Anthropic is a billing gate, not a transient rate limit. Classify it as
quota_exhausted so the handler enters the fallback path instead of an
infinite backoff loop. When no cross-provider fallback exists, attempt a
[1m] to base model downgrade before stopping cleanly.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Community extensions must be placed in ~/.pi/agent/extensions/, not
~/.gsd/agent/extensions/ which is reserved for bundled extensions synced
from the gsd-pi package. Extensions placed in the wrong path are silently
ignored by the loader.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Slices defined in ROADMAP.md but missing from the SQLite database caused
permanent "No slice eligible — check dependency ordering" blocks. The
dependency resolver only considered DB rows, so disk-only slices were
invisible. This adds a reconciliation step (mirroring the existing
milestone reconciliation) that parses each milestone's ROADMAP.md,
compares against getMilestoneSlices(), and inserts missing slices with
correct status based on SUMMARY file presence.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Move the dedup check from after the Investigation Protocol to before it,
so already-known bugs are caught before spending tokens on deep source
analysis. The DEDUP_PROMPT_SECTION now acts as a pre-investigation gate
with a decision to skip full investigation when a match is found.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When gsd is spawned as an RPC bridge child process, stdout is a pipe
(process.stdout.isTTY === undefined). The TUI render loop would run at
~4,600 renders/sec writing ANSI escape codes to the pipe, consuming
500%+ CPU per process while idle.
Add isTTY guard to Terminal interface, ProcessTerminal.start(), TUI.start(),
and requestRender() so the entire render pipeline is skipped on non-TTY stdout.
RemoteTerminal (browser-backed) correctly reports isTTY=true.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The forensics prompt was sent as a one-shot message via sendMessage()
with triggerTurn: true, causing context loss on follow-up turns. Now
writes an active-forensics.json marker to .gsd/runtime/ so that
buildBeforeAgentStartResult() can re-inject the forensics prompt on
subsequent turns, mirroring how guided task execution context works.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The milestones list only refreshed on agent_end events, causing stale
milestone state during multi-turn agent execution. Add turn_end as a
workspace cache invalidation trigger so the UI reflects milestone
changes after each turn boundary.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Bug 1: orphaned worktree check now skips directories that only contain
doctor artifacts (.gsd/doctor-history.jsonl), preventing the circular
false positive where appendDoctorHistory recreates the dir it reports.
Bug 2: blocker_discovered_no_replan check now skips when all tasks are
done, treating the blocker as implicitly resolved and breaking the
deadlock with stale_replan_file.
Bug 3: parsePlan now scans the full body for task checkboxes after the
Tasks section, finding T02+ entries that appear after interleaved
detail headings (## Steps, ## Must-Haves).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The subprocess spawned by collectAuthoritativeAutoDashboardData always
starts with fresh module state (s.active === false), so the web UI
always showed "Start auto" even while auto mode was running. After
obtaining the subprocess result, reconcile active/paused state with
the on-disk session lock (.gsd/auto.lock) and paused-session metadata
(.gsd/runtime/paused-session.json).
Closes#2705
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Milestones with no registry entry (ghost directories with no planning
files) were falling through to eligible status due to the fallback
`entry?.status ?? "pending"` combined with empty deps. Now explicitly
classified as ineligible with "no planning data" reason before any
status/dep checks run.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When `gsd auto` is run with piped stdout (e.g. `gsd auto | cat` or
`gsd auto > file`), the TUI cannot render on a non-terminal output
stream, causing the process to hang indefinitely.
This fix:
- Detects piped stdout before entering interactive mode and redirects
`gsd auto` to headless mode automatically
- Extends the interactive mode TTY gate to also check process.stdout.isTTY
(previously only checked stdin), with a descriptive error message
- Adds `gsd headless` to the non-interactive alternatives hint
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When a file-backed database has a corrupted freelist, DDL operations
fail with "database disk image is malformed" even though integrity_check
passes. This adds VACUUM recovery to openDatabase() before re-throwing,
matching SQLite's documented recovery strategy for freelist corruption.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Three fixes for the auto-mode regression where db_unavailable causes
infinite artifact-retry re-dispatch loops:
1. resolveProjectRootDbPath now handles /.gsd/projects/<hash>/worktrees/
paths (symlink-resolved layout) in addition to /.gsd/worktrees/
2. ensureDbOpen emits structured diagnostics (resolvedPath, cwd, error)
instead of silently returning false
3. Post-unit artifact retry skips when isDbAvailable() is false, treating
DB infra failure as fatal instead of entering a retry loop
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The searchWithOAuth() function sent a request body that the Cloud Code
Assist API rejected with 400 INVALID_ARGUMENT. Two issues:
1. URL was missing ?alt=sse query parameter (endpoint returns SSE format)
2. Request body was missing the required userAgent field
Also adds regression tests that capture the fetch call and assert the
request URL and body match the Cloud Code Assist wire contract.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Bug 1 -- UAT stuck-loop: syncProjectRootToWorktree used force:false for
all milestone files, which preserved stale ASSESSMENT files in the
worktree. When the project root had a passing verdict but the worktree
retained a FAIL copy (or lost it during DB rebuild), checkNeedsRunUat
found no passing verdict and re-dispatched run-uat indefinitely (x9).
Fix: after the additive-only safeCopyRecursive, walk ASSESSMENT files in
the project root and force-overwrite the worktree copy when the source
contains a verdict field. This is safe because ASSESSMENT verdicts are
only ever overwritten in a forward direction (FAIL -> PASS on retry).
Bug 2 -- Orphaned worktree: removeWorktree silently swallowed failures
from git worktree remove when untracked files (UAT-RESULT, ASSESSMENT)
blocked removal. The .git/worktrees/<name> internal directory held a
lock that also prevented the rmSync fallback from working.
Fix: after both native removal attempts fail, explicitly remove the git
internal .git/worktrees/<name> directory first, then retry rmSync on
the worktree filesystem directory. Log a warning with manual cleanup
instructions if the final attempt also fails.
Closes#2821
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
getServerConfig now trims whitespace and performs case-insensitive
matching so that names like "langgraph Code" resolve correctly.
getOrConnect uses config.name as the canonical cache key to prevent
duplicate connections from variant casing.
Closes#3029
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes for the state corruption chain reported in #2960:
1. extractVerdict() now detects verdicts in markdown body patterns
(e.g., **Verdict:** PASS) when YAML frontmatter is absent, preventing
the state machine from looping on validating-milestone when LLMs write
VALIDATION.md manually.
2. handlePlanMilestone() now refuses to re-plan a milestone that has
completed slices, preventing INSERT OR IGNORE from shadowing completed
work after worktree recreation or DB resync.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Previously, headless --verbose mode accumulated text_delta events into a
buffer and displayed a single truncated 120-char [thinking] line before
tool calls. The model's actual text responses between tool calls were
effectively invisible.
Changes:
- Stream text_delta and thinking_delta events directly to stderr in
verbose mode with [text] and [thinking] block markers
- No truncation — full model output is visible
- Fix non-verbose fallback: read from ame.delta (correct field) instead
of ame.text (always undefined for text_delta events)
- Track inTextBlock/inThinkingBlock state to properly close streaming
blocks before tool calls
- Expand summarizeToolArgs with support for async_bash, await_job,
cancel_job, find, ls, lsp, hashline_edit, subagent, browser_navigate,
and gsd_* tools
- Add streaming formatter functions: formatTextStart, formatTextEnd,
formatThinkingStart, formatThinkingEnd
- Update tests for new tool arg summarization and path field handling
Saves in-progress daemon work from M005-m138xe that was sitting uncommitted.
Includes orchestrator expansion, event bridge/formatter enhancements,
message batcher tweaks, and discord bot additions.
checkAutoStartAfterDiscuss() fire-and-forgets startAuto() when a
milestone is ready. The headless runner then chains `/gsd auto`,
calling startAuto() a second time. Two concurrent auto-loops on the
same AutoSession singleton corrupt shared state (counters, dispatch
maps), causing planning/execution to never run after research.
Add an early `s.active` check at the top of startAuto() so the second
call no-ops. Add source-scanning test to enforce the guard exists.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three defects in the completing-milestone dispatch guard caused false
positive blocks on valid validation output:
1. Single-line constraint: [^\n]* stopped at newlines, missing verdicts
on subsequent lines. Fixed with [\s\S]{0,500}? (bounded lazy match).
2. Missing keywords: 'satisfied' and 'partially' were absent from the
alternation. LLMs commonly write 'PARTIALLY SATISFIED' or 'FULLY
SATISFIED'. Added both.
3. Markdown bold delimiters: **Operational** blocked [\s:] after the
word. The new [\s\S] class handles any character including *.
Also adds SATISFIED to the structuredMatch includes check, and ✅ to
the prose regex (overlaps with #2862).
Includes 8 regression test cases covering multi-line formats, satisfied
keyword variants, markdown bold tables, and checkmark emoji.
Bug 1 — Workers exit immediately (#2792):
spawnWorker() used `--print "/gsd auto"` which calls session.prompt()
that returns immediately when ctx.newSession() resets the session inside
the auto-loop. Changed to `headless --json auto` which uses an RPC
client that keeps the process alive until auto-mode completes.
Bug 2 — Dispatch guard blocks parallel workers (#2797):
getPriorSliceCompletionBlocker() checked ALL milestones in queue order,
blocking M012 when M011 had incomplete slices. When GSD_MILESTONE_LOCK
is set, the guard now only checks intra-milestone slice dependencies.
Added test covering cross-milestone bypass + intra-milestone preservation.
Bug 3 — Orphaned RPC children on stop (#2798):
stopParallel() gave only 750ms for SIGTERM before SIGKILL. The headless
parent needs ~1500ms to cascade shutdown to its RPC child via
client.stop(). Increased to 3000ms to prevent orphaned processes holding
auto.lock.
Updated tests:
- dispatch-guard.test.ts: new test for GSD_MILESTONE_LOCK bypass
- parallel-worker-monitoring.test.ts: updated spawn args assertion
The dashboard reads elapsed time, total cost, and tokens used
exclusively from AutoDashboardData. When auto-mode is not active
(e.g. manual /gsd next), auto is null and all three metrics show 0
— even though the status bar displays real values via /api/visualizer.
Add the same projectTotals polling pattern (30s interval via
/api/visualizer) that status-bar.tsx already uses, and wire it into
the fallback chain: projectTotals ?? auto ?? 0.
Closes#2709
When worktrees use shared-WAL mode (R012), the worktree DB path resolves
to the same physical file as the project root DB via symlink. Calling
reconcileWorktreeDb() ATTACHes this WAL-mode file to itself, corrupting
the database with 'database disk image is malformed'.
Fix 1 — auto-worktree.ts mergeMilestoneToMain(): skip reconciliation
when isSamePath() confirms both DB paths resolve to the same file.
Fix 2 — gsd-db.ts reconcileWorktreeDb(): defence-in-depth realpathSync
guard inside the function itself, before the ATTACH statement.
Fix 3 — auto/infra-errors.ts: classify 'database disk image is
malformed' as SQLITE_CORRUPT infrastructure error so the auto-loop
stops immediately instead of burning 3 retries on a guaranteed failure.
Regression tests verify:
1. Same-file via symlink returns zero (no ATTACH)
2. Identical string paths return zero
3. Genuinely different DBs still reconcile normally
4. Malformed DB message classified as infra error
5. Transient SQLITE_BUSY is not falsely classified
Closes#2823
When GSD_WEB_DAEMON_MODE=1 is set, scheduleShutdown() becomes a no-op.
The /api/shutdown endpoint still returns { ok: true } so the client
beacon fires without a network error, but process.exit() is never
called. This allows gsd --web to run as a persistent daemon behind a
reverse proxy without exiting on every browser tab close or refresh.
Closes#2835
Multi-turn commands (auto, next) have their own completion signals via
isTerminalNotification ("Auto-mode stopped..."/"Step-mode stopped...").
The execution_complete event fires after command setup before any real
work begins, causing these commands to exit immediately with zero work done.
Closes#2917
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mapStatusToExitCode only handled "complete" but RPC v2 emits "completed",
causing all headless sessions to falsely timeout and restart.
Also emits milestone-ready notification in checkAutoStartAfterDiscuss so
headless parent can detect and chain into auto-mode.
Closes#2914
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests cover: provider registration, base URL + API type, reasoning +
context window specs, and non-collision with generated zai models.
Required by CI lint gate (require-tests.sh).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mount point detection for /media, /mnt, /run/media
- Display mount points as quick-access entries when browsing home dir
- Allow navigation to mount points while maintaining security scope
Fixes#2908
Open the project database before the first auto bootstrap derive so cold-start resume uses DB-backed slice state instead of stale markdown fallback state.
Also recognize glyph completion markers in roadmap tables and lock the new bootstrap ordering with regression coverage.
Closes#2841
Auto-mode selected the correct unit model in runUnitPhase, but a fresh session could drop that selection before the first prompt was sent.
Persist the applied unit model on AutoSession, restore it immediately after newSession(), and cover the seam with a regression test that proves the model is re-applied before dispatch.
Closes#2853