Commit Graph
8978 Commits
Author SHA1 Message Date
m4air 99328ba1fb fix(auth): retain expired refresh replay evidence 2026-09-20 00:43:35 -07:00
m4air 1aef160d5c fix(memory): trim successful capability probes 2026-09-19 23:22:12 -07:00
m4air 9bf533fb38 fix(memory): align evicted upstream generations 2026-09-19 23:07:01 -07:00
m4air b2b3ae9748 fix(memory): close remaining eviction fences 2026-09-19 19:12:40 -07:00
m4air a4cbedb062 Merge origin/main into OrcaWin/np-oom-09-19 2026-09-19 17:58:13 -07:00
84d827a6ab fix(daemon): pause producers when stream backlogs grow (#20947)
* fix(daemon): pause producers when stream backlogs grow

* fix(daemon): reset stream backpressure on socket replacement

* docs(daemon): point retention audit at current reproducer

* test(daemon): validate stream retention audit outcomes

* fix(daemon): bound the stream producer stall and leave a visible gap

Stream backpressure pauses a session's PTY with no deadline: the only
un-pause comes from the consumer draining, so a half-open peer that stops
reading without closing freezes the shell for the rest of the session.

Arm a 60s watchdog on the false->true stream-pause transition (not on the
re-assertions refresh() makes for neighbouring sessions). On fire, mark the
session stall-released: it becomes keep-tail droppable, its backlog is
thinned behind a dataGap, and the producer runs again. The existing dataGap
path makes the renderer restore that pane from the daemon's snapshot, so the
user sees the terminal jump to current rather than sit frozen. The mark
clears once the session's last byte leaves the daemon, restoring ordinary
pausing. Nothing here reports a process exit - loss of contact with a
consumer is not evidence about the child.

Also enable TCP keepalive on the stream socket so a genuinely dead peer
closes and onStreamDisconnected clears the pause.

* test(daemon): put each casting SAFETY: directive on one line

`oxlint-disable-next-line` covers only the line directly after it, so a
rationale wrapped onto a second comment line suppressed nothing and the
casts failed the changed-code quality gate. Drop the remaining JSON.parse
cast for an annotated binding.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:51:59 -07:00
921882619e fix: retire closed editor models from the app shell (#21178)
* fix: retire closed editor models from the app shell

* test(editor): use checked Monaco attachment calls

* Preserve bounded editor view caches when retiring closed models

* docs(editor): describe batched model retirement

* fix(editor): preserve cleanup work across registry replacement

* fix(editor): build editor model URIs with the file scheme

Monaco keys its model registry by `uri.toString()`, and both
`@monaco-editor/react` (via the `path` prop) and the closed-tab disposal
path built that key with `Uri.parse`. On Windows a raw path such as
`C:\repo\a.ts` parses as scheme `c`, which fails the scheme gate in
`modelService._schemaShouldMaintainUndoRedoElements`, so closed-file undo
history was dropped for every file at any size — not only the large files
the tradeoff note covers.

Add `toEditorModelUri`, the one filesystem-path -> model-key function,
built on `Uri.file` so the result always carries the `file:` scheme and
re-parses to itself. Route model creation, disposal lookup and the
still-open ownership comparison through it so all three agree; a
divergence there would dispose a model an open editor is still editing.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:51:55 -07:00
NeilandXiro The Dev ee354a35d7 feat(agents): add OpenCode 2 beta support (#21418)
* feat(agents): add OpenCode 2 beta support

Co-authored-by: Xiro The Dev <lethanhtrung.trungle@gmail.com>

* fix(opencode2): support current plugin lifecycle and session storage

* fix(opencode2): preserve lifecycle ordering and full session capture

* test(opencode2): cover setup event bridge

* test(opencode2): cover setup event bridge

* test(browser): satisfy anti-slop naming check

* test(opencode2): cover live form lifecycle

* fix(relay): preserve OMP config directory selection

* test(opencode2): avoid assertions in bridge fixture

* fix(rebase): retain OMP resume and fresh launch behavior

* test: align upstream OMP resume expectations

* test(opencode2): verify rejected form closes waiting state

---------

Co-authored-by: Xiro The Dev <lethanhtrung.trungle@gmail.com>
2026-09-19 17:49:03 -07:00
m4air 5d21208986 fix(memory): preserve generation fences across eviction 2026-09-19 17:49:02 -07:00
403c0881e1 Bound AI Vault transcript record assembly before allocation (#20963)
* fix(ai-vault): bound incremental transcript record assembly

* fix(ai-vault): skip one oversized record instead of dropping the session

An agent transcript record over the 10 MiB budget threw out of the JSONL
fold, so the whole session vanished from Agent Session History and from
search. A 10 MiB base64 image or a runaway tool result is ordinary.

The reader now discards the offending record up to its newline and keeps
folding. The in-progress record always starts at `consumedThrough`, which
is what makes both its running size and the resume offset past a discarded
span exact; an unterminated oversized tail leaves the cursor at the
record's start so a still-growing record is re-read rather than guessed at.
Skips accumulate on the resume point keyed by start offset, and the scanner
reports them as a per-session `notice` so nothing is silently lost.

The budget itself is unchanged.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:47:56 -07:00
f87359cda6 fix(runtime): persist acknowledged terminal tab retirement (#21020)
* fix(runtime): persist acknowledged terminal tab retirement

* test(runtime): drain tab retirement fixture writes before teardown

* fix(runtime): explain a refused workspace terminal close

The Sleep-workspace path threw the raw refusal enum ("stale-terminal") as an
Error message, which reaches a CLI user verbatim and a Sleep toast via
describeSleepFailure. Map each refusal reason to a sentence instead.

Also pins two behaviours that had no coverage: the user-visible outcome of a
republished stale-terminal refusal on the web client (the caller cannot tell it
from a real close), and the one-call-per-close invariant that keeps a successor
terminal alive.

The bounded close retry was NOT implemented: notifier.closeTerminalTab carries
only a tab id, so a second call destroys whatever successor took that id.

* test(runtime): build refusal fixtures without type assertions

The changed-code quality gate rejects new `as` casts. Replace the
branded-outcome cast with refusedMobileSessionTabClose, and model the
wire-skew reason as a decoded host answer instead of `as never`.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:38:05 -07:00
db7b57b846 fix(claude): enforce history window quota while reading (#21021)
* fix(claude): enforce history window quota while reading

* test: repair history quota audit dependency and CI import

* fix(native-chat): record why restart reconciliation leaves work unconfirmed

Two silent paths hid the cause of an unconfirmed submission. The reconciler's
bare `continue` on an `unknown` outcome dropped the reason it already carried,
and the transcript read swallowed its error, collapsing an oversize file and a
genuine read failure into the same verdict.

Log both. No control flow changes.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:25:36 -07:00
a445abadd4 fix(browser): bound CDP output for stalled clients (#20949)
* fix(browser): bound CDP output for stalled clients

* fix(browser): log CDP outbound overflow before terminating the client

The outbound queue terminated the automation client silently on overflow, so
the client saw a socket close indistinguishable from a crash. Surface the cap
that tripped and the backlog held when it did.

The queue dropped its backlog before invoking onOverflow, so the counters were
already zero at the callback. Snapshot them first and pass them through.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:24:33 -07:00
4d82149fe5 fix(runtime): reject stale inventory after PTY lifecycle changes (#21014)
* fix(runtime): reject provider inventory across PTY lifecycle changes

* fix(runtime): canonicalize SSH inventory generation keys

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-19 17:24:29 -07:00
m4air ce761b9745 fix(memory): keep hot cache entries warm 2026-09-19 17:15:54 -07:00
Neil b766f512ec fix(editor): extract diff first-change auto-scroll to a hook to unblock main (#21738) 2026-09-19 17:06:58 -07:00
OrcaWinandm4air b8f67a6266 Close workspace board when selecting sidebar worktree (#21737)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-09-19 16:54:56 -07:00
m4air 968ab90e28 fix(memory): bound WSL preflight cache 2026-09-19 16:52:37 -07:00
m4air b6b4e3ad7e fix(memory): bound WSL Git environment cache 2026-09-19 16:50:24 -07:00
m4air ccc18e8be4 fix(memory): bound WSL Git environment cache 2026-09-19 16:49:23 -07:00
m4air bd756fadb6 fix(memory): bound local Git capability cache 2026-09-19 16:47:55 -07:00
m4air 16833818f2 fix(memory): bound Linear workspace credential cache 2026-09-19 16:46:51 -07:00
m4air 75a2f6edac fix(memory): bound WSL auth drain state 2026-09-19 16:44:48 -07:00
Neil 85a3ba6d42 fix(terminal): align CJK IME preedit spacing (#19367)
* fix(terminal): align IME preedit to terminal cell grid

* fix(terminal): preserve native shaping and reuse IME preedit on repaint

* fix(terminal): preserve native shaping with bounded IME spacing runs

* test(terminal): account for inline preedit subpixel rounding

* test(terminal): keep the IME grid fixture wide at every DPI

* chore: regenerate xterm patch after rebase

* test(terminal): remove IME assertion lint findings

* test(terminal): avoid reflective IME fixture access

* test(e2e): run IME renderer matrix with WebGL available

* fix(ci): restore editor line budget
2026-09-19 16:44:38 -07:00
m4air 18e5ee4177 fix(memory): bound trust grant cooldowns 2026-09-19 16:41:45 -07:00
m4air 467fa2f00d fix(memory): bound SSH capability cache 2026-09-19 16:40:11 -07:00
m4air 80e51277df fix(memory): bound WSL home cache 2026-09-19 16:38:20 -07:00
m4air 4107cd5efa fix(memory): bound cloud session cache 2026-09-19 16:31:54 -07:00
m4air af7113ac78 fix(memory): bound web session close intents 2026-09-19 16:29:51 -07:00
m4air 67f1bcb5fa fix(memory): bound retained session activity 2026-09-19 16:27:33 -07:00
m4air a55027309d fix(memory): bound retained session activity 2026-09-19 16:26:46 -07:00
Neil e4c7632db2 perf(terminal): skip kitty scans for plain PTY output (#21643)
* perf(terminal): skip kitty scans for plain output

* fix(terminal): keep the kitty scan fast path total for absent chunks

The new escape-byte fast path dereferences the chunk before the string
concatenation that used to coerce a nullish value, so an unchecked
caller now throws instead of no-opping. Normalize once at the top.

Also type the AgentTerminalPreview connect mock against the real preload
signature, which turns the stale bare-string replay fixture that tripped
this into a compile error.
2026-09-19 16:26:32 -07:00
Neil abd310e5a3 perf(terminal): skip background SGR scans without ESC (#21646)
* perf(terminal): skip background SGR scan without escapes

* perf(terminal): avoid duplicate renderer risk scans

* test(terminal): pin the carried renderer risk scan tail

The foreground renderer-risk scan splices the carried tail onto the
incoming chunk before classifying it, and nothing covered that ordering:
a pre-gate moved back above the concatenation would silently drop the
refresh for a background SGR split across ConPTY chunks.

Also pins the escape-free ASCII path and the shared global SGR pattern's
statelessness across calls, since the background hit returns mid-loop.
2026-09-19 16:25:58 -07:00
m4air baa6914b4c fix(memory): bound host mirror waiters 2026-09-19 16:23:52 -07:00
m4air a5762e19cf fix(memory): bound automation dispatch tokens 2026-09-19 16:22:22 -07:00
m4air 52952623db fix(memory): bound web session handoffs 2026-09-19 16:21:02 -07:00
m4air 9677bd71d0 fix(memory): bound web session focus intents 2026-09-19 16:19:15 -07:00
m4air df81c993d8 fix(memory): bound web session reorder intents 2026-09-19 16:18:16 -07:00
m4air 51137f868c fix(memory): bound automation manager cache 2026-09-19 16:16:51 -07:00
m4air a59ad29e49 fix(memory): bound advertised URL scan snapshots 2026-09-19 16:15:46 -07:00
m4air e4947ce2de fix(memory): bound shared directory cache 2026-09-19 16:14:23 -07:00
m4air ad0129e002 fix(memory): bound sparse checkout cache 2026-09-19 16:12:58 -07:00
m4air 2ca969217f fix(memory): bound WSL canonical path cache 2026-09-19 16:09:56 -07:00
m4air 53bc377e3d fix(memory): bound codex credential absence paths 2026-09-19 16:08:31 -07:00
m4air 2b416b3e4e fix(memory): bound web session tracking generations 2026-09-19 16:06:48 -07:00
m4air 810ae3268c fix(memory): bound native chat enrichment cache 2026-09-19 16:03:35 -07:00
m4air a220b321c6 fix(memory): bound automation authority generations 2026-09-19 16:02:08 -07:00
m4air 995598aff0 fix(memory): bound plugin log key retention 2026-09-19 15:59:26 -07:00
m4air e5f0812592 fix(memory): release retired plugin generations 2026-09-19 15:58:20 -07:00
m4air b3e77c733a fix(memory): expire cloud refresh replay guards 2026-09-19 15:56:38 -07:00