Commit Graph

80561 Commits

Author SHA1 Message Date
Peter Steinberger fd8326c5bf fix(codex): reap sandbox process trees before termination (#125908) 2026-08-18 10:48:10 -07:00
Peter Steinberger fd216cb550 fix: prevent plugin metadata rescans from stalling Gateway (#125596)
* fix(plugins): preserve gateway metadata ownership

Generic runtime contexts no longer displace the Gateway lifecycle snapshot, preventing repeated synchronous plugin inventory validation on session hot paths.

* fix(gateway): reuse lifecycle plugin generation for turns

* test(agents): align static runtime lifecycle expectations

* test(gateway): refresh minimal runtime fixtures

* test(runtime): pass lifecycle metadata explicitly

* fix(skills): reuse gateway metadata for commands

* test(gateway): prepare reply runtime for agent RPCs

* style(agents): format rebased runtime preparation

* test(gateway): prepare runtime for direct agent RPCs

* test(gateway): provide direct agent runtime fixture

* test(gateway): prepare chat send reply runtime

* test(qa): await descendant process exit
2026-08-18 10:47:16 -07:00
Peter Steinberger f95b5a0062 test(ui): wait for the outbox retry drain instead of the timer tick (#125912)
The retryable-send and retryable-history tests asserted the resend side
effect immediately after `vi.advanceTimersByTimeAsync(100)`. Sinon's async
tick yields exactly one real macrotask after firing the last timer, and the
retry chain (`void scheduleStoredChatOutboxDrain` -> `chat.history` ->
`chat.send`) consumes exactly that one boundary, so the assertions had zero
slack and flaked under CI contention.

Wait for the outcome with `waitForFast` instead, and fold the outbox-empty
assertion into the wait since retirement lands after the send call.
2026-08-18 10:45:29 -07:00
Peter Steinberger 0684f50136 fix(gateway): harden hook admission and shutdown (#125893)
* fix(gateway): harden hook admission and shutdown

Flush structured 413 and 408 hook responses before closing oversized or timed-out request sockets, and reject deferred wake requests that target an explicit session.

Direct Gateway close now marks startup and readiness as draining immediately and attempts every HTTP listener shutdown before reporting an incomplete close.

* test(gateway): model request destruction in fuzzing

Give the HTTP request fuzz double the IncomingMessage destroy contract exercised after 413 and 408 responses finish.

* fix(gateway): preserve response and shutdown bounds

Route installed webhook body-limit failures through the shared response-first close owner and require complete Feishu 413/408 responses before terminal connection closure.

Retain the current-main grace bound for agent-harness disposal so one stuck harness cannot block listener teardown.

* test(telegram): model response-close request cleanup

Keep the slow-body request alive through response finish, then assert cleanup when the mock response transport closes.
2026-08-18 10:39:56 -07:00
Peter Steinberger d33ba0015d fix(mcp): preserve recovery text with structured results (#125914)
* fix(mcp): preserve structured result text

* fix(mcp): preserve node-host structured results
2026-08-18 10:36:03 -07:00
Peter Steinberger a7d6256be8 fix(agents): link known progress card references (#125887) 2026-08-18 10:31:28 -07:00
Peter Steinberger bc30277683 perf(test): narrow harness differential mock (#125911) 2026-08-18 10:27:32 -07:00
Peter Steinberger fead7fee27 refactor: consolidate small shared helpers (#125805)
* refactor: consolidate small shared helpers

* fix: reject inherited Parallels smoke arguments

* fix: preserve day-prefixed CPU probe times
2026-08-18 10:23:40 -07:00
Peter Steinberger d204ebe6a4 fix(codex): recover replies after compaction failure (#125895)
Preserve completed tool work when native Codex compaction fails, close failed compaction progress, and bypass unrelated model/auth failover before isolated finalization. Fixes #125789.
2026-08-18 10:22:35 -07:00
Onur Solmaz 6988551b87 fix(ollama): report streaming responses (#125834) 2026-08-18 20:19:48 +03:00
Peter Steinberger 96d603f530 fix(gateway): block unauthorized session lifecycle sources (#125889)
* fix(gateway): enforce session participation at lifecycle commits

* refactor(gateway): simplify session target extraction
2026-08-18 10:17:28 -07:00
Peter Steinberger f8ba65636c feat(control-ui): simplified settings experience for non-admin operators (#125492)
* test(control-ui): add --operator-scopes flag to the mock dev server

* feat(control-ui): simplified settings experience for non-admin operators

Non-admin browsers previously saw every settings page, many of which
dead-ended or rendered enabled controls whose RPCs fail with
'missing scope: operator.admin'.

- config.schema drops from operator.admin to operator.read: the schema is a
  static document describing options whose values are already readable via
  read-scoped config.get; admin-only schema only broke read-only settings
  rendering (Automation/Infrastructure/AI Agents/Communications showed
  'Schema unavailable. Use Raw.').
- Settings sidebar and settings search hide admin-only routes (custodian,
  labs, updates, automation, infrastructure, mcp, security, secrets,
  cloud-workers, communications, ai-agents, model-setup) for non-admin
  viewers; legacy gateways without advertised scopes keep the full UI.
- Channels, Devices, Worktrees, Memory Import, Profile gate their mutation
  controls on actual scopes with 'Browsing only…' notices instead of
  enabled-but-failing buttons; Devices no longer fires device.pair.list /
  exec.approvals.get without the scopes to call them (kills the two red
  error callouts on page load).
- Scope-upgrade banner: dismissing it in the guidance phase (no in-app
  upgrade path) now hides it fully instead of leaving a permanent chip.
- Config write coordinator surfaces scope refusals as a visible
  admin-required error instead of silently resolving false.

* test(control-ui): advertise config.schema in the mock dev gateway

ensureSchemaLoaded now checks method advertisement + scope before loading
the schema; the mock harness must advertise config.schema like a real
gateway does or schema-driven settings pages render empty in the mock.

* fix(control-ui): close the worktree create draft on scope downgrade

* perf(doctor): isolate memory health artifact

Doctor lint loaded the broad Memory Core API barrel only to register health checks and read isolated check IDs. That synchronously pulled the full memory public graph into the first lint run, consuming most of the 120-second test budget.

Load a dedicated doctor-health public artifact instead and verify it is packaged. The bisect boundary was 9de3ca5fc9 (#125571); because that commit only adds upgrade-test assets, it exposed a pre-existing runner-sensitive cost rather than introducing the expensive import path.

* test(control-ui): restore device lifecycle test boundary

* perf(control-ui): lazy-load settings sidebar

* fix(ui): recheck access after confirmations

* fix(control-ui): gate presence-driven device reloads on pairing access

The presence connectivity-change path still called device.pair.list without
operator.pairing, the same invariant the pair-event and poller paths already
guard; a limited browser got a doomed RPC on every connectivity change.

* fix(control-ui): fail open on schema loads for legacy scope-less gateways

canCallGatewayMethod hardened to strict advertisement+scope checks (#125478),
which made the new ensureSchemaLoaded gate silently skip config.schema for
legacy hellos without advertised scopes or a method list. Schema loads now
skip only on a definitive denial (method advertised absent, or advertised
scopes without operator.read), reusing the fail-open hasOperatorReadAccess
semantics the rest of the non-admin UI uses; regression test pins the
legacy snapshot path.

* test(control-ui): split schema-access coverage into its own file

runtime-config-capability.test.ts crossed the max-lines cap; the legacy
fail-open regression and its denial counterpart move to a colocated
schema-access test file.

* fix(scripts): keep mapped Vitest lanes at their measured no-output floor

The codex extension shard legitimately works in silence beyond 300s under
the default reporter (measured 61s import + 293s testing at ~95% CPU); the
CI-wide OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=300000 env override shrank the
lane below that and the watchdog killed healthy runs, flipping with
incidental flake output (#125825). Per-config entries in
VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS now act as measured silence floors: a
global env value may widen a mapped lane's window but no longer shrinks it;
unmapped configs and the explicit '0' disable keep env verbatim. Adds the
codex extension lane to the map at the extra-long tier (same class as the
discord entry from #123025).
2026-08-18 10:15:10 -07:00
Peter Steinberger b9d0120ee2 fix(cli): protect immutable deployment artifacts (#125902) 2026-08-18 10:11:43 -07:00
Dallin Romney 1a2af5c690 fix(exec): isolate interactive shell env imports (#125624) 2026-08-18 10:06:19 -07:00
Peter Steinberger b9d0e13b5d fix(agents): share one delegation policy across agent runtimes (#125892)
The `## Delegation` guidance added in #125691 lived only in
buildAgentSystemPrompt, so Codex-runtime agents never received it: the
Codex harness builds its own developer instructions in
extensions/codex/src/app-server/thread-prompt.ts and imports nothing
from the system-prompt builders. Live A/B on gpt-5.6-luna had the native
runtime answer "spawn a visible session" while the Codex runtime
answered "spawn a hidden subagent".

Move the policy into src/agents/delegation-guidance.ts, owning both the
main-session mode resolver and the section text, and export it through
the agent-harness plugin SDK barrel that the Codex harness already uses.
The hidden-delegation vocabulary is injected by each runtime, so core
never names a plugin-owned tool: native passes `sessions_spawn`, Codex
passes native `spawn_agent`. Visible sessions stay `sessions_spawn`
with visible=true on both runtimes because Codex-native children are
never OpenClaw sessions.

Also narrows the Codex line that told the model to use `sessions_spawn`
only for OpenClaw/ACP delegation; it now scopes that to internal
legwork, so user-facing deliverables still route to a visible session.
2026-08-18 09:57:52 -07:00
Peter Steinberger 2bed8caf9e feat(ui): channel conversation avatars in the sidebar (Discord + Slack) (#125668)
* feat(gateway): proxy channel conversation avatars

* feat(discord): capture conversation avatars

* feat(slack): capture DM sender avatars

* test(discord): bind guild avatar mock

* feat(ui): render channel conversation avatars

* fix(ui): align sidebar owner fixtures

* fix(gateway): version channel-avatar routes by media revision

A stable per-session URL let AuthenticatedAvatarRouteLoader's blob and
sticky-404 caches pin a mounted row to a stale or blank avatar after the
backing media changed. Append an opaque digest of the media reference so
replacement and 404-recovery change the route identity.

* test(ui): align sidebar owner facet

* fix(ui): keep owner chip until channel avatar loads

A session with a channelAvatarUrl suppressed its owner chip even while the
blob was loading, auth was not ready, or the route 404ed, leaving an empty
lead slot. The chip now rides as fallback content inside the avatar element
and yields only to a usable image. Covers 404 and auth-pending states;
avatar rows keep renderedOwnerId unset so an owner-viewer stays visible in
the facepile.

* perf(ui): keep channel avatar fallback within budget

* perf(ui): lazy-load the channel avatar element

The avatar element and its authenticated blob loader rode the startup
bundle through session-leading-indicator, pushing startup JS 51 B over the
CI gzip budget. Channel avatars are not startup-critical: register the
element on the first avatar row; the owner-chip fallback covers the
one-time upgrade window. Startup JS returns ~1 KiB under the ceiling.

* build(ui): raise startup baseline for channel avatars

CI-measured startup JS is 344379 B against a 343289 B baseline (+1090 B).
The avatar element and blob loader are code-split out of startup (previous
commit); the residual is the sidebar lead-slot render branch and row
plumbing, which cannot be deferred. Baseline updated via
check-control-ui-performance --update-baseline with CI bytes per the
script's contract; well inside the 4096 B ratchet step and 358400 B
ceiling.
2026-08-18 09:55:50 -07:00
Peter Steinberger 302d05b988 fix(tui): surface interrupted runs after reconnect (#125898) 2026-08-18 09:43:14 -07:00
Peter Steinberger 0c94dd9913 fix(ui): restore startup budget margin (#125891)
Move GitHub markdown label formatting back behind the markdown loading boundary and exercise markdown-table interactions through the real delegated click owner. This restores startup bundle margin without changing the committed budget baseline and prevents the isolated table test from depending on leaked listeners.
2026-08-18 09:41:48 -07:00
Peter Steinberger d8c1d90edb perf(test): consolidate shutdown watchdog proof (#125890) 2026-08-18 09:27:35 -07:00
openclaw-mantis[bot] 641c9c1943 chore(ui): refresh control ui locales (#125871)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-18 09:25:13 -07:00
Peter Steinberger e011e9db61 fix: child sessions honor inherited model pins over channel defaults (#125880)
* fix: honor inherited model pins over channel defaults

Child sessions now keep parent model pins consistently across reply, status, harness prediction, and agentCommand.

* test: align agent command model selection fixtures

Keep concurrent override and threaded parent-selection coverage aligned with canonical model normalization and runtime snapshot access.
2026-08-18 09:24:15 -07:00
Peter Steinberger e68e973c05 fix: report unknown gateway service state when inspection fails (#125734)
* fix(daemon): preserve unknown service load state

* test(daemon): update service load-state fixtures

* fix(onboard): preserve loaded service diagnostic

* fix(daemon): preserve unknown lifecycle state

* fix(status): preserve loaded JSON fields

* fix(daemon): fail restart on unknown service state

* fix(daemon): fence unknown service state
2026-08-18 09:20:02 -07:00
Peter Steinberger 6629ca32df fix(status): surface gateway runtime degradation (#125888) 2026-08-18 09:17:31 -07:00
Peter Steinberger 9e24399e82 fix(ci): stop the codex lane hanging on a cold real-tool graph (#125864)
* fix(ci): stop codex lane cold-graph hangs

The side-question domain-policy test loaded the complete agent-harness tool graph inside a one-second readiness race, making the serial non-isolated Codex shard fail or stay silent under cold imports. Build the test's web_search marker and real web_fetch tool from the narrow implementation, then synchronize on turn startup before issuing the tool call. Cap each Codex test process at 12 files so CI gets bounded time-to-first-output as defense in depth.\n\nRefs #125839

* fix(test): keep codex web fetch fixture on sdk boundary

Load the real web_fetch factory on demand through the existing local-only plugin test runtime. This preserves the narrow cold-graph fix without letting a bundled plugin test reach into core internals.
2026-08-18 09:15:38 -07:00
Dallin Romney 0ac6c4bd2e test(agents): isolate live session model fixture (#125659) 2026-08-18 09:14:09 -07:00
Peter Steinberger 5f65ef8138 feat: add A2UI widgets to session boards (#125803)
* feat: add A2UI board widgets

* fix: harden A2UI board widget integration

* fix: repair A2UI CI contracts

* fix(canvas): keep native A2UI pushes on v0.8

* fix(canvas): support board-only widgets without file host
2026-08-18 09:08:45 -07:00
Peter Steinberger 6d01ae5168 fix(ui): refresh chat checkout side panels (#125785)
* fix(ui): refresh chat checkout side panels

Retire checkout-owned PR, branch, Files, and Review state when a
structural session mutation or logical connection epoch replaces the
checkout. Surface an actionable reload path for transient sidebar chunk
failures while keeping chat usable.

Release note: Control UI checkout side panels now refresh reliably after
session replacement and reconnect, and failed sidebar chunks can recover
without leaving blank content.

Refs #125767

* fix(ui): keep structural refresh within startup budget

Record the structural-session classification once at the canonical event
parser and carry that fact to PR, session, and chat consumers. This removes
duplicate payload classification and keeps the checkout refresh repair within
the Control UI startup bundle budget.

Refs #125767

* test(ui): align worker refresh with chunk recovery

Advance the mock Gateway build identity with replacement assets so stale
sidebar chunks can recover without creating an artificial version-skew loop.
Assert that the catalog-owned terminal intent survives both refresh owners and
opens exactly once.

Refs #125767

* fix(ui): retire checkout summaries at consumers

Keep structural mutation policy in the PR snapshot store, match every watched
session alias, and retire derived summaries through fenced chat/sidebar
consumers. Preserve canonical summary identity and avoid adding structural
event policy to the startup session parser.

This also restores the Control UI startup bundle below its enforced budget on
the latest main base.

Refs #125767

* test(ui): accept either update recovery owner

Allow stale-chunk document recovery or service-worker activation to win the
pre-activation race, while still requiring the catalog terminal intent to
settle exactly once after both recovery owners finish.

Refs #125767

* refactor(ui): keep workspace agent resolver private

The split workspace state owner consumes the pane agent resolver internally;
do not retain a stale export after adapting the checkout-ownership repair.

Refs #125767
2026-08-18 08:54:26 -07:00
Dallin Romney 8de2679a5e test(release): preserve Codex follow-through finality (#125619)
* fix(ci): mark Codex follow-through progress non-final

* test(ci): assert Codex progress finality

* test(ci): align Codex follow-through assertion

* test(codex): accept explicit progress finality

* test(release): preserve frozen Codex finality
2026-08-18 08:53:48 -07:00
Peter Steinberger 100e80a023 fix(copilot): preserve profile tool grants (#125875) 2026-08-18 08:53:34 -07:00
Dallin Romney 9a5b808f11 fix(ui): restore drafts after owner discovery (#125637) 2026-08-18 08:53:00 -07:00
Dallin Romney f25f7429df test(release): redact shared failure diagnostics (#125697)
* test(release): use shared channel diagnostics

* fix(release): redact shared E2E failure logs

* test(release): configure redaction timeout fixture
2026-08-18 08:52:17 -07:00
Dallin Romney f263e75260 test(matrix): expose raw command mention safety (#125685)
* test(matrix): expose raw command mention safety

* refactor(qa): consolidate Matrix preview snapshot

* fix(matrix): project command text through progress

* refactor(matrix): keep QA projection within lint boundary

* style(matrix): apply canonical transport formatting
2026-08-18 08:51:50 -07:00
Peter Steinberger 7f4b7be3c1 test(agents): make Code Mode drain coverage deterministic (#125869) 2026-08-18 08:51:23 -07:00
Peter Steinberger 13e3d4535b fix(agents): finalize guided creation safely (#125768)
* fix(agents): finalize guided creation safely

Run channel post-write hooks only after config publication, defer portable auth copying until agent creation succeeds without overwriting newer credentials, and provision existing workspaces before publishing updates.

Keep JSON-only guided creation interactive while routing wizard output to stderr so stdout remains one machine-readable summary.

* fix(terminal): preserve note call signature

* fix(agents): pass committed config to setup hooks

* ci: split heavy codex changed-test shards

Cap non-isolated Codex extension processes at 20 files so 4-vCPU changed-target jobs do not starve real-time watches or hit the no-output watchdog.

* test(ci): align codex shard cap fixture

* docs(cli): clarify agents add JSON mode
2026-08-18 08:50:01 -07:00
Peter Steinberger fc1862c35c perf(test): remove duplicate hovercard waits (#125876) 2026-08-18 08:48:14 -07:00
Peter Steinberger 9bbb33bd2e fix(skills): report execution-directory skill precedence collisions (#125865)
loadMergedWorkspaceSkills dropped execution-directory skills whose name
collided with an agent-workspace skill without any log, diagnostic, or
record, while the sibling loadSkillEntries merge warned on every
collision with winner/loser source and path. An operator's
execution-directory skill simply did not exist and nothing said why.

Extract the existing warning into warnSkillPrecedenceCollision and call
it from both merge paths. Precedence is unchanged: the agent workspace
still wins.
2026-08-18 08:46:11 -07:00
Peter Steinberger 005a63f252 test: remove prompt snapshot facades (#124333) 2026-08-18 08:45:44 -07:00
Peter Steinberger 1f54696b29 perf(ui): coalesce new session draft writes (#125868) 2026-08-18 08:41:18 -07:00
Peter Steinberger d84a910fc8 refactor(ui): send to the selected session; delete exact-run steer machinery (#125862)
browser no longer chooses or persists run targets; steer sends ride the generic durable outbox with queueMode steer and no expectedRunId/expectedLeafEntryId; deletes steer-lifecycle.ts, steered-chip.ts, kind:"steered", steerTargetRunId, sendState:"steering", target-bound retry, uniqueness failure rows; persisted outbox rows normalize at load; net -625 production LOC.
2026-08-18 08:38:23 -07:00
Peter Steinberger 8dd0434f86 fix(config): redact plugin secrets and preserve safe mutations (#125753)
* fix(config): secure CLI reads and mutations

Use exact plugin metadata for config get redaction, reject impossible SecretRef provider bindings in canonical validation, preserve include CAS provenance, and skip destructive authored no-op rewrites.

* fix(config): preserve inactive SecretRef startup

Keep normal Gateway validation scoped to active secret owners while strict config validation and write paths reject impossible provider/source bindings, including authored no-ops.

* fix(gateway): preserve config patch no-op

Keep unchanged Gateway config.patch requests on the existing no-op path; strict validation remains owned by actual config writes and the config CLI mutation surfaces.
2026-08-18 08:37:21 -07:00
Peter Steinberger 8cfacedabe test(gateway): pin chat-run lifecycle transitions (#125851) 2026-08-18 08:26:04 -07:00
Peter Steinberger 07a0b51703 fix(gateway): enforce shutdown deadline during event-loop stalls (#125863)
Use an off-main-thread watchdog for the process-owning Gateway runner so a CPU-bound shutdown cannot outlive the managed restart deadline. Bound agent-harness disposal so listener teardown can continue.

Release note: Managed Gateway restarts now recover when shutdown work stalls the event loop while preserving graceful cleanup first.

Closes #125840
2026-08-18 08:14:30 -07:00
Ayaan Zaidi 0c0649037c feat(ui): show applied revision changes (#125854)
Show bounded predecessor diffs by default so operators can understand applied Skill Workshop revisions without manual comparison. Keep the full revision body one click away and preserve oldest-revision fallback behavior.
2026-08-18 20:40:07 +05:30
Peter Steinberger c77feb00f3 feat(ui): move session filter to a global sidebar toolbar (#125690)
* feat(ui): promote session controls to toolbar

* test(ui): add session toolbar proof capture script

* chore: register session toolbar proof script

* test(ui): target ungrouped session drop zone

* fix(ui): trim session toolbar startup cost

* docs(ui): point new-session guide at the Sessions toolbar

Also name the accepted tradeoff for the inert ungrouped-collapse preference at the partition site (ClawSweeper P1/P3 response).

* test(ui): deflake new-session workspace-memory e2e

Menu-geometry assertions now measure relative to the picker anchor in one atomic evaluate (immune to unrelated page settles, still catches focus-induced moves). The post-reload refill raced the composer's async draft restore, which appended the stored draft to the typed text; waiting for the restored draft asserts the documented persistence instead. Failed CI shard checks-ui-e2e 5/12 on runs 32122284238 attempts 1-2.

* fix(ui): use canonical session owner filter state

* chore(ui): keep session toolbar proof artifacts ignored
2026-08-18 08:09:57 -07:00
Peter Steinberger 1ed682f883 fix(codex): explain timed-out MCP approvals (#125860) 2026-08-18 08:02:54 -07:00
Peter Steinberger 8131f56cb1 fix(ui): show progress cards on session links (#125733) 2026-08-18 07:58:52 -07:00
Peter Steinberger 77326c5797 fix(sessions): retry late reply initialization conflicts (#125849) 2026-08-18 07:55:20 -07:00
Peter Steinberger 66dae86d86 refactor(agents): prepare provider route facts at model-route build (#125799)
* refactor(agents): prepare provider route facts at model-route build

* test(agents): isolate prepared route generation assertion

* test(fal): update provider HTTP mock shape
2026-08-18 07:55:13 -07:00
Peter Steinberger bdbb0444ee fix: share Control UI terminals with chat agents (#125758)
* fix: share Control UI terminals with chat agents

* fix: terminate canceled shared terminal opens

* perf(ui): keep terminal binding behind lazy boundary

* perf(ui): reuse terminal session scope for bottom dock

* perf(ui): reuse session route decision

* fix: keep shared terminal cleanup server-owned

* fix: preserve shared terminal session identity
2026-08-18 07:51:48 -07:00
Dallin Romney f6dbcc1ba9 test(e2e): keep recovery proof alive (#125804) 2026-08-18 07:44:38 -07:00