fix(slack): detect control commands when message starts with @mention#14142
Merged
gumadeiras merged 3 commits intoopenclaw:mainfrom Feb 11, 2026
Merged
fix(slack): detect control commands when message starts with @mention#14142gumadeiras merged 3 commits intoopenclaw:mainfrom
gumadeiras merged 3 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 265e40d905
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ade7e72 to
cb0b4f6
Compare
Member
GoddessSerenity
pushed a commit
to GoddessSerenity/openclaw
that referenced
this pull request
Feb 12, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
Hansen1018
pushed a commit
to Hansen1018/openclaw
that referenced
this pull request
Feb 12, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
Takhoffman
pushed a commit
to tomsun28/openclaw
that referenced
this pull request
Feb 12, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
sauerdaniel
pushed a commit
to sauerdaniel/openclaw
that referenced
this pull request
Feb 12, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
dbachelder
pushed a commit
to dbachelder/openclaw
that referenced
this pull request
Feb 13, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
Baukebrenninkmeijer
pushed a commit
to orq-ai/openclaw
that referenced
this pull request
Feb 13, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
skyhawk14
pushed a commit
to skyhawk14/openclaw
that referenced
this pull request
Feb 13, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
jbold
added a commit
to jbold/openclaw
that referenced
this pull request
Feb 15, 2026
* chore: bump version to 2026.2.10 * docs: start 2026.2.10 changelog section * Feat/litellm provider (#12823) * feat: add LiteLLM provider types, env var, credentials, and auth choice Add litellm-api-key auth choice, LITELLM_API_KEY env var mapping, setLitellmApiKey() credential storage, and LITELLM_DEFAULT_MODEL_REF. * feat: add LiteLLM onboarding handler and provider config Add applyLitellmProviderConfig which properly registers models.providers.litellm with baseUrl, api type, and model definitions. This fixes the critical bug from PR #6488 where the provider entry was never created, causing model resolution to fail at runtime. * docs: add LiteLLM provider documentation Add setup guide covering onboarding, manual config, virtual keys, model routing, and usage tracking. Link from provider index. * docs: add LiteLLM to sidebar navigation in docs.json Add providers/litellm to both English and Chinese provider page lists so the docs page appears in the sidebar navigation. * test: add LiteLLM non-interactive onboarding test Wire up litellmApiKey flag inference and auth-choice handler for the non-interactive onboarding path, and add an integration test covering profile, model default, and credential storage. * fix: register --litellm-api-key CLI flag and add preferred provider mapping Wire up the missing Commander CLI option, action handler mapping, and help text for --litellm-api-key. Add litellm-api-key to the preferred provider map for consistency with other providers. * fix: remove zh-CN sidebar entry for litellm (no localized page yet) * style: format buildLitellmModelDefinition return type * fix(onboarding): harden LiteLLM provider setup (#12823) * refactor(onboarding): keep auth-choice provider dispatcher under size limit --------- Co-authored-by: Peter Steinberger <[email protected]> * fix(web-search): handle xAI Responses API format in Grok provider The xAI /v1/responses API returns content in a structured format with typed output blocks (type: 'message') containing typed content blocks (type: 'output_text') and url_citation annotations. The previous code only checked output[0].content[0].text without filtering by type, which could miss content in responses with multiple output entries. Changes: - Update GrokSearchResponse type to include annotations on content blocks - Filter output blocks by type='message' and content by type='output_text' - Extract url_citation annotations as fallback citations when top-level citations array is empty - Deduplicate annotation-derived citation URLs - Update tests for the new structured return type Closes #13520 * fix(gateway): default-deny missing connect scopes * fix(plugins): ignore install scripts during plugin/hook install * fix: don't lowercase Slack channel IDs (#14055) * feat: Add --localTime option to logs command for local timezone display (#13818) * feat: add --localTime options to make logs to show time with local time zone fix #12447 * fix: prep logs local-time option and docs (#13818) (thanks @xialonglee) --------- Co-authored-by: xialonglee <[email protected]> Co-authored-by: Sebastian <[email protected]> * fix(config): avoid redacting maxTokens-like fields (#14006) * fix(config): avoid redacting maxTokens-like fields * fix(config): finalize redaction prep items (#14006) (thanks @constansino) --------- Co-authored-by: Sebastian <[email protected]> * fix(cli): drop logs --localTime alias noise * chore(irc): sync plugin version to 2026.2.10 * chore: update AGENTS.md and add mintlify skill (#14123) * docs(skills): update mintlify skill to reference docs/ directory (#14125) * docs: modernize gateway configuration page (Phase 1) (#14111) * docs(configuration): split into overview + full reference with Mintlify components * docs(configuration): use tooltip for JSON5 format note * docs(configuration): fix Accordion closing tags inside list contexts * docs(configuration): expand intro to reflect full config surface * docs(configuration): trim intro to three concise bullets * docs(configuration-examples): revert all branch changes * docs(configuration): improve hot-reload section with tabs and accordion * docs(configuration): uncramp hot-reload — subheadings, bullet list, warning * docs(configuration): restore hot-apply vs restart table * docs(configuration): fix hot-reload table against codebase * docs: add configuration-reference.md — full field-by-field reference * docs(gateway): refresh runbook and align config reference * docs: include pending docs updates and install graphic * fix: use configured base URL for Ollama model discovery (#14131) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 2292d2de6d6a4608fba8124ace738df75ae890fc Co-authored-by: shtse8 <[email protected]> Reviewed-by: @gumadeiras * fix(slack): detect control commands when message starts with @mention (#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6a3b675bceb7e59b8939b4800f813bc069 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * docs(channels): modernize telegram docs page (#14168) * docs(channels): fix telegram card icon (#14193) * PI: assign landpr to self * docs(channels): modernize discord docs page (#14190) * docs(nav): move grammy page to technical reference (#14198) * fix(discord): default standalone threads to public type (#14147) When creating a Discord thread without a messageId, the API defaults to type 12 (private thread) which is unexpected. This adds an explicit type: PublicThread (11) for standalone thread creation in non-forum channels, matching user expectations. Closes #14147 * fix(discord): default standalone threads to public type (#14147) When creating a Discord thread without a messageId (standalone thread), the Discord API defaults to type 12 (private). Most users expect public. - Default standalone non-forum threads to ChannelType.PublicThread (11) - Add optional type field to DiscordThreadCreate for explicit control Closes #14147 * Discord: honor explicit thread type * docs(channels): modernize whatsapp docs page (#14202) * fix(agents): honor heartbeat.model override instead of session model (#14181) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: f19b789057e03d424ee20baf3c678475ad94f72f Co-authored-by: 0xRaini <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * docs(channels): modernize slack docs page (#14205) * fix: report subagent timeout as 'timed out' instead of 'completed successfully' (#13996) * fix: report subagent timeout as 'timed out' instead of 'completed successfully' * fix: propagate subagent timeout status across agent.wait (#13996) (thanks @dario-github) --------- Co-authored-by: Sebastian <[email protected]> * docs(channels): modernize imessage docs page (#14213) * fix(cli): exit with non-zero code when configure/agents-add wizards are cancelled (#14156) * fix(cli): exit with non-zero code when configure/agents-add wizards are cancelled Follow-up to the onboard cancel fix. The configure wizard and agents add wizard also caught WizardCancelledError and exited with code 0, which signals success to callers. Change to exit(1) for consistency — user cancellation is not a successful completion. This ensures scripts that chain these commands with set -e will correctly stop when the user cancels. * fix(cli): make wizard cancellations exit non-zero (#14156) (thanks @0xRaini) --------- Co-authored-by: Rain <[email protected]> Co-authored-by: Sebastian <[email protected]> * chore: making PR review chores deterministic + less token hungry * fix(heartbeat): honor heartbeat.model config for heartbeat turns (#14103) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: f46080b0adb882c4d18af7ac0e80055505ff640c Co-authored-by: shtse8 <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * chore: make review mode switching idempotent * fix(discord): use partial mock for @buape/carbon in slash test Replace the full manual mock with importOriginal spread so new SDK exports are available automatically. Only ChannelType, MessageType, and Client are overridden — the rest come from the real module. Prevents CI breakage when @buape/carbon adds exports (e.g. the recent StringSelectMenu failure that blocked unrelated PRs). Closes #13244 * Changelog: add #13262 entry * onboard: support custom provider in non-interactive flow (#14223) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 5b98d6514e73f7ee934a350f3b38619c70f49aed Co-authored-by: ENCHIGO <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * fix(media): guard local media reads + accept all path types in MEDIA directive * Memory/QMD: treat plain-text no-results as empty * Memory/QMD: harden no-results parsing * fix(agents): exclude rate limit errors from context overflow classification (#13747) Co-authored-by: 0xRaini <[email protected]> * fix(ui): escape raw HTML in chat messages instead of rendering it (#13952) Co-authored-by: 0xRaini <[email protected]> * fix(agents): re-run tool_use pairing repair after history truncation (#13926) Co-authored-by: 0xRaini <[email protected]> * fix(agents): enable tool call ID sanitization for Anthropic provider (#13830) Co-authored-by: 0xRaini <[email protected]> * chore: Update deps. * chore: Cleanup useless CI job. * chore: Clean up pre-commit hook. * chore: Remove accidentally committed `.md` file. * Memory/QMD: add configurable search mode * Memory: make qmd search-mode flags compatible * fix(agents): scope process/exec tools to sessionKey for isolation (#4887) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 5d30672e756cc10a6cda90f5bc55cf4812b7d1d6 Co-authored-by: mcinteerj <[email protected]> Co-authored-by: Takhoffman <[email protected]> Reviewed-by: @Takhoffman * CI: add PR size autolabel workflow (#14410) * (fix): handle Cloudflare 521 and transient 5xx errors gracefully (#13500) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: a8347e95c55c6244bbf2e9066c8bf77bf62de6c9 Co-authored-by: rodrigouroz <[email protected]> Co-authored-by: Takhoffman <[email protected]> Reviewed-by: @Takhoffman * fix(cron): prevent duplicate fires when multiple jobs trigger simultaneously (#14256) The `computeNextRunAtMs` function used `nowSecondMs - 1` as the reference time for croner's `nextRun()`, which caused it to return the current second as a valid next-run time. When a job fired at e.g. 11:00:00.500, computing the next run still yielded 11:00:00.000 (same second, already elapsed), causing the scheduler to immediately re-fire the job in a tight loop (15-21x observed in the wild). Fix: use `nowSecondMs` directly (no `-1` lookback) and change the return guard from `>=` to `>` so next-run is always strictly after the current second. Fixes #14164 * fix(cron): re-arm timer when onTimer fires during active job execution (#14233) * fix(cron): re-arm timer when onTimer fires during active job execution When a cron job takes longer than MAX_TIMER_DELAY_MS (60s), the clamped timer fires while state.running is still true. The early return in onTimer() previously exited without re-arming the timer, leaving no setTimeout scheduled. This silently kills the cron scheduler until the next gateway restart. The fix calls armTimer(state) before the early return so the scheduler continues ticking even when a job is in progress. This is the likely root cause of recurring cron jobs silently skipping, as reported in #12025. One-shot (kind: 'at') jobs were unaffected because they typically complete within a single timer cycle. Includes a regression test that simulates a slow job exceeding the timer clamp period and verifies the next occurrence still fires. * fix: update tests for timer re-arm behavior - Update existing regression test to expect timer re-arm with non-zero delay instead of no timer at all - Simplify new test to directly verify state.timer is set after onTimer returns early due to running guard * fix: use fixed 60s delay for re-arm to prevent zero-delay hot-loop When the running guard re-arms the timer, use MAX_TIMER_DELAY_MS directly instead of calling armTimer() which can compute a zero delay for past-due jobs. This prevents a tight spin while still keeping the scheduler alive. * style: add curly braces to satisfy eslint(curly) rule * fix(cron): isolate schedule errors to prevent one bad job from breaking all jobs (#14385) Previously, if one cron job had a malformed schedule expression (e.g. invalid cron syntax), the error would propagate up and break the entire scheduler loop. This meant one misconfigured job could prevent ALL cron jobs from running. Changes: - Wrap per-job schedule computation in try/catch in recomputeNextRuns() - Track consecutive schedule errors via new scheduleErrorCount field - Log warnings for schedule errors with job ID and name - Auto-disable jobs after 3 consecutive schedule errors (with error-level log) - Clear error count when schedule computation succeeds - Continue processing other jobs even when one fails This ensures the scheduler is resilient to individual job misconfigurations while still providing visibility into problems through logging. Co-authored-by: Marvin <[email protected]> * fix(cron): pass agentId to runHeartbeatOnce for main-session jobs (#14140) * fix(cron): pass agentId to runHeartbeatOnce for main-session jobs Main-session cron jobs with agentId always ran the heartbeat under the default agent, ignoring the job's agent binding. enqueueSystemEvent correctly routed the system event to the bound agent's session, but runHeartbeatOnce was called without agentId, so the heartbeat ran under the default agent and never picked up the event. Thread agentId from job.agentId through the CronServiceDeps type, timer execution, and the gateway wrapper so heartbeat-runner uses the correct agent. Co-Authored-By: Claude Opus 4.6 <[email protected]> * cron: add heartbeat agentId propagation regression test (#14140) (thanks @ishikawa-pro) --------- Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: buffer upload path for feishu SDK (openclaw#10345) thanks @youngerstyle Co-authored-by: zhiyi <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: tighten feishu mention trigger matching (openclaw#11088) thanks @openperf Co-authored-by: 王春跃 <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: use resolved feishu account in status probe (openclaw#11233) thanks @onevcat Co-authored-by: Wei Wang <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: preserve top-level feishu doc block order (openclaw#13994) thanks @Cynosure159 Co-authored-by: Cynosure159 <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: remove workspace dev dependency in feishu plugin (openclaw#14423) thanks @jackcooper2015 Co-authored-by: jack-cooper <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * chore: refresh lockfile after feishu dep removal (openclaw#14423) thanks @jackcooper2015 Co-authored-by: jack-cooper <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * chore: add feishu contributor thanks to changelog (openclaw#14448) Co-authored-by: zhiyi <[email protected]> Co-authored-by: 王春跃 <[email protected]> Co-authored-by: Wei Wang <[email protected]> Co-authored-by: Cynosure159 <[email protected]> Co-authored-by: jack-cooper <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(whatsapp): convert Markdown bold/strikethrough to WhatsApp formatting (#14285) * fix(whatsapp): convert Markdown bold/strikethrough to WhatsApp formatting * refactor: Move `escapeRegExp` utility function to `utils.js`. --------- Co-authored-by: Luna AI <[email protected]> * fix: default MIME type for WhatsApp voice messages when Baileys omits it (#14444) * fix(whatsapp): allow media-only sends and normalize leading blank payloads (#14408) Co-authored-by: Tak Hoffman <[email protected]> * fix(cron): use requested agentId for isolated job auth resolution (#13983) Co-authored-by: Tak Hoffman <[email protected]> * fix(cron): prevent one-shot at jobs from re-firing on restart after skip/error (#13845) (#13878) Co-authored-by: Tak Hoffman <[email protected]> * fix: prevent cron jobs from skipping execution when nextRunAtMs advances (#14068) Co-authored-by: Tak Hoffman <[email protected]> * changelog: add cron and whatsapp fix entries with contributor thanks * fix(telegram): handle no-text message in model picker editMessageText (#14397) Co-authored-by: Tak Hoffman <[email protected]> * fix(slack): change default replyToMode from "off" to "all" (#14364) Co-authored-by: Tak Hoffman <[email protected]> * fix(tests): update thread ID handling in Slack message collection tests (#14108) Co-authored-by: Tak Hoffman <[email protected]> * changelog: add telegram and slack fix entries * fix(telegram): surface REACTION_INVALID as non-fatal warning (#14340) Co-authored-by: Tak Hoffman <[email protected]> * changelog: add telegram reaction warning fix entry * perf: use JSON.parse instead of JSON5.parse for sessions.json (~35x faster) (#14530) Co-authored-by: hyf0-agent <[email protected]> * fix: add types condition to plugin-sdk export for moduleResolution NodeNext (#14485) Co-authored-by: 0xRaini <[email protected]> * refactor(config): restore schema.ts to use schema.hints * fix(config): restore schema.ts schema helper types after hints refactor * feat(provider): Z.AI endpoints + model catalog (#13456) (thanks @tomsun28) (#13456) Co-authored-by: Tak Hoffman <[email protected]> * feat(telegram): render blockquotes as native <blockquote> tags (#14608) (#14626) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 4a967c51f560fea33694a980bda0d76be6385c71 Co-authored-by: lailoo <[email protected]> Co-authored-by: sebslight <[email protected]> Reviewed-by: @sebslight * fix: BlueBubbles webhook auth bypass via loopback proxy trust (#13787) * fix(an-08): apply security fix Generated by staged fix workflow. * fix(an-08): apply security fix Generated by staged fix workflow. * fix(an-08): stabilize bluebubbles auth fixture for security patch Restore the default test password in createMockAccount and add a fallback password query in createMockRequest when auth is omitted. This keeps the AN-08 loopback-auth regression tests strict while preserving existing monitor behavior tests that assume authenticated webhook fixtures. * fix(gateway): auto-generate token during `gateway install` to prevent launchd restart loop (#13813) When the gateway is installed as a macOS launch agent and no token is configured, the service enters an infinite restart loop because launchd does not inherit shell environment variables. Auto-generate a token during `gateway install` when auth mode is `token` and no token exists, matching the existing pattern in doctor.ts and configure.gateway.ts. The token is persisted to the config file and embedded in the plist EnvironmentVariables for belt-and-suspenders reliability. Relates-to: #5103, #2433, #1690, #7749 * fix(media): strip MEDIA: lines with local paths instead of leaking as text (#14399) When internal tools (e.g. TTS) emit MEDIA:/tmp/... with absolute paths, isValidMedia() correctly rejects them for security. However, the rejected MEDIA: line was kept as visible text in the output, leaking the path to the user. Now strip MEDIA: lines that look like local paths even when the path is invalid, so they never appear as user-visible text. Closes #14365 Co-authored-by: Echo Ito <[email protected]> * fix(gateway): handle async EPIPE on stdout/stderr during shutdown (#13414) * fix(gateway): handle async EPIPE on stdout/stderr during shutdown The console capture forward() wrapper catches synchronous EPIPE errors, but when the receiving pipe closes during shutdown Node emits the error asynchronously on the stream. Without a listener this becomes an uncaught exception that crashes the gateway, causing macOS launchd to permanently unload the service. Add error listeners on process.stdout and process.stderr inside enableConsoleCapture() that silently swallow EPIPE/EIO (matching the existing isEpipeError helper) and re-throw anything else. Closes #13367 * guard stream error listeners against repeated enableConsoleCapture() calls Use a separate streamErrorHandlersInstalled flag in loggingState so that test resets of consolePatched don't cause listener accumulation on process.stdout/stderr. * fix: prevent undefined token in gateway auth config (#13809) - Guard against undefined/empty token in buildGatewayAuthConfig - Automatically generate random token when token param is undefined, empty, or whitespace - Prevents JSON.stringify from writing literal string "undefined" to config - Add tests for undefined, empty, and whitespace token cases Fixes #13756 Co-authored-by: Klawd Asklee <[email protected]> * fix(voice-call): pass Twilio stream auth token via <Parameter> instead of query string (#14029) Twilio strips query parameters from WebSocket URLs in <Stream> TwiML, so the auth token set via ?token=xxx never arrives on the WebSocket connection. This causes stream rejection when token validation is enabled. Fix: pass the token as a <Parameter> element inside <Stream>, which Twilio delivers in the start message's customParameters field. The media stream handler now extracts the token from customParameters, falling back to query string for backwards compatibility. Co-authored-by: McWiggles <[email protected]> * fix: exclude maxTokens from config redaction + honor deleteAfterRun on skipped cron jobs (#13342) * fix: exclude maxTokens and token-count fields from config redaction The /token/i regex in SENSITIVE_KEY_PATTERNS falsely matched fields like maxTokens, maxOutputTokens, maxCompletionTokens etc. These are numeric config fields for token counts, not sensitive credentials. Added a whitelist (SENSITIVE_KEY_WHITELIST) that explicitly excludes known token-count field names from redaction. This prevents config corruption when maxTokens gets replaced with __OPENCLAW_REDACTED__ during config round-trips. Fixes #13236 * fix: honor deleteAfterRun for one-shot 'at' jobs with 'skipped' status Previously, deleteAfterRun only triggered when result.status was 'ok'. For one-shot 'at' jobs, a 'skipped' status (e.g. empty heartbeat file) would leave the job in state but disabled, never getting cleaned up. Now deleteAfterRun also triggers on 'skipped' status for 'at' jobs, since a skipped one-shot job has no meaningful retry path. Fixes #13249 * Cron: format timer.ts --------- Co-authored-by: nice03 <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(gateway): drain active turns before restart to prevent message loss (#13931) * fix(gateway): drain active turns before restart to prevent message loss On SIGUSR1 restart, the gateway now waits up to 30s for in-flight agent turns to complete before tearing down the server. This prevents buffered messages from being dropped when config.patch or update triggers a restart while agents are mid-turn. Changes: - command-queue.ts: add getActiveTaskCount() and waitForActiveTasks() helpers to track and wait on active lane tasks - run-loop.ts: on restart signal, drain active tasks before server.close() with a 30s timeout; extend force-exit timer accordingly - command-queue.test.ts: update imports for new exports Fixes #13883 * fix(queue): snapshot active tasks for restart drain --------- Co-authored-by: Elonito <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix: Unauthenticated Nostr profile API allows remote config tampering (#13719) * fix(an-07): apply security fix Generated by staged fix workflow. * fix(an-07): apply security fix Generated by staged fix workflow. * fix(an-07): satisfy lint in plugin auth regression test Replace unsafe unknown-to-string coercion in the gateway plugin auth test helper with explicit string/null/JSON handling so pnpm check passes. * fix: ignore meta field changes in config file watcher (#13460) Prevents infinite restart loop when gateway updates meta.lastTouchedAt and meta.lastTouchedVersion on startup. Fixes #13458 * fix(daemon): suppress EPIPE error in restartLaunchAgent stdout write (#14343) After a successful launchctl kickstart, the stdout.write() for the status message may fail with EPIPE if the receiving end has already closed. Catch and ignore EPIPE specifically; re-throw other errors. Closes #14234 Co-authored-by: Echo Ito <[email protected]> * fix: prevent double compaction caused by cache-ttl entry bypassing guard (#13514) Move appendCacheTtlTimestamp() to after prompt + compaction retry completes instead of before. The previous placement inserted a custom entry (openclaw.cache-ttl) between compaction and the next prompt, which broke pi-coding-agent's prepareCompaction() guard — the guard only checks if the last entry is type 'compaction', and the cache-ttl custom entry made it type 'custom', allowing an immediate second compaction at very low token counts (e.g. 5,545 tokens) that nuked all preserved context. Fixes #9282 Relates to #12170 * feat: support .agents/skills/ directory for cross-agent skill discovery (#9966) Adds loading from two .agents/skills/ locations: - ~/.agents/skills/ (personal/user-level, source "agents-skills-personal") - {workspace}/.agents/skills/ (project-level, source "agents-skills-project") Precedence: extra < bundled < managed < personal .agents/skills < project .agents/skills < workspace. Closes #8822 * fix(antigravity): opus 4.6 forward-compat model + thinking signature sanitization bypass (#14218) Two fixes for Google Antigravity (Cloud Code Assist) reliability: 1. Forward-compat model fallback: pi-ai's model registry doesn't include claude-opus-4-6-thinking. Add resolveAntigravityOpus46ForwardCompatModel() that clones the opus-4-5 template so the correct api ("google-gemini-cli") and baseUrl are preserved. Fixes #13765. 2. Fix thinking.signature rejection: The API returns Claude thinking blocks without signatures, then rejects them on replay. The existing sanitizer strips unsigned blocks, but the orphaned-user-message path in attempt.ts bypassed it by reading directly from disk. Now applies sanitizeAntigravityThinkingBlocks at that code path. Co-authored-by: Claude Opus 4.6 <[email protected]> * Fix: Prevent file descriptor leaks in child process cleanup (#13565) * fix: prevent FD leaks in child process cleanup - Destroy stdio streams (stdin/stdout/stderr) after process exit - Remove event listeners to prevent memory leaks - Clean up child process reference in moveToFinished() - Also fixes model override handling in agent.ts Fixes EBADF errors caused by accumulating file descriptors from sub-agent spawns. * Fix: allow stdin destroy in process registry cleanup --------- Co-authored-by: Tak Hoffman <[email protected]> * fix: use last API call's cache tokens for context-size display (#13698) (#13805) The UsageAccumulator sums cacheRead/cacheWrite across all API calls within a single turn. With Anthropic prompt caching, each call reports cacheRead ≈ current_context_size, so after N tool-call round-trips the accumulated total becomes N × actual_context, which gets clamped to contextWindow (200k) by deriveSessionTotalTokens(). Fix: track the most recent API call's cache fields separately and use them in toNormalizedUsage() for context-size reporting. This makes /status Context display accurate while preserving accumulated output token counts. Fixes #13698 Fixes #13782 Co-authored-by: akari-musubi <[email protected]> * changelog: add missing fix entries * fix(agents): narrow billing error 402 regex to avoid false positives on issue IDs (#13827) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: b0501bbab7b3ec3ed56eb8903d9a27f8273f0edb Co-authored-by: 0xRaini <[email protected]> Co-authored-by: sebslight <[email protected]> Reviewed-by: @sebslight * fix(runtime): guard cleanup and preserve skipped cron jobs * AGENTS.md: make PR_WORKFLOW optional (don’t override maintainer workflows) * fix(telegram): add retry logic to health probe (openclaw#7405) thanks @mcinteerj Verified: - CI=true pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: mcinteerj <[email protected]> * fix: fix(boot): use ephemeral session per boot to prevent stale context (openclaw#11764) thanks @mcinteerj Verified: - pnpm build - pnpm check - pnpm test Co-authored-by: mcinteerj <[email protected]> * fix(tts): strip markdown before sending text to TTS engines (#13237) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 163c68539f672eaa81cca9388573a12b39eb1b58 Co-authored-by: danielwanwx <[email protected]> Co-authored-by: sebslight <[email protected]> Reviewed-by: @sebslight * fix: fix: transcribe audio before mention check in groups with requireMention (openclaw#9973) thanks @mcinteerj Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: mcinteerj <[email protected]> * fix(gateway): increase WebSocket max payload to 5 MB for image uploads (#14486) * fix(gateway): increase WebSocket max payload to 5 MB for image uploads The 512 KB limit was too small for base64-encoded images — a 400 KB image becomes ~532 KB after encoding, exceeding the limit and closing the connection with code 1006. Bump MAX_PAYLOAD_BYTES to 5 MB and MAX_BUFFERED_BYTES to 8 MB to support standard image uploads via webchat. Closes #14400 * fix: align gateway WS limits with 5MB image uploads (#14486) (thanks @0xRaini) * docs: fix changelog conflict for #14486 --------- Co-authored-by: 0xRaini <[email protected]> Co-authored-by: Peter Steinberger <[email protected]> * perf(test): speed up vitest by skipping plugins + LLM slug * perf(test): add vitest slowest report artifact * refactor(test): consolidate infra unit tests * test(agents): make grok api key test hermetic * chore: bump version to 2026.2.12 * fix(cli): guard against read-only process.noDeprecation on Node.js v23+ (#14152) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 11bb9f141ae01d85c7eb8d4f8b526d7bda419558 Co-authored-by: 0xRaini <[email protected]> Co-authored-by: steipete <[email protected]> Reviewed-by: @steipete * fix: remove bundled soul-evil hook (closes #8776) (#14757) * fix: remove bundled soul-evil hook (closes #8776) * fix: remove soul-evil docs (#14757) (thanks @Imccccc) --------- Co-authored-by: OpenClaw Bot <[email protected]> Co-authored-by: Peter Steinberger <[email protected]> * fix(security): add --ignore-scripts to skills install commands (#14659) Skills install runs package manager install commands (npm, pnpm, yarn, bun) without --ignore-scripts, allowing malicious npm packages to execute arbitrary code via postinstall/preinstall lifecycle scripts during global installation. This is inconsistent with the security fix in commit 92702af7a which added --ignore-scripts to both plugin installs (src/plugins/install.ts) and hook installs (src/hooks/install.ts). Skills install was overlooked in that change. Global install (-g) is particularly dangerous as scripts execute with the user's full permissions and can modify globally-accessible binaries. * perf(test): speed up test runs and harden temp cleanup * fix(feishu): use msg_type 'media' for video/audio messages (#14648) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: e8044cb2085cc77ac2b9e819a09dc7e1c21bc8da Co-authored-by: 0xRaini <[email protected]> Co-authored-by: steipete <[email protected]> Reviewed-by: @steipete * fix: use local timezone in console log timestamps formatConsoleTimestamp previously used Date.toISOString() which always returns UTC time (suffixed with Z). This confused users whose local timezone differs from UTC. Now uses local time methods (getHours, getMinutes, etc.) and appends the local UTC offset (e.g. +08:00) instead of Z. The pretty style returns local HH:MM:SS. The hasTimestampPrefix regex is updated to accept both Z and +/-HH:MM offset suffixes. Closes #14699 * fix: local-time timestamps include offset (#14771) (thanks @0xRaini) * feat(zai): auto-detect endpoint + default glm-5 (#14786) * feat(zai): auto-detect endpoint + default glm-5 * test: fix Z.AI default endpoint expectation (#14786) * test: bump embedded runner beforeAll timeout * chore: update changelog for Z.AI GLM-5 autodetect (#14786) * chore: resolve changelog merge conflict with main (#14786) * chore: append changelog note for #14786 without merge conflict * chore: sync changelog with main to resolve merge conflict * fix(providers): include provider name in billing error messages (#14697) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 774e0b660514d59fea48bda0e300e94b398f58e8 Co-authored-by: fagemx <[email protected]> Co-authored-by: shakkernerd <[email protected]> Reviewed-by: @shakkernerd * fix: resolve symlinked argv1 for Control UI asset detection (#14919) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 07b85041dc70b5839247dc661f123ff37b745c1c Co-authored-by: gumadeiras <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * docs(changelog): add Control UI symlink install fix entry Co-authored-by: aynorica <[email protected]> * chore: refining review PR additional prompts * chore(pr-skills): suppress output for successful commands (pnpm install/build/test/etc) to lower context usage * chore: move local imports to the top * fix(agents): guard against undefined path in context file entries (#14903) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 25856b863d62eda20720db53fea43cbf213b5cc5 Co-authored-by: 0xRaini <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * CI: add contributor tier labels * fix: prevent heartbeat scheduler death when runOnce throws (#14901) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 022efbfef959f4c4225d7ab1a49540c8f39accd3 Co-authored-by: joeykrug <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * CI: add labeler backfill dispatch * CI: handle search 422 in labeler * fix: use os.tmpdir fallback paths for temp files (#14985) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 347c689407037a05be0717209660076c6a07d0ec Co-authored-by: gumadeiras <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * Scripts: add issue labeler state + PR support * CI: close PRs with excessive labels * CI: gate auto-response with trigger label * Browser/Logging: share default openclaw tmp dir resolver * feat(minimax): update models from M2.1 to M2.5 (#14865) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 1d58bc5760af657e205f7a113cec30aaf461abc6 Co-authored-by: adao-max <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * chore(deps): update dependencies * fix(irc): type socket error param * Tests: make download temp-path assertion cross-platform * chore: fix windows CI tests * fix: respect session model override in agent runtime (#14783) (#14983) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: ec47d1a7bf4e97a5db77281567318c1565d319b5 Co-authored-by: shtse8 <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * Discord: handle thread edit params * fix(discord): add TTL and LRU eviction to thread starter cache Fixes #5260 The DISCORD_THREAD_STARTER_CACHE Map was growing unbounded during long-running gateway sessions, causing memory exhaustion. This fix adds: - 5-minute TTL expiry (thread starters rarely change) - Max 500 entries with LRU eviction - Same caching pattern used by Slack's thread resolver The implementation mirrors src/slack/monitor/thread-resolution.ts which already handles this correctly. * fix: use iterator.done check for LRU eviction Fixes edge case where empty string key would stop eviction early * fix(signal): replace  with @uuid/@phone from mentions Related #1926 Signal mentions were appearing as  (object replacement character) instead of readable identifiers. This caused Clawdbot to misinterpret messages and respond inappropriately. Now parses dataMessage.mentions array and replaces the placeholder character with @{uuid} or @{phone} from the mention metadata. * Signal: normalize mention placeholders * Signal: satisfy lint * fix: normalize Signal mentions (#2013) (thanks @alexgleason) * Discord: preserve media caption whitespace * fix: document Discord media-only messages (#9507) (thanks @leszekszpunar) * fix: add Discord channel-edit thread params (#5542) (thanks @stumct) * fix: process Discord DM reactions instead of silently dropping them * fix: use proper LoadedConfig type in test mock * fix: use canonical 'direct' instead of 'dm' for DM peer kind (fixes TS2322) * fix: handle discord dm reaction allowlist * Changelog: note discord dm reaction fix * fix: update totalTokens after compaction using last-call usage (#15018) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 9214291bf7e9e62ba8661aa46b4739113794056a Co-authored-by: shtse8 <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * chore: make changelog mandatory in PR skills * Signal: validate account input * Changelog: credit Signal account validation * Signal: harden E.164 validation * fix(security): harden untrusted web tool transcripts * fix(agents): stabilize overflow compaction retries and session context accounting (openclaw#14102) thanks @vpesh Verified: - CI checks for commit 86a7ecb45ebf0be61dce9261398000524fd9fab6 - Rebase conflict resolution for compatibility with latest main Co-authored-by: vpesh <[email protected]> * fix: wire 9 unwired plugin hooks to core code (openclaw#14882) thanks @shtse8 Verified: - GitHub CI checks green (non-skipped) Co-authored-by: shtse8 <[email protected]> * fix: prevent ghost reminder notifications (#13317) The heartbeat runner was incorrectly triggering CRON_EVENT_PROMPT whenever ANY system events existed during a cron heartbeat, even if those events were unrelated (e.g., HEARTBEAT_OK acks, exec completions). This caused phantom 'scheduled reminder' notifications with no actual reminder content. Fix: Only treat as cron event if pending events contain actual cron-related messages, excluding standard heartbeat acks and exec completion messages. Fixes #13317 * test: add test for ghost reminder bug (#13317) * test: fix test isolation and assertion issues - Add resetSystemEventsForTest() in beforeEach/afterEach - Fix hardcoded status assertions (use toBeDefined + conditional checks) - Prevents cross-test pollution of global system event queue Addresses Greptile feedback on PR #15059 * feat: embed actual event text in cron prompt Combines two complementary fixes for ghost reminder bug: 1. Filter HEARTBEAT_OK/exec messages (previous commit) 2. Embed actual event content in prompt (this commit) Instead of static 'shown above' message, dynamically build prompt with actual reminder text. Ensures model sees event content directly. Credit: Approach inspired by @nyx-rymera's analysis in #13317 Fixes #13317 * fix: refine cron heartbeat event detection * changelog: keep signal entry while restoring removed rows * changelog: dedupe signal entry restored by merge conflict fix * fix: align cron prompt content with filtered reminder events * fix(security): harden hook and device token auth * fix: confine sandbox skill sync destinations * fix: harden session transcript path resolution * fix: harden OpenResponses URL input fetching * chore: Update deps. * fix(memory-flush): instruct agents to append rather than overwrite memory files (openclaw#6878) thanks @EmberCF Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test (fails on unrelated existing telegram test file) Co-authored-by: EmberCF <[email protected]> * fix: dispatch before_tool_call and after_tool_call hooks from both tool execution paths (openclaw#15012) thanks @Patrick-Barletta Verified: - pnpm check Co-authored-by: Patrick-Barletta <[email protected]> * fix(discord): respect replyToMode in thread channel * fix(discord): replyToMode first behaviour * fix: update replyToMode notes (#11062) (thanks @cordx56) * Changelog: add missing entries for #14882 and #15012 * fix(media): strip audio attachments after successful transcription (openclaw#9076) thanks @nobrainer-tech Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test (fails in known unrelated telegram suite) - pnpm vitest run src/auto-reply/media-note.test.ts src/auto-reply/reply.media-note.test.ts Co-authored-by: nobrainer-tech <[email protected]> * fix: preserve inter-session input provenance (thanks @anbecker) * fix(browser): require auth on control HTTP and auto-bootstrap token * docs: add Windows installer debug equivalents * fix: harden hook session key routing defaults * test: stabilize telegram media timing tests * fix: remove accidental root package-lock.json (#15102) * fix: include plugin sdk dts tsconfig in onboard docker image * fix: emit message_sent hook for all successful outbound paths (#15104) * fix: add adapter-path after_tool_call coverage (follow-up to #15012) (#15105) * fix(ci): resolve windows test path assertion and sync protocol swift models * Discord: implement role allowlist with OR logic in preflight * Discord: implement role-based agent routing in resolveAgentRoute * Discord: pass member role IDs to agent route resolution * Discord: add unit tests for role-based agent routing * fix: add curly braces to resolve-route.ts for eslint(curly) compliance * fix: use member.roles as string[] per Discord API types * fix: add missing role-based type definitions for RBAC routing * fix: exclude role-restricted bindings from guild-only matching * fix: add discord role allowlists (#10650) (thanks @Minidoracat) * Discord: honor Administrator in permission checks * Changelog: note Discord admin permission fix * CLI: add plugins uninstall command (#5985) (openclaw#6141) thanks @JustasMonkev Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: JustasMonkev <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(browser): hide navigator.webdriver from reCAPTCHA v3 detection (openclaw#10735) thanks @Milofax Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: Milofax <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * feat: expose /compact command in Telegram native menu (openclaw#10352) thanks @akramcodez Verified: - pnpm build - pnpm check - pnpm test Co-authored-by: akramcodez <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * chore: update appcast for 2026.2.12 * feat(feishu): add streaming card support via Card Kit API (openclaw#10379) thanks @xzq-xu Verified: - pnpm build - pnpm check - pnpm test Co-authored-by: xzq-xu <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(onboarding): exit cleanly after web ui hatch * fix(session): preserve verbose/thinking/tts overrides across /new and /reset (openclaw#10881) thanks @mcaxtr Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: mcaxtr <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(macos): prevent Voice Wake crash on CJK trigger transcripts (openclaw#11052) thanks @Flash-LHR Verified: - pnpm build - pnpm check - pnpm test Co-authored-by: Flash-LHR <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(update): repair daemon-cli compat exports after self-update * chore(release): bump version to 2026.2.13 * fix(security): prevent String(undefined) coercion in credential inputs (#12287) * fix(security): prevent String(undefined) coercion in credential inputs When a prompter returns undefined (due to cancel, timeout, or bug), String(undefined).trim() produces the literal string "undefined" instead of "". This truthy string prevents secure fallbacks from triggering, allowing predictable credential values (e.g., gateway password = "undefined"). Fix all 8 occurrences by using String(value ?? "").trim(), which correctly yields "" for null/undefined inputs and triggers downstream validation or fallback logic. Fixes #8054 * fix(security): also fix String(undefined) in api-provider credential inputs Address codex review feedback: 4 additional occurrences of the unsafe String(variable).trim() pattern in auth-choice.apply.api-providers.ts (Cloudflare Account ID, Gateway ID, synthetic API key inputs + validators). * fix(test): strengthen password coercion test per review feedback * fix(security): harden credential prompt coercion --------- Co-authored-by: Peter Steinberger <[email protected]> * fix: prevent heartbeat scheduler silent death from wake handler race (#15108) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: fd7165b93547251c48904fa60b4b608d96bfb65c Co-authored-by: joeykrug <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * fix(sandbox): pass docker.env into sandbox container * fix: pass sandbox docker env into containers (#15138) (thanks @stevebot-alive) * fix(cli): use raw config instead of runtime-merged config in config set/unset Fixes #6070 The config set/unset commands were using snapshot.config (which contains runtime-merged defaults) instead of snapshot.parsed (the raw user config). This caused runtime defaults like agents.defaults to leak into the written config file when any value was set or unset. Changed both set and unset commands to use structuredClone(snapshot.parsed) to preserve only user-specified config values. * fix(config): add resolved field to ConfigFileSnapshot for pre-defaults config The initial fix using snapshot.parsed broke configs with $include directives. This commit adds a new 'resolved' field to ConfigFileSnapshot that contains the config after $include and ${ENV} substitution but BEFORE runtime defaults are applied. This is now used by config set/unset to avoid: 1. Breaking configs with $include directives 2. Leaking runtime defaults into the written config file Also removes applyModelDefaults from writeConfigFile since runtime defaults should only be applied when loading, not when writing. * fix(config): redact resolved field in config snapshots The newly added 'resolved' field contains secrets after ${ENV} substitution. This commit ensures redactConfigSnapshot also redacts the resolved field to prevent credential leaks in config.get responses. * fix(config): enforce default-free persistence in write path * fix(exec): allow heredoc operator (<<) in allowlist security mode (#13811) * fix(exec): allow heredoc operator (<<) in allowlist security mode * fix: allow multiline heredoc parsing in exec approvals (#13811) (thanks @mcaxtr) --------- Co-authored-by: Peter Steinberger <[email protected]> * fix(security): distinguish webhooks from internal hooks in audit summary (#13474) * fix(security): distinguish webhooks from internal hooks in audit summary The attack surface summary reported a single 'hooks: disabled/enabled' line that only checked the external webhook endpoint (hooks.enabled), ignoring internal hooks (hooks.internal.enabled). Users who enabled internal hooks (session-memory, command-logger, etc.) saw 'hooks: disabled' and thought something was broken. Split into two separate lines: - hooks.webhooks: disabled/enabled - hooks.internal: disabled/enabled Fixes #13466 * test(security): move attack surface tests to focused test file Move the 3 new hook-distinction tests from the monolithic audit.test.ts (1,511 lines) into a dedicated audit-extra.sync.test.ts that tests collectAttackSurfaceSummaryFindings directly. Avoids growing the already-large test file and keeps tests focused on the changed unit. * fix: add changelog entry for security audit hook split (#13474) (thanks @mcaxtr) --------- Co-authored-by: Peter Steinberger <[email protected]> * fix(docs): remove hardcoded Mermaid init blocks that break dark mode (#15157) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 3239baaf150f451328d86a0e054ab4a8de264e30 Co-authored-by: heytulsiprasad <[email protected]> Co-authored-by: sebslight <[email protected]> Reviewed-by: @sebslight * fix: thread replyToId and threadId through message tool send action (#14948) * fix: thread replyToId and threadId through message tool send action * fix: omit replyToId/threadId from gateway send params * fix: add threading seam regression coverage (#14948) (thanks @mcaxtr) --------- Co-authored-by: Peter Steinberger <[email protected]> * fix: replace file-based session store lock with in-process Promise chain mutex (#14498) * fix: replace file-based session store lock with in-process Promise chain mutex Node.js is single-threaded, so file-based locking (open('wx') + polling + stale eviction) is unnecessary and causes timeouts under heavy session load. Replace with a simple per-storePath Promise chain that serializes access without any filesystem overhead. In a 1159-session environment over 3 hours: - Lock timeouts: 25 - Stuck sessions: 157 (max 1031s, avg 388s) - Slow listeners: 39 (max 265s, avg 70s) Root cause: during sessions.json file I/O, await yields control and other lock requests hit the 10s timeout waiting for the .lock file to be released. * test: add comprehensive tests for Promise chain mutex lock - Concurrent access serialization (10 parallel writers, counter integrity) - Error resilience (single & multiple consecutive throws don't poison queue) - Independent storePath parallelism (different paths run concurrently) - LOCK_QUEUES cleanup after completion and after errors - No .lock file created on disk Also fix: store caught promise in LOCK_QUEUES to avoid unhandled rejection warnings when queued fn() throws. * fix: add timeout to Promise chain mutex to prevent infinite hangs on Windows * fix(session-store): enforce strict queue timeout + cross-process lock --------- Co-authored-by: Peter Steinberger <[email protected]> * feat(ui): add RTL support for Hebrew/Arabic text in webchat (openclaw#11498) thanks @dirbalak Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: dirbalak <[email protected]> Co-authored-by: Tak Hoffman <[email protected]> * fix(sandbox): force network bridge for browser container (#6961) * feat(slack): include thread metadata (thread_ts, parent_user_id) in agent context Adds thread_ts and parent_user_id to the Slack message footer for thread replies, giving agents awareness of thread context. Top-level messages remain unchanged. Includes tests verifying: - Thread replies include thread_ts and parent_user_id in footer - Top-level messages exclude thread metadata * fix: align slack thread footer metadata with reply semantics (#14625) (thanks @bennewton999) * fix(outbound): return error instead of silently redirecting to allowList[0] (#13578) * fix(reply): auto-inject replyToCurrent for reply threading replyToMode "first"/"all" only filters replyToId but never generates it — that required the LLM to emit [[reply_to_current]] tags. Inject replyToCurrent:true on all payloads so applyReplyTagsToPayload sets replyToId=currentMessageId, then let the existing mode filter decide which replies keep threading (first only, all, or off). Covers both final reply path (reply-payloads.ts) and block streaming path (agent-runner-execution.ts). * fix: preserve off-mode semantics in auto reply threading (#14976) (thanks @Diaspar4u) * Auto-reply: fix non-default agent session transcript path resolution (#15154) * Auto-reply: fix non-default agent transcript path resolution * Auto-reply: harden non-default agent transcript lookups * Auto-reply: harden session path resolution across agent stores * test: speed up test suite and trim redundant onboarding tests * fix: stabilize test runner and daemon-cli compat * fix(aa-01): apply security fix Generated by staged fix workflow. * fix: enforce feishu dm policy + pairing flow (#14876) (thanks @coygeek) * fix(slack): populate thread session with existing thread history (#7610) * feat(slack): populate thread session with existing thread history When a new session is created for a Slack thread, fetch and inject the full thread history as context. This preserves conversation continuity so the bot knows what it previously said in the thread. - Add resolveSlackThreadHistory() to fetch all thread messages - Add ThreadHistoryBody to context payload - Use thread history instead of just thread starter for new sessions Fixes #4470 * chore: remove redundant comments * fix: use threadContextNote in queue body * fix(slack): address Greptile review feedback - P0: Use thread session key (not base session key) for new-session check This ensures thread history is injected when the thread session is new, even if the base channel session already exists. - P1: Fetch up to 200 messages and take the most recent N Slack API returns messages in chronological order (oldest first). Previously we took the first N, now we take the last N for relevant context. - P1: Batch resolve user names with Promise.all Avoid N sequential API calls when resolving user names in thread history. - P2: Include file-only messages in thread history Messages with attachments but no text are now included with a placeholder like '[attached: image.png, document.pdf]'. - P2: Add documentation about intentional 200-message fetch limit Clarifies that we intentionally don't paginate; 200 covers most threads. * style: add braces for curly lint rule * feat(slack): add thread.initialHistoryLimit config option Allow users to configure the maximum number of thread messages to fetch when starting a new thread session. Defaults to 20. Set to 0 to disable thread history fetching entirely. This addresses the optional configuration request from #2608. * chore: trigger CI * fix(slack): ensure isNewSession=true on first thread turn recordInboundSession() in prepare.ts creates the thread session entry before session.ts reads the store, causing isNewSession to be false on the very first user message in a thread. This prevented thread context (history/starter) from being injected. Add IsFirstThreadTurn flag to message context, set when readSessionUpdatedAt() returns undefined for the thread session key. session.ts uses this flag to force isNewSession=true. * style: format prepare.ts for oxfmt * fix: suppress InboundHistory/ThreadStarterBody when ThreadHistoryBody present (#13912) When ThreadHistoryBody is fetched from the Slack API (conversations.replies), it already contains pending messages and the thread starter. Passing both InboundHistory and ThreadStarterBody alongside ThreadHistoryBody caused duplicate content in the LLM context on new thread sessions. Suppress InboundHistory and ThreadStarterBody when ThreadHistoryBody is present, since it is a strict superset of both. * remove verbose comment * fix(slack): paginate thread history context fetch * fix(slack): wire session file path options after main merge --------- Co-authored-by: Peter Steinberger <[email protected]> * fix: /status shows incorrect context percentage — totalTokens clamped to contextTokens (#15114) (#15133) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: a489669fc7e86db03484ef5a0ae222d9360e72f7 Co-authored-by: echoVic <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras * fix(ci): sync extension versions to root release (#15199) * test: stabilize local-timestamp assertion in session resets * fix: update systemd unit version on gateway restart When restarting the gateway via restartSystemdService(), the systemd unit file's Description and OPENCLAW_SERVICE_VERSION are now checked against the running version. If stale, they are patched and daemon-reload is run before restarting. Previously, only `openclaw gateway install` wrote the version to the unit file. After upgrading (git pull + rebuild, or pnpm update), a restart would leave the old version baked into the service description and environment. Fixes #16012 AI-assisted: written with Claude (OpenClaw agent), fully understood and reviewed. * test(memory): add failing engram backend config and manager contract specs * feat(memory): wire native engram backend with builtin fallback * ci: add GitHub Actions CI workflow (#3) --------- Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: ryan-crabbe <[email protected]> Co-authored-by: Rain <[email protected]> Co-authored-by: Sk Akram <[email protected]> Co-authored-by: Peter Lee <[email protected]> Co-authored-by: xialonglee <[email protected]> Co-authored-by: Sebastian <[email protected]> Co-authored-by: constansino <[email protected]> Co-authored-by: Kyle Tse <[email protected]> Co-authored-by: shtse8 <[email protected]> Co-authored-by: J young Lee <[email protected]> Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Co-authored-by: Shadow <[email protected]> Co-authored-by: Rain <[email protected]> Co-authored-by: 0xRain <[email protected]> Co-authored-by: 0xRaini <[email protected]> Co-authored-by: gumadeiras <[email protected]> Co-authored-by: Dario Zhang <[email protected]> Co-authored-by: Claude Code <[email protected]> Co-authored-by: ENCHIGO <[email protected]> Co-authored-by: buddyh <[email protected]> Co-authored-by: Vignesh Natarajan <[email protected]> Co-authored-by: 0xRaini <[email protected]> Co-authored-by: 0xRaini <[email protected]> Co-authored-by: cpojer <[email protected]> Co-authored-by: Jake <[email protected]> Co-authored-by: mcinteerj <[email protected]> Co-authored-by: Takhoffman <[email protected]> Co-authored-by: Rodrigo Uroz <[email protected]> Co-authored-by: rodrigouroz <[email protected]> Co-authored-by: Xinhua Gu <[email protected]> Co-authored-by: Tom Ron <[email protected]> Co-authored-by: MarvinDontPanic <[email protected]> Co-authored-by: Marvin <[email protected]> Co-authored-by: 石川 諒 <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: zhiyi <[email protected]> Co-authored-by: 王春跃 <[email protected]> Co-authored-by: Wei Wang <[email protected]> Co-authored-by: Cynosure159 <[email protected]> Co-authored-by: jack-cooper <[email protected]> Co-authored-by: Ajay Rajnikanth <[email protected]> Co-authored-by: Luna AI <[email protected]> Co-authored-by: Marcus Castro <[email protected]> Co-authored-by: Karim Naguib <[email protected]> Co-authored-by: 大猫子 <[email protected]> Co-authored-by: WalterSumbon <[email protected]> Co-authored-by: NM <[email protected]> Co-authored-by: J. Brandon Johnson <[email protected]> Co-authored-by: hyf0-agent <[email protected]> Co-authored-by: hyf0-agent <[email protected]> Co-authored-by: Tomsun28 <[email protected]> Co-authored-by: lailoo <[email protected]> Co-authored-by: Coy Geek <[email protected]> Co-authored-by: Cathryn Lavery <[email protected]> Co-authored-by: Echo Ito <[email protected]> Co-authored-by: Keshav Rao <[email protected]> Co-authored-by: asklee-klawd <[email protected]> Co-authored-by: Klawd Asklee <[email protected]> Co-authored-by: mcwigglesmcgee <[email protected]> Co-authored-by: McWiggles <[email protected]> Co-authored-by: niceysam <[email protected]> Co-authored-by: nice03 <[email protected]> Co-authored-by: brandonwise <[email protected]> Co-authored-by: taw0002 <[email protected]> Co-authored-by: Taras Lukavyi <[email protected]> Co-authored-by: jg-noncelogic <[email protected]> Co-authored-by: Kyle Chen <[email protected]> Co-authored-by: Akari <[email protected]> Co-authored-by: akari-musubi <[email protected]> Co-authored-by: danielwanwx <[email protected]> Co-authored-by: steipete <[email protected]> Co-authored-by: Tyler <[email protected]> Co-authored-by: OpenClaw Bot <[email protected]> Co-authored-by: Yi Liu <[email protected]> Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: fagemx <[email protected]> Co-authored-by: shakkernerd <[email protected]> Co-authored-by: gumadeiras <[email protected]> Co-authored-by: aynorica <[email protected]> Co-authored-by: Gustavo Madeira Santana <[email protected]> Co-authored-by: Joseph Krug <[email protected]> Co-authored-by: joeykrug <[email protected]> Co-authored-by: Skyler Miao <[email protected]> Co-authored-by: Web Vijayi <[email protected]> Co-authored-by: Alex Gleason <[email protected]> Co-authored-by: Vladimir Peshekhonov <[email protected]> Co-authored-by: vpesh <[email protected]…
cloud-neutral
pushed a commit
to cloud-neutral-toolkit/openclawbot.svc.plus
that referenced
this pull request
Feb 15, 2026
…openclaw#14142) Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2. Prepared head SHA: cb0b4f6 Co-authored-by: beefiker <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
jiulingyun
added a commit
to jiulingyun/openclaw-cn
that referenced
this pull request
Feb 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related
#9971 did not resolve this issue for me.
Summary
Slack messages like
@Labrador /newarrive as regular messages with the mention as<@U123> /new. Control-command detection was done on the raw text, so<@U123> /newwas never matched as/new. This fix strips Slack mentions before detection so@Bot /newis recognized.Repro Steps
@Labrador /newor/newruns.Root Cause
hasControlCommandwas called with rawmessage.text(e.g.<@U123> /new).normalizeCommandBodyrequires text to start with/, so it returned the raw string unchanged. No command alias matched<@u123> /new, so detection failed.Behavior Changes
@Bot /new→ not detected as control command → goes to model.@Bot /new→ detected as control command → processed as/new(subject to authorization).Tests
prepare.sender-prefix.test.ts: New test for<@BOT> /new→CommandAuthorized: true.prepare.inbound-contract.test.ts: All pass.command-control.test.ts: All pass.session-resets.test.ts: All pass.Manual Testing (omit if N/A)
Prerequisites
channels.slack.dm.allowFromor channelusersallowlist (ifcommands.useAccessGroups: true).Steps
@Bot /newin a channel.@Bot /help— should show help.hello @Bot /new— should not be treated as command (unchanged).Evidence (omit if N/A)
Sign-Off
Greptile Overview
Greptile Summary
This PR fixes control command detection when Slack messages start with bot mentions. The core change strips Slack mention tags (
<@U123>) before command detection so messages like@Labrador /neware correctly recognized as the/newcommand rather than being passed to the model as normal chat.The implementation:
<@[^>]+>with spaces before command detectionhasControlCommand()for matching against command aliasesThe test coverage validates the fix:
<@BOT> /newnow correctly setsCommandAuthorized: true.Confidence Score: 5/5
(2/5) Greptile learns from your feedback when you react with thumbs up/down!