Commit Graph

867 Commits

Author SHA1 Message Date
can1357 ba91877b6e fix(tui): restored read selector previews for explicit selector args
The v16.3.12 explicit `selector` field (ff3b0c795c) was consumed by the
read tool but never threaded into the TUI renderers: ReadRenderArgs in
both readToolRenderer (read.ts) and ReadToolGroupComponent only derived
selectors from path-embedded `:sel` suffixes, so split-arg calls like
{ path, selector: "2-3" } rendered bare paths without line ranges or
raw modifiers.

Joined the explicit selector (trimmed, leading colons stripped, non-string
guarded) back onto the display path in renderCall, renderResult error and
success branches, and the grouped read summary, keeping hyperlinks on the
base path only.

Adopted from PR #4904 (both commits squashed), minus its unrelated
workflow-notice.md prompt churn.

Fixes #4899
2026-07-09 18:27:21 +02:00
can1357 0297202989 fix(tool): bounded ranged grep native fetch budgets
- Replaced the unbounded native fetch (no total cap; no per-file cap for
  open-ended ranges) adopted from PR #4903 with finite budgets: per-file
  fetch covers bounded ranges up to endLine and open-ended ranges up to
  startLine-1 plus the kept window, clamped to the native file-size
  ceiling; the global ceiling scales by the same amplification.
- Threaded the scaled ceiling through mergeGrepResults so mixed
  native+virtual ranged searches are not re-truncated pre-filter.
- Dropped the unrelated workflow-notice.md ellipsis churn from the PR.
- Added open-ended directory selector coverage.

Fixes #4898
2026-07-09 18:27:21 +02:00
roboomp 81a7749836 fix(tool): fetched ranged grep matches before filtering
- Raised or removed native grep pre-filter caps when line selectors are present so later selected lines are available to the post-filter.

- Added coverage for directory selectors beyond the normal multi-file per-file cap.
2026-07-09 18:27:21 +02:00
roboomp f9b425f4b7 fix(tool): allowed grep directory line selectors
- Applied explicit grep selectors as per-file line filters for directory and glob searches instead of pre-validating them as single files.

- Clarified the grep selector prompt/schema language and added regression coverage for directory searches.

Fixes #4898
2026-07-09 18:27:20 +02:00
can1357 2e189b6f9e test: aligned full suite with merged sweep contracts
- container stubs gained disposeChildren for the stale-renderer teardown paths
- login-stored API key assertions include the new source provenance field
- bash timeout test covers the zero-disable contract alongside the clamp
- skill keyword steering activates a task tool for the gated workflow notice
2026-07-08 16:52:28 +02:00
can1357 3f7581505c merge PR #4804: fix(coding-agent): launch browser on Microsoft Edge installs 2026-07-08 15:19:41 +02:00
can1357 be89a136aa merge PR #4616: fix(coding-agent/edit): sealed inverse video and preserved gutters in wrapped diff rows 2026-07-08 15:19:40 +02:00
can1357 d15e28336f merge PR #4622: fix(tools): prefer literal filesystem match over trailing :selector peel 2026-07-08 15:19:39 +02:00
can1357 613f6435f5 merge PR #4738: fix(coding-agent): preserve literal bash internal URLs 2026-07-08 15:19:37 +02:00
can1357 83896d274a merge PR #4644: fix(prompting): hide eval guidance when disabled 2026-07-08 15:19:36 +02:00
qfrtt e787a90a7d Fix Edge browser launch 2026-07-07 15:09:58 -04:00
roboomp 1adc202bf5 fix(coding-agent): preserved literal bash internal URLs
Left unresolved internal URLs unchanged during bash command expansion so quoted literal mentions can execute verbatim.

Skipped expansion for URL tokens embedded inside larger quoted shell text while preserving resolvable path-argument expansion.

Fixes #4737
2026-07-06 18:00:14 +00:00
can1357 0006252d6e test(utils): validated tool error handling and cleanup signal propagation
- Added comprehensive test suite for `postmortem` utility error handling, covering cleanup symbol marking, cause chain depth validation, and process exception suppression.
- Added tests for `browser-run-cancellation` ensuring proper `unhandledRejection` suppression and correct `ToolAbortError` propagation during teardown.
- Implemented `collectUnhandledRejections` helper to verify silence of process-level rejections during async race conditions in browser runs.
- Added integration-style probe tests for `postmortem` to verify that marked cleanup errors allow process survival while unmarked ones remain fatal.
2026-07-06 08:07:25 +02:00
can1357 dd5c329bc3 fix(coding-agent): resolved browser teardown crashes by tracking expected abort errors
- Added `markHandled` helper to prevent unhandled promise rejections in fire-and-forget browser tasks.
- Integrated `postmortem.markExpectedCleanupError` to distinguish between expected teardown aborts and actual runtime failures.
- Updated `runCmuxCode` and `WorkerCore` to propagate abort reasons via `ToolAbortError` cause chains.
- Modified `tab-protocol` and supervisor logic to signal expected cleanup states during tab release.
- Added test coverage for `ToolAbortError` wrapping and cause preservation.
2026-07-06 08:07:24 +02:00
roboomp 06f6762103 fix(agent): surfaced pending irc replies to wait
Drained pending IRC asides before parking irc wait so replies that arrive between wait calls are returned instead of being treated only as queued interrupts.

