Commit Graph

5450 Commits

Author SHA1 Message Date
Peter Steinberger 986be4558f fix(ui): prevent duplicate Skills preload requests (#123705)
* fix(ui): wait for Skills route preload

* fix(ui): defer Skills fallback until first update

* fix(ui): keep Skills unmounted during preload

* fix(ui): retain route data through gateway metadata updates

* test(ui): make Skills preload race deterministic

* fix(ci): round boundary artifact refresh mtimes

* fix(ci): repair merged main checks

* chore: keep Skills repair diff focused
2026-08-14 12:41:24 -07:00
Peter Steinberger 1805e8eec3 fix(ui): surface auto-disabled automations instead of hiding them as paused (#123769)
An auto-disabled job (10 consecutive run failures / 3 schedule errors)
rendered as plain 'Paused' and simultaneously vanished from the failed
chip, the failing count, and the error dot — the escalation removed
visibility exactly when the problem became permanent. The recorded fact
(state.autoDisabled, already public and used by CLI/doctor) now renders as
a distinct danger note with the reason and count, and auto-disabled jobs
stay in the active-failure predicate.
2026-08-14 12:39:03 -07:00
Peter Steinberger 877f2ec083 fix(ui): report connection loss instead of silently dropping session actions (#123771)
* fix(ui): report connection loss instead of silently dropping session actions

patchSession returned 'stale' with no message when the gateway dropped
before a queued dialog submit (rename and similar) — the dialog closed and
the edit vanished with no visible outcome. loadCheckpoint had the sibling
gap: expanding a row while disconnected left the drawer claiming 'No
checkpoints' beside a nonzero checkpoint badge. Both now surface the
existing actionRequiresConnection message at their owning error surface.

* test: widen patchSession test-support patch type for label patches
2026-08-14 11:33:47 -07:00
Peter Steinberger 0bdf11c9dc fix(ui): surface companion clear failures (#123724)
* fix(ui): surface companion clear failures

* fix(ui): scope companion reset errors

* fix(ui): preserve companion clear async contract
2026-08-14 11:30:26 -07:00
Peter Steinberger f22e4990c1 fix(ui): surface Talk input backpressure (#123783) 2026-08-14 11:27:13 -07:00
Peter Steinberger da7a2b4651 fix(ui): show session attention on Home (#123759)
* fix(ui): show main-session attention on Home

* refactor(ui): keep Home attention boundary private
2026-08-14 11:27:04 -07:00
Peter Steinberger c4b92d9a7a fix(ui): stop turn recap freezing the previous run's token count (#123712)
The session row's terminal stamp (status/endedAt/runtimeMs) and its usage
persist (outputTokens) are separate gateway writes. resolveTurnRecap settled
on the first fresh terminal row and froze whatever outputTokens it carried —
frequently the PREVIOUS turn's count. Treat an unchanged-from-baseline value
as that lag and fall back to the watched run's live usage-stream counter
(captured while watching, since the usage map entry dies at lifecycle end).
2026-08-14 11:18:18 -07:00
Vyctor H. Brzezowski 3f006ba0fc fix(ui): complete mobile pairing after code redemption (#120933)
* fix(ui): complete pairing setup lifecycle

Redeemed and expired mobile setup codes stayed on screen as usable QR
codes, so a successful pairing had no visible outcome and expired bearer
material still looked live.

The Gateway now mints an opaque, non-authorizing setupId beside each
setup credential, returns its authoritative expiresAtMs, records the
terminal outcome of the exact redemption, and broadcasts
device.pair.setup.completed. Because that broadcast is dropped for
buffered operator sockets, the completion is persisted first and can be
reconciled through the new device.pair.setupStatus method: the Control UI
asks for the recorded outcome before it may present a credential as
expired, so a pairing that succeeds is never shown as a failure.

The Control UI models one closed lifecycle (selection, loading, waiting,
success, expired, error) correlated only by the active setupId, and
Pairing help now carries the external-link affordance.

* fix(ui): preserve unknown pairing outcomes

* test(ui): target pairing terminal headings

* test(ui): align pairing completion fixture

* fix(gateway-protocol): decode setup-code results from older gateways

Older protocol-v4 gateways omit the new setupId and expiresAtMs
lifecycle fields, so requiring them in the generated native model broke
decoding an existing device.pair.setupCode response. Keep both optional
at the wire boundary, require lifecycle metadata before the Control UI
enters its waiting state so a missing outcome stays visible, and cover
the legacy payload with Swift and schema regressions.

* fix(ui): surface rejected pairing dialog loads

The lazy pairing chunk could reject while its overlay was already open,
leaving the shell rendering nothing at all. Record the rejection on the
shell and render a recoverable modal with a reason and a retry so the
open action always ends in a visible outcome.

* fix(state): preserve pairing setup schema compatibility

* test(gateway): cover pairing setup release train

* fix(gateway): commit pairing setup completion atomically

* refactor(state): distinguish setup transaction helpers

* refactor(state): remove obsolete bootstrap restore path

* fix(gateway): preserve setup handoff type safety

* fix(gateway): keep pairing completion terminal after consume

* fix(gateway): validate Watch binding during setup commit

* fix(gateway): revalidate setup credential expiry at commit

* chore: refresh Plugin SDK API contracts after rebase

* fix(pairing): prune expired setup completions

* chore: retrigger CI

* fix(protocol): deduplicate setup expiry field

* fix(protocol): refresh pairing setup clients

* fix(gateway): make pairing setup completion durable

* fix(ui): retire expired pairing credentials immediately

* fix(ui): keep pairing dialog visible while loading

* fix(macos): align setup result initializer order

* fix(gateway): restore generic bootstrap retries

* chore(ui): record pairing startup budget

* chore(ui): refresh pairing startup budget

* style(gateway): format maintenance imports

* test(gateway): cover session-sharing mock

* fix(state): defer setup correlation schema

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-14 11:10:30 -07:00
Peter Steinberger 88babc4643 test(ui): stabilize update confirmation focus proof (#123757)
* test(ui): wait for update dialog focus

* test(ui): poll update confirmation focus
2026-08-14 11:09:03 -07:00
Peter Steinberger 3292ff146c fix(ui): keep the archive Undo working after leaving the Sessions page (#123749)
The archive toast outlives the Sessions page (toast host is app-shell
level), but its Undo action was gated on the page's request scope, which
dies the moment the operator navigates away — clicking Undo within the 6s
window then silently did nothing. Run the un-archive through the shared
sessions mutations store directly (it already fails closed on connection
replacement and publishes errors), mirroring the always-mounted sidebar
undo sibling.
2026-08-14 11:09:02 -07:00
Peter Steinberger f9d9b9da2b fix(ui): stop flagging running automations as overdue and show their state (#123745)
* fix(ui): stop flagging running automations as overdue and show their state

The gateway intentionally leaves nextRunAtMs past-due while a run executes
(it advances only on the outcome), and agentTurn runs may take up to an
hour — 12x the sidebar's 5-minute overdue grace. The overdue chip and the
cron table therefore reported healthy in-flight jobs as 'overdue' / 'next
run: X minutes ago'. runningAtMs is the recorded fact for an in-flight run
(already public and used by the CLI's status), but no UI surface read it.
Add the shared isCronJobRunning helper, exclude running jobs from the
overdue filter, and render 'Running' in the next-run cell.

* test(cron): move running-state row test beside the capped view suite
2026-08-14 11:07:08 -07:00
Josh Lehman 84c2d64206 fix(ui): preserve new session drafts across navigation (#123697) 2026-08-14 11:01:28 -07:00
ClawSweeper eab9cf5ea4 fix(ui): preserve pinned widget identity (#123721)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-14 10:44:55 -07:00
ClawSweeper e03d1a42f8 improve(ui): collapse limited access notice (#123735)
* improve(ui): collapse limited access notice

* test(ui): follow limited access banner host

* test(ui): await limited access guidance host

* test(compaction): split context budget coverage

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-14 10:25:28 -07:00
ClawSweeper 0803505259 fix(ui): retire persisted steer chips immediately (#123744)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-14 10:22:40 -07:00
Josh Lehman ab363234f7 fix(ui): open image attachments in a lightbox (#123693)
* fix(ui): open attachment images in lightbox

* fix(ui): verify blob image types before navigation
2026-08-14 10:08:59 -07:00
ClawSweeper a875ead7ef fix(ui): prevent dashboard chat messages from overlapping (#123713)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-14 10:00:01 -07:00
Peter Steinberger fc5265d685 improve: tighten newest regression ownership (#123606)
* test: tighten newest regression ownership

* test(ui): stabilize request-driven e2e waits

* fix(ci): stabilize lifecycle-bound test observations

* test(ci): pin current Telegram job cap

* test(ui): wait for terminal selection owner

* test(mac): use shared unread wait policy
2026-08-14 08:08:45 -07:00
Josh Lehman c23c188902 fix: explicit agent ownership no longer breaks system surfaces (#123339)
* fix: honor explicit agent ownership in system surfaces

* oc-000: fix explicit-owner runtime preparation
2026-08-14 06:52:21 -07:00
Peter Steinberger 5523f8a334 fix(ui): surface the autosave reconnect latch instead of silently never saving (#123663)
When a gateway connection is replaced while a config form draft is
dirty, autosave intentionally latches off (autoSaveRequiresExplicitSubmit)
until an explicit Save — but the latch was invisible: the indicator
rendered nothing on idle, form mode has no Save button, and every
subsequent edit (plus the dispose-time teardown flush) silently never
saved. A recorded fact existed in the coordinator with no read where
the operator needed it.

The latch now projects a visible "paused" autosave status owned by the
same arm/clear transitions (conflict outranks it; local edits cannot
clear it), and the save indicator renders "Autosave paused after
reconnect" with a Save action reusing the existing retry plumbing.
2026-08-14 06:36:00 -07:00
Peter Steinberger 946e49cb80 fix(ui): renaming a config map key that holds a stored secret dead-ends the draft or binds the wrong credential (#123571)
* fix(ui): block renaming config map keys that still hold redacted secrets

Renaming a map entry whose value is the server redaction sentinel moves
the sentinel to a new key. The gateway's exact-key restore then fails
closed forever (dead-end draft with a Retry that can never succeed), and
when the rename is folded with a delete of the target key inside one
autosave window, the restore silently binds the deleted entry's old
credential under the new name and drops the intended one — a green
Saved with the wrong secret.

The rename handler is the only owner that knows a sentinel was moved
rather than typed, so it now rejects the rename like the existing
duplicate-key guard and explains the retype path via input validity.
Plain values rename exactly as before.

* chore(ui): record startup JS growth for the redacted-rename guard string

The renameRedactedBlocked validity message in the startup en locale adds
65 gzip bytes over the recorded baseline; record the CI-measured size
per the established baseline pattern.
2026-08-14 06:34:24 -07:00
Peter Steinberger 45d5b5ef51 fix(ui): empty-string i18n params rendered the raw {placeholder} (#123474)
t() interpolation used || so a provided empty-string param fell through to
the visible {placeholder} fallback meant for missing params — e.g. the
devices page rendered 'Bound to {node}' whenever an agent binding was the
empty string. ?? keeps the missing-param debugging aid and renders provided
empties as empty.
2026-08-14 06:26:21 -07:00
Peter Steinberger c3d16060d4 fix(ui): oversized attachment kills the whole gateway connection instead of being rejected client-side (#123654)
* fix(ui): validate attachment size against hello policy before encoding

The gateway advertises decoded-size attachment ceilings in hello-ok
policy.attachments precisely so clients can validate before sending,
but the Control UI never read them. A file over ~18.7MB decoded
expands past the gateway's 25MiB WS frame cap: ws hard-terminates the
connection (1009) for every pane and session in the tab, the message
parks as waiting-reconnect with wrong copy, and manual retry kills the
connection again.

appendAttachmentFiles — the single funnel for file input, paste, drop,
and plus-menu — now rejects oversized files up front with a named
toast, mirroring the terminal-upload sibling guard. Limits thread from
hello policy at both composer assembly sites (chat pane, new-session);
absent policy means no client-side cap, matching older gateways.

* refactor: keep chat-pane-render under the line cap

The attachmentLimits prop tipped chat-pane-render.ts to 701 counted
lines (cap 700, main sits exactly at cap). Compact the checkpoint
deep-link callback and read limits from the pane's own hello snapshot.
2026-08-14 06:24:19 -07:00
Peter Steinberger 5972b36b14 test(ui): make model auth scoping proof route-owned (#123661) 2026-08-14 06:24:04 -07:00
Peter Steinberger 1f61c9e295 test(ui): stabilize activity and workboard e2e waits (#123664) 2026-08-14 06:23:18 -07:00
Peter Steinberger e342e02b6f test(ui): capture mock gateway timeout diagnostics (#123650) 2026-08-14 05:50:05 -07:00
Peter Steinberger f39f48f7b9 fix(ui): hiding a catalog makes its adopted sessions vanish from the entire sidebar (#123481)
* fix(ui): hiding a catalog no longer makes its adopted sessions vanish everywhere

The adopted-key exclusion set was computed from the unfiltered catalog list
while the renderer shows only visible catalogs (hidden ids filtered; none
under the Archived filter). Hiding a catalog therefore removed its adopted
sessions — possibly running, unread, or selected — from the entire sidebar
with no row anywhere. One visibleSessionCatalogs() projection now feeds both
the renderer and the exclusion; the subclass's duplicate filter is deleted.

* refactor: fold sidebar catalog projection into its owner module

The visibleSessionCatalogs projection and adopted-PR-row merge pushed
app-sidebar-session-navigation.ts over the 700-line lint cap. Move the
projection predicate to app-sidebar-session-catalogs.ts (the catalog
helper owner) and the PR-row merge to the navigation-logic module,
inlining the single-caller passthrough into the indicators controller.
2026-08-14 05:48:47 -07:00
Peter Steinberger 44dd983c0c feat(mac): add canonical elevation host workflow (#123569)
* feat(mac): add canonical elevation host workflow

* fix(mac): clarify elevation host deployment

* test(ui): stabilize cloud startup effort flow

* fix(mac): fail closed on unknown TCC status

* test: synchronize async CI boundaries

* test: remove remaining CI timing races
2026-08-14 05:39:24 -07:00
Peter Steinberger db6e238aff fix(ui): gateway client rotation silently discards plain staged attachments (#123628)
* fix(ui): gateway client rotation silently discarded plain staged attachments

replacePaneStagedAttachmentGatewayOwner discarded every staged
attachment when the gateway client object rotated — which happens on
event-gap recovery (laptop sleep/wake reconnect) and after plugin
install/enable, not just on real credential changes. Draft text
survived; attachments vanished with no error, so a user who staged
screenshots before sleeping delivered a text-only message.

Only browser-annotation attachments actually depend on the old client
(their Undo context dies with it). Plain file/image payloads are
client-local data URLs; rotation now drops annotation-backed
attachments and keeps the rest, in both live state and memory
fallbacks.

* test: align annotation-lifecycle rotation tests with selective discard

Three tests pinned the old wholesale-discard contract; rotation now
drops only annotation-backed attachments while plain payloads survive
(live state, fallbacks, and post-undo-toast state).
2026-08-14 05:33:25 -07:00
Peter Steinberger c9152fef4e test(ui-e2e): scale Control UI wait budget for loaded CI runners (#123623)
ui-e2e intermittently failed with `page.waitForFunction: Timeout 10000ms
exceeded` on loaded CI runners (model-agent-scoping, terminal-embedded),
both green on rerun. The 10s deadlines were repo-imposed at the mock
Gateway helper and readiness helper, plus twelve per-test
setDefaultTimeout sprinkles.

Give the harness one owner for the wait budget: 30s under CI, 10s
locally, mirroring the ui-e2e vitest config's existing expect.poll
reasoning. Suite-created contexts inherit it, so two per-test overrides
are deleted outright.
2026-08-14 05:20:45 -07:00
Peter Steinberger 08d41e55a5 refactor(ui): one token formatter — the same count no longer renders two ways (#123472)
The UI carried three token formatters with proven divergence: 15,600
rendered as 16k on the Sessions page (formatTokens) but 15.6k in the chat
composer and /usage (formatCompactTokenCount); 999,600 as 1.0M vs 999.6k.
The message-meta cost line also bypassed formatCost with a hardcoded
toFixed(4), showing $1.2346 next to a popover showing $1.23.

formatCompactTokenCount is now the one owner: it absorbs formatTokens'
nullish fallback and model-providers' local billion-suffix wrapper (both
deleted), and the message cost line goes through formatCost. Production
net −19.
2026-08-14 05:09:05 -07:00
Peter Steinberger c3ae887f46 fix(ui): autosave acks no longer wipe open add-entry drafts and in-progress JSON (#123502)
A drained autosave ack (and the config.changed refresh path) clones the
whole config form, changing every object/array identity while content is
byte-identical. The collection add-entry draft closed on identity change
and the JSON textarea reset its uncommitted text — the operator's typing
vanished ~1s after any earlier toggle. Both guards now check content
equality when the identity churns; a genuinely external content change
still closes/resets as before.
2026-08-14 04:51:26 -07:00
Peter Steinberger 37a63fbf45 fix(ui): catalog continuation silently dropped staged attachments (#123581)
A continuable catalog session exposes the full attachment surface
(file inputs, plus-menu, paste), and the send button counts staged
attachments as composed content — but continueCatalogSession required a
non-empty text draft and always handed off attachments: []. Draft+images
sent text only with the images silently vanishing (payloads leaked,
never released); images-only made the enabled send button do nothing at
all: the worst bug class, an action with no visible outcome and no
recorded reason.

Carry independently-owned attachment clones through the continuation
handoff, mirroring the new-session sibling
(chat-pane-session-creation.ts), and treat attachments as composed
content in the guard so attachment-only continuations send. Empty
draft with no attachments still no-ops.
2026-08-14 04:36:08 -07:00
Peter Steinberger ee6c2cb50d fix(ui): terminal actions disappear during Gateway updates (#123578)
* fix(ui): replay terminal actions across refresh fences

* refactor(ui): isolate terminal pending action journal

* refactor(ui): remove terminal storage import cycle

* test(ui): release worker update fence explicitly

* test(ui): gate worker install with held response

* fix(ui): fence stable-client terminal reconnects

* fix(ui): carry selected agent through terminal toggle

* fix(ui): keep terminal toggle event shape stable
2026-08-14 04:34:51 -07:00
Peter Steinberger 7aac8ee04b fix: preserve device sessions while runner is offline (#123477)
* fix(runners): recover offline device placements

* test(runners): model reclaimed launch dispatch

* ci: serialize macOS Swift test retries

* test: wait for steering subscription readiness

* fix(gateway): restore authority-safe steering

* test(gateway): align authority projector fixture

* fix(gateway): dispatch leaf authority mismatches

* refactor: keep authority overlay contract leaf-only

* test(ui): close place popover before details
2026-08-14 03:31:19 -07:00
Jason (Json) 4c37947a33 fix: managed images render under Control UI base paths (#123592)
* fix(control-ui): serve managed images under base path

* test(ui): align managed-media base-path contract
2026-08-14 03:08:32 -07:00
Peter Steinberger 678c89c550 fix(ui): partial tool output no longer flips a running card to succeeded (#123510)
The live tool stream emits a toolresult block for partial update output
(so streaming stdout renders), but the card extractor treated any result
block as completion — spinner gone mid-execution, and partial text that
looks like an error badged the still-running tool Failed. Live cards'
completion is owned by the stream's resultReceived marker (per the
producer's own contract comment); the result branch now defers to it.
2026-08-14 02:29:02 -07:00
Peter Steinberger 06e23130cb fix(ui): revealing a stored secret displayed the redaction sentinel as an editable value (#123493)
config.get never sends plaintext secrets — stored values arrive as the
__OPENCLAW_REDACTED__ sentinel. The reveal eye had no sentinel awareness:
clicking it showed the literal sentinel in a now-editable input, and any
edit broke the exact-match restore so the mangled text was written over
the real credential with a green Saved. Sentinel values are now never
revealable (input stays readonly) and the disabled eye explains why.
2026-08-14 02:27:06 -07:00
Peter Steinberger 1011b4102f fix(ui): restore custom page and session ordering (#123530)
* fix(ui): restore interleaved sidebar ordering

Render pinned sessions at their persisted slots among page entries again instead of projecting them into a separate group. This restores custom page/session interleaving regressed by #121712 while preserving drag-to-pin behavior.

* test: consolidate steering authority fixtures

* test: isolate CLI commentary fixture

* fix: dispatch tool-bound turns normally
2026-08-14 02:00:03 -07:00
Jason (Json) 0bd50cc0a5 fix(ui): preserve delayed final turn order (#123560) 2026-08-14 01:41:34 -07:00
Peter Steinberger 204be37803 fix(ui): stale tabs lose terminal owner after Gateway updates (#123526)
* fix(ui): refresh stale clients before terminal reconnect

* fix(ui): hold reconnect fence through worker activation

* fix(ui): isolate reconnect worker refresh

* refactor(ui): own reconnect fence in terminal lifecycle

* test(ui): satisfy reconnect refresh lint
2026-08-14 01:32:33 -07:00
Peter Steinberger 8ace19a071 fix(ui): unkeyed preamble segments corrupted the accumulated-stream prefix tracker (#123515)
itemId-less preamble segments carry standalone text, but the tracker
treated any itemId-less segment as cumulative run text. A preamble made the
tracker diverge from the real cumulative prefix, the next snapshot failed
startsWith, and every earlier segment's text rendered twice — persisted at
terminal materialization. advanceAccumulatedStreamText now owns the
continuity rule at all four advance sites: only text that extends the
current baseline becomes the new baseline.
2026-08-14 00:26:24 -07:00
Peter Steinberger 73e2489a5e test: delete final plugin and UI duplicates (#123214)
* test: delete final plugin and UI duplicates

* test(ios): remove duplicate watch reply case

* test(nostr): isolate ambient private key

Co-authored-by: Josh Avant <830519+joshavant@users.noreply.github.com>

---------

Co-authored-by: Josh Avant <830519+joshavant@users.noreply.github.com>
2026-08-14 00:20:09 -07:00
Peter Steinberger 00dbf6fd85 fix(ui): zone writes during startup no longer erase persisted Workboard pins (#123475)
The reconciler dropped workboard entries from the canonical persisted list
whenever workboardEnabled was false — but enablement reads as disabled until
the runtime config snapshot loads, so any pin/unpin/drag in that window
permanently deleted every workboard pin from synced prefs. The boards-not-
ready branch already preserved slots for exactly this ambiguity; disabled
now folds into it. Prod net −1.
2026-08-14 00:19:31 -07:00
Peter Steinberger e5fca42952 fix(apps): per-session desktop button opens that session's machine (#123412)
* fix(apps): open session desktop on its machine

* fix(ui): scope the desktop session lookup to the key's own agent

`sessions.list` has no exact-key filter, so the viewer resolves a `session=`
parameter by searching for the key and matching it exactly in the response. A
key that prefixes longer ones — `agent:main:main` alongside user-named sessions
that start the same way — could push the exact row outside a five-row page and
silently fall back to the picker.

Session keys encode their agent and the list API accepts `agentId`, so scope the
search to that agent and widen the page.

* refactor(ui): stop parking a session key in the desktop environment id

Document-mode inventory failures stashed the requested session key in
`environmentId` purely so the Retry button's non-null guard would pass, even
though document-mode retry refreshes the inventory and never reads the value.
A session key only names a machine once the inventory loads, so it now stays
out of `environmentId`, and the retry branch that ignores it runs before the
guard. Adds E2E coverage for recovering a session-preselected desktop.

* fix(ui): resolve the desktop session with an exact-key lookup

The session-preselect path searched `sessions.list` and scoped the search to
the key's own agent, but a bounded search cannot rule a key out: 25 newer
same-agent sessions sharing the requested key's prefix would push the exact row
off the page, and the viewer would report the source as unavailable for a
session that exists. `sessions.describe` is the exact-key operation and already
projects placement, so the panel calls it directly and the app-root resolver
plumbing goes away with it.

* refactor(ui): move the desktop document keyboard bridge into its own controller

`desktop-panel.ts` crossed the 700-line cap. The mobile keyboard bridge — the
padded sentinel, the value diffing that turns composed input into backspaces
and text, and the field focus/reset helpers — is a self-contained concern, so
it moves into a `DesktopMobileKeyboard` controller alongside the existing
fullscreen controller instead of taking a `max-lines` suppression.

* test(ios): drain text fields instead of assuming a delete burst lands

`testReleaseChatScreenshot` typed a 5-character probe, sent 5 deletes in one
`typeText`, then asserted the field was empty. CI dropped one synthetic
keystroke under simulator load and the assertion failed with a leftover "f".
XCUITest makes no lossless-burst guarantee, so clearing now re-sends against
whatever the field actually still holds, bounded. The two gateway-setup fields
that overtyped through the same burst use the helper for the same reason.

* fix(ui): keep the chat placement owner out of the startup chunk

`desktop-document-mode.ts` is imported by bootstrap, so importing the chat
placement owner from it pulled the chat page's dependency tree into the startup
bundle and pushed startup JS past its gzip budget (331075 B against a 330507 B
allowance). The route module now only parses the URL; resolving a session to its
machine moves next to the lazily loaded desktop panel, which is the only caller.
Startup JS is back to 329710 B.
2026-08-13 23:33:19 -07:00
Ayaan Zaidi c6dbc96cbf fix(ui): drop empty sidebar session lead columns (#123505)
Reserved 16/20px indicator slots indented titles when there was no artwork.
2026-08-14 11:22:16 +05:30
Josh Avant 49275b8f4b fix(ui): stop agent roster retry storms (#123483) 2026-08-14 00:24:48 -05:00
Josh Avant 9496a4b199 fix(ui): scope model reads to selected agent (#123415)
* fix(ui): scope model reads to selected agent

* test(ui): align selected-agent diagnostics coverage

* test(ui): scope debug diagnostics expectation

* fix(ui): route model reads through canonical owners

* refactor(ui): narrow model ownership repair
2026-08-13 23:40:34 -05:00
Peter Steinberger d540905f56 fix: terminals and model setup fail in explicit-agent fleets (#123429)
* fix(gateway): preserve explicit setup owners

* fix(gateway): complete explicit setup owner coverage
2026-08-13 21:32:41 -07:00
Peter Steinberger 92eed63f58 fix(ui): repair shared vitest lane cross-file leaks (#123453)
The non-isolated |ui| lane resets the module graph per test file while the
jsdom document and customElements registry persist for the whole worker.
Three producers leaked across that lifetime mismatch:

- github-link-hovercard-registration.ts: each file's module instance adds
  document-level bootstrap listeners; on the first real focusin every stale
  instance raced customElements.define -> unhandled NotSupportedError.
  Guard the define inside the single-flight loader.
- app-host.test.ts locale retry asserted through createElement, which serves
  a sibling graph's shell class bound to a different i18n singleton; construct
  ShellGatewayOwner directly so spy and callee share one graph.
- route-transition.test.ts assigned updateComplete over the real Lit outlet's
  getter-only accessor when a sibling had registered it; define an own data
  property instead (byte-identical to the hunk in PR #123347).

Adds a boundary regression test reproducing the duplicate-module-instance
order; it failed pre-fix with 2 registry defines and the NotSupportedError.
2026-08-13 21:12:57 -07:00