Commit graph

152 commits

Author SHA1 Message Date
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
Andriyansyah Nurrachman
132ae92944 feat: update ollama cloud provider models (#578) 2026-03-15 22:22:29 -06:00
Mannan Kant
96f5b58bd3 fix(pi-ai): address review comments on #504 — exhaustive switch, tests, cleanup (#587)
- Restore exhaustive never check in mapStopReason (throw on unhandled FinishReason)
- Add 12 unit tests for sanitizeSchemaForGoogle covering patternProperties removal,
  const→enum conversion at various depths, arrays, deeply nested objects, pass-through
- Simplify redundant recursion branches into single typeof object catch-all
- Fix misleading comment ("only in anyOf/oneOf") — conversion happens everywhere
- Drop unnecessary (p: Part) annotation; TypeScript infers it from @google/genai types

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 22:21:20 -06:00
78slogs
6d84d1c317 fix: arrow key cursor not updating + Shift+Enter not inserting newlines (#485)
Fix two editor input bugs:

1. Arrow key cursor movement not visually updating (fixes #464)
   The layout cache key only included {width, textVersion}. Cursor-only
   moves don't change textVersion, so stale cached layout was returned
   and the diff renderer skipped repaint. Added cursorLine and cursorCol
   to the cache key so cursor movements invalidate the cache.

2. Shift+Enter not inserting newlines in non-kitty terminals (Zed, VS Code, etc.)
   The /terminal-setup command configures terminals to send ESC+CR (\x1b\r)
   for Shift+Enter. But the followUp app action (bound to alt+enter) was
   intercepting \x1b\r in CustomEditor.handleInput before the editor's
   newLine handler could see it — because in non-kitty terminals, \x1b\r
   matches alt+enter. Now when kitty protocol is not active and \x1b\r is
   received, the followUp match is skipped so it falls through to newLine.
   Alt+Enter followUp still works in kitty-protocol terminals (iTerm2,
   Ghostty, Kitty, WezTerm) where the key combos are distinguishable.

Co-authored-by: TÂCHES <afromanguy@me.com>
2026-03-15 19:47:49 -06:00
TÂCHES
7578292b6b fix: resolve TypeScript errors in GSD extension files (#571)
Add "success" to notify type union across ExtensionUIContext, interactive
mode, and RPC mode implementations. Fix null safety for readFileSync and
contextUsage.percent in auto.ts. Add discriminated union narrowing for
dispatch results. Add string type guards for select() return values in
commands.ts. Align ProviderErrorPauseUI notify signature. Simplify
AuthStorage return type.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:12:23 -06:00
Flux Labs
c20c57b941 feat: default to Opus 4.6 1M context variant (#565) 2026-03-15 18:57:46 -06:00
Mannan Kant
611cd0f508 copilot fix for https://github.com/gsd-build/gsd-2/issues/496 (#504) 2026-03-15 18:19:41 -06:00
TÂCHES
ee355b52d1 Merge pull request #482 from fluxlabs/fix/tui-resource-leaks-and-quality
fix: TUI resource leaks, code quality, and regression tests
2026-03-15 17:32:31 -06:00
TÂCHES
946fce4ee6 Merge pull request #532 from fluxlabs/fix/arrow-keys-escape-sequence-splitting-493
fix: prevent arrow keys from inserting escape sequences as text
2026-03-15 17:18:00 -06:00
TÂCHES
bc4d4fcf48 perf: fix synchronous I/O in hot paths (#540)
Replace existsSync collision loop with atomic O_CREAT|O_EXCL file
creation, hoist regex to module-level constant, and memoize
getPackageDir() to avoid repeated directory walks.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 16:57:22 -06:00
TÂCHES
97eec7a33f Merge branch 'main' into fix/tui-resource-leaks-and-quality 2026-03-15 16:46:54 -06:00
TÂCHES
5493fe07fa Merge branch 'main' into fix/arrow-keys-escape-sequence-splitting-493 2026-03-15 16:40:22 -06:00
Flux Labs
8913aea968 fix: prevent arrow keys from inserting escape sequences as text (#493)
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
2026-03-15 17:17:58 -05:00
TÂCHES
8882ce484e fix(session): update cwd on newSession to reflect worktree chdir (#517)
When auto-mode creates a worktree and chdir's into it, the Node process
cwd changes but AgentSession._cwd stays frozen at the original path.
Every newSession() builds a system prompt telling the LLM "Current
working directory: /original/path", so the LLM cd's back there and
writes files to the wrong location.

Update _cwd = process.cwd() at the start of newSession() so the system
prompt reflects the actual working directory after chdir.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 15:45:15 -06:00
TÂCHES
f844635de0 Merge branch 'main' into fix/tui-resource-leaks-and-quality 2026-03-15 13:45:04 -06:00
Flux Labs
e6d55f8aaf Perf/gsd startup speed (#497)
* docs: add startup performance analysis and optimization plan

Profiled GSD CLI startup finding 2.2s for --version and ~3.8s for
interactive mode. Identified 5 root causes with measured timings and
created a phased optimization plan targeting <0.2s for --version
and ~0.8s for interactive startup.

* perf: speed up GSD startup with lazy loading and fast paths

- Fast-path --version/-v and --help/-h in loader.ts before importing
  any heavy dependencies (2.2s → 0.15s, 14x faster)
- Lazy-load undici (~200ms) only when HTTP_PROXY env vars are set
- Skip initResources cpSync when managed-resources.json version
  matches current GSD version (~128ms saved per launch)
- Lazy-load Mistral SDK (~369ms) on first API call instead of startup
- Lazy-load Google GenAI SDK (~186ms) on first API call instead of
  startup
- Parallelize extension loading with Promise.all() instead of
  sequential for-loop

---------

Co-authored-by: TÂCHES <afromanguy@me.com>
2026-03-15 13:33:43 -06:00
Flux Labs
4a76d7b174 Merge branch 'main' into fix/tui-resource-leaks-and-quality 2026-03-15 11:39:52 -05:00
TÂCHES
c0ab967f35 Merge pull request #457 from deseltrus/fix/skill-diagnostics-ux
fix(ux): improve preferences wizard and skill diagnostics
2026-03-15 09:53:46 -06:00
Flux Labs
ea2b626c98 test(pi-tui): add regression tests for loader, cancellable-loader, input
First test coverage for pi-tui components (8 tests):
- Loader: start() idempotency, dispose() cleanup, stop() safety
- CancellableLoader: abort on dispose, callback cleanup, signal state
- Input: paste buffer reset on focus loss, focused getter/setter
2026-03-15 09:56:50 -05:00
Flux Labs
ea2efe804f fix(pi-tui): patch 5 resource leak bugs in TUI components
- Loader: clear existing interval in start() to prevent orphaned timers
  on double-call; add dispose() to stop and null TUI ref
- CancellableLoader: abort the AbortController and clear onAbort in
  dispose() so external signal holders release the controller
- Editor: add public dispose() that clears the autocomplete debounce
  timer to prevent post-removal callbacks
- Input: convert focused to getter/setter that resets isInPaste and
  pasteBuffer on focus loss, preventing paste state corruption
- TUI.stop(): iterate overlayStack calling dispose() on each component
  before clearing, stopping overlay timers (e.g. dashboard refresh)
2026-03-15 09:56:36 -05:00
Lex Christopherson
34cd1056ea feat(M003/S05): Self-healing git repair
Tasks:
- chore(M003/S05): auto-commit after complete-slice
- docs: tighten GSD system prompt tool-routing — prescriptive rules + anti-patterns
- chore(M003/S05/T02): auto-commit after execute-task
- chore(M003/S05/T01): auto-commit after execute-task
- chore(M003/S05): auto-commit after plan-slice
- docs(S05): add slice plan

Branch: gsd/M003/S05
2026-03-15 08:33:13 -06:00
Lex Christopherson
4ec30cdc2d chore(M003/S04): auto-commit after reassess-roadmap 2026-03-15 08:33:13 -06:00
deseltrus
b97a47db42 feat(tui): add placeholder support to Input component
The Input component had no placeholder text support — when empty, it
showed only "> " with a blinking cursor and no hint of expected input.

The ExtensionInputComponent received a placeholder parameter but
discarded it (_placeholder with underscore = intentionally unused).

Fix: Input now has a public placeholder property. When value is empty,
renders the placeholder in dim text. ExtensionInputComponent passes
the placeholder through to Input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 07:23:59 +01:00
deseltrus
0c9cbf6b4c fix(ux): differentiate skill diagnostics and improve prefs discoverability
Split skill diagnostics into [Skill conflicts] (actual collisions) and
[Skill issues] (validation warnings like missing description) so users
aren't misled by the label. Add wizard hint to /gsd prefs output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 06:54:11 +01:00
Flux Labs
3bfa444809 fix: debounce @ file autocomplete to prevent TUI freeze on large codebases (#448) (#452)
The synchronous fuzzyFind() native call blocks the event loop during
@ file autocomplete. On large codebases (e.g. Java projects with deep
directory trees), each call can take seconds. Since updateAutocomplete()
was called on every keystroke while autocomplete was active, rapid typing
would cascade into dozens of blocking searches — freezing the TUI for
minutes. This made it appear that arrow keys caused the freeze, when
the actual cause was accumulated backlog from processing buffered input.

Debounce all @ file reference autocomplete paths (character input,
backspace, forward delete, and re-trigger after cancellation) with a
150ms delay so only the final keystroke triggers the expensive search.
Slash command autocomplete remains synchronous since it's cheap.

Co-authored-by: TÂCHES <afromanguy@me.com>
2026-03-14 23:45:05 -06:00