Commit graph

1396 commits

Author SHA1 Message Date
Peter Steinberger
1f6f0d42dc
feat: start remote sessions without a repository (#147773)
* feat: start remote sessions without a repository

Offer a fresh isolated workspace for cloud and paired-device sessions while preserving explicit and saved repository choices. Use a private empty backing repository per session through the existing managed-worktree lifecycle, retaining reclaim, snapshot restore, and cleanup without copying the agent workspace.

* fix: preserve workspace intent and independent snapshot cleanup

Retain legacy source selections before Git discovery updates availability, keep ordinary snapshot expiry independent of allocation contention, and update the complete source-selection browser flow. Keep request mapping and validation at their existing owners while satisfying import-cycle and export checks.

* fix: retain allocation and cleanup error causes

* test: expect normalized workspace source preferences
2026-09-13 22:06:12 -07:00
Vincent Koc
1f3b87b35e
feat(artifacts): select assistant-delivered files by run (#147682)
* feat(artifacts): select assistant-delivered files by run

* test(artifacts): verify canonical generated protocol and complete file summaries

* test(gateway): prove retained scoped artifact downloads

* test(gateway): ingest fresh artifact documents from local files
2026-09-14 12:57:24 +08:00
Vincent Koc
3de18f60bd
feat(gateway): bind requests to selected profiles (#143587)
* feat(gateway): bind requests to selected profiles

Punchcard-Session: amber-timber-workshop-bk

* test(gateway): verify profile-bound wire admission and replay

Punchcard-Session: amber-timber-workshop-bk

* fix(gateway): preserve idle presence during profile refresh

Keep unchanged profiles out of presence writes while retaining explicit refresh and recipient preparation. Complete profile-bound test fixtures and regenerate the dependent Workboard asset pointers.

Punchcard-Session: amber-timber-workshop-bk

* test(gateway): repair context and loading-state fixtures

Punchcard-Session: amber-timber-workshop-bk

* test(gateway): verify instance retirement before agent dispatch

Punchcard-Session: amber-timber-workshop-bk

* test(gateway): verify session revocation during accepted steering

Punchcard-Session: amber-timber-workshop-bk

* chore(gateway): refresh embedded protocol assets

* test(ui): await Inbox fixture preload

* test(transcripts): bind Discord lifecycle fixture generation

* test(gateway): drain task fixture notifications

* fix(protocol): exclude profile ID primitive from generated registry

* test(gateway): simplify subscription fixture state setup

* test(gateway): preserve authority refusal through terminal admission

* fix(gateway): retain live profile refresh after runtime extraction

* test(agents): cover redaction with fresh transcript admission

* refactor(gateway): inline release version checks

* test(gateway): observe async runtime lease disposal

* test(gateway): supply profile refresh callbacks in lifecycle fixtures

* test(agents): assert recorder admission callback availability

* test(gateway): model native profile fixture node subscribers

* test(desktop): retain bounded viewer close diagnostics

* test(ui): keep cloud history aligned with placement failure

* test(ui): brace the desktop close bound
2026-09-14 12:35:53 +08:00
Vincent Koc
086471b22c
fix(ios): restore native chat routing and typography checks (#147598) 2026-09-14 11:59:27 +08:00
Peter Steinberger
9a84afd1f9
feat: show subagent status through claw motion and tooltips (#147753) 2026-09-13 20:31:59 -07:00
Peter Steinberger
61b87fa8bd
feat(macos): collapse completed work above chat replies (#147540)
* feat(macos): collapse completed chat work above replies

Keep final answers and attachments visible while completed commentary and tool activity fold into a reversible disclosure. Preserve phase and turn metadata, retain split native transcript projections across history refreshes, and keep active or unresolved work exposed.

* fix(macos): preserve commentary segment identity through replay

Use the Gateway segment marker to distinguish commentary from canonical messages, preserve it through native cache copies, and keep it out of answer settlement. Retain canonical identity across reasoning framing changes so cached and live finals converge.
2026-09-13 17:52:55 -07:00
Peter Steinberger
d7f01d3e16
feat: show rolling session recaps in Activity (#147441)
* feat: show rolling session recaps in Activity

* fix: respect lifecycle and viewer permissions for recaps
2026-09-13 16:40:49 -07:00
Peter Steinberger
17ee9fbffd
fix(chat): identify subagent activity by its display title (#147458)
Promote canonical task titles in native and web subagent activity rows while keeping status and progress separate. Gateway summaries already prefer the configured task label, with a bounded task-text fallback. Preserve generic labels when no title is supplied.
2026-09-13 15:19:37 -07:00
RoboClaw
98101871f2
feat(dashboard): save shared fullscreen and split defaults (#146475)
* feat(dashboard): save shared fullscreen and split defaults

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

* fix(dashboard): preserve transient and legacy presentation intent

Keep command-driven route activation and cross-tab personal choices separate from shared defaults. Restore offline layouts, keep ordinary renders storage-free, refresh generated protocol models, and cover the affected Gateway and UI boundaries.

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

* fix(dashboard): preserve cross-tab choices and keyboard defaults

Keep personal override writes with the persistence owner, share the opening decision across keyboard and rail controls, and preserve prepared sidebar content during initial reconnect observation.

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

---------

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
2026-09-13 13:58:28 -07:00
Peter Steinberger
dab1f08376
feat: give every plugin a compact chat activity icon (#147333)
* feat: give every plugin a compact chat activity icon

Separate package-owned activity SVGs from plugin identity artwork. Ship 154 defaults and seven exact tool overrides, preserving Echo and the progress claw. Include authenticated bounded delivery, safe mask rendering, packaging, and authoring guidance.

* test: declare Vite types for the activity asset browser test

* refactor: keep plugin artwork selection with catalog presentation facts

* test: scope activity browser types and simplify fixture copies
2026-09-13 13:49:51 -07:00
Peter Steinberger
791124ac5e
feat(computer): control Gateway desktops without paired nodes (#147275)
* feat(computer): control Gateway desktops without paired nodes

* fix(computer): preserve remote nodes and cancel revoked executions
2026-09-13 12:58:42 -07:00
Peter Steinberger
cd1ff2a4d6
feat: load CDN libraries and fonts in widgets (#147265)
* feat: load CDN libraries and fonts in widgets

Share public static-resource origins across document, sandbox, and channel policies while keeping API access and native Gateway pins separate. Add visualization guidance for inline code explanations and persistent dashboards.

* fix: preserve local widget renderers in direct hosting

Keep document-approved same-origin renderer scripts available in the intersecting HTTP CSP. Cover stored and newly wrapped registered documents without granting API connections.
2026-09-13 12:50:45 -07:00
Peter Steinberger
7dddf51c90
fix: hide subagent sessions from Activity (#147253)
* fix: hide subagent sessions from Activity

Filter subagent sessions before search, facets, counts, and pagination so Activity stays focused on conversations. Preserve normal nested sessions and existing diagnostic listings.

* test: use the stored session label in Activity regression

* style: group session key predicates by their owning module
2026-09-13 12:12:50 -07:00
Peter Steinberger
43f081aa44
feat(macos): clarify agent activity in native chat (#147197)
* feat(macos): clarify agent activity in native chat

* refactor(macos): remove unused activity predicate
2026-09-13 11:37:22 -07:00
Peter Steinberger
7f3379c3cd
fix: high Gateway CPU while viewing diagnostics (#147110)
* fix: high Gateway CPU while viewing diagnostics

* test: match agent selection observer contract

* test: exercise diagnostics replacement through initial load
2026-09-13 09:17:41 -07:00
PollyBot13
1ba4a8b86d
feat: show when conversation memory is being saved (#140380)
* feat: show when conversation memory is being saved

* fix: regenerate Swift memory maintenance status
2026-09-13 22:19:09 +08:00
Peter Steinberger
c735af2e8b
feat(macos): improve agent navigation and chat layout (#146531)
* feat(macos): add agent navigation to the chat sidebar

* fix(macos): polish chat controls and preserve session ownership

* test(macos): align global conversation fixtures with routing ownership

* fix(macos): retain global ownership in selection and unread state

* test(macos): expect retained agent routing metadata

* test: repair sidebar helpers and restore typecheck shard headroom
2026-09-13 02:51:57 -07:00
RoboClaw
65c8b06f2e
feat(ui): keep file previews in tabs and render HTML (#146672)
* feat(ui): keep open files in shared sidebar tabs

Give chat files named tabs in the existing shared strip and retain their view and editor state. Keep workspace browsing and original downloads, honor explicit line links in reused tabs, and isolate split-pane focus.

Closes #146655

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

* feat(ui): render HTML in file tabs

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

* fix: synchronize HTML preview protocol and CI fixtures

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>

---------

Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
2026-09-13 00:39:13 -07:00
Peter Steinberger
e7b868bbab
feat(voice): share GPT Live across meetings and calls (#146546)
* feat(voice): unify Live sessions across calls and meetings

Resolve provider capabilities and interruption policy through the shared realtime voice owner. Keep meeting input isolated from virtual-microphone output, reuse native delegation for meetings and Voice Call, and preserve explicit Stop across browser and Apple relay clients.\n\nValidated with real Live API and synthetic Chromium/WebRTC proof, focused regressions, changed-file checks, and independent review. Related to #146289.

* test(voice): align capture fixtures and validation gates

Model browser audio capture in the shared meeting RPC fixtures so startup
failure tests reach the provider and verify capture cleanup. Preserve the
same relay startup behavior while simplifying duplicate lifecycle branches.

Rebalance the pre-existing 702-root platform test graph by moving security
tests beside sandbox/tool tests; keep coverage, graph counts, and limits.

* fix(meetings): preserve configured input commands

Keep explicitly configured capture/filter/mixer output as provider input on
local Chrome and paired nodes, preserving the v2026.9.4 contract. Generated
input and output-only overrides continue to use managed browser capture.

Retain Live's isolation guard and explain how to remove an input override
when selecting Live. Prove the actual PCM paths through both meeting engines
and transports, and document the preserved configuration behavior.
2026-09-12 17:06:51 -07:00
Ayaan Zaidi
7753ffb475
fix(ui): publish initial model catalog on connect (#145927)
## What Problem This Solves

The first web model picker open could wait seven seconds for a catalog reply. A late initial snapshot could also restore an old saved account after the user changed it.

## Why This Change Was Made

Publish the existing catalog during connection setup through the authenticated request dispatcher. Initial and ordinary replies use the same cache publication checks, so delayed work cannot replace a newer session selection.

## User Impact

Published choices appear on first open and reconnect while discovery continues. Warm reopen stays fast, without an extra catalog request from opening the picker.

## Evidence

With catalog replies held for seven seconds, the original picker had no usable choices until the reply. The corrected New Session and active-chat pickers showed rows within 100 ms; warm reopen took 8–12 ms. Neither open added a request.

Real browser/Gateway tests cover reconnect and a saved-account change before snapshot completion. Sixteen valid configuration fixtures start; an invalid legacy fixture rejects as expected. Previous-version source builds connect in both directions; installed-release upgrades were not tested. Full consumer analysis: `consumers.md`.

## Compatibility

The new connect field is sent only after server advertisement. Clients without opt-in receive no snapshot. No protocol-version bump, configuration key, database change, or migration.

## Consumers

- New Session picker: uses published rows before its ordinary catalog reply.
- Active-chat picker: receives the saved session's model/account projection and retains newer selections.
- Mounted browser shell: preserves initial publication across reconnect.

## Invalidation

Connection, identity, configuration, session metadata, session mutations, and explicit refresh retire stale reads. Expiry and eviction retain publication ordering; delayed results cannot refill invalidated state.

## Contention

Snapshot publication adds no lock, transaction, or await. The existing dispatcher owns catalog reads; the common cache owner admits results synchronously.

## Tests

Browser picker tests exercise fresh, saved-session, refresh, and reconnect flows. Gateway tests enter connect, `models.list`, and `sessions.patch`. Handshake, cache, metadata, and sibling checks pass. The shared test partition guard passes with the server grouping from #146212. Full automated validation is still required.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-12 23:39:39 +05:30
Peter Steinberger
ec9260bcd9
fix: recover failed cloud sessions locally and clear stale errors (#146054)
* fix: recover failed cloud sessions locally and clear stale errors

* fix(ui): guard restart state and retain recovery fixture types

* test: separate failed placement gateway recovery coverage
2026-09-12 08:18:26 -07:00
Peter Steinberger
1a9533f6f0
feat: refresh plugin tools within active agent conversations (#145648)
* feat: refresh plugin tools within active agent conversations

* build: refresh native plugin tool display metadata

* refactor: isolate plugin refresh controls from the agent runner

* fix: retain delivery and pending media across plugin refresh

* fix: preserve plugin tool metadata across module copies
2026-09-12 03:53:24 -07:00
Peter Steinberger
6e259355b8
feat: apply supported plugin installs without restarting the Gateway (#145710)
* feat: apply supported plugin installs without restarting the Gateway

* fix: preserve read-only plugin reload and inspection fixtures

* fix: preserve plugin recovery and policy metadata
2026-09-12 01:56:54 -07:00
Peter Steinberger
f9ccd07ded
fix: skip official setup approvals and default to Astra (#145646)
* fix: skip official setup approvals and default to Astra

* test: align default-model expectations across consumers

* test: align attachment catalog with Astra default

* fix: preserve configured Codex catalog model selections
2026-09-12 00:34:25 -07:00
Ayaan Zaidi
3d7d21166f
fix(models): discover account models after sign-in (#145190)
Publish static model choices after sign-in, then let the existing provider-scoped catalog owner acquire and publish account models, including late results. Keep ordinary model menus and picker opens passive, retain rows during renewal, and fence results after account changes.

Validated with registered Gateway tests, Telegram and browser flows, previous-release state and SDK contract checks, and successful CI.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-12 12:18:49 +05:30
Peter Steinberger
b5134de70a
feat: manage and reload plugins without Gateway restarts (#145484)
* feat: manage and reload plugins without Gateway restarts

* fix(plugins): preserve Bun loading and align lifecycle fixtures
2026-09-11 23:12:58 -07:00
Peter Steinberger
7f5a5231dc
fix(gateway): admit healthy agents when one agent's database copies diverged (#145426)
A divergent database copy for one agent no longer refuses the whole Gateway at startup. That agent is refused with a typed reason visible in status and Doctor while healthy agents keep running. Repairing the files and restarting clears the refusal; the default and configured system agents stay fatal.

Startup owns the process-local admission decision. Routing, cron, session scans, status, and Doctor consume it while preserving divergent files. The protocol projection adds optional response metadata without a version bump; no durable admission state or config option is added.

Regression evidence includes failing-before/passing-after admission and consumer-boundary tests, isolated Gateway service/refusal/recovery proof, and successful exact-head pull_request CI. Published-updater-to-candidate and native Windows proof remain unverified; the maintainer accepted that bounded gap for this landing.

Fixes #144689. Refs #145252.
Reported by @steipete in #144689.
2026-09-11 22:16:24 -07:00
Peter Steinberger
f093c0edde
feat(openai): support GPT-Live and default Talk by account (#145382)
* feat(openai): support public GPT-Live-1 voice sessions

Adapt public Live sessions, startup events, delegation, audio, captions, and
Platform authentication through the existing OpenAI voice plugin. Keep the
Codex subscription transport separate.

Persist public WebRTC transcripts through the Gateway and drain provider
finalization before releasing voice session owners across relay, Discord,
Voice Call, and MeetingBot. Preserve synchronous bridge disposal.

Validate targeted protocol and lifecycle regressions, authenticated synthetic
voice and WebRTC flows, and the iOS Simulator app build.

Closes #145071

* fix(voice): preserve cleanup and package boundaries

Keep the OpenAI capability catalog cold, remove the delegation type cycle, and expose portable Google mock declarations. Route failed call startup through the existing binding cleanup owner and stop failed local audio processes while provider finalization drains.

* fix(ui): preserve public Live caption fragments

Carry explicit verbatim semantics through the browser transcript pipeline so split words, repeated fragments, whitespace, and overlapping speakers bypass legacy ASR heuristics. Keep Gateway-only persistence and avoid synthetic final or item events.

* test(openai): expose portable delegation mock types

Use public logger and gateway callback contracts in test helpers so declaration-enabled plugin package compilation does not reference private Vitest types. Verified declaration compilation for all six affected plugins and test callers.

* fix(openai): wait for delayed GPT-Live delegation transcripts

Retain metadata-only public delegation notices while user captions are empty, resume through the existing admission owners when text arrives, and claim notice IDs before callbacks to prevent duplicate work. Bound pending notices and missing-input waits; revoke them during close, cancellation, and transcript drain. Preserve subscription prompt fallback behavior.

Validation: 103 focused tests pass; new regressions failed against the original behavior. Independent P0-P2 autoreview is scoped-clean. Combined type/lint gates are owned by the landing checkout because declaration boundaries reject this worker worktree borrowed compiler install.

* feat(openai): select GPT-Live Talk defaults by account

Resolve unpinned Talk models with the selected agent account and session requirements. Platform credentials select public GPT-Live; ChatGPT-only accounts select the subscription voice model. Preserve explicit model pins, manual responses, video, Azure, and direct tool bridge defaults. Keep catalog discovery aligned with session creation without rewriting saved config.

Validation: 177 focused tests pass; scope and account regressions fail on the prior owners. Authenticated microphone-to-delegation-to-spoken-answer proof passes with 211200 audio bytes and awaited completed shutdown. Core and plugin production/test typechecks pass; independent review through P2 is scoped-clean. Full changed-file guards continue in the landing workflow.

* test(openai): isolate Talk account default coverage

Keep the routing suite below its existing line limit by reusing its fixtures in a focused defaults suite with injected host auth. Use explicit blocks in the live audio fixture. Production behavior is unchanged.

Validation: all 61 routing/default tests, extension test typecheck and typed lint pass; independent P0-P2 review is scoped-clean.

* refactor(openai): split realtime delegation dispatch and tests

Keep direct bridge admission and dispatch in a focused local owner, reuse the existing bridge fixture across a dedicated delayed-delegation suite, and apply the required block style. Preserve lifecycle checks, callback binding, transcript publication and subscription behavior without relaxing file budgets.

Validation: 103 focused tests pass across five files; independent P0-P2 autoreview is scoped-clean. The landing lane owns canonical typed validation of the combined candidate with physical dependencies.

* test(openai): expose portable bridge mock callback types

Use public Mock annotations tied to the realtime callback and logger contracts so exported bridge fixtures emit declarations without Vitest private Procedure types.

Validation: actual OpenAI declaration emission and extension-test typecheck pass after reproducing TS2883 before the fix; 40 helper-consumer tests pass; independent P0-P2 autoreview scoped-clean.

* fix(openai): preserve camera-capable Talk defaults

* fix(talk): align browser capabilities with launch models

Resolve optional provider and model overrides through the existing Talk catalog before browser camera negotiation. Preserve other provider rows and explicit model choices, while unpinned OpenAI Talk follows the requested GPT Live account defaults.

* fix(ui): avoid shadowing Talk provider selections
2026-09-11 20:42:25 -07:00
Peter Steinberger
4fdcfc07b2
fix(ui): clarify model authentication and prevent overlapping controls (#145525)
* fix(ui): clarify model authentication and prevent overlapping controls

Show available credential methods and account identity in Models settings,
including the global Auto utility model resolved by the Gateway. Keep
provider connection separate from model setup, use a compact discovery
spinner, and keep tablet labels and controls side by side.

* test(ui): align Models catalog expectations with utility previews
2026-09-11 20:42:09 -07:00
Peter Steinberger
095f75f20e
fix(macos): finish capture cleanup before starting new work (#145450)
* fix(macos): finish capture cleanup before starting new work

* refactor(macos): retire unused microphone debounce helper

* refactor(macos): retire caller-owned warm camera sessions
2026-09-11 20:40:51 -07:00
Peter Steinberger
0141569e79
fix(ui): distinguish terminal clients in presence cards (#145559)
Preserve the accepted client type in presence and restore it with the connection mode after cache eviction. Display Terminal for TUI connections while retaining App for native clients.
2026-09-11 20:36:40 -07:00
Vincent Koc
dda6470454
feat(desktop): match virtual worker displays to the viewport (#143938)
* feat(desktop): match virtual worker displays to the viewport

Keep Fit as the default and gate Match on provider-owned resize permission and authenticated controller ownership. Preserve sizing choices during reconnects and retire resize authority with input control.

Pass resolved SSH VNC credentials through optional auth metadata and reconcile lost physical modifier releases after native popups. Add instrumented production Gateway/XFCE resize proof and native selection regressions.

* fix(desktop): align renderer exports and suppression inventory

* test(desktop): cover real node carrier resize qualification

* test(workers): align repository access provider fixture

* fix(ci): run real desktop resize proof with an upstream fixture

* fix(ci): bind desktop proof to raw merge identity

* fix(ci): retain safe desktop proof failure diagnostics

* fix(ci): expose safe desktop SSH setup diagnostics

* fix(ci): keep desktop proof phase tuple private

* fix(ci): retain desktop proof phase after timeout

* fix(ci): observe Gateway startup at desktop proof timeout

* fix(ci): run desktop proof against built Gateway

* fix(ci): assert visible desktop recovery state

* fix(ci): remove retired desktop spy allowance

* test(ui): model targeted desktop status in sizing fixtures
2026-09-12 11:26:46 +08:00
Peter Steinberger
360f4cfd0b
fix(macos): retire stale Gateway discovery callbacks (#145435) 2026-09-11 18:08:40 -07:00
Peter Steinberger
aa0ad4c780
feat(sessions): automatically archive older transcripts (#145172)
* feat(sessions): automatically archive inactive transcripts

Add opt-in worker maintenance, live storage settings, and exact restoration from compressed JSONL archives. Advance the agent schema to 20 and embed verified cold payloads in supported backups.

* fix(sessions): preserve cold history across reads and lifecycle actions

Restore archived history before channel context, latest-text reads, reset and fork operations. Preserve legacy schema migration preflight and steering transcript order; regenerate native protocol bindings and repair the Windows cleanup fault fixture.

* fix(ci): regenerate plugin assets and rebalance cold storage tests

* fix: harden updater validation and account selection
2026-09-11 16:50:58 -07:00
Peter Steinberger
371791b9d6
fix(computer): honor capture-free CUA window observations (#145351)
* fix(computer): honor capture-free CUA window observations

* fix(computer): preserve released window capture requests
2026-09-11 16:19:50 -07:00
Peter Steinberger
cc0d3ca78e
fix: keep Mac desktops available and resolve session views directly (#144226)
* fix: keep Mac desktops available and resolve session views directly

Keep authorized Computer executions awake with bounded native assertions, report locked/unknown desktop state, and offer explicit unattended hosting. Manual lock and route retirement revoke old executions without disturbing a successor or unrelated held input.

Resolve session desktops through exact session and environment status before unrelated inventory. Preserve retry for transient errors, recover missing sources to the picker, and refresh availability when the presenter reconnects.

* test: keep node host alive for inventory assertions

* refactor: remove unused Mac service protocol requirement

* fix(macos): preserve desktop parameter errors

Preserve command-specific malformed snapshot and computer.act errors at the execution-envelope guard, using the existing decoder and a shared response formatter. Include unattended hosting in the existing consent and setting-coercion coverage tables.

Verified the four original CI failures and eight lifecycle siblings with a signed Intel payload in an isolated native test run. Swift lint, formatting, schema guard, and independent review passed.

* fix(macos): preserve literal desktop error responses

Keep the two complete diagnostic strings at the response boundary so native translation discovery does not interpret a temporary command label as UI copy. The selection predicate, error code, and response messages are unchanged.

Verified unchanged native i18n inventory and generated artifacts, strict Swift lint and formatting, an isolated Intel compile, and independent review. Existing signed native regression proof remains applicable to the identical output contract.

* fix(macos): read console state from the registry root

The IOService plane root can be the hardware entry and omit IOConsoleUsers,
leaving an unlocked desktop unavailable to Computer work. Use the registry
root accessor while preserving CFBoolean, UID, lock, and release validation.

Live signed Swift proof calls the actual platform method before and
after the accessor repair on macOS 15.7.9.

* fix: refill prepared workers after session worktree cleanup

Retain the canonical Git donor while keeping the admitted session commit.
Reuse repository identity for immutable replays and preserve managed archive
snapshot retention. Cover archive removal, immediate Git pruning, store
reopen, pinned refill, bare donors, and idempotency rejection with real Git.

Validation: 130 focused and sibling tests passed, scoped changed checks,
and managed review with the retention finding resolved against the existing
archive owner and forced-pruning regression.

* test(android): await approval reconciliation before reconnect

Wait for the original resolution coroutine to finish its immediate readback
before replacing the test backend. The published unknown-outcome message
precedes that read and was not a completion barrier. Preserve the exact
reconnect request-order assertions and existing timeout.

Validation: causal reproduction of the extra leading get, all 26 approval
runtime tests, app ktlint, and independent review.

* test(android): await complete gateway deadline admission

Read operation readiness through the existing lifecycle owner lock before
advancing virtual time. The operation field is published before its deadline
is registered, so an unlocked read could observe half-completed admission.
Preserve the deadline, cleanup, and replacement-admission assertions.

Validation: causal RED/GREEN, all 53 foreground-service tests, Android
ktlint, and independent review.

* fix(macos): propagate native worker task cancellation

Route Swift task cancellation through the existing worker owner and settle
cancelled calls without waiting for a suppressed child result. Bind queued
cancellation to its exact request reservation and consume that request's
buffered controls when admission is already cancelled.

Clarify that Screen Sharing can explicitly lock a Mac on viewer disconnect;
unattended hosting respects that operating-system boundary.

Signed isolated native proof passed six functions/eight cases, including
active and pre-dispatch cancellation, scoped buffered controls, worker
replacement, and process cleanup. Swift and documentation checks passed.

* test(browser): report tab creation errors before polling

* perf(ui): reuse native embed shape validation

* test(ui): await plugin mutation reconnect before assertions

* test(codex): control native relay retention clock

* fix(workers): cancel reserves and finalize confirmed cleanup

Let environments.destroy cancel an unused automatic reserve through the existing guarded preparation owner before waiting for provider settlement. Preserve claimed workers and admitted capture expiry behavior.

Carry confirmed allocation cleanup through WorkerProviderError.cleanupComplete and the existing teardown finalizer. Retire pending or bound node enrollment before terminal failure and preserve the original provider error. Uncertain allocation and cleanup retain their existing recovery ownership.

Validate with producer/consumer RED-GREEN cases, 53 combined service regressions, provider and ownership siblings, changed checks, and scoped P2 review. Keep separate checkpoint/image recovery obligations with the provider.

* fix(memory): reject views in FTS schema checks

Restore the existing unavailable-FTS fallback when a view occupies the derived index name. Preserve the colliding view and the existing savepoint boundary; table lookup must include views while excluding the independent trigger namespace. The unchanged temporal-ranking regression fails before this repair and passes afterward, with 64 focused cases, changed checks, and independent review passing.

* fix(cua): launch observed Mac apps by native identity

Use the observed bundle ID or name accepted by the pinned Mac driver instead of its unsupported launch_path field. Preserve discovered launch-path precedence on Linux and Windows and the rejection of model-supplied paths. Both Mac regressions failed before the guard; all 21 provider cases, selected changed checks and independent review pass. A fresh signed artifact and native launch proof remain required.

* fix(nodes): republish runner inventory after reapproval

* test(memory): preserve equal-count view collision coverage

* test(ui): wait for chat readiness before submitting controls

* fix(ci): recover stranded hosted tooling capacity

Rebalance one eligible file within its existing tooling family after bounded tail packing overflows. Preserve the 80-job cap, timing floors, complete inventories, process isolation, and ordinary plans.

* test(android): observe promotion before crossing discovery deadline

Use the existing retirement callback to observe reservation before exercising bounded cleanup. Preserve discovery and assertion deadlines and release the held callback during cleanup.
2026-09-11 08:45:05 -07:00
Ayaan Zaidi
f2c4e63ed6
fix(macos): keep Quick Chat model and speed choices current (#144804)
Related: #136257
Projection owner: #144762

## What Problem This Solves

Quick Chat could keep stale model choices after a catalog update and did not expose the published Fast setting. Its picker must preserve the Gateway's availability and thinking decisions, including refusal guidance and selectable rows whose availability is unknown.

## Why This Change Was Made

Quick Chat consumes the shared OpenClawKit catalog projection introduced in #144762. Both chat surfaces now use one Fast-state projection. Model and speed changes use the existing session-settings route lease and target queue, then reload canonical catalog/session state. This removes the partial patch-response model/thinking derivation.

Catalog publications refresh the open picker without losing its draft; late reads cannot replace a reopened presentation. The nonactivating panel preserves Attach text and Paste reply targeting. Native tests exercise the registered shortcut callback and require the panel/editor to present even while the application does not own foreground.

## User Impact

- Refused model rows are disabled with the published guidance; unknown availability remains selectable.
- Effort labels come from the catalog, and speed offers Session default, Fast, and Normal when applicable.
- Settings changes settle before sending. Rejected speed changes preserve the retry key for an unchanged draft.
- Reopening Quick Chat retains the correct catalog and presentation state.

## Evidence

- [Connected native candidate](https://github.com/openclaw/openclaw/actions/runs/34584437164) passes at this exact PR head using the real Gateway fixture from #144762/run 34571594676. A real catalog publication refreshes the same Quick Chat presentation without losing its draft. Clearing a saved speed override and choosing the unknown-availability model both reload canonical session state. No inference server or transport mock was added.
- [Connected baseline](https://github.com/openclaw/openclaw/actions/runs/34585094303) reproduces the missing refresh on main `68b7893b`: the Gateway publishes the new model name, but Quick Chat retains the old name. Build, connection, and publication pass before the stale-name assertion fails. The baseline's existing test guard suppresses its panel, so this is publication-state red, not a visual baseline.
- [Exact-head CI](https://github.com/openclaw/openclaw/actions/runs/34583201846) passed.
- [Final targeted macOS run](https://github.com/openclaw/openclaw/actions/runs/34581841571): app/native builds, 2 XCTest UI cases, 83 Swift Testing cases, and 11 shared projection tests passed. Includes rendered model selection, effort, Fast/default, refused/unknown rows, publication, stale reads, and send retry behavior.
- [Earlier resumed run](https://github.com/openclaw/openclaw/actions/runs/34581142507): the same picker and lifecycle proof passed; its first attempt failed before compilation on an HTTP 500 while downloading SwiftLint.
- [Baseline picker red](https://github.com/openclaw/openclaw/actions/runs/34566007763): refused row enabled, guidance missing, and inferred effort options. The candidate's native menu records show the corrected states.
- The final rebase was followed by 67 passing config/state/recovery tests and real Gateway startup/list/create/command transport checks for all 17 sanitized config fixtures, with fake credentials and external networking disabled. Legacy roster used Doctor repair before startup.
- Focused catalog/auth protocol tests passed. Retained Telegram Test Server `/models` proof returned the provider selector with zero inference requests.

Original and connected native captures were inspected locally and by an independent validator. Artifacts retain native menu JSON, real Gateway/session records, and panel images. Panel captures have clipping/transition limits; they do not establish expanded-menu visual quality. The shortcut proof invokes the registered callback and observes a visible editor with application-active/key-window state false; it does not claim a physical key event, foreground ownership, signing, or permission grants.

The corpus also exposed an unchanged base issue: the generic-token `/models` command advertises an OpenAI fallback while the published catalog is empty. Startup and command transport succeed; complete command/catalog semantic parity is not claimed. This PR changes only native app code and its tests.

No protocol version or schema change. The temporary proof workflow is removed from this PR; its task staging branch is retired and artifacts are retained. No shipped test behavior is deleted; existing fixtures are adapted to the typed settings provider, and the new speed tests cover accepted and rejected writes.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 15:23:14 +05:30
Ayaan Zaidi
0806c534c1
fix: Apple chat model controls follow the Gateway catalog (#144762)
Related: #136257

## What Problem This Solves

Fixes an issue where users of iOS chat and macOS shared chat or Quick Chat could see Fast and thinking choices that did not match the selected model's published capabilities. Model availability and provider sign-in also need to follow the session's Gateway state.

## Why This Change Was Made

The Apple clients now request the direct session catalog and consume its availability, Fast, thinking, input, and route fields. A saved Fast override takes precedence, and thinking choices, labels, and defaults come from one published profile. Unknown availability stays selectable; explicitly unavailable rows show the published refusal guidance and use disabled menu buttons in both shared composer layouts.

Native sign-in shows the owner's code and link, waits for the wizard result, and then reads published authentication state. Connection changes and cancellation retire the captured operation. Older Gateways keep slash commands with update guidance. This removes app-side capability inference and duplicate metadata decoding without a protocol or storage change.

## User Impact

Model controls reflect the selected session and model. Users can complete supported sign-in methods from shared chat without treating a displayed code or browser navigation as successful authentication.

## Evidence

- Baseline projection tests reproduce three regressions in [run 34564827772](https://github.com/openclaw/openclaw/actions/runs/34564827772).
- [The macOS CI job](https://github.com/openclaw/openclaw/actions/runs/34574028270/job/103182622412) passes 1,693 OpenClawKit tests and 2,146 macOS tests on the PR merge. This includes cancellation/failure messages, older-Gateway command fallback, and stale model-catalog responses across session or connection changes.
- [Run 34571594676](https://github.com/openclaw/openclaw/actions/runs/34571594676) passes 11 projection tests, 13 Quick Chat tests, and one iOS simulator test with zero skips or failures. The simulator shows unknown rows selectable, refused rows disabled, Fast absent where unsupported, published thinking labels, the device code and link, and connected auth state after wizard completion. CLI model inventory and session details come from the same fixture Gateway.
- 33 Gateway session-catalog and native-auth tests pass. Swift protocol regeneration check leaves generated source unchanged.
- Config, state, and startup-recovery suites: 56 tests pass. Real Gateway startup passes all 15 sanitized config fixtures with fake credentials and no inference.
- Telegram Test Server `/models` returns the provider selector with no inference; this covers the command sibling.
- Max-lines, assertion-safety, workflow, and native string inventory checks pass.

The task-owned proof workflow is removed from this PR; its run artifacts retain the screenshots, catalog, auth-state output, and test results. The CLI inventory omits Fast/thinking fields, so those controls are compared to the direct session catalog for the same model.

Simulator proof uses an isolated synthetic sign-in provider and ad-hoc signing. It does not claim external OAuth, release signing, or device permission proof.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 13:57:31 +05:30
Patrick Erichsen
2e939d9d30
fix(ui): load plugin catalog home from one snapshot (#144569)
* fix(ui): load plugin catalog home from one snapshot

* fix(ui): preserve bounded plugin catalog browsing

* fix(ui): reconcile plugin catalog continuation

* fix(ui): align plugin overview lifecycle tests

* test(ui): satisfy plugin overview lint rules
2026-09-10 20:17:23 -07:00
EMORI
89f3645122
fix(ui): resolve channel icons by owning plugin (#144177)
Closes #144152

## What Problem This Solves

Channels showed letter tiles when a channel ID differed from its plugin ID, even when that plugin supplied a valid icon. 

## Why This Change Was Made

The catalog exposes existing manifest ownership, and gallery, details, and setup resolve artwork through the owning plugin. Channel names and descriptions stay unchanged.

Each plugin owns one image URL. Channels that appear later reuse it, and page cleanup releases it once. Exact plugin/channel-ID matches retain priority. The existing authenticated package-icon route, trust rules, and configuration authority remain in place. The optional catalog field preserves older payload decoding.

## User Impact

Channels can use their plugin’s packaged artwork while keeping their own stable identity, name, and description. Multiple channels share one loaded plugin image.

## Evidence

### Real browser proof

An isolated Gateway served its matching Control UI with a normally installed external plugin, `agent-system`, and distinct channels `agent-system-github` and `agent-system-chat`.

- Pinned main `acbe754b93`: both channels showed fallback tiles; no owning-plugin icon request occurred.
- Candidate: one authenticated `GET /__openclaw__/plugin-icon/agent-system` returned PNG with HTTP 200. Both channels shared the decoded 256×256 image. Gallery, details, setup, and reload showed the packaged icon with the original text.
- Navigation released each image URL once. Invalid and missing icons showed readable fallbacks. Fresh unauthenticated requests returned 401. Normal plugin removal followed by Gateway restart removed both channels and the plugin.
- A source-blind validator independently drove the candidate and removal flows, inspected their screenshots, and separately judged the retained fallback captures.

| Surface | Before | After |
| --- | --- | --- |
| Gallery | ![Before: gallery](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/baseline-gallery.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=aac20738b279e628380cf4539c1e6f14ec7c4dbdeb21eb8eb9bc9300a65fb202) | ![After: gallery](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/candidate-gallery.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=3f0ff8257578b5b6f7908f36fc4cae82f60a0e143cae9b8128b48978912b13a4) |
| Details | ![Before: details](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/baseline-details.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=86e48e7796f77a1666aa58df454f7ec434d07898b32e1b10dea6e848611c689b) | ![After: details](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/candidate-details.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=f858a119fa632e124d59e650d9066c3de0bf94890defa7f05f6200fef76b5a49) |
| Wizard | ![Before: wizard](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/baseline-wizard.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=9e9755f3238cc551dab3a70979cbf41e728dd4e0ce23963da5bbfc95165df1db) | ![After: wizard](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/candidate-wizard.png?X-Amz-Expires=604800&X-Amz-Date=20260911T013707Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=75e561d647d4eb6ec2eabe9ea8f501572e558c9eb30fd52a822d85ef4ab8874e) |

[Artifact manifest with file hashes](https://91b59577e757131d68d55a471fe32aca.r2.cloudflarestorage.com/openclaw-crabbox-artifacts/crabbox-artifacts/v2/org/b3BlbmNsYXc/owner/Z2l0aHViOjIyMDMxMTE0/pr-144177/public-media/20260911-013708-191645532/artifact-manifest.json?X-Amz-Expires=604800&X-Amz-Date=20260911T013709Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=a677a1e59413a4e54bcc2da5fec6164a%2F20260911%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=0455b1ca86ec7edd9f5051d69bff11dd4209be45ec56eb04e1b069f4e8e0a031). These brokered image links expire September 18, 2026; the original captures and full private proof remain retained.

### Validation

- 161 distinct focused catalog, HTTP icon, page, view, and loader tests pass across retained runs.
- A later-sibling regression fails on the original duplicate-fetch behavior and passes with one shared URL and one release. Exact-ID priority is tested in both catalog orders; pending disconnect and timeout controls pass.
- Changed TypeScript lint, canonical protocol generation, Swift/Kotlin generated-output checks, protocol compatibility guard, source ratchets, UI copy checks, normal commit hook, and `git diff --check` pass.
- Hosted CI owns full type checking and execution of the added Swift JSONDecoder test for old and current catalog payloads. Those results remain required before landing.

No channel message delivery is claimed by this icon proof. The original contributor's implementation and commit ancestry are preserved.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 07:57:38 +05:30
PollyBot13
448a48c652
feat: reject stale reset after session replacement (#123864)
* feat(gateway): reject stale session reset requests

Add an optional expectedSessionId precondition to sessions.reset so stale automation is rejected before interrupting a replacement generation.

Refs #123862

* test: bind setup credential checks to fixture provider

* perf(ui): keep environment shuffle icon out of startup

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-09-10 18:34:41 -07:00
Vincent Koc
c4636e47f1
refactor(chat): reuse canonical test helpers (#144481) 2026-09-11 08:05:31 +08:00
Ayaan Zaidi
09e2b15466
fix(models): share API-key editing and removal (#144420)
Related: #136257
Supersedes #142851. Builds on #144181.

## What Problem This Solves

Fixes an issue where API keys saved on the Models page followed a different persistence path from CLI keys, and CLI logout refused to remove profiles referenced by provider configuration.

## Why This Change Was Made

Models and CLI key operations now share credential selection, persistence, and removal. Removal clears references for the same captured credential plan that the store deletes; concurrent replacements are preserved. Both paths use the Gateway auth-refresh owner and retain recovery guidance after a committed write.

If another client changes the provider binding while the CLI key prompt is open, the saved key does not replace the newer binding. The CLI reports the committed key and tells the user to reopen Models. Internal write controls stay outside the public plugin interface.

Reference-backed profiles cannot be converted to inline keys by replacement. If a concurrent credential generation rejects removal after config cleanup, the remover restores only cleanup-owned config values that no later writer changed.

If removal throws or commits only some owner stores, the removal owner reads the targeted stores again. It restores references only for credentials that still exist and keeps successful deletions removed.

Recovery replays only the captured config delta for targeted survivors. A retained token or external-secret profile keeps its provider binding.

## User Impact

- Edit or remove saved API keys through Models or the CLI with the same stored result.
- Keep model defaults, connection settings, account metadata, credential copy restrictions, tokens, and reference-backed keys intact.
- Explicit CLI profile selection still supports named backups without changing the active connection.
- Agent-local overrides remain intact; a conflicting shared-key replacement reports how to resolve the override.

## Evidence

- Baseline CLI: removing a configured profile failed with the provider-reference refusal.
- Baseline browser: Models reported “Secret saved,” while the key remained inline in provider configuration and the profile store stayed empty.
- Real Gateway/browser and CLI proof: save and removal produce identical credential/configuration state; both refresh auth successfully and preserve the selected model.
- Targeted owner, CLI, Gateway, UI, portability, and plugin-interface tests cover persistence, reference cleanup, concurrent credential replacement, retained credential kinds, explicit backups, administrator scope, and committed-write warnings.
- Independent real-browser acceptance passed UI/CLI state parity, metadata and credential-kind preservation, administrator-scope enforcement, config-write failure recovery, and active-run preservation during targeted removal. Full-provider logout closed the matching real local-provider streams.
- Final rebased candidate: 230 targeted owner, CLI, and Gateway tests passed. The rebuilt Gateway/UI passed the real-browser and CLI save/remove parity test. UI and portability checks passed on the integrated candidate, whose Auth B production files match the final candidate.
- Corrective focused checks: 80 tests passed for the binding race, public plugin boundary, CLI test types, and UI end-to-end inventory. Protocol generation passed.
- Real CLI race proof: a second CLI changed the provider from `fixture:manual` to `fixture:secondary` while key entry waited. The first CLI then preserved `fixture:secondary`, returned the saved-key recovery message, and exited 1.
- Final review-fix checks: 151 owner and Gateway tests passed. They cover configured and default reference-backed profiles plus API-key-only and full-provider removal races that preserve credential, profile metadata, order, and provider binding.
- Final public CLI proof: reference-backed replacement rejected without state change, then logout and save succeeded. A same-ID concurrent replacement completed while logout waited on the config lock; the rejected logout preserved credential and config, then retry and save succeeded.
- Rebased-head checks: 291 focused owner, CLI, Gateway, SDK, and UI-inventory tests plus 50 Models-page tests passed. Protocol generation, full build, the public CLI campaign, and real Models-page UI/CLI parity passed again after the Models login work landed.
- Incomplete-removal checks: 154 owner and Gateway tests passed. They cover thrown store errors, incomplete removal, partial multi-store deletion, surviving-reference restoration, and successful retry.
- Untargeted-binding checks: 155 owner and Gateway tests passed. Failed API-key-only removal preserves the retained token binding, and retry removes only the targeted key.
- Proof limit: the running Gateway's internal refresh exception was not live-injected. Gateway tests cover the failure branches and UI tests cover the resulting warning; remote-target and absent-local-Gateway CLI outcomes were observed separately.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 05:12:54 +05:30
Ayaan Zaidi
b34254154b
feat(models): separate provider login from model activation (#144329)
## Problem

Models sign-in also runs model setup, which can activate a provider's starter model. Bare `/login` starts OpenAI device authentication before the user chooses a provider.

## Solution

Add credential-only provider login in Models and one shared provider menu for chat. Plugins declare optional login choices in their manifests. Core resolves provider and method choices and produces existing command buttons or copyable commands. Bare `/login` always asks for a provider, even when only one is available. API-key and local setup methods remain available through explicit provider commands. `/login codex` retains its device-code flow.

The credential-only flow uses the shared persistence and auth-refresh owner from merged #144181. It preserves the selected model, restrictions, concurrent settings and existing account pins. Models publishes the saved credential through the current Gateway context. Cancellation locks at the real persistent-effect boundary; confirmed saves remain visible through later errors. Caller authority is checked at credential and session commits, and disconnected clients cannot finish pending login. Qualified choices reject stale or ambiguous plugin owners. Leaving Models closes its wizard input through the existing close operation and waits for admission to settle. This uses optional `closeInput` on `wizard.cancel`; ordinary cancellation still refuses to interrupt a protected save. Separate pending requests keep page disposal independent of an outstanding Cancel response.

The final conflict resolution also preserves the shared refresh outcomes from merged #144436: rejected or unreachable refresh reports saved credentials with recovery guidance. One shared error module carries saved-credential and settings-write failure facts, and the provider-neutral runtime owns completion/failure wording for both chat paths.

Channels render core-owned command actions. Provider-neutral recovery replaces the old OpenAI-specific recovery path. OpenAI, MiniMax and xAI declare their supported credential-only choices; methods requiring starter discovery retain setup.

## Impact

- No new configuration keys or database schema.
- Optional metadata preserves setup for plugins that omit it.
- Connecting a provider does not activate its default model.
- Chat selection rechecks current owner permission and availability.

## Evidence

Original baseline: `d35cefd9b7`. Integrated base after #144181: `7d2296e333`. The later required conflict resolution integrates #144436 at `39b671dc74`.

- Real Telegram Test Server baseline: bare `/login` issued a device code before selection. Candidate: provider buttons, second method menu, synthetic device code, saved result and rejection of a stale qualified selection. Telegram transport and user actions are real; provider credentials are synthetic.
- Real Gateway baseline: `models.authLogin` was unknown. Candidate: saved fixture credential with the same default model and restrictions.
- Independent public-client checks cover singleton webchat selection, wrong-connection denial, unavailable choices, disconnect rejection and positive connected-owner completion. An existing CLI setup flow with omitted metadata still saves credentials and honors explicit `--set-default`.
- Integrated public-client cancellation proof: cancelling before save leaves no credential; cancelling after profile visibility while a provider note is pending returns running, and acknowledging the note produces the saved terminal result. A public settings edit during login survives; the saved profile appears without restarting the Gateway.
- Browser captures show Connect, explicit provider selection, the sign-in URL/code and saved result with the selected model unchanged. Captures were inspected.
- Current integrated focused Vitest: 243 passing tests across the auth producer and choice resolution, shared login runtime, core chat, native Telegram, Gateway wizard ownership, Models UI and the CLI sibling. Earlier retained checks cover method ordering, setup, MiniMax/xAI and provider recovery. The Telegram fixture cleanup preserves all test names, parameter rows and assertions; its 25 cases pass after cleanup.
- Page-disposal regression: the original Gateway kept waiting after a saved note, and the original Models page left the wizard unsettled on removal. The correction passes 33 Gateway and 49 UI tests, including disposal during a pending Cancel and a second login on the same connection. Fresh real-Gateway proof rejects a peer disposal, preserves the saved credential, returns truthful closure status, and immediately admits the same owner’s next login.
- Focused lint, assertion safety, runtime build and whitespace checks pass. Full typechecking and full CI run on GitHub.

This extracts Auth C+E from #136257 and replaces closed #142943. Auth A was merged before integration; its implementation was not copied into this branch.

## Deletion and rewrite ledger

`src/auto-reply/codex-login-recovery.ts` moved to `src/auto-reply/provider-login-recovery.ts`. Its `buildCodexLoginRecovery`, `CodexLoginRecoveryEvidence`, and `CodexLoginRecovery` symbols moved to `buildProviderLoginRecovery` (`:23`), `ProviderLoginRecoveryEvidence` (`:5`), and `ProviderLoginRecovery` (`:11`). The fixed OpenAI/Codex recovery action is replaced by the shared provider menu. No recovery test definition was deleted; the nine renamed or parameterized definitions are mapped below against head `73cfa4b319b9640a6711b2dc8e871d9ff4aea035`.

| Removed test name | Disposition | New test name and location |
| --- | --- | --- |
| `adds Codex login recovery to raw forwarded refresh failures` | **behavior moved** | `adds provider login recovery to raw forwarded refresh failures` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:51` |
| `keeps Codex login recovery actionable on Control UI turns` | **behavior moved** | `keeps provider login recovery actionable on Control UI turns` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:72` |
| `preserves Codex login recovery in known failure payloads` | **behavior moved** | `preserves provider login recovery in known failure payloads` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:118` |
| `keeps disabled OpenAI OAuth profiles actionable on later turns` | **behavior moved**; original OpenAI row retained, xAI and MiniMax rows added | `keeps disabled %s OAuth profiles actionable on later turns` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:228` |
| `does not offer Codex login for $label` | **behavior moved**; API-key and transient OAuth negative rows retained, provider-name-only negative row added | `does not offer provider login for $label` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:277` |
| `keeps non-OpenAI OAuth refresh failures on provider-specific terminal guidance` | **behavior moved and expanded**; terminal guidance retained, shared login action added | `adds provider login while retaining non-OpenAI terminal guidance` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:289` |
| `turns returned OpenAI refresh failures into Codex login recovery` | **behavior moved**; original OpenAI row retained, xAI and MiniMax rows added | `turns returned %s refresh failures into provider login recovery` — `src/agents/embedded-agent-runner/run/payloads.errors.test.ts:121` |
| `adds Codex login recovery to OpenAI OAuth refresh failures` | **behavior moved** | `adds provider login recovery to OpenAI OAuth refresh failures` — `src/cron/service.failure-alert.test.ts:845` |
| `does not offer Codex login for non-OAuth authentication failures` | **behavior moved** | `does not offer provider login for non-OAuth authentication failures` — `src/cron/service.failure-alert.test.ts:884` |

The obsolete provider restriction in `buildCodexLoginRecovery` is intentionally removed: typed non-OpenAI OAuth failures now receive the shared action while keeping their provider-specific terminal repair command. The old `/login codex` recovery presentation becomes `/login`; explicit `/login codex` remains supported. Typed OAuth evidence, negative authentication cases, private profile handling, and complete recovery-presentation assertions remain covered.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 04:18:48 +05:30
Ayaan Zaidi
54c3655e12
fix: preserve model login settings and refresh gateway auth (#144181)
Related: #136257

## Problem

Provider login could overwrite settings changed during sign-in and could hide that credentials were already saved when settings application failed. CLI auth changes used a read-only status refresh that did not acknowledge publication to the Gateway's prepared auth state.

## Solution

Login saves credentials through the existing owner and replays only its configuration changes against the writer's current source. Independent additions also merge when their parent object was absent at login start; overlapping edits still report a conflict. Model identities are normalized through the existing config owner. ID-keyed model rows merge as upserts: unchanged fields and concurrent entries survive, while overlapping changes report a settings conflict separately from the saved credential.

The administrator-only `models.authRefresh` method uses the existing Gateway publication owner and waits for prepared auth state. It reloads shared-store ownership after external writes and rekeys configured owners before queuing publication. Login, logout, profile order, and local-store notifications share that owner. Generated protocol artifacts and the dependent Workboard manifest are updated without a protocol version bump.

When an older Gateway returns `INVALID_REQUEST` with `unknown method: models.authRefresh`, the CLI makes one guarded legacy `models.authStatus { refresh: true }` request and still prints restart guidance. Legacy status refresh is not reported as acknowledged publication.

## Impact

- Full-provider logout cancels matching active runs immediately after credential removal, even when later auth refresh fails. Targeted logout and unrelated runs remain unchanged.
- Unset and existing defaults are preserved unless `--set-default` is requested.
- Concurrent model IDs and independent fields survive sign-in; partial rows retain existing settings.
- Read-only status access stays unchanged. The read-to-admin scope narrowing is intentional for the new mutation; permission errors do not trigger the compatibility path.
- Order acknowledgement includes auth publication. A committed order still returns a warning if refresh fails.
- Omitted workspace is supported by configured-owner lookup; refresh uses current configuration rather than stale request facts.

## Evidence

- 398 current-owner targeted tests pass across retained and refreshed owner/sibling proof, including CLI login/logout/order, config replay, ID normalization, partial model rows, fallback classification, runtime notifications, scoped/overlapping publication, and public method admission.
- Baseline real CLI proof shows a concurrent logging edit being overwritten before the repair. Credential readback confirms persistence even when settings are rejected.
- Fresh eight-scenario CLI acceptance on `f6044cbdd60a` passes default controls, ordinary ID upserts, concurrent new IDs, independent field edits, and saved-credential reporting for genuine conflicts. The prior failed partial-row run is retained in the evidence history.
- Real Gateway proof shows acknowledged publication, visible credentials/model availability, overlapping agent refreshes, read-only denial with status access retained, local-agent logout, and remote-store separation.
- Fresh real-Gateway proof with older-method response controls on `f6044cbdd60a` passes login, order, and local logout: exactly one legacy status request follows the typed unknown-method response, restart guidance remains, and no publication success is claimed. Wrong method/code, permission failures, and mismatched state do not use the fallback. The same pass verifies the updated prepared-catalog behavior from main.
- Live logout fault proof on `117f47d41b4a` starts two real provider HTTP requests through `chat.send`, then makes provider auth preparation fail during publication. Full-provider logout still closes the matching request and emits `auth-revoked`; the unrelated request stays active and completes. The response remains `UNAVAILABLE`. The registered-handler regression is red before the fix and green afterward.
- The absent-parent regression fails on `117f47d41b4a` and passes after the one-condition conflict-check correction. The existing registered-provider login test verifies both provider entries, credentials, and the original default; 52 selected login/config tests pass. No further live fixture experiments were run.
- Formatting, syntax lint, assertion safety, max-lines limits, protocol generation/validation, and relevant generated-output checks pass. Full CI runs on GitHub. Fixtures use synthetic credentials; no live vendor OAuth or model inference is claimed.

Existing limitation: shared-main CLI logout reports an auth-store lock failure on both the pinned baseline and candidate before refresh. Agent-local logout and its refresh are verified; this PR does not change the shared-profile remover.

An additional targeted-profile fault attempt stopped at credential removal before reaching publication; it is retained as a limitation. Existing targeted-logout preservation tests pass.

The separate setup lifecycle is owned by #144195. Shared login results and chat/Telegram completion presentation follow in the next extraction PR.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-11 02:17:50 +05:30
Peter Steinberger
0589eaf3a3
refactor(protocol): simplify generated schema registration (#144112)
* refactor(protocol): simplify generated schema registration

* fix(protocol): handle Windows paths in registry type checks

Normalize diagnostic filenames using the same path rule as the compiler host, so expected readonly diagnostics are recognized on Windows. The actual package guard and both optional-mode compiler probes pass; the native Windows execution is separate evidence.
2026-09-10 09:00:15 -07:00
Peter Steinberger
3c3c65e5aa
feat(ui): build and rebuild cloud worker snapshots (#143929)
## What Problem This Solves

Cloud worker snapshots could be inspected and recovered in Settings, but operators could not start a build, rebuild a project image, or cancel an active build from that view.

## Why This Change Was Made

Add Build snapshot with eligible-profile and Gateway-local repository selection, Rebuild using a recorded local project root, and confirmed cancellation through the existing environment methods. Group build environments with their snapshots, refresh worker inventory before image inventory, and poll every 10 seconds while a worker build or capture remains active. Preserve the observed worker state when image listing fails.

Failed and orphaned builds remain visible with their existing worker error and count toward Needs attention; they do not keep polling or offer cancellation. Capture counts are deduplicated by lease ID. Pending build dialogs retain their errors, and profile-save notices direct operators to Snapshots after restart.

Carry optional local project-root metadata through preparation and Crabbox allocation/listing, and include profile identity in the existing worker summary. Preserve main's computed project label for repository-backed sources; only local snapshots expose Gateway-local root metadata. No new RPCs, configuration options, database schema, or image reuse policy. The rebase retains #143893's pin, previous-generation, rollback, delete, and retention controls.

## User Impact

Operators can prepare committed project snapshots without starting a session. Inline errors explain invalid selections and prepared-pool capacity. Rebuild uses ordinary preparation/reuse policy and does not force a capture when the existing image remains reusable. Images without a recorded local root omit Rebuild; the repository picker remains available for local checkouts.

Cancellation explicitly asks to destroy the selected worker, including an unused ready reserve. It uses non-force destruction: the existing lifecycle owner checks attachment under the environment lock and retains failed/orphaned records. The earlier stale-cancellation review concern was rejected on that source evidence, and the review accepted the rejection.

## Evidence

- Rebased onto #144002, which repairs the unrelated docs-navigation CI expectation. The previously failing navigation test now passes locally.
- Expanded focused tests passed: 50 project-preparation/provider tests, 117 cloud-worker UI tests, four snapshot browser flows, and 23 Crabbox Gateway tests (194 total).
- Changed-file `pnpm exec oxlint` passed. Core typechecking passed after narrowing the existing local/repository project union without casts or suppressions.
- Independent review of the complete feature was scoped-clean at P0–P2. The new one-line project-variant integration repair also received a clean scoped review.
- Asynchronous failure, capture polling, inventory ordering, and image-list failure regressions were each demonstrated failing before their repair and passing afterward.
- Full `node scripts/check-changed.mjs` passed before the patch-identical rebase onto #144037. Post-rebase changed-file oxlint and all four focused snapshot test shards passed; both previously failing navigation assertions also passed. Exact-head CI [34480832658](https://github.com/openclaw/openclaw/actions/runs/34480832658) passed for `31306f3861d4ec0aee8b5de1bf2c2a0c89fa2d53`.

Earlier CI exposed two settings E2E assertions expecting the old restart notice; those assertions now require the complete intended notice. The integrated pin/delete browser fixture supplies the valid empty worker inventory it consumes. A cancelled security workflow passed on its single retry; the later navigation failures were repaired upstream in #144002 and #144037. No checks or baselines were weakened.

The additive optional provider-metadata compatibility risk is accepted within this reviewed change. Required fields, allocation identity, and preparation policy remain unchanged. Bundled-provider tests and core/plugin typechecks cover the changed boundary; arbitrary third-party providers were not exhaustively exercised.

[Maintainer-provided live UI proof](https://github.com/openclaw/openclaw/pull/143929#issuecomment-5619200603) covers Build snapshot through available-image publication and surplus retirement. The Snapshots UI and project-preparation modules are byte-identical to that proof revision across this rebase. The cancelled Labeler automation passed on its single retry.

## Screenshots

Mock Gateway fixture (synthetic profiles, one build in progress).

| Before: Snapshots view (read-only) | After: Build snapshot, Rebuild, Cancel, and a build row |
| --- | --- |
| ![before](https://github.com/user-attachments/assets/d54e8cff-fd89-4c42-99fa-e685cdd2bf51) | ![after](https://github.com/user-attachments/assets/e5eabb7c-63a7-49dd-90c6-7c89f182bee5) |

| After: build dialog |
| --- |
| ![build dialog](https://github.com/user-attachments/assets/defdee99-9bb1-4e76-ac7c-07c7786def00) |

The underlying `environments.prepare` path was proven live against Crabbox AWS in #143838 (build → capture → available → surplus retirement); this PR wires that method into the view.

The rebase onto #144037 preserved both source commits unchanged by range-diff. No duplicate navigation/catalog repair was included in this PR.
2026-09-10 06:37:46 -07:00
Peter Steinberger
e89128c69e
feat(control-ui): show cloud session machine specs (#143864)
* feat(control-ui): show cloud session machine specs

Expose optional OS, machine class, vCPU, and memory metadata on correlated
worker placements. Resolve provider defaults through lifecycle-owned catalogs
without changing persisted profile snapshots.

Show known machine facts in sidebar hovercards and placement tooltips. Refresh
session subscribers when discovery completes, and fence catalog warmups
against profile changes.

* test(gateway): account for machine catalog preflight discovery

Model the read-only providers catalog query in Crabbox preflight fixtures. Assert exact command sequences so failed preflight still cannot allocate or clean up a worker.

* refactor(gateway): centralize machine catalog lifecycle

Keep machine metadata subscriptions, cleanup, and warmup warnings with the catalog owner. Delegate its async listing operations directly so the environment service stays within its line limit after concurrent preparation changes.
2026-09-10 03:47:57 -07:00
Peter Steinberger
e5acecfca9
feat(gateway): prepare cloud workers on demand (#143838)
## Problem

Operators cannot prepare a cloud worker for a profile and local repository without first dispatching a session. Ready-worker demand currently comes from session activity.

## Solution

Add the admin-only `environments.prepare({ profileId, projectPath })` RPC. It validates the local Git checkout and pins HEAD, authorizes the committed setup recipe, atomically reuses matching inventory or admits a build, and schedules the existing preparation pool. List and status summaries expose preparation purpose and key; `environments.destroy` cancels an in-flight build while retaining provider settlement and cleanup ownership.

Persist purpose through nullable `worker_environments.preparation_purpose TEXT`, using the existing compatible additive migration. Legacy rows remain reserves. Unfinished builds bypass the per-project ready target, including reused reserves promoted to builds, while retaining their original expiry and obeying the global cap. Ready builds return to ordinary reserve retention. A zero global cap rejects admission before reuse.

Pool retention uses the inventory behind each pass's source snapshot while rereading existing rows live. A build admitted during an awaited retention operation is handled by the already-requested next pass, so stale eligibility cannot cancel successful admission. Current store queries still enforce capacity; expiry, cancellation, and provider settlement remain live.

## Impact

An operator can build an eligible project's prepared worker without creating a session. Admission returns its environment ID, preparation key, and whether it reused inventory. Validation and capacity errors remain typed. Existing reserve targets, idle timeouts, provider capture behavior, and global capacity accounting remain intact.

This adds no UI, CLI command, provider changes, version bump, or changelog edit. Build admission has a separate module to keep lifecycle ownership and file-size limits clear; the existing profile validator is shared, with its obsolete assertion-baseline allowance removed.

## Evidence

The [initial exact-head CI attempt](https://github.com/openclaw/openclaw/actions/runs/34455365820/job/102800854096) hit the pre-existing Doctor/plugin-index SQLite lock flake in `channel-plugin-blockers.test.ts`. The failing path is unchanged by this PR and is recorded for separate repair. The first authorized failed-job rerun passed. [Exact-head CI attempt 2](https://github.com/openclaw/openclaw/actions/runs/34455365820/attempts/2) completed successfully on `8ceaeb8f9e60a241badc1c283503c7783d68bc15`, including the required CI gate. No test or locking behavior was changed to bypass the failure.

- Reproduced the admission-versus-retention race before the fix: a newly admitted build was durably marked for destruction. All **50 tests across four pool suites** pass after the snapshot/liveness repair, including new-admission and reserve-promotion interleavings with zero ready target, global capacity, and preserved expiry. Fresh combined autoreview is scoped-clean through P2, and the full `check-changed` lane passed for the pool and schema-test repair.
- Schema-maintenance and prepared-environment-store suites pass **46 tests**, including bare nullable-column repair, legacy-row reopening, purpose persistence, and integrity checks. The schema contract list now includes the already-declared `preparation_purpose TEXT` column.
- The existing public method-order tests reproduced two failures because their appended suffix omitted `environments.prepare`. Added the new method to the exact suffix expectations and existing mutation-policy table; all **32 tests** in `server-methods-list.test.ts` pass with legacy prefix/index assertions preserved.
- Landing CI found missing generated native protocol models and a stale Workboard asset hash. Regenerated Swift/Kotlin outputs and the manifest using the repository commands; `pnpm protocol:check` and `pnpm plugins:assets:check` pass. Both repair diffs passed autoreview through P2. The initial Docker packaging failure followed generated assets dirtying the tracked tree; the replacement exact-head run passed Docker packaging as well as protocol and build-artifact checks.
- Post-rebase validation: changed-file `pnpm exec oxlint` passed; descriptor registry, release-train, and prepare RPC tests passed (**22 tests across 3 files**). The rebase retained both adjacent RPC descriptor additions and otherwise preserved the reviewed patch.
- `pnpm install` — passed.
- Broad worker, environment RPC, protocol, and state migration run — **3,088 passed**, two Windows-only tests skipped on macOS. This preceded the final mechanical admission extraction and zero-cap correction.
- Final focused run, including the corrected boundary tests and SDK E2E — **153 passed across 12 files**. The E2E runner also completed its runtime build.
- `node scripts/check-changed.mjs` — passed, including production/test typechecks, core/scripts lint, database guards, and zero runtime import cycles. Earlier type, lint, fixture, and shrink-only baseline findings were fixed.
- `pnpm db:kysely:check` — passed.
- `pnpm docs:check-links` — passed: 13,092 links checked, zero broken links.
- `git diff --check` — passed.
- Autoreview — scoped-clean through P2. Reserve promotion and zero-cap findings were fixed. Regression cases demonstrated the reserve-reuse, stale-expiry, cancellation, and zero-cap failures before their fixes.

Live provider build verification was not run; validation uses the boundary tests listed above.

The [initial CI test shard](https://github.com/openclaw/openclaw/actions/runs/34451706681/job/102788886784) also reported `StateDatabaseCoordinatorContentionError: another OpenClaw process owns state-lifecycle` while the update-run-ledger process fixture closed its database. The PR does not modify that fixture, test, coordinator, or database-cache lifecycle owner. No lifecycle-lock behavior was changed for this landing; the replacement shard passed, including the update-run-ledger tests.

<details>
<summary>Exact test and review commands</summary>

```sh
node scripts/run-vitest.mjs src/gateway/worker-environments/ src/gateway/server-methods/environments packages/gateway-protocol src/state/openclaw-state-db-prepared-workers.test.ts

node scripts/run-vitest.mjs src/gateway/worker-environments/service-prepare.test.ts src/gateway/worker-environments/prepared-pool-build.test.ts src/gateway/worker-environments/prepared-environment-store.test.ts src/gateway/worker-environments/prepared-pool.test.ts src/gateway/worker-environments/prepared-pool-expiry.test.ts src/gateway/worker-environments/prepared-pool-maintenance.test.ts src/gateway/worker-environments/provider-project-preparation.test.ts src/gateway/worker-environments/provider-intent.test.ts src/gateway/worker-environments/service-validation.test.ts src/gateway/server-methods/environments.prepare.test.ts packages/gateway-protocol/src/schema/environments.test.ts packages/sdk/src/app-sdk-composed-resources.e2e.test.ts

.agents/skills/autoreview/scripts/autoreview --mode local --max-priority P2 --dataset src/gateway/worker-environments/provider-intent.ts --prompt 'Review final environments.prepare change. Prior actionable findings are fixed: unfinished reserve reuse promotes to build without renewing expiry, and maxTotal zero rejects before reuse; both have before-fix failing regression proof. The capability concern was disproved by supplied unchanged provider-intent.ts: current provider support is rechecked before constructing preparation identity, and missing preparationKey rejects admission. Admission moved from service.ts into build-preparation.ts for max-lines; validated profile helper moved unchanged into service-validation.ts. Build-specific cancellation still retains provider settlement and cleanup ownership. Broad suite passed 3088 tests; latest focused final helper/store/pool/RPC/schema plus SDK E2E passed 153 tests. SDK build is finished and its unrelated generated manifest hash restored; sources are now stable.'
```

</details>
2026-09-10 02:28:18 -07:00
Peter Steinberger
5da05f85e4
fix: show full subagent transcripts in the task sidebar (#143747)
* fix: show full subagent transcripts in the task sidebar

* fix(codex): keep task history dependencies lazy

Preserve the registration-only import boundary and regenerate the dependent Workboard manifest.

* fix(codex): preserve native task history across refreshes

Expose stable shared message identities from native history projections and verify them across paging and content updates.

* test(ui): use task history in file intent fixture
2026-09-10 00:09:49 -07:00