Added regression coverage for the already-aborted queued-IRC signal path and documented the fix in the coding-agent changelog.

Fixes #4657
2026-07-06 02:36:35 +00:00
Christian Stewart 1936d4f250 fix(prompting): refresh bash guidance on tool changes
Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-05 18:15:22 -07:00
Christian Stewart 96850a1642 fix(prompting): keep eval-disabled tool state coherent
Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-05 18:04:24 -07:00
roboomp a2e055fa9c fix(tools): closed two open literal-wins gaps flagged by codex
Two Codex bot findings from earlier PR reviews were still open.

1. local:// URL selector shadow (read.ts): the local:// branch resolved
   `local://foo:1-2` and rewrote readPath to `${localFile.path}:${sel}`,
   then let splitPathAndSelPreferringLiteral run on the synthesized
   string. A sibling literal `${localFile.path}:${sel}` file would win
   over the intended URL selector semantics. The branch now promotes the
   URL selector into the explicit-selector state and sets
   readPath = localFile.path, so downstream literal-preferring routing
   never re-splits the concatenation.

2. Delimited expansion before literal probe (path-utils.ts): grep called
   expandDelimitedPathEntries before parsePathSpecs, and
   splitDelimitedPathEntry only checked whether the peeled base of the
   entry resolved. A real POSIX file whose name contained a delimiter
   plus a selector-shaped tail (a;b:1-2) got split into ["a", "b:1-2"]
   and never reached the literal-preferring probe. splitDelimitedPathEntry
   now short-circuits on probeLiteralPathExists — "missing" is the only
   outcome that lets delimiter expansion run.

Added regressions: `read local://notes.md:1-2` still slices the base file
when a sibling `notes.md:1-2` literal exists, and grep searches a real
`a;b:1-2` file without semicolon-splitting.
2026-07-05 19:24:21 +00:00
roboomp 6c8e7625a2 fix(tools): tightened literal-path probe against stat ambiguity
resolveExistingReadPath treated any stat failure other than ENOENT/ENOTDIR as
"exists" and any other resolved path was considered a hit. That silently
reinterpreted a real literal path such as test:1-2 as test plus selector 1-2
whenever the raw path was a dangling symlink, sat under an unreadable parent,
or hit a transient I/O error.

The new probeLiteralPathExists returns "exists" / "missing" / "unknown" from
an lstat probe. splitPathAndSelPreferringLiteral now falls back to the strict
selector split only on "missing"; both "exists" and "unknown" keep the raw
path, so an unreachable literal is never reinterpreted. Grep and read use
the same probe: the explicit selector branch keeps the literal path when
existence is uncertain, and only a definitive ENOENT/ENOTDIR lets structured
archive/sqlite/pdf dispatch take over.

Added regressions covering probeLiteralPathExists exists/missing/dangling-
symlink cases and splitPathAndSelPreferringLiteral over a dangling symlink.
2026-07-05 18:17:59 +00:00
roboomp ff3b0c795c fix(tools): added explicit selector fields for read and grep
The literal-path stat fallback made selector-shaped filenames accessible, but it did not give callers a deterministic way to read or grep a range from a literal filename such as test:1-2. Encoding that as test:1-2:1-2 remained recursively ambiguous if a longer literal file later appeared.

Read now accepts an optional selector field that is parsed independently from path. When selector is present, path is treated as the exact path first, so { path: "test:1-2", selector: "1-2" } always means lines 1-2 from the literal file test:1-2. Inline :<sel> remains supported for compatibility.

Grep now accepts an optional line-range selector field with the same literal-path behavior. Explicit selectors bypass path suffix peeling, while archive/internal/URL routing still handles non-literal structured paths.

Updated read/grep tool prompts and added deterministic regressions proving that a longer literal file like test:1-2:5-6 or test:1-2:2-2 does not change the meaning of { path: "test:1-2", selector: ... }.
2026-07-05 18:09:29 +00:00
roboomp c493d12f95 fix(tools): preserved escaped literal selector-shaped paths
splitPathAndSelPreferringLiteral only statted resolveToCwd(rawPath), so shell-escaped paths such as dir/a\ b:1-2 missed the existing dir/a b:1-2 file and fell back to the strict selector peel. That let read target dir/a\ b with a range instead of the literal filename.

The helper now probes resolveReadPath(rawPath, cwd), reusing the read path resolver's existing escaped-space and filesystem variant normalization before deciding whether the literal file exists.

Grep also stores the resolved filesystem path for literal matches so the later search-scope parser does not reinterpret backslashes as path separators. Regression coverage now includes helper, read, and grep cases for dir/a\ b:1-2.
2026-07-05 17:47:06 +00:00
roboomp c40b0ff5da fix(tools): skipped grep archive materialization for literal filesystem matches
parsePathSpecs preserved an existing literal path like data.zip:1-2, but resolveArchiveSearchPaths only received the cleaned path strings and reparsed the same literal as archive data.zip plus member 1-2. If data.zip existed, grep materialized or errored on the archive member before searching the literal file.

GrepPathSpec now carries whether a local entry was kept because the raw filesystem path exists. Archive materialization consumes the specs instead of bare strings and skips those literal matches, while ordinary archive selectors still materialize as before.

Regression coverage adds grep over data.zip:1-2 with a real data.zip alongside, proving the literal file is searched instead of the archive member.
2026-07-05 17:38:20 +00:00
roboomp 48a6e46750 fix(tools): hoisted literal-preferring split ahead of archive/sqlite/pdf dispatch in read
The prior hunk placed the literal-preferring split after resolveArchiveReadPath,
resolveSqliteReadPath, and splitPdfImageMemberReadPath, so a real POSIX file
such as data.zip:1-2 or notes.db:1-2 still got hijacked: the archive/sqlite
resolvers matched the base extension, opened data.zip / notes.db, and errored
on the phantom :1-2 member before the literal file was ever considered.

Now the async splitter runs first. When the strict grammar would have peeled
a suffix but the literal path stats successfully, all three structured
dispatchers decline. Otherwise the ordering is unchanged, so archive/sqlite/
pdf-image reads keep working when the literal file does not exist.

Regression coverage adds `data.zip:1-2` and `notes.db:1-2` cases where the
base archive/sqlite file also exists on disk, exercising the exact ordering
bug the reviewer flagged.
2026-07-05 17:33:21 +00:00
roboomp c8df93ca31 fix(tools): preferred literal filesystem match over trailing :selector peel for read and grep
splitPathAndSel unconditionally peels a trailing :<sel> chunk whenever it
matches the read-tool selector grammar (raw, conflicts, N-M, N+K, ...). On
POSIX, filenames may legitimately contain colons, so a real file named
test:1-2 or log:raw was shredded to test/log before either read.ts or
grep.parsePathSpecs stated anything and both surfaced "Path not found".

Added splitPathAndSelPreferringLiteral(rawPath, cwd) alongside the strict
splitter: it only overrides the peel when fs.stat succeeds against the raw
path. Read (execute) and grep (parsePathSpecs) call the async variant for
non-URL paths; internal-URL splitting stays unchanged. Regression covers
splitter fallbacks, read/grep behavior on literal-colon files, and that
:1-2 selectors still work when the base file is the only real match.

Fixes #4618
2026-07-05 17:23:12 +00:00
chan1103 44daed1fff fix(coding-agent/edit): sealed inverse video and preserved gutters in wrapped diff rows
Two wrap artifacts in the Edit result card, both in wrapEditRendererLine:

- A row that broke inside an intra-line diff highlight ended with inverse
  video still active (only the foreground was reset), so the frame's
  right-edge padding painted as a default-foreground block. Every wrapped
  diff row now closes inverse alongside the foreground reset; the next row
  re-opens its own state, so highlights spanning the break render the same.

- The gutter matcher required a marker at column 0 immediately followed by
  digits, a shape only produced when marker and number exactly fill the
  gutter. Left-padded gutters (" -42│", any line number narrower than the
  widest in the diff) and dedup-blanked gutters ("   +│" on the added row
  of a single-line replacement) fell back to generic wrapping, so their
  continuation rows escaped into the line-number column. │-separated gutters
  now accept padded and blank line numbers; ASCII "|" gutters still require
  the canonical marker+number shape emitted by the plain fallback, so body
  lines that merely start with "|", "   |", or "123|" keep wrapping
  generically.

Regression tests cover continuation-gutter containment, net-inverse-off at
every row end (with a precondition proving a highlight actually crossed a
break), phantom-gutter rejection for pipe- and digit-leading body lines, and
the plain-fallback canonical-row path.
2026-07-06 00:34:23 +09:00
can1357 3458b037ae chore: update tests 2026-07-05 16:53:07 +02:00
can1357 76e21e9364 test(eval): cover JS worker exits 2026-07-05 13:39:09 +02:00
can1357 caef81cf0b Merge PR #4409: docs(tool): document bash timeout clamp (@roboomp) 2026-07-05 13:10:27 +02:00
can1357 535e8256b0 fix(lsp): avoid watched-file side effects 2026-07-05 13:10:26 +02:00
can1357 9a319b8a89 Merge PR #4462: fix(lsp): notify servers about harness file writes (@roboomp) 2026-07-05 13:10:26 +02:00
can1357 661a8794ef Merge PR #4529: fix(tui): handle invalid path render args (@roboomp) 2026-07-05 13:03:06 +02:00
can1357 7101527e60 fix(providers): skip borrowed xai env after oauth fallback 2026-07-05 13:03:06 +02:00
can1357 942ca7ce06 Merge PR #4539: fix(providers): prefer xAI OAuth for web search (@roboomp) 2026-07-05 13:03:06 +02:00
can1357 1dcab092d3 Merge PR #4538: fix(providers): remove xAI web_search search_parameters (@roboomp) 2026-07-05 13:03:05 +02:00
roboomp 281a01a2a0 fix(tool): removed unused bash fixup wrapper
Deleted the coding-agent wrapper and tests for the stripTrailingHeadTail command rewrite now that BashTool executes pipelines as written.

Fixes #4562
2026-07-04 20:16:30 +00:00
roboomp 6a1ea9bf27 fix(tool): preserved bash pipeline output
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
2026-07-04 19:40:31 +00:00
roboomp 4654125023 fix(providers): avoided borrowed xai env for oauth web search
Tightened xAI web_search's xai-oauth preference so lower-priority xai-oauth api_key or fallback credentials do not get shadowed by the shared XAI_API_KEY fallback.

Added regression coverage for the stored xai-oauth API-key plus shared XAI_API_KEY case, preserving explicit xai runtime credential routing.

Refs #4536
2026-07-04 17:40:35 +00:00
roboomp b59a4050d2 fix(providers): gated xai oauth preference on dedicated credential
Restricted the xai-oauth preference in web_search to dedicated credentials (hasNonEnvCredential("xai-oauth") or XAI_OAUTH_TOKEN) so an XAI_API_KEY-only environment no longer routes an explicit xai runtime/config credential through the xai-oauth resolver.

Added regression tests covering the shared-env case and the xai-only availability check.

Refs #4536
2026-07-04 17:30:37 +00:00
roboomp fd9bf38ebd fix(providers): preferred xai oauth for web search
Fixed xAI web_search credential resolution to try xai-oauth before xai API-key auth.

Added regression coverage for xai-oauth-only availability and precedence.

Fixes #4536
2026-07-04 17:22:51 +00:00
roboomp 1e6782af13 fix(providers): removed xai web search parameters
- Stopped adding Responses Agent Tools-incompatible search_parameters to xAI web_search requests.
- Kept limit and numSearchResults enforcement as a local cap over parsed sources and citations.
- Added regression coverage for limit, numSearchResults, recency, and local cap request shapes.

Fixes #4537
2026-07-04 17:19:29 +00:00
roboomp 0b7f4865a7 fix(tui): handled invalid path render args
Validated path-like renderer inputs before calling path helpers so provider-supplied arrays or objects cannot crash TUI rendering before schema validation reports the bad tool call.

Added renderer regression coverage for read, write, and edit call/result components with array and object path arguments.

Fixes #4525
2026-07-04 15:47:52 +00:00
can1357 6b90d34924 Merge remote-tracking branch 'origin/farm/96461c96/fix-browser-cmux-pending-unhandled-rejection' 2026-07-04 11:27:29 +02:00
can1357 42fc4e6b0a refactor(agent): unified transcript block finalization logic
- 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.
2026-07-04 11:22:05 +02:00
roboomp 8bd40a6db9 test(browser): restored cmux release mocks after each test
The cmux release regression tests install spies on CmuxSocketClient.prototype. Bun keeps those spies active across later browser-* files unless the file restores them explicitly, so browser-cmux-socket.test could stop exercising the real socket client depending on order.

Restore all Bun test mocks in afterEach after draining any test tabs, preserving mocked cleanup while preventing cross-file pollution.

Fixes #4499
2026-07-04 06:29:41 +00:00
roboomp a6a8258945 fix(browser): propagate cmux tab-close into the run body, not only the caller
Codex review of #4502 flagged that a bare `.catch(() => undefined)`
neutralizes the unhandledRejection but leaves the affected `runInTab`
call blocked inside `runCmuxCode` until timeout when the in-flight
code does not make another cmux socket request (e.g. `await
wait(60_000)`). `releaseTab` was signaling the run only by rejecting
an orphaned promise.

Wire the tab-close event all the way into the cmux run body:

- `PendingRun` gains a `closeAc: AbortController` that `releaseTab`
  aborts BEFORE calling `pending.reject`. `wait(...)` (via
  `waitForBrowserRun` -> `untilAborted`), in-flight cmux socket calls
  (via CmuxTab's `#request` -> `untilAborted`), and facade proxies
  (via `bindBrowserRunFacade`) all consume the composed signal, so
  the run body unwinds within a microtask instead of blocking to its
  own timeout.
- `runInTabWithSnapshot`'s cmux branch composes `closeAc.signal` into
  the run's signal (`AbortSignal.any([opts.signal, closeAc.signal])`)
  and now publishes `runCmuxCode(...)`'s outcome to the shared
  `promise` via `.then(resolve, reject)` and returns `await promise`.
  Both branches thus await the same promise, so `pending.reject`
  always has an attached handler (removing the original crash) AND
  the caller sees `Tab "..." was closed` immediately instead of
  waiting on the run's timeout.
- Drop the defensive `promise.catch(() => undefined)` — the promise
  is now actively consumed on both backends.

The new regression test adds a second case that exercises the
reviewer's exact scenario (`await wait(60_000);`) and asserts:
1. `pending.closeAc.signal.aborted` flips from `false` to `true`
   across `releaseTab`, with the tab-close error as its reason.
2. The awaited `runInTab(...)` rejects with `Tab "..." was closed`.
3. No `unhandledRejection` fires.

Verified locally by temporarily removing `closeAc.abort(...)` in
`releaseTab` — the new assertions fail; restoring it makes them pass.

Fixes #4499
2026-07-04 06:24:45 +00:00
roboomp 3622094e91 fix(browser): swallowed cmux tab-close rejection to prevent session crash
The cmux branch of `runInTabWithSnapshot` awaits `runCmuxCode(...)`
directly and never awaits/`.catch`es the `Promise.withResolvers()`
promise it stashes on `tab.pending`. When `releaseTab` walks pending
runs and calls `pending.reject(new ToolError("Tab ... was closed"))`
(a sibling subagent's `browser close --all`, session-scoped reap, etc.),
that orphaned promise had zero handlers and Bun surfaced the rejection
as `unhandledRejection`, which the CLI's top-level handler treats as
fatal — killing every other tab and subagent sharing the process, not
just the affected run.

Attach a no-op `.catch(() => undefined)` to the promise immediately
after creation. Inert for the worker branch (which still awaits the
same promise via `raceWithTimeout`, and attaching a second handler is
safe) and neutralizes the orphan on the cmux branch.

Adds a regression test that drives real `acquireBrowser` /
`acquireTab` / `runInTab` / `releaseTab` against a mocked
`CmuxSocketClient`, races `releaseTab` against an in-flight cmux run,
and asserts no `unhandledRejection` fires.

Fixes #4499
2026-07-04 06:06:18 +00:00
can1357 6f8e060419 Merge remote-tracking branch 'origin/farm/d78d878e/lsp-duplicate-edits' 2026-07-04 05:14:37 +02:00
can1357 98e450f0c4 Merge remote-tracking branch 'origin/farm/2dfff794/suppress-orphan-lsp-noise' 2026-07-04 05:13:55 +02:00
roboomp 2b8c8cadfb fix(read): kept raw artifact chunks verbatim and broadened path-only resolution
Skipped the workflow notice on raw selectors so bounded raw reads stay byte-for-byte, and taught resolveToolSearchScope to request pathOnly resolution so ast_grep/ast_edit scope-only calls no longer trip the inline-content cap on large artifacts.

Fixes #4482
2026-07-03 23:36:57 +00:00
roboomp 8d60e361eb fix(lsp): bounded watched-file notifications during writes
Watched-file notifications sent from the LSP writethrough now use the same bounded operation signal as sync/save notifications, so a stalled server cannot hang the write after disk commit.

Extended the freshness regression to assert a bounded signal reaches watched-file notification sends.

Refs #4459
2026-07-03 23:27:10 +00:00