Tested the shell-control guard against the raw command: whitespace
normalization collapsed newlines/CR before the guard ran, so
'git status\nrm file.txt' rode a 'git *' allow rule while bash executed
both lines. Honored tool-owned allow/prompt policies in yolo mode so
per-command prompt rules were no longer silently discarded under the
default approvalMode. Added precision regression tests through the real
matcher (separators, subshells, redirects, env prefixes, path/quoting
variants) that fail on the unfixed head.
clampTimeout resolved the per-tool default (bash 300s) whenever the agent
omitted `timeout` and only enforced the tool's own min/max, so the
tools.maxTimeout global ceiling — applied solely in sdk.ts on explicitly
numeric args — was bypassed on the common default-fallback path.
Thread maxTimeout into clampTimeout so the resolved effective timeout,
including the default path, is capped before the per-tool floor/ceiling
apply. Explicit values below the cap still win; maxTimeout <= 0 stays
no-cap. Applied at every call site (bash, eval, browser, debug, lsp,
fetch, and the session-level bash executor), and the bash clamp notice
now names the global ceiling when it is the binding limit.
Fixes#6294
Three-piece architecture so subagents inherit async.enabled and
bash.autoBackground.enabled instead of having both force-disabled:
- Owner-routed delivery: AsyncJobManager gains registerDeliverySink /
waitForOwnerJobs; every AgentSession registers a sink for its own agent
id, so background job results inject into the owning agent's run.
Owned deliveries with no live sink dead-letter (result retained on the
job row) instead of misrouting into the first top-level session.
- Quiescence barrier: a subagent's final yield with owner jobs still
running/undelivered is a scheduling pause, not completion. The run
driver notifies the model once (hub wait/cancel), settles owner work,
and folds results in as async-result follow-ups; teardown cancels and
awaits surviving jobs before isolation worktree capture/cleanup.
- Steering soft channel: queued steering no longer hard-aborts
non-interruptible tools; it aborts interruptible waits and raises a
cooperative ToolCallContext.steeringSignal. The mid-batch watch runs
for every batch, and auto-backgroundable bash backgrounds itself on
steer so incoming messages inject promptly with no work lost.
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
Bash command timeouts now render with a warning (yellow) border instead
of an error (red) border, reflecting that the timeout ran its course
rather than the command failing.
The timeout is no longer thrown as a ToolError — instead #buildCompletedResult
returns a non-throwing error result (isError=true, keeping the model-facing
contract) with details.timedOut=true. The renderer reads this flag to pick
state="warning" (yellow) instead of state="error" (red).
The timedOut flag is propagated from bash-executor.ts, which now sets
timedOut=true on timeout return paths and leaves it unset on user-abort
paths. This distinguishes timeouts from user Esc-cancels — previously both
returned cancelled=true with no way to tell them apart in bash.ts.
- Changed daemon log reads to return both sanitized display text and a raw `terminalText` slice, and included it on log RPC responses for PTY runs when grep was not used.
- Extended the logs result contract and launch tool rendering to consume `terminalText`, reconstruct terminal output, and display it in framed, preview-capped sections.
- Kept terminal row layout stable by writing space characters for empty cells when reading rows, preserving spacing during output reconstruction.
- Added a configuration setting `launch.enabled` to control the availability of the project-scoped launch tool.
- Integrated the setting into the bash tool and tool registry to conditionally enable or disable the launch functionality.
- Updated documentation and settings schema to include the new toggle.
- Introduced a project-scoped `launch` tool to orchestrate long-running services, debuggers, and watchers with persistent execution capabilities.
- Implemented a robust daemon broker with Unix/Windows IPC transport that manages process lifecycles, readiness monitoring, and automatic log rotation.
- Added detached process support to ensure services persist independently of the main application lifecycle, including recovery and cleanup mechanisms.
- Updated the `bash` interceptor to prioritize the new `launch` tool for background processes and provided comprehensive documentation for lifecycle and signal handling.
- Stop propagating real-time updates for backgrounded Bash jobs to avoid UI flickering once a job enters the background.
- Refine background task tracking in `EventController` to distinguish between persistent background tasks and transient backgrounded Bash commands.
- Update UI rendering to display cleaner background job metadata in the footer instead of inline text notices.
Resolved file-backed memory://root URLs from the calling session cwd before falling back to the global registry.
Passed the caller cwd through bash internal-URL expansion so redirected memory paths cannot pick another live agent root.
Fixes#5079
The executeBash direnv preflight clamps its load budget to a positive
caller command timeout, but the PTY / ACP-terminal backend preflight in
bash.ts passed the raw bash.direnvLoadTimeoutMs (30s default) with no
clamp — so a short-timeout command routed through those backends could
hang up to 30s on a cold `.envrc` before its own timeout is even
installed. Centralize the clamp inside applyDirenvPreflight (new
callerTimeoutMs option) so every backend inherits one contract:
`timeout: 0`/undefined keeps the full budget, a positive deadline clamps.
Co-Authored-By: seal <noreply@sealedsecurity.com>
Extract applyDirenvPreflight() so the ACP client terminal and PTY backends
get the same direnv/devenv overlay as executeBash (previously only the
one-shot path did). The helper is a pure (command, env) transform — merge
direnv's set under the caller's overlay, prepend a regex-gated unset -v for
removed vars — so interactive backends keep their own env shape (live TERM)
while executeBash still layers its non-interactive defaults on top. The three
dispatch branches are mutually exclusive, so no command is preflighted twice.
Also drop the content-hash export cache in loadDirenvEnv: always run
direnv export json and let direnv's own watch/mtime invalidation decide
freshness, so a changed watched file re-exports even when .envrc is unchanged.
Co-Authored-By: seal <noreply@sealedsecurity.com>
Stop advertising eval in the default prompt and workflow notice when no eval
backend is enabled. Gate bash guidance on live eval backend availability and
cover the disabled-backend rendering contract.
Agent-Milestone: tooling: hide eval prompt guidance when eval backends are disabled
Signed-off-by: Christian Stewart <christian@aperture.us>
Treat timeout 0 as an explicit no-deadline contract across the bash tool, executor, async job, and PTY paths.
Signed-off-by: Christian Stewart <christian@aperture.us>
Removed the bash tool execution-path rewrite that stripped trailing head/tail pipeline stages before running commands.
Added regression coverage for short-reading final pipeline stages.
Fixes#4562
- Replaced commit-based stability checks with a unified `isTranscriptBlockFinalized` tracking mechanism.
- Removed deprecated provisional rendering configuration and flags across tool and renderer interfaces.
- Standardized native scrollback boundary logic to pin at the first unfinalized block using settled row verification.
- Updated and refactored test suites to validate block finalization and settled row boundaries instead of deprecated commit stability methods.
Documented the 1-3600 second bash timeout clamp in the schema, model-facing prompt, and tool docs, including the async timeout behavior.
Added coverage that the shipped schema and rendered prompt expose the contract.
Fixes#4408
Addresses codex review on #4335: the previous wrap dropped to cmd.exe on Windows, which broke bash tool semantics for $VAR, $(...), source, and POSIX quoting even when the local executor would have resolved Git Bash / bash.exe. The wrap now takes the resolved ShellConfig (shell binary + login/-c args + optional prefix) from settings.getShellConfig() and reuses it for the ACP terminal/create shape, so the ACP path matches the local path on both platforms. Tests updated to stub getShellConfig and assert the resolved-shell shape deterministically.
The bash tool routes commands through the ACP client's terminal/create when the client advertises the terminal capability. It was passing the full shell line as the ACP command field with no args, which relies on the client interpreting command through a shell. Per the ACP protocol docs, command is the executable and args is its argv tail; a spec-conformant client spawns them directly (no implicit shell), so any bash line with a space, pipe, &&, redirect, or $(...) failed with ENOENT and the agent silently degraded to read-only tools.
The bash tool now wraps the shell line before the createTerminal call: { command: /bin/sh, args: [-c, line] } on POSIX and { command: cmd.exe, args: [/d, /s, /c, line] } on Windows. /d/s/c matches Node's spawn({ shell: true }) convention (/s preserves the whole shell line as one argv element on the receiving end). process.platform on the agent side proxies the client's platform, which matches the near-universal ACP shape of an editor spawning omp as a co-hosted subprocess.
Fixes#4333
Cancel the ACP terminal timeout timer on completion: the hoisted Bun.sleep(timeoutMs) left a live ref'd timer for the full command timeout after every fast command, accumulating timers and delaying process shutdown in SDK/headless use. Switched to a cleared setTimeout, and rewrote the timeout regression test against real time instead of mocking Bun.sleep (the mock coupled the test to timer implementation and starved the event loop).
ACP terminal RPCs in `BashTool.execute` were awaited without abort or timeout guards, so a hung `createTerminal`, `kill`, or `currentOutput` call could keep the tool alive past its configured timeout. The ACP polling loop also recreated `exitPromise`/`abortedP` `.then()` closures on every 250 ms tick, leaking memory during long-running commands. This change moves abort/timeout setup before `createTerminal`, races it against the timeout/abort signals, hoists the exit/abort racers outside the loop, tracks `lastPolledOutput`, and bounds kill and final-output waits with fallbacks; late-resolving `createTerminal` handles are killed and released. Verified with `bun run check:types` and `bun test test/bash-acp-terminal.test.ts` in `packages/coding-agent` (6 pass, 0 fail).
Closes#4241
Started live partial tool spinner intervals for non-static tool blocks and forwarded spinner frames through eval and shell-style renderers.
Added regression coverage for live eval and shell preview spinner frames.
Fixes#4170
Reused output notice stripping for task live progress and rendered recent subagent output through the viewport-sized preview budget.
Added regression coverage for fixed six-line capping and raw bash footer leakage.
Fixes#4162
- Renamed the `find` and `search` tools to `glob` and `grep` respectively across the codebase to improve command clarity.
- Implemented full-stack support for the renamed tools, including CLI arguments, system prompts, SDK exports, and tool registration.
- Added automated migration logic in `settings` to transform legacy `find` and `search` configuration keys to their new equivalents.
- Updated the `collab-web` renderer registry to ensure backwards compatibility with legacy tool outputs.
- Clamped tool output preview height to the available viewport rows to stop redundant banner commits.
- Added `outputBlockContentWidth` helper to accurately measure visual lines for scrollback budget calculations.
- Updated `bash` and `eval-render` output wrapping to account for block padding and inner content width.
- Added regression test confirming streaming tool output maintains a stable line count without duplicating headers.
- Synchronize tool arguments with the component state upon receipt of `tool_execution_start` to ensure visual consistency when final update events are missed.
- Terminate active argument reveal streams to prevent late ticks from overwriting valid, fully-materialized tool arguments with stale partial data.
- Add test coverage to verify that tool UI components render finalized arguments even in the absence of intermediate streaming updates.
- Standardized elision markers across all tool outputs and filters to use cohesive `[...N [type] elided...]`, `[...Nln elided...]`, and `[...xB elided...]` syntax.
- Updated documentation, prompts, and test expectations to reflect the unified elision format.
- Improved transcript viewer robustness by preventing content aliasing through path-inclusive signature hashing.
- Added logic to clear stale transcript content when associated session files are deleted, accompanied by verifying test cases.
- Added explicit ArkType schema descriptions across all coding agent tool definitions.
- Updated schema definitions in autoresearch and commit tools with descriptive wrappers.
- Documented tool schema enhancements in the packages/coding-agent CHANGELOG.
- Migrated all wire protocol, schema definitions, and tools validation from Zod to ArkType across multiple packages.
- Updated extension runtimes, custom tools loader, and TypeBox compatibility shim to expose and use ArkType instances.
- Added a comprehensive ArkType migration guide, validation parity tests, and helper utilities.
- Removed redundant PDF asset routing and parsing implementations from the read tool.
- Added session-domain modules and exports for session-entries, context, listing, loader, and migrations.
- Changed persistence to async append writes plus writeTextAtomic, removing sync line APIs.
- Added compaction-aware session context rebuild with dangling tool-call cleanup.
- Added resumable session resolution with status inference, id/stem/suffix matching, and backup recovery.
- Added `ToolRenderer.provisionalPendingPreview` in `renderers.ts` and consulted it from `ToolExecutionComponent.isTranscriptBlockCommitStable`, replacing the 15.11.6 blanket gate that marked every collapsed pending preview commit-unstable.
- Marked only the tail-window previews the result render re-anchors as provisional: the edit streamed-diff tail (`edit/renderer.ts`), bash/ssh command caps (`createShellRenderer`, `sshToolRenderer`), and eval cells with interleaved outputs (`evalToolRenderer`).
- Restored mid-stream scrollback commits for every other pending preview, so tool calls taller than the viewport (e.g. a task call's context/assignment markdown) no longer read as cut off until the result lands.
- Added a regression test in `tool-live-region-scrollback.test.ts` scroll-appending a tall collapsed streaming task call into native scrollback mid-stream.
- Replaced the fixed `CALL_PREVIEW_MAX_LINES` cap in `render-utils.ts` with a dynamic `previewWindowRows()` (terminal rows minus a chrome reserve); `capPreviewLines` now returns lines untouched when expanded and windows them otherwise.
- Applied the cap in every render state for bash and ssh command previews — streaming and final render identically instead of snapping fully open on completion — and included the preview window in bash's render cache key so terminal resizes invalidate it.
- Capped eval cell code previews via the same window; previously cell code was never capped at all, with `ctrl+o` remaining the only way to uncap.
- Added stream-vs-final parity coverage in `bash-sixel-render.test.ts`, `ssh-render.test.ts`, and the new `eval-code-preview.test.ts`, and a changelog entry.
- Extended `AgentTool.concurrency` to accept per-call resolver functions and resolved concurrency mode from each tool call, falling back to exclusive on resolver errors.
- Updated BashTool to schedule non-PTY calls as shared and PTY calls as exclusive so non-interactive bash calls can run in parallel within one message.
- Tracked in-use persistent shell sessions in the bash executor and routed overlapping calls on the same session key to isolated one-shot shells while preserving owner session availability.