@ai-setting/roy-agent-core 1.7.53 → 1.7.55
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/dist/env/agent/index.js +3 -3
- package/dist/env/error-reply.d.ts +184 -0
- package/dist/env/event-source/event-source-handlers.d.ts +9 -23
- package/dist/env/event-source/index.js +6 -6
- package/dist/env/index.js +18 -18
- package/dist/env/llm/adapter-pi-ai.d.ts +147 -2
- package/dist/env/llm/adapter.d.ts +21 -1
- package/dist/env/llm/index.js +2 -2
- package/dist/env/llm/invoke.d.ts +41 -1
- package/dist/env/llm/llm.d.ts +25 -0
- package/dist/env/llm/reasoning-defense.d.ts +104 -0
- package/dist/env/llm/types.d.ts +26 -0
- package/dist/env/prompt/index.js +2 -2
- package/dist/env/prompt/prompts-index.d.ts +1 -1
- package/dist/env/session/index.js +4 -4
- package/dist/env/session/storage/index.js +3 -3
- package/dist/env/task/backend/index.js +0 -2
- package/dist/env/task/backend/types.d.ts +0 -11
- package/dist/env/task/delegate/index.js +2 -2
- package/dist/env/task/index.js +3 -3
- package/dist/env/task/plugins/card-chat-routing.d.ts +42 -89
- package/dist/env/task/plugins/index.js +4 -4
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +0 -51
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +14 -31
- package/dist/env/task/plugins/per-task-group-chat-plugin.d.ts +4 -4
- package/dist/env/workflow/engine/engine.d.ts +65 -0
- package/dist/env/workflow/engine/index.js +2 -2
- package/dist/env/workflow/index.js +9 -9
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/env/workflow/nodes/tool-node.d.ts +6 -0
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/env/workflow/tools/index.js +6 -6
- package/dist/env/workflow/tools/workflow-validate-tool.d.ts +11 -2
- package/dist/env/workflow/types/run.d.ts +19 -0
- package/dist/env/workflow/utils/agent-session-metadata.d.ts +13 -0
- package/dist/env/workflow/utils/index.js +1 -1
- package/dist/env/workflow/utils/redact-command-secrets.d.ts +70 -0
- package/dist/env/workflow/utils/shell-dialect-lint.d.ts +75 -0
- package/dist/env/workflow/utils/validate-workflow-definition.d.ts +22 -0
- package/dist/index.js +20 -20
- package/dist/shared/@ai-setting/{roy-agent-core-stnddvx9.js → roy-agent-core-12d2xap8.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pk1b3kvf.js → roy-agent-core-2b8jtv7m.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-x8n1r7h4.js → roy-agent-core-2bscfrr1.js} +188 -7
- package/dist/shared/@ai-setting/{roy-agent-core-gdsqp6j8.js → roy-agent-core-6masakz4.js} +45 -0
- package/dist/shared/@ai-setting/{roy-agent-core-vvxb9522.js → roy-agent-core-6qxh4xrm.js} +67 -6
- package/dist/shared/@ai-setting/{roy-agent-core-h93v6p6y.js → roy-agent-core-7qy3nffr.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-4vpk40ss.js → roy-agent-core-8eqngasy.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-brwzs8wf.js → roy-agent-core-9h72sk1n.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-na73mym1.js → roy-agent-core-a4vzsn0g.js} +212 -1
- package/dist/shared/@ai-setting/{roy-agent-core-35s1w7tc.js → roy-agent-core-aer5kw1j.js} +142 -70
- package/dist/shared/@ai-setting/{roy-agent-core-j8e92gj8.js → roy-agent-core-b5ew8t0k.js} +0 -59
- package/dist/shared/@ai-setting/{roy-agent-core-4sx6sdb2.js → roy-agent-core-cd62e9p1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-39xejr39.js → roy-agent-core-e2z1etk4.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hch2geta.js → roy-agent-core-g36jevrk.js} +14 -183
- package/dist/shared/@ai-setting/{roy-agent-core-ph5qbqcx.js → roy-agent-core-j2nvedt6.js} +465 -128
- package/dist/shared/@ai-setting/{roy-agent-core-p2r27era.js → roy-agent-core-mxdc756a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-p8ak03s0.js → roy-agent-core-w527pcpe.js} +293 -42
- package/dist/shared/@ai-setting/{roy-agent-core-3tv1q6f2.js → roy-agent-core-ytr2w0vb.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-yd21n6c7.js → roy-agent-core-zvemdfx5.js} +1 -1
- package/dist/test-utils/child-process-mock.d.ts +73 -0
- package/package.json +2 -2
- /package/dist/shared/@ai-setting/{roy-agent-core-zy3hqfwg.js → roy-agent-core-0hq21px2.js} +0 -0
|
@@ -6,19 +6,18 @@ import {
|
|
|
6
6
|
createLarkCliTaskNotifyHook,
|
|
7
7
|
createPerTaskGroupChatPlugin,
|
|
8
8
|
extractPerTaskChatId,
|
|
9
|
-
extractPerTaskChatName
|
|
10
|
-
|
|
11
|
-
} from "./roy-agent-core-hch2geta.js";
|
|
9
|
+
extractPerTaskChatName
|
|
10
|
+
} from "./roy-agent-core-g36jevrk.js";
|
|
12
11
|
import {
|
|
13
12
|
getSharedEventStore
|
|
14
13
|
} from "./roy-agent-core-yhsssn86.js";
|
|
15
14
|
import {
|
|
16
15
|
createLarkCliWorkflowNotifyHook
|
|
17
|
-
} from "./roy-agent-core-
|
|
16
|
+
} from "./roy-agent-core-9h72sk1n.js";
|
|
18
17
|
import {
|
|
19
18
|
LarkCardPatchNotifier,
|
|
20
19
|
buildTaskCard
|
|
21
|
-
} from "./roy-agent-core-
|
|
20
|
+
} from "./roy-agent-core-b5ew8t0k.js";
|
|
22
21
|
import {
|
|
23
22
|
normalizeLarkAtMentions
|
|
24
23
|
} from "./roy-agent-core-64f22h1g.js";
|
|
@@ -611,7 +610,7 @@ var bountyIMHandler = {
|
|
|
611
610
|
};
|
|
612
611
|
|
|
613
612
|
// src/env/event-source/event-source-handlers.ts
|
|
614
|
-
import { spawn as
|
|
613
|
+
import { spawn as spawn3, exec as execSync } from "child_process";
|
|
615
614
|
import { promisify as promisify2 } from "node:util";
|
|
616
615
|
init_global_hook_manager();
|
|
617
616
|
init_context();
|
|
@@ -1086,8 +1085,407 @@ var bountyCliHandler = {
|
|
|
1086
1085
|
|
|
1087
1086
|
// src/env/event-source/event-source-handlers.ts
|
|
1088
1087
|
init_logger();
|
|
1088
|
+
|
|
1089
|
+
// src/env/error-reply.ts
|
|
1090
|
+
init_logger();
|
|
1091
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1092
|
+
var logger2 = createLogger("env:error-reply");
|
|
1093
|
+
var UPSTREAM_RETRY_PATTERNS = [
|
|
1094
|
+
/failed after \d+ attempts/i,
|
|
1095
|
+
/endpoint is unavailable/i,
|
|
1096
|
+
/upstream request failed/i,
|
|
1097
|
+
/rate.?limit/i,
|
|
1098
|
+
/\b429\b/,
|
|
1099
|
+
/\b50[0234]\b/,
|
|
1100
|
+
/service (is )?(temporarily )?unavailable/i,
|
|
1101
|
+
/\beconn(reset|refused|aborted)\b/i,
|
|
1102
|
+
/socket hang up/i,
|
|
1103
|
+
/fetch failed/i,
|
|
1104
|
+
/network error/i,
|
|
1105
|
+
/overloaded/i
|
|
1106
|
+
];
|
|
1107
|
+
var TIMEOUT_PATTERNS = [
|
|
1108
|
+
/timeout/i,
|
|
1109
|
+
/timed out/i,
|
|
1110
|
+
/deadline exceeded/i,
|
|
1111
|
+
/etimedout/i,
|
|
1112
|
+
/aborted due to timeout/i
|
|
1113
|
+
];
|
|
1114
|
+
var TRANSPORT_ABORT_PATTERNS = [
|
|
1115
|
+
/requestabortederror/i,
|
|
1116
|
+
/econnaborted/i,
|
|
1117
|
+
/connection (was )?(aborted|reset|closed)/i,
|
|
1118
|
+
/premature close/i
|
|
1119
|
+
];
|
|
1120
|
+
var ABORT_PATTERNS = [
|
|
1121
|
+
/\babort(?:ed|ing)?\b/i,
|
|
1122
|
+
/operation was cancelled/i,
|
|
1123
|
+
/operation was canceled/i,
|
|
1124
|
+
/sigint/i,
|
|
1125
|
+
/\binterrupted\b/i,
|
|
1126
|
+
/exiting due to (signal|shutdown)/i
|
|
1127
|
+
];
|
|
1128
|
+
var CONTEXT_PATTERNS = [
|
|
1129
|
+
/context threshold/i,
|
|
1130
|
+
/context (window|length|limit)/i,
|
|
1131
|
+
/token limit/i,
|
|
1132
|
+
/maximum context/i,
|
|
1133
|
+
/ctrieve\b/,
|
|
1134
|
+
/CTX_001/
|
|
1135
|
+
];
|
|
1136
|
+
var ASK_USER_PATTERNS = [/__ASK_USER_ERROR__/];
|
|
1137
|
+
function collectErrorText(error, depth = 0) {
|
|
1138
|
+
const parts = [];
|
|
1139
|
+
const push = (v) => {
|
|
1140
|
+
if (typeof v === "string" && v.length > 0)
|
|
1141
|
+
parts.push(v);
|
|
1142
|
+
};
|
|
1143
|
+
if (error === null || error === undefined)
|
|
1144
|
+
return "";
|
|
1145
|
+
if (typeof error === "string") {
|
|
1146
|
+
push(error);
|
|
1147
|
+
return parts.join(`
|
|
1148
|
+
`);
|
|
1149
|
+
}
|
|
1150
|
+
if (typeof error !== "object") {
|
|
1151
|
+
push(String(error));
|
|
1152
|
+
return parts.join(`
|
|
1153
|
+
`);
|
|
1154
|
+
}
|
|
1155
|
+
const e = error;
|
|
1156
|
+
push(e.name);
|
|
1157
|
+
push(e.message);
|
|
1158
|
+
for (const key of ["statusCode", "status", "code"]) {
|
|
1159
|
+
const v = e[key];
|
|
1160
|
+
if (typeof v === "number" || typeof v === "string")
|
|
1161
|
+
push(String(v));
|
|
1162
|
+
}
|
|
1163
|
+
if (depth < 3) {
|
|
1164
|
+
const nested = collectErrorText(e.lastError, depth + 1);
|
|
1165
|
+
if (nested)
|
|
1166
|
+
parts.push(nested);
|
|
1167
|
+
if (Array.isArray(e.errors)) {
|
|
1168
|
+
for (const inner of e.errors.slice(-3)) {
|
|
1169
|
+
const s = collectErrorText(inner, depth + 1);
|
|
1170
|
+
if (s)
|
|
1171
|
+
parts.push(s);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
const cause = collectErrorText(e.cause, depth + 1);
|
|
1175
|
+
if (cause)
|
|
1176
|
+
parts.push(cause);
|
|
1177
|
+
}
|
|
1178
|
+
return parts.join(`
|
|
1179
|
+
`);
|
|
1180
|
+
}
|
|
1181
|
+
function truncate(text, max) {
|
|
1182
|
+
if (text.length <= max)
|
|
1183
|
+
return text;
|
|
1184
|
+
return text.slice(0, max) + "…";
|
|
1185
|
+
}
|
|
1186
|
+
var FAILURE_RULES = [
|
|
1187
|
+
{
|
|
1188
|
+
id: "ask_user",
|
|
1189
|
+
kind: "ask_user",
|
|
1190
|
+
names: ["AskUserError"],
|
|
1191
|
+
patterns: ASK_USER_PATTERNS,
|
|
1192
|
+
notify: false,
|
|
1193
|
+
title: "等待用户回答",
|
|
1194
|
+
reason: "agent 正在等待用户回答,不是失败。",
|
|
1195
|
+
retryable: false
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
id: "context_overflow",
|
|
1199
|
+
kind: "context_overflow",
|
|
1200
|
+
names: ["ContextError"],
|
|
1201
|
+
patterns: CONTEXT_PATTERNS,
|
|
1202
|
+
notify: true,
|
|
1203
|
+
title: "上下文超出限制",
|
|
1204
|
+
reason: "这次对话的上下文超出模型窗口,自动压缩也未能恢复。建议新开一个会话继续,或先让我压缩当前会话。",
|
|
1205
|
+
retryable: false
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
id: "timeout",
|
|
1209
|
+
kind: "timeout",
|
|
1210
|
+
names: ["TimeoutError"],
|
|
1211
|
+
patterns: TIMEOUT_PATTERNS,
|
|
1212
|
+
notify: true,
|
|
1213
|
+
title: "执行超时",
|
|
1214
|
+
reason: "本次执行等待响应超时(上游长时间未返回或网络卡住)。建议稍后重试,或把任务拆小一些。",
|
|
1215
|
+
retryable: true
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
id: "upstream_retry",
|
|
1219
|
+
kind: "upstream_retry",
|
|
1220
|
+
names: ["AI_RetryError", "RetryError", "APICallError", "AI_APICallError"],
|
|
1221
|
+
patterns: UPSTREAM_RETRY_PATTERNS,
|
|
1222
|
+
notify: true,
|
|
1223
|
+
title: "模型服务暂时不可用(重试已用尽)",
|
|
1224
|
+
reason: "调用模型时上游持续返回错误(如 429 限流 / 503 不可用),自动重试多次后仍未成功。" + "这不是你的操作问题,也不是仓库代码的问题 —— 稍后重发一次即可。",
|
|
1225
|
+
retryable: true
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
id: "upstream_aborted",
|
|
1229
|
+
kind: "upstream_aborted",
|
|
1230
|
+
names: ["RequestAbortedError"],
|
|
1231
|
+
patterns: TRANSPORT_ABORT_PATTERNS,
|
|
1232
|
+
unless: TIMEOUT_PATTERNS,
|
|
1233
|
+
notify: true,
|
|
1234
|
+
title: "与模型服务的连接中断",
|
|
1235
|
+
reason: "请求在传输过程中被中断(连接被重置 / 代理提前关闭),不是你的操作问题。稍后重发一次即可。",
|
|
1236
|
+
retryable: true
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
id: "aborted",
|
|
1240
|
+
kind: "aborted",
|
|
1241
|
+
names: ["AbortError", "AbortSignal"],
|
|
1242
|
+
patterns: ABORT_PATTERNS,
|
|
1243
|
+
unless: [...TIMEOUT_PATTERNS, ...TRANSPORT_ABORT_PATTERNS],
|
|
1244
|
+
notify: true,
|
|
1245
|
+
title: "执行被中断",
|
|
1246
|
+
reason: "本次执行在完成前被中断(可能你手动取消了,或进程收到了停止信号)。你可以直接让我重新执行。",
|
|
1247
|
+
retryable: true
|
|
1248
|
+
}
|
|
1249
|
+
];
|
|
1250
|
+
var UNKNOWN_RULE = {
|
|
1251
|
+
id: "unknown",
|
|
1252
|
+
kind: "unknown",
|
|
1253
|
+
notify: true,
|
|
1254
|
+
title: "执行异常失败",
|
|
1255
|
+
reason: "本次执行遇到了未预期的异常,已中止。你可以重试;如果持续失败,请把这条消息里的技术细节发我。",
|
|
1256
|
+
retryable: true
|
|
1257
|
+
};
|
|
1258
|
+
function ruleMatches(rule, name, text) {
|
|
1259
|
+
const lowered = name.toLowerCase();
|
|
1260
|
+
const nameHit = rule.names?.some((n) => n.toLowerCase() === lowered) ?? false;
|
|
1261
|
+
const patternHit = rule.patterns?.some((p) => p.test(text)) ?? false;
|
|
1262
|
+
if (!nameHit && !patternHit)
|
|
1263
|
+
return false;
|
|
1264
|
+
if (rule.unless?.some((p) => p.test(text)))
|
|
1265
|
+
return false;
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
function classifyReactFailure(error) {
|
|
1269
|
+
const text = collectErrorText(error);
|
|
1270
|
+
const name = error && typeof error === "object" ? String(error.name ?? "") : "";
|
|
1271
|
+
const technical = text ? truncate(text.replace(/\s*\n\s*/g, " | "), 400) : undefined;
|
|
1272
|
+
const rule = FAILURE_RULES.find((r) => ruleMatches(r, name, text)) ?? UNKNOWN_RULE;
|
|
1273
|
+
return {
|
|
1274
|
+
kind: rule.kind,
|
|
1275
|
+
ruleId: rule.id,
|
|
1276
|
+
title: rule.title,
|
|
1277
|
+
reason: rule.reason,
|
|
1278
|
+
retryable: rule.retryable,
|
|
1279
|
+
notify: rule.notify,
|
|
1280
|
+
technical
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
var MAX_QUERY_PREVIEW = 200;
|
|
1284
|
+
function buildFailureReplyMarkdown(info, opts) {
|
|
1285
|
+
const lines = [];
|
|
1286
|
+
lines.push(`❌ **${info.title}**`);
|
|
1287
|
+
lines.push("");
|
|
1288
|
+
lines.push(info.reason);
|
|
1289
|
+
const query = opts?.query?.trim();
|
|
1290
|
+
if (query) {
|
|
1291
|
+
lines.push("");
|
|
1292
|
+
lines.push(`> 原始请求:${truncate(query.replace(/\s+/g, " "), MAX_QUERY_PREVIEW)}`);
|
|
1293
|
+
}
|
|
1294
|
+
if (info.retryable) {
|
|
1295
|
+
lines.push("");
|
|
1296
|
+
lines.push("**你可以:** 直接再发一次(重发即可,无需额外操作)。");
|
|
1297
|
+
} else {
|
|
1298
|
+
lines.push("");
|
|
1299
|
+
lines.push("**你可以:** 新开一个会话,或先让我压缩当前会话。");
|
|
1300
|
+
}
|
|
1301
|
+
const technical = info.technical;
|
|
1302
|
+
if (technical) {
|
|
1303
|
+
lines.push("");
|
|
1304
|
+
lines.push(`> 技术细节:${truncate(technical, 300)}`);
|
|
1305
|
+
}
|
|
1306
|
+
return lines.join(`
|
|
1307
|
+
`);
|
|
1308
|
+
}
|
|
1309
|
+
function extractReplyChannelFromEvent(envEvent) {
|
|
1310
|
+
if (!envEvent || typeof envEvent !== "object")
|
|
1311
|
+
return;
|
|
1312
|
+
const e = envEvent;
|
|
1313
|
+
const candidates = [
|
|
1314
|
+
e.metadata?.replyChannel,
|
|
1315
|
+
e.payload?.replyChannel
|
|
1316
|
+
];
|
|
1317
|
+
for (const c of candidates) {
|
|
1318
|
+
if (c && typeof c === "object") {
|
|
1319
|
+
const ch = c;
|
|
1320
|
+
if (ch.chatId || ch.messageId)
|
|
1321
|
+
return ch;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
function isUsableChannel(ch) {
|
|
1327
|
+
if (!ch)
|
|
1328
|
+
return false;
|
|
1329
|
+
if (!ch.chatId && !ch.messageId)
|
|
1330
|
+
return false;
|
|
1331
|
+
if (ch.type && !ch.type.toLowerCase().includes("lark"))
|
|
1332
|
+
return false;
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
var repliedTriggers = new Map;
|
|
1336
|
+
var CHAT_DEDUP_WINDOW_MS = 5 * 60000;
|
|
1337
|
+
var MAX_DEDUP_ENTRIES = 1000;
|
|
1338
|
+
function makeDedupKey(channel, info, explicit, now = Date.now()) {
|
|
1339
|
+
if (explicit)
|
|
1340
|
+
return explicit;
|
|
1341
|
+
if (channel.messageId)
|
|
1342
|
+
return `msg:${channel.messageId}`;
|
|
1343
|
+
if (channel.chatId) {
|
|
1344
|
+
const bucket = Math.floor(now / CHAT_DEDUP_WINDOW_MS);
|
|
1345
|
+
return `chat:${channel.chatId}:${info.kind}:${bucket}`;
|
|
1346
|
+
}
|
|
1347
|
+
return "unknown";
|
|
1348
|
+
}
|
|
1349
|
+
function isDuplicate(key, now = Date.now()) {
|
|
1350
|
+
const at = repliedTriggers.get(key);
|
|
1351
|
+
if (at === undefined)
|
|
1352
|
+
return false;
|
|
1353
|
+
if (key.startsWith("chat:") && now - at >= CHAT_DEDUP_WINDOW_MS) {
|
|
1354
|
+
repliedTriggers.delete(key);
|
|
1355
|
+
return false;
|
|
1356
|
+
}
|
|
1357
|
+
return true;
|
|
1358
|
+
}
|
|
1359
|
+
function rememberTrigger(key, now = Date.now()) {
|
|
1360
|
+
if (repliedTriggers.size >= MAX_DEDUP_ENTRIES) {
|
|
1361
|
+
const oldest = repliedTriggers.keys().next().value;
|
|
1362
|
+
if (oldest !== undefined)
|
|
1363
|
+
repliedTriggers.delete(oldest);
|
|
1364
|
+
}
|
|
1365
|
+
repliedTriggers.set(key, now);
|
|
1366
|
+
}
|
|
1367
|
+
var DEFAULT_REPLY_TIMEOUT_MS = 5000;
|
|
1368
|
+
function spawnLarkReply(options) {
|
|
1369
|
+
return new Promise((resolve, reject) => {
|
|
1370
|
+
const { chatId, messageId, content, profile } = options;
|
|
1371
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_REPLY_TIMEOUT_MS;
|
|
1372
|
+
let settled = false;
|
|
1373
|
+
let timer;
|
|
1374
|
+
const finish = (err) => {
|
|
1375
|
+
if (settled)
|
|
1376
|
+
return;
|
|
1377
|
+
settled = true;
|
|
1378
|
+
if (timer)
|
|
1379
|
+
clearTimeout(timer);
|
|
1380
|
+
if (err)
|
|
1381
|
+
reject(err);
|
|
1382
|
+
else
|
|
1383
|
+
resolve();
|
|
1384
|
+
};
|
|
1385
|
+
const normalizedContent = normalizeLarkAtMentions(content);
|
|
1386
|
+
let args;
|
|
1387
|
+
if (messageId) {
|
|
1388
|
+
args = [
|
|
1389
|
+
"im",
|
|
1390
|
+
"+messages-reply",
|
|
1391
|
+
"--message-id",
|
|
1392
|
+
messageId,
|
|
1393
|
+
"--markdown",
|
|
1394
|
+
normalizedContent,
|
|
1395
|
+
"--as",
|
|
1396
|
+
"bot"
|
|
1397
|
+
];
|
|
1398
|
+
} else if (chatId) {
|
|
1399
|
+
args = [
|
|
1400
|
+
"im",
|
|
1401
|
+
"+messages-send",
|
|
1402
|
+
"--chat-id",
|
|
1403
|
+
chatId,
|
|
1404
|
+
"--markdown",
|
|
1405
|
+
normalizedContent
|
|
1406
|
+
];
|
|
1407
|
+
} else {
|
|
1408
|
+
finish(new Error("No target specified for failure reply"));
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
if (profile) {
|
|
1412
|
+
args.unshift("--profile", profile);
|
|
1413
|
+
}
|
|
1414
|
+
let proc;
|
|
1415
|
+
try {
|
|
1416
|
+
proc = spawn2("lark-cli", args, {
|
|
1417
|
+
shell: false,
|
|
1418
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1419
|
+
});
|
|
1420
|
+
} catch (err) {
|
|
1421
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
timer = setTimeout(() => {
|
|
1425
|
+
try {
|
|
1426
|
+
proc.kill("SIGKILL");
|
|
1427
|
+
} catch {}
|
|
1428
|
+
finish(new Error(`lark-cli timed out after ${timeoutMs}ms`));
|
|
1429
|
+
}, timeoutMs);
|
|
1430
|
+
timer.unref?.();
|
|
1431
|
+
let stderr = "";
|
|
1432
|
+
proc.stdout?.on("data", () => {});
|
|
1433
|
+
proc.stderr?.on("data", (data) => {
|
|
1434
|
+
stderr += data.toString();
|
|
1435
|
+
});
|
|
1436
|
+
proc.on("close", (code) => {
|
|
1437
|
+
if (code === 0)
|
|
1438
|
+
finish();
|
|
1439
|
+
else
|
|
1440
|
+
finish(new Error(`lark-cli exited with code ${code}: ${stderr}`));
|
|
1441
|
+
});
|
|
1442
|
+
proc.on("error", (err) => finish(err));
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
async function notifyReactFailure(options) {
|
|
1446
|
+
const info = classifyReactFailure(options.error);
|
|
1447
|
+
if (!info.notify) {
|
|
1448
|
+
logger2.debug(`[#4418] 命中规则 ${info.ruleId}(非失败),不发失败说明` + (options.sessionId ? ` (session=${options.sessionId})` : ""));
|
|
1449
|
+
return { sent: false, kind: info.kind, info, skipped: "not_a_failure" };
|
|
1450
|
+
}
|
|
1451
|
+
const channel = (isUsableChannel(options.replyChannel) ? options.replyChannel : undefined) ?? extractReplyChannelFromEvent(options.envEvent);
|
|
1452
|
+
if (!isUsableChannel(channel)) {
|
|
1453
|
+
const hasTrigger = Boolean(options.envEvent);
|
|
1454
|
+
const noChannelMsg = `[#4418] React 中断(${info.kind}/${info.ruleId})无法定位 replyChannel,` + `飞书端收不到失败说明` + (hasTrigger ? " —— triggerEvent 存在但缺少 metadata.replyChannel" : "(本地执行,无 triggerEvent)") + (options.sessionId ? ` (session=${options.sessionId})` : "");
|
|
1455
|
+
if (hasTrigger)
|
|
1456
|
+
logger2.warn(noChannelMsg);
|
|
1457
|
+
else
|
|
1458
|
+
logger2.debug(noChannelMsg);
|
|
1459
|
+
return { sent: false, kind: info.kind, info, skipped: "no_channel" };
|
|
1460
|
+
}
|
|
1461
|
+
const dedupKey = makeDedupKey(channel, info, options.dedupKey);
|
|
1462
|
+
if (isDuplicate(dedupKey)) {
|
|
1463
|
+
logger2.info(`[#4418] React 中断(${info.kind})已回复过 ${dedupKey},跳过`);
|
|
1464
|
+
return { sent: false, kind: info.kind, info, skipped: "duplicate" };
|
|
1465
|
+
}
|
|
1466
|
+
rememberTrigger(dedupKey);
|
|
1467
|
+
const content = buildFailureReplyMarkdown(info, { query: options.query });
|
|
1468
|
+
try {
|
|
1469
|
+
await spawnLarkReply({
|
|
1470
|
+
chatId: channel.chatId,
|
|
1471
|
+
messageId: channel.messageId,
|
|
1472
|
+
content,
|
|
1473
|
+
profile: channel.profile,
|
|
1474
|
+
timeoutMs: options.replyTimeoutMs
|
|
1475
|
+
});
|
|
1476
|
+
logger2.info(`[#4418] React 中断(${info.kind}/${info.ruleId})已回飞书 ` + `(${channel.messageId ?? channel.chatId})`);
|
|
1477
|
+
return { sent: true, kind: info.kind, info };
|
|
1478
|
+
} catch (err) {
|
|
1479
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1480
|
+
repliedTriggers.delete(dedupKey);
|
|
1481
|
+
logger2.warn(`[#4418] React 中断(${info.kind}/${info.ruleId})回飞书失败(已忽略): ${errorMsg}`);
|
|
1482
|
+
return { sent: false, kind: info.kind, info, error: errorMsg };
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// src/env/event-source/event-source-handlers.ts
|
|
1089
1487
|
var execAsync2 = promisify2(execSync);
|
|
1090
|
-
var
|
|
1488
|
+
var logger3 = createLogger("lark-cli:event-source");
|
|
1091
1489
|
var CHILD_READY_TIMEOUT_MS = 5000;
|
|
1092
1490
|
var GRACEFUL_STOP_TIMEOUT_MS = 5000;
|
|
1093
1491
|
var CARD_ACTION_EVENT_TYPE = "card.action.trigger";
|
|
@@ -1320,13 +1718,12 @@ class LarkCliInstance {
|
|
|
1320
1718
|
starting = false;
|
|
1321
1719
|
eventHandler;
|
|
1322
1720
|
cardRoutingPorts;
|
|
1323
|
-
chatNameCache = new Map;
|
|
1324
1721
|
pluginInstances = new Map;
|
|
1325
1722
|
cardActionPorts;
|
|
1326
1723
|
setCardActionPorts(ports) {
|
|
1327
1724
|
this.cardActionPorts = ports;
|
|
1328
|
-
if (typeof
|
|
1329
|
-
|
|
1725
|
+
if (typeof logger3 !== "undefined" && logger3?.debug) {
|
|
1726
|
+
logger3.debug(`[LarkCliInstance] CardActionPorts injected: ` + `getTask=${typeof ports.getTask}, updateTaskContext=${typeof ports.updateTaskContext}, ` + `createGroupChat=${typeof ports.createGroupChat}, deleteGroupChat=${typeof ports.deleteGroupChat}, ` + `notifier=${typeof ports.notifier}`);
|
|
1330
1727
|
}
|
|
1331
1728
|
}
|
|
1332
1729
|
hasCardActionPorts() {
|
|
@@ -1353,13 +1750,12 @@ class LarkCliInstance {
|
|
|
1353
1750
|
if (this.status === "running")
|
|
1354
1751
|
return;
|
|
1355
1752
|
if (this.starting) {
|
|
1356
|
-
|
|
1753
|
+
logger3.warn(`[LarkCliInstance] start() 已在执行中,忽略重复调用`);
|
|
1357
1754
|
return;
|
|
1358
1755
|
}
|
|
1359
1756
|
this.starting = true;
|
|
1360
1757
|
try {
|
|
1361
1758
|
await this.loadPlugins();
|
|
1362
|
-
this.wireCardRoutingGroupProvider();
|
|
1363
1759
|
this.wireCardActionPorts();
|
|
1364
1760
|
const commands = this.buildConsumeCommands();
|
|
1365
1761
|
this.warnOnCardActionConfigTraps(commands);
|
|
@@ -1384,12 +1780,12 @@ class LarkCliInstance {
|
|
|
1384
1780
|
if (!consumesCardAction)
|
|
1385
1781
|
return;
|
|
1386
1782
|
if (this.config.eventTypes?.length && !matchEventType(CARD_ACTION_EVENT_TYPE, this.config.eventTypes)) {
|
|
1387
|
-
|
|
1783
|
+
logger3.warn(`[LarkCliInstance] eventKeys 含 ${CARD_ACTION_EVENT_TYPE},但 eventTypes=` + `${JSON.stringify(this.config.eventTypes)} 不含它 → 卡片点击会被**静默丢弃**。` + `请把 ${CARD_ACTION_EVENT_TYPE} 加进 eventTypes,或清空 eventTypes。`);
|
|
1388
1784
|
}
|
|
1389
|
-
|
|
1785
|
+
logger3.info(`[LarkCliInstance] 已监听 ${CARD_ACTION_EVENT_TYPE}。` + `⚠️ 若点击卡片无反应,先确认飞书开发者后台「事件与回调 → 回调配置」已开启该事件。`);
|
|
1390
1786
|
}
|
|
1391
1787
|
spawnConsumeChild(command) {
|
|
1392
|
-
return
|
|
1788
|
+
return spawn3("exec " + command, [], {
|
|
1393
1789
|
shell: true,
|
|
1394
1790
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1395
1791
|
windowsHide: true
|
|
@@ -1426,7 +1822,7 @@ class LarkCliInstance {
|
|
|
1426
1822
|
const conflicts = keys.filter((k) => busy.has(k));
|
|
1427
1823
|
if (conflicts.length > 0) {
|
|
1428
1824
|
const profile = this.config.profile;
|
|
1429
|
-
|
|
1825
|
+
logger3.warn(`[LarkCliInstance] eventKey 已被其它 consumer 占用(lark-cli 一个 key 只允许一个 consumer):` + `${conflicts.join(", ")}。本 event-source 启动后可能 exit 2。` + `用 \`lark-cli${profile ? ` --profile ${profile}` : ""} event status\` 查看,必要时 \`event stop\`。`);
|
|
1430
1826
|
}
|
|
1431
1827
|
}
|
|
1432
1828
|
async probeBusyEventKeys() {
|
|
@@ -1477,16 +1873,16 @@ class LarkCliInstance {
|
|
|
1477
1873
|
});
|
|
1478
1874
|
const handleExit = (code, source) => {
|
|
1479
1875
|
if (code !== 0 && code !== null) {
|
|
1480
|
-
|
|
1876
|
+
logger3.warn(`[LarkCliInstance] consume 子进程异常退出 code=${code} (${source}) cmd="${command}"`);
|
|
1481
1877
|
this.status = "error";
|
|
1482
1878
|
} else {
|
|
1483
|
-
|
|
1879
|
+
logger3.info(`[LarkCliInstance] consume 子进程已退出 code=${code} (${source}) cmd="${command}"`);
|
|
1484
1880
|
}
|
|
1485
1881
|
settle();
|
|
1486
1882
|
queueMicrotask(() => {
|
|
1487
1883
|
if (this.children.length > 0 && this.children.every((c) => !isChildAlive(c))) {
|
|
1488
1884
|
if (this.status !== "error") {
|
|
1489
|
-
|
|
1885
|
+
logger3.warn(`[LarkCliInstance] 所有 consume 子进程都已退出,状态从 running 改为 stopped`);
|
|
1490
1886
|
this.status = "stopped";
|
|
1491
1887
|
}
|
|
1492
1888
|
}
|
|
@@ -1495,12 +1891,12 @@ class LarkCliInstance {
|
|
|
1495
1891
|
child.on("exit", (code) => handleExit(code, "exit"));
|
|
1496
1892
|
child.on("close", (code) => handleExit(code, "close"));
|
|
1497
1893
|
child.on("error", (error) => {
|
|
1498
|
-
|
|
1894
|
+
logger3.error(`[LarkCliInstance] consume 子进程 error: ${error.message}`);
|
|
1499
1895
|
this.status = "error";
|
|
1500
1896
|
settle();
|
|
1501
1897
|
});
|
|
1502
1898
|
const timer = setTimeout(() => {
|
|
1503
|
-
|
|
1899
|
+
logger3.warn(`[LarkCliInstance] consume 子进程 ${CHILD_READY_TIMEOUT_MS}ms 内未见 ready marker: cmd="${command}"`);
|
|
1504
1900
|
settle();
|
|
1505
1901
|
}, CHILD_READY_TIMEOUT_MS);
|
|
1506
1902
|
ready.then(() => clearTimeout(timer));
|
|
@@ -1523,7 +1919,7 @@ class LarkCliInstance {
|
|
|
1523
1919
|
try {
|
|
1524
1920
|
child.kill("SIGTERM");
|
|
1525
1921
|
} catch (error) {
|
|
1526
|
-
|
|
1922
|
+
logger3.warn(`[LarkCliInstance] Error sending SIGTERM to ${child.pid}: ${error}`);
|
|
1527
1923
|
}
|
|
1528
1924
|
}
|
|
1529
1925
|
const allExited = Promise.all(children.map((child) => new Promise((resolve) => {
|
|
@@ -1578,12 +1974,12 @@ class LarkCliInstance {
|
|
|
1578
1974
|
}
|
|
1579
1975
|
wireCardActionPorts() {
|
|
1580
1976
|
if (this.cardActionPorts) {
|
|
1581
|
-
|
|
1977
|
+
logger3.debug("[LarkCliInstance] cardActionPorts 已由外部注入,跳过默认 cross-wire");
|
|
1582
1978
|
return;
|
|
1583
1979
|
}
|
|
1584
1980
|
const taskComponent = this.environment?.getComponent?.("task");
|
|
1585
1981
|
if (!taskComponent?.getTask || !taskComponent?.updateTask) {
|
|
1586
|
-
|
|
1982
|
+
logger3.debug(`[LarkCliInstance] card.action.trigger 端口未注入:taskComponent 不可用` + `(getTask=${typeof taskComponent?.getTask}, updateTask=${typeof taskComponent?.updateTask})。` + `卡片按钮点击会被跳过。`);
|
|
1587
1983
|
return;
|
|
1588
1984
|
}
|
|
1589
1985
|
const sharedNotifier = this.pluginInstances.get("LarkCliTaskNotifyPlugin")?.cardNotifier ?? this.pluginInstances.get("PerTaskGroupChatPlugin")?.cardNotifier;
|
|
@@ -1612,20 +2008,7 @@ class LarkCliInstance {
|
|
|
1612
2008
|
deleteGroupChat: (chatId, profile) => deleteGroupChatViaLarkCli(chatId, profile),
|
|
1613
2009
|
notifier: sharedNotifier ?? new LarkCardPatchNotifier
|
|
1614
2010
|
});
|
|
1615
|
-
|
|
1616
|
-
}
|
|
1617
|
-
wireCardRoutingGroupProvider() {
|
|
1618
|
-
const notifyHook = this.pluginInstances.get("LarkCliTaskNotifyPlugin");
|
|
1619
|
-
const perTaskGroup = this.pluginInstances.get("PerTaskGroupChatPlugin");
|
|
1620
|
-
if (!notifyHook || typeof notifyHook.setCardRoutingPorts !== "function")
|
|
1621
|
-
return;
|
|
1622
|
-
if (!perTaskGroup || typeof perTaskGroup.ensureGroupChat !== "function")
|
|
1623
|
-
return;
|
|
1624
|
-
notifyHook.setCardRoutingPorts({
|
|
1625
|
-
...this.cardRoutingPorts ?? {},
|
|
1626
|
-
ensureTaskGroupChat: (task) => perTaskGroup.ensureGroupChat(task)
|
|
1627
|
-
});
|
|
1628
|
-
console.debug("[LarkCliInstance] Card routing cross-wired: " + "LarkCliTaskNotifyPlugin.ensureTaskGroupChat ← PerTaskGroupChatPlugin");
|
|
2011
|
+
logger3.info(`[LarkCliInstance] card.action.trigger 端口已注入` + `(notifier ${sharedNotifier ? "复用插件共享实例" : "新建实例"})`);
|
|
1629
2012
|
}
|
|
1630
2013
|
getPluginHookPoints(plugin) {
|
|
1631
2014
|
if (Array.isArray(plugin.hooks)) {
|
|
@@ -1779,63 +2162,11 @@ class LarkCliInstance {
|
|
|
1779
2162
|
if (typeof plugin.setCardRoutingPorts !== "function")
|
|
1780
2163
|
return;
|
|
1781
2164
|
const taskComponent = this.environment?.getComponent?.("task");
|
|
1782
|
-
const sessionComponent = this.environment?.getComponent?.("session");
|
|
1783
|
-
const lookupChatOwnership = async (chatId) => {
|
|
1784
|
-
if (!chatId)
|
|
1785
|
-
return;
|
|
1786
|
-
try {
|
|
1787
|
-
let boundTaskId;
|
|
1788
|
-
if (sessionComponent?.getChatTaskBinding) {
|
|
1789
|
-
try {
|
|
1790
|
-
const binding = await sessionComponent.getChatTaskBinding(chatId);
|
|
1791
|
-
if (binding && typeof binding.taskId === "number") {
|
|
1792
|
-
boundTaskId = binding.taskId;
|
|
1793
|
-
}
|
|
1794
|
-
} catch {}
|
|
1795
|
-
}
|
|
1796
|
-
let candidates = [];
|
|
1797
|
-
if (taskComponent?.findTasksByContextValue) {
|
|
1798
|
-
const tasks = await taskComponent.findTasksByContextValue(chatId, 50);
|
|
1799
|
-
candidates = (tasks ?? []).map((t) => ({
|
|
1800
|
-
id: t.id,
|
|
1801
|
-
context: t.context
|
|
1802
|
-
}));
|
|
1803
|
-
}
|
|
1804
|
-
const chatName = await this.lookupChatName(chatId);
|
|
1805
|
-
return mergeChatOwnership(chatId, candidates, { boundTaskId, chatName });
|
|
1806
|
-
} catch (error) {
|
|
1807
|
-
if (isPluginDebugEnabled()) {
|
|
1808
|
-
console.debug(`[LarkCliInstance] lookupChatOwnership failed for ${chatId}: ${error}`);
|
|
1809
|
-
}
|
|
1810
|
-
return;
|
|
1811
|
-
}
|
|
1812
|
-
};
|
|
1813
2165
|
this.cardRoutingPorts = {
|
|
1814
|
-
lookupChatOwnership,
|
|
1815
2166
|
getTask: taskComponent?.getTask ? (id) => taskComponent.getTask(id) : undefined
|
|
1816
2167
|
};
|
|
1817
2168
|
plugin.setCardRoutingPorts({ ...this.cardRoutingPorts });
|
|
1818
2169
|
}
|
|
1819
|
-
async lookupChatName(chatId) {
|
|
1820
|
-
const cached = this.chatNameCache.get(chatId);
|
|
1821
|
-
if (cached !== undefined)
|
|
1822
|
-
return cached || undefined;
|
|
1823
|
-
try {
|
|
1824
|
-
const runner = getLarkCliRunner();
|
|
1825
|
-
const result = await runner.run(`lark-cli ${this.config.profile ? `--profile ${this.config.profile} ` : ""}im chats get --chat-id ${chatId}`);
|
|
1826
|
-
if (result.code !== 0) {
|
|
1827
|
-
this.chatNameCache.set(chatId, "");
|
|
1828
|
-
return;
|
|
1829
|
-
}
|
|
1830
|
-
const parsed = JSON.parse(result.stdout || "{}");
|
|
1831
|
-
const name = parsed?.data?.name ?? parsed?.data?.chat?.name ?? parsed?.name;
|
|
1832
|
-
this.chatNameCache.set(chatId, typeof name === "string" ? name : "");
|
|
1833
|
-
return typeof name === "string" ? name : undefined;
|
|
1834
|
-
} catch {
|
|
1835
|
-
this.chatNameCache.set(chatId, "");
|
|
1836
|
-
return;
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
2170
|
injectSessionComponent(plugin) {
|
|
1840
2171
|
if (typeof plugin.setSessionComponent !== "function") {
|
|
1841
2172
|
return;
|
|
@@ -1874,7 +2205,7 @@ class LarkCliInstance {
|
|
|
1874
2205
|
}
|
|
1875
2206
|
return null;
|
|
1876
2207
|
} catch (err) {
|
|
1877
|
-
|
|
2208
|
+
logger3.warn(`[LarkCliInstance] resolveChatTaskBinding failed for chatId=${chatId}: ${err}. ` + `群消息将不会注入 parentTaskId。`);
|
|
1878
2209
|
return null;
|
|
1879
2210
|
}
|
|
1880
2211
|
}
|
|
@@ -1896,7 +2227,7 @@ class LarkCliInstance {
|
|
|
1896
2227
|
processStreamWith(data, buffer, opts = {}) {
|
|
1897
2228
|
buffer.value += data;
|
|
1898
2229
|
if (buffer.value.length > 2 * 1024 * 1024) {
|
|
1899
|
-
|
|
2230
|
+
logger3.warn(`[LarkCliInstance] stream 行缓冲超过 2MB 仍无换行,丢弃(疑似非 NDJSON 输出)`);
|
|
1900
2231
|
buffer.value = "";
|
|
1901
2232
|
return;
|
|
1902
2233
|
}
|
|
@@ -1926,12 +2257,12 @@ class LarkCliInstance {
|
|
|
1926
2257
|
const now = Date.now();
|
|
1927
2258
|
const lastShared = LarkCliInstance.SHARED_SEEN.get(dedupKey);
|
|
1928
2259
|
if (lastShared !== undefined && now - lastShared < LarkCliInstance.SHARED_MSG_TTL_MS) {
|
|
1929
|
-
|
|
2260
|
+
logger3.warn(`[LarkCliInstance] duplicate lark-cli event suppressed across instances (event_id=${dedupKey}, ` + `lastSeen=${now - lastShared}ms ago). ` + `Task #4137: SHARED_SEEN 跨实例去重。`);
|
|
1930
2261
|
return;
|
|
1931
2262
|
}
|
|
1932
2263
|
const last = this.recentEventIds.get(dedupKey);
|
|
1933
2264
|
if (last !== undefined && now - last < this.DEDUP_WINDOW_MS) {
|
|
1934
|
-
|
|
2265
|
+
logger3.warn(`[LarkCliInstance] duplicate lark-cli event suppressed (event_id=${dedupKey}, ` + `lastSeen=${now - last}ms ago). ` + `Task #3977/3978: 防止同一飞书事件触发两次任务创建。`);
|
|
1935
2266
|
return;
|
|
1936
2267
|
}
|
|
1937
2268
|
LarkCliInstance.SHARED_SEEN.set(dedupKey, now);
|
|
@@ -1965,6 +2296,7 @@ class LarkCliInstance {
|
|
|
1965
2296
|
attributes: { rawData: rawData.substring(0, 500) }
|
|
1966
2297
|
});
|
|
1967
2298
|
provider.setGlobalContext(rootSpan.spanContext);
|
|
2299
|
+
let failureReplyChannel;
|
|
1968
2300
|
try {
|
|
1969
2301
|
let rawEvent;
|
|
1970
2302
|
try {
|
|
@@ -1994,6 +2326,7 @@ class LarkCliInstance {
|
|
|
1994
2326
|
eventSourceId: this.config.id
|
|
1995
2327
|
};
|
|
1996
2328
|
const { metadata, replyChannel, recommendedAction } = extractMetadata(enrichedEvent, eventType);
|
|
2329
|
+
failureReplyChannel = replyChannel;
|
|
1997
2330
|
const parentTaskId = isCardAction ? null : await this.resolveChatTaskBinding(metadata?.chatId);
|
|
1998
2331
|
const userId = this.extractUserId(rawEvent);
|
|
1999
2332
|
let triggerEventId;
|
|
@@ -2095,6 +2428,10 @@ class LarkCliInstance {
|
|
|
2095
2428
|
} catch (error) {
|
|
2096
2429
|
console.error(`[LarkCliInstance] Error handling event: ${error}`);
|
|
2097
2430
|
rootSpan.setAttribute("error", String(error));
|
|
2431
|
+
notifyReactFailure({
|
|
2432
|
+
error,
|
|
2433
|
+
replyChannel: failureReplyChannel
|
|
2434
|
+
}).catch(() => {});
|
|
2098
2435
|
} finally {
|
|
2099
2436
|
rootSpan.end();
|
|
2100
2437
|
}
|
|
@@ -2109,11 +2446,11 @@ class LarkCliInstance {
|
|
|
2109
2446
|
const chatId = event.chat_id || "";
|
|
2110
2447
|
const operatorId = event.operator_id?.open_id ?? event.operator_id ?? undefined;
|
|
2111
2448
|
if (!token || !messageId || !chatId) {
|
|
2112
|
-
|
|
2449
|
+
logger3.warn(`[LarkCliInstance] handleCardActionEvent: missing token/messageId/chatId, skip`);
|
|
2113
2450
|
return;
|
|
2114
2451
|
}
|
|
2115
2452
|
if (!this.cardActionPorts) {
|
|
2116
|
-
|
|
2453
|
+
logger3.warn(`[LarkCliInstance] handleCardActionEvent: cardActionPorts 未注入,` + `card.action.trigger 事件被跳过。` + `调 instance.setCardActionPorts({getTask, updateTaskContext, createGroupChat, deleteGroupChat, notifier}) 注入。`);
|
|
2117
2454
|
return;
|
|
2118
2455
|
}
|
|
2119
2456
|
const result = await handleCardAction({
|
|
@@ -2128,10 +2465,10 @@ class LarkCliInstance {
|
|
|
2128
2465
|
const patch = this.cardActionPorts.patchByToken ?? patchCardByLarkCli;
|
|
2129
2466
|
await patch(token, result.cardUpdate, profile);
|
|
2130
2467
|
} else {
|
|
2131
|
-
|
|
2468
|
+
logger3.warn(`[LarkCliInstance] handleCardActionEvent failed: ${result.error ?? "unknown"}`);
|
|
2132
2469
|
}
|
|
2133
2470
|
} catch (err) {
|
|
2134
|
-
|
|
2471
|
+
logger3.error(`[LarkCliInstance] handleCardActionEvent error: ${err.message}`);
|
|
2135
2472
|
}
|
|
2136
2473
|
}
|
|
2137
2474
|
async patchCardByToken(token, card, profile) {
|
|
@@ -2223,7 +2560,7 @@ class LarkCliInstance {
|
|
|
2223
2560
|
if (profile) {
|
|
2224
2561
|
args.unshift("--profile", profile);
|
|
2225
2562
|
}
|
|
2226
|
-
const proc =
|
|
2563
|
+
const proc = spawn3("lark-cli", args, {
|
|
2227
2564
|
shell: false,
|
|
2228
2565
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2229
2566
|
});
|
|
@@ -2302,7 +2639,7 @@ var larkCliHandler = {
|
|
|
2302
2639
|
},
|
|
2303
2640
|
async emitTriggerEvent(payload, store) {
|
|
2304
2641
|
const eventId = await store.insertTriggerEvent(payload, "lark-cli");
|
|
2305
|
-
|
|
2642
|
+
logger3.info(`[larkCliHandler] emitTriggerEvent: id=${eventId}`, {
|
|
2306
2643
|
chatId: payload.metadata?.chatId,
|
|
2307
2644
|
senderId: payload.senderId
|
|
2308
2645
|
});
|
|
@@ -2317,7 +2654,7 @@ var larkCliHandler = {
|
|
|
2317
2654
|
try {
|
|
2318
2655
|
const result = await runner.run(command);
|
|
2319
2656
|
if (result.code !== 0) {
|
|
2320
|
-
|
|
2657
|
+
logger3.error(`[larkCliHandler] replyMessage non-zero exit`, {
|
|
2321
2658
|
code: result.code,
|
|
2322
2659
|
stderr: result.stderr
|
|
2323
2660
|
});
|
|
@@ -2331,7 +2668,7 @@ var larkCliHandler = {
|
|
|
2331
2668
|
return { success: true, messageId: replyMessageId };
|
|
2332
2669
|
} catch (err) {
|
|
2333
2670
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2334
|
-
|
|
2671
|
+
logger3.error(`[larkCliHandler] replyMessage spawn error`, { error: errMsg });
|
|
2335
2672
|
return { success: false, error: errMsg };
|
|
2336
2673
|
}
|
|
2337
2674
|
},
|
|
@@ -2418,9 +2755,9 @@ async function patchCardByLarkCli(token, card, profile) {
|
|
|
2418
2755
|
const cmd = `lark-cli ${profileFlag}api POST /open-apis/interactive/v1/card/update ` + `--data '${JSON.stringify({ token, card }).replace(/'/g, "'\\''")}' --as bot`;
|
|
2419
2756
|
try {
|
|
2420
2757
|
const { stdout } = await execAsync2(cmd, { timeout: 30000 });
|
|
2421
|
-
|
|
2758
|
+
logger3.debug(`patchCardByLarkCli ok: ${stdout?.slice(0, 200)}`);
|
|
2422
2759
|
} catch (err) {
|
|
2423
|
-
|
|
2760
|
+
logger3.error(`patchCardByLarkCli failed: ${err.message}`);
|
|
2424
2761
|
}
|
|
2425
2762
|
}
|
|
2426
2763
|
var builtInHandlers = [
|
|
@@ -2457,7 +2794,7 @@ var EVENT_SOURCE_CONFIG_REGISTRATION = {
|
|
|
2457
2794
|
};
|
|
2458
2795
|
|
|
2459
2796
|
// src/env/event-source/event-source-component.ts
|
|
2460
|
-
var
|
|
2797
|
+
var logger4 = createLogger("event-source");
|
|
2461
2798
|
|
|
2462
2799
|
class EventSourceComponent extends BaseComponent {
|
|
2463
2800
|
name = "event-source";
|
|
@@ -2524,7 +2861,7 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2524
2861
|
for (const handler of builtInHandlers) {
|
|
2525
2862
|
if (!this.handlers.has(handler.type)) {
|
|
2526
2863
|
this.handlers.set(handler.type, handler);
|
|
2527
|
-
|
|
2864
|
+
logger4.debug(`Registered built-in handler: ${handler.type}`);
|
|
2528
2865
|
}
|
|
2529
2866
|
}
|
|
2530
2867
|
}
|
|
@@ -2534,15 +2871,15 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2534
2871
|
}
|
|
2535
2872
|
registerHandler(handler) {
|
|
2536
2873
|
if (this.handlers.has(handler.type)) {
|
|
2537
|
-
|
|
2874
|
+
logger4.warn(`Handler already registered for type: ${handler.type}, overwriting`);
|
|
2538
2875
|
}
|
|
2539
2876
|
this.handlers.set(handler.type, handler);
|
|
2540
|
-
|
|
2877
|
+
logger4.debug(`Handler registered: ${handler.type}`);
|
|
2541
2878
|
}
|
|
2542
2879
|
unregisterHandler(type) {
|
|
2543
2880
|
const deleted = this.handlers.delete(type);
|
|
2544
2881
|
if (deleted) {
|
|
2545
|
-
|
|
2882
|
+
logger4.debug(`Handler unregistered: ${type}`);
|
|
2546
2883
|
}
|
|
2547
2884
|
return deleted;
|
|
2548
2885
|
}
|
|
@@ -2632,7 +2969,7 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2632
2969
|
});
|
|
2633
2970
|
}
|
|
2634
2971
|
onConfigChange(event) {
|
|
2635
|
-
|
|
2972
|
+
logger4.info(`EventSource config changed: ${event.key}`, {
|
|
2636
2973
|
oldValue: event.oldValue,
|
|
2637
2974
|
newValue: event.newValue
|
|
2638
2975
|
});
|
|
@@ -2651,9 +2988,9 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2651
2988
|
}
|
|
2652
2989
|
this.sources.set(config.id, config);
|
|
2653
2990
|
this.statuses.set(config.id, "created");
|
|
2654
|
-
|
|
2991
|
+
logger4.debug(`EventSource registered: ${config.id} (${config.type})`);
|
|
2655
2992
|
this.saveConfig().catch((err) => {
|
|
2656
|
-
|
|
2993
|
+
logger4.error(`Failed to save config after registering ${config.id}:`, err);
|
|
2657
2994
|
});
|
|
2658
2995
|
}
|
|
2659
2996
|
unregister(id) {
|
|
@@ -2668,9 +3005,9 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2668
3005
|
this.eventHandlers.delete(id);
|
|
2669
3006
|
this.buffers.delete(id);
|
|
2670
3007
|
if (existed) {
|
|
2671
|
-
|
|
3008
|
+
logger4.debug(`EventSource unregistered: ${id}`);
|
|
2672
3009
|
this.saveConfig().catch((err) => {
|
|
2673
|
-
|
|
3010
|
+
logger4.error(`Failed to save config after unregistering ${id}:`, err);
|
|
2674
3011
|
});
|
|
2675
3012
|
}
|
|
2676
3013
|
return existed;
|
|
@@ -2708,13 +3045,13 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2708
3045
|
}
|
|
2709
3046
|
}
|
|
2710
3047
|
this.sources.set(id, updated);
|
|
2711
|
-
|
|
3048
|
+
logger4.info(`EventSource updated: ${id}`, {
|
|
2712
3049
|
fields: Object.keys(partial)
|
|
2713
3050
|
});
|
|
2714
3051
|
try {
|
|
2715
3052
|
await this.saveConfig();
|
|
2716
3053
|
} catch (err) {
|
|
2717
|
-
|
|
3054
|
+
logger4.error(`Failed to save config after updating ${id}:`, err);
|
|
2718
3055
|
throw err;
|
|
2719
3056
|
}
|
|
2720
3057
|
return {
|
|
@@ -2783,18 +3120,18 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2783
3120
|
type: "event-source.started",
|
|
2784
3121
|
payload: { sourceId: id, sourceType: config.type }
|
|
2785
3122
|
});
|
|
2786
|
-
|
|
3123
|
+
logger4.info(`EventSource started: ${id} (${config.type})`);
|
|
2787
3124
|
} catch (error) {
|
|
2788
3125
|
this.statuses.set(id, "error");
|
|
2789
|
-
|
|
3126
|
+
logger4.error(`EventSource failed to start: ${id}`, error);
|
|
2790
3127
|
throw error;
|
|
2791
3128
|
}
|
|
2792
3129
|
}
|
|
2793
3130
|
async stopSource(id) {
|
|
2794
3131
|
const status = this.statuses.get(id);
|
|
2795
|
-
|
|
3132
|
+
logger4.info(`[EventSource ${id}] stopSource called, current status: ${status}`);
|
|
2796
3133
|
if (status === "stopped" || status === "created") {
|
|
2797
|
-
|
|
3134
|
+
logger4.info(`[EventSource ${id}] already stopped/created, skipping`);
|
|
2798
3135
|
return;
|
|
2799
3136
|
}
|
|
2800
3137
|
this.statuses.set(id, "stopping");
|
|
@@ -2810,10 +3147,10 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2810
3147
|
type: "event-source.stopped",
|
|
2811
3148
|
payload: { sourceId: id, sourceType: config?.type }
|
|
2812
3149
|
});
|
|
2813
|
-
|
|
3150
|
+
logger4.info(`EventSource stopped: ${id}`);
|
|
2814
3151
|
} catch (error) {
|
|
2815
3152
|
this.statuses.set(id, "error");
|
|
2816
|
-
|
|
3153
|
+
logger4.error(`EventSource failed to stop: ${id}`, error);
|
|
2817
3154
|
throw error;
|
|
2818
3155
|
}
|
|
2819
3156
|
}
|
|
@@ -2838,9 +3175,9 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2838
3175
|
sources: Array.from(this.sources.values())
|
|
2839
3176
|
};
|
|
2840
3177
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
2841
|
-
|
|
3178
|
+
logger4.debug(`Saved ${this.sources.size} event source configurations`);
|
|
2842
3179
|
} catch (error) {
|
|
2843
|
-
|
|
3180
|
+
logger4.error("Failed to save event source configurations:", error);
|
|
2844
3181
|
throw error;
|
|
2845
3182
|
}
|
|
2846
3183
|
}
|
|
@@ -2850,13 +3187,13 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2850
3187
|
try {
|
|
2851
3188
|
const configPath = this.getConfigFilePath();
|
|
2852
3189
|
if (!existsSync(configPath)) {
|
|
2853
|
-
|
|
3190
|
+
logger4.debug(`No event source config file found at ${configPath}`);
|
|
2854
3191
|
return;
|
|
2855
3192
|
}
|
|
2856
3193
|
const content = readFileSync(configPath, "utf-8");
|
|
2857
3194
|
const config = JSON.parse(content);
|
|
2858
3195
|
if (!config.sources || !Array.isArray(config.sources)) {
|
|
2859
|
-
|
|
3196
|
+
logger4.warn("Invalid event source config format, skipping load");
|
|
2860
3197
|
return;
|
|
2861
3198
|
}
|
|
2862
3199
|
let loadedCount = 0;
|
|
@@ -2867,9 +3204,9 @@ class EventSourceComponent extends BaseComponent {
|
|
|
2867
3204
|
loadedCount++;
|
|
2868
3205
|
}
|
|
2869
3206
|
}
|
|
2870
|
-
|
|
3207
|
+
logger4.info(`Loaded ${loadedCount} event source configurations`);
|
|
2871
3208
|
} catch (error) {
|
|
2872
|
-
|
|
3209
|
+
logger4.error("Failed to load event source configurations:", error);
|
|
2873
3210
|
}
|
|
2874
3211
|
}
|
|
2875
3212
|
}
|