- Add version-match early return to initResources() — skips ~800ms of
synchronous rmSync + cpSync when managed-resources.json already matches
the running GSD version (steady-state on every launch)
- Consolidate package.json reads in loader.ts from 3 to 1 — single read
reused for --version, --help, banner, and GSD_VERSION env var
- Replace blocking checkAndPromptForUpdates() with passive checkForUpdates()
to avoid blocking startup on npm registry fetch + user prompt (up to 5s)
- Cache bundled extension keys in resource-loader to avoid redundant
filesystem scan in buildResourceLoader()
- Use GSD_VERSION env var in getBundledGsdVersion() to skip package.json
re-read from resource-loader.ts
- Add test verifying version-skip behavior: marker file survives when
versions match, gets cleaned on mismatch
The startup model validation overwrote the user's configured model when
it was 'not available' (API key missing, OAuth token expired, rate
limited). This silently changed the model to a fallback like
google/gemini-1.5-flash or openai/gpt-5.4.
Fix: Only trigger the fallback when the configured model doesn't exist
in the registry at all (removed/unknown). A model that exists but is
temporarily unavailable (credential issue) keeps its setting — the
session-level fallback resolver handles it at prompt time.
* feat: interactive update prompt on startup (#770)
When a newer version of gsd-pi is available, show an interactive
prompt at startup with two options:
[1] Update now (runs npm install -g gsd-pi@latest)
[2] Skip
- Adds checkAndPromptForUpdates() to update-check.ts
- Reuses existing 24h cache so the registry is hit at most once/day
- Shows a boxed banner with current → latest versions
- Runs npm install -g gsd-pi@latest if the user picks [1]
- Exits after a successful update so the user relaunches with the new build
- Cleans up stdin state (listeners + raw mode) so the TUI starts cleanly
- Updates cli.ts to call checkAndPromptForUpdates() instead of the
fire-and-forget checkForUpdates() in interactive mode
- Skipped in print/RPC/MCP/headless modes (isPrintMode guard)
* fix: update-check prompt cleanup and robustness (#770)
- Remove duplicate NPM_PACKAGE constant (was shadowing NPM_PACKAGE_NAME)
- Fix hardcoded box width: measure visible text width dynamically so the
border aligns correctly for any version string length
- Add 30s timeout to rl.question so the prompt auto-skips in non-TTY
or piped-stdin edge cases that slip past the isPrintMode guard
* fix: address review feedback on update prompt (#770)
Three issues from @glittercowboy's review:
1. Box rendering bug: mid line was built as '║' + content + '║' then
sliced with .slice(1,-1) which cuts into ANSI escape sequences.
Fix: build midContent without delimiters and wrap with chalk.yellow('║')
directly, keeping a separate plain-text midVisible for width measurement.
2. Missing TTY guard: !isPrintMode alone isn't sufficient — a piped
stdin without --print would sit waiting 30s silently.
Fix: gate checkAndPromptForUpdates() on process.stdin.isTTY; fall back
to the passive checkForUpdates() banner for non-TTY interactive mode.
3. Dead import: checkForUpdates was imported but unused after the
previous refactor. Now used again as the non-TTY fallback — no
dead code.
Adds a first-class `gsd headless` command that runs auto-mode without a
TUI by spawning a child process in RPC mode via RpcClient. Useful for
CI/CD pipelines, scripts, and unattended execution.
CLI interface:
gsd headless - Run auto-mode until complete
gsd headless --step - Run one unit only (sends /gsd next)
gsd headless --timeout 300000 - Custom timeout (default 5 min)
gsd headless --json - Forward RPC events as JSONL to stdout
gsd headless --verbose - Show full agent text and tool results
gsd headless --model <id> - Override model
Exit codes: 0 = complete, 1 = error/timeout, 2 = blocked
Features:
- Extension UI auto-responder (handles select, confirm, input, editor,
notify, setStatus, setWidget, setTitle, set_editor_text)
- Completion detection via terminal notification keywords + idle timeout
- Human-readable progress output to stderr
- SIGINT/SIGTERM forwarding for clean shutdown
- Child process crash detection
- Completion summary with diagnostics on failure
Add a new `gsd sessions` subcommand that lists all saved sessions for
the current directory and lets the user interactively pick one to resume.
Currently `gsd --continue` only resumes the most recent session, with no
way to access older conversations. This change adds:
- `gsd sessions` subcommand that calls SessionManager.list() to enumerate
all sessions for the current working directory
- Interactive numbered list showing date, message count, session name (if
set), and a preview of the first message
- Selection by number to resume any past session via SessionManager.open()
- Subcommand help text (`gsd sessions --help`)
- Help text entry in the main `gsd --help` output
The implementation uses only existing SessionManager APIs (list, open) -
no SDK changes required.
- Add native MCP server mode (--mode mcp): exposes GSD's tools via
Model Context Protocol over stdin/stdout for Claude Desktop, VS Code,
and other MCP-compatible clients. Uses @modelcontextprotocol/sdk.
- Add /lint skill: auto-detects ESLint, Biome, Prettier, rustfmt,
gofmt, Black, Ruff and runs with structured output
- Add 6 E2E smoke tests: --version, --help, config --help, update
--help, --list-models, and --mode text --print startup
- Fix diff-context.ts stdio type for CI compatibility
- Fix token-counter.ts tiktoken import for extensions typecheck
- Update help text and CLI to include --mode mcp
- Add /review skill: reviews staged/unstaged/commit changes for security,
performance, bugs, and quality with structured findings by severity
- Add /test skill: auto-detects test framework, generates comprehensive
tests for source files, or runs suites with failure analysis
- Add chokidar file watcher: watches ~/.gsd/agent/ for config changes
(settings.json, auth.json, models.json, extensions/) with debounced
events on an EventBus
- Add --help per subcommand: `gsd config --help` and `gsd update --help`
show subcommand-specific usage information
- 8 new file-watcher tests (start/stop, event emission, debouncing,
unrelated file filtering)
- Extract duplicated help text from loader.ts and cli.ts into shared
help-text.ts module (single source of truth)
- Convert validate-pack.sh to Node.js for Windows compatibility
- Fix dev.js using unnecessary npx for tsc (it's a devDependency,
use node_modules/.bin/tsc directly)
Extension-based providers like pi-claude-cli may not require credentials
in auth.json, causing shouldRunOnboarding() to always return true and
repeat the wizard every launch. Now checks if a defaultProvider is
already set in settings before triggering the wizard.
Arrow keys produce `^[[D`/`^[[C` instead of moving the cursor when event
loop latency causes the StdinBuffer to split escape sequences.
Three layered fixes:
1. Increase StdinBuffer timeout from 10ms to 50ms (matches xterm default)
so split escape sequences are reassembled even under load.
2. Clean up stale readline listeners after @clack/prompts onboarding —
readline.emitKeypressEvents() leaves a permanent data listener that
is unnecessary for the TUI.
3. Guard in editor against CSI remnants: if a split still occurs, reject
text matching navigation escape patterns ([A-F, [H, [Z, [n~) instead
of inserting them as characters.
Closes#493
- cli.ts: use chalk.yellow/dim/bold instead of raw \x1b sequences for
version mismatch message; chalk v5 auto-respects NO_COLOR
- update-check.ts: same chalk migration for the update banner
- guided-flow.ts: log auto-start errors when GSD_DEBUG is set instead
of silently swallowing them
Three fixes for config/setup UX:
1. cli.ts: Add missing loadStoredEnvKeys() call in gsd config flow.
Previously, gsd config showed keys as "not configured" even when
they existed in auth.json because env vars weren't hydrated first.
2. commands.ts: New /gsd config slash command that lets users configure
API keys (Tavily, Brave, Context7, Jina, Groq) from within a running
session. Keys are saved to auth.json and activated immediately.
No need to exit the session and run gsd config externally.
3. command-search-provider.ts: Show native Anthropic web search status
when using Claude models, so users know search works even without
Brave/Tavily keys.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a CLI subcommand that checks npm for the latest version and
runs `npm install -g gsd-pi@latest` if an update is available.
Prints current/latest version and clear success/failure messages.
Queries npm registry at most once per 24h to check if a newer version
of gsd-pi is available. Displays a non-blocking banner in interactive
mode when an update exists. The check is fire-and-forget — network
errors or timeouts never block startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vendor all 4 Pi packages (tui, ai, agent-core, coding-agent) from
pi-mono v0.57.1 as @gsd/* workspace packages under packages/. This
replaces the compiled npm dependency (@mariozechner/pi-coding-agent)
and patch-package workflow, giving direct source access for
modifications.
- Copy Pi source from pi-mono v0.57.1 into packages/
- Create workspace package.json + tsconfig.json for each package
- Rename ~240 imports from @mariozechner/pi-* to @gsd/pi-*
- Apply existing patches as source edits (setModel persist, VT input)
- Remove @mariozechner/pi-coding-agent dep and patch-package
- Update build pipeline to build packages in dependency order
- Add pi-upstream git remote for future selective syncing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses the existing SessionManager.continueRecent() from the Pi SDK
to load the most recent session for the current working directory.
Mirrors the --continue flag already available in the base Pi CLI.
Replace the plain-text API-key-only wizard with a branded, clack-based
onboarding experience that guides first-launch users through LLM provider
authentication (OAuth or API key), optional tool API keys, and a summary.
- Create src/logo.ts as single source of truth for ASCII logo
- Create src/onboarding.ts with shouldRunOnboarding() and runOnboarding()
- Trim src/wizard.ts to env hydration only (loadStoredEnvKeys)
- Wire onboarding into src/cli.ts, add `gsd config` subcommand
- Remove duplicate first-launch banner from src/loader.ts
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
CLI routing (#81, #107):
- Import and route --mode rpc to runRpcMode() instead of silently falling through to runPrintMode
- Add TTY guard before interactive mode — exit with helpful message when stdin is not a TTY
- Add --version and --help flags
Auto-mode infinite loop (#96):
- Move summarizing/complete-slice dispatch before reassessment check (D1) — ensures mergeSliceToMain always runs
- Add per-unit dispatch counter to detect alternating loops like A→B→A→B (D3)
Windows shell escaping (#106, #98):
- Platform-aware escapeShellArg() in mcporter extension — double quotes on Windows, single quotes on Unix
CRASH: parseSummary (#91):
- Add asStringArray() helper to safely coerce YAML bare scalars (e.g. "none") to string arrays
- Applied to all 7 frontmatter fields that expect string[]
Google Search model (#99):
- Replace hardcoded gemini-3-flash-preview with env var GEMINI_SEARCH_MODEL (default: gemini-2.5-flash)
Worktree branch collision (#84):
- Check git worktree list before checkout to detect branches already in use by another worktree
Migration UX (#90, #93):
- Improve error messages to distinguish migration from new project setup, suggest /gsd:new-project
Keyboard shortcuts (#100, #104):
- Document terminal protocol requirement in shortcut descriptions — Ctrl+Alt combos need Kitty/modifyOtherKeys
Closes#81, #84, #91, #96, #99, #106, #107
Addresses #90, #93, #95, #98, #100, #104
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ensureSliceBranch() now auto-commits dirty files before git checkout,
preventing "would be overwritten" errors when doctor/STATE.md rebuild
leaves uncommitted changes between slice dispatches. (closes#63)
On startup, migrate any .jsonl session files from the flat
~/.gsd/sessions/ directory into the per-cwd subdirectory so /resume
can find sessions created before per-directory scoping was added.
(closes#64)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cli.ts unconditionally entered InteractiveMode, ignoring --mode, -p,
--no-session and other flags the subagent extension passes to child
processes. The child would wait for TTY input that never arrives
(stdin is "ignore"), causing the parent to hang forever on "working".
Parse CLI args to detect print/subagent mode and route to runPrintMode()
with proper session, model, extension, and system prompt handling.
Closes#45
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sessions are stored in a single flat ~/.gsd/sessions/ directory, so
/resume shows sessions from all projects regardless of which folder
you're in.
Use per-cwd subdirectories under ~/.gsd/sessions/ with the same
path encoding the upstream SDK uses (--path-segments--), so /resume
only lists sessions from the current working directory.
Uses getAll() instead of getAvailable() so stale models like grok-2
are caught even when the user has no auth for the correct provider yet.
Resets thinking to off when the configured model was invalid.
- Remove gsd-pi from its own dependencies (circular dep caused ENOTEMPTY install failures)
- Auto-select anthropic/claude-sonnet-4-6 as default model for new installs
- Reset to valid model if configured model no longer exists in registry
- Default thinking level to off
When users logged in via /login but never explicitly ran /model, the agent
would throw 'No model configured' on every action. Now GSD auto-selects
a default model from available authenticated providers on startup.
Preference order: claude-sonnet-4-20250514 > any Anthropic model > first available.
Also documented /model command in README Getting Started section.
Closes#4