Compare commits

..

820 Commits

Author SHA1 Message Date
Peter Steinberger
bfd9fcac18 test: remove redundant task flow temp dir args 2026-06-04 23:40:09 +01:00
Peter Steinberger
4f7b5d8f44 fix: refresh node plugin tools after plugin load 2026-06-04 23:39:46 +01:00
Peter Steinberger
32caafd4ed test: align rebased runtime defaults 2026-06-04 23:39:46 +01:00
Peter Steinberger
60becfb941 fix: avoid node plugin tool registry cycle 2026-06-04 23:39:45 +01:00
Peter Steinberger
3f4ea59779 build: refresh generated gateway protocol 2026-06-04 23:39:45 +01:00
Peter Steinberger
cde2b5f718 fix: keep node plugin tools fresh 2026-06-04 23:39:45 +01:00
Peter Steinberger
2af75a93c2 feat: expose node-hosted plugin tools 2026-06-04 23:39:45 +01:00
Peter Steinberger
571179c80b docs: document gateway live tests 2026-06-04 18:38:44 -04:00
Peter Steinberger
f0e5fdc064 docs: document gateway connection helpers 2026-06-04 18:36:52 -04:00
Peter Steinberger
f24ae91842 docs: document gateway server runtime 2026-06-04 18:35:26 -04:00
Peter Steinberger
ec22756340 docs: document gateway method descriptors 2026-06-04 18:34:05 -04:00
Peter Steinberger
e1b5fd2716 docs: document gateway test helpers 2026-06-04 18:33:25 -04:00
Peter Steinberger
437a5a71ae docs: document gateway runtime helpers 2026-06-04 18:30:41 -04:00
Peter Steinberger
a8154f425c docs: document gateway tool methods 2026-06-04 18:28:04 -04:00
Peter Steinberger
a6ecc4bd89 docs: document gateway session methods 2026-06-04 18:25:03 -04:00
Peter Steinberger
8c94131c0d docs: document gateway send methods 2026-06-04 18:22:31 -04:00
Peter Steinberger
e825301393 docs: document gateway node methods 2026-06-04 18:21:03 -04:00
Peter Steinberger
a84910be91 docs: document gateway diagnostics methods 2026-06-04 18:18:51 -04:00
Peter Steinberger
390a35d441 docs: document gateway chat methods 2026-06-04 18:17:28 -04:00
Peter Steinberger
f4c448f65b docs: document gateway agents methods 2026-06-04 18:15:10 -04:00
Peter Steinberger
c5d6764f56 docs: document gateway agent methods 2026-06-04 18:13:20 -04:00
Peter Steinberger
7f6af117f2 docs: document gateway tool test suites 2026-06-04 18:11:47 -04:00
Peter Steinberger
f0cb1a93e5 docs: document gateway session test suites 2026-06-04 18:10:05 -04:00
Peter Steinberger
d89d352971 docs: document gateway auth test suites 2026-06-04 18:08:07 -04:00
Shakker
3f6268ebd7 test: scope utility home env 2026-06-04 23:06:33 +01:00
Shakker
f3128f92d0 test: scope qqbot path env 2026-06-04 23:06:33 +01:00
Shakker
ec56a94ba3 test: scope sandbox env checks 2026-06-04 23:06:33 +01:00
Shakker
f0256be48d test: fence oauth manager env 2026-06-04 23:06:33 +01:00
Shakker
9de73ab6d2 test: scope agent auth copy state 2026-06-04 23:06:33 +01:00
Shakker
6bb91b2971 test: fence embedding provider secrets env 2026-06-04 23:06:33 +01:00
Shakker
840eaf9c19 test: centralize task flow state env 2026-06-04 23:06:33 +01:00
Shakker
2f6d4b811c test: isolate cleanup plan env 2026-06-04 23:06:33 +01:00
Shakker
509fa621de test: contain completion cache env 2026-06-04 23:06:33 +01:00
Peter Steinberger
6a95c8724a docs: document gateway chat test suites 2026-06-04 18:05:57 -04:00
Peter Steinberger
82de5903d7 docs: document gateway server test suites 2026-06-04 18:04:23 -04:00
Peter Steinberger
64b288be64 docs: document gateway probe test suites 2026-06-04 18:02:27 -04:00
Peter Steinberger
768143af06 docs: document gateway http test suites 2026-06-04 18:01:05 -04:00
Peter Steinberger
1e311058bc docs: document gateway config test suites 2026-06-04 17:58:55 -04:00
Peter Steinberger
7d216c2945 docs: document gateway client test suites 2026-06-04 17:57:26 -04:00
Peter Steinberger
fd8c789d42 docs: document gateway root test suites 2026-06-04 17:56:00 -04:00
Vincent Koc
deb9f11897 test(docker): harden live acp bind probes 2026-06-04 14:55:05 -07:00
Peter Steinberger
41d5e685ef docs: document gateway probe test helpers 2026-06-04 17:52:50 -04:00
Peter Steinberger
ca72d2706e docs: document gateway live runtime helpers 2026-06-04 17:50:37 -04:00
Shakker
81d9c2f41f test: scope session history state 2026-06-04 22:49:01 +01:00
Shakker
a0a115d466 test: wrap managed image attachment env 2026-06-04 22:49:01 +01:00
Shakker
501adb2524 test: isolate command secret env values 2026-06-04 22:49:01 +01:00
Shakker
1a4732410a test: scope host hook contract state 2026-06-04 22:49:01 +01:00
Peter Steinberger
8779bc49e0 docs: document gateway test helper fixtures 2026-06-04 17:47:12 -04:00
Peter Steinberger
15afc1d34c docs: document gateway auth ui runtime helpers 2026-06-04 17:45:49 -04:00
Peter Steinberger
8b4d12e161 docs: document gateway node startup helpers 2026-06-04 17:43:37 -04:00
Peter Steinberger
4c5b423fb8 docs: document gateway history runtime helpers 2026-06-04 17:41:47 -04:00
Peter Steinberger
bd76296c21 docs: document gateway runtime helpers 2026-06-04 17:38:20 -04:00
Peter Steinberger
360b2c9699 docs: document gateway session utility helpers 2026-06-04 17:36:25 -04:00
Peter Steinberger
aa9cc80060 docs: document gateway shutdown session helpers 2026-06-04 17:34:36 -04:00
Peter Steinberger
861bf541c2 docs: document gateway client auth helpers 2026-06-04 17:32:38 -04:00
Peter Steinberger
c8ac4c8aea docs: document gateway reload helpers 2026-06-04 17:30:08 -04:00
Peter Steinberger
8e371cfea1 docs: document gateway channel helpers 2026-06-04 17:27:42 -04:00
Peter Steinberger
dc23e924ef docs: document gateway runtime startup 2026-06-04 17:26:02 -04:00
Peter Steinberger
a3f495eb09 docs: document gateway node helpers 2026-06-04 17:23:48 -04:00
Peter Steinberger
1e438739bc docs: document gateway mcp helpers 2026-06-04 17:22:27 -04:00
Peter Steinberger
4d8502804d docs: document gateway state helpers 2026-06-04 17:20:55 -04:00
Peter Steinberger
d72184d3e0 docs: document gateway auth helpers 2026-06-04 17:18:36 -04:00
Peter Steinberger
7e0ee6d5c8 docs: document gateway utility policies 2026-06-04 17:16:36 -04:00
Peter Steinberger
2da49ef4ac docs: document gateway node policies 2026-06-04 17:14:38 -04:00
Peter Steinberger
fba99cddc1 docs: document gateway session utilities 2026-06-04 17:13:14 -04:00
Peter Steinberger
d76301e0ab docs: document gateway http helpers 2026-06-04 17:10:56 -04:00
Peter Steinberger
043929e76d docs: document gateway auth helpers 2026-06-04 17:09:08 -04:00
Peter Steinberger
c9c8125941 docs: document time formatting helpers 2026-06-04 17:06:59 -04:00
Peter Steinberger
b4a63886af docs: document outbound action runner 2026-06-04 17:06:05 -04:00
Peter Steinberger
5a6eddf5d0 docs: document outbound delivery queue 2026-06-04 17:04:07 -04:00
Peter Steinberger
ba72fb5b43 docs: document outbound message policy 2026-06-04 17:02:49 -04:00
Peter Steinberger
fc1848a28b docs: document outbound channel resolution 2026-06-04 17:01:45 -04:00
Peter Steinberger
aa12e7cda9 docs: document outbound action helpers 2026-06-04 17:00:31 -04:00
Peter Steinberger
9093556647 docs: document outbound session bindings 2026-06-04 16:59:17 -04:00
Peter Steinberger
ffc6bc0be0 docs: document outbound target helpers 2026-06-04 16:58:07 -04:00
Peter Steinberger
1f52854c0d docs: document command analysis infra 2026-06-04 16:56:05 -04:00
Peter Steinberger
170df6612e docs: document managed proxy net helpers 2026-06-04 16:54:14 -04:00
Peter Steinberger
eb6be3cf62 docs: document proxy network helpers 2026-06-04 16:52:20 -04:00
Peter Steinberger
53aa5232bc docs: document guarded fetch net helpers 2026-06-04 16:50:29 -04:00
Peter Steinberger
ba82257e37 docs: document media runner scenario tests 2026-06-04 16:48:42 -04:00
Peter Steinberger
5f7095f8be docs: document media runner core 2026-06-04 16:47:26 -04:00
Peter Steinberger
d6e4c879e8 docs: document media audio helpers 2026-06-04 16:46:02 -04:00
Peter Steinberger
ef6f4c1544 docs: document media attachment runtime 2026-06-04 16:45:01 -04:00
Peter Steinberger
9b42f399a1 docs: document media understanding defaults 2026-06-04 16:43:48 -04:00
Peter Steinberger
347ed87a96 docs: document agent instruction files 2026-06-04 16:42:36 -04:00
Peter Steinberger
3d168074b4 docs: document sandbox ssh tests 2026-06-04 16:41:43 -04:00
Peter Steinberger
cc296f3a46 docs: document subagent tests 2026-06-04 16:40:43 -04:00
Peter Steinberger
f39aff1558 docs: document remaining agent tool tests 2026-06-04 16:39:32 -04:00
Peter Steinberger
ea9f791a68 docs: document image and pdf tool tests 2026-06-04 16:38:27 -04:00
Peter Steinberger
d5ce1edf7e docs: document core agent tool tests 2026-06-04 16:37:10 -04:00
Peter Steinberger
5c71f2190b docs: document media cron tool tests 2026-06-04 16:35:06 -04:00
Peter Steinberger
c70e2bd2b3 docs: document sandbox helper tests 2026-06-04 16:33:10 -04:00
Peter Steinberger
ba02f12464 docs: document sandbox policy tests 2026-06-04 16:31:29 -04:00
Peter Steinberger
4e6fbf73a2 docs: document sandbox filesystem tests 2026-06-04 16:30:09 -04:00
Peter Steinberger
a0fa579cdc docs: document docker sandbox tests 2026-06-04 16:28:39 -04:00
Peter Steinberger
a98f292a11 docs: document status tool tests 2026-06-04 16:26:49 -04:00
Peter Steinberger
56ae6d3c1a docs: document common agent tool tests 2026-06-04 16:25:47 -04:00
Peter Steinberger
0e427e6cdc docs: document web runtime tests 2026-06-04 16:24:37 -04:00
Peter Steinberger
caa9078e70 docs: document web search fetch tests 2026-06-04 16:23:34 -04:00
Peter Steinberger
099584676b docs: document extension loader tests 2026-06-04 16:22:24 -04:00
Peter Steinberger
1ad9109a6c docs: document agent session infra tests 2026-06-04 16:21:30 -04:00
Peter Steinberger
1e8609af5d docs: document pdf web tool tests 2026-06-04 16:20:29 -04:00
Peter Steinberger
a3f21d03e8 docs: document sandbox config tests 2026-06-04 16:18:47 -04:00
Peter Steinberger
d045deb79d docs: document session tool tests 2026-06-04 16:17:22 -04:00
Peter Steinberger
c65eacae17 docs: document agent session tests 2026-06-04 16:16:25 -04:00
Chunyue Wang
6c259af759 fix(agents): strip stale compaction thinking signatures before Anthropic replay (#90163)
Pre-compaction assistant messages carry thinkingSignature values bound to the
original conversation prefix. After compaction the prefix changes (summarized
content is replaced by the compaction summary), so Anthropic rejects those
signatures with "Invalid signature in thinking block", permanently stalling the
session through gateway restarts.

stripInvalidThinkingSignatures only catches absent/blank signatures; this adds
stripStaleThinkingSignaturesForCompactionReplay (thinking.ts) which identifies
pre-compaction assistant messages by timestamp comparison against the latest
compaction summary and strips their signature fields. Called in
sanitizeSessionHistory (replay-history.ts) before stripInvalidThinkingSignatures
for all signed-thinking providers (Anthropic, Bedrock, Vertex). Also fixes
buildSuccessorEntries (compaction-successor-transcript.ts) to strip only
pre-compaction kept entries when writing the rotation successor JSONL; uses
strict < timestamp boundary so same-instant post-compaction messages are not
affected.

Docs: update transcript-hygiene.md Anthropic and Bedrock sections.
Tests: 8 new cases for stripStaleThinkingSignaturesForCompactionReplay; 1 new
case for buildSuccessorEntries verifying pre/post-compaction signature boundary.

Fixes #90108
2026-06-04 16:15:44 -04:00
Peter Steinberger
266dcf33f2 docs: document gateway web tool tests 2026-06-04 16:15:21 -04:00
Peter Steinberger
b380cdc84e docs: document media generation tests 2026-06-04 16:13:06 -04:00
Peter Steinberger
0f73e09769 docs: document sessions tools tests 2026-06-04 16:11:19 -04:00
Peter Steinberger
2d3b378876 docs: document tool guard tests 2026-06-04 16:09:36 -04:00
Peter Steinberger
3ac506a887 docs: document agent utility tests 2026-06-04 16:08:01 -04:00
Peter Steinberger
22f21ed7e6 docs: document runtime plan type tests 2026-06-04 16:06:12 -04:00
Shakker
bca7d18c60 test: scope chat directive transcript state 2026-06-04 21:06:04 +01:00
Shakker
9932ba7359 test: wrap session projection stores 2026-06-04 21:06:04 +01:00
Shakker
53978b358a test: isolate auth profile state dirs 2026-06-04 21:06:04 +01:00
Shakker
3f16f2e9a5 test: contain config write env state 2026-06-04 21:06:04 +01:00
Shakker
4a6dc1b830 test: scope task registry env setup 2026-06-04 21:06:04 +01:00
Peter Steinberger
7766d2b65b docs: document runtime plan tests 2026-06-04 16:04:45 -04:00
Peter Steinberger
01eefa7f96 docs: document transcript tool tests 2026-06-04 16:03:01 -04:00
Peter Steinberger
ff254a44c9 docs: document workspace transport tests 2026-06-04 16:01:19 -04:00
Peter Steinberger
22f2a91c2d docs: document system prompt tests 2026-06-04 15:59:59 -04:00
Peter Steinberger
1f57a946ca docs: document tool policy tests 2026-06-04 15:58:11 -04:00
Peter Steinberger
a09594b4ac docs: document subagent spawn tests 2026-06-04 15:56:34 -04:00
Peter Steinberger
e7de27f8b0 docs: document subagent registry persistence tests 2026-06-04 15:55:31 -04:00
Peter Steinberger
ec4a871f91 docs: document subagent registry lifecycle tests 2026-06-04 15:54:32 -04:00
Peter Steinberger
7af2673965 docs: document subagent registry helpers 2026-06-04 15:53:22 -04:00
Peter Steinberger
a9224f6f5d docs: document subagent control tests 2026-06-04 15:52:23 -04:00
Peter Steinberger
ca24dd7793 docs: document subagent announce tests 2026-06-04 15:51:15 -04:00
Peter Steinberger
f4ac968577 docs: document simple completion tests 2026-06-04 15:50:27 -04:00
Peter Steinberger
939fe702a6 docs: document session shell tests 2026-06-04 15:48:20 -04:00
Peter Steinberger
dca200ade5 docs: document session guard tests 2026-06-04 15:46:45 -04:00
Peter Steinberger
58f00707ed docs: document sandbox path tests 2026-06-04 15:45:12 -04:00
Peter Steinberger
3da0803ab4 docs: document sandbox runtime tests 2026-06-04 15:43:40 -04:00
Vincent Koc
40661e9d19 fix(test): use API-key auth for Codex live Docker lanes 2026-06-04 12:43:30 -07:00
Peter Steinberger
57ec0b236f docs: document runtime utility tests 2026-06-04 15:42:07 -04:00
Peter Steinberger
88a0fc69f0 docs: document provider transport tests 2026-06-04 15:40:23 -04:00
Peter Steinberger
4a93974a90 docs: document provider policy tests 2026-06-04 15:39:01 -04:00
Peter Steinberger
d3e5959669 docs: document subagent tool harness tests 2026-06-04 15:37:17 -04:00
Peter Steinberger
f8f7ba8f01 docs: document subagent spawn tests 2026-06-04 15:35:43 -04:00
Peter Steinberger
1a8d237369 docs: document openclaw session tool tests 2026-06-04 15:34:42 -04:00
Peter Steinberger
b491058e88 docs: document openclaw tool tests 2026-06-04 15:33:39 -04:00
Peter Steinberger
1df9bca8e2 docs: document openai transport tests 2026-06-04 15:32:37 -04:00
Peter Steinberger
48d67e88d0 docs: document openai live compat tests 2026-06-04 15:31:22 -04:00
Peter Steinberger
8605076a6f docs: document models config serialization tests 2026-06-04 15:30:20 -04:00
Peter Steinberger
c1b54fe01e docs: document provider policy tests 2026-06-04 15:29:14 -04:00
Peter Steinberger
117bb3c61c docs: document provider config tests 2026-06-04 15:28:05 -04:00
Peter Steinberger
c31877464c docs: document models config tests 2026-06-04 15:25:52 -04:00
Peter Steinberger
4653454c91 docs: document model selection tests 2026-06-04 15:24:14 -04:00
Peter Steinberger
287a62c2fd docs: document model runtime tests 2026-06-04 15:22:18 -04:00
Peter Steinberger
a0cdd4e305 docs: document model fallback tests 2026-06-04 15:20:42 -04:00
Peter Steinberger
3140bb695d docs: document model auth tests 2026-06-04 15:18:53 -04:00
Josh Lehman
ab0a633ab9 fix: tolerate missing streamed response content type
Fixes the OpenAI-compatible stream transport regression where a valid ChatGPT Codex HTTP 200 stream could arrive without a `content-type` header and be rejected before the OpenAI SDK consumed it.

Prepared head SHA: 0d7f8abb17

Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
2026-06-04 12:17:22 -07:00
Peter Steinberger
d4523cba74 docs: document model transport tests 2026-06-04 15:16:44 -04:00
Peter Steinberger
0d2a9073f5 docs: document mcp session tests 2026-06-04 15:14:28 -04:00
Peter Steinberger
4c5b2cf2e2 docs: document live model tests 2026-06-04 15:13:12 -04:00
Jacob Tomlinson
829847292e feat(nvidia): default to nemotron ultra
Add NVIDIA Nemotron 3 Ultra to the bundled NVIDIA provider catalog and make it the bundled fallback default. Keep successful NVIDIA featured-model feeds authoritative, while treating the first live feed row as the setup default option. Update NVIDIA provider docs and focused provider/model-picker tests for the new Ultra behavior.

Verification:
- node scripts/run-vitest.mjs src/commands/model-picker.test.ts extensions/nvidia/provider-catalog.test.ts extensions/nvidia/index.test.ts extensions/nvidia/onboard.test.ts
- pnpm exec oxfmt --check src/flows/model-picker.ts src/commands/model-picker.test.ts
- pnpm format:docs:check
- pnpm docs:check-mdx
- git diff --check upstream/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base upstream/main --parallel-tests "node scripts/run-vitest.mjs src/commands/model-picker.test.ts extensions/nvidia/provider-catalog.test.ts extensions/nvidia/index.test.ts extensions/nvidia/onboard.test.ts"
2026-06-04 20:13:06 +01:00
Peter Steinberger
8048ceca71 docs: document agent identity tests 2026-06-04 15:10:14 -04:00
Peter Steinberger
a1c6a6e36f docs: document harness lifecycle tests 2026-06-04 15:08:47 -04:00
Peter Steinberger
bc2294b413 docs: document agent harness tests 2026-06-04 15:07:36 -04:00
Shakker
b4e47ae395 docs: document env mutation report 2026-06-04 20:06:24 +01:00
Shakker
51f9082873 test: add env mutation report 2026-06-04 20:06:24 +01:00
Peter Steinberger
85b4bd6c7b docs: document agent policy tests 2026-06-04 15:06:09 -04:00
Vincent Koc
023427b1d5 test(docker): cap npm scheduler concurrency 2026-06-04 12:04:45 -07:00
Peter Steinberger
5864669b3b docs: document embedded subscribe tools 2026-06-04 15:04:14 -04:00
Peter Steinberger
e0fe08ccce docs: document embedded subscribe lifecycle 2026-06-04 15:03:07 -04:00
Peter Steinberger
a5880a3747 docs: document embedded subscribe chunking 2026-06-04 15:02:04 -04:00
Peter Steinberger
60cb5d633f docs: document embedded subscribe text streaming 2026-06-04 15:00:33 -04:00
Peter Steinberger
fc7f96c826 docs: document embedded subscribe reply regressions 2026-06-04 14:59:30 -04:00
Peter Steinberger
6cde30a77c docs: document embedded subscribe handlers 2026-06-04 14:58:34 -04:00
Peter Steinberger
82d4d989d0 docs: document embedded runner helper tests 2026-06-04 14:57:12 -04:00
Peter Steinberger
69df4c9136 docs: document embedded runner registry tests 2026-06-04 14:54:59 -04:00
Peter Steinberger
689bafd16f docs: document embedded payload prompt tests 2026-06-04 14:53:23 -04:00
Peter Steinberger
d91f645d28 docs: document embedded failover image tests 2026-06-04 14:51:49 -04:00
Peter Steinberger
c7c67fc790 docs: document embedded attempt auth tests 2026-06-04 14:49:17 -04:00
Peter Steinberger
9dcf42472b docs: document embedded attempt spawn tests 2026-06-04 14:46:45 -04:00
Peter Steinberger
0f53d0000c docs: document embedded attempt workspace tests 2026-06-04 14:44:56 -04:00
Peter Steinberger
6365951160 docs: document embedded attempt helper tests 2026-06-04 14:43:03 -04:00
Peter Steinberger
838bc724ec docs: document embedded attempt tests 2026-06-04 14:41:17 -04:00
Peter Steinberger
ff39de4806 docs: document embedded runner overflow tests 2026-06-04 14:39:46 -04:00
Shakker
dfde0ce1a6 test: explain skipped changed vitest targets 2026-06-04 19:38:06 +01:00
Shakker
dd8f491040 test: expose changed fallback skip metadata 2026-06-04 19:38:06 +01:00
Peter Steinberger
a31d3355cd docs: document embedded runner run tests 2026-06-04 14:38:00 -04:00
Peter Steinberger
cd26595d6f docs: document embedded runner cache tests 2026-06-04 14:36:52 -04:00
Peter Steinberger
810f29b5f6 docs: document embedded runner model tests 2026-06-04 14:35:43 -04:00
Peter Steinberger
0b6aad58f2 docs: document embedded runner routing tests 2026-06-04 14:33:55 -04:00
Peter Steinberger
e78ef6fbad docs: document embedded runner extra params tests 2026-06-04 14:32:48 -04:00
Peter Steinberger
315cdd42fb docs: document embedded runner compaction tests 2026-06-04 14:31:27 -04:00
Peter Steinberger
85df2e1f85 docs: document embedded runner history tests 2026-06-04 14:29:25 -04:00
Peter Steinberger
94555a5898 docs: document embedded runner guard tests 2026-06-04 14:26:32 -04:00
Peter Steinberger
998adc707f docs: document embedded runner extra params tests 2026-06-04 14:24:17 -04:00
Peter Steinberger
77d0792e02 docs: document embedded helper classifier tests 2026-06-04 14:22:41 -04:00
Peter Steinberger
0241665795 docs: document embedded helper tests 2026-06-04 14:19:48 -04:00
Peter Steinberger
100be0e55a docs: document context lookup tests 2026-06-04 14:18:08 -04:00
Peter Steinberger
31b4575172 docs: document compaction tests 2026-06-04 14:16:34 -04:00
Peter Steinberger
17fc1c430f docs: document command session tests 2026-06-04 14:14:07 -04:00
Peter Steinberger
a767c6d1df docs: document agent command tests 2026-06-04 14:12:48 -04:00
Peter Steinberger
8fb70a90bd docs: document cli runner preparation tests 2026-06-04 14:11:04 -04:00
Peter Steinberger
429bf9fe84 docs: document cli runner bundle mcp tests 2026-06-04 14:07:58 -04:00
Peter Steinberger
a44c5ee3f7 docs: document cli runner tests 2026-06-04 14:06:45 -04:00
Peter Steinberger
bb6c3ce262 docs: document agent cli tests 2026-06-04 14:04:32 -04:00
Peter Steinberger
ddc832ead1 docs: document agent cache auth tests 2026-06-04 14:03:39 -04:00
Peter Steinberger
d216322640 docs: document agent bootstrap tests 2026-06-04 14:02:28 -04:00
Peter Steinberger
2761e8cc3b docs: document daemon systemd helpers 2026-06-04 14:00:34 -04:00
Peter Steinberger
407f4777d2 docs: document daemon service env helpers 2026-06-04 13:58:33 -04:00
Peter Steinberger
a3c44d53d1 docs: document daemon audit helpers 2026-06-04 13:57:21 -04:00
Peter Steinberger
feeaff20ab docs: document daemon runtime helpers 2026-06-04 13:55:33 -04:00
Peter Steinberger
975d40d474 docs: document launchd daemon helpers 2026-06-04 13:54:21 -04:00
Peter Steinberger
0d35da9cc4 docs: document daemon command helpers 2026-06-04 13:51:23 -04:00
Peter Steinberger
d1bf769dbd docs: document cron store helpers 2026-06-04 13:50:06 -04:00
Peter Steinberger
77f09f2575 docs: document cron service state and timer 2026-06-04 13:47:51 -04:00
Peter Steinberger
f51126f0fa docs: document cron service operations 2026-06-04 13:45:55 -04:00
Peter Steinberger
31ce6dfc4c docs: document cron schedule helpers 2026-06-04 13:44:43 -04:00
Peter Steinberger
875c9fd96d docs: document cron normalization and run logs 2026-06-04 13:42:58 -04:00
Peter Steinberger
03a2f6f89d docs: document isolated cron run helpers 2026-06-04 13:41:33 -04:00
Peter Steinberger
93e75f646f docs: document isolated cron delivery helpers 2026-06-04 13:38:54 -04:00
Peter Steinberger
9d2c7bcb66 docs: document cron delivery helpers 2026-06-04 13:37:20 -04:00
Peter Steinberger
a10dfb7185 docs: document crestodian helpers 2026-06-04 13:35:15 -04:00
Peter Steinberger
a0e19507e3 docs: document context engine helpers 2026-06-04 13:33:05 -04:00
Peter Steinberger
c74fd6f015 docs: document session transcript helpers 2026-06-04 13:31:05 -04:00
Peter Steinberger
fbac4a2ec7 docs: document session store facade 2026-06-04 13:29:18 -04:00
Peter Steinberger
3f16b96ddc docs: document session store helpers 2026-06-04 13:27:40 -04:00
Peter Steinberger
0e3f7a82fd docs: document session path helpers 2026-06-04 13:26:14 -04:00
Mason Huang
8b29ff5f16 fix(ci): scope PR merge diff checks to first parent (#90287)
Summary:
- This PR adds opt-in first-parent merge-head diff-base handling for CI changed-scope, changed-lanes, and OpenGrep PR scans, plus synthetic merge coverage and small lint/type cleanups.
- PR surface: Source +6, Tests +204, Config +1, Other +179. Total +390 across 15 files.
- Reproducibility: yes. The synthetic merge tests and PR body live-ref proof show the stale payload-base path can include main-only files, and first-parent mode narrows it to PR-owned paths.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ci): update workflow guard expectations
- PR branch already contained follow-up commit before automerge: fix(ci): resolve plugin guardrail lint failures
- PR branch already contained follow-up commit before automerge: fix(ci): preserve plugin run context typing
- PR branch already contained follow-up commit before automerge: fix(ci): scope PR merge diff checks to first parent

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

Prepared head SHA: 40235e8c3d
Review: https://github.com/openclaw/openclaw/pull/90287#issuecomment-4621155576

Co-authored-by: Mason Huang <masonxhuang@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: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
2026-06-04 17:24:03 +00:00
Peter Steinberger
fff04af46d docs: document session metadata helpers 2026-06-04 13:23:36 -04:00
Peter Steinberger
c87c1569d5 docs: document session cleanup helpers 2026-06-04 13:21:00 -04:00
Peter Steinberger
d00d10f172 docs: document command test helpers 2026-06-04 13:18:37 -04:00
Peter Steinberger
8d65e78a07 docs: document task command helpers 2026-06-04 13:17:07 -04:00
Peter Steinberger
726bc2b6c7 docs: document status summary helpers 2026-06-04 13:15:41 -04:00
joshavant
cb4f6af504 fix ios canvas presentation 2026-06-04 10:15:32 -07:00
joshavant
81c8f525eb fix ios gateway forced reconnect 2026-06-04 10:15:32 -07:00
Peter Steinberger
1794efbba1 docs: document status scan core 2026-06-04 13:13:46 -04:00
Peter Steinberger
9b7ad2441f docs: document status scan helpers 2026-06-04 13:12:00 -04:00
Peter Steinberger
976ea3ff50 docs: document status command wiring 2026-06-04 13:10:25 -04:00
Peter Steinberger
f0b3c4164f docs: document status runtime helpers 2026-06-04 13:09:09 -04:00
Peter Steinberger
ea6d3232ca docs: document status overview helpers 2026-06-04 13:07:17 -04:00
Peter Steinberger
abb09b93cb docs: document status json helpers 2026-06-04 13:05:43 -04:00
Peter Steinberger
e11e4e8935 docs: document status report helpers 2026-06-04 13:04:21 -04:00
Peter Steinberger
2939ac6b72 docs: document status channel helpers 2026-06-04 13:02:30 -04:00
Peter Steinberger
ae948fa429 docs: document setup command helpers 2026-06-04 13:00:10 -04:00
Peter Steinberger
d09e0740e5 docs: document session display commands 2026-06-04 12:58:22 -04:00
Peter Steinberger
09467b1b87 docs: document sandbox session utilities 2026-06-04 12:55:08 -04:00
Peter Steinberger
97cdf8e7ac docs: document plugin install utilities 2026-06-04 12:52:51 -04:00
Vincent Koc
7dead6537a test(e2e): keep tui pty smoke off arm gateway runs 2026-06-04 09:50:57 -07:00
Peter Steinberger
d3cabb0fc6 docs: document onboard command surface 2026-06-04 12:50:31 -04:00
Peter Steinberger
c100ae1f36 docs: document noninteractive onboarding entrypoints 2026-06-04 12:48:25 -04:00
Peter Steinberger
3bae50af7f docs: document local onboarding helpers 2026-06-04 12:46:22 -04:00
Peter Steinberger
fe70a2f5a6 docs: document noninteractive auth choice helpers 2026-06-04 12:44:26 -04:00
Peter Steinberger
6c89ef9c3a docs: document noninteractive onboarding helpers 2026-06-04 12:42:33 -04:00
Peter Steinberger
0812b7e3a8 docs: document custom onboarding comments 2026-06-04 12:40:58 -04:00
Peter Steinberger
d4ed8964d3 docs: document onboarding helper comments 2026-06-04 12:37:56 -04:00
Peter Steinberger
12efbcaa7e docs: document daemon oauth command seams 2026-06-04 12:36:05 -04:00
Peter Steinberger
47f0af0d2d docs: document model command comments 2026-06-04 12:33:53 -04:00
Peter Steinberger
9d7f83b175 docs: document model list source comments 2026-06-04 12:32:05 -04:00
Peter Steinberger
73752f07f2 docs: document model list runtime comments 2026-06-04 12:29:16 -04:00
Peter Steinberger
feb6dc6bb6 docs: document model list comments 2026-06-04 12:27:15 -04:00
Peter Steinberger
865bd10bda docs: document model auth fallback comments 2026-06-04 12:25:03 -04:00
Peter Steinberger
945a7fdb36 docs: document migrate picker comments 2026-06-04 12:22:26 -04:00
Peter Steinberger
c6a6f56699 docs: document message migrate helpers 2026-06-04 12:20:26 -04:00
Peter Steinberger
09df56ee1f docs: document gateway status health comments 2026-06-04 12:18:52 -04:00
Peter Steinberger
473f651e09 docs: document gateway helper comments 2026-06-04 12:17:02 -04:00
Peter Steinberger
4912342dd7 docs: document doctor command entrypoints 2026-06-04 12:13:46 -04:00
Peter Steinberger
d4ac91d8f0 docs: document doctor state checks 2026-06-04 12:10:56 -04:00
Peter Steinberger
c0b3c8cdb9 docs: document doctor session checks 2026-06-04 12:08:24 -04:00
Peter Steinberger
0913b6989c docs: document doctor repair policy helpers 2026-06-04 12:06:06 -04:00
Peter Steinberger
9d6e8b872a docs: document doctor plugin checks 2026-06-04 12:04:28 -04:00
Peter Steinberger
f1e6177331 docs: document doctor heartbeat checks 2026-06-04 12:02:48 -04:00
Peter Steinberger
3b914ca40b docs: document doctor gateway checks 2026-06-04 12:01:00 -04:00
Peter Steinberger
688777ca79 docs: document doctor config preflight checks 2026-06-04 11:59:11 -04:00
Peter Steinberger
d2ff1c31d6 docs: document doctor configuration checks 2026-06-04 11:57:47 -04:00
Peter Steinberger
c0e9797644 docs: document doctor auth repair helpers 2026-06-04 11:56:19 -04:00
Peter Steinberger
3e2d56469b docs: document doctor stale warning helpers 2026-06-04 11:53:40 -04:00
Peter Steinberger
3e6978770a docs: document doctor plugin repair helpers 2026-06-04 11:51:25 -04:00
Peter Steinberger
51f7844c43 docs: document legacy web and auth helpers 2026-06-04 11:48:55 -04:00
Peter Steinberger
2016d32187 docs: document legacy migration registry 2026-06-04 11:46:48 -04:00
Peter Steinberger
90f9f2c2e4 docs: document runtime legacy migrations 2026-06-04 11:44:36 -04:00
Peter Steinberger
8dc5b9afcd docs: document legacy config normalizers 2026-06-04 11:43:03 -04:00
Peter Steinberger
4fcc7537ff docs: document doctor legacy repair helpers 2026-06-04 11:41:21 -04:00
Peter Steinberger
7beeedbe73 docs: document doctor warning helpers 2026-06-04 11:39:28 -04:00
Peter Steinberger
6a6da54062 docs: document codex doctor helpers 2026-06-04 11:37:55 -04:00
Peter Steinberger
efda5918b5 docs: document channel doctor helpers 2026-06-04 11:36:22 -04:00
Peter Steinberger
5e8190b779 docs: document doctor allowlist repairs 2026-06-04 11:34:47 -04:00
Peter Steinberger
98df83079d docs: document doctor allowlist warnings 2026-06-04 11:33:51 -04:00
Peter Steinberger
0c4ea11b06 docs: document doctor repair orchestration 2026-06-04 11:32:42 -04:00
Peter Steinberger
695e181179 docs: document doctor cron repair helpers 2026-06-04 11:31:17 -04:00
Peter Steinberger
4eb3d1fae9 docs: document daemon install helpers 2026-06-04 11:27:53 -04:00
Peter Steinberger
118060157d docs: document configure wizard helpers 2026-06-04 11:25:31 -04:00
Peter Steinberger
14962b2825 docs: document cleanup and configure helpers 2026-06-04 11:22:51 -04:00
Peter Steinberger
7385c611fc docs: document channel command helpers 2026-06-04 11:20:59 -04:00
Peter Steinberger
b9aade4b12 refactor: move MS Teams state migration to doctor 2026-06-04 08:20:39 -07:00
Peter Steinberger
3a335c6df1 refactor: remove Feishu runtime dedupe JSON fallback 2026-06-04 08:20:28 -07:00
Peter Steinberger
0a351cdf7f docs: document channel setup commands 2026-06-04 11:18:50 -04:00
Vincent Koc
52b07b4a46 test(ci): stabilize ARM changed-test guards 2026-06-04 08:18:15 -07:00
Jesse Merhi
fa3901e665 fix(message-tool): stabilize send idempotency keys 2026-06-04 20:47:41 +05:30
Peter Steinberger
4c32553875 docs: document backup and channel setup helpers 2026-06-04 11:16:37 -04:00
Peter Steinberger
63dfa848a6 docs: document auth choice command helpers 2026-06-04 11:14:36 -04:00
Peter Steinberger
03490ba1b9 docs: document agent management commands 2026-06-04 11:12:55 -04:00
Vincent Koc
367be94676 test(agents): stabilize compaction worker timing 2026-06-04 08:11:39 -07:00
Peter Steinberger
4af066b013 docs: document update and agent cli helpers 2026-06-04 11:11:07 -04:00
Peter Steinberger
20c4e9475a docs: document cli startup helpers 2026-06-04 11:07:54 -04:00
Peter Steinberger
98187f3277 docs: document cli program helpers 2026-06-04 11:05:42 -04:00
Peter Steinberger
f7e54acec1 docs: document plugin program cli helpers 2026-06-04 11:03:24 -04:00
Peter Steinberger
169a4159de docs: document plugin cli helpers 2026-06-04 11:01:13 -04:00
Peter Steinberger
a94a939626 docs: document cli command runtimes 2026-06-04 10:58:50 -04:00
Peter Steinberger
69c27677f6 docs: document gateway cli helpers 2026-06-04 10:56:59 -04:00
Peter Steinberger
cb5d43ba95 docs: document cli utility helpers 2026-06-04 10:55:01 -04:00
Peter Steinberger
8946648ace docs: document daemon cli helpers 2026-06-04 10:53:30 -04:00
Peter Steinberger
09cee22249 docs: document cli config and cron helpers 2026-06-04 10:52:10 -04:00
Vincent Koc
5522268b24 test(ci): align lint suppression guard 2026-06-04 07:51:28 -07:00
Peter Steinberger
e2a5823c83 docs: document cli startup policy helpers 2026-06-04 10:50:04 -04:00
Peter Steinberger
dd0dd662a1 docs: document cli command helpers 2026-06-04 10:48:30 -04:00
Peter Steinberger
ca9249e357 docs: document channel core helpers 2026-06-04 10:47:00 -04:00
Peter Steinberger
cc73ef8ba5 docs: document channel plugin setup types 2026-06-04 10:42:48 -04:00
Peter Steinberger
67ddda2a21 docs: document channel plugin runtime helpers 2026-06-04 10:39:46 -04:00
Peter Steinberger
15f3903b6f docs: document channel plugin contract helpers 2026-06-04 10:36:02 -04:00
Vincent Koc
ecb30fece4 fix(ci): stabilize include permission checks 2026-06-04 07:35:25 -07:00
Vincent Koc
71bda851d1 test(ui): harden control ui vitest setup 2026-06-04 07:35:02 -07:00
Peter Steinberger
08fd123906 docs: document channel plugin binding helpers 2026-06-04 10:31:28 -04:00
Peter Steinberger
7d3f1963d3 docs: document channel message access helpers 2026-06-04 10:28:38 -04:00
Peter Steinberger
6aed185ccb docs: document channel utility helpers 2026-06-04 10:26:27 -04:00
Peter Steinberger
041fab7b72 docs: document session web tools 2026-06-04 10:22:14 -04:00
Peter Steinberger
1ce11fbf42 docs: document media session tools 2026-06-04 10:17:38 -04:00
Peter Steinberger
2cbaacda43 docs: document built-in tool helpers 2026-06-04 10:14:36 -04:00
Peter Steinberger
bf1634b17a docs: document tool utility helpers 2026-06-04 10:11:57 -04:00
Peter Steinberger
3894fe11ca docs: document subagent registry helpers 2026-06-04 10:08:39 -04:00
Peter Steinberger
589b1f6aec docs: document subagent helpers 2026-06-04 10:05:53 -04:00
Peter Steinberger
600a57e60f docs: document session tools 2026-06-04 10:03:05 -04:00
Peter Steinberger
f84460e625 docs: document session services 2026-06-04 10:01:18 -04:00
Ayaan Zaidi
735587dde0 docs(acp): document parent commentary default 2026-06-04 19:30:46 +05:30
Ayaan Zaidi
8fdfb2d7e3 fix(acp): default parent commentary in progress mode 2026-06-04 19:30:46 +05:30
Peter Steinberger
88f78190ee docs: document sandbox helpers 2026-06-04 09:58:14 -04:00
Peter Steinberger
15361bfe07 docs: document provider tool helpers 2026-06-04 09:55:11 -04:00
Peter Steinberger
e8895f0a99 docs: document model selection helpers 2026-06-04 09:51:42 -04:00
Vincent Koc
8e9a4e99f5 test(gateway): extend vitest idle watchdog 2026-06-04 06:49:43 -07:00
Peter Steinberger
b031913031 docs: document agent runtime helpers 2026-06-04 09:48:36 -04:00
Peter Steinberger
585e89adbe docs: document exec and harness helpers 2026-06-04 09:46:22 -04:00
Peter Steinberger
46b826944c docs: document embedded subscribe helpers 2026-06-04 09:43:42 -04:00
Peter Steinberger
33bda2629a docs: document runner root helpers 2026-06-04 09:41:21 -04:00
Peter Steinberger
e95e51a24f docs: document runner message helpers 2026-06-04 09:38:52 -04:00
Peter Steinberger
fa6be505ef docs: document runner failover helpers 2026-06-04 09:36:19 -04:00
Peter Steinberger
20577f0b3b docs: document runner attempt runtime helpers 2026-06-04 09:34:34 -04:00
Peter Steinberger
f5ccfb7319 docs: document runner attempt helpers 2026-06-04 09:32:25 -04:00
Peter Steinberger
6719528316 docs: document runner model helpers 2026-06-04 09:30:31 -04:00
Peter Steinberger
dea0be4f11 docs: document runner utility helpers 2026-06-04 09:28:31 -04:00
Ayaan Zaidi
e59a7680e6 test(acp): keep streaming off regression typed (#89505) (thanks @100yenadmin) 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
448e67bd8b fix(config): accept shared progress commentary (#89505) (thanks @100yenadmin) 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
1f4b08ad2a fix(acp): preserve parent streaming off overrides (#89505) (thanks @100yenadmin) 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
afb8d80ce7 fix(acp): satisfy relay lint checks (#89505) (thanks @100yenadmin) 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
bd065c1154 fix(acp): harden parent commentary progress (#89505) (thanks @100yenadmin) 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
4c9b724987 fix(acp): relay codex parent commentary 2026-06-04 18:55:55 +05:30
Ayaan Zaidi
2bf886b7dd fix(acp): reuse progress commentary config 2026-06-04 18:55:55 +05:30
Eva
9ac94568f3 fix(acp): honor tag visibility for status progress 2026-06-04 18:55:55 +05:30
Eva
ca0789ee8f fix(acp): type status progress relay metadata 2026-06-04 18:55:55 +05:30
Eva
0d44d970a9 Handle ACP status progress commentary 2026-06-04 18:55:55 +05:30
Eva
0c272958cf Add opt-in ACP commentary relay 2026-06-04 18:55:55 +05:30
Peter Steinberger
d07cce7bd1 docs: document runner compaction helpers 2026-06-04 09:25:41 -04:00
Peter Steinberger
dbfe5a252c docs: document embedded agent helpers 2026-06-04 09:22:40 -04:00
Peter Steinberger
550f707565 docs: document agent config helpers 2026-06-04 09:19:21 -04:00
Peter Steinberger
2173d1bf47 docs: document compaction planning helpers 2026-06-04 09:17:00 -04:00
Peter Steinberger
e12776037f docs: document agent command helpers 2026-06-04 09:15:00 -04:00
Peter Steinberger
a4550c5769 docs: document agent attempt helpers 2026-06-04 09:12:59 -04:00
Peter Steinberger
e996956c29 docs: document codex search helpers 2026-06-04 09:11:36 -04:00
Peter Steinberger
31a1034cb5 docs: document code mode helpers 2026-06-04 09:10:13 -04:00
Peter Steinberger
087fcf4085 docs: document cli runner history helpers 2026-06-04 09:08:46 -04:00
Peter Steinberger
1d7d8a1658 docs: document cli runner execution helpers 2026-06-04 09:06:53 -04:00
Peter Steinberger
f178c31305 docs: document cli runner shared helpers 2026-06-04 09:05:29 -04:00
Peter Steinberger
e6ec78ede4 docs: document cli runner mcp helpers 2026-06-04 09:04:02 -04:00
Peter Steinberger
34f7d78449 docs: document cli agent helpers 2026-06-04 09:02:44 -04:00
Peter Steinberger
258373717a docs: document chutes oauth helpers 2026-06-04 09:01:15 -04:00
Vincent Koc
383d214c7c test(plugin-sdk): restore testing facade guard 2026-06-04 15:00:21 +02:00
Vincent Koc
59777971d2 fix(plugins): remove stale run context generic 2026-06-04 15:00:21 +02:00
Vincent Koc
f187bec815 fix(cli): skip plugin loader cache clear on short-lived commands 2026-06-04 15:00:21 +02:00
Peter Steinberger
0dea7eab37 docs: document agent cache helpers 2026-06-04 09:00:00 -04:00
Peter Steinberger
b53c6eae62 docs: document bundle mcp helpers 2026-06-04 08:59:21 -04:00
Peter Steinberger
67ff2f8c95 docs: document btw side-question helpers 2026-06-04 08:58:19 -04:00
Peter Steinberger
1e1a966651 docs: document agent bootstrap helpers 2026-06-04 08:57:18 -04:00
Peter Steinberger
9b9d4883c3 docs: document codex command helpers 2026-06-04 08:55:39 -04:00
Peter Steinberger
796ed1b501 docs: document codex approval roundtrip 2026-06-04 08:53:19 -04:00
Peter Steinberger
ff867fcb7f docs: document codex protocol validators 2026-06-04 08:51:38 -04:00
Peter Steinberger
e72447de40 docs: document codex app-server support helpers 2026-06-04 08:50:13 -04:00
Peter Steinberger
bd94eda53a docs: document codex trajectory progress helpers 2026-06-04 08:48:00 -04:00
Peter Steinberger
d99268ae51 docs: document codex plugin app config 2026-06-04 08:46:41 -04:00
Peter Steinberger
22efdfa904 docs: document codex app-server runtime utilities 2026-06-04 08:45:03 -04:00
Peter Steinberger
b91ed087c8 docs: document codex app-server small utilities 2026-06-04 08:42:50 -04:00
Peter Steinberger
e4a775567c docs: document codex sandbox process bridge 2026-06-04 08:41:11 -04:00
Peter Steinberger
e1c7f228d6 docs: document codex sandbox fs policy 2026-06-04 08:40:26 -04:00
Peter Steinberger
226f5ac17f docs: document codex sandbox exec server 2026-06-04 08:39:30 -04:00
Peter Steinberger
29e9625b18 docs: document codex sandbox exec fs http 2026-06-04 08:37:41 -04:00
Peter Steinberger
b1c47dabd9 docs: document codex sandbox exec protocol 2026-06-04 08:36:28 -04:00
Peter Steinberger
2ff83d3023 docs: document codex app-server utilities 2026-06-04 08:35:15 -04:00
Peter Steinberger
121ee3f555 docs: document codex native subagent helpers 2026-06-04 08:33:42 -04:00
Peter Steinberger
7a2aa68960 docs: document codex app-server helpers 2026-06-04 08:32:30 -04:00
Peter Steinberger
c67491cbaf docs: document codex dynamic tool build 2026-06-04 08:31:20 -04:00
Peter Steinberger
7139f47333 docs: document codex dynamic tool bridge 2026-06-04 08:29:21 -04:00
Peter Steinberger
381a51b2d4 docs: document codex compaction projection 2026-06-04 08:27:05 -04:00
Peter Steinberger
0dc1d6a989 docs: document codex app-server client helpers 2026-06-04 08:25:40 -04:00
Peter Steinberger
0b5298d24e docs: document codex attempt context 2026-06-04 08:22:45 -04:00
Peter Steinberger
d249e25a64 docs: document codex attempt lifecycle helpers 2026-06-04 08:21:04 -04:00
Peter Steinberger
0050f6b165 docs: document codex notification helpers 2026-06-04 08:19:31 -04:00
Peter Steinberger
23258c86be docs: document codex app-server cleanup modules 2026-06-04 08:18:04 -04:00
Peter Steinberger
f60943717e docs: document codex root plugin modules 2026-06-04 08:16:35 -04:00
Peter Steinberger
8b477d2887 docs: document cloudflare and codex supervisor plugins 2026-06-04 08:14:22 -04:00
Peter Steinberger
802cdc7783 docs: document clickclack plugin 2026-06-04 08:12:22 -04:00
Peter Steinberger
a4a27517ff docs: document cerebras and chutes providers 2026-06-04 08:09:34 -04:00
Peter Steinberger
4726aaa08c docs: document canvas plugin 2026-06-04 08:07:38 -04:00
Peter Steinberger
18ecb82034 docs: document byteplus provider 2026-06-04 08:03:04 -04:00
Peter Steinberger
e900428a47 docs: document repo support scripts 2026-06-04 08:01:15 -04:00
Peter Steinberger
f07ee23d23 docs: document browser root modules 2026-06-04 08:00:12 -04:00
Peter Steinberger
f750029c72 docs: document browser support modules 2026-06-04 07:58:03 -04:00
Peter Steinberger
0d7f8051d0 docs: document browser cli modules 2026-06-04 07:56:15 -04:00
Peter Steinberger
5ab430fa11 docs: document browser server context 2026-06-04 07:53:45 -04:00
Peter Steinberger
29ddb9d926 docs: document browser utility helpers 2026-06-04 07:50:05 -04:00
Peter Steinberger
383531da96 docs: document browser playwright tools 2026-06-04 07:47:51 -04:00
Peter Steinberger
44ceccd2be docs: document browser playwright session 2026-06-04 07:45:58 -04:00
Peter Steinberger
3720ecaf52 docs: document browser config paths 2026-06-04 07:42:57 -04:00
Peter Steinberger
e8e57f9395 docs: document browser config support 2026-06-04 07:40:44 -04:00
Peter Steinberger
3dcdfee1e1 docs: document browser client APIs 2026-06-04 07:37:59 -04:00
Peter Steinberger
b24979cc30 docs: document browser chrome helpers 2026-06-04 07:36:15 -04:00
Peter Steinberger
c32748bc28 docs: document browser cdp runtime 2026-06-04 07:34:30 -04:00
Peter Steinberger
a3af426353 docs: document browser route support 2026-06-04 07:31:50 -04:00
Peter Steinberger
7fe6c16f03 docs: document browser route handlers 2026-06-04 07:29:19 -04:00
Peter Steinberger
ce56fc176a docs: document browser act routes 2026-06-04 07:27:43 -04:00
Peter Steinberger
5dcb072f7f docs: document browser cdp policies 2026-06-04 07:26:23 -04:00
Peter Steinberger
a982f798ca docs: document browser tool runtime 2026-06-04 07:24:31 -04:00
Peter Steinberger
83e4cfba30 docs: document browser plugin entrypoints 2026-06-04 07:22:35 -04:00
Peter Steinberger
2ad6314d72 docs: document small provider plugins 2026-06-04 07:20:32 -04:00
Peter Steinberger
caf930e65e docs: document anthropic runtime provider 2026-06-04 07:17:20 -04:00
Peter Steinberger
d89ad16124 docs: document anthropic cli config helpers 2026-06-04 07:15:05 -04:00
Peter Steinberger
c46610472f docs: document anthropic vertex plugin 2026-06-04 07:13:17 -04:00
Peter Steinberger
8cfc09238f docs: document bedrock provider plugins 2026-06-04 07:11:24 -04:00
Peter Steinberger
8c02521c47 docs: document active memory admin alibaba plugins 2026-06-04 07:07:49 -04:00
Peter Steinberger
bac84c5858 docs: document acpx runtime internals 2026-06-04 07:06:08 -04:00
Peter Steinberger
198d0b36a2 docs: document acpx process runtime helpers 2026-06-04 07:04:59 -04:00
Peter Steinberger
33c284ca0d docs: document acpx entry contracts 2026-06-04 07:03:35 -04:00
Peter Steinberger
1cbbfe8ed2 docs: document workspace policy helpers 2026-06-04 07:02:08 -04:00
Peter Steinberger
7ef836812b docs: document runtime plan contracts 2026-06-04 06:59:48 -04:00
Peter Steinberger
6ca104d129 docs: document runtime config helpers 2026-06-04 06:57:27 -04:00
Peter Steinberger
1a8263c2f5 docs: document auth redaction helpers 2026-06-04 06:55:31 -04:00
Peter Steinberger
18ed27bf5f docs: document provider planning helpers 2026-06-04 06:53:58 -04:00
Peter Steinberger
8edd7e84ad docs: document session output helpers 2026-06-04 06:52:02 -04:00
Peter Steinberger
7fb74310f0 docs: document agent policy helpers 2026-06-04 06:50:26 -04:00
Peter Steinberger
eb48b6bd06 docs: document agent utility contracts 2026-06-04 06:48:45 -04:00
Peter Steinberger
511f114138 docs: document models config runtime 2026-06-04 06:47:40 -04:00
Peter Steinberger
7913b6cd27 docs: document agent control helpers 2026-06-04 06:46:16 -04:00
Peter Steinberger
f3a2488ab0 docs: document agent test helpers 2026-06-04 06:44:16 -04:00
Peter Steinberger
f5f046a736 docs: document provider auth helpers 2026-06-04 06:42:49 -04:00
Peter Steinberger
e533ff4c4a docs: document runtime helper contracts 2026-06-04 06:40:26 -04:00
Peter Steinberger
fbf3e009d4 docs: document failover utility helpers 2026-06-04 06:37:21 -04:00
Peter Steinberger
21031c2243 docs: document model policy helpers 2026-06-04 06:34:39 -04:00
Peter Steinberger
5181a93391 docs: document agent utility helpers 2026-06-04 06:32:31 -04:00
Peter Steinberger
a8f6e7601b docs: document live model helpers 2026-06-04 06:30:11 -04:00
Peter Steinberger
76f2a12ad7 docs: document auth marker helpers 2026-06-04 06:28:22 -04:00
Peter Steinberger
88eb405491 docs: document tool utility helpers 2026-06-04 06:26:19 -04:00
Peter Steinberger
36ae3dd235 docs: document transcript policy helpers 2026-06-04 06:24:59 -04:00
Peter Steinberger
53d08d4aef docs: document agent helper contracts 2026-06-04 06:23:32 -04:00
Peter Steinberger
d2d2dfd9f2 docs: document process tool controls 2026-06-04 06:21:15 -04:00
Peter Steinberger
ac7ef5b8c6 style: restore exec approval e2e formatting 2026-06-04 06:18:55 -04:00
Peter Steinberger
bc88f735cd style: restore exec approval e2e formatting 2026-06-04 06:17:53 -04:00
Peter Steinberger
2feb81249f docs: document exec tool entry 2026-06-04 06:16:34 -04:00
Peter Steinberger
045145c700 docs: document exec runtime 2026-06-04 06:13:45 -04:00
Peter Steinberger
ec6cf6a2ac docs: document node exec host 2026-06-04 06:12:10 -04:00
Peter Steinberger
6537080674 docs: document gateway exec host 2026-06-04 06:09:49 -04:00
Peter Steinberger
8cd4d74d94 docs: document exec approval requests 2026-06-04 06:08:28 -04:00
Peter Steinberger
e5f3bf99cc docs: document exec approval followups 2026-06-04 06:07:16 -04:00
Peter Steinberger
11eb9ac1b9 docs: document bash tool helpers 2026-06-04 06:06:03 -04:00
Peter Steinberger
41cefdff8f docs: document bash process registry 2026-06-04 06:04:28 -04:00
Peter Steinberger
7b8da19302 docs: document auth profile usage 2026-06-04 06:03:18 -04:00
Peter Steinberger
db7a228e6c docs: document auth profile state store 2026-06-04 06:01:47 -04:00
Peter Steinberger
f9613ff01e docs: document auth profile persistence 2026-06-04 05:59:18 -04:00
Ayaan Zaidi
9ed9af4f39 fix(agents): restore Anthropic system cache boundary 2026-06-04 15:27:23 +05:30
Ayaan Zaidi
01cc68ee0d fix(agents): bound Anthropic cache markers 2026-06-04 15:27:23 +05:30
Ayaan Zaidi
2454952544 fix(agents): keep Anthropic tool cache breakpoint advancing 2026-06-04 15:27:23 +05:30
Ayaan Zaidi
77c383d1e0 refactor(agents): distill Anthropic cache marker cleanup 2026-06-04 15:27:23 +05:30
Peter Lindsey
ca9ab97427 fix: stabilize Anthropic cache marker through tool loops 2026-06-04 15:27:23 +05:30
Peter Steinberger
e1da5a36d4 docs: document oauth profile resolution 2026-06-04 05:57:01 -04:00
Peter Steinberger
d581d9d733 docs: document oauth refresh manager 2026-06-04 05:54:47 -04:00
Peter Steinberger
9d20ad261a docs: document oauth identity helpers 2026-06-04 05:52:57 -04:00
Peter Steinberger
81516ca1a4 docs: document external auth overlays 2026-06-04 05:51:25 -04:00
Peter Steinberger
474d6e520a docs: document auth health helpers 2026-06-04 05:49:50 -04:00
Vincent Koc
2cba10a49f test(infra): remove empty skipped builtin placeholder 2026-06-04 11:48:40 +02:00
Peter Steinberger
f7ef52e66d docs: document apply patch helpers 2026-06-04 05:47:45 -04:00
Peter Steinberger
479df18caf docs: document anthropic agent transports 2026-06-04 05:46:46 -04:00
Peter Steinberger
523537a627 docs: document agent tool assembly 2026-06-04 05:45:05 -04:00
Peter Steinberger
c25800ccc1 docs: document agent tool guards 2026-06-04 05:43:42 -04:00
Peter Steinberger
60e0d2a7b9 docs: document agent tool adapters 2026-06-04 05:41:50 -04:00
Peter Steinberger
634174f050 docs: document agent model settings 2026-06-04 05:38:58 -04:00
Peter Steinberger
6c113837b8 docs: document agent command hooks 2026-06-04 05:36:39 -04:00
Peter Steinberger
f2d8facb48 docs: document agent bundle runtimes 2026-06-04 05:34:48 -04:00
Peter Steinberger
b851ba2f98 docs: document agents acp auth helpers 2026-06-04 05:32:57 -04:00
Peter Steinberger
e112fb939a docs: document acp translator bridge 2026-06-04 05:31:15 -04:00
Peter Steinberger
61fdc7bf34 docs: document acp runtime bridge 2026-06-04 05:29:10 -04:00
Peter Steinberger
fc64494b03 docs: document acp events and bindings 2026-06-04 05:27:58 -04:00
Peter Steinberger
05289f1aa0 docs: document acp turn control plane 2026-06-04 05:26:08 -04:00
Peter Steinberger
d88b06cb75 docs: document acp runtime handles 2026-06-04 05:24:49 -04:00
Peter Steinberger
c782e8e44f docs: document acp control plane failover 2026-06-04 05:23:42 -04:00
Peter Steinberger
5a350aeaf5 docs: document acp client helpers 2026-06-04 05:22:29 -04:00
Peter Steinberger
053fbf0209 docs: document web fetch runtime 2026-06-04 05:21:16 -04:00
Peter Steinberger
3c1e9984e0 docs: document secrets surface helpers 2026-06-04 05:20:16 -04:00
Peter Steinberger
bea35d0902 docs: document secrets resolution helpers 2026-06-04 05:17:28 -04:00
Peter Steinberger
d28ac4dbdb docs: document secrets target registry 2026-06-04 05:13:24 -04:00
Peter Steinberger
a720a1f9de docs: document secrets runtime state 2026-06-04 05:09:51 -04:00
Peter Steinberger
5a869eea5a docs: document node host runtime 2026-06-04 05:06:54 -04:00
Peter Steinberger
0135a0a780 docs: document image generation runtime 2026-06-04 05:00:21 -04:00
Peter Steinberger
f4d2748ca5 docs: document plugin metadata utilities 2026-06-04 04:57:48 -04:00
Vincent Koc
72bb5cd692 fix(e2e): bound release journey output assertions 2026-06-04 10:55:37 +02:00
Peter Steinberger
7c1deea5fa docs: document plugin setup state 2026-06-04 04:54:37 -04:00
Peter Steinberger
f875b519e5 docs: document plugin host contracts 2026-06-04 04:51:24 -04:00
Peter Steinberger
040ebadfc5 docs: document plugin runtime contracts 2026-06-04 04:48:42 -04:00
Peter Steinberger
f91fab8b18 docs: document plugin manifest helpers 2026-06-04 04:46:27 -04:00
Peter Steinberger
a77f20a6d6 docs: document plugin registry helpers 2026-06-04 04:44:12 -04:00
Peter Steinberger
4d54d196c9 docs: document plugin discovery helpers 2026-06-04 04:41:47 -04:00
Peter Steinberger
fffd72f36d docs: document plugin compatibility helpers 2026-06-04 04:38:31 -04:00
Peter Steinberger
21572415c8 docs: document plugin lifecycle helpers 2026-06-04 04:36:44 -04:00
Peter Steinberger
f6049db20f docs: document plugin discovery helpers 2026-06-04 04:34:19 -04:00
Vincent Koc
d77d231507 fix(e2e): ignore stale agent output markers 2026-06-04 10:32:31 +02:00
Peter Steinberger
6de517cbcb docs: document plugin registry helpers 2026-06-04 04:31:52 -04:00
Peter Steinberger
507e237d8c docs: document plugin command helpers 2026-06-04 04:29:53 -04:00
Peter Steinberger
6082f01b97 docs: document plugin loader helpers 2026-06-04 04:27:23 -04:00
Peter Steinberger
d33664aef0 docs: document plugin provider helpers 2026-06-04 04:25:18 -04:00
Peter Steinberger
8975f75c8b docs: document plugin public surface helpers 2026-06-04 04:22:45 -04:00
Peter Steinberger
463e9f2704 docs: document plugin install metadata helpers 2026-06-04 04:21:07 -04:00
Vincent Koc
10b9df6d8a fix(release): bound cross-os agent log fallback reads 2026-06-04 10:19:21 +02:00
Peter Steinberger
ee282c6de5 docs: document plugin auth helpers 2026-06-04 04:19:03 -04:00
Peter Steinberger
6d6aba2be5 docs: document plugin runtime helpers 2026-06-04 04:17:40 -04:00
Peter Steinberger
a6d084113a docs: document plugin install helpers 2026-06-04 04:15:33 -04:00
Peter Steinberger
6a2b1b2198 docs: document plugin metadata helpers 2026-06-04 04:14:06 -04:00
Peter Steinberger
e8e6c684bb docs: document tui and plugin helpers 2026-06-04 04:12:38 -04:00
Peter Steinberger
4ed2fb75f2 docs: document tui runtime helpers 2026-06-04 04:10:14 -04:00
Peter Steinberger
bced79b63d docs: document security policy helpers 2026-06-04 04:08:10 -04:00
Mrunal Patel
d522e02fe4 fix(docker): qualify base image refs for podman short-name mode (#90058)
* fix(docker): qualify base image refs for podman short-name mode

Podman with short-name-mode=enforcing (the Fedora/RHEL default) blocked
the build: `FROM oven/bun:1.3.13...` is an ambiguous short name with no
alias, so Podman prompted interactively for a registry (the apparent
"hang") or, headless, failed with "short-name resolution enforced but
cannot prompt without a TTY". `node:*` only resolved because a `node`
short-name alias ships in registries.conf.d.

Fully-qualify the node and bun base images with docker.io/ so registry
resolution is deterministic. Pinned digests are unchanged, so resolved
image content is identical, and Docker/Buildx builds are unaffected.

Also qualify the docker.io/ prefix in the digest-refresh maintenance
comments so the documented update path matches the defaults and does not
reintroduce the same short-name ambiguity for Podman users.

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

* test(docker): expect qualified base image refs

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: sallyom <somalley@redhat.com>
2026-06-04 04:06:20 -04:00
Peter Steinberger
961759c08b docs: document security finding helpers 2026-06-04 04:06:08 -04:00
Peter Steinberger
0e8c5fd85d docs: document security audit helpers 2026-06-04 04:04:43 -04:00
Peter Steinberger
8408c16da4 docs: document config diagnostics helpers 2026-06-04 04:03:16 -04:00
Peter Steinberger
40c8ed0dff docs: document config provider helpers 2026-06-04 04:01:24 -04:00
Peter Steinberger
838644b989 docs: document config policy helpers 2026-06-04 04:00:03 -04:00
Peter Steinberger
0796e992e4 docs: document config schema runtime helpers 2026-06-04 03:58:47 -04:00
mushuiyu_xydt
1f1ce8a1fe fix(feishu): preserve streaming card content (#90181)
* fix(feishu): preserve streaming card content

* fix(feishu): preserve streaming card content (#90181) (thanks @mushuiyu886)

---------

Co-authored-by: sliverp <870080352@qq.com>
2026-06-04 15:57:37 +08:00
Peter Steinberger
9572267f64 docs: document config recovery helpers 2026-06-04 03:57:07 -04:00
Peter Steinberger
edc6042c65 docs: document config validation helpers 2026-06-04 03:55:53 -04:00
Peter Steinberger
186e966483 docs: document config agent helpers 2026-06-04 03:54:37 -04:00
Peter Steinberger
51474b6f15 docs: document config mutation helpers 2026-06-04 03:52:12 -04:00
Peter Steinberger
54fe5dc842 docs: document config runtime helpers 2026-06-04 03:51:01 -04:00
Peter Steinberger
6989d6283a docs: document config io helpers 2026-06-04 03:49:54 -04:00
Peter Steinberger
43190f5248 docs: document config schema helpers 2026-06-04 03:47:57 -04:00
Peter Steinberger
6f358fd8e0 docs: document config and commitments helpers 2026-06-04 03:46:55 -04:00
Peter Steinberger
bff849b874 docs: document tool and model helpers 2026-06-04 03:45:53 -04:00
Peter Steinberger
606e3d7866 docs: document task execution helpers 2026-06-04 03:44:45 -04:00
Peter Steinberger
cca24cc78b docs: document task registry helpers 2026-06-04 03:43:46 -04:00
Peter Steinberger
4930766711 docs: document infra flow helpers 2026-06-04 03:42:18 -04:00
Peter Steinberger
2e8b444da8 docs: document infra storage helpers 2026-06-04 03:40:45 -04:00
Peter Steinberger
d13a431860 docs: document infra install runtime helpers 2026-06-04 03:37:48 -04:00
Peter Steinberger
117aca7f4e docs: document infra approval runtime helpers 2026-06-04 03:34:47 -04:00
Peter Steinberger
ec3aa5def4 docs: document infra transport helpers 2026-06-04 03:32:06 -04:00
Peter Steinberger
73b6de1011 docs: document infra socket helpers 2026-06-04 03:29:58 -04:00
Peter Steinberger
5780aa1cd6 docs: document infra heartbeat helpers 2026-06-04 03:27:16 -04:00
Peter Steinberger
cfe31ca3b2 docs: document infra policy helpers 2026-06-04 03:24:36 -04:00
Peter Steinberger
25eb63885d docs: document infra event helpers 2026-06-04 03:22:42 -04:00
Peter Steinberger
79dc565825 docs: document infra database helpers 2026-06-04 03:20:32 -04:00
Peter Steinberger
5dcb2ab40e docs: document infra push helpers 2026-06-04 03:17:57 -04:00
Peter Steinberger
d3b38311b0 docs: document infra approval helpers 2026-06-04 03:16:06 -04:00
Peter Steinberger
59fca2d738 docs: document infra runtime helpers 2026-06-04 03:14:19 -04:00
Peter Steinberger
1275368151 docs: document infra install helpers 2026-06-04 03:12:47 -04:00
Peter Steinberger
a881181fd8 docs: document infra update helpers 2026-06-04 03:11:12 -04:00
Peter Steinberger
f542e23a2f docs: document infra pairing helpers 2026-06-04 03:09:43 -04:00
Pavan Kumar Gondhi
3c6259ebb7 fix: guard mcp http redirects (#89732) 2026-06-04 12:38:25 +05:30
Peter Steinberger
6851dc9505 docs: document infra config helpers 2026-06-04 03:08:12 -04:00
Vincent Koc
cce1a14795 fix(e2e): bound parallels package progress extraction 2026-06-04 09:06:35 +02:00
Peter Steinberger
2f814c6c92 docs: document infra execution helpers 2026-06-04 03:06:18 -04:00
Peter Steinberger
dc3f2bd1d9 docs: document infra process helpers 2026-06-04 03:03:13 -04:00
Peter Steinberger
d819ef3e32 docs: document infra status helpers 2026-06-04 03:00:57 -04:00
Peter Steinberger
334a1dd716 docs: document infra package helpers 2026-06-04 02:58:15 -04:00
Vincent Koc
5c08fb225a fix(e2e): stream docker stats resource scans 2026-06-04 08:57:47 +02:00
Peter Steinberger
0d109750ae docs: document infra runtime helpers 2026-06-04 02:55:39 -04:00
Peter Steinberger
a9a386dee1 docs: document test utils and infra helpers 2026-06-04 02:53:43 -04:00
Peter Steinberger
4295329ec3 docs: document test utility helpers 2026-06-04 02:51:28 -04:00
Peter Steinberger
b4f16c7bcb docs: document pairing and transcript helpers 2026-06-04 02:49:38 -04:00
Vincent Koc
e17bfc4938 fix(e2e): tighten kitchen sink plugin log allowlist 2026-06-04 08:48:58 +02:00
Peter Steinberger
2db057423b docs: document root and music generation helpers 2026-06-04 02:47:44 -04:00
Peter Steinberger
c1aa424d6b docs: document src root entry helpers 2026-06-04 02:45:34 -04:00
Peter Steinberger
b18a05ae3e docs: document auto reply queue and acp helpers 2026-06-04 02:43:05 -04:00
Peter Steinberger
29f057b242 docs: document auto reply admission helpers 2026-06-04 02:41:04 -04:00
Peter Steinberger
119bb57627 docs: document auto reply command gates 2026-06-04 02:39:12 -04:00
Vincent Koc
21c3d6993b fix(e2e): tighten kitchen sink error log allowlist 2026-06-04 08:37:59 +02:00
Peter Steinberger
e71e585969 docs: document auto reply fast path helpers 2026-06-04 02:37:27 -04:00
Peter Steinberger
ea6d3a35ff docs: document auto reply dispatch helpers 2026-06-04 02:35:34 -04:00
Peter Steinberger
26355cc35d docs: document auto reply delivery runtime 2026-06-04 02:33:09 -04:00
Peter Steinberger
25e9097af0 docs: document auto reply session routing 2026-06-04 02:31:18 -04:00
Vincent Koc
d0f05d98d2 fix(e2e): share gateway websocket request handling 2026-06-04 08:29:33 +02:00
Peter Steinberger
88b27c378d docs: document auto reply directive helpers 2026-06-04 02:29:18 -04:00
Peter Steinberger
a66462b583 docs: document auto reply runner support 2026-06-04 02:28:00 -04:00
Peter Steinberger
e61fb145fc docs: document auto reply runtime helpers 2026-06-04 02:26:38 -04:00
Peter Steinberger
afeab32780 docs: document auto reply routing helpers 2026-06-04 02:25:21 -04:00
Peter Steinberger
4e5752631c docs: document auto reply behavior tests 2026-06-04 02:23:56 -04:00
Peter Steinberger
08b1b06aab docs: document auto reply reply tests 2026-06-04 02:21:46 -04:00
Peter Steinberger
0289b046da docs: document auto reply command tests 2026-06-04 02:18:51 -04:00
Peter Steinberger
1053a76dd8 docs: document auto reply top-level tests 2026-06-04 02:16:34 -04:00
Peter Steinberger
82e5dd4da7 docs: document auto reply runner internals 2026-06-04 02:13:57 -04:00
Peter Steinberger
a70e618b20 docs: document auto reply routing helpers 2026-06-04 02:11:29 -04:00
Peter Steinberger
20d7c7ae02 docs: document auto reply run helpers 2026-06-04 02:09:32 -04:00
Peter Steinberger
1c0fb5768b docs: document auto reply command helpers 2026-06-04 02:06:38 -04:00
Peter Steinberger
25c0699fe9 docs: document auto reply delivery helpers 2026-06-04 02:04:44 -04:00
Vincent Koc
ce0d5117bf fix(e2e): fail codex app server log errors 2026-06-04 08:03:24 +02:00
Peter Steinberger
826cdd884c docs: document auto reply command contracts 2026-06-04 02:01:00 -04:00
Peter Steinberger
4503560084 docs: document auto reply top-level helpers 2026-06-04 01:58:27 -04:00
Peter Steinberger
bf1056c554 docs: document gateway helper contracts 2026-06-04 01:54:01 -04:00
Peter Steinberger
344417c0de docs: document media and sdk package facades 2026-06-04 01:51:12 -04:00
Peter Steinberger
86150a3e51 docs: document shared test helpers 2026-06-04 01:48:32 -04:00
Peter Steinberger
d8b5e22e8b docs: document voice call runtime surfaces 2026-06-04 01:45:11 -04:00
Peter Steinberger
5dd026f3f7 docs: document voice call manager helpers 2026-06-04 01:42:32 -04:00
Peter Steinberger
ae5376a599 docs: document voice call helper APIs 2026-06-04 01:41:07 -04:00
Vincent Koc
cc122956df fix(qa): bound malformed otlp receiver requests 2026-06-04 07:39:30 +02:00
Peter Steinberger
eaf803b223 docs: document shared package contracts 2026-06-04 01:39:12 -04:00
Peter Steinberger
d14fe163b5 docs: document terminal core helpers 2026-06-04 01:36:23 -04:00
Peter Steinberger
5b98f03c64 docs: document memory host runtime helpers 2026-06-04 01:34:57 -04:00
Peter Steinberger
eecec7495f docs: document memory remote helpers 2026-06-04 01:32:51 -04:00
Peter Steinberger
c40dd6ff5c docs: document memory batch helpers 2026-06-04 01:31:52 -04:00
Peter Steinberger
8b6bed9c9c docs: document memory host sdk helpers 2026-06-04 01:30:42 -04:00
Peter Steinberger
5a10f46c56 docs: document sdk package facades 2026-06-04 01:26:12 -04:00
Peter Steinberger
bdfeece562 docs: document agent core package 2026-06-04 01:23:43 -04:00
Peter Steinberger
aafdf67d39 docs: document speech core facades 2026-06-04 01:22:31 -04:00
Peter Steinberger
55bde6750f docs: document embedded agent barrels 2026-06-04 01:21:09 -04:00
Peter Steinberger
546f44f395 docs: document ssh sandbox helpers 2026-06-04 01:20:33 -04:00
Peter Steinberger
9877f31fdd docs: document code mode bridge 2026-06-04 01:19:45 -04:00
Peter Steinberger
9bc7712c40 docs: document model selection reconciliation 2026-06-04 01:18:43 -04:00
Peter Steinberger
ba445e0e3f docs: document tool search surfaces 2026-06-04 01:17:16 -04:00
Peter Steinberger
f1ec2605b7 docs: document subscribe helper seams 2026-06-04 01:16:17 -04:00
Peter Steinberger
81f359ec5b docs: document transcript state harness 2026-06-04 01:15:25 -04:00
Peter Steinberger
d8a67ef39a docs: document sandbox backend bridges 2026-06-04 01:14:14 -04:00
Peter Steinberger
cf36b9456d docs: document subagent display seams 2026-06-04 01:12:08 -04:00
Peter Steinberger
376bf65d8e docs: document session list web search tools 2026-06-04 01:10:37 -04:00
Peter Steinberger
b7b069c4d6 docs: document Claude CLI runner helpers 2026-06-04 01:08:59 -04:00
Peter Steinberger
340fca0a45 docs: document embedded compaction helpers 2026-06-04 01:07:28 -04:00
Peter Steinberger
c768a9e6ca docs: document e2e helper mocks 2026-06-04 01:05:37 -04:00
Peter Steinberger
ce1ef04efe docs: document schema media planning helpers 2026-06-04 01:04:21 -04:00
Peter Steinberger
79f6c5a8ad docs: document media generation actions 2026-06-04 01:02:54 -04:00
Peter Steinberger
3a5baf1229 docs: document embedded attempt helpers 2026-06-04 01:01:38 -04:00
Peter Steinberger
fe52654d2e docs: document agent test helpers 2026-06-04 01:00:05 -04:00
Peter Steinberger
45144ce2e8 docs: document model helper normalization 2026-06-04 00:58:43 -04:00
Peter Steinberger
5b36bbf83e docs: document sandbox lifecycle registry 2026-06-04 00:57:14 -04:00
Peter Steinberger
9b4e2fa8a8 docs: document session tool bridges 2026-06-04 00:55:22 -04:00
Peter Steinberger
cc191e8021 docs: document sandbox support types 2026-06-04 00:53:43 -04:00
Peter Steinberger
64b9b60d94 docs: document runner guard helpers 2026-06-04 00:52:32 -04:00
Vincent Koc
68307afb5b fix(e2e): fail parallels host log write errors 2026-06-04 06:51:27 +02:00
Peter Steinberger
5a557b5e10 docs: document embedded runner state helpers 2026-06-04 00:51:06 -04:00
Peter Steinberger
7e85ba6139 docs: document sandbox helper utilities 2026-06-04 00:49:00 -04:00
Peter Steinberger
edd3870d53 docs: document session helper metadata 2026-06-04 00:47:48 -04:00
Peter Steinberger
a590fd24a9 docs: document agent harness helpers 2026-06-04 00:46:44 -04:00
Peter Steinberger
8f14a1c59a docs: document embedded runner helpers 2026-06-04 00:45:31 -04:00
Peter Steinberger
e1db0f01fe docs: document image pdf model helpers 2026-06-04 00:42:21 -04:00
Peter Steinberger
b1053ef9e9 docs: document session reply sentinels 2026-06-04 00:41:04 -04:00
Peter Steinberger
35d801a1e5 docs: document goal planning tools 2026-06-04 00:40:08 -04:00
Peter Steinberger
d901f85abb docs: document sandbox backend contracts 2026-06-04 00:38:23 -04:00
Vincent Koc
61d16dd173 fix(e2e): fail mock openai request log errors 2026-06-04 06:37:24 +02:00
Peter Steinberger
bb8e0ab5dc docs: document sandbox hash helpers 2026-06-04 00:37:11 -04:00
Peter Steinberger
1c640622dd docs: document sandbox safety helpers 2026-06-04 00:36:17 -04:00
Peter Steinberger
918d5afd67 docs: document embedded gateway helpers 2026-06-04 00:34:26 -04:00
Peter Steinberger
5820d105c9 docs: document media generation task helpers 2026-06-04 00:33:39 -04:00
Pavan Kumar Gondhi
3f1e0ebb86 Rate limit node pairing requests [AI] (#90147)
* fix: rate limit node pairing requests

* fix: preserve paired node reconnects
2026-06-04 10:02:55 +05:30
Peter Steinberger
52f96fab51 docs: document subagent tool step helpers 2026-06-04 00:31:53 -04:00
Peter Steinberger
9c10ef2ffa docs: document web fetch helpers 2026-06-04 00:30:14 -04:00
Peter Steinberger
4cd8b5eb78 docs: document tool runtime availability helpers 2026-06-04 00:29:25 -04:00
Peter Steinberger
07676fbb44 docs: document subagent registry read helpers 2026-06-04 00:28:29 -04:00
Peter Steinberger
bb1f3e8eaf docs: document session tool render helpers 2026-06-04 00:26:52 -04:00
Peter Steinberger
fd3cc7d224 docs: document session support helpers 2026-06-04 00:26:08 -04:00
Peter Steinberger
5a62a896b2 docs: document subagent announce runtime helpers 2026-06-04 00:25:03 -04:00
Pavan Kumar Gondhi
85b26bd206 fix: protect global agent config defaults (#90145) 2026-06-04 09:53:56 +05:30
Peter Steinberger
6f08a1a3dd docs: document session tool helpers 2026-06-04 00:23:38 -04:00
Peter Steinberger
20c3736dae docs: document web search helper config 2026-06-04 00:22:49 -04:00
Peter Steinberger
3c21fdad3c docs: document subagent session helpers 2026-06-04 00:22:08 -04:00
Peter Steinberger
5960549816 docs: document session keybinding helpers 2026-06-04 00:20:46 -04:00
Vincent Koc
2baa9d550e fix(e2e): fail pty transcript log errors 2026-06-04 06:20:02 +02:00
Peter Steinberger
b90fb1ef71 docs: document tool inventory helpers 2026-06-04 00:19:46 -04:00
Peter Steinberger
301c6d0043 docs: document exec utility helpers 2026-06-04 00:18:22 -04:00
Peter Steinberger
ed4c133c2c docs: document tool policy helpers 2026-06-04 00:17:34 -04:00
Peter Steinberger
f4369d225a docs: document model auth helpers 2026-06-04 00:15:57 -04:00
Peter Steinberger
b77c272fb9 docs: document tool model helpers 2026-06-04 00:13:55 -04:00
Peter Steinberger
46f3efe7ce docs: document harness hook helpers 2026-06-04 00:12:10 -04:00
Peter Steinberger
87b5796649 docs: document agent test fixtures 2026-06-04 00:10:47 -04:00
Peter Steinberger
2bb3132a5c docs: document harness classification helpers 2026-06-04 00:09:28 -04:00
Vincent Koc
54c3f53de5 fix(e2e): fail vanished crabbox sync checkouts 2026-06-04 06:08:04 +02:00
Peter Steinberger
73a81d1d6a docs: document harness helpers 2026-06-04 00:07:49 -04:00
Peter Steinberger
7b02080fa1 docs: document runtime utility helpers 2026-06-04 00:05:49 -04:00
Peter Steinberger
c90f42dbae docs: document dispatch report helpers 2026-06-04 00:04:19 -04:00
Peter Steinberger
32282418eb docs: document schema status helpers 2026-06-03 23:47:47 -04:00
Peter Steinberger
3eaab8632e docs: document mcp plugin helpers 2026-06-03 23:46:22 -04:00
Peter Steinberger
ff43ede887 docs: document cli compat helpers 2026-06-03 23:45:12 -04:00
Peter Steinberger
e4f6dd3440 docs: document agent utility helpers 2026-06-03 23:43:45 -04:00
Peter Steinberger
48557cecff docs: document model tool helpers 2026-06-03 23:41:43 -04:00
Peter Steinberger
6439b64c90 docs: document shared runtime helpers 2026-06-03 23:40:46 -04:00
Peter Steinberger
2fb968a425 docs: document runtime system helpers 2026-06-03 23:39:30 -04:00
Peter Steinberger
ddaa2c5dc8 docs: document status capability helpers 2026-06-03 23:38:32 -04:00
Peter Steinberger
fba1e49083 docs: document live provider probes 2026-06-03 23:37:21 -04:00
Peter Steinberger
059277f83b docs: document provider error helpers 2026-06-03 23:35:55 -04:00
Peter Steinberger
ae8b868342 docs: document oauth test helpers 2026-06-03 23:32:59 -04:00
Peter Steinberger
48d6c75111 docs: document text transform helpers 2026-06-03 23:30:53 -04:00
Mukunda Rao Katta
d966486242 fix(whatsapp): restart channel when a per-account config field changes so disabled accounts are torn down (#87965)
Merged via squash.

Prepared head SHA: 4142d5562e
Co-authored-by: MukundaKatta <99349238+MukundaKatta@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-06-04 00:30:29 -03:00
Peter Steinberger
e98b864752 docs: document agent contract helpers 2026-06-03 23:28:53 -04:00
Marcus Castro
88dc177afc fix(auto-reply): count message tool sends as delivery (#90123) 2026-06-04 00:26:45 -03:00
Peter Steinberger
06fee678e1 docs: document runtime timeout helpers 2026-06-03 23:26:32 -04:00
Peter Steinberger
1d2e91e20d docs: document mcp workspace helpers 2026-06-03 23:24:30 -04:00
Peter Steinberger
5169d19ce8 docs: document agent test helpers 2026-06-03 23:21:21 -04:00
Peter Steinberger
86c071035d docs: document provider config helpers 2026-06-03 23:19:46 -04:00
Peter Steinberger
c635716297 docs: document model normalization helpers 2026-06-03 23:17:44 -04:00
Peter Steinberger
0df6292ab3 docs: document live provider helpers 2026-06-03 23:16:10 -04:00
Peter Steinberger
dd555073d0 docs: document provider tool helpers 2026-06-03 23:13:43 -04:00
Vincent Koc
8c74fd4e23 fix(e2e): keep parallels json output parseable 2026-06-04 05:12:13 +02:00
Peter Steinberger
59768909ba docs: document runtime test helpers 2026-06-03 23:11:45 -04:00
Peter Steinberger
1b35d46257 docs: document prompt routing helpers 2026-06-03 23:10:06 -04:00
Peter Steinberger
20e443b965 docs: document model tool utilities 2026-06-03 23:09:20 -04:00
Peter Steinberger
d714803e6d docs: document subagent session helpers 2026-06-03 23:07:58 -04:00
Peter Steinberger
18d036326c docs: document codex context helpers 2026-06-03 23:05:41 -04:00
Peter Steinberger
8b47fa5a76 docs: document runtime utility helpers 2026-06-03 23:02:33 -04:00
Peter Steinberger
e168a82367 docs: document cli runner mcp helpers 2026-06-03 22:59:39 -04:00
Peter Steinberger
83eab79d15 docs: document bootstrap cache helpers 2026-06-03 22:56:27 -04:00
Peter Steinberger
c7a8114f54 docs: document bash process helpers 2026-06-03 22:54:12 -04:00
Peter Steinberger
ef17cecca9 docs: document auth profile store helpers 2026-06-03 22:51:20 -04:00
Peter Steinberger
8835787ed6 docs: document tool hook helpers 2026-06-03 22:47:45 -04:00
Vincent Koc
b12114e45c fix(e2e): abort kitchen sink readiness on gateway exit 2026-06-04 04:46:34 +02:00
Peter Steinberger
32e51f250f docs: document auth redaction helpers 2026-06-03 22:43:51 -04:00
Peter Steinberger
8f7808d1e6 docs: document agent diagnostics helpers 2026-06-03 22:42:05 -04:00
Peter Steinberger
3788a2fd3d docs: document agent steering helpers 2026-06-03 22:40:24 -04:00
Peter Steinberger
b6d6ed34ed docs: document runtime tool helpers 2026-06-03 22:37:59 -04:00
Peter Steinberger
44bcaf00b7 docs: document model auth helpers 2026-06-03 22:36:19 -04:00
Vincent Koc
546aa5770a fix(e2e): report gauntlet log write failures 2026-06-04 04:34:50 +02:00
Peter Steinberger
658f90f845 docs: document subagent model helpers 2026-06-03 22:34:29 -04:00
Peter Steinberger
155260eb04 docs: document model path helpers 2026-06-03 22:33:13 -04:00
Peter Steinberger
7ce1487f33 docs: document auth profile oauth helpers 2026-06-03 22:30:03 -04:00
Peter Steinberger
ac2dbfcfca docs: document auth profile persistence helpers 2026-06-03 22:28:03 -04:00
Vincent Koc
d6ab1fdfe4 test: read codex on-demand auth store from sqlite 2026-06-04 04:26:51 +02:00
Vincent Koc
50c3995894 fix(e2e): fail secret provider startup exits fast 2026-06-04 04:25:53 +02:00
Peter Steinberger
ad958fd97a docs: document auth profile selection helpers 2026-06-03 22:25:34 -04:00
Vincent Koc
0451dcdc56 test(codex): isolate app-server auth fixtures 2026-06-03 19:23:57 -07:00
Peter Steinberger
003bb8546d docs: document auth profile discovery helpers 2026-06-03 22:23:37 -04:00
Peter Steinberger
a2a4924679 docs: document auth profile path state helpers 2026-06-03 22:21:50 -04:00
Peter Steinberger
2ff2ed4099 docs: document agent tool policy helpers 2026-06-03 22:19:38 -04:00
Peter Steinberger
fc5cb461c9 docs: document agent runtime preset helpers 2026-06-03 22:15:52 -04:00
Peter Steinberger
c86eb20dc5 docs: document agent routing state helpers 2026-06-03 22:13:26 -04:00
Peter Steinberger
0d0632d88d docs: document agent runtime utility helpers 2026-06-03 22:11:33 -04:00
Peter Steinberger
2e89655a03 docs: document agent command exec helpers 2026-06-03 22:09:31 -04:00
Peter Steinberger
233666366f docs: document agent command shared helpers 2026-06-03 22:07:59 -04:00
Vincent Koc
474be452a7 test: align dependency override guard with workspace metadata 2026-06-04 04:07:15 +02:00
Peter Steinberger
076178adc6 docs: document agent provider request helpers 2026-06-03 22:06:48 -04:00
Peter Steinberger
eda170f328 docs: document agent inventory recovery helpers 2026-06-03 22:04:42 -04:00
Peter Steinberger
d4867ec20d docs: document agent runtime tool policies 2026-06-03 22:03:35 -04:00
Vincent Koc
d26cef4249 fix(ci): preserve crabbox hydrate pnpm store 2026-06-04 03:59:51 +02:00
Peter Steinberger
e1e095d020 docs: document agent catalog helpers 2026-06-03 21:59:30 -04:00
Vincent Koc
7e5ea598c5 fix(e2e): fail gateway frame waits on socket close 2026-06-04 03:52:52 +02:00
Peter Steinberger
0328f29707 docs: document subagent sqlite registry 2026-06-03 21:51:50 -04:00
Peter Steinberger
9dce23f295 docs: document agent workspace helpers 2026-06-03 21:50:11 -04:00
Peter Steinberger
caa6102144 docs: document agent provider auth helpers 2026-06-03 21:48:41 -04:00
Peter Steinberger
ca3250a3c1 docs: document agent schema and outcome helpers 2026-06-03 21:46:11 -04:00
Vincent Koc
dcfd033746 test: seed auto-reply auth profiles through store 2026-06-04 03:44:04 +02:00
Peter Steinberger
45f4875613 docs: document agent model auth helpers 2026-06-03 21:43:58 -04:00
Peter Steinberger
51e279153f docs: document agent safety helpers 2026-06-03 21:42:04 -04:00
Peter Steinberger
d54addcd28 docs: document agent helper barrels 2026-06-03 21:40:38 -04:00
Peter Steinberger
9eb525de0e docs: document fetch header normalization 2026-06-03 21:38:41 -04:00
Peter Steinberger
d0bf656a3f docs: document session helper APIs 2026-06-03 21:37:49 -04:00
Peter Steinberger
604597d825 docs: document daemon process helpers 2026-06-03 21:35:27 -04:00
Vincent Koc
c286f56167 test: align e2e fixtures with current runtime stores 2026-06-04 03:29:37 +02:00
Vincent Koc
036b730321 fix(scripts): run deadcode knip through pnpm runner 2026-06-04 03:23:45 +02:00
Vincent Koc
deea78da72 perf(gateway): bypass config facade for config handlers 2026-06-04 03:23:45 +02:00
Vincent Koc
eb5d6c7294 perf(gateway): delay provider auth warmup 2026-06-04 03:23:45 +02:00
Vincent Koc
009d7335b5 fix(scripts): run RPC RTT probe without pnpm 2026-06-04 03:23:45 +02:00
Vincent Koc
25f3d2d714 perf(gateway): avoid heavy chat imports in history tests 2026-06-04 03:23:45 +02:00
Peter Steinberger
0416117168 docs: document channel helper APIs 2026-06-03 21:21:02 -04:00
Shakker
4cb34f3999 fix: refresh generated gateway protocol 2026-06-04 02:10:38 +01:00
Shakker
0059f5c24a fix: suppress commands for revision handoff sends 2026-06-04 02:10:38 +01:00
Shakker
4bcae169e2 refactor: centralize chat command interpretation 2026-06-04 02:10:38 +01:00
Shakker
3da05d01a7 fix: namespace chat dedupe by system context 2026-06-04 02:10:38 +01:00
Shakker
f7e44ac6b5 fix: treat Skill Workshop slash drafts as revisions 2026-06-04 02:10:38 +01:00
Shakker
25e3162cce fix: route Skill Workshop revisions through request RPC 2026-06-04 02:10:38 +01:00
Shakker
7150c3c957 fix: separate Skill Workshop revision target agent 2026-06-04 02:10:38 +01:00
Shakker
bf08234ee3 feat: add Skill Workshop revision request 2026-06-04 02:10:38 +01:00
Peter Steinberger
179ff9b423 docs: document plugin registry helper APIs 2026-06-03 21:03:43 -04:00
Peter Steinberger
9b6cd2ea75 docs: document plugin security channel helpers 2026-06-03 21:01:33 -04:00
Vincent Koc
4fbc318e30 ci: stabilize live e2e resource lanes 2026-06-04 02:59:52 +02:00
Brian
7b5f75eb98 Pin official npm plugin install records (#88585)
* fix(plugins): pin official npm install records

* fix(infra): tolerate equivalent plugin install migrations

* fix(plugins): preserve manual exact plugin pins

* fix(infra): remove stale migration imports

* chore: unblock ci guards

* fix: preserve official sync integrity checks

* fix: avoid prerelease integrity carryover

* fix: preserve manual official npm specs

* fix: preserve beta fallback integrity checks

* fix: preserve trusted prerelease fallback integrity

* fix: preserve prerelease-only integrity checks

* fix: pin unchanged official npm records

* fix: allow official compatible fallback updates

* fix: preserve fallback integrity after prerelease resolution

* fix: skip incompatible fallback integrity pins

* fix: preserve pin-only install provenance

* fix: check integrity when repairing missing official pins

---------

Co-authored-by: Lilac <lilac@Lilacs-iMac.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-06-03 17:58:09 -07:00
Peter Steinberger
d1fef1d50d docs: document plugin runtime config helpers 2026-06-03 20:54:08 -04:00
Vincent Koc
392af2e612 fix(deps): keep managed overrides in workspace metadata 2026-06-03 17:43:09 -07:00
Vincent Koc
b4234d4028 test: preserve version exports in partial mocks 2026-06-03 17:43:09 -07:00
Peter Steinberger
69c8097dd1 docs: document plugin overlay memory helpers 2026-06-03 20:41:35 -04:00
Val Alexander
60104fe254 fix(workboard): isolate stale lifecycle bulk patches
Follow-up to #89600 for #88592.

- Keep stale lifecycle bulk updates from mutating shared Workboard patch objects.
- Preserve non-status updates while suppressing stale lifecycle status/provenance writes.
- Tighten current-main migrate-hermes test assertions against the canonical auth-profile store shape.

Verification:
- node scripts/run-vitest.mjs ui/src/ui/controllers/workboard.test.ts ui/src/ui/views/workboard.test.ts extensions/workboard/src/store.test.ts extensions/workboard/src/gateway.test.ts --reporter=verbose
- node scripts/run-vitest.mjs --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/workboard-status-persistence.e2e.test.ts ui/src/ui/e2e/workboard.e2e.test.ts --reporter=verbose
- 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
- node scripts/run-vitest.mjs extensions/migrate-hermes/files-and-skills.test.ts extensions/migrate-hermes/secrets.test.ts --reporter=verbose
- corepack pnpm deadcode:unused-files
- git diff --name-only origin/main...HEAD | xargs node scripts/run-oxlint.mjs
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --no-web-search
- GitHub CI for 5ee8b3dd5f
2026-06-03 17:40:07 -07:00
Peter Steinberger
fd5dc5bb3a docs: document plugin catalog install helpers 2026-06-03 20:39:16 -04:00
Peter Steinberger
f6aa2c02d1 docs: document plugin runtime load context 2026-06-03 20:36:52 -04:00
Peter Steinberger
7b4d14f786 docs: document plugin runtime helper APIs 2026-06-03 20:34:17 -04:00
Vincent Koc
822ebb4c94 test(e2e): read onboard auth profiles from sqlite 2026-06-04 02:33:56 +02:00
Peter Steinberger
58f7d7e5f8 docs: document plugin scope state helpers 2026-06-03 20:30:38 -04:00
Peter Steinberger
0ad13b714e docs: document plugin manifest install helpers 2026-06-03 20:28:45 -04:00
Peter Steinberger
bb8192ff7c docs: document plugin hook provider helpers 2026-06-03 20:26:18 -04:00
Peter Steinberger
c5d52bf2a7 docs: document plugin runtime utilities 2026-06-03 20:22:56 -04:00
Peter Steinberger
06ad1d0d74 docs: document plugin public artifact helpers 2026-06-03 20:21:16 -04:00
Peter Steinberger
27b1d05a1d docs: document plugin runtime status helpers 2026-06-03 20:19:17 -04:00
Peter Steinberger
02c6630f11 docs: document plugin install helpers 2026-06-03 20:17:55 -04:00
Peter Steinberger
c821ef274b docs: document plugin test helpers 2026-06-03 20:16:51 -04:00
Vincent Koc
6d84fb35c7 test(plugins): read migrated auth profiles from sqlite store 2026-06-04 02:15:52 +02:00
Peter Steinberger
335f045393 docs: document plugin manifest helpers 2026-06-03 20:15:37 -04:00
Peter Steinberger
371777ad14 docs: document plugin runtime loaders 2026-06-03 20:13:51 -04:00
Peter Steinberger
ca7c2714f6 docs: document plugin auth runtime helpers 2026-06-03 20:12:42 -04:00
Peter Steinberger
b1d434b666 docs: document plugin provider helpers 2026-06-03 20:11:25 -04:00
Vincent Koc
a7f442ffd8 test(infra): follow active npm override pins 2026-06-04 02:07:49 +02:00
Peter Steinberger
bbff951880 docs: document plugin index policy helpers 2026-06-03 20:04:38 -04:00
Peter Steinberger
9a4d28695b docs: document plugin host helpers 2026-06-03 20:01:47 -04:00
Vincent Koc
96136e6d71 fix(plugins): align auth profile tests with sqlite store 2026-06-04 02:00:35 +02:00
Peter Steinberger
e993e1c334 docs: document auto-reply final helpers 2026-06-03 19:57:58 -04:00
Vincent Koc
99e627b283 fix(deps): align root override metadata 2026-06-03 16:54:52 -07:00
Vincent Koc
edc9be1b7f test(release): read auth refs from sqlite store 2026-06-03 16:54:52 -07:00
Peter Steinberger
01d69041a2 docs: document auto-reply session runtime helpers 2026-06-03 19:54:16 -04:00
Peter Steinberger
6baa5ca5b1 docs: document auto-reply runtime facades 2026-06-03 19:51:54 -04:00
joshavant
d5d3e9983e fix: harden mobile a2ui bridge trust 2026-06-03 16:50:08 -07:00
Peter Steinberger
0b6fff44f5 docs: document auto-reply policy helpers 2026-06-03 19:48:48 -04:00
Val Alexander
e07dbb27d9 Fix Workboard status persistence
Summary:
- Persist Workboard lifecycle status provenance so stale linked session/task lifecycle updates cannot overwrite newer manual or non-default creation status.
- Add focused Workboard store/controller regressions for lifecycle-vs-manual precedence and creation-status precedence.
- Add mocked Control UI browser E2E proof for create/edit/reopen, running move, lifecycle sync, reload persistence, and read-only operator behavior.

Verification:
- `node scripts/run-vitest.mjs extensions/workboard/src/store.test.ts extensions/workboard/src/gateway.test.ts --reporter=verbose`
- `node scripts/run-vitest.mjs ui/src/ui/controllers/workboard.test.ts ui/src/ui/views/workboard.test.ts --reporter=verbose`
- `node scripts/run-vitest.mjs --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/workboard-status-persistence.e2e.test.ts ui/src/ui/e2e/workboard.e2e.test.ts --reporter=verbose`
- `corepack pnpm tsgo:core:test`
- `corepack pnpm tsgo:extensions:test`
- `node scripts/run-oxlint.mjs extensions/workboard/src/sqlite-store.ts extensions/workboard/src/store.test.ts extensions/workboard/src/store.ts extensions/workboard/src/types.ts ui/src/ui/controllers/workboard.test.ts ui/src/ui/controllers/workboard.ts ui/src/ui/e2e/workboard-status-persistence.e2e.test.ts ui/src/ui/e2e/workboard.e2e.test.ts ui/src/ui/views/workboard.test.ts ui/src/ui/views/workboard.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main` clean
- GitHub PR checks green on head `6d05d6edd5ca6cbb2e625f3e478e973feba5e4cf`

Proof:
- E2E manifest: `/Users/buns/.codex/worktrees/74e7/openclaw/.artifacts/control-ui-e2e/workboard/manifest.json`
- Live Gateway success proof: `/Users/buns/.codex/worktrees/74e7/openclaw/.artifacts/live-workboard/proof/12-live-review-success.png`
- Remaining gap: read-only operator behavior is covered by mocked browser E2E, not live Gateway.
2026-06-03 16:46:14 -07:00
Peter Steinberger
d9d4514c00 docs: document auto-reply directive helpers 2026-06-03 19:31:07 -04:00
Peter Steinberger
05d92d8761 docs: document auto-reply queue exec helpers 2026-06-03 19:29:12 -04:00
Peter Steinberger
90b1ab1c70 docs: document auto-reply block helpers 2026-06-03 19:25:58 -04:00
Peter Steinberger
93917413de docs: document auto-reply dispatch helpers 2026-06-03 19:23:08 -04:00
Peter Steinberger
9a1e896c96 docs: document auto-reply queue helpers 2026-06-03 19:21:12 -04:00
Josh Lehman
208fec6ddc docs: clarify legacy openai-codex auth (#90028) 2026-06-03 16:18:51 -07:00
Peter Steinberger
6d4d313d44 docs: document auto-reply runtime helpers 2026-06-03 19:16:37 -04:00
Peter Steinberger
8129fc0f3a docs: document auto-reply top-level helpers 2026-06-03 19:14:43 -04:00
Peter Steinberger
e16ac04330 refactor(auth): store auth profiles in sqlite (#89102) 2026-06-03 16:14:15 -07:00
Peter Steinberger
116bc2a0f0 docs: surface Windows Hub across docs 2026-06-03 16:09:24 -07:00
6640 changed files with 58840 additions and 12596 deletions

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env node
// Secret scanning alert handler for OpenClaw maintainers.
// Usage: node secret-scanning.mjs <command> [options]
/**
* Secret scanning alert handler for OpenClaw maintainers.
* Usage: node secret-scanning.mjs <command> [options]
*/
import { spawnSync } from "node:child_process";
import crypto from "node:crypto";
@@ -57,6 +59,7 @@ function isBodyLocationType(locationType) {
return locationType === "issue_body" || locationType === "pull_request_body";
}
/** Decides whether redacting an issue/PR body requires notifying the reporter. */
export function decideBodyRedaction(currentBody, redactedBody) {
const bodyChanged = String(currentBody) !== String(redactedBody);
return {
@@ -65,6 +68,7 @@ export function decideBodyRedaction(currentBody, redactedBody) {
};
}
/** Loads redaction-result metadata for issue/PR body secret locations. */
export function loadBodyRedactionResult(locationType, resultFile) {
if (!isBodyLocationType(locationType)) {
return { notify_required: true };

View File

@@ -1,4 +1,7 @@
#!/usr/bin/env node
/**
* Heap snapshot diff utility for OpenClaw test memory leak investigations.
*/
import fs from "node:fs";
import path from "node:path";

View File

@@ -1,4 +1,8 @@
#!/usr/bin/env node
/**
* Release CI summary helper that prints parent and child workflow status for a
* full release run.
*/
import { execFileSync } from "node:child_process";
import process from "node:process";

View File

@@ -1,4 +1,8 @@
#!/usr/bin/env node
/**
* Release preflight helper that verifies required provider API keys can reach
* their model-list endpoints without printing secret values.
*/
import process from "node:process";
const args = new Map();

View File

@@ -92,7 +92,7 @@ jobs:
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 \
fetch --no-tags --prune --no-recurse-submodules --depth=2 origin \
"+${ref}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
@@ -146,12 +146,12 @@ jobs:
if [ "${{ github.event_name }}" = "push" ]; then
BASE="${{ github.event.before }}"
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD
else
BASE="${{ github.event.pull_request.base.sha }}"
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD --merge-head-first-parent
fi
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD
- name: Build CI manifest
id: manifest
env:

View File

@@ -34,7 +34,7 @@ env:
PNPM_CONFIG_CHILD_CONCURRENCY: "1"
PNPM_CONFIG_MODULES_DIR: "/var/tmp/openclaw-pnpm/node_modules"
PNPM_CONFIG_NETWORK_CONCURRENCY: "1"
PNPM_CONFIG_STORE_DIR: "/var/tmp/openclaw-pnpm/store"
PNPM_CONFIG_STORE_DIR: "/var/cache/crabbox/pnpm/store"
PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN: "false"
PNPM_CONFIG_VIRTUAL_STORE_DIR: "/var/tmp/openclaw-pnpm/virtual-store"
@@ -120,16 +120,24 @@ jobs:
append_pnpm_option_arg PNPM_CONFIG_MODULES_DIR modules-dir
append_pnpm_option_arg PNPM_CONFIG_NETWORK_CONCURRENCY network-concurrency
append_pnpm_option_arg PNPM_CONFIG_VIRTUAL_STORE_DIR virtual-store-dir
reset_crabbox_pnpm_root() {
local root="/var/tmp/openclaw-pnpm"
rm -rf -- "$root"
mkdir -p "$root"
if [ -L "$root" ] || [ ! -d "$root" ] || [ ! -O "$root" ]; then
echo "::error::Refusing unsafe pnpm cache root: $root"
require_safe_writable_dir() {
local dir="$1"
if [ -L "$dir" ] || [ ! -d "$dir" ] || [ ! -w "$dir" ]; then
echo "::error::Refusing unsafe pnpm directory: $dir"
exit 1
fi
}
reset_crabbox_pnpm_root
prepare_crabbox_pnpm_dirs() {
local volatile_root="/var/tmp/openclaw-pnpm"
case "${PNPM_CONFIG_MODULES_DIR:?}" in "$volatile_root"/*) ;; *) echo "::error::PNPM_CONFIG_MODULES_DIR must stay under $volatile_root"; exit 1 ;; esac
case "${PNPM_CONFIG_VIRTUAL_STORE_DIR:?}" in "$volatile_root"/*) ;; *) echo "::error::PNPM_CONFIG_VIRTUAL_STORE_DIR must stay under $volatile_root"; exit 1 ;; esac
rm -rf -- "$volatile_root"
mkdir -p "$volatile_root" "$PNPM_CONFIG_STORE_DIR"
require_safe_writable_dir "$volatile_root"
require_safe_writable_dir "$PNPM_CONFIG_STORE_DIR"
mkdir -p "$PNPM_CONFIG_MODULES_DIR" "$PNPM_CONFIG_VIRTUAL_STORE_DIR"
}
prepare_crabbox_pnpm_dirs
if [ -L node_modules ] && [ "$(readlink node_modules)" = "${PNPM_CONFIG_MODULES_DIR:-}" ]; then
rm -f node_modules
fi

View File

@@ -563,7 +563,7 @@ jobs:
needs: validate_selected_ref
if: inputs.include_repo_e2e && inputs.live_suite_filter == ''
continue-on-error: ${{ inputs.advisory }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ inputs.release_test_profile == 'full' && 90 || 60 }}
env:
OPENCLAW_VITEST_MAX_WORKERS: "2"
@@ -595,7 +595,7 @@ jobs:
needs: validate_selected_ref
if: inputs.include_repo_e2e && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'openshell-e2e')
continue-on-error: ${{ inputs.advisory }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false

View File

@@ -44,7 +44,7 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
fetch-depth: 1
fetch-depth: 2
fetch-tags: false
persist-credentials: false
submodules: false
@@ -74,6 +74,7 @@ jobs:
- name: Run opengrep on PR diff
env:
OPENCLAW_OPENGREP_BASE_REF: ${{ github.event.pull_request.base.sha }}...HEAD
OPENCLAW_OPENGREP_MERGE_HEAD_FIRST_PARENT: "1"
# Findings from precise rules block this workflow. Pull requests scan
# changed first-party source paths only so findings stay attributable to
# the PR diff. Test/fixture/QA path exclusions live in `.semgrepignore`

View File

@@ -27,7 +27,9 @@ env:
jobs:
tui-pty:
runs-on: ubuntu-24.04
timeout-minutes: 5
timeout-minutes: 8
env:
OPENCLAW_TUI_PTY_INCLUDE_LOCAL: "1"
steps:
- name: Checkout
uses: actions/checkout@v6
@@ -38,4 +40,4 @@ jobs:
install-bun: "false"
- name: Run TUI PTY tests
run: timeout --kill-after=30s 120s node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts
run: timeout --kill-after=30s 240s node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts

View File

@@ -27,11 +27,23 @@ Docs: https://docs.openclaw.ai
- Channels/outbound: keep channel sends durable when transcript mirroring fails, stop schema-padded poll modifiers from blocking normal sends, preserve WebChat `sessions_send` handoffs, preserve Discord channel-label suppression while hiding internal agent failure traces, match Discord libopus error shapes, and sanitize Discord tool progress scaffolding. (#89626, #89812, #89601) Thanks @Petru2224, @codezz, and @takhoffman.
- Telegram/Feishu: require admin rights for Telegram target writeback, keep Telegram DM exec approval allowlists working with `ask:off`, prevent Telegram preview duplication across streaming modes, isolate verbose status after streamed finals, cancel clean restart stop timers, slow polling restart storms, and wire Feishu setup runtime setters. (#88973, #89035, #89813, #89814) Thanks @pgondhi987, @zhangguiping-xydt, and @takhoffman.
- Feishu: preserve full streaming card content by sending the merged text on each update instead of only the latest delta, so card readers see complete output when intermediate frames are missed. (#90181) Thanks @mushuiyu886.
- Chat/UI/Gateway: preserve visible chat stream text, clear stale stream buffers before terminal commits, reconcile completed sends, scroll pending sends into view, harden Workboard dialog accessibility, stabilize WebChat prompt-cache affinity, overlap chat catalog startup, render chat history incrementally, lazy-load usage dashboard, and report gateway health auth diagnostics. (#89337) Thanks @RomneyDa.
- Agents/Codex/providers/models: release session write locks when prompt-release fence reads fail, retire abandoned Codex app-server startups, keep stream-to-parent ACP spawns registered, close Codex startup clients on timeout, recover bundled provider aliases, avoid custom-provider runtime fanout, preserve provider prompt-cache boundaries, forward Gemini stop sequences, and strip Kimi-incompatible Anthropic cache markers. (#89811) Thanks @takhoffman.
- Memory/build/update: warn after startup watcher pressure checks, externalize optional Baileys image backends, restore and pin Canvas A2UI compatibility assets, keep plugin repair fetch failures nonblocking, restore Skill Workshop view switching, and keep the current chat toggle active after awaited session switches. (#89244) Thanks @RomneyDa.
- Plugins/auth: keep Hermes migration reports pointed at SQLite auth-profile stores and keep plugin auth-profile reuse tests on the current store path.
- Plugins/CLI: avoid importing the runtime plugin loader only to clear in-process caches after short-lived plugin install, enable, disable, update, and uninstall commands refresh registry metadata.
- Security/config/tooling: reject corrupt shell snapshots, suspicious gateway startup configs, malformed release/test/tooling/Docker/perf numeric limits, oversized audit responses, unsafe exec precheck env, and invalid pending-agent SQLite scaffold denials. (#89701, #89705, #89480, #81488) Thanks @RomneyDa and @mmaps.
- Release/CI/E2E: restore package changelog extraction after the post-2026.6.1 version bump, keep hydrated pnpm modules under `node_modules` for ARM/Linux package lifecycle scripts, keep OpenAI live-cache prerequisites advisory while Anthropic prerequisites stay blocking, retry Windows Parallels background log appends on transient file-lock errors, bound candidate GitHub and cross-OS Discord fetches, harden ARM smoke/browser checks, show Docker build heartbeats, reset Crabbox pnpm hydrate state, and isolate Testbox/Docker/release journey artifacts.
- Release/CI/E2E: keep Crabbox hydrate pnpm stores on the persistent cache volume while still resetting volatile modules, reducing cold installs and runner memory churn.
- Release/CI/E2E: fail secret-provider proof startup immediately when the gateway exits by signal instead of waiting for the readiness timeout.
- Release/CI/E2E: report plugin gateway gauntlet command-log write failures as failed rows instead of crashing the harness from child-process callbacks.
- Release/CI/E2E: abort stalled Kitchen Sink RPC readiness probes as soon as the gateway exits so proof failures return promptly.
- Release/CI/E2E: keep Parallels JSON-mode progress on stderr so macOS, Linux, Windows, and aggregate update smoke summaries stay parseable on stdout.
- Release/CI/E2E: fail Crabbox sparse-sync runs clearly when their temporary full checkout disappears while the child process is running, instead of pretending the child's deleted cwd can be repaired.
- Release/CI/E2E: fail PTY-backed E2E commands when transcript logs cannot be written instead of letting missing proof capture crash around a live child process.
- Release/CI/E2E: fail mock OpenAI request-log write errors with clear HTTP responses instead of leaving provider proof clients waiting on a broken socket.
- Release/CI/E2E: fail Parallels host-command log write errors through the command result path instead of leaving streaming smoke phases unresolved.
## 2026.6.1

View File

@@ -9,18 +9,18 @@
# Build stages use full bookworm; the runtime image is always bookworm-slim.
ARG OPENCLAW_EXTENSIONS=""
ARG OPENCLAW_BUNDLED_PLUGIN_DIR=extensions
ARG OPENCLAW_NODE_BOOKWORM_IMAGE="node:24-bookworm@sha256:8530f76a96d88820d288761f022e318970dda93d01536919fbc16076b7983e63"
ARG OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE="node:24-bookworm-slim@sha256:242549cd46785b480c832479a730f4f2a20865d61ea2e404fdb2a5c3d3b73ecf"
ARG OPENCLAW_NODE_BOOKWORM_IMAGE="docker.io/library/node:24-bookworm@sha256:8530f76a96d88820d288761f022e318970dda93d01536919fbc16076b7983e63"
ARG OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE="docker.io/library/node:24-bookworm-slim@sha256:242549cd46785b480c832479a730f4f2a20865d61ea2e404fdb2a5c3d3b73ecf"
ARG OPENCLAW_NODE_BOOKWORM_SLIM_DIGEST="sha256:242549cd46785b480c832479a730f4f2a20865d61ea2e404fdb2a5c3d3b73ecf"
# Keep in sync with .github/actions/setup-node-env/action.yml bun-version.
# To update: docker buildx imagetools inspect oven/bun:<version> and use the manifest-list digest.
ARG OPENCLAW_BUN_IMAGE="oven/bun:1.3.13@sha256:87416c977a612a204eb54ab9f3927023c2a3c971f4f345a01da08ea6262ae30e"
# To update: docker buildx imagetools inspect docker.io/oven/bun:<version> and use the manifest-list digest.
ARG OPENCLAW_BUN_IMAGE="docker.io/oven/bun:1.3.13@sha256:87416c977a612a204eb54ab9f3927023c2a3c971f4f345a01da08ea6262ae30e"
# Base images are pinned to SHA256 digests for reproducible builds.
# Dependabot refreshes these blessed digests; release builds consume the
# reviewed base snapshot instead of mutating distro state on every build.
# To update, run: docker buildx imagetools inspect node:24-bookworm and
# node:24-bookworm-slim (or podman) and replace the digests below with the
# To update, run: docker buildx imagetools inspect docker.io/library/node:24-bookworm and
# docker.io/library/node:24-bookworm-slim (or podman) and replace the digests below with the
# current multi-arch manifest list entries.
FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS workspace-deps

View File

@@ -30,7 +30,8 @@ Supported channels include: WhatsApp, Telegram, Slack, Discord, Google Chat, Sig
New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started)
Preferred setup: run `openclaw onboard` in your terminal.
OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on **macOS, Linux, and Windows**.
Windows desktop users can start with the native [Windows Hub](https://docs.openclaw.ai/platforms/windows) companion app for setup, tray status, chat, node mode, and local MCP mode.
Works with npm, pnpm, or bun.
## Sponsors
@@ -164,7 +165,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
- **[Voice Wake](https://docs.openclaw.ai/nodes/voicewake) + [Talk Mode](https://docs.openclaw.ai/nodes/talk)** — wake words on macOS/iOS and continuous voice on Android (ElevenLabs + system TTS fallback).
- **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- **[First-class tools](https://docs.openclaw.ai/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions.
- **[Companion apps](https://docs.openclaw.ai/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.openclaw.ai/nodes).
- **[Companion apps](https://docs.openclaw.ai/platforms)** — Windows Hub, macOS menu bar app, and iOS/Android [nodes](https://docs.openclaw.ai/nodes).
- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — onboarding-driven setup with bundled/managed/workspace skills.
## Security model (important)
@@ -185,7 +186,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
- New here: [Getting started](https://docs.openclaw.ai/start/getting-started), [Onboarding](https://docs.openclaw.ai/start/wizard), [Updating](https://docs.openclaw.ai/install/updating)
- Channel setup: [Channels index](https://docs.openclaw.ai/channels), [WhatsApp](https://docs.openclaw.ai/channels/whatsapp), [Telegram](https://docs.openclaw.ai/channels/telegram), [Discord](https://docs.openclaw.ai/channels/discord), [Slack](https://docs.openclaw.ai/channels/slack)
- Apps + nodes: [macOS](https://docs.openclaw.ai/platforms/macos), [iOS](https://docs.openclaw.ai/platforms/ios), [Android](https://docs.openclaw.ai/platforms/android), [Nodes](https://docs.openclaw.ai/nodes)
- Apps + nodes: [Windows Hub](https://docs.openclaw.ai/platforms/windows), [macOS](https://docs.openclaw.ai/platforms/macos), [iOS](https://docs.openclaw.ai/platforms/ios), [Android](https://docs.openclaw.ai/platforms/android), [Nodes](https://docs.openclaw.ai/nodes)
- Config + security: [Configuration](https://docs.openclaw.ai/gateway/configuration), [Security](https://docs.openclaw.ai/gateway/security), [Exposure runbook](https://docs.openclaw.ai/gateway/security/exposure-runbook), [Sandboxing](https://docs.openclaw.ai/gateway/sandboxing)
- Remote + web: [Gateway](https://docs.openclaw.ai/gateway), [Remote access](https://docs.openclaw.ai/gateway/remote), [Tailscale](https://docs.openclaw.ai/gateway/tailscale), [Web surfaces](https://docs.openclaw.ai/web)
- Tools + automation: [Tools](https://docs.openclaw.ai/tools), [Skills](https://docs.openclaw.ai/tools/skills), [Cron jobs](https://docs.openclaw.ai/automation/cron-jobs), [Webhooks](https://docs.openclaw.ai/automation/webhook), [Gmail Pub/Sub](https://docs.openclaw.ai/automation/gmail-pubsub)

View File

@@ -253,9 +253,9 @@ Pre-req checklist:
4) Open the app **Screen** tab and keep it active during the run (canvas/A2UI commands require the canvas WebView attached there).
5) Grant runtime permissions for capabilities you expect to pass (camera/mic/location/notification listener/location, etc.).
6) No interactive system dialogs should be pending before test start.
7) Canvas host is enabled and reachable from the device (do not run gateway with `OPENCLAW_SKIP_CANVAS_HOST=1`; startup logs should include `canvas host mounted at .../__openclaw__/`).
7) Canvas host is enabled and reachable from the device for remote Canvas checks (do not run gateway with `OPENCLAW_SKIP_CANVAS_HOST=1`; startup logs should include `canvas host mounted at .../__openclaw__/`).
8) Local operator test client pairing is approved. If first run fails with `pairing required`, preview the latest pending request, approve the printed request ID, then rerun:
9) For A2UI checks, keep the app on **Screen** tab; the node now auto-refreshes canvas capability once on first A2UI reachability failure (TTL-safe retry).
9) For A2UI checks, keep the app on **Screen** tab; the node uses its bundled app-owned A2UI page for message application.
```bash
openclaw devices list
@@ -287,8 +287,8 @@ Common failure quick-fixes:
- `pairing required` before tests start:
- list pending requests (`openclaw devices list`), then approve with the exact ID (`openclaw devices approve <requestId>`) and rerun.
- `A2UI host not reachable` / `A2UI_HOST_NOT_CONFIGURED`:
- ensure the Canvas plugin host is running and reachable, keep the app on the **Screen** tab. The app refreshes the Canvas plugin surface URL once before failing; if it still fails, reconnect app and rerun.
- `A2UI host not reachable` / `A2UI_HOST_UNAVAILABLE`:
- keep the app foregrounded on the **Screen** tab and rerun. A2UI commands use the bundled app-owned A2UI page; the Gateway Canvas host is still needed for remote Canvas checks, but not for A2UI message application.
- `NODE_BACKGROUND_UNAVAILABLE: canvas unavailable`:
- app is not effectively ready for canvas commands; keep app foregrounded and **Screen** tab active.

View File

@@ -189,8 +189,6 @@ class NodeRuntime(
A2UIHandler(
canvas = canvas,
json = json,
getNodeCanvasHostUrl = { nodeSession.currentCanvasHostUrl() },
getOperatorCanvasHostUrl = { operatorSession.currentCanvasHostUrl() },
)
private val connectionManager: ConnectionManager =
@@ -254,7 +252,6 @@ class NodeRuntime(
_canvasRehydrateErrorText.value = null
},
onCanvasA2uiReset = { _canvasA2uiHydrated.value = false },
refreshCanvasHostUrl = { nodeSession.refreshCanvasHostUrl() },
motionActivityAvailable = { motionHandler.isActivityAvailable() },
motionPedometerAvailable = { motionHandler.isPedometerAvailable() },
)

View File

@@ -12,47 +12,30 @@ import kotlinx.serialization.json.JsonPrimitive
class A2UIHandler(
private val canvas: CanvasController,
private val json: Json,
private val getNodeCanvasHostUrl: () -> String?,
private val getOperatorCanvasHostUrl: () -> String?,
) {
fun isTrustedCanvasActionUrl(rawUrl: String?): Boolean =
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = rawUrl,
trustedA2uiUrls = listOfNotNull(resolveA2uiHostUrl()),
)
fun isTrustedCanvasActionUrl(rawUrl: String?): Boolean = CanvasActionTrust.isTrustedCanvasActionUrl(rawUrl)
fun resolveA2uiHostUrl(): String? {
val nodeRaw = getNodeCanvasHostUrl()?.trim().orEmpty()
val operatorRaw = getOperatorCanvasHostUrl()?.trim().orEmpty()
// Prefer node-advertised canvas host; operator URL is a fallback for older hello payloads.
val raw = if (nodeRaw.isNotBlank()) nodeRaw else operatorRaw
if (raw.isBlank()) return null
val base = raw.trimEnd('/')
return "$base/__openclaw__/a2ui/?platform=android"
}
suspend fun ensureA2uiReady(a2uiUrl: String): Boolean {
try {
val already = canvas.eval(a2uiReadyCheckJS)
if (already == "true") return true
} catch (_: Throwable) {
// ignore
suspend fun ensureA2uiReady(): Boolean {
if (canvas.currentUrl()?.trim() == CanvasActionTrust.localA2uiAssetUrl && isA2uiReady()) {
return true
}
canvas.navigate(a2uiUrl)
// A2UI host bootstraps asynchronously after navigation; poll briefly before failing the command.
canvas.showLocalA2ui()
// The bundled A2UI host bootstraps asynchronously after navigation; poll briefly before failing the command.
repeat(50) {
try {
val ready = canvas.eval(a2uiReadyCheckJS)
if (ready == "true") return true
} catch (_: Throwable) {
// ignore
}
if (isA2uiReady()) return true
delay(120)
}
return false
}
private suspend fun isA2uiReady(): Boolean =
try {
canvas.eval(a2uiReadyCheckJS) == "true"
} catch (_: Throwable) {
false
}
fun decodeA2uiMessages(
command: String,
paramsJson: String?,

View File

@@ -1,7 +1,5 @@
package ai.openclaw.app.node
import java.net.URI
/**
* Trust helper for WebView-originated canvas/A2UI actions.
*/
@@ -9,62 +7,15 @@ object CanvasActionTrust {
/** Local canvas scaffold is the only trusted file URL. */
const val scaffoldAssetUrl: String = "file:///android_asset/CanvasScaffold/scaffold.html"
/** Accepts local scaffold or exact remote A2UI URLs advertised by the gateway. */
fun isTrustedCanvasActionUrl(
rawUrl: String?,
trustedA2uiUrls: List<String>,
): Boolean {
/** Local bundled A2UI is the only action-capable A2UI host. */
const val localA2uiAssetUrl: String = "file:///android_asset/CanvasA2UI/index.html"
/** Accepts only app-owned bundled pages. Remote WebView content is render-only. */
fun isTrustedCanvasActionUrl(rawUrl: String?): Boolean {
val candidate = rawUrl?.trim().orEmpty()
if (candidate.isEmpty()) return false
if (candidate == scaffoldAssetUrl) return true
val candidateUri = parseUri(candidate) ?: return false
if (candidateUri.scheme.equals("file", ignoreCase = true)) {
return false
}
val normalizedCandidate = normalizeTrustedRemoteA2uiUri(candidateUri) ?: return false
return trustedA2uiUrls.any { trusted ->
matchesTrustedRemoteA2uiUrlExact(normalizedCandidate, trusted)
}
if (candidate == localA2uiAssetUrl) return true
return false
}
private fun matchesTrustedRemoteA2uiUrlExact(
candidateUri: URI,
trustedUrl: String,
): Boolean {
// Gateway-advertised URLs are capabilities. Treat malformed entries as
// absent instead of broadening trust to same-origin or prefix matches.
val trustedUri = parseUri(trustedUrl) ?: return false
val normalizedTrusted = normalizeTrustedRemoteA2uiUri(trustedUri) ?: return false
return candidateUri == normalizedTrusted
}
/** Normalizes only the URL parts allowed to vary across trusted remote A2UI URLs. */
private fun normalizeTrustedRemoteA2uiUri(uri: URI): URI? {
// Keep Android trust normalization aligned with iOS ScreenController:
// exact remote URL match, scheme/host normalized, fragment ignored.
val scheme = uri.scheme?.lowercase() ?: return null
if (scheme != "http" && scheme != "https") return null
val host =
uri.host
?.trim()
?.takeIf { it.isNotEmpty() }
?.lowercase() ?: return null
return try {
URI(scheme, uri.userInfo, host, uri.port, uri.rawPath, uri.rawQuery, null)
} catch (_: Throwable) {
null
}
}
/** Parses untrusted WebView/gateway URL text without throwing into UI event handlers. */
private fun parseUri(raw: String): URI? =
try {
URI(raw)
} catch (_: Throwable) {
null
}
}

View File

@@ -48,7 +48,8 @@ class CanvasController {
private val _currentUrl = MutableStateFlow<String?>(null)
val currentUrl: StateFlow<String?> = _currentUrl.asStateFlow()
private val scaffoldAssetUrl = "file:///android_asset/CanvasScaffold/scaffold.html"
private val scaffoldAssetUrl = CanvasActionTrust.scaffoldAssetUrl
private val localA2uiAssetUrl = CanvasActionTrust.localA2uiAssetUrl
private fun clampJpegQuality(quality: Double?): Int {
val q = (quality ?: 0.82).coerceIn(0.1, 1.0)
@@ -87,6 +88,13 @@ class CanvasController {
reload()
}
/** Shows the app-owned A2UI renderer that is allowed to dispatch native actions. */
fun showLocalA2ui() {
this.url = localA2uiAssetUrl
_currentUrl.value = localA2uiAssetUrl
reload()
}
fun currentUrl(): String? = url
fun isDefaultCanvas(): Boolean = url == null

View File

@@ -89,7 +89,6 @@ class InvokeDispatcher(
private val debugBuild: () -> Boolean,
private val onCanvasA2uiPush: () -> Unit,
private val onCanvasA2uiReset: () -> Unit,
private val refreshCanvasHostUrl: suspend () -> String?,
private val motionActivityAvailable: () -> Boolean,
private val motionPedometerAvailable: () -> Boolean,
) {
@@ -242,24 +241,11 @@ class InvokeDispatcher(
}
private suspend fun withReadyA2ui(block: suspend () -> GatewaySession.InvokeResult): GatewaySession.InvokeResult {
var a2uiUrl =
a2uiHandler.resolveA2uiHostUrl()
?: refreshCanvasHostUrl().let { a2uiHandler.resolveA2uiHostUrl() }
?: return GatewaySession.InvokeResult.error(
code = "A2UI_HOST_NOT_CONFIGURED",
message = "A2UI_HOST_NOT_CONFIGURED: gateway did not advertise canvas host",
)
val readyOnFirstCheck = a2uiHandler.ensureA2uiReady(a2uiUrl)
if (!readyOnFirstCheck) {
// Gateway canvas host metadata can lag reconnects; refresh once before failing the command.
refreshCanvasHostUrl()
a2uiUrl = a2uiHandler.resolveA2uiHostUrl() ?: a2uiUrl
if (!a2uiHandler.ensureA2uiReady(a2uiUrl)) {
return GatewaySession.InvokeResult.error(
code = "A2UI_HOST_UNAVAILABLE",
message = "A2UI_HOST_UNAVAILABLE: A2UI host not reachable",
)
}
if (!a2uiHandler.ensureA2uiReady()) {
return GatewaySession.InvokeResult.error(
code = "A2UI_HOST_UNAVAILABLE",
message = "A2UI_HOST_UNAVAILABLE: bundled A2UI host not reachable",
)
}
return block()
}

View File

@@ -152,9 +152,8 @@ fun CanvasScreen(
}
}
// The listener accepts any WebView origin at registration time because
// gateway A2UI URLs are dynamic; CanvasActionTrust validates the live URL
// before forwarding each message.
// The listener accepts any WebView origin at registration time; native
// dispatch still requires the live URL to be an app-owned bundled page.
val bridge =
CanvasA2UIActionBridge(
isTrustedPage = { viewModel.isTrustedCanvasActionUrl(currentPageUrlRef.get()) },

View File

@@ -7,66 +7,57 @@ import org.junit.Test
class CanvasActionTrustTest {
@Test
fun acceptsBundledScaffoldAsset() {
assertTrue(CanvasActionTrust.isTrustedCanvasActionUrl(CanvasActionTrust.scaffoldAssetUrl, emptyList()))
assertTrue(CanvasActionTrust.isTrustedCanvasActionUrl(CanvasActionTrust.scaffoldAssetUrl))
}
@Test
fun acceptsTrustedA2uiPageOnAdvertisedCanvasHost() {
assertTrue(
fun acceptsBundledA2uiAsset() {
assertTrue(CanvasActionTrust.isTrustedCanvasActionUrl(CanvasActionTrust.localA2uiAssetUrl))
}
@Test
fun rejectsRemoteHttpA2uiPageEvenWhenGatewayAdvertised() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "http://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android",
),
)
}
@Test
fun rejectsRemoteHttpsA2uiPageEvenWhenGatewayAdvertised() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
),
)
}
@Test
fun rejectsDifferentOriginEvenIfPathMatches() {
fun rejectsRemoteCanvasPage() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://evil.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
rawUrl = "https://canvas.example.com:9443/__openclaw__/canvas/",
),
)
}
@Test
fun rejectsUntrustedCanvasPagePathOnTrustedOrigin() {
fun rejectsDescendantPathUnderBundledA2uiRoot() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://canvas.example.com:9443/untrusted/index.html",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
rawUrl = "file:///android_asset/CanvasA2UI/child/index.html",
),
)
}
@Test
fun acceptsFragmentOnlyDifferenceForTrustedA2uiPage() {
assertTrue(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android#step2",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
),
)
}
@Test
fun rejectsQueryMismatchOnTrustedOriginAndPath() {
fun rejectsQueryOrFragmentChangesToBundledA2uiAsset() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=ios",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
),
)
}
@Test
fun rejectsDescendantPathUnderTrustedA2uiRoot() {
assertFalse(
CanvasActionTrust.isTrustedCanvasActionUrl(
rawUrl = "https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/child/index.html?platform=android",
trustedA2uiUrls = listOf("https://canvas.example.com:9443/__openclaw__/cap/token/__openclaw__/a2ui/?platform=android"),
rawUrl = "${CanvasActionTrust.localA2uiAssetUrl}?platform=android",
),
)
assertFalse(CanvasActionTrust.isTrustedCanvasActionUrl("${CanvasActionTrust.localA2uiAssetUrl}#step2"))
}
}

View File

@@ -299,8 +299,6 @@ class InvokeDispatcherTest {
A2UIHandler(
canvas = canvas,
json = Json { ignoreUnknownKeys = true },
getNodeCanvasHostUrl = { null },
getOperatorCanvasHostUrl = { null },
),
debugHandler = DebugHandler(appContext, DeviceIdentityStore(appContext)),
callLogHandler = CallLogHandler.forTesting(appContext, InvokeDispatcherFakeCallLogDataSource()),
@@ -317,7 +315,6 @@ class InvokeDispatcherTest {
debugBuild = { debugBuild },
onCanvasA2uiPush = {},
onCanvasA2uiReset = {},
refreshCanvasHostUrl = { null },
motionActivityAvailable = { motionActivityAvailable },
motionPedometerAvailable = { motionPedometerAvailable },
)

View File

@@ -1,4 +1,8 @@
#!/usr/bin/env bun
/**
* Android release helper that bumps version fields, builds release AAB variants,
* verifies signatures, and prints SHA-256 checksums.
*/
import { $ } from "bun";
import { dirname, join } from "node:path";

View File

@@ -702,6 +702,9 @@ final class GatewayConnectionController {
appModel.gatewayStatusText = "Connecting…"
Task { [weak self, weak appModel] in
guard let self, let appModel else { return }
if forceReconnect {
await appModel.resetGatewaySessionsForForcedReconnect()
}
let nodeOptions = await self.makeConnectOptions(stableID: gatewayStableID)
let cfg = GatewayConnectConfig(
url: url,
@@ -990,7 +993,10 @@ extension GatewayConnectionController {
}
private func currentCaps() -> [String] {
var caps = [OpenClawCapability.canvas.rawValue, OpenClawCapability.screen.rawValue]
var caps = [
OpenClawCapability.canvas.rawValue,
OpenClawCapability.screen.rawValue,
]
// Default-on: if the key doesn't exist yet, treat it as enabled.
let cameraEnabled =

View File

@@ -1,106 +1,35 @@
import Foundation
import Network
import OpenClawKit
enum A2UIReadyState {
case ready(String)
case hostNotConfigured
case ready
case hostUnavailable
}
extension NodeAppModel {
func resolveCanvasHostURL() async -> String? {
guard let raw = await self.gatewaySession.currentCanvasHostUrl() else { return nil }
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, let base = URL(string: trimmed) else { return nil }
if let host = base.host, LoopbackHost.isLoopback(host) {
return nil
}
return base.appendingPathComponent("__openclaw__/canvas/").absoluteString
}
func _test_resolveA2UIHostURL() async -> String? {
await self.resolveA2UIHostURL()
}
func resolveA2UIHostURL() async -> String? {
guard let raw = await self.gatewaySession.currentCanvasHostUrl() else { return nil }
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, let base = URL(string: trimmed) else { return nil }
if let host = base.host, LoopbackHost.isLoopback(host) {
return nil
}
return base.appendingPathComponent("__openclaw__/a2ui/").absoluteString + "?platform=ios"
}
/// Normalize a URL string for trust comparison: lowercase scheme/host and strip fragment.
/// This matches the normalization applied by ScreenController.isTrustedCanvasUIURL so that
/// SPA hash-routing fragments and scheme/host casing do not silently prevent trust being set.
static func normalizeURLForTrustComparison(_ raw: String) -> String {
guard let url = URL(string: raw),
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
else { return raw }
components.fragment = nil
components.scheme = components.scheme?.lowercased()
components.host = components.host?.lowercased()
return components.url?.absoluteString ?? raw
}
func showA2UIOnConnectIfNeeded() async {
await MainActor.run {
// Keep the bundled home canvas as the default connected view.
// Agents can still explicitly present a remote or local canvas later.
self.lastAutoA2uiURL = nil
self.screen.showDefaultCanvas()
}
}
func ensureA2UIReadyWithCapabilityRefresh(timeoutMs: Int = 5000) async -> A2UIReadyState {
guard let initialUrl = await self.resolveA2UIHostURLWithCapabilityRefresh() else {
return .hostNotConfigured
if self.screen.isShowingLocalA2UI(),
await self.screen.waitForA2UIReady(timeoutMs: timeoutMs)
{
return .ready
}
self.screen.navigate(to: initialUrl, trustA2UIActions: true)
self.screen.showLocalA2UI()
if await self.screen.waitForA2UIReady(timeoutMs: timeoutMs) {
return .ready(initialUrl)
}
guard let refreshedUrl = await self.resolveA2UIHostURLWithCapabilityRefresh(forceRefresh: true) else {
return .hostUnavailable
}
self.screen.navigate(to: refreshedUrl, trustA2UIActions: true)
if await self.screen.waitForA2UIReady(timeoutMs: timeoutMs) {
return .ready(refreshedUrl)
return .ready
}
return .hostUnavailable
}
func showLocalCanvasOnDisconnect() {
self.lastAutoA2uiURL = nil
self.screen.showDefaultCanvas()
}
private func resolveA2UIHostURLWithCapabilityRefresh(forceRefresh: Bool = false) async -> String? {
if !forceRefresh, let current = await self.resolveA2UIHostURL() {
return current
}
_ = await self.gatewaySession.refreshCanvasHostUrl()
return await self.resolveA2UIHostURL()
}
private func resolveCanvasHostURLWithCapabilityRefresh(forceRefresh: Bool = false) async -> String? {
if !forceRefresh, let current = await self.resolveCanvasHostURL() {
return current
}
_ = await self.gatewaySession.refreshCanvasHostUrl()
return await self.resolveCanvasHostURL()
}
private static func probeTCP(url: URL, timeoutSeconds: Double) async -> Bool {
guard let host = url.host, !host.isEmpty else { return false }
let portInt = url.port ?? ((url.scheme ?? "").lowercased() == "wss" ? 443 : 80)
return await TCPProbe.probe(
host: host,
port: portInt,
timeoutSeconds: timeoutSeconds,
queueLabel: "a2ui.preflight")
}
}

View File

@@ -173,7 +173,6 @@ final class NodeAppModel {
private let remindersService: any RemindersServicing
private let motionService: any MotionServicing
private let watchMessagingService: any WatchMessagingServicing
var lastAutoA2uiURL: String?
private var pttVoiceWakeSuspended = false
private var talkVoiceWakeSuspended = false
private var backgroundVoiceWakeSuspended = false
@@ -1035,24 +1034,18 @@ final class NodeAppModel {
OpenClawCanvasPresentParams()
let url = params.url?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if url.isEmpty {
self.screen.showDefaultCanvas()
self.screen.presentDefaultCanvas()
} else {
let trustedA2UIURL = await self.resolveA2UIHostURL()
self.screen.navigate(
to: url,
trustA2UIActions: trustedA2UIURL == Self.normalizeURLForTrustComparison(url))
self.screen.present(urlString: url)
}
return BridgeInvokeResponse(id: req.id, ok: true)
case OpenClawCanvasCommand.hide.rawValue:
self.screen.showDefaultCanvas()
self.screen.hideCanvas()
return BridgeInvokeResponse(id: req.id, ok: true)
case OpenClawCanvasCommand.navigate.rawValue:
let params = try Self.decodeParams(OpenClawCanvasNavigateParams.self, from: req.paramsJSON)
let trimmedURL = params.url.trimmingCharacters(in: .whitespacesAndNewlines)
let trustedA2UIURL = await self.resolveA2UIHostURL()
self.screen.navigate(
to: trimmedURL,
trustA2UIActions: trustedA2UIURL == Self.normalizeURLForTrustComparison(trimmedURL))
self.screen.present(urlString: trimmedURL)
return BridgeInvokeResponse(id: req.id, ok: true)
case OpenClawCanvasCommand.evalJS.rawValue:
let params = try Self.decodeParams(OpenClawCanvasEvalParams.self, from: req.paramsJSON)
@@ -1095,20 +1088,13 @@ final class NodeAppModel {
switch await self.ensureA2UIReadyWithCapabilityRefresh(timeoutMs: 5000) {
case .ready:
break
case .hostNotConfigured:
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: OpenClawNodeError(
code: .unavailable,
message: "A2UI_HOST_NOT_CONFIGURED: gateway did not advertise canvas host"))
case .hostUnavailable:
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: OpenClawNodeError(
code: .unavailable,
message: "A2UI_HOST_UNAVAILABLE: A2UI host not reachable"))
message: "A2UI_HOST_UNAVAILABLE: bundled A2UI host not reachable"))
}
let json = try await self.screen.eval(javaScript: """
(() => {
@@ -1138,20 +1124,13 @@ final class NodeAppModel {
switch await self.ensureA2UIReadyWithCapabilityRefresh(timeoutMs: 5000) {
case .ready:
break
case .hostNotConfigured:
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: OpenClawNodeError(
code: .unavailable,
message: "A2UI_HOST_NOT_CONFIGURED: gateway did not advertise canvas host"))
case .hostUnavailable:
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: OpenClawNodeError(
code: .unavailable,
message: "A2UI_HOST_UNAVAILABLE: A2UI host not reachable"))
message: "A2UI_HOST_UNAVAILABLE: bundled A2UI host not reachable"))
}
let messagesJSON = try OpenClawCanvasA2UIJSONL.encodeMessagesJSONArray(messages)
@@ -1960,6 +1939,15 @@ extension NodeAppModel {
forceReconnect: forceReconnect)
}
func resetGatewaySessionsForForcedReconnect() async {
self.nodeGatewayTask?.cancel()
self.nodeGatewayTask = nil
self.operatorGatewayTask?.cancel()
self.operatorGatewayTask = nil
await self.operatorGateway.disconnect()
await self.nodeGateway.disconnect()
}
func disconnectGateway() {
self.gatewayAutoReconnectEnabled = false
self.gatewayPairingPaused = false
@@ -4578,6 +4566,10 @@ extension NodeAppModel {
self.clearingBootstrapToken(in: config)
}
func _test_hasGatewayLoopTasks() -> (node: Bool, operator: Bool) {
(self.nodeGatewayTask != nil, self.operatorGatewayTask != nil)
}
func _test_handleSuccessfulBootstrapGatewayOnboarding() async {
await self.handleSuccessfulBootstrapGatewayOnboarding(
url: URL(string: "wss://gateway.example")!,

View File

@@ -200,6 +200,36 @@ struct RootTabs: View {
RootCameraFlashOverlay(nonce: self.appModel.cameraFlashNonce)
}
}
.overlay {
if self.appModel.screen.isCanvasPresented {
self.canvasPresentationOverlay
.transition(.opacity)
.zIndex(20)
}
}
}
private var canvasPresentationOverlay: some View {
ZStack(alignment: .topTrailing) {
Color.black.ignoresSafeArea()
ScreenWebView(controller: self.appModel.screen)
.ignoresSafeArea()
Button {
self.appModel.screen.hideCanvas()
} label: {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 30, weight: .semibold))
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.white)
.shadow(color: .black.opacity(0.32), radius: 8, y: 2)
.frame(width: 48, height: 48)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.accessibilityLabel("Close canvas")
.safeAreaPadding(.top, 8)
.padding(.trailing, 12)
}
}
private func rootLifecycle(_ content: some View) -> some View {

View File

@@ -7,10 +7,10 @@ import WebKit
@Observable
final class ScreenController {
private weak var activeWebView: WKWebView?
private var trustedRemoteA2UIURL: URL?
var urlString: String = ""
var errorText: String?
var isCanvasPresented: Bool = false
/// Callback invoked when an openclaw:// deep link is tapped in the canvas
var onDeepLink: ((URL) -> Void)?
@@ -27,11 +27,10 @@ final class ScreenController {
self.reload()
}
func navigate(to urlString: String, trustA2UIActions: Bool = false) {
func navigate(to urlString: String, trustA2UIActions _: Bool = false) {
let trimmed = urlString.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty {
self.urlString = ""
self.trustedRemoteA2UIURL = nil
self.reload()
return
}
@@ -45,7 +44,6 @@ final class ScreenController {
return
}
self.urlString = (trimmed == "/" ? "" : trimmed)
self.trustedRemoteA2UIURL = trustA2UIActions ? Self.normalizeTrustedRemoteA2UIURL(from: trimmed) : nil
self.reload()
}
@@ -75,10 +73,42 @@ final class ScreenController {
func showDefaultCanvas() {
self.urlString = ""
self.trustedRemoteA2UIURL = nil
self.reload()
}
func presentDefaultCanvas() {
self.isCanvasPresented = true
self.showDefaultCanvas()
}
func present(urlString: String) {
self.isCanvasPresented = true
self.navigate(to: urlString)
}
func hideCanvas() {
self.isCanvasPresented = false
self.showDefaultCanvas()
}
func showLocalA2UI() {
self.isCanvasPresented = true
guard let url = Self.localA2UIURL else {
self.showDefaultCanvas()
return
}
self.urlString = url.absoluteString
self.reload()
}
func isShowingLocalA2UI() -> Bool {
guard let url = URL(string: self.urlString),
url.isFileURL,
let expected = Self.localA2UIURL
else { return false }
return url.standardizedFileURL == expected.standardizedFileURL
}
func setDebugStatusEnabled(_ enabled: Bool) {
self.debugStatusEnabled = enabled
self.applyDebugStatusIfNeeded()
@@ -239,6 +269,11 @@ final class ScreenController {
ext: "html",
subdirectory: "CanvasScaffold")
private static let localA2UIURL: URL? = ScreenController.bundledResourceURL(
name: "index",
ext: "html",
subdirectory: "CanvasA2UI")
func isTrustedCanvasUIURL(_ url: URL) -> Bool {
if url.isFileURL {
let std = url.standardizedFileURL
@@ -247,10 +282,14 @@ final class ScreenController {
{
return true
}
if let expected = Self.localA2UIURL,
std == expected.standardizedFileURL
{
return true
}
return false
}
guard let trusted = self.trustedRemoteA2UIURL else { return false }
return Self.normalizeTrustedRemoteA2UIURL(from: url) == trusted
return false
}
nonisolated static func parseA2UIActionBody(_ body: Any) -> [String: Any]? {
@@ -280,26 +319,6 @@ final class ScreenController {
scrollView.isScrollEnabled = allowScroll
scrollView.bounces = allowScroll
}
private static func normalizeTrustedRemoteA2UIURL(from raw: String) -> URL? {
guard let url = URL(string: raw) else { return nil }
return self.normalizeTrustedRemoteA2UIURL(from: url)
}
private static func normalizeTrustedRemoteA2UIURL(from url: URL) -> URL? {
guard !url.isFileURL else { return nil }
guard let scheme = url.scheme?.lowercased(), scheme == "http" || scheme == "https" else {
return nil
}
guard let host = url.host?.trimmingCharacters(in: .whitespacesAndNewlines), !host.isEmpty else {
return nil
}
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.scheme = scheme
components?.host = host.lowercased()
components?.fragment = nil
return components?.url
}
}
extension Double {

View File

@@ -235,6 +235,20 @@ import UIKit
#expect(appModel.connectedGatewayID == second.stableID)
}
@Test @MainActor func forcedReconnectResetClearsActiveGatewayLoopTasks() async {
let appModel = NodeAppModel()
defer { appModel.disconnectGateway() }
appModel.applyGatewayConnectConfig(Self.makeGatewayConnectConfig())
#expect(appModel._test_hasGatewayLoopTasks().node)
#expect(appModel._test_hasGatewayLoopTasks().operator)
await appModel.resetGatewaySessionsForForcedReconnect()
#expect(!appModel._test_hasGatewayLoopTasks().node)
#expect(!appModel._test_hasGatewayLoopTasks().operator)
}
@Test @MainActor func loadLastConnectionReadsSavedValues() {
let prior = KeychainStore.loadString(service: "ai.openclaw.gateway", account: "lastConnection")
defer {

View File

@@ -623,13 +623,13 @@ private final class MockBootstrapNotificationCenter: NotificationCentering, @unc
#expect(appModel.screen.urlString.isEmpty)
}
@Test @MainActor func handleInvokeA2UICommandsFailWhenHostMissing() async throws {
@Test @MainActor func handleInvokeA2UICommandsFailWhenLocalHostUnavailable() async throws {
let appModel = NodeAppModel()
let reset = BridgeInvokeRequest(id: "reset", command: OpenClawCanvasA2UICommand.reset.rawValue)
let resetRes = await appModel._test_handleInvoke(reset)
#expect(resetRes.ok == false)
#expect(resetRes.error?.message.contains("A2UI_HOST_NOT_CONFIGURED") == true)
#expect(resetRes.error?.message.contains("A2UI_HOST_UNAVAILABLE") == true)
let jsonl = "{\"beginRendering\":{}}"
let pushParams = OpenClawCanvasA2UIPushJSONLParams(jsonl: jsonl)
@@ -641,7 +641,7 @@ private final class MockBootstrapNotificationCenter: NotificationCentering, @unc
paramsJSON: pushJSON)
let pushRes = await appModel._test_handleInvoke(push)
#expect(pushRes.ok == false)
#expect(pushRes.error?.message.contains("A2UI_HOST_NOT_CONFIGURED") == true)
#expect(pushRes.error?.message.contains("A2UI_HOST_UNAVAILABLE") == true)
}
@Test @MainActor func handleInvokeUnknownCommandReturnsInvalidRequest() async {

View File

@@ -45,6 +45,23 @@ private func mountScreen(_ screen: ScreenController) throws -> (ScreenWebViewCoo
#expect(screen.urlString.isEmpty)
}
@Test @MainActor func canvasPresentationTracksExplicitPresentAndHide() {
let screen = ScreenController()
#expect(screen.isCanvasPresented == false)
screen.showDefaultCanvas()
#expect(screen.isCanvasPresented == false)
screen.presentDefaultCanvas()
#expect(screen.isCanvasPresented == true)
#expect(screen.urlString.isEmpty)
screen.hideCanvas()
#expect(screen.isCanvasPresented == false)
#expect(screen.urlString.isEmpty)
}
@Test @MainActor func evalExecutesJavaScript() async throws {
let screen = ScreenController()
let (coordinator, _) = try mountScreen(screen)
@@ -66,26 +83,37 @@ private func mountScreen(_ screen: ScreenController) throws -> (ScreenWebViewCoo
}
}
@Test @MainActor func trustedRemoteA2UIURLMustMatchExactly() {
@Test("remote A2UI URL is not trusted for native actions")
@MainActor func remoteA2UIURLIsNotTrustedForNativeActions() throws {
let screen = ScreenController()
let trusted = "https://node.ts.net:18789/__openclaw__/a2ui/?platform=ios"
screen.navigate(to: trusted, trustA2UIActions: true)
#expect(screen.isTrustedCanvasUIURL(URL(string: trusted)!) == true)
// Fragment differences must not affect trust (SPA hash routing).
#expect(screen.isTrustedCanvasUIURL(URL(string: "https://node.ts.net:18789/__openclaw__/a2ui/?platform=ios#step2")!) == true)
#expect(screen.isTrustedCanvasUIURL(URL(string: "https://node.ts.net:18789/__openclaw__/a2ui/?platform=android")!) == false)
#expect(screen.isTrustedCanvasUIURL(URL(string: "https://node.ts.net:18789/__openclaw__/canvas/")!) == false)
#expect(screen.isTrustedCanvasUIURL(URL(string: "https://evil.ts.net:18789/__openclaw__/a2ui/?platform=ios")!) == false)
#expect(screen.isTrustedCanvasUIURL(URL(string: "http://192.168.0.10:18789/")!) == false)
#expect(screen.isShowingLocalA2UI() == false)
let urls = try [
trusted,
"https://node.ts.net:18789/__openclaw__/a2ui/?platform=ios#step2",
"http://192.168.0.10:18789/__openclaw__/a2ui/?platform=ios",
"https://node.ts.net:18789/__openclaw__/a2ui/?platform=android",
"https://node.ts.net:18789/__openclaw__/canvas/",
"https://evil.ts.net:18789/__openclaw__/a2ui/?platform=ios",
].map { try #require(URL(string: $0)) }
for url in urls {
#expect(screen.isTrustedCanvasUIURL(url) == false)
}
}
@Test @MainActor func genericNavigationClearsTrustedRemoteA2UIURL() {
@Test("local A2UI URL is trusted for native actions")
@MainActor func localA2UIURLIsTrustedForNativeActions() throws {
let screen = ScreenController()
screen.navigate(to: "https://node.ts.net:18789/__openclaw__/a2ui/?platform=ios", trustA2UIActions: true)
screen.navigate(to: "https://evil.ts.net:18789/")
screen.showLocalA2UI()
#expect(screen.isTrustedCanvasUIURL(URL(string: "https://node.ts.net:18789/__openclaw__/a2ui/?platform=ios")!) == false)
let url = try #require(URL(string: screen.urlString))
#expect(url.isFileURL)
#expect(screen.isShowingLocalA2UI() == true)
#expect(screen.isTrustedCanvasUIURL(url) == true)
}
@Test func parseA2UIActionBodyAcceptsJSONString() throws {

View File

@@ -139,7 +139,10 @@ final class MacNodeModeCoordinator {
locationMode: OpenClawLocationMode,
connectionMode: AppState.ConnectionMode) -> [String]
{
var caps: [String] = [OpenClawCapability.canvas.rawValue, OpenClawCapability.screen.rawValue]
var caps: [String] = [
OpenClawCapability.canvas.rawValue,
OpenClawCapability.screen.rawValue,
]
if browserControlEnabled, connectionMode == .local {
caps.append(OpenClawCapability.browser.rawValue)
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

View File

@@ -0,0 +1,311 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OpenClaw Canvas</title>
<script>
(() => {
const normalizeLower = (value) => {
const trimmed = String(value || "").trim();
return trimmed.toLocaleLowerCase();
};
try {
const params = new URLSearchParams(window.location.search);
const platform = normalizeLower(params.get("platform"));
if (platform) {
document.documentElement.dataset.platform = platform;
return;
}
if (/android/i.test(navigator.userAgent || "")) {
document.documentElement.dataset.platform = "android";
}
} catch (_) {}
})();
</script>
<style>
:root {
color-scheme: dark;
}
@media (prefers-reduced-motion: reduce) {
body::before,
body::after {
animation: none !important;
}
}
html,
body {
height: 100%;
margin: 0;
}
body {
font:
14px system-ui,
-apple-system,
BlinkMacSystemFont,
"Roboto",
sans-serif;
background:
radial-gradient(1200px 900px at 15% 20%, rgba(42, 113, 255, 0.18), rgba(0, 0, 0, 0) 55%),
radial-gradient(900px 700px at 85% 30%, rgba(255, 0, 138, 0.14), rgba(0, 0, 0, 0) 60%),
radial-gradient(1000px 900px at 60% 90%, rgba(0, 209, 255, 0.1), rgba(0, 0, 0, 0) 60%),
#000;
color: #e5e7eb;
overflow: hidden;
}
:root[data-platform="android"] body {
background:
radial-gradient(1200px 900px at 15% 20%, rgba(42, 113, 255, 0.62), rgba(0, 0, 0, 0) 55%),
radial-gradient(900px 700px at 85% 30%, rgba(255, 0, 138, 0.52), rgba(0, 0, 0, 0) 60%),
radial-gradient(1000px 900px at 60% 90%, rgba(0, 209, 255, 0.48), rgba(0, 0, 0, 0) 60%),
#0b1328;
}
body::before {
content: "";
position: fixed;
inset: -20%;
background:
repeating-linear-gradient(
0deg,
rgba(255, 255, 255, 0.03) 0,
rgba(255, 255, 255, 0.03) 1px,
transparent 1px,
transparent 48px
),
repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.03) 0,
rgba(255, 255, 255, 0.03) 1px,
transparent 1px,
transparent 48px
);
transform: translate3d(0, 0, 0) rotate(-7deg);
will-change: transform, opacity;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
opacity: 0.45;
pointer-events: none;
animation: openclaw-grid-drift 140s ease-in-out infinite alternate;
}
:root[data-platform="android"] body::before {
opacity: 0.8;
}
body::after {
content: "";
position: fixed;
inset: -35%;
background:
radial-gradient(900px 700px at 30% 30%, rgba(42, 113, 255, 0.16), rgba(0, 0, 0, 0) 60%),
radial-gradient(800px 650px at 70% 35%, rgba(255, 0, 138, 0.12), rgba(0, 0, 0, 0) 62%),
radial-gradient(900px 800px at 55% 75%, rgba(0, 209, 255, 0.1), rgba(0, 0, 0, 0) 62%);
filter: blur(28px);
opacity: 0.52;
will-change: transform, opacity;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform: translate3d(0, 0, 0);
pointer-events: none;
animation: openclaw-glow-drift 110s ease-in-out infinite alternate;
}
:root[data-platform="android"] body::after {
opacity: 0.85;
}
@supports (mix-blend-mode: screen) {
body::after {
mix-blend-mode: screen;
}
}
@supports not (mix-blend-mode: screen) {
body::after {
opacity: 0.7;
}
}
@keyframes openclaw-grid-drift {
0% {
transform: translate3d(-12px, 8px, 0) rotate(-7deg);
opacity: 0.4;
}
50% {
transform: translate3d(10px, -7px, 0) rotate(-6.6deg);
opacity: 0.56;
}
100% {
transform: translate3d(-8px, 6px, 0) rotate(-7.2deg);
opacity: 0.42;
}
}
@keyframes openclaw-glow-drift {
0% {
transform: translate3d(-18px, 12px, 0) scale(1.02);
opacity: 0.4;
}
50% {
transform: translate3d(14px, -10px, 0) scale(1.05);
opacity: 0.52;
}
100% {
transform: translate3d(-10px, 8px, 0) scale(1.03);
opacity: 0.43;
}
}
canvas {
position: fixed;
inset: 0;
display: block;
width: 100vw;
height: 100vh;
touch-action: none;
z-index: 1;
}
:root[data-platform="android"] #openclaw-canvas {
background:
radial-gradient(1100px 800px at 20% 15%, rgba(42, 113, 255, 0.78), rgba(0, 0, 0, 0) 58%),
radial-gradient(900px 650px at 82% 28%, rgba(255, 0, 138, 0.66), rgba(0, 0, 0, 0) 62%),
radial-gradient(1000px 900px at 60% 88%, rgba(0, 209, 255, 0.58), rgba(0, 0, 0, 0) 62%),
#141c33;
}
#openclaw-status {
position: fixed;
inset: 0;
display: none;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 24px;
box-sizing: border-box;
pointer-events: none;
z-index: 3;
}
#openclaw-status .card {
width: min(560px, 88vw);
text-align: left;
padding: 14px 16px 12px;
border-radius: 16px;
background: linear-gradient(140deg, rgba(23, 24, 35, 0.78), rgba(18, 19, 28, 0.55));
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow:
0 16px 46px rgba(0, 0, 0, 0.52),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
-webkit-backdrop-filter: blur(18px) saturate(140%);
backdrop-filter: blur(18px) saturate(140%);
}
#openclaw-status .title {
font:
600 12px/1.2 -apple-system,
BlinkMacSystemFont,
"SF Pro Text",
system-ui,
sans-serif;
letter-spacing: 0.45px;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.7);
}
#openclaw-status .subtitle {
margin-top: 8px;
font:
500 13px/1.45 -apple-system,
BlinkMacSystemFont,
"SF Pro Text",
system-ui,
sans-serif;
color: rgba(255, 255, 255, 0.9);
white-space: pre-wrap;
overflow-wrap: anywhere;
}
openclaw-a2ui-host {
display: block;
height: 100%;
position: fixed;
inset: 0;
z-index: 4;
--openclaw-a2ui-inset-top: 28px;
--openclaw-a2ui-inset-right: 0px;
--openclaw-a2ui-inset-bottom: 0px;
--openclaw-a2ui-inset-left: 0px;
--openclaw-a2ui-scroll-pad-bottom: 0px;
--openclaw-a2ui-status-top: calc(50% - 18px);
--openclaw-a2ui-empty-top: 18px;
}
</style>
</head>
<body>
<canvas id="openclaw-canvas"></canvas>
<div id="openclaw-status" role="status" aria-live="polite">
<section class="card">
<div class="title" id="openclaw-status-title">Ready</div>
<div class="subtitle" id="openclaw-status-subtitle">Waiting for agent</div>
</section>
</div>
<openclaw-a2ui-host></openclaw-a2ui-host>
<script src="a2ui.bundle.js"></script>
<script>
(() => {
const canvas = document.getElementById("openclaw-canvas");
const ctx = canvas.getContext("2d");
const statusEl = document.getElementById("openclaw-status");
const titleEl = document.getElementById("openclaw-status-title");
const subtitleEl = document.getElementById("openclaw-status-subtitle");
const debugStatusEnabledByQuery = (() => {
try {
const params = new URLSearchParams(window.location.search);
const raw = params.get("debugStatus") ?? params.get("debug");
if (!raw) return false;
const normalized = normalizeLower(raw);
return normalized === "1" || normalized === "true" || normalized === "yes";
} catch (_) {
return false;
}
})();
let debugStatusEnabled = debugStatusEnabledByQuery;
function resize() {
const dpr = window.devicePixelRatio || 1;
const w = Math.max(1, Math.floor(window.innerWidth * dpr));
const h = Math.max(1, Math.floor(window.innerHeight * dpr));
canvas.width = w;
canvas.height = h;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
window.addEventListener("resize", resize);
resize();
const setDebugStatusEnabled = (enabled) => {
debugStatusEnabled = !!enabled;
if (!statusEl) return;
if (!debugStatusEnabled) {
statusEl.style.display = "none";
}
};
if (statusEl && !debugStatusEnabled) {
statusEl.style.display = "none";
}
window.__openclaw = {
canvas,
ctx,
setDebugStatusEnabled,
setStatus: (title, subtitle) => {
if (!statusEl || !debugStatusEnabled) return;
if (!title && !subtitle) {
statusEl.style.display = "none";
return;
}
statusEl.style.display = "flex";
if (titleEl && typeof title === "string") titleEl.textContent = title;
if (subtitleEl && typeof subtitle === "string") subtitleEl.textContent = subtitle;
if (!debugStatusEnabled) {
clearTimeout(window.__statusTimeout);
window.__statusTimeout = setTimeout(() => {
statusEl.style.display = "none";
}, 3000);
} else {
clearTimeout(window.__statusTimeout);
}
},
};
})();
</script>
</body>
</html>

View File

@@ -52,6 +52,7 @@ public struct ConnectParams: Codable, Sendable {
public let client: [String: AnyCodable]
public let caps: [String]?
public let commands: [String]?
public let nodeplugintools: [NodePluginToolDescriptor]?
public let permissions: [String: AnyCodable]?
public let pathenv: String?
public let role: String?
@@ -67,6 +68,7 @@ public struct ConnectParams: Codable, Sendable {
client: [String: AnyCodable],
caps: [String]?,
commands: [String]?,
nodeplugintools: [NodePluginToolDescriptor]?,
permissions: [String: AnyCodable]?,
pathenv: String?,
role: String?,
@@ -81,6 +83,7 @@ public struct ConnectParams: Codable, Sendable {
self.client = client
self.caps = caps
self.commands = commands
self.nodeplugintools = nodeplugintools
self.permissions = permissions
self.pathenv = pathenv
self.role = role
@@ -97,6 +100,7 @@ public struct ConnectParams: Codable, Sendable {
case client
case caps
case commands
case nodeplugintools = "nodePluginTools"
case permissions
case pathenv = "pathEnv"
case role
@@ -1128,6 +1132,54 @@ public struct NodeRenameParams: Codable, Sendable {
public struct NodeListParams: Codable, Sendable {}
public struct NodePluginToolDescriptor: Codable, Sendable {
public let pluginid: String
public let name: String
public let description: String
public let parameters: [String: AnyCodable]?
public let command: String?
public let mcp: [String: AnyCodable]?
public init(
pluginid: String,
name: String,
description: String,
parameters: [String: AnyCodable]?,
command: String?,
mcp: [String: AnyCodable]?)
{
self.pluginid = pluginid
self.name = name
self.description = description
self.parameters = parameters
self.command = command
self.mcp = mcp
}
private enum CodingKeys: String, CodingKey {
case pluginid = "pluginId"
case name
case description
case parameters
case command
case mcp
}
}
public struct NodePluginToolsUpdateParams: Codable, Sendable {
public let tools: [NodePluginToolDescriptor]
public init(
tools: [NodePluginToolDescriptor])
{
self.tools = tools
}
private enum CodingKeys: String, CodingKey {
case tools
}
}
public struct NodePendingAckParams: Codable, Sendable {
public let ids: [String]
@@ -5478,6 +5530,62 @@ public struct SkillsProposalReviseParams: Codable, Sendable {
}
}
public struct SkillsProposalRequestRevisionParams: Codable, Sendable {
public let agentid: String?
public let targetagentid: String?
public let proposalid: String
public let instructions: String
public let sessionkey: String
public let sessionid: String?
public let idempotencykey: String
public init(
agentid: String? = nil,
targetagentid: String?,
proposalid: String,
instructions: String,
sessionkey: String,
sessionid: String?,
idempotencykey: String)
{
self.agentid = agentid
self.targetagentid = targetagentid
self.proposalid = proposalid
self.instructions = instructions
self.sessionkey = sessionkey
self.sessionid = sessionid
self.idempotencykey = idempotencykey
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case targetagentid = "targetAgentId"
case proposalid = "proposalId"
case instructions
case sessionkey = "sessionKey"
case sessionid = "sessionId"
case idempotencykey = "idempotencyKey"
}
}
public struct SkillsProposalRequestRevisionResult: Codable, Sendable {
public let runid: String
public let status: AnyCodable
public init(
runid: String,
status: AnyCodable)
{
self.runid = runid
self.status = status
}
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case status
}
}
public struct SkillsProposalActionParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
@@ -6974,6 +7082,7 @@ public struct ChatSendParams: Codable, Sendable {
public let timeoutms: Int?
public let systeminputprovenance: [String: AnyCodable]?
public let systemprovenancereceipt: String?
public let suppresscommandinterpretation: Bool?
public let idempotencykey: String
public init(
@@ -6992,6 +7101,7 @@ public struct ChatSendParams: Codable, Sendable {
timeoutms: Int?,
systeminputprovenance: [String: AnyCodable]?,
systemprovenancereceipt: String?,
suppresscommandinterpretation: Bool?,
idempotencykey: String)
{
self.sessionkey = sessionkey
@@ -7009,6 +7119,7 @@ public struct ChatSendParams: Codable, Sendable {
self.timeoutms = timeoutms
self.systeminputprovenance = systeminputprovenance
self.systemprovenancereceipt = systemprovenancereceipt
self.suppresscommandinterpretation = suppresscommandinterpretation
self.idempotencykey = idempotencykey
}
@@ -7028,6 +7139,7 @@ public struct ChatSendParams: Codable, Sendable {
case timeoutms = "timeoutMs"
case systeminputprovenance = "systemInputProvenance"
case systemprovenancereceipt = "systemProvenanceReceipt"
case suppresscommandinterpretation = "suppressCommandInterpretation"
case idempotencykey = "idempotencyKey"
}
}

View File

@@ -1,3 +1,6 @@
/**
* Knip configuration for OpenClaw root and bundled plugin dependency hygiene.
*/
const BUNDLED_PLUGIN_ROOT_DIR = "extensions";
function bundledPluginFile(pluginId: string, relativePath: string, suffix = ""): string {

View File

@@ -916,7 +916,7 @@ OpenClaw sends Teams polls as Adaptive Cards (there is no native Teams poll API)
- CLI: `openclaw message poll --channel msteams --target conversation:<id> ...`
- Votes are recorded by the gateway in OpenClaw plugin-state SQLite under `state/openclaw.sqlite`.
- Existing `msteams-polls.json` files are imported once when the MSTeams plugin starts.
- Existing `msteams-polls.json` files are imported by `openclaw doctor --fix`, not by the running plugin.
- The gateway must stay online to record votes.
- Polls do not auto-post result summaries yet, and there is no supported poll-results CLI yet.

View File

@@ -397,7 +397,7 @@ Docker lane definitions live in `scripts/lib/docker-e2e-scenarios.mjs`, planner
| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | Main-pool slot count for normal lanes. |
| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | Provider-sensitive tail-pool slot count. |
| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | Concurrent live lane cap so providers do not throttle. |
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | Concurrent npm install lane cap. |
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 5 | Concurrent npm install lane cap. |
| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | Concurrent multi-service lane cap. |
| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | Stagger between lane starts to avoid Docker daemon create storms; set `0` for no stagger. |
| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | Per-lane fallback timeout (120 minutes); selected live/tail lanes use tighter caps. |

View File

@@ -25,6 +25,13 @@ Common use cases:
Execution is still guarded by **exec approvals** and per-agent allowlists on the
node host, so you can keep command access scoped and explicit.
Gateway-loaded plugins can also register node-host commands. When a registered
command includes `agentTool` metadata, `openclaw node run` advertises that
plugin or MCP-backed tool to the Gateway while the node is connected. The agent
sees it as a normal plugin tool, but execution still goes through `node.invoke`
and the node command allowlist, so disconnecting the node removes the tool from
new agent runs.
## Browser proxy (zero-config)
Node hosts automatically advertise a browser proxy if `browser.enabled` is not

View File

@@ -20,8 +20,8 @@ title: "Features"
<Card title="Media" icon="image" href="/nodes/images">
Images, audio, video, documents, and image/video generation.
</Card>
<Card title="Apps and UI" icon="monitor" href="/web/control-ui">
Web Control UI and macOS companion app.
<Card title="Apps and UI" icon="monitor" href="/platforms">
Windows Hub, Web Control UI, macOS app, and mobile nodes.
</Card>
<Card title="Mobile nodes" icon="smartphone" href="/nodes">
iOS and Android nodes with pairing, voice/chat, and rich device commands.

View File

@@ -108,10 +108,10 @@ These notices are operational messages, not assistant content. They are delivere
OpenClaw uses **auth profiles** for both API keys and OAuth tokens.
- Secrets live in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json` (legacy: `~/.openclaw/agent/auth-profiles.json`).
- Runtime auth-routing state lives in `~/.openclaw/agents/<agentId>/agent/auth-state.json`.
- Secrets and runtime auth-routing state live in `~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite`.
- Config `auth.profiles` / `auth.order` are **metadata + routing only** (no secrets).
- Legacy import-only OAuth file: `~/.openclaw/credentials/oauth.json` (imported into `auth-profiles.json` on first use).
- Legacy import-only OAuth file: `~/.openclaw/credentials/oauth.json` (imported into the per-agent auth store on first use).
- Legacy `auth-profiles.json`, `auth-state.json`, and per-agent `auth.json` files are imported by `openclaw doctor --fix`.
More detail: [OAuth](/concepts/oauth)
@@ -127,7 +127,7 @@ OAuth logins create distinct profiles so multiple accounts can coexist.
- Default: `provider:default` when no email is available.
- OAuth with email: `provider:<email>` (for example `google-antigravity:user@gmail.com`).
Profiles live in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json` under `profiles`.
Profiles live in the per-agent `openclaw-agent.sqlite` auth profile store.
## Rotation order
@@ -141,7 +141,7 @@ When a provider has multiple profiles, OpenClaw chooses an order like this:
`auth.profiles` filtered by provider.
</Step>
<Step title="Stored profiles">
Entries in `auth-profiles.json` for the provider.
Per-agent SQLite auth profile entries for the provider.
</Step>
</Steps>
@@ -229,7 +229,7 @@ Cooldowns use exponential backoff:
- 25 minutes
- 1 hour (cap)
State is stored in `auth-state.json` under `usageStats`:
State is stored in the per-agent SQLite auth state under `usageStats`:
```json
{
@@ -253,7 +253,7 @@ Not every billing-shaped response is `402`, and not every HTTP `402` lands here.
Meanwhile temporary `402` usage-window and organization/workspace spend-limit errors are classified as `rate_limit` when the message looks retryable (for example `weekly usage limit exhausted`, `daily limit reached, resets tomorrow`, or `organization spending limit exceeded`). Those stay on the short cooldown/failover path instead of the long billing-disable path.
</Note>
State is stored in `auth-state.json`:
State is stored in the per-agent SQLite auth state:
```json
{

View File

@@ -306,7 +306,7 @@ See [/providers/kilocode](/providers/kilocode) for setup details.
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M3` |
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-super-120b-a12b` |
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-ultra-550b-a55b` |
| NovitaAI | `novita` | `NOVITA_API_KEY` | `novita/deepseek/deepseek-v3-0324` |
| [Ollama Cloud](/providers/ollama-cloud) | `ollama-cloud` | `OLLAMA_API_KEY` | `ollama-cloud/kimi-k2.6` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `openrouter/auto` |

View File

@@ -17,10 +17,18 @@ is now:
told us this usage is allowed again
OpenAI Codex OAuth is explicitly supported for use in external tools like
OpenClaw. This page explains:
OpenClaw.
OpenClaw stores both OpenAI API-key auth and ChatGPT/Codex OAuth under the
canonical provider id `openai`. Older `openai-codex:*` profile ids and
`auth.order.openai-codex` entries are legacy state repaired by
`openclaw doctor --fix`; use `openai:*` profile ids and `auth.order.openai` for
new config.
For Anthropic in production, API key auth is the safer recommended path.
This page explains:
- how the OAuth **token exchange** works (PKCE)
- where tokens are **stored** (and why)
- how to handle **multiple accounts** (profiles + per-session overrides)
@@ -122,6 +130,18 @@ Flow shape:
OpenAI Codex OAuth is explicitly supported for use outside the Codex CLI, including OpenClaw workflows.
The login command still uses the canonical OpenAI provider id:
```bash
openclaw models auth login --provider openai
```
Use `--profile-id openai:<name>` for multiple ChatGPT/Codex OAuth accounts in
one agent. Do not use `openai-codex:<name>` for new profiles. Doctor migrates
that older prefix to a collision-free `openai:*` profile id; run
`openclaw models auth list --provider openai` after repair before copying
profile ids into `auth.order` or `/model ...@<profileId>`.
Flow shape (PKCE):
1. generate PKCE verifier/challenge + random `state`

View File

@@ -87,13 +87,13 @@ This is a two-step setup:
If `claude` is not on `PATH`, either install Claude Code first or set
`agents.defaults.cliBackends.claude-cli.command` to the real binary path.
Manual token entry (any provider; writes `auth-profiles.json` + updates config):
Manual token entry (any provider; writes the per-agent SQLite auth store + updates config):
```bash
openclaw models auth paste-token --provider openrouter
```
`auth-profiles.json` stores credentials only. The canonical shape is:
The auth profile store keeps credentials only. Legacy `auth-profiles.json` files used this canonical shape:
```json
{
@@ -108,9 +108,9 @@ openclaw models auth paste-token --provider openrouter
}
```
OpenClaw expects the canonical `version` + `profiles` shape at runtime. If an older install still has a flat file such as `{ "openrouter": { "apiKey": "..." } }`, run `openclaw doctor --fix` to rewrite it as an `openrouter:default` API-key profile; doctor keeps a `.legacy-flat.*.bak` copy beside the original. Endpoint details such as `baseUrl`, `api`, model ids, headers, and timeouts belong under `models.providers.<id>` in `openclaw.json` or `models.json`, not in `auth-profiles.json`.
OpenClaw now reads auth profiles from each agent's `openclaw-agent.sqlite`. If an older install still has `auth-profiles.json`, `auth-state.json`, or a flat auth profile file such as `{ "openrouter": { "apiKey": "..." } }`, run `openclaw doctor --fix` to import it into SQLite; doctor keeps timestamped backups beside the original JSON files. Endpoint details such as `baseUrl`, `api`, model ids, headers, and timeouts belong under `models.providers.<id>` in `openclaw.json` or `models.json`, not in auth profiles.
External auth routes such as Bedrock `auth: "aws-sdk"` are also not credentials. If you want a named Bedrock route, put `auth.profiles.<id>.mode: "aws-sdk"` in `openclaw.json`; do not write `type: "aws-sdk"` into `auth-profiles.json`. `openclaw doctor --fix` moves legacy AWS SDK markers from the credential store into config metadata.
External auth routes such as Bedrock `auth: "aws-sdk"` are also not credentials. If you want a named Bedrock route, put `auth.profiles.<id>.mode: "aws-sdk"` in `openclaw.json`; do not write `type: "aws-sdk"` into the auth profile store. `openclaw doctor --fix` moves legacy AWS SDK markers from the credential store into config metadata.
Auth profile refs are also supported for static credentials:
@@ -193,6 +193,25 @@ key in the provider dashboard when you need provider-side invalidation.
## Controlling which credential is used
### OpenAI and legacy `openai-codex` ids
OpenAI API-key profiles and ChatGPT/Codex OAuth profiles both use the canonical
provider id `openai`. New config should use `openai:*` profile ids and
`auth.order.openai`.
If you see `openai-codex` in older config, auth profile ids, or
`auth.order.openai-codex`, treat it as legacy migration input. Do not create new
`openai-codex` profiles. Run:
```bash
openclaw doctor --fix
openclaw models auth list --provider openai
```
Doctor rewrites legacy `openai-codex:*` profile ids and
`auth.order.openai-codex` entries to the canonical `openai` auth route. For
OpenAI-specific model/runtime routing, see [OpenAI](/providers/openai).
### During login (CLI)
Use `openclaw models auth login --provider <id> --profile-id <profileId>` for
@@ -225,7 +244,7 @@ Use `/model` (or `/model list`) for a compact picker; use `/model status` for th
### Per-agent (CLI override)
Set an explicit auth profile order override for an agent (stored in that agent's `auth-state.json`):
Set an explicit auth profile order override for an agent (stored in that agent's SQLite auth state):
```bash
openclaw models auth order get --provider anthropic

View File

@@ -270,6 +270,13 @@ Nodes declare capability claims at connect time:
- `permissions`: granular toggles (e.g. `screen.record`, `camera.capture`).
The Gateway treats these as **claims** and enforces server-side allowlists.
Connected nodes can publish optional agent-visible plugin or MCP tool
descriptors with `node.pluginTools.update` after a successful connect, after
reconnect, or after a local plugin/MCP inventory change. Each descriptor must
use a provider-safe tool `name` and name a `command` in the node's current
command allowlist. The Gateway filters descriptors outside the approved command
surface, removes them when the node disconnects, and rejects operator attempts
to mutate another node's catalog.
## Presence
@@ -461,6 +468,7 @@ enumeration of `src/gateway/server-methods/*.ts`.
- `node.invoke` forwards a command to a connected node.
- `node.invoke.result` returns the result for an invoke request.
- `node.event` carries node-originated events back into the gateway.
- `node.pluginTools.update` replaces the connected node's agent-visible plugin/MCP tool descriptors.
- `node.pending.pull` and `node.pending.ack` are the connected-node queue APIs.
- `node.pending.enqueue` and `node.pending.drain` manage durable pending work for offline/disconnected nodes.

View File

@@ -512,9 +512,10 @@ The agent-facing `gateway` runtime tool still refuses to rewrite
`tools.exec.ask` or `tools.exec.security`; legacy `tools.bash.*` aliases are
normalized to the same protected exec paths before the write.
Agent-driven `gateway config.apply` and `gateway config.patch` edits are
fail-closed by default: only a narrow set of prompt, model, and mention-gating
paths are agent-tunable. New sensitive config trees are therefore protected
unless they are deliberately added to the allowlist.
fail-closed by default: only a narrow set of low-risk runtime tuning,
mention-gating, and visible-reply paths are agent-tunable. Global model defaults
and prompt overlays stay operator-controlled. New sensitive config trees are
therefore protected unless they are deliberately added to the allowlist.
For any agent/surface that handles untrusted content, deny these by default:

View File

@@ -856,7 +856,8 @@ and troubleshooting see the main [FAQ](/help/faq).
- **Recommended:** 2GB RAM or more if you run multiple channels, browser automation, or media tools.
- **OS:** Ubuntu LTS or another modern Debian/Ubuntu.
If you are on Windows, **WSL2 is the easiest VM style setup** and has the best tooling
If you are on Windows, use **Windows Hub** for desktop setup, or WSL2 when
you specifically want a Linux-style Gateway VM with broad tooling
compatibility. See [Windows](/platforms/windows), [VPS hosting](/vps).
If you are running macOS in a VM, see [macOS VM](/install/macos-vm).

View File

@@ -1652,9 +1652,14 @@ lives on the [Models FAQ](/help/faq-models).
</Accordion>
<Accordion title="I closed my terminal on Windows - how do I restart OpenClaw?">
There are **two Windows install modes**:
There are **three Windows install modes**:
**1) WSL2 (recommended):** the Gateway runs inside Linux.
**1) Windows Hub local setup:** the native app manages a local app-owned WSL Gateway.
Open **OpenClaw Companion** from the Start menu or tray, then use
**Gateway Setup** or the Connections tab.
**2) Manual WSL2 Gateway:** the Gateway runs inside Linux.
Open PowerShell, enter WSL, then restart:
@@ -1670,7 +1675,7 @@ lives on the [Models FAQ](/help/faq-models).
openclaw gateway run
```
**2) Native Windows (not recommended):** the Gateway runs directly in Windows.
**3) Native Windows CLI/Gateway:** the Gateway runs directly in Windows.
Open PowerShell and run:
@@ -1685,7 +1690,7 @@ lives on the [Models FAQ](/help/faq-models).
openclaw gateway run
```
Docs: [Windows (WSL2)](/platforms/windows), [Gateway service runbook](/gateway).
Docs: [Windows](/platforms/windows), [Gateway service runbook](/gateway).
</Accordion>

View File

@@ -746,7 +746,7 @@ These Docker runners split into two buckets:
`OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`, and
`OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`. Set `OPENCLAW_LIVE_MAX_MODELS`
or the gateway env vars when you explicitly want a smaller cap or larger scan.
- `test:docker:all` builds the live Docker image once via `test:docker:live-build`, packs OpenClaw once as an npm tarball through `scripts/package-openclaw-for-docker.mjs`, then builds/reuses two `scripts/e2e/Dockerfile` images. The bare image is only the Node/Git runner for install/update/plugin-dependency lanes; those lanes mount the prebuilt tarball. The functional image installs the same tarball into `/app` for built-app functionality lanes. Docker lane definitions live in `scripts/lib/docker-e2e-scenarios.mjs`; planner logic lives in `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` executes the selected plan. The aggregate uses a weighted local scheduler: `OPENCLAW_DOCKER_ALL_PARALLELISM` controls process slots, while resource caps keep heavy live, npm-install, and multi-service lanes from all starting at once. If a single lane is heavier than the active caps, the scheduler can still start it when the pool is empty and then keeps it running alone until capacity is available again. Defaults are 10 slots, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; tune `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` or `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` only when the Docker host has more headroom. The runner performs a Docker preflight by default, removes stale OpenClaw E2E containers, prints status every 30 seconds, stores successful lane timings in `.artifacts/docker-tests/lane-timings.json`, and uses those timings to start longer lanes first on later runs. Use `OPENCLAW_DOCKER_ALL_DRY_RUN=1` to print the weighted lane manifest without building or running Docker, or `node scripts/test-docker-all.mjs --plan-json` to print the CI plan for selected lanes, package/image needs, and credentials.
- `test:docker:all` builds the live Docker image once via `test:docker:live-build`, packs OpenClaw once as an npm tarball through `scripts/package-openclaw-for-docker.mjs`, then builds/reuses two `scripts/e2e/Dockerfile` images. The bare image is only the Node/Git runner for install/update/plugin-dependency lanes; those lanes mount the prebuilt tarball. The functional image installs the same tarball into `/app` for built-app functionality lanes. Docker lane definitions live in `scripts/lib/docker-e2e-scenarios.mjs`; planner logic lives in `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` executes the selected plan. The aggregate uses a weighted local scheduler: `OPENCLAW_DOCKER_ALL_PARALLELISM` controls process slots, while resource caps keep heavy live, npm-install, and multi-service lanes from all starting at once. If a single lane is heavier than the active caps, the scheduler can still start it when the pool is empty and then keeps it running alone until capacity is available again. Defaults are 10 slots, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=5`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; tune `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` or `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` only when the Docker host has more headroom. The runner performs a Docker preflight by default, removes stale OpenClaw E2E containers, prints status every 30 seconds, stores successful lane timings in `.artifacts/docker-tests/lane-timings.json`, and uses those timings to start longer lanes first on later runs. Use `OPENCLAW_DOCKER_ALL_DRY_RUN=1` to print the weighted lane manifest without building or running Docker, or `node scripts/test-docker-all.mjs --plan-json` to print the CI plan for selected lanes, package/image needs, and credentials.
- `Package Acceptance` is the GitHub-native package gate for "does this installable tarball work as a product?" It resolves one candidate package from `source=npm`, `source=ref`, `source=url`, or `source=artifact`, uploads it as `package-under-test`, then runs the reusable Docker E2E lanes against that exact tarball instead of repacking the selected ref. Profiles are ordered by breadth: `smoke`, `package`, `product`, and `full`. See [Testing updates and plugins](/help/testing-updates-plugins) for the package/update/plugin contract, published-upgrade survivor matrix, release defaults, and failure triage.
- Build and release checks run `scripts/check-cli-bootstrap-imports.mjs` after tsdown. The guard walks the static built graph from `dist/entry.js` and `dist/cli/run-main.js` and fails if pre-dispatch startup imports package dependencies such as Commander, prompt UI, undici, or logging before command dispatch; it also keeps the bundled gateway run chunk under budget and rejects static imports of known cold gateway paths. Packaged CLI smoke also covers root help, onboard help, doctor help, status, config schema, and a model-list command.
- Package Acceptance legacy compatibility is capped at `2026.4.25` (`2026.4.25-beta.*` included). Through that cutoff, the harness tolerates only shipped-package metadata gaps: omitted private QA inventory entries, missing `gateway install --wrapper`, missing patch files in the tarball-derived git fixture, missing persisted `update.channel`, legacy plugin install-record locations, missing marketplace install-record persistence, and config metadata migration during `plugins update`. For packages after `2026.4.25`, those paths are strict failures.

View File

@@ -1,3 +1,7 @@
/**
* Docs UI enhancement that mirrors the active nav tab underline with a stable
* animated underline element.
*/
(() => {
const NAV_TABS_SELECTOR = ".nav-tabs";
const ACTIVE_UNDERLINE_SELECTOR = ".nav-tabs-item > div.bg-primary";

View File

@@ -249,7 +249,9 @@ openclaw nodes canvas a2ui reset --node <idOrNameOrIp>
Notes:
- Mobile nodes use a bundled app-owned A2UI page for action-capable rendering.
- Only A2UI v0.8 JSONL is supported (v0.9/createSurface is rejected).
- iOS and Android render remote Gateway Canvas pages, but A2UI button actions are dispatched only from the bundled app-owned A2UI page. Gateway-hosted HTTP/HTTPS A2UI pages are render-only on those mobile clients.
## Photos + videos (node camera)

View File

@@ -198,12 +198,12 @@ openclaw nodes invoke --node "<Android Node>" --command canvas.navigate --params
Tailnet (optional): if both devices are on Tailscale, use a MagicDNS name or tailnet IP instead of `.local`, e.g. `http://<gateway-magicdns>:18789/__openclaw__/canvas/`.
This server injects a live-reload client into HTML and reloads on file changes.
The A2UI host lives at `http://<gateway-host>:18789/__openclaw__/a2ui/`.
The Gateway also serves `/__openclaw__/a2ui/`, but the Android app treats remote A2UI pages as render-only. Action-capable A2UI commands use the bundled app-owned A2UI page before applying messages.
Canvas commands (foreground only):
- `canvas.eval`, `canvas.snapshot`, `canvas.navigate` (use `{"url":""}` or `{"url":"/"}` to return to the default scaffold). `canvas.snapshot` returns `{ format, base64 }` (default `format="jpeg"`).
- A2UI: `canvas.a2ui.push`, `canvas.a2ui.reset` (`canvas.a2ui.pushJSONL` legacy alias)
- A2UI: `canvas.a2ui.push`, `canvas.a2ui.reset` (`canvas.a2ui.pushJSONL` legacy alias). These commands use the bundled app-owned A2UI page for action-capable rendering.
Camera commands (foreground only; permission-gated):

View File

@@ -10,9 +10,11 @@ OpenClaw core is written in TypeScript. **Node is the recommended runtime**.
Bun is not recommended for the Gateway — known issues with WhatsApp and
Telegram channels; see [Bun (experimental)](/install/bun) for details.
Companion apps exist for macOS (menu bar app) and mobile nodes (iOS/Android). Windows and
Linux companion apps are planned, but the Gateway is fully supported today.
Native companion apps for Windows are also planned; the Gateway is recommended via WSL2.
Companion apps exist for Windows Hub, macOS (menu bar app), and mobile nodes
(iOS/Android). Linux companion apps are planned, but the Gateway is fully
supported today. On Windows, choose Windows Hub for the desktop app, native
PowerShell install for terminal-first use, or WSL2 for the most
Linux-compatible Gateway runtime.
## Choose your OS
@@ -35,6 +37,7 @@ Native companion apps for Windows are also planned; the Gateway is recommended v
## Common links
- Install guide: [Getting Started](/start/getting-started)
- Windows Hub: [Windows](/platforms/windows)
- Gateway runbook: [Gateway](/gateway)
- Gateway configuration: [Configuration](/gateway/configuration)
- Service status: `openclaw gateway status`
@@ -57,5 +60,6 @@ The service target depends on OS:
## Related
- [Install overview](/install)
- [Windows Hub](/platforms/windows)
- [macOS app](/platforms/macos)
- [iOS app](/platforms/ios)

View File

@@ -238,7 +238,8 @@ Notes:
- The Gateway canvas host serves `/__openclaw__/canvas/` and `/__openclaw__/a2ui/`.
- It is served from the Gateway HTTP server (same port as `gateway.port`, default `18789`).
- The iOS node auto-navigates to A2UI on connect when a canvas host URL is advertised.
- The iOS node keeps the built-in scaffold as the connected default view. `canvas.a2ui.push` and `canvas.a2ui.reset` use the bundled app-owned A2UI page.
- Remote Gateway A2UI pages are render-only on iOS; native A2UI button actions are accepted only from bundled app-owned pages.
- Return to the built-in scaffold with `canvas.navigate` and `{"url":""}`.
## Computer Use relationship
@@ -275,7 +276,7 @@ openclaw nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"ma
## Common errors
- `NODE_BACKGROUND_UNAVAILABLE`: bring the iOS app to the foreground (canvas/camera/screen commands require it).
- `A2UI_HOST_NOT_CONFIGURED`: the Gateway did not advertise the Canvas plugin surface URL; check `plugins.entries.canvas.config.host` in [Gateway configuration](/gateway/configuration).
- `A2UI_HOST_UNAVAILABLE`: the bundled A2UI page was not reachable in the app WebView; keep the app foregrounded on the Screen tab and retry.
- Pairing prompt never appears: run `openclaw devices list` and approve manually.
- Reconnect fails after reinstall: the Keychain pairing token was cleared; re-pair the node.

View File

@@ -120,10 +120,11 @@ Use [`defineToolPlugin`](/plugins/tool-plugins) for simple tool-only plugins
with fixed tool names. Use `api.registerTool(...)` directly for mixed plugins
or fully dynamic tool registration.
| Method | What it registers |
| ------------------------------- | --------------------------------------------- |
| `api.registerTool(tool, opts?)` | Agent tool (required or `{ optional: true }`) |
| `api.registerCommand(def)` | Custom command (bypasses the LLM) |
| Method | What it registers |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `api.registerTool(tool, opts?)` | Agent tool (required or `{ optional: true }`) |
| `api.registerCommand(def)` | Custom command (bypasses the LLM) |
| `api.registerNodeHostCommand(command)` | Command handled by `openclaw node run`; optional `agentTool` metadata can expose it as an agent-visible tool while the node is connected |
Plugin commands can set `agentPromptGuidance` when the agent needs a short,
command-owned routing hint. Keep that text about the command itself; do not add
@@ -150,6 +151,19 @@ surfaces: only guidance explicitly scoped to `codex_app_server` is promoted into
that higher-priority lane. Legacy string guidance and unscoped structured
guidance remain available to non-Codex prompt surfaces for compatibility.
Node-host commands run on the connected node host, not inside the Gateway
process. If `agentTool` is present, the node publishes a descriptor after a
successful Gateway connect; the Gateway exposes it to agent runs only while that
node is connected and only if the descriptor's `command` is in the node's
approved command surface. Set `agentTool.defaultPlatforms` to opt a
non-dangerous command into the default node command allowlist; otherwise require
explicit `gateway.nodes.allowCommands` or a node-invoke policy. `agentTool.name`
must be provider-safe: start with a letter, use only letters, digits,
underscores, or hyphens, and stay within 64 characters. MCP-backed node tools
can set `agentTool.mcp` metadata so catalog and tool-search surfaces can show
the remote MCP server/tool identity, but execution still goes through the
advertised node command.
### Infrastructure
| Method | What it registers |

View File

@@ -251,9 +251,15 @@ two-party event loops that do not go through the shared inbound reply runner.
});
```
`nodes.list(...)` includes each connected node's advertised
`nodePluginTools` descriptors when that node exposes plugin or MCP-backed
tools to the agent. Those descriptors are live connection state: the Gateway
drops them when the node disconnects, and a node can replace them with
`node.pluginTools.update` after local plugin/MCP inventory changes.
Inside the Gateway this runtime is in-process. In plugin CLI commands it calls the configured Gateway over RPC, so commands such as `openclaw googlemeet recover-tab` can inspect paired nodes from the terminal. Node commands still go through normal Gateway node pairing, command allowlists, plugin node-invoke policies, and node-local command handling.
Plugins that expose dangerous node-host commands should register a node-invoke policy with `api.registerNodeInvokePolicy(...)`. The policy runs in the Gateway after command allowlist checks and before the command is forwarded to the node, so direct `node.invoke` calls and higher-level plugin tools share the same enforcement path.
Plugins that expose node-hosted agent tools can set `agentTool.defaultPlatforms` for non-dangerous commands that should be allowlisted by default. Omit it when operators must opt in with `gateway.nodes.allowCommands`. Dangerous node-host commands should register a node-invoke policy with `api.registerNodeInvokePolicy(...)`; the policy runs in the Gateway after command allowlist checks and before the command is forwarded to the node, so direct `node.invoke` calls, node-hosted plugin tools, and higher-level plugin tools share the same enforcement path.
</Accordion>
<Accordion title="api.runtime.tasks.managedFlows">

View File

@@ -3,12 +3,15 @@ summary: "Use NVIDIA's OpenAI-compatible API in OpenClaw"
read_when:
- You want to use open models in OpenClaw for free
- You need NVIDIA_API_KEY setup
- You want to use Nemotron 3 Ultra through NVIDIA
title: "NVIDIA"
---
NVIDIA provides an OpenAI-compatible API at `https://integrate.api.nvidia.com/v1` for
open models for free. Authenticate with an API key from
[build.nvidia.com](https://build.nvidia.com/settings/api-keys).
[build.nvidia.com](https://build.nvidia.com/settings/api-keys). OpenClaw
defaults the NVIDIA provider to Nemotron 3 Ultra, NVIDIA's 550B total / 55B
active reasoning model for long-context agentic work.
## Getting started
@@ -24,7 +27,7 @@ open models for free. Authenticate with an API key from
</Step>
<Step title="Set an NVIDIA model">
```bash
openclaw models set nvidia/nvidia/nemotron-3-super-120b-a12b
openclaw models set nvidia/nvidia/nemotron-3-ultra-550b-a55b
```
</Step>
</Steps>
@@ -56,7 +59,7 @@ openclaw onboard --auth-choice nvidia-api-key --nvidia-api-key "nvapi-..."
},
agents: {
defaults: {
model: { primary: "nvidia/nvidia/nemotron-3-super-120b-a12b" },
model: { primary: "nvidia/nvidia/nemotron-3-ultra-550b-a55b" },
},
},
}
@@ -69,22 +72,39 @@ try NVIDIA's public featured-model catalog from
`https://assets.ngc.nvidia.com/products/api-catalog/featured-models.json` and
caches the ranked result for 24 hours. New featured models from build.nvidia.com
therefore appear in setup and model-selection surfaces without waiting for an
OpenClaw release.
OpenClaw release. When the live feed is available, the first returned model is
the default option shown during NVIDIA setup.
The fetch uses a fixed HTTPS host policy for `assets.ngc.nvidia.com`. If no
NVIDIA API key is configured, or if that public catalog is unavailable or
malformed, OpenClaw falls back to the bundled catalog below.
malformed, OpenClaw falls back to the bundled catalog and bundled default below.
## Nemotron 3 Ultra
Nemotron 3 Ultra is the default NVIDIA model in OpenClaw. NVIDIA's build page for
[`nvidia/nemotron-3-ultra-550b-a55b`](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b)
lists it as an available free endpoint with a 1M-token context specification.
The bundled catalog records a 16,384-token max output to match NVIDIA's current
OpenAI-compatible sample request for the hosted endpoint.
Use Ultra for the highest-capability NVIDIA default. Keep Super selected when
you want the smaller Nemotron 3 option, or choose one of the third-party models
hosted in NVIDIA's catalog when their context, latency, or behavior fits better.
The bundled Ultra row sends `chat_template_kwargs.enable_thinking: false` and
`force_nonempty_content: true` by default so normal chat output stays in the
visible answer instead of exposing reasoning text.
## Bundled fallback catalog
| Model ref | Name | Context | Max output | Notes |
| ------------------------------------------ | ---------------------------- | ------- | ---------- | --------------------------------- |
| `nvidia/nvidia/nemotron-3-super-120b-a12b` | NVIDIA Nemotron 3 Super 120B | 262,144 | 8,192 | Featured fallback |
| `nvidia/moonshotai/kimi-k2.5` | Kimi K2.5 | 262,144 | 8,192 | Featured fallback |
| `nvidia/minimaxai/minimax-m2.7` | Minimax M2.7 | 196,608 | 8,192 | Featured fallback |
| `nvidia/z-ai/glm-5.1` | GLM 5.1 | 202,752 | 8,192 | Featured fallback |
| `nvidia/minimaxai/minimax-m2.5` | MiniMax M2.5 | 196,608 | 8,192 | Deprecated, upgrade compatibility |
| `nvidia/z-ai/glm5` | GLM-5 | 202,752 | 8,192 | Deprecated, upgrade compatibility |
| Model ref | Name | Context | Max output | Notes |
| ------------------------------------------ | ---------------------------- | --------- | ---------- | --------------------------------- |
| `nvidia/nvidia/nemotron-3-ultra-550b-a55b` | NVIDIA Nemotron 3 Ultra 550B | 1,000,000 | 16,384 | Default |
| `nvidia/nvidia/nemotron-3-super-120b-a12b` | NVIDIA Nemotron 3 Super 120B | 262,144 | 8,192 | Featured fallback |
| `nvidia/moonshotai/kimi-k2.5` | Kimi K2.5 | 262,144 | 8,192 | Featured fallback |
| `nvidia/minimaxai/minimax-m2.7` | Minimax M2.7 | 196,608 | 8,192 | Featured fallback |
| `nvidia/z-ai/glm-5.1` | GLM 5.1 | 202,752 | 8,192 | Featured fallback |
| `nvidia/minimaxai/minimax-m2.5` | MiniMax M2.5 | 196,608 | 8,192 | Deprecated, upgrade compatibility |
| `nvidia/z-ai/glm5` | GLM-5 | 202,752 | 8,192 | Deprecated, upgrade compatibility |
## Advanced configuration
@@ -97,9 +117,9 @@ malformed, OpenClaw falls back to the bundled catalog below.
<Accordion title="Catalog and pricing">
OpenClaw prefers NVIDIA's public featured-model catalog when NVIDIA auth is
configured and caches it for 24 hours. The bundled fallback catalog is static
and keeps deprecated shipped refs for upgrade compatibility. Costs default to
`0` in source since NVIDIA currently offers free API access for the listed
models.
and keeps deprecated shipped refs for upgrade compatibility. Costs default
to `0` in source since NVIDIA currently offers free API access for the
listed models.
</Accordion>
<Accordion title="OpenAI-compatible endpoint">
@@ -107,6 +127,36 @@ malformed, OpenClaw falls back to the bundled catalog below.
tooling should work out of the box with the NVIDIA base URL.
</Accordion>
<Accordion title="Nemotron 3 Ultra reasoning params">
NVIDIA's Ultra sample request uses `chat_template_kwargs.enable_thinking`
and `reasoning_budget` for reasoning output. OpenClaw's bundled Ultra row
disables template thinking by default for normal chat use. If you need to
opt into NVIDIA reasoning output or force other NVIDIA-specific request
fields, set per-model params and keep provider-specific overrides scoped to
the NVIDIA model:
```json5
{
agents: {
defaults: {
models: {
"nvidia/nvidia/nemotron-3-ultra-550b-a55b": {
params: {
chat_template_kwargs: { enable_thinking: true },
extra_body: { reasoning_budget: 16384 },
},
},
},
},
},
}
```
`params.extra_body` is the final OpenAI-compatible request-body override, so
use it only for fields NVIDIA documents for the selected endpoint.
</Accordion>
<Accordion title="Slow custom provider responses">
Some NVIDIA-hosted custom models can take longer than the default model idle
watchdog before they emit a first response chunk. For custom NVIDIA provider

View File

@@ -1002,10 +1002,10 @@ sessionId})`; create, branch, continue, list, and fork flows live in their
- The generic plugin SDK persistent-dedupe helper no longer exposes file-shaped
options. Callers provide SQLite scope keys and durable dedupe rows live in
shared plugin state.
- Microsoft Teams SSO and delegated OAuth tokens moved from locked JSON files
to SQLite plugin state. Doctor imports `msteams-sso-tokens.json` and
`msteams-delegated.json`, rebuilds canonical SSO token keys from payloads,
and removes the source files.
- Microsoft Teams SSO tokens moved from locked JSON files to SQLite plugin
state. Doctor imports `msteams-sso-tokens.json`, rebuilds canonical SSO token
keys from payloads, and removes the source file. Delegated OAuth tokens stay
on their existing private credential-file boundary.
- Matrix sync cache state moved from `bot-storage.json` to SQLite plugin
state. Doctor imports legacy raw or wrapped sync payloads and removes the
source file. Active Matrix and QA Matrix clients pass a SQLite sync-store root
@@ -1613,13 +1613,13 @@ Move these into the global database:
`reply-cache`, `sent-echoes`) instead of `imessage/catchup/*.json`,
`imessage/reply-cache.jsonl`, and `imessage/sent-echoes.jsonl`; the iMessage
doctor/setup migration imports and removes the legacy files.
- Microsoft Teams conversations, polls, delegated tokens, pending uploads, and
feedback learnings now use SQLite plugin state/blob namespaces
(`conversations`, `polls`, `delegated-tokens`, `pending-uploads`,
- Microsoft Teams conversations, polls, SSO tokens, and feedback learnings now
use SQLite plugin state namespaces (`conversations`, `polls`, `sso-tokens`,
`feedback-learnings`) instead of `msteams-conversations.json`,
`msteams-polls.json`, `msteams-delegated.json`,
`msteams-pending-uploads.json`, and `*.learnings.json`; the Microsoft Teams
doctor/setup migration imports and removes the legacy files.
`msteams-polls.json`, `msteams-sso-tokens.json`, and `*.learnings.json`; the
Microsoft Teams doctor/setup migration imports and archives the legacy files.
Pending uploads are a short-lived SQLite cache and old JSON cache files are
not migrated.
- Matrix sync cache, storage metadata, thread bindings, inbound dedupe markers,
startup verification cooldown state, credentials, recovery keys, and SDK
IndexedDB crypto snapshots now use SQLite plugin state/blob namespaces under
@@ -2191,8 +2191,6 @@ Add a repo check that fails new runtime writes to legacy state paths:
- Microsoft Teams `msteams-conversations.json`
- Microsoft Teams `msteams-polls.json`
- Microsoft Teams `msteams-sso-tokens.json`
- Microsoft Teams `msteams-delegated.json`
- Microsoft Teams `msteams-pending-uploads.json`
- Microsoft Teams `*.learnings.json`
- Matrix `bot-storage.json`
- Matrix `sync-store.json`

View File

@@ -24,6 +24,7 @@ title: "Tests"
- `pnpm test`: routes explicit file/directory targets through scoped Vitest lanes. Untargeted runs are full-suite proof: they use fixed shard groups, expand to leaf configs for local parallel execution, and print the expected local shard fanout before starting. The extension group always expands to the per-extension shard configs instead of one giant root-project process.
- Test wrapper runs end with a short `[test] passed|failed|skipped ... in ...` summary. Vitest's own duration line stays the per-shard detail.
- Shared OpenClaw test state: use `src/test-utils/openclaw-test-state.ts` from Vitest when a test needs an isolated `HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, config fixture, workspace, agent dir, or auth-profile store.
- `pnpm test:env-mutations:report`: non-blocking report of tests and harnesses that mutate `HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, `OPENCLAW_WORKSPACE_DIR`, or related OpenClaw env keys directly. Use it to find candidates for migration to the shared test-state helper.
- Control UI mocked E2E: use `pnpm test:ui:e2e` for the Vitest + Playwright lane that starts the Vite Control UI and drives a real Chromium page against a mocked Gateway WebSocket. Tests live in `ui/src/**/*.e2e.test.ts`; shared mocks and controls live in `ui/src/test-helpers/control-ui-e2e.ts`. `pnpm test:e2e` includes this lane. In Codex worktrees, prefer `node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/chat-flow.e2e.test.ts` for tiny targeted proof after dependencies are installed, or Testbox/Crabbox for broader GUI proof.
- Process E2E helpers: use `test/helpers/openclaw-test-instance.ts` when a Vitest process-level E2E test needs a running Gateway, CLI env, log capture, and cleanup in one place.
- TUI PTY tests: use `node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts` for the fast fake-backend PTY lane. Use `OPENCLAW_TUI_PTY_INCLUDE_LOCAL=1` or `pnpm tui:pty:test:watch --mode local` for the slower `tui --local` smoke, which mocks only the external model endpoint. Assert stable visible text or fixture calls, not raw ANSI snapshots.
@@ -48,7 +49,7 @@ title: "Tests"
- `pnpm test:e2e`: Runs the repo E2E aggregate: gateway end-to-end smoke tests plus the Control UI mocked browser E2E lane.
- `pnpm test:e2e:gateway`: Runs gateway end-to-end smoke tests (multi-instance WS/HTTP/node pairing). Defaults to `threads` + `isolate: false` with adaptive workers in `vitest.e2e.config.ts`; tune with `OPENCLAW_E2E_WORKERS=<n>` and set `OPENCLAW_E2E_VERBOSE=1` for verbose logs.
- `pnpm test:live`: Runs provider live tests (minimax/zai). Requires API keys and `LIVE=1` (or provider-specific `*_LIVE_TEST=1`) to unskip.
- `pnpm test:docker:all`: Builds the shared live-test image, packs OpenClaw once as an npm tarball, builds/reuses a bare Node/Git runner image plus a functional image that installs that tarball into `/app`, then runs Docker smoke lanes with `OPENCLAW_SKIP_DOCKER_BUILD=1` through a weighted scheduler. The bare image (`OPENCLAW_DOCKER_E2E_BARE_IMAGE`) is used for installer/update/plugin-dependency lanes; those lanes mount the prebuilt tarball instead of using copied repo sources. The functional image (`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`) is used for normal built-app functionality lanes. `scripts/package-openclaw-for-docker.mjs` is the single local/CI package packer and validates the tarball plus `dist/postinstall-inventory.json` before Docker consumes it. Docker lane definitions live in `scripts/lib/docker-e2e-scenarios.mjs`; planner logic lives in `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` executes the selected plan. `node scripts/test-docker-all.mjs --plan-json` emits the scheduler-owned CI plan for selected lanes, image kinds, package/live-image needs, state scenarios, and credential checks without building or running Docker. `OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` controls process slots and defaults to 10; `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` controls the provider-sensitive tail pool and defaults to 10. Heavy lane caps default to `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; provider caps default to one heavy lane per provider via `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4`, and `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4`. Use `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` or `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` for larger hosts. If one lane exceeds the effective weight or resource cap on a low-parallelism host, it can still start from an empty pool and will run alone until it releases capacity. Lane starts are staggered by 2 seconds by default to avoid local Docker daemon create storms; override with `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>`. The runner preflights Docker by default, cleans stale OpenClaw E2E containers, emits active-lane status every 30 seconds, shares provider CLI tool caches between compatible lanes, retries transient live-provider failures once by default (`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`), and stores lane timings in `.artifacts/docker-tests/lane-timings.json` for longest-first ordering on later runs. Use `OPENCLAW_DOCKER_ALL_DRY_RUN=1` to print the lane manifest without running Docker, `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>` to tune status output, or `OPENCLAW_DOCKER_ALL_TIMINGS=0` to disable timing reuse. Use `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip` for deterministic/local lanes only or `OPENCLAW_DOCKER_ALL_LIVE_MODE=only` for live-provider lanes only; package aliases are `pnpm test:docker:local:all` and `pnpm test:docker:live:all`. Live-only mode merges main and tail live lanes into one longest-first pool so provider buckets can pack Claude, Codex, and Gemini work together. The runner stops scheduling new pooled lanes after the first failure unless `OPENCLAW_DOCKER_ALL_FAIL_FAST=0` is set, and each lane has a 120-minute fallback timeout overridable with `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`; selected live/tail lanes use tighter per-lane caps. CLI backend Docker setup commands have their own timeout via `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS` (default 180). Per-lane logs, `summary.json`, `failures.json`, and phase timings are written under `.artifacts/docker-tests/<run-id>/`; use `pnpm test:docker:timings <summary.json>` to inspect slow lanes and `pnpm test:docker:rerun <run-id|summary.json|failures.json>` to print cheap targeted rerun commands.
- `pnpm test:docker:all`: Builds the shared live-test image, packs OpenClaw once as an npm tarball, builds/reuses a bare Node/Git runner image plus a functional image that installs that tarball into `/app`, then runs Docker smoke lanes with `OPENCLAW_SKIP_DOCKER_BUILD=1` through a weighted scheduler. The bare image (`OPENCLAW_DOCKER_E2E_BARE_IMAGE`) is used for installer/update/plugin-dependency lanes; those lanes mount the prebuilt tarball instead of using copied repo sources. The functional image (`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`) is used for normal built-app functionality lanes. `scripts/package-openclaw-for-docker.mjs` is the single local/CI package packer and validates the tarball plus `dist/postinstall-inventory.json` before Docker consumes it. Docker lane definitions live in `scripts/lib/docker-e2e-scenarios.mjs`; planner logic lives in `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` executes the selected plan. `node scripts/test-docker-all.mjs --plan-json` emits the scheduler-owned CI plan for selected lanes, image kinds, package/live-image needs, state scenarios, and credential checks without building or running Docker. `OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` controls process slots and defaults to 10; `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` controls the provider-sensitive tail pool and defaults to 10. Heavy lane caps default to `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=5`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; provider caps default to one heavy lane per provider via `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4`, and `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4`. Use `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` or `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` for larger hosts. If one lane exceeds the effective weight or resource cap on a low-parallelism host, it can still start from an empty pool and will run alone until it releases capacity. Lane starts are staggered by 2 seconds by default to avoid local Docker daemon create storms; override with `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>`. The runner preflights Docker by default, cleans stale OpenClaw E2E containers, emits active-lane status every 30 seconds, shares provider CLI tool caches between compatible lanes, retries transient live-provider failures once by default (`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`), and stores lane timings in `.artifacts/docker-tests/lane-timings.json` for longest-first ordering on later runs. Use `OPENCLAW_DOCKER_ALL_DRY_RUN=1` to print the lane manifest without running Docker, `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>` to tune status output, or `OPENCLAW_DOCKER_ALL_TIMINGS=0` to disable timing reuse. Use `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip` for deterministic/local lanes only or `OPENCLAW_DOCKER_ALL_LIVE_MODE=only` for live-provider lanes only; package aliases are `pnpm test:docker:local:all` and `pnpm test:docker:live:all`. Live-only mode merges main and tail live lanes into one longest-first pool so provider buckets can pack Claude, Codex, and Gemini work together. The runner stops scheduling new pooled lanes after the first failure unless `OPENCLAW_DOCKER_ALL_FAIL_FAST=0` is set, and each lane has a 120-minute fallback timeout overridable with `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`; selected live/tail lanes use tighter per-lane caps. CLI backend Docker setup commands have their own timeout via `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS` (default 180). Per-lane logs, `summary.json`, `failures.json`, and phase timings are written under `.artifacts/docker-tests/<run-id>/`; use `pnpm test:docker:timings <summary.json>` to inspect slow lanes and `pnpm test:docker:rerun <run-id|summary.json|failures.json>` to print cheap targeted rerun commands.
- `pnpm test:docker:browser-cdp-snapshot`: Builds a Chromium-backed source E2E container, starts raw CDP plus an isolated Gateway, runs `browser doctor --deep`, and verifies CDP role snapshots include link URLs, cursor-promoted clickables, iframe refs, and frame metadata.
- `pnpm test:docker:skill-install`: Installs the packed OpenClaw tarball in a bare Docker runner, disables `skills.install.allowUploadedArchives`, resolves a current skill slug from live ClawHub search, installs it through `openclaw skills install`, and verifies `SKILL.md`, `.clawhub/origin.json`, `.clawhub/lock.json`, and `skills info --json`.
- CLI backend live Docker probes can be run as focused lanes, for example `pnpm test:docker:live-cli-backend:claude`, `pnpm test:docker:live-cli-backend:claude:resume`, or `pnpm test:docker:live-cli-backend:claude:mcp`. Gemini has matching `:resume` and `:mcp` aliases.

View File

@@ -150,6 +150,13 @@ inter-session user turns that only have provenance metadata.
- Turn validation (merge consecutive user turns to satisfy strict alternation).
- Trailing assistant prefill turns are stripped from outgoing Anthropic Messages
payloads when thinking is enabled, including Cloudflare AI Gateway routes.
- Pre-compaction assistant thinking signatures are stripped before provider
replay when a session has been compacted. Thinking signatures are
cryptographically bound to the conversation prefix at generation time; after
compaction the prefix changes (summarized content is replaced by a compaction
summary), so replaying the original signatures causes Anthropic to reject the
request with "Invalid signature in thinking block". The thinking text is
preserved as an unsigned block and is then handled by the rule below.
- Thinking blocks with missing, empty, or blank replay signatures are stripped
before provider conversion. If that empties an assistant turn, OpenClaw keeps
turn shape with non-empty omitted-reasoning text.
@@ -165,6 +172,9 @@ inter-session user turns that only have provenance metadata.
repaired on disk before load.
- Assistant stream-error turns that contain only blank text blocks are dropped
from the in-memory replay copy instead of replaying an invalid blank block.
- Pre-compaction assistant thinking signatures are stripped before Converse
replay when a session has been compacted, for the same reason as Anthropic
above.
- Claude thinking blocks with missing, empty, or blank replay signatures are
stripped before Converse replay. If that empties an assistant turn, OpenClaw
keeps turn shape with non-empty omitted-reasoning text.

View File

@@ -51,7 +51,7 @@ For a complete map of the docs, see [Docs hubs](/start/hubs).
- [macOS app](/platforms/macos)
- [iOS app](/platforms/ios)
- [Android app](/platforms/android)
- [Windows (WSL2)](/platforms/windows)
- [Windows Hub](/platforms/windows)
- [Linux app](/platforms/linux)
## Operations and safety

View File

@@ -135,7 +135,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [macOS](/platforms/macos)
- [iOS](/platforms/ios)
- [Android](/platforms/android)
- [Windows (WSL2)](/platforms/windows)
- [Windows Hub](/platforms/windows)
- [Linux](/platforms/linux)
- [Web surfaces](/web)

View File

@@ -235,7 +235,7 @@ Logs live under `/tmp/openclaw/` (default: `openclaw-YYYY-MM-DD.log`).
- macOS menu bar companion: [OpenClaw macOS app](/platforms/macos)
- iOS node app: [iOS app](/platforms/ios)
- Android node app: [Android app](/platforms/android)
- Windows status: [Windows (WSL2)](/platforms/windows)
- Windows Hub: [Windows](/platforms/windows)
- Linux status: [Linux app](/platforms/linux)
- Security: [Security](/gateway/security)

View File

@@ -7,8 +7,9 @@ title: "Onboarding (CLI)"
sidebarTitle: "Onboarding: CLI"
---
CLI onboarding is the **recommended** way to set up OpenClaw on macOS,
Linux, or Windows (via WSL2; strongly recommended).
CLI onboarding is the **recommended** terminal setup path for OpenClaw on
macOS, Linux, or Windows. Windows desktop users can also start with
[Windows Hub](/platforms/windows).
It configures a local Gateway or a remote Gateway connection, plus channels, skills,
and workspace defaults in one guided flow.

View File

@@ -548,6 +548,11 @@ Two ways to start an ACP session:
requester session as system events. Accepted responses include
`streamLogPath` pointing to a session-scoped JSONL log
(`<sessionId>.acp-stream.jsonl`) you can tail for full relay history.
Parent progress streams show assistant commentary and ACP status progress by
default unless `streaming.progress.commentary=false`. Discord also defaults
parent previews to progress mode when no stream mode is configured. Status
progress still honors `acp.stream.tagVisibility`, so tags such as `plan`
remain hidden unless explicitly enabled.
</ParamField>
ACP `sessions_spawn` runs use `agents.defaults.subagents.runTimeoutSeconds` for

View File

@@ -1,3 +1,7 @@
/**
* ACPX runtime plugin entry. It registers the embedded ACP backend service and
* wires reply-dispatch hooks into the plugin SDK runtime.
*/
import { tryDispatchAcpReplyHook } from "openclaw/plugin-sdk/acp-runtime-backend";
import { createAcpxRuntimeService } from "./register.runtime.js";
import type { OpenClawPluginApi } from "./runtime-api.js";

View File

@@ -1,3 +1,7 @@
/**
* Lazy ACPX runtime service registration. The plugin exposes an ACP backend
* immediately, then imports the heavier service only when a session needs it.
*/
import {
getAcpRuntimeBackend,
registerAcpRuntimeBackend,
@@ -62,6 +66,7 @@ function createDeferredRuntime(state: DeferredServiceState): AcpRuntime {
return createLazyAcpRuntimeProxy(resolveRuntime);
}
/** Creates the plugin service that registers ACPX as an ACP runtime backend. */
export function createAcpxRuntimeService(
params: CreateAcpxRuntimeServiceParams = {},
): OpenClawPluginService {

View File

@@ -1,3 +1,7 @@
/**
* Public runtime API barrel for ACPX. Core and plugin consumers import these
* SDK-facing ACP runtime contracts instead of reaching into ACPX internals.
*/
export type { AcpRuntimeErrorCode } from "openclaw/plugin-sdk/acp-runtime-backend";
export {
AcpRuntimeError,

View File

@@ -1,3 +1,7 @@
/**
* ACPX setup plugin entry. It auto-enables setup when ACP config already points
* at the embedded ACPX runtime backend.
*/
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";

View File

@@ -1,3 +1,7 @@
/**
* Prepares isolated Codex and Claude ACP wrapper commands for ACPX. The bridge
* copies safe auth/config state into plugin-owned homes and redacts diagnostics.
*/
import fsSync from "node:fs";
import fs from "node:fs/promises";
import { createRequire } from "node:module";
@@ -724,6 +728,7 @@ function buildClaudeAcpWrapperCommand(wrapperPath: string, configuredCommand?: s
return configuredCommand?.trim() || buildWrapperCommand(wrapperPath);
}
/** Prepare ACPX agent commands and isolated auth homes for Codex/Claude adapters. */
export async function prepareAcpxCodexAuthConfig(params: {
pluginConfig: ResolvedAcpxPluginConfig;
stateDir: string;

View File

@@ -1,3 +1,7 @@
/**
* Builds isolated Codex config for ACPX sessions. It preserves safe inherited
* runtime options while rendering only trusted project entries for the session.
*/
import path from "node:path";
function stripTomlComment(line: string): string {
@@ -114,6 +118,7 @@ function parseTrustedInlineProjectEntries(value: string): string[] {
return trusted;
}
/** Extract trusted project paths from Codex TOML config. */
export function extractTrustedCodexProjectPaths(configToml: string): string[] {
const trusted = new Set<string>();
let currentProjectPath: string | undefined;
@@ -261,6 +266,7 @@ function extractInheritedCodexRuntimeConfig(configToml: string): string {
return inheritedLines.join("\n");
}
/** Render a session-local Codex config with inherited runtime settings and trust entries. */
export function renderIsolatedCodexConfig(params: {
sourceConfigToml?: string;
projectPaths: string[];
@@ -292,6 +298,7 @@ export function renderIsolatedCodexConfig(params: {
.join("\n");
}
/** Render only the project trust section for a session-local Codex config. */
export function renderIsolatedCodexProjectTrustConfig(projectPaths: string[]): string {
return renderIsolatedCodexConfig({ projectPaths });
}

View File

@@ -1,7 +1,13 @@
/**
* Small shell-command helpers for ACPX-launched processes. Splitting supports
* simple quoted command strings from config without invoking a shell parser.
*/
/** Quote one command argument for display or config serialization. */
export function quoteCommandPart(value: string): string {
return JSON.stringify(value);
}
/** Split a command string into argv-like parts using simple quote/backslash rules. */
export function splitCommandParts(value: string): string[] {
const parts: string[] = [];
let current = "";

View File

@@ -1,19 +1,28 @@
/**
* ACPX plugin configuration schema and public config types. Runtime setup uses
* this file as the single source of truth for validation and defaulting.
*/
import { z } from "zod";
const ACPX_PERMISSION_MODES = ["approve-all", "approve-reads", "deny-all"] as const;
/** Permission policy applied to interactive ACPX tool requests. */
export type AcpxPermissionMode = (typeof ACPX_PERMISSION_MODES)[number];
const ACPX_NON_INTERACTIVE_POLICIES = ["deny", "fail"] as const;
/** Permission policy applied when ACPX cannot ask a human for approval. */
export type AcpxNonInteractivePermissionPolicy = (typeof ACPX_NON_INTERACTIVE_POLICIES)[number];
/** Default session timeout for ACPX runtime turns. */
export const DEFAULT_ACPX_TIMEOUT_SECONDS = 120;
/** Raw MCP server command config accepted from plugin configuration. */
export type McpServerConfig = {
command: string;
args?: string[];
env?: Record<string, string>;
};
/** Normalized MCP server config emitted to the ACPX runtime process. */
export type AcpxMcpServer = {
name: string;
command: string;
@@ -21,6 +30,7 @@ export type AcpxMcpServer = {
env: Array<{ name: string; value: string }>;
};
/** User-provided ACPX plugin configuration before defaults are resolved. */
export type AcpxPluginConfig = {
cwd?: string;
stateDir?: string;
@@ -36,6 +46,7 @@ export type AcpxPluginConfig = {
agents?: Record<string, { command: string; args?: string[] }>;
};
/** Fully resolved ACPX config consumed by the runtime service. */
export type ResolvedAcpxPluginConfig = {
cwd: string;
stateDir: string;
@@ -76,6 +87,7 @@ const McpServerConfigSchema = z.object({
.describe("Environment variables for the MCP server"),
});
/** Zod schema for validating raw ACPX plugin config from OpenClaw config. */
export const AcpxPluginConfigSchema = z.strictObject({
cwd: nonEmptyTrimmedString("cwd must be a non-empty string").optional(),
stateDir: nonEmptyTrimmedString("stateDir must be a non-empty string").optional(),

View File

@@ -1,3 +1,7 @@
/**
* Resolves ACPX plugin config from raw user configuration. It locates the
* plugin root, injects optional MCP bridge servers, and applies runtime defaults.
*/
import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
@@ -80,6 +84,7 @@ function resolveAcpxPluginRootFromOpenClawLayout(moduleUrl: string): string | nu
}
return null;
}
/** Resolve the ACPX plugin root across source, dist, and dist-runtime layouts. */
export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): string {
const resolvedRoot = resolveNearestAcpxPluginRoot(moduleUrl);
// In a live repo checkout, dist/ can be rebuilt out from under the running gateway.
@@ -210,6 +215,7 @@ function resolveConfiguredMcpServers(params: {
return resolved;
}
/** Convert OpenClaw MCP server config into ACPX runtime MCP server entries. */
export function toAcpMcpServers(mcpServers: Record<string, McpServerConfig>): AcpxMcpServer[] {
return Object.entries(mcpServers).map(([name, server]) => ({
name,
@@ -222,6 +228,7 @@ export function toAcpMcpServers(mcpServers: Record<string, McpServerConfig>): Ac
}));
}
/** Validate and normalize raw ACPX plugin config for runtime startup. */
export function resolveAcpxPluginConfig(params: {
rawConfig: unknown;
workspaceDir?: string;

View File

@@ -1,15 +1,25 @@
/**
* Persistent lease store for ACPX wrapper processes. Leases let OpenClaw attach
* gateway/session identity to spawned ACP processes and clean them up later.
*/
import { randomUUID, createHash } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
/** Environment variable carrying the ACPX process lease id. */
export const OPENCLAW_ACPX_LEASE_ID_ENV = "OPENCLAW_ACPX_LEASE_ID";
/** Environment variable carrying the owning gateway instance id. */
export const OPENCLAW_GATEWAY_INSTANCE_ID_ENV = "OPENCLAW_GATEWAY_INSTANCE_ID";
/** CLI argument carrying the ACPX process lease id for platforms without env wrapping. */
export const OPENCLAW_ACPX_LEASE_ID_ARG = "--openclaw-acpx-lease-id";
/** CLI argument carrying the owning gateway instance id. */
export const OPENCLAW_GATEWAY_INSTANCE_ID_ARG = "--openclaw-gateway-instance-id";
/** Lifecycle state for a tracked ACPX wrapper process. */
export type AcpxProcessLeaseState = "open" | "closing" | "closed" | "lost";
/** Persisted identity and command metadata for one ACPX wrapper process. */
export type AcpxProcessLease = {
leaseId: string;
gatewayInstanceId: string;
@@ -23,6 +33,7 @@ export type AcpxProcessLease = {
state: AcpxProcessLeaseState;
};
/** Async lease store used by runtime sessions and cleanup routines. */
export type AcpxProcessLeaseStore = {
load(leaseId: string): Promise<AcpxProcessLease | undefined>;
listOpen(gatewayInstanceId?: string): Promise<AcpxProcessLease[]>;
@@ -84,6 +95,7 @@ function writeLeaseFile(filePath: string, value: LeaseFile): Promise<void> {
return writeJsonFileAtomically(filePath, value);
}
/** Create a serialized JSON-backed ACPX process lease store. */
export function createAcpxProcessLeaseStore(params: { stateDir: string }): AcpxProcessLeaseStore {
const filePath = path.join(params.stateDir, LEASE_FILE);
let updateQueue: Promise<void> = Promise.resolve();
@@ -135,10 +147,12 @@ export function createAcpxProcessLeaseStore(params: { stateDir: string }): AcpxP
};
}
/** Create a unique lease id for one ACPX wrapper process. */
export function createAcpxProcessLeaseId(): string {
return randomUUID();
}
/** Hash a wrapper command so process leases can detect command drift. */
export function hashAcpxProcessCommand(command: string): string {
return createHash("sha256").update(command).digest("hex");
}
@@ -161,6 +175,7 @@ function appendAcpxLeaseArgs(params: {
].join(" ");
}
/** Add ACPX lease identity to a command through env vars and portable args. */
export function withAcpxLeaseEnvironment(params: {
command: string;
leaseId: string;

View File

@@ -1,3 +1,7 @@
/**
* ACPX process ownership checks and cleanup. The reaper only terminates
* OpenClaw-owned wrapper trees after validating paths, packages, and lease ids.
*/
import { execFile } from "node:child_process";
import { createRequire } from "node:module";
import path from "node:path";
@@ -29,24 +33,28 @@ const ACP_PACKAGE_MARKERS = [
"/acpx/dist/",
];
/** Minimal process-table row used by ACPX cleanup. */
export type AcpxProcessInfo = {
pid: number;
ppid: number;
command: string;
};
/** Injectable process-listing and termination hooks for tests. */
export type AcpxProcessCleanupDeps = {
listProcesses?: () => Promise<AcpxProcessInfo[]>;
killProcess?: (pid: number, signal: NodeJS.Signals) => void;
sleep?: (ms: number) => Promise<void>;
};
/** Result from cleaning up a single ACPX process tree. */
export type AcpxProcessCleanupResult = {
inspectedPids: number[];
terminatedPids: number[];
skippedReason?: "missing-root" | "not-openclaw-owned" | "unverified-root";
};
/** Result from startup orphan reaping. */
export type AcpxStartupReapResult = {
inspectedPids: number[];
terminatedPids: number[];
@@ -109,6 +117,7 @@ function commandWrapperBelongsToRoot(command: string, wrapperRoot: string | unde
);
}
/** Check whether a command references an OpenClaw-generated ACPX wrapper path. */
export function isOpenClawLeaseAwareAcpxProcessCommand(params: {
command: string | undefined;
wrapperRoot?: string;
@@ -158,6 +167,7 @@ function liveCommandMatchesLeaseIdentity(params: {
);
}
/** Check whether a command is owned by OpenClaw ACPX runtime packages or wrappers. */
export function isOpenClawOwnedAcpxProcessCommand(params: {
command: string | undefined;
wrapperRoot?: string;
@@ -200,6 +210,7 @@ function parseProcessList(stdout: string): AcpxProcessInfo[] {
return processes;
}
/** List host processes in the compact shape needed by ACPX cleanup. */
export async function listPlatformProcesses(): Promise<AcpxProcessInfo[]> {
if (process.platform === "win32") {
return [];
@@ -294,6 +305,7 @@ async function terminatePids(
return terminated;
}
/** Terminate one validated OpenClaw-owned ACPX wrapper process tree. */
export async function cleanupOpenClawOwnedAcpxProcessTree(params: {
rootPid?: number;
rootCommand?: string;
@@ -378,6 +390,7 @@ export async function cleanupOpenClawOwnedAcpxProcessTree(params: {
};
}
/** Reap orphaned OpenClaw-owned ACPX wrapper trees during runtime startup. */
export async function reapStaleOpenClawOwnedAcpxOrphans(params: {
wrapperRoot: string;
deps?: AcpxProcessCleanupDeps;

View File

@@ -1,3 +1,7 @@
/**
* Command-line parser for ACPX MCP proxy targets. It handles simple quoting and
* Windows executable paths before spawning the configured MCP target.
*/
const WINDOWS_DIRECT_EXECUTABLE_PATH_RE =
/^(?<command>(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/]).*?\.(?:exe|com))(?=\s|$)(?:\s+(?<rest>.*))?$/i;
@@ -106,6 +110,7 @@ function assertSupportedWindowsCommand(command, platform = process.platform) {
);
}
/** Split a configured command string into `{ command, args }` for child_process.spawn. */
export function splitCommandLine(value, platform = process.platform) {
const windowsCommand = splitWindowsExecutableCommand(value, platform);
const parts = windowsCommand ?? splitCommandParts(value, platform);

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env node
/**
* Stdio MCP proxy used by ACPX wrappers. It injects OpenClaw-provided MCP
* servers into session creation/load/fork requests before forwarding to target.
*/
import { spawn } from "node:child_process";
import path from "node:path";
import { createInterface } from "node:readline";
@@ -70,6 +74,7 @@ function rewriteLine(line, mcpServers) {
}
}
/** Build spawn options for the proxied MCP target process. */
export function createTargetSpawnOptions(platform = process.platform) {
const options = {
stdio: ["pipe", "pipe", "inherit"],

View File

@@ -1,6 +1,11 @@
/**
* Lazy ACP runtime proxy for ACPX. It defers resolving the real runtime until
* the first ACP call while preserving the SDK runtime shape.
*/
import type { AcpRuntime } from "../runtime-api.js";
import { lazyStartRuntimeTurn } from "./runtime-turn.js";
/** Create an ACP runtime facade backed by an async runtime resolver. */
export function createLazyAcpRuntimeProxy<T extends AcpRuntime>(
resolveRuntime: () => Promise<T>,
): AcpRuntime {

View File

@@ -1,3 +1,7 @@
/**
* ACPX turn adapters. Modern runtimes can expose startTurn directly; legacy
* runtimes that only stream runTurn events are adapted to the newer contract.
*/
import type {
AcpRuntime,
AcpRuntimeEvent,
@@ -153,10 +157,12 @@ function legacyRunTurnAsStartTurn(runtime: AcpRuntime, input: AcpRuntimeTurnInpu
};
}
/** Start an ACP turn, adapting legacy runTurn-only runtimes when needed. */
export function startRuntimeTurn(runtime: AcpRuntime, input: AcpRuntimeTurnInput): AcpRuntimeTurn {
return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
}
/** Start an ACP turn through a lazy runtime resolver. */
export function lazyStartRuntimeTurn(
resolveRuntime: () => Promise<AcpRuntime>,
input: AcpRuntimeTurnInput,

View File

@@ -1,3 +1,7 @@
/**
* OpenClaw ACPX runtime adapter. It wraps the upstream acpx runtime with
* OpenClaw session metadata, lease tracking, model scoping, and cleanup policy.
*/
import { AsyncLocalStorage } from "node:async_hooks";
import fs from "node:fs/promises";
import path, { resolve as resolvePath } from "node:path";
@@ -635,6 +639,7 @@ function shouldUseDistinctBridgeDelegate(options: AcpRuntimeOptions): boolean {
return Array.isArray(mcpServers) && mcpServers.length > 0;
}
/** OpenClaw-managed ACP runtime implementation backed by the upstream acpx runtime. */
export class AcpxRuntime implements AcpRuntime {
private readonly sessionStore: ResetAwareSessionStore;
private readonly agentRegistry: AcpAgentRegistry;
@@ -1235,6 +1240,7 @@ export {
encodeAcpxRuntimeHandleState,
};
/** Test-only hooks for ACPX runtime behavior that is otherwise private. */
export const testing = {
appendCodexAcpConfigOverrides,
assertSupportedRuntimeSessionMode,

View File

@@ -1,3 +1,7 @@
/**
* ACPX plugin service lifecycle. It resolves config, prepares isolated adapter
* wrappers, registers the ACP backend, and manages startup/cleanup probes.
*/
import { randomUUID } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
@@ -61,6 +65,7 @@ function loadRuntimeModule(): Promise<AcpxRuntimeModule> {
return runtimeModulePromise;
}
/** Convert ACPX timeout seconds into timer-safe milliseconds. */
export function resolveAcpxTimerTimeoutMs(timeoutSeconds: number | undefined): number | undefined {
if (timeoutSeconds === undefined) {
return undefined;
@@ -295,6 +300,7 @@ async function reapOpenAcpxProcessLeases(params: {
return { inspectedPids, terminatedPids };
}
/** Create the ACPX plugin service that owns runtime registration and cleanup. */
export function createAcpxRuntimeService(
params: CreateAcpxRuntimeServiceParams = {},
): OpenClawPluginService {

View File

@@ -1,3 +1,7 @@
/**
* Doctor migration contract for Active Memory state. It moves legacy per-session
* toggle JSON into the plugin state keyed store used by current runtimes.
*/
import crypto from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
@@ -81,6 +85,7 @@ async function archiveLegacySource(params: {
}
}
/** State migrations exposed to OpenClaw doctor for Active Memory. */
export const stateMigrations: PluginDoctorStateMigration[] = [
{
id: "active-memory-session-toggles-json-to-plugin-state",

View File

@@ -1,3 +1,7 @@
/**
* Active Memory plugin entry and runtime implementation. It recalls recent
* memory context through configured agents and injects bounded context snippets.
*/
import crypto from "node:crypto";
import fsSync from "node:fs";
import fs from "node:fs/promises";
@@ -2861,6 +2865,7 @@ async function maybeResolveActiveRecall(params: {
}
}
/** Plugin entry registering Active Memory hooks, tools, config schema, and doctor cleanup. */
export default definePluginEntry({
id: "active-memory",
name: "Active Memory",

View File

@@ -1,3 +1,7 @@
/**
* Admin HTTP RPC plugin entry. It exposes a trusted gateway-authenticated HTTP
* endpoint for the explicit admin method allowlist.
*/
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { handleAdminHttpRpcRequest } from "./src/handler.js";

View File

@@ -1,3 +1,7 @@
/**
* HTTP handler for the Admin RPC endpoint. It validates JSON requests, enforces
* the method allowlist, dispatches gateway methods, and maps errors to HTTP.
*/
import { randomUUID } from "node:crypto";
import type { IncomingMessage, ServerResponse } from "node:http";
import { dispatchGatewayMethod } from "openclaw/plugin-sdk/gateway-method-runtime";
@@ -184,6 +188,7 @@ async function dispatchAdminRpc(request: ParsedRequest): Promise<RpcResponse> {
}
}
/** Handle one gateway-authenticated Admin HTTP RPC request. */
export async function handleAdminHttpRpcRequest(
req: IncomingMessage,
res: ServerResponse,

View File

@@ -1,3 +1,7 @@
/**
* Method allowlist for Admin HTTP RPC. Only methods listed here can cross the
* trusted operator HTTP surface.
*/
const ADMIN_HTTP_RPC_ALLOWED_METHOD_GROUPS = {
gateway: [
"health",
@@ -54,10 +58,12 @@ const ADMIN_HTTP_RPC_ALLOWED_METHODS: ReadonlySet<string> = new Set(
Object.values(ADMIN_HTTP_RPC_ALLOWED_METHOD_GROUPS).flat(),
);
/** Return whether an admin RPC method is exposed over HTTP. */
export function isAdminHttpRpcAllowedMethod(method: string): boolean {
return ADMIN_HTTP_RPC_ALLOWED_METHODS.has(method);
}
/** List all admin RPC methods exposed over HTTP. */
export function listAdminHttpRpcAllowedMethods(): string[] {
return Array.from(ADMIN_HTTP_RPC_ALLOWED_METHODS);
}

View File

@@ -1,3 +1,7 @@
/**
* Alibaba Model Studio plugin entry. Registers the DashScope-backed video
* generation provider.
*/
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { buildAlibabaVideoGenerationProvider } from "./video-generation-provider.js";

View File

@@ -1,3 +1,7 @@
/**
* Alibaba Model Studio video provider adapter. It resolves DashScope auth and
* HTTP policy before delegating task polling to the shared video helper.
*/
import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth";
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
import { resolveProviderHttpRequestConfig } from "openclaw/plugin-sdk/provider-http";
@@ -25,6 +29,7 @@ function resolveDashscopeAigcApiBaseUrl(baseUrl: string): string {
return baseUrl.replace(/\/+$/u, "");
}
/** Build the Alibaba/DashScope video generation provider descriptor. */
export function buildAlibabaVideoGenerationProvider(): VideoGenerationProvider {
return {
id: "alibaba",

View File

@@ -1,3 +1,7 @@
/**
* Public Amazon Bedrock Mantle API barrel for discovery and bearer-token
* helpers shared by config, runtime, and tests.
*/
export {
discoverMantleModels,
generateBearerTokenFromIam,

View File

@@ -1,3 +1,7 @@
/**
* Amazon Bedrock Mantle discovery and bearer-token handling. It resolves
* explicit tokens, IAM-generated tokens, model catalogs, and implicit provider config.
*/
import { createSubsystemLogger } from "openclaw/plugin-sdk/core";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import {
@@ -22,6 +26,7 @@ const DEFAULT_COST = {
const DEFAULT_CONTEXT_WINDOW = 32000;
const DEFAULT_MAX_TOKENS = 4096;
const DEFAULT_REFRESH_INTERVAL_SECONDS = 3600; // 1 hour
/** Config auth marker meaning Mantle should mint runtime bearer tokens from IAM. */
export const MANTLE_IAM_TOKEN_MARKER = "__amazon_bedrock_mantle_iam__";
// ---------------------------------------------------------------------------
@@ -152,6 +157,7 @@ export function getCachedIamToken(region: string): string | undefined {
return getCachedIamTokenEntry(region)?.token;
}
/** Resolve the actual runtime bearer token for Mantle, generating IAM tokens when needed. */
export async function resolveMantleRuntimeBearerToken(params: {
apiKey: string;
env?: NodeJS.ProcessEnv;
@@ -186,7 +192,7 @@ export async function resolveMantleRuntimeBearerToken(params: {
...(expiresAt === undefined ? {} : { expiresAt }),
};
}
/** Reset the IAM token cache (for testing). */
/** Clear the IAM token cache for tests. */
export function resetIamTokenCacheForTest(): void {
iamTokenCache.clear();
}
@@ -241,7 +247,7 @@ type MantleDiscoveryConfig = {
const discoveryCache = new Map<string, MantleCacheEntry>();
/** Clear the discovery cache (for testing). */
/** Clear the Mantle discovery cache for tests. */
export function resetMantleDiscoveryCacheForTest(): void {
discoveryCache.clear();
}
@@ -261,6 +267,7 @@ export function resetMantleDiscoveryCacheForTest(): void {
* Results are cached per region for `DEFAULT_REFRESH_INTERVAL_SECONDS`.
* Returns an empty array if the request fails (no permission, network error, etc.).
*/
/** Discover Mantle models for one region/config. */
export async function discoverMantleModels(params: {
region: string;
bearerToken: string;
@@ -334,6 +341,7 @@ export async function discoverMantleModels(params: {
* - Region from AWS_REGION / AWS_DEFAULT_REGION / default us-east-1
* - Models discovered from `/v1/models`
*/
/** Resolve implicit Mantle provider config from env, IAM token support, and discovery. */
export async function resolveImplicitMantleProvider(params: {
env?: NodeJS.ProcessEnv;
pluginConfig?: { discovery?: MantleDiscoveryConfig };
@@ -408,6 +416,7 @@ export async function resolveImplicitMantleProvider(params: {
};
}
/** Merge an implicit Mantle provider catalog with explicit user config. */
export function mergeImplicitMantleProvider(params: {
existing: ModelProviderConfig | undefined;
implicit: ModelProviderConfig;

View File

@@ -1,3 +1,7 @@
/**
* Amazon Bedrock Mantle plugin entry. Registers the OpenAI-compatible Mantle
* provider plus Anthropic stream compatibility hooks.
*/
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { registerBedrockMantlePlugin } from "./register.sync.runtime.js";

View File

@@ -1,3 +1,7 @@
/**
* Anthropic Messages stream adapter for Bedrock Mantle. It rewrites Mantle
* endpoints to Anthropic-compatible URLs and adjusts thinking-token budgets.
*/
import Anthropic from "@anthropic-ai/sdk";
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
import { stream, type Model, type SimpleStreamOptions } from "openclaw/plugin-sdk/llm";
@@ -7,6 +11,7 @@ type AnthropicOptions = ConstructorParameters<typeof Anthropic>[0];
type MantleAnthropicStream = typeof stream;
type AnthropicStreamClient = Anthropic;
/** Resolve the Anthropic-compatible Mantle base URL from a provider base URL. */
export function resolveMantleAnthropicBaseUrl(baseUrl: string): string {
const trimmed = baseUrl.replace(/\/+$/, "");
if (trimmed.endsWith("/anthropic")) {
@@ -76,6 +81,7 @@ function adjustMaxTokensForThinking(
return { maxTokens, thinkingBudget };
}
/** Create the Mantle Anthropic Messages stream function. */
export function createMantleAnthropicStreamFn(deps?: {
createClient?: (options: AnthropicOptions) => Anthropic;
stream?: MantleAnthropicStream;

View File

@@ -1,3 +1,7 @@
/**
* Synchronous Amazon Bedrock Mantle provider registration. It wires discovery,
* runtime bearer-token preparation, stream wrappers, and failover classifiers.
*/
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
@@ -15,6 +19,7 @@ type BedrockMantlePluginConfig = {
};
};
/** Register the Amazon Bedrock Mantle provider with OpenClaw. */
export function registerBedrockMantlePlugin(api: OpenClawPluginApi): void {
const providerId = "amazon-bedrock-mantle";
const startupPluginConfig = (api.pluginConfig ?? {}) as BedrockMantlePluginConfig;

View File

@@ -1,3 +1,7 @@
/**
* Lightweight Amazon Bedrock API barrel for config and discovery consumers.
* Keep runtime streaming exports out of this path so metadata flows stay cheap.
*/
export { mergeImplicitBedrockProvider, resolveBedrockConfigApiKey } from "./discovery-shared.js";
export {
discoverBedrockModels,

View File

@@ -1,3 +1,7 @@
/**
* AWS shared config cache refresh helpers for Bedrock. They nudge the AWS SDK
* to re-read profile/SSO config when no static credentials are present.
*/
type SharedIniFileLoader = {
loadSharedConfigFiles(init?: { ignoreCache?: boolean }): Promise<unknown>;
};
@@ -8,6 +12,7 @@ function hasStaticAwsCredentialEnv(env: NodeJS.ProcessEnv): boolean {
return Boolean(env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY);
}
/** Return whether Bedrock should refresh the AWS shared config cache before discovery. */
export function shouldRefreshAwsSharedConfigCacheForBedrock(env: NodeJS.ProcessEnv): boolean {
if (env.AWS_BEDROCK_SKIP_AUTH === "1" || env.AWS_BEARER_TOKEN_BEDROCK) {
return false;
@@ -25,6 +30,7 @@ async function loadSharedIniFileLoader(): Promise<SharedIniFileLoader> {
return (await import("@smithy/shared-ini-file-loader")) as SharedIniFileLoader;
}
/** Refresh Smithy shared config files when Bedrock needs default-chain credentials. */
export async function refreshAwsSharedConfigCacheForBedrock(
env: NodeJS.ProcessEnv = process.env,
): Promise<void> {
@@ -35,6 +41,7 @@ export async function refreshAwsSharedConfigCacheForBedrock(
await loader.loadSharedConfigFiles({ ignoreCache: true });
}
/** Override the shared INI loader for Bedrock credential-refresh tests. */
export function setAwsSharedIniFileLoaderForTest(
loader: SharedIniFileLoader | null | undefined,
): void {

View File

@@ -1,7 +1,13 @@
/**
* Stream option extensions and prompt-cache policy for Amazon Bedrock models.
* Provider registration and runtime streaming share these contracts.
*/
import type { StreamOptions, ThinkingBudgets, ThinkingLevel } from "openclaw/plugin-sdk/llm";
/** How Bedrock thinking output should be displayed to users. */
export type BedrockThinkingDisplay = "summarized" | "omitted";
/** Extra Bedrock-specific stream options accepted by the provider runtime. */
export interface BedrockOptions extends StreamOptions {
region?: string;
profile?: string;
@@ -22,6 +28,7 @@ function getModelMatchCandidates(modelId: string, modelName?: string): string[]
});
}
/** Return whether a Bedrock model is known to support Anthropic prompt caching. */
export function supportsBedrockPromptCaching(modelId: string, modelName?: string): boolean {
const candidates = getModelMatchCandidates(modelId, modelName);
const hasClaudeRef = candidates.some((s) => s.includes("claude"));

View File

@@ -1,4 +1,5 @@
// Narrow barrel for config compatibility helpers consumed outside the plugin.
// Keep this separate from runtime exports so doctor/config code stays lightweight.
/**
* Narrow config compatibility barrel for Amazon Bedrock. Doctor/config code can
* import this without loading runtime provider dependencies.
*/
export { migrateAmazonBedrockLegacyConfig } from "./config-compat.js";

Some files were not shown because too many files have changed in this diff Show More