* 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
* 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>
* 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>
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
* 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>
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>
* 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>
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>
* 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>
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
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.