Commit Graph

5682 Commits

Author SHA1 Message Date
Josh Avant 1c37c8cdc7 fix(exec): scope reusable approvals to their working directory (#129636)
* fix(exec): bind durable approvals to working directory

* chore(apps): refresh native string inventory

* test(node-host): preserve prepared working directory

* fix(exec): use shared path safety facade

* fix(exec): revalidate approved directory identity
2026-08-25 18:24:14 -07:00
RoboClaw 238c884986 fix(ui): expose mobile Inbox dismiss actions (#129379)
Keep per-item dismissal visible on touch layouts, add selected-tab Dismiss shown for dismissible entries, and preserve non-dismissible approvals.

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-25 18:09:17 -07:00
RoboClaw d6510fa961 fix(ui): show delegated work on selected threads (#129328)
Fixes #129318

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-25 18:07:10 -07:00
Peter Steinberger 6133ad92a0 fix(ui): show resolved agent workspace and effective model consistently (#129701) 2026-08-25 17:36:28 -07:00
Josh Lehman 2dbaeef693 fix(ui): keep active commentary after session navigation (#129640)
* fix(ui): restore active commentary after navigation

* test(ui): wait for responsive activity layout
2026-08-26 00:27:41 +00:00
Peter Steinberger 18ad0dda91 test: remove duplicate model-readiness assertion (#129683)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b5-3918-749f-90bd-5c9ac1dced16

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 17:18:20 -07:00
Peter Steinberger c2602193d6 fix(ui): honor forced filtered session roster refreshes (#129484) 2026-08-25 17:13:48 -07:00
Peter Steinberger fbd067732a fix(ui): show channel configuration save errors inside the editor (#129654)
* fix(ui): show failed channel saves inside the settings editor

* test(gateway): isolate captured agent command calls between cases

* test(gateway): mock canonical terminal transcript lifecycle decision

Co-authored-by: Dallin Romney <dallinromney@gmail.com>

---------

Co-authored-by: Dallin Romney <dallinromney@gmail.com>
2026-08-25 17:04:17 -07:00
Peter Steinberger 088c45ab7c fix(ui): clear provider credential drafts when switching agents (#129676) 2026-08-25 17:00:32 -07:00
Vyctor H. Brzezowski 64853b1a9d improve(control-ui): restructure the composer as a multiline surface (#124301)
* improve(control-ui): align composer stack with current main

* refactor(ui): isolate new-session permission state

* fix(ui): close composer CI regressions

* test(ui): align composer presentation contracts

* test(ui): fix composer browser contracts

* test(ui): stabilize composer browser ownership

* test(ui): target presented mobile composer

* test(ui): select accessible mobile composer

* test(ui): open mobile rail session directly

* fix(ui): keep mobile composer content laid out

* fix(ui): address composer review findings

* fix(ui): close composer interaction gaps

* fix(ui): bound swarm task popover

* fix(ui): restore progress-card docking beside the wide composer

The multiline restructure dropped the .session-progress-card--dock
placement shipped in #129141 and left the completed marker inside the
collapsed-only summary span, so it vanished when the disclosure opened.
Restore the dock positioning block and hoist the marker into the
always-visible summary grid.

* fix(ui): bound swarm task popover by its composer anchor

The popover capped its height against the raw viewport, so on short
mobile viewports its top rendered above the screen. Register the swarm
group with the existing composer popover anchor observer and consume the
measured --chat-composer-popover-max-height, keeping the viewport calc
only as fallback. The new actual-tree mobile regression failed with
-71px top clipping before the fix.

* fix(ui): restore Draft capability controls and split the new-session composer

Restores the Draft option and selected-state indicators the capability
menu lost in the restructure, and moves the capability/visibility
controls into composer-capability-controls.ts so composer.ts drops back
under the 700-line lint gate (677 lines) without a suppression.

* test(ui): prove permission-mode final effect before session creation

Adds mocked-gateway proof that an admin's Full selection reaches
sessions.create as permissionMode:"full" exactly once, and that a
write-scoped operator's retained Full selection is rejected before
creation with a visible status notice and zero create requests. Also
aligns the mobile footer reading-order assertion with the shipped
attachments-draft-model order.

* test(ui): register swarm popover layout test as node-driven

chat-swarm-progress.browser.test.ts drives its own Playwright chromium
from node, but d3396c4d3b added it without registering it in
nodeDrivenBrowserLayoutTests, so the browser-mode chromium project tried
to fetch it into the page and failed on the node-only playwright import.
This was the deterministic checks-ui failure on both prior heads.

* test(ci): register codex attempt-startup-retry in its support lane

#129505 added extensions/codex/src/app-server/attempt-startup-retry.test.ts
without lane ownership, so the full-suite coverage guard
(test/vitest-projects-config.test.ts) fails on every full run. Register it
beside attempt-startup.test.ts in the attempt-support lane.

* test(ui): expect last-activity suffix in composer summary label

Merge weave: #129520 appends the accessible last-activity to the summary
aria-label; align the restructured composer card's assertion with it.

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 16:59:46 -07:00
RoboClaw 3cc64f90ed fix(ui): keep pinned sidebar pages through reconnect (#129517)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 16:44:05 -07:00
Peter Steinberger e2c8dae785 fix(ui): stop warm sidebar refreshes from blanking foreign-owned rows (#129558)
* fix(ui): stop warm sidebar refreshes from blanking foreign-owned rows

The owner-first roster plan (#128767) published its provisional owner-only
window as a full membership replacement on every primary refresh, so on
multi-owner gateways every other user's sessions blinked out of the sidebar
until the shared merge landed - up to once a second under event load. The
provisional phase now publishes only when no roster is on screen (cold start
keeps its fast first paint), and the shared phase merges the owner window
from the initial load's returned rows instead of reading published state;
the mergeExisting option is gone. A warm refresh whose shared phase fails
now keeps the previous roster instead of collapsing to owner-only rows.

The thread and child session lists also rendered rows positionally with
map()+keyed(), so any reorder tore down and rebuilt every shifted row's DOM
(spinners restarting, avatars remounting). Both now use repeat() with key
identity, matching the catalog renderer.

Regression coverage: owner-first-roster.test.ts pins the publish-sequence
invariant and shared-failure retention (both fail pre-fix); the new browser
test proves row DOM identity survives a reorder (fails on map()). The
owner-first tests moved out of index.event-refresh.test.ts, which hit the
max-lines limit.

* test(ui): prove foreign-owned rows survive a warm owner-first refresh

Browser-level regression for the warm-refresh half of this fix: holds the
shared phase deferred after a sessions.changed event and asserts the
foreign-owned row never leaves the DOM. Fails on pre-fix code (the row
count drops to zero the moment the provisional owner window publishes).

* test(anthropic): pin the local retired-profile id to the plugin-sdk constant

The provider-policy artifact keeps this id as a local literal so it never
imports the provider-auth barrel (#129052 regressed dist-less CI checkouts
into 120s jiti compiles of ~2.2k modules); this parity test stops the two
constants from drifting apart.
2026-08-25 16:38:55 -07:00
Peter Steinberger 0246aaf06d improve(ui): speed up session loading and chat rendering (#129656)
* perf(ui): reduce session loading and render overhead

* test(ui): align shell fixtures with appearance settings owner
2026-08-25 16:32:12 -07:00
razshlomo a74080d5d5 fix(control-ui): chat Markdown preview renders RTL documents left-to-right (#129129)
* fix(control-ui): render the chat Markdown preview in its own text direction

The chat transcript already picks a direction per message
(`chat-message-markdown.ts` sets `dir` from `detectTextDirection`), but the
Markdown preview in the chat detail panel never did. A Hebrew or Arabic
document opened there rendered left-to-right: bullets and quote bars on the
wrong side, table columns in the wrong order, and sentence-final punctuation
detached from its sentence.

Detect the direction from the document source and set `dir` on the reader, then
let the shared `.sidebar-markdown` rules mirror with it by using logical
properties instead of left/right ones. Code blocks get `unicode-bidi: plaintext`
so each hard-wrapped line keeps its own direction — that also covers the raw-text
view, which renders the whole document as one fenced block. Block art carries no
strong characters, so it stays left-to-right as before.

Under LTR the logical properties resolve to exactly the previous physical ones,
so nothing changes for existing documents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(control-ui): make the task-list checkbox gap direction-aware

The sidebar sheet moved its indents, quote bar and cell alignment to logical
properties, but `.task-list-item-checkbox` kept `margin-right`. In an RTL
document the label sits to the left of the box, so the physical margin pushed
the gap to the outer edge of the row instead of between the box and its label
— the one remaining place in this sheet where direction still leaked through.

`margin-inline-end` is what the message renderer already uses for the same
control (`chat/text.css` positions it with `inset-inline-start`), so this also
lines the two sheets up.

The RTL and LTR browser tests each grow a task item and assert the computed
margin lands on the inline-end side, mirroring the existing quote-bar and
list-indent assertions.

Formatting proof (node_modules absent in this checkout, so the pre-commit
oxfmt hook could not run): oxfmt 0.60.0 --check and oxlint 1.78.0 both pass
on the changed test file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(control-ui): assert the checkbox gap by side, not against zero

The assertions added in the previous commit demanded the opposite margin be
0, and `checks-ui` failed on exactly that: 3px in RTL, 4px in LTR. Those are
the UA sheet's own `margin: 3px 3px 3px 4px` on an `input[type=checkbox]`.
The rule overrides only the inline-end side, so the opposite side keeps the
default and never reaches zero.

Assert instead that the sheet's 0.4em resolved onto the expected physical
side — margin-left under RTL, margin-right under LTR — which is the mapping
the fix is actually about and owes nothing to UA defaults.

Verified against a real Chromium before pushing: with `margin-inline-end`
both directions land 5.33px (0.4em of the 13.333px UA control font) on the
inline-end side; with the pre-fix `margin-right` the RTL assertion fails and
the LTR one passes, which is the regression shape this test exists to catch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ui(chat): scope the code-block bidi rule to the markdown reader

`unicode-bidi: plaintext` sat in the shared `.sidebar-markdown pre` rule, which
also matches the skills, session-progress-card and agent status-file previews.
Those surfaces never opt into a document direction, so this branch was changing
their code-block rendering while declaring them unchanged.

Move the declaration to `.sidebar-markdown-reader pre` — the chat preview is the
only consumer that sets `dir`. The shared layout properties stay shared, and the
existing direction test already queried the reader-scoped selector, so it is
unaffected. Adds a regression test pinning that a bare `.sidebar-markdown`
surface keeps its previous code-block rendering.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: yehezkel-assistant[bot] <3902212+yehezkel-assistant[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 16:31:32 -07:00
Peter Steinberger 5b0c094258 feat(ui): stack the docked progress card under the suggestion tray (#129443)
The suggestion tray and the docked progress card both floated over the
conversation's top-right area as independent absolutely-positioned
elements. The tray is 450px at z-index 24 and the card sat at z-index 3,
so whenever a suggestion arrived while a plan was live the tray covered
the card outright: session state disappearing with no trace, which is
the failure mode this repo weighs heaviest.

Give the gutter a single owner. .chat-gutter-stack is one absolutely
positioned column at top-right; the tray and the card become its
children and cannot overlap by construction. The tray keeps its exact
geometry (same inset, same width, position: relative only so its stacked
-card shadow still anchors to itself); the card right-aligns beneath it.

The card is now top-anchored rather than pinned to the composer's bottom
edge, so appended steps and a longer note extend downward instead of
shifting the rows already being read, and the empty gutter falls below
the card instead of above it. Its width becomes a fixed token rather
than gutter-derived arithmetic: the pane already gates this placement on
a measured gutter wide enough to hold it, so the clearance is guaranteed
and a stable card beats one that grows with the window.

Covered by a new placement case asserting the card sits fully below the
tray when both render.
2026-08-25 16:01:21 -07:00
Peter Steinberger df9b7a5fbe fix(ui): show accessible last activity on session progress cards (#129520)
* fix(ui): show accessible last activity on session progress cards

* fix(ui): validate progress activity timestamps at ingress
2026-08-25 15:47:56 -07:00
Josh Lehman 3f6f6799e9 fix: New Session adopts discovered models (#129307)
* oc-92a.8: converge dynamic chat metadata catalog

* fix(gateway): converge discovered model catalogs across sessions

Co-authored-by: Josh Lehman <550978+jalehman@users.noreply.github.com>

* test(gateway): satisfy deferred helper lint

* test(ui): bind model discovery proof to the active route

* chore: keep release notes in pull request metadata

* test(agents): preserve plugin metadata scope in model fixtures

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 15:33:11 -07:00
Peter Steinberger 18fba50e84 fix(linux): keep first-run onboarding alive when the gateway restarts (#129502)
* fix(linux): preserve onboarding through gateway restarts

* refactor(ui): keep model setup below file-size limit

* test: isolate plugin metadata and register startup retry coverage
2026-08-25 15:30:16 -07:00
RoboClaw 648c60775d fix(ui): keep generated session titles editable (#129529)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 15:23:09 -07:00
Peter Steinberger ce9a4c9a60 fix(ui): stop cloud tasks from silently switching to local execution (#129440)
* fix(ui): preserve selected cloud worker when runtime changes

* test(ui): stabilize disabled update touch interaction

* test(agents): remove redundant mocked metadata scope
2026-08-25 15:19:06 -07:00
Peter Steinberger 9afc4ef28e fix(ui): protect replacement sessions during delete confirmation (#129628) 2026-08-25 15:15:20 -07:00
Masato Hoshino 8c31fada1b fix(gateway): serve Control UI assistant media for uppercase file URLs (#121827)
* fix(gateway): normalize assistant media file URLs

Co-authored-by: masatohoshino <g515hoshino@gmail.com>

* fix(gateway): normalize webchat media at the producer

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 14:14:52 -07:00
Peter Steinberger 6eaf521cff improve(ui): faster session switching and smoother chat rendering (#129548)
* perf(ui): speed up session switching and transcript rendering

* test(skills): assert canonical learn authoring standards

* test(ci): include startup retry coverage in its owning shard

* test(agents): reuse scoped metadata in alias regression
2026-08-25 14:05:20 -07:00
Josh Avant f9dbda38dc fix(mcp): revoke resource access with app authority (#129550) 2026-08-25 14:04:14 -07:00
Peter Steinberger 0e9b6bccb2 perf(test): skip routine Workboard sibling proof capture (#129596) 2026-08-25 14:03:22 -07:00
Peter Steinberger a6ebad9964 fix(worker): honor full access on paired node sessions (#129537)
* fix(worker): honor full access on paired node sessions

* test(worker): preserve narrowed operator in live proof

* test(vitest): assign Codex startup retry to its owner shard
2026-08-25 14:01:39 -07:00
RoboClaw 7642587232 fix(ui): model Inbox alert dismissibility (#129495)
Make every Inbox producer declare a dismissal fact or null so stable limited-access guidance can retire without hiding active requests, approvals, or forced updates. Derive counts and rendering from one typed entry list and persist snoozes per browser and Gateway.

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-25 13:47:21 -07:00
Vyctor H. Brzezowski c71c16ce1a fix(ui): preserve routable models across reconnect (#128694)
* fix(ui): refresh model catalog after reconnect

* chore(ui): refresh boot manifest

* chore: refresh PR merge ref

* chore(ui): refresh boot manifest after rebase

* chore(ui): align boot manifest with current main
2026-08-25 17:43:26 -03:00
Peter Steinberger a8d5350499 fix(ui): automation actions fail and schedule changes unexpectedly (#129469)
* fix(ui): keep automation actions and schedules valid

* test(ui): keep cloned stream schedule fixtures mutable

* test(ui): register pairing sidebar before lifecycle teardown

* fix(anthropic): keep provider policy artifacts lightweight

* test(vitest): assign codex startup retry to its owner shard
2026-08-25 13:21:09 -07:00
Sasan e9620fba9d fix(gateway): usage.status no longer waits on provider HTTP (#121799)
* fix(gateway): refresh provider usage asynchronously

* fix(ui): report a stalled provider-usage refresh on Model Providers

The page observed the incomplete-usage marker but discarded the exhausted
outcome, so once the retry budget was spent it rendered ordinary provider
cards with no usage and no explanation — indistinguishable from providers
that report no usage at all. Keep the outcome and render the warning the
Usage page already owns, reusing usage.providerUsage.stalled rather than
minting a Model Providers key so no locale baseline churns.

A user-initiated refresh now restarts the retry budget. The notice tells the
operator to refresh, so the button has to hand back attempts to spend; only
the forced path resets it, or the budget could never exhaust.

Also fixes tsgo:core:test on the current head: createStore's inferred literal
had no usageStats, so the run-bookkeeping case could not stamp it, and
view.test.ts needed the new prop.

Closes the ClawSweeper P2 at model-providers-page.ts:169-175.

* fix(ui): keep the stalled usage notice when usage.status starts rejecting

loadModelProvidersData turned a rejected usage.status into providerUsage:
null, which the page read as a completed load. observe(false) then reset the
retry budget and cleared the stalled callout, so a permanently broken usage
endpoint rendered as ordinary cards with no usage and no explanation — the
same silent failure the callout was added to prevent. The reset also fired
mid-cycle: one incomplete response followed by one rejection restarted the
budget, so the notice could be deferred indefinitely.

Record the failure at its producer instead of inferring it downstream. A null
providerUsage also means "not loaded yet", and no caller can tell the two
apart, so load.ts now reports providerUsageFailed explicitly and the page
treats a failed read as unresolved rather than resolved-empty.

Found by a Codex review of 417d43b65d.

* revert(gateway): drop the opportunistic model-catalog fast path

It broke two chat.history tests on main — both assert the cold catalog loader
runs exactly once, and reading the prepared snapshot first means it never does.
checks-node-compact-small-10 was red for that reason.

The change was a separate-surface latency fix that this PR picked up in passing,
and the body already offered to split it. Dropping it is the honest resolution:
rewriting main's assertions to accommodate a drive-by optimization would trade
one concern's proof for another's convenience. optional-model-catalog.ts,
server-model-catalog-auth.ts and their test return to the merge-base.

This PR is now only the usage.status non-blocking contract and its clients.

* fix(usage): preserve incomplete retry state

* perf(ui): keep usage capability startup-neutral

* fix(ui): restore provider usage retry convergence

* fix(usage): restore retry and cache invariants

* fix(usage): stabilize provider convergence

* test(ui): exercise provider recovery path

* test(ui): remove stale usage route fixture field

* fix(macos): show provider usage errors

* fix(macos): bound usage retries per menu open

* fix(macos): end usage retries on menu close

---------

Co-authored-by: Josh Lehman <550978+jalehman@users.noreply.github.com>
2026-08-25 13:20:10 -07:00
Peter Steinberger 99fbe2207f fix(ui): usage filters hide sessions when multiple providers are selected (#129482)
* fix(ui): make usage multi-select and quoted filters work

* fix(anthropic): keep provider policy artifacts lightweight

* test(vitest): assign codex startup retry to its owner shard
2026-08-25 13:19:18 -07:00
Peter Steinberger 8dd7bc5320 perf(test): make Workboard browser proof capture opt-in (#129554) 2026-08-25 12:36:37 -07:00
Peter Steinberger a6810bb00e fix(ui): align sidebar unread dot with pull-request rows (#129477)
The trailing unread dot sat 3.5px inboard on rows that also show a
pull-request icon, so the dots did not form one column down the sidebar.

`.session-row-state` centred its glyphs as one flex box, which only lands
the glyph on the action-icon axis when the box holds exactly one glyph.
Give each glyph its own fixed 14px grid track instead, so the trailing
glyph keeps that axis regardless of what precedes it.
2026-08-25 10:26:53 -07:00
Shakker ce62d6db74 test: await lazy sidebar load before teardown (#129376)
* fix: drain lazy UI module loads in tests

* test: await lazy sidebar before teardown
2026-08-25 15:47:28 +01:00
Colin Johnson 081ce11324 feat(ui): add collapsible Workboard columns (#128115)
Co-authored-by: Solver <solver@localhost>
Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
2026-08-25 08:22:03 -04:00
Peter Steinberger d94dd51276 refactor(ui): deduplicate workboard metadata normalization (#129280) 2026-08-25 05:03:28 -07:00
Peter Steinberger 4dc7bb7411 chore(deps): refresh dependencies after seven-day cooldown (#129187)
* chore(deps): refresh dependencies after cooldown

* fix(gateway): emit append-only Responses content events

* chore(deps): retain unverified Sherpa runtime
2026-08-25 05:00:46 -07:00
Peter Steinberger 22fa9f5786 fix(linux): first-run desktop onboarding automatically connects working AI (#129211)
* fix(linux): make desktop AI onboarding work automatically

* fix(linux): harden provider ownership and onboarding lifecycle

* test(ui): document partial onboarding context fixture

* fix(linux): preserve operator-owned onboarding API keys

* fix(linux): retire previously managed provider credentials

* fix(linux): retain rotated onboarding provider credentials
2026-08-25 04:47:35 -07:00
Peter Steinberger 1fdd10bf6a fix(gateway): prevent live profile retries from replacing runtimes (#129239)
* fix(gateway): isolate live model session scopes

* test(ui): bound streaming markdown benchmark

* test(gateway): carry prepared live model auth into isolated profiles

* test(gateway): keep fallback sessions write-scoped
2026-08-25 04:44:55 -07:00
Peter Steinberger b579f3ee3f fix(ui): preserve confirmed cloud profile deletion across reconnects (#129245)
* fix(ui): preserve confirmed cloud profile deletion across reconnects

* fix(ui): bind cloud profile deletion to gateway client identity
2026-08-25 04:25:56 -07:00
Peter Steinberger 6fb3303492 perf(ui): parallelize session roster loads (#129175)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b3-be95-76ea-8fb3-75979929acf1

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 02:17:18 -07:00
Peter Steinberger 7e8412e080 fix(ui): stabilize the sidebar session list with a single projection owner (#129150)
* fix(ui): stabilize sidebar session list with a single projection owner

The sidebar flickered as gateway events arrived: rows popped out when runs
ended (active/pinned page bypass), rows jumped within createdAt ties after
paging (per-publish created-order pruning), child trees auto-collapsed when
a descendant went idle (per-render derivation), and running-row subtitles
blank-flashed between observer/narration updates.

SidebarSessionProjection now owns all presentation stability for the
sidebar lifetime: sticky page membership with user-action reset boundaries,
a monotonic bounded created-order registry, latched child expansion with an
explicit collapsed-by-user mode, and a last-subtitle hold per active run.
The scattered mechanisms it replaces are deleted (limitSidebarSessionRows,
partitionSidebarVisibleSections, per-publish order pruning, three expansion
key sets).

* fix(ui): hold running-row subtitles across run rotation with a display floor

Live A/B on a dev gateway showed two residual subtitle defects: the hold
was keyed to the exact active-run-id set, so the queued->running rotation
still blanked the row, and racing ambient sources (observer digest,
narration, work path) swapped the line A->B->A within a second.

The hold now lives for the session's running lifetime and ambient
replacements respect a 2s minimum display floor (matching the narration
throttle); attention, agent status, and the queued explanation bypass the
floor because the operator must act on them.

* test(ui): assert subtitle holds on non-localized sources

The run-rotation and critical-replacement tests asserted the localized
queued string through the shared i18n singleton; in the striped ui CI lane
(shared module graph, isolate=false) that resolution is environment-
sensitive and failed in checks-node-compact-large-11. Narration and
agentStatusNote exercise the same hold invariants with raw strings.

* fix(ui): reset sticky sidebar membership when grouping changes

ClawSweeper finding: grouping switches can re-emit the same section id
(e.g. ungrouped) with a different row population, so sticky keys must not
carry across; grouping now joins the membership reset boundary with a
regression row in the boundary table. The created-sort e2e migrates to the
sticky contract: an externally discovered newest session still lands on
top, and the previously visible page is retained instead of evicted.
2026-08-25 02:12:42 -07:00
Peter Steinberger 24898ba894 fix(workers): repair cloud session lifecycle and recovery (#121564)
* fix(workers): repair cloud session lifecycle and recovery

* test(workers): preserve dual-mode provider dispatch coverage

* refactor(workers): centralize inherited profile authorization
2026-08-25 01:48:57 -07:00
Peter Steinberger 5b5fdacfda feat(ui): dock the session progress card beside a wide composer (#129141)
* feat(ui): dock the session progress card beside a wide composer

The progress card had two placements: the companion rail when that side
panel is open, otherwise a collapsed one-line bar stacked inside the
composer box. On a wide chat the composer stays centered at the
transcript width, so the space either side of it sits empty while the
card is squeezed into the composer.

Add a third placement. When the measured free gutter beside the composer
is at least 280px, the card docks into it with its full checklist
expanded; below that it falls back to the existing composer bar, and an
open companion rail still wins. Exactly one placement renders at a time,
now expressed as a closed {card, placement} prop so the composer bar and
the dock cannot both draw the same card.

The gutter is measured from the DOM by a small ResizeObserver controller
rather than derived from the pane width: the transcript width is a
browser-local setting in arbitrary CSS units, and an open side panel
shrinks the conversation column without changing the pane. The dock is
positioned absolutely in that gutter, so the transcript and composer
never shift when a card appears or is dismissed, and its inline-start
edge repeats the composer's own half-width formula through a shared
--chat-composer-side-inset token so the two stay in agreement.

* fix(ui): keep the new-session composer sized outside the chat surface

The composer shell tokens are declared on .chat, but the new-session page
reuses .agent-chat__composer-shell outside it. There the var() had no
value, so the whole width declaration was invalid and dropped, and the
composer stretched full-width instead of holding its 48rem centered box.

Give both tokens their literal fallback at the use site, matching the
neighbouring --chat-thread-max-width. The custodian surface was already
immune because it overrides width outright.

Caught by ui/src/e2e/new-session-page.places.e2e.test.ts, which is the
regression test for this: it failed on the previous head and passes now.
2026-08-25 01:34:09 -07:00
RoboClaw 51825130d8 fix(ui): hide archived threads from sidebar immediately (#129153)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 01:32:30 -07:00
RoboClaw e485212348 fix: keep message identity stable through send failures (#129127)
* fix(ui): keep failed sends inline

* fix(ui): preserve editable send failures

* test(ui): assert inline initial-send failures

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 01:29:02 -07:00
RoboClaw 991a3203d3 fix(ui): align owner avatars with labels (#129133)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 01:28:03 -07:00
Peter Steinberger 27e3eac75d fix(ui): preserve loaded history across pane eviction (#126979)
Loaded older Control UI history now remains available after retained-pane eviction and remount, preserving pagination state and the user's visible transcript.

Refs #126978.
Reviewed-by: @shakkernerd
2026-08-25 09:22:44 +01:00
Peter Steinberger 6eaf1b8cb6 refactor(ui): use canonical sessions usage request (#129137)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-8aa3-72eb-95f7-517a508319f6

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 01:18:30 -07:00
Peter Steinberger 1010a537a3 fix(ui): make session switching and history loading faster (#129111)
* fix(ui): speed up retained chat session switching

* test(ui): keep retained-pane coverage below file size limits

* chore(ui): leave release changelog to generated notes
2026-08-25 01:14:27 -07:00