Compare commits

..

1228 Commits

Author SHA1 Message Date
Gustavo Madeira Santana
e6d8ea9ca7 fix(zoom): harden browser join teardown 2026-04-30 12:15:13 -04:00
Gustavo Madeira Santana
af2de5cb37 feat(zoom): add participant name config 2026-04-30 12:15:13 -04:00
Gustavo Madeira Santana
c99c20ec91 docs(zoom): document native speech setup 2026-04-30 12:15:12 -04:00
Gustavo Madeira Santana
15f16690c2 feat(zoom): add browser conversation plugin 2026-04-30 12:15:06 -04:00
Logan Ye
adc20fed0d fix: guard blank prompt submissions (#74168)
Fixes #74137.\n\nThanks @yelog.
2026-04-30 16:48:46 +01:00
Peter Steinberger
46888f5afb test(gateway): align lock conflict success expectation 2026-04-30 16:39:12 +01:00
Peter Steinberger
1a2228d291 fix: align tool-result guard budget 2026-04-30 16:36:55 +01:00
NVIDIAN
797d574dfd fix(deepseek): expose V4 max thinking levels (#73008)
Merged via squash.

Prepared head SHA: ef561a59de
Co-authored-by: ai-hpc <183861985+ai-hpc@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-30 23:34:05 +08:00
konanok
0eb8f34000 refactor(usage): add precise token buckets for Usage Mosaic (#74337)
Merged via squash.

Prepared head SHA: 15185354c4
Co-authored-by: konanok <30515586+konanok@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-30 23:32:34 +08:00
Peter Steinberger
9289a502bb fix(gateway): stop systemd EADDRINUSE restart loops 2026-04-30 16:30:56 +01:00
Peter Steinberger
de1ac12f1c fix: keep telegram polling timeout above long poll 2026-04-30 16:11:42 +01:00
Vincent Koc
d6e568ec95 docs(changelog): backfill b85147ff76 mid-turn compaction precheck 2026-04-30 08:07:57 -07:00
Peter Steinberger
32d429e647 test(signal): cover inbound prompt body contract 2026-04-30 16:06:37 +01:00
marchpure
b85147ff76 feat(agents): add mid-turn compaction precheck (#73499)
Co-authored-by: haoxingjun <haoxingjun@bytedance.com>
2026-04-30 23:05:31 +08:00
Peter Steinberger
b743506549 fix: reduce runtime mirror and signal group regressions 2026-04-30 15:59:03 +01:00
Peter Steinberger
29a35f04a9 fix(browser): use source config for proxy decisions 2026-04-30 15:56:49 +01:00
Peter Steinberger
eb8e892df9 fix(plugins): harden runtime mirrors 2026-04-30 15:56:08 +01:00
Peter Steinberger
a3228977fb test(signal): cover group mention gating defaults 2026-04-30 15:53:09 +01:00
Peter Steinberger
b40c679630 fix(signal): match group allowlists against group ids 2026-04-30 15:49:44 +01:00
Peter Steinberger
65c94df872 test(infra): cover fallback tmp chmod race 2026-04-30 15:45:58 +01:00
Peter Steinberger
165d62b15f fix(infra): tolerate concurrent tmp dir repair 2026-04-30 15:45:57 +01:00
Peter Steinberger
11a56db5c1 docs(changelog): credit refresh guard contributors 2026-04-30 15:45:45 +01:00
Peter Steinberger
c5bc4b6892 fix: repair telegram transcript echo routing 2026-04-30 15:39:33 +01:00
Peter Steinberger
cf772079c6 fix(browser): share control runtime state 2026-04-30 15:35:42 +01:00
Peter Steinberger
44ad65f02b fix(signal): harden signal-cli installer downloads 2026-04-30 15:34:37 +01:00
Peter Steinberger
8291537710 fix(auto-reply): preserve visible fallback for requested modes 2026-04-30 15:26:55 +01:00
Peter Steinberger
ac599c9e53 fix: retain local memory runtime deps 2026-04-30 15:22:26 +01:00
Peter Steinberger
9d037d2f5a docs(changelog): note Signal regression fixes 2026-04-30 15:14:26 +01:00
Peter Steinberger
3b0ed18b86 fix(signal): handle attachment and SSE regressions 2026-04-30 15:14:26 +01:00
Peter Steinberger
4e168de6d9 fix: avoid provider policy runtime deps 2026-04-30 15:13:35 +01:00
Peter Steinberger
98b96182f8 test(gateway): cover web fetch startup bind 2026-04-30 14:59:30 +01:00
Peter Steinberger
2a54427aba fix(plugins): keep runtime deps manifest complete
Co-authored-by: HCL <chenglunhu@gmail.com>
2026-04-30 14:55:40 +01:00
Peter Steinberger
82ca6ecdde fix(auto-reply): surface private group replies 2026-04-30 14:54:34 +01:00
Peter Steinberger
8b665e0d70 fix(slack): gate bot room relays on owner presence 2026-04-30 14:46:31 +01:00
Peter Steinberger
afb17eade9 fix(secrets): skip optional web fetch discovery before bind 2026-04-30 14:45:55 +01:00
Peter Steinberger
3766bbb674 fix(models): restore codex mini oauth route 2026-04-30 14:43:39 +01:00
Peter Steinberger
0f120c09ba fix(agents): bound subagent orphan recovery 2026-04-30 14:43:18 +01:00
Vincent Koc
f3145f6db8 fix(telegram): remove unused draft stream helper 2026-04-30 06:19:08 -07:00
Vincent Koc
ad7fa6c387 docs(tools): note explicit alsoAllow needed under restrictive profiles (4aa08e9d79) 2026-04-30 05:38:28 -07:00
Ayaan Zaidi
823f13c6e4 fix: remove Telegram native draft previews (#75073) 2026-04-30 18:07:57 +05:30
Ayaan Zaidi
565f4314fe docs(telegram): remove native draft fallback note 2026-04-30 18:07:57 +05:30
Ayaan Zaidi
c9d9067931 test(telegram): cover message-only previews 2026-04-30 18:07:57 +05:30
Ayaan Zaidi
2a4dd89253 fix(telegram): remove native draft preview transport 2026-04-30 18:07:57 +05:30
Alex Knight
4aa08e9d79 fix(security): stop implicit tool grants from config sections (#47487) (#75055)
* fix(security): stop implicit tool grants from config sections (#47487)

Configured tool sections (tools.exec, tools.fs) no longer implicitly
widen restrictive profiles (messaging, minimal). Previously, having a
tools.exec section anywhere in config — even just safety settings like
security: "allowlist" — would automatically add exec and process to the
profile's allowed tools, defeating the purpose of the restrictive
profile.

The same pattern existed in tool-fs-policy.ts where tools.fs presence
would add read/write/edit to the profile allowlist for root expansion.

Changes:
- pi-tools.policy.ts: Stop merging implicit grants into profileAlsoAllow.
  Renamed resolveImplicitProfileAlsoAllow → detectImplicitProfileGrants
  and use it only for a startup warning that tells users to add explicit
  alsoAllow entries.
- tool-fs-policy.ts: Remove the implicit read/write/edit grant from
  resolveEffectiveToolFsRootExpansionAllowed when tools.fs is present.
  Root expansion now requires actual read access via profile or alsoAllow.
- Updated 4 existing tests and added 3 new regression tests.

Migration: users who relied on tools.exec or tools.fs implicitly granting
access under a restrictive profile should add explicit alsoAllow entries:

  tools:
    profile: "messaging"
    alsoAllow: ["exec", "process"]  # was implicit, now required
    exec: { security: "allowlist" }

Fixes #47487

* fix: address tool policy review feedback
2026-04-30 22:19:26 +10:00
Nimrod Gutman
58a0b077c1 fix(macos): keep A2UI canvas content visible (#75039) 2026-04-30 14:21:06 +03:00
Nimrod Gutman
eecd758e39 fix(macos): repair stale gateway tls pins (#75038)
Merged via squash.

Prepared head SHA: 35196f8f71
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-04-30 14:14:03 +03:00
clawsweeper[bot]
29d3b65a83 fix(ci): bound manual stale closure backfill
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-30 03:52:23 -07:00
Radek Sienkiewicz
52e2d4e16a fix(cli): avoid progress spinners in active TUI input (#75003)
Merged via squash.

Prepared head SHA: 129e23e716
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
2026-04-30 12:31:05 +02:00
Vincent Koc
9cb71f7672 chore(barnacle): add false positive close label (#75014) 2026-04-30 02:55:45 -07:00
Val Alexander
20cbc1f216 fix(control-ui): wire slash menu accessibility
Wire the Control UI chat slash-command menu to the composer with stable listbox and option IDs, active-descendant updates, and a live status announcement. Keep the native textarea role conforming while preserving the menu relationships and tests.
2026-04-30 04:53:27 -05:00
clawsweeper[bot]
099037cca6 fix(channels): align Yuanbao catalog id
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-30 02:50:35 -07:00
Vincent Koc
9d68c6768a ci: shallow checkout OpenGrep PR scan 2026-04-30 02:43:00 -07:00
Vincent Koc
9f0bf1c71e chore(ci): skip maintainer assignees in stale backfill 2026-04-30 02:13:18 -07:00
Vincent Koc
d117ed183a chore(ci): tune stale policy and add backfill
* chore(ci): tune stale grace periods

* chore(ci): add stale closure backfill
2026-04-30 02:01:02 -07:00
Vincent Koc
005eeca06f ci: right-size OpenGrep PR scan
* ci: right-size opengrep pr scan

* ci: avoid opengrep rulepack self-scan

* ci: opt opengrep workflows into node24 actions

* ci: update opengrep workflow action majors
2026-04-30 01:52:12 -07:00
Vincent Koc
d50ad19e4b test(gateway): avoid post-close auth rotation rpc 2026-04-30 01:50:39 -07:00
Vincent Koc
62be4eb21e docs: cover qqbot /bot-me + c2cOnly admin gating (62fb87641e) and cron add --agent warning (dc0c54c7f1) 2026-04-30 01:39:13 -07:00
clawsweeper[bot]
9061d1e4c3 fix(agents): preserve string user content when merging turns
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-30 01:27:57 -07:00
clawsweeper[bot]
e20147a1b6 fix: warning text cli correctness issue (#74964)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-30 01:26:01 -07:00
cxy
62fb87641e fix(qqbot): unify slash command auth, c2cOnly gating, and file delivery (#73616)
* fix(qqbot): align clear-storage command with actual downloads directory

The /bot-clear-storage command previously targeted
~/.openclaw/media/qqbot/downloads/{appId}/, but inbound attachments
and outbound fallback downloads are stored directly under
~/.openclaw/media/qqbot/downloads/ without appId subdivision.

This mismatch caused the clear command to report 'no files to clean'
while downloaded files continued to occupy disk space.

Changes:
- Replace resolveQqbotDownloadsDirForApp(appId) with
  resolveQqbotDownloadsDir() that returns the downloads root
- Use getQQBotMediaPath('downloads') instead of manual path assembly
- Remove appId-based path validation (no longer needed)
- Update usage text to reflect the new scope

* refactor(qqbot): unify slash command auth and c2cOnly gating in registry

Previously, slash command authorization and group-chat rejection were
scattered across individual handlers and a hardcoded GROUP_EXCLUDED set.
This led to inconsistent behavior: commandAuthorized was hardcoded to
true in the pre-dispatch path, some handlers checked allowFrom while
others did not, and group users received no response for auth-gated
commands.

Changes:

1. Add resolveSlashCommandAuth() (new file slash-command-auth.ts)
   - Requires sender to appear in an explicit non-wildcard allowFrom
     list; wildcard ['*'] does not grant admin command access
   - Group messages use groupAllowFrom, falling back to allowFrom

2. Fix commandAuthorized in slash-command-handler.ts
   - Replace hardcoded 'true' with resolveSlashCommandAuth() call

3. Add c2cOnly field to SlashCommand interface
   - Commands declare c2cOnly: true instead of checking ctx.type
     inside their handler
   - Registry rejects c2cOnly commands in group chat before auth
     check, returning a user-friendly hint

4. Remove GROUP_EXCLUDED hardcoded set from register-basic.ts
   - /bot-help now filters by cmd.c2cOnly dynamically

5. Clean up handler-level auth and scene checks
   - Remove hasExplicitCommandAllowlist check from register-logs
   - Remove ctx.type !== 'c2c' guards from all c2cOnly handlers
   - Improve rejection message to mention the correct config field
     (allowFrom for c2c, groupAllowFrom for group)

6. Mark commands: bot-upgrade, bot-streaming, bot-logs,
   bot-clear-storage, bot-approve as c2cOnly: true

* fix(qqbot): pass allowQQBotDataDownloads when sending slash command file attachments

The /bot-logs command writes temporary log files to the QQBot data
downloads directory (~/.openclaw/qqbot/downloads/), but sendDocument
was called without allowQQBotDataDownloads: true. This caused
resolveOutboundMediaPath to reject the file path as outside the
allowed media roots, silently failing the file attachment while
the text reply was sent successfully.

Add { allowQQBotDataDownloads: true } to the sendDocument call in
slash-command-handler.ts so file-bearing slash command results
(currently only /bot-logs) can deliver their attachments.

* feat(qqbot): add /bot-me command to display sender user ID

Add a new /bot-me slash command that returns the sender's user ID
(openid). This helps users quickly find the value they need to add
to allowFrom or groupAllowFrom configuration for admin command
access.

Marked as c2cOnly since the user ID is sensitive information.

* feat(qqbot): update response timeout

* feat(qqbot): add engine import boundary test and bump version

- Add engine-import-boundary.test.ts to enforce that engine/ sources
  only import from openclaw/plugin-sdk/* and never reach into other
  openclaw internals directly. Scans all 110 source files recursively.
- Bump plugin version to 2026.4.27.

* fix(qqbot): unify slash command auth, c2cOnly gating, and file delivery (#73616) (thanks @cxyhhhhh)

---------

Co-authored-by: sliverp <870080352@qq.com>
2026-04-30 16:12:39 +08:00
Vincent Koc
30d9777b3f docs(changelog): backfill 1e20babcf7 memory-lancedb ltm list 2026-04-30 01:11:08 -07:00
Vincent Koc
092321dc9e fix(github): skip maintainer-owned Barnacle targets 2026-04-30 01:10:52 -07:00
Vincent Koc
f31311d104 fix(security): align QQBot log sanitizer with CodeQL
Aligns QQBot debug log newline removal with the CodeQL js/log-injection sanitizer model to close alert 232.
2026-04-30 01:10:26 -07:00
loongfay
914287642d feat(channel) update yuanbao plugin github location (#74253)
* feat(channel) update yuanbao plugin version and github location

* feat(channel) update yuanbao plugin github location

* fix(channel): update yuanbao plugin GitHub location and add yuanbao alias (#74253) (thanks @loongfay)

---------

Co-authored-by: loongzhao <loongzhao@tencent.com>
Co-authored-by: sliverp <870080352@qq.com>
2026-04-30 16:02:40 +08:00
YueZhang
1e20babcf7 fix(memory-lancedb): get memory records through ltm list command (#67952)
* fix(mem-lancedb): get memory records through ltm list command

* code review

---------

Co-authored-by: zhangyue19921010 <zhangyue.1010@bytedance.com>
2026-04-30 16:01:51 +08:00
clawsweeper[bot]
53dff569b8 fix: bounded directory scan actionable regression (#74942)
* fix: bounded directory scan actionable regression

* fix: current main remaining regression

* fix(skills): compose workspace scan caps

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-30 00:54:02 -07:00
Vincent Koc
77f904d35c fix(security): emit QQBot debug logs as sanitized lines
Emits QQBot debug logs as CRLF-neutralized lines to remediate CodeQL alert 231.
2026-04-30 00:49:38 -07:00
ethanclaw
dc0c54c7f1 fix(cron): warn when --agent is not specified on cron add (#42245)
* fix(cron): warn when --agent is not specified on cron add

Warn users when creating a cron job without specifying the --agent flag,
so they know the job will run with the default agent (main).

Fixes #42196

* fix(cron): warn when cron add omits --agent

* fix(cron): name default agent in warning

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-30 00:45:41 -07:00
JC
83753535eb fix(pdf): resolve standard fonts from pdfjs package root (#70936)
* fix(pdf): resolve standard fonts from pdfjs package root

Resolve PDF.js standard fonts via pdfjs-dist/package.json instead of a
relative ../../node_modules path so the fallback renderer does not depend
on emitted dist chunk layout.

Add focused regression coverage that asserts the forwarded
standardFontDataUrl matches the installed pdfjs-dist package root and
exists on disk.

* fix(pdf): resolve pdfjs standard fonts from package root

* fix(pdf): use PDF.js font URL separator

---------

Co-authored-by: Dr JCai <jingxiao.cai@gmail.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-30 00:38:48 -07:00
Vincent Koc
2d748e4ac1 fix(security): sanitize QQBot debug log values
Sanitizes QQBot debug log values to remediate CodeQL alert 230.
2026-04-30 00:37:05 -07:00
Val Alexander
13e917e292 fix: derive dynamic context-window guard thresholds
Derive context-window guard thresholds from the effective model window, keeping 10% hard-min and 20% warning ratios with 4k/8k floors.

Stop the embedded runner from forcing old fixed guard overrides so runtime admission uses the dynamic resolver.

Validation:
- CI run 25151866833 passed, including build-artifacts and checks-node-channels.
- Parity gate 25151866868 passed.
- Testbox pnpm test:channels passed: 54 files / 433 tests.

Fixes #42999.

Prepared head SHA: 9c80383639
2026-04-30 02:33:43 -05:00
clawsweeper[bot]
f0721452a8 fix(ci): committed Plugin SDK API baseline hash is not reproducible from the committed source... (#74789)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-30 00:31:29 -07:00
clawsweeper[bot]
8d4928b505 fix(sdk): treat terminal wait timeouts as timed out (#74697)
* fix: wait-status mapping sdk regression

* fix(sdk): treat terminal wait timeouts as timed out

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper-repair <clawsweeper-repair@users.noreply.github.com>
2026-04-30 00:27:32 -07:00
Vincent Koc
25f0b5dda3 docs(changelog): note secret comparison CodeQL remediation
Adds the requested changelog attribution for CodeQL alert 229.
2026-04-30 00:21:59 -07:00
Vincent Koc
9720358bad docs(changelog): note outbound CodeQL remediation
Adds the requested changelog attribution for CodeQL alert 228.
2026-04-30 00:19:36 -07:00
clawsweeper[bot]
554b32feea fix: change disables bundled dependency repair when plugins.enabled: false, but the same fall... (#74916)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-30 00:13:52 -07:00
clawsweeper[bot]
402b826ba2 fix: existing doctor-contract Windows loader test still expects Jiti to be called for contrac... (#74923)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-30 00:13:42 -07:00
Vincent Koc
7c5bf1c675 fix(security): remediate CodeQL alerts 2026-04-30 00:12:50 -07:00
Vincent Koc
a093b5b2de fix(skills): bound grouped skill directory scans 2026-04-30 00:03:19 -07:00
Vincent Koc
02597caa8b chore(ci): add agent CodeQL PR quality guard
Promotes the existing agent-runtime quality shard to PR/manual selection and documents the expanded twelve-shard PR quality set.
2026-04-30 00:01:12 -07:00
Otto Deng
8ca1f6d590 fix(skills): scan grouped skill directories
* fix(skills): scan nested subdirectories for grouped skill layouts

Previously, skill discovery only checked immediate children of the
skills root for SKILL.md files. Skills organized in subdirectories
(e.g. ~/.openclaw/skills/coze/koze-retrieval/SKILL.md) were silently
ignored.

Now, when an immediate child directory does not contain a SKILL.md,
its own children are checked one level deeper. This supports grouped
skill layouts while keeping the scan depth bounded (max 2 levels) to
avoid unbounded filesystem traversal.

The existing per-source skill count limits and containment checks
still apply to nested discoveries.

Fixes #56915

* test(skills): cover nested grouped skill discovery

* fix(skills): cache contained-path checks and cap nested scans

- Reuse skillDirRealPath captured during the collection phase so the load
  loop no longer re-runs resolveContainedSkillPath on the same directory.
- Apply the per-root candidate cap (and the matching warning log) when
  descending into nested grouped skill directories, matching the outer
  scan's behavior.

Addresses Greptile P2 feedback on PR #72534.

* fix(skills): load grouped skill directories under skills roots

* fix(clownfish): address review for ghcrawl-156697-autonomous-smoke (1)

---------

Co-authored-by: Otto Deng <otto@ottodeng.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Otto Deng <ottodeng2@github.local>
2026-04-29 23:56:19 -07:00
Vincent Koc
d18fdecd53 test(channels): align module loader jiti fixture 2026-04-29 23:46:39 -07:00
NianJiu
43ca7399e5 Fix CLI text command hangs (#74220)
* fix(cli): keep agents list off plugin preload

* docs(changelog): note cli text hang fix

* test(cli): update preaction agents list expectations
2026-04-30 06:36:24 +00:00
Galin Iliev
c4a4c189f1 fix: enable native require fast path on Windows for bundled plugins (#74173)
Removes the win32 exclusion from supportsNativeJitiRuntime() and adds { allowWindows: true } to all tryNativeRequireJavaScriptModule call sites, so bundled plugin modules use native require() instead of Jiti on Windows. Also adds an attempted-load counter to the debug timing log and a changelog entry.

Fixes #68656

Co-authored-by: Galin Iliev <galiniliev@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-29 23:32:20 -07:00
Vincent Koc
e0c75cd0bd chore(ci): cover bundled channels in CodeQL PR guard
Extends the channel CodeQL quality shard to bundled channel plugin source directories and documents the scoped PR guard coverage.
2026-04-29 23:28:18 -07:00
clawsweeper[bot]
d55fafd130 fix(ci): disable install smoke Docker build cache
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 23:16:10 -07:00
Vincent Koc
423f6df5b1 chore(ci): add config CodeQL PR quality guard
Adds the config-boundary quality shard to the PR CodeQL guard and documents the expanded eleven-shard PR quality set.
2026-04-29 23:15:58 -07:00
clawsweeper[bot]
6dbaa0a278 fix(plugins): keep disabled plugin runtime deps off
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 23:15:47 -07:00
clawsweeper[bot]
fbc145440f fix(slack): offset presentation controls after native blocks
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 23:15:19 -07:00
Vincent Koc
a265abaf29 docs(changelog): backfill c34ed90822 control UI refresh-during-runs guard 2026-04-29 23:07:28 -07:00
Vincent Koc
3031726905 chore(ci): add auth CodeQL PR quality guard
Adds the core-auth-secrets quality shard to the PR CodeQL guard and documents the expanded ten-shard PR quality set.
2026-04-29 23:06:02 -07:00
Val Alexander
c34ed90822 fix(control-ui): disable refresh during active runs
Disable the Control UI refresh button while chat is disconnected, loading, sending, running, or streaming.

This prevents manual chat-history refresh from racing active run/stream state and adds browser render coverage for the disabled-state matrix.

Closes #65522.

Validation:
- Exact PR head `1511a086614a727fc4200730e7ad9622134bb7d3` reached `CLEAN` merge state.
- GitHub CI for the exact head completed with no failed or pending checks.
2026-04-30 01:02:14 -05:00
Vincent Koc
e9d4cb2bb6 chore(ci): add memory CodeQL PR quality guard
Adds the memory runtime quality shard to the PR CodeQL guard while preserving provider/plugin overlap only for the memory files that share those contracts.
2026-04-29 22:54:37 -07:00
Vincent Koc
c259a90b3b fix(ui): refresh Persian locale copy 2026-04-29 22:51:36 -07:00
Vincent Koc
c500b26bb6 chore(ci): add plugin SDK reply CodeQL PR guard
Adds the Plugin SDK reply runtime quality shard to the PR CodeQL guard while keeping reply runtime changes on the existing plugin and package-contract shards.
2026-04-29 22:43:24 -07:00
clawsweeper[bot]
897ca6abbb fix: Windows-specific reliability gap in the new timeout cleanup path (#74703)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:43:09 -07:00
github-actions[bot]
0c74952bcf chore(ui): refresh fa control ui locale 2026-04-30 05:39:39 +00:00
clawsweeper[bot]
9177fab07b fix: environment edge case launcher regression (#74696)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:39:12 -07:00
clawsweeper[bot]
3c9437ae54 fix: configs that used the previously documented WhatsApp exposeErrorText key now fail valida... (#74667)
* fix: configs that used the previously documented WhatsApp exposeErrorText key now fail valida...

* fix(clawsweeper): address review for clawsweeper-commit-openclaw-openclaw-4cba08df01ea (1)

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:34:59 -07:00
clawsweeper[bot]
1ff1fbe682 fix(plugins): honor runtime deps fallback install option
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:28:15 -07:00
clawsweeper[bot]
44296fcd2b fix(sdk): emit replacement chat projection deltas
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:28:05 -07:00
clawsweeper[bot]
b876ecdb84 fix(plugins): select runtime deps by configured models
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:27:54 -07:00
clawsweeper[bot]
0459206c40 fix(gateway): preserve rpc abort terminal snapshots
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:27:44 -07:00
Vincent Koc
a34ba362c6 chore(ci): add session CodeQL PR quality guard
Adds the session diagnostics quality shard to the PR CodeQL guard while keeping diagnostics and delivery queue analysis path-sharded by surface.
2026-04-29 22:27:27 -07:00
clawsweeper[bot]
1a9763f578 fix(google): accept Windows ADC manifest paths
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:26:09 -07:00
clawsweeper[bot]
9189b16c1c fix(bedrock): expose Opus 4.7 max thinking
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:25:58 -07:00
clawsweeper[bot]
59e7053464 fix(plugins): prefer require export conditions
* fix: fixed condition order prefers a top-level require export before a node condition, which...

* fix(clawsweeper): address review for clawsweeper-commit-openclaw-openclaw-6877360218c9 (1)

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:25:48 -07:00
clawsweeper[bot]
ebf05be742 fix(slack): preserve mixed interactive blocks
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:25:38 -07:00
clawsweeper[bot]
c6c518e6e9 fix(slack): cap select option values
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:25:29 -07:00
Vincent Koc
4fc0981a52 chore(ci): add process CodeQL PR quality guard
Adds the MCP/process runtime quality shard to the PR CodeQL guard and keeps non-security quality analysis path-sharded by surface.
2026-04-29 22:15:17 -07:00
openclaw-clownfish[bot]
3af4575a84 fix(media): treat legacy Word docs as binary attachments
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-29 22:07:21 -07:00
clawsweeper[bot]
fa1b8a25b8 test(ci): guard install smoke docker cache removal
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:06:02 -07:00
clawsweeper[bot]
ccb43f95cb fix(channels): suppress observe-only prepared dispatch
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:05:28 -07:00
clawsweeper[bot]
87a211d309 fix(slack): cap approval update fallback text
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:05:18 -07:00
clawsweeper[bot]
19d6404168 fix(slack): share edit fallback text truncation
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 22:05:07 -07:00
Vincent Koc
1c0b02a297 docs(ci): rewrite for structure, deduplication, and findability
Splits the previous wall-of-prose docs/ci.md into discoverable sections
while preserving every operator-relevant detail:

- Lead orientation paragraph kept; cross-links to umbrella and prerelease
- Pipeline overview anchors the job table at the top
- Fail-fast order tightened; superseded-run/concurrency notes folded in
- Scope and routing surfaces ci-changed-scope.mjs, the routing-only fast
  path, the Windows scope rule, Vitest shard balancing, the Android
  dual-flavor rule, and the check-dependencies (Knip + unused-file
  allowlist) pass that was buried in the lead
- Manual dispatches groups examples + include_android + target_ref
- Runners and Local equivalents tables/blocks preserved
- Full Release Validation: release_profile and rerun_group bulleted;
  verifier-only rerun guidance and the shared release-package-under-test
  artifact called out
- Live and E2E shards: native-live shard names listed, live-media-runner
  image and openclaw-live-test:<sha> with OPENCLAW_SKIP_DOCKER_BUILD=1
  broken out
- Package Acceptance split into Jobs / Candidate sources / Suite profiles
  / Legacy compatibility windows / Examples / debugging
- Install smoke: fast vs full paths, main-push policy, Bun gate
- Local Docker E2E: scheduler tunables in a table, reusable workflow
  flow, release-path chunks list, rerun helpers
- Plugin Prerelease, QA Lab, CodeQL each get their own discoverable
  sections; CodeQL uses tables for security and quality categories
  instead of paragraph walls (kept the new provider-runtime-boundary
  shard in the PR-quality-guard list)
- Maintenance workflows groups Docs Agent, Test Performance Agent, and
  Duplicate PRs After Merge
- Local check gates and changed routing turn boundary lane rules into
  bullets and keep the explicit-mapping prose
- Testbox validation kept; Related links preserved

Audited every workflow name and CodeQL category against
.github/workflows/ — no stale references. File goes from 527 to 413
lines while preserving shard names, env vars, profiles, chunks, and
legacy-compat windows. Layout obeys oxfmt.
2026-04-29 22:04:44 -07:00
Vincent Koc
6308d2a1dc chore(ci): add channel CodeQL PR quality guard
Adds the channel runtime quality shard to the PR CodeQL guard and keeps non-security quality analysis path-sharded by surface.
2026-04-29 22:00:55 -07:00
dependabot[bot]
2d53b1d314 build(deps): bump debian docker base digest
Bumps the docker-images group with 1 update in the / directory: debian.


Updates `debian` from `4724b8c` to `f9c6a2f`

---
updated-dependencies:
- dependency-name: debian
  dependency-version: bookworm-slim
  dependency-type: direct:production
  dependency-group: docker-images
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-29 21:55:26 -07:00
clawsweeper[bot]
6689e414bb fix(gateway): avoid caching empty model catalogs
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 21:53:25 -07:00
clawsweeper[bot]
a6af23a1de fix(test): keep kitchen-sink conformance diagnostics clean
* fix: test-harness regression risk

* fix: keep kitchen-sink conformance diagnostics clean

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper-repair <clawsweeper-repair@users.noreply.github.com>
2026-04-29 21:53:15 -07:00
clawsweeper[bot]
54bebc5f5e fix(commands): require gateway memory probe skipped state
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 21:52:07 -07:00
dependabot[bot]
4d8c155d33 chore(deps): bump swift-testing
Bumps [github.com/apple/swift-testing](https://github.com/apple/swift-testing) from 0.99.0 to 6.3.1.
- [Release notes](https://github.com/apple/swift-testing/releases)
- [Commits](https://github.com/apple/swift-testing/compare/0.99.0...6.3.1)

---
updated-dependencies:
- dependency-name: github.com/apple/swift-testing
  dependency-version: 6.3.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-29 21:48:39 -07:00
dependabot[bot]
9cb71bbaab chore(deps): bump actions group
Bumps the actions group with 2 updates in the / directory: [useblacksmith/setup-docker-builder](https://github.com/useblacksmith/setup-docker-builder) and [useblacksmith/build-push-action](https://github.com/useblacksmith/build-push-action).


Updates `useblacksmith/setup-docker-builder` from 1.7.0 to 1.8.0
- [Release notes](https://github.com/useblacksmith/setup-docker-builder/releases)
- [Commits](ac083cc846...722e97d12b)

Updates `useblacksmith/build-push-action` from 2.1.0 to 2.2.0
- [Release notes](https://github.com/useblacksmith/build-push-action/releases)
- [Commits](cbd1f60d19...fb9e3e6a92)

---
updated-dependencies:
- dependency-name: useblacksmith/build-push-action
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: useblacksmith/setup-docker-builder
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-29 21:48:30 -07:00
Vincent Koc
8dc99feb50 chore(ci): add provider CodeQL PR quality guard
Adds the provider runtime quality shard to the PR CodeQL guard, keeps PR quality analysis path-sharded by surface, and fixes selector overlap for Plugin SDK/package-contract paths.
2026-04-29 21:47:17 -07:00
拐爷&&老拐瘦
3224075edc fix: reject invalid cron edits on disabled jobs (#74720)
* fix(cron): reject invalid disabled schedule updates

* docs: add cron validation changelog entry

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-30 04:33:43 +00:00
Vincent Koc
eea964330c chore(ci): add gateway CodeQL PR quality guard
Adds the gateway runtime quality shard to the PR CodeQL guard, keeps PR quality analysis path-sharded by surface, and documents the shard selector behavior.
2026-04-29 21:26:03 -07:00
hcl
2de6ad4544 fix(exec): preserve turnSourceChannel as messageProvider in approval followup runs (#74666)
When an exec-approval followup run has no deliverable route and no
gateway-internal channel, buildAgentFollowupArgs was passing channel=undefined
to the spawned agent. This left defaults.messageProvider=undefined in the
followup run, causing tools.elevated.allowFrom.<provider> checks to always
fail with provider=null after the user approved an async elevated command.

Thread turnSourceChannel through buildAgentFollowupArgs and use it as a
fallback when sessionOnlyOriginChannel is absent. Fixes #74646.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 04:25:16 +00:00
hcl
38aac70830 fix(feishu): skip empty-text messages with no media to prevent blank session turns (#74634) (#74661)
Feishu delivers empty-text events (e.g. {"text":""}) when users send
blank messages or when a media-only message produces no text content.
Writing a blank user turn to the session file causes downstream LLM
providers such as MiniMax to reject requests with:

  invalid params, messages must not be empty (2013)

Guard at the point after media resolution: if ctx.content.trim() is
empty AND mediaList is empty, log the skip and return without queuing
a reply. This preserves all existing behaviour for text, media, and
mixed messages.

Regression test: dispatch a DM with {"text":""} (no media), assert
mockDispatchReplyFromConfig is not called.

Closes #74634. Thanks @xdengli.
2026-04-30 04:24:27 +00:00
hcl
5716428adc fix(acp): fall through to thread-bound resolution when token is unresolvable (#66299) (#74641)
* fix(acp): fall through to thread-bound resolution when token is unresolvable (#66299)

resolveAcpTargetSessionKey returned an error immediately when an explicit
session token was supplied but could not be resolved as a key/id/label.
This blocked the thread-bound and requester-session fallback paths from
ever being reached.

Discord slash commands auto-fill the current thread ID as a positional
ACP target. That value is not a session identifier, so the gateway lookup
returns null, and the command returned 'Unable to resolve session target'
instead of falling through to the thread-bound session that was already
known via the binding context.

Fix: when the token lookup returns null, skip the early-exit error and
fall through to thread-bound → requester-session → error in the normal
way. The 'Missing session key' error still surfaces when neither fallback
produces a binding.

Adds a focused regression test: unresolvable token + bound thread session
→ steer command reaches the thread-bound session, not an error.

Fixes #66299

* fix(changelog): add Thanks @martingarramon attribution for #66299

Per clawsweeper P2 review — every new CHANGELOG entry must credit
at least one author. martingarramon authored the issue analysis and
explicitly invited the PR.

* fix(acp): preserve bad-token diagnostics after thread fallback

---------

Co-authored-by: clawsweeper-repair <clawsweeper-repair@users.noreply.github.com>
2026-04-30 04:24:21 +00:00
Peter Steinberger
e648f38efc fix: stabilize Parallels update restart checks 2026-04-30 05:22:04 +01:00
Peter Steinberger
d363565375 fix: harden Windows Parallels update smoke 2026-04-30 05:22:04 +01:00
Peter Steinberger
d5e4ec9ea8 fix: accept extensionless runtime dependency mains 2026-04-30 05:22:04 +01:00
Peter Steinberger
c976cf6ebd chore: refresh a2ui bundle hash 2026-04-30 05:22:04 +01:00
Shubhankar Tripathy
0142c79123 config: accept browser.tabCleanup keys in zod schema (#74577) (#74638)
* config: accept browser.tabCleanup keys in zod schema (#74577)

* docs: update config baseline hash

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-30 04:21:09 +00:00
Peter Steinberger
4b3f91c686 fix(active-memory): clarify fallback config help (#74602) (thanks @jeffrey701) 2026-04-30 05:17:27 +01:00
jeffrey701
c894dbf0ae fix(active-memory): clarify modelFallbackPolicy deprecation warning text
Closes #74587. AI-assisted, fully tested.

The previous deprecation warning ("set config.modelFallback explicitly
if you want a fallback model") read naturally as runtime failover —
model A errors → switch to model B. The actual semantics in
`getModelRef` are different: `modelFallback` is the **last candidate
in the chain-resolution walk**, consulted only when `config.model`,
the current run's model, AND the agent's configured default have all
resolved to nothing. There is no error-recovery / retry-with-different-model
path.

The mismatch wastes real debug time. The issue filer reports ~1 hour of
cycles before reading source revealed the gap; users without source
access can debug for much longer assuming runtime failover exists.

## Fix

Rewrite the warning string to:

1. State the deprecation (preserved).
2. Describe `modelFallback`'s actual semantics — chain-resolution
   last-resort, gated on the three earlier candidates resolving to
   nothing.
3. Explicitly disclaim the wrong mental model — "it is NOT a runtime
   failover that substitutes a different model when the resolved model
   errors out" — so a quick read can't lead the operator astray.

No behavior change, only operator-facing copy. Surrounding code paths
(`getModelRef`, `hasDeprecatedModelFallbackPolicy`, the warn caller in
`register()`) are untouched.

## Tests

`extensions/active-memory/index.test.ts` extends the existing
deprecation-warning assertion to pin both the positive copy
(`chain-resolution`, `last-resort`) and the negative disclaimer
(`NOT a runtime failover`), so a future "let's reword this" change
that reintroduces the failover-implying language fails the test
instead of silently regressing.

`pnpm test extensions/active-memory/index.test.ts` — 94 passed.
`pnpm exec oxfmt --check` — clean. `pnpm exec oxlint` — 0 warnings,
0 errors.

## AI-assisted PR

- [x] Mark as AI-assisted (Claude). Lightly tested via the targeted
  Vitest extension shard; not exercised against a live Ollama / AM
  rollout because the change is a log-string update, not behavior.
- [x] Confirm I understand what the code does: yes — `getModelRef`
  walks four candidates (`config.model`, `currentRunModel`,
  `configuredDefaultModel`, `config.modelFallback`) and returns the
  first non-null parse; `modelFallback` is purely a default-when-empty
  selector, not a runtime failover.
2026-04-30 05:17:27 +01:00
Peter Steinberger
395ad91323 fix: cap slack approval update text 2026-04-30 05:16:25 +01:00
Peter Steinberger
c4f9cf1a27 fix: cap slack edit fallback text 2026-04-30 05:12:04 +01:00
Peter Steinberger
30774786f1 fix: cap slack block fallback text 2026-04-30 05:12:03 +01:00
Peter Steinberger
c316dbfc4a fix: keep slack message controls 2026-04-30 05:12:03 +01:00
Peter Steinberger
035b70aed1 docs: credit doctor memory probe fix (#74653) (thanks @hclsys) 2026-04-30 05:10:32 +01:00
HCL
96482b3e62 test(doctor): add skipped: false to gateway error and timeout test assertions 2026-04-30 05:10:32 +01:00
HCL
549624ffb2 fix(doctor): add skipped discriminator to distinguish probe skip from gateway timeout
Previously both a planned probe skip (probe:false path) and a transport timeout
returned checked:false, so the renderer's !checked early return would silently
suppress diagnostics for key-optional providers even when the gateway had timed out.

- Add `skipped?: boolean` to GatewayMemoryProbe: true for gateway-confirmed skip,
  false for timeout/unavailable paths
- Renderer now guards on `probe.skipped` instead of `!probe.checked`, so timeouts
  fall through to the existing warning path
- Update doctor-memory-search inline type and buildGatewayProbeWarning signature
- Update skipped-probe tests to pass { skipped: true }; add regression test for
  key-optional timeout (lmstudio gateway timeout now warns)

Addresses clawsweeper P2: src/commands/doctor-memory-search.ts:416
2026-04-30 05:10:32 +01:00
HCL
34d62b0650 fix(doctor): propagate gateway skipped-probe flag through adapter
clawsweeper P1: probeGatewayMemoryStatus always returned checked: true
on successful RPC, silently discarding payload.embedding.checked === false
from the SKIPPED_MEMORY_EMBEDDING_PROBE gateway response. The renderer
guard in noteMemorySearchHealth (added in prior commit) never saw checked:
false in real execution — only on timeout paths.

Fix: propagate checked flag from payload.embedding.checked so a skipped
gateway probe surfaces as checked: false to the renderer, allowing the
key-optional provider guard to suppress the false-positive warning.

Add adapter-level regression test that verifies the skipped payload shape
from doctor.memory.status reaches GatewayMemoryProbe as checked: false.
2026-04-30 05:10:32 +01:00
HCL
45082aaed3 fix(doctor): suppress false-positive embedding warning when probe skipped
When `openclaw doctor` runs without --deep, the gateway probe is skipped
and returns { checked: false, ready: false } (SKIPPED_MEMORY_EMBEDDING_PROBE).
Key-optional providers (ollama, lmstudio, local) were incorrectly shown
"could not confirm embeddings are ready" in this case, misleading users
into thinking their fully-functional embedding setup had an issue.

Guard the key-optional provider path: if probe.checked is false (probe
was skipped, not run), return early without warning. A skipped probe
carries no readiness signal — it is not a failure.

- Adds two focused regression tests for ollama and lmstudio with
  skipped probe (checked: false) → expect note() not called
- Updates the prior test that expected a warning on checked:false
  to reflect the corrected behaviour

Fixes #74608
2026-04-30 05:10:32 +01:00
Peter Steinberger
d7396d4ffa fix(channels): keep status accessors config-only 2026-04-30 05:08:32 +01:00
Vincent Koc
2a6809467a docs(changelog): backfill 1f1f70a23f gateway sessions abort wait semantics 2026-04-29 21:07:16 -07:00
Peter Steinberger
5c46ccba0b docs: update 2026.4.29 changelog 2026-04-30 05:05:14 +01:00
Peter Steinberger
56155e5048 test: accept kitchen sink conformance diagnostics 2026-04-30 05:04:49 +01:00
clawsweeper[bot]
0603c2327d fix(file-transfer): require canonical node policy authorization (#74742)
* feat(file-transfer): add bundled plugin for binary file ops on nodes

New extensions/file-transfer/ plugin exposing four agent tools
(file_fetch, dir_list, dir_fetch, file_write) and four matching
node-host commands (file.fetch, dir.list, dir.fetch, file.write).
Lets agents read and write files on paired nodes by absolute path,
bypassing the bash output cap (200KB) and the live tool-result
text cap that would otherwise truncate base64 payloads.

Public surface
--------------
- file_fetch({ node, path, maxBytes? })
  Image MIMEs return image content blocks; small text (<=8 KB) inlines
  as text content; everything else returns a saved-media-path text
  block. sha256-verified end-to-end.
- dir_list({ node, path, pageToken?, maxEntries? })
  Structured directory listing — name, path, size, mimeType, isDir,
  mtime. Paginated. No content transfer.
- dir_fetch({ node, path, maxBytes?, includeDotfiles? })
  Server-side tar -czf streamed back, unpacked into the gateway media
  store, returns a manifest of saved paths. Single round-trip.
  60s wall-clock timeouts on tar create/unpack. tar -xzf without -P
  rejects absolute paths in archive entries.
- file_write({ node, path, contentBase64, mimeType?, overwrite?,
              createParents? })
  Atomic write (temp + rename). Refuses to overwrite by default.
  Refuses to write through symlinks (lstat check). Buffer-side
  sha256 (no read-back race). Pair with file_fetch to round-trip
  files between nodes — DO NOT use exec/cp for file copies.

All four commands gated by:
  - dangerous-by-default node command policy
    (gateway.nodes.allowCommands opt-in)
  - per-node path policy (gateway.nodes.fileTransfer)
  - optional operator approval prompt (ask: off | on-miss | always)

16 MB raw byte ceiling per single-frame round-trip (25 MB WS frame
with ~33% base64 overhead and JSON envelope). 8 MB defaults.

Path policy and approvals
-------------------------
Default behavior is DENY. The operator must explicitly opt in:

  {
    "gateway": {
      "nodes": {
        "fileTransfer": {
          "<nodeId-or-displayName>": {
            "ask":              "off" | "on-miss" | "always",
            "allowReadPaths":   ["~/Screenshots/**", "/tmp/**"],
            "allowWritePaths":  ["~/Downloads/**"],
            "denyPaths":        ["**/.ssh/**", "**/.aws/**"],
            "maxBytes":         16777216
          },
          "*": { "ask": "on-miss" }
        }
      }
    }
  }

ask modes:
  off       — silent: allow if matched, deny if not (default)
  on-miss   — silent allow if matched; prompt on miss
  always    — prompt every call (denyPaths still hard-deny)

denyPaths always wins. allow-always from the prompt persists the
exact path back into allowReadPaths/allowWritePaths via
mutateConfigFile so subsequent matching calls go silent.

Reuses existing primitives — no new gateway methods:
  plugin.approval.request / plugin.approval.waitDecision
  decision: allow-once | allow-always | deny

Pre-flight against requested path AND post-flight against the
canonicalPath returned by the node — closes symlink-escape attacks
where the requested path matched policy but realpath resolves
somewhere else.

Audit log
---------
JSONL at ~/.openclaw/audit/file-transfer.jsonl. Records every
decision (allow/allowed-once/allowed-always/denied/error) with
timestamp, op, nodeId, displayName, requestedPath, canonicalPath,
decision, error code, sizeBytes, sha256, durationMs. Best-effort
writes; never propagates failure.

Plugin layout
-------------
extensions/file-transfer/
  index.ts                       definePluginEntry, nodeHostCommands
  openclaw.plugin.json           contracts.tools registration
  package.json
  src/node-host/{file-fetch,dir-list,dir-fetch,file-write}.ts
  src/tools/{file-fetch,dir-list,dir-fetch,file-write}-tool.ts
  src/shared/
    mime.ts        single-source extension->MIME map + image/text sets
    errors.ts      shared error code enum and helpers
    params.ts      shared param-validation helpers + GatewayCallOptions
    policy.ts      evaluateFilePolicy, persistAllowAlways
    approval.ts    plugin.approval.request wrapper
    gatekeep.ts    one-stop policy + approval + audit orchestrator
    audit.ts       JSONL audit sink

Core touch points
-----------------
- src/infra/node-commands.ts: NODE_FILE_FETCH_COMMAND,
  NODE_DIR_LIST_COMMAND, NODE_DIR_FETCH_COMMAND,
  NODE_FILE_WRITE_COMMAND, NODE_FILE_COMMANDS array
- src/gateway/node-command-policy.ts: all four added to
  DEFAULT_DANGEROUS_NODE_COMMANDS
- src/security/audit-extra.sync.ts: audit detail mentions file ops
- src/agents/tools/nodes-tool-media.ts: MEDIA_INVOKE_ACTIONS entry
  for file.fetch redirects raw nodes(action=invoke) callers to the
  dedicated file_fetch tool to prevent base64 context bloat
- src/agents/tools/nodes-tool.ts: nodes tool description points to
  the dedicated file_fetch tool

Known limitations / follow-ups
------------------------------
- No tests in this PR. For a security-sensitive surface this is a
  gap; will follow up with a test pass.
- Direct CLI invocation (openclaw nodes invoke --command file.fetch)
  bypasses the plugin policy entirely. Plugin-side gating is the
  realistic threat model (agent on iMessage requesting paths it
  shouldn't), but for true defense-in-depth, policy belongs in the
  gateway-side node.invoke dispatch. Move-policy-to-core is a
  separate PR.
- file_watch (long-lived filesystem event subscription) is not
  included; it needs a new node-protocol primitive for streaming
  event channels and was descoped from this PR.
- dir_fetch includeDotfiles: true is the only supported mode;
  BSD tar exclude patterns reliably collapse dotfile filtering
  to an empty archive. Reliable filtering needs a
  `find ! -name ".*" | tar -T -` pipeline; deferred.
- dir_fetch du -sk preflight is a heuristic (du * 4 vs maxBytes);
  the mid-stream byte cap is the actual safety net.

* test(file-transfer): add unit tests for handlers, policy, and shared utilities

Adds 77 tests covering:
- handleFileFetch: validation, fs errors, sha256, size cap, symlink canonicalization
- handleFileWrite: validation, atomic write, overwrite policy, parent dir handling, symlink refusal, integrity check, size cap
- handleDirList: validation, fs errors, sorted listing, dotfile inclusion, pagination
- handleDirFetch: validation, fs errors, gzipped tar with sha256, mid-stream byte cap
- evaluateFilePolicy: default-deny, denyPaths-wins, allow matching, ask modes (off/on-miss/always), node-id/displayName/'*' resolution
- persistAllowAlways: append, dedupe, create-on-missing
- shared/mime: extension lookup, image/text inline sets
- shared/errors: err helper, classifyFsError, throwFromNodePayload

Also fixes accumulated lint regressions in the prod source flagged once these
files moved into the changed-gate scope (parseInt -> Number.parseInt, redundant
type casts removed, single-statement if bodies wrapped in braces).

* fix(file-transfer): address PR review feedback (security + availability)

Reviewer findings addressed (greptile + aisle):

- policy: persistAllowAlways no longer escalates per-node approvals to the
  '*' wildcard entry; allow-always now writes under the specific node's
  own entry, never the wildcard (greptile P1 SECURITY).
- policy: add literal '..' segment short-circuit in evaluateFilePolicy,
  raised before glob match. Stops "/allowed/../etc/passwd" from passing
  preflight against "/allowed/**" globs (aisle MEDIUM CWE-22).
- file-write: replace no-op base64 try/catch with actual round-trip
  validation. Buffer.from(s, "base64") never throws — invalid input
  silently decoded to garbage bytes. Now re-encodes and compares
  modulo padding/url-variant chars (greptile P1 SECURITY).
- file-write: document the parent-symlink residual risk and rely on the
  existing gateway-side post-flight policy check; full rollback requires
  a node-side file.unlink which is deferred to a follow-up. Initial
  segment-walk attempt was reverted because it false-positives on system
  symlinks like macOS /var → /private/var (aisle HIGH CWE-59).
- dir-fetch tool: add preValidateTarball pass that runs `tar -tzvf` and
  rejects symlinks, hardlinks, absolute paths, '..' traversal,
  uncompressed sizes >64MB, and entry counts >5000 — before any
  extraction. Drops --no-overwrite-dir (GNU-only flag rejected by BSD
  tar on macOS) (aisle HIGH x2 CWE-22 + CWE-409, greptile P2).
- dir-fetch tool: stream-hash files via fs.open + read loop instead of
  fs.readFile to avoid full-buffer reads on large extracted entries.
- dir-fetch handler: replace spawnSync in countTarEntries with async
  spawn + bounded buffer so tar -tzf can't park the node-host event
  loop for up to 10s on a slow filesystem (greptile P1 AVAIL).
- audit: clear auditDirPromise on rejection so a transient mkdir
  failure doesn't permanently silence the audit log (greptile P2).

New tests: wildcard escalation rejection, base64 malformed/url-variant,
'..' traversal short-circuit (3 cases). 84/84 passing.

* fix(file-transfer): CI failures + second-round PR review feedback

CI failures on previous push:

- Declare runtime deps (minimatch, typebox) in package.json — failed the
  extension-runtime-dependencies contract test that scans imports.
- Switch policy.ts and policy.test.ts off the broad
  openclaw/plugin-sdk/config-runtime barrel and onto the narrow
  openclaw/plugin-sdk/config-mutation + runtime-config-snapshot subpaths.
  This satisfies the deprecated-internal-config-api architecture guard.

Second-round Aisle findings:

- policy: traversal-segment check now treats backslash and forward slash
  as equivalent, so a Windows node can't be hit with mixed-separator
  "C:\\allowed\\..\\Windows\\system.ini" (Aisle HIGH CWE-22).
- dir-fetch tool: replace the single fragile `tar -tvzf` parser pass
  (which broke for filenames containing whitespace) with two robust
  passes: `tar -tzf` for paths only (one per line, no parsing of
  fixed columns) and `tar -tzvf` for type chars only (FIRST CHAR of each
  line, never the path column). Also reject backslash-containing entry
  names. Drops the in-process uncompressed-size cap because reliably
  parsing sizes from tar output is fragile and Aisle flagged it as a
  bypass primitive — entry-count cap stays (Aisle HIGH CWE-22, MED).

Tests still 84/84 passing.

* fix(file-transfer): third-round PR review feedback

Aisle's re-analysis on b63daa6a05 surfaced 3 actionable findings:

- nodes.invoke bypass (HIGH CWE-285): generic nodes.action="invoke" let
  agents call dir.list/dir.fetch/file.write directly, skipping the
  file-transfer plugin's gatekeep + policy + approval flow. Only file.fetch
  was redirected to its dedicated tool. Add the other three to
  MEDIA_INVOKE_ACTIONS so the redirect-or-deny logic in
  nodes-tool-commands fires for all four. The dedicated tools enforce
  policy; the generic invoke surface no longer has a way to skip them
  without an explicit allowMediaInvokeCommands opt-in.
- prototype pollution in persistAllowAlways (MED CWE-1321): a paired
  node with displayName "__proto__" / "prototype" / "constructor" would
  mutate the fileTransfer object's prototype when persisting allow-always.
  Reject those keys explicitly. Switch the existing-key lookup to
  Object.prototype.hasOwnProperty.call so a key like "constructor"
  doesn't accidentally match Object.prototype.constructor.
- decompression-bomb cap in dir_fetch (MED CWE-409): compressed tar is
  bounded upstream, but a highly compressible bomb can still expand to
  gigabytes. Enforce DIR_FETCH_MAX_UNCOMPRESSED_BYTES (64MB) summed
  across extracted files and DIR_FETCH_MAX_SINGLE_FILE_BYTES (16MB) per
  entry, both checked during the post-extract walk. On bust, rm -rf the
  rootDir and audit-log + throw UNCOMPRESSED_TOO_LARGE.

Tests: 85/85 passing (added prototype-pollution rejection test).

Aisle's HIGH parent-symlink finding remains documented as deferred — full
rollback requires a node-side file.unlink command which is out of scope
for this PR. The gateway-side post-flight policy check still detects and
loudly errors on canonical-path mismatches.

* fix(file-transfer): refuse symlink traversal by default with followSymlinks opt-in

Closes the deferred Aisle HIGH parent-symlink finding. Instead of
detecting the escape in a post-flight gateway check after the file is
already written, the node-side handler now refuses pre-flight if any
component of the requested path resolves through a symlink.

Behavior:
- Reads (file.fetch / dir.list / dir.fetch): node realpath()s the
  requested path. If canonical != requested AND followSymlinks=false,
  return SYMLINK_REDIRECT { canonicalPath } — no I/O happens.
- Writes (file.write): node realpath()s the parent dir. Same refusal
  rule. The lstat-on-final check is kept to catch the case where the
  target file itself is an existing symlink.
- Opt-in: set gateway.nodes.fileTransfer.<node>.followSymlinks=true to
  bring back the previous "follow + post-flight check" behavior.

Operator UX: the SYMLINK_REDIRECT response includes the canonical path
so the operator can either update their allow list to the canonical form
or set followSymlinks=true on that node. On macOS, /var → /private/var
and /tmp → /private/tmp are system aliases that trip the new check, so
operators using those paths need followSymlinks=true OR canonical-path
allowlists.

Wiring:
- Add followSymlinks?: boolean to NodeFilePolicyConfig.
- evaluateFilePolicy returns followSymlinks (default false) on its
  ok=true branches.
- gatekeep propagates it via GatekeepOutcome.
- Each tool passes it as a node.invoke param.
- Each handler honors it pre-flight before any read/write.

Tests updated: 89/89 passing.
- realpath(mkdtemp()) so existing happy-path tests don't trip the new
  default on macOS where mkdtemp lands under symlinked /var/folders.
- New tests: SYMLINK_REDIRECT refusal for file.fetch and file.write
  parent traversal; opt-in passthrough when followSymlinks=true.
- New policy test: followSymlinks propagation default false / true.

* fix(file-transfer): close two more aisle findings on 069bd66

Aisle re-analysis on 069bd66 surfaced two issues my earlier round-three
fix missed:

- HIGH (CWE-284): file.fetch / dir.fetch / dir.list / file.write were
  still bypassable via the generic nodes.action="invoke" surface when
  the operator had set allowMediaInvokeCommands=true. That flag was
  meant to opt in to base64-bloat for camera/screen, not to disable
  path policy on file-transfer. Split the redirect map: introduce
  POLICY_REDIRECT_INVOKE_COMMANDS (file-transfer only) which ALWAYS
  rerouts to its dedicated tool regardless of the bloat flag. Camera
  and screen continue to use the bloat-only redirect (suppressed by
  allowMediaInvokeCommands=true). Confirmed by clawsweeper P1.
- MED (CWE-276): tar -xzf in dir_fetch unpack preserved archive
  ownership and permissions, so a malicious node could plant
  setuid/setgid or world-writable files on a gateway running with
  elevated privileges. Add --no-same-owner --no-same-permissions
  (both flags are portable across BSD tar / GNU tar).

Tests: 89/89 passing.

* chore(file-transfer): drop file_watch from plugin description

Phase 5 (file_watch) was deferred earlier in this PR. Strip the watch
mention from the plugin description in package.json,
openclaw.plugin.json, and index.ts so the metadata reflects what's
actually shipped (file_fetch, dir_list, dir_fetch, file_write).
Closes clawsweeper P3.

* fix(file-transfer): hash before rename and allow zero-byte round-trip

Two of Peter's review findings on PR #74134:

- P2 (file-write integrity): hash the decoded buffer + compare against
  expectedSha256 BEFORE temp+rename. Previously the rename happened
  first, then the sha check unlinked the target on mismatch — with
  overwrite=true a bad caller hash could replace + delete the original.
  Now a hash mismatch returns INTEGRITY_FAILURE without touching disk.
  Added a regression test that asserts the original file survives.

- P2/P3 (zero-byte round-trip): the tool layer's truthy checks on
  contentBase64 and base64 rejected the empty string, blocking zero-byte
  files from round-tripping through file_fetch -> file_write. Switched
  to type-checks (typeof === "string") and added zero-byte tests at the
  handler layer for both fetch and write (sha matches the known empty
  digest).

Tests: 92/92 passing.

* fix(file-transfer): declare gateway.nodes.fileTransfer in core config schema

Peter's P1/P2 finding: the plugin reads/writes gateway.nodes.fileTransfer
via casts through unknown because the strict zod schema and OpenClawConfig
type didn't declare it. That meant `openclaw config validate` would
reject the very examples in the plugin's own documentation.

- Add fileTransfer block to gateway.nodes in src/config/zod-schema.ts
  with the full per-node entry shape (ask, allowReadPaths,
  allowWritePaths, denyPaths, maxBytes, followSymlinks).
- Add GatewayNodeFileTransferEntry + the fileTransfer field on
  GatewayNodesConfig in src/config/types.gateway.ts.
- Drop the `as unknown` casts in the extension's policy.ts now that
  gateway.nodes.fileTransfer is properly typed end-to-end.
- Regenerate docs/.generated/config-baseline.sha256.

Tests: 92/92 passing. pnpm config:docs:check OK.

* fix(file-transfer): enforce path policy at gateway dispatch

Closes Peter's P1 review finding on PR #74134.

The agent-tool-only redirect added in earlier commits left CLI
(`openclaw nodes invoke`), plugin-runtime, and raw `node.invoke` callers
able to skip the file-transfer path policy entirely. The fix moves the
security boundary down to the gateway: every code path that reaches
`node.invoke` for file.fetch / dir.list / dir.fetch / file.write now
runs the same allow/deny check.

- New: src/gateway/file-transfer-dispatch.ts with
  `evaluateFileTransferDispatchPolicy` and `isFileTransferCommand`. Same
  semantics as the extension-side `evaluateFilePolicy` minus the
  operator-prompt flow (prompts stay at the agent-tool layer; the
  gateway is silent enforcement).
- src/gateway/server-methods/nodes.ts: after the existing command
  allowlist check, run the new gate before forwarding. Denies emit
  INVALID_REQUEST with a structured `{ command, code, reason }`.
- Decision matrix mirrors the extension: NO_POLICY (no entry for
  this node) deny, denyPaths-wins, '..' traversal short-circuit
  (with backslash separator handling), allowPaths match → allow,
  no allow match → deny.
- 19 new unit tests covering each branch including identity
  resolution (nodeId/displayName/'*'), prototype-pollution-safe lookup,
  and read-vs-write allow-list separation.

Note on allow-once approvals: the agent tool's interactive
`allow-once` decision now has to flow through the dedicated tool's
pre-flight (which forwards an approved request); raw `nodes.invoke`
callers cannot benefit from one-time approvals because the gateway is
silent. allow-always (which persists to allowReadPaths/allowWritePaths)
continues to work transparently because by the time the next request
hits the gateway the path is in the persisted allow list.

Tests: 92 extension + 19 gateway = 111 total, all passing.

* fix(file-transfer): enforce node policy in gateway

* fix(file-transfer): use plugin node policy only

* fix(file-transfer): harden node policy edge cases

* fix(file-transfer): close review hardening gaps

* fix(file-transfer): harden node invoke policy

* fix(file-transfer): align runtime dependency versions

* fix(file-transfer): keep minimatch extension-owned

* refactor(file-transfer): remove unused approval gate

* fix(file-transfer): require canonical node policy authorization

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>

* fix(clawsweeper): address review for automerge-openclaw-openclaw-74134 (1)

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>

* fix(file-transfer): recheck dir fetch archive policy after fetch

* fix(file-transfer): name file-transfer tool in invoke redirect

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: clawsweeper-repair <clawsweeper-repair@users.noreply.github.com>
2026-04-30 04:03:40 +00:00
Peter Steinberger
d80a8eb3ad fix(agents): drop metadata-only replay turns
Fixes #74745
2026-04-30 04:58:05 +01:00
Peter Steinberger
bb44909262 docs: update changelog for Discord SecretRef accessor (#74737) 2026-04-30 04:57:07 +01:00
천유신
e4ca4c7fbf fix(discord): avoid resolving tokens for read-only accessors 2026-04-30 04:57:07 +01:00
Peter Steinberger
94cb213544 fix: stabilize full release validation 2026-04-30 04:55:23 +01:00
Val Alexander
1f1f70a23f fix(gateway): align sessions abort wait semantics (#74751) thanks @BunsDev
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
2026-04-29 22:55:19 -05:00
bitloi
e6abd9e3d8 fix(sdk): stabilize run event chat projections (#74750) thanks @bitloi
Co-authored-by: bitloi <raphaelaloi.eth@gmail.com>
2026-04-29 22:54:52 -05:00
Peter Steinberger
5f13af6b68 fix: warn before npm prefix redirection (#73890) (thanks @Sayeem3051) 2026-04-30 04:49:03 +01:00
Peter Steinberger
bbf932fd7d fix(channels): preserve observe-only turn compatibility 2026-04-30 04:20:40 +01:00
Peter Steinberger
7a2bb2fcda docs: document high-confidence triage candidate filter 2026-04-30 04:18:16 +01:00
Peter Steinberger
a89fe0f5a0 docs: update plugin runtime changelog 2026-04-30 04:13:52 +01:00
Peter Steinberger
6877360218 fix(plugins): prefer require runtime aliases 2026-04-30 04:13:39 +01:00
Peter Steinberger
5138d3f8b6 fix(plugins): resolve plugin paths from root 2026-04-30 04:13:39 +01:00
Peter Steinberger
09310931cf fix(plugins): repair configured runtime deps 2026-04-30 04:13:39 +01:00
Peter Steinberger
db18323551 fix(plugin-sdk): restore zalouser facade 2026-04-30 04:13:39 +01:00
Peter Steinberger
9e5d6c7091 docs: credit macos attach-only launchd fix 2026-04-30 04:10:54 +01:00
Luka Dolenc
07605c79ad style(macos): order attach-only test modifiers 2026-04-30 04:10:54 +01:00
Luka Dolenc
25d2e9bdac fix(macos): keep attach-only from stopping gateway launchd 2026-04-30 04:10:54 +01:00
Peter Steinberger
ffe67e9cdc refactor(channels): route inbound turns through kernel 2026-04-30 04:08:47 +01:00
Vincent Koc
6e73101df3 chore(ci): widen CodeQL PR guard
Runs the PR CodeQL security guard as high-confidence high/critical security coverage and adds the initial plugin/package-contract quality guard.
2026-04-29 20:06:50 -07:00
Peter Steinberger
8672737f81 fix: drop overlong slack command values 2026-04-30 04:04:45 +01:00
Peter Steinberger
d25cfda54c fix: cap slack command menu blocks 2026-04-30 04:04:44 +01:00
Peter Steinberger
a4af1e91da docs(changelog): thank memory forget fix contributor 2026-04-30 04:03:41 +01:00
Peter Steinberger
757894e201 test(memory-lancedb): mock embedding transport in forget test 2026-04-30 04:03:41 +01:00
amittell
6f7c89ce21 fix(lint): resolve oxlint errors 2026-04-30 04:03:41 +01:00
amittell
faad655c21 fix(memory-lancedb): show full IDs in memory_forget candidate list 2026-04-30 04:03:41 +01:00
openclaw-clownfish[bot]
873df76132 fix(feishu): clean up bitable placeholder rows with empty defaults
Preserve the Feishu-local cleanup path while matching the Lark SDK record value shapes: recursively delete default-empty strings, nulls, arrays, and nested text spans, but keep meaningful links, attachments, users, locations, numbers, and booleans.\n\nCarries forward #40602. Thanks @boat2moon.
2026-04-30 04:01:49 +01:00
openclaw-clownfish[bot]
0e97f962ac fix(mattermost): add WebSocket ping/pong keepalive (#73979)
Adds Mattermost WebSocket ping/pong liveness checks so half-open sockets terminate and the existing reconnect loop recovers.

Fixes #41837.
Carries forward #57621.
Refs #50138, #44160, and #51104.
Thanks @JasonWang1124.

Co-authored-by: JasonWang1124 <56307673+JasonWang1124@users.noreply.github.com>
2026-04-30 03:57:31 +01:00
Peter Steinberger
2d1523e573 fix: interpolate heartbeat response prefix templates (#73996) (thanks @yweiii and @JunJD) 2026-04-30 03:48:51 +01:00
Peter Steinberger
329568905e fix: bound slack approval metadata 2026-04-30 03:47:12 +01:00
Peter Steinberger
c39ca49c71 fix(bonjour): cap flapping advertiser restarts 2026-04-30 03:46:18 +01:00
Peter Steinberger
df4faac71f fix(plugins): repair incomplete runtime-deps mirrors 2026-04-30 03:46:18 +01:00
Peter Steinberger
c403ea9063 refactor(channels): move more turn policy into kernel 2026-04-30 03:44:21 +01:00
Peter Steinberger
a6390efeba fix: bound slack command confirm text 2026-04-30 03:40:15 +01:00
Peter Steinberger
eab4024934 fix(whatsapp): track provider-accepted auto-replies 2026-04-30 03:38:19 +01:00
Peter Steinberger
b07c7f6ab3 fix(amazon-bedrock): expose Opus 4.7 thinking profile 2026-04-30 03:36:58 +01:00
Peter Steinberger
b7dd912541 test: cover app sdk gateway surfaces 2026-04-30 03:36:03 +01:00
Peter Steinberger
5d8f4d8767 fix(feishu): fallback to media resource download (#73986) (thanks @alex-xuweilong) 2026-04-30 03:35:44 +01:00
Peter Steinberger
6421e1f36a fix(gateway): refresh model catalog off request path 2026-04-30 03:35:09 +01:00
Peter Steinberger
57a3d7f6e8 fix(gateway): bound discovery advertise startup 2026-04-30 03:35:09 +01:00
Peter Steinberger
11d8ba96f9 fix: bound slack interactive button urls 2026-04-30 03:32:11 +01:00
Peter Steinberger
4329cee0c0 fix: mirror sqlite-vec for bundled memory runtime 2026-04-30 03:25:03 +01:00
Peter Steinberger
fc8fafbd2f fix: harden slack interactive blocks 2026-04-30 03:20:19 +01:00
Vincent Koc
8aed80d2fa chore(ci): add CodeQL PR security guard
Runs the narrow CodeQL critical-security matrix on non-draft pull requests for code and workflow security-boundary changes.
2026-04-29 19:19:45 -07:00
Vincent Koc
35264ca034 fix(plugins): use tokenjuice published openclaw types 2026-04-29 19:12:52 -07:00
Vincent Koc
c538906b72 docs(changelog): backfill last-24h sidebar trigger entry
For 323985f4ca (Val Alexander/@BunsDev): adds a Control UI/exports
entry covering the sidebar-trigger affordance alignment across the
resizable divider, mobile layout, and exported-HTML transcript template.
The other Val/@BunsDev fix (b1c515270e) was already covered by the
existing "Control UI/mobile: persist mobile chat settings" entry.

The rest of the last 24h's missing-CHANGELOG candidates are either:
- already covered by adjacent entries (Shakker manifest auth-evidence
  series under "CLI/models: keep manifest auth-evidence credentials
  visible", Discord application id + Cloudflare 429 under "Channels/
  Discord: cool down Cloudflare/Error 1015 HTML 429", config patch
  follow-ups under "Plugins/runtime-deps: add openclaw plugins deps",
  etc.);
- internal/test/CI/refactor with no operator surface;
- Clawsweeper-bot self-fixes for already-merged PRs;
- Peter-only with no external collaborator (per the
  attribution rule against thanking @steipete).
2026-04-29 19:07:06 -07:00
Peter Steinberger
30650fec73 chore: ignore Google OAuth client secrets 2026-04-30 03:06:52 +01:00
Peter Steinberger
58153d38af fix(codex): flush pending steering on completion 2026-04-30 03:06:26 +01:00
Peter Steinberger
1a103088ba fix: harden slack command menus 2026-04-30 03:04:10 +01:00
Peter Steinberger
1f006dbc5f test(core): stabilize changed gate mocks 2026-04-30 02:58:40 +01:00
Peter Steinberger
02ebac6250 refactor(channels): share turn dispatch results 2026-04-30 02:58:40 +01:00
Peter Steinberger
f94d970cee fix: refresh Google Meet speech retry readiness 2026-04-30 02:45:44 +01:00
Vincent Koc
cab86dc325 fix(docs): allow partial i18n doc batches 2026-04-29 18:19:32 -07:00
Peter Steinberger
5e8c396bb8 docs: explain security autofix boundary 2026-04-30 02:11:36 +01:00
Peter Steinberger
64cb9c5b71 docs: document clawsweeper changelog gate 2026-04-30 02:08:54 +01:00
Peter Steinberger
6331fec05e test(scripts): align changed sdk routing expectation 2026-04-30 02:06:47 +01:00
hcl
1fb096f0e6 fix(models): unconditionally suppress stale openai-codex/gpt-5.4-mini inline entries (#74451) (#74655)
* fix(models): block stale openai-codex/gpt-5.4-mini inline entries via unconditional suppression (#74451)

Suppress explicitly user-configured openai-codex/gpt-5.4-mini inline entries
so a stale models config written by `openclaw doctor --fix` cannot bypass the
manifest capability block and cause repeated assistant-turn failures when the
runtime switches to that model on ChatGPT-backed Codex accounts.

Adds `unconditionalOnly` flag to `buildManifestBuiltInModelSuppressionResolver`
and a `shouldUnconditionallySuppress` helper. Inside `resolveExplicitModelWithRegistry`,
inline matches are now gated on unconditional suppressions (no `when` clause)
before returning. Conditional suppressions such as the qwen Coding Plan endpoint
guard remain bypassable by explicit user configuration, preserving the existing
`resolves explicitly configured qwen3.6-plus before Coding Plan built-in suppression`
behaviour.

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

* fix(changelog): add missing reporter attribution for #74451 models suppression fix

* docs: credit codex mini suppression contributors

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shakker <shakkerdroid@gmail.com>
2026-04-30 02:02:23 +01:00
Fred blum
9b1bde2561 fix(voice-call): close webhook in-flight limiter fail-open on empty remote address (#74453)
* fix(voice-call): close in-flight limiter fail-open on empty remote address

The webhook in-flight limiter (createWebhookInFlightLimiter in
src/plugin-sdk/webhook-request-guards.ts) returns true unconditionally
when tryAcquire is called with an empty key — that is its by-contract
fail-open path used to mean 'caller is opting out of the limiter'.

The voice-call webhook handler reached that path silently: it computed
'req.socket.remoteAddress ?? ""' and passed the empty string straight
into tryAcquire. Whenever req.socket.remoteAddress was absent (closed
socket, edge proxy quirk), the limiter became a no-op and the request
proceeded directly to readBody without any concurrency cap.

Fix: when remoteAddress is missing, log a warning and fall back to a
constant non-empty key ('__voice_call_no_remote__') so all such
requests share one in-flight bucket instead of bypassing the limiter
entirely. The bucket size stays maxInFlightPerKey (default 8), which
is the right defense-in-depth posture against slow-body attacks
arriving with stripped IP info.

Scoped to voice-call only. Other consumers of the SDK helper
(bluebubbles via openclaw/plugin-sdk/webhook-ingress) are not changed
to avoid drive-by edits to plugins this PR does not own. The shared
SDK contract (empty key = bypass) is left as-is and documented
implicitly by the fix's comment block.

The existing 8-concurrent test in webhook.test.ts continues to assert
the limiter engages on the happy path; no new test added since the
private handleRequest path is not unit-test exposed and the change is
two-line auditable from the diff alone.

* test(voice-call): cover missing webhook remote address limiter

* test: align changed package sdk routing

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-30 01:02:14 +00:00
Peter Steinberger
10a9654674 docs: update clawsweeper automerge workflow 2026-04-30 02:00:07 +01:00
Peter Steinberger
78fc27fe7d docs: document shipped app sdk 2026-04-30 01:59:04 +01:00
Peter Steinberger
6863694a22 fix(status): resolve packaged channel setup loader 2026-04-30 01:58:02 +01:00
Peter Steinberger
80ec402d0f test(sdk): remove redundant fake transport cast 2026-04-30 01:54:58 +01:00
clawsweeper[bot]
3bd6b54f0b fix: compatibility gaps in the new Google Vertex ADC manifest evidence
Tighten Google Vertex ADC manifest evidence to canonical project env vars and canonical ADC fallback paths only.

Local proof:
- OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test src/agents/model-auth.profiles.test.ts src/plugins/manifest-registry.test.ts src/secrets/provider-env-vars.dynamic.test.ts
- pnpm exec oxfmt --check --threads=1 docs/plugins/manifest.md extensions/google/openclaw.plugin.json src/agents/model-auth-env.ts src/agents/model-auth.profiles.test.ts src/plugins/manifest.ts
- git diff --check origin/main...HEAD

CI note: checks-node-core-support-boundary was red on an unrelated tooling assertion in test/scripts/test-projects.test.ts for packages/sdk/src/index.test.ts routing; that file and scripts/test-projects.mjs are unchanged from origin/main.
2026-04-30 01:52:09 +01:00
Vincent Koc
5a631e1ee9 fix(docs): bound i18n codex prompt cleanup 2026-04-29 17:47:58 -07:00
Peter Steinberger
a548d8e1ea docs(discord): tag Cloudflare cooldown changelog 2026-04-30 01:47:02 +01:00
Peter Steinberger
9c22a0133b docs(discord): clarify application id account scope 2026-04-30 01:47:02 +01:00
Peter Steinberger
485b875d72 fix(discord): allow configured application ids 2026-04-30 01:47:02 +01:00
Peter Steinberger
a81e3ee888 fix(discord): bound application summary probes 2026-04-30 01:47:02 +01:00
Peter Steinberger
950a9b5500 fix(discord): cool down Cloudflare 429 responses 2026-04-30 01:47:02 +01:00
Peter Steinberger
d4e88e7a2f test: align sdk gateway event e2e 2026-04-30 01:44:47 +01:00
Peter Steinberger
cd0fb36c1c docs: clarify app sdk documentation 2026-04-30 01:39:55 +01:00
Peter Steinberger
d86c5775b8 test: cover sdk gateway integration 2026-04-30 01:39:49 +01:00
clawsweeper[bot]
e9fcbe1533 fix: changed explicit-path handling regression (#74672)
* fix: changed explicit-path handling regression

* fix: preserve unicode adc fallback paths

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Shakker <shakkerdroid@gmail.com>
2026-04-30 01:36:59 +01:00
Peter Steinberger
08c4af0ddf fix(msteams): accept conversation id allowlists 2026-04-30 01:35:42 +01:00
Peter Steinberger
c397486648 fix(test): configure kitchen sink before enable 2026-04-30 01:35:13 +01:00
Peter Steinberger
1ead1b2d18 refactor(channels): finish turn kernel migration 2026-04-30 01:31:00 +01:00
Peter Steinberger
442e14e359 docs(config): document queue backlog alias 2026-04-30 01:30:51 +01:00
Peter Steinberger
cf125c125a test(plugins): align release validation fixtures 2026-04-30 01:25:54 +01:00
Peter Steinberger
30a2b3049a feat: default active steering to batched delivery 2026-04-30 01:22:43 +01:00
Peter Steinberger
fabfab2b84 test: avoid volatile model availability assertions 2026-04-30 01:22:05 +01:00
Vignesh
b20eea92d8 changelog: Add inferred follow-up commitments for agents
Move commitment changelog entry to unreleased.
2026-04-29 17:21:14 -07:00
Peter Steinberger
70ddeef0e8 test: align model list expectations 2026-04-30 01:18:18 +01:00
Peter Steinberger
52b57d0953 fix(cli): scope packaged compile cache 2026-04-30 01:16:38 +01:00
Peter Steinberger
0b59964ec9 fix(google): support Vertex authorized_user ADC 2026-04-30 01:13:25 +01:00
Peter Steinberger
601596bfe2 docs: refresh plugin sdk api baseline 2026-04-30 01:04:51 +01:00
Peter Steinberger
68c99616a3 docs: add 2026.4.27 changelog highlights 2026-04-30 01:03:57 +01:00
Peter Steinberger
692211a758 chore: refresh sdk workspace lock importer 2026-04-30 01:01:53 +01:00
Vincent Koc
e5c608f804 docs: clarify i18n locale visibility 2026-04-29 17:00:48 -07:00
Peter Steinberger
172bc9d043 fix(plugin-sdk): keep test contracts publishable 2026-04-30 01:00:15 +01:00
Peter Steinberger
59982c2aa5 chore: update macOS appcast for 2026.4.27 2026-04-30 00:56:13 +01:00
Peter Steinberger
b113d92c6f docs: clarify managed proxy routing hooks 2026-04-30 00:55:52 +01:00
Peter Steinberger
b7c3e19ed6 fix: mark channel system events untrusted 2026-04-30 00:51:24 +01:00
Peter Steinberger
29de89a8d9 fix: align SDK wait and protocol contracts 2026-04-30 00:51:24 +01:00
Peter Steinberger
204d200be3 fix: preserve SDK run event outcomes 2026-04-30 00:51:24 +01:00
Peter Steinberger
43f6c8b01a feat: add OpenClaw SDK package 2026-04-30 00:51:24 +01:00
Peter Steinberger
01254500df fix(cli): preserve lazy command parent flags 2026-04-30 00:48:46 +01:00
Mike Harsh
36bb723dfb fix(github-copilot): support GUI/RPC wizard auth flow (#73290)
Merged via squash.

Prepared head SHA: aea7d6650c
Co-authored-by: indierawk2k2 <18598712+indierawk2k2@users.noreply.github.com>
Co-authored-by: shanselman <2892+shanselman@users.noreply.github.com>
Reviewed-by: @shanselman
2026-04-29 16:45:31 -07:00
Blasius Patrick
d30b8dccfd fix(pi-embedded): strip [tool calls omitted] from user-facing text (#74578)
* fix(pi-embedded): strip [tool calls omitted] from user-facing text

The internal replay placeholder '[tool calls omitted]' was leaking
into channel output (e.g. Telegram) after aborted tool calls.

Fix: strip the placeholder early in sanitizeUserFacingText so all
channels are protected by default. The replay transcript path in
turns.ts is unaffected — it uses the placeholder internally.

Fixes #74573.

Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>

* fix(pi-embedded): preserve whitespace when stripping placeholder

* test(pi-embedded): document replay placeholder sanitization

* fix(pi-embedded): strip consecutive replay placeholders

---------

Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 23:20:19 +00:00
Vincent Koc
845dd2a7d5 chore(ci): add provider runtime CodeQL quality shard
Adds a focused non-security CodeQL quality shard for provider runtime and model catalog contracts.
2026-04-29 16:15:38 -07:00
Shakker
6662dcf209 refactor: reuse provider auth lookup maps 2026-04-30 00:13:13 +01:00
Shakker
e327c96ce6 fix: preserve spawned workspace in models command 2026-04-30 00:13:13 +01:00
Shakker
a887df9cd5 fix: preserve workspace auth in model list alias 2026-04-30 00:13:13 +01:00
Shakker
7d4a0bb621 fix: preserve workspace auth labels in model status 2026-04-30 00:13:13 +01:00
Shakker
0d702f3e28 test: type model auth label env mock 2026-04-30 00:13:13 +01:00
Shakker
3b4d2d8886 fix: pass workspace auth evidence into model auth labels 2026-04-30 00:13:13 +01:00
Shakker
d3c6a8f0fb fix: use agent auth store for model status probes 2026-04-30 00:13:13 +01:00
Shakker
a0cf07ec10 fix: preserve workspace auth in model registry discovery 2026-04-30 00:13:13 +01:00
Shakker
4109446c2f fix: align model status auth evidence paths 2026-04-30 00:13:12 +01:00
Shakker
98e4c18e39 refactor: centralize provider auth evidence lookup 2026-04-30 00:13:12 +01:00
Shakker
b4ecc814c5 fix: align model auth display with workspace evidence 2026-04-30 00:13:12 +01:00
Shakker
2fe3e779ff fix: preserve workspace auth scope in runtime paths 2026-04-30 00:13:12 +01:00
Shakker
c4e249114d fix: thread workspace auth evidence through model auth 2026-04-30 00:13:12 +01:00
Shakker
1db2e63519 fix: align provider auth checker with config evidence 2026-04-30 00:13:12 +01:00
Shakker
9307affe59 fix: align runtime auth evidence with config trust 2026-04-30 00:13:12 +01:00
Shakker
10b9adb010 fix: trust-gate manifest auth evidence 2026-04-30 00:13:12 +01:00
Shakker
b8c77c1bd7 test: type google setup registration coverage 2026-04-30 00:13:12 +01:00
Shakker
68aedf3908 fix: register google vertex setup provider 2026-04-30 00:13:12 +01:00
Shakker
78f3470368 fix: preserve explicit auth evidence path semantics 2026-04-30 00:13:12 +01:00
Shakker
5a606947b5 docs: document manifest auth evidence 2026-04-30 00:13:12 +01:00
Shakker
dec5de8a2c fix: declare google vertex local auth evidence 2026-04-30 00:13:12 +01:00
Shakker
225620a9b3 refactor: resolve env auth evidence generically 2026-04-30 00:13:12 +01:00
Shakker
dd5b96c11d feat: expose provider auth evidence lookup 2026-04-30 00:13:12 +01:00
Shakker
1d1edca92f feat: add setup auth evidence metadata 2026-04-30 00:13:12 +01:00
Marcus Castro
4cba08df01 fix(whatsapp): remove exposeErrorText config (#74642)
* fix(whatsapp): remove exposeErrorText config

* fix(whatsapp): mark internal system events trusted
2026-04-29 20:03:58 -03:00
Peter Steinberger
426107d2f8 fix(telegram): retry invalid native quotes 2026-04-30 00:02:13 +01:00
Vincent Koc
d115faa367 chore: update security codeowners team 2026-04-29 15:57:17 -07:00
Vincent Koc
847d8fa0e1 chore(ci): add Plugin SDK reply CodeQL quality shard
Adds a focused non-security CodeQL quality shard for Plugin SDK reply/session delivery runtime contracts.
2026-04-29 15:56:41 -07:00
Peter Steinberger
6acd588bdd test(ci): update changed gate expectations 2026-04-29 23:49:48 +01:00
Vincent Koc
8f50920c45 chore(ci): add session diagnostics CodeQL quality shard
Adds a focused non-security CodeQL quality shard for session diagnostics, delivery queues, and related diagnostic contracts.
2026-04-29 15:29:03 -07:00
Peter Steinberger
c7e2aceb05 ci(dup): guard duplicate scan coverage 2026-04-29 23:24:57 +01:00
Peter Steinberger
4c712d3372 fix: add bundled plugin deps repair command 2026-04-29 23:23:14 +01:00
Peter Steinberger
9a3a341d93 refactor(channels): route remaining turns through kernel 2026-04-29 23:16:16 +01:00
Peter Steinberger
9a9cd0c0ab refactor(channels): add shared turn kernel 2026-04-29 23:16:16 +01:00
Peter Steinberger
4396361f35 fix(config): regenerate base schema help 2026-04-29 23:09:39 +01:00
Peter Steinberger
fa467c20e3 test: allow browser indirect zod runtime dependency 2026-04-29 23:03:06 +01:00
Vincent Koc
6717f8b334 chore(ci): add plugin trust CodeQL shard
Adds the plugin trust-boundary CodeQL security shard on Blacksmith and documents the rollout scope.
2026-04-29 15:02:06 -07:00
Peter Steinberger
a31b55a8d8 fix(config): document queue help options 2026-04-29 23:01:39 +01:00
Peter Steinberger
18faf22e15 fix(plugins): mirror global-agent runtime dependency (#74593)
* fix(plugins): mirror global-agent runtime dependency

* fix(plugins): update bundled dependency drift guard
2026-04-29 21:55:46 +00:00
Peter Steinberger
36ff8d78e4 fix: explain stuck session diagnostics 2026-04-29 22:55:27 +01:00
Peter Steinberger
4a6e10ece8 feat: default queueing to steer 2026-04-29 22:48:10 +01:00
Peter Steinberger
83267e99b0 chore: update dependencies 2026-04-29 22:42:45 +01:00
Vignesh Natarajan
05627f797e Docs: skip unsupported Mintlify locale nav 2026-04-29 14:38:56 -07:00
Michael Marr
aaf4cc6862 docs(slack): warn that groupPolicy allowlist requires channel IDs not names (#53112) 2026-04-29 14:36:38 -07:00
Gabriel A. Mays
f0f1635f9f Docs: add VPS admin hardening note (#54685) 2026-04-29 14:36:33 -07:00
Vincent Koc
71ab341f46 chore(ci): rename CodeQL auth security shard
Renames the default auth/secrets CodeQL security category from the generic javascript-typescript label to core-auth-secrets.

Proof:
- Branch CodeQL security run https://github.com/openclaw/openclaw/actions/runs/25134871512 passed on 1d9f727bfd.
- Core auth/secrets analysis 1200412263 returned 0 results.
- Branch open CodeQL alerts: none.
- Workflow Sanity, Blacksmith Testbox, Blacksmith Build Artifacts Testbox, and OpenGrep PR Diff passed.

Scope is label/config only: same paths, query pack, filters, timeout, and runner.
2026-04-29 14:32:34 -07:00
Peter Steinberger
b552e31563 test: update install smoke workflow contract 2026-04-29 22:31:17 +01:00
Peter Steinberger
ebff12e84f fix(agents): finalize embedded lifecycle backstop 2026-04-29 22:29:07 +01:00
Vignesh Natarajan
d51af16fab Docs: document inferred commitments 2026-04-29 14:28:22 -07:00
Peter Steinberger
21e2168b8f ci: shard install smoke release checks 2026-04-29 22:25:55 +01:00
Vincent Koc
bdbce3b1c2 fix(ci): align postpublish mirror fixtures 2026-04-29 14:25:26 -07:00
Peter Steinberger
fd8fae7af2 ci(dup): scan docs and security scripts 2026-04-29 22:23:52 +01:00
Vincent Koc
9b536ed3a9 fix(ci): declare bundled root mirrors 2026-04-29 14:20:06 -07:00
Peter Steinberger
6e351f2f05 docs: prefer clawsweeper mentions in skill 2026-04-29 22:18:44 +01:00
Vignesh Natarajan
aecde2b3ac Agents: simplify inferred commitment config (#74189) 2026-04-29 14:14:53 -07:00
Vignesh Natarajan
11771ec172 Agents: annotate post-compaction system event trust (#74189) 2026-04-29 14:14:53 -07:00
Vignesh Natarajan
7451415f36 Agents: fix heartbeat rebase conflict (#74189) 2026-04-29 14:14:53 -07:00
Vignesh Natarajan
f569ed0803 Agents: use runtime config for commitments command (#74189) 2026-04-29 14:14:53 -07:00
Vignesh Natarajan
95bf450dc9 Agents: address inferred commitments review (#74189) 2026-04-29 14:14:53 -07:00
Vignesh Natarajan
8e4035d09a Agents: add inferred commitments 2026-04-29 14:14:53 -07:00
clawsweeper[bot]
95a1356278 fix: Found one reliability bug: the new Docker-daemon-unavailable bran (#74520)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:10:38 -07:00
clawsweeper[bot]
cdb424a642 fix: Found one regression in the runtime dependency staging cache. The (#74517)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:09:31 -07:00
clawsweeper[bot]
12a82aa788 fix: Found two heartbeat regressions in the changed behavior: default (#74523)
* fix: Found two heartbeat regressions in the changed behavior: default

* fix: repair heartbeat task-block stripping

---------

Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper-repair <clawsweeper-repair@users.noreply.github.com>
2026-04-29 14:09:11 -07:00
clawsweeper[bot]
0b48a69ff2 fix: Found two actionable issues in the bundled runtime-deps staging c (#74526)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:08:57 -07:00
clawsweeper[bot]
27fafa4754 fix: Found two release-validation regressions in the new focused live- (#74562)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:08:45 -07:00
clawsweeper[bot]
7b97af4899 fix: Found one narrow regression risk in the new Ollama tool-call name (#74563)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:08:33 -07:00
clawsweeper[bot]
6378de91e7 fix: Found one low-severity route-question recall regression in the co (#74582)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:08:21 -07:00
clawsweeper[bot]
fbe41fbdfc fix(ci): Found one low-severity diagnostic bug in the new Full Release Val (#74513)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:08:07 -07:00
clawsweeper[bot]
296d07c22f fix(ci): Found one low-severity formatting bug in the new loose-list parag (#74518)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:07:55 -07:00
Peter Steinberger
0e46240543 docs: document clawsweeper autofix mode 2026-04-29 22:07:47 +01:00
clawsweeper[bot]
e4edefd0fc fix: Found one regression in model-list availability heuristics for pr (#74524)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:07:42 -07:00
clawsweeper[bot]
22ea08997e fix: The one-line picker change hides unauthenticated catalog rows in (#74530)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:07:29 -07:00
clawsweeper[bot]
e2ab5b98cc fix: Found one compatibility regression in the Discord public API barr (#74533)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:07:15 -07:00
clawsweeper[bot]
bf5541b4bf fix: Found one low-severity compatibility regression in the diagnostic (#74560)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:07:02 -07:00
clawsweeper[bot]
6fb729a451 fix: Found one low-severity diagnostics flag contract issue introduced (#74561)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 14:06:48 -07:00
clawsweeper[bot]
0e5d3cb0e5 fix: Found one regression in the exported transcript mobile sidebar tr (#74584)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
2026-04-29 14:06:35 -07:00
Peter Steinberger
df51878b0b fix(config): preserve empty patch objects 2026-04-29 22:02:02 +01:00
Peter Steinberger
ec7536078f fix(config): validate unresolved SecretRef refs in dry-run 2026-04-29 22:02:02 +01:00
Peter Steinberger
e3b7b4cf63 fix(channels): keep lazy bundled discovery off staged deps 2026-04-29 22:02:02 +01:00
Peter Steinberger
8b8bba9621 fix(config): tighten patch command semantics 2026-04-29 22:02:02 +01:00
Peter Steinberger
01893d725a docs: require full PR URLs in final answers 2026-04-29 22:02:02 +01:00
Peter Steinberger
48a01798b0 feat: add config apply patch command 2026-04-29 22:02:02 +01:00
clawsweeper[bot]
1e4a37fbfb fix(ci): Found three actionable i18n regressions: the touched i18n test fi (#74527)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 13:59:45 -07:00
Peter Steinberger
c160bec3d6 refactor(plugins): split runtime deps planner 2026-04-29 21:59:01 +01:00
Peter Steinberger
9ae7db5562 refactor(plugins): split runtime deps materialization 2026-04-29 21:59:01 +01:00
clawsweeper[bot]
585c2bdba3 fix: Found one low-severity UI localization regression in the markdown (#74600)
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 13:58:07 -07:00
Vincent Koc
fdf8ffaf3c fix(ci): exempt automation PRs from Barnacle PR limit
Treat ClawSweeper and Clownfish head refs as automation PRs for Barnacle's active-PR-limit close path, and cover the behavior with a regression test.
2026-04-29 13:58:06 -07:00
pash-openai
3b5dab372a Keep Codex Computer Use hook relays live across turns (#74107)
* Fix Codex native hook relay across processes

* fix: harden native hook relay bridge

* test: stabilize pairing store cache assertion

---------

Co-authored-by: pashpashpash <nik@vault77.ai>
2026-04-30 05:57:12 +09:00
Peter Steinberger
9ccd015898 ci: bound install smoke docker builds 2026-04-29 21:56:54 +01:00
Vincent Koc
1a4d55de43 test(plugins): split kitchen sink qa personalities (#74612) 2026-04-29 13:56:49 -07:00
Peter Steinberger
987af6805b docs: update clawsweeper repair cap 2026-04-29 21:55:35 +01:00
Peter Steinberger
b478262a9e ci(dup): add mixed duplicate scans 2026-04-29 21:50:38 +01:00
Vincent Koc
cd6efd1a42 chore(ci): add MCP process CodeQL shard
Adds the focused MCP/process/tool-execution CodeQL security shard and documents it in CI docs.

Proof:
- Branch CodeQL security run https://github.com/openclaw/openclaw/actions/runs/25132942030 passed on 9d8ca2bae7.
- New mcp-process-tool-boundary analysis 1200250367 returned 0 results.
- Branch open CodeQL alerts: none.
- Workflow Sanity, Blacksmith Testbox, Blacksmith Build Artifacts Testbox, and OpenGrep PR Diff passed.
2026-04-29 13:48:53 -07:00
Peter Steinberger
06fcd3b60e docs: document clawsweeper freeform mentions 2026-04-29 21:46:18 +01:00
Vincent Koc
2fa5590a93 docs: list all control ui locales 2026-04-29 13:42:07 -07:00
Peter Steinberger
65c9eddae8 fix(heartbeat): suppress metadata-only exec completion noise 2026-04-29 21:39:47 +01:00
Peter Steinberger
470098bd26 fix: keep embedded run lanes from wedging 2026-04-29 21:37:17 +01:00
Peter Steinberger
b83b639287 ci(dup): include test root in duplicate scan 2026-04-29 21:32:07 +01:00
Vincent Koc
6516be1023 fix(ci): stop ClawSweeper dispatch PAT fallback
Remove the maintainer PAT fallback from the ClawSweeper dispatch workflow so missing app auth fails closed instead of attributing downstream automation to a human token.
2026-04-29 13:26:02 -07:00
Peter Steinberger
7fc0859a01 perf(tests): split plugin state runtime imports 2026-04-29 21:21:38 +01:00
Peter Steinberger
12ee7f696f fix(ollama): avoid broad provider hooks for local runs 2026-04-29 21:20:48 +01:00
Vincent Koc
f1ec163f77 fix(browser): remove unused zod dependency 2026-04-29 13:18:50 -07:00
github-actions[bot]
576f64c242 chore(ui): refresh fa control ui locale 2026-04-29 20:17:45 +00:00
github-actions[bot]
0d1ac827b3 chore(ui): refresh nl control ui locale 2026-04-29 20:17:35 +00:00
github-actions[bot]
2bf2720632 chore(ui): refresh vi control ui locale 2026-04-29 20:16:53 +00:00
github-actions[bot]
63cc63e8e0 chore(ui): refresh th control ui locale 2026-04-29 20:16:29 +00:00
github-actions[bot]
e3484727ba chore(ui): refresh pl control ui locale 2026-04-29 20:16:20 +00:00
github-actions[bot]
565cb9029b chore(ui): refresh id control ui locale 2026-04-29 20:16:18 +00:00
github-actions[bot]
b31369a701 chore(ui): refresh uk control ui locale 2026-04-29 20:15:30 +00:00
github-actions[bot]
7e9326026e chore(ui): refresh tr control ui locale 2026-04-29 20:15:16 +00:00
Peter Steinberger
1738ebb385 fix(browser): declare zod runtime dependency 2026-04-29 21:15:03 +01:00
github-actions[bot]
c16a4dfce6 chore(ui): refresh it control ui locale 2026-04-29 20:15:00 +00:00
github-actions[bot]
185a3fcab8 chore(ui): refresh ar control ui locale 2026-04-29 20:14:56 +00:00
github-actions[bot]
5802fcb405 chore(ui): refresh ko control ui locale 2026-04-29 20:14:05 +00:00
github-actions[bot]
2925c801f7 chore(ui): refresh fr control ui locale 2026-04-29 20:14:01 +00:00
github-actions[bot]
92c30630ad chore(ui): refresh ja-JP control ui locale 2026-04-29 20:13:47 +00:00
github-actions[bot]
7c4c008de8 chore(ui): refresh es control ui locale 2026-04-29 20:13:39 +00:00
github-actions[bot]
fef8203de1 chore(ui): refresh zh-TW control ui locale 2026-04-29 20:12:43 +00:00
github-actions[bot]
82629225ac chore(ui): refresh zh-CN control ui locale 2026-04-29 20:12:39 +00:00
github-actions[bot]
b8f4338a94 chore(ui): refresh de control ui locale 2026-04-29 20:12:33 +00:00
github-actions[bot]
b799f6c451 chore(ui): refresh pt-BR control ui locale 2026-04-29 20:12:29 +00:00
Shakker
9c19335276 fix: package bundled runtime deps helper 2026-04-29 21:11:59 +01:00
Agustin Rivera
b8372a714c fix(auth): bound bootstrap handoff scopes (#72919)
* fix(auth): bound bootstrap handoff scopes

Co-authored-by: zsx <git@zsxsoft.com>

* fix(auth): log stripped bootstrap scopes

* docs: add changelog entry for bootstrap handoff scope bounds

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-29 14:11:16 -06:00
Vincent Koc
60c2a90550 fix(ui): gate control ui raw copy 2026-04-29 13:09:47 -07:00
Vincent Koc
c9156cd9a8 chore(ci): add network SSRF CodeQL shard
Adds a narrow critical-security CodeQL shard for the network/SSRF boundary and documents the new category.
2026-04-29 13:08:46 -07:00
Peter Steinberger
65e969aeea ci(dup): split duplicate scans 2026-04-29 21:02:24 +01:00
Agustin Rivera
fef42acda0 fix(commands): scope owner allowlist prefixes (#72928)
* fix(commands): scope owner allowlist prefixes

Co-authored-by: zsx <git@zsxsoft.com>

* fix(commands): annotate owner allowlist short-circuit

* docs: move changelog entry to unreleased fixes

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-29 14:00:07 -06:00
Josh Lehman
f05b789736 test: align Codex provider payload test (#74536) 2026-04-29 12:56:27 -07:00
Michael Appel
665b0ef542 fix(agents): move groupId trust check into resolveGroupToolPolicy for all callers [AI-assisted] (#73720)
* fix: address issue

* fix: address review feedback

* fix(gateway): validate groupId against session key before persisting to session entry

* test(gateway): verify groupId is validated against session key before session entry write

* fix(agents): trust stored group metadata

* fix(gateway): keep first group selectors

* docs: add group policy trust changelog entry

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-29 13:56:26 -06:00
clawsweeper[bot]
7c51cd2baf fix(device-pair): reject invalid remote setup URLs
Fail setup-code generation when gateway.remote.url is configured but malformed, instead of falling back to a bind-derived URL and issuing a bootstrap token.
2026-04-29 20:45:33 +01:00
Vincent Koc
21b3eb5c34 test(memory-wiki): remove duplicate fixture keys 2026-04-29 12:43:01 -07:00
Peter Steinberger
dac7237494 ci: shard release validation hotspots 2026-04-29 20:40:42 +01:00
Peter Steinberger
fdba408bce fix: restore codex verbose full output 2026-04-29 20:36:36 +01:00
clawsweeper[bot]
8a3507e310 fix(memory-wiki): route natural people questions
Let route-question searches match people-routing metadata from natural-language prompts, and allow wiki_apply evidence provenance fields that the markdown parser already supports.
2026-04-29 20:36:31 +01:00
Devin Robison
4808361fca fix: gate startup context for sandboxed spawned sessions (#73611)
* fix: gate startup context for sandboxed spawned sessions

* docs: add startup sandbox changelog entry

* fix: address startup sandbox review feedback

* test: format startup sandbox coverage
2026-04-29 13:35:55 -06:00
Vincent Koc
3abc90aac5 test(scripts): remove managed child race 2026-04-29 12:34:41 -07:00
Val Alexander
323985f4ca fix(ui): align sidebar trigger affordances
Align the Control UI and exported transcript sidebar triggers around a shared accessible hamburger affordance.
2026-04-29 20:33:39 +01:00
Vincent Koc
f55b810412 docs(changelog): backfill last 6h user-facing entries
Adds six missing entries for commits that landed without their own
CHANGELOG.md update, picked from the last six hours of origin/main and
attributed to the original contributors.

Changes:
- Control UI/i18n locale registry expansion + new docs glossaries
  (297f4c6e60, 0126692bf5 by @vincentkoc).
- Gateway/diagnostics opt-in startup timeline (097eed8cd8, d001c3436b,
  e69da9d578 by @shakkernerd).

Fixes:
- Matrix `verify confirm-sas` cross-signing close (86956f71e6 by
  @nklock; #74542).
- `openclaw status` channel context-window overrides (eb7d89f4b9 by
  @HemantSudarshan).
- Sandbox Docker daemon graceful when sandbox mode is off (2dadc82cf4
  by @kaseonedge; #73671).
- Control UI mobile chat settings persisted via Lit state (b1c515270e
  by @BunsDev).

Skipped Peter-only commits with no external collaborator (per the
maintainer-attribution rule against thanking @steipete) and the model
list auth-index series (already covered by the existing "Models/UI:
hide unauthenticated providers" entry).
2026-04-29 12:31:29 -07:00
Jeff
9b6670d5c9 fix(ssrf): allow IPv6 fake-ip SSRF opt-in
Allow trusted fake-IP proxy stacks to opt into IPv6 unique-local SSRF resolution without opening broader private-network access.
2026-04-29 20:31:17 +01:00
github-actions[bot]
cd00a6d6dd chore(ui): refresh fa control ui locale 2026-04-29 19:29:08 +00:00
github-actions[bot]
070129f34f chore(ui): refresh nl control ui locale 2026-04-29 19:28:59 +00:00
github-actions[bot]
d6918113f0 chore(ui): refresh vi control ui locale 2026-04-29 19:28:23 +00:00
github-actions[bot]
9ffc2f9d06 chore(ui): refresh th control ui locale 2026-04-29 19:27:46 +00:00
github-actions[bot]
38694111aa chore(ui): refresh id control ui locale 2026-04-29 19:27:43 +00:00
github-actions[bot]
ec0836693c chore(ui): refresh pl control ui locale 2026-04-29 19:27:40 +00:00
Vincent Koc
e1c97cb24d fix(memory-wiki): satisfy CI guard checks 2026-04-29 12:27:22 -07:00
github-actions[bot]
9af0a7153e chore(ui): refresh it control ui locale 2026-04-29 19:26:53 +00:00
github-actions[bot]
5de9145562 chore(ui): refresh ar control ui locale 2026-04-29 19:26:45 +00:00
github-actions[bot]
fe15e1e83e chore(ui): refresh uk control ui locale 2026-04-29 19:26:43 +00:00
github-actions[bot]
dba4487d05 chore(ui): refresh tr control ui locale 2026-04-29 19:26:28 +00:00
github-actions[bot]
fd98ce3c15 chore(ui): refresh ko control ui locale 2026-04-29 19:25:41 +00:00
github-actions[bot]
8b54c71f90 chore(ui): refresh fr control ui locale 2026-04-29 19:25:36 +00:00
github-actions[bot]
09d7c66c06 chore(ui): refresh ja-JP control ui locale 2026-04-29 19:25:27 +00:00
github-actions[bot]
9168ad1b19 chore(ui): refresh es control ui locale 2026-04-29 19:25:06 +00:00
github-actions[bot]
6e940d3cc8 chore(ui): refresh de control ui locale 2026-04-29 19:24:37 +00:00
github-actions[bot]
e2ffc49f9a chore(ui): refresh zh-TW control ui locale 2026-04-29 19:24:34 +00:00
github-actions[bot]
da0e96dbbb chore(ui): refresh pt-BR control ui locale 2026-04-29 19:24:27 +00:00
Peter Steinberger
d2e55b01f2 perf(tests): speed up channel plugin id tests 2026-04-29 20:24:12 +01:00
Peter Steinberger
4aedffd37a refactor(plugins): split loader runtime helpers (#74545)
* refactor(plugins): split loader runtime helpers

* test(scripts): include discord api barrel lane

* test(ci): align built artifact guard expectations

* fix(plugins): avoid redundant cache key assertion
2026-04-29 19:22:41 +00:00
openclaw-clownfish[bot]
648ed69f82 fix(control-ui): repair zh-CN localization coverage
Route remaining Control UI agent, debug, channel refresh, and exec approval copy through the locale source of truth.

Preserve the English Cron Jobs tab label, keep the security audit command monospace, and regenerate locale metadata against current main.

Verified locally:
- pnpm test ui/src/ui/views/agents.test.ts ui/src/ui/views/debug.test.ts ui/src/ui/views/exec-approval.test.ts
- pnpm ui:i18n:check
- pnpm exec oxfmt --check --threads=1 ui/src/i18n/locales/en.ts ui/src/i18n/locales/zh-CN.ts ui/src/ui/views/agents-panels-status-files.ts ui/src/ui/views/agents.ts ui/src/ui/views/agents.test.ts ui/src/ui/views/debug.ts ui/src/ui/views/debug.test.ts ui/src/ui/views/exec-approval.ts ui/src/ui/views/exec-approval.test.ts
- git diff --check origin/main...HEAD
2026-04-29 14:22:36 -05:00
Peter Steinberger
3059702687 feat(memory-wiki): add agent-facing people wiki metadata 2026-04-29 20:17:37 +01:00
Vyctor Huggo Przozwski da Silva
ccb8472daf fix(agents): preserve seeded Anthropic text blocks
* fix(agents): preserve seeded Anthropic text blocks

* docs(changelog): note Anthropic seeded block fix

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 20:16:52 +01:00
辉哥
4eb30fc13a fix(media): surface vision pipeline diagnostics
* fix: improve error message in optimizeImageToJpeg to include actual error details

* fix: improve error message to include configured input for Model does not support images

* fix(media): surface vision pipeline diagnostics

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 20:13:19 +01:00
Peter Steinberger
945c910f20 test: remove redundant migration runtime assertion 2026-04-29 20:09:50 +01:00
Vincent Koc
26c03c761f test(ci): align CI guard expectations 2026-04-29 12:09:09 -07:00
Vyctor Huggo Przozwski da Silva
06b1d4e0f7 fix(agents): avoid empty Codex Responses input 2026-04-29 20:08:49 +01:00
Peter Steinberger
4b4e0c82e4 perf(tests): avoid channel plugin imports in system prompt 2026-04-29 20:06:07 +01:00
Peter Steinberger
b0ae867034 refactor(migration): share cached config runtime helper 2026-04-29 20:05:23 +01:00
Vyctor Huggo Przozwski da Silva
97e2f5b332 fix(auto-reply): honor direct silent empty replies
* fix(auto-reply): allow direct silent empty replies

* fix(auto-reply): guard direct silent empty replies
2026-04-29 20:02:38 +01:00
Hemant Sudarshan
eb7d89f4b9 fix(status): honor channel model context windows 2026-04-29 19:58:21 +01:00
Peter Steinberger
57e4994caf ci: speed up release validation 2026-04-29 19:55:37 +01:00
clawsweeper[bot]
fc2d957923 test(infra): assert dotenv logger warning sink
Co-authored-by: openclaw-clawsweeper[bot] <280122609+openclaw-clawsweeper[bot]@users.noreply.github.com>
2026-04-29 19:55:18 +01:00
Shakker
e69da9d578 fix: honor config timeline diagnostics 2026-04-29 19:53:55 +01:00
Shakker
d001c3436b fix: gate diagnostics timeline by flag 2026-04-29 19:53:55 +01:00
Shakker
097eed8cd8 feat: emit diagnostics timeline 2026-04-29 19:53:55 +01:00
Hemant Sudarshan
db6951088a fix(telegram): keep unreachable polling sockets non-fatal
* Runtime: suppress transient network uncaught exceptions

* fix(telegram): keep unreachable polling sockets non-fatal

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 19:53:43 +01:00
Simone
dabf76b3de fix(device-pair): validate public setup urls (#74538)
* fix(device-pair): validate public setup urls

* test(cli): cover invalid qr override urls

---------

Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 19:47:35 +01:00
Peter Steinberger
c728d604b2 fix: harden parallels smoke harness 2026-04-29 19:44:50 +01:00
Natalie K
86956f71e6 fix(matrix): close owner-side device verification loop on SAS confirm (#74542)
* fix(matrix): close owner-side device verification loop on SAS confirm

After SAS confirm via the `openclaw matrix verify confirm-sas` CLI, the
operator's Element X stayed in "Verifying…" because three things on the
bot side did not happen before the verb returned:

1. confirmVerificationSas didn't await the rust-crypto verifier promise.
   `Verifier.verify()` resolves only after both sides exchange MACs and
   the protocol fully settles, including cross-signing-key uploads
   triggered by `crossSignDevice`. Returning early meant Element X's
   next /keys/query saw an inconsistent state and the prompt persisted.

2. The 30s auto-confirm path (used when the operator initiates from
   their phone) explicitly passed `{ trustOwnDevice: false }`, so the
   bot never cross-signed its own device on this path. The check inside
   trustOwnDeviceAfterConfirmedSas already gates on isSelfVerification,
   so flipping the flag is safe — non-self requests remain a no-op.

3. The standalone `confirmMatrixVerificationSas` action did not call
   `trustOwnIdentityAfterSelfVerification` (only the higher-level
   `runMatrixSelfVerification` path did). Without that call, the bot
   had not signed the operator's master key, so Element X had no path
   to clear the prompt without a passive sync tick.

Three additive edits:

- verification-manager.ts (confirmVerificationSas): await
  session.verifyPromise after confirmSasForSession returns.
  verifyPromise is the .then().catch() chain set by
  ensureVerificationStarted, which already routes rejections into
  session.error, so awaiting it cannot double-throw.
- verification-manager.ts (maybeAutoConfirmSas): pass
  { trustOwnDevice: true } so the auto-confirm path also cross-signs
  the bot device for self-verifications.
- actions/verification.ts (confirmMatrixVerificationSas): mirror the
  trustOwnIdentityAfterSelfVerification call from
  completeMatrixSelfVerification when the returned summary indicates
  isSelfVerification.

Tests:
- verification-manager.test.ts: flipped the existing "auto-confirmed
  self-verification" assertion (now expects trustOwnDeviceAfterSas to
  be called); added two new tests for verifyPromise await and
  rejection-on-summary.error.
- actions/verification.test.ts: two new tests asserting
  confirmMatrixVerificationSas calls trustOwnIdentityAfterSelfVerification
  on self-verifications and not on remote verifications.

Verified end-to-end against matrix.thepolycule.ca (Synapse 1.145.0+ess.1,
MAS-fronted): after `verify confirm-sas`, Element X's device-list view
shows the bot device with a green shield and no pending Verify prompt.

* fix(matrix): guard owner trust after failed SAS verification

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 19:42:45 +01:00
Peter Steinberger
072e73d7c3 fix(codex): release quiet app-server turns 2026-04-29 19:42:02 +01:00
Hemant Sudarshan
fbae2a6441 Fix gateway timeout embedded fallback session lock (#74543)
* Agent: isolate gateway timeout fallback sessions

* fix(cli): isolate gateway timeout fallback sessions

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 19:38:11 +01:00
Peter Steinberger
89f871679e fix(ollama): normalize prefixed tool calls 2026-04-29 19:28:53 +01:00
Blasius Patrick
f5aebe42e1 fix(security): resolve model aliases before audit classification (#74532)
* fix(security): resolve model aliases before audit classification

Before classification, model strings are now resolved through the alias
index so that configured aliases (e.g. 'gpt-prev') are translated to
their canonical provider/key form (e.g. 'openai/gpt-5.4') before hygene
and tier checks run.

Fixes #74455.

Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>

* fix(security): share audit model alias resolution

---------

Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 19:26:02 +01:00
Val Alexander
b1c515270e fix(control-ui): keep mobile chat settings in Lit state
Move the mobile chat settings dropdown open state into Lit-owned app state.

- Render the dropdown open class and ARIA disclosure attributes from state.
- Add Escape, outside pointer, tab-change cleanup, and focus restoration.
- Cover closed/open render state and mounted app dismissal flows with browser tests.

Validation:
- pnpm test ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/navigation.browser.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/ui/app.ts ui/src/ui/app-view-state.ts ui/src/ui/app-render.helpers.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/navigation.browser.test.ts
- node scripts/run-oxlint.mjs --tsconfig tsconfig.oxlint.core.json ui/src/ui/app.ts ui/src/ui/app-view-state.ts ui/src/ui/app-render.helpers.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/navigation.browser.test.ts
2026-04-29 13:25:41 -05:00
Peter Steinberger
68912111cf fix(slack): avoid generic inline button prompt hint 2026-04-29 19:15:49 +01:00
Peter Steinberger
4bc79f9737 test: relax live web search timeouts 2026-04-29 19:14:15 +01:00
Vincent Koc
39ecedb300 test(gateway): complete reload model config fixture 2026-04-29 11:09:38 -07:00
Peter Steinberger
7e1acf2f1e refactor(discord): split threading and voice segment helpers 2026-04-29 19:09:17 +01:00
Peter Steinberger
6470a23504 fix(slack): ignore duplicate reaction adds 2026-04-29 19:07:08 +01:00
Vincent Koc
b54c642bd6 test(infra): assert dotenv structured warning 2026-04-29 11:04:45 -07:00
Vincent Koc
edf579c406 test(gateway): align reload model visibility fixture 2026-04-29 11:04:45 -07:00
Peter Steinberger
db665a09cd fix(slack): expose fileId in message tool schema 2026-04-29 19:02:30 +01:00
Peter Steinberger
43b084e5fa refactor(discord): split message and binding helpers 2026-04-29 19:00:44 +01:00
Peter Steinberger
efefba2db1 refactor(plugins): split bundled runtime deps jiti aliases 2026-04-29 18:57:05 +01:00
github-actions[bot]
2a7d83b6ad chore(ui): refresh fa control ui locale 2026-04-29 17:45:55 +00:00
github-actions[bot]
6e5a703dd2 chore(ui): refresh vi control ui locale 2026-04-29 17:42:18 +00:00
github-actions[bot]
14118d4bc1 chore(ui): refresh nl control ui locale 2026-04-29 17:42:10 +00:00
github-actions[bot]
b10dd5f3ae chore(ui): refresh ar control ui locale 2026-04-29 17:40:48 +00:00
Vincent Koc
139815d6a9 test(i18n): align locale registry expectations 2026-04-29 10:40:07 -07:00
github-actions[bot]
a7414f728b chore(ui): refresh it control ui locale 2026-04-29 17:39:54 +00:00
Vincent Koc
0126692bf5 fix(docs): allow Thai navigation locale 2026-04-29 10:39:43 -07:00
github-actions[bot]
b0d649b4cb chore(ui): refresh th control ui locale 2026-04-29 17:38:50 +00:00
github-actions[bot]
5ca401f974 chore(ui): refresh pl control ui locale 2026-04-29 17:38:31 +00:00
github-actions[bot]
6ba66c8a8d chore(ui): refresh id control ui locale 2026-04-29 17:38:01 +00:00
github-actions[bot]
58405c70cd chore(ui): refresh uk control ui locale 2026-04-29 17:37:10 +00:00
github-actions[bot]
6ef98f48aa chore(ui): refresh tr control ui locale 2026-04-29 17:37:00 +00:00
github-actions[bot]
0b79e4a223 chore(ui): refresh es control ui locale 2026-04-29 17:36:12 +00:00
github-actions[bot]
7e20f368dd chore(ui): refresh fr control ui locale 2026-04-29 17:36:10 +00:00
github-actions[bot]
35293d3eb2 chore(ui): refresh ja-JP control ui locale 2026-04-29 17:36:07 +00:00
github-actions[bot]
e6acc74db6 chore(ui): refresh ko control ui locale 2026-04-29 17:36:04 +00:00
github-actions[bot]
bfdd255b92 chore(ui): refresh zh-CN control ui locale 2026-04-29 17:35:14 +00:00
github-actions[bot]
5ed819af7b chore(ui): refresh zh-TW control ui locale 2026-04-29 17:35:09 +00:00
github-actions[bot]
44ff41aa77 chore(ui): refresh de control ui locale 2026-04-29 17:35:05 +00:00
github-actions[bot]
542606bea7 chore(ui): refresh pt-BR control ui locale 2026-04-29 17:35:03 +00:00
Vincent Koc
297f4c6e60 feat(i18n): align docs and ui locales 2026-04-29 10:25:47 -07:00
Shakker
c85ff84334 test: type model picker env auth mock 2026-04-29 18:23:40 +01:00
Shakker
fba8af4d62 test: align model picker auth mock 2026-04-29 18:23:40 +01:00
Shakker
587ce45ec9 fix: preserve google vertex adc auth fallback 2026-04-29 18:23:40 +01:00
Shakker
1df1ee48c0 fix: keep model list synthetic auth refs exact 2026-04-29 18:23:39 +01:00
Shakker
fceaecd123 test: type model list auth snapshot mock 2026-04-29 18:23:39 +01:00
Shakker
69181342e1 fix: preserve manifest-backed model list auth 2026-04-29 18:23:39 +01:00
Shakker
be1037fd34 test: tighten model list auth fixtures 2026-04-29 18:23:39 +01:00
Shakker
bfb6b82ffd docs: document model list auth index 2026-04-29 18:23:39 +01:00
Shakker
87bd12b2d3 fix: include local model list auth markers 2026-04-29 18:23:39 +01:00
Shakker
b418c08a22 refactor: use auth index for model list rows 2026-04-29 18:23:39 +01:00
Shakker
a777b82da0 feat: add model list auth index 2026-04-29 18:23:39 +01:00
Vincent Koc
0e0ade80a0 fix(codex): remove redundant abort signal assertion 2026-04-29 10:22:20 -07:00
Peter Steinberger
09baec68ea fix(codex): bound dynamic tool bridge responses 2026-04-29 18:13:53 +01:00
Peter Steinberger
a16f7fb6cd test(models): update auth profile mock 2026-04-29 18:05:34 +01:00
Peter Steinberger
8a06db084d fix(models): hide unauthenticated catalog entries 2026-04-29 18:05:34 +01:00
jindongfu
2bb16f771b fix(model-picker): hide models from providers without auth configured
Previously, models from unconfigured providers were shown with an
"auth missing" hint, flooding the picker with 900+ unusable entries.

Now addModelSelectOption early-returns when the provider has no auth,
so only usable models appear in /models and the web chat dropdown.

Fixes #74423
2026-04-29 18:05:34 +01:00
Peter Steinberger
e3af6fb3c8 docs: document ClawSweeper review command 2026-04-29 18:05:03 +01:00
Peter Steinberger
dcd428e8c1 refactor(discord): split preflight and native command helpers 2026-04-29 18:03:32 +01:00
Simone
630629667c fix(markdown): preserve loose list paragraphs (#74474)
* fix(markdown): preserve loose list paragraphs

* fix(markdown): avoid loose nested list triples

* fix(markdown): keep tight list block spacing

* fix(markdown): scope loose list paragraphs

* docs(changelog): credit markdown list spacing fix

---------

Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 17:56:51 +01:00
Sekhar Parida
3215ab6de5 infra: fix heartbeat directive preservation and global enablement (#74471)
* refactor(security): replace console.warn with structured logger in windows-acl

* infra: fix heartbeat directive preservation and global enablement

* logging: migrate dotenv and temp-download to subsystem logger

* logging: migrate command-auth, unhandled-rejections, and index to subsystem logger

* logging: migrate config defaults to subsystem logger

* fix(heartbeat): preserve heartbeat task context

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 17:49:41 +01:00
Peter Steinberger
9f21335462 ci: reduce release runner queue pressure 2026-04-29 17:45:53 +01:00
Peter Steinberger
b53ec93ed9 refactor(plugins): split bundled runtime deps staging script 2026-04-29 17:43:46 +01:00
Peter Steinberger
e420592bdf refactor(discord): split runtime helpers 2026-04-29 17:43:07 +01:00
Jesse Merhi
6de9d71bfb feat(security): add GHSA detector-review pipeline and OpenGrep CI workflows (#69483)
* feat(security): add GHSA detector-review pipeline and OpenGrep CI workflows [AI-assisted]

Stand up an end-to-end pipeline that turns every published openclaw GitHub
Security Advisory into a reusable OpenGrep rule, and wire the compiled rules
into manual-dispatch GitHub Actions workflows that publish SARIF to GitHub
Code Scanning.

The pipeline is harness-agnostic: any coding-agent CLI (Rovo Dev, Claude
Code, Codex, OpenCode, or anything you can shell out to) can drive it via
the runner script's --harness flag. Built-in adapters cover the four common
harnesses; --harness-cmd '<template>' supports anything else with shell-style
{prompt}/{model}/{output_file} substitution.

Pipeline pieces:

- scripts/run-ghsa-detector-review-batch.mjs runs your chosen coding harness
  in parallel against every advisory using the agent-agnostic detector-review
  spec at security/detector-review/detector-review-spec.md. Each case
  produces an opengrep general-rule.yml (precise) and broad-rule.yml
  (review-aid), plus a coverage-validated report against the vulnerable
  commit's changed files.
- scripts/compile-opengrep-rules.mjs walks a run directory, rewrites each
  rule's id to ghsa-detector.<ghsa>.<orig-id>, injects ghsa/advisory-url/
  detector-bucket/source-rule-id metadata, and uses opengrep itself to drop
  rules with InvalidRuleSchemaError so the published super-configs load
  cleanly.

Compiled outputs:

- security/opengrep/precise.yml     (336 rules)
- security/opengrep/broad.yml       (459 rules)
- security/opengrep/compile-manifest.json    (per-rule provenance map)

CI workflows (manual workflow_dispatch only):

- .github/workflows/opengrep-precise.yml
- .github/workflows/opengrep-broad.yml

Both install a pinned opengrep, run opengrep scan against src/, upload SARIF
to Code Scanning under categories opengrep-precise / opengrep-broad, and use
continue-on-error: true so findings never block the workflow.

Detector-review spec and assets:

- security/detector-review/detector-review-spec.md   the agent-agnostic spec
  the runner injects into each per-case prompt
- security/detector-review/references/{detector-rubric,report-template}.md
- security/detector-review/scripts/init_case.py
- security/prompt-suffix-coverage-first.md   mandatory prompt addendum that
  enforces coverage-first validation (rule must catch the OG vuln, not just
  pass synthetic fixtures)

Docs:

- security/README.md          end-to-end flow, supported harnesses, regen recipe
- security/opengrep/README.md compiled-config details + recompile recipe

* security: tighten GHSA OpenGrep detector workflow

* chore: refine precise opengrep workflow

* chore: remove stale opengrep metadata

* fix: harden GHSA OpenGrep workflow

* ci: split OpenGrep diff and full scans

* chore: remove performance-only opengrep rule

* ci: use OpenGrep installer path

* chore: enforce opengrep rule metadata provenance

* chore: generalize opengrep rule compilation

* docs: align opengrep rulepack guidance

* chore: support generic opengrep rule sources

* fix: validate opengrep rulepack-only changes

---------

Co-authored-by: Jesse Merhi <security-engineering@atlassian.com>
2026-04-30 02:42:20 +10:00
Peter Steinberger
c7aaa40848 perf(test): trim bundled runtime deps imports 2026-04-29 17:39:27 +01:00
Peter Steinberger
0519107bd3 refactor(plugins): share bundled runtime deps install script helpers 2026-04-29 17:35:01 +01:00
Peter Steinberger
f4af0777a7 fix(discord): remove duplicate public policy export 2026-04-29 17:33:33 +01:00
openclaw-clawsweeper[bot]
63fe2e12d7 fix(clawsweeper): address review for clawsweeper-commit-openclaw-openclaw-587b537b4745 (1) 2026-04-29 17:33:33 +01:00
openclaw-clawsweeper[bot]
4e115c5dbb fix: Found one compatibility regression in the published Discord plugi 2026-04-29 17:33:33 +01:00
Peter Steinberger
9d03cd15a9 refactor(plugins): split bundled runtime deps helpers 2026-04-29 17:32:14 +01:00
Peter Steinberger
5201c42251 refactor(discord): split messaging runtime actions 2026-04-29 17:31:53 +01:00
openclaw-clawsweeper[bot]
a512b5dde9 fix: The commit introduces imports from `src/channels/plugins/dm-acces 2026-04-29 17:31:11 +01:00
Carl
5e384fed6d fix(google): prevent empty contents error for gemini (#74465)
* fix(google): prevent empty contents error for gemini

* test(google): cover empty Gemini contents fallback

* docs(changelog): note Gemini empty content fallback

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 17:30:51 +01:00
Vyctor Huggo Przozwski da Silva
df0074768c fix(exec): reject invalid host targets (#74468)
* fix(exec): reject invalid host targets

* docs(changelog): credit exec host validation contributor

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 17:25:45 +01:00
Agustin Rivera
9a0b43c47e feat(nvidia): add NVIDIA provider with onboarding flow (#71204)
* feat(nvidia): add NVIDIA provider with onboarding flow

Add the NVIDIA build.nvidia.com API as a bundled provider. Default model
is nvidia/nvidia/nemotron-3-super-120b-a12b: first segment is the provider
id, remaining "nvidia/nemotron-3-super-120b-a12b" is the literal upstream
model id (which happens to start with "nvidia/" because NVIDIA is also the
model maker).

Supporting core change: introduce a provider capability flag
nativeIdsIncludeProviderPrefix so providers whose native catalog ids
intentionally include their provider prefix (OpenRouter) opt into self-prefix
dedupe in modelKey, without hardcoding provider names in core. Providers
whose ids merely happen to start with their own name (NVIDIA) leave the flag
unset and get the full <provider>/<model-id> concatenation.

- extensions/nvidia/*: new plugin, catalog, onboarding, tests, docs
- extensions/openrouter/index.ts: declare nativeIdsIncludeProviderPrefix
- src/plugins/types.ts: add field to ProviderPlugin
- src/plugins/registry.ts: populate self-prefix set on registration
- src/agents/provider-self-prefix.ts: sync accessor used by modelKey
- src/agents/model-ref-shared.ts: modelKey consults the flag
- test updates for affected surfaces

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

* refactor(model-picker): simplify literal-prefix display to label-only

* fix(model-picker): pass workspaceDir/env to allowlist literal-prefix resolution

* chore: untrack generated baseline JSON artifacts (gitignored)

* fix(nvidia): show literal model ref in picker and onboarding notes

* fix(nvidia): show hint whenever display label differs from stored config

* fix(nvidia): drop redundant hint from Keep current label

* fix(nvidia): restore literal double-prefix display labels

* fix(picker): handle literal-prefix fast path

* fix(picker): show literal keep label

* fix(docs): update nvidia provider docs

* fix(nvidia): update test helper imports

* fix(changelog): add nvidia provider entry

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 09:25:12 -07:00
edge_kase
2dadc82cf4 fix(sandbox): gracefully handle Docker daemon unavailability when sandbox mode is off (#73671)
Merged via squash.

Prepared head SHA: 378851cf40
Co-authored-by: kaseonedge <15183881+kaseonedge@users.noreply.github.com>
Co-authored-by: sallyom <11166065+sallyom@users.noreply.github.com>
Reviewed-by: @sallyom
2026-04-29 12:23:30 -04:00
Peter Steinberger
e46dccb353 fix(discord): clarify command deploy rate-limit logs 2026-04-29 17:19:40 +01:00
Peter Steinberger
7471c2116f ci: use smaller runners for native live shards 2026-04-29 17:16:26 +01:00
Peter Steinberger
8cf724a381 fix(plugins): simplify bundled runtime deps staging
* fix(plugins): simplify bundled runtime deps staging

* refactor(plugins): declare bundled root runtime deps

* fix(plugins): isolate pnpm runtime dependency installs

* test(gateway): wait for deferred agent routing calls in server suite

* test(ci): follow extracted update-channel assertions

* fix(plugins): bypass pnpm age gate for bundled runtime deps

* test: drop stale rebase leftovers

* test: preserve mirrored root dependency drift guard

* test: stage mirrored deps in facade fixtures

* fix(plugin-sdk): expose provider setup metadata

* test(plugin-sdk): satisfy spread lint in facade deps fixture

* refactor(plugins): share bundled runtime deps install flow

* fix(plugins): finish runtime deps rebase cleanup

* fix(plugins): remove stale mirror import

* refactor(plugins): centralize bundled runtime root preparation

* fix(plugins): skip Windows pnpm cmd shims

* refactor(plugins): let package managers own runtime deps staging

* fix(plugins): validate staged runtime deps

* fix(plugins): preserve lazy runtime deps fallback
2026-04-29 17:04:56 +01:00
Peter Steinberger
86f473d8b9 ci: isolate moonshot live shard 2026-04-29 17:03:48 +01:00
Cathryn Lavery
763a88083e fix(gateway): persist hidden lifecycle session keys (#74442)
* Prevent hidden channel lifecycle runs from staying stuck as running

Hidden channel-routed runs were dropping session keys on lifecycle events at
our shared agent-event bus. Gateway lifecycle persistence then had to rely on
run-context lookup surviving until the terminal event, which is unnecessarily
fragile for the exact sessions that are intentionally hidden from Control UI.

This keeps session keys on hidden lifecycle events only, preserving the existing
privacy boundary for assistant/tool traffic while making terminal session-state
persistence explicit and test-covered.

Constraint: Hidden channel runs must stay out of Control UI chat/tool streams
Rejected: Broaden sessionKey preservation to every hidden event | would expose more hidden traffic than needed
Confidence: medium
Scope-risk: narrow
Reversibility: clean
Directive: If hidden-run event redaction changes again, keep lifecycle persistence independent from ephemeral run-context lookup
Tested: pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/infra/agent-events.ts src/infra/agent-events.test.ts; pnpm tsgo:core; pnpm tsgo:extensions; pnpm tsgo:core:test; pnpm tsgo:extensions:test; pnpm test src/infra/agent-events.test.ts; pnpm test src/gateway/server-chat.agent-events.test.ts; pnpm test src/gateway/session-lifecycle-state.test.ts; pnpm lint:extensions:bundled; codex exec review returned ship it
Not-tested: Live gateway reproduction against Knox's local stuck-session install

* Clarify hidden lifecycle redaction and cover context fallback

The follow-up review asked for two things: document why the separate error
stream stays redacted for hidden runs, and cover the registered-context fallback
branch for hidden lifecycle events when callers omit sessionKey.

Constraint: Hidden assistant/tool/error diagnostics must remain redacted from Control UI
Rejected: Preserve sessionKey on the generic error stream | terminal persistence already flows through lifecycle phase:error, so widening the visible identity surface is unnecessary
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep hidden-run identity exceptions tightly scoped to terminal lifecycle persistence unless a concrete downstream consumer requires more
Tested: pnpm exec oxfmt --write --threads=1 src/infra/agent-events.ts src/infra/agent-events.test.ts; pnpm test src/infra/agent-events.test.ts; pnpm test src/gateway/server-chat.agent-events.test.ts; pnpm test src/gateway/session-lifecycle-state.test.ts
Not-tested: Full repo gate rerun; previous branch-wide gates remain from the parent PR commit

* fix(gateway): keep hidden agent broadcasts redacted

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 17:03:10 +01:00
Peter Steinberger
58db3d2d22 perf(test): trim media runner import cost 2026-04-29 16:59:42 +01:00
Peter Steinberger
e8b82d1cf9 refactor(discord): split component auth helpers 2026-04-29 16:56:17 +01:00
Peter Steinberger
334f4624e0 ci: avoid blacksmith for release setup jobs 2026-04-29 16:55:08 +01:00
Peter Steinberger
61d53f98d3 fix(cron): clean up timed out agent runs 2026-04-29 16:54:22 +01:00
Devin Robison
c1a42dce86 fix: enforce focus subagent scope (#73613)
* fix: enforce focus subagent scope

* docs: add changelog for focus scope fix
2026-04-29 09:54:09 -06:00
Peter Steinberger
b48f6ca1fc fix(ui): bind dashboard breadcrumb handler 2026-04-29 16:54:05 +01:00
Peter Steinberger
8d63ddce69 fix: harden runtime deps lock owner identity 2026-04-29 16:54:05 +01:00
Jim Smith
2d885a2402 fix(plugins): disambiguate runtime-deps lock owners by process start-time
`shouldRemoveRuntimeDepsLock` previously trusted `isAlive(owner.pid)`
alone when deciding whether a lock could be reclaimed. That works fine
on a normal host: when the writer dies the PID is gone and `isAlive`
returns false. Inside Docker it does not — every Node gateway process
runs as PID 1 (or PID 7 with `init: true`) in its container PID
namespace, so a stale lock left behind by a previous incarnation looks
"alive" to the new one. The 5-minute lock-wait timeout then fires and
the supervisor restarts, and the cycle repeats indefinitely. Operators
have to manually remove `.openclaw-runtime-deps.lock` to recover.

This change records `pidStartTimeMs` alongside `pid` and `createdAtMs`
when the lock is acquired, and consults it in the staleness check.
When both sides have start-time evidence and they disagree, the lock
is treated as stale; otherwise the existing PID-alive-means-fresh
behavior is preserved exactly. The capture point uses
`Date.now() - process.uptime() * 1000` once at module load, and the
read side uses `/proc/<pid>/stat` field 22 on Linux (returning null
elsewhere so legacy semantics still apply on macOS/Windows hosts).

This is strictly additive on the wire format and the predicate:
existing lock files without `pidStartTimeMs` continue to take the same
code path they did before, and platforms that cannot resolve a live
PID's start-time fall back to the same legacy behavior.

Refs #74346.
2026-04-29 16:54:05 +01:00
Peter Steinberger
3f0039e2ea fix(memory-wiki): reduce people wiki search noise 2026-04-29 16:52:48 +01:00
Peter Steinberger
c99d680714 ci: run release orchestration on github runners 2026-04-29 16:49:13 +01:00
Peter Steinberger
616f24fd49 refactor(gateway): consolidate lifecycle lazy boundary (#74105)
* refactor(gateway): consolidate lifecycle lazy boundary

* test(gateway): cover quoted lifecycle imports
2026-04-29 16:45:51 +01:00
Peter Steinberger
53e0874864 fix(models): satisfy params merge lint 2026-04-29 16:41:56 +01:00
Peter Steinberger
e8d23e5489 ci: cancel superseded release validation runs 2026-04-29 16:41:26 +01:00
Peter Steinberger
acae48b790 docs: document clawsweeper review findings 2026-04-29 16:40:19 +01:00
Peter Steinberger
240362bf6d fix: keep Discord runtime policy API export 2026-04-29 16:35:37 +01:00
Peter Steinberger
9fcae8458e fix: accept channel lastConnectedAt health snapshots 2026-04-29 16:35:37 +01:00
Peter Steinberger
8cbf77d997 chore: remove unused Discord runtime policy shim 2026-04-29 16:35:37 +01:00
Peter Steinberger
7acb78852f fix: keep Discord DM wildcard out of owner checks 2026-04-29 16:35:37 +01:00
Peter Steinberger
04f651b783 fix: preserve Slack DM access account lookup 2026-04-29 16:35:37 +01:00
Peter Steinberger
1d9959b77e fix: preserve DM access precedence in Slack runtime 2026-04-29 16:35:37 +01:00
Peter Steinberger
e6d72548b7 refactor: add shared channel DM access helpers 2026-04-29 16:35:37 +01:00
Peter Steinberger
8c68e7535f refactor: centralize channel DM access resolution 2026-04-29 16:35:37 +01:00
Peter Steinberger
606c881d27 test: stabilize release live e2e probes 2026-04-29 16:32:05 +01:00
Peter Steinberger
46171d7848 fix(models): merge legacy openrouter params 2026-04-29 16:32:05 +01:00
Peter Steinberger
e49703def6 fix(channels): preserve account status generic 2026-04-29 16:30:03 +01:00
Peter Steinberger
4dd2768c4b fix(channels): improve health metadata and reply diagnostics 2026-04-29 16:27:24 +01:00
Val Alexander
1390eadd92 fix(control-ui): link dashboard breadcrumb
Make the topbar OpenClaw breadcrumb a semantic Overview link, wire the existing navigate event at the app shell, and preserve prefixed Control UI base paths.\n\nValidation:\n- pnpm test ui/src/ui/navigation.browser.test.ts\n- pnpm exec oxfmt --check --threads=1 ui/src/ui/components/dashboard-header.ts ui/src/ui/app-render.ts ui/src/ui/navigation.browser.test.ts\n- git diff --check origin/main...HEAD
2026-04-29 10:27:10 -05:00
Peter Steinberger
a2cf05c4fb docs: complete clawsweeper skill commands 2026-04-29 16:26:28 +01:00
Peter Steinberger
c6b269154a docs: document clawsweeper re-review mention 2026-04-29 16:22:49 +01:00
Peter Steinberger
508cd6f805 fix(discord): remove stale component policy helper 2026-04-29 16:20:19 +01:00
Peter Steinberger
dc5a85d606 test(ci): align package artifact reuse assertion 2026-04-29 16:15:13 +01:00
Peter Steinberger
8935dd154a refactor(discord): simplify gateway and component wiring 2026-04-29 16:14:55 +01:00
Shakker
a0300378d6 docs: note openai model list manifest path 2026-04-29 16:07:33 +01:00
Shakker
2b4909e2db perf: move openai model list catalog to manifest 2026-04-29 16:07:33 +01:00
Peter Steinberger
2d53b49b20 ci: use same-run release package artifacts 2026-04-29 16:06:02 +01:00
Peter Steinberger
995aa4f428 fix(ci): restore package validation coverage 2026-04-29 16:05:20 +01:00
Peter Steinberger
b92d145252 fix(ci): repair discord route and health fixtures 2026-04-29 15:58:56 +01:00
Peter Steinberger
beff88175e ci: run release orchestration on blacksmith 2026-04-29 15:58:00 +01:00
Peter Steinberger
ca093d8402 ci: speed up package tarball validation 2026-04-29 15:56:08 +01:00
Peter Steinberger
204ef7f1c4 fix(telegram): report webhook registration status 2026-04-29 15:40:44 +01:00
Mason Huang
7108414009 ci: add codeql quality profile input (#74348)
* ci: add codeql quality profile input

* ci: gate codeql quality profiles

* ci: ignore spec files in codeql shard
2026-04-29 22:39:54 +08:00
Peter Steinberger
587b537b47 refactor(discord): simplify internal component wiring 2026-04-29 15:37:09 +01:00
Jesse Merhi
542821cd1e docs(security): clarify proxy SSRF reporting scope (#74338)
Merged via squash.

Prepared head SHA: 7dd9fcfade
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Reviewed-by: @jesse-merhi
2026-04-30 00:30:16 +10:00
Peter Steinberger
b7db63751b perf(agents): cache subagent registry reads 2026-04-29 15:25:21 +01:00
Peter Steinberger
34d11d5757 fix(gateway): recognize Windows gateway listeners via PowerShell 2026-04-29 15:25:03 +01:00
Peter Steinberger
4bd6dd77ef ci: bound release package tarball checks 2026-04-29 15:12:09 +01:00
Peter Steinberger
8055e74485 test(doctor): mock system gateway discovery in e2e harness 2026-04-29 15:11:40 +01:00
Peter Steinberger
b929701e97 test(agents): capture codex payload mutations 2026-04-29 15:11:40 +01:00
Peter Steinberger
16f604d7e7 test(image): isolate provider registry mock 2026-04-29 15:11:40 +01:00
Peter Steinberger
6fcddbbd96 fix(auth): keep newer agent oauth credentials 2026-04-29 15:11:40 +01:00
Peter Steinberger
65b0927490 test(gateway): complete startup config path mock 2026-04-29 15:11:40 +01:00
Peter Steinberger
bf1a8eebba fix(memory): preserve dreams path bridge behavior 2026-04-29 15:11:40 +01:00
Peter Steinberger
bea75406bb test(configure): fix provider catalog fixture types 2026-04-29 15:11:39 +01:00
Peter Steinberger
e3a0c7615b build: broaden duplicate scan coverage 2026-04-29 15:11:39 +01:00
Peter Steinberger
577438ca73 test: dedupe mirrored memory and deepseek tests 2026-04-29 15:11:39 +01:00
Peter Steinberger
1dd37f5c90 refactor(memory): bridge host sdk duplicates 2026-04-29 15:11:39 +01:00
Peter Steinberger
f52958ad67 test(active-memory): make circuit breaker reset test deterministic 2026-04-29 15:11:26 +01:00
Peter Steinberger
5a2c50275d ci: cap docker e2e package validation 2026-04-29 15:10:25 +01:00
jacky
0544c6d493 fix: suppress raw JSON parse errors from leaking to Discord channels (#59076) [AI-assisted] (#59118)
Merged via squash.

Prepared head SHA: b8b3686445
Co-authored-by: singleGanghood <156392444+singleGanghood@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-29 21:59:46 +08:00
Peter Steinberger
03e17d19e9 test(plugins): avoid map spread in provider fixture 2026-04-29 14:55:25 +01:00
Peter Steinberger
66cdbccc8a fix(agents): demote embedded run stage logs to trace 2026-04-29 14:52:14 +01:00
Peter Steinberger
6bbacd14a3 fix(gateway): wait for event loop before client start 2026-04-29 14:50:44 +01:00
Peter Steinberger
a972c9ec45 test: tolerate transient google tts and openrouter tool probes 2026-04-29 14:46:28 +01:00
Peter Steinberger
3a875e7549 test: speed up provider plugin tests 2026-04-29 14:42:16 +01:00
Peter Steinberger
aaa194c58b fix(discord): align internal gateway and component parity 2026-04-29 14:38:52 +01:00
Peter Steinberger
d8b25506bb test: tolerate opencl live stt transcript variant 2026-04-29 14:37:28 +01:00
Mason Huang
dda765c445 ci: add plugin sdk package contract codeql quality shard (#74342) 2026-04-29 21:33:11 +08:00
Peter Steinberger
5605b31375 test: make doctor migration assertion order independent 2026-04-29 14:24:06 +01:00
Peter Steinberger
0be8d127d6 test(scripts): update discord changed-lane expectation 2026-04-29 14:22:58 +01:00
Peter Steinberger
da6135d34c fix(discord): satisfy internal boundary checks 2026-04-29 14:22:58 +01:00
Peter Steinberger
47b3530af3 fix(discord): prune idle rest route mappings 2026-04-29 14:22:58 +01:00
Peter Steinberger
32db9ff538 fix(discord): prune remapped rest buckets 2026-04-29 14:22:58 +01:00
Peter Steinberger
cea2da7049 refactor(discord): trim interaction helper duplication 2026-04-29 14:22:58 +01:00
Peter Steinberger
f0adbd48e8 refactor(discord): internalize discord client 2026-04-29 14:22:58 +01:00
Peter Steinberger
20e2117371 fix(agents): trace slow embedded run startup stages 2026-04-29 14:08:41 +01:00
Alex Knight
bbf985d50a feat(plugins): add SQLite plugin state store (#74190)
* feat(plugins): add experimental sqlite plugin state store
2026-04-29 23:02:14 +10:00
Peter Steinberger
abaa4326d8 docs: classify media decode overhead as performance-only (#74311)
* docs: classify media decode overhead as hardening

* docs: classify decode overhead as performance

---------

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-04-29 05:54:35 -07:00
Peter Steinberger
d1b2d81752 fix: send OpenClaw attribution to OpenAI 2026-04-29 13:54:07 +01:00
Peter Steinberger
9881a808f2 ci: fallback deadcode check for legacy targets 2026-04-29 13:50:27 +01:00
samzong
443ca4865d [Feat] surface spawnedBy in chat and agent broadcast payloads (#63244)
Merged via squash.

Prepared head SHA: ff0fe5db38
Co-authored-by: samzong <13782141+samzong@users.noreply.github.com>
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Reviewed-by: @frankekn
2026-04-29 20:48:59 +08:00
Peter Steinberger
390a7598c9 fix(cli): keep tools rpc namespace off plugin startup 2026-04-29 13:47:03 +01:00
Val Alexander
88101e81ef fix(ui): improve command palette accessibility
Render the command palette as a native modal dialog with labelled combobox/listbox semantics, stable active-descendant wiring, and guarded close behavior.\n\nValidated with targeted command palette tests and formatter checks.
2026-04-29 07:44:03 -05:00
Peter Steinberger
03148a6a76 test: guard legacy target ci planner fallback 2026-04-29 13:42:10 +01:00
Vincent Koc
ad2516b1c8 fix(ci): tolerate legacy plugin contract targets 2026-04-29 05:40:28 -07:00
Alex Knight
8f2dd02d2d fix(deepseek): add provider-policy-api to hydrate contextWindow and cost from catalog (#74326)
DeepSeek models had no provider-policy-api.ts, so materializeRuntimeConfig
filled contextWindow with DEFAULT_CONTEXT_TOKENS (200k) and cost with zeros
for all DeepSeek models. This caused premature session compaction at ~125k
instead of using the full 1M window, and zero-cost display for v4 models.

Add a normalizeConfig surface that hydrates missing contextWindow, maxTokens,
and cost from the bundled DeepSeek model catalog for matching model ids.
Explicit user overrides are preserved.

Fixes #74245
2026-04-29 22:38:11 +10:00
Peter Steinberger
7a69069bfc ci: retry release live smokes faster 2026-04-29 13:31:29 +01:00
Vincent Koc
56d2749b5b test(auth): follow enabled plugin setup config 2026-04-29 05:30:11 -07:00
openclaw-clownfish[bot]
2f31184d07 fix(hooks): repair shared-hook announcement policy (#73800)
* fix(hooks): repair shared-hook announcement policy

* fix(hooks): audit suppressed hook successes

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-29 05:28:16 -07:00
Peter Steinberger
cf43b92fc9 fix(cli): keep status usage on fast path 2026-04-29 13:20:59 +01:00
Shakker
4e4f9204d7 fix: restore provider-filtered model registry rows 2026-04-29 13:13:55 +01:00
Vincent Koc
1b56c7723b fix(agents): keep PI telemetry on model provider
Keep PI embedded-run usage metadata and traces attributed to the resolved model provider instead of the PI harness label.
2026-04-29 05:13:00 -07:00
Peter Steinberger
81551ac24b fix(telegram): bound command menu setup requests 2026-04-29 13:11:41 +01:00
Ayaan Zaidi
75286ef838 fix: document provider-scoped model picker (#74322) 2026-04-29 17:41:05 +05:30
Ayaan Zaidi
991da29481 test(configure): cover provider-scoped catalog prompts 2026-04-29 17:41:05 +05:30
Ayaan Zaidi
49f94db5d4 test(auth): cover manifest provider plugin enabling 2026-04-29 17:41:05 +05:30
Ayaan Zaidi
9bf7b6bfca fix(auth): enable selected manifest provider plugins 2026-04-29 17:41:05 +05:30
Ayaan Zaidi
17d05269f9 fix(configure): preserve selected provider scope 2026-04-29 17:41:05 +05:30
Peter Steinberger
234cbf5f46 perf(plugins): memoize packaged runtime dist mirrors 2026-04-29 13:10:28 +01:00
Peter Steinberger
40f820bda2 fix: preserve discord voice owner allowlist fallback 2026-04-29 13:09:13 +01:00
Val Alexander
efb1a7cb02 fix(control-ui): make chat divider accessible
Make the chat sidebar divider accessible and input-method agnostic.\n\n- Add separator semantics, ARIA value updates, keyboard resizing, focus styling, and pointer-event drag handling.\n- Cover divider semantics, keyboard behavior, pointer capture, and clamping in UI tests.\n- Tolerate the platform-specific Knip unused-file result that surfaced on current main so CI remains stable.
2026-04-29 07:07:16 -05:00
Peter Steinberger
64bd2a2cbe refactor: simplify parallels smoke helpers 2026-04-29 13:04:43 +01:00
Peter Steinberger
579334f9f8 fix: preserve agent provider params on config writes 2026-04-29 13:02:24 +01:00
Val Alexander
1424982792 fix(ui): keep assistant avatar overrides authoritative
Summary:
- Make browser-local assistant avatar overrides win over stale missing IDENTITY.md avatar metadata.
- Show the selected assistant image in Personal settings and chat instead of a false File not found state.
- Add focused Control UI coverage for assistant avatar override and clear behavior.

Validation:
- pnpm test ui/src/ui/app-render.assistant-avatar.test.ts ui/src/ui/views/config-quick.test.ts ui/src/ui/controllers/assistant-identity.test.ts -- --reporter=verbose
- pnpm tsgo:core:test
- pnpm deadcode:dependencies
- pnpm deadcode:unused-files
- CI green on PR #74260
2026-04-29 07:02:01 -05:00
Peter Steinberger
49a6bfe601 ci: keep codex cli live smoke on fast tier 2026-04-29 13:01:44 +01:00
Squirbie
94a85e77de fix(discord): disambiguate allow-from DM targets (#74303)
* fix(discord): disambiguate allow-from DM targets

* test(discord): align allowFrom precedence

* docs(discord): clarify allowFrom id forms

* fix(discord): align allowFrom precedence

---------

Co-authored-by: 따온이네 맥북프로 <tulisy@ttaon-ine-ui-MacBookPro.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-29 13:01:28 +01:00
Peter Steinberger
4f540c703f fix(telegram): warn on stale polling status 2026-04-29 12:58:41 +01:00
Peter Steinberger
39f810911c refactor: convert parallels smoke scripts to typescript 2026-04-29 12:53:58 +01:00
Masato Hoshino
016f5ae862 test(plugins): cover dead-PID stale runtime-deps lock removal
Adds focused regression coverage for dead owner PID runtime-deps install locks so stale lock recovery remains PID-first and does not wait on age when the recorded owner process is gone.

Co-authored-by: masatohoshino <g515hoshino@gmail.com>
2026-04-29 12:51:14 +01:00
Peter Steinberger
fc49f94ccf test(gateway): drop stale sessions helper allowlist 2026-04-29 12:48:25 +01:00
Peter Steinberger
84d8d5d5e7 test(gateway): name sessions helper for deadcode guard 2026-04-29 12:47:25 +01:00
Peter Steinberger
7214b40a7b test: allowlist split session test helper 2026-04-29 12:44:27 +01:00
Peter Steinberger
1fb58ca5ee fix(telegram): recover transient polling and reply sends 2026-04-29 12:42:31 +01:00
Peter Steinberger
027337df79 test: fix github copilot discovery contract mock 2026-04-29 12:41:24 +01:00
Vincent Koc
c357235fe6 docs(memory): document active-memory circuit breaker config and lancedb memory query CLI
- docs/concepts/active-memory.md: extend the "Useful tuning fields" config
  table with the new `config.circuitBreakerMaxTimeouts` and
  `config.circuitBreakerCooldownMs` keys (with their schema-declared ranges
  and defaults) added by 89cd2b6362, so operators tuning Active Memory
  recall after consecutive timeouts can find the knobs alongside
  `cacheTtlMs`.
- docs/plugins/memory-lancedb.md: extend the "Commands" section with the
  new `openclaw memory query` subcommand 6b44dce0c8 registered when
  memory-lancedb is the active memory plugin, including the `--cols`,
  `--filter`, `--limit`, and `--order-by` options and the safety bounds
  (200-character filter cap, sanitized character allowlist, positive
  integer limit, in-memory order-by).
2026-04-29 04:41:06 -07:00
Peter Steinberger
0207f9ceec refactor: split gateway sessions tests 2026-04-29 12:40:50 +01:00
Peter Steinberger
f6c0dde1b3 test(ci): follow Parallels workspace seed helper 2026-04-29 12:40:44 +01:00
Peter Steinberger
de0f54b54a test(security): isolate windows acl user fallback 2026-04-29 12:36:28 +01:00
Peter Steinberger
1446069707 ci: speed up release live smoke retries 2026-04-29 12:33:52 +01:00
Peter Steinberger
d8b9ace39c fix(ci): repair github copilot setup types 2026-04-29 12:31:17 +01:00
Peter Steinberger
d30ba5351e docs: update clawsweeper gate names 2026-04-29 12:27:15 +01:00
vinoyang
96dff27808 feat(memory-lancedb): support Chinese memory trigger keywords (#70040) 2026-04-29 19:25:29 +08:00
Peter Steinberger
f79553bef6 fix(auth): scope external CLI auth status overlays (#74156)
* fix(auth): scope external CLI auth status overlays

* fix: pass external auth config to overlays

* fix(auth): keep no-prompt CLI reads file-only

* docs: update clawsweeper app wording
2026-04-29 12:23:50 +01:00
Peter Steinberger
8f6c72823e fix(ci): repair main typecheck after merges 2026-04-29 12:22:42 +01:00
Max Caldar
4d73cd52dc fix(plugins): mirror core root-package deps used by core dist code (#74213)
Extend MIRRORED_CORE_RUNTIME_DEP_NAMES from ["semver", "tslog"] to
also include @agentclientprotocol/sdk, @lydell/node-pty, croner,
dotenv, jiti, json5, jszip, markdown-it, tar, and web-push.

These are all declared as direct dependencies in the openclaw root
package.json and imported by core source code (src/acp/*, src/cron/*,
src/config/*, src/infra/{archive,backup,dotenv,push-web}.ts,
src/markdown/ir.ts, src/plugin-sdk/root-alias.cjs,
src/plugins/jiti-loader-cache.ts, src/process/supervisor/adapters/pty.ts,
etc), but the existing collectMirroredPackageRuntimeDeps allowlist only
covered semver and tslog.

The dynamic collectRootDistMirroredRuntimeDeps scan does pick up
imports that have an extension package.json owner (for example
memory-core declares chokidar, matrix declares jiti and markdown-it).
For deps with no extension owner, or for setups where the owning
extension is not enabled, those imports never make it into the
runtime-deps mirror and Node fails to resolve them at runtime, e.g.:

    Cannot find package 'chokidar' imported from
    .../plugin-runtime-deps/openclaw-<ver>/dist/qmd-manager-...js

Also add a static drift guard test that walks src/ for value imports of
root-package runtime deps and fails when one is neither in
MIRRORED_CORE_RUNTIME_DEP_NAMES nor declared by any extension's
package.json (with an explicit allowlist for known-transitive or
build/type-only imports such as chalk, ipaddr.js, file-type,
proxy-agent, typescript, qrcode). The guard caught @lydell/node-pty
during this change.

Refs #74199.
2026-04-29 07:19:39 -04:00
Peter Steinberger
dc9f1b8525 fix(telegram): honor managed proxy env 2026-04-29 12:18:49 +01:00
Logan Ye
89cd2b6362 feat(active-memory): add timeout circuit breaker to skip recall after consecutive failures (#74054) (#74158) 2026-04-29 07:18:43 -04:00
Ayaan Zaidi
d9c4fcf67d fix: surface GitHub Copilot models in configure (#74276) 2026-04-29 16:48:18 +05:30
Ayaan Zaidi
42b352c57e fix(github-copilot): publish model catalog 2026-04-29 16:48:18 +05:30
Ayaan Zaidi
1f9fafb288 fix(configure): use manifest model catalogs in picker 2026-04-29 16:48:18 +05:30
Ayaan Zaidi
22c42b6b30 fix(github-copilot): reuse existing auth profiles 2026-04-29 16:48:18 +05:30
Roger Deng
d4e52f4542 fix(tui): resync streaming watchdog after reconnect (#74224)
* fix(tui): resync streaming watchdog after reconnect

* fix(tui): keep reconnect history fallback armed

* fix(tui): tighten reconnect watchdog recovery
2026-04-29 07:17:18 -04:00
Logan Ye
d2db67e693 fix(cron): catch croner parse errors in cron.add and cron.update handlers (#74193)
* fix(cron): catch croner parse errors in cron.add and cron.update handlers

* fix(cron): narrow catch to TypeError/RangeError only; add braces for linter
2026-04-29 07:16:37 -04:00
Logan Ye
2aa6abddbe fix(memory): add LIKE fallback when FTS5 MATCH throws and log silent search errors (#74175)
* fix(memory): add LIKE fallback when FTS5 MATCH throws and log silent search errors

When searchKeyword FTS5 MATCH fails (e.g. unicode61 tokenizer rejects
certain query patterns), the search now falls back to a LIKE-based query
instead of silently returning zero results. The four .catch(() => [])
sites in the search orchestrator now log warnings so failures are
visible in diagnostics.

Fixes #74036

* fix(memory): split LIKE fallback into per-token clauses and log MATCH errors
2026-04-29 07:16:32 -04:00
Logan Ye
ef7c528c8a fix(agents): recognize flat JSON billing payloads and snake_case error codes (#74188)
* fix(agents): recognize flat JSON billing payloads and snake_case error codes

Two independent fixes for billing error detection:

1. isErrorPayloadObject/parseApiErrorInfo now recognize flat JSON like
   {"error":"string_code","message":"..."} where error is a string code
   at the top level, not just nested {"error":{"type":"...","message":"..."}}
   envelopes.

2. isBillingErrorMessage now matches "insufficient_balance" (underscore)
   and "Insufficient MBT balance" (one word between insufficient/balance)
   via two new patterns in the billing pattern list.

Together these prevent raw JSON from leaking to user-facing chat when
providers return 402-style flat payloads.

Fixes #74079

* fix(agents): remove redundant billing pattern and fix misleading regex comment
2026-04-29 07:15:45 -04:00
Peter Steinberger
1f8ccf2d2a refactor(gateway): reuse chat state registries 2026-04-29 12:14:59 +01:00
Peter Steinberger
34ec184dcb refactor: reuse shared dedupe helpers 2026-04-29 12:14:59 +01:00
Peter Steinberger
81ad827380 refactor(plugin-sdk): extract shared dedupe helpers 2026-04-29 12:14:59 +01:00
bitloi
dce2513db2 fix(agents): preserve CLI wake-up session metadata (#74171)
* Fix CLI wake-up resume metadata

* Rerun CI

* ci: re-trigger parity gate
2026-04-29 07:14:48 -04:00
Peter Steinberger
1d494af03a refactor: simplify gateway and e2e test helpers 2026-04-29 12:14:19 +01:00
Peter Steinberger
9d1c5a77c2 fix: add vercel ai gateway thinking profile
Adds a Vercel AI Gateway provider thinking-profile resolver for trusted OpenAI and Anthropic upstream refs, preserving catalog compat fallback for unsupported/base-only refs.

Includes provider tests, docs, and changelog coverage. Supersedes #41561.

Co-authored-by: Zcg2021 <80769518+Zcg2021@users.noreply.github.com>
2026-04-29 12:13:20 +01:00
Vincent Koc
6d7a77dcf9 fix(tui): recover stale streaming status after unbound final (#73749)
* fix(tui): clear stale streaming after unbound final events

* fix(clownfish): address review for ghcrawl-156749-autonomous-smoke (1)

* fix(tui): address stale streaming review
2026-04-29 04:12:25 -07:00
Peter Steinberger
77a5d82e64 test(ci): align telegram live package assertion 2026-04-29 12:06:57 +01:00
Peter Steinberger
fce62c6129 fix(ci): classify gateway agent helper as test-only 2026-04-29 11:59:44 +01:00
Peter Steinberger
bdcd543ed7 fix(gateway): bypass proxies for localhost control plane 2026-04-29 11:59:33 +01:00
Peter Steinberger
af31fc938a ci: fix ClawHub plugin peer fixture 2026-04-29 11:58:32 +01:00
Peter Steinberger
e6cd90e3fd fix(agents): keep OAuth auth read-through 2026-04-29 11:54:28 +01:00
Vincent Koc
21a92ea0f6 fix(whatsapp): recover group inbound after reconnect churn
Repair WhatsApp group inbound recovery after repeated reconnect churn while keeping the fallback scoped to reconnect metadata.

Canonical issue: #66920. Related evidence: #7433, #63855, #70856.

Thanks to legonhilltech-jpg, octopuslabs-fl, Kanorin-chan, and stuswan for the reports and reproduction details.
2026-04-29 03:54:18 -07:00
Peter Steinberger
4f73baf7d7 refactor(test): split e2e fixture helpers 2026-04-29 11:49:45 +01:00
Deepak Jain
0c9f84451a feat(config): add reasoningDefault to agents.defaults
Add reasoningDefault support under agents.defaults and preserve the existing per-agent/session/inline override order.

Includes authorization gating for configured reasoning state, /status coverage, config schema/docs baseline updates, and regression tests for the reply and status paths. Also carries the related cron startup-run preservation fix and CI test stabilization needed for this PR branch.

Validated locally with pnpm check:changed, the focused Vitest bundle for touched gateway/cron/auto-reply/plugin-sdk/tooling tests, pnpm config:docs:check, and git diff --check. GitHub checks are green on the merged head; Greptile latest visible review is 4/5 with no P0/P1 findings.
2026-04-29 05:47:18 -05:00
Peter Steinberger
7be65cd798 test: cover session-scoped model overrides (#74265) 2026-04-29 11:46:53 +01:00
Val Alexander
e5a5ea1072 fix(ui): make control prompts real modals
Introduce a native dialog-backed Control UI modal primitive and migrate the exec approval, gateway URL confirmation, and dreaming restart confirmation prompts to it.

The modal primitive provides aria-modal semantics, shadow-root-local labels/descriptions, focus trapping, safe initial focus, Escape cancellation, and focus restoration while preserving the existing prompt content and decision semantics.

Validation:
- pnpm lint --threads=8
- pnpm --dir ui test src/ui/components/modal-dialog.test.ts src/ui/views/exec-approval.test.ts src/ui/navigation.browser.test.ts
- pnpm test:ui
- pnpm exec oxfmt --check --threads=1 ui/src/ui/components/modal-dialog.ts ui/src/styles/config-quick.test.ts
- git diff --check

CI note: checks-node-core-support-boundary is failing in test/scripts/docker-build-helper.test.ts on an unrelated package-acceptance assertion; the failing files are identical to origin/main and outside this UI-only PR.
2026-04-29 05:46:50 -05:00
Peter Steinberger
1dac6ac4c6 ci: retry transient live provider flakes 2026-04-29 11:44:42 +01:00
Peter Steinberger
6b4873d0c1 ci: split plugin contract shards 2026-04-29 11:44:32 +01:00
vinoyang
6b44dce0c8 feat(memory-lancedb): support query cmd for llm CLI (#71112)
* feat(memory-lancedb): support query cmd for llm CLI

* address review comments

* address review comments

* trigger ci
2026-04-29 18:42:40 +08:00
Peter Steinberger
4528682487 chore: remove stale Knip voice-call ignore 2026-04-29 11:40:21 +01:00
Peter Steinberger
69e6f65237 test: avoid CI lint false positive in ACP config mock 2026-04-29 11:35:34 +01:00
Peter Steinberger
427d5d4f69 ci: guard unused dead-code files 2026-04-29 11:35:34 +01:00
Peter Steinberger
38fdb42069 chore: remove unused internal entrypoints 2026-04-29 11:35:34 +01:00
Peter Steinberger
93d5cd1015 fix: honor configured xhigh thinking compat (#74273)
* fix: honor configured xhigh thinking compat

* test: update agent command model selection mock
2026-04-29 11:35:03 +01:00
Peter Steinberger
6cea276976 ci: shard release docker plugin validation 2026-04-29 11:33:24 +01:00
Peter Steinberger
99950c7f12 fix(doctor): use lightweight gateway liveness check 2026-04-29 11:32:02 +01:00
Peter Steinberger
a1197b9075 test: remove unused ACP mock parameter 2026-04-29 11:24:47 +01:00
Peter Steinberger
20ed597495 fix: restore verbose command and ACP cleanup controls 2026-04-29 11:20:11 +01:00
Vincent Koc
ae57eb635c fix(gateway): reduce session-store clone memory growth
## Summary
- Addresses the remaining Gateway RSS/session-accumulation path tracked by #54155.
- Narrows the fix to the structuredClone/session-store cache memory growth described in #45438.
- Preserves prior report context from #57699, #62717, #66886, #69977, and #70717 as validation evidence.

## Validation
- pnpm -s vitest run src/config/sessions/store.pruning.test.ts src/config/sessions/store.pruning.integration.test.ts src/gateway/sessions-resolve-store.test.ts
- pnpm check:changed

## Credit
Thanks @the-lobsternaut for #54155 and @markus-lassfolk plus the #45438 commenters for isolating the structuredClone/native-memory behavior.

ProjectClownfish replacement details:
- Cluster: ghcrawl-156648-autonomous-smoke
- Source PRs: none
- Credit: Credit #54155 reporter @the-lobsternaut for the multi-day Gateway RSS/session-accumulation report.; Credit #45438 reporter @markus-lassfolk and commenters for isolating the structuredClone/session-store native-memory path.; Preserve prior closed-report context from #57699, #62717, #66886, #69977, and #70717 in the PR body as reproduction evidence, not as new close targets.
- Validation: pnpm -s vitest run src/config/sessions/store.pruning.test.ts src/config/sessions/store.pruning.integration.test.ts src/gateway/sessions-resolve-store.test.ts; pnpm check:changed
2026-04-29 03:19:13 -07:00
Peter Steinberger
07ca99d2a8 ci: split auto-reply session shard 2026-04-29 11:18:26 +01:00
Vincent Koc
0f6fea813c test(gateway): allow cold plugin route dispatch 2026-04-29 03:17:41 -07:00
Peter Steinberger
923837accd test: wait for deferred gateway agent dispatch 2026-04-29 11:13:30 +01:00
Peter Steinberger
06088c6b05 test: follow update channel assertion extraction 2026-04-29 11:12:13 +01:00
Peter Steinberger
e1fd27fb24 feat(messages): add global visible replies mode 2026-04-29 11:06:39 +01:00
Super Zheng
1c45592e62 perf(plugins): add O(1) fast-path for empty plugin loads 2026-04-29 03:04:21 -07:00
Peter Steinberger
48683a7f71 ci: split auto-reply reply routing shard 2026-04-29 11:03:55 +01:00
Yao
af548bb07d fix(ui): persist default agent via agents list flag
Fix the Control UI Set Default action to persist agents.list[].default instead of the unsupported agents.defaultId config key.\n\nCloses #65565.\n\nThanks @luyao618.
2026-04-29 03:03:12 -07:00
Super Zheng
d33c3f7da6 perf(catalog): cache manifest built-in model suppression resolver (#74236)
* perf(catalog): cache manifest built-in model suppression resolver

* fix(catalog): address PR review comments for manifest suppression resolver

* fix(catalog): preserve cached suppression semantics

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-29 02:52:26 -07:00
Peter Steinberger
b52197427c refactor: consolidate e2e fixture helpers 2026-04-29 10:49:37 +01:00
Vincent Koc
412434a450 test(plugins): extend external install contract coverage 2026-04-29 02:48:58 -07:00
Logan Ye
3af661384c fix(hooks): deduplicate boot-md startup tasks by workspaceDir (#74194) 2026-04-29 02:48:31 -07:00
Peter Steinberger
d7cc8d0b03 ci: split agentic gateway test shards 2026-04-29 10:47:35 +01:00
Peter Steinberger
146c0a7e1d test(gateway): wait for deferred agent session event 2026-04-29 10:45:09 +01:00
luzhidong
1c17fd5edf feat(ui): add mobile cron session filter
Add the existing desktop cron-session visibility toggle to the mobile chat settings dropdown, reusing the shared session filtering state and cron filter icon path.

Also add focused browser render coverage for the mobile dropdown so the cron filter button, hidden-count title, active/pressed state, and click behavior are covered.

Validated:
- pnpm exec oxfmt --check --threads=1 ui/src/ui/app-render.helpers.browser.test.ts
- pnpm test ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/app-render.helpers.node.test.ts
- pnpm lint --threads=8

Thanks @luzhidong.
2026-04-29 04:38:50 -05:00
Peter Steinberger
3c19588fc5 test(ci): align bun install smoke assertion 2026-04-29 10:35:55 +01:00
Vincent Koc
4b99724a9c test(plugins): isolate config alias scan regression 2026-04-29 02:29:03 -07:00
Vincent Koc
a3519e362f fix(plugins): reuse config alias scans 2026-04-29 02:29:02 -07:00
Vincent Koc
985000026e fix(gateway): defer agent dispatch after accept 2026-04-29 02:29:02 -07:00
Vincent Koc
1d61862adb fix(gateway): yield after agent accepted ack 2026-04-29 02:29:02 -07:00
Vincent Koc
d95719d7c1 test(qa): widen kitchen sink turn budget 2026-04-29 02:29:01 -07:00
Vincent Koc
abed3a056d test(qa): add kitchen sink plugin gauntlet 2026-04-29 02:29:01 -07:00
Vincent Koc
e4b09e1bf3 fix(mcp): serialize raw plugin tool results 2026-04-29 02:29:00 -07:00
Vincent Koc
24adf2c8e6 fix(plugins): reject malformed channel registrations 2026-04-29 02:29:00 -07:00
Peter Steinberger
8d58ad4c15 fix(gateway): retry startup handshakes before surfacing failures 2026-04-29 10:25:53 +01:00
Peter Steinberger
a98a4e6ca5 refactor: extract e2e scenario fixtures 2026-04-29 10:25:35 +01:00
Peter Steinberger
3b10b8cf74 chore: remove unused internal barrels 2026-04-29 10:23:41 +01:00
Peter Steinberger
fa8a7d70ee docs: fix clawsweeper skill metadata 2026-04-29 10:20:09 +01:00
Peter Steinberger
f28bc31ecd ci: rename clawsweeper automation labels 2026-04-29 10:18:57 +01:00
Peter Steinberger
35cccbeb68 docs: unify clawsweeper skill 2026-04-29 10:16:07 +01:00
Vincent Koc
bc205836ca test(plugins): harden kitchen sink external install 2026-04-29 02:14:44 -07:00
Peter Steinberger
04c650c2c4 test: allow slow packaged agent acceptance 2026-04-29 10:12:00 +01:00
Peter Steinberger
f5e7557c70 fix(heartbeat): defer during cron and nested lane pressure 2026-04-29 10:08:48 +01:00
Peter Steinberger
422d139ba0 refactor: simplify e2e fixture helpers 2026-04-29 10:08:34 +01:00
openclaw-clownfish[bot]
c33968e10c fix(discord): split CJK text at safe break points (#73960)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Penchan <5032148+p3nchan@users.noreply.github.com>
2026-04-29 02:07:26 -07:00
Peter Steinberger
0f078f2ea2 chore: remove unused media host server 2026-04-29 10:05:47 +01:00
Peter Steinberger
6350dd5ace fix: include deleted files in changed lanes 2026-04-29 10:05:47 +01:00
openclaw-clownfish[bot]
ea9f17256a fix(exec): prevent shell startup files from overriding daemon env
Carries forward the focused shell startup suppression fix from #40200 by NewdlDewdl.

- launch bash, zsh, and fish exec shells with startup files suppressed
- preserve fish/bash/sh PATH fallback, non-interactive shell fallback, and Windows PowerShell behavior
- add regression coverage for the affected shell arg paths

Fixes #40179.
Carries forward #40200.
Thanks @NewdlDewdl.
2026-04-29 02:01:07 -07:00
openclaw-clownfish[bot]
d35e6f79e1 fix: canonicalize extra params model lookup keys
Carries forward https://github.com/openclaw/openclaw/pull/44319 by @HenryXiaoYang.
2026-04-29 01:57:48 -07:00
openclaw-clownfish[bot]
928698d388 fix(discord): fail closed when bot identity is unavailable
Fail Discord startup closed when the bot identity cannot be resolved, and keep mention gating active when configured mention patterns can still detect required mentions without a bot id.\n\nFixes #42219. Carries forward source PRs #46856 by @education-01 and #49218 by @BenediktSchackenberg. #46847 was already closed as a duplicate; #42675 was security-routed separately and left out of the replacement source.
2026-04-29 01:55:04 -07:00
Peter Steinberger
c881e0a176 fix: keep sessions list responsive without catalog 2026-04-29 09:50:02 +01:00
Peter Steinberger
a4e92c0aa4 chore(gateway): track watch tmux cwd 2026-04-29 09:49:00 +01:00
Ted Li
8c8f396985 fix(feishu): suppress late streaming card finals (#72294)
Merged via squash.

Prepared head SHA: d18a9ff4c3
Co-authored-by: MonkeyLeeT <6754057+MonkeyLeeT@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-29 16:47:20 +08:00
Peter Steinberger
68ba1e7180 chore(gateway): run watch mode in tmux 2026-04-29 09:42:48 +01:00
Shakker
4fbd683819 test: clarify manifest catalog alias planning 2026-04-29 09:40:45 +01:00
Vincent Koc
eb82694217 test(ci): follow extracted docker assertions 2026-04-29 01:40:10 -07:00
Peter Steinberger
a5cb171d73 test: follow docker helper extraction 2026-04-29 09:39:20 +01:00
Ayaan Zaidi
fceaaa4494 fix: prevent Telegram gateway stalls (#74210) 2026-04-29 14:09:03 +05:30
Ayaan Zaidi
c211b41f17 perf(plugins): cache bundled alias lookup 2026-04-29 14:09:03 +05:30
Ayaan Zaidi
071e7610d6 fix(telegram): bound outbound request timeouts 2026-04-29 14:09:03 +05:30
Peter Steinberger
14e8a2d00b chore: remove unused internal dead code 2026-04-29 09:34:40 +01:00
Vincent Koc
cf6e4d0ed7 ci: keep clownfish command reactions owned 2026-04-29 01:34:29 -07:00
openclaw-clownfish[bot]
9bb1e59447 fix(cron): preserve model overrides for text payloads (#73946)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-29 01:32:27 -07:00
openclaw-clownfish[bot]
5762cc321a Improve pairing diagnostics without unsafe formatting (#73933)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-29 01:31:49 -07:00
Peter Steinberger
beb1d9b481 refactor: extract docker e2e helpers 2026-04-29 09:30:27 +01:00
Vincent Koc
fed552c2ef ci: keep command reactions in progress 2026-04-29 01:30:16 -07:00
Peter Steinberger
2a64f1a2de test: follow deferred cron startup catch-up 2026-04-29 09:29:12 +01:00
Peter Steinberger
dc810437e7 test: harden docker mcp smoke requests 2026-04-29 09:27:05 +01:00
openclaw-clownfish[bot]
61b0cd3781 fix(ui): keep control UI select values stable on load (#74000)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-29 01:26:30 -07:00
Vincent Koc
3a6d3dfa06 test(gateway): mock bundled runtime deps pruning 2026-04-29 01:25:27 -07:00
Peter Steinberger
7a32d6a09f chore: remove unused plugin helper code 2026-04-29 09:24:51 +01:00
Vincent Koc
88237faed3 ci: drop bare automerge reaction trigger 2026-04-29 01:19:43 -07:00
Vincent Koc
a7c8a3eed0 test: follow split plugin docker helpers 2026-04-29 01:18:35 -07:00
Peter Steinberger
7877182b6f fix(gateway): defer missed cron agent startup work 2026-04-29 09:15:54 +01:00
openclaw-clownfish[bot]
1a936f225e fix: Found one bug in the new compile-cache prune path: it removes a d (#74067)
* fix: Found one bug in the new compile-cache prune path: it removes a d

* fix(postinstall): keep compile cache pruning resilient

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-29 01:12:59 -07:00
openclaw-clownfish[bot]
4d43daa7bb fix(browser): ignore Playwright dialog race rejections
Carries forward #40067 from @randyjtw.

Validated:
- OPENCLAW_TESTBOX=1 pnpm check:changed (tbx_01kqc44esqmt15ygzvfxd1pqng)
- CI: https://github.com/openclaw/openclaw/actions/runs/25097879442
2026-04-29 01:11:54 -07:00
Peter Steinberger
72cf700fbf ci: add Knip dependency check
Add a dependency-only Knip CI shard, keep full unused-file mode manual, and scope pnpm's release-age override to the latest Knip dlx install.
2026-04-29 09:10:48 +01:00
Peter Steinberger
2c0449571c refactor: simplify docker e2e helpers 2026-04-29 09:09:47 +01:00
Vincent Koc
b85cf280c7 fix(ci): gate plugin prerelease docker suite 2026-04-29 01:06:57 -07:00
Vincent Koc
115e763804 Revert "docs(readme): add Yuanbao to supported channels list"
This reverts commit f2405c830b.
2026-04-29 01:05:39 -07:00
Peter Steinberger
6b480e09b9 test: follow docker e2e helper extraction 2026-04-29 09:04:01 +01:00
Vincent Koc
9d8de70c20 ci: tolerate command reaction token limits 2026-04-29 00:59:30 -07:00
Vincent Koc
59a0457251 fix(ci): restore extension package boundary excludes 2026-04-29 00:57:08 -07:00
Peter Steinberger
1c4262ef87 refactor: extract remaining docker e2e scenarios 2026-04-29 08:56:48 +01:00
Peter Steinberger
f3f614fae6 test: follow docker e2e script refactor 2026-04-29 08:56:23 +01:00
Vincent Koc
f2405c830b docs(readme): add Yuanbao to supported channels list
For 7b07a0ab8f: the Tencent Yuanbao bot was added to docs/channels/index.md
and docs/docs.json with that SHA, but the root README.md "Supported
channels include" line still listed all the other Chinese-platform
channels (WeChat, QQ) without Yuanbao. Adds it before WebChat so the
README reflects the same channel surface as the docs.
2026-04-29 00:52:55 -07:00
Vincent Koc
250fec85e1 ci: react to autoclose on issues 2026-04-29 00:52:02 -07:00
Vincent Koc
bd3ffd0802 fix(testbox): guard stale OpenClaw Testbox reuse 2026-04-29 00:51:17 -07:00
Vincent Koc
1e168b17b7 fix(ci): keep browser test support out of prod boundaries 2026-04-29 00:50:56 -07:00
openclaw-clownfish[bot]
0f11dcd15f fix(media): handle ffprobe stdin EPIPE
Handle broken-pipe errors from stdin-backed ffprobe without leaking as uncaught exceptions.
2026-04-29 00:49:52 -07:00
HDYA
5cc834a11a docs(msteams): fix federated auth added-in date
Correct the documented added-in date for MS Teams federated authentication.\n\nThanks @HDYA.
2026-04-29 02:47:56 -05:00
Peter Steinberger
ca972f692f fix: keep browser fetch helper under test support 2026-04-29 08:47:43 +01:00
Vincent Koc
a62c7e5a27 ci: react to autoclose commands 2026-04-29 00:46:00 -07:00
Peter Steinberger
8ac2dd4cd2 refactor: simplify docker e2e harness scripts 2026-04-29 08:45:42 +01:00
Peter Steinberger
2b811fe6d9 fix(memory): make qmd gateway startup lazy 2026-04-29 08:45:19 +01:00
Peter Steinberger
e52b660749 fix(browser): repair test fetch helper export 2026-04-29 08:45:05 +01:00
Peter Steinberger
2a02b3bcec test: harden plugin prerelease smoke checks 2026-04-29 08:41:30 +01:00
Vincent Koc
1d0e9a907e fix(doctor): migrate legacy tts enabled toggles 2026-04-29 00:39:18 -07:00
Vincent Koc
eb7f305737 Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix: exclude test support from raw fetch guard
  fix(ollama): preserve aborts with stream timeouts
  ci: require maintainer permission for command reactions
  docs(hooks/bundled/readme): cover session compaction and message events
  refactor: share docker e2e harness runner
  fix: keep browser test fetch out of runtime scan
2026-04-29 00:36:24 -07:00
Peter Steinberger
f8faf40a9e fix: exclude test support from raw fetch guard 2026-04-29 08:36:00 +01:00
Peter Steinberger
a31342ab6b fix(ollama): preserve aborts with stream timeouts 2026-04-29 08:33:23 +01:00
Vincent Koc
275b0f00b0 ci: require maintainer permission for command reactions 2026-04-29 00:30:32 -07:00
Vincent Koc
b69b508d20 docs(hooks/bundled/readme): cover session compaction and message events
The bundled hooks README listed only command/agent/gateway events and
ended with a stale "More event types coming soon (session lifecycle,
agent errors, etc.)" line, but production code now triggers:

- session:compact:before / session:compact:after via
  src/agents/pi-embedded-runner/compaction-hooks.ts
- message:received via src/auto-reply/reply/dispatch-from-config.ts
- message:sent via src/infra/outbound/deliver.ts

Updates the "Event Types" list with the four real production event
names, drops the stale coming-soon line, and aligns the InternalHookEvent
interface example with the actual InternalHookEventType union (adds
"message" and refreshes the action examples). HOOK.md authors that target
session lifecycle or message routing now have a real surface to subscribe
to instead of relying on tribal knowledge or the type definitions.
2026-04-29 00:29:29 -07:00
Peter Steinberger
34bd962a20 refactor: share docker e2e harness runner 2026-04-29 08:28:54 +01:00
Vincent Koc
c01244e859 test(browser): keep undici fetch helper test-only 2026-04-29 00:28:02 -07:00
Peter Steinberger
f6a2cf15c0 fix: keep browser test fetch out of runtime scan 2026-04-29 08:27:57 +01:00
konanok
bd5afadc5c fix(ui): use precise hourly message counts for Peak Error Hours (#49396)
Merged via squash.

Prepared head SHA: fbbf43b84a
Co-authored-by: konanok <30515586+konanok@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-29 15:22:42 +08:00
Peter Steinberger
a0fd105e5e ci: split plugin prerelease validation 2026-04-29 08:21:12 +01:00
Peter Steinberger
9b1967e5ef perf(push): lazy load web push runtime 2026-04-29 08:20:56 +01:00
Vincent Koc
1dd500c495 test: stabilize mcp docker smokes 2026-04-29 00:19:52 -07:00
Vincent Koc
6a3310bbda chore(ci): add memory CodeQL quality shard
Adds a narrow CodeQL Critical Quality shard for the memory host/runtime boundary.
2026-04-29 00:18:30 -07:00
Peter Steinberger
26546dfbcb test: harden Docker release smoke probes 2026-04-29 08:16:17 +01:00
Peter Steinberger
7662a17b08 test: trim release smoke memory startup 2026-04-29 08:16:17 +01:00
Peter Steinberger
9ddd10b84c test: tighten MCP channel smoke route contract 2026-04-29 08:16:17 +01:00
Peter Steinberger
afc4f06ca3 fix(memory): isolate qmd boot refresh 2026-04-29 08:14:08 +01:00
Peter Steinberger
7e5d6dba80 build(deps): trim runtime dependency graph 2026-04-29 08:11:57 +01:00
Peter Steinberger
023d3371a5 refactor(gateway): classify gateway transport failures
# Conflicts:
#	CHANGELOG.md
2026-04-29 08:10:15 +01:00
Peter Steinberger
e25b542100 fix(cli): fall back to file logs when local logs rpc closes 2026-04-29 08:10:15 +01:00
Vincent Koc
6306e2fdcb ci: react to maintainer PR commands 2026-04-29 00:09:49 -07:00
Vincent Koc
13390fcac8 docs(apps/ios/readme): list authenticated background presence beacons
For bdba90a20b: apps/ios/README.md "What Works Now (Concrete)" section
omitted the authenticated background `node.presence.alive` beacon
feature that shipped on iOS first, even though apps/android/README.md
already lists it on the rebuild checklist. Adds a matching bullet so
the iOS README reflects the gateway last-seen metadata update path
across foreground/background transitions.
2026-04-29 00:09:25 -07:00
Vincent Koc
81f490f26a docs(changelog): note deprecated alias metadata 2026-04-29 00:07:12 -07:00
Vincent Koc
5fa0d282a8 fix(mcp): stringify plugin tool content safely 2026-04-29 00:04:18 -07:00
Vincent Koc
ca427df924 test(scripts): guard deprecated alias jsdoc 2026-04-29 00:04:17 -07:00
Vincent Koc
8b71d2347f docs(types): mark remaining deprecated aliases 2026-04-29 00:04:17 -07:00
Peter Steinberger
64387ad8e2 refactor: simplify docker e2e harness scripts 2026-04-29 08:03:15 +01:00
peter
e71d7d48fb fix(telegram): probe video dimensions through sdk
Fix Telegram portrait video distortion by probing video dimensions through the shared media helper and passing width/height to sendVideo.

Validation:
- Targeted Telegram/media tests passed locally.
- Plugin SDK API baseline check passed locally.
- Formatter and git diff whitespace checks passed locally.

CI note: current boundary drift observed on prior run came from existing src/plugin-sdk/discord.ts and src/plugin-sdk/telegram-account.ts, not this PR diff.
2026-04-29 01:58:25 -05:00
tmimmanuel
0bbbc99980 fix(ui): preserve queued chat messages across session switches (#73679)
Fixes #73621.

Preserve queued Control UI chat messages across in-UI session switches by saving the active queue per session before reset and restoring it when switching back. Route the overview session selector through the shared switchChatSession helper so it follows the same queue lifecycle.

Validation:
- OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test ui/src/ui/app-render.helpers.node.test.ts
- pnpm tsgo:test:ui
- pnpm exec oxfmt --check --threads=1 ui/src/ui/app-render.helpers.node.test.ts ui/src/ui/app-render.helpers.ts ui/src/ui/app-render.ts ui/src/ui/app-view-state.ts ui/src/ui/app.ts
2026-04-29 01:57:04 -05:00
brokemac79
20c7a98fb8 fix(plugins): keep provider discovery metadata-only
Fix startup and per-turn provider registry hot paths by keeping primary-model startup discovery on metadata-only provider entries and by keeping capability provider fallback loads scoped to manifest-derived owners, including explicit empty scopes when no bundled owner exists.

Evidence:
- Reproduces the reported code paths from #73729, #73835, and #73793: startup prewarm was able to enter provider/model discovery that loaded plugin runtime, and capability lookups could bypass active registry reuse or broaden fallback registry loads.
- Fix threads providerDiscoveryEntriesOnly through models-config planning into plugin discovery.
- Fix reuses active non-memory/non-speech capability providers even with explicit plugins.entries.
- Fix keeps fallback registry loads scoped with onlyPluginIds, including [] for no-owner media capability checks.
- Local targeted tests passed for gateway startup, models config, provider discovery, capability providers, and web provider runtimes.
- Testbox pnpm check:changed passed.
- Testbox pnpm build passed.
- GitHub CI required checks passed on e5e6fe1d52.

Fixes #73729.
Fixes #73835.
Fixes #73793.
Supersedes #73794.
2026-04-29 07:52:32 +01:00
Peter Steinberger
13757465ba fix(agents): scope external CLI auth discovery 2026-04-29 07:52:13 +01:00
Peter Steinberger
3367cfaa14 test: skip bot-to-bot telegram mention in default qa 2026-04-29 07:40:15 +01:00
Peter Steinberger
885d88c1ac refactor(test): simplify bundled channel Docker scenarios 2026-04-29 07:38:38 +01:00
Vincent Koc
99f0ea92fe ci: update qqbot raw fetch allowlist 2026-04-28 23:37:28 -07:00
Peter Steinberger
6a4c866b6a ci: speed up broad validation setup 2026-04-29 07:36:55 +01:00
Vincent Koc
1d87d757e9 ci: add mcp process codeql quality shard 2026-04-28 23:36:34 -07:00
Vincent Koc
1b25dcf57a docs(types): mark legacy hook surfaces deprecated 2026-04-28 23:31:32 -07:00
Peter Steinberger
71473e7448 test: make telegram live mention scenario privacy-safe 2026-04-29 07:27:14 +01:00
Peter Steinberger
32c2337095 test(ci): tolerate slow live provider cleanup 2026-04-29 07:24:47 +01:00
Brad Groux
5fe81cdf52 docs(changelog): link Teams JWT fix to #73167
Link the existing Microsoft Teams JWT runtime dependency fix to the matching #73167 report.\n\nFixes #73167
2026-04-29 01:19:31 -05:00
Peter Steinberger
ad761975de test: align zalo fixtures with open dm policy 2026-04-29 07:16:04 +01:00
Peter Steinberger
2da2d506b5 test(zalo): align open dm lifecycle fixtures 2026-04-29 07:15:29 +01:00
Vincent Koc
4eba70b532 docs(types): mark legacy aliases deprecated 2026-04-28 23:10:10 -07:00
Peter Steinberger
7d74c1f4b9 test: align channel fixtures with open dm policy 2026-04-29 07:08:06 +01:00
Peter Steinberger
d28500ffd6 ci: remove duplicate extension shard output 2026-04-29 07:02:25 +01:00
Peter Steinberger
a887a512ef ci: skip empty extension shard aggregate 2026-04-29 07:01:09 +01:00
Peter Steinberger
a9f58d34a2 ci: skip release-only extension aggregate on main 2026-04-29 07:00:13 +01:00
Peter Steinberger
926071762d test(ci): keep legacy sdk guardrail text stable 2026-04-29 06:57:19 +01:00
Peter Steinberger
fd72177830 test(ci): harden main release validation 2026-04-29 06:57:19 +01:00
Ayaan Zaidi
47204a1db5 test(media): cover timeout request forwarding 2026-04-29 11:26:58 +05:30
Ayaan Zaidi
09a64bd77e fix(media): propagate image timeout to providers 2026-04-29 11:26:58 +05:30
Vincent Koc
b62e9e624d test(codex): satisfy bundled app-server lint 2026-04-28 22:55:36 -07:00
Peter Steinberger
213f92a9ef test(ci): fix release validation regressions 2026-04-29 06:54:48 +01:00
Vincent Koc
6186ed2c07 ci: rename codeql quality baseline shard 2026-04-28 22:52:55 -07:00
Peter Steinberger
bd1d1f0f2b fix: align open DM allowlist policy (#74112)
* fix: harden telegram open dm allowlist merging

* fix: align open dm allowlist policy
2026-04-29 06:52:12 +01:00
Peter Steinberger
fda8cc2a9d ci: keep heavy plugin sweeps release-only 2026-04-29 06:49:05 +01:00
Peter Steinberger
cfcb8f4eda test(ci): fix current validation shards 2026-04-29 06:49:05 +01:00
Peter Steinberger
ade863e08f docs: update Clownfish automerge skill 2026-04-29 06:47:52 +01:00
Peter Steinberger
358b4f24cd test: guard broad plugin resolver fixtures 2026-04-29 06:46:02 +01:00
Peter Steinberger
83df409d94 refactor(test): share bundled channel Docker helpers 2026-04-29 06:42:14 +01:00
Peter Steinberger
5580d8951c test(ci): harden release failure paths 2026-04-29 06:41:58 +01:00
Vincent Koc
a7c3755327 docs(plugin-sdk): mark compatibility facades deprecated 2026-04-28 22:41:23 -07:00
Vincent Koc
67e8d35f1c test(codex): tolerate slower app-server startup 2026-04-28 22:40:26 -07:00
Peter Steinberger
95adc64326 docs: update process poll changelog 2026-04-29 06:38:47 +01:00
Peter Steinberger
4932e91517 fix(test): wait for Windows gateway recovery 2026-04-29 06:35:54 +01:00
Peter Steinberger
39513771bb test(ci): align scoped commands pool expectation 2026-04-29 06:35:35 +01:00
Peter Steinberger
1825f611f8 fix(agents): document process poll cap 2026-04-29 06:30:01 +01:00
Peter Steinberger
548c280eff fix(discord): keep exec approval fallbacks reachable 2026-04-29 06:29:44 +01:00
Peter Steinberger
66b4324d41 test(ci): align commands vitest pool expectation 2026-04-29 06:28:08 +01:00
samzong
450607847b [Feat] Gateway: add doctor.memory.remHarness probe (#66673)
Merged via squash.

Prepared head SHA: c19e6a335a
Co-authored-by: samzong <13782141+samzong@users.noreply.github.com>
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Reviewed-by: @frankekn
2026-04-29 13:23:36 +08:00
Peter Steinberger
364c67bcb5 refactor(discord): share channel run queue 2026-04-29 06:21:09 +01:00
Peter Steinberger
996c9d71e9 ci(test): reserve plugin prerelease for release validation 2026-04-29 06:20:38 +01:00
Peter Steinberger
3a6f7d8db9 ci(test): split command shards and harden release checks 2026-04-29 06:20:38 +01:00
Vincent Koc
7c7561f5a3 fix(plugins): scope capability provider snapshots 2026-04-28 22:19:34 -07:00
Vincent Koc
2f04731a48 ci: shard web media codeql quality 2026-04-28 22:18:21 -07:00
Peter Steinberger
1476e24af3 refactor(test): share bundled channel Docker harness helpers 2026-04-29 06:15:10 +01:00
Peter Steinberger
f6d23ab5c2 perf(test): speed facade loader fallback test 2026-04-29 06:13:03 +01:00
Peter Steinberger
2b0b614417 docs(plugins): clarify clawhub npm migration 2026-04-29 06:09:34 +01:00
Peter Steinberger
8d78451e8b fix: clarify session runtime metadata 2026-04-29 06:07:30 +01:00
Peter Steinberger
4d729d0aa8 docs: update changelog for timeout fixes 2026-04-29 06:07:12 +01:00
Peter Steinberger
d674225d88 fix(agents): clamp process poll waits 2026-04-29 06:07:12 +01:00
Peter Steinberger
07631fb931 fix(discord): remove channel run timeouts 2026-04-29 06:07:12 +01:00
Peter Steinberger
f7aebf8cb7 fix(release): keep legacy memory chunk stub 2026-04-29 06:03:20 +01:00
Ke He
e3bc985a6e fix(shared): preserve unicode slug labels
Fixes #58932.

Carries forward #58942 and #58995.

Thanks @fengqing-git, @Starhappysh, and @koen666.
2026-04-28 21:56:56 -07:00
Chunyue Wang
16fd9a9d59 fix(agents): inject resolved OAuth bearer into boundary-aware embedded streams (#73588)
Fixes openclaw#73559. Extracts a shared wrapEmbeddedAgentStreamFn helper and applies it to both provider-owned and boundary-aware fallback paths in resolveEmbeddedAgentStreamFn, forwarding the resolved OAuth bearer (resolvedApiKey → authStorage → options.apiKey) and run abort signal so models routing through openai-codex-responses and other boundary-aware transports stop failing with 401 Missing bearer auth header.
2026-04-29 12:56:43 +08:00
Vincent Koc
2f589aacf9 ci: tolerate missing prerelease plan on target refs 2026-04-28 21:55:03 -07:00
Peter Steinberger
07104c80b3 fix(plugin-sdk): keep compat facades out of core graph 2026-04-29 05:54:35 +01:00
Peter Steinberger
7994833fac fix(gateway): align handshake client timeouts 2026-04-29 05:53:50 +01:00
Peter Steinberger
5e2f6ce294 fix(agents): flush final block tag fragments (#74065) 2026-04-29 05:53:16 +01:00
Vincent Koc
0a8a255733 ci: restrict plugin prerelease suite to mega runs 2026-04-28 21:50:16 -07:00
Peter Steinberger
52a7e2264c fix(plugins): cache runtime deps scans 2026-04-29 05:49:09 +01:00
Vincent Koc
d49ebe7bde fix(plugins): stage runtime deps for selected slots 2026-04-28 21:45:55 -07:00
Peter Steinberger
9023b120a1 fix: scope claude doctor runtime checks 2026-04-29 05:44:45 +01:00
Peter Steinberger
b3a8c7146b fix(doctor): default missing health env 2026-04-29 05:44:26 +01:00
Rubén Cuevas
652f34103a fix(whatsapp): sanitize tool XML and hide configured error text (#71830)
Merged via squash.

Prepared head SHA: 184d4a25e4
Co-authored-by: rubencu <4742789+rubencu@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-29 01:43:25 -03:00
Vincent Koc
9e34fb9feb fix(plugin-sdk): restore channel compatibility facades 2026-04-28 21:38:11 -07:00
Peter Steinberger
02c4249632 perf: speed contract test imports 2026-04-29 05:37:39 +01:00
Peter Steinberger
3aadeba93f fix(update): skip legacy parent doctor config writes 2026-04-29 05:37:29 +01:00
Vincent Koc
b85edb3f0c docs(changelog): backfill vincentkoc readiness and CLI teardown fixes
Adds two missing changelog entries for previously merged fixes that
landed without their own CHANGELOG.md updates:

- Gateway/readiness covers 75ba8398f9 (`fix(gateway): expose event loop
  health in readiness`), which adds a new `eventLoop` block (p99/max
  delay, utilization, CPU core ratio, `degraded` flag) to authenticated
  `/readyz` responses. The same SHA already documented the surface in
  docs/cli/gateway.md but had no changelog line.
- CLI/update covers 09cb0b0e64 (`fix(cli): ignore stale memory cleanup
  after package update`), which moves the memory-state import inside
  the best-effort teardown try/catch so hashed-chunk replacement during
  `openclaw update` no longer surfaces as exit-time errors.

No changelog backfill for 68ef37011e (Ollama unused destructure cleanup —
no user-facing change), 1f41b8b44b (already covered by the
"Gateway/reload: bound default restart deferral" entry), df9d26eb43 and
d55c7ea997 (jointly covered by the existing "Active Memory: register
the prompt-build hook with the configured recall timeout" entry), or
the gauntlet/CI/QA-test commits which are internal infrastructure with
no end-user behavior change.
2026-04-28 21:32:10 -07:00
Vincent Koc
8c886e9438 fix(telegram): suppress acknowledged mutating tool warning leaks
Suppress raw failed edit/write warning payloads when the assistant already delivered a user-facing error reply for the same turn, while keeping the fallback warning for unresolved, ambiguous, or success-looking mutating failures.

Fixes #39631.
Refs #51065, #39636, #39717, and #39406.

Validation:
- Testbox tbx_01kqbqxw1yqpyyxb25vvjkrc90: OPENCLAW_TESTBOX=1 pnpm test:serial src/agents/pi-embedded-runner/run/payloads.errors.test.ts
- Testbox tbx_01kqbqxw1yqpyyxb25vvjkrc90: OPENCLAW_TESTBOX=1 pnpm check:changed
- CI run 25086475010: success on ea33538add
- Parity gate run 25086474949: success on ea33538add
2026-04-28 21:31:51 -07:00
Peter Steinberger
0fc3032325 test(live): classify provider media drift 2026-04-29 05:25:43 +01:00
Peter Steinberger
5eb9b3da34 ci(qa): slim release transport startup 2026-04-29 05:25:42 +01:00
Peter Steinberger
806a0119f3 ci(release): reuse live test Docker image 2026-04-29 05:25:42 +01:00
Peter Steinberger
aa84b738b6 fix(docker): copy postinstall helper imports 2026-04-29 05:25:42 +01:00
Peter Steinberger
203213028e perf: speed plugin contract tests and fix ci 2026-04-29 05:20:08 +01:00
Peter Steinberger
9ae629052a fix(parallels): fail dev update on unrepaired errors 2026-04-29 05:17:39 +01:00
Peter Steinberger
128115fb25 fix(update): prune stale compile cache on install 2026-04-29 05:17:39 +01:00
Peter Steinberger
ab39f2b272 [codex] Bias group chat prompts toward subagent delegation (#74046)
Bias group-chat prompt composition toward using subagents for tool-heavy work, keeping maintainer-channel responsiveness higher.\n\nValidated locally with focused prompt/auto-reply tests before opening the PR.
2026-04-29 05:16:21 +01:00
Vincent Koc
0382ac5f7d chore(plugins): track probe compat contracts 2026-04-28 21:12:07 -07:00
Vincent Koc
a2e077e468 chore(lint): fix changed gate drift 2026-04-28 21:10:24 -07:00
Vincent Koc
09cb0b0e64 fix(cli): ignore stale memory cleanup after package update 2026-04-28 21:10:24 -07:00
openclaw-clownfish[bot]
be445dd1c1 fix(imessage): normalize leading echoed text corruption
Fixes #59973
2026-04-28 21:04:20 -07:00
Peter Steinberger
34ef403cb2 docs: clarify provider hook compatibility 2026-04-29 05:02:04 +01:00
Peter Steinberger
e5dc0e6d15 fix: expose agent runtime status metadata 2026-04-29 05:02:04 +01:00
jesse-merhi
0015d34fda fix: group collect queue deliveries 2026-04-29 13:51:42 +10:00
jesse-merhi
2b8c20c8a3 fix: route rich menu images through media loader 2026-04-29 13:51:42 +10:00
jesse-merhi
4cf2284667 fix: preserve plugin route ownership 2026-04-29 13:51:42 +10:00
jesse-merhi
ef08f59b9f fix: constrain channel setup catalog resolution 2026-04-29 13:51:42 +10:00
jesse-merhi
d1b4dbffc3 fix: bound default media response reads 2026-04-29 13:51:42 +10:00
jesse-merhi
2e406c05f8 fix: cap realtime websocket payloads 2026-04-29 13:51:42 +10:00
jesse-merhi
706eb8833f fix: filter launchd handoff environment 2026-04-29 13:51:42 +10:00
Sathvik Gilakamsetty
7ddd815e46 fix(whatsapp): report transport activity so stale-socket health detection works (#72656)
Merged via squash.

Prepared head SHA: 1b1920742c
Co-authored-by: Sathvik-1007 <195685832+Sathvik-1007@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-29 00:46:55 -03:00
Peter Steinberger
8edb99f0e3 fix(update): preserve doctor repair writes in legacy handoff 2026-04-29 04:43:15 +01:00
Juan Flores
aa1bccfe80 fix(whatsapp): detect group @mentions when self is in allowFrom (#49317) (#73453)
Merged via squash.

Prepared head SHA: 357c62849f
Co-authored-by: juan-flores077 <112629487+juan-flores077@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-29 00:39:37 -03:00
Peter Steinberger
04f6ffd8be fix(ollama): resolve cloud models omitted from tags 2026-04-29 04:37:52 +01:00
Peter Steinberger
eb5adc3cd2 fix(parallels): align OpenAI smoke help text 2026-04-29 04:37:33 +01:00
Peter Steinberger
9863bb964b fix(update): type legacy doctor handoff env 2026-04-29 04:36:34 +01:00
Peter Steinberger
5a9c0efa54 fix(tasks): clean orphaned parent-owned acp sessions 2026-04-29 04:35:06 +01:00
Peter Steinberger
d130a77a3b fix(parallels): default OpenAI smokes to gpt-5.5 2026-04-29 04:35:03 +01:00
Peter Steinberger
e27fe55aa8 refactor: simplify plugin cache boundaries 2026-04-29 04:33:15 +01:00
Peter Steinberger
4f9f7fc8c2 fix(doctor): use process env for metadata handoff 2026-04-29 04:28:56 +01:00
Vincent Koc
e53c45ba94 ci: shard control ui codeql quality
Adds a narrow CodeQL Critical Quality shard for the Control UI/control-plane surface and fixes the custom-theme font-family ReDoS finding discovered by the new shard.
2026-04-28 20:24:19 -07:00
Peter Steinberger
c20a3f548f docs: update Clownfish cloud PR skill 2026-04-29 04:23:51 +01:00
Peter Steinberger
3dc6e408b9 ci(release): isolate channel live qa from provider latency 2026-04-29 04:22:01 +01:00
Peter Steinberger
6fcaf6ed58 docs(plugins): clarify setup metadata cache boundary 2026-04-29 04:21:37 +01:00
SATISH K C
ab5c8025c9 docs: add AllowTcpForwarding prerequisite to Hetzner SSH tunnel step
Fixes #54557; carries forward #54564; refs #54954. Thanks @satishkc7, @blackstrype, and @Aftabbs.
2026-04-28 20:16:30 -07:00
Peter Steinberger
7475b27887 fix(update): tolerate legacy doctor metadata handoff 2026-04-29 04:16:06 +01:00
nighty
6e31de5847 docs: fix custom skill naming example
Fix the custom skill docs example so the folder and SKILL.md frontmatter use the same hyphen-case name.
2026-04-28 20:15:36 -07:00
Peter Steinberger
64533ed7b1 ci(release): allow slower qa live canaries 2026-04-29 04:13:15 +01:00
Peter Steinberger
74889462a8 fix(media): enforce image description timeouts 2026-04-29 04:13:15 +01:00
Peter Steinberger
855c220a63 fix(channels): preserve bundled channel load caches 2026-04-29 04:13:14 +01:00
Arnav Panicker
eb332c2f32 docs: encode Control UI gatewayUrl examples
Squashed from PR #60773 after maintainer closeout.\n\nValidation:\n- Testbox tbx_01kqbkfn9nqpspssrveg5t3mrr: pnpm docs:list; OPENCLAW_TESTBOX=1 pnpm check:changed (docs-only)\n- Exact-head CI: https://github.com/openclaw/openclaw/actions/runs/25040057222
2026-04-28 20:12:51 -07:00
Alberto Farah Blair
aa03c5be82 docs(slack): document attachment vision behavior and known limits
Adds a Slack attachment vision reference covering downloaded media handling, PDF/file limits, thread-starter media fallback, multi-attachment behavior, and known troubleshooting cases.

Fixes #51355

Thanks @haroldfabla2-hue.
2026-04-28 20:12:44 -07:00
Vincent Koc
5847c0ed58 test(plugins): expect fresh derived registries 2026-04-28 20:09:18 -07:00
Peter Steinberger
5435591f6a fix(streaming): preserve split final tags 2026-04-29 04:07:39 +01:00
Vincent Koc
68ef37011e fix(ollama): drop unused cloud reachability flag 2026-04-28 20:03:27 -07:00
Ayaan Zaidi
e12eb9acdd docs(changelog): note Ollama configure picker fix 2026-04-29 08:23:57 +05:30
Ayaan Zaidi
d8c4d7c3c1 fix(configure): show provider model picker after setup 2026-04-29 08:23:57 +05:30
Ayaan Zaidi
2613692298 fix(ollama): avoid cloud model metadata fanout 2026-04-29 08:23:57 +05:30
Peter Steinberger
7a5b419843 refactor(plugins): simplify plugin cache boundaries 2026-04-29 03:52:22 +01:00
Vincent Koc
86c5f378d6 fix(github): skip clownfish active PR label 2026-04-28 19:51:26 -07:00
Peter Steinberger
9bf50450de docs: document ClawSweeper commit reruns 2026-04-29 03:51:00 +01:00
Peter Steinberger
ba0f2e948f ci: preinstall ffmpeg for live media checks 2026-04-29 03:48:33 +01:00
Peter Steinberger
1f055d23fd refactor(test): share onboarding e2e helpers 2026-04-29 03:44:36 +01:00
Ehsan
18237bc015 docs(install): fix gog/goplaces release URLs in docker-vm-runtime example (#72154)
Merged via squash.

Prepared head SHA: 7f06b724af
Co-authored-by: Ehsan <22658149+ebarkhordar@users.noreply.github.com>
Co-authored-by: Sally O'Malley <11166065+sallyom@users.noreply.github.com>
Reviewed-by: @sallyom
2026-04-28 22:42:37 -04:00
Sliverp
e0008268ad fix(onboarding): Improve the dynamic import UX. (#73419)
* fix(onboarding): skip redundant install prompt when only one source exists

When the channel-setup flow asks 'Install <plugin>?' after the user has
already picked the channel in the previous menu, and the only real
install source available is npm (or local), the prompt degenerates into
'<that source> vs Skip'. The user already expressed intent by picking
the channel, so re-confirming adds friction without offering a
meaningful choice.

Resolve directly to the available source in that case. Keep the prompt
when both npm and local sources exist so the user can still pick which
to use, and keep it when no real source exists (the prompt then only
offers Skip, which is informative).

* fix ci

* fix ci

* fix(channel-setup): skip redundant install prompt when only one source exists

Add autoConfirmSingleSource opt-in parameter to promptInstallChoice /
ensureOnboardingPluginInstalled / ensureChannelSetupPluginInstalled.
When set and only one real install source (npm or local, not both)
exists, the 'Install <plugin>? / Skip' prompt is skipped and the
single source is used directly.

Only channel-setup.ts passes autoConfirmSingleSource: true — the user
already expressed intent by picking the channel in the previous menu,
so re-confirming adds friction without a meaningful choice. The
onboarding and quickstart entry points keep the existing prompt
behavior unchanged.

Also fix findBundledPluginSourceInMap mock type in
onboarding-plugin-install.test.ts to avoid TS2345.

* fix(tests): revert auto-confirm test expectations and fix mock leak

- Revert 'offers registry npm specs' test to expect the prompt
  (autoConfirmSingleSource not passed)
- Revert channel-setup 'does not default to bundled local path' test
  to expect the prompt
- Reset findBundledPluginSourceInMap and
  resolveBundledInstallPlanForCatalogEntry mocks after the bundled
  prompt test to prevent cross-test leakage

* fix ci

* docs(changelog): add #73419
2026-04-29 10:41:42 +08:00
Peter Steinberger
180033eeae fix(update): resume git post-update in updated process 2026-04-29 03:39:09 +01:00
Vincent Koc
43da089790 fix(update): skip disabled plugins during post-update sync (#73970)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-28 19:36:11 -07:00
Vincent Koc
c65ec4d68c fix(github): exempt clownfish PRs from active limit closure 2026-04-28 19:34:40 -07:00
Peter Steinberger
c2e3b6e6f8 fix(openai): skip malformed empty SSE frames 2026-04-29 03:28:46 +01:00
Vincent Koc
09e2cf1103 ci: right-size codeql quality runners
Run CodeQL Critical Quality on 4 vCPU Blacksmith runners.
2026-04-28 19:26:45 -07:00
Peter Steinberger
13fdeec2cc ci: disable ClawSweeper commit checks by default 2026-04-29 03:25:20 +01:00
Peter Steinberger
38e56972cd docs: document Clownfish comment commands 2026-04-29 03:24:01 +01:00
Peter Steinberger
f4c9e71e4e fix(models): guard provider policy model shape 2026-04-29 03:16:35 +01:00
Peter Steinberger
b5a90b066d refactor: reuse docker gateway e2e helpers 2026-04-29 03:15:29 +01:00
ethanclaw
492e2a3060 fix(logs): find active log file across date boundaries (#42904)
* fix(logs): find active log file across date boundaries

Fixes #42875

When gateway runs across midnight, openclaw channels logs was looking
for today's log file instead of the active one. This change makes
the CLI find the most recently modified log file as a fallback.

(cherry picked from commit fba6b88e8644365360f82802cbe25039a091409d)

* fix(channels): resolve active log file for channel logs

(cherry picked from commit ee87397a4323f04fdd37a2fc136de02e648a92d5)

---------

Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
2026-04-28 19:11:14 -07:00
Peter Steinberger
a5790946f5 test(parallels): tolerate old updater stale chunk recovery 2026-04-29 03:10:44 +01:00
Vincent Koc
1e1fe80ae0 docs(changelog): note plugin lifecycle fixes 2026-04-28 19:02:45 -07:00
Bek
d6c2280aab fix(slack): normalize action thread targets (#73931) 2026-04-28 22:02:18 -04:00
Eden
bb6a15da04 fix(gateway): improve shutdown error visibility and add close timeout
Adds structured warning collection to gateway shutdown, preserves lifecycle timeout handling, and covers HTTP/WebSocket/subsystem warning paths.

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
2026-04-28 19:01:11 -07:00
Vincent Koc
df9d26eb43 fix(active-memory): narrow prompt hook timeout 2026-04-28 19:00:14 -07:00
Andrew Barnes
79159f11f6 fix: use LRU eviction for cron schedule cache
Fixes #39679
2026-04-28 18:56:19 -07:00
Peter Steinberger
610e575844 chore: add ClawSweeper agent skill 2026-04-29 02:48:40 +01:00
Vincent Koc
1f41b8b44b fix(gateway): bound default restart deferral 2026-04-28 18:42:49 -07:00
openclaw-clownfish[bot]
7e5c3753f6 fix(security): include dangerous commands in audit known commands (#73915)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-04-28 18:34:55 -07:00
Vincent Koc
7a88117f42 fix(qa): retry transient Telegram polling failures 2026-04-28 18:26:37 -07:00
Peter Steinberger
51119f2ef1 fix(release): ship dist import helper 2026-04-29 02:22:56 +01:00
Jari Mustonen
d8a600f2ad context-engine: pass runtime context to ContextEngineFactory (#67243)
Merged via squash.

Prepared head SHA: 9aca6a5af1
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-28 18:21:14 -07:00
Josh Lehman
12c52963ea fix: allow cron self-removal in isolated runs (#73028) 2026-04-28 18:16:31 -07:00
hcl
46783d41e9 fix(whatsapp): gate pairing access-control on extractable inbound user content (#73797) (#73823)
Merged via squash.

Prepared head SHA: 61506e1439
Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-28 22:09:23 -03:00
Peter Steinberger
381c2e1d1a fix(security): tighten telegram dm audit coverage 2026-04-29 02:04:20 +01:00
Peter Steinberger
a968f4f437 test(parallels): reset macos state after restore 2026-04-29 02:03:26 +01:00
Peter Steinberger
a5824b9d01 fix(ci): stabilize full release validation 2026-04-29 02:00:30 +01:00
Peter Steinberger
28ff82dcda chore: add Clownfish cloud PR skill 2026-04-29 01:40:04 +01:00
Vincent Koc
b96e7739a9 docs(install/docker): document compose config dir default fallback
For 054b2e1b7e: docs/install/docker.md "Storage and persistence" now
records that the bundled docker-compose.yml falls back to
${HOME}/.openclaw (and ${HOME}/.openclaw/workspace for the workspace
mount), or /tmp/.openclaw when HOME is also unset, when
OPENCLAW_CONFIG_DIR / OPENCLAW_WORKSPACE_DIR are not provided. That
matches the new default expressions in the compose file and prevents an
empty-source volume spec on bare environments.
2026-04-28 17:38:25 -07:00
Vincent Koc
293348b429 fix(plugins): prebuild private qa for gauntlet 2026-04-28 17:34:18 -07:00
Vincent Koc
8e5fcfff50 fix(test): stabilize core runtime infra shard 2026-04-28 17:31:35 -07:00
Peter Steinberger
7229ec5e04 fix(ci): pin release validation child ref 2026-04-29 01:30:53 +01:00
Peter Steinberger
ceeb3a7398 ci: dispatch commit reviews on main pushes 2026-04-29 01:27:45 +01:00
pashpashpash
4aa8da3756 Route sensitive group commands to the owner privately (#73872)
* fix(commands): route sensitive group approvals privately

* fix(commands): require owner private routes

* test(commands): cover owner-derived Telegram diagnostics routing
2026-04-29 09:27:18 +09:00
Peter Steinberger
e94e9347a4 fix(cli): load plugins for local JSON agent runs 2026-04-29 01:25:50 +01:00
Peter Steinberger
c24c8bab13 test(parallels): prefer arm64 mingit downloads 2026-04-29 01:25:08 +01:00
Peter Steinberger
a820a307df fix(ci): keep postinstall script self-contained 2026-04-29 01:20:37 +01:00
Peter Steinberger
45f3074ee6 fix(cli): skip plugin preload for json agent runs 2026-04-29 01:19:05 +01:00
Peter Steinberger
3286e99bc2 refactor: share docker e2e instance helpers 2026-04-29 01:17:19 +01:00
Peter Steinberger
6249c32826 ci: raise Blacksmith Docker cache caps 2026-04-29 01:14:39 +01:00
Peter Steinberger
03b1731d0f fix(ci): preserve imported dist chunks after install 2026-04-29 01:13:03 +01:00
Joe LaPenna
054b2e1b7e fix(docker): add config dir defaults to compose mounts (#64485)
Merged via squash.

Prepared head SHA: 2c5b954a2c
Reviewed-by: @sallyom
2026-04-28 20:12:24 -04:00
Vincent Koc
fd2625a162 fix(plugins): resolve ClawHub tags in prerelease CI 2026-04-28 17:04:01 -07:00
Vincent Koc
2eac4bacee test(ci): add kitchen-sink npm plugin prerelease lane 2026-04-28 17:04:01 -07:00
Peter Steinberger
0487cc59f0 fix(bonjour): suppress ciao internal cancellations
(cherry picked from commit 27599d319e)
2026-04-29 00:59:56 +01:00
Peter Steinberger
212a32648f fix(ci): speed up tarball checks and avoid CLI bootstrap 2026-04-29 00:52:45 +01:00
Peter Steinberger
5a0702ecf8 test: add reusable OpenClaw test instance helper 2026-04-29 00:50:55 +01:00
Peter Steinberger
8f4cbbbe66 perf(prompt): stabilize channel prompt suffix 2026-04-29 00:49:57 +01:00
Peter Steinberger
d3683a61c5 fix(bonjour): recover from ciao cancellation
(cherry picked from commit c34ba97262)
2026-04-29 00:49:41 +01:00
AARON AGENT
7dc0041ca9 fix(sandbox): add once option to Docker abort listener (#58277)
Merged via squash.

Prepared head SHA: 692dd15014
Reviewed-by: @sallyom
2026-04-28 19:47:52 -04:00
Patrick Erichsen
2a7ba582cb Use kitchen sink for ClawHub plugin E2E (#73821) 2026-04-28 16:44:38 -07:00
Vincent Koc
8cca1598d9 fix(plugins): satisfy gauntlet script lint 2026-04-28 16:44:13 -07:00
Vincent Koc
e4cb0f6683 fix(plugins): run gauntlet qa through source cli 2026-04-28 16:44:12 -07:00
Vincent Koc
de3f8af48e fix(plugins): allow bundled gauntlet install scan 2026-04-28 16:44:12 -07:00
Vincent Koc
dd31a27e71 fix(plugins): run gauntlet against built cli 2026-04-28 16:44:11 -07:00
Vincent Koc
8c9cac244d fix(plugins): print gauntlet failure details 2026-04-28 16:44:11 -07:00
Vincent Koc
516a91243f fix(plugins): link gauntlet lifecycle installs 2026-04-28 16:44:11 -07:00
Vincent Koc
a6dfaaeb4e test(plugins): add gateway gauntlet 2026-04-28 16:44:10 -07:00
Peter Steinberger
ef58307f84 fix(ci): keep video live helper within plugin boundary 2026-04-29 00:40:42 +01:00
Peter Steinberger
b04c9380ed fix(ci): harden full release live checks 2026-04-29 00:36:49 +01:00
pashpashpash
43fa40a35d fix(telegram): use owners for exec approvals (#73852) 2026-04-29 08:34:46 +09:00
Patrick Erichsen
a235a487d0 docs: add clawhub rescan recovery guidance (#73414)
* docs: add clawhub rescan recovery guidance

* docs: clarify clawhub rescan wording
2026-04-28 16:34:00 -07:00
imanewstudent
e2b825eba4 fix: add local build context to docker-compose (#65894)
Merged via squash.

Prepared head SHA: d8ad8d89b7
Reviewed-by: @sallyom
2026-04-28 19:29:30 -04:00
Vincent Koc
9c9dcd4d5d ci: shard agent runtime codeql quality
Add the agent runtime boundary to the CodeQL Critical Quality workflow.
2026-04-28 16:18:33 -07:00
Peter Steinberger
a0f0c964fd test(ci): tolerate live STT brand drift 2026-04-29 00:11:31 +01:00
Peter Steinberger
d86ad7a61b test(ci): accept compact codex status output 2026-04-29 00:03:09 +01:00
Joe LaPenna
a3f74410e4 build: ignore generated docker-compose.sandbox.yml (#64257) 2026-04-28 19:02:45 -04:00
Peter Steinberger
955b4df093 fix(ci): stabilize full release validation 2026-04-28 23:54:43 +01:00
jinjim
490e6d6dc5 feat(docker): add OPENCLAW_SKIP_ONBOARDING env to skip onboarding during Docker setup (#55518)
Merged via squash.

Prepared head SHA: 2744ed8b53
Co-authored-by: jinjimz <201528812+jinjimz@users.noreply.github.com>
Co-authored-by: sallyom <11166065+sallyom@users.noreply.github.com>
Reviewed-by: @sallyom
2026-04-28 18:50:51 -04:00
Peter Steinberger
bcc6a2400d fix(gateway): make handshake timeout configurable 2026-04-28 23:50:24 +01:00
Peter Steinberger
75df09b9ec perf(plugins): cache runtime mirror file decisions 2026-04-28 23:40:43 +01:00
pashpashpash
6ce1058296 Wire diagnostics through the core chat command (#72936)
* feat: wire codex diagnostics feedback

* fix: harden codex diagnostics hints

* fix: neutralize codex diagnostics output

* fix: tighten codex diagnostics safeguards

* fix: bound codex diagnostics feedback output

* fix: tighten codex diagnostics throttling

* fix: confirm codex diagnostics uploads

* docs: clarify codex diagnostics add-on

* fix: route diagnostics through core command

* fix: tighten diagnostics authorization

* fix: pin diagnostics to bundled codex command

* fix: limit owner status in plugin commands

* fix: scope diagnostics confirmations

* fix: scope codex diagnostics cooldowns

* fix: harden codex diagnostics ownership scopes

* fix: harden diagnostics command trust and display

* fix: keep diagnostics command trust internal

* fix: clarify diagnostics exec boundary

* fix: consume codex diagnostics confirmations atomically

* test: include codex diagnostics binding metadata

* test: use string codex binding timestamps

* fix: keep reserved command trust host-only

* fix: harden diagnostics trust and resume hints

* wire diagnostics through exec approval

* fix: keep diagnostics tests aligned with bundled root trust

* fix telegram diagnostics owner auth

* route trajectory exports through exec approval

* fix trajectory exec command encoding

* fix telegram group owner auth

* fix export trajectory approval hardening

* fix pairing command owner bootstrap

* fix telegram owner exec approvals

* fix: make diagnostics approval flow pasteable

* fix: route native sensitive command followups

* fix: invoke diagnostics exports with current cli

* fix: refresh exec approval protocol models

* fix: list codex diagnostics from thread bindings

* fix: fold codex diagnostics into exec approval

* fix: preserve diagnostics approval line breaks

* docs: clarify diagnostics codex workflow
2026-04-29 07:40:37 +09:00
Peter Steinberger
7e41913a20 fix(gateway): reduce TUI history startup latency 2026-04-28 23:34:59 +01:00
Peter Steinberger
f4a9d34f98 fix(model): explain rejected session overrides 2026-04-28 23:33:24 +01:00
Peter Steinberger
baeba45be9 test: speed up tts contract shard 2026-04-28 23:28:10 +01:00
Peter Steinberger
60861b3823 ci: use api key auth for Codex CLI backend smoke 2026-04-28 23:24:45 +01:00
Peter Steinberger
e583db63c6 test(ci): stabilize release validation flakes 2026-04-28 23:10:34 +01:00
Peter Steinberger
eb970bdb42 fix(tasks): repair terminal mirrored flow timestamps 2026-04-28 23:09:37 +01:00
Peter Steinberger
1184925572 fix(ci): speed up release validation live probes 2026-04-28 23:03:57 +01:00
Peter Steinberger
cc7a209982 fix: normalize QA model refs for parity gates 2026-04-28 23:01:58 +01:00
Peter Steinberger
5ef6e82685 fix(cli): skip plugin bootstrap for json gateway agents 2026-04-28 22:54:42 +01:00
Vincent Koc
e7947948b6 test(ci): add plugin prerelease suite to CI (#73741)
* test(ci): route plugin prerelease coverage to plugin shard

* test(ci): add plugin prerelease suite to CI

* fix(ci): preserve pnpm path in plugin prerelease shard

* fix(ci): avoid inheriting secrets for plugin prerelease suite
2026-04-28 14:52:03 -07:00
Peter Steinberger
69fb7455c6 fix(ci): harden full release validation monitors 2026-04-28 22:36:14 +01:00
Peter Steinberger
d9b46e0551 ci: start repo live release checks earlier 2026-04-28 22:18:41 +01:00
Peter Steinberger
25f7e062e1 fix(ci): harden cross-os release harness 2026-04-28 22:12:27 +01:00
Peter Steinberger
7b2b0d07e8 fix(ci): disable compile cache for cross-os upgrades 2026-04-28 22:02:12 +01:00
Vincent Koc
7a5638ea88 test(qa): restore GPT-5.5 scenario live metadata 2026-04-28 13:56:58 -07:00
Peter Steinberger
193c7432e3 fix(gateway): reuse paired auth for probes 2026-04-28 21:52:50 +01:00
Peter Steinberger
969cb8b4c0 ci: use standard runner for release package preparation 2026-04-28 21:51:30 +01:00
Said Urtabajev
652bde387d podman: wire OPENCLAW_INSTALL_BROWSER build-arg to setup script (#63407)
* podman: wire OPENCLAW_INSTALL_BROWSER build-arg to setup script

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

* chore: re-trigger CI

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-28 16:48:58 -04:00
Peter Steinberger
35059d1e3a ci: use standard runner for cross-os preparation 2026-04-28 21:47:35 +01:00
Vincent Koc
61960342b1 test(plugin): bound plugin update package smoke 2026-04-28 13:41:52 -07:00
Vincent Koc
14f140d6f0 docs(providers/bedrock): document Opus 4.7 temperature omission
For 771846c5fa: docs/providers/bedrock.md "Advanced configuration" now
includes a "Claude Opus 4.7 temperature" accordion describing that
OpenClaw automatically omits `temperature` for Opus 4.7 Bedrock refs
(foundation model ids, named profiles, application inference profiles
whose underlying model resolves to Opus 4.7, and dotted `opus-4.7`
variants with regional prefixes), since Bedrock rejects the parameter on
that model. The fix has no user-facing knob, but Opus 4.7 Bedrock users
need to know the request shape changes silently.
2026-04-28 13:39:53 -07:00
Peter Steinberger
d84ce5e419 fix(update): disable compile cache for post-update commands 2026-04-28 21:39:10 +01:00
Peter Steinberger
11d2128820 fix(ci): build complete release package artifacts 2026-04-28 21:39:10 +01:00
pashpashpash
78d51dcebe Clear Codex app-server env keys case-insensitively on Windows (#73102)
* fix(codex): clear app-server env case variants

* fix(codex): avoid repeated env clear scans
2026-04-29 05:34:14 +09:00
Vincent Koc
4509420dd4 test(qa): add gateway CPU scenario pack 2026-04-28 13:26:43 -07:00
Peter Steinberger
5e8d3130c6 fix(qa): include mention helpers in lab runtime 2026-04-28 21:23:32 +01:00
Peter Steinberger
5642653168 fix(qa): add mention helpers to lab harness 2026-04-28 21:20:53 +01:00
Peter Steinberger
da1084caf2 ci: start release checks on standard runner 2026-04-28 21:14:37 +01:00
Peter Steinberger
7ee85a1dd6 fix: align bootstrap landing check (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
7cefdd956a fix: unblock landing checks (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
18990f4fea test: avoid bundled discovery in disabled plugin test (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
b8f071a139 fix: isolate bundled plugin test roots (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
2f7c4070f4 fix: de-dupe doctor manifest repairs (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
c244ab5667 fix: unblock plugin landing checks (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Peter Steinberger
5b1202e11e fix: tighten BlueBubbles route identity hardening (#73235) (thanks @zqchris) 2026-04-28 21:06:49 +01:00
Chris Zhang
081e4be11e fix(bluebubbles): address aisle re-review on routing-guard PR
Three findings from the second pass:

1. **MEDIUM — Cross-chat short message ID guard bypassed on empty chat
   context (CWE-285).** When `requireKnownShortId=true` and `chatContext`
   was missing or `{}`, `resolveBlueBubblesMessageId` would still resolve
   the short id. Short ids are allocated from a single global counter
   across every account and chat, so an action call without a chat
   scope could silently apply to the wrong conversation. Throw "requires
   a chat scope" instead. The previous behavior was an explicit
   "fail-open" choice with a comment acknowledging the risk; the
   underlying assumption (downstream call carries chatGuid) does not
   hold for every action handler. Test rewritten to expect fail-closed.

2. **LOW — Unsanitized messageId reflected in cross-chat guard error
   (CWE-117 / CWE-200).** The thrown error embedded the raw inputId
   (and the raw chatGuid / chatIdentifier from the cached entry until
   the previous pass). Replace the inputId with a shape descriptor
   (`<short:N-digit>` or `<uuid:prefix…>`) so cross-chat errors no
   longer leak any concrete identifier. Combined with the chat
   identifier redaction in describeChatForError (already in place),
   the error is fully redacted.

3. **LOW — PII exposure via verbose logs (CWE-532).** Untrusted webhook
   identifiers (senderId / messageId / action) were already passed
   through `sanitizeForLog`, but the helper only stripped control
   characters — it did not redact secrets such as `?password=` query
   strings or `Authorization: Bearer …` headers that occasionally
   bleed into error chains. Extend `sanitizeForLog` to redact those
   patterns. All call sites benefit immediately.
2026-04-28 21:06:49 +01:00
Chris Zhang
81fd4d560a fix(bluebubbles): address aisle review on routing-guard PR
Four findings on this PR, all addressed in this commit:

1. **Cross-chat guard bypass when ctx.chatGuid present but cached lacks chatGuid**
   (CWE-697). Earlier `isCrossChatMismatch` gated chatIdentifier and chatId
   fallback comparisons on `!ctxChatGuid`, which let any non-empty
   ctx.chatGuid suppress the fallback checks when the cached entry happened
   to lack chatGuid — letting a short id from chat A be reused while acting
   in chat B. Rewrite the function so chatIdentifier/chatId comparisons
   run independently based on availability on each side, not on whether
   ctx.chatGuid happens to be present.

2. **Sensitive chat identifiers exposed via thrown cross-chat error**
   (CWE-200). `describeChatForError` interpolated raw chatGuid /
   chatIdentifier / chatId into the error message — these can leak phone
   numbers / email addresses / chat GUIDs into agent transcripts, tool
   results, remote channel deliveries, or third-party log aggregators.
   Surface only the *shape* of the chat target with `=<redacted>` values.

3. **Group reaction drop-guard bypass via whitespace chatIdentifier**.
   Earlier guard treated "" as missing but accepted " " / "\t". Trim
   chatGuid/chatIdentifier before the missing-check so a webhook sender
   supplying whitespace cannot satisfy the guard and have peerId degrade
   to the literal "group".

4. **Log injection via webhook senderId/messageId in verbose log lines**
   (CWE-117). Untrusted webhook fields were interpolated directly into
   `logVerbose` calls without sanitization, allowing log forging if a
   sender carried CR/LF/control bytes. Wrap with the existing
   `sanitizeForLog()` helper at all such sites.

Test updates: monitor-reply-cache.test.ts cross-chat error assertions
now expect `chatGuid=<redacted>` instead of raw values.
2026-04-28 21:06:49 +01:00
Chris Zhang
8fe7d495bc docs(changelog): note BlueBubbles routing-guard hardening 2026-04-28 21:06:49 +01:00
Chris Zhang
b1195c6452 fix(bluebubbles): distinguish DM vs group chat_guid in outbound session route
resolveBlueBubblesOutboundSessionRoute classified all `chat_guid:`
prefixed targets as groups:

    const isGroup =
      parsed.kind === "chat_id" ||
      parsed.kind === "chat_guid" ||
      parsed.kind === "chat_identifier";

But BlueBubbles also encodes DM chatGuids in the same `chat_guid:`
form — they look like `iMessage;-;+15551234567` (the `;-;` separator
is the DM marker; groups use `;+;`). Treating those as groups gave
the same DM two different sessionKeys depending on how the caller
addressed it:

- handle form (`bluebubbles:imessage:+15551234567`)
  → peer.kind = "direct", from = `bluebubbles:+15551234567`
- chat_guid form (`bluebubbles:chat_guid:iMessage;-;+15551234567`)
  → peer.kind = "group", from = `group:iMessage;-;+15551234567`

When a bound DM session was looked up against the second form, no
binding matched and the outbound landed in a freshly-synthesized
"group" sessionKey — a degenerate session that the next inbound
message also failed to find, surfacing the conversation in the
wrong place.

Use resolveGroupFlagFromChatGuid (already used by monitor-normalize
to read the same marker for inbound webhooks) so both directions
agree on what counts as a group. Unknown chatGuid shapes still
fall back to "group" to preserve prior behavior — we never
silently downgrade a real group to direct.

Tests: extensions/bluebubbles/src/session-route.test.ts (new)
- chat_guid `;-;` → direct
- chat_guid `;+;` → group
- chat_guid with no recognizable marker → group (back-compat)
- handle target → direct
- chat_id / chat_identifier → group (unchanged)
- DM addressed two ways converges on the same peer kind

Local patch for upstream consideration. Latent bug introduced by
0f7cd59824 (BlueBubbles: move outbound session routing behind plugin
boundary), not commonly hit because most outbound DM call sites use
the handle form, but a real foot-gun for callers that pass the
chat_guid form.
2026-04-28 21:06:49 +01:00
Chris Zhang
07089f11c7 fix(bluebubbles): drop group reactions that arrive without any chat identifier
processReaction's peerId calculation:

    const peerId = reaction.isGroup
      ? (chatGuid ?? chatIdentifier ?? (chatId ? String(chatId) : "group"))
      : reaction.senderId;

reads as "if it's a group with at least one chat hint, use that hint;
otherwise fall through to either the literal string 'group' (group case)
or the sender id (DM case)". Two failure modes hide here:

1. BlueBubbles fires a `message-reaction` event with `isGroup: true` but
   omits chatGuid AND chatId AND chatIdentifier — peerId becomes the
   literal "group" and resolveBlueBubblesConversationRoute synthesizes
   a session key unrelated to any real binding. The reaction surfaces in
   whatever session the binding fallback picks, never the right one.

2. The same payload arrives with isGroup misclassified as false (BB's
   group-flag inference relies on chatGuid, explicit isGroup, or
   participants > 2 — none of which are guaranteed for reaction events;
   monitor.webhook.test-helpers.ts even ships a default reaction fixture
   with no chatGuid and isGroup defaulted to false). peerId then becomes
   reaction.senderId and the event is enqueued into the sender's DM
   session — the group tapback shows up inside an unrelated 1:1
   transcript Chris was looking at.

Neither outcome is recoverable without a chat hint — without chatGuid,
chatId, or chatIdentifier we cannot identify which group the reaction
belongs to. Drop the event with a verbose-log and let the agent miss
that reaction rather than route it incorrectly. DM reactions (which
legitimately may arrive with no chat hint and only a sender) keep
working because the guard is gated on `reaction.isGroup === true`.

A latent risk remains: if BB ever sends an isGroup-misclassified-as-false
payload, this guard does not catch it. That would require teaching
normalize to surface group-flag confidence, which is a larger change
left for follow-up.

Tests (extensions/bluebubbles/src/monitor.test.ts):
- Group reaction with no chat identifiers → not enqueued
- Group reaction with at least one chat identifier → still enqueued
  (regression sentinel for the new guard)

Local patch for upstream consideration.
2026-04-28 21:06:49 +01:00
Chris Zhang
6ade320421 fix(bluebubbles): apply cross-chat guard to full message GUIDs as well
The cross-chat guard added in the prior commit (resolveBlueBubblesMessageId
with chatContext) only ran on numeric short ids — `if (/^\d+$/.test(trimmed))`.
Full GUID input fell through to `return trimmed` with no chat check.

Once the short-id guard started rejecting cross-chat reuses, agents would
retry the same call with the full GUID copied from history or a previous
tool result. That second attempt bypassed the guard entirely and the
group reaction landed in the DM anyway — exactly the symptom the prior
commit was meant to close.

Apply the same `isCrossChatMismatch` check to full GUID input. Cache miss
still falls through (callers may legitimately supply a fresh-from-the-wire
GUID the cache hasn't observed yet), but cache hits with a chat mismatch
throw with a remediation hint pointed at the chat target rather than at
the id format — telling an agent to "retry with the full GUID" makes no
sense when it already supplied one.

Tests (extensions/bluebubbles/src/monitor-reply-cache.test.ts):
- UUID + same chat → resolves
- UUID + different chat → throws (this is the regression)
- UUID + cache miss → passes through (preserves behavior for fresh GUIDs)
- UUID + empty chatContext → passes through (preserves prior behavior)
- UUID error message hints at the chat target, not the id format
- chatIdentifier fallback applies to UUID input too

Local patch for upstream consideration — completes the cross-chat guard
started in the prior commit so both id forms are protected symmetrically.
2026-04-28 21:06:49 +01:00
Chris Zhang
4bd3d258cd fix(bluebubbles): refuse sender-DM fallback when resolving group inbound chatGuid
When a BlueBubbles inbound webhook arrives without `chatGuid`, processMessage
falls back to `resolveChatGuidForTarget` to look it up. The previous fallback
target was:

    isGroup && (chatId || chatIdentifier)
      ? <chat_id or chat_identifier>
      : { kind: "handle", address: message.senderId }

That `else` branch quietly covered two very different cases:

1. DM with no chatGuid — resolving via sender handle is correct, the chat
   IS the conversation with that handle.
2. **Group with no chatGuid AND no chatId AND no chatIdentifier** — resolving
   via sender handle yields *that sender's DM chatGuid*, then the rest of
   processMessage uses it for ack reactions, mark-read, outbound reply cache,
   typing indicators, and outboundTarget.

Case 2 is reachable: `monitor.webhook.test-helpers.ts` ships a default
`createMessageReactionPayloadForTest` payload with no chatGuid/chatId/
chatIdentifier and `isGroup` defaulted to `false`, mirroring real BlueBubbles
reaction/tapback webhooks. When a group reaction or tapback arrives in that
shape and isGroup is later corrected to true (or the message takes the same
poisoned path), `chatGuidForActions` becomes the sender's DM chatGuid. The
poisoned chatGuid then writes the outbound reply cache (line ~1395) with the
wrong chat, defeating the cross-chat short-id guard added in
9912472289 — a later short id resolved against that cache cannot detect the
mismatch and the agent's reaction/reply silently lands in the DM.

Symptom Chris observed (recurring after 9912472289 baked): group messages
getting reacted to from the agent's side show up in a DM transcript with
that sender, attached to a message GUID the user can no longer locate in
the DM.

Extract the fallback target construction into
`buildBlueBubblesInboundChatResolveTarget` so the rule is testable in
isolation and the wrong fallback can never be reached again:

- Group inbound + chatId present → `chat_id`
- Group inbound + chatIdentifier present → `chat_identifier`
- **Group inbound + neither → return null (caller skips chatGuid-dependent actions)**
- DM inbound → `handle` (unchanged: the conversation IS that sender)

processMessage now logs at verbose when the group case returns null instead
of silently degrading to the sender's DM.

Tests: extensions/bluebubbles/src/monitor-processing-chat-resolve.test.ts
covers the eight branches (group with id, group with identifier, group
preferring id, group with neither, blank/non-finite/null variants, DM, DM
with chat_id present, DM with empty sender).

Local patch for upstream consideration — pairs with the short-id chat guard
landed in the previous commit.
2026-04-28 21:06:49 +01:00
Chris Zhang
9f97e8c521 fix(bluebubbles): scope short message id resolution to the caller's chat
BlueBubbles short message ids (numeric aliases like "1", "5" that agents
use instead of full GUIDs to save tokens) are allocated from a single
global counter across every account and every chat. Nothing in
resolveBlueBubblesMessageId verified that the resolved GUID was actually
in the chat the caller was acting on, so any time an agent reused or
mis-remembered a short id — especially common after a long group
conversation — the id could silently point at a different chat entirely.

Symptom Chris observed: reactions/tapbacks and quoted replies authored
inside a group would intermittently land in a DM, targeting an old
message the user could no longer see. Tool call looks successful, chat
archive shows a group reaction appearing in the DM transcript.

Add an optional chatContext parameter to resolveBlueBubblesMessageId
(chatGuid / chatIdentifier / chatId). When provided, look up the
cached reply entry for the resolved GUID and compare. A clear mismatch
(same identifier present on both sides, different values) throws with a
message that lists both chats and points at "use the full GUID", so the
agent fails fast and retries with a disambiguated id. Ambiguous cases
(either side missing all identifiers) pass through to preserve existing
behavior for callers that cannot supply chat hints. The comparison
mirrors resolveReplyContextFromCache so outbound and inbound paths agree
on scope.

Update every call site that resolves a short id for outbound BB traffic
to pass chatContext:
- extensions/bluebubbles/src/actions.ts: react, edit, unsend, reply
  (build context from chat* params, then to/target, then the tool's
  currentChannelId)
- extensions/bluebubbles/src/channel.ts sendText: derive context from
  the `to` target
- extensions/bluebubbles/src/media-send.ts: same
- extensions/bluebubbles/src/monitor-processing.ts deliver path: pass
  the chat already resolved for routing

Add buildBlueBubblesChatContextFromTarget to targets.ts so callers can
project a raw target string (`chat_guid:...`, `chat_id:42`,
`imessage:+1...`, bare handle) into the context shape.

Tests:
- extensions/bluebubbles/src/monitor-reply-cache.test.ts (new, 8 cases):
  same-chat resolves, cross-chatGuid throws, ambiguous passes,
  chatIdentifier fallback, chatId fallback, full GUID input bypasses,
  error message identifies both chats, unknown short id still errors.
- extensions/bluebubbles/src/actions.test.ts: update the react short-id
  assertion to verify chatContext now flows through.

Local patch for upstream consideration — same root cause affects every
BB user; plan is to open a separate upstream PR once this bakes locally.
2026-04-28 21:06:49 +01:00
Peter Steinberger
96a21e2553 fix(qa): restore release channel reply checks 2026-04-28 21:05:35 +01:00
Peter Steinberger
3aac8e650c fix(googlechat): keep config schema on runtime api 2026-04-28 21:04:44 +01:00
Peter Steinberger
5dfc14d49b fix(tasks): close stale terminal acp sessions 2026-04-28 21:03:55 +01:00
Peter Steinberger
3cad579c4e fix(plugin-sdk): restore discord compatibility facade 2026-04-28 20:59:26 +01:00
Peter Steinberger
d1a7612bd6 docs(changelog): narrow gateway status fix reference 2026-04-28 20:58:09 +01:00
Peter Steinberger
c399fb750b fix(ui): handle Google Live binary talk frames 2026-04-28 20:57:46 +01:00
Peter Steinberger
0a2d635e68 fix(gateway): harden local reachability checks
Co-authored-by: arthurianresolve <arthurianresolve@users.noreply.github.com>
Co-authored-by: codexGW <9350182+codexGW@users.noreply.github.com>
2026-04-28 20:57:14 +01:00
Peter Steinberger
3d736f67cf test: fix onboard Docker test state setup 2026-04-28 20:56:19 +01:00
Peter Steinberger
c1c217035d test: align bare reset bootstrap expectation 2026-04-28 20:56:04 +01:00
Peter Steinberger
3b593bc561 fix(cli): authorize gateway model probe overrides 2026-04-28 20:55:44 +01:00
Vincent Koc
87172dc9fe fix(ci): harden package acceptance refs 2026-04-28 12:53:05 -07:00
Peter Steinberger
f0c8640d81 test: speed up read-only channel fixtures 2026-04-28 20:49:55 +01:00
Peter Steinberger
0dcab4e347 fix(agents): harden bootstrap and ACP session routing 2026-04-28 20:47:34 +01:00
Vincent Koc
3ae69498e2 ci: shard channel codeql security
Add a narrow channel-runtime CodeQL critical-security shard and document it.
2026-04-28 12:46:44 -07:00
Peter Steinberger
230f8886c6 ci: keep full release validation children pinned 2026-04-28 20:43:39 +01:00
HeYan
170a961744 fix(config): guard non-string values in env.vars to prevent TypeError (#42402)
* fix(config): guard non-string values in env.vars to prevent TypeError (#42363)

* docs(changelog): note malformed env vars crash fix

---------

Co-authored-by: Altay <altay@uinaf.dev>
2026-04-28 22:43:22 +03:00
Peter Steinberger
0f3a9d812b docs(changelog): note model auth fixes 2026-04-28 20:40:11 +01:00
Peter Steinberger
771846c5fa fix(bedrock): omit Opus temperature for profiles 2026-04-28 20:39:58 +01:00
Peter Steinberger
1f26e32f5f fix(agents): strip empty assistant transcript text 2026-04-28 20:39:58 +01:00
Peter Steinberger
1824ceba54 fix(agents): reuse cached Claude keychain credentials 2026-04-28 20:39:58 +01:00
Peter Steinberger
aec5efed8d fix(agents): resolve model aliases before fallback 2026-04-28 20:39:58 +01:00
Peter Steinberger
06a0cd88fb fix(discord): align gateway metadata timeout tests 2026-04-28 20:39:28 +01:00
Peter Steinberger
0608c1015b perf(plugins): cache manifest metadata loads 2026-04-28 20:39:28 +01:00
Vincent Koc
98f5fd12df docs(gateway/security): list system-reminder and previous_response in outbound stripping
For c2d31a5e59: docs/gateway/security/index.md "External content
special-token sanitization" section already mentions the outbound
sanitizer with `<tool_call>` and `<function_calls>` examples, but it
predates the new internal-runtime-scaffolding stripping that targets
`<system-reminder>` and `<previous_response>` tags. Adds those two tags
as explicit examples and notes the final channel delivery boundary so
operators reading the security page see the same coverage exposed by
the c2d31a5e59 sanitizer.
2026-04-28 12:39:15 -07:00
Peter Steinberger
c500e8704f fix(gateway): recover stale session lanes 2026-04-28 20:37:29 +01:00
Peter Steinberger
933c7968dc fix(ci): stabilize full release validation lanes 2026-04-28 20:36:42 +01:00
Peter Steinberger
1e9faa2a59 docs: document inter-session prompt guards 2026-04-28 20:34:55 +01:00
Peter Steinberger
c2d31a5e59 fix(outbound): strip internal runtime scaffolding 2026-04-28 20:34:55 +01:00
Peter Steinberger
c5c08c074a fix(agents): mark inter-session prompts 2026-04-28 20:34:54 +01:00
Peter Steinberger
5de06ac00e test: keep bundled root fixtures scoped 2026-04-28 20:28:45 +01:00
Peter Steinberger
cb8c513ce3 fix(telegram): honor final-only streaming mode 2026-04-28 20:28:06 +01:00
Vincent Koc
df8611c420 test(loader): re-enable bundled fixtures 2026-04-28 12:24:28 -07:00
Vincent Koc
b014462690 fix(test): trust bundled plugin fixtures explicitly 2026-04-28 12:24:28 -07:00
Peter Steinberger
0311e172e0 test: preserve bundled dir fixture helpers 2026-04-28 20:19:51 +01:00
Peter Steinberger
c89b67e6c8 test(config): isolate bundled channel metadata fixture 2026-04-28 20:17:51 +01:00
Peter Steinberger
9f37ff0c6c test: allow bundled root fixtures under vitest 2026-04-28 20:14:56 +01:00
Peter Steinberger
e61756f9e8 test(plugin-sdk): avoid heavy facade fallback fixture 2026-04-28 20:14:14 +01:00
Peter Steinberger
df4e2ecb87 fix(plugin-sdk): expose concrete memory host types 2026-04-28 20:14:14 +01:00
Peter Steinberger
4a24b23e3e fix(ci): stabilize full release validation 2026-04-28 20:14:14 +01:00
Peter Steinberger
f641691910 fix(discord): harden account and binding routing 2026-04-28 20:08:27 +01:00
Vincent Koc
87fd216d9a chore(plugin-sdk): refresh api baseline 2026-04-28 12:06:27 -07:00
Peter Steinberger
702e5fc4a9 test: isolate facade bundled fixture roots 2026-04-28 20:04:06 +01:00
Peter Steinberger
6d4599a796 fix: satisfy discord gateway lint 2026-04-28 19:54:52 +01:00
Peter Steinberger
f2f34e5f35 fix: restore ci gates on main 2026-04-28 19:54:52 +01:00
Vincent Koc
bb0461b682 ci: shard channel codeql quality
Add a narrow channel-runtime CodeQL critical-quality shard and document it.
2026-04-28 11:52:54 -07:00
Peter Steinberger
6d542ebcee test: clean up Docker test-state leftovers 2026-04-28 19:50:51 +01:00
Peter Steinberger
d22a851253 test: reuse Docker test-state in core E2E lanes 2026-04-28 19:47:11 +01:00
Peter Steinberger
4b69dc6228 docs(changelog): note discord gateway fixes 2026-04-28 19:40:06 +01:00
Peter Steinberger
7191f1a1eb fix(discord): tune gateway intents and metadata timeout 2026-04-28 19:39:49 +01:00
Peter Steinberger
065284deab fix(auto-reply): pass model catalog to think menus 2026-04-28 19:37:10 +01:00
Kevin Lin
f351961173 fix: log fetch timeout aborts (#73692)
* fix: log fetch timeout aborts

* fix: redact relative timeout urls
2026-04-28 11:36:10 -07:00
Vincent Koc
dcd665cd05 fix(nvidia): align NIM provider metadata
Persist the NVIDIA_API_KEY marker in generated catalog output and mark bundled NVIDIA Chat Completions models as string-content compatible.\n\nFixes #73013.\nFixes #50107.\nRefs #73014.
2026-04-28 11:30:57 -07:00
Peter Steinberger
e2295b33c1 fix(ci): restore full release validation blockers 2026-04-28 19:20:18 +01:00
Peter Steinberger
2290adbf57 test: reuse Docker test-state in more lanes 2026-04-28 19:19:53 +01:00
Vincent Koc
e476523082 ci: shard gateway codeql quality
Add a narrow gateway/runtime CodeQL critical-quality shard and document it.
2026-04-28 11:16:48 -07:00
Peter Steinberger
cd2e13be8a test: isolate channel catalog fixtures 2026-04-28 19:06:38 +01:00
Peter Steinberger
84154bb09c perf(test): speed up boundary report checks 2026-04-28 19:00:22 +01:00
Peter Steinberger
53d34e7cde fix(cli): support image files in model probes 2026-04-28 18:52:15 +01:00
Peter Steinberger
3f780bb27d test: share Docker test-state wrapper 2026-04-28 18:47:45 +01:00
Vincent Koc
4d82dc4fb4 docs(skills): expand test performance workflow 2026-04-28 10:41:53 -07:00
Vincent Koc
6d323ee736 docs(channels/groups): note native command bypass of visibleReplies
For 195f704c74: docs/channels/groups.md "Visible replies" section now
records that native slash commands (Discord, Telegram, and other surfaces
with native command support) reply visibly even when
`messages.groupChat.visibleReplies` is `"message_tool"`, so the channel-
native command UI gets the response it expects. Text-typed `/...` commands
and ordinary chat turns still follow the configured group default.
2026-04-28 10:24:14 -07:00
Vincent Koc
7d2d8732d0 docs(plugins/hooks): document per-hook timeoutMs registration option
For 891c7d9f1c: docs/plugins/hooks.md "Quick start" now lists the `priority`
and new `timeoutMs` opts that `api.on(...)` accepts, explaining that the
per-hook budget aborts a slow handler instead of letting plugin setup or
recall work consume the caller's configured model timeout. The change is
traceable to the new `OpenClawPluginApi.on` `{ priority?; timeoutMs? }`
signature and `PluginHookRegistration.timeoutMs` field added in the same
SHA.
2026-04-28 10:12:44 -07:00
Shakker
c0ec58f4b6 fix: preserve runtime kind install fallback 2026-04-28 18:04:54 +01:00
Shakker
a48ffda7f7 chore: trace plugin lifecycle phases 2026-04-28 18:03:01 +01:00
Shakker
3d89b0f2ec fix: use plugin metadata for install slots 2026-04-28 18:02:40 +01:00
Neerav Makwana
3de5476f51 fix(auto-reply): preserve DM continuity across silent session rotations (#70898)
Merged via squash.

Prepared head SHA: 13bd2cef86
Co-authored-by: neeravmakwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-28 10:01:15 -07:00
Ayaan Zaidi
7120f5b254 docs(changelog): note native command group reply fix 2026-04-28 22:11:27 +05:30
Ayaan Zaidi
8af50b5b4c fix(commands): preserve owner allowlists for native auth 2026-04-28 22:11:27 +05:30
Ayaan Zaidi
195f704c74 fix(reply): keep native command replies visible 2026-04-28 22:11:27 +05:30
Ayaan Zaidi
7b91f06384 fix(commands): honor channel-native command auth 2026-04-28 22:11:27 +05:30
Pavan Kumar Gondhi
bdfb408ce6 fix(plugins): restrict bundled plugin dir resolution to trusted package roots (#73275)
* fix: address issue

* fix: address review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* fix: address PR review feedback

* fix: address review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address review feedback

* docs: add changelog entry for PR merge
2026-04-28 21:35:32 +05:30
Pavan Kumar Gondhi
230f7122dd fix(security): prevent workspace PATH injection via service env and trash helpers (#73264)
* fix: address issue

* fix: address PR review feedback

* fix: address review-pr skill feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address build feedback

* fix: address PR review feedback

* docs: add changelog entry for PR merge
2026-04-28 21:30:51 +05:30
Ayaan Zaidi
b79e617ad1 fix: persist Telegram native command metadata (#57548) (thanks @GaosCode) 2026-04-28 21:18:58 +05:30
Ayaan Zaidi
c57960b8d1 fix(telegram): distill native metadata session key 2026-04-28 21:18:58 +05:30
MrBrain
c4f741e534 fix(telegram): persist native command metadata to target sessions 2026-04-28 21:18:58 +05:30
Harry Xie
891c7d9f1c fix(active-memory): align recall timeout with hook runner
Fixes #72606.
2026-04-28 10:15:01 -05:00
Tak Hoffman
f256eeba43 fix(active-memory): use bundled recall tool
Fixes #73502.

Active Memory now allows its hidden recall sub-agent to use both bundled memory tool contracts: memory_recall for memory-lancedb and memory_search/memory_get for memory-core. The prompt prefers memory_recall when available and falls back to the legacy tool pair when that is the active backend surface.

Also updates Active Memory docs, QA mock fixtures, and debug parsing compatibility for the two recall paths.
2026-04-28 09:03:47 -05:00
Radek Sienkiewicz
dd643c82b5 fix(whatsapp): expose Baileys socket timing (#73580)
Merged via squash.

Prepared head SHA: d34755262f
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
2026-04-28 15:46:47 +02:00
Joseph Krug
16906780fd feat(active-memory): return partial transcript on timeout (openclaw#73219)
Verified:
- pnpm test extensions/active-memory/index.test.ts
- pnpm exec oxfmt --check --threads=1 extensions/active-memory/index.ts extensions/active-memory/index.test.ts CHANGELOG.md
- git diff --check

Co-authored-by: joeykrug <5925937+joeykrug@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:44:46 -05:00
Lidang Jiang
6d539db011 fix: support explicit active-memory chat types (openclaw#66285)
Verified:
- pnpm install --frozen-lockfile
- pnpm test extensions/active-memory/config.test.ts extensions/active-memory/index.test.ts
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md extensions/active-memory/index.ts extensions/active-memory/index.test.ts extensions/active-memory/config.test.ts extensions/active-memory/openclaw.plugin.json
- git diff --check

Co-authored-by: Lidang-Jiang <119769478+Lidang-Jiang@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:43:06 -05:00
Peter
ba17b8b728 docs(active-memory): document cacheTtlMs bounds (#65708) (openclaw#65737)
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test (local full suite failed in unrelated plugin/logging shards; PR-specific docs/changelog checks and GitHub checks passed)
- GitHub status checks for c2c5a94df8 completed without failure

Co-authored-by: WuKongAI-CMU <210765158+WuKongAI-CMU@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:42:16 -05:00
quengh
373e7fc242 feat(active-memory): add allowedChatIds/deniedChatIds per-conversation filters (openclaw#67977)
Verified:
- pnpm install --frozen-lockfile
- git diff --check
- pnpm exec oxfmt --check --threads=1 extensions/active-memory/index.ts extensions/active-memory/index.test.ts docs/concepts/active-memory.md CHANGELOG.md
- OPENCLAW_TEST_HEAVY_CHECK_LOCK_HELD=1 OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=.vitest-cache-pr67977 pnpm test extensions/active-memory/index.test.ts extensions/active-memory/config.test.ts
- gh pr checks 67977 --repo openclaw/openclaw --required

Co-authored-by: quengh <3940773+quengh@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:37:55 -05:00
Spolen23
12aaef9035 Fix infer CLI reliability gaps (openclaw#63263)
Verified:
- pnpm install --frozen-lockfile
- git diff --check
- pnpm test src/media-understanding/defaults.test.ts src/media-understanding/runner.vision-skip.test.ts src/media-understanding/runner.cli-audio.test.ts src/web-search/runtime.test.ts
- pnpm tsgo:test:src

Co-authored-by: Spolen23 <215900770+Spolen23@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:36:41 -05:00
SimbaKingjoe
bdb75bd8c7 fix(active-memory): skip payload-less memory_search toolResults in tr… (openclaw#68773)
Verified:
- pnpm install --frozen-lockfile
- pnpm test extensions/active-memory/index.test.ts
- pnpm exec oxfmt --check --threads=1 extensions/active-memory/index.ts extensions/active-memory/index.test.ts CHANGELOG.md
- git diff --check origin/main..HEAD
- gh pr checks 68773 --repo openclaw/openclaw --required

Co-authored-by: SimbaKingjoe <126222269+SimbaKingjoe@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-28 08:20:13 -05:00
Pavan Kumar Gondhi
189c91eae6 fix(device-pairing): validate callerScopes against resolved token scopes on repair [AI] (#72925)
* fix: address issue

* docs: add changelog entry for PR merge
2026-04-28 18:31:05 +05:30
Pavan Kumar Gondhi
037f197684 fix(agents): canonicalize provider aliases in byProvider tool policy lookup [AI] (#72917)
* fix: address issue

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* docs: add changelog entry for PR merge
2026-04-28 18:14:59 +05:30
Pavan Kumar Gondhi
ccb3af556f fix(security): block npm_execpath injection from workspace .env [AI-assisted] (#73262)
* fix: address issue

* fix: finalize issue changes

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* docs: add changelog entry for PR merge
2026-04-28 18:11:16 +05:30
Alex Knight
7a23c18830 fix(acpx): validate runtime session mode at wrapper boundary (#73071) (#73548) 2026-04-28 22:35:25 +10:00
Alex Knight
7a23b2d945 fix: decode web fetch legacy charsets (#73513)
* fix: decode web fetch legacy charsets
2026-04-28 22:09:06 +10:00
Alex Knight
e4ff7c1620 fix: Discord read/search timeout, session-key fallback, and gateway execution mode (#73521)
* fix: Discord read/search timeout, session-key fallback, and gateway execution mode

- Add 15s timeout to readMessagesDiscord and searchMessagesDiscord so they
  fail fast instead of hanging indefinitely (#73431)
- Fall back to CommandTargetSessionKey in dispatchReplyFromConfig when
  SessionKey is empty, so Discord inbound message:received hooks fire
  reliably (#73431, refs #33038)
- Add resolveExecutionMode to Discord channel actions routing read/search
  through gateway timeout path, matching Telegram's pattern (#73431)

* fix: move timeout to fetch layer, drop send.messages wrapper

Inject AbortSignal.timeout into the Discord proxy-request-client fetch
wrapper so every Discord REST call gets a 15s timeout at the HTTP level.
This replaces the Promise.race wrapper in send.messages.ts — cleaner,
covers all calls, and actually aborts the TCP connection.

* fix: remove unused callerController variable in proxy-request-client test

* fix: remove unnecessary mergeAbortSignal helper
2026-04-28 21:46:05 +10:00
Vincent Koc
c478aeca5a docs: cover cron_changed plugin hook and legacy env-var deprecation
- docs/plugins/hooks.md: add `cron_changed` to the Lifecycle hook catalog and
  a Gateway lifecycle paragraph describing its typed event payload, run
  status, delivery status, and removed-event job snapshot, so plugin authors
  picking up f155a5f955 (#72773) have a canonical reference beyond the
  sdk-overview bullet that already shipped in the same SHA.
- docs/help/environment.md: add a "Legacy environment variables" section for
  aa1834a3ff so users see that `CLAWDBOT_*` and `MOLTBOT_*` prefixes are now
  ignored and trigger an `OPENCLAW_LEGACY_ENV_VARS` deprecation warning,
  with a rename example to `OPENCLAW_*`.
2026-04-28 04:40:38 -07:00
Alex Knight
f155a5f955 Add cron changed plugin hook (#72773)
* feat: add cron changed plugin hook

* fix: improve cron_changed hook correctness and code quality

- Fix PluginHookGatewayCronDeliveryStatus: replace 'error' with 'unknown'
  to match internal CronDeliveryStatus enum
- Add job snapshot to CronEvent so removed events carry the deleted job
- Extract pickDefined helper, replace 14-field verbose spread mapping
- Add toPluginCronJob mapper for explicit internal→public type boundary
- Fix schedule union: use literal-only kind discriminants for TS narrowing
- Use loadConfig() (runtime) instead of params.cfg (startup) in hook ctx
- Use formatErrorMessage instead of String(err) for stack preservation
- Fix pre-existing getCron TS2322 with explicit cast (matches gateway_start)
- Re-export supporting types from hooks.ts for plugin consumers
- Add tests: removed events with job, finished with full fields, runtime cfg
2026-04-28 21:34:42 +10:00
Alex Knight
e84ebeafbd fix(memory-core): retry dreaming cron startup reconciliation (#73493)
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
2026-04-28 21:15:23 +10:00
Peter Steinberger
2ccdbc7dd9 fix(plugin-sdk): keep memory host wildcard shims 2026-04-28 12:08:13 +01:00
Peter Steinberger
343c69d7a1 fix: auto-enable media provider plugins 2026-04-28 12:05:30 +01:00
Peter Steinberger
3eb2a9d371 fix(plugin-sdk): drop unavailable memory host exports 2026-04-28 12:01:43 +01:00
Vincent Koc
e10f493160 ci: shard config codeql quality
Split config quality CodeQL results into a separate category while keeping the default quality bucket narrow.
2026-04-28 04:00:14 -07:00
Vincent Koc
75ba8398f9 fix(gateway): expose event loop health in readiness 2026-04-28 03:56:58 -07:00
Peter Steinberger
9f7932fbcc test: update gateway client callsite guard 2026-04-28 11:54:43 +01:00
Peter Steinberger
9e5aa10e97 fix(memory-host): preserve core resolver exports in sdk shims 2026-04-28 11:54:12 +01:00
Peter Steinberger
af10be59d8 fix(approvals): stop stale approval resume loops 2026-04-28 11:53:22 +01:00
Peter Steinberger
2a0af6754e ci: narrow ClawSweeper dispatch cancellation 2026-04-28 11:53:06 +01:00
Peter Steinberger
ba722fd126 test: speed up channel mcp tests 2026-04-28 11:49:18 +01:00
Peter Steinberger
8260b64f7a fix(memory-host): keep sdk shim exports complete 2026-04-28 11:48:59 +01:00
loongfay
7b07a0ab8f feat(channel) add yuanbao docs entrance (#73443)
* feat(channel) add yuanbao docs entrance

* feat(channel): add yuanbao docs entrance (#73443) (thanks @loongfay)

---------

Co-authored-by: loongzhao <loongzhao@tencent.com>
Co-authored-by: sliverp <870080352@qq.com>
2026-04-28 18:47:09 +08:00
Vincent Koc
d55c7ea997 fix(plugins): bound prompt memory recall latency 2026-04-28 03:46:18 -07:00
Peter Steinberger
5de284c2e3 fix(release): restore main release checks 2026-04-28 11:44:44 +01:00
Peter Steinberger
dc541662f8 docs(changelog): finalize 2026.4.27 notes 2026-04-28 11:41:29 +01:00
Vincent Koc
3c0eac31f1 docs(providers/qwen): note explicit qwen3.6-plus opt-in on Coding Plan
For 058b57867e: docs/providers/qwen.md "Qwen 3.6 Plus availability"
accordion now records that the bundled catalog still does not advertise
`qwen3.6-plus` on Coding Plan endpoints, but explicitly configured
`models.providers.qwen.models` entries for that model are honored on
Coding Plan baseUrls so subscribers whose plan enables it can opt in. The
upstream API still decides whether the call succeeds.
2026-04-28 03:40:39 -07:00
Peter Steinberger
adf166936a docs(changelog): document pairing and approval fixes 2026-04-28 11:38:18 +01:00
Peter Steinberger
6559288d4a fix(agents): hide successful resume fallback prefix 2026-04-28 11:38:18 +01:00
Peter Steinberger
6dec2e1852 fix(telegram): scope native approvals by target account 2026-04-28 11:38:18 +01:00
Peter Steinberger
279e6453fc fix(gateway): make repeated approval resolves idempotent 2026-04-28 11:38:18 +01:00
Peter Steinberger
885806d5ca fix(gateway): stop stale device token reconnect loops 2026-04-28 11:38:18 +01:00
Peter Steinberger
205d8d4994 fix(pairing): recover malformed pairing state files 2026-04-28 11:38:18 +01:00
Vincent Koc
aa1834a3ff fix(gateway): warn on legacy env vars
Fixes #53482.

Supersedes #53667.
2026-04-28 03:37:57 -07:00
Peter Steinberger
d770a3b786 test(memory): stabilize reindex and cron checks 2026-04-28 11:36:28 +01:00
Peter Steinberger
6a387afc53 refactor(memory-host): route sdk shims to package source 2026-04-28 11:36:28 +01:00
Peter Steinberger
94fc91e235 ci: harden clawsweeper dispatch workflow 2026-04-28 11:35:40 +01:00
Peter Steinberger
5a1ff1347d fix(slack): bound inbound media downloads 2026-04-28 11:35:26 +01:00
James Reagan
a722da3ed0 fix(gateway): align session thinking defaults (#63418)
Aligns Gateway history and session list thinking-default resolution so backend session state matches the Control UI default label:

- `chat.history` now falls back through the shared Gateway session thinking-default resolver.
- Explicit session overrides still win, then owning `agents.list[].thinkingDefault`, then global/model/catalog defaults.
- `sessions.list` catalog-aware thinking defaults are covered by focused regressions.

PR by @jpreagan.

Validated in Blacksmith Testbox `tbx_01kq9t1aeqrz1mj598vvqv9dpg`:
- `pnpm test:serial src/gateway/session-utils.test.ts src/gateway/server.sessions.gateway-server-sessions-a.test.ts src/gateway/server.chat.gateway-server-chat.test.ts` (141 passed)
- `OPENCLAW_TESTBOX=1 pnpm check:changed`
2026-04-28 03:34:58 -07:00
Vincent Koc
d70191f8af feat(sandbox): add Docker GPU passthrough
Add opt-in `sandbox.docker.gpus` config plumbing for Docker sandbox containers.

- thread the optional GPU passthrough field through config types, schema, resolution, and Docker create args
- reject empty config values and emit `--gpus` as a separate Docker argv pair
- document the Docker-only behavior and credit the original contributor in the changelog

Fixes #57976.
Carries forward #58124 from @cyan-ember.

Co-authored-by: cyan-ember <5855097+cyan-ember@users.noreply.github.com>
2026-04-28 03:33:28 -07:00
Peter Steinberger
7150acba69 ci: debounce clawsweeper dispatch metadata 2026-04-28 11:31:49 +01:00
Peter Steinberger
35bc13f9ef fix: prefer OpenAI media for Codex defaults 2026-04-28 11:30:17 +01:00
Shakker
32c987626b fix: prune stale plugin runtime mirror entries 2026-04-28 11:25:09 +01:00
Shakker
92016b82ae fix: refresh plugin runtime mirrors in place 2026-04-28 11:25:09 +01:00
Shakker
7727e102a5 fix: scope plugin inspect runtime loading 2026-04-28 11:25:09 +01:00
Shakker
1bd4b7ac4d fix: keep plugin uninstall on metadata path 2026-04-28 11:25:09 +01:00
Vincent Koc
7950a18025 fix(whatsapp): recover stale listener after auth conflict churn (#72621)
* fix(whatsapp): recover stale listener after auth conflict churn

* fix(whatsapp): block symlink auth cleanup escapes

* fix(whatsapp): refuse external auth cleanup
2026-04-28 03:24:57 -07:00
Vincent Koc
e2f3044b8f fix(memory-wiki): route bridge CLI through gateway
Route Memory Wiki bridge-mode status, doctor, and bridge import CLI paths through Gateway RPC when bridge artifact reads are active, while preserving local/offline fallbacks.

Harden Gateway CLI rendering and imported-source writes: validate RPC response shapes, bound response strings before rendering/JSON serialization, sanitize/escape terminal-controlled output, avoid redundant JSON forwarding, and replace imported source pages through a temp-file rename path with symlink and hardlink regressions.

Fixes #65722
Fixes #65976
Fixes #66082
Fixes #67979
Fixes #68371
Fixes #68828
Fixes #69019
Fixes #70181
Fixes #70242
Fixes #70842

Thanks @moorsecopers99, @vincentkoc, and @prasad-yashdeep.
2026-04-28 03:22:12 -07:00
Vincent Koc
f12dedb5c8 fix(tasks): keep media tool runs live 2026-04-28 03:21:00 -07:00
Peter Steinberger
1b13f53047 fix(ollama): reject garbled Kimi symbol output 2026-04-28 11:20:15 +01:00
Vincent Koc
77192572f6 ci: split macos codeql shard
Split the slow macOS CodeQL job into its own weekly/manual workflow and keep the daily CodeQL default on the fast JS/Actions security path.
2026-04-28 03:14:07 -07:00
Peter Steinberger
6cc6996a1c fix(slack): tune socket mode pong timeout 2026-04-28 11:13:03 +01:00
Peter Steinberger
c9ead1b928 test: annotate Docker test-state scenarios 2026-04-28 11:10:30 +01:00
Peter Steinberger
ade9aaae89 fix(cli): classify scope-limited status probes as reachable 2026-04-28 11:09:42 +01:00
Peter Steinberger
1fcf0a422f fix(agents): keep media generation tasks fresh 2026-04-28 10:59:42 +01:00
Peter Steinberger
9da76c4255 test: fix openclaw test state helper types 2026-04-28 10:59:42 +01:00
Gabriel Kripalani
17ef9ef895 feat(openrouter): add video generation provider (#72700)
Adds OpenRouter video generation via video_generate, with hardened async polling/download handling, docs, and regression coverage.

Validation:
- pnpm test src/plugins/plugin-lookup-table.test.ts src/secrets/target-registry.fast-path.test.ts src/gateway/server-startup-post-attach.test.ts extensions/openrouter/video-generation-provider.test.ts src/video-generation/live-test-helpers.test.ts src/media-generation/provider-capabilities.contract.test.ts src/agents/pi-embedded-helpers/failover-matches.test.ts src/plugins/manifest-metadata-scan.test.ts src/agents/openai-transport-stream.test.ts src/media-understanding/openai-compatible-audio.test.ts src/agents/schema-normalization-runtime-contract.test.ts src/agents/provider-request-config.test.ts src/plugin-sdk/provider-stream.test.ts src/agents/pi-embedded-runner/run/attempt.spawn-workspace.websocket.test.ts -- --reporter=verbose
- OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_TEST_QUIET=0 OPENCLAW_LIVE_VIDEO_GENERATION_MODELS=openrouter/google/veo-3.1-fast pnpm test:live src/video-generation/video-generation.live.test.ts -- --runInBand

Co-authored-by: notamicrodose <gabrielkripalani@me.com>
2026-04-28 10:57:31 +01:00
Peter Steinberger
5915489631 test: stabilize tts fast-lane guard 2026-04-28 10:54:23 +01:00
Peter Steinberger
6f8792f3f1 fix(cli): wire image describe prompt options 2026-04-28 10:53:53 +01:00
Peter Steinberger
0bc8b9a95a test: add shared OpenClaw test-state harness 2026-04-28 10:52:47 +01:00
Patrick Erichsen
ab3feca0d5 docs(skills): generalize pre-release testing skill wording (#73468) 2026-04-28 02:50:11 -07:00
Peter Steinberger
9207660c87 test: fix main ci shard routing 2026-04-28 10:48:27 +01:00
Vincent Koc
ae63f76bbd fix(cron): infer session agentId when omitted (#72326)
* fix(cron): infer session agentId when omitted

* fix(clownfish): address review for ghcrawl-165998-agentic-merge (1)
2026-04-28 02:47:20 -07:00
Peter Steinberger
c5cd7aabcf fix(auto-reply): bound pending tool result drain 2026-04-28 10:46:06 +01:00
Vincent Koc
210cccb0fe fix(tasks): index async media tasks by agent 2026-04-28 02:43:17 -07:00
Peter Steinberger
a6bb0265f0 test: speed up unit hotspot routing 2026-04-28 10:42:14 +01:00
Vincent Koc
17811480da docs(skills): add plugin pre-release test plan 2026-04-28 02:40:33 -07:00
Vincent Koc
cfbf4d1fa4 docs: note default sandbox image fail-fast behavior
For 47dc9f7fc0: docs/gateway/sandboxing.md now warns under "Build the default
image" that OpenClaw no longer silently retags plain debian:bookworm-slim as
openclaw-sandbox:bookworm-slim when the default image is missing. Sandbox runs
fail with a build instruction so the python3 tooling required by sandbox
write/edit helpers is preserved instead of being silently dropped.
2026-04-28 02:40:26 -07:00
Vincent Koc
058b57867e fix(qwen): allow explicit qwen3.6-plus on Coding Plan (#72664) 2026-04-28 02:38:47 -07:00
Peter Steinberger
b4ffef5c5f fix(plugins): prune inactive bundled runtime deps 2026-04-28 10:34:24 +01:00
Peter Steinberger
1346a31861 fix(plugins): keep manifestless bundles indexed 2026-04-28 10:34:01 +01:00
Peter Steinberger
f5922e6eb1 fix(agents): trim config write tool responses 2026-04-28 10:32:58 +01:00
Vincent Koc
5820a48fca ci: add plugin boundary codeql quality shard (#73447) 2026-04-28 02:30:33 -07:00
Peter Steinberger
1f1b98e33b fix(auto-reply): keep consumed reset triggers out of prompt 2026-04-28 10:24:04 +01:00
Vincent Koc
aa2f964bda fix(mattermost): keep inspector capture quiet 2026-04-28 02:19:57 -07:00
Vincent Koc
ad954dd1ca test(plugins): fix codex inspector capture regression 2026-04-28 02:19:56 -07:00
Vincent Koc
5f3b8b4100 fix(plugins): harden inspector runtime capture 2026-04-28 02:19:56 -07:00
Peter Steinberger
0f24a8d8e1 test: isolate gateway prewarm scheduling 2026-04-28 10:18:42 +01:00
Peter Steinberger
fac116cfa4 fix: resolve providerless image model refs 2026-04-28 10:18:07 +01:00
ZC
5741e40c14 fix(cron): clarify local timezone cron expressions (#73372)
* fix(cron): clarify local timezone cron expressions

* fix: clarify cron timezone guidance

---------

Co-authored-by: Altay <altay@uinaf.dev>
2026-04-28 12:16:27 +03:00
Peter Steinberger
9cdae734a7 test: stabilize gateway startup prewarm test 2026-04-28 10:14:03 +01:00
Vincent Koc
1912e309f7 fix(ui): confirm button-triggered new session resets (#73361) 2026-04-28 02:10:33 -07:00
Peter Steinberger
62997f7fce fix(deepseek): backfill v4 assistant reasoning replay 2026-04-28 10:07:39 +01:00
Peter Steinberger
0876ff481b test: speed up styled select test 2026-04-28 10:02:20 +01:00
Scott Hanselman
8f277e4b7f fix: allow safe Windows companion node commands (#71884)
Merged via squash.

Prepared head SHA: 24e2b79fe4
Co-authored-by: shanselman <2892+shanselman@users.noreply.github.com>
Co-authored-by: shanselman <2892+shanselman@users.noreply.github.com>
Reviewed-by: @shanselman
2026-04-28 02:01:20 -07:00
Edwin Rivera
bca30b62be fix: defer Claude live MCP cleanup (#73351)
Thanks @edwin-rivera-dev.
2026-04-28 09:59:58 +01:00
Peter Steinberger
249cb54373 fix: keep acp typing for tool-only replies 2026-04-28 09:58:18 +01:00
Vincent Koc
7fd9c152d1 fix(memory): keep pre-compaction flush prompt out of user transcript (#73380) 2026-04-28 01:58:14 -07:00
Vincent Koc
47dc9f7fc0 Fix default sandbox image fallback for python3-dependent mutations (#73362) 2026-04-28 01:57:44 -07:00
Peter Steinberger
6f3b5f8666 fix(agents): pause yielded subagent runs 2026-04-28 09:57:12 +01:00
Peter Steinberger
2790825ae5 test(auto-reply): assert bare reset acknowledgement 2026-04-28 09:56:41 +01:00
Peter Steinberger
11f0244cf4 fix(gateway): start channels before model prewarm 2026-04-28 09:56:16 +01:00
Vincent Koc
b6a21cde34 ci: schedule android codeql shard (#73430) 2026-04-28 01:54:57 -07:00
Vincent Koc
76cd97289b fix(cron): support Telegram thread IDs in cron add/edit
- Add `--thread-id` support to cron add/edit Telegram delivery.
- Reject non-positive thread IDs and guard cron edit lookup pagination against non-progress/max-page loops.
- Preserve existing delivery mode on thread-only cron edit patches.

Carries forward #51581, #60373, and #60890.

Co-authored-by: ChunHao Chen <crazycjh@gmail.com>
2026-04-28 01:50:44 -07:00
Vincent Koc
02908db62b fix(ui): clear webchat pending state only for completed active run (#73368) 2026-04-28 01:47:00 -07:00
Peter Steinberger
3ed3248d7b fix(gateway): preserve config SecretRef env for services 2026-04-28 09:44:51 +01:00
Peter Steinberger
4c61040c52 test: speed up small unit fast cases 2026-04-28 09:44:44 +01:00
Vincent Koc
fe7865aad6 docs: cover Anthropic beta header suppression and claude-cli fallback prelude
- docs/concepts/model-providers.md: add proxy-route shaping rule for the
  09ec5d2c4d fix that suppresses implicit Anthropic beta headers
  (`claude-code-20250219`, `interleaved-thinking-2025-05-14`, OAuth markers)
  on non-direct endpoints, parallel to the existing OpenAI
  `compat.supportsDeveloperRole` rule.
- docs/gateway/cli-backends.md: add a "Fallback prelude from claude-cli
  sessions" section for a96f1fa5ef so users know that non-CLI fallback
  candidates after a claude-cli failure are now seeded with a context prelude
  harvested from Claude Code's `~/.claude/projects/` JSONL (preferring the
  latest `/compact` summary, coalescing tool blocks, skipping same-provider
  `--resume` fallbacks).
2026-04-28 01:42:25 -07:00
Peter Steinberger
8a98c08c8a fix(mattermost): avoid system events for user posts 2026-04-28 09:41:04 +01:00
Peter Steinberger
28bf71d74b fix(auto-reply): preserve silent voice payloads 2026-04-28 09:41:04 +01:00
Peter Steinberger
a3bbcf2792 fix(docker): keep plugin runtime deps off bind mounts 2026-04-28 09:37:59 +01:00
Peter Steinberger
3ee5490c60 fix(auto-reply): avoid duplicate reset hook acknowledgements 2026-04-28 09:37:15 +01:00
Vincent Koc
e2bcec33b3 fix(security): avoid duplicate skill package import 2026-04-28 01:37:01 -07:00
Vincent Koc
7e028917c0 fix(android): remediate app CodeQL alerts 2026-04-28 01:37:01 -07:00
Vincent Koc
5ac6d7661c fix(ci): harden workflow checkouts 2026-04-28 01:37:00 -07:00
Peter Steinberger
f76c8322d3 test: route gateway audit through fast lane 2026-04-28 09:35:34 +01:00
Vincent Koc
474859aaaa test(agents): cover raw model cache trace stage 2026-04-28 01:32:34 -07:00
Peter Steinberger
99ceaaa76e test: fix attempt execution fixture lint 2026-04-28 09:32:02 +01:00
Peter Steinberger
a68ca1ae0b fix(auto-reply): acknowledge bare reset commands 2026-04-28 09:31:14 +01:00
Peter Steinberger
8178b62187 fix(android): include third-party sensitive handlers 2026-04-28 09:27:59 +01:00
Peter Steinberger
2276f660f3 refactor(android): split sensitive features by flavor 2026-04-28 09:27:39 +01:00
Peter Steinberger
8ff0ea50b0 ci: stabilize full release validation 2026-04-28 09:26:50 +01:00
Vincent Koc
bab403d0ee fix(plugins): avoid bundled install load path aliases 2026-04-28 01:26:21 -07:00
Peter Steinberger
169dba2042 fix(skills): require opt-in for coding-agent 2026-04-28 09:24:24 +01:00
Peter Steinberger
4f6dab852e ci: fix main test and boundary checks 2026-04-28 09:23:26 +01:00
Peter Steinberger
09ec5d2c4d fix(agents): suppress Anthropic beta headers for custom endpoints 2026-04-28 09:20:58 +01:00
Peter Steinberger
2a1e47ffcb fix(agents): restore raw model run type coverage 2026-04-28 09:20:58 +01:00
Peter Steinberger
732e5805e3 fix(ollama): preserve configured native thinking 2026-04-28 09:20:44 +01:00
Peter Steinberger
7092313b2f docs: advertise xhigh docs i18n thinking 2026-04-28 09:19:40 +01:00
3121 changed files with 213624 additions and 64183 deletions

View File

@@ -123,17 +123,22 @@ instantly and boots the CI environment in the background while you work:
blacksmith testbox warmup ci-check-testbox.yml
# → tbx_01jkz5b3t9...
Save this ID. You need it for every `run` command.
Save this ID in the current session. You need it for every `run` command.
Treat `blacksmith testbox list` as diagnostics, not a reusable work queue.
Listed boxes can be visible at the org/repo level while still being unusable or
stale for the current local agent lane.
For OpenClaw maintainer Testbox mode, pre-warm at the start of longer or wider
tasks:
blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90
pnpm testbox:claim --id <ID>
Use the build-artifact warmup when e2e/package/build proof benefits from seeded
`dist/`, `dist-runtime/`, and build-all caches:
blacksmith testbox warmup ci-build-artifacts-testbox.yml --ref main --idle-timeout 90
pnpm testbox:claim --id <ID>
Warmup dispatches a GitHub Actions workflow that provisions a VM with the
full CI environment: dependencies installed, services started, secrets
@@ -178,6 +183,26 @@ The `run` command automatically waits for the testbox to become ready if
it is still booting, so you can call `run` immediately after warmup without
needing to check status first.
In OpenClaw, prefer the guarded runner wrapper so stale/reused ids fail before
the Blacksmith CLI spends time syncing or emits a confusing missing-key error:
pnpm testbox:run --id <ID> -- "OPENCLAW_TESTBOX=1 pnpm check:changed"
The wrapper refuses to run when the local per-Testbox key is missing or when the
id was not claimed by this OpenClaw checkout with `pnpm testbox:claim --id
<ID>`. Treat that as the expected remediation, not as a GitHub account or
normal SSH-key problem. A local key alone is not enough; a ready box may still
carry stale rsync state from another lane.
If the agent crashes, the remote box relies on Blacksmith's idle timeout. The
local OpenClaw claim marker is not deleted automatically, so the wrapper treats
claims older than 12 hours as stale. Override only for intentional long-running
work with `OPENCLAW_TESTBOX_CLAIM_TTL_MINUTES=<minutes>`.
Before spending a broad gate on a manually assembled command, you can also run:
pnpm testbox:sanity -- --id <ID>
## Downloading files from a testbox
Use the `download` command to retrieve files or directories from a running
@@ -286,16 +311,17 @@ checks that need parity or remote state.
1. Decide whether the repo's local loop is the right default. For OpenClaw,
`OPENCLAW_TESTBOX=1` makes Testbox the maintainer default.
2. If Testbox is warranted, warm up early:
`blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90` → save the ID
`blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90` → save the ID,
then `pnpm testbox:claim --id <ID>`
3. Write code while the testbox boots in the background.
4. Run the remote command when needed:
`blacksmith testbox run --id <ID> "pnpm check:changed"`
`pnpm testbox:run --id <ID> -- "OPENCLAW_TESTBOX=1 pnpm check:changed"`
5. If tests fail, fix code and re-run against the same warm box.
6. If you changed dependency manifests (package.json, etc.), prepend
the install command: `blacksmith testbox run --id <ID> "npm install && npm test"`
7. If a narrow PR reports a full sync or the box was reused/expired, sanity
check the remote copy before a slow gate:
`blacksmith testbox run --id <ID> "pnpm testbox:sanity"`.
`pnpm testbox:run --id <ID> -- "pnpm testbox:sanity"`.
If it reports missing root files or mass tracked deletions, stop the box and
warm a fresh one. Use `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1` only for an
intentional large deletion PR.

View File

@@ -0,0 +1,339 @@
---
name: clawsweeper
description: "Use for all ClawSweeper work: OpenClaw issue/PR sweep reports, commit-review reports, repair jobs, cloud fix PRs, @clawsweeper maintainer mention commands, trusted ClawSweeper-reviewed autofix/automerge, GitHub Actions monitoring, permissions, gates, and manual backfills."
---
# ClawSweeper
ClawSweeper lives at `~/Projects/clawsweeper`. It is the one OpenClaw
maintenance bot for sweeping, commit review, repair jobs, and guarded fix PRs.
Use this skill whenever Peter asks about reports, findings, dispatch health,
repair/cloud PR creation, comment commands, automerge, permissions, or gates.
## Start
```bash
cd ~/Projects/clawsweeper
git status --short --branch
git pull --ff-only
pnpm run build:all
```
Do not overwrite unrelated edits. If the tree is dirty, inspect first and keep
read-only report work read-only unless Peter asked to commit.
## One Bot, One App
Use the ClawSweeper repo and the `clawsweeper` GitHub App. Use only
`CLAWSWEEPER_*` configuration for this automation. Do not use legacy apps,
variables, labels, or skills.
Required app setup:
- `CLAWSWEEPER_APP_CLIENT_ID`: public app client ID for `clawsweeper`.
- `CLAWSWEEPER_APP_PRIVATE_KEY`: private key used only inside
`actions/create-github-app-token` steps.
- Target app permissions: read target scan context; write issues and pull
requests; contents write for report commits, repair branches, and workflow
inputs; Actions write on `openclaw/clawsweeper` for comment-router
re-review dispatch, workflow dispatch, run cancellation, and self-heal;
optional Checks write for commit Check Runs.
Token boundary:
- Codex workers do not get mutation credentials.
- Review workers run with stripped secret/token env.
- Deterministic scripts own comments, labels, branch pushes, PR creation,
closes, and merges through short-lived GitHub App tokens.
- Merge and write gates default closed.
## Commit Reports
Canonical commit reports:
```text
records/<repo-slug>/commits/<40-char-sha>.md
```
Use the lister:
```bash
pnpm commit-reports -- --since 6h
pnpm commit-reports -- --since "24 hours ago" --findings
pnpm commit-reports -- --since 7d --non-clean
pnpm commit-reports -- --repo openclaw/openclaw --author steipete --since 7d
pnpm commit-reports -- --since 24h --json
```
Results: `nothing_found`, `findings`, `inconclusive`, `failed`,
`skipped_non_code`. One report per SHA; reruns overwrite the SHA-named report.
Manual rerun/backfill:
```bash
gh workflow run commit-review.yml --repo openclaw/clawsweeper \
-f target_repo=openclaw/openclaw \
-f commit_sha=<end-sha> \
-f before_sha=<start-or-parent-sha> \
-f create_checks=false \
-f enabled=true
```
Use `create_checks=true` only when Peter explicitly wants target commit Check
Runs. Add `-f additional_prompt="..."` for focused one-off review instructions.
## Sweep Reports
Issue/PR reports live at:
```text
records/<repo-slug>/items/<number>.md
records/<repo-slug>/closed/<number>.md
```
Lead with counts, concrete findings, and report links. Do not post unsolicited
GitHub comments from report-reading work. Public surfaces are markdown reports,
durable ClawSweeper review comments, and optional checks.
PR reports include Codex `/review`-style `reviewFindings` with priority,
confidence, repository-relative file, and line range. Public PR comments show a
short `Review findings:` list when findings exist; full review comments,
evidence links, likely owners, and runtime details stay inside the collapsed
`Review details` block.
Useful commands:
```bash
pnpm run status
pnpm run audit
pnpm run reconcile
pnpm run apply-decisions -- --dry-run
```
## Create One Repair Job
Create a job from issue/PR refs and a maintainer prompt:
```bash
pnpm run repair:create-job -- \
--repo openclaw/openclaw \
--refs 123,456 \
--prompt-file /tmp/clawsweeper-prompt.md
```
Create from an existing ClawSweeper report:
```bash
pnpm run repair:create-job -- \
--from-report ../clawsweeper/records/openclaw-openclaw/items/123.md
```
The job creator checks for an existing open PR, body match, or remote
`clawsweeper/<cluster-id>` branch before writing another job. Use `--dry-run`
to inspect. Use `--force` only after deciding the duplicate guard is stale.
Validate, commit, then dispatch:
```bash
pnpm run repair:validate-job -- jobs/openclaw/inbox/clawsweeper-openclaw-openclaw-123.md
pnpm run repair:dispatch -- jobs/openclaw/inbox/clawsweeper-openclaw-openclaw-123.md \
--mode autonomous \
--runner blacksmith-4vcpu-ubuntu-2404 \
--execution-runner blacksmith-16vcpu-ubuntu-2404 \
--model gpt-5.5
```
Do not dispatch a just-created job before the job file is committed and pushed;
the workflow reads the job path from GitHub.
## Replacement PRs
For a useful but uneditable/stale/unsafe source PR, make the maintainer prompt
explicit:
```md
Treat #123 as useful source work. If the source branch cannot be safely updated
because it is uneditable, stale, draft-only, unmergeable, or unsafe, create a
narrow ClawSweeper replacement PR instead of waiting. Preserve the source PR
author as co-author, credit the source PR in the replacement PR body, and close
only that source PR after the replacement PR is opened.
```
The worker should emit `repair_strategy=replace_uneditable_branch` and list the
source PR URL in `source_prs`. The deterministic executor opens or updates
`clawsweeper/<cluster-id>`, adds non-bot source authors as `Co-authored-by`
trailers, and closes superseded source PRs only after replacement exists.
## Gates
Open execution windows intentionally and close them after the run:
```bash
gh variable set CLAWSWEEPER_ALLOW_EXECUTE --repo openclaw/clawsweeper --body 1
gh variable set CLAWSWEEPER_ALLOW_FIX_PR --repo openclaw/clawsweeper --body 1
gh variable set CLAWSWEEPER_ALLOW_MERGE --repo openclaw/clawsweeper --body 1
gh variable set CLAWSWEEPER_ALLOW_AUTOMERGE --repo openclaw/clawsweeper --body 1
```
Reset gates only when Peter asks; the active maintainer window may intentionally
leave them at `1`.
Important gates:
- `CLAWSWEEPER_ALLOW_EXECUTE`: allows deterministic write lanes.
- `CLAWSWEEPER_ALLOW_FIX_PR`: allows branch repair/replacement PRs.
- `CLAWSWEEPER_ALLOW_MERGE`: allows merge-capable applicators.
- `CLAWSWEEPER_ALLOW_AUTOMERGE`: allows comment-router automerge.
- `CLAWSWEEPER_COMMENT_ROUTER_EXECUTE`: lets scheduled comment routing
post replies and dispatch repair.
## Maintainer Mentions
Prefer `@clawsweeper` comments for all maintainer-facing control. Slash
commands still parse as compatibility aliases, but examples and live guidance
should use mentions.
```text
@clawsweeper status
@clawsweeper re-review
@clawsweeper review
@clawsweeper fix ci
@clawsweeper address review
@clawsweeper rebase
@clawsweeper autofix
@clawsweeper automerge
@clawsweeper approve
@clawsweeper explain
@clawsweeper stop
@clawsweeper <question or safe action request>
@clawsweeper[bot] re-review
@openclaw-clawsweeper fix ci
@openclaw-clawsweeper[bot] fix ci
```
Accepted aliases: `review`, `re-review`, `rereview`, `review again`,
`rerun review`, and `run review`. `review` and `re-review` dispatch a fresh
ClawSweeper issue/PR review without starting repair. `fix ci`,
`address review`, and `rebase` dispatch the
repair worker only for ClawSweeper PRs or PRs opted into
`clawsweeper:autofix` or `clawsweeper:automerge`. `autofix` runs the bounded
review/fix loop without merging. `automerge` runs the bounded review/fix/merge
loop, but draft PRs stay fix-only until GitHub marks them ready for review.
Freeform maintainer mentions such as `@clawsweeper why did automerge stop?`
or `@clawsweeper: can you explain this failure?` dispatch a read-only assist
review with the mention text as one-off instructions. The answer lands in the
next public ClawSweeper review comment. Action-looking prose does not directly
mutate GitHub; it must map to existing structured recommendations and pass the
normal deterministic gates.
Default accepted maintainers: `OWNER`, `MEMBER`, `COLLABORATOR`; fallback
repository permission accepts `admin`, `maintain`, or `write`. Contributor
comments are ignored without a reply.
Run router manually:
```bash
pnpm run repair:comment-router -- --repo openclaw/openclaw --lookback-minutes 180
pnpm run repair:comment-router -- --repo openclaw/openclaw --execute --wait-for-capacity
```
Scheduled routing stays dry unless
`CLAWSWEEPER_COMMENT_ROUTER_EXECUTE=1`.
## Trusted Autofix And Automerge
`@clawsweeper autofix` opts an existing PR into the bounded review/fix loop.
`@clawsweeper automerge` opts an existing PR into the bounded review/fix/merge
loop. The router:
- verifies maintainer authorization;
- labels the PR `clawsweeper:autofix` or `clawsweeper:automerge`;
- dispatches ClawSweeper review for the current head SHA;
- creates or reuses a durable adopted job;
- repairs at most the configured caps;
- never merges autofix PRs or draft PRs;
- merges automerge PRs only when ClawSweeper passed the exact current head,
checks are green, GitHub says mergeable, no human-review label is present,
the PR is not draft, required user-facing OpenClaw changelog entries are
present, and both merge gates are open.
If ClawSweeper passes while merge gates are closed, it labels
`clawsweeper:merge-ready` and comments instead of merging. `@clawsweeper stop`
adds `clawsweeper:human-review`.
When Peter asks Codex to create a PR and enable ClawSweeper automerge, do not
leave his local OpenClaw checkout on the PR branch. After the PR is created,
pushed, and the `@clawsweeper automerge` request is posted or otherwise
confirmed, return the local checkout to `main` and fast-forward it when the
working tree is clean:
```bash
git switch main
git pull --ff-only
```
If unrelated local edits or an in-progress rebase prevent switching, report the
blocker instead of stashing, deleting, or overwriting work.
Repair caps:
```bash
CLAWSWEEPER_MAX_REPAIRS_PER_PR=10
CLAWSWEEPER_MAX_REPAIRS_PER_HEAD=1
```
## Security Boundary
Do not stage unapproved security-sensitive work for ClawSweeper Repair. Route
vulnerability reports, CVE/GHSA/advisory work, leaked secrets/tokens/keys,
plaintext secret storage, SSRF, XSS, CSRF, RCE, auth bypass, privilege
escalation, and sensitive data exposure to central OpenClaw security handling.
For PRs explicitly opted into `clawsweeper:autofix` or
`clawsweeper:automerge`, security-sensitive review findings may dispatch
bounded repair, but merge remains blocked until a later exact-head review is
clean and the normal merge gates pass. Trust deterministic ClawSweeper security
markers, labels, and job frontmatter; do not infer security handling from vague
prose.
## Monitoring
Receiver workflows:
```bash
gh run list --repo openclaw/clawsweeper --workflow "ClawSweeper Commit Review" \
--limit 12 --json databaseId,displayTitle,event,status,conclusion,createdAt,updatedAt,url
gh run list --repo openclaw/clawsweeper --workflow "repair cluster worker" \
--limit 12 --json databaseId,displayTitle,event,status,conclusion,createdAt,updatedAt,url
gh run list --repo openclaw/clawsweeper --workflow "repair comment router" \
--limit 12 --json databaseId,displayTitle,event,status,conclusion,createdAt,updatedAt,url
```
Target dispatcher:
```bash
gh run list --repo openclaw/openclaw --workflow "ClawSweeper Dispatch" \
--event push --limit 8 --json databaseId,displayTitle,event,status,conclusion,headSha,url
```
Target commit check:
```bash
gh api "repos/openclaw/openclaw/commits/<sha>/check-runs?per_page=100" \
--jq '.check_runs[] | select(.name=="ClawSweeper Commit Review") | [.status,.conclusion,.details_url] | @tsv'
```
## Reading Output
For findings or failures, summarize:
- target repo, item/PR/commit, run, report path
- result, confidence, severity, and exact blocker
- affected files or cluster refs
- validation commands and whether they passed
- whether mutation gates were open or closed
- next deterministic action
Keep the broom small: one cluster, one branch, one PR, narrow proof, clear
owner-visible evidence.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "ClawSweeper"
short_description: "Inspect ClawSweeper commit review reports and Actions runs."
default_prompt: "Review recent ClawSweeper commit reports and summarize findings."

View File

@@ -41,6 +41,28 @@ gitcrawl cluster-detail openclaw/openclaw --id <cluster-id> --member-limit 20 --
- `invalid`
- `dirty` for PRs only
## Select small high-confidence triage candidates
When asked for `X` issues or PRs to triage, `X` means qualified candidates, not sampled threads.
Only list candidates that pass all gates:
- small owner/surface, with a likely narrow fix and focused regression test
- symptom is reproducible or provable with logs, failing test, live command, dependency contract, or current-main behavior
- root cause is traceable to code with file/line and the proposed fix touches that path
- no strong smell that a broader refactor, ownership rethink, migration, or product decision is the better fix
- dependency-backed behavior checked against upstream docs/source/types; live or web proof used when local proof is insufficient
Loop:
1. Use `gitcrawl` / `gh` to gather candidate clusters.
2. Read issue/PR body, comments, current code, adjacent tests, and dependency contracts.
3. Try focused repro or proof.
4. Reject unclear, stale, speculative, broad-refactor, or owner-ambiguous items.
5. Continue until `X` qualified candidates or the bounded search is exhausted.
Output only qualifying candidates, with: ref, surface, proof, cause, fix sketch, why small, expected test/gate. If none qualify, say so; do not pad.
## Enforce the bug-fix evidence bar
- Never merge a bug-fix PR based only on issue text, PR text, or AI rationale.

View File

@@ -0,0 +1,234 @@
---
name: openclaw-pre-release-plugin-testing
description: Plan and run pre-release OpenClaw plugin validation across bundled plugins, package artifacts, lifecycle commands, doctor/fix, config round-trip, gateway startup, SDK compatibility, Docker E2E, Package Acceptance, and Testbox proof.
---
# OpenClaw Pre-Release Plugin Testing
Use this skill when the user asks for plugin release confidence, plugin lifecycle
sweeps, package-artifact plugin proof, or "what else should we test before
release?" It complements `openclaw-testing`; use that skill too when choosing
the cheapest safe runner or debugging a failing lane.
## Goal
Prove the plugin system as a product surface, not just as source tests:
- bundled plugin lifecycle: install, inspect, enable, disable, uninstall
- package artifact behavior from a clean `HOME`
- doctor/fix/config validation and idempotence
- config discovery and config round-trip
- status/log visibility and diagnostics
- gateway startup/bootstrap with plugin metadata snapshots
- public SDK compatibility for real external plugins
- live-ish provider/channel probes only when safe credentials exist
## First Checks
From the OpenClaw repo root:
```bash
pnpm docs:list
git status --short --branch
readlink node_modules
pnpm changed:lanes --json
```
In Codex worktrees under `.codex/worktrees`, `node_modules` must be a symlink to
the main OpenClaw checkout. Do not run `pnpm install` there. For broad or
package-heavy proof, use Blacksmith Testbox or GitHub Actions.
## Runner Choice
Prefer this order:
1. **GitHub Package Acceptance** for installable-package product proof.
2. **`ci-build-artifacts-testbox.yml` Testbox** when Docker/package lanes need
seeded `dist`, `dist-runtime`, and package caches.
3. **`ci-check-testbox.yml` Testbox** for source checks, targeted Vitest,
package-boundary checks, or focused Docker lanes.
4. **Local targeted commands only** for small format/static/unit probes.
Avoid long package Docker runs from a stale sparse worktree. If Testbox sync
reports hundreds of changed files or starts deleting package inputs, stop and
warm a fresh box from current `main`, or switch to Package Acceptance.
## Existing Baseline
Run or verify these before inventing new coverage:
```bash
OPENCLAW_TESTBOX=1 pnpm check:changed
pnpm run test:extensions:package-boundary:canary
pnpm run test:extensions:package-boundary:compile
pnpm test:docker:plugins
OPENCLAW_PLUGINS_E2E_CLAWHUB=0 pnpm test:docker:plugins
pnpm test:docker:plugin-update
pnpm test:docker:bundled-channel-deps:fast
```
For full bundled install/uninstall proof, shard the packaged sweep:
```bash
OPENCLAW_BUNDLED_PLUGIN_SWEEP_TOTAL=8 \
OPENCLAW_BUNDLED_PLUGIN_SWEEP_INDEX=<0-7> \
pnpm test:docker:bundled-plugin-install-uninstall
```
Expected current packaged scope: 116 public bundled plugins over shards `0-7`.
Private QA plugins are source-mode only unless a package explicitly includes
them.
## Confidence Matrix
Use this matrix for pre-release signoff. Record pass/fail, run URL/Testbox ID,
package SHA/version, and skipped-live reason.
| Surface | Proof | Preferred runner |
| --- | --- | --- |
| Package artifact | Package Acceptance `suite_profile=package` or custom lanes | GitHub Actions |
| Bundled lifecycle | 8-shard `test:docker:bundled-plugin-install-uninstall` | Testbox or release Docker |
| External plugins | `test:docker:plugins` and `plugins-offline` | Testbox/package acceptance |
| Update no-op | `test:docker:plugin-update` | Testbox/package acceptance |
| Channel runtime deps | `test:docker:bundled-channel-deps:fast` plus key channels | Testbox/package acceptance |
| Doctor/fix | seeded bad configs + `doctor --fix --non-interactive` | new Docker/Testbox harness |
| Config round-trip | `config set/get`, inspect, doctor, reload, diff hash | new Docker/Testbox harness |
| Gateway bootstrap | clean `HOME`, plugin groups enabled/disabled, status JSON | new Docker/Testbox harness |
| SDK compatibility | directory, tgz, and `file:` external plugins using SDK subpaths | `test:docker:plugins` plus new smoke |
| Live-ish | redacted provider/channel probes only for present env | Testbox live lanes |
## Package Acceptance Plan
Use this when validating a release branch, beta, or candidate package:
```bash
gh workflow run package-acceptance.yml \
--repo openclaw/openclaw \
--ref main \
-f workflow_ref=main \
-f source=ref \
-f package_ref=<branch-or-sha> \
-f suite_profile=custom \
-f docker_lanes='plugins-offline plugin-update bundled-channel-deps-compat doctor-switch update-channel-switch config-reload mcp-channels npm-onboard-channel-agent' \
-f telegram_mode=mock-openai
```
Use `source=npm -f package_spec=openclaw@beta` for published beta proof. Keep
`workflow_ref` as trusted current harness code unless the release process says
otherwise.
## New Testbox Harness Plan
If more certainty is needed, add or run a `plugin-lifecycle-matrix` Docker lane
that uses one package tarball and sharded plugin lists. Per plugin:
1. Start with a clean `HOME`.
2. Capture `plugins list --json`.
3. `plugins install <id>`.
4. `plugins inspect <id> --json`.
5. `plugins disable <id>`, then assert disabled visibility.
6. `plugins enable <id>`, except config-required plugins without config.
7. `plugins registry --refresh`.
8. `doctor --non-interactive`.
9. `plugins uninstall <id> --force`.
10. Assert no config entry, allow/deny residue, install record, managed dir, or
bundled `dist/extensions/...` load path remains.
11. Assert diagnostics contain no `level: "error"` and output redacts
secret-looking values.
Keep `memory-lancedb` special: it is config-required. First assert install does
not enable it without embedding config, then run a second configured case.
## Doctor/Fix Matrix
Seed bad states and require `doctor --fix --non-interactive` to repair them,
then run doctor again and require idempotence:
- stale `plugins.allow`
- stale `plugins.entries`
- stale channel config for missing channel plugin
- invalid `plugins.entries.<id>.config`
- packaged bundled path in `plugins.load.paths`
- legacy `plugins.installs`
- disabled channel/plugin config that must not stage runtime deps
- root-owned global package tree that must remain unmodified
## Gateway Bootstrap Matrix
Start packaged OpenClaw in Docker with clean state:
- provider plugins enabled, no credentials: ready with warnings, no crash
- channel plugins configured disabled: no runtime deps staged
- startup-activation plugins enabled: ready and reflected in status
- invalid single plugin config: bad plugin skipped/quarantined, others remain
Assert:
- gateway reaches ready
- `openclaw status --json` includes plugin diagnostics
- `openclaw plugins inspect --all --json` is parseable
- package tree is not mutated
- logs contain no raw tokens
## Config Round-Trip Representatives
Use representative plugin families instead of every plugin for deep config
round-trip:
- providers: `openai`, `anthropic`, `mistral`, `openrouter`
- channels: `telegram`, `discord`, `slack`, `whatsapp`
- memory: `memory-lancedb`
- feature/runtime: `browser`, `acpx`, `tokenjuice`
For each representative:
1. Write config through CLI when possible.
2. Read it back through `config get` or JSON.
3. Run `plugins inspect`.
4. Run `doctor --non-interactive`.
5. Trigger gateway config reload if applicable.
6. Compare config hash before/after no-op commands.
## External SDK Smoke
In a package Docker lane, create tiny external plugins and install them from:
- local directory
- `.tgz`
- `file:` npm spec
Cover CJS and ESM shapes, plus at least one plugin importing focused
`openclaw/plugin-sdk/*` subpaths. Assert `plugins inspect` sees its tool,
gateway method, CLI command, or service.
## Live-Ish Probe Rules
Before live-ish work, source allowed env in Testbox and generate a redacted
availability matrix: present/missing only, never values.
Only run probes for credentials that exist. Prefer auth/catalog/status probes
over sending user-visible messages. If a probe might contact an external user,
channel, or workspace, stop and ask the user.
## Reporting
Report in this shape:
```text
package/ref:
tbx ids / run urls:
matrix:
bundled lifecycle:
package acceptance:
doctor/fix:
gateway bootstrap:
config round-trip:
sdk external:
live-ish:
failures:
skips:
next highest-value gap:
```
Say clearly when a failure is Testbox sync/env damage rather than product
behavior, and prove that with a clean rerun or current-main comparison.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "OpenClaw Plugin Pre-Release Testing"
short_description: "Plan plugin release validation"
default_prompt: "Use $openclaw-pre-release-plugin-testing to plan or run pre-release OpenClaw plugin validation across package, lifecycle, doctor, gateway, SDK, and live-ish proof."

View File

@@ -1,12 +1,13 @@
---
name: openclaw-test-performance
description: Benchmark, diagnose, and optimize OpenClaw test runtime, import hotspots, CPU/RSS, and slow coverage paths.
description: Benchmark, diagnose, and optimize OpenClaw test and plugin-suite runtime, import hotspots, CPU/RSS, heap growth, and slow coverage paths.
---
# OpenClaw Test Performance
Use evidence first. The goal is real `pnpm test` speed/RSS improvement with
coverage intact, not runner tuning by guesswork.
Use evidence first. The goal is real `pnpm test`, plugin-suite, and
plugin-inspector speed/RSS improvement with coverage intact, not runner tuning by
guesswork.
## Workflow
@@ -21,6 +22,9 @@ coverage intact, not runner tuning by guesswork.
2. Establish a baseline before changing code:
- Prefer `pnpm test:perf:groups --full-suite --allow-failures --output <file>`
for full-suite ranking.
- For bundled plugin breadth, run the smallest relevant `pnpm
test:extensions:batch <plugin[,plugin...]>` or plugin-inspector command
before jumping to the full extension sweep.
- For a scoped hotspot use:
`/usr/bin/time -l pnpm test <file-or-files> --maxWorkers=1 --reporter=verbose`
- For import-heavy suspicion add:
@@ -33,6 +37,8 @@ coverage intact, not runner tuning by guesswork.
passed, capture that as harness/noise and verify the suspect file directly.
4. Pick the next attack by return and risk:
- High return: one file/test dominates seconds or RSS and has a clear root.
- High leverage: one plugin or SDK barrel causes every plugin-inspector or
extension-batch run to load broad runtime.
- Lower risk: static descriptors, target parsing, routing, auth bypass,
setup hints, registry fixtures, or test server lifecycle.
- Higher risk: real memory/runtime behavior, live providers, protocol
@@ -44,6 +50,8 @@ coverage intact, not runner tuning by guesswork.
and pure helpers over broad mocks.
- Reuse suite-level servers/clients when a fresh handshake is irrelevant.
- Keep schedulers/background loops off unless the test proves scheduling.
- In plugin paths, move static metadata into manifest/lightweight artifacts
and keep runtime plugin loads behind explicit execution boundaries.
6. Preserve coverage shape:
- Do not delete a slow integration proof unless the exact production
composition is extracted into a named helper and tested.
@@ -57,6 +65,90 @@ coverage intact, not runner tuning by guesswork.
9. Commit with `scripts/committer "<message>" <paths...>` and push when the
user asked for commits/pushes. Stage only files touched for this attack.
## Plugin-Suite Workflow
Use this section when perf work involves bundled plugins, plugin-inspector, SDK
barrels, package-boundary tests, or extension suites.
1. Map the suite shape first:
- source tests: `pnpm test extensions/<id>` or `pnpm test:extensions:batch <id>`
- package boundaries: `pnpm run test:extensions:package-boundary:canary` and
`pnpm run test:extensions:package-boundary:compile`
- all bundled source tests: `pnpm test:extensions`
- plugin import memory: `pnpm test:extensions:memory -- --json .artifacts/test-perf/extensions-memory.json`
- plugin-inspector/report work: keep report primitives in `plugin-inspector`;
keep wrappers thin and collect peak RSS when the command supports it.
2. Start narrow, then widen:
- one plugin changed: run that plugin's tests and plugin-inspector slice.
- SDK/public barrel changed: add representative provider, channel, memory,
and feature plugins.
- loader/runtime mirror changed: add package-boundary checks and build/package
proof as needed.
- unknown shared plugin behavior: run `test:extensions:batch` groups before
`pnpm test:extensions`.
3. Treat plugin-inspector failures as product signals:
- JSON must parse.
- warnings/errors must be classified, not hidden.
- runtime capture should be quiet and config-tolerant.
- command output should include wall time, exit code, and peak RSS when
available.
4. For broad or package-heavy plugin proof, use Blacksmith Testbox by default on
maintainer machines. Warm once and reuse the same box:
- `blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90`
- `blacksmith testbox run --id <ID> "OPENCLAW_TESTBOX=1 pnpm test:extensions:batch <ids>"`
- stop the box when done.
5. If plugin performance is package-artifact sensitive, switch to
`openclaw-pre-release-plugin-testing` and Package Acceptance rather than
trusting source-only timing.
## Metric Collection
Collect at least one stable metric before and after. Prefer the same machine and
same command. For Testbox comparisons, use the same `tbx_...` id when possible.
| Metric | Use for | Preferred source |
| --------------- | ---------------------------------- | --------------------------------------------------------------------------- |
| wall time | user-visible suite cost | `/usr/bin/time -l`, test wrapper duration, Testbox run time |
| Vitest duration | test body/import cost | Vitest output per file/shard |
| import duration | broad barrel/runtime loads | `OPENCLAW_VITEST_IMPORT_DURATIONS=1` |
| max RSS | memory pressure and OOM risk | `/usr/bin/time -l`, `pnpm test:extensions:memory`, wrapper memory summaries |
| CPU/user/sys | CPU-bound vs wait-bound split | `/usr/bin/time -l` locally, Testbox job timing when local CPU is noisy |
| heap snapshots | real leak vs retained module graph | `openclaw-test-heap-leaks` workflow |
Local scoped command with CPU/RSS:
```bash
timeout 240 /usr/bin/time -l pnpm test <file> --maxWorkers=1 --reporter=verbose
```
Plugin import memory profile:
```bash
pnpm build
pnpm test:extensions:memory -- --top 20 --json .artifacts/test-perf/extensions-memory.json
```
Targeted plugin import memory:
```bash
pnpm test:extensions:memory -- --extension discord --extension telegram --skip-combined
```
Heap/RSS escalation:
```bash
OPENCLAW_TEST_MEMORY_TRACE=1 \
OPENCLAW_TEST_HEAPSNAPSHOT_INTERVAL_MS=60000 \
OPENCLAW_TEST_HEAPSNAPSHOT_DIR=.tmp/heapsnap \
OPENCLAW_TEST_WORKERS=2 \
OPENCLAW_TEST_MAX_OLD_SPACE_SIZE_MB=6144 \
pnpm test
```
Use `openclaw-test-heap-leaks` when RSS keeps growing across intervals, workers
OOM, or the suspect command has app-object retention. Do not call RSS growth a
leak until snapshots or retainers support it.
## Common Root Causes
- Full bundled channel/plugin runtime loaded for static data.
@@ -64,6 +156,12 @@ coverage intact, not runner tuning by guesswork.
parser would suffice.
- Broad `api.ts`, `runtime-api.ts`, `test-api.ts`, or plugin-sdk barrels pulled
into hot tests.
- SDK root aliases or package barrels pulling focused subpaths back into a broad
plugin graph.
- Plugin-inspector loading runtime code just to render metadata, reports, or CI
policy scores.
- Bundled plugin capture reusing real config/home state instead of synthetic,
redacted, isolated state.
- Partial-real mocks using `importActual()` around broad modules.
- `vi.resetModules()` plus fresh imports in per-test loops.
- Test plugin registry seeded in `beforeAll` while runtime state resets in
@@ -72,6 +170,10 @@ coverage intact, not runner tuning by guesswork.
- Runtime/default model/auth selection paid by idle snapshots or fixtures.
- Plugin-owned media/action discovery triggered before checking whether args
contain plugin-owned fields.
- Timings missing from `test/fixtures/test-timings.unit.json`, causing hotspot
files to stay in shared workers.
- Parallel Vitest runs sharing `node_modules/.experimental-vitest-cache` without
distinct `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH` values.
## Benchmark Commands
@@ -97,6 +199,25 @@ pnpm test:perf:groups --full-suite --allow-failures \
--output .artifacts/test-perf/<name>.json
```
Extension batch:
```bash
pnpm test:extensions:batch <plugin[,plugin...]> -- --reporter=verbose
```
All extension tests:
```bash
pnpm test:extensions
```
Package-boundary plugin checks:
```bash
pnpm run test:extensions:package-boundary:canary
pnpm run test:extensions:package-boundary:compile
```
Reuse an existing Vitest JSON report:
```bash
@@ -107,19 +228,26 @@ pnpm test:perf:groups --report <vitest-json> \
## Verification
- Always run the targeted test surface that proves the change.
- Run `pnpm check` before commit unless the change is docs-only and the hook
handles it.
- For source changes, run `pnpm check:changed` before push; in maintainer
Testbox mode run it in the warmed Testbox.
- For test-only changes, run `pnpm test:changed` or the exact edited tests.
- Run `pnpm build` when touching lazy-loading, bundled artifacts, package
boundaries, dynamic imports, build output, or public surfaces.
- For plugin SDK/barrel/runtime changes, add `pnpm plugin-sdk:api:check` or
`pnpm plugin-sdk:api:gen` when the API surface may drift.
- For plugin-suite perf fixes, verify at least one representative plugin batch
plus the changed gate; use Package Acceptance if the bug only exists in a
packed artifact.
- If deps are missing/stale, run `pnpm install` and retry the exact failed
command once.
- Use the report format:
```markdown
| Metric | Before | After | Gain |
| -------------- | -----: | ----: | ------------: |
| File wall time | `Xs` | `Ys` | `-Zs` (`P%`) |
| Max RSS | `XMB` | `YMB` | `-ZMB` (`P%`) |
| Metric | Before | After | Gain |
| -------------- | -----: | -----: | ------------: |
| File wall time | `Xs` | `Ys` | `-Zs` (`P%`) |
| Max RSS | `XMB` | `YMB` | `-ZMB` (`P%`) |
| CPU user/sys | `X/Ys` | `A/Bs` | explain |
```
## Handoff
@@ -127,8 +255,12 @@ pnpm test:perf:groups --report <vitest-json> \
Keep the final concise:
- Root cause.
- Suite/plugin scope.
- Files changed.
- Before/after numbers.
- Before/after wall, Vitest/import, CPU, and RSS numbers where available.
- Leak classification if memory was involved: real leak, retained module graph,
or inconclusive.
- Coverage retained.
- Verification commands.
- Testbox ID or workflow URL for remote proof.
- Commit hash and push status.

View File

@@ -1,6 +1,6 @@
interface:
display_name: "OpenClaw Test Performance"
short_description: "Benchmark and fix slow OpenClaw tests"
default_prompt: "Use $openclaw-test-performance to reassess the OpenClaw test benchmark, identify the next real hotspot, fix it without losing coverage, update the report, and commit scoped changes."
short_description: "Benchmark tests, plugin suites, CPU, RSS, and heap growth"
default_prompt: "Use $openclaw-test-performance to reassess OpenClaw test and plugin-suite performance, collect wall/import/CPU/RSS metrics, investigate memory growth when needed, fix the next real hotspot without losing coverage, update the report, and commit scoped changes."
policy:
allow_implicit_invocation: false

View File

@@ -36,6 +36,14 @@ Prove the touched surface first. Do not reflexively run the whole suite.
- Prefer GitHub Actions for release/Docker proof when the workflow already has the prepared image and secrets.
- Use `scripts/committer "<msg>" <paths...>` when committing; stage only your files.
- If deps are missing, run `pnpm install`, retry once, then report the first actionable error.
- For Blacksmith Testbox proof, reuse only an id warmed and claimed in this
operator session. `blacksmith testbox list` is diagnostics only; a listed id
can have a local key and still carry stale rsync state from another lane.
After warmup, run `pnpm testbox:claim --id <id>`, then prefer
`pnpm testbox:run --id <id> -- "<command>"` for OpenClaw gates so stale
org-visible ids fail fast before syncing. Claims older than 12 hours are
stale unless `OPENCLAW_TESTBOX_CLAIM_TTL_MINUTES` is explicitly set for long
work.
## Local Test Shortcuts
@@ -111,7 +119,10 @@ rerun after a focused patch.
the manual "everything before release" umbrella. It resolves a target ref, then
dispatches:
- manual `CI` for the full normal CI graph
- manual `CI` for the full normal CI graph, with Android enabled via
`include_android=true`
- `Plugin Prerelease` for release-only plugin static checks, extension shards,
the release-only `agentic-plugins` shard, and plugin product Docker lanes
- `OpenClaw Release Checks` for install smoke, cross-OS release checks, live and
E2E checks, Docker release-path suites, OpenWebUI, QA Lab, fast Matrix, and
Telegram release lanes
@@ -138,13 +149,19 @@ Use `release_profile=minimum|stable|full` to control live/provider breadth:
`minimum` keeps the fastest OpenAI/core release-critical set, `stable` adds the
stable provider/backend set, and `full` adds the broad advisory provider/media
matrix. Do not make `full` faster by silently dropping suites; optimize setup,
artifact reuse, and sharding instead. The parent verifier job appends
slowest-job tables for child runs; rerun only that verifier after a child rerun
turns green.
artifact reuse, and sharding instead. The parent verifier job appends a child
overview plus slowest-job tables for child runs; rerun only that verifier after
a child rerun turns green.
Standalone manual `CI` dispatches do not run the plugin prerelease suite, the
extension batch sweep, or the release-only `agentic-plugins` Vitest shard. Those
lanes are intentionally reserved for the separate `Plugin Prerelease` child so
PRs, main pushes, and ad hoc broad CI checks do not spend Docker/package time or
all-plugin runtime time on release-only product coverage.
If a full run is already active on a newer `origin/main`, prefer watching that
run over dispatching a duplicate. If you accidentally dispatch a stale duplicate,
cancel it and monitor the current run.
run over dispatching a duplicate. Do not cancel release, release-check, or child
workflow runs unless Peter explicitly asks for cancellation.
The child-dispatch jobs record the child run ids. The final
`Verify full validation` job re-queries those child runs and is the canonical
@@ -153,9 +170,15 @@ only the failed parent verifier job; do not dispatch a new full umbrella unless
the release evidence is stale.
For bounded recovery after a focused fix, pass `-f rerun_group=<group>`.
Supported umbrella groups are `all`, `ci`, `release-checks`, `install-smoke`,
`cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, and
`npm-telegram`. Use the narrowest group that covers the failed box.
Supported umbrella groups are `all`, `ci`, `plugin-prerelease`,
`release-checks`, `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`,
`qa-parity`, `qa-live`, and `npm-telegram`. Use the narrowest group that covers
the failed box. After a targeted release-check fix, do not restart the full
umbrella by habit: dispatch the matching `rerun_group` and rerun only the parent
verifier/evidence step after the child is green unless the release evidence is
stale. For a single failed live/E2E shard, use
`-f rerun_group=live-e2e -f live_suite_filter=<suite_id>` so the Blacksmith
workflow only spends setup and queue time on that suite.
### Release Evidence
@@ -222,6 +245,20 @@ When `Full Release Validation` dispatches release checks, it passes the requeste
branch/tag plus an `expected_sha` so branch/tag refs resolve through the fast
remote-ref path while the package and QA jobs still validate the exact SHA.
The full install-smoke child is split on purpose: one job prepares or reuses the
target-SHA GHCR root Dockerfile smoke image, QR package install runs in its own
job, root Dockerfile/gateway smokes pull the prepared image, and installer/Bun
smokes pull the same image while building only their small installer images.
If install-smoke gets slow again, first check whether the root image was reused
or rebuilt before adding/removing coverage.
The full-profile native live media shards use the prebuilt
`ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` container so
`ffmpeg`/`ffprobe` are already present. If those jobs suddenly spend minutes in
dependency setup again, first check the `Live Media Runner Image` workflow and
the `Verify preinstalled live media dependencies` step before assuming the media
tests themselves slowed down.
The release Docker path intentionally shards the plugin/runtime tail. The
workflow uses `plugins-runtime-plugins`, `plugins-runtime-services`, and
`plugins-runtime-install-a` through `plugins-runtime-install-d`; aggregate

85
.github/CODEOWNERS vendored
View File

@@ -2,50 +2,51 @@
/.github/CODEOWNERS @steipete
# WARNING: GitHub CODEOWNERS uses last-match-wins semantics.
# If you add overlapping rules below the secops block, include @openclaw/secops
# If you add overlapping rules below the secops block, include @openclaw/openclaw-secops
# on those entries too or you can silently remove required secops review.
# Security-sensitive code, config, and docs require secops review.
/SECURITY.md @openclaw/secops
/.github/dependabot.yml @openclaw/secops
/.github/codeql/ @openclaw/secops
/.github/workflows/codeql.yml @openclaw/secops
/.github/workflows/codeql-critical-quality.yml @openclaw/secops
/src/security/ @openclaw/secops
/src/secrets/ @openclaw/secops
/src/config/*secret*.ts @openclaw/secops
/src/config/**/*secret*.ts @openclaw/secops
/src/gateway/*auth*.ts @openclaw/secops
/src/gateway/**/*auth*.ts @openclaw/secops
/src/gateway/*secret*.ts @openclaw/secops
/src/gateway/**/*secret*.ts @openclaw/secops
/src/gateway/security-path*.ts @openclaw/secops
/src/gateway/resolve-configured-secret-input-string*.ts @openclaw/secops
/src/gateway/protocol/**/*secret*.ts @openclaw/secops
/src/gateway/server-methods/secrets*.ts @openclaw/secops
/src/agents/*auth*.ts @openclaw/secops
/src/agents/**/*auth*.ts @openclaw/secops
/src/agents/auth-profiles*.ts @openclaw/secops
/src/agents/auth-health*.ts @openclaw/secops
/src/agents/auth-profiles/ @openclaw/secops
/src/agents/sandbox.ts @openclaw/secops
/src/agents/sandbox-*.ts @openclaw/secops
/src/agents/sandbox/ @openclaw/secops
/src/infra/secret-file*.ts @openclaw/secops
/src/cron/stagger.ts @openclaw/secops
/src/cron/service/jobs.ts @openclaw/secops
/docs/security/ @openclaw/secops
/docs/gateway/authentication.md @openclaw/secops
/docs/gateway/sandbox-vs-tool-policy-vs-elevated.md @openclaw/secops
/docs/gateway/sandboxing.md @openclaw/secops
/docs/gateway/secrets-plan-contract.md @openclaw/secops
/docs/gateway/secrets.md @openclaw/secops
/docs/gateway/security/ @openclaw/secops
/docs/cli/approvals.md @openclaw/secops
/docs/cli/sandbox.md @openclaw/secops
/docs/cli/security.md @openclaw/secops
/docs/cli/secrets.md @openclaw/secops
/docs/reference/secretref-credential-surface.md @openclaw/secops
/docs/reference/secretref-user-supplied-credentials-matrix.json @openclaw/secops
/SECURITY.md @openclaw/openclaw-secops
/.github/dependabot.yml @openclaw/openclaw-secops
/.github/codeql/ @openclaw/openclaw-secops
/.github/workflows/codeql.yml @openclaw/openclaw-secops
/.github/workflows/codeql-android-critical-security.yml @openclaw/openclaw-secops
/.github/workflows/codeql-critical-quality.yml @openclaw/openclaw-secops
/src/security/ @openclaw/openclaw-secops
/src/secrets/ @openclaw/openclaw-secops
/src/config/*secret*.ts @openclaw/openclaw-secops
/src/config/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/*auth*.ts @openclaw/openclaw-secops
/src/gateway/**/*auth*.ts @openclaw/openclaw-secops
/src/gateway/*secret*.ts @openclaw/openclaw-secops
/src/gateway/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/security-path*.ts @openclaw/openclaw-secops
/src/gateway/resolve-configured-secret-input-string*.ts @openclaw/openclaw-secops
/src/gateway/protocol/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/server-methods/secrets*.ts @openclaw/openclaw-secops
/src/agents/*auth*.ts @openclaw/openclaw-secops
/src/agents/**/*auth*.ts @openclaw/openclaw-secops
/src/agents/auth-profiles*.ts @openclaw/openclaw-secops
/src/agents/auth-health*.ts @openclaw/openclaw-secops
/src/agents/auth-profiles/ @openclaw/openclaw-secops
/src/agents/sandbox.ts @openclaw/openclaw-secops
/src/agents/sandbox-*.ts @openclaw/openclaw-secops
/src/agents/sandbox/ @openclaw/openclaw-secops
/src/infra/secret-file*.ts @openclaw/openclaw-secops
/src/cron/stagger.ts @openclaw/openclaw-secops
/src/cron/service/jobs.ts @openclaw/openclaw-secops
/docs/security/ @openclaw/openclaw-secops
/docs/gateway/authentication.md @openclaw/openclaw-secops
/docs/gateway/sandbox-vs-tool-policy-vs-elevated.md @openclaw/openclaw-secops
/docs/gateway/sandboxing.md @openclaw/openclaw-secops
/docs/gateway/secrets-plan-contract.md @openclaw/openclaw-secops
/docs/gateway/secrets.md @openclaw/openclaw-secops
/docs/gateway/security/ @openclaw/openclaw-secops
/docs/cli/approvals.md @openclaw/openclaw-secops
/docs/cli/sandbox.md @openclaw/openclaw-secops
/docs/cli/security.md @openclaw/openclaw-secops
/docs/cli/secrets.md @openclaw/openclaw-secops
/docs/reference/secretref-credential-surface.md @openclaw/openclaw-secops
/docs/reference/secretref-user-supplied-credentials-matrix.json @openclaw/openclaw-secops
# Release workflow and its supporting release-path checks.
/.github/workflows/openclaw-npm-release.yml @openclaw/openclaw-release-managers

View File

@@ -4,6 +4,7 @@
self-hosted-runner:
labels:
# Blacksmith CI runners
- blacksmith-4vcpu-ubuntu-2404
- blacksmith-8vcpu-ubuntu-2404
- blacksmith-8vcpu-windows-2025
- blacksmith-16vcpu-ubuntu-2404

View File

@@ -90,9 +90,11 @@ runs:
install_args=(
install
--prefer-offline
--ignore-scripts=false
--config.engine-strict=false
--config.enable-pre-post-scripts=true
--config.side-effects-cache=true
)
if [ -n "$LOCKFILE_FLAG" ]; then
install_args+=("$LOCKFILE_FLAG")

View File

@@ -1,5 +1,18 @@
name: openclaw-codeql-actions-critical-security
disable-default-queries: true
queries:
- uses: security-extended
query-filters:
- include:
precision:
- high
- very-high
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- .github/actions
- .github/workflows

View File

@@ -0,0 +1,53 @@
name: openclaw-codeql-agent-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/acp/control-plane
- src/agents/command
- src/agents/cli-runner
- src/agents/pi-embedded-runner
- src/agents/tools
- src/agents/*completion*.ts
- src/agents/*transport*.ts
- src/agents/model-*.ts
- src/agents/openclaw-tools*.ts
- src/agents/provider-*.ts
- src/agents/session*.ts
- src/agents/tool-call*.ts
- src/auto-reply/reply/agent-runner*.ts
- src/auto-reply/reply/commands*.ts
- src/auto-reply/reply/directive-handling*.ts
- src/auto-reply/reply/dispatch-*.ts
- src/auto-reply/reply/get-reply-run*.ts
- src/auto-reply/reply/provider-dispatcher*.ts
- src/auto-reply/reply/queue*.ts
- src/auto-reply/reply/reply-run-registry*.ts
- src/auto-reply/reply/session*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,56 @@
name: openclaw-codeql-channel-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- extensions/bluebubbles/src
- extensions/discord/src
- extensions/feishu/src
- extensions/googlechat/src
- extensions/imessage/src
- extensions/irc/src
- extensions/line/src
- extensions/matrix/src
- extensions/mattermost/src
- extensions/msteams/src
- extensions/nextcloud-talk/src
- extensions/nostr/src
- extensions/qa-channel/src
- extensions/qqbot/src
- extensions/signal/src
- extensions/slack/src
- extensions/synology-chat/src
- extensions/telegram/src
- extensions/tlon/src
- extensions/twitch/src
- extensions/whatsapp/src
- extensions/zalo/src
- extensions/zalouser/src
- src/channels
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,48 @@
name: openclaw-codeql-channel-runtime-boundary-critical-security
disable-default-queries: true
queries:
- uses: security-extended
query-filters:
- include:
precision:
- high
- very-high
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- src/channels
- src/config/channel-*.ts
- src/config/types.channel*.ts
- src/gateway/server-channel*.ts
- src/gateway/server-methods/channels.ts
- src/gateway/protocol/schema/channels.ts
- src/infra/channel-*.ts
- src/infra/exec-approval-channel-runtime.ts
- src/infra/outbound/channel-*.ts
- src/plugin-sdk/channel-*.ts
- src/plugins/channel-*.ts
- src/plugins/bundled-channel-*.ts
- src/plugins/runtime/*channel*.ts
- src/secrets/channel-*.ts
- src/secrets/runtime-config-collectors-channels.ts
- src/security/audit-channel*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,33 @@
name: openclaw-codeql-config-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/config
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -1,4 +1,4 @@
name: openclaw-codeql-javascript-typescript-critical-quality
name: openclaw-codeql-core-auth-secrets-critical-quality
disable-default-queries: true
@@ -22,7 +22,6 @@ paths:
- src/agents/sandbox
- src/agents/sandbox.ts
- src/agents/sandbox-*.ts
- src/config
- src/cron/service/jobs.ts
- src/cron/stagger.ts
- src/gateway/*auth*.ts

View File

@@ -1,4 +1,4 @@
name: openclaw-codeql-javascript-typescript-critical-security
name: openclaw-codeql-core-auth-secrets-critical-security
disable-default-queries: true
@@ -10,10 +10,8 @@ query-filters:
precision:
- high
- very-high
- exclude:
problem.severity:
- recommendation
- warning
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- src/agents/*auth*.ts

View File

@@ -0,0 +1,37 @@
name: openclaw-codeql-gateway-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/gateway/method-scopes.ts
- src/gateway/protocol
- src/gateway/server-methods
- src/gateway/server-methods.ts
- src/gateway/server-methods-list.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,35 @@
name: openclaw-codeql-mcp-process-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/mcp
- src/process
- src/infra/outbound
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,56 @@
name: openclaw-codeql-mcp-process-tool-boundary-critical-security
disable-default-queries: true
queries:
- uses: security-extended
query-filters:
- include:
precision:
- high
- very-high
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- src/mcp
- src/process
- src/infra/outbound
- src/agents/bash-tools.exec*.ts
- src/agents/bash-tools.process*.ts
- src/agents/exec-*.ts
- src/agents/execution-contract.ts
- src/agents/openclaw-plugin-tools.ts
- src/agents/openclaw-tools.runtime.ts
- src/agents/openclaw-tools.registration.ts
- src/agents/pi-tool-definition-adapter.ts
- src/agents/pi-tools.abort.ts
- src/agents/pi-tools.before-tool-call*.ts
- src/agents/pi-tools.host-edit.ts
- src/agents/pi-tools-parameter-schema.ts
- src/agents/pi-embedded-runner/effective-tool-policy.ts
- src/agents/pi-embedded-runner/tool-name-allowlist.ts
- src/agents/pi-embedded-runner/tool-schema-runtime.ts
- src/agents/tools/gateway-tool.ts
- src/agents/tools/message-tool.ts
- src/agents/tools/sessions-send-tool.ts
- src/agents/tools/sessions-spawn-tool.ts
- src/agents/tools/subagents-tool.ts
- src/agents/tools/tool-runtime.helpers.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,41 @@
name: openclaw-codeql-memory-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- packages/memory-host-sdk/src
- src/memory
- src/memory-host-sdk
- src/plugin-sdk/memory-*.ts
- src/plugin-sdk/memory-core-host-*.ts
- src/plugins/memory-*.ts
- src/gateway/server-startup-memory.ts
- src/commands/doctor-memory-search.ts
- src/commands/doctor-cron-dreaming-payload-migration.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,41 @@
name: openclaw-codeql-network-ssrf-boundary-critical-security
disable-default-queries: true
queries:
- uses: security-extended
query-filters:
- include:
precision:
- high
- very-high
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- src/infra/net
- src/shared/net
- src/agents/tools/web-fetch.ts
- src/agents/tools/web-guarded-fetch.ts
- src/agents/tools/web-shared.ts
- src/plugin-sdk/ssrf-policy.ts
- src/web-fetch
- src/web/provider-runtime-shared.ts
- packages/memory-host-sdk/src/host/ssrf-policy.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,76 @@
name: openclaw-codeql-plugin-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/plugins/activation-planner.ts
- src/plugins/api-builder.ts
- src/plugins/bundled-compat.ts
- src/plugins/bundled-dir.ts
- src/plugins/bundled-plugin-metadata.ts
- src/plugins/bundled-public-surface-runtime-root.ts
- src/plugins/bundled-runtime-deps.ts
- src/plugins/bundled-runtime-root.ts
- src/plugins/captured-registration.ts
- src/plugins/config-activation-shared.ts
- src/plugins/config-contracts.ts
- src/plugins/config-normalization-shared.ts
- src/plugins/config-policy.ts
- src/plugins/config-schema.ts
- src/plugins/config-state.ts
- src/plugins/discovery.ts
- src/plugins/effective-plugin-ids.ts
- src/plugins/externalized-bundled-plugins.ts
- src/plugins/installed-plugin-index*.ts
- src/plugins/loader*.ts
- src/plugins/manifest*.ts
- src/plugins/module-export.ts
- src/plugins/package-entrypoints.ts
- src/plugins/plugin-registry*.ts
- src/plugins/provider-contract-public-artifacts.ts
- src/plugins/provider-public-artifacts.ts
- src/plugins/public-surface*.ts
- src/plugins/registry.ts
- src/plugins/registry-types.ts
- src/plugins/runtime
- src/plugins/runtime-state.ts
- src/plugins/runtime.ts
- src/plugins/sdk-alias.ts
- src/plugins/source-loader.ts
- src/plugins/types.ts
- src/plugins/validation-diagnostics.ts
- src/plugins/web-provider-public-artifacts*.ts
- src/plugin-sdk/*entry*.ts
- src/plugin-sdk/*facade*.ts
- src/plugin-sdk/api-baseline.ts
- src/plugin-sdk/config-schema.ts
- src/plugin-sdk/config-types.ts
- src/plugin-sdk/core.ts
- src/plugin-sdk/extension-shared.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,36 @@
name: openclaw-codeql-plugin-sdk-package-contract-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- packages/plugin-sdk/src
- packages/plugin-package-contract/src
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.spec.ts"
- "**/*.spec.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,44 @@
name: openclaw-codeql-plugin-sdk-reply-runtime-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/plugin-sdk/inbound-envelope.ts
- src/plugin-sdk/inbound-reply-dispatch.ts
- src/plugin-sdk/reply-*.ts
- src/plugin-sdk/channel-reply-*.ts
- src/plugin-sdk/delivery-queue-runtime.ts
- src/plugin-sdk/outbound-runtime.ts
- src/plugin-sdk/outbound-send-deps.ts
- src/plugin-sdk/model-session-runtime.ts
- src/plugin-sdk/session-*.ts
- src/plugin-sdk/thread-bindings-runtime.ts
- src/plugin-sdk/thread-bindings-session-runtime.ts
- src/plugin-sdk/conversation-binding-runtime.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,87 @@
name: openclaw-codeql-plugin-trust-boundary-critical-security
disable-default-queries: true
queries:
- uses: security-extended
query-filters:
- include:
precision:
- high
- very-high
tags contain: security
security-severity: /([7-9]|10)\.(\d)+/
paths:
- src/cli/plugin-install-config-policy.ts
- src/cli/plugin-registry-loader.ts
- src/cli/plugins-command-helpers.ts
- src/cli/plugins-install-command.ts
- src/cli/plugins-install-record-commit.ts
- src/plugins/activation-planner.ts
- src/plugins/bundle-manifest.ts
- src/plugins/bundled-compat.ts
- src/plugins/bundled-dir.ts
- src/plugins/bundled-plugin-metadata.ts
- src/plugins/bundled-plugin-scan.ts
- src/plugins/bundled-runtime-deps*.ts
- src/plugins/bundled-runtime-root.ts
- src/plugins/cli-registry-loader.ts
- src/plugins/config-activation-shared.ts
- src/plugins/config-contracts.ts
- src/plugins/config-policy.ts
- src/plugins/config-schema.ts
- src/plugins/dependency-denylist.ts
- src/plugins/discovery.ts
- src/plugins/effective-plugin-ids.ts
- src/plugins/externalized-bundled-plugins.ts
- src/plugins/install.runtime.ts
- src/plugins/install-source-info.ts
- src/plugins/installed-plugin-index*.ts
- src/plugins/loader*.ts
- src/plugins/manifest*.ts
- src/plugins/marketplace.ts
- src/plugins/module-export.ts
- src/plugins/package-entrypoints.ts
- src/plugins/plugin-config-trust.ts
- src/plugins/plugin-origin.types.ts
- src/plugins/plugin-registry*.ts
- src/plugins/public-surface*.ts
- src/plugins/registry*.ts
- src/plugins/runtime
- src/plugins/runtime-state.ts
- src/plugins/runtime.ts
- src/plugins/source-loader.ts
- src/plugins/update.ts
- src/plugins/validation-diagnostics.ts
- src/plugin-sdk/*entry*.ts
- src/plugin-sdk/*facade*.ts
- src/plugin-sdk/api-baseline.ts
- src/plugin-sdk/config-schema.ts
- src/plugin-sdk/config-types.ts
- src/plugin-sdk/core.ts
- src/plugin-sdk/extension-shared.ts
- packages/plugin-package-contract/src
- packages/plugin-sdk/src/plugin-entry.ts
- packages/plugin-sdk/src/plugin-runtime.ts
- packages/plugin-sdk/src/runtime-env.ts
- packages/plugin-sdk/src/security-runtime.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.spec.ts"
- "**/*.spec.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,44 @@
name: openclaw-codeql-provider-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/model-catalog
- src/plugins/provider-*.ts
- src/plugins/providers*.ts
- src/plugins/*provider*.ts
- src/plugins/capability-provider-runtime.ts
- src/plugins/compaction-provider.ts
- src/plugins/memory-embedding-provider*.ts
- src/plugins/memory-embedding-providers*.ts
- src/plugins/migration-provider-runtime.ts
- src/plugins/synthetic-auth.runtime.ts
- src/plugins/web-fetch-providers*.ts
- src/plugins/web-search-providers*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,48 @@
name: openclaw-codeql-session-diagnostics-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/auto-reply/reply/queue
- src/auto-reply/reply/post-compaction-context.ts
- src/auto-reply/reply/startup-context.ts
- src/infra/diagnostic-*.ts
- src/infra/diagnostics-timeline.ts
- src/infra/session-delivery-queue*.ts
- src/infra/outbound/base-session-key.ts
- src/infra/outbound/delivery-queue*.ts
- src/infra/outbound/outbound-session.ts
- src/infra/outbound/session-binding*.ts
- src/infra/outbound/session-context.ts
- src/infra/outbound/targets-session.ts
- src/logging/diagnostic*.ts
- src/commands/doctor-session-*.ts
- src/commands/session-store-targets.ts
- src/commands/sessions*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,36 @@
name: openclaw-codeql-ui-control-plane-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- ui/src/main.ts
- ui/src/local-storage.ts
- ui/src/ui
- src/tasks/task-registry-control*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,39 @@
name: openclaw-codeql-web-media-runtime-boundary-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- src/web-fetch
- src/web-search
- src/web/provider-runtime-shared.ts
- src/media
- src/media-understanding
- src/image-generation
- src/media-generation
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -0,0 +1,16 @@
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
ffmpeg \
git \
openssh-client \
unzip \
xz-utils \
zstd \
&& rm -rf /var/lib/apt/lists/*

14
.github/labeler.yml vendored
View File

@@ -9,6 +9,12 @@
- "extensions/azure-speech/**"
- "docs/providers/azure-speech.md"
- "docs/tools/tts.md"
"plugin: file-transfer":
- changed-files:
- any-glob-to-any-file:
- "extensions/file-transfer/**"
- "docs/nodes/index.md"
- "docs/plugins/sdk-runtime.md"
"channel: discord":
- changed-files:
- any-glob-to-any-file:
@@ -35,6 +41,11 @@
- any-glob-to-any-file:
- "extensions/google-meet/**"
- "docs/plugins/google-meet.md"
"plugin: zoom":
- changed-files:
- any-glob-to-any-file:
- "extensions/zoom/**"
- "docs/plugins/zoom.md"
"plugin: migrate-hermes":
- changed-files:
- any-glob-to-any-file:
@@ -238,8 +249,11 @@
"security":
- changed-files:
- any-glob-to-any-file:
- ".github/workflows/opengrep-*.yml"
- ".semgrepignore"
- "docs/cli/security.md"
- "docs/gateway/security.md"
- "security/**"
"extensions: copilot-proxy":
- changed-files:

View File

@@ -26,7 +26,7 @@ jobs:
timeout-minutes: 35
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@v2
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
with:
testbox_id: ${{ inputs.testbox_id }}
@@ -218,7 +218,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@v2
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
if: always()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -25,7 +25,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@v2
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
with:
testbox_id: ${{ inputs.testbox_id }}
- name: Checkout
@@ -121,7 +121,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@v2
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
if: always()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -8,6 +8,11 @@ on:
required: false
default: ""
type: string
include_android:
description: Run Android lanes for this manual CI dispatch.
required: false
default: false
type: boolean
push:
branches: [main]
paths-ignore:
@@ -36,7 +41,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 20
outputs:
checkout_sha: ${{ steps.checkout_ref.outputs.sha }}
checkout_revision: ${{ steps.checkout_ref.outputs.sha }}
docs_only: ${{ steps.manifest.outputs.docs_only }}
docs_changed: ${{ steps.manifest.outputs.docs_changed }}
run_node: ${{ steps.manifest.outputs.run_node }}
@@ -49,8 +54,9 @@ jobs:
run_checks_fast_core: ${{ steps.manifest.outputs.run_checks_fast_core }}
run_checks_fast: ${{ steps.manifest.outputs.run_checks_fast }}
checks_fast_core_matrix: ${{ steps.manifest.outputs.checks_fast_core_matrix }}
run_plugin_contracts_shards: ${{ steps.manifest.outputs.run_plugin_contracts_shards }}
plugin_contracts_matrix: ${{ steps.manifest.outputs.plugin_contracts_matrix }}
channel_contracts_matrix: ${{ steps.manifest.outputs.channel_contracts_matrix }}
checks_node_extensions_matrix: ${{ steps.manifest.outputs.checks_node_extensions_matrix }}
run_checks: ${{ steps.manifest.outputs.run_checks }}
checks_matrix: ${{ steps.manifest.outputs.checks_matrix }}
run_checks_node_core_nondist: ${{ steps.manifest.outputs.run_checks_node_core_nondist }}
@@ -117,13 +123,14 @@ jobs:
OPENCLAW_CI_DOCS_CHANGED: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.docs_scope.outputs.docs_changed }}
OPENCLAW_CI_RUN_NODE: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_node || 'false' }}
OPENCLAW_CI_RUN_MACOS: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_macos || 'false' }}
OPENCLAW_CI_RUN_ANDROID: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_android || 'false' }}
OPENCLAW_CI_RUN_ANDROID: ${{ github.event_name == 'workflow_dispatch' && inputs.include_android && 'true' || steps.changed_scope.outputs.run_android || 'false' }}
OPENCLAW_CI_RUN_WINDOWS: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_windows || 'false' }}
OPENCLAW_CI_RUN_NODE_FAST_ONLY: ${{ github.event_name == 'workflow_dispatch' && 'false' || steps.changed_scope.outputs.run_node_fast_only || 'false' }}
OPENCLAW_CI_RUN_NODE_FAST_PLUGIN_CONTRACTS: ${{ github.event_name == 'workflow_dispatch' && 'false' || steps.changed_scope.outputs.run_node_fast_plugin_contracts || 'false' }}
OPENCLAW_CI_RUN_NODE_FAST_CI_ROUTING: ${{ github.event_name == 'workflow_dispatch' && 'false' || steps.changed_scope.outputs.run_node_fast_ci_routing || 'false' }}
OPENCLAW_CI_RUN_SKILLS_PYTHON: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_skills_python || 'false' }}
OPENCLAW_CI_RUN_CONTROL_UI_I18N: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.changed_scope.outputs.run_control_ui_i18n || 'false' }}
OPENCLAW_CI_CHECKOUT_REVISION: ${{ steps.checkout_ref.outputs.sha }}
OPENCLAW_CI_REPOSITORY: ${{ github.repository }}
run: |
node --input-type=module <<'EOF'
@@ -134,10 +141,6 @@ jobs:
import {
createChannelContractTestShards,
} from "./scripts/lib/channel-contract-test-plan.mjs";
import {
createExtensionTestShards,
DEFAULT_EXTENSION_TEST_SHARD_COUNT,
} from "./scripts/lib/extension-test-plan.mjs";
const parseBoolean = (value, fallback = false) => {
if (value === undefined) return fallback;
@@ -147,6 +150,24 @@ jobs:
return fallback;
};
const { createPluginContractTestShards } = await import(
"./scripts/lib/plugin-contract-test-plan.mjs"
).catch((error) => {
if (error?.code !== "ERR_MODULE_NOT_FOUND") {
throw error;
}
return {
createPluginContractTestShards: () => [
{
checkName: "checks-fast-contracts-plugins-legacy",
includePatterns: ["src/plugins/contracts/**/*.test.ts"],
runtime: "node",
task: "contracts-plugins",
},
],
};
});
const createMatrix = (include) => ({ include });
const outputPath = process.env.GITHUB_OUTPUT;
const isCanonicalRepository = process.env.OPENCLAW_CI_REPOSITORY === "openclaw/openclaw";
@@ -160,7 +181,7 @@ jobs:
runNode && parseBoolean(process.env.OPENCLAW_CI_RUN_NODE_FAST_PLUGIN_CONTRACTS);
const runNodeFastCiRouting =
runNode && parseBoolean(process.env.OPENCLAW_CI_RUN_NODE_FAST_CI_ROUTING);
const runChecksFastCore = runNodeFull || runNodeFastPluginContracts || runNodeFastCiRouting;
const runPluginContractShards = runNodeFull || runNodeFastPluginContracts;
const runMacos =
parseBoolean(process.env.OPENCLAW_CI_RUN_MACOS) && !docsOnly && isCanonicalRepository;
const runAndroid =
@@ -173,44 +194,13 @@ jobs:
const runSkillsPython = parseBoolean(process.env.OPENCLAW_CI_RUN_SKILLS_PYTHON) && !docsOnly;
const runControlUiI18n =
parseBoolean(process.env.OPENCLAW_CI_RUN_CONTROL_UI_I18N) && !docsOnly;
const extensionTestShardCount = isCanonicalRepository
? DEFAULT_EXTENSION_TEST_SHARD_COUNT
: Math.max(DEFAULT_EXTENSION_TEST_SHARD_COUNT, 36);
const extensionShardMatrix = createMatrix(
runNodeFull
? createExtensionTestShards({
shardCount: extensionTestShardCount,
}).map((shard) => ({
check_name: shard.checkName,
extensions_csv: shard.extensionIds.join(","),
runner: isCanonicalRepository && [0, 3, 4].includes(shard.index)
? "blacksmith-8vcpu-ubuntu-2404"
: isCanonicalRepository
? "blacksmith-4vcpu-ubuntu-2404"
: "ubuntu-24.04",
shard_index: shard.index + 1,
task: "extensions-batch",
}))
: [],
);
const checksFastCoreTasks = [];
if (runNodeFull) {
checksFastCoreTasks.push(
{ check_name: "checks-fast-bundled", runtime: "node", task: "bundled" },
{
check_name: "checks-fast-contracts-plugins",
runtime: "node",
task: "contracts-plugins",
},
);
} else {
if (runNodeFastPluginContracts) {
checksFastCoreTasks.push({
check_name: "checks-fast-contracts-plugins",
runtime: "node",
task: runNodeFastCiRouting ? "contracts-plugins-ci-routing" : "contracts-plugins",
});
} else if (runNodeFastCiRouting) {
if (runNodeFastCiRouting) {
checksFastCoreTasks.push({
check_name: "checks-fast-ci-routing",
runtime: "node",
@@ -220,7 +210,9 @@ jobs:
}
const nodeTestShards = runNodeFull
? createNodeTestShards().map((shard) => ({
? createNodeTestShards({
includeReleaseOnlyPluginShards: false,
}).map((shard) => ({
check_name: shard.checkName,
runtime: "node",
task: "test-shard",
@@ -243,13 +235,16 @@ jobs:
run_skills_python: runSkillsPython,
run_windows: runWindows,
run_build_artifacts: runNodeFull,
run_checks_fast_core: runChecksFastCore,
run_checks_fast_core: checksFastCoreTasks.length > 0,
run_checks_fast: runNodeFull,
checks_fast_core_matrix: createMatrix(checksFastCoreTasks),
run_plugin_contracts_shards: runPluginContractShards,
plugin_contracts_matrix: createMatrix(
runPluginContractShards ? createPluginContractTestShards() : [],
),
channel_contracts_matrix: createMatrix(
runNodeFull ? createChannelContractTestShards() : [],
),
checks_node_extensions_matrix: extensionShardMatrix,
run_checks: runNodeFull,
checks_matrix: createMatrix(
runNodeFull
@@ -468,7 +463,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -540,7 +535,7 @@ jobs:
path: |
dist/
dist-runtime/
key: ${{ runner.os }}-dist-build-${{ needs.preflight.outputs.checkout_sha }}
key: ${{ runner.os }}-dist-build-${{ needs.preflight.outputs.checkout_revision }}
- name: Pack built runtime artifacts
run: tar --posix -cf dist-runtime-build.tar.zst --use-compress-program zstdmt dist dist-runtime
@@ -669,7 +664,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -748,6 +743,112 @@ jobs:
;;
esac
checks-fast-plugin-contracts-shard:
permissions:
contents: read
name: ${{ matrix.checkName }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_contracts_shards == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.plugin_contracts_matrix) }}
steps:
- name: Checkout
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
workdir="$GITHUB_WORKSPACE"
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
reset_checkout_dir() {
mkdir -p "$workdir"
find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
}
checkout_attempt() {
local attempt="$1"
reset_checkout_dir
git init "$workdir" >/dev/null
git config --global --add safe.directory "$workdir"
git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}"
git -C "$workdir" config gc.auto 0
timeout --signal=TERM 30s git -C "$workdir" \
-c protocol.version=2 \
-c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1
git -C "$workdir" checkout --force --detach "$CHECKOUT_SHA" || return 1
test -f "$workdir/.github/actions/setup-node-env/action.yml" || return 1
echo "checkout attempt ${attempt}/5 succeeded"
}
for attempt in 1 2 3 4 5; do
if checkout_attempt "$attempt"; then
exit 0
fi
echo "checkout attempt ${attempt}/5 failed"
sleep $((attempt * 5))
done
echo "checkout failed after 5 attempts" >&2
exit 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Run plugin contract shard
env:
OPENCLAW_CONTRACT_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
shell: bash
run: |
set -euo pipefail
include_file="$RUNNER_TEMP/plugin-contract-include.json"
INCLUDE_FILE="$include_file" node --input-type=module <<'EOF'
import { writeFileSync } from "node:fs";
const includePatterns = JSON.parse(process.env.OPENCLAW_CONTRACT_INCLUDE_PATTERNS_JSON ?? "[]");
if (!Array.isArray(includePatterns) || includePatterns.length === 0) {
console.error("Missing plugin contract include patterns");
process.exit(1);
}
writeFileSync(process.env.INCLUDE_FILE, JSON.stringify(includePatterns), "utf8");
EOF
OPENCLAW_VITEST_INCLUDE_FILE="$include_file" pnpm test:contracts:plugins
checks-fast-plugin-contracts:
permissions:
contents: read
name: checks-fast-contracts-plugins
needs: [preflight, checks-fast-plugin-contracts-shard]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_plugin_contracts_shards == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Verify plugin contract shards
env:
SHARD_RESULT: ${{ needs.checks-fast-plugin-contracts-shard.result }}
run: |
if [ "$SHARD_RESULT" = "cancelled" ]; then
echo "Plugin contract shards were cancelled, usually because a newer commit superseded this run." >&2
exit 1
fi
if [ "$SHARD_RESULT" != "success" ]; then
echo "Plugin contract shards failed: $SHARD_RESULT" >&2
exit 1
fi
checks-fast-channel-contracts-shard:
permissions:
contents: read
@@ -764,7 +865,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -867,7 +968,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -919,97 +1020,6 @@ jobs:
- name: Run protocol check
run: pnpm protocol:check
checks-node-extensions-shard:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_fast == 'true'
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.checks_node_extensions_matrix) }}
steps:
- name: Checkout
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
workdir="$GITHUB_WORKSPACE"
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
reset_checkout_dir() {
mkdir -p "$workdir"
find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
}
checkout_attempt() {
local attempt="$1"
reset_checkout_dir
git init "$workdir" >/dev/null
git config --global --add safe.directory "$workdir"
git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}"
git -C "$workdir" config gc.auto 0
timeout --signal=TERM 30s git -C "$workdir" \
-c protocol.version=2 \
-c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1
git -C "$workdir" checkout --force --detach "$CHECKOUT_SHA" || return 1
test -f "$workdir/.github/actions/setup-node-env/action.yml" || return 1
echo "checkout attempt ${attempt}/5 succeeded"
}
for attempt in 1 2 3 4 5; do
if checkout_attempt "$attempt"; then
exit 0
fi
echo "checkout attempt ${attempt}/5 failed"
sleep $((attempt * 5))
done
echo "checkout failed after 5 attempts" >&2
exit 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Run extension shard
env:
NODE_OPTIONS: --max-old-space-size=6144
OPENCLAW_EXTENSION_BATCH_PARALLEL: 2
OPENCLAW_VITEST_MAX_WORKERS: 1
OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }}
run: pnpm test:extensions:batch -- "$OPENCLAW_EXTENSION_BATCH"
checks-node-extensions:
permissions:
contents: read
name: checks-node-extensions
needs: [preflight, checks-node-extensions-shard]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_checks_fast == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Verify extension shards
env:
SHARD_RESULT: ${{ needs.checks-node-extensions-shard.result }}
run: |
if [ "$SHARD_RESULT" != "success" ]; then
echo "Extension shard checks failed: $SHARD_RESULT" >&2
exit 1
fi
checks:
permissions:
contents: read
@@ -1055,7 +1065,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -1135,7 +1145,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -1308,6 +1318,9 @@ jobs:
- check_name: check-lint
task: lint
runner: blacksmith-16vcpu-ubuntu-2404
- check_name: check-dependencies
task: dependencies
runner: ubuntu-24.04
- check_name: check-policy-guards
task: policy-guards
runner: ubuntu-24.04
@@ -1322,7 +1335,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -1383,6 +1396,7 @@ jobs:
pnpm check:no-conflict-markers
pnpm tool-display:check
pnpm check:host-env-policy:swift
pnpm dup:check:coverage
;;
prod-types)
pnpm tsgo:prod
@@ -1390,6 +1404,14 @@ jobs:
lint)
pnpm lint --threads=8
;;
dependencies)
if pnpm run --silent 2>/dev/null | grep -q '^ deadcode:dependencies$'; then
pnpm deadcode:dependencies
pnpm deadcode:unused-files
else
pnpm deadcode:ci
fi
;;
policy-guards)
pnpm lint:webhook:no-low-level-body-read
pnpm lint:auth:no-pairing-store-group
@@ -1454,7 +1476,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -1652,7 +1674,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -1715,7 +1737,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_sha }}
ref: ${{ needs.preflight.outputs.checkout_revision }}
persist-credentials: false
submodules: false
@@ -1758,7 +1780,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_sha }}
ref: ${{ needs.preflight.outputs.checkout_revision }}
persist-credentials: false
submodules: false
@@ -1863,7 +1885,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_sha }}
ref: ${{ needs.preflight.outputs.checkout_revision }}
persist-credentials: false
submodules: false
@@ -1904,7 +1926,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_sha }}
ref: ${{ needs.preflight.outputs.checkout_revision }}
persist-credentials: false
submodules: false
@@ -2005,7 +2027,7 @@ jobs:
shell: bash
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_sha }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
@@ -2061,6 +2083,14 @@ jobs:
apps/android/**/gradle-wrapper.properties
apps/android/gradle/libs.versions.toml
- name: Cache Android SDK
uses: actions/cache@v5
with:
path: ~/.android-sdk
key: ${{ runner.os }}-android-sdk-v1-cmdline-12266719-platform-36-build-tools-36.0.0
restore-keys: |
${{ runner.os }}-android-sdk-v1-
- name: Setup Android SDK cmdline-tools
run: |
set -euo pipefail
@@ -2069,11 +2099,13 @@ jobs:
ARCHIVE="commandlinetools-linux-${CMDLINE_TOOLS_VERSION}_latest.zip"
URL="https://dl.google.com/android/repository/${ARCHIVE}"
mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
curl -fsSL "$URL" -o "/tmp/${ARCHIVE}"
rm -rf "$ANDROID_SDK_ROOT/cmdline-tools/latest"
unzip -q "/tmp/${ARCHIVE}" -d "$ANDROID_SDK_ROOT/cmdline-tools"
mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest"
if [ ! -x "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then
mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
curl -fsSL "$URL" -o "/tmp/${ARCHIVE}"
rm -rf "$ANDROID_SDK_ROOT/cmdline-tools/latest"
unzip -q "/tmp/${ARCHIVE}" -d "$ANDROID_SDK_ROOT/cmdline-tools"
mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest"
fi
echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT" >> "$GITHUB_ENV"
echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> "$GITHUB_ENV"

View File

@@ -3,44 +3,64 @@ name: ClawSweeper Dispatch
on:
issues:
types: [opened, reopened, edited, labeled, unlabeled]
push:
branches: [main]
pull_request_target: # zizmor: ignore[dangerous-triggers] maintainer-owned external dispatch; no checkout or untrusted PR code execution
types: [opened, reopened, synchronize, ready_for_review, edited, labeled, unlabeled]
permissions:
contents: read
concurrency:
group: clawsweeper-dispatch-${{ github.repository }}-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event.action == 'edited' || github.event.action == 'synchronize' || github.event.action == 'ready_for_review' }}
jobs:
dispatch:
runs-on: ubuntu-latest
if: ${{ !(endsWith(github.actor, '[bot]') && (github.event.action == 'labeled' || github.event.action == 'unlabeled')) }}
env:
HAS_CLAWSWEEPER_APP_PRIVATE_KEY: ${{ secrets.CLAWSWEEPER_APP_PRIVATE_KEY != '' }}
CLAWSWEEPER_APP_CLIENT_ID: Iv23liOECG0slfuhz093
SUPERSEDES_IN_PROGRESS: ${{ (github.event.action == 'edited' || github.event.action == 'synchronize' || github.event.action == 'ready_for_review') && 'true' || 'false' }}
steps:
- name: Debounce bursty metadata events
if: ${{ github.event.action == 'labeled' || github.event.action == 'unlabeled' }}
run: sleep 20
- name: Create ClawSweeper dispatch token
id: token
if: ${{ env.HAS_CLAWSWEEPER_APP_PRIVATE_KEY == 'true' }}
uses: actions/create-github-app-token@v2
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: 3306130
client-id: ${{ env.CLAWSWEEPER_APP_CLIENT_ID }}
private-key: ${{ secrets.CLAWSWEEPER_APP_PRIVATE_KEY }}
owner: openclaw
repositories: clawsweeper
permission-contents: write
- name: Dispatch exact ClawSweeper review
if: ${{ github.event_name != 'push' }}
env:
GH_TOKEN: ${{ steps.token.outputs.token || secrets.OPENCLAW_GH_TOKEN }}
GH_TOKEN: ${{ steps.token.outputs.token }}
TARGET_REPO: ${{ github.repository }}
ITEM_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
ITEM_KIND: ${{ github.event_name == 'pull_request_target' && 'pull_request' || 'issue' }}
SOURCE_EVENT: ${{ github.event_name }}
SOURCE_ACTION: ${{ github.event.action }}
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::Skipping ClawSweeper dispatch because no dispatch credential is configured."
echo "::notice::Skipping ClawSweeper dispatch because no ClawSweeper app token is configured. Not falling back to a maintainer token."
exit 0
fi
payload="$(jq -nc \
--arg target_repo "$TARGET_REPO" \
--argjson item_number "$ITEM_NUMBER" \
--arg item_kind "$ITEM_KIND" \
'{event_type:"clawsweeper_item",client_payload:{target_repo:$target_repo,item_number:$item_number,item_kind:$item_kind}}')"
--arg source_event "$SOURCE_EVENT" \
--arg source_action "$SOURCE_ACTION" \
--argjson supersedes_in_progress "$SUPERSEDES_IN_PROGRESS" \
'{event_type:"clawsweeper_item",client_payload:{target_repo:$target_repo,item_number:$item_number,item_kind:$item_kind,source_event:$source_event,source_action:$source_action,supersedes_in_progress:$supersedes_in_progress}}')"
if gh api repos/openclaw/clawsweeper/dispatches \
--method POST \
--input - <<< "$payload"; then
@@ -48,3 +68,36 @@ jobs:
else
echo "::warning::Skipping ClawSweeper dispatch because the configured credential could not dispatch to openclaw/clawsweeper."
fi
- name: Dispatch ClawSweeper commit review
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.deleted != true }}
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
TARGET_REPO: ${{ github.repository }}
BEFORE_SHA: ${{ github.event.before }}
AFTER_SHA: ${{ github.sha }}
SOURCE_REF: ${{ github.ref }}
CREATE_CHECKS: ${{ vars.CLAWSWEEPER_COMMIT_REVIEW_CREATE_CHECKS || 'false' }}
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::Skipping ClawSweeper commit dispatch because no ClawSweeper app token is configured. Not falling back to a maintainer token."
exit 0
fi
case "$CREATE_CHECKS" in
true|TRUE|1|yes|YES|on|ON) create_checks=true ;;
*) create_checks=false ;;
esac
payload="$(jq -nc \
--arg target_repo "$TARGET_REPO" \
--arg before_sha "$BEFORE_SHA" \
--arg after_sha "$AFTER_SHA" \
--arg ref "$SOURCE_REF" \
--argjson create_checks "$create_checks" \
'{event_type:"clawsweeper_commit_review",client_payload:{target_repo:$target_repo,before_sha:$before_sha,after_sha:$after_sha,ref:$ref,enabled:true,create_checks:$create_checks}}')"
if gh api repos/openclaw/clawsweeper/dispatches \
--method POST \
--input - <<< "$payload"; then
echo "Dispatched ClawSweeper commit review."
else
echo "::warning::Skipping ClawSweeper commit dispatch because the configured credential could not dispatch to openclaw/clawsweeper."
fi

View File

@@ -0,0 +1,51 @@
name: CodeQL Android Critical Security
on:
workflow_dispatch:
schedule:
- cron: "0 7 * * *"
concurrency:
group: codeql-android-critical-security-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.sha }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
permissions:
actions: read
contents: read
security-events: write
jobs:
android:
name: Critical Security (android)
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Setup Java
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: temurin
java-version: "21"
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: java-kotlin
build-mode: manual
config-file: ./.github/codeql/codeql-android-critical-security.yml
- name: Build Android for CodeQL
working-directory: apps/android
run: ./gradlew --no-daemon :app:assemblePlayDebug
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-security/android"

View File

@@ -2,12 +2,135 @@ name: CodeQL Critical Quality
on:
workflow_dispatch:
inputs:
profile:
description: CodeQL quality profile to run
required: false
default: all
type: choice
options:
- all
- agent-runtime-boundary
- config-boundary
- core-auth-secrets
- channel-runtime-boundary
- gateway-runtime-boundary
- memory-runtime-boundary
- mcp-process-runtime-boundary
- plugin-boundary
- plugin-sdk-package-contract
- plugin-sdk-reply-runtime
- provider-runtime-boundary
- session-diagnostics-boundary
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- ".github/codeql/**"
- ".github/workflows/codeql-critical-quality.yml"
- "packages/plugin-package-contract/**"
- "packages/plugin-sdk/**"
- "packages/memory-host-sdk/**"
- "src/config/**"
- "extensions/bluebubbles/src/**"
- "extensions/discord/src/**"
- "extensions/feishu/src/**"
- "extensions/googlechat/src/**"
- "extensions/imessage/src/**"
- "extensions/irc/src/**"
- "extensions/line/src/**"
- "extensions/matrix/src/**"
- "extensions/mattermost/src/**"
- "extensions/msteams/src/**"
- "extensions/nextcloud-talk/src/**"
- "extensions/nostr/src/**"
- "extensions/qa-channel/src/**"
- "extensions/qqbot/src/**"
- "extensions/signal/src/**"
- "extensions/slack/src/**"
- "extensions/synology-chat/src/**"
- "extensions/telegram/src/**"
- "extensions/tlon/src/**"
- "extensions/twitch/src/**"
- "extensions/whatsapp/src/**"
- "extensions/zalo/src/**"
- "extensions/zalouser/src/**"
- "src/agents/*auth*.ts"
- "src/agents/**/*auth*.ts"
- "src/agents/auth-health*.ts"
- "src/agents/auth-profiles"
- "src/agents/auth-profiles/**"
- "src/agents/bash-tools.exec-host-shared.ts"
- "src/agents/sandbox"
- "src/agents/sandbox/**"
- "src/agents/sandbox.ts"
- "src/agents/sandbox-*.ts"
- "src/acp/control-plane/**"
- "src/agents/cli-runner/**"
- "src/agents/command/**"
- "src/agents/pi-embedded-runner/**"
- "src/agents/tools/**"
- "src/agents/*completion*.ts"
- "src/agents/*transport*.ts"
- "src/agents/model-*.ts"
- "src/agents/openclaw-tools*.ts"
- "src/agents/provider-*.ts"
- "src/agents/session*.ts"
- "src/agents/tool-call*.ts"
- "src/auto-reply/reply/agent-runner*.ts"
- "src/auto-reply/reply/commands*.ts"
- "src/auto-reply/reply/directive-handling*.ts"
- "src/auto-reply/reply/dispatch-*.ts"
- "src/auto-reply/reply/get-reply-run*.ts"
- "src/auto-reply/reply/provider-dispatcher*.ts"
- "src/auto-reply/reply/queue*.ts"
- "src/auto-reply/reply/reply-run-registry*.ts"
- "src/auto-reply/reply/session*.ts"
- "src/channels/**"
- "src/auto-reply/reply/post-compaction-context.ts"
- "src/auto-reply/reply/queue/**"
- "src/auto-reply/reply/startup-context.ts"
- "src/commands/doctor-cron-dreaming-payload-migration.ts"
- "src/commands/doctor-memory-search.ts"
- "src/commands/doctor-session-*.ts"
- "src/commands/session-store-targets.ts"
- "src/commands/sessions*.ts"
- "src/cron/service/jobs.ts"
- "src/cron/stagger.ts"
- "src/gateway/*auth*.ts"
- "src/gateway/**/*auth*.ts"
- "src/gateway/*secret*.ts"
- "src/gateway/**/*secret*.ts"
- "src/gateway/protocol/**/*secret*.ts"
- "src/gateway/resolve-configured-secret-input-string*.ts"
- "src/gateway/security-path*.ts"
- "src/gateway/server-methods/secrets*.ts"
- "src/gateway/server-startup-memory.ts"
- "src/gateway/method-scopes.ts"
- "src/gateway/protocol/**"
- "src/gateway/server-methods/**"
- "src/gateway/server-methods.ts"
- "src/gateway/server-methods-list.ts"
- "src/infra/diagnostic-*.ts"
- "src/infra/diagnostics-timeline.ts"
- "src/infra/outbound/**"
- "src/infra/secret-file*.ts"
- "src/infra/session-delivery-queue*.ts"
- "src/logging/diagnostic*.ts"
- "src/memory/**"
- "src/memory-host-sdk/**"
- "src/mcp/**"
- "src/model-catalog/**"
- "src/plugin-sdk/**"
- "src/plugins/**"
- "src/process/**"
- "src/secrets/**"
- "src/security/**"
schedule:
- cron: "30 6 * * *"
concurrency:
group: codeql-critical-quality-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.sha }}
cancel-in-progress: false
group: codeql-critical-quality-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -15,12 +138,171 @@ env:
permissions:
actions: read
contents: read
pull-requests: read
security-events: write
jobs:
javascript-typescript:
name: Critical Quality (javascript-typescript)
runs-on: blacksmith-8vcpu-ubuntu-2404
quality-shards:
name: Select Critical Quality shards
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 5
outputs:
agent: ${{ steps.detect.outputs.agent }}
channel: ${{ steps.detect.outputs.channel }}
config: ${{ steps.detect.outputs.config }}
core_auth_secrets: ${{ steps.detect.outputs.core_auth_secrets }}
gateway: ${{ steps.detect.outputs.gateway }}
memory: ${{ steps.detect.outputs.memory }}
mcp_process: ${{ steps.detect.outputs.mcp_process }}
plugin: ${{ steps.detect.outputs.plugin }}
plugin_sdk_package: ${{ steps.detect.outputs.plugin_sdk_package }}
plugin_sdk_reply: ${{ steps.detect.outputs.plugin_sdk_reply }}
provider: ${{ steps.detect.outputs.provider }}
session_diagnostics: ${{ steps.detect.outputs.session_diagnostics }}
steps:
- name: Detect PR shard paths
id: detect
env:
EVENT_NAME: ${{ github.event_name }}
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
agent=false
channel=false
config=false
core_auth_secrets=false
gateway=false
memory=false
mcp_process=false
plugin=false
plugin_sdk_package=false
plugin_sdk_reply=false
provider=false
session_diagnostics=false
if [[ "${EVENT_NAME}" != "pull_request" ]]; then
agent=true
channel=true
config=true
core_auth_secrets=true
gateway=true
memory=true
mcp_process=true
plugin=true
plugin_sdk_package=true
plugin_sdk_reply=true
provider=true
session_diagnostics=true
else
while IFS= read -r file; do
case "${file}" in
.github/codeql/*|.github/workflows/codeql-critical-quality.yml)
agent=true
channel=true
config=true
core_auth_secrets=true
gateway=true
memory=true
mcp_process=true
plugin=true
plugin_sdk_package=true
plugin_sdk_reply=true
provider=true
session_diagnostics=true
;;
src/acp/control-plane/*|src/agents/cli-runner/*|src/agents/command/*|src/agents/pi-embedded-runner/*|src/agents/tools/*|src/agents/*completion*.ts|src/agents/*transport*.ts|src/agents/model-*.ts|src/agents/openclaw-tools*.ts|src/agents/provider-*.ts|src/agents/session*.ts|src/agents/tool-call*.ts|src/auto-reply/reply/agent-runner*.ts|src/auto-reply/reply/commands*.ts|src/auto-reply/reply/directive-handling*.ts|src/auto-reply/reply/dispatch-*.ts|src/auto-reply/reply/get-reply-run*.ts|src/auto-reply/reply/provider-dispatcher*.ts|src/auto-reply/reply/queue*.ts|src/auto-reply/reply/reply-run-registry*.ts|src/auto-reply/reply/session*.ts)
agent=true
;;
src/auto-reply/reply/post-compaction-context.ts|src/auto-reply/reply/queue/*|src/auto-reply/reply/startup-context.ts|src/commands/doctor-session-*.ts|src/commands/session-store-targets.ts|src/commands/sessions*.ts|src/infra/diagnostic-*.ts|src/infra/diagnostics-timeline.ts|src/infra/session-delivery-queue*.ts|src/logging/diagnostic*.ts)
session_diagnostics=true
;;
extensions/bluebubbles/src/*|extensions/discord/src/*|extensions/feishu/src/*|extensions/googlechat/src/*|extensions/imessage/src/*|extensions/irc/src/*|extensions/line/src/*|extensions/matrix/src/*|extensions/mattermost/src/*|extensions/msteams/src/*|extensions/nextcloud-talk/src/*|extensions/nostr/src/*|extensions/qa-channel/src/*|extensions/qqbot/src/*|extensions/signal/src/*|extensions/slack/src/*|extensions/synology-chat/src/*|extensions/telegram/src/*|extensions/tlon/src/*|extensions/twitch/src/*|extensions/whatsapp/src/*|extensions/zalo/src/*|extensions/zalouser/src/*|src/channels/*)
channel=true
;;
src/config/*)
config=true
;;
src/gateway/protocol/*secret*.ts|src/gateway/server-methods/secrets*.ts)
core_auth_secrets=true
gateway=true
;;
src/agents/*auth*.ts|src/agents/auth-health*.ts|src/agents/auth-profiles|src/agents/auth-profiles/*|src/agents/bash-tools.exec-host-shared.ts|src/agents/sandbox|src/agents/sandbox.ts|src/agents/sandbox-*.ts|src/agents/sandbox/*|src/cron/service/jobs.ts|src/cron/stagger.ts|src/gateway/*auth*.ts|src/gateway/*secret*.ts|src/gateway/resolve-configured-secret-input-string*.ts|src/gateway/security-path*.ts|src/infra/secret-file*.ts|src/secrets/*|src/security/*)
core_auth_secrets=true
;;
src/gateway/method-scopes.ts|src/gateway/protocol/*|src/gateway/server-methods/*|src/gateway/server-methods.ts|src/gateway/server-methods-list.ts)
gateway=true
;;
packages/memory-host-sdk/*|src/commands/doctor-cron-dreaming-payload-migration.ts|src/commands/doctor-memory-search.ts|src/gateway/server-startup-memory.ts|src/memory/*|src/memory-host-sdk/*)
memory=true
;;
src/infra/outbound/base-session-key.ts|src/infra/outbound/delivery-queue*.ts|src/infra/outbound/outbound-session.ts|src/infra/outbound/session-binding*.ts|src/infra/outbound/session-context.ts|src/infra/outbound/targets-session.ts)
mcp_process=true
session_diagnostics=true
;;
src/infra/outbound/*|src/mcp/*|src/process/*)
mcp_process=true
;;
src/plugin-sdk/inbound-envelope.ts|src/plugin-sdk/inbound-reply-dispatch.ts|src/plugin-sdk/reply-*.ts|src/plugin-sdk/channel-reply-*.ts|src/plugin-sdk/delivery-queue-runtime.ts|src/plugin-sdk/outbound-runtime.ts|src/plugin-sdk/outbound-send-deps.ts|src/plugin-sdk/model-session-runtime.ts|src/plugin-sdk/session-*.ts|src/plugin-sdk/thread-bindings-runtime.ts|src/plugin-sdk/thread-bindings-session-runtime.ts|src/plugin-sdk/conversation-binding-runtime.ts)
plugin=true
plugin_sdk_package=true
plugin_sdk_reply=true
;;
src/plugin-sdk/memory-*.ts|src/plugin-sdk/memory-core-host-*.ts)
memory=true
plugin=true
plugin_sdk_package=true
;;
src/plugin-sdk/*)
plugin=true
plugin_sdk_package=true
;;
src/plugins/provider-contract-public-artifacts.ts|src/plugins/provider-public-artifacts.ts|src/plugins/web-provider-public-artifacts*.ts)
plugin=true
provider=true
;;
src/plugins/memory-embedding-provider*.ts|src/plugins/memory-embedding-providers*.ts)
memory=true
provider=true
;;
src/plugins/memory-*.ts)
memory=true
;;
src/model-catalog/*|src/plugins/*provider*.ts|src/plugins/capability-provider-runtime.ts|src/plugins/compaction-provider.ts|src/plugins/memory-embedding-provider*.ts|src/plugins/memory-embedding-providers*.ts|src/plugins/migration-provider-runtime.ts|src/plugins/synthetic-auth.runtime.ts|src/plugins/web-fetch-providers*.ts|src/plugins/web-search-providers*.ts)
provider=true
;;
src/plugins/activation-planner.ts|src/plugins/api-builder.ts|src/plugins/bundled-*.ts|src/plugins/captured-registration.ts|src/plugins/config-*.ts|src/plugins/discovery.ts|src/plugins/effective-plugin-ids.ts|src/plugins/externalized-bundled-plugins.ts|src/plugins/installed-plugin-index*.ts|src/plugins/loader*.ts|src/plugins/manifest*.ts|src/plugins/module-export.ts|src/plugins/package-entrypoints.ts|src/plugins/plugin-registry*.ts|src/plugins/public-surface*.ts|src/plugins/registry.ts|src/plugins/registry-types.ts|src/plugins/runtime|src/plugins/runtime/*|src/plugins/runtime-state.ts|src/plugins/runtime.ts|src/plugins/sdk-alias.ts|src/plugins/source-loader.ts|src/plugins/types.ts|src/plugins/validation-diagnostics.ts)
plugin=true
;;
packages/plugin-package-contract/*|packages/plugin-sdk/*)
plugin_sdk_package=true
;;
esac
done < <(gh api --paginate "repos/${REPOSITORY}/pulls/${PR_NUMBER}/files" --jq '.[].filename')
fi
{
echo "agent=${agent}"
echo "channel=${channel}"
echo "config=${config}"
echo "core_auth_secrets=${core_auth_secrets}"
echo "gateway=${gateway}"
echo "memory=${memory}"
echo "mcp_process=${mcp_process}"
echo "plugin=${plugin}"
echo "plugin_sdk_package=${plugin_sdk_package}"
echo "plugin_sdk_reply=${plugin_sdk_reply}"
echo "provider=${provider}"
echo "session_diagnostics=${session_diagnostics}"
} >> "${GITHUB_OUTPUT}"
core-auth-secrets:
name: Critical Quality (core-auth-secrets)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.core_auth_secrets == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'core-auth-secrets') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
@@ -32,9 +314,306 @@ jobs:
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-javascript-typescript-critical-quality.yml
config-file: ./.github/codeql/codeql-core-auth-secrets-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/javascript-typescript"
category: "/codeql-critical-quality/core-auth-secrets"
config-boundary:
name: Critical Quality (config-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.config == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'config-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-config-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/config-boundary"
gateway-runtime-boundary:
name: Critical Quality (gateway-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.gateway == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'gateway-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-gateway-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/gateway-runtime-boundary"
channel-runtime-boundary:
name: Critical Quality (channel-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.channel == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'channel-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-channel-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/channel-runtime-boundary"
agent-runtime-boundary:
name: Critical Quality (agent-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.agent == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'agent-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-agent-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/agent-runtime-boundary"
mcp-process-runtime-boundary:
name: Critical Quality (mcp-process-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.mcp_process == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'mcp-process-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-mcp-process-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/mcp-process-runtime-boundary"
memory-runtime-boundary:
name: Critical Quality (memory-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.memory == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'memory-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-memory-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/memory-runtime-boundary"
session-diagnostics-boundary:
name: Critical Quality (session-diagnostics-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.session_diagnostics == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'session-diagnostics-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-session-diagnostics-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/session-diagnostics-boundary"
plugin-sdk-reply-runtime:
name: Critical Quality (plugin-sdk-reply-runtime)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.plugin_sdk_reply == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'plugin-sdk-reply-runtime') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-plugin-sdk-reply-runtime-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/plugin-sdk-reply-runtime"
provider-runtime-boundary:
name: Critical Quality (provider-runtime-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.provider == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'provider-runtime-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-provider-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/provider-runtime-boundary"
ui-control-plane:
name: Critical Quality (ui-control-plane)
if: ${{ github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || inputs.profile == 'all') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-ui-control-plane-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/ui-control-plane"
web-media-runtime-boundary:
name: Critical Quality (web-media-runtime-boundary)
if: ${{ github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || inputs.profile == 'all') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-web-media-runtime-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/web-media-runtime-boundary"
plugin-boundary:
name: Critical Quality (plugin-boundary)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.plugin == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'plugin-boundary') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-plugin-boundary-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/plugin-boundary"
plugin-sdk-package-contract:
name: Critical Quality (plugin-sdk-package-contract)
needs: quality-shards
if: ${{ needs.quality-shards.outputs.plugin_sdk_package == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name == 'pull_request' || github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'plugin-sdk-package-contract') }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-plugin-sdk-package-contract-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/plugin-sdk-package-contract"

View File

@@ -0,0 +1,89 @@
name: CodeQL macOS Critical Security
on:
workflow_dispatch:
schedule:
- cron: "0 8 * * 1"
concurrency:
group: codeql-macos-critical-security-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.sha }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
permissions:
actions: read
contents: read
security-events: write
jobs:
macos:
name: Critical Security (macOS)
runs-on: blacksmith-6vcpu-macos-latest
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Select Xcode
run: |
sudo xcode-select -s /Applications/Xcode_26.1.app
xcodebuild -version
swift --version
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: swift
build-mode: manual
config-file: ./.github/codeql/codeql-macos-critical-security.yml
- name: Build macOS for CodeQL
run: swift build --package-path apps/macos --product OpenClaw
- name: Analyze
id: analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
output: sarif-results
upload: failure-only
category: "/codeql-critical-security/macos"
- name: Remove dependency build results
env:
SARIF_OUTPUT: sarif-results
run: |
set -euo pipefail
shopt -s nullglob
if [ ! -d "$SARIF_OUTPUT" ]; then
echo "SARIF output directory not found: $SARIF_OUTPUT" >&2
exit 1
fi
mkdir -p sarif-results-filtered
files=("$SARIF_OUTPUT"/*.sarif)
if [ "${#files[@]}" -eq 0 ]; then
echo "No SARIF files found in $SARIF_OUTPUT" >&2
exit 1
fi
for file in "${files[@]}"; do
jq '
def in_dependency_build:
((.locations // []) | length > 0)
and all(.locations[]; (.physicalLocation.artifactLocation.uri? // "") | test("^apps/macos/\\.build/"));
.runs |= map(.results = ((.results // []) | map(select(in_dependency_build | not))))
' "$file" > "sarif-results-filtered/$(basename "$file")"
done
- name: Upload filtered SARIF
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
sarif_file: sarif-results-filtered
category: "/codeql-critical-security/macos"

View File

@@ -11,14 +11,20 @@ on:
options:
- all
- security
- android-security
- macos-security
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- ".github/actions/**"
- ".github/codeql/**"
- ".github/workflows/**"
- "packages/**"
- "src/**"
schedule:
- cron: "0 6 * * *"
concurrency:
group: codeql-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.sha }}
cancel-in-progress: false
group: codeql-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -29,9 +35,9 @@ permissions:
security-events: write
jobs:
critical-security:
name: Critical Security (${{ matrix.language }})
if: ${{ github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'security' }}
security-high:
name: Security High (${{ matrix.category }})
if: ${{ (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (github.event_name != 'workflow_dispatch' || inputs.profile == 'all' || inputs.profile == 'security') }}
runs-on: ${{ matrix.runs_on }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
@@ -39,10 +45,32 @@ jobs:
matrix:
include:
- language: javascript-typescript
category: core-auth-secrets
runs_on: blacksmith-8vcpu-ubuntu-2404
timeout_minutes: 25
config_file: ./.github/codeql/codeql-javascript-typescript-critical-security.yml
config_file: ./.github/codeql/codeql-core-auth-secrets-critical-security.yml
- language: javascript-typescript
category: channel-runtime-boundary
runs_on: blacksmith-8vcpu-ubuntu-2404
timeout_minutes: 25
config_file: ./.github/codeql/codeql-channel-runtime-boundary-critical-security.yml
- language: javascript-typescript
category: network-ssrf-boundary
runs_on: blacksmith-4vcpu-ubuntu-2404
timeout_minutes: 25
config_file: ./.github/codeql/codeql-network-ssrf-boundary-critical-security.yml
- language: javascript-typescript
category: mcp-process-tool-boundary
runs_on: blacksmith-4vcpu-ubuntu-2404
timeout_minutes: 25
config_file: ./.github/codeql/codeql-mcp-process-tool-boundary-critical-security.yml
- language: javascript-typescript
category: plugin-trust-boundary
runs_on: blacksmith-4vcpu-ubuntu-2404
timeout_minutes: 25
config_file: ./.github/codeql/codeql-plugin-trust-boundary-critical-security.yml
- language: actions
category: actions
runs_on: blacksmith-8vcpu-ubuntu-2404
timeout_minutes: 10
config_file: ./.github/codeql/codeql-actions-critical-security.yml
@@ -61,108 +89,4 @@ jobs:
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-security/${{ matrix.language }}"
android-security:
name: Critical Security (android)
if: ${{ github.event_name == 'workflow_dispatch' && inputs.profile == 'android-security' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Setup Java
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: temurin
java-version: "21"
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: java-kotlin
build-mode: manual
config-file: ./.github/codeql/codeql-android-critical-security.yml
- name: Build Android for CodeQL
working-directory: apps/android
run: ./gradlew --no-daemon :app:assemblePlayDebug
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-security/android"
macos-security:
name: Critical Security (macOS)
if: ${{ github.event_name == 'workflow_dispatch' && inputs.profile == 'macos-security' }}
runs-on: blacksmith-6vcpu-macos-latest
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Select Xcode
run: |
sudo xcode-select -s /Applications/Xcode_26.1.app
xcodebuild -version
swift --version
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: swift
build-mode: manual
config-file: ./.github/codeql/codeql-macos-critical-security.yml
- name: Build macOS for CodeQL
run: swift build --package-path apps/macos --product OpenClaw
- name: Analyze
id: analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
output: sarif-results
upload: failure-only
category: "/codeql-critical-security/macos"
- name: Remove dependency build results
env:
SARIF_OUTPUT: sarif-results
run: |
set -euo pipefail
shopt -s nullglob
if [ ! -d "$SARIF_OUTPUT" ]; then
echo "SARIF output directory not found: $SARIF_OUTPUT" >&2
exit 1
fi
mkdir -p sarif-results-filtered
files=("$SARIF_OUTPUT"/*.sarif)
if [ "${#files[@]}" -eq 0 ]; then
echo "No SARIF files found in $SARIF_OUTPUT" >&2
exit 1
fi
for file in "${files[@]}"; do
jq '
def in_dependency_build:
((.locations // []) | length > 0)
and all(.locations[]; (.physicalLocation.artifactLocation.uri? // "") | test("^apps/macos/\\.build/"));
.runs |= map(.results = ((.results // []) | map(select(in_dependency_build | not))))
' "$file" > "sarif-results-filtered/$(basename "$file")"
done
- name: Upload filtered SARIF
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
sarif_file: sarif-results-filtered
category: "/codeql-critical-security/macos"
category: "/codeql-security-high/${{ matrix.category }}"

View File

@@ -49,7 +49,7 @@ jobs:
run: |
set -euo pipefail
all_locales_json='["zh-CN","zh-TW","pt-BR","de","es","ja-JP","ko","fr","tr","uk","id","pl","th"]'
all_locales_json='["zh-CN","zh-TW","pt-BR","de","es","ja-JP","ko","fr","ar","it","tr","uk","id","pl","th","vi","nl","fa"]'
if [ "$EVENT_NAME" != "push" ]; then
echo "has_locales=true" >> "$GITHUB_OUTPUT"

View File

@@ -149,7 +149,7 @@ jobs:
- name: Run Codex docs agent
if: steps.gate.outputs.run_agent == 'true'
uses: openai/codex-action@v1
uses: openai/codex-action@5c3f4ccdb2b8790f73d6b21751ac00e602aa0c02
env:
DOCS_AGENT_BASE_SHA: ${{ steps.gate.outputs.review_base_sha }}
DOCS_AGENT_HEAD_SHA: ${{ steps.gate.outputs.review_head_sha }}

View File

@@ -20,6 +20,7 @@ jobs:
set -euo pipefail
for event_type in \
translate-zh-cn-release \
translate-zh-tw-release \
translate-ja-jp-release \
translate-es-release \
translate-pt-br-release \
@@ -28,6 +29,9 @@ jobs:
translate-fr-release \
translate-ar-release \
translate-it-release \
translate-vi-release \
translate-nl-release \
translate-fa-release \
translate-tr-release \
translate-uk-release \
translate-id-release \

View File

@@ -43,6 +43,7 @@ on:
options:
- all
- ci
- plugin-prerelease
- release-checks
- install-smoke
- cross-os
@@ -52,6 +53,11 @@ on:
- qa-parity
- qa-live
- npm-telegram
live_suite_filter:
description: Optional exact live suite id for focused live/E2E reruns; blank runs all selected live suites
required: false
default: ""
type: string
npm_telegram_package_spec:
description: Optional published package spec for the post-publish Telegram E2E lane
required: false
@@ -81,7 +87,7 @@ permissions:
contents: read
concurrency:
group: full-release-validation-${{ inputs.ref }}
group: full-release-validation-${{ inputs.ref }}-${{ inputs.rerun_group }}
cancel-in-progress: false
env:
@@ -122,6 +128,7 @@ jobs:
NPM_TELEGRAM_PACKAGE_SPEC: ${{ inputs.npm_telegram_package_spec }}
EVIDENCE_PACKAGE_SPEC: ${{ inputs.evidence_package_spec }}
RERUN_GROUP: ${{ inputs.rerun_group }}
LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
run: |
{
echo "## Full release validation"
@@ -130,12 +137,20 @@ jobs:
echo "- Target SHA: \`${TARGET_SHA}\`"
echo "- Child workflow ref: \`${CHILD_WORKFLOW_REF}\`"
echo "- Rerun group: \`${RERUN_GROUP}\`"
if [[ -n "${LIVE_SUITE_FILTER// }" ]]; then
echo "- Live suite filter: \`${LIVE_SUITE_FILTER}\`"
fi
if [[ "$RERUN_GROUP" == "all" || "$RERUN_GROUP" == "ci" ]]; then
echo "- Normal CI: \`CI\` with \`target_ref=${TARGET_SHA}\`"
else
echo "- Normal CI: skipped by rerun group"
fi
if [[ "$RERUN_GROUP" != "ci" && "$RERUN_GROUP" != "npm-telegram" ]]; then
if [[ "$RERUN_GROUP" == "all" || "$RERUN_GROUP" == "plugin-prerelease" ]]; then
echo "- Plugin prerelease: \`Plugin Prerelease\` with \`target_ref=${TARGET_SHA}\`"
else
echo "- Plugin prerelease: skipped by rerun group"
fi
if [[ "$RERUN_GROUP" == "all" || "$RERUN_GROUP" == "release-checks" || "$RERUN_GROUP" == "install-smoke" || "$RERUN_GROUP" == "cross-os" || "$RERUN_GROUP" == "live-e2e" || "$RERUN_GROUP" == "package" || "$RERUN_GROUP" == "qa" || "$RERUN_GROUP" == "qa-parity" || "$RERUN_GROUP" == "qa-live" ]]; then
echo "- Release/live/Docker/package/QA: \`OpenClaw Release Checks\`"
else
echo "- Release/live/Docker/package/QA: skipped by rerun group"
@@ -214,6 +229,7 @@ jobs:
fi
sleep 30
done
trap - EXIT INT TERM
conclusion="$(gh run view "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view "$run_id" --json url --jq '.url')"
@@ -232,30 +248,26 @@ jobs:
echo "- Target SHA: \`${TARGET_SHA}\`"
} >> "$GITHUB_STEP_SUMMARY"
dispatch_and_wait ci.yml -f target_ref="$TARGET_SHA"
dispatch_and_wait ci.yml -f target_ref="$TARGET_SHA" -f include_android=true
release_checks:
name: Run release/live/Docker/QA validation
plugin_prerelease:
name: Run plugin prerelease validation
needs: [resolve_target]
if: contains(fromJSON('["all","release-checks","install-smoke","cross-os","live-e2e","package","qa","qa-parity","qa-live"]'), inputs.rerun_group)
if: contains(fromJSON('["all","plugin-prerelease"]'), inputs.rerun_group)
runs-on: ubuntu-24.04
timeout-minutes: 720
timeout-minutes: 300
outputs:
run_id: ${{ steps.dispatch.outputs.run_id }}
url: ${{ steps.dispatch.outputs.url }}
conclusion: ${{ steps.dispatch.outputs.conclusion }}
steps:
- name: Dispatch and monitor release checks
- name: Dispatch and monitor plugin prerelease
id: dispatch
env:
GH_TOKEN: ${{ github.token }}
TARGET_REF: ${{ inputs.ref }}
TARGET_SHA: ${{ needs.resolve_target.outputs.sha }}
CHILD_WORKFLOW_REF: ${{ github.ref_name }}
PROVIDER: ${{ inputs.provider }}
MODE: ${{ inputs.mode }}
RELEASE_PROFILE: ${{ inputs.release_profile }}
RERUN_GROUP: ${{ inputs.rerun_group }}
run: |
set -euo pipefail
@@ -302,6 +314,97 @@ jobs:
fi
sleep 30
done
trap - EXIT INT TERM
conclusion="$(gh run view "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view "$run_id" --json url --jq '.url')"
echo "${workflow} finished with ${conclusion}: ${url}"
echo "url=${url}" >> "$GITHUB_OUTPUT"
echo "conclusion=${conclusion}" >> "$GITHUB_OUTPUT"
if [[ "$conclusion" != "success" ]]; then
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
fi
}
{
echo "### Plugin prerelease"
echo
echo "- Target ref: \`${TARGET_REF}\`"
echo "- Target SHA: \`${TARGET_SHA}\`"
} >> "$GITHUB_STEP_SUMMARY"
dispatch_and_wait plugin-prerelease.yml -f target_ref="$TARGET_SHA" -f expected_sha="$TARGET_SHA" -f full_release_validation=true
release_checks:
name: Run release/live/Docker/QA validation
needs: [resolve_target]
if: contains(fromJSON('["all","release-checks","install-smoke","cross-os","live-e2e","package","qa","qa-parity","qa-live"]'), inputs.rerun_group)
runs-on: ubuntu-24.04
timeout-minutes: 720
outputs:
run_id: ${{ steps.dispatch.outputs.run_id }}
url: ${{ steps.dispatch.outputs.url }}
conclusion: ${{ steps.dispatch.outputs.conclusion }}
steps:
- name: Dispatch and monitor release checks
id: dispatch
env:
GH_TOKEN: ${{ github.token }}
TARGET_REF: ${{ inputs.ref }}
TARGET_SHA: ${{ needs.resolve_target.outputs.sha }}
CHILD_WORKFLOW_REF: ${{ github.ref_name }}
PROVIDER: ${{ inputs.provider }}
MODE: ${{ inputs.mode }}
RELEASE_PROFILE: ${{ inputs.release_profile }}
RERUN_GROUP: ${{ inputs.rerun_group }}
LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
run: |
set -euo pipefail
dispatch_and_wait() {
local workflow="$1"
shift
local before_json dispatch_output run_id status conclusion url
before_json="$(gh run list --workflow "$workflow" --event workflow_dispatch --limit 100 --json databaseId --jq '[.[].databaseId]')"
dispatch_output="$(gh workflow run "$workflow" --ref "$CHILD_WORKFLOW_REF" "$@" 2>&1)"
printf '%s\n' "$dispatch_output"
run_id="$(
printf '%s\n' "$dispatch_output" |
sed -nE 's#.*actions/runs/([0-9]+).*#\1#p' |
tail -n 1
)"
if [[ -z "$run_id" ]]; then
for _ in $(seq 1 60); do
run_id="$(
BEFORE_IDS="$before_json" gh run list --workflow "$workflow" --event workflow_dispatch --limit 50 --json databaseId,createdAt \
--jq 'map(select(.databaseId as $id | (env.BEFORE_IDS | fromjson | index($id) | not))) | sort_by(.createdAt) | reverse | .[0].databaseId // empty'
)"
if [[ -n "$run_id" ]]; then
break
fi
sleep 5
done
fi
if [[ -z "${run_id:-}" ]]; then
echo "Could not find dispatched run for ${workflow}." >&2
exit 1
fi
echo "Dispatched ${workflow}: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${run_id}"
echo "run_id=${run_id}" >> "$GITHUB_OUTPUT"
while true; do
status="$(gh run view "$run_id" --json status --jq '.status')"
if [[ "$status" == "completed" ]]; then
break
fi
sleep 30
done
trap - EXIT INT TERM
conclusion="$(gh run view "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view "$run_id" --json url --jq '.url')"
@@ -322,6 +425,9 @@ jobs:
echo "- Cross-OS mode: \`${MODE}\`"
echo "- Release profile: \`${RELEASE_PROFILE}\`"
echo "- Rerun group: \`${RERUN_GROUP}\`"
if [[ -n "${LIVE_SUITE_FILTER// }" ]]; then
echo "- Live suite filter: \`${LIVE_SUITE_FILTER}\`"
fi
} >> "$GITHUB_STEP_SUMMARY"
child_rerun_group="$RERUN_GROUP"
@@ -329,13 +435,19 @@ jobs:
child_rerun_group=all
fi
dispatch_and_wait openclaw-release-checks.yml \
-f ref="$TARGET_REF" \
-f expected_sha="$TARGET_SHA" \
-f provider="$PROVIDER" \
-f mode="$MODE" \
-f release_profile="$RELEASE_PROFILE" \
args=(
-f ref="$TARGET_SHA"
-f expected_sha="$TARGET_SHA"
-f provider="$PROVIDER"
-f mode="$MODE"
-f release_profile="$RELEASE_PROFILE"
-f rerun_group="$child_rerun_group"
)
if [[ -n "${LIVE_SUITE_FILTER// }" ]]; then
args+=(-f live_suite_filter="$LIVE_SUITE_FILTER")
fi
dispatch_and_wait openclaw-release-checks.yml "${args[@]}"
npm_telegram:
name: Run post-publish Telegram E2E
@@ -396,6 +508,7 @@ jobs:
fi
sleep 30
done
trap - EXIT INT TERM
conclusion="$(gh run view "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view "$run_id" --json url --jq '.url')"
@@ -408,7 +521,7 @@ jobs:
summary:
name: Verify full validation
needs: [normal_ci, release_checks, npm_telegram]
needs: [normal_ci, plugin_prerelease, release_checks, npm_telegram]
if: always()
runs-on: ubuntu-24.04
timeout-minutes: 5
@@ -473,9 +586,11 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
NORMAL_CI_RUN_ID: ${{ needs.normal_ci.outputs.run_id }}
PLUGIN_PRERELEASE_RUN_ID: ${{ needs.plugin_prerelease.outputs.run_id }}
RELEASE_CHECKS_RUN_ID: ${{ needs.release_checks.outputs.run_id }}
NPM_TELEGRAM_RUN_ID: ${{ needs.npm_telegram.outputs.run_id }}
NORMAL_CI_RESULT: ${{ needs.normal_ci.result }}
PLUGIN_PRERELEASE_RESULT: ${{ needs.plugin_prerelease.result }}
RELEASE_CHECKS_RESULT: ${{ needs.release_checks.result }}
NPM_TELEGRAM_RESULT: ${{ needs.npm_telegram.result }}
run: |
@@ -495,20 +610,64 @@ jobs:
return 1
fi
local status conclusion url attempt
status="$(gh run view "$run_id" --json status --jq '.status')"
conclusion="$(gh run view "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view "$run_id" --json url --jq '.url')"
attempt="$(gh run view "$run_id" --json attempt --jq '.attempt')"
local run_json status conclusion url attempt
run_json="$(gh run view "$run_id" --json status,conclusion,url,attempt,jobs)"
status="$(jq -r '.status' <<< "$run_json")"
conclusion="$(jq -r '.conclusion' <<< "$run_json")"
url="$(jq -r '.url' <<< "$run_json")"
attempt="$(jq -r '.attempt' <<< "$run_json")"
echo "${label}: ${status}/${conclusion} attempt ${attempt}: ${url}"
if [[ "$status" != "completed" || "$conclusion" != "success" ]]; then
echo "::error::${label} child run ended with ${status}/${conclusion}: ${url}"
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, status, conclusion, url}' || true
jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, status, conclusion, url}' <<< "$run_json" || true
return 1
fi
}
append_child_overview() {
{
echo
echo "### Child workflow overview"
echo
echo "| Child | Result | Minutes | Run |"
echo "| --- | --- | ---: | --- |"
} >> "$GITHUB_STEP_SUMMARY"
append_child_row() {
local label="$1"
local run_id="$2"
local result="$3"
if [[ -z "${run_id// }" ]]; then
echo "| \`${label}\` | \`${result}\` | | skipped |" >> "$GITHUB_STEP_SUMMARY"
return 0
fi
local run_json row
run_json="$(gh run view "$run_id" --json status,conclusion,url,createdAt,updatedAt)"
row="$(
jq -r --arg label "$label" '
def ts: fromdateiso8601;
. as $run |
($run.createdAt // "") as $created |
($run.updatedAt // "") as $updated |
(if ($created | length) > 0 and ($updated | length) > 0
then (((($updated | ts) - ($created | ts)) / 60) * 10 | round / 10 | tostring)
else ""
end) as $minutes |
"| `" + $label + "` | `" + ($run.status // "") + "/" + ($run.conclusion // "") + "` | " + $minutes + " | [run](" + ($run.url // "") + ") |"
' <<< "$run_json"
)"
echo "$row" >> "$GITHUB_STEP_SUMMARY"
}
append_child_row "normal_ci" "$NORMAL_CI_RUN_ID" "$NORMAL_CI_RESULT"
append_child_row "plugin_prerelease" "$PLUGIN_PRERELEASE_RUN_ID" "$PLUGIN_PRERELEASE_RESULT"
append_child_row "release_checks" "$RELEASE_CHECKS_RUN_ID" "$RELEASE_CHECKS_RESULT"
append_child_row "npm_telegram" "$NPM_TELEGRAM_RUN_ID" "$NPM_TELEGRAM_RESULT"
}
summarize_child_timing() {
local label="$1"
local run_id="$2"
@@ -534,17 +693,46 @@ jobs:
| map("| `" + (.name | gsub("\\|"; "\\|")) + "` | `" + ((.conclusion // "") | tostring) + "` | " + (.durationMin | tostring) + " |")
| .[])
' || echo "_Unable to summarize jobs for run ${run_id}._"
echo
echo "### Longest queues: ${label}"
echo
gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${run_id}/jobs?per_page=100" --jq ".jobs[] | @json" | jq -sr '
def ts: fromdateiso8601;
"| Job | Result | Queue minutes | Run minutes |",
"| --- | --- | ---: | ---: |",
([.[]
| select(.created_at != null and .started_at != null)
| . + {
queueMin: ((((.started_at | ts) - (.created_at | ts)) / 60) * 10 | round / 10),
durationMin: (if .completed_at == null then null else ((((.completed_at | ts) - (.started_at | ts)) / 60) * 10 | round / 10) end)
}
| select(.queueMin > 0)
| {name, conclusion, queueMin, durationMin}]
| sort_by(.queueMin)
| reverse
| .[0:10]
| map("| `" + (.name | gsub("\\|"; "\\|")) + "` | `" + ((.conclusion // "") | tostring) + "` | " + (.queueMin | tostring) + " | " + ((.durationMin // "") | tostring) + " |")
| .[])
' || echo "_Unable to summarize queue times for run ${run_id}._"
} >> "$GITHUB_STEP_SUMMARY"
}
failed=0
append_child_overview
if [[ "$NORMAL_CI_RESULT" == "skipped" && -z "${NORMAL_CI_RUN_ID// }" ]]; then
check_child "normal_ci" "" 0 || failed=1
else
check_child "normal_ci" "$NORMAL_CI_RUN_ID" 1 || failed=1
fi
if [[ "$PLUGIN_PRERELEASE_RESULT" == "skipped" && -z "${PLUGIN_PRERELEASE_RUN_ID// }" ]]; then
check_child "plugin_prerelease" "" 0 || failed=1
else
check_child "plugin_prerelease" "$PLUGIN_PRERELEASE_RUN_ID" 1 || failed=1
fi
if [[ "$RELEASE_CHECKS_RESULT" == "skipped" && -z "${RELEASE_CHECKS_RUN_ID// }" ]]; then
check_child "release_checks" "" 0 || failed=1
else
@@ -558,6 +746,7 @@ jobs:
fi
summarize_child_timing "normal_ci" "$NORMAL_CI_RUN_ID"
summarize_child_timing "plugin_prerelease" "$PLUGIN_PRERELEASE_RUN_ID"
summarize_child_timing "release_checks" "$RELEASE_CHECKS_RUN_ID"
summarize_child_timing "npm_telegram" "$NPM_TELEGRAM_RUN_ID"

View File

@@ -34,10 +34,11 @@ on:
permissions:
contents: read
packages: write
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-manual-{1}', github.workflow, github.run_id) || format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: true
group: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && format('{0}-{1}-{2}', github.workflow, github.event_name, github.run_id) || format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: ${{ github.event_name != 'workflow_call' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -51,6 +52,8 @@ jobs:
run_fast_install_smoke: ${{ steps.manifest.outputs.run_fast_install_smoke }}
run_full_install_smoke: ${{ steps.manifest.outputs.run_full_install_smoke }}
run_bun_global_install_smoke: ${{ steps.manifest.outputs.run_bun_global_install_smoke }}
target_sha: ${{ steps.manifest.outputs.target_sha }}
dockerfile_image: ${{ steps.manifest.outputs.dockerfile_image }}
steps:
- name: Checkout
uses: actions/checkout@v6
@@ -74,6 +77,9 @@ jobs:
run_full_install_smoke=true
run_bun_global_install_smoke=false
run_install_smoke=true
target_sha="$(git rev-parse HEAD)"
owner="$(printf '%s' "${GITHUB_REPOSITORY_OWNER:-openclaw}" | tr '[:upper:]' '[:lower:]')"
dockerfile_image="ghcr.io/${owner}/openclaw-dockerfile-smoke:${target_sha}"
if [ "$event_name" = "schedule" ]; then
run_bun_global_install_smoke=true
elif [ "$event_name" = "workflow_dispatch" ] || [ "$event_name" = "workflow_call" ]; then
@@ -87,6 +93,8 @@ jobs:
echo "run_fast_install_smoke=$run_fast_install_smoke"
echo "run_full_install_smoke=$run_full_install_smoke"
echo "run_bun_global_install_smoke=$run_bun_global_install_smoke"
echo "target_sha=$target_sha"
echo "dockerfile_image=$dockerfile_image"
} >> "$GITHUB_OUTPUT"
install-smoke-fast:
@@ -103,23 +111,23 @@ jobs:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
# Blacksmith's builder owns the Docker layer cache; keep smoke builds off
# explicit gha cache directives so local tags still load cleanly.
- name: Build root Dockerfile smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
context: .
file: ./Dockerfile
build-args: |
OPENCLAW_EXTENSIONS=matrix
tags: |
openclaw-dockerfile-smoke:local
openclaw-ext-smoke:local
load: true
push: false
provenance: false
max-cache-size-mb: 800000
# Keep release smoke builds bounded and log-producing. The Blacksmith
# build action can leave jobs in-progress without step logs when a remote
# builder stalls; an explicit buildx invocation fails closed instead.
- name: Build root Dockerfile smoke image
run: |
timeout 45m docker buildx build \
--progress=plain \
--load \
--build-arg OPENCLAW_EXTENSIONS=matrix \
-t openclaw-dockerfile-smoke:local \
-t openclaw-ext-smoke:local \
-f ./Dockerfile \
.
- name: Run root Dockerfile CLI smoke
run: |
@@ -196,10 +204,12 @@ jobs:
"
'
install-smoke:
root_dockerfile_image:
needs: [preflight]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
outputs:
image_ref: ${{ steps.image.outputs.image_ref }}
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
@@ -209,51 +219,127 @@ jobs:
with:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Check for existing root Dockerfile smoke image
id: existing
env:
IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }}
run: |
set -euo pipefail
if timeout 180s docker pull "$IMAGE_REF"; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Using existing root Dockerfile smoke image: \`$IMAGE_REF\`" >> "$GITHUB_STEP_SUMMARY"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "No existing root Dockerfile smoke image found for \`$IMAGE_REF\`; building it." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Set up Blacksmith Docker Builder
if: steps.existing.outputs.exists != 'true'
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
max-cache-size-mb: 800000
# Build once with the matrix extension and publish by target SHA. Use a
# direct buildx command so release jobs emit Docker progress and time out.
- name: Build and push root Dockerfile smoke image
if: steps.existing.outputs.exists != 'true'
env:
IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }}
run: |
timeout 45m docker buildx build \
--progress=plain \
--push \
--build-arg OPENCLAW_EXTENSIONS=matrix \
-t "$IMAGE_REF" \
-f ./Dockerfile \
.
- name: Record root image output
id: image
env:
IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }}
run: echo "image_ref=$IMAGE_REF" >> "$GITHUB_OUTPUT"
- name: Summarize root image
env:
IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }}
TARGET_SHA: ${{ needs.preflight.outputs.target_sha }}
run: |
{
echo "## Root Dockerfile smoke image"
echo
echo "- Target SHA: \`${TARGET_SHA}\`"
echo "- Image: \`${IMAGE_REF}\`"
echo "- Reused existing image: \`${{ steps.existing.outputs.exists }}\`"
} >> "$GITHUB_STEP_SUMMARY"
qr_package_install_smoke:
needs: [preflight]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
# Blacksmith's builder owns the Docker layer cache; keep smoke builds off
# explicit gha cache directives so local tags still load cleanly.
- name: Run QR package install smoke
env:
OPENCLAW_QR_SMOKE_FORCE_INSTALL: "1"
run: bash scripts/e2e/qr-import-docker.sh
# Build once with the matrix extension and tag both smoke names. This
# keeps the build-arg coverage without a second Blacksmith build action.
- name: Build root Dockerfile smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
root_dockerfile_smokes:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
context: .
file: ./Dockerfile
build-args: |
OPENCLAW_EXTENSIONS=matrix
tags: |
openclaw-dockerfile-smoke:local
openclaw-ext-smoke:local
load: true
push: false
provenance: false
ref: ${{ inputs.ref || github.ref }}
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Pull root Dockerfile smoke image
env:
IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }}
run: timeout 300s docker pull "$IMAGE_REF"
- name: Run root Dockerfile CLI smoke
env:
IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }}
run: |
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
docker run --rm --entrypoint sh "$IMAGE_REF" -lc 'which openclaw && openclaw --version'
- name: Run agents delete shared workspace Docker CLI smoke
env:
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }}
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh
- name: Run Docker gateway network e2e
env:
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }}
OPENCLAW_GATEWAY_NETWORK_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/gateway-network-docker.sh
- name: Smoke test Dockerfile with matrix extension build arg
env:
IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }}
run: |
docker run --rm --entrypoint sh openclaw-ext-smoke:local -lc '
docker run --rm --entrypoint sh "$IMAGE_REF" -lc '
which openclaw &&
openclaw --version &&
node -e "
@@ -296,39 +382,60 @@ jobs:
"
'
- name: Build installer smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
installer_smoke:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
context: ./scripts/docker
file: ./scripts/docker/install-sh-smoke/Dockerfile
tags: openclaw-install-smoke:local
load: true
push: false
provenance: false
ref: ${{ inputs.ref || github.ref }}
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Pull root Dockerfile smoke image
env:
IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }}
run: timeout 300s docker pull "$IMAGE_REF"
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
max-cache-size-mb: 800000
- name: Build installer smoke image
run: |
timeout 20m docker buildx build \
--progress=plain \
--load \
-t openclaw-install-smoke:local \
-f ./scripts/docker/install-sh-smoke/Dockerfile \
./scripts/docker
- name: Build installer non-root image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
context: ./scripts/docker
file: ./scripts/docker/install-sh-nonroot/Dockerfile
tags: openclaw-install-nonroot:local
load: true
push: false
provenance: false
run: |
timeout 20m docker buildx build \
--progress=plain \
--load \
-t openclaw-install-nonroot:local \
-f ./scripts/docker/install-sh-nonroot/Dockerfile \
./scripts/docker
- name: Setup Node environment for installer smoke
uses: ./.github/actions/setup-node-env
with:
install-bun: ${{ needs.preflight.outputs.run_bun_global_install_smoke }}
install-bun: "false"
install-deps: "true"
- name: Run Bun global install image-provider smoke
if: needs.preflight.outputs.run_bun_global_install_smoke == 'true'
env:
OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD: "0"
run: bash scripts/e2e/bun-global-install-smoke.sh
- name: Run installer docker tests
env:
OPENCLAW_INSTALL_URL: https://openclaw.ai/install.sh
@@ -341,15 +448,49 @@ jobs:
OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL: "1"
OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS: "1"
OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE: ${{ inputs.update_baseline_version || 'latest' }}
OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }}
OPENCLAW_INSTALL_SMOKE_UPDATE_SKIP_LOCAL_BUILD: "1"
run: bash scripts/test-install-sh-docker.sh
bun_global_install_smoke:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true' && needs.preflight.outputs.run_bun_global_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Pull root Dockerfile smoke image
env:
IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }}
run: timeout 300s docker pull "$IMAGE_REF"
- name: Setup Node environment for Bun smoke
uses: ./.github/actions/setup-node-env
with:
install-bun: "true"
install-deps: "true"
- name: Run Bun global install image-provider smoke
env:
OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }}
OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD: "0"
run: bash scripts/e2e/bun-global-install-smoke.sh
docker-e2e-fast:
needs: [preflight]
if: needs.preflight.outputs.run_fast_install_smoke == 'true' || needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 8
timeout-minutes: 12
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
@@ -360,7 +501,9 @@ jobs:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
max-cache-size-mb: 800000
- name: Setup Node environment for package smoke
uses: ./.github/actions/setup-node-env
@@ -372,4 +515,4 @@ jobs:
env:
OPENCLAW_BUNDLED_CHANNEL_DEPS_E2E_IMAGE: openclaw-bundled-channel-fast:local
OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT: 90s
run: timeout 240s pnpm test:docker:bundled-channel-deps:fast
run: timeout 480s pnpm test:docker:bundled-channel-deps:fast

View File

@@ -278,6 +278,7 @@ jobs:
const labelColor = "B60205";
const labelDescription = `Author has more than ${activePrLimit} active PRs in this repo`;
const authorLogin = pullRequest.user?.login;
const headRefName = pullRequest.head?.ref ?? "";
if (!authorLogin) {
return;
}
@@ -374,7 +375,12 @@ jobs:
return false;
};
if (await isPrivilegedAuthor()) {
const automationPrHeadPrefixes = ["clawsweeper/", "clownfish/"];
const isAutomationPullRequest =
typeof headRefName === "string" &&
automationPrHeadPrefixes.some((prefix) => headRefName.startsWith(prefix));
if ((await isPrivilegedAuthor()) || isAutomationPullRequest) {
if (labelNames.has(activePrLimitLabel)) {
try {
await github.rest.issues.removeLabel({

View File

@@ -0,0 +1,54 @@
name: Live Media Runner Image
on:
workflow_dispatch:
push:
branches: [main]
paths:
- ".github/images/live-media-runner/Dockerfile"
- ".github/workflows/live-media-runner-image.yml"
permissions:
contents: read
packages: write
concurrency:
group: live-media-runner-image-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
build:
name: Build live media runner image
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Login to GHCR
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
max-cache-size-mb: 800000
- name: Build and push live media runner image
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
with:
context: .github/images/live-media-runner
file: .github/images/live-media-runner/Dockerfile
platforms: linux/amd64
tags: |
ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04
ghcr.io/openclaw/openclaw-live-media-runner:${{ github.sha }}
sbom: true
provenance: mode=max
push: true

View File

@@ -0,0 +1,99 @@
name: Maintainer Command Reactions
on:
issue_comment:
types: [created, edited]
permissions: {}
concurrency:
group: maintainer-command-reactions-${{ github.event.comment.id }}
cancel-in-progress: true
jobs:
react:
if: ${{ !endsWith(github.actor, '[bot]') }}
runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write
env:
MAINTAINER_COMMAND_REACTIONS: ${{ vars.MAINTAINER_COMMAND_REACTIONS || '/autoclose,/clawsweeper autoclose,/clawsweeper automerge,/merge,/land,/landpr' }}
steps:
- name: React to maintainer slash command
uses: actions/github-script@v9
with:
script: |
const comment = context.payload.comment;
const issue = context.payload.issue;
const commands = (process.env.MAINTAINER_COMMAND_REACTIONS || "")
.split(",")
.map((command) => command.trim())
.filter(Boolean);
const commandLine = String(comment.body || "")
.split(/\r?\n/)
.map((line) => line.trim())
.find((line) => commands.some((command) => line === command || line.startsWith(`${command} `)));
if (!commandLine) {
core.info(`Skipping comment ${comment.id}; no tracked maintainer command found.`);
return;
}
const isAutocloseCommand =
commandLine === "/autoclose" ||
commandLine.startsWith("/autoclose ") ||
commandLine === "/clawsweeper autoclose" ||
commandLine.startsWith("/clawsweeper autoclose ");
if (!issue.pull_request && !isAutocloseCommand) {
core.info("Skipping non-autoclose command reaction because the comment is not on a pull request.");
return;
}
const maintainerPermissions = new Set(["admin", "maintain", "write"]);
let permission = "none";
try {
const result = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: comment.user.login,
});
permission = String(result.data.permission || "none").toLowerCase();
} catch (error) {
if (error.status !== 404) {
core.info(`Could not resolve repository permission for ${comment.user.login}: ${error.message}`);
}
}
if (!maintainerPermissions.has(permission)) {
core.info(
`Skipping non-maintainer command reaction for ${comment.user.login}; repository permission is ${permission}.`,
);
return;
}
async function react(content) {
try {
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
content,
});
core.info(`Added ${content} reaction to comment ${comment.id}.`);
} catch (error) {
if (error.status === 422 && /already exists/i.test(String(error.message))) {
core.info(`${content} reaction already exists on comment ${comment.id}.`);
return;
}
if (error.status === 403 && /resource not accessible by integration/i.test(String(error.message))) {
core.warning(`${content} reaction could not be added with this token: ${error.message}`);
return;
}
throw error;
}
}
await react("eyes");
core.info(`Maintainer command observed on ${issue.pull_request ? "PR" : "issue"} #${issue.number}: ${commandLine}`);

View File

@@ -105,12 +105,12 @@ jobs:
fetch-depth: 1
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
with:
max-cache-size-mb: 800000
- name: Build Docker E2E image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
with:
context: .
file: ./scripts/e2e/Dockerfile

View File

@@ -158,7 +158,7 @@ permissions: read-all
concurrency:
group: openclaw-cross-os-release-checks-${{ inputs.ref }}-${{ inputs.provider }}-${{ inputs.mode }}
cancel-in-progress: false
cancel-in-progress: ${{ inputs.ref == 'main' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -166,10 +166,11 @@ env:
PNPM_VERSION: "10.32.1"
OPENCLAW_REPOSITORY: openclaw/openclaw
TSX_VERSION: "4.21.0"
OPENCLAW_CROSS_OS_OPENAI_MODEL: ${{ vars.OPENCLAW_CROSS_OS_OPENAI_MODEL || 'openai/gpt-5.4-mini' }}
jobs:
prepare:
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
outputs:
baseline_file_name: ${{ steps.baseline_metadata.outputs.file_name }}
baseline_spec: ${{ steps.baseline.outputs.value }}
@@ -321,7 +322,7 @@ jobs:
submodules: recursive
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -333,6 +334,9 @@ jobs:
cache: pnpm
cache-dependency-path: ${{ inputs.candidate_artifact_name == '' && 'source/pnpm-lock.yaml' || 'workflow/pnpm-lock.yaml' }}
- name: Ensure pnpm store cache directory exists
run: mkdir -p "$(pnpm store path --silent)"
- name: Build candidate artifact once
if: inputs.candidate_artifact_name == ''
env:
@@ -343,12 +347,19 @@ jobs:
--source-dir source \
--output-dir "${OUTPUT_DIR}"
- name: Download provided candidate artifact
if: inputs.candidate_artifact_name != ''
- name: Download current-run candidate artifact
if: inputs.candidate_artifact_name != '' && inputs.candidate_artifact_run_id == ''
uses: actions/download-artifact@v8
with:
name: ${{ inputs.candidate_artifact_name }}
run-id: ${{ inputs.candidate_artifact_run_id || github.run_id }}
path: ${{ runner.temp }}/openclaw-cross-os-release-checks/prepare/package
- name: Download previous-run candidate artifact
if: inputs.candidate_artifact_name != '' && inputs.candidate_artifact_run_id != ''
uses: actions/download-artifact@v8
with:
name: ${{ inputs.candidate_artifact_name }}
run-id: ${{ inputs.candidate_artifact_run_id }}
github-token: ${{ github.token }}
path: ${{ runner.temp }}/openclaw-cross-os-release-checks/prepare/package
@@ -496,7 +507,7 @@ jobs:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1
with:
version: ${{ env.PNPM_VERSION }}
run_install: false

File diff suppressed because it is too large Load Diff

View File

@@ -53,30 +53,36 @@ on:
- qa
- qa-parity
- qa-live
live_suite_filter:
description: Optional exact live suite id for focused live/E2E reruns; blank runs all selected live suites
required: false
default: ""
type: string
concurrency:
group: openclaw-release-checks-${{ inputs.ref }}
group: openclaw-release-checks-${{ inputs.expected_sha || inputs.ref }}-${{ inputs.rerun_group }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
jobs:
resolve_target:
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
outputs:
ref: ${{ steps.inputs.outputs.ref }}
sha: ${{ steps.ref.outputs.sha }}
revision: ${{ steps.ref.outputs.sha }}
provider: ${{ steps.inputs.outputs.provider }}
mode: ${{ steps.inputs.outputs.mode }}
release_profile: ${{ steps.inputs.outputs.release_profile }}
rerun_group: ${{ steps.inputs.outputs.rerun_group }}
live_suite_filter: ${{ steps.inputs.outputs.live_suite_filter }}
steps:
- name: Require main or release workflow ref for release checks
env:
@@ -106,6 +112,7 @@ jobs:
- name: Checkout trusted workflow helper
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.ref_name }}
path: workflow
fetch-depth: 1
@@ -126,6 +133,7 @@ jobs:
if: steps.fast_ref.outputs.fallback == 'true'
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ inputs.ref }}
path: source
fetch-depth: 0
@@ -190,6 +198,7 @@ jobs:
RELEASE_MODE_INPUT: ${{ inputs.mode }}
RELEASE_PROFILE_INPUT: ${{ inputs.release_profile }}
RELEASE_RERUN_GROUP_INPUT: ${{ inputs.rerun_group }}
RELEASE_LIVE_SUITE_FILTER_INPUT: ${{ inputs.live_suite_filter }}
run: |
set -euo pipefail
{
@@ -198,6 +207,7 @@ jobs:
printf 'mode=%s\n' "$RELEASE_MODE_INPUT"
printf 'release_profile=%s\n' "$RELEASE_PROFILE_INPUT"
printf 'rerun_group=%s\n' "$RELEASE_RERUN_GROUP_INPUT"
printf 'live_suite_filter=%s\n' "$RELEASE_LIVE_SUITE_FILTER_INPUT"
} >> "$GITHUB_OUTPUT"
- name: Summarize validated ref
@@ -209,6 +219,7 @@ jobs:
RELEASE_MODE: ${{ inputs.mode }}
RELEASE_PROFILE: ${{ inputs.release_profile }}
RELEASE_RERUN_GROUP: ${{ inputs.rerun_group }}
RELEASE_LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
run: |
{
echo "## Release checks"
@@ -220,17 +231,21 @@ jobs:
echo "- Cross-OS mode: \`${RELEASE_MODE}\`"
echo "- Release profile: \`${RELEASE_PROFILE}\`"
echo "- Rerun group: \`${RELEASE_RERUN_GROUP}\`"
if [[ -n "${RELEASE_LIVE_SUITE_FILTER// }" ]]; then
echo "- Live suite filter: \`${RELEASE_LIVE_SUITE_FILTER}\`"
fi
echo "- This run will execute cross-OS release validation, install smoke, QA Lab parity, Matrix, and Telegram lanes, and the non-Parallels Docker/live/openwebui coverage from the CI migration plan."
} >> "$GITHUB_STEP_SUMMARY"
prepare_release_package:
name: Prepare release package artifact
needs: [resolve_target]
if: contains(fromJSON('["all","cross-os","live-e2e","package"]'), needs.resolve_target.outputs.rerun_group)
runs-on: blacksmith-32vcpu-ubuntu-2404
if: contains(fromJSON('["all","cross-os","package"]'), needs.resolve_target.outputs.rerun_group) || (needs.resolve_target.outputs.rerun_group == 'live-e2e' && needs.resolve_target.outputs.live_suite_filter == '')
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
packages: write
outputs:
artifact_name: ${{ steps.artifact.outputs.name }}
package_sha256: ${{ steps.package.outputs.sha256 }}
@@ -240,6 +255,7 @@ jobs:
- name: Checkout trusted workflow ref
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.ref_name }}
fetch-depth: 0
@@ -259,7 +275,7 @@ jobs:
id: package
shell: bash
env:
PACKAGE_REF: ${{ needs.resolve_target.outputs.sha }}
PACKAGE_REF: ${{ needs.resolve_target.outputs.revision }}
run: |
set -euo pipefail
node scripts/resolve-openclaw-package-candidate.mjs \
@@ -296,9 +312,10 @@ jobs:
if: contains(fromJSON('["all","install-smoke"]'), needs.resolve_target.outputs.rerun_group)
permissions:
contents: read
packages: write
uses: ./.github/workflows/install-smoke.yml
with:
ref: ${{ needs.resolve_target.outputs.sha }}
ref: ${{ needs.resolve_target.outputs.revision }}
run_bun_global_install_smoke: true
cross_os_release_checks:
@@ -307,11 +324,10 @@ jobs:
permissions: read-all
uses: ./.github/workflows/openclaw-cross-os-release-checks-reusable.yml
with:
ref: ${{ needs.resolve_target.outputs.ref }}
ref: ${{ needs.resolve_target.outputs.revision }}
provider: ${{ needs.resolve_target.outputs.provider }}
mode: ${{ needs.resolve_target.outputs.mode }}
candidate_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
candidate_artifact_run_id: ${{ github.run_id }}
candidate_file_name: openclaw-current.tgz
candidate_version: ${{ needs.prepare_release_package.outputs.package_version }}
candidate_source_sha: ${{ needs.prepare_release_package.outputs.source_sha }}
@@ -323,8 +339,9 @@ jobs:
OPENCLAW_DISCORD_SMOKE_GUILD_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_GUILD_ID }}
OPENCLAW_DISCORD_SMOKE_CHANNEL_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_CHANNEL_ID }}
live_and_e2e_release_checks:
needs: [resolve_target, prepare_release_package]
live_repo_e2e_release_checks:
name: Run repo/live E2E validation
needs: [resolve_target]
if: contains(fromJSON('["all","live-e2e"]'), needs.resolve_target.outputs.rerun_group)
permissions:
actions: read
@@ -333,15 +350,14 @@ jobs:
pull-requests: read
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
with:
ref: ${{ needs.resolve_target.outputs.sha }}
ref: ${{ needs.resolve_target.outputs.revision }}
include_repo_e2e: true
include_release_path_suites: true
include_openwebui: ${{ needs.resolve_target.outputs.release_profile != 'minimum' }}
include_release_path_suites: false
include_openwebui: false
include_live_suites: true
release_test_profile: ${{ needs.resolve_target.outputs.release_profile }}
package_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
package_artifact_run_id: ${{ github.run_id }}
secrets:
live_suite_filter: ${{ needs.resolve_target.outputs.live_suite_filter }}
secrets: &live_e2e_release_secrets
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -388,6 +404,26 @@ jobs:
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
docker_e2e_release_checks:
name: Run Docker release-path validation
needs: [resolve_target, prepare_release_package]
if: contains(fromJSON('["all","live-e2e"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.live_suite_filter == ''
permissions:
actions: read
contents: read
packages: write
pull-requests: read
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
with:
ref: ${{ needs.resolve_target.outputs.revision }}
include_repo_e2e: false
include_release_path_suites: true
include_openwebui: ${{ needs.resolve_target.outputs.release_profile != 'minimum' }}
include_live_suites: false
release_test_profile: ${{ needs.resolve_target.outputs.release_profile }}
package_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
secrets: *live_e2e_release_secrets
package_acceptance_release_checks:
name: Run package acceptance
needs: [resolve_target, prepare_release_package]
@@ -401,7 +437,6 @@ jobs:
with:
workflow_ref: ${{ github.ref_name }}
source: artifact
artifact_run_id: ${{ github.run_id }}
artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
package_sha256: ${{ needs.prepare_release_package.outputs.package_sha256 }}
suite_profile: custom
@@ -461,7 +496,7 @@ jobs:
name: Run QA Lab parity lane (${{ matrix.lane }})
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 30
permissions:
contents: read
@@ -488,7 +523,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.sha }}
persist-credentials: false
ref: ${{ needs.resolve_target.outputs.revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -535,7 +571,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-parity-${{ matrix.lane }}-${{ needs.resolve_target.outputs.sha }}
name: release-qa-parity-${{ matrix.lane }}-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
@@ -544,7 +580,7 @@ jobs:
name: Run QA Lab parity report
needs: [resolve_target, qa_lab_parity_lane_release_checks]
if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 20
permissions:
contents: read
@@ -556,7 +592,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.sha }}
persist-credentials: false
ref: ${{ needs.resolve_target.outputs.revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -569,7 +606,7 @@ jobs:
- name: Download parity lane artifacts
uses: actions/download-artifact@v4
with:
pattern: release-qa-parity-*-${{ needs.resolve_target.outputs.sha }}
pattern: release-qa-parity-*-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/qa-e2e/
merge-multiple: true
@@ -590,7 +627,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-parity-${{ needs.resolve_target.outputs.sha }}
name: release-qa-parity-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
@@ -599,7 +636,7 @@ jobs:
name: Run QA Lab live Matrix lane
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group)
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
permissions:
contents: read
@@ -612,7 +649,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.sha }}
persist-credentials: false
ref: ${{ needs.resolve_target.outputs.revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -622,18 +660,6 @@ jobs:
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
echo "Missing required OPENAI_API_KEY." >&2
exit 1
fi
- name: Build private QA runtime
run: pnpm build
@@ -641,8 +667,8 @@ jobs:
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS: "90000"
OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS: "3000"
run: |
set -euo pipefail
@@ -652,10 +678,9 @@ jobs:
matrix_args=(
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--provider-mode mock-openai \
--model mock-openai/gpt-5.5 \
--alt-model mock-openai/gpt-5.5-alt \
--profile fast \
--fast
)
@@ -663,13 +688,23 @@ jobs:
matrix_args+=(--fail-fast)
fi
pnpm openclaw qa matrix "${matrix_args[@]}"
for attempt in 1 2; do
attempt_output_dir="${output_dir}/attempt-${attempt}"
if pnpm openclaw qa matrix --output-dir "${attempt_output_dir}" "${matrix_args[@]}"; then
exit 0
fi
if [[ "${attempt}" == "2" ]]; then
exit 1
fi
echo "Matrix live lane failed on attempt ${attempt}; retrying once..." >&2
sleep 10
done
- name: Upload Matrix QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-live-matrix-${{ needs.resolve_target.outputs.sha }}
name: release-qa-live-matrix-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
@@ -678,7 +713,7 @@ jobs:
name: Run QA Lab live Telegram lane
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group)
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
permissions:
contents: read
@@ -691,7 +726,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.sha }}
persist-credentials: false
ref: ${{ needs.resolve_target.outputs.revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -703,7 +739,6 @@ jobs:
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
@@ -718,7 +753,6 @@ jobs:
fi
}
require_var OPENAI_API_KEY
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
@@ -729,7 +763,6 @@ jobs:
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
@@ -740,21 +773,31 @@ jobs:
output_dir=".artifacts/qa-e2e/telegram-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa telegram \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci
for attempt in 1 2; do
attempt_output_dir="${output_dir}/attempt-${attempt}"
if pnpm openclaw qa telegram \
--repo-root . \
--output-dir "${attempt_output_dir}" \
--provider-mode mock-openai \
--model mock-openai/gpt-5.5 \
--alt-model mock-openai/gpt-5.5-alt \
--fast \
--credential-source convex \
--credential-role ci; then
exit 0
fi
if [[ "${attempt}" == "2" ]]; then
exit 1
fi
echo "Telegram live lane failed on attempt ${attempt}; retrying once..." >&2
sleep 10
done
- name: Upload Telegram QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-live-telegram-${{ needs.resolve_target.outputs.sha }}
name: release-qa-live-telegram-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
@@ -765,7 +808,8 @@ jobs:
- prepare_release_package
- install_smoke_release_checks
- cross_os_release_checks
- live_and_e2e_release_checks
- live_repo_e2e_release_checks
- docker_e2e_release_checks
- package_acceptance_release_checks
- qa_lab_parity_lane_release_checks
- qa_lab_parity_report_release_checks
@@ -785,7 +829,8 @@ jobs:
"prepare_release_package=${{ needs.prepare_release_package.result }}" \
"install_smoke_release_checks=${{ needs.install_smoke_release_checks.result }}" \
"cross_os_release_checks=${{ needs.cross_os_release_checks.result }}" \
"live_and_e2e_release_checks=${{ needs.live_and_e2e_release_checks.result }}" \
"live_repo_e2e_release_checks=${{ needs.live_repo_e2e_release_checks.result }}" \
"docker_e2e_release_checks=${{ needs.docker_e2e_release_checks.result }}" \
"package_acceptance_release_checks=${{ needs.package_acceptance_release_checks.result }}" \
"qa_lab_parity_lane_release_checks=${{ needs.qa_lab_parity_lane_release_checks.result }}" \
"qa_lab_parity_report_release_checks=${{ needs.qa_lab_parity_report_release_checks.result }}" \

View File

@@ -0,0 +1,70 @@
name: OpenGrep — Full
# Manual repository-wide scan for the high-precision OpenGrep rule super-config.
# This is intentionally separate from PR scanning so broad/backlog findings do
# not block unrelated pull requests.
on:
workflow_dispatch:
concurrency:
group: opengrep-full-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
permissions:
contents: read
security-events: write
jobs:
scan:
name: Scan full repository (precise)
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install opengrep
env:
# Pin both the install script (by commit SHA) and the binary version.
# The script SHA must match the v1.19.0 release tag in opengrep/opengrep
# so a compromised or force-pushed `main` cannot RCE in our CI runner.
# Bump both together when upgrading.
OPENGREP_VERSION: v1.19.0
OPENGREP_INSTALL_SHA: 9a4c0a68220618441608cd2bad4ff2eddccf8113
run: |
curl -fsSL "https://raw.githubusercontent.com/opengrep/opengrep/${OPENGREP_INSTALL_SHA}/install.sh" \
| bash -s -- -v "$OPENGREP_VERSION"
echo "$HOME/.opengrep/cli/latest" >> "$GITHUB_PATH"
- name: Verify opengrep
run: opengrep --version
- name: Run full opengrep scan
# Manual full scans cover all first-party source paths so maintainers can
# audit the complete rulepack without making PRs inherit unrelated backlog.
run: |
mkdir -p .opengrep-out
scripts/run-opengrep.sh --sarif --error
- name: Upload SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v4
# Only upload if the scan actually produced a SARIF file.
if: always() && hashFiles('.opengrep-out/precise.sarif') != ''
with:
sarif_file: .opengrep-out/precise.sarif
category: opengrep-full
- name: Upload SARIF as workflow artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: opengrep-full-sarif
path: .opengrep-out/precise.sarif
if-no-files-found: warn
retention-days: 30

100
.github/workflows/opengrep-precise.yml vendored Normal file
View File

@@ -0,0 +1,100 @@
name: OpenGrep — PR Diff
# Runs the high-precision OpenGrep rule super-config against only first-party
# source paths changed by a pull request. Keeping PR scans diff-scoped makes
# findings attributable to the proposed change instead of surfacing unrelated
# repository-wide backlog.
#
# For a repository-wide scan, use the manual OpenGrep — Full workflow.
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- ".github/actions/ensure-base-commit/**"
- ".github/workflows/opengrep-precise.yml"
- ".github/workflows/opengrep-precise-full.yml"
- ".semgrepignore"
- "apps/**"
- "extensions/**"
- "packages/**"
- "scripts/**"
- "security/opengrep/**"
- "src/**"
concurrency:
group: opengrep-pr-diff-${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
permissions:
contents: read
security-events: write
jobs:
scan:
name: Scan changed paths (precise)
if: ${{ !github.event.pull_request.draft }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Ensure PR base commit
uses: ./.github/actions/ensure-base-commit
with:
base-sha: ${{ github.event.pull_request.base.sha }}
fetch-ref: ${{ github.event.pull_request.base.ref }}
- name: Install opengrep
env:
# Pin both the install script (by commit SHA) and the binary version.
# The script SHA must match the v1.19.0 release tag in opengrep/opengrep
# so a compromised or force-pushed `main` cannot RCE in our CI runner.
# Bump both together when upgrading.
OPENGREP_VERSION: v1.19.0
OPENGREP_INSTALL_SHA: 9a4c0a68220618441608cd2bad4ff2eddccf8113
run: |
curl -fsSL "https://raw.githubusercontent.com/opengrep/opengrep/${OPENGREP_INSTALL_SHA}/install.sh" \
| bash -s -- -v "$OPENGREP_VERSION"
echo "$HOME/.opengrep/cli/latest" >> "$GITHUB_PATH"
- name: Verify opengrep
run: opengrep --version
- name: Run opengrep on PR diff
env:
OPENCLAW_OPENGREP_BASE_REF: ${{ github.event.pull_request.base.sha }}...HEAD
# 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`
# at the repo root and are picked up automatically.
run: |
mkdir -p .opengrep-out
scripts/run-opengrep.sh --changed --sarif --error
- name: Upload SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v4
# Only upload if the scan actually produced a SARIF file.
if: always() && hashFiles('.opengrep-out/precise.sarif') != ''
with:
sarif_file: .opengrep-out/precise.sarif
category: opengrep-pr-diff
- name: Upload SARIF as workflow artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: opengrep-pr-diff-sarif
path: .opengrep-out/precise.sarif
if-no-files-found: warn
retention-days: 30

View File

@@ -254,7 +254,7 @@ env:
jobs:
resolve_package:
name: Resolve package candidate
runs-on: ubuntu-24.04
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
outputs:
docker_lanes: ${{ steps.profile.outputs.docker_lanes }}
@@ -262,6 +262,7 @@ jobs:
include_openwebui: ${{ steps.profile.outputs.include_openwebui }}
include_release_path_suites: ${{ steps.profile.outputs.include_release_path_suites }}
package_artifact_name: ${{ steps.profile.outputs.package_artifact_name }}
package_source_sha: ${{ steps.resolve.outputs.package_source_sha }}
package_sha256: ${{ steps.resolve.outputs.sha256 }}
package_version: ${{ steps.resolve.outputs.package_version }}
telegram_enabled: ${{ steps.profile.outputs.telegram_enabled }}
@@ -281,8 +282,15 @@ jobs:
install-bun: ${{ inputs.source == 'ref' && 'true' || 'false' }}
install-deps: "false"
- name: Download package artifact input
if: inputs.source == 'artifact'
- name: Download current-run package artifact input
if: inputs.source == 'artifact' && inputs.artifact_run_id == ''
uses: actions/download-artifact@v8
with:
name: ${{ inputs.artifact_name }}
path: .artifacts/package-candidate-input
- name: Download previous-run package artifact input
if: inputs.source == 'artifact' && inputs.artifact_run_id != ''
env:
GH_TOKEN: ${{ github.token }}
ARTIFACT_RUN_ID: ${{ inputs.artifact_run_id }}
@@ -290,10 +298,6 @@ jobs:
shell: bash
run: |
set -euo pipefail
if [[ -z "${ARTIFACT_RUN_ID// }" ]]; then
echo "artifact_run_id is required when source=artifact." >&2
exit 1
fi
if [[ -z "${ARTIFACT_NAME// }" ]]; then
echo "artifact_name is required when source=artifact." >&2
exit 1
@@ -493,7 +497,7 @@ jobs:
package_spec: ${{ inputs.package_spec }}
package_artifact_name: ${{ needs.resolve_package.outputs.package_artifact_name }}
package_label: openclaw@${{ needs.resolve_package.outputs.package_version }}
harness_ref: ${{ inputs.source == 'ref' && inputs.package_ref || inputs.workflow_ref }}
harness_ref: ${{ needs.resolve_package.outputs.package_source_sha || inputs.workflow_ref }}
provider_mode: ${{ needs.resolve_package.outputs.telegram_mode }}
scenario: ${{ inputs.telegram_scenarios }}
secrets:
@@ -505,7 +509,7 @@ jobs:
name: Verify package acceptance
needs: [resolve_package, docker_acceptance, package_telegram]
if: always()
runs-on: ubuntu-24.04
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 5
steps:
- name: Verify package acceptance results

View File

@@ -42,7 +42,7 @@ jobs:
# followthrough gate that expects a fast post-approval read within a 30s
# agent.wait timeout.
QA_PARITY_CONCURRENCY: "1"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
@@ -57,9 +57,11 @@ jobs:
steps:
- name: Checkout PR
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1
- name: Setup Node
uses: actions/setup-node@v6

View File

@@ -35,7 +35,7 @@ jobs:
permissions:
contents: read
outputs:
ref_sha: ${{ steps.ref.outputs.sha }}
ref_revision: ${{ steps.ref.outputs.sha }}
has_candidates: ${{ steps.plan.outputs.has_candidates }}
candidate_count: ${{ steps.plan.outputs.candidate_count }}
skipped_published_count: ${{ steps.plan.outputs.skipped_published_count }}
@@ -44,6 +44,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.sha }}
fetch-depth: 0
@@ -150,7 +151,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preview_plugins_clawhub.outputs.ref_sha }}
persist-credentials: false
ref: ${{ needs.preview_plugins_clawhub.outputs.ref_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -164,6 +166,7 @@ jobs:
- name: Checkout ClawHub CLI source
uses: actions/checkout@v6
with:
persist-credentials: false
repository: ${{ env.CLAWHUB_REPOSITORY }}
ref: ${{ env.CLAWHUB_REF }}
path: clawhub-source
@@ -187,7 +190,7 @@ jobs:
env:
CLAWHUB_REGISTRY: ${{ env.CLAWHUB_REGISTRY }}
SOURCE_REPO: ${{ github.repository }}
SOURCE_COMMIT: ${{ needs.preview_plugins_clawhub.outputs.ref_sha }}
SOURCE_COMMIT: ${{ needs.preview_plugins_clawhub.outputs.ref_revision }}
SOURCE_REF: ${{ github.ref }}
PACKAGE_TAG: ${{ matrix.plugin.publishTag }}
PACKAGE_DIR: ${{ matrix.plugin.packageDir }}
@@ -209,7 +212,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preview_plugins_clawhub.outputs.ref_sha }}
persist-credentials: false
ref: ${{ needs.preview_plugins_clawhub.outputs.ref_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -223,6 +227,7 @@ jobs:
- name: Checkout ClawHub CLI source
uses: actions/checkout@v6
with:
persist-credentials: false
repository: ${{ env.CLAWHUB_REPOSITORY }}
ref: ${{ env.CLAWHUB_REF }}
path: clawhub-source
@@ -266,7 +271,7 @@ jobs:
env:
CLAWHUB_REGISTRY: ${{ env.CLAWHUB_REGISTRY }}
SOURCE_REPO: ${{ github.repository }}
SOURCE_COMMIT: ${{ needs.preview_plugins_clawhub.outputs.ref_sha }}
SOURCE_COMMIT: ${{ needs.preview_plugins_clawhub.outputs.ref_revision }}
SOURCE_REF: ${{ github.ref }}
PACKAGE_TAG: ${{ matrix.plugin.publishTag }}
PACKAGE_DIR: ${{ matrix.plugin.packageDir }}

View File

@@ -46,7 +46,7 @@ jobs:
permissions:
contents: read
outputs:
ref_sha: ${{ steps.ref.outputs.sha }}
ref_revision: ${{ steps.ref.outputs.sha }}
has_candidates: ${{ steps.plan.outputs.has_candidates }}
candidate_count: ${{ steps.plan.outputs.candidate_count }}
matrix: ${{ steps.plan.outputs.matrix }}
@@ -54,6 +54,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
fetch-depth: 0
@@ -151,7 +152,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preview_plugins_npm.outputs.ref_sha }}
persist-credentials: false
ref: ${{ needs.preview_plugins_npm.outputs.ref_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -185,7 +187,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preview_plugins_npm.outputs.ref_sha }}
persist-credentials: false
ref: ${{ needs.preview_plugins_npm.outputs.ref_revision }}
fetch-depth: 1
- name: Setup Node environment

413
.github/workflows/plugin-prerelease.yml vendored Normal file
View File

@@ -0,0 +1,413 @@
name: Plugin Prerelease
on:
workflow_dispatch:
inputs:
target_ref:
description: Branch, tag, or full commit SHA to validate
required: false
default: main
type: string
expected_sha:
description: Optional full commit SHA that target_ref must resolve to
required: false
default: ""
type: string
full_release_validation:
description: Enable release-only Docker prerelease lanes from Full Release Validation
required: false
default: false
type: boolean
permissions:
contents: read
concurrency:
group: plugin-prerelease-${{ inputs.target_ref }}
cancel-in-progress: ${{ inputs.target_ref == 'main' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
preflight:
name: Build plugin prerelease plan
runs-on: ubuntu-24.04
timeout-minutes: 15
outputs:
checkout_revision: ${{ steps.manifest.outputs.checkout_revision }}
run_plugin_prerelease_suite: ${{ steps.manifest.outputs.run_plugin_prerelease_suite }}
run_plugin_prerelease_static: ${{ steps.manifest.outputs.run_plugin_prerelease_static }}
plugin_prerelease_static_matrix: ${{ steps.manifest.outputs.plugin_prerelease_static_matrix }}
run_plugin_prerelease_node: ${{ steps.manifest.outputs.run_plugin_prerelease_node }}
plugin_prerelease_node_matrix: ${{ steps.manifest.outputs.plugin_prerelease_node_matrix }}
run_plugin_prerelease_extensions: ${{ steps.manifest.outputs.run_plugin_prerelease_extensions }}
plugin_prerelease_extension_matrix: ${{ steps.manifest.outputs.plugin_prerelease_extension_matrix }}
run_plugin_prerelease_docker: ${{ steps.manifest.outputs.run_plugin_prerelease_docker }}
plugin_prerelease_docker_lanes: ${{ steps.manifest.outputs.plugin_prerelease_docker_lanes }}
steps:
- name: Checkout target
uses: actions/checkout@v6
with:
ref: ${{ inputs.target_ref }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Build plugin prerelease manifest
id: manifest
env:
EXPECTED_SHA: ${{ inputs.expected_sha }}
FULL_RELEASE_VALIDATION: ${{ inputs.full_release_validation && 'true' || 'false' }}
run: |
node --input-type=module <<'EOF'
import { appendFileSync } from "node:fs";
import { execFileSync } from "node:child_process";
const createMatrix = (include) => ({ include });
const outputPath = process.env.GITHUB_OUTPUT;
const checkoutRevision = execFileSync("git", ["rev-parse", "HEAD"], {
encoding: "utf8",
}).trim();
const expectedSha = (process.env.EXPECTED_SHA ?? "").trim();
const fullReleaseValidation = process.env.FULL_RELEASE_VALIDATION === "true";
if (expectedSha && expectedSha !== checkoutRevision) {
console.error(
`target_ref resolved to ${checkoutRevision}, expected ${expectedSha}`,
);
process.exit(1);
}
let pluginPrereleasePlan = { staticChecks: [], dockerLanes: [] };
let extensionShards = [];
let nodeShards = [];
try {
const { assertPluginPrereleaseTestPlanComplete } = await import(
"./scripts/lib/plugin-prerelease-test-plan.mjs"
);
pluginPrereleasePlan = assertPluginPrereleaseTestPlanComplete();
} catch (error) {
const errorCode =
error && typeof error === "object" && "code" in error ? error.code : "";
const moduleUrl =
error && typeof error === "object" && "url" in error ? String(error.url) : "";
if (
errorCode === "ERR_MODULE_NOT_FOUND" &&
moduleUrl.endsWith("/scripts/lib/plugin-prerelease-test-plan.mjs")
) {
console.warn(
"Plugin prerelease plan unavailable in target ref; skipping static and Docker plugin prerelease lanes.",
);
} else {
throw error;
}
}
try {
const { createExtensionTestShards, DEFAULT_EXTENSION_TEST_SHARD_COUNT } = await import(
"./scripts/lib/extension-test-plan.mjs"
);
extensionShards = createExtensionTestShards({
shardCount: DEFAULT_EXTENSION_TEST_SHARD_COUNT,
}).map((shard) => ({
check_name: shard.checkName,
extensions_csv: shard.extensionIds.join(","),
runner: [0, 1, 2, 3].includes(shard.index)
? "blacksmith-8vcpu-ubuntu-2404"
: "blacksmith-4vcpu-ubuntu-2404",
shard_index: shard.index + 1,
task: "extensions-batch",
}));
} catch (error) {
const errorCode =
error && typeof error === "object" && "code" in error ? error.code : "";
const moduleUrl =
error && typeof error === "object" && "url" in error ? String(error.url) : "";
if (
errorCode === "ERR_MODULE_NOT_FOUND" &&
moduleUrl.endsWith("/scripts/lib/extension-test-plan.mjs")
) {
console.warn(
"Extension test plan unavailable in target ref; skipping extension prerelease shards.",
);
} else {
throw error;
}
}
try {
const { createNodeTestShards } = await import("./scripts/lib/ci-node-test-plan.mjs");
nodeShards = createNodeTestShards({
includeReleaseOnlyPluginShards: true,
})
.filter((shard) => shard.shardName === "agentic-plugins")
.map((shard) => ({
check_name: shard.checkName,
runtime: "node",
task: "test-shard",
shard_name: shard.shardName,
configs: shard.configs,
includePatterns: shard.includePatterns,
runner: shard.runner,
}));
} catch (error) {
const errorCode =
error && typeof error === "object" && "code" in error ? error.code : "";
const moduleUrl =
error && typeof error === "object" && "url" in error ? String(error.url) : "";
if (
errorCode === "ERR_MODULE_NOT_FOUND" &&
moduleUrl.endsWith("/scripts/lib/ci-node-test-plan.mjs")
) {
console.warn(
"Node test plan unavailable in target ref; skipping release-only plugin Node shard.",
);
} else {
throw error;
}
}
const staticChecks = pluginPrereleasePlan.staticChecks.map((check) => ({
check_name: check.checkName,
command: check.command,
task: check.check,
}));
const dockerLanes = pluginPrereleasePlan.dockerLanes;
const runStatic = staticChecks.length > 0;
const runNode = nodeShards.length > 0;
const runExtensions = extensionShards.length > 0;
const runDocker = fullReleaseValidation && dockerLanes.length > 0;
const runSuite = runStatic || runNode || runExtensions || runDocker;
const manifest = {
checkout_revision: checkoutRevision,
run_plugin_prerelease_suite: runSuite,
run_plugin_prerelease_static: runStatic,
plugin_prerelease_static_matrix: createMatrix(staticChecks),
run_plugin_prerelease_node: runNode,
plugin_prerelease_node_matrix: createMatrix(nodeShards),
run_plugin_prerelease_extensions: runExtensions,
plugin_prerelease_extension_matrix: createMatrix(extensionShards),
run_plugin_prerelease_docker: runDocker,
plugin_prerelease_docker_lanes: dockerLanes.join(" "),
};
for (const [key, value] of Object.entries(manifest)) {
appendFileSync(
outputPath,
`${key}=${typeof value === "string" ? value : JSON.stringify(value)}\n`,
"utf8",
);
}
EOF
plugin-prerelease-static-shard:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_static == 'true'
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 45
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.plugin_prerelease_static_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_revision }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Run plugin prerelease static shard
env:
PLUGIN_PRERELEASE_COMMAND: ${{ matrix.command }}
PLUGIN_PRERELEASE_TASK: ${{ matrix.task }}
shell: bash
run: |
set -euo pipefail
echo "Running ${PLUGIN_PRERELEASE_TASK}: ${PLUGIN_PRERELEASE_COMMAND}"
bash -c "$PLUGIN_PRERELEASE_COMMAND"
plugin-prerelease-node-shard:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_node == 'true'
runs-on: ${{ matrix.runner || 'ubuntu-24.04' }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.plugin_prerelease_node_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_revision }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Configure Node test resources
run: echo "OPENCLAW_VITEST_MAX_WORKERS=2" >> "$GITHUB_ENV"
- name: Run release-only plugin Node shard
env:
NODE_OPTIONS: --max-old-space-size=6144
OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }}
OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
OPENCLAW_VITEST_SHARD_NAME: ${{ matrix.shard_name }}
OPENCLAW_TEST_PROJECTS_PARALLEL: "2"
shell: bash
run: |
set -euo pipefail
node --input-type=module <<'EOF'
import { spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";
import { join } from "node:path";
const configs = JSON.parse(process.env.OPENCLAW_NODE_TEST_CONFIGS_JSON ?? "[]");
if (!Array.isArray(configs) || configs.length === 0) {
console.error("Missing node test shard configs");
process.exit(1);
}
const includePatterns = JSON.parse(
process.env.OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON ?? "null",
);
const childEnv = { ...process.env };
if (Array.isArray(includePatterns) && includePatterns.length > 0) {
const includeFile = join(
process.env.RUNNER_TEMP ?? ".",
`node-test-include-${process.env.GITHUB_JOB ?? "local"}-${Date.now()}.json`,
);
writeFileSync(includeFile, JSON.stringify(includePatterns), "utf8");
childEnv.OPENCLAW_VITEST_INCLUDE_FILE = includeFile;
}
const result = spawnSync(
"pnpm",
["exec", "node", "scripts/test-projects.mjs", ...configs],
{
env: childEnv,
stdio: "inherit",
},
);
process.exit(result.status ?? 1);
EOF
plugin-prerelease-extension-shard:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_extensions == 'true'
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.plugin_prerelease_extension_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_revision }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Run extension shard
env:
NODE_OPTIONS: --max-old-space-size=6144
OPENCLAW_EXTENSION_BATCH_PARALLEL: 2
OPENCLAW_VITEST_MAX_WORKERS: 1
OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }}
run: pnpm test:extensions:batch -- "$OPENCLAW_EXTENSION_BATCH"
plugin-prerelease-docker-suite:
name: plugin-prerelease-docker-suite
needs: [preflight]
if: ${{ inputs.full_release_validation && needs.preflight.outputs.run_plugin_prerelease_docker == 'true' }}
permissions:
actions: read
contents: read
packages: write
pull-requests: read
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
with:
ref: ${{ needs.preflight.outputs.checkout_revision }}
include_repo_e2e: false
include_release_path_suites: false
include_openwebui: false
docker_lanes: ${{ needs.preflight.outputs.plugin_prerelease_docker_lanes }}
include_live_suites: false
live_models_only: false
plugin-prerelease-suite:
permissions:
contents: read
name: plugin-prerelease-suite
needs:
- preflight
- plugin-prerelease-static-shard
- plugin-prerelease-node-shard
- plugin-prerelease-extension-shard
- plugin-prerelease-docker-suite
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_plugin_prerelease_suite == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Verify plugin prerelease suite
env:
RUN_STATIC: ${{ needs.preflight.outputs.run_plugin_prerelease_static }}
RUN_NODE: ${{ needs.preflight.outputs.run_plugin_prerelease_node }}
RUN_EXTENSIONS: ${{ needs.preflight.outputs.run_plugin_prerelease_extensions }}
RUN_DOCKER: ${{ needs.preflight.outputs.run_plugin_prerelease_docker }}
STATIC_RESULT: ${{ needs.plugin-prerelease-static-shard.result }}
NODE_RESULT: ${{ needs.plugin-prerelease-node-shard.result }}
EXTENSIONS_RESULT: ${{ needs.plugin-prerelease-extension-shard.result }}
DOCKER_RESULT: ${{ needs.plugin-prerelease-docker-suite.result }}
shell: bash
run: |
set -euo pipefail
failed=0
check_required() {
local name="$1"
local required="$2"
local status="$3"
if [ "$required" != "true" ]; then
return 0
fi
if [ "$status" != "success" ]; then
echo "::error::${name} ended with ${status}"
failed=1
fi
}
check_required "plugin-prerelease-static" "$RUN_STATIC" "$STATIC_RESULT"
check_required "plugin-prerelease-node" "$RUN_NODE" "$NODE_RESULT"
check_required "plugin-prerelease-extensions" "$RUN_EXTENSIONS" "$EXTENSIONS_RESULT"
check_required "plugin-prerelease-docker" "$RUN_DOCKER" "$DOCKER_RESULT"
exit "$failed"

View File

@@ -44,7 +44,7 @@ env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
@@ -81,12 +81,13 @@ jobs:
needs: authorize_actor
runs-on: blacksmith-8vcpu-ubuntu-2404
outputs:
selected_sha: ${{ steps.validate.outputs.selected_sha }}
selected_revision: ${{ steps.validate.outputs.selected_revision }}
trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
persist-credentials: false
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
fetch-depth: 0
@@ -98,27 +99,27 @@ jobs:
shell: bash
run: |
set -euo pipefail
selected_sha="$(git rev-parse HEAD)"
selected_revision="$(git rev-parse HEAD)"
trusted_reason=""
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
if git merge-base --is-ancestor "$selected_sha" refs/remotes/origin/main; then
if git merge-base --is-ancestor "$selected_revision" refs/remotes/origin/main; then
trusted_reason="main-ancestor"
elif git tag --points-at "$selected_sha" | grep -Eq '^v'; then
elif git tag --points-at "$selected_revision" | grep -Eq '^v'; then
trusted_reason="release-tag"
elif [[ "$INPUT_REF" =~ ^release/[0-9]{4}\.[0-9]+\.[0-9]+$ ]]; then
git fetch --no-tags origin "+refs/heads/${INPUT_REF}:refs/remotes/origin/${INPUT_REF}"
release_branch_sha="$(git rev-parse "refs/remotes/origin/${INPUT_REF}")"
if [[ "$selected_sha" == "$release_branch_sha" ]]; then
if [[ "$selected_revision" == "$release_branch_sha" ]]; then
trusted_reason="release-branch-head"
fi
else
pr_head_count="$(
gh api \
-H "Accept: application/vnd.github+json" \
"repos/${GITHUB_REPOSITORY}/commits/${selected_sha}/pulls" \
--jq '[.[] | select(.state == "open" and .head.repo.full_name == "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${selected_sha}"'")] | length'
"repos/${GITHUB_REPOSITORY}/commits/${selected_revision}/pulls" \
--jq '[.[] | select(.state == "open" and .head.repo.full_name == "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${selected_revision}"'")] | length'
)"
if [[ "$pr_head_count" != "0" ]]; then
trusted_reason="open-pr-head"
@@ -126,23 +127,23 @@ jobs:
fi
if [[ -z "$trusted_reason" ]]; then
echo "Ref '${INPUT_REF}' resolved to $selected_sha, which is not trusted for this secret-bearing QA run." >&2
echo "Ref '${INPUT_REF}' resolved to $selected_revision, which is not trusted for this secret-bearing QA run." >&2
echo "Allowed refs must be on main, point to a release tag, match a release branch head, or match an open PR head in ${GITHUB_REPOSITORY}." >&2
exit 1
fi
echo "selected_sha=$selected_sha" >> "$GITHUB_OUTPUT"
echo "selected_revision=$selected_revision" >> "$GITHUB_OUTPUT"
echo "trusted_reason=$trusted_reason" >> "$GITHUB_OUTPUT"
{
echo "Validated ref: \`${INPUT_REF}\`"
echo "Resolved SHA: \`$selected_sha\`"
echo "Resolved SHA: \`$selected_revision\`"
echo "Trust reason: \`$trusted_reason\`"
} >> "$GITHUB_STEP_SUMMARY"
run_mock_parity:
name: Run QA Lab parity gate
needs: [validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 30
env:
QA_PARITY_CONCURRENCY: "1"
@@ -157,7 +158,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
persist-credentials: false
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -213,14 +215,15 @@ jobs:
name: Run Matrix live QA lane
needs: [authorize_actor, validate_selected_ref]
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.matrix_profile == 'all') }}
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
persist-credentials: false
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -287,7 +290,7 @@ jobs:
name: Run Matrix live QA lane (${{ matrix.profile }})
needs: [authorize_actor, validate_selected_ref]
if: ${{ github.event_name == 'workflow_dispatch' && inputs.matrix_profile == 'all' }}
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
strategy:
@@ -303,7 +306,8 @@ jobs:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
persist-credentials: false
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -368,14 +372,15 @@ jobs:
run_live_telegram:
name: Run Telegram live QA lane with Convex leases
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
persist-credentials: false
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
fetch-depth: 1
- name: Setup Node environment
@@ -460,14 +465,15 @@ jobs:
run_live_discord:
name: Run Discord live QA lane with Convex leases
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
persist-credentials: false
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
fetch-depth: 1
- name: Setup Node environment

View File

@@ -4,6 +4,32 @@ on:
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
inputs:
backfill_stale_closures:
description: "Close currently stale-eligible issues and PRs with the Barnacle app"
required: false
type: boolean
default: false
dry_run:
description: "List matching stale-eligible items without closing them"
required: false
type: boolean
default: true
include_issues:
description: "Include stale-eligible issues in the backfill"
required: false
type: boolean
default: true
include_prs:
description: "Include stale-eligible pull requests in the backfill"
required: false
type: boolean
default: true
max_closures:
description: "Maximum items to close when dry_run is false"
required: false
type: number
default: 50
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -12,6 +38,7 @@ permissions: {}
jobs:
stale:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.backfill_stale_closures != true }}
permissions:
issues: write
pull-requests: write
@@ -35,10 +62,10 @@ jobs:
uses: actions/stale@v10
with:
repo-token: ${{ steps.app-token.outputs.token || steps.app-token-fallback.outputs.token }}
days-before-issue-stale: 7
days-before-issue-close: 5
days-before-pr-stale: 5
days-before-pr-close: 3
days-before-issue-stale: 14
days-before-issue-close: 7
days-before-pr-stale: 14
days-before-pr-close: 7
stale-issue-label: stale
stale-pr-label: stale
exempt-issue-labels: enhancement,maintainer,pinned,security,no-stale,bad-barnacle
@@ -95,7 +122,7 @@ jobs:
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 27
days-before-pr-close: 3
days-before-pr-close: 7
stale-pr-label: stale
exempt-pr-labels: maintainer,no-stale,bad-barnacle
operations-per-run: 2000
@@ -139,10 +166,10 @@ jobs:
uses: actions/stale@v10
with:
repo-token: ${{ steps.app-token-fallback.outputs.token }}
days-before-issue-stale: 7
days-before-issue-close: 5
days-before-pr-stale: 5
days-before-pr-close: 3
days-before-issue-stale: 14
days-before-issue-close: 7
days-before-pr-stale: 14
days-before-pr-close: 7
stale-issue-label: stale
stale-pr-label: stale
exempt-issue-labels: enhancement,maintainer,pinned,security,no-stale,bad-barnacle
@@ -197,7 +224,7 @@ jobs:
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 27
days-before-pr-close: 3
days-before-pr-close: 7
stale-pr-label: stale
exempt-pr-labels: maintainer,no-stale,bad-barnacle
operations-per-run: 2000
@@ -213,7 +240,253 @@ jobs:
If you believe this PR should be revived, post in #clawtributors on Discord to talk to a maintainer.
That channel is the escape hatch for high-quality PRs that get auto-closed.
backfill-stale-closures:
if: ${{ github.event_name == 'workflow_dispatch' && inputs.backfill_stale_closures == true }}
permissions:
issues: write
pull-requests: write
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: "2971289"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY_FALLBACK }}
- name: Backfill stale closures
uses: actions/github-script@v9
env:
DRY_RUN: ${{ inputs.dry_run }}
INCLUDE_ISSUES: ${{ inputs.include_issues }}
INCLUDE_PRS: ${{ inputs.include_prs }}
MAX_CLOSURES: ${{ inputs.max_closures }}
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const dayMs = 24 * 60 * 60 * 1000;
const dryRun = process.env.DRY_RUN !== "false";
const includeIssues = process.env.INCLUDE_ISSUES !== "false";
const includePrs = process.env.INCLUDE_PRS !== "false";
const maxClosures = Math.max(0, Number(process.env.MAX_CLOSURES || "50"));
const nowMs = Date.now();
const { owner, repo } = context.repo;
const issueExemptLabels = new Set([
"enhancement",
"maintainer",
"pinned",
"security",
"no-stale",
"bad-barnacle",
]);
const prExemptLabels = new Set(["maintainer", "no-stale", "bad-barnacle"]);
const maintainerAssociations = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
const maintainerLogins = new Set([
"altaywtf",
"BunsDev",
"cpojer",
"gumadeiras",
"hydro13",
"hxy91819",
"jalehman",
"joshavant",
"joshp123",
"mbelinky",
"mukhtharcm",
"ngutman",
"obviyus",
"odysseus0",
"onutc",
"osolmaz",
"sebslight",
"sliverp",
"steipete",
"thewilloftheshadow",
"tyler6204",
"velvet-shark",
"vignesh07",
"vincentkoc",
"visionik",
].map(login => login.toLowerCase()));
const issueCloseMessage = [
"Closing due to inactivity.",
"If this is still an issue, please retry on the latest OpenClaw release and share updated details.",
"If you are absolutely sure it still happens on the latest release, open a new issue with fresh steps to reproduce.",
].join("\n");
const prCloseMessage = [
"Closing due to inactivity.",
"If you believe this PR should be revived, post in #clawtributors on Discord to talk to a maintainer.",
"That channel is the escape hatch for high-quality PRs that get auto-closed.",
].join("\n");
const hasAny = (labels, exemptLabels) => {
for (const label of labels) {
if (exemptLabels.has(label)) {
return true;
}
}
return false;
};
const isOlderThan = (dateString, days) => {
const timestamp = Date.parse(dateString);
return Number.isFinite(timestamp) && timestamp < nowMs - days * dayMs;
};
const candidates = [];
const skipped = {
missingStale: 0,
exemptLabel: 0,
maintainerAuthor: 0,
maintainerAssignee: 0,
notOldEnough: 0,
disabledType: 0,
};
for await (const response of github.paginate.iterator(github.rest.issues.listForRepo, {
owner,
repo,
state: "open",
sort: "updated",
direction: "asc",
per_page: 100,
})) {
for (const item of response.data) {
const isPr = Boolean(item.pull_request);
if ((isPr && !includePrs) || (!isPr && !includeIssues)) {
skipped.disabledType += 1;
continue;
}
const labels = new Set((item.labels || []).map(label => label.name));
if (!labels.has("stale")) {
skipped.missingStale += 1;
continue;
}
const exemptLabels = isPr ? prExemptLabels : issueExemptLabels;
if (hasAny(labels, exemptLabels)) {
skipped.exemptLabel += 1;
continue;
}
if (maintainerAssociations.has(item.author_association)) {
skipped.maintainerAuthor += 1;
continue;
}
const assigned = (item.assignees || []).length > 0;
const assignedToMaintainer = (item.assignees || []).some(assignee =>
maintainerLogins.has(assignee.login.toLowerCase()),
);
if (assignedToMaintainer) {
skipped.maintainerAssignee += 1;
continue;
}
let eligible = false;
let lane = "";
if (isPr && assigned) {
lane = "assigned-pr";
eligible = isOlderThan(item.created_at, 34) && isOlderThan(item.updated_at, 7);
} else if (isPr) {
lane = "unassigned-pr";
eligible = isOlderThan(item.updated_at, 7);
} else if (assigned) {
lane = "assigned-issue";
eligible = isOlderThan(item.updated_at, 10);
} else {
lane = "unassigned-issue";
eligible = isOlderThan(item.updated_at, 7);
}
if (!eligible) {
skipped.notOldEnough += 1;
continue;
}
candidates.push({
number: item.number,
title: item.title,
lane,
isPr,
assigned,
createdAt: item.created_at,
updatedAt: item.updated_at,
authorAssociation: item.author_association,
url: item.html_url,
});
}
}
const countsByLane = candidates.reduce((counts, candidate) => {
counts[candidate.lane] = (counts[candidate.lane] || 0) + 1;
return counts;
}, {});
const selected = candidates.slice(0, maxClosures);
core.info(`Dry run: ${dryRun}`);
core.info(`Candidates: ${candidates.length}`);
core.info(`Selected: ${selected.length}`);
core.info(`Counts by lane: ${JSON.stringify(countsByLane)}`);
core.info(`Skipped: ${JSON.stringify(skipped)}`);
for (const candidate of selected) {
core.info(`${dryRun ? "Would close" : "Closing"} ${candidate.lane} #${candidate.number}: ${candidate.title} (${candidate.url})`);
}
await core.summary
.addHeading("Stale Closure Backfill")
.addRaw(`Dry run: ${dryRun}\n\n`)
.addRaw(`Candidates: ${candidates.length}\n\n`)
.addRaw(`Selected: ${selected.length}\n\n`)
.addCodeBlock(JSON.stringify({ countsByLane, skipped }, null, 2), "json")
.addTable([
[
{ data: "Lane", header: true },
{ data: "Number", header: true },
{ data: "Title", header: true },
{ data: "URL", header: true },
],
...selected.map(candidate => [
candidate.lane,
String(candidate.number),
candidate.title,
candidate.url,
]),
])
.write();
if (dryRun) {
return;
}
for (const candidate of selected) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: candidate.number,
body: candidate.isPr ? prCloseMessage : issueCloseMessage,
});
if (candidate.isPr) {
await github.rest.pulls.update({
owner,
repo,
pull_number: candidate.number,
state: "closed",
});
} else {
await github.rest.issues.update({
owner,
repo,
issue_number: candidate.number,
state: "closed",
state_reason: "not_planned",
});
}
}
lock-closed-issues:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.backfill_stale_closures != true }}
permissions:
issues: write
runs-on: blacksmith-16vcpu-ubuntu-2404

View File

@@ -129,7 +129,7 @@ jobs:
- name: Run Codex test performance agent
if: steps.gate.outputs.run_agent == 'true'
uses: openai/codex-action@v1
uses: openai/codex-action@5c3f4ccdb2b8790f73d6b21751ac00e602aa0c02
with:
openai-api-key: ${{ secrets.OPENCLAW_TEST_PERF_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
prompt-file: .github/codex/prompts/test-performance-agent.md

5
.gitignore vendored
View File

@@ -3,6 +3,7 @@ node_modules
.env
docker-compose.override.yml
docker-compose.extra.yml
docker-compose.sandbox.yml
dist
dist-runtime/
pnpm-lock.yaml
@@ -136,6 +137,7 @@ USER.md
.agent/*.json
!.agent/workflows/
/local/
/client_secret_*.json
package-lock.json
.claude/
.agent/
@@ -190,3 +192,6 @@ extensions/qa-lab/web/dist/
# Generated bundled plugin runtime dependency manifests
extensions/**/.openclaw-runtime-deps.json
extensions/**/.openclaw-runtime-deps-stamp.json
# Output dir for scripts/run-opengrep.sh (local opengrep scans)
/.opengrep-out/

View File

@@ -25,6 +25,7 @@
"eslint/no-sequences": "error",
"eslint/no-self-compare": "error",
"eslint/no-shadow": "off",
"eslint/no-underscore-dangle": "off",
"eslint/no-var": "error",
"eslint/no-useless-call": "error",
"eslint/no-useless-computed-key": "error",

95
.semgrepignore Normal file
View File

@@ -0,0 +1,95 @@
# .semgrepignore — single source of truth for paths excluded from
# opengrep / semgrep scans run against this repo.
#
# Syntax: gitignore-style globs (https://git-scm.com/docs/gitignore).
# Consumed automatically by `opengrep scan` and `semgrep scan`. The compiled
# detector rulepacks under security/opengrep/ and the GitHub Actions workflows
# under .github/workflows/opengrep-*.yml all rely on this file rather than
# duplicating exclude lists in 50+ places.
#
# When adding a new test naming convention, fixture directory, or QA-tooling
# extension to the codebase, add its glob here so the security rulepacks
# stop firing on it. Real product code should never match anything in this
# file.
# ----------------------------------------------------------------------------
# Standard test file suffixes
# ----------------------------------------------------------------------------
*.test.*
*.spec.*
# ----------------------------------------------------------------------------
# Fixture & mock file suffixes (cover both .foo and -foo styles used in repo)
# ----------------------------------------------------------------------------
*.fixture.*
*-fixture.*
*-fixtures.*
*.mock.*
*-mock.*
*-mocks.*
# ----------------------------------------------------------------------------
# Test helper / harness / support / shared / utils naming conventions
# ----------------------------------------------------------------------------
*.test-helper.*
*.test-helpers.*
*-test-helpers.*
*.test-harness.*
*-test-harness.*
*.test-support.*
*-test-support.*
*.test-shared.*
*-test-shared.*
*.test-mocks.*
*-test-mocks.*
*.test-utils.*
*-test-utils.*
*.test-fixtures.*
*-test-fixtures.*
*.e2e-test-helpers.*
# Bare top-of-dir test helper files (e.g. extensions/foo/src/test-helpers.ts)
test-helper.*
test-helpers.*
test-harness.*
test-support.*
test-shared.*
test-utils.*
test-mocks.*
test-fixtures.*
test-fetch.*
test-manager-helpers.*
# ----------------------------------------------------------------------------
# Test / mock / fixture directories anywhere in the tree
# ----------------------------------------------------------------------------
__tests__/
__mocks__/
test/
tests/
test-fixtures/
test-fixture/
test-helpers/
test-utils/
test-support/
test-mocks/
test-harness/
fixtures/
mocks/
# ----------------------------------------------------------------------------
# QA tooling — entire QA-only directories and extensions, not product code
# ----------------------------------------------------------------------------
qa/
qa-lab/
extensions/qa-*/
# ----------------------------------------------------------------------------
# Top-level scripts that drive tests rather than ship product behavior
# ----------------------------------------------------------------------------
scripts/test-*
scripts/run-vitest*
scripts/run-tests*
scripts/lib/test-*
scripts/lib/extension-test-*
scripts/lib/vitest-*

View File

@@ -72,6 +72,7 @@ Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
- GH comments with markdown backticks, `$`, or shell snippets: avoid inline double-quoted `--body`; use single quotes or `--body-file`.
- PR execution artifacts/screenshots: attach them to the PR, comment, or an external artifact store. Do not add `.github/pr-assets` or other PR-only assets to the repo.
- PR review answer must explicitly cover: what bug/behavior we are trying to fix; PR/issue URL(s) and affected endpoint/surface; whether this is the best possible fix, with high-certainty evidence from code, tests, CI, and shipped/current behavior.
- When working on an issue or PR, always end the user-facing final answer with the full GitHub URL.
- CI polling: exact SHA, needed fields only. Example: `gh api repos/<owner>/<repo>/actions/runs/<id> --jq '{status,conclusion,head_sha,updated_at,name,path}'`.
- Post-land wait: minimal. Exact landed SHA only. If superseded on `main`, same-branch `cancel-in-progress` cancellations are expected; stop once local touched-surface proof exists. Never wait for newer unrelated `main` unless asked.
- Wait matrix:
@@ -141,6 +142,7 @@ Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
## Docs / Changelog
- Docs change with behavior/API. Use docs list/read_when hints; docs links per `docs/AGENTS.md`.
- Docs final answers: when doc files changed, end with the relevant full `https://docs.openclaw.ai/...` URL(s).
- Changelog user-facing only; pure test/internal usually no entry.
- Changelog placement: active version `### Changes`/`### Fixes`; every added entry must include at least one `Thanks @author` attribution, using credited GitHub username(s). Never add `Thanks @codex`, `Thanks @openclaw`, or `Thanks @steipete`.
- Changelog bullets are always single-line. No wrapping/continuation across multiple lines. Long entries stay on one long line so dedupe, PR-ref, and credit-audit tooling work and so the visual style stays uniform.
@@ -174,7 +176,7 @@ Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
- Before simulator/emulator testing, check real iOS/Android devices.
- "restart iOS/Android apps" = rebuild/reinstall/relaunch, not kill/launch.
- SwiftUI: Observation (`@Observable`, `@Bindable`) over new `ObservableObject`.
- Mac gateway: use app or `openclaw gateway restart/status --deep`; no ad-hoc tmux gateway. Logs: `./scripts/clawlog.sh`.
- Mac gateway: dev watch = `pnpm gateway:watch` (tmux `openclaw-gateway-watch-main`, auto-attach). Noninteractive: `OPENCLAW_GATEWAY_WATCH_ATTACH=0 pnpm gateway:watch`; attach/stop: `tmux attach -t openclaw-gateway-watch-main` / `tmux kill-session -t openclaw-gateway-watch-main`. Managed installs: `openclaw gateway restart/status --deep`. No launchd/ad-hoc tmux. Logs: `./scripts/clawlog.sh`.
- Version bump touches: `package.json`, `apps/android/app/build.gradle.kts`, `apps/ios/version.json` + `pnpm ios:version:sync`, macOS `Info.plist`, `docs/install/updating.md`. Appcast only for Sparkle release.
- Mobile LAN pairing: plaintext `ws://` loopback-only. Private-network `ws://` needs `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`; Tailscale/public use `wss://` or tunnel.
- A2UI hash `src/canvas-host/a2ui/.bundle.hash`: generated; ignore unless running `pnpm canvas:a2ui:bundle`; commit separately.
@@ -182,6 +184,8 @@ Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
## Ops / Footguns
- Remote install docs: `docs/install/{exe-dev,fly,hetzner}.md`. Parallels smoke: `$openclaw-parallels-smoke`; Discord roundtrip: `parallels-discord-roundtrip`.
- Memory wiki: keep prompt digest tiny. The prompt should only say the wiki exists, prefer `wiki_search` / `wiki_get`, start from `reports/person-agent-directory.md` for people routing, use search modes (`find-person`, `route-question`, `source-evidence`, `raw-claim`) when useful, and verify contact data before use.
- People wiki provenance: generated identity, social, contact, and "fun detail" notes need explicit source class/confidence (`maintainer-whois`, Discrawl sample/stat, GitHub profile, maintainer repo file). Do not promote inferred details to facts.
- Rebrand/migration/config warnings: run `openclaw doctor`.
- Never edit `node_modules`.
- Local-only `.agents` ignores: `.git/info/exclude`, not repo `.gitignore`.

View File

@@ -6,54 +6,389 @@ Docs: https://docs.openclaw.ai
### Changes
- Messages/docs: clarify that `BodyForAgent` is the primary inbound model text while `Body` is the legacy envelope fallback, and add Signal coverage so channel hardening patches target the real prompt path. Refs #66198. Thanks @defonota3box.
- Control UI/Usage: add UTC quarter-hour token buckets for the Usage Mosaic and reuse them for hour filtering, keeping the legacy session-span fallback for older summaries. (#74337) Thanks @konanok.
### Fixes
- Agents/tool-result guard: use the resolved runtime context token budget for non-context-engine tool-result overflow checks, so long tool-heavy sessions no longer compact early when `contextTokens` is larger than native `contextWindow`. Fixes #74917. Thanks @kAIborg24.
- Gateway/systemd: exit with sysexits 78 for supervised lock and `EADDRINUSE` conflicts so `RestartPreventExitStatus=78` stops `Restart=always` restart loops instead of repeatedly reloading plugins against an occupied port. Fixes #75115. Thanks @yhyatt.
- Agents/runtime: skip blank visible user prompts at the embedded-runner boundary before provider submission while still allowing internal runtime-only turns and media-only prompts, so Telegram/group sessions no longer leak raw empty-input provider errors when replay history exists. Fixes #74137. Thanks @yelog, @Gracker, and @nhaener.
- Plugins/runtime-deps: replace stale symlinked mirror target roots before writing runtime-mirror temp files and skip rewriting already materialized hardlinks, so cross-version container upgrades no longer crash-loop on read-only image-layer paths while warm mirrors do less churn. Fixes #75108; refs #75069. Thanks @coletebou and @xiaohuaxi.
- Auto-reply/group chats: fall back to automatic source delivery when a channel precomputes message-tool-only replies but the `message` tool is unavailable, so Discord/Slack-style group turns do not silently complete without a visible reply. Fixes #74868. Thanks @kagura-agent.
- Browser/gateway: share one browser control runtime across the HTTP control server and `browser.request`, and refresh browser profile config from the source snapshot, so CLI status/start honors configured `browser.executablePath`, `headless`, and `noSandbox` instead of falling back to stale auto-detection. Fixes #75087; repairs #73617. Thanks @civiltox and @martingarramon.
- Agents/subagents: bound automatic orphan recovery with persisted recovery attempts and a wedged-session tombstone, and teach task maintenance/doctor to reconcile those sessions so restart loops no longer require manual `sessions.json` surgery. Fixes #74864. Thanks @solosage1.
- Plugins/runtime-deps: keep bundled provider policy config loading from staging plugin runtime dependencies, so config reads no longer fail on locked-down `/var/lib/openclaw/plugin-runtime-deps` directories. Fixes #74971. Thanks @eurojojo.
- Memory/runtime-deps: retain the native `node-llama-cpp` runtime only when local memory search is configured, so packaged installs can repair local embeddings without relying on unreachable global npm installs. Fixes #74777. Thanks @LLagoon3.
- Gateway/startup: skip pre-bind web-fetch provider discovery for credential-free `tools.web.fetch` config, so Docker/Kubernetes gateways bind even when optional fetch limits are present. Fixes #74896. Thanks @KoykL.
- Signal: match group allowlists against inbound Signal group ids as well as sender ids, and process explicitly configured Signal groups without requiring mentions unless `requireMention` is set. Fixes #53308. Thanks @minupla and @juan-flores077.
- Signal: bound `signal-cli` installer release and archive downloads with explicit timeouts, declared and streamed size checks, and partial-file cleanup. Fixes #54153. Thanks @jinduwang1001-max and @juan-flores077.
- Slack: require bot-authored room messages with `allowBots=true` to come from an explicitly channel-allowlisted bot or from a room where an explicit Slack owner is present, so broad bot relays cannot run unattended. Fixes #59284. Thanks @andrewhong-translucent.
- Signal: derive `getAttachment` HTTP response caps from `channels.signal.mediaMaxMb` with base64 headroom, so inbound photos and videos no longer drop behind the 1 MiB RPC default. Fixes #73564. Thanks @heyhudson.
- Signal: keep the long-lived receive SSE monitor open while idle instead of applying the 10s RPC/check deadline, so `signal-cli` 0.14.3 event streams no longer reconnect before inbound messages arrive. Fixes #74741. Thanks @fgabelmannjr and @k7n4n5t3w4rt.
- CLI/progress: suppress nested progress spinners and line clears while TUI input owns raw stdin, so Crestodian `/status` no longer disturbs the active input row. (#75003) Thanks @velvet-shark.
- Models/OpenAI Codex: restore `openai-codex/gpt-5.4-mini` for ChatGPT/Codex OAuth PI runs after live OAuth proof, and align the manifest, forward-compat metadata, docs, and regression tests so stale cron and heartbeat configs resolve again. Fixes #74451. Thanks @0xCyda, @hclsys, and @Marvae.
- Plugins/runtime-deps: always write a dependency map in generated runtime-deps install manifests, so npm does not crash or prune staged bundled-plugin packages when the plan is empty. Fixes #74949. Thanks @hclsys.
- Telegram: use durable message edits for streaming previews instead of native draft state, so generated replies no longer flicker through draft-to-message transitions that look like duplicates. (#75073) Thanks @obviyus.
- Telegram: echo preflighted DM voice-note transcripts back to the originating chat, including Telegram DM topic thread metadata, instead of only echoing later media-understanding transcripts. Fixes #75084. Thanks @M-Lietz.
- Telegram: clamp low long-polling client timeouts so configured `timeoutSeconds` values below the `getUpdates` poll window no longer force a fresh HTTPS connection every few seconds. Fixes #75114. Thanks @hpinho77.
- Web search: describe `web_search` as using the configured provider instead of hard-coding Brave when DuckDuckGo or another provider is active. Fixes #75088. Thanks @sun-rongyang.
- Infra/tmp: tolerate concurrent temp-dir permission repairs by rechecking directories that another process already tightened, so parallel ACP subprocess startup no longer throws `Unsafe fallback OpenClaw temp dir`. Fixes #66867. Thanks @Kane808-AI and @jarvisz8.
- Agents/compaction: add an opt-in `agents.defaults.compaction.midTurnPrecheck` mid-turn precheck that detects tool-loop context pressure and triggers compaction before the next tool call instead of waiting for end-of-turn. (#73499) Thanks @marchpure and @haoxingjun.
## 2026.4.29
### Highlights
- Messaging and automation get active-run steering by default, visible-reply enforcement, spawned subagent routing metadata, and opt-in follow-up commitments for heartbeat-delivered reminders. Thanks @vincentkoc, @scoootscooob, @samzong, and @vignesh07.
- Memory grows into a people-aware wiki with provenance views, per-conversation Active Memory filters, partial recall on timeout, and bounded REM preview diagnostics. Thanks @vincentkoc, @quengh, @joeykrug, and @samzong.
- Provider/model coverage expands with NVIDIA onboarding/catalogs plus faster manifest-backed model/auth paths, Bedrock Opus 4.7 thinking parity, and safer Codex/OpenAI-compatible replay and streaming behavior. Thanks @eleqtrizit, @shakkernerd, @prasad-yashdeep, @woodhouse-bot, and @LyHug.
- Gateway and packaged-plugin reliability focuses on slow-host startup, reusable model catalogs, event-loop readiness diagnostics, runtime-dependency repair, stale-session recovery, and version-scoped update caches. Thanks @lpendeavors, @DerFlash, @vincentkoc, @pashpashpash, and @jhsmith409.
- Channel fixes cluster around Slack Block Kit limits, Telegram proxy/webhook/polling/send resilience, Discord startup/rate-limit handling, WhatsApp delivery/liveness, and Microsoft Teams/Matrix/Feishu edge cases. Thanks @slackapi, @SymbolStar, @djgeorg3, @TinyTb, @dseravalli, @nklock, and @alex-xuweilong.
- Security and operations add OpenGrep scanning, sharper GHSA triage policy, safer exec/pairing/owner-scope handling, Docker/onboarding automation, and web-fetch IPv6 ULA opt-in for trusted proxy stacks. Thanks @jesse-merhi, @pgondhi987, @mmaps, @jinjimz, and @jeffrey701.
### Changes
- Security/tools: configured tool sections (`tools.exec`, `tools.fs`) no longer implicitly widen restrictive profiles (`messaging`, `minimal`). Users who need those tools under a restricted profile must add explicit `alsoAllow` entries; a startup warning identifies affected configs. Fixes #47487. Thanks @amknight.
- Agents/commitments: add opt-in inferred follow-up commitments with hidden batched extraction, per-agent/per-channel scoping, heartbeat delivery, CLI management, a simple `commitments.enabled`/`commitments.maxPerDay` config, and heartbeat-interval due-time clamping so magical check-ins do not echo immediately. (#74189) Thanks @vignesh07.
- Messages/queue: make `steer` drain all pending Pi steering messages at the next model boundary, keep legacy one-at-a-time steering as `queue`, and add a dedicated steering queue docs page. Thanks @vincentkoc.
- Messages/queue: default active-run queueing to `steer` with a 500ms followup fallback debounce, and document the queue modes, precedence, and drop policies on the command queue page. Thanks @vincentkoc.
- Messages: add global `messages.visibleReplies` so operators can require visible output to go through `message(action=send)` for any source chat, while `messages.groupChat.visibleReplies` stays available as the group/channel override. Thanks @scoootscooob.
- Gateway/events: surface `spawnedBy` on subagent chat and agent broadcast payloads so clients can route child session events without an extra session lookup. (#63244) Thanks @samzong.
- Memory/wiki: add agent-facing people wiki metadata, canonical aliases, person cards, relationship graphs, privacy/provenance reports, evidence-kind drilldown, and search modes for person lookup, question routing, source evidence, and raw claims. Thanks @vincentkoc.
- Active Memory: add optional per-conversation `allowedChatIds` and `deniedChatIds` filters so operators can enable recall only for selected direct, group, or channel conversations while keeping broad sessions skipped. (#67977) Thanks @quengh.
- Active Memory: return bounded partial recall summaries when the hidden memory sub-agent times out, including the default temporary-transcript path, so useful recovered context is not discarded. (#73219) Thanks @joeykrug.
- Gateway/memory: add a read-only `doctor.memory.remHarness` RPC so operator clients can preview bounded REM dreaming output without running mutation paths. (#66673) Thanks @samzong.
- Providers/NVIDIA: add the NVIDIA provider with API-key onboarding, setup docs, static catalog metadata, and literal model-ref picker support so NVIDIA hosted models can be selected with their provider prefix intact. (#71204) Thanks @eleqtrizit.
- Models: suppress explicitly configured openai-codex/gpt-5.4-mini inline entries so a stale models config written by `openclaw doctor --fix` cannot bypass the manifest capability block and cause repeated assistant-turn failures when the runtime switches to that model on ChatGPT-backed Codex accounts. Conditional suppressions (e.g. qwen Coding Plan endpoint guards) remain bypassable by explicit user configuration. (#74451) Thanks @0xCyda, @hclsys, and @Marvae.
- Added SQLite-backed plugin state store (`api.runtime.state.openKeyedStore`) for restart-safe keyed registries with TTL, eviction, and automatic plugin isolation. Thanks @amknight.
- Plugin SDK: mark remaining legacy alias exports and diffs tool/config aliases with deprecation metadata, and add a guard so future legacy alias comments require `@deprecated` tags. Thanks @vincentkoc.
- CLI/QR/dependencies: internalize small terminal progress and QR wrapper helpers while keeping the real QR encoder dependency direct, reducing the default runtime dependency graph without changing QR output behavior. Thanks @vincentkoc.
- Dependencies: refresh workspace runtime, plugin, and tooling packages, including ACP, Pi, AWS SDK, TypeBox, pnpm, oxlint, oxfmt, jsdom, pdfjs, ciao, and tokenjuice, while keeping patched ACP behavior and lint gates current. Thanks @mariozechner.
- Gateway/dev: run `pnpm gateway:watch` through a named tmux session by default, with `gateway:watch:raw` and `OPENCLAW_GATEWAY_WATCH_TMUX=0` for foreground mode, so repeated starts respawn an inspectable watcher without trapping the invoking agent shell. Thanks @vincentkoc.
- Gateway/diagnostics: emit an opt-in startup diagnostics timeline that records gateway lifecycle and plugin-load phases behind a config flag, so slow-start diagnosis no longer requires bespoke instrumentation. Thanks @shakkernerd.
- Control UI/i18n: extend the locale registry with new Persian (fa), Dutch (nl), Vietnamese (vi), Italian (it), Arabic (ar), and Thai (th) entries and ship `fa`, `nl`, `vi`, and `zh-TW` docs glossaries, so the docs translation pipeline and the Control UI language picker stay aligned across surfaces. Thanks @vincentkoc.
- Channels: add Yuanbao channel docs entrance so the Tencent Yuanbao bot appears in the channel listing and sidebar navigation. (#73443) Thanks @loongfay.
- Channels/Yuanbao: update plugin GitHub location to YuanbaoTeam/yuanbao-openclaw-plugin and add "yuanbao" alias to channel catalog. (#74253) Thanks @loongfay.
- Docker setup: add `OPENCLAW_SKIP_ONBOARDING` so automated Docker installs can skip the interactive onboarding step while still applying gateway defaults. (#55518) Thanks @jinjimz.
- Security policy: classify media/base64 decode and format-conversion overhead after configured acceptance limits as performance-only for GHSA triage unless a report demonstrates a limit bypass, crash, exhaustion, data exposure, or another boundary bypass. (#74311)
- Security/OpenGrep: add a precise OpenGrep rulepack, source-rule compiler, provenance metadata check, and PR/full scan workflows that validate first-party code and rulepack-only changes while uploading SARIF to GitHub Code Scanning. (#69483) Thanks @jesse-merhi.
### Fixes
- Security/outbound: strip re-formed HTML tags during plain-text sanitization so nested tag fragments cannot leave a CodeQL-detected `<script>` sequence behind. Thanks @vincentkoc.
- Security/secrets: compare credential bytes with padded timing-safe buffers instead of hashing candidate passwords before equality checks. Thanks @vincentkoc.
- Security/QQBot: sanitize debug log arguments before writing to `console.*`, so gateway payload fields cannot forge extra log lines when debug logging is enabled. Thanks @vincentkoc.
- QQBot: unify slash command auth and c2cOnly gating in the command registry, pass `allowQQBotDataDownloads` when sending slash command file attachments, align clear-storage with actual downloads directory, and add `/bot-me` to display sender user ID. (#73616) Thanks @cxyhhhhh.
- CLI/agents/status: keep `openclaw agents`, text `agents list`, and plain text `status` on read-only metadata paths so human output no longer preloads plugin runtimes or live channel scans before printing. Fixes #74195. Thanks @NianJiuZst.
- Agents/local models: derive context-window guard thresholds from the effective model window with 4k/8k safety floors, so small local models are no longer rejected by fixed 16k/32k preflight cutoffs. Fixes #42999. Thanks @chengjialu8888.
- PDF extraction: resolve PDF.js standard fonts from the installed package root and pass a filesystem path to the Node fallback extractor, so built-in font PDFs render without `file://` URL lookup failures. Fixes #51455; carries forward #70936, #54447, and #62175. Thanks @anyech, @JuanRdBO, and @solomonneas.
- Media: treat legacy Word/OLE attachments with `application/msword` or `application/x-cfb` MIME as binary so printable-looking `.doc` files are not embedded into prompts as text. Fixes #54176; carries forward #54380. Thanks @andyliu.
- Config: accept documented `browser.tabCleanup` keys in strict root config validation, so configured tab cleanup no longer fails before runtime reads it. Fixes #74577. Thanks @lonexreb and @ezdlp.
- Cron: validate disabled job schedule edits before persisting updates, so invalid cron changes no longer partially mutate stored jobs. Fixes #74459. Thanks @yfge.
- CLI/cron: warn when `openclaw cron add --message` omits a nonblank `--agent`, including blank agent values and session-key jobs, so scheduled agent-turn jobs make default-agent fallback explicit while system events stay quiet. Fixes #42196; carries forward #42245. Thanks @ethanclaw.
- Channels/status: keep Telegram, Slack, and Google Chat read-only allowlist/default-target accessors on config-only paths, so status and channel summaries do not resolve SecretRef-backed runtime credentials. Thanks @eusine.
- Active Memory: clarify the deprecated `modelFallbackPolicy` warning and config help so `modelFallback` is described as a chain-resolution last resort, not runtime failover. (#74602) Thanks @jeffrey701.
- Channels/Discord: keep read-only allowlist/default-target accessors from resolving SecretRef-backed bot tokens, so status and channel summaries no longer fail when tokens are only available in gateway runtime. (#74737) Thanks @eusine.
- Gateway/sessions: align session abort wait semantics across `chat`, `agent`, and `sessions` server methods so abort RPCs return after the targeted sessions actually halt instead of resolving early while runs are still draining. (#74751) Thanks @BunsDev.
- Agents/output: drop copied inbound metadata-only assistant replay turns before provider replay instead of synthesizing a placeholder, so Telegram and other channels cannot receive `[assistant copied inbound metadata omitted]` as model output. Fixes #74745. Thanks @adamwdear and @Marvae.
- Doctor/memory: suppress skipped embedding-readiness warnings for key-optional providers such as Ollama and LM Studio while preserving timeout and not-ready diagnostics. Fixes #74608 and #73882. Thanks @hclsys.
- Channels/groups: preserve observe-only turn suppression for prepared dispatch paths and restore deprecated channel turn runtime aliases, so passive observer/group flows stay silent while older plugins keep compiling. Thanks @vincentkoc.
- Feishu: skip empty-text messages (e.g. `{"text":""}`) that carry no media, so no blank user turn is written to the session and downstream LLM providers cannot reject the request with "messages must not be empty". (#74634) Thanks @xdengli and @hclsys.
- Feishu/Bitable: clean up newly created placeholder rows whose fields contain only default empty values while preserving meaningful link, attachment, user, number, boolean, and location values during create-app cleanup. (#73920) Carries forward #40602. Thanks @boat2moon.
- macOS app: keep attach-only mode and the Debug Settings launchd toggle marker-only, so launching with `--attach-only`/`--no-launchd` no longer uninstalls the Gateway LaunchAgent or drops active sessions. (#72174) Thanks @DolencLuka.
- macOS Canvas: stop auto-reloading the current A2UI host during push/eval/snapshot flows, so pushed A2UI content remains visible instead of returning to the empty Canvas shell. Fixes #73337. Thanks @Gr4via.
- Plugin SDK: restore the deprecated `plugin-sdk/zalouser` command-auth facade so published Lark/Zalo plugins that import it load on current hosts. Fixes #74702. Thanks @Goron01.
- Plugins/runtime-deps: include bundled provider plugins when `models.providers`, auth profiles, agent defaults, or subagent model refs configure that provider, while keeping inactive default-enabled provider plugins out of doctor repair. Refs #74307. Thanks @Skeptomenos.
- Plugins/runtime: resolve relative plugin `api.resolvePath` inputs against the plugin root instead of the host working directory, while keeping absolute and home paths user-resolved. Fixes #74718. Thanks @jimdawdy-hub.
- Plugins/runtime-deps: refresh mirrored root chunks through a temporary file before replacing the active copy, so failed refreshes do not delete chunks that running plugin imports still need. Thanks @shakkernerd.
- Plugins/runtime-deps: prefer `require` conditional exports when building staged dependency aliases, so CommonJS-only plugin runtime deps such as `ws` do not resolve to ESM wrappers under Jiti. Fixes #74547. Thanks @aderius.
- Bonjour/Gateway: cap flapping advertiser restarts in a sliding window, so mDNS probing/name-conflict loops disable discovery instead of churning indefinitely on constrained hosts. Refs #74209 and #74242. Thanks @ndj888 and @Sanjays2402.
- Plugins/runtime-deps: verify staged package entry files before reusing mirrored runtime roots, so browser-control repairs incomplete `ajv`/MCP SDK installs after update instead of failing after restart on a missing `ajv/dist/ajv.js`. Refs #74630. Thanks @spickeringlr.
- Heartbeat: resolve `responsePrefix` template variables with the selected provider, model, and thinking context before delivering alerts or suppressing prefixed `HEARTBEAT_OK` replies. Fixes #43064; repairs #43065; supersedes #46858. Thanks @yweiii and @JunJD.
- Memory/LanceDB: show full memory UUIDs in the `memory_forget` candidate list so agents can pass the displayed ID back to targeted deletion without hitting the full-UUID validator. (#66913) Thanks @amittell.
- File-transfer plugin: require canonical read-path preflight authorization for `file.fetch`, fail closed when `dir.fetch` preflight entries are missing, absolute, or traversing, and recheck returned archive entries before handing archive bytes to callers. Carries forward #74134. Thanks @omarshahine.
- Channels/Feishu: retry file-typed iOS video resource downloads as `media` after a Feishu/Lark HTTP 502 and preserve the original 502 when the fallback also fails. Fixes #49855; carries forward #50164 and #73986. Thanks @alex-xuweilong.
- Providers/Amazon Bedrock: expose the full Claude Opus 4.7 thinking profile (`xhigh`, `adaptive`, and `max`) for Bedrock model refs, while keeping Opus/Sonnet 4.6 on adaptive-by-default, so `/think` menus and validation match the Anthropic transport behavior. Fixes #74701. Thanks @prasad-yashdeep, @sparkleHazard, @Sanjays2402, and @hclsys.
- Plugins/tokenjuice: compile the bundled plugin against tokenjuice 0.7.0's published OpenClaw host types instead of a local compatibility shim, so package contract drift fails in OpenClaw validation before release. Thanks @vincentkoc.
- OAuth/secrets: ignore root-level Google OAuth `client_secret_*.json` downloads so local client-secret files do not appear as commit candidates. (#74689) Thanks @jeongdulee.
- Memory: mirror `sqlite-vec` into packaged bundled-plugin runtime deps for the default memory plugin, so builtin vector search does not lose its SQLite extension after upgrading to 2026.4.27. Fixes #74692. Thanks @mozi1924.
- Gateway/startup: bound local discovery advertisement during startup, so a stuck discovery plugin can no longer keep the Gateway from reaching ready. Fixes #73865; refs #74630 and #74633. Thanks @lpendeavors, @moltar-bot, and @Saboor711.
- Gateway/models: serve the last successful model catalog while stale reloads refresh in the background, so Gateway control-plane and OpenAI-compatible requests no longer block behind model-provider rediscovery after model config changes. Refs #74135, #74630, and #74633. Thanks @DerFlash, @moltar-bot, and @Saboor711.
- CLI/status: resolve read-only channel setup runtime fallback from the packaged OpenClaw dist root, so `status --all`, `status --deep`, channel, and doctor paths do not crash when an external channel plugin needs setup metadata. Fixes #74693. Thanks @giangthb.
- SDK/events: keep per-run SDK event streams from surfacing duplicate raw chat projection frames, while normalizing chat-only projection frames and preserving raw access through `rawEvents`. Refs #74704. Thanks @BunsDev.
- SDK: report Gateway terminal `agent.wait` timeout snapshots with lifecycle metadata as `timed_out` while keeping bare wait deadlines non-terminal. Thanks @clawsweeper.
- Google Meet: block managed Chrome intro/test speech until browser health proves the participant is in-call, and expose `speechReady` diagnostics so login, admission, permission, and audio-bridge blockers no longer look like successful speech. Refs #72478. Thanks @DougButdorf.
- Slack/commands: keep native command argument menus on select controls for encoded choice values up to Slack's option limit and truncate fallback button labels to Slack's button-text limit, so long valid choices no longer render invalid Slack blocks. Thanks @slackapi.
- Agents/Codex: flush accepted debounced steering messages before normal app-server turn cleanup, so inbound follow-ups acknowledged as queued are not dropped when the turn completes before the debounce fires. Thanks @vincentkoc.
- Slack/interactive replies: keep rendered buttons and selects within Slack Block Kit value and count limits, and align command argument select values with Slack's option limit, so overlong agent-authored choices no longer make Slack reject the whole block payload. Thanks @slackapi.
- Slack/interactive replies: drop overlong Block Kit button URLs while preserving valid callback values, so malformed link buttons no longer make Slack reject the whole interactive reply. Thanks @slackapi.
- Slack/commands: truncate native command argument-menu confirmation text to Slack's dialog limit, so long plugin arg names no longer make fallback buttons render invalid Block Kit payloads. Thanks @slackapi.
- Slack/exec approvals: cap native approval metadata context to Slack's element and text limits, so large approval details no longer make Slack reject the approval card. Thanks @slackapi.
- Slack/exec approvals: cap native approval update fallback text to Slack's message limit while preserving the rendered approval blocks, so long commands no longer make resolved or expired approval cards stay stale after `chat.update` rejects `msg_too_long`. Thanks @slackapi.
- Slack/commands: cap native command argument-menu fallback rows to Slack's message block limit, so large plugin choice lists no longer make Slack reject the generated menu. Thanks @slackapi.
- Slack/commands: drop fallback command argument buttons whose encoded values exceed Slack's button-value limit, so one oversized plugin choice no longer makes Slack reject the whole menu. Thanks @slackapi.
- Slack/messages: merge message-tool presentation and interactive blocks on Slack sends, so buttons and selects are no longer dropped when a structured message body is also present. Thanks @slackapi.
- Slack/messages: cap Block Kit fallback text to Slack's send limit while preserving the rendered blocks, so long context fallbacks no longer make rich Slack messages fail with `msg_too_long`. Thanks @slackapi.
- Slack/messages: cap Block Kit fallback text on message edits while preserving the rendered blocks, so long context fallbacks no longer make Slack reject `chat.update` calls with `msg_too_long`. Thanks @slackapi.
- Channels/WhatsApp: require Baileys outbound message ids before marking auto-replies delivered, so transcript text and ack reactions no longer make failed group replies look sent. Fixes #49225. Thanks @TinyTb.
- CLI/update: scope packaged Node compile caches by OpenClaw version and install metadata, so global installs no longer reuse stale compiled chunks after package updates. Thanks @pashpashpash.
- Channels/Voice call: keep pre-auth webhook in-flight limiting active when socket remote address metadata is missing, so slow-body requests from stripped-IP proxy paths still share the fallback bucket. (#74453) Thanks @davidangularme.
- Plugin SDK/testing: lazy-load TypeScript from the plugin test-contract runtime and add release checks for critical SDK contract entrypoint imports and bundle size, so published packages fail preflight before shipping ESM-incompatible or oversized contract helpers. Thanks @vincentkoc.
- Channels/Microsoft Teams: treat configured `19:...@thread.tacv2` and legacy `19:...@thread.skype` team/channel IDs as already resolved during startup, avoiding false `channels unresolved` warnings while preserving Graph name lookup for display-name entries. Fixes #74683. Thanks @dseravalli.
- CLI/browser: preserve parent flags while lazy-loading browser subcommands, so `openclaw browser --json open` and `openclaw browser --json tabs` keep machine-readable output after reparsing. Fixes #74574. Thanks @devintegeritsm.
- Exec/elevated: preserve `turnSourceChannel` as `messageProvider` on approval-followup runs so `tools.elevated.allowFrom.<provider>` checks no longer fail with `provider=null` after the user approves an async elevated command. Fixes #74646. Thanks @xhd2015.
- Plugins/runtime-deps: add `openclaw plugins deps` inspection and repair with script-free package-manager defaults shared across plugin installers, so operators can repair missing bundled runtime deps without corrupting JSON output or blocking unrelated conflict-free deps. Thanks @vincentkoc.
- Agents/output: strip internal `[tool calls omitted]` replay placeholders from user-facing replies while preserving visible reply whitespace. Fixes #74573. Thanks @blaspat.
- Providers/Google Vertex: route authorized_user ADC credentials through OpenClaw's REST transport so Docker installs using gcloud application-default credentials no longer crash in the Google SDK before requests are sent. Fixes #74628. Thanks @frankhal2001-design.
- ACP/resolver: fall through to thread-bound session resolution when an explicit `--session` token cannot be resolved while preserving the bad-token diagnostic when no thread binding exists, so Discord slash commands that auto-fill the current thread ID as the positional ACP target no longer return "Unable to resolve session target" errors. Fixes #66299. Thanks @hclsys, @kindomLee, and @martingarramon.
- Agents/sessions: emit a terminal lifecycle backstop when embedded timeout/error turns return without `agent_end`, so Gateway sessions no longer stay stuck in `running` after failover surfaces a timeout. Fixes #74607. Thanks @millerc79.
- Gateway/diagnostics: include stuck-session reason hints and recovery skip causes in warnings, so operators can tell whether a lane is waiting on active work, queued work, or stale bookkeeping. Thanks @vincentkoc.
- Providers/DeepSeek: expose native DeepSeek V4 `xhigh` and `max` thinking levels through the provider `resolveThinkingProfile` hook so `/think xhigh|max` applies the intended effort instead of falling back to base levels. (#73008) Thanks @ai-hpc.
- Agents/Codex: bound embedded-run cleanup, trajectory flushing, and command-lane task timeouts after runtime failures, so Discord and other chat sessions return to idle instead of staying stuck in processing. Thanks @vincentkoc.
- Heartbeat/exec: consume successful metadata-only async exec completions silently so Telegram and other chat surfaces no longer ask users for missing command logs after `No session found`. Fixes #74595. Thanks @gkoch02.
- Web fetch: add a documented `tools.web.fetch.ssrfPolicy.allowIpv6UniqueLocalRange` opt-in and thread it through cache keys and DNS/IP checks so trusted fake-IP proxy stacks using `fc00::/7` can work without broad private-network access. Fixes #74351. Thanks @jeffrey701.
- OpenAI Codex: restore `/verbose full` persistence and app-server tool-output forwarding, and retry Gateway E2E temp-home cleanup so debug runs do not regress on stale validation or cleanup flakes. Thanks @vincentkoc.
- Anthropic/Meridian: preserve text and thinking content seeded on `content_block_start` in anthropic-messages streams, so `[thinking, text]` replies no longer persist as empty turns or trigger empty-response fallbacks. Fixes #74410. Thanks @vyctorbrzezowski.
- Channels/Matrix: complete the cross-signing handshake on `openclaw matrix verify confirm-sas` so the operator's other Matrix device clears its `Verifying…` loop instead of staying stuck after the agent confirms. (#74542) Thanks @nklock.
- CLI/status: honor channel-specific model context-window overrides when reporting effective context, so channel-scoped sessions reflect the active window in `openclaw status`. Thanks @HemantSudarshan.
- Sandbox/Docker: tolerate Docker daemon unavailability when sandbox mode is off, so doctor and preflight checks no longer fail on installs that do not run the Docker daemon. Fixes #73671. Thanks @kaseonedge.
- Control UI/mobile: persist mobile chat settings through Lit-managed state and route mobile navigation through the same view-state path so chat panel toggles survive transitions on small viewports. Thanks @BunsDev.
- Control UI/exports: align sidebar trigger affordances across the resizable divider, mobile layout, and exported-HTML transcript template so the sidebar toggle and exported transcript sidebar render with consistent hit areas and styling. Thanks @BunsDev.
- Control UI/chat: disable the page refresh affordance while a chat run is active so accidental refreshes do not abort an in-flight reply. Thanks @Angfr95 and @BunsDev.
- Memory/LanceDB: return real memory records from `openclaw ltm list` (with optional `--limit` and createdAt ordering) instead of an empty placeholder, so the CLI surface matches the documented LTM listing contract. (#67952) Thanks @zhangyue19921010.
- Media: include redacted per-attempt resize failures and resolved model input capabilities in vision-pipeline errors so ARM64 image failures are diagnosable without closing the remaining routing investigation. Refs #74552. Thanks @1yihui.
- Control UI/i18n: route zh-CN agent, debug, channel-refresh, and exec-approval copy through the locale source while preserving the English `Cron Jobs` agent tab label and the security-audit command styling. Carries forward #39692 repair context. Thanks @hepeng154833488 and @vincentkoc.
- Auto-reply: honor explicit `silentReply.direct: "allow"` for clean empty or reasoning-only direct chat turns while keeping the default direct-chat empty-response guard conservative. Fixes #74409. Thanks @jesuskannolis.
- OpenAI Codex: send a non-empty Responses input item when a Codex turn only has systemPrompt-backed instructions, avoiding ChatGPT backend 400s from `input: []`. Fixes #73820. Thanks @woodhouse-bot.
- Ollama: normalize provider-prefixed tool-call names at the native stream boundary so Kimi/Ollama calls such as `functions.exec` dispatch as `exec` instead of missing configured tools. Fixes #74487. Thanks @afurm and @carreipeia.
- Security/audit: resolve configured model aliases before model-tier and small-parameter checks, so alias-based GPT-5/Codex configs no longer report false weak-model warnings. Fixes #74455. Thanks @blaspat.
- CLI/agent: isolate Gateway-timeout embedded fallback runs under explicit `gateway-fallback-*` sessions so accepted Gateway runs cannot race transcript locks or replace the routed conversation session. Fixes #62981. Thanks @HemantSudarshan.
- CLI/QR/device-pair: reject malformed public setup URLs before issuing mobile pairing bootstrap tokens, while keeping valid bare host:port setup URLs supported. Thanks @Lucenx9.
- Models/UI: hide unauthenticated providers from the default Web chat, `/models`, and model setup pickers while keeping explicit full-catalog browse paths through `view: "all"`, `/models <provider> all`, and `models list --all`. Fixes #74423. Thanks @guarismo and @SymbolStar.
- Ollama: keep explicit local model runs on target-provider runtime hooks when PI discovery is skipped, so one-shot Ollama calls no longer cold-load unrelated provider runtimes before streaming. Fixes #74078. Thanks @sakalaboator.
- Slack/prompts: rely on Slack `interactiveReplies` guidance instead of generic `inlineButtons` config hints so enabled Slack button directives are not contradicted. Fixes #46647. Thanks @jeremykoerber.
- Slack/reactions: treat duplicate `already_reacted` responses as idempotent success so repeated agent reaction adds no longer surface as tool failures. Fixes #69005. Thanks @shipitsteven and @martingarramon.
- Channels/Discord: cool down Cloudflare/Error 1015 HTML 429 REST failures during startup application lookup and gateway metadata fetches, add `channels.discord.applicationId` as an app-id lookup bypass, sanitize HTML bodies before logging, and honor Retry-After before falling back to a conservative cooldown. Fixes #38853. (#74489) Thanks @djgeorg3 and @Garyko0730.
- Slack/tools: expose `fileId` in the shared message tool schema so `download-file` can receive Slack attachment IDs from inbound placeholders. Fixes #45574. Thanks @chadvegas.
- Exec: reject invalid per-call `host` values instead of silently falling back to the default target, so hostname-like values fail before commands run. Fixes #74426. Thanks @scr00ge-00 and @vyctorbrzezowski.
- Google/Gemini: send non-empty placeholder content when a Gemini run is triggered with empty or filtered user content, avoiding `contents is not specified` API errors. Thanks @CaoYuhaoCarl.
- Heartbeat: preserve non-task `HEARTBEAT.md` context around `tasks:` blocks and apply `agents.defaults.heartbeat` to all agents unless per-agent heartbeat entries restrict scope. Thanks @Sekhar03.
- Markdown: preserve paragraph breaks inside loose list items in shared outbound formatting while keeping tight list spacing stable. Thanks @Lucenx9.
- Build/Gateway: route restart, shutdown, respawn, diagnostics, command-queue cleanup, and runtime cleanup through one stable gateway lifecycle runtime entry so rebuilt packages do not strand long-running gateways on stale hashed chunks. Carries forward #73964. Thanks @pashpashpash.
- Memory/wiki: keep broad shared-source and generated related-link blocks from turning every page into a search hit, cap noisy backlinks, support all-term searches such as people-routing queries, and prefer readable page body snippets over generated metadata. Thanks @vincentkoc.
- Cron/Gateway: abort and bounded-clean up timed-out isolated agent turns before recording the timeout, so stale cron sessions cannot leave Discord or other chat lanes stuck in `processing` after a timeout. Thanks @vincentkoc.
- Agents/errors: suppress malformed streaming tool-call JSON fragments before they reach chat surfaces while preserving provider request-validation diagnostics. Fixes #59076; keeps #59080 as duplicate coverage. (#59118) Thanks @singleGanghood.
- CLI/models: restore provider-filtered `models list --all --provider <id>` rows for providers without manifest/static catalog coverage, including Anthropic and Amazon Bedrock, while keeping the compatibility fallback off expensive availability and resolver paths. Thanks @shakkernerd.
- CLI/models: keep manifest auth-evidence credentials visible across `models status`, auth probes, and PI model discovery so workspace-scoped provider auth does not disagree between listing, probing, and execution. Thanks @shakkernerd.
- CLI/models: move local credential evidence such as Google Vertex ADC into generic plugin manifest setup metadata so the model-list auth index stays declarative without provider-specific runtime branches. Thanks @shakkernerd.
- CLI/models: compute the `models list` Auth column through one command-local provider auth index so row rendering no longer repeats auth profile, env, configured-provider, AWS, or synthetic-auth checks per model row. Thanks @shakkernerd.
- CLI/models: move the OpenAI listable catalog into the plugin manifest so `models list --all --provider openai` uses the manifest fast path instead of loading provider runtime normalization hooks. Thanks @shakkernerd.
- CLI/tools: keep the Gateway `tools.*` RPC namespace out of plugin command discovery and managed proxy startup, so stray commands like `openclaw tools effective` fail quickly instead of cold-loading plugin metadata. Refs #73477. Thanks @oromeis.
- CLI/status: keep default text `openclaw status --usage` on metadata-only channel scans unless `--deep` or `--all` is set, and send stray `openclaw tools --help` through the precomputed root-help fast path so latency-triage commands avoid plugin/runtime cold loads before printing. Refs #73477 and #74220. Thanks @oromeis and @NianJiuZst.
- Agents/diagnostics: trace embedded-run startup and preparation stage timings before model I/O, and warn only on severe slow stages, so Docker/VPS latency reports can identify whether plugin loading, auth/model resolution, tool inventory, bootstrap, MCP/LSP, resource loading, or stream setup is dominating pre-run latency without noisy normal logs. Refs #73428. Thanks @Dimaoggg, @quangtran88, and @Heyvhuang.
- Agents/subagents: cache persisted subagent run registry reads by file signature while preserving fresh-parse isolation, so busy gateways stop reparsing unchanged `subagents/runs.json` on controller/list/status hot paths. Refs #72338. Thanks @argus-as.
- Gateway/clients: wait for the event loop to become responsive before opening Gateway WebSocket RPC/probe/client connections while charging that readiness wait to caller timeouts, so Windows deferred module-evaluation stalls no longer turn healthy loopback gateways into false handshake timeouts across status, TUI, ACP, MCP, node-host, and plugin client paths. Refs #74279 and #48270. Thanks @wongcode and @joost-heijden.
- Gateway/Windows: read listener command lines via PowerShell before falling back to `wmic`, so restart health can recognize OpenClaw listeners on modern Windows installs and avoid long anonymous-port waits. Refs #74280. Thanks @zym951223.
- Plugins/runtime-deps: record process start-time in bundled dependency install locks and expire recycled-PID locks, so Docker gateway restarts recover from stale `.openclaw-runtime-deps.lock` directories without waiting through repeated five-minute timeouts. Fixes #74346. (#74361) Thanks @jhsmith409.
- Plugins/runtime-deps: memoize packaged bundled runtime dist-mirror preparation after the first successful pass while keeping source-checkout mirrors refreshable, so constrained Docker/VPS installs avoid repeated root scans before chat turns. Refs #73428, #73421, #73532, and #73477. Thanks @Dimaoggg, @oromeis, @oadiazp, @jmfraga, @bstanbury, @antoniusfelix, and @jkobject.
- Channels/Discord: treat bare numeric outbound targets that match the effective Discord DM allowlist as user DMs while preserving account-specific legacy `dm.allowFrom` precedence over inherited root `allowFrom`. (#74303) Thanks @Squirbie.
- Channels/Discord/Slack: share one DM policy/allowlist resolver across runtime, setup, allowlist editing, and doctor repair, so legacy `dm.policy` / `dm.allowFrom` compatibility migrates to canonical `dmPolicy` / `allowFrom` without divergent access checks. Thanks @Squirbie.
- Control UI: make the chat sidebar split divider focusable, keyboard-resizable, ARIA-described, and pointer-event based so sidebar resizing works without a mouse. Thanks @BunsDev.
- Control UI/chat: wire the slash-command autocomplete menu to the composer with stable ARIA relationships so screen readers announce the active command or argument option. Thanks @BunsDev.
- Agents/usage: keep PI embedded-run telemetry attributed to the resolved model provider instead of the PI harness label, so OpenRouter and other provider-backed turns report the right provider in session usage and traces. Thanks @vincentkoc.
- Agents/attribution: send OpenClaw attribution headers on native OpenAI and Codex traffic, including SDK transports, realtime voice and TTS, device-code auth, WHAM usage, and remote embeddings, so PI-origin defaults no longer leak into provider requests. Thanks @vincentkoc.
- Agents/auth: keep OAuth auth profiles inherited from the main agent read-through instead of copying refresh tokens into secondary agents, and refresh Codex app-server tokens against the owning store so multi-agent swarms avoid reused refresh-token failures. Fixes #74055. Thanks @ClarityInvest.
- Channels/Telegram: honor `ALL_PROXY` / `all_proxy` and service-level `OPENCLAW_PROXY_URL` when constructing the HTTP/1-only Telegram Bot API transport, so Windows and service installs that rely on those proxy settings no longer fall back to direct egress. Fixes #74014; refs #74086. Thanks @SymbolStar.
- Channels/Telegram: keep raw host/network-unreachable Bot API connect failures non-fatal and route tagged polling uncaught exceptions through the Telegram restart path, so transient reachability failures no longer kill the Gateway or leave long polling stuck. Fixes #60515; refs #74540. Thanks @HemantSudarshan, @thacid22, and @ewimsatt.
- Channels/Telegram: continue polling when `deleteWebhook` hits a transient network failure but `getWebhookInfo` confirms no webhook is configured, so startup does not retry cleanup forever after the webhook was already removed. Refs #74086; carries forward #47384. Thanks @clovericbot.
- Channels/Telegram: retry native quote replies without `reply_parameters.quote` when Telegram returns `QUOTE_TEXT_INVALID`, so stale or truncated quote excerpts no longer drop the whole reply. Fixes #74581. Thanks @moeedahmed.
- Channels/Telegram: apply strict safe-send retry to inbound final replies when grammY wraps a pre-connect failure, while leaving ambiguous plain network envelopes single-shot to avoid duplicate visible messages. Fixes #74203. Thanks @nanli2000cn.
- Channels/Telegram: surface polling liveness warnings in channel status and doctor when a running long-poller has not completed `getUpdates` after startup grace or its transport activity is stale, so silent polling failures no longer look clean. Refs #74299. Thanks @lolaopenclaw.
- Channels/Telegram: publish webhook runtime state and warn when `setWebhook` has not completed after startup grace, so webhook-mode accounts no longer look healthy while registration is still failing or retrying. Refs #74299. Thanks @lolaopenclaw and @martingarramon.
- Channels/Telegram: bound native command menu `deleteMyCommands` and `setMyCommands` Bot API calls and allow the same timeout-triggered transport fallback retry as other startup control calls, so Windows/WSL network stalls cannot leave command sync hanging behind an otherwise running provider. Refs #74086. Thanks @SymbolStar.
- ACP/commands: accept forwarded ACP timeout config controls in the OpenClaw bridge, treat unsupported discard-close controls as recoverable cleanup, and restore native `/verbose full` plus no-arg status behavior, so Discord command menus and nested ACP turns no longer fail on supported session controls. Thanks @vincentkoc.
- Codex harness: interrupt and release native app-server turns that go quiet after an OpenClaw dynamic-tool response without sending `turn/completed`, so Discord and other chat lanes do not stay stuck in `processing`. Thanks @vincentkoc.
- Codex harness: bound OpenClaw dynamic tool responses to 30 seconds and fail closed with an explicit tool result when the app-server bridge would otherwise strand the turn in `processing`. Thanks @vincentkoc.
- TUI/status: clear stale `streaming` footer state when a final event arrives after the active run was already cleared and no tracked runs remain, while preserving concurrent-run ownership and inactive local `/btw` terminal handling. Fixes #64825; carries forward #64842, #64843, #64847, and #64862. Thanks @briandevans and @Yanhu007.
- Channels/Discord: fail startup closed when Discord cannot resolve the bot's own identity and keep mention gating active when only configured mention patterns can detect mentions, so the provider no longer continues with a missing bot id. Fixes #42219; carries forward #46856 and #49218. Thanks @education-01 and @BenediktSchackenberg.
- Channels/Discord: split long CJK replies at punctuation and code-point-safe fallback boundaries so Discord chunking stays readable without corrupting astral characters. Fixes #38597; repairs #71384. Thanks @p3nchan.
- TUI: keep the streaming watchdog alive across active tool/lifecycle proof-of-life, pause it during disconnects, and reload history after stale reconnect runs so long-running chats stop flipping to false idle or hanging on stale streaming. Fixes #69081. Thanks @EenvoudJasper.
- Browser/gateway: ignore Playwright dialog-close races from `Page.handleJavaScriptDialog` so browser automation no longer crashes the Gateway when a dialog disappears before Playwright accepts it. (#40067) Thanks @randyjtw.
- Cron/Gateway: defer missed isolated agent-turn catch-up out of the channel startup window, so overdue cron work cannot starve Discord or Telegram while providers connect after a restart. Thanks @vincentkoc.
- Heartbeat/cron: defer heartbeat turns while cron work is active or queued, add opt-in `heartbeat.skipWhenBusy` for subagent/nested lane pressure, and retry busy skips without advancing the schedule so local Ollama hosts do not run heartbeat and cron prompts concurrently. Fixes #50773. Thanks @scottgl9.
- Agents/thinking: honor configured model `compat.supportedReasoningEfforts` entries that include `xhigh`, so custom OpenAI-compatible provider refs expose and validate `/think xhigh` consistently across command menus, Gateway sessions, agent CLI, and `llm-task`. Carries forward #48904. Thanks @Milchstrassse and @wufunc.
- Vercel AI Gateway: expose provider-owned `/think xhigh` for trusted OpenAI/Codex upstream refs and Claude adaptive thinking for Anthropic upstream refs, while leaving untrusted namespaced refs on base levels. Carries forward #41561. Thanks @Zcg2021.
- Plugins/runtime-deps: prune stale `openclaw-unknown-*` bundled runtime dependency roots during Gateway startup while keeping recent or locked roots, so old staging debris cannot keep growing across restarts. Thanks @vincentkoc.
- Plugins/runtime-deps: include ten more root-package runtime dependencies (`@agentclientprotocol/sdk`, `@lydell/node-pty`, `croner`, `dotenv`, `jiti`, `json5`, `jszip`, `markdown-it`, `tar`, `web-push`) in `MIRRORED_CORE_RUNTIME_DEP_NAMES` so they are mirrored into the runtime-deps tree alongside `semver` and `tslog`, preventing `Cannot find package 'X'` failures from core dist code (for example `qmd-manager`, `cron/schedule`, `infra/archive`, `infra/push-web`, `infra/backup-create`, `process/supervisor/adapters/pty`) when no enabled extension owns the dependency. Adds a static drift guard test that scans `src/` for value imports of root-package deps and fails CI when one is missing from the mirror allowlist or extension-owned set. Refs #74199. Thanks @maxpuppet.
- Ollama: compose caller abort signals with guarded-fetch timeouts for native `/api/chat` streams, so `/stop` and early cancellation still interrupt local Ollama requests that also carry provider timeout budgets. Refs #74133. Thanks @obviyus.
- Doctor/TTS: migrate legacy `messages.tts.enabled`, agent TTS, channel TTS, and voice-call plugin TTS toggles to `auto` mode during `openclaw doctor --fix`, matching the documented TTS config contract. Thanks @vincentkoc.
- CLI/logs: fall back to the configured Gateway file log when implicit loopback Gateway connections close or time out before or during `logs.tail`, so `openclaw logs` still works while diagnosing local-model Gateway disconnects. Refs #74078. Thanks @sakalaboator.
- MCP/plugins: stringify non-array plugin tool results with chat-content coercion instead of default object stringification, so MCP callers receive useful JSON/text content from plugin tools. Thanks @vincentkoc.
- Active Memory/QMD: make gateway-start QMD refresh opt-in via `memory.qmd.update.startup`, keep normal memory access lazy, preserve interactive file watching, and align watcher dependency/build ignores with QMD's scanner so cold gateway startup no longer imports or initializes QMD by default. Thanks @codexGW.
- Channels/Discord: remove Discord-owned queued-run timeout replies through the shared channel lifecycle queue while preserving message ordering and compatibility timeout constants, so long Discord turns stay governed by session/tool/runtime lifecycle instead of channel fallback errors. Thanks @codexGW.
- Agents/tools: clamp `process.poll` waits to 30 seconds, advertise that cap in the tool schema, and honor abort signals while waiting, so long command polls cannot pin agent responsiveness after cancellation. Thanks @vincentkoc.
- Plugin SDK: add tracked Discord component-message helpers and a Telegram account-resolution compatibility facade, so existing plugins using those subpaths resolve while new plugins stay on generic channel SDK contracts. Thanks @vincentkoc.
- Shared labels: preserve Unicode combining marks and NFC-equivalent accented text in group/channel slug normalization so non-Latin labels no longer lose meaningful characters. Fixes #58932; carries forward #58942 and #58995. Thanks @fengqing-git, @Starhappysh, and @koen666.
- Channels/Telegram: include probed video width and height when sending regular Telegram videos, so portrait clips render with the correct orientation instead of being stretched by clients. (#18915) Thanks @storyarcade.
- Docs/Hetzner: clarify that SSH tunnel access requires `AllowTcpForwarding local` before running `ssh -L`, so hardened VPS sshd configs do not block loopback Gateway access. Fixes #54557; carries forward #54564; refs #54954. Thanks @satishkc7, @blackstrype, and @Aftabbs.
- Agents/config: preserve authored `agents.defaults.params` and per-model `agents.defaults.models[].params` during narrowed internal config writes, so OpenAI transport overrides such as `transport: "sse"` and `openaiWsWarmup: false` are not stripped from `openclaw.json`. Fixes #73607; refs #73428. Thanks @quangtran88.
- Agents/model config: resolve per-model extra params through canonical model keys while preserving legacy double-prefixed fallback entries, so provider-prefixed model ids such as `openrouter/auto` keep their configured runtime params. (#44319) Thanks @HenryXiaoYang.
- Gateway/shutdown: report structured shutdown warnings and HTTP close timeout warnings through `ShutdownResult` while preserving lifecycle hook hardening. Carries forward #41296. Thanks @edenfunf.
- Control UI: keep Agents Overview and config-form select dropdowns on their configured value after options render while preserving inherited agent model placeholders. Fixes #40352; carries forward #52948. Thanks @xiaoquanidea.
- Agents/exec: launch zsh, bash, and fish host exec shells with startup files suppressed while preserving existing PATH fallbacks, so daemon env is not overridden by shell startup files. Carries forward #40200; fixes #40179. Thanks @NewdlDewdl.
- Plugins/QA: prebuild the private QA channel runtime before plugin gauntlet source runs so wrapper CPU/RSS measurements are not polluted by private QA dist rebuild work. Thanks @vincentkoc.
- Plugins/QA: add a Kitchen Sink plugin gauntlet that installs the external package, checks command inventory, MCP tools, channel status, provider turns, gateway RSS, CPU, and fatal log anomalies. Thanks @vincentkoc.
- Plugins/config: reuse the bundled plugin alias scan within a single config normalization pass, so Kitchen Sink-style plugin configs no longer peg Gateway CPU by repeatedly rescanning bundled metadata before agent turns. Thanks @vincentkoc.
- Plugins/channels: reject malformed runtime channel registrations that omit required config helpers before they can poison channel status. Thanks @vincentkoc.
- MCP/plugins: serialize raw plugin tool return values through the plugin-tools MCP bridge so Kitchen Sink-style tools no longer surface `undefined` content. Thanks @vincentkoc.
- Gateway/reload: bound default restart deferral and SIGUSR1 restart drain to five minutes while preserving explicit `deferralTimeoutMs: 0` indefinite waits, so stale active work accounting cannot block config reloads forever. Thanks @vincentkoc.
- Active Memory: register the prompt-build hook with the configured recall timeout plus setup grace instead of the 150s maximum budget, so default memory recall cannot delay turn startup for multiple minutes. Thanks @vincentkoc.
- Gateway/readiness: include an `eventLoop` diagnostic block in local or authenticated `/readyz` responses with event-loop delay (p99 and max), event-loop utilization, CPU core ratio, and a `degraded` flag, so operators can see when slow startups or runaway turns stall the event loop. Thanks @vincentkoc.
- Gateway/agents: schedule accepted agent runs after the accepted RPC frame has a chance to flush, so pre-turn prompt/context work is less likely to starve immediate `agent.wait` callers. Thanks @vincentkoc.
- CLI/update: tolerate stale memory-runtime import failures during best-effort CLI process teardown, so `openclaw update` replacing hashed runtime chunks before the finalizer runs no longer surfaces as exit-time `Cannot find module` noise. Thanks @vincentkoc.
- CLI/channels logs: reuse the rolling log-file resolver so `openclaw channels logs` falls back to the active dated log across date boundaries without reading unrelated custom log files. Fixes #42875; carries forward #42904 and #43043. Thanks @ethanclaw and @wdskuki.
- CLI/update: skip tracked plugins disabled in config during post-update plugin sync before npm, ClawHub, or marketplace update checks, preserving their install records without failing the update. Fixes #73880. Thanks @islandpreneur007.
- Control UI: fix Peak Error Hours showing incorrect hourly rates when the browser's timezone observes DST, by storing hourly message counts with UTC date keys and using DST-aware `Date.getHours()` for local conversion. Also extract `accumulateMessageCounts` helper to reduce duplicated daily/hourly aggregation logic. (#49396) Thanks @konanok.
- iMessage: normalize known leading attributedBody corruption markers on sent-message echo text keys so delayed reflected echoes with U+FFFD/U+FFFE/U+FFFF/FEFF prefixes are dropped without collapsing interior text. Fixes #59973; carries forward #59980 and #62191. Thanks @neeravmakwana and @maguilar631697.
- Security/audit: recognize dangerous node command IDs as valid `gateway.nodes.denyCommands` entries, so audit only warns on real typos or unsupported patterns. (#56923) Thanks @chziyue.
- Cron: treat implicit text payloads with agent-turn overrides as agent turns, preserving model overrides for scheduled text prompts instead of pruning them as system events. Fixes #28905. (#64060) Thanks @liaoandi.
- Telegram/exec approvals: stop treating general Telegram chat allowlists and `defaultTo` routes as native exec approvers; Telegram now uses explicit `execApprovals.approvers` or owner identity from `commands.ownerAllowFrom`, matching the first-pairing owner bootstrap path. Thanks @pashpashpash.
- Plugins/providers: keep Gateway startup primary-model discovery on metadata-only provider entries and reuse active non-speech capability providers even with explicit plugin entries, avoiding unnecessary provider registry loads during startup and media capability checks. Fixes #73729, #73835, and #73793; carries forward #73853 and #73794. Thanks @sg1416-zg, @brokemac79, and @poolside-ventures.
- Chat commands: route sensitive group `/diagnostics` and `/export-trajectory` approvals and results to a private owner route, preferring same-surface DMs before falling back to the first configured owner route, so Discord group invocations can land in Telegram when that is the primary owner interface. Thanks @pashpashpash.
- Gateway/hooks: keep successful `deliver:false` agent hooks silent, log a hook audit record for suppressed success announcements, and suppress fallback summaries after attempted hook delivery while still surfacing failed hook runs. Repairs #55761; builds on #36332 and #49234. Thanks @EffortlessSteven, @cioclawcode, and @BrennerSpear.
- Plugin SDK/Discord: restore a deprecated `openclaw/plugin-sdk/discord` compatibility facade and the legacy compat group-policy warning export for the published `@openclaw/discord@2026.3.13` package, covering its config, account, directory, status, and thread-binding imports while keeping new plugins on generic SDK subpaths. Fixes #73685; supersedes #73703. Thanks @rderickson9 and @SymbolStar.
- Channels/Discord: suppress duplicate gateway monitors when multiple enabled accounts resolve to the same bot token, preferring config tokens over default env fallback and reporting skipped duplicates as disabled. Supersedes #73608. Thanks @kagura-agent.
- CLI/health: build channel health summaries from inspected credential metadata plus runtime state, so `openclaw health --json` reports Discord `running`, `connected`, and `tokenSource` consistently with channel status. Fixes #44354. Thanks @ferenc-acs.
- Control UI/Talk: decode Google Live binary WebSocket JSON frames and stop queued browser audio on interruption or shutdown, so browser Talk leaves `Connecting Talk...` and barge-in no longer plays stale audio. Fixes #73601 and #73460; supersedes #73466. Thanks @Spolen23 and @WadydX.
- Channels/Discord: ignore stale route-shaped conversation bindings after a Discord channel is reconfigured to another agent, while preserving explicit focus and subagent bindings. Fixes #73626. Thanks @ramitrkar-hash.
- Agents/bootstrap: pass pending BOOTSTRAP.md contents through the first-run user prompt while keeping them out of privileged system context, and show limited bootstrap guidance when workspace file access is unavailable. Fixes #73622. Thanks @mark1010.
- ACP/tasks: classify parent-owned ACP sessions as background work regardless of persistent runtime mode, and close terminal stale ACP sessions when no active binding remains, so delegated ACP output reports through the parent task notifier instead of acting like a normal foreground chat session. Refs #73609. Thanks @joerod26.
- Tasks: keep terminal mirrored TaskFlow timestamps pinned to task completion time and let maintenance repair stale mirrors, so ACP terminal delivery updates no longer leave inconsistent flow audits. Refs #73609. Thanks @joerod26.
- Gateway/sessions: add conservative stuck-session recovery that releases only stale session lanes while active embedded runs, reply operations, and lane tasks remain serialized, so queued follow-ups can drain without aborting legitimate long-running turns. Refs #73581, #73655, #73652, #73705, #73647, #73602, #73592, and #73601. Thanks @WS-Q0758, @bryangauvin, @spenceryang1996-dot, @bmilne1981, @mattmcintyre, @Vksh07, and @Spolen23.
- Plugins: cache unchanged plugin manifest loads by file signature, reducing repeated JSON/JSON5 parsing and manifest normalization in bursty startup and runtime registry paths. Refs #73532 and #73647; carries forward #73678. Thanks @TheDutchRuler.
- Plugins/runtime-deps: cache unchanged bundled runtime mirror dist-file materialization decisions and close file-lock handles on owner-write failures, reducing repeated startup chunk scans and avoiding FileHandle-GC recovery stalls. Refs #73532. Thanks @oadiazp and @bstanbury.
- Plugins/runtime-deps: retry and defer transient cleanup failures for owned runtime staging directories so CLI startup no longer aborts after a successful bundled dependency swap. Refs #73903. Thanks @bobfreeman1989.
- Plugins/runtime-deps: cache bundled runtime-deps JSON/package files by file signature, reducing repeated staged-runtime metadata reads during bundled channel startup. Refs #73647 and #73705. Thanks @mattmcintyre and @bmilne1981.
- Plugins/runtime-deps: delegate bundled plugin dependency staging to complete npm/pnpm install plans with durable runtime state, removing retained-manifest and source-checkout cache reconciliation from Gateway startup. Refs #73532. Thanks @oadiazp, @bstanbury, and @jmfraga.
- Plugins/runtime-deps: replace Gateway-start root chunk dependency inference with explicit mirrored-root dependency metadata, reducing staged runtime scans while preserving lazy per-plugin installs. Refs #73532. Thanks @oadiazp and @bstanbury.
- Plugins/runtime-deps: run pnpm staged installs outside the repository workspace and disable pnpm release-age gates for exact bundled runtime dependency materialization, so bundled plugin dependency repair writes packages into the generated stage without blocking fresh packaged dependencies. Refs #73532. Thanks @oadiazp and @bstanbury.
- CLI/TUI: keep `chat.history` off model-catalog discovery so initial Gateway-backed TUI history loads cannot block behind slow provider/plugin model scans on low-core hosts. Refs #73524. Thanks @harshcatsystems-collab.
- Channels/WhatsApp: flag recently reconnected linked accounts in channel status even when the socket is currently healthy, so flapping WhatsApp Web sessions no longer look clean after a brief reconnect. Refs #73602. Thanks @Vksh07.
- Channels/WhatsApp: log shared dispatcher delivery failures with reply kind, message id, chat id, and connection id, so typing-without-send reports can identify whether the WhatsApp send path rejected a generated reply. Refs #74269. Thanks @tomcosta-git.
- Feishu: suppress distinct late `final` text deliveries after a streaming card has already closed, while keeping media attachments deliverable, so late-finals no longer reopen duplicate Feishu cards. Fixes #71977. (#72294) Thanks @MonkeyLeeT.
- Gateway: expose `gateway.handshakeTimeoutMs` in config, schema, and docs while preserving `OPENCLAW_HANDSHAKE_TIMEOUT_MS` precedence, so loaded or low-powered hosts can tune local WebSocket pre-auth handshakes without patching dist files. Supersedes #51282; refs #73592 and #73652. Thanks @henry-the-frog.
- Gateway/TUI/status: align configured and env-based WebSocket handshake budgets across local clients, probes, and fallback RPCs while preserving explicit status timeouts and paired-device auth fallback, so slow local gateways are not marked unreachable by a shorter client watchdog. Refs #73524, #73535, #73592, and #73602. Thanks @harshcatsystems-collab, @DJBlackhawk, and @Vksh07.
- Gateway/startup: return retryable `UNAVAILABLE` during the sidecar startup window and keep CLI/TUI/status clients retrying inside their existing timeout budget, so early connects no longer surface as terminal handshake failures. Fixes #73652. Thanks @spenceryang1996-dot.
- Gateway/proxy: bypass inherited proxy environment for local Gateway control-plane WebSockets to `localhost` as well as loopback IPs, so Windows/WSL proxy settings cannot intercept local CLI/TUI Gateway connections. Supersedes #73474; refs #73602. Thanks @DhtIsCoding.
- Doctor/Gateway: use a lightweight `status` RPC without channel summary work for doctor Gateway liveness, so slow health snapshots do not falsely drive service restart repair. Fixes #64400; supersedes #64511. Thanks @CHE10X and @EronFan.
- Agents/auth: scope external CLI credential discovery to configured providers during model auth status and startup prewarm, so opencode-only and other single-provider gateways do not block on unrelated Claude CLI Keychain probes. Fixes #73908. Thanks @Ailuras.
- Agents/model selection: resolve slash-form aliases before provider/model parsing and keep alias-resolved primary models subject to transient provider cooldowns, so cron and persisted sessions do not retry cooled-down raw aliases. Fixes #73573 and #73657. Thanks @akai-shuuichi and @hashslingers.
- Agents/Claude CLI: reuse already-cached macOS Keychain credentials for no-prompt Claude credential reads, so doctor/runtime checks do not miss fresh interactive Claude auth. Fixes #73682. Thanks @RyanSandoval.
- Agents/Claude CLI doctor: scope workspace and project-dir checks to agents that actually use the Claude CLI runtime, so non-default Claude agents no longer make the default agent look Claude-backed. Fixes #73903. Thanks @bobfreeman1989.
- Gateway/sessions: expose effective agent runtime metadata on session rows, `sessions.patch`, and local `openclaw sessions --json`, while keeping Claude CLI-backed rows on the canonical model provider so runtime backend and model identity are no longer conflated. Fixes #73090. Thanks @vishutdhar.
- Gateway/auth status: scope external CLI credential overlays to configured providers, runtimes, or profiles and keep status reads off new Keychain prompts, so single-provider Gateway configs no longer probe unrelated Claude/Codex/MiniMax auth on startup. Fixes #73908. Thanks @Ailuras.
- Agents/runtime status: expose effective agent runtime metadata in `agents.list`, Control UI agent panels, and `/agents`, and avoid rendering stale or cumulative CLI token totals as live context usage. Fixes #73660, #73578, and #45268. Thanks @spartman, @DashLabsDev, and @xyooz.
- Agents/transcripts: strip empty assistant text blocks while preserving valid text, images, and signatures, so Anthropic-style providers no longer reject sanitized transcript turns. Fixes #73640. Thanks @jowhee327.
- Gateway/sessions: preserve session keys on hidden lifecycle events so channel-routed runs still persist terminal session state and do not strand session status as running after Codex turn completion. Thanks @cathrynlavery.
- Providers/Bedrock: omit deprecated `temperature` for Claude Opus 4.7 Bedrock model ids, named and application inference profiles, including dotted `opus-4.7` refs, and classify the nested validation response for failover. Fixes #73663. Thanks @bstanbury.
- Gateway: raise the preauth/connect-challenge timeout to 15s so cold CLI starts on slower hosts have more time to process the WebSocket challenge before the Gateway closes the connection. Fixes #51469; refs #73592 and #62060. Thanks @GothicFox and @jackychen-png.
- CLI/status: fall back to a bounded local `status` RPC when loopback detail probes time out or report unknown capability, so reachable local gateways are no longer marked unreachable by slow read diagnostics. Fixes #73535; refs #48360, #62762, #51357, and #42019. Thanks @RacecarGuy, @justinschille, @DJBlackhawk, @tianyaqpzm, and @0xrsydn.
- CLI/gateway: reuse cached paired-device auth during `gateway probe` and report post-connect diagnostic failures as degraded reachability, so healthy local gateways are no longer marked unreachable after loopback auth or read timeouts. Fixes #48360. Thanks @RacecarGuy.
- Channels/Discord: give Discord Gateway WebSocket handshakes a 30s timeout so stalled TLS/network transitions emit an error and Carbon can continue its reconnect loop instead of leaving the bot silent until restart. Refs #50046. Thanks @codexGW.
- Mattermost/WebSocket: send protocol ping/pong keepalives and terminate stale sessions when pongs stop arriving, so silent TCP drops reconnect instead of leaving monitoring idle. Fixes #41837; carries forward #57621; refs #50138, #44160, and #51104. Thanks @JasonWang1124.
- Channels/Telegram: suppress standalone failed edit/write warning payloads when a user-facing assistant error reply already covers the turn, while keeping unresolved mutating failures visible behind success-looking or suppressed-error replies. Fixes #39631; refs #73750; carries forward #39636 and #39717; leaves #39406 for configurable delivery policy. Thanks @Bartok9 and @Bortlesboat.
- Control UI/agents: persist the Set Default action through `agents.list[].default` instead of writing the unsupported `agents.defaultId` field, so saved default-agent changes survive config validation. Fixes #65565; carries forward #72585. Thanks @luyao618.
- NVIDIA/NIM: persist the `NVIDIA_API_KEY` provider marker and mark bundled NVIDIA Chat Completions models as string-content compatible, so NIM models load from `models.json` and OpenAI-compatible subagent calls send plain text content. Fixes #73013 and #50107; refs #73014. Thanks @bautrey, @iot2edge, @ifearghal, and @futhgar.
- Channels/Discord: let text-only configs drop the `GuildVoiceStates` gateway intent and expose a bounded `/gateway/bot` metadata timeout with rate-limited fallback logs, reducing idle CPU and warning floods. Fixes #73709 and #73585. Thanks @sanchezm86 and @trac3r00.
- Agents/sessions: mark same-turn `sessions_send` and A2A reply prompts with an inter-session `isUser=false` envelope before they reach the model, so foreign session output no longer lands as bare active user text. Fixes #73702; refs #73698, #73609, #73595, and #73622. Thanks @alvelda.
- Channels/Telegram: fail closed when account-level public DM settings conflict with a restrictive top-level `allowFrom`, and require an effective wildcard before `dmPolicy="open"` behaves as public access. Fixes #73756; refs #73698. Thanks @Hilo-Hilo and @xace1825.
- Channels/security: move open-DM allowlist semantics into the shared policy helpers and align Discord, Slack, Mattermost, Matrix, Feishu, LINE, IRC, Google Chat, Zalo, Zalo User, QQ Bot, and Synology Chat so `dmPolicy="open"` is public only with an effective wildcard and otherwise still respects sender allowlists. Refs #73756 and #73698. Thanks @Hilo-Hilo and @xace1825.
- ACP/tasks: sweep orphaned parent-owned ACP sessions whose task records are gone, preserving bound persistent sessions but clearing unbound stale ACPX metadata so old child sessions cannot silently respawn into chat. Fixes #73609. Thanks @joerod26.
- Outbound/security: strip known internal runtime scaffolding such as `<system-reminder>` and `<previous_response>` at the final channel delivery boundary and keep Discord output on targeted tag stripping, so degraded harness replies cannot leak those tags to users. Fixes #73595. Thanks @gabrielexito-stack and @martingarramon.
- Security/Telegram: load Telegram security adapters in read-only audit/doctor, audit malformed Telegram DM `allowFrom` entries even when groups are disabled, and keep allowlist DM audits from counting stale pairing-store senders, so public/shared-DM risk checks stay accurate. Refs #73698. Thanks @xace1825.
- Plugins: remove hidden manifest, provider-owner, bootstrap, and channel metadata caches so plugin installs, manifest edits, and bundled-root changes are visible on the next metadata read while keeping runtime/module loader caches for actual plugin code. Thanks @shakkernerd.
- CLI/plugins: use plugin metadata snapshots for install slot selection and add opt-in plugin lifecycle timing traces, so plugin install avoids runtime-loading the plugin registry for metadata-only decisions. Thanks @shakkernerd.
- fix(plugins): restrict bundled plugin dir resolution to trusted package roots. (#73275) Thanks @pgondhi987.
- fix(security): prevent workspace PATH injection via service env and trash helpers. (#73264) Thanks @pgondhi987.
- Active Memory: allow `allowedChatTypes` to include explicit portal/webchat sessions and classify `agent:...:explicit:...` session keys before opaque session ids can shadow the chat type. Fixes #65775. (#66285) Thanks @Lidang-Jiang.
- Active Memory: allow the hidden recall sub-agent to use both `memory_recall` and the legacy `memory_search`/`memory_get` memory tool contract, so bundled `memory-lancedb` recall works without breaking the default `memory-core` path. Fixes #73502. (#73584) Thanks @Takhoffman.
- fix(device-pairing): validate callerScopes against resolved token scopes on repair [AI]. (#72925) Thanks @pgondhi987.
- Active Memory docs: document the `cacheTtlMs` 1000-120000 ms range and 15000 ms default so setup snippets do not lead users past the schema limit. Fixes #65708. (#65737) Thanks @WuKongAI-CMU.
- fix(agents): canonicalize provider aliases in byProvider tool policy lookup [AI]. (#72917) Thanks @pgondhi987.
- fix(security): block npm_execpath injection from workspace .env [AI-assisted]. (#73262) Thanks @pgondhi987.
- Tools/web_fetch: decode response bodies from raw bytes using declared HTTP, XML, or HTML meta charsets before extraction, so Shift_JIS and other legacy-charset pages no longer return mojibake. Fixes #72916. Thanks @amknight.
- Active Memory: skip payload-less `memory_search` transcript tool results when building debug telemetry, so newer empty entries no longer hide the latest useful debug payload. (#68773) Thanks @SimbaKingjoe.
- Active Memory: keep recall setup time from consuming the configured model timeout while giving the hook runner an explicit bounded budget for the plugin, so slow embedded-run setup no longer causes immediate recall timeouts. Fixes #72606. (#72620) Thanks @hyspacex.
- Channels/Discord: bound message read/search REST calls, route those actions through Gateway execution, and fall back to `CommandTargetSessionKey` for inbound hook session keys so Discord reads do not hang and hooks still fire when `SessionKey` is empty. Fixes #73431. (#73521) Thanks @amknight.
- Plugins/media: auto-enable provider plugins referenced by `agents.defaults.imageGenerationModel`, `videoGenerationModel`, and `musicGenerationModel` primary/fallback refs, so configured Google and MiniMax media providers do not stay disabled behind a restrictive plugin allowlist. Thanks @vincentkoc.
- Memory-core/dreaming: retry managed dreaming cron registration after startup when the cron service is not reachable yet, so the scheduled Memory Dreaming Promotion sweep recovers without waiting for heartbeat traffic. Fixes #72841. Thanks @amknight.
- Acpx/runtime: validate the runtime session mode at the `AcpxRuntime.ensureSession` wrapper boundary so callers that pass anything other than `persistent` or `oneshot` get a clear `ACP_INVALID_RUNTIME_OPTION` error instead of silently round-tripping through the encoded handle as a default `persistent` mode and later throwing `SessionResumeRequiredError`. Investigation context: #73071. (#73548) Thanks @amknight.
- CLI/infer: keep web-search fallback on missing provider API keys, preserve structured validation errors from the selected provider, and let per-request image describe prompts override configured media-entry prompts. (#63263) Thanks @Spolen23.
- Chat commands: include configured model-catalog reasoning metadata when building `/think` argument menus so Ollama Cloud and other provider-owned reasoning models show supported levels instead of only `off`. Fixes #73515; supersedes #73568. Thanks @danielzinhu99 and @neeravmakwana.
- Channels/Telegram: suppress generic tool-progress chatter when preview streaming is off, so non-streaming Telegram turns only deliver final replies while approvals, media, and errors still route normally. Refs #72363 and #72482. Thanks @neeravmakwana and @SweetSophia.
- CLI/model probes: add repeatable image `--file` inputs to `infer model run` for local and gateway multimodal model smokes, so vision models such as Ollama Qwen VL and Gemini can be tested through the raw model-probe surface. Fixes #63700. Thanks @cedricjanssens.
- CLI/model probes: request trusted operator scope for `infer model run --gateway --model <provider/model>` so Gateway raw model smokes can use one-off provider/model overrides instead of being rejected before provider auth resolution. Fixes #73759. Thanks @chrislro.
- CLI/image describe: pass `--prompt` and `--timeout-ms` through `infer image describe` and `describe-many`, so custom vision instructions and slow local model budgets reach media-understanding providers such as Ollama, OpenAI, Google, and OpenRouter. Refs #63700. Thanks @cedricjanssens.
- Model selection: include the rejected provider/model ref and allowlist recovery hint when a stored session override is cleared, so local model selections such as Gemma GGUF variants do not fall back to the default with a generic message. Refs #71069. Thanks @CyberRaccoonTeam.
- OpenAI-compatible providers: drop malformed event-only or blank-data SSE frames before the OpenAI SDK stream parser sees them, so proxies that split `event:` from `data:` no longer crash streaming runs with `Unexpected end of JSON input`. Fixes #52802. Thanks @LyHug.
- Gateway/OpenAI-compatible streaming: strip `<final>` tags split across streamed model deltas before they reach SSE clients, so `/v1/chat/completions` no longer emits tag remnants or drops content when final-answer wrappers cross chunk boundaries. Fixes #63325. Thanks @tzwickl.
- Ollama: resolve explicitly selected signed-in `:cloud` models through `/api/show` when `/api/tags` omits them, so working models such as `gemini-3-flash-preview:cloud` and `deepseek-v4-pro:cloud` do not fail dynamic model resolution before the native `/api/chat` transport runs. Fixes #73909. Thanks @chtse53.
- Discord/exec approvals: keep the local `/approve` prompt when no native Discord approval runtime is active, and send a manual fallback notice when native approval delivery reaches no targets, so failed DM cards no longer leave approval turns silent or dependent on model-written shell commands. Fixes #73954; carries forward #74027. Thanks @guarismo and @brokemac79.
- Local model prompt caching: keep stable Project Context above volatile channel/session prompt guidance and stop embedding current channel names in the message tool description, so Ollama, MLX, llama.cpp, and other prefix-cache backends avoid avoidable full prompt reprocessing across channel turns. Fixes #40256; supersedes #40296. Thanks @rhclaw and @sriram369.
- Gateway/OpenAI-compatible API: guard provider policy lookup against runtime providers with non-array `models` values, so `/v1/chat/completions` no longer fails with `provider?.models?.some is not a function`. Fixes #66744; carries forward #66761. Thanks @MightyMoud, @MukundaKatta.
- WhatsApp/Web: pass explicit Baileys socket timings into every WhatsApp Web socket and expose `web.whatsapp.*` keepalive, connect, and query timeout settings so unstable networks can avoid repeated 408 disconnect and opening-handshake timeout loops. Fixes #56365. (#73580) Thanks @velvet-shark.
- WhatsApp/Web: recover recently active listeners when a post-408 reconnect keeps receiving transport frames but stops delivering app messages, while keeping group metadata fallback off Baileys sends. Fixes #63855 and #66920; refs #7433, #67986, #70856, #60007, and #72621. Thanks @legonhilltech-jpg, @octopuslabs-fl, @Kanorin-chan, and @stuswan.
- Channels/Telegram: persist native command metadata on target sessions so topic, helper, and ACP-bound slash commands keep their session metadata attached to the routed conversation. (#57548) Thanks @GaosCode.
- Channels/native commands: keep validated native slash command replies visible in group chats while preserving explicit owner allowlists for command authorization. (#73672) Thanks @obviyus.
- Pairing/doctor: bootstrap `commands.ownerAllowFrom` from the first approved DM pairing when no command owner exists, and have doctor explain missing owners so privileged slash commands are not accidentally unusable after onboarding. Thanks @pashpashpash.
- Telegram/exec: infer native exec approvers from `commands.ownerAllowFrom` and auto-enable the Telegram approval client when an owner is resolvable, so owner-only commands such as `/diagnostics` can be approved in Telegram without duplicate per-channel approver config. Thanks @pashpashpash.
- Auto-reply/session: carry the tail of user/assistant turns into the freshly-rotated transcript on silent in-reply session resets (compaction failure, role-ordering conflict) so direct-chat continuity survives the rebind. Fixes #70853. (#70898) Thanks @neeravmakwana.
- Skills: load grouped skill directories such as `skills/<group>/<skill>/SKILL.md` from configured skill roots while keeping grouped discovery capped for large directories. Fixes #56915. (#72534) Thanks @ottodeng, @MoerAI, and @i010542.
- Config: skip malformed non-string `env.vars` entries before env-reference checks, so config loading no longer crashes on JSON values like numbers or booleans. (#42402) Thanks @MiltonHeYan.
- Docker Compose: default missing config and workspace bind mounts to `${HOME:-/tmp}/.openclaw` so manual compose runs do not create invalid empty-source volume specs. (#64485) Thanks @jlapenna.
- Agents/context engines: preserve the child agent's configured `agentDir` when subagent cleanup re-resolves a context engine, so `onSubagentEnded` hooks keep operating on the correct per-agent state. (#67243) Thanks @jarimustonen.
- Channels/WhatsApp: restrict pairing verification replies to real inbound user content, preventing unsolicited prompts from receipts, typing indicators, presence updates, and other non-message Baileys upserts. Fixes #73797. (#73823) Thanks @hclsys.
- Configure/Ollama: show the configured Ollama model allowlist after Cloud only or Cloud + Local setup and skip slow per-model cloud metadata fetches. (#73995) Thanks @obviyus.
- Channels/WhatsApp: detect explicit group `@mentions` again when the bot's own E.164 is in `allowFrom`, so shared-number setups no longer skip group pings that directly mention the bot. Fixes #49317. (#73453) Thanks @juan-flores077.
- WhatsApp/reliability: publish real transport-liveness into WhatsApp channel status and force earlier reconnects on silent transport stalls, so quiet healthy sessions stay connected while wedged sockets recover before the later remote 408 path. (#72656) Thanks @Sathvik-1007.
- Core/channels: tighten selected runtime, media, and plugin edge-case handling while preserving existing behavior. Thanks @jesse-merhi.
- Channels/WhatsApp: strip leaked plural tool-call XML wrappers on every WhatsApp-visible outbound path and keep channel error payloads out of WhatsApp chats. (#71830) Thanks @rubencu.
- Agents/embedded-runner: inject the resolved OAuth bearer (and forward the run abort signal) on the boundary-aware embedded stream fallback so models that route through `openai-codex-responses` and other boundary-aware transports stop failing with `401 Unauthorized: Missing bearer or basic authentication in header`. Fixes #73559. (#73588) Thanks @openperf.
- Telegram/gateway: bound outbound Bot API calls and cache bundled plugin alias lookup so slow Telegram sends or WSL2 filesystem scans no longer wedge gateway replies. (#74210) Thanks @obviyus.
- Configure/GitHub Copilot: reuse existing Copilot auth during configure and show the provider's manifest model catalog in the model picker. (#74276) Thanks @obviyus.
- Configure/models: keep the model picker scoped to the selected manifest provider and enable its bundled plugin before catalog lookup, so choosing GitHub Copilot no longer falls back to Ollama or skips the catalog. (#74322) Thanks @obviyus.
- Auto-reply/subagents: reject `/focus` from leaf subagents and scope fallback target resolution to the requesting subagent's children, so subagents cannot bind conversations outside their control boundary. (#73613) Thanks @drobison00.
- Gateway/startup: skip inherited workspace startup memory for sandboxed spawned sessions without real-workspace write access, so `/new` no longer preloads host workspace memory into isolated child runs. (#73611) Thanks @drobison00.
- Agents/tool policy: validate caller group IDs against session or spawned context before applying group-scoped tool policies or persisting gateway group metadata, so forged group IDs cannot unlock more permissive tools. (#73720) Thanks @mmaps.
- Commands: keep channel-prefixed owner allowlist entries scoped to matching providers so webchat command contexts cannot inherit external channel owners. Thanks @zsxsoft.
- Auth/device pairing: bound bootstrap handoff token issuance, redemption, and approved pairing baselines to the documented per-role scope allowlist, so bootstrap approvals cannot persistently grant `operator.admin`, `operator.pairing`, or `node.exec` scopes. Thanks @eleqtrizit.
- Providers/GitHub Copilot: support the GUI/RPC wizard device-code auth flow so onboarding from non-TTY clients (gateway RPC bridge, GUI wizards) completes instead of returning empty profiles. Dangerous-state handling now distinguishes `access_denied` and `expired_token` from transport errors. (#73290) Thanks @indierawk2k2.
- Installer/Linux: warn before switching an unwritable npm global prefix to `~/.npm-global`, then tell users to run future global updates with `npm i -g openclaw@latest` without `sudo` so npm keeps using the redirected user prefix. Fixes #44365; carries forward #50479. Thanks @Sayeem3051.
- Gateway/plugins: enable the native `require()` fast path on Windows for bundled plugin modules so plugin loading uses `require()` instead of Jiti's transform pipeline, reducing startup from ~39s to ~2s on typical 6-plugin setups. Fixes #68656. (#74173) Thanks @galiniliev.
- macOS app: detect stale Gateway TLS certificate pins, automatically repair trusted Tailscale Serve rotations, and surface paired-but-disconnected Mac companion nodes so partial Gateway connections no longer look healthy. Thanks @guti.
## 2026.4.27
### Highlights
- Codex Computer Use setup now ships with status/install commands, marketplace discovery, and fail-closed MCP checks for Codex-mode desktop control. Thanks @pash-openai.
- DeepInfra joins the bundled provider set with model discovery, media generation/editing, TTS, embeddings, and provider-owned onboarding policy. Thanks @ats3v.
- Tencent Yuanbao and QQBot support expand channel coverage with Yuanbao docs/catalog entries and QQBot group chat, streaming, media upload, and pipeline refactors. Thanks @loongfay and @cxyhhhhh.
- Plugin startup and model catalogs move toward manifest-first metadata, reducing Gateway boot work and making provider rows/aliases/suppressions easier to audit. Thanks @shakkernerd.
- Reliability fixes cover Telegram startup/sends, Slack socket/media stalls, gateway startup prewarm, session/history defaults, update sync, and Windows restart handoffs. Thanks @joerod26, @obviyus, @shivasymbl, @freerk, @bassboy2k, @jpreagan, @islandpreneur007, and @Thatgfsj.
### Changes
- Sandbox/Docker: add opt-in `sandbox.docker.gpus` passthrough for Docker sandbox containers so local GPU workloads can run inside sandboxed agents when the host Docker runtime supports `--gpus`. Fixes #57976; carries forward #58124. Thanks @cyan-ember.
- iOS/Gateway: add an authenticated `node.presence.alive` protocol event and `node.list` last-seen fields so background iOS wakes can mark paired nodes recently alive without treating them as connected. Carries forward #63123. Thanks @ngutman.
- Android: publish authenticated `node.presence.alive` events after node connect and background transitions so paired Android nodes retain durable last-seen metadata after disconnects. Carries forward #63123. Thanks @ngutman.
- Gateway/chat: accept non-image attachments through `chat.send` by staging them as agent-readable media paths, while keeping unsupported RPC attachment paths explicit instead of silently dropping files. Fixes #48123. (#67572) Thanks @samzong.
- Security/networking: add opt-in operator-managed outbound proxy routing (proxy.enabled + proxy.proxyUrl/OPENCLAW_PROXY_URL) with strict http:// forward-proxy validation, loopback-only Gateway bypass, and cleanup of proxy env/dispatcher state on exit. (#70044) Thanks @jesse-merhi and @joshavant.
### Fixes
- Plugins/startup: precompute bundled runtime mirror fingerprints before taking the mirror lock, including dist-runtime canonical roots, so Docker Desktop/WSL cold starts no longer hold `.openclaw-runtime-mirror.lock` while scanning slow persisted volumes. Fixes #73339. Thanks @1yihui.
- Channels/LINE: persist inbound image, video, audio, and file downloads in `~/.openclaw/media/inbound/` instead of temporary files so agents can still read LINE media after `/tmp` cleanup. Fixes #73370. Thanks @hijirii and @wenxu007.
- Control UI/WebChat: keep large attachment payloads out of Lit state and optimistic chat messages, using object URL previews plus send-time payload serialization so PDF/image uploads no longer trigger `RangeError: Maximum call stack size exceeded`. Fixes #73360; refs #54378 and #63432. Thanks @hejunhui-73, @Ansub, and @christianhernandez3-afk.
- Agents/Anthropic: cancel stalled Anthropic Messages SSE body reads when abort signals fire, so active-memory timeouts release transport resources instead of leaving hidden recall runs parked on `reader.read()`. Refs #72965 and #73120. Thanks @wdeveloper16.
- Agents/models: keep per-agent primary models strict when `fallbacks` is omitted, so probe-only custom providers are not tried as hidden fallback candidates unless the agent explicitly opts in. Fixes #73332. Thanks @haumanto.
- Gateway/models: add `models.pricing.enabled` so offline or restricted-network installs can skip startup OpenRouter and LiteLLM pricing-catalog fetches while keeping explicit model costs working. Fixes #53639. Thanks @callebtc, @palewire, and @rjdjohnston.
- Onboarding: pin interactive and non-interactive health checks to the just-configured setup token/password so stale `OPENCLAW_GATEWAY_TOKEN` or `OPENCLAW_GATEWAY_PASSWORD` values do not produce false gateway-token-mismatch failures after setup. Fixes #72203. Thanks @galiniliev.
- Doctor/state: require an interactive confirmation before archiving orphan transcript files, so `openclaw doctor --fix` no longer silently renames recoverable session history after upgrades regenerate `sessions.json`. Fixes #73106. Thanks @scottgl9.
- Cron/Telegram: preserve explicit `:topic:` delivery targets over stale session-derived thread IDs when isolated cron announces to Telegram forum topics. Carries forward #59069; refs #49704 and #43808. Thanks @roytong9.
- Build/runtime: write the runtime-postbuild stamp after `pnpm build` writes the build stamp, so the next CLI invocation does not re-sync runtime artifacts after a successful build. Fixes #73151. Thanks @bittoby.
- Build/runtime: preserve staged bundled-plugin runtime dependency caches across source-checkout tsdown rebuilds, so local CLI and gateway-watch rebuilds no longer recreate large plugin dependency trees before starting. Refs #73205. Thanks @SymbolStar.
- CLI/channels: list configured chat channel accounts from read-only setup metadata even when the standalone CLI has not loaded the runtime channel registry, so `openclaw channels list` shows Telegram accounts before auth providers. Fixes #73319 and #73322. Thanks @mlaihk.
- CLI/model probes: keep `infer model run --gateway` raw by skipping prior session transcript, bootstrap context, context-engine assembly, tools, and bundled MCP servers, so local backends can be tested without full agent-context overhead. Fixes #73308. Thanks @ScientificProgrammer.
- CLI/model probes: reject empty or whitespace-only `infer model run --prompt` values before calling local providers or the Gateway, so smoke checks do not spend provider calls on invalid turns. Fixes #73185. Thanks @iot2edge.
- Gateway/media: route text-only `chat.send` image offloads through media-understanding fields so `agents.defaults.imageModel` can describe WebChat attachments instead of leaving only an opaque `media://inbound` marker. Fixes #72968. Thanks @vorajeeah.
- Gateway/Windows: route no-listener restart handoffs through the Windows supervisor without leaving restart tokens in flight, so failed task scheduling can be retried and successful handoffs do not coalesce later restart requests. (#69056) Thanks @Thatgfsj.
- Gateway/model pricing: skip plugin manifest discovery during background pricing refreshes when `plugins.enabled: false`, so disabled-plugin setups do not keep rebuilding plugin metadata from the Gateway hot path. Fixes #73291. Thanks @slideshow-dingo and @fishgills.
- Ollama/thinking: validate `/think` commands against live Ollama catalog reasoning metadata, so models whose `/api/show` capabilities include `thinking` expose `low`, `medium`, `high`, and `max` instead of being stuck on `off`. Fixes #73366. Thanks @cymise.
- Gateway/sessions: remove automatic oversized `sessions.json` rotation backups, deprecate `session.maintenance.rotateBytes`, and teach `openclaw doctor --fix` to remove the ignored key so hot session writes no longer copy multi-MB stores. Refs #72338. Thanks @midhunmonachan and @DougButdorf.
- Channels/Telegram: fail fast when Telegram rejects the startup `getMe` token probe with 401, so invalid or stale BotFather tokens are reported as token auth failures instead of misleading `deleteWebhook` cleanup failures. Fixes #47674. Thanks @samaedan-arch.
- ACPX: keep generated Codex and Claude ACP wrapper startup paths working when remote or special state filesystems reject chmod, since OpenClaw invokes the wrappers through Node instead of executing them directly. Fixes #73333. Thanks @david-garcia-garcia.
- CLI/onboarding: infer image input for common custom-provider vision model IDs, ask only for unknown models, and keep `--custom-image-input`/`--custom-text-input` overrides so vision-capable proxies do not get saved as text-only configs. Fixes #51869. Thanks @Antsoldier1974.
- Models/OpenAI Codex: stop listing or resolving unsupported `openai-codex/gpt-5.4-mini` rows through Codex OAuth, keep stale discovery rows suppressed with a clear API-key-route hint, and leave direct `openai/gpt-5.4-mini` available. Fixes #73242. Thanks @0xCyda.
- Plugin SDK: restore the root `stringEnum` and `optionalStringEnum` exports on both the published SDK entry and runtime root-alias bridge, so older external plugins can keep building and loading while migrating to focused SDK subpaths. Fixes #68279. Thanks @marzliak.
- Plugin SDK: restore the root-alias bridge for `registerContextEngine` and expose missing legacy compat helpers `normalizeAccountId` and `resolvePreferredOpenClawTmpDir` so older external plugins such as `openclaw-weixin` can keep loading while migrating to focused SDK subpaths. Fixes #53497. Thanks @alanxchen85.
- Auth profiles: make `openclaw doctor --fix` migrate legacy flat `auth-profiles.json` files such as `{ "ollama-windows": { "apiKey": "ollama-local" } }` to canonical provider default API-key profiles with a backup, so custom Ollama/OpenAI-compatible providers recover cleanly after upgrading. Fixes #59629; supersedes #59642. Thanks @Xsanders555 and @Linux2010.
- Memory/Dreaming: retry Dream Diary once with the session default when a configured dreaming model is unavailable, while leaving subagent trust and allowlist errors visible instead of silently masking configuration problems. Refs #67409 and #69209. Thanks @Ghiggins18 and @everySympathy.
- Feishu/inbound files: recover CJK filenames from plain `Content-Disposition: filename=` download headers when Feishu exposes UTF-8 bytes through Latin-1 header decoding, while leaving valid Latin-1 and JSON-derived names unchanged. (#48578, #50435, #59431) Thanks @alex-xuweilong, @lishuaigit, and @DoChaoing.
- Channels/Telegram: normalize accidental full `/bot<TOKEN>` Telegram `apiRoot` values at runtime and teach `openclaw doctor --fix` to remove the suffix, so startup control calls no longer 404 when direct Bot API curl commands work. Fixes #55387. Thanks @brendanmatthewjones-cmyk, @techfindubai-ux, and @Sivlerback-Chris.
- Zalo Personal: persist refreshed `zca-js` session cookies after QR login, session restore, and successful API calls so gateway restarts restore the freshest local session. (#73277) Thanks @darkamenosa.
- Logging/security: redact sensitive tokens (sk-\* keys, Bearer/Authorization values, etc.) at the subsystem console sink so `createSubsystemLogger().info/warn/error` output that bypasses the patched console-capture handler still applies the same redaction the file transport already does. Fixes #73284; refs #67953 and #64046. Thanks @edwin-rivera-dev.
- Plugins/runtime deps: reuse enclosing versioned cache roots when bundled plugins resolve from nested staged paths, so plugin-runtime-deps no longer mints `openclaw-unknown-*` directories or loops on `ENOTEMPTY`. Fixes #72956. (#73205) Thanks @SymbolStar.
- Agents/failover: classify CJK provider transport, quota, billing, auth, and overload error text so Chinese-language provider failures trigger fallback and user-facing transport copy instead of surfacing as unclassified raw errors. (#56242) Thanks @tomcatzh.
- Agents/failover: seed non-claude-cli fallback prompts with Claude Code session context when a claude-cli attempt fails, so fallback models do not restart cold after billing or quota failover. (#72069) Thanks @stainlu.
## 2026.4.27
### Changes
- Dependencies: refresh provider and tooling dependencies, including AWS SDK, PI runtime packages, AJV, Feishu SDK, Anthropic SDK, tokenjuice, and native TypeScript/oxlint tooling. Thanks @dependabot.
- Matrix/QA: add live Matrix approval scenarios for exec metadata, chunked fallback, plugin approvals, deny reactions, thread targeting, and `target: "both"` delivery, with redacted artifacts preserving safe approval summaries. Thanks @gumadeiras.
- Diagnostics/Codex: add owner-only core `/diagnostics` with a sensitive-data preamble, docs link, and explicit Gateway export approval guidance; Codex harness sessions also ask before uploading Codex feedback for the attached thread and print the matching `codex resume <thread-id>` inspection command after confirmed upload. Thanks @pashpashpash.
- Trajectory export: route `/export-trajectory` through per-run exec approval, send group-chat approval prompts and export results only to the owner privately, and add `openclaw sessions export-trajectory` for the approved command path. Thanks @pashpashpash.
- Codex: add Computer Use setup for Codex-mode agents, including `/codex computer-use status/install`, marketplace discovery, optional auto-install, and fail-closed MCP server checks before Codex-mode turns start. Fixes #72094. (#71842) Thanks @pash-openai.
- Apps: consume Peekaboo 3.0.0-beta4 and ElevenLabsKit 0.1.1, align Swabble on Commander 0.2.2, and refresh macOS/iOS SwiftPM resolutions against the released dependency graph. Thanks @Blaizzy.
- Plugin SDK: expose shared channel route normalization, parser-driven target resolution, raw-target compact keys, parsed-target types, and route comparison helpers through `openclaw/plugin-sdk/channel-route`, switch native approval origin matching onto that route contract with optional delivery and match-only target normalization, and retire the internal channel-route shim behind dated compatibility aliases for legacy key/comparable-target helpers. Thanks @vincentkoc.
@@ -92,6 +427,92 @@ Docs: https://docs.openclaw.ai
### Fixes
- CLI/channel-setup: auto-skip the redundant "Install \<plugin\>?" confirmation when only one install source (npm or local) exists, show `download from <npm-spec>` hints for installable catalog channels in the picker, and suppress misleading npm hints for already-bundled channels. Fixes #73419. Thanks @sliverp.
- BlueBubbles: tighten DM-vs-group routing across the outbound session route (`chat_guid:iMessage;-;...` DMs no longer classified as groups), reaction handling (drop group reactions that arrive without any chat identifier instead of synthesizing a `"group"` literal peerId), inbound `chatGuid` fallback (no longer fall back to the sender's DM chatGuid when resolving a group whose webhook omits chatGuid+chatId+chatIdentifier), and short message id resolution (carry caller chat context so a numeric short id reused after a long group conversation cannot silently resolve to a message in a different chat, with the same cross-chat guard applied to full GUIDs so retries cannot bypass it). Thanks @zqchris.
- Gateway/sessions: clone cached session stores through the persisted JSON shape instead of `structuredClone`, reducing native-memory growth on the remaining #54155 Gateway RSS/session-accumulation path while keeping #54155 as the broader tracker and carrying forward the #45438 session-cache hypothesis. Thanks @vincentkoc and the #45438 reporters/commenters.
- Agents/approvals: fail restart-interrupted sessions whose transcript tail is still `approval-pending` instead of replaying stale exec approval IDs into the new Gateway process after restart. Fixes #65486. Thanks @mjmai20682068-create.
- CLI/Gateway: use method-specific least-privilege scopes for classified CLI Gateway calls while preserving legacy broad scopes for unclassified plugin methods, so read-only commands no longer create admin/write/pairing scope-upgrade prompts. Fixes #68634. Thanks @nightmusher.
- Gateway/sessions: align `chat.history` and `sessions.list` thinking defaults with owning-agent and catalog-aware resolution so Control UI session defaults match backend runtime state. (#63418) Thanks @jpreagan.
- Devices/pairing: recover array-shaped device and node pairing state files before persisting approvals, so UUID-keyed pending and paired entries no longer disappear after a malformed JSON store write. Fixes #63035. Thanks @sar618.
- Gateway/auth: clear reused stale device tokens and stop reconnecting on device-token mismatch in the Control UI and Node gateway clients, avoiding rate-limit loops after scope-upgrade or token-rotation handoffs. Fixes #71609. Thanks @ricksayhi.
- Gateway/approvals: treat duplicate same-decision approval resolves as idempotent during the resolved-entry grace window, including consumed `allow-once` approvals, while returning an explicit already-resolved error for conflicting repeats. Fixes #59162; refs #58479 and #65486. Thanks @wikithoughts, @sajazuniga7-coder, and @mjmai20682068-create.
- Channels/Telegram: honor `approvals.exec/plugin.targets[].accountId` when routing native approvals across multi-bot Telegram accounts while preserving unscoped Telegram targets for any account. Fixes #69916. Thanks @joerod26.
- Agents/exec: omit the internal session-resume fallback preface from successful async exec completion messages sent directly back to chat. Fixes #67181. Thanks @raistlin88.
- Agents/media: register detached `video_generate` and `music_generate` tool run contexts until terminal status, so Discord-backed provider jobs stay live in `/tasks` instead of becoming `lost` when the parent chat run context disappears. Thanks @vincentkoc.
- Agents/media: prefer OpenAI image and video providers when the default model uses the OpenAI Codex auth alias, so auto media generation no longer falls through to Fal before GPT Image or Sora. Thanks @vincentkoc.
- Tasks/media: infer agent ownership for session-scoped task records so `/tasks` agent-local fallback includes session-backed `video_generate` and other async media jobs even when the current chat session has no linked rows. Thanks @vincentkoc.
- Agents/media: keep long-running `video_generate` and `music_generate` tasks fresh while provider jobs are still pending, so task maintenance does not mark active Discord media renders lost before completion. Thanks @vincentkoc.
- CLI/status: treat scope-limited gateway probes as reachable-but-degraded in shared status scans, so `openclaw status --all` no longer reports a live gateway as unreachable after `missing scope: operator.read`. Fixes #49180; supersedes #47981. Thanks @openjay.
- Slack/Socket Mode: use a 15s Slack SDK pong timeout by default and add `channels.slack.socketMode.clientPingTimeout`, `serverPingTimeout`, and `pingPongLoggingEnabled` overrides so stale-websocket handling no longer depends on app-event health heuristics. Fixes #14248; refs #58519, #64009, and #63488. Thanks @shivasymbl and @freerk.
- Slack/media: bound private file and forwarded attachment downloads with idle and total timeouts while preserving placeholder fallback, so stalled Slack `file_share` media no longer wedges inbound message handling. Fixes #61850. Thanks @bassboy2k.
- Plugins/inspector: keep bundled plugin runtime capture quiet and config-tolerant for Codex, memory-lancedb, Feishu, Mattermost, QQBot, and Tlon so plugin-inspector JSON checks can validate the full bundled set. Thanks @vincentkoc.
- Slack/auto-reply: keep fully consumed text reset triggers such as `new session` out of `BodyForAgent` after directive cleanup, so configured Slack reset phrases do not leak into the fresh model turn. Fixes #73137. Thanks @neeravmakwana.
- Plugins/runtime deps: prune stale retained bundled runtime deps and keep doctor/secret channel contract scans on lightweight artifacts, so disabled bundled channels stop preserving old dependency trees or importing heavy plugin surfaces. Thanks @SymbolStar and @vincentkoc.
- Auto-reply: bound the post-run pending tool-result delivery drain with a progress-aware idle timeout, so a never-settling tool-result task no longer leaves the session active forever while slow healthy deliveries can keep draining. Fixes #53889; supersedes #64733 and #73434. Thanks @zijunl and @wujiaming88.
- Gateway/startup: start chat channels without waiting for primary model prewarm, keeping model warmup bounded in the background so Slack and other channels come online promptly when provider discovery is slow. Supersedes #73420. Thanks @dorukardahan.
- Gateway/install: carry env-backed config SecretRefs such as `channels.discord.token` into generated service environments when they are present only in the installing shell, while keeping gateway auth SecretRefs non-persisted. Fixes #67817; supersedes #73426. Thanks @wdimaculangan and @ztexydt-cqh.
- Auto-reply/commands: stop bare `/reset` and `/new` after reset hooks acknowledge the command, so non-ACP channels no longer fall through into empty provider calls while `/reset <message>` and `/new <message>` still seed the next model turn. Fixes #73367 and #73412. Thanks @hoyanhan, @wenxu007, and @amdhelper.
- Providers/DeepSeek: backfill DeepSeek V4 `reasoning_content` on plain assistant replay messages as well as tool-call turns, so thinking sessions with prior tool use no longer fail follow-up requests with missing reasoning content. Fixes #73417; refs #71372. Thanks @34262315716 and @Bartok9.
- Agents/gateway tool: strip full config payloads from `config.patch` and `config.apply` tool responses while preserving direct RPC responses, so config-heavy sessions no longer replay large redacted configs into transcript history. Fixes #47610; supersedes #73439. Thanks @HanenVit and @juan-flores077.
- Auto-reply: preserve voice-note media from silent turns while continuing to suppress text and non-voice media, so `NO_REPLY` TTS replies still deliver the requested audio bubble. (#73406) Thanks @zqchris.
- Channels/Mattermost: stop enqueueing regular inbound posts as system events, so Mattermost user messages reach the model only as user-role inbound-envelope content instead of also appearing as `System: Mattermost message...` directives. Fixes #71795. Thanks @juan-flores077.
- Agents/media: qualify bare `agents.defaults.imageModel` and `pdfModel` refs from unique configured image-capable providers, so Ollama vision models such as `moondream` and `qwen2.5vl:7b` do not fall through to the default provider. Fixes #38816; supersedes #73396. Thanks @alainasclaw and @vincentkoc.
- Agents/Anthropic: send implicit Anthropic beta headers only to direct public Anthropic endpoints, including OAuth, so custom Anthropic-compatible providers no longer mis-handle unsupported beta flags unless explicitly configured. Refs #73346. Thanks @byBrodowski.
- Skills: require explicit `skills.entries.coding-agent.enabled` before exposing the bundled coding-agent skill, so installs with Codex on PATH but no OpenAI auth do not silently offer Codex delegation. Fixes #73358. Thanks @LaFleurAdvertising and @Sanjays2402.
- Plugins/startup: treat manifestless Claude bundles as valid installed-plugin registry entries instead of stale missing manifests, so workspace bundles no longer force repeated derived registry rebuilds or noisy `plugins.entries.workspace` warnings during Gateway startup. Fixes #73433. Thanks @AnneVoss.
- Agents/subagents: preserve `sessions_yield` as a paused subagent state and ignore its wait text while freezing completion output, so parent sessions wait for the final post-compaction answer instead of receiving intermediate progress or `(no output)`. Fixes #73413. Thanks @Ask-sola.
- Plugins/startup: precompute bundled runtime mirror fingerprints before taking the mirror lock and keep Docker bundled plugin runtime deps/mirrors in a Docker-managed volume instead of the Windows/WSL config bind mount, so cold starts avoid slow host-volume mirror writes. Fixes #73339. Thanks @1yihui.
- Plugins/runtime deps: refresh bundled runtime mirrors without deleting active import trees, so config-triggered restarts do not see transient missing plugin files during registration. Thanks @shakkernerd.
- Channels/LINE: persist inbound image, video, audio, and file downloads in `~/.openclaw/media/inbound/` instead of temporary files so agents can still read LINE media after `/tmp` cleanup. Fixes #73370. Thanks @hijirii and @wenxu007.
- CLI/plugins: keep bundled plugin installs out of `plugins.load.paths` while preserving install records, so install/inspect/doctor loops no longer warn about the current bundled plugin directory. Thanks @vincentkoc.
- CLI/plugins: scope `plugins inspect <id>` runtime loading to the matched plugin so single-plugin inspection does not load every plugin before checking the target. Thanks @shakkernerd.
- CLI/plugins: remove managed copied-path plugin directories during uninstall and plan uninstall from metadata instead of runtime-loading plugins, so plugin lifecycle commands avoid unnecessary bundled runtime-deps work. Thanks @shakkernerd.
- Cron tool: infer the creating session's agentId for `cron.add` jobs when `agentId` is omitted or passed as undefined, keeping scheduled agentTurn jobs routed to the session agent; #40571 identified the guard bug and supplied the focused regression coverage. Thanks @ChanningYul.
- Cron/Telegram: add `--thread-id` to `openclaw cron add` and `openclaw cron edit`, preserving Telegram forum topic delivery targets across scheduled announcements. Carries forward #51581, #60373, and #60890. Thanks @ChunHao-dev.
- Cron/Telegram: preserve session-derived Telegram topic thread IDs when isolated cron delivery explicitly targets the parent chat, keeping bare chat targets in the active forum topic without leaking stale topics to other chats. Carries forward #64708. Thanks @addelh.
- Memory/compaction: keep pre-compaction memory-flush prompts runtime-only so session transcripts and `chat.history` no longer expose them as normal user turns. Fixes #54408 and #58956; refs #43567. Thanks @markgong and @guoyuhang9.
- Control UI/WebChat: keep large attachment payloads out of Lit state and optimistic chat messages, using object URL previews plus send-time payload serialization so PDF/image uploads no longer trigger `RangeError: Maximum call stack size exceeded`. Fixes #73360; refs #54378 and #63432. Thanks @hejunhui-73, @Ansub, and @christianhernandez3-afk.
- Agents/Anthropic: cancel stalled Anthropic Messages SSE body reads when abort signals fire, so active-memory timeouts release transport resources instead of leaving hidden recall runs parked on `reader.read()`. Refs #72965 and #73120. Thanks @wdeveloper16.
- Control UI/WebChat: keep pending run and typing state attached to the active client run, so unowned inject/announce/side-result finals no longer unlock unrelated active runs while completed owned runs still clear promptly. Fixes #57795; carries forward the narrow diagnosis from #57887. Thanks @haoyu-haoyu.
- Sandbox/Docker: stop satisfying a missing default sandbox image by tagging plain Debian as `openclaw-sandbox:bookworm-slim`, preserving the Python tooling required by sandbox write/edit helpers and directing users to build the default image. Fixes #51185; refs #45108, #51099, #51609, and #57713. Thanks @dpalis, @Tin55FoilDev, @jbcohen2-coder, @macminihal-cyber, and @PraxoOnline.
- Control UI/WebChat: confirm toolbar New Session button resets before dispatching `/new` while leaving typed `/new` and `/reset` commands immediate. Fixes #45800; refs #27065, #56611, #54499, and #27110. Thanks @aethnova, @kosta228-huli, @adambezemek, and @xss925175263 (xianshishan).
- Agents/models: keep per-agent primary models strict when `fallbacks` is omitted, so probe-only custom providers are not tried as hidden fallback candidates unless the agent explicitly opts in. Fixes #73332. Thanks @haumanto.
- Gateway/models: add `models.pricing.enabled` so offline or restricted-network installs can skip startup OpenRouter and LiteLLM pricing-catalog fetches while keeping explicit model costs working. Fixes #53639. Thanks @callebtc, @palewire, and @rjdjohnston.
- Gateway/startup: warn when legacy `CLAWDBOT_*` or `MOLTBOT_*` environment variables are still present, pointing users to `OPENCLAW_*` names instead of failing silently. Fixes #53482; carries forward #53667. Thanks @lndyzwdxhs.
- Onboarding: pin interactive and non-interactive health checks to the just-configured setup token/password so stale `OPENCLAW_GATEWAY_TOKEN` or `OPENCLAW_GATEWAY_PASSWORD` values do not produce false gateway-token-mismatch failures after setup. Fixes #72203. Thanks @galiniliev.
- Doctor/state: require an interactive confirmation before archiving orphan transcript files, so `openclaw doctor --fix` no longer silently renames recoverable session history after upgrades regenerate `sessions.json`. Fixes #73106. Thanks @scottgl9.
- Cron/Telegram: preserve explicit `:topic:` delivery targets over stale session-derived thread IDs when isolated cron announces to Telegram forum topics. Carries forward #59069; refs #49704 and #43808. Thanks @roytong9.
- Build/runtime: write the runtime-postbuild stamp after `pnpm build` writes the build stamp, so the next CLI invocation does not re-sync runtime artifacts after a successful build. Fixes #73151. Thanks @bittoby.
- Build/runtime: preserve staged bundled-plugin runtime dependency caches across source-checkout tsdown rebuilds, so local CLI and gateway-watch rebuilds no longer recreate large plugin dependency trees before starting. Refs #73205. Thanks @SymbolStar.
- CLI/channels: list configured chat channel accounts from read-only setup metadata even when the standalone CLI has not loaded the runtime channel registry, so `openclaw channels list` shows Telegram accounts before auth providers. Fixes #73319 and #73322. Thanks @mlaihk.
- CLI/model probes: keep `infer model run --gateway` raw by skipping prior session transcript, bootstrap context, context-engine assembly, tools, and bundled MCP servers, so local backends can be tested without full agent-context overhead. Fixes #73308. Thanks @ScientificProgrammer.
- CLI/image describe: pass `--prompt` and `--timeout-ms` through `infer image describe` and `describe-many`, so custom vision instructions and slow local model budgets reach media-understanding providers such as Ollama, OpenAI, Google, and OpenRouter. Addresses #63700. Thanks @cedricjanssens.
- Providers/Ollama: reject long non-linguistic Kimi/GLM symbol runs as provider failures instead of storing them as successful visible assistant replies, so fallback or error handling can recover from garbled cloud output. Fixes #64262; refs #67019. Thanks @Kloz813 and @xiaomenger123.
- CLI/model probes: reject empty or whitespace-only `infer model run --prompt` values before calling local providers or the Gateway, so smoke checks do not spend provider calls on invalid turns. Fixes #73185. Thanks @iot2edge.
- Gateway/media: route text-only `chat.send` image offloads through media-understanding fields so `agents.defaults.imageModel` can describe WebChat attachments instead of leaving only an opaque `media://inbound` marker. Fixes #72968. Thanks @vorajeeah.
- Gateway/Windows: route no-listener restart handoffs through the Windows supervisor without leaving restart tokens in flight, so failed task scheduling can be retried and successful handoffs do not coalesce later restart requests. (#69056) Thanks @Thatgfsj.
- Gateway/model pricing: skip plugin manifest discovery during background pricing refreshes when `plugins.enabled: false`, so disabled-plugin setups do not keep rebuilding plugin metadata from the Gateway hot path. Fixes #73291. Thanks @slideshow-dingo and @fishgills.
- Ollama/thinking: validate `/think` commands against live Ollama catalog reasoning metadata and preserve explicit native `params.think`/`params.thinking`, so models whose `/api/show` capabilities include `thinking` expose `low`, `medium`, `high`, and `max` instead of being stuck on `off`. Fixes #73366. Thanks @cymise.
- Gateway/sessions: remove automatic oversized `sessions.json` rotation backups, deprecate `session.maintenance.rotateBytes`, and teach `openclaw doctor --fix` to remove the ignored key so hot session writes no longer copy multi-MB stores. Refs #72338. Thanks @midhunmonachan and @DougButdorf.
- Channels/Telegram: fail fast when Telegram rejects the startup `getMe` token probe with 401, so invalid or stale BotFather tokens are reported as token auth failures instead of misleading `deleteWebhook` cleanup failures. Fixes #47674. Thanks @samaedan-arch.
- ACPX: keep generated Codex and Claude ACP wrapper startup paths working when remote or special state filesystems reject chmod, since OpenClaw invokes the wrappers through Node instead of executing them directly. Fixes #73333. Thanks @david-garcia-garcia.
- CLI/onboarding: infer image input for common custom-provider vision model IDs, ask only for unknown models, and keep `--custom-image-input`/`--custom-text-input` overrides so vision-capable proxies do not get saved as text-only configs. Fixes #51869. Thanks @Antsoldier1974.
- Models/OpenAI Codex: stop listing or resolving unsupported `openai-codex/gpt-5.4-mini` rows through Codex OAuth, keep stale discovery rows suppressed with a clear API-key-route hint, and leave direct `openai/gpt-5.4-mini` available. Fixes #73242. Thanks @0xCyda.
- Plugin SDK: restore the root `stringEnum` and `optionalStringEnum` exports on both the published SDK entry and runtime root-alias bridge, so older external plugins can keep building and loading while migrating to focused SDK subpaths. Fixes #68279. Thanks @marzliak.
- Plugin SDK: restore the root-alias bridge for `registerContextEngine` and expose missing legacy compat helpers `normalizeAccountId` and `resolvePreferredOpenClawTmpDir` so older external plugins such as `openclaw-weixin` can keep loading while migrating to focused SDK subpaths. Fixes #53497. Thanks @alanxchen85.
- Auth profiles: make `openclaw doctor --fix` migrate legacy flat `auth-profiles.json` files such as `{ "ollama-windows": { "apiKey": "ollama-local" } }` to canonical provider default API-key profiles with a backup, so custom Ollama/OpenAI-compatible providers recover cleanly after upgrading. Fixes #59629; supersedes #59642. Thanks @Xsanders555 and @Linux2010.
- Memory/Dreaming: retry Dream Diary once with the session default when a configured dreaming model is unavailable, while leaving subagent trust and allowlist errors visible instead of silently masking configuration problems. Refs #67409 and #69209. Thanks @Ghiggins18 and @everySympathy.
- Feishu/inbound files: recover CJK filenames from plain `Content-Disposition: filename=` download headers when Feishu exposes UTF-8 bytes through Latin-1 header decoding, while leaving valid Latin-1 and JSON-derived names unchanged. (#48578, #50435, #59431) Thanks @alex-xuweilong, @lishuaigit, and @DoChaoing.
- Channels/Telegram: normalize accidental full `/bot<TOKEN>` Telegram `apiRoot` values at runtime and teach `openclaw doctor --fix` to remove the suffix, so startup control calls no longer 404 when direct Bot API curl commands work. Fixes #55387. Thanks @brendanmatthewjones-cmyk, @techfindubai-ux, and @Sivlerback-Chris.
- Zalo Personal: persist refreshed `zca-js` session cookies after QR login, session restore, and successful API calls so gateway restarts restore the freshest local session. (#73277) Thanks @darkamenosa.
- Logging/security: redact sensitive tokens (sk-\* keys, Bearer/Authorization values, etc.) at the subsystem console sink so `createSubsystemLogger().info/warn/error` output that bypasses the patched console-capture handler still applies the same redaction the file transport already does. Fixes #73284; refs #67953 and #64046. Thanks @edwin-rivera-dev.
- Plugins/runtime deps: reuse enclosing versioned cache roots when bundled plugins resolve from nested staged paths, so plugin-runtime-deps no longer mints `openclaw-unknown-*` directories or loops on `ENOTEMPTY`. Fixes #72956. (#73205) Thanks @SymbolStar.
- Agents/failover: classify CJK provider transport, quota, billing, auth, and overload error text so Chinese-language provider failures trigger fallback and user-facing transport copy instead of surfacing as unclassified raw errors. (#56242) Thanks @tomcatzh.
- Agents/failover: seed non-claude-cli fallback prompts with Claude Code session context when a claude-cli attempt fails, so fallback models do not restart cold after billing or quota failover. (#72069) Thanks @stainlu.
- Agents/CLI runner: transfer bundle-MCP tempDir cleanup from the per-turn runner finally to the Claude live-session lifecycle, so persistent Claude CLI sessions keep their `--mcp-config` directory until the live subprocess closes. Fixes #73244. Thanks @edwin-rivera-dev.
- Gateway/nodes: allow Windows companion nodes to use safe declared commands such as canvas, camera list, location, device info, and screen snapshot by default while keeping dangerous media commands opt-in. (#71884) Thanks @shanselman.
- Agents/cron: clarify agent-tool and CLI cron timezone guidance so supplied `tz` values use local wall-clock cron fields and omitted cron `tz` falls back to the Gateway host local timezone. Fixes #53669; carries forward #46177. (#73372) Thanks @chen-zhang-cs-code and @maranello-o.
- Providers/Qwen: allow explicitly configured `qwen/qwen3.6-plus` to resolve on Qwen Coding Plan endpoints while keeping the built-in catalog from advertising it there. Fixes #63654; carries forward #63987. Thanks @jepson-liu.
- Channels/Telegram: keep Bot API network fallbacks sticky after failed attempts and retry timed-out startup control calls once on the fallback route, so `deleteWebhook` IPv6 stalls no longer trigger slow multi-account retry storms. Fixes #73255. Thanks @ttomiczek and @sktbrd.
- Gateway/agents: accept heartbeat, cron, and webhook as internal channel hints for agent runs so `sessions_spawn` works from non-delivery parent sessions while unknown channel hints still fail closed. Fixes #73237. Thanks @KeWang0622.
- Gateway/models: merge explicit `models.providers.*.models` rows into the Gateway model catalog with normalized provider/model dedupe, and use normalized image-capability lookup so custom vision models keep native image attachments even when Pi discovery omits them or model ID casing differs. Fixes #64213 and #65165. Thanks @billonese and @202233a.
@@ -136,7 +557,7 @@ Docs: https://docs.openclaw.ai
- Doctor/channels: suppress disabled bundled-plugin blocker warnings when a trusted external plugin owns the configured channel, so Lark/Feishu installs no longer get Feishu repair noise after switching to `openclaw-lark`. Fixes #56794. Thanks @wuji-tech-dev.
- CLI/status: show skipped fast-path memory checks as `not checked` and report active custom memory plugin runtime status from `status --json --all` without requiring built-in `agents.defaults.memorySearch`, so plugins such as memory-lancedb-pro and memory-cms no longer look unavailable when their own runtime is healthy. Fixes #56968. Thanks @Tony-ooo and @aderius.
- Gateway/channels: record and log unexpected clean channel monitor exits so channels that return without throwing no longer appear stopped with no error. Fixes #73099. Thanks @balaji1968-kingler.
- Discord/group chats: keep group/channel replies private by default unless the agent explicitly uses the message tool, so always-on rooms can lurk without leaking automatic final, block, preview, or status-reaction output; `messages.groupChat.visibleReplies: "automatic"` restores legacy auto-posting. (#73046) Thanks @scoootscooob.
- Group/channel chats (all channels): keep group/channel replies private by default unless the agent explicitly uses the message tool, so always-on rooms can lurk without leaking automatic final, block, preview, or status-reaction output; `messages.groupChat.visibleReplies: "automatic"` restores legacy auto-posting. (#73046) Thanks @scoootscooob.
- Plugins/package: force nested bundled-plugin runtime dependency installs out of inherited npm dry-run mode during prepack and package smoke checks, so packed installs materialize required plugin modules instead of reporting missing bundled files. Refs #73128. Thanks @Adam-Researchh.
- Discord: skip reaction events before REST channel fetch when notifications are off, guild reactions are disabled, or allowlist mode cannot match without channel overrides, reducing reconnect bursts that caused slow listener warnings. Fixes #73133. Thanks @isaacsummers.
- Channels/Telegram: centralize polling update tracking so accepted offsets remain durable across restarts, same-process handler failures can still retry, and slow offset writes cannot overwrite newer accepted watermarks. Refs #73115. Thanks @vdruts.
@@ -183,7 +604,7 @@ Docs: https://docs.openclaw.ai
- CLI/status: keep default `openclaw status` off the heavyweight security audit, plugin compatibility, and memory-vector probes while still showing configured Telegram channels through setup metadata, so routine health checks stay fast and no longer render an empty Channels table. Fixes #72993. Thanks @comick1.
- Channels/Telegram: send a best-effort native typing cue immediately after an inbound message is accepted, so slow pre-dispatch turns show Telegram liveness before queueing, compaction, model, or tool work starts. Fixes #63759. Thanks @alessandropcostabr.
- Channels/Telegram: stop native approval startup auth failures from retrying every second, while still waiting through retryable Gateway auth handoffs, so Telegram approval setup problems no longer create a reconnect/log loop during channel startup. Refs #72846 and #72867. Thanks @kiranvk-2011 and @porly1985.
- Channels/Microsoft Teams: unwrap staged CommonJS JWT runtime dependencies before Bot Connector token validation so inbound Teams messages no longer 401 after the bundled runtime-deps move. Fixes #73026. Thanks @kbrown10000.
- Channels/Microsoft Teams: unwrap staged CommonJS JWT runtime dependencies before Bot Connector token validation so inbound Teams messages no longer 401 after the bundled runtime-deps move. Fixes #73026 and #73167. Thanks @kbrown10000 and @mikelavrik.
- Gateway/auth: allow local direct callers in trusted-proxy mode to use the configured gateway password as an internal fallback while keeping token fallback rejected. Fixes #17761. Thanks @dashed, @vincentkoc, and @jetd1.
- Gateway/auth: add explicit `trustedProxy.allowLoopback` support for same-host loopback reverse proxies while keeping loopback trusted-proxy auth fail-closed by default and preserving required-header and allowlist checks. Fixes #59167; carries forward #63379. Thanks @Matir, @jeremyakers, and @mrosmarin.
- Channels/sessions: prevent guarded inbound session recording from creating route-only phantom sessions while still allowing last-route updates for sessions that already exist. Carries forward #73009. Thanks @jzakirov.
@@ -239,6 +660,7 @@ Docs: https://docs.openclaw.ai
- Discord/gateway: count failed health-monitor restart attempts toward cooldown and hourly caps, and evict stale account lifecycle state during channel reloads so repeated Discord gateway recovery cannot loop on old status. Fixes #38596. (#40413) Thanks @jellyAI-dev and @vashquez.
- TTS/BlueBubbles: pre-transcode synthesized MP3 audio to opus-in-CAF (mono, 24 kHz — validated against macOS 15.x Messages.app's native voice-memo CAF descriptor) on macOS hosts before handing the file to BlueBubbles, so iMessage renders the result as a native voice-memo bubble with proper duration and waveform UI instead of a plain file attachment. Adds an opt-in `tts.voice.preferAudioFileFormat` channel capability and a magic-byte sniff for the CAF container so the host-local-media validator (which uses `file-type` and didn't recognize CAF natively) can verify the pre-transcoded buffer. Channels that don't opt in are unaffected. (#72586) Fixes #72506. Thanks @omarshahine.
- Feishu: retry WebSocket startup failures with monitor-owned backoff while preserving SDK-local heartbeat defaults, so persistent-connection startup failures no longer leave the monitor hung. Fixes #68766; related #42354 and #55532. Thanks @alex-xuweilong, @120106835, @sirfengyu, and @tianhaocui.
- Cron: normalize isolated job tool allowlists before granting the narrow self-removal cron tool path, keeping scheduled jobs aligned with shared tool policy normalization. (#73028) Thanks @jalehman.
## 2026.4.26
@@ -246,6 +668,7 @@ Docs: https://docs.openclaw.ai
- Control UI/Talk: add a generic browser realtime transport contract, Google Live browser Talk sessions with constrained ephemeral tokens, and a Gateway relay for backend-only realtime voice plugins. Thanks @VACInc.
- CLI/models: route provider-filtered model listing through an explicit source plan so user config, installed manifest rows, Provider Index previews, and scoped runtime fallbacks keep a stable authority order without adding another catalog cache. Thanks @shakkernerd.
- Plugins/cron: add a typed `cron_changed` hook for observing gateway-owned cron lifecycle updates without depending on internal cron events. Thanks @amknight.
- Providers: add Cerebras as a bundled plugin with onboarding, static model catalog, docs, and manifest-owned endpoint metadata.
- Memory/OpenAI-compatible: add optional `memorySearch.inputType`, `queryInputType`, and `documentInputType` config for asymmetric embedding endpoints, including direct query embeddings and provider batch indexing. Carries forward #63313 and #60727. Thanks @HOYALIM and @prospect1314521.
- Ollama/memory: add model-specific retrieval query prefixes for `nomic-embed-text`, `qwen3-embedding`, and `mxbai-embed-large` memory-search queries while leaving document batches unchanged. Carries forward #45013. Thanks @laolin5564.
@@ -402,6 +825,7 @@ Docs: https://docs.openclaw.ai
- Agents/bootstrap: dedupe hook-injected bootstrap context files by workspace-relative path and store normalized resolved paths so duplicate relative and absolute hook paths no longer depend on the process cwd. (#59344; fixes #59319; related #56721, #56725, and #57587) Thanks @koen666.
- Agents/bootstrap: refresh cached workspace bootstrap snapshots on long-lived main-session turns when `AGENTS.md`, `SOUL.md`, `MEMORY.md`, or `TOOLS.md` change on disk, while preserving unchanged snapshot identity through the workspace file cache. (#64871; related #43901, #26497, #28594, #30896) Thanks @aimqwest and @mikejuyoon.
- macOS Gateway: detect installed-but-unloaded LaunchAgent split-brain states during status, doctor, and restart, and re-bootstrap launchd supervision before falling back to unmanaged listener restarts. Fixes #67335, #53475, and #71060; refs #58890, #60885, and #70801. Thanks @ze1tgeist88, @dafacto, and @vishutdhar.
- WhatsApp: clear cached Web auth and active listener state after terminal 440/401 conflict/logout closes so linked/OK status no longer masks a dead inbound listener after relink or restart. Fixes #45474; refs #49305, #63855, #66920, and #70856. Thanks @juvenalmakoszay and @dsantoreis.
- Gateway/restart: keep local restart-health probes on configured local daemon auth without falling back to remote gateway credentials. (#57374, #59439) Thanks @zssggle-rgb and @roytong9.
- Plugins/install: treat mirrored core logger dependencies as staged bundled runtime deps so packaged Gateway starts do not crash when the external plugin-runtime-deps root is missing `tslog`. Fixes #72228; supersedes #72493. Thanks @deepujain.
- Build/plugins: preserve active bundled runtime-dependency staging temp directories owned by live build processes so overlapping postbuild runs no longer delete each other's staged deps mid-prune. Supersedes #72220. Thanks @VACInc.
@@ -413,6 +837,7 @@ Docs: https://docs.openclaw.ai
- TTS/SecretRef: resolve `messages.tts.providers.*.apiKey` from the active runtime snapshot so SecretRef-backed MiniMax and other TTS provider keys work in runtime reply/audio paths. Fixes #68690. Thanks @joshavant.
- Gateway/install: surface systemd user-bus recovery hints during Linux service activation and retry via the target user scope when `systemctl --user` reports no-medium bus failures, without letting stale `SUDO_USER` override `sudo -u` installs. Fixes #39673; refs #44417 and #63561. Thanks @Arbor4, @myrsu, @mssteuer, and @boyuaner.
- CLI/nodes: make unfiltered `openclaw nodes list` prefer the effective paired-node view used by `nodes status` while preserving pending rows, pairing-scope fallback, terminal-safe table rendering, and paired JSON metadata. Fixes #46871; carries forward #65772 through the ProjectClownfish #72619 repair. Thanks @skainguyen1412.
- Memory Wiki/CLI: route active bridge-mode status, doctor, and bridge imports through Gateway RPC so CLI checks use the runtime memory plugin context while disabled bridge imports stay local/offline. Carries forward #67208 and #71479; related #70185. Thanks @moorsecopers99, @vincentkoc, and @prasad-yashdeep.
- CLI/startup: read generated startup metadata from the bundled `dist` layout before falling back to live help rendering, so root/browser help and channel-option bootstrap stay on the fast path. Thanks @vincentkoc.
- Feishu/Lark: stop treating broadcast-only `@all`/`@_all` messages as bot mentions while preserving direct bot mentions, including messages that also include `@all`. Fixes #37706. Thanks @JosepLee.
- CLI/help: treat positional `help` invocations like `openclaw channels help` as help paths for startup gating, avoiding model/auth warmup while preserving positional arguments such as `openclaw docs help`. Thanks @gumadeiras.
@@ -923,6 +1348,7 @@ Docs: https://docs.openclaw.ai
- Google Meet joins OpenClaw as a bundled participant plugin, with personal Google auth, Chrome/Twilio realtime sessions, paired-node Chrome support, artifact/attendance exports, and recovery tooling for already-open Meet tabs.
- DeepSeek V4 Flash and V4 Pro are in the bundled catalog, V4 Flash is the onboarding default, and DeepSeek thinking/replay behavior is fixed for follow-up tool-call turns.
- Talk, Voice Call, and Google Meet can use realtime voice loops that consult the full OpenClaw agent for deeper tool-backed answers.
- Providers/OpenRouter: add native video generation through `video_generate`, so OpenRouter video models work with `OPENROUTER_API_KEY`. (#72700) Thanks @notamicrodose.
- Browser automation gets coordinate clicks, longer default action budgets, per-profile headless overrides, and steadier tab reuse/recovery.
- Plugin and model infrastructure is lighter at startup: static model catalogs, manifest-backed model rows, lazy provider dependencies, and external runtime-dependency repair for packaged installs.

View File

@@ -63,6 +63,8 @@ COPY openclaw.mjs ./
COPY ui/package.json ./ui/package.json
COPY patches ./patches
COPY scripts/postinstall-bundled-plugins.mjs scripts/preinstall-package-manager-warning.mjs scripts/npm-runner.mjs scripts/windows-cmd-helpers.mjs ./scripts/
COPY scripts/lib/bundled-runtime-deps-install.mjs ./scripts/lib/bundled-runtime-deps-install.mjs
COPY scripts/lib/package-dist-imports.mjs ./scripts/lib/package-dist-imports.mjs
COPY --from=ext-deps /out/ ./${OPENCLAW_BUNDLED_PLUGIN_DIR}/
@@ -130,7 +132,8 @@ RUN printf 'packages:\n - .\n - ui\n' > /tmp/pnpm-workspace.runtime.yaml && \
cp /tmp/pnpm-workspace.runtime.yaml pnpm-workspace.yaml && \
CI=true NPM_CONFIG_FROZEN_LOCKFILE=false pnpm prune --prod && \
node scripts/postinstall-bundled-plugins.mjs && \
find dist -type f \( -name '*.d.ts' -o -name '*.d.mts' -o -name '*.d.cts' -o -name '*.map' \) -delete
find dist -type f \( -name '*.d.ts' -o -name '*.d.mts' -o -name '*.d.cts' -o -name '*.map' \) -delete && \
node scripts/check-package-dist-imports.mjs /app
# ── Runtime base image ──────────────────────────────────────────
FROM ${OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE} AS base-runtime
@@ -258,10 +261,12 @@ RUN --mount=type=cache,id=openclaw-bookworm-apt-cache,target=/var/cache/apt,shar
RUN ln -sf /app/openclaw.mjs /usr/local/bin/openclaw \
&& chmod 755 /app/openclaw.mjs
# Pre-create the default state dir so first-run Docker named volumes mounted
# here inherit node ownership instead of starting as root-owned state.
# Pre-create the default state and runtime-deps dirs so first-run Docker named
# volumes mounted here inherit node ownership instead of root-owned state.
RUN install -d -m 0700 -o node -g node /home/node/.openclaw && \
stat -c '%U:%G %a' /home/node/.openclaw | grep -qx 'node:node 700'
install -d -m 0700 -o node -g node /var/lib/openclaw/plugin-runtime-deps && \
stat -c '%U:%G %a' /home/node/.openclaw | grep -qx 'node:node 700' && \
stat -c '%U:%G %a' /var/lib/openclaw/plugin-runtime-deps | grep -qx 'node:node 700'
ENV NODE_ENV=production

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.7
FROM debian:bookworm-slim@sha256:4724b8cc51e33e398f0e2e15e18d5ec2851ff0c2280647e1310bc1642182655d
FROM debian:bookworm-slim@sha256:f9c6a2fd2ddbc23e336b6257a5245e31f996953ef06cd13a59fa0a1df2d5c252
ENV DEBIAN_FRONTEND=noninteractive

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.7
FROM debian:bookworm-slim@sha256:4724b8cc51e33e398f0e2e15e18d5ec2851ff0c2280647e1310bc1642182655d
FROM debian:bookworm-slim@sha256:f9c6a2fd2ddbc23e336b6257a5245e31f996953ef06cd13a59fa0a1df2d5c252
ENV DEBIAN_FRONTEND=noninteractive

View File

@@ -64,6 +64,7 @@ These are frequently reported but are typically closed with no code change:
- Reports that only show differences in heuristic detection/parity (for example obfuscation-pattern detection on one exec path but not another, such as `node.invoke -> system.run` parity gaps) without demonstrating bypass of auth, approvals, allowlist enforcement, sandboxing, or other documented trust boundaries.
- Reports that only show an ACP tool can indirectly execute, mutate, orchestrate sessions, or reach another tool/runtime without demonstrating bypass of ACP prompt/approval, allowlist enforcement, sandboxing, or another documented trust boundary. ACP silent approval is intentionally limited to narrow readonly classes; parity-only indirect-command findings are hardening, not vulnerabilities.
- Reports that only show untrusted media bytes reaching a maintained native decoder dependency (for example Sharp/libvips/libheif) without proving the shipped dependency version is vulnerable and demonstrating crash, memory corruption, data exposure, or a boundary bypass through OpenClaw. JavaScript header sniffing and image dimension fast-paths are preflight/UX checks, not the security boundary for native decoder correctness.
- Reports whose only impact is transient extra memory, CPU, or allocation work from decoding, base64 expansion, media transcoding, serialization, or other format conversion after the input was already accepted under OpenClaw's configured size/trust limits, including base64 decode-before-size-estimate findings. These are performance issues, not vulnerabilities, unless the report demonstrates unauthenticated amplification, bypass of configured limits, crash/process termination, persistent resource exhaustion, data exposure, or another documented boundary bypass.
- ReDoS/DoS claims that require trusted operator configuration input (for example catastrophic regex in `sessionFilter` or `logging.redactPatterns`) without a trust-boundary bypass.
- Archive/install extraction claims that require pre-existing local filesystem priming in trusted state (for example planting symlink/hardlink aliases under destination directories such as skills/tools paths) without showing an untrusted path that can create/control that primitive.
- Reports that depend on replacing or rewriting an already-approved executable path on a trusted host (same-path inode/content swap) without showing an untrusted path to perform that write.
@@ -75,6 +76,7 @@ These are frequently reported but are typically closed with no code change:
- Claims that Microsoft Teams `fileConsent/invoke` `uploadInfo.uploadUrl` is attacker-controlled without demonstrating one of: auth boundary bypass, a real authenticated Teams/Bot Framework event carrying attacker-chosen URL, or compromise of the Microsoft/Bot trust path.
- Scanner-only claims against stale/nonexistent paths, or claims without a working repro.
- Reports that restate an already-fixed issue against later released versions without showing the vulnerable path still exists in the shipped tag or published artifact for that later version.
- SSRF reports against the operator-managed HTTP/WebSocket proxy-routing feature whose only claim is that ordinary process-local HTTP clients (`fetch`, `node:http`, `node:https`, WebSocket clients, axios/got/node-fetch-style clients) can reach an internal, metadata, private, or otherwise sensitive destination when proxy routing is disabled, missing, or the operator-managed proxy policy allows it. For this feature, OpenClaw provides fail-closed proxy routing when enabled; the external proxy's destination policy is operator infrastructure, not an OpenClaw-controlled security boundary. See [Network proxy](https://docs.openclaw.ai/security/network-proxy).
### Duplicate Report Handling
@@ -148,9 +150,11 @@ Plugins/extensions are part of OpenClaw's trusted computing base for a gateway.
- Reports whose only claim is that an ACP-exposed tool can indirectly execute commands, mutate host state, or reach another privileged tool/runtime without demonstrating a bypass of ACP prompt/approval, allowlist enforcement, sandboxing, or another documented trust boundary. These are hardening-only findings, not vulnerabilities.
- Reports whose only claim is that exec approvals do not semantically model every interpreter/runtime loader form, subcommand, flag combination, package script, or transitive module/config import. Exec approvals bind exact request context and best-effort direct local file operands; they are not a complete semantic model of everything a runtime may load.
- Reports whose only claim is parser reachability in an up-to-date maintained dependency without showing that the exact shipped dependency build is vulnerable. We keep native media dependencies current; dependency exposure alone is not a vulnerability.
- Reports whose only claim is resource overhead from decode/encode, base64 expansion, media transcoding, serialization, or format-conversion order after input has already passed the applicable configured acceptance limits, including base64 decode-before-size-estimate findings. These are performance-only and should be ignored for GHSA triage unless the report demonstrates unauthenticated amplification, limit bypass, crash/process termination, persistent exhaustion, data exposure, or another documented boundary bypass.
- Exposed secrets that are third-party/user-controlled credentials (not OpenClaw-owned and not granting access to OpenClaw-operated infrastructure/services) without demonstrated OpenClaw impact
- Reports whose only claim is host-side exec when sandbox runtime is disabled/unavailable (documented default behavior in the trusted-operator model), without a boundary bypass.
- Reports whose only claim is that a platform-provided upload destination URL is untrusted (for example Microsoft Teams `fileConsent/invoke` `uploadInfo.uploadUrl`) without proving attacker control in an authenticated production flow.
- SSRF reports limited to the operator-managed HTTP/WebSocket proxy-routing feature where the demonstrated mitigation is to enable/configure `proxy.enabled` with a filtering `proxy.proxyUrl`/`OPENCLAW_PROXY_URL`, or where impact depends on a permissive/misconfigured operator proxy. This only covers normal process-local HTTP(S)/WebSocket egress (`fetch`, Node HTTP(S), and similar JavaScript clients); non-HTTP egress and other features are assessed separately. See [Network proxy](https://docs.openclaw.ai/security/network-proxy).
## Deployment Assumptions

View File

@@ -1,5 +1,5 @@
{
"originHash" : "e6910acc97de62dc423c0a391985c1c2f28207951e356081539abde41f9ffc72",
"originHash" : "646c710cf04fdf9e6c6ca935f3184924db3397a816848a7f8a8a3c10a4d8e9c8",
"pins" : [
{
"identity" : "commander",
@@ -15,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-syntax.git",
"state" : {
"revision" : "0687f71944021d616d34d922343dcef086855920",
"version" : "600.0.1"
"revision" : "9de99a78f099e59caf2b2beec65a4c45d54b2081",
"version" : "603.0.1"
}
},
{
@@ -24,8 +24,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-testing",
"state" : {
"revision" : "399f76dcd91e4c688ca2301fa24a8cc6d9927211",
"version" : "0.99.0"
"revision" : "937120cbc281cf29727fdfb8734482158508b4fc",
"version" : "6.3.1"
}
}
],

View File

@@ -14,7 +14,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/steipete/Commander.git", exact: "0.2.2"),
.package(url: "https://github.com/apple/swift-testing", from: "0.99.0"),
.package(url: "https://github.com/apple/swift-testing", from: "6.3.1"),
],
targets: [
.target(

View File

@@ -2,6 +2,298 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.4.27</title>
<pubDate>Wed, 29 Apr 2026 23:53:26 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026042790</sparkle:version>
<sparkle:shortVersionString>2026.4.27</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.27</h2>
<h3>Changes</h3>
<ul>
<li>Sandbox/Docker: add opt-in <code>sandbox.docker.gpus</code> passthrough for Docker sandbox containers so local GPU workloads can run inside sandboxed agents when the host Docker runtime supports <code>--gpus</code>. Fixes #57976; carries forward #58124. Thanks @cyan-ember.</li>
<li>iOS/Gateway: add an authenticated <code>node.presence.alive</code> protocol event and <code>node.list</code> last-seen fields so background iOS wakes can mark paired nodes recently alive without treating them as connected. Carries forward #63123. Thanks @ngutman.</li>
<li>Android: publish authenticated <code>node.presence.alive</code> events after node connect and background transitions so paired Android nodes retain durable last-seen metadata after disconnects. Carries forward #63123. Thanks @ngutman.</li>
<li>Gateway/chat: accept non-image attachments through <code>chat.send</code> by staging them as agent-readable media paths, while keeping unsupported RPC attachment paths explicit instead of silently dropping files. Fixes #48123. (#67572) Thanks @samzong.</li>
<li>Security/networking: add opt-in operator-managed outbound proxy routing (proxy.enabled + proxy.proxyUrl/OPENCLAW_PROXY_URL) with strict http:// forward-proxy validation, loopback-only Gateway bypass, and cleanup of proxy env/dispatcher state on exit. (#70044) Thanks @jesse-merhi and @joshavant.</li>
<li>Dependencies: refresh provider and tooling dependencies, including AWS SDK, PI runtime packages, AJV, Feishu SDK, Anthropic SDK, tokenjuice, and native TypeScript/oxlint tooling. Thanks @dependabot.</li>
<li>Matrix/QA: add live Matrix approval scenarios for exec metadata, chunked fallback, plugin approvals, deny reactions, thread targeting, and <code>target: "both"</code> delivery, with redacted artifacts preserving safe approval summaries. Thanks @gumadeiras.</li>
<li>Codex: add Computer Use setup for Codex-mode agents, including <code>/codex computer-use status/install</code>, marketplace discovery, optional auto-install, and fail-closed MCP server checks before Codex-mode turns start. Fixes #72094. (#71842) Thanks @pash-openai.</li>
<li>Apps: consume Peekaboo 3.0.0-beta4 and ElevenLabsKit 0.1.1, align Swabble on Commander 0.2.2, and refresh macOS/iOS SwiftPM resolutions against the released dependency graph. Thanks @Blaizzy.</li>
<li>Plugin SDK: expose shared channel route normalization, parser-driven target resolution, raw-target compact keys, parsed-target types, and route comparison helpers through <code>openclaw/plugin-sdk/channel-route</code>, switch native approval origin matching onto that route contract with optional delivery and match-only target normalization, and retire the internal channel-route shim behind dated compatibility aliases for legacy key/comparable-target helpers. Thanks @vincentkoc.</li>
<li>Docs/Codex: document how Codex Computer Use, direct <code>cua-driver mcp</code>, and OpenClaw.app's PeekabooBridge fit together so desktop-control setup choices are clearer. Thanks @pash-openai and @trycua.</li>
<li>Matrix/streaming: stream tool-progress updates into live Matrix preview edits by default when preview streaming is active, with <code>streaming.preview.toolProgress: false</code> to keep answer previews while hiding interim tool lines. Thanks @gumadeiras.</li>
<li>Plugins/models: wire manifest <code>modelCatalog.aliases</code> and <code>modelCatalog.suppressions</code> into model-catalog planning and built-in model suppression, with stale Spark and Qwen Coding Plan suppressions now declared in plugin manifests instead of runtime fallback hooks. Thanks @shakkernerd.</li>
<li>Plugin SDK/models: add a shared manifest-backed provider catalog builder and move Qianfan, Xiaomi, NVIDIA, Cerebras, Mistral, Moonshot, DeepSeek, Tencent TokenHub, and StepFun provider catalogs onto their plugin manifest <code>modelCatalog</code> rows. Thanks @shakkernerd.</li>
<li>Plugin SDK/models: move BytePlus and Volcano Engine standard and plan-provider catalogs into plugin manifest <code>modelCatalog</code> rows and remove the now-unused Volcengine-family shared catalog SDK subpath. Thanks @shakkernerd.</li>
<li>CLI/models: move Fireworks and Together AI fixed provider catalogs into plugin manifest <code>modelCatalog</code> rows so provider-filtered listing can use manifest-backed static rows. Thanks @shakkernerd.</li>
<li>Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (<code>openclaw-plugin-yuanbao</code>) in the official channel catalog, contract suites, and community plugin docs, with a new <code>docs/channels/yuanbao.md</code> quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay.</li>
<li>Channels/Yuanbao: add a channel docs entrance so the Tencent Yuanbao bot appears in the channel listing and sidebar navigation. (#73443) Thanks @loongfay.</li>
<li>Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C <code>stream_messages</code> streaming with a <code>StreamingController</code> lifecycle manager, unified <code>sendMedia</code> with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via <code>createEngineAdapters()</code>. (#70624) Thanks @cxyhhhhh.</li>
<li>Plugins/startup: migrate bundled plugin manifests to explicit <code>activation.onStartup</code> declarations so Gateway startup imports only the bundled plugins that intentionally register startup-time runtime surfaces. Thanks @shakkernerd.</li>
<li>Plugins/startup: add an opt-in future-mode gate for disabling deprecated implicit startup sidecar loading while preserving explicit startup and narrower activation triggers. Thanks @shakkernerd.</li>
<li>Plugins/startup: add plugin compatibility warnings for deprecated implicit startup loading so authors can migrate to explicit <code>activation.onStartup</code> metadata. Thanks @shakkernerd.</li>
<li>Plugins/runtime: load bundled agent tool-result middleware from manifest contracts on demand so tokenjuice stays startup-lazy without losing Pi/Codex tool-output compaction. Thanks @shakkernerd.</li>
<li>Plugins/startup: add explicit <code>activation.onStartup</code> metadata so plugins can declare Gateway startup import behavior while the deprecated implicit sidecar fallback remains for legacy plugins. Thanks @shakkernerd.</li>
<li>Gateway/startup: reuse lookup-table plugin manifests when loading startup plugins so Gateway boot avoids rebuilding plugin discovery and manifest metadata. Thanks @shakkernerd.</li>
<li>CLI/models: declare fixed Qianfan, Xiaomi, NVIDIA, Cerebras, Mistral, Chutes, Kilo, OpenAI, and OpenCode Go model catalogs in refreshable plugin manifests, keep broad <code>models list --all</code> on raw registry and supplement rows without runtime normalization, and avoid duplicate supplement resolution. Thanks @shakkernerd.</li>
<li>Gateway/runtime: reuse the current plugin metadata snapshot for provider discovery so repeated model-provider discovery avoids rebuilding plugin manifest metadata. Thanks @shakkernerd.</li>
<li>Gateway/startup: pass the plugin metadata snapshot from config validation into plugin bootstrap so startup reuses one manifest product instead of rebuilding plugin metadata. Thanks @shakkernerd.</li>
<li>Plugin SDK/testing: move core-only channel contract fixtures under the channel contract test tree and retire the old <code>test/helpers/channels</code> bridge directory so plugin tests stay on focused SDK surfaces. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: expose native agent-runtime contract fixtures through <code>plugin-sdk/agent-runtime-test-contracts</code>, move sandbox config fixtures into the focused generic fixture subpath, and block extension tests from importing repo-only <code>test/helpers</code> bridges. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: expose generic module reload, bundled-path, Node builtin mock, channel pairing/envelope, HTTP server, temp-home, replay-policy, and live STT helpers through focused SDK test subpaths so extension tests no longer depend on repo-only helper bridges. Thanks @vincentkoc.</li>
<li>Plugin SDK: move maintained bundled channels off the deprecated <code>channel-config-schema-legacy</code> subpath, add an explicit bundled-channel schema SDK surface, and track both remaining legacy test/config compatibility barrels with dated removal windows. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: expose media provider capability assertions and provider HTTP mocks through focused SDK test subpaths, and retire the repo-only media-generation test helper bridge. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: promote bundled plugin/provider/channel contract helpers to focused SDK test subpaths and retire the repo-only <code>test/helpers/plugins</code> TypeScript bridge. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: expose generic channel action, setup, status, and directory contract helpers through <code>plugin-sdk/channel-test-helpers</code> so bundled extension tests no longer import repo-only channel helper bridges. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: add <code>plugin-sdk/channel-target-testing</code> for shared channel target-resolution cases, document channel reaction helpers on <code>plugin-sdk/channel-feedback</code>, and keep the old <code>plugin-sdk/test-utils</code> alias as compatibility-only. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: add a focused generic fixture subpath for CLI capture, sandbox, skill, agent-message, system-event, terminal, chunking, auth-token, and typed-case helpers. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: add focused plugin runtime and environment fixture subpaths so plugin tests can avoid the broad <code>plugin-sdk/testing</code> barrel for common setup helpers. Thanks @vincentkoc.</li>
<li>Plugin SDK/testing: add a focused <code>plugin-sdk/plugin-test-api</code> helper subpath and move bundled plugin registration tests off the repo-only plugin API bridge. Thanks @vincentkoc.</li>
<li>Plugin SDK: add generic host hooks for session state, next-turn context, trusted tool policy, UI descriptors, events, scheduler cleanup, and run-scoped plugin context. (#72287) Thanks @100yenadmin.</li>
<li>Plugin SDK/testing: expose provider catalog, wizard, registry, manifest, public-artifact, outbound, and TTS contract helpers through documented SDK testing seams so bundled plugin tests no longer import repo <code>src/**</code> internals. Thanks @vincentkoc.</li>
<li>Providers/DeepInfra: add a bundled DeepInfra provider with <code>DEEPINFRA_API_KEY</code> onboarding, dynamic OpenAI-compatible model discovery, image generation/editing, image/audio media understanding, TTS, text-to-video, memory embeddings, static catalog metadata, and provider-owned base URL policy. Carries forward #53805, #48088, #37576, #43896, #11533, and #2554. Thanks @ats3v.</li>
<li>Matrix: attach versioned structured approval metadata to pending approval messages so capable Matrix clients can render richer approval UI while body text and reaction fallback keep working. (#72432) Thanks @kakahu2015.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Gateway/sessions: align <code>chat.history</code> and <code>sessions.list</code> thinking defaults with owning-agent and catalog-aware resolution so Control UI session defaults match backend runtime state. (#63418) Thanks @jpreagan.</li>
<li>Devices/pairing: recover array-shaped device and node pairing state files before persisting approvals, so UUID-keyed pending and paired entries no longer disappear after a malformed JSON store write. Fixes #63035. Thanks @sar618.</li>
<li>Gateway/auth: clear reused stale device tokens and stop reconnecting on device-token mismatch in the Control UI and Node gateway clients, avoiding rate-limit loops after scope-upgrade or token-rotation handoffs. Fixes #71609. Thanks @ricksayhi.</li>
<li>Gateway/approvals: treat duplicate same-decision approval resolves as idempotent during the resolved-entry grace window, including consumed <code>allow-once</code> approvals, while returning an explicit already-resolved error for conflicting repeats. Fixes #59162; refs #58479 and #65486. Thanks @wikithoughts, @sajazuniga7-coder, and @mjmai20682068-create.</li>
<li>Channels/Telegram: honor <code>approvals.exec/plugin.targets[].accountId</code> when routing native approvals across multi-bot Telegram accounts while preserving unscoped Telegram targets for any account. Fixes #69916. Thanks @joerod26.</li>
<li>Telegram/gateway: bound outbound Bot API calls and cache bundled plugin alias lookup so slow Telegram sends or WSL2 filesystem scans no longer wedge gateway replies. (#74210) Thanks @obviyus.</li>
<li>Agents/exec: omit the internal session-resume fallback preface from successful async exec completion messages sent directly back to chat. Fixes #67181. Thanks @raistlin88.</li>
<li>Agents/media: register detached <code>video_generate</code> and <code>music_generate</code> tool run contexts until terminal status, so Discord-backed provider jobs stay live in <code>/tasks</code> instead of becoming <code>lost</code> when the parent chat run context disappears. Thanks @vincentkoc.</li>
<li>Agents/media: prefer OpenAI image and video providers when the default model uses the OpenAI Codex auth alias, so auto media generation no longer falls through to Fal before GPT Image or Sora. Thanks @vincentkoc.</li>
<li>Tasks/media: infer agent ownership for session-scoped task records so <code>/tasks</code> agent-local fallback includes session-backed <code>video_generate</code> and other async media jobs even when the current chat session has no linked rows. Thanks @vincentkoc.</li>
<li>Agents/media: keep long-running <code>video_generate</code> and <code>music_generate</code> tasks fresh while provider jobs are still pending, so task maintenance does not mark active Discord media renders lost before completion. Thanks @vincentkoc.</li>
<li>CLI/status: treat scope-limited gateway probes as reachable-but-degraded in shared status scans, so <code>openclaw status --all</code> no longer reports a live gateway as unreachable after <code>missing scope: operator.read</code>. Fixes #49180; supersedes #47981. Thanks @openjay.</li>
<li>CLI/update: skip tracked plugins disabled in config during post-update plugin sync before npm, ClawHub, or marketplace update checks, preserving their install records without failing the update. Fixes #73880. Thanks @islandpreneur007.</li>
<li>Slack/Socket Mode: use a 15s Slack SDK pong timeout by default and add <code>channels.slack.socketMode.clientPingTimeout</code>, <code>serverPingTimeout</code>, and <code>pingPongLoggingEnabled</code> overrides so stale-websocket handling no longer depends on app-event health heuristics. Fixes #14248; refs #58519, #64009, and #63488. Thanks @shivasymbl and @freerk.</li>
<li>Slack/media: bound private file and forwarded attachment downloads with idle and total timeouts while preserving placeholder fallback, so stalled Slack <code>file_share</code> media no longer wedges inbound message handling. Fixes #61850. Thanks @bassboy2k.</li>
<li>Plugins/inspector: keep bundled plugin runtime capture quiet and config-tolerant for Codex, memory-lancedb, Feishu, Mattermost, QQBot, and Tlon so plugin-inspector JSON checks can validate the full bundled set. Thanks @vincentkoc.</li>
<li>Slack/auto-reply: keep fully consumed text reset triggers such as <code>new session</code> out of <code>BodyForAgent</code> after directive cleanup, so configured Slack reset phrases do not leak into the fresh model turn. Fixes #73137. Thanks @neeravmakwana.</li>
<li>Plugins/runtime deps: prune stale retained bundled runtime deps and keep doctor/secret channel contract scans on lightweight artifacts, so disabled bundled channels stop preserving old dependency trees or importing heavy plugin surfaces. Thanks @SymbolStar and @vincentkoc.</li>
<li>Plugins/runtime deps: cache unchanged bundled runtime mirror dist-file materialization decisions and close file-lock handles on owner-write failures, reducing repeated startup chunk scans and avoiding FileHandle-GC recovery stalls. Refs #73532. Thanks @oadiazp and @bstanbury.</li>
<li>Auto-reply: bound the post-run pending tool-result delivery drain with a progress-aware idle timeout, so a never-settling tool-result task no longer leaves the session active forever while slow healthy deliveries can keep draining. Fixes #53889; supersedes #64733 and #73434. Thanks @zijunl and @wujiaming88.</li>
<li>Gateway/startup: start chat channels without waiting for primary model prewarm, keeping model warmup bounded in the background so Slack and other channels come online promptly when provider discovery is slow. Supersedes #73420. Thanks @dorukardahan.</li>
<li>Gateway/install: carry env-backed config SecretRefs such as <code>channels.discord.token</code> into generated service environments when they are present only in the installing shell, while keeping gateway auth SecretRefs non-persisted. Fixes #67817; supersedes #73426. Thanks @wdimaculangan and @ztexydt-cqh.</li>
<li>Auto-reply/commands: stop bare <code>/reset</code> and <code>/new</code> after reset hooks acknowledge the command, so non-ACP channels no longer fall through into empty provider calls while <code>/reset <message></code> and <code>/new <message></code> still seed the next model turn. Fixes #73367 and #73412. Thanks @hoyanhan, @wenxu007, and @amdhelper.</li>
<li>Providers/DeepSeek: backfill DeepSeek V4 <code>reasoning_content</code> on plain assistant replay messages as well as tool-call turns, so thinking sessions with prior tool use no longer fail follow-up requests with missing reasoning content. Fixes #73417; refs #71372. Thanks @34262315716 and @Bartok9.</li>
<li>Agents/gateway tool: strip full config payloads from <code>config.patch</code> and <code>config.apply</code> tool responses while preserving direct RPC responses, so config-heavy sessions no longer replay large redacted configs into transcript history. Fixes #47610; supersedes #73439. Thanks @HanenVit and @juan-flores077.</li>
<li>Auto-reply: preserve voice-note media from silent turns while continuing to suppress text and non-voice media, so <code>NO_REPLY</code> TTS replies still deliver the requested audio bubble. (#73406) Thanks @zqchris.</li>
<li>Channels/Mattermost: stop enqueueing regular inbound posts as system events, so Mattermost user messages reach the model only as user-role inbound-envelope content instead of also appearing as <code>System: Mattermost message...</code> directives. Fixes #71795. Thanks @juan-flores077.</li>
<li>Agents/media: qualify bare <code>agents.defaults.imageModel</code> and <code>pdfModel</code> refs from unique configured image-capable providers, so Ollama vision models such as <code>moondream</code> and <code>qwen2.5vl:7b</code> do not fall through to the default provider. Fixes #38816; supersedes #73396. Thanks @alainasclaw and @vincentkoc.</li>
<li>Agents/Anthropic: send implicit Anthropic beta headers only to direct public Anthropic endpoints, including OAuth, so custom Anthropic-compatible providers no longer mis-handle unsupported beta flags unless explicitly configured. Refs #73346. Thanks @byBrodowski.</li>
<li>Skills: require explicit <code>skills.entries.coding-agent.enabled</code> before exposing the bundled coding-agent skill, so installs with Codex on PATH but no OpenAI auth do not silently offer Codex delegation. Fixes #73358. Thanks @LaFleurAdvertising and @Sanjays2402.</li>
<li>Plugins/startup: treat manifestless Claude bundles as valid installed-plugin registry entries instead of stale missing manifests, so workspace bundles no longer force repeated derived registry rebuilds or noisy <code>plugins.entries.workspace</code> warnings during Gateway startup. Fixes #73433. Thanks @AnneVoss.</li>
<li>Agents/subagents: preserve <code>sessions_yield</code> as a paused subagent state and ignore its wait text while freezing completion output, so parent sessions wait for the final post-compaction answer instead of receiving intermediate progress or <code>(no output)</code>. Fixes #73413. Thanks @Ask-sola.</li>
<li>Plugins/startup: precompute bundled runtime mirror fingerprints before taking the mirror lock and keep Docker bundled plugin runtime deps/mirrors in a Docker-managed volume instead of the Windows/WSL config bind mount, so cold starts avoid slow host-volume mirror writes. Fixes #73339. Thanks @1yihui.</li>
<li>Plugins/runtime deps: refresh bundled runtime mirrors without deleting active import trees, so config-triggered restarts do not see transient missing plugin files during registration. Thanks @shakkernerd.</li>
<li>Channels/LINE: persist inbound image, video, audio, and file downloads in <code>~/.openclaw/media/inbound/</code> instead of temporary files so agents can still read LINE media after <code>/tmp</code> cleanup. Fixes #73370. Thanks @hijirii and @wenxu007.</li>
<li>CLI/plugins: keep bundled plugin installs out of <code>plugins.load.paths</code> while preserving install records, so install/inspect/doctor loops no longer warn about the current bundled plugin directory. Thanks @vincentkoc.</li>
<li>CLI/plugins: scope <code>plugins inspect <id></code> runtime loading to the matched plugin so single-plugin inspection does not load every plugin before checking the target. Thanks @shakkernerd.</li>
<li>CLI/plugins: remove managed copied-path plugin directories during uninstall and plan uninstall from metadata instead of runtime-loading plugins, so plugin lifecycle commands avoid unnecessary bundled runtime-deps work. Thanks @shakkernerd.</li>
<li>Cron tool: infer the creating session's agentId for <code>cron.add</code> jobs when <code>agentId</code> is omitted or passed as undefined, keeping scheduled agentTurn jobs routed to the session agent; #40571 identified the guard bug and supplied the focused regression coverage. Thanks @ChanningYul.</li>
<li>Cron/Telegram: add <code>--thread-id</code> to <code>openclaw cron add</code> and <code>openclaw cron edit</code>, preserving Telegram forum topic delivery targets across scheduled announcements. Carries forward #51581, #60373, and #60890. Thanks @ChunHao-dev.</li>
<li>Cron/Telegram: preserve session-derived Telegram topic thread IDs when isolated cron delivery explicitly targets the parent chat, keeping bare chat targets in the active forum topic without leaking stale topics to other chats. Carries forward #64708. Thanks @addelh.</li>
<li>Memory/compaction: keep pre-compaction memory-flush prompts runtime-only so session transcripts and <code>chat.history</code> no longer expose them as normal user turns. Fixes #54408 and #58956; refs #43567. Thanks @markgong and @guoyuhang9.</li>
<li>Control UI/WebChat: keep large attachment payloads out of Lit state and optimistic chat messages, using object URL previews plus send-time payload serialization so PDF/image uploads no longer trigger <code>RangeError: Maximum call stack size exceeded</code>. Fixes #73360; refs #54378 and #63432. Thanks @hejunhui-73, @Ansub, and @christianhernandez3-afk.</li>
<li>Agents/Anthropic: cancel stalled Anthropic Messages SSE body reads when abort signals fire, so active-memory timeouts release transport resources instead of leaving hidden recall runs parked on <code>reader.read()</code>. Refs #72965 and #73120. Thanks @wdeveloper16.</li>
<li>Control UI/WebChat: keep pending run and typing state attached to the active client run, so unowned inject/announce/side-result finals no longer unlock unrelated active runs while completed owned runs still clear promptly. Fixes #57795; carries forward the narrow diagnosis from #57887. Thanks @haoyu-haoyu.</li>
<li>Sandbox/Docker: stop satisfying a missing default sandbox image by tagging plain Debian as <code>openclaw-sandbox:bookworm-slim</code>, preserving the Python tooling required by sandbox write/edit helpers and directing users to build the default image. Fixes #51185; refs #45108, #51099, #51609, and #57713. Thanks @dpalis, @Tin55FoilDev, @jbcohen2-coder, @macminihal-cyber, and @PraxoOnline.</li>
<li>Control UI/WebChat: confirm toolbar New Session button resets before dispatching <code>/new</code> while leaving typed <code>/new</code> and <code>/reset</code> commands immediate. Fixes #45800; refs #27065, #56611, #54499, and #27110. Thanks @aethnova, @kosta228-huli, @adambezemek, and @xss925175263 (xianshishan).</li>
<li>Agents/models: keep per-agent primary models strict when <code>fallbacks</code> is omitted, so probe-only custom providers are not tried as hidden fallback candidates unless the agent explicitly opts in. Fixes #73332. Thanks @haumanto.</li>
<li>Gateway/models: add <code>models.pricing.enabled</code> so offline or restricted-network installs can skip startup OpenRouter and LiteLLM pricing-catalog fetches while keeping explicit model costs working. Fixes #53639. Thanks @callebtc, @palewire, and @rjdjohnston.</li>
<li>Gateway/startup: warn when legacy <code>CLAWDBOT_*</code> or <code>MOLTBOT_*</code> environment variables are still present, pointing users to <code>OPENCLAW_*</code> names instead of failing silently. Fixes #53482; carries forward #53667. Thanks @lndyzwdxhs.</li>
<li>Onboarding: pin interactive and non-interactive health checks to the just-configured setup token/password so stale <code>OPENCLAW_GATEWAY_TOKEN</code> or <code>OPENCLAW_GATEWAY_PASSWORD</code> values do not produce false gateway-token-mismatch failures after setup. Fixes #72203. Thanks @galiniliev.</li>
<li>Doctor/state: require an interactive confirmation before archiving orphan transcript files, so <code>openclaw doctor --fix</code> no longer silently renames recoverable session history after upgrades regenerate <code>sessions.json</code>. Fixes #73106. Thanks @scottgl9.</li>
<li>Cron/Telegram: preserve explicit <code>:topic:</code> delivery targets over stale session-derived thread IDs when isolated cron announces to Telegram forum topics. Carries forward #59069; refs #49704 and #43808. Thanks @roytong9.</li>
<li>Build/runtime: write the runtime-postbuild stamp after <code>pnpm build</code> writes the build stamp, so the next CLI invocation does not re-sync runtime artifacts after a successful build. Fixes #73151. Thanks @bittoby.</li>
<li>Build/runtime: preserve staged bundled-plugin runtime dependency caches across source-checkout tsdown rebuilds, so local CLI and gateway-watch rebuilds no longer recreate large plugin dependency trees before starting. Refs #73205. Thanks @SymbolStar.</li>
<li>CLI/channels: list configured chat channel accounts from read-only setup metadata even when the standalone CLI has not loaded the runtime channel registry, so <code>openclaw channels list</code> shows Telegram accounts before auth providers. Fixes #73319 and #73322. Thanks @mlaihk.</li>
<li>CLI/model probes: keep <code>infer model run --gateway</code> raw by skipping prior session transcript, bootstrap context, context-engine assembly, tools, and bundled MCP servers, so local backends can be tested without full agent-context overhead. Fixes #73308. Thanks @ScientificProgrammer.</li>
<li>CLI/image describe: pass <code>--prompt</code> and <code>--timeout-ms</code> through <code>infer image describe</code> and <code>describe-many</code>, so custom vision instructions and slow local model budgets reach media-understanding providers such as Ollama, OpenAI, Google, and OpenRouter. Addresses #63700. Thanks @cedricjanssens.</li>
<li>Providers/Ollama: reject long non-linguistic Kimi/GLM symbol runs as provider failures instead of storing them as successful visible assistant replies, so fallback or error handling can recover from garbled cloud output. Fixes #64262; refs #67019. Thanks @Kloz813 and @xiaomenger123.</li>
<li>CLI/model probes: reject empty or whitespace-only <code>infer model run --prompt</code> values before calling local providers or the Gateway, so smoke checks do not spend provider calls on invalid turns. Fixes #73185. Thanks @iot2edge.</li>
<li>Gateway/media: route text-only <code>chat.send</code> image offloads through media-understanding fields so <code>agents.defaults.imageModel</code> can describe WebChat attachments instead of leaving only an opaque <code>media://inbound</code> marker. Fixes #72968. Thanks @vorajeeah.</li>
<li>Gateway/Windows: route no-listener restart handoffs through the Windows supervisor without leaving restart tokens in flight, so failed task scheduling can be retried and successful handoffs do not coalesce later restart requests. (#69056) Thanks @Thatgfsj.</li>
<li>Gateway/model pricing: skip plugin manifest discovery during background pricing refreshes when <code>plugins.enabled: false</code>, so disabled-plugin setups do not keep rebuilding plugin metadata from the Gateway hot path. Fixes #73291. Thanks @slideshow-dingo and @fishgills.</li>
<li>Ollama/thinking: validate <code>/think</code> commands against live Ollama catalog reasoning metadata and preserve explicit native <code>params.think</code>/<code>params.thinking</code>, so models whose <code>/api/show</code> capabilities include <code>thinking</code> expose <code>low</code>, <code>medium</code>, <code>high</code>, and <code>max</code> instead of being stuck on <code>off</code>. Fixes #73366. Thanks @cymise.</li>
<li>Gateway/sessions: remove automatic oversized <code>sessions.json</code> rotation backups, deprecate <code>session.maintenance.rotateBytes</code>, and teach <code>openclaw doctor --fix</code> to remove the ignored key so hot session writes no longer copy multi-MB stores. Refs #72338. Thanks @midhunmonachan and @DougButdorf.</li>
<li>Channels/Telegram: fail fast when Telegram rejects the startup <code>getMe</code> token probe with 401, so invalid or stale BotFather tokens are reported as token auth failures instead of misleading <code>deleteWebhook</code> cleanup failures. Fixes #47674. Thanks @samaedan-arch.</li>
<li>ACPX: keep generated Codex and Claude ACP wrapper startup paths working when remote or special state filesystems reject chmod, since OpenClaw invokes the wrappers through Node instead of executing them directly. Fixes #73333. Thanks @david-garcia-garcia.</li>
<li>CLI/onboarding: infer image input for common custom-provider vision model IDs, ask only for unknown models, and keep <code>--custom-image-input</code>/<code>--custom-text-input</code> overrides so vision-capable proxies do not get saved as text-only configs. Fixes #51869. Thanks @Antsoldier1974.</li>
<li>Models/OpenAI Codex: stop listing or resolving unsupported <code>openai-codex/gpt-5.4-mini</code> rows through Codex OAuth, keep stale discovery rows suppressed with a clear API-key-route hint, and leave direct <code>openai/gpt-5.4-mini</code> available. Fixes #73242. Thanks @0xCyda.</li>
<li>Plugin SDK: restore the root <code>stringEnum</code> and <code>optionalStringEnum</code> exports on both the published SDK entry and runtime root-alias bridge, so older external plugins can keep building and loading while migrating to focused SDK subpaths. Fixes #68279. Thanks @marzliak.</li>
<li>Plugin SDK: restore the root-alias bridge for <code>registerContextEngine</code> and expose missing legacy compat helpers <code>normalizeAccountId</code> and <code>resolvePreferredOpenClawTmpDir</code> so older external plugins such as <code>openclaw-weixin</code> can keep loading while migrating to focused SDK subpaths. Fixes #53497. Thanks @alanxchen85.</li>
<li>Auth profiles: make <code>openclaw doctor --fix</code> migrate legacy flat <code>auth-profiles.json</code> files such as <code>{ "ollama-windows": { "apiKey": "ollama-local" } }</code> to canonical provider default API-key profiles with a backup, so custom Ollama/OpenAI-compatible providers recover cleanly after upgrading. Fixes #59629; supersedes #59642. Thanks @Xsanders555 and @Linux2010.</li>
<li>Memory/Dreaming: retry Dream Diary once with the session default when a configured dreaming model is unavailable, while leaving subagent trust and allowlist errors visible instead of silently masking configuration problems. Refs #67409 and #69209. Thanks @Ghiggins18 and @everySympathy.</li>
<li>Feishu/inbound files: recover CJK filenames from plain <code>Content-Disposition: filename=</code> download headers when Feishu exposes UTF-8 bytes through Latin-1 header decoding, while leaving valid Latin-1 and JSON-derived names unchanged. (#48578, #50435, #59431) Thanks @alex-xuweilong, @lishuaigit, and @DoChaoing.</li>
<li>Channels/Telegram: normalize accidental full <code>/bot<TOKEN></code> Telegram <code>apiRoot</code> values at runtime and teach <code>openclaw doctor --fix</code> to remove the suffix, so startup control calls no longer 404 when direct Bot API curl commands work. Fixes #55387. Thanks @brendanmatthewjones-cmyk, @techfindubai-ux, and @Sivlerback-Chris.</li>
<li>Zalo Personal: persist refreshed <code>zca-js</code> session cookies after QR login, session restore, and successful API calls so gateway restarts restore the freshest local session. (#73277) Thanks @darkamenosa.</li>
<li>Logging/security: redact sensitive tokens (sk-\* keys, Bearer/Authorization values, etc.) at the subsystem console sink so <code>createSubsystemLogger().info/warn/error</code> output that bypasses the patched console-capture handler still applies the same redaction the file transport already does. Fixes #73284; refs #67953 and #64046. Thanks @edwin-rivera-dev.</li>
<li>Plugins/runtime deps: reuse enclosing versioned cache roots when bundled plugins resolve from nested staged paths, so plugin-runtime-deps no longer mints <code>openclaw-unknown-*</code> directories or loops on <code>ENOTEMPTY</code>. Fixes #72956. (#73205) Thanks @SymbolStar.</li>
<li>Agents/failover: classify CJK provider transport, quota, billing, auth, and overload error text so Chinese-language provider failures trigger fallback and user-facing transport copy instead of surfacing as unclassified raw errors. (#56242) Thanks @tomcatzh.</li>
<li>Agents/failover: seed non-claude-cli fallback prompts with Claude Code session context when a claude-cli attempt fails, so fallback models do not restart cold after billing or quota failover. (#72069) Thanks @stainlu.</li>
<li>Agents/CLI runner: transfer bundle-MCP tempDir cleanup from the per-turn runner finally to the Claude live-session lifecycle, so persistent Claude CLI sessions keep their <code>--mcp-config</code> directory until the live subprocess closes. Fixes #73244. Thanks @edwin-rivera-dev.</li>
<li>Gateway/nodes: allow Windows companion nodes to use safe declared commands such as canvas, camera list, location, device info, and screen snapshot by default while keeping dangerous media commands opt-in. (#71884) Thanks @shanselman.</li>
<li>Agents/cron: clarify agent-tool and CLI cron timezone guidance so supplied <code>tz</code> values use local wall-clock cron fields and omitted cron <code>tz</code> falls back to the Gateway host local timezone. Fixes #53669; carries forward #46177. (#73372) Thanks @chen-zhang-cs-code and @maranello-o.</li>
<li>Providers/Qwen: allow explicitly configured <code>qwen/qwen3.6-plus</code> to resolve on Qwen Coding Plan endpoints while keeping the built-in catalog from advertising it there. Fixes #63654; carries forward #63987. Thanks @jepson-liu.</li>
<li>Channels/Telegram: keep Bot API network fallbacks sticky after failed attempts and retry timed-out startup control calls once on the fallback route, so <code>deleteWebhook</code> IPv6 stalls no longer trigger slow multi-account retry storms. Fixes #73255. Thanks @ttomiczek and @sktbrd.</li>
<li>Gateway/agents: accept heartbeat, cron, and webhook as internal channel hints for agent runs so <code>sessions_spawn</code> works from non-delivery parent sessions while unknown channel hints still fail closed. Fixes #73237. Thanks @KeWang0622.</li>
<li>Gateway/models: merge explicit <code>models.providers.*.models</code> rows into the Gateway model catalog with normalized provider/model dedupe, and use normalized image-capability lookup so custom vision models keep native image attachments even when Pi discovery omits them or model ID casing differs. Fixes #64213 and #65165. Thanks @billonese and @202233a.</li>
<li>Gateway/reload: publish canonical post-write source config to in-process reloaders so simple config saves no longer create phantom plugin diffs or trigger unnecessary Gateway restarts. (#73267) Thanks @szsip239.</li>
<li>Gateway/Docker: keep config-triggered restarts in-process inside containers instead of spawning a detached child and exiting PID 1 cleanly, so Docker Swarm and other on-failure supervisors do not leave the service stuck at 0/1 replicas. Fixes #73178. Thanks @du-nguyen-IT007.</li>
<li>CLI/tasks: ship the task-registry control runtime in npm packages so <code>openclaw tasks cancel</code> can load ACP/subagent cancellation helpers from published builds. Fixes #68997. Thanks @1OAKDesign.</li>
<li>Channels/Telegram: preserve unsent generated media after partial reply streaming has already delivered the text, so <code>image_generate</code> outputs still reach Telegram as photos instead of being dropped from the final payload. Fixes #73253. Thanks @mlaihk.</li>
<li>Memory-core/dreaming: cap detached Dream Diary narrative subagents across cron sweeps so multi-workspace dreaming no longer fans out unbounded subagent sessions, lock contention, and cascading narrative timeouts. Fixes #73198. (#73287) Thanks @KeWang0622.</li>
<li>CLI/agents: close local one-shot Claude live stdio sessions and bundled MCP loopback resources after embedded <code>openclaw agent --local</code> runs, while keeping gateway-owned MCP loopback cleanup internal to the Gateway. Thanks @frankekn.</li>
<li>Export/session: keep inline export HTML scripts and vendor libraries injected after template formatting so generated session exports open with the app code, markdown renderer, and syntax highlighter present. Fixes #41862 and #49957; carries forward #41861 and #68947. Thanks @briannewman, @martenzi, and @armanddp.</li>
<li>Agents/ACPX: stage the patched Claude ACP adapter as an ACPX runtime dependency and route known Codex/Claude ACP commands through local wrappers, so Gateway runtime no longer depends on live <code>npx</code> adapter resolution. Fixes #73202. Thanks @joerod26.</li>
<li>Memory/compaction: let pre-compaction memory flush use an exact <code>agents.defaults.compaction.memoryFlush.model</code> override such as <code>ollama/qwen3:8b</code> without inheriting the active session fallback chain, so local housekeeping can avoid paid conversation models. Fixes #53772. Thanks @limen96.</li>
<li>macOS/update: stop managed Gateway services before package replacement and keep LaunchAgent service secrets out of world-readable plist metadata by loading them from owner-only env files. Fixes #72996. Thanks @Mathewb7.</li>
<li>Google Meet: keep observe-only Chrome joins and setup checks from requiring BlackHole or audio bridge commands, avoid granting or selecting the microphone in observe-only mode, and make <code>test_speech</code> report fresh realtime output-byte verification instead of only confirming a queued utterance. Refs #72478. Thanks @DougButdorf.</li>
<li>Gateway/hooks: route non-delivered hook completion and error summaries to the target agent's main session instead of the default agent session, preserving multi-agent hook isolation. Fixes #24693; carries forward #68667. Thanks @abersonFAC and @bluesky6868.</li>
<li>Control UI/models: request the configured Gateway model-list view so dashboards with only <code>models.providers.*.models</code> show those configured models first instead of flooding the picker with the full built-in catalog. Fixes #65405. Thanks @wbyanclaw.</li>
<li>CLI/models: keep default-model and allowlist pickers on explicit <code>models.providers.*.models</code> entries when <code>models.mode</code> is <code>replace</code> instead of loading the full built-in catalog. Fixes #64950. Thanks @mrozentsvayg.</li>
<li>Media/security: tighten media-understanding MIME sanitization so parameterized MIME values stay end-anchored and malformed whitespace or suffix payloads are rejected before file-context handling. Fixes #9795; carries forward #68225 with related review/test context from #61016/#68456. Thanks @ymaxgit, @bluesky6868, and @shamsulalam1114.</li>
<li>Discord: own the Carbon interaction listener and hand off Discord slash/component handling asynchronously, so compaction or long session locks no longer trip <code>InteractionEventListener</code> listener timeouts. Fixes #73204. Thanks @slideshow-dingo.</li>
<li>Compaction/diagnostics: keep unknown compaction failure classifications stable while logging sanitized detail for unclassified provider errors such as missing Ollama provider adapters. Thanks @gzsiang.</li>
<li>Models/fallbacks: record first-class <code>model.fallback_step</code> trajectory events with from/to models, failure detail, chain position, and final outcome so support exports preserve the primary model failure even when a later fallback also fails. Fixes #71744. Thanks @nikolaykazakovvs-ux.</li>
<li>Gateway/agents: block agent <code>exec</code> from launching interactive <code>openclaw channels login</code> flows and abort active agent runs after invalid-config recovery restores last-known-good config, preventing known channel-login and reload paths from wedging replies. Refs #72338. Thanks @midhunmonachan.</li>
<li>Gateway/diagnostics: emit payload-free liveness warnings with event-loop delay, event-loop utilization, CPU-core ratio, active-session counts, and OTEL warning metrics/spans so live-but-stalled Gateways capture CPU-spin context in stability bundles and telemetry. Refs #72338. Thanks @midhunmonachan and @DougButdorf.</li>
<li>Gateway/startup: keep value-option foreground starts on the gateway fast path and skip proxy bootstrap unless proxy env is configured, reducing normal gateway startup RSS and avoiding full CLI graph loading. Thanks @vincentkoc.</li>
<li>Heartbeat/models: show heartbeat model bleed guidance on context-overflow resets when the last runtime model matches configured <code>heartbeat.model</code>, so smaller local heartbeat models point users to <code>isolatedSession</code> or <code>lightContext</code> instead of only compaction-buffer tuning. Fixes #67314. Thanks @Knightmare6890.</li>
<li>Subagents/models: persist <code>sessions_spawn.model</code> and configured subagent models as child-session model overrides before the first turn, so spawned subagents actually run on the requested provider/model instead of reverting to the target agent default. Fixes #73180. Thanks @danielzinhu99.</li>
<li>Channels/Telegram: keep webhook-mode local listeners alive and retry Telegram <code>setWebhook</code> registration after recoverable startup network failures, so transient Bot API timeouts no longer leave reverse proxies pointing at a closed listener. Fixes #71834. Thanks @jinon86.</li>
<li>Agents/ACPX: bundle the Codex ACP adapter and launch it from the isolated <code>CODEX_HOME</code> wrapper before falling back to npm, so Codex ACP startup no longer depends on live <code>npx</code> resolution or the stale <code>@zed-industries/codex-acp@^0.11.1</code> range. Fixes #72037; refs #73202. Thanks @jasonftl, @sazora, and @joerod26.</li>
<li>Agents/ACPX: register the embedded ACP backend at Gateway startup through a lightweight ACP backend SDK path and without importing the heavy ACPX runtime until an ACP session or explicit startup probe needs it, reducing baseline Gateway RSS. Thanks @vincentkoc.</li>
<li>CLI/update: keep restart health polling when the restarted Gateway is reachable but has not reported its version yet, so macOS service restarts do not fail early with <code>actual unavailable</code>. Thanks @ProspectOre.</li>
<li>Backup: skip installed plugin <code>extensions/*/node_modules</code> dependency trees while keeping plugin manifests and source files in archives, so local backups avoid rebuildable npm payload bloat. Fixes #64144. Thanks @BrilliantWang.</li>
<li>Cron/models: fail isolated cron runs closed when an explicit <code>payload.model</code> is not allowed or cannot be resolved, so scheduled jobs do not silently fall back to an unrelated agent default or paid route before configured provider proxies such as LiteLLM can run. Fixes #73146. Thanks @oneandrewwang.</li>
<li>Memory/QMD: back off repeated chat-turn QMD open failures while still letting memory status and CLI probes recheck immediately, so a broken sidecar dependency cannot trigger active-memory or cron retry storms. Fixes #73188 and #73176. Thanks @leonlushgit and @w3i-William.</li>
<li>Talk Mode: resolve <code>messages.tts.providers.<id>.apiKey</code> through the active runtime snapshot for <code>talk.config</code>, so Talk overlays can discover SecretRef-backed speech providers without falling back to local speech. Fixes #73109. (#73111) Thanks @omarshahine.</li>
<li>Memory/Ollama: resolve <code>memorySearch.provider</code> custom provider ids through their configured <code>models.providers.<id>.api</code> owner, so multi-GPU Ollama setups can dedicate embeddings to providers such as <code>ollama-5080</code> without losing the Ollama adapter or local auth semantics. Fixes #73150. Thanks @oneandrewwang.</li>
<li>CLI/memory: skip eager context-window warmup for <code>openclaw memory</code> commands so memory search does not race unrelated model metadata discovery. Fixes #73123. Thanks @oalansilva and @neeravmakwana.</li>
<li>CLI/Telegram: route Telegram <code>message send</code> and poll actions through the running Gateway when available, so packaged installs use the staged <code>grammy</code> runtime deps and CLI sends return instead of hanging after the Telegram channel is active. Fixes #73140. Thanks @oalansilva.</li>
<li>Plugins/runtime deps: prepare staged bundled plugin dependencies before loading packaged public surfaces, so OpenClaw's Telegram runtime/test facade loads resolve <code>grammy</code> from the managed runtime-deps stage without copying dependencies into the global package root. Refs #73140. Thanks @oalansilva.</li>
<li>Agents/exec: emit <code>(no output)</code> for silent exec update and node-host result blocks so Anthropic-compatible providers no longer reject empty tool-result text after quiet commands. Fixes #73117. Thanks @pfrederiksen and @Sanjays2402.</li>
<li>Cron/providers: preflight local Ollama and OpenAI-compatible provider endpoints before isolated cron agent turns, record unreachable local providers as skipped runs, and cache dead-endpoint probes so many jobs do not hammer the same stopped local server. Fixes #58584. Thanks @jpeghead.</li>
<li>Gateway/config: let config reload continue in degraded mode when invalidity is scoped to plugin entries, so incompatible plugin configs can be skipped and the Gateway restart can still pick up the rest of the config after rollbacks. Fixes #73131. Thanks @Adam-Researchh.</li>
<li>Doctor/channels: suppress disabled bundled-plugin blocker warnings when a trusted external plugin owns the configured channel, so Lark/Feishu installs no longer get Feishu repair noise after switching to <code>openclaw-lark</code>. Fixes #56794. Thanks @wuji-tech-dev.</li>
<li>CLI/status: show skipped fast-path memory checks as <code>not checked</code> and report active custom memory plugin runtime status from <code>status --json --all</code> without requiring built-in <code>agents.defaults.memorySearch</code>, so plugins such as memory-lancedb-pro and memory-cms no longer look unavailable when their own runtime is healthy. Fixes #56968. Thanks @Tony-ooo and @aderius.</li>
<li>Gateway/channels: record and log unexpected clean channel monitor exits so channels that return without throwing no longer appear stopped with no error. Fixes #73099. Thanks @balaji1968-kingler.</li>
<li>Discord/group chats: keep group/channel replies private by default unless the agent explicitly uses the message tool, so always-on rooms can lurk without leaking automatic final, block, preview, or status-reaction output; <code>messages.groupChat.visibleReplies: "automatic"</code> restores legacy auto-posting. (#73046) Thanks @scoootscooob.</li>
<li>Plugins/package: force nested bundled-plugin runtime dependency installs out of inherited npm dry-run mode during prepack and package smoke checks, so packed installs materialize required plugin modules instead of reporting missing bundled files. Refs #73128. Thanks @Adam-Researchh.</li>
<li>Discord: skip reaction events before REST channel fetch when notifications are off, guild reactions are disabled, or allowlist mode cannot match without channel overrides, reducing reconnect bursts that caused slow listener warnings. Fixes #73133. Thanks @isaacsummers.</li>
<li>Channels/Telegram: centralize polling update tracking so accepted offsets remain durable across restarts, same-process handler failures can still retry, and slow offset writes cannot overwrite newer accepted watermarks. Refs #73115. Thanks @vdruts.</li>
<li>Agents/models: classify empty, reasoning-only, and planning-only terminal agent runs before accepting a model fallback candidate, so invalid or incompatible models can advance to the next configured fallback instead of returning a 30-second terminal failure. Fixes #73115. Thanks @vdruts.</li>
<li>Memory/LanceDB: let embedding config use provider-backed auth profiles, environment credentials, or provider config without a separate plugin <code>embedding.apiKey</code>, so OAuth-capable embedding providers can power auto-recall/capture. Fixes #68950. Thanks @malshaalan-ai.</li>
<li>CLI/parents: invoking <code>openclaw <parent></code> (memory, channels, plugins, approvals, devices, cron, mcp) without a subcommand now prints the parent's help and exits <code>0</code>, matching <code><parent> --help</code> and the existing <code>agents</code> / <code>sessions</code> defaults so shell <code>&&</code> chains and pnpm wrappers no longer surface a misleading <code>ELIFECYCLE Command failed with exit code 1.</code> line. Fixes #73077. Thanks @hclsys.</li>
<li>Plugins/hooks: time out never-settling <code>agent_end</code> observation hooks after 30 seconds and log the plugin failure, so hung embedding endpoints no longer leave memory capture silently pending forever. Fixes #65544. Thanks @ghoc0099.</li>
<li>Gateway/config: serve runtime config schemas from the current plugin metadata snapshot and generated bundled channel schema metadata instead of rebuilding plugin channel config modules on every <code>config.get</code>/<code>config.schema</code>, preventing idle plugin-discovery CPU churn after upgrades. Fixes #73088. Thanks @sleitor and @geovansb.</li>
<li>Memory/LanceDB: call OpenAI-compatible embedding endpoints through the raw SDK transport without sending <code>encoding_format</code>, then normalize float-array or base64 responses so providers such as ZhiPu and DashScope no longer fail recall with wrong vector dimensions or rejected parameters. Fixes #63655. Thanks @kinthaiofficial.</li>
<li>Plugins/install: run dependency installs with npm error-level logging instead of silent mode so failed plugin or hook installs surface actionable npm errors such as EUNSUPPORTEDPROTOCOL instead of <code>npm install failed:</code> with no detail. (#73093) Thanks @sanctrl.</li>
<li>Memory/LanceDB: bound memory recall embedding queries with a new <code>recallMaxChars</code> setting, prefer the latest user message over channel prompt metadata during auto-recall, and document the knob so small Ollama embedding models avoid context-length failures. Fixes #56780. Thanks @rungmc357 and @zak-collaborator.</li>
<li>CLI/skills: resolve workspace-backed skills commands from <code>--agent</code>, then the current agent workspace, before falling back to the default agent, so multi-agent ClawHub installs, updates, and status checks stay scoped to the active workspace. Fixes #56161; carries forward #72726. Thanks @langbowang and @luyao618.</li>
<li>Plugin SDK: fall back from partial bundled plugin directory overrides to package source public surfaces while preserving <code>OPENCLAW_DISABLE_BUNDLED_PLUGINS</code> as a hard disable. (#72817) Thanks @serkonyc.</li>
<li>Agents/ACPX: stop forwarding Codex ACP timeout config controls that Codex rejects while preserving OpenClaw's run-timeout watchdog for ACP subagents. Fixes #73052. Thanks @pfrederiksen and @richa65.</li>
<li>Memory Core: stream fallback vector search scoring with a bounded top-K result set so large indexes do not materialize every chunk embedding when sqlite-vec is unavailable. (#73069) Thanks @parkertoddbrooks.</li>
<li>Memory Core: stream embedding-cache seeding during safe reindex so large local caches do not materialize every row into the V8 heap before the atomic rebuild. (#73067) Thanks @parkertoddbrooks.</li>
<li>Memory/Ollama: add <code>memorySearch.remote.nonBatchConcurrency</code> for inline embedding indexing, default Ollama non-batch indexing to one request at a time, and keep batch concurrency separate from non-batch concurrency so local embedding backfills avoid timeout storms on smaller hosts. Carries forward #57733. Thanks @itilys.</li>
<li>macOS app: update Peekaboo, ElevenLabsKit, and MLX TTS helper dependencies, make canvas file watching and config/exec-approval state writes reliable under concurrent app/test activity, and keep the app plus helper builds warning-free. Thanks @Blaizzy.</li>
<li>iOS app: refresh SwiftPM/XcodeGen source hygiene, make app, extension, watch, and curated shared Swift files pass the prebuild SwiftFormat and SwiftLint checks, move relay registration off deprecated StoreKit receipt APIs, and keep simulator builds and logic tests warning-free. Thanks @ngutman.</li>
<li>Agents/models: keep <code>models.json</code> readiness and provider-hook caches warm across repeated agent and subagent model resolution while preserving external <code>models.json</code> invalidation, reducing repeated provider-plugin loads on slower ARM64 hosts. Fixes #73075. Thanks @jochen.</li>
<li>Docs/tools: clarify that <code>tools.profile: "messaging"</code> is intentionally narrow and that <code>tools.profile: "full"</code> is the unrestricted baseline for broader command/control access. Carries forward #39954. Thanks @posigit.</li>
<li>Control UI/Agents: redact tool-call args, partial/final results, derived exec output, and configured custom secret patterns before streaming tool events to the Control UI, so tool output cannot expose provider or channel credentials. Fixes #72283. (#72319) Thanks @volcano303 and @BunsDev.</li>
<li>Agents/sessions: keep <code>sessions_history</code> recall redaction enabled even when general log redaction is disabled, and clarify that safety-boundary UI/tool/diagnostic payloads still redact independently of <code>logging.redactSensitive</code>. Carries forward #72319. Thanks @volcano303 and @BunsDev.</li>
<li>Providers/Codex: pass agent and workspace directories into provider stream wrappers so Codex native <code>web_search</code> activation can evaluate the correct auth context, and smoke-test the built status-message runtime by resolving the emitted bundle name. Carries forward #67843; refs #65909. Thanks @neilofneils404.</li>
<li>Cron/models: keep <code>payload.model</code> as a per-job primary that can use configured fallbacks, while still letting <code>payload.fallbacks: []</code> make cron runs strict and avoid hidden agent-primary retries. Refs #73023. Thanks @pavelyortho-cyber.</li>
<li>Models/fallbacks: treat user-selected session models as exact choices, so <code>/model ollama/...</code> and model-picker switches fail visibly when the selected provider is unreachable instead of answering from an unrelated configured fallback. Fixes #73023. Thanks @pavelyortho-cyber.</li>
<li>Codex harness: keep ChatGPT subscription app-server runs from inheriting <code>CODEX_API_KEY</code> or <code>OPENAI_API_KEY</code>, and fall back to <code>CODEX_API_KEY</code> / <code>OPENAI_API_KEY</code> app-server login only when no Codex account is available. Fixes #73057. Thanks @holgergruenhagen and @pashpashpash.</li>
<li>CLI/model probes: fail local <code>infer model run</code> probes when the provider returns no text output, so unreachable local providers and empty completions no longer look like successful smoke tests. Refs #73023. Thanks @pavelyortho-cyber.</li>
<li>CLI/Ollama: run local <code>infer model run</code> through the lean provider completion path and skip global model discovery for one-shot local probes, so Ollama smoke tests no longer pay full chat-agent/tool startup cost or hang before the native <code>/api/chat</code> request. Fixes #72851. Thanks @TotalRes2020.</li>
<li>Doctor/gateway services: ignore launchd/systemd companion services that only reference the gateway as a dependency, suppress inactive Linux extra-service warnings, and avoid rewriting a running systemd gateway command/entrypoint during doctor repair. Carries forward #39118. Thanks @therk.</li>
<li>Daemon/service: only emit hard-coded version-manager paths such as <code>~/.volta/bin</code>, <code>~/.asdf/shims</code>, <code>~/.bun/bin</code>, and fnm/pnpm fallbacks into gateway and node service PATHs when the directories exist, so <code>openclaw doctor</code> no longer flags <code>gateway.path.non-minimal</code> against a PATH the daemon just wrote. Env-driven roots and stable user-bin dirs remain unconditional. Fixes #71944; carries forward #71964. Thanks @Sanjays2402.</li>
<li>CLI/startup: disable Node's module compile cache automatically for live source-checkout launchers so in-place <code>pnpm build</code> updates are visible to the next <code>openclaw</code> CLI invocation. Fixes #73037. Thanks @LouisGameDev.</li>
<li>Agents/group chat: keep silent-allowed empty and reasoning-only turns on the <code>NO_REPLY</code> path without injecting visible-answer retry prompts, and clarify the group prompt so agents use the exact silent token instead of prose. Thanks @vincentkoc.</li>
<li>Agents/group chat: move <code>NO_REPLY</code> mechanics into channel-aware direct/group prompts and suppress the duplicate generic silent-reply section for auto-reply runs, so always-on group agents get one consistent stay-silent instruction. Thanks @vincentkoc.</li>
<li>Providers/OpenAI: preserve encrypted empty-summary Responses reasoning items in WebSocket replay and request <code>reasoning.encrypted_content</code> on reasoning turns so GPT-5.4/GPT-5.5 sessions do not lose required <code>rs_*</code> state beside <code>msg_*</code> items. Fixes #73053. Thanks @odb36777.</li>
<li>Gateway/startup: treat <code>plugins.enabled=false</code> as an early plugin fast path, skipping plugin auto-enable discovery, gateway plugin lookup/runtime-dependency staging, and stale-plugin cleanup warnings while preserving channel blocker warnings. (#73041) Thanks @WuKongAI-CMU.</li>
<li>Channels/commands: make generated <code>/dock-*</code> commands switch the active session reply route through <code>session.identityLinks</code> instead of falling through to normal chat. Fixes #69206; carries forward #73033. Thanks @clawbones and @michaelatamuk.</li>
<li>Providers/Cloudflare AI Gateway: strip assistant prefill turns from Anthropic Messages payloads when thinking is enabled, so Claude requests through Cloudflare AI Gateway no longer fail Anthropic conversation-ending validation. Fixes #72905; carries forward #73005. Thanks @AaronFaby and @sahilsatralkar.</li>
<li>Gateway/startup: keep primary-model startup prewarm on scoped metadata preparation, let native approval bootstraps retry outside channel startup, and skip the global hook runner when no <code>gateway_start</code> hook is registered, so clean post-ready sidecar work stays off the critical path. Refs #72846. Thanks @RayWoo, @livekm0309, and @mrz1836.</li>
<li>Gateway/channels: start bundled channel accounts with a lightweight <code>runtimeContexts</code> surface instead of importing the full reply/routing/session channel runtime before <code>startAccount</code>, so Discord, Telegram, Slack, Matrix, and QQBot startup no longer block on unrelated channel helper graphs. Refs #72846 and #72960. Thanks @mrz1836, @RayWoo, and @rollingshmily.</li>
<li>Gateway/supervisor: exit cleanly when a supervised restart finds an existing healthy gateway and bound retries when the existing gateway stays unhealthy, so stale lock contention cannot loop indefinitely. Refs #72846. Thanks @azgardtek.</li>
<li>Gateway/startup: scope primary-model provider discovery during channel prewarm to the configured provider owner and add split startup trace timings, so boot avoids staging unrelated bundled provider dependencies while setup discovery remains broad. Fixes #73002. Thanks @Schnup03.</li>
<li>Plugins/runtime deps: declare retained staged bundled plugin dependencies in the npm staging manifest while installing only newly missing packages, so Gateway restarts avoid reinstalling the full retained dependency set when one runtime dependency is absent. Fixes #73055. Thanks @GCorp2026.</li>
<li>CLI/status: keep default <code>openclaw status</code> off the heavyweight security audit, plugin compatibility, and memory-vector probes while still showing configured Telegram channels through setup metadata, so routine health checks stay fast and no longer render an empty Channels table. Fixes #72993. Thanks @comick1.</li>
<li>Channels/Telegram: send a best-effort native typing cue immediately after an inbound message is accepted, so slow pre-dispatch turns show Telegram liveness before queueing, compaction, model, or tool work starts. Fixes #63759. Thanks @alessandropcostabr.</li>
<li>Channels/Telegram: stop native approval startup auth failures from retrying every second, while still waiting through retryable Gateway auth handoffs, so Telegram approval setup problems no longer create a reconnect/log loop during channel startup. Refs #72846 and #72867. Thanks @kiranvk-2011 and @porly1985.</li>
<li>Channels/Microsoft Teams: unwrap staged CommonJS JWT runtime dependencies before Bot Connector token validation so inbound Teams messages no longer 401 after the bundled runtime-deps move. Fixes #73026. Thanks @kbrown10000.</li>
<li>Gateway/auth: allow local direct callers in trusted-proxy mode to use the configured gateway password as an internal fallback while keeping token fallback rejected. Fixes #17761. Thanks @dashed, @vincentkoc, and @jetd1.</li>
<li>Gateway/auth: add explicit <code>trustedProxy.allowLoopback</code> support for same-host loopback reverse proxies while keeping loopback trusted-proxy auth fail-closed by default and preserving required-header and allowlist checks. Fixes #59167; carries forward #63379. Thanks @Matir, @jeremyakers, and @mrosmarin.</li>
<li>Channels/sessions: prevent guarded inbound session recording from creating route-only phantom sessions while still allowing last-route updates for sessions that already exist. Carries forward #73009. Thanks @jzakirov.</li>
<li>Cron: accept <code>delivery.threadId</code> in Gateway cron add/update schemas so scheduled announce delivery can target Telegram forum topics and other threaded channel destinations through the documented delivery path. Fixes #73017. Thanks @coachsootz.</li>
<li>Plugins/runtime deps: stage bundled plugin dependencies imported by mirrored root dist chunks, so packaged memory and status commands do not miss <code>chokidar</code> or similar root-chunk dependencies after update. Fixes #72882 and #72970; carries forward #72992. Thanks @shrimpy8, @colin-chang, and @Schnup03.</li>
<li>Plugins/runtime deps: reuse unchanged bundled plugin runtime mirrors instead of rebuilding plugin trees on every load, cutting avoidable writes and restart/reconnect I/O on slow storage. Fixes #72933. Thanks @jasonftl.</li>
<li>Agents/runtime context: deliver hidden runtime context through prompt-local system context while keeping the transcript-only custom entry out of provider user turns, and strip stale copied runtime-context prefaces from user-facing replies. Fixes #72386; carries forward #72969. Thanks @jhsmith409.</li>
<li>Channels/Telegram: skip the optional webhook-info API call during polling-mode status checks and startup bot-label probes so long-polling setups avoid an unnecessary Telegram round trip. Carries forward #72990. Thanks @danielgruneberg.</li>
<li>CLI/message: resolve targeted <code>openclaw message</code> channels to their owning plugin before loading the registry, and fall back to configured channel plugins when the channel must be inferred, so scripted sends avoid full bundled plugin registry scans without assuming channel ids match plugin ids. Fixes #73006. Thanks @jasonftl.</li>
<li>Plugins/startup: parse strict JSON plugin manifests with native JSON first and keep JSON5 as the compatibility fallback, reducing manifest registry CPU during Gateway boot and CLI startup. Fixes #73011. Thanks @jasonftl.</li>
<li>CLI/models: keep route-first <code>models status --json</code> stdout reserved for the JSON payload by routing auth-profile and startup diagnostics to stderr. Fixes #72962. Thanks @vishutdhar.</li>
<li>Gateway/runtime: keep dirty-tree status calls from rebuilding live <code>dist</code>, clear stale task and restart state across in-process restarts, retry transient Discord lazy imports, and let channel startup continue after slow model warmup so browser, Discord, and voice-call sidecars come online. Thanks @vincentkoc.</li>
<li>Security/CodeQL: replace file SecretRef id gateway schema regex validation with segment-aligned predicates and set empty permissions on release summary/backfill jobs so the narrowed CodeQL profile stays clean. Thanks @vincentkoc.</li>
<li>Sessions: ignore future-dated session activity timestamps during reset freshness checks and cap future <code>updatedAt</code> values at the merge boundary so clock-skewed messages cannot keep stale sessions alive forever. Fixes #72989. Thanks @martingarramon.</li>
<li>Sessions: apply search, activity filters, and limits before gateway row enrichment so bounded session lists avoid scanning discarded transcripts. Carries forward #72978. Thanks @yeager.</li>
<li>Sessions: remove trajectory runtime and pointer sidecars when session maintenance prunes, caps, or disk-evicts their owning session, while preserving sidecars still referenced by live rows. Fixes #73000. Thanks @jared-rebel.</li>
<li>Plugins/CLI: allow managed plugin installs when the active extensions root is a symlink to a real state directory, while keeping nested target symlinks blocked and suppressing misleading hook-pack fallback errors for install-boundary failures. Fixes #72946. Thanks @mayank6136.</li>
<li>Providers/Ollama: mark discovered Ollama catalog models as supporting streaming usage metadata so token accounting stays enabled for local models. (#72976) Thanks @sdeyang.</li>
<li>Media understanding: reject malformed MIME values with trailing junk while preserving standard parameter tails before enrichment uses them. (#72914) Thanks @volcano303.</li>
<li>WebChat: keep bare <code>/new</code> and <code>/reset</code> prompts from producing empty transcript text by inserting the hidden session marker when the visible tail is blank. (#72863) Thanks @mahopan.</li>
<li>CLI/update: explain completion-cache refresh timeouts with manual refresh guidance instead of surfacing a raw low-level timeout. Fixes #72842. (#72850) Thanks @iot2edge.</li>
<li>Memory-core/dreaming: give narrative generation a 60-second timeout so slower local or remote models can finish instead of timing out at 15 seconds. Fixes #72837. (#72852) Thanks @RayWoo.</li>
<li>Plugins/hooks: inject each plugin's resolved config into internal hook event context without mutating the shared event object. (#72888) Thanks @jalapeno777.</li>
<li>Agents/ACP: pass the resolved ACP agent directory into media understanding so per-agent media caches and config are used for ACP-dispatched image turns. (#72832) Thanks @luyao618.</li>
<li>Gateway/Bonjour: truncate mDNS service names and host labels to the 63-byte DNS label limit at valid UTF-8 boundaries. (#72809) Thanks @luyao618.</li>
<li>Feishu: treat groups explicitly configured under channels.feishu.groups as admitted even when groupAllowFrom is empty, while preserving groupPolicy: "disabled" as a hard group block and keeping groups.\* wildcard defaults non-admitting. Fixes #67687. (#72789) Thanks @MoerAI.</li>
<li>Gateway/startup: keep hot Gateway boot paths on leaf config imports and add max-RSS reporting to the gateway startup bench so low-memory startup regressions are visible before release. Thanks @vincentkoc.</li>
<li>WebChat: read <code>chat.history</code> from active transcript branches, drop stale streamed assistant tails once final history catches up, and coalesce duplicate in-flight Control UI submits, so rewritten prompts, completed replies, and rapid send events no longer render or process twice. Fixes #72975, #72963, and #72974. Thanks @dmagdici, @lhtpluto, and @Benjamin5281999.</li>
<li>WebChat/TTS: persist automatic final-mode TTS audio as a supplemental audio-only transcript update instead of adding a second assistant message with the same visible text. Fixes #72830. Thanks @lhtpluto.</li>
<li>Agents/LSP: terminate bundled stdio LSP process trees during runtime disposal and Gateway shutdown, so nested children such as <code>tsserver</code> do not survive stop or restart. Fixes #72357. Thanks @ai-hpc and @bittoby.</li>
<li>Diagnostics/OTEL: capture privacy-safe model-call request payload bytes, streamed response bytes, first-response latency, and total duration in diagnostic events, plugin hooks, stability snapshots, and OTEL model-call spans/metrics without logging raw model content. Fixes #33832. Thanks @wwh830.</li>
<li>Logging: write validated diagnostic trace context as top-level <code>traceId</code>, <code>spanId</code>, <code>parentSpanId</code>, and <code>traceFlags</code> fields in file-log JSONL records so traced requests and model calls are easier to correlate in log processors. Refs #40353. Thanks @liangruochong44-ui.</li>
<li>Logging/sessions: apply configured redaction patterns to persisted session transcript text and accept escaped character classes in safe custom redaction regexes, so transcript JSONL no longer keeps matching sensitive text in the clear. Fixes #42982. Thanks @panpan0000.</li>
<li>Providers/Ollama: honor <code>/api/show</code> capabilities when registering local models so non-tool Ollama models no longer receive the agent tool surface, and keep native Ollama thinking opt-in instead of enabling it by default. Fixes #64710 and duplicate #65343. Thanks @yuan-b, @netherby, @xilopaint, and @Diyforfun2026.</li>
<li>Control UI/Agents: remount the Overview model controls when switching agents so the primary-model picker cannot retain stale per-agent selection. Fixes #39392; carries forward #39401, notes the duplicate #39495 approach, and keeps #46275/#54724 broader stabilization out of scope. Thanks @daijunyi002, @SergioChan, @aworki, and @wsyjh8.</li>
<li>Auto-reply: poison inbound message dedupe after replay-unsafe provider/runtime failures so retries stay safe before visible progress but cannot duplicate messages after block output, tool side effects, or session progress. Fixes #69303; keeps #58549 and #64606 as duplicate validation. Thanks @martingarramon, @NikolaFC, and @zeroth-blip.</li>
<li>Agents/model fallback: jump directly to a known later live-session model redirect instead of walking unrelated fallback candidates, while preserving the already-landed live-session/fallback loop guard. Fixes #57471; related loop family already closed via #58496. Thanks @yuxiaoyang2007-prog.</li>
<li>Gateway/Bonjour: keep @homebridge/ciao cancellation handlers registered across advertiser restarts so late probing cancellations cannot crash Linux and other mDNS-churned gateways. Thanks @vincentkoc.</li>
<li>Plugins/startup: load the default <code>memory-core</code> slot during Gateway startup when permitted so active-memory recall can call <code>memory_search</code> and <code>memory_get</code> without requiring an explicit <code>plugins.slots.memory</code> entry, while preserving <code>plugins.slots.memory: "none"</code>. Thanks @vincentkoc.</li>
<li>Gateway/plugins: resolve <code>gateway_start</code> cron hooks from live Gateway runtime state before the legacy deps fallback, so memory-core dreaming cron reconciliation keeps working on installs where <code>deps.cron</code> is not populated during service startup. Fixes #72835. Thanks @RayWoo.</li>
<li>Plugins/CLI: prefer native require for compiled bundled plugin JavaScript before jiti so read-only config, status, device, and node commands avoid unnecessary transform overhead on slow hosts. Fixes #62842. Thanks @Effet.</li>
<li>Plugins/compat: inventory doctor-side deprecation migrations separately from runtime plugin compatibility so release sweeps preserve needed repairs while enforcing dated removal windows. Thanks @vincentkoc.</li>
<li>Plugins/compat: add missing dated compatibility records for legacy extension-api, memory registration, provider hook/type aliases, runtime aliases, channel SDK helpers, and approval/test utility shims. Thanks @vincentkoc.</li>
<li>Plugins/CLI: refresh the persisted registry after managed plugin files are removed so ClawHub uninstall cannot leave stale <code>plugins list</code> entries. Thanks @vincentkoc.</li>
<li>Plugins/CLI: make plugin install and uninstall config writes conflict-aware, clear stale denylist entries on explicit reinstall/removal, and delete managed plugin files only after config/index commit succeeds. Thanks @vincentkoc.</li>
<li>Plugins: fail <code>plugins update</code> when tracked plugin or hook updates error, keep bundled runtime-dependency repair behind restrictive allowlists, and reject package installs with unloadable extension entries. Thanks @vincentkoc.</li>
<li>WebChat/Control UI: support non-video file attachments in chat uploads while preserving the existing image attachment path and MIME-sniff fallback for generic image uploads. (#70947) Thanks @IAMSamuelRodda.</li>
<li>Skills/memory: restore Chokidar v5 hot reloads by watching concrete skill and memory roots with filters, including SKILL.md removals and deleted skill folders without broad workspace recursion. Fixes #27404, #33585, and #41606. Thanks @shelvenzhou, @08820048, and @rocke2020.</li>
<li>Gateway/chat: keep duplicate attachment-backed <code>chat.send</code> retries with the same idempotency key on the documented in-flight path so aborts still target the real active run. Fixes #70139. Thanks @Feelw00.</li>
<li>Gateway/chat: preserve repeated boundary characters while merging assistant chat stream deltas, including repeated digits, CJK characters, and markdown/table tokens. Fixes #63769; carries forward #63994 and #65457. Thanks @yon950905 and @mohuaxiao.</li>
<li>Plugins: share package entrypoint resolution between install and discovery, reject mismatched <code>runtimeExtensions</code>, and cache bundled runtime-dependency manifest reads during scans. Thanks @vincentkoc.</li>
<li>WhatsApp/Web: keep quiet but healthy linked-device sessions connected by basing the watchdog on WhatsApp Web transport activity, while retaining a longer app-silence cap so frame activity cannot mask a stuck session forever. Fixes #70678; carries forward the focused #71466 approach and keeps #63939 as related configurable-timeout follow-up. Thanks @vincentkoc and @oromeis.</li>
<li>Discord/gateway: count failed health-monitor restart attempts toward cooldown and hourly caps, and evict stale account lifecycle state during channel reloads so repeated Discord gateway recovery cannot loop on old status. Fixes #38596. (#40413) Thanks @jellyAI-dev and @vashquez.</li>
<li>TTS/BlueBubbles: pre-transcode synthesized MP3 audio to opus-in-CAF (mono, 24 kHz — validated against macOS 15.x Messages.app's native voice-memo CAF descriptor) on macOS hosts before handing the file to BlueBubbles, so iMessage renders the result as a native voice-memo bubble with proper duration and waveform UI instead of a plain file attachment. Adds an opt-in <code>tts.voice.preferAudioFileFormat</code> channel capability and a magic-byte sniff for the CAF container so the host-local-media validator (which uses <code>file-type</code> and didn't recognize CAF natively) can verify the pre-transcoded buffer. Channels that don't opt in are unaffected. (#72586) Fixes #72506. Thanks @omarshahine.</li>
<li>Feishu: retry WebSocket startup failures with monitor-owned backoff while preserving SDK-local heartbeat defaults, so persistent-connection startup failures no longer leave the monitor hung. Fixes #68766; related #42354 and #55532. Thanks @alex-xuweilong, @120106835, @sirfengyu, and @tianhaocui.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.4.27/OpenClaw-2026.4.27.zip" length="50595360" type="application/octet-stream" sparkle:edSignature="X8DQNQNWVcvtpYLkhZcsKNpnA78ycyzgGlZaG0XBY1GIph3oZNUIpAszGGocJVqTK7+F89Au5ZPb60mOqJQ6DQ=="/>
</item>
<item>
<title>2026.4.26</title>
<pubDate>Tue, 28 Apr 2026 02:40:27 +0000</pubDate>
@@ -641,53 +933,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.4.25/OpenClaw-2026.4.25.zip" length="48125363" type="application/octet-stream" sparkle:edSignature="RnQ01wCFgupauUdwOFan+XPGZhBJi/w3sgJYA5EaasbeGrduDHBGw1e9Zj2Lqb4ud8e6Q+tRcJVfxh5KKSEIDg=="/>
</item>
<item>
<title>2026.4.24</title>
<pubDate>Sat, 25 Apr 2026 19:34:45 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026042490</sparkle:version>
<sparkle:shortVersionString>2026.4.24</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.24</h2>
<h3>Highlights</h3>
<ul>
<li>Google Meet joins OpenClaw as a bundled participant plugin, with personal Google auth, Chrome/Twilio realtime sessions, paired-node Chrome support, artifact/attendance exports, and recovery tooling for already-open Meet tabs.</li>
<li>DeepSeek V4 Flash and V4 Pro are in the bundled catalog, V4 Flash is the onboarding default, and DeepSeek thinking/replay behavior is fixed for follow-up tool-call turns.</li>
<li>Talk, Voice Call, and Google Meet can use realtime voice loops that consult the full OpenClaw agent for deeper tool-backed answers.</li>
<li>Browser automation gets coordinate clicks, longer default action budgets, per-profile headless overrides, and steadier tab reuse/recovery.</li>
<li>Plugin and model infrastructure is lighter at startup: static model catalogs, manifest-backed model rows, lazy provider dependencies, and external runtime-dependency repair for packaged installs.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Packaged installs: preserve package-root runtime dependencies and their exported subpaths when bundled plugin runtime mirrors fall back to copying shared chunks, fixing Windows npm updates that could fail to load copied <code>dist</code> modules.</li>
<li>Heartbeat: clamp oversized scheduler delays through the shared safe timer helper, preventing <code>every</code> values over Node's timeout cap from becoming a 1 ms crash loop. Fixes #71414. (#71478) Thanks @hclsys.</li>
<li>Telegram: remove the startup persisted-offset <code>getUpdates</code> preflight so polling restarts do not self-conflict before the runner starts. Fixes #69304. (#69779) Thanks @chinar-amrutkar.</li>
<li>Browser/Playwright: ignore benign already-handled route races during guarded navigation so browser-page tasks no longer fail when Playwright tears down a route mid-flight. (#68708) Thanks @Steady-ai.</li>
<li>Browser/aria snapshots: bind <code>format=aria</code> <code>axN</code> refs to live DOM nodes through backend DOM ids when Playwright is available, so follow-up browser actions can use those refs without timing out. (#62434) Thanks @MrKipler.</li>
<li>Telegram: prevent duplicate in-process long pollers for the same bot token and add clearer <code>getUpdates</code> conflict diagnostics for external duplicate pollers. Fixes #56230.</li>
<li>Browser/Linux: detect Chromium-based installs under <code>/opt/google</code>, <code>/opt/brave.com</code>, <code>/usr/lib/chromium</code>, and <code>/usr/lib/chromium-browser</code> before asking users to set <code>browser.executablePath</code>. (#48563) Thanks @lupuletic.</li>
<li>Sessions/browser: close tracked browser tabs when idle, daily, <code>/new</code>, or <code>/reset</code> session rollover archives the previous transcript, preventing tabs from leaking past the old session. Thanks @jakozloski.</li>
<li>Sessions/forking: fall back to transcript-estimated parent token counts when cached totals are stale or missing, so oversized thread forks start fresh instead of cloning the full parent transcript. Thanks @jalehman.</li>
<li>OpenAI/Codex: send Codex Responses system prompts through top-level</li>
</ul>
<code>instructions</code> while preserving the existing native Codex payload controls.
<ul>
<li>MCP/CLI: retire bundled MCP runtimes at the end of one-shot <code>openclaw agent</code> and <code>openclaw infer model run</code> gateway/local executions, so repeated scripted runs do not accumulate stdio MCP child processes. Fixes #71457.</li>
<li>OpenAI/Codex image generation: canonicalize legacy <code>openai-codex.baseUrl</code> values such as <code>https://chatgpt.com/backend-api</code> to the Codex Responses backend before calling <code>gpt-image-2</code>, matching the chat transport. Fixes #71460.</li>
<li>Control UI: make <code>/usage</code> use the fresh context snapshot for context percentage, and include cache-write tokens in the Usage overview cache-hit denominator. Fixes #47885. Thanks @imwyvern and @Ante042.</li>
<li>GitHub Copilot: preserve encrypted Responses reasoning item IDs during replay so Copilot can validate encrypted reasoning payloads across requests. (#71448) Thanks @a410979729-sys.</li>
<li>Agents/replies: recover final-answer text when streamed assistant chunks contain only whitespace, preventing completed turns from surfacing as empty-payload errors. Fixes #71454. (#71467) Thanks @Sanjays2402.</li>
<li>Feishu/TTS: transcode voice-intent MP3 and other audio replies to Ogg/Opus before sending native Feishu audio bubbles, while keeping ordinary MP3 attachments as files. Fixes #61249 and #37868.</li>
<li>Telegram/webhook: acknowledge validated webhook updates before running bot middleware, keeping slow agent turns from tripping Telegram delivery retries while preserving per-chat processing lanes. Fixes #71392. Thanks @joelforsberg46-source.</li>
<li>MCP: retire one-shot embedded bundled MCP runtimes at run end, skip bundle-MCP startup when a runtime tool allowlist cannot reach bundle-MCP tools, and add <code>mcp.sessionIdleTtlMs</code> idle eviction for leaked session runtimes. Fixes #71106, #71110, #70389, and #70808.</li>
<li>MCP/config reload: hot-apply <code>mcp.*</code> changes by disposing cached session MCP runtimes, and dispose bundled MCP runtimes during gateway shutdown so removed <code>mcp.servers</code> entries reap child processes promptly. Fixes #60656.</li>
<li>Gateway/restart continuation: durably hand restart continuations to a session-delivery queue before deleting the restart sentinel, recover queued continuation work after crashy restarts, and fall back to a session-only wake when no channel route survives reboot. (#70780) Thanks @fuller-stack-dev.</li>
<li>Agents/tool-result pruning: harden the tool-result character estimator and context-pruning loops against malformed <code>{ type: "text" }</code> blocks created by void or undefined tool handler results, serializing non-string text payloads for size accounting so they cannot bypass trimming as zero-sized. Fixes #34979. (#51267) Thanks @cgdusek, @alvinttang, and @coffeexcoin.</li>
<li>Daemon/service-env: add Nix Home Manager profile bin directories to generated gateway service PATHs on macOS and Linux, honoring <code>NIX_PROFILES</code> right-to-left precedence and falling back to <code>~/.nix-profile/bin</code> when unset. Fixes #44402. (#59935) Thanks @jerome-benoit.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.4.24/OpenClaw-2026.4.24.zip" length="48033180" type="application/octet-stream" sparkle:edSignature="wxOfxadSZ/9iXMitaC6SA9J6YPZC3P2tkeK7HZPHzjUIlzQTvOl7EjR4aRyXzaYt1N1AK5ba+YhuCwEngrTdCQ=="/>
</item>
</channel>
</rss>

View File

@@ -11,9 +11,6 @@ indent_style = space
indent_size = 2
max_line_length = off
ktlint_standard_filename = disabled
ktlint_standard_function-expression-body = disabled
ktlint_standard_function-naming = disabled
ktlint_standard_if-else-bracing = disabled
ktlint_standard_max-line-length = disabled
ktlint_standard_no-wildcard-imports = disabled
ktlint_standard_property-naming = disabled

View File

@@ -33,10 +33,10 @@ if (wantsAndroidReleaseBuild && !hasAndroidReleaseSigning) {
}
plugins {
id("com.android.application")
id("org.jlleitschuh.gradle.ktlint")
id("org.jetbrains.kotlin.plugin.compose")
id("org.jetbrains.kotlin.plugin.serialization")
alias(libs.plugins.android.application)
alias(libs.plugins.ktlint)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
}
android {
@@ -78,13 +78,9 @@ android {
productFlavors {
create("play") {
dimension = "store"
buildConfigField("boolean", "OPENCLAW_ENABLE_SMS", "false")
buildConfigField("boolean", "OPENCLAW_ENABLE_CALL_LOG", "false")
}
create("thirdParty") {
dimension = "store"
buildConfigField("boolean", "OPENCLAW_ENABLE_SMS", "true")
buildConfigField("boolean", "OPENCLAW_ENABLE_CALL_LOG", "true")
}
}
@@ -133,15 +129,7 @@ android {
}
lint {
disable +=
setOf(
"AndroidGradlePluginVersion",
"GradleDependency",
"HighAppVersionCode",
"IconLauncherShape",
"NewerVersionAvailable",
"OldTargetApi",
)
lintConfig = file("lint.xml")
warningsAsErrors = true
}
@@ -184,57 +172,57 @@ ktlint {
}
dependencies {
val composeBom = platform("androidx.compose:compose-bom:2026.04.01")
val composeBom = platform(libs.androidx.compose.bom)
implementation(composeBom)
androidTestImplementation(composeBom)
implementation("androidx.core:core-ktx:1.18.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0")
implementation("androidx.activity:activity-compose:1.13.0")
implementation("androidx.webkit:webkit:1.15.0")
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.webkit)
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
// material-icons-extended pulled in full icon set (~20 MB DEX). Only ~18 icons used.
// R8 will tree-shake unused icons when minify is enabled on release builds.
implementation("androidx.compose.material:material-icons-extended")
implementation(libs.androidx.compose.material.icons.extended)
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation(libs.androidx.compose.ui.tooling)
// Material Components (XML theme + resources)
implementation("com.google.android.material:material:1.13.0")
implementation(libs.material)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0")
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.serialization.json)
implementation("androidx.security:security-crypto:1.1.0")
implementation("androidx.exifinterface:exifinterface:1.4.2")
implementation("com.squareup.okhttp3:okhttp:5.3.2")
implementation("org.bouncycastle:bcprov-jdk18on:1.84")
implementation("org.commonmark:commonmark:0.28.0")
implementation("org.commonmark:commonmark-ext-autolink:0.28.0")
implementation("org.commonmark:commonmark-ext-gfm-strikethrough:0.28.0")
implementation("org.commonmark:commonmark-ext-gfm-tables:0.28.0")
implementation("org.commonmark:commonmark-ext-task-list-items:0.28.0")
implementation(libs.androidx.security.crypto)
implementation(libs.androidx.exifinterface)
implementation(libs.okhttp)
implementation(libs.bcprov)
implementation(libs.commonmark)
implementation(libs.commonmark.ext.autolink)
implementation(libs.commonmark.ext.gfm.strikethrough)
implementation(libs.commonmark.ext.gfm.tables)
implementation(libs.commonmark.ext.task.list.items)
// CameraX (for node.invoke camera.* parity)
implementation("androidx.camera:camera-core:1.6.0")
implementation("androidx.camera:camera-camera2:1.6.0")
implementation("androidx.camera:camera-lifecycle:1.6.0")
implementation("androidx.camera:camera-video:1.6.0")
implementation("com.google.android.gms:play-services-code-scanner:16.1.0")
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.video)
implementation(libs.play.services.code.scanner)
// Unicast DNS-SD (Wide-Area Bonjour) for tailnet discovery domains.
implementation("dnsjava:dnsjava:3.6.4")
implementation(libs.dnsjava)
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
testImplementation("io.kotest:kotest-runner-junit5-jvm:6.1.11")
testImplementation("io.kotest:kotest-assertions-core-jvm:6.1.11")
testImplementation("com.squareup.okhttp3:mockwebserver:5.3.2")
testImplementation("org.robolectric:robolectric:4.16.1")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:6.0.3")
testImplementation(libs.junit)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.mockwebserver)
testImplementation(libs.robolectric)
testRuntimeOnly(libs.junit.vintage.engine)
}
tasks.withType<Test>().configureEach {

13
apps/android/app/lint.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<lint>
<issue id="AndroidGradlePluginVersion" severity="ignore" />
<issue id="GradleDependency" severity="ignore" />
<issue id="IconLauncherShape" severity="ignore" />
<issue id="NewerVersionAvailable" severity="ignore" />
<!-- OpenClaw uses date-based version codes (yyyyMMddNN), which are high but still below the Android max. -->
<issue id="HighAppVersionCode" severity="ignore" />
<!-- Target SDK follows the current release train; bump only after platform compatibility testing. -->
<issue id="OldTargetApi" severity="ignore" />
</lint>

View File

@@ -13,7 +13,33 @@ import ai.openclaw.app.gateway.GatewaySession
import ai.openclaw.app.gateway.GatewayTlsProbeFailure
import ai.openclaw.app.gateway.GatewayTlsProbeResult
import ai.openclaw.app.gateway.probeGatewayTlsFingerprint
import ai.openclaw.app.node.*
import ai.openclaw.app.node.A2UIHandler
import ai.openclaw.app.node.CalendarHandler
import ai.openclaw.app.node.CallLogHandler
import ai.openclaw.app.node.CameraCaptureManager
import ai.openclaw.app.node.CameraHandler
import ai.openclaw.app.node.CanvasController
import ai.openclaw.app.node.ConnectionManager
import ai.openclaw.app.node.ContactsHandler
import ai.openclaw.app.node.DEFAULT_SEAM_COLOR_ARGB
import ai.openclaw.app.node.DebugHandler
import ai.openclaw.app.node.DeviceHandler
import ai.openclaw.app.node.DeviceNotificationListenerService
import ai.openclaw.app.node.InvokeDispatcher
import ai.openclaw.app.node.LocationCaptureManager
import ai.openclaw.app.node.LocationHandler
import ai.openclaw.app.node.MotionHandler
import ai.openclaw.app.node.NodePresenceAliveBeacon
import ai.openclaw.app.node.NotificationsHandler
import ai.openclaw.app.node.PhotosHandler
import ai.openclaw.app.node.Quad
import ai.openclaw.app.node.SmsHandler
import ai.openclaw.app.node.SmsManager
import ai.openclaw.app.node.SystemHandler
import ai.openclaw.app.node.asObjectOrNull
import ai.openclaw.app.node.asStringOrNull
import ai.openclaw.app.node.invokeErrorFromThrowable
import ai.openclaw.app.node.parseHexColorArgb
import ai.openclaw.app.protocol.OpenClawCanvasA2UIAction
import ai.openclaw.app.voice.MicCaptureManager
import ai.openclaw.app.voice.TalkModeManager
@@ -103,8 +129,8 @@ class NodeRuntime(
private val deviceHandler: DeviceHandler =
DeviceHandler(
appContext = appContext,
smsEnabled = BuildConfig.OPENCLAW_ENABLE_SMS,
callLogEnabled = BuildConfig.OPENCLAW_ENABLE_CALL_LOG,
smsEnabled = SensitiveFeatureConfig.smsEnabled,
callLogEnabled = SensitiveFeatureConfig.callLogEnabled,
)
private val notificationsHandler: NotificationsHandler =
@@ -163,10 +189,10 @@ class NodeRuntime(
voiceWakeMode = { VoiceWakeMode.Off },
motionActivityAvailable = { motionHandler.isActivityAvailable() },
motionPedometerAvailable = { motionHandler.isPedometerAvailable() },
sendSmsAvailable = { BuildConfig.OPENCLAW_ENABLE_SMS && sms.canSendSms() },
readSmsAvailable = { BuildConfig.OPENCLAW_ENABLE_SMS && sms.canReadSms() },
smsSearchPossible = { BuildConfig.OPENCLAW_ENABLE_SMS && sms.hasTelephonyFeature() },
callLogAvailable = { BuildConfig.OPENCLAW_ENABLE_CALL_LOG },
sendSmsAvailable = { SensitiveFeatureConfig.smsEnabled && sms.canSendSms() },
readSmsAvailable = { SensitiveFeatureConfig.smsEnabled && sms.canReadSms() },
smsSearchPossible = { SensitiveFeatureConfig.smsEnabled && sms.hasTelephonyFeature() },
callLogAvailable = { SensitiveFeatureConfig.callLogEnabled },
hasRecordAudioPermission = { hasRecordAudioPermission() },
manualTls = { manualTls.value },
)
@@ -190,11 +216,11 @@ class NodeRuntime(
isForeground = { _isForeground.value },
cameraEnabled = { cameraEnabled.value },
locationEnabled = { locationMode.value != LocationMode.Off },
sendSmsAvailable = { BuildConfig.OPENCLAW_ENABLE_SMS && sms.canSendSms() },
readSmsAvailable = { BuildConfig.OPENCLAW_ENABLE_SMS && sms.canReadSms() },
smsFeatureEnabled = { BuildConfig.OPENCLAW_ENABLE_SMS },
sendSmsAvailable = { SensitiveFeatureConfig.smsEnabled && sms.canSendSms() },
readSmsAvailable = { SensitiveFeatureConfig.smsEnabled && sms.canReadSms() },
smsFeatureEnabled = { SensitiveFeatureConfig.smsEnabled },
smsTelephonyAvailable = { sms.hasTelephonyFeature() },
callLogAvailable = { BuildConfig.OPENCLAW_ENABLE_CALL_LOG },
callLogAvailable = { SensitiveFeatureConfig.callLogEnabled },
debugBuild = { BuildConfig.DEBUG },
refreshNodeCanvasCapability = { nodeSession.refreshNodeCanvasCapability() },
onCanvasA2uiPush = {

View File

@@ -1,6 +1,7 @@
package ai.openclaw.app.node
import ai.openclaw.app.BuildConfig
import ai.openclaw.app.SensitiveFeatureConfig
import ai.openclaw.app.gateway.GatewaySession
import android.Manifest
import android.app.ActivityManager
@@ -25,8 +26,8 @@ import java.util.Locale
class DeviceHandler(
private val appContext: Context,
private val smsEnabled: Boolean = BuildConfig.OPENCLAW_ENABLE_SMS,
private val callLogEnabled: Boolean = BuildConfig.OPENCLAW_ENABLE_CALL_LOG,
private val smsEnabled: Boolean = SensitiveFeatureConfig.smsEnabled,
private val callLogEnabled: Boolean = SensitiveFeatureConfig.callLogEnabled,
) {
companion object {
internal fun hasAnySmsCapability(

View File

@@ -1,8 +1,8 @@
package ai.openclaw.app.ui
import ai.openclaw.app.BuildConfig
import ai.openclaw.app.LocationMode
import ai.openclaw.app.MainViewModel
import ai.openclaw.app.SensitiveFeatureConfig
import ai.openclaw.app.gateway.GatewayEndpoint
import ai.openclaw.app.node.DeviceNotificationListenerService
import android.Manifest
@@ -248,10 +248,10 @@ fun OnboardingFlow(
val smsAvailable =
remember(context) {
BuildConfig.OPENCLAW_ENABLE_SMS &&
SensitiveFeatureConfig.smsEnabled &&
context.packageManager?.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) == true
}
val callLogAvailable = remember { BuildConfig.OPENCLAW_ENABLE_CALL_LOG }
val callLogAvailable = remember { SensitiveFeatureConfig.callLogEnabled }
val motionAvailable =
remember(context) {
hasMotionCapabilities(context)

View File

@@ -4,6 +4,7 @@ import ai.openclaw.app.BuildConfig
import ai.openclaw.app.LocationMode
import ai.openclaw.app.MainViewModel
import ai.openclaw.app.NotificationPackageFilterMode
import ai.openclaw.app.SensitiveFeatureConfig
import ai.openclaw.app.node.DeviceNotificationListenerService
import ai.openclaw.app.normalizeLocalHourMinute
import android.Manifest
@@ -204,10 +205,10 @@ fun SettingsSheet(viewModel: MainViewModel) {
val smsPermissionAvailable =
remember {
BuildConfig.OPENCLAW_ENABLE_SMS &&
SensitiveFeatureConfig.smsEnabled &&
context.packageManager?.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) == true
}
val callLogPermissionAvailable = remember { BuildConfig.OPENCLAW_ENABLE_CALL_LOG }
val callLogPermissionAvailable = remember { SensitiveFeatureConfig.callLogEnabled }
val photosPermission =
if (Build.VERSION.SDK_INT >= 33) {
Manifest.permission.READ_MEDIA_IMAGES

View File

@@ -0,0 +1,6 @@
package ai.openclaw.app
object SensitiveFeatureConfig {
const val smsEnabled: Boolean = false
const val callLogEnabled: Boolean = false
}

View File

@@ -0,0 +1,54 @@
package ai.openclaw.app.node
import ai.openclaw.app.gateway.GatewaySession
import android.content.Context
internal data class CallLogRecord(
val number: String?,
val cachedName: String?,
val date: Long,
val duration: Long,
val type: Int,
)
internal data class CallLogSearchRequest(
val limit: Int,
val offset: Int,
val cachedName: String?,
val number: String?,
val date: Long?,
val dateStart: Long?,
val dateEnd: Long?,
val duration: Long?,
val type: Int?,
)
internal interface CallLogDataSource {
fun hasReadPermission(context: Context): Boolean
fun search(
context: Context,
request: CallLogSearchRequest,
): List<CallLogRecord>
}
class CallLogHandler private constructor() {
constructor(
@Suppress("unused") appContext: Context,
) : this()
fun handleCallLogSearch(
@Suppress("unused") paramsJson: String?,
): GatewaySession.InvokeResult =
GatewaySession.InvokeResult.error(
code = "CALL_LOG_UNAVAILABLE",
message = "CALL_LOG_UNAVAILABLE: call log not available on this build",
)
companion object {
internal fun forTesting(
@Suppress("unused") appContext: Context,
@Suppress("unused") dataSource: CallLogDataSource,
): CallLogHandler = CallLogHandler()
}
}

View File

@@ -0,0 +1,69 @@
package ai.openclaw.app.node
import ai.openclaw.app.PermissionRequester
import android.content.Context
class SmsManager(
@Suppress("unused") private val context: Context,
) {
data class SendResult(
val ok: Boolean,
val to: String,
val message: String?,
val error: String? = null,
val payloadJson: String,
)
data class SmsMessage(
val id: Long,
val threadId: Long,
val address: String?,
val person: String?,
val date: Long,
val dateSent: Long,
val read: Boolean,
val type: Int,
val body: String?,
val status: Int,
val transportType: String? = null,
)
data class SearchResult(
val ok: Boolean,
val messages: List<SmsMessage>,
val error: String? = null,
val payloadJson: String,
)
fun attachPermissionRequester(
@Suppress("unused") requester: PermissionRequester,
) {
}
fun canSendSms(): Boolean = false
fun canSearchSms(): Boolean = false
fun canReadSms(): Boolean = false
fun hasTelephonyFeature(): Boolean = false
suspend fun send(paramsJson: String?): SendResult =
SendResult(
ok = false,
to = "",
message = null,
error = "SMS_PERMISSION_REQUIRED: grant SMS permission",
payloadJson = unavailablePayload(paramsJson),
)
suspend fun search(paramsJson: String?): SearchResult =
SearchResult(
ok = false,
messages = emptyList(),
error = "SMS_PERMISSION_REQUIRED: grant READ_SMS permission",
payloadJson = unavailablePayload(paramsJson),
)
private fun unavailablePayload(paramsJson: String?): String = """{"ok":false,"error":"SMS_UNAVAILABLE","paramsProvided":${!paramsJson.isNullOrBlank()}}"""
}

View File

@@ -0,0 +1,6 @@
package ai.openclaw.app
object SensitiveFeatureConfig {
const val smsEnabled: Boolean = true
const val callLogEnabled: Boolean = true
}

View File

@@ -0,0 +1,39 @@
package ai.openclaw.app.node
import ai.openclaw.app.gateway.GatewaySession
class SmsHandler(
private val sms: SmsManager,
) {
suspend fun handleSmsSend(paramsJson: String?): GatewaySession.InvokeResult {
val res = sms.send(paramsJson)
if (res.ok) {
return GatewaySession.InvokeResult.ok(res.payloadJson)
}
return errorResult(res.error, defaultCode = "SMS_SEND_FAILED")
}
suspend fun handleSmsSearch(paramsJson: String?): GatewaySession.InvokeResult {
val res = sms.search(paramsJson)
if (res.ok) {
return GatewaySession.InvokeResult.ok(res.payloadJson)
}
return errorResult(res.error, defaultCode = "SMS_SEARCH_FAILED")
}
private fun errorResult(
error: String?,
defaultCode: String,
): GatewaySession.InvokeResult {
val rawMessage = error ?: defaultCode
val idx = rawMessage.indexOf(':')
val code = if (idx > 0) rawMessage.substring(0, idx).trim() else defaultCode
val message =
if (idx > 0 && code == rawMessage.substring(0, idx).trim()) {
rawMessage.substring(idx + 1).trim().ifEmpty { rawMessage }
} else {
rawMessage
}
return GatewaySession.InvokeResult.error(code = code, message = message)
}
}

View File

@@ -1,6 +1,6 @@
plugins {
id("com.android.test")
id("org.jlleitschuh.gradle.ktlint")
alias(libs.plugins.android.test)
alias(libs.plugins.ktlint)
}
android {
@@ -39,7 +39,7 @@ ktlint {
}
dependencies {
implementation("androidx.benchmark:benchmark-macro-junit4:1.4.1")
implementation("androidx.test.ext:junit:1.3.0")
implementation("androidx.test.uiautomator:uiautomator:2.4.0-beta02")
implementation(libs.androidx.benchmark.macro.junit4)
implementation(libs.androidx.test.ext.junit)
implementation(libs.androidx.uiautomator)
}

View File

@@ -1,7 +1,7 @@
plugins {
id("com.android.application") version "9.2.0" apply false
id("com.android.test") version "9.2.0" apply false
id("org.jlleitschuh.gradle.ktlint") version "14.2.0" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.3.21" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "2.3.21" apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.test) apply false
alias(libs.plugins.ktlint) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.kotlin.serialization) apply false
}

View File

@@ -0,0 +1,74 @@
[versions]
agp = "9.2.0"
androidx-activity = "1.13.0"
androidx-benchmark = "1.4.1"
androidx-camera = "1.6.0"
androidx-compose-bom = "2026.04.01"
androidx-core = "1.18.0"
androidx-exifinterface = "1.4.2"
androidx-lifecycle = "2.10.0"
androidx-security = "1.1.0"
androidx-test-ext = "1.3.0"
androidx-uiautomator = "2.4.0-beta02"
androidx-webkit = "1.15.0"
bcprov = "1.84"
commonmark = "0.28.0"
coroutines = "1.10.2"
dnsjava = "3.6.4"
junit = "4.13.2"
junit-vintage = "6.0.3"
kotest = "6.1.11"
ktlint-gradle = "14.2.0"
kotlin = "2.3.21"
material = "1.13.0"
okhttp = "5.3.2"
play-services-code-scanner = "16.1.0"
robolectric = "4.16.1"
serialization-json = "1.11.0"
[libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark" }
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "androidx-camera" }
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
androidx-camera-video = { module = "androidx.camera:camera-video", version.ref = "androidx-camera" }
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidx-compose-bom" }
androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", version.ref = "androidx-exifinterface" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "androidx-security" }
androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-ext" }
androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx-uiautomator" }
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "androidx-webkit" }
bcprov = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bcprov" }
commonmark = { module = "org.commonmark:commonmark", version.ref = "commonmark" }
commonmark-ext-autolink = { module = "org.commonmark:commonmark-ext-autolink", version.ref = "commonmark" }
commonmark-ext-gfm-strikethrough = { module = "org.commonmark:commonmark-ext-gfm-strikethrough", version.ref = "commonmark" }
commonmark-ext-gfm-tables = { module = "org.commonmark:commonmark-ext-gfm-tables", version.ref = "commonmark" }
commonmark-ext-task-list-items = { module = "org.commonmark:commonmark-ext-task-list-items", version.ref = "commonmark" }
dnsjava = { module = "dnsjava:dnsjava", version.ref = "dnsjava" }
junit = { module = "junit:junit", version.ref = "junit" }
junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit-vintage" }
kotest-assertions-core = { module = "io.kotest:kotest-assertions-core-jvm", version.ref = "kotest" }
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5-jvm", version.ref = "kotest" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization-json" }
material = { module = "com.google.android.material:material", version.ref = "material" }
mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
play-services-code-scanner = { module = "com.google.android.gms:play-services-code-scanner", version.ref = "play-services-code-scanner" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-test = { id = "com.android.test", version.ref = "agp" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gradle" }

View File

@@ -245,6 +245,7 @@ gateway can only send pushes for iOS devices that paired with that gateway.
- Gateway connection via discovery or manual host/port with TLS fingerprint trust prompt.
- Chat + Talk surfaces through the operator gateway session.
- iPhone node commands in foreground: camera snap/clip, canvas present/navigate/eval/snapshot, screen record, location, contacts, calendar, reminders, photos, motion, local notifications.
- Authenticated background `node.presence.alive` beacons that update gateway last-seen metadata when the app moves between foreground and background, without treating suspended sockets as connected.
- Share extension deep-link forwarding into the connected gateway session.
## Computer Use Relationship

View File

@@ -184,7 +184,9 @@ final class CanvasManager {
private func maybeAutoNavigateToA2UI(controller: CanvasWindowController, a2uiUrl: String?) {
guard let a2uiUrl else { return }
let shouldNavigate = controller.shouldAutoNavigateToA2UI(lastAutoTarget: self.lastAutoA2UIUrl)
let shouldNavigate = controller.shouldAutoNavigateToA2UI(
lastAutoTarget: self.lastAutoA2UIUrl,
candidateTarget: a2uiUrl)
guard shouldNavigate else {
Self.logger.debug("canvas auto-nav skipped; target unchanged")
return

View File

@@ -319,12 +319,14 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
self.sessionDir.path
}
func shouldAutoNavigateToA2UI(lastAutoTarget: String?) -> Bool {
let trimmed = (self.currentTarget ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty || trimmed == "/" { return true }
func shouldAutoNavigateToA2UI(lastAutoTarget: String?, candidateTarget: String) -> Bool {
let current = (self.currentTarget ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
let candidate = candidateTarget.trimmingCharacters(in: .whitespacesAndNewlines)
if current.isEmpty || current == "/" { return true }
if !candidate.isEmpty, current == candidate { return false }
if let lastAuto = lastAutoTarget?.trimmingCharacters(in: .whitespacesAndNewlines),
!lastAuto.isEmpty,
trimmed == lastAuto
current == lastAuto
{
return true
}

View File

@@ -92,14 +92,6 @@ struct DebugSettings: View {
self.launchAgentWriteDisabled = GatewayLaunchAgentManager.isLaunchAgentWriteDisabled()
return
}
if newValue {
Task {
_ = await GatewayLaunchAgentManager.set(
enabled: false,
bundlePath: Bundle.main.bundlePath,
port: GatewayEnvironment.gatewayPort())
}
}
}
Text(

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