claw-lark Patches
v1.0.0Re-apply custom patches to claw-lark plugin dist files after updates. Use when claw-lark plugin is updated/reinstalled and custom behaviors (requireMention f...
Like a lobster shell, security has layers — review code before you run it.
claw-lark Patches
claw-lark is a compiled plugin — we patch dist files directly. Every plugin update wipes these patches. This skill documents exactly what to change and provides an auto-apply script.
Quick Apply
bash scripts/apply-patches.sh
Then restart gateway: openclaw gateway restart
Patches Overview
Four files are patched:
- channel.js — messaging.targetResolver (target ID recognition) + outbound account resolution
- monitor.js — requireMention filtering + reply-in-thread for deliver callback
- provider.js — reply-in-thread for sendTextMessage
- send.js — reply-in-thread for SDK reply calls
Patch Details
0. channel.js — Target Resolution + Account Resolution (2026-02-22)
Problem 1: message(send, lark, "oc_xxx") returns "Unknown target" because claw-lark has no messaging.targetResolver.looksLikeId. The core doesn't recognize oc_/ou_/on_ as valid IDs and falls through to directory lookup which fails.
Fix: Add messaging property to larkPlugin export:
- Import
looksLikeLarkId, normalizeLarkTargetfrom./utils.js - Add
messaging.targetResolver.looksLikeIdusing existinglooksLikeLarkId() - Add
messaging.normalizeTargetusing existingnormalizeLarkTarget()
Problem 2: outbound.sendText gets { cfg, to, accountId } from core but expects { account, recipientId }. The account object is undefined → "Cannot read properties of undefined (reading 'appId')".
Fix: All 5 outbound methods (sendText, sendMedia, downloadMedia, addReaction, removeReaction) add:
const account = args.account ?? resolveAccount(args.cfg, args.accountId ?? "default");
const recipientId = args.recipientId ?? args.to;
1. monitor.js — requireMention Filter
Location: routeMessage() function, after parseMessage(event) and the log line.
What: In group chats, skip messages that don't @mention our bot.
Key facts:
event.messageis the correct path (NOTevent.event.message)- Lark webhook
message.mentionscontains mention data withid.open_id - Bot open_id: set via
BOT_OPEN_IDenv var when runningapply-patches.sh - All bots lack
user_id(empty string) — cannot use!user_idto detect "is it me" @_user_Ntext placeholders appear for ALL @'d bots, not just ours — don't use regex match- Fallback: if mentions array empty, check
parsed.text.includes("@" + BOT_NAME)(set viaBOT_NAMEenv var)
2. monitor.js — Reply in Thread (deliver callback)
Location: Inside dispatchReplyWithBufferedBlockDispatcher deliver callback.
What:
- Set
replyToId = payload.replyToId || parsed.threadId || parsed.messageId(always have a value) - Use
client.im.message.reply()withreply_in_thread: trueinstead ofclient.im.message.create()withroot_id
Key facts:
root_idon create only associates with existing thread, does NOT create new threadreply_in_thread: trueon reply API creates a new thread- Works in both p2p and group chats
3. provider.js — sendTextMessage Thread Reply
Location: sendTextMessage() function.
What: When threadId is provided, use client.im.message.reply() instead of client.im.message.create().
4. send.js — reply_in_thread on SDK Reply
Location: sendMessageLark() and sendCardLark() reply branches.
What: Add reply_in_thread: true to data object in client.im.message.reply() calls.
Verification
After applying patches and restarting gateway:
- Send a group message WITHOUT @bot → should be silently ignored
- Send a group message WITH @bot → should reply in thread
- Send a DM → should reply in thread
- @ another bot → should be silently ignored
See Also
references/patch-details.md— Full code diffs for each patch
Comments
Loading comments...
