Adds cleanup handlers to release held file locks when the process
terminates via SIGTERM, SIGINT, or normal exit. This prevents orphaned
lock files that would block future sessions.
Fixes#1951
* security: add skill/plugin code safety scanner module
* security: integrate skill scanner into security audit
* security: add pre-install code safety scan for plugins
* style: fix curly brace lint errors in skill-scanner.ts
* docs: add changelog entry for skill code safety scanner
* security: redact credentials from config.get gateway responses
The config.get gateway method returned the full config snapshot
including channel credentials (Discord tokens, Slack botToken/appToken,
Telegram botToken, Feishu appSecret, etc.), model provider API keys,
and gateway auth tokens in plaintext.
Any WebSocket client—including the unauthenticated Control UI when
dangerouslyDisableDeviceAuth is set—could read every secret.
This adds redactConfigSnapshot() which:
- Deep-walks the config object and masks any field whose key matches
token, password, secret, or apiKey patterns
- Uses the existing redactSensitiveText() to scrub the raw JSON5 source
- Preserves the hash for change detection
- Includes 15 test cases covering all channel types
* security: make gateway config writes return redacted values
* test: disable control UI by default in gateway server tests
* fix: redact credentials in gateway config APIs (#9858) (thanks @abdelsfane)
---------
Co-authored-by: George Pickett <gpickett00@gmail.com>
- Sync latest changes from clawdbot-feishu including multi-account support
- Add eslint-disable comments for SDK-related any types
- Remove unused imports
- Fix no-floating-promises in monitor.ts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- monitor.ts: throw error for webhook mode instead of silently returning,
so gateway properly marks channel as failed
- targets.ts: default receive_id_type to "user_id" instead of "open_id"
for non-prefixed IDs, fixing message delivery for enterprise user IDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add line-specific eslint-disable-next-line comments for SDK type casts
and union type issues, rather than file-level disables.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(slack): add mention stripPatterns for /new and /reset commands
Fixes#9937
The Slack dock was missing mentions.stripPatterns that Discord has.
This caused /new and /reset to fail when sent with a mention
(e.g. @bot /reset) because <@USERID> wasn't stripped before matching.
* fix(slack): strip mentions for /new and /reset (#9971) (thanks @ironbyte-rgb)
---------
Co-authored-by: ironbyte-rgb <amontaboi76@gmail.com>
Co-authored-by: George Pickett <gpickett00@gmail.com>
Nextcloud Talk's ChecksumVerificationService verifies HMAC against the
extracted message/reaction text, not the full JSON body. This fixes 401
authentication errors when sending messages via the bot API.
- sendMessageNextcloudTalk: sign 'message' text only
- sendReactionNextcloudTalk: sign 'reaction' string only
* fix(cron): handle undefined sessionTarget in list output (#9649)
When sessionTarget is undefined, pad() would crash with 'Cannot read
properties of undefined (reading trim)'. Use '-' as fallback value.
* test(cron): add regression test for undefined sessionTarget (#9649)
Verifies that printCronList handles jobs with undefined sessionTarget
without crashing. Test fails on main branch, passes with the fix.
* fix: use correct CronSchedule format in tests (#9752) (thanks @lailoo)
Tests were using { kind: 'at', atMs: number } but the CronSchedule type
requires { kind: 'at', at: string } where 'at' is an ISO date string.
---------
Co-authored-by: damaozi <1811866786@qq.com>
Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
Fixes tool call/tool_result pairing issues that cause permanent session corruption when assistant messages have stopReason "error" or "aborted". Includes 4 unit tests.
* fix(cron): handle legacy atMs field in schedule when computing next run
The cron scheduler only checked for `schedule.at` (string) but legacy jobs
may have `schedule.atMs` (number) from before the schema migration.
This caused nextRunAtMs to stay null because:
1. Store migration runs on load but may not persist immediately
2. Race conditions or file mtime issues can skip migration
3. computeJobNextRunAtMs/computeNextRunAtMs only checked `at`, not `atMs`
Fix: Make both functions defensive by checking `atMs` first (number),
then `atMs` (string, for edge cases), then falling back to `at` (string).
This ensures jobs fire correctly even if:
- Migration hasn't run yet
- Old data was written by a previous version
- The store was manually edited
Fixes#9930
* fix: validate numeric atMs to prevent NaN/Infinity propagation
Addresses review feedback - numeric atMs values are now validated with
Number.isFinite() && atMs > 0 before use. This prevents corrupted or
manually edited stores from causing hot timer loops via setTimeout(..., NaN).
* fix(cron): prevent recomputeNextRuns from skipping due jobs in onTimer
ensureLoaded(forceReload) called recomputeNextRuns before runDueJobs,
which recalculated nextRunAtMs to a strictly future time. Since
setTimeout always fires a few ms late, the due check (now >= nextRunAtMs)
always failed and every/cron jobs never executed. Fixes#9788.
* docs: add changelog entry for cron timer race fix (#9823) (thanks @pycckuu)
---------
Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
* fix(telegram): accept messages from group members in allowlisted groups
Issue #4559: Telegram bot was silently dropping messages from non-paired users
in allowlisted group chats due to overly strict sender filtering.
The fix adds a check to distinguish between:
1. Group itself is allowlisted → accept messages from any member
2. Group is NOT allowlisted → only accept from allowlisted senders
Changes:
- Check if group ID is in the allowlist (or allowlist is wildcard)
- Only reject sender if they're not in allowlist AND group is not allowlisted
- Improved logging to indicate the actual reason for rejection
This preserves security controls while fixing the UX issue where group members
couldn't participate unless individually allowlisted.
Backwards compatible: existing allowlists continue to work as before.
* style: format telegram fix for oxfmt compliance
* refactor(telegram): clarify group allowlist semantics in fix for #4559
Changes:
- Rename 'isGroupInAllowlist' to 'isGroupChatIdInAllowlist' for clarity
- Expand comments to explain the semantic distinction:
* Group chat ID in allowlist -> accept any group member (fixes#4559)
* Group chat ID NOT in allowlist -> enforce sender allowlist (preserves security)
- This addresses concerns about config semantics raised in code review
The fix maintains backward compatibility:
- 'groupAllowFrom' with group chat IDs now correctly acts as group enablement
- 'groupAllowFrom' with sender IDs continues to work as sender allowlist
- Operators should use group chat IDs for group enablement, sender IDs for sender control
Note: If operators were using 'groupAllowFrom' with group IDs expecting sender-level
filtering, they should migrate to a separate sender allowlist config. This is the
intended behavior per issue #4559.
* Telegram: allow per-group groupPolicy overrides
* Telegram: support per-group groupPolicy overrides (#9775) (thanks @nicolasstanley)
---------
Co-authored-by: George Pickett <gpickett00@gmail.com>
* docs: restructure Get Started tab and improve onboarding flow
- Flatten nested Onboarding group into linear First Steps flow
- Add 'What is OpenClaw?' narrative section to landing page
- Split wizard.md into streamlined overview + full reference (reference/wizard.md)
- Move Pairing to Channels > Configuration
- Move Bootstrapping to Agents > Fundamentals
- Move macOS app onboarding to Platforms > macOS companion app
- Move Lore to Help > Community
- Remove duplicate install instructions from openclaw.md
- Mirror navigation changes in zh-CN tabs
- No content deleted — all detail preserved or relocated
* docs: move deployment pages to install/, fix Platforms tab routing, clarify onboarding paths
- Move deployment guides (fly, hetzner, gcp, macos-vm, exe-dev, railway, render,
northflank) from platforms/ and root to install/
- Add 'Hosting and deployment' group to Install tab
- Slim Gateway & Ops 'Remote access and deployment' down to 'Remote access'
- Swap Platforms tab before Gateway & Ops to fix path-prefix routing
- Move macOS app onboarding into First steps (parallel to CLI wizard)
- Rename sidebar titles to 'Onboarding: CLI' / 'Onboarding: macOS App'
- Add redirects for all moved paths
- Update all internal links (en + zh-CN)
- Fix img tag syntax in onboarding.md
Add a more prominent security warning for multi-user DM setups:
- Add blockquote security warning about context leakage
- Include concrete example showing the privacy risk
- Add "When to enable this" checklist
- Clarify that default is fine for single-user setups
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(errors): return clear billing error message instead of cryptic raw error (#8136)
When an LLM API provider returns a credit/billing-related error (HTTP 402,
insufficient credits, low balance, etc.), OpenClaw now shows a clear,
actionable message instead of passing through the raw/cryptic error text:
⚠️ API provider returned a billing error — your API key has run out of
credits or has an insufficient balance. Check your provider's billing
dashboard and top up or switch to a different API key.
Changes:
- formatAssistantErrorText: detect billing errors via isBillingErrorMessage()
and return a user-friendly message (placed before the generic HTTP/JSON
error fallthrough)
- sanitizeUserFacingText: same billing detection for the sanitization path
- pi-embedded-runner/run.ts: add billingFailure detection in the profile
exhaustion fallback, so the FailoverError message is billing-specific
- Added 3 new tests for credit balance, HTTP 402, and insufficient credits
* fix: extract billing error message to shared constant
Previously, overflowCompactionAttempted was a boolean flag set once, preventing
recovery when a single compaction wasn't enough. Change to a counter allowing up
to 3 attempts before giving up. Also add diagnostic logging on overflow events to
help debug early-overflow issues.
Fixes sessions that hit context overflow during long agentic turns with many tool
calls, where one compaction round isn't sufficient to bring context below limits.
When starting a new session via /new or /reset, the token usage fields
(totalTokens, inputTokens, outputTokens, contextTokens) survived from the
previous session via the spread pattern in session init. This caused /status
to display misleading context usage from the old session.
Clear all four token metrics explicitly in the isNewSession block, alongside
the existing compactionCount reset. Also add diagnostic logging for session
forking via ParentSessionKey to help trace context inheritance.
* fix(runtime): bump minimum Node.js version to 22.12.0
Aligns the runtime guard with the declared package.json engines requirement.
The Matrix plugin (and potentially others) requires Node >= 22.12.0,
but the runtime guard previously allowed 22.0.0+. This caused confusing
errors like 'Cannot find module @vector-im/matrix-bot-sdk' when the real
issue was an unsupported Node version.
- Update MIN_NODE from 22.0.0 to 22.12.0
- Update error message to reflect the correct version
- Update tests to use 22.12.0 as the minimum valid version
Fixes#5292
* fix: update test versions to match MIN_NODE=22.12.0
---------
Co-authored-by: Markus Glucksberg <markus@glucksberg.com>
* fix(cron): prevent timer from allowing process exit (fixes#9694)
The cron timer was using .unref(), which caused the Node.js event
loop to exit or sleep if no other handles were active. This prevented
cron jobs from firing in some environments.
* fix(cron): infer delivery target for isolated jobs (fixes#9683)
When creating isolated agentTurn jobs (e.g. reminders) without explicit
delivery options, the job would default to 'announce' but fail to
resolve the target conversation. Now, we infer the channel and
recipient from the agent's current session key.
* fix(cron): enhance delivery inference for threaded sessions and null inputs (#9733)
Improves the delivery inference logic in the cron tool to correctly handle threaded session keys and cases where delivery is explicitly set to null. This ensures that the appropriate delivery mode and target are inferred based on the agent's session key, enhancing the reliability of job execution.
* fix: preserve telegram topic delivery inference (#9733) (thanks @tyler6204)
* fix: simplify cron delivery merge spread (#9733) (thanks @tyler6204)
When pruneHistoryForContextShare drops chunks of messages, it could drop
an assistant message with tool_use blocks while leaving corresponding
tool_result messages in the kept portion. These orphaned tool_results
cause Anthropic's API to reject the session with 'unexpected tool_use_id'.
Fix by calling repairToolUseResultPairing after each chunk drop to clean
up any orphaned tool_results. This reuses existing battle-tested code
from session-transcript-repair.ts.
Fixes#9769, #9724, #9672
What:
- require the bot open_id match for group mention detection when available
Why:
- prevent replies when other users are mentioned and the bot id is known
Tests:
- pnpm test
What:
- add post parsing, doc link extraction, routing, replies, reactions, typing, and user lookup
- fix media download/send flows and make doc fetches domain-aware
- update Feishu docs and clawtributor credits
Why:
- raise Feishu parity with other channels and avoid dropped group messages
- keep replies threaded while supporting Lark domains
- document new configuration and credit the contributor
Tests:
- pnpm build
- pnpm check
- pnpm test (gateway suite timed out; reran pnpm vitest run --config vitest.gateway.config.ts)
Co-authored-by: 九灵云 <server@jiulingyun.cn>
* feat: add Claude Opus 4.6 to built-in model catalog
- Update default model from claude-opus-4-5 to claude-opus-4-6
- Add opus-4.6 model ID normalization
- Add claude-opus-4-6 to live model filter prefixes
- Update image tool to prefer claude-opus-4-6 for vision
- Add CLI backend alias for opus-4.6
- Update onboard auth default selections to include opus-4.6
- Update model picker placeholder
Closes#9811
* test: update tests for claude-opus-4-6 default
- Fix model-alias-defaults test to use claude-opus-4-6
- Fix image-tool test to expect claude-opus-4-6 in fallbacks
* feat: support claude-opus-4-6
* docs: update changelog for opus 4.6 (#9853) (thanks @TinyTb)
* chore: bump pi to 0.52.0
---------
Co-authored-by: Slurpy <slurpy@openclaw.ai>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Both English and Chinese documentation had incorrect configuration template
using 'fallback' instead of 'fallbacks' in agents.defaults.model config.
Co-authored-by: damaozi <1811866786@qq.com>