* fix(macos): let AI setup proceed when the login keychain is unavailable
A missing/locked login keychain made GatewayActivationBindingKeyStore
unable to mint the activation binding key, and onboarding refused every
candidate and manual-key activation with 'Secure storage is unavailable'.
The fingerprint only protects the crash/relaunch resume receipt, so
degrade instead of refusing: write an ownerless pending record (still
matched exactly, never as a wildcard), keep the full activation-ambiguity
window, and skip only restart reconciliation, which needs fingerprint
proof by design. A relaunch then repeats activation rather than trusting
the receipt.
Reported by Peter Steinberger.
* fix(macos): render proper provider brand icons in onboarding AI setup
Nearly every provider icon URL the gateway sends is a simpleicons.org
SVG, which AsyncImage cannot decode, so the Connect your AI page fell
back to generic symbols for every tool and provider; the two GitHub
avatar PNGs that did render clashed as full-color rasters.
Bundle nine monochrome template marks (Simple Icons CC0; xAI from
LobeHub icons, MIT) and resolve them local-first by brand id/kind,
including composed choice ids like xai-oauth. Remote icons now load via
NSImage(data:), which decodes SVG, with vector payloads tinted as
templates so plugin-supplied icons blend too. Every glyph sits in a
uniform rounded well; install cards show host-only links, hover states,
and a softer translucent surface shared by all setup sections instead
of controlBackgroundColor.
Requested by Peter Steinberger.
* fix(macos): use failable UTF-8 decode in icon vector sniffing (swiftlint)
* fix(macos): address ClawSweeper review of onboarding icon/keychain changes
- Refuse relaunch handoff from ownerless (keychain-unavailable) completed
receipts at the reconciliation trust boundary; such receipts can belong
to replaced credentials, so setup repeats a fresh activation instead.
- Decode and pass the canonical brandId the gateway sends for candidates,
auth options, and manual providers so bundled marks resolve for opaque
choice ids.
- Scan the bounded XML prolog (comments, declarations, doctype) when
sniffing remote SVG payloads; comment-prefixed vectors now tint as
templates.
* refactor(macos): move setup error enum to support file (swiftlint file length)
* chore(i18n): refresh native source inventory
* fix(macos): give keychain-unavailable activations attempt-specific unbound leases
A nil owner made concurrent unbound attempts indistinguishable: a stale
attempt's delayed response could complete or clear a newer attempt's
record. Unbound attempts now mint a random per-attempt lease id with a
sentinel fingerprint — live matching stays attempt-exact, restart
reconciliation's fingerprint guard rejects them, and relaunch
verification refuses unbound receipts before any handoff.
* chore(macos): ship third-party artwork notices with provider icons
Simple Icons (CC0) attribution and the LobeHub Icons MIT license text
for the xAI mark now travel inside the bundled ProviderIcons directory.
* fix(ci): refresh plugin-sdk API manifest for private-type hashing
#120975 changed the baseline generator to hash private types but landed
without regenerating the manifest; the check-plugin-sdk-api-baseline
lane was gated off on that PR and first failed here. Regenerated via
pnpm plugin-sdk:api:gen with no SDK surface change in this branch.
Make timeout paths cancel or release every pending test continuation before cleanup, so failures cannot poison the remaining Swift suite. Inject the retry sleeper to preserve invalidation-before-backoff ordering without real-time polling.
* feat(agents): record run-end worktree cleanup outcome
Persist removed, retained, and failed run-end cleanup outcomes on managed worktree records. Operators and QA can inspect the durable fact through worktrees.list and openclaw worktrees list --json.
Release note: Managed worktree run-end cleanup now records why a checkout was removed or retained in worktree list JSON.
* test(qa): prove dirty worktree retention outcome
* chore(protocol): regenerate swift gateway models
* fix(agents): harden worktree cleanup recovery
Register run_end_cleanup_json as a lazy compatible column so same-version v6 index repair and read-only doctor migration can recover databases created before the column existed.
Type removal contention at the registry boundary; unexpected claim failures now best-effort record a bounded failed outcome and rethrow the original error.
* fix(ci): clear repo-wide lint debt blocking merge gates
The red-main landing rule requires this PR to repair repository-wide merge-gate debt instead of bypassing it. Apply the current lint contracts mechanically and split turn-transition coverage into a concept-named sibling with per-file-safe test state.
Exact line delta: +676/-574 (net +102) across 44 test/support files.
* fix(ci): preserve cached health refresh proof
Require the public refresh call to exist before accepting that sensitive fields were omitted, so the boundary proof cannot pass on a missing call.
* fix(ci): correct test typing left by the lint sweep
Literal-widened totalTokensVersion fixtures, a WebSocket RawData overload
mismatch, and the protocol schema document cast broke check-test-types
after the repo-wide lint repair. Aligns the fixtures with SessionEntry,
narrows Buffer handling per RawData, and keeps the JSON-shaped undefined
omission under structuredClone.
* test(agents): reuse upstream resource-loader test support
The session-loop split and #120463's helper extraction landed the same
createResourceLoader/createCompactionHandlers twice; the rebase kept both,
orphaning main's agent-session-loop-resource-loader.test-support.ts and
failing the dead-code gate. Import the upstream helpers and delete the
duplicates.
* fix(agents): reject finalized rows at the worktree removal claim
Address the accepted ClawSweeper late-claim finding by rereading and rejecting missing or finalized worktree rows inside the synchronous removal-claim transaction.
Preserve the authoritative cleanup invariant: finalized contenders record nothing, while retained-busy is written only while the row remains live.
* refactor(agents): reuse registry update for busy outcomes
Keep the live-row conditional write in the canonical registry update path so the finalized-claim repair stays below the registry max-lines ratchet without weakening the authoritative-outcome invariant.
* test(agents): drop session test duplicates after rebase
Keep current main as the canonical owner of next-turn lifecycle coverage and correctness test support after replaying the older lint-debt split.
* fix(agents): guard post-abort cleanup outcomes against finalization
After abortWorktreeRemoval releases a stale remover's claim, its retained or
failed write raced a finalizing remover and could overwrite the authoritative
removed-lossless fact. Route every retained/failed write through the live-row
condition; only the finalizing remover's own removed-lossless write stays
unconditional.
* fix(agents): persist the removal outcome atomically with finalization
A delayed removed-lossless write after remove() finalized could race a
restore plus newer cleanup and overwrite the newer operator-visible fact.
The run-end outcome now rides remove()'s finalization update; every other
cleanup write stays live-row conditional, so no post-finalize write path
remains.
* test(qa): restore strict cached-health contract assertions
The lint sweep's Boolean() coercions let truthy non-booleans satisfy the
wire-typed cached-meta contract. Assert the literal boolean for unknown-typed
fields and use nullish-coalesced strict equivalents for boolean chains.
* fix(agents): clear the stale cleanup outcome when restoring a worktree
A restored checkout begins a new lifecycle; leaving the removed-lossless
fact on the live row showed operators a stale result until the next
cleanup. Restore clears the recorded outcome and the regression asserts
the cleared state before the next cleanup records fresh truth.
* fix(agents): scope stale cleanup outcomes to their observed lifecycle
A stale remover's retained/failed write raced a concurrent remove-plus-
restore: the revived row is live again, so the live-row condition alone
could stamp a prior-lifecycle outcome. Condition those writes on the
activity stamp the remover observed; restore bumps lastActiveAt, making
any prior-lifecycle write a no-op.
* fix(agents): advance the restore activity stamp within one millisecond
Stale cleanup writes fence on the activity stamp they observed; a restore
completing in the same millisecond could revive the row with an identical
stamp and let the fence match. Restore now always advances past the
stored value, and the ABA regression pins the clock to prove the
same-millisecond case.
Fresh Dev installs now preflight disk space and stream honest stages, while Codex activation probes the refreshed request-scoped registry.
Closes#120779Closes#120780
* feat(update): scheduled update campaigns with countdown, dev-channel auto-update, and Updates settings page
* fix(ui): satisfy update campaign deadcode checks
* feat(update): extend scheduled update campaigns
* test(ui): include Updates page in settings sidebar search expectations
* fix(update): end campaigns when apply fails
* fix(update): pin dev campaign applies to the announced commit
* test(ui): align update e2e fixtures
* fix(update): pin adopted dev updates to the announced commit
* docs(update): document automatic dev update campaigns
* fix(ui): gate automatic dev updates on git installs
* fix(gateway): scope detailed update metadata to read-capable clients
* fix(gateway): break post-attach madge cycle with a leaf client-lookup type
* chore(protocol): regenerate clients after rebase
* test(gateway): update method tail after rebase
* fix(update): preserve campaign target and hold state
* test(update): align adoption mocks and split handoff suite
* test(update): route split handoff suites on Windows
* feat(macos): add native camera PTZ controls
Add physical UVC pan, tilt, and zoom through the signed Mac app, with camera.ptz.control kept behind dangerous-command approval. Verified against real Insta360 Link 2 Pro hardware.
* refactor(agents): split message tool display config
* fix(mac): harden camera PTZ contracts