Commit Graph

81255 Commits

Author SHA1 Message Date
Alix-007 607eb2efbf fix(agents): fall back from tool search code under Electron (#122037)
Punchcard-Session: ember-cedar-willow-tp
2026-08-20 01:44:53 -07:00
Vincent Koc 45ed68e6ea fix(release): accept trusted Codex scan layouts (#126588)
Allow the trusted release inventory to accept exactly one complete reviewed Codex source layout while remaining fail closed for partial, mixed, duplicate, absent, or unknown layouts. Frozen-candidate and upstream Codex contract proof are recorded in the PR.
release-publish/45ed68e6ea62-1787220256
2026-08-20 01:38:27 -07:00
Peter Steinberger 1d2986b06f fix: prevent incompatible cloud runtime dispatches (#126585)
* fix(ui): gate cloud profiles by runtime mode

* test(gateway): expect cloud placement mode

* test(gateway): keep route suite within lint budget
2026-08-20 01:31:27 -07:00
Vyctor H. Brzezowski 68ae235318 improve(ui): refine chat widget host and image actions (#125250)
* improve(ui): refine chat widget host actions

* fix(ui): keep widget pin presentation unchanged

* fix(ui): compact widget actions and restore rounded host

* style(ui): format widget action menu

* test(canvas): refresh widget host document contract

* test(ui): model the widget host wrapper

* fix(ui): preserve retained widget downloads

* fix(ci): register Codex tool coverage

* fix(protocol): keep version exports compact

* fix(ui): preserve widget action outcomes

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-20 05:27:56 -03:00
weiqinl bd6802ffb6 test(ui): make formatNextRun weekday assertion locale-portable (#125164)
The "includes weekday and relative time" test computed the expected
weekday with the ambient host locale (`toLocaleDateString(undefined, ...)`)
while `formatNextRun` formats the weekday through `i18n.getLocale()`
(default "en"). On hosts whose default locale is not English (e.g.
`LANG=zh_CN.UTF-8` -> "周一"), the two diverge and the slice assertion
fails: `expected 'Mon,' to be '周一, '`.

Mirror `i18n.getLocale()` in the test so the expected weekday always
matches the locale the presenter uses. No production behavior change.

Verified: passes under `LANG=zh_CN.UTF-8` and `LANG=C` via
`pnpm test:unit:fast -- test/ui.presenter-next-run.test.ts`.

AI-assisted.
2026-08-20 01:25:28 -07:00
Peter Steinberger 7f68741cdd perf(test): inject QA evidence command runner (#126596) 2026-08-20 01:22:30 -07:00
weiqinl a29d8c8803 test(unit-fast): isolate computer-tool.test-helpers consumers (#125167)
* test(unit-fast): isolate computer-tool.test-helpers consumers

The unit-fast shard classifier recognizes "stateful" test helpers
(those whose source trips a disqualifying pattern such as `vi.mock(`
or top-level dynamic `import`) via `statefulTestHelperImportPattern`,
so that tests importing them are routed to the isolated pool instead
of the shared `isolate:false` pool.

`computer-tool.test-helpers` was missing from that pattern, even though
the helper sets up `vi.mock("./gateway.js")`, `vi.mock("./nodes-utils.js")`
and uses top-level `await import(...)` — i.e. it is stateful. Its
consumers (`computer-tool.v2/schema/context.test.ts`) therefore
classified with empty `reasons`, fell into the `isolate:false` pool,
and relied on `vi.mock` against a shared module registry. When another
test file loaded the real `./gateway.js` / `./nodes-utils.js` in the
same worker first, the mock was bypassed and `computer-tool.v2.test.ts`
threw `GatewayCredentialsRequiredError: gateway node.list requires
credentials` for all 8 of its cases — while passing in isolation.

Add `computer-tool\.test-helpers` to the pattern (mirroring the existing
`message-action-runner\.test-helpers` entry) so consumers are routed to
the isolated pool where the mock is honored.

Verified on `main` (`83d279a`), Node 24.15.0:
- Before: `pnpm test:unit:fast` -> 8 failures in
  `src/agents/tools/computer-tool.v2.test.ts` (`GatewayCredentialsRequiredError`);
  the file passes alone (8/8).
- After: the three consumers classify `inIsolated=true`; `pnpm test:unit:fast`
  no longer runs them in the shared pool; the suite's only remaining
  failures are unrelated (`test/ui.presenter-next-run.test.ts` locale,
  `test/scripts/resolve-openclaw-ref.test.ts` git version) and the
  computer-tool suite passes (16/16) under `vitest --isolate`.

AI-assisted.

* test(unit-fast): cover computer-tool helper isolation

Punchcard-Session: ember-willow-valley-9r

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-20 01:17:25 -07:00
Peter Steinberger 10e707435a fix(mcp): repair channel lifecycle ownership (#126592)
Restore persisted channel media, cancellation cleanup, retryable permission delivery, bounded-event gap recovery, complete shutdown, and actionable Gateway startup diagnostics.
2026-08-20 01:14:43 -07:00
Peter Steinberger 83978aec63 fix(ui): refresh approval history when decisions resolve (#126579) 2026-08-20 01:13:42 -07:00
Peter Steinberger ab7fc490d6 fix(package): clean dist before root packaging (#126577) 2026-08-20 01:13:06 -07:00
Peter Steinberger 980b07f4a2 refactor(agents): replace tool-failure warning heuristics with a two-rule policy (#126542)
* refactor(agents): reduce tool failure warnings to two rules

* test(agents): remove obsolete tool recovery receipt proof

* refactor(agents): drop unused meta param from buildToolMutationState

* test(agents): remove stale tool warning assertions

* test: export runtime source snapshot from closed runtime-snapshot mocks

Heal the main breakage introduced by 9441e3fe6e / #126531, which added a runtime source-snapshot read to provider model route resolution. Closed Vitest factories now return null for that source snapshot, preserving their pre-projection behavior.

* test(gateway): make compaction read-error faults order-immune

Generation-2 CI failure in run 32342180898, job 96343444772 showed that the mock factory initialized while shared gateway-server importers remained bound to the real transcript reader.

The dedicated isolated project fixes normal shards. Complete its ownership by adding it to the root project matrix and excluding the test from the non-isolated OPENCLAW_GATEWAY_PROJECT_SHARDS=0 fallback.
2026-08-20 01:11:05 -07:00
chelsealong b886eed3de fix(macos): surface concrete Gateway start failure reason in onboarding (#121306)
* fix(macos): surface concrete Gateway start failure reason in onboarding

GatewayProcessManager already retains the specific registration/readiness
failure (e.g. "launchd disabled", a launchd enable error, a readiness
timeout) in lastFailureReason, and Settings/menu bar UI already read it.
Onboarding discarded it: LocalGatewayActivation.failed collapses every
cause to the same generic "Retry setup" message, so a missing LaunchAgent
registration is indistinguishable from any other startup failure.

Surface the retained reason in the onboarding status text so the failure
is diagnosable without going through Settings.

* fix(macos): record command-resolution failures in lastFailureReason

GatewayProcessManager set status but not lastFailureReason when
GatewayEnvironment.resolveGatewayCommand() returns no command (missing
runtime/CLI), unlike the launchd-disabled and launchd-enable-error
branches a few lines below. Onboarding's new failure message therefore
rendered the generic text or a stale reason from an earlier attempt
for this failure class. Mirror the sibling branches and record
resolution.status.message.

Also fixes the macos-swift SwiftFormat lint failure: the comment block
directly above gatewayStartFailureMessage needed to be a doc comment
(///), matching the repo's existing convention for declaration-adjacent
comments.

* fix(macos): bind Gateway start failure reason to its activation attempt

LocalGatewayActivation.failed carried no data, so both onboarding call
sites reread the mutable GatewayProcessManager.shared.lastFailureReason
singleton after activateLocalGateway() returned. A later gateway-start
attempt can overwrite that singleton before the caller gets around to
reading it, so a stale wait could surface a newer attempt's reason (or
vice versa) attributed to the wrong onboarding attempt.

Widen LocalGatewayActivation.failed to carry reason: String?, captured
inside activateLocalGateway() the instant waitUntilReady() resolves to
false, and have both onboarding call sites map that bound value instead
of rereading the singleton. CLIInstallPrompter's two `!= .failed`
comparisons become `if case .failed = activation` pattern matches since
`.failed` is no longer a payload-free value; its existing `case .failed:`
message switch is unaffected, since bare-case patterns still match
regardless of associated data.

* fix(macos): satisfy SwiftFormat lint on CLIInstaller.swift

Converts the LocalGatewayActivation.failed declaration comment to a
doc comment and wraps activateLocalGateway's closing signature per
config/swiftformat, matching the same docComments convention already
applied elsewhere in this PR. No behavior change.
2026-08-20 01:08:12 -07:00
Peter Steinberger 4fd208fc60 fix(sessions): preserve conversation preferences on reset (#126575) 2026-08-20 01:06:21 -07:00
Peter Steinberger 764622342c fix(ui): keep empty session groups compact (#126565) 2026-08-20 00:58:54 -07:00
Peter Steinberger 5066bd782e fix(agents): continue oversized read lines (#126587) 2026-08-20 00:57:06 -07:00
Heming Zeng 366dbebd98 fix(agents): reject unusable explicit spawn models (#125931)
Prevent explicit subagent model requests from silently falling back by validating model policy and provider ownership before child state is created.

Co-authored-by: Heming Zeng <hermanzeng@foxmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-20 13:19:53 +05:30
Peter Steinberger 531fc9b365 fix(ui): read-only Agents identity editor stays stuck on Saving (#126568)
* fix(ui): show accurate save state for read-only agents

* test(ui): use canonical text content in agent save assertion
2026-08-20 00:48:17 -07:00
Peter Steinberger 4d6c40ae30 fix(replies): settle pre-aborted delivery immediately (#126582) 2026-08-20 00:44:03 -07:00
Peter Steinberger 828f1fa851 perf(test): gate lazy recovery proof capture (#126583) 2026-08-20 00:43:50 -07:00
Peter Steinberger 147edf47f3 fix(auth): keep a retired auth JSON from stranding a migrated store (#126562)
* fix(auth): keep a retired auth JSON from stranding a migrated store

Runtime failed closed with AUTH_PROFILE_MIGRATION_REQUIRED whenever a retired
credential file was present, even when the canonical SQLite store already held
the agent's profiles. One leftover auth.json therefore made a fully migrated
install unusable, and the gateway lifecycle preflight refused start/restart on
top of it, so every channel and provider stayed offline until Doctor ran.

A legacy file is now only fatal when the canonical store cannot serve
credentials. Doctor's importer never overwrites a usable stored credential, so
a file sitting beside a populated store is unarchived bytes, not pending
migration: runtime logs a one-time warning and keeps serving. An empty store
with a credential file still fails closed and never falls through to
environment auth. Startup degrades that owner to configured-unavailable
instead of refusing to boot, which lets the lifecycle preflight go away.

* refactor(secrets): retire the auth-profiles.json vocabulary

Auth profiles moved to SQLite, but operator-facing surfaces still named the
retired JSON file. The duplicate-agentDir error told operators to copy
auth-profiles.json to share credentials, which does nothing and lands the
second agent in a migration-required state; `openclaw migrate plan codex`
reported a target file that is never created; and the secrets picker labelled
candidates with a filename that no longer exists.

Renames the SecretTargetConfigFile discriminator to "auth-profile-store" and
corrects the operator-facing text, the migrate plan target, and the docs that
described the file as a live target. Genuine legacy-filename uses in doctor,
the security fixer, and migration fixtures are unchanged.

Also deletes resolveSecretPlanTargetByPath and ResolvedSecretPlanTarget from
the plugin SDK. They have no callers in core, plugins, or tests, and the
symbols are absent from the latest stable tag, so they carry no compatibility
obligation and are removed rather than deprecated. Their inline parameter type
was the only thing putting the retired filename on the public SDK surface.

* improve(wizard): warn about device-code phishing

The device-code prompt only warned against sharing the code, and only when an
expiry was known. Device-code phishing works the other way around: the attacker
starts the login and gets the victim to enter the attacker's code. Codes
delivered over a chat channel are the risky case and carry no expiry hint, so
the warning is now unconditional and covers received codes, matching the Codex
CLI prompt.

Also documents the Codex auth handoff: a subscription profile is installed as
in-memory external auth rather than persisted, and token refresh is inverted
so the refresh token stays in OpenClaw's store.

* fix(test): make transcript read-failure injection order-independent

server.sessions.compaction-read-errors.test.ts injected its failures with
mockRejectedValueOnce, which fails the NEXT call to loadTranscriptEvents
globally. Under --isolate=false a shard shares one worker, so any sibling
transcript read could consume the one-shot rejection before the compaction RPC
issued its own; compaction then ran against the real reader and returned ok,
failing three assertions. This shard was already red on main; a prior repair
fixed the mock's initialization order but left the call-order dependency.

Key the injection on the seeded sessionId instead, so unrelated readers cannot
consume it and the re-read case counts only its own session's reads.

Also updates two expectations invalidated by this branch: the duplicate-agentDir
remediation text, and the plugin SDK export ratchet, shrunk by the two retired
secret-plan exports.
2026-08-20 00:42:41 -07:00
Peter Steinberger 966c233dcc refactor(sessions): remove thinking selection provenance (#126561)
* refactor(sessions): remove thinking selection provenance

* test(gateway): fix shared-worker reasoning cleanup

* test(gateway): avoid shared-worker merge overlap
2026-08-20 00:38:45 -07:00
Peter Steinberger 83c0f81173 fix(onboard): keep token suppression in guided setup (#126580) 2026-08-20 00:38:40 -07:00
Peter Steinberger 921e945013 fix(onboard): keep OpenRouter API keys with their provider (#126578) 2026-08-20 00:35:27 -07:00
Peter Steinberger 75fcb1fbb9 fix(memory): reject unknown --agent ids and keep the hint runnable (#126570)
The memory CLI resolved --agent by returning the caller's string verbatim,
so an id that is not configured produced a confident empty result:
`memory status` rendered a panel for it, `memory index` fabricated a
workspace-<id> path, and `memory search` reported No matches. A typo read
as an empty memory rather than a nonexistent agent, while hooks, status
--usage, capability, migrate, and session targets already rejected unknown
ids.

Consolidate that duplicated check into resolveConfiguredAgentId beside the
agent roster owner, reuse it at the matching core sites, and route memory
to it through the existing memory-core host-runtime facade so no new
plugin SDK surface is added.

The canonical hint uses formatCliCommand rather than a literal: under a
profile or container the bare command is wrong, so consolidating on a
literal would have regressed the hooks and migrate hints and left the
status, capability, and session-target hints unrunnable.
2026-08-20 00:32:59 -07:00
sunlit-deng a19d924797 fix(lmstudio): expose read-only reachability probe for guided setup (#119134)
* fix(lmstudio): expose read-only reachability probe for guided setup

* fix(lmstudio): route guided availability through public setup API
2026-08-20 00:32:05 -07:00
Peter Steinberger 16bec3c727 fix(memory): keep tool guidance aligned with sources (#126552)
* fix(memory): keep tool guidance aligned with sources

* refactor(memory): keep source contract internal
2026-08-20 00:30:52 -07:00
Alix-007 2a79f74701 fix(ui): prioritize active session quota provider (#120557) (#122053) 2026-08-20 00:22:30 -07:00
Peter Steinberger 49cd6009cc test(gateway): give module-mocking Gateway tests a private module graph
`server.sessions.compaction-read-errors` mocks
`config/sessions/session-accessor.sqlite-read.js`, but production reaches
`loadTranscriptEvents` through re-exports: `server-methods/sessions-compact.ts`
imports it from the `session-accessor.js` barrel and
`preflightSessionTranscriptForManualCompact` imports it from the leaf. The
`gateway-server` project is `isolate: false`, so when a neighbour has already
evaluated those importers they stay bound to the real implementation and the
mock never fires -- the injected read error simply does not happen and all three
tests fail with `expected true to be false`, reading like a product regression.

Trigger: 33744584f3 added `server.chat-metadata-boundary.test.ts`, which boots
a full non-minimal Gateway in `beforeAll` and lands immediately before this file
in the shard. Main has gone red on it repeatedly since (32338154086, 32339521003,
32339928383, 32341300955, 32341946296); e294c154a6 fixed only the sibling
symptom where the factory had not run yet.

Route the file to a new `gateway-server-isolated` project instead, mirroring
`unit-fast-isolated` -- whose comment describes this exact hazard. A fresh graph
per file makes both symptoms structurally impossible rather than order-dependent.
The list is explicit so the reason travels with the file.

Not reproducible on macOS: the exact 24-file stripe in CI's own order, and the
triggering pair three times, are green locally every time.
2026-08-20 00:16:43 -07:00
SunnyShu a6a8f74ac3 fix(onboard): report requested daemon install failure regardless of --skip-health (#122845)
* fix(onboard): fail requested daemon installation when health is skipped

Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>

* test(onboard): avoid shadowing the shared regression runtime

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-20 00:12:43 -07:00
Vyctor H. Brzezowski 689ab6ec82 fix(ui): contain narrated tool details (#126348)
* fix(ui): contain narrated tool details

* fix(ui): repair narrated tool details
2026-08-20 04:04:53 -03:00
Peter Steinberger 9cf5859d57 ci: refit hybrid compact hints from measured Blacksmith runs
Hybrid runs attempt 1 on Blacksmith but packs bins with the GitHub-calibrated
`COMPACT_GITHUB_GROUP_SECONDS_HINTS`. Measured across four healthy main runs
(32316204633, 32317242374, 32318250756, 32320063231), normalized per run by
that run's own VM speed, those hints land at 0.64x on Blacksmith across 100
groups -- so nearly everything is over-predicted and only five groups overshoot:

  core-runtime-infra-process   x2.03   34.5s vs 17
  agentic-cli-process          x1.64  109.8s vs 67
  agentic-agents-core-models   x1.45   81.3s vs 56
  core-runtime-cron-service    x1.35  107.8s vs 80
  agentic-commands-doctor      x1.30   82.9s vs 64

Those five are exactly the ones that matter: an under-predicted group leaves
budget for partners, so the packer piles work onto the bins that already set the
wall. Replaying the plan against the measured per-shard medians, the tallest bin
drops from 164s to 141s of test time and the runner-up from 151s to 140s, for one
extra job (47 -> 48 on push). The plateau is flat and queue time is ~2s, so the
extra job is free and the 23s comes straight off the critical path.

Guard counts move with the plan; they exist to make repacking deliberate, and the
150s non-dist ceiling and 140s max are unchanged.
2026-08-19 23:59:18 -07:00
Peter Steinberger c3051d453c perf(test): fake TUI auth child timers (#126563) 2026-08-19 23:50:34 -07:00
Peter Steinberger 1b6c42d1f0 refactor(openai): unify ChatGPT auth identity derivation in plugin SDK (#126544)
The OpenAI ChatGPT auth profile identity was derived in two drifted copies:
the plugin-sdk helper (used by Codex/Hermes import migrations) fell back to
bare JWT sub and leaked the workspace accountId into the user subject, while
the openai extension copy (used by login/refresh) composed the OIDC-stable
iss|sub pair and honored the credential email fallback.

Fold the extension's chain into the canonical SDK helper (credential-email
fallback, iss|sub before bare sub, no workspace-id subject), delete the
extension copy, and move all extension call sites onto
openclaw/plugin-sdk/provider-auth. Cross-checked against Codex OSS
(codex-rs/login/src/token_data.rs): chatgpt_account_id is workspace identity,
never user identity. No doctor migration: the divergent fallback branch only
fires for tokens lacking every user-id claim and email, which real ChatGPT
tokens do not produce, so no shipped install holds divergent keys from it.
2026-08-19 23:48:43 -07:00
Peter Steinberger c15f31df49 fix(crabbox): keep worker wallpaper in XFCE session (#126560)
Bind setup to the active worker-owned XFCE session and reload the existing renderer so desktop recovery does not leave a black wallpaper.
2026-08-19 23:45:53 -07:00
Peter Steinberger e294c154a6 test(gateway): resolve mocked implementations without factory timing
`server.sessions.compaction-read-errors` captured the real transcript reader as
a side effect of its `vi.mock` factory and consumed it in `beforeEach`. Vitest
runs a factory on first import of the mocked module, and the gateway-server
project is `isolate: false`, so on a warm module graph the factory can still be
unrun when the hook fires. Run 32335933003 hit that on `main`: all five tests
failed with `transcript reader mock was not initialized` while the same 24-file
shard passes locally in the same order.

Resolve the real implementations with `vi.importActual` at use time instead, so
there is no state that can be observed before it is written. Applies the same
repair to the two siblings sharing the invariant: `server.sessions.create`
(which had worked around it by force-importing both mocked modules in
`beforeAll`) and `client-voice-session` (whose `beforeEach` silently skipped
installing the real append when the capture was missing).

`tools.optional` keeps its guard: it evaluates inside the mock implementation,
so the factory has necessarily run by then.
2026-08-19 23:36:39 -07:00
Peter Steinberger dc59703a16 fix(qa): isolate character eval artifacts (#126558) 2026-08-19 23:31:01 -07:00
Peter Steinberger bf03acef39 fix(gateway): release channel startup gate before handoff (#126555) 2026-08-19 23:29:01 -07:00
Peter Steinberger a947730c66 fix(sessions): scope legacy-main owner notice to real legacy rows (#126551)
* fix(sessions): scope legacy-main owner notice to real legacy rows

resolveArmingDecision returns owner-unresolved purely from config, before any
session store is read, so the unresolved-owner notice and the agents-create
gate both fired without checking whether any legacy `main` rows exist. A new
explicit-ownership fleet with zero session data printed "legacy main rows have
no unambiguous configured owner" on every startup, and `agents create main`
dead-ended: it told operators to run `openclaw doctor --fix`, which cannot
resolve anything when there is nothing to migrate.

Probe the candidate stores in the unresolved-owner branch and report
no-legacy-rows when every store proves clean. Unreadable stores, legacy JSON
stores, and genuine read failures still fail open and keep the notice, so the
precaution survives exactly where absence cannot be proven. The main-creation
gate now blocks an unarmed run only when the scan did not prove the fleet
clean; armed runs still require a completed ledger.

Store scanning moves to legacy-main-session-key-scan.ts: the probe and the
armed claim reader share one normalization-aware key predicate, so a store
holding `agent:Main:...` or another key that normalizes to `main` cannot be
misread as clean, and the migration module stays under the max-lines limit.

* test(gateway): stop compaction read-error mocks depending on factory order

src/gateway/server.sessions.compaction-read-errors.test.ts captured the real
loadTranscriptEvents as a side effect of its vi.mock factory, then required it
in beforeEach. The factory runs on first import of the mocked module, so once a
shard shares a worker (--isolate=false) the field could still be unset and all
five tests failed with "transcript reader mock was not initialized".

Resolve the real reader with vi.importActual in beforeAll instead, so the
default implementation no longer depends on whether the factory has run.

Pre-existing on main: 0a8226c3 fails the same checks-node-compact-small-4 shard
with the identical five tests. Not reproducible locally, including with the
exact 25-file shard composition; CI on Linux runners is the verification.

* test(gateway): load the mocked transcript reader deterministically

src/gateway/server.sessions.compaction-read-errors.test.ts captures the real
loadTranscriptEvents as a side effect of its vi.mock factory and requires it in
beforeEach. The factory only runs when the mocked module is first imported, and
nothing in this file imported it directly, so once a shard shares a worker
(--isolate=false) the capture could still be unset and all five tests failed
with "transcript reader mock was not initialized".

Import the mocked module for its side effect so the factory always runs.

Resolving the reader with vi.importActual instead was wrong: that returns a
separately instantiated, unmocked copy that does not share the module-level
SQLite state the harness sets up, so it read no events, compaction no-opped
successfully and the three rejection tests failed on response.ok. Capturing
through importOriginal keeps the harness's own module instance.

Pre-existing on main: 0a8226c3 fails the same checks-node-compact-small-4 shard
with the identical five tests.
2026-08-19 23:25:14 -07:00
Vito Cappello f612675284 fix(models): keep Claude CLI OAuth available in Control UI (#125471)
* fix(models): honor Claude CLI OAuth ownership in Control UI

Co-authored-by: XX441 <169966250+XX441@users.noreply.github.com>

* test(models): preserve OAuth fixture literal type

* fix(models): preserve persisted CLI runtime ownership

* fix(auth): discover Claude CLI credentials for Anthropic scope

* fix(models): honor CLI-owned OAuth over legacy metadata

* fix(models): migrate CLI OAuth profile ownership

* fix(models): centralize CLI metadata normalization

* fix(doctor): keep CLI migration result internal

* test(models): type CLI OAuth fixtures

* refactor(models): isolate auth status projection

* refactor(models): split auth status API key projection

* fix(auth): preserve legacy CLI metadata on failed migration

* fix(auth): retain healthy CLI OAuth migration state

* fix(doctor): type CLI migration store fallback

* test(doctor): type CLI migration store mock

* fix(models): retain non-CLI credential expiry status

* fix(models): preserve independent auth route status

* fix(models): retain independently configured alias auth

* test(ui): stabilize activity feed fixture clock

* fix(auth): preserve legacy CLI recovery metadata

* fix(auth): scope legacy CLI migration to Claude

* fix(auth): preserve MiniMax CLI expiry ownership

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: XX441 <169966250+XX441@users.noreply.github.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-19 23:05:32 -07:00
Peter Steinberger 1bf3e4e9b8 fix(android): gate gateway RPC polling on the hello method catalog (#126540)
* fix(android): gate gateway RPC polling on the hello method catalog

Released 2026.7.x gateways authorize before dispatch and reject unknown
methods with "missing scope: operator.admin", so the app's
"unknown method: X" detectors never fired: outbox sends parked forever
behind an ~800ms sessions.branches.list retry loop and question.list
retried on every health event. Generalize the progress-card negotiation
(3377a21c4e) into a tri-state gatewayAdvertisesMethod seam fed by
hello features.methods and skip sessions.branches.list, question.list,
and progressCard.get when the gateway does not advertise them; branch
scopes reconcile immediately and queued sends flush.

* fix(android): keep the hello method catalog unknown when hello omits features.methods

A successful connect without a usable features.methods list must not read
as a known-empty catalog: parse it as null so gatewayAdvertisesMethod stays
tri-state and the catalog gates no-op instead of skipping documented RPCs.
Pairing capabilities keep positive-advertisement semantics via orEmpty().
Addresses the ClawSweeper P1 on #126540.
2026-08-19 22:56:15 -07:00
Peter Steinberger 0a8226c3db fix(ui): give embedded settings sections the shared section rhythm (#126541)
* fix(ui): give embedded settings sections the shared section rhythm

The agents tab panel hosted settings sections in a bare div, so sections
stacked with zero separation; the bespoke .agents-main margin rule in
agents.css missed the nested tabpanel entirely. Descriptions also pulled
up to 4px under control-height header actions (squeezed Verify/Save rows).

Add a .settings-stack primitive to settings.css for embedded surfaces,
use it on the agent tab panel, delete the page-local margin fork, and let
section descriptions clear action-bearing headers.

* test(agents): export getRuntimeConfigSourceSnapshot from runtime-snapshot mock

Main's checks-node-compact-large shard is red: #126531 routed
provider-model-routes through projectConfigOntoRuntimeSourceSnapshot,
which reads getRuntimeConfigSourceSnapshot, and this suite's explicit
vi.mock factory did not export it (24 failures). Return null so the
projection no-ops and resolvers keep reading the provided config.
2026-08-19 22:31:35 -07:00
Vito Cappello 33744584f3 fix: New Session stays on Models unavailable after a missing catalog owner (#125450)
* fix: New Session stays on Models unavailable after a missing catalog owner

Control UI chat.metadata cached the first unavailable snapshot, and a
partial auth-bind publication could fail-close the picker while sibling
owners were still stale.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(gateway): type unavailable metadata owner fixture

* test(gateway): cover sticky metadata recovery boundary

* test(gateway): reuse metadata boundary server

* test(gateway): remove chat metadata shard order race

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-19 22:21:01 -07:00
Peter Steinberger 6a637469a0 fix(memory): detect offline source drift in status (#126535)
* fix(memory): detect offline source drift in status

* fix(status): preserve memory source inspection

* test(status): cover memory source inspection
2026-08-19 22:14:38 -07:00
Peter Steinberger 4b55192f81 fix(gateway): defer restored subagent recovery until ready (#126523) 2026-08-19 21:55:17 -07:00
Hannes Rudolph 9441e3fe6e fix(models): preserve Codex selection for catalog-seeded models (#126531)
* fix(models): keep catalog compat out of route overrides

* fix(models): preserve authored compat provenance

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-19 21:54:57 -07:00
Peter Steinberger efc33f882e fix: preserve GPT-5.6 Max and Ultra through Codex (#126492)
* fix(agents): preserve GPT-5.6 thinking capabilities

Carry harness-owned effort metadata from the prepared catalog to the final executable model without leaking it across model or harness changes. Preserve exact GPT-5.6 registry metadata and persisted Ultra selections across route-scoped projections.

* fix(agents): resolve ambient catalog owner

* test(commands): mock thinking hydration policy

* fix(sessions): validate persisted thinking selections

* fix(commands): persist thinking selection provenance

* fix(agents): scope thinking hydration per fallback

* fix(sessions): hide fallback thinking provenance
2026-08-19 21:48:18 -07:00
Peter Steinberger 29f86119e0 docs(gateway): recommend Access service tokens over route exemption (#126536)
* docs(gateway): recommend Access service tokens over route exemption

* docs(gateway): fix Nodes heading link
2026-08-19 21:40:44 -07:00
Peter Steinberger f289685bf3 fix(ui): stabilize settings and update recovery E2E (#126538)
* test(ui): await settings takeover in app chrome E2E

* test(ui): assert current build after update recovery
2026-08-19 21:39:26 -07:00
Peter Steinberger 70b6f44f13 improve: one alert surface, explained by Ask OpenClaw (#126155)
* refactor(ui): unify sidebar alerts with custodian

* refactor(ui): move custodian alert state

* fix(ui): use the defined mono token in the custodian alert card

* fix(ui): break the update-watcher import cycle

Type the watcher against a structural leaf contract instead of
Pick<ApplicationContext,...>; context.ts reaches this module through
overlays-types.ts, so naming the context type closed a madge cycle.

* fix(ui): re-arm the alert explanation when an incident recurs

Failed-automation and model-auth alerts keep one incident id across
recover-then-fail-again, so an id-keyed dedupe showed the renewed alert
and never explained it. Scope ask-once to the presentation instead.
2026-08-19 21:33:31 -07:00
Omar Shahine 641ccba793 fix(cli): allow agent selection for direct inference (#125143)
* fix(cli): inherit inference agent options

* fix(cli): route inference model auth agents

* fix(cli): route video describe agent

* fix(cli): route audio transcription agent

* fix(cli): preserve inherited agent selectors

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-08-19 21:27:09 -07:00