Commit Graph

78942 Commits

Author SHA1 Message Date
Peter Steinberger 3cdbe3a511 fix(ollama): verify guided setup with runtime model (#123190) 2026-08-13 14:27:34 -07:00
Peter Steinberger 459891c035 fix(ai): session cost understates gpt-5.5 priority (fast mode) turns by 20% (#123152)
* fix(ai): managed OpenAI transport understates gpt-5.5 priority pricing by 20%

The managed Responses transport carried its own copy of the service-tier
pricing table in openai-responses-debug.ts (flat 2x for priority). The
canonical helper applyResponsesServiceTierPricing in
openai-responses-shared.ts was updated to 2.5x for gpt-5.5 priority
(#117298) but the transport copy was never touched, so UI cost for
managed-transport fast-mode turns understated the real spend.

Delete the duplicated table and delegate the transport's pricingOptions
to the canonical model-aware helper. Azure intentionally remains
tier-unpriced (it sets no pricingOptions).

* test(ai): pin managed-transport gpt-5.5 priority pricing at the transport boundary

ClawSweeper correctly flagged that the helper-only test also passes on
unfixed main. Add a mocked managed-transport run with a priority
response and nonzero model cost asserting the final usage cost is 2.5x
(fails at 24 vs 30 on the pre-fix flat table).
2026-08-13 14:26:38 -07:00
Peter Steinberger ffa8a1d892 fix(release): print post-update config diagnostics (#123221) 2026-08-13 14:24:22 -07:00
Peter Steinberger 63b18e6e5f feat(auth): explicit shared auth store seam (#123298)
* feat(auth): explicit shared auth store seam

* fix(auth): fail closed on unserved shared store

* fix(auth): preserve snapshot database identity
2026-08-13 14:22:51 -07:00
Peter Steinberger babba7124d fix: heartbeats fail after successful replies in explicit agent fleets (#123303)
* fix: keep heartbeat reply accounting agent-scoped

* fix: close ambient owner fallback gaps
2026-08-13 14:19:25 -07:00
Peter Steinberger dbea5a77f0 fix(ui): make Control UI terminal readable in light mode (#123184)
The light terminal theme reused the dark-background ANSI palette (1.4-2.6:1
contrast on #f7f8fa; brightWhite was 1.06), and the intro banner hardcoded
256-color indices 223/216 that bypass the client theme entirely.

Light mode now gets its own darkened ANSI-16 palette (>=4.5:1, bright
variants darker for emphasis, brightWhite maps to strongest ink), and the
banner emits themable ANSI-16 yellow/bright-red so each mode owns its
rendering. Dark mode is visually unchanged.
2026-08-13 14:14:35 -07:00
Josh Lehman f04fdd5594 fix(ui): align transcript search corner radius (#123299) 2026-08-13 14:12:30 -07:00
Josh Lehman 0b847dc92f fix(ui): keep question prompts from fading transcript (#123301) 2026-08-13 14:11:48 -07:00
Peter Steinberger be7f3225f7 fix: auth-cold gateways hide all models and dead-end the operator (#123130)
* fix(control-ui): recover auth-cold model pickers

Keep configured auth-cold models visible but disabled in chat and new-session, block submission, and link Model Setup. Fixes #123080.

* fix(control-ui): preserve rebased model picker behavior

* fix(ui): split composer model picker under the lint size cap

Repairs main's red check-lint caused by the #123090 restore.

* fix(ui): align auth-cold picker CI contracts
2026-08-13 14:09:35 -07:00
Peter Steinberger b3d5265f58 fix(docker): harden runtime images against CVE surface (#123282)
* fix(docker): harden runtime image dependencies

* chore(deps): update container security dependencies

* docs(docker): explain image security contents

* test(browser): align file-chooser and install tests with #114506 contract

* test(browser): restore extension install test isolation

* test(browser): add temporary CI diagnostics for pre-registration refusal

* test(browser): make install fixture interpreter hermetic

The suite passed process.execPath as the native-host interpreter; on
GitHub-hosted runners the hostedtoolcache node binary is group/world-
writable, which installChromeExtensionBootstrap correctly refuses, so
every registration test failed CI-only. The fixture now provides an
owned 0700 interpreter; only the launcher-exec test keeps the real
node it must spawn.

* fix(qa-lab): stop re-polling after a probe consumes the discovery deadline

The Matrix health-probe loop re-entered when the probe timeout fired
marginally before Date.now() crossed the deadline, starting a doomed
extra probe. Flaked on contended CI runners as 'expected 1 fetch, got
2'. A timed-out probe now ends discovery.

* test(ui): poll the callout inset invariant in device-scope E2E

One-shot boundingBox reads raced the nav-collapse transition and
intermittently measured a 20px stale offset on CI.
2026-08-13 14:02:39 -07:00
Peter Steinberger 2dcd47d4f4 feat(runners): remember offline devices (#123198)
* feat(runners): remember offline devices

Persist exact node connection end timestamps and keep execution-capable offline devices visible with quiet lifecycle history in the session picker.

* test(ui): keep offline devices disabled
2026-08-13 13:49:00 -07:00
Peter Steinberger faa6202412 fix(slack): keep thread freshness on routed agent (#123202) 2026-08-13 13:17:36 -07:00
ClawSweeper 036bcc1a65 fix(agents): self-heal unsupported harness transports (#123258)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-13 13:08:35 -07:00
Peter Steinberger 927a97c1ea fix: keep automation delivery owned in multi-agent fleets (#123283)
* fix: preserve automation owner during channel bootstrap

* fix: retain scoped runtime during cron delivery

* style: format cron delivery regression

* chore: defer release changelog entry
2026-08-13 12:52:34 -07:00
Peter Steinberger 12ada43464 refactor(ui): resolve duplicate stylesheet selectors and restore no-duplicate-selectors (#123166)
* refactor(ui): resolve duplicate stylesheet selectors and restore no-duplicate-selectors

* refactor(ui): merge duplicate .kbd block in file-preview modal instead of config carve-out
2026-08-13 12:50:18 -07:00
Peter Steinberger 21d59e16e2 feat(gateway): monitor cloud session disk space (#123177)
* feat(gateway): monitor cloud session disk space

* fix(gateway): keep disk monitor contract acyclic
2026-08-13 12:47:53 -07:00
Peter Steinberger b233ea7957 fix(health): surface blocked ingress lanes (#123234) 2026-08-13 12:44:59 -07:00
Peter Steinberger 9415181b75 fix(ui): make active visibility pill distinct from its hover state (#123173)
* fix(ui): make active visibility pill distinct from its hover state

* test(ui): advertise sessions.create in the control-ui mock harness

* ci: refresh pull_request run after zombie-queued Blacksmith jobs
2026-08-13 12:42:40 -07:00
Peter Steinberger d3308e2cfd fix(cron): fence executions with durable receipts (#122948)
* fix(cron): fence concurrent executions durably

* refactor(cron): keep receipt hooks internal

* refactor(cron): hide internal save hooks

* test(cron): inspect receipts through SQLite

* test(cron): auto-clean process fixtures

* refactor(cron): avoid receipt service cycle

* fix(cron): harden receipt cleanup and retention

* refactor(cron): simplify receipt cleanup

* fix(cron): serialize owner updates with run leases

* fix(cron): hold run leases through settlement

* fix(cron): recover stale foreign run receipts

* fix(cron): complete durable receipt recovery

* fix(cron): preserve foreign handoff transitions

* fix(cron): make owner recovery atomic

* fix(cron): isolate reservation retries

* refactor(cron): scope runtime writes by job

* fix(cron): harden lazy receipts and reservations

* fix(cron): close startup recovery races

* fix(cron): make queued leases atomic

* fix(cron): unify receipt lifecycle recovery

* fix(cron): adjudicate stale receipts before fencing

* fix(cron): close terminal consistency gaps

* fix(cron): preserve terminal publication ordering

* fix(cron): break rebased store import cycles

* fix(cron): reconcile rebased finalization contracts

* fix(cron): type unavailable-owner settlement
2026-08-13 12:40:55 -07:00
Peter Steinberger f2f3ba2eaf refactor(ui): consolidate responsive breakpoints onto a canonical ladder (#123160)
Use the 400, 560, 640, 768, 900, 1100, and 1320px max-width ladder. Round noncanonical thresholds up to the next rung so compact layouts engage before desktop layouts become cramped.

Move the 1180px agent-tool summary breakpoint to 1320px because the persistent desktop rail leaves about a 1020px content column at that viewport; 1100px would coincide with the rail disappearing and the content expanding.

Stylelint now enforces the ladder and the existing compound-query exceptions.
2026-08-13 12:34:50 -07:00
Peter Steinberger 0d73229b60 fix(ci): route fork-PR runs to hosted runners in standalone workflows
Repo variables are not supplied to fork-triggered pull_request runs, so
the OPENCLAW_CI_RUNNER_BACKEND breaker silently fell through to bare
Blacksmith labels for fork PRs; mirror ci.yml's fork-to-hosted fallback.
2026-08-13 12:28:20 -07:00
Peter Steinberger f329a9489f fix(ci): raise shared e2e hookTimeout to 180s on all platforms
GitHub-hosted 4-core fallback runners (Blacksmith-outage breaker) push
ui e2e beforeAll hooks past the 120s Linux limit; Windows already ran
at 180s for the same slower-machine reason.
2026-08-13 11:40:57 -07:00
Peter Steinberger d805562a84 fix(ui): verify referenced translation keys (#123279) 2026-08-13 11:32:56 -07:00
Peter Steinberger bc8e51ce37 refactor(memory-core): strengthen dreaming boundaries (#123138)
Replace assertion-driven cleanup with real runtime narrowing and typed owner contracts across memory-core dreaming.

Reject the unsound one-file lint ratchet and document repository-wide rules against checker-gaming and baseline-driven enforcement.

Co-authored-by: Amp <amp@ampcode.com>
2026-08-13 11:32:25 -07:00
Vincent Koc abd63c06c2 fix(ci): allow GitHub-hosted npm preflight (#123191) release-publish/abd63c06c2f5-1786646045 2026-08-14 02:32:01 +08:00
Peter Steinberger 249a38d29f fix: keep background work scoped to its selected agent (#123257)
* fix: preserve explicit agent ownership

Scoped route, session, and job owners now survive hooks, cron, process exits, global delivery, bindings, and media cleanup. Truly ownerless operations remain explicit errors.

* test: provide session memory hook owner

* test(ui): close failed-module page explicitly

* test(matrix): align ownership and replacement proof
2026-08-13 11:29:31 -07:00
Peter Steinberger 8e0f464a5f fix(gateway): suppress ambient channel auto-enable (#123174) 2026-08-13 11:20:40 -07:00
Peter Steinberger 11b3bf374c feat(slack): unify the native progress turn into one streamed message (#122976)
* feat(slack): unify the native progress turn into one streamed message

Native progress mode now streams the whole turn into a single Slack message:
narration flows as markdown_text chunks interleaved with plan/task chunks,
task rows carry file-path details and +N/-N output, the terminal task links
the session via url_source, and the final answer lands through stopStream in
the same message. Media/oversized/error finals keep their normal-delivery
fallbacks.

Deletes the finished-card receipt collapse (the '\u{1F6E0} N tool calls · ⏱ Ns' edit)
outright: the card now stays as its finished self.

Live-verified on a real workspace: exactly one bot message per turn.

* fix(slack): serialize native stream updates and keep append-only rendered text monotonic

Overlapping progress updates (compositor render, narration payload, final)
computed their narration delta before awaiting the network and committed
state only afterwards, so concurrent updates re-appended identical
narration into the streamed message (each status line landed 3x live).
A single ordering chain now makes each update's compute -> append -> commit
atomic.

applyAppendOnlyStreamUpdate also replaced the accumulated rendered text
with the incoming cumulative partial once an appended chunk had diverged
rendered from source, dropping content the sink already displayed; rendered
now only ever extends.

* fix(slack): stop refreshing thread status once a turn has visible output

Slack clears the assistant thread status as soon as the app puts anything
in the thread, and renders its own rotating agent-working row ("Generating
response...", "Finding answers...") for every status write after that -- it
ignores the app-supplied string. The typing keepalive re-set the status
every 3s for up to 60s, so each turn painted a duplicate status row under
the streamed card or progress message.

The status write is now gated on the turn having visible output, which the
dispatcher already tracks (delivered reply, committed preview, or posted
draft message). The first status still fires before any output, so slow
turns keep their indicator, and the typing reaction is tracked separately
so a suppressed status write still cleans up its reaction.

* fix(slack): let the plan card own the status line instead of echoing it

The status headline and plan explanation fed both the streamed narration
markdown and the plan card title, so every headline rendered twice: once as
static text and once in the card that keeps updating it in place. Narration
now carries only authored commentary and reasoning, and a preamble payload
whose text the card title already shows is not streamed again.

* feat(slack): make the native agent card the default progress surface

Slack's native plan/task card was opt-in behind streaming.progress
.nativeTaskCards while the Block Kit session card shipped as the default.
The native surface is the better product on every axis we can measure --
one streamed message instead of three artifacts, live task rows with file
paths and diff counts, and Slack's own agent chrome -- so it becomes the
default and an explicit false selects the Block Kit card instead.

The session link is now emitted only when it can actually work: the
operator set gateway.publicOrigin and left the Control UI enabled.
Installations with no externally reachable Gateway get no link rather than
a dead one.

The progress card still only appears for turns that do real work; the
existing compositor start gate keeps plain question-and-answer turns
card-free.

* fix(slack): finish the final inside a buffered native stream

A short narration leaves the SDK session un-flushed, so `delivered` stays
false until `stop` makes its first network call. Requiring delivery before
finishing in-stream sent the final through normal delivery and then
finalized the stream anyway, producing exactly the second message this path
exists to prevent. Stop-time rejection already falls back via
SlackStreamNotDeliveredError, so a live session is enough.

Addresses the ClawSweeper P1/P2 finding on this PR.

* refactor(slack): collapse duplicate streaming surfaces and drop dead code

Cleanup pass over the progress/streaming neighborhood, all verified unused
by exhaustive reference search:

- Deleted buildSlackProgressStreamStartChunks/UpdateChunks: byte-identical
  pass-throughs to the same builder, plus the render-module branch that
  chose between them. One exported builder now.
- Collapsed slackStreaming.draftMode, a lossless restatement of the mode it
  was derived from, and its outbound mapper; nine comparisons now read the
  mode directly. Inbound legacy parsing stays for doctor migration.
- Dropped stopSlackStream's text parameter, the draft stream's stop() member
  and onMessageSent hook, a redundant nativeStreaming argument, four dead
  members on the progress runtime, and two single-expression wrappers.
- Deduped the native card title, which was computed twice per render.

Production LOC for the whole PR drops from +216 to +114.

* chore(config): regenerate bundled channel metadata for the Slack card default

The generated metadata still carried the old opt-in help text and
default-false description for streaming.progress.nativeTaskCards, so
config UI and diagnostics would publish stale guidance.

* fix(slack): un-export the now-internal legacy draft-mode type

Collapsing draftMode removed the type's only external consumer, so knip
flagged it as an unused export. Doctor migration still parses these legacy
values inbound, so the type stays module-local.
2026-08-13 11:19:32 -07:00
Peter Steinberger 2b6bf2f8c2 fix(agents): keep portal URLs visible to the portal tool listing (#123149)
* fix(agents): keep portal URLs visible to the portal tool listing

portal.list redacts the bearer URL for read-scope callers, and every
caller resolves least-privilege scopes per method, so listing always ran
read-scoped and lost the URL — even for a caller that can mint the same
credential through action=open. The listing now asks for the write
authority the tool already requires, leaving redaction intact for
genuinely read-only clients.

Live-verified against a running gateway: open returns the URL, a
least-privilege list still omits it, and the tool's write-scoped list
returns it.

* test(agents): align portal gateway request fixture

* test(agents): simplify portal response fixture
2026-08-13 11:00:01 -07:00
Peter Steinberger 2a70d849e8 improve(ci): stripe giant compact test groups (#123142)
* ci: stripe media-ui, gateway-core, and security compact groups

* fix(ci): preserve compact stripe config ownership
2026-08-13 10:46:38 -07:00
Peter Steinberger 165a2e9ede fix(ci): extend runner-backend breaker to PR-gating standalone workflows
OpenGrep precise/full, sandbox-common-smoke, and plugin-init scaffold
validation were still pinned to Blacksmith runners outside ci.yml, so
PR checks starved during the Blacksmith outage even with
OPENCLAW_CI_RUNNER_BACKEND=github. Route them through the same breaker
expression and bound sandbox-common-smoke with a timeout.
2026-08-13 10:23:22 -07:00
Peter Steinberger fb82d87cad fix: keep CI running during Blacksmith outages (#123263)
* ci: add runner-backend circuit breaker with GitHub-hosted fallback

* fix(ci): extend hosted timeouts to circuit-breaker runs
2026-08-13 10:18:35 -07:00
openclaw-mantis[bot] 9550d6f962 chore(i18n): refresh native locales (#123101)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-14 01:00:58 +08:00
Ayaan Zaidi f70d5b8ba5 fix(reasoning-tags): prevent internal reflections in replies (#123196)
Treat <internal> blocks as private reasoning in the shared parser and remove Telegram raw-reasoning fallbacks. This keeps model reflections out of user-visible replies while preserving surrounding answer text.

Closes #122623

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: WangYan <wang.yan29@xydigit.com>
2026-08-13 20:36:48 +05:30
sunlit-deng 0e5855be8b fix(memory-wiki): guard malformed wiki_apply input (#123050)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-13 09:26:21 -05:00
Peter Steinberger 843017073c refactor(ui): route stylesheet colors through the token layer and gate hex literals (#123156)
Add semantic, presentation, brand, and shared highlight tokens in base.css.
Remove dead fallbacks and consolidate dark/light syntax colors behind tokens.
Enforce color-no-hex for CSS while exempting token definitions and sprite artwork.
2026-08-13 05:36:52 -07:00
Peter Steinberger 0926d56cbf fix(ui): stop stamping a dead blur class on chat links containing 'tail' (#123154)
The DOMPurify afterSanitizeAttributes hook added class
chat-link-tail-blur to every rendered chat link whose href merely
contains the substring "tail" (docs.openclaw.ai/tailscale, /details/,
retail, ...). No stylesheet or script anywhere consumes the class: it is
an orphaned producer that survived the Control UI import, polluting
sanitized HTML and the markdown LRU cache, and priming a foot-gun where
any future .chat-link-tail-blur CSS rule would visually blur docs links
in every transcript.

Link presentation classes are owned by markdown-parser.ts
(web-link-classes, hostname-based); delete the substring classifier.
2026-08-13 05:22:02 -07:00
Peter Steinberger 5739c1951b test: speed up model selection suite (#123155)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-13 04:55:15 -07:00
Peter Steinberger 6c9916a48a feat(runners): publish atomic device runner inventory (#123094)
* feat(runners): publish atomic node inventory

# Conflicts:
#	docs/.generated/plugin-sdk-api-baseline/agent-harness-runtime.json
#	src/gateway/server-methods/environments.ts
#	src/gateway/worker-environments/device-provider.test.ts

* fix(runners): refresh topology on inventory removal

* fix(runners): resolve session host type overlap

* fix(protocol): document mobile runner inventory event

* fix(runners): project authoritative session host state

* docs(nodes): clarify prepared session host status
2026-08-13 04:54:26 -07:00
Vincent Koc 6f99d3405c fix(doctor): stop after failed config migration write (#123045) 2026-08-13 19:42:21 +08:00
Peter Steinberger c3d843eb24 test: remove residual duplicate assertions (#123134)
* test: remove residual duplicate assertions

* test: repair stale routing and capability fixtures

* fix(cli): bound one-shot stream drain exit
2026-08-13 04:41:37 -07:00
Peter Steinberger 449ca204a6 fix(ui): keep limited-access banner clear of shell controls (#123128)
* fix(ui): keep limited-access banner clear of shell controls

* fix(ui): avoid native notice gutters
2026-08-13 04:40:26 -07:00
Peter Steinberger baf85e6868 fix(raft): report missing CLI in channel status (#123140) 2026-08-13 04:21:13 -07:00
Vincent Koc 57fabb2c9c fix(release): allow ANSI in reusable job logs (#123129)
Preserve ANSI output for reusable validation job-log reads while retaining a bounded fallback for GitHub CLI versions that do not support the raw-output flag.
release-publish/57fabb2c9c35-1786621048
2026-08-13 19:19:03 +08:00
Vincent Koc 033247ab42 fix(codex): resume parent after terminal subagent fan-out (#123124)
* fix(codex): settle terminal tool releases immediately

Punchcard-Session: quiet-workshop-river-e5

* fix(agents): materialize requester ownership at launch

Punchcard-Session: quiet-workshop-river-e5
2026-08-13 19:15:58 +08:00
Peter Steinberger 2a8b322ebf feat: view your machine's screen from the iOS and Android apps (#123097)
* feat(ui): add mobile desktop document mode

Add a shell-free mobile desktop route that reuses the dock panel controller and lazy noVNC client, with source preselection, touch controls, keyboard input, and retryable inventory failures.

* feat(ios): add desktop viewer entry points

* feat(android): add desktop viewer

* fix(android): keep System Back inside the desktop viewer

The per-session viewer replaces SessionDashboardScreen in place instead of
pushing a shell tab, so System Back fell through to the shell-level handler
and popped the whole Dashboard tab, stranding the operator on Chat. Claim
Back while the viewer is showing.

Also carry over TerminalSettingsScreen's imePadding: the viewer's own touch
toolbar hosts the keyboard affordance, so the soft keyboard would cover it.

Proof (emulator, Medium_Phone_API_36.0, stub control UI on 18789):
pre-fix Back from the viewer lands on Chat; post-fix it returns to Dashboard.
No Robolectric regression test — no existing screen test constructs
MainViewModel, and BackHandler under Robolectric would need new scaffolding
for weaker evidence than the live repro.

* test(ui): stop the pairing views leaking dialogs into the shared document

`ui/vitest.config.ts` runs the unit project with `isolate: false`, so test files
share one jsdom document inside a worker. `view.pairing.test.ts` appends a
container to `document.body` for every case and never tears down, unlike its
sibling `channels-page.test.ts`, so whichever suite the worker scheduled next
inherited a mounted pairing dialog.

That surfaced on this PR's first CI run as ten failures in the untouched
`input-dialog.test.ts`, which found "Approve DM access" where it expected
"Rename session". A rerun went green, so the ordering is scheduler-dependent
rather than deterministic; this removes the contamination source rather than
leaving the next suite to lose the race.

Not a proven fix for that specific run — the leak reproduces only under CI's
file scheduling, and the full suite passes locally either way — but the missing
teardown is a real violation of the shared-environment contract.

* test(ui): stop the background-tasks rail asserting on a ticking clock

The rail e2e captured the main transcript's text before opening a task detail
and required it to be byte-identical afterwards. A running task renders a live
elapsed label, so the assertion failed whenever a second ticked over between
the two reads — twice while landing this PR, both times "12s" against "13s"
with no other difference.

Normalize elapsed labels on both sides instead of weakening the assertion. The
invariant it protects, that opening a detail leaves the main transcript alone,
still holds: a real content change is still caught, and only complete duration
tokens collapse, so diffstat figures like +14/-3 and phrases like "5 messages"
are untouched.
2026-08-13 04:10:48 -07:00
Peter Steinberger d5d069a09e fix(agents): prepare selected harnesses for setup probes (#123141)
Keep explicitly selected plugin runtimes in isolated read-only generations so gateway setup can run Codex candidates. Improve missing-registration guidance.
2026-08-13 04:09:15 -07:00
Peter Steinberger fa18d8d273 ci: pipeline canonical main runs across two concurrency slots (#123135)
Measured canonical-main first-start delay: median 180s, average 209s; 10 of the last 30 runs waited more than 300s.

Approved tradeoff: up to ~+30 concurrent Blacksmith VMs during merge storms. Scope is canonical main pushes only; pull requests, manual runs, non-main refs, and forks keep their existing semantics.

Bump the canonical-main concurrency group from v7 to v8 so in-flight old-group runs cannot mix with the two-slot pipeline.
2026-08-13 04:04:51 -07:00
Peter Steinberger 88a412b0d9 improve: speed up focused model directive tests (#123119)
* test(auto-reply): trim directive suite runtime imports

* test(auto-reply): type channel policy fixture narrowly

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-13 03:58:31 -07:00
Peter Steinberger c218187244 fix(ci): stop killing healthy discord Vitest runs and repair partial runtime-env mocks (#123131)
The discord extension shard's silent transform/import startup (~210s measured
on a loaded macOS host) exceeded the run-vitest wrapper's 120s default
no-output timeout, so the watchdog killed healthy runs (#123025). The config
now gets the extra-long budget like the other large shards.

Three discord tests mocked openclaw/plugin-sdk/runtime-env with bare factories
missing most exports; under isolate=false they poison the shared worker module
cache and break later files that bind logVerbose/sleepWithAbort through the
shared process test harness. They now spread importOriginal and override only
their stubs.

Fixes #123025
2026-08-13 03:54:22 -07:00