Compare commits

...

2283 Commits

Author SHA1 Message Date
Peter Steinberger
d08909f06d test: align sqlite rebase tooling assertions 2026-05-31 10:41:20 +01:00
Peter Steinberger
1087429881 fix: align sqlite rebase with sms ci 2026-05-31 10:41:20 +01:00
Peter Steinberger
89b3cb75e7 fix: align sqlite rebase with current scripts 2026-05-31 10:41:20 +01:00
Josh Lehman
5d7f370dcf fix: drop premature sqlite store guard 2026-05-31 10:41:20 +01:00
Josh Lehman
f4e7a996da fix: restore sqlite sdk build entries 2026-05-31 10:41:20 +01:00
Peter Steinberger
99e5b9f2c7 fix: refresh sqlite rebase generated docs 2026-05-31 10:41:19 +01:00
Peter Steinberger
c21a379a3b fix: align sqlite rebase cleanup with current runtime 2026-05-31 10:41:19 +01:00
Peter Steinberger
fa1a589443 fix: drop stale plugin sdk entries 2026-05-31 10:41:19 +01:00
Peter Steinberger
410bbe69e8 refactor: rebase sqlite runtime cleanup 2026-05-31 10:41:19 +01:00
Peter Steinberger
2c6a3f6b04 fix(gateway): make bare reset commands fast 2026-05-31 10:38:20 +01:00
Peter Steinberger
7bf6667d6c docs: update crabbox skill cache-volume guidance 2026-05-31 10:38:05 +01:00
David
778c4f90b9 fix(agents): route per-turn media task hints below the cache boundary (#87998)
* fix(agents): route media task hints below the system-prompt cache boundary

Per-turn image/video/music generation task hints were injected into the
static prependSystemContext slot, landing above the cache boundary inside the
cacheable prefix. The hints are present only on user/manual turns and vary
with active media tasks, so the cacheable prefix shifted turn-to-turn and
defeated Anthropic/OpenAI prompt caching (#85203).

Split the per-turn media hints out of the prepend resolver into
resolveAttemptMediaTaskSystemPromptAddition and route them below the boundary
via the existing prependSystemPromptAddition helper, matching how subagent and
context-engine system-prompt additions are already routed. The static plugin
prependSystemContext / appendSystemContext hook fields are unchanged and
remain in the cacheable prefix. Applied at both consumers (embedded agent
runner and CLI runner).

* fix(agents): keep media task hints below the cache boundary for hook systemPrompt overrides

A before_prompt_build hook that returns a full systemPrompt override replaces
the base prompt with marker-free text. Per-turn media-generation task hints
were then front-prepended into that marker-free prompt, which providers cache
as a single block, so the cached prefix still shifted turn-to-turn on the
override path (#85203).

Wrap the base with ensureSystemPromptCacheBoundary at both media-routing sites
(embedded agent runner and CLI runner) so a marker-free override gets an
appended boundary and the hint routes into the uncached suffix. The helper is
idempotent, so marker-bearing prompts are unchanged. The shared
prependSystemPromptAddition wrapper and the static prependSystemContext /
appendSystemContext hook fields are untouched.

* fix(agents): keep marker-free idle prompts cacheable below the boundary

A marker-free hook systemPrompt override only had the cache boundary
ensured on turns with an active media task. On idle turns the later
appendModelIdentitySystemPrompt landed above the absent boundary, so the
idle cached system prefix diverged from active turns and prompt caching
broke across active/idle transitions. Ensure the boundary regardless of
media state in both the embedded and CLI runners, and extend the
regression to cover the model-identity append across active->idle.

* fix(agents): scope cache-boundary ensure to the model-identity append

Ensuring the boundary unconditionally on media-idle turns appended a
boundary marker to empty raw/gateway system prompts (turning "" into a
marker-only prompt) and to prompts with nothing below the boundary.
Instead ensure the boundary only when a model identity line is actually
appended to a non-empty prompt, in both the embedded and CLI runners.
This still keeps the identity below the boundary for marker-free hook
systemPrompt overrides (the #85203 idle-cache regression) while leaving
empty and identity-less prompts untouched.

* test: refresh stale type and lint expectations

* test: stabilize CI timeout checks

* test: satisfy channel entry lint

* fix(agents): skip cache boundary for blank prompts

* fix(channels): keep draft flush timer referenced

* test(agents): tolerate failed exec timeout setup

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 10:35:53 +01:00
Peter Steinberger
75ea8b5094 docs: clarify message-tool-only visible replies 2026-05-31 10:35:20 +01:00
Patrick Star
9c1adf4e51 feat: scope group mention patterns by channel
Provider-scoped configured regex mention patterns for Discord, Matrix, Slack, Telegram, and WhatsApp.

Native platform mentions keep their existing behavior, and unsupported channels do not opt into the new regex policy path. The new policy supports per-channel allow/deny routing through mentionPatterns.mode with allowIn and denyIn so group auto-reply regexes can be limited without broad global blast radius.

Refs #70864.
Supersedes #87200.
Thanks @patrick-slimelab.
2026-05-31 10:34:56 +01:00
giming
f94512cd7f fix(xiaomi): support MiMo voicedesign TTS
Adds Xiaomi MiMo voicedesign TTS support by registering the v2.5 voicedesign model and omitting audio.voice for that model's prompt-driven voice design flow.

Also accepts generic TTS aliases modelId, speakerVoice, and speakerVoiceId for Xiaomi provider config and request overrides.

Fixes exec timeout classification so a process that exits after a missed timeout callback is still reported as timed out, using monotonic deadlines to avoid wall-clock skew.

Verification:
- node scripts/run-vitest.mjs extensions/xiaomi/speech-provider.test.ts
- node scripts/run-vitest.mjs src/process/supervisor/supervisor.test.ts
- node scripts/run-vitest.mjs src/agents/bash-tools.exec-foreground-failures.test.ts
- git diff --check
- autoreview --mode local
- live Xiaomi MiMo voicedesign call returned wav RIFF/WAVE output, 169004 bytes
- GitHub CI success on fb3018ef31: CI 26708919072, CodeQL Critical Quality 26708919082, CodeQL 26708919091, OpenGrep PR Diff 26708919089, Workflow Sanity 26708919083, Dependency Guard 26708918574, Real behavior proof 26708921767

Thanks @GimingRao.

Co-authored-by: Raoyu <2425198313@qq.com>
Co-authored-by: giming <53329020+GimingRao@users.noreply.github.com>
2026-05-31 10:34:51 +01:00
Coder
d9d5d97dbc fix(cron): accept sub-second --at datetimes resolved in a timezone (#88185)
getTimeZoneOffsetMs built localAsUtc via Date.UTC() without the millisecond
argument, so for a sub-second instant the computed timezone offset was wrong by
that fraction. That corrupts resolvedMs and fails the exact-millisecond
re-validation in matchesOffsetlessIsoDateTimeParts, so parseOffsetlessIsoDateTimeInTimeZone
returned null for valid fractional input.

User impact: openclaw cron --at "<ISO>.<ms>" --tz <zone> was silently rejected
even though the parser's regex explicitly accepts fractional seconds (\.\d+).

Pass parts.millisecond (carried from utcMs via getUTCMilliseconds) into Date.UTC
so the offset is exact. Add fractional-second regression rows.

Co-authored-by: coder999999999 <coder999999999@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:32:17 +01:00
Feelw00
056bc46a67 fix(infra): guard against overwriting corrupt target session store during migration (#88018)
* fix(infra): guard against overwriting corrupt target session store during migration

migrateLegacySessions reads the target agents/{id}/sessions/sessions.json
and merges it with the legacy sessions dir. When the target file is
corrupt, readSessionStoreJson5 swallows the parse error and returns
{store:{}, ok:false}, so the merge becomes legacy-only. The save gate
(legacyParsed.ok || targetParsed.ok) passes on legacyParsed.ok alone and
never checks targetParsed.ok, so the corrupt target is atomically
overwritten with the legacy-only store. Target-only session records (keys
with no legacy counterpart) are lost permanently and the corrupt file can
no longer be recovered by hand. Legacy corruption is already guarded
(warn + skip delete); target corruption was asymmetrically unprotected.

Skip the save (and the legacy delete) when the target store exists but is
unreadable, leaving the corrupt file and the legacy store both in place,
and push a warning mirroring the legacy-unreadable path. saveSessionStore
and readSessionStoreJson5 signatures are untouched.

AI-assisted: drafted with claude code (claude-opus-4-8).

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

* fix(infra): report direct-chat session migration only after target save commits

Addresses ClawSweeper review on #88018. The `Migrated latest direct-chat session`
result.changes entry was pushed before the targetReadable guard, so the
corrupt-target skip path (which intentionally does not save) still reported a
session migration in doctor/startup logs. Defer that report into the
save-committed block (keeping its existing position before `Merged sessions
store`) and assert its absence in the corrupt-target regression test.

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

* fix(infra): add explicit corrupt session recovery

* fix(infra): keep legacy sessions retryable

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 10:31:59 +01:00
Peter Steinberger
ed46e62bcc feat(workboard): add worker dispatch CLI
* feat(workboard): add worker dispatch CLI

* fix(workboard): avoid new unsafe assertions

* fix(workboard): keep remote dispatch failures remote
2026-05-31 10:31:56 +01:00
shawnduggan
1d55caa162 fix(memory): respect QMD status timeout
Respect the configured QMD status timeout during vector availability probes and skip checkpoint-style session transcript exports while preserving valid session IDs that merely contain checkpoint words.

Includes maintainer fixups for latest-main timer-dependent CI and SMS status/test drift.

Thanks @shawnduggan.

Verification:
- `mise exec node@24.13.0 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents-core.config.ts src/agents/bash-tools.exec-foreground-failures.test.ts --maxWorkers=1`
- `mise exec node@24.16.0 -- node scripts/run-vitest.mjs run src/channels/draft-stream-loop.test.ts --maxWorkers=1`
- `mise exec node@24.16.0 -- node scripts/run-vitest.mjs run extensions/sms/src/channel.test.ts extensions/sms/src/inbound.test.ts extensions/sms/src/twilio.test.ts extensions/sms/src/gateway.test.ts --maxWorkers=1`
- `mise exec node@24.16.0 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway-server.config.ts src/gateway/server.agent.gateway-server-agent-b.test.ts --maxWorkers=1`
- `mise exec node@24.16.0 -- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `mise exec node@24.16.0 -- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo`
- `mise exec node@24.16.0 -- node scripts/run-oxlint-shards.mjs --threads=8`
- `git diff --check`
- GitHub Actions: run `26708853296` and required checks passed on `0c97217a9de501cb861fee731d5c008781da056c`.
2026-05-31 10:29:45 +01:00
Andy Ye
17c2e95334 fix(ui): prefer Talk source-reply final text
Fix Control UI Talk consults so an empty final chat event no longer forces the no-text realtime tool result when a later source-reply or delivery-mirror final contains the answer displayed in the UI.

Also makes agent.wait use the chat-side terminal snapshot while a same-runId chat.send is active, so lifecycle completion cannot beat chat post-dispatch/source-reply delivery.

Adds regression coverage for delayed source replies, agent.wait failure/timeout handling, the wait-before-source-reply race, gateway wait ordering, and punctuation-only skill searches.

Fixes #85275.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-31 10:29:19 +01:00
Evan Newman
a0d2febe6b fix(scripts): timeout crabbox wrapper sanity checks
Add bounded timeouts for Crabbox wrapper sanity probes so a stale or hung selected binary cannot block the wrapper indefinitely. The wrapper now maps timed-out sanity probes to a deterministic failure and keeps provider/help parsing behavior intact.

Also add regression coverage for a binary whose `--version` probe hangs while `run --help` still responds.

Co-authored-by: Evan Newman <evanjames010101@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 10:29:12 +01:00
Peter Steinberger
70c8abdca1 refactor(telegram): keep topic thread mapping plugin-local
* refactor(telegram): keep topic thread mapping plugin-local

* fix(telegram): preserve native topic ids for username targets
2026-05-31 10:25:54 +01:00
Peter Steinberger
9e2bd8b2f7 fix(memory): fail open when embedding recall stalls
Preserve custom OpenAI-compatible memory embedding provider ids from #81170.
Fixes #47884.
Fixes #49524.
Refs #56532.

Co-authored-by: adone0 <vladyslav.yavorskyi@outlook.com>
2026-05-31 10:21:17 +01:00
Gio Della-Libera
2d3fa4832f feat(doctor): expose UI freshness health findings
Expose UI freshness doctor findings through the structured health contribution path so lint JSON and dry-run repair output include stale UI asset guidance.

Keep legacy positional repair filtering stable while excluding health checks that already own their structured repair output. Maintainer fixups also avoid stale UI warnings when git history cannot prove changed sources, and make the foreground timeout regression test deterministic.

Verification:
- Local: `git diff --check origin/main...HEAD`
- Local: `node_modules/.bin/oxfmt --check --threads=1 src/agents/bash-tools.exec-foreground-failures.test.ts src/commands/doctor-ui.test.ts src/commands/doctor-ui.ts src/flows/doctor-core-checks.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-health-contributions.ts src/flows/doctor-health-conversion-plan.ts`
- Local: `node_modules/.bin/oxlint --tsconfig config/tsconfig/oxlint.core.json src/agents/bash-tools.exec-foreground-failures.test.ts src/commands/doctor-ui.test.ts src/commands/doctor-ui.ts src/flows/doctor-core-checks.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-health-contributions.ts src/flows/doctor-health-conversion-plan.ts`
- Local: `node scripts/run-vitest.mjs src/commands/doctor-ui.test.ts src/flows/doctor-health-contributions.test.ts src/commands/doctor-lint.test.ts src/agents/bash-tools.exec-foreground-failures.test.ts --reporter=dot --pool=forks --testTimeout=30000 --hookTimeout=30000`
- Local: `GOMAXPROCS=4 node scripts/run-tsgo.mjs -p tsconfig.core.json --noEmit --incremental false --pretty false`
- Local: `GOMAXPROCS=4 node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --noEmit --incremental false --pretty false`
- Local: `GOMAXPROCS=4 node scripts/run-tsgo.mjs -p tsconfig.extensions.json --noEmit --incremental false --pretty false`
- Autoreview: `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub Actions: CI `26708647282`, Real behavior proof `26708646476`, CodeQL `26708647258`, CodeQL Critical Quality `26708647230`, OpenGrep PR Diff `26708647214`, Workflow Sanity `26708647232`, Dependency Guard `26708646489`, ClawSweeper Dispatch `26708646475`, Labeler `26708646480`

Co-authored-by: Gio Della-Libera <giodl73@gmail.com>
2026-05-31 10:20:12 +01:00
Peter Steinberger
7606e1dd3d docs: expand MCP operator guide 2026-05-31 10:12:44 +01:00
github-actions[bot]
ef7854abbc chore(ui): refresh fa control ui locale 2026-05-31 09:12:28 +00:00
github-actions[bot]
53e063962d chore(ui): refresh nl control ui locale 2026-05-31 09:12:16 +00:00
github-actions[bot]
cef86c1748 chore(ui): refresh vi control ui locale 2026-05-31 09:11:52 +00:00
github-actions[bot]
ee39aa84b2 chore(ui): refresh pl control ui locale 2026-05-31 09:11:49 +00:00
github-actions[bot]
e93e2a0f18 chore(ui): refresh th control ui locale 2026-05-31 09:11:42 +00:00
github-actions[bot]
fce45a2178 chore(ui): refresh id control ui locale 2026-05-31 09:11:33 +00:00
github-actions[bot]
2a58d92655 chore(ui): refresh uk control ui locale 2026-05-31 09:10:59 +00:00
github-actions[bot]
b335018c3c chore(ui): refresh tr control ui locale 2026-05-31 09:10:54 +00:00
github-actions[bot]
80294a4f6b chore(ui): refresh ar control ui locale 2026-05-31 09:10:48 +00:00
github-actions[bot]
20ab73e7d4 chore(ui): refresh it control ui locale 2026-05-31 09:10:43 +00:00
github-actions[bot]
a041e393c1 chore(ui): refresh fr control ui locale 2026-05-31 09:10:15 +00:00
github-actions[bot]
2e0d191725 chore(ui): refresh ko control ui locale 2026-05-31 09:10:13 +00:00
github-actions[bot]
ec949a856e chore(ui): refresh ja-JP control ui locale 2026-05-31 09:10:03 +00:00
github-actions[bot]
0b9193c0b7 chore(ui): refresh es control ui locale 2026-05-31 09:09:55 +00:00
github-actions[bot]
aa56f592bb chore(ui): refresh pt-BR control ui locale 2026-05-31 09:09:24 +00:00
github-actions[bot]
10b4057c36 chore(ui): refresh zh-TW control ui locale 2026-05-31 09:09:22 +00:00
github-actions[bot]
ecef6ae626 chore(ui): refresh zh-CN control ui locale 2026-05-31 09:09:18 +00:00
github-actions[bot]
f456114b12 chore(ui): refresh de control ui locale 2026-05-31 09:09:13 +00:00
Peter Steinberger
617c658498 feat: improve MCP operator controls (#88536)
* feat: improve MCP operator controls

* test: stabilize draft stream loop background errors

* fix: prune empty MCP server enablement stubs

* fix: ignore disabled MCP overrides in doctor

* fix: keep MCP doctor saved-config warnings

* fix: redact malformed MCP URLs in UI

* fix: harden MCP UI command actions

* fix: allow MCP logout after auth removal
2026-05-31 10:06:55 +01:00
Peter Steinberger
3258338ec8 chore(lint): clean sms lint fallout 2026-05-31 10:04:48 +01:00
Peter Steinberger
3a4943ef87 fix(ci): repair sms channel checks 2026-05-31 05:02:18 -04:00
Vincent Koc
84b025eb62 fix(e2e): make plugin sweep wrappers executable 2026-05-31 10:42:50 +02:00
Jason O'Neal
a776de25e8 fix(auto-reply): redact secrets in config show output (#88496)
* fix(auto-reply): redact config show secrets

* fix(auto-reply): use schema redaction for config show

* fix(auto-reply): redact config set acknowledgements

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 09:36:24 +01:00
Peter Steinberger
b4aaca3365 fix(ci): repair copilot sdk drift 2026-05-31 04:34:54 -04:00
Peter Steinberger
f5eca3f84c chore(lint): enable object and reassignment rules 2026-05-31 09:32:52 +01:00
Peter Steinberger
ea11b8ad3d docs: expand SMS channel setup guide 2026-05-31 09:31:00 +01:00
Peter Steinberger
d4f78c9339 ci: harden Crabbox Testbox runs 2026-05-31 09:29:56 +01:00
Zee Zheng
15ae2deb30 fix(webchat): preserve refresh-visible history and composer state (#83992)
WebChat now stores/restores composer draft and queued sends across refresh, scoped by gateway/session/agent. It skips in-flight/steered sends, restores after agent scope hydration, waits for fresh idle session proof before draining restored sends, and backfills visible chat history when the raw tail contains silent/context entries.

Refs #83344

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
2026-05-31 09:23:58 +01:00
Vincent Koc
e6ce83487c fix(check): restore core typecheck 2026-05-31 10:23:33 +02:00
Peter Steinberger
3513e8bfd9 feat: add Twilio SMS channel
Add a bundled SMS channel backed by Twilio inbound webhooks and outbound text delivery.

Includes signed webhook validation, pairing/allowlist access, Messaging Service sender support, chunked plain-text SMS delivery, default target support, docs, config metadata, labeler updates, and focused SMS coverage.

Verification:
- pnpm exec tsgo -p extensions/sms/tsconfig.json --noEmit
- OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-sms-land-fix2 node scripts/run-vitest.mjs extensions/sms/src/phone.test.ts extensions/sms/src/accounts.test.ts extensions/sms/src/twilio.test.ts extensions/sms/src/inbound.test.ts extensions/sms/src/gateway.test.ts extensions/sms/src/channel.test.ts extensions/sms/src/send.test.ts extensions/sms/src/webhook.test.ts --reporter=verbose
- pnpm config:channels:check
- pnpm plugins:inventory:check
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
2026-05-31 09:22:31 +01:00
Andy Ye
0f1767a26a fix(telegram): support media message edits
Fixes #86161.

Route Telegram media-message edits through the Telegram caption/reply-markup APIs instead of always calling `editMessageText`. Button-only edits now update reply markup, explicit captions use `editMessageCaption`, and text edits can fall back to caption edits when Telegram reports the message has no editable text.

Also documents the edit behavior, adds regression coverage, tightens timer-spy cleanup for the affected agents test lane, and removes a stale loader helper from the current base that broke core typecheck.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-31 09:22:20 +01:00
Peter Steinberger
63a95930ca chore: remove stale unsafe assertion suppressions 2026-05-31 09:11:28 +01:00
Peter Steinberger
b81adc6202 fix(ci): keep unsafe assertion lint disabled 2026-05-31 04:09:48 -04:00
Peter Steinberger
0ac725278d Revert "fix(ci): annotate unsafe boundary casts"
This reverts commit 8a40f90f62.
2026-05-31 04:09:48 -04:00
Peter Steinberger
4471335d26 Revert "fix(ci): clean core unsafe assertions"
This reverts commit 88203c9b10.
2026-05-31 04:09:48 -04:00
Peter Steinberger
b78dd6a9ca test: remove channel test isolation hack
Remove isolate: true from the channel Vitest config and fix the leaking fake-timer/mock tests so the lane runs under the shared non-isolated runner. Verified with focused scoped-config/channel tests, the full channel Vitest config, git diff --check, and branch-mode autoreview.
2026-05-31 09:09:10 +01:00
Frank Yang
15c1511817 fix(agents): clear stale compaction bindings 2026-05-31 13:38:52 +05:30
Frank Yang
5e1e029d91 fix(agents): skip below-target CLI compaction failures 2026-05-31 13:38:52 +05:30
Peter Steinberger
48ccc50282 chore: update dependencies 2026-05-31 09:07:53 +01:00
Shakker
5a8bb1a7d2 docs: add Skill Workshop guide 2026-05-31 09:05:03 +01:00
Peter Steinberger
e1ad5f5170 docs: remove divider comments (#88115) 2026-05-31 09:03:18 +01:00
Peter Steinberger
88203c9b10 fix(ci): clean core unsafe assertions 2026-05-31 03:58:58 -04:00
Steven
b48c72cd19 fix(discord): deliver same-session channel replies
Deliver same-session channel replies directly while preserving stale-reply guards.

The fix bypasses the announce decider only when the requester and target are the same source channel, carries reply baselines into fire-and-forget follow-up delivery, and keeps history reads best-effort so timeout-zero sends still dispatch. It also includes focused regression coverage for delayed same-session replies, stale snapshots, retry timer caps, and the current strict-null/package-boundary blockers fixed while preparing the PR.
2026-05-31 08:52:01 +01:00
Peter Steinberger
8a40f90f62 fix(ci): annotate unsafe boundary casts 2026-05-31 03:51:18 -04:00
Peter Steinberger
ae651e7210 docs: add permission modes page 2026-05-31 08:47:02 +01:00
Peter Steinberger
4d95ae39d4 fix(ci): repair extension type drift 2026-05-31 03:40:32 -04:00
Peter Steinberger
e6782254e4 perf: avoid blocking gateway bind on control ui build 2026-05-31 08:36:30 +01:00
Peter Steinberger
59694e86d9 chore(lint): enable structured clone rules 2026-05-31 08:34:28 +01:00
Ayaan Zaidi
87664ed096 Fix iMessage startup watch replay (#88406)
* fix(imessage): start watch after existing local rows

* test(imessage): cover stale startup watch rows

* fix(imessage): keep watch startup tolerant of db probes

* fix(imessage): watermark default local watch startup

* fix(imessage): tolerate missing sqlite startup probe

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 08:33:22 +01:00
Peter Steinberger
1fd9fe2b33 fix(ci): isolate timer-sensitive tests 2026-05-31 03:30:37 -04:00
Peter Steinberger
122ae5db9e perf: lazy-load agent reply payload formatter 2026-05-31 08:29:32 +01:00
Peter Steinberger
930b371a2f refactor(telegram): persist plugin state in sqlite
Move Telegram plugin-local state from JSON sidecars into plugin-state SQLite. Keep legacy JSON handling in startup and doctor migration plans, with runtime state now reading and writing SQLite directly. Stabilize the channel Vitest lane by cleaning up typing timers and isolating that lane.
2026-05-31 08:28:53 +01:00
Peter Steinberger
b9fe0894a6 chore(lint): enable additional cleanup rules 2026-05-31 08:16:11 +01:00
Peter Steinberger
444562b3de chore: remove stale dead code 2026-05-31 03:04:25 -04:00
Peter Steinberger
ce547bfd44 fix(ci): stabilize ui paste and telegram types 2026-05-31 02:56:46 -04:00
Peter Steinberger
d4d7fdbc59 fix(ci): satisfy strict nullish guards 2026-05-31 02:50:24 -04:00
mochiexists
096bd13962 build(OpenClawKit): make ElevenLabsKit optional behind Talk trait
Adds a default-enabled SwiftPM Talk trait for OpenClawKit so chat-only consumers can opt out with traits: [] and avoid resolving ElevenLabsKit. Default traits preserve existing talk/TTS API and bundled app behavior; macOS CI now verifies the trait-off dependency graph and build.

Verification:
- CI at 85f00ebc04 passed macos-swift and Real behavior proof.
- Local Swift 6.3.2: trait-off dependency graph omitted ElevenLabsKit; full swift build with default traits disabled built through OpenClawChatUI; default dependency graph still included ElevenLabsKit; trait-off OpenClawKit target build passed.
- merge-tree against latest origin/main 4eba3e5d7d was clean.
- Current main already fails plugin-SDK declaration gates in unrelated TS files; reproduced locally with node scripts/run-tsgo.mjs -p tsconfig.plugin-sdk.dts.json --declaration true.

Thanks @mochiexists.

Co-authored-by: mochiexists <259077624+mochiexists@users.noreply.github.com>
Co-authored-by: atlascodesai <76924051+atlascodesai@users.noreply.github.com>
2026-05-31 07:40:35 +01:00
Peter Steinberger
4eba3e5d7d chore(lint): enable more readability rules 2026-05-31 07:38:33 +01:00
Peter Steinberger
9c3cf35e08 fix(ci): stop channel timers holding vitest open 2026-05-31 02:33:48 -04:00
Peter Steinberger
deb7bc6539 chore(lint): enable readability lint rules 2026-05-31 07:17:57 +01:00
Peter Steinberger
0211a3aa9f fix(ci): restore main validation 2026-05-31 02:13:10 -04:00
Peter Steinberger
ade6e7769b perf: prewarm gateway runtime plugins 2026-05-31 07:09:42 +01:00
guanbear
f1cb9f2f6a fix(slack): keep DM thread turns out of active steering
Keep Slack direct-message sessions stable while tracking routed Slack thread ids on active reply operations. Different top-level Slack DM threads from the same sender no longer steer into or block each other, while ordinary same-thread follow-ups and non-Slack direct-message behavior keep their existing semantics.

Verification:
- `git diff --check origin/main...FETCH_HEAD`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main --output /tmp/pr85904-autoreview.txt --json-output /tmp/pr85904-autoreview.json`
- GitHub CI green for head `6703e166545bcb96c1a50de93a42446212cca9a7`, including Real behavior proof and auto-reply reply routing/dispatch shards.

Co-authored-by: guanbear <123guan@gmail.com>
2026-05-31 07:05:50 +01:00
Ted Li
667393be8f fix(commands): make /skill load workspace skills
Fixes #88056.

Reload workspace skill commands for `/skill <name>` when directive resolution supplied only an empty placeholder list, so the generic skill wrapper can invoke the same command-visible skills as direct slash commands.

Keep stale-message cutoff and empty-config channel suppression ahead of skill discovery and tool dispatch so suppressed `/skill` messages cannot trigger side-effecting skill tools.

Co-authored-by: Ted Li <tl2493@columbia.edu>
2026-05-31 07:04:59 +01:00
brokemac79
72c61bc123 fix(telegram): align DM topic session routing
Align Telegram proactive DM-topic outbound session routing with inbound reply routing.

The Telegram plugin now uses the chat-scoped DM-topic suffix for direct-topic outbound sessions, so cron/proactive sends and replies reuse the same session. Delivery metadata is kept as the numeric Telegram topic id so visible sends still target the correct private topic.

Refs #80212.
Thanks @brokemac79.

Verification:
- PR head d904115e4c
- GitHub CI/checks green on PR head; Real behavior proof passed; OpenGrep passed; CodeQL neutral/pass
- git diff --check origin/main...pr/88421 -- extensions/telegram/src/channel.ts extensions/telegram/src/session-route.test.ts
- git merge-tree $(git merge-base origin/main pr/88421) origin/main pr/88421
2026-05-31 06:54:51 +01:00
Peter Steinberger
b372af6b81 test: keep timeout clamp checks under one second 2026-05-31 06:51:35 +01:00
Peter Steinberger
04b68e8fa4 fix(shared): restore number coercion barrel 2026-05-31 06:51:34 +01:00
Peter Steinberger
9f99acf12d test: restore marketplace cleanup coverage 2026-05-31 06:51:34 +01:00
Peter Steinberger
23dac6c263 test: keep vitest cases under one second 2026-05-31 06:51:34 +01:00
Peter Steinberger
8a4679026c fix: clarify generated media reply prompts (#88458)
* fix: clarify generated media reply prompts

* fix: hide media compat aliases from message schema

* fix: hide message media url aliases

* test: refresh media prompt snapshots
2026-05-31 06:45:57 +01:00
Peter Steinberger
0303f3a8f0 fix(qa): clamp transport wait intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
bb680a845b fix(onboard): clamp gateway reachability polling 2026-05-31 01:37:46 -04:00
Peter Steinberger
5de0d873ed fix(qa): clamp gateway restart polling 2026-05-31 01:37:46 -04:00
Peter Steinberger
83597b7f95 fix(qa): clamp cron run poll intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
edd8aa2f4e fix(agents): clamp embedded run drain polling 2026-05-31 01:37:46 -04:00
Peter Steinberger
fab8d29d21 fix(feishu): clamp sequential queue timeouts 2026-05-31 01:37:46 -04:00
Peter Steinberger
7595d52e56 fix(auth): bound profile usage window expiries 2026-05-31 01:37:46 -04:00
Peter Steinberger
11c050d0d0 fix(agents): clamp session suspension TTLs 2026-05-31 01:37:46 -04:00
Peter Steinberger
764321d3d3 fix(channels): clamp draft stream throttles 2026-05-31 01:37:46 -04:00
Peter Steinberger
54a27f4e57 fix(gateway): clamp auth limiter durations 2026-05-31 01:37:46 -04:00
Peter Steinberger
84061c1f8e fix(memory): clamp batch timeout minutes 2026-05-31 01:37:46 -04:00
Peter Steinberger
5c38c0c76d fix(memory): clamp sync interval timers 2026-05-31 01:37:46 -04:00
Peter Steinberger
db94eac5c0 fix(auto-reply): clamp typing timers 2026-05-31 01:37:46 -04:00
Peter Steinberger
92f1d90e0f fix(channels): clamp typing timers 2026-05-31 01:37:46 -04:00
Peter Steinberger
a1d7a7536a fix(gateway): clamp auth limiter prune intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
287f531de6 fix(sqlite): clamp WAL checkpoint intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
d06e1b2c71 fix(gateway): bound health monitor intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
5b0036ffde fix(nostr): bound seen tracker capacity 2026-05-31 01:37:46 -04:00
Peter Steinberger
dca53afd53 fix(openai): convert realtime secret expiry 2026-05-31 01:37:46 -04:00
Peter Steinberger
604339ebf9 fix(clickclack): normalize reconnect intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
74c5548c0d fix(github-copilot): chunk device polling waits 2026-05-31 01:37:46 -04:00
Peter Steinberger
33c44626d2 fix(memory): bound embedding batch poll intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
68b5371fca fix(discord): bound transport activity timestamps 2026-05-31 01:37:46 -04:00
Peter Steinberger
9417b9cea8 fix(discord): bound ACP activity timestamps 2026-05-31 01:37:46 -04:00
Peter Steinberger
0c97922e23 fix(codex): bound synthesized hook start times 2026-05-31 01:37:46 -04:00
Peter Steinberger
2bdb2e8e02 fix(gateway-client): clamp readiness intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
984951f55c fix(gateway-client): clamp tick watchdog intervals 2026-05-31 01:37:46 -04:00
Peter Steinberger
59f96078b2 fix(sessions): bound lifecycle timestamps 2026-05-31 01:37:45 -04:00
Peter Steinberger
f0c0181b10 fix(sandbox): prune invalid registry timestamps 2026-05-31 01:37:45 -04:00
Peter Steinberger
84dec338e7 fix(sandbox): bound fs bridge mtimes 2026-05-31 01:37:45 -04:00
Peter Steinberger
66a4410095 fix(memory): bound session export timestamps 2026-05-31 01:37:45 -04:00
Peter Steinberger
b26f89213e fix(usage): bound minimax usage epochs 2026-05-31 01:37:45 -04:00
Peter Steinberger
ae4ddece91 fix(agents): bound model scan created timestamps 2026-05-31 01:37:45 -04:00
Peter Steinberger
9161db534e fix(zalouser): bound inbound timestamp normalization 2026-05-31 01:37:45 -04:00
Peter Steinberger
cae98c1daf fix(gateway): centralize plugin approval timeout bounds 2026-05-31 01:37:45 -04:00
Peter Steinberger
3d0dc15904 fix(codex): bound native hook cleanup grace 2026-05-31 01:37:45 -04:00
Peter Steinberger
f71df664c9 fix(synology-chat): bound rate limit windows 2026-05-31 01:37:45 -04:00
Peter Steinberger
4ca218246e fix(diffs): cap artifact ttl normalization 2026-05-31 01:37:45 -04:00
Peter Steinberger
11b5968534 fix(channels): bound thread binding lifecycle durations 2026-05-31 01:37:45 -04:00
Peter Steinberger
5e139e32dc fix(agents): centralize subagent timeout math 2026-05-31 01:37:45 -04:00
Peter Steinberger
620acafb15 fix(browser): bound tab cleanup timer config 2026-05-31 01:37:45 -04:00
Peter Steinberger
8247f824b9 fix(google-meet): bound timer config values 2026-05-31 01:37:45 -04:00
Peter Steinberger
c767b37e3b fix(discord): bound identify limiter clock skew 2026-05-31 01:37:45 -04:00
Peter Steinberger
21478cab93 fix(agents): clamp abortable sleep helper 2026-05-31 01:37:45 -04:00
Peter Steinberger
dbddf4093f fix(utils): clamp shared sleep timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
1cf264c468 fix(infra): clamp abortable sleep timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
9d866d8b2a fix(cli): clamp port wait timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
0e3cc2e5ad fix(cli): clamp cron wait poll timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
1670b970ee fix(gateway): clamp lock poll timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
37fbc8cd8f fix(memory): clamp remote batch timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
7eeea30d8c fix(minimax): clamp oauth poll interval 2026-05-31 01:37:45 -04:00
Peter Steinberger
cdab5fc16a fix(infra): clamp provider usage timeout 2026-05-31 01:37:45 -04:00
Peter Steinberger
aa42905354 fix(agents): clamp idle flush timeout 2026-05-31 01:37:45 -04:00
Peter Steinberger
fbee4d56c4 fix(web): clamp shared tool timeout 2026-05-31 01:37:45 -04:00
Peter Steinberger
ed59533574 fix(feishu): clamp abortable delay timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
1f92a3e351 fix(mattermost): clamp probe timeout 2026-05-31 01:37:45 -04:00
Peter Steinberger
ac4ebc053a fix(cli): clamp progress delay timers 2026-05-31 01:37:45 -04:00
Peter Steinberger
9b2146775f fix(browser): clamp client action timeouts 2026-05-31 01:37:45 -04:00
Peter Steinberger
bc38a929aa fix(plugins): clamp hook timeouts 2026-05-31 01:37:44 -04:00
Peter Steinberger
8e12c6ea1f fix(plugin-sdk): clamp oauth callback timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
65167c9637 fix(tlon): clamp sse reconnect delays 2026-05-31 01:37:44 -04:00
Peter Steinberger
87eae7f811 fix(memory): clamp lancedb recall timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
b4e331fe81 fix(health): clamp probe timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
c8d458d13d fix(outbound): clamp message gateway timeouts 2026-05-31 01:37:44 -04:00
Peter Steinberger
2cbfb910f2 fix(commands): clamp gateway agent timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
1c1f42a74a fix(secrets): clamp provider timeouts 2026-05-31 01:37:44 -04:00
Peter Steinberger
3734ed6402 fix(agents): clamp compaction worker timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
5e11c85c0a fix(codex): clamp app-server timer config 2026-05-31 01:37:44 -04:00
Peter Steinberger
4135771adf fix(codex): clamp app-server watch timers 2026-05-31 01:37:44 -04:00
Peter Steinberger
58db38e088 fix(voice-call): clamp telephony tts timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
e500f401ea fix(voice-call): clamp pre-start stream timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
1ff52b2786 fix(voice-call): clamp continue poll timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
2b3f09659c fix(qa): clamp cli child timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
0d391bacf7 fix(qa): clamp bus wait timers 2026-05-31 01:37:44 -04:00
Peter Steinberger
85c8e7f89f fix(qa): clamp browser runtime timeouts 2026-05-31 01:37:44 -04:00
Peter Steinberger
1987d364b5 fix(qa): clamp web runtime timeouts 2026-05-31 01:37:44 -04:00
Peter Steinberger
971cb2d4bd fix(discord): clamp rest scheduler delay 2026-05-31 01:37:44 -04:00
Peter Steinberger
c66b21662d fix(discord): clamp rest request timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
6e318684c1 fix(discord): clamp component wait timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
89022023a3 fix(talk): clamp forced consult delay 2026-05-31 01:37:44 -04:00
Peter Steinberger
10e8426aa5 fix(hooks): clamp fire-and-forget timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
79d3083eb6 fix(agents): clamp catalog browse timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
95e2427189 fix(provider): clamp poll wait timers 2026-05-31 01:37:44 -04:00
Peter Steinberger
29a67f4d11 fix(media): clamp saved response idle timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
2d2ab6d480 fix(media): clamp response idle timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
cb79864cb9 fix(tts): clamp summarization timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
0530596eef fix(codex): clamp turn collector timeout 2026-05-31 01:37:44 -04:00
Peter Steinberger
417022864b fix(codex): clamp media turn timeout 2026-05-31 01:37:43 -04:00
Peter Steinberger
2833d4b347 fix(agents): clamp embedded run wait timers 2026-05-31 01:37:43 -04:00
Peter Steinberger
490a155f15 fix(auto-reply): clamp reply idle wait timers 2026-05-31 01:37:43 -04:00
Peter Steinberger
5f7217db2c fix(gateway): bound exec approval timers 2026-05-31 01:37:43 -04:00
Peter Steinberger
de1c4f8aec fix(infra): clamp restart deferral poll 2026-05-31 01:37:43 -04:00
Peter Steinberger
3a31b34151 fix(infra): clamp heartbeat wake delay 2026-05-31 01:37:43 -04:00
Peter Steinberger
8ef5b5ddba fix(auto-reply): bound session lifecycle expiries 2026-05-31 01:37:43 -04:00
Peter Steinberger
0adf3220b8 fix(auto-reply): bound auth label expiries 2026-05-31 01:37:43 -04:00
Peter Steinberger
edb2c498d5 fix(auth): bound profile unusable windows 2026-05-31 01:37:43 -04:00
Peter Steinberger
00831cf8ff fix(gateway): bound model auth expiry rollups 2026-05-31 01:37:43 -04:00
Peter Steinberger
b0ca5d7407 fix(auth): adopt main oauth over invalid local expiry 2026-05-31 01:37:43 -04:00
Peter Steinberger
c9311ef0a9 fix(auth): bound stored oauth replacement expiry 2026-05-31 01:37:43 -04:00
Peter Steinberger
1a4d2f7cca fix(auth): bound inherited oauth expiry 2026-05-31 01:37:43 -04:00
Peter Steinberger
9d31cbbd6a refactor(cron): split service timer helpers
Split cron timer helper concerns into focused service modules for agent watchdog cleanup, execution error text, failure alerts, task-run ledger handling, and wake dispatch.

Verification: focused cron Vitest, oxfmt check, git diff check, autoreview clean, and GitHub PR checks green.
2026-05-31 06:31:27 +01:00
Peter Steinberger
bbc4bee7a2 fix(heartbeat): advance stale scheduler deferrals
Fix stale heartbeat scheduler deferrals so disabled/non-retry skips and flood deferrals advance the due slot instead of rearming a 0 ms timer loop.

Fixes #79380.
Supersedes #79418.

Proof:
- pnpm test src/infra/heartbeat-runner.scheduler.test.ts -- --reporter=verbose
- pnpm check:changed via Testbox tbx_01ksxfavykc7qyve4ysnxg3smh
- autoreview clean
- GitHub CI green for 213003a854, including Real behavior proof
2026-05-31 06:26:44 +01:00
Vincent Koc
ef9e9bf6b9 fix(build): preserve fresh startup metadata across rebuilds 2026-05-31 07:16:13 +02:00
Peter Steinberger
51dee73a5d perf: cache log timestamp formatters 2026-05-31 06:09:22 +01:00
Peter Steinberger
b858d418aa fix(ui): localize tool error card label 2026-05-31 06:04:55 +01:00
Vincent Koc
e1a9817141 fix(e2e): preflight openai chat tools auth 2026-05-31 05:20:33 +02:00
Peter Steinberger
4dad7bd93b fix(release): tolerate npm README metadata lag 2026-05-31 02:49:06 +01:00
Vincent Koc
26913e60a4 fix(codex): preserve public OpenAI app-server provider 2026-05-31 03:39:03 +02:00
Shakker
5c5711f061 fix: keep tool card actions inline 2026-05-31 02:11:53 +01:00
Shakker
1e3542bbe7 fix: label collapsed tool cards by tool 2026-05-31 02:07:52 +01:00
Shakker
9a00d74044 fix: share skill workshop prompt with codex 2026-05-31 01:53:01 +01:00
Shakker
e9d01320d7 fix: isolate dev source plugin aliases 2026-05-31 01:47:11 +01:00
Shakker
ae800e160d fix: prefer source plugins in dev runs 2026-05-31 01:47:11 +01:00
Peter Steinberger
e086bfeb91 chore(release): refresh plugin sdk api baseline 2026-05-31 01:45:54 +01:00
Peter Steinberger
dd72b104ac fix(qa): use auth credential type for OpenAI live model selection 2026-05-31 01:39:36 +01:00
NianJiu
199a1b9014 fix(webchat): fetch full sidebar content for truncated history
Add a bounded `chat.message.get` gateway method so Control UI can fetch one display-normalized transcript message by id when an assistant history preview was truncated. Keep `chat.history` lightweight, reject oversized/hidden/missing rows with explicit unavailable reasons, and wire the WebChat side reader to request full content only for visible truncated assistant messages.

Also refresh the generated Swift gateway protocol models and document the new assistant-message side-reader behavior.

Closes #84651.
Related #53242.

Co-authored-by: NianJiuZst <3235467914@qq.com>
2026-05-31 01:33:52 +01:00
Peter Steinberger
00d8d7ead0 refactor: extract normalization core package
Extract shared normalization/coercion helpers into private @openclaw/normalization-core workspace package while preserving existing plugin SDK helper subpaths.\n\nAlso keeps direct normalization-core imports internal, wires UI/build/loader resolution, and replaces the slow PR network CodeQL lane with a fast added-line boundary scan while retaining full CodeQL for scheduled/manual runs.\n\nVerification: local moved tests, plugin SDK boundary tests, extension loader tests, agents-support shard, UI build/test, build artifacts, lint, workflow guards, autoreview, and GitHub CI passed on PR head 963d893715.
2026-05-31 01:33:00 +01:00
Peter Steinberger
94814f3516 fix(qa): restore OpenAI OAuth release contracts 2026-05-31 01:25:48 +01:00
Peter Steinberger
9caefeaf08 fix(ui): satisfy vite alias lint guard 2026-05-31 01:08:42 +01:00
Peter Steinberger
16bae70af4 fix(release): align prerelease contracts after provider rename 2026-05-31 00:52:22 +01:00
Vincent Koc
6270d5326f fix(e2e): prove gateway health after websocket connect 2026-05-31 01:39:28 +02:00
Shakker
6561bdc41d fix: resolve root aliases in ui dev 2026-05-31 00:36:02 +01:00
Shakker
54d42c7c9a fix: vertically center tool summary labels 2026-05-31 00:36:01 +01:00
Peter Steinberger
ab35dcd333 fix(release): repair 2026.5.30 beta prerelease gates 2026-05-31 00:32:02 +01:00
Peter Steinberger
4c33aaa86c refactor: unify OpenAI provider identity (#88451)
* refactor: unify OpenAI provider identity

* refactor: move legacy oauth sidecar doctor helpers

* test: align OpenAI fixtures after rebase

* test: clean OpenAI provider unification

* fix: finish OpenAI provider cleanup

* fix: finish OpenAI cleanup follow-through

* fix: finish OpenAI CI cleanup
2026-05-31 00:29:44 +01:00
Peter Steinberger
8d6a6e9d03 feat: move workboard to relational sqlite
Move Workboard durable data into a relational SQLite database and add extension doctor migration for .28 plugin-state rows. Preserve attachment lifecycle behavior, SQLite permissions/WAL settings, and scoped plugin migration access.
2026-05-31 00:02:23 +01:00
Vincent Koc
7fc02d36b3 fix(scripts): assert lifecycle inspect output 2026-05-31 01:00:58 +02:00
scotthuang
7920af0c9e refactor: route browser screenshot vision through shared media understanding
* feat(browser): add optional vision understanding to screenshot tool

* fix(browser): wrap vision output as external content, enforce maxBytes, forward auth profiles

* fix(browser): remove no-op scope/attachments config, drop profile pass-through lacking runtime support

* feat(media-understanding): add profile/preferredProfile to DescribeImageFileWithModelParams and forward to describeImage

* style(browser): add curly braces to satisfy eslint curly rule

* fix(browser): correct tools.browser.enabled help text to match actual behavior

* fix(browser): thread agentDir/workspaceDir from plugin tool context into browser vision

* refactor(browser): move vision config from tools.browser to browser.models

The browser plugin's vision configuration now lives on the top-level
`browser` config namespace (browser.models, browser.visionEnabled,
browser.visionPrompt, etc.) instead of `tools.browser`. This aligns
with the plugin's existing config location and avoids confusion between
tool-level and plugin-level settings.

- Remove tools.browser from ToolsSchema and ToolsConfig
- Add models/vision* fields to BrowserConfig and its zod schema
- Update getBrowserVisionConfig to read from cfg.browser
- Update schema help, labels, and quality test
- Update vision.test.ts to use new config shape

* docs(browser): add screenshot vision configuration section

Document the new browser.models config for automatic screenshot
description via vision models, enabling text-only main models to
reason about web page content.

* fix(browser): remove deliverable media markers from vision result, drop unused import

P1: Vision-success path no longer exposes the raw screenshot as
deliverable media (removes MEDIA: line and details.media.mediaUrl).
This prevents channel delivery from auto-sending sensitive page content
when the intended output is a text description.

P2: Remove unused ToolsMediaUnderstandingSchema import that would fail
noUnusedLocals typecheck.

* fix(browser): add command/args fields to browser models schema

The browser vision model schema uses .strict(), so CLI-type entries
with command/args were rejected by TypeScript. Add these fields to
align with MediaUnderstandingModelSchema.

* chore(browser): remove debug console.log statements

* fix(browser): harden screenshot vision result against MEDIA: directive injection and restore image sanitization on failure fallback

ClawSweeper #84247 review round 2:

P1 (security, high): neutralize line-start MEDIA: directives in vision descriptions
before wrapping with wrapExternalContent. The agent media extractor scans every
browser tool-result text block via splitMediaFromOutput which treats line-start
MEDIA: as a trusted local-media delivery directive, and browser is on the
trusted-media allowlist. Without neutralization, page or vision-provider output
containing 'MEDIA:/tmp/secret.png' could synthesize a channel-deliverable media
artifact from untrusted content. wrapExternalContent itself does not strip
line-start directives. Introduce neutralizeMediaDirectives in vision.ts that
prepends '[neutralized] ' to any line whose trimStart() begins with MEDIA:
(case-insensitive), defanging the parser anchor while keeping the original
text human-readable.

P2 (compatibility): pass resolveRuntimeImageSanitization() to imageResultFromFile
in the vision-failure catch fallback. The non-vision screenshot path already
forwards this option (d5cc0d53b7) so configured agents.defaults.imageMaxDimensionPx
takes effect. Without this fix, any provider timeout/error silently bypasses the
sanitization guard and returns a raw full-resolution screenshot.

Regression coverage:
- vision.test.ts: 6 unit cases for neutralizeMediaDirectives (no-op fast path,
  mid-line MEDIA: untouched, line-start defanged, leading-whitespace defanged,
  case-insensitive, multiple directives per blob).
- browser-tool.test.ts: 2 integration cases that drive the full screenshot
  tool execute path:
    - 'neutralizes MEDIA: directives in vision text and does not attach media'
      asserts no line matches /^\s*MEDIA:/i in returned text, secret path text
      is preserved verbatim, details.media is absent, and imageResultFromFile
      is not called on the success path.
    - 'preserves screenshot image sanitization on vision failure fallback'
      mocks describeImageFileWithModel to reject and asserts the fallback
      imageResultFromFile call receives imageSanitization: {maxDimensionPx:1600}
      plus the 'browser screenshot vision failed' extraText.

* fix(browser): apply clawsweeper fallback media fix from PR #84247

* refactor: reuse media image understanding for browser screenshots

* refactor: use structured media delivery

* test: update music completion media instruction expectation

* fix: trim buffered reply directive padding

* test: refresh codex prompt snapshots for message media aliases

---------

Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-31 00:00:19 +01:00
Peter Steinberger
3e7f74505c fix(release): harden beta doctor and RTT credential deadlines 2026-05-30 23:54:06 +01:00
Peter Steinberger
38d3d11cbc feat: improve MCP operator workflows
Add MCP server add/configure/login/reload flows plus config/runtime support for enablement, filters, timeouts, OAuth, TLS, and parallel execution hints. Update docs and tests for the expanded MCP operator surface.
2026-05-30 23:51:40 +01:00
Zee Zheng
8be581cbf8 fix(browser): allow inbound media uploads
Allow the browser upload tool to resolve OpenClaw-managed inbound media refs such as `media://inbound/<id>` and sandbox-relative `media/inbound/<id>` while preserving the existing upload-root path contract.

Keep upload-root files ahead of sandbox-relative inbound fallback, reject nested absolute inbound media files, and validate raw `media://` paths before URL normalization so traversal-shaped refs cannot resolve to direct media ids.

Verification:
- `OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/browser/src/browser/paths.test.ts --reporter=verbose`
- `OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/browser/src/browser/paths.test.ts --reporter=dot`
- `OPENCLAW_HEAVY_CHECK_LOCK_SCOPE=worktree node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `pnpm lint --threads=8`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `git diff --check`
- GitHub PR checks on be08e6c8a8: dependency-guard, check-lint, check-test-types, check-additional-extension-bundled, checks-fast-contracts-plugins-a, checks-fast-contracts-plugins-b all passed.

Fixes #83544.

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-30 23:49:07 +01:00
Peter Steinberger
d05e4a4bc6 fix(feishu): use full gateway channel runtime 2026-05-30 23:46:04 +01:00
Vincent Koc
0b0edcdf1c fix(scripts): fail gauntlet on missing qa summaries 2026-05-31 00:37:48 +02:00
Peter Steinberger
57c88dd46e chore: remove more unused internal helpers 2026-05-30 23:26:29 +01:00
Peter Steinberger
654de643e4 perf: skip idle channel shutdown enumeration 2026-05-30 23:21:54 +01:00
Vincent Koc
ee2b90b4e2 perf(scripts): prebuild qa runtime assets 2026-05-31 00:17:39 +02:00
Jerry-Xin
f59fc0d477 fix(gateway): strip spurious tool calls on non-tool stops
Treat OpenAI-compatible streaming tool deltas as executable only when the final finish reason is `tool_calls`. This prevents malformed provider streams from triggering spurious tool execution while preserving normal tool-call responses.

Fixes #85161.

Verification:
- Local OpenAI-compatible SSE replay: spurious stop stream `finalToolCalls: 0`; valid tool-call stream `finalToolCalls: 1`.
- `pnpm test src/agents/openai-transport-stream.test.ts src/llm/providers/openai-completions.test.ts -- --reporter=verbose`
- PR CI green on `cdc2fc34753492c862cae99b37f8cf3761d9bbed`.

Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
2026-05-30 23:14:16 +01:00
Ted Li
1cab722fe0 fix(ci): ignore fenced headings in proof parser (#87390)
Harden real behavior proof parsing for fenced transcript Markdown. Ref #87341. Thanks @MonkeyLeeT.
2026-05-30 23:14:06 +01:00
Peter Steinberger
4739f0cfe2 chore: remove old unused helpers 2026-05-30 23:13:43 +01:00
Andy Ye
2442e9c178 fix(cron): preserve plugin delivery targets
Preserve plugin-resolved cron delivery targets after target resolution so provider-looking canonical target prefixes are not stripped before outbound delivery.

Adds regression coverage for plugin canonical targets returned directly and via aliases, plus a guard that generic normalized fallback targets still strip the selected prefix.

Fixes #87905

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-30 23:12:45 +01:00
Peter Steinberger
0ac61072b8 Refactor cron migrations under doctor (#88455)
* refactor: move cron migrations under doctor

* fix: break cron run log parser type cycle
2026-05-30 23:09:09 +01:00
Peter Steinberger
31099ccb1f docs(changelog): refresh 2026.5.30 notes 2026-05-30 23:04:23 +01:00
Peter Steinberger
2d23519c77 fix(agents): preserve generated media fallback routing 2026-05-30 23:03:32 +01:00
Peter Steinberger
bbd2854c45 fix: show chat errors as visible messages
Surface gateway chat failures as visible assistant messages in the Control UI, with regression coverage and Crabbox/WebVNC proof.

(cherry picked from commit 31a46638ad)
2026-05-30 23:03:32 +01:00
Josh Avant
5d3a6909fb fix subagent dm completion delivery (#88182)
(cherry picked from commit 00d87c7b5d)
2026-05-30 23:03:32 +01:00
Peter Steinberger
1e0c9d8174 test(wizard): include tokenjuice optional plugin
(cherry picked from commit dd658474a5)
2026-05-30 23:03:32 +01:00
Peter Steinberger
4c16bd2453 fix(codex-supervisor): satisfy release lint
(cherry picked from commit bac13419a6)
2026-05-30 23:03:32 +01:00
Steven
cd3d960ec5 fix(ui): add agent selector to dreaming tab (#78748)
Fixes #63558.

Adds a Dreaming-tab agent selector and propagates the selected agent through Dreaming status, diary, and diary actions while preserving default-agent fallback when agentId is omitted. Also keeps report Memory Palace cards in the Control UI wiki-preview flow and documents the optional Dreaming agentId gateway parameters.

Verification:
- GitHub CI run 26693682975 passed on 43a2b17243.
- CodeQL Critical Quality run 26693682971 passed.
- CodeQL / Security High run 26693682957 passed.
- Workflow Sanity run 26693682949 passed.
- OpenGrep PR Diff run 26693682947 passed.
- Dependency Guard run 26693682003 passed.
- Real behavior proof run 26693860539 passed.
- git diff --check origin/main...refs/remotes/origin/pr/78748 passed.
- git merge-tree --write-tree origin/main refs/remotes/origin/pr/78748 passed.

Thanks @stevenepalmer.

Co-authored-by: Steven Palmer <6134396+stevenepalmer@users.noreply.github.com>
2026-05-30 22:58:00 +01:00
Peter Steinberger
d93394e29b perf: cache validated session prompt blobs 2026-05-30 22:57:30 +01:00
Peter Steinberger
83dff5855e docs: trim release performance report tail 2026-05-30 22:54:35 +01:00
Peter Steinberger
3402477314 chore: remove unused infra helpers 2026-05-30 22:45:22 +01:00
Peter Steinberger
71b3bc87ca perf: cache serialized session prompt refs 2026-05-30 22:44:11 +01:00
Peter Steinberger
0be3ef5a38 chore: remove unused agent helpers 2026-05-30 22:43:09 +01:00
Peter Steinberger
287687da20 feat: add internal code mode namespaces (#88043)
* feat: add internal code mode namespaces

* test: add code mode namespace live proof

* test: add live code mode Docker repro

* chore: keep code mode docker repro out of package scripts

* fix: break code mode namespace type cycle

* fix: clean code mode namespace ci drift

* fix: route code mode namespaces through tools

* fix: preserve explicit agent global sessions

* docs: explain code mode namespace registry

* test: cap realtime websocket payload

* fix: normalize code mode timeout results

* fix: satisfy code mode timeout lint

* chore: rerun code mode CI

* ci: extend node shard silence watchdog

* test: avoid child process mock deadlocks

* test: fix code mode repro shebang

* fix: scope explicit agent sentinel sessions

* test: preserve child process mock actual loader

* fix: dispatch namespace tools by exact id

* test: satisfy restart execFile mock type
2026-05-30 22:42:57 +01:00
Peter Steinberger
22e4289d3f chore(release): update appcast for 2026.5.28
Promote the Sparkle appcast generated by macOS publish for v2026.5.28.
2026-05-30 22:39:55 +01:00
Vincent Koc
5367ef7bd3 fix(scripts): accept forwarded otel smoke args 2026-05-30 23:37:27 +02:00
Peter Steinberger
598e177e12 chore: remove unused changelog helper 2026-05-30 22:36:09 +01:00
Peter Steinberger
0ed9fb48c4 docs: refresh release performance sweep for 2026.5.28 2026-05-30 22:35:45 +01:00
Jason (Json)
3ea911558c fix: promote serialized tool calls via repair package
Extracts serialized plaintext tool-call parsing, scrubbing, stream normalization, and standalone promotion into the private internal @openclaw/tool-call-repair package.

Provider wrappers and the embedded runner now share one repair path for standalone serialized tool calls, including adjacent text-block splits, while preserving exact argument bytes when already valid. The public plugin SDK payload module remains as the compatibility facade.

Verification:
- pnpm test src/plugin-sdk/provider-stream-shared.test.ts src/plugin-sdk/tool-payload.test.ts src/agents/embedded-agent-runner/run/attempt.tool-call-normalization.test.ts -- --reporter=verbose
- env -u OPENCLAW_TESTBOX pnpm check:changed
- PR CI: all reported checks green/skipped/neutral on ff0b3c0a5c

Refs #86924

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-30 22:34:57 +01:00
Yossi Eliaz
443255461c fix(slack): preserve assistant DM root thread context (#63840)
Preserve Slack Agents & Assistants DM root thread context for tool and subagent replies even when Slack omits or misreports `channel_type`, while leaving non-DM self-thread roots top-level.

Fixes #63659.

Thanks @zozo123.
2026-05-30 22:28:49 +01:00
Vincent Koc
7dde396d4d fix(scripts): accept forwarded watch regression args 2026-05-30 23:20:16 +02:00
Jason (Json)
89975eea24 feat: pass structured provider error signals to hooks
Summary:
- Pass provider status/code/type descriptors through failover hook classification.
- Keep structured provider hook dispatch scoped, while preserving legacy broad message-hook fallback for unresolved custom provider ids.
- Isolate long commands/infra Vitest lanes in fork workers and update config expectations.

Verification:
- node scripts/run-vitest.mjs src/agents/embedded-agent-helpers/errors-provider-structured-signals.test.ts src/agents/failover-error.test.ts
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/provider-runtime.test.ts
- node scripts/run-vitest.mjs src/agents/embedded-agent-helpers/errors-provider-structured-signals.test.ts src/agents/embedded-agent-helpers/provider-error-patterns.test.ts src/agents/failover-error.test.ts src/plugins/provider-runtime.test.ts test/vitest-projects-config.test.ts test/vitest-scoped-config.test.ts src/infra/vitest-config.test.ts
- pnpm tsgo:prod
- autoreview --mode branch --base origin/main --no-web-search --thinking low
- GitHub required dependency-guard: pass
- GitHub Real behavior proof: pass
- GitHub broad CI/checks visible on PR: pass

Co-authored-by: Jason (Json) <fuller-stack-dev@users.noreply.github.com>
2026-05-30 22:14:46 +01:00
zhang-guiping
dbd3e10312 fix(ui): filter sidebar recent sessions by selected agent
Fixes #88214.

Control UI dashboard Recent sessions now follows the selected agent, preserves legacy main sessions under stale identity, keeps unknown sessions unscoped, and scopes agent/default session refreshes before the session-list limit. Completed run refreshes now use the run's original session/agent target, global New Chat creates under the selected agent, and the agent switcher preserves last known target sessions across scoped refreshes without resurrecting deleted or archived sessions while accepting newer out-of-scope live rows into the switch cache. Also fixes a current-main lint issue around trusted approval params.

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
2026-05-30 22:13:37 +01:00
Vincent Koc
8b50cdd151 ci: update remaining Testbox actions 2026-05-30 22:11:51 +01:00
Peter Steinberger
a825b5576b refactor: simplify sqlite cron persistence 2026-05-30 22:11:17 +01:00
summerview1997
76b300babc Fix /acp spawn cwd inheritance for target agent workspaces (#82415)
* Fix ACP spawn cwd inheritance

* Share ACP spawn cwd guard with command path

* Fix ACP spawn cwd typing and temp dir test

* test: stabilize crabbox wrapper provider fixtures

---------

Co-authored-by: Thomas Yao <thomas@local>
2026-05-30 22:11:06 +01:00
Vincent Koc
ada22739be perf(build): skip dts for runtime build profiles 2026-05-30 23:06:25 +02:00
Peter Steinberger
8fe50a2136 build: classify release dependency ownership
Classify release dependency ownership metadata so release evidence no longer reports current root dependencies as missing ownership metadata. Also recognizes command-explainer package-file lookups for tree-sitter-bash.

Verification: jq empty scripts/lib/dependency-ownership.json; node scripts/dependency-ownership-surface-report.mjs --check; node scripts/root-dependency-ownership-audit.mjs --check; targeted Vitest for root dependency ownership and ownership surface reports; git diff --check; autoreview clean; PR CI green including Real behavior proof.
2026-05-30 22:04:54 +01:00
Peter Steinberger
b374505e7a refactor: source model catalog types from core
Source model catalog SDK types from @openclaw/model-catalog-core while preserving released compat fields and sanitized routing normalization.
2026-05-30 22:00:51 +01:00
zhang-guiping
653292901a fix(tui): surface terminal lifecycle errors
Surface terminal TUI lifecycle errors after the chat stream ends, deduplicate delayed chat errors, and allow explicit runnable Vitest config targets to run through the target planner.

Fixes #85782.

Verification:
- pnpm exec oxfmt --check src/tui/tui-event-handlers.ts src/tui/tui-event-handlers.test.ts test/scripts/test-projects.test.ts scripts/test-projects.test-support.mjs src/agents/model-catalog-visibility.test.ts
- node scripts/run-vitest.mjs src/tui/tui-event-handlers.test.ts
- node scripts/run-vitest.mjs src/tui/tui-event-handlers.test.ts src/tui/tui-command-handlers.test.ts test/scripts/test-projects.test.ts src/agents/model-catalog-visibility.test.ts
- git diff --check
- autoreview --mode local: no accepted/actionable findings
- autoreview --mode branch --base origin/main: no accepted/actionable findings
- Required CI check dependency-guard passed

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-30 21:59:27 +01:00
Peter Steinberger
3f50485156 perf: cache manifest model suppression resolver 2026-05-30 21:56:38 +01:00
Vincent Koc
9c2744f1e1 test(scripts): require usable memory search in fd repro 2026-05-30 22:48:50 +02:00
brokemac79
3aa460409e fix: route denied exec approval followups to sessions
Routes denied async exec approval followups through the originating main session before using direct external fallback. Keeps strict inline-eval timeout denials fail-closed, while preserving suppression for subagent, cron, and no-session denial cases.

Refs #88167.

Verification:
- git diff --check origin/main...refs/remotes/pr/88417
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- gh pr checks 88417 --repo openclaw/openclaw --watch=false

Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
2026-05-30 21:45:16 +01:00
Thomas Krohnfuß
48980a0f41 fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019) (#88067)
* fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019)

When an Azure/OpenAI Responses session falls back to a non-Responses model
and later resumes a Responses model, sanitizeSessionHistory drops the
replayable reasoning (rs_*) item via downgradeOpenAIReasoningBlocks. The
paired assistant text block still carried its textSignature (the msg_* id),
so the transport replayed an assistant message item referencing msg_* with
no accompanying rs_* reasoning item. Azure Responses then rejected the next
turn with:

  400 Item 'msg_...' provided without its required 'reasoning' item: 'rs_...'

permanently poisoning the session.

Fix:
- downgradeOpenAIReasoningBlocks now strips the textSignature from a turn's
  text blocks whenever it drops a replayable reasoning item, so the msg_* id
  and its rs_* reasoning are removed together. The transport then falls back
  to a synthetic, unpaired id that Azure accepts.
- Because the synthetic fallback id is derived from the per-message msgIndex,
  multiple id-less text blocks in one assistant turn (e.g. commentary +
  final_answer) would collide on the same id. Make the fallback unique per
  text block in both Responses conversion sites
  (openai-transport-stream.ts and the shared llm provider
  openai-responses-shared.ts).

Tests:
- sanitize-session-history: model-switch path drops the paired msg_* id.
- embedded-agent-helpers: downgrade strips paired text signature(s).
- reasoning-replay: multiple id-less text blocks get distinct item ids.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(responses): preserve phase metadata and guard malformed blocks (#88019)

Address PR review feedback on the orphaned msg_* replay fix:

- Preserve Responses phase metadata: dropping the paired msg_* id when its
  rs_* reasoning is removed previously stripped the entire textSignature,
  which also discarded the phase (commentary/final_answer). Phased text now
  keeps a phase-only signature ({v:1,phase}) so commentary is not replayed
  as user-visible output. Both parseTextSignature copies (shared provider and
  embedded transport) now accept id-less phase-only signatures and fall back
  to a synthetic id while preserving the phase.
- Guard malformed content blocks: the post-drop map no longer dereferences
  contentBlock.type unconditionally, so a corrupted transcript with a
  null/primitive block can still sanitize through a model switch.

Tests:
- sanitize-session-history: phase metadata is preserved while the paired id
  is dropped on a model switch.
- reasoning-replay: id-less phase-only signatures get distinct synthetic ids
  and retain their phase.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 21:45:08 +01:00
Ashd.LW.
eb170a0adb fix(agents): extend payload-less session lock grace
Payload-less session write-lock files now get a 30s grace for default/long acquire timeouts and cleanup sweeps, while short acquire timeouts keep 5s recovery. This avoids reclaiming a lock while the owner is suspended between exclusive create and metadata write.

Verified with:
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "node scripts/run-vitest.mjs src/agents/session-write-lock.test.ts"
- gh pr checks 80686 --repo openclaw/openclaw --watch=false

Thanks @wAngByg.
2026-05-30 21:42:57 +01:00
Han Kim
b7232db1b0 test(gateway): avoid brittle shutdown timer assertion
Co-authored-by: Han Kim <han.kim@Bowcaster.local>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-05-30 21:39:49 +01:00
Peter Steinberger
a20b2dc740 refactor: extract web content core package (#88346)
Extract web-content shared runtime helpers into packages/web-content-core, move the focused tests with the new package, and split quiet CI shards so the node matrix no longer stalls past the no-output watchdog.\n\nVerification: node scripts/run-vitest.mjs test/scripts/ci-node-test-plan.test.ts test/scripts/run-vitest.test.ts src/infra/restart.test.ts src/infra/os-summary.test.ts src/infra/gateway-processes.test.ts src/infra/inline-option-token.test.ts src/infra/map-size.test.ts src/infra/machine-name.test.ts src/commands/doctor-whatsapp-responsiveness.test.ts; autoreview clean; manual CI https://github.com/openclaw/openclaw/actions/runs/26693962844; dependency guard https://github.com/openclaw/openclaw/actions/runs/26693959937. Admin merge used because optional Mantis Telegram Desktop proof was cancelled after blocking merge outside this PR's required proof.
2026-05-30 21:38:29 +01:00
Feelw00
c6b1fede5a fix(mcp): bound channel bridge pending approvals
Bound MCP channel bridge pending Claude permission and approval maps with TTL sweep and close cleanup.
Also sweep before listing pending approvals so expired requests are not exposed between periodic ticks.

Fixes #71646.
Thanks @Feelw00.
2026-05-30 21:36:50 +01:00
Zee Zheng
c80ec43325 feat(cli): add sessions tail progress view
Adds `openclaw sessions tail` as an operator-facing progress view over session trajectory events, with conservative redaction for prompt text, tool arguments, and tool result bodies. The command supports explicit session keys, store/agent scope, follow mode, relocated trajectory pointer files, and cursor-safe follow across bounded trajectory window rewrites.

Documents the new sessions tail CLI surface in `docs/cli/sessions.md`.

Fixes #83441.

Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
2026-05-30 21:29:39 +01:00
Peter Steinberger
b6891d284d docs(changelog): restore 2026.5.28 release credits 2026-05-30 21:29:16 +01:00
Peter Steinberger
ec78a21e0b docs(changelog): require complete release credits 2026-05-30 21:28:11 +01:00
Peter Steinberger
be3af54f98 perf: fast path session store json parsing 2026-05-30 21:22:14 +01:00
Peter Steinberger
3fc0df953c refactor(agents): bind subagent threads in core (#88416)
Move subagent thread binding ownership into core so session-mode spawns prepare channel bindings before launching the child agent. Deprecate the legacy subagent_spawning SDK hook in code, compatibility metadata, diagnostics, and plugin docs; plugin authors should observe subagent_spawned instead.

Verification:
- node scripts/run-vitest.mjs src/agents/sessions-spawn-hooks.test.ts src/agents/subagent-spawn.thread-binding.test.ts src/agents/subagent-spawn.workspace.test.ts src/agents/subagent-spawn.mode-session-diagnostics.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- CI run 26693808952 green, including checks-node-agentic-agents-core and checks-node-agentic-plugin-sdk
2026-05-30 21:19:09 +01:00
Nicolas
4ac90a5b48 fix: skip browser cleanup when browser is disabled
Skip browser lifecycle cleanup when root browser support or the browser plugin entry is disabled, and make the browser maintenance facade respect activation before cached surface use.

Also stabilize the resource-only MCP runtime test by waiting for the async rejection log that CI can observe late.

Verification:
- pnpm test src/plugin-sdk/browser-maintenance.test.ts src/browser-lifecycle-cleanup.test.ts src/auto-reply/reply/session.test.ts src/gateway/server.sessions.reset-cleanup.test.ts src/agents/auth-profiles/usage.test.ts
- pnpm test src/agents/agent-bundle-mcp-runtime.test.ts
- git diff --check
- pnpm build
- autoreview local: no accepted/actionable findings
- GitHub Actions: CI 26693713166, CodeQL 26693713159, CodeQL Critical Quality 26693713157, OpenGrep PR Diff 26693713125, Workflow Sanity 26693713149, Dependency Guard 26693712478

Co-authored-by: Nicolas Van Eenaeme <nicolas@poison.be>
2026-05-30 21:16:47 +01:00
Peter Steinberger
39e987314a perf: skip unnecessary setup auth fallback 2026-05-30 21:16:36 +01:00
Peter Steinberger
427df01d4e ci(release): checkout approval helper 2026-05-30 21:13:19 +01:00
Peter Steinberger
50b7a2ffa1 ci(release): allow direct publish recovery 2026-05-30 21:13:19 +01:00
Vincent Koc
b93ed3f93f test(scripts): expose kitchen sink command RSS 2026-05-30 22:10:25 +02:00
Peter Steinberger
a2b2c4a76c refactor(msteams): persist conversation and poll stores in sqlite
Move MSTeams conversation and poll plugin-local stores to plugin-state SQLite. Legacy JSON stores import once without overwriting existing SQLite state; conversation and poll IDs are hashed for plugin-state keys; poll votes are sharded with bounded row-cap headroom and prune cleanup; MSTeams docs now describe SQLite storage. SSO and delegated token stores are unchanged. Verified with focused MSTeams tests, docs sanity, autoreview, Testbox check:changed, and green PR CI.
2026-05-30 21:08:39 +01:00
Feelw00
a9a86f788b fix(agents): dedupe subagent browser session cleanup
Deduplicate the browser lifecycle cleanup wrapper for embedded subagent completions while preserving retire and announce finalization for duplicate callers.\n\nAdds regression coverage for parallel completion callers and the held-first-cleanup duplicate-tail path.\n\nFixes #68668.\n\nCo-authored-by: Feelw00 <dhrtn1006@naver.com>
2026-05-30 21:04:37 +01:00
keshavbotagent
371a8abe9d fix(build): avoid stale agent-core dts warnings (#87915)
* fix(build): avoid stale agent-core dts warnings

* test(secrets): secure plugin entrypoint fixtures

* fix(agent-core): normalize compaction summary timestamps

* test(secrets): secure platform preset fixture

* fix(build): preserve tracked package dts on skip builds

* test(secrets): secure platform preset resolver fixture

* fix(build): keep declarations during skip dts clean

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 21:03:49 +01:00
Peter Steinberger
005da57957 Move cron persistence to SQLite (#88285)
* refactor: move cron persistence to sqlite

* fix: repair sqlite cron migration regressions

* fix: move cron legacy migration to doctor

* test: align cron sqlite migration fixtures

* test: fix cron sqlite rebase gates

* test: align cron sqlite runtime tests

* test: fix doctor e2e migration mock

* test: fix doctor shard e2e isolation

* test: fix infra child-process mocks
2026-05-30 21:03:41 +01:00
brokemac79
d11e82aeea fix(ui): keep selected chat model visible after session switch
Fixes #86597. Thanks @brokemac79.
2026-05-30 20:53:47 +01:00
Coder
adcac404e1 fix(llm): repair invalid streaming unicode escapes
Repair invalid \u escapes during streaming JSON parsing without changing valid Unicode escapes. Split oversized node CI doctor/infra shards and fix the restart test mock deadlock so PR CI stays under the no-output threshold.\n\nCo-authored-by: Coder <83845889+coder999999999@users.noreply.github.com>
2026-05-30 20:53:26 +01:00
Vincent Koc
eb5e80f58a ci: update Blacksmith Testbox actions 2026-05-30 20:51:31 +01:00
Peter Steinberger
5891cfec3e refactor: move model catalog normalization into core package
Move model catalog normalization and package-owned catalog schema/types into model-catalog-core while keeping public plugin SDK model catalog declarations on the existing SDK surface. Verified focused tests, package-boundary compile, full build, changed gate, declaration leak grep, CI, and autoreview.
2026-05-30 20:51:11 +01:00
Abner Shang
961691def2 fix(codex): keep app-server continuation turns alive
Keep Codex app-server continuation turns alive after post-tool, raw assistant, and progress notifications, and reschedule continuation idle watches when shorter progress timeouts apply.

Add regression coverage for the plugin-sdk child_process mock helper deadlock that blocked CI shards on this PR.

Co-authored-by: abnershang <abner.shang@gmail.com>
2026-05-30 20:41:04 +01:00
Vincent Koc
2780f540f8 test(agents): wait for MCP method-not-found log 2026-05-30 20:39:52 +01:00
Vincent Koc
37058ad75a fix(scripts): quiet minimal runtime asset copies
Stop minimal cliStartup and gatewayWatch builds from copying generated plugin static assets they intentionally do not build.\n\nVerified with focused Vitest, autoreview, AWS Crabbox startup-memory proof, and AWS Crabbox changed gate run_bd9ea01e6a12 plus rebased changed gate run_bd9ea01e6a12.
2026-05-30 20:38:19 +01:00
Peter Steinberger
37c6e2dfa0 ci: skip codeql network shard for test-only changes 2026-05-30 20:29:19 +01:00
Shakker
473993f73a fix: remove redundant unknown union 2026-05-30 20:28:29 +01:00
Peter Steinberger
e24a9c5457 ci: keep harness changes on fast checks (#88429) 2026-05-30 20:27:59 +01:00
Shakker
d9c0d09f1a chore: remove inert skill workshop package 2026-05-30 20:15:31 +01:00
Peter Steinberger
0c7ab411e5 fix(auth): bound oauth mirror expiry 2026-05-30 15:11:14 -04:00
Alix-007
5811693c7f fix(export-html): guard msg.content and result.content filter/iteration paths against non-array values (#88271)
* fix(export-html): guard all msg.content and result.content filter/iteration paths

Three call sites in the export HTML template called `.filter()` or iterated
with `for...of` directly on `msg.content` or `result.content` without first
checking `Array.isArray`. When a transcript message row carries a non-array
content value (null, undefined, or any scalar), those paths throw:

  TypeError: msg.content.filter is not a function

Fix: normalize with `Array.isArray(x) ? x : []` before every unguarded
filter and iteration on `msg.content` (computeStats stats path and the
renderEntry assistant render loops) and `result.content` (renderToolCall
text/image accessors).

Regression test added: renderTemplate resolves without throwing for assistant
messages with null, undefined, string, and numeric content values.

Closes #88255

* fix(export-html): guard user message text extraction path against non-array content

The user-message render path in the export HTML template extracted text with
`content.filter(...)` without checking whether `content` is an array. A
persisted user message row with null, undefined, or any non-string scalar
content crashed during export with the same TypeError class as the assistant
path.

Fix: normalize the ternary so a non-string, non-array value falls through to
an empty string rather than calling `.filter` on it.

Regression test added for null, undefined, and numeric user message content.

Addresses feedback from ClawSweeper review on #88271.

* fix(export-html): preserve string content guards

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 20:10:43 +01:00
Peter Steinberger
445ff22018 fix(agents): bound auth health expiry 2026-05-30 15:09:37 -04:00
Peter Steinberger
602364f1c7 ci: stabilize changed checks 2026-05-30 20:07:38 +01:00
Peter Steinberger
c73e8eedf4 fix(agents): bound discovery auth expiry 2026-05-30 15:07:04 -04:00
Shakker
dcc329ac09 chore: keep skill workshop package manifest inert 2026-05-30 20:04:52 +01:00
Shakker
515d4ffc21 fix: refresh skill workshop CI expectations 2026-05-30 20:04:52 +01:00
Shakker
28290a496f fix: allow concise skill update descriptions 2026-05-30 20:04:52 +01:00
Shakker
3cd368edec fix: approve final skill workshop tool params 2026-05-30 20:04:52 +01:00
Shakker
908fc35b97 fix: preserve trusted policy checks for skill workshop 2026-05-30 20:04:52 +01:00
Shakker
d6d1cc2a3e fix: serialize skill proposal creation limits 2026-05-30 20:04:52 +01:00
Shakker
41044a207c fix: serialize skill proposal lifecycle mutations 2026-05-30 20:04:52 +01:00
Shakker
7d19f89094 fix: harden skill workshop proposal results 2026-05-30 20:04:52 +01:00
Shakker
43e4b9dc1c fix: keep autonomous skill capture opt-in 2026-05-30 20:04:52 +01:00
Shakker
77c6bee421 fix: refresh skill workshop generated surfaces 2026-05-30 20:04:52 +01:00
Shakker
0b49710e8d fix: preserve auto-captured skill updates 2026-05-30 20:04:52 +01:00
Shakker
3a9e7dfa1a fix: bound skill workshop descriptions 2026-05-30 20:04:52 +01:00
Shakker
e4905ce4c9 fix: enforce skill workshop proposal bounds 2026-05-30 20:04:52 +01:00
Shakker
131e662924 fix: scan skill proposal prompt content 2026-05-30 20:04:52 +01:00
Shakker
7051bf16f0 fix: align skill proposal revise validation 2026-05-30 20:04:52 +01:00
Shakker
6eb6730137 refactor: move skill research capture logic 2026-05-30 20:04:52 +01:00
Shakker
2383cfd303 refactor: rename skill workshop agent tool 2026-05-30 20:04:52 +01:00
Shakker
c09e1efe99 fix: clean up skill workshop lint issues 2026-05-30 20:04:52 +01:00
Shakker
308fdbe7fb refactor: remove skill workshop plugin package 2026-05-30 20:04:52 +01:00
Shakker
c5af09e378 refactor: route agent end side effects through harness 2026-05-30 20:04:52 +01:00
Shakker
3037646d22 feat: add skill workshop runtime policy 2026-05-30 20:04:52 +01:00
Shakker
3ea82adf97 fix: show skill proposal support files on inspect 2026-05-30 20:04:52 +01:00
Shakker
bc6d570659 fix: reject non-text skill proposal files 2026-05-30 20:04:52 +01:00
Shakker
f7729028ae fix: guard skill proposal apply writes 2026-05-30 20:04:52 +01:00
Shakker
11d6ce15e8 fix: harden skill proposal boundaries 2026-05-30 20:04:52 +01:00
Shakker
897a7efe15 fix: preserve skill proposal target state 2026-05-30 20:04:52 +01:00
Shakker
fafa4c8b65 fix: scope skill workshop proposal access 2026-05-30 20:04:52 +01:00
Shakker
186182fe9e feat: let skill research manage proposal lifecycle 2026-05-30 20:04:52 +01:00
Shakker
e5455b61c3 feat: let skill research manage proposal discovery 2026-05-30 20:04:52 +01:00
Shakker
e89417d77b fix: keep skill research available to agents 2026-05-30 20:04:52 +01:00
Shakker
e9b0a5f69e feat: revise pending skill proposals 2026-05-30 20:04:52 +01:00
Shakker
339e212c85 fix: expose skill proposal gateway methods 2026-05-30 20:04:52 +01:00
Shakker
199cdc1052 fix: enforce canonical workshop skill names 2026-05-30 20:04:52 +01:00
Shakker
ab0613c9d3 feat: support skill proposal files 2026-05-30 20:04:52 +01:00
Shakker
91ba5fd4fe fix: store skill workshop proposals in state 2026-05-30 20:04:52 +01:00
Shakker
9da7498d31 fix: satisfy skill workshop lint 2026-05-30 20:04:52 +01:00
Shakker
67298c4bd8 fix: satisfy skill workshop changed checks 2026-05-30 20:04:52 +01:00
Shakker
9417a3f39f fix: rebuild corrupt skill proposal manifests 2026-05-30 20:04:52 +01:00
Shakker
1609fcaff3 docs: document skill workshop proposals 2026-05-30 20:04:52 +01:00
Shakker
5205b94d84 feat: expose skill workshop gateway methods 2026-05-30 20:04:52 +01:00
Shakker
7f48ee1e57 feat: add skill research proposal tool 2026-05-30 20:04:52 +01:00
Shakker
c4be8d8730 feat: add skill workshop cli commands 2026-05-30 20:04:52 +01:00
Shakker
bc1c3701c4 feat: add skill workshop proposal store 2026-05-30 20:04:52 +01:00
Peter Steinberger
4e8b74568f refactor: move model catalog refs into core package
Move model catalog ref helpers into @openclaw/model-catalog-core/model-catalog-refs and update internal callers/package-boundary aliases. Also fix the timestamp predicate typing that blocked prod type checks on current main.
2026-05-30 20:04:16 +01:00
Peter Steinberger
b80dcbd650 fix(plugin-sdk): bound copilot token expiry 2026-05-30 15:04:03 -04:00
Peter Steinberger
417aba7b9b fix(infra): bound session delivery recovery deadline 2026-05-30 15:02:02 -04:00
Peter Steinberger
ed63523db9 test(release): expect public latest in installer smoke 2026-05-30 20:01:22 +01:00
Peter Steinberger
677f7c80dc fix(plugin-sdk): bound oauth result expiry 2026-05-30 14:59:59 -04:00
Vincent Koc
231d0b28bd fix(agents): harden message dts and block timestamps 2026-05-30 20:58:21 +02:00
Peter Steinberger
979907e004 fix(outbound): bound delivery recovery deadline 2026-05-30 14:57:47 -04:00
Peter Steinberger
9eb17a0277 fix(shared): bound epoch expiry helpers 2026-05-30 14:55:37 -04:00
Peter Steinberger
06e0fd3347 fix(media): bound provider operation deadlines 2026-05-30 14:54:03 -04:00
Peter Steinberger
51cceaf70c fix(agents): bound run drain deadlines 2026-05-30 14:51:59 -04:00
Peter Steinberger
471164afbd fix(github-copilot): bound device code expiry 2026-05-30 14:49:34 -04:00
Peter Steinberger
99ce71ddbb feat: improve MCP operability
Summary:
- Add MCP status, probe, and projected-tools CLI surfaces.
- Add per-server MCP tool filters plus resource/prompt utility projection.
- Harden MCP runtime discovery, listChanged invalidation, request-failure backoff, and metadata sanitization.
- Preserve current main type health by narrowing the shared future timestamp guard.

Verification:
- pnpm test src/shared/number-coercion.test.ts src/agents/auth-profiles/usage.test.ts src/cli/mcp-cli.test.ts src/agents/agent-bundle-mcp-runtime.test.ts src/agents/agent-bundle-mcp-tools.materialize.test.ts -- --reporter=verbose
- pnpm lint
- pnpm tsgo:prod
- pnpm build
- git diff --check origin/main...HEAD
- GitHub Actions: dependency-guard, real behavior proof, security high MCP boundary, build/lint/types/guards/docs, gateway/plugin/agent shards green on PR head.

Known proof gap:
- Existing checks-node-agentic-commands-doctor no-output watchdog reproduced locally outside touched paths.
2026-05-30 19:48:52 +01:00
Peter Steinberger
9cb9851bf8 fix(models): bound pasted token expiry 2026-05-30 14:47:41 -04:00
Peter Steinberger
2b31c02163 fix(plugins): bound scheduled turn delays 2026-05-30 14:44:24 -04:00
Coder
878e433d81 fix(skill-creator): sort .skill entries deterministically
Fixes #37748.

Sort skill package archive entries by relative POSIX archive name so generated `.skill` bundles are reproducible regardless of filesystem traversal order.

Verification:
- `PYTHONDONTWRITEBYTECODE=1 python3 skills/skill-creator/scripts/test_package_skill.py`
- `git diff --check origin/main...HEAD`
- GitHub CI run 26690938925 on `43a0fdf7175f33a5c74bc7ff92723ebf5efc4df9`: all checks passed except repeated unrelated no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state` after visible tests passed.
2026-05-30 19:42:55 +01:00
Peter Steinberger
dfbed5053a fix(qqbot): bound reminder schedule time 2026-05-30 14:41:39 -04:00
Peter Steinberger
caac9733a7 fix(memory): bound qmd embed backoff 2026-05-30 14:39:33 -04:00
Peter Steinberger
6399b6a445 fix(discord): bound timeout member expiry 2026-05-30 14:34:40 -04:00
Peter Steinberger
472606de9b fix(qqbot): skip token cache on invalid clock 2026-05-30 14:33:04 -04:00
Peter Steinberger
177496552b fix(infra): bound device bootstrap expiry 2026-05-30 14:31:30 -04:00
Peter Steinberger
e0248fc11f fix(cron): bound relative at timestamps 2026-05-30 14:29:39 -04:00
Peter Steinberger
6a753ade78 fix(crestodian): bound rescue approval expiry 2026-05-30 14:28:25 -04:00
Peter Steinberger
53812bd8aa fix(agents): bound codex cli fallback expiry 2026-05-30 14:26:17 -04:00
Lellansin Huang
fe3c3ac5cd fix(gateway): forward stop sequences across providers
Forward OpenAI-compatible stop sequences from gateway chat completions through the agent runner into provider transports.

The gateway now normalizes stop into sampling extras, agent transports pass it into the shared stream options, and OpenAI, Anthropic, Mistral, Google, and Vertex-backed simple providers map it to their native request fields. Provider/gateway/agent coverage plus Crabbox live gateway proof verify valid stop dispatch and invalid stop rejection.

Refs #87920
2026-05-30 19:24:21 +01:00
Peter Steinberger
5435b453ca feat: expand workboard orchestration metadata (#88408) 2026-05-30 19:22:19 +01:00
Peter Steinberger
abc26b072b fix(discord): bound rest rate-limit deadlines 2026-05-30 14:22:16 -04:00
Jiatai Wang
64533bab65 fix(agents): show exec target node in tool display
Show the remote node name in exec tool transparency details when an exec call targets `host=node`, while ignoring stray `node` values for gateway, sandbox, and auto-host calls.

Covers node-only, cwd+node, absent-node, and non-node-host regression cases in the tool display tests.

Fixes #77719.

Co-authored-by: JiataiWang <wangjiatai@proton.me>
2026-05-30 19:19:17 +01:00
Peter Steinberger
7d4bf8f285 fix(telegram): bound transport cooldown expiry 2026-05-30 14:16:57 -04:00
Peter Steinberger
bdb0fde0ea test(release): harden live release checks 2026-05-30 19:14:27 +01:00
Peter Steinberger
926a165a52 fix(anthropic): bound setup token expiry 2026-05-30 14:14:13 -04:00
Peter Steinberger
70b6fdd149 fix(bedrock): bound mantle runtime token expiry 2026-05-30 14:09:59 -04:00
Peter Steinberger
9ad7f5bbde fix(agents): bound sqlite cache expiry 2026-05-30 14:07:32 -04:00
Peter Steinberger
1ee751ddb1 fix(agents): bound google prompt cache expiry 2026-05-30 14:02:50 -04:00
Peter Steinberger
30e3ca08a5 fix(agents): bound auth profile block expiry 2026-05-30 14:00:46 -04:00
Peter Steinberger
1f6c1eacf0 fix(telegram): bound error cooldown expiry 2026-05-30 13:59:06 -04:00
Peter Steinberger
8654353be8 fix(discord): bound component registry expiry 2026-05-30 13:57:13 -04:00
Peter Steinberger
c5aa3ff02f fix(msteams): bound delegated token probe expiry 2026-05-30 13:54:56 -04:00
Peter Steinberger
5fde637ba8 fix(codex): bound app inventory cache expiry 2026-05-30 13:53:13 -04:00
guanbear
044f5a814e Expose subagent resolved model metadata (#80037)
Co-authored-by: guanbear <guanbear@macmini.bearhome>
2026-05-30 18:52:21 +01:00
Peter Steinberger
3ae521745e fix(voice-call): bound webhook replay cache expiry 2026-05-30 13:51:12 -04:00
Peter Steinberger
f89f5d930f fix(gateway): bound system run event expiry 2026-05-30 13:49:03 -04:00
Vincent Koc
13c77f00c3 fix(agents): classify code mode deadline interrupts 2026-05-30 18:47:42 +01:00
chuanchuan
3b8ab4e112 fix(feishu): stream plain replies as cards
Feishu `channels.feishu.streaming=true` now streams ordinary assistant replies through CardKit in auto mode, while keeping tool-summary delivery on the existing message path.

Also discards stale partial previews when final delivery intentionally suppresses text for voice media or duplicate final text, and preserves streamed partial text for regular media-only finals.

Verification:
- `node scripts/run-vitest.mjs run extensions/feishu/src/reply-dispatcher.test.ts`
- `pnpm tsgo:extensions`
- `pnpm test:extensions:package-boundary:compile`
- `pnpm exec oxfmt --check extensions/feishu/src/reply-dispatcher.ts extensions/feishu/src/reply-dispatcher.test.ts extensions/feishu/src/streaming-card.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub PR checks on run 26689677607 passed except repeated unrelated broad Vitest no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state`.

Co-authored-by: 传妈 <chuanmother@chuanMac-Mini.local>
2026-05-30 18:47:03 +01:00
Peter Steinberger
ca4a12381a fix(gateway): bound chat abort expiry registration 2026-05-30 13:46:16 -04:00
Steven
86e33d6985 fix(models): preserve exact provider refs before aliases
Fixes #88218.

Preserves exact configured provider/model defaults before bare alias target reverse matches, while retaining slash-form aliases and auth-profile alias behavior.

Co-authored-by: Steven Palmer <palmer.e.steven@gmail.com>
2026-05-30 18:46:11 +01:00
Peter Steinberger
9ef699fedc fix(gateway): bound maintenance run expiry checks 2026-05-30 13:43:21 -04:00
Peter Steinberger
912a276ca1 fix(gateway): bound talk handoff expiry 2026-05-30 13:41:14 -04:00
Brian
6f20f29688 fix(discord): carry reply typing feedback through queue
Carry Discord reply typing feedback through preflight, queued dispatch, and cleanup so delayed accepted replies keep typing alive at the actual dispatch target without duplicate keepalives. Adds focused Discord queue/process policy coverage and stronger lifecycle invariant comments.
2026-05-30 18:39:39 +01:00
Merlin
b6d253eefb fix(discord): omit undefined component registry fields
Prunes undefined Discord component and modal registry metadata before persisting it so SQLite-backed plugin state never receives JSON-incompatible undefined values. Adds direct regression coverage for undefined own properties on component, modal, and nested field entries.
2026-05-30 18:39:26 +01:00
Peter Steinberger
0a87f6e4ad fix(gateway): bound node pending work expiry 2026-05-30 13:38:54 -04:00
Ashd.LW.
bc77f7a00a fix(gateway): explain ignored restart signal
Add actionable operator guidance when an unauthorized SIGUSR1 gateway restart is ignored because unmanaged restart is disabled.

The change is log-only: restart authorization and scheduling semantics are unchanged, and the existing run-loop test now asserts both the reason warning and the recovery hint.

Refs #79577
Refs #78110
Refs #82433

Co-authored-by: wAngByg <281221101+wAngByg@users.noreply.github.com>
2026-05-30 18:38:35 +01:00
ToToKr
9e3d5310cc fix(media): dedupe duplicate inbound media path urls
Dedupe prompt-side inbound media note suffixes when sanitized MediaPath and MediaUrl render to the same value, while preserving genuinely distinct remote URLs.\n\nFixes #47587.\nThanks @MoerAI for the patch and @yzjJosh for the report.
2026-05-30 18:37:42 +01:00
Peter Steinberger
4d9366fecb fix(gateway): bound plugin node capability expiry 2026-05-30 13:35:43 -04:00
Sebastien Tardif
1c9851e115 fix(install): show npm install progress without gum
Show the same Installing OpenClaw package progress line in the no-gum npm install fallback before redirecting npm output to the temp log.

Fixes #82305

Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-30 18:35:32 +01:00
Peter Steinberger
a4f62400a7 fix(commitments): bound terminal failure cooldown expiry 2026-05-30 13:33:06 -04:00
吴杨帆
8d3fe21b53 test(tasks): cover task domain view mappers (#86755)
Adds focused coverage for task-domain view mapper DTO contracts, including summary cloning, task run/detail mapping, flow view/detail mapping, and implicit summary computation.

Test-only PR. Verified with git diff --check and PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false pnpm test src/tasks/task-domain-views.test.ts on the current-main merge result.

Thanks @leno23.

Co-authored-by: wuyangfan <yangfan.wu@succaiss.com>
2026-05-30 18:30:36 +01:00
Peter Steinberger
becd45325b fix(imessage): bound private api negative cache expiry 2026-05-30 13:28:17 -04:00
Peter Steinberger
84a965a1a2 refactor(matrix): move ephemeral state to plugin sqlite (#88387)
* refactor(matrix): persist ephemeral state in plugin sqlite

* test(channels): wire matrix contract plugin state
2026-05-30 18:26:29 +01:00
Peter Steinberger
f4d461bbff fix(imessage): bound approval reaction poll expiry 2026-05-30 13:25:45 -04:00
Peter Steinberger
cbad1b6e69 fix(agents): bound exec followup handoff expiry 2026-05-30 13:23:03 -04:00
Peter Steinberger
f4cd5e4050 fix(sandbox): bound novnc observer token expiry 2026-05-30 13:21:26 -04:00
Peter Steinberger
0e7773d1a6 test(release): wait for live probe cleanup 2026-05-30 18:21:01 +01:00
Peter Steinberger
d8e7734d27 fix(agents): bound exec approval request expiry 2026-05-30 13:19:42 -04:00
Peter Steinberger
da7fb64aa4 fix(google): bound realtime browser session expiry 2026-05-30 13:16:22 -04:00
Peter Steinberger
3fffb34ba0 fix(msteams): bound delegated token expiry 2026-05-30 13:13:56 -04:00
Peter Steinberger
0dd67e2f25 fix(workboard): bound claim expiry checks 2026-05-30 13:11:14 -04:00
Peter Steinberger
4df27b9626 fix(browser): bound armed dialog expiry 2026-05-30 13:08:52 -04:00
Peter Steinberger
e708a872a1 fix(commands): bound private approval route expiry 2026-05-30 13:06:29 -04:00
zhang-guiping
2dacc6da28 fix(agents): hide sessions_send alias normalization
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
2026-05-30 18:06:22 +01:00
Peter Steinberger
9660e42fe2 fix(plugin-state): bound ttl expiry writes 2026-05-30 13:03:24 -04:00
Peter Steinberger
522da25932 fix(skills): bound upload expiry checks 2026-05-30 13:00:52 -04:00
Peter Steinberger
d44621b544 fix(exec): bound approval pending expiry 2026-05-30 12:58:59 -04:00
Peter Steinberger
6fe0539992 test(release): skip unavailable anthropic live models 2026-05-30 17:58:01 +01:00
Peter Steinberger
283238fd77 fix(matrix): bound allowlist store cache expiry 2026-05-30 12:56:54 -04:00
Peter Steinberger
5568ecc7aa fix(discord): bound unbound webhook echo expiry 2026-05-30 12:54:25 -04:00
Peter Steinberger
743d5378d2 fix(zalouser): bound group context cache expiry 2026-05-30 12:52:24 -04:00
史启明(QimingShi)
63a3676d3c fix(tui): distinguish /new and /reset descriptions
Fixes #49517.

Updates the TUI command catalog so /new describes spawning an isolated session while /reset describes resetting the current session. Adds a focused regression test for the two descriptions.

Co-authored-by: KhanCold <119404710+KhanCold@users.noreply.github.com>
2026-05-30 17:50:14 +01:00
Peter Steinberger
2a39c217c8 fix(voice-call): bound realtime stream token expiry 2026-05-30 12:49:36 -04:00
NianJiu
a2fc4ca7ad feat(ui): add collapsible recent sessions section
Adds a persisted collapse state for the Control UI Recent sessions sidebar group, including storage and browser coverage.

Also narrows gateway run miss cache expiry typing so the rebased branch stays clean against current main.

Closes #85510

Co-authored-by: NianJiuZst <3235467914@qq.com>
2026-05-30 17:48:29 +01:00
Peter Steinberger
8eeaa45729 refactor: route model catalog imports to core package
Route internal model catalog imports to the extracted @openclaw/model-catalog-core package and delete obsolete internal facades.

Keep public SDK declarations self-contained by wrapping core helpers at public boundaries instead of leaking private package imports.

Verification:
- pnpm test src/plugins/contracts/model-catalog-core-imports.test.ts src/plugins/sdk-alias.test.ts packages/model-catalog-core/src/configured-model-refs.test.ts packages/model-catalog-core/src/provider-model-id-normalize.test.ts packages/model-catalog-core/src/provider-model-id-normalization.test.ts src/config/config.model-ref-validation.test.ts src/agents/model-selection.test.ts src/plugin-sdk/provider-model-shared.test.ts -- --reporter=verbose
- pnpm check:test-types
- pnpm test:extensions:package-boundary:compile
- pnpm build
- rg "@openclaw/model-catalog-core" dist/plugin-sdk packages/plugin-sdk/dist -n --glob '*.d.ts' || true
- git diff --check
- autoreview clean after fix

CI note: merged with admin override because checks-node-agentic-commands-doctor and checks-node-core-runtime-infra-state failed twice with exit 143/no-output watchdog termination after prior passing test output, while relevant local proof and the rest of CI were green.
2026-05-30 17:48:18 +01:00
Vincent Koc
4d13055ca5 fix(sessions): repair prompt blobs on fast updates 2026-05-30 17:47:07 +01:00
Peter Steinberger
bfceffa2f7 fix(qqbot): bound upload cache expiry 2026-05-30 12:46:56 -04:00
Peter Steinberger
031583e8f5 fix(gateway): bound exec approval expiry 2026-05-30 12:44:39 -04:00
Vincent Koc
2ccbc673df fix(scripts): prebuild gateway cpu private qa artifacts 2026-05-30 18:42:17 +02:00
Peter Steinberger
11b5728faa fix(agents): bound code mode snapshot expiry 2026-05-30 12:42:07 -04:00
samzong
4decdf6245 [Fix] Deliver restart recovery replies (#86089)
* fix(agents): deliver restart recovery replies

* fix(auto-reply): import session entry updater

* test(auto-reply): use current embedded agent mock

* test(feishu): refresh typed account fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 17:39:43 +01:00
Peter Steinberger
ac0fb976c8 fix(feishu): bound card action token expiry 2026-05-30 12:37:24 -04:00
Vincent Koc
1de9f99ea8 fix(ci): repair current test type fixtures 2026-05-30 17:35:02 +01:00
Peter Steinberger
60f8e18372 fix(nvidia): bound featured model cache expiry 2026-05-30 12:34:53 -04:00
Peter Steinberger
e52b4bce01 fix(bedrock): bound discovery cache expiry 2026-05-30 12:33:07 -04:00
mushuiyu_xydt
f93a558892 fix(plugins): ignore helper files in extension roots
Fixes #88198.

Ignore top-level helper scripts in auto-discovered global/workspace extension roots so they do not become manifestless plugin candidates during config validation. Standalone plugin files remain supported when explicitly configured through `plugins.load.paths`, and docs now call out the supported path.

Verification:
- `node scripts/run-vitest.mjs src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `node scripts/run-oxlint.mjs src/plugins/discovery.ts src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `git diff --check`
- GitHub CI green at `93073bfa85ee294e644c623881ba59ba71d90975`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`

Thanks @mushuiyu886 for the fix and @mmhzlrj for the report.
2026-05-30 17:31:53 +01:00
Peter Steinberger
5ba3505fed fix(bedrock): bound mantle iam token expiry 2026-05-30 12:31:08 -04:00
Peter Steinberger
18e7d28b21 perf(gateway): reuse stable turn metadata 2026-05-30 17:30:47 +01:00
Peter Steinberger
02ca283716 fix(outbound): bound current conversation expiry 2026-05-30 12:27:26 -04:00
Peter Steinberger
4f0e3cb621 fix(plugin-sdk): bound live catalog cache expiry 2026-05-30 12:25:14 -04:00
Martin Kessler
73a69d9e64 fix(outbound): pack newline-mode paragraphs up to limit
Pack newline-mode outbound paragraphs up to the configured text limit instead of sending one message per blank-line-separated paragraph. Preserves markdown fence guardrails and adds focused chunking plus outbound delivery regressions.\n\nVerified: autoreview clean; node scripts/run-vitest.mjs src/auto-reply/chunk.test.ts src/infra/outbound/deliver.test.ts; git diff --check origin/main...HEAD.\n\nThanks @kesslerio.
2026-05-30 17:24:57 +01:00
Peter Steinberger
b1911a7cd3 fix(gateway): bound run session miss cache expiry 2026-05-30 12:22:24 -04:00
Peter Steinberger
450642a897 fix(agents): bound native permission approval expiry 2026-05-30 12:20:29 -04:00
Vincent Koc
f7a1903bfc fix(discord): avoid private test session intersection 2026-05-30 17:18:51 +01:00
Peter Steinberger
61cf22f147 fix(agents): bound native hook relay expiry 2026-05-30 12:17:36 -04:00
Peter Steinberger
55505776fb fix(gateway): bound transcription relay session expiry 2026-05-30 12:15:06 -04:00
brokemac79
3c91928bae fix(codex): refresh stale managed runtime plugin
Refresh stale managed Codex runtime plugin installs during doctor repair and restore Codex status usage attribution. Thanks @brokemac79.
2026-05-30 17:15:04 +01:00
Peter Steinberger
6ac7564918 fix(gateway): bound realtime relay session expiry 2026-05-30 12:13:10 -04:00
Peter Steinberger
23e1aac9b2 fix(feishu): bound sender name cache expiry 2026-05-30 12:10:19 -04:00
Peter Steinberger
c65af78853 fix(discord): bound realtime wake followup expiry 2026-05-30 12:06:57 -04:00
Vincent Koc
4155ac1c0d fix(scripts): make kitchen sink rpc help inert 2026-05-30 18:04:44 +02:00
Peter Steinberger
cfe5544b30 fix(qqbot): honor legacy c2c stream progress 2026-05-30 17:02:41 +01:00
Peter Steinberger
d7b901a1e7 fix(discord): bound speaker context cache expiry 2026-05-30 12:02:18 -04:00
Peter Steinberger
5225a8c644 fix(gateway): bound config schema cache expiry 2026-05-30 12:00:37 -04:00
Peter Steinberger
fc50f949d4 Add per-agent SQLite cache store (#88349)
* feat: add per-agent sqlite cache store

* fix: preserve sqlite cache adapter scope

* chore: mark sqlite cache scaffold intentional
2026-05-30 17:00:24 +01:00
samzong
f6b40861f7 fix(qqbot): deliver partial tool progress
Fixes #66509.

QQBot now sends text-only tool progress immediately when partial streaming is enabled instead of buffering it until a fallback timer that is cleared by the final block. Immediate progress uses QQ plain-text sends so markdown-enabled accounts do not reinterpret media-like progress text, while streaming-off behavior remains final-only.

Thanks @gabrielduartesignart for the report.

Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-30 17:00:09 +01:00
Peter Steinberger
f491d420f7 fix(tailscale): bound whois cache expiry 2026-05-30 11:58:07 -04:00
Peter Steinberger
ef0882e17e fix(google): bound gemini oauth token expiry 2026-05-30 11:55:02 -04:00
Peter Steinberger
697bafa9c9 fix(google): bound vertex adc token cache expiry 2026-05-30 11:52:19 -04:00
Peter Steinberger
77761f4a3e fix(msteams): bound parent thread cache expiry 2026-05-30 11:49:47 -04:00
Peter Steinberger
0e2694ff47 fix(msteams): bound team id cache expiry 2026-05-30 11:47:00 -04:00
Peter Steinberger
5eb71927b7 fix(whatsapp): bound group metadata cache expiry 2026-05-30 11:45:05 -04:00
Vincent Koc
cbd8049b9f fix(scripts): parse forwarded package script options 2026-05-30 17:44:14 +02:00
Peter Steinberger
19f22b5924 fix(feishu): bound approval card expiry 2026-05-30 11:41:43 -04:00
Peter Steinberger
05634708e0 fix(feishu): bound quick action launcher expiry 2026-05-30 11:38:50 -04:00
Vincent Koc
536c00991f fix(gateway): guard traced channel handoff stops 2026-05-30 16:36:43 +01:00
Peter Steinberger
c94c43d3bb fix(feishu): bound card action chat cache clocks 2026-05-30 11:36:19 -04:00
Nimrod Gutman
8a99c0d17a feat(ios): refresh app store metadata (#88235)
Merged via squash.

Prepared head SHA: a54d2ffad2
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-30 18:36:01 +03:00
Peter Steinberger
30e1556cda refactor: extract model catalog core package
* refactor: extract model catalog core package

* refactor: route model catalog imports through package boundary

* build: include model catalog in plugin sdk package dts

* fix: preserve static fallback model metadata
2026-05-30 16:33:45 +01:00
Peter Steinberger
ec15f90a55 fix(feishu): bound group name cache clocks 2026-05-30 11:33:30 -04:00
Peter Steinberger
3da34a4673 fix(feishu): bound probe cache expiry clocks 2026-05-30 11:31:16 -04:00
Peter Steinberger
f91ddefbfb fix(zalo): bound hosted media expiry clocks 2026-05-30 11:29:33 -04:00
Vincent Koc
84385898ec fix(deps): remove photon root runtime 2026-05-30 16:27:48 +01:00
Peter Steinberger
6c7642b532 fix(workboard): bound claim expiry timestamps 2026-05-30 11:27:09 -04:00
Peter Steinberger
9988a37d37 fix(phone-control): bound arm expiry timestamps 2026-05-30 11:24:36 -04:00
Peter Steinberger
37b33d11ce test: isolate channel manager teardown 2026-05-30 16:24:34 +01:00
Peter Steinberger
7086e34533 feat(workboard): persist orchestration metadata in sqlite
Persist Workboard orchestration data in plugin SQLite KV storage, including board metadata, cards, notification subscriptions, decomposition history, and board lifecycle/RPC support.
2026-05-30 16:24:14 +01:00
Peter Steinberger
20fbb8bd14 fix(mattermost): bound slash validation cache clocks 2026-05-30 11:22:25 -04:00
Peter Steinberger
8e90a1cad9 fix(slack): bound subteam member cache clocks 2026-05-30 11:19:34 -04:00
Peter Steinberger
7e3ebb8e10 fix(slack): bound external menu cache clocks 2026-05-30 11:17:13 -04:00
Peter Steinberger
06b2bf1c0a fix(telegram): bound forum flag cache clocks 2026-05-30 11:15:03 -04:00
Peter Steinberger
d649548a7a fix(active-memory): bound recall cache clocks 2026-05-30 11:13:04 -04:00
Vincent Koc
5adc681238 refactor: share approval lookup state 2026-05-30 17:12:03 +02:00
Vincent Koc
53e8dc6a54 fix(scripts): stop parsing after option terminators 2026-05-30 17:10:36 +02:00
Peter Steinberger
2d0a0c5e43 test: clear channel manager restart timers 2026-05-30 16:09:38 +01:00
Peter Steinberger
b668ffe7ca fix(slack): bound thread resolution cache clocks 2026-05-30 11:09:21 -04:00
Peter Steinberger
6736936cbc fix(slack): bound thread starter cache clocks 2026-05-30 11:06:47 -04:00
Peter Steinberger
8539e0283a fix(slack): bound app mention retry clocks 2026-05-30 11:04:24 -04:00
Peter Steinberger
ef88f0f949 perf(sessions): skip prompt hydration for metadata reads 2026-05-30 16:03:39 +01:00
Peter Steinberger
816c692035 fix(slack): bound member cache clocks 2026-05-30 11:01:19 -04:00
Peter Steinberger
c635e560d0 build: update rastermill to 0.3.1 2026-05-30 16:01:14 +01:00
Vincent Koc
ccb59d989b fix(scripts): honor memory fd option terminator 2026-05-30 17:00:54 +02:00
Vincent Koc
642f85dc5b test(sdk): resolve local package deps in pack smoke 2026-05-30 15:57:18 +01:00
Vincent Koc
53300a5c1a refactor: share skills method validation 2026-05-30 16:56:36 +02:00
Vincent Koc
b51610a1c3 fix(ci): serialize gateway server vitest project 2026-05-30 15:56:25 +01:00
Peter Steinberger
5269924ff8 fix(imessage): bound probe cache clocks 2026-05-30 10:55:53 -04:00
Peter Steinberger
62fa5692cb fix(imessage): bound chat list cache clocks 2026-05-30 10:52:38 -04:00
Peter Steinberger
2d4369d176 fix(signal): bound api mode cache clocks 2026-05-30 10:50:44 -04:00
Peter Steinberger
99e8cf22a8 fix(web): bound tool cache expiry clocks 2026-05-30 10:47:46 -04:00
Vincent Koc
e780a6b7ba fix(agents): type configured fallback model metadata 2026-05-30 16:45:53 +02:00
Vincent Koc
313554059c fix(docs): route anchor audit through pnpm runner 2026-05-30 16:45:52 +02:00
Peter Steinberger
77b334a984 fix(mattermost): bound reaction cache clocks 2026-05-30 10:43:44 -04:00
Peter Steinberger
ab67a198c1 fix(mattermost): bound monitor cache clocks 2026-05-30 10:41:19 -04:00
Peter Steinberger
9ef5a9afdc fix(discord): bound REST entity cache clocks 2026-05-30 10:38:26 -04:00
Vincent Koc
c39fbdb698 refactor: share web login request validation 2026-05-30 16:37:35 +02:00
Peter Steinberger
d33d6bfafa fix(discord): bound channel info cache clocks 2026-05-30 10:34:45 -04:00
Peter Steinberger
2209f71a78 fix(oauth): reject date-invalid token expiries 2026-05-30 10:31:36 -04:00
Peter Steinberger
f13a615036 fix(foundry): bound entra token expiry clocks 2026-05-30 10:29:26 -04:00
Peter Steinberger
5660b67062 fix(google-meet): bound oauth fallback expiry clocks 2026-05-30 10:26:07 -04:00
Vincent Koc
1d21646e96 fix(ci): type static catalog runtime metadata 2026-05-30 15:23:48 +01:00
Peter Steinberger
55d4456751 fix(webhook): bound replay response expiry timestamps 2026-05-30 10:21:50 -04:00
Peter Steinberger
a80d9f00f1 test(imessage): align SMS route expectations 2026-05-30 15:18:30 +01:00
Peter Steinberger
22d635080d fix(feishu): guard streaming token expiry clocks 2026-05-30 10:14:14 -04:00
Peter Steinberger
d5be702f86 fix(gateway): guard assistant media ticket clocks 2026-05-30 10:08:32 -04:00
Vincent Koc
3d66d203d0 test(daemon): keep systemd tests off real systemctl 2026-05-30 15:03:37 +01:00
Peter Steinberger
a918e93421 fix(cron): keep out-of-range atMs invalid 2026-05-30 10:00:45 -04:00
Vincent Koc
56eadf36d0 refactor: share approval resolve param parsing 2026-05-30 15:57:57 +02:00
Peter Steinberger
912f663173 fix(agents): guard compaction successor timestamps 2026-05-30 09:56:55 -04:00
Peter Steinberger
f44af7eebf fix(gateway): guard live probe schedule timestamps 2026-05-30 09:52:20 -04:00
Peter Steinberger
65fe2b7e91 ci: tolerate release branches without llm core package 2026-05-30 14:48:08 +01:00
Peter Steinberger
941e04e9f3 fix: clamp configured OpenAI-compatible output tokens 2026-05-30 14:46:30 +01:00
AI-HUB
f327073fb3 fix: classify ws pre-handshake close as benign
Classify the exact `ws` pre-handshake close-before-open error as a benign uncaught network exception so transient Feishu WebSocket cleanup does not crash the gateway process.

The classifier now keeps the upstream `ws` message as an exact contract and rejects broader prefixed WebSocket messages, with regression coverage for direct, wrapped, and non-exact cases.

Fixes #88257.
Thanks @akrimm702.

Co-authored-by: AI-HUB <144416483+akrimm702@users.noreply.github.com>
2026-05-30 15:45:23 +02:00
Peter Steinberger
41e5acbb6c perf(gateway): skip unchanged auth persistence writes 2026-05-30 14:44:45 +01:00
Peter Steinberger
2333d47a1e fix(matrix): guard verification timestamps 2026-05-30 09:43:09 -04:00
Vincent Koc
c9e481ac48 refactor: share approval request registration 2026-05-30 15:40:49 +02:00
scotthuang
462e315953 fix(ui): stop pulsing completed stream segments
Completed WebChat stream segment bubbles now render without the active streaming animation after live output has moved on. The UI chat item contract now marks completed stream segments as non-streaming and the active stream as streaming, so the renderer applies the pulsing class only to live output.

Verified with:
- node scripts/run-vitest.mjs ui/src/ui/chat/build-chat-items.test.ts ui/src/ui/chat/grouped-render.test.ts ui/src/ui/views/chat.test.ts
- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui-stream-artifacts.tsbuildinfo
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main

PR: #88225
Credit: @scotthuang
2026-05-30 15:40:12 +02:00
Peter Steinberger
6b14df7792 fix(qqbot): guard token expiry logging 2026-05-30 09:38:58 -04:00
Vincent Koc
e449392c4f fix(e2e): route telegram proof through pnpm runner 2026-05-30 15:33:38 +02:00
Peter Steinberger
326db58229 fix(gateway): guard hook job timestamps 2026-05-30 09:33:19 -04:00
Vincent Koc
3caf4facec fix(test): include workflow lint target in routing expectation (#88310) 2026-05-30 14:29:26 +01:00
Peter Steinberger
c9a97f54e0 fix(discord): preserve preference recency under invalid clocks 2026-05-30 09:29:02 -04:00
Vincent Koc
85506c36a0 fix(e2e): route secret proof through pnpm runner 2026-05-30 15:25:15 +02:00
Ayaan Zaidi
a176b8ec2f perf(cli): compact resumed room-event prompts 2026-05-30 18:53:59 +05:30
Ayaan Zaidi
2b726457d8 fix(cli): persist first room-event session binding 2026-05-30 18:53:59 +05:30
Vincent Koc
6464f8d1d9 refactor: share visible approval list mapping 2026-05-30 15:19:10 +02:00
Peter Steinberger
a17c7a56da fix(sessions): guard transcript append timestamps 2026-05-30 09:08:20 -04:00
Peter Steinberger
98a1aa491f fix(gateway): guard lock payload timestamps 2026-05-30 09:04:34 -04:00
Vincent Koc
25b87b111d refactor: share find tool result builder 2026-05-30 15:00:22 +02:00
Peter Steinberger
f823123aa5 fix(time): centralize date timestamp fallback 2026-05-30 08:59:36 -04:00
Vincent Koc
d717ff71bf fix(live): reject loose heartbeat intervals 2026-05-30 14:56:58 +02:00
Peter Steinberger
840192caa9 fix(diffs): cap artifact expiry overflow 2026-05-30 08:54:56 -04:00
Vincent Koc
61ef6b12dd test(agents): harden code mode wait timeout 2026-05-30 13:53:25 +01:00
Peter Steinberger
660a6dec7f fix(cron): reject out-of-range cli relative times 2026-05-30 08:52:47 -04:00
Peter Steinberger
e49ef86945 fix(cron): guard timestamp validation clocks 2026-05-30 08:49:58 -04:00
Peter Steinberger
d2f69ecc3b fix(migrate): guard report timestamp formatting 2026-05-30 08:46:55 -04:00
Vincent Koc
a89abcb1e9 fix(release): reject loose npm verifier retry limits 2026-05-30 14:46:28 +02:00
Peter Steinberger
8bf7bc5b5c fix(sessions): guard archive timestamp formatting 2026-05-30 08:43:22 -04:00
Vincent Koc
4e2ef87c31 refactor: share git url parsing helpers 2026-05-30 14:42:17 +02:00
Vincent Koc
ec58491f75 fix(e2e): reject loose upgrade probe limits 2026-05-30 14:40:12 +02:00
Peter Steinberger
0840fea50d fix(matrix): guard startup verification timestamps 2026-05-30 08:38:12 -04:00
Vincent Koc
cf60e83118 fix(e2e): scope strict ClawHub preflight limits 2026-05-30 14:33:56 +02:00
Peter Steinberger
7ad2ebb515 fix(google): guard realtime browser session expiries 2026-05-30 08:33:06 -04:00
Peter Steinberger
3c41e1722f fix(discord): guard timeout expiry dates 2026-05-30 08:29:15 -04:00
Vincent Koc
dd5b70bcc4 refactor: share web search provider load context 2026-05-30 14:25:30 +02:00
Peter Steinberger
30c0422a8e fix(commitments): guard extraction prompt timestamps 2026-05-30 08:24:27 -04:00
Vincent Koc
6d43200248 fix(e2e): reject loose Telegram proof log limits 2026-05-30 14:23:40 +02:00
Peter Steinberger
be3153cabb fix(update): guard startup timestamps 2026-05-30 08:18:55 -04:00
Vincent Koc
56995069f1 fix(ci): preserve goal continuation prompts 2026-05-30 13:17:57 +01:00
Vincent Koc
2238e0ce76 fix(e2e): reject loose tool search fetch limits 2026-05-30 14:17:15 +02:00
Vincent Koc
38a463fe93 fix(deps): remove sharp from root package 2026-05-30 13:15:05 +01:00
Vincent Koc
e1f462b352 fix(e2e): reject loose Telegram Bot API limits 2026-05-30 14:11:43 +02:00
Peter Steinberger
ccd635fdb9 fix(memory-core): guard short-term recall timestamps 2026-05-30 08:10:54 -04:00
Vincent Koc
27dce6c6bb refactor: share embedded run abort loop 2026-05-30 14:09:15 +02:00
Peter Steinberger
9c08d8cd35 fix(memory-core): guard injected timestamps 2026-05-30 08:06:42 -04:00
Vincent Koc
dc5b3ecc4c fix(tui): continue goal commands after creation 2026-05-30 13:03:33 +01:00
Ayaan Zaidi
95f66a34e7 fix(gateway): honor queued manual restarts 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
1695ee2f43 fix(gateway): defer recovery restarts to callers 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
801520b0f0 fix(gateway): consume recovery restart edge cases 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
8ba79d72b4 test(gateway): cover reload stop timeout restart 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
5876ba6152 fix(gateway): restart channels after timed-out reload stop 2026-05-30 17:33:18 +05:30
Peter Steinberger
5b895f2592 fix(memory-wiki): guard injected timestamps 2026-05-30 08:02:26 -04:00
Peter Steinberger
fb61363763 fix(auto-reply): guard date stamp formatting 2026-05-30 07:58:51 -04:00
Vincent Koc
07e0af44b3 fix(e2e): reject loose MCP channel limits 2026-05-30 13:55:39 +02:00
Peter Steinberger
059d5405fe fix(infra): guard backup creation timestamps 2026-05-30 07:53:55 -04:00
Vincent Koc
cd37dbd4e5 refactor: share block reply coalescer enqueue 2026-05-30 13:51:47 +02:00
Vincent Koc
3e8d06a6be fix(ci): include workflow guard target 2026-05-30 12:50:38 +01:00
Peter Steinberger
2f07e4e6c0 fix(agents): guard current time context timestamp 2026-05-30 07:47:11 -04:00
Peter Steinberger
15fb3314de fix(discord): guard model picker legacy dates 2026-05-30 07:43:47 -04:00
Peter Steinberger
5a019e7725 fix(auto-reply): guard subagent info timestamps 2026-05-30 07:34:01 -04:00
Vincent Koc
aea31934d4 refactor: share directory id collection 2026-05-30 13:32:27 +02:00
Peter Steinberger
8ec7e80cb2 fix(agents): bound cli oauth jwt expiries 2026-05-30 07:29:59 -04:00
Peter Steinberger
6c3533d8c4 fix(ui): guard debug event timestamps 2026-05-30 07:23:02 -04:00
Vincent Koc
9c313a7826 fix(test): preserve live test passthrough flags 2026-05-30 13:20:02 +02:00
Peter Steinberger
368a719879 fix(ui): guard dreaming next-cycle timestamps 2026-05-30 07:19:22 -04:00
Peter Steinberger
ec7e3eaf64 fix(ui): guard chat picker session timestamps 2026-05-30 07:15:40 -04:00
Vincent Koc
8bcdab8933 refactor: share oauth identity safety check 2026-05-30 13:14:10 +02:00
Peter Steinberger
c2f0d811e7 fix(ui): guard next run weekday formatting 2026-05-30 07:12:51 -04:00
Peter Steinberger
8f3d3a549d fix(ui): guard usage chart timestamps 2026-05-30 07:10:21 -04:00
Peter Steinberger
d389a52494 fix(ui): centralize invalid date formatting 2026-05-30 07:07:13 -04:00
Vincent Koc
346b14a51a fix(test): route conventional script tests 2026-05-30 13:00:33 +02:00
Vincent Koc
ffa2da8478 fix(test): skip broad changed import scans 2026-05-30 13:00:33 +02:00
Vincent Koc
61a768be75 fix(test): route script library changes 2026-05-30 13:00:33 +02:00
Vincent Koc
3d8a77a113 fix(test): route package tooling changes 2026-05-30 13:00:33 +02:00
Vincent Koc
a6a358f1a6 fix(test): route ci tooling changes 2026-05-30 13:00:33 +02:00
Vincent Koc
131dc4eaeb fix(test): route workflow helper changes 2026-05-30 13:00:33 +02:00
Vincent Koc
022fd55bad fix(test): route crabbox changed tests 2026-05-30 13:00:33 +02:00
Vincent Koc
d9820e4098 fix(ci): disable crabbox on-demand fallback 2026-05-30 13:00:33 +02:00
Vincent Koc
a4ebdc9aa1 fix(test): guard run-with-env help 2026-05-30 13:00:32 +02:00
Vincent Koc
cf2461f7f6 fix(test): guard live runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
f5f829db79 fix(test): guard tsdown runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
a06daab97e fix(test): guard build runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
09f094057a fix(test): guard verify runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
9def042fab fix(test): guard check runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
f6adea5757 fix(test): guard force runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
78f4a5c05f fix(tooling): ignore inline type-only re-exports 2026-05-30 13:00:32 +02:00
Vincent Koc
731a7af9c5 fix(test): keep wrapper help metadata-only 2026-05-30 13:00:32 +02:00
Vincent Koc
ffa4342a6a fix(test): route docker e2e script targets 2026-05-30 13:00:32 +02:00
Vincent Koc
550a134cf9 fix(tooling): forward oxlint shard cancellation 2026-05-30 13:00:32 +02:00
Vincent Koc
1b43e84d0d fix(test): batch explicit source route resolution 2026-05-30 13:00:32 +02:00
Vincent Koc
31f0635f4f fix(test): route explicit source targets narrowly 2026-05-30 13:00:31 +02:00
Vincent Koc
1c65e2e7c1 fix(tooling): bound oxlint shard stalls 2026-05-30 13:00:31 +02:00
Vincent Koc
b6f3fe7938 fix(test): route explicit helper targets narrowly 2026-05-30 13:00:31 +02:00
Vincent Koc
d65b3a68aa perf(cli): keep plugins JSON list on snapshot path 2026-05-30 13:00:31 +02:00
Vincent Koc
e2b54fecd8 fix(doctor): reuse lazy state migration import 2026-05-30 13:00:31 +02:00
Vincent Koc
b8067d073a fix(extensions): keep subagent hook facades lazy 2026-05-30 13:00:31 +02:00
Vincent Koc
e420c001d0 perf(policy): cache doctor file reads 2026-05-30 13:00:31 +02:00
Vincent Koc
44b6b79a66 perf(plugin-sdk): cache runtime helper imports 2026-05-30 13:00:31 +02:00
Vincent Koc
3ef2935ac9 perf(browser): reuse chrome mcp import 2026-05-30 13:00:31 +02:00
Vincent Koc
fced29de17 perf(extensions): cache meeting runtime loaders 2026-05-30 13:00:31 +02:00
Vincent Koc
4f074c3235 perf(extensions): cache plugin runtime loaders 2026-05-30 13:00:31 +02:00
Vincent Koc
5df00520cb perf(extensions): cache provider runtime imports 2026-05-30 13:00:30 +02:00
Vincent Koc
b2c85bc0a2 perf(browser): cache registration runtime import 2026-05-30 13:00:30 +02:00
Vincent Koc
5e2e78a75a perf(wizard): cache setup migration imports 2026-05-30 13:00:30 +02:00
Vincent Koc
2196f107da perf(gateway): cache post-attach startup imports 2026-05-30 13:00:30 +02:00
Vincent Koc
ff56a2d7b3 perf(gateway): cache plugin bootstrap imports 2026-05-30 13:00:30 +02:00
Vincent Koc
24cff8a3bc perf(gateway): share model catalog module loader 2026-05-30 13:00:30 +02:00
Vincent Koc
b495ac2abb perf(gateway): cache remote skills startup import 2026-05-30 13:00:30 +02:00
Vincent Koc
3f2585424d perf(gateway): cache plugin HTTP imports 2026-05-30 13:00:30 +02:00
Vincent Koc
9d1a3007d9 perf(gateway): cache model catalog imports 2026-05-30 13:00:30 +02:00
Vincent Koc
b5c163dffa test(doctor): complete browser health mock 2026-05-30 13:00:30 +02:00
Vincent Koc
ee0cf9e5bb perf(gateway): cache session event imports 2026-05-30 13:00:30 +02:00
Vincent Koc
37fdfa0e0b perf(doctor): cache health contribution imports 2026-05-30 13:00:30 +02:00
Vincent Koc
d550b804b8 perf(doctor): cache core check imports 2026-05-30 13:00:30 +02:00
Vincent Koc
05988500bc perf(crestodian): cache operation imports 2026-05-30 13:00:29 +02:00
Vincent Koc
b01290cf64 perf(cli): cache command ownership imports 2026-05-30 13:00:29 +02:00
Vincent Koc
117f6fb254 test(agents): complete provider runtime mock 2026-05-30 13:00:29 +02:00
Vincent Koc
c363816fea perf(cli): cache runtime startup imports 2026-05-30 13:00:29 +02:00
Vincent Koc
aeed31cdb1 perf(cli): cache root help imports 2026-05-30 13:00:29 +02:00
Vincent Koc
58c8c022c5 perf(entry): cache root help module imports 2026-05-30 13:00:29 +02:00
Vincent Koc
2cfae61743 perf(onboarding): split ClawHub install error codes 2026-05-30 13:00:29 +02:00
Vincent Koc
c6b4daf426 perf(health): remove duplicate config import 2026-05-30 13:00:29 +02:00
Vincent Koc
348fabe04d perf(auto-reply): remove reset model duplicate import 2026-05-30 13:00:29 +02:00
Vincent Koc
6c83e8e7e4 perf(models): cache provider index catalog import 2026-05-30 13:00:29 +02:00
Vincent Koc
817b6259c4 perf(agents): cache live model runtime import 2026-05-30 13:00:29 +02:00
Vincent Koc
959af0fa5b perf(cli): cache secrets command imports 2026-05-30 13:00:29 +02:00
Vincent Koc
669b26a3dc perf(cli): cache routed command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
67c139fc36 perf(cli): cache status command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
8b6829e1bc perf(cli): cache plugin runtime imports 2026-05-30 13:00:28 +02:00
Vincent Koc
86e6fbcf52 perf(cli): cache agent bind command import 2026-05-30 13:00:28 +02:00
Vincent Koc
9b4b3aa348 perf(cli): cache plugins command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
51ab2c0d79 perf(cli): cache models runtime import 2026-05-30 13:00:28 +02:00
Vincent Koc
bdd9c70787 perf(cli): cache devices runtime import 2026-05-30 13:00:28 +02:00
Vincent Koc
1ff95ff3e6 perf(doctor): cache health config import 2026-05-30 13:00:28 +02:00
Peter Steinberger
7c5b55c5ff fix(ui): ignore invalid reset timestamps 2026-05-30 07:00:01 -04:00
Vincent Koc
b0d6076208 refactor: share setup dashboard open flow 2026-05-30 12:55:19 +02:00
Peter Steinberger
4385e57dce fix(doctor): tolerate invalid cron atMs 2026-05-30 06:54:58 -04:00
Vincent Koc
eb45c1c623 fix(scripts): report missing workflow linter fallback 2026-05-30 12:52:54 +02:00
Peter Steinberger
adf981de89 fix(imessage): tolerate invalid catchup cursor timestamps 2026-05-30 06:46:09 -04:00
Peter Steinberger
023a101b91 fix(heartbeat): tolerate invalid commitment due timestamps 2026-05-30 06:41:16 -04:00
Peter Steinberger
8b92aca27f refactor: extract media understanding common package (#88297)
* refactor: extract media understanding common package

* test: move media understanding format test
2026-05-30 12:40:49 +02:00
Peter Steinberger
b13fb788b5 fix(commitments): tolerate invalid due timestamps 2026-05-30 06:36:49 -04:00
Vincent Koc
87c0ee7685 refactor: share config observe recovery restore helpers 2026-05-30 12:35:36 +02:00
Peter Steinberger
eef32e94c7 fix(memory-wiki): tolerate invalid source mtimes 2026-05-30 06:33:13 -04:00
Peter Steinberger
1350efcfd8 fix(acp): tolerate invalid status timestamps 2026-05-30 06:27:44 -04:00
Peter Steinberger
e7ef051149 fix(slack): tolerate invalid interaction datetimes 2026-05-30 06:23:39 -04:00
Peter Steinberger
2b5ddf8f2a fix(acp): tolerate invalid session timestamps 2026-05-30 06:19:44 -04:00
Vincent Koc
6f655573d3 refactor: share parallels smoke lifecycle 2026-05-30 12:18:46 +02:00
Peter Steinberger
8aabf45ddb fix(memory-wiki): tolerate invalid chatgpt timestamps 2026-05-30 06:16:03 -04:00
Peter Steinberger
4d4748e807 fix(voice-call): tolerate invalid ended timestamps 2026-05-30 06:10:40 -04:00
Peter Steinberger
439c09668e fix(ui): ignore invalid usage export timestamps 2026-05-30 06:06:19 -04:00
Peter Steinberger
54bbe87cd5 fix(ui): ignore invalid chat export timestamps 2026-05-30 06:02:38 -04:00
Peter Steinberger
6804b7cb71 fix(matrix): ignore invalid device timestamps 2026-05-30 05:59:10 -04:00
Peter Steinberger
63470e99f0 fix(session): tolerate invalid lifecycle expiry 2026-05-30 05:53:24 -04:00
Peter Steinberger
90b0f7bd85 fix(auth): ignore invalid auth list timestamps 2026-05-30 05:49:32 -04:00
Peter Steinberger
d92b3b5cc2 refactor: unify OpenAI provider identity
Refactor OpenAI provider identity so OpenAI remains the canonical provider for API-key and OAuth-backed flows while legacy openai-codex state is doctor/migration-only.

Keeps OpenAI Codex Responses as an API/transport class rather than a provider identity, moves auth aliases through providerAuthAliases, updates doctor repair sequencing for old auth/profile state, and refreshes tests/docs around the canonical OpenAI behavior.
2026-05-30 11:48:41 +02:00
Vincent Koc
4d0668a546 refactor: share proxy capture event recording 2026-05-30 11:47:45 +02:00
Peter Steinberger
2c0f79d53a fix(status): tolerate invalid retained task cleanup 2026-05-30 05:45:18 -04:00
Peter Steinberger
5374c7a8a2 Persist subagent registry in SQLite (#88260)
* fix(agents): persist subagent registry in sqlite

* test(agents): mock sqlite subagent registry in loop guard
2026-05-30 11:44:11 +02:00
Vincent Koc
35ce103378 fix(agents): harden autoreview Windows harness (#88284) 2026-05-30 10:43:52 +01:00
Peter Steinberger
029c17de41 fix(tasks): tolerate invalid flow timestamps 2026-05-30 05:41:26 -04:00
Marvinthebored
6b41a0692f fix(plugins): preserve single-pass plugin env config
Resolve raw plugin config environment references before plugin discovery and validation, while preserving the existing single-pass behavior for configs already loaded through config IO.

The loader now resolves raw config opt-ins with config.env vars included, bypasses active/cache reuse for that mode, and redacts plugin entry config from raw-mode cache keys so resolved secrets do not enter registry keys or reentry errors.

Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/loader.test.ts src/plugins/loader.runtime-registry.test.ts
- autoreview --mode branch --base origin/main
- pnpm check:changed on Blacksmith Testbox tbx_01ksw36bp7zygwxgq3jcsvjv3b / GitHub Actions run 26680322889
- PR CI green on facb77634e

Co-authored-by: Peter Lindsey <peter@lindsey.jp>
2026-05-30 11:39:15 +02:00
NianJiu
da5d1a6215 feat(xiaomi): add Token Plan provider support
Adds first-class Xiaomi Token Plan provider support with regional onboarding/configuration, token-plan key prefix validation, runtime pricing/catalog metadata, and docs/test coverage.

Keeps Token Plan model catalog discovery runtime-owned so region-specific base URLs are required and the provider cannot silently fall back to the static SGP manifest catalog.

Fixes #86169.

Verification:
- node scripts/run-vitest.mjs src/plugins/provider-discovery.runtime.test.ts extensions/xiaomi/index.test.ts src/plugins/manifest-model-catalog.test.ts src/model-catalog/manifest-planner.test.ts
- git diff --check
- autoreview --mode local: clean, no accepted/actionable findings
- CI run 26678998539: all relevant checks passed; check-prod-types failed on unrelated browser unused-function issue already present on origin/main

Co-authored-by: NianJiuZst <3235467914@qq.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 11:37:36 +02:00
Peter Steinberger
f72762ae8f fix(tasks): tolerate invalid task timestamps 2026-05-30 05:36:31 -04:00
Peter Steinberger
0185d0d2ac fix(telegram): ignore invalid forwarded timestamps 2026-05-30 05:32:53 -04:00
Vincent Koc
82fe55acac refactor: share workboard card tool helpers 2026-05-30 11:31:40 +02:00
Peter Steinberger
28eb4cfa12 fix(codex): ignore invalid history timestamps 2026-05-30 05:28:14 -04:00
Peter Steinberger
a9cbec912e fix(minimax): validate oauth authorization expiry 2026-05-30 05:23:53 -04:00
Peter Steinberger
095bc6d4b4 fix(google-meet): refresh invalid cached oauth expiries 2026-05-30 05:18:21 -04:00
Vincent Koc
b72853a742 refactor: share native approval route gates 2026-05-30 11:15:49 +02:00
Peter Steinberger
4f784b5d47 fix(auth): reject invalid oauth expiry dates 2026-05-30 05:14:49 -04:00
Peter Steinberger
ff2a99b22e fix(codex): ignore invalid rate limit reset dates 2026-05-30 05:10:50 -04:00
Peter Steinberger
de1dfab03e refactor: move terminal core into package (#88279)
* refactor: move terminal core into package

* refactor: move terminal module files

* fix: clean terminal package CI followups

* test: update lint suppression allowlist

* fix: ship terminal core runtime aliases
2026-05-30 11:07:45 +02:00
Peter Steinberger
7b699fddac fix(auth): guard codex jwt expiry timestamps 2026-05-30 05:03:03 -04:00
Peter Steinberger
7854f547ce fix(agents): cap compaction retry timeout 2026-05-30 04:59:11 -04:00
Peter Steinberger
e64d713e41 fix(workboard): cap duration arithmetic 2026-05-30 04:56:14 -04:00
Vincent Koc
8348af99e8 fix(ci): clear stale changed-check failures 2026-05-30 09:55:59 +01:00
Peter Steinberger
b1958256fd fix(memory): cap embedding timeouts 2026-05-30 04:48:15 -04:00
Peter Steinberger
65fc5d1c5d fix(voice-call): cap manager timer delays 2026-05-30 04:45:06 -04:00
Vincent Koc
b19584b25e refactor: share runtime plugin install flow 2026-05-30 10:43:33 +02:00
Peter Steinberger
069ea7942d fix(browser): cap proxy request timeouts 2026-05-30 04:39:55 -04:00
Peter Steinberger
5d75f64369 fix(browser): cap cdp reachability timeouts 2026-05-30 04:36:23 -04:00
Peter Steinberger
7666d71fab fix(media): cap understanding timeouts 2026-05-30 04:32:21 -04:00
Vincent Koc
25affd6584 refactor: share subagent attachment preparation 2026-05-30 10:27:03 +02:00
Peter Steinberger
d8db7f561e fix(sandbox): cap browser autostart timeout 2026-05-30 04:26:41 -04:00
Peter Steinberger
26ef325219 fix(gateway): cap node invoke timers 2026-05-30 04:21:43 -04:00
Peter Steinberger
86311b0e00 fix(release): harden Parallels Discord smoke 2026-05-30 09:20:11 +01:00
Peter Steinberger
b09cab4ebd fix(whatsapp): cap QR login timers 2026-05-30 04:16:36 -04:00
Peter Steinberger
7d71c5d0c6 fix(gateway): cap node reconnect wait timers 2026-05-30 04:11:02 -04:00
Vincent Koc
b13529767b refactor: share inline image data URL sanitizer 2026-05-30 10:08:54 +02:00
Peter Steinberger
cc42367f3f fix(agents): cap plugin approval timeouts 2026-05-30 04:06:45 -04:00
Peter Steinberger
915f88a0a3 fix(browser): centralize route timeout clamping 2026-05-30 03:59:45 -04:00
Peter Steinberger
cec50aa047 fix(browser): cap act action timeouts 2026-05-30 03:52:29 -04:00
Peter Steinberger
fc90f0f15c fix(qa-matrix): cap live timeout env 2026-05-30 03:47:22 -04:00
Vincent Koc
0d4828497e refactor: share respawn child runner 2026-05-30 09:44:20 +02:00
Peter Steinberger
aae0d54752 fix(browser): cap Chrome MCP navigation timeout grace 2026-05-30 03:41:53 -04:00
Peter Steinberger
650027106b fix(google-meet): share operation timeout clamp 2026-05-30 03:36:20 -04:00
Peter Steinberger
99ffd714ce refactor: extract markdown core package (#88265)
* refactor: extract markdown core package

* refactor: remove old markdown sources

* fix: use source paths for markdown core imports

* fix: clean markdown package dependency ownership

* fix: refresh root shrinkwrap for markdown dependency move
2026-05-30 09:33:24 +02:00
Vincent Koc
0f8ea1d3d9 fix(build): skip tsx preload for metadata help 2026-05-30 09:30:55 +02:00
Peter Steinberger
8d8f5a59e2 fix(agents): cap overflowed wait timeout grace 2026-05-30 03:30:42 -04:00
keshavbotagent
fcf2852f0f fix(codex): prevent post-tool edit stream timeouts
Keep Codex post-tool assistant/commentary progress and patch snapshot updates on the post-tool completion guard so long generated edits do not fall back to terminal idle handling. Enable Codex patch streaming events for native code mode and refresh exact prompt/config expectations.

Verification:
- pnpm prompt:snapshots:check
- pnpm test extensions/codex/src/app-server/run-attempt.turn-watches.test.ts extensions/codex/src/app-server/thread-lifecycle.test.ts extensions/codex/src/app-server/thread-lifecycle.binding.test.ts extensions/codex/src/app-server/side-question.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- git diff --check origin/main...HEAD
- exact-head CI run 26677938955
- Real behavior proof override run 26678097960

Thanks @keshavbotagent.

Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
2026-05-30 09:30:09 +02:00
Vincent Koc
7054aa562e refactor: share manifest capability availability checks 2026-05-30 09:24:08 +02:00
Peter Steinberger
dad8cfaf74 fix(runtime): reuse timeout grace for voice and memory 2026-05-30 03:21:14 -04:00
Peter Steinberger
5f4fc7512e fix(runtime): centralize timeout grace clamping 2026-05-30 03:15:50 -04:00
Peter Steinberger
530351e394 fix(codex): stop injecting mirrored history into prompts
Stop Codex app-server turns from projecting mirrored OpenClaw transcript history into prompt/model-input surfaces by default. Keep context-engine output on the rendered prompt/developer-instruction path and preserve mirrored history only for OpenClaw-side snapshots.
2026-05-30 09:13:38 +02:00
Peter Steinberger
f52355ce5f fix(google-meet): cap CLI timeout options 2026-05-30 03:07:16 -04:00
Vincent Koc
9b605846bb refactor: share ACP metadata readers 2026-05-30 09:06:19 +02:00
Peter Steinberger
26bf8f0dc8 fix(voice-call): cap CLI gateway timeouts 2026-05-30 03:00:14 -04:00
Dmitry Golubev
3fbd2432b6 fix(codex): move stable context to developer instructions
Move OpenClaw skills and the routed workspace-memory pointer out of native Codex turn user input and into turn-scoped collaboration developer instructions.

Preserve full MEMORY.md fallback prompt injection, delivery-hint rewrapping, lightweight cron exact prompts, and trajectory reporting for the rendered developer surface.

Co-authored-by: Beru <beru@lastguru.lv>
2026-05-30 08:59:02 +02:00
Peter Steinberger
f90b8cffc7 perf: prefer built plugin public surfaces 2026-05-30 07:54:30 +01:00
Peter Steinberger
1ac037d948 fix(memory): cap qmd search process timeouts 2026-05-30 02:54:11 -04:00
Vincent Koc
45c4f1edd4 refactor: share task registry sqlite helpers 2026-05-30 08:49:19 +02:00
Peter Steinberger
be76841143 fix(agents): cap bash tool timeouts 2026-05-30 02:48:06 -04:00
Peter Steinberger
89e64f70c1 fix: accept bare goal objectives 2026-05-30 08:46:09 +02:00
Vincent Koc
e35db953eb fix(build): raise inherited tsdown heap caps 2026-05-30 08:45:43 +02:00
Peter Steinberger
032945a5cd fix(codex): cap approval gateway timeouts 2026-05-30 02:44:14 -04:00
Peter Steinberger
f61a5bc797 feat(workboard): add board ops recovery metadata
Add board-scoped Workboard metadata, stats, and recovery operations.\n\nIncludes gateway/tool contracts, docs, UI normalization, and regression coverage for board-scoped idempotency, linked child manifests, recovery diagnostics, and worker context.
2026-05-30 08:43:58 +02:00
Peter Steinberger
0915b72bcf docs: expand provider descriptions 2026-05-30 07:41:59 +01:00
Peter Steinberger
7840fdbada fix(agent-core): cap shell exec timeouts 2026-05-30 02:40:32 -04:00
Peter Steinberger
4abde61366 fix(qa-lab): cap gateway wait timeouts 2026-05-30 02:33:11 -04:00
Vincent Koc
4291e32777 refactor: share OpenRouter video mode capabilities 2026-05-30 08:28:41 +02:00
Vincent Koc
453f40d5bf fix(testing): mark gauntlet cold-start observations 2026-05-30 08:26:41 +02:00
Peter Steinberger
470fc879e8 feat: add hosted model providers (#88247)
* feat(providers): add GMI provider

* feat(providers): add Novita provider

* feat(providers): add Qwen OAuth provider

* feat(providers): add Ollama Cloud provider

* docs: add hosted provider pages

* test(providers): align qwen catalog result typing
2026-05-30 08:26:16 +02:00
Peter Steinberger
311c1a05eb fix(plugins): cap CLI node invoke timeout 2026-05-30 02:25:18 -04:00
Peter Steinberger
7c3d7fc6e3 fix(memory): cap retry sleep delays 2026-05-30 02:21:24 -04:00
Vincent Koc
94df665cdc refactor: share Discord outbound payload options 2026-05-30 08:18:23 +02:00
Peter Steinberger
7c1484d637 refactor: extract media generation core package
Extract pure media generation catalog/model-ref/normalization helpers into a private workspace package and wire the package through build, watch, SDK alias, and plugin boundary d.ts paths.

Verification:
- node scripts/run-vitest.mjs test/scripts/crabbox-wrapper.test.ts packages/media-generation-core/src src/media-generation/runtime-shared.test.ts src/plugins/sdk-alias.test.ts src/infra/watch-node.test.ts src/plugins/registry.provider-like.test.ts src/agents/model-ref-shared.test.ts extensions/codex-supervisor/src/plugin-tools.test.ts extensions/codex-supervisor/src/supervisor.test.ts src/wizard/setup.official-plugins.test.ts src/infra/net/http-connect-tunnel.test.ts
- node scripts/prepare-extension-package-boundary-artifacts.mjs --mode=all
- node scripts/run-vitest.mjs src/plugins/contracts/extension-package-project-boundaries.test.ts src/plugins/sdk-alias.test.ts
- pnpm protocol:check
- pnpm check:changed
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI 26676608512
2026-05-30 08:17:43 +02:00
Peter Steinberger
be2c43ee3e fix(llm): cap codex retry delays 2026-05-30 02:17:30 -04:00
Peter Steinberger
5aa2bd7921 fix(agents): cap subagent context TTLs 2026-05-30 02:12:45 -04:00
Peter Steinberger
0a7ecd5428 fix(release): verify plugin npm readmes 2026-05-30 07:12:21 +01:00
Peter Steinberger
5db2cd6c00 perf: skip session store clones in turn hot paths 2026-05-30 07:11:03 +01:00
Jason (Json)
81505ada18 fix(codex): rotate native threads before overflow
Fix Codex app-server native thread overflow recovery and CLI compaction fallback.

- rotate Codex native startup bindings when rollout token pressure leaves too little headroom
- keep byte-size rollout fuses ahead of rollout content reads
- clear stale resumed context-engine bindings only when the stored thread id still matches
- fall back to context-engine compaction when Codex owns/skips native compaction

Verification:
- node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-codex.config.ts extensions/codex/src/app-server/startup-binding.test.ts extensions/codex/src/app-server/run-attempt.context-engine.test.ts extensions/codex/src/app-server/session-binding.test.ts --reporter=verbose
- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts src/agents/command/cli-compaction.test.ts --reporter=verbose
- git diff --check origin/main...HEAD
- autoreview --mode branch --base origin/main: clean
- GitHub CI for 466bfbe78c: green

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-30 08:07:29 +02:00
Peter Steinberger
8edeba0de3 fix(agents): cap provider request timeouts 2026-05-30 02:07:14 -04:00
Peter Steinberger
beb42b12c9 refactor(agents): type media completion delivery misses (#88250) 2026-05-30 08:04:50 +02:00
Peter Steinberger
42b320ad65 fix(cron): cap explicit job timeouts 2026-05-30 02:00:52 -04:00
Peter Steinberger
bba8015688 fix: show chat errors as visible messages
Surface gateway chat failures as visible assistant messages in the Control UI, with regression coverage and Crabbox/WebVNC proof.
2026-05-30 07:57:18 +02:00
Peter Steinberger
05e31bbedd refactor(agents): reuse terminal outcome for subagent waits 2026-05-30 06:56:52 +01:00
Peter Steinberger
c806a736af fix(agents): cap session wait timeouts 2026-05-30 01:56:44 -04:00
Vincent Koc
ceb179f84d refactor: share web search time filters 2026-05-30 07:53:51 +02:00
Peter Steinberger
72a2cc0acb chore(release): refresh generated release metadata 2026-05-30 06:51:37 +01:00
Peter Steinberger
cd07d013ba chore(release): bump version to 2026.5.30 2026-05-30 06:49:13 +01:00
Peter Steinberger
afa6d0cd18 fix(web): cap provider timeout seconds 2026-05-30 01:47:06 -04:00
Peter Steinberger
aa0d6e1bca refactor: extract LLM core packages (#88117)
* refactor: extract llm core packages

* chore: drop generated llm package artifacts

* fix: align llm package export artifacts

* test: fix moving main CI expectations

* fix: align llm core subpath aliases

* fix: use llm package exports

* fix: stabilize llm package boundary artifacts

* fix: sync llm boundary path contract

* test: isolate crabbox provider env

* test: pin crabbox configured-provider cases

* test: apply crabbox lease provider override
2026-05-30 07:45:04 +02:00
Vincent Koc
17e75f8641 test(e2e): expose bundled plugin lifecycle timing 2026-05-30 07:42:42 +02:00
Peter Steinberger
d69ee6777d fix(telegram): cap configured request timeouts 2026-05-30 01:42:01 -04:00
Peter Steinberger
344aff383b fix(acpx): cap service timer timeouts 2026-05-30 01:36:33 -04:00
Peter Steinberger
56f46a2581 fix(copilot): avoid bundling platform binaries 2026-05-30 06:34:48 +01:00
Peter Steinberger
62abfd3dcb fix(codex): cap app-server idle timers 2026-05-30 01:31:57 -04:00
Peter Steinberger
c536bd6af1 fix(agents): cap exec reviewer timeout 2026-05-30 01:29:05 -04:00
Peter Steinberger
fcdc25ba64 test: dedupe redundant test coverage 2026-05-30 06:27:13 +01:00
Peter Steinberger
9090f6b1c4 fix(comfy): cap workflow polling timeouts 2026-05-30 01:18:06 -04:00
Vincent Koc
0d604f160d refactor: share OpenAI realtime transcription payload 2026-05-30 07:02:12 +02:00
Nimrod Gutman
b352cb2d8e fix(ios): guard websocket ping continuation (#88231)
Merged via squash.

Prepared head SHA: b4cee97b8a
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-30 07:56:34 +03:00
Vincent Koc
b9933b2ec1 refactor: share Discord account token inspection 2026-05-30 06:47:40 +02:00
Ayaan Zaidi
f848a6f7f7 perf(agents): bound claude orphan transcript scan 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
72eff6b2e9 fix(agents): clear orphan tool state on string assistant turns 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
56fc17be78 fix(agents): avoid cli facade load in flush gate 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
3c3e39684e test(agents): cover flushed cli context engine session 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
25dfe9294f fix(agents): pass workspace to cli flush probe 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
622404fcec fix(agents): detect claude-specific orphaned tools 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
bda02f4be8 fix(agents): scope cli binding clears 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
58de6f91dc fix(auto-reply): clear unflushed cli bindings 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
c0a5f15dc8 fix(agents): clear unflushed cli bindings 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
21b5f601b6 fix(agents): preserve auth-boundary cli invalidation 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
2e21158d04 refactor(agents): simplify cli session recovery probes 2026-05-30 10:09:19 +05:30
Abdel Gomez-Perez
16b510807b fix(agents/cli-runner): invalidate sessions whose transcript ends mid-tool
A claude-cli session whose JSONL transcript ends with an assistant
`tool_use` content block that was never answered by a `tool_result` user
message cannot resume — claude-cli will sit waiting for the missing
`tool_result`, hit its no-output watchdog, and the runtime kills it
with `reason=abort`. The dispatcher then sees an empty payload and emits
NO_REPLY, which to the user looks like the agent silently ignored their
message — same end-user symptom as the binding-flush amnesia bug, but a
different root cause.

The orphan can be left behind when:
  - Gateway restarts mid-tool (brew upgrade, manual kickstart, OOM,
    crash) — claude was waiting on a tool result that never arrived.
  - `claude-live-session.ts` no-output watchdog fires while a tool is
    actively running and OC kills the subprocess.
  - The tool itself crashed or hung past its own deadline.

In all cases the resumed session is dead until the binding gets cleared,
because every subsequent resume hits the same trailing tool_use and the
same kill cycle. Observed in production on a personal OpenClaw gateway
(3d-engineer agent, 50-message-deep transcript ending in a Bash
`tool_use`; every Telegram message after the orphan landed silently
aborted at the 180s no-output mark).

Add `claudeCliSessionTranscriptHasOrphanedToolUse` to the helpers that
walks the JSONL, finds the last assistant message, and returns true if
any of its `tool_use` ids has no matching `tool_result` later in the
file. Wire into `prepareCliRunContext` as a second invalidator gate
alongside `missing-transcript`. The new `invalidatedReason:
"orphaned-tool-use"` follows the same path as missing-transcript: the
binding is dropped, this turn starts a fresh session, and the prior
context is reseeded into the new session via `RAW_TRANSCRIPT_RESEED`.

Detection only considers TRAILING orphans — an unanswered tool_use
deeper in history is inert because a later assistant message already
moved past it. Only the most recent assistant message's tool_use ids
matter for forward progress.

Probe runs only for claude-cli providers and only when the transcript-
content gate already passed, so we add no I/O on already-invalidated
sessions and no behavior change for non-claude providers.

AI-assisted: yes. Tooling: Claude Opus + claude-cli.
2026-05-30 10:09:19 +05:30
Abdel Gomez-Perez
07c1245db4 fix(agents/cli-runner): gate cliSessionBinding persist on transcript flush
When a claude-cli turn produces a session id but the underlying claude
subprocess fails to flush an assistant-role record to its
~/.claude/projects/<cwd>/<sid>.jsonl transcript (e.g. mid-turn kill from
a concurrent fingerprint-mismatched turn, supervisor restart, internal
failure), buildCliRunResult was still persisting that session id into
cliSessionBinding. The next turn ran claudeCliSessionTranscriptHasContent,
didn't find the file, logged 'cli session reset: reason=missing-transcript',
and started a brand-new claude session with empty memory.

End-user symptom: agent forgets prior conversation between turns.

Gate the cliSessionBinding spread on the same predicate the next-turn
invalidator uses, evaluated at write time. Also clear agentMeta.sessionId
in the same case so the session-store fallback at command/session-store.ts
(which reads agentMeta.sessionId via setCliSessionId when the binding is
absent) doesn't re-persist the unflushed sid through a different field
path. The fallback is what makes the binding-only gate insufficient on
its own; both writes must drop together.

The gate only fires for claude-cli providers — other CLI providers don't
write to ~/.claude/projects, so probing them would always return false
and incorrectly strip valid binding metadata. isCliBindingFlushed now
takes the provider id and returns true unconditionally for non-claude-cli
sessions.

A bounded retry (0 / 50 / 150 ms) tolerates the brief gap between
claude-cli's stdio close and the OS making the JSONL line visible to
readers (cooperative fsync semantics on APFS, but not guaranteed under
stress).

The transcript-probe is exposed as an injectable dep
(setCliRunnerTestDeps / restoreCliRunnerTestDeps) mirroring the existing
pattern in src/agents/cli-runner/prepare.ts so isCliBindingFlushed is
testable without touching ~/.claude/projects.

AI-assisted: yes. Tooling: Claude Opus + claude-cli. Codex review caught
the fallback path and the missing provider gate before this hit upstream.
Real-Behavior-Proof: dist-side patch on M5 gateway; branch-build
follow-up pending — see PR body.
2026-05-30 10:09:19 +05:30
Vincent Koc
d13c8b03c9 refactor: share Google Meet audio input loop 2026-05-30 06:34:06 +02:00
Vincent Koc
7b3104fe4c chore(crabbox): default runner billing to azure 2026-05-30 06:25:35 +02:00
Vincent Koc
8fa4c4ff4e test(e2e): print MCP Docker proof logs 2026-05-30 06:24:58 +02:00
Vincent Koc
67ddc1a3e1 refactor: share Google Chat plugin base 2026-05-30 06:11:31 +02:00
Vincent Koc
a17487bc9f refactor: share QA channel plugin base 2026-05-30 06:05:36 +02:00
Marcus Castro
f613f32b22 fix(whatsapp): retry QR login 408 timeouts (#88183) 2026-05-30 00:59:12 -03:00
Vincent Koc
03415bb696 refactor: share MSTeams outbound send resolvers 2026-05-30 05:53:39 +02:00
Vincent Koc
723b5085d9 fix(dev): reject closed gateway websocket calls 2026-05-30 05:46:19 +02:00
Vincent Koc
28ffcf88bd refactor: share Slack approval block helpers 2026-05-30 05:43:30 +02:00
Dallin Romney
7de025eacd fix: route explicit vitest files through project runner (#88127) 2026-05-29 20:38:52 -07:00
Ayaan Zaidi
1659b26151 fix(agent): allow media retry after blocked delivery 2026-05-30 09:07:53 +05:30
Ayaan Zaidi
c88178d9b6 fix(agent): recover media completion delivery 2026-05-30 09:07:53 +05:30
Vincent Koc
117af11a6f fix(test): route tooling vitest files narrowly 2026-05-30 05:32:13 +02:00
Vincent Koc
b5bae67aad refactor: share Telegram outbound send context 2026-05-30 05:28:50 +02:00
Vincent Koc
0fdc51f35d fix(e2e): bound secret provider readiness probes 2026-05-30 05:19:49 +02:00
Vincent Koc
a1c6882777 refactor: share Discord agent component controls 2026-05-30 05:04:15 +02:00
Vincent Koc
59c84f8e5c refactor: share WhatsApp media send state 2026-05-30 04:56:07 +02:00
Peter Steinberger
d115fb4cf9 refactor: move task state to shared sqlite
Move task run, delivery, and flow registry persistence onto the shared OpenClaw state SQLite database.

Summary:
- Store task runs, delivery state, and flow runs in state/openclaw.sqlite via the generated Kysely schema.
- Migrate shipped task sidecars into the shared state DB and archive old sidecars, including invalid-config/read-only CLI paths.
- Keep startup migration lightweight for read-only status/tasks paths while still detecting known legacy state markers and custom session stores.

Verification:
- .agents/skills/autoreview/scripts/autoreview --mode local: clean after final fix
- pnpm test src/tasks/task-registry.store.test.ts src/tasks/task-flow-registry.store.test.ts src/commands/doctor-state-migrations.test.ts -- --reporter=verbose
- pnpm test src/commands/doctor-state-migrations.test.ts src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-path-policy.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-startup-policy.test.ts src/cli/command-path-policy.test.ts src/cli/command-execution-startup.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/argv.test.ts src/cli/route.test.ts src/commands/doctor-config-preflight.state-migration.test.ts -- --reporter=verbose
- pnpm test src/tasks/task-flow-registry.store.test.ts -- --reporter=verbose
- pnpm test test/scripts/lint-suppressions.test.ts -- --reporter=verbose
- pnpm db:kysely:check
- pnpm lint:kysely
- git diff --check HEAD
- pnpm test:startup:memory
- PR CI green on 2f7d76f0d5
2026-05-30 04:54:37 +02:00
Vincent Koc
e9dee8dfe1 refactor: share harness truncation result helpers 2026-05-30 04:41:49 +02:00
Vincent Koc
9f30af5a96 fix(e2e): bound bundled plugin readiness probes 2026-05-30 04:38:21 +02:00
Dallin Romney
29b32050c1 feat(ci): autoscrub dependency lockfile-only PR changes (#87796)
* ci: autoscrub dependency lockfile residue

* ci: harden dependency autoscrub commits

* ci: scope dependency autoscrub tokens

* ci: split autoscrub base reads

* ci: expand autoscrub proof comment
2026-05-29 19:37:16 -07:00
Vincent Koc
815ffb3bb2 refactor: share Codex thread binding flow 2026-05-30 04:27:24 +02:00
Vincent Koc
440e737c67 fix(e2e): stop credential retries after deadline 2026-05-30 04:21:01 +02:00
Dallin Romney
784fbcfd16 ci: relax platform checkout fetch timeout (#88199) 2026-05-29 19:17:29 -07:00
Josh Avant
584fa3215c Fix restart sentinel internal continuations (#88161)
* fix restart sentinel internal continuations

* update gateway prompt snapshots

* stabilize sandbox browser audit timer tests

* drive sandbox audit timeouts deterministically

* drive gh-read timeout tests deterministically

* drive label-open-issues timeout tests deterministically

* document deterministic timeout test timers

* test: preserve deterministic timer setup after rebase
2026-05-29 19:06:54 -07:00
Kevin Lin
dc4f3b57cf fix(imessage): preserve SMS approval reply routes
Preserve iMessage SMS reply routes for approval replies so a direct SMS /approve response can acknowledge and return results to the same SMS conversation.

Verification: gateway-only build, extension type checks, CI build-artifacts/check-prod-types/check-test-types/check-lint/check-additional-extension-package-boundary, and live prod iMessage SMS approval proof. checks-node-core-fast was waived by maintainer request after unrelated flaky failures in non-iMessage tests.
2026-05-29 19:00:45 -07:00
Vincent Koc
985b41e136 refactor: share Codex auth identity helpers 2026-05-30 03:57:20 +02:00
Vincent Koc
51d0ef80c2 fix(e2e): bound kitchen sink readiness probes 2026-05-30 03:54:47 +02:00
Josh Avant
f870beac85 fix(codex): project raw image generation media (#88191) 2026-05-29 18:50:11 -07:00
Vincent Koc
75de853c37 refactor: share provider OAuth runtime helpers 2026-05-30 03:30:51 +02:00
Josh Avant
b3b962a051 fix subagent dm completion delivery (#88182) 2026-05-29 18:24:49 -07:00
Vincent Koc
6f3f4f7420 fix(dev): stop discord smoke retries past deadline 2026-05-30 03:15:29 +02:00
Peter Steinberger
acb0e9c155 fix(agents): extend terminal outcome projections (#88162)
* fix(agents): extend terminal outcome projections

* fix(agents): align terminal outcome follow-up checks

* fix(agents): satisfy terminal outcome mapper lint

* test(scripts): isolate websocket open timers

* test(security): drive sandbox browser timeout timers

* test(scripts): drive gh-read timeout timers

* test(agents): isolate code mode timers

* fix(agents): preserve hard timeouts on wait surfaces

* fix(agents): require timeout attribution for provider errors

* fix(sdk): require timeout attribution for provider errors

* fix(scripts): preserve changelog parse cause
2026-05-30 03:13:01 +02:00
Vincent Koc
be1c4f3ee1 fix(release): preserve changelog restore cause 2026-05-30 03:08:04 +02:00
Vincent Koc
deb48a96fb refactor: share prompt template arguments 2026-05-30 03:05:46 +02:00
Vincent Koc
086df266cc fix(release): guard package changelog restore 2026-05-30 03:01:27 +02:00
Vincent Koc
730aa406ef fix(ui): abort orphaned workboard runs 2026-05-30 02:52:20 +02:00
Vincent Koc
1a4eb0b5e7 refactor: share agent truncate utilities 2026-05-30 02:46:45 +02:00
Peter Steinberger
4be8a58a7d test(ci): isolate infra vitest lane 2026-05-30 02:46:35 +02:00
Peter Steinberger
a341ae27ec feat(workboard): add orchestration primitives
Adds Workboard orchestration statuses, dependency links, idempotent child creation, dispatch, and complete/block lifecycle operations backed by the plugin SQLite keyed store.

Persists tenant, skills, workspace, schedule, runtime, retry, dispatch, and handoff metadata in card records, with claim scoping and token redaction. Surfaces the new states and metadata in the Control UI, horizontal board layout, localized strings, and Workboard docs.

Verification:
- pnpm test extensions/workboard/src/store.test.ts extensions/workboard/src/tools.test.ts extensions/workboard/src/gateway.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/styles/workboard.test.ts ui/src/ui/views/workboard.test.ts -- --reporter=verbose
- pnpm ui:i18n:check
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main, followed by focused clean local autoreview loops for final fixes
- env -u OPENCLAW_TESTBOX pnpm check:changed
- git diff --check
2026-05-30 02:40:46 +02:00
clawsweeper[bot]
18f94fc83a fix(agents): classify embedded provider business denials for fallback (#84814)
Summary:
- The PR classifies selected embedded agent provider-denial error payloads through the shared failover matcher ... 1/current-ak auth matching, preserves guarded non-fallback cases, and covers fallback progression in tests.
- PR surface: Source +34, Tests +166. Total +200 across 5 files.
- Reproducibility: yes. Current main is source-reproducible: a non-GPT embedded result whose only signal is CE ... returns null from the classifier, and the fallback wrapper treats null classification as candidate success.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): classify embedded provider business denials for fallback
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8304…

Validation:
- ClawSweeper review passed for head e266beac93.
- Required merge gates passed before the squash merge.

Prepared head SHA: e266beac93
Review: https://github.com/openclaw/openclaw/pull/84814#issuecomment-4505010446

Co-authored-by: Stellar鱼 <2182712990@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-30 00:34:28 +00:00
Peter Steinberger
aada44fca5 fix(agents): preserve Codex auth for compaction fallback
Fixes #86820.

Preserve Codex OAuth-backed compaction by selecting and loading the Codex harness before resolving direct or queued compaction models, while keeping OpenAI-compatible custom base URLs on the OpenAI context config path. Also preserves persisted concrete harness pins so compaction does not hot-switch existing sessions just because an explicit Codex fallback exists.

Verification:
- node scripts/run-vitest.mjs src/agents/embedded-agent-runner/compact.hooks.test.ts src/agents/harness/selection.test.ts src/agents/harness/runtime-plugin.test.ts
- pnpm tsgo:prod
- pnpm check:test-types
- pnpm lint --threads=8
- git diff --check origin/main...HEAD
- git diff --check
- autoreview clean: no accepted/actionable findings reported; overall patch is correct (0.82)
- GitHub PR checks green on ac6f93de4a
2026-05-30 02:26:00 +02:00
Peter Steinberger
43658872d9 test: stabilize sandbox browser audit timers 2026-05-30 01:18:53 +01:00
Dallin Romney
bd04d2db0d feat: only include the current changelog section in tarball (#88107)
* build: package current changelog section

* build: guard packaged changelog section size
2026-05-29 17:18:35 -07:00
Merlin
c8a733eae5 fix(gateway): resolve message actions against runtime config (#84535)
* fix(gateway): resolve message action config from runtime snapshot

* fix(gateway): preserve runtime config matching through auto-enable

* fix(gateway): preserve auto-enabled message action fallback

* fix(gateway): use canonical runtime snapshot for message actions

* fix(discord): route credential actions through gateway

---------

Co-authored-by: Merlin <258679497+funmerlin@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-05-29 17:14:45 -07:00
Vincent Koc
3e35f599bc refactor: collapse zalo runtime api barrel 2026-05-30 02:11:24 +02:00
Dallin Romney
914f313740 test(unit-fast): isolate fake-timer files (#88160) 2026-05-29 17:11:05 -07:00
Peter Steinberger
4efc48a80d test(ci): stabilize sandbox browser audit timeout 2026-05-30 02:06:58 +02:00
Vincent Koc
ecc5601b2a fix(github): bound proof comment API bodies 2026-05-30 01:58:19 +02:00
Peter Steinberger
14795dc0cc test: stabilize block reply abort timers 2026-05-30 00:56:15 +01:00
Peter Steinberger
05dee6760d test: stabilize tool search fetch timeout 2026-05-30 00:54:20 +01:00
Peter Steinberger
582aa1ceb2 test(ci): stabilize tool search gateway timeout helper 2026-05-30 01:49:13 +02:00
Peter Steinberger
f6e1bc393b fix(fal): cap video queue deadline 2026-05-29 19:38:41 -04:00
Peter Steinberger
c91d1048e4 fix(release): harden release ci summary lookup 2026-05-30 00:35:57 +01:00
Peter Steinberger
90994a38a0 fix(openrouter): cap music stream timeout 2026-05-29 19:34:45 -04:00
Vincent Koc
c01a0f5588 refactor: share provider oauth runtime helpers 2026-05-30 01:31:10 +02:00
Peter Steinberger
8ff61be8d6 fix(providers): cap local service timers 2026-05-29 19:29:40 -04:00
Peter Steinberger
90d569e896 fix(telegram): centralize positive timer bounds 2026-05-29 19:25:30 -04:00
Peter Steinberger
d8bc71f222 test: stabilize realtime websocket timeout 2026-05-30 00:18:02 +01:00
Peter Steinberger
f3ea2982f5 test(realtime): stabilize websocket timeout test 2026-05-30 01:15:31 +02:00
Peter Steinberger
8f389de88f fix(release): build beta smoke REST curl command 2026-05-30 00:12:11 +01:00
Peter Steinberger
2bcba64906 fix(release): avoid gh api in beta smoke 2026-05-30 00:12:11 +01:00
Peter Steinberger
cbd492d680 fix(feishu): reopen retryable bot menu replay 2026-05-30 00:12:10 +01:00
Peter Steinberger
fadd275e7b fix(release): harden candidate run status polling 2026-05-30 00:11:24 +01:00
Peter Steinberger
35a3c064a7 fix(release): avoid gh api for candidate reads 2026-05-30 00:10:05 +01:00
Peter Steinberger
91adfa1582 fix(telegram): cap polling lease wait timer 2026-05-29 19:07:40 -04:00
Vincent Koc
f3f85ae5f7 refactor: share live transport scenario helpers 2026-05-30 01:05:56 +02:00
Peter Steinberger
69550a9d3d ci: satisfy build profile lint 2026-05-30 00:05:40 +01:00
Peter Steinberger
5b8472b0b9 fix(whatsapp): cap credential flush timeout 2026-05-29 19:03:59 -04:00
Dallin Romney
73dd36626c test(infra): avoid max fake-timer jumps (#88155) 2026-05-29 16:02:41 -07:00
Peter Steinberger
83905c9169 fix(ci): repair main lint gates 2026-05-30 00:01:11 +01:00
Peter Steinberger
d92a0292a9 fix(memory): cap qmd process timeouts 2026-05-29 19:00:05 -04:00
Peter Steinberger
0e6937cc1b ci: skip bundled dts in artifact build 2026-05-29 23:56:31 +01:00
Peter Steinberger
b1e5c9d7fa fix(agents): centralize terminal run outcome precedence (#88136)
* fix(agents): centralize terminal run outcome precedence

* docs(agents): explain terminal outcome precedence

* docs(agents): note terminal outcome helper

* fix(agents): preserve pending hard timeout over late completion

* test(agents): align global session scoping expectation

* Revert "test(agents): align global session scoping expectation"

This reverts commit 9b4a0c3cb1b3885299eea7081d97f7142c415dc2.

* test(infra): stabilize CONNECT timeout cap test

* fix(agents): prioritize hard timeout terminal evidence

* fix(gateway): preserve pending hard timeout snapshots
2026-05-30 00:56:20 +02:00
Vincent Koc
ba3eae5518 fix(dev): cap Discord smoke response bodies 2026-05-30 00:54:23 +02:00
Peter Steinberger
60673b03bc fix(zalouser): cap qr login timeouts 2026-05-29 18:54:18 -04:00
Peter Steinberger
d5e8da8499 fix(ci): repair main normalization checks 2026-05-29 23:53:28 +01:00
keshavbotagent
5f89fbe669 fix(codex): recover app-server completion stalls
Fix Codex app-server completion-stall recovery so replay-safe stdio completion-idle failures retry once, while progress/terminal turn-watch timeouts only surface timeout payloads.

Also preserve post-tool completion guards for scoped native response deltas and stabilize the oversized CONNECT timeout regression test picked up from latest main.

Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
2026-05-30 00:52:48 +02:00
Peter Steinberger
bc848b367f refactor: add shared sqlite state database
Adds the shared SQLite state database base, moves plugin keyed state into it with doctor migration coverage, and keeps generated Kysely guardrails aligned. Proof: focused SQLite/plugin-state tests, db:kysely:check, lint:kysely, architecture/dependency guards, autoreview, and PR CI all clean.
2026-05-30 00:52:23 +02:00
Peter Steinberger
a6a99b923e fix(zalouser): cap probe timeout timer 2026-05-29 18:48:43 -04:00
Peter Steinberger
ccad5d7b63 fix(web): cap guarded fetch timeout seconds 2026-05-29 18:45:30 -04:00
Peter Steinberger
42b4715124 test(infra): preserve script wrapper fixture 2026-05-30 00:42:41 +02:00
Peter Steinberger
465c4cb580 test(infra): stabilize main CI tests 2026-05-30 00:42:41 +02:00
Peter Steinberger
37ccec0dc7 fix(nostr): cap profile import relay timers 2026-05-29 18:40:17 -04:00
Peter Steinberger
cb4d2e7bb9 test: stabilize infra state shard 2026-05-29 23:38:31 +01:00
Peter Steinberger
41a92ae445 perf: resolve native esm plugin sdk imports 2026-05-29 23:38:08 +01:00
Peter Steinberger
d7354d61b2 fix(channels): centralize stall watchdog timer bounds 2026-05-29 18:35:37 -04:00
Kevin Lin
c57671176e refactor: share native approval route gates
Share native approval route gate helpers across mainstream channel approval runtimes and keep PR #87770 green on current main.
2026-05-29 15:32:31 -07:00
Peter Steinberger
44e31f7c6a test(gateway): stabilize live helper shard 2026-05-30 00:31:07 +02:00
Peter Steinberger
63a06e312d ci: reduce main workflow critical path 2026-05-29 23:29:32 +01:00
Peter Steinberger
ed9e9aab3d fix(infra): cap transport readiness timeouts 2026-05-29 18:28:15 -04:00
Vincent Koc
dfe99e9cd7 refactor: share media understanding post params 2026-05-30 00:27:13 +02:00
Vincent Koc
9331ac2cb0 fix(scripts): cap issue labeler response bodies 2026-05-30 00:25:51 +02:00
Peter Steinberger
7f28c8bd07 fix: route media completions through requester agent (#88141) 2026-05-30 00:24:28 +02:00
Peter Steinberger
bafa6de76d fix(proxy): cap connect tunnel timeouts 2026-05-29 18:24:03 -04:00
Sally O'Malley
6037a74660 Add plugin manifest contract for SecretRef provider integrations (#82326)
* secret-provider-integrations

Signed-off-by: sallyom <somalley@redhat.com>

* feat(secrets): configure plugin provider presets

* secrets: use plugin-managed provider refs

Signed-off-by: sallyom <somalley@redhat.com>

* fix secretref auth profile service env

* test secret provider integration e2e

* fix secretref plugin config service env

* fix secret provider preset schema alignment

* stabilize secret provider service proof

* validate secret provider plugin integrations

* harden secret provider resolver paths

* scope secret provider config validation

* stabilize openai secret provider proof

* fix secret provider metadata proof

* stabilize config baseline proof

* fix secret provider e2e lint

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-05-29 18:20:45 -04:00
Peter Steinberger
f1235477de fix(apns): cap direct timeout paths 2026-05-29 18:18:33 -04:00
Peter Steinberger
526925c509 test: stabilize remaining CI flakes 2026-05-29 23:17:36 +01:00
Peter Steinberger
3204efc195 fix(infra): cap shell env timeouts 2026-05-29 18:11:50 -04:00
Peter Steinberger
2860da8cd5 fix(infra): cap jsonl socket timeouts 2026-05-29 18:07:19 -04:00
Peter Steinberger
8f2e520abb fix(apns): cap relay timeout 2026-05-29 18:03:41 -04:00
Peter Steinberger
fe3f2bee3f test: fix main CI regressions 2026-05-29 23:03:01 +01:00
Peter Steinberger
a51e8a21b6 fix(ci): break skills loading cycle 2026-05-30 00:02:24 +02:00
Peter Steinberger
260e8e26fd fix(ci): repair main checks 2026-05-30 00:02:24 +02:00
Vincent Koc
196ea61ec4 refactor: share diagnostics timeline span helpers 2026-05-30 00:01:58 +02:00
Vincent Koc
49cc613021 fix(supervisor): narrow stored session limit parsing 2026-05-30 00:01:47 +02:00
Peter Steinberger
347486a4c4 fix(openai): cap codex oauth preflight timeout 2026-05-29 17:59:29 -04:00
Peter Steinberger
1517fe2c32 perf: prefer package-local bundled plugin artifacts 2026-05-29 22:57:40 +01:00
Peter Steinberger
fe69df6b3a fix(gateway-client): cap stop wait timeout 2026-05-29 17:55:17 -04:00
Shakker
dac67b3978 test: complete skills status mock surface 2026-05-29 22:51:15 +01:00
Shakker
a6c694da7e test: remove duplicate skill fixture wrappers 2026-05-29 22:51:15 +01:00
Shakker
259d6aada8 test: share skills entry fixtures 2026-05-29 22:51:15 +01:00
Shakker
de6aaf8e23 test: preserve real skills status exports 2026-05-29 22:51:15 +01:00
Shakker
496e1e071f perf: use set for bundled skill allowlist 2026-05-29 22:51:15 +01:00
Shakker
112939df60 perf: prepare bundled skill allowlist once 2026-05-29 22:51:15 +01:00
Shakker
e8cece82ef perf: speed up skills filtering 2026-05-29 22:51:15 +01:00
Shakker
93c68c4432 perf: reuse resolved skills allowlist 2026-05-29 22:51:15 +01:00
Shakker
2009bec87a refactor: reuse shared skills prompt formatter 2026-05-29 22:51:15 +01:00
Shakker
f382a36458 perf: centralize skill status lookup 2026-05-29 22:51:15 +01:00
Shakker
45b12c0085 refactor: share skill command exposure policy 2026-05-29 22:51:15 +01:00
Shakker
0b86591d9d perf: avoid unnecessary skills index maps 2026-05-29 22:51:15 +01:00
Shakker
1221414709 feat: add skills index 2026-05-29 22:51:15 +01:00
Peter Steinberger
1c8de09ba9 ci: stabilize main checks 2026-05-29 22:49:06 +01:00
Peter Steinberger
7cd93f8e5c fix(infra): cap request body timeouts 2026-05-29 17:48:40 -04:00
Dallin Romney
1dbde826f2 fix ci mainline checks (#88137) 2026-05-29 14:41:30 -07:00
Peter Steinberger
1d84255581 fix(media): cap generation provider timeouts 2026-05-29 17:36:53 -04:00
Peter Steinberger
e1c88d4425 fix(tts): cap speech provider timeouts 2026-05-29 17:31:37 -04:00
Vincent Koc
e69fedc8cf refactor: share media temp save wrapper 2026-05-29 23:24:56 +02:00
Peter Steinberger
a841778b7b fix(acp): cap turn timeout timers 2026-05-29 17:20:48 -04:00
Peter Steinberger
522d0f7ef5 perf: reuse gateway runtime metadata 2026-05-29 22:16:53 +01:00
Peter Steinberger
50378c01e4 fix(discord): cap monitor helper timeouts 2026-05-29 17:15:28 -04:00
Peter Steinberger
3416edf740 fix(codex-supervisor): centralize session limit parsing 2026-05-29 17:10:38 -04:00
Peter Steinberger
040f14b641 fix(browser): cap node runtime timeouts 2026-05-29 17:07:33 -04:00
Peter Steinberger
8c53d100ca fix(ci): repair main checks 2026-05-29 23:05:54 +02:00
Peter Steinberger
5230a23202 fix(browser): cap control fetch timeouts 2026-05-29 17:04:43 -04:00
Peter Steinberger
6443d06764 fix: move compaction planning off the event loop
Move compaction planning work to a bounded worker-thread path so large transcript planning no longer monopolizes the agent event loop. Extract pure planning helpers, sanitize worker inputs before structured clone, package the worker entrypoint, and keep synchronous fallback only for worker-unavailable cases.

Fixes #86358.
2026-05-29 23:04:23 +02:00
Vincent Koc
6fd8cfd5bb refactor: share script bounded response reader 2026-05-29 23:02:03 +02:00
Peter Steinberger
95f9231136 fix(feishu): cap async helper timeouts 2026-05-29 17:01:11 -04:00
Peter Steinberger
e6b011823e fix(signal): cap client request timeouts 2026-05-29 16:57:04 -04:00
Peter Steinberger
31169ff3b4 fix: bound default heartbeat run timeout (#88133)
Fixes #87438.

Bound unset heartbeat run timeouts so background heartbeat turns no longer inherit the built-in 48-hour interactive agent default. Timeout precedence is explicit heartbeat timeout, explicit global agent timeout, then heartbeat cadence capped at 600 seconds.

Verification:
- git diff --check
- Testbox tbx_01kstna69zvznn4fq7zrqr04a1: corepack pnpm test src/infra/heartbeat-runner.model-override.test.ts -- --reporter=verbose passed 13 tests
- Direct node --import tsx runtime probe verified 300s, 600s, 60s, and 45s timeout precedence cases
- Autoreview clean

Known CI state:
- PR CI run 26661465248 has failures matching latest main CI run 26661386468 at a7820b2f54; failures are outside this six-file heartbeat/docs diff.
2026-05-29 22:56:13 +02:00
Peter Steinberger
7f09d6ae48 fix(usage): cap provider usage fetch timeouts 2026-05-29 16:53:07 -04:00
Peter Steinberger
a7820b2f54 fix(provider): cap operation timeouts 2026-05-29 16:47:36 -04:00
Vincent Koc
150673a734 refactor: share script budget number parsing 2026-05-29 22:44:38 +02:00
Peter Steinberger
b7e9272dbe fix(agents): cap model scan timeouts 2026-05-29 16:43:03 -04:00
Peter Steinberger
0b86decf94 fix: keep live OpenClaw session locks during cleanup (#88129)
Keep session lock cleanup from removing live OpenClaw-owned locks solely because they are old. Cleanup now reports age-only stale locks without deleting them, while still removing dead, orphaned, recycled, malformed-old, and non-OpenClaw-owned locks.

Update doctor docs and regression coverage for the cleanup/repair contract.

Refs #87779
2026-05-29 22:42:04 +02:00
Peter Steinberger
61e7b042b6 fix(crestodian): cap probe timeouts 2026-05-29 16:38:45 -04:00
Peter Steinberger
d10fd6b8f4 test: fix timeout mock return types 2026-05-29 16:38:45 -04:00
Peter Steinberger
a509c48f0e feat: add core session goals (#87469)
* feat: add core session goals

* feat: polish session goals in tui

* fix: resolve goal tool session stores

* fix: keep get goal read-only

* fix: migrate legacy goal session slots

* fix: persist goal token accounting

* fix: validate goal session rows

* refactor: remove unshipped goal legacy handling

* fix: handle goal commands in local tui

* fix: satisfy goal tool display checks

* fix: reset goal budget on overdue resume

* feat: surface session goals across control surfaces

* test: update gateway protocol test import

* test: align goal fixture types with protocol

* fix: scope selected global transcript usage fallback

* fix: scope selected global web subscriptions

* fix: preserve selected global agent during chat dispatch

* fix: scope chat inject to selected global agents
2026-05-29 22:36:29 +02:00
Peter Steinberger
057be10e5b perf: reuse provider handles and strict tool schemas 2026-05-29 21:34:59 +01:00
Peter Steinberger
b832975f3e fix(mattermost): cap dm retry timeouts 2026-05-29 16:31:01 -04:00
Peter Steinberger
26ea53cc68 fix(zai): cap endpoint probe timeouts 2026-05-29 16:28:33 -04:00
Peter Steinberger
57aec8c565 docs(skills): require grouped release changelogs 2026-05-29 21:28:06 +01:00
Vincent Koc
be6cac375a refactor: share e2e mock http helpers 2026-05-29 22:26:17 +02:00
Peter Steinberger
6e125adf3a fix(xiaomi): cap tts request timeouts 2026-05-29 16:25:32 -04:00
Peter Steinberger
0983e763fe fix(qa-matrix): cap substrate request timeouts 2026-05-29 16:22:33 -04:00
Peter Steinberger
69c3b56bde fix: stabilize codex supervisor session listing 2026-05-29 21:20:00 +01:00
Peter Steinberger
f66d14def5 fix(zalo): cap api request timeouts 2026-05-29 16:19:18 -04:00
Lucas Giordano
eb7e237151 docs(browser): add Notte cloud browser to direct WebSocket CDP providers
Notte exposes a CDP-compatible WebSocket gateway at
wss://us-prod.notte.cc/sessions/connect?token=<NOTTE_API_KEY> that
auto-creates a session on connect — the same shape OpenClaw's existing
"Direct WebSocket CDP providers" section was generically framed for
(per #31085).

Real behaviour proof (against wss://us-prod.notte.cc/sessions/connect):

  $ openclaw browser --browser-profile notte open https://example.com
  opened: https://example.com/
  tab: t4
  id: 7FE04AC44931A6E1C799DE4ABF0DC807

A screenshot captured against the same session is a 1254x1111 PNG of
the rendered example.com page.

Playwright connectOverCDP flow against the same URL (today):

  connectOverCDP                                      695ms
  context.newCDPSession(page)                         169ms
  session.send('Target.getTargetInfo') → targetId     87ms
  page.goto('https://example.com')                    631ms
  total                                               1.8s

AI-assisted (Claude Opus 4.7). codex review --base origin/main returned
clean. See PR description for the full pre-flight checklist.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 22:17:32 +02:00
Vincent Koc
beb665212c refactor: share e2e bounded response reader 2026-05-29 22:10:14 +02:00
zhang-guiping
689e8ec893 fix(agents): forward ACP spawn attachments
Forward initial image/file attachments when spawning ACP subagents through the existing sessions_spawn attachment opt-in. Remove the PR-only acpEnabled config split so ACP uses the same attachment gate as other runtimes.

Also fix the PR branch CI fallout: type the browser element CLI request mock and use Vitest env stubs in the Azure speech test to satisfy the changed-path security scan.

Verification:
- GitHub CI passed on f6ca26b160.
- Autoreview clean.
- Crabbox AWS live OpenAI proof passed: cbx_a576d49493fe / run_081dcc6c6a1b.

Thanks @zhangguiping-xydt.
2026-05-29 22:08:19 +02:00
Peter Steinberger
f8ad20b87e fix(signal): cap container timeout timers 2026-05-29 16:08:08 -04:00
Nimrod Gutman
6897711d19 feat(ios): add talk tab realtime playback (#88105)
Merged via squash.

Prepared head SHA: f41112a882
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-29 23:06:19 +03:00
Peter Steinberger
8ed5ea499d fix: keep compaction timeout snapshots continuable 2026-05-29 22:06:16 +02:00
xin zhuang
960117259d fix(agents): preserve rotated compaction session identity
Fix `sessions.json` persistence after compaction transcript rotation.

When the agent runtime rotates from the pre-compaction session transcript to the post-compaction transcript, post-run consumers now receive the effective OpenClaw session id and session file. Backend CLI session ids remain backend metadata and no longer overwrite the top-level OpenClaw session identity.

Refs #88040.
Thanks @1052326311.

Verification:
- `node scripts/run-vitest.mjs src/agents/agent-command.compaction-rotation.test.ts src/agents/agent-command.live-model-switch.test.ts src/agents/command/session-store.test.ts`
- Autoreview clean
- GitHub CI green on PR head `c3d3c77ddf675bbba0b9ba6681b030a2f69a898c`
2026-05-29 22:05:05 +02:00
Peter Steinberger
4b9a80d895 fix(discord): cap request timeout signals 2026-05-29 16:03:39 -04:00
Peter Steinberger
3b91d18c37 docs(skills): expand Discrawl archive workflow 2026-05-29 22:02:52 +02:00
Peter Steinberger
4f2dc09431 fix(auth): cap GitHub Copilot OAuth timeouts 2026-05-29 22:02:52 +02:00
Peter Steinberger
b3dc7a4a80 fix(exec): bind node auto-review to prepared plans 2026-05-29 22:01:27 +02:00
Peter Steinberger
e2966faea7 perf: reuse gateway session and plugin metadata paths 2026-05-29 21:01:00 +01:00
Peter Steinberger
b245cb2b6d docs(plugins): add external package readmes 2026-05-29 21:00:29 +01:00
Peter Steinberger
2b15850b47 build(plugins): externalize tokenjuice 2026-05-29 21:00:29 +01:00
Peter Steinberger
f10bad944f fix(oauth): cap tls preflight timeout 2026-05-29 15:59:27 -04:00
Peter Steinberger
fb8b9e9138 fix(copilot): cap oauth request timeouts 2026-05-29 15:54:28 -04:00
Dallin Romney
e848671e9d test(ci): fix main test expectations (#88122) 2026-05-29 12:53:30 -07:00
Vincent Koc
b1719474d5 refactor: share e2e incremental line reader 2026-05-29 21:51:46 +02:00
Peter Steinberger
c8f5a2e0e2 fix(qa-lab): cap credential broker request timeouts 2026-05-29 15:49:38 -04:00
Peter Steinberger
c4e1bb30da fix: close native hook relay replacement race 2026-05-29 21:47:14 +02:00
Peter Steinberger
1e2fda9e68 docs(plugins): clarify external plugin installs 2026-05-29 20:43:51 +01:00
Vincent Koc
7d0347b6de refactor: share ui chat send wrapper 2026-05-29 21:38:29 +02:00
Peter Steinberger
a0c1f5962d fix(runtime): centralize safe timer timeout resolution 2026-05-29 15:36:38 -04:00
Vincent Koc
33b81686ad test(file-transfer): remove stale tar fixture awaits 2026-05-29 21:23:11 +02:00
Vincent Koc
07870dff45 refactor: share codex app server start context 2026-05-29 21:19:55 +02:00
Peter Steinberger
99b24a80fb build(plugins): externalize copilot runtime 2026-05-29 20:14:38 +01:00
Peter Steinberger
a39c2d784e fix(minimax): cap tts timeout delays 2026-05-29 15:11:01 -04:00
Nimrod Gutman
0167f0a6df feat(ios): default to hosted push relay (#88096)
Merged via squash.

Prepared head SHA: 75f939af5c
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-29 22:05:25 +03:00
Peter Steinberger
11e82bdef2 fix(lmstudio): cap model fetch timeout delays 2026-05-29 15:05:20 -04:00
Vincent Koc
7aca070723 fix(scripts): cap gh-read json bodies 2026-05-29 21:01:37 +02:00
Peter Steinberger
e5845dd452 fix(codex): cap responses request timeout delays 2026-05-29 14:59:37 -04:00
Vincent Koc
ba55b3e360 refactor: share script bounded response helper 2026-05-29 20:54:29 +02:00
Peter Steinberger
467b068fdc perf(sessions): patch single-entry store writes 2026-05-29 19:54:01 +01:00
Peter Steinberger
18bfd44439 test: shard channel import guardrails 2026-05-29 20:52:19 +02:00
Peter Steinberger
fb18f95348 test: stabilize slow assertion timings 2026-05-29 20:52:19 +02:00
Peter Steinberger
7f4338d435 test: speed up slow assertions 2026-05-29 20:52:18 +02:00
Peter Steinberger
16cd7f9d3f fix(oauth): cap request abort timeout delays 2026-05-29 14:52:01 -04:00
Peter Steinberger
4e2d9b0b76 fix(providers): cap model request timeout delays 2026-05-29 14:43:32 -04:00
Vincent Koc
040eba1cdc refactor: share bounded response reader 2026-05-29 20:34:12 +02:00
Vincent Koc
18d2bc441c fix(e2e): harden kitchen sink probe body caps 2026-05-29 20:31:54 +02:00
Peter Steinberger
75ef73d4f7 fix(talk): cap fast context timeout delay 2026-05-29 14:30:59 -04:00
Peter Steinberger
f440121a49 fix(node-host): cap timeout wrapper delays 2026-05-29 14:25:28 -04:00
Peter Steinberger
1ca7f5c0a0 perf(gateway): reuse session maintenance config during turns 2026-05-29 19:23:28 +01:00
Peter Steinberger
61031d1b1c feat(workboard): add agent coordination tools
Summary:
- Add Workboard agent coordination tools for list/read/claim/heartbeat/release/comment/proof/unblock flows.
- Store artifacts, claims, diagnostics, and notifications in the Workboard SQLite-backed plugin state; surface the new metadata through Gateway, Control UI, docs, and plugin manifest contracts.
- Add scoped claim authorization, token redaction, stale diagnostic cleanup, atomic proof artifact writes, and generated i18n metadata.

Verification:
- pnpm test ui/src/i18n/test/translate.test.ts extensions/browser/src/cli/browser-cli-actions-input/register.element.test.ts extensions/workboard/src/store.test.ts extensions/workboard/src/gateway.test.ts extensions/workboard/src/tools.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/ui/views/workboard.test.ts
- pnpm ui:i18n:check
- env -u OPENCLAW_TESTBOX pnpm check:changed
- autoreview --mode local: clean
- PR CI passed; Windows checkout failure rerun passed on attempt 2
2026-05-29 20:23:21 +02:00
Peter Steinberger
afa6b81120 fix(sandbox): bound novnc observer token ttl 2026-05-29 14:20:18 -04:00
Peter Steinberger
4eeb7bfa57 fix(retry): cap unsafe retry delays 2026-05-29 14:15:38 -04:00
Vincent Koc
aae13f4dd2 refactor: share qa report arg parsing 2026-05-29 20:07:53 +02:00
Peter Steinberger
4305fb7cdf fix(auth): reject unsafe wham reset windows 2026-05-29 14:05:14 -04:00
Vincent Koc
e8217cbb7a fix(scripts): cap npm packument reads 2026-05-29 20:01:02 +02:00
Peter Steinberger
e3be541a6c fix(google): reject unsafe vertex adc lifetimes 2026-05-29 13:57:34 -04:00
Peter Steinberger
b9d7dd4a84 fix(feishu): normalize app registration poll timers 2026-05-29 13:53:05 -04:00
Vincent Koc
6d362dbe9a fix(minimax): guard oauth token fetches (#88088) 2026-05-29 18:50:20 +01:00
Vincent Koc
1fd5a90894 refactor: share e2e websocket open helper 2026-05-29 19:49:13 +02:00
Peter Steinberger
bf3921dab7 refactor: centralize timer-safe timeout bounds 2026-05-29 13:44:41 -04:00
Peter Steinberger
c36b2bf64e fix(openshell): cap command timeout config 2026-05-29 13:33:41 -04:00
Peter Steinberger
04de01f8cf fix(feishu): bound streaming token expiry 2026-05-29 13:28:40 -04:00
Vincent Koc
6811cee756 refactor: share codex e2e install helpers 2026-05-29 19:27:53 +02:00
benjamin1492
de455304cc fix(command): stabilize claude-cli transcript resume (#81048)
Fix claude-cli transcript resume so session-id rotation and transcript flush timing do not drop valid resume state.

- Capture the latest claude-cli session_id from JSONL output.
- Resolve Claude project transcript paths through the shared canonical project-dir resolver.
- Probe transcript content from the actual CLI process cwd.
- Thanks @benjamin1492!
2026-05-29 22:56:09 +05:30
Peter Steinberger
f499841be6 fix(google-meet): normalize oauth expiry 2026-05-29 13:22:07 -04:00
Vincent Koc
9ad3ed481f fix(ci): cap dependency guard error bodies 2026-05-29 19:20:01 +02:00
Peter Steinberger
604a6b5452 fix(minimax): reject unsafe oauth expiry 2026-05-29 13:15:00 -04:00
Peter Steinberger
5e2c200d06 test(xai): type device-code note mock 2026-05-29 13:15:00 -04:00
Vincent Koc
5620229f9f refactor: reuse e2e text tail helper 2026-05-29 19:06:38 +02:00
Peter Steinberger
58c46ec03b fix(openai): normalize codex device lifetimes 2026-05-29 13:03:32 -04:00
Peter Steinberger
4ef77dadec fix(google): normalize unsafe oauth expiry 2026-05-29 12:59:28 -04:00
Vincent Koc
65b00716d2 refactor: share e2e text file helpers 2026-05-29 18:58:22 +02:00
Peter Steinberger
1ec23446a0 fix(xai): normalize unsafe oauth lifetimes 2026-05-29 12:55:24 -04:00
Vincent Koc
d5d59eb1ea fix(scripts): cap firecrawl compare HTML reads 2026-05-29 18:54:12 +02:00
Peter Steinberger
67faef0182 perf(agent): skip plugin validation for gateway dispatch 2026-05-29 17:50:10 +01:00
Peter Steinberger
2106714f6b fix(exec): cap node run timeouts 2026-05-29 12:49:46 -04:00
Peter Steinberger
ece92bcbde fix: persist Copilot SDK session bindings
Persist GitHub Copilot SDK session ids in the plugin-state SQLite store so separate OpenClaw process turns can resume the same Copilot-side session when the compatibility fingerprint still matches.

The fingerprint covers provider/model/cwd, resolved agent id, resolved Copilot home, and auth identity. Plugin-state lookup/register/delete failures are non-fatal, stale rows are invalidated, and reset delete failures use an in-process tombstone so reset does not accidentally reuse a durable binding.

Also routes the QQBot token POST through the plugin SDK SSRF guard with capture disabled for the secret-bearing request, preserving the current token lifetime validation from main.

Verification: focused Copilot and QQBot Vitest suites, raw channel fetch guard, autoreview clean, Blacksmith Testbox pnpm check:changed tbx_01kst9fwjmsfzwaxqatszcbf40, live local Copilot two-turn smoke with the same SDK session id persisted in SQLite.

Refs #88064
2026-05-29 18:46:03 +02:00
Peter Steinberger
95e898bf05 fix(exec): normalize unsafe timeout values 2026-05-29 12:43:57 -04:00
Peter Steinberger
5a294cb2bd refactor: centralize safe expiry parsing 2026-05-29 12:38:11 -04:00
Vincent Koc
95ea4b7cc6 refactor: share web secret target selection 2026-05-29 18:35:47 +02:00
Shakker
8eb03d81a0 refactor: centralize skills runtime tests 2026-05-29 17:35:02 +01:00
Shakker
a6df6838b9 fix: route moved skills tests through unit-fast 2026-05-29 17:35:02 +01:00
Shakker
ea487eb72c fix: unblock skills centralization checks 2026-05-29 17:35:02 +01:00
Shakker
6e026fbb46 refactor: centralize skills subsystem 2026-05-29 17:35:02 +01:00
Shakker
efffb42ef9 refactor: split skills index follow-up 2026-05-29 17:35:02 +01:00
Shakker
de83e9eb87 fix: lint centralized skills subsystem 2026-05-29 17:35:02 +01:00
Shakker
d9278c8efd refactor: organize skills subsystem layout 2026-05-29 17:35:02 +01:00
Shakker
355fb4d860 refactor: use direct skills imports 2026-05-29 17:35:02 +01:00
Shakker
11ef611080 refactor: remove stale agents skills barrel 2026-05-29 17:35:02 +01:00
Shakker
ba2dedb3bc refactor: centralize skills runtime paths 2026-05-29 17:35:02 +01:00
Shakker
8640b6aa7f fix: drop stale system prompt override imports 2026-05-29 17:35:02 +01:00
Shakker
5fff679aea fix: align skills branch with upstream tar verbose test 2026-05-29 17:35:02 +01:00
Shakker
c46ca5d638 fix: align empty default skill filter behavior 2026-05-29 17:35:02 +01:00
Shakker
40a9c38736 fix: preserve empty skill filter short circuit 2026-05-29 17:35:02 +01:00
Shakker
4d46098772 refactor: move session skill loader into skills subsystem 2026-05-29 17:35:02 +01:00
Shakker
970df5f6e0 fix: preserve preloaded skill snapshot entries 2026-05-29 17:35:02 +01:00
Shakker
407ffdef0b fix: preserve skill snapshot freshness 2026-05-29 17:35:02 +01:00
Shakker
98834defb0 fix: bound skill index cache invalidation 2026-05-29 17:35:02 +01:00
Shakker
bedfd4c200 refactor: move skill lifecycle code into skills subsystem 2026-05-29 17:35:02 +01:00
Shakker
22e2d1560f refactor: centralize skills subsystem 2026-05-29 17:35:02 +01:00
Vincent Koc
dc7bd4abf5 fix(scripts): cap Claude usage response reads 2026-05-29 18:31:55 +02:00
Peter Steinberger
6c041ef65e fix(agent-core): reject invalid session timestamps 2026-05-29 12:27:54 -04:00
Ayaan Zaidi
e8628c6717 fix(auto-reply): keep room event cli sessions transient 2026-05-29 21:56:25 +05:30
Ayaan Zaidi
a397f53723 fix(auto-reply): reuse cli sessions for room events 2026-05-29 21:56:25 +05:30
Peter Steinberger
8c0aaee882 fix(chutes): validate oauth token lifetimes 2026-05-29 12:19:29 -04:00
Vincent Koc
21bcc0e942 fix(scripts): cap realtime smoke responses 2026-05-29 18:14:59 +02:00
Peter Steinberger
a5717c34ab fix(github-copilot): validate oauth expiry values 2026-05-29 12:09:47 -04:00
Vincent Koc
39c5de484d refactor: share cli help argv scan 2026-05-29 18:07:48 +02:00
Peter Steinberger
7a750100c9 fix(msteams): validate oauth token lifetimes 2026-05-29 12:01:59 -04:00
Peter Steinberger
64e6ea0727 fix(github-copilot): validate device code lifetimes 2026-05-29 11:56:26 -04:00
Vincent Koc
edc573daba fix(scripts): cap memory FD repro RPC bodies 2026-05-29 17:53:17 +02:00
Peter Steinberger
b67679fb73 fix(anthropic): validate oauth token lifetimes 2026-05-29 11:50:12 -04:00
Vincent Koc
92fc7c5608 refactor: share node pairing surface helpers 2026-05-29 17:47:13 +02:00
Peter Steinberger
806b3b73bb fix(openai): validate codex oauth token lifetimes 2026-05-29 11:42:49 -04:00
Peter Steinberger
91ecd9645f fix(qqbot): validate token expiry lifetimes 2026-05-29 11:36:36 -04:00
Gio Della-Libera
7ed17e3174 fix(doctor): label auth health by agent (#85924)
Merged via squash.

Prepared head SHA: 8c179fc851
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-05-29 08:35:13 -07:00
Peter Steinberger
7dbc7702c3 fix(googlechat): drop invalid inbound timestamps 2026-05-29 11:29:49 -04:00
Peter Steinberger
3654ea32a9 fix(telegram): centralize safe thread id parsing 2026-05-29 11:24:27 -04:00
Vincent Koc
fe329ffff0 fix(scripts): cap clawtributor avatar probes 2026-05-29 17:18:12 +02:00
Vincent Koc
7e8364f6d5 fix(cli): avoid underscored gateway test export 2026-05-29 17:17:29 +02:00
Peter Steinberger
aa75477533 fix(zalouser): reject unsafe inbound timestamps 2026-05-29 11:13:09 -04:00
Shadow
598e3f8e7b Delete changelog directory 2026-05-29 10:12:41 -05:00
Vincent Koc
778f72f75b refactor: share cron state parsing 2026-05-29 17:08:26 +02:00
Peter Steinberger
3d7df2bc07 fix(discord): bound delivery retry delays 2026-05-29 11:02:34 -04:00
Vincent Koc
e394e0f9b8 fix(qa-matrix): cap fault proxy bodies 2026-05-29 17:02:11 +02:00
Peter Steinberger
fb37811b65 fix(discord): reject unsafe retry-after delays 2026-05-29 10:58:36 -04:00
Peter Steinberger
f2ba23424e fix(slack): reject unsafe inbound timestamps 2026-05-29 10:52:02 -04:00
Vincent Koc
27e13933c0 refactor: share store writer queue 2026-05-29 16:48:34 +02:00
Peter Steinberger
ec1e27d562 fix(msteams): ignore unsafe retry-after delays 2026-05-29 10:48:05 -04:00
Peter Steinberger
ec0d3752ca perf(agent): defer session resolver for scoped gateway turns 2026-05-29 15:39:51 +01:00
Peter Steinberger
fca7f220a7 fix(agents): cap unsafe retry-after delays 2026-05-29 10:38:38 -04:00
Vincent Koc
e95fbc05aa refactor: share agent harness loader helpers 2026-05-29 16:27:03 +02:00
Peter Steinberger
cde6aff622 fix(whatsapp): validate inbound timestamps 2026-05-29 10:25:59 -04:00
Peter Steinberger
854be10e65 perf(agent): lazy load embedded agent cli path 2026-05-29 15:19:56 +01:00
Peter Steinberger
239523668e ci(release): make plugin publish retries idempotent 2026-05-29 15:18:18 +01:00
Peter Steinberger
0fa034ed6d fix(discord): reject unsafe rate limit headers 2026-05-29 10:17:42 -04:00
Peter Steinberger
9ae38ac821 fix(discord): validate error code integers 2026-05-29 10:13:15 -04:00
Vincent Koc
0902ee723b fix(provider): bound Vydra and Comfy media downloads 2026-05-29 16:12:23 +02:00
Peter Steinberger
c093e4508d fix(tts): centralize directive number parsing 2026-05-29 10:05:37 -04:00
joshavant
65f6e53e62 test(release): repair live matrix expectations
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
13926e622d fix(exec): include mode in doctor policy warnings
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
5814f7e1d3 ci: relax native OpenAI live proof timing
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
9945060c7d fix(exec): resolve auto approvals as runtime
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
941329b2e5 test(e2e): repair release docker smoke fixtures
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
209732535f fix(exec): align release validation checks
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
47c578034a fix(exec): align release validation surfaces
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
9e7110bb7d fix(exec): harden auto-review prompt boundaries
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
c82d7011b5 fix(exec): honor node runtime policy for auto-review
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
2bfc735050 fix(exec): bind node auto-review commands
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
ab84c8cc09 fix(exec): bind gateway auto-review commands
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
0aed1641c4 fix(exec): fail closed on unknown node approval policy
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
7652eda80c test(node-host): prove suppression edits bypass auto-review
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
49ab52894a fix(exec): honor node approval floors before auto-review
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
765477d77a fix(codex): preserve read-only approval floors
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
b5f8191887 fix(codex): honor exec approval floors in bindings
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
adca9a7523 fix(exec): layer session exec overrides
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
a314a923bd fix(exec): forward auto mode defaults
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
joshavant
80227005a0 feat(exec): add normalized auto mode
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-30 00:04:06 +10:00
Peter Steinberger
4925f84219 fix(minimax): validate directive numbers 2026-05-29 09:58:21 -04:00
Vincent Koc
b9d609edfe refactor: share bounded release response reader 2026-05-29 15:54:36 +02:00
Peter Steinberger
af3e354ff8 fix(signal): validate reaction message ids 2026-05-29 09:53:20 -04:00
Peter Steinberger
4ef63646d2 fix(discord): validate deploy retry-after 2026-05-29 09:50:21 -04:00
Peter Steinberger
8a4573917d fix(sandbox): validate remote hardlink counts 2026-05-29 09:47:33 -04:00
Vincent Koc
67697fa309 test: repair current main extension checks 2026-05-29 15:45:12 +02:00
Peter Steinberger
d9db23dc2f fix(sandbox): clamp unsafe stat sizes 2026-05-29 09:43:14 -04:00
Vincent Koc
8b12be05ec refactor: share outbound mirror block text 2026-05-29 15:38:11 +02:00
zhang-guiping
b3c7ef6e62 fix(config): preserve empty plugin allowlist (#87883)
Summary:
- The PR changes plugin auto-enable materialization so an explicit empty `plugins.allow` stays empty while non-empty restrictive allowlists are still extended, and adds a regression test.
- PR surface: Source +3, Tests +17. Total +20 across 2 files.
- Reproducibility: yes. Source inspection of current main shows an empty array reaches `ensurePluginAllowlisted`, and the linked report gives a concrete `doctor --fix` config path that matches that code.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head c06837f5dd.
- Required merge gates passed before the squash merge.

Prepared head SHA: c06837f5dd
Review: https://github.com/openclaw/openclaw/pull/87883#issuecomment-4570537738

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-29 13:37:50 +00:00
Peter Steinberger
80baa49342 fix(telegram): validate dispatch thread ids 2026-05-29 09:35:43 -04:00
Vincent Koc
a19225343b fix(video): bound remaining provider downloads 2026-05-29 15:30:11 +02:00
Peter Steinberger
b022c6d770 fix(telegram): validate cached thread ids 2026-05-29 09:28:17 -04:00
Ayaan Zaidi
82c0a60777 fix(trajectory): bound runtime source ordering state 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
6361c46fe2 fix(trajectory): assign file-global runtime source order 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
d879340ed9 fix(trajectory): preserve runtime window order 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
39e3daa168 fix(trajectory): preserve safe path checks for window writes 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
538b405fdd fix(trajectory): merge concurrent runtime window flushes 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
ac605a463a fix(trajectory): keep latest runtime capture within cap 2026-05-29 18:55:53 +05:30
Ayaan Zaidi
f17c472f26 fix(trajectory): keep latest runtime capture within cap 2026-05-29 18:55:53 +05:30
Peter Steinberger
9a1b5f9b68 fix(feishu): validate merge-forward timestamps 2026-05-29 09:22:33 -04:00
Vincent Koc
f019e27c1d refactor: share gateway client readiness helpers 2026-05-29 15:19:29 +02:00
Peter Steinberger
8f22632a29 fix(msteams): validate bot attachment content length 2026-05-29 09:18:40 -04:00
Peter Steinberger
7fb91317ba fix(feishu): validate thread message timestamps 2026-05-29 09:15:07 -04:00
Peter Steinberger
001da78fab fix(feishu): validate message create time 2026-05-29 09:12:06 -04:00
Peter Steinberger
5fbeffd56b fix(imessage): validate chat list ids 2026-05-29 09:08:39 -04:00
Peter Steinberger
3142c97c22 fix(google): validate gemini retry timeout env 2026-05-29 09:05:38 -04:00
Peter Steinberger
58e82d91ba fix(media): centralize content length parsing 2026-05-29 09:02:21 -04:00
zhang-guiping
b5bc752a48 fix(active-memory): isolate recall lane
Active Memory recall now runs on its own queue lane instead of sharing the parent prompt-build lane.\n\nValidation:\n- git diff --check\n- node scripts/run-vitest.mjs extensions/active-memory/index.test.ts -t "runs recall on a dedicated active-memory lane"\n- fresh local gateway smoke with Active Memory + Memory Core + loopback OpenAI-compatible model: HTTP 200, active-memory start/done, recall elapsedMs=209\n\nFixes #79026.\nRelated: #72015.
2026-05-29 20:57:53 +08:00
Peter Steinberger
2cb8ac1596 fix(signal): validate attachment content length 2026-05-29 08:55:44 -04:00
Peter Steinberger
63d6bce324 fix(slack): reuse timestamp parser in dispatch 2026-05-29 08:52:46 -04:00
Peter Steinberger
d7e24e024f fix(slack): centralize timestamp parsing 2026-05-29 08:48:22 -04:00
Vincent Koc
19c70e2a29 refactor: share provider install choice fields 2026-05-29 14:44:51 +02:00
Peter Steinberger
f8c60cb9b7 fix(slack): validate dm history timestamps 2026-05-29 08:44:21 -04:00
Peter Steinberger
6235720c8a fix(slack): validate inbound timestamp parsing 2026-05-29 08:40:37 -04:00
Peter Steinberger
93e15abdf6 fix(discord): validate deploy status codes 2026-05-29 08:36:28 -04:00
Peter Steinberger
4ad9478d68 fix(discord): validate thread binding error codes 2026-05-29 08:32:48 -04:00
Peter Steinberger
58e52e9424 fix(signal): validate container send timestamps 2026-05-29 08:29:20 -04:00
Vincent Koc
7d5dd8aad2 fix(fal): bound generated media downloads 2026-05-29 14:28:15 +02:00
Peter Steinberger
476d0a2c4b fix(agent-core): reject non-decimal numeric tool args 2026-05-29 08:25:28 -04:00
clawsweeper[bot]
468b971fba fix(doctor): preserve explicit agentRuntime pin during codex model migration [AI-assisted] (#84362)
Summary:
- The PR updates Codex doctor route repair to preserve explicit non-default `agentRuntime` pins across agent model maps and provider policies, adds regression coverage, and tightens a live-gateway test helper type guard.
- PR surface: Source +240, Tests +574. Total +814 across 3 files.
- Reproducibility: yes. The source path is clear from current main's model-map merge behavior and the PR's bef ... beRepairCodexRoutes` with the reported config, though this read-only review did not execute the test suite.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(doctor): preserve explicit non-default agentRuntime pin during le…
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8414…

Validation:
- ClawSweeper review passed for head c142ec1ef8.
- Required merge gates passed before the squash merge.

Prepared head SHA: c142ec1ef8
Review: https://github.com/openclaw/openclaw/pull/84362#issuecomment-4493152445

Co-authored-by: David Huang <nxmxbbd@gmail.com>
Co-authored-by: Nex <nex@dbitstec.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-29 12:22:35 +00:00
Vincent Koc
f712bbcb3f refactor: share host hook projection collection 2026-05-29 14:21:21 +02:00
Peter Steinberger
62c6f4480e fix(agents): preserve tool-search numeric literals 2026-05-29 08:19:50 -04:00
Peter Steinberger
2644f26a35 fix(discord): centralize retry status parsing 2026-05-29 08:14:57 -04:00
Peter Steinberger
2be1d1b9f9 fix(msteams): centralize poll selection parsing 2026-05-29 08:09:10 -04:00
Peter Steinberger
2cd0c8b515 fix(agents): centralize failover status parsing 2026-05-29 08:05:12 -04:00
Vincent Koc
a18bc56996 refactor: share google provider stream helpers 2026-05-29 14:02:26 +02:00
Peter Steinberger
e01b04d48a fix(agents): centralize live model limit parsing 2026-05-29 08:00:40 -04:00
Peter Steinberger
351d056ca6 fix(update): centralize timeout seconds parsing 2026-05-29 07:56:28 -04:00
Vincent Koc
e098fd40ac fix(azure-speech): bound generated speech downloads 2026-05-29 13:54:33 +02:00
Peter Steinberger
150296261e fix(cli): centralize timeout integer parsing 2026-05-29 07:52:00 -04:00
Peter Steinberger
36b0b12971 fix(polls): centralize duration string parsing 2026-05-29 07:47:59 -04:00
Peter Steinberger
151f3a4cec fix(cli): centralize argv positive int parsing 2026-05-29 07:43:49 -04:00
Peter Steinberger
c8334ad0eb test(telegram): type loose throttler string-id fixtures 2026-05-29 07:43:49 -04:00
Vincent Koc
9366d0a873 refactor: share responses stream lifecycle 2026-05-29 13:38:55 +02:00
Peter Steinberger
e2794cdf65 fix(telegram): centralize throttler id parsing 2026-05-29 07:33:35 -04:00
Peter Steinberger
5102e0cabe test(release): widen live session control timeout 2026-05-29 12:33:22 +01:00
Peter Steinberger
615199a6a4 fix(browser): centralize cli index parsing 2026-05-29 07:29:52 -04:00
Peter Steinberger
91a4c594d8 refactor(agents): centralize bash env integer parsing 2026-05-29 07:26:01 -04:00
Vincent Koc
79691d4858 fix(provider): bound binary response reads 2026-05-29 13:24:19 +02:00
Peter Steinberger
6a2ccbc929 fix(gateway): require strict preauth budget env 2026-05-29 07:21:23 -04:00
Peter Steinberger
4b6517d114 fix(provider-auth): centralize copilot expiry parsing 2026-05-29 07:18:04 -04:00
Peter Steinberger
3dfb76f13b fix(synology-chat): centralize user id parsing 2026-05-29 07:14:31 -04:00
Peter Steinberger
1951413a0b fix(file-transfer): centralize dir-list page token parsing 2026-05-29 07:11:26 -04:00
Vincent Koc
92c1547a89 refactor: share gateway send inflight handling 2026-05-29 13:10:32 +02:00
Peter Steinberger
95bf36fe28 test(release): align live provider timeouts 2026-05-29 12:09:43 +01:00
Vincent Koc
0d382d7823 test(memory-lancedb): stabilize aggregate mocks 2026-05-29 13:09:30 +02:00
Peter Steinberger
ebb1615676 fix(openai): centralize responses threshold parsing 2026-05-29 07:08:17 -04:00
Peter Steinberger
cb765f1664 ci(release): require all plugins for core publish 2026-05-29 12:07:03 +01:00
Peter Steinberger
4c4e8a213f fix(feishu): centralize action integer parsing 2026-05-29 07:04:26 -04:00
Peter Steinberger
721cedfbf0 fix(discord): centralize model picker numeric parsing 2026-05-29 07:01:24 -04:00
Vincent Koc
4438be7f05 fix(tts): bound generated speech downloads 2026-05-29 12:58:56 +02:00
Peter Steinberger
c4a5bba800 fix(mattermost): centralize model picker page parsing 2026-05-29 06:58:37 -04:00
Peter Steinberger
d1fad163d9 fix(subagents): centralize stored depth parsing 2026-05-29 06:55:00 -04:00
Vincent Koc
2799e6c910 refactor: share runtime secret scans 2026-05-29 12:49:37 +02:00
Peter Steinberger
d095d1663b fix(exa): reject non-decimal search counts 2026-05-29 06:49:23 -04:00
Peter Steinberger
ed59629ccd fix(nextcloud-talk): centralize integer coercion 2026-05-29 06:45:24 -04:00
Peter Steinberger
4a206db106 fix(irc): centralize setup port parsing 2026-05-29 06:41:44 -04:00
Peter Steinberger
1042dce454 fix(codex): centralize session limit parsing 2026-05-29 06:37:59 -04:00
Peter Steinberger
9996cad49a fix(proxy): centralize cli integer parsing 2026-05-29 06:34:28 -04:00
Peter Steinberger
68d0c0f2f5 fix(media): allow trusted generated html attachments (#87982) 2026-05-29 11:33:50 +01:00
Vincent Koc
529ea02353 refactor: share discord native command access context 2026-05-29 12:28:45 +02:00
Peter Steinberger
18641831bf test(release): size explicit live fallback models 2026-05-29 11:28:37 +01:00
Peter Steinberger
1b138d3f38 fix(qa-matrix): centralize timeout env parsing 2026-05-29 06:27:30 -04:00
Peter Steinberger
ba2620a9af fix(memory-lancedb): centralize cli integer parsing 2026-05-29 06:24:22 -04:00
Peter Steinberger
182d60535a test: fix main test type checks 2026-05-29 11:21:42 +01:00
Peter Steinberger
28a2043f51 fix(qa-lab): centralize cli integer parsing 2026-05-29 06:20:43 -04:00
Vincent Koc
036298fbae fix(music): bound generated track downloads 2026-05-29 12:20:09 +02:00
Peter Steinberger
3eca409456 test(release): typecheck live gate hardening 2026-05-29 11:18:39 +01:00
Peter Steinberger
3430a2d26f fix(memory-wiki): centralize cli line option parsing 2026-05-29 06:16:44 -04:00
Peter Steinberger
888cd08fa8 fix(memory-core): centralize cli integer parsing 2026-05-29 06:12:45 -04:00
Peter Steinberger
fbf900c746 refactor: move plugin state consumers to sqlite
Summary:
- add plugin-state runtime SDK subpaths backed by the existing sidecar DB
- migrate Discord model-picker preferences and Feishu dedup state to plugin-state keyed stores
- wire doctor legacy-state migration imports, including TTL preservation, for existing plugin JSON state

Verification:
- pnpm plugin-sdk:api:check
- focused plugin-state, doctor, Discord, Feishu, and package-boundary Vitest suites
- git diff --check origin/main...HEAD
- env -u OPENCLAW_TESTBOX pnpm check:changed
- autoreview --mode branch --base origin/main
- GitHub Actions PR checks green on 1025c2b570
2026-05-29 11:12:15 +01:00
Peter Steinberger
0ad43bbf3d test(release): harden live provider gates 2026-05-29 11:09:15 +01:00
Peter Steinberger
7a803c113d fix(talk-voice): parse signed list limits 2026-05-29 06:08:50 -04:00
Peter Steinberger
aff6d079d3 fix(agents): add typed tool progress updates
Add a general typed tool-progress contract so long-running non-exec tools can emit public channel progress without overloading model-facing tool content.

`web_fetch` now uses the generic delayed progress helper: it shows `Fetching page content...` only when the fetch is still pending after five seconds, clears the timer on completion/abort, passes the abort signal into guarded fetch, and avoids provider fallback or cached success after cancellation. The subscriber path accepts only explicit `visibility: "channel"` and `privacy: "public"` progress metadata, while untyped tool partials and exec output keep their existing behavior.

Docs now explain typed progress, delayed producer examples, and the `web_fetch` timing behavior.

Proof: `pnpm test src/agents/tools/web-tools.fetch.test.ts src/agents/embedded-agent-subscribe.handlers.tools.test.ts -- --run`; `pnpm docs:check-mdx`; changed-file `pnpm exec oxlint ...`; `git diff --check`; autoreview clean.
2026-05-29 11:06:13 +01:00
Vincent Koc
bba28df9f7 refactor: share qqbot typing notify retry 2026-05-29 12:05:54 +02:00
Peter Steinberger
9f28e8c5f4 fix(browser): centralize cli integer option parsing 2026-05-29 06:05:01 -04:00
Peter Steinberger
27eb8732d3 fix(workboard): clear landing gates 2026-05-29 11:04:37 +01:00
Peter Steinberger
1d645ff66b feat(workboard): persist card metadata 2026-05-29 11:04:37 +01:00
Peter Steinberger
ab3eca14f1 fix(workboard): tighten controls and track card events 2026-05-29 11:04:37 +01:00
Peter Steinberger
7e59e43ce6 feat(workboard): add card execution actions 2026-05-29 11:04:37 +01:00
Peter Steinberger
e7e3b4a58b fix(workboard): align bundled metadata 2026-05-29 11:04:37 +01:00
Peter Steinberger
ad038c87e8 fix(workboard): respect default-off before config loads 2026-05-29 11:04:37 +01:00
Peter Steinberger
83f006a11d fix(workboard): skip read-only lifecycle writes 2026-05-29 11:04:37 +01:00
Peter Steinberger
e961803332 fix(workboard): localize status labels 2026-05-29 11:04:37 +01:00
Peter Steinberger
717bfb4031 fix(workboard): abort stale linked runs 2026-05-29 11:04:37 +01:00
Peter Steinberger
8477e39db7 fix(workboard): keep plugin opt-in 2026-05-29 11:04:37 +01:00
Peter Steinberger
d5c98696a0 fix(workboard): refresh cards on tab reload 2026-05-29 11:04:37 +01:00
Peter Steinberger
ff9df09e53 fix(workboard): refresh id uk locales 2026-05-29 11:04:37 +01:00
Peter Steinberger
a631f5ff26 fix(workboard): refresh tr locale 2026-05-29 11:04:37 +01:00
Peter Steinberger
c3a073769f fix(workboard): refresh generated locales 2026-05-29 11:04:37 +01:00
Peter Steinberger
3ab0e78028 fix(workboard): refresh remaining locales 2026-05-29 11:04:37 +01:00
Peter Steinberger
e1f64a0dd0 fix(workboard): scope card stop aborts 2026-05-29 11:04:37 +01:00
Peter Steinberger
eb3dc18b13 fix(workboard): localize card form labels 2026-05-29 11:04:37 +01:00
Peter Steinberger
9f9067f559 fix(workboard): localize mini game labels 2026-05-29 11:04:37 +01:00
Peter Steinberger
853b7cc75d fix(workboard): handle failed card starts 2026-05-29 11:04:37 +01:00
Peter Steinberger
0cdb80078f fix(workboard): polish card editing flow 2026-05-29 11:04:37 +01:00
Peter Steinberger
63111746b1 feat: capture sessions into workboard 2026-05-29 11:04:37 +01:00
Peter Steinberger
024cd0e4aa feat: sync workboard cards with sessions 2026-05-29 11:04:37 +01:00
Peter Steinberger
8a04851fa0 fix: localize workboard disabled state 2026-05-29 11:04:37 +01:00
Peter Steinberger
86ed25af34 feat: add workboard dashboard plugin 2026-05-29 11:04:37 +01:00
Peter Steinberger
ed62aefeee refactor(gateway): centralize handshake timeout parsing 2026-05-29 05:56:21 -04:00
Vincent Koc
7708e8c7ef refactor: share qqbot media path decoding 2026-05-29 11:53:33 +02:00
Peter Steinberger
82a16d2fee fix: alias net policy in plugin loader 2026-05-29 10:47:27 +01:00
Peter Steinberger
656c238295 fix(telegram): ignore unsafe cached message ids 2026-05-29 05:44:15 -04:00
Peter Steinberger
e890d7ea4f fix(telegram): reject unsafe topic targets 2026-05-29 05:39:57 -04:00
Peter Steinberger
7d76e54f2b fix: honor cron backoff from run end 2026-05-29 05:36:50 -04:00
Peter Steinberger
8ac0c35462 fix(prompts): reject unsafe template indexes 2026-05-29 05:36:15 -04:00
Vincent Koc
49807ac1f1 refactor: share plugin http dispatch helpers 2026-05-29 11:32:14 +02:00
Peter Steinberger
0b84d8b521 ci: refresh live gateway release lanes 2026-05-29 10:30:23 +01:00
Peter Steinberger
75c011b606 fix(subagents): ignore unsafe log limits 2026-05-29 05:29:50 -04:00
Vincent Koc
c7127c7c34 test(doctor): satisfy legacy migration lint 2026-05-29 11:28:32 +02:00
拐爷&&老拐瘦
f634062f35 fix(cron): quarantine malformed persisted jobs
Quarantine malformed persisted cron rows before sanitizing active jobs.json.
Preserve raw malformed rows plus split runtime metadata in jobs-quarantine.json so later cron writes cannot silently delete recoverable data.
Doctor now reports quarantine sidecars for manual review.

Closes #51871.
Thanks @yfge.

Verification:
- pnpm test src/cron/service/store.test.ts src/cron/service/store.load-missing-session-target.test.ts src/cron/store.test.ts src/commands/doctor-cron-store-migration.test.ts src/commands/doctor-cron.test.ts ui/src/ui/controllers/cron-filters.test.ts ui/src/ui/controllers/cron.test.ts ui/src/ui/app-render.helpers.node.test.ts ui/src/ui/app-settings.refresh-active-tab.node.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json --files src/cron/store.ts src/cron/service/store.ts src/cron/service/state.ts src/commands/doctor-cron.ts && node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --files src/cron/store.test.ts src/cron/service/store.test.ts src/cron/service/store.load-missing-session-target.test.ts src/commands/doctor-cron.test.ts src/commands/doctor-cron-store-migration.test.ts
- node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/cron/store.ts src/cron/service/store.ts src/cron/service/state.ts src/commands/doctor-cron.ts src/cron/store.test.ts src/cron/service/store.test.ts src/cron/service/store.load-missing-session-target.test.ts src/commands/doctor-cron.test.ts src/commands/doctor-cron-store-migration.test.ts
- git diff --check
- pnpm docs:list
- autoreview clean: no accepted/actionable findings reported
- GitHub CI: cron, doctor, docs, lint/type/build/security/quality, real behavior proof, and Windows rerun green; checks-node-agentic-agents remains red on current PR and recent main with unrelated pre-existing module/mock failures outside touched files.

Co-authored-by: yfge <geyunfei@gmail.com>
2026-05-29 10:27:45 +01:00
Peter Steinberger
c3e02d9fd4 fix(models): ignore unsafe page tokens 2026-05-29 05:22:55 -04:00
Peter Steinberger
837d6a13a2 test(release): refresh plugin sdk api baseline 2026-05-29 10:20:09 +01:00
Peter Steinberger
57a3dbe736 perf: avoid jiti for built plugin startup paths 2026-05-29 10:17:43 +01:00
Peter Steinberger
97afdc144d fix(file-transfer): validate node fetch byte limits 2026-05-29 05:15:56 -04:00
Vincent Koc
9bf48660b3 fix(ci): keep Windows Crabbox hydrate fetch alive 2026-05-29 11:12:22 +02:00
Vincent Koc
966c274f20 refactor: share browser snapshot helpers 2026-05-29 11:11:46 +02:00
Peter Steinberger
173a21f557 fix: refresh npm shrinkwrap after net policy split 2026-05-29 10:11:29 +01:00
兰之
6950e85605 fix(agents): allow hyphenated subagent task names
Allow `sessions_spawn.taskName` to accept lowercase hyphenated task slugs while keeping the existing underscore support and invalid-name rejection. Update the tool schema, system prompt wording, docs, focused tests, and generated prompt snapshots so the user/model-facing contract matches the validator.

Verification:
- `pnpm prompt:snapshots:check`
- `node scripts/run-vitest.mjs src/agents/tools/sessions-spawn-tool.test.ts src/agents/system-prompt.test.ts`
- Real behavior proof gate: https://github.com/openclaw/openclaw/actions/runs/26628449324/job/78470916945
- PR CI: https://github.com/openclaw/openclaw/actions/runs/26628441940, with failures matching current `main` at https://github.com/openclaw/openclaw/actions/runs/26628128225

Co-authored-by: chenhaoqiang <chenhaoqiang@xiaomi.com>
Co-authored-by: Lanzhi <lizhan3@xiaomi.com>
2026-05-29 10:10:12 +01:00
兰之
30c1ca5c7b fix: match slash commands case-insensitively
Match text slash command names case-insensitively across the reset/new fallback paths and the shared registry/control detection contract while preserving command argument casing.

Add regression coverage for uppercase and mixed-case reset/new commands plus registered non-reset commands such as `/STATUS`, `/Model`, `/T`, and `/COMPACT`.

Co-authored-by: zhangtong26 <zhangtong26@xiaomi.com>
Co-authored-by: Lanzhi <lizhan3@xiaomi.com>
2026-05-29 10:06:53 +01:00
Peter Steinberger
274a8116af fix(session): reject unsafe lifecycle durations 2026-05-29 05:06:26 -04:00
Peter Steinberger
5871d118ad fix: restore package CI after net policy split 2026-05-29 10:04:57 +01:00
Peter Steinberger
c951867a21 test(release): satisfy doctor migration lint 2026-05-29 10:04:42 +01:00
litang9
18f9310844 fix(gateway): clear stale chat stream buffers (#75089)
Merged via squash.

Prepared head SHA: 05ca0e30ac

Verification:
- gh pr checks 75089 --required --watch --fail-fast: dependency-guard passed.
- node scripts/run-vitest.mjs src/gateway/chat-abort.test.ts src/gateway/server-maintenance.test.ts src/gateway/server-close.test.ts src/gateway/server-methods/models-auth-status.test.ts src/gateway/server-methods/chat.abort-authorization.test.ts: 9 files, 136 tests passed on the rebased clean head.
- pnpm build and pnpm check passed after the rebase.
- Local live-style Gateway WebSocket RPC proof passed with a mock OpenAI Responses SSE provider.

Co-authored-by: litang9 <tangli1987118@hotmail.com>
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Reviewed-by: @osolmaz
2026-05-29 17:01:42 +08:00
Peter Steinberger
d506e9e666 fix(subagents): keep numeric log targets from shrinking history 2026-05-29 05:00:18 -04:00
Vincent Koc
9e002c12ac fix(video): bound generated video downloads 2026-05-29 11:00:06 +02:00
Vincent Koc
bee163bf37 refactor: share chrome cdp websocket diagnostics 2026-05-29 10:57:12 +02:00
Peter Steinberger
5fce8cef1e refactor(qa-lab): share guarded config merge patches 2026-05-29 04:54:42 -04:00
兰之
b620c58e65 fix: remove telegram-only reasoning stream copy
Remove stale Telegram-only wording from the reasoning stream acknowledgement and docs so channel-neutral behavior is reflected.

Fixes #68305.

Co-authored-by: Lanzhi <lizhan3@xiaomi.com>
2026-05-29 09:54:37 +01:00
Peter Steinberger
2e015ab124 test(release): fix beta live release checks 2026-05-29 09:54:00 +01:00
Rajvardhan Patil
5518ac998f fix(agents): add CLI turn output digests
Adds content-safe output fingerprints to CLI backend turn logs so repeated byte-identical responses can be detected from gateway logs without exposing response text.

Covers Claude live-session turns, synthetic cron before_agent_reply short-circuits, and ordinary CLI subprocess turns with shared outBytes/outHash fields.

Verification:
- pnpm test src/agents/cli-runner.spawn.test.ts src/agents/cli-runner.before-agent-reply-cron.test.ts -- --reporter=verbose
- pnpm check:changed (Blacksmith Testbox tbx_01kssdqes22wqhas0v7h339zr7)
- .agents/skills/autoreview/scripts/autoreview --mode local
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub PR checks passed for e130c1acbf

Fixes #81004

Co-authored-by: Rajvardhan Patil <raj@Rajvardhans-MacBook-Air.local>
2026-05-29 09:50:56 +01:00
Vincent Koc
850f7c24d4 refactor: share browser basic route helpers 2026-05-29 10:45:55 +02:00
Zee Zheng
17907bc2cd fix(clawdock): load compose override file
Load `docker-compose.override.yml` when ClawDock builds its explicit Docker Compose file list, preserving standard Compose override behavior while keeping `docker-compose.extra.yml` as the final OpenClaw overlay.

Update Docker docs so manual Compose users include the same override order, and keep the regression test for the generated `_clawdock_compose` arguments.

Fixes #49909.
Thanks @spacegeologist.

Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
2026-05-29 09:45:35 +01:00
Peter Steinberger
25b3c8ef71 refactor: remove old net policy sources 2026-05-29 09:45:14 +01:00
Peter Steinberger
f4c6c0aec4 refactor: extract net policy package 2026-05-29 09:45:14 +01:00
Peter Steinberger
03ac6e3171 fix(qa-lab): ignore prototype keys in patch checks 2026-05-29 04:44:37 -04:00
Phil
00ca654c74 fix(plugins): persist resolved npm install specs
Preserve npm install selectors while recording resolved npm provenance for plugin and hook install/update records. Active `record.spec` stays the requested selector unless explicitly pinned, while resolved npm fields remain available for audit and diagnostics.

Adds focused coverage for hook-pack npm fallback provenance after the maintainer review found that path worth pinning down.

Co-authored-by: Phil <99397913+GitHoubi@users.noreply.github.com>
2026-05-29 09:42:46 +01:00
tanshanshan
8201e851ca feat(zalouser): forward data.quote metadata into agent context
Forward Zalo quote-reply metadata from zca-js data.quote into the existing ReplyToId, ReplyToBody, and ReplyToIsQuote context keys so agents can correlate quoted replies with prior bot messages.

Adds parser and monitor regression coverage for quote extraction and context projection.

Fixes #86851.
Thanks @tanshanshan.
2026-05-29 09:42:39 +01:00
Peter Steinberger
e144d1c8d9 fix(oc-path): reject noncanonical array indexes 2026-05-29 04:37:41 -04:00
Chunyue Wang
fb6f2c61bf fix(auto-reply): deliver compact replies in room events
Restore visible terminal command replies for explicit command turns that are otherwise source-suppressed in room-event/message-tool-only delivery. Also keep compaction notifyUser notices independent from internal callbacks while preserving hook-message de-duplication.

Fixes #87107

Verification:
- git diff --check origin/main...HEAD
- node scripts/run-vitest.mjs src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts src/auto-reply/reply/agent-runner-execution.test.ts
- GitHub required check dependency-guard passed on d3aaad90fc
- Relevant GitHub auto-reply/build/lint/type/security checks passed on d3aaad90fc

Co-authored-by: openperf <16864032@qq.com>
2026-05-29 09:35:19 +01:00
Peter Steinberger
def11c0978 fix(plugins): bound config contract array indexes 2026-05-29 04:29:14 -04:00
Vincent Koc
628104662b refactor: share browser client request helpers 2026-05-29 10:26:44 +02:00
Peter Steinberger
d4a17477b0 fix(schema): reject noncanonical array refs 2026-05-29 04:25:10 -04:00
Peter Steinberger
b78ebacb18 refactor: centralize plugin model discovery 2026-05-29 09:24:08 +01:00
Jayesh Betala
189a7962b2 fix(cli): reject empty config path segments
Reject malformed dot-notation config paths before `openclaw config get/set/unset` reads or mutates config. Empty, leading, trailing, whitespace-only, and dot-before-bracket segments now fail closed instead of normalizing to a different key, while valid bracket paths and escaped dots continue to work.

Thanks @jbetala7 for the fix.

Verification:
- `git diff --check`
- `node scripts/run-vitest.mjs run src/cli/config-cli.test.ts` (111 passed)
- GitHub exact-head checks on `116254ba414bff6a0c3881e34fad30baca95ef0a`: 76 success, 23 skipped, 1 neutral, 0 failures

Fixes #87564

Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
2026-05-29 09:23:32 +01:00
UB
d18ee1881c fix(discord): remove optional runtime error shims
Remove unreachable optional chaining from four Discord message-handler-family runtime error calls.

This aligns the code with the required RuntimeEnv.error contract while leaving production behavior unchanged for valid runtimes. Maintainer-updated PR proof clarifies that shared queue reporter hooks still treat malformed runtime reporter failures as best-effort.
2026-05-29 09:22:44 +01:00
Peter Steinberger
5ff0c75da7 fix(config): preserve large numeric schema keys 2026-05-29 04:20:42 -04:00
Peter Steinberger
f6d293a1ee fix(telegram): reject unsafe callback pages 2026-05-29 04:15:13 -04:00
Ninty
ee6eab8143 fix(agents): clean up exec abort listener after completion (#83022)
Clean up completed exec tool-call abort listeners so normal foreground completion and background-yield no longer retain the exec run/session context through AbortSignal listener state.

The listener cleanup now lives beside the exec listener registration and runs when the foreground process settles, rejects, or the tool returns a background running result. Existing abort/timeout/background behavior remains owned by the process supervisor and process registry.

Verification:
- gh pr checks 83022
- gh api repos/openclaw/openclaw/commits/fe86528ecb2043b6febef5c2eec53f9124be5543/check-runs
- git merge-tree --write-tree origin/main refs/remotes/pr/83022
- git diff --check origin/main...refs/remotes/pr/83022
- node AbortSignal add/remove listener probe

Thanks @c19354837.

Co-authored-by: Ninty <c19354837@hotmail.com>
2026-05-29 09:15:07 +01:00
Syu
843577f69a test(tasks): cover legacy flow run migration edge cases
Add regression coverage for legacy and hybrid flow_runs SQLite migrations, including post-rebuild managed writes and canonical owner_key schema assertions.\n\nVerification:\n- node scripts/run-vitest.mjs src/tasks/task-flow-registry.store.test.ts\n- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
2026-05-29 09:15:01 +01:00
Vincent Koc
a4bb9b1438 refactor: share browser debug route responses 2026-05-29 10:14:18 +02:00
Peter Steinberger
895d1a90f3 fix(google-meet): reject invalid auth timeouts 2026-05-29 04:11:02 -04:00
Vincent Koc
456cade93c fix(together): bound generated video downloads 2026-05-29 10:10:39 +02:00
Jayesh Betala
2990c00cb5 fix(skills): tolerate BOM-prefixed frontmatter
Fixes #66479.

Workspace skills whose SKILL.md starts with a UTF-8 BOM now keep their shared markdown frontmatter metadata, so they remain discoverable through skills list. The fix strips one leading BOM at the parser boundary and adds parser plus workspace discovery regression coverage.

Thanks @jbetala7 for the fix.

Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
2026-05-29 09:10:21 +01:00
Peter Steinberger
35cdd40182 fix(cli): reject unsafe duration values 2026-05-29 04:06:56 -04:00
Pavan Kumar Gondhi
9497629c1e fix(msteams): pin attachment fetch DNS
Route Microsoft Teams attachment downloads through the shared SSRF guarded fetch path so DNS validation is pinned into the dispatcher used for the actual request.

Keep Teams auth fallback and allowlisted HTTPS Authorization redirect behavior while failing closed for custom fetch hooks that cannot accept dispatcher injection.

Verification:
- CI=1 OPENCLAW_VITEST_MAX_WORKERS=1 timeout 300 node scripts/run-vitest.mjs run extensions/msteams/src/attachments/shared.test.ts extensions/msteams/src/attachments/bot-framework.test.ts src/infra/net/fetch-guard.ssrf.test.ts
- gh pr checks 87567 --repo openclaw/openclaw --watch=false

PR: #87567
2026-05-29 09:03:50 +01:00
Peter Steinberger
e5063f51cb fix(phone-control): reject invalid arm durations 2026-05-29 04:03:45 -04:00
Vincent Koc
3e050d05e8 refactor: share session tab registry helpers 2026-05-29 10:02:18 +02:00
Peter Steinberger
8363d6596c ci: retry transient checkout fetch timeouts 2026-05-29 09:00:45 +01:00
Peter Steinberger
6fab00acaa fix(docs): preserve plugin reference manual sections 2026-05-29 09:00:28 +01:00
Peter Steinberger
24614ac100 refactor(browser): centralize route numeric readers 2026-05-29 03:59:19 -04:00
Vincent Koc
6c309b9883 refactor: share browser route navigation policy 2026-05-29 09:52:12 +02:00
Peter Steinberger
2ea8d88d63 fix(browser): validate cookie expiry values 2026-05-29 03:50:19 -04:00
Vincent Koc
0fbd975fe8 test(infra): avoid host-specific exec path fixtures 2026-05-29 09:49:49 +02:00
Peter Steinberger
ac52499aca fix(browser): validate screenshot timeout 2026-05-29 03:46:53 -04:00
Vincent Koc
4ad875308f fix(memory): bound remote JSON responses 2026-05-29 09:45:39 +02:00
Peter Steinberger
c48a4a3188 fix(browser): validate geolocation options 2026-05-29 03:43:06 -04:00
Abdel Gomez-Perez
9de6abd8d7 fix(agents): bridge CLI tool progress events 2026-05-29 13:04:31 +05:30
Peter Steinberger
c7f50738c0 fix(browser): validate permission grant timeout 2026-05-29 03:34:06 -04:00
Peter Steinberger
dca86d47e0 fix(browser): validate hook download timeouts 2026-05-29 03:30:46 -04:00
Peter Steinberger
854cb9292d fix(browser): validate response body numeric options 2026-05-29 03:27:34 -04:00
Vincent Koc
fce7470495 refactor: share file transfer node host path handling 2026-05-29 09:26:24 +02:00
Peter Steinberger
0b24f47465 fix(browser): tighten act numeric parsing 2026-05-29 03:23:42 -04:00
Peter Steinberger
4fae13e29e fix(browser): centralize snapshot numeric parsing 2026-05-29 03:15:56 -04:00
Peter Steinberger
0bc591a7d7 fix(browser): reject invalid tab indexes 2026-05-29 03:07:15 -04:00
Vincent Koc
0a14f593c3 refactor: share file transfer node invoke handling 2026-05-29 09:05:36 +02:00
Vincent Koc
c9a939ad2d fix(release): bound ClawHub owner metadata 2026-05-29 09:03:22 +02:00
Peter Steinberger
286883cc54 fix(browser): cap route timer delays 2026-05-29 03:03:07 -04:00
Peter Steinberger
b0730944eb fix(browser): cap cli request timeouts 2026-05-29 02:50:51 -04:00
Vincent Koc
d78b0814d5 fix(gateway): avoid cold-loading providers for MCP inventory 2026-05-29 08:48:35 +02:00
Vincent Koc
2879f76301 refactor: share xai code execution tool config 2026-05-29 08:48:27 +02:00
Peter Steinberger
13ac8a0758 fix(google-meet): validate api page size 2026-05-29 02:46:50 -04:00
Peter Steinberger
31f3914082 fix(voice-call): bound cli numeric options 2026-05-29 02:42:44 -04:00
Peter Steinberger
8e56c024df fix(gateway): cap handshake timer delays 2026-05-29 02:38:45 -04:00
Vincent Koc
70230f4235 refactor: share brave web search metadata 2026-05-29 08:34:37 +02:00
Vincent Koc
44adda3195 fix(release): bound ClawHub verifier responses 2026-05-29 08:33:50 +02:00
Peter Steinberger
4829d30cf0 fix(mattermost): bound slash callback env port 2026-05-29 02:31:53 -04:00
ZC
7a381b807e fix(cron): preflight model fallbacks before skip (#82887)
Fix cron local-model preflight fallback handling so scheduled runs try configured fallback candidates before skipping when the local primary is unavailable.

Verification:
- GitHub CI on PR head fe884dab90: passing required CI checks.
- Local focused cron/model fallback tests passed earlier for the touched surface.
- Local merge-wrapper build and check passed on the prepared candidate.
- Local full pnpm test reported unrelated failures outside this PR's touched files; touched files are limited to cron docs, src/agents/model-fallback.ts, and src/cron/isolated-agent/*.

Co-authored-by: chen-zhang-cs-code <chenzhangcode@163.com>
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
2026-05-29 14:29:26 +08:00
Ayaan Zaidi
c559776c51 fix(channels): preserve room event progress suppression 2026-05-29 11:56:58 +05:30
Ayaan Zaidi
f9b1132bbb test(channels): cover suppressed group progress callbacks 2026-05-29 11:56:58 +05:30
Peter Lindsey
85b6f91bd7 fix(dispatch): forward channel-owned progress callbacks in all chat types when verbose is off
Remove the chatType === 'direct' guard from
shouldAllowQuietChannelOwnedProgressCallbacks so that channel-owned native
progress callbacks (onToolStart, onItemEvent, onPlanUpdate,
onApprovalEvent, onCommandOutput, onPatchSummary, onCompactionStart/End)
are forwarded in group and group-channel sessions when verbose is off.

Previously the guard required chatType === 'direct', which meant that
/verbose off would suppress all progress callbacks in group sessions
while direct sessions continued to relay them. Message-level tool
summary suppression is handled separately; native channel relay hooks
should not be gated on chat type.

Closes #87612
2026-05-29 11:56:58 +05:30
Peter Steinberger
0f0c744517 fix(config): bound gateway env ports 2026-05-29 02:26:01 -04:00
Vincent Koc
91a78477d0 refactor: share xai web search metadata 2026-05-29 08:23:32 +02:00
Peter Steinberger
625b793635 fix(daemon): centralize tcp port bounds 2026-05-29 02:22:03 -04:00
YEEE
aa53823981 fix(whatsapp): resolve auth dir from active profile (#82492)
Merged via squash.

Prepared head SHA: 82b1404905
Co-authored-by: lidge-jun <243035832+lidge-jun@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-05-29 03:20:26 -03:00
Rob Pierson
b474f429ee feat(plugin-sdk): add reply payload sending hook (#82823)
* feat(plugin-sdk): add reply payload sending hook

* fix(dispatch): compose caller beforeDeliver with plugin hooks instead of nullish-coalescing

ClawSweeper review identified that Telegram's identity beforeDeliver
would skip reply_payload_sending and message_sending hooks entirely.
Now we always compose caller-provided hooks with global plugin hooks
so plugins get a chance to run even when the caller already supplies
a beforeDeliver hook.

Also adds regression test for composition case.

* test(dispatch): align beforeDeliver hook assertion with current context

* fix(plugin-sdk): remove leftover merge markers from hook types

* feat(plugin-sdk): add reply payload sending hook

* fix(plugin-sdk): protect reply payload media trust

* fix(auto-reply): honor suppressed routed ACP blocks

* fix(auto-reply): avoid double message sending hooks

* fix(auto-reply): require routed reply kind

* test(auto-reply): type routed suppression mock

* fix(auto-reply): honor reply payload hooks in followups

* fix(auto-reply): suppress empty hooked dispatcher replies

* fix(auto-reply): wire reply payload hooks at dispatcher boundary

* fix(plugins): preserve reply payload metadata in hooks

* fix(auto-reply): defer reply hook availability checks

* fix(auto-reply): preserve message hook order for routed payloads

* fix(auto-reply): persist routed payload hook decisions

* fix(auto-reply): run routed payload hooks inside delivery

* fix(auto-reply): enforce message hooks after payload edits

* fix(auto-reply): gate source reply mirrors on delivery

* fix(auto-reply): scope hook-mutated media delivery

* chore(plugin-sdk): refresh reply hook api baseline

* fix(auto-reply): mirror delivered source replies

---------

Co-authored-by: Rob via OpenClaw <noreply@openclaw.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-29 07:15:10 +01:00
Peter Steinberger
8d63d466b8 fix(infra): preserve inline option values 2026-05-29 02:12:59 -04:00
Vincent Koc
05ff7d374f refactor: share tavily web search helpers 2026-05-29 08:12:48 +02:00
Gio Della-Libera
08beb6b0e8 Policy: add policy file comparison command (#86768)
Merged via squash.

Prepared head SHA: 2023e8cba1
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-05-28 23:10:27 -07:00
Galin Iliev
8124fb4aa4 fix(gateway): cache single session row child indexes
Cache single-row gateway session child indexes without hiding live subagent registry changes.

Summary:
- Reuses store-derived child-session candidates for repeated single-row session loads.
- Keeps runtime subagent registry reads live per row so moved child sessions do not stay attached to stale parents.
- Versions the session-store cache and includes that version in the single-row cache key so same-object store rewrites cannot reuse stale child candidates.
- Adds focused regression coverage for cache reuse, live registry refresh, and same-object session-store writes.

Verification:
- git diff --check
- pnpm tsgo:prod
- pnpm test src/gateway/session-utils.single-row-cache.test.ts src/gateway/session-utils.subagent.test.ts -- --reporter=verbose
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI run 26620265206: passing
- Azure Crabbox cbx_a58389e50f49: single-row-loads 13.622240 ms before vs 1.869456 ms after, 7.29x speedup, 86.3% reduction
2026-05-28 23:09:10 -07:00
Peter Steinberger
f212176e91 fix(azure): preserve equals in deployment maps 2026-05-29 02:03:03 -04:00
Vincent Koc
611adb2ee0 test(browser): align loopback auth mock types 2026-05-29 08:01:21 +02:00
Vincent Koc
667c03f87e refactor: share fal provider http auth 2026-05-29 08:01:21 +02:00
Peter Steinberger
fa9901c78f fix(discord): escape component custom id delimiters 2026-05-29 01:58:31 -04:00
Dallin Romney
ed36f423da fix(ci): bound manual git fetches (#87839)
* fix(ci): bound manual git fetches

* fix(ci): cover platform fetch guards

* fix(ci): fail timed out target fetches

* fix(ci): repair typecheck regressions

* fix(ci): refresh CI expectations

* fix(ci): preserve main cron coverage
2026-05-28 22:56:54 -07:00
Vincent Koc
2e042fbca8 fix(browser): reject excessive viewport resizes 2026-05-29 07:51:27 +02:00
Dallin Romney
cdeafd1895 chore: revert dependency guard backfill machinery (#87867)
* Revert "ci: isolate dependency guard backfill label (#87882)"

This reverts commit 21b33bd04d.

* Revert "ci: add dependency guard backfill label trigger (#87866)"

This reverts commit 5a6472718d.

* ci: preserve clawsweeper bot label filter
2026-05-28 22:50:59 -07:00
Peter Steinberger
621db8f0b1 fix(browser): reject explicit zero cdp ports 2026-05-29 01:43:05 -04:00
Vincent Koc
f5e1fe9755 refactor: share firecrawl web search metadata 2026-05-29 07:41:27 +02:00
Peter Steinberger
e9d49299d6 fix(canvas): default malformed host base paths 2026-05-29 01:34:30 -04:00
Peter Steinberger
00e4d54e1f fix(diffs): normalize render presentation numbers 2026-05-29 01:31:35 -04:00
Dallin Romney
31627d0808 fix(gateway): drop unused transcript option binding (#87899) 2026-05-28 22:29:57 -07:00
Peter Steinberger
6bf2fdf739 fix(channels): normalize direct dm guard numeric overrides 2026-05-29 01:28:40 -04:00
Peter Steinberger
fa1d5f6584 fix(markdown): normalize non-finite render chunk limits 2026-05-29 01:25:26 -04:00
Peter Steinberger
1e5ccd1ce8 fix(matrix): centralize initial sync limit coercion 2026-05-29 01:22:24 -04:00
Peter Steinberger
b43910b590 fix(gateway): default non-finite http media caps 2026-05-29 01:17:41 -04:00
Vincent Koc
6fdf6b0680 refactor: share acp dispatch text helpers 2026-05-29 07:15:41 +02:00
Peter Steinberger
13cb9f8277 docs: update Anthropic Claude CLI billing guidance 2026-05-29 06:14:30 +01:00
Peter Steinberger
8eb5ff08c8 fix(agents): bound media duplicate guard age 2026-05-29 01:12:45 -04:00
Vincent Koc
309fdd95da fix(scripts): silence diffs viewer side-effect warning 2026-05-29 07:11:46 +02:00
Peter Steinberger
1188aa3b81 feat: add Claude Opus 4.8 support (#87890)
* feat: add Claude Opus 4.8 support

* fix: omit Vertex Opus sampling overrides

* fix: preserve Opus adaptive thinking levels

* fix: clamp Anthropic max effort support

* fix: use sha256 for QA mock call ids

* fix: type Anthropic transport test model metadata

* test: update PDF model default for Opus 4.8
2026-05-29 06:10:42 +01:00
Peter Steinberger
98611e6272 fix(agents): normalize subagent capability depth 2026-05-29 01:09:04 -04:00
Gio Della-Libera
5fb83af3e3 Policy: add ingress channel conformance checks (#85744)
Policy: add ingress channel conformance checks (#85744)

Merged via squash.

Prepared head SHA: bd63c8d153
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-05-28 22:07:49 -07:00
Peter Steinberger
0e86ca1352 fix(gateway): default non-finite recent transcript limits 2026-05-29 01:05:04 -04:00
clawsweeper[bot]
22e8cd2a1d fix(gateway): clear completed session active runs (#87810)
Summary:
- This PR adds an internal gateway active-run projection flag, clears it during terminal lifecycle handling be ... ons.list on that flag, adds gateway regression coverage, and tightens memory-wiki confidence normalization.
- PR surface: Source +29, Tests +131. Total +160 across 7 files.
- Reproducibility: yes. Source inspection shows current main can broadcast terminal sessions.changed before ch ...  the abort-controller entry, and the before/after recording supports the visible stuck In progress symptom.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): preserve chat retry guard after terminal state
- PR branch already contained follow-up commit before automerge: fix(gateway): clear completed session active runs

Validation:
- ClawSweeper review passed for head 9b132bdc2b.
- Required merge gates passed before the squash merge.

Prepared head SHA: 9b132bdc2b
Review: https://github.com/openclaw/openclaw/pull/87810#issuecomment-4569094800

Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-29 05:03:10 +00:00
Peter Steinberger
7979639cd8 fix(gateway): cap non-finite preauth limits 2026-05-29 01:01:20 -04:00
Peter Steinberger
8ada0f4ae2 fix(gateway): default non-finite auth guard limits 2026-05-29 00:58:19 -04:00
Vincent Koc
1d11178d02 refactor: reuse subagent target resolver 2026-05-29 06:56:03 +02:00
Galin Iliev
935f84b8e9 fix(agents): reuse cached subagent registry reads
Reduce repeated subagent registry clone work on hot read paths while preserving cloned snapshot behavior for default callers.

Verification:
- pnpm tsgo:prod
- node scripts/run-vitest.mjs src/agents/subagent-registry.persistence.test.ts --reporter=verbose
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- PR CI green at 51bd608d09
2026-05-28 21:55:44 -07:00
Peter Steinberger
141b0b3afb fix(discord): normalize scheduler numeric options 2026-05-29 00:55:27 -04:00
Peter Steinberger
3c5f5efc8c fix(discord): default non-finite chunk limits 2026-05-29 00:51:17 -04:00
Peter Steinberger
59cec74d89 fix(browser): clamp non-finite viewport dimensions 2026-05-29 00:46:07 -04:00
Vincent Koc
0f72a042d6 fix(scripts): harden shared flag parsing 2026-05-29 06:45:21 +02:00
Peter Steinberger
1e48ca4e32 fix(browser): default non-finite chrome mcp click delays 2026-05-29 00:42:37 -04:00
Vincent Koc
4b147f2c2e refactor: share embedding provider runtime lookup 2026-05-29 06:41:16 +02:00
Ted Li
8a60f39221 fix(agents): enforce subagent run timeouts
Fix explicit subagent runTimeoutSeconds enforcement so wait, lifecycle, session-store reconciliation, sweeper recovery, pending delivery retry, and in-flight cleanup paths preserve the configured deadline as the terminal contract.

Adds regression coverage for late competing terminal sources, observed child/session starts, restored successful waits without startedAt, and cron schedule identity stagger normalization.

Co-authored-by: Ted Li <tl2493@columbia.edu>
2026-05-29 05:39:41 +01:00
Peter Steinberger
4638f58615 fix(browser): default non-finite keypress delays 2026-05-29 00:38:45 -04:00
Peter Steinberger
c7144a8689 fix(browser): default non-finite DOM text budgets 2026-05-29 00:35:43 -04:00
Peter Steinberger
4dd3ba149c fix(browser): default non-finite snapshot limits 2026-05-29 00:32:35 -04:00
Peter Steinberger
30c24bba97 fix(core): centralize non-finite integer options 2026-05-29 00:28:32 -04:00
Peter Steinberger
27cd18748f fix(memory): default non-finite lancedb text limits 2026-05-29 00:23:52 -04:00
Dallin Romney
21b33bd04d ci: isolate dependency guard backfill label (#87882) 2026-05-28 21:21:13 -07:00
Vincent Koc
2fef80aee5 refactor: share provider catalog projection 2026-05-29 06:21:05 +02:00
Peter Steinberger
25a5cb3270 fix(memory): default non-finite qmd read windows 2026-05-29 00:18:27 -04:00
Ramrajprabu
f3cfd752d3 feat(copilot): add GitHub Copilot agent runtime
Adds the opt-in bundled GitHub Copilot agent runtime, pinned SDK install path, docs/inventory, SDK/tool/sandbox/auth wiring, and replay/tool-safety fixes.

Verification:
- Local: git diff --check; fnm exec --using 24.15.0 pnpm tsgo:extensions; fnm exec --using 24.15.0 pnpm check:test-types; fnm exec --using 24.15.0 pnpm build.
- Autoreview local: clean for the replay-safety fix; branch autoreview engine returned empty output twice, so local autoreview plus local/Crabbox/CI proof was used.
- Crabbox focused Copilot: run_2c0db9f48a4a, 19 files / 485 tests passed.
- Crabbox additional boundary shard: run_26a246a1aa24, prompt snapshots and plugin SDK boundary/export checks passed.
- Crabbox live Copilot: run_d128e4048b4e, real gpt-4.1 turn with live_echo phase-1-green and clean session-file check.
- GitHub checks: green on head 7cc8657e0d, including Dependency Guard after exact-head approval.

Co-authored-by: Ramraj Balasubramanian <ramrajba@microsoft.com>
2026-05-29 05:15:22 +01:00
Peter Steinberger
15772c527a fix(memory-wiki): default non-finite search limits 2026-05-29 00:14:26 -04:00
Peter Steinberger
846ca1e5bd fix(memory-wiki): default non-finite page line options 2026-05-29 00:11:30 -04:00
Vincent Koc
dc0d833efc fix(scripts): reject loose changed bench workers 2026-05-29 06:10:03 +02:00
Peter Steinberger
9596b7bd7a fix(memory): default non-finite read window options 2026-05-29 00:07:49 -04:00
Peter Steinberger
adabff1bf0 fix(browser): centralize non-finite tool timeouts 2026-05-29 00:04:04 -04:00
Peter Steinberger
0bacc93208 fix(qa-lab): keep package telegram harness off private sdk 2026-05-29 05:03:10 +01:00
Peter Steinberger
dac13d9a69 fix(browser): default non-finite navigation timeouts 2026-05-29 00:00:44 -04:00
Gio Della-Libera
af64a824a1 Policy: add sandbox posture conformance checks (#85572)
Policy: add sandbox posture conformance checks (#85572)

Merged via squash.

Prepared head SHA: 1cf1953d8c
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-05-28 21:00:24 -07:00
Vincent Koc
c037ab5c74 fix(doctor): report failed MCP tool schema loading 2026-05-29 05:57:24 +02:00
Vincent Koc
58149e41dc fix(scripts): reject loose startup bench budgets 2026-05-29 05:56:59 +02:00
Peter Steinberger
00c9f81171 fix: retry transient recurring cron failures 2026-05-29 04:54:42 +01:00
Peter Steinberger
3c8ad8cbaa fix(browser): default non-finite fetch timeouts 2026-05-28 23:52:40 -04:00
Peter Steinberger
b2bdad5bee fix(browser): default non-finite snapshot timeouts 2026-05-28 23:48:33 -04:00
Vincent Koc
27b15a19e8 refactor(voice): catalog voice models through providers (#87794)
* refactor(providers): catalog voice models

* feat(tts): route speech through voice models

* refactor(tts): rename speaker selection fields

* refactor(tts): mark default speech models

* test(tts): type migrated speaker config assertions

* refactor(providers): avoid catalog merge map spread

* fix(tts): honor voice model fallbacks

* refactor(tts): move speech core into package

* chore(tts): register speech core knip workspace

* fix(tts): show migrated speaker voice in status

* fix(tts): satisfy speech core lint

* fix(tts): preserve explicit model aliases

* test(tts): narrow provider config assertion

* test(doctor): allow slow commitments repair check

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-29 04:46:45 +01:00
Vincent Koc
398b98dcbe refactor: share acpx lazy runtime proxy 2026-05-29 05:45:20 +02:00
Vincent Koc
9ec4e94c48 fix(scripts): reject loose test perf budgets 2026-05-29 05:44:56 +02:00
Peter Steinberger
18ef59bb33 fix(browser): default non-finite dialog arm timeouts 2026-05-28 23:44:42 -04:00
Peter Steinberger
e7fb8cabb6 fix(discord): default non-finite identify concurrency 2026-05-28 23:40:43 -04:00
Peter Steinberger
6f9d5e1b95 fix(channels): default non-finite typing options 2026-05-28 23:37:28 -04:00
Peter Steinberger
2209faef40 feat: improve cron create delivery ergonomics
Summary:
- Add Hermes-style schedule-first cron create parsing while preserving flagged create options.
- Support webhook create/edit delivery and clear stale webhook/chat delivery fields across mode changes.
- Update cron docs and schedule identity normalization tests.

Verification:
- pnpm test src/cron/schedule-identity.test.ts src/cli/cron-cli.test.ts src/cron/service.jobs.test.ts -- --reporter=verbose
- pnpm test src/cli/cron-cli.test.ts src/cron/service.jobs.test.ts -- --reporter=verbose
- pnpm check:test-types
- pnpm check:import-cycles
- pnpm check:docs
- pnpm check:changed via Crabbox run_8c44bcb158da, exit 0
- autoreview branch diff clean
2026-05-29 04:34:50 +01:00
Vincent Koc
4b18234fc1 fix(scripts): enforce plugin sdk surface budgets 2026-05-29 05:32:12 +02:00
Vincent Koc
bf30361bc8 refactor: dedupe voice stream frame adapter 2026-05-29 05:31:50 +02:00
Peter Steinberger
cb085ec5f1 fix(discord): default non-finite REST numeric options 2026-05-28 23:30:47 -04:00
Dallin Romney
5a6472718d ci: add dependency guard backfill label trigger (#87866) 2026-05-28 20:26:32 -07:00
Peter Steinberger
fd643139b1 fix(memory): validate non-finite lancedb numeric config 2026-05-28 23:22:32 -04:00
Peter Steinberger
d8f2437cf4 test(doctor): bound config flow schema warnings 2026-05-29 04:22:23 +01:00
Vincent Koc
ffd4a80145 refactor: share live transport QA CLI helpers 2026-05-29 05:21:23 +02:00
clawsweeper[bot]
4df1fcf7b3 feat(discord): show commentary in progress drafts (#85200)
Adds opt-in Discord progress-draft commentary for assistant preambles while keeping commentary hidden by default and final delivery unchanged.
Keeps commentary config Discord-specific, strips directive tags/NO_REPLY, and clears stale commentary rows without stopping the active draft stream.
Thanks @bryanpearson.

Co-authored-by: bryanpearson <bryanmpearson@gmail.com>
2026-05-29 04:21:06 +01:00
Forrest 0x59
5c7f960125 fix(test): resolve temp dir outside Windows mock to prevent dirty folders on Linux (#85677)
Merged via squash.

Prepared head SHA: ddd6291bde
Co-authored-by: forrest0x59 <250948165+forrest0x59@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-05-29 00:18:43 -03:00
Peter Steinberger
5a84869c06 test: remove duplicate catalog write expectation 2026-05-29 04:15:27 +01:00
Peter Steinberger
bca6a91fc4 fix: harden smart-quoted argument repair (#86611) 2026-05-29 04:15:27 +01:00
Fermin Quant
059bed7731 fix(agents): repair smart-quoted edit arrays 2026-05-29 04:15:27 +01:00
Fermin Quant
d4543ac8e4 fix(agents): satisfy smart quote lint 2026-05-29 04:15:27 +01:00
Fermin Quant
fae58591cd fix(agents): decode smart-quoted arg escapes 2026-05-29 04:15:27 +01:00
Fermin Quant
d560588e1e fix(agents): handle exact smart-quoted args 2026-05-29 04:15:27 +01:00
Fermin Quant
1c0b8f6a6b fix(agents): repair smart-quoted tool args 2026-05-29 04:15:27 +01:00
Peter Steinberger
5f301e09ea fix(sandbox): default non-finite novnc token ttl 2026-05-28 23:08:57 -04:00
Peter Steinberger
f2dfb67f2c fix(agents): default non-finite run wait timeouts 2026-05-28 23:05:26 -04:00
Peter Steinberger
01d9963e4e fix(models): default non-finite catalog browse timeout 2026-05-28 23:01:45 -04:00
samzong
c237de552a [Fix] Prefer external session delivery context (#87476)
* fix(sessions): prefer external delivery context

Signed-off-by: samzong <samzong.lu@gmail.com>

* fix: route Feishu session announces from delivery context

* fix: accept normalized cron schedule inputs

---------

Signed-off-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-29 03:59:54 +01:00
Peter Steinberger
3cf9877d0c fix(agents): alias typebox format for extensions 2026-05-29 03:58:59 +01:00
Peter Steinberger
d503ec52d8 feat: add Fal Krea image model schemas (#87845)
* feat: add fal krea image model schemas

* fix: support fal model-specific aspect ratios

* fix: preserve fal native auto aspect ratio

* fix: honor image model-specific geometry
2026-05-29 03:58:46 +01:00
Peter Steinberger
c91cbf3f71 fix(codex): default non-finite app-server timeouts 2026-05-28 22:58:14 -04:00
Vincent Koc
b012ae46aa refactor: dedupe migrate selection helpers 2026-05-29 04:55:42 +02:00
Peter Steinberger
ee3efc0152 test(plugins): alias gateway workspace packages in plugin loader 2026-05-29 03:54:10 +01:00
Peter Steinberger
45892a6595 fix(heartbeat): default non-finite schedule inputs 2026-05-28 22:53:53 -04:00
Peter Steinberger
9d84a13bb8 fix(slack): default non-finite thread cache options 2026-05-28 22:51:16 -04:00
Peter Steinberger
9dd3bce549 feat: add codex supervisor extension
* feat: add codex supervisor plugin

* fix: restore merged branch checks

* fix: unblock supervisor extension CI

* fix: restore merged agent checks
2026-05-29 03:49:43 +01:00
Peter Steinberger
c8cc010e09 fix(infra): centralize non-finite numeric option bounds 2026-05-28 22:48:19 -04:00
Peter Steinberger
6e25112aad fix(collection): preserve maps for non-finite upper bounds 2026-05-28 22:42:43 -04:00
Peter Steinberger
a4ff3e19ea test: repair gateway client boundary snapshots 2026-05-29 03:40:08 +01:00
Vincent Koc
9ca791288c fix(scripts): parse startup bench gateway ports 2026-05-29 04:39:37 +02:00
Peter Steinberger
564ccf1faa fix(dedupe): bound non-finite retention options 2026-05-28 22:39:09 -04:00
Vincent Koc
47e86bc1ac refactor: share task sqlite store helpers 2026-05-29 04:35:45 +02:00
Peter Steinberger
7f6579e416 fix(shared): default non-finite string sample limits 2026-05-28 22:35:00 -04:00
Peter Steinberger
19d9e71b84 fix(shared): bound non-finite expiring cache options 2026-05-28 22:33:10 -04:00
Peter Steinberger
dbf711c2ea fix(acp): default non-finite session rate limits 2026-05-28 22:31:17 -04:00
Peter Steinberger
c7a1e909a3 fix(plugin-sdk): default non-finite webhook guard limits 2026-05-28 22:29:04 -04:00
Peter Steinberger
fce00ccb6e fix(acp): ignore non-finite retention options 2026-05-28 22:26:20 -04:00
Peter Steinberger
2f8b1a8c0e fix(gateway): default non-finite readiness waits 2026-05-28 22:24:00 -04:00
Peter Steinberger
51b5f75b92 refactor: move plugin model catalogs into plugin state 2026-05-29 03:23:57 +01:00
Peter Steinberger
94db48d028 fix(sandbox): skip non-finite docker resource limits 2026-05-28 22:20:49 -04:00
Peter Steinberger
2dcca3ec8a test(vitest): alias gateway client package to source 2026-05-29 03:17:06 +01:00
Vincent Koc
91df558e69 fix(qa): reject loose otel size limits 2026-05-29 04:16:15 +02:00
Peter Steinberger
6f2add2cc6 fix(gateway): centralize safe timeout delays 2026-05-28 22:15:15 -04:00
Peter Steinberger
bb2254520d test: fix cron schedule identity legacy fixture types 2026-05-29 03:12:56 +01:00
Peter Steinberger
d5bbf3033c perf: avoid full session snapshots for entry reads 2026-05-29 03:12:56 +01:00
Peter Steinberger
c36ba9ea7a fix(memory): keep qmd numeric overrides positive 2026-05-28 22:11:58 -04:00
Peter Steinberger
185e62a9ae fix: show reasoning previews in Slack 2026-05-29 03:08:48 +01:00
Peter Steinberger
66bf324256 fix: default non-finite matrix timeouts 2026-05-28 22:07:49 -04:00
Peter Steinberger
0d189102f5 fix: clamp web provider subsecond timeouts 2026-05-28 22:04:22 -04:00
Vincent Koc
60392a1136 fix(scripts): reject loose memory fd limits 2026-05-29 03:59:04 +02:00
Peter Steinberger
d7aa368776 fix: reject negative cron timeouts 2026-05-28 21:58:00 -04:00
Peter Steinberger
025e6ac31d refactor: tighten gateway client test boundary 2026-05-29 02:56:51 +01:00
Peter Steinberger
f5cb6177e4 fix: align message numeric schemas 2026-05-28 21:54:23 -04:00
Vincent Koc
c3e629cbf4 refactor: share non-interactive onboard config writes 2026-05-29 03:51:51 +02:00
Peter Steinberger
edda0608ac fix: advertise telegram poll duration integer 2026-05-28 21:51:28 -04:00
Peter Steinberger
b425438a58 fix(memory-wiki): narrow synthesis confidence normalization 2026-05-29 02:49:06 +01:00
Peter Steinberger
c0094a232d fix: validate feishu bitable page size 2026-05-28 21:48:06 -04:00
Peter Steinberger
d6c76eb5bf perf: prefer bundled plugin dist entries 2026-05-29 02:47:30 +01:00
Peter Steinberger
d33c2eefce fix: validate feishu chat page size 2026-05-28 21:45:20 -04:00
Peter Steinberger
d2fbc8c0e7 fix: validate message poll duration hours 2026-05-28 21:43:04 -04:00
Vincent Koc
4835a7ecd9 fix(e2e): reject loose parallels limits 2026-05-29 03:41:25 +02:00
Peter Steinberger
b779bdb5a0 fix: centralize cron schedule number coercion 2026-05-28 21:39:06 -04:00
Vincent Koc
a087dbd9e9 fix(doctor): validate tool schemas with model context 2026-05-29 03:32:34 +02:00
Peter Steinberger
6bdaada782 fix: normalize memory wiki confidence 2026-05-28 21:32:10 -04:00
Vincent Koc
417b6e72c4 fix(context-engine): expose fallback metadata after quarantine 2026-05-29 02:32:06 +01:00
Vincent Koc
14ce8733fe fix(context-engine): quarantine broken plugin engines 2026-05-29 02:32:06 +01:00
Vincent Koc
9813ff2f0a refactor: share channel setup promotion keys 2026-05-29 03:29:32 +02:00
Peter Steinberger
9b692f0a5b test(plugins): expect openclaw npm metadata lookup 2026-05-29 02:29:07 +01:00
Peter Steinberger
4ac6bb1964 fix: validate memory search min score 2026-05-28 21:28:02 -04:00
Dallin Romney
e0aa820257 ci: rename dependency guard workflow (#87842) 2026-05-28 18:26:49 -07:00
Peter Steinberger
fe76bae1ed fix: validate lancedb memory importance 2026-05-28 21:25:05 -04:00
Peter Steinberger
b1117d9862 refactor: extract gateway client package (#87797)
* refactor: extract gateway client package

* chore: drop generated gateway package artifacts

* refactor: move gateway protocol package

* refactor: remove old gateway protocol tree

* test: keep auth compat split in run mode

* test: expose gateway wrapper options for internals

* fix: watch moved gateway package sources

* test: normalize slash command import guard

* chore: teach knip gateway package entries

* ci: route gateway client package checks

* fix: reuse ipaddr for gateway client hosts

* fix: sync gateway protocol usage schema
2026-05-29 02:23:42 +01:00
Peter Steinberger
fd8353012f fix: parse diffs numeric options 2026-05-28 21:22:05 -04:00
Peter Steinberger
c0d525c8a0 fix: validate whatsapp login timeout 2026-05-28 21:18:29 -04:00
Vincent Koc
c66c404d58 fix(e2e): reject loose pty env limits 2026-05-29 03:17:12 +02:00
Peter Steinberger
10a3417bd3 fix: validate browser act numeric params 2026-05-28 21:16:12 -04:00
Dallin Romney
c8f2bbf76d ci: guard dependency graph PR changes (#87791) 2026-05-28 18:13:54 -07:00
Peter Steinberger
efc93bf282 fix: validate google meet numeric params 2026-05-28 21:11:53 -04:00
Josh Avant
92051f6746 fix: probe stale rate-limit cooldown primaries (#87833) 2026-05-28 18:11:14 -07:00
Shakker
73cf516def fix: preserve embedded base system prompts
Preserve OpenClaw-owned embedded system prompts after active tool selection in both normal embedded attempts and compaction. Adds an exact base prompt path on AgentSession that keeps active tool prompt metadata current for extension hooks.

Fixes #87807.

Verification:
- mise exec node@24.16.0 -- node scripts/run-vitest.mjs src/agents/sessions/sdk.test.ts src/agents/embedded-agent-runner/system-prompt.test.ts src/agents/embedded-agent-runner/run/attempt.spawn-workspace.context-engine.test.ts src/agents/embedded-agent-runner/compact.hooks.test.ts --reporter=dot
- mise exec node@24.16.0 -- pnpm tsgo:core
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main

Thanks @shakkernerd.
2026-05-29 02:09:15 +01:00
Dallin Romney
93c30de17b ci: restore timing summary artifact (#87832)
* ci: restore timing summary artifact

* ci: report pnpm warmup fanout timing

* ci: run timing summary from trusted base
2026-05-28 18:08:12 -07:00
Merlin
00067563a6 fix(doctor): handle gateway SecretRefs in auth checks
Handle exec-backed Gateway SecretRefs in doctor, lint, and health probing without executing providers by default.

- Add `openclaw doctor --allow-exec` for explicit SecretRef execution during lint/doctor checks.
- Skip only the active exec-backed gateway probe path and avoid local service diagnostics for remote-only skipped health.
- Keep env-winning and dormant fallback credentials probeable, stabilize related tests, and remove a stale live-shard fixture left by the moving base.

Verification:
- `node scripts/run-vitest.mjs src/commands/doctor-gateway-auth-token.test.ts src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts src/gateway/credentials.test.ts src/gateway/probe-auth.test.ts src/commands/doctor-gateway-daemon-flow.test.ts test/scripts/test-live-shard.test.ts --reporter=verbose`
- `mise x node@24.13.0 -- pnpm prompt:snapshots:check`
- `pnpm tsgo:prod`
- `pnpm build`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- Crabbox AWS live config proof: `run_f44a4d9dae4e`
- GitHub CI: green on final head `88d24abdbf9529a59d75d1d5e04eac74bbbbc267` after rerunning a stale in-progress Security High workflow.

Co-authored-by: Merlin <258679497+funmerlin@users.noreply.github.com>
2026-05-29 02:07:50 +01:00
Peter Steinberger
3aae25358e fix: validate lobster numeric options 2026-05-28 21:06:23 -04:00
Peter Steinberger
5d8cf28578 fix: validate file transfer numeric params 2026-05-28 21:03:39 -04:00
Alix-007
99bd275359 fix(ui): scope usage by agent filter
Fixes #87132.

Default Usage now requests all configured agents with `agentScope: "all"`, while selecting a specific agent sends `agentId` consistently to both session usage and cost usage calls. The gateway now supports explicit all-agent session usage, aggregates all-agent cost summaries across configured agents, and keeps scoped cache entries separate. Legacy gateway fallbacks remain for older `agentId` / `agentScope` support, with protocol docs/schema and Swift generated models updated.

Verification:
- `node scripts/run-vitest.mjs ui/src/ui/controllers/usage.node.test.ts ui/src/ui/app-render-usage-tab.test.ts ui/src/ui/views/usage.test.ts --reporter=dot`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway-methods.config.ts src/gateway/server-methods/usage.test.ts src/gateway/server-methods/usage.cost-usage-cache.test.ts src/gateway/server-methods/usage.sessions-usage.test.ts --reporter=dot`
- `pnpm check:test-types`
- `pnpm protocol:check`
- targeted `node scripts/run-oxlint.mjs ...`
- `git diff --check`
- autoreview clean after Swift compatibility fix
- PR CI green at head `d67156a3c552c4f9c8b6edf8516b6242bf5cdd26`

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-05-29 02:03:33 +01:00
Vincent Koc
d4021d1d54 fix(e2e): reject loose bundled sweep limits 2026-05-29 03:02:21 +02:00
Peter Steinberger
f927e532da perf: cache installed package paths 2026-05-29 02:00:21 +01:00
Peter Steinberger
0ae1ac17ea fix: validate web guarded fetch timeouts 2026-05-28 20:59:02 -04:00
David
37c5003ed9 fix(auth): harden Codex auth probes (#87559)
* fix(auth): harden Codex auth probes

* fix: preserve Codex probe auth overlay (#87559)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-29 01:58:48 +01:00
Vincent Koc
ca41fa293f refactor: share live transport scenario helpers 2026-05-29 02:58:05 +02:00
Peter Steinberger
7bf100b028 fix: validate embedded chat history limits 2026-05-28 20:56:45 -04:00
Peter Steinberger
f7b0b5429e fix: validate llm task numeric options 2026-05-28 20:54:18 -04:00
Vincent Koc
8bd4736f03 fix(ui): replay pending cron filter reloads 2026-05-29 02:50:58 +02:00
Peter Steinberger
27d1c08c51 fix: normalize web provider numeric params 2026-05-28 20:49:19 -04:00
Sebastien Tardif
b998a921c7 fix(codex): preserve reasoning stream snapshots
Keep Codex reasoning updates as accumulated snapshots and mark the stream payload so channel consumers can distinguish snapshots from deltas.

This prevents Discord and Teams progress previews from duplicating accumulated reasoning text while preserving delta-style reasoning for legacy producers.

Refs #86708
Thanks @SebTardif.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-05-29 01:48:51 +01:00
Peter Steinberger
61cf005437 fix: normalize canvas numeric params 2026-05-28 20:45:27 -04:00
Peter Steinberger
61c538e2fc fix: validate memory recall limits 2026-05-28 20:42:42 -04:00
Peter Steinberger
f09b69a78f test: drop removed gateway live shard fixture 2026-05-28 20:41:11 -04:00
Peter Steinberger
091e15139b refactor: centralize numeric tool schemas 2026-05-28 20:39:51 -04:00
Vincent Koc
c903b271cf fix(e2e): reject loose mock config limits 2026-05-29 02:38:29 +02:00
Dallin Romney
5cccfe1c17 docs: correct ci timing summary guidance (#87813) 2026-05-28 17:36:54 -07:00
Peter Steinberger
7e04680e23 fix: parse browser top-level timeouts 2026-05-28 20:36:34 -04:00
Peter Steinberger
3a20a0cd4f fix: remove unused voice agent helper 2026-05-28 20:35:22 -04:00
Peter Steinberger
1901b832eb perf: cache installed package metadata 2026-05-29 01:32:11 +01:00
Peter Steinberger
5869131eea test: refresh numeric tool prompt snapshots 2026-05-28 20:29:06 -04:00
Peter Steinberger
101cb70844 test: type message gateway options 2026-05-28 20:25:18 -04:00
Peter Steinberger
913241ebf9 fix: parse browser snapshot numeric params 2026-05-28 20:25:18 -04:00
Peter Steinberger
e12a6d6a67 refactor(agents): own system prompt assembly 2026-05-29 01:22:09 +01:00
Peter Steinberger
c3ff31e770 fix: validate slack read limits 2026-05-28 20:20:51 -04:00
Peter Steinberger
7bcef07297 test: update numeric tool schema snapshots 2026-05-28 20:18:49 -04:00
Peter Steinberger
ecbb5cd9b6 fix: preserve cron gateway timeout parsing 2026-05-28 20:18:49 -04:00
Vincent Koc
ffd517b513 test: dedupe schtasks startup fallback helpers 2026-05-29 02:17:18 +02:00
Vincent Koc
5685238656 fix(e2e): reject loose telegram rtt limits 2026-05-29 02:16:54 +02:00
Peter Steinberger
f8d63f4b24 fix: centralize gateway timeout schema 2026-05-28 20:15:36 -04:00
Peter Steinberger
592277cd77 ci(release): bound cross-os baseline packing 2026-05-29 01:13:10 +01:00
Peter Steinberger
fc8b57e0cf fix: validate gateway rpc timeouts 2026-05-28 20:10:06 -04:00
Peter Steinberger
92a405b536 chore: remove unused plugin source loader 2026-05-28 20:08:42 -04:00
Peter Steinberger
c4e4d122e9 fix: validate gateway restart delays 2026-05-28 20:06:50 -04:00
Peter Steinberger
9119e8d99c fix: validate image caps 2026-05-28 20:02:51 -04:00
Vincent Koc
f9f4c4959b fix(e2e): reject loose helper env limits 2026-05-29 02:02:23 +02:00
Vincent Koc
d264119c75 test: dedupe gateway context fixture 2026-05-29 02:01:14 +02:00
Peter Steinberger
a92eb02ec3 fix: validate pdf byte cap 2026-05-28 19:59:42 -04:00
Peter Steinberger
f77a2687b6 test: refresh codex dynamic tool snapshots 2026-05-28 19:59:13 -04:00
Peter Steinberger
661a9ba559 fix: validate node command timeouts 2026-05-28 19:56:23 -04:00
Peter Steinberger
068e02684b fix: validate node media numeric params 2026-05-28 19:53:58 -04:00
Peter Steinberger
3cb4f33d3c fix: validate node photo limit 2026-05-28 19:50:10 -04:00
Peter Steinberger
0296f0a779 perf: load provider discovery entries natively 2026-05-29 00:49:20 +01:00
Peter Steinberger
49f36ab58d fix: validate node media duration 2026-05-28 19:46:06 -04:00
Peter Steinberger
28597d2790 fix: validate cron context count 2026-05-28 19:43:27 -04:00
Vincent Koc
72de534a93 test: dedupe realtime WebRTC helpers 2026-05-29 01:43:07 +02:00
Vincent Koc
7c16af4933 fix(e2e): reject loose fixture config limits 2026-05-29 01:42:49 +02:00
Peter Steinberger
0e40408375 perf: speed up launcher version output 2026-05-29 00:41:40 +01:00
Peter Steinberger
9a4aa438bb fix: validate session spawn timeout 2026-05-28 19:41:11 -04:00
Peter Steinberger
f2843d3d79 fix: validate session send timeout 2026-05-28 19:38:35 -04:00
Peter Steinberger
d7fca5794d fix: validate image numeric options 2026-05-28 19:35:50 -04:00
Peter Steinberger
4c49ca75d9 fix: validate session tool numeric params 2026-05-28 19:32:00 -04:00
Gio Della-Libera
82cb02a4fd fix(cli): preserve Discord voice outbound helper (#85529)
Merged via squash.

Prepared head SHA: e5f5e3d23f
Co-authored-by: giodl73-repo <giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-05-28 16:29:08 -07:00
Peter Steinberger
30de7874cf fix: validate memory wiki numeric params 2026-05-28 19:27:51 -04:00
Dallin Romney
2ba725ef48 fix: stabilize code mode timeout and prompt snapshots (#87809)
* fix: normalize code mode timeout interrupts

* test: refresh firecrawl prompt snapshots
2026-05-28 16:26:12 -07:00
Peter Steinberger
36de671cad fix: validate perplexity token budgets 2026-05-28 19:25:20 -04:00
Dallin Romney
aeeccdf27f fix(ci): bound ClawHub docs checkout (#87811) 2026-05-28 16:25:09 -07:00
Peter Steinberger
46546e6817 test(slack): serialize shared-global media tests 2026-05-29 00:23:48 +01:00
Peter Steinberger
6a65cc5e9c fix(e2e): fail fast when gateway exits before readiness 2026-05-29 00:23:48 +01:00
Peter Steinberger
b4f03c2e64 fix: validate subagents recent minutes 2026-05-28 19:23:08 -04:00
Vincent Koc
38fd443677 fix(e2e): reject loose gateway network timeouts 2026-05-29 01:21:50 +02:00
Peter Steinberger
3c907250b9 fix: validate firecrawl numeric options 2026-05-28 19:20:18 -04:00
Peter Steinberger
1211123fe6 fix(agents): pass agent id to bootstrap preload 2026-05-29 00:18:18 +01:00
Peter Steinberger
e9cca2d1ef fix: validate memory search result counts 2026-05-28 19:17:42 -04:00
Jason (Json)
1610b4983f fix: scope jiti transform cache by OpenClaw install
Scope jiti filesystem transform caches for OpenClaw plugin loaders by package version and package.json install metadata so stale transforms cannot survive upgrades or package reinstalls.

Covers the central plugin module loader and the plugin SDK root alias CJS loader, while preserving jiti filesystem-cache env opt-outs and the TMPDIR cwd guard.

Verification: CI run 26601117143 passed; Real behavior proof run 26601445285 passed; CodeQL selected checks passed in run 26601117126; CodeQL Critical Quality plugin-boundary and plugin-sdk-package-contract passed in run 26601117074; OpenGrep PR diff passed in run 26601117137.

Refs: https://github.com/openclaw/openclaw/pull/87745
Thanks @fuller-stack-dev.
2026-05-29 00:17:04 +01:00
Peter Steinberger
13c1aa7fb9 test(ui): cover cron table filter e2e 2026-05-29 00:15:17 +01:00
Peter Steinberger
8a8767dd1e fix: validate imessage action integers 2026-05-28 19:14:45 -04:00
Vincent Koc
9dd8ffd767 refactor: dedupe session storage indexing 2026-05-29 01:14:34 +02:00
Peter Steinberger
46a67eea4c fix: throttle voice wake meter preview 2026-05-29 00:14:05 +01:00
Peter Steinberger
361753908e fix: validate memory get ranges 2026-05-28 19:11:37 -04:00
Peter Steinberger
56a5d7e865 fix(codex): defer report-mode plugin approvals
Route Codex app-server report-mode PreToolUse plugin approval requirements through the matching app-server approval request instead of failing closed. Shares duplicate in-flight approvals, preserves block/rewrite fail-closed behavior, and keeps generic plugin allow-always scoped to one Codex request. Supersedes #86978; thanks @clawSean for the original docs clarification.
2026-05-29 00:09:23 +01:00
Peter Steinberger
44dc29f397 fix: validate web fetch max chars 2026-05-28 19:06:39 -04:00
AMARA
3029326a56 fix(memory): compact short-term promotion entries
Compact promoted short-term memory snippets before writing them into MEMORY.md, while keeping the full rehydrated snippet in recall state for ranking/provenance. Adds the deep-dreaming config surface and docs, with the default promoted snippet cap set to 160 estimated tokens.

Verification:
- git diff --check
- fnm exec --using v24.13.0 node scripts/run-vitest.mjs run extensions/memory-core/src/short-term-promotion.test.ts extensions/memory-core/src/dreaming.test.ts src/memory-host-sdk/dreaming.test.ts
- GitHub CI run 26605272497
- CodeQL security run 26605272404

Co-authored-by: AMARA <amara@eyeinthesky.pl>
2026-05-29 00:05:54 +01:00
Peter Steinberger
5990524c5f fix: validate google chat reaction limits 2026-05-28 19:04:31 -04:00
Peter Steinberger
b240ce2085 fix: validate discord action integers 2026-05-28 19:02:24 -04:00
Vincent Koc
e32a59bc79 fix(e2e): reject loose lifecycle metric limits 2026-05-29 01:01:18 +02:00
Dallin Romney
ac8c56cc70 test: refresh codex prompt snapshots (#87803) 2026-05-28 15:59:05 -07:00
Peter Steinberger
201fe25dad ci(release): let Telegram QA wait on credential leases 2026-05-28 23:58:52 +01:00
Peter Steinberger
74d5aeae1a fix: validate matrix action integers 2026-05-28 18:53:51 -04:00
Peter Steinberger
7932a4aa74 fix: validate slack action limits 2026-05-28 18:49:51 -04:00
Vincent Koc
6d90e00fa3 refactor: dedupe channel approval forwarding 2026-05-29 00:48:40 +02:00
Peter Steinberger
b0e9569ebd fix: validate telegram action integers 2026-05-28 18:46:26 -04:00
Vincent Koc
444dd19a28 fix(e2e): reject loose codex media limits 2026-05-29 00:46:22 +02:00
Peter Steinberger
59d4327698 fix: validate web search count integers 2026-05-28 18:38:39 -04:00
Peter Steinberger
9a7014ac38 fix: validate tavily integer options 2026-05-28 18:34:43 -04:00
Vincent Koc
7b8ec95108 fix(ci): stabilize agentic drift checks (#87786)
* fix(ci): stabilize agentic drift checks

* fix(ci): refresh opengrep scanner pin

* fix(ci): avoid full-depth opengrep checkout
2026-05-28 23:33:47 +01:00
Vincent Koc
8176bc8a76 fix(e2e): reject loose live plugin timeouts 2026-05-29 00:33:32 +02:00
Peter Steinberger
66d71238a8 fix: validate tool timeout integers 2026-05-28 18:32:17 -04:00
Peter Steinberger
b21b105752 fix: validate video duration option 2026-05-28 18:29:55 -04:00
Peter Steinberger
b877fc58a5 refactor: centralize numeric coercion helpers 2026-05-28 18:27:36 -04:00
Kevin Lin
359c31b7e7 Add WhatsApp approval QA scenarios (#87782)
* test(qa): add WhatsApp approval scenarios

* fix(qa): keep WhatsApp approval scenarios explicit
2026-05-28 15:27:20 -07:00
Peter Steinberger
86d7beab99 fix: keep plugin registry memo fresh for installs 2026-05-28 23:25:12 +01:00
Peter Steinberger
365f551f9d fix: validate music duration option 2026-05-28 18:24:27 -04:00
Vincent Koc
278d04aa4b fix(e2e): reject loose chat tools limits 2026-05-29 00:23:11 +02:00
Peter Steinberger
9184b096bf fix: validate image generation numeric options 2026-05-28 18:21:59 -04:00
Peter Steinberger
4491232874 fix: resolve compatible npm plugin versions
* fix: resolve compatible npm plugin versions

* fix: satisfy plugin install lint

* fix: refresh plugin install tests on latest main
2026-05-28 23:20:32 +01:00
Peter Steinberger
11ef608685 fix: validate firecrawl numeric options 2026-05-28 18:18:33 -04:00
Alix-007
ff21b4e731 fix(cron): complete jobs filters
Server-side cron job list filtering now applies schedule-kind and last-run-status filters before pagination, and the UI only sends table filters for the cron table view.

Fixes #9455.

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-05-28 23:18:31 +01:00
Peter Steinberger
2df9b2e8ea fix: validate perplexity token budgets 2026-05-28 18:14:36 -04:00
Vincent Koc
7ebd600297 test: dedupe tui pty helpers 2026-05-29 00:14:04 +02:00
Peter Steinberger
bd77ebc761 ci(release): fix release smoke timeouts 2026-05-28 23:13:33 +01:00
Vincent Koc
7be08d0376 fix(cli): keep agents delete local fallback 2026-05-29 00:12:29 +02:00
Peter Steinberger
f5c7d77fb0 fix: validate openrouter stt temperature 2026-05-28 18:12:11 -04:00
Vincent Koc
3ca1135515 fix(e2e): reject loose runtime smoke limits 2026-05-29 00:11:17 +02:00
Peter Steinberger
80f7e36ddc fix: validate lmstudio discovered context lengths 2026-05-28 18:10:55 -04:00
Peter Steinberger
8e806e9125 fix: validate lmstudio preload context length 2026-05-28 18:09:13 -04:00
Peter Steinberger
f77e09f78e fix: validate llm task numeric options 2026-05-28 18:07:37 -04:00
Peter Steinberger
4287cd2e6e fix: validate lmstudio configured token metadata 2026-05-28 18:05:31 -04:00
Peter Steinberger
ac05545dba fix: validate copilot model token limits 2026-05-28 18:03:50 -04:00
Peter Steinberger
aa09f44b47 fix: validate kilocode model token metadata 2026-05-28 18:02:34 -04:00
Peter Steinberger
ef7ad6f744 fix: validate chutes model token metadata 2026-05-28 18:01:07 -04:00
Peter Steinberger
39db00f896 fix: validate vercel gateway model token metadata 2026-05-28 17:59:42 -04:00
Peter Steinberger
423531df50 fix: validate deepinfra model metadata numbers 2026-05-28 17:58:06 -04:00
Peter Steinberger
cb790f77da docs: polish release performance report 2026-05-28 22:57:10 +01:00
Peter Steinberger
938b2a84dd fix: validate byteplus video duration metadata 2026-05-28 17:54:45 -04:00
Aamir Jawaid
04c2982535 fix(msteams): rebase TeamsSDK patterns to simplify Teams Integration (#76262)
* fix(msteams): rebase SDK migration onto current main

Reapply the msteams SDK migration (originally on feat/msteams-sdk-migration)
on top of upstream/main, resolving conflicts with parallel msteams work that
landed upstream during our session.

What got applied vs decisions made:

CLEANLY APPLIED (3-way patch):
- monitor.ts, monitor-handler.ts, polls.ts, reply-stream-controller.ts/.test.ts,
  reply-dispatcher.ts, attachments/download.ts, monitor.lifecycle.test.ts,
  monitor-handler/message-handler.ts, monitor-handler.types.ts, etc.
- streaming-message.ts + .test.ts deletions

WHOLESALE TAKE FROM ORIGINAL BRANCH (partial 3-way left broken cross-refs):
- sdk.ts, sdk.test.ts, messenger.ts, feedback-reflection.ts,
  send-context.ts, send.test.ts

KEPT UPSTREAM (deferred for separate cleanup):
- extensions/msteams/package.json (still has jsonwebtoken/jwks-rsa per
  Peter's b3bc60ae25 incremental approach)
- src/plugins/contracts/package-manifest.contract.test.ts (consistent with
  package.json)
- pnpm-lock.yaml (avoids lockfile churn; pnpm install --frozen-lockfile clean)

ADAPTED:
- Dockerfile matrix-sdk-crypto check now wraps upstream's new retry-loop in
  the if-matrix-bundled gate

KNOWN TEST FAILURES (need eyes — see PR comment):
- attachments.test.ts: 1 fail (pre-existing — warn meta arg shape changed in
  our migration but test wasn't updated)
- reply-dispatcher.test.ts: 6 fails (pre-existing — tests mock old
  TeamsHttpStream, not updated for our ctx.stream rewrite)
- send.test.ts: 4 fails (NEW from merge — upstream's send.ts changed media
  loading; our mocks need updating or take upstream's send.test.ts wholesale)

UPSTREAM COMMITS POTENTIALLY MISSED (in wholesale-take files):
- 08c4af0ddf fix(msteams): accept conversation id allowlists
- e1840b8581 fix(msteams): bind global audience tokens to app id
- Channels turn-kernel refactor (ffe67e9cdc / 1ead1b2d18 / 9a9cd0c0ab) —
  may be partially preserved in cleanly-patched files

Static checks pass: pnpm check:changed is green (typecheck, lint, contract
tests, import cycles, etc.). Manual testing required before merge.

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

* fix(msteams): preserve thread routing for channel and group-chat replies

- monitor.ts: adaptSdkContext now uses ctx.reply() for channel and groupChat
  conversations (so the SDK threads outbound activities to the inbound's
  replyToId/serviceUrl) and ctx.send() only for personal DMs (where
  reply()'s blockquote-prepend is ugly).
- messenger.ts: sendProactively passes resolvedThreadId on the non-thread
  fallback path so channel @mentions that fall through outbound.ts -> send.ts
  still land in the original thread instead of top-level.

Live-validated: channel @mention -> bot replies in thread, threaded reply
-> bot replies in same thread, no top-level leakage.

* fix(msteams): tag outbound SDK calls with OpenClaw User-Agent

- user-agent.ts: add buildOpenClawUserAgentFragment() that returns just
  'OpenClaw/<version>'. The SDK's Client.clone merges this with its own
  'teams.ts[apps]/<sdk-version>' identifier — passing the full buildUserAgent()
  here would double-print the SDK token.
- sdk.ts: pass the fragment via AppOptions.client.headers['User-Agent'] so
  the Teams backend can identify OpenClaw traffic for usage telemetry.

Final UA looks like 'OpenClaw/<openclaw-version> teams.ts[apps]/<sdk-version>'.

* fix(msteams): handle StreamCancelledError when user presses Stop mid-stream

The new SDK throws StreamCancelledError synchronously from stream.emit/update
when the user pressed Stop in Teams: Teams replies 403 to the next chunk
update, the SDK flips _canceled, and any subsequent emit() throws. The old
custom TeamsHttpStream either swallowed cancel or didn't expose this exception
type, so the migration inherited an SDK behavior the original code didn't have
to handle.

Symptom on 2026-05-05: pressing Stop during a streaming reply caused an
unhandled promise rejection that crashed the Node 24 process. Docker restarted
the gateway about two minutes after each Stop click. Two related bugs surfaced
once the crash was caught: the would-be block fallback re-delivered the full
text as a second message (duplicate after Stop), and the typing-keepalive kept
pulsing in Teams for the rest of the agent run because nothing told it to
stop.

reply-stream-controller.ts:
- Wrap stream.update / stream.emit / stream.close in try/catch that swallows
  StreamCancelledError (matched by .name to dodge tsgo's SDK re-export
  resolution quirk). Latch a wasCanceled flag so subsequent calls
  short-circuit even if stream.canceled is stale.
- preparePayload() returns undefined when the stream was canceled — the
  streamed prefix is already visible to the user, so dropping the payload
  prevents a duplicate block message from overriding the cancel intent.

reply-dispatcher.ts:
- Typing-keepalive gate now also checks streamController.wasCanceled() so
  typing pulses stop firing once Stop is observed. Otherwise the bot keeps
  pulsing for the rest of the (uncancellable) agent run.

reply-stream-controller.test.ts:
- 6 new regression tests cover: cancel-during-emit (the crash scenario),
  cancel-during-update, cancel-during-finalize, non-cancel error propagation,
  post-cancel inactivity, and dropped-payload-on-cancel.

Live-validated: long streaming reply + Stop mid-stream -> stream freezes,
no duplicate message, no zombie typing, container stays healthy.

* fix(msteams): allow Bearer-token retry on Skype CDN attachment downloads

Teams puts inline DM images and clipboard-pasted images on
*.asm.skype.com URLs (e.g. us-api.asm.skype.com/v1/objects/<id>/views/imgo).
The download path in attachments/download.ts already does a plain GET first
and falls back to a Bearer-token retry on 401/403 — but the retry was gated
on the URL being in DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST. asm.skype.com hosts
were in DEFAULT_MEDIA_HOST_ALLOWLIST (download permitted) but not in the
auth-host list, so a 401 plain-GET response skipped the retry and surfaced
as a missing image to the agent.

Add asm.skype.com and ams.skype.com to the auth allowlist so openclaw
attempts the Bearer-token retry consistently, matching how it treats the
other CDN/Bot-Framework hosts already in the list.

Note: this does not unblock all clipboard-pasted DM images — for at least
some tenants asm.skype.com rejects the Bot Framework token (returns 401
even with auth). Routing those URLs through <serviceUrl>/v3/attachments/...
the way #62219 already handles HTML-wrapped attachments is a separate
follow-up. The +button 'Upload from this device' path works today because
Teams generates an attachment with an HTML wrapper that triggers the
existing BF v3 attachments fallback in monitor-handler/inbound-media.ts.

* fix(msteams): align docker-compose msteams port default with plugin default

The plugin defaults webhook.port to 3978 (the Bot Framework standard used in
Microsoft samples) and listens on whatever the operator sets there. The
docker-compose.yml port mapping was exposing ${OPENCLAW_MSTEAMS_PORT:-3000}:3000
which only works for operators who explicitly set webhook.port to 3000.
Default-config users would have the plugin listening on 3978 inside the
container while compose forwarded 3000, causing connection refused.

Realign to ${OPENCLAW_MSTEAMS_PORT:-3978}:3978 so a default-config docker
compose up Just Works with Teams. Operators wanting a custom port override
both webhook.port in openclaw.json and OPENCLAW_MSTEAMS_PORT env var.

* fix(msteams): post-rebase reconciliation with main

Three follow-ups after rebasing the SDK migration onto current main:

- reply-dispatcher.ts: rename createChannelReplyPipeline to its post-rebase
  identifier createChannelMessageReplyPipeline (the plugin-sdk barrel renamed
  it during the 1454-commit rebase window).
- reply-dispatcher.ts: tighten the typing-keepalive onStartError signature to
  (err: unknown) to satisfy upstream's stricter type checks.
- messenger.ts: drop the unconditional thread suffix on the bottom proactive
  fallback. The previous behavior threaded all top-level proactive sends when
  the stored ref had a threadId, which contradicts replyStyle='top-level'
  semantics (and breaks the new upstream test). Threading on the proactive
  path is preserved where it matters — the onRevoked branch within
  replyStyle==='thread' still passes resolvedThreadId, which is the original
  #55198 fix path.
- attachments.test.ts: update the warn-call assertion to match the migration's
  inline message format (host=... error=...) — the structured meta object was
  being dropped by the logger formatter pre-migration.

* feat(msteams): port streaming preview/progress features to ctx.stream

While the SDK migration was open, upstream landed preview/progress/draft
streaming features built on the OLD custom TeamsHttpStream class (which the
migration deletes). This commit ports the user-visible parts of those
features onto the new ctx.stream substrate so the migration doesn't lose
ground:

- pickInformativeStatusText: reads custom labels from
  msteams.streaming.progressDraft config via resolveChannelProgressDraftLabel.
  Falls back to the plugin-sdk default rotation. Pre-rebase used a hardcoded
  4-string array.
- streamMode resolution: "partial" (default, per-token streaming),
  "progress" (no tokens; preview card carries informative label that updates
  as tools run), or "block" (no native streaming). Mode is read from
  cfg.channels.msteams.streaming.preview.
- progress-draft gate: createChannelProgressDraftGate gates informative
  updates so the rotating label only starts firing once meaningful work has
  begun (avoids flicker before the first tool call).
- noteProgressWork() / pushProgressLine(): public methods on the controller
  for callers (typing keepalive ticks, tool-event callbacks) to signal work.
  pushProgressLine appends tool names as bullets above the rotating label
  when streaming.previewToolProgress is enabled. Wiring these into actual
  tool events is a separate follow-up.
- preparePayload progress-mode path: when stream is active but no tokens
  streamed (progress mode) and a final text payload arrives, emit the text
  into the stream so the preview card transitions in place to the final
  reply on close().

reply-dispatcher: pass log + msteamsConfig + a stable progressSeed
(${accountId}:${conversation.id}) to createTeamsReplyStreamController so the
informative-label rotation is consistent across reconnects.

What's NOT ported and why:
- Live-edit-via-replaceInformativeWithFinal: the SDK's HttpStream natively
  accumulates emitted text + entities + channelData and flushes ONE final
  activity at close() using the same activity id as the preview. So the
  separate "replace informative with final" call from upstream is
  unnecessary — we get live-finalization for free via the SDK's design.
- pushProgressLine triggers from tool events: needs reply-pipeline-side
  callbacks the new SDK migration didn't surface yet. Follow-up.

Tests: existing 22 reply-stream-controller tests still pass (the new
behaviors are additive).

* feat(msteams): wire pipeline tool events to streaming progress + fix test debt

Two follow-ups from yesterday's stopping point:

1. Wire pipeline events into the stream controller's progress-draft surface.
   reply-dispatcher's replyOptions now exposes onReasoningStream, onToolStart,
   onItemEvent, onPlanUpdate, onApprovalEvent, onCommandOutput callbacks that
   format each event via the channel-streaming helpers and route through
   streamController.pushProgressLine(). Mirrors the discord adapter's wiring.
   Also:
   - resolveChannelStreamingPreviewToolProgress + ...SuppressDefaultTool... so
     the dispatcher exposes suppressDefaultToolProgressMessages on its
     replyOptions when progress mode is on.
   - Switch disableBlockStreaming resolution to the channel-streaming helpers
     (resolveChannelPreviewStreamMode + resolveChannelStreamingBlockEnabled)
     so streaming.mode='block' and streaming.block.enabled=true are honored
     alongside the legacy blockStreaming boolean.

2. Fix the test debt that the rebase exposed:
   - reply-dispatcher.test.ts: drop the streamInstances + TeamsHttpStream
     mock pattern (file deleted by migration); replace with a streamMock
     provided via context.stream that mirrors the SDK's IStreamer shape
     (update/emit/close/canceled). Update assertions on sendInformativeUpdate
     -> stream.update, stream.update -> stream.emit. Drop the
     resumes-typing-between-segments test (no equivalent in the new
     ctx.stream model — the SDK's HttpStream doesn't have a 'between
     segments' notion; close ends the stream).
   - send.test.ts: fix two stale mock targets — loadOutboundMediaFromUrl
     comes from openclaw/plugin-sdk/outbound-media (not /msteams), and
     resolveMarkdownTableMode comes from openclaw/plugin-sdk/markdown-table-runtime
     (not /config-runtime). The previous mock paths were no-ops post-migration.

All 854 msteams tests now pass (was 17 failing in 4 files yesterday).

* fix(msteams): SDK streaming delta + use app.reply for proactive thread sends

Two narrow regressions exposed by the @microsoft/teams.apps migration:

- The SDK's HttpStream.emit appends each chunk to its internal buffer
  (`this.text += activity.text`), but the channel reply pipeline emits
  cumulative text on each chunk. Forwarding cumulative text into an
  appending sink produced "chunk1 + chunk1chunk2 + chunk1chunk2chunk3..."
  duplication for streamed (DM) replies. Track the emitted prefix length
  in the stream controller and only forward the new tail.
- Replace the manual `${convId};messageid=${msgId}` URL construction in
  the proactive thread fallback with `app.reply()`, which builds the
  threaded conversation id via the SDK's own toThreadedConversationId
  helper. Mechanically equivalent today; removes coupling to Teams' URL
  format and tracks any future SDK changes.

Also adds the `reply` method to the structural MSTeamsApp type so the
refactor typechecks without casts.

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

* chore(msteams): bump @microsoft/teams.api and teams.apps to 2.0.10

2.0.10 adds support for the AAD v1 token issuer that the Bot Framework
JWT validator needs. The minor version bump pulls teams.cards / common /
graph along to 2.0.10 too.

Add `@microsoft/teams.*` to `minimumReleaseAgeExclude` in
pnpm-workspace.yaml because 2.0.10 was published <48h ago and the default
`minimumReleaseAge: 2880` (~2 days) would otherwise reject it.

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

* revert(msteams): remove asm.skype.com auth-host allowlist additions

These hosts were added in dfc169d31d for inline DM image auth-retry, but
the commit's own footnote acknowledges it doesn't actually unblock
clipboard-pasted images (asm.skype.com rejects Bot Framework tokens in
at least some tenants). The change is unrelated to the SDK migration and
the user-visible bug it claimed to fix isn't fixed; lifting it out keeps
this PR focused on the migration. Will land as a separate PR if the
auth-allowlist consistency improvement is wanted on its own.

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

* refactor(msteams): typed ExpressAdapter helper, drop unknown-cast pyramid

The monitor's SDK bootstrap had an awkward chain:

  httpServerAdapter: new (
    (await import("@microsoft/teams.apps")) as unknown as {
      ExpressAdapter: new (app: unknown) => unknown;
    }
  ).ExpressAdapter(expressApp) as never,

Three casts (`unknown`, structural shape literal, `never`) were a
defensive workaround from when the SDK's hashed d.ts files tripped up
tsgo. With the SDK's exports now resolving cleanly, the same import can
be done with full types.

- Extend the lazy `loadSdkModules()` cache to include `ExpressAdapter`
  alongside `App` so the dynamic import is shared.
- Add `createMSTeamsExpressAdapter(serverOrApp)` helper in `sdk.ts` that
  encapsulates the lazy import and returns a properly-typed adapter
  instance.
- Replace `httpServerAdapter`'s structural shape on `CreateMSTeamsAppOptions`
  with the SDK's own `IHttpServerAdapter` interface (re-exported from
  `@microsoft/teams.apps`).

The call site in `monitor.ts` becomes a single typed call with no `any`,
no `unknown`, no `as never`. The lazy-load behavior is preserved: nothing
imports `@microsoft/teams.apps` at module load time.

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

* fix(msteams): unbreak tsgo:extensions on the ExpressAdapter helper

CI's check-prod-types failed because the previous commit's typed helper
used `typeof import("@microsoft/teams.apps").ExpressAdapter`, which
tsc/tsgo's NodeNext resolution can't follow through the SDK's chained
`export *` barrel:

    @microsoft/teams.apps/dist/index.d.ts:
        export * from "./http";          // folder with index.d.ts
        export * from "./app";           // single .d.ts file

The folder re-export drops `ExpressAdapter` and `IHttpServerAdapter` from
the namespace shape under `tsconfig.extensions.json` (passes under the
per-extension `tsconfig.json` because of inherited `paths`). Same root
cause as why we already model `MSTeamsApp` structurally (line 47 comment).

Switch the ExpressAdapter side to the same structural-shape pattern:
- Define `MSTeamsHttpServerAdapter` and `MSTeamsExpressAdapterCtor` locally.
- Cast `m.ExpressAdapter` once inside `loadSdkModules` (the runtime export
  is fine; only the type surface is hidden).
- `httpServerAdapter` on `CreateMSTeamsAppOptions` and the return type of
  `createMSTeamsExpressAdapter` use the local structural type.

Net result: the call site in `monitor.ts` stays the cast-free single line
the previous commit landed; the one remaining cast is confined to the
SDK-loading helper with an explanatory comment.

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

* chore(msteams): drop unused jsonwebtoken/jwks-rsa deps

The SDK migration removed all `import "jsonwebtoken"` / `import "jwks-rsa"`
from source code (the SDK does JWT validation internally now), but the
package.json entries and the matching `package-manifest.contract.test.ts`
expectation were left orphaned. Drop both:

- `extensions/msteams/package.json`: remove `jsonwebtoken` (^9), `jwks-rsa`
  (^4) from `dependencies` and `@types/jsonwebtoken` from `devDependencies`.
- `src/plugins/contracts/package-manifest.contract.test.ts`: remove the
  two entries from msteams's `pluginLocalRuntimeDeps` expectation.
- `monitor.lifecycle.test.ts`: extend the `./sdk.js` mock with the
  `createMSTeamsExpressAdapter` export added in the typed-helper cleanup,
  so the lifecycle suite still mounts after the deps drop.

Lockfile regenerates accordingly. All msteams tests (865) pass.

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

* chore(msteams): drop unused @microsoft/teams.api direct dep

CI's deadcode:dependencies (knip) flagged @microsoft/teams.api as
unused in extensions/msteams. The plugin source uses structural type
aliases (MSTeamsActivityParams, MSTeamsActivityLike, etc.) to dodge
tsgo resolution bugs with teams.api's hashed d.ts files, so it never
imports teams.api directly. The package is brought in transitively
via @microsoft/teams.apps; the only other reference is
probe.test.ts's vi.mock("@microsoft/teams.api"), which works on the
import-path string and doesn't require a direct dep declaration.

Lockfile regenerates accordingly. tsgo:extensions, knip, and all
865 msteams tests pass.

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

* fix(msteams): clear three CI gate failures (lint, contract, deprecated config API)

Three CI checks flagged on the latest run; all three are msteams-local
and unrelated to one another:

- **check-lint** / **check-additional-extension-bundled**:
  `oxlint` flagged a redundant `as string[]` assertion in
  `reply-dispatcher.ts:431`. The preceding `every((s: unknown) => typeof
  s === "string")` already narrows the array type, so the cast does
  nothing. Drop it.

- **checks-fast-contracts-plugins-c**: the
  `package-manifest.contract.test.ts` `pluginLocalRuntimeDeps` for
  msteams still expected `@microsoft/teams.api`, but the deadcode
  cleanup commit (8f4050f51a) dropped it from
  `extensions/msteams/package.json`. Remove it from the contract test
  too — `teams.api` is only present transitively via `teams.apps`,
  which is the reason knip flagged it.

- **check-additional-runtime-topology-architecture**: the deprecated
  internal config API guard caught `messenger.ts:223` calling
  `getMSTeamsRuntime().config.loadConfig()`. Switch to
  `config.current()` to match the pattern used by phone-control,
  synology-chat, and matrix.

Pre-existing failures on this run that are NOT msteams-related and not
caused by this PR: `check-test-types` (errors in
`src/agents/openai-transport-stream.test.ts` and
`pi-embedded-runner/openai-stream-wrappers.test.ts`) and `macos-swift`
(`hoistAwait` in `MacNodeRuntime.swift`). Leaving those for upstream.

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

* fix(msteams): cast config.current() return to OpenClawConfig

The previous commit switched `messenger.ts:223` from the deprecated
`config.loadConfig()` to `config.current()` to satisfy the architecture
guard, but `config.current()` returns a deeply-readonly type that's not
assignable to the `Partial<OpenClawConfig>` parameter
`resolveMarkdownTableMode` expects (a mutable type from the SDK
contract). Phone-control, synology-chat, and matrix all cast at this
seam — adopt the same pattern.

Verified locally: tsgo:core, tsgo:extensions, check:architecture, and
test:extensions:package-boundary:compile all pass.

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

* fix(msteams): address PR review — pre-auth body limit, allowlist log level, /api/messages forwarder, narrow release-age exclude

Four narrow fixes from the PR review (BradGroux + clawsweeper bot +
galiniliev's plan), each its own concern:

- **pre-auth-body-limit** (monitor.ts) — install
  `express.json({ limit: DEFAULT_WEBHOOK_MAX_BODY_BYTES })` before the
  bearer-presence gate and SDK route. Express memoizes the parsed body
  on the request, so the SDK's later `json()` becomes a no-op and our
  limit applies before any handler parses bodies. Closes the gap where
  a `Bearer garbage`-shaped attacker could force unbounded JSON parsing
  before token validation.

- **allowlist-error-logging** (monitor.ts) — restore main's `runtime.error`
  level for the `msteams resolve failed` catch (was downgraded to
  `runtime.log` mid-merge). Graph allowlist resolution failures are
  security-relevant; they need to surface to operators.

- **legacy-messages-route** (monitor.ts) — when `webhook.path` is set
  to a custom value, also accept POSTs on the legacy `/api/messages`
  path with a one-time deprecation warning, then re-enter the Express
  middleware chain on the configured path. Keeps existing Azure Bot
  registrations working through the transition. Cast-free
  (`expressApp(req, res, next)` works because `Application extends
  IRouter extends RequestHandler`).

- **release-age-scope** (pnpm-workspace.yaml) — narrow
  `@microsoft/teams.*` glob to the single direct dep
  `@microsoft/teams.apps`. Future scoped packages no longer get a
  freshness-guard pass.

Tests + checks: msteams suite (867), tsgo:core, tsgo:extensions,
tsgo:test, lint:extensions, check:architecture, knip --dependencies,
package-manifest contract, all green.

Still pending from the review (separate commits):
- auth-coverage-tests (Brad #1 + comment) — tests proving the SDK accepts
  `aud=<bot app id>` and rejects `aud=api.botframework.com`.
- invoke-response-handling (Brad #2, codex P2) — file-consent invoke ack
  must return through the SDK invoke handler, not `ctx.sendActivity`.
- stream-failure-fallback (codex P2, galin F5) — `streamFailed` latch so
  partial streams fall back to block delivery on non-cancel errors.
- serviceurl-routing (Brad #4, codex P2) — proposed rebuttal pending
  empirical confirmation that `smba.trafficmanager.net/teams` routes to
  non-default-region conversations.

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

* test(msteams): lock SDK auth contract — aud + v1/v2 issuer coverage

Adds extensions/msteams/src/auth-coverage.test.ts driving ServiceTokenValidator
and createEntraTokenValidator directly with jose-minted RS256 tokens against an
in-memory JWKS (via JwksClient.prototype patch). Locks in the three contract
cases @BradGroux flagged on #76262: aud=<bot app id> accepted, aud=api.botframework.com
rejected even when appid/azp match, and v1/v2 issuers accepted for allowed tenant
(disallowed tenant rejected).

Drops a stale ambient module declaration in src/types/microsoft-teams-sdk.d.ts
that was shadowing the SDK's real jwt-validator types with a long-renamed
createServiceTokenValidator surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): route file-consent invokes through typed app.on, drop broken invokeResponse send

Brad #2 / codex #4 on PR #76262 — `ctx.sendActivity({ type: "invokeResponse", ... })`
no longer reaches Teams as an HTTP InvokeResponse on the new SDK; it becomes
an outbound Bot Framework activity instead. Move file-consent accept/decline
to typed `app.on("file.consent.accept|decline", ...)` handlers. The SDK's
typed-route layer wraps a void return into `{ status: 200 }`
(`app.process.js:130`), so the manual ack disappears.

While in here, type `MSTeamsApp.on` properly. Borrowing the SDK's `App.on`
directly fails because that function carries a `this: App<TPlugin>`
constraint our structural alias can't satisfy, so we model an equivalent
generic over `IRoutes` with route-specific overloads (`card.action`,
`file.consent.*`, `activity`). The overloads work around a tsgo bug — the
`@microsoft/teams.api` `Activity` discriminated union collapses to `any`,
turning `ActivityRoutes` into a `[string]: RouteHandler<X, void>` index
signature that swallows every typed `Out` not already void-compatible
(card.action returns `AdaptiveCardActionResponse`; the others happen to
include `void`). Real tsc resolves cleanly. Linked upstream:
https://github.com/microsoft/typescript-go/issues/1057.

Other cleanups:
- Cast-free call sites for `adaptSdkContext` (now returns
  `MSTeamsTurnContext` instead of `unknown`).
- card.action error responses include `innerHttpError` per the SDK's
  `HttpError` shape requirement.
- Activity catch-all also skips `fileConsent/invoke` now that it's
  typed-routed (parallel to the existing `adaptiveCard/action` skip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): route SSO sign-in invokes through typed app.on, drop broken invokeResponse send

Brad #2 / codex #4 on PR #76262, SSO half. Continue the typed-route migration:
`signin/tokenExchange` and `signin/verifyState` now register via
`app.on("signin.token-exchange" | "signin.verify-state", ...)`. Per the
SDK's router, registering a user route with the same name as a system
route removes the system default — so the SDK's built-in handlers (which
would call `api.users.token.exchange` themselves and emit a `signin` event
nobody currently subscribes to) are silenced, and only ours runs. The SDK
wraps a void return into the HTTP 200 InvokeResponse, so the legacy
`ctx.sendActivity({ type: "invokeResponse", ... })` ack — broken on the new
SDK because it becomes an outbound BF activity instead of the HTTP
response — is gone.

The handler body is extracted from the activity-catch-all dispatch in
`monitor-handler.ts` to a new `signin-invoke.ts`, parallel to
`file-consent-invoke.ts`. `isSigninInvokeAuthorized` is now exported from
`monitor-handler.ts` so the new handler can reuse it. The activity
catch-all skips the SSO invoke names alongside the existing skips for
`adaptiveCard/action` and `fileConsent/invoke`.

`MSTeamsAppOn` overloads now cover the two SSO routes with their typed
ctx (`ISignInTokenExchangeInvokeActivity` / `ISignInVerifyStateInvokeActivity`).
Tests in `monitor-handler.sso.test.ts` were rewritten to call the
extracted handler directly — the `registered.run(ctx)` shape no longer
covers SSO, and the `expect(ctx.sendActivity).toHaveBeenCalledWith({ type:
"invokeResponse" })` assertions were dropped to match the new contract
(the SDK ack happens via the typed-route return value).

Note on overlap with #77784 (Stefan Stüben, Microsoft): that PR is doing
a much bigger SSO rework (sign-in card / sign-in-link / six-digit-code
fallbacks plus a `ctx.auth` plumbed to plugin tools). This change is
the small migration-correctness fix and is structured so #77784's SSO
body changes drop into the typed-route registrations cleanly on rebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): route message-submit (feedback) invokes through typed app.on

Last invoke off the activity catch-all dispatch. `message/submitAction`
(thumbs up/down on AI-generated messages) now registers via
`app.on("message.submit", ...)`. Same shape as file-consent and SSO:
handler body extracted to a new `feedback-invoke.ts`, the SDK wraps a
void return into the HTTP 200 InvokeResponse, the broken
`ctx.sendActivity({ type: "invokeResponse", ... })` line is gone, and
the activity catch-all skips this invoke name alongside the others.

`isFeedbackInvokeAuthorized` is exported from `monitor-handler.ts` so
`feedback-invoke.ts` can reuse it. Tests in
`monitor-handler.feedback-authz.test.ts` were rewritten to call the
extracted handler directly — the old `handler.run(ctx)` shape no longer
intercepts feedback, and `originalRun` was removed because the typed
route is the dispatch point now.

`MSTeamsAppOn` overload added with the typed
`IMessageSubmitActionInvokeActivity` ctx, slotted between the SSO
overloads and the `activity` catch-all so `activity` stays last.

This leaves only `message`, `conversationUpdate`, and `messageReaction`
flowing through `app.on("activity", ...)` → `handler.run`. Promoting
those is the path to deleting the catch-all entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): fall back to block delivery when partial-mode stream fails mid-flight

codex #5 / Galin F5 on PR #76262. `reply-stream-controller.ts` previously
re-threw any non-cancel error from `stream.emit` during partial streaming
and from `stream.emit`/`stream.close` during finalize. Combined with
`preparePayload` suppressing block delivery once `tokensEmitted` was
true, that meant a network blip or API error mid-stream produced a
truncated reply with no recovery — the user saw the prefix that made it
through and nothing else.

Add a `streamFailed` latch parallel to `canceledLocally` / `tokensEmitted`:

- `onPartialReply`: catch non-cancel errors, set `streamFailed = true`,
  log a warn, don't propagate (the pipeline must keep running so
  `preparePayload` can decide).
- `preparePayload`: when `tokensEmitted && streamFailed`, fall through to
  block delivery instead of suppressing. The user may see a duplicate
  (streamed prefix + full block reply); intentional — matches the
  pre-migration `TeamsHttpStream.hasContent` recovery and is better than
  truncated-only.
- `finalize`: same latch + warn on non-cancel close failure, swallow
  rather than throw. The streamed content already reached the user; the
  closing activity (AI-Generated marker, feedback channelData) is the
  only loss, not worth blowing up the dispatcher.
- `isStreamActive` returns false once the stream has failed.

New tests cover crash-mid-stream after tokens were emitted (assert block
delivery payload is returned), happy-path no-duplicate behavior (assert
`preparePayload` still suppresses when nothing failed), and finalize
close-failure (assert no throw). The pre-existing "re-throws non-cancel"
test was inverted to assert non-throwing latch behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): declare @microsoft/teams.api as a runtime dependency

Type-only `import("@microsoft/teams.api/dist/...").TypeName` references
in `sdk.ts` (added when typed `MSTeamsApp.on` overloads were introduced)
are picked up by the `extension-runtime-dependencies` contract test as
genuine runtime imports. Declaring `@microsoft/teams.api` as a direct
dep makes the contract pass; the package was already coming in
transitively via `@microsoft/teams.apps`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(msteams): keep SSO on SDK signin routes

* test(msteams): avoid redundant signin handler assertion

* docs(msteams): clarify Teams cloud support

* fix(msteams): use current SDK string helper

* fix(msteams): gate SDK invoke side effects

* test(msteams): avoid implicit any in lifecycle tests

* fix(msteams): preserve SDK user agent and matrix check

* fix(msteams): expose SDK common dependency

* fix(msteams): use SDK user agent merge

* fix(msteams): fall back when stream close no-ops

* chore(msteams): drop unrelated merge artifacts

* chore(msteams): restore unrelated main files

* chore(msteams): restore unrelated main files

* chore(msteams): restore unrelated main files

* test(msteams): type stream close mock result

* fix(msteams): configure Teams cloud service URL

* chore(msteams): refresh shrinkwrap

* chore(deps): refresh shrinkwrap locks

* chore(ci): rerun guards after main sync

* chore(deps): refresh shrinkwrap for node 24

* chore(config): refresh docs baseline

* fix(msteams): preserve Teams SDK proactive references

* fix(msteams): harden SDK proactive sends

* fix(msteams): align service url contract

* test: fix bonjour beacon type narrowing

* fix(msteams): ignore ambient service url

* fix(msteams): fall through submit invokes

* test: align shrinkwrap override policy with Teams SDK deps

* fix(msteams): ack invoke routes promptly

* fix(msteams): support china cloud boundaries

* test: sync PR with current CI gates

* test: isolate channel setup registry metadata

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-28 22:54:34 +01:00
Peter Steinberger
912e9dd0a6 fix: validate pixverse video response ids 2026-05-28 17:52:04 -04:00
Peter Steinberger
1fd73947d1 fix: validate pixverse video seed metadata 2026-05-28 17:49:58 -04:00
Peter Steinberger
4dbe2a3d2b fix: validate deepinfra video seed metadata 2026-05-28 17:48:09 -04:00
Peter Steinberger
1e913580d4 fix: validate fal seedance durations 2026-05-28 17:46:16 -04:00
Vincent Koc
dcecda5596 fix(e2e): reject loose journey limits 2026-05-28 23:45:26 +02:00
Vincent Koc
b8311ad6ea refactor: dedupe script validation helpers 2026-05-28 23:44:34 +02:00
Peter Steinberger
bab9a8dc37 fix: validate together video durations 2026-05-28 17:44:06 -04:00
Peter Steinberger
6d39b94a7b ci(release): serialize Telegram CI bot consumers 2026-05-28 22:42:06 +01:00
Paul Frederiksen
e69855e68c fix(codex): recover raw missing-thread compaction failures (#87738)
Recover Codex compaction paths when a stale app-server thread binding returns an unstructured `thread not found` failure. The raw missing-thread response now shares the same recovery behavior as structured missing/stale binding failures for preflight, queued compaction, and CLI fallback.

Fixes #87736.

Co-authored-by: Paul Frederiksen <paul@paulfrederiksen.com>
2026-05-28 22:41:44 +01:00
Peter Steinberger
2bc3c7ad5a fix: validate byteplus video durations 2026-05-28 17:40:33 -04:00
Jason (Json)
0dbdaf98ea fix: release session lock before runtime teardown (#87747)
Summary:
- The PR reorders embedded attempt cleanup to release the session write lock before session/MCP/LSP teardown, treats sessions_yield cleanup as abort-like for flush timing, and adds focused regression tests.
- PR surface: Source +14, Tests +71. Total +85 across 3 files.
- Reproducibility: yes. Source inspection shows current main releases the cleanup lock only after runtime tear ... R body’s terminal proof exercises the same ordering with production cleanup and filesystem lock primitives.

Automerge notes:
- PR branch already contained follow-up commit before automerge: Merge branch 'main' into fix/session-lock-release-before-teardown

Validation:
- ClawSweeper review passed for head 178192fa0e.
- Required merge gates passed before the squash merge.

Prepared head SHA: 178192fa0e
Review: https://github.com/openclaw/openclaw/pull/87747#issuecomment-4566994280

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 21:40:06 +00:00
Peter Steinberger
59997d8689 perf: avoid no-op session store rewrites 2026-05-28 22:37:56 +01:00
Peter Steinberger
a2d386638c fix: validate byteplus video seeds 2026-05-28 17:37:52 -04:00
Dallin Romney
563ad77d13 ci: sparse checkout CodeQL actions shard (#87775) 2026-05-28 14:36:31 -07:00
Vincent Koc
b05aefa3cf fix(release): bound beta smoke waits 2026-05-28 23:35:06 +02:00
Peter Steinberger
fc6fd9aa36 fix: validate inworld speech temperature 2026-05-28 17:34:49 -04:00
Peter Steinberger
769de93f9c fix: validate xai speech speed 2026-05-28 17:32:39 -04:00
Peter Steinberger
e04158a028 fix: validate volcengine speech speed ratio 2026-05-28 17:30:33 -04:00
Jason (Json)
8a007c987d fix(agents): fallback when generated media handoff locks
Generated-media completions now use the existing idempotent direct-media fallback when active requester wake has already failed and the requester-agent handoff hits a session write-lock-shaped no-response error. Generic requester-agent handoff errors still fail visibly instead of direct-sending after an unknown side effect.

Release-note context: fixes a message-delivery loss path for generated images, music, and video where the artifact had been created but the final handoff could be reported as failed after a session write lock.

Verification:
- GitHub CI run 26601111985 passed at b0be994332.
- Blacksmith Testbox through Crabbox tbx_01ksr2jtt3fnz0zqvwmqq513h7 covered the exact lock fallback and qa-channel generated-media smoke.
- git diff --check origin/main...refs/remotes/pull/87741/head passed before merge.

Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-28 22:30:13 +01:00
Peter Steinberger
51b69497a3 fix: cover explicit live model discovery 2026-05-28 22:27:35 +01:00
Peter Steinberger
c84d53ccfe fix: validate minimax speech voice settings 2026-05-28 17:26:29 -04:00
Peter Steinberger
d9452e6acb fix: validate openrouter video seeds 2026-05-28 17:16:51 -04:00
Peter Steinberger
ee6f26406f fix(release): keep mock release lanes offline
(cherry picked from commit 6ef61e4daf2fda31b84c3652feafb04677415371)
2026-05-28 22:15:42 +01:00
Peter Steinberger
4512363e85 fix: validate pixverse video seeds 2026-05-28 17:12:22 -04:00
Peter Steinberger
a5241782ca fix(nostr): close relay pool after subscription shutdown 2026-05-28 22:10:43 +01:00
IWhatsskill
8a76cc3470 fix(nostr): keep dm subscriptions alive until abort 2026-05-28 22:10:43 +01:00
Peter Steinberger
22515eea44 fix: validate google live thinking budget 2026-05-28 17:09:36 -04:00
Peter Steinberger
017e241162 fix: validate google live vad timing 2026-05-28 17:07:08 -04:00
Peter Steinberger
09c3768cdd fix: validate elevenlabs latency tiers 2026-05-28 17:04:07 -04:00
Vincent Koc
f0207d3ea0 fix(security): bound prod audit registry responses 2026-05-28 23:02:24 +02:00
Peter Steinberger
b5202f975b fix: validate elevenlabs speech seeds 2026-05-28 17:01:59 -04:00
Peter Steinberger
516be11db9 docs: add shrinkwrap and release performance report 2026-05-28 22:00:55 +01:00
Vincent Koc
3807a01542 test: dedupe gateway benchmark teardown tests 2026-05-28 23:00:29 +02:00
Peter Steinberger
1d965d9a6f fix: validate elevenlabs voice settings 2026-05-28 16:59:08 -04:00
Peter Steinberger
ec4a00beae fix: validate openai speech speeds 2026-05-28 16:56:01 -04:00
Peter Steinberger
3533297cd9 fix: validate openai realtime voice numeric config 2026-05-28 16:49:10 -04:00
Vincent Koc
db66004b31 fix(agents): stream assistant deltas incrementally (#87671) 2026-05-28 21:48:33 +01:00
Peter Steinberger
2b69cfe030 fix: validate openai realtime transcription vad 2026-05-28 16:46:15 -04:00
Super Zheng
0c716d7717 perf(plugins): reuse facade manifest snapshots
Reuses the current plugin metadata snapshot in facade activation checks when the resolved boundary config matches, avoiding repeated manifest registry loads on the facade path.

Falls back to manifest registry loading when the current snapshot is missing or belongs to a different config/environment. Adds regression coverage for snapshot mismatch, snapshot reuse, and Windows path normalization.

Co-authored-by: 郑苏波 (Super Zheng) <superzheng@tencent.com>
2026-05-28 21:45:17 +01:00
Peter Steinberger
9a21e4e6c2 perf: cache plugin registry snapshots 2026-05-28 21:45:09 +01:00
Peter Steinberger
b5d90ae4ec fix: validate voice-call legacy streaming numbers 2026-05-28 16:43:31 -04:00
Vincent Koc
b3fbe5325e refactor: dedupe approval and benchmark helpers 2026-05-28 22:41:26 +02:00
Peter Steinberger
607e6c206f fix: validate elevenlabs realtime numeric config 2026-05-28 16:39:25 -04:00
Peter Steinberger
48291462ef fix: validate runway video durations 2026-05-28 16:35:09 -04:00
Peter Steinberger
ccf3476a4a fix: validate deepinfra video seeds 2026-05-28 16:32:58 -04:00
Peter Steinberger
6966c202b9 fix: validate media size dimensions 2026-05-28 16:30:23 -04:00
Fermin Quant
205d6b730f fix(agents): attribute embedded tool logs to channels
Fixes #50565.
2026-05-28 21:29:26 +01:00
Peter Steinberger
a661506b0f fix(release): satisfy lint for beta preflight 2026-05-28 21:28:50 +01:00
Dallin Romney
2be9eb1e97 ci: consolidate Blacksmith runner defaults (#87503) 2026-05-28 13:28:22 -07:00
Peter Steinberger
714ff554fd fix: validate provider retry attempts 2026-05-28 16:28:07 -04:00
Peter Steinberger
b1c95a82a0 fix: refresh live Together and Vydra coverage 2026-05-28 21:27:50 +01:00
Vincent Koc
9268f9fe8a fix(e2e): drop unused codex media event buffer 2026-05-28 22:27:39 +02:00
Peter Steinberger
90c2ac3b6a fix: validate memory retry attempts 2026-05-28 16:26:08 -04:00
ooiuuii
f49a3e4c26 fix: bound aggregate prompt tool results
Bound aggregate tool-result history at the provider prompt boundary without rewriting persisted session entries.

Provider-visible prompt history now trims older aggregate tool results before newer evidence, while canonical session history, slash/extension command handlers, and context-engine afterTurn snapshots stay unmodified.

Co-authored-by: luyifan <al3060388206@gmail.com>
2026-05-28 21:25:02 +01:00
Peter Steinberger
4cbce8458d fix: validate acp prompt timeout metadata 2026-05-28 16:23:59 -04:00
Peter Steinberger
80c50c2370 test(whatsapp): fix remote media header mocks 2026-05-28 21:22:17 +01:00
Peter Steinberger
898f74c27e test(release): align runtime alias expectation 2026-05-28 21:22:17 +01:00
Peter Steinberger
a8dec44f56 fix(release): accept openclaw qa runtime alias 2026-05-28 21:22:17 +01:00
Peter Steinberger
2267ddc3a0 fix(release): accept openclaw runtime alias 2026-05-28 21:22:17 +01:00
Tideclaw
05202c1f8a test: tighten imessage notification callback type 2026-05-28 21:22:16 +01:00
Vincent Koc
9803261f71 fix(media): cancel ignored input fetch bodies 2026-05-28 21:22:16 +01:00
Vincent Koc
5e68d2f811 fix(media): cancel oversized fetch responses 2026-05-28 21:22:16 +01:00
Peter Steinberger
6e3f38d033 fix: validate telegram throttle ids 2026-05-28 16:21:35 -04:00
Peter Steinberger
e85231d63d fix: validate google oauth token expiry 2026-05-28 16:19:34 -04:00
Vincent Koc
686751f639 test(agents): add small model live profile (#87638) 2026-05-28 21:17:40 +01:00
Peter Steinberger
f7507fd921 fix: validate msteams error status codes 2026-05-28 16:16:43 -04:00
Peter Steinberger
ea682182d0 fix: isolate npm plugin installs per package (#87647)
* fix: isolate npm plugin installs per package

* test: assert isolated npm plugin projects in upgrade survivor

* test: assert plugin lifecycle npm project roots

* test: resolve npm project deps in live assertions

* fix: resolve codex bins from isolated npm projects

* docs: document isolated npm plugin projects

* ci: configure testbox workflow for crabbox

* fix: stabilize npm project fingerprint

* fix: keep fetch runtime import side-effect free

* test: keep dynamic live model unit hermetic

* ci: handle empty node toolcache roots

* test: make nounset toolcache probe deterministic
2026-05-28 21:16:07 +01:00
Vincent Koc
2b587be44d fix(e2e): bound tool search fetch bodies 2026-05-28 22:14:46 +02:00
Vincent Koc
50e6bd307d test(agents): narrow Codex bootstrap assertions 2026-05-28 22:14:38 +02:00
Peter Steinberger
7bc871139d fix: validate pricing content length headers 2026-05-28 16:14:25 -04:00
Dallin Romney
c629270f23 ci: filter release workflow matrices (#87508) 2026-05-28 13:12:54 -07:00
Dallin Romney
3dee915b3b ci: warm pnpm store before node fanout (#87518)
* ci: warm pnpm store before node fanout

* test: update pnpm cache acceptance key

* ci: clarify pnpm cache save controls
2026-05-28 13:11:20 -07:00
Peter Steinberger
09c5b2dd37 fix: validate discord component numeric limits 2026-05-28 16:10:07 -04:00
Vincent Koc
59205bd63c fix(e2e): bound Telegram Bot API helper bodies 2026-05-28 22:01:36 +02:00
Agustin Rivera
6fd4aa8a27 fix(nvidia): load featured model catalog (#80775)
* fix(nvidia): load featured model catalog

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

* fix(nvidia): widen catalog fetch timeout

* fix(nvidia): cover catalog registration

* fix(picker): include provider catalog loader

* fix(nvidia): guard featured catalog fetch

* fix(nvidia): sync bundled catalog with live API

Replace minimaxai/minimax-m2.5 (MiniMax M2.5) with minimaxai/minimax-m2.7 (Minimax M2.7) and z-ai/glm5 (GLM-5) with z-ai/glm-5.1 (GLM 5.1) in the bundled fallback catalog to match NVIDIA's public featured-models endpoint.

Update docs table and all extension test expectations.

* fix(nvidia): retain shipped catalog refs

* fix(picker): keep alias catalog rows

* fix(nvidia): restore live catalog priority

---------

Co-authored-by: CaptainTimon <CaptainTimon@users.noreply.github.com>
2026-05-28 12:59:55 -07:00
Peter Steinberger
409356fc66 fix: validate synology rate limits 2026-05-28 15:57:51 -04:00
Peter Steinberger
c0946e6e58 chore: remove stale dependency ownership records 2026-05-28 20:56:51 +01:00
Peter Steinberger
fcbc254d0d fix: validate feishu action count params 2026-05-28 15:55:19 -04:00
Vincent Koc
9cb4e48018 test(infra): use bonjour beacon type in discovery test
Replace the loose bonjour discovery test record shape with the exported GatewayBonjourBeacon contract so invalid-port regression coverage keeps passing the core test typecheck gate.

Verification:
- node scripts/run-vitest.mjs run src/infra/bonjour-discovery.test.ts --reporter=verbose
- node scripts/run-oxlint.mjs src/infra/bonjour-discovery.test.ts
- ./node_modules/oxfmt/bin/oxfmt --check --threads=1 src/infra/bonjour-discovery.test.ts
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- AWS Crabbox corepack pnpm check:changed: run_1af313cdd0bb, cbx_f0ef52388e7c, provider aws, exit 0

PR: https://github.com/openclaw/openclaw/pull/87765
2026-05-28 20:53:02 +01:00
Peter Steinberger
46f023d097 fix: validate nextcloud talk numeric flags 2026-05-28 15:52:39 -04:00
Peter Steinberger
8b180fe829 fix: reject malformed tlon sse event ids 2026-05-28 15:50:40 -04:00
Vincent Koc
b84078a975 fix(e2e): bound Telegram RTT driver API bodies 2026-05-28 21:48:45 +02:00
Peter Steinberger
1dcb677985 fix: reject partial qq reminder durations 2026-05-28 15:48:30 -04:00
Peter Steinberger
c42664f9b2 fix: require integer qmd line metadata 2026-05-28 15:46:23 -04:00
Peter Steinberger
04a6fd7fde fix: validate debug proxy connect ports 2026-05-28 15:44:19 -04:00
Peter Steinberger
483b06fb86 fix(ci): serialize oxlint on constrained runners 2026-05-28 20:42:37 +01:00
Peter Steinberger
d487c58c6f fix: validate browser profile ports 2026-05-28 15:40:16 -04:00
Peter Steinberger
1e67387475 fix: validate browser responsebody limits 2026-05-28 15:37:59 -04:00
Peter Steinberger
8ed9330a30 perf: defer Slack full startup (#87760) 2026-05-28 20:37:09 +01:00
Vincent Koc
605e2976ed fix(e2e): bound release fixture response bodies 2026-05-28 21:36:25 +02:00
Peter Steinberger
8fbdfc0a76 fix: validate browser geolocation numbers 2026-05-28 15:35:14 -04:00
Peter Steinberger
503d8d5542 fix: validate browser snapshot numbers 2026-05-28 15:32:25 -04:00
Peter Steinberger
f99259d25c fix(perf): preserve gateway health benchmark auth 2026-05-28 20:29:24 +01:00
Peter Steinberger
ec8ff27803 fix: validate browser viewport dimensions 2026-05-28 15:29:12 -04:00
Peter Steinberger
afb56ea972 fix: reject invalid browser tab indexes 2026-05-28 15:26:33 -04:00
clawsweeper[bot]
3617247c65 fix(tui): force repaint final chat events (#87423)
Summary:
- The PR changes three TUI final chat-event early returns to call `tui.requestRender(true)` and adds focused event-handler assertions for those branches.
- PR surface: Source 0, Tests +25. Total +25 across 2 files.
- Reproducibility: yes. Current main and the latest release still have the three unforced final-event repaint calls, and the linked source PR includes PTY terminal proof showing the changed behavior after the patch.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(tui): force repaint final chat events

Validation:
- ClawSweeper review passed for head 570dc3af86.
- Required merge gates passed before the squash merge.

Prepared head SHA: 570dc3af86
Review: https://github.com/openclaw/openclaw/pull/87423#issuecomment-4558845936

Co-authored-by: Ted Li <tl2493@columbia.edu>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 19:26:05 +00:00
Rohit
376b03f8ea fix(plugins): reject incompatible package plugin API installs (#87477)
* fix(plugins): enforce package plugin API compatibility

* fix(plugins): preserve plugin API prerelease floors

* fix(plugins): gate persisted plugin api compatibility

* fix(plugins): skip incompatible package discovery

* fix(plugins): check api compatibility before package shape

* fix(plugins): gate bundle package api compatibility

* docs(plugins): clarify plugin API release sync

* test(agents): keep dynamic live model unit test runtime-free

* fix(plugins): normalize correction plugin api floors

* test(agents): align dynamic normalizer expectation

* fix(plugins): reject malformed plugin api metadata

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-28 20:25:30 +01:00
Vincent Koc
4d5b317ace fix(e2e): bound ClawHub preflight response bodies 2026-05-28 21:24:18 +02:00
Vincent Koc
396a8ef6f8 fix(agents): loosen abort settle env typing
Narrow the abort-settle timeout helper to the env keys it reads and keep the dynamic live-model hook unit test from loading provider normalization/runtime plugins.\n\nProof: focused Vitest for live-model-dynamic-candidates, oxfmt/oxlint/diff checks, autoreview clean, AWS Crabbox run_8a485e593c2e corepack pnpm check:changed exit 0, and PR CI green.
2026-05-28 20:24:06 +01:00
Peter Steinberger
5eed10fd6e fix: reject invalid discovery ports 2026-05-28 15:23:47 -04:00
Peter Steinberger
76130fd988 fix: parse tar verbose sizes strictly 2026-05-28 15:19:53 -04:00
Peter Steinberger
73168d37ac feat: support encrypted PDF extraction (#87751) 2026-05-28 20:19:49 +01:00
Peter Steinberger
41366d3f51 fix: ignore unsafe timestamp values 2026-05-28 15:17:13 -04:00
Peter Steinberger
bd773d2f61 fix: parse subagent depth strings strictly 2026-05-28 15:15:06 -04:00
Peter Steinberger
2a5a9fd720 fix: parse usage query numbers strictly 2026-05-28 15:13:27 -04:00
Vincent Koc
4fb904ca63 fix(e2e): bound Parallels host server stderr 2026-05-28 21:11:44 +02:00
clawsweeper[bot]
dfe9774387 fix(minimax): stream music generation responses (#84764)
Summary:
- The PR updates the bundled MiniMax music provider to request streaming hex responses, decode SSE/audio bodie ... while preserving JSON/url fallbacks, and adds provider tests for streaming, fallback, and timeout behavior.
- PR surface: Source +148, Tests +152. Total +300 across 2 files.
- Reproducibility: yes. by source inspection and live proof, though I did not run a fresh live reproduction. C ... s provider fallback, and the source PR reports a 130s live MiniMax provider run succeeding after the patch.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(minimax): stream music generation responses
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8456…

Validation:
- ClawSweeper review passed for head 806b0b40f2.
- Required merge gates passed before the squash merge.

Prepared head SHA: 806b0b40f2
Review: https://github.com/openclaw/openclaw/pull/84764#issuecomment-4504175527

Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 19:11:37 +00:00
Peter Steinberger
663cf97bea fix: parse sessions filters strictly 2026-05-28 15:11:08 -04:00
Peter Steinberger
7c4601ec73 feat(slack): render progress as native task cards
Render Slack progress-mode updates as native task-card progress blocks, with bounded Slack chunk text and stable fallback behavior.

Also deep-merge Slack account streaming objects over top-level defaults while preserving legacy scalar account overrides, and keep the plugin SDK fetch runtime import path from evaluating guarded-fetch dispatcher code.

Verification:
- pnpm test extensions/slack/src/progress-blocks.test.ts extensions/slack/src/accounts.test.ts src/plugin-sdk/fetch-runtime.test.ts
- pnpm lint --threads=8
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub PR checks green on #87748 at 4803e98820

Refs #82258

Co-authored-by: Simon van Laak <32648751+simonvanlaak@users.noreply.github.com>
2026-05-28 20:08:51 +01:00
Peter Steinberger
588078224b fix: parse session lock env timeouts strictly 2026-05-28 15:06:57 -04:00
Peter Steinberger
a0fcb91670 fix(release): keep private test helpers out of npm pack 2026-05-28 20:05:50 +01:00
Dallin Romney
2d8cebba5c test: surface broad local Vitest runs (#87757) 2026-05-28 12:05:19 -07:00
Peter Steinberger
1ac8c71cf5 fix: reject unsafe memory duration values 2026-05-28 15:04:27 -04:00
Dallin Romney
9f0fccd3a5 test(auto-reply): narrow directive model test dependencies (#87519)
* test(auto-reply): narrow directive model test dependencies

* test(auto-reply): stabilize directive model test mocks
2026-05-28 12:03:08 -07:00
Peter Steinberger
490c226202 fix: parse matrix no-reply window strictly 2026-05-28 15:02:14 -04:00
Peter Steinberger
a2595f16d4 fix: reject unsafe bash env integers 2026-05-28 15:00:08 -04:00
Vincent Koc
1a926d19b0 fix(e2e): bound RTT credential broker bodies 2026-05-28 20:58:01 +02:00
Peter Steinberger
d23e4111b0 fix: parse matrix qa env timeouts strictly 2026-05-28 14:57:52 -04:00
Peter Steinberger
a691d52329 fix: parse slack cache ttl strictly 2026-05-28 14:54:02 -04:00
Vincent Koc
f9834a3f95 ci: pin macOS runner labels 2026-05-28 20:52:52 +02:00
Peter Steinberger
43e243f436 fix: support grouped skill folders
Support grouped skill folders while keeping skill invocation flat via frontmatter names.

Includes bounded nested SKILL.md discovery, refresh/watch coverage for grouped folders, plugin symlink containment, and docs for grouped skill organization.

Verification:
- Node 24 targeted skill discovery and refresh tests passed locally.
- Docs checks passed locally and in CI.
- Autoreview clean.
- Crabbox live OpenAI proof showed nested foo/bar skills listed and visible in the agent system prompt.
- CI run 26595118581 passed.
2026-05-28 19:52:27 +01:00
Peter Steinberger
4b8c260444 fix: parse browser action timeouts strictly 2026-05-28 14:51:23 -04:00
alkor2000
b3db1dba85 fix(anthropic): stop migrating current claude-haiku-4-5 to sonnet (#87719)
Summary:
- The branch preserves current Claude Haiku 4.5 refs in the Anthropic resolver and doctor migration, repoints the bare `haiku` family alias to `claude-haiku-4-5`, and updates regression tests.
- PR surface: Source +5, Tests +21. Total +26 across 4 files.
- Reproducibility: yes. Current main source maps the bare `haiku` alias and explicit Haiku 4.5 migration path  ... de-sonnet-4-6`; the PR body also supplies before/after terminal proof for the resolver and migration tests.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head 64429e23b3.
- Required merge gates passed before the squash merge.

Prepared head SHA: 64429e23b3
Review: https://github.com/openclaw/openclaw/pull/87719#issuecomment-4566419633

Co-authored-by: alkor2000 <200923177@qq.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 18:50:36 +00:00
Peter Steinberger
0786f586af fix: parse memory wiki cli numbers strictly 2026-05-28 14:49:02 -04:00
Peter Steinberger
f0bfa650dc fix: parse browser cli numbers strictly 2026-05-28 14:46:34 -04:00
NVIDIAN
6fbdae1c51 fix(memory-core): cap Dreaming short-term recall growth
Cap Dreaming short-term recall stores so repeated recall recording, repair, and promotion application cannot grow the JSON artifact without bound.

The fix keeps full normalized snippets for recall identity and contamination checks before truncating persisted snippets, exposes the new overflow audit code through the SDK facade, and adds regression coverage for recording, repair, promotion rehydration, and deterministic retention ties.

Fixes #87095.

Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/memory-core/src/short-term-promotion.test.ts src/commands/doctor-memory-search.test.ts src/plugin-sdk/memory-core-engine-runtime.test.ts
- pnpm tsgo:prod
- pnpm check:test-types
- pnpm lint --threads=8
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- PR CI run 26594527697: unrelated current-main failures only in checks-node-agentic-plugin-sdk and checks-node-agentic-agents; same failures reproduced on main run 26594198639.

Co-authored-by: ai-hpc <mail.speedy.hpc@hotmail.com>
2026-05-28 19:44:58 +01:00
Peter Steinberger
e8f29087ae fix: validate configure gateway ports strictly 2026-05-28 14:43:19 -04:00
Peter Steinberger
b2fdbc53e8 fix: parse qa parent pid strictly 2026-05-28 14:41:02 -04:00
Peter Steinberger
528371e7a4 docs(changelog): refresh 2026.5.28 notes 2026-05-28 19:39:42 +01:00
Peter Steinberger
5e33d7dff9 fix: parse discord gateway timeouts strictly 2026-05-28 14:39:05 -04:00
Peter Steinberger
cd80b4efca fix: parse qa cli integers strictly 2026-05-28 14:36:47 -04:00
Peter Steinberger
68ff0b9881 fix: parse memory cli numbers strictly 2026-05-28 14:33:18 -04:00
Peter Steinberger
8ec4a72f64 fix: parse voice call cli integers strictly 2026-05-28 14:31:24 -04:00
Vincent Koc
8338986a59 fix(e2e): bound telegram credential broker bodies 2026-05-28 20:29:16 +02:00
Peter Steinberger
d23e4aea6f fix: parse google meet cli numbers strictly 2026-05-28 14:28:49 -04:00
Peter Steinberger
a82dfb8e58 fix: parse google meet env numbers strictly 2026-05-28 14:25:58 -04:00
Peter Steinberger
2afff85ca4 fix: parse signal archive length strictly 2026-05-28 14:23:26 -04:00
Peter Steinberger
b87510957f docs: clarify Codex native hook relay recovery 2026-05-28 19:21:50 +01:00
Peter Steinberger
4ad9f0bdbb refactor: route node proxy agents through proxyline 2026-05-28 19:21:50 +01:00
Peter Steinberger
2305bca782 fix: parse discord rate limit headers strictly 2026-05-28 14:21:29 -04:00
Peter Steinberger
bcf354eac1 fix: parse codex retry headers strictly 2026-05-28 14:19:47 -04:00
Vincent Koc
21e69fdd4f fix(ollama): promote plain text tool calls
Wrap Ollama native streams with the shared plain-text tool-call compatibility wrapper so local/plain-text tool requests are delivered as structured toolCall events when matching tools are available.

Verified with live local Ollama proof, focused Testbox Vitest, Testbox check:changed, and autoreview.
2026-05-28 19:18:41 +01:00
Peter Steinberger
7859ee396e fix: parse provider retry dates strictly 2026-05-28 14:17:36 -04:00
Peter Steinberger
5eee488d93 fix: parse discord api retry headers strictly 2026-05-28 14:12:33 -04:00
Peter Steinberger
1d28dd87a5 fix: parse discord retry delays strictly 2026-05-28 14:08:04 -04:00
Peter Steinberger
a8991e02d8 fix: parse feishu startup timeout env strictly 2026-05-28 14:05:23 -04:00
Peter Steinberger
99f70284bf fix: parse feishu timeout env strictly 2026-05-28 14:03:06 -04:00
Peter Steinberger
21db3ff11c fix: parse telegram qa timeout env strictly 2026-05-28 14:00:56 -04:00
Peter Steinberger
19d1c217dc fix: parse qa credential integer env strictly 2026-05-28 13:57:33 -04:00
Lior Balmas
492105db5a fix(media): compact whatsapp terminal qr (#87581) 2026-05-28 10:57:03 -07:00
Peter Steinberger
d3b5413a01 fix: parse qa worker stagger env strictly 2026-05-28 13:55:13 -04:00
Peter Steinberger
2e8b3445fb fix: parse qa transport timeout env strictly 2026-05-28 13:53:18 -04:00
Peter Steinberger
339a74a342 fix: parse qa process metrics strictly 2026-05-28 13:51:33 -04:00
Peter Steinberger
5b79ab0901 fix: parse codex computer use timeout env strictly 2026-05-28 13:49:38 -04:00
Peter Steinberger
929b3a4f16 fix: parse codex migration timeout env strictly 2026-05-28 13:45:05 -04:00
Peter Steinberger
2cde331772 fix: parse qa suite concurrency env strictly 2026-05-28 13:41:28 -04:00
Dallin Romney
5f9d71f8af fix(ci): raise plugin sdk strict smoke heap (#87729) 2026-05-28 10:39:32 -07:00
Peter Steinberger
df4475d232 fix: parse embedded abort settle timeout strictly 2026-05-28 13:38:19 -04:00
Peter Steinberger
f90e266416 fix: parse sdk retry wait env strictly 2026-05-28 13:36:34 -04:00
Vincent Koc
bbc9a7d3fa fix(e2e): bound OpenWebUI probe response bodies 2026-05-28 19:35:12 +02:00
Peter Steinberger
d47eee4407 fix: parse queue caps strictly 2026-05-28 13:34:47 -04:00
Peter Steinberger
2122dccb91 fix: parse gateway usage days strictly 2026-05-28 13:31:45 -04:00
Peter Steinberger
d08bcb427e fix: parse http idle timeout strings strictly 2026-05-28 13:29:15 -04:00
Peter Steinberger
42688f5aae fix: parse cleanup timeout env strictly 2026-05-28 13:27:20 -04:00
Peter Steinberger
d6c8e05de9 fix: parse handshake timeout env strictly 2026-05-28 13:25:12 -04:00
Peter Steinberger
ca87241289 fix: parse cron stagger strings strictly 2026-05-28 13:22:54 -04:00
Peter Steinberger
ed9299a216 fix: reject invalid cron epoch timestamps 2026-05-28 13:20:09 -04:00
Peter Steinberger
3bf86877c2 fix: parse cron task run ids strictly 2026-05-28 13:17:57 -04:00
clawsweeper[bot]
202ccf4cf7 fix(native-hook-relay): prune stale bridge files on registration (#87706)
Summary:
- The PR adds registration-time pruning of expired or ESRCH-dead native-hook relay bridge JSON files and regression tests for dead, expired, live, and unknown-liveness foreign records.
- PR surface: Source +59, Tests +148. Total +207 across 2 files.
- Reproducibility: yes. The linked source PR includes a concrete live WSL2/systemd reproduction with stale bri ...  hook failures, and current source shows the native hook CLI fails closed when the relay cannot be reached.

Automerge notes:
- PR branch already contained follow-up commit before automerge: test(native-hook-relay): cover stale bridge pruning
- PR branch already contained follow-up commit before automerge: ci: raise plugin sdk strict smoke heap
- PR branch already contained follow-up commit before automerge: test(native-hook-relay): satisfy process kill mock types
- PR branch already contained follow-up commit before automerge: fix(native-hook-relay): prune stale bridge files on registration

Validation:
- ClawSweeper review passed for head 65c17cdf6e.
- Required merge gates passed before the squash merge.

Prepared head SHA: 65c17cdf6e
Review: https://github.com/openclaw/openclaw/pull/87706#issuecomment-4566131519

Co-authored-by: Applied-AI-Solutions-hub <Applied-AI-Solutions-hub@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 17:17:28 +00:00
Peter Steinberger
27dfb9149f test: cover dynamic live model refs 2026-05-28 18:16:45 +01:00
Peter Steinberger
b2fc8af1b1 fix: reject malformed media content length 2026-05-28 13:15:25 -04:00
Peter Steinberger
f3a23f8f5d fix: parse ffprobe sample rates strictly 2026-05-28 13:12:42 -04:00
Peter Steinberger
c2c29588f4 chore: update dependency pins 2026-05-28 18:10:39 +01:00
Peter Steinberger
0311171350 fix: parse ps cpu time formats 2026-05-28 13:10:28 -04:00
Peter Steinberger
5393240441 fix: clamp read tool line limits 2026-05-28 13:06:21 -04:00
Peter Steinberger
5ebf3b0396 fix: parse sandbox stat fields strictly 2026-05-28 13:03:14 -04:00
Vincent Koc
ea0b6bcb1f fix(scripts): give boundary root shims macos headroom 2026-05-28 19:00:45 +02:00
Vincent Koc
5fc5aa8f81 fix(e2e): bound kitchen sink rpc probe bodies 2026-05-28 19:00:45 +02:00
Peter Steinberger
a23a668d91 fix: honor bare ipv6 no_proxy entries 2026-05-28 12:54:13 -04:00
Peter Steinberger
e205888fa7 fix: honor ipv6 no_proxy entries 2026-05-28 12:50:59 -04:00
Nachiket Torwekar
53475c21b8 perf: reduce latency across async I/O hot paths
Improves gateway/device-auth/session discovery latency by caching unchanged device-auth reads, deduping session root realpaths, cleaning temp dirs in parallel, and bulk-loading APNs registrations for iOS exec approval delivery.

The maintainer fixup replaces per-device APNs registration reads with a single canonical store snapshot, preserving empty-target skip behavior and requested target ordering while avoiding delayed read failures from the bounded queue path.

Verification:
- node scripts/run-vitest.mjs src/gateway/exec-approval-ios-push.test.ts src/infra/push-apns.store.test.ts src/infra/device-auth-store.test.ts src/config/sessions/targets.test.ts src/test-utils/tracked-temp-dirs.test.ts src/utils/run-with-concurrency.test.ts
- env -u OPENCLAW_TESTBOX pnpm check:changed
- env -u OPENCLAW_TESTBOX pnpm test:changed
- pnpm exec oxfmt --check --threads=1 on touched files
- autoreview clean: no accepted/actionable findings
- before/after 500-device APNs discovery benchmark: p50 189.89 ms -> 2.03 ms
- GitHub Actions CI 26588266247 green after rerun; Real behavior proof 26588276271 green

Co-authored-by: Nachiket Torwekar <nachiket.torwekar@gmail.com>
2026-05-28 17:47:26 +01:00
Peter Steinberger
9e1faf81ab fix: count qmd output caps by code point 2026-05-28 12:47:08 -04:00
Peter Steinberger
f4f059ef94 fix: cap chrome mcp stderr by utf8 bytes 2026-05-28 12:42:18 -04:00
Peter Steinberger
75c3b53038 [codex] Use clawpdf for PDF extraction (#87670)
* feat: use clawpdf for PDF extraction

* fix: align approval action prompt typing

* chore: use clawpdf 0.2.0

* fix: lazily load clawpdf backend
2026-05-28 17:35:39 +01:00
Peter Steinberger
478e0ec3f8 fix: keep stderr tail within utf8 byte cap 2026-05-28 12:35:00 -04:00
clawsweeper[bot]
51e240123b fix(images): skip CLI image cache refs (#87523)
Summary:
- The branch filters OpenClaw CLI image-cache paths out of prompt image-reference detection and adds parser/helper regression tests.
- PR surface: Source +17, Tests +65. Total +82 across 3 files.
- Reproducibility: yes. source-level reproduction is high confidence: current main still scans replayed prompt ... ectImageReferences and has no cache-path exclusion before loadPromptRefImages can reload stale image paths.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(images): skip CLI image cache refs
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8750…

Validation:
- ClawSweeper review passed for head dfe0408df8.
- Required merge gates passed before the squash merge.

Prepared head SHA: dfe0408df8
Review: https://github.com/openclaw/openclaw/pull/87523#issuecomment-4560945125

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 16:34:54 +00:00
clawsweeper[bot]
e9655b9fdc fix(ui): preserve session picker on empty search blur (#87682)
Summary:
- The PR changes the Control UI chat session picker blur handler to skip empty-query search application and adds a regression test that picker options remain clickable after an empty search blur.
- PR surface: Source +4, Tests +52. Total +56 across 2 files.
- Reproducibility: yes. The issue steps, before recording, and current-main source path all point to the same  ... r clearing picker state before click delivery; I did not rerun a live browser repro in this read-only pass.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ui): preserve session picker on empty search blur

Validation:
- ClawSweeper review passed for head bb14687756.
- Required merge gates passed before the squash merge.

Prepared head SHA: bb14687756
Review: https://github.com/openclaw/openclaw/pull/87682#issuecomment-4565441074

Co-authored-by: Ryan Weng <14496969+ryan4559@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-28 16:34:50 +00:00
Peter Steinberger
0d66710539 fix: parse lsp content length by byte 2026-05-28 12:29:45 -04:00
rain
2df8021cda fix(agents): surface MCP structured content in tool results
Surface inbound bundle-MCP structuredContent as the model-visible result when present so agents can read Codex MCP threadId values and continue with codex-reply. Preserve non-structured content behavior, preserve the empty-result fallback, and keep details.structuredContent for internal consumers.

Also remove an unused secrets path helper that was breaking the latest prod-type gate on main.

Fixes #87511.

Verification:
- node scripts/run-vitest.mjs src/agents/agent-bundle-mcp-tools.materialize.test.ts
- pnpm exec oxfmt --check src/secrets/path-utils.ts src/agents/agent-bundle-mcp-materialize.ts src/agents/agent-bundle-mcp-tools.materialize.test.ts
- pnpm tsgo:prod
- local check-guards shard commands
- live Codex MCP smoke with codex__codex and codex__codex-reply same-thread continuation
- autoreview clean
- CI run 26587222874 green

Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 17:29:29 +01:00
clawsweeper[bot]
cd0b692b61 fix(voice-call): make webhook replays token-safe
Fix replay handling for voice-call webhooks so duplicate signed requests do not mint or expose realtime stream tokens.

- Return token-free Twilio replay TwiML before realtime setup shortcuts.
- Cache bounded non-Twilio first responses for idempotent replay XML while skipping duplicate side effects.
- Cover Twilio realtime replay and Plivo replay behavior with regression tests.
- Remove an unused secrets path helper that was tripping latest-main prod type CI.

Fixes #87497.

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
2026-05-28 17:29:15 +01:00
Vincent Koc
716fd67e03 fix(scripts): bound Z.AI fallback repro output 2026-05-28 18:19:34 +02:00
Peter Steinberger
a85ff92c05 perf: cache bundled channel entry resolution 2026-05-28 17:18:51 +01:00
Val Alexander
96635c7c27 fix(webchat): preserve sends through reconnect (#87531)
* fix(webchat): preserve sends through reconnect

* fix(webchat): scope queued sends by session

* fix(webchat): localize queue retry labels

* fix(secrets): remove unused path helper

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-28 17:18:24 +01:00
Peter Steinberger
c00ac952a8 fix: reject malformed inspected tcp ports 2026-05-28 12:15:23 -04:00
Peter Steinberger
982e2cf0ef fix: reject malformed marketplace content length 2026-05-28 12:11:50 -04:00
Peter Steinberger
03e6181f9f fix: reject exponent provider integer options 2026-05-28 12:08:09 -04:00
Andy Ye
5f88932806 fix(sessions): recover empty preflight compaction
Fixes #87016.

Empty preflight compaction recovery now resets stale token snapshots immediately, preserves valid legacy transcript rows during cleanup, and avoids re-persisting stale context-budget or compaction metadata after a successful retry.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-28 17:06:38 +01:00
Peter Steinberger
fb80d3a491 perf: reduce gateway startup sidecar overhead 2026-05-28 17:05:19 +01:00
Peter Steinberger
e67ff0c43e fix: canonicalize secret target array indexes 2026-05-28 12:02:21 -04:00
Peter Steinberger
c9c53e3153 fix: harden config array index parsing 2026-05-28 11:58:40 -04:00
David
7a36bb37af feat(gateway): show warm MCP tools in effective inventory
Add read-only MCP visibility to `tools.effective` by projecting MCP tools only after a session catalog has already been warmed by an agent turn. Keep the gateway additive: no `tools.effective.refresh`, no forced MCP startup, and no behavior change for MCP loading.

Verification:
- `git diff --check origin/main..HEAD`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts --reporter=verbose src/agents/tools-effective-inventory.test.ts`
- GitHub checks green on `a8a7f8442adb216f60da24d50118374a15c62e06`, including `Real behavior proof`, `check-guards`, `check-prod-types`, `check-test-types`, `build-artifacts`, `Critical Quality (gateway-runtime-boundary)`, and `Critical Quality (network-runtime-boundary)`.

Co-authored-by: David Huang <nxmxbbd@gmail.com>
2026-05-28 16:52:53 +01:00
Vincent Koc
b261e9e6dd fix(approvals): restore reaction command prompt lines 2026-05-28 17:32:58 +02:00
Vincent Koc
e707b452c0 fix(scripts): bound control UI i18n process output 2026-05-28 17:32:58 +02:00
Peter Steinberger
79e733cc34 docs: remove public GHSA fix mechanism details 2026-05-28 16:30:39 +01:00
Peter Steinberger
f8c8c0d41e fix(agents): handle seeded Anthropic signatures 2026-05-28 16:28:36 +01:00
Jerry Xin
8dc9cfe734 fix(agents): concatenate signature_delta chunks in transport stream
The anthropic-transport-stream was overwriting thinkingSignature on each
signature_delta event instead of appending. Since Anthropic sends the
thinking block signature across multiple streaming chunks, only the last
chunk survived. The truncated signature was persisted to session JSONL,
causing all subsequent replay attempts to fail with HTTP 400:

  thinking or redacted_thinking blocks in the latest assistant message
  cannot be modified

This permanently bricked sessions with no user recovery path.

Fix: accumulate signature_delta values by concatenating instead of
overwriting, matching the correct implementation in the LLM provider
layer (src/llm/providers/anthropic.ts:629-634).

Includes real-scenario proof against live Anthropic API validating that
correct signatures replay successfully while truncated signatures are
rejected.

Fixes #87574
Refs #80625, #85781, #87475
2026-05-28 16:28:36 +01:00
Peter Steinberger
e5adde9fe3 fix(auto-reply): respect provider for directive persistence (#87683) 2026-05-28 16:27:19 +01:00
rain
ad3e3cb7d2 fix(agents): preserve reasoning_content replay across DeepSeek tier suffixes (#87593)
* fix(agents): preserve reasoning_content replay across DeepSeek tier suffixes

OpenCode Zen exposes DeepSeek V4 as `deepseek-v4-flash-free`, which keeps the upstream DeepSeek thinking-mode contract that requires `reasoning_content` to be passed back on follow-up requests. The existing replay allowlist only matched the bare ids (`deepseek-v4-flash`, `kimi-k2-thinking`, ...), so the tier-suffixed id missed every candidate and the sanitizer stripped `reasoning_content` from the assistant turn. DeepSeek then rejected the second API call with HTTP 400 and the session deadlocked.

Strip the well-known tier suffixes (`-free`, `-paid`, `-trial`) when generating allowlist candidates so the base model id matches and the reasoning replay survives. Existing matching for prefixed / colon-suffixed routes is unchanged.

Fixes #87575

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agents): avoid spread-rebuild when iterating allowlist candidates

oxlint flagged the [...candidates] spread as an unnecessary array copy. Use an explicit baseCount loop bound instead so we still iterate the original entries while pushing tier-stripped variants onto the same array.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(opencode): add live DeepSeek replay probe

* test(opencode): avoid forced tool choice in live replay

---------

Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-28 16:25:54 +01:00
clawsweeper[bot]
5216841a9e docs: treat CLI setup flows as API contracts (#87685)
Co-authored-by: ClawSweeper <clawsweeper@users.noreply.github.com>
2026-05-28 16:17:42 +01:00
Peter Steinberger
b601550c97 docs: harden GHSA wording guidance 2026-05-28 16:16:10 +01:00
rain
ad1d8bf990 fix(openrouter): apply strict9 ids to Mistral routes
Fixes #58012.

Applies strict9 replay tool call id sanitization to OpenRouter Mistral-family model routes, including unprefixed Mistral/Codestral/Devstral aliases, while preserving existing passthrough behavior for Gemini and other OpenRouter-backed routes.

Adds focused unit coverage plus a live OpenRouter model catalog test so new Mistral-family routes are checked against the replay policy. Also keeps the current core lint gate green by switching the tool schema cache key sort to a non-mutating sorted array.

Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 16:14:32 +01:00
Peter Steinberger
049c1158c9 perf: cache plugin module exports per loader 2026-05-28 16:12:13 +01:00
Peter Steinberger
81c90aab6b perf: prefer built bundled runtime surfaces 2026-05-28 16:03:02 +01:00
Michael Appel
85277c2db1 Block provider credentials from workspace dotenv [AI] (#83655)
* fix: block provider credentials from workspace dotenv

* addressing codex review

* fix(dotenv): document provider credential sources

---------

Co-authored-by: Agustin Rivera <agustin@rivera-web.com>
Co-authored-by: Devin Robison <drobison00@users.noreply.github.com>
2026-05-28 08:57:57 -06:00
Vincent Koc
9adbab05c6 fix(core): restore changed gate typecheck 2026-05-28 16:53:01 +02:00
Vincent Koc
83bb5fb994 fix(agents): quarantine compaction tool schemas 2026-05-28 16:52:44 +02:00
Peter Steinberger
b6ef874220 fix: reject partial numeric parsing 2026-05-28 10:51:32 -04:00
Peter Steinberger
68e6f03fd9 perf: reduce gateway runtime discovery overhead 2026-05-28 15:47:50 +01:00
Vincent Koc
7b5f0c23e5 fix(codex): bound sandbox http stream lines 2026-05-28 16:36:12 +02:00
Vincent Koc
3e2994b975 fix(ssh): bound config probe output 2026-05-28 16:33:12 +02:00
Agustin Rivera
2c3d7f5bad fix(msteams): bind bot framework service urls (#87160)
* fix(msteams): bind bot framework service urls

* fix(msteams): harden service url validation
2026-05-28 07:31:46 -07:00
Vincent Koc
dab3152e0e fix(telegram): bound proof command output 2026-05-28 16:31:05 +02:00
Andy Ye
3fea219692 fix(daemon): preserve explicit systemd unit during refresh
Preserve explicit gateway service identity when package/update refreshes the managed service environment. This keeps caller-selected systemd units ahead of stale persisted service env and applies the same precedence to launchd labels and Windows task names during service-state inspection.

Fixes #87490

Verification:
- node scripts/run-vitest.mjs src/daemon/service-env.test.ts src/daemon/service.test.ts src/cli/update-cli.test.ts src/cli/update-cli/restart-helper.test.ts src/cli/daemon-cli/install.test.ts src/daemon/systemd.test.ts
- git diff --check origin/main...pr/87556
- Crabbox AWS Linux systemd install/refresh proof: run_f3374bd610f7, lease cbx_754e69eb6c3a, provider aws, target linux
- autoreview --mode branch --base origin/main: clean, no accepted/actionable findings

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-28 15:27:51 +01:00
Nimrod Gutman
3f3ed5ec66 fix(gateway): preserve traced child sessions 2026-05-28 17:26:51 +03:00
Colin Johnson
f6e51ff99a feat(ios): refresh pro UI and gateway flows (#87367)
Summary:
- Replace the legacy iOS shell with Pro Command, Chat, Agents, and Settings tabs.
- Wire iOS chat/session/settings/diagnostics and realtime Talk flows through gateway-backed APIs.
- Add gateway/session and shared chat coverage for the new iOS flow.

Verification:
- git diff --check
- node scripts/run-vitest.mjs src/gateway/server.sessions.create.test.ts src/gateway/talk-realtime-relay.test.ts
- swift test --filter ChatViewModelTests (apps/shared/OpenClawKit)
- xcodebuild build for Nimrod's iPhone succeeded; install succeeded; launch was blocked because the phone was locked

Known follow-up:
- Preserve traceLevel in sessions.create parent runtime inheritance and keep the changelog credit in the follow-up patch.
2026-05-28 17:23:26 +03:00
Vincent Koc
65d47dc5d7 fix(imessage): bound cli output capture 2026-05-28 16:22:21 +02:00
Vincent Koc
b4741302c6 fix(auto-reply): bound scp staging stderr 2026-05-28 16:16:01 +02:00
Vincent Koc
76f447b250 fix(voice-call): ignore tailscale helper stderr 2026-05-28 16:13:59 +02:00
Vincent Koc
bc6ecc89d5 fix(voice-call): ignore ngrok probe output 2026-05-28 16:11:54 +02:00
Vincent Koc
47fdd6b88b fix(voice-call): drain tailscale tunnel output 2026-05-28 16:09:50 +02:00
Vincent Koc
80909b3265 fix(scripts): bound boundary check output 2026-05-28 16:09:12 +02:00
Vincent Koc
c7891ec67e fix(voice-call): bound tailscale status output 2026-05-28 16:07:19 +02:00
Peter Steinberger
910354b07f docs: point release process at public evidence repo 2026-05-28 15:04:33 +01:00
Ayaan Zaidi
844d263af0 test(telegram): cover long streamed final replay 2026-05-28 19:33:53 +05:30
Ayaan Zaidi
27d57af127 fix(telegram): retain streamed long final prefixes 2026-05-28 19:33:53 +05:30
Vincent Koc
b667bdd622 fix(release): bound command output capture 2026-05-28 16:01:25 +02:00
Ayaan Zaidi
3cb7ae5350 fix(docker): alias main images to latest release 2026-05-28 19:30:17 +05:30
Peter Steinberger
b58786ce9f perf: reduce agent turn CPU overhead 2026-05-28 14:59:09 +01:00
Vincent Koc
ff5886bba2 fix(matrix): bound bootstrap output capture 2026-05-28 15:58:34 +02:00
Vincent Koc
f2f18f5958 fix(agents): bound search tool stderr 2026-05-28 15:55:51 +02:00
Vincent Koc
8ba71e4aff fix(process): bound command output capture 2026-05-28 15:52:02 +02:00
Vincent Koc
44451eaa47 fix(ci): run CodeQL on main pushes 2026-05-28 15:49:18 +02:00
Vincent Koc
865678eb6b fix(backup): cap verify manifest extraction 2026-05-28 15:48:51 +02:00
Vincent Koc
38f3040384 fix(agents): normalize session tool limits 2026-05-28 15:44:44 +02:00
Ayaan Zaidi
bda924b639 fix(telegram): preserve final overflow state 2026-05-28 19:08:27 +05:30
Ayaan Zaidi
8677310fb5 fix(telegram): skip stopped draft finalization 2026-05-28 19:08:27 +05:30
Ayaan Zaidi
e856932600 fix(telegram): clamp partial draft overflow 2026-05-28 19:08:27 +05:30
Ayaan Zaidi
a048cbc4f0 test(telegram): cover draft preview overflow 2026-05-28 19:08:27 +05:30
Vincent Koc
8e3be0a705 fix(crestodian): bound local command probes 2026-05-28 15:37:05 +02:00
Vincent Koc
76ebc14956 fix(agents): detect signaled local service exits 2026-05-28 15:25:32 +02:00
Peter Steinberger
3d89f493ba fix(release): port 2026.5.27 fixes 2026-05-28 14:25:01 +01:00
Vincent Koc
a5eddb91bb fix(msteams): bound service error bodies 2026-05-28 15:22:03 +02:00
Vincent Koc
56302f79a8 fix(test): keep btw fs promises mock partial 2026-05-28 15:19:09 +02:00
Ayaan Zaidi
dc31f73b39 ci(docker): publish browser release images 2026-05-28 18:48:45 +05:30
Vincent Koc
5809bdf0cb fix(test): detect signaled memory fd gateway exits 2026-05-28 15:17:23 +02:00
Vincent Koc
97ed582f1c fix(test): detect signaled kitchen sink gateway exits 2026-05-28 15:09:16 +02:00
Peter Steinberger
6eedc8331b docs: add release verification skill 2026-05-28 14:07:24 +01:00
Vincent Koc
6835f05cd0 fix(test): detect signaled test gateway exits 2026-05-28 15:02:01 +02:00
Peter Steinberger
d7e62a87f2 test: stabilize code mode wait timeout
Increase the code-mode wait-timeout test timeout so CI shard load does not trip the worker startup guard before the test reaches the intended pending-tool wait path.
2026-05-28 08:56:57 -04:00
Vincent Koc
f48a89cb1c fix(test): detect signaled cross-os gateway exits 2026-05-28 14:52:47 +02:00
Vincent Koc
aa82b43c9f fix(test): detect signaled bundled smoke exits 2026-05-28 14:46:39 +02:00
Vincent Koc
a854331c4c fix(test): hard kill boundary prep timeouts 2026-05-28 14:40:52 +02:00
Vincent Koc
3fb67467fa fix(test): hard kill boundary step timeouts 2026-05-28 14:34:14 +02:00
Peter Steinberger
51e57d46cf docs: tune clawdtributor refresh summaries 2026-05-28 13:33:12 +01:00
Vincent Koc
e5a687f115 fix(test): handle extension memory spawn errors 2026-05-28 14:27:59 +02:00
Peter Steinberger
17c1b06cc7 chore(release): update appcast for 2026.5.27
Updates production Sparkle appcast for v2026.5.27 from the private macOS publish workflow.
2026-05-28 13:27:54 +01:00
Vincent Koc
bda3531560 fix(test): bound startup build helpers 2026-05-28 14:25:06 +02:00
Peter Steinberger
aab5410bd5 test: speed up slow test suite (#87611)
* test: speed up slow test suite

* test: preserve fake timer cleanup hooks

* test: avoid timeout readiness race

* test: satisfy reply test types

* test: restore runner and image coverage

* test: restore final media runner path

* test: make cli auth status fixture deterministic

* test: repair runtime alias fixtures
2026-05-28 13:20:19 +01:00
Vincent Koc
e0635eb6fd fix(release): bound npm release checks 2026-05-28 14:20:01 +02:00
Peter Steinberger
4252f07ff0 fix: reduce gateway warning noise
Reduce repeated gateway warning noise in startup/auth retry paths while preserving credential mismatch and rate-limit audit visibility.

Also hardens empty embedded-assistant retry handling by carrying lifecycle state through the missing-assistant guard, and keeps the relevant regression coverage in gateway and agent tests.
2026-05-28 13:17:57 +01:00
Vincent Koc
4ce3c3e36c fix(test): rebuild startup memory artifacts 2026-05-28 14:14:34 +02:00
Vincent Koc
653e8d1ea5 fix(release): bound prepack subprocesses 2026-05-28 14:14:13 +02:00
Vincent Koc
98d6331d10 fix(release): bound release check commands 2026-05-28 14:11:55 +02:00
Vincent Koc
2b0e399da1 fix(release): bound npm verifier commands 2026-05-28 14:06:46 +02:00
Vincent Koc
b234aa0085 fix(e2e): bound bundled plugin selection 2026-05-28 14:03:24 +02:00
Vincent Koc
cee364e2f6 fix(docker): bound package capture output 2026-05-28 14:01:02 +02:00
Vincent Koc
da551463e3 fix(agent-sessions): fail oversized exec output 2026-05-28 13:53:17 +02:00
Vincent Koc
2252cf6f03 fix(supervisor): bound captured process output 2026-05-28 13:43:36 +02:00
Vincent Koc
9a7f808953 fix(file-transfer): bound dir fetch tar listings 2026-05-28 13:39:55 +02:00
Vincent Koc
eb273a8a4a fix(brave): bound search error bodies 2026-05-28 13:28:27 +02:00
Vincent Koc
259796dc3d fix(test): bound package candidate command output 2026-05-28 13:26:16 +02:00
Vincent Koc
d64b394537 fix(test): bound extension memory profiler output 2026-05-28 13:22:57 +02:00
Vincent Koc
88c395c83c fix(test): wait for credential timeout cleanup 2026-05-28 13:17:35 +02:00
Vincent Koc
9085d17ab6 fix(qa-lab): bound plugin tools stderr tail 2026-05-28 13:07:46 +02:00
Vincent Koc
4a2b02e86f fix(qa-lab): bound child process output 2026-05-28 13:04:09 +02:00
Vincent Koc
beb25d60f7 fix(test): escalate e2e watchdog termination 2026-05-28 13:03:29 +02:00
Vincent Koc
4bd711e1c4 fix(security): avoid fetching untrusted proof refs 2026-05-28 12:39:12 +02:00
Vincent Koc
3844e035bb fix(security): avoid CodeQL legacy auth patterns 2026-05-28 12:32:49 +02:00
Vincent Koc
9fef53c3b1 fix(test): keep upgrade survivor runtime state local 2026-05-28 12:30:58 +02:00
Pavan Kumar Gondhi
91a4635bdc Tighten phone-control mutation authorization [AI] (#87150)
* fix: require admin authorization for phone control mutations

* addressing codex review

* addressing codex review

* addressing ci

* addressing ci

* test: restore provider registry mock isolation

* docs: add changelog entry for PR merge
2026-05-28 16:00:01 +05:30
Vincent Koc
629fc2f8f0 fix(voice-call): bound ngrok diagnostics 2026-05-28 12:16:44 +02:00
Vincent Koc
1bc32e53ab fix(qa): expose credential fingerprints in admin list 2026-05-28 12:04:20 +02:00
Vincent Koc
93577ad587 fix(memory): bound remote error bodies 2026-05-28 11:51:26 +02:00
Pavan Kumar Gondhi
bb418a857e Clarify directive persistence authorization policy [AI] (#86369)
* fix: require admin scope for persisted directive defaults

* addressing codex review

* fix: complete directive persistence scope gate

* addressing review-skill

* fix: preserve channel directive persistence

* fix: require admin scope for directive default persistence

* addressing codex review

* fix: complete directive persistence scope handling

* addressing codex review

* fix: complete directive persistence gate

* addressing review-skill

* fix: complete directive persistence gate

* addressing review-skill

* clarify directive persistence policy

* docs: add changelog entry for PR merge
2026-05-28 15:20:47 +05:30
Vincent Koc
dc5671edae fix(install): harden Windows git installs 2026-05-28 11:47:05 +02:00
Vincent Koc
f9aec04167 fix(qa): stabilize live transport lanes
Wire QA fallback models into live gateway config, fix Slack allowlist-block coverage, and keep WhatsApp live artifacts useful while redacting raw credential metadata.\n\nVerification: focused QA Vitest; autoreview clean; AWS Crabbox pnpm check:changed run_0207de7d47aa; QA-Lab branch-defined transport run 26565521272 with Matrix transport 56/56 and Slack/Discord/Telegram/parity clear. WhatsApp remains blocked by stale shared Convex WhatsApp Web credentials returning Baileys 401 before scenarios.
2026-05-28 10:38:09 +01:00
Vincent Koc
b008989bef fix(security): address OpenClaw CodeQL alerts 2026-05-28 11:34:32 +02:00
Peter Steinberger
7275304793 fix(parallels): guard release target harness mismatch 2026-05-28 10:11:40 +01:00
Peter Steinberger
9ebf51efe9 docs(skills): refine beta release announcement guidance 2026-05-28 10:11:34 +01:00
Peter Steinberger
98052028aa docs(skills): add OpenClaw release announcement guide 2026-05-28 10:11:34 +01:00
Vincent Koc
13dcded7c8 fix(release): bound cross-os fetch bodies 2026-05-28 10:38:08 +02:00
Josh Avant
4c3a0292ff Fix Claude live tool progress for watchdog recovery (#87546)
* fix: keep claude live tools fresh for watchdog

* fix: avoid claude live active tool spread
2026-05-28 01:37:40 -07:00
Peter Steinberger
bd02977e29 test: avoid platform-specific transcript stat assertion 2026-05-28 04:29:31 -04:00
Vincent Koc
9f7006407f fix(scripts): bound audit advisory error bodies 2026-05-28 10:22:44 +02:00
Peter Steinberger
b005f01c13 fix: ignore leading transcript bytes in tail scan 2026-05-28 04:20:01 -04:00
Peter Steinberger
e397636051 fix: avoid direct transcript stat fallback 2026-05-28 04:05:36 -04:00
Vincent Koc
23f494cba9 fix(scripts): bound docker preflight capture 2026-05-28 09:59:51 +02:00
Vincent Koc
744da7e6bd fix(scripts): bound gh read error bodies 2026-05-28 09:47:07 +02:00
Peter Steinberger
5da34a982b perf: avoid runtime catalog load for reasoning defaults 2026-05-28 08:43:49 +01:00
Peter Steinberger
a0cf1858a2 fix(release): pin ClawHub publish workdir 2026-05-28 08:37:06 +01:00
Peter Steinberger
8d5f6c8ae4 perf: reuse preflight transcript scan size 2026-05-28 08:31:06 +01:00
Vincent Koc
1395d71821 fix(scripts): bound labeler error bodies 2026-05-28 09:24:40 +02:00
Peter Steinberger
39bc43cb60 perf: skip recent transcript read after final usage 2026-05-28 08:19:47 +01:00
Vincent Koc
05f357b13b fix(scripts): bound memory fd ready output 2026-05-28 09:05:47 +02:00
Peter Steinberger
bd6a404aa3 perf: reuse transcript scan size 2026-05-28 07:59:25 +01:00
Vincent Koc
0ade360da5 fix(scripts): bound gateway watch log capture 2026-05-28 08:45:18 +02:00
Vincent Koc
00fb15253c fix(agents): cancel failed skill download bodies 2026-05-28 08:13:31 +02:00
Peter Steinberger
ea48ac7da8 fix(agents): suppress abandoned requester completion handoff (#87541) 2026-05-28 07:10:17 +01:00
Vincent Koc
50a708c5f9 fix(qa): keep live transport artifacts local 2026-05-28 08:04:53 +02:00
Peter Steinberger
02b1a2168c test(release): satisfy cross-os socket lint 2026-05-28 07:01:55 +01:00
Peter Steinberger
13427276b8 fix(release): speed windows upgrade fallback 2026-05-28 07:01:55 +01:00
Peter Steinberger
97717277c4 fix(release): close cross-os artifact sockets 2026-05-28 07:01:55 +01:00
Peter Steinberger
ca1829c3f4 fix(ci): bound optional performance report publishing 2026-05-28 07:01:55 +01:00
github-actions[bot]
43deaf4621 chore(ui): refresh nl control ui locale 2026-05-28 05:55:02 +00:00
github-actions[bot]
c16620cb07 chore(ui): refresh fa control ui locale 2026-05-28 05:55:00 +00:00
github-actions[bot]
55e1878e57 chore(ui): refresh vi control ui locale 2026-05-28 05:54:49 +00:00
github-actions[bot]
47c67e31ab chore(ui): refresh th control ui locale 2026-05-28 05:54:36 +00:00
github-actions[bot]
062d429d9c chore(ui): refresh pl control ui locale 2026-05-28 05:54:29 +00:00
github-actions[bot]
580e95fad1 chore(ui): refresh id control ui locale 2026-05-28 05:54:24 +00:00
github-actions[bot]
dcb00f3d8e chore(ui): refresh tr control ui locale 2026-05-28 05:54:07 +00:00
github-actions[bot]
748015b42f chore(ui): refresh uk control ui locale 2026-05-28 05:54:02 +00:00
github-actions[bot]
ae0f46927d chore(ui): refresh it control ui locale 2026-05-28 05:53:55 +00:00
github-actions[bot]
5f3012bc70 chore(ui): refresh ar control ui locale 2026-05-28 05:53:52 +00:00
github-actions[bot]
b0517f1f54 chore(ui): refresh fr control ui locale 2026-05-28 05:53:28 +00:00
github-actions[bot]
5058fc94b3 chore(ui): refresh ja-JP control ui locale 2026-05-28 05:53:26 +00:00
github-actions[bot]
d4ffac4597 chore(ui): refresh ko control ui locale 2026-05-28 05:53:24 +00:00
github-actions[bot]
384dd1216e chore(ui): refresh es control ui locale 2026-05-28 05:53:15 +00:00
github-actions[bot]
6c858ac65f chore(ui): refresh de control ui locale 2026-05-28 05:52:52 +00:00
github-actions[bot]
d3751e409f chore(ui): refresh pt-BR control ui locale 2026-05-28 05:52:50 +00:00
github-actions[bot]
831bb456f7 chore(ui): refresh zh-CN control ui locale 2026-05-28 05:52:46 +00:00
github-actions[bot]
71781b82b4 chore(ui): refresh zh-TW control ui locale 2026-05-28 05:52:43 +00:00
Dallin Romney
127c0ad418 test(cron): speed up isolated fallback tests (#87520) 2026-05-27 22:45:15 -07:00
Dallin Romney
e805ffd2eb refactor(openai): centralize codex oauth flow (#87411) 2026-05-27 22:32:08 -07:00
Dallin Romney
53704b26e8 perf(ci): instrument build artifacts phases (#87514) 2026-05-27 22:31:32 -07:00
Vincent Koc
44027e72d0 test(agents): narrow bounded error assertions 2026-05-28 07:17:21 +02:00
Vincent Koc
d1bca0c32c test(agents): prove active live subagent steering 2026-05-28 07:17:21 +02:00
joshavant
8f6a2f0f6b chore: clarify bug report issue scope 2026-05-27 22:07:44 -07:00
Josh Avant
4a45a259ec fix(agents): preserve signed thinking payloads (#87493) 2026-05-27 21:57:41 -07:00
Vincent Koc
d10d30c5fa fix(test): harden startup benchmark harness 2026-05-28 06:53:58 +02:00
Vincent Koc
4f26cc9090 fix(agents): bound minimax vlm error bodies 2026-05-28 06:50:55 +02:00
amittell
f7c32fc8be fix(telegram): lower polling keepalive delay (#83304)
* fix(telegram): enable TCP keepalive on getUpdates connections to prevent NAT timeout stalls

Long-polling connections to api.telegram.org stay idle for up to the
getUpdates timeout (~900 s). Most home/office NAT tables expire idle TCP
entries after 60–1800 s (commonly ~1000 s). When the NAT entry is
silently dropped the connection hangs rather than returning an error,
leaving the grammY runner stuck until the 90 s stall watchdog fires and
forces a restart cycle.

Fix: unconditionally set `keepAlive: true` and
`keepAliveInitialDelay: 30_000` (30 s) on the undici Agent `connect`
options built in `buildTelegramConnectOptions`. OS-level TCP keepalive
probes sent every ~75 s (OS default) will:
1. Refresh the NAT table entry before it expires.
2. Surface dead connections immediately with ETIMEDOUT instead of
   hanging forever.

The `return Object.keys(connect).length > 0 ? connect : null` guard is
also removed; `connect` is now always non-empty so it always returns the
object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 92e454c0614256201cdf6f0f73c7897d006616d4)

* fix(telegram): stop self-flagging disconnected on poll-cycle start; widen channel connect grace to 300s

(cherry picked from commit 1ca963a05dac0d9d605e9a15dc97fced9cf7725e)

* fix(telegram): catch hung polling startups that preserve inherited connected:true

The widened 300s channel connect grace and the removal of connected:false from
notePollingStart left a path where a polling restart could hang forever
looking healthy. notePollingStart clears lastConnectedAt, lastEventAt, and
lastTransportActivityAt but deliberately omits connected, so server-channels'
patch-merge inherits a connected:true from the previous lifecycle. After grace,
evaluateChannelHealth's stale-socket branch requires lastTransportActivityAt
to be non-null and the connected:false branch is masked, so the channel sits
healthy with no first getUpdates.

Add a post-grace branch to evaluateChannelHealth that flags polling channels
as stale-socket when connected:true is paired with null lastConnectedAt and
null lastTransportActivityAt and a non-null lastStartAt. Scoped to mode:polling
so webhook channels and channels without continuous transport tracking are
not falsely flagged. Align TELEGRAM_POLLING_CONNECT_GRACE_MS in the Telegram
status diagnostic with DEFAULT_CHANNEL_CONNECT_GRACE_MS so openclaw channels
status agrees with the shared health monitor on the grace window. Refresh
the notePollingStart comment to point at the new evaluateChannelHealth branch.

Addresses clawsweeper review on #83304 (P1 connect-grace startup-hang, P2
diagnostic grace drift). Tests cover the new flagged path, the in-grace happy
path, and the prior-successful-connect happy path.

* fix(telegram): clear polling connected state on startup

* fix(gateway): add defense-in-depth health-policy branch for hung polling startups

Defense in depth on top of 87db46c576's notePollingStart connected:false fix.
The primary path (notePollingStart writes connected:false explicitly so
evaluateChannelHealth's existing connected===false branch catches a hung
restart) is unchanged. This adds a defensive post-grace branch that catches
the same hang via a different signature -- inherited connected:true paired
with null lastConnectedAt and null lastTransportActivityAt -- in case a
future code path forgets to clear the inherited connected flag on lifecycle
start. Scoped to mode:polling so webhook channels and channels without
continuous transport tracking are not falsely flagged.

Also bump lastStartAt: Date.now() - 121_000 to 301_000 in the spool-handler
timeout test added by upstream #83505 so it falls past the widened 300s
TELEGRAM_POLLING_CONNECT_GRACE_MS suppression window (mirroring the same
fixup already applied to the two adjacent polling-startup tests).

* revert(telegram,gateway): keep connect grace at 120s

Drop the 120s -> 300s widening from this PR after maintainer feedback that
the extra grace masks real startup bugs. The defense-in-depth checks added
in earlier commits (notePollingStart clearing inherited connected state,
the stale-socket policy branch, the per-snapshot startup grace test) all
work fine at 120s and remain valuable on their own.

Reverts in:
- src/gateway/channel-health-policy.ts: DEFAULT_CHANNEL_CONNECT_GRACE_MS 300 -> 120
- extensions/telegram/src/status-issues.ts: TELEGRAM_POLLING_CONNECT_GRACE_MS 300 -> 120
- extensions/telegram/src/status.test.ts: lastStartAt 301_000 -> 121_000 (3 cases)

The new channel-health-policy.test.ts cases use explicit channelConnectGraceMs:
10_000 in the policy, so they are unaffected by the default constant change.

* fix(telegram): narrow polling keepalive fix

---------

Co-authored-by: Yibei Ou <yibeiou@Yibeis-Mac-mini.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-05-28 10:13:13 +05:30
Ayaan Zaidi
51d7f3c143 ci(mantis): route telegram proof runs to us-east-1 2026-05-28 10:10:32 +05:30
Vincent Koc
c841218ace fix(agents): bound native pdf error bodies 2026-05-28 06:39:55 +02:00
Dallin Romney
647e18aa04 test: deflake agent image root checks (#87499) 2026-05-27 21:32:04 -07:00
Ayaan Zaidi
771ddcf184 fix(android): trust private LAN credentials 2026-05-28 10:00:32 +05:30
Ayaan Zaidi
5f3d6cde19 fix(android): keep LAN cleartext untrusted 2026-05-28 10:00:32 +05:30
Ayaan Zaidi
633c40aa65 fix(android): preserve private LAN TLS pins 2026-05-28 10:00:32 +05:30
Ayaan Zaidi
ec3ac182c5 fix(android): allow private LAN pairing 2026-05-28 10:00:32 +05:30
Vincent Koc
6ae4a00a66 fix(qa): reject loose openwebui probe timeouts 2026-05-28 06:27:04 +02:00
Vincent Koc
a0ba9f2b72 fix(media): cancel oversized fetch responses 2026-05-28 06:20:23 +02:00
Masato Hoshino
313d6ae1b3 fix(whatsapp): strip control characters from outbound document fileName (#77114)
Merged via squash.

Prepared head SHA: 5417a8ee2c
Co-authored-by: masatohoshino <246810661+masatohoshino@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-05-28 01:17:52 -03:00
Dallin Romney
8d21ac3f6e refactor: share QA runtime helpers (#87412)
* refactor: share QA runtime helpers

* refactor: keep QA helpers private

* refactor: keep QA helpers on private runtime seam

* chore: prune stale QA duplicate ignores

* fix: align qa runtime boundary alias

* fix: avoid startup memory lint conversion
2026-05-27 21:16:24 -07:00
Vincent Koc
96b8df75d5 fix(media): cancel ignored input fetch bodies 2026-05-28 06:13:24 +02:00
Vincent Koc
6adf2340fb fix(qa): parse kitchen sink rpc guardrails strictly 2026-05-28 06:05:24 +02:00
Vincent Koc
736e04cb90 fix(media): drain ignored download responses 2026-05-28 05:53:09 +02:00
Vincent Koc
6a324f6400 fix(perf): keep abort leak thresholds active 2026-05-28 05:29:40 +02:00
Agustin Rivera
b860a0d4d0 fix: harden qqbot direct media uploads
Harden QQBot direct media URL uploads by downloading through the local SSRF guard before QQ upload, disabling redirects, bounding fetch/setup and body reads, and routing downloaded buffers through the existing one-shot/chunked size gate.

Co-authored-by: Agustin Rivera <agustin@rivera-web.com>
2026-05-28 04:21:46 +01:00
Vincent Koc
751cd0c9b8 fix(doctor): validate normalized tool schemas 2026-05-28 05:09:58 +02:00
Vincent Koc
f5e48f767f fix(perf): keep startup memory budgets active 2026-05-28 05:07:34 +02:00
Dallin Romney
d165100c93 perf(tests): refactor embedded attempt runner helpers (#87410)
* refactor: extract embedded attempt runner helpers

* fix: remove unused attempt queue type import

* fix: restore attempt helper coverage

* fix: clear attempt cleanup ci

* fix: restore model prompt transform extraction
2026-05-27 20:04:36 -07:00
Dallin Romney
5887119e8d chore: stop tracking generated diffs viewer runtime (#87405)
* chore: stop tracking generated diffs viewer runtime

* test(diffs): generate viewer runtime fixture when missing
2026-05-27 19:59:35 -07:00
Vincent Koc
bf22893cb6 fix(perf): reject loose extension memory numeric flags 2026-05-28 04:57:51 +02:00
Peter Steinberger
edd4c62da1 perf: dedupe persisted skill prompts (#87458)
* perf: dedupe persisted skills prompts

* fix: account for blobbed skill prompts

* fix: prune unreferenced skill prompt blobs

* fix: refresh skill prompt blob lifecycle

* fix: prune skill prompt blob temp files

* chore: rerun ci

* fix: keep blobbed store serialized cache

* fix: preserve blobbed store cache fast paths

* fix: protect in-flight session prompt blobs

* fix: revalidate session prompt blob cleanup

* test: avoid bundled channel load in image tool tests

* fix: revalidate session prompt blobs before commit

* fix: keep CI guard and media root tests lean
2026-05-28 03:52:03 +01:00
Vincent Koc
6fe7dddcf2 fix(qa): reject loose Docker scheduler numeric env 2026-05-28 04:48:56 +02:00
Vincent Koc
3ef34702c8 fix(qa): reject loose gateway CPU numeric flags 2026-05-28 04:38:41 +02:00
bladin
e0d003b372 fix(whatsapp): support pluginHooks.messageReceived in channel/account config schema (#86426)
Merged via squash.

Prepared head SHA: 27003a8d5a
Co-authored-by: bladin <1740879+bladin@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-05-27 23:31:47 -03:00
Peter Steinberger
2229122077 fix: keep private SDK declarations local 2026-05-28 03:28:27 +01:00
Vincent Koc
8b78ded074 test(agents): cover tool schema quarantine in turns 2026-05-28 04:26:00 +02:00
Vincent Koc
ac28c0611d fix(qa): reject loose gauntlet numeric flags 2026-05-28 04:24:13 +02:00
Dallin Romney
3005b62242 perf(plugins) refactor plugin SDK declarations for flat package types (#87165)
* refactor: flatten plugin sdk declarations

* fix: align package inventory with flat sdk declarations

* refactor: move packed sdk smoke to fixture

* test: simplify packed sdk type smoke

* fix(canvas): use focused number runtime helpers

* fix(ci): stabilize sdk boundary checks

* test: guard private sdk declaration leaks

Co-authored-by: Peter Steinberger <steipete@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 19:22:32 -07:00
Vincent Koc
b6e354f6ca fix(file-transfer): handle late tar pipe errors 2026-05-28 04:14:57 +02:00
Vincent Koc
d1577a2ff2 fix(perf): reject invalid startup bench counts 2026-05-28 03:48:55 +02:00
Andy
d2319d718c fix(status): keep default JSON scan lean
Default `openclaw status --json` stays on the lean health-probe path while preserving the JSON task summary, local update/install metadata, explicit probe timeouts, and configured gateway handshake timeouts. Deeper memory, registry, remote git, and local status-RPC diagnostics remain behind `status --json --all`.

Also keeps generated diffs viewer output in its built form and ignores it in oxfmt so `pnpm build` leaves a clean tree.

Proof:
- `node scripts/run-vitest.mjs src/commands/status.scan.fast-json.test.ts src/commands/status-json-payload.test.ts src/commands/status.scan.shared.test.ts`
- `OPENCLAW_LOCAL_CHECK=0 node scripts/run-oxlint-shards.mjs --threads=8`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub checks green for head `47a63f87ea7c2351994fdb71e8cc18041aa0b64e`

Thanks @andyylin.

Co-authored-by: Andy <andyylin@users.noreply.github.com>
2026-05-28 02:28:49 +01:00
Vincent Koc
5846878924 fix(auth): honor OAuth login cancellation 2026-05-28 03:12:40 +02:00
Vincent Koc
a20c091411 test(reply): avoid redundant settled hook return unions 2026-05-28 02:55:01 +02:00
Vincent Koc
069f33b410 test(openai): type malformed context window fixture 2026-05-28 02:55:01 +02:00
Vincent Koc
28a719f3da fix(agents): allow steering yielded subagents 2026-05-28 02:55:01 +02:00
Peter Steinberger
7c7fb7df67 chore(release): refresh plugin sdk baseline 2026-05-28 01:51:27 +01:00
Peter Steinberger
cee2a50fe6 chore(release): prepare 2026.5.28 2026-05-28 01:48:07 +01:00
Peter Steinberger
0e262d20e7 fix(discord): fence tool warning fallback delivery (#87465)
* fix(discord): fence recovered tool warning fallback

* fix(discord): keep warning fallback after failed final

* fix(reply): keep settled cleanup unconditional
2026-05-28 01:39:14 +01:00
Vincent Koc
748510b7a3 fix(doctor): validate tool schemas for configured agents 2026-05-28 02:17:43 +02:00
Peter Steinberger
45e6af5e57 fix: reject partial numeric runtime values 2026-05-27 20:10:01 -04:00
Peter Steinberger
d1aa3cb925 fix: reject partial numeric command values 2026-05-27 20:10:01 -04:00
WarrenJones
65e2120f8c fix(hooks): pass media metadata to received hook
Forward canonical inbound media metadata to plugin message_received hooks so plugins can inspect the same mediaPath, mediaUrl, mediaType, mediaPaths, mediaUrls, and mediaTypes fields already available to inbound_claim.

Verification:
- node scripts/run-vitest.mjs src/hooks/message-hook-mappers.test.ts
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main

Refs: https://github.com/openclaw/openclaw/pull/87297
Co-authored-by: WarrenJones <8704779+WarrenJones@users.noreply.github.com>
2026-05-28 01:06:00 +01:00
Martin Kessler
d00e764e66 fix(heartbeat): stop pending final replay
Stop heartbeat runs from directly returning non-ack durable pending final text. Heartbeats now only clear ack-only pending state and otherwise continue the heartbeat turn, so stale prior final answers cannot be replayed through a later heartbeat/default route.

Keep the isolated heartbeat active-run guard so an immediate/manual heartbeat cannot overwrite an isolated heartbeat session that is still running.

Proof:
- node scripts/run-vitest.mjs src/auto-reply/reply/get-reply.fast-path.test.ts src/infra/heartbeat-runner.skips-busy-session-lane.test.ts
- git diff --check
- autoreview --mode local
- autoreview --mode branch --base origin/main
- GitHub CI 26543804437, CodeQL 26543804438, Critical Quality 26543804441, OpenGrep PR Diff 26543804440 rerun job 78197443511, Real behavior proof 26544027357

Refs #74257.

Co-authored-by: kesslerio <martin@kessler.io>
2026-05-28 00:58:57 +01:00
Peter Steinberger
c86667c5cf test(discord): use reply payload SDK test helper (#87454)
* test(discord): use reply payload SDK test helper

* build(plugin-sdk): exclude reply payload test helper
2026-05-28 00:57:22 +01:00
Peter Steinberger
ff0990d800 fix: accept uncommitted autoreview mode 2026-05-28 00:55:08 +01:00
Edward Abrams
05db911775 fix(outbound): thread session keys into outbound hooks (#73706)
Thread the canonical outbound session key into plugin message_sending and message_sent hook contexts, and align native command redirect routed delivery with the agent runtime session key. This lets plugins correlate agent_end with outbound delivery hooks without seeing missing or divergent session keys.

Verification:
- gh pr checks 73706 --repo openclaw/openclaw --watch=false
- Real behavior proof: https://github.com/openclaw/openclaw/actions/runs/26526635074/job/78131933497

Thanks @zeroaltitude.

Co-authored-by: Edward Abrams <zeroaltitude@gmail.com>
2026-05-28 00:43:27 +01:00
Vincent Koc
c9151ba902 fix(provider): bound local service startup 2026-05-28 01:38:35 +02:00
Peter Steinberger
1f1cdd84ea chore: forward gateway profiling env 2026-05-28 00:35:35 +01:00
Peter Steinberger
da279041ab fix(discord): suppress recovered tool warnings (#87451) 2026-05-28 00:32:28 +01:00
Fermin Quant
3f9d2415ac fix(cron): stabilize isolated prompt cache affinity
Stabilize isolated cron prompt cache affinity by deriving a stable prompt cache key per cron job/session/model and forwarding it separately from the rotating run session id.

Thread the key through embedded runs, stream resolution, provider options, proxy forwarding, custom streams, and prompt-cache observability. Keep OpenAI-compatible payloads valid by using hyphen-safe keys, clamping upstream prompt_cache_key values, and omitting affinity when cache retention is disabled.

Thanks @ferminquant.

Co-authored-by: Fermin Quant <ferminquant@hotmail.com>
2026-05-28 00:31:19 +01:00
Alix-007
8b7a4826a1 fix(agents): keep hook context prompt-local (#86875)
Fixes embedded agent prompt handling so before_prompt_build prepend/append context stays prompt-local: visible transcripts keep the user prompt, provider/model prompts keep hook context, and runtime/system context stays separate.

Local verification:
- git diff --check
- fnm exec --using v22.22.2 pnpm exec oxfmt --check src/agents/embedded-agent-runner/tool-result-context-guard.ts src/agents/embedded-agent-runner/tool-result-context-guard.test.ts
- fnm exec --using v22.22.2 node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/agents/embedded-agent-runner/tool-result-context-guard.ts src/agents/embedded-agent-runner/tool-result-context-guard.test.ts
- fnm exec --using v22.22.2 pnpm tsgo:test:src
- autoreview clean: no accepted/actionable findings

CI verification:
- GitHub CI run 26544578760 passed on rebased head 9715d3a01a

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-05-28 00:29:31 +01:00
alkor2000
603aa8a2ed fix(doctor): rewrite non-canonical api_key auth profiles
Rewrites non-canonical api_key fields in auth-profiles.json to canonical key via openclaw doctor --fix, with backups, while preserving canonical key/keyRef credentials and active-agent auth stores.

Fixes #57389.

Co-authored-by: alkor2000 <200923177@qq.com>
2026-05-28 00:29:28 +01:00
lukeboyett
b5bd6e8828 fix(sessions): preserve Matrix room-id case in session keys (#75670) (#87366)
* fix(sessions): preserve Matrix room-id case in session keys (#75670)

Matrix room IDs (and thread event IDs) are opaque, case-sensitive per the
Matrix spec, but session-key canonicalization lowercased them. That forked
one room into duplicate sessions and produced 403 M_FORBIDDEN on recovery /
delivery paths that reconstruct the target from the (lowercased) session key,
even though deliveryContext.to stayed correct.

Introduce a generic, opt-in case-preservation registry (CASE_PRESERVING_PEERS)
consulted at all three lowercasing sites:
- construction: normalizeSessionPeerId
- store canonicalization: normalizeSessionKeyPreservingOpaquePeerIds
- gateway send: explicit request.sessionKey

Signal group preservation is encoded to match prior behavior exactly (segment
span, unscoped, thread suffix still lowercased). Matrix channel/group enrolls
the opaque tail (room id with embedded :server + any 🧵<event> suffix).
Exact mixed-case keys now win over folded legacy aliases in
resolveSessionStoreEntry and delivery-info lookup; existing lowercased rows
collapse on the next write. Matrix DM/MXID and non-enrolled channels keep the
default lowercase behavior.

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

* fix(sessions): guard Matrix folded alias delivery proof

* test(agents): cover cold OpenAI gpt-5.5 fallback

* fix(sessions): preserve non-opaque alias freshness

* fix(sessions): prevent Matrix cross-room thread recovery

* build(protocol): refresh tools effective Swift models

* test(codex): include effective cwd in startup fixture

* test(codex): align startup failure cleanup expectation

* fix(sessions): keep Signal folded aliases fresh

* fix(sessions): preserve unscoped Matrix room keys

* fix(sessions): recover legacy Matrix thread aliases

* fix(sessions): preserve Matrix keys in state migrations

* fix(sessions): keep Matrix structural alias freshness

* fix(sessions): preserve unscoped Matrix migration keys

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-28 00:26:49 +01:00
Vincent Koc
92043f7547 test(gateway): retry live exec read probe wording 2026-05-28 01:20:56 +02:00
Peter Steinberger
59c3ee7c45 fix(imessage): continue polling after denied reactions
(cherry picked from commit 6cc534af9b859301f9ff814bdd8672fa910141e3)
2026-05-28 00:17:52 +01:00
Chunyue Wang
65fb56513f fix(agents): release session lock on timeout abort
Fixes #86816.

Co-authored-by: Chunyue Wang <16864032@qq.com>
2026-05-28 00:16:40 +01:00
Vincent Koc
c20a055341 fix(provider): honor Codex response timeouts 2026-05-28 01:03:21 +02:00
Vincent Koc
da5fe990d8 fix(codex): report quarantined dynamic tools 2026-05-28 00:56:30 +02:00
Kevin Lin
40bca6d8bb fix(imessage): suppress duplicate native exec approvals
Fix iMessage native exec approval routing so approval prompts bind to the sent GUID without duplicate sends after RPC timeout. Also keeps chat.db GUID recovery on the local imsg path while avoiding local DB recovery for configured or detected SSH wrappers.

Thanks @kevinslin.
2026-05-27 23:55:28 +01:00
Andy Ye
d8641a661b fix(sessions): avoid stale restart continuation reuse
Avoid stale restart continuation reuse after a session key has rotated.

Queued restart agent turns now carry the session id they were queued for and fall back to a system wake if the key points at a different session by delivery time. Normal completed-run lifecycle fields stay reusable for fresh sessions, while new-session creation clears stale lifecycle markers.

Closes #86593.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-27 23:55:24 +01:00
Andy Ye
cc72519053 fix(gateway): drain probe client close
Closes #87210.

Gateway probe now waits for GatewayClient.stopAndWait() before resolving so callers do not observe a successful probe while the client socket is still draining. If the drain fails, probe falls back to stop().

Adds mocked probe coverage plus a real WebSocket regression test that verifies no client socket handle remains when probeGateway() resolves.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-27 23:55:14 +01:00
Peter Steinberger
550a9b459a test(ci): bound image tool iMessage fixtures 2026-05-27 18:50:49 -04:00
simplyclever914
169effacc2 feat(status): show active subagent details
Show active subagent detail rows in /status with labels and elapsed runtime while keeping completed-subagent summary behavior. Thanks @simplyclever914.
2026-05-27 23:49:46 +01:00
Sarah Fortune
6ac3561c69 fix(codex): format skills command output (#87400) 2026-05-27 15:43:05 -07:00
Paul Frederiksen
77fe36bb98 Improve stale Codex auth recovery guidance
Fixes #83935.

Summary:
- clear stale legacy openai-codex auto route pins only when the canonical OpenAI provider is still using the Codex harness for the same model
- preserve usable Codex auth profiles while clearing stale route state
- keep explicit/custom OpenAI API route pins intact

Verification:
- git diff --check
- pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/model-selection.ts src/auto-reply/reply/model-selection.test.ts src/auto-reply/reply/agent-runner-execution.ts src/auto-reply/reply/agent-runner-execution.test.ts
- fnm exec --using 24.15.0 node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
- .agents/skills/autoreview/scripts/autoreview --mode local
- CI: https://github.com/openclaw/openclaw/actions/runs/26542490863

Co-authored-by: Paul Frederiksen <paul@paulfrederiksen.com>
2026-05-27 23:35:48 +01:00
samzong
316fd5b625 [Fix] Warm provider auth off main thread (#86281)
* fix(agents): warm provider auth off main thread

Signed-off-by: samzong <samzong.lu@gmail.com>

* fix(agents): keep provider auth warm read-only

* fix(ci): unblock provider auth landing

* ci: serialize gateway watch artifact check

* fix(ci): stabilize diffs viewer asset generation

* fix(agents): avoid stale plugin auth warm results

* fix(agents): keep partial auth warm cache

---------

Signed-off-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 23:24:55 +01:00
Peter Steinberger
5cef288d65 fix(agents): resolve Codex runtime models first
* fix(agents): resolve Codex runtime models first

* test(agents): align Codex runtime resolution fixtures
2026-05-27 23:23:22 +01:00
Gio Della-Libera
f3e285126a fix(doctor): make restart follow-up actionable (#87361) 2026-05-27 23:23:19 +01:00
Vincent Koc
53ad531df9 fix(crabbox): preserve sparse run artifacts 2026-05-28 00:20:39 +02:00
Peter Steinberger
78c5eeab01 docs(changelog): require contributor thanks 2026-05-27 23:20:03 +01:00
Peter Steinberger
5d437de70f fix(web-search): preserve runtime-only provider config
Fixes #87191. Keeps Brave and Gemini runtime-injected web search provider config readable by providers without re-exposing legacy tools.web.search provider objects to config validation.
2026-05-27 23:17:07 +01:00
xiaotian
fb1dfd486b fix(slack): retain delivered final replies during late cleanup
Fix Slack draft cleanup after final-visible delivery.

Track when Slack has already delivered a visible final reply and stop reusing the draft finalizer for later same-turn final/error payloads. This keeps the first fallback cleanup for transient previews while preventing late cleanup from deleting a visible answer.

Fixes #87363

Co-authored-by: tianxiaochannel-oss88 <tianxiaochannel@gmail.com>
2026-05-27 23:16:17 +01:00
Peter Steinberger
cf47580a45 test(ci): align startup and model fixtures 2026-05-27 18:09:03 -04:00
Peter Steinberger
efbd00f282 fix: preserve retry-after fallback 2026-05-27 18:03:13 -04:00
Peter Steinberger
f24844d801 fix: reject partial numeric parsing 2026-05-27 18:00:19 -04:00
Peter Steinberger
db549137d3 fix(agents): bound compaction wake retry timeouts 2026-05-27 22:57:51 +01:00
alkor2000
ea2e9ce8bd fix(agents): clamp compaction steer retry wait to remaining delivery window
The compaction retry loop checked the delivery-timeout deadline before
choosing a fixed backoff delay, then slept that whole delay. When the
remaining window was shorter than the next backoff entry, the final
retry could sleep past the deadline, overrunning the delivery timeout
the retry is meant to stay within. Clamp the wait to the remaining
window (min(scheduledDelay, deadline - now)) and stop retrying once no
time remains, so compaction waiting never exceeds the delivery timeout.

Addresses the near-deadline overrun raised in ClawSweeper review of #86606.
2026-05-27 22:57:51 +01:00
alkor2000
a7b8e6a5a9 fix(agents): wait for compaction before requester steering fallback
Follow-up to #85489. Active requester steering treated a `compacting`
outcome from queueEmbeddedPiMessageWithOutcome as a terminal wake
failure and fell through to the requester-agent/direct fallback, even
though the active run becomes steerable again as soon as compaction
finishes.

Introduce a shared resolveActiveWakeWithRetries helper used by both the
steer path (maybeSteerSubagentAnnounce) and the generated-completion
active wake (sendSubagentAnnounceDirectly). The helper treats
`compacting` as transient and waits through compaction, retrying the
same wake. Waiting is bounded by the active wake's delivery timeout (not
just the backoff schedule): the backoff schedule controls the gap
between attempts, and once it is exhausted its last delay is reused until
the delivery deadline, so a compaction that finishes after the schedule
but within the delivery timeout still re-steers. The best-effort
transcript-commit retry and the compaction retry share one loop, so a
run that compacts and then reports transcript_commit_wait_unsupported
still gets the best-effort retry. Other wake failures keep their
existing single-attempt fallback.

Fixes #86566
2026-05-27 22:57:51 +01:00
Mariano
7299c56953 Fix sub-agent cwd/workspace separation (#87218)
Merged via squash.

Prepared head SHA: f47b073830
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-05-27 23:55:24 +02:00
martingarramon
039fcbaa4c fix(agent-job): preserve grace for pending error diagnostics
Preserve pending agent-job error diagnostics as non-terminal timeout snapshots so the retry grace path can still recover when the lifecycle later starts and completes.

Local proof:
- node scripts/run-vitest.mjs packages/sdk/src/index.test.ts src/gateway/server-methods/server-methods.test.ts src/gateway/server.chat.gateway-server-chat.test.ts src/agents/run-wait.test.ts src/agents/openclaw-tools.sessions.test.ts
- node scripts/run-oxlint.mjs packages/sdk/src/client.ts packages/sdk/src/index.test.ts src/gateway/server-methods/agent-job.ts src/gateway/server-methods/agent.ts src/gateway/server-methods/agent-wait-dedupe.ts src/agents/run-wait.ts src/agents/tools/sessions-send-tool.ts src/gateway/server-methods/server-methods.test.ts src/gateway/server.chat.gateway-server-chat.test.ts src/agents/run-wait.test.ts src/agents/openclaw-tools.sessions.test.ts
- autoreview --mode local: no accepted/actionable findings
- CI run 26536599850: success

Co-authored-by: Martin Garramon <martin@yulicreative.ai>
2026-05-27 22:51:11 +01:00
Kevin Lin
bb752c2b47 Revert "feat: expose plugin approval action metadata" (#87419)
This reverts commit 0c867eef75.

# Conflicts:
#	docs/.generated/plugin-sdk-api-baseline.sha256
2026-05-27 14:48:06 -07:00
Vincent Koc
dfcf211232 test(agents): clarify live subagent steering prompt 2026-05-27 23:45:35 +02:00
Vincent Koc
5ad8036bda test(openai): stabilize live audio transcription 2026-05-27 23:45:35 +02:00
Vincent Koc
7b967c5701 fix(oauth): bound GitHub Copilot requests 2026-05-27 23:27:27 +02:00
Patrick Erichsen
b4e5038692 fix(cli): respect subcommand version options (#87398)
* fix(cli): respect subcommand version options

* test: stabilize model directive auth status
2026-05-27 16:26:11 -05:00
Vincent Koc
67277088eb fix(oauth): bound Codex token requests 2026-05-27 23:20:15 +02:00
Peter Steinberger
5f68291f4f fix(agents): move session write lock into owned session runtime (#87409)
* fix(agents): move session write lock into owned session runtime

* test(agents): use typed tool-call fixtures
2026-05-27 22:17:35 +01:00
Vincent Koc
21d9609866 fix(gateway): quarantine unsupported effective tool schemas 2026-05-27 23:15:24 +02:00
Mariano Belinky
a7d2d9c6df fix: migrate legacy memory auto provider 2026-05-27 23:03:32 +02:00
Vincent Koc
09d2682cd8 fix(openai): resolve gpt-5.5 without cached catalog 2026-05-27 22:57:30 +02:00
Vincent Koc
00004ca798 fix(cli): wait for respawn child shutdown 2026-05-27 22:57:30 +02:00
Peter Steinberger
7f7eca1ad2 fix(codex): preserve shared app-server after startup app errors (#87399)
* fix(codex): preserve shared app-server after startup app errors

* fix(codex): align startup cleanup tests with current types

* test(config): isolate installed plugin ledger cache
2026-05-27 21:50:41 +01:00
Dallin Romney
87944c0d80 chore(ui): mark generated locale artifacts (#87406) 2026-05-27 13:48:21 -07:00
Vincent Koc
f39f1a4712 fix(e2e): bound MCP channel harness buffers 2026-05-27 22:34:08 +02:00
Vincent Koc
1eb27da55d fix(testing): bound openclaw instance logs 2026-05-27 22:29:36 +02:00
Peter Steinberger
9ff071f646 test(config): clear install record cache in validation fixture 2026-05-27 16:23:01 -04:00
GarlicGo
2900c1c25c fix(inbound-meta): include seconds in timestamps
Include second-level precision in inbound metadata and auto-reply envelope timestamps, matching the timestamp helper contract used by providers and channel adapters.

Docs now show the weekday plus seconds form in date-time and timezone examples.

Verification:
- node scripts/run-vitest.mjs src/auto-reply/envelope.test.ts src/auto-reply/reply/inbound-meta.test.ts
- pnpm docs:list >/tmp/openclaw-docs-list-87360.log
- git diff --check origin/main...HEAD
- pnpm format:docs:check
- pnpm lint:docs
- pnpm lint:extensions:bundled
- pnpm lint
- PR CI green on 495bb6c10f

Fixes #87257

Co-authored-by: GarlicGo <582149912@qq.com>
2026-05-27 21:18:08 +01:00
Alix-007
f4329fe0d6 fix(agents): bound plugin system context
* fix(agents): bound plugin system context

* test(agents): align wrapped system context expectations

* style(agents): format hook context helper

* test(codex): expect plugin system context boundary

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 21:16:15 +01:00
Peter Steinberger
b257b988a1 perf(plugins): trust install records cache between reloads 2026-05-27 21:13:39 +01:00
Pavan Kumar Gondhi
c923b07784 fix(gateway): expire browser tokens after auth rotation
Expire browser-origin Control UI/WebChat device tokens when shared gateway auth rotates by tagging those tokens with the shared-auth generation and enforcing it during verification.

Preserve the issuer tag when a shared-auth-derived device token reconnects through a non-browser client, so reconnect rotation cannot turn it into an untagged long-lived token.

Proof:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/gateway/server.shared-auth-rotation.test.ts src/infra/device-pairing.test.ts src/gateway/control-ui.http.test.ts
- GitHub CI run 26535632102: relevant build/runtime/test-type checks green; inherited lint reds match origin/main.
- GitHub CodeQL Critical Quality run 26535631610: network-runtime-boundary green.

Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
2026-05-27 21:13:20 +01:00
Vincent Koc
d9051151d7 fix(gateway): scope assistant idempotency dedupe 2026-05-27 22:09:31 +02:00
Vincent Koc
4ff944c0e8 fix(ci): stabilize model picker and release checks 2026-05-27 22:05:38 +02:00
Peter Steinberger
171675b54b docs: clarify backport target 2026-05-27 21:05:25 +01:00
Peter Steinberger
d30ba7f961 fix(ci): satisfy codex extension lint 2026-05-27 16:05:06 -04:00
Dallin Romney
cc2948d1e1 fix(codex): narrow legacy hook generation grace (#87386) 2026-05-27 13:01:44 -07:00
Peter Steinberger
4da2b5f4d9 perf(config): prefer native JSON parsing 2026-05-27 20:56:58 +01:00
Peter Steinberger
c71c49c460 fix(ci): address lint and test type failures 2026-05-27 15:56:12 -04:00
Sebastien Tardif
60e8e60306 fix(tool-search): reuse unchanged catalogs
Fixes repeated Tool Search catalog registration for unchanged effective tool sets by reusing a fingerprinted catalog snapshot across embedded-agent run cleanup.

The reusable catalog is guarded by catalog-affecting fields, parameters, and executable identity, and reuse now rebinds the current run/session refs before returning. Embedded-agent prep logging only suppresses the catalog line when reuse actually happened.

Verification:
- pnpm test src/agents/tool-search.test.ts -- --reporter=verbose
- pnpm check:changed, Testbox tbx_01ksney4f00wgk9n39yv7jsh4m
- Real behavior proof, GitHub Actions run 26534896284
- CI rerun for unrelated model-picker timeout passed, GitHub Actions run 26534489215
- autoreview clean: no accepted/actionable findings

Closes #86887
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-27 20:56:06 +01:00
Peter Steinberger
d93524d1cc fix(codex): route workspace memory through tools (#87383)
* fix(codex): route workspace memory through tools

* fix(codex): preserve extra memory bootstrap files

* fix(codex): support memory_get-only context routing

* fix(codex): only tool-route canonical workspace memory

* fix(codex): keep memory fallback for sandbox workspaces
2026-05-27 20:55:27 +01:00
Yuval Dinodia
74f9d6b96d fix(codex): preserve shared app-server when spawned helper run fails logically (#72574) (#87375)
* fix(codex): preserve shared app-server when spawned helper run fails logically

* fix(codex): widen spawnedBy param to match EmbeddedRunAttemptParams

* fix(codex): align spawnedBy startup typing

* fix(codex): retire shared client on spawned startup timeout

* fix(codex): narrow spawned thread-start preservation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 20:48:18 +01:00
Peter Steinberger
15b1e99df3 perf(sessions): add precomputed patch writer 2026-05-27 20:45:27 +01:00
Peter Steinberger
26a8432ee1 fix(ci): align release and image tests 2026-05-27 15:44:56 -04:00
Peter Steinberger
94749b0a45 fix(cli): reject malformed numeric inputs 2026-05-27 15:43:12 -04:00
狼哥
b789e71e57 fix(agents): avoid session event queue self-wait (#86123)
Avoids a self-wait in embedded agent session event hooks by skipping the queue drain only for hooks running inside the current session event processing chain. Detached or external hook work still drains the queue before taking the session write lock.

Verification:
- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents-embedded-agent.config.ts src/agents/embedded-agent-runner/run/attempt.session-lock.test.ts
- node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/agents/embedded-agent-runner/run/attempt.session-lock.test.ts src/agents/embedded-agent-runner/run/attempt.session-lock.ts --threads=8
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI: https://github.com/openclaw/openclaw/actions/runs/26533883763

Thanks @luoyanglang.

Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
2026-05-27 20:38:01 +01:00
keshavbotagent
e339586750 fix(plugin-state): evict current namespace on plugin row cap
Make plugin-state enforce the plugin-wide live-row fuse by evicting only from the namespace currently being written, preserving sibling namespace rows and still failing atomically when the current namespace cannot free enough rows.

Raise the plugin-wide cap to 6,000 rows, keep Telegram's persistent message-cache namespace at 3,000 entries, and document the updated SDK runtime contract. Harden legacy plugin-state import so capacity pressure cannot archive a source after losing imported keys, with focused regression coverage for Telegram-shaped namespaces and migration rollback.

Also restore the Docker runtime-assets preflight step in full release validation so release workflow contract tests stay aligned.

Verification: focused plugin-state, migration, Telegram, workflow-contract, lint, deprecated-API, diff-check, Blacksmith Testbox, CI, CodeQL, Workflow Sanity, OpenGrep, and autoreview all passed on PR head fee021cfa6.

Co-authored-by: Keshav's Bot <keshavbotagent@gmail.com>
2026-05-27 20:33:40 +01:00
Shubhankar Tripathy
90f30075aa fix(channels): preserve Telegram SecretRef prompt config
Use read-only Telegram account inspection for prompt-time channel actions, inline buttons, and reaction guidance so unresolved SecretRef tokens retain configured non-secret behavior before runtime snapshot hydration.

Match runtime Telegram account lookup for normalized config keys and multi-account fallback guards, while keeping sends/actions on the existing strict credential resolution path.

Fixes #75433.

Co-authored-by: Shubhankar Tripathy <reach2shubhankar@gmail.com>
2026-05-27 20:25:41 +01:00
Patrick Erichsen
ee57f341f0 Add ClawHub skill verification and trust surfaces (#86699)
* feat(skills): fetch ClawHub skill verification

* feat(skills): resolve ClawHub verification targets

* feat(skills): add ClawHub verify command

* docs(skills): document ClawHub verification

* test(skills): type verify CLI fixture

* fix(skills): fetch verified skill card URL

* fix(skills): bound verified card downloads

* fix(skills): fail closed on malformed verification

* fix(skills): corroborate ClawHub install origins

* feat(skills): surface ClawHub trust in control UI

* chore(protocol): refresh generated gateway models

* chore(ui): refresh i18n raw copy baseline

* docs: clarify skills verify wording

* fix: fail closed on skill trust mismatches

* fix: reject incomplete clawhub provenance

* fix: satisfy trust verdict lint

* fix: restore ci checks after main merge
2026-05-27 14:23:24 -05:00
Peter Steinberger
431eb9cda4 perf(sessions): skip unchanged store serialization 2026-05-27 20:22:22 +01:00
Vincent Koc
bde1bad2c1 fix(gateway): bound webchat image data scans 2026-05-27 21:00:38 +02:00
Peter Steinberger
2f710f5604 fix(ci): avoid deprecated sdk import in canvas cli 2026-05-27 14:57:00 -04:00
Alex Knight
42e9504114 fix(codex): preserve native hook relay across restarts
Fixes #87331.\n\nPersist Codex native hook relay generations for real app-server resumes, keep a bounded legacy-binding grace path, and rotate generation on fresh-thread fallback so stale hook commands stay rejected.\n\nCo-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
2026-05-27 19:55:19 +01:00
Peter Steinberger
6727985365 docs: add macOS gateway sleep troubleshooting
Refs: #87337
Co-authored-by: Arunjeet Singh <arunjeetsingh@gmail.com>
2026-05-27 19:52:56 +01:00
Peter Steinberger
da1a3434f4 docs: document native Codex hook relay recovery 2026-05-27 19:46:56 +01:00
Vincent Koc
fdbf3cf4e7 fix(qa): make matrix block streaming deterministic 2026-05-27 20:43:33 +02:00
Peter Steinberger
9755241b56 fix(cli): reject partial numeric options 2026-05-27 14:36:07 -04:00
Peter Steinberger
163df2578b fix(diffs): use root viewer runtime builder 2026-05-27 14:36:07 -04:00
Peter Steinberger
0f5ea87244 fix(cli): reject partial numeric options 2026-05-27 14:36:06 -04:00
Vincent Koc
ac176d496b fix(gateway): bound artifact transcript scans 2026-05-27 20:32:54 +02:00
Peter Steinberger
bb46b79d3c refactor: internalize OpenClaw agent runtime (#85341)
* refactor: extract agent core package

Introduce packages/agent-core as the OpenClaw-owned home for reusable agent loop, harness, session, prompt, and runtime dependency contracts.

* refactor: extract shared llm runtime

Move provider model registries, stream wrappers, OAuth helpers, and LLM utilities into src/llm with plugin-sdk barrels instead of depending on the old embedded runtime layout.

* refactor: remove pi runtime internals

Rename remaining Pi-shaped agent surfaces to OpenClaw agent runtime names, delete obsolete Pi docs and package graph checks, and add the third-party notice for incorporated code.

* refactor: tighten agent session runtime

Make agent-core/runtime dependencies explicit, consolidate compaction and session transcript helpers, and move model/session helpers behind OpenClaw-owned contracts.

* refactor: remove static model and pi auth paths

Drop static model catalogs and Pi auth bridges, move model/provider facts to manifest-owned runtime contracts, and harden internal embedded-agent utilities.

* refactor: remove legacy provider compat paths

* docs: remove agent parity notes

* fix: skip provider wildcard metadata parsing

* refactor: share session extension sdk loading

* refactor: inline acpx proxy error formatter

* refactor: fold edit recovery into edit tool

* fix: accept extension batch separator

* test: align startup provider plugin expectations

* fix: restore provider-scoped release discovery

* test: align static asset packaging expectations

* fix: run static provider catalogs during scoped discovery

* fix: add provider entry catalogs for scoped live discovery

* fix: load lightweight provider catalog entries

* fix: refresh provider-scoped plugin metadata

* fix: keep provider catalog entries on release live path

* fix: keep static manifest models in release live checks

* fix: harden release model discovery

* fix: reduce OpenAI live cache probe reasoning

* fix: disable OpenAI cache probe reasoning

* ci: extend OpenAI gateway live timeout

* fix: extend live gateway model budget

* fix: stabilize release validation regressions

* fix: honor provider aliases in model rows

* fix: stabilize release validation lanes

* fix: stabilize release memory qa

* ci: stabilize release validation lanes

* ci: prefer ipv4 for live docker node calls

* fix: restore shared tool-call stream wrapper

* ci: remove legacy pi test shard alias

* fix: clean up embedded agent test drift

* fix: stabilize runtime alias status

* fix: clean up embedded agent ci drift

* fix: restore release ci invariants

* fix: clean up post-rebase runtime drift

* fix: restore release ci checks

* fix: restore release ci after rebase

* fix: remove stale pi runtime path

* test: align compaction runtime expectations

* test: update plugin prerelease expectations

* fix: handle claude live tool approvals

* fix: stabilize release validation gates

* fix: finish agent runtime import

* test: finish post-rebase agent runtime mocks

* fix: keep codex compaction native

* fix: stabilize codex app-server hook tests

* test: isolate codex diagnostic active run

* test: remove codex diagnostic completion race

# Conflicts:
#	extensions/codex/src/app-server/run-attempt.test.ts

* ci: fix full release manifest performance run id

* refactor: narrow llm plugin sdk boundary

* chore: drop generated google boundary stamps

* fix: repair rebase fallout

* fix: clean up rebased runtime references

* fix: decode codex jwt payloads as base64url

* fix: preserve shipped pi runtime alias

* fix: add scoped sdk virtual modules

* fix: decode llm codex oauth jwt as base64url

* fix: avoid stale vertex adc negative cache

* fix: harden tool arg decoding and codeql path

* fix: keep vertex adc negative checks live

* refactor: consolidate codex jwt and edit helpers

* fix: await codex oauth node runtime imports

* fix: preserve sdk tool and notice contracts

* fix: preserve shipped compat config boundaries

* fix: align codex oauth callback host

* fix: terminate agent-core loop streams on failure

* fix: keep codex oauth callback alive during fallback

* ci: include session tools in critical codeql scans

* fix: keep Cloudflare Anthropic provider auth header

* docs: redirect legacy pi runtime pages

* fix: honor bundled web provider compat discovery

* fix: protect session output spill files

* fix: keep legacy agent dir env blocked

* fix: contain auto-discovered skill symlinks

* fix: harden agent core sdk proxy surfaces

* fix: restore approval reaction sdk compat

* fix: keep live docker runs bounded

* fix: keep codex oauth redirect host aligned

* fix: resolve post-rebase agent runtime drift

* fix: redact anthropic oauth parse failures

* fix: preserve responses strict tool shaping

* fix: repair agent runtime rebase cleanup

* docs: redirect retired parity pages

* fix: bound auto-discovered resources to roots

* fix: repair post-rebase agent test drift

* fix: preserve bundled provider allowlist migration

* fix: preserve manifest-owned provider aliases

* fix: declare photon image dependency

* fix: keep provider headers out of proxy body

* fix: preserve shipped env aliases

* fix: refresh control ui i18n generated state

* fix: quote read fallback paths

* fix: preview edits through configured backend

* test: satisfy core test typecheck

* fix: preserve ZAI usage auth fallback

* test: repair codex diagnostic test

* fix: repair agent runtime rebase drift

* test: finish embedded runner import rename

* fix: repair agent runtime rebase integrations

* test: align compaction oauth fallback expectations

* fix: allow sdk-auth session models

* fix: update doctor tool schema import

* fix: preserve bedrock plugin region

* fix: stream harmony-like prose immediately

* ci: include session runtime in codeql shards

* fix: repair latest rebase integrations

* fix: honor explicit codex websocket transport

* fix: keep openai-compatible credentials provider-scoped

* fix: refresh sdk api baseline after rebase

* fix: route cli runtime aliases through openclaw harness

* test: rename stale harness mock expectation

* test: rename embedded agent overflow calls

* test: clean embedded auth test wording

* test: use openclaw stream types in deepinfra cache test

* fix: refresh sdk api baseline on latest main

* fix: honor bundled discovery compat allowlists

* fix: refresh sdk api baseline after latest rebase

* fix: remove stale rebase imports

* test: rename stale model catalog mock

* test: mock renamed doctor runtime modules

* fix: map canonical kimi env auth

* fix: use internal model registry in bench script

* fix: migrate deepinfra provider catalog entry

* fix: enforce builtin tool suppression

* fix: route compaction auth and proxy payloads safely

* refactor: prune unused llm registry leftovers

* test: update codex hooks session import

* test: fix model picker ci coverage

* test: align model picker auth mock types
2026-05-27 19:24:04 +01:00
Peter Steinberger
99b27cde64 perf(sessions): reduce store clone allocations 2026-05-27 19:20:17 +01:00
Peter Steinberger
f40275ce26 test(agents): make live subagent steering explicit 2026-05-27 14:17:22 -04:00
Peter Steinberger
dfe49ae2f4 test(matrix): quarantine live block-streaming scenario 2026-05-27 14:15:49 -04:00
Dallin Romney
cff8e4383c expand default diffs languages (#87372) 2026-05-27 11:14:16 -07:00
Dallin Romney
2c95752c1e fix(diffs): align language pack host floor (#87370) 2026-05-27 11:13:50 -07:00
Vincent Koc
140cede2e2 fix(qa): make matrix block streaming deterministic 2026-05-27 20:11:37 +02:00
Peter Steinberger
c0f16460d7 ci(release): smoke Docker runtime templates in full validation 2026-05-27 19:08:56 +01:00
Vincent Koc
11ca150a1b fix(testing): bound plugin gauntlet relay logs 2026-05-27 20:04:56 +02:00
Peter Steinberger
a4d33fd81b docs: clarify container model auth 2026-05-27 19:04:04 +01:00
Peter Steinberger
b01c6d4eaa test(matrix): force block-streaming marker separation 2026-05-27 13:58:42 -04:00
Peter Steinberger
97eba607b5 perf(gateway): skip concrete jiti alias rewrites 2026-05-27 18:58:12 +01:00
Peter Steinberger
659b5dce79 fix(docker): package runtime workspace templates 2026-05-27 18:54:22 +01:00
Vincent Koc
8e8445905f fix(release): stream cross-os served artifacts 2026-05-27 19:51:51 +02:00
Agustin Rivera
62550710bf fix(msteams): block untrusted Teams service URLs (#87334) 2026-05-27 10:48:39 -07:00
Andi Liao
085228c961 fix(auth): document paste-token stdin setup (#63050)
Document that automation should pipe `models auth paste-token` credentials over stdin instead of passing token material in argv, keeping the existing secret-handling path explicit in the CLI docs.

Also include accepted auth-profile credential types in invalid-profile warning logs so malformed local auth stores are easier to repair.

Fixes #63042.

Thanks @liaoandi.
2026-05-27 18:44:44 +01:00
Shadow
1806b152a9 fix: add ClawHub plugin display names (#87354) 2026-05-27 12:37:35 -05:00
Vincent Koc
c571652487 fix(e2e): stream live plugin transcripts 2026-05-27 19:36:43 +02:00
Peter Steinberger
c3b7e91f26 docs: clarify device token admin gate 2026-05-27 18:35:27 +01:00
Ben Badejo
7691a8a9a3 docs(codex): clarify computer use setup (#87313)
Clarify the Codex Computer Use docs around inferred opt-in, read-only status checks, and marketplace root versus marketplace JSON path setup.

The docs now match current source-backed behavior: autoInstall opts Computer Use in, status does not mutate plugin setup, and marketplacePath is for a local marketplace JSON file while source registers a marketplace root.

Verification:
- pnpm docs:list
- GitHub CI check-docs passed
- Real behavior proof passed via maintainer proof override for this docs-only PR

Thanks @bdjben.

Co-authored-by: Benjamin Badejo <ben@benbadejo.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
2026-05-27 18:35:21 +01:00
Peter Steinberger
fe91ada730 fix: reflect lazy plugin runtime surfaces 2026-05-27 18:35:04 +01:00
Peter Steinberger
1577e8f10e fix(diffs): avoid extension build-script boundary import 2026-05-27 13:33:58 -04:00
Peter Steinberger
05b23e9b7e refactor(codex): extract app-server notification state 2026-05-27 18:31:06 +01:00
Vincent Koc
b182b71d74 fix(e2e): align prerelease and google live guards 2026-05-27 19:30:27 +02:00
Peter Steinberger
04880ab250 fix(gateway): avoid viewer asset watch loops 2026-05-27 18:29:42 +01:00
Vincent Koc
e93cf52782 fix(e2e): stream release scenario log checks 2026-05-27 19:23:11 +02:00
Peter Steinberger
f80f47d408 fix(status): show configured fast-status channels 2026-05-27 13:22:03 -04:00
Vincent Koc
32d9caf662 test(matrix): clarify block streaming QA prompt 2026-05-27 19:14:54 +02:00
Peter Steinberger
d84cbfa50e perf(gateway): cache manifest model catalog rows 2026-05-27 18:12:47 +01:00
Peter Steinberger
a4c2e7f5cf refactor(codex): split app-server attempt seams 2026-05-27 18:11:16 +01:00
Vincent Koc
1a34c4833e fix(e2e): stream OpenAI web search request logs 2026-05-27 19:09:32 +02:00
Dallin Romney
d638611684 feat: split diffs language pack
Split the diffs viewer Shiki language pack into an external publishable plugin.

The diffs plugin keeps the default curated syntax set, while the new @openclaw/diffs-language-pack package carries the extended Shiki languages for npm and ClawHub distribution. The install metadata includes the external ClawHub spec, and the curated C# alias set keeps both c# and cs supported without the language pack.

Co-authored-by: Dallin Romney <dallinromney@gmail.com>
2026-05-27 18:08:40 +01:00
Peter Steinberger
5f7e21e26a fix(cli): reject malformed timeout values 2026-05-27 13:06:17 -04:00
Peter Steinberger
de5971eedc fix(onboard): preserve rerun config migrations
Fix non-interactive and wizard onboarding reruns so existing agent lists and bindings are preserved unless the user explicitly resets config.

Isolate legacy `plugins.installs` migration into its own write so the config size-drop allowance cannot mask unrelated config loss, while preserving new or repaired install records for the final plugin-index commit. Also keep shrinkwrap generation pinned to pnpm-locked transitive patch versions only when the dependency edge still allows that version, and isolate the tooling Vitest shard that mutates process state.

Fixes #84692.
Replaces #84748.

Co-authored-by: yetval <yetvald@gmail.com>
2026-05-27 18:05:07 +01:00
Vincent Koc
11dfef201f fix(e2e): keep doctor loader mock current 2026-05-27 18:57:13 +02:00
Shadow
930d9f63ad docs: expand install deployment cards 2026-05-27 11:54:12 -05:00
Vincent Koc
5c20ff93e0 fix(e2e): isolate kitchen sink log scans 2026-05-27 18:45:11 +02:00
Peter Steinberger
ca7b6be7cf perf(gateway): cache auto-enabled plugin config 2026-05-27 17:42:34 +01:00
Vincent Koc
c285766d62 fix(ci): merge nested shrinkwrap override pins 2026-05-27 18:37:00 +02:00
Vincent Koc
8ee767baa7 fix(ci): pin aged lru cache lock entry 2026-05-27 18:17:09 +02:00
Vincent Koc
d2a1f62d23 fix(matrix): keep fallback tool warnings mention-inert 2026-05-27 18:07:24 +02:00
Vincent Koc
98a9a523e6 fix(ci): preserve forked shrinkwrap pins 2026-05-27 18:07:24 +02:00
Vincent Koc
162a79b170 fix(e2e): bound agent turn assertion logs 2026-05-27 18:04:43 +02:00
Peter Steinberger
97a8c09b0a perf(gateway): slim current metadata identity cache 2026-05-27 16:54:57 +01:00
Peter Steinberger
7aaca4a8a6 chore(release): prepare 2026.5.27 2026-05-27 16:53:50 +01:00
Vincent Koc
46f5905498 fix(e2e): zero log tail buffers 2026-05-27 17:48:56 +02:00
Onur Solmaz
b7a5bcba78 fix(memory): salvage qmd search JSON after nonzero exit (#87225)
Merged via squash.

Prepared head SHA: 964617b224
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Reviewed-by: @osolmaz
2026-05-27 23:44:43 +08:00
Pavan Kumar Gondhi
0314d67d87 Harden hostname normalization for repeated trailing dots [AI] (#87305)
* fix: canonicalize trailing hostname dots

* test: reuse shared hostname normalization

* docs: add changelog entry for PR merge
2026-05-27 21:08:29 +05:30
Vincent Koc
12dc398267 fix(e2e): harden kitchen sink log tailing 2026-05-27 17:35:51 +02:00
Pavan Kumar Gondhi
8e41c118fa fix: block side-effecting command wrappers [AI] (#87292)
* fix: block side-effecting command wrappers

* docs: add changelog entry for PR merge
2026-05-27 20:56:53 +05:30
Vincent Koc
694907d01e fix(e2e): bound bundled runtime log scans 2026-05-27 17:22:46 +02:00
Vincent Koc
5574f7518a fix(matrix): ignore filename-embedded mxids 2026-05-27 17:19:23 +02:00
Vincent Koc
20eab65ff4 fix(e2e): relax kitchen sink plugin memory guard 2026-05-27 17:10:01 +02:00
Agustin Rivera
0d0bddf032 fix(gateway): require admin for device role approvals (#87146)
* fix(gateway): require admin for device role approvals

* fix(gateway): add trusted-proxy approval proof
2026-05-27 08:08:51 -07:00
Pavan Kumar Gondhi
91590132f6 Block unsafe Node runtime env overrides [AI] (#87308)
* fix: block unsafe node runtime env overrides

* fix: block node env path redirects

* docs: add changelog entry for PR merge
2026-05-27 20:34:12 +05:30
Vincent Koc
d242774ec6 fix(matrix): await shared DM notices 2026-05-27 17:03:13 +02:00
Vincent Koc
a2f714cd44 fix(e2e): bound Telegram proof log polling 2026-05-27 16:59:35 +02:00
Vincent Koc
0d565833e1 fix(matrix): send mention finals normally 2026-05-27 16:48:09 +02:00
Vincent Koc
bca2501c7f fix(matrix): preserve final mention delivery 2026-05-27 16:44:02 +02:00
Vincent Koc
96eec2aab6 fix(matrix): keep draft previews mention-inert 2026-05-27 16:36:55 +02:00
Vincent Koc
5eeaa5603f fix(e2e): bound Open WebUI control probes 2026-05-27 16:31:16 +02:00
Vincent Koc
b8cf83aeb3 fix(qa): keep Matrix mention preview finals strict 2026-05-27 16:15:34 +02:00
Vincent Koc
2f1e314211 test(qa): assert final-first Matrix mention previews 2026-05-27 16:15:34 +02:00
Vincent Koc
bf5fef857a fix(qa): use read failure for Matrix mention progress 2026-05-27 16:15:34 +02:00
Vincent Koc
5bf1f168d4 fix(e2e): bound ClawHub preflight waits 2026-05-27 16:14:51 +02:00
Vincent Koc
101c83448b fix(qa): relax Matrix artifact modes on Windows 2026-05-27 16:10:34 +02:00
zunkai Zhao
0c493a161f fix(auto-reply): suppress reasoning-prefixed NO_REPLY
Suppress reasoning-prefixed silent replies before outbound delivery while preserving substantive replies that merely end with the silent token.\n\nFixes #66701.\n\nThanks @zuoanCo for the PR and @Cavadus for the report.\n\nProof: focused Vitest and pnpm check:changed passed on Testbox-through-Crabbox tbx_01ksmvfw0gk9xwh10ra1cyhzfw; CI passed for head a014eb0d91.
2026-05-27 15:09:56 +01:00
Vincent Koc
4d099c354b fix(e2e): bound kitchen sink log scans 2026-05-27 15:50:11 +02:00
Vincent Koc
e2f6734dac fix(qa): force Matrix mention progress search 2026-05-27 15:35:01 +02:00
Mariano
c9d4f7e35c Deprecate memory-specific embedding provider registration (#85072)
Merged via squash.

Prepared head SHA: 661eb99066
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-05-27 15:24:17 +02:00
Vincent Koc
4a8d89f8b5 fix(ci): bound real behavior proof API waits 2026-05-27 15:12:53 +02:00
Peter Steinberger
dc5954b0f8 fix(gateway): reject no-auth tailscale exposure
Fixes #50630.
Replaces stale PR #50631.

Behavior: reject gateway auth mode none when Tailscale Serve or Funnel exposes the gateway, across config validation, install-token preflight, and runtime startup.

Proof:
- node scripts/run-vitest.mjs src/config/config.gateway-tailscale-bind.test.ts src/gateway/server-runtime-config.test.ts src/commands/doctor-gateway-auth-token.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode local
- node scripts/crabbox-wrapper.mjs run --shell -- "pnpm check:changed" (run_5a999c1e11c0, exit 0)
- GitHub PR checks clean on 0b306e8e00ebfe2856e672fbd1964a51a69bfe58; prior checkout/diff failures were GitHub infrastructure and cleared after rebase.
2026-05-27 14:11:17 +01:00
Marvinthebored
04774071b1 fix(agents): avoid false Codex runtime live switches
Fixes #87226.

Preserve the already-applied `openai` to `openai-codex` Codex runtime promotion when the persisted selection is canonical `openai` with the same model, while keeping explicit runtime provider changes switchable.

Verification:
- `node scripts/run-vitest.mjs src/agents/live-model-switch.test.ts`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `pnpm check:changed` via Testbox `tbx_01ksmr59zdaqj3617w8w53xv4t` / Actions run `26512418770`
- Real behavior proof override gate: Actions run `26513059970`

Co-authored-by: Peter Lindsey <peter@lindsey.jp>
2026-05-27 14:11:11 +01:00
Peter Steinberger
128262fbc1 perf(gateway): trust current metadata lifecycle cache 2026-05-27 14:07:17 +01:00
openclaw-release-bot
c95b51f0cc chore(release): update appcast for 2026.5.26 2026-05-27 13:06:26 +00:00
Peter Steinberger
8e5183c60d refactor: move channel message sdk compat into core 2026-05-27 13:59:33 +01:00
Peter Steinberger
ef17bbaabf ci(release): harden postpublish verification 2026-05-27 13:58:14 +01:00
Peter Steinberger
1e67af7006 ci(release): accept main full-validation proof 2026-05-27 13:58:14 +01:00
Peter Steinberger
e61f175203 fix(cli): reject malformed gateway timeouts 2026-05-27 08:57:03 -04:00
Vincent Koc
b12bd3fc98 fix(dev): bound issue labeler OpenAI waits 2026-05-27 14:56:10 +02:00
Yuval Dinodia
ef77428c95 fix(openai): normalize responses replay tool ids
Fixes #74665.

Normalize replayed OpenAI Responses tool call identifiers before same-model pi-ai replay sends them back to the provider. This keeps canonical `call_*|fc_*` pairs intact when valid, rewrites overlong or malformed `function_call.call_id`, `function_call.id`, and matching `function_call_output.call_id` values into OpenAI's accepted 64-character shape, and preserves the reasoning replay path.

Verification:
- Live OpenAI E2E with maintainer key: raw replay payload failed with HTTP 400 for overlong `input[1].id`; normalized replay succeeded with HTTP 200 and `LIVE_OK`.
- `pnpm exec oxfmt --check --threads=1 src/agents/pi-embedded-helpers/openai.ts`
- `CI=1 OPENCLAW_VITEST_FS_MODULE_CACHE_PATH="$(mktemp -d /tmp/openclaw-vitest-cache.XXXXXX)" fnm exec --using 24.15.0 -- pnpm test src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.test.ts -- --run --reporter=verbose --maxWorkers=1`
- `CI=1 OPENCLAW_VITEST_FS_MODULE_CACHE_PATH="$(mktemp -d /tmp/openclaw-vitest-cache.XXXXXX)" fnm exec --using 24.15.0 -- pnpm test src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts src/agents/openai-responses.reasoning-replay.test.ts -- --run --reporter=verbose --maxWorkers=2`
- `autoreview --mode branch --base origin/main`: clean, no accepted/actionable findings.
- GitHub CI green on c675b35ade.

Co-authored-by: Yuval Dinodia <yetvald@gmail.com>
2026-05-27 13:51:57 +01:00
xin zhuang
7121f674ba fix(status): keep default status fast path bounded
Keeps plain `openclaw status` on a bounded fast path while preserving local status metadata. The default text scan now avoids network update fetches, live channel checks, setup fallback work, and unbounded session hydration; deep/all status keeps the fuller behavior.

Behavior addressed: default status latency from update, channel, setup, and session scans
Real environment tested: GitHub Actions on PR head 98f589a35df74a7abb8327984d0103bb9f31af3e; local focused lint; autoreview
Exact steps or command run after this patch: CI workflow 26510790999; CodeQL workflow 26510790924; CodeQL Critical Quality workflow 26510791058; OpenGrep workflow 26510791138; autoreview branch against origin/main
Evidence after fix: all current-SHA workflows completed successfully; autoreview clean; local focused core oxlint passed on touched status files
Observed result after fix: default status hydrates only visible recent sessions, keeps local update metadata, and shows intentionally skipped SecretRef credentials as unknown instead of warning
What was not tested: live provider/channel roundtrip

Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
2026-05-27 13:49:51 +01:00
Bob
4d89e00c50 feat(embeddings): add OpenAI-compatible core provider (#85269)
Merged via squash.

Prepared head SHA: dc9a5d5397
Co-authored-by: dutifulbob <261991368+dutifulbob@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-05-27 14:37:17 +02:00
Mariano
f3fe48e8b7 Make Telegram sendMessage actions durable (#87261)
Route Telegram sendMessage action replies through durable outbound delivery so completed agent responses remain retryable when the gateway send path times out.

Verified with focused Telegram/outbound tests, extension test typecheck, prepare build/check/full test gates, and green CI rerun for head 20b45687e1.
2026-05-27 14:34:47 +02:00
Vincent Koc
5fb57b533e fix(dev): bound gh-read API waits 2026-05-27 14:33:06 +02:00
rendrag-git
e153eceea5 fix(vllm): wire configured thinking params
Move vLLM Qwen thinking control onto configured model compat metadata and carry it through catalog/model-selection/runtime thinking contexts.

Also migrate legacy provider/default request params in doctor and keep Pi/runtime model rows buildable with explicit reasoning defaults.

Thanks @rendrag-git.

Co-authored-by: rendrag-git <253747599+rendrag-git@users.noreply.github.com>
2026-05-27 13:32:18 +01:00
Mason Huang
75221e0550 fix(agents): separate heartbeat runtime template (#85416)
Summary:
- The PR moves the runtime `HEARTBEAT.md` bootstrap template into `src/agents/templates`, keeps docs templates ... or other workspace files, adds a legacy heartbeat-template doctor repair, and updates package guards/tests.
- PR surface: Source +281, Tests +283, Docs +11, Config +1, Other 0. Total +576 across 15 files.
- Reproducibility: yes. from source inspection: current main loads `HEARTBEAT.md` from the docs template, and  ... pty heartbeat file non-empty to the runtime. I did not run a live heartbeat repro in this read-only review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(doctor): recognize heartbeat docs boilerplate
- PR branch already contained follow-up commit before automerge: fix(agents): update heartbeat workspace test
- PR branch already contained follow-up commit before automerge: fix(doctor): tighten heartbeat template repair

Validation:
- ClawSweeper review passed for head e34e85864c.
- Required merge gates passed before the squash merge.

Prepared head SHA: e34e85864c
Review: https://github.com/openclaw/openclaw/pull/85416#issuecomment-4519851630

Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
2026-05-27 12:30:22 +00:00
Peter Steinberger
3e351b718e fix(agents): honor OpenAI-compatible cache retention
Carry over #82973 and fix #81281 by preserving explicit cacheRetention for OpenAI-compatible completions providers that opt into prompt-cache-key support.

The change keeps explicit cacheRetention suppressed for OpenAI-compatible providers without compat.supportsPromptCacheKey, adds regression coverage for both paths, and updates prompt-caching docs for prompt_cache_key / prompt_cache_retention behavior.

Fixes #81281.
Supersedes #82973.

Co-authored-by: lonexreb <reach2shubhankar@gmail.com>
2026-05-27 13:21:23 +01:00
Peter Steinberger
517ce3df75 fix: require admin for node device approvals 2026-05-27 13:18:50 +01:00
Vincent Koc
983759b9b8 fix(qa): create Matrix mention progress target 2026-05-27 14:14:17 +02:00
Vincent Koc
d09eb437f2 fix(dev): bound Claude usage debug fetches 2026-05-27 14:10:15 +02:00
Peter Steinberger
5fdaf6b49b fix(cli): validate message numeric options 2026-05-27 08:05:03 -04:00
Peter Steinberger
7efbaf7dba perf(gateway): cache current plugin metadata fingerprints 2026-05-27 12:59:23 +01:00
Vincent Koc
e2cebe88ca fix(dev): bound realtime smoke HTTP waits 2026-05-27 13:46:42 +02:00
Vincent Koc
a275ce8611 fix(qa): accept Matrix tool error final races 2026-05-27 13:43:17 +02:00
Vincent Koc
099b0f816a fix(qa): cap Matrix readiness polling 2026-05-27 13:39:14 +02:00
Peter Steinberger
513a223c15 fix(cli): validate directory limits before resolution 2026-05-27 07:35:02 -04:00
Peter Steinberger
0889106cb2 fix(cli): reject loose webhook and directory numeric options 2026-05-27 07:35:02 -04:00
Syu
0503853c29 fix(agents): keep runtime context before active user turns
Fix runtime context placement so hidden runtime context is model-visible before the active user turn without persisting as a visible/session message.

Verification:
- git diff --check origin/main...origin/pr/86995-merge
- gh pr checks 86995 --repo openclaw/openclaw --watch=false
- gh run rerun 26493979156 --repo openclaw/openclaw --failed
- gh run watch 26493979156 --repo openclaw/openclaw --exit-status
- CodeQL run 26493979156 attempt 2, Security High (mcp-process-tool-boundary) job 78066719467 passed
2026-05-27 12:31:56 +01:00
Vincent Koc
f4b9d24621 fix(qa): stop Matrix phases after run timeout 2026-05-27 13:22:18 +02:00
Andy Ye
66965f5008 fix(agents): strip stale Anthropic thinking
Preserve replayability for direct Anthropic sessions whose stored assistant thinking blocks have empty or blank signatures after a newer user turn. Older invalid thinking-only assistant turns are replaced with the existing omitted-reasoning placeholder so the turn shape survives provider replay.

Also keep active tool-use continuations safe: when an assistant tool call is followed by tool results, preserve the latest assistant thinking block so signed-thinking providers can replay the current tool turn unchanged.

Proof:
- node scripts/run-vitest.mjs src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/pi-embedded-runner/thinking.test.ts test/scripts/openclaw-e2e-instance.test.ts
- pnpm check:changed via Blacksmith Testbox through Crabbox, tbx_01ksmfypqet50et92vdm5mmv5v, run https://github.com/openclaw/openclaw/actions/runs/26505947008
- Live Anthropic Messages replay accepted the OpenClaw-sanitized active tool-turn history with a real thinking signature.
- PR CI on 37c2e72d82 completed successfully for relevant checks.

Fixes #86886.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-27 12:20:27 +01:00
Vincent Koc
a02fe525f1 fix(doctor): validate bundled MCP tool schemas 2026-05-27 13:15:15 +02:00
Vincent Koc
b8fc2f6587 fix(qa): kill timed out Matrix CLI runs 2026-05-27 13:01:36 +02:00
Vincent Koc
545ad7f256 fix(dev): bound discord smoke waits 2026-05-27 12:56:39 +02:00
Vincent Koc
53662094c3 chore(pixverse): publish as external plugin 2026-05-27 12:41:10 +02:00
Vincent Koc
b3083de4f2 feat(pixverse): add api region selection 2026-05-27 12:41:10 +02:00
Vincent Koc
c18370574e feat(pixverse): add video generation provider 2026-05-27 12:41:10 +02:00
Vincent Koc
a46e839f7c fix(qa): tolerate fast Matrix tool replies 2026-05-27 12:41:04 +02:00
Peter Steinberger
6c3740255f refactor: remove channel turn runtime aliases 2026-05-27 11:37:23 +01:00
Vincent Koc
83ab0ba99f fix(test): bound qa otel receiver bodies 2026-05-27 12:26:49 +02:00
Peter Steinberger
fd648edfa9 fix(lint): clean manifest registry installed checks 2026-05-27 06:26:15 -04:00
Vincent Koc
7a7d9dedc1 fix(scripts): resolve npm package candidates through npm runner 2026-05-27 12:12:32 +02:00
Vincent Koc
42f3550f7e fix(qa): hide Matrix tool progress marker in workspace 2026-05-27 12:09:35 +02:00
caz0075
12e5876903 fix(usage): forward cached token usage in chat completions (#82062)
Forward cache-read token counts through the OpenAI-compatible chat-completions usage shape as prompt_tokens_details.cached_tokens so clients can price cached turns correctly.

Align internal gateway usage typing with the expanded wire shape.

Thanks @caz0075.
2026-05-27 11:07:37 +01:00
Peter Steinberger
42387aff59 test(codex): align provider claim expectation 2026-05-27 11:03:50 +01:00
Peter Steinberger
2babe03bf5 perf(gateway): cache stable plugin index fingerprints 2026-05-27 11:03:50 +01:00
Vincent Koc
1d4537add3 fix(test): scan kitchen rpc readiness logs incrementally 2026-05-27 11:51:03 +02:00
Vincent Koc
8c6da93fdf fix(test): fail startup bench on bad samples 2026-05-27 11:46:02 +02:00
Yuval Dinodia
bbdff39b6a fix(onboard): preserve agents.list and bindings on rerun
Preserve existing `agents.list` and top-level `bindings` during ordinary onboarding reruns so rerunning `openclaw onboard` cannot silently wipe configured agents or routing bindings.

Keep config size-drop allowances scoped to explicit reset/import/plugin-install migration flows, validate binding agent ids with normalized agent ids, and add doctor repair coverage for dangling bindings that is still best-effort around malformed agent lists.

Closes #84692.

Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 10:45:14 +01:00
Andy Ye
aa0a29099f fix: send bare direct Anthropic model ids
Closes #87181.

Direct Anthropic Messages requests now send bare Claude model ids even when OpenClaw stores them with the `anthropic/` provider prefix. Anthropic-compatible proxy and custom endpoint routes keep slash-bearing model ids unchanged so configured proxy models do not regress.

Also preserves the original parse error as `cause` in the JSONL request tail helper to keep the current CI lint gate green.

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-27 10:44:20 +01:00
Georgi Atsev
9e7c2b356b fix(deepinfra): load all DeepInfra models when user wants to browse t… (#84549)
* fix(deepinfra): load all DeepInfra models when user wants to browse them during onboarding

* docs(deepinfra): align TTS default

* fix(deepinfra): refresh video fallbacks

* fix(deepinfra): share credential-aware catalog discovery

* test(deepinfra): narrow catalog regression types

* test(deepinfra): keep catalog narrowing across callback

* fix(deepinfra): preserve default model in live catalog

* fix(deepinfra): align default model pricing

* fix(deepinfra): keep pixverse as video default

* docs(deepinfra): match video fallback default

* fix(deepinfra): honor config api keys for live catalog

* test(e2e): wait for watchdog stdio close

* test(media): align live harness provider expectation

* fix(deepinfra): always augment custom catalogs

* test(e2e): resolve watchdog commands before spawning

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 10:43:37 +01:00
Vincent Koc
32b3fb698d fix(qa): harden Matrix tool progress scenario 2026-05-27 11:37:55 +02:00
Vincent Koc
f4bcd61c9b fix(package): match npm globstar exclusions 2026-05-27 11:37:55 +02:00
Vincent Koc
296fbde279 fix(package): honor dist package exclusions in inventory 2026-05-27 11:37:55 +02:00
Peter Steinberger
c89298f9f8 fix: preserve channel runResolved mock compatibility 2026-05-27 10:36:33 +01:00
Vincent Koc
329dad23f5 fix(test): bound config reload log polling 2026-05-27 11:23:50 +02:00
Peter Steinberger
d6949d5951 fix(lint): preserve JSONL parse cause 2026-05-27 05:18:46 -04:00
Peter Steinberger
5eba76531b test(e2e): preserve macos smoke entrypoint path 2026-05-27 10:07:36 +01:00
Vincent Koc
109ba23083 fix(test): await mcp timeout cleanup 2026-05-27 11:04:09 +02:00
Vincent Koc
a4a75a8694 fix(test): harden mcp channel ws timeout 2026-05-27 11:01:52 +02:00
Vincent Koc
e50b20fe7b fix(test): harden gateway network ws timeout 2026-05-27 10:59:50 +02:00
Cathryn Lavery
730ac1a68d fix(agents/harness): validate forced plugin harness support before pinning (#74341)
Validates forced plugin harness support for the requested provider/model before pinning Codex or any other plugin harness. This prevents an explicitly forced Codex runtime from accepting unsupported OpenAI-like providers through a hardcoded bypass while preserving implicit PI fallback and CLI runtime alias passthrough.

Regression coverage covers forced Codex rejection for unsupported openai/openai-codex support, Codex provider support declarations, CLI attempt routing, pi-embedded auth/profile forwarding fakes, Testbox scenario probes, and live Docker Codex plugin E2E.

Thanks @cathrynlavery.
2026-05-27 09:59:04 +01:00
Vincent Koc
40a2600544 fix(test): bound codex media path log polling 2026-05-27 10:55:00 +02:00
Peter Steinberger
98c0ad8b42 test: align extension inbound context assertions 2026-05-27 04:52:02 -04:00
Sebastien Tardif
527b7c2eed fix(install): skip Homebrew until macOS packages need it
Keep macOS Homebrew setup lazy so users with supported Node and Git can install without admin/Homebrew, while still installing Homebrew before macOS Node or Git package installs.

Updates installer docs and adds focused install.sh coverage for the lazy Git path. Also aligns the live-media provider expectation with current main so built-artifact checks stay green.

Fixes #83232

Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-27 09:48:04 +01:00
Vincent Koc
351aac9f57 fix(ci): bound additional boundary checks 2026-05-27 10:42:22 +02:00
Vincent Koc
4dfc2cf14a fix(release): reject empty beta smoke runs 2026-05-27 10:34:06 +02:00
Vincent Koc
158bc697c4 fix(lint): split source lint shards 2026-05-27 10:32:53 +02:00
Vincent Koc
ecdc925698 fix(crabbox): reinitialize invalid changed-gate git dirs 2026-05-27 10:32:53 +02:00
Vincent Koc
1ba4448a60 fix(lint): shard core lint checks 2026-05-27 10:32:53 +02:00
Vincent Koc
8caa44fba3 fix(lint): cap oxlint helper memory locally 2026-05-27 10:32:53 +02:00
Vincent Koc
6c42fea2d8 fix(package): omit unpacked test helpers from inventory 2026-05-27 10:32:53 +02:00
Vincent Koc
cc662ba7d3 fix(docker): skip declarations in runtime packages 2026-05-27 10:32:53 +02:00
Vincent Koc
e8dde305e2 fix(build): cap tsdown heap in containers 2026-05-27 10:32:53 +02:00
Vincent Koc
b3e3b1b659 fix(crabbox): full-sync local sparse container runs 2026-05-27 10:32:52 +02:00
Vincent Koc
72c681396e fix(test): enable live cache script gates 2026-05-27 10:31:27 +02:00
Vincent Koc
51dd548a59 fix(test): reject unknown live media providers 2026-05-27 10:29:24 +02:00
Peter Steinberger
6b391efa4e fix(cli): reject loose model and gateway numeric options 2026-05-27 04:27:02 -04:00
Peter Steinberger
1507a9701b refactor: centralize inbound supplemental context
* refactor: centralize inbound supplemental context

* refactor: trim supplemental finalizer typing

* docs: clarify supplemental context projection

* refactor: move inbound finalization into core

* refactor: simplify channel inbound facts

* refactor: fold supplemental media into inbound finalizer

* refactor: migrate channel inbound callers to builder

* docs: mark inbound finalizer compat types deprecated

* refactor: wire runtime turn context builder

* refactor: replace channel turn runtime API

* fix: respect discord quote visibility

* fix: avoid deprecated line dispatch helper

* refactor: deprecate channel message SDK seams

* docs: trim channel outbound SDK page

* test: migrate irc inbound assertion

* refactor: deprecate outbound SDK facades

* refactor: deprecate channel helper SDK facades

* refactor: deprecate channel streaming SDK facade

* refactor: move direct dm helpers into inbound SDK

* chore: mark legacy test-utils SDK alias deprecated

* refactor: remove unused allow-from read helper

* refactor: route remaining channel dispatch through core

* refactor: enforce modern extension SDK imports

* test: give slow image root tests more time

* ci: support node fallback on windows

* fix: add transcripts tool display metadata

* refactor: trim legacy channel test seams

* fix: preserve channel compat after rebase

* fix: keep deprecated channel inbound aliases

* fix: preserve discord thread context visibility

* fix: clean final rebase conflicts

* fix: preserve channel message dispatch aliases

* fix: sync channel refactor after rebase

* fix: sync channel refactor after latest main

* fix: dedupe memory-core subagent mock

* test: align clickclack inbound dispatch assertions

* fix: sync plugin sdk api hash after rebase

* fix: sync channel refactor after latest main

* fix: sync plugin sdk api hash after rebase

* fix: sync plugin sdk api hash after latest main

* test: remove stale inbound context awaits
2026-05-27 09:26:06 +01:00
Vincent Koc
ad3d197c68 fix(test): reject empty gateway cpu runs 2026-05-27 10:19:57 +02:00
Vincent Koc
b460ee48a6 fix(test): fail empty plugin gauntlet runs 2026-05-27 10:16:16 +02:00
Josh Avant
cc704caa08 fix: load Claude CLI OAuth for PI auth profiles (#87167)
* test: cover auth profile SecretRef regressions

* docs: note auth profile regression coverage

* test: satisfy auth profile regression lint

* fix: load Claude CLI OAuth overlay for PI runs

* fix(agents): share external CLI auth selection with btw

* chore: remove release-owned changelog entry
2026-05-27 01:15:41 -07:00
Vincent Koc
cefa6777e2 fix(qa): keep fallback delivery on latest targets 2026-05-27 10:06:09 +02:00
Vincent Koc
31ecbbd5bf fix(agents): ignore failed subagent placeholders 2026-05-27 10:06:09 +02:00
Vincent Koc
2c3190d9de fix(agents): preserve bridge hook context 2026-05-27 10:06:09 +02:00
Vincent Koc
88bbc5b84b fix(agents): report approval resolutions in bridge mode 2026-05-27 10:06:09 +02:00
Vincent Koc
79f7b9348e fix(agents): classify direct fallback targets by channel grammar 2026-05-27 10:06:08 +02:00
Vincent Koc
35248be6b0 fix(qa): isolate mock bridge hook state 2026-05-27 10:06:08 +02:00
Vincent Koc
c2d059dc29 fix(qa): scope mock image prompts to latest turn 2026-05-27 10:06:08 +02:00
Vincent Koc
14198a1c66 fix(qa): close remaining mock qa e2e regressions 2026-05-27 10:06:08 +02:00
Vincent Koc
81c1892c9a fix(qa): stabilize mock QA scenario contracts 2026-05-27 10:06:08 +02:00
ToToKr
7e702bb43d fix(agents): suppress Write/Edit failed warning on response-timeout false-failure (#55424) (#86855)
* fix(agents): suppress Write/Edit failed warning on response-timeout false-failure (#55424)

Reporter sees '⚠️ Write failed' / '⚠️ Edit failed' warnings on Feishu (and other channels) even though the file was 100% saved successfully (8 of 8 verified writes succeeded; warning shown for all 8). Source path: tool-mutation records lastToolError.timedOut=true with a fileTarget when a write/edit tool ack reply times out after the disk mutation has already completed, then resolveToolErrorWarningPolicy goes through the default mutating-tool branch and emits the misleading failure summary.

Add a narrow gate inside resolveToolErrorWarningPolicy that suppresses the warning only when both lastToolError.timedOut is true AND lastToolError.fileTarget is defined. fileTarget is set by tool-mutation.ts only for the write/edit family (FILE_MUTATING_TOOL_NAMES), so this branch never matches exec/message/cron/gateway mutating-tool timeouts where the disk-write idempotency reasoning does not apply. Real file failures (no timeout) and timeouts without recorded fileTarget keep their visible warnings.

* fix: recover completed write timeouts safely

* fix: bound write timeout recovery precheck

* fix: type write recovery precheck fallback

* test: complete write recovery result mock

* test: isolate e2e timeout fixture shims

* test: stabilize e2e timeout fixture path

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 09:03:58 +01:00
Yoshikazu Terashi
3104f36329 fix(cron): surface classified run failure causes
Surface classified cron failure causes without changing raw cron JSON error text.

- add additive CLI `cause` output for finished run entries with `errorReason`
- persist/backfill full `FailoverReason` values on cron run-log entries
- thread provider context through cron finalization so provider-specific failure causes stay accurate
- extend protocol/Swift models and regression coverage for CLI JSON, run-log parsing/search, alerts, and protocol conformance

Verification:
- `pnpm lint --threads=8`
- `pnpm protocol:check`
- `pnpm exec oxfmt --check src/cli/cron-cli/shared.ts src/cli/cron-cli/shared.cause-display.test.ts src/cron/run-log.ts src/cron/run-log.error-reason.test.ts src/cron/cron-protocol-conformance.test.ts src/cron/service.failure-alert.test.ts src/cron/service/timer.ts src/cron/service/ops.ts src/gateway/protocol/schema/cron.ts scripts/protocol-gen-swift.ts`
- `git diff --check`
- AWS Crabbox `cbx_8a6a65ab83b0` / `run_42b73a4a9750`: 4 files, 20 tests passed
- autoreview clean, no accepted/actionable findings
- GitHub CI/CodeQL/OpenGrep/Workflow Sanity green/skipped/neutral on `aa29b087b2587d0aed3d409de5e7a2c706c32cdf`

Co-authored-by: Yoshikazu Terashi <yterashi@peperon-works.jp>
2026-05-27 09:03:17 +01:00
Vincent Koc
57b1c0b3d9 fix(test): fail empty extension test requests 2026-05-27 09:57:18 +02:00
Peter Steinberger
c95d348bb5 fix(cli): reject loose numeric options 2026-05-27 03:52:40 -04:00
Shubhankar Tripathy
717003aaff docs(providers/openai): clarify OpenAI Realtime Platform credits
Clarify that OpenAI Realtime voice is billed through OpenAI Platform credits, not Codex/ChatGPT subscription quota, for Voice Call and Control UI Talk.

Document the direct Platform API key path, the `openai-codex` OAuth client-secret path, the quota symptom, and the Platform billing fix. Keep the changelog note crediting @lonexreb.

Closes #76498.

Co-authored-by: lonexreb <reach2shubhankar@gmail.com>
2026-05-27 08:51:26 +01:00
Vincent Koc
ca990f2ce1 fix(codex): keep attempt watchdog for queued terminal turns
Keep the Codex app-server full attempt watchdog armed after a terminal turn notification is queued, so a wedged notification projector cannot leave a run stuck indefinitely.

Proof:
- `git diff --check origin/main...HEAD`
- `node scripts/run-oxlint.mjs extensions/codex/src/app-server/run-attempt.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `node scripts/run-vitest.mjs run extensions/codex/src/app-server/run-attempt.test.ts --testNamePattern "keeps the attempt watchdog armed"` passed in PR proof (`1 passed | 232 skipped`)
- `OPENCLAW_TESTBOX=1 pnpm check:changed` passed in `tbx_01kskyg44ej461k574jee8ffjc`
- CI required checks green after `build-artifacts` rerun job `78031279635` passed

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-27 08:50:59 +01:00
Agustin Rivera
08a73dbe4b fix(qqbot): gate fallback approval buttons (#87154)
QQBot fallback approval buttons now reuse the same slash-command authorization path as real commands, including access groups and default-account config merging.

Verification:
- node scripts/test-extension.mjs qqbot
- node --max-old-space-size=8192 --import tsx scripts/generate-plugin-sdk-api-baseline.ts --check && git diff --check
- pnpm lint --threads=8
- node scripts/run-vitest.mjs src/agents/agent-command.live-model-switch.test.ts
- GitHub PR checks for 7cc0f15031: passed

Thanks @eleqtrizit.

Co-authored-by: Agustin Rivera <agustin@rivera-web.com>
2026-05-27 08:44:55 +01:00
Vincent Koc
7615c3137d fix(test): fail explicit empty vitest runs 2026-05-27 09:41:53 +02:00
Peter Steinberger
8d990378a6 ci: fall back from stale workflow dispatch refs 2026-05-27 03:39:28 -04:00
Vincent Koc
c93b7d8bbc fix(lint): serialize oxlint shards on constrained hosts 2026-05-27 09:36:56 +02:00
Peter Steinberger
d2d5010aec fix: reject partial numeric CLI options 2026-05-27 03:34:44 -04:00
clawsweeper[bot]
f4e20f806e fix(agents): avoid duplicate Claude CLI skill prompts
Fix Claude CLI skill prompt handling so native skill plugin materialization is prepared before prompt suppression, with the prompt fallback preserved when plugin args are unavailable. Also keeps direct prepared-run callers covered by an execute-time fallback.

Fixes #87063.

Co-authored-by: uday <udaymanish.thumma@gmail.com>
2026-05-27 08:34:34 +01:00
Peter Steinberger
cf399d65d8 test: harden e2e instance package fixture 2026-05-27 03:30:57 -04:00
Peter Steinberger
e718d471f2 test(codex): mirror raw reasoning event order 2026-05-27 08:29:18 +01:00
Peter Steinberger
4314eadc79 fix(codex): keep raw assistant release path intact 2026-05-27 08:29:18 +01:00
Peter Steinberger
284098d2d8 fix(codex): preserve raw reasoning source-reply guard 2026-05-27 08:29:18 +01:00
Username
4d6bcf9f17 test(codex): verify completion idle watch arms after non-assistant rawResponseItem/completed
Regression test for the binary stall fix: when rawResponseItem/completed
arrives with a non-assistant type (e.g. "reasoning") and all tracked
items have completed, the completion idle watch must stay armed so the
stall is caught in 60s, not 30 minutes.

Refs openclaw/openclaw#87071

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-27 08:29:18 +01:00
Username
a36c82ba8b fix(codex): arm completion idle watch after rawResponseItem/completed with no active items
When the codex binary emits rawResponseItem/completed and all tracked
items have completed (activeTurnItemIds empty, no active requests), the
binary should deliver turn/completed imminently. Previously, a
rawResponseItem/completed that didn't qualify as a post-tool assistant
completion would actively disarm the completion idle watch, leaving only
the 30-minute terminal timeout to catch a stalled binary. This caused
turns to hang for up to 30 minutes when the OpenAI Responses API fails
to deliver response.completed to the binary.

Now, rawResponseItem/completed with no active items arms the 60s
completion idle watch and is excluded from the disarm path, so stalled
binaries are detected in 60s instead of 30 minutes.

Refs openclaw/openclaw#87071

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-27 08:29:18 +01:00
scotthuang
819fd9fbe9 fix(node-host): restart stale node host on version mismatch
Restart stale local node-host processes when they reconnect to a newer gateway with a released-version mismatch, so launchd/systemd can restart them with updated code instead of leaving old dynamic imports alive.

Adds gateway mismatch detail propagation, node-host terminal pause handling, and regression coverage for the GatewayClient reconnect-pause path.

Verification:
- node scripts/run-vitest.mjs run src/gateway/client.test.ts -t 'CLIENT_VERSION_MISMATCH' --reporter=verbose
- node scripts/run-vitest.mjs run src/gateway/server.node-version-mismatch.test.ts src/node-host/runner.credentials.test.ts src/gateway/client.test.ts --reporter=verbose
- /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode local
- Crabbox AWS run_292dcbfd78d9: focused GatewayClient mismatch regression plus server/node-host mismatch tests passed

Co-authored-by: scotthuang <scotthuang@tencent.com>
2026-05-27 08:25:02 +01:00
Vincent Koc
761c802c2a fix(e2e): bound tool search gateway proof 2026-05-27 09:23:57 +02:00
Peter Steinberger
9ed1b02134 fix(discord): harden requester checks for guild actions 2026-05-27 08:22:25 +01:00
Peter Steinberger
482018e536 fix: mark plugin command groups in root help 2026-05-27 08:22:01 +01:00
Peter Steinberger
2bbef6caac fix: route nested root help targets 2026-05-27 08:22:01 +01:00
Peter Steinberger
5f6293a902 fix: route root help targets to command help 2026-05-27 08:22:01 +01:00
Peter Steinberger
b31c9e9810 fix: preserve root options in generated help 2026-05-27 08:22:01 +01:00
Peter Steinberger
ec377dd079 fix: support plugin generated help targets 2026-05-27 08:22:01 +01:00
Peter Steinberger
1de98487cc fix: route generated help targets to subcommands 2026-05-27 08:22:01 +01:00
Peter Steinberger
9015d0c582 fix: normalize generated help self-help 2026-05-27 08:22:01 +01:00
Peter Steinberger
f407e4e498 fix: validate gateway call timeouts 2026-05-27 08:22:01 +01:00
Peter Steinberger
84b11237f2 fix: let skills JSON output flush naturally 2026-05-27 08:22:01 +01:00
Peter Steinberger
ef2ebeef89 fix: keep root help plugin descriptor loading quiet 2026-05-27 08:22:01 +01:00
Super Zheng
6790b0f792 perf(secrets): propagate snapshots and eliminate esm side-effects in auth env vars (#86439)
* perf(secrets): propagate snapshots and eliminate esm side-effects in auth env vars

* perf(secrets): reuse provider auth lookup maps

* test(auth): update provider env var mocks

* test(auth): cover rebased provider env mocks

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 08:19:07 +01:00
Peter Steinberger
f327df866c test: stabilize main ci lanes 2026-05-27 08:07:13 +01:00
Peter Steinberger
54eca3fb56 perf(gateway): keep agent session working store active-only 2026-05-27 08:00:24 +01:00
Peter Steinberger
e6937f9f01 test(e2e): harden shell helper env assertions 2026-05-27 07:57:27 +01:00
Vincent Koc
497685111b fix(doctor): warn on unsupported active tool schemas 2026-05-27 08:55:49 +02:00
Peter Steinberger
368469688b test: fix main ci expectations 2026-05-27 07:55:01 +01:00
Vincent Koc
9b2860324b fix(e2e): bound Telegram credential setup 2026-05-27 08:49:56 +02:00
Peter Steinberger
3b9fa16862 perf(gateway): borrow agent session lookup safely 2026-05-27 07:44:56 +01:00
Vincent Koc
6afe3e8952 fix(crabbox): prefer Azure for Windows targets (#87186) 2026-05-27 07:37:19 +01:00
Peter Steinberger
b28f9e0df3 test(e2e): isolate shell helper env 2026-05-27 07:36:55 +01:00
Vincent Koc
aa40174f0a fix(e2e): bound MCP channel connect 2026-05-27 08:33:49 +02:00
Peter Steinberger
8c8162f1f7 perf(gateway): borrow read-only session metadata 2026-05-27 07:32:29 +01:00
xin zhuang
152f68d037 fix(gateway): persist model auth profile suffixes
Persist trailing `/model ...@profile` suffixes through the gateway session patch path so documented per-session credential pinning reaches the session entry. Strip the suffix before model resolution so bare allowlisted model IDs still infer their configured provider, and mark same-model profile-only changes as pending live model switches.

Closes #87099.

Verification:
- `npx oxfmt --check src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts`
- `node scripts/run-vitest.mjs src/gateway/sessions-patch.test.ts src/sessions/model-overrides.test.ts`
- `npx oxlint src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `gh pr checks 87123 --watch --fail-fast`

Co-authored-by: xin zhuang <65798732+1052326311@users.noreply.github.com>
2026-05-27 07:29:02 +01:00
Javier Ailbirt
da822dd28b fix(googlechat): suppress thread sends in DMs
Guard Google Chat DM delivery so direct-space messages that include thread metadata do not request threaded sends. The monitor now derives one group-only reply thread and reuses it for both turn reply context and typing indicator messages.

Adds regression coverage for a DM event carrying `message.thread.name`, proving reply metadata and typing sends omit the thread while the turn still runs.

Verification:
- `node scripts/run-vitest.mjs extensions/googlechat/src/monitor.test.ts`
- `pnpm check:changed` (Blacksmith Testbox `tbx_01ksm18yck1zy35k0adgf66hax`, run https://github.com/openclaw/openclaw/actions/runs/26494371192)
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode local`
- PR CI run https://github.com/openclaw/openclaw/actions/runs/26494573295
- Critical Quality run https://github.com/openclaw/openclaw/actions/runs/26494573221
- Real behavior proof override run https://github.com/openclaw/openclaw/actions/runs/26494609491

Co-authored-by: Javier Ailbirt <jailbirt@theeye.io>
2026-05-27 07:28:09 +01:00
Josh Avant
3349fe21bb Fix embedded session file ownership race (#87159)
* fix: serialize embedded session file attempts

* test: update reply runtime mock for session file lookup

* fix: thread session files into diagnostic recovery

* fix: attach causes to session owner abort errors
2026-05-26 23:18:27 -07:00
Peter Steinberger
ebe09be500 ci(ui): refresh raw copy baseline 2026-05-27 07:14:57 +01:00
Sanjay Santhanam
1710dac5eb fix(pi-embedded): route Codex OAuth compaction through OpenAI-Codex
Fix Codex OAuth-backed OpenAI compaction routing by separating the configured provider from the runtime auth provider, preserving same-provider fallback auth, and keeping OpenAI context policy lookup intact. Also preserves the original cause when sessions.send reports A2A fallback failure. Fixes #86373.
2026-05-27 07:14:02 +01:00
Coy Geek
ce64d74e5a fix(commands): enforce /allowlist configWrites origin policy
Summary:
- Enforces /allowlist config and pairing-store writes against the real command origin plus the selected target.
- Adds regressions for disabled Telegram-origin commands targeting an enabled Discord allowlist.

Verification:
- node scripts/run-vitest.mjs src/auto-reply/reply/commands-allowlist.test.ts
- pnpm check:changed via Blacksmith Testbox tbx_01ksm06e82dnpxmnj00hrt6xzd
- autoreview --mode local clean, no accepted/actionable findings
- GitHub PR checks green on 42a38d2b00

Closes #72360.
Thanks @coygeek.

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
Co-authored-by: opencode <opencode@users.noreply.github.com>
2026-05-27 07:10:50 +01:00
Dallin Romney
780bc79147 fix(plugin-sdk): stop exporting vitest test helpers (#87120) 2026-05-26 23:10:41 -07:00
Peter Steinberger
9c2a6a8df5 perf(gateway): borrow session reads on turn hot paths 2026-05-27 07:02:00 +01:00
keshavbotagent
455d5e807c fix(reply): keep visible turn admission unbounded (#87044)
Remove the hidden 15s default from reply-run idle waits so visible user turns do not inherit cleanup-settle behavior while waiting behind an active same-session reply operation.

Keep the 15s timeout explicit for queued follow-up retry/defer paths and interrupt/reset cleanup waits, and add reply-admission regressions for both visible and queued follow-up behavior. Also preserve the original cause on a nearby sessions-send fallback error to keep current lint green after rebasing onto main.

Thanks @keshavbotagent.

Co-authored-by: Keshav's Bot <keshavbotagent@gmail.com>
2026-05-27 07:01:46 +01:00
Vincent Koc
4b40197eae fix(e2e): bound Telegram proof Bot API calls 2026-05-27 07:58:34 +02:00
Vincent Koc
798691779b fix(agents): preserve sessions fallback errors 2026-05-27 07:54:24 +02:00
Vincent Koc
e7214efbb7 test(core): isolate provider and approval tests 2026-05-27 07:54:24 +02:00
Vincent Koc
8c644ee611 fix(agents): quarantine unsupported tool schemas 2026-05-27 07:54:24 +02:00
Agustin Rivera
2c88547254 fix(prompt): route untrusted group prompts outside system prompt [AI] (#87144)
* fix(prompt): route untrusted group prompts outside system prompt

* fix(prompt): align untrusted group prompt helpers
2026-05-26 22:47:54 -07:00
Pablo Guardiola
0c867eef75 feat: expose plugin approval action metadata
Expose plugin approval action metadata so plugins can describe richer approval actions across gateway, SDK, channel, and UI surfaces.
2026-05-26 22:46:09 -07:00
8492 changed files with 496795 additions and 132890 deletions

View File

@@ -50,8 +50,9 @@ Dirty local work:
```
Use this only when the patch is actually unstaged/staged/untracked in the
current checkout. For committed, pushed, or PR work, point the helper at the commit
or branch diff instead; do not force `--mode local` / `--uncommitted` just
current checkout. `--mode uncommitted` is accepted as an alias for `--mode local`.
For committed, pushed, or PR work, point the helper at the commit
or branch diff instead; do not force dirty modes just
because the helper docs mention dirty work first. A clean local review
only proves there is no local patch.
@@ -99,6 +100,10 @@ Format first if formatting can change line locations. Then it is OK to run tests
scripts/autoreview --parallel-tests "<focused test command>"
```
On Windows, the default `--parallel-tests` shell preserves the platform `cmd.exe`
semantics used by Python `shell=True`. Use `--parallel-tests-shell powershell`
or `--parallel-tests-shell pwsh` when the focused test command is PowerShell-specific.
Tradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain. Once that rerun exits cleanly, stop; do not spend another long review cycle on redundant confirmation.
## Review Panels
@@ -143,6 +148,22 @@ OpenClaw repo-local helper:
.agents/skills/autoreview/scripts/autoreview --help
```
On native Windows, invoke the extensionless Python helper through Python:
```powershell
python .agents\skills\autoreview\scripts\autoreview --help
```
The smoke harness has thin shell wrappers over a shared Python implementation:
```bash
.agents/skills/autoreview/scripts/test-review-harness --fixture benign --engine codex
```
```powershell
.agents\skills\autoreview\scripts\test-review-harness.ps1 -Fixture benign -Engine codex
```
`agent-scripts` checkout helper:
```bash
@@ -164,13 +185,15 @@ If installed from `agent-scripts`, path is:
The helper:
- chooses dirty local changes first
- accepts `--mode uncommitted` as an alias for `--mode local`
- otherwise uses current PR base if `gh pr view` works
- otherwise uses `origin/main` for non-main branches
- supports `--engine codex`, `claude`, `droid`, and `copilot`; default is `AUTOREVIEW_ENGINE` or `codex`; Codex should remain the default when nothing is set
- resolves bare `git`, `gh`, reviewer, and PowerShell shell commands from absolute `PATH` entries only, never from the reviewed checkout; explicit relative `--*-bin` paths are resolved from the reviewed repository root
- use `--mode commit --commit <ref>` for already-committed work, especially clean `main` after landing
- should be left in `--mode auto` or forced to `--mode branch` for PR/branch work; do not force `--mode local` after committing
- writes only to stdout unless `--output`, `--json-output`, or live streamed engine stderr is set
- supports `--dry-run`, `--parallel-tests`, `--prompt`, `--prompt-file`, `--dataset`, `--no-tools`, `--no-web-search`, and commit refs
- supports `--dry-run`, `--parallel-tests`, `--parallel-tests-shell`, `--prompt`, `--prompt-file`, `--dataset`, `--no-tools`, `--no-web-search`, and commit refs
- supports `--stream-engine-output` or `AUTOREVIEW_STREAM_ENGINE_OUTPUT=1` for live engine text while preserving structured validation; Codex and Claude hide tool/file event details, emit compact activity summaries, and report usage at turn completion
- supports opt-in review panels with `--panel` / `--reviewers`, plus per-engine `--model` and `--thinking`
- allows read-only tools and web search by default where the selected CLI supports them; forbids nested review in the prompt; Codex is run through `codex exec` with read-only sandbox and structured output

View File

@@ -214,12 +214,17 @@ def run_with_stream(
def git(repo: Path, *args: str, check: bool = True) -> str:
return run(["git", *args], repo, check=check).stdout
return run([resolve_command("git", repo), *args], repo, check=check).stdout
def repo_root() -> Path:
start = Path.cwd().resolve()
unsafe_root = discover_repo_root(start) or start
git_bin = find_command("git", unsafe_root)
if not git_bin:
raise SystemExit("git executable not found. Install Git or add it to PATH.")
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
[git_bin, "rev-parse", "--show-toplevel"],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -229,6 +234,16 @@ def repo_root() -> Path:
return Path(result.stdout.strip()).resolve()
def discover_repo_root(start: Path) -> Path | None:
current = start
while True:
if (current / ".git").exists():
return current
if current.parent == current:
return None
current = current.parent
def current_branch(repo: Path) -> str:
return git(repo, "branch", "--show-current", check=False).strip() or "detached"
@@ -238,6 +253,7 @@ def is_dirty(repo: Path) -> bool:
def choose_target(repo: Path, mode: str, base_ref: str | None) -> tuple[str, str | None]:
mode = "local" if mode == "uncommitted" else mode
branch = current_branch(repo)
if mode == "local" or (mode == "auto" and is_dirty(repo)):
return "local", None
@@ -249,17 +265,70 @@ def choose_target(repo: Path, mode: str, base_ref: str | None) -> tuple[str, str
def detect_pr_base(repo: Path) -> str | None:
if not shutil_which("gh"):
gh_bin = find_command("gh", repo)
if not gh_bin:
return None
result = run(["gh", "pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"], repo, check=False)
result = run([gh_bin, "pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"], repo, check=False)
base = result.stdout.strip()
return f"origin/{base}" if result.returncode == 0 and base else None
def shutil_which(name: str) -> str | None:
def resolve_command(name: str, repo: Path) -> str:
resolved = find_command(name, repo)
if resolved:
return resolved
raise SystemExit(f"executable not found: {name}. Install it or pass an explicit trusted path when supported.")
def find_command(name: str, repo: Path) -> str | None:
command = Path(name)
if has_directory_component(name, command):
base = command if command.is_absolute() else repo / command
return first_executable_candidate(base)
for part in os.environ.get("PATH", "").split(os.pathsep):
candidate = Path(part) / name
if candidate.exists() and os.access(candidate, os.X_OK):
if not part or part == ".":
continue
path_part = Path(part)
if not path_part.is_absolute():
continue
try:
resolved_part = path_part.resolve()
resolved_repo = repo.resolve()
except OSError:
continue
if is_within(resolved_part, resolved_repo):
continue
found = first_executable_candidate(resolved_part / name, reject_root=resolved_repo)
if found:
return found
return None
def is_within(path: Path, root: Path) -> bool:
return path == root or path.is_relative_to(root)
def has_directory_component(name: str, command: Path) -> bool:
separators = [separator for separator in (os.sep, os.altsep) if separator]
return command.is_absolute() or bool(command.drive) or any(separator in name for separator in separators)
def first_executable_candidate(path: Path, *, reject_root: Path | None = None) -> str | None:
if os.name == "nt" and not path.suffix:
extensions = [ext for ext in os.environ.get("PATHEXT", ".COM;.EXE;.BAT;.CMD").split(";") if ext]
candidates = [path.with_suffix(ext.lower()) for ext in extensions]
candidates.extend(path.with_suffix(ext.upper()) for ext in extensions)
candidates.append(path)
else:
candidates = [path]
for candidate in candidates:
if candidate.is_file() and os.access(candidate, os.X_OK):
if reject_root is not None:
try:
if is_within(candidate.resolve(), reject_root):
continue
except OSError:
continue
return str(candidate)
return None
@@ -418,7 +487,7 @@ def run_codex(args: argparse.Namespace, repo: Path, prompt: str) -> str:
raise SystemExit("--no-tools is not supported by the Codex engine; use --engine claude --no-tools for a no-tools run")
schema_path = write_json_temp(SCHEMA)
output_path = Path(tempfile.NamedTemporaryFile("w", suffix=".json", delete=False).name)
cmd = [args.codex_bin, "--ask-for-approval", "never"]
cmd = [resolve_command(args.codex_bin, repo), "--ask-for-approval", "never"]
if args.web_search:
cmd.append("--search")
if args.model:
@@ -462,7 +531,7 @@ def run_codex(args: argparse.Namespace, repo: Path, prompt: str) -> str:
def run_claude(args: argparse.Namespace, repo: Path, prompt: str) -> str:
cmd = [
args.claude_bin,
resolve_command(args.claude_bin, repo),
"--print",
"--no-session-persistence",
"--output-format",
@@ -499,7 +568,7 @@ def run_droid(args: argparse.Namespace, repo: Path, prompt: str) -> str:
prompt_path = Path(tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False).name)
prompt_path.write_text(prompt)
cmd = [
args.droid_bin,
resolve_command(args.droid_bin, repo),
"exec",
"--cwd",
str(repo),
@@ -529,7 +598,7 @@ def run_copilot(args: argparse.Namespace, repo: Path, prompt: str) -> str:
prompt_path.write_text(prompt)
os.chmod(prompt_path, 0o600)
cmd = [
args.copilot_bin,
resolve_command(args.copilot_bin, repo),
"-C",
tempdir,
"-p",
@@ -876,9 +945,23 @@ def print_report(report: dict[str, Any], *, label: str = "autoreview") -> None:
print(report["overall_explanation"])
def start_parallel_tests(command: str, repo: Path) -> tuple[subprocess.Popen, float]:
def start_parallel_tests(command: str, repo: Path, shell_kind: str) -> tuple[subprocess.Popen, float]:
print(f"tests: {command}")
return subprocess.Popen(command, cwd=repo, shell=True), time.time()
if shell_kind == "default" or shell_kind == "cmd":
return subprocess.Popen(command, cwd=repo, shell=True), time.time()
if shell_kind == "powershell":
powershell = resolve_command("powershell", repo)
return subprocess.Popen(
[powershell, "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", command],
cwd=repo,
), time.time()
if shell_kind == "pwsh":
pwsh = resolve_command("pwsh", repo)
return subprocess.Popen(
[pwsh, "-NoProfile", "-Command", command],
cwd=repo,
), time.time()
raise SystemExit(f"invalid --parallel-tests-shell/AUTOREVIEW_PARALLEL_TESTS_SHELL: {shell_kind}")
def finish_parallel_tests(proc: subprocess.Popen, started: float) -> int:
@@ -889,7 +972,7 @@ def finish_parallel_tests(proc: subprocess.Popen, started: float) -> int:
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Bundle-driven AI code review.")
parser.add_argument("--mode", choices=["auto", "local", "branch", "commit"], default="auto")
parser.add_argument("--mode", choices=["auto", "local", "uncommitted", "branch", "commit"], default="auto")
parser.add_argument("--base")
parser.add_argument("--commit", default="HEAD")
parser.add_argument("--engine", choices=ENGINES, default=os.environ.get("AUTOREVIEW_ENGINE", "codex"))
@@ -923,6 +1006,12 @@ def parse_args() -> argparse.Namespace:
help="Stream review engine output while preserving buffered output for validation. Codex output is filtered to hide tool/file chatter.",
)
parser.add_argument("--parallel-tests", help="Run a test command concurrently with review; failure fails the helper.")
parser.add_argument(
"--parallel-tests-shell",
choices=["default", "cmd", "powershell", "pwsh"],
default=os.environ.get("AUTOREVIEW_PARALLEL_TESTS_SHELL", "default"),
help="Shell for --parallel-tests. Default preserves Python shell=True platform behavior; use powershell or pwsh for PowerShell-specific commands.",
)
parser.add_argument("--require-finding", action="append", default=[], help="Require finding text to contain this substring.")
parser.add_argument("--expect-findings", action="store_true", help="Treat findings as success; for harness acceptance tests.")
parser.add_argument("--dry-run", action="store_true")
@@ -1128,7 +1217,7 @@ def main() -> int:
tests_proc: tuple[subprocess.Popen, float] | None = None
if args.parallel_tests:
tests_proc = start_parallel_tests(args.parallel_tests, repo)
tests_proc = start_parallel_tests(args.parallel_tests, repo, args.parallel_tests_shell)
try:
if len(reviewers) == 1:
report = run_reviewer(reviewers[0], repo, prompt, changed_paths, args.require_finding)

View File

@@ -1,176 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: test-review-harness [--fixture malicious|benign] [--engine codex|claude|droid|copilot]...
Creates a temporary git repo with either a deliberately unsafe patch or a
security-sensitive-but-safe patch, then verifies each selected engine through
autoreview.
Default engines: codex, claude.
EOF
}
engines=()
fixture=malicious
while [[ $# -gt 0 ]]; do
case "$1" in
--fixture)
fixture=${2:-}
shift 2
;;
--engine)
engines+=("${2:-}")
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
done
case "$fixture" in
malicious|benign) ;;
*)
usage >&2
exit 2
;;
esac
if [[ ${#engines[@]} -eq 0 ]]; then
engines=(codex claude)
fi
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
repo=$(mktemp -d "${TMPDIR:-/tmp}/autoreview-fixture.XXXXXX")
trap 'rm -rf "$repo"' EXIT
harness="$script_dir/test-review-harness.py"
cd "$repo"
git init --quiet
git config user.name "Review Fixture"
git config user.email "review-fixture@example.com"
if [[ "$fixture" == malicious ]]; then
cat > app.js <<'EOF'
export function uploadPath(name) {
return `uploads/${name.replaceAll("/", "")}`;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
EOF
else
cat > app.js <<'EOF'
import path from "node:path";
const uploadsRoot = path.resolve("uploads");
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
EOF
if command -v python3 >/dev/null 2>&1; then
exec python3 "$harness" "$@"
fi
git add app.js
git commit --quiet -m "initial safe version"
if [[ "$fixture" == malicious ]]; then
cat > app.js <<'EOF'
import { execSync } from "node:child_process";
export function uploadPath(name) {
return `uploads/${name}`;
}
export function deleteUpload(name) {
return execSync(`rm -rf uploads/${name}`);
}
export function publicUser(user) {
return { id: user.id, name: user.name, password: user.password };
}
EOF
else
cat > app.js <<'EOF'
import { execFile } from "node:child_process";
import path from "node:path";
import { promisify } from "node:util";
const uploadsRoot = path.resolve("uploads");
const reposRoot = path.resolve("repos");
const execFileAsync = promisify(execFile);
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
function repoChildPath(root, name) {
if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error("invalid repo name");
return safeChildPath(root, name);
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export async function repoStatus(repoName) {
const { stdout } = await execFileAsync("git", ["status", "--short"], {
cwd: repoChildPath(reposRoot, repoName),
encoding: "utf8",
maxBuffer: 16 * 1024 * 1024,
});
return stdout;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
export function accountSettingsForOwner(user, requesterId) {
if (String(requesterId) !== String(user.id)) throw new Error("forbidden");
return { id: user.id, hasPassword: Boolean(user.passwordHash) };
}
EOF
if command -v python >/dev/null 2>&1; then
exec python "$harness" "$@"
fi
for engine in "${engines[@]}"; do
echo "== $engine =="
if [[ "$fixture" == malicious ]]; then
"$script_dir/autoreview" \
--mode local \
--engine "$engine" \
--prompt "This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch." \
--require-finding "command" \
--expect-findings
else
"$script_dir/autoreview" \
--mode local \
--engine "$engine" \
--prompt "Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff."
fi
done
echo "Python 3 is required to run test-review-harness." >&2
exit 127

View File

@@ -0,0 +1,45 @@
[CmdletBinding()]
param(
[ValidateSet('malicious', 'benign')]
[string] $Fixture,
[ValidateSet('codex', 'claude', 'droid', 'copilot')]
[string[]] $Engine,
[Alias('h')]
[switch] $Help
)
$ErrorActionPreference = 'Stop'
$Harness = Join-Path $PSScriptRoot 'test-review-harness.py'
$ForwardedArgs = @()
if ($Help) {
$ForwardedArgs += '--help'
}
if ($PSBoundParameters.ContainsKey('Fixture')) {
$ForwardedArgs += @('--fixture', $Fixture)
}
if ($PSBoundParameters.ContainsKey('Engine')) {
foreach ($SelectedEngine in $Engine) {
$ForwardedArgs += @('--engine', $SelectedEngine)
}
}
$PyLauncher = Get-Command py -ErrorAction SilentlyContinue
if ($null -ne $PyLauncher) {
& $PyLauncher.Source -3 $Harness @ForwardedArgs
exit $LASTEXITCODE
}
$Python = Get-Command python -ErrorAction SilentlyContinue
if ($null -ne $Python) {
& $Python.Source $Harness @ForwardedArgs
exit $LASTEXITCODE
}
Write-Error 'Python 3 is required to run test-review-harness.'
exit 127

View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import os
import shutil
import stat
import subprocess
import sys
import tempfile
from collections.abc import Callable
from pathlib import Path
ENGINES = ("codex", "claude", "droid", "copilot")
DEFAULT_ENGINES = ("codex", "claude")
MALICIOUS_INITIAL = """export function uploadPath(name) {
return `uploads/${name.replaceAll("/", "")}`;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
"""
BENIGN_INITIAL = r"""import path from "node:path";
const uploadsRoot = path.resolve("uploads");
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
"""
MALICIOUS_CHANGED = """import { execSync } from "node:child_process";
export function uploadPath(name) {
return `uploads/${name}`;
}
export function deleteUpload(name) {
return execSync(`rm -rf uploads/${name}`);
}
export function publicUser(user) {
return { id: user.id, name: user.name, password: user.password };
}
"""
BENIGN_CHANGED = r"""import { execFile } from "node:child_process";
import path from "node:path";
import { promisify } from "node:util";
const uploadsRoot = path.resolve("uploads");
const reposRoot = path.resolve("repos");
const execFileAsync = promisify(execFile);
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
function repoChildPath(root, name) {
if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error("invalid repo name");
return safeChildPath(root, name);
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export async function repoProbe(repoName) {
const { stdout } = await execFileAsync(process.execPath, ["--version"], {
cwd: repoChildPath(reposRoot, repoName),
encoding: "utf8",
maxBuffer: 16 * 1024 * 1024,
});
return stdout;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
export function accountSettingsForOwner(user, requesterId) {
if (String(requesterId) !== String(user.id)) throw new Error("forbidden");
return { id: user.id, hasPassword: Boolean(user.passwordHash) };
}
"""
MALICIOUS_PROMPT = "This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch."
BENIGN_PROMPT = "Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff."
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
prog="test-review-harness",
description=(
"Creates a temporary git repo with either a deliberately unsafe patch "
"or a security-sensitive-but-safe patch, then verifies each selected "
"engine through autoreview."
),
epilog="Default engines: codex, claude.",
)
parser.add_argument("--fixture", choices=("malicious", "benign"), default="malicious")
parser.add_argument("--engine", action="append", choices=ENGINES, dest="engines")
return parser.parse_args(argv)
def write_fixture_file(repo: Path, content: str) -> None:
with (repo / "app.js").open("w", encoding="utf-8", newline="\n") as handle:
handle.write(content)
def run(command: list[str], cwd: Path) -> None:
subprocess.run(command, cwd=cwd, check=True)
def create_fixture_repo(repo: Path, fixture: str) -> None:
run(["git", "init", "--quiet"], repo)
run(["git", "config", "user.name", "Review Fixture"], repo)
run(["git", "config", "user.email", "review-fixture@example.com"], repo)
write_fixture_file(repo, MALICIOUS_INITIAL if fixture == "malicious" else BENIGN_INITIAL)
run(["git", "add", "app.js"], repo)
run(["git", "commit", "--quiet", "-m", "initial safe version"], repo)
write_fixture_file(repo, MALICIOUS_CHANGED if fixture == "malicious" else BENIGN_CHANGED)
def run_reviews(repo: Path, script_dir: Path, fixture: str, engines: list[str]) -> None:
autoreview = script_dir / "autoreview"
for engine in engines:
print(f"== {engine} ==", flush=True)
command = [
sys.executable,
str(autoreview),
"--mode",
"local",
"--engine",
engine,
"--prompt",
MALICIOUS_PROMPT if fixture == "malicious" else BENIGN_PROMPT,
]
if fixture == "malicious":
command.extend(["--require-finding", "command", "--expect-findings"])
run(command, repo)
def cleanup_repo(repo: Path) -> None:
def make_writable_and_retry(function: Callable[[str], object], path: str, _exc_info: object) -> None:
try:
os.chmod(path, stat.S_IREAD | stat.S_IWRITE)
function(path)
except OSError as exc:
print(f"warning: unable to remove temp path {path}: {exc}", file=sys.stderr)
if not repo.exists():
return
try:
shutil.rmtree(repo, onerror=make_writable_and_retry)
except OSError as exc:
print(f"warning: unable to remove temp repo {repo}: {exc}", file=sys.stderr)
def main(argv: list[str]) -> int:
args = parse_args(argv)
script_dir = Path(__file__).resolve().parent
engines = args.engines or list(DEFAULT_ENGINES)
repo = Path(tempfile.mkdtemp(prefix="autoreview-fixture."))
try:
create_fixture_repo(repo, args.fixture)
run_reviews(repo, script_dir, args.fixture, engines)
except subprocess.CalledProcessError as exc:
return int(exc.returncode or 1)
finally:
cleanup_repo(repo)
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))

View File

@@ -98,7 +98,7 @@ Do not close from title alone. If closing as done on main or nonsensical, prove
When asked for `5 new`, exclude refs already surfaced in the session and refill from the archive until there are 5 live-open candidates. If fewer than 5 remain open, list all open ones and say how many short.
When asked to `update`, `refresh`, `recheck`, `check again`, or similar, return an updated live-open candidate list. Do not fill the main list with items that merely merged/closed since the last pass; put those numbers in a short bottom line.
When asked to `update`, `refresh`, `recheck`, `check again`, or similar, return an updated live-open candidate list. Sort by maintainer importance, not recency: high-impact ready fixes first, then useful-but-review-first, then open/not-ready items. Do not include a "changed since last pass" section or bottom-line merged/closed summary unless the user explicitly asks for churn.
Prefer:
@@ -142,18 +142,20 @@ No Markdown tables. Compact bullets. Use color/risk markers:
Required line shape:
```markdown
- **PR #81244** `@whatsskill.` `+118/-1` `bug` 🟢 verifiable: yes. This prevents chat action buttons from overlapping short assistant replies. Blast: web chat rendering, low.
- **Issue #81245** `@alice` `LOC n/a` `bug` 🟡 verifiable: partial. This reports duplicate Telegram replies when reconnecting after gateway restart. Blast: Telegram channel runtime, medium.
- **PR #81244** `@whatsskill.` `+118/-1` `bug` 🟢 https://github.com/openclaw/openclaw/pull/81244 - Prevents chat action buttons from overlapping short assistant replies. Verifiable: yes. Blast: web chat rendering, low.
- **Issue #81245** `@alice` `LOC n/a` `bug` 🟡 https://github.com/openclaw/openclaw/issues/81245 - Reports duplicate Telegram replies when reconnecting after gateway restart. Verifiable: partial. Blast: Telegram channel runtime, medium.
```
Rules:
- Bold the `PR #n` or `Issue #n` marker.
- Use `@handle`, not author bio text.
- Always include the full GitHub URL.
- Include a one-line description after the URL, separated with `-`.
- PR LOC is `+additions/-deletions`; issue LOC is `LOC n/a`.
- Type: `bug`, `feature`, `perf`, `security`, `docs`, `test`, `chore`, or `refactor`.
- Write a full sentence for what it does.
- Always include blast radius in one phrase.
- Always include `verifiable: yes|partial|no` plus the shortest proof hint when helpful.
- If status is not open, still show it only when the user asked for all surfaced refs; use ✅ or ⚪ and state merged/closed.
- For refresh-style asks, bottom line: `Merged/closed since last pass: #81016 merged, #81026 closed.` Omit if none.
- For refresh-style asks, prefer section order: `Best Open Now`, `Useful But Review First`, `Still Open / Not Ready`. Omit merged/closed churn by default.

View File

@@ -44,7 +44,9 @@ pnpm crabbox:run -- --help | sed -n '1,120p'
- OpenClaw scripts prefer `../crabbox/bin/crabbox` when present. The user PATH
shim can be stale.
- Check `.crabbox.yaml` for direct-provider defaults. Omitting `--provider`
means brokered AWS today.
means brokered AWS for normal Linux/macOS paths; the wrapper selects Azure
for unqualified Windows/WSL2 runs when the local Crabbox binary advertises
Azure.
- The brokered AWS default is a Linux developer image in `eu-west-1`; the repo
config pins hot `eu-west-1a/b/c` placement so Fast Snapshot Restore can apply.
If warmup drifts well past the minute-scale path, verify image promotion,
@@ -82,18 +84,16 @@ Use these only when the task needs an existing non-Linux host. OpenClaw broad
Linux validation uses the repo Crabbox config unless a provider is explicitly
requested.
Native brokered Windows is available for Windows-specific proof. Use the AWS
developer image in `us-west-2` on demand; it has the expected OpenClaw developer
toolchain and Docker image cache. Keep broad Linux gates on Linux/Testbox unless
the bug is Windows-specific:
Native brokered Windows is available for Windows-specific proof. Prefer Azure
for Windows/WSL2 when the subscription has quota or credits and the local
Crabbox binary advertises Azure. Keep broad Linux gates on Linux/Testbox unless
the bug is Windows-specific, and only force AWS when the operator asks for the
older AWS developer image/cache path or Azure is unavailable:
```sh
../crabbox/bin/crabbox warmup \
--provider aws \
pnpm crabbox:warmup -- \
--target windows \
--windows-mode normal \
--region us-west-2 \
--market on-demand \
--windows-mode wsl2 \
--timing-json
```
@@ -223,6 +223,21 @@ Read the JSON summary and the Testbox line. Useful fields:
- Actions run URL/id from the Testbox output
- `exitCode`
Use provider-backed cache volumes only for rebuildable caches, not secrets or
checkout state. On Blacksmith, Crabbox forwards them as sticky disks:
```sh
node scripts/crabbox-wrapper.mjs run \
--provider blacksmith-testbox \
--cache-volume pnpm-store=openclaw-node24-pnpm-lock:/tmp/openclaw-pnpm-store \
--timing-json \
-- \
corepack pnpm check:changed
```
The selected provider must advertise cache-volume support. If not, omit
`--cache-volume` and rely on kept-lease caches.
`blacksmith testbox list` may hide hydrating or ready boxes. Use:
```sh
@@ -292,7 +307,8 @@ Live-provider debug template for direct AWS/Hetzner leases:
```sh
mkdir -p .crabbox/logs
pnpm crabbox:run -- --provider aws \
CRABBOX_ENV_ALLOW=OPENAI_API_KEY,OPENAI_BASE_URL \
pnpm crabbox:run -- --provider aws \
--preflight \
--allow-env OPENAI_API_KEY,OPENAI_BASE_URL \
--timing-json \
@@ -304,10 +320,8 @@ pnpm crabbox:run -- --provider aws \
```
Do not pass `--capture-*`, `--download`, `--checksum`, `--force-sync-large`, or
`--sync-only` to delegated providers. Also do not pass `--script*`,
`--fresh-pr`, `--full-resync`, or `--env-helper` there. Crabbox rejects these
because the provider owns sync or command transport. `--keep-on-failure` is OK
for delegated one-shots when you need to inspect a failed lease.
`--sync-only` to delegated providers. Crabbox rejects them because the provider
owns sync or command transport.
## Efficient Bug E2E Verification
@@ -590,7 +604,8 @@ Crabbox Blacksmith backend delegates setup to:
The hydration workflow owns checkout, Node/pnpm setup, dependency install,
secrets, ready marker, and keepalive. Crabbox owns dispatch, sync, SSH command
execution, timing, logs/results, and cleanup.
execution, timing, logs/results, cleanup, and cache-volume requests. Blacksmith
implements cache volumes as sticky disks.
Minimal Blacksmith-backed Crabbox run, from repo root:
@@ -685,6 +700,7 @@ crabbox events <run_id> --json
crabbox logs <run_id>
crabbox results <run_id>
crabbox cache stats --id <id-or-slug>
crabbox cache volumes
crabbox ssh --id <id-or-slug>
blacksmith testbox list
```

View File

@@ -1,6 +1,6 @@
---
name: discrawl
description: "Discord archive: search, sync freshness, DMs, channel slices, SQL counts, and Discrawl repo work."
description: "Discord archive: search, sync freshness, DMs, summaries, TUI, repo/release work."
metadata:
openclaw:
homepage: https://github.com/openclaw/discrawl
@@ -16,29 +16,154 @@ metadata:
# Discrawl
Use local Discord archive data before live Discord APIs. Check freshness for recent/current questions:
Use local Discord archive data first for Discord questions. Hit Discord APIs
only when the archive is stale, missing the requested scope, or the user asks
for current external context.
## Sources
- DB: platform-native XDG data dir, usually
`${XDG_DATA_HOME:-~/.local/share}/discrawl/discrawl.db` on Linux or
`~/Library/Application Support/discrawl/discrawl.db` on macOS
- Config: platform-native XDG config dir, with legacy fallback to
`~/.discrawl/config.toml`
- Cache: platform-native XDG cache dir
- Logs: platform-native XDG state dir
- Git share repo: platform-native XDG data dir
- Repo: `openclaw/discrawl`; use `~/GIT/_Perso/discrawl` only after verifying
its remote targets `openclaw/discrawl`, otherwise use a fresh checkout
- Preferred CLI: `discrawl`; fallback to `go run ./cmd/discrawl` from the repo
if the installed binary is stale
## Freshness
For recent/current questions, check freshness before analysis:
```bash
discrawl status --json
```
For precise freshness from the default database:
```bash
# Discrawl uses macOS ~/Library defaults unless XDG_DATA_HOME is explicitly set.
case "$(uname -s)" in
Darwin)
db="$HOME/Library/Application Support/discrawl/discrawl.db"
;;
*)
db="${XDG_DATA_HOME:-$HOME/.local/share}/discrawl/discrawl.db"
;;
esac
sqlite3 "$db" \
"select coalesce(max(updated_at),'') from sync_state where scope like 'channel:%';"
```
Routine diagnostics:
```bash
discrawl doctor
```
Refresh only when stale or asked:
Desktop-local refresh:
```bash
discrawl sync --source wiretap
```
Bot API latest refresh, when credentials are available:
```bash
discrawl sync
```
Query with bounded slices:
Use `--full` only for deliberate historical backfills:
```bash
discrawl sync --full
```
If SQLite reports busy/locked, check for stray `discrawl` processes before retrying.
## Query Workflow
1. Resolve scope: guild, channel, DM, author, keyword, date range.
2. Check freshness for recent/current requests.
3. Prefer CLI search/messages for slices; use read-only SQL for exact counts.
4. Report absolute date spans, counts, channel/DM names, and known gaps.
Use root or subcommand help for syntax: `discrawl --help`,
`discrawl help search`, `discrawl search --help`. Use
`DISCRAWL_NO_AUTO_UPDATE=1` for read smokes when you do not want git-share
updates.
Common commands:
```bash
DISCRAWL_NO_AUTO_UPDATE=1 discrawl search --limit 20 "query"
discrawl messages --channel '#maintainers' --days 7 --all
discrawl dms --last 20
discrawl tui --dm
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) from messages;"
```
Report absolute date spans, channel/DM names, counts, and known gaps. Use read-only SQL for exact counts/rankings. Never use `--unsafe --confirm` unless the user explicitly requests a reviewed DB mutation.
## SQL
Boundaries: bot sync needs configured Discord bot credentials. Wiretap reads local Discord Desktop artifacts only; do not extract user tokens, call Discord as the user, or write to Discord storage. Git-share snapshots must not include secrets or `@me` DM rows.
Use `discrawl sql` for exact counts, joins, and ranking queries when normal
CLI reads are too coarse. The command is read-only by default, accepts SQL as
args or stdin, and supports `--json` for agent parsing.
Useful examples:
```bash
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) as messages from messages;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(c.name, ''), m.channel_id) as channel, count(*) as messages from messages m left join channels c on c.id = m.channel_id group by m.channel_id order by messages desc limit 20;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(mm.display_name, ''), nullif(mm.global_name, ''), nullif(mm.username, ''), m.author_id) as author, count(*) as messages from messages m left join members mm on mm.guild_id = m.guild_id and mm.user_id = m.author_id group by m.guild_id, m.author_id order by messages desc limit 20;"
```
Never use `--unsafe --confirm` unless the user explicitly asks for a database
mutation and the write has been reviewed.
When the installed CLI lacks a new feature, build or run from a verified
`openclaw/discrawl` checkout before concluding the feature is missing.
## Discord Boundaries
Bot API sync requires configured Discord bot credentials; do not invent token
availability. Desktop wiretap mode reads local Discord Desktop artifacts and
must not extract credentials, use user tokens, call Discord as the user, or
write to Discord application storage. Wiretap/Desktop cache DMs are local-only
and must not be described as part of the published Git snapshot. Git-share
snapshots must not include secrets or `@me` DM rows.
## Verification
For repo edits, prefer existing Go gates:
```bash
GOWORK=off go test ./...
```
Then run targeted CLI smoke for the touched surface, for example:
```bash
discrawl doctor
discrawl status --json
DISCRAWL_NO_AUTO_UPDATE=1 discrawl search --limit 5 "test"
```
## ClawSweeper Sandbox
Use the sandbox reader only:
```bash
discrawl-sandbox search --limit 20 "query"
discrawl-sandbox messages --channel clawtributors --days 7 --all
discrawl-sandbox status --json
```
This reader imports `https://github.com/openclaw/discord-store.git` into
`/root/clawsweeper-sandbox-workspace/.discrawl/discrawl.db` with
`discord.token_source = "none"`. The published Git snapshot is public-channel
filtered; do not use `/root/.discrawl/config.toml` or the rich writer DB from
sandboxed public Discord sessions.

View File

@@ -0,0 +1,202 @@
---
name: kysely-database-access
description: Use when adding, reviewing, or refactoring OpenClaw Kysely database access, native node:sqlite stores, generated DB types, SQLite schemas, migrations, raw SQL, transactions, or database access best practices.
---
# Kysely Database Access
Use this skill for OpenClaw database code that touches Kysely, `node:sqlite`,
generated DB types, SQLite schemas, migrations, or store/query design.
## Read First
- `docs/concepts/kysely.md` for the repo's Kysely rules and examples.
- The owning subtree `AGENTS.md`, if present.
- Relevant local Kysely source/types under `node_modules/kysely/dist/esm/...`
before assuming dialect behavior, result types, transactions, plugins, or raw
SQL semantics.
- For codegen behavior, inspect `scripts/generate-kysely-types.mjs` and
`kysely-codegen --help` from the repo package manager.
## Official Docs Cross-Check
When the behavior matters, verify against current Kysely docs/source before
patching:
- Generating types: production apps should keep schema types aligned with the
database through code generation.
- Data types: TypeScript types do not affect runtime values; the driver decides
runtime values, and Kysely returns what the driver returns unless a plugin
transforms results.
- Raw SQL: the `sql` tag can execute full raw SQL and embed snippets into
builders. Prefer typed builders/helpers when they express the same thing.
- Reusable helpers: take `Expression<T>` or an `ExpressionBuilder` when wrapping
SQL expressions; alias helper expressions explicitly in `select`. Extract a
helper only when it quarantines raw SQL, removes meaningful duplication, or
preserves a tricky inferred type.
- Split build/execute only at deliberate boundaries. Compiled-query execution
is useful for native sync adapters, but keep plugin/result-transform behavior
in mind.
- Migrations: Kysely migration files run without a schema type. In OpenClaw,
prefer the committed SQL-source-of-truth path unless a new owner explicitly
needs Kysely-managed migrations.
- Plugins: plugins can transform queries and results. Any sync shortcut that
bypasses Kysely's async executor needs a documented invariant or tests.
## Default Workflow
1. Identify the owner boundary:
- Core state DB: `src/state/*`
- Per-agent DB: `src/state/openclaw-agent-*`
- Feature store: owning `*.sqlite.ts` module
- Plugin-owned state: plugin/module owner, not generic core
2. Inspect the schema source first:
- `*.sql` is the source of truth when generated schema/types exist.
- Generated `*.generated.*` files are outputs, not hand-edit targets.
3. Prefer Kysely builders for normal CRUD:
- `selectFrom`, `insertInto`, `updateTable`, `deleteFrom`
- `executeTakeFirst`, `executeTakeFirstOrThrow`, `execute`
- `eb.fn.countAll`, `eb.fn.count`, `eb.fn.coalesce` for common functions
- Keep compile-time Kysely reference literals such as `"host"` and
`"flow_id as flowId"` when they are clearer than constants; they are
type-checked by Kysely.
- Let Kysely infer selected row shapes. Do not pass broad row generics to
sync helpers for normal builder queries.
- Treat `executeSqliteQuerySync<Row>(db, builder)` and
`executeSqliteQueryTakeFirstSync<Row>(db, builder)` as a smell: the generic
can lie about selected columns. Use no generic for builders; use an exact
raw boundary helper for raw SQL.
- For finite public query presets, use a preset-to-row type map plus a union
boundary type instead of `Record<string, ...>`.
- After touching Kysely/native SQLite code, run `pnpm lint:kysely`. The AST
guard rejects raw identifier helpers, unreviewed typed `sql<T>` snippets,
`db.dynamic`, explicit sync-helper row generics for builders, and new raw
`node:sqlite` runtime access outside owner allowlists. It also rejects
persisted enum-like casts in SQLite stores; keep row fields as `string` and
parse through closed validators.
4. Keep raw SQL deliberate:
- Good: pragmas, virtual tables, FTS, SQLite JSON functions, migrations,
`sqlite_master`, compact repeated expressions.
- Bad: raw `COUNT(*)` or dynamic SQL where Kysely has a typed builder shape.
- Use `${value}` parameters; use `sql.ref` / `sql.table` only for validated,
closed-set identifiers.
- Do not feed unconstrained runtime `string` values into table/column/group/
order/identifier positions. Narrow them to local unions or generated table
keys first.
- Prefer `eb.fn`, `eb.lit`, `eb.ref`, and expression callbacks for scalar
SQL such as `count`, `coalesce`, `max`, `exists`, and constant selections.
5. Align TypeScript with real driver values:
- Kysely does not coerce runtime values.
- Native `node:sqlite` returns BLOB columns as `Uint8Array`; convert with
`Buffer.from(...)` only at API boundaries that need Buffer helpers.
- Keep JSON/text/timestamp parsing at module boundaries.
- Keep persisted enum-like strings as `string` in row types, then parse them
through closed validator helpers such as `parseTaskStatus(value)`. Do not
cast corrupt persisted data into exported unions.
6. Decide migration need from shipped state:
- Unshipped schema/type cleanup: no SQLite migration.
- Shipped canonical schema change: add the appropriate migration or
doctor/fix repair path with tests.
- Legacy config repair belongs in doctor/fix paths, not startup surprises.
## Codegen
For committed SQL-backed generated types:
```bash
pnpm db:kysely:gen
pnpm db:kysely:check
```
The repo maps SQLite `blob` to `Uint8Array` through `kysely-codegen`
`--type-mapping`. Do not post-process generated files by hand; change the
generator or SQL source and regenerate.
## Native SQLite Guardrails
- Use `getNodeSqliteKysely(db)` and sync helpers from `src/infra/kysely-sync.ts`
for `DatabaseSync` stores.
- New direct `db.prepare(...)` / `db.exec(...)` runtime access should be rare.
Prefer Kysely or add an explicit `scripts/check-kysely-guardrails.mjs`
allowlist entry with a clear owner reason.
- If raw SQLite is repeated or cast-heavy, extract a narrow boundary helper
such as `assertSqliteIntegrityOk(db, message)` and allowlist that helper
instead of each caller.
- Keep sync helper result types derived from `CompiledQuery<Row>` / Kysely
builders. Explicit helper generics are for raw SQL or external boundaries,
not for widening a typed builder result into a generic record.
- Keep the native dialect in `src/infra/kysely-node-sqlite.ts` aligned with
Kysely's SQLite driver structure: single connection, mutex, SQLite adapter,
SQLite query compiler, SQLite introspector.
- Use `StatementSync.columns().length` behavior for row-returning statements;
do not parse SQL verbs.
- Return `insertId` only for changed Kysely insert nodes. Raw insert SQL and
ignored inserts must not expose stale `lastInsertRowid`.
- Remember that sync execution compiles through Kysely but bypasses async
`executeQuery` result plugins/logging. If plugins enter this path, add tests
or a documented invariant.
## Tests
Pick the smallest proof that covers the touched surface:
```bash
pnpm db:kysely:check
pnpm lint:kysely
pnpm test src/infra/kysely-node-sqlite.test.ts
pnpm test <owning-store>.test.ts
pnpm tsgo:core
```
Add or update focused tests for:
- generated type/runtime mismatches
- native dialect metadata (`insertId`, `numAffectedRows`, row-returning SQL)
- transactions/savepoints
- BLOB and JSON boundary conversions
- schema/codegen drift
- type inference contracts for sync helpers and public query result maps
- negative type contracts with `@ts-expect-error` for important column/preset
mistakes
- corruption-path tests that mutate SQLite directly and assert the public load
or read method rejects invalid persisted strings
- public store behavior, not just private SQL shape
## Helper Extraction
Good helpers:
- `readSqliteNumberPragma(db, pragma)` style helpers with a closed union for
PRAGMA names.
- Raw-expression helpers that accept Kysely expressions/refs instead of raw
column strings.
- Public query preset maps that preserve exact row types at the API boundary.
Avoid helpers that:
- Wrap obvious Kysely literals just to avoid strings.
- Take generic `string` table/column/order names.
- Return heavily generic query builders that are harder to type than the query
they hide.
## Performance
- Benchmark prepare/compile overhead before adding statement caches or compiled
query caches. Include the real public store method work: SQLite execution,
JSON/BLOB conversion, and result mapping.
- Keep caches local, close/dispose them with the owning store, and test invalid
or stale behavior. Clear builders are the default until numbers prove a hot
path.
## Avoid
- Do not introduce ORM/repository layers or hidden relation loading.
- Do not make root dependencies for plugin-only database needs.
- Do not migrate everything to raw SQL or everything to builders for purity.
- Do not hand-edit generated DB types.
- Do not hide finite query result shapes behind `Record<string, ...>` just to
make JSON output convenient; use exact row unions or map at the boundary.
- Do not replace every Kysely string literal with constants for aesthetics; fix
dynamic identifiers, raw SQL assertions, and public result boundaries instead.
- Do not add broad cache layers to hide repeated query/discovery work; carry the
known runtime fact earlier when possible.

View File

@@ -6,14 +6,16 @@ description: Regenerate OpenClaw release changelog sections from git history bef
# OpenClaw Changelog Update
Use this for release changelog rewrites and GitHub release-note source text.
Use it with `release-openclaw-maintainer`; this skill owns changelog content,
ordering, and audit discipline.
This is mandatory before every beta, beta rerun, stable release, or stable
rerun. Use it with `release-openclaw-maintainer`; this skill owns changelog
content, ordering, grouping, and attribution discipline.
## Goal
Rewrite the target `CHANGELOG.md` version section from history, not from stale
draft notes. Produce user-facing release notes sorted by user interest while
preserving issue/PR refs and thanks.
draft notes. Produce grouped user-facing release notes sorted by user interest
while preserving every relevant issue/PR ref and every human `Thanks @...`
attribution.
## Inputs
@@ -44,13 +46,35 @@ preserving issue/PR refs and thanks.
- `### Highlights`: 5-8 bullets, broad user wins first
- `### Changes`: new capabilities and behavior changes
- `### Fixes`: user-facing fixes first, grouped by impact and surface
- group related changes/fixes by surface and user impact; avoid one bullet
per tiny commit when several commits tell one user-facing story
6. Preserve attribution:
- keep `#issue`, `(#PR)`, `Fixes #...`, and `Thanks @...`
- every human-authored merged PR represented by a user-facing entry needs
its PR ref and `Thanks @author`, even when the PR had no linked issue
- every human issue reporter for a `Fixes #...` or referenced bug issue
represented by a user-facing entry needs `Thanks @reporter` unless the
same handle is already thanked in that bullet
- every human `Co-authored-by` contributor on represented user-facing work
needs `Thanks @handle` when a GitHub handle is known
- when grouping multiple PRs/issues in one bullet, include every relevant
PR/issue ref and every human contributor handle in that same bullet
- multiple `Thanks @...` handles in one bullet are expected; do not drop or
collapse contributor credit just because the note is grouped
- if one grouped bullet covers both direct commits and PRs, keep all PR refs
and thanks, plus any issue refs from the direct commits
- before finalizing, audit the final release-note body:
- extract all `#NNN` refs from the notes
- resolve which refs are PRs and collect human PR authors
- resolve issue refs used as bug/report refs and collect human reporters
- scan represented commits for `Co-authored-by`
- compare those handles to the final `Thanks @...` set
- fix every missing human credit or explicitly record why it is omitted
- do not add GHSA references, advisory IDs, or security advisory slugs to
changelog entries or GitHub release-note text unless explicitly requested
- never thank bots, `@openclaw`, `@clawsweeper`, or `@steipete`
- if grouping multiple entries, carry all relevant refs and thanks into the
grouped bullet
- do not use GitHub's release contributor count as the source of truth; the
changelog must carry the complete human credit set itself
7. Sorting preference:
- security/data-loss and content-boundary fixes
- transcript/replay/reply delivery correctness

View File

@@ -1,6 +1,6 @@
---
name: openclaw-ghsa-maintainer
description: Inspect, patch, validate, publish, or confirm OpenClaw GHSA security advisories and private-fork state.
description: "Inspect, patch, validate, publish, or confirm OpenClaw GHSA security advisories and private-fork state."
---
# OpenClaw GHSA Maintainer
@@ -85,3 +85,4 @@ jq -r .description < /tmp/ghsa.refetch.json | rg '\\\\n'
- Publishing fails with HTTP 422 if required fields are missing or the private fork still has open PRs.
- A payload that looks correct in shell can still be wrong if Markdown was assembled with escaped newline strings.
- Advisory PATCH sequencing matters; separate field updates when GHSA API constraints require it.
- Public hardening/no-publish comments and draft text should avoid raw commit hashes, PR titles/numbers, and fix-mechanism summaries. Prefer patched-version fields or release-only wording; keep SHAs, PRs, and implementation notes in internal evidence.

View File

@@ -75,7 +75,9 @@ OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test <path-or-filter>
```
Use targeted file paths whenever possible. Avoid raw `vitest`; use the repo
`pnpm test` wrapper so project routing, workers, and setup stay correct.
`pnpm test` wrapper so project routing, workers, and setup stay correct. If raw
Vitest is unavoidable, use `vitest run ...`; bare `vitest ...` starts local watch
mode and will not exit on its own.
When the checkout is a Codex worktree, prefer the direct node harness instead:
```bash
@@ -213,7 +215,7 @@ workflow only spends setup and queue time on that suite.
### Release Evidence
After release-candidate validation or before a release decision, record the
important run ids in the private `openclaw/releases-private` evidence ledger.
important run ids in the public `openclaw/releases` evidence ledger.
Use the manual `OpenClaw Release Evidence`
(`openclaw-release-evidence.yml`) workflow there. It writes durable summaries
under `evidence/<release-id>/` and commits:
@@ -236,13 +238,13 @@ short release-manager notes there. Do not store raw logs, provider
prompts/responses, channel transcripts, signing material, or secret-bearing
config in git; raw logs stay in Actions artifacts.
When `Full Release Validation` completes and
`OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN` is configured in the public repo, it
requests the private `OpenClaw Release Evidence From Full Validation` workflow.
That private workflow reads the parent full-validation run, extracts the child
CI/release-checks/Telegram run ids from the parent logs, and opens the evidence
PR automatically. If the token is absent or the run predates this wiring, trigger
that private workflow manually with the full-validation run id.
When `Full Release Validation` completes and `OPENCLAW_RELEASES_DISPATCH_TOKEN`
is configured in the source repo, it requests the public
`OpenClaw Release Evidence From Full Validation` workflow. That workflow reads
the parent full-validation run, extracts the child CI/release-checks/Telegram
run ids from the parent logs, and opens the evidence PR automatically. If the
token is absent or the run predates this wiring, trigger that workflow manually
with the full-validation run id.
### Release Checks

View File

@@ -0,0 +1,85 @@
---
name: release-openclaw-announcement
description: "Draft or post OpenClaw beta/stable Discord release announcements from changelog, GitHub release, registry, and validation evidence. Use when announcing a beta, stable release, release candidate, or asking what users should test after an OpenClaw release."
---
# OpenClaw Release Announcement
Use with `release-openclaw-maintainer` after a beta or stable release is live.
Use with `openclaw-discord` when actually posting to Discord.
## Evidence First
Before drafting focus areas, read real release evidence:
1. Current GitHub release body for the tag.
2. `CHANGELOG.md` section for the released base version.
3. Commits since the previous shipped version or the operator-specified base.
4. Registry/package metadata for the exact version and current dist-tag.
5. Validation status that is relevant to user confidence.
Do not claim a full changelog audit unless you did it. If you only read the
generated release notes or top changelog section, say that and either audit
properly or draft with that limitation.
For beta focus areas, prioritize user-observable changes over internal test or
CI mechanics:
- install/update paths
- OS/platform-specific behavior
- Gateway startup/restart, config, and runtime behavior
- provider/model/runtime routing
- plugin loading and local plugin development
- channels and media paths
- security/data-loss/user-impact fixes
Do not let late release-branch fixes automatically dominate the announcement.
If the version includes a large delta from the previous shipped version, rank
focus areas by the whole release delta and expected user impact; mention late
fixes in their natural category.
## Required Copy
Every beta announcement must make beta status explicit and include:
- exact version, e.g. `OpenClaw 2026.5.25-beta.1`
- one-sentence risk framing: beta, useful for testing, not stable promotion
- focused test areas derived from evidence, not guesswork
- update command promoted near the top:
```sh
openclaw update --channel beta --yes
openclaw --version
```
- fresh install path:
`Install from https://openclaw.ai`
- GitHub release link
- concise validation note, without making CI the headline
Do not suggest npm install commands in beta announcements unless the operator
explicitly asks for npm-specific copy or troubleshooting text. It is fine to use
registry metadata as evidence; do not turn that into public install guidance.
For stable announcements, use the stable channel wording:
```sh
openclaw update --channel stable --yes
openclaw --version
```
Fresh installs still point to `https://openclaw.ai`.
## Style
- Discord Markdown, no tables.
- Keep it skimmable: short intro, bullets, commands, links.
- Lead with what users can feel or test, not proof plumbing.
- Mention validation only after install/update instructions.
- Be specific about where feedback is useful.
- Do not mention private local proof paths in public announcements.
- Do not overstate unverified platforms, channels, or provider behavior.
## Posting
When asked to post, use the configured Discord workflow from
`openclaw-discord` or the approved OpenClaw relay. Never print tokens.
For public channels, inspect the final body before sending.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "OpenClaw Release Announcement"
short_description: "Draft Discord beta/stable release announcements from evidence."
default_prompt: "Use this skill to draft an OpenClaw beta or stable Discord announcement from changelog, release notes, npm/GitHub release proof, and validation evidence."

View File

@@ -21,6 +21,30 @@ function jsonGh(args) {
return JSON.parse(gh(args));
}
function githubRestJson(pathSuffix) {
const result = execFileSync(
"bash",
[
"-lc",
[
"set -euo pipefail",
'token="$(gh auth token)"',
'curl -fsS -H "Authorization: Bearer ${token}" -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" "${OPENCLAW_GITHUB_REST_URL}"',
].join("\n"),
],
{
encoding: "utf8",
env: {
...process.env,
OPENCLAW_GITHUB_REST_URL: `https://api.github.com/repos/${repo}/${pathSuffix}`,
},
maxBuffer: 16 * 1024 * 1024,
stdio: ["ignore", "pipe", "pipe"],
},
);
return JSON.parse(result);
}
function rate() {
try {
return jsonGh(["api", "rate_limit"]).resources.core;
@@ -59,12 +83,30 @@ for (const job of parent.jobs ?? []) {
}
const since = parent.createdAt;
const runList = gh([
"api",
`repos/${repo}/actions/runs?per_page=100`,
"--jq",
`.workflow_runs[] | select(.created_at >= "${since}") | select(.name=="CI" or .name=="OpenClaw Release Checks" or .name=="Plugin Prerelease" or .name=="NPM Telegram Beta E2E" or .name=="Full Release Validation") | [.id,.name,.status,.conclusion,.head_sha,.html_url] | @tsv`,
]).trim();
const runsQuery = new URLSearchParams({
per_page: "100",
created: `>=${since}`,
exclude_pull_requests: "true",
});
const childWorkflowNames = new Set([
"CI",
"OpenClaw Release Checks",
"Plugin Prerelease",
"NPM Telegram Beta E2E",
"Full Release Validation",
]);
const runs = githubRestJson(`actions/runs?${runsQuery.toString()}`).workflow_runs ?? [];
const runList = runs
.filter(
(run) =>
run.created_at >= since &&
run.head_sha === parent.headSha &&
childWorkflowNames.has(run.name),
)
.map((run) =>
[run.id, run.name, run.status, run.conclusion ?? "", run.head_sha, run.html_url].join("\t"),
)
.join("\n");
if (!runList) {
console.log("children: none found yet");

View File

@@ -69,9 +69,13 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
or clawgrit reports. Report regressions explicitly. A major regression is a
release blocker unless the operator waives it or the data clearly proves
infrastructure noise.
- Generate the changelog before version/tag preparation so the top changelog
section is deduped and ordered by user impact. Use
`$openclaw-changelog-update` for the rewrite.
- Generate the changelog before every beta, beta rerun, stable release, or
stable rerun, before version/tag preparation. Use
`$openclaw-changelog-update` for the rewrite. Do not continue release prep if
the target `CHANGELOG.md` section does not have `### Highlights`,
`### Changes`, and `### Fixes`, grouped by user-facing surface while
preserving every relevant PR/issue ref and every human `Thanks @...`
attribution in the grouped bullet.
- Do not create beta-specific `CHANGELOG.md` headings. Beta releases use the
stable base version section, for example `v2026.4.20-beta.1` uses
`## 2026.4.20` release notes.
@@ -144,6 +148,9 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
section from history, not existing notes. Use the last reachable stable or
beta release tag as the base, then inspect every commit through the target
release SHA.
- The changelog rewrite is not optional for beta reruns: any `beta.N` after a
rebase or backport must refresh the same stable-base `## YYYY.M.D` section
before the new version/tag commit.
- Include both merged PR commits and direct commits on `main`. Direct commits
matter: infer notes from their subject, body, touched files, linked issues,
tests, and nearby code when no PR body exists.
@@ -157,6 +164,11 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
- Add missed user-facing changes, remove internal-only noise, dedupe overlapping
PR/direct-commit entries, and sort each section from most to least interesting
for users.
- Group related highlights, changes, and fixes by user-facing surface and
impact, but never lose traceability: each grouped bullet keeps every relevant
`#issue`, `(#PR)`, `Fixes #...`, and every human `Thanks @...` handle.
Multiple thanks in one bullet are expected when multiple contributor PRs are
grouped.
- Changelog entries should be user-facing, not internal release-process notes.
- GitHub release and prerelease bodies must use the full matching
`CHANGELOG.md` version section, not highlights or an excerpt. When creating

View File

@@ -1,6 +1,6 @@
---
name: security-triage
description: Triage OpenClaw security advisories, drafts, and GHSA reports with shipped-tag and trust-model proof.
description: "Triage OpenClaw security advisories, drafts, and GHSA reports with shipped-tag and trust-model proof."
---
# Security Triage
@@ -87,11 +87,19 @@ When preparing a maintainer-ready close reply:
- exact reason for close
- exact code refs
- exact shipped tag / release facts
- exact fix commit or canonical duplicate GHSA when applicable
- fix provenance or canonical duplicate GHSA when applicable
- optional hardening note only if worthwhile and functionality-preserving
Keep tone firm, specific, non-defensive.
## Public Wording Hygiene
- Keep raw commit hashes, PR titles/numbers, and fix-mechanism summaries out of public advisory text. Use the patched release/version field only.
- Keep exact commit SHAs, PRs, and implementation notes in internal notes and verification files.
- For hardening/no-publish outcomes, do not add exploit-heavy details, "Fixed by" text, or a "Fix Commit(s)" section. Thank reporters, preserve credit, state the `SECURITY.md` boundary, and say clearly that the GHSA will close without publication.
- For published CVE/GHSA text, prefer `### Patched Versions` with the fixed release. Do not explain how the patch works unless Peter explicitly asks for that public detail.
- Keep GHSA ids out of changelog and release-note wording unless Peter explicitly asks.
## Discussion Mode
When Peter is manually posting GHSA comments, use this flow:

View File

@@ -0,0 +1,87 @@
---
name: verify-release
description: "Verify an OpenClaw release is fully published across GitHub, npm, plugins, ClawHub, package smoke, and live Gateway agent turns."
---
# Verify Release
Use this when asked whether an OpenClaw release is fully released, published,
promoted, smoke-tested, or live-verified. This is a verification skill, not a
publish skill; use `$release-openclaw-maintainer` before changing release state.
## Rules
- Resolve short suffixes like `.27` to the concrete CalVer version from the
current date/context, then say the resolved version.
- Verify live state. Do not trust local checkout state, release notes, or old
memory as current truth.
- If the checkout is dirty or divergent, use it only for scripts/reference.
For version metadata, fetch from GitHub release/tag or unpack the tag tarball
under `/tmp`.
- Never print secrets. Use inherited live keys only for scoped smoke commands.
- Keep the final terse: `yes/no`, evidence bullets, caveats, cleanup.
## Core Checks
1. GitHub release:
- `gh release view v<VERSION> --repo openclaw/openclaw --json tagName,name,publishedAt,isDraft,isPrerelease,targetCommitish,url,body,assets`
- Confirm stable releases are not draft/prerelease.
- Confirm release body has npm, CI, plugin npm, ClawHub, mac/appcast evidence
links when expected.
- Confirm assets expected for stable mac releases are uploaded: zip, dmg,
dSYM, dependency evidence when present.
2. Root npm:
- `npm view openclaw@<VERSION> version dist-tags.latest dist.tarball dist.integrity time.<VERSION> --json`
- `latest` must equal `<VERSION>` for stable.
- Record tarball, integrity, publish time.
3. Plugin publish set:
- Get exact tag metadata from GitHub, not the local checkout when dirty:
download `https://api.github.com/repos/openclaw/openclaw/tarball/v<VERSION>`
into `/tmp/openclaw-v<VERSION>-src`.
- Count `extensions/*/package.json` with
`openclaw.release.publishToNpm === true` and
`openclaw.release.publishToClawHub === true`.
- Compare expected counts to workflow job counts:
`gh api repos/openclaw/openclaw/actions/runs/<RUN>/jobs --paginate`.
- Each expected npm plugin must have version `<VERSION>` and
`dist-tags.latest === <VERSION>`.
4. ClawHub:
- Check the Plugin ClawHub Release workflow conclusion and publish job count.
- Use OpenClaw itself for live registry proof:
`openclaw plugins search <known-plugin> --json`.
- Install one official plugin from ClawHub in an isolated HOME:
`openclaw plugins install clawhub:@openclaw/matrix --pin`.
Prefer `matrix` unless that plugin is not in the expected set.
5. Release workflows:
- Verify conclusions for release notes evidence links:
Full Release Validation, OpenClaw Release Checks, OpenClaw NPM Release,
Plugin NPM Release, Plugin ClawHub Release, mac preflight/validation/publish
when stable mac assets are expected.
- Summarize only relevant successful/failed jobs; ignore routine skipped
optional lanes unless the release body promised them.
6. Published package smoke:
- In `/tmp`, isolated HOME:
`npm exec --yes --package openclaw@<VERSION> -- openclaw --version`.
- Run at least one harmless command that touches the published CLI surface,
for example `plugins --help` or `gateway --help`.
7. Dev Gateway live model smoke:
- Use temp HOME/workspace, not the user's normal state:
`HOME=/tmp/openclaw-release-smoke/home OPENCLAW_WORKSPACE=/tmp/openclaw-release-smoke/work pnpm openclaw --dev gateway run --auth none --force --verbose`.
- Health check via CLI: `openclaw --dev gateway health --json`.
- Run one Gateway-backed agent turn with inherited `OPENAI_API_KEY`, short
prompt, explicit session key, JSON output, and a known-available model.
- If the configured default model fails as unavailable, record that caveat
and retry with the newest known-good OpenAI model instead of declaring the
release failed.
- Stop the gateway and verify the port is not listening.
## Caveats To Report
- Dist-tag caveat: stable `latest` is release truth; if optional `beta` mirrors
still point at a beta version, report it as a caveat, not a stable-release
blocker, unless the user asked to verify beta promotion.
- Divergent checkout caveat: say when local source SHA differs from release tag
or origin and which live sources were used instead.
- Smoke caveat: distinguish Gateway-backed agent success from local embedded
fallback. A valid Gateway smoke has health OK plus gateway log/run id for the
agent call.

View File

@@ -1,21 +1,15 @@
profile: openclaw-check
provider: aws
# Default OpenClaw runner spend to the Azure-backed Crabbox account.
# Use `--provider aws` only for AWS-specific runner proof.
provider: azure
class: standard
capacity:
market: spot
strategy: most-available
fallback: on-demand-after-120s
# Fail closed instead of silently falling back to on-demand while the
# Azure-backed billing account is the default runner path.
fallback: spot-only
hints: true
availabilityZones:
- eu-west-1a
- eu-west-1b
- eu-west-1c
regions:
- eu-west-1
- eu-west-2
- eu-central-1
- us-east-1
- us-west-2
actions:
workflow: .github/workflows/crabbox-hydrate.yml
# Default AWS hydration uses local Actions replay. Use
@@ -29,7 +23,14 @@ actions:
- openclaw
runnerVersion: latest
ephemeral: true
blacksmith:
org: openclaw
workflow: .github/workflows/ci-check-testbox.yml
job: check
ref: main
aws:
# AWS-specific overrides still pin direct `--provider aws` runs without
# leaking AWS region names into the Azure default capacity fallback list.
region: eu-west-1
rootGB: 400
sync:

3
.gitattributes vendored
View File

@@ -1,3 +1,6 @@
* text=auto eol=lf
CLAUDE.md -text
src/gateway/server-methods/CLAUDE.md -text
ui/src/i18n/.i18n/* linguist-generated
ui/src/i18n/locales/*.ts linguist-generated
ui/src/i18n/locales/en.ts -linguist-generated

8
.github/CODEOWNERS vendored
View File

@@ -11,8 +11,10 @@
/.github/workflows/codeql.yml @openclaw/openclaw-secops
/.github/workflows/codeql-android-critical-security.yml @openclaw/openclaw-secops
/.github/workflows/codeql-critical-quality.yml @openclaw/openclaw-secops
/.github/workflows/dependency-change-awareness.yml @openclaw/openclaw-secops
/test/scripts/dependency-change-awareness-workflow.test.ts @openclaw/openclaw-secops
/.github/workflows/dependency-guard.yml @openclaw/openclaw-secops
/test/scripts/dependency-guard-workflow.test.ts @openclaw/openclaw-secops
/test/scripts/dependency-guard-script.test.ts @openclaw/openclaw-secops
/scripts/github/dependency-guard.mjs @openclaw/openclaw-secops
/package-lock.json @openclaw/openclaw-secops
/npm-shrinkwrap.json @openclaw/openclaw-secops
/extensions/*/package-lock.json @openclaw/openclaw-secops
@@ -29,7 +31,7 @@
/src/gateway/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/security-path*.ts @openclaw/openclaw-secops
/src/gateway/resolve-configured-secret-input-string*.ts @openclaw/openclaw-secops
/src/gateway/protocol/**/*secret*.ts @openclaw/openclaw-secops
/packages/gateway-protocol/src/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/server-methods/secrets*.ts @openclaw/openclaw-secops
/src/agents/*auth*.ts @openclaw/openclaw-secops
/src/agents/**/*auth*.ts @openclaw/openclaw-secops

View File

@@ -11,6 +11,8 @@ body:
Do not speculate or infer beyond the evidence. If a narrative section cannot be answered from the available evidence, respond with exactly `NOT_ENOUGH_INFO`.
If this is a plugin beta-release blocker, rename the issue title to `Beta blocker: <plugin-name> - <summary>` and apply the `beta-blocker` label after filing.
Please only report one issue per submission. Break multiple issues up into separate submissions.
- type: dropdown
id: bug_type
attributes:

View File

@@ -14,6 +14,10 @@ self-hosted-runner:
- blacksmith-16vcpu-ubuntu-2404-arm
- blacksmith-6vcpu-macos-latest
- blacksmith-12vcpu-macos-latest
- blacksmith-6vcpu-macos-15
- blacksmith-12vcpu-macos-15
- blacksmith-6vcpu-macos-26
- blacksmith-12vcpu-macos-26
# Ignore patterns for known issues
paths:

View File

@@ -35,17 +35,29 @@ runs:
exit 0
fi
# Check if any changed file is a doc
DOCS=$(echo "$CHANGED" | grep -E '^docs/|\.md$|\.mdx$' || true)
if [ -n "$DOCS" ]; then
docs_changed=false
non_docs=false
while IFS= read -r changed_path; do
case "$changed_path" in
test/fixtures/*)
non_docs=true
;;
docs/* | *.md | *.mdx)
docs_changed=true
;;
*)
non_docs=true
;;
esac
done <<< "$CHANGED"
if [ "$docs_changed" = "true" ]; then
echo "docs_changed=true" >> "$GITHUB_OUTPUT"
else
echo "docs_changed=false" >> "$GITHUB_OUTPUT"
fi
# Check if all changed files are docs or markdown
NON_DOCS=$(echo "$CHANGED" | grep -vE '^docs/|\.md$|\.mdx$' || true)
if [ -z "$NON_DOCS" ]; then
if [ "$non_docs" = "false" ]; then
echo "docs_only=true" >> "$GITHUB_OUTPUT"
echo "Docs-only change detected — skipping heavy jobs"
else

View File

@@ -38,9 +38,15 @@ runs:
exit 0
fi
fetch_base_ref() {
timeout --signal=TERM --kill-after=10s 30s git \
-c protocol.version=2 \
fetch "$@"
}
for deepen_by in 25 100 300; do
echo "Base commit missing; deepening $FETCH_REF by $deepen_by."
if ! git fetch --no-tags --deepen="$deepen_by" origin -- "$FETCH_REF"; then
if ! fetch_base_ref --no-tags --deepen="$deepen_by" origin -- "$FETCH_REF"; then
echo "::warning title=ensure-base-commit fetch failed::Failed to deepen $FETCH_REF by $deepen_by while looking for $BASE_SHA"
fi
if git rev-parse --verify "$BASE_SHA^{commit}" >/dev/null 2>&1; then
@@ -50,7 +56,7 @@ runs:
done
echo "Base commit still missing; fetching full history for $FETCH_REF."
if ! git fetch --no-tags origin -- "$FETCH_REF"; then
if ! fetch_base_ref --no-tags origin -- "$FETCH_REF"; then
echo "::warning title=ensure-base-commit fetch failed::Failed to fetch full history for $FETCH_REF while looking for $BASE_SHA"
fi
if git rev-parse --verify "$BASE_SHA^{commit}" >/dev/null 2>&1; then

View File

@@ -20,9 +20,13 @@ inputs:
required: false
default: "true"
use-actions-cache:
description: Whether to restore and save the pnpm store with actions/cache.
description: Whether to restore the pnpm store with actions/cache.
required: false
default: "true"
save-actions-cache:
description: Whether to save the pnpm store with actions/cache after install when no exact cache restored.
required: false
default: "false"
runs:
using: composite
steps:
@@ -45,6 +49,7 @@ runs:
openclaw_ensure_node "$REQUESTED_NODE_VERSION"
- name: Setup pnpm
id: setup-pnpm
uses: ./.github/actions/setup-pnpm-store-cache
with:
node-version: ${{ inputs.node-version }}
@@ -130,3 +135,10 @@ runs:
ln -sfn "$PNPM_CONFIG_MODULES_DIR" node_modules
ln -sfn . "$PNPM_CONFIG_MODULES_DIR/node_modules"
fi
- name: Save pnpm store cache
if: ${{ inputs.install-deps == 'true' && inputs.use-actions-cache == 'true' && inputs.save-actions-cache == 'true' && runner.os != 'Windows' && steps.setup-pnpm.outputs.store-cache-hit != 'true' }}
uses: actions/cache/save@v5
with:
path: ${{ steps.setup-pnpm.outputs.store-path }}
key: ${{ steps.setup-pnpm.outputs.store-cache-primary-key }}

View File

@@ -14,7 +14,7 @@ inputs:
required: false
default: ""
use-actions-cache:
description: Whether actions/cache should cache the pnpm store.
description: Whether actions/cache should restore the pnpm store.
required: false
default: "true"
outputs:
@@ -24,6 +24,15 @@ outputs:
project-dir:
description: Directory containing the packageManager file used for pnpm resolution.
value: ${{ steps.setup-pnpm.outputs.project-dir }}
store-cache-hit:
description: Whether the pnpm store cache restored an exact key.
value: ${{ steps.pnpm-store-cache.outputs.cache-hit }}
store-cache-primary-key:
description: Exact pnpm store cache key used for restore/save.
value: ${{ steps.pnpm-store-cache.outputs.cache-primary-key }}
store-path:
description: Resolved pnpm store path.
value: ${{ steps.pnpm-store.outputs.path }}
runs:
using: composite
steps:
@@ -81,14 +90,15 @@ runs:
echo "path=$store_path" >> "$GITHUB_OUTPUT"
- name: Restore pnpm store cache
id: pnpm-store-cache
if: ${{ inputs.use-actions-cache == 'true' && runner.os != 'Windows' }}
uses: actions/cache@v5
uses: actions/cache/restore@v5
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: pnpm-store-${{ runner.os }}-${{ inputs.node-version }}-${{ hashFiles(inputs.lockfile-path) }}
key: pnpm-store-${{ runner.os }}-${{ runner.arch }}-${{ inputs.node-version }}-${{ hashFiles(inputs.package-manager-file) }}-${{ hashFiles(inputs.lockfile-path) }}
restore-keys: |
pnpm-store-${{ runner.os }}-${{ inputs.node-version }}-
pnpm-store-${{ runner.os }}-
pnpm-store-${{ runner.os }}-${{ runner.arch }}-${{ inputs.node-version }}-${{ hashFiles(inputs.package-manager-file) }}-
pnpm-store-${{ runner.os }}-${{ runner.arch }}-${{ inputs.node-version }}-
- name: Record pnpm version
id: pnpm-version

View File

@@ -53,14 +53,16 @@ openclaw_active_node_version() {
openclaw_prepend_node_bin() {
local node_bin_dir="$1"
local github_path_dir="${2:-$node_bin_dir}"
local shell_node_bin_dir="$node_bin_dir"
if command -v cygpath >/dev/null 2>&1; then
shell_node_bin_dir="$(cygpath -u "$node_bin_dir" 2>/dev/null || printf '%s' "$node_bin_dir")"
fi
export PATH="$shell_node_bin_dir:$PATH"
if [[ -n "${GITHUB_PATH:-}" ]]; then
local github_node_bin_dir="$shell_node_bin_dir"
if command -v cygpath >/dev/null 2>&1; then
local github_node_bin_dir="$github_path_dir"
if [[ $# -lt 2 ]] && command -v cygpath >/dev/null 2>&1; then
github_node_bin_dir="$shell_node_bin_dir"
github_node_bin_dir="$(cygpath -w "$shell_node_bin_dir" 2>/dev/null || printf '%s' "$shell_node_bin_dir")"
fi
echo "$github_node_bin_dir" >> "$GITHUB_PATH"
@@ -93,7 +95,7 @@ openclaw_find_toolcache_node() {
done
local node_root candidate candidate_version
for node_root in "${roots[@]}"; do
for node_root in ${roots[@]+"${roots[@]}"}; do
while IFS= read -r candidate; do
candidate_version="$("$candidate" -p 'process.versions.node' 2>/dev/null || true)"
if openclaw_node_version_matches "$candidate_version" "$requested_node"; then
@@ -139,6 +141,7 @@ openclaw_node_download_platform() {
MINGW*:x86_64 | MSYS*:x86_64 | CYGWIN*:x86_64 | MINGW*:AMD64 | MSYS*:AMD64 | CYGWIN*:AMD64)
printf 'win-x64\n'
;;
MINGW*:aarch64 | MINGW*:arm64 | MSYS*:aarch64 | MSYS*:arm64 | CYGWIN*:aarch64 | CYGWIN*:arm64) printf 'win-arm64\n' ;;
*)
return 1
;;
@@ -147,31 +150,47 @@ openclaw_node_download_platform() {
openclaw_download_node() {
local requested_node="$1"
local version platform archive_url install_root
local version platform archive_url install_root temp_root
version="$(openclaw_resolve_node_download_version "$requested_node")"
platform="$(openclaw_node_download_platform)" || return 1
install_root="${RUNNER_TEMP:-/tmp}/openclaw-node-${version}-${platform}"
mkdir -p "$install_root"
temp_root="${RUNNER_TEMP:-/tmp}"
if command -v cygpath >/dev/null 2>&1; then
temp_root="$(cygpath -u "$temp_root" 2>/dev/null || printf '%s\n' "$temp_root")"
fi
install_root="${temp_root}/openclaw-node-${version}-${platform}"
if [[ "$platform" == win-* ]]; then
local archive_path
local archive_path ps_archive_path ps_install_root ps_bin_dir node_bin_dir
archive_path="${temp_root}/node-${version}-${platform}.zip"
archive_url="https://nodejs.org/dist/${version}/node-${version}-${platform}.zip"
archive_path="${RUNNER_TEMP:-/tmp}/node-${version}-${platform}.zip"
rm -rf "$install_root"
mkdir -p "$install_root"
echo "Downloading Node ${version} from ${archive_url}"
curl -fsSL "$archive_url" -o "$archive_path"
if command -v powershell.exe >/dev/null 2>&1 && command -v cygpath >/dev/null 2>&1; then
powershell.exe -NoLogo -NoProfile -Command \
"Expand-Archive -LiteralPath '$(cygpath -w "$archive_path")' -DestinationPath '$(cygpath -w "$install_root")' -Force"
curl -fsSL -o "$archive_path" "$archive_url"
ps_archive_path="$archive_path"
ps_install_root="$install_root"
if command -v cygpath >/dev/null 2>&1; then
ps_archive_path="$(cygpath -w "$archive_path")"
ps_install_root="$(cygpath -w "$install_root")"
fi
ps_bin_dir="$ps_install_root\\node-${version}-${platform}"
node_bin_dir="$install_root/node-${version}-${platform}"
if command -v pwsh >/dev/null 2>&1; then
pwsh -NoLogo -NoProfile -Command "Expand-Archive -LiteralPath '${ps_archive_path}' -DestinationPath '${ps_install_root}' -Force"
openclaw_prepend_node_bin "$node_bin_dir" "$ps_bin_dir"
elif command -v powershell.exe >/dev/null 2>&1; then
powershell.exe -NoLogo -NoProfile -Command "Expand-Archive -LiteralPath '${ps_archive_path}' -DestinationPath '${ps_install_root}' -Force"
openclaw_prepend_node_bin "$node_bin_dir" "$ps_bin_dir"
else
unzip -q "$archive_path" -d "$install_root"
openclaw_prepend_node_bin "$node_bin_dir"
fi
openclaw_prepend_node_bin "$install_root/node-${version}-${platform}"
return 0
else
archive_url="https://nodejs.org/dist/${version}/node-${version}-${platform}.tar.xz"
mkdir -p "$install_root"
echo "Downloading Node ${version} from ${archive_url}"
curl -fsSL "$archive_url" | tar -xJ -C "$install_root" --strip-components=1
openclaw_prepend_node_bin "$install_root/bin"
fi
archive_url="https://nodejs.org/dist/${version}/node-${version}-${platform}.tar.xz"
echo "Downloading Node ${version} from ${archive_url}"
curl -fsSL "$archive_url" | tar -xJ -C "$install_root" --strip-components=1
openclaw_prepend_node_bin "$install_root/bin"
}
openclaw_ensure_node() {

View File

@@ -17,7 +17,8 @@ paths:
- src/acp/control-plane
- src/agents/command
- src/agents/cli-runner
- src/agents/pi-embedded-runner
- src/agents/embedded-agent-runner
- src/agents/sessions
- src/agents/tools
- src/agents/*completion*.ts
- src/agents/*transport*.ts

View File

@@ -19,7 +19,7 @@ paths:
- src/config/types.channel*.ts
- src/gateway/server-channel*.ts
- src/gateway/server-methods/channels.ts
- src/gateway/protocol/schema/channels.ts
- packages/gateway-protocol/src/schema/channels.ts
- src/infra/channel-*.ts
- src/infra/exec-approval-channel-runtime.ts
- src/infra/outbound/channel-*.ts

View File

@@ -22,13 +22,15 @@ paths:
- src/agents/sandbox
- src/agents/sandbox.ts
- src/agents/sandbox-*.ts
- src/agents/sessions/*auth*.ts
- src/agents/sessions/**/*auth*.ts
- src/cron/service/jobs.ts
- src/cron/stagger.ts
- src/gateway/*auth*.ts
- src/gateway/**/*auth*.ts
- src/gateway/*secret*.ts
- src/gateway/**/*secret*.ts
- src/gateway/protocol/**/*secret*.ts
- packages/gateway-protocol/src/**/*secret*.ts
- src/gateway/resolve-configured-secret-input-string*.ts
- src/gateway/security-path*.ts
- src/gateway/server-methods/secrets*.ts

View File

@@ -30,7 +30,7 @@ paths:
- src/gateway/**/*auth*.ts
- src/gateway/*secret*.ts
- src/gateway/**/*secret*.ts
- src/gateway/protocol/**/*secret*.ts
- packages/gateway-protocol/src/**/*secret*.ts
- src/gateway/resolve-configured-secret-input-string*.ts
- src/gateway/security-path*.ts
- src/gateway/server-methods/secrets*.ts

View File

@@ -15,7 +15,7 @@ query-filters:
paths:
- src/gateway/method-scopes.ts
- src/gateway/protocol
- packages/gateway-protocol/src
- src/gateway/server-methods
- src/gateway/server-methods.ts
- src/gateway/server-methods-list.ts

View File

@@ -24,14 +24,15 @@ paths:
- src/agents/openclaw-plugin-tools.ts
- src/agents/openclaw-tools.runtime.ts
- src/agents/openclaw-tools.registration.ts
- src/agents/pi-tool-definition-adapter.ts
- src/agents/pi-tools.abort.ts
- src/agents/pi-tools.before-tool-call*.ts
- src/agents/pi-tools.host-edit.ts
- src/agents/pi-tools-parameter-schema.ts
- src/agents/pi-embedded-runner/effective-tool-policy.ts
- src/agents/pi-embedded-runner/tool-name-allowlist.ts
- src/agents/pi-embedded-runner/tool-schema-runtime.ts
- src/agents/agent-tool-definition-adapter.ts
- src/agents/agent-tools.abort.ts
- src/agents/agent-tools.before-tool-call*.ts
- src/agents/agent-tools.read.ts
- src/agents/agent-tools-parameter-schema.ts
- src/agents/sessions/tools/**
- src/agents/embedded-agent-runner/effective-tool-policy.ts
- src/agents/embedded-agent-runner/tool-name-allowlist.ts
- src/agents/embedded-agent-runner/tool-schema-runtime.ts
- src/agents/tools/gateway-tool.ts
- src/agents/tools/message-tool.ts
- src/agents/tools/sessions-send-tool.ts

View File

@@ -7,8 +7,17 @@ queries:
- uses: ./.github/codeql/openclaw-boundary/queries/managed-proxy-runtime-mutation.ql
paths:
- src
- extensions
- src/cli/gateway-cli/run-loop.ts
- src/infra/gateway-lock.ts
- src/infra/jsonl-socket.ts
- src/infra/net
- src/infra/push-apns-http2.ts
- src/infra/ssh-tunnel.ts
- src/proxy-capture
- extensions/codex-supervisor/src/json-rpc-client.ts
- extensions/irc/src
- extensions/qa-lab/src
- packages/net-policy/src
paths-ignore:
- "**/node_modules"

View File

@@ -15,7 +15,6 @@ query-filters:
paths:
- src/infra/net
- src/shared/net
- src/agents/tools/web-fetch.ts
- src/agents/tools/web-guarded-fetch.ts
- src/agents/tools/web-shared.ts
@@ -23,6 +22,7 @@ paths:
- src/web-fetch
- src/web/provider-runtime-shared.ts
- packages/memory-host-sdk/src/host/ssrf-policy.ts
- packages/net-policy/src
paths-ignore:
- "**/node_modules"

View File

@@ -76,6 +76,8 @@ predicate allowedRawSocketClientCall(Expr call) {
or
allowedOwnerScope(call, "src/proxy-capture/proxy-server.ts", "startDebugProxyServer")
or
allowedOwnerScope(call, "extensions/codex-supervisor/src/json-rpc-client.ts", "connectCodexSupervisorUnixSocket")
or
allowedOwnerScope(call, "extensions/irc/src/client.ts", "connectIrcClient")
or
allowedOwnerScope(call, "extensions/qa-lab/src/lab-server-capture.ts", "probeTcpReachability")

41
.github/labeler.yml vendored
View File

@@ -10,6 +10,11 @@
- "extensions/file-transfer/**"
- "docs/nodes/index.md"
- "docs/plugins/sdk-runtime.md"
"plugin: pixverse":
- changed-files:
- any-glob-to-any-file:
- "extensions/pixverse/**"
- "docs/providers/pixverse.md"
"channel: discord":
- changed-files:
- any-glob-to-any-file:
@@ -42,6 +47,12 @@
- "extensions/meeting-notes/**"
- "docs/plugins/meeting-notes.md"
- "src/meeting-notes/**"
"plugin: workboard":
- changed-files:
- any-glob-to-any-file:
- "extensions/workboard/**"
- "docs/plugins/workboard.md"
- "docs/plugins/reference/workboard.md"
"plugin: migrate-hermes":
- changed-files:
- any-glob-to-any-file:
@@ -121,6 +132,11 @@
- any-glob-to-any-file:
- "extensions/slack/**"
- "docs/channels/slack.md"
"channel: sms":
- changed-files:
- any-glob-to-any-file:
- "extensions/sms/**"
- "docs/channels/sms.md"
"channel: synology-chat":
- changed-files:
- any-glob-to-any-file:
@@ -183,7 +199,7 @@
- "ui/**"
- "src/gateway/control-ui.ts"
- "src/gateway/control-ui-shared.ts"
- "src/gateway/protocol/**"
- "packages/gateway-protocol/src/**"
- "src/gateway/server-methods/chat.ts"
- "src/infra/control-ui-assets.ts"
@@ -191,6 +207,7 @@
- changed-files:
- any-glob-to-any-file:
- "src/gateway/**"
- "packages/gateway-protocol/src/**"
- "src/daemon/**"
- "docs/gateway/**"
@@ -343,6 +360,11 @@
- any-glob-to-any-file:
- "extensions/deepinfra/**"
- "docs/providers/deepinfra.md"
"extensions: gmi":
- changed-files:
- any-glob-to-any-file:
- "extensions/gmi/**"
- "docs/providers/gmi.md"
"extensions: tencent":
- changed-files:
- any-glob-to-any-file:
@@ -393,6 +415,17 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/codex/**"
"extensions: codex-supervisor":
- changed-files:
- any-glob-to-any-file:
- "extensions/codex-supervisor/**"
- "docs/plugins/reference/codex-supervisor.md"
- "docs/specs/claw-supervisor.md"
"extensions: copilot":
- changed-files:
- any-glob-to-any-file:
- "extensions/copilot/**"
- "docs/plugins/copilot.md"
"extensions: kimi-coding":
- changed-files:
- any-glob-to-any-file:
@@ -413,6 +446,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/nvidia/**"
"extensions: novita":
- changed-files:
- any-glob-to-any-file:
- "extensions/novita/**"
- "docs/providers/novita.md"
"extensions: phone-control":
- changed-files:
- any-glob-to-any-file:
@@ -491,6 +529,7 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/diffs/**"
- "extensions/diffs-language-pack/**"
"extensions: elevenlabs":
- changed-files:
- any-glob-to-any-file:

View File

@@ -27,7 +27,7 @@ jobs:
timeout-minutes: 35
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
with:
testbox_id: ${{ inputs.testbox_id }}
@@ -188,7 +188,10 @@ jobs:
run: |
set -euo pipefail
git fetch --no-tags --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"
timeout --signal=TERM --kill-after=10s 30s git \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=50 origin \
"+refs/heads/main:refs/remotes/origin/main"
node_bin="$(dirname "$(node -p 'process.execPath')")"
sudo ln -sf "$node_bin/node" /usr/local/bin/node
@@ -228,7 +231,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -15,6 +15,9 @@ permissions:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
PNPM_CONFIG_MODULES_DIR: "/tmp/openclaw-pnpm-node-modules"
PNPM_CONFIG_STORE_DIR: "/tmp/openclaw-pnpm-store"
PNPM_CONFIG_VIRTUAL_STORE_DIR: "/tmp/openclaw-pnpm-virtual-store"
jobs:
check:
@@ -26,7 +29,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
with:
testbox_id: ${{ inputs.testbox_id }}
- name: Checkout
@@ -89,7 +92,10 @@ jobs:
run: |
set -euo pipefail
git fetch --no-tags --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"
timeout --signal=TERM --kill-after=10s 30s git \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=50 origin \
"+refs/heads/main:refs/remotes/origin/main"
node_bin="$(dirname "$(node -p 'process.execPath')")"
sudo ln -sf "$node_bin/node" /usr/local/bin/node
@@ -130,7 +136,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -28,7 +28,7 @@ permissions:
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-manual-v1-{1}', github.workflow, github.run_id) || (github.event_name == 'pull_request' && format('{0}-v7-{1}', github.workflow, github.event.pull_request.number) || (github.repository == 'openclaw/openclaw' && format('{0}-v7-{1}', github.workflow, github.ref) || format('{0}-v7-{1}-{2}', github.workflow, github.ref, github.sha))) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && github.repository == 'openclaw/openclaw' && github.ref == 'refs/heads/main') }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -79,12 +79,46 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_REF: ${{ inputs.target_ref || github.sha }}
CHECKOUT_FALLBACK_REF: ${{ github.sha }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_REF}:refs/remotes/origin/checkout"
fetch_checkout_ref() {
local ref="$1"
local fetch_status
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${ref}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
return "$fetch_status"
fi
if [ "$attempt" = "3" ]; then
return "$fetch_status"
fi
echo "::warning::checkout fetch for '$ref' timed out on attempt $attempt; retrying"
sleep 5
done
}
if fetch_checkout_ref "$CHECKOUT_REF"; then
:
else
fetch_status="$?"
if [ "$fetch_status" = "124" ] || [ "$fetch_status" = "137" ]; then
echo "::error::checkout fetch for '$CHECKOUT_REF' timed out"
exit "$fetch_status"
fi
if [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ] || [ "$CHECKOUT_REF" = "$CHECKOUT_FALLBACK_REF" ]; then
exit "$fetch_status"
fi
echo "::warning::workflow_dispatch target_ref '$CHECKOUT_REF' is unavailable; falling back to head SHA '$CHECKOUT_FALLBACK_REF'"
fetch_checkout_ref "$CHECKOUT_FALLBACK_REF"
fi
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Resolve checkout SHA
@@ -306,12 +340,46 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_REF: ${{ inputs.target_ref || github.sha }}
CHECKOUT_FALLBACK_REF: ${{ github.sha }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_REF}:refs/remotes/origin/checkout"
fetch_checkout_ref() {
local ref="$1"
local fetch_status
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${ref}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
return "$fetch_status"
fi
if [ "$attempt" = "3" ]; then
return "$fetch_status"
fi
echo "::warning::checkout fetch for '$ref' timed out on attempt $attempt; retrying"
sleep 5
done
}
if fetch_checkout_ref "$CHECKOUT_REF"; then
:
else
fetch_status="$?"
if [ "$fetch_status" = "124" ] || [ "$fetch_status" = "137" ]; then
echo "::error::checkout fetch for '$CHECKOUT_REF' timed out"
exit "$fetch_status"
fi
if [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ] || [ "$CHECKOUT_REF" = "$CHECKOUT_FALLBACK_REF" ]; then
exit "$fetch_status"
fi
echo "::warning::workflow_dispatch target_ref '$CHECKOUT_REF' is unavailable; falling back to head SHA '$CHECKOUT_FALLBACK_REF'"
fetch_checkout_ref "$CHECKOUT_FALLBACK_REF"
fi
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Ensure security base commit
@@ -398,6 +466,66 @@ jobs:
- name: Audit production dependencies
run: node scripts/pre-commit/pnpm-audit-prod.mjs --audit-level=high
# Warm the lockfile- and pnpm-pinned store without blocking Linux Node shards.
# On a cold key this job owns the save for later workflow runs.
pnpm-store-warmup:
permissions:
contents: read
needs: [preflight]
if: needs.preflight.outputs.run_node == 'true' || needs.preflight.outputs.run_check_docs == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
steps:
- name: Checkout
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
run: |
set -euo pipefail
workdir="$GITHUB_WORKSPACE"
reset_checkout_dir() {
mkdir -p "$workdir"
find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
}
checkout_attempt() {
local attempt="$1"
reset_checkout_dir
git init "$workdir" >/dev/null
git config --global --add safe.directory "$workdir"
git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$workdir" config gc.auto 0
timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1
git -C "$workdir" checkout --force --detach "$CHECKOUT_SHA" || return 1
test -f "$workdir/.github/actions/setup-node-env/action.yml" || return 1
echo "checkout attempt ${attempt}/5 succeeded"
}
for attempt in 1 2 3 4 5; do
if checkout_attempt "$attempt"; then
exit 0
fi
echo "checkout attempt ${attempt}/5 failed"
sleep $((attempt * 5))
done
echo "checkout failed after 5 attempts" >&2
exit 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
save-actions-cache: "true"
# Build dist once for Node-relevant changes and share it with downstream jobs.
# Keep this overlapping with the fast correctness lanes so green PRs get heavy
# test/build feedback sooner instead of waiting behind a full `check` pass.
@@ -406,7 +534,7 @@ jobs:
contents: read
needs: [preflight]
if: needs.preflight.outputs.run_build_artifacts == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-32vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
outputs:
channels-result: ${{ steps.built_artifact_checks.outputs['channels-result'] }}
@@ -469,14 +597,19 @@ jobs:
with:
install-bun: "false"
- name: Restore build-all step cache
uses: actions/cache@v5
with:
path: .artifacts/build-all-cache
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
restore-keys: |
${{ runner.os }}-build-all-v3-
- name: Build dist
env:
NODE_OPTIONS: --max-old-space-size=8192
run: pnpm build:ci-artifacts
- name: Build Control UI
run: pnpm ui:build
- name: Check Control UI i18n
if: needs.preflight.outputs.run_control_ui_i18n == 'true'
run: pnpm ui:i18n:check
@@ -584,7 +717,8 @@ jobs:
fi
if [ "$RUN_GATEWAY_WATCH" = "true" ]; then
start_check "gateway-watch" node scripts/check-gateway-watch-regression.mjs --skip-build --ready-timeout-ms 5000
start_check "gateway-watch" \
node scripts/check-gateway-watch-regression.mjs --skip-build --ready-timeout-ms 5000
fi
for index in "${!pids[@]}"; do
@@ -700,10 +834,10 @@ jobs:
;;
contracts-plugins-ci-routing)
pnpm test:contracts:plugins
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
;;
ci-routing)
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
;;
bun-launcher)
OPENCLAW_TEST_BUN_LAUNCHER=1 pnpm test test/openclaw-launcher.e2e.test.ts
@@ -945,14 +1079,13 @@ jobs:
node openclaw.mjs --help
node openclaw.mjs status --json --timeout 1
pnpm test:build:singleton
checks-node-core-test-nondist-shard:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_node_core_nondist == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'ubuntu-24.04') || 'ubuntu-24.04') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-8vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -1017,6 +1150,7 @@ jobs:
OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }}
OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
OPENCLAW_VITEST_SHARD_NAME: ${{ matrix.shard_name }}
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: "900000"
OPENCLAW_TEST_PROJECTS_PARALLEL: "2"
shell: bash
run: |
@@ -1058,7 +1192,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && matrix.runner || 'ubuntu-24.04') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
fail-fast: false
@@ -1149,7 +1283,7 @@ jobs:
pnpm lint:auth:pairing-account-scope
pnpm check:import-cycles
# build-artifacts already runs the tsdown/runtime build for the same Node-relevant changes.
pnpm build:plugin-sdk:strict-smoke
NODE_OPTIONS=--max-old-space-size=8192 pnpm build:plugin-sdk:strict-smoke
;;
prod-types)
pnpm tsgo:prod
@@ -1269,7 +1403,7 @@ jobs:
packages/plugin-sdk/dist
extensions/*/dist/.boundary-tsc.tsbuildinfo
extensions/*/dist/.boundary-tsc.stamp
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-extension-package-boundary-v1-
@@ -1286,10 +1420,22 @@ jobs:
find src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
touch -t 200001010000 \
if [ -d packages/llm-core/src ]; then
find packages/llm-core/src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
if [ -d packages/model-catalog-core/src ]; then
find packages/model-catalog-core/src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
cache_inputs=(
tsconfig.json \
tsconfig.plugin-sdk.dts.json \
packages/plugin-sdk/tsconfig.json \
packages/llm-core/package.json \
packages/model-catalog-core/package.json \
scripts/check-extension-package-tsc-boundary.mjs \
scripts/prepare-extension-package-boundary-artifacts.mjs \
scripts/write-plugin-sdk-entry-dts.ts \
@@ -1297,6 +1443,12 @@ jobs:
scripts/lib/plugin-sdk-entries.mjs \
package.json \
pnpm-lock.yaml
)
for cache_input in "${cache_inputs[@]}"; do
if [ -e "$cache_input" ]; then
touch -t 200001010000 "$cache_input"
fi
done
- name: Run additional check shard
env:
@@ -1411,11 +1563,44 @@ jobs:
- name: Checkout ClawHub docs source
run: |
set -euo pipefail
git init clawhub-source
git -C clawhub-source config gc.auto 0
git -C clawhub-source remote add origin "https://github.com/openclaw/clawhub.git"
git -C clawhub-source fetch --no-tags --depth=1 origin "+HEAD:refs/remotes/origin/checkout"
git -C clawhub-source checkout --detach refs/remotes/origin/checkout
workdir="$GITHUB_WORKSPACE/clawhub-source"
started_at="$(date +%s)"
reset_checkout_dir() {
mkdir -p "$workdir"
find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
}
checkout_attempt() {
local attempt="$1"
reset_checkout_dir
git init "$workdir" >/dev/null
git -C "$workdir" config gc.auto 0
git -C "$workdir" remote add origin "https://github.com/openclaw/clawhub.git"
timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+refs/heads/main:refs/remotes/origin/checkout" || return 1
git -C "$workdir" checkout --force --detach refs/remotes/origin/checkout || return 1
echo "ClawHub checkout attempt ${attempt}/5 succeeded"
}
for attempt in 1 2 3 4 5; do
if checkout_attempt "$attempt"; then
elapsed="$(( $(date +%s) - started_at ))"
echo "ClawHub checkout completed in ${elapsed}s"
exit 0
fi
echo "ClawHub checkout attempt ${attempt}/5 failed"
sleep $((attempt * 5))
done
echo "ClawHub checkout failed after 5 attempts" >&2
exit 1
- name: Check docs
env:
@@ -1439,7 +1624,25 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
fetch_checkout_ref() {
local fetch_status
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
return "$fetch_status"
fi
if [ "$attempt" = "3" ]; then
return "$fetch_status"
fi
echo "::warning::checkout fetch for '$CHECKOUT_SHA' timed out on attempt $attempt; retrying"
sleep 5
done
}
fetch_checkout_ref
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Setup Python
@@ -1487,7 +1690,28 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" &
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
wait "$fetch_pid" || true
return 124
fi
sleep 1
elapsed=$((elapsed + 1))
done
wait "$fetch_pid"
}
fetch_checkout_ref
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Try to exclude workspace from Windows Defender (best-effort)
@@ -1572,7 +1796,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_macos_node == 'true' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-latest' || (github.repository == 'openclaw/openclaw' && 'blacksmith-6vcpu-macos-latest' || 'macos-latest') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-15' || (github.repository == 'openclaw/openclaw' && 'blacksmith-6vcpu-macos-15' || 'macos-15') }}
timeout-minutes: 20
strategy:
fail-fast: false
@@ -1587,7 +1811,28 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" &
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
wait "$fetch_pid" || true
return 124
fi
sleep 1
elapsed=$((elapsed + 1))
done
wait "$fetch_pid"
}
fetch_checkout_ref
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Setup Node environment
@@ -1621,7 +1866,7 @@ jobs:
name: "macos-swift"
needs: [preflight]
if: needs.preflight.outputs.run_macos_swift == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-26' || (github.repository == 'openclaw/openclaw' && 'blacksmith-12vcpu-macos-latest' || 'macos-26') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-26' || (github.repository == 'openclaw/openclaw' && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
timeout-minutes: 20
steps:
- name: Checkout
@@ -1633,7 +1878,28 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" &
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
wait "$fetch_pid" || true
return 124
fi
sleep 1
elapsed=$((elapsed + 1))
done
wait "$fetch_pid"
}
fetch_checkout_ref
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Install XcodeGen / SwiftLint / SwiftFormat
@@ -1705,6 +1971,21 @@ jobs:
done
exit 1
- name: OpenClawKit Talk-trait opt-out (no ElevenLabsKit when default traits disabled)
run: |
set -euo pipefail
# Guard: chat-only consumers build OpenClawKit with the Talk trait
# disabled and must NOT link ElevenLabsKit. Assert that future sources
# under OpenClawKit cannot silently reintroduce an unconditional
# ElevenLabsKit dependency while the manifest still looks correct.
deps="$(swift package --package-path apps/shared/OpenClawKit show-dependencies --disable-default-traits)"
echo "$deps"
if grep -qi 'elevenlabs' <<<"$deps"; then
echo "::error::ElevenLabsKit resolved with the Talk trait disabled; keep it gated behind the Talk trait."
exit 1
fi
swift build --package-path apps/shared/OpenClawKit --target OpenClawKit --disable-default-traits
- name: Swift test
run: |
set -euo pipefail
@@ -1844,3 +2125,53 @@ jobs:
exit 1
;;
esac
ci-timings-summary:
permissions:
actions: read
contents: read
name: ci-timings-summary
needs:
- preflight
- security-fast
- pnpm-store-warmup
- build-artifacts
- checks-fast-core
- checks-fast-plugin-contracts-shard
- checks-fast-channel-contracts-shard
- checks-node-compat
- checks-node-core-test-nondist-shard
- check-shard
- check-additional-shard
- check-docs
- skills-python
- checks-windows
- macos-node
- macos-swift
- android
if: ${{ !cancelled() && always() && github.event_name != 'push' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout timing summary helper
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || needs.preflight.outputs.checkout_revision || github.sha }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Write CI timing summary
env:
GH_TOKEN: ${{ github.token }}
run: |
node scripts/ci-run-timings.mjs "$GITHUB_RUN_ID" --limit 25 > ci-timings-summary.txt
cat ci-timings-summary.txt >> "$GITHUB_STEP_SUMMARY"
- name: Upload CI timing summary
uses: actions/upload-artifact@v7
with:
name: ci-timings-summary
path: ci-timings-summary.txt
retention-days: 14

View File

@@ -24,7 +24,14 @@ concurrency:
jobs:
dispatch:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'issue_comment' || !(endsWith(github.actor, '[bot]') && (github.event.action == 'labeled' || github.event.action == 'unlabeled')) }}
if: >-
${{
github.event_name == 'issue_comment' ||
!(
endsWith(github.actor, '[bot]') &&
(github.event.action == 'labeled' || github.event.action == 'unlabeled')
)
}}
env:
HAS_CLAWSWEEPER_APP_PRIVATE_KEY: ${{ secrets.CLAWSWEEPER_APP_PRIVATE_KEY != '' }}
CLAWSWEEPER_APP_CLIENT_ID: Iv23liOECG0slfuhz093

View File

@@ -33,6 +33,7 @@ on:
- "packages/plugin-package-contract/**"
- "packages/plugin-sdk/**"
- "packages/memory-host-sdk/**"
- "packages/net-policy/**"
- "src/*.ts"
- "src/**/*.ts"
- "src/config/**"
@@ -71,7 +72,9 @@ on:
- "src/acp/control-plane/**"
- "src/agents/cli-runner/**"
- "src/agents/command/**"
- "src/agents/pi-embedded-runner/**"
- "src/agents/embedded-agent-runner/**"
- "src/agents/sessions/**"
- "src/agents/sessions/tools/**"
- "src/agents/tools/**"
- "src/agents/*completion*.ts"
- "src/agents/*transport*.ts"
@@ -104,13 +107,13 @@ on:
- "src/gateway/**/*auth*.ts"
- "src/gateway/*secret*.ts"
- "src/gateway/**/*secret*.ts"
- "src/gateway/protocol/**/*secret*.ts"
- "packages/gateway-protocol/src/**/*secret*.ts"
- "src/gateway/resolve-configured-secret-input-string*.ts"
- "src/gateway/security-path*.ts"
- "src/gateway/server-methods/secrets*.ts"
- "src/gateway/server-startup-memory.ts"
- "src/gateway/method-scopes.ts"
- "src/gateway/protocol/**"
- "packages/gateway-protocol/src/**"
- "src/gateway/server-methods/**"
- "src/gateway/server-methods.ts"
- "src/gateway/server-methods-list.ts"
@@ -207,6 +210,9 @@ jobs:
else
while IFS= read -r file; do
case "${file}" in
.github/codeql/codeql-network-runtime-boundary-critical-quality.yml|.github/codeql/openclaw-boundary/queries/raw-socket-callsite-classification.ql|.github/codeql/openclaw-boundary/queries/managed-proxy-runtime-mutation.ql)
network_runtime=true
;;
.github/codeql/*|.github/workflows/codeql-critical-quality.yml)
agent=true
channel=true
@@ -219,10 +225,17 @@ jobs:
plugin_sdk_package=true
plugin_sdk_reply=true
provider=true
network_runtime=true
session_diagnostics=true
;;
src/acp/control-plane/*|src/agents/cli-runner/*|src/agents/command/*|src/agents/pi-embedded-runner/*|src/agents/tools/*|src/agents/*completion*.ts|src/agents/*transport*.ts|src/agents/model-*.ts|src/agents/openclaw-tools*.ts|src/agents/provider-*.ts|src/agents/session*.ts|src/agents/tool-call*.ts|src/auto-reply/reply/agent-runner*.ts|src/auto-reply/reply/commands*.ts|src/auto-reply/reply/directive-handling*.ts|src/auto-reply/reply/dispatch-*.ts|src/auto-reply/reply/get-reply-run*.ts|src/auto-reply/reply/provider-dispatcher*.ts|src/auto-reply/reply/queue*.ts|src/auto-reply/reply/reply-run-registry*.ts|src/auto-reply/reply/session*.ts)
src/agents/sessions/tools/*)
agent=true
mcp_process=true
;;
src/agents/sessions/*auth*.ts|src/agents/sessions/**/*auth*.ts)
agent=true
core_auth_secrets=true
;;
src/acp/control-plane/*|src/agents/cli-runner/*|src/agents/command/*|src/agents/embedded-agent-runner/*|src/agents/sessions/*|src/agents/tools/*|src/agents/*completion*.ts|src/agents/*transport*.ts|src/agents/model-*.ts|src/agents/openclaw-tools*.ts|src/agents/provider-*.ts|src/agents/session*.ts|src/agents/tool-call*.ts|src/auto-reply/reply/agent-runner*.ts|src/auto-reply/reply/commands*.ts|src/auto-reply/reply/directive-handling*.ts|src/auto-reply/reply/dispatch-*.ts|src/auto-reply/reply/get-reply-run*.ts|src/auto-reply/reply/provider-dispatcher*.ts|src/auto-reply/reply/queue*.ts|src/auto-reply/reply/reply-run-registry*.ts|src/auto-reply/reply/session*.ts)
agent=true
;;
src/auto-reply/reply/post-compaction-context.ts|src/auto-reply/reply/queue/*|src/auto-reply/reply/startup-context.ts|src/commands/doctor-session-*.ts|src/commands/session-store-targets.ts|src/commands/sessions*.ts|src/infra/diagnostic-*.ts|src/infra/diagnostics-timeline.ts|src/infra/session-delivery-queue*.ts|src/logging/diagnostic*.ts)
@@ -234,14 +247,14 @@ jobs:
src/config/*)
config=true
;;
src/gateway/protocol/*secret*.ts|src/gateway/server-methods/secrets*.ts)
packages/gateway-protocol/src/*secret*.ts|packages/gateway-protocol/src/**/*secret*.ts|src/gateway/server-methods/secrets*.ts)
core_auth_secrets=true
gateway=true
;;
src/agents/*auth*.ts|src/agents/auth-health*.ts|src/agents/auth-profiles|src/agents/auth-profiles/*|src/agents/bash-tools.exec-host-shared.ts|src/agents/sandbox|src/agents/sandbox.ts|src/agents/sandbox-*.ts|src/agents/sandbox/*|src/cron/service/jobs.ts|src/cron/stagger.ts|src/gateway/*auth*.ts|src/gateway/*secret*.ts|src/gateway/resolve-configured-secret-input-string*.ts|src/gateway/security-path*.ts|src/infra/secret-file*.ts|src/secrets/*|src/security/*)
core_auth_secrets=true
;;
src/gateway/method-scopes.ts|src/gateway/protocol/*|src/gateway/server-methods/*|src/gateway/server-methods.ts|src/gateway/server-methods-list.ts)
packages/gateway-protocol/src/*|packages/gateway-protocol/src/**/*|src/gateway/method-scopes.ts|src/gateway/server-methods/*|src/gateway/server-methods.ts|src/gateway/server-methods-list.ts)
gateway=true
;;
packages/memory-host-sdk/*|src/commands/doctor-cron-dreaming-payload-migration.ts|src/commands/doctor-memory-search.ts|src/gateway/server-startup-memory.ts|src/memory/*|src/memory-host-sdk/*)
@@ -291,7 +304,9 @@ jobs:
esac
case "${file}" in
src/*.ts|src/**/*.ts|extensions/*.ts|extensions/**/*.ts)
src/**/*.test.ts|src/**/*.test.tsx|extensions/**/*.test.ts|extensions/**/*.test.tsx)
;;
packages/net-policy/src/*|packages/net-policy/src/**/*|src/cli/gateway-cli/run-loop.ts|src/infra/net/*|src/infra/net/**/*|src/infra/ssh-tunnel.ts|src/infra/gateway-lock.ts|src/infra/jsonl-socket.ts|src/infra/push-apns-http2.ts|src/proxy-capture/*|src/proxy-capture/**/*|extensions/codex-supervisor/src/json-rpc-client.ts|extensions/irc/src/*|extensions/qa-lab/src/*)
network_runtime=true
;;
esac
@@ -418,7 +433,33 @@ jobs:
with:
submodules: false
- name: Fast PR network boundary diff scan
if: ${{ github.event_name == 'pull_request' }}
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
added_lines="$(mktemp)"
gh api --paginate "repos/${REPOSITORY}/pulls/${PR_NUMBER}/files" --jq '
.[]
| select(.filename | test("^(src/cli/gateway-cli/run-loop\\.ts|src/infra/(gateway-lock|jsonl-socket|push-apns-http2|ssh-tunnel)\\.ts|src/infra/net/|src/proxy-capture/|extensions/codex-supervisor/src/json-rpc-client\\.ts|extensions/irc/src/|extensions/qa-lab/src/|packages/net-policy/src/)"))
| .filename as $file
| (.patch // "")
| split("\n")[]
| select(startswith("+") and (startswith("+++") | not))
| "\($file): \(.)"
' > "$added_lines"
if grep -En '(from|require\().*["'\''](node:)?(net|tls|http2)["'\'']|\b(net|tls|http2)\.(connect|createConnection)\b|new Socket\(|HTTP_PROXY|HTTPS_PROXY|NO_PROXY|GLOBAL_AGENT_|OPENCLAW_PROXY_' "$added_lines"; then
echo "Network runtime boundary-sensitive added lines require full CodeQL review." >&2
exit 1
fi
- name: Initialize CodeQL
if: ${{ github.event_name != 'pull_request' }}
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
@@ -426,12 +467,14 @@ jobs:
- name: Analyze
id: analyze
if: ${{ github.event_name != 'pull_request' }}
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
output: sarif-results
category: "/codeql-critical-quality/network-runtime-boundary"
- name: Fail on network runtime boundary findings
if: ${{ github.event_name != 'pull_request' }}
env:
SARIF_OUTPUT: sarif-results
run: |

View File

@@ -20,7 +20,7 @@ permissions:
jobs:
macos:
name: Critical Security (macOS)
runs-on: blacksmith-6vcpu-macos-latest
runs-on: blacksmith-6vcpu-macos-15
timeout-minutes: 45
steps:
- name: Checkout

View File

@@ -19,6 +19,15 @@ on:
- ".github/workflows/**"
- "packages/**"
- "src/**"
push:
branches:
- main
paths:
- ".github/actions/**"
- ".github/codeql/**"
- ".github/workflows/**"
- "packages/**"
- "src/**"
schedule:
- cron: "0 6 * * *"
@@ -76,10 +85,21 @@ jobs:
config_file: ./.github/codeql/codeql-actions-critical-security.yml
steps:
- name: Checkout
if: ${{ matrix.category != 'actions' }}
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Checkout Actions security sources
if: ${{ matrix.category == 'actions' }}
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
sparse-checkout: |
.github/actions
.github/workflows
.github/codeql
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:

View File

@@ -138,7 +138,7 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENCLAW_CONTROL_UI_I18N_PROVIDER: ${{ secrets.ANTHROPIC_API_KEY != '' && 'anthropic' || 'openai' }}
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ secrets.ANTHROPIC_API_KEY != '' && 'claude-opus-4-7' || vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ secrets.ANTHROPIC_API_KEY != '' && 'claude-opus-4-8' || vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_THINKING: low
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "1"
LOCALE: ${{ matrix.locale }}

View File

@@ -137,7 +137,10 @@ jobs:
set -euo pipefail
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git fetch --no-tags --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"
timeout --signal=TERM --kill-after=10s 30s git \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=50 origin \
"+refs/heads/main:refs/remotes/origin/main"
fi
- name: Prepare Crabbox shell
@@ -318,7 +321,26 @@ jobs:
$ErrorActionPreference = "Stop"
if (git rev-parse --is-inside-work-tree 2>$null) {
git fetch --no-tags --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"
$repo = (Get-Location).Path
$fetchInfo = New-Object System.Diagnostics.ProcessStartInfo
$fetchInfo.FileName = "git"
$fetchInfo.WorkingDirectory = $repo
$fetchInfo.UseShellExecute = $false
$fetchInfo.Arguments = '-c protocol.version=2 fetch --no-tags --no-progress --prune --no-recurse-submodules --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"'
$fetch = New-Object System.Diagnostics.Process
$fetch.StartInfo = $fetchInfo
if (-not $fetch.Start()) {
throw "git fetch failed to start"
}
if (-not $fetch.WaitForExit(30000)) {
$fetch.Kill()
$fetch.WaitForExit()
throw "git fetch timed out after 30 seconds"
}
if ($fetch.ExitCode -ne 0) {
throw "git fetch failed with exit code $($fetch.ExitCode)"
}
}
- name: Setup pnpm and dependencies
@@ -513,7 +535,10 @@ jobs:
set -euo pipefail
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git fetch --no-tags --depth=50 origin "+refs/heads/main:refs/remotes/origin/main"
timeout --signal=TERM --kill-after=10s 30s git \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=50 origin \
"+refs/heads/main:refs/remotes/origin/main"
fi
node_bin="$(dirname "$(node -p 'process.execPath')")"

View File

@@ -1,176 +0,0 @@
name: Dependency Change Awareness
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] metadata-only workflow; no checkout or untrusted code execution
types: [opened, reopened, synchronize, ready_for_review]
permissions:
pull-requests: write
issues: write
concurrency:
group: dependency-change-awareness-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
dependency-change-awareness:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Label and comment on dependency changes
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const marker = "<!-- openclaw:dependency-change-awareness -->";
const labelName = "dependencies-changed";
const maxListedFiles = 25;
const pullRequest = context.payload.pull_request;
if (!pullRequest) {
core.info("No pull_request payload found; skipping.");
return;
}
const isDependencyFile = (filename) =>
filename === "package.json" ||
filename === "package-lock.json" ||
filename === "npm-shrinkwrap.json" ||
filename === "pnpm-lock.yaml" ||
filename === "pnpm-workspace.yaml" ||
filename === "ui/package.json" ||
filename.startsWith("patches/") ||
/^packages\/[^/]+\/package\.json$/u.test(filename) ||
/^extensions\/[^/]+\/package-lock\.json$/u.test(filename) ||
/^extensions\/[^/]+\/npm-shrinkwrap\.json$/u.test(filename) ||
/^extensions\/[^/]+\/package\.json$/u.test(filename);
const sanitizeDisplayValue = (value) =>
String(value)
.replace(/[\u0000-\u001f\u007f]/gu, "?")
.slice(0, 240);
const markdownCode = (value) =>
`\`${sanitizeDisplayValue(value).replaceAll("`", "\\`")}\``;
const ignoreUnavailableWritePermission = (action) => (error) => {
if (error?.status === 403) {
core.warning(
`Skipping dependency change ${action}; token does not have issue write permission.`,
);
return;
}
if (error?.status === 404 || error?.status === 422) {
core.warning(`Dependency change ${action} is unavailable.`);
return;
}
throw error;
};
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullRequest.number,
per_page: 100,
});
const dependencyFiles = files
.map((file) => file.filename)
.filter((filename) => typeof filename === "string" && isDependencyFile(filename))
.sort((left, right) => left.localeCompare(right));
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
per_page: 100,
});
const existingComment = comments.find(
(comment) =>
comment.user?.login === "github-actions[bot]" && comment.body?.includes(marker),
);
const labels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
per_page: 100,
});
const hasLabel = labels.some((label) => label.name === labelName);
if (dependencyFiles.length === 0) {
if (hasLabel) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
name: labelName,
}).catch(ignoreUnavailableWritePermission("label removal"));
}
if (existingComment) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
}).catch(ignoreUnavailableWritePermission("comment deletion"));
}
await core.summary
.addHeading("Dependency Change Awareness")
.addRaw("No dependency-related file changes detected.")
.write();
core.info("No dependency-related file changes detected.");
return;
}
if (!hasLabel) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
labels: [labelName],
}).catch(ignoreUnavailableWritePermission(`label "${labelName}" update`));
}
const listedFiles = dependencyFiles.slice(0, maxListedFiles);
const omittedCount = dependencyFiles.length - listedFiles.length;
const fileLines = listedFiles.map((filename) => `- ${markdownCode(filename)}`);
if (omittedCount > 0) {
fileLines.push(`- ${omittedCount} additional dependency-related files not shown`);
}
const body = [
marker,
"",
"### Dependency Changes Detected",
"",
"This PR changes dependency-related files. Maintainers should confirm these changes are intentional.",
"",
"Changed files:",
...fileLines,
"",
"Maintainer follow-up:",
"- Review whether the dependency changes are intentional.",
"- Inspect resolved package deltas when lockfile, shrinkwrap, or workspace dependency policy changes are present.",
"- Treat `package-lock.json` and `npm-shrinkwrap.json` diffs as security-review surfaces.",
"- Run `pnpm deps:changes:report -- --base-ref origin/main --markdown /tmp/dependency-changes.md --json /tmp/dependency-changes.json` locally for detailed release-style evidence.",
].join("\n");
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body,
}).catch(ignoreUnavailableWritePermission("comment update"));
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
body,
}).catch(ignoreUnavailableWritePermission("comment creation"));
}
await core.summary
.addHeading("Dependency Change Awareness")
.addRaw(`Detected ${dependencyFiles.length} dependency-related file change(s).`)
.addList(dependencyFiles.map((filename) => markdownCode(filename)))
.write();
core.notice(`Detected ${dependencyFiles.length} dependency-related file change(s).`);

109
.github/workflows/dependency-guard.yml vendored Normal file
View File

@@ -0,0 +1,109 @@
name: Dependency Guard
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] checks trusted base script only; never checks out PR head
types: [opened, reopened, synchronize, ready_for_review]
permissions:
contents: read
pull-requests: write
issues: write
concurrency:
group: dependency-guard-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
dependency-guard-detect:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
autoscrub: ${{ steps.guard.outputs.autoscrub }}
autoscrub-owner: ${{ steps.guard.outputs.autoscrub-owner }}
autoscrub-repository: ${{ steps.guard.outputs.autoscrub-repository }}
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Detect dependency changes
id: guard
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: detect
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs
dependency-guard-autoscrub:
if: ${{ !github.event.pull_request.draft && needs.dependency-guard-detect.outputs.autoscrub == 'true' }}
needs: dependency-guard-detect
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
issues: write
pull-requests: read
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Create autoscrub app token
id: app-token
continue-on-error: true
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: "2729701"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: ${{ needs.dependency-guard-detect.outputs.autoscrub-owner }}
repositories: ${{ needs.dependency-guard-detect.outputs.autoscrub-repository }}
permission-contents: write
- name: Create fallback autoscrub app token
id: app-token-fallback
continue-on-error: true
if: steps.app-token.outcome == 'failure'
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: "2971289"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY_FALLBACK }}
owner: ${{ needs.dependency-guard-detect.outputs.autoscrub-owner }}
repositories: ${{ needs.dependency-guard-detect.outputs.autoscrub-repository }}
permission-contents: write
- name: Remove package lockfile changes
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_AUTOSCRUB_TOKEN: ${{ steps.app-token.outputs.token || steps.app-token-fallback.outputs.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: autoscrub
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs
dependency-guard:
if: ${{ !github.event.pull_request.draft && always() }}
needs:
- dependency-guard-detect
- dependency-guard-autoscrub
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Enforce dependency guard
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: enforce
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs

View File

@@ -75,6 +75,7 @@ jobs:
contents: read
outputs:
digest: ${{ steps.build.outputs.digest }}
browser_digest: ${{ steps.build-browser.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v6
@@ -102,14 +103,18 @@ jobs:
set -euo pipefail
tags=()
slim_tags=()
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
tags+=("${IMAGE}:main-amd64")
slim_tags+=("${IMAGE}:main-slim-amd64")
browser_tags=()
browser_supported=0
if grep -q '^ARG OPENCLAW_INSTALL_BROWSER' Dockerfile; then
browser_supported=1
fi
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
version="${SOURCE_REF#refs/tags/v}"
tags+=("${IMAGE}:${version}-amd64")
slim_tags+=("${IMAGE}:${version}-slim-amd64")
if [[ "${browser_supported}" == "1" ]]; then
browser_tags+=("${IMAGE}:${version}-browser-amd64")
fi
fi
if [[ ${#tags[@]} -eq 0 ]]; then
echo "::error::No amd64 tags resolved for ref ${SOURCE_REF}"
@@ -119,6 +124,9 @@ jobs:
echo "value<<EOF"
printf "%s\n" "${tags[@]}" "${slim_tags[@]}"
echo "EOF"
echo "browser<<EOF"
printf "%s\n" "${browser_tags[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Resolve OCI labels (amd64)
@@ -162,6 +170,91 @@ jobs:
provenance: mode=max
push: true
- name: Build and push amd64 browser image
id: build-browser
if: steps.tags.outputs.browser != ''
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64
cache-from: |
type=gha,scope=docker-release-amd64
type=gha,scope=docker-release-browser-amd64
cache-to: type=gha,mode=max,scope=docker-release-browser-amd64
build-args: |
OPENCLAW_EXTENSIONS=diagnostics-otel,codex
OPENCLAW_INSTALL_BROWSER=1
tags: ${{ steps.tags.outputs.browser }}
labels: ${{ steps.labels.outputs.value }}
sbom: true
provenance: mode=max
push: true
- name: Smoke test amd64 runtime workspace templates
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.value }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No amd64 image ref resolved for runtime template smoke"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
test -f /app/src/agents/templates/HEARTBEAT.md
temp_root="$(mktemp -d)"
trap "rm -rf \"${temp_root}\"" EXIT
mkdir -p "${temp_root}/home" "${temp_root}/cwd"
cd "${temp_root}/cwd"
set +e
HOME="${temp_root}/home" \
USERPROFILE="${temp_root}/home" \
OPENCLAW_HOME="${temp_root}/home" \
OPENCLAW_NO_ONBOARD=1 \
OPENCLAW_SUPPRESS_NOTES=1 \
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 \
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK=1 \
AWS_EC2_METADATA_DISABLED=true \
AWS_SHARED_CREDENTIALS_FILE="${temp_root}/home/.aws/credentials" \
AWS_CONFIG_FILE="${temp_root}/home/.aws/config" \
node /app/openclaw.mjs agent --message "workspace bootstrap smoke" --session-id "workspace-bootstrap-smoke" --local --timeout 1 --json \
>"${temp_root}/out.log" 2>&1
status="$?"
set -e
if grep -F "Missing workspace template:" "${temp_root}/out.log"; then
cat "${temp_root}/out.log"
exit 1
fi
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
if [ "${status}" -ne 0 ]; then
cat "${temp_root}/out.log"
fi
'
- name: Smoke test amd64 browser image
if: steps.tags.outputs.browser != ''
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.browser }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No amd64 browser image ref resolved"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
browser="$(find /home/node/.cache/ms-playwright -maxdepth 5 -type f \( -name chrome -o -name chromium -o -name chrome-headless-shell \) -print | head -1)"
test -n "${browser}"
"${browser}" --version
'
# Build arm64 image. Default and slim tags point to the same slim runtime.
build-arm64:
needs: [approve_manual_backfill]
@@ -173,6 +266,7 @@ jobs:
contents: read
outputs:
digest: ${{ steps.build.outputs.digest }}
browser_digest: ${{ steps.build-browser.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v6
@@ -200,14 +294,18 @@ jobs:
set -euo pipefail
tags=()
slim_tags=()
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
tags+=("${IMAGE}:main-arm64")
slim_tags+=("${IMAGE}:main-slim-arm64")
browser_tags=()
browser_supported=0
if grep -q '^ARG OPENCLAW_INSTALL_BROWSER' Dockerfile; then
browser_supported=1
fi
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
version="${SOURCE_REF#refs/tags/v}"
tags+=("${IMAGE}:${version}-arm64")
slim_tags+=("${IMAGE}:${version}-slim-arm64")
if [[ "${browser_supported}" == "1" ]]; then
browser_tags+=("${IMAGE}:${version}-browser-arm64")
fi
fi
if [[ ${#tags[@]} -eq 0 ]]; then
echo "::error::No arm64 tags resolved for ref ${SOURCE_REF}"
@@ -217,6 +315,9 @@ jobs:
echo "value<<EOF"
printf "%s\n" "${tags[@]}" "${slim_tags[@]}"
echo "EOF"
echo "browser<<EOF"
printf "%s\n" "${browser_tags[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Resolve OCI labels (arm64)
@@ -260,6 +361,91 @@ jobs:
provenance: mode=max
push: true
- name: Build and push arm64 browser image
id: build-browser
if: steps.tags.outputs.browser != ''
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/arm64
cache-from: |
type=gha,scope=docker-release-arm64
type=gha,scope=docker-release-browser-arm64
cache-to: type=gha,mode=max,scope=docker-release-browser-arm64
build-args: |
OPENCLAW_EXTENSIONS=diagnostics-otel,codex
OPENCLAW_INSTALL_BROWSER=1
tags: ${{ steps.tags.outputs.browser }}
labels: ${{ steps.labels.outputs.value }}
sbom: true
provenance: mode=max
push: true
- name: Smoke test arm64 runtime workspace templates
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.value }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No arm64 image ref resolved for runtime template smoke"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
test -f /app/src/agents/templates/HEARTBEAT.md
temp_root="$(mktemp -d)"
trap "rm -rf \"${temp_root}\"" EXIT
mkdir -p "${temp_root}/home" "${temp_root}/cwd"
cd "${temp_root}/cwd"
set +e
HOME="${temp_root}/home" \
USERPROFILE="${temp_root}/home" \
OPENCLAW_HOME="${temp_root}/home" \
OPENCLAW_NO_ONBOARD=1 \
OPENCLAW_SUPPRESS_NOTES=1 \
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 \
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK=1 \
AWS_EC2_METADATA_DISABLED=true \
AWS_SHARED_CREDENTIALS_FILE="${temp_root}/home/.aws/credentials" \
AWS_CONFIG_FILE="${temp_root}/home/.aws/config" \
node /app/openclaw.mjs agent --message "workspace bootstrap smoke" --session-id "workspace-bootstrap-smoke" --local --timeout 1 --json \
>"${temp_root}/out.log" 2>&1
status="$?"
set -e
if grep -F "Missing workspace template:" "${temp_root}/out.log"; then
cat "${temp_root}/out.log"
exit 1
fi
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
if [ "${status}" -ne 0 ]; then
cat "${temp_root}/out.log"
fi
'
- name: Smoke test arm64 browser image
if: steps.tags.outputs.browser != ''
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.browser }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No arm64 browser image ref resolved"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
browser="$(find /home/node/.cache/ms-playwright -maxdepth 5 -type f \( -name chrome -o -name chromium -o -name chrome-headless-shell \) -print | head -1)"
test -n "${browser}"
"${browser}" --version
'
# Create multi-platform manifests
create-manifest:
needs: [approve_manual_backfill, build-amd64, build-arm64]
@@ -294,18 +480,25 @@ jobs:
set -euo pipefail
tags=()
slim_tags=()
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
tags+=("${IMAGE}:main")
slim_tags+=("${IMAGE}:main-slim")
browser_tags=()
browser_supported=0
if grep -q '^ARG OPENCLAW_INSTALL_BROWSER' Dockerfile; then
browser_supported=1
fi
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
version="${SOURCE_REF#refs/tags/v}"
tags+=("${IMAGE}:${version}")
slim_tags+=("${IMAGE}:${version}-slim")
if [[ "${browser_supported}" == "1" ]]; then
browser_tags+=("${IMAGE}:${version}-browser")
fi
# Manual backfills should only republish the requested version tags.
if [[ "${IS_MANUAL_BACKFILL}" != "1" && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]]; then
tags+=("${IMAGE}:latest")
slim_tags+=("${IMAGE}:slim")
tags+=("${IMAGE}:latest" "${IMAGE}:main")
slim_tags+=("${IMAGE}:slim" "${IMAGE}:main-slim")
if [[ "${browser_supported}" == "1" ]]; then
browser_tags+=("${IMAGE}:latest-browser" "${IMAGE}:main-browser")
fi
fi
fi
if [[ ${#tags[@]} -eq 0 ]]; then
@@ -316,25 +509,39 @@ jobs:
echo "value<<EOF"
printf "%s\n" "${tags[@]}" "${slim_tags[@]}"
echo "EOF"
echo "browser<<EOF"
printf "%s\n" "${browser_tags[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Create and push manifest
shell: bash
env:
TAGS: ${{ steps.tags.outputs.value }}
BROWSER_TAGS: ${{ steps.tags.outputs.browser }}
AMD64_DIGEST: ${{ needs.build-amd64.outputs.digest }}
ARM64_DIGEST: ${{ needs.build-arm64.outputs.digest }}
AMD64_BROWSER_DIGEST: ${{ needs.build-amd64.outputs.browser_digest }}
ARM64_BROWSER_DIGEST: ${{ needs.build-arm64.outputs.browser_digest }}
run: |
set -euo pipefail
mapfile -t tags <<< "${TAGS}"
args=()
for tag in "${tags[@]}"; do
[ -z "$tag" ] && continue
args+=("-t" "$tag")
done
docker buildx imagetools create "${args[@]}" \
"${AMD64_DIGEST}" \
"${ARM64_DIGEST}"
mapfile -t browser_tags <<< "${BROWSER_TAGS}"
create_manifest() {
local amd64_digest="$1"
local arm64_digest="$2"
shift 2
local args=()
for tag in "$@"; do
[ -z "$tag" ] && continue
args+=("-t" "$tag")
done
docker buildx imagetools create "${args[@]}" "$amd64_digest" "$arm64_digest"
}
create_manifest "${AMD64_DIGEST}" "${ARM64_DIGEST}" "${tags[@]}"
if [[ -n "${BROWSER_TAGS}" ]]; then
create_manifest "${AMD64_BROWSER_DIGEST}" "${ARM64_BROWSER_DIGEST}" "${browser_tags[@]}"
fi
verify-attestations:
needs: [create-manifest]
@@ -372,21 +579,39 @@ jobs:
slim_multi_refs=()
amd64_refs=()
arm64_refs=()
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
multi_refs+=("${IMAGE}:main")
slim_multi_refs+=("${IMAGE}:main-slim")
amd64_refs+=("${IMAGE}:main-amd64" "${IMAGE}:main-slim-amd64")
arm64_refs+=("${IMAGE}:main-arm64" "${IMAGE}:main-slim-arm64")
browser_supported=0
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
tag="${SOURCE_REF#refs/tags/}"
git fetch --depth=1 origin "refs/tags/${tag}:refs/tags/${tag}"
if git show "${SOURCE_REF}:Dockerfile" | grep -q '^ARG OPENCLAW_INSTALL_BROWSER'; then
browser_supported=1
fi
elif grep -q '^ARG OPENCLAW_INSTALL_BROWSER' Dockerfile; then
browser_supported=1
fi
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
version="${SOURCE_REF#refs/tags/v}"
multi_refs+=("${IMAGE}:${version}")
slim_multi_refs+=("${IMAGE}:${version}-slim")
amd64_refs+=("${IMAGE}:${version}-amd64" "${IMAGE}:${version}-slim-amd64")
arm64_refs+=("${IMAGE}:${version}-arm64" "${IMAGE}:${version}-slim-arm64")
amd64_refs+=(
"${IMAGE}:${version}-amd64"
"${IMAGE}:${version}-slim-amd64"
)
arm64_refs+=(
"${IMAGE}:${version}-arm64"
"${IMAGE}:${version}-slim-arm64"
)
if [[ "${browser_supported}" == "1" ]]; then
multi_refs+=("${IMAGE}:${version}-browser")
amd64_refs+=("${IMAGE}:${version}-browser-amd64")
arm64_refs+=("${IMAGE}:${version}-browser-arm64")
fi
if [[ "${IS_MANUAL_BACKFILL}" != "1" && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]]; then
multi_refs+=("${IMAGE}:latest")
slim_multi_refs+=("${IMAGE}:slim")
multi_refs+=("${IMAGE}:latest" "${IMAGE}:main")
slim_multi_refs+=("${IMAGE}:slim" "${IMAGE}:main-slim")
if [[ "${browser_supported}" == "1" ]]; then
multi_refs+=("${IMAGE}:latest-browser" "${IMAGE}:main-browser")
fi
fi
fi
if [[ ${#multi_refs[@]} -eq 0 || ${#amd64_refs[@]} -eq 0 || ${#arm64_refs[@]} -eq 0 ]]; then

View File

@@ -43,7 +43,7 @@ jobs:
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
uses: actions/setup-node@v6
with:
node-version: "24.x"
node-version: "22.19.0"
- name: Clone publish repo
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''

View File

@@ -80,7 +80,7 @@ on:
default: ""
type: string
evidence_package_spec:
description: Optional published package spec to prove in the private release evidence report
description: Optional published package spec to prove in the release evidence report
required: false
default: ""
type: string
@@ -225,7 +225,7 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
docker_runtime_assets_preflight:
name: Verify Docker runtime-assets prune path
name: Verify Docker runtime image assets
needs: [resolve_target]
if: inputs.rerun_group == 'all'
runs-on: ubuntu-24.04
@@ -250,6 +250,49 @@ jobs:
--build-arg OPENCLAW_EXTENSIONS="diagnostics-otel,codex" \
.
- name: Build and smoke test final Docker runtime image
env:
DOCKER_BUILDKIT: "1"
TARGET_SHA: ${{ needs.resolve_target.outputs.sha }}
run: |
set -euo pipefail
image_ref="openclaw-release-runtime-smoke:${TARGET_SHA}"
timeout --kill-after=30s 35m docker build \
--build-arg OPENCLAW_EXTENSIONS="diagnostics-otel,codex" \
-t "${image_ref}" \
.
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
test -f /app/src/agents/templates/HEARTBEAT.md
temp_root="$(mktemp -d)"
trap "rm -rf \"${temp_root}\"" EXIT
mkdir -p "${temp_root}/home" "${temp_root}/cwd"
cd "${temp_root}/cwd"
set +e
HOME="${temp_root}/home" \
USERPROFILE="${temp_root}/home" \
OPENCLAW_HOME="${temp_root}/home" \
OPENCLAW_NO_ONBOARD=1 \
OPENCLAW_SUPPRESS_NOTES=1 \
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 \
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK=1 \
AWS_EC2_METADATA_DISABLED=true \
AWS_SHARED_CREDENTIALS_FILE="${temp_root}/home/.aws/credentials" \
AWS_CONFIG_FILE="${temp_root}/home/.aws/config" \
node /app/openclaw.mjs agent --message "workspace bootstrap smoke" --session-id "workspace-bootstrap-smoke" --local --timeout 1 --json \
>"${temp_root}/out.log" 2>&1
status="$?"
set -e
if grep -F "Missing workspace template:" "${temp_root}/out.log"; then
cat "${temp_root}/out.log"
exit 1
fi
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
if [ "${status}" -ne 0 ]; then
cat "${temp_root}/out.log"
fi
'
normal_ci:
name: Run normal full CI
needs: [resolve_target, docker_runtime_assets_preflight]
@@ -1407,9 +1450,9 @@ jobs:
exit "$failed"
- name: Request private evidence update
- name: Request release evidence update
env:
RELEASE_PRIVATE_DISPATCH_TOKEN: ${{ secrets.OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN }}
RELEASES_DISPATCH_TOKEN: ${{ secrets.OPENCLAW_RELEASES_DISPATCH_TOKEN }}
TARGET_REF: ${{ inputs.ref }}
PACKAGE_SPEC: ${{ inputs.evidence_package_spec || inputs.npm_telegram_package_spec }}
GITHUB_RUN_ID_VALUE: ${{ github.run_id }}
@@ -1417,11 +1460,11 @@ jobs:
run: |
set -euo pipefail
if [[ "$RELEASE_CHECKS_RESULT" == "skipped" ]]; then
echo "Release checks were skipped by rerun group; skipping automatic private evidence update."
echo "Release checks were skipped by rerun group; skipping automatic release evidence update."
exit 0
fi
if [[ -z "${RELEASE_PRIVATE_DISPATCH_TOKEN// }" ]]; then
echo "OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN is not configured; skipping automatic private evidence update."
if [[ -z "${RELEASES_DISPATCH_TOKEN// }" ]]; then
echo "OPENCLAW_RELEASES_DISPATCH_TOKEN is not configured; skipping automatic release evidence update."
exit 0
fi
@@ -1440,7 +1483,7 @@ jobs:
fi
release_id="$(printf '%s' "$release_id" | tr '/:@ ' '----' | tr -cd 'A-Za-z0-9._-')"
if [[ -z "$release_id" ]]; then
echo "::warning::Could not derive release evidence id from target ref '${TARGET_REF}'; skipping automatic private evidence update."
echo "::warning::Could not derive release evidence id from target ref '${TARGET_REF}'; skipping automatic release evidence update."
exit 0
fi
@@ -1466,18 +1509,18 @@ jobs:
if ! curl --fail-with-body \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${RELEASE_PRIVATE_DISPATCH_TOKEN}" \
-H "Authorization: Bearer ${RELEASES_DISPATCH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openclaw/releases-private/dispatches \
https://api.github.com/repos/openclaw/releases/dispatches \
-d "$payload"; then
echo "::warning::Automatic private release evidence dispatch failed; child workflow validation remains authoritative."
echo "::warning::Automatic release evidence dispatch failed; child workflow validation remains authoritative."
{
echo "### Private release evidence dispatch failed"
echo "### Release evidence dispatch failed"
echo
echo "Child workflow validation remains authoritative. Backfill durable evidence from \`openclaw/releases-private\`:"
echo "Child workflow validation remains authoritative. Backfill durable evidence from \`openclaw/releases\`:"
echo
echo "\`\`\`bash"
echo "gh workflow run openclaw-release-evidence-from-full-validation.yml --repo openclaw/releases-private --ref main -f full_validation_run_id=${GITHUB_RUN_ID_VALUE} -f release_id=${release_id} -f release_ref=${TARGET_REF} -f package_spec=${evidence_package_spec}"
echo "gh workflow run openclaw-release-evidence-from-full-validation.yml --repo openclaw/releases --ref main -f full_validation_run_id=${GITHUB_RUN_ID_VALUE} -f release_id=${release_id} -f release_ref=${TARGET_REF} -f package_spec=${evidence_package_spec}"
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
fi

View File

@@ -143,7 +143,7 @@ jobs:
for (const [dep, rel] of Object.entries(workspace.patchedDependencies ?? {})) {
const absolute = path.join(\"/app\", rel);
if (!fs.existsSync(absolute)) {
throw new Error(`missing patch for ${dep}: ${rel}`);
throw new Error(\"missing patch for \" + dep + \": \" + rel);
}
}
"
@@ -337,7 +337,7 @@ jobs:
for (const [dep, rel] of Object.entries(workspace.patchedDependencies ?? {})) {
const absolute = path.join(\"/app\", rel);
if (!fs.existsSync(absolute)) {
throw new Error(`missing patch for ${dep}: ${rel}`);
throw new Error(\"missing patch for \" + dep + \": \" + rel);
}
}
"

View File

@@ -115,6 +115,7 @@ jobs:
issue_number: pullRequest.number,
per_page: 100,
});
const labelNames = new Set(currentLabels.map((label) => label.name ?? ""));
for (const label of currentLabels) {
const name = label.name ?? "";
@@ -130,14 +131,17 @@ jobs:
issue_number: pullRequest.number,
name,
});
labelNames.delete(name);
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
labels: [targetSizeLabel],
});
if (!labelNames.has(targetSizeLabel)) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
labels: [targetSizeLabel],
});
}
- name: Apply maintainer or trusted-contributor label
uses: actions/github-script@v9
with:

View File

@@ -93,8 +93,8 @@ jobs:
echo "It does not sign, notarize, or upload macOS assets."
echo
echo "Next step:"
echo "- Run \`openclaw/releases-private/.github/workflows/openclaw-macos-validate.yml\` with tag \`${RELEASE_TAG}\` and wait for the private mac validation lane to pass."
echo "- Run \`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml\` with tag \`${RELEASE_TAG}\` and \`preflight_only=true\` for the full private mac preflight."
echo "- For the real publish path, run the same private mac publish workflow from \`main\` with the successful private preflight \`preflight_run_id\` so it promotes the prepared artifacts instead of rebuilding them."
echo "- For stable releases, the private publish workflow also publishes the signed \`appcast.xml\` to public \`main\`, or opens an appcast PR if direct push is blocked."
echo "- Run \`openclaw/releases/.github/workflows/openclaw-macos-validate.yml\` with tag \`${RELEASE_TAG}\` and wait for the macOS validation lane to pass."
echo "- Run \`openclaw/releases/.github/workflows/openclaw-macos-publish.yml\` with tag \`${RELEASE_TAG}\` and \`preflight_only=true\` for the full macOS preflight."
echo "- For the real publish path, run the same macOS publish workflow from \`main\` with the successful preflight \`preflight_run_id\` so it promotes the prepared artifacts instead of rebuilding them."
echo "- For stable releases, the publish workflow also publishes the signed \`appcast.xml\` to public \`main\`, or opens an appcast PR if direct push is blocked."
} >> "$GITHUB_STEP_SUMMARY"

View File

@@ -48,7 +48,8 @@ env:
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
CRABBOX_REF: main
CRABBOX_CAPACITY_REGIONS: eu-west-1,eu-west-2,eu-central-1,us-east-1,us-west-2
CRABBOX_AWS_REGION: us-east-1
CRABBOX_CAPACITY_REGIONS: us-east-1
MANTIS_OUTPUT_DIR: .artifacts/qa-e2e/mantis/telegram-desktop-proof
jobs:
@@ -224,6 +225,7 @@ jobs:
- name: Checkout harness ref
uses: actions/checkout@v6
with:
ref: main
persist-credentials: false
fetch-depth: 0
@@ -239,9 +241,6 @@ jobs:
set -euo pipefail
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
if [[ -n "${PR_NUMBER:-}" ]]; then
git fetch --no-tags origin "+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr/${PR_NUMBER}" || true
fi
resolve_commit() {
local input_ref="$2"
@@ -255,7 +254,6 @@ jobs:
}
baseline_revision="$(resolve_commit baseline "$BASELINE_REF")"
candidate_revision="$(resolve_commit candidate "$CANDIDATE_REF")"
if ! git merge-base --is-ancestor "$baseline_revision" refs/remotes/origin/main; then
echo "baseline ref '${BASELINE_REF}' resolved to ${baseline_revision}, which is not on main." >&2
exit 1
@@ -269,6 +267,11 @@ jobs:
pr_state="$(jq -r '.state' <<<"$pr_head")"
pr_head_sha="$(jq -r '.head_sha' <<<"$pr_head")"
pr_head_repo="$(jq -r '.head_repo' <<<"$pr_head")"
candidate_revision="$CANDIDATE_REF"
if [[ ! "$candidate_revision" =~ ^[0-9a-f]{40}$ ]]; then
echo "candidate ref '${CANDIDATE_REF}' is not an immutable commit SHA." >&2
exit 1
fi
if [[ "$pr_state" != "open" || "$candidate_revision" != "$pr_head_sha" ]]; then
echo "candidate ref '${CANDIDATE_REF}' resolved to ${candidate_revision}, which is not the open PR head." >&2
exit 1
@@ -423,7 +426,7 @@ jobs:
{
printf '%s\n' 'Defaults env_keep += "CODEX_HOME CODEX_INTERNAL_ORIGINATOR_OVERRIDE"'
printf '%s\n' 'Defaults env_keep += "BASELINE_REF BASELINE_SHA CANDIDATE_REF CANDIDATE_SHA"'
printf '%s\n' 'Defaults env_keep += "CRABBOX_ACCESS_CLIENT_ID CRABBOX_ACCESS_CLIENT_SECRET CRABBOX_COORDINATOR CRABBOX_COORDINATOR_TOKEN CRABBOX_LEASE_ID CRABBOX_PROVIDER CRABBOX_CAPACITY_REGIONS"'
printf '%s\n' 'Defaults env_keep += "CRABBOX_ACCESS_CLIENT_ID CRABBOX_ACCESS_CLIENT_SECRET CRABBOX_COORDINATOR CRABBOX_COORDINATOR_TOKEN CRABBOX_AWS_REGION CRABBOX_CAPACITY_REGIONS CRABBOX_LEASE_ID CRABBOX_PROVIDER"'
printf '%s\n' 'Defaults env_keep += "GH_TOKEN MANTIS_CANDIDATE_TRUST MANTIS_INSTRUCTIONS MANTIS_OUTPUT_DIR MANTIS_PR_NUMBER"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_BUILD_PRIVATE_QA OPENCLAW_ENABLE_PRIVATE_QA_CLI OPENCLAW_QA_CONVEX_SECRET_CI OPENCLAW_QA_CONVEX_SITE_URL OPENCLAW_QA_CREDENTIAL_OWNER_ID OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_TELEGRAM_USER_CRABBOX_BIN OPENCLAW_TELEGRAM_USER_CRABBOX_PROVIDER OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT OPENCLAW_TELEGRAM_USER_PROOF_CMD"'
@@ -452,6 +455,7 @@ jobs:
CRABBOX_ACCESS_CLIENT_SECRET: ${{ secrets.CRABBOX_ACCESS_CLIENT_SECRET }}
CRABBOX_COORDINATOR: ${{ secrets.CRABBOX_COORDINATOR || secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR }}
CRABBOX_COORDINATOR_TOKEN: ${{ secrets.CRABBOX_COORDINATOR_TOKEN || secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN }}
CRABBOX_AWS_REGION: ${{ env.CRABBOX_AWS_REGION }}
CRABBOX_CAPACITY_REGIONS: ${{ env.CRABBOX_CAPACITY_REGIONS }}
CRABBOX_LEASE_ID: ${{ needs.resolve_request.outputs.lease_id }}
CRABBOX_PROVIDER: ${{ needs.resolve_request.outputs.crabbox_provider }}

View File

@@ -44,6 +44,8 @@ env:
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
CRABBOX_REF: main
CRABBOX_AWS_REGION: us-east-1
CRABBOX_CAPACITY_REGIONS: us-east-1
jobs:
authorize_actor:
@@ -375,6 +377,7 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
CRABBOX_COORDINATOR: ${{ secrets.CRABBOX_COORDINATOR }}
@@ -383,6 +386,8 @@ jobs:
OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN: ${{ secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN }}
CRABBOX_ACCESS_CLIENT_ID: ${{ secrets.CRABBOX_ACCESS_CLIENT_ID }}
CRABBOX_ACCESS_CLIENT_SECRET: ${{ secrets.CRABBOX_ACCESS_CLIENT_SECRET }}
CRABBOX_AWS_REGION: ${{ env.CRABBOX_AWS_REGION }}
CRABBOX_CAPACITY_REGIONS: ${{ env.CRABBOX_CAPACITY_REGIONS }}
CRABBOX_LEASE_ID: ${{ needs.resolve_request.outputs.lease_id }}
CRABBOX_PROVIDER: ${{ needs.resolve_request.outputs.crabbox_provider }}
SCENARIO_INPUT: ${{ needs.resolve_request.outputs.scenario }}

View File

@@ -218,6 +218,7 @@ jobs:
OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE: ci
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
INPUT_SCENARIO: ${{ inputs.scenario }}

View File

@@ -451,7 +451,7 @@ jobs:
OUTPUT_DIR: ${{ runner.temp }}/openclaw-cross-os-release-checks/prepare/baseline
run: |
mkdir -p "${OUTPUT_DIR}"
npm pack --ignore-scripts --json "${BASELINE_SPEC}" --pack-destination "${OUTPUT_DIR}" > "${OUTPUT_DIR}/pack.json"
timeout --preserve-status 300s npm pack --ignore-scripts --json "${BASELINE_SPEC}" --pack-destination "${OUTPUT_DIR}" > "${OUTPUT_DIR}/pack.json"
- name: Capture candidate metadata
id: candidate_metadata

View File

@@ -480,6 +480,35 @@ jobs:
fi
exit 1
plan_release_workflow_matrices:
needs: validate_selected_ref
runs-on: ubuntu-24.04
outputs:
docker_e2e_count: ${{ steps.plan.outputs.docker_e2e_count }}
docker_e2e_matrix: ${{ steps.plan.outputs.docker_e2e_matrix }}
docker_e2e_omitted_json: ${{ steps.plan.outputs.docker_e2e_omitted_json }}
live_models_count: ${{ steps.plan.outputs.live_models_count }}
live_models_matrix: ${{ steps.plan.outputs.live_models_matrix }}
live_models_omitted_json: ${{ steps.plan.outputs.live_models_omitted_json }}
steps:
- name: Checkout trusted release harness
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.sha }}
fetch-depth: 1
- name: Plan release workflow matrices
id: plan
env:
DOCKER_LANES: ${{ inputs.docker_lanes }}
INCLUDE_LIVE_SUITES: ${{ inputs.include_live_suites }}
INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include_release_path_suites }}
LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
RELEASE_TEST_PROFILE: ${{ inputs.release_test_profile }}
run: node scripts/plan-release-workflow-matrix.mjs >> "$GITHUB_OUTPUT"
validate_release_live_cache:
needs: validate_selected_ref
if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'live-cache')
@@ -636,72 +665,15 @@ jobs:
run: ${{ matrix.command }}
validate_docker_e2e:
needs: [validate_selected_ref, prepare_docker_e2e_image]
if: inputs.include_release_path_suites && inputs.docker_lanes == ''
needs: [validate_selected_ref, prepare_docker_e2e_image, plan_release_workflow_matrices]
if: inputs.include_release_path_suites && inputs.docker_lanes == '' && needs.plan_release_workflow_matrices.outputs.docker_e2e_count != '0'
name: Docker E2E (${{ matrix.label }})
continue-on-error: ${{ inputs.advisory }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
matrix:
include:
- chunk_id: core
label: core
timeout_minutes: 60
profiles: stable full
- chunk_id: package-update-openai
label: package/update OpenAI install
timeout_minutes: 45
profiles: beta minimum stable full
- chunk_id: package-update-anthropic
label: package/update Anthropic install
timeout_minutes: 60
profiles: beta minimum stable full
- chunk_id: package-update-core
label: package/update core
timeout_minutes: 60
profiles: beta minimum stable full
- chunk_id: plugins-runtime-plugins
label: plugins/runtime plugins
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-services
label: plugins/runtime services
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-a
label: plugins/runtime install A
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-b
label: plugins/runtime install B
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-c
label: plugins/runtime install C
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-d
label: plugins/runtime install D
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-e
label: plugins/runtime install E
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-f
label: plugins/runtime install F
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-g
label: plugins/runtime install G
timeout_minutes: 60
profiles: stable full
- chunk_id: plugins-runtime-install-h
label: plugins/runtime install H
timeout_minutes: 60
profiles: stable full
matrix: ${{ fromJson(needs.plan_release_workflow_matrices.outputs.docker_e2e_matrix) }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
@@ -1631,42 +1603,14 @@ jobs:
validate_live_models_docker:
name: Docker live models (${{ matrix.provider_label }})
needs: [validate_selected_ref, prepare_live_test_image]
if: inputs.include_live_suites && inputs.live_model_providers == '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models')
needs: [validate_selected_ref, prepare_live_test_image, plan_release_workflow_matrices]
if: inputs.include_live_suites && inputs.live_model_providers == '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models') && needs.plan_release_workflow_matrices.outputs.live_models_count != '0'
continue-on-error: ${{ inputs.advisory }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- provider_label: Anthropic
providers: anthropic
profiles: stable full
- provider_label: Google
providers: google
profiles: stable full
- provider_label: MiniMax
providers: minimax
profiles: stable full
- provider_label: OpenAI
providers: openai
profiles: beta minimum stable full
- provider_label: OpenCode
providers: opencode-go
profiles: full
- provider_label: OpenRouter
providers: openrouter
profiles: full
- provider_label: xAI
providers: xai
profiles: full
- provider_label: Z.ai
providers: zai
profiles: full
- provider_label: Fireworks
providers: fireworks
profiles: full
matrix: ${{ fromJson(needs.plan_release_workflow_matrices.outputs.live_models_matrix) }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
@@ -1744,6 +1688,8 @@ jobs:
- name: Validate provider credential
if: contains(matrix.profiles, inputs.release_test_profile)
shell: bash
env:
LIVE_MODEL_PROVIDERS: ${{ matrix.providers }}
run: |
set -euo pipefail
@@ -1760,7 +1706,7 @@ jobs:
exit 1
}
case "${{ matrix.providers }}" in
case "${LIVE_MODEL_PROVIDERS}" in
anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;;
google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;;
minimax) require_any MiniMax MINIMAX_API_KEY ;;
@@ -1771,7 +1717,7 @@ jobs:
zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;;
fireworks) require_any Fireworks FIREWORKS_API_KEY ;;
*)
echo "Unhandled live model provider shard: ${{ matrix.providers }}" >&2
echo "Unhandled live model provider shard: ${LIVE_MODEL_PROVIDERS}" >&2
exit 1
;;
esac
@@ -1857,7 +1803,6 @@ jobs:
normalize_provider() {
local value="${1,,}"
case "$value" in
z.ai|z-ai) echo "zai" ;;
opencode|opencode-go) echo "opencode-go" ;;
open-router|openrouter) echo "openrouter" ;;
*) echo "$value" ;;
@@ -1987,7 +1932,7 @@ jobs:
- suite_id: native-live-src-gateway-profiles-anthropic-opus
suite_group: native-live-src-gateway-profiles-anthropic
label: Native live gateway profiles Anthropic Opus
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-opus-4-7 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-opus-4-8 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
timeout_minutes: 30
profile_env_only: false
advisory: true
@@ -1995,26 +1940,26 @@ jobs:
- suite_id: native-live-src-gateway-profiles-anthropic-sonnet-haiku
suite_group: native-live-src-gateway-profiles-anthropic
label: Native live gateway profiles Anthropic Sonnet/Haiku
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6,anthropic/claude-haiku-4-5 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6,anthropic/claude-haiku-4-5 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
timeout_minutes: 30
profile_env_only: false
advisory: true
profiles: full
- suite_id: native-live-src-gateway-profiles-google
label: Native live gateway profiles Google
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview,google/gemini-3-flash-preview node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
timeout_minutes: 60
profile_env_only: false
profiles: stable full
- suite_id: native-live-src-gateway-profiles-minimax
label: Native live gateway profiles MiniMax
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MODELS=minimax/MiniMax-M2.7,minimax-portal/MiniMax-M2.7 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
timeout_minutes: 60
profile_env_only: false
profiles: stable full
- suite_id: native-live-src-gateway-profiles-openai
label: Native live gateway profiles OpenAI
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=180000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
timeout_minutes: 60
profile_env_only: false
profiles: beta minimum stable full
@@ -2289,25 +2234,25 @@ jobs:
include:
- suite_id: live-gateway-docker
label: Docker live gateway OpenAI
command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
timeout_minutes: 40
profile_env_only: false
profiles: beta minimum stable full
- suite_id: live-gateway-anthropic-docker
label: Docker live gateway Anthropic
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6,anthropic/claude-haiku-4-5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
timeout_minutes: 40
profile_env_only: false
profiles: stable full
- suite_id: live-gateway-google-docker
label: Docker live gateway Google
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview,google/gemini-3-flash-preview OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
timeout_minutes: 40
profile_env_only: false
profiles: stable full
- suite_id: live-gateway-minimax-docker
label: Docker live gateway MiniMax
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MODELS=minimax/MiniMax-M2.7,minimax-portal/MiniMax-M2.7 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
timeout_minutes: 40
profile_env_only: false
profiles: stable full

View File

@@ -47,8 +47,8 @@ jobs:
# KEEP THIS WORKFLOW SHORT AND DETERMINISTIC OR IT CAN GET STUCK AND JEOPARDIZE THE RELEASE.
# RELEASE-TIME LIVE OR END-TO-END VALIDATION BELONGS IN openclaw-release-checks.yml.
# SECURITY NOTE: TOKEN-BASED npm dist-tag mutation moved to
# openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml
# so this public workflow can stay focused on OIDC publish only.
# openclaw/releases/.github/workflows/openclaw-npm-dist-tags.yml
# so this source workflow can stay focused on OIDC publish only.
preflight_openclaw_npm:
if: ${{ inputs.preflight_only }}
runs-on: ubuntu-latest
@@ -372,6 +372,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Require trusted workflow ref for publish
env:
RELEASE_TAG: ${{ inputs.tag }}
@@ -429,12 +434,13 @@ jobs:
echo "Direct OpenClaw npm publish; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "OpenClaw npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct OpenClaw npm recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
publish_openclaw_npm:
# KEEP THE REAL RELEASE/PUBLISH PATH ON A GITHUB-HOSTED RUNNER.

View File

@@ -551,25 +551,31 @@ jobs:
retention-days: ${{ matrix.deep_profile == 'true' && 14 || 30 }}
- name: Prepare clawgrit reports checkout
id: clawgrit_reports
if: ${{ steps.kova.outputs.report_json != '' && steps.clawgrit.outputs.present == 'true' }}
env:
CLAWGRIT_REPORTS_TOKEN: ${{ secrets.CLAWGRIT_REPORTS_TOKEN }}
shell: bash
run: |
set -euo pipefail
echo "ready=false" >> "$GITHUB_OUTPUT"
reports_root=".artifacts/clawgrit-reports"
mkdir -p "$reports_root"
git -C "$reports_root" init -b main
git -C "$reports_root" remote add origin "https://x-access-token:${CLAWGRIT_REPORTS_TOKEN}@github.com/openclaw/clawgrit-reports.git"
if git -C "$reports_root" ls-remote --exit-code --heads origin main >/dev/null 2>&1; then
git -C "$reports_root" fetch --depth=1 origin main
if timeout 60s git -C "$reports_root" ls-remote --exit-code --heads origin main >/dev/null 2>&1; then
if ! timeout 120s git -C "$reports_root" fetch --depth=1 origin main; then
echo "::warning::Skipping optional clawgrit report publish because the reports checkout fetch timed out or failed."
exit 0
fi
git -C "$reports_root" checkout -B main FETCH_HEAD
else
git -C "$reports_root" checkout -B main
fi
echo "ready=true" >> "$GITHUB_OUTPUT"
- name: Publish to clawgrit reports
if: ${{ steps.kova.outputs.report_json != '' && steps.clawgrit.outputs.present == 'true' }}
if: ${{ steps.kova.outputs.report_json != '' && steps.clawgrit.outputs.present == 'true' && steps.clawgrit_reports.outputs.ready == 'true' }}
env:
CLAWGRIT_REPORTS_TOKEN: ${{ secrets.CLAWGRIT_REPORTS_TOKEN }}
shell: bash
@@ -642,6 +648,9 @@ jobs:
exit 0
fi
sleep $((attempt * 2))
git -C "$reports_root" fetch --depth=1 origin main
timeout 120s git -C "$reports_root" fetch --depth=1 origin main || {
echo "::warning::Skipping optional clawgrit report rebase because the reports fetch timed out or failed."
exit 0
}
git -C "$reports_root" rebase FETCH_HEAD
done

View File

@@ -813,7 +813,7 @@ jobs:
alt_model="openai/gpt-5.5-alt"
;;
baseline)
model="anthropic/claude-opus-4-7"
model="anthropic/claude-opus-4-8"
alt_model="anthropic/claude-sonnet-4-6"
;;
*)
@@ -885,7 +885,7 @@ jobs:
--candidate-summary .artifacts/qa-e2e/openai-candidate/qa-suite-summary.json \
--baseline-summary .artifacts/qa-e2e/anthropic-baseline/qa-suite-summary.json \
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
--baseline-label anthropic/claude-opus-4-7 \
--baseline-label anthropic/claude-opus-4-8 \
--output-dir .artifacts/qa-e2e/parity
- name: Upload parity artifacts
@@ -946,7 +946,7 @@ jobs:
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "openai/gpt-5.5-alt" \
--runtime-pair pi,codex \
--runtime-pair openclaw,codex \
--output-dir ".artifacts/qa-e2e/runtime-parity"
- name: Run standard runtime parity tier
@@ -959,7 +959,7 @@ jobs:
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "openai/gpt-5.5-alt" \
--runtime-pair pi,codex \
--runtime-pair openclaw,codex \
--output-dir ".artifacts/qa-e2e/runtime-parity-standard"
- name: Run soak runtime parity tier
@@ -973,7 +973,7 @@ jobs:
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "openai/gpt-5.5-alt" \
--runtime-pair pi,codex \
--runtime-pair openclaw,codex \
--output-dir ".artifacts/qa-e2e/runtime-parity-soak"
- name: Generate runtime parity report
@@ -1207,6 +1207,7 @@ jobs:
env:
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
run: |

View File

@@ -122,6 +122,10 @@ jobs:
echo "publish_openclaw_npm=true requires dispatching this workflow from main, release/YYYY.M.D, or a Tideclaw alpha branch for alpha prereleases." >&2
exit 1
fi
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" && "${PLUGIN_PUBLISH_SCOPE}" != "all-publishable" ]]; then
echo "publish_openclaw_npm=true requires plugin_publish_scope=all-publishable so every publishable official plugin is released with OpenClaw." >&2
exit 1
fi
if [[ "${PLUGIN_PUBLISH_SCOPE}" == "selected" && -z "${PLUGINS}" ]]; then
echo "plugin_publish_scope=selected requires plugins." >&2
exit 1
@@ -265,7 +269,7 @@ jobs:
run: |
set -euo pipefail
RUN_JSON="$(gh run view "$FULL_RELEASE_VALIDATION_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "Full Release Validation"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"], ["status", "completed"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "Full Release Validation"], ["event", "workflow_dispatch"], ["status", "completed"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } const allowedBranches = new Set(["main", process.env.EXPECTED_WORKFLOW_BRANCH].filter(Boolean)); if (!allowedBranches.has(run.headBranch)) { console.error(`Referenced full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID} must have headBranch in ${[...allowedBranches].join(", ")}, got ${run.headBranch ?? "<missing>"}.`); process.exit(1); } console.log(`Using full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID}: ${run.url}`);'
manifest="${RUNNER_TEMP}/full-release-validation-manifest/full-release-validation-manifest.json"
if [[ ! -f "$manifest" ]]; then
@@ -810,7 +814,7 @@ jobs:
`- npm package: https://www.npmjs.com/package/openclaw/v/${process.env.RELEASE_VERSION}`,
`- registry tarball: ${process.env.RELEASE_TARBALL}`,
`- integrity: \`${process.env.RELEASE_INTEGRITY}\``,
`- full release CI report: https://github.com/openclaw/releases-private/blob/main/evidence/${process.env.RELEASE_VERSION}/release-evidence.md`,
`- full release CI report: https://github.com/openclaw/releases/blob/main/evidence/${process.env.RELEASE_VERSION}/release-evidence.md`,
`- release publish: https://github.com/${process.env.RELEASE_REPO}/actions/runs/${process.env.RELEASE_PUBLISH_RUN_ID}`,
`- npm preflight: https://github.com/${process.env.RELEASE_REPO}/actions/runs/${process.env.PREFLIGHT_RUN_ID}`,
`- full release validation: https://github.com/${process.env.RELEASE_REPO}/actions/runs/${process.env.FULL_RELEASE_VALIDATION_RUN_ID}`,

View File

@@ -32,11 +32,11 @@ jobs:
- name: Install opengrep
env:
# Pin both the install script (by commit SHA) and the binary version.
# The script SHA must match the v1.19.0 release tag in opengrep/opengrep
# The script SHA must match the v1.22.0 release tag in opengrep/opengrep
# so a compromised or force-pushed `main` cannot RCE in our CI runner.
# Bump both together when upgrading.
OPENGREP_VERSION: v1.19.0
OPENGREP_INSTALL_SHA: 9a4c0a68220618441608cd2bad4ff2eddccf8113
OPENGREP_VERSION: v1.22.0
OPENGREP_INSTALL_SHA: f458d7f0d52cc58eae1ca3cf3d5caf101e637519
run: |
curl -fsSL "https://raw.githubusercontent.com/opengrep/opengrep/${OPENGREP_INSTALL_SHA}/install.sh" \
| bash -s -- -v "$OPENGREP_VERSION"

View File

@@ -44,7 +44,7 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
fetch-depth: 0
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
@@ -58,11 +58,11 @@ jobs:
- name: Install opengrep
env:
# Pin both the install script (by commit SHA) and the binary version.
# The script SHA must match the v1.19.0 release tag in opengrep/opengrep
# The script SHA must match the v1.22.0 release tag in opengrep/opengrep
# so a compromised or force-pushed `main` cannot RCE in our CI runner.
# Bump both together when upgrading.
OPENGREP_VERSION: v1.19.0
OPENGREP_INSTALL_SHA: 9a4c0a68220618441608cd2bad4ff2eddccf8113
OPENGREP_VERSION: v1.22.0
OPENGREP_INSTALL_SHA: f458d7f0d52cc58eae1ca3cf3d5caf101e637519
run: |
curl -fsSL "https://raw.githubusercontent.com/opengrep/opengrep/${OPENGREP_INSTALL_SHA}/install.sh" \
| bash -s -- -v "$OPENGREP_VERSION"

View File

@@ -207,6 +207,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -222,12 +227,13 @@ jobs:
echo "Direct Plugin ClawHub Release dispatch; relying on this workflow's clawhub-plugin-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "Plugin ClawHub publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct Plugin ClawHub Release recovery with release_publish_run_id; relying on this workflow's clawhub-plugin-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
preview_plugin_pack:
needs: preview_plugins_clawhub
@@ -431,7 +437,8 @@ jobs:
EOF
echo "CLAWHUB_CONFIG_PATH=${RUNNER_TEMP}/clawhub-config.json" >> "$GITHUB_ENV"
- name: Ensure version is not already published
- name: Check ClawHub package version
id: clawhub_package_version
env:
PACKAGE_NAME: ${{ matrix.plugin.packageName }}
PACKAGE_VERSION: ${{ matrix.plugin.version }}
@@ -456,14 +463,17 @@ jobs:
done
if [[ "${status}" =~ ^2 ]]; then
echo "${PACKAGE_NAME}@${PACKAGE_VERSION} is already published on ClawHub."
exit 1
echo "already_published=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "${status}" != "404" ]]; then
echo "Unexpected ClawHub response (${status}) for ${PACKAGE_NAME}@${PACKAGE_VERSION}."
exit 1
fi
echo "already_published=false" >> "$GITHUB_OUTPUT"
- name: Publish
if: steps.clawhub_package_version.outputs.already_published != 'true'
env:
CLAWHUB_REGISTRY: ${{ env.CLAWHUB_REGISTRY }}
SOURCE_REPO: ${{ github.repository }}

View File

@@ -184,6 +184,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -199,12 +204,13 @@ jobs:
echo "Direct Plugin NPM Release dispatch; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "Plugin npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct Plugin NPM Release recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
preview_plugin_pack:
needs: preview_plugins_npm
@@ -263,7 +269,8 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
install-bun: "false"
- name: Ensure version is not already published
- name: Check npm package version
id: npm_package_version
env:
PACKAGE_NAME: ${{ matrix.plugin.packageName }}
PACKAGE_VERSION: ${{ matrix.plugin.version }}
@@ -271,10 +278,13 @@ jobs:
set -euo pipefail
if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
echo "${PACKAGE_NAME}@${PACKAGE_VERSION} is already published on npm."
exit 1
echo "already_published=true" >> "$GITHUB_OUTPUT"
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish
if: steps.npm_package_version.outputs.already_published != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -52,6 +52,7 @@ env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
OPENCLAW_CI_OPENAI_FALLBACK_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_FALLBACK_MODEL || 'openai/gpt-5.4' }}
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
@@ -198,13 +199,13 @@ jobs:
--alt-model openai/gpt-5.5-alt \
--output-dir .artifacts/qa-e2e/openai-candidate
- name: Run Opus 4.7 lane
- name: Run Opus 4.8 lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model anthropic/claude-opus-4-7 \
--model anthropic/claude-opus-4-8 \
--alt-model anthropic/claude-sonnet-4-6 \
--output-dir .artifacts/qa-e2e/anthropic-baseline
@@ -215,7 +216,7 @@ jobs:
--candidate-summary .artifacts/qa-e2e/openai-candidate/qa-suite-summary.json \
--baseline-summary .artifacts/qa-e2e/anthropic-baseline/qa-suite-summary.json \
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
--baseline-label anthropic/claude-opus-4-7 \
--baseline-label anthropic/claude-opus-4-8 \
--output-dir .artifacts/qa-e2e/parity
- name: Upload parity artifacts
@@ -288,8 +289,8 @@ jobs:
--runtime-parity-tier live-only \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--runtime-pair pi,codex \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--runtime-pair openclaw,codex \
--fast \
--allow-failures \
--output-dir "${output_dir}/runtime-suite"
@@ -373,7 +374,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--profile "${INPUT_MATRIX_PROFILE}" \
--fast
)
@@ -457,7 +458,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--profile "${{ matrix.profile }}" \
--fast
)
@@ -529,6 +530,7 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.scenario || '' }}
@@ -555,7 +557,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci \
@@ -649,7 +651,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model openai/gpt-5.5 \
--alt-model openai/gpt-5.5 \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci \
@@ -746,7 +748,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci \
@@ -840,7 +842,7 @@ jobs:
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci \

View File

@@ -90,7 +90,7 @@ jobs:
bash -lc 'apt-get update -y && apt-get install -y curl && bash /tmp/install-cli.sh --prefix /tmp/openclaw --no-onboard --version latest && /tmp/openclaw/bin/openclaw --version'
macos-installer:
runs-on: macos-latest
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v6

View File

@@ -197,4 +197,4 @@ jobs:
- name: Testbox action marker
if: ${{ false }}
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d

View File

@@ -34,7 +34,10 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Fail on tabs in workflow files
@@ -75,7 +78,10 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Install actionlint
@@ -116,7 +122,10 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
git -C "$GITHUB_WORKSPACE" fetch --no-tags --depth=1 origin "+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout"
git -C "$GITHUB_WORKSPACE" checkout --detach refs/remotes/origin/checkout
- name: Setup Node environment

14
.gitignore vendored
View File

@@ -59,6 +59,8 @@ apps/ios/.swiftpm/
apps/ios/.derivedData/
apps/ios/.local-signing.xcconfig
vendor/
!src/auto-reply/reply/export-html/vendor/
!src/auto-reply/reply/export-html/vendor/**
apps/ios/Clawdbot.xcodeproj/
apps/ios/Clawdbot.xcodeproj/**
apps/macos/.build/**
@@ -101,9 +103,13 @@ USER.md
# though the bare names match the local-untracked rule above.
!extensions/oc-path/src/oc-path/tests/fixtures/real/IDENTITY.md
!extensions/oc-path/src/oc-path/tests/fixtures/real/USER.md
!docs/reference/templates/IDENTITY.md
!docs/reference/templates/USER.md
*.tgz
*.tar.gz
*.zip
!test/fixtures/plugins-install/*.tgz
!test/fixtures/plugins-install/*.zip
.idea
.vscode/
@@ -128,10 +134,7 @@ mantis/
!.agents/skills/control-ui-e2e/**
!.agents/skills/gitcrawl/
!.agents/skills/gitcrawl/**
!.agents/skills/technical-documentation/
!.agents/skills/technical-documentation/**
!.agents/skills/openclaw-refactor-docs/
!.agents/skills/openclaw-refactor-docs/**
!.agents/skills/openclaw-docs/**
!.agents/skills/openclaw-debugging/
!.agents/skills/openclaw-debugging/**
!.agents/skills/openclaw-ghsa-maintainer/
@@ -178,6 +181,7 @@ mantis/
/local/
/client_secret_*.json
package-lock.json
!src/commands/copilot-sdk-install-manifest/package-lock.json
.claude/
.agent/
skills-lock.json
@@ -249,6 +253,8 @@ extensions/qa-lab/web/dist/
# Generated bundled plugin runtime dependency manifests
extensions/**/.openclaw-runtime-deps.json
extensions/**/.openclaw-runtime-deps-stamp.json
extensions/diffs/assets/viewer-runtime.js
extensions/diffs-language-pack/assets/viewer-runtime.js
# Output dir for scripts/run-opengrep.sh (local opengrep scans)
/.opengrep-out/

View File

@@ -30,6 +30,7 @@
"docker-compose.yml",
"dist/",
"docs/_layouts/",
"extensions/diffs/assets/viewer-runtime.js",
"**/*.json",
"node_modules/",
"patches/",

View File

@@ -20,34 +20,44 @@
"eslint/no-multi-str": "error",
"eslint/no-new": "error",
"eslint/no-object-constructor": "error",
"eslint/no-param-reassign": "error",
"eslint/no-proto": "error",
"eslint/no-regex-spaces": "error",
"eslint/no-return-assign": "error",
"eslint/no-sequences": "error",
"eslint/no-self-compare": "error",
"eslint/no-shadow": "off",
"eslint/no-implicit-coercion": "error",
"eslint/no-var": "error",
"eslint/no-useless-call": "error",
"eslint/no-useless-computed-key": "error",
"eslint/no-useless-concat": "error",
"eslint/no-useless-constructor": "error",
"eslint/no-useless-rename": "error",
"eslint/no-useless-return": "error",
"eslint/no-unused-vars": "off",
"eslint/no-warning-comments": "error",
"eslint/no-unmodified-loop-condition": "error",
"eslint/no-new-wrappers": "error",
"eslint/no-else-return": "error",
"eslint/no-lonely-if": "error",
"eslint/no-case-declarations": "error",
"eslint/default-case-last": "error",
"eslint/default-param-last": "error",
"eslint/prefer-exponentiation-operator": "error",
"eslint/prefer-const": "error",
"eslint/prefer-numeric-literals": "error",
"eslint/prefer-object-has-own": "error",
"eslint/object-shorthand": "error",
"eslint/prefer-rest-params": "error",
"eslint/prefer-spread": "error",
"eslint/radix": "error",
"eslint/unicode-bom": "error",
"eslint/yoda": "error",
"import/no-absolute-path": "error",
"import/first": "error",
"import/no-empty-named-blocks": "error",
"import/no-duplicates": "error",
"import/no-self-import": "error",
"node/no-exports-assign": "error",
"eslint-plugin-unicorn/prefer-set-size": "error",
@@ -66,7 +76,9 @@
"typescript/no-empty-object-type": ["error", { "allowInterfaces": "with-single-extends" }],
"typescript/no-explicit-any": "error",
"typescript/no-extraneous-class": "error",
"typescript/no-import-type-side-effects": "error",
"typescript/no-meaningless-void-operator": "error",
"typescript/no-inferrable-types": "error",
"typescript/no-non-null-asserted-nullish-coalescing": "error",
"typescript/no-unnecessary-qualifier": "error",
"typescript/no-unnecessary-type-assertion": "error",
@@ -86,6 +98,7 @@
"typescript/prefer-namespace-keyword": "error",
"typescript/prefer-return-this-type": "error",
"typescript/prefer-find": "error",
"typescript/prefer-for-of": "error",
"typescript/prefer-function-type": "error",
"typescript/prefer-includes": "error",
"typescript/prefer-reduce-type-parameter": "error",
@@ -106,14 +119,17 @@
"unicorn/no-new-buffer": "error",
"unicorn/no-thenable": "error",
"unicorn/no-typeof-undefined": "error",
"unicorn/no-unreadable-array-destructuring": "error",
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-useless-error-capture-stack-trace": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-node-protocol": "error",
@@ -123,6 +139,8 @@
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-set-size": "error",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-structured-clone": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/require-array-join-separator": "error",
@@ -182,10 +200,12 @@
"dist-runtime/",
"docs/_layouts/",
"extensions/diffs/assets/viewer-runtime.js",
"extensions/diffs-language-pack/assets/viewer-runtime.js",
"extensions/canvas/src/host/a2ui/a2ui.bundle.js",
"node_modules/",
"patches/",
"pnpm-lock.yaml",
"skills/",
"skills/**",
"src/auto-reply/reply/export-html/template.js",
"src/canvas-host/a2ui/a2ui.bundle.js",
"vendor/",

View File

@@ -35,9 +35,9 @@ Skills own workflows; root owns hard policy and routing.
## Map
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `src/gateway/protocol/*`; docs/apps: `docs/`, `apps/`.
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `packages/gateway-protocol/*`; docs/apps: `docs/`, `apps/`.
- Installers: sibling `../openclaw.ai`.
- Scoped guides: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,gateway/protocol,agents}/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
- Scoped guides: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,agents}/`, `packages/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
## Docs
@@ -57,6 +57,7 @@ Skills own workflows; root owns hard policy and routing.
- External official plugins own package/deps and are excluded from core dist; core uses registry-aware `facade-runtime` or generic contracts.
- Externalizing a bundled plugin: update package excludes, official catalogs, docs, tests, and prove core runtime paths resolve installed plugin roots before root-dep removal.
- Runtime reads canonical config only. No silent compat for old/malformed config keys. If a config change invalidates existing files, add a matching `openclaw doctor --fix` migration. Core/auth config repairs live in core doctor; plugin-owned config repairs live in that plugin's doctor contract (`legacyConfigRules` / `normalizeCompatibilityConfig`).
- CLI setup flows are public API when external docs, installers, or integrations can copy them. Changes to `openclaw onboard`, `openclaw configure`, their documented flags, non-interactive behavior, or generated config shape are compatibility-sensitive API contract changes; prefer additive flags/aliases, deprecation windows, and backward-preserving migrations over breaking existing snippets.
- Fix shape: default to clean bounded refactor, not smallest patch. Move ownership to right boundary; delete stale abstractions, duplicate policy, dead branches, wrappers, fallback stacks.
- Fix observed local failures with generic product rules; do not hardcode names, ids, log phrases, or user examples in prod code unless they are an explicit contract.
- Tests may use observed examples, but prod literals need a short contract reason.
@@ -71,12 +72,13 @@ Skills own workflows; root owns hard policy and routing.
- Plugin SDK exception: shipped external API gets new API first plus named compat/deprecation, small tests/docs if useful, removal plan.
- Migrate internal/bundled callers to modern API in the same change. Do not let internal compat become permanent architecture.
- Channels are implementation under `src/channels/**`; plugin authors get SDK seams. Providers own auth/catalog/runtime hooks; core owns generic loop.
- Agent run terminal state: normalize/merge via `src/agents/agent-run-terminal-outcome.ts`; do not rederive timeout/cancel precedence in projections.
- Hot paths should carry prepared facts forward: provider id, model ref, channel id, target, capability family, attachment class. Do not rediscover with broad plugin/provider/channel/capability loaders.
- Do not fix repeated request-time discovery with scattered caches. Move the canonical fact earlier; reuse prepared runtime objects; delete duplicate lookup branches.
- Gateway/plugin metadata is process-stable: installs, manifests, catalogs, generated paths, bundled metadata. Changes require restart or explicit owner reload/install/doctor flow.
- Runtime hot paths: no freshness polling (`stat`/`realpath`/JSON reread/hash). Reuse current snapshots, install records, discovery, lookup tables, root scopes, resolved paths.
- Process-local metadata caches ok when lifecycle-owned and bounded/single-slot. Freshness exceptions need named owner + tests.
- Inline comments: preserve reviewer context at the code site. Use for cross-path/state invariants, platform/dependency caps, deterministic ordering, compact encoded state, lifecycle ordering, ownership boundaries, session/id adoption, queue-depth symmetry, fallbacks, or intentional caller differences.
- Inline comments: preserve reviewer context at the code site. Required for non-obvious cross-path/state invariants, lifecycle ordering, ownership boundaries, queue/dedupe symmetry, TTL/cache expiry, cleanup/release coupling, session/id adoption, fallback behavior, platform/dependency caps, deterministic ordering, compact encoded state, or intentional caller differences.
- Comment shape: 1-3 short lines; state why the branch/helper exists, what contract it protects, and the bad outcome if removed. Cite nearby constants/helpers when useful. No syntax narration, PR/user-specific lore, or obvious mechanics.
- Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
- Protocol version bumps: explicit owner confirmation only; never automatic/generated.
@@ -91,6 +93,7 @@ Skills own workflows; root owns hard policy and routing.
- Install: `pnpm install` (keep Bun lock/patches aligned if touched).
- CLI: `pnpm openclaw ...` or `pnpm dev`; build: `pnpm build`.
- Tests in a normal source checkout: `pnpm test <path-or-filter> [vitest args...]`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`; never raw `vitest`.
- If raw Vitest is unavoidable, use `vitest run ...`; bare `vitest ...` starts local watch mode and will not exit on its own.
- Tests in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm test*`; use `node scripts/run-vitest.mjs <path-or-filter>` for tiny explicit-file proof, or Crabbox/Testbox for anything broader.
- Checks in a normal source checkout: `pnpm check:changed`; lanes: `pnpm changed:lanes --json`; staged: `pnpm check:changed --staged`; full: `pnpm check`.
- Checks in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm check*`; use `node scripts/crabbox-wrapper.mjs run ... --shell -- "pnpm check:changed"` so pnpm runs inside Testbox, not locally.
@@ -151,19 +154,9 @@ Skills own workflows; root owns hard policy and routing.
- Calls should be boring: complex decisions happen above; call args/object fields are names, literals, or simple property reads.
- Prefer early returns over nested condition pyramids. Split code into gather -> normalize -> decide -> act.
- Use named intermediates only for domain meaning or readability; avoid temp-variable soup.
- Code size matters. Prefer small clear code; maintainability includes not growing LOC without payoff.
- Refactors should delete about as much local complexity as they add. If LOC grows, the new ownership/API needs to clearly pay for it.
- Before adding helpers/files, check whether existing code can absorb the behavior with less new surface.
- Keep APIs narrow: export only current caller needs; keep types/helpers local by default.
- Return the smallest useful shape. Avoid broad result objects, flags, metadata unless callers use them.
- Avoid adapter layers that only rename fields. Move real responsibility or leave code local.
- Inline simple one-use objects/spreads when clearer. Extract only when it removes duplication or hard logic.
- Tests prove behavior/regressions, not every internal branch.
- For non-trivial refactors, check `git diff --numstat` before closeout. If LOC grew, trim or explain why.
- Prefer existing narrow helpers over repeated casts/guards. Add local helpers when 2+ nearby call sites share real boundary logic.
- Prefer ctor parameter properties for injected deps/config. Do not ban them for erasable-syntax purity.
- Prefer `satisfies` for registries/config maps; derive types from schemas when a runtime schema already exists.
- Table-drive repetitive tests when it reduces code and keeps failure names clear.
- Storage adapters: quarantine schema/nullability mess at the boundary. Use one named mapper from domain object to DB row, one mapper from DB row to domain object, and keep read/write paths boring.
- Discriminated unions: use exhaustive `switch` mappers instead of repeated inline conditionals. If insert/update share shape, build the row once and reuse it; split primary keys once for update sets.
- Kysely rows: prefer generated `Insertable`/`Selectable` types for mapper contracts. Do not duplicate nullable-column logic inside `values(...)` and `doUpdateSet(...)`.
- Dynamic import: no static+dynamic import for same prod module. Use `*.runtime.ts` lazy boundary. After edits: `pnpm build`; check `[INEFFECTIVE_DYNAMIC_IMPORT]`.
- Cycles: keep `pnpm check:import-cycles` + architecture/madge green.
- Classes: no prototype mixins/mutations. Prefer inheritance/composition. Tests prefer per-instance stubs.
@@ -211,6 +204,7 @@ Skills own workflows; root owns hard policy and routing.
- Lockfiles/shrinkwrap are security surface: review `pnpm-lock.yaml`, `npm-shrinkwrap.json`, `package-lock.json`; root/plugin npm packages ship shrinkwrap, not package-lock.
- Carbon pins owner-only: do not change `@buape/carbon` unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
- Releases/publish/version bumps need explicit approval. Use `$release-openclaw-maintainer`.
- Backport means apply to newest open `release/` branch unless user names another target.
- GHSA/advisories: `$openclaw-ghsa-maintainer` / `$security-triage`. Secret scanning: `$openclaw-secret-scanning-maintainer`.
- Beta tag/version match: `vYYYY.M.D-beta.N` -> npm `YYYY.M.D-beta.N --tag beta`.
@@ -225,6 +219,8 @@ Skills own workflows; root owns hard policy and routing.
- Parallels: `$openclaw-parallels-smoke`; Discord roundtrip: `$parallels-discord-roundtrip`.
- Crabbox/WebVNC human demos: keep remote desktop visible/windowed; no fullscreen remote browser unless video/capture-style output.
- ClawSweeper ops: `$clawsweeper`. Deployed hook sessions may post one concise `#clawsweeper` note only when surprising/actionable/risky; if using message tool, reply exactly `NO_REPLY`.
- Generated-media completions wake the requester agent first. Requester visible-reply config decides final text vs message tool; direct media send is fallback/recovery only.
- `message_tool_only`: visible source reply = current-source `message(action=send)` only. No `NO_REPLY` prompt/contract; no message call = no source reply. Never auto-publish private final.
- Memory wiki prompt digest stays tiny; prefer `wiki_search` / `wiki_get`; verify contact data before use; source-class provenance for generated people facts.
- Rebrand/migration/config warnings: run `openclaw doctor`.
- Never edit `node_modules`.

View File

@@ -2,6 +2,156 @@
Docs: https://docs.openclaw.ai
## 2026.5.30
### Highlights
- Agents and CLI-backed runtimes recover more cleanly from interrupted tool calls, stale session bindings, compaction handoffs, and media delivery retries. (#88129, #88136, #88141, #88162, #88182)
- Channels and mobile delivery are steadier across Telegram, WhatsApp, iMessage, Slack, Discord, Microsoft Teams, Google Chat, Google Meet, and iOS realtime Talk. (#88096, #88105, #88183, #88231)
- Provider and plugin requests now bound more timers, retries, OAuth/device-code lifetimes, media downloads, local service probes, and generated-content polling paths before they can hang a run.
- Skills, session metadata, gateway runtime state, plugin metadata, and store writes do less repeated work on hot paths while keeping config and dispatch behavior stable.
- Workboard, SecretRef plugin manifests, hosted iOS push relay, and external Copilot/Tokenjuice packaging add broader orchestration, integration, and plugin delivery surfaces. (#82326, #87469, #87796, #88107, #88117)
- Release, CI, Docker, E2E, and diagnostics lanes now cap more logs, response bodies, readiness probes, artifact checks, and status polling so failures report bounded proof instead of stalling.
### Changes
- Docs: add a dedicated Skill Workshop guide covering governed skill creation, reviewable proposals, CLI, Gateway, agent tool behavior, approval policy, support files, and recovery. Thanks @shakkernerd.
- Skills: let the `skill_workshop` agent tool apply, reject, and quarantine explicit proposals through the guarded review flow. Thanks @shakkernerd.
- Skills: let proposals carry approved support files under standard skill folders, with scanner, hash, and rollback safeguards. Thanks @shakkernerd.
- Skills: let pending proposals be revised in place with versioned, dated proposal frontmatter before approval. Thanks @shakkernerd.
- Skills: add Skill Workshop with pending proposals, CLI/Gateway review actions, rollback metadata, and the `skill_workshop` agent tool. Thanks @shakkernerd.
- Plugins: externalize Tokenjuice as the official `@openclaw/tokenjuice` plugin with npm and ClawHub publish metadata.
- Plugins: externalize the GitHub Copilot agent runtime as the official `@openclaw/copilot` plugin with npm and ClawHub publish metadata.
- iOS: add hosted push relay defaults, realtime Talk playback, and a guarded WebSocket ping path for more reliable mobile sessions. (#88096, #88105, #88231)
- Workboard: add orchestration primitives and agent coordination tools for multi-agent planning and run tracking. (#87469)
- Code mode: add internal namespaces for scoped agent/global sessions and exact namespace tool dispatch. (#88043)
- Control UI: add a Dreaming-tab agent selector and propagate the selected agent through Dreaming status, diary, and diary actions. (#78748) Thanks @stevenepalmer.
- Plugins: add a SecretRef provider integration manifest contract and extract shared LLM core packages for provider/plugin reuse. (#82326, #88117)
- Skills: add the core skills index and centralize skills runtime loading, status, filtering, and prompt formatting.
### Fixes
- Agents/Codex: keep public OpenAI API-key profiles from being treated as native Codex app-server auth while preserving persisted Codex OAuth sessions.
- Control UI: keep collapsed tool cards labeled with the tool name and action instead of generic output text. Thanks @shakkernerd.
- Agents/Codex: surface Skill Workshop guidance in Codex app-server prompts when `skill_workshop` is available. Thanks @shakkernerd.
- CLI: keep `plugins list --json` on the snapshot-only path so plugin sweeps avoid loading the full runtime status graph.
- Plugins: make PixVerse external-plugin ClawHub metadata explicit and keep it out of bundled dist builds.
- Cron: keep SQLite cron migrations compatible with legacy run-log tables, archived job stores, diagnostic cron names, and legacy one-shot delete-after-run behavior. (#88285)
- Providers: bound generated media downloads from OpenAI, Runway, xAI, MiniMax, BytePlus, DashScope-compatible, FAL, OpenRouter, Google, Vydra, and Comfy providers.
- Providers: cap GitHub Copilot OAuth request timeouts before creating abort signals.
- Cron: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot.
- Agents/Codex: keep live session locks during cleanup, recover interrupted CLI tool transcripts, preserve Codex auth and compaction session identity, clear orphan tool state, cap app-server idle timers, and keep media completion delivery retryable. (#88129, #88136, #88141, #88162, #88182)
- Chat/UI: show Gateway chat failures as visible assistant messages in the Control UI instead of only setting an invisible error state.
- Channels: cap Telegram, Discord, WhatsApp, Signal, Feishu, Google Chat, Microsoft Teams, QQBot, Nostr, Zalo, Zalouser, and Nextcloud-style request/retry timers; preserve SMS approval reply routes; and retry WhatsApp QR login 408 timeouts. (#88183)
- Security/config parsing: reject unsafe OAuth/token lifetimes, retry-after delays, inbound timestamps, response body sizes, command timeout config, sandbox observer token TTLs, and gateway WebSocket calls after close.
- Providers/media: cap local service, model, usage, queue, generated media, TTS, music, workflow polling, and provider OAuth request timers across hosted and local providers.
- Release/CI/E2E: bound release candidate reads, beta smoke REST calls, changelog restore, kitchen-sink and bundled plugin readiness probes, secret-provider probes, Vitest routing, and mainline test flakes. (#88127, #88137, #88155, #88160)
- Release/CI/E2E: run the secret-provider integration proof through the repo pnpm runner so native macOS and Windows validation use the hydrated package-manager shim.
- Release/CI/E2E: run the Telegram desktop proof gateway through the repo pnpm runner so native macOS proof uses the hydrated package-manager shim.
- Docs/CI: run Mintlify anchor checks through the repo pnpm runner so docs link validation works when pnpm is only available through the hydrated package-manager shim.
- Agents: keep configured fallback model metadata typed so provider params, context-token caps, and media input limits do not break changed-gate typechecks.
- Agents: accept hidden `sessions_send` body aliases before validation while keeping the model-facing `message` schema canonical. (#88229) Thanks @zhangguiping-xydt.
- CI/Crabbox: keep default runner capacity spot-only and provider-neutral so OpenClaw remote validation does not silently fall back to on-demand leases or stale AWS region hints.
- CI/Crabbox: route Crabbox wrapper and Testbox workflow edits to their regression tests so changed-test gates do not silently run zero specs.
- CI/workflows: route workflow sanity helper edits to their guard tests and cover composite-action input interpolation checks.
- CI/tooling: route CI scope, dependency, changelog, and docs helper edits to their owner tests instead of silently skipping changed-test coverage.
- CI/tooling: route package, release, and install helper edits to their owner tests so changed-test gates cover publish and installer script changes.
- CI/tooling: route shared script library edits through their owner tests so lock, process, safety, and scan helpers do not skip changed-test coverage.
- CI/tooling: skip expensive import-graph scans once a changed diff already requires broad fallback, keeping local changed-test planning fast while still collecting explicit owner tests.
- CI/tooling: route script edits through conventional owner tests when matching `test/scripts` or `src/scripts` coverage already exists.
- CI/tooling: honor option terminators in the memory FD repro script so follow-on arguments are not reparsed.
- Release/CI/E2E: assert plugin lifecycle runtime inspect output instead of only capturing it.
- Release/CI/E2E: make gateway-network prove the advertised health RPC and retry early WebSocket closes without burning full open timeouts.
- Release/CI/E2E: honor option terminators across release, Parallels smoke, plugin gauntlet, and extension-memory scripts.
- Release/CI/E2E: fail plugin gateway gauntlet QA chunks when the requested suite summary is missing or invalid.
- Performance: prebuild QA runtime probes with generated plugin assets but without CLI startup metadata.
- Performance: skip declaration bundling for runtime-only CLI startup and gateway watch build profiles.
- Performance: reuse prepared provider handles, strict tool schemas, gateway runtime metadata, session maintenance config, plugin metadata, bundled skill allowlists, package-local plugin artifacts, single-entry store writes, and validated/serialized session prompt blobs.
## 2026.5.28
### Highlights
- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman and @BunsDev.
- Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)
- Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)
- Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.
### Changes
- Status: show active subagent details in status output.
- Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.
- ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.
- iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.
- PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)
- Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.
- Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.
- Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.
- Workboard: add agent coordination tools for tracking and handing off active agent work.
- Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)
- Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @piersonr and @RomneyDa.
- Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)
### Fixes
- Agents: fall back to local config pruning when the optional `agents delete` Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.
- Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.
- Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.
- Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, @benjamin1492, @c19354837, @fuller-stack-dev, @pfrederiksen, and @dodge1218.
- Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @jarvis-mns1, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @lidge-jun, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.
- Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.
- Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887) Thanks @chen-zhang-cs-code.
- Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)
- WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492) Thanks @lidge-jun.
- Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.
- Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)
- Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611) Thanks @ferminquant.
- Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @Pluviobyte and @eleqtrizit.
- Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)
- File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.
- Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)
## 2026.5.27
### Highlights
- Safer local/runtime boundaries: OpenClaw now rejects unsafe command wrappers, malformed CLI numeric options, unsafe Node runtime env overrides, no-auth Tailscale exposure, and non-admin device-role pairing approvals before they can affect live runs. (#87308, #87305, #87292, #87146)
- Matrix and auto-reply delivery are steadier: mention previews stay inert, final mention replies deliver normally, shared-DM notices are awaited, MXID parsing ignores filenames, and reasoning-prefixed `NO_REPLY` responses stay suppressed.
- Provider and agent reliability improved across OpenAI-compatible embeddings, cached token usage, Anthropic/Codex/Claude runtime state, unsupported tool-schema quarantine, heartbeat templates, and session fallback errors. (#85269, #82062, #85416, #86855)
- Plugin and package release paths got tighter: Pixverse ships as an external video plugin with region selection, package exclusions and shrinkwrap inventory match the published npm shape, and release/package smoke commands fail bounded instead of hanging.
- Gateway hot paths do less rediscovery by reusing current plugin metadata fingerprints, stable plugin index fingerprints, read-only session metadata, active working stores, status fast paths, and auth/env snapshots. (#86439)
### Changes
- Memory: add a core OpenAI-compatible embedding provider for local and hosted OpenAI-style endpoints, with config, doctor, and docs support. (#85269) Thanks @dutifulbob.
- Plugin SDK: mark memory-specific embedding provider registration as deprecated compatibility and surface non-bundled usage in plugin compatibility diagnostics. (#85072) Thanks @mbelinky.
- Pixverse: add video generation provider support, API region selection, and external plugin publishing.
- Plugins: expose approval action metadata for plugin-driven approval surfaces.
### Fixes
- Security/CLI/runtime: harden hostname normalization for repeated trailing dots, block side-effecting command wrappers, reject unsafe Node runtime env overrides, reject loose numeric CLI and gateway options, require admin approval for node device-role pairing, and reject no-auth Tailscale exposure. (#87305, #87292, #87308, #87146) Thanks @pgondhi987.
- Doctor: validate runtime tool schemas for every configured embedded agent while skipping ACP-only profiles, so bad non-default plugin or MCP tools are reported before assistant turns.
- Telegram: route `sendMessage` action replies through durable outbound delivery so completed agent responses remain retryable when the gateway send path times out. (#87261) Thanks @mbelinky.
- Matrix/auto-reply: keep draft previews mention-inert, preserve final mention delivery, send mention finals normally, await shared DM notices, ignore filename-embedded MXIDs, and suppress reasoning-prefixed `NO_REPLY` responses.
- Agents/providers: add OpenAI-compatible cache retention, forward cached token usage in chat completions, preserve runtime context before active user turns, strip stale Anthropic thinking, load Claude CLI OAuth for Pi auth profiles, avoid false Codex runtime live switches, and quarantine unsupported tool schemas. (#82062, #87167, #86855)
- Gateway/performance: cache plugin metadata fingerprints and stable plugin index fingerprints, borrow read-only session metadata safely, keep the active session working store hot, keep status on a bounded fast path, and preserve model auth profile suffixes. (#86439)
- Package/install/release: align npm package exclusions and inventory, omit unpacked test helpers, skip Homebrew until macOS packages need it, cap tsdown heap in containers, bound install/release smoke waits, and harden post-publish verification.
- Codex/Auth: bound ChatGPT OAuth token exchange and refresh requests, and honor cancellation across Codex and Anthropic OAuth login flows.
- QA/E2E/CI: bound Telegram, kitchen-sink, Open WebUI, ClawHub, MCP, Discord, realtime, labeler, and GitHub API waits; fail empty explicit test, live-media, gateway CPU, startup benchmark, plugin gauntlet, and beta-smoke runs instead of false-greening.
- Agents/Codex: keep spawned agent bootstrap files rooted in the agent workspace while running task commands, transcripts, and compaction from the requested cwd. (#87218) Thanks @mbelinky.
## 2026.5.26
### Highlights
@@ -34,7 +184,7 @@ Docs: https://docs.openclaw.ai
- Voice: share activation-name matching and consult-transcript screening through the realtime voice SDK so Discord, browser voice, and meeting surfaces can reuse one implementation.
- Cron: default `cron.maxConcurrentRuns` to 8 so scheduled automations and their isolated agent turns can make progress in parallel without explicit configuration.
- QA-Lab: add `qa coverage --match <query>` so focused proof selection can discover matching scenarios from existing metadata before running live or remote lanes.
- Discord/model picker: surface an alpha-bucket select (e.g. `AG (12) · HN (18) · OZ (5)`) when the provider list or a provider's model list exceeds 25 items, so configs with `provider/*` wildcards stay one click from the right page instead of paginating through prev/next; falls back to numeric chunks when every item shares the same first letter.
- Discord/model picker: surface an alpha-bucket select (e.g. `AG (12) · HN (18) · OZ (5)`) when the provider list or a provider's model list exceeds 25 items, so configs with `provider/*` wildcards stay one click from the right page instead of paginating through prev/next; falls back to numeric chunks when every item shares the same first letter. (#86181) Thanks @rendrag-git.
- Control UI: add an ephemeral Activity tab for sanitized live tool activity summaries without persisting raw telemetry. Fixes #12831. Thanks @BunsDev.
- Build: include `ui:build` in the `full` and `ciArtifacts` profiles of `scripts/build-all.mjs` so `pnpm build` always rebuilds `dist/control-ui` after `tsdown` cleans `dist`, removing the second-command requirement and the missing-asset failure mode for source/runtime installs and CI artifact uploads. (#85206)
- iOS: improve Talk mode with direct realtime voice sessions, compact toolbar status, and responsive voice waveform feedback. (#86355) Thanks @ngutman.
@@ -45,6 +195,7 @@ Docs: https://docs.openclaw.ai
- Memory/security: reject prompt-like text submitted through the explicit `memory_store` tool before embedding or storage, matching the existing auto-capture prompt-injection filter. (#87142)
- Gateway/security: enable the default auth rate limiter for remote non-browser and HTTP gateway auth failures when `gateway.auth.rateLimit` is unset, while preserving the loopback exemption. (#87148)
- Prompt hardening: route untrusted group prompt metadata through sanitized untrusted structured context while preserving trusted operator-configured group system prompts and aligning the plugin SDK docs/test helpers. (#87144)
- Security/content boundaries: validate Browser snapshot tab URLs against SSRF policy before ChromeMCP or direct CDP reads, sanitize queued system-event text so untrusted plugin/channel labels cannot spoof nested prompt markers, wrap fetched file text and metadata as external content, apply ClickClack `allowFrom` sender allowlists before agent dispatch, reject RPCs from invalidated device-token clients during rotation, require staged sandbox media refs, and scrub serialized tool-call text from replies. (#78526, #87094, #87062, #83741, #70707, #86924) Thanks @zsxsoft, @ttzero25, and @mmaps.
- Transcripts/user turns: persist CLI, WebChat, media, follow-up, hook, and Codex-mirror user turns to the admitted session target; keep cleaned transcript text, inline image routing, provenance metadata, replay hooks, and fallback paths idempotent when runtimes fail or restart.
- TUI/status/onboarding/UI: queue busy TUI prompts instead of dropping them, preserve the configured default model during onboarding, show failed tool results as errors, show config-open failures in Control UI, keep status JSON plugin scans healthy, preserve xAI usage-limit errors locally, and expose explicit fast-mode/systemd state. (#86722, #87000, #85786, #87108, #87001, #86614, #87115, #86976)
@@ -58,9 +209,12 @@ Docs: https://docs.openclaw.ai
- Agents/hooks/subagents: enforce default hook agent allowlists, recover failed subagent lifecycle completions, and keep node task lifecycle cleanup from closing the Gateway listener. (#86101)
- Codex: project newer OpenClaw chat history into resumed app-server threads and keep Codex turn timeouts inside the Codex runtime boundary so timeouts do not poison shared app-server clients or fall through to unrelated provider fallback. (#86677, #86476) Thanks @TurboTheTurtle and @pashpashpash.
- Config/doctor/update: narrow profiled tool-section doctor repair, keep runtime-injected legacy web-search provider config out of user-authored config validation, and keep prerelease tags excluded from stable updater resolution. (#87030, #86818, #86559) Thanks @joshavant, @luoyanglang, and @stevenepalmer.
- Doctor/runtime: validate active bundled MCP tool schemas through the same runtime projection path so unsupported MCP input schemas are reported and quarantined instead of poisoning assistant startup.
- CLI/Windows: add a Windows-only stack-size respawn for stack-heavy startup paths, default CLI logs to local timestamps, and validate timeout/banner TTY state more strictly. (#87031, #85387) Thanks @giodl73-repo and @vincentkoc.
- Locking/security: require owner identity proof before stale plugin lock removal, memoize session lock owner arguments, and avoid writing default exec approval stores unless policy state actually changed. (#86814, #86964) Thanks @Alix-007 and @vincentkoc.
- Install/release: bound Docker package build, inventory, pack, and tarball preparation with process-group timeouts; pin shrinkwrap patch drift to the pnpm lock; harden macOS restart and dSYM packaging; and run release Docker/live timeout wrappers in the foreground so child processes cannot wedge gates.
- QA/Telegram: bound Telegram user credential tar and broker calls so live proof setup fails with a timeout instead of waiting for the outer Crabbox job deadline.
- QA/Tool Search: bound gateway E2E HTTP probes, run only the fixture plugin, and clean up temporary fixture trees after the compact tool-catalog proof completes.
- Telegram/network: treat `ENETDOWN` as a transient pre-connect network failure so Telegram sends, gateway unhandled-rejection handling, and cron network retries follow the same recovery path as sibling network outages. (#86762) Thanks @TurboTheTurtle.
- Telegram: preserve inbound text entities, overlapping DM replies, account topic cache sidecars, outbound reply context, targeted bot-command mentions, durable group retry targets, forum topic names, and native progress callbacks. (#83873, #85361, #85555, #85656, #85709, #86299, #86553) Thanks @SebTardif, @luoyanglang, and @neeravmakwana.
- iMessage: read image attachments from local Messages attachment roots, dedupe duplicate local Messages-source accounts, seed direct DM history, fix image/group media attachment commands, advance catchup cursors after live handling, and keep slash-command acknowledgements in the source conversation. (#82642, #85475, #86569, #86705, #86706, #86770) Thanks @homer-byte, @TurboTheTurtle, @swang430, and @OmarShahine.
@@ -81,6 +235,8 @@ Docs: https://docs.openclaw.ai
- CI: bound Docker/Bash E2E tarball npm installs with `OPENCLAW_E2E_NPM_INSTALL_TIMEOUT` so package, onboarding, plugin, and upgrade lanes fail instead of hanging on a stuck npm install.
- CI: fail Parallels npm-update smoke jobs after the guest command timeout and cleanup backstop instead of only logging a timeout line.
- CI: bound kitchen-sink RPC HTTP probes so stalled gateway readiness or response bodies fail and retry instead of wedging the walker.
- CI: bound Telegram user Crabbox proof Bot API calls so stalled Telegram responses fail instead of wedging credential and desktop proof cleanup.
- CI: bound MCP channel stdio client initialization so Docker channel proof fails and closes the bridge transport instead of waiting for the outer job timeout.
- CI: keep `OPENCLAW_TESTBOX=1 pnpm check:changed` delegating to Blacksmith Testbox through Crabbox without forwarding local Testbox or worker env into the remote command.
- CI: send KILL after the TERM grace period for manual checkout fetch timeouts so stuck Testbox and workflow checkout retries cannot hang behind a wedged `git fetch`.
- CI: send KILL after the TERM grace period for Bun global install smoke command timeouts so trapped `openclaw` child processes cannot wedge the scheduled install smoke.
@@ -228,6 +384,7 @@ Docs: https://docs.openclaw.ai
- Maintainer skills: add `openclaw-landable-bug-sweep` for producing five small, reviewed, CI-green OpenClaw bugfix PRs from issue/PR sweeps.
- Control UI/chat: add search and Load More pagination to the chat session picker, keeping initial session loads bounded while making older conversations reachable. (#85237) Thanks @amknight.
- CLI/onboarding: start classic onboarding when bare `openclaw` runs before an authored config exists, while keeping configured installs on Crestodian. (#72343) Thanks @fuller-stack-dev.
- Agents/runtime: internalize the former Pi agent runtime into OpenClaw, remove legacy package dependencies, and keep Pi-named SDK aliases only as deprecated plugin compatibility.
- Discord: allow configuring a bounded `agentComponents.ttlMs` callback registry lifetime for long-running component workflows, with per-account overrides and a 24-hour cap. (#84189) Thanks @100menotu001.
- xAI/Grok: reuse xAI OAuth auth profiles for Grok `web_search`, thread active-agent auth through web search, add Grok model aliases, and let media providers declare default operation timeouts. (#85182) Thanks @fuller-stack-dev.
- Plugin SDK: add row-level session workflow helpers and deprecate `loadSessionStore` so plugins can read and patch sessions without depending on the legacy whole-store shape. (#84693) Thanks @efpiva.
@@ -484,6 +641,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents: validate a forced plugin harness against the candidate provider/model before pinning it, so unsupported fallback-chain candidates fail with a clear harness error instead of producing a late `Model provider X not found` from the underlying harness. Codex harness `supports()` now also accepts the canonical `openai` and `openai-codex` routing ids so documented Codex configs keep working. Thanks @cathrynlavery.
- Control UI/WebChat: keep selected external-channel sessions live by mirroring Codex prompts at turn start, streaming hidden runs only to exact selected-session subscribers, and deduplicating accumulated stream snapshots around tool cards. Fixes #83528, #82611, refs #83949. Thanks @BunsDev.
- CLI/tasks: include stale-running task maintenance decisions in `openclaw tasks maintenance --json` so retained and reconcile candidates explain backing-session, cron, CLI, and wedged-subagent state. (#84691) Thanks @efpiva.
- Codex app-server: keep system-prompt reports working when bootstrap hooks provide workspace files with only a path and content, so hook-supplied SOUL/IDENTITY/TOOLS/USER context still reports injected characters correctly. (#84736) Thanks @JARVIS-Glasses.
@@ -1849,6 +2007,7 @@ Docs: https://docs.openclaw.ai
- Agents/read tool: treat positive offsets beyond EOF as empty ranges instead of surfacing the upstream read error, so stale pagination cursors no longer crash tool calls while unrelated read failures still fail loud. Fixes #62466. (#75536) Thanks @vyctorbrzezowski.
- Google/Gemini: normalize retired Gemini 3 Pro Preview refs left in Google API-key onboarding model allowlists and fallbacks, so setup-emitted config keeps testing `google/gemini-3.1-pro-preview` instead of `google/gemini-3-pro-preview`.
- Telegram/context: bound selected topic context to the active session so messages from before `/new` or `/reset` are not replayed into later turns. (#80848) Thanks @VACInc.
- Docs/providers/openai: clarify that OpenAI Realtime voice goes through the OpenAI Platform Realtime API and requires Platform credits — Codex/ChatGPT subscription quota does not cover this route. Fixes #76498. Thanks @lonexreb.
- Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids when resolving exact configured proxy-provider refs, so `kilocode/google/gemini-3-pro-preview` resolves to `kilocode/google/gemini-3.1-pro-preview` for Gemini 3.1 testing.
- CLI: strip generic OSC terminal escape payloads from sanitized output fields, preventing clipboard/title escape bodies from leaking into commitment tables and other terminal-safe text. Thanks @shakkernerd.
- Codex app-server: match connector-backed plugin approval elicitations by stable connector id so enabled destructive actions no longer fall through to display-name-only rejection.

View File

@@ -48,6 +48,7 @@ RUN --mount=type=bind,source=packages,target=/tmp/packages,readonly \
FROM ${OPENCLAW_BUN_IMAGE} AS bun-binary
FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS build
ARG OPENCLAW_BUNDLED_PLUGIN_DIR
ARG OPENCLAW_EXTENSIONS
# Copy pinned Bun binary from the official image instead of fetching via curl.
COPY --from=bun-binary /usr/local/bin/bun /usr/local/bin/bun
@@ -77,7 +78,12 @@ RUN --mount=type=cache,id=openclaw-pnpm-store,target=/root/.local/share/pnpm/sto
# pnpm v10+ may append peer-resolution hashes to virtual-store folder names; do not hardcode `.pnpm/...`
# paths. Matrix's native downloader can hit transient release CDN errors while
# still exiting successfully, so retry the package downloader before failing.
# Skip the entire check when matrix is not a bundled extension (e.g. msteams-only builds).
RUN set -eux; \
if ! printf '%s\n' "$OPENCLAW_EXTENSIONS" | tr ',' ' ' | tr ' ' '\n' | grep -qx 'matrix'; then \
echo "==> matrix not bundled, skipping matrix-sdk-crypto check"; \
exit 0; \
fi; \
echo "==> Verifying critical native addons..."; \
for attempt in 1 2 3 4 5; do \
if find /app/node_modules -name "matrix-sdk-crypto*.node" 2>/dev/null | grep -q .; then \
@@ -178,6 +184,7 @@ COPY --from=runtime-assets --chown=node:node /app/package.json .
COPY --from=runtime-assets --chown=node:node /app/pnpm-workspace.yaml .
COPY --from=runtime-assets --chown=node:node /app/patches ./patches
COPY --from=runtime-assets --chown=node:node /app/openclaw.mjs .
COPY --from=runtime-assets --chown=node:node /app/src/agents/templates ./src/agents/templates
COPY --from=runtime-assets --chown=node:node /app/${OPENCLAW_BUNDLED_PLUGIN_DIR} ./${OPENCLAW_BUNDLED_PLUGIN_DIR}
COPY --from=runtime-assets --chown=node:node /app/skills ./skills
COPY --from=runtime-assets --chown=node:node /app/docs ./docs

View File

@@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Third-party notices for incorporated or adapted code are recorded in
THIRD_PARTY_NOTICES.md.

View File

@@ -25,7 +25,7 @@ If you want a personal, single-user assistant that feels local, fast, and always
Supported channels include: WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, IRC, Microsoft Teams, Matrix, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, Zalo Personal, WeChat, QQ, WebChat.
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Onboarding](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [Third-party notices](THIRD_PARTY_NOTICES.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Onboarding](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started)
@@ -306,7 +306,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, maintainers, and how to s
AI/vibe-coded PRs welcome! 🤖
Special thanks to [Mario Zechner](https://mariozechner.at/) for his support and for
[pi-mono](https://github.com/badlogic/pi-mono).
[pi-mono](https://github.com/earendil-works/pi-mono).
Special thanks to Adam Doppelt for the lobster.bot domain.
Thanks to all clawtributors:

37
THIRD_PARTY_NOTICES.md Normal file
View File

@@ -0,0 +1,37 @@
# Third-party notices
This file records third-party notices for code or substantial implementation
portions incorporated into OpenClaw source, beyond normal package-manager
dependency metadata.
## Pi / pi-mono
Portions of OpenClaw were adapted from Pi / pi-mono, and OpenClaw also depends
on `@earendil-works/pi-tui` for terminal UI rendering.
- Upstream: https://github.com/earendil-works/pi-mono
- Package family: `@earendil-works/pi-*`
- License: MIT
- Copyright: Copyright (c) 2025 Mario Zechner
MIT License
Copyright (c) 2025 Mario Zechner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -3,675 +3,324 @@
<channel>
<title>OpenClaw</title>
<item>
<title>2026.5.22</title>
<pubDate>Sun, 24 May 2026 01:41:27 +0000</pubDate>
<title>2026.5.28</title>
<pubDate>Sat, 30 May 2026 21:21:09 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052290</sparkle:version>
<sparkle:shortVersionString>2026.5.22</sparkle:shortVersionString>
<sparkle:version>2026052890</sparkle:version>
<sparkle:shortVersionString>2026.5.28</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.22</h2>
<description><![CDATA[<h2>OpenClaw 2026.5.28</h2>
<h3>Highlights</h3>
<ul>
<li>Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)</li>
<li>Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)</li>
<li>Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman.</li>
<li>Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)</li>
<li>Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)</li>
<li>CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy <code>api_key</code> auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.</li>
<li>Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)</li>
<li>Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Gateway/perf: reuse process-stable channel catalog reads, avoid repeated bundled-channel boundary checks, and rotate gateway watch CPU profiles so benchmark runs do not accumulate unbounded artifacts.</li>
<li>Gateway/perf: reuse immutable plugin metadata snapshots across startup, config, model, channel, setup, and secret metadata readers so hot paths avoid repeated plugin file stats and manifest registry reloads.</li>
<li>Gateway/perf: lazy-load startup-idle plugin work, core gateway method handlers, and the embedded ACPX runtime so Gateway health and ready signals no longer wait on unused handler trees or ACPX probes.</li>
<li>Gateway/perf: cache plugin SDK public-surface alias maps and skip irrelevant macOS Linuxbrew PATH probes so Gateway startup avoids repeated filesystem walks and slow missing-directory stats.</li>
<li>Meeting Notes: add a source-only external meeting-notes plugin and SDK source-provider contract outside the core npm package, with auto-start capture config, manual transcript imports, read-only <code>openclaw meeting-notes</code> CLI access, and Discord voice as the first live source.</li>
<li>Docs/channels/config: add Signal <code>configPath</code>, Telegram wildcard topic defaults, local-time backup archive names, Termux home fallback, include-path validation, secret-scanner-safe placeholder guidance, Gemini CLI/Antigravity media guidance, and macOS VM auto-login guidance. Thanks @NorseGaud, @yudistiraashadi, @huangqian8, @VibhorGautam, @maweibin, @tianxingleo, @IgnacioPro, and @xzcxzcyy-claw.</li>
<li>Docs: clarify model-usage portability, Codex migration prerequisites, status bootstrap wording, thread-bound subagent limits, hook ownership, and config-preserving safety guidance. Thanks @aniruddhaadak80, @leno23, @TomDjerry, @matthewxmurphy, @vincentkoc, and @stablegenius49.</li>
<li>Docs: clarify README onboarding and Gateway startup paths, WhatsApp QR/408 recovery, cron output language prompts, skill advanced features, gateway upstream 403 troubleshooting, and plugin fallback override guidance. Thanks @deepujain, @Zacxxx, @Jah-yee, @neyric, @usimic, @Renu-Cybe, @BigUncle, and @SeashoreShi.</li>
<li>Docs: clarify context-pruning ratio bounds, local dashboard recovery, CLI env markers, remote onboarding token behavior, and Peekaboo Bridge permissions for subprocess agents. Thanks @ayesha-aziz123, @dishraters, @hougangdev, and @brandonlipman.</li>
<li>Docs: clarify browser CDP diagnostics, Plugin SDK allowlist imports, status-reaction timing defaults, queue steering behavior, limited-tool troubleshooting, cron HEARTBEAT handling, Telegram multi-agent groups, Bitwarden SecretRef setup, and EasyRunner deployments. Thanks @Quratulain-bilal, @mbelinky, @Mickey-, @vancece, @xenouzik, @posigit, @surlymochan, @janaka, and @choiking.</li>
<li>Crabbox/Testbox: run clean sparse-checkout Testbox syncs from a temporary full checkout and route remote changed gates through Corepack pnpm.</li>
<li>Docs: clarify IPv4-only Gateway BYOH binding, trusted-proxy scope clearing, Android pairing approval, macOS Accessibility grants, Zalo profile env vars, password-store SecretRef setup, and Chinese memory navigation. Thanks @itskai-dev, @gwh7078, @longstoryscott, @MoeJaberr, and @yuaiccc.</li>
<li>Docs: consolidate GLM under Z.AI, add the Upstash Box install guide and Gateway exposure runbook, clarify MEDIA directives, Copilot and Voyage setup, config path quoting, real behavior proof, and memory-file write guidance. Thanks @BobDu, @alitariksahin, @Jefsky, @musaabhasan, @OmerZeyveli, @leno23, @WuKongAI-CMU, @luoyanglang, and @majin1102.</li>
<li>Docs: clarify media provider credentials, Codex/OpenClaw code-mode boundaries, Slack and Telegram ack reactions, Feishu dynamic agents, secrets plaintext boundaries, memory guidance, and Chinese glossary terms. Thanks @nielskaspers, @cosmopolitan033, @drclaw-iq, @alexgduarte, @zccyman, @chengoak, and @cassthebandit.</li>
<li>Packaging: exclude documentation images and assets from the npm tarball, reducing published package size without affecting runtime docs search or CLI behavior. Thanks @SebTardif.</li>
<li>Media understanding: stop auto-probing Gemini CLI and use Antigravity CLI only as a lower-priority image/video fallback after configured provider APIs.</li>
<li>Agents/subagents: limit default sub-agent bootstrap context to <code>AGENTS.md</code> and <code>TOOLS.md</code>, keeping persona, identity, user, memory, heartbeat, and setup files out of delegated workers by default. (#85283) Thanks @100yenadmin.</li>
<li>Maintainer skills: exclude plugin SDK/API boundary work from <code>openclaw-landable-bug-sweep</code> so bugbash sweeps stay focused on small paper-cut fixes.</li>
<li>QA-Lab/diagnostics: extend the OpenTelemetry smoke harness to prove trace, metric, and log export, and add first-class Prometheus and observability smoke aliases.</li>
<li>Plugin SDK: add a generic channel-message poll sender so channel plugins can expose poll delivery without depending on channel-specific SDK facades.</li>
<li>Crabbox: keep the local wrapper's provider validation synced with the installed Crabbox binary while preserving supported aliases such as <code>docker</code> and <code>blacksmith</code>. (#85302) Thanks @hxy91819.</li>
<li>Maintainer skills: add <code>openclaw-landable-bug-sweep</code> for producing five small, reviewed, CI-green OpenClaw bugfix PRs from issue/PR sweeps.</li>
<li>Control UI/chat: add search and Load More pagination to the chat session picker, keeping initial session loads bounded while making older conversations reachable. (#85237) Thanks @amknight.</li>
<li>CLI/onboarding: start classic onboarding when bare <code>openclaw</code> runs before an authored config exists, while keeping configured installs on Crestodian. (#72343) Thanks @fuller-stack-dev.</li>
<li>Discord: allow configuring a bounded <code>agentComponents.ttlMs</code> callback registry lifetime for long-running component workflows, with per-account overrides and a 24-hour cap. (#84189) Thanks @100menotu001.</li>
<li>xAI/Grok: reuse xAI OAuth auth profiles for Grok <code>web_search</code>, thread active-agent auth through web search, add Grok model aliases, and let media providers declare default operation timeouts. (#85182) Thanks @fuller-stack-dev.</li>
<li>Plugin SDK: add row-level session workflow helpers and deprecate <code>loadSessionStore</code> so plugins can read and patch sessions without depending on the legacy whole-store shape. (#84693) Thanks @efpiva.</li>
<li>Gateway/plugins: reuse a compatible Gateway startup plugin registry during dispatch so safe plugin dispatches avoid redundant registry loading. (#84324) Thanks @ai-hpc.</li>
<li>Plugins/SDK: add a general <code>embeddingProviders</code> capability contract and registration API so embeddings can become a reusable provider surface outside memory-specific adapters.</li>
<li>Dependencies: refresh provider, plugin, UI, and tooling packages, update <code>protobufjs</code> to 8.4.0 to clear the current npm advisory, and carry the Claude ACP completion patch forward to <code>@agentclientprotocol/claude-agent-acp</code> 0.36.1.</li>
<li>Agents/tools: remove the old sender-owner tool gating path so configured tools stay visible for trusted sessions while command and channel-action auth still carry real sender identity.</li>
<li>QA-Lab: add curated mock JSONL replay fixtures and first-drift reporting for runtime-parity audits. (#80323, refs #80176) Thanks @100yenadmin.</li>
<li>QA-Lab: add a QA bus tool-trace visibility scenario for sanitized tool-call assertions.</li>
<li>QA-Lab: replace generic evidence framing in seeded scenario prompts with concrete observed QA behavior.</li>
<li>QA-Lab: list named scenario packs in the coverage report so personal-agent privacy coverage stays visible in audits.</li>
<li>QA-Lab: list live transport lane membership in the coverage report so real transport checks stay separate from seeded qa-channel scenarios.</li>
<li>Release/package: run package integrity checks before package acceptance lanes so public install/update validation fails before private QA assets can leak into the package.</li>
<li>QA-Lab: include the optional 100-turn runtime parity soak in release-soak artifacts so long-run Codex/Pi transcript drift stays visible outside the default gate. (#80395) Thanks @100yenadmin.</li>
<li>QA-Lab: add a live-only long-context progress watchdog scenario for Codex app-server timeout and stalled-run sentinels. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: tag gateway restart recovery and streaming final-integrity scenarios as live-only runtime parity lanes. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: add a personal-agent failure recovery scenario that checks honest partial status, retry boundaries, and local recovery artifacts. (#83872) Thanks @iFiras-Max1.</li>
<li>QA-Lab: include an opt-in <code>update.run</code> package self-upgrade sentinel for destructive latest-package recovery checks.</li>
<li>QA-Lab: add Codex plugin lifecycle and auth-profile fixture coverage for missing installs, pinned-version drift, first-turn install ordering, and doctor migration safety. (#80323, refs #80174) Thanks @100yenadmin.</li>
<li>Models/perf: pre-warm the provider auth-state map at gateway startup so <code>/models</code> and every model-listing call short-circuits the per-provider plugin / external-CLI discovery on the hot path. Per-call cost drops from ~20 s to ~5 ms (~4,100×); the one-time startup warm resets and re-warms after hot reloads. (#84816) Thanks @sjf.</li>
<li>Release/security: ship the root npm package and OpenClaw-owned npm plugins with generated shrinkwrap, support bundled plugin runtime dependencies for suitable plugin tarballs, and require review for lockfile/shrinkwrap changes so published installs use locked dependency graphs.</li>
<li>Tests/perf: isolate doctor core health check unit coverage from real skills/workspace discovery so <code>doctor-core-checks</code> no longer dominates unit perf while keeping one real skills-readiness smoke. (#84493) Thanks @frankekn.</li>
<li>Status: show active subagent details in status output.</li>
<li>Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.</li>
<li>ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.</li>
<li>iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.</li>
<li>Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.</li>
<li>PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)</li>
<li>Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.</li>
<li>Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.</li>
<li>Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.</li>
<li>Workboard: add agent coordination tools for tracking and handing off active agent work.</li>
<li>Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)</li>
<li>Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @RomneyDa.</li>
<li>Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>WebChat: summarize internal message-tool source replies so tool cards no longer duplicate the visible reply body. (#84773) Thanks @jason-allen-oneal.</li>
<li>Gateway: preserve deferred lifecycle-error cleanup across later non-terminal events so provider timeouts can persist failed session state instead of leaving sessions stuck running. (#85256, fixes #63819) Thanks @samzong.</li>
<li>Agents/subagents: report tool-only child progress during timeout summaries instead of showing no visible output.</li>
<li>Telegram/ACP: preserve explicit <code>:topic:</code> conversation suffixes when inbound ACP targets do not carry a separate thread id.</li>
<li>Browser/proxy: bypass the managed proxy for the exact local managed Chrome CDP readiness and DevTools WebSocket endpoints, so <code>openclaw browser start</code> works when the operator proxy blocks loopback egress. (#83255) Thanks @lightcap.</li>
<li>Ollama: bypass the managed proxy for configured local embedding origins while keeping SSRF guardrails on unconfigured targets. Thanks @Kaspre.</li>
<li>OpenAI/images: route Codex API-key image generation through the native OpenAI Images API instead of the Codex OAuth streaming backend, avoiding 401s from valid API keys.</li>
<li>Agents/OpenAI completions: omit empty tool payload fields for proxy-like OpenAI-compatible endpoints so strict vLLM-style servers accept tool-free turns. (#85835) Thanks @rendrag-git.</li>
<li>Checks/Windows: route full <code>pnpm check</code> stage commands through the managed child runner so Windows avoids Node shell-argv deprecation warnings there too.</li>
<li>Checks/Windows: run managed child commands through explicit <code>cmd.exe</code> wrapping instead of Node shell mode with argv, avoiding Node 24 subprocess deprecation warnings during changed checks.</li>
<li>Gateway: omit internal stream-error placeholder entries from agent prompt history so failed assistant turns are not replayed as model-authored text. (#85652) Thanks @anyech.</li>
<li>Sessions: enforce the session write-lock max-hold policy during lock acquisition so long-held locks can be reclaimed before the stale-lock window. (#85764) Thanks @njuboy11.</li>
<li>Models: prune retired Groq, GitHub Copilot, OpenAI, xAI, and old Claude catalog entries, with doctor migration to upgrade existing configs to current provider refs.</li>
<li>Doctor/update: recognize junction-backed source checkouts as git installs by comparing canonical paths before showing package-manager update guidance. Fixes #82215. Thanks @igormf.</li>
<li>Channels: honor <code>/verbose on</code> for tool/progress summaries across direct chats, groups, channels, and forum topics while preserving quiet default behavior. (#85488) Thanks @kurplunkin.</li>
<li>CLI/skills: show an all-ready note with next-step commands when skill setup has no missing dependencies to install. (#85032) Thanks @aniruddhaadak80.</li>
<li>Microsoft Foundry: route DeepSeek V4 Pro and Flash models through the Foundry Responses API while keeping older DeepSeek models on their existing path. (#85549) Thanks @roslinmahmud.</li>
<li>Status/usage: show configured cost estimates for AWS SDK models in full usage output while keeping token-only usage replies cost-free. (#85619) Thanks @ItsOtherMauridian.</li>
<li>Agents/OpenAI Responses: retry non-visible reasoning-only turns for OpenAI Responses API families instead of treating them as empty failed turns. (#85603) Thanks @SebTardif.</li>
<li>Directive tags: preserve message and content-part object identity when display stripping makes no directive-tag changes. (#85682) Thanks @willamhou.</li>
<li>Telegram: send local <code>path</code>/<code>filePath</code> and structured attachment media from <code>sendMessage</code> actions instead of dropping them or sending text-only messages. (#85219) Thanks @keshavbotagent.</li>
<li>Sessions/status: show the estimated context budget when fresh provider usage is unavailable and clear stale estimates across session resets and compaction boundaries. (#84830) Thanks @giodl73-repo.</li>
<li>Gateway/config: pin relative <code>OPENCLAW_STATE_DIR</code> overrides to an absolute path at startup so later working-directory changes cannot retarget gateway state. (#52264) Thanks @PerfectPan.</li>
<li>Release/package: run npm release, prepublish, and postpublish verification through Windows-safe npm command shims so native Windows checks can execute <code>npm.cmd</code> instead of treating it as a binary.</li>
<li>Agents/harness: pass CLI runtime aliases through harness selection so provider-owned CLI aliases no longer get rejected before reaching the right runtime. (#85631) Thanks @potterdigital.</li>
<li>Secrets: show the irreversible apply warning after interactive <code>secrets configure</code> confirmation so confirmed migrations still get the final safety prompt. (#85638) Thanks @alkor2000.</li>
<li>Agents/CLI output: ignore cumulative Claude <code>stream-json</code> result usage when assistant usage events are present, preventing inflated cache-read accounting. (#85625) Thanks @zhouhe-xydt.</li>
<li>CLI: keep <code>waitForever()</code> alive by leaving its keep-alive interval ref'd so the public helper no longer exits immediately with Node's unsettled-await code. (#85694) Thanks @m1qaweb.</li>
<li>Agents/bootstrap: guard bootstrap name checks against missing file names so malformed bootstrap entries warn and truncate instead of crashing. Fixes #85523. (#85615) Thanks @zhouhe-xydt.</li>
<li>CLI/tasks: reject partially numeric <code>openclaw tasks audit --limit</code> values so audit limits must be real positive integers instead of accepting strings like <code>5abc</code>. (#84901) Thanks @jbetala7.</li>
<li>Status/diagnostics: bound deep Docker audit probes so <code>openclaw status --deep</code> reports slow container checks instead of hanging behind unbounded inspection. (#85476) Thanks @giodl73-repo.</li>
<li>Providers/Anthropic: migrate 1M context handling to GA-capable Claude 4.x models by sizing eligible models at 1M without the retired <code>context-1m-2025-08-07</code> beta, ignoring that retired beta in older configs, and preserving OAuth-required Anthropic beta headers. (#45613) Thanks @haoyu-haoyu.</li>
<li>Cron/Telegram: parse forum-topic delivery targets through the Telegram plugin instead of cron core, including <code>:topic:</code> and <code>:topicId</code> forms for announce delivery. Thanks @etticat.</li>
<li>Twitch: keep stale message-handler cleanup callbacks from removing newer handler registrations for the same account, preserving inbound message delivery after reconnects. Fixes #83888. (#85425) Thanks @alkor2000.</li>
<li>Memory/LanceDB: expose public memory artifacts through the active memory provider bridge so memory-wiki imports durable memory files, daily notes, dream reports, and event logs without depending on memory-core internals. Fixes #83604. (#85060) Thanks @brokemac79.</li>
<li>Crabbox: keep AWS hydration compatible with local Actions replay by inlining the hydrate workflow's Node/pnpm setup instead of invoking repo-local composite actions.</li>
<li>Agents/subagents: simplify native sub-agent completion handoff so children report their latest visible assistant result to the requester without using <code>message</code>, while keeping parent-owned message-tool delivery policy intact. Fixes #85070. (#85089) Thanks @brokemac79.</li>
<li>Docker setup: stop printing the Gateway bearer token in setup logs and printed follow-up commands.</li>
<li>Agents: let embedded compaction fallback retries proceed when PI-compatible candidates do not need agent harness plugin preparation.</li>
<li>Agents/tools: honor configured custom provider API keys when deciding whether media, image-generation, video-generation, music-generation, and PDF tools are available. (#85570)</li>
<li>StepFun: stop advertising stale generic API key auth choices so onboarding only offers runtime-backed Standard and Step Plan choices.</li>
<li>Diagnostics: keep OpenTelemetry log bodies behind explicit content capture and scrub scoped agent-session keys from OpenTelemetry and Prometheus labels while preserving bounded queue-lane prefixes.</li>
<li>Windows installer: fail Git checkout installs when <code>pnpm install</code> or <code>pnpm build</code> fails instead of writing a wrapper to a missing CLI build.</li>
<li>Sessions: surface previous-transcript archive failures during <code>/new</code> rotation so disk rename errors are logged instead of silently hiding stranded transcript files. Fixes #81984. (#85586, from #82081) Thanks @0xghost42.</li>
<li>TUI/agents: mirror internal-ui message-tool replies into final chat output so message-tool-only agents remain visible in <code>openclaw tui</code>. Fixes #85538. Thanks @danpolasek.</li>
<li>Agents: keep parallel OpenAI-compatible tool-call deltas in separate argument buffers so interleaved tool calls no longer corrupt streamed arguments. (#82263) Thanks @luna-system.</li>
<li>Memory/doctor: report missing or unusable QMD workspace directories as workspace failures instead of generic binary failures. (#63167) Thanks @sercada.</li>
<li>Debug proxy: record CONNECT client-socket errors and destroy the paired upstream socket so abrupt client disconnects no longer leak tunnel resources. (#82444) Thanks @SebTardif.</li>
<li>Diffs: continue hydrating later diff cards when one card fails so a single broken card no longer blanks the whole diff viewer. (#84775) Thanks @cosmopolitan033.</li>
<li>Mac app: use the native settings sidebar window chrome so the sidebar toggle stays on the left and content no longer clips under oversized titlebar padding.</li>
<li>QA-Lab/Codex: bundle auth/plugin fixture imports for flow scenarios and let terminal async media tools end Codex app-server turns without timing out. (#80397, refs #80323) Thanks @100yenadmin.</li>
<li>Gateway/agents: preserve fresh session overrides and metadata when stale cached agent-session entries race with store updates, so subagent model/provider overrides and routing policy survive concurrent writes. (#19328) Thanks @CodeReclaimers.</li>
<li>Control UI/chat: keep chat session search inline with the session selector so the header no longer shows a duplicate standalone search row.</li>
<li>Control UI/chat: collapse focused-mode header chrome and suppress hidden-header scroll updates so focus mode no longer jumps while scrolling. Thanks @amknight.</li>
<li>Codex app-server: restart the native app-server and retry once when server-side compaction times out, so preflight compaction stalls recover instead of failing every dispatch. (#85500)</li>
<li>Restore Control UI gateway token pairing [AI]. (#85459) Thanks @pgondhi987.</li>
<li>OpenAI video: honor configured provider request private-network opt-in for local/custom video endpoints so explicitly trusted mock and self-hosted providers are not blocked. Thanks @shakkernerd.</li>
<li>OpenAI video: send uploaded video edit requests to the documented <code>/videos/edits</code> endpoint with a <code>video</code> file instead of posting MP4 references to <code>/videos</code>. Thanks @shakkernerd.</li>
<li>Agents/channels: preserve message-tool delivery evidence through gateway agent completion handoffs so successful generated media sends are not followed by false failure messages. Thanks @shakkernerd.</li>
<li>CLI/update: repair managed npm plugin <code>openclaw</code> peer links during post-core convergence and reject stale or wrong-target peer links before restart. (#83794) Thanks @fuller-stack-dev.</li>
<li>CLI/agents: default new omitted-account bindings to all accounts when the channel has multiple configured accounts, and clarify account-scope docs. (#49769) Thanks @Gcaufy.</li>
<li>Codex app-server: let authorized <code>/codex</code> control commands such as <code>/codex detach</code> escape plugin-owned conversation bindings while keeping unknown or unauthorized slash text routed to the bound plugin. Fixes #85157. (#85188) Thanks @TurboTheTurtle.</li>
<li>Auto-reply/models: keep <code>/models</code> browse replies fast by sharing the bounded read-only catalog path with Gateway model listing. (#84735) Thanks @safrano9999.</li>
<li>Codex app-server: disable native Code Mode when the effective exec host is <code>node</code> and keep OpenClaw <code>exec</code>/<code>process</code> available, so <code>/exec host=node</code> routes shell commands through the selected node instead of the gateway. Fixes #85012. (#85090) Thanks @sahilsatralkar.</li>
<li>Agents: bound embedded auto-compaction session write-lock watchdogs to the compaction timeout instead of the full run timeout, so stuck compaction cannot hold the live session lock for the whole run window. (#84949) Thanks @luoyanglang.</li>
<li>Gateway/agents: return phase-aware <code>agent.wait</code> timeout attribution and only cool auth profiles on provider-started timeouts. Refs #65504. Thanks @100yenadmin.</li>
<li>Gateway: defer provider auth-state prewarm until after startup readiness so early gateway tool/session requests are not blocked by provider auth discovery. (#85272) Thanks @dutifulbob.</li>
<li>Gateway/models: coalesce provider auth-state rewarms after auth-profile failures and log event-loop delay for warm/rewarm work, so provider auth bursts no longer stack full auth sweeps behind channel replies.</li>
<li>Gateway/models: stop cancelled provider auth-state prewarms from continuing full provider sweeps, so reload and auth-failure bursts no longer keep startup busy.</li>
<li>Agents/Codex: show the first plan update as a transient chat status notice without counting it as final assistant content.</li>
<li>CLI/update: walk the macOS process ancestry and honor the inherited Gateway runtime PID before package updates stop the managed Gateway service, so nested in-band updater children can refuse instead of killing the LaunchAgent-supervised Gateway that owns them. Fixes #85120.</li>
<li>Gateway/LaunchAgent: wait for launchd reload bootout to finish and fall back to kickstart when bootstrap races, so reload handoff does not leave the service deregistered. Fixes #84630. (#84641) Thanks @NianJiuZst.</li>
<li>Gateway/LaunchAgent: treat a concurrent launchd bootstrap as a successful restart when the service is already loaded, avoiding false macOS Gateway restart failures. Fixes #84721. (#84722) Thanks @googlerest.</li>
<li>Gateway/service: include the active <code>openclaw</code> command bin directory in managed service PATH generation and doctor audit expectations for npm-global macOS installs. Fixes #84201. (#84475) Thanks @jbetala7.</li>
<li>Control UI/chat: disable the thinking selector for known non-reasoning models instead of showing duplicate Off choices. Fixes #84069. Thanks @DrippingMellow.</li>
<li>Memory: expand <code>~</code> in configured extra memory paths before resolving them, so home-relative folders are not treated as workspace-relative. Fixes #58026. Thanks @stadman.</li>
<li>Skills: treat <code>openclaw.os: macos</code> as Darwin when checking skill requirements, so macOS-only skills no longer report as missing on macOS hosts. Fixes #61338. Thanks @Jessecq1995.</li>
<li>Control UI/logs: strip ANSI escape sequences from displayed Gateway log messages so color codes no longer appear as raw text. Fixes #64399. Thanks @guguangxin-eng.</li>
<li>Docker: pre-create the workspace and auth-profile config mount points with <code>node</code> ownership so first-run named volumes do not start root-owned. Fixes #85076. Thanks @Noerr.</li>
<li>Telegram: pass configured markdown table mode through outbound markdown chunking so chunked sends render tables consistently. Fixes #85085. Thanks @ShuaiHui.</li>
<li>CLI/update: preserve managed Gateway service environment during package cutovers so macOS LaunchAgent repair/restart reads the pre-update service state instead of caller shell state. (#83026)</li>
<li>Agents/providers: honor per-model <code>api</code> and <code>baseUrl</code> overrides in custom provider auth hooks and transport selection. Fixes #80487. (#80488) Thanks @huveewomg.</li>
<li>Gateway/restart: eager-load the lifecycle runtime before in-place upgrade signal handling so package replacement does not deadlock restart imports. (#84890) Thanks @myps6415.</li>
<li>CLI/update: start managed Gateway update handoff helpers from a stable existing directory and tolerate deleted cwd/package roots during macOS LaunchAgent handoff. Fixes #83808. (#83875) Thanks @jason-allen-oneal.</li>
<li>Skills: watch each shared skill directory once across agent workspaces instead of once per agent, preventing file-descriptor exhaustion (<code>EMFILE</code>) that disposed bundle-mcp processes and stalled sessions on multi-agent gateways. Fixes #84968. (#85130) Thanks @openperf.</li>
<li>Release/security: keep generated npm shrinkwrap package versions inside the pnpm lock graph so published package locks cannot bypass pnpm dependency age and override policy.</li>
<li>Cron: honor <code>cron.retry.retryOn: ["network"]</code> for common network error codes such as <code>EAI_AGAIN</code>, <code>EHOSTUNREACH</code>, and <code>ENETUNREACH</code>.</li>
<li>Gateway chat: broadcast returned agent-run error payloads after an agent starts so ACP/WebChat clients receive terminal idle-timeout errors. Fixes #84945.</li>
<li>Gateway chat display: preserve OpenAI-compatible <code>prompt_tokens</code>, <code>completion_tokens</code>, and <code>total_tokens</code> usage fields in sanitized chat history so llama.cpp sessions keep context counts. Fixes #77992. Thanks @MarTT79.</li>
<li>Dashboard/CLI: allow macOS browser launching through <code>open</code> even when SSH environment variables are present, while preserving Linux SSH no-display protection. Fixes #67088. Thanks @theglove44.</li>
<li>Codex app-server: keep native web search observations out of mirrored chat transcripts while preserving tool progress telemetry. Fixes #85109. Thanks @ugitmebaby.</li>
<li>OpenCode Go: strip unsupported Kimi reasoning replay fields before provider requests so repeated <code>kimi-k2.6</code> turns do not fail schema validation. Fixes #83812. Thanks @Sleeck.</li>
<li>Browser/CDP: add a WSL2 portproxy self-loop hint when Chrome DevTools endpoints accept connections but return an empty HTTP reply. Fixes #59209. Thanks @Owlock.</li>
<li>Agents/OpenAI: preserve structured provider error code, type, and redacted body metadata on boundary-aware transport failures.</li>
<li>Doctor/Codex: point native Codex asset warnings at the canonical <code>openclaw migrate plan codex</code> preview command. Fixes #84948. Thanks @markoa.</li>
<li>CLI/models: make <code>capability model auth logout --agent</code> remove auth profiles from the selected non-default agent store. Fixes #85092. Thanks @islandpreneur007.</li>
<li>Gateway/models: reuse prepared provider auth metadata during model-listing auth checks so repeated lookups avoid broad plugin discovery while preserving synthetic local auth.</li>
<li>CLI/status: suppress systemd user-service setup hints when <code>openclaw status --deep</code> can already reach a running Gateway RPC service. Fixes #85094. Thanks @islandpreneur007.</li>
<li>CLI/devices: recover local approval when a same-device repair request replaces the request ID being approved.</li>
<li>CLI/agents: retry transient normal-close Gateway handshakes before falling back to embedded <code>openclaw agent</code> execution.</li>
<li>CLI/update: keep managed Gateway service stop/restart status lines out of <code>openclaw update --json</code> stdout so package-update automation can parse the JSON payload.</li>
<li>Plugins: resolve OpenClaw plugin SDK subpaths for native external plugin runtimes without mutating package installs or broadening process-wide module resolution.</li>
<li>Agents/OpenAI: preserve Responses and Chat Completions <code>reasoning_tokens</code> usage metadata without double-counting it in aggregate output tokens. (#85319)</li>
<li>Control UI/chat: convert pasted <code>data:image/...;base64,...</code> clipboard text into an image attachment instead of dumping the payload into the composer. Fixes #62604. Thanks @cpwilhelmi.</li>
<li>Providers/Gemini: strip fractional seconds from web-search time range filters so Gemini accepts freshness-bound search requests. (#85071) Thanks @Noerr.</li>
<li>OpenAI Codex: preserve image input support for sparse <code>openai-codex/gpt-5.5</code> catalog rows. (#85095) Thanks @sercada.</li>
<li>CLI/models: add a piped or pasted API-key path for OpenAI Codex auth and warn when API keys are pasted into token-mode auth. (#85533) Thanks @joshavant.</li>
<li>Telegram: dead-letter missing-harness isolated ingress failures so a poisoned spooled update no longer blocks later same-lane messages. Fixes #85470. (#85605) Thanks @joshavant.</li>
<li>Plugins/discovery: strip <code>-plugin</code> package suffixes when deriving plugin id hints so package names line up with manifest ids. (#85170) Thanks @JulyanXu.</li>
<li>Tlon: stop advertising a non-existent agent tool contract in the plugin manifest.</li>
<li>Telegram: preserve fenced code block languages through Markdown rendering so Telegram receives <code>language-*</code> code classes. (#85209) Thanks @leno23.</li>
<li>Windows installer: run npm and Corepack command shims from a Windows-local directory so installs launched from WSL2 UNC paths do not fail before OpenClaw is installed.</li>
<li>Windows updates: roll back git-backed updates to the previous checkout when dependency install, build, UI build, or doctor repair fails.</li>
<li>Windows installer: persist user-local portable Git on PATH and activate the repo-pinned pnpm version for git-backed installs and updates.</li>
<li>Windows installer: bootstrap a user-local portable Node.js when native Windows has no Node and no winget, Chocolatey, or Scoop, so first-run installs can continue on raw hosts.</li>
<li>Windows installer: extract the downloaded portable Node.js directory with native <code>tar</code> before falling back to .NET zip extraction, avoiding PowerShell 5.1 archive and path-length failures.</li>
<li>fix(integrations): enforce channel read target allowlists [AI]. (#84982) Thanks @pgondhi987.</li>
<li>Agents/heartbeat: route single-owner <code>session.dmScope=main</code> direct-message exec and cron event wakes back to the agent main session so async completions no longer strand context in orphan direct-DM queues. Fixes #71581. (#83743) Thanks @Kaspre.</li>
<li>Agents/code-mode: expose outer code-mode <code>exec</code> source through the <code>command</code> hook alias with <code>toolKind</code>/<code>toolInputKind</code> discriminators so exec-shaped policies can distinguish code-mode cells. (#83483) Thanks @Kaspre.</li>
<li>Agents/code mode: return structured timeout and runtime-unavailable error codes for known worker failures. Fixes #83389. (#83444) Thanks @Kaspre.</li>
<li>QA-Lab: isolate multi-scenario suite workers when scenarios need startup config patches, preventing message-routing config from leaking into unrelated scenarios.</li>
<li>QA-Lab: make the commitments heartbeat-target-none scenario request an immediate heartbeat instead of waiting for the next scheduled heartbeat.</li>
<li>Codex/Plugin SDK: deliver Codex-native subagent completions through a generic harness task runtime so harness-backed plugins can mirror durable task lifecycle and completion delivery without Codex-specific SDK imports. (#83445) Thanks @bryanpearson.</li>
<li>Gateway CLI: surface local post-challenge connect assembly failures immediately instead of waiting for the wrapper timeout. Fixes #68944. (#85253) Thanks @samzong.</li>
<li>Messages: strip unsupported web-search citation control markers from outbound replies before they reach WebChat or external channels. Fixes #85193. (#85204) Thanks @neeravmakwana.</li>
<li>Agents/exec: treat denied exec approvals as terminal instead of feeding them back into agent follow-up work, and recognize Chinese stop phrases in abort handling. Fixes #69386. (#85194) Thanks @samzong.</li>
<li>CLI/agents: abort accepted Gateway-backed <code>openclaw agent</code> runs on SIGINT/SIGTERM so cron and supervisor timeouts do not leave remote agent work alive. Fixes #71710. (#84381) Thanks @Kaspre.</li>
<li>Codex app-server: retry replay-safe stdio client-close turns once using structured failure metadata, while surfacing idle <code>turn/completed</code> timeouts instead of blindly replaying active shared-server turns. Thanks @VACInc.</li>
<li>Codex app-server: reject command overrides that embed Node or package-manager arguments and point users to <code>appServer.args</code>, so Windows startup avoids shell parsing failures. (#84417) Thanks @TurboTheTurtle.</li>
<li>Agents/Copilot: drop unsafe GitHub Copilot Responses reasoning replay items before send so Telegram direct sessions no longer fail on overlong replay IDs. Fixes #85197. (#85198) Thanks @galiniliev.</li>
<li>UI: add accessible tooltips to the topbar color-mode buttons so System, Light, and Dark choices are labeled on hover and focus. (#85227) Thanks @amknight.</li>
<li>fix: constrain Windows task script names [AI]. (#85064) Thanks @pgondhi987.</li>
<li>Control UI: keep the chat session picker from hiding older or cross-agent configured conversations while preserving the bounded configured-agent refresh. (#85211) Thanks @amknight.</li>
<li>Agents/Anthropic: preserve unsafe integer tool-call input values in streamed Anthropic tool-use JSON, preventing Discord-style IDs from being rounded before dispatch. Fixes #47229. (#83063) Thanks @leno23.</li>
<li>Agents/Codex: estimate tool-heavy prompt pressure at the LLM boundary before provider submission, so persistent sessions compact before overflowing context windows. (#85541) Thanks @fuller-stack-dev and @joshavant.</li>
<li>Agents/hooks: wait for local one-shot CLI and Codex <code>agent_end</code> plugin hooks before process cleanup so terminal observability flushes reliably. (#85007)</li>
<li>Providers/Google: preserve Gemini 3 cron <code>thinkingDefault: "low"</code> when stale catalog metadata says <code>reasoning:false</code>, so scheduled runs keep provider-supported thinking instead of downgrading to off. (#85185) Thanks @neeravmakwana.</li>
<li>CLI/agents: allow <code>openclaw agent --session-key</code> to target explicit session keys, including agent-scoped legacy keys. (#85121) Thanks @Kaspre.</li>
<li>Auto-reply/ACP: wait for same-channel block reply delivery before starting tool work, while still honoring ACP dispatch aborts so stopped turns do not wait on slow channel sends. (#83722) Thanks @IWhatsskill.</li>
<li>Codex/ACP: mark required child-run completions that only report progress, omit a final deliverable, or fail requester delivery as blocked while preserving real final reports. (#85110) Thanks @IWhatsskill.</li>
<li>Channels: treat bare abort messages such as <code>stop</code>, <code>abort</code>, and <code>wait</code> as immediate control commands in inbound debounce paths so stop requests are not delayed behind pending message coalescing. (#83348) Thanks @IWhatsskill.</li>
<li>Channels/message tool: resolve configured external channel plugins during in-agent channel selection, so <code>openclaw agent --local</code> message-tool sends no longer report an available channel as unavailable. (#85022) Thanks @Kaspre.</li>
<li>Agents/heartbeat: honor group/channel <code>message_tool</code> visible-reply policy and model-specific Codex runtime config for scheduled heartbeat runs, so failed internal tool output stays private. Fixes #85310. (#85357) Thanks @neeravmakwana.</li>
<li>Gateway/ACP: close child ACP sessions spawned via <code>sessions_spawn</code> when their parent session is reset or deleted, instead of leaving orphaned <code>claude-agent-acp</code> processes that accumulate and exhaust memory. Fixes #68916. (#85190) Thanks @openperf.</li>
<li>Codex app-server: block native execution paths when OpenClaw exec resolves to a node host while preserving the first-party CLI node binding path. Fixes #85012. (#85534) Thanks @joshavant.</li>
<li>Diagnostics: bound cleanup timeout detail logs, emit drop summaries when async diagnostic bursts exceed the queue cap, and surface async queue drops through diagnostic telemetry.</li>
<li>Agents/subagents: surface blocked child-run completions as errors instead of successful subagent finishes. (#80886) Thanks @TurboTheTurtle.</li>
<li>Context engines: fail closed with a descriptive error when the selected agent runtime cannot satisfy declared context-engine host requirements.</li>
<li>Agents/Pi: treat accepted embedded <code>sessions_spawn</code> child-session handoffs as terminal progress so parent turns no longer report false non-deliverable failures. (#85054) Thanks @samzong.</li>
<li>CLI/models: resolve <code>openclaw models set</code> aliases from the runtime config while keeping authored aliases ahead of runtime-only defaults. (#83262) Thanks @IWhatsskill.</li>
<li>Doctor: show personal Codex CLI asset notices as info instead of warnings. Fixes #84859.</li>
<li>WhatsApp: update Baileys to <code>7.0.0-rc13</code> and drop the obsolete logger type patch.</li>
<li>CLI/update: pre-pack GitHub/git package update targets before the staged npm install, restoring <code>openclaw update --tag main</code> for one-off package updates. (#81296) Thanks @fuller-stack-dev.</li>
<li>Gateway: mirror successful same-source message-tool sends into session transcripts so delivered replies stay in later history/context. (#84837) Thanks @iFiras-Max1.</li>
<li>Media generation: keep image, music, and video completion delivery from duplicating or losing task ownership when generated media finishes through active session replies. (#84006) Thanks @fuller-stack-dev.</li>
<li>Infra/json: retry transient <code>File changed during read</code> races while loading JSON state so config and state reads recover instead of failing the turn. (#84285)</li>
<li>Plugins/providers: fail closed for workspace provider plugins during setup-mode discovery unless explicitly trusted, preventing untrusted workspace plugin code from running during provider setup. (#81069) Thanks @mmaps.</li>
<li>Providers/Ollama: resolve configured Ollama Cloud <code>OLLAMA_API_KEY</code> markers to the real discovery key so cloud provider entries keep authenticated model catalog access. (#85037)</li>
<li>Discord: keep persistent component registry fallback warnings actionable by forwarding structured error and cause metadata through the runtime logger. Fixes #84185. (#84190) Thanks @100menotu001.</li>
<li>Gateway/sessions: preserve compatible session auth profile overrides when switching models within the same provider, including provider-auth aliases. Fixes #81837. (#81886) Thanks @TurboTheTurtle.</li>
<li>Gateway/status: surface inbound delivery telemetry counters and transport-liveness warnings in <code>openclaw status --all</code>. Fixes #49577. (#72724)</li>
<li>Docker: prune package-excluded plugin source workspaces and dependency closures so runtime images do not keep packages for plugins that were not opted in.</li>
<li>Providers/Ollama: treat Docker/OrbStack host aliases as local Ollama endpoints so <code>ollama-local</code> marker auth works when OpenClaw runs inside a VM/container and Ollama runs on the host. Fixes #84875.</li>
<li>QA-Lab: keep explicitly searchable/deferred OpenClaw dynamic tool rows report-only by default so tool-coverage gates do not treat mock discovery gaps as hard product failures. (#80319) Thanks @100yenadmin.</li>
<li>Agents/config: keep non-Google provider model refs from being rewritten by Google Gemini preview-id normalization. (#84762) Thanks @zhangguiping-xydt.</li>
<li>Installer: require a real controlling terminal before launching onboarding so headless <code>curl | bash</code> installs finish cleanly after installing the CLI.</li>
<li>Agents/Codex: promote a completed final assistant response when a prompt timeout races Codex app-server completion instead of returning an empty timeout envelope. Refs #84516.</li>
<li>Codex app-server: keep interrupted turn statuses from being treated as OpenClaw aborts by themselves, so tool-only turns remain eligible for no-visible-answer recovery. Fixes #84492.</li>
<li>Agents: cap heartbeat model bleed context hints by the stored session window when runtime model metadata is unavailable, so overflow recovery advice does not suggest a larger window than the active session actually has.</li>
<li>Control UI/Web Push: use <code>https://openclaw.ai</code> as the generated default VAPID subject instead of the old localhost mailbox so iOS PWA push setup uses an Apple-acceptable subject when <code>OPENCLAW_VAPID_SUBJECT</code> is unset. Fixes #83134. (#83317) Thanks @IWhatsskill.</li>
<li>Control UI: distinguish inherited thinking-off settings from explicit Off selections so the thinking selector no longer shows two identical Off rows. (#85223) Thanks @amknight.</li>
<li>Agents/Pi: keep embedded session transcript writes from tripping false takeover detection after packaged npm onboarding agent turns.</li>
<li>Codex/TUI: surface Codex-native post-turn compaction failures instead of continuing uncompacted, and keep successful native compaction serialized before local idle/next-turn handling. Fixes #84305. (#85160) Thanks @joshavant.</li>
<li>Memory/search: stop recall tracking from writing dreaming side-effect artifacts when <code>dreaming.enabled=false</code>, while preserving normal search results. Fixes #84436. (#84444) Thanks @NianJiuZst.</li>
<li>Diffs: render viewer toolbar icons from a closed icon-name map instead of HTML strings, removing the toolbar icon XSS sink. (#83955) Thanks @tanshanshan.</li>
<li>QA: keep <code>pnpm qa:e2e</code> self-check runs inside the private QA runtime envelope even when inherited shell env disables bundled plugins.</li>
<li>fix(config): validate browser sandbox bind sources [AI]. (#84799) Thanks @pgondhi987.</li>
<li>doctor: constrain legacy plugin cleanup paths [AI]. (#84801) Thanks @pgondhi987.</li>
<li>Update/doctor: prune stale local bundled plugin install records that point at old compiled bundled output so current bundled plugin schemas win after upgrade. (#84863) Thanks @fuller-stack-dev.</li>
<li>Providers/Ollama: preserve native Ollama tool-call IDs across assistant replay so Gemini over Ollama Cloud can keep its hidden function-call thought-signature handle.</li>
<li>Discord: keep session recovery and <code>/stop</code> abort ownership on the source dispatch lane while bound ACP turns continue routing to their target session, so stalled pre-run work and late replies are cleared instead of leaking after stop. Fixes #84477. (#85100) Thanks @joshavant.</li>
<li>Codex app-server: mark missing turn completion after observed execution as replay-unsafe and release the session so follow-up turns can run. Fixes #84076. (#85107) Thanks @joshavant.</li>
<li>Codex app-server: give visible <code>message</code> dynamic tool sends a longer timeout budget so slow channel delivery can return its own result or error instead of hitting the 30-second Codex wrapper. (#85216) Thanks @amknight.</li>
<li>Codex app-server: add a dedicated post-tool raw assistant completion idle timeout config so trusted heavy turns can wait longer after tool handoff without weakening final assistant release.</li>
<li>Matrix: keep explicitly configured two-person rooms on the room route before stale <code>m.direct</code> or strict two-member DM fallback can bypass mention gating. Fixes #85017. (#85137) Thanks @joshavant.</li>
<li>Agents/subagents: require explicit subagent allowlist targets to be configured agents so stale deleted-agent ids are omitted from <code>agents_list</code> and rejected by <code>sessions_spawn</code>. Fixes #84811. (#85154) Thanks @joshavant.</li>
<li>PDF tool: time out idle remote PDF body reads after 120 seconds so stalled remote documents return an error instead of wedging the session. Fixes #68649. (#84768) Thanks @luoyanglang.</li>
<li>Diagnostics/OpenTelemetry plugin: suppress handled OTLP exporter promise rejections so collector shutdowns no longer crash the Gateway. (#81085) Thanks @luoyanglang.</li>
<li>Agents/exec: omit raw command text and env values from denied exec failure logs while keeping safe correlation metadata. Fixes #85049. (#85140) Thanks @joshavant.</li>
<li>Media/audio: skip empty structured sherpa-onnx transcripts instead of treating the raw JSON payload as spoken text. (#84667) Thanks @TurboTheTurtle.</li>
<li>Agents/exec: preserve inherited XDG base-directory environment values for subprocesses while still rejecting agent-supplied XDG overrides. Fixes #84854. (#85139) Thanks @joshavant.</li>
<li>Node/Linux: keep <code>OPENCLAW_GATEWAY_TOKEN</code> out of generated systemd unit files by writing node service token values to a node-specific env file. (#84408)</li>
<li>Memory-core/dreaming: reuse stable narrative subagent session keys per workspace and phase while keeping per-run idempotency and bounded cleanup, so stale <code>dreaming-narrative-*</code> sessions do not accumulate. Fixes #68252, #69187, and #70402. (#70464) Thanks @chiyouYCH.</li>
<li>Trajectory/support: tolerate partial skill snapshot entries when building support metadata so rejected skill path scans no longer abort trajectory capture. (#71185) Thanks @lukeboyett.</li>
<li>TUI: coalesce repeated idle Esc abort notices into a single <code>no active run xN</code> system row instead of appending duplicate rows.</li>
<li>Telegram: honor <code>channels.telegram.pollingStallThresholdMs</code> in the default isolated polling path, restarting silent workers instead of leaving inbound updates wedged. Fixes #83950. (#84861) Thanks @joshavant.</li>
<li>Telegram: dedupe replayed message dispatches by Telegram chat/message identity so isolated-ingress replays do not trigger duplicate model dispatches. Fixes #84886. (#85208) Thanks @joshavant.</li>
<li>Slack: suppress reasoning payloads before reply delivery and dispatch accounting, so Slack monitor, slash-command, fallback, and direct reply paths do not leak model reasoning. Fixes #84319. (#84322) Thanks @ffluk3 and @joshavant.</li>
<li>Slack: deliver native plugin approval prompts and updates when Slack native approvals are enabled, while keeping plugin approval authorization separate from exec approvers.</li>
<li>Slack: keep native plugin approval prompts in the originating app conversation thread when the live Slack turn source is a <code>D...</code> conversation.</li>
<li>Agents/Pi: disable the embedded pi-coding-agent runtime auto-retry so OpenClaw's own retry and failover loop does not replay failed tool calls through a nested SDK retry. Fixes #73781. (#74434) Thanks @yelog.</li>
<li>CLI/perf: keep <code>setup --help</code>, <code>onboard --help</code>, and <code>configure --help</code> out of the full wizard runtime while preserving the existing help output. (#84488) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>agents --help</code> out of agents action/runtime imports so help, completion, and command discovery paths avoid loading the full agents runtime. (#84483) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>secrets --help</code> and <code>nodes --help</code> on the precomputed help path so parent help avoids loading action-heavy command runtime modules. (#84818) Thanks @frankekn.</li>
<li>CLI/perf: serve <code>doctor</code>, <code>gateway</code>, <code>models</code>, and <code>plugins</code> parent help from startup metadata so common subcommand help avoids full CLI program construction. (#84786) Thanks @frankekn.</li>
<li>Codex/Lossless: keep context-engine history on the canonical run session when Telegram DMs use per-peer runtime policy keys. Fixes #84936. (#84954) Thanks @neeravmakwana.</li>
<li>Codex: keep heartbeat response tool schemas durable without exposing dynamic tools disabled by turn policy, so heartbeat wakeups can reuse threads while scoped tool allowlists stay enforced. (#84681) Thanks @jalehman.</li>
<li>Auth/OAuth: skip the refresh adapter when a stored OAuth credential has no refresh token so agent turns fail fast on missing-key instead of waiting on the 120s refresh timeout. Thanks @romneyda.</li>
<li>Auth/Codex: load legacy OAuth sidecar credentials in the embedded runner's secrets-runtime auth loaders so Telegram replies, cron-triggered turns, and other isolated sub-agent lanes can reach the existing #83312 refresh-and-rewrite migration instead of failing with <code>No API key found for provider "openai-codex"</code> until the user runs <code>openclaw doctor</code>. Thanks @Totalsolutionsync and @romneyda.</li>
<li>Codex/failover: classify <code>deactivated_workspace</code> as a permanent auth failure so configured fallback models can advance when a Codex workspace is deactivated. (#55893) Thanks @litang9.</li>
<li>Exec: keep configured <code>tools.exec.pathPrepend</code> entries ahead of user shell startup PATH changes on POSIX gateway runs. (#81403) Thanks @medns.</li>
<li>Gateway/sessions: allow shared-secret bearer callers to read and stream session history without an explicit scope header. (#81815) Thanks @medns.</li>
<li>Agents/embedded runner: classify HTML auth provider responses as <code>auth_html</code> and return a re-authentication hint instead of the CDN-blocked copy that <code>upstream_html</code> returns. Cloudflare Access login pages, nginx basic-auth challenges, and gateway login walls all produce HTML auth bodies that were previously misdiagnosed as transient CDN blocks. (#79900) Thanks @martingarramon.</li>
<li>TUI/streaming watchdog: dismiss the <code>This response is taking longer than expected</code> notice as soon as a chat event for the same run arrives, so the message no longer sits next to the recovered response when the run was only briefly silent. Refs #67052, #69081 (closed), prior attempt #69026. Thanks @jpruit20 and @romneyda.</li>
<li>Agents/Pi: tolerate OpenClaw-owned transcript writes while embedded prompts are released for model I/O, keeping long-running Feishu, Slack, Telegram, and cron turns from failing with false session-takeover errors. Fixes #84059. (#84250) Thanks @tianxiaochannel-oss88.</li>
<li>Agents: fall back to local config pruning when the optional <code>agents delete</code> Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.</li>
<li>Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.</li>
<li>Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.</li>
<li>Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format <code>skills</code> command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, and @benjamin1492.</li>
<li>Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.</li>
<li>Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.</li>
<li>CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical <code>api_key</code> auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.</li>
<li>Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.</li>
<li>Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 <code>no_proxy</code> entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.</li>
<li>Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.</li>
<li>Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887)</li>
<li>Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)</li>
<li>WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492)</li>
<li>Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.</li>
<li>Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)</li>
<li>Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611)</li>
<li>Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek <code>reasoning_content</code> replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @eleqtrizit.</li>
<li>Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)</li>
<li>File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.</li>
<li>Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)</li>
<li>Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.</li>
<li>Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.22/OpenClaw-2026.5.22.zip" length="54409357" type="application/octet-stream" sparkle:edSignature="am1mwLOmUHor9QuQWtxSsKoBOCySUBo4fB+0Qdcrz0E3wf6ESIMTfOC0k+dKJSh9gtLZw5jzpWVqTBzEdU36Aw=="/>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.28/OpenClaw-2026.5.28.zip" length="54750142" type="application/octet-stream" sparkle:edSignature="U4O55uMdPU+OqSx9QR1ApUJ8wg65wxTydzD7iyCn1GHtm1MBK9noEeiA/yoUKkqb/bx0hzi1gNhn+ye19RXnCA=="/>
</item>
<item>
<title>2026.5.20</title>
<pubDate>Thu, 21 May 2026 21:19:52 +0000</pubDate>
<title>2026.5.27</title>
<pubDate>Thu, 28 May 2026 12:12:19 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052090</sparkle:version>
<sparkle:shortVersionString>2026.5.20</sparkle:shortVersionString>
<sparkle:version>2026052790</sparkle:version>
<sparkle:shortVersionString>2026.5.27</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.20</h2>
<description><![CDATA[<h2>OpenClaw 2026.5.27</h2>
<h3>Highlights</h3>
<ul>
<li>Stronger security and content boundaries: group prompt text is kept out of the system prompt, repeated-dot hostnames are normalized, side-effecting command wrappers and unsafe Node runtime env overrides are blocked, no-auth Tailscale exposure is rejected, and node/device-role approvals now require admin authority. (#87144, #87305, #87292, #87308, #87146) Thanks @eleqtrizit and @pgondhi987.</li>
<li>More reliable Codex app-server runs: Codex runtime models resolve first, workspace memory is routed through tools, shared app-server clients survive startup and spawned-helper failures, native hook relay generations survive restarts and rotate on fresh fallbacks, and false runtime live switches are avoided. (#87383, #87403, #87375, #72574, #87428) Thanks @yetval.</li>
<li>Faster Gateway and reply paths: session reads, plugin metadata fingerprints, auth env snapshots, auto-enabled plugin config, tool-search catalogs, and stable metadata caches do less hot-path rediscovery while visible replies no longer inherit hidden cleanup timeouts. (#86439, #87044) Thanks @keshavbotagent.</li>
<li>Better provider and model coverage: OpenAI-compatible embedding providers are core, DeepInfra catalog browsing loads the full credential-aware model set, Pixverse adds video generation and API region selection, VLLM thinking params are wired, Claude CLI OAuth overlays load for PI auth profiles, and bare direct Anthropic model ids work. (#85269, #84549, #87167) Thanks @dutifulbob, @ats3v, and @joshavant.</li>
<li>Channel delivery is steadier: Telegram <code>sendMessage</code> actions use durable outbound delivery, iMessage suppresses duplicate native exec approval prompts and sends, Slack keeps delivered final replies during late cleanup, Matrix mention previews/finals are stricter, QQBot fallback approval buttons honor slash-command auth, Discord guild requester checks are tighter, recovered Discord tool-warning artifacts stay out of successful replies, and Google Chat stops thread sends in DMs. (#87261, #87154) Thanks @mbelinky and @eleqtrizit.</li>
<li>Release, package, and CI proof paths are harder to wedge: npm/package inventory honors dist exclusions, shrinkwrap override pins merge correctly, Docker runtime workspace templates are packaged and smoked, release postpublish checks are stricter, beta smoke rejects empty runs, and E2E log/probe waits are bounded.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Exec approvals: remove the old <code>cat SKILL.md && printf ... && <skill-wrapper></code> allowlist compatibility path so skill files must be loaded with the read tool and only the real skill executable is auto-allowed.</li>
<li>Discord: let voice sessions follow configured Discord users into voice channels, with allowed-channel checks, multi-user handoff, bounded reconciliation, and DAVE recovery preservation. (#84264) Thanks @fuller-stack-dev.</li>
<li>Discord/voice: include bounded <code>IDENTITY.md</code>, <code>USER.md</code>, and <code>SOUL.md</code> profile context in realtime voice session instructions by default, with <code>voice.realtime.bootstrapContextFiles: []</code> available to disable it. (#84499) Thanks @fuller-stack-dev.</li>
<li>Dependencies: bump the bundled Codex harness to <code>@openai/codex</code> <code>0.132.0</code> and refresh the app-server model-list docs for the new catalog.</li>
<li>CLI/policy: add the bundled Policy plugin for policy-backed channel conformance checks, doctor lint findings, and opt-in workspace repair. (#80407) Thanks @giodl73-repo.</li>
<li>Agents/config: allow <code>agents.list[].experimental.localModelLean</code> so lean local-model mode can be enabled for one configured agent instead of globally.</li>
<li>Providers/xAI: add device-code OAuth login so remote and headless setups can authorize xAI without a localhost browser callback. (#84005) Thanks @fuller-stack-dev.</li>
<li>Providers/OpenRouter: honor provider-level <code>params.provider</code> routing policy for OpenRouter requests, with model and agent params overriding the defaults. Thanks @amknight.</li>
<li>Memory: add a core OpenAI-compatible embedding provider for local and hosted OpenAI-style endpoints, with config, doctor, and docs support. (#85269) Thanks @dutifulbob.</li>
<li>Plugin SDK: mark memory-specific embedding provider registration as deprecated compatibility and surface non-bundled usage in plugin compatibility diagnostics. (#85072) Thanks @mbelinky.</li>
<li>Providers: add the Pixverse video generation provider, API region selection, docs, and external plugin packaging support.</li>
<li>DeepInfra: load the full model catalog when users browse models during onboarding, preserve configured API-key catalogs, refresh media/video defaults, and keep pricing/default model metadata aligned. (#84549) Thanks @ats3v.</li>
<li>Plugin SDK: expose plugin approval action metadata and stop exporting Vitest test helpers from the public SDK surface. (#87120) Thanks @RomneyDa.</li>
<li>Channel SDK: move channel message compatibility into core, remove old channel turn runtime aliases, and preserve runtime catalog markdown metadata for plugins.</li>
<li>ClawHub: add plugin display metadata so catalog/package listings use cleaner names. (#87354) Thanks @thewilloftheshadow.</li>
<li>Agents: split the heartbeat runtime template out of docs assets and add compatibility repair for legacy heartbeat template content. (#85416) Thanks @hxy91819.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>CLI/tasks: include stale-running task maintenance decisions in <code>openclaw tasks maintenance --json</code> so retained and reconcile candidates explain backing-session, cron, CLI, and wedged-subagent state. (#84691) Thanks @efpiva.</li>
<li>Codex app-server: keep system-prompt reports working when bootstrap hooks provide workspace files with only a path and content, so hook-supplied SOUL/IDENTITY/TOOLS/USER context still reports injected characters correctly. (#84736) Thanks @JARVIS-Glasses.</li>
<li>Providers/MiniMax music: stop advertising <code>durationSeconds</code> control and remove prompt-injected duration hints, so <code>music_generate</code> reports MiniMax duration as an unsupported override instead of suggesting MiniMax can enforce track length. Fixes #84508. Thanks @neeravmakwana.</li>
<li>Doctor: warn when sandbox tool policy hides configured MCP server tools before provider requests. (#84699) Thanks @nxmxbbd.</li>
<li>WhatsApp: update Baileys to <code>7.0.0-rc12</code>.</li>
<li>Build: suppress per-locale <code>rolldown-plugin-dts:fake-js</code> CommonJS dts warnings emitted while bundling the intentionally-inlined <code>zod/v4/locales/*.d.cts</code> files, so <code>pnpm build</code> output stays readable after the 0.25.1 plugin bump. Thanks @romneyda.</li>
<li>CLI/nodes: route lazy plugin-registration logs to stderr for JSON-mode <code>openclaw nodes</code> commands so stdout stays parseable. (#84684) Thanks @TurboTheTurtle.</li>
<li>Approvals: route manual <code>/approve</code> decisions through the trusted approval runtime so active exec and plugin approvals no longer look unknown or expired.</li>
<li>Mac app: update the About settings copyright year to 2026. (#84385) Thanks @pejmanjohn.</li>
<li>Dependencies: update <code>@openclaw/fs-safe</code> to <code>0.2.7</code> so OpenClaw's default Python-helper-off policy keeps best-effort Node write fallbacks for private stores, secret writes, run logs, and media attachments on Linux/macOS.</li>
<li>Infra/secrets: restore the fail-closed contract for <code>tryReadSecretFileSync</code> so credential loaders that pass <code>rejectSymlink: true</code> (Telegram, LINE, Zalo, IRC, Nextcloud Talk tokens) refuse symlinked credential files instead of silently accepting them, and the infra-state CI shard's secret-file symlink test passes again. Thanks @romneyda.</li>
<li>Browser: honor the configured image sanitization limit for screenshots and labeled snapshots so browser-captured images follow the same resize policy as other image results. (#84595)</li>
<li>Doctor: remove unrecognized <code>models.providers.*.models[*].compat.thinkingFormat</code> values during <code>doctor --fix</code> so stale provider model config can validate after upgrade. Fixes #77803.</li>
<li>Doctor: warn when <code>openclaw.json</code> stores plaintext secret-bearing config fields, including model provider API keys and sensitive provider headers. (#84718) Thanks @lukaIvanic.</li>
<li>Status: show the configured default, session-selected model, reason, clear hint, and docs link when a session remains pinned to a model that differs from <code>agents.defaults.model.primary</code>.</li>
<li>WebChat: clear stale typing indicators when session change events mark the active chat run complete.</li>
<li>Mac app: keep local packaging signed with a stable app identity for permission testing and fix Control UI production builds under current Vite/Highlight.js exports.</li>
<li>macOS app: update the embedded Peekaboo bridge to 3.2.1 so OpenClaw-hosted UI automation works with current Peekaboo CLI capture flows.</li>
<li>Cron: deliver preferred final assistant output for successful scheduled runs when trailing plain tool warnings remain in diagnostics instead of marking the run failed.</li>
<li>fix(mattermost): fail closed on missing channel type [AI]. (#84091) Thanks @pgondhi987.</li>
<li>Recheck rebuilt system.run argv [AI]. (#84090) Thanks @pgondhi987.</li>
<li>CLI: keep the private QA subcommand out of exported command descriptors unless <code>OPENCLAW_ENABLE_PRIVATE_QA_CLI=1</code>, so root help and subcommand markers match runtime registration. (#84519)</li>
<li>CLI/cron: bound <code>openclaw cron show</code> job lookup pagination so non-advancing or unbounded <code>cron.list</code> responses fail instead of hanging the command. Fixes #83856. (#83989)</li>
<li>Agents/messages: stop message-tool-only turns after a successful source-channel <code>message</code> send while keeping transcript mirrors under the session write lock. (#84289)</li>
<li>Agents: filter silent heartbeat response-tool transcript artifacts out of embedded context snapshots so later user turns are not polluted by heartbeat no-op messages. (#83477) Thanks @fuller-stack-dev.</li>
<li>Agents/OpenAI: log repeated strict tool-schema downgrade diagnostics once per provider/model/tool signature, reducing duplicate debug noise while preserving <code>strict=false</code> fallback behavior. Fixes #82930. (#82933) Thanks @galiniliev.</li>
<li>Agents/code mode: spell out the <code>exec</code> tool's JavaScript/TypeScript, no Node module, and catalog-bridge constraints in model-visible schema text so agents can use enabled tools without trial-and-error. (#84269) Thanks @Kaspre.</li>
<li>Codex: give <code>image_generate</code> dynamic-tool calls a 120s default watchdog when no per-call or configured image timeout is set, so image generation no longer falls back to the generic 30s bridge timeout. (#84254) Thanks @moritzmmayerhofer.</li>
<li>Codex: avoid duplicate dynamic tool terminal diagnostics while large diagnostic backlogs drain without blocking tool responses. (#82937) Thanks @galiniliev.</li>
<li>CLI/message: include a stable top-level <code>messageId</code> in <code>openclaw message --json</code> output when channel sends return one. (#84191) Thanks @100menotu001.</li>
<li>Cron: preserve legacy top-level array <code>jobs.json</code> stores when loading or adding scheduled jobs so old cron jobs are no longer treated as an empty store during upgrade. Fixes #60799. (#84433) Thanks @IWhatsskill.</li>
<li>Gateway/agents: use an agent's <code>identity.name</code> in Gateway agent summaries when <code>agents.list[].name</code> is unset, so configured agent labels remain visible in clients. (#84355; refs #57835) Thanks @luoyanglang.</li>
<li>Channels/replies: keep normal <code>/verbose</code> failed-tool progress compact in message-tool replies and prevent late text-only tool output from appearing after the final answer. (#84303) Thanks @VACInc.</li>
<li>Plugins/hooks: apply a default 30-second timeout to <code>before_compaction</code> and <code>after_compaction</code> hooks so a hung plugin handler no longer blocks compaction completion. (#84153)</li>
<li>Discord: preserve disabled presentation buttons when adapting and rendering Discord message controls. (#84188) Thanks @100menotu001.</li>
<li>Twitch: add a test-only client-manager registry reset helper so non-isolated Twitch tests can clear cached managers between cases. Fixes #83887. (#84244) Thanks @hclsys.</li>
<li>Cron: run main-session scheduled work on a cron-owned wake lane while preserving reply delivery context, so background cron turns no longer block human main-session chat. Fixes #82766. (#82767) Thanks @galiniliev.</li>
<li>Cron: use structured embedded-run denial metadata for isolated scheduled tasks so blocked exec requests fail the job without treating ordinary assistant prose as a denial. (#84067) Thanks @abnershang.</li>
<li>Cron: keep recovered tool warnings diagnostic for successful scheduled runs so final cron output is delivered instead of being replaced by a post-processing warning. (#84045) Thanks @abnershang.</li>
<li>Plugins/perf: thread explicit plugin discovery results through <code>loadBundledCapabilityRuntimeRegistry</code>, <code>resolveBundledPluginSources</code>, and <code>listChannelCatalogEntries</code> so callers that already hold a discovery result skip redundant filesystem walks. Thanks @SebTardif.</li>
<li>harden update restart script creation [AI]. (#84088) Thanks @pgondhi987.</li>
<li>Docker: keep the bundled Codex plugin in official release image keep lists so the default OpenAI agent harness remains available after Docker pruning. Fixes #83613. (#83626) Thanks @YuanHanzhong.</li>
<li>CLI/channels: preserve the first line of <code>openclaw channels logs</code> output when the rolling tail window starts exactly on a line boundary, mirroring the already-fixed <code>readLogSlice</code> behavior in <code>src/logging/log-tail.ts</code>.</li>
<li>Control UI: treat terminal session status as authoritative over stale active-run flags so completed terminal runs stop showing abort/live UI. (#84057)</li>
<li>CLI: preserve embedded equals signs in inline root option values instead of truncating after the second separator. (#83995) Thanks @ThiagoCAltoe.</li>
<li>Matrix/config: accept <code>messages.queue.byChannel.matrix</code> queue overrides and keep queue provider schema/type keys aligned for Matrix, Google Chat, and Mattermost. Thanks @bdjben.</li>
<li>CLI: format <code>openclaw acp client</code> failures through the shared error formatter so object-shaped errors stay readable instead of printing <code>[object Object]</code>. Fixes #83904. (#84080)</li>
<li>Providers/Ollama: default unknown-capabilities models to tool-capable so discovered native Ollama models can use tools when <code>/api/show</code> omits capabilities. (#84055) Thanks @dutifulbob.</li>
<li>Installer/Windows: launch <code>install.ps1</code> onboarding as an attached child process so fresh native Windows installs do not freeze visibly at <code>Starting setup...</code> or corrupt the wizard's terminal rendering.</li>
<li>CLI/update: keep restart health checks working across one-version CLI/Gateway protocol skew and use the managed Gateway service Node for all follow-up commands even when the package root is unchanged, so <code>openclaw update</code> no longer silently switches the gateway to a different Node binary when multiple Node installations are present. Thanks @amknight.</li>
<li>CLI/gateway: include the running Gateway version in <code>gateway status</code> JSON output, preserving existing server metadata while falling back to status RPC data for read probes. Fixes #56222. Thanks @galiniliev.</li>
<li>Memory/search: close local embedding providers when active-memory searches time out so pending local model loads and embedding contexts are aborted and released. (#83858) Thanks @brokemac79.</li>
<li>CLI/nodes: request pending node surface approval scopes before <code>openclaw nodes approve</code> so exec-capable node approval can use admin-scoped Gateway credentials instead of failing with <code>missing scope: operator.admin</code>. (#84392) Thanks @joshavant.</li>
<li>Gateway: reject slow node event sends before outbound buffers grow unbounded and log the rejected payload diagnostic. (#84387) Thanks @samzong.</li>
<li>Agents: include bounded trajectory queued-writer diagnostics in <code>pi-trajectory-flush</code> timeout warnings so flush stalls show pending writes, queued bytes, and append state. Fixes #82961. (#82962) Thanks @galiniliev.</li>
<li>Agents/subagents: recover stale completion announces by retrying unsupported transcript-wait wakes without transcript waiting and forcing a message-tool handoff when the requester run is already stale. Fixes #83699. (#83700) Thanks @galiniliev.</li>
<li>Agents/subagents: constrain wildcard subagent target allowlists to configured agents while preserving explicitly listed compatibility targets. Fixes #84040. (#84357) Thanks @joshavant.</li>
<li>Providers/Anthropic: route Anthropic model refs selected with Claude CLI auth through the Claude CLI runtime so shorthand refs such as <code>anthropic/opus-4.7</code> no longer fall back to embedded Anthropic billing. Fixes #84222. (#84374) Thanks @joshavant.</li>
<li>Agents: honor explicit <code>models.providers.<id>.timeoutSeconds</code> values above the default idle watchdog for cloud and self-hosted providers, so long first-token waits no longer fall back at ~120s when the provider timeout is higher. (#83979) Thanks @yujiawei.</li>
<li>Agents/Codex: keep encrypted Responses reasoning replay provenance-bound so stale mirrored Codex transcripts drop invalid encrypted content before request assembly while preserving matching same-session replay. Fixes #83836. (#84367) Thanks @joshavant.</li>
<li>Agents/subagents: skip stale embedded-run wake probes for dormant completion requesters, so late subagent completions go straight to requester-agent/direct handoff instead of producing <code>reason=no_active_run</code> queue noise. (#82964) Thanks @galiniliev.</li>
<li>CLI: retry config snapshot reads after a transient failure so one rejected read no longer poisons later commands in the same process. (#83931) Thanks @honor2030.</li>
<li>Media: decode URL path basenames before using them as remote media fallback filenames, so files like <code>My%20Report.pdf</code> are surfaced as <code>My Report.pdf</code>. Fixes #84050. (#84052) Thanks @jbetala7.</li>
<li>WhatsApp: clarify inbound group diagnostics so observed but unregistered groups point to <code>channels.whatsapp.groups</code> without changing routing or sender authorization. (#83846) Thanks @neeravmakwana.</li>
<li>WhatsApp: drain pending outbound deliveries on a 30s periodic timer in addition to the reconnect handler, so messages enqueued while the provider is already connected no longer wait for the next reconnect to send. (#79083) Thanks @Oviemudiaga.</li>
<li>CLI/TUI: include gateway plugin slash commands in TUI autocomplete, so connected sessions can suggest plugin-owned commands exposed by the running Gateway. (#83640) Thanks @se7en-agent.</li>
<li>Gateway/mobile: restore QR setup-code handoff of bounded operator tokens for iOS and Android onboarding while keeping admin and pairing scopes out of bootstrap. (#83684) Thanks @ngutman.</li>
<li>iOS: repair Release archive compilation for the TestFlight build. (#84255) Thanks @ngutman.</li>
<li>Agents/compaction: bound plugin-owned CLI transcript compaction with the host safety timeout so a hung context engine can no longer stall post-turn cleanup. (#84083) Thanks @100yenadmin.</li>
<li>Control UI/usage: truncate long context skill, tool, and file names in the usage panel while keeping the full name available on hover. (#42197) Thanks @Rain120.</li>
<li>Codex: respect explicit <code>models auth order set</code> and <code>config.auth.order</code> precedence over stale <code>lastGood</code> in <code>/codex account</code>, and show <code>no working credential</code> when every explicit-order profile is ineligible instead of marking a lower-ranked profile as active. Fixes #84386. (#84412) Thanks @openperf.</li>
<li>Agents: honor <code>messages.suppressToolErrors</code> for mutating tool failures so configured chat surfaces do not receive separate warning payloads. (#81561) Thanks @moeedahmed.</li>
<li>Agents/fallback: surface billing guidance for mixed rate-limit plus billing fallback exhaustion instead of generic failure copy. Fixes #79396. (#79489) Thanks @aayushprsingh.</li>
<li>Security/content boundaries: route untrusted group prompt metadata outside system prompts, normalize repeated trailing hostname dots, block side-effecting command wrappers, reject unsafe Node runtime env overrides, reject no-auth Tailscale exposure, block untrusted Microsoft Teams service URLs, enforce <code>/allowlist configWrites</code> origin policy, gate QQBot fallback approval buttons, and require admin for node/device-role approvals. (#87144, #87305, #87292, #87308, #87146, #87154, #87334) Thanks @eleqtrizit and @pgondhi987.</li>
<li>Codex: resolve Codex runtime models before generic routing, route workspace memory through tools, preserve shared app-server clients after startup and spawned-helper failures, preserve native hook relay generations across restarts and fresh fallbacks, keep raw reasoning/source-reply guards intact, report quarantined dynamic tools, keep the attempt watchdog armed for queued terminal turns, and route Codex OAuth compaction through OpenAI-Codex. (#87383, #87403, #87375, #72574, #87428) Thanks @yetval.</li>
<li>Agents/runtime: avoid session event queue self-waits, bound compaction wake and steering retries, preserve grace for pending error diagnostics, avoid false Codex runtime live switches, avoid stale restart continuation reuse, preserve session fallback errors, suppress duplicate Claude CLI skill prompts, keep runtime context before active user turns, strip stale Anthropic thinking, quarantine unsupported tool schemas, recover completed write timeouts safely, release retained session write locks on timeout abort, and validate forced plugin harness support before pinning. (#86123, #55424, #86855, #74341, #87278) Thanks @luoyanglang, @cathrynlavery, and @openperf.</li>
<li>Reply/session delivery: keep visible turn admission unbounded, keep visible fallback delivery on latest targets, preserve bridge hook context, classify direct fallback targets by channel grammar, report approval resolutions in bridge mode, and avoid stale source-reply artifacts. (#87044) Thanks @keshavbotagent.</li>
<li>Channels: make Telegram <code>sendMessage</code> action replies durable and preserve SecretRef prompt config, suppress duplicate iMessage native exec approval prompts and sends, keep iMessage approval polling alive after denied reactions, keep Slack delivered final replies during late cleanup, keep Matrix mention previews/finals mention-inert and normally delivered, ignore filename-embedded Matrix IDs, suppress recovered Discord tool-warning artifacts from successful replies, suppress Google Chat thread sends in DMs, and harden Discord guild requester checks. (#87261, #87452) Thanks @mbelinky.</li>
<li>Memory: salvage QMD search JSON after nonzero exits and keep workspace memory routing through the Codex tool path where possible. (#87225, #87383, #87403) Thanks @osolmaz.</li>
<li>Providers/models: forward cached token usage in OpenAI-compatible chat completions, load Claude CLI OAuth overlays for PI auth profiles, send bare direct Anthropic model ids, wire configured VLLM thinking params, honor OpenAI-compatible cache retention, normalize OpenAI Responses replay tool ids, resolve OpenAI <code>gpt-5.5</code> without a cached catalog, preserve <code>retry-after</code> fallback handling, bound GitHub Copilot auth requests, and load DeepInfra custom/live catalogs consistently. (#82062, #87167, #84549) Thanks @caz0075, @joshavant, and @ats3v.</li>
<li>Gateway/performance: borrow read-only session metadata and active session working stores, cache current/stable plugin metadata fingerprints, cache auto-enabled plugin config, slim metadata identity caches, trust current metadata lifecycle caches, stabilize isolated cron prompt-cache affinity, persist model auth profile suffixes, drain probe client closes, expire browser tokens after auth rotation, and keep default status fast paths bounded. Thanks @ferminquant.</li>
<li>CLI/help/config: reject loose or malformed numeric options for gateway timeouts, model limits, directory limits, message options, webhooks, and partial values; respect subcommand version options; route generated/root/plugin help targets correctly; keep skills JSON output flushing naturally; and keep plugin descriptor loading quiet in root help. (#87398) Thanks @Patrick-Erichsen.</li>
<li>Plugin state/tool search: evict the current namespace when plugin rows hit caps, reuse unchanged tool-search catalogs, align the release catalog reuse wrapper, and keep fallback tool warnings mention-inert.</li>
<li>Install/package/release: match npm globstar exclusions, honor dist package exclusions in inventory, omit unpacked test helpers, skip Homebrew until macOS packages need it, package Docker runtime workspace templates, smoke Docker runtime templates during full validation, merge nested shrinkwrap override pins, preserve forked shrinkwrap pins, pin aged <code>lru-cache</code>, harden postpublish verification, accept main full-validation proof, and reject empty beta smoke runs.</li>
<li>E2E/QA/Crabbox: bound Telegram, Open WebUI, ClawHub, Matrix, Tool Search, MCP, gateway network, bundled runtime, kitchen-sink, codex media, config reload, and agent-turn assertion waits; prefer Azure for Windows targets; reinitialize invalid changed-gate git dirs; full-sync sparse container runs; and fail empty explicit test requests. (#87186)</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.20/OpenClaw-2026.5.20.zip" length="54396392" type="application/octet-stream" sparkle:edSignature="Ufz+twYjgj5NDg29tG3Ttx/JNyT3/a3EKLciBGvsa38C6Dwqp4yFYC5jSBiSlubwBXhrq8OQDMgavMKtSsclBQ=="/>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.27/OpenClaw-2026.5.27.zip" length="54488811" type="application/octet-stream" sparkle:edSignature="c5w2T1UO6vpPs70hyYH93cIyWEOd5sl5z2NkhU53E+XQBSd+jAr+xd0qf3KzWbeX2mfXYMQmnx+VMls3L22EDg=="/>
</item>
<item>
<title>2026.5.19</title>
<pubDate>Wed, 20 May 2026 21:27:21 +0000</pubDate>
<title>2026.5.26</title>
<pubDate>Wed, 27 May 2026 12:24:26 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026051990</sparkle:version>
<sparkle:shortVersionString>2026.5.19</sparkle:shortVersionString>
<sparkle:version>2026052690</sparkle:version>
<sparkle:shortVersionString>2026.5.26</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.19</h2>
<description><![CDATA[<h2>OpenClaw 2026.5.26</h2>
<h3>Highlights</h3>
<ul>
<li>Faster Gateway and replies: startup avoids repeated plugin, channel, session, usage-cost, warning, scheduled-service, and filesystem scans; visible replies separate user-facing sends from slower follow-up work; Gateway runtime/session caches churn less under load.</li>
<li>Transcripts are core: transcript-backed meeting summaries, source-provider chunks, cleaned user turns, media provenance, Codex mirrors, WebChat replies, and CLI/TUI replay now use one more reliable transcript path.</li>
<li>More channels are production-ready: Telegram keeps typing/progress context and forum topics, iMessage handles attachment roots, remote media staging, and duplicate local Messages sources, WhatsApp restores group/media behavior, Discord improves voice playback and model picking, and Signal/iMessage/WhatsApp get reaction approvals.</li>
<li>Better voice and Talk: realtime Talk runs can be inspected, steered, cancelled, or followed up from Web UI and Discord voice; wake-name handling is more tolerant without letting ambient speech trigger agents.</li>
<li>Safer content boundaries: Browser snapshot reads honor SSRF policy, system-event text cannot spoof nested prompt markers, fetched file text is wrapped as external content, ClickClack inbound sender allowlists run before agent dispatch, stale device tokens are rejected, and serialized tool-call text is scrubbed from replies.</li>
<li>Providers, Codex, and local models are steadier: named auth profiles, OpenAI sampling params, Codex app-server resume/timeout/usage-limit recovery, dynamic tool-schema guards, xAI usage-limit surfacing, Ollama top-p normalization, and local approval resolution reduce provider-specific dead ends.</li>
<li>More reliable install/update/release paths: Alpine installs, trusted runtime fallback roots, stable update channels, Docker/package timeouts, Windows Scheduled Tasks, Windows/macOS proof lanes, Testbox/Crabbox delegation, plugin publish checks, and macOS runner bootstraps all got hardened.</li>
<li>Better observability: Activity tab, gateway secret-prep traces, tool/model stream progress, explicit fast-mode status, systemd Gateway hygiene, OpenTelemetry LLM spans, release performance evidence, and richer telemetry signals make failures easier to inspect.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Agents: clarify that fixes should default to clean bounded refactors, lean internals, and explicit plugin SDK/API deprecation paths.</li>
<li>Dependencies: update <code>@openclaw/proxyline</code> to 0.3.3.</li>
<li>Dependencies: update Pi packages to 0.75.1 and raise the minimum supported Node.js 22 line to 22.19.</li>
<li>Docker/Podman: add <code>OPENCLAW_IMAGE_APT_PACKAGES</code> as the runtime-neutral image build arg for extra apt packages while keeping <code>OPENCLAW_DOCKER_APT_PACKAGES</code> as a legacy fallback. (#62431) Thanks @urtabajev.</li>
<li>Gateway/ACPX: attribute startup probe, config, runtime, and resource-count costs in restart traces without changing readiness behavior. (#83300) Thanks @samzong.</li>
<li>Gateway: overlap startup logging and plugin-service startup with channel sidecars to reduce restart ready latency while preserving <code>/readyz</code> sidecar gating. (#83301) Thanks @samzong.</li>
<li>Plugins/admin-http-rpc: allow trusted admin HTTP RPC clients to start and wait for web QR login flows. (#83259) Thanks @liorb-mountapps.</li>
<li>Mac app: redesign Settings pages with consistent card layouts, cached navigation, cleaner permissions/voice/skills/cron/exec/debug panes, and steadier spacing around the native sidebar.</li>
<li>Mac app: refine Voice & Talk recognition-language and wake-phrase settings so they use the same compact card rows as the rest of Settings.</li>
<li>Skills: rename the repo-local Codex closeout review skill and helper to <code>autoreview</code> while preserving the Codex-first fallback behavior.</li>
<li>Skills: add a meme-maker skill for curated template search, local SVG/PNG rendering, Imgflip hosted rendering, and Know Your Meme provenance links.</li>
<li>Skills CLI: allow <code>openclaw skills install</code> and <code>openclaw skills update</code> to target shared managed skills with <code>--global</code>. (#74466) Thanks @Marvae.</li>
<li>Browser: surface pending and recently handled modal dialogs in snapshots, return <code>blockedByDialog</code> when an action opens a modal, and allow <code>browser dialog --dialog-id</code> to answer pending dialogs.</li>
<li>Browser CLI: add <code>openclaw browser evaluate --timeout-ms</code> so long-running page functions can extend both the evaluate action and request timeout budgets. (#83447) Thanks @eefreenyc.</li>
<li>Codex app-server: scope OpenClaw prompt guidance by runtime surface so native Codex keeps Codex-owned base/personality instructions while OpenClaw contributes only runtime context, delivery guidance, and explicitly scoped command hints. (#83454) Thanks @100yenadmin.</li>
<li>Docker/Podman: add <code>OPENCLAW_IMAGE_PIP_PACKAGES</code> for opt-in Python package installation in local image builds. (#83771) Thanks @stephenredmond-straiteis.</li>
<li>Agents/tools: shorten built-in tool descriptions and schema hints across media, messaging, sessions, cron, Gateway, web, image/PDF, TTS, nodes, and plan tools while preserving routing guardrails.</li>
<li>Skills: add node inspector debugging, fused diagram generation, and throwaway spike workflow skills.</li>
<li>CLI/plugins: add <code>defineToolPlugin</code> plus <code>openclaw plugins build</code>, <code>validate</code>, and <code>init</code> for typed simple tool plugins with generated manifest metadata, optional tool declarations, and context factories.</li>
<li>Agents/skills: tighten bundled skill prompts and metadata, quote skill descriptions, refresh current CLI/API guidance, and update embedded sherpa-onnx runtime downloads.</li>
<li>Skills: update the Obsidian skill to target the official <code>obsidian</code> CLI and require its registered binary instead of the third-party <code>obsidian-cli</code>.</li>
<li>Skills: add a Python debugging skill for pdb, breakpoint(), post-mortem inspection, and debugpy remote attach.</li>
<li>Codex: add <code>/codex plugins list</code>, <code>enable</code>, and <code>disable</code> for managing configured native Codex plugins from chat without editing config by hand.</li>
<li>Plugins/messages: add presentation capability limits for channel renderers, adapt rich message controls before native rendering, and mark legacy <code>interactive</code>/Slack directive producer APIs as deprecated.</li>
<li>Plugins/subagents: store channel delivery routes as canonical session metadata and deprecate ad hoc subagent hook delivery-origin fields in favor of core route projection.</li>
<li>Proxy: support HTTPS managed forward-proxy endpoints and scoped <code>proxy.tls.caFile</code> CA trust for proxy endpoint TLS. (#79171) Thanks @jesse-merhi.</li>
<li>QA-Lab: add first-hour 20-turn and optional 100-turn runtime parity scenarios, with tier metadata for standard and soak QA gates. Fixes #80338; refs #80337. Thanks @100yenadmin.</li>
<li>QA-Lab: add <code>openclaw qa suite --runtime-parity-tier</code> and wire the standard Codex-vs-Pi tier into release checks separately from optional/live-only/soak lanes. Fixes #80337. Thanks @100yenadmin.</li>
<li>QA-Lab: add a live-only Codex Pi-shaped Read vocabulary canary so runtime parity catches native workspace-read prompt compatibility drift. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: add live-only harness self-health scenarios for plugin hook crashes, manifest contract errors, and WebChat direct-reply self-message routing. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: add runtime tool fixture scenarios and coverage reporting for Codex-native workspace tools, OpenClaw dynamic tools, and optional plugin-backed tools. Fixes #80173. Thanks @100yenadmin.</li>
<li>QA-Lab: expose runtime tool fixture coverage through <code>openclaw qa coverage --tools</code>, with optional suite-summary evaluation for parity gate artifacts. Thanks @100yenadmin.</li>
<li>QA-Lab: schedule a live-frontier Codex-vs-Pi runtime token-efficiency artifact lane in the all-lanes QA workflow. Fixes #80175. Thanks @100yenadmin.</li>
<li>QA-Lab: hard-gate required OpenClaw dynamic runtime-tool drift in the standard Codex-vs-Pi tier with a blocking release-check verifier and publish the tool coverage report artifact. Fixes #80339; refs #80319. Thanks @100yenadmin.</li>
<li>QA-Lab: add the personal-agent approval-denial scenario so the benchmark pack verifies denied local reads stop cleanly without tool progress or fixture leaks. (#83150) Thanks @iFiras-Max1.</li>
<li>QA-Lab: extend the personal-agent benchmark pack with a local task followthrough scenario for proof-backed pending, blocked, and done status reporting. Thanks @iFiras-Max1.</li>
<li>QA-Lab: add a report-only dreaming shadow-trial scenario so candidate memory promotion can be evaluated without mutating <code>MEMORY.md</code>. Thanks @iFiras-Max1.</li>
<li>Gateway/performance: add <code>pnpm test:restart:gateway</code> benchmark tooling for repeated restart readiness, downtime, trace, and resource-slope evidence. (#83299) Thanks @samzong.</li>
<li>Android: switch Talk Mode to realtime Gateway relay voice sessions with streaming mic input, realtime audio playback, tool-result bridging, and on-screen transcripts. (#83130) Thanks @sliekens.</li>
<li>Gateway/config: expose config lookup reload metadata so tools can distinguish restart-required, hot-reloadable, and no-op fields before applying config edits. Fixes #81409. (#81612) Thanks @LLagoon3.</li>
<li>Telegram: add allowlisted native DM draft previews for transient tool progress while keeping final answers on the normal persistent delivery path. (#83622) Thanks @akrimm702.</li>
<li>QA-Lab: add a personal-agent share-safe diagnostics artifact scenario so support handoffs keep useful status while omitting raw personal content. Thanks @iFiras-Max1.</li>
<li>QA-Lab: add a personal-agent no-fake-progress scenario so completion claims stay tied to local evidence instead of unsupported external progress. (#83824) Thanks @iFiras-Max1.</li>
<li>Transcripts: add core transcript capture and source-provider support for transcript-backed meeting summaries, including the renamed Transcripts docs, CLI surface, source-provider chunks, and cleaned user-turn persistence.</li>
<li>Auth: add named model login profiles and supported credential migration for Hermes, OpenCode, and Codex auth profiles, with explicit opt-out and non-interactive controls. (#85667) Thanks @fuller-stack-dev.</li>
<li>Diagnostics: trace gateway secret preparation, classify skill/tool usage, surface model stream progress, add OpenTelemetry LLM content spans, and expose alertable telemetry for blocked tools, failover, stale sessions, liveness, oversized payloads, and webhook ingress. (#83019, #80370, #86191)</li>
<li>Channels: add Signal reaction approvals, iMessage thumb approval reactions, and WhatsApp thumb approval reaction support so mobile approval flows work without textual <code>/approve</code> commands. (#85894, #85952, #85477)</li>
<li>Agents/API: forward OpenAI sampling params through the Gateway and expose estimated context-budget status for active agent runs. (#84094)</li>
<li>TUI/status: queue prompts submitted while an agent is busy and show explicit fast-mode state plus richer systemd Gateway hygiene in status output. (#86722, #87115, #86976)</li>
<li>Exec approvals: hide durable approval actions that are unavailable for the current prompt and keep approval runtime tokens local-only so stale prompts cannot offer misleading controls. (#86270, #86359)</li>
<li>Plugin SDK: add reaction approval helpers and keep diagnostic event root exports discoverable across function-name and alias-bound module graphs. (#86735, #87084)</li>
<li>Android/iOS: add the Android pair-new-gateway action and improve mobile Talk mode surfaces, including iOS realtime Talk mode and Android offline voice/gateway recovery. (#86798, #86355) Thanks @ngutman.</li>
<li>Performance: cache plugin metadata snapshots, package realpaths, stable gateway metadata, model cost indexes, channel resolution, usage-cost indexes, and session/auth hot-path facts so common Gateway and reply paths do less rediscovery. (#84649, #85843, #86517, #86678)</li>
<li>Voice: expose shared realtime turn-context tracking through the realtime voice SDK and reuse it for Discord speaker attribution and wake-name context recovery.</li>
<li>Voice: reuse shared realtime output activity tracking in Google Meet command and node audio bridges, including recent-output checks for local barge-in detection.</li>
<li>Voice: expose shared realtime output activity tracking through the realtime voice SDK and reuse it for Discord playback activity and barge-in decisions.</li>
<li>Voice: expose shared realtime consult question matching, speakable-result extraction, and alias-aware forced-consult coordination through the realtime voice SDK, then reuse it in Gateway Talk, Voice Call, and Discord voice paths.</li>
<li>Voice: share activation-name matching and consult-transcript screening through the realtime voice SDK so Discord, browser voice, and meeting surfaces can reuse one implementation.</li>
<li>Cron: default <code>cron.maxConcurrentRuns</code> to 8 so scheduled automations and their isolated agent turns can make progress in parallel without explicit configuration.</li>
<li>QA-Lab: add <code>qa coverage --match <query></code> so focused proof selection can discover matching scenarios from existing metadata before running live or remote lanes.</li>
<li>Discord/model picker: surface an alpha-bucket select (e.g. <code>AG (12) · HN (18) · OZ (5)</code>) when the provider list or a provider's model list exceeds 25 items, so configs with <code>provider/*</code> wildcards stay one click from the right page instead of paginating through prev/next; falls back to numeric chunks when every item shares the same first letter.</li>
<li>Control UI: add an ephemeral Activity tab for sanitized live tool activity summaries without persisting raw telemetry. Fixes #12831. Thanks @BunsDev.</li>
<li>Build: include <code>ui:build</code> in the <code>full</code> and <code>ciArtifacts</code> profiles of <code>scripts/build-all.mjs</code> so <code>pnpm build</code> always rebuilds <code>dist/control-ui</code> after <code>tsdown</code> cleans <code>dist</code>, removing the second-command requirement and the missing-asset failure mode for source/runtime installs and CI artifact uploads. (#85206)</li>
<li>iOS: improve Talk mode with direct realtime voice sessions, compact toolbar status, and responsive voice waveform feedback. (#86355) Thanks @ngutman.</li>
<li>Media: replace the Sharp image backend with Rastermill for metadata, resizing, EXIF orientation, and PNG alpha-preserving optimization so OpenClaw no longer installs Sharp or the WhatsApp Jimp fallback for image processing. (#86437)</li>
<li>Codex: update the bundled Codex CLI to 0.134.0 and keep native compaction disabled for budget-triggered app-server turns so OpenClaw owns the recovery boundary. (#86772)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>CLI: reject explicit port numbers above 65535 before they reach Gateway or Node bind paths. Fixes #83900. (#84008) Thanks @hclsys.</li>
<li>Codex app-server: preserve plugin tool auth profiles when Codex owns model transport so OpenClaw dynamic tools can resolve their provider credentials. (#83603) Thanks @rubencu.</li>
<li>Memory/search: scan the JS-side fallback vector path (used when the sqlite-vec index is unavailable or has a mismatched dimension) in bounded rowid batches and yield to the event loop between batches so large chunk tables can no longer pin the Node.js main thread for multi-second windows. Also keeps the SQL prepared statement rooted in a local so node:sqlite cannot finalize it mid-scan under heap pressure. Fixes #81172. Thanks @dev23xyz-oss.</li>
<li>Memory Wiki: preserve fs-safe diagnostics when bridge source page writes fail for non-symlink filesystem safety reasons, so directory collisions are reported with the underlying error code. (#83776) Thanks @TurboTheTurtle.</li>
<li>Telegram: keep forum topics from blocking sibling topic traffic by routing inbound serialization, media/text buffers, and account API queues on topic-aware lanes. (#83829)</li>
<li>Telegram: keep queued forum-topic follow-up messages from inheriting superseded source abort signals, so later same-topic user turns can still run and reply after an active turn is replaced. (#83827) Thanks @VACInc.</li>
<li>CLI/update: bypass npm freshness filters consistently during managed package and plugin installs so freshly published release plugins remain installable. Thanks @jalehman.</li>
<li>CLI/update: guide root-owned npm install EACCES recovery by stopping the managed Gateway before manual package replacement, then reinstalling and restarting the service. Fixes #83747. (#83757) Thanks @brokemac79.</li>
<li>Twitch: register refreshing chat tokens with Twurple's chat intent so automatic token refresh keeps chat access available. (#83750) Thanks @TurboTheTurtle.</li>
<li>Agents/subagents: keep collect-mode announce queues batching unresolved-origin items with compatible same-route messages and resume collection after a true cross-channel drain when a later compatible batch remains. Fixes #83577.</li>
<li>Skills: refresh existing session skill snapshots when watched skill roots change, so changed extra skill directories take effect without starting a new session. Fixes #83782. (#83800) Thanks @hclsys.</li>
<li>Providers/Anthropic: preserve native image input for current Claude model rows when stale local catalog data marks them text-only. (#83756) Thanks @TurboTheTurtle.</li>
<li>Providers/Anthropic: preserve Claude 4 image capability when configured model refs resolve through a stale local catalog row. (#83756) Thanks @TurboTheTurtle.</li>
<li>Providers/DeepSeek: normalize MCP tool schemas with <code>anyOf</code>/<code>oneOf</code> unions before normal and compaction requests reach DeepSeek, preventing union-shaped parameters from being rejected. (#83766) Thanks @TurboTheTurtle.</li>
<li>Control UI: render live tool progress from session-scoped <code>session.tool</code> Gateway events so externally started runs show their tool cards in the active session. (#83734) Thanks @TurboTheTurtle.</li>
<li>Outbound: resolve send-capable channel plugins from the active runtime registry when the pinned startup registry only has setup metadata. (#83733) Thanks @TurboTheTurtle.</li>
<li>Discord: preserve streamed reply previews when recovered tool-warning finals are delivered before or after the assistant's final reply. (#84169) Thanks @neeravmakwana.</li>
<li>Control UI: keep the chat delete confirmation popover clamped inside the visible viewport on small screens. (#83804) Thanks @ThiagoCAltoe.</li>
<li>Browser: enforce current-tab URL allowlist checks for <code>/act</code> evaluate/batch actions and <code>/highlight</code> routes while leaving tab-management actions unblocked. (#78523)</li>
<li>CI: require real-behavior-proof verdict markers to come from the ClawSweeper GitHub App before accepting exact-head proof. (#83692)</li>
<li>Models: show the effective OpenAI/Codex auth profile in <code>/models</code> provider headers instead of falling back to the OpenAI env-key label. (#83697) Thanks @yu-xin-c.</li>
<li>CLI: include active bundled loopback MCP tools in CLI system prompts and reset provider-side CLI sessions when that prompt-visible tool surface changes. (#83785) Thanks @TurboTheTurtle.</li>
<li>Browser: keep a profile <code>cdpPort</code> when its <code>cdpUrl</code> omits a port, while still letting explicitly written URL ports win. (#82166) Thanks @Marvae.</li>
<li>Agents/image generation: allow distinct <code>image_generate</code> prompts to start separate session-backed background tasks while same-prompt retries still return the active task status. (#83614) Thanks @Elarwei001.</li>
<li>Gateway/WebChat: honor configured <code>channels.webchat.textChunkLimit</code> and <code>chunkMode</code> overrides when chunking WebChat replies. (#83713)</li>
<li>Control UI: stop the chat reading indicator from sticking after an assistant response finishes. (#83515) Thanks @njuboy11.</li>
<li>Skills: reject empty or whitespace-only skill names and descriptions during quick validation. (#27061)</li>
<li>Sessions: skip trailing custom transcript entries when checking tail assistant replies so embedded CLI gap-fill does not duplicate canonical assistant output. (#83635) Thanks @yaoyi1222.</li>
<li>Memory Wiki: keep <code>wiki_lint</code> tool output path-safe by reporting vault-internal lint reports as relative paths in tool text and details while preserving absolute report paths for CLI/file callers. (#83439) Thanks @LLagoon3.</li>
<li>Telegram: keep verbose tool progress visible without mirroring non-final progress into active session transcripts, preventing embedded provider replies from aborting mid-run. (#83631) Thanks @kurplunkin.</li>
<li>Telegram: log successful outbound text and media deliveries with account, chat, message, operation, thread, reply, silent, and chunk metadata while keeping message bodies out of logs. Fixes #83196. (#83247) Thanks @jrwrest.</li>
<li>Cron: link isolated scheduled task runs to their stable cron session so task status and cleanup can follow the backing agent run. (#83606) Thanks @jai.</li>
<li>Codex app-server: mark Codex-native subagent task mirrors terminal when blocked or failed spawn-agent calls arrive with stale initializing child state, preventing task registry entries from staying running. Fixes #83852. (#83945) Thanks @joshavant.</li>
<li>CLI: enforce the documented Node.js 22.19 runtime floor in the source launcher.</li>
<li>Release stability: repair broad-gate regressions in requester-agent completion handoff, QA-Lab mock spawn attribution, Slack monitor test isolation, plugin uninstall peer fixtures, and Node-floor launcher contract coverage.</li>
<li>Agents/replies: persist queued follow-up user messages and assistant error stubs only once across model-fallback retries, preventing repeated provider rejections from corrupted same-role session transcripts. Fixes #83404. (#83417) Thanks @yetval.</li>
<li>Telegram: preserve reply-target context for bare mention replies on runtime-only turns so the model sees the replied-to message body. Fixes #83767. (#83953) Thanks @joshavant.</li>
<li>ClawHub: preserve configured base URL path prefixes when building API request URLs, so self-hosted ClawHub instances mounted under a subpath keep routing correctly. (#83982) Thanks @ThiagoCAltoe.</li>
<li>Slack: persist delivered inbound message IDs and fail closed when same-channel thread replies lose their thread context, preventing delayed duplicate replies and accidental channel-root posts. Fixes #83521. Thanks @shannon0430.</li>
<li>Codex app-server: complete OpenClaw dynamic tool diagnostics at the request boundary so successful, failed, timed out, aborted, and blocked tool calls do not leave active tool state behind. Fixes #83474. Thanks @rozmiarD.</li>
<li>Gateway/config: keep config writes from failing on unrelated unresolved auth-profile SecretRefs while preserving live auth-profile runtime snapshots.</li>
<li>Gateway/sessions: clear stored CLI provider resume bindings on non-subagent <code>/reset</code> so the next turn starts a fresh provider-side CLI conversation instead of resuming old context. (#83448) Thanks @jasonyliu.</li>
<li>Doctor: preserve legacy whole-agent Claude CLI intent by moving matching Anthropic model selections to model-scoped runtime policy before removing stale runtime pins. Fixes #83491. Thanks @danielcrick.</li>
<li>Discord/OpenAI: keep realtime Discord voice sessions hearing follow-up turns with OpenAI realtime and prebuffer assistant playback to avoid choppy starts. (#80505) Thanks @Solvely-Colin.</li>
<li>LM Studio: resolve env-template API keys like <code>${LMSTUDIO_API_KEY}</code> through the standard SecretInput path instead of sending the raw template as the bearer token, and preserve header-auth and discovery-key precedence when the template is unset. Fixes #80495. (#80568) Thanks @MonkeyLeeT.</li>
<li>Discord/subagents: route the initial reply from thread-bound delegated sessions into the bound Discord thread instead of the parent channel. Fixes #83170. (#83172) Thanks @100menotu001.</li>
<li>Gateway/sessions: rotate failed agent sessions when their transcript file is missing instead of wedging per-channel lanes. Fixes #83488. (#83553) Thanks @LLagoon3.</li>
<li>Agents: refresh final-delivery routing from fresh session state before declaring a no-send failure, keeping recovered runs on the normal durable delivery path. (#83835) Thanks @joshavant.</li>
<li>Agents: guard final-delivery fresh session routing against mismatched logical sessions before reusing recovered delivery context. (#83928) Thanks @joshavant.</li>
<li>Media: prevent image metadata probing from invoking external decoder delegates on unrecognized image bytes, and stop fallback chaining after real processing errors.</li>
<li>Media: install Sharp with the root package and fall back to sips, Windows native imaging, ImageMagick, GraphicsMagick, or ffmpeg for image resizing/conversion when Sharp is unavailable. Fixes #83401. Thanks @scotthuang.</li>
<li>Telegram: deliver generated media completions back into forum topics by preserving topic IDs across requester-agent handoff. (#83556) Thanks @fuller-stack-dev.</li>
<li>Gateway: defer update-check startup until after readiness so package update checks no longer block sidecar-ready startup, while preserving update broadcasts and shutdown cleanup. (#83520) Thanks @samzong.</li>
<li>Telegram: keep <code>/btw</code> and read-only status commands from aborting active runs, and avoid retaining raw update payloads in timed-out spool tombstones. Refs #83272.</li>
<li>Agents: log strict-agentic execution contract diagnostics only when the planning-only retry path actually triggers.</li>
<li>Agents: stop embedded session takeover and session write-lock errors from consuming model fallbacks while preserving provider fallback metadata. Fixes #83510. Thanks @luyao618.</li>
<li>Agents/video: hide <code>video_generate</code> reference-audio parameters unless a registered video provider supports audio inputs.</li>
<li>Plugins: fall back to npm for official ClawHub updates when artifact downloads are unavailable, including beta-to-default fallback and dry-run version reporting.</li>
<li>Plugins/xAI: echo PKCE challenge fields during OAuth authorization-code token exchange for xAI token-endpoint compatibility. (#83499) Thanks @fuller-stack-dev.</li>
<li>Codex app-server: hydrate current inbound image attachments before queued runs so Responses-backed agents receive Discord and other channel images as native vision input. Fixes #83466. Thanks @iannwu.</li>
<li>Codex app-server: keep native code mode available without forcing code-mode-only so OpenClaw dynamic tool turns complete through the app-server tool bridge. Fixes #83109. Thanks @daswass.</li>
<li>Codex app-server: expose OpenClaw's sandbox-routed shell as <code>sandbox_exec</code>/<code>sandbox_process</code> for non-Docker sandbox backends so SSH sandbox agents keep a correctly routed shell path without shadowing Codex native shell. Fixes #80322. Thanks @keramblock.</li>
<li>Release stability: recover stale session diagnostics and Codex OAuth fallback state so stuck runs and reused refresh tokens clear without blocking follow-up work. (#83503) Thanks @100yenadmin.</li>
<li>Messages/TTS: apply TTS directives before message-tool sends reach core, gateway, or plugin delivery so opt-in message-tool rooms and proactive sends attach voice notes instead of leaking raw tags. Fixes #81598. Thanks @CG-Intelligence-Agent-Jack and @CoronovirusG10.</li>
<li>Messages/Codex: keep Codex direct/source chats on message-tool visible delivery by default while documenting and testing <code>messages.visibleReplies: "automatic"</code> as the old-mode opt-out; channel wildcard model overrides now apply to direct chats before harness delivery defaults.</li>
<li>Memory/QMD: keep archived session transcript hits visible after QMD export while preserving normal <code>.md</code> session ids that only resemble archive names. (#83518; fixes #83506) Thanks @tanshanshan.</li>
<li>Codex app-server: preserve network access for sandboxed Codex code-mode turns when the OpenClaw sandbox allows outbound egress. Fixes #83347. Thanks @YusukeIt0.</li>
<li>Codex app-server: honor writable Docker bind mounts for sandboxed workspace-write turns while disabling native Code Mode when container-path aliases or read-only bind shadows cannot be represented safely host-side. Fixes #83737. (#83849) Thanks @joshavant.</li>
<li>QA-Lab: keep the OTLP smoke decoder independent of removed OpenTelemetry generated-root internals.</li>
<li>Messages: default group/channel visible replies to automatic final delivery again, keeping <code>message_tool</code> opt-in for ambient/shared rooms and tool-reliable models.</li>
<li>CLI/TUI: force standalone <code>/exit</code> runs to terminate after <code>runTui</code> returns so onboarding-launched TUI children do not stay alive invisibly. (#83501) Thanks @fuller-stack-dev.</li>
<li>Agents/code mode: honor per-agent code-mode config in schema, runtime catalog activation, and model payload filtering. Fixes #83388. Thanks @Kaspre.</li>
<li>Agents/code mode: preserve agent, session, run, and channel context in <code>before_tool_call</code> hooks for top-level <code>exec</code>/<code>wait</code> dispatches. Fixes #83387.</li>
<li>QQBot: shorten C2C typing indicators to a 10-second window renewed every 5 seconds, capped to keep a final passive-reply slot available. (#83469)</li>
<li>Replies: keep final payload delivery after live preview updates so channels can finalize or send the completed answer instead of losing preview-only drafts. (#83468)</li>
<li>Discord: deliver final replies in progress-mode preview streams instead of deduplicating the final visible message. (#83443) Thanks @compoodment.</li>
<li>Providers/Xiaomi: replay MiMo Anthropic-compatible <code>reasoning_content</code> as provider-required thinking blocks even when OpenClaw thinking is disabled, fixing follow-up tool turns for <code>mimo-v2-flash</code>. Fixes #83407. Thanks @Xgenious7.</li>
<li>Agents/exec approvals: forward approval-runtime credentials on agent-owned Gateway approval calls so approved async commands complete through the existing runtime path instead of stalling on unauthenticated follow-up calls. Thanks @IWhatsskill, @Patrick-Erichsen, and @jesse-merhi.</li>
<li>Gateway/skills: preflight remote macOS skill-bin refreshes with a WebSocket connectivity check so stale node sessions skip quickly instead of logging slow <code>system.which</code> timeout warnings.</li>
<li>CLI/config: keep broken discovered plugins that are not referenced by active config from failing <code>openclaw config validate</code>, while preserving fatal errors for explicitly configured plugin entries.</li>
<li>GitHub Copilot: drop unsafe native Responses reasoning replay items with non-replayable IDs before dispatch, preventing affected Copilot sessions from failing with <code>invalid_request_body</code>. Fixes #83220. Thanks @galiniliev.</li>
<li>Agents/Codex: fail closed when an explicitly requested Codex harness is not registered instead of silently trying configured model fallbacks. Fixes #83349. Thanks @r2-vibes.</li>
<li>QA-Lab: make runtime tool coverage fail on missing required tool exercise instead of treating pass/pass parity envelope drift as missing coverage.</li>
<li>Core/plugins: harden clawpatch-reported edge cases across gateway auth cleanup, Claude session id paths, plugin activation policy, apply-patch hunk handling, diagnostic redaction, and plugin metadata validation.</li>
<li>UI: show reasoning choices as plain labels instead of leaking internal override wording in session and chat pickers.</li>
<li>Mac app: avoid repeating the Configuration heading inside channel quick settings.</li>
<li>Mac app: keep the Settings sidebar always visible and remove the redundant titlebar hide/show control.</li>
<li>Mac app: normalize Settings pane content margins so pages share the same left and right rail.</li>
<li>Mac app: prefer explicit private/Tailscale/LAN Gateway endpoints over SSH tunnels, preserve legacy loopback tunnel configs, persist transport choices, and show captured SSH stderr when tunneling really fails.</li>
<li>Gateway/sessions: keep ACP/acpx and runtime child sessions visible in configured-only session lists when their owner or parent session belongs to a configured agent.</li>
<li>Mac app: keep app-level menu commands and Dashboard failure states reachable when the remote Gateway is disconnected.</li>
<li>Mac app: allow longer Gateway and Context errors to wrap in the menu instead of truncating the useful failure detail.</li>
<li>Mac app: tighten remote Gateway fields in Settings so the Connection pane keeps readable labels and full action button text.</li>
<li>Mac app: keep custom Settings card rows left-aligned and full-width so Discovery and status sections no longer appear centered or detached.</li>
<li>Mac app: align Location permission controls to the same trailing column as the rest of Settings.</li>
<li>Mac app: add Dashboard, Chat, Canvas, and Settings shortcuts to the Dock icon menu.</li>
<li>Mac app: replace the Settings window's native split-view sidebar with an explicit layout so page content keeps its leading gutter when the sidebar is shown or hidden.</li>
<li>Mac app: render channel quick config as aligned Settings rows and hide schema-only variants that cannot be edited safely from the quick pane.</li>
<li>Gateway/webchat: hide internal runtime-context and other <code>display: false</code> transcript messages from Chat history and live message events. Fixes #83216. Thanks @EmpireCreator.</li>
<li>CLI/help: keep <code>gateway</code>, <code>doctor</code>, <code>status</code>, and <code>health</code> help registration out of action/runtime imports so subcommand <code>--help</code> stays lightweight in constrained terminals. Fixes #83228. Thanks @dfguerrerom.</li>
<li>CLI/help: show plugin-owned command help based on the active memory slot so LanceDB memory users see <code>ltm</code> instead of unavailable <code>memory</code> commands. Fixes #83745. (#83841) Thanks @joshavant.</li>
<li>Cron/Discord: keep explicit announce runs in message-tool-only source-reply mode so scheduled agent turns post once instead of also echoing through automatic visible replies. Fixes #83261. Thanks @Theralley.</li>
<li>Telegram: preserve forum-topic origin targets in inbound, audio-preflight, and skipped-message hook contexts so follow-up delivery stays bound to the originating topic. Fixes #83302. Thanks @M00zyx.</li>
<li>Telegram: retry HTTP 421 Misdirected Request send failures on a fresh fallback transport so transient edge-node routing errors no longer drop outbound replies. Fixes #48892. (#48908) Thanks @MarsDoge.</li>
<li>Telegram: fail topic sends closed when Telegram reports <code>message thread not found</code> instead of retrying without <code>message_thread_id</code> into the base chat. Refs #83302.</li>
<li>Config/subagents: remove ignored agent-model <code>timeoutMs</code> keys, keep subagent model config to primary/fallback selection, and clean shipped stale config through doctor. Fixes #83291. Thanks @giodl73-repo.</li>
<li>Mac app: align the Sessions settings pane with the standard Settings page gutter and row spacing.</li>
<li>OpenAI/Codex: stop rejecting available <code>openai-codex</code> GPT-5.1, GPT-5.2, and GPT-5.3 model refs during config validation, while keeping removed Spark aliases suppressed. Fixes #83303.</li>
<li>Plugins/xAI: complete OAuth-backed xAI login and sidecar auth fixes, including guarded loopback callback CORS handling, video generation polling/defaults, and native-host User-Agent attribution. (#83322) Thanks @Jaaneek.</li>
<li>Codex app-server: preserve streamed native command output in mirrored transcripts and trajectory exports when final snapshots omit aggregated output. (#83200) Thanks @rozmiarD.</li>
<li>Codex app-server: fail closed when chat or sender policy denies tools, disabling native code, app, environment, and user MCP surfaces for restricted turns. (#82374) Thanks @VACInc.</li>
<li>Codex app-server: keep recent context-engine messages when oversized projected history is truncated, so short follow-ups in long channel sessions do not fall back to stale earlier turns. (#83127) Thanks @VACInc.</li>
<li>Codex app-server: keep OpenClaw session spawning searchable while steering Codex-native delegation through native subagents, avoiding duplicate direct subagent surfaces. (#83329) Thanks @fuller-stack-dev.</li>
<li>Codex app-server: recover stale childless Codex-native subagent task mirrors during maintenance and allow their registry rows to be cancelled without an OpenClaw child session. (#82836) Thanks @yshimadahrs-ship-it and @joshavant.</li>
<li>Feishu: return bound subagent delivery origins from session thread setup so Feishu subagent completions route back to the same DM or topic. (#83190) Thanks @100menotu001.</li>
<li>CLI/update: tailor post-update Gateway recovery hints by platform, showing systemd, LaunchAgent, Scheduled Task, or generic service-manager guidance instead of macOS-only recovery text. (#83096) Thanks @rubencu.</li>
<li>Plugins: apply a default 15-second timeout to legacy <code>before_agent_start</code> hooks so hung plugin handlers no longer block agent startup. Fixes #48534. (#83136) Thanks @therahul-yo.</li>
<li>Feishu: refresh inbound session delivery context for DM, group, and broadcast turns so later replies do not inherit stale WebChat routing. Fixes #78274.</li>
<li>Agents/subagents: require the initial subagent registry save before reporting spawn accepted, returning a spawn error instead of losing an untracked run when the registry write fails. (#83146) Thanks @yetval.</li>
<li>QA-Lab/qa-channel: attach redacted agent tool-start traces to outbound <code>QaBusMessage</code> records so scenarios can assert actual tool use instead of relying only on reply text. Fixes #67637. Thanks @100yenadmin.</li>
<li>QA-Lab: fail live runtime parity reports when assistant-message usage is missing, preventing <code>0 vs 0</code> live token rows from being reported as passing proof. Fixes #80411. Thanks @100yenadmin.</li>
<li>QA-Lab: add a runtime token-efficiency sidecar report that classifies Codex savings separately from regressions and fails only positive Codex-over-Pi live token deltas above threshold. Fixes #81093. Thanks @100yenadmin.</li>
<li>QA-Lab: fail Codex-backed OpenAI live runtime-pair runs before launching isolated workers when no portable Codex auth is available, while staging API-key fallbacks and configured Codex keys for isolated QA agents. Fixes #80412. Thanks @100yenadmin.</li>
<li>QA-Lab: refresh parity gates, mock frontier fixtures, model scenarios, and workflow artifact lanes to compare GPT-5.5 against Claude Opus 4.7. Fixes #74262. Thanks @100yenadmin.</li>
<li>QA-Lab: make mock parity dispatch provider-aware for source discovery and subagent scenarios so OpenAI and Anthropic lanes no longer share identical canned plans. Fixes #64879. Thanks @100yenadmin.</li>
<li>QA-Lab: stop returning Control UI bearer tokens from unauthenticated bootstrap payloads and bind Docker harness ports to loopback-only host addresses. (#66355) Thanks @pgondhi987.</li>
<li>Mac app: avoid a SwiftUI metadata crash when rendering the Cron Jobs settings pane.</li>
<li>Agents/subagents: preserve run-mode keep subagent registry entries past the session sweep TTL, so kept subagent runs remain visible after cleanup completes. Fixes #83132. (#83168) Thanks @yetval.</li>
<li>Agents/OpenAI streams: yield via <code>setTimeout(0)</code> instead of <code>setImmediate</code> between bursty Responses chunks so abort timers can fire during the yield, keeping cancel-on-timeout responsive on hot streams. Refs #82462.</li>
<li>Agents/Codex: keep legacy <code>oauthRef</code>-backed OAuth profiles usable while <code>openclaw doctor --fix</code> migrates them back to inline credentials, without creating new sidecar credentials. (#83312) Thanks @joshavant.</li>
<li>Agents/Codex: load the selected provider owner alongside the Codex harness runtime so <code>openai-codex</code> models resolve when plugin allowlists scope runtime loading. Fixes #83380. (#83519) Thanks @joshavant.</li>
<li>Telegram: fail stalled isolated-ingress handlers into tombstones and abort same-lane reply work before restarting, so later same-chat updates drain after a hung turn. Fixes #83272. (#83505) Thanks @joshavant.</li>
<li>CLI/config: send SecretRef diagnostics to stderr so JSON command stdout remains parseable.</li>
<li>CLI/doctor: seed Control UI allowed origins when migrating legacy non-loopback gateway bind host aliases like <code>0.0.0.0</code>. Fixes #83286. Thanks @giodl73-repo.</li>
<li>CLI/plugins: ship the bundled memory CLI as a package entry so package-installed <code>openclaw memory</code> commands register correctly.</li>
<li>CLI/update: defer doctor-time plugin package installs during package swaps and seed post-core repair from the updated install registry, preventing duplicate reinstall failures.</li>
<li>CLI/update: preserve old-parent-readable config metadata during legacy package handoffs, fall back only to official <code>@openclaw/*</code> npm plugin packages when ClawHub plugin artifacts are unavailable, and keep managed service package roots authoritative during updates.</li>
<li>Feishu: detect SecretRef top-level credentials as a configured default account instead of treating object-backed app secrets as missing.</li>
<li>Gateway/restart: keep ordinary unmanaged SIGUSR1/config restarts in-process instead of detach-spawning an orphaned child, preserving custom supervisor PID tracking while leaving update restarts on the fresh-process path. Fixes #65668.</li>
<li>CLI/completion: resolve concrete PowerShell profile paths and reload commands during setup and doctor completion installation. Fixes #44296. (#83059) Thanks @yu-xin-c.</li>
<li>Telegram: keep isolated long polling below the hard <code>getUpdates</code> request guard so idle bot accounts with high <code>timeoutSeconds</code> do not false-disconnect and restart-loop. Fixes #83264. Thanks @riccodecarvalho.</li>
<li>Providers/Google: preserve and recover Gemini 3 tool-call thought signatures during native replay so function-calling turns no longer fail with missing <code>thought_signature</code> 400s. Fixes #72879. (#80358) Thanks @abnershang.</li>
<li>Telegram: skip transcript-only delivery mirrors and gateway-injected rows when resolving latest assistant text, preventing retained previews from replacing final replies with stale fragments. Fixes #83159. (#83362) Thanks @joshavant.</li>
<li>Memory/QMD: keep lexical search on raw hyphenated queries while normalizing semantic QMD sub-searches, avoiding fallback to the builtin index for dashed identifiers and dates. Fixes #81328.</li>
<li>Memory-core: distinguish sqlite-vec load failures from missing semantic vector embeddings in degraded <code>memory index</code> warnings, so vector recall diagnostics point at unresolved dimensions instead of blaming sqlite-vec when the store is ready. Fixes #75624. (#83056) Thanks @xuruiray and @Noah3521.</li>
<li>Agents/subagents: preserve sandbox-peer controller ownership while routing completion announcements back to the originating run session, keeping subagent control and completion delivery scoped correctly. Fixes #80201. (#80242) Thanks @Jerry-Xin.</li>
<li>Gateway: continue restarting remaining channels when one hot-reload channel restart fails, while still reporting aggregate reload failure and rolling back plugin pre-replace stops. Fixes #83054. Thanks @zqchris.</li>
<li>Gateway/plugins: bind admin HTTP RPC dispatch to the accepting gateway instance so multi-gateway processes cannot execute plugin HTTP control-plane calls against another live gateway. Fixes #83486. (#83487) Thanks @coygeek.</li>
<li>Telegram: keep hot-reload restarts from marking polling accounts manually stopped and restart isolated ingress cleanly after worker shutdown, preserving Telegram replies across config reloads. Fixes #83008. (#83410) Thanks @joshavant.</li>
<li>Telegram/Ollama: pass current Telegram image attachments into native PI/Ollama vision turns so live photo prompts reach Ollama as native images. Fixes #83023. (#83516) Thanks @joshavant.</li>
<li>Gateway/secrets: split the lightweight secrets runtime state and auth-store cache from the full secrets runtime and take a startup fast path when the gateway startup config has no SecretRef values, speeding up secrets startup while preserving cleanup and refresh semantics.</li>
<li>Codex app-server: rotate oversized native Codex threads before resume and cap dynamic tool-result text entering native Codex sessions, preventing stale oversized context from surviving OpenClaw compaction. (#82981) Thanks @hansolo949.</li>
<li>Gateway/restart: drain pending replies and active chat runs during restart shutdown before sockets and channels close, aborting timed-out chat runs through the normal cleanup path. (#69121) Thanks @alexlomt.</li>
<li>Agents/Codex: use the Codex runtime context window for OpenAI-model preflight compaction and memory flush checks, so GPT-5.5 Codex sessions compact before hitting the smaller native context limit. Fixes #82982. Thanks @vliuyt.</li>
<li>QA-Lab: clean orphaned gateway temp roots when a suite parent exits and wait on gateway plus transport readiness after config restarts, reducing stale <code>qa-channel</code> noise from interrupted runs. Fixes #65506. Thanks @100yenadmin.</li>
<li>QA-Lab: wake qa-bus long polls that arrive with stale future cursors after a bus restart, preserving reconnect readiness for harness clients. (#67142) Thanks @hxy91819.</li>
<li>QA-Lab: stage Multipass transfer scripts under OpenClaw's preferred temp root instead of raw OS temp paths, keeping the VM runner inside temp-path guardrails. (#64098) Thanks @ImLukeF.</li>
<li>Agents/replies: keep surviving reply media and append a warning when other media references fail, so partial media normalization no longer drops failures silently. Thanks @Jerry-Xin.</li>
<li>Config/models: accept <code>thinkingFormat: "together"</code> in model compat config so Together routes can opt into the Together-specific thinking response shape.</li>
<li>Plugins/tokenjuice: bump the bundled tokenjuice runtime to 0.7.1, bringing Codex hook approval compatibility, pre-tool command wrapping fixes, and Rolldown/Vitest output compaction improvements into the OpenClaw plugin.</li>
<li>Agents/OpenAI: stop post-processing GPT-5 final replies with hardcoded brevity caps, preserving full channel responses instead of appending synthetic ellipses, and log when strict-agentic GPT-5 execution activates. Fixes #82910.</li>
<li>Mac app: refine the Settings General and Connection panes with cleaner status panels, card rows, and a single native titlebar sidebar toggle.</li>
<li>Agents/media: deliver failed async image, music, and video generation completions directly when requester-session completion handoff fails, so channel users see provider errors instead of silent fallback stalls.</li>
<li>Browser/CDP: keep loopback proxy bypass active across both <code>NO_PROXY</code> casings and redact home-relative Chrome MCP profile paths in attach-failure diagnostics.</li>
<li>Agents/music: steer song, jingle, beat, anthem, and instrumental requests toward <code>music_generate</code> audio creation instead of lyric-only replies, and reserve <code>lyrics</code> for exact sung words.</li>
<li>Codex app-server: record native Codex tool calls and results into trajectory artifacts so debug/trajectory exports capture the full Codex-native tool history, not just OpenClaw-bridged turns. Thanks @vyctorbrzezowski.</li>
<li>Codex/app-server: keep bound conversation sessions on the owning agent runtime so native Codex control and follow-up turns do not fall back to the default agent client. Fixes #82954. (#82993)</li>
<li>CLI/infer: run gateway model probes in fresh explicit sessions so one-shot provider checks do not inherit default agent transcript state. (#82861) Thanks @Kaspre.</li>
<li>Providers/Together: send video-generation requests to Together's v2 video API even when shared text-model config still points at the v1 base URL. (#82992)</li>
<li>Browser CLI: preserve browser-level options on nested commands, skip option values during lazy command registration, and keep long-running wait/download/dialog hooks open for their advertised wait window.</li>
<li>CLI/sessions: accept <code>openclaw sessions list</code> as an alias for <code>openclaw sessions</code>, matching other list-style commands. Fixes #81139. (#81163) Thanks @YB0y.</li>
<li>Channels/stream previews: widen compact progress draft lines and cut prose at word boundaries while preserving command/path suffixes, with <code>streaming.progress.maxLineChars</code> for channel-specific tuning.</li>
<li>CLI/plugins: have <code>openclaw plugins doctor</code> warn when a configured runtime needs a missing owner plugin, sharing the same install mapping as <code>openclaw doctor --fix</code>. Fixes #81326. (#81674) Thanks @Zavianx.</li>
<li>Agents/Codex: route OpenAI runs that resolve to <code>openai-codex</code> through the Codex provider and bootstrap OpenClaw's stored OAuth profile into the Codex harness when the harness owns transport, so <code>openai/*</code> model refs no longer fail with <code>No API key found for openai-codex</code> despite an existing Codex OAuth profile. (#82864) Thanks @ragesaq.</li>
<li>Agents/ACP: distinguish prompt-submitted and runtime-active child stalls from true interactive waits, including redacted proxy-env diagnostics for Codex ACP no-output runs. Fixes #44810.</li>
<li>Agents/memory: explain that memory-triggered compaction exposes only <code>read</code> and append-only <code>write</code> when configured core tools are unavailable in <code>tools.allow</code> warnings. Fixes #82941. Thanks @galiniliev.</li>
<li>Agents/OpenAI: preserve deterministic tool payload ordering for prompt-cache reuse across OpenAI Responses and chat completions calls. (#82940) Thanks @galiniliev.</li>
<li>ACP/Codex: honor terminal ACP turn results so failed Codex/acpx runs are not recorded as successful after only progress text. Fixes #79522. Thanks @dudaefj.</li>
<li>Telegram: warn when a media group drops photos that fail to download, including albums where every photo is skipped. Fixes #55216. (#82987) Thanks @eldar702.</li>
<li>Agents/diagnostics: treat repeated same-handle embedded-run cleanup as idempotent while preserving true replacement-handle mismatch diagnostics. Fixes #82959. (#82960) Thanks @galiniliev.</li>
<li>Agents/subagents: preserve high-priority <code>AGENTS.md</code> policy in bootstrap context when oversized files are trimmed, and warn agents to read the full policy file before relying on scoped rules. Fixes #82920. (#82921) Thanks @galiniliev.</li>
<li>Agents/skills: apply the full effective tool policy pipeline to inline <code>command-dispatch: tool</code> skill dispatch before owner-only filtering, preserving configured allow, deny, sandbox, sender, group, and subagent restrictions. (#78525)</li>
<li>Codex: avoid spawning native hook relay subprocesses for post-tool/finalize events with no registered hook handlers while preserving pre-tool safety and approval relays. Fixes #76552. (#78004) Thanks @evgyur.</li>
<li>Channel accounts: keep top-level default channel accounts visible when named accounts are added alongside default credential material, so mixed legacy/new account configs keep resolving <code>default</code> instead of silently dropping it.</li>
<li>Agents/CLI: reject empty successful CLI subprocess replies as <code>empty_response</code> and keep them out of shared auth-profile health, so blank Claude CLI results no longer become green no-payload turns. Fixes #83231. (#83421) Thanks @joshavant.</li>
<li>Codex/Telegram: synthesize native Codex tool progress from final turn snapshots so Telegram <code>/verbose</code> stays visible when command events arrive only at completion.</li>
<li>Codex/Telegram: deliver Codex verbose tool summaries in direct message-tool-only turns while suppressing message-send and activity-log noise. (#83186) Thanks @kurplunkin.</li>
<li>Mac app: make Channels settings open faster by deferring config-schema work, avoiding startup channel probes, caching decoded channel status rows, and showing only compact quick settings instead of the full generated channel schema.</li>
<li>Control UI: include the Control UI and Gateway protocol versions in protocol-mismatch errors so stale app/dashboard pairings identify which side needs rebuilding or restarting.</li>
<li>Gateway/protocol: restore Gateway WS protocol v4 and keep <code>message.action</code> room-event metadata on the existing <code>inboundTurnKind</code> wire field while preserving internal inbound-event classification.</li>
<li>Agents/tools: prefer non-webchat session-key routes when the message tool has stale webchat context, so message-tool-only replies keep delivering to the originating channel. Fixes #82911. (#83004) Thanks @joshavant.</li>
<li>Channels: keep direct-message last-route writes on isolated <code>per-channel-peer</code> sessions instead of contaminating the agent main session with channel delivery context. Fixes #36614. Thanks @aspenas.</li>
<li>Mac app: move the Settings sidebar toggle into the native titlebar and tighten the General pane width.</li>
<li>Mac app: keep visited Settings panes mounted so switching tabs no longer blanks and reloads their content.</li>
<li>Mac app: make Config settings open from shallow schema lookups and load selected paths on demand instead of fetching and rendering the full generated config schema up front.</li>
<li>Codex: sanitize inline image payloads before Codex app-server and OpenAI Responses replay, and clear poisoned Codex thread bindings after invalid image errors. Fixes #82878.</li>
<li>Providers/GitHub Copilot: request identity-encoded Copilot API responses across token exchange, catalog, model calls, usage, and embeddings so compressed Business-account error payloads no longer reach JSON parsers as gzip bytes. Fixes #82871. Thanks @tonyfe01.</li>
<li>Telegram: redact nested raw-update identifiers and user metadata before verbose raw update logging, preserving useful update/message ids without exposing chat, user, command, or profile details. (#82945) Thanks @galiniliev and @joshavant.</li>
<li>Telegram: preserve replied-to bot messages, captions, and media metadata in group reply chains so follow-up replies understand what the user is reacting to. (#82863)</li>
<li>Providers/Together: update PI runtime packages to 0.74.1 and emit Together-style <code>reasoning.enabled</code>/<code>max_tokens</code> controls for reasoning-capable OpenAI-completions models.</li>
<li>Agents/diagnostics: split slow embedded-run <code>attempt-dispatch</code> startup summaries into workspace, prompt, runtime-plan, and final dispatch subspans so traces identify the delayed setup phase. Fixes #82782. (#82783) Thanks @galiniliev.</li>
<li>Agents/Codex: flatten nested tool-result middleware blocks into bounded text so successful message sends are no longer replaced with <code>Tool output unavailable due to post-processing error</code>. Fixes #82912. Thanks @joeykrug.</li>
<li>CLI/media: accept HTTP(S) URLs in <code>openclaw infer image describe --file</code>, fetching remote images through the guarded media path instead of treating URLs as local files. Fixes #82837. (#82854) Thanks @neeravmakwana.</li>
<li>Agents/subagents: keep session-backed parent runs active when the child wait call times out before the child session has actually settled, so late subagent completions are reconciled instead of being lost. Fixes #82787. Thanks @ramitrkar-hash.</li>
<li>Control UI: advertise shared Gateway protocol constants in browser connect frames, fixing protocol mismatch handshakes after protocol constant drift. Fixes #82882. Thanks @galiniliev.</li>
<li>Gateway: add rollback protocol-mismatch diagnostics, including client protocol ranges in Gateway logs and deep status/doctor hints for stale client processes. Fixes #82841. (#82908)</li>
<li>Agents/subagents: keep successful keep-mode completion payloads pending after final-delivery retry exhaustion, so requester recovery no longer loses final subagent results. Fixes #82583. (#82999) Thanks @joshavant.</li>
<li>Gateway/auth: allow same-host trusted-proxy callers to use the documented local direct <code>gateway.auth.password</code> fallback after revisiting the #78684 fail-closed policy, while keeping token fallback rejected and forwarded-header requests on the trusted-proxy path. Fixes #82607. (#82953) Thanks @joshavant.</li>
<li>Agents/subagents: wait for queued completion handoffs to reach the parent transcript before marking them announced, preventing busy parent runs from cleaning up before observing child results. Fixes #82913. (#83039) Thanks @joshavant.</li>
<li>Agents/subagents: route group/channel subagent completions through message-tool-only handoffs when required and keep active-requester wake failures from dropping completion delivery. Fixes #82803. Thanks @galiniliev, @yozakura-ava, and @moeedahmed.</li>
<li>Memory-core: scan persisted memory source sessions on startup, comparing on-disk transcripts against the index and marking only missing/newer/resized files dirty for incremental sync. Fixes #82341. (#82341) Thanks @giodl73-repo.</li>
<li>Telegram: keep the top-level default account in the account list when named accounts or bindings are added alongside top-level credentials, preserving default polling while still letting named-only configs resolve to a single account. Fixes #82794. (#82794) Thanks @giodl73-repo.</li>
<li>CLI/models: reuse command-scoped plugin metadata across model listing, provider catalog, auth, and synthetic-auth checks, restoring fast <code>openclaw models</code> runs for plugin-heavy installs. Fixes #82881. (#83033) Thanks @joshavant.</li>
<li>CLI/channels: show configured official external channels such as Discord in <code>openclaw channels list</code> when their plugin package is missing, including the install and doctor repair command instead of reporting no configured channels. Fixes #82813.</li>
<li>Signal: preserve mixed-case group IDs through routing and session persistence so group auto-replies keep delivering after updates. Fixes #82827.</li>
<li>Agents/tools: keep the <code>message</code> tool available in embedded runs when it is explicitly allowed through <code>tools.alsoAllow</code> or runtime tool allowlists, so channel plugins with custom reply delivery can still use configured message sends. Fixes #82833. Thanks @cn1313113.</li>
<li>WhatsApp: honor forced document delivery for outbound image, GIF, and video media so <code>forceDocument</code>/<code>asDocument</code> sends preserve original media bytes instead of using compressed media payloads. (#79272) Thanks @itsuzef.</li>
<li>WhatsApp: name outbound document attachments from their MIME type when no filename is provided, so PDF and CSV sends arrive as <code>file.pdf</code> and <code>file.csv</code> instead of an extensionless <code>file</code>. Thanks @mcaxtr.</li>
<li>Process/diagnostics: report active lane blockers in lane wait warnings so <code>queueAhead=0</code> no longer hides commands waiting behind active work. Fixes #82791. (#82792) Thanks @galiniliev.</li>
<li>Process/diagnostics: stop counting the active processing turn as queued backlog in liveness warnings so transient max-only event-loop spikes do not surface as gateway warnings.</li>
<li>Agents/replies: classify provider conversation-state rejections and return a clear message-channel error instead of auto-resetting or falling back to a generic runner failure. (#82616) Thanks @dutifulbob.</li>
<li>Browser plugin: trust managed Chrome CDP diagnostics when launch HTTP probes race cold-start readiness, avoiding false startup failures. Fixes #82904. (#82986) Thanks @kmanan and @hclsys.</li>
<li>Android: prompt before replacing a changed Gateway TLS thumbprint, showing the old and new SHA-256 fingerprints so users can accept expected certificate rotations instead of hard failing on pin mismatch. (#83077) Thanks @sliekens.</li>
<li>CLI/status: render extra gateway-like service diagnostics as warning/info output instead of error output. Fixes #46930. (#82922) thanks @giodl73-repo.</li>
<li>Agents/failover: classify Moonshot/Kimi exhausted-balance HTTP 429 payloads as billing instead of generic rate limits, preserving billing guidance and fallback behavior. Fixes #43447. (#83079) Thanks @leno23.</li>
<li>Plugin SDK: bundle <code>openclaw/plugin-sdk/zod</code> into the published package artifact and verify the packed zod subpath stays self-contained, so pnpm global installs can register plugins without a package-local <code>zod</code> symlink. Fixes #78398. (#78515) Thanks @ggzeng.</li>
<li>Providers/Google: drop compaction-truncated Gemini thought signatures before replay so malformed Base64 no longer aborts the next assistant turn. (#82995) Thanks @wAngByg.</li>
<li>Gateway/mobile: allow paired iOS and Android clients to refresh same-family OS metadata on authenticated reconnect instead of requiring a new approval. (#83490) Thanks @ngutman.</li>
<li>WhatsApp: treat <code>upload-file</code> as a supported media send intent by lowering path/URL uploads through the channel's normal send-media transport. (#81883) Thanks @ngutman.</li>
<li>iOS: end Live Activities when OpenClaw is connected, idle, or disconnected, and show compact attention states for approval-required reconnects. (#83597) Thanks @ngutman.</li>
<li>Control UI: hide child nav items when collapsing the active sidebar group. Fixes #42167. (#42223) Thanks @Aroool.</li>
<li>CI/proof: skip the real-behavior-proof gate for private org maintainers by minting a least-privilege (<code>members: read</code>) GitHub App token and checking active membership in the <code>maintainer</code> team, instead of treating <code>author_association=CONTRIBUTOR</code> as definitively external. (#83418) Thanks @romneyda.</li>
<li>Memory/security: reject prompt-like text submitted through the explicit <code>memory_store</code> tool before embedding or storage, matching the existing auto-capture prompt-injection filter. (#87142)</li>
<li>Gateway/security: enable the default auth rate limiter for remote non-browser and HTTP gateway auth failures when <code>gateway.auth.rateLimit</code> is unset, while preserving the loopback exemption. (#87148)</li>
<li>Security/content boundaries: validate Browser snapshot tab URLs against SSRF policy before ChromeMCP or direct CDP reads, sanitize queued system-event text so untrusted plugin/channel labels cannot spoof nested prompt markers, wrap fetched file text and metadata as external content, apply ClickClack <code>allowFrom</code> sender allowlists before agent dispatch, reject RPCs from invalidated device-token clients during rotation, require staged sandbox media refs, and scrub serialized tool-call text from replies. (#78526, #87094, #87062, #83741, #70707, #86924) Thanks @zsxsoft, @ttzero25, and @mmaps.</li>
<li>Transcripts/user turns: persist CLI, WebChat, media, follow-up, hook, and Codex-mirror user turns to the admitted session target; keep cleaned transcript text, inline image routing, provenance metadata, replay hooks, and fallback paths idempotent when runtimes fail or restart.</li>
<li>TUI/status/onboarding/UI: queue busy TUI prompts instead of dropping them, preserve the configured default model during onboarding, show failed tool results as errors, show config-open failures in Control UI, keep status JSON plugin scans healthy, preserve xAI usage-limit errors locally, and expose explicit fast-mode/systemd state. (#86722, #87000, #85786, #87108, #87001, #86614, #87115, #86976)</li>
<li>Plugin commands/SDK: preserve plugin LLM command auth, bind native plugin command dispatch to the host agent's LLM auth, keep <code>onDiagnosticEvent</code> exports discoverable through <code>Function.name</code>, stabilize diagnostic event root aliases, correlate pathless read diagnostics, suppress transient runner failures in channel command paths, and repair local approval resolution. (#85936, #87084, #86977, #87069, #86771)</li>
<li>Codex/providers: keep WebChat delivery hints out of user prompts, avoid false queued-terminal idle timeouts, share the native hook relay registry, quarantine unsupported dynamic tool schemas, preserve Claude resumed-session system prompts, normalize greedy Ollama <code>top_p</code>, preserve per-agent thinking defaults for ingress runs, and avoid native compaction takeover on budget-triggered Codex turns. (#87096, #73950, #87049, #86689, #86772)</li>
<li>Gateway/perf/release: reuse startup-warning metadata and prepared auth stores, avoid cloning live-switch and lifecycle session caches on read paths, defer warning and scheduled-service fallback imports, trim Gateway session/startup/runtime CPU churn, skip duplicate turn session touches, stop chat timeout fallback cascades, drop stale subagent announce history, bound benchmark/watch/kitchen-sink teardown waits, bound macOS/package/onboarding/plugin smoke commands, bound install finalization probes, resolve Parallels npm-update commands from guest <code>PATH</code>, and bootstrap raw AWS macOS Node/pnpm commands through <code>/usr/bin/env</code>. (#86997)</li>
<li>Reply/perf: reduce visible reply delivery latency by preserving Telegram typing/progress context, lazy-loading slash-command startup metadata, avoiding hot-path model hydration, flag-gating Codex profiler timing, deferring context compaction maintenance, and tracking delivery timing. (#86989, #86990, #86991, #86992, #86993, #86994) Thanks @keshavbotagent.</li>
<li>Reply/source delivery: keep TUI, Control UI, media, TTS, transcript, and Codex source-reply finals live without duplicate terminal events or stale replay artifacts.</li>
<li>Agents/replay: repair legacy tool results before replay, preserve <code>sessions_spawn</code> transcript payloads, restore current guard checks, stage sandboxed workspace media, and keep duplicate transcripts tool display metadata from reappearing. (#82203, #86934, #87025) Thanks @martingarramon, @vincentkoc, and @joshavant.</li>
<li>Agents/sessions: handle active-fallback failures in <code>sessions_send</code> so fallback routing reports the real failure and does not leave callers with an ambiguous dropped send. (#86638)</li>
<li>Agents/hooks/subagents: enforce default hook agent allowlists, recover failed subagent lifecycle completions, and keep node task lifecycle cleanup from closing the Gateway listener. (#86101)</li>
<li>Codex: project newer OpenClaw chat history into resumed app-server threads and keep Codex turn timeouts inside the Codex runtime boundary so timeouts do not poison shared app-server clients or fall through to unrelated provider fallback. (#86677, #86476) Thanks @TurboTheTurtle and @pashpashpash.</li>
<li>Config/doctor/update: narrow profiled tool-section doctor repair, keep runtime-injected legacy web-search provider config out of user-authored config validation, and keep prerelease tags excluded from stable updater resolution. (#87030, #86818, #86559) Thanks @joshavant, @luoyanglang, and @stevenepalmer.</li>
<li>CLI/Windows: add a Windows-only stack-size respawn for stack-heavy startup paths, default CLI logs to local timestamps, and validate timeout/banner TTY state more strictly. (#87031, #85387) Thanks @giodl73-repo and @vincentkoc.</li>
<li>Locking/security: require owner identity proof before stale plugin lock removal, memoize session lock owner arguments, and avoid writing default exec approval stores unless policy state actually changed. (#86814, #86964) Thanks @Alix-007 and @vincentkoc.</li>
<li>Install/release: bound Docker package build, inventory, pack, and tarball preparation with process-group timeouts; pin shrinkwrap patch drift to the pnpm lock; harden macOS restart and dSYM packaging; and run release Docker/live timeout wrappers in the foreground so child processes cannot wedge gates.</li>
<li>Telegram/network: treat <code>ENETDOWN</code> as a transient pre-connect network failure so Telegram sends, gateway unhandled-rejection handling, and cron network retries follow the same recovery path as sibling network outages. (#86762) Thanks @TurboTheTurtle.</li>
<li>Telegram: preserve inbound text entities, overlapping DM replies, account topic cache sidecars, outbound reply context, targeted bot-command mentions, durable group retry targets, forum topic names, and native progress callbacks. (#83873, #85361, #85555, #85656, #85709, #86299, #86553) Thanks @SebTardif, @luoyanglang, and @neeravmakwana.</li>
<li>iMessage: read image attachments from local Messages attachment roots, dedupe duplicate local Messages-source accounts, seed direct DM history, fix image/group media attachment commands, advance catchup cursors after live handling, and keep slash-command acknowledgements in the source conversation. (#82642, #85475, #86569, #86705, #86706, #86770) Thanks @homer-byte, @TurboTheTurtle, @swang430, and @OmarShahine.</li>
<li>WhatsApp/QQ/Twitch/IRC/Slack: restore WhatsApp ack identity and group-drop warnings, make QQ Bot media respect <code>OPENCLAW_HOME</code>, serialize Twitch auth disconnects, store IRC channel routes canonically, and keep Slack downloaded files out of reply media. (#83833, #85309, #85777, #85794, #85906, #86318, #86697) Thanks @sliverp, @neeravmakwana, and @Kailigithub.</li>
<li>Discord/voice: improve voice playback and wake replies, bucket large model picker menus, merge media captions into one message, route metadata through configured proxies, restore numeric channel sends, suppress self-reply echoes, and tighten wake matching without breaking fuzzy wake phrases. (#80227, #86238, #86487, #86571, #86595, #86601)</li>
<li>Codex: preserve native web-search metadata, keep oversized native thread reuse, bridge CLI API-key auth into the app server, preserve sandbox bootstrap path style, recover context-window prompt errors, honor yolo approval policy, disable native thread personality, and route compaction through Codex auth. (#85378, #85542, #85891, #85909, #86408)</li>
<li>Agents/runtime: enforce session lock max-hold reclaim, release embedded-attempt locks on all exits, treat aborted subagent runs as terminal, avoid runtime model hydration on hot paths, disclose scoped session list counts, derive overflow budgets from provider errors, and keep fallback errors scoped to the active model candidate. (#70473, #85764, #86014, #86134, #86427, #86944) Thanks @openperf, @fuller-stack-dev, @zhangguiping-xydt, and @ferminquant.</li>
<li>Config/update/doctor: retry config recovery after failed backup restore, skip shell env fallback on Windows, exclude prerelease tags from the stable git channel, support deep config edits, warn instead of aborting on unreadable cron stores, prune stale bundled plugin paths, and avoid duplicate restart prompts when the Gateway is already healthy. (#85739, #85787, #86060, #86260, #86384, #86533) Thanks @liaoyl830.</li>
<li>Install/release: support Alpine CLI installs and runtime floors, prefer trusted startup argv runtime fallback roots, reject stale CLI node runtimes, avoid npm <code>min-release-age</code> installer failures, bound npm/package/Docker install phases, restore config parent ownership in Docker, seed Docker lockfile package tarballs before prune, make release/plugin prerelease checks fail closed instead of hanging or false-greening, and use host-visible Crabbox local work roots for Docker-backed proof. (#85491)</li>
<li>Windows daemon: keep Scheduled Task gateway launches running on battery power and avoid workgroup-machine prompts for a domain user during task installation. (#59299)</li>
<li>Security: avoid printing Gateway tokens in Docker, validate plugin model-pattern regexes safely, escape transcript metadata field names, harden session allowlist glob matching, audit Claude permission overrides under YOLO, and require explicit allow for ACP auto approvals. (#85849, #85934, #86046, #86557)</li>
<li>Media/images: replace Sharp with Rastermill, keep EXIF normalization best-effort, normalize HEIC/HEIF before image descriptions, route Codex image API keys through OpenAI, preserve image compression metadata, and auto-scale live tool result caps. (#85776, #86037, #86437, #86857, #86923)</li>
<li>Memory: prevent semantic vector indexes from silently degrading when embeddings are unavailable, stop doctor OOMs on large session stores, preserve sidecar hooks/artifacts, write fallback dream diaries, use CJK-aware dreaming dedupe, and avoid per-file watcher FD fan-out. (#80613, #82928, #85060, #85704, #85967, #86701) Thanks @brokemac79, @openperf, and @yaaboo-gif.</li>
<li>Agents/sessions: include visibility metadata on restricted <code>sessions_list</code> results so scoped counts are clearly reported without widening access or exposing hidden-session counts. (#86944) Thanks @ferminquant.</li>
<li>Gateway/DNS: validate wide-area discovery domains before deriving zone paths or writing zone files, so invalid <code>discovery.wideArea.domain</code> and <code>dns setup --domain</code> values fail with a DNS-name diagnostic instead of falling through to unrelated configuration errors. Thanks @mmaps.</li>
<li>Agents/BTW: route fallback side-question streams through the embedded stream resolver so Anthropic-compatible MiniMax requests use the same capped transport as normal chat. (#86312) Thanks @neeravmakwana.</li>
<li>Telegram: treat <code>/command@TargetBot</code> bot-command entities as explicit mentions for the addressed bot so <code>requireMention</code> groups no longer drop targeted commands or captions. Fixes #84462. (#86553) Thanks @luoyanglang.</li>
<li>CI: bound Docker/Bash E2E tarball npm installs with <code>OPENCLAW_E2E_NPM_INSTALL_TIMEOUT</code> so package, onboarding, plugin, and upgrade lanes fail instead of hanging on a stuck npm install.</li>
<li>CI: fail Parallels npm-update smoke jobs after the guest command timeout and cleanup backstop instead of only logging a timeout line.</li>
<li>CI: bound kitchen-sink RPC HTTP probes so stalled gateway readiness or response bodies fail and retry instead of wedging the walker.</li>
<li>CI: keep <code>OPENCLAW_TESTBOX=1 pnpm check:changed</code> delegating to Blacksmith Testbox through Crabbox without forwarding local Testbox or worker env into the remote command.</li>
<li>CI: send KILL after the TERM grace period for manual checkout fetch timeouts so stuck Testbox and workflow checkout retries cannot hang behind a wedged <code>git fetch</code>.</li>
<li>CI: send KILL after the TERM grace period for Bun global install smoke command timeouts so trapped <code>openclaw</code> child processes cannot wedge the scheduled install smoke.</li>
<li>iMessage: thread current channel/account inbound attachment roots into the image tool so iMessage-saved attachments under <code>~/Library/Messages/Attachments</code> (including the wildcard <code>/Users/*/Library/Messages/Attachments</code> root) are read through the existing inbound path policy instead of being rejected as <code>path-not-allowed</code>. Literal <code>localRoots</code> stays workspace-scoped. Fixes #30170. (#86569)</li>
<li>QQ Bot: respect <code>OPENCLAW_HOME</code> for outbound media path resolution so <code><qqmedia></code> sends no longer silently fail when <code>HOME</code> and <code>OPENCLAW_HOME</code> differ (Docker / multi-user hosts). Persisted QQ Bot data (sessions, known users, refs) stays anchored on the OS home for upgrade compatibility. Fixes #83562. Thanks @sliverp.</li>
<li>Update: report the primary malformed <code>openclaw.extensions</code> payload error without adding a duplicate missing-main diagnostic. (#86596) Thanks @ferminquant.</li>
<li>Control UI: keep host-local Markdown file paths inert while preserving app-relative links. (#86620) Thanks @BryanTegomoh.</li>
<li>Gateway: dampen repeated unauthenticated device-required probes per URL while preserving explicit-auth and paired recovery paths. (#86575) Thanks @ferminquant.</li>
<li>IRC: store inbound channel routes with the canonical <code>channel:#name</code> target and join transient channel sends before writing. (#85906) Thanks @Kailigithub.</li>
<li>Usage: surface unknown all-zero model pricing as missing cost entries instead of a confident <code>$0</code> total. (#85882) Thanks @MichaelZelbel.</li>
<li>Agents/Codex: honor yolo app-server approval policy only for the full <code>never</code> plus <code>danger-full-access</code> case. (#85909) Thanks @earlvanze.</li>
<li>Gateway/Gmail: clear Gmail watcher renewal intervals on re-entry so hot reloads do not leak lifecycle timers. (#82947) Thanks @SebTardif.</li>
<li>Logging: exit cleanly on broken stdout/stderr pipes without masking existing failure exit codes. (#80059) Thanks @pavelzak.</li>
<li>Gateway/security: escape transcript metadata field names while extracting oversized session line prefixes. (#85934) Thanks @SebTardif.</li>
<li>Plugins/security: validate manifest model pattern regexes with the safe-regex compiler so unsafe patterns are ignored before matching. (#86046) Thanks @SebTardif.</li>
<li>Discord: route gateway metadata REST lookups through the configured Discord proxy so proxied accounts do not fall back to direct <code>discord.com</code> connections before opening the WebSocket. Fixes #80227. Thanks @Clivilwalker.</li>
<li>Agents/media: hydrate current-turn image attachments from filename-derived MIME types so active vision can see generated or forwarded images whose source omitted an image content type. (#84812) Thanks @marchpure.</li>
<li>Agents/fs: point workspace-only scratch-path guidance at in-workspace temp directories while keeping host-root writes rejected by the tool guard. (#86501) Thanks @tianxiaochannel-oss88.</li>
<li>Agents/media: keep async cron media completions scoped to their run session while preserving direct delivery for stale generated-media success and failure notifications. (#86529) Thanks @ai-hpc.</li>
<li>Gateway: emit plugin <code>session_end</code>/<code>session_start</code> hooks when <code>agent.send</code> rotates or replaces a session id, keeping hook lifecycle state aligned with <code>sessions.changed</code> notifications. Fixes #83507. (#85875) Thanks @brokemac79.</li>
<li>OpenShell/SSH: reject malformed generated exec commands before sandbox/session setup so unresolved workflow placeholders fail fast instead of reaching the remote shell. Fixes #72373. Thanks @brokemac79.</li>
<li>Google: stop normalizing <code>gemini-3.1-flash-lite</code> to the retired preview endpoint and update Flash Lite alias guidance to the GA model id. Fixes #86151. (#86240) Thanks @SebTardif.</li>
<li>Installer: make Alpine apk installs cover Git, verify the Node runtime floor, try <code>nodejs-current</code>, and report Alpine version guidance when repositories only provide older Node packages.</li>
<li>Agents/status: prefer the active Claude CLI OAuth auth label over an unused Anthropic env API-key label for equivalent runtime aliases. Fixes #80184. (#86570) Thanks @brokemac79.</li>
<li>Agents/media: send direct fallback for generated media still missing after an active requester wake fails. (#85489) Thanks @fuller-stack-dev.</li>
<li>Agents: derive overflow compaction budgets from provider-reported and synthetic over-budget token counts so confirmed context overflows compact before retrying. (#70473) Thanks @fuller-stack-dev.</li>
<li>Agents/Codex: recover Codex context-window prompt errors through overflow compaction and surface reset guidance when recovery is exhausted. (#85542) Thanks @fuller-stack-dev.</li>
<li>Agents/Codex: allow Codex app-server runs to bootstrap from <code>CODEX_API_KEY</code> or <code>OPENAI_API_KEY</code> when no Codex auth profile is configured.</li>
<li>Agents/Codex: keep selected Codex runtime routing on OpenAI-Codex while preserving direct OpenAI API-key compaction fallback. (#86408) Thanks @funmerlin and @VACInc.</li>
<li>Agent transcript: include OpenClaw agent session logs when finding local transcript candidates.</li>
<li>Crabbox: bootstrap raw AWS macOS shell commands wrapped in absolute <code>time</code> paths so RSS probes can run Node and pnpm on fresh macOS runners.</li>
<li>Crabbox: bootstrap raw AWS macOS shell commands even when setup statements precede Node or pnpm usage.</li>
<li>TUI/local: skip unnecessary secret resolution, gateway model catalog loading, bootstrap, and skill scans in explicit local-model runs so startup reaches the model request faster.</li>
<li>Sessions/doctor: load large session stores without clone amplification during read-only doctor checks and reclaim stale <code>sessions.json.*.tmp</code> sidecars. Fixes #56827. Thanks @openperf.</li>
<li>Tests: clean successful plugin gateway gauntlet isolated temp roots while keeping an explicit preservation switch for failed/debug runs.</li>
<li>Plugins/perf: reuse derived plugin metadata snapshots for the lifetime of the process so reply-time skill setup no longer rescans plugin metadata on every turn.</li>
<li>Discord/OpenAI voice: keep wake-name master consults using the current speaker context after ignored ambient transcripts and shorten the default capture silence grace.</li>
<li>Doctor: skip redundant Gateway restart prompts when a recent supervisor restart leaves the Gateway healthy. Fixes #86518. (#86533) Thanks @liaoyl830.</li>
<li>Cron: restore suspended cron lanes to the configured/default concurrency instead of falling back to one after quota or circuit-breaker auto-resume.</li>
<li>Gateway: keep session-only Control UI tool-start mirrors flowing during diagnostic queue pressure instead of silently dropping non-terminal tool updates.</li>
<li>Agents/memory: return optional not-found context for missing date-only daily memory reads instead of logging benign first-run <code>ENOENT</code> failures. Fixes #82928. Thanks @galiniliev.</li>
<li>Discord: merge streamed text captions into following media block replies so captions and attachments send as one message. (#86487) Thanks @neeravmakwana.</li>
<li>Gateway: avoid sending duplicate tool-event frames to Control UI connections that are subscribed by both run and session.</li>
<li>Discord/OpenAI voice: accept broader edge-position fuzzy wake-name transcripts while keeping ambient speech gated.</li>
<li>Discord/OpenAI voice: accept longer leading wake-name mistranscripts such as "Open Club" for OpenClaw.</li>
<li>Agents/OpenAI-compatible: stop ModelStudio-compatible chat requests before sending system/tool-only payloads that have no usable user or assistant turn. (#86177) Thanks @TurboTheTurtle.</li>
<li>Gateway/plugins: reuse plugin package realpath checks while building installed plugin indexes so startup avoids repeated filesystem resolution work.</li>
<li>Kilo Gateway: send string <code>stop</code> sequences as arrays so Kilo accepts OpenAI-compatible chat completions. (#86461) Thanks @SebTardif.</li>
<li>Discord/OpenAI voice: accept leading fuzzy wake-name transcripts such as "Monty" or "Moti" for a Molty agent while keeping ambient speech gated.</li>
<li>Media understanding: convert HEIC and HEIF images to JPEG before image description providers run so iPhone photos work in direct and configured image-description flows. (#86037)</li>
<li>Agents: release embedded-attempt session locks from outer teardown so post-prompt exceptions cannot wedge later requests behind <code>SessionWriteLockTimeoutError</code>. Fixes #86014. Thanks @openperf.</li>
<li>Discord/OpenAI voice: rotate Realtime sessions at provider max duration without logging the expected session-expiry event as an error.</li>
<li>Sessions: skip metadata-only entries during QMD-slugified session lookup so one incomplete row does not block transcript hit resolution. (#86327) Thanks @abnershang.</li>
<li>Agents/media: derive bundled plugin local-media trust from plugin tool metadata instead of importing the full plugin registry on subscription paths. (#84409) Thanks @samzong.</li>
<li>Image tool: keep config-backed custom-provider API keys usable for auto-discovered vision models, including deferred image-tool execution without env keys or auth profiles. (#85733)</li>
<li>Memory/local embeddings: run local GGUF embeddings in an isolated worker sidecar and degrade to configured fallback or keyword search on worker failure so native embedding crashes do not take down the Gateway. (#85348) Thanks @osolmaz.</li>
<li>Gateway: clear the runtime config snapshot before <code>SIGUSR1</code> in-process restarts so config changes survive the next gateway loop. (#86388) Thanks @XuZehan-iCenter.</li>
<li>Models: show OAuth delegation markers as configured <code>models.json</code> auth while keeping runtime route usability checks strict. (#86378) Thanks @rohitjavvadi.</li>
<li>Cron: seed active scheduled and manual cron task rows with a progress summary so status surfaces do not look blank while jobs run. (#86313) Thanks @ferminquant.</li>
<li>Cron: preserve unsupported persisted cron payload rows during routine store writes while keeping those rows non-runnable. Fixes #84922. (#86415) Thanks @IWhatsskill.</li>
<li>Updater: exclude prerelease git tags from stable channel resolution so source updates do not check out newer alpha/rc/preview/canary tags. (#86260) Thanks @stevenepalmer.</li>
<li>Security/Audit: flag webhook <code>hooks.token</code> reuse of active Gateway password auth in <code>openclaw security audit</code> while keeping password-mode startup compatibility. (#84338) Thanks @coygeek.</li>
<li>QQBot: derive the outbound reply watchdog from configured agent and provider timeouts so slow local model replies are not cut off at five minutes. Fixes #85267. (#85271) Thanks @SymbolStar.</li>
<li>Agents/heartbeat: stop heartbeat turns after the first valid <code>heartbeat_respond</code> so repeated response loops do not burn tokens. (#86357) Thanks @udaymanish6.</li>
<li>Tasks: keep retained lost tasks out of default status health counts, explain their cleanup window during maintenance, and prune lost task records after 24 hours instead of the general 7-day terminal retention.</li>
<li>Memory-core: keep REM dreaming focused on live light-staged memories and mark staged entries as considered so old recall history no longer dominates fresh candidates. (#86302) Thanks @SebTardif.</li>
<li>Memory: abort sync instead of downgrading an existing semantic vector index to FTS-only when the configured embedding provider is temporarily unavailable. (#85704) Thanks @yaaboo-gif.</li>
<li>Telegram: propagate forum topic names through the account-scoped topic cache for native command context and topic create/edit actions. (#86299) Thanks @SebTardif.</li>
<li>Slack: keep downloaded read-only files out of reply media so Slack file reads do not echo files back to the conversation. (#86318) Thanks @neeravmakwana.</li>
<li>Cron: accept leading-plus relative durations such as <code>+5m</code> for one-shot <code>--at</code> schedules. (#86341) Thanks @mushuiyu886.</li>
<li>Agents/media: preserve async-started media tool metadata so background generation starts no longer surface generic incomplete-turn warnings while replay stays unsafe. (#85933) Thanks @fuller-stack-dev.</li>
<li>Docker E2E: dedupe scheduler lane resources so npm/service package lanes are not over-counted and serialized unnecessarily.</li>
<li>QA/diagnostics: add a collector-backed OpenTelemetry smoke lane, make the OTLP payload leak check scenario-aware, and keep source QA builds from failing on optional dependency imports resolved through pnpm's temp module path.</li>
<li>Crabbox: bootstrap Git metadata for sparse remote changed gates so raw synced workspaces can run <code>pnpm check:changed</code> from the intended diff.</li>
<li>xAI/LM Studio: avoid buffering ordinary bracketed or <code>final</code> prose until stream completion while watching for plain-text tool-call fallbacks.</li>
<li>Doctor: warn and continue when the cron job store exists but cannot be read so later health checks still run. Fixes #86102. (#86384) Thanks @1052326311.</li>
<li>Discord: suppress a bot's previous reply body and referenced media from prompt context when a user replies to that bot message, while keeping reply metadata for routing. (#86238) Thanks @fuller-stack-dev.</li>
<li>Discord: restore bare numeric channel IDs for outbound message-tool sends while keeping explicit DM targets unambiguous. (#86571) Thanks @joshavant.</li>
<li>Docker E2E: avoid rebuilding the Control UI twice while preparing the shared OpenClaw package tarball for package-backed scenario runs.</li>
<li>Tests: avoid rebuilding the Control UI twice during the installer Docker smoke now that <code>pnpm build</code> includes <code>ui:build</code>.</li>
<li>Tests: give QA config mutation RPCs enough native Windows budget to finish gateway config writes and restart settle after hot scenario runs.</li>
<li>Tests: keep the gateway restart-inflight QA scenario focused on restart recovery on native Windows by allowing expected embedded prompt handoff errors and using the Windows-safe timeout budget.</li>
<li>QA-Lab: make the synthetic OpenAI provider honor generic <code>reply exactly:</code> directives after required kickoff reads so restart-recovery scenarios do not fall through to generic repo-summary prose.</li>
<li>Gateway: abort active <code>agent</code> RPC runs during forced restart shutdown so stale in-process turns cannot keep writing a session after the Gateway lifecycle restarts.</li>
<li>Crabbox: sync clean sparse worktrees through a temporary full checkout even when reusing an existing lease so tracked build-time files are not omitted.</li>
<li>Build: route <code>scripts/ui.js</code> through the shared pnpm runner and keep Control UI chunking helpers in sparse-included source so native Windows Corepack builds can produce <code>dist/control-ui</code>.</li>
<li>Tests: give the memory fallback QA scenario enough turn budget to exercise native Windows gateway runs instead of failing on the client timeout while the mock agent is still dispatching.</li>
<li>Tests: collect QA gateway CPU/RSS metrics on native Windows and give the channel baseline enough turn budget to report slow gateway runs instead of timing out before proof.</li>
<li>Install/update: bypass npm <code>min-release-age</code> policies with <code>--min-release-age=0</code> instead of <code>--before</code> so hosted installers keep working on npm versions that reject the combined config. (#84749) Thanks @TeodoroRodrigo.</li>
<li>Diagnostics: reclaim wedged session lanes when stale active-run bookkeeping blocks queued work despite no forward progress. Fixes #85639. Thanks @openperf.</li>
<li>WebChat: keep message-tool replies visible in the chat while still summarizing internal tool results for the model. Fixes #86347. Thanks @shakkernerd.</li>
<li>Gateway/perf: fail startup benchmark samples when the Gateway process exits before benchmark teardown, including signal deaths after readiness probes.</li>
<li>Gateway/perf: fail restart benchmark samples when the Gateway exits before benchmark teardown, including clean exits and signal deaths after successful restart probes.</li>
<li>Agents/tests: keep model catalog visibility on static selection helpers so catalog visibility checks avoid the broad model-selection barrel import.</li>
<li>Agents/commitments: serialize commitment store load-modify-save writes so concurrent heartbeat and CLI updates no longer lose dismissal, sent, or attempt state. (#81153) Thanks @ai-hpc.</li>
<li>xAI/LM Studio: promote plain-text tool-call fallbacks into structured tool calls and strip leaked internal tool syntax before user-facing delivery. (#86222) Thanks @fuller-stack-dev.</li>
<li>CLI: suppress benign self-update version-skew warnings during package post-update finalization.</li>
<li>Gateway/perf: tighten restart and startup benchmark failure handling so long profiling runs, failed probes, and fresh Linux runners no longer produce false passing or <code>n/a</code> results.</li>
<li>Checks: keep intentional Knip unused-file findings optional so full CI and sparse proof workspaces stay aligned.</li>
<li>Docker: restore writable <code>~/.config</code> in runtime images. Fixes #85968. Thanks @hkoessler and @Bartok9.</li>
<li>Plugin SDK: keep legacy root diagnostic subscriptions connected when built plugin SDK aliases resolve diagnostic helpers through a separate module graph.</li>
<li>Diagnostics: export alertable OTel and Prometheus signals for blocked tools, model failover, stale sessions, liveness warnings, oversized payloads, and webhook ingress while fixing shared OTLP endpoints with query strings.</li>
<li>Tests: normalize macOS canonical temp paths in exec allowlists, fs-safe trash assertions, installed plugin matching, Telegram topic-name stores, and built ACPX MCP server expectations so native macOS proof runners cover the intended behavior.</li>
<li>Codex/app-server: preserve message-tool-only source reply delivery mode on active runs so sub-agent completion wakeups can steer the active Codex turn instead of being rejected. (#86287) Thanks @ferminquant.</li>
<li>Tests: sample the Windows kitchen-sink RPC gateway directly and serialize RSS probes so native runs keep the memory guard active.</li>
<li>Tests: normalize bundled plugin lifecycle probe paths and state-root lookup so native Windows release sweeps accept valid packaged plugin installs.</li>
<li>Agents/Claude CLI: route live native Bash permission requests through OpenClaw exec policy so Claude turns no longer stall on <code>control_request</code>, and document that OpenClaw exec policy is authoritative. Fixes #80819. (#86330, from #81971) Thanks @guthirry and @sallyom.</li>
<li>Security audit: warn when YOLO OpenClaw exec policy overrides a restrictive raw Claude <code>--permission-mode</code> for managed live sessions. (#86557) Thanks @sallyom.</li>
<li>Config: keep benign legacy metadata write anomalies out of default doctor and config command output while preserving explicit anomaly logging for diagnostics.</li>
<li>Codex: log when implicit app-server <code>never</code> approvals are promoted for OpenClaw tool policy, including whether the trigger was a <code>before_tool_call</code> hook or trusted tool policy.</li>
<li>Codex harness: make subscription usage-limit errors without reset times explain that OpenClaw cannot determine the reset and point users to wait until Codex is available, use another Codex account, or switch to another configured model/provider. Thanks @amknight.</li>
<li>Google Vertex: support production ADC modes such as Workload Identity Federation, service-account credentials, and metadata-server ADC for the native Vertex transport. (#83971) Thanks @damianFelixPago.</li>
<li>Telegram: route normal <code>[telegram][diag]</code> polling diagnostics through <code>runtime.log</code> while keeping non-diag warnings and persistence failures on <code>runtime.error</code>, so healthy polling startup no longer looks like an error. Fixes #82957. (#82958) Thanks @galiniliev.</li>
<li>Providers/Ollama: strip inline Kimi cloud reasoning prefixes from streamed and final visible replies while keeping ordinary Kimi answers append-only. (#86286) Thanks @jason-allen-oneal.</li>
</ul>
<ul>
<li>Gateway: require Talk secret authority before setup-code handoff can include Talk secrets. (#85690) Thanks @ngutman.</li>
<li>Agents: keep fallback error reporting scoped to the active model candidate so stale prior-provider quota/auth text is not reported for later fallback attempts. (#86134) Thanks @zhangguiping-xydt.</li>
<li>iMessage: dedupe watcher startup when <code>channels.imessage.accounts</code> lists both <code>default</code> and a named account that point at the same local Messages source, so the gateway no longer spawns two <code>imsg rpc</code> processes or doubles inbound replies; the dedupe is scoped to watcher startup, leaving duplicate accounts addressable for outbound sends, status, and capability listings, and <code>openclaw doctor</code> flags the redundant account with a rebinding hint. Fixes #65141. (#86705) Thanks @swang430.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.19/OpenClaw-2026.5.19.zip" length="54062201" type="application/octet-stream" sparkle:edSignature="7bVi6rv+TjhrUfi32V62BW2VgyV17jm7x+H6p10PRClCdXKZjhM7AX6MyvAz2+e7kzXIknj1Y9X7q43/E9fBBw=="/>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.26/OpenClaw-2026.5.26.zip" length="54484748" type="application/octet-stream" sparkle:edSignature="y4WXG7JT8ktJ+K7YDgllY7u5Z9BSKR/SwGiwEh0gikOJ/SWqwcQd+z2tWa2zgwvCJKWsAUFwJs1ATor880SUBg=="/>
</item>
</channel>
</rss>

View File

@@ -65,8 +65,8 @@ android {
applicationId = "ai.openclaw.app"
minSdk = 31
targetSdk = 36
versionCode = 2026052601
versionName = "2026.5.26"
versionCode = 2026053001
versionName = "2026.5.30"
ndk {
// Support all major ABIs — native libs are tiny (~47 KB per ABI)
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")

View File

@@ -6,6 +6,7 @@ import ai.openclaw.app.chat.ChatPendingToolCall
import ai.openclaw.app.chat.ChatSessionEntry
import ai.openclaw.app.chat.OutgoingAttachment
import ai.openclaw.app.gateway.DeviceAuthStore
import ai.openclaw.app.gateway.DeviceAuthTokenStore
import ai.openclaw.app.gateway.DeviceIdentityStore
import ai.openclaw.app.gateway.GatewayDiscovery
import ai.openclaw.app.gateway.GatewayEndpoint
@@ -79,6 +80,7 @@ class NodeRuntime(
context: Context,
val prefs: SecurePrefs = SecurePrefs(context.applicationContext),
private val tlsFingerprintProbe: suspend (String, Int) -> GatewayTlsProbeResult = ::probeGatewayTlsFingerprint,
private val deviceAuthStore: DeviceAuthTokenStore = DeviceAuthStore(context.applicationContext),
) {
data class GatewayConnectAuth(
val token: String?,
@@ -88,7 +90,6 @@ class NodeRuntime(
private val appContext = context.applicationContext
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val deviceAuthStore = DeviceAuthStore(prefs)
val canvas = CanvasController()
val camera = CameraCaptureManager(appContext)
val location = LocationCaptureManager(appContext)
@@ -109,7 +110,6 @@ class NodeRuntime(
private val cameraHandler: CameraHandler =
CameraHandler(
appContext = appContext,
camera = camera,
externalAudioCaptureActive = externalAudioCaptureActive,
showCameraHud = ::showCameraHud,
@@ -119,7 +119,6 @@ class NodeRuntime(
private val debugHandler: DebugHandler =
DebugHandler(
appContext = appContext,
identityStore = identityStore,
)
@@ -2871,7 +2870,7 @@ fun providerDisplayName(provider: String): String =
when (provider.trim().lowercase()) {
"openai" -> "OpenAI"
"openrouter" -> "OpenRouter"
"openai-codex", "codex" -> "Codex"
"codex" -> "Codex"
"ollama", "ollama-local" -> "Ollama Local"
else ->
provider

View File

@@ -442,6 +442,23 @@ class SecurePrefs(
securePrefs.edit { remove(key) }
}
fun keysWithPrefix(prefix: String): Set<String> =
securePrefs
.all
.keys
.filter { it.startsWith(prefix) }
.toSet()
fun removeKeysWithPrefix(prefix: String) {
val keys = keysWithPrefix(prefix)
if (keys.isEmpty()) return
securePrefs.edit {
for (key in keys) {
remove(key)
}
}
}
private fun createSecurePrefs(
context: Context,
name: String,

View File

@@ -1,7 +1,9 @@
package ai.openclaw.app.gateway
import ai.openclaw.app.SecurePrefs
import android.content.Context
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@@ -18,6 +20,10 @@ private data class PersistedDeviceAuthMetadata(
val updatedAtMs: Long = 0L,
)
private const val deviceAuthTokenPrefix = "gateway.deviceToken."
private const val deviceAuthMetadataPrefix = "gateway.deviceTokenMeta."
private const val sqliteSecurePrefsTokenMarker = "__openclaw_secure_prefs__"
interface DeviceAuthTokenStore {
fun loadEntry(
deviceId: String,
@@ -42,29 +48,104 @@ interface DeviceAuthTokenStore {
)
}
class DeviceAuthStore(
private val prefs: SecurePrefs,
internal interface DeviceAuthStateStore {
fun readDeviceAuthToken(
deviceId: String,
role: String,
): OpenClawSQLiteDeviceAuthTokenRow?
fun readLatestDeviceAuthDeviceId(): String?
fun upsertDeviceAuthToken(row: OpenClawSQLiteDeviceAuthTokenRow)
fun deleteDeviceAuthToken(
deviceId: String,
role: String,
)
fun deleteAllDeviceAuthTokens()
}
private class OpenClawSQLiteDeviceAuthStateStore(
private val store: OpenClawSQLiteStateStore,
) : DeviceAuthStateStore {
override fun readDeviceAuthToken(
deviceId: String,
role: String,
): OpenClawSQLiteDeviceAuthTokenRow? = store.readDeviceAuthToken(deviceId, role)
override fun readLatestDeviceAuthDeviceId(): String? = store.readLatestDeviceAuthDeviceId()
override fun upsertDeviceAuthToken(row: OpenClawSQLiteDeviceAuthTokenRow) {
store.upsertDeviceAuthToken(row)
}
override fun deleteDeviceAuthToken(
deviceId: String,
role: String,
) {
store.deleteDeviceAuthToken(deviceId, role)
}
override fun deleteAllDeviceAuthTokens() {
store.deleteAllDeviceAuthTokens()
}
}
class DeviceAuthStore private constructor(
private val context: Context,
private val legacyPrefsOverride: SecurePrefs? = null,
private val stateStore: DeviceAuthStateStore,
) : DeviceAuthTokenStore {
constructor(
context: Context,
legacyPrefsOverride: SecurePrefs? = null,
) : this(
context = context,
legacyPrefsOverride = legacyPrefsOverride,
stateStore = OpenClawSQLiteDeviceAuthStateStore(OpenClawSQLiteStateStore(context)),
)
internal companion object {
fun createForTesting(
context: Context,
legacyPrefsOverride: SecurePrefs? = null,
stateStoreOverride: DeviceAuthStateStore,
): DeviceAuthStore =
DeviceAuthStore(
context = context,
legacyPrefsOverride = legacyPrefsOverride,
stateStore = stateStoreOverride,
)
}
private val json = Json { ignoreUnknownKeys = true }
private val legacyPrefs by lazy { legacyPrefsOverride ?: SecurePrefs(context) }
override fun loadEntry(
deviceId: String,
role: String,
): DeviceAuthEntry? {
val key = tokenKey(deviceId, role)
val token = prefs.getString(key)?.trim()?.takeIf { it.isNotEmpty() } ?: return null
val normalizedDevice = normalizeDeviceId(deviceId)
val normalizedRole = normalizeRole(role)
val metadata =
prefs
.getString(metadataKey(deviceId, role))
?.let { raw ->
runCatching { json.decodeFromString<PersistedDeviceAuthMetadata>(raw) }.getOrNull()
val row =
stateStore.readDeviceAuthToken(normalizedDevice, normalizedRole)
?: return migrateLegacyEntryIfNoSqliteAuthRows(normalizedDevice, normalizedRole)
val token =
legacyPrefs
.getString(tokenKey(normalizedDevice, normalizedRole))
?.trim()
?.takeIf { it.isNotEmpty() }
?: row.token.trim().takeIf { it.isNotEmpty() && it != sqliteSecurePrefsTokenMarker }?.also {
legacyPrefs.putString(tokenKey(normalizedDevice, normalizedRole), it)
stateStore.upsertDeviceAuthToken(row.copy(token = sqliteSecurePrefsTokenMarker))
}
?: return null
return DeviceAuthEntry(
token = token,
role = normalizedRole,
scopes = metadata?.scopes ?: emptyList(),
updatedAtMs = metadata?.updatedAtMs ?: 0L,
scopes = decodeScopes(row.scopesJson),
updatedAtMs = row.updatedAtMs,
)
}
@@ -74,16 +155,35 @@ class DeviceAuthStore(
token: String,
scopes: List<String>,
) {
val normalizedDevice = normalizeDeviceId(deviceId)
val normalizedRole = normalizeRole(role)
val normalizedScopes = normalizeScopes(scopes)
val key = tokenKey(deviceId, role)
prefs.putString(key, token.trim())
prefs.putString(
metadataKey(deviceId, role),
json.encodeToString(
PersistedDeviceAuthMetadata(
scopes = normalizedScopes,
updatedAtMs = System.currentTimeMillis(),
),
val latestDeviceId = stateStore.readLatestDeviceAuthDeviceId()
val shouldSeedSameDeviceLegacyRoles = latestDeviceId == null
val sqliteDeviceChanged = latestDeviceId != null && latestDeviceId != normalizedDevice
val shouldDropLegacyAuth =
sqliteDeviceChanged ||
legacyPrefs.keysWithPrefix(deviceAuthTokenPrefix).any {
!it.startsWith(tokenKeyPrefix(normalizedDevice))
}
if (sqliteDeviceChanged) {
stateStore.deleteAllDeviceAuthTokens()
}
if (shouldDropLegacyAuth) {
removeForeignLegacyEntries(normalizedDevice)
}
if (shouldSeedSameDeviceLegacyRoles) {
migrateLegacyEntriesForDevice(normalizedDevice)
}
legacyPrefs.putString(tokenKey(normalizedDevice, normalizedRole), token.trim())
removeLegacyMetadata(normalizedDevice, normalizedRole)
stateStore.upsertDeviceAuthToken(
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = normalizedDevice,
role = normalizedRole,
token = sqliteSecurePrefsTokenMarker,
scopesJson = json.encodeToString(normalizedScopes),
updatedAtMs = System.currentTimeMillis(),
),
)
}
@@ -92,28 +192,124 @@ class DeviceAuthStore(
deviceId: String,
role: String,
) {
val key = tokenKey(deviceId, role)
prefs.remove(key)
prefs.remove(metadataKey(deviceId, role))
val normalizedDevice = normalizeDeviceId(deviceId)
val normalizedRole = normalizeRole(role)
removeLegacyEntry(normalizedDevice, normalizedRole)
stateStore.deleteDeviceAuthToken(
deviceId = normalizedDevice,
role = normalizedRole,
)
}
private fun migrateLegacyEntryIfNoSqliteAuthRows(
normalizedDevice: String,
normalizedRole: String,
): DeviceAuthEntry? {
if (stateStore.readLatestDeviceAuthDeviceId() != null) {
removeLegacyEntry(normalizedDevice, normalizedRole)
return null
}
return migrateLegacyEntriesForDevice(normalizedDevice)[normalizedRole]
}
private fun migrateLegacyEntriesForDevice(normalizedDevice: String): Map<String, DeviceAuthEntry> {
val prefix = tokenKeyPrefix(normalizedDevice)
return legacyPrefs
.keysWithPrefix(prefix)
.mapNotNull { key ->
val role = normalizeRole(key.removePrefix(prefix))
if (role.isEmpty()) {
null
} else {
migrateLegacyEntry(normalizedDevice, role)?.let { role to it }
}
}.toMap()
}
private fun migrateLegacyEntry(
normalizedDevice: String,
normalizedRole: String,
): DeviceAuthEntry? {
val token =
legacyPrefs
.getString(tokenKey(normalizedDevice, normalizedRole))
?.trim()
?.takeIf { it.isNotEmpty() }
?: return null
val metadata =
legacyPrefs
.getString(metadataKey(normalizedDevice, normalizedRole))
?.let { raw -> runCatching { json.decodeFromString<PersistedDeviceAuthMetadata>(raw) }.getOrNull() }
val entry =
DeviceAuthEntry(
token = token,
role = normalizedRole,
scopes = normalizeScopes(metadata?.scopes ?: emptyList()),
updatedAtMs = metadata?.updatedAtMs?.takeIf { it > 0L } ?: System.currentTimeMillis(),
)
val migrated =
runCatching {
stateStore.upsertDeviceAuthToken(
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = normalizedDevice,
role = normalizedRole,
token = sqliteSecurePrefsTokenMarker,
scopesJson = json.encodeToString(entry.scopes),
updatedAtMs = entry.updatedAtMs,
),
)
}.isSuccess
if (migrated) {
legacyPrefs.putString(tokenKey(normalizedDevice, normalizedRole), entry.token)
removeLegacyMetadata(normalizedDevice, normalizedRole)
}
return entry
}
private fun removeLegacyMetadata(
normalizedDevice: String,
normalizedRole: String,
) {
legacyPrefs.remove(metadataKey(normalizedDevice, normalizedRole))
}
private fun removeLegacyEntry(
normalizedDevice: String,
normalizedRole: String,
) {
legacyPrefs.remove(tokenKey(normalizedDevice, normalizedRole))
legacyPrefs.remove(metadataKey(normalizedDevice, normalizedRole))
}
private fun removeForeignLegacyEntries(normalizedDevice: String) {
val currentTokenPrefix = tokenKeyPrefix(normalizedDevice)
legacyPrefs
.keysWithPrefix(deviceAuthTokenPrefix)
.filterNot { it.startsWith(currentTokenPrefix) }
.forEach { legacyPrefs.remove(it) }
val currentMetadataPrefix = "$deviceAuthMetadataPrefix$normalizedDevice."
legacyPrefs
.keysWithPrefix(deviceAuthMetadataPrefix)
.filterNot { it.startsWith(currentMetadataPrefix) }
.forEach { legacyPrefs.remove(it) }
}
private fun tokenKeyPrefix(normalizedDevice: String): String = "$deviceAuthTokenPrefix$normalizedDevice."
private fun tokenKey(
deviceId: String,
role: String,
): String {
val normalizedDevice = normalizeDeviceId(deviceId)
val normalizedRole = normalizeRole(role)
return "gateway.deviceToken.$normalizedDevice.$normalizedRole"
}
normalizedDevice: String,
normalizedRole: String,
): String = "${tokenKeyPrefix(normalizedDevice)}$normalizedRole"
private fun metadataKey(
deviceId: String,
role: String,
): String {
val normalizedDevice = normalizeDeviceId(deviceId)
val normalizedRole = normalizeRole(role)
return "gateway.deviceTokenMeta.$normalizedDevice.$normalizedRole"
}
normalizedDevice: String,
normalizedRole: String,
): String = "$deviceAuthMetadataPrefix$normalizedDevice.$normalizedRole"
private fun decodeScopes(raw: String): List<String> =
runCatching { json.decodeFromString<List<String>>(raw) }
.getOrDefault(emptyList())
.let(::normalizeScopes)
private fun normalizeDeviceId(deviceId: String): String = deviceId.trim().lowercase()

View File

@@ -19,7 +19,8 @@ class DeviceIdentityStore(
context: Context,
) {
private val json = Json { ignoreUnknownKeys = true }
private val identityFile = File(context.filesDir, "openclaw/identity/device.json")
private val stateStore = OpenClawSQLiteStateStore(context)
private val legacyIdentityFile = File(context.filesDir, "openclaw/identity/device.json")
@Volatile private var cachedIdentity: DeviceIdentity? = null
@@ -28,16 +29,14 @@ class DeviceIdentityStore(
cachedIdentity?.let { return it }
val existing = load()
if (existing != null) {
val derived = deriveDeviceId(existing.publicKeyRawBase64)
if (derived != null && derived != existing.deviceId) {
val updated = existing.copy(deviceId = derived)
save(updated)
cachedIdentity = updated
return updated
}
cachedIdentity = existing
return existing
}
if (legacyIdentityFile.exists()) {
val migrated = migrateLegacyIdentity()
cachedIdentity = migrated
return migrated
}
val fresh = generate()
save(fresh)
cachedIdentity = fresh
@@ -111,34 +110,76 @@ class DeviceIdentityStore(
null
}
private fun load(): DeviceIdentity? = readIdentity(identityFile)
private fun load(): DeviceIdentity? {
val row = stateStore.readDeviceIdentity(IDENTITY_KEY) ?: return null
return readIdentity(row)
?: throw IllegalStateException(
"Stored OpenClaw device identity is invalid. Run openclaw doctor --fix.",
)
}
private fun readIdentity(file: File): DeviceIdentity? {
return try {
if (!file.exists()) return null
val raw = file.readText(Charsets.UTF_8)
val decoded = json.decodeFromString(DeviceIdentity.serializer(), raw)
if (decoded.deviceId.isBlank() ||
decoded.publicKeyRawBase64.isBlank() ||
decoded.privateKeyPkcs8Base64.isBlank()
) {
null
} else {
decoded
private fun migrateLegacyIdentity(): DeviceIdentity {
val raw =
try {
legacyIdentityFile.readText(Charsets.UTF_8)
} catch (error: Throwable) {
throw IllegalStateException("Failed to read legacy OpenClaw device identity.", error)
}
val identity =
runCatching { json.decodeFromString(DeviceIdentity.serializer(), raw) }
.getOrNull()
?.let(::normalizeRawIdentity)
?: throw IllegalStateException(
"Legacy OpenClaw device identity is invalid. Run openclaw doctor --fix.",
)
save(identity)
legacyIdentityFile.delete()
return identity
}
private fun normalizeRawIdentity(identity: DeviceIdentity): DeviceIdentity? =
try {
if (identity.publicKeyRawBase64.isBlank() || identity.privateKeyPkcs8Base64.isBlank()) {
return null
}
val publicRaw = Base64.decode(identity.publicKeyRawBase64, Base64.DEFAULT)
val privateDer = Base64.decode(identity.privateKeyPkcs8Base64, Base64.DEFAULT)
if (publicRaw.size != ED25519_KEY_SIZE || privateDer.isEmpty()) {
return null
}
val normalized = identity.copy(deviceId = sha256Hex(publicRaw))
if (!hasMatchingKeyPair(normalized)) {
return null
}
normalized
} catch (_: Throwable) {
null
}
private fun readIdentity(row: OpenClawSQLiteDeviceIdentityRow): DeviceIdentity? =
PersistedDeviceIdentity(
deviceId = row.deviceId,
publicKeyPem = row.publicKeyPem,
privateKeyPem = row.privateKeyPem,
createdAtMs = row.createdAtMs,
).toRuntimeIdentity()?.takeIf(::hasMatchingKeyPair)
private fun hasMatchingKeyPair(identity: DeviceIdentity): Boolean {
val signature = signPayload(KEYPAIR_VALIDATION_PAYLOAD, identity) ?: return false
return verifySelfSignature(KEYPAIR_VALIDATION_PAYLOAD, signature, identity)
}
private fun save(identity: DeviceIdentity) {
try {
identityFile.parentFile?.mkdirs()
val encoded = json.encodeToString(DeviceIdentity.serializer(), identity)
identityFile.writeText(encoded, Charsets.UTF_8)
} catch (_: Throwable) {
// best-effort only
}
val persisted = PersistedDeviceIdentity.fromRuntimeIdentity(identity)
stateStore.writeDeviceIdentity(
OpenClawSQLiteDeviceIdentityRow(
deviceId = persisted.deviceId,
publicKeyPem = persisted.publicKeyPem,
privateKeyPem = persisted.privateKeyPem,
createdAtMs = persisted.createdAtMs,
),
identityKey = IDENTITY_KEY,
)
}
private fun generate(): DeviceIdentity {
@@ -168,14 +209,6 @@ class DeviceIdentityStore(
)
}
private fun deriveDeviceId(publicKeyRawBase64: String): String? =
try {
val raw = Base64.decode(publicKeyRawBase64, Base64.DEFAULT)
sha256Hex(raw)
} catch (_: Throwable) {
null
}
private fun sha256Hex(data: ByteArray): String {
val digest = MessageDigest.getInstance("SHA-256").digest(data)
val out = CharArray(digest.size * 2)
@@ -194,7 +227,92 @@ class DeviceIdentityStore(
Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING,
)
@Serializable
private data class PersistedDeviceIdentity(
val version: Int = 1,
val deviceId: String,
val publicKeyPem: String,
val privateKeyPem: String,
val createdAtMs: Long,
) {
fun toRuntimeIdentity(): DeviceIdentity? {
if (version != 1 || deviceId.isBlank() || publicKeyPem.isBlank() || privateKeyPem.isBlank()) {
return null
}
val publicDer = decodePem(publicKeyPem, "PUBLIC KEY") ?: return null
if (!publicDer.startsWith(PUBLIC_KEY_INFO_PREFIX)) return null
val publicRaw = publicDer.copyOfRange(PUBLIC_KEY_INFO_PREFIX.size, publicDer.size)
if (publicRaw.size != ED25519_KEY_SIZE) return null
val derivedDeviceId = sha256HexStatic(publicRaw)
if (derivedDeviceId != deviceId.lowercase()) return null
val privateDer = decodePem(privateKeyPem, "PRIVATE KEY") ?: return null
return DeviceIdentity(
deviceId = derivedDeviceId,
publicKeyRawBase64 = Base64.encodeToString(publicRaw, Base64.NO_WRAP),
privateKeyPkcs8Base64 = Base64.encodeToString(privateDer, Base64.NO_WRAP),
createdAtMs = createdAtMs,
)
}
companion object {
fun fromRuntimeIdentity(identity: DeviceIdentity): PersistedDeviceIdentity {
val publicRaw = Base64.decode(identity.publicKeyRawBase64, Base64.DEFAULT)
val privateDer = Base64.decode(identity.privateKeyPkcs8Base64, Base64.DEFAULT)
return PersistedDeviceIdentity(
deviceId = identity.deviceId,
publicKeyPem = encodePem("PUBLIC KEY", PUBLIC_KEY_INFO_PREFIX + publicRaw),
privateKeyPem = encodePem("PRIVATE KEY", privateDer),
createdAtMs = identity.createdAtMs,
)
}
}
}
companion object {
private const val IDENTITY_KEY = "default"
private const val KEYPAIR_VALIDATION_PAYLOAD = "openclaw-device-identity-keypair-validation"
private const val ED25519_KEY_SIZE = 32
private val HEX = "0123456789abcdef".toCharArray()
private val PUBLIC_KEY_INFO_PREFIX =
byteArrayOf(0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00)
private fun ByteArray.startsWith(prefix: ByteArray): Boolean = size >= prefix.size && prefix.indices.all { this[it] == prefix[it] }
private fun encodePem(
label: String,
bytes: ByteArray,
): String {
val body = Base64.encodeToString(bytes, Base64.NO_WRAP)
val wrapped = body.chunked(64).joinToString("\n")
return "-----BEGIN $label-----\n$wrapped\n-----END $label-----\n"
}
private fun decodePem(
pem: String,
label: String,
): ByteArray? {
val header = "-----BEGIN $label-----"
val footer = "-----END $label-----"
val trimmed = pem.trim()
if (!trimmed.startsWith(header) || !trimmed.endsWith(footer)) return null
val body =
trimmed
.removePrefix(header)
.removeSuffix(footer)
.replace("\\s".toRegex(), "")
return runCatching { Base64.decode(body, Base64.DEFAULT) }.getOrNull()
}
private fun sha256HexStatic(data: ByteArray): String {
val digest = MessageDigest.getInstance("SHA-256").digest(data)
val out = CharArray(digest.size * 2)
var i = 0
for (byte in digest) {
val v = byte.toInt() and 0xff
out[i++] = HEX[v ushr 4]
out[i++] = HEX[v and 0x0f]
}
return String(out)
}
}
}

View File

@@ -44,7 +44,7 @@ internal fun isLoopbackGatewayHost(
return isMappedIpv4 && address[12] == 127.toByte()
}
internal fun isPrivateLanGatewayHost(
internal fun isLocalCleartextGatewayHost(
rawHost: String?,
allowEmulatorBridgeAlias: Boolean = isAndroidEmulatorRuntime(),
): Boolean {

View File

@@ -632,7 +632,7 @@ class GatewaySession(
private fun shouldPersistBootstrapHandoffTokens(authSource: GatewayConnectAuthSource): Boolean {
if (authSource != GatewayConnectAuthSource.BOOTSTRAP_TOKEN) return false
if (isLoopbackGatewayHost(endpoint.host)) return true
if (isLocalCleartextGatewayHost(endpoint.host)) return true
return tls != null
}
@@ -1212,9 +1212,7 @@ class GatewaySession(
endpoint: GatewayEndpoint,
tls: GatewayTlsParams?,
): Boolean {
if (isLoopbackGatewayHost(endpoint.host)) {
return true
}
if (isLocalCleartextGatewayHost(endpoint.host)) return true
return tls?.expectedFingerprint?.trim()?.isNotEmpty() == true
}
}

View File

@@ -0,0 +1,310 @@
package ai.openclaw.app.gateway
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import java.io.File
data class OpenClawSQLiteDeviceIdentityRow(
val deviceId: String,
val publicKeyPem: String,
val privateKeyPem: String,
val createdAtMs: Long,
)
data class OpenClawSQLiteDeviceAuthTokenRow(
val deviceId: String,
val role: String,
val token: String,
val scopesJson: String,
val updatedAtMs: Long,
)
class OpenClawSQLiteStateStore(
context: Context,
) {
private val appContext = context.applicationContext
private val databaseFile = File(appContext.filesDir, "openclaw/state/openclaw.sqlite")
fun databaseFile(): File = databaseFile
@Synchronized
fun readDeviceIdentity(identityKey: String = "default"): OpenClawSQLiteDeviceIdentityRow? {
if (!databaseFile.exists()) return null
return openDatabase().use { db ->
db
.rawQuery(
"""
SELECT device_id, public_key_pem, private_key_pem, created_at_ms
FROM device_identities
WHERE identity_key = ?
""".trimIndent(),
arrayOf(identityKey),
).use { cursor ->
if (!cursor.moveToFirst()) return@use null
OpenClawSQLiteDeviceIdentityRow(
deviceId = cursor.getString(0),
publicKeyPem = cursor.getString(1),
privateKeyPem = cursor.getString(2),
createdAtMs = cursor.getLong(3),
)
}
}
}
@Synchronized
fun writeDeviceIdentity(
identity: OpenClawSQLiteDeviceIdentityRow,
identityKey: String = "default",
updatedAtMs: Long = System.currentTimeMillis(),
) {
openDatabase().use { db ->
db.inWriteTransaction {
val values =
ContentValues().apply {
put("identity_key", identityKey)
put("device_id", identity.deviceId)
put("public_key_pem", identity.publicKeyPem)
put("private_key_pem", identity.privateKeyPem)
put("created_at_ms", identity.createdAtMs)
put("updated_at_ms", updatedAtMs)
}
db.insertWithOnConflict("device_identities", null, values, SQLiteDatabase.CONFLICT_REPLACE)
}
}
}
@Synchronized
fun readDeviceAuthToken(
deviceId: String,
role: String,
): OpenClawSQLiteDeviceAuthTokenRow? {
if (!databaseFile.exists()) return null
return openDatabase().use { db ->
db
.rawQuery(
"""
SELECT device_id, role, token, scopes_json, updated_at_ms
FROM device_auth_tokens
WHERE device_id = ? AND role = ?
""".trimIndent(),
arrayOf(deviceId, role),
).use { cursor ->
if (!cursor.moveToFirst()) return@use null
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = cursor.getString(0),
role = cursor.getString(1),
token = cursor.getString(2),
scopesJson = cursor.getString(3),
updatedAtMs = cursor.getLong(4),
)
}
}
}
@Synchronized
fun readLatestDeviceAuthDeviceId(): String? {
if (!databaseFile.exists()) return null
return openDatabase().use { db ->
db
.rawQuery(
"""
SELECT device_id
FROM device_auth_tokens
ORDER BY updated_at_ms DESC, device_id ASC
LIMIT 1
""".trimIndent(),
emptyArray(),
).use { cursor ->
if (cursor.moveToFirst()) cursor.getString(0) else null
}
}
}
@Synchronized
fun upsertDeviceAuthToken(row: OpenClawSQLiteDeviceAuthTokenRow) {
openDatabase().use { db ->
db.inWriteTransaction {
val values =
ContentValues().apply {
put("device_id", row.deviceId)
put("role", row.role)
put("token", row.token)
put("scopes_json", row.scopesJson)
put("updated_at_ms", row.updatedAtMs)
}
db.insertWithOnConflict("device_auth_tokens", null, values, SQLiteDatabase.CONFLICT_REPLACE)
}
}
}
@Synchronized
fun deleteDeviceAuthToken(
deviceId: String,
role: String,
) {
openDatabase().use { db ->
db.inWriteTransaction {
db.delete("device_auth_tokens", "device_id = ? AND role = ?", arrayOf(deviceId, role))
}
}
}
@Synchronized
fun deleteAllDeviceAuthTokens() {
openDatabase().use { db ->
db.inWriteTransaction {
db.delete("device_auth_tokens", null, null)
}
}
}
@Synchronized
fun readRecentNotificationPackages(limit: Int = 64): List<String> {
if (!databaseFile.exists()) return emptyList()
return openDatabase().use { db ->
db
.rawQuery(
"""
SELECT package_name
FROM android_notification_recent_packages
ORDER BY sort_order ASC, package_name ASC
LIMIT ?
""".trimIndent(),
arrayOf(limit.coerceAtLeast(0).toString()),
).use { cursor ->
val packages = mutableListOf<String>()
while (cursor.moveToNext()) {
packages += cursor.getString(0)
}
packages
}
}
}
@Synchronized
fun replaceRecentNotificationPackages(
packageNames: List<String>,
limit: Int = 64,
updatedAtMs: Long = System.currentTimeMillis(),
) {
val normalized =
packageNames
.asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.distinct()
.take(limit.coerceAtLeast(0))
.toList()
openDatabase().use { db ->
db.inWriteTransaction {
db.delete("android_notification_recent_packages", null, null)
normalized.forEachIndexed { index, packageName ->
val values =
ContentValues().apply {
put("package_name", packageName)
put("sort_order", index)
put("updated_at_ms", updatedAtMs)
}
db.insertWithOnConflict(
"android_notification_recent_packages",
null,
values,
SQLiteDatabase.CONFLICT_REPLACE,
)
}
}
}
}
private fun openDatabase(): SQLiteDatabase {
databaseFile.parentFile?.mkdirs()
val db =
SQLiteDatabase.openDatabase(
databaseFile.absolutePath,
null,
SQLiteDatabase.OPEN_READWRITE or SQLiteDatabase.CREATE_IF_NECESSARY,
)
configure(db)
return db
}
private fun configure(db: SQLiteDatabase) {
db.enableWriteAheadLogging()
executePragma(db, "PRAGMA synchronous = NORMAL")
executePragma(db, "PRAGMA busy_timeout = 30000")
executePragma(db, "PRAGMA foreign_keys = ON")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS device_identities (
identity_key TEXT NOT NULL PRIMARY KEY,
device_id TEXT NOT NULL,
public_key_pem TEXT NOT NULL,
private_key_pem TEXT NOT NULL,
created_at_ms INTEGER NOT NULL,
updated_at_ms INTEGER NOT NULL
)
""".trimIndent(),
)
db.execSQL(
"""
CREATE INDEX IF NOT EXISTS idx_device_identities_device
ON device_identities(device_id, updated_at_ms DESC)
""".trimIndent(),
)
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS device_auth_tokens (
device_id TEXT NOT NULL,
role TEXT NOT NULL,
token TEXT NOT NULL,
scopes_json TEXT NOT NULL,
updated_at_ms INTEGER NOT NULL,
PRIMARY KEY (device_id, role)
)
""".trimIndent(),
)
db.execSQL(
"""
CREATE INDEX IF NOT EXISTS idx_device_auth_tokens_updated
ON device_auth_tokens(updated_at_ms DESC, device_id, role)
""".trimIndent(),
)
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS android_notification_recent_packages (
package_name TEXT NOT NULL PRIMARY KEY,
sort_order INTEGER NOT NULL,
updated_at_ms INTEGER NOT NULL
)
""".trimIndent(),
)
db.execSQL(
"""
CREATE INDEX IF NOT EXISTS idx_android_notification_recent_packages_order
ON android_notification_recent_packages(sort_order, package_name)
""".trimIndent(),
)
}
private fun executePragma(
db: SQLiteDatabase,
sql: String,
) {
db.rawQuery(sql, null).use { cursor ->
if (cursor.moveToFirst()) {
// Some PRAGMA assignments return their new value; reading it closes the cursor cleanly.
}
}
}
private inline fun SQLiteDatabase.inWriteTransaction(body: () -> Unit) {
beginTransaction()
try {
body()
setTransactionSuccessful()
} finally {
endTransaction()
}
}
}

View File

@@ -3,7 +3,6 @@ package ai.openclaw.app.node
import ai.openclaw.app.BuildConfig
import ai.openclaw.app.CameraHudKind
import ai.openclaw.app.gateway.GatewaySession
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
@@ -19,7 +18,6 @@ internal const val CAMERA_CLIP_MAX_RAW_BYTES: Long = 18L * 1024L * 1024L
internal fun isCameraClipWithinPayloadLimit(rawBytes: Long): Boolean = rawBytes in 0L..CAMERA_CLIP_MAX_RAW_BYTES
class CameraHandler(
private val appContext: Context,
private val camera: CameraCaptureManager,
private val externalAudioCaptureActive: MutableStateFlow<Boolean>,
private val showCameraHud: (message: String, kind: CameraHudKind, autoHideMs: Long?) -> Unit,
@@ -54,16 +52,12 @@ class CameraHandler(
}
suspend fun handleSnap(paramsJson: String?): GatewaySession.InvokeResult {
val logFile = if (BuildConfig.DEBUG) java.io.File(appContext.cacheDir, "camera_debug.log") else null
fun camLog(msg: String) {
if (!BuildConfig.DEBUG) return
val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.US).format(java.util.Date())
logFile?.appendText("[$ts] $msg\n")
android.util.Log.w("openclaw", "camera.snap: $msg")
android.util.Log.w("openclaw", "camera.snap[$ts]: $msg")
}
try {
logFile?.writeText("") // clear
camLog("starting, params=$paramsJson")
camLog("calling showCameraHud")
showCameraHud("Taking photo…", CameraHudKind.Photo, null)
@@ -93,18 +87,14 @@ class CameraHandler(
}
suspend fun handleClip(paramsJson: String?): GatewaySession.InvokeResult {
val clipLogFile = if (BuildConfig.DEBUG) java.io.File(appContext.cacheDir, "camera_debug.log") else null
fun clipLog(msg: String) {
if (!BuildConfig.DEBUG) return
val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.US).format(java.util.Date())
clipLogFile?.appendText("[CLIP $ts] $msg\n")
android.util.Log.w("openclaw", "camera.clip: $msg")
android.util.Log.w("openclaw", "camera.clip[$ts]: $msg")
}
val includeAudio = parseIncludeAudio(paramsJson) ?: true
if (includeAudio) externalAudioCaptureActive.value = true
try {
clipLogFile?.writeText("") // clear
clipLog("starting, params=$paramsJson includeAudio=$includeAudio")
clipLog("calling showCameraHud")
showCameraHud("Recording…", CameraHudKind.Recording, null)

View File

@@ -8,6 +8,7 @@ import ai.openclaw.app.gateway.GatewayClientInfo
import ai.openclaw.app.gateway.GatewayConnectOptions
import ai.openclaw.app.gateway.GatewayEndpoint
import ai.openclaw.app.gateway.GatewayTlsParams
import ai.openclaw.app.gateway.isLocalCleartextGatewayHost
import ai.openclaw.app.gateway.isLoopbackGatewayHost
import android.os.Build
@@ -35,7 +36,12 @@ class ConnectionManager(
val stableId = endpoint.stableId
val stored = storedFingerprint?.trim().takeIf { !it.isNullOrEmpty() }
val isManual = stableId.startsWith("manual|")
val cleartextAllowedHost = isLoopbackGatewayHost(endpoint.host)
val cleartextAllowedHost =
if (isManual) {
isLocalCleartextGatewayHost(endpoint.host)
} else {
isLoopbackGatewayHost(endpoint.host)
}
if (isManual) {
if (!manualTlsEnabled && cleartextAllowedHost) return null

View File

@@ -3,13 +3,16 @@ package ai.openclaw.app.node
import ai.openclaw.app.BuildConfig
import ai.openclaw.app.gateway.DeviceIdentityStore
import ai.openclaw.app.gateway.GatewaySession
import android.content.Context
import kotlinx.serialization.json.JsonPrimitive
import java.io.InputStream
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
private const val LOGCAT_PATH = "/system/bin/logcat"
private const val LOGCAT_TIMEOUT_MS = 4_000L
private const val LOGCAT_MAX_CHARS = 128_000
class DebugHandler(
private val appContext: Context,
private val identityStore: DeviceIdentityStore,
) {
fun handleEd25519(): GatewaySession.InvokeResult {
@@ -81,24 +84,14 @@ class DebugHandler(
val pid = android.os.Process.myPid()
val rt = Runtime.getRuntime()
val info = "v6 pid=$pid thread=${Thread.currentThread().name} free=${rt.freeMemory() / 1024}K total=${rt.totalMemory() / 1024}K max=${rt.maxMemory() / 1024}K uptime=${android.os.SystemClock.elapsedRealtime() / 1000}s sdk=${android.os.Build.VERSION.SDK_INT} device=${android.os.Build.MODEL}\n"
// Run logcat on current dispatcher thread (no withContext) with file redirect
// Run logcat on current dispatcher thread; output is bounded by -t and never staged to disk.
val logResult =
try {
val tmpFile = java.io.File(appContext.cacheDir, "debug_logs.txt")
if (tmpFile.exists()) tmpFile.delete()
val pb = ProcessBuilder(LOGCAT_PATH, "-d", "-t", "200", "--pid=$pid")
pb.redirectOutput(tmpFile)
pb.redirectErrorStream(true)
val proc = pb.start()
val finished = proc.waitFor(4, java.util.concurrent.TimeUnit.SECONDS)
if (!finished) proc.destroyForcibly()
val raw =
if (tmpFile.exists() && tmpFile.length() > 0) {
tmpFile.readText().take(128000)
} else {
"(no output, finished=$finished, exists=${tmpFile.exists()})"
}
tmpFile.delete()
val (finished, raw) = collectProcessOutput(proc, LOGCAT_TIMEOUT_MS, LOGCAT_MAX_CHARS)
val normalizedRaw = raw.ifBlank { "(no output, finished=$finished)" }
val spamPatterns =
listOf(
"setRequestedFrameRate",
@@ -119,7 +112,7 @@ class DebugHandler(
"IncorrectContextUseViolation",
)
val sb = StringBuilder()
for (line in raw.lineSequence()) {
for (line in normalizedRaw.lineSequence()) {
if (line.isBlank()) continue
if (spamPatterns.any { line.contains(it) }) continue
if (sb.length + line.length > 16000) {
@@ -129,18 +122,55 @@ class DebugHandler(
if (sb.isNotEmpty()) sb.append('\n')
sb.append(line)
}
sb.toString().ifEmpty { "(all ${raw.lines().size} lines filtered as spam)" }
sb.toString().ifEmpty { "(all ${normalizedRaw.lines().size} lines filtered as spam)" }
} catch (e: Throwable) {
"(logcat error: ${e::class.java.simpleName}: ${e.message})"
}
// Also include camera debug log if it exists
val camLogFile = java.io.File(appContext.cacheDir, "camera_debug.log")
val camLog =
if (camLogFile.exists() && camLogFile.length() > 0) {
"\n--- camera_debug.log ---\n" + camLogFile.readText().take(4000)
} else {
""
}
return GatewaySession.InvokeResult.ok("""{"logs":${JsonPrimitive(info + logResult + camLog)}}""")
return GatewaySession.InvokeResult.ok("""{"logs":${JsonPrimitive(info + logResult)}}""")
}
}
internal fun collectProcessOutput(
process: Process,
timeoutMs: Long,
maxChars: Int,
): Pair<Boolean, String> {
val output = AtomicReference("")
val failure = AtomicReference<Throwable?>(null)
val reader =
Thread({
try {
output.set(readBoundedText(process.inputStream, maxChars))
} catch (error: Throwable) {
failure.set(error)
}
}, "openclaw-debug-output-reader")
reader.isDaemon = true
reader.start()
val finished = process.waitFor(timeoutMs, TimeUnit.MILLISECONDS)
if (!finished) {
process.destroyForcibly()
}
reader.join(1_000)
failure.get()?.let { throw it }
return finished to output.get()
}
private fun readBoundedText(
stream: InputStream,
maxChars: Int,
): String =
stream.bufferedReader().use { reader ->
val out = StringBuilder(minOf(maxChars, 8192))
val buffer = CharArray(4096)
while (true) {
val read = reader.read(buffer)
if (read < 0) break
val remaining = maxChars - out.length
if (remaining > 0) {
out.append(buffer, 0, minOf(read, remaining))
}
}
out.toString()
}

View File

@@ -3,6 +3,7 @@ package ai.openclaw.app.node
import ai.openclaw.app.NotificationBurstLimiter
import ai.openclaw.app.SecurePrefs
import ai.openclaw.app.allowsPackage
import ai.openclaw.app.gateway.OpenClawSQLiteStateStore
import ai.openclaw.app.isWithinQuietHours
import android.app.Notification
import android.app.NotificationManager
@@ -12,7 +13,6 @@ import android.content.Context
import android.content.Intent
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import androidx.core.content.edit
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
@@ -278,8 +278,9 @@ class DeviceNotificationListenerService : NotificationListenerService() {
}
companion object {
private const val recentPackagesPref = "notifications.forwarding.recentPackages"
private const val legacyRecentPackagesPref = "notifications.recentPackages"
private const val notificationsPrefsPrefix = "notifications."
private const val recentPackagesPref = notificationsPrefsPrefix + "forwarding.recentPackages"
private const val legacyRecentPackagesPref = notificationsPrefsPrefix + "recentPackages"
private const val recentPackagesLimit = 64
@Volatile private var activeService: DeviceNotificationListenerService? = null
@@ -292,31 +293,45 @@ class DeviceNotificationListenerService : NotificationListenerService() {
nodeEventSink = sink
}
private fun recentPackagesPrefs(context: Context) = context.applicationContext.getSharedPreferences("openclaw.secure", Context.MODE_PRIVATE)
private fun recentPackagesPrefs(context: Context) =
context.applicationContext
.getSharedPreferences("openclaw.secure", Context.MODE_PRIVATE)
private fun migrateLegacyRecentPackagesIfNeeded(context: Context) {
private fun migrateLegacyRecentPackagesIfNeeded(
context: Context,
stateStore: OpenClawSQLiteStateStore,
): List<String> {
val prefs = recentPackagesPrefs(context)
val hasNew = prefs.contains(recentPackagesPref)
val legacy = prefs.getString(legacyRecentPackagesPref, null)?.trim().orEmpty()
if (!hasNew && legacy.isNotEmpty()) {
prefs.edit {
putString(recentPackagesPref, legacy)
remove(legacyRecentPackagesPref)
}
} else if (hasNew && prefs.contains(legacyRecentPackagesPref)) {
prefs.edit { remove(legacyRecentPackagesPref) }
val raw =
prefs.getString(recentPackagesPref, null)?.trim()?.takeIf { it.isNotEmpty() }
?: prefs.getString(legacyRecentPackagesPref, null)?.trim().orEmpty()
val packages =
raw
.split(',')
.map { it.trim() }
.filter { it.isNotEmpty() }
.distinct()
.take(recentPackagesLimit)
if (packages.isNotEmpty()) {
stateStore.replaceRecentNotificationPackages(packages, recentPackagesLimit)
}
if (prefs.contains(recentPackagesPref) || prefs.contains(legacyRecentPackagesPref)) {
prefs
.edit()
.remove(recentPackagesPref)
.remove(legacyRecentPackagesPref)
.apply()
}
return packages
}
fun recentPackages(context: Context): List<String> {
migrateLegacyRecentPackagesIfNeeded(context)
val prefs = recentPackagesPrefs(context)
val stored = prefs.getString(recentPackagesPref, null).orEmpty()
return stored
.split(',')
.map { it.trim() }
.filter { it.isNotEmpty() }
.distinct()
val stateStore = OpenClawSQLiteStateStore(context)
val stored = stateStore.readRecentNotificationPackages(recentPackagesLimit)
if (stored.isNotEmpty()) {
return stored
}
return migrateLegacyRecentPackagesIfNeeded(context, stateStore)
}
fun isAccessEnabled(context: Context): Boolean {
@@ -366,18 +381,13 @@ class DeviceNotificationListenerService : NotificationListenerService() {
val service = activeService ?: return
val normalized = packageName?.trim().orEmpty()
if (normalized.isEmpty() || normalized == service.packageName) return
migrateLegacyRecentPackagesIfNeeded(service.applicationContext)
val prefs = recentPackagesPrefs(service.applicationContext)
val existing =
prefs
.getString(recentPackagesPref, null)
.orEmpty()
.split(',')
.map { it.trim() }
.filter { it.isNotEmpty() && it != normalized }
recentPackages(service.applicationContext)
.filter { it != normalized }
.take(recentPackagesLimit - 1)
val updated = listOf(normalized) + existing
prefs.edit { putString(recentPackagesPref, updated.joinToString(",")) }
OpenClawSQLiteStateStore(service.applicationContext)
.replaceRecentNotificationPackages(updated, recentPackagesLimit)
}
}

View File

@@ -1,6 +1,6 @@
package ai.openclaw.app.ui
import ai.openclaw.app.gateway.isLoopbackGatewayHost
import ai.openclaw.app.gateway.isLocalCleartextGatewayHost
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
@@ -56,9 +56,9 @@ internal data class GatewayScannedSetupCodeResult(
private val gatewaySetupJson = Json { ignoreUnknownKeys = true }
private const val remoteGatewaySecurityRule =
"Tailscale and public mobile nodes require wss:// or Tailscale Serve. ws:// is allowed only for localhost and the Android emulator."
"Public gateways require wss:// or Tailscale Serve. ws:// is allowed for localhost, the Android emulator, and private LAN IPs."
private const val remoteGatewaySecurityFix =
"Use localhost/the Android emulator, or enable Tailscale Serve / expose a wss:// gateway URL."
"Use a private LAN IP for local setup, or enable Tailscale Serve / expose a wss:// gateway URL for remote access."
internal fun resolveGatewayConnectConfig(
useSetupCode: Boolean,
@@ -147,7 +147,7 @@ internal fun parseGatewayEndpointResult(rawInput: String): GatewayEndpointParseR
return GatewayEndpointParseResult(error = GatewayEndpointValidationError.INVALID_URL)
}
val tls = scheme == "wss" || scheme == "https"
if (!tls && !isLoopbackGatewayHost(host)) {
if (!tls && !isLocalCleartextGatewayHost(host)) {
return GatewayEndpointParseResult(error = GatewayEndpointValidationError.INSECURE_REMOTE_URL)
}
val defaultPort = if (tls) 443 else 18789

View File

@@ -51,7 +51,7 @@ internal fun buildGatewayDiagnosticsReport(
Please:
- pick one route only: same machine, same LAN, Tailscale, or public URL
- classify this as pairing/auth, TLS trust, wrong advertised route, wrong address/port, or gateway down
- remember: Tailscale/public mobile routes require wss:// or Tailscale Serve; ws:// is loopback-only
- remember: public routes require wss:// or Tailscale Serve; ws:// is allowed for localhost, the Android emulator, and private LAN IPs
- quote the exact app status/error below
- tell me whether `openclaw devices list` should show a pending pairing request
- if more signal is needed, ask for `openclaw qr --json`, `openclaw devices list`, and `openclaw nodes status`

View File

@@ -11,10 +11,6 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// ---------------------------------------------------------------------------
// MobileColors semantic color tokens with light + dark variants
// ---------------------------------------------------------------------------
internal data class MobileColors(
val surface: Color,
val surfaceStrong: Color,
@@ -108,9 +104,6 @@ internal object MobileColorsAccessor {
@Composable get() = LocalMobileColors.current
}
// ---------------------------------------------------------------------------
// Backward-compatible top-level accessors (composable getters)
// ---------------------------------------------------------------------------
// These allow existing call sites to keep using `mobileSurface`, `mobileText`, etc.
// without converting every file at once. Each resolves to the themed value.
@@ -149,10 +142,6 @@ internal val mobileBackgroundGradient: Brush
)
}
// ---------------------------------------------------------------------------
// Typography tokens (theme-independent)
// ---------------------------------------------------------------------------
internal val mobileFontFamily =
FontFamily(
Font(resId = R.font.manrope_400_regular, weight = FontWeight.Normal),

View File

@@ -270,7 +270,7 @@ private fun providerPriority(provider: String): Int =
"google" -> 2
"openrouter" -> 3
"ollama", "ollama-local" -> 4
"codex", "openai-codex" -> 5
"codex" -> 5
else -> 100
}

View File

@@ -130,9 +130,10 @@ class GatewayBootstrapAuthTest {
android.content.Context.MODE_PRIVATE,
)
val prefs = SecurePrefs(app, securePrefsOverride = securePrefs)
val runtime = NodeRuntime(app, prefs)
val authStore = DeviceAuthStore(app, legacyPrefsOverride = prefs)
val runtime = NodeRuntime(app, prefs, deviceAuthStore = authStore)
val deviceId = DeviceIdentityStore(app).loadOrCreate().deviceId
DeviceAuthStore(prefs).saveToken(deviceId, "operator", "bootstrap-operator-token")
authStore.saveToken(deviceId, "operator", "bootstrap-operator-token")
writeField(runtime, "operatorStatusText", "Connecting…")
invokeMaybeStartOperatorSessionAfterNodeConnect(
@@ -192,6 +193,7 @@ class GatewayBootstrapAuthTest {
app,
prefs,
tlsFingerprintProbe = { _, _ -> GatewayTlsProbeResult(fingerprintSha256 = "fp:1") },
deviceAuthStore = DeviceAuthStore(app, legacyPrefsOverride = prefs),
)
val endpoint = GatewayEndpoint.manual(host = "gateway.example", port = 18789)
val explicitAuth =
@@ -326,9 +328,9 @@ class GatewayBootstrapAuthTest {
android.content.Context.MODE_PRIVATE,
)
val prefs = SecurePrefs(app, securePrefsOverride = securePrefs)
val runtime = NodeRuntime(app, prefs)
val authStore = DeviceAuthStore(app, legacyPrefsOverride = prefs)
val runtime = NodeRuntime(app, prefs, deviceAuthStore = authStore)
val deviceId = DeviceIdentityStore(app).loadOrCreate().deviceId
val authStore = DeviceAuthStore(prefs)
prefs.setGatewayToken("stale-shared-token")
prefs.setGatewayBootstrapToken("stale-bootstrap-token")
prefs.setGatewayPassword("stale-password")

View File

@@ -4,27 +4,28 @@ import ai.openclaw.app.SecurePrefs
import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import java.util.UUID
import java.io.File
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [34])
class DeviceAuthStoreTest {
@Before
fun resetState() {
File(RuntimeEnvironment.getApplication().filesDir, "openclaw").deleteRecursively()
}
@Test
fun saveTokenPersistsNormalizedScopesMetadata() {
fun saveTokenPersistsNormalizedScopesMetadataInSQLite() {
val app = RuntimeEnvironment.getApplication()
val securePrefs =
app.getSharedPreferences(
"openclaw.node.secure.test.${UUID.randomUUID()}",
Context.MODE_PRIVATE,
)
val prefs = SecurePrefs(app, securePrefsOverride = securePrefs)
val store = DeviceAuthStore(prefs)
val store = DeviceAuthStore(app, legacyPrefsOverride = legacyPrefs(app))
store.saveToken(
deviceId = " Device-1 ",
@@ -39,25 +40,255 @@ class DeviceAuthStoreTest {
assertEquals("operator", entry?.role)
assertEquals(listOf("operator.read", "operator.write"), entry?.scopes)
assertTrue((entry?.updatedAtMs ?: 0L) > 0L)
val row = OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "operator")
assertNotNull(row)
assertEquals("__openclaw_secure_prefs__", row?.token)
assertEquals("""["operator.read","operator.write"]""", row?.scopesJson)
}
@Test
fun loadEntryReadsLegacyTokenWithoutMetadata() {
fun clearTokenUpdatesSQLiteStore() {
val app = RuntimeEnvironment.getApplication()
val securePrefs =
app.getSharedPreferences(
"openclaw.node.secure.test.${UUID.randomUUID()}",
Context.MODE_PRIVATE,
)
val prefs = SecurePrefs(app, securePrefsOverride = securePrefs)
prefs.putString("gateway.deviceToken.device-1.operator", "legacy-token")
val store = DeviceAuthStore(prefs)
val store = DeviceAuthStore(app, legacyPrefsOverride = legacyPrefs(app))
store.saveToken("device-1", "operator", "operator-token", scopes = listOf("operator.read"))
store.clearToken("device-1", "operator")
assertNull(store.loadEntry("device-1", "operator"))
assertNull(OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "operator"))
}
@Test
fun loadEntryMigratesLegacySecurePrefsToken() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
prefs.putString("gateway.deviceToken.device-1.operator", " operator-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.operator",
"""{"scopes":["operator.write"," operator.read ","operator.write"],"updatedAtMs":1700000000000}""",
)
val entry = DeviceAuthStore(app, legacyPrefsOverride = prefs).loadEntry(" Device-1 ", " Operator ")
val entry = store.loadEntry("device-1", "operator")
assertNotNull(entry)
assertEquals("legacy-token", entry?.token)
assertEquals("operator-token", entry?.token)
assertEquals("operator", entry?.role)
assertEquals(emptyList<String>(), entry?.scopes)
assertEquals(0L, entry?.updatedAtMs)
assertEquals(listOf("operator.read", "operator.write"), entry?.scopes)
assertEquals(1700000000000L, entry?.updatedAtMs)
assertEquals("operator-token", prefs.getString("gateway.deviceToken.device-1.operator"))
assertNull(prefs.getString("gateway.deviceTokenMeta.device-1.operator"))
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "operator")?.token,
)
}
@Test
fun loadEntryMigratesAllLegacyRolesBeforeSQLiteRowsExist() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
prefs.putString("gateway.deviceToken.device-1.operator", " operator-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.operator",
"""{"scopes":["operator.write"],"updatedAtMs":1700000000000}""",
)
prefs.putString("gateway.deviceToken.device-1.node", " node-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.node",
"""{"scopes":["node.connect"],"updatedAtMs":1700000000001}""",
)
val store = DeviceAuthStore(app, legacyPrefsOverride = prefs)
val operator = store.loadEntry("device-1", "operator")
val node = store.loadEntry("device-1", "node")
assertEquals("operator-token", operator?.token)
assertEquals(listOf("operator.write"), operator?.scopes)
assertEquals("node-token", node?.token)
assertEquals(listOf("node.connect"), node?.scopes)
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "operator")?.token,
)
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "node")?.token,
)
}
@Test
fun loadEntryDoesNotResurrectLegacyRoleAfterSQLiteRowsExist() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
val store = DeviceAuthStore(app, legacyPrefsOverride = prefs)
store.saveToken("device-1", "operator", "operator-token", scopes = listOf("operator.write"))
prefs.putString("gateway.deviceToken.device-1.admin", " stale-admin-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.admin",
"""{"scopes":["admin"],"updatedAtMs":1700000000000}""",
)
store.saveToken("device-1", "operator", "operator-token-2", scopes = listOf("operator.write"))
assertNull(store.loadEntry("device-1", "admin"))
assertNull(OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "admin"))
assertNull(prefs.getString("gateway.deviceToken.device-1.admin"))
assertNull(prefs.getString("gateway.deviceTokenMeta.device-1.admin"))
}
@Test
fun saveTokenMigratesSameDeviceLegacyRolesBeforeFirstSqliteWrite() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
prefs.putString("gateway.deviceToken.device-1.operator", " old-operator-token ")
prefs.putString("gateway.deviceToken.device-1.node", " node-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.node",
"""{"scopes":["node.connect"],"updatedAtMs":1700000000001}""",
)
val store = DeviceAuthStore(app, legacyPrefsOverride = prefs)
store.saveToken("device-1", "operator", "operator-token", scopes = listOf("operator.write"))
assertEquals("operator-token", store.loadEntry("device-1", "operator")?.token)
assertEquals("node-token", store.loadEntry("device-1", "node")?.token)
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "node")?.token,
)
assertNull(prefs.getString("gateway.deviceTokenMeta.device-1.node"))
}
@Test
fun loadEntryReturnsLegacySecurePrefsTokenWhenSQLiteMigrationFails() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
val metadata = """{"scopes":["operator.read"],"updatedAtMs":1700000000000}"""
prefs.putString("gateway.deviceToken.device-1.operator", " operator-token ")
prefs.putString("gateway.deviceTokenMeta.device-1.operator", metadata)
val store =
DeviceAuthStore.createForTesting(
context = app,
legacyPrefsOverride = prefs,
stateStoreOverride = ThrowingDeviceAuthStateStore(),
)
val entry = store.loadEntry("device-1", "operator")
assertEquals("operator-token", entry?.token)
assertEquals(listOf("operator.read"), entry?.scopes)
assertEquals(1700000000000L, entry?.updatedAtMs)
assertEquals(" operator-token ", prefs.getString("gateway.deviceToken.device-1.operator"))
assertEquals(metadata, prefs.getString("gateway.deviceTokenMeta.device-1.operator"))
}
@Test
fun loadEntryMovesPlaintextSqliteTokenBackToSecurePrefs() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
OpenClawSQLiteStateStore(app).upsertDeviceAuthToken(
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = "device-1",
role = "operator",
token = "operator-token",
scopesJson = """["operator.read"]""",
updatedAtMs = 1700000000000,
),
)
val entry = DeviceAuthStore(app, legacyPrefsOverride = prefs).loadEntry("device-1", "operator")
assertEquals("operator-token", entry?.token)
assertEquals("operator-token", prefs.getString("gateway.deviceToken.device-1.operator"))
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-1", "operator")?.token,
)
}
@Test
fun saveTokenForDifferentDevicePurgesStaleLegacySecurePrefsTokens() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
prefs.putString("gateway.deviceToken.device-1.operator", " stale-token ")
prefs.putString(
"gateway.deviceTokenMeta.device-1.operator",
"""{"scopes":["operator.read"],"updatedAtMs":1700000000000}""",
)
val store = DeviceAuthStore(app, legacyPrefsOverride = prefs)
store.saveToken("device-2", "operator", "fresh-token", scopes = listOf("operator.write"))
assertNull(store.loadEntry("device-1", "operator"))
assertNull(prefs.getString("gateway.deviceToken.device-1.operator"))
assertNull(prefs.getString("gateway.deviceTokenMeta.device-1.operator"))
assertEquals("fresh-token", store.loadEntry("device-2", "operator")?.token)
assertEquals("fresh-token", prefs.getString("gateway.deviceToken.device-2.operator"))
assertEquals(
"__openclaw_secure_prefs__",
OpenClawSQLiteStateStore(app).readDeviceAuthToken("device-2", "operator")?.token,
)
}
@Test
fun saveTokenPrunesForeignLegacyTokensWithoutOrphaningCurrentSqliteRows() {
val app = RuntimeEnvironment.getApplication()
val prefs = legacyPrefs(app)
prefs.putString("gateway.deviceToken.device-1.operator", " operator-token ")
prefs.putString("gateway.deviceToken.device-1.node", " node-token ")
prefs.putString("gateway.deviceToken.device-2.operator", " stale-token ")
val sqlite = OpenClawSQLiteStateStore(app)
sqlite.upsertDeviceAuthToken(
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = "device-1",
role = "operator",
token = "__openclaw_secure_prefs__",
scopesJson = """["operator.read"]""",
updatedAtMs = 1700000000000,
),
)
sqlite.upsertDeviceAuthToken(
OpenClawSQLiteDeviceAuthTokenRow(
deviceId = "device-1",
role = "node",
token = "__openclaw_secure_prefs__",
scopesJson = """["node.connect"]""",
updatedAtMs = 1700000000001,
),
)
val store = DeviceAuthStore(app, legacyPrefsOverride = prefs)
store.saveToken("device-1", "operator", "operator-token-2", scopes = listOf("operator.write"))
assertEquals("operator-token-2", store.loadEntry("device-1", "operator")?.token)
assertEquals("node-token", store.loadEntry("device-1", "node")?.token)
assertNull(prefs.getString("gateway.deviceToken.device-2.operator"))
}
private fun legacyPrefs(context: Context): SecurePrefs {
val prefs = context.getSharedPreferences("openclaw.node.secure.test", Context.MODE_PRIVATE)
prefs.edit().clear().commit()
return SecurePrefs(context, securePrefsOverride = prefs)
}
private class ThrowingDeviceAuthStateStore : DeviceAuthStateStore {
override fun readDeviceAuthToken(
deviceId: String,
role: String,
): OpenClawSQLiteDeviceAuthTokenRow? = null
override fun readLatestDeviceAuthDeviceId(): String? = null
override fun upsertDeviceAuthToken(row: OpenClawSQLiteDeviceAuthTokenRow) {
error("sqlite unavailable")
}
override fun deleteDeviceAuthToken(
deviceId: String,
role: String,
) = Unit
override fun deleteAllDeviceAuthTokens() = Unit
}
}

Some files were not shown because too many files have changed in this diff Show More