When gsd.db is truncated to 0 bytes after a crash, getMilestoneSlices()
returns [] even though isDbAvailable() is true. This caused showDiscuss()
to falsely report "All slices are complete" despite incomplete slices
existing in the ROADMAP file. Add a cross-check: if the DB returns zero
slices but a roadmap exists, fall back to parseRoadmapSlices() to derive
slice state from the roadmap (the ground truth).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Extend PROVIDER_ROUTES so doctor/routing recognizes google-gemini-cli
as an alternative for google and openai-codex as an alternative for
openai. Cap rate-limit backoff at 30s for CLI-style providers to avoid
leaving users stuck in long backoff windows.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Stream-truncation JSON parse errors like "Expected ',' or '}' after
property value in JSON" were falling through to kind: "unknown", causing
permanent auto-mode pause instead of transient 15s backoff.
- Broaden STREAM_RE: replace narrow "Expected double-quoted property name"
with "Expected.*in JSON" and add "Unterminated.*in JSON" to catch all 7
V8 JSON parse error message variants
- Move stream check before server/connection checks to prevent false
matches (e.g. "position 500" matching SERVER_RE, "Unterminated" matching
CONNECTION_RE's "terminated" pattern)
- Add 4 test cases for the previously uncovered V8 error variants
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The pre-merge stash in mergeMilestoneToMain used --include-untracked
which swept ALL untracked files into the stash, including queued
milestone CONTEXT files under .gsd/milestones/. If stash pop failed,
these files were permanently trapped in the stash entry.
Two-part fix:
1. Add pathspec exclusion `:(exclude).gsd/milestones` to stash push
so queued milestone dirs are never swept into the stash
2. Shelter queued milestone dirs before squash merge to prevent
conflicts with copies in the milestone branch (via copyPlanningArtifacts),
then restore them on both success and error paths
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The ensure-workspace-builds.cjs postinstall script falsely detected
workspace packages as stale in npm tarball installs. npm sets all
tarball entries to a canonical timestamp (Oct 26 1985), but extraction
ordering causes src/ files to appear 1-2 seconds newer than dist/
files. This triggered a rebuild attempt that either failed silently
(no tsc available) or — when tsc was globally installed — could
produce broken dist/ output, corrupting the known-good pre-built
files and causing the DefaultResourceLoader export error on startup.
The fix gates the src-vs-dist staleness check behind a .git directory
check: only development clones (with .git/) perform the timestamp
comparison. npm tarball installs (no .git/) only check for missing
dist/index.js, which is the safe and correct behavior.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: TÂCHES <afromanguy@me.com>
determineMergeOrder relied solely on orchestrator WorkerInfo.state
being "stopped" to find mergeable milestones. When the orchestrator
state drifts (worker respawned, status.json deleted, etc.), completed
milestones become invisible to the merge command.
Now scans .gsd/worktrees/<MID>/.gsd/gsd.db for milestones with
status='complete', using the same subprocess-sqlite3 pattern as the
parallel-monitor-overlay. The worktree DB is the ground truth.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The claude-code provider in gsd-pi was effectively stateless: it sent
only the last user message, disabled session persistence, and filtered
out all sidechain/subagent events. This made multi-turn conversations
feel isolated and caused incomplete responses.
- Replace extractLastUserPrompt with buildPromptFromContext that
serialises the full conversation history (system prompt + all turns)
- Change persistSession from false to true for session continuity
- Remove parent_tool_use_id filtering so delegated/sidechain outputs
are included in the final response
- Extract buildSdkOptions for testability
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
syncProjectRootToWorktree unconditionally deleted the worktree's gsd.db
to force a rebuild from synced artifacts (#853). On respawned workers,
gsd-migrate had already populated the DB (~1.7MB), so the deletion
caused openDatabase to create a new empty file, leading to "no such
table: slices" failures and a respawn loop.
Now only deletes 0-byte (empty/corrupt) DB files, preserving freshly
migrated databases.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: align @gsd/native module type with compiled output (#2861)
The package declared "type": "module" and used "import"-only export
conditions, but the addon loader used import.meta.url which is
incompatible when the parent package enforces ESM resolution on
Node.js v24. Switch to "type": "commonjs" with "default" export
conditions and remove the import.meta.url/__dirname shim (CJS
provides both natively).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore dual CJS/ESM compat for native addon loader
The ESM-to-CJS conversion removed import.meta.url polyfills, but the CI
test loader (dist-redirect.mjs) transpiles this file to ESM via
ts.transpileModule — making __dirname and require unavailable at test time.
Add runtime typeof guards that use the CJS globals when available (compiled
output) and fall back to import.meta.url in ESM (test runner). Use
@ts-expect-error to suppress TS1470 for the import.meta branches that are
unreachable in the compiled CJS output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use indirect eval for import.meta.url to avoid CJS parse-time error
import.meta is a parse-time syntax error in CJS — typeof guards don't
help because Node.js rejects the syntax before executing any code.
Wrapping in new Function("return import.meta.url") hides the syntax
from the CJS parser while still working when executed as ESM (test runner).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace new Function(import.meta.url) with loader-injected CJS globals
import.meta is static syntax unavailable in new Function() and eval()
scopes, causing rtk-portability CI failures across all platforms.
Instead of trying to access import.meta.url indirectly, the test loader
(dist-redirect.mjs) now injects __dirname, __filename, and require as a
preamble when transpiling workspace packages to ESM. This lets native.ts
use __dirname/require directly in both CJS (production) and ESM (CI test)
contexts without any import.meta.url fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The `key.indexOf("/")` split broke compound hook types like
"hook/telegram-progress/M007/S01", yielding unitType="hook" instead of
"hook/telegram-progress". This bypassed the `startsWith("hook/")` guard
in verifyExpectedArtifact, producing false-positive missing-artifact
errors for every hook unit.
Extract a shared `splitCompletedKey()` helper that handles the two-segment
hook prefix and use it in both `detectMissingArtifacts` (forensics.ts) and
the orphaned-key check (doctor-runtime-checks.ts).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add mcp.json to ROOT_STATE_FILES and copyPlanningArtifacts so MCP
server configurations are available inside worktrees.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add gsd_requirement_save tool and upsert path for gsd_requirement_update (#2919)
gsd_requirement_update returned not_found for all requirements because
requirements written to REQUIREMENTS.md were never inserted into the DB,
and no create path existed. This adds:
- saveRequirementToDb() + nextRequirementId() in db-writer.ts (symmetric
to saveDecisionToDb/nextDecisionId)
- gsd_requirement_save tool in db-tools.ts with auto-assigned IDs
- Upsert behavior in updateRequirementInDb() — creates a skeleton row
when the requirement ID is not in the DB instead of throwing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add null check before reverting requirement on disk write failure
The `existing` variable from `getRequirementById` can be null when the
requirement was newly created (not previously in DB). Guard the revert
call to avoid passing null to `upsertRequirement`.
Fixes TypeScript error: 'Requirement | null' is not assignable to 'Requirement'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Map pause_turn to "pauseTurn" instead of "stop" so the agent loop
continues when Anthropic's server pauses a long-running turn (e.g.
native web search hitting its iteration limit). Previously the
incomplete server_tool_use block was saved to history, causing a
400 invalid_request_error on the next API call.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use authoritative milestone status in web roadmap instead of slice heuristics (#2807)
The roadmap view was deriving milestone status from slice completion
flags, which disagrees with the actual GSD state model when milestones
have lifecycle states (complete/active/pending/parked) or validation
verdicts that differ from what slice progress implies.
Add status and validationVerdict fields to WorkspaceMilestoneTarget,
populate them from the state registry and VALIDATION files, and update
getMilestoneStatus() to prefer the authoritative status with a fallback
to the old heuristic for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add .js import extension and slice type annotations in workspace-status
Fixes TS2835 (missing .js extension for NodeNext resolution) and TS7006
(implicit any on slice callback parameters) that caused CI build failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: extract workspace types to .ts file to avoid jsx resolution error
Move WorkspaceTaskTarget, WorkspaceSliceTarget, WorkspaceMilestoneTarget,
and RiskLevel to workspace-types.ts so that workspace-status.ts (a plain
.ts file) can import them without requiring --jsx. The .tsx store file
re-exports the types for backward compatibility.
Fixes TS6142 in CI for PR #3258.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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>
The old STREAM_RE enumerated specific JSON error messages individually,
missing variants like "No number after minus sign", "Bad control character",
and "Expected ',' or '}' after property value" — causing auto-mode to
permanently pause instead of retrying.
Replace with a catch-all: all V8 JSON.parse errors end with
"in JSON at position \d+", so one pattern covers every current and
future variant. Keeps "Unexpected end of JSON" and "SyntaxError.*JSON"
for older runtimes.
Supersedes PR #3134. Refs #2882.
Adds a read-only command to display the current effective GSD
configuration — token profile, model assignments per phase, dynamic
routing tiers, git settings, budget, supervisor, workflow toggles,
parallel config, hooks, and preference file sources.
Renders as a themed TUI overlay (scrollable, esc/q to close) with
plain-text fallback for headless/RPC mode.
Comprehensive vscode extension redesign with sidebar reorganization,
new features, and enhanced agent integration:
- Redesign sidebar UI: reduce 6 panels to 3, declutter layout
- SCM provider for tracking agent-modified files
- Checkpoint system for saving/restoring agent state
- Diagnostic integration for surfacing errors in editor
- Line-level editor decorations for agent-modified lines
- Git integration for visualizing agent changes
- Execution plan viewer for live agent step visualization
- Approval/permissions mode system
- Auto-inject editor selection and diagnostics in chat
- Route workflow buttons through Chat panel
- Handle extension UI requests from agent (select, confirm, input)
- Session persistence, ISO timestamp support, descriptive checkpoints
- Bump to v0.3.0
Addresses 30+ issues found in a full review of the interactive TUI spanning
layout/visual, user flow, message rendering, and state management dimensions.
Critical (state/memory):
- Fix onBranchChange unsubscribe function being discarded; store and call in stop()
- Add onThemeChange cleanup in stop() to prevent stale callback retention
- Resolve getUserInput() Promise on shutdown so run() while-loop exits cleanly
- Serialize concurrent message_update event handlers via Promise chain to prevent
duplicate ToolExecutionComponent creation under rapid streaming
- Add cleanup of customFooter, customHeader, autocompleteProvider, and extension
widgets in stop() to prevent timer/watcher leaks
Major (UX/flow):
- Add two-step confirmation for provider auth removal (r key) — matches session
delete pattern; first press shows confirm hint, second press executes
- Normalize list navigation wrapping: oauth-selector and session-selector now
wrap at boundaries, consistent with all other selectors
- Ctrl+C in scoped-models-selector now always cancels modal immediately instead
of clearing search first
- Config-selector position indicator now counts only selectable items, excluding
non-selectable group headers from both numerator and denominator
- user-message-selector auto-dismiss replaced setTimeout(100) with
Promise.resolve().then() to eliminate 100ms flicker
- Add "Unknown command: /foo. Type /help for available commands." feedback for
unrecognized slash commands instead of silently submitting as chat
- Fix dead-end input path: submitPromptsDirectly=false now dispatches prompt
- Wrap session.prompt in isCompacting path with try/catch (was missing, other
path had it)
- Add Esc-to-close hint to provider-manager footer (was undocumented)
Rendering bugs:
- Remove identical dead-code else branch in assistant-message spacing logic
- Add 20-line truncation to generic/unknown tool JSON rendering (was unbounded)
- bash-execution updateDisplay() now uses stored _borderColorKey so
excludeFromContext dim styling is preserved on re-render
- Fix countdown-timer dispose race: _disposed flag prevents extra tick after
clearInterval
- extension-selector nextSelectable() guard prevents cursor landing on separator
- extension-input now rejects empty/whitespace-only submissions
- Normalize bordered-loader spacing: non-cancellable variant no longer adds
orphaned spacer before bottom border
Visual/theme:
- daxnuts.ts center() replaced naive ANSI regex with visibleWidth() from
@gsd/pi-tui for correct true-color sequence handling
- Remove incorrect mistral.ai URL from daxnuts component
- armin.ts now centers art using same visibleWidth approach as daxnuts
- Dark theme warning color: #ffff00 → #e6b800 (muted amber, less harsh)
- dynamic-border default color function wrapped in try/catch to guard against
undefined theme in jiti-loaded extension contexts
- Footer stats grouped with · separator; cache labels changed from R/W to cr:/cw:
- Replace raw \x1b[1m ANSI codes in custom-message, branch-summary-message,
compaction-summary-message, skill-invocation-message with theme.bold()
- welcome-screen visLen now uses strip-ansi instead of hand-rolled regex
Performance:
- diff.ts parseDiffLine regex: [+-\s] → [+\- ] (space only, not all whitespace)
- tab replacement width: 3 spaces → 4 spaces (standard) in both diff.ts and
tool-execution.ts
- chat-controller message_update: skip already-processed content blocks using
lastProcessedContentIndex to reduce O(n) scan per event
The validate-milestone prompt was rewritten to use 3 parallel reviewers.
Update the prompt contract test to verify the new structure instead of
the old gsd_validate_milestone tool approach.
Add getMissingAnnotationTasks() to surface which tasks lack IO
annotations and prevent parallel dispatch. Also add subagent_model
to ReactiveExecutionConfig for overriding the model used by
subagents during parallel task execution.
- getMissingAnnotationTasks() with 4 tests
- subagent_model field on ReactiveExecutionConfig type
- Validation for reactive_execution.subagent_model preference
Add dispatch rule that detects when multiple slices need research
simultaneously and dispatches them in parallel via subagents. Also
rewrite validate-milestone prompt to use 3 parallel reviewers
(requirements, integration, UAT) for faster validation.
- New dispatch rule: planning → parallel-research-slices (2+ ready)
- buildParallelResearchSlicesPrompt with per-slice subagent prompts
- Parallel research slices prompt template
- Validate-milestone rewritten for 3 parallel reviewers
Add parallel.worker_model preference so coordinators can assign a
cheaper model to parallel workers (e.g. Haiku for execution) instead
of inheriting the coordinator's model. The override is applied via
GSD_WORKER_MODEL env var during worker bootstrap.
- Add worker_model to ParallelConfig type and validation
- Inject GSD_WORKER_MODEL env in spawnWorker when configured
- Apply override in bootstrapAutoSession for parallel workers
- Document in preferences-reference.md
Move plan-milestone and plan-slice from standard to heavy tier so
planning uses the best configured model (e.g. Opus) and is not
downgraded by dynamic routing. Milestone-level planning analysis
also returns heavy instead of standard.
Add configured remote channel (Discord/Slack/Telegram) as a checkmark
in the tools row alongside Brave/Answers/Jina. Remove verbose remote
status lines and duplicate display from header-renderer and register-hooks.
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>