Commit graph

176 commits

Author SHA1 Message Date
TÂCHES
27e79f76b3 refactor: centralize magic numbers into constants.ts (#1044)
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>
2026-03-17 18:45:43 -06:00
TÂCHES
5657f302a6 refactor: fix unicode regex discrepancy and standardize function naming (#1031)
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>
2026-03-17 18:29:44 -06:00
TÂCHES
3537f6b716 chore: fix chalk version mismatch and document pinned dependency rationale (#1030)
- 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>
2026-03-17 18:29:31 -06:00
TÂCHES
61f4693f16 perf: add concurrency limits to unbounded Promise.all operations (#1029)
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>
2026-03-17 18:29:28 -06:00
TÂCHES
311f3c2c36 fix(security): use execFileSync in resolve-config-value to prevent shell operator bypass (#1025)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:29:12 -06:00
TÂCHES
e66039162e perf: optimize SSE streaming buffer to avoid quadratic string growth (#1024)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:29:09 -06:00
TÂCHES
61858b914f fix(security): use execFile for browser URL opening to prevent shell injection (#1022)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:28:24 -06:00
Jeremy McSpadden
fd9565299c feat(autocomplete): add /thinking completions, GSD subcommand descriptions, and test coverage (#1019)
- 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
2026-03-17 18:27:17 -06:00
Tom Boucher
cc4e3aa7b5 feat: add respectGitignoreInPicker setting for @ file picker (#979) (#1016)
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
2026-03-17 18:03:02 -06:00
TÂCHES
f8b16beddb fix: add missing package.json subpath exports and oauth stubs (#1014)
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>
2026-03-17 18:01:56 -06:00
Jeremy McSpadden
f85c41c693 feat(ux): group model list by provider in /gsd prefs wizard (#993)
* feat(ux): group model list by provider in /gsd prefs wizard

The model selection in configureModels() was a single flat alphabetical
list that became unwieldy with many providers. This groups models under
provider headers (e.g. "─── anthropic (24) ───") so users can quickly
scan to the right provider section.

Changes:
- ExtensionSelectorComponent: add SEPARATOR_PREFIX convention for
  non-selectable group headers. Navigation skips separators, Enter
  ignores them, and they render with borderAccent styling.
- configureModels: build grouped option list with provider headers
  instead of flat map.
- New test: extension-selector-separator.test.ts (6 tests).

* fix(ci): use node:test instead of vitest in extension-selector test

tsconfig.extensions.json does not include vitest type declarations,
causing TS2307 in CI. Rewrite test to use node:test + node:assert
to match the convention used by other extension tests.

* fix(ci): rewrite separator test to avoid TS parameter property issue

The extension-selector component transitively imports countdown-timer.ts
which uses TypeScript parameter properties (private tui: TUI). Node's
--experimental-strip-types cannot handle these, causing ERR_UNSUPPORTED_
TYPESCRIPT_SYNTAX in CI.

Rewrite the test to verify the separator detection logic and model
grouping contract without importing the component. Duplicates the
isSeparator/nextSelectable helpers and tests them directly.
2026-03-17 17:20:13 -06:00
TÂCHES
4cb5f8dbca fix: add exports fields to pi-tui and pi-agent-core packages (#991)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:05:47 -06:00
TÂCHES
4da793f576 fix: remove broken ./hooks export path from pi-coding-agent (#984)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:02:12 -06:00
Lex Christopherson
a8b9030560 fix: export RPC utilities from pi-coding-agent public API
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 16:20:13 -06:00
Jeremy McSpadden
0e0f47ef9f fix: failure recovery & resume safeguards (all 4 waves) (#956)
* fix: prevent data loss on crash with atomic writes, file locking, and error handling

Wave 1 of failure recovery safeguards:

1. Atomic session file rewrites (tmp+rename) — _rewriteFile() and forkFrom()
   now use atomicWriteFileSync to prevent session file corruption on crash
2. Atomic auto.lock writes — crash-recovery.ts writeLock() uses tmp+rename
   so the crash detection system itself can't be corrupted
3. unhandledRejection handler — catches silent process death from unhandled
   promise rejections in OAuth, extensions, LSP, or MCP connections
4. try/catch in emitToolCall — matches pattern used by emitUserBash,
   emitContext, and emitToolResult to prevent extension handler crashes
   from killing the entire agent turn
5. File locking on session appends — prevents concurrent pi instances from
   interleaving partial JSON lines in session JSONL files using the same
   proper-lockfile pattern established in auth-storage.ts and settings-manager.ts

* fix: add OAuth timeouts, RPC exit detection, and command context guards

Wave 2 of failure recovery safeguards:

1. OAuth fetch timeouts — all fetch() calls across all OAuth providers
   (Anthropic, OpenAI Codex, Google Antigravity, Google Gemini CLI,
   GitHub Copilot) now have 30-second AbortSignal.timeout() to prevent
   indefinite hangs when OAuth servers are unresponsive
2. RPC subprocess exit detection — pending requests are now rejected
   when the agent subprocess exits unexpectedly, preventing indefinite
   hangs in the RPC client
3. Extension command context guards — default handlers for newSession,
   fork, navigateTree, switchSession, and reload now throw explicit
   errors instead of silently returning success when called before
   bindCommandContext()
4. OAuth error detail preservation — token refresh errors now preserve
   the original error as `cause` for better diagnostics

* fix: resource cleanup, LSP retry, and crash detection on session resume

Wave 3 of failure recovery safeguards:

1. Atomic completed-units.json cleanup — milestone completion writes
   now use tmp+rename pattern for consistency with auto-recovery.ts
2. Bash temp file cleanup — track temp files created for large output
   and register a process exit handler to clean them up
3. Settings write queue flush on shutdown — call settingsManager.flush()
   during interactive mode shutdown so queued writes aren't lost
4. LSP initialization retry — wrap getOrCreateClient with up to 2 retries
   with exponential backoff (1s, 2s) for transient spawn failures
5. Crash detection on session resume — wasInterrupted() checks if last
   assistant turn had tool calls without results, shows warning on resume

* fix: blob garbage collection and LSP debug logging

Wave 4 of failure recovery safeguards:

1. Blob garbage collection — BlobStore.gc(referencedHashes) removes
   orphaned blobs not referenced by any session file, plus totalSize()
   for monitoring blob directory growth
2. LSP JSON parse error logging — malformed LSP messages are now logged
   at debug level (when DEBUG env is set) instead of being silently dropped
2026-03-17 16:03:49 -06:00
Tom Boucher
188e7a67c4 fix: single ENTER submits slash command argument autocomplete (#944) (#953)
When completing a /gsd subcommand via autocomplete (e.g. selecting 'auto'
after typing '/gsd '), ENTER now submits immediately instead of requiring
a second press.

The selectConfirm handler already fell through to submit when the
autocomplete prefix started with '/' (completing the command name itself).
Now it also falls through when the cursor is in a slash command context
(completing an argument like 'auto', 'status', 'help').

Non-slash completions (@file references, paths) still require explicit
ENTER to submit — only slash command arguments auto-submit.
2026-03-17 15:28:40 -06:00
Tom Boucher
2306e6bb34 fix: LSP command resolution and ENOENT crash on Windows/MSYS (#901) (#925)
Two fixes:

1. lsp/config.ts: Use `where.exe` instead of `which` on Windows.
   MSYS's `which` returns POSIX paths (/c/Users/...) that Node's
   spawn() can't execute. `where.exe` returns native Windows paths.

2. lsp/client.ts: Handle spawn ENOENT error gracefully. When the LSP
   server binary doesn't exist, the error event now triggers a clean
   exit instead of bubbling up and crashing auto-mode.
2026-03-17 14:01:16 -06:00
Tom Boucher
5d86159ea8 fix: replan-slice infinite loop, non-standard finish_reason crash, fork-resilient test (#866) 2026-03-17 11:47:07 -06:00
Tom Boucher
3542b17c97 fix: normalize Windows paths in LLM-visible text to prevent bash failures (#874) (#884)
On Windows, process.cwd() returns backslash paths (C:\Users\name\...).
When these paths are injected into system prompts, worktree context
blocks, or tool results, the model copies them into bash commands.
Bash interprets backslashes as escape characters, silently stripping
them — producing invalid paths like 'C:Usersnamedevelopmentapp-name'.

This is not a regex hack — it's a proper cross-platform boundary:
- Filesystem operations (fs, path.join, spawn cwd) use native paths
  unchanged. Node handles both separators correctly for I/O.
- LLM-visible text (prompts, tool results, extension messages) uses
  toPosixPath() to normalize to forward slashes. C:/Users/name/...
  is valid in Git Bash, WSL bash, PowerShell, and Node.js.

Changes:

- utils/path-display.ts: New toPosixPath() utility in pi-coding-agent
  package (for system prompt) and shared extension module (for
  extensions that can't import from the compiled package at dev time)

- system-prompt.ts: Normalize resolvedCwd before injecting into the
  'Current working directory' line

- gsd/index.ts: Normalize all process.cwd() and originalBase paths in
  worktree context blocks injected into the system prompt

- bg-shell/index.ts: Normalize cwd in tool result text (start, env
  actions) that the model reads and may reference in commands

- path-display.test.ts: 9 regression tests covering toPosixPath
  behavior and system prompt output verification. Includes a scanner
  that fails if any Windows absolute paths with backslashes appear in
  buildSystemPrompt() output.

Audit scope: Checked all process.cwd() usage across pi-coding-agent
and all bundled extensions. Filesystem-only paths (join, readFile,
spawn cwd, existsSync) are correct and left unchanged. Only paths
entering LLM text are normalized.
2026-03-17 09:02:23 -06:00
Tom Boucher
62bbaa8e8e feat: integrate hashline edit mode into active workflow (#870) (#872) 2026-03-17 08:23:53 -06:00
Jeremy McSpadden
a8eb66b8b3 feat: group /model selector by provider (#871) 2026-03-17 08:23:29 -06:00
Tom Boucher
0abc61987d fix: add Alt+V as clipboard image paste shortcut on macOS and document it (#852) (#854) 2026-03-17 08:19:13 -06:00
Tom Boucher
8872c9095e fix: mark transient network errors as retriable in Anthropic provider (#833) (#849) 2026-03-17 08:17:25 -06:00
Tom Boucher
d593b2e367 fix: handle BMP clipboard images on WSL2 via wl-paste PNG conversion or ImageMagick (#813) (#841) 2026-03-17 07:59:56 -06:00
Tom Boucher
0873961550 fix: handle EPIPE in LSP sendNotification and wait for process exit on reload (#815) (#837) 2026-03-17 07:59:25 -06:00
Tom Boucher
d94728aa7e fix: prevent crash when cancelling OAuth provider login dialog (#821) (#831)
OAuthSelectorComponent calls its onSelect callback synchronously (no
await), but the callback was async — calling showLoginDialog which
throws 'Login cancelled' on Escape. The unhandled rejection bubbled
up to the uncaughtException handler and crashed GSD.

Wrap the async work in a named function with .catch() so cancellation
errors are swallowed gracefully. showLoginDialog already handles its
own error display internally.
2026-03-17 07:49:09 -06:00
TÂCHES
440e6e878f feat: render native web search in TUI + PREFER_BRAVE_SEARCH toggle (#806)
* feat: render native web search tool calls in TUI

The Anthropic streaming parser silently dropped server_tool_use and
web_search_tool_result content blocks, making native web search
invisible. Add ServerToolUseContent and WebSearchResultContent types,
handle both block types in the streaming parser and conversation replay,
and render them as ToolExecutionComponent in the interactive TUI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add PREFER_BRAVE_SEARCH env var to bypass native web search

Set PREFER_BRAVE_SEARCH=1 to keep Brave/custom search tools active
on Anthropic models instead of injecting native server-side web search.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: skip non-toolCall blocks in Mistral provider conversation replay

The ServerToolUseContent and WebSearchResultContent types added for
native web search don't have id/name/arguments properties, causing
TypeScript errors when the Mistral provider tried to push them as
tool calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:35:20 -06:00
TÂCHES
52848d7fd2 fix: raise maxDelayMs default from 60s to 300s (#756) (#773)
Anthropic rate limit reset windows are typically 60-120s. The previous 60s
default, combined with the +1s buffer in extractRetryAfterMs(), meant that
virtually all rate limit retries were immediately abandoned.

300s (5 min) covers the vast majority of rate limit windows and lets the
built-in retry logic work as intended.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:03:13 -06:00
TÂCHES
6a452f27d9 Merge pull request #750 from jeremymcs/fix/startup-lazy-loading
perf: lazy-load LLM provider SDKs to reduce startup time
2026-03-16 20:28:32 -06:00
Jeremy McSpadden
6d77724378 perf: lazy-load LLM provider SDKs to reduce startup time
All major LLM provider SDKs were loaded eagerly at startup, penalizing
users regardless of which provider they actually use. This change defers
SDK loading until first API call for:

- @anthropic-ai/sdk (anthropic.ts)
- openai (openai-responses.ts, openai-completions.ts, azure-openai-responses.ts)
- @google/genai (google-vertex.ts)

The Bedrock provider already used this pattern. Now all 5 remaining
providers use the same async lazy-loader pattern:
- Static import changed to `import type` (erased at compile time)
- Module-level `let _SdkClass` cache variable
- `async function getSdkClass()` loader with singleton caching
- `createClient()` made async, uses `await getSdkClass()`
- Call sites updated with `await createClient()`

For google-vertex.ts, ThinkingLevel enum usage replaced with equivalent
string literals to eliminate the runtime import entirely.

All packages build cleanly. The startup improvement is proportional to
how many providers were installed — on typical installs this eliminates
eager loading of 30-40MB of SDK code.
2026-03-16 18:33:24 -05:00
Jeremy McSpadden
a3ff25c668 fix(bash): rewrite background commands to prevent pipe-open hang
Root cause: when the LLM runs `cmd &`, bash forks the process and
exits immediately. The forked process inherits Node's piped stdout/
stderr FDs. Node.js waits for all holders of those FDs to close before
firing the 'close' event — so the tool hangs until the background
process exits (which for a server is never).

Fix: add rewriteBackgroundCommand() in bash.ts. Before exec, detect
commands with a trailing & background operator and inject
>/dev/null 2>&1 before the & when stdout is not already redirected.
This severs the pipe inheritance so Node gets 'close' immediately
when the shell exits.

Guards:
- Commands already redirecting stdout (>, >>, &>, |) are not rewritten
- && (logical AND) is not affected
- & inside single-quoted strings is not affected
- A brief onUpdate advisory is surfaced when rewrite happens so the
  LLM knows to prefer nohup/setsid for robust detachment

Export rewriteBackgroundCommand from pi-coding-agent for testability.

Tests: bash-background.test.ts — 12 cases covering no-op paths,
rewrite paths, compound commands, and already-safe nohup patterns.
Closes #733
2026-03-16 18:03:01 -05:00
TÂCHES
e4d47de1f6 Merge pull request #690 from trek-e/fix/688-thinking-minimal-gpt5
fix: clamp 'minimal' thinking level to 'low' for gpt-5.x models (#688)
2026-03-16 14:17:51 -06:00
Tom Boucher
1a499aecb2 fix: clamp 'minimal' thinking level to 'low' for gpt-5.x models (#688)
gpt-5.x models (via Copilot/OpenAI/Azure) don't support 'minimal' as a
reasoning effort level — they only accept 'none', 'low', 'medium',
'high', and 'xhigh'. Setting /thinking minimal with gpt-5.4 causes a
400 error.

The openai-codex-responses provider already had this clamping, but the
openai-responses and azure-openai-responses providers passed the value
through unclamped.

Add clampReasoningForModel() to both providers that maps 'minimal' to
'low' for gpt-5.x models, matching the existing behavior in
openai-codex-responses.

Fixes the bug portion of #688
2026-03-16 16:02:54 -04:00
TÂCHES
07effd64cc Merge pull request #471 from Jamie-BitFlight/feat/claude-import-skills-plugins
feat: import Claude marketplace plugins with namespaced components
2026-03-16 13:32:09 -06:00
TÂCHES
0112a0f390 Merge pull request #680 from trek-e/fix/658-warp-cursor-visibility
fix: auto-enable hardware cursor in Warp terminal (#658)
2026-03-16 13:20:37 -06:00
Tom Boucher
d862c43424 fix: auto-enable hardware cursor in Warp terminal (#658)
Warp terminal does not correctly re-render inverse video (\x1b[7m)
cursor indicators on arrow key movement, making the cursor appear
invisible when navigating with arrow keys.

Auto-detect Warp via TERM_PROGRAM=WarpTerminal and enable the hardware
cursor by default (same as PI_HARDWARE_CURSOR=1). The hardware cursor
is positioned correctly via CURSOR_MARKER and provides reliable visual
feedback in Warp.

Terminals that render inverse video correctly (iTerm2, Terminal.app)
are unaffected — they continue using the fake cursor by default.
2026-03-16 15:11:58 -04:00
Tom Boucher
0ced559044 fix: remove CSI 3J scrollback clear from TUI full redraws (#455)
During full redraws, the TUI emitted \x1b[3J (clear scrollback) before
\x1b[2J\x1b[H (clear screen + home). In terminals like Ubuntu Terminal
that honor CSI 3J, this destroyed the scrollback buffer and caused the
scrollbar/view position to jump to the top during phase transitions.

Replace with just \x1b[2J\x1b[H which clears the visible screen and
homes the cursor without touching scrollback history. This preserves
view continuity while still performing a clean redraw.
2026-03-16 15:11:11 -04:00
Jamie McGregor Nelson
d4cf95f204 fix: type errors in claude-import.ts and marketplace-discovery.ts 2026-03-16 14:46:31 -04:00
TÂCHES
a90aa0c8d6 Merge pull request #666 from jeremymcs/fix/v2.19.0-phase1-quick-wins
fix: v2.20 Phase 1+2 — bugs, security, performance, code quality
2026-03-16 12:44:17 -06:00
Jeremy McSpadden
d41338cafb refactor: extract inline build scripts from package.json to files
- Extract copy-resources, copy-themes, copy-export-html from root
  package.json inline node -e commands to proper .cjs script files
- Extract pi-coding-agent copy-assets (356-char inline command) to
  scripts/copy-assets.cjs with readable multi-line formatting
- All scripts use .cjs extension for CommonJS compatibility in ESM
  package context
2026-03-16 13:34:05 -05:00
Jeremy McSpadden
4af3e5b741 fix: move @types/mime-types to devDependencies, align chalk versions
- Move @types/mime-types from dependencies to devDependencies in pi-tui
  (type declarations are only needed at compile time)
- Align chalk version: upgrade root from ^5.5.0 to ^5.6.2 to match
  pi-ai and avoid version skew
2026-03-16 13:31:15 -05:00
Lex Christopherson
a58e256e42 fix: resolve 4 small issues reported in #663
1. Windows: `start` command opens CMD instead of browser during GitHub
   Copilot login — pass empty title arg so URL is treated as target
2. Launch banner missing Tavily provider in web search status display
3. MCPorter auto-installs via npm when not found (like ripgrep auto-download)
4. Notification prefs showing [object Object] — guard against non-boolean values

Closes #663

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:23:20 -06:00
Jeremy McSpadden
2c926c12e3 fix: Phase 1 quick wins — bug fixes, security hardening, and performance
- Fix loadStoredEnvKeys divergent provider lists: add telegram_bot and
  custom-openai to wizard.ts (the canonical copy used by CLI), remove
  dead duplicate from onboarding.ts
- Security: add SAFE_COMMAND_PREFIXES allowlist to resolveConfigValue
  to prevent arbitrary RCE via settings.json shell commands
- Security: add TOFU (Trust On First Use) model for project-local
  extensions — skip untrusted .pi/extensions/ with stderr warning
- Performance: debounce sql.js MemoryStorage persistence (500ms window)
  so rapid mutations coalesce into a single db.export()+writeFileSync
- Fix double lstatSync call in tool-bootstrap.ts isRegularFile
- Add 26 new tests covering all changes
2026-03-16 13:18:02 -05:00
Tom Boucher
cdf42fe001 fix: prevent model config bleed between concurrent GSD instances (#650) (#652)
Two fixes for the model configuration bleeding between simultaneous
GSD instances that share the same global settings.json.

## Root Cause

1. `setDefaultModelAndProvider()` always persisted to `~/.gsd/agent/settings.json`
   (global), so when either instance's interactive mode changed models (via
   Ctrl+P or /model), it overwrote the other instance's saved default.

2. When auto-mode dispatched a new unit (after context wipe), if no
   per-unit-type model preference was configured, the session picked up
   the default from the now-contaminated global settings file.

## Fix 1: Project-scoped model persistence (settings-manager.ts)

`setDefaultModelAndProvider()`, `setDefaultModel()`, and `setDefaultProvider()`
now persist to project-level settings (`.pi/settings.json`) when a project
settings file exists, falling back to global only when no project context
is available. This prevents concurrent instances from overwriting each
other's model choice.

Added `hasProjectSettingsFile()` helper to detect project context.

## Fix 2: Auto-mode model capture (auto.ts)

Captures the session's model at auto-mode start (`autoModeStartModel`).
At each unit dispatch, if no model preference is configured for the unit
type, the captured model is re-applied with `persist: false`. This
ensures each auto-mode session maintains its own model regardless of
what other instances write to the shared settings file.

## Tests

3 new tests covering:
- Project settings file isolates model from global
- Two projects have independent model configs
- autoModeStartModel concept prevents model drift

All 448 existing tests pass.

Fixes #650
2026-03-16 10:59:12 -06:00
Jamie McGregor Nelson
526fa7439d fix: add missing type declarations for typecheck
- Add @smithy/node-http-handler to pi-ai
- Add @types/proper-lockfile, @types/hosted-git-info, @types/sql.js to pi-coding-agent
- These were causing typecheck:extensions to fail due to missing type declarations
2026-03-16 12:29:45 -04:00
Tom Boucher
75e82a4236 fix(session): rebuild tools when cwd changes in newSession (#633) (#638)
Tools (write, read, edit, bash) capture cwd at creation time via
createWriteTool(cwd), createReadTool(cwd), etc. When auto-mode
enters a worktree, process.cwd() changes but tools were not
recreated — they continued resolving relative paths against the
original project root.

This caused artifacts to be written to the main project's .gsd/
directory instead of the worktree's .gsd/ directory. The dispatcher
then couldn't find the artifact at the expected worktree path and
retried the unit indefinitely.

Fix: detect cwd change in newSession() and call _buildRuntime()
to recreate tools with the updated cwd. This is a targeted rebuild
that only fires when cwd actually changed (typically once per
auto-mode session when entering/exiting a worktree).

Fixes #633
2026-03-16 09:23:19 -06:00
TÂCHES
fd29c02c81 feat(lsp): activate LSP by default, add call hierarchy/format/signature, sync edits (#639)
LSP was never activated in interactive sessions because the default
active tools list hardcoded only read/bash/edit/write. This adds lsp
to that list and ships four new capabilities alongside edit sync and
stronger prompt guidance.

- Add "lsp" to default active tools in agent-session.ts
- New actions: incoming_calls, outgoing_calls, format, signature
- Wire edit/write tools to notify LSP clients on file changes
- Strengthen system prompt and GSD prompt with full LSP operation catalog

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:22:52 -06:00
Gary Trakhman
1ea9163dea feat: add yaml support, run-hook command, and path sanitization (#637)
* feat: allow extensions to use 'yaml' and rework frontmatter parsing

* feat: add run-hook command for manual hook execution

* fix: sanitize slashes in unitType for runtime file paths
2026-03-16 09:22:23 -06:00
Flux Labs
9ed812ed54 feat: dynamic model discovery & provider management UX (#581) 2026-03-16 06:23:18 -06:00
Flux Labs
d35ae683f1 Fix #453 native hangs in GSD auto-mode paths (#502)
* fix: avoid native hangs in gsd auto paths

* fix: use .js extension in edit-diff.test.ts import for tsc compatibility

* fix: prevent OOM on large file diffs and implement context-line windowing

- Add size guard (MAX_DP_CELLS=4M) to buildLineDiff that falls back to a
  linear-time prefix/suffix matching algorithm for large files, preventing
  the O(n*m) DP table from causing OOM crashes
- Implement contextLines parameter in generateDiffString so only lines
  within N lines of a change are rendered (with "..." separators), matching
  unified diff behavior — the parameter was previously accepted but ignored
- Add tests for both context windowing and large-file fallback

---------

Co-authored-by: TÂCHES <afromanguy@me.com>
2026-03-15 22:22:58 -06:00