Validates the race routing logic: raceRemoteAndLocal helper exists,
routing checks both hasRemote and ctx.hasUI, remote timeouts are
treated as non-wins, AbortController cancels the loser, and
isRemoteConfigured is exported from manager.ts.
When a remote channel (Discord/Slack/Telegram) is configured, ask_user_questions
now races the local TUI against the remote dispatch. The first response wins and
the loser is cancelled. Previously, remote completely preempted the local TUI,
meaning terminal users never saw the question prompt when remote was configured.
Closes#3801
Helps users understand that 'anthropic-api' makes direct API calls (requires
API key / extra usage) while 'claude-code' routes through the local CLI
(uses subscription).
When ask_user_questions fails, errors, or is cancelled during a
discussion flow, the model is now mechanically blocked from all
non-read-only tool calls until it re-asks and gets a valid response.
Previously, gate enforcement was prompt-only — the model could
rationalize past failed ask_user_questions calls ("auth issue, I'll
continue") and generate an entire plan without any user interaction.
The pending gate mechanism:
- tool_call hook: any ask_user_questions during discussion sets pending
- tool_result hook: valid user response clears pending; failure keeps it
- tool_call hook: blocks write/edit/gsd/mutating-bash while pending
- read-only tools and ask_user_questions itself always allowed
Add 3 new tests covering editor↔selector/input component swaps that
happen during /gsd prefs, /gsd migrate, and /gsd setup:
- editor-to-selector swap: verifies cursor tracking when editor with
CURSOR_MARKER is replaced by a selector without one
- selector-to-editor swap: verifies cursor restores to CURSOR_MARKER
position when editor returns after selector dismissal
- input component swap: verifies typing in prefs wizard text input
produces correct cursor movement without jumps
All tests confirm hardwareCursorRow baseline computes correct movement
deltas for these interactive component transitions.
Two bugs prevented subscription users from routing through Claude Code CLI:
1. Retry handler regex only matched "third-party" errors but actual error is
"You're out of extra usage" — fallback never triggered
2. auto-model-selection actively rerouted bare model IDs back to anthropic
even after startup migration set claude-code as the session provider
Verify claude-code fallback only fires for anthropic provider and
does not reroute non-anthropic providers on similar error text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevent _tryClaudeCodeFallback from firing for non-Anthropic providers
that may produce similar error text, avoiding unintended provider drift.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Anthropic now blocks third-party apps from using Pro/Max subscription
quotas via direct API calls. This change makes the claude-code provider
(which delegates to the local claude CLI binary) the default path for
Anthropic subscription users — TOS-compliant because requests flow
through Anthropic's own infrastructure.
Changes:
- Enhanced readiness check to verify CLI auth status (not just binary)
- Startup migration: auto-switch anthropic → claude-code when CLI ready
- Error recovery: auto-switch on third-party 400 block error
- Onboarding: removed Anthropic from OAuth, added Claude CLI option
- Added claude-code to flat-rate providers (no dynamic routing benefit)
Closes#3772
PR #3744 and #3765 introduced contentCursorRow which diverges from the
actual terminal cursor position after IME repositioning. computeLineDiff
computes ANSI escape movements which are relative to where the cursor
physically is — that must be hardwareCursorRow, not a phantom position.
Remove contentCursorRow entirely and revert computeLineDiff baseline to
hardwareCursorRow. The ghost-line test was asserting wrong movement
direction (UP from phantom position vs DOWN from actual cursor).
Closes#3764
- Added queryKnowledge() for keyword-based KNOWLEDGE.md section filtering
- Added formatRoadmapExcerpt() for slice-scoped roadmap excerpts
- Added inlineKnowledgeScoped() and inlineRoadmapExcerpt() to auto-prompts
- Context reduction: ~65% for knowledge, ~67% for roadmap excerpts
- Also includes deriveSliceScope() fix for unit IDs and process words
Squash merge of milestone/M005
Verify that contentCursorRow is correctly maintained across renders
and that IME repositioning does not cause spurious cursor jumps
during normal typing or content shrinking.
Refs #3764
PR #3744 fixed autocomplete ghost lines by introducing a local
contentCursorRow initialized from this.cursorRow, but this.cursorRow
tracks the content end (last line), not where the cursor actually
ended up after rendering. This caused computeLineDiff to compute
wrong movement deltas, making content clear and jump on every keystroke.
Fix: add an instance field contentCursorRow that stores finalCursorRow
after content rendering but before positionHardwareCursor moves the
cursor for IME. This correctly separates three cursor concepts:
- cursorRow: logical content end (viewport calculation)
- contentCursorRow: post-render cursor position (movement baseline)
- hardwareCursorRow: actual terminal cursor (may differ due to IME)
Closes#3764
The workflow-logger coverage test (#3348) requires all catch blocks in
migrated files to include logging. Add logWarning for the expected
failure case when nativeWorktreeRemove fails on orphaned directories.
Refs #3739
Address adversarial review findings:
1. Timed-out pre/post verification continues running in background and
can mutate s.currentUnit for the wrong unit. Fix: null out
s.currentUnit on timeout so late async completions are harmless
(all side effects in postUnitPreVerification guard on s.currentUnit).
2. Finalize timeouts were treated as successful iterations, resetting
consecutiveErrors and enabling silent infinite churn. Fix: add
consecutiveFinalizeTimeouts counter to LoopState, increment on each
timeout, hard-stop auto-mode after MAX_FINALIZE_TIMEOUTS (3)
consecutive timeouts. Reset to 0 on successful finalize.
Both fixes apply symmetrically to pre and post verification timeouts.
Refs #3757
postUnitPostVerification already has a 60s timeout guard (#2344) but
postUnitPreVerification was called with bare await — if any async
operation inside it never resolves (browser teardown, worktree sync,
safety harness validation), the auto-loop freezes permanently with no
error, notification, or recovery.
Wrap postUnitPreVerification in the same withTimeout() pattern with a
dedicated FINALIZE_PRE_TIMEOUT_MS constant. On timeout, log a warning
and force-continue to the next iteration.
Closes#3757
Keyboard shortcut hints were hardcoded as Ctrl+Alt+X everywhere except
auto-dashboard.ts which had an inline platform check. On macOS these
should render as ⌃⌥X.
- Add formatShortcut() to files.ts — converts Ctrl/Alt/Shift/Cmd
modifiers to macOS symbols (⌃/⌥/⇧/⌘) when process.platform is darwin
- Replace all inline platform checks and hardcoded hints with
formatShortcut() calls
- Use template variables in system.md for shortcut hints
- Update comments in overlay files for consistency
- Add 7 tests covering all modifier conversions and passthrough
Closes#3753