Commit Graph

11709 Commits

Author SHA1 Message Date
roboclaw-bot 32d984e507 fix(gateway): isolate mutable GitHub identity checks
Co-authored-by: Jesse Merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-08-27 14:04:11 +00:00
roboclaw-bot a329cfac7a fix(gateway): harden GitHub identity lookup coordination
Co-authored-by: Jesse Merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-08-27 04:44:41 +00:00
Markus Hartung 8c293c1ae1 fix(matrix): show recovery key availability in text status (#128051)
Keep raw recovery keys in explicitly opted-in JSON output. Add a safe text
hint in the CLI-owned result renderer, remove duplicated stored-key output,
and cover normal, verbose, missing-key and JSON command behavior.

Thanks @hartmark for the original fix and real-account reproduction.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 21:38:32 -07:00
ruel225 cd321938f6 fix(agents): strip external-content nonce so loop detection blocks repeated wrapped failures (#130261)
* fix(agents): strip external-content nonce before loop-detection resultHash

External-content wrappers carry a fresh anti-forgery nonce per result
(createExternalContentMarkerId). The loop detector hashed the wrapper text
including the nonce, so identical failing wrapped tool calls never reached
the no-progress block threshold — the detector warned but never blocked,
leaving the agent to loop until it gave up (#130210).

Strip the wrapper nonce before hashing in extractTextContent, mirroring
the existing stripVolatileSendIds treatment of per-call send ids (#89090).
Only the hash is normalized; the delivered wrapper keeps its nonce, so
anti-forgery is unaffected.

Closes #130210

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

* test(agents): validate protected error marker capture

Narrow the generated marker capture before recording it so the real network-error loop regression also passes its owning test-type graph.

---------

Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 21:22:39 -07:00
Peter Steinberger 8f237b6a97 fix(ui): show cloud session startup progress in chat (#130669) 2026-08-26 21:13:04 -07:00
Rain 110eb787a1 fix(github-copilot): preserve catalog thinking efforts in requests (#107834)
* fix(github-copilot): preserve catalog thinking efforts in requests

Unify discovered and bundled capability mapping with the provider thinking policy. Preserve supported xhigh/max Responses efforts and map minimal to the supported low minimum, while respecting explicit account opt-outs and transport limits.

Fixes #107792

Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>

* fix(github-copilot): resolve nullable thinking policy transport

Accept the public policy API context and resolve missing transports before enforcing Claude and Gemini effort restrictions. Cover undefined and null API values without changing explicit Responses routes.

* refactor(github-copilot): normalize manifest models as one catalog

Use the canonical batch model provider builder after the single-row helper was removed on main. Preserve model transport and compatibility decoration without a legacy API shim.

* refactor(github-copilot): decorate owned catalog rows in place

Keep the normalized manifest batch as the sole owner of runtime rows and apply transport metadata directly, avoiding redundant row copies.

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
2026-08-26 21:09:21 -07:00
Peter Steinberger 63f7df85bb feat(channels): post a grounded introduction when the bot joins a group room (#130103)
* feat(channels): introduce bots when they join group rooms

* feat(channels): add Discord and Telegram join introductions

* fix(channels): isolate untrusted evidence and select allowed join targets

* refactor(channels): scope joinIntro to implementing channels

* fix(channels): keep a delivered join introduction settled when its durable commit fails

* feat(channels): read more room history and document join introductions in detail

* chore(config): regenerate bundled channel metadata after rebase
2026-08-26 21:02:26 -07:00
Vincent Koc b7d9be0209 fix(ci): stabilize compact node shards (#129702) 2026-08-27 11:52:20 +08:00
Mislav Ivanda 3a5cb3847c feat(sandbox): add Daytona cloud sandbox backend plugin (#121554)
* feat: @openclaw/daytona-sandbox inital version

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* feat: plugin config params extended

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* feat: implement ClawSweeper review notes

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* fix(daytona): honor abort signals and clean up remote staging on failure

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* fix(daytona): register launcher as knip entry and refresh manifest schema

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* fix(daytona): cancellable session transport and auto-stopped sandbox restart

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* fix(daytona): deny egress by default and arm launcher cleanup before startup

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>

* fix(daytona): stop cancelled startup before submission

* test(daytona): satisfy deferred race lint

* test(release): update plugin publisher inventory

* fix(daytona): close provisioning and PTY cleanup gaps

* test(daytona): type PTY launcher mock

* fix(acpx): avoid promise-returning line handler

* fix(daytona): await PTY signal cleanup

* fix(daytona): declare ClawHub install route

* fix(daytona): forward PTY stdin EOF

* fix(daytona): serialize PTY input

* docs(daytona): document sandbox backend config

---------

Signed-off-by: Mislav Ivanda <mislavivanda454@gmail.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-26 20:52:12 -07:00
wangyan2026 e00d46b19b fix(plugins): normalize managed npm overrides before peer planning (#124532)
* [AI] fix(plugins): filter pnpm parent-child overrides at managed npm producer

readOpenClawManagedNpmRootOverrides returned host pnpm-workspace overrides
without filtering pnpm-only parent-child selectors (parent>child). Those
selectors are invalid npm override keys and trigger EINVALIDTAGNAME before
the retry-based compatibility path can recover, breaking managed npm plugin
installs and the pre-install peer-sync that runs before the retry loop.

Filter pnpm parent-child selectors once at the shared producer so every
managed npm install/uninstall consumer receives a npm-compatible manifest
up front. The existing retry path stays as a fallback for npm alias
compatibility, which is npm-version-dependent.

Fixes #124426

* fix(plugins): normalize overrides before managed peer planning

Plan peers against the incoming compatible override set so retired selectors cannot silently retain stale pins. Remove duplicate selector retry and synchronization paths while preserving npm alias compatibility.

Co-authored-by: WangYan <wang.yan29@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 20:41:34 -07:00
Peter Steinberger 0924fd9a0c fix(codex): reclaim binding capacity after session deletion (#128366)
* fix(codex): reclaim binding ownership when sessions are deleted

Prepare harness deletion outside the SQLite writer and compare-delete exact companion ownership at the session removal edge, with compensation before commit and native subscription release afterward. Preserve live siblings and upstream native history. Repair proven orphan bindings through the existing Doctor planner under maintenance ownership.

* fix(codex): reuse prepared auth for resumed thread ownership

* docs(plugins): clarify shared migration and auth contracts

* test(codex): use the canonical config type facade

* fix(codex): preserve native threads during manual resume

Record pending attachment intent and validate the immutable native tool catalog
before applying configuration to the selected thread. Require uninterrupted
physical-client ownership through native unsubscribe, resume, and binding commit.
Keep the thread intact on unsupported policy, competing work, or failed proof.

Reuse canonical retained-owner cleanup and preserve unsafe-client retirement.
Cover the real command producer, cold and loaded resumes, competing leases,
lazy-store commit fencing, and the Gateway competing-owner path.

* test: isolate Codex auth and session completion fixtures
2026-08-26 20:33:53 -07:00
JC 8a0cf73053 fix(memory): isolate sqlite-vec KNN from the event loop (#128078)
* fix(memory): isolate sqlite-vec KNN in subprocess

* fix(memory): satisfy KNN subprocess CI guards

* test(release): include memory KNN child artifact

* test(memory): update KNN subprocess fixtures

* fix(memory): bound KNN child row payloads

* fix(memory): preserve published readers during cancellable KNN

Keep shadow reindex database, vector readiness, FTS and metadata state in
an owned async context. Public operations retain the published connection,
and escaped shadow continuations cannot write to it after rebuild closes.

Terminate the one-shot query child through its owned handle and retain
admission until close. Remove process-tree/PID probing and test-only hooks.
Cover publication overlap, callback reads, cancellation and recovery.

Co-authored-by: OpenClaw Assistant <assistant@openclaw.local>

* refactor(memory): separate database context ownership

Keep the published reader and shadow writer context in its own owner module. Repair plugin test imports and typed lint findings without changing the verified KNN behavior.

---------

Co-authored-by: OpenClaw Assistant <assistant@openclaw.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 20:29:02 -07:00
Peter Steinberger 7c6a79828a fix(feishu): preserve unavailable controls in message cards (#130641) 2026-08-26 20:27:31 -07:00
Vincent Koc d62cb8aa07 fix(sqlite): safely discard retired commitments state (#130629)
* fix(sqlite): finalize commitments retirement

* fix(doctor): discard retired commitments json
2026-08-27 11:18:58 +08:00
Peter Steinberger f1bef4b3a2 fix(browser): preserve snapshot names and native refs (#130623) 2026-08-26 20:09:49 -07:00
Peter Steinberger 682ddcb28c fix: preserve Gateway when setup Reinstall is cancelled (#130617)
Keep replacement preparation ahead of service mutation in configure and onboarding. Let platform installers own replacement, and report surviving Gateway reachability independently of failed setup.
2026-08-26 20:07:50 -07:00
Peter Steinberger a872abc978 fix(ui): preserve startup errors across session navigation (#130593) 2026-08-26 20:03:43 -07:00
Peter Steinberger d3d43eb6cf fix(cli): reject missing repeatable inference inputs (#130608) 2026-08-26 19:55:41 -07:00
cxbAsDev e3c78c3487 fix(agents): keep embedded prompts isolated from ambient files (#110776)
Skip unused SYSTEM.md and APPEND_SYSTEM.md discovery in embedded turns,
compaction, and workers. Preserve bounded workspace context and interpret
Gateway-supplied instructions as literal text rather than local filenames.
Share the existing loader policy and retain standalone loader semantics.

Rewrite the prompt-read repair reported in #110776.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 19:53:59 -07:00
Peter Steinberger 4b287caac3 fix(memory): stop false Copilot index mismatch warnings (#130603)
Share provider-owned canonical model projection across cold identity and creation, keep undiscovered models unknown, and preserve strict initialized identity checks. Consolidate obsolete lookup and table-existence paths.

Co-authored-by: 1052326311 <65798732+1052326311@users.noreply.github.com>
2026-08-26 19:50:15 -07:00
Peter Steinberger bbd66c475e fix(plugins): fail closed when plugin runtime is unavailable during registration (#130597)
* fix(plugins): fail closed when plugin runtime is unavailable

Core fabricated an empty object as `PluginRuntime` for the `cli-metadata`
and `setup-only` registration passes, so any plugin touching `api.runtime`
during `register()` died with an opaque
`TypeError: Cannot read properties of undefined (reading 'openSyncKeyedStore')`
that named neither the contract nor the mode.

Replace those fabrications with one shared fail-closed runtime that throws a
named, actionable error identifying the plugin and registration mode. Symbol
reads stay inert so inspection and reflection cannot trigger the guard.

Also resolve the lightweight `cli-metadata` entry beside the resolved plugin
entry, not only at the package root. Published plugin packages emit it at
`dist/cli-metadata.js`, so the probe always missed and the loader fell back to
executing the full heavy entry for CLI metadata collection.

Documents which registration modes expose a live `api.runtime`; the SDK
reference previously claimed it was injected into every plugin.

* fix(ui): restore sidebar lazy import boundaries

Remove the redundant viewer-facepile dynamic import: sidebar consumers
already register that element through the static graph.

Import pet data and sprite helpers from their owning leaf modules, delete
the registration module's re-export barrel, and make the element itself
the lobster-pet.runtime.ts lazy boundary. Keep shared sprite styles with
the look renderer so standalone pages do not need element registration.

Regenerate the measured boot inventory with the canonical browser probe.
Use Lit's typed lifecycle map to remove the obsolete assertion baseline
entry and keep the now-private facepile variant type local.

The full build has no INEFFECTIVE_DYNAMIC_IMPORT warnings. Relevant UI
coverage passes (503 tests plus 5 Chromium E2E tests); the unchanged plugin
runtime regression suites pass all 58 tests. The broad plugin suite still
reports schema-version, doctor-closure, hook-process, and catalog failures.
2026-08-26 19:45:39 -07:00
Ayaan Zaidi 1cb914d6bf fix(telegram): make ask_user controls native and reliable (#130262)
Make ask_user use native Telegram controls when one single-select question can be represented directly, while keeping multi-select and batch questions on the text fallback. Add native Other-to-ForceReply input, preserve Gateway-owned option ordering across Telegram, Slack, and Discord, and prevent later progress from overwriting the delivered question.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-27 08:14:39 +05:30
Peter Steinberger 31b26d09f0 feat(ui): group advanced settings by messaging channel (#130591)
* feat(ui): group advanced settings by messaging channel

* test(ui): connect channel settings fixture for label checks
2026-08-26 19:40:34 -07:00
Peter Steinberger 7f05472938 feat(buzz): retain bounded passive context for accepted turns (#130509)
* feat(buzz): retain bounded passive context for accepted turns

Add opt-in connection-owned room and thread context using the shared history window. Preserve sender admission, current roster filtering, UTF-8 bounds, and snapshot consumption without passive inference, session recording, or typing. Related: #129599.

* docs(config): align baseline with landed Feishu sticker sets
2026-08-26 19:36:05 -07:00
Peter Steinberger c35b183093 fix(ui): highlight source code in chat and session diffs (#130578)
* fix(ui): highlight source code in chat and session diffs

* test(ui): isolate roster bootstrap from slug lookup

* fix(ui): preserve both languages in renamed diffs
2026-08-26 19:28:03 -07:00
Markus Hartung 18c801daa1 fix(ai): stabilize runtime context across Responses tool rounds (#130166)
* fix(agents): stabilize runtime context across tool rounds

Keep current-turn metadata after the active user and before tool calls so Responses continuation retains the complete prior request prefix. Preserve active hook context and intentionally resend when transient context expires on a later turn.

Reworks #130166. Thanks to Markus Hartung for investigating continuation failures.

Co-authored-by: Markus Hartung <mail@hartmark.se>

* fix(ai): localize continuation ordering to Responses

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 19:01:32 -07:00
Vito Cappello b8d2ac735a fix(compaction): scope the transcript byte fuse to the latest compaction window (#130487)
* fix(compaction): scope the transcript byte fuse to the latest compaction window

readVisibleTranscriptStats only closed its window at a reset boundary, so once a session compacted, maxActiveTranscriptBytes measured the whole active path and every following turn re-compacted. The preflight fuse now measures the window the model actually sees (since the latest compaction or reset, plus its kept tail); history readers keep their reset-only scope.

* test(compaction): cover retained transcript accounting

## Worked on by
- @VACInc

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-26 21:40:28 -04:00
Peter Steinberger 67d22a58ac refactor(embeddings): unify provider contract (#130506)
* refactor(embeddings): unify provider contract

* test(plugins): declare embedding type bridge

* test(memory): migrate embedding fixtures
2026-08-26 18:20:48 -07:00
Peter Steinberger 789a346fa3 fix(macos): detect screen recording permission after granting access (#130530)
Reuse the existing Peekaboo live permission service so Quick Chat, Settings, screenshot gating, and computer-control diagnostics retain confirmed grants instead of re-reading stale CoreGraphics denials. Passive checks remain consent-gated. Document same-build grant recovery.
2026-08-26 18:20:26 -07:00
Peter Steinberger de70b00d95 feat(buzz): bound bot-to-bot room conversations (#130488)
Use the shared per-Gateway bot-pair budget with the latest received signed room roles. Preserve existing sender and mention admission and human traffic. Release note: bound repeated Buzz bot exchanges without adding a channel-specific policy or persistent state.
2026-08-26 17:58:41 -07:00
Peter Steinberger 42112dd86e fix(feishu): preserve commands in select fallback cards (#130515) 2026-08-26 17:41:40 -07:00
Peter Steinberger a0d6467948 feat(feishu): find received stickers by configured keywords (#130498)
* feat(feishu): search configured received stickers by keyword

Bind curated sticker sets to the selected bot app ID and reuse the existing sticker action gate and native sender. Enforce matching scalar bounds in runtime and generated config schemas, with bounded search output and explicit truncation. Completes the configurable-set request in #114578.

* refactor(feishu): keep sticker schemas with config owner

* build(feishu): regenerate catalog metadata after channel schema update
2026-08-26 17:37:05 -07:00
Peter Steinberger 00713ca253 fix(cli): honor selected port when tailing logs (#130513) 2026-08-26 17:34:17 -07:00
Vincent Koc 8afa8f339e fix(release): restore direct package Telegram acceptance (#129912)
* fix(release): provision package acceptance plugin registry

* fix(release): accept registry tuple in package dispatch

* fix(release): default Docker advisory input

* fix(release): bind artifact registry to package source

* fix(release): preserve package advisory dispatch

* fix(ci): bound hosted release gate checks

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

* test(ci): update release-gate manifest fixture

* fix(ci): avoid duplicate release gate lint

* test(release): restore Docker helper fixture path

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-27 08:32:19 +08:00
Peter Steinberger 0b60846fa4 fix(workers): re-arm admission-deadline launches, terminalize dead-worker turns, defer debris cleanup (#130446)
* fix(workers): re-arm admission-deadline launches, terminalize dead-worker turns, defer debris cleanup

Three lifecycle repairs from the 50-worker campaign (#129979): the gateway
launch adapter re-arms a launch up to five times (exponential backoff with
jitter, caller-deadline capped, deterministic derived launch/turn ids so
adapter replays find the same journal rows) when the node journal proves the
child died on the admission deadline — credential/build rejections and
post-start failures stay terminal; stuck-turn recovery records a terminal
failure once a journal-terminal worker has no claim past a 30s cleanup grace
instead of skipping keep_lane forever; and startup recovery defers orphan
git cleanup for terminal placements into the first tracked background sweep
(50-placement fixture: 50 startup git scans to zero, ~556ms to ~5ms) while
pending-result recovery and ownership fences stay ahead of readiness.

* fix(workers): use the diagnosed admission-deadline message after #130435 rebase

WorkerConnection now formats the redacted last-failure diagnosis into the
deadline error itself, so the runtime's re-format (and its
lastConnectionFailure tracking) is redundant; errorText uses error.message.

* fix(workers): cap admission re-arms within the minted credential lifetime

Re-arms reused the credential minted before the first admission attempt,
so with five 120s windows plus backoff the final advertised retry could
start after the credential expiry and fail closed as credential-expired.
The launcher now threads credential.expiresAtMs through the tunnel launch
request, and the adapter re-arms only while the retried child still gets a
full admission window (WORKER_ADMISSION_DEADLINE_MS, now shared from the
connection contract) on the original credential; otherwise it returns the
terminal admission result. Expiry-boundary tests walk both sides.
2026-08-26 17:28:04 -07:00
Ayaan Gazali 1f2e99832b fix(channels): bundled channels reject the documented responsePrefix override (#118148)
* fix(channels): bundled channels reject the documented responsePrefix override

* fix(feishu): pass channel and account to the reply prefix resolver

The ordinary reply dispatcher built the prefix context without channel or
accountId, so channels.feishu.responsePrefix and its account override fell
through to the global value. The comment dispatcher already passed them.

* fix(channels): accept twitch's root responsePrefix and type ClickClack's

Twitch validates as a two-branch union with both branches closed, so
responsePrefix declared only on the account shape left
channels.twitch.responsePrefix rejected whenever accounts is present. Also
declares responsePrefix on ClickClackAccountConfig so typed callers can express
what its schema already accepts.

* fix(clickclack): apply the configured responsePrefix in model mode

Model mode sends the completion straight to ClickClack instead of going through
the agent reply pipeline, so the documented responsePrefix parsed and then did
nothing. Resolve it through the public reply-pipeline seam so template
variables like {model} render from the completion's own provider and model.

* fix(clickclack): do not double the response prefix in model mode

systemPrompt is operator-owned, so a model can be instructed to emit the
configured prefix itself and the unconditional concatenation then sent it
twice. Match the shared reply normalizer's startsWith guard.

* test(clickclack): resolve inbound access through the real resolver

Main now requires access.channelIngress, which the hand-built fixture did not
provide, so the model-mode messages never dispatched. Drop the fixture and let
handleClickClackInbound resolve access from a DM-shaped message, matching the
sibling bot-loop tests.

* test(channels): reject a key missing from any composed branch

A union alternative is a configuration mode an operator can pick, so a key
present in only one mode is unusable in the other even though the union still
validates. Treat any rejecting alternative as a rejection, and walk allOf when
collecting account schemas.

* fix(channels): offer responsePrefix only where the reply path applies it

Applying the prefix to an outbound reply is per-channel wiring, not a shared
step. Buzz, Nostr, QA Channel, Raft, Reef and SMS never read it, so accepting
the key there validated a setting their delivery path ignores. Anchor the
contract to the channels that consume the prefix.

* fix(channels): complete shared response prefix delivery

Co-authored-by: ayaangazali <ayaangazali.work@gmail.com>

* docs(config): refresh response prefix baseline

* test(tlon): use canonical prefix fixture helpers

* test(channels): prove Twitch reply prefix delivery

Exercise schema admission and the real shared reply dispatcher at the Twitch native send boundary, replacing redundant schema-only coverage. Keep Tlon fixtures on canonical imports and recording options.

* docs(channels): clarify explicit message prefix behavior

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 17:08:28 -07:00
Peter Steinberger a4c01c1a77 feat(ui): save appearance preferences per user profile (#130340)
* feat(ui): save appearance preferences per user profile

When a Control UI connection is bound to an authenticated user profile
(trusted-proxy, Tailscale, GitHub identity), theme, theme mode, and accent
become per-profile: stored in the existing user_preferences KV store via
users.prefs.set, overriding gateway-wide ui.prefs, with live cross-device
updates over a new additive users.prefs.changed event scoped to the same
merged profile. Restore default deletes only the profile key and falls back
to the gateway-wide value. talk.config projects the caller's profile accent
for native clients. Profile-less connections (token/password/none auth)
keep the existing gateway-config behavior byte-identically.

Release-note context: on multi-person gateways appearance choices are now
personal and follow you across devices; an admin restyling their own UI no
longer reskins the whole team.

* chore(protocol): allowlist users.prefs.changed for mobile clients

iOS and Android resolve the profile accent through talk.config on connect
and config refresh; live per-profile appearance push on natives is a named
follow-up.

* chore(protocol): regenerate Swift/Kotlin models for users.prefs.changed

* fix(ui): honor explicit defaults and identity switches for profile appearance

Addresses the three ClawSweeper review findings:
- resetValue for profile-bound appearance keys is the deletion fallback
  (gateway value), so an explicit product-default selection persists as a
  profile write instead of being misclassified as a reset.
- An identity switch between two known scopes forces a full appearance
  reconcile and clears appearance keys the returning identity never set,
  so a shared browser cannot keep the previous profile's look (boot keeps
  the last-seen shortcut).
- talk.config joins the profile-dependent dispatch gate so a pending
  GitHub identity sync completes before the profile accent is projected;
  token clients pass through untouched.

* chore(ui): satisfy assertion-safety ratchet and docs formatting

* refactor(ui): extract server-prefs storage primitives

server-prefs.ts crossed the 700-line cap after the review fixes; the
stateless localStorage persistence primitives move to
server-prefs-storage.ts (no behavior change). Shrink-prunes the
assertion-safety baseline for the moved casts.

* fix(ui): keep imported custom themes out of profile storage

Custom palettes are browser-local by contract, so a profile must never
carry theme=custom to a browser that cannot render it. The wire contract
drops custom from the storable theme values (readers self-heal any stored
value), a profile-bound custom selection stays retained browser-local
(including the offline-queued path), and the exhaustive theme test now
encodes the exception.
2026-08-26 16:48:26 -07:00
Peter Steinberger e9dc4b9d1a fix: Buzz bots recover relay stalls and reject revoked senders (#130467)
* fix(buzz): recover stalled sessions and revalidate room admission

* test: correct Buzz relay fixture types

Keep release notes in the PR body and leave the release-owned changelog unchanged.

* test: isolate Buzz relay mock exports

* test: clarify Buzz admission and output lifetimes
2026-08-26 16:47:58 -07:00
Peter Steinberger 5153f25495 fix(memory): prevent forgotten session content from returning (#130451) 2026-08-26 16:26:00 -07:00
Peter Steinberger 95161c2335 fix(workers): protect in-flight workspace manifests from concurrent retention (#130449)
At high completion concurrency, 12/50 turns failed with 'Cloud worker
finished, but its workspace result could not be reconciled' (#129979):
between a worker's manifest upload and its verification, a sibling
completion could trigger retention with a snapshot holding only the old
base manifest — the terminal worker no longer protected the workspace, so
cleanup deleted the just-uploaded manifest and verification died on ENOENT.
The node workspace runtime now pins the latest transferred manifest per
generation and includes it in every cleanup's reachable set (cleared with
its generation), and gateway retention snapshots treat unsettled results —
an active claim or a pending-result fence — as protection, which also
preserves it across restarts when node-local pins are gone. Capture errors
retain bounded redacted stderr so this failure class can never be
faceless again. No deadlines, protocol, or completion-semantics changes;
deterministic 1-turn and 50-turn reproductions fail pre-fix.
2026-08-26 16:22:52 -07:00
Peter Steinberger 25a16dd96c fix(portals): keep worker previews reachable and owned by the active environment (#130434)
* fix(portals): preserve worker routes and portal lifetime ownership

* fix(worker): keep diagnostics off the JSON result stream

* test(portals): model worker stream closure across Node versions

* test(agents): refresh compaction runtime mocks
2026-08-26 16:16:21 -07:00
Ayaan Gazali c464bf1512 fix(config): keep core channels keys in the generated config schema (#120736)
* fix(config): keep core channels keys in the generated config schema

* test(config): expect the core channels keys in schema surfaces

* fix(config): keep the core channels schema instead of listing its keys

ChannelsSchema is the only core owner at this point, since plugin channel
entries merge in later, so clearing the property map and re-adding a literal
allowlist duplicated that ownership and would silently drop any future core
field. Stop clearing it, and assert parity against the core schema rather
than a key list.

* test(config): derive the channels parity keys from the production conversion

The parity assertion converted OpenClawSchema without the io:input mode the
base schema builder uses, so an input-only core channel field could be absent
from the expectation and still get dropped. Also formats the file, which is
what turned check-docs and check-lint red.

* test(config): repair the parity test after the schema helper rename

* fix(config): preserve core channel schema lookup contracts

Remove redundant schema normalization and cover core descendant lookups alongside bundled and external channel metadata.

Co-authored-by: Ayaan Gazali <ayaangazali.work@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 16:15:16 -07:00
Peter Steinberger 395e5db41b chore(deps): refresh dependencies after seven-day cooldown (#130296)
* chore(deps): refresh cooled npm and plugin dependencies

* chore(deps): refresh cooled build and workflow tooling

* chore(deps): retain formatter compatibility

* chore(deps): retain lint compatibility
2026-08-26 16:13:18 -07:00
Peter Steinberger 7d008a8db2 fix(auth): honor shared-store ownership in temp-state exec and agent deletion (#130437)
Two follow-ups from #130264: agent exec temporary state now preserves the
original shared auth root, so temp-state runs read-through portable static
profiles (local precedence and cooldowns preserved, no inherited-secret
copies); and agent deletion safety consults resolveSharedAuthStoreOwnership,
so the implicit legacy main owner is protected only while the legacy store
owns credentials — post-relocation main is deletable and shared credentials
provably survive. Explicitly bound inheritance owners stay protected.
2026-08-26 16:09:33 -07:00
Peter Steinberger dcb20658fc fix(openshell): preserve file writes during concurrent mirror commands (#130447)
Lease complete mirror file operations through the workspace owner instead of locking only remote transport. Preserve successful writes across exec publication and share serialization across backend handles.

Proven with a real Docker red/green reproduction, 128-workflow mirror/remote stress matrix, exact inventories, failure recovery, 170 focused tests, and updated operator docs. Related: #127441; follow-up to #130031.
2026-08-26 15:59:31 -07:00
Peter Steinberger 1320f6ba23 fix(ios): stop blaming device storage for incomplete Gateway setup (#130407)
* fix(ios): distinguish incomplete gateway setup from credential save failures

Record received and persisted device-auth roles separately, and centralize setup handoff failure handling without changing credential grants or persistence policy. Related: #108888. Thanks @rhubain for reporting the misleading recovery guidance.

* fix(ios): refresh handoff diagnostic localization inventory
2026-08-26 15:40:34 -07:00
Peter Steinberger ab0c2203f8 fix(plugins): report registered inspection capabilities (#117518) 2026-08-26 15:37:04 -07:00
Peter Steinberger b10beeee7c fix(onboard): preserve the saved skills package manager (#130438)
Keep explicit CLI choice precedence while preserving existing pnpm, Bun, and Yarn preferences when onboarding is rerun. Retain npm defaults for fresh config and the narrower explicit CLI choices. Fixes #130433.
2026-08-26 15:18:46 -07:00
Peter Steinberger 86e208310f improve(worker): diagnose admission-deadline failures and widen daemon revalidation budget (#130435)
WorkerAdmissionDeadlineExceededError now carries the terminal diagnosis —
the last connection failure kind and detail, attempt count, and the
redacted endpoint — instead of a bare deadline sentence, and that text
flows through IPC, container stderr, the node launch journal, and the
gateway turn error. Credential material (raw, URL-encoded, JSON-escaped)
is scrubbed before truncation. A LAN partition was misdiagnosed as a
gateway admission wedge for a day because the old text was identical for
never-connected and never-answered (#129979). Container daemon
revalidation gets a 30s budget: a slammed-but-healthy OrbStack daemon
exceeded the old 5s under a 50-container burst; fail-closed semantics
unchanged.
2026-08-26 15:15:10 -07:00
Peter Steinberger 0e05d8205a fix(browser): accept common keyboard aliases (#130401)
* fix(browser): accept common keyboard aliases

* docs(browser): note keyboard alias repair
2026-08-26 15:12:37 -07:00