evolclaw 3.1.4 → 3.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/dist/agents/claude-runner.js +398 -161
- package/dist/agents/kit-renderer.js +191 -25
- package/dist/aun/aid/agentmd.js +75 -103
- package/dist/aun/aid/client.js +1 -29
- package/dist/aun/aid/identity.js +105 -64
- package/dist/aun/aid/index.js +2 -1
- package/dist/aun/aid/store.js +74 -0
- package/dist/aun/msg/group.js +2 -2
- package/dist/aun/msg/p2p.js +26 -2
- package/dist/aun/rpc/connection.js +23 -30
- package/dist/channels/aun.js +174 -99
- package/dist/channels/dingtalk.js +2 -1
- package/dist/channels/feishu.js +301 -199
- package/dist/channels/qqbot.js +2 -1
- package/dist/channels/wechat.js +2 -1
- package/dist/channels/wecom.js +2 -1
- package/dist/cli/agent.js +21 -16
- package/dist/cli/bench.js +41 -28
- package/dist/cli/help.js +8 -0
- package/dist/cli/index.js +176 -87
- package/dist/cli/init-channel.js +5 -1
- package/dist/cli/init.js +37 -21
- package/dist/cli/link-rules.js +1 -7
- package/dist/cli/model.js +549 -0
- package/dist/cli/net-check.js +133 -50
- package/dist/cli/watch-msg.js +7 -7
- package/dist/cli/watch-web/debug-log.js +18 -0
- package/dist/cli/watch-web/server.js +306 -0
- package/dist/cli/watch-web/sources/aid.js +63 -0
- package/dist/cli/watch-web/sources/msg.js +70 -0
- package/dist/cli/watch-web/sources/session.js +638 -0
- package/dist/cli/watch-web/sources/types.js +10 -0
- package/dist/cli/watch-web/static/app.js +546 -0
- package/dist/cli/watch-web/static/index.html +54 -0
- package/dist/cli/watch-web/static/style.css +247 -0
- package/dist/config-store.js +1 -22
- package/dist/core/channel-loader.js +7 -4
- package/dist/core/command-handler.js +261 -133
- package/dist/core/evolagent-registry.js +1 -1
- package/dist/core/evolagent.js +4 -22
- package/dist/core/interaction-router.js +59 -0
- package/dist/core/message/im-renderer.js +9 -20
- package/dist/core/message/message-bridge.js +13 -9
- package/dist/core/message/message-log.js +2 -2
- package/dist/core/message/message-processor.js +211 -123
- package/dist/core/message/stream-idle-monitor.js +21 -0
- package/dist/core/model/model-catalog.js +215 -0
- package/dist/core/model/model-scope.js +250 -0
- package/dist/core/relation/peer-identity.js +58 -55
- package/dist/core/relation/peer-key.js +16 -0
- package/dist/core/session/session-fs-store.js +34 -55
- package/dist/core/session/session-key.js +24 -0
- package/dist/core/session/session-manager.js +308 -251
- package/dist/core/session/session-mapper.js +9 -4
- package/dist/core/trigger/manager.js +3 -3
- package/dist/core/trigger/parser.js +4 -4
- package/dist/core/trigger/scheduler.js +22 -7
- package/dist/index.js +61 -7
- package/dist/ipc.js +23 -1
- package/dist/utils/error-utils.js +6 -0
- package/dist/utils/process-introspect.js +7 -5
- package/kits/docs/GUIDE.md +2 -2
- package/kits/docs/INDEX.md +8 -8
- package/kits/docs/channels/aun.md +56 -17
- package/kits/docs/channels/feishu.md +41 -12
- package/kits/docs/context-assembly.md +182 -0
- package/kits/docs/evolclaw/INDEX.md +43 -0
- package/kits/docs/evolclaw/agent.md +49 -0
- package/kits/docs/evolclaw/aid.md +49 -0
- package/kits/docs/evolclaw/ctl.md +46 -0
- package/kits/docs/evolclaw/group.md +89 -0
- package/kits/docs/evolclaw/model.md +51 -0
- package/kits/docs/evolclaw/msg.md +91 -0
- package/kits/docs/evolclaw/rpc.md +35 -0
- package/kits/docs/evolclaw/storage.md +49 -0
- package/kits/docs/venues/aun-group.md +10 -0
- package/kits/docs/venues/aun-private.md +10 -0
- package/kits/docs/venues/client-desktop.md +10 -0
- package/kits/docs/venues/client-mobile.md +10 -0
- package/kits/docs/venues/feishu-group.md +13 -0
- package/kits/docs/venues/feishu-private.md +9 -0
- package/kits/docs/venues/group.md +23 -0
- package/kits/docs/venues/private.md +10 -0
- package/kits/eck_manifest.json +81 -36
- package/kits/rules/01-overview.md +20 -10
- package/kits/rules/06-channel.md +34 -27
- package/kits/templates/system-fragments/baseagent.md +7 -1
- package/kits/templates/system-fragments/channel.md +7 -5
- package/kits/templates/system-fragments/commands.md +19 -0
- package/kits/templates/system-fragments/session.md +19 -3
- package/kits/templates/system-fragments/venue.md +24 -0
- package/package.json +10 -5
- package/dist/aun/aid/lifecycle-log.js +0 -33
- package/dist/utils/aid-lifecycle-log.js +0 -33
- package/kits/docs/evolclaw/AGENT_CMD.md +0 -31
- package/kits/docs/evolclaw/MSG_GROUP.md +0 -30
- package/kits/docs/evolclaw/MSG_PRIVATE.md +0 -72
- package/kits/docs/evolclaw/tools.md +0 -25
|
@@ -51,7 +51,7 @@ export function detectDuplicates(agents) {
|
|
|
51
51
|
export class EvolAgentRegistry {
|
|
52
52
|
_agentsDir;
|
|
53
53
|
agents = new Map();
|
|
54
|
-
/** channel key (`<type>#<
|
|
54
|
+
/** channel key (`<type>#<selfAID>#<name>`) → agent aid */
|
|
55
55
|
channelIndex = new Map();
|
|
56
56
|
/** 启动期被 ConfigStore 跳过的目录(命名非法 / 缺 config.json / 校验失败等) */
|
|
57
57
|
skipped = [];
|
package/dist/core/evolagent.js
CHANGED
|
@@ -62,11 +62,11 @@ export class EvolAgent {
|
|
|
62
62
|
}
|
|
63
63
|
// ── Channels ──────────────────────────────────────────────────────────
|
|
64
64
|
/**
|
|
65
|
-
* effective channel key:`<type>#<
|
|
66
|
-
* AUN channel 的
|
|
65
|
+
* effective channel key:`<type>#<selfAID>#<name>`。
|
|
66
|
+
* AUN channel 的 selfAID 是 agent.aid,name 固定为 'main'。
|
|
67
67
|
*/
|
|
68
68
|
effectiveChannelName(type, rawName) {
|
|
69
|
-
return formatChannelKey({ type,
|
|
69
|
+
return formatChannelKey({ type, selfAID: this.aid, name: rawName });
|
|
70
70
|
}
|
|
71
71
|
channelInstanceNames() {
|
|
72
72
|
// AUN channel 隐式存在(从 agent.aid 派生),不需要在 channels[] 里声明
|
|
@@ -97,7 +97,7 @@ export class EvolAgent {
|
|
|
97
97
|
*/
|
|
98
98
|
isAunChannelKey(channelKey) {
|
|
99
99
|
const parsed = tryParseChannelKey(channelKey);
|
|
100
|
-
return parsed?.type === 'aun' && parsed.
|
|
100
|
+
return parsed?.type === 'aun' && parsed.selfAID === this.aid;
|
|
101
101
|
}
|
|
102
102
|
getOwner(channelKey) {
|
|
103
103
|
if (this.isAunChannelKey(channelKey)) {
|
|
@@ -213,24 +213,6 @@ export class EvolAgent {
|
|
|
213
213
|
this.merged.dispatch = value;
|
|
214
214
|
this.persist();
|
|
215
215
|
}
|
|
216
|
-
// ── Projects ──────────────────────────────────────────────────────────
|
|
217
|
-
getProjects() {
|
|
218
|
-
const list = this.merged.projects?.list;
|
|
219
|
-
if (list && Object.keys(list).length > 0)
|
|
220
|
-
return { ...list };
|
|
221
|
-
const dp = this.merged.projects?.defaultPath;
|
|
222
|
-
if (dp)
|
|
223
|
-
return { [path.basename(dp)]: dp };
|
|
224
|
-
return {};
|
|
225
|
-
}
|
|
226
|
-
addProject(name, projectPath) {
|
|
227
|
-
if (!this.rawAgent.projects)
|
|
228
|
-
this.rawAgent.projects = { defaultPath: projectPath, list: {} };
|
|
229
|
-
if (!this.rawAgent.projects.list)
|
|
230
|
-
this.rawAgent.projects.list = {};
|
|
231
|
-
this.rawAgent.projects.list[name] = projectPath;
|
|
232
|
-
this.persist();
|
|
233
|
-
}
|
|
234
216
|
// ── Personal layer ────────────────────────────────────────────────────
|
|
235
217
|
_personaCache = undefined;
|
|
236
218
|
/**
|
|
@@ -1,14 +1,55 @@
|
|
|
1
1
|
import { logger } from '../utils/logger.js';
|
|
2
2
|
export class InteractionRouter {
|
|
3
3
|
handlers = new Map();
|
|
4
|
+
/** sessionId → 该会话当前待应答的交互数量,用于触发 wait 生命周期钩子 */
|
|
5
|
+
pendingBySession = new Map();
|
|
6
|
+
waitHooks;
|
|
7
|
+
setWaitHooks(hooks) {
|
|
8
|
+
this.waitHooks = hooks;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 在 register() 之前提前标记 session 为等待状态(适用于发卡片有异步延迟的场景)。
|
|
12
|
+
* 必须与 unmarkWaiting() 配对使用,或后续 register() 会接管计数。
|
|
13
|
+
*/
|
|
14
|
+
markWaiting(sessionId) {
|
|
15
|
+
this.incPending(sessionId);
|
|
16
|
+
}
|
|
17
|
+
/** 取消 markWaiting() 的占位(后续若有 register() 接管则不需调用此方法) */
|
|
18
|
+
unmarkWaiting(sessionId) {
|
|
19
|
+
this.decPending(sessionId);
|
|
20
|
+
}
|
|
21
|
+
/** 登记一个待应答交互;session 计数 0→1 时触发 onWaitStart */
|
|
22
|
+
incPending(sessionId) {
|
|
23
|
+
const next = (this.pendingBySession.get(sessionId) ?? 0) + 1;
|
|
24
|
+
this.pendingBySession.set(sessionId, next);
|
|
25
|
+
if (next === 1)
|
|
26
|
+
this.waitHooks?.onWaitStart(sessionId);
|
|
27
|
+
}
|
|
28
|
+
/** 注销一个待应答交互;session 计数 1→0 时触发 onWaitEnd */
|
|
29
|
+
decPending(sessionId) {
|
|
30
|
+
const cur = this.pendingBySession.get(sessionId) ?? 0;
|
|
31
|
+
if (cur <= 0)
|
|
32
|
+
return;
|
|
33
|
+
const next = cur - 1;
|
|
34
|
+
if (next === 0) {
|
|
35
|
+
this.pendingBySession.delete(sessionId);
|
|
36
|
+
this.waitHooks?.onWaitEnd(sessionId);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.pendingBySession.set(sessionId, next);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
4
42
|
register(id, sessionId, callback, opts) {
|
|
43
|
+
// 同 id 替换:槽位本就占用,计数不变,不触发 wait 钩子
|
|
5
44
|
const existing = this.handlers.get(id);
|
|
6
45
|
if (existing?.timer)
|
|
7
46
|
clearTimeout(existing.timer);
|
|
47
|
+
const isReplacement = !!existing;
|
|
8
48
|
let timer;
|
|
9
49
|
if (opts?.timeoutMs && opts.timeoutMs > 0) {
|
|
10
50
|
timer = setTimeout(() => {
|
|
11
51
|
this.handlers.delete(id);
|
|
52
|
+
this.decPending(sessionId);
|
|
12
53
|
logger.debug(`[InteractionRouter] Timeout for interaction: ${id}`);
|
|
13
54
|
opts.onTimeout?.();
|
|
14
55
|
}, opts.timeoutMs);
|
|
@@ -20,6 +61,8 @@ export class InteractionRouter {
|
|
|
20
61
|
initiatorId: opts?.initiatorId,
|
|
21
62
|
fallbackCommand: opts?.fallbackCommand,
|
|
22
63
|
});
|
|
64
|
+
if (!isReplacement)
|
|
65
|
+
this.incPending(sessionId);
|
|
23
66
|
}
|
|
24
67
|
handle(response) {
|
|
25
68
|
const handler = this.handlers.get(response.id);
|
|
@@ -28,6 +71,7 @@ export class InteractionRouter {
|
|
|
28
71
|
if (handler.timer)
|
|
29
72
|
clearTimeout(handler.timer);
|
|
30
73
|
this.handlers.delete(response.id);
|
|
74
|
+
this.decPending(handler.sessionId);
|
|
31
75
|
try {
|
|
32
76
|
const result = handler.callback(response.action, response.values, response.operatorId);
|
|
33
77
|
if (result && typeof result.catch === 'function') {
|
|
@@ -47,6 +91,7 @@ export class InteractionRouter {
|
|
|
47
91
|
if (handler.timer)
|
|
48
92
|
clearTimeout(handler.timer);
|
|
49
93
|
this.handlers.delete(id);
|
|
94
|
+
this.decPending(handler.sessionId);
|
|
50
95
|
}
|
|
51
96
|
}
|
|
52
97
|
}
|
|
@@ -56,6 +101,7 @@ export class InteractionRouter {
|
|
|
56
101
|
if (handler.timer)
|
|
57
102
|
clearTimeout(handler.timer);
|
|
58
103
|
this.handlers.delete(id);
|
|
104
|
+
this.decPending(handler.sessionId);
|
|
59
105
|
}
|
|
60
106
|
}
|
|
61
107
|
getPending(sessionId) {
|
|
@@ -100,6 +146,16 @@ export function renderActionAsText(req) {
|
|
|
100
146
|
const lines = [action.title];
|
|
101
147
|
if (action.body)
|
|
102
148
|
lines.push(action.body);
|
|
149
|
+
// checkers 多选:渲染选项列表
|
|
150
|
+
if (action.checkers?.length) {
|
|
151
|
+
lines.push('');
|
|
152
|
+
action.checkers.forEach((chk, idx) => {
|
|
153
|
+
const desc = chk.description ? ` — ${chk.description}` : '';
|
|
154
|
+
lines.push(` ${idx + 1}. ${chk.label}${desc}`);
|
|
155
|
+
});
|
|
156
|
+
lines.push('', '回复选项编号(多选用逗号分隔),或输入自定义内容');
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
}
|
|
103
159
|
if (!fb) {
|
|
104
160
|
return lines.join('\n');
|
|
105
161
|
}
|
|
@@ -111,5 +167,8 @@ export function renderActionAsText(req) {
|
|
|
111
167
|
if (fb.acceptFreeText && fb.freeTextHint) {
|
|
112
168
|
lines.push(` ${fb.freeTextHint}`);
|
|
113
169
|
}
|
|
170
|
+
if (action.allowCustomInput) {
|
|
171
|
+
lines.push(` 或直接输入自定义内容`);
|
|
172
|
+
}
|
|
114
173
|
return lines.join('\n');
|
|
115
174
|
}
|
|
@@ -132,26 +132,6 @@ export class IMRenderer {
|
|
|
132
132
|
getRemainingText() {
|
|
133
133
|
return this.textBuffer;
|
|
134
134
|
}
|
|
135
|
-
/** 从 buffer 中移除指定 pattern(用于文件标记预处理) */
|
|
136
|
-
stripFromBuffer(pattern) {
|
|
137
|
-
this.textBuffer = this.textBuffer.replace(pattern, '').trim();
|
|
138
|
-
// itemsQueue 中的 text items 也同步过滤
|
|
139
|
-
for (const item of this.itemsQueue) {
|
|
140
|
-
if (item.kind === 'text') {
|
|
141
|
-
item.text = item.text.replace(pattern, '');
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/** 清除上下文过长错误文本(从 buffer + allText 中移除) */
|
|
146
|
-
stripContextError(pattern) {
|
|
147
|
-
this.textBuffer = this.textBuffer.replace(pattern, '').trim();
|
|
148
|
-
this.allText = this.allText.replace(pattern, '').trim();
|
|
149
|
-
for (const item of this.itemsQueue) {
|
|
150
|
-
if (item.kind === 'text') {
|
|
151
|
-
item.text = item.text.replace(pattern, '');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
135
|
// ── 文本/活动注入(替代 StreamFlusher.addText/addActivity)──
|
|
156
136
|
/** 添加文本片段(流式 text) */
|
|
157
137
|
addText(text, outputTokens, turn) {
|
|
@@ -328,6 +308,15 @@ export class IMRenderer {
|
|
|
328
308
|
clearTimeout(this.timer);
|
|
329
309
|
this.timer = undefined;
|
|
330
310
|
}
|
|
311
|
+
// 上下文错误短语过滤:剔除错误关键词本身,保留前后内容
|
|
312
|
+
const ctxErrPattern = /prompt is too long|input is too long|context too long|context limit|context_length_exceeded|上下文过长/gi;
|
|
313
|
+
const stripCtxErr = (s) => s.replace(ctxErrPattern, '').trim();
|
|
314
|
+
this.textBuffer = stripCtxErr(this.textBuffer);
|
|
315
|
+
this.allText = stripCtxErr(this.allText);
|
|
316
|
+
for (const item of this.itemsQueue) {
|
|
317
|
+
if (item.kind === 'text')
|
|
318
|
+
item.text = stripCtxErr(item.text);
|
|
319
|
+
}
|
|
331
320
|
// 文件标记过滤
|
|
332
321
|
if (this.opts.fileMarkerPattern) {
|
|
333
322
|
this.textBuffer = this.textBuffer.replace(this.opts.fileMarkerPattern, '').trim();
|
|
@@ -81,12 +81,12 @@ export class MessageBridge {
|
|
|
81
81
|
logger.debug(`[MessageBridge] Command detected: "${cmdContent}", routing to handler`);
|
|
82
82
|
// 命令也要记录入方向 jsonl(不创建 session,直接用 chatDirPath 计算路径)
|
|
83
83
|
try {
|
|
84
|
-
const chatDir = chatDirPath(resolvePaths().sessionsDir, msg.channelType || effectiveChannelType, msg.channelId, msg.
|
|
84
|
+
const chatDir = chatDirPath(resolvePaths().sessionsDir, msg.channelType || effectiveChannelType, msg.channelId, msg.selfAID || '');
|
|
85
85
|
const inboundEncrypt = msg.replyContext?.metadata?.encrypted != null ? !!(msg.replyContext.metadata.encrypted) : undefined;
|
|
86
86
|
const inboundChatmode = msg.replyContext?.metadata?.chatmode;
|
|
87
87
|
appendMessageLog(chatDir, buildInboundEntry({
|
|
88
88
|
from: msg.peerId || 'unknown',
|
|
89
|
-
to: msg.
|
|
89
|
+
to: msg.selfAID || 'self',
|
|
90
90
|
chatType: msg.chatType || 'private',
|
|
91
91
|
groupId: msg.groupId ?? null,
|
|
92
92
|
msgId: msg.messageId ?? null,
|
|
@@ -105,7 +105,7 @@ export class MessageBridge {
|
|
|
105
105
|
if (await this.handleCommand(cmdContent, channelName, msg.channelId, (text) => {
|
|
106
106
|
logger.channelOut({ channel: channelName, channelId: msg.channelId, taskId: `cmd-${msg.messageId || Date.now()}`, payload: { kind: 'command.result', text } });
|
|
107
107
|
return sendReply(msg.channelId, text, msg.replyContext);
|
|
108
|
-
}, msg.peerId, msg.threadId, msg.chatType, msg.source, msg.replyContext))
|
|
108
|
+
}, msg.peerId, msg.threadId, msg.chatType, msg.source, msg.replyContext, msg.messageId, msg.selfAID))
|
|
109
109
|
return;
|
|
110
110
|
// 3. session 解析(使用 Channel 层填充的 chatType)
|
|
111
111
|
const chatType = msg.chatType || 'private';
|
|
@@ -114,7 +114,7 @@ export class MessageBridge {
|
|
|
114
114
|
if (msg.threadId && msg.replyContext)
|
|
115
115
|
metadata.replyContext = msg.replyContext;
|
|
116
116
|
// 写入实例名(审计 + 精确出站路由)
|
|
117
|
-
metadata.
|
|
117
|
+
metadata.channelKey = channelName;
|
|
118
118
|
if (chatType === 'private' && msg.peerId) {
|
|
119
119
|
metadata.peerId = msg.peerId;
|
|
120
120
|
if (msg.peerName)
|
|
@@ -134,7 +134,7 @@ export class MessageBridge {
|
|
|
134
134
|
const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
|
|
135
135
|
const effectiveProjectPath = owningAgent?.projectPath
|
|
136
136
|
?? this.defaultProjectPath;
|
|
137
|
-
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, undefined, msg.peerId, chatType, undefined, msg.
|
|
137
|
+
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, undefined, msg.peerId, chatType, undefined, msg.selfAID, msg.channelType || effectiveChannelType, msg.peerType);
|
|
138
138
|
// 4. 消息前缀(由 policy 决定)
|
|
139
139
|
const channelInfo = this.processor.getChannelInfo?.(channelName);
|
|
140
140
|
if (channelInfo?.policy) {
|
|
@@ -147,11 +147,14 @@ export class MessageBridge {
|
|
|
147
147
|
channel: channelName,
|
|
148
148
|
channelType: msg.channelType || effectiveChannelType,
|
|
149
149
|
channelId: msg.channelId, content,
|
|
150
|
-
|
|
150
|
+
selfAID: msg.selfAID,
|
|
151
151
|
chatType,
|
|
152
152
|
images: msg.images, timestamp: Date.now(),
|
|
153
153
|
peerId: msg.peerId, peerName: msg.peerName,
|
|
154
154
|
peerType: msg.peerType,
|
|
155
|
+
sameDevice: msg.sameDevice,
|
|
156
|
+
sameNetwork: msg.sameNetwork,
|
|
157
|
+
sameEgressIp: msg.sameEgressIp,
|
|
155
158
|
messageId: msg.messageId,
|
|
156
159
|
mentions: msg.mentions, threadId: msg.threadId,
|
|
157
160
|
replyContext: msg.replyContext,
|
|
@@ -162,7 +165,7 @@ export class MessageBridge {
|
|
|
162
165
|
const inboundChatmode = msg.replyContext?.metadata?.chatmode;
|
|
163
166
|
appendMessageLog(chatDir, buildInboundEntry({
|
|
164
167
|
from: msg.peerId || 'unknown',
|
|
165
|
-
to: msg.
|
|
168
|
+
to: msg.selfAID || 'self',
|
|
166
169
|
chatType,
|
|
167
170
|
groupId: msg.groupId ?? null,
|
|
168
171
|
msgId: msg.messageId ?? null,
|
|
@@ -219,6 +222,7 @@ export class MessageBridge {
|
|
|
219
222
|
permission: '/perm',
|
|
220
223
|
activity: '/activity',
|
|
221
224
|
system: '/system',
|
|
225
|
+
cli: '/cli',
|
|
222
226
|
};
|
|
223
227
|
resolveCmd(name, cmd) {
|
|
224
228
|
if (cmd)
|
|
@@ -374,11 +378,11 @@ export class MessageBridge {
|
|
|
374
378
|
}
|
|
375
379
|
}
|
|
376
380
|
/** 命令快速路径:返回 true 表示已处理 */
|
|
377
|
-
async handleCommand(content, channel, channelId, sendReply, userId, threadId, chatType, source, replyContext) {
|
|
381
|
+
async handleCommand(content, channel, channelId, sendReply, userId, threadId, chatType, source, replyContext, messageId, selfAID) {
|
|
378
382
|
if (!this.cmdHandler.isCommand(content))
|
|
379
383
|
return false;
|
|
380
384
|
logger.info(`[${channel}] ${channelId}: ${content}${source === 'card-trigger' ? ' [card]' : ''}`);
|
|
381
|
-
const cmdResult = await this.cmdHandler.handle(content, channel, channelId, (_cid, text, opts) => sendReply(text), userId, threadId, chatType, source);
|
|
385
|
+
const cmdResult = await this.cmdHandler.handle(content, channel, channelId, (_cid, text, opts) => sendReply(text), userId, threadId, chatType, source, messageId, selfAID);
|
|
382
386
|
logger.debug(`[MessageBridge] handleCommand: result type=${typeof cmdResult}`);
|
|
383
387
|
if (cmdResult === undefined)
|
|
384
388
|
return false;
|
|
@@ -31,8 +31,8 @@ function formatTimestampMs(epochMs) {
|
|
|
31
31
|
export function messageLogPath(chatDir) {
|
|
32
32
|
return path.join(chatDir, MESSAGE_LOG_FILE);
|
|
33
33
|
}
|
|
34
|
-
export function resolveChatDir(sessionsDir, channelType, channelId,
|
|
35
|
-
return chatDirPath(sessionsDir, channelType, channelId,
|
|
34
|
+
export function resolveChatDir(sessionsDir, channelType, channelId, selfAID) {
|
|
35
|
+
return chatDirPath(sessionsDir, channelType, channelId, selfAID);
|
|
36
36
|
}
|
|
37
37
|
export function appendMessageLog(chatDir, entry) {
|
|
38
38
|
if (entry.dir === 'in' && isDuplicate(entry.msgId)) {
|