Introduces six new modules that work together to reduce token usage across
the dispatch pipeline while preserving semantic content quality:
- Provider-aware token counting with per-provider char/token ratios
- Prompt cache optimizer for maximizing Anthropic/OpenAI cache hit rates
- Structured data formatter (compact notation for decisions/requirements/tasks)
- Deterministic prompt compressor (light/moderate/aggressive levels)
- Semantic chunker with TF-IDF relevance scoring for context selection
- Summary distiller for condensed dependency summaries
Integration points:
- inlineDependencySummaries uses distillation before truncation (3+ deps)
- inlineDecisionsFromDb/inlineRequirementsFromDb use compact format at non-full levels
- buildExecuteTaskPrompt compresses carry-forward when it exceeds 40% of budget
- context-budget.reduceToFit combines compression with section-boundary truncation
- computeBudgets accepts optional provider for accurate char/token ratios
All existing 1475 unit tests + 30 integration tests pass with zero regressions.
157 new tests cover all optimization modules.
When handleAgentEnd dispatches a sub-unit (via hooks, triage, or quick-task
early-dispatch paths) and that unit completes before handleAgentEnd returns,
the resulting agent_end event is silently dropped by the reentrancy guard.
This leaves auto-mode active but permanently stalled — no unit running, no
watchdog set, process at high CPU doing nothing.
Add a pendingAgentEndRetry flag to AutoSession that the reentrancy guard sets
when it drops an agent_end event. The finally block in handleAgentEnd checks
this flag and schedules a deferred retry via setImmediate, ensuring the
completed unit's agent_end is always processed.
* fix: add barrel files for remote-questions, ttsr, and shared extensions
Centralizes public API surface for three extension directories behind
index.ts barrel files. External consumers now import from the barrel
instead of reaching into internal module files, reducing coupling and
making future refactors safer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: rename barrel files to mod.ts to avoid extension loader auto-discovery
The extension loader auto-discovers extensions by looking for index.ts files
inside extensions/*/ directories. remote-questions/ and shared/ are utility
directories, not extensions — their index.ts barrel files caused load failures.
Renamed to mod.ts which the loader ignores, and updated all import paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extracts 11 hardcoded timeout, retry, compaction, and tool-default
values from 9 source files into a single constants.ts module. Each
source file now imports from the central definition, eliminating
duplicated literals and making tuning a single-file change.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: consolidate frontmatter parsing into shared module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: strip quotes from frontmatter scalar values
The shared parseFrontmatterMap was missing quote-stripping that the old
rule-loader had, causing 3 test failures in ttsr-rule-loader.test.ts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
oh-my-zsh's git plugin defines alias gsd='git svn dcommit' which
shadows the GSD binary. Added troubleshooting section to
getting-started.md with two solutions: unalias in .zshrc, or use
the gsd-cli alternative binary name.
ensurePreconditions() had two branches: create-slice (which included
tasks/) and slice-exists (which conditionally created tasks/). The
conditional path could miss cases where a slice dir was created
manually or by a previous run without the tasks/ subdirectory.
Simplified to: create slice dir if missing, then always check and
create tasks/ unconditionally. Removes the branching that could
leave tasks/ missing.
9 tests that enforce the encapsulation of auto-mode state in AutoSession:
1. No module-level let declarations in auto.ts
2. No module-level var declarations in auto.ts
3. Exactly one AutoSession singleton
4. reset() covers every instance property
5. toJSON() includes key diagnostic properties
6. Module-level consts are only constants/accessors (no mutable state)
7-9. session.ts exports AutoSession with reset() and toJSON()
Added maintenance comments to auto.ts and auto/session.ts explaining
the invariant and linking to these tests. Any PR that adds a module-level
mutable variable to auto.ts will fail CI.
Move scattered timeout and cache-size constants (DEFAULT_COMMAND_TIMEOUT_MS,
DEFAULT_BASH_TIMEOUT_SECS, DIR_CACHE_MAX, CACHE_MAX) into a single
constants.ts module within the GSD extension.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split RemotePromptRecord into a discriminated union of PendingPromptRecord
(ref is undefined) and DispatchedPromptRecord (ref is required). This
makes the type system enforce that ref is always present after dispatch.
Also removes a redundant truthiness check on dispatch.ref in manager.ts,
since RemoteDispatchResult.ref is already non-optional.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add descriptive comments to all empty catch blocks explaining why the
error is intentionally swallowed. Covers networkidle timeouts, optional
screenshots, best-effort file writes, response body reads, route
cleanup, and page metadata refreshes.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes a security gap where ask-user-questions errorResult() could leak
tokens in error messages. The sanitizeError function and TOKEN_PATTERNS
are now in shared/sanitize.ts, imported by both manager.ts and
ask-user-questions.ts.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add missing \u1680 (Ogham space mark) to UNICODE_SPACES in path-utils.ts
and loader.ts. Make edit-diff.ts import the shared constant from
path-utils.ts instead of maintaining an inline copy.
Rename hashlineParseText to parseHashlineText to follow the parseX()
convention used across the codebase.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Align pi-tui chalk from ^5.5.0 to ^5.6.2 (matches root, pi-ai, pi-coding-agent)
- Convert @mistralai/mistralai and openai to caret ranges (^1.14.1, ^6.26.0)
in both root and pi-ai — no intentional pin rationale found in git history,
versions were just hoisted as-is from workspace deps
- Keep gaxios@7.1.4 override pinned — intentionally set in 5c64f99 to
eliminate glob@10.5.0 deprecation warnings from transitive deps
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cap parallel async operations to prevent memory spikes when processing
large numbers of items:
- session-manager.ts: limit file loading to 10 concurrent reads
- pipeline.ts: limit job execution to 5 concurrent LLM calls
- discovery.ts: limit tool scanning to 5 concurrent scanners
Uses an inline pLimit utility in each file to avoid adding a dependency.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate six per-subdirectory makeTreeWritable calls (pre+post copy
for extensions, agents, and skills) into two calls on the parent agentDir:
one before all copies to unlock existing Nix-store read-only files, and
one after to ensure newly copied files are writable for subsequent runs.
Eliminates ~4 redundant recursive stat+chmod walks, saving 100-300ms on
every CLI launch that triggers resource sync.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add argument completions for /thinking command with all 6 levels
(off, minimal, low, medium, high, xhigh) and descriptions
- Add descriptions to all GSD 2nd-level subcommand completions across
14 subcommand groups (auto, mode, parallel, setup, prefs, remote,
next, history, undo, export, cleanup, knowledge, doctor, dispatch)
- Add 35 new tests for autocomplete and fuzzy matching systems
gsd_generate_milestone_id scans disk for existing milestone dirs.
When called multiple times before any artifacts are written, it
returned the same ID (e.g. M001) every time because no dirs existed
yet.
Added an in-memory reservation set that tracks IDs returned by the
tool. Subsequent calls merge reserved IDs with on-disk IDs before
computing the next sequential ID, ensuring M001, M002, M003 are
returned in sequence even without intermediate disk writes.
* fix: consolidate duplicate formatting functions
- Rename private formatDuration in verification-evidence.ts to
formatDurationSecs to clarify its distinct fixed-seconds behavior
- Replace formatUptime implementation in bg-shell/utilities.ts with
import of shared formatDuration (functionally equivalent for >=1s)
- Replace inline fmt lambda in cli.ts with shared formatTokenCount
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: revert cli.ts import from extensions path that breaks at runtime
The extensions directory uses a separate compilation/bundle path and
cannot be imported from cli.ts. Restores the inline fmt lambda.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(gsd): delete orphaned complexity.ts (superseded by complexity-classifier.ts)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(test): update complexity-routing tests for complexity-classifier.ts
The test file imported from the deleted complexity.ts. Removed tests
for the defunct classifyTaskComplexity function and updated all source
reads to reference complexity-classifier.ts with its actual exports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(search): consolidate duplicate Brave API helper functions
getBraveApiKey() and braveHeaders() were duplicated across provider.ts,
tool-llm-context.ts, and tool-search.ts. Export both from provider.ts
and import in the tool files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(test): update provider export count to include braveHeaders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the final milestone completed with no queued follow-up, stopAuto()
tore down the worktree with preserveBranch: true but never called
mergeMilestoneToMain(). All work stayed on the milestone branch,
unmerged to main.
Add merge logic to the "all milestones complete" path in
dispatchNextUnit(), mirroring the existing merge handling in the
single-milestone-complete path. Handles both worktree isolation and
branch isolation modes.
Adds a new setting 'respectGitignoreInPicker' (default: true) that
controls whether the @ file picker respects .gitignore when listing
files. When set to false, gitignored files appear in fuzzy search
results.
Wired through:
- CombinedAutocompleteProvider: new constructor option + setter
- SettingsManager: getter/setter with persistence
- Settings selector UI: toggle in settings panel
- InteractiveMode: reads setting at init, updates provider on change
Move resolveGitHeadPath() and nudgeGitBranchCache() to worktree.ts as
the canonical shared location. Both auto-worktree.ts and
worktree-command.ts now import from worktree.ts instead of defining
their own copies.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 7 missing subpath exports to @gsd/native (diff, gsd-parser,
highlight, json-parse, stream-process, truncate, ttsr) and create
root-level oauth.js/oauth.d.ts stub files for @gsd/pi-ai to match
the bedrock-provider pattern.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename browser-tools VerificationCheck/Result to BrowserVerificationCheck/Result
to eliminate name collisions with the semantically different types in gsd/types.ts.
The browser-tools types track UI element state verification (name/passed/value),
while gsd/types.ts types track command execution verification (command/exitCode/stdout).
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gitFileExec() was missing the GIT_NO_PROMPT_ENV env overlay, which meant
git could prompt for credentials and hang the process on write operations
(add, commit, revert, checkout). Extract the shared constant into
git-constants.ts to avoid duplication between git-service.ts and
native-git-bridge.ts.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, only rate-limit errors (429/too many requests) triggered
auto-resume with a delay. Server errors (500 Internal Server Error,
503 Service Unavailable, overloaded) paused auto-mode indefinitely,
requiring manual /gsd auto to resume. This was the core complaint in
sit idle until morning.
Now all transient provider errors auto-resume:
- Rate limits: auto-resume after retry-after delay (or 60s default)
- Server errors (500/502/503/overloaded/api_error): auto-resume after 30s
- Permanent errors (auth/billing/quota): still pause indefinitely
New classifyProviderError() function in provider-error-pause.ts provides
structured error classification with suggested delays. The agent_end
handler in index.ts now uses this instead of a simple regex check.
14 new tests cover all error categories and edge cases.
Files changed:
- provider-error-pause.ts: Add classifyProviderError(), update
pauseAutoForProviderError() to support isTransient flag
- index.ts: Use classifyProviderError() for structured error handling
- tests/provider-error-classify.test.ts: 14 new tests
* Add CI/CD pipeline design spec
Three-stage promotion pipeline (Dev → Test → Prod) using npm dist-tags,
GitHub Environments, Docker images, and an LLM fixture recording system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace ambiguous compound question in reflection step (#963)
The reflection prompt 'Did I get that right, or did I miss something?'
is a compound question where 'yes' maps to both possible answers.
Replaced with 'Does that capture it? If not, tell me what I missed.'
— one closed question plus an instruction, removing ambiguity.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Allow orchestrators to filter the JSONL event stream to specific event
types, reducing stdout noise. The filter applies only to output —
internal processing (completion detection, supervised mode, answer
injection) is unaffected.
- New `--events <types>` flag (comma-separated, implies `--json`)
- Filter applied at stdout write point, all events still processed internally
- Updated help-text and SKILL.md with examples
- Tests for argument parsing and filter matching logic
* fix(gsd): clear all caches after discuss dispatch so picker sees new CONTEXT files
guided-flow.ts called only invalidateStateCache() after waitForIdle(),
leaving dirEntryCache stale. resolveSliceFile("CONTEXT") missed files
written during the discuss session, keeping the just-discussed slice
recommended and preventing the allDiscussed exit gate from firing.
Swap to invalidateAllCaches() at both call sites (discuss loop and
queue reorder), matching the pattern used throughout auto.ts.
Fixes#977
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(gsd): remove STATE.md update instructions from all prompts (#978)
STATE.md is a derived runtime file rebuilt by auto.ts after every unit.
Prompts telling LLMs to update it caused git staging errors when the
LLM ran `git add .gsd/` and hit the gitignore barrier, leaving sessions
stuck. Removed redundant STATE.md instructions from 13 prompts, made
commit instructions explicit about which files to stage, and switched
bootstrap `nativeAddPaths` to `nativeAddAll` to respect .gitignore in
the CLI fallback path.
Closes#978
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>