Skip to content

fix(terminal): retry with execa when shell integration loses command - #2

Closed
myk1yt wants to merge 41 commits into
mainfrom
fix/terminal-execa-retry
Closed

myk1yt wants to merge 41 commits into
mainfrom
fix/terminal-execa-retry

Conversation

@myk1yt

@myk1yt myk1yt commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

When shell integration loses a command (issues Zoo-Code-Org#779, Zoo-Code-Org#705, Zoo-Code-Org#634), the terminal would silently fail. This PR adds a fallback mechanism: retry the command using execa when shell integration loses it.

Context

This is part of a split from the large feature/local-usage-stats PR (43 commits, 138 files). This terminal fix is completely independent of the stats feature.

Split plan: C → A → B → D (this is PR A)

Changes

  • src/core/tools/ExecuteCommandTool.ts: Add execa retry fallback when shell integration loses command output
  • src/core/tools/__tests__/executeCommandTool.spec.ts: Add test coverage for the retry behavior
  • src/integrations/terminal/TerminalProcess.ts: Adjust terminal process to support the retry mechanism
  • apps/vscode-e2e/src/fixtures/terminal-reuse-shell-race.ts: Fix fixture re-match loop

Fixes

morgan-coded and others added 30 commits July 19, 2026 13:40
…hLock (Zoo-Code-Org#912)

* fix: lock task history invalidation

* fix(task-history): address invalidation review feedback
…#961) (Zoo-Code-Org#962)

checkExistKey ignored Zoo Gateway session auth, so Finish saved config but never left the setup screen.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Roomote <roomote@roomote.dev>
DeepSeek V4 Pro and V4 Flash support image inputs via their OpenAI-compatible
API, but the model definitions had supportsImages: false. This change flips it
to true for both models, enabling users to attach images when using these models.
…treaming, and model metadata (Zoo-Code-Org#857)

* fix(moonshot): fix provider issues with model picker, refresh, and streaming

- Fix duplicate ModelPicker by adding moonshot to PROVIDERS_WITH_CUSTOM_MODEL_UI
- Fix HTTP 404 on Refresh Models by preserving /v1 in fetcher URL
- Fix empty model list (consequence of 404 fix)
- Fix 'No output generated' error by switching MoonshotHandler from
  OpenAICompatibleHandler (Vercel AI SDK) to OpenAiHandler (OpenAI Node SDK)
  which is what Moonshot's own API docs recommend
- Add dedicated Moonshot fetcher with proper model ID prefixing
- Update tests to match new handler implementation

All 6,660 backend and 1,432 webview-ui tests pass.

* feat(moonshot): add missing models with correct pricing from official docs

Add kimi-k2.7-code, kimi-k2.7-code-highspeed, and kimi-k2.6 to static
models map with accurate pricing from Moonshot documentation.

Also fix kimi-k2.5 to correctly mark supportsImages: true.

* Update webview-ui/src/components/settings/providers/Moonshot.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix(moonshot): remove fallback pricing for unknown models to match handler behavior

* Bump coverage

* fix(moonshot): address PR review feedback — add tests and fix inline import type

- Replace inline import() type with top-level OpenAI.Chat.Completions.X in moonshot.ts
- Add useSelectedModel moonshot tests (default model, router override, unknown fallback, getValidatedModelId)
- Add modelCache moonshot dispatch test for fetchModelsFromProvider switch
- Create Moonshot.spec.tsx with state machine tests (idle/loading/success/error states, race condition guard)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Roomote <roomote@roomote.dev>
…milies (Zoo-Code-Org#899)

* fix(litellm): preserve reasoning_content for known reasoning model families

LiteLLM's /v1/model/info never reports reasoning capability flags, so infer
preserveReasoning from the model alias/routed-model name and use
convertToR1Format to keep reasoning_content intact across tool-call turns.

Signed-off-by: daewoongoh <dw.oh@samsung.com>

* test(litellm): cover preserveReasoning inference and message conversion branching

Add unit coverage for LITELLM_PRESERVE_REASONING_PATTERN matching per model
family, getLiteLLMModels setting preserveReasoning on matched models, and
LiteLLMHandler.createMessage branching between convertToR1Format and
convertToOpenAiMessages based on info.preserveReasoning.

Signed-off-by: daewoongoh <dw.oh@samsung.com>

* refactor(litellm): replace preserveReasoning regex with an explicit model id list

Regex-based family matching could over-match unrelated aliases sharing a
substring (e.g. glm-5-flash matching a glm-5 prefix), a gap flagged in
PR Zoo-Code-Org#899 review. LITELLM_PRESERVE_REASONING_MODEL_IDS now lists the exact
model ids that set preserveReasoning: true in their native provider
config, matched via isLiteLLMPreserveReasoningModel() against the final
segment of model_name/litellm_params.model.

Also fixes a test in litellm.spec.ts where the model_name alias itself
matched a known id, so the assertion didn't actually prove
litellm_params.model was being checked.

Signed-off-by: daewoongoh <dw.oh@samsung.com>

---------

Signed-off-by: daewoongoh <dw.oh@samsung.com>
)

* chore(deps): update dependency esbuild-wasm to v0.28.1

* fix(build): eagerly initialize stdout/stderr in esbuild-wasm to prevent V8 crash

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Elliott de Launay <edelaunay@wealthsimple.com>
…ode-Org#925)

* fix(webview): sync cachedState on mode changes in SettingsView

* test(settings): strengthen mode sync change detection

---------

Co-authored-by: Eason Liang <easonliang28@gmail.com>
* fix(code-index): index plain text files

* fix(tree-sitter): skip plain text definition parsing

* fix(code-index): address plain text review feedback

* fix(tree-sitter): preserve Scala structural parsing

* test(code-index): remove redundant async usage
)

* fix(mcp): remove obsolete server creation translations

* test(mcp): remove stale server creation references

* test(mcp): fix no-server prompt snapshot
… and surface delegation status (Zoo-Code-Org#935)

* feat(task-lifecycle): explicit interrupted status + delegation state machine

* feat(history-ui): delegation status badges in history list

* fix(ci): add dedicated fixtures for abandon e2e test and add missing i18n keys

* test: cover evictCurrentTask, markDelegatedChildInterrupted, and onTaskCompleted paths

* fix: address CodeRabbit review - guard active-only in markDelegatedChildInterrupted, evict on disposal, fix delegateParentAndOpenChild TOCTOU, translate i18n keys

* fix(e2e): allow parent status to be active or completed after child delegation

---------

Co-authored-by: Naved  Merchant <naved.merchant@gmail.com>
…o-Code-Org#989)

* refactor(types): use canonical provider category identifiers

* test(types): cover cross-category provider guards
…ode-Org#996)

* feat(types): add Kimi K3 to moonshot and opencode-go providers

* test(types): add moonshot registry suite and explicit kimi-k3 reasoning assertions

* test(types): widen moonshot registry entries to ModelInfo in tests

---------

Co-authored-by: Roomote <roomote@roomote.dev>
* feat: add Kimi Code provider

* no-mistakes(review): add explicit error handling for OAuth retry path

* no-mistakes(document): Fix incorrect provider attribution in OAuth comment

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* fix(kimi-code): harden OAuth request handling

* feat(kimi-code): add configurable reasoning effort (low/high/max)

* fix(kimi-code): address review feedback and resolve main merge conflicts

- Wrap kimiCodeOAuthState aggregation in try/catch in ClineProvider
- Add non-401 OAuth no-retry test for createMessage
- Add vi.resetModules() to kimiCode sign-in/out spec setup
- Localize kimiCode settings strings in 9 locales
- Merge origin/main: adopt canonical providerIdentifiers registry,
  keep both kimi-code and zoo-gateway setup-gate checks

---------

Co-authored-by: Toray Altas <6816042+taltas@users.noreply.github.com>
Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Naved  Merchant <naved.merchant@gmail.com>
…GPT OAuth (Zoo-Code-Org#889)

* fix(openai-codex): support Luna Responses Lite requests

* Nuke md file that shouldnt have been commited in the first place

* fix(openai-codex): address Luna Responses Lite review feedback

- Capture telemetry when transformLunaResponsesLiteBody throws in createMessage
- Drop weak Record<string, any> alias from transformLunaResponsesLiteBody signature
- Document intentional tool_choice/parallel_tool_calls and reasoning context overrides
- Strengthen tests: full input array assertion, reasoning context overwrite case,
  retry header coverage, single-build spy, and uuidv7 session shape check

---------

Co-authored-by: Naved  Merchant <naved.merchant@gmail.com>
Co-authored-by: Roomote <roomote@roomote.dev>
* feat(tree-sitter): add Dart definition support

* fix(tree-sitter): address Dart query review feedback

* fix(tree-sitter): include adjacent Dart function bodies

---------

Co-authored-by: Naved  Merchant <naved.merchant@gmail.com>
…Org#1010)

Add full Claude Opus 5 support across all provider paths with correct
model definitions, adaptive-thinking handling, fetcher overrides, and
accurate pricing from Anthropic's published docs.

Model definitions (anthropic.ts, bedrock.ts, vertex.ts):
- 1M native context window (no beta header required)
- Adaptive-thinking binary toggle (supportsReasoningBudget/Binary)
- supportsTemperature: false (sampling params return a 400)
- Pricing: input $5.0, output $25.0, cacheWrites $6.25, cacheReads $0.50
  per million tokens

Provider handling:
- Add opus-5 to the Bedrock adaptive-thinking guard
- Add claude-opus-5 to OpenRouter and Vercel AI Gateway allow-lists
- Apply Opus 5 overrides (maxTokens, reasoning budget, temperature)
  in the openrouter, requesty, and vercel-ai-gateway fetchers

Tests:
- Add Opus 5 coverage across provider and fetcher test suites

Co-authored-by: Naved Merchant <14171946+navedmerchant@users.noreply.github.com>
* chore: prepare v3.72.0 release

* fix: address v3.72.0 release review

* Update README.md

* Update README.md

---------

Co-authored-by: edelauna <54631123+edelauna@users.noreply.github.com>
… child fixture (Zoo-Code-Org#1002)

* test(e2e-mock): fix subtasks fixture collision between child and parent-resume fixtures (Zoo-Code-Org#1001)

The fast-child and SUBTASK_CHILD fixtures matched a bare marker that the
parent prompt embeds verbatim, so parent-resume turns could be served the
child fixture (mirrors Zoo-Code-Org#561, which fixed the same class for cross-profile
fixtures only). Parent-resume fixtures also guarded on the literal new_task
tool-call id, which validateAndFixToolResultIds can rewrite on resume.

- Add parent-marker exclusion (with aimock's last-user-message scoping) to
  the fast-child and SUBTASK_CHILD fixtures
- Guard parent-resume fixtures on the injected subtask result content
  instead of the fragile tool-call id

* test(e2e-mock): address PR review — injection-guard all parent fixtures, link fixture format contract

- Regular parent turn-1 fixture: exclude resume turns via
  SUBTASK_RESULT_INJECTION instead of relying on registration order
  (sequenceIndex is not viable here — the fixture is shared by 4 tests)
- Fast and api-hang parent-resume guards: match SUBTASK_RESULT_INJECTION
  instead of the child result text, which is embedded verbatim in the
  parent prompts and could match the parent's initial request on retry
- Add unit-test assertion pinning reopenParentFromDelegation's injected
  tool_result format to the 'completed.\n\nResult:' contract the e2e
  fixtures match on
- lastUserMessageContains: mirror aimock's getTextContent (text parts
  only) instead of JSON.stringify for non-string content
- Extract SUBTASK_FAST_CHILD_RESULT constant
- Replace tautological find()/assert pairs in the api-hang test
- Move the no-parent-resume assertion in the cancellation test behind
  the async settle gates and also assert no completion_result

---------

Co-authored-by: Roomote <roomote@roomote.dev>
…Zoo-Code-Org#872)

* fix(settings): buffer Save-managed settings in cachedState until Save

Several controls inside SettingsView wrote their changes to the extension host immediately via `updateSettings`, instead of buffering them in local `cachedState` and waiting for the user to click Save.
Because Discard reverts edits by resetting `cachedState` to the persisted state, any control that already posted `updateSettings` poisoned that source of truth — so Discard could no longer undo the change, silently breaking the Save/Discard contract.

Route all five Save-managed values exclusively through `cachedState` / `setCachedStateField` while SettingsView is open:

- allowedCommands / deniedCommands (AutoApproveSettings): drop the   immediate updateSettings on add/remove.
- profileThresholds (ContextManagementSettings): drop the immediate updateSettings on the non-default profile branch; remove the now-unused vscode import.
- includeTaskHistoryInEnhance (PromptsSettings): drop the immediate updateSettings on toggle.
- mcpEnabled (McpEnabledToggle / McpView): adopt the existing "props first, fall back to context" pattern so SettingsView can pass the buffered value and a cachedState-backed setter; uncontrolled usage keeps the original immediate behavior.

Genuinely-immediate actions (autoApprovalEnabled, per-server MCP toggle/delete/restart/timeout) are not in the Save payload and are left unchanged. The extension host side is correct and untouched.

Add/update tests at the webview-ui component layer: buffering assertions for each control, a McpEnabledToggle controlled/uncontrolled regression, and a SettingsView Discard regression.

Signed-off-by: JunyongParkDev <jun94.park@samsung.com>

* test(settings): cover buffered MCP enablement

* test(settings): verify discarded commands are reverted in UI

Strengthen the SettingsView regression test to verify that buffered
commands disappear from the UI when changes are discarded.

Signed-off-by: JunyongParkDev <jun94.park@samsung.com>

* fix(settings): restore immediate persistence for uncontrolled includeTaskHistoryInEnhance

The previous Save-buffering change dropped the updateSettings post unconditionally, which fixed the controlled path but broke the uncontrolled one:
with props omitted the toggle falls back to the context setter, which only updates local state and never persists.

Gate the post on whether the component is controlled:
- Controlled: setter buffers into cachedState, Save persists — no post here.
- Uncontrolled: context setter is local-only, so post updateSettings now.

Mirrors the props-first / context-fallback pattern used for McpEnabledToggle.
Adds an uncontrolled regression test (updates local state *and* posts), symmetric with the controlled "buffer only" case.

Signed-off-by: JunyongParkDev <jun94.park@samsung.com>

---------

Signed-off-by: JunyongParkDev <jun94.park@samsung.com>
… form-edited base URL (Zoo-Code-Org#878)

* ollama fetch fix

* address review comments
…g#906)

* Fix bedrock DNS resolution when behind a corporate proxy

When behind a corporate proxy, Node.js resolves DNS locally before contacting
the proxy. If the proxy is the only path to the endpoint, the request fails
with ENOTFOUND.

HttpsProxyAgent uses CONNECT tunneling so the proxy handles DNS resolution.
Configure NodeHttpHandler with HttpsProxyAgent when a system proxy is detected.

* test: add coverage for getSystemProxyUrl function

* fix: honor NO_PROXY, support http proxy, trim proxy env vars
* chore(deps): update node.js to v24

* chore(deps): target node 22 lts

* chore: downgrade Node to 22 LTS to fix Windows CI crash

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Elliott de Launay <edelauna@gmail.com>
Zoo-Code-Org#968)

The Architect mode custom instructions ended with 'put it in the /plans
directory', which models interpreted as an absolute filesystem path,
causing 'EROFS: read-only file system, mkdir /plans' when saving plan
files. Reword to './plans' and clarify it is relative to the workspace
root.

Fixes Zoo-Code-Org#965

Co-authored-by: Toray Altas <6816042+taltas@users.noreply.github.com>
…o-Code-Org#1014)

* feat(TaskRegistry): introduce TaskRegistry and migrate clineStack

* refactor(tests): replace `as any` casts with bracket notation for private member access

* chore(eslint): enforce no-explicit-any with bulk suppressions for existing violations

* docs(TaskRegistry): push method

* fixup! chore(eslint): enforce no-explicit-any with bulk suppressions for existing violations
…Code-Org#986)

* chore(deps): update dependency shell-quote to v1.9.0 [security]

* chore(deps): remove obsolete shell-quote types

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…#526)

* test(webview): add visual regression harness

* fix(webview): resolve relative compose path & font race in visual tests

* test(webview): configure Codecov JSDOM coverage ratcheting

* feat(webview): add Playwright CT coverage ratcheting

* fix(webview): swap visual regression target off deprecated toolkit

* chore(webview): address CodeRabbit review feedback

* fix(webview): emit Playwright CT coverage LCOV

* fix(webview): address code review feedback for Playwright CT harness

* docs: prefer committed visual snapshots; split videos into their own lane

* revert(RooHero): removing on hover test - can't make it deterministic
WebMad and others added 9 commits July 26, 2026 12:21
* refactor(api): use canonical provider identifiers

* test(api): cover canonical provider routing

* test(api): enforce exhaustive provider routing

* test(api): avoid concrete Vertex model IDs
…de-Org#991)

* refactor(types): use canonical identifiers for default models

* test(types): cover international ZAI default

* refactor(types): name absent provider default

* test(types): cover defaults preserved during rebase

* test(types): document identical Zai defaults
…de-Org#1020)

* refactor(api): use canonical model cache provider identifiers

* test(api): address model cache review feedback

* refactor(api): retain auth-scoped provider set

---------

Co-authored-by: edelauna <54631123+edelauna@users.noreply.github.com>
…e-Org#1019)

* refactor(shared): use canonical profile provider identifiers

* test(shared): strengthen profile validator coverage

* test(shared): avoid mutating provider identifiers

* chore(lint): prune profile validator suppressions
* refactor(core): use canonical provider identifiers

* test(core): tighten canonical provider coverage

* test(core): avoid mutating provider identifiers

* test(core): address canonical identifier review feedback

* chore(lint): update test suppression counts

* test(core): keep existing non-null assertions
…oo-Code-Org#1024) (Zoo-Code-Org#1032)

* fix(ripgrep): resolve platform-specific binary for @vscode/ripgrep >=1.18

* fix(environment): gracefully handle ripgrep not found during file listing

* fix(ripgrep): use npm_config_arch for platform-package resolution

* refactor(ripgrep): replace createRequire resolver with static candidate paths

* fix(ripgrep): evaluate npm_config_arch at call time in candidate paths

---------

Co-authored-by: Naved  Merchant <naved.merchant@gmail.com>
When shell integration fails with commandSubmitted=true (command was
submitted but output tracking was lost), silently retry with execa
fallback instead of showing a dead-end error to the user.

Issues: Zoo-Code-Org#779, Zoo-Code-Org#705, Zoo-Code-Org#634
@myk1yt myk1yt closed this Jul 27, 2026
@myk1yt
myk1yt deleted the fix/terminal-execa-retry branch August 7, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Allow users to select and configure the execution shell for the inline terminal