Commit Graph
9801 Commits
Author SHA1 Message Date
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
roboomp bfa44eb8c1 fix(coding-agent): scoped /model search to the active provider tab
`#filterModels` in `packages/coding-agent/src/modes/components/model-selector.ts`
used to auto-switch to the ALL tab on any non-empty query. Typing a search from
a provider tab silently escaped the scope, so selecting the apparent match could
persist a same-named model from a different provider (e.g. a custom-proxy
`glm-5.2` while the user was on the openrouter tab wanting
`z-ai/glm-5.2`) under the default role.

Keep the search scoped to the active provider tab; empty results now name the
active tab and point at ALL as the explicit escape. Regression tests in
`test/model-selector-provider-search-scope.test.ts` cover the scoped search,
the still-global ALL-tab search, and the empty-state hint.

Fixes #4522
2026-07-04 14:45:56 +00:00
roboomp 8cce6f637c fix(tts): stopped queued TTS playback on Esc after stream end
Once the assistant reply stops streaming, `vocalizer.clear()` was only invoked from the aborted-stream cascade in EventController. Escaping after the model finished fell through InputController to the empty-editor double-Esc gesture while StreamingAudioPlayer kept draining buffered Kokoro PCM.

Add `Vocalizer.isSpeaking()` (true while any live player, stream handle, or in-flight abort is around) and consult it in the Esc handler before the double-Esc branch: if speech is still audible, a single Esc calls `vocalizer.clear()` and resets `lastEscapeTime` so tree/branch stays reachable via the next press.

Fixes #4521
2026-07-04 14:42:24 +00:00
roboomp cf14a74dde fix(tool): rejected root glob paths
Rejected slash-only glob search paths before resolveToCwd can collapse them to the session cwd.

Added contract coverage for both / and // root inputs.

Fixes #4516
2026-07-04 13:51:53 +00:00
can1357 78126d925c test(ci): kept messagePersistenceKey call strict in event-controller
Reverted the defensive typeof guard; the assistant component contract guarantees the method, and test doubles now mock it. Keeping the production call strict avoids masking broken mocks or silently skipping persistence-key recovery.
2026-07-04 14:41:22 +02:00
can1357 53e8a8b807 test(ci): fixed event-controller and auth-storage test failures
- Mocked messagePersistenceKey in event-controller-error-banner.test.ts and safe-guarded it in event-controller.ts to prevent TypeError.
- Updated thinking loop retry test expectations to handle new dynamic recoveredErrors structure.
- Updated schema version assertions in auth-storage-email-dedupe.test.ts to v5, preserving v6 for future schema test.
- Simulated scrollback commitment in event-controller-message-start.test.ts by rendering container and committing rows before advancing timers.
2026-07-04 14:21:01 +02:00
roboomp 65bc422e83 fix(coding-agent): handled inline image pdf delimiters
Skipped binary inline-image payload bytes after the PDF ID operator so tokenizer scanning resumes at post-image content.

Advanced past stray closing delimiters while recovering malformed content streams to avoid zero-width tokenizer iterations.

Fixes #4512
2026-07-04 12:18:06 +00:00
can1357 e8d1ab005e test(coding-agent): verified transcript component streaming and state management
- Added comprehensive unit tests for `TranscriptContainer` to verify uncommitted block tracking.
- Created integration tests ensuring `AssistantMessageComponent` correctly streams thinking and answer content into scrollback.
- Added tests verifying that expanded tool evaluation output records rows correctly without duplication after settling.
- Updated `AssistantMessageComponent` test suite to cover table streaming scenarios in the unsettled tail.
2026-07-04 12:15:23 +02:00
can1357 10043a5990 feat(coding-agent): gated block lifecycle and state transitions
- Enforced strict history protection by gating ephemeral block removal on uncommitted state across controllers and UI components.
- Optimized settled-row calculations using explicit mermaid fence detection and improved scrollback integrity.
- Refactored transience management to target only actively streaming blocks, preventing redundant label rendering.
- Implemented persistent compaction for auto-retry errors and enabled consistent terminal title updates during session renaming.
2026-07-04 12:13:34 +02:00
can1357 0cdd0a09b8 refactor(coding-agent): consolidated session title update logic
- Moved terminal title update logic to a single listener onSessionNameChanged.
- Removed redundant setSessionTerminalTitle calls from ExtensionUiController, InputController, and InteractiveMode.
- Ensured consistent side-effect execution for terminal titles and editor accents across all session name change triggers.
2026-07-04 12:13:34 +02:00
can1357 71dd8c8e81 refactor(coding-agent/modes): updated abort reason rendering logic
- Refactored abort reason handling to rely on shouldRenderAbortReason instead of isSilentAbort.
- Updated documentation to clarify that both silent and user-interrupt aborts yield no label.
2026-07-04 11:37:54 +02: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 141244ab21 Merge remote-tracking branch 'origin/farm/1f0795db/guard-write-render-content' 2026-07-04 11:27:12 +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
can1357 6e2bba871e feat(agent): implemented automated retry recovery and transcript compaction
- Introduced an automated retry recovery system to track, manage, and persist recovered error states within agent sessions.
- Enabled compact transcript rendering for recovered auto-retry errors by removing heuristic commit machinery.
- Improved raw read tracking and provenance in the ReadTool to support refined file snapshot recording and hashline editing.
- Excluded recovered assistant messages from default model context and updated event controllers to handle retry recovery life cycles.
2026-07-04 11:22:04 +02:00
can1357 d5e9084e65 refactor: restructured audit logic and render boundary tracking
- Removed complex snapshot caching and volatile/stable state tracking logic.
- Replaced multi-zone audit logic with streamlined tail-sample checks.
- Simplified render boundaries by deriving a single final boundary from the live region.
- Eliminated redundant audit state management and auxiliary safe-end interfaces.
2026-07-04 09:50:20 +02: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
cagedbird043 1c56a9f315 fix(gemini): suppress CCA thinking summaries by default 2026-07-04 13:50:19 +08:00
roboomp 74a8289404 fix(coding-agent): guarded write renderer content
Coerced runtime write content before preview rendering so truthy non-string transcript values cannot crash CR normalization, line counting, or highlighting.

Added regression coverage for pending write calls and merged write results with non-string runtime content.

Fixes #4495
2026-07-04 05:22:21 +00:00
roboomp db9cb30763 fix(models): normalized list-valued model roles
- Normalized string-array modelRoles values at the settings accessor boundary so existing role resolution paths keep receiving comma-list strings.
- Added regression coverage for resolving pi/task from a YAML-equivalent modelRoles.task list.

Fixes #4492
2026-07-04 05:20:55 +00:00
roboomp 783f36d235 docs(coding-agent): fixed workflowz recursion wording
- Aligned the workflowz eval notice with task.maxRecursionDepth.
- Documented the default depth 2 and eval hard cap 3.
Fixes #4493
2026-07-04 05:01:21 +00:00
roboomp a8add580d9 fix(snapcompact): selected silver for cjk auto shape
- Made resolveShapeForText choose silver16-bw for CJK-heavy auto transcripts while preserving explicit variants and unsafe glyph protection.
- Added silver16-bw to the snapcompact shape settings submenu and renamed unsupported-glyph warnings.
- Covered auto shape selection, explicit variant precedence, unsafe glyph scans, and settings option parity.

Fixes #4486
2026-07-04 03:54:55 +00:00
Mathews-Tom 7f56b68a5e Merge remote-tracking branch 'upstream/main' into feat/secret-friendly-names 2026-07-04 08:49:14 +05:30
can1357 3dec7ac12c Merge remote-tracking branch 'origin/farm/99fd01f3/fix-linux-tiny-cuda-runtime' 2026-07-04 05:15:18 +02:00
can1357 6f8e060419 Merge remote-tracking branch 'origin/farm/d78d878e/lsp-duplicate-edits' 2026-07-04 05:14:37 +02:00
can1357 a96f2f9292 Merge remote-tracking branch 'origin/farm/ab9741c2/fix-mcp-oauth-windows-opener-and-url-truncation' 2026-07-04 05:14:28 +02:00
can1357 98e450f0c4 Merge remote-tracking branch 'origin/farm/2dfff794/suppress-orphan-lsp-noise' 2026-07-04 05:13:55 +02:00
can1357 cdad865b64 Merge remote-tracking branch 'origin/farm/8316301c/cherry-pick-skip-empty' 2026-07-04 05:13:37 +02:00
can1357 4bd8f270ae Merge remote-tracking branch 'origin/farm/a6b7ad66/mcp-oauth-carry-challenge-scopes' 2026-07-04 05:13:18 +02:00
can1357 21d2c2271a Revert "fix(tui): merged scrollback offer boundary repair"
This reverts commit ae89b3ff08, reversing
changes made to 227874dcc6.
2026-07-04 05:12:18 +02:00
can1357 e9c44f3277 Merge remote-tracking branch 'origin/farm/59fcbc18/guard-large-raw-artifacts' 2026-07-04 05:11:26 +02:00
can1357 45f1d63861 Merge remote-tracking branch 'origin/farm/035627c4/slice-mnemopi-retain-window' 2026-07-04 05:10:38 +02:00
Mathews-Tom b929c8f2c3 fix(secrets): reject friendly names that embed another live secret's literal
A configured secret's friendlyName is baked verbatim into every
placeholder minted for it via an exact deobfuscateMap entry - not
through the alias-fallback path fixed earlier. If the sanitized label
happens to contain another configured secret's literal (or is matched
by a configured regex), that secret is smuggled into every use of the
unrelated placeholder and is never scanned, since the token is
recognized as already-generated on an exact match.

createPlaceholder() now drops the friendly-name prefix for a mint
whenever it collides with a configured plain secret or a configured
regex pattern. Regex entries are now compiled in a dedicated
constructor pass before any placeholder is minted, so the collision
check sees the full picture regardless of entries[] order.
2026-07-04 07:57:30 +05:30
Mathews-Tom 1da33c74cf fix(secrets): cover regex-discovered secrets and preserve full cut-match length
Two follow-up fixes on the friendly-placeholder alias check:

- isGeneratedPlaceholder() now also rejects a forged prefix that
  contains any regex-discovered secret's value (tracked in
  #obfuscateMappings), not just statically configured plain secrets,
  closing the same smuggling path for type: "regex" entries.
- The regex match collector's placeholder-prefix clamp branch now
  keeps the full original match length for the short-match guard
  instead of the clamped prefix's shorter length, so a full-size
  match whose wholly-outside prefix is under MIN_OBFUSCATE_SECRET_LEN
  is no longer wrongly skipped as noise.
2026-07-04 07:33:17 +05:30
ben 3fadaee37f fix(coding-agent): guard legacy snapcompact resume frames 2026-07-04 09:59:03 +08:00
Mathews-Tom cf1c491f64 fix(secrets): reject forged secret-value prefixes in friendly placeholder aliases
Untrusted text could wrap a real secret's plaintext in a fabricated
friendly-name prefix around a hash suffix borrowed from any OTHER
already-obfuscated secret. obfuscate() treated the whole forged token
- including the exposed secret literal standing in for the prefix - as
already redacted, letting it reach the provider untouched.

isGeneratedPlaceholder() now refuses the friendly-name-independent
alias fallback whenever the dropped prefix contains a configured
secret's literal value, while still accepting a stale prefix left over
from a legitimate friendly-name rename (same secret, same key).
2026-07-04 07:10:01 +05:30
Mathews-Tom ec9dedec3d Merge remote-tracking branch 'upstream/main' into feat/secret-friendly-names 2026-07-04 06:30:49 +05:30
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 7049966def fix(mcp): hydrate JSON-body OAuth scopes from resource metadata
When the error body already advertises OAuth endpoints, `/mcp add` and `/mcp reauth` use `authResult.oauth` directly and skip `discoverOAuthEndpoints`, so scopes advertised only in the RFC 9728 protected-resource metadata document never reach the grant.

Add exported `fetchResourceMetadataScopes(url, opts?)` that fetches the metadata doc and returns `scopes_supported` / `scopes` / `scope`. Hoist the shared `readMetadataScopes` reader out of `discoverOAuthEndpoints`. At all three call sites (wizard, `/mcp add`, `/mcp reauth`), when `oauth` is populated from the JSON body but `oauth.scopes` is empty and `authResult.resourceMetadataUrl` was advertised, fetch the metadata and merge scopes onto `oauth`.

Regression tests cover the resource-metadata fetch and its failure/empty-doc paths.

Refs #4467
2026-07-03 23:27:18 +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
roboomp 7497e68189 fix(read): shortened artifact paths in user-visible notices
shortenPath() the artifact.path leaked into the read-tool 'Artifact storage' and 'Unbounded raw read blocked' notices so $HOME never appears verbatim; details.resolvedPath keeps the absolute path for tooling.

Fixes #4482
2026-07-03 23:20:20 +00:00
roboomp ff397cf27a fix(read): kept large artifacts reachable from path-only resolvers
Bash URL expansion and search/grep only need sourcePath; they now request pathOnly resolution so large artifacts stay usable for search/copy workflows while unbounded content materialization stays blocked.

Fixes #4482
2026-07-03 23:17:46 +00:00
roboomp a9bb4c7d59 fix(read): guarded large artifact raw reads
Resolved artifact:// reads to backing files before selector handling, streamed bounded reads, and blocked unbounded raw reads for large artifacts with recovery guidance.

Fixes #4482
2026-07-03 23:08:18 +00:00
roboomp 941a931599 fix(tiny): repaired cuda sidecars for auto gpu requests
Extended ONNX Runtime CUDA sidecar repair to PI_TINY_DEVICE=auto and gpu on Linux x64, matching the CUDA-capable diagnostics path.

Added focused regression coverage for both generic accelerated settings.

Refs #4475
2026-07-03 18:34:56 +00:00
roboomp ccd68b9d84 fix(tiny): preserved cpu fallback when cuda sidecar repair fails
Deferred ONNX Runtime CUDA sidecar repair failure into the runtime metadata so loadTransformersRuntime keeps loading and loadPipelineWithDeviceFallback still gets its CUDA→CPU retry when NuGet is offline or the ort install script is unavailable. The failure surfaces through the CUDA diagnostics helper instead of hard-erroring the tiny worker.

Refs #4475
2026-07-03 18:26:13 +00:00
roboomp f257fd533f fix(tiny): repaired cuda side-runtime install
Downloaded missing ONNX Runtime CUDA provider sidecars when the compiled tiny-model side runtime is used with PI_TINY_DEVICE=cuda.

Preserved actionable CUDA worker diagnostics in tiny-models text output and added focused regression coverage.

Fixes #4475
2026-07-03 18:21:19 +00:00
roboomp 1d4e9a5384 fix(mcp): width-wrap the full authorize URL so narrow viewports cannot truncate
@DylanBohlender's follow-up caught that MCPAuthorizationLinkPrompt.render
still ignored `width` and emitted `Copy URL: <full URL>` as one composed
row. On any viewport narrower than the row (~272 columns for a
Linear-shaped authorize URL), TUI#prepareLine's
`truncateToWidth(..., Ellipsis.Omit)` silently clipped the trailing
`code_challenge_method=S256` — the exact #4418 fingerprint reappearing
inside the remote-safety fix. A remote user on a narrow terminal
copying the rendered line would lose the S256 method again; the local
shortcut below cannot help them (localhost isn't reachable), and the
OSC 52 clipboard staged full URL isn't visible in their local browser.

Component-level fix: honor `width` in render.

- New `wrapUrlRows(label, url, width)` helper.
  - When `label + " " + url` fits in `width`, emit one inline row.
  - Otherwise emit the label on its own row and slice the URL into
    chunks of `width - indent`, each on its own row.
  - Floors the effective width at 16 columns so degenerately narrow
    terminals still emit every character; browsers strip whitespace
    when a multi-row selection is pasted into the address bar, so the
    reassembled URL is byte-identical.
- `render(width)` now uses the helper for both the primary `Copy URL:`
  row and the additive `Local shortcut (this machine only):` row.

Regression tests in
`packages/coding-agent/test/modes/controllers/mcp-authorization-link.test.ts`:

- Wide viewport (1000 cols): inline `Copy URL: <url>` layout preserved.
- Narrow viewport (80 cols) + Linear-shaped URL: every row's visible
  width ≤ 80, and the chunks reassemble byte-for-byte to the URL —
  explicitly asserting the trailing `code_challenge_method=S256`
  survives.
- Launch shortcut also wrapped at 80 cols; every row fits.
- Degenerate viewport (4 cols): URL still reconstructs exactly; the
  16-col floor governs chunk width.
- Full URL remains the primary target even when a launch URL is
  present, and the shortcut row is omitted when launchUrl is absent
  or identical to the full URL.
2026-07-03 17:45:08 +00:00
roboomp a52ed682c7 fix(ai): separated codex orchestration usage
- Added a Usage.orchestration sidecar for provider-side service tokens so Responses/Codex totals and costs stay accurate without inflating visible prompt input/cache buckets.
- Updated Codex/WebSocket usage, session/status aggregates, and usage reporting to preserve orchestration-aware totals.
- Added regressions for OpenAI Responses accounting, Codex WebSocket terminal usage, cost calculation, and session aggregation.

Fixes #4469
2026-07-03 16:44:12 +00:00
roboomp 89fc4df9f4 fix(extension): refreshed editor after extension paste
Scheduled a TUI repaint after extension-driven prompt mutations so pasteToEditor and setEditorText do not leave the editor visually stale until the next input event.

Fixes #4341
2026-07-03 16:40:48 +00:00