Commit Graph

79183 Commits

Author SHA1 Message Date
Peter Steinberger 3a49aa1ac6 improve: split hosted Windows CI into three lanes (#123577)
* ci: split Windows tests into three lanes

* test: cover three-way Windows CI partition
2026-08-14 02:40:02 -07:00
Peter Steinberger 37c9a30f58 fix: stabilize steering tests and skill reconciliation (#123553)
* test: align steering fixtures with session owner

* test: wait for steering subscription readiness

* fix(skills): serialize proposal reconciliation

* test: cover skill proposal lease contention

* test: split skill workshop list coverage
2026-08-14 02:37:14 -07:00
Peter Steinberger 655724a727 fix(gateway): run timeouts reach the browser as timeout, not generic failed (#123511)
classifyAgentRunTerminalOutcome computes the timeout classification and the
emit path discarded it: errorKind came only from event metadata the
lifecycle producer never sets, plus text-sniffing an often-undefined error.
The browser projection classifies status timeout only via errorKind, so an
idle/run-budget timeout rendered generic failed with empty error while
sessions.list and the TUI both said timeout. The recorded classification
now flows through.
2026-08-14 02:30:40 -07:00
Peter Steinberger 678c89c550 fix(ui): partial tool output no longer flips a running card to succeeded (#123510)
The live tool stream emits a toolresult block for partial update output
(so streaming stdout renders), but the card extractor treated any result
block as completion — spinner gone mid-execution, and partial text that
looks like an error badged the still-running tool Failed. Live cards'
completion is owned by the stream's resultReceived marker (per the
producer's own contract comment); the result branch now defers to it.
2026-08-14 02:29:02 -07:00
Peter Steinberger 06e23130cb fix(ui): revealing a stored secret displayed the redaction sentinel as an editable value (#123493)
config.get never sends plaintext secrets — stored values arrive as the
__OPENCLAW_REDACTED__ sentinel. The reveal eye had no sentinel awareness:
clicking it showed the literal sentinel in a now-editable input, and any
edit broke the exact-match restore so the mangled text was written over
the real credential with a green Saved. Sentinel values are now never
revealable (input stays readonly) and the disabled eye explains why.
2026-08-14 02:27:06 -07:00
Ayaan Zaidi fc87337c14 fix(ci): keep Telegram shards alive after the first isolated file (#123576)
Five-file Telegram jobs finished the first file, then isolate re-imported the next graph in silence until the 300s watchdog killed the worker. Recycle the Vitest process after each file and keep five files per CI job.
2026-08-14 14:50:21 +05:30
Peter Steinberger 8865c2539b ci: shorten hosted PR path (#123570) 2026-08-14 02:11:25 -07:00
Peter Steinberger 1011b4102f fix(ui): restore custom page and session ordering (#123530)
* fix(ui): restore interleaved sidebar ordering

Render pinned sessions at their persisted slots among page entries again instead of projecting them into a separate group. This restores custom page/session interleaving regressed by #121712 while preserving drag-to-pin behavior.

* test: consolidate steering authority fixtures

* test: isolate CLI commentary fixture

* fix: dispatch tool-bound turns normally
2026-08-14 02:00:03 -07:00
Peter Steinberger d4b1e9644e fix(ai): stabilize prompt caching across discovery order (#123543) 2026-08-14 01:59:10 -07:00
Peter Steinberger c0930de5de fix(secrets): scope egress sentinels to Gateway and survive client tunnel resets (#123527)
* fix(secrets): scope exec egress proxy to gateway

* fix(secrets): keep a client reset from crashing the egress proxy host
2026-08-14 01:56:29 -07:00
Peter Steinberger 8a3964f87c fix: node workspace transfers fail after successful turns (#123564)
* fix(node-host): preserve TLS transfer failures

* fix(node-host): clean transfer backpressure listeners

* fix(gateway): explain node workspace sync paths
2026-08-14 01:51:42 -07:00
Peter Steinberger 97e012b4cb perf(test): use minimal gateway for CLI pairing (#123531) 2026-08-14 01:49:17 -07:00
Jason (Json) 0bd50cc0a5 fix(ui): preserve delayed final turn order (#123560) 2026-08-14 01:41:34 -07:00
Peter Steinberger 703c681aac test: remove latest duplicate coverage (#123551) 2026-08-14 01:39:19 -07:00
Peter Steinberger 65597f93b0 fix: restore default-profile backup archives (#123504)
* fix(backup): make default-profile backups restorable

* fix(backup): preserve restore cleanup context

* refactor(backup): drop preserve-caught-error suppression via hoisted cleanup error

* refactor(backup): hoist restore failure handling out of catch scopes
2026-08-14 01:39:08 -07:00
Peter Steinberger 749340fc16 ci: widen hybrid Blacksmith routing (#123552) 2026-08-14 01:37:32 -07:00
Peter Steinberger 204be37803 fix(ui): stale tabs lose terminal owner after Gateway updates (#123526)
* fix(ui): refresh stale clients before terminal reconnect

* fix(ui): hold reconnect fence through worker activation

* fix(ui): isolate reconnect worker refresh

* refactor(ui): own reconnect fence in terminal lifecycle

* test(ui): satisfy reconnect refresh lint
2026-08-14 01:32:33 -07:00
Peter Steinberger 2f85e5e33d fix(config): allow agents add while the local Gateway is running (#123490)
* fix(config): allow agent topology writes with healthy gateway

* fix(config): preserve dynamic cron ownership
2026-08-14 01:30:30 -07:00
Peter Steinberger c500ab7cc0 fix: preserve steering after tool-authority checks (#123549)
* fix: preserve authority-bound steering paths

* test: preserve heartbeat exports in execution mocks
2026-08-14 01:10:51 -07:00
Peter Steinberger 8e398d9591 fix(macos): prevent app-owned child processes surviving shutdown (#123538)
* fix(macos): reap app-owned child process groups

macOS-owned SSH, Codex, and node-host descendants no longer survive terminal shutdown. Codex retains EOF-first graceful exit before bounded process-group termination and reaping.

* fix(macos): correct managed cleanup wake binding

* fix(macos): preserve Codex shutdown escalation

Keep the app-owned EOF grace window while allowing abortive requests to interrupt it before process-group TERM and KILL.
2026-08-14 01:09:32 -07:00
Vatsal Garg d8a1ebbb49 fix(approvals): prevent cross-channel exec approval leak (#122517)
Reject unbound foreign-channel fallback at shared approval-account selection while preserving recorded bindings and explicit forwarding targets. Cover Telegram and Matrix routing contracts.

Co-authored-by: vatsalgargg <vatsalg80@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-14 13:11:03 +05:30
Peter Steinberger db2854e681 docs(macos): document cookie sync to a remote computer (#123537)
* docs(macos): document cookie sync to a remote computer

Add a Settings > General > Cookie sync section to the macOS platform guide,
alongside the existing browser-login import docs: off-by-default toggle, domain
allowlist, target profile, remote-mode requirement, host-local decryption, and
the DBSC caveat. Cross-links the browser CLI cookie-sync reference.

* docs(macos): clarify cookie sync status
2026-08-14 00:35:13 -07:00
Peter Steinberger 8ace19a071 fix(ui): unkeyed preamble segments corrupted the accumulated-stream prefix tracker (#123515)
itemId-less preamble segments carry standalone text, but the tracker
treated any itemId-less segment as cumulative run text. A preamble made the
tracker diverge from the real cumulative prefix, the next snapshot failed
startsWith, and every earlier segment's text rendered twice — persisted at
terminal materialization. advanceAccumulatedStreamText now owns the
continuity rule at all four advance sites: only text that extends the
current baseline becomes the new baseline.
2026-08-14 00:26:24 -07:00
Peter Steinberger 73e2489a5e test: delete final plugin and UI duplicates (#123214)
* test: delete final plugin and UI duplicates

* test(ios): remove duplicate watch reply case

* test(nostr): isolate ambient private key

Co-authored-by: Josh Avant <830519+joshavant@users.noreply.github.com>

---------

Co-authored-by: Josh Avant <830519+joshavant@users.noreply.github.com>
2026-08-14 00:20:09 -07:00
Peter Steinberger 00dbf6fd85 fix(ui): zone writes during startup no longer erase persisted Workboard pins (#123475)
The reconciler dropped workboard entries from the canonical persisted list
whenever workboardEnabled was false — but enablement reads as disabled until
the runtime config snapshot loads, so any pin/unpin/drag in that window
permanently deleted every workboard pin from synced prefs. The boards-not-
ready branch already preserved slots for exactly this ambiguity; disabled
now folds into it. Prod net −1.
2026-08-14 00:19:31 -07:00
Peter Steinberger e51ee089b7 improve: add hybrid CI runner backend (#123479)
* ci: add hybrid runner backend

* test: admit hybrid backend in CI fixture
2026-08-14 00:19:28 -07:00
Peter Steinberger 3eed7596a9 fix(doctor): sidecar OAuth recovery misses PI_CODING_AGENT_DIR and strands recoverable secrets (#123187)
* fix(doctor): unify legacy auth repair candidate enumeration

The sidecar inline-recovery and flat-store SQLite migration each carried
a near-duplicate listAuthProfileRepairCandidates that diverged: the
sidecar copy ignored PI_CODING_AGENT_DIR (a supported env contract used
by dotenv, gateway env selection, secrets scan, and stale-auth-order)
and the flat copy ignored symlinked state agent dirs. Because repair
sequencing runs sidecar recovery first, any store only visible to the
flat migration had its decryptable sidecar secrets imported as
credential-less 'configured-unavailable' profiles and the user was told
to re-authenticate — while the secrets sat on disk, recoverable.

Move one canonical enumeration (env superset + symlink-tolerant dirent
filter) into doctor-auth-legacy-paths.ts and delete both copies.

* fix(doctor): preserve shared-main precedence in extracted candidate dedupe

The extraction dropped main's undefined-agentDir-wins rule (added with the
state-DB shared store work); an agent-scoped alias resolving to the same
path demoted the shared-main store to a per-agent import, breaking SQLite
migration and archive repair.
2026-08-14 00:17:37 -07:00
Ayaan Zaidi d4ee874fea fix(ci): preserve scoped extension test plans (#123534)
Preserve externally scoped Telegram and Matrix test plans instead of expanding each CI shard back into the full extension suite. Keep broad runs bounded and retain external include ownership through directory run specs.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-14 12:43:54 +05:30
Peter Steinberger 8391ac59ae fix(macos): order parallel lifecycle cleanup (#123529)
Quick Chat model changes now settle in target order, the remote probe uses one deadline, and node-owned Codex child shutdown is acknowledged and bounded.

Related: #123420
2026-08-14 00:12:50 -07:00
Peter Steinberger 2ef92d0bbe feat: cookie sync from Mac to a remote Gateway browser profile (#123494)
* feat(browser): sync system cookies to a remote gateway profile

Add `openclaw browser cookie-sync`: decrypt allowlisted macOS Chrome-family
cookies locally and push them into a managed profile on a possibly-remote
Gateway over the existing operator channel. --watch re-syncs on cookie-DB
changes with a single Keychain prompt per session.

- New POST /cookies/set-many batch route (mirrors /cookies/set)
- Extract one canonical readSystemProfileCookies reused by import + sync
- Mandatory domain allowlist (never syncs an unrestricted cookie jar)
- Decryption stays host-local (macOS); no cookie values are logged

* feat(macos): cookie sync checkbox and configuration UI

Add an off-by-default 'Cookie sync' section (Settings > General): a toggle, an
editable domain allowlist editor, and a target-profile field, actionable only in
remote-gateway mode. CookieSyncManager supervises `openclaw browser cookie-sync
--watch` against the connected Gateway when enabled, resolving a LOCAL CLI (never
the SSH-redirect path, since decryption is host-local) and injecting gateway
URL + token/password via environment, never argv. A status row surfaces
running/stopped/error and the last sync summary.

* fix(macos): satisfy cookie sync lint gates

* chore(i18n): register cookie sync native source strings

Regenerate apps/.i18n/native-source.json baseline for the new macOS Cookie
sync settings strings (additive only). Satisfies the native:i18n:verify gate;
generated locale artifacts are refreshed separately by the locale-refresh job.
2026-08-13 23:47:26 -07:00
Josh Avant f8e6c6b7c7 fix(cron): run explicit-agent schedules without a default (#123516) 2026-08-14 01:47:01 -05:00
Peter Steinberger 312397ab4d feat(providers): add GLM 5.3 support (#123523) 2026-08-13 23:34:50 -07:00
Peter Steinberger e5fca42952 fix(apps): per-session desktop button opens that session's machine (#123412)
* fix(apps): open session desktop on its machine

* fix(ui): scope the desktop session lookup to the key's own agent

`sessions.list` has no exact-key filter, so the viewer resolves a `session=`
parameter by searching for the key and matching it exactly in the response. A
key that prefixes longer ones — `agent:main:main` alongside user-named sessions
that start the same way — could push the exact row outside a five-row page and
silently fall back to the picker.

Session keys encode their agent and the list API accepts `agentId`, so scope the
search to that agent and widen the page.

* refactor(ui): stop parking a session key in the desktop environment id

Document-mode inventory failures stashed the requested session key in
`environmentId` purely so the Retry button's non-null guard would pass, even
though document-mode retry refreshes the inventory and never reads the value.
A session key only names a machine once the inventory loads, so it now stays
out of `environmentId`, and the retry branch that ignores it runs before the
guard. Adds E2E coverage for recovering a session-preselected desktop.

* fix(ui): resolve the desktop session with an exact-key lookup

The session-preselect path searched `sessions.list` and scoped the search to
the key's own agent, but a bounded search cannot rule a key out: 25 newer
same-agent sessions sharing the requested key's prefix would push the exact row
off the page, and the viewer would report the source as unavailable for a
session that exists. `sessions.describe` is the exact-key operation and already
projects placement, so the panel calls it directly and the app-root resolver
plumbing goes away with it.

* refactor(ui): move the desktop document keyboard bridge into its own controller

`desktop-panel.ts` crossed the 700-line cap. The mobile keyboard bridge — the
padded sentinel, the value diffing that turns composed input into backspaces
and text, and the field focus/reset helpers — is a self-contained concern, so
it moves into a `DesktopMobileKeyboard` controller alongside the existing
fullscreen controller instead of taking a `max-lines` suppression.

* test(ios): drain text fields instead of assuming a delete burst lands

`testReleaseChatScreenshot` typed a 5-character probe, sent 5 deletes in one
`typeText`, then asserted the field was empty. CI dropped one synthetic
keystroke under simulator load and the assertion failed with a leftover "f".
XCUITest makes no lossless-burst guarantee, so clearing now re-sends against
whatever the field actually still holds, bounded. The two gateway-setup fields
that overtyped through the same burst use the helper for the same reason.

* fix(ui): keep the chat placement owner out of the startup chunk

`desktop-document-mode.ts` is imported by bootstrap, so importing the chat
placement owner from it pulled the chat page's dependency tree into the startup
bundle and pushed startup JS past its gzip budget (331075 B against a 330507 B
allowance). The route module now only parses the URL; resolving a session to its
machine moves next to the lazily loaded desktop panel, which is the only caller.
Startup JS is back to 329710 B.
2026-08-13 23:33:19 -07:00
Peter Steinberger 848a7e30b3 refactor(computer-use): one canonical wire contract + node-host provider seam (#123509)
* refactor(computer-use): add provider seam

* refactor(computer-use): retry provider open after failure; drop changelog entry
2026-08-13 23:32:32 -07:00
ClawSweeper 0b0fe6ecc0 fix(gateway): retain admission across setup sessions (#123418)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Colin Johnson <colin@solvely.net>
2026-08-13 23:30:24 -07:00
Peter Steinberger 1647027880 fix: isolate collected turns by model route 2026-08-13 23:28:53 -07:00
Peter Steinberger 42b74b2978 fix: restrict pending input to route-only changes 2026-08-13 23:28:53 -07:00
Peter Steinberger 129c06d811 fix: bind steering authority to model route 2026-08-13 23:28:53 -07:00
Peter Steinberger d183d06738 fix(codex): deny native tool feature pins 2026-08-13 23:28:53 -07:00
Peter Steinberger 54cf346abb fix: preserve pending input across authority changes 2026-08-13 23:28:53 -07:00
Peter Steinberger 1bb20fb16a fix(codex): bind steering to tool authority 2026-08-13 23:28:53 -07:00
Peter Steinberger 0fa354827f fix(copilot): bind active runs to host tool authority 2026-08-13 23:28:53 -07:00
Peter Steinberger 18b4cc94ff fix: drain authority-mismatched provided operations 2026-08-13 23:28:53 -07:00
Peter Steinberger b5809f5f44 fix: enforce native tool policy across harness lifecycles 2026-08-13 23:28:53 -07:00
Peter Steinberger 252bb545b4 fix(macos): keep background hosts out of GUI keychain (#123500)
Background-only Bridge and Mac-node launches keep GUI onboarding and saved Gateway-profile Keychain state cold while preserving environment/config-owned Gateway connectivity.
2026-08-13 23:28:26 -07:00
Peter Steinberger 8cfc415af4 fix(plugins): make setup registration atomic (#123506) 2026-08-13 23:27:57 -07:00
Ayaan Zaidi 14882ac44d fix(ci): prevent Telegram test watchdog stalls (#123514)
Bound Telegram extension tests to five files per Vitest process across explicit config, directory, and full-suite routes while preserving serial isolated execution.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-14 11:55:29 +05:30
Peter Steinberger e7a2d1758a fix: Control UI test lane fails at random on unrelated pull requests (#123512)
* fix(test): keep shared jsdom window in step with the per-file module reset

The non-isolated runner already resets the module graph after every test file,
so each file evaluates its own component classes. The jsdom window it shares
across the whole worker was never reset with it: every Control UI component
registers with `if (!customElements.get(tag))`, so the first file to import a
component owned that tag for the rest of the run and `document.createElement`
kept building elements closed over that file's module instances. Later files'
singletons, module mocks, and spies were never the ones production reached, so
assertions failed as "expected ... to be called once, but got 0 times" in
whichever files the size-based sequencer happened to place after a warming one.

Drop repo-owned tags with the graph they came from. Dependency packages are
externalized and register once per worker through native ESM, so their
definitions are attributed by define call site and kept.

The same window also carried mounted DOM forward, so helpers reading
`document.body.querySelector(...)` answered an earlier file's leaked dialog and
focus assertions read its stale activeElement. Clear the body with it;
`document.head` stays, since dependency styles cannot be replayed either.

* fix(test): keep the jsdom definition shape local to its module
2026-08-13 23:25:08 -07:00
Peter Steinberger 7cadfb0bd6 fix: speed up local node launches and isolate scratch state (#123503)
* perf(node-host): reuse advertised worker build identity

* fix(agents): keep default workspaces inside state dir

* fix(plugins): package llama.cpp private SSRF runtime

* fix(node-host): silence missing skills directory
2026-08-13 23:24:54 -07:00
Peter Steinberger 6bd21a1122 fix: make device onboarding and dispatch outcomes honest (#123501)
* fix(gateway): approve joined node surface

* fix(sessions): record offline device dispatches

* fix(sessions): reclaim failed worker placements

* fix(gateway): escalate session cwd scope

* fix(agent): honor recorded terminal outcomes
2026-08-13 22:55:09 -07:00