@ai-setting/roy-agent-cli 1.7.57 → 1.7.59

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.
@@ -9639,7 +9639,7 @@ class CliQuietModeService {
9639
9639
  // package.json
9640
9640
  var package_default = {
9641
9641
  name: "@ai-setting/roy-agent-cli",
9642
- version: "1.7.57",
9642
+ version: "1.7.59",
9643
9643
  type: "module",
9644
9644
  description: "CLI for roy-agent - Non-interactive command execution",
9645
9645
  main: "./dist/index.js",
@@ -11785,6 +11785,321 @@ import {
11785
11785
  } from "@ai-setting/roy-agent-core/env";
11786
11786
  import { TracedAs as TracedAs5 } from "@ai-setting/roy-agent-core";
11787
11787
  import { notifyReactFailure as notifyReactFailure2 } from "@ai-setting/roy-agent-core/env/error-reply";
11788
+
11789
+ // src/commands/shared/telemetry-notice.ts
11790
+ import { spawn } from "node:child_process";
11791
+ import { normalizeLarkAtMentions } from "@ai-setting/roy-agent-core/env/lark-mention-utils";
11792
+ import { deriveIdempotencyKey } from "@ai-setting/roy-agent-core/env/event-source/idempotency-key";
11793
+ var TELEMETRY_EVENT_TYPES = new Set([
11794
+ "task.background.started",
11795
+ "task.background.progress"
11796
+ ]);
11797
+ function isTelemetryEvent(type) {
11798
+ if (!type)
11799
+ return false;
11800
+ return TELEMETRY_EVENT_TYPES.has(type);
11801
+ }
11802
+ var RULE_NOTICE_EVENT_TYPES = new Set([
11803
+ "task.background.completed",
11804
+ "task.background.timeout"
11805
+ ]);
11806
+ function isRuleNoticeEvent(type) {
11807
+ if (!type)
11808
+ return false;
11809
+ return RULE_NOTICE_EVENT_TYPES.has(type);
11810
+ }
11811
+ var MAX_TITLE_CHARS = 40;
11812
+ function pad2(n) {
11813
+ return n < 10 ? `0${n}` : String(n);
11814
+ }
11815
+ function formatElapsed(ms) {
11816
+ if (!Number.isFinite(ms) || ms <= 0)
11817
+ return "0m";
11818
+ const totalMin = Math.floor(ms / 60000);
11819
+ if (totalMin < 60)
11820
+ return `${totalMin}m`;
11821
+ const totalHour = Math.floor(totalMin / 60);
11822
+ const min = totalMin % 60;
11823
+ if (totalHour < 24) {
11824
+ return min === 0 ? `${totalHour}h` : `${totalHour}h${min}m`;
11825
+ }
11826
+ const day = Math.floor(totalHour / 24);
11827
+ const hour = totalHour % 24;
11828
+ return hour === 0 ? `${day}d` : `${day}d${hour}h`;
11829
+ }
11830
+ function formatClock(ts) {
11831
+ const d = new Date(ts);
11832
+ return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
11833
+ }
11834
+ function formatTimeoutLabel(ms) {
11835
+ if (!Number.isFinite(ms) || ms <= 0)
11836
+ return "0m";
11837
+ return formatElapsed(ms);
11838
+ }
11839
+ function truncateTitle(raw) {
11840
+ const s = raw.trim();
11841
+ if (s.length <= MAX_TITLE_CHARS)
11842
+ return s;
11843
+ return `${s.slice(0, MAX_TITLE_CHARS)}…`;
11844
+ }
11845
+ function pickString(v) {
11846
+ return typeof v === "string" && v.length > 0 ? v : undefined;
11847
+ }
11848
+ function pickNumber(v) {
11849
+ return typeof v === "number" && Number.isFinite(v) ? v : undefined;
11850
+ }
11851
+ function buildTelemetryNoticeText(type, payload, now = Date.now()) {
11852
+ const p = payload ?? {};
11853
+ const taskId = pickNumber(p.associatedTaskId);
11854
+ const bgId = pickString(p.backgroundTaskId);
11855
+ const desc = truncateTitle(pickString(p.description) ?? "后台任务");
11856
+ let label;
11857
+ if (taskId !== undefined)
11858
+ label = `Task #${taskId}`;
11859
+ else if (bgId)
11860
+ label = bgId;
11861
+ else
11862
+ label = "后台任务";
11863
+ const head = type === "task.background.started" ? `\uD83D\uDD14 ${label}「${desc}」已启动` : `\uD83D\uDD04 ${label}「${desc}」后台运行中`;
11864
+ const parts = [];
11865
+ const startedAt = pickNumber(p.startedAt);
11866
+ const timeoutMs = pickNumber(p.timeoutMs);
11867
+ if (type !== "task.background.started" && startedAt !== undefined) {
11868
+ parts.push(`已跑 ${formatElapsed(now - startedAt)}`);
11869
+ }
11870
+ if (startedAt !== undefined && timeoutMs !== undefined) {
11871
+ parts.push(`预计 ${formatClock(startedAt + timeoutMs)} 超时(timeout ${formatTimeoutLabel(timeoutMs)})`);
11872
+ }
11873
+ let text = head;
11874
+ if (parts.length > 0)
11875
+ text += `
11876
+ ${parts.join(",")}`;
11877
+ const progressMessage = pickString(p.progressMessage);
11878
+ if (progressMessage)
11879
+ text += `
11880
+ ${progressMessage}`;
11881
+ return text;
11882
+ }
11883
+ function parseTimeoutMsFromError(error) {
11884
+ if (!error)
11885
+ return;
11886
+ const m = error.match(/timeout after\s+(\d+)\s*ms/i);
11887
+ if (!m)
11888
+ return;
11889
+ const n = Number(m[1]);
11890
+ return Number.isFinite(n) && n > 0 ? n : undefined;
11891
+ }
11892
+ function buildTerminalNoticeText(type, payload) {
11893
+ const p = payload ?? {};
11894
+ const taskId = pickNumber(p.associatedTaskId);
11895
+ const bgId = pickString(p.backgroundTaskId);
11896
+ const desc = truncateTitle(pickString(p.description) ?? "后台任务");
11897
+ let label;
11898
+ if (taskId !== undefined)
11899
+ label = `Task #${taskId}`;
11900
+ else if (bgId)
11901
+ label = bgId;
11902
+ else
11903
+ label = "后台任务";
11904
+ const elapsedMs = pickNumber(p.executionTimeMs);
11905
+ const elapsed = elapsedMs !== undefined ? formatElapsed(elapsedMs) : undefined;
11906
+ if (type === "task.background.timeout") {
11907
+ const timeoutMs = pickNumber(p.timeoutMs) ?? parseTimeoutMsFromError(p.error);
11908
+ const parts = [];
11909
+ if (elapsed)
11910
+ parts.push(`跑了 ${elapsed}`);
11911
+ if (timeoutMs !== undefined)
11912
+ parts.push(`timeout ${formatTimeoutLabel(timeoutMs)}`);
11913
+ const head = `⏱️ ${label}「${desc}」已超时`;
11914
+ return parts.length > 0 ? `${head}(${parts.join(",")})
11915
+ 助手随后补充结论与下一步选项。` : `${head}
11916
+ 助手随后补充结论与下一步选项。`;
11917
+ }
11918
+ if (type === "task.background.completed") {
11919
+ const head = `✅ ${label}「${desc}」已完成`;
11920
+ return elapsed ? `${head}(耗时 ${elapsed})
11921
+ 助手随后补充交付摘要。` : `${head}
11922
+ 助手随后补充交付摘要。`;
11923
+ }
11924
+ const bgStatus = type.replace("task.background.", "");
11925
+ return `ℹ️ ${label}「${desc}」${bgStatus}${elapsed ? `(耗时 ${elapsed})` : ""}`;
11926
+ }
11927
+ var DEFAULT_SEND_TIMEOUT_MS = 5000;
11928
+ var MAX_IDEMPOTENCY_KEY_LEN = 50;
11929
+ function deriveTelemetryIdempotencyKey(eventId, chatId) {
11930
+ return deriveNoticeIdempotencyKey("telemetry", eventId, chatId);
11931
+ }
11932
+ function deriveRuleNoticeIdempotencyKey(eventId, chatId) {
11933
+ return deriveNoticeIdempotencyKey("rule", eventId, chatId);
11934
+ }
11935
+ function deriveNoticeIdempotencyKey(namespace, eventId, chatId) {
11936
+ const anchor = pickString(eventId) ?? `ts-${Date.now()}-${Math.random()}`;
11937
+ return deriveIdempotencyKey([namespace, anchor, chatId]);
11938
+ }
11939
+ function buildLarkSendArgs(input) {
11940
+ const { chatId, text, profile, idempotencyKey } = input;
11941
+ const args = [
11942
+ "im",
11943
+ "+messages-send",
11944
+ "--chat-id",
11945
+ chatId,
11946
+ "--markdown",
11947
+ normalizeLarkAtMentions(text),
11948
+ "--as",
11949
+ "bot"
11950
+ ];
11951
+ if (idempotencyKey) {
11952
+ args.push("--idempotency-key", idempotencyKey.slice(0, MAX_IDEMPOTENCY_KEY_LEN));
11953
+ }
11954
+ if (profile)
11955
+ args.unshift("--profile", profile);
11956
+ return args;
11957
+ }
11958
+ function sendLarkChatMarkdown(options) {
11959
+ const { chatId, text, profile, idempotencyKey } = options;
11960
+ const timeoutMs = options.timeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
11961
+ if (!chatId) {
11962
+ return Promise.reject(new Error("sendLarkChatMarkdown: empty chatId"));
11963
+ }
11964
+ return new Promise((resolve, reject) => {
11965
+ let settled = false;
11966
+ let timer;
11967
+ const finish = (err) => {
11968
+ if (settled)
11969
+ return;
11970
+ settled = true;
11971
+ if (timer)
11972
+ clearTimeout(timer);
11973
+ if (err)
11974
+ reject(err);
11975
+ else
11976
+ resolve();
11977
+ };
11978
+ const args = buildLarkSendArgs({ chatId, text, profile, idempotencyKey });
11979
+ let proc;
11980
+ try {
11981
+ proc = spawn("lark-cli", args, {
11982
+ shell: false,
11983
+ stdio: ["ignore", "pipe", "pipe"]
11984
+ });
11985
+ } catch (err) {
11986
+ finish(err instanceof Error ? err : new Error(String(err)));
11987
+ return;
11988
+ }
11989
+ let stderr = "";
11990
+ proc.stderr?.on("data", (chunk) => {
11991
+ stderr += chunk.toString();
11992
+ });
11993
+ timer = setTimeout(() => {
11994
+ try {
11995
+ proc.kill("SIGKILL");
11996
+ } catch {}
11997
+ finish(new Error(`lark-cli timed out after ${timeoutMs}ms`));
11998
+ }, timeoutMs);
11999
+ timer.unref?.();
12000
+ proc.on("close", (code) => {
12001
+ if (code === 0)
12002
+ finish();
12003
+ else
12004
+ finish(new Error(`lark-cli exited with code ${code}: ${stderr}`));
12005
+ });
12006
+ proc.on("error", (err) => finish(err));
12007
+ });
12008
+ }
12009
+ function targetFromEventMetadata(metadata) {
12010
+ if (!metadata)
12011
+ return;
12012
+ const replyChannel = metadata.replyChannel;
12013
+ const chatId = pickString(replyChannel?.chatId) ?? pickString(metadata.chatId);
12014
+ if (!chatId)
12015
+ return;
12016
+ const profile = pickString(replyChannel?.profile) ?? pickString(metadata.profile);
12017
+ return profile ? { chatId, profile } : { chatId };
12018
+ }
12019
+ async function targetFromTriggerEvent(eventStore, triggerEventId) {
12020
+ if (!eventStore || !triggerEventId)
12021
+ return;
12022
+ let persisted;
12023
+ try {
12024
+ persisted = await eventStore.getEventById(triggerEventId);
12025
+ } catch {
12026
+ return;
12027
+ }
12028
+ if (!persisted || typeof persisted !== "object")
12029
+ return;
12030
+ const metadata = persisted.metadata;
12031
+ if (!metadata || typeof metadata !== "object")
12032
+ return;
12033
+ return targetFromEventMetadata(metadata);
12034
+ }
12035
+
12036
+ // src/commands/shared/self-echo-filter.ts
12037
+ var BOT_SENDER_TYPES = new Set(["bot", "app"]);
12038
+ function pickString2(v) {
12039
+ return typeof v === "string" && v.length > 0 ? v : undefined;
12040
+ }
12041
+ function extractSenderIdentity(event) {
12042
+ if (!event)
12043
+ return {};
12044
+ const metadata = event.metadata;
12045
+ const payload = event.payload;
12046
+ const payloadMeta = payload?.metadata;
12047
+ const rawEvent = payload?.rawEvent;
12048
+ const innerEvent = rawEvent?.event;
12049
+ const innerSender = innerEvent?.sender;
12050
+ const topSender = rawEvent?.sender;
12051
+ const senderType = pickString2(metadata?.senderType) ?? pickString2(payloadMeta?.senderType) ?? pickString2(rawEvent?.sender_type) ?? pickString2(innerSender?.sender_type) ?? pickString2(topSender?.sender_type) ?? pickString2(payload?.senderType);
12052
+ const nestedSenderId = innerSender?.sender_id ?? topSender?.sender_id;
12053
+ const senderId = pickString2(metadata?.senderId) ?? pickString2(payloadMeta?.senderId) ?? pickString2(payload?.senderId) ?? pickString2(rawEvent?.sender_id) ?? (typeof nestedSenderId === "string" ? pickString2(nestedSenderId) : pickString2(nestedSenderId?.open_id) ?? pickString2(nestedSenderId?.user_id) ?? pickString2(nestedSenderId?.union_id));
12054
+ return {
12055
+ ...senderType ? { senderType } : {},
12056
+ ...senderId ? { senderId } : {}
12057
+ };
12058
+ }
12059
+ function isSelfEchoEvent(event, options = {}) {
12060
+ const { senderType, senderId } = extractSenderIdentity(event);
12061
+ if (options.enabled === false) {
12062
+ return {
12063
+ skip: false,
12064
+ reason: "disabled",
12065
+ ...senderType ? { senderType } : {},
12066
+ ...senderId ? { senderId } : {}
12067
+ };
12068
+ }
12069
+ if (senderType && BOT_SENDER_TYPES.has(senderType.toLowerCase())) {
12070
+ return {
12071
+ skip: true,
12072
+ reason: "bot-sender",
12073
+ ...senderType ? { senderType } : {},
12074
+ ...senderId ? { senderId } : {}
12075
+ };
12076
+ }
12077
+ if (senderId && options.selfBotIds && options.selfBotIds.length > 0) {
12078
+ if (options.selfBotIds.includes(senderId)) {
12079
+ return {
12080
+ skip: true,
12081
+ reason: "self-bot-id",
12082
+ ...senderType ? { senderType } : {},
12083
+ senderId
12084
+ };
12085
+ }
12086
+ }
12087
+ return {
12088
+ skip: false,
12089
+ ...senderType ? { senderType } : {},
12090
+ ...senderId ? { senderId } : {}
12091
+ };
12092
+ }
12093
+ var SELF_ECHO_FILTER_ENABLED_ENV = "ROY_AGENT_SELF_ECHO_FILTER";
12094
+ function readSelfEchoFilterEnabled(env = process.env) {
12095
+ const raw = env[SELF_ECHO_FILTER_ENABLED_ENV];
12096
+ if (raw === undefined)
12097
+ return true;
12098
+ const v = raw.trim().toLowerCase();
12099
+ return !(v === "0" || v === "false" || v === "off" || v === "no");
12100
+ }
12101
+
12102
+ // src/commands/shared/event-handler.ts
11788
12103
  function parseLarkPerTaskChatId(contextJson) {
11789
12104
  if (!contextJson)
11790
12105
  return;
@@ -11837,6 +12152,15 @@ class EventHandler {
11837
12152
  resolvedSessionByTrigger = new Map;
11838
12153
  eventStore = null;
11839
12154
  getHandlerForEsType = null;
12155
+ telemetrySender = (notice) => sendLarkChatMarkdown(notice);
12156
+ selfEchoFilter = {
12157
+ enabled: true,
12158
+ selfBotIds: []
12159
+ };
12160
+ selfEchoDroppedCount = 0;
12161
+ getSelfEchoDroppedCount() {
12162
+ return this.selfEchoDroppedCount;
12163
+ }
11840
12164
  constructor(options) {
11841
12165
  this.env = options.env;
11842
12166
  this.eventTypes = options.eventTypes;
@@ -11851,6 +12175,11 @@ class EventHandler {
11851
12175
  this.sessionComponent = options.sessionComponent ?? null;
11852
12176
  this.eventStore = options.eventStore ?? null;
11853
12177
  this.getHandlerForEsType = options.getHandlerForEsType ?? null;
12178
+ this.telemetrySender = options.telemetrySender ?? ((notice) => sendLarkChatMarkdown(notice));
12179
+ this.selfEchoFilter = {
12180
+ enabled: options.selfEchoFilter?.enabled ?? readSelfEchoFilterEnabled(),
12181
+ selfBotIds: options.selfEchoFilter?.selfBotIds ?? []
12182
+ };
11854
12183
  }
11855
12184
  start() {
11856
12185
  this.isStopped = false;
@@ -11897,13 +12226,82 @@ class EventHandler {
11897
12226
  if (this.isStopped) {
11898
12227
  return;
11899
12228
  }
11900
- const formatted = await this.formatEvent(event);
12229
+ if (this.selfEchoFilter.enabled) {
12230
+ const verdict = isSelfEchoEvent(event, {
12231
+ selfBotIds: this.selfEchoFilter.selfBotIds
12232
+ });
12233
+ if (verdict.skip) {
12234
+ this.selfEchoDroppedCount += 1;
12235
+ console.error(`[EventHandler] self-echo event dropped (reason=${verdict.reason}` + `, senderType=${verdict.senderType ?? "-"}` + `, senderId=${verdict.senderId ?? "-"}` + `, type=${event.type})`);
12236
+ return;
12237
+ }
12238
+ }
12239
+ if (isTelemetryEvent(event.type)) {
12240
+ this.sendTelemetryNotice(event);
12241
+ return;
12242
+ }
12243
+ const ruleNotice = isRuleNoticeEvent(event.type) ? await this.sendRuleNotice(event) : undefined;
12244
+ const formatted = await this.formatEvent(event, { ruleNotice });
11901
12245
  this.enqueue(formatted);
11902
12246
  }
11903
- async formatEvent(event) {
12247
+ async resolveNoticeTarget(event) {
12248
+ const metadata = event.metadata;
12249
+ const target = targetFromEventMetadata(metadata);
12250
+ if (target)
12251
+ return target;
12252
+ const triggerEventId = typeof metadata?.triggerEventId === "string" ? metadata.triggerEventId : undefined;
12253
+ return targetFromTriggerEvent(this.eventStore, triggerEventId);
12254
+ }
12255
+ async sendRuleNotice(event) {
12256
+ try {
12257
+ const target = await this.resolveNoticeTarget(event);
12258
+ if (!target) {
12259
+ return { attempted: true, delivered: false, error: "no-target" };
12260
+ }
12261
+ const text = buildTerminalNoticeText(event.type, event.payload);
12262
+ await this.telemetrySender({
12263
+ chatId: target.chatId,
12264
+ ...target.profile ? { profile: target.profile } : {},
12265
+ text,
12266
+ idempotencyKey: deriveRuleNoticeIdempotencyKey(event.id, target.chatId)
12267
+ });
12268
+ return {
12269
+ attempted: true,
12270
+ delivered: true,
12271
+ chatId: target.chatId,
12272
+ text,
12273
+ sentAt: Date.now()
12274
+ };
12275
+ } catch (err) {
12276
+ console.error(`[EventHandler] rule notice failed (swallowed) type=${event.type}`, err);
12277
+ return {
12278
+ attempted: true,
12279
+ delivered: false,
12280
+ error: err instanceof Error ? err.message : String(err)
12281
+ };
12282
+ }
12283
+ }
12284
+ async sendTelemetryNotice(event) {
12285
+ try {
12286
+ const target = await this.resolveNoticeTarget(event);
12287
+ if (!target) {
12288
+ return;
12289
+ }
12290
+ const text = buildTelemetryNoticeText(event.type, event.payload);
12291
+ await this.telemetrySender({
12292
+ chatId: target.chatId,
12293
+ ...target.profile ? { profile: target.profile } : {},
12294
+ text,
12295
+ idempotencyKey: deriveTelemetryIdempotencyKey(event.id, target.chatId)
12296
+ });
12297
+ } catch (err) {
12298
+ console.error(`[EventHandler] telemetry notice failed (swallowed) type=${event.type}`, err);
12299
+ }
12300
+ }
12301
+ async formatEvent(event, opts = {}) {
11904
12302
  if (NOTIFY_V2_TERMINAL_TYPES.has(event.type) && event.metadata?.triggerEventId && this.eventStore && this.getHandlerForEsType) {
11905
12303
  try {
11906
- const v2Formatted = await this.formatEventViaESPluginV2(event);
12304
+ const v2Formatted = await this.formatEventViaESPluginV2(event, opts.ruleNotice);
11907
12305
  if (v2Formatted) {
11908
12306
  return v2Formatted;
11909
12307
  }
@@ -11913,7 +12311,26 @@ class EventHandler {
11913
12311
  }
11914
12312
  return this.formatter.formatWithEvent(event);
11915
12313
  }
11916
- async formatEventViaESPluginV2(event) {
12314
+ buildNotifyChannelInfo(triggerEvent, handler, profile) {
12315
+ const meta = triggerEvent.metadata ?? {};
12316
+ const ctx = handler.extractReplyContext?.(triggerEvent, profile);
12317
+ const chatId = ctx?.chatId || meta.chatId || undefined;
12318
+ const messageId = ctx?.messageId || meta.messageId || undefined;
12319
+ const senderId = ctx?.senderOpenId || meta.senderId || undefined;
12320
+ const resolvedProfile = ctx?.profile ?? profile ?? meta.profile;
12321
+ const rawChatType = meta.chatType;
12322
+ const chatType = rawChatType === "group" || rawChatType === "p2p" ? rawChatType : "unknown";
12323
+ return {
12324
+ esType: triggerEvent.esType ?? handler.type,
12325
+ ...chatId ? { chatId } : {},
12326
+ chatType,
12327
+ ...messageId ? { messageId } : {},
12328
+ ...senderId ? { senderId } : {},
12329
+ ...resolvedProfile ? { profile: resolvedProfile } : {},
12330
+ replyKind: chatId ? messageId ? "reply" : "send" : "none"
12331
+ };
12332
+ }
12333
+ async formatEventViaESPluginV2(event, ruleNotice) {
11917
12334
  const triggerEventId = event.metadata.triggerEventId;
11918
12335
  const triggerEvent = await this.eventStore.getEventById(triggerEventId);
11919
12336
  if (!triggerEvent) {
@@ -11928,17 +12345,21 @@ class EventHandler {
11928
12345
  summary: typeof payload?.result === "string" ? payload.result : typeof payload?.error === "string" ? payload.error : "(无结果)"
11929
12346
  };
11930
12347
  const profile = triggerEvent.metadata?.profile ?? undefined;
12348
+ const channel = this.buildNotifyChannelInfo(triggerEvent, handler, profile);
11931
12349
  const prompt = handler.buildNotifyHandlePrompt({
11932
12350
  notifyEvent: {
11933
12351
  type: event.type,
11934
12352
  taskId: typeof payload?.associatedTaskId === "number" ? payload.associatedTaskId : undefined,
11935
12353
  description: typeof payload?.description === "string" ? payload.description : undefined,
11936
12354
  result: typeof payload?.result === "string" ? payload.result : undefined,
11937
- error: typeof payload?.error === "string" ? payload.error : undefined
12355
+ error: typeof payload?.error === "string" ? payload.error : undefined,
12356
+ subSessionId: typeof payload?.subSessionId === "string" ? payload.subSessionId : undefined
11938
12357
  },
11939
12358
  triggerEvent,
11940
12359
  subAgentResult,
11941
- profile
12360
+ profile,
12361
+ channel,
12362
+ ...ruleNotice ? { ruleNotice } : {}
11942
12363
  });
11943
12364
  if (handler.postProcessNotifyEvent) {
11944
12365
  const notifyEventForHook = {
@@ -12388,18 +12809,36 @@ __legacyDecorateClassTS([
12388
12809
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12389
12810
  ], EventHandler.prototype, "handleEvent", null);
12390
12811
  __legacyDecorateClassTS([
12391
- TracedAs5("cli.event-handler.formatEvent", { recordParams: true, recordResult: false }),
12812
+ TracedAs5("event_handler.rule_notice", { recordParams: true, recordResult: false }),
12392
12813
  __legacyMetadataTS("design:type", Function),
12393
12814
  __legacyMetadataTS("design:paramtypes", [
12394
12815
  typeof EnvEvent === "undefined" ? Object : EnvEvent
12395
12816
  ]),
12396
12817
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12818
+ ], EventHandler.prototype, "sendRuleNotice", null);
12819
+ __legacyDecorateClassTS([
12820
+ TracedAs5("event_handler.telemetry_notice", { recordParams: true, recordResult: false }),
12821
+ __legacyMetadataTS("design:type", Function),
12822
+ __legacyMetadataTS("design:paramtypes", [
12823
+ typeof EnvEvent === "undefined" ? Object : EnvEvent
12824
+ ]),
12825
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12826
+ ], EventHandler.prototype, "sendTelemetryNotice", null);
12827
+ __legacyDecorateClassTS([
12828
+ TracedAs5("cli.event-handler.formatEvent", { recordParams: true, recordResult: false }),
12829
+ __legacyMetadataTS("design:type", Function),
12830
+ __legacyMetadataTS("design:paramtypes", [
12831
+ typeof EnvEvent === "undefined" ? Object : EnvEvent,
12832
+ Object
12833
+ ]),
12834
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12397
12835
  ], EventHandler.prototype, "formatEvent", null);
12398
12836
  __legacyDecorateClassTS([
12399
12837
  TracedAs5("event_handler.process_notify", { recordParams: true, recordResult: false }),
12400
12838
  __legacyMetadataTS("design:type", Function),
12401
12839
  __legacyMetadataTS("design:paramtypes", [
12402
- typeof EnvEvent === "undefined" ? Object : EnvEvent
12840
+ typeof EnvEvent === "undefined" ? Object : EnvEvent,
12841
+ typeof RuleNoticeInfo === "undefined" ? Object : RuleNoticeInfo
12403
12842
  ]),
12404
12843
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12405
12844
  ], EventHandler.prototype, "formatEventViaESPluginV2", null);
package/dist/index.js CHANGED
@@ -9638,7 +9638,7 @@ class CliQuietModeService {
9638
9638
  // package.json
9639
9639
  var package_default = {
9640
9640
  name: "@ai-setting/roy-agent-cli",
9641
- version: "1.7.57",
9641
+ version: "1.7.59",
9642
9642
  type: "module",
9643
9643
  description: "CLI for roy-agent - Non-interactive command execution",
9644
9644
  main: "./dist/index.js",
@@ -11784,6 +11784,321 @@ import {
11784
11784
  } from "@ai-setting/roy-agent-core/env";
11785
11785
  import { TracedAs as TracedAs5 } from "@ai-setting/roy-agent-core";
11786
11786
  import { notifyReactFailure as notifyReactFailure2 } from "@ai-setting/roy-agent-core/env/error-reply";
11787
+
11788
+ // src/commands/shared/telemetry-notice.ts
11789
+ import { spawn } from "node:child_process";
11790
+ import { normalizeLarkAtMentions } from "@ai-setting/roy-agent-core/env/lark-mention-utils";
11791
+ import { deriveIdempotencyKey } from "@ai-setting/roy-agent-core/env/event-source/idempotency-key";
11792
+ var TELEMETRY_EVENT_TYPES = new Set([
11793
+ "task.background.started",
11794
+ "task.background.progress"
11795
+ ]);
11796
+ function isTelemetryEvent(type) {
11797
+ if (!type)
11798
+ return false;
11799
+ return TELEMETRY_EVENT_TYPES.has(type);
11800
+ }
11801
+ var RULE_NOTICE_EVENT_TYPES = new Set([
11802
+ "task.background.completed",
11803
+ "task.background.timeout"
11804
+ ]);
11805
+ function isRuleNoticeEvent(type) {
11806
+ if (!type)
11807
+ return false;
11808
+ return RULE_NOTICE_EVENT_TYPES.has(type);
11809
+ }
11810
+ var MAX_TITLE_CHARS = 40;
11811
+ function pad2(n) {
11812
+ return n < 10 ? `0${n}` : String(n);
11813
+ }
11814
+ function formatElapsed(ms) {
11815
+ if (!Number.isFinite(ms) || ms <= 0)
11816
+ return "0m";
11817
+ const totalMin = Math.floor(ms / 60000);
11818
+ if (totalMin < 60)
11819
+ return `${totalMin}m`;
11820
+ const totalHour = Math.floor(totalMin / 60);
11821
+ const min = totalMin % 60;
11822
+ if (totalHour < 24) {
11823
+ return min === 0 ? `${totalHour}h` : `${totalHour}h${min}m`;
11824
+ }
11825
+ const day = Math.floor(totalHour / 24);
11826
+ const hour = totalHour % 24;
11827
+ return hour === 0 ? `${day}d` : `${day}d${hour}h`;
11828
+ }
11829
+ function formatClock(ts) {
11830
+ const d = new Date(ts);
11831
+ return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
11832
+ }
11833
+ function formatTimeoutLabel(ms) {
11834
+ if (!Number.isFinite(ms) || ms <= 0)
11835
+ return "0m";
11836
+ return formatElapsed(ms);
11837
+ }
11838
+ function truncateTitle(raw) {
11839
+ const s = raw.trim();
11840
+ if (s.length <= MAX_TITLE_CHARS)
11841
+ return s;
11842
+ return `${s.slice(0, MAX_TITLE_CHARS)}…`;
11843
+ }
11844
+ function pickString(v) {
11845
+ return typeof v === "string" && v.length > 0 ? v : undefined;
11846
+ }
11847
+ function pickNumber(v) {
11848
+ return typeof v === "number" && Number.isFinite(v) ? v : undefined;
11849
+ }
11850
+ function buildTelemetryNoticeText(type, payload, now = Date.now()) {
11851
+ const p = payload ?? {};
11852
+ const taskId = pickNumber(p.associatedTaskId);
11853
+ const bgId = pickString(p.backgroundTaskId);
11854
+ const desc = truncateTitle(pickString(p.description) ?? "后台任务");
11855
+ let label;
11856
+ if (taskId !== undefined)
11857
+ label = `Task #${taskId}`;
11858
+ else if (bgId)
11859
+ label = bgId;
11860
+ else
11861
+ label = "后台任务";
11862
+ const head = type === "task.background.started" ? `\uD83D\uDD14 ${label}「${desc}」已启动` : `\uD83D\uDD04 ${label}「${desc}」后台运行中`;
11863
+ const parts = [];
11864
+ const startedAt = pickNumber(p.startedAt);
11865
+ const timeoutMs = pickNumber(p.timeoutMs);
11866
+ if (type !== "task.background.started" && startedAt !== undefined) {
11867
+ parts.push(`已跑 ${formatElapsed(now - startedAt)}`);
11868
+ }
11869
+ if (startedAt !== undefined && timeoutMs !== undefined) {
11870
+ parts.push(`预计 ${formatClock(startedAt + timeoutMs)} 超时(timeout ${formatTimeoutLabel(timeoutMs)})`);
11871
+ }
11872
+ let text = head;
11873
+ if (parts.length > 0)
11874
+ text += `
11875
+ ${parts.join(",")}`;
11876
+ const progressMessage = pickString(p.progressMessage);
11877
+ if (progressMessage)
11878
+ text += `
11879
+ ${progressMessage}`;
11880
+ return text;
11881
+ }
11882
+ function parseTimeoutMsFromError(error) {
11883
+ if (!error)
11884
+ return;
11885
+ const m = error.match(/timeout after\s+(\d+)\s*ms/i);
11886
+ if (!m)
11887
+ return;
11888
+ const n = Number(m[1]);
11889
+ return Number.isFinite(n) && n > 0 ? n : undefined;
11890
+ }
11891
+ function buildTerminalNoticeText(type, payload) {
11892
+ const p = payload ?? {};
11893
+ const taskId = pickNumber(p.associatedTaskId);
11894
+ const bgId = pickString(p.backgroundTaskId);
11895
+ const desc = truncateTitle(pickString(p.description) ?? "后台任务");
11896
+ let label;
11897
+ if (taskId !== undefined)
11898
+ label = `Task #${taskId}`;
11899
+ else if (bgId)
11900
+ label = bgId;
11901
+ else
11902
+ label = "后台任务";
11903
+ const elapsedMs = pickNumber(p.executionTimeMs);
11904
+ const elapsed = elapsedMs !== undefined ? formatElapsed(elapsedMs) : undefined;
11905
+ if (type === "task.background.timeout") {
11906
+ const timeoutMs = pickNumber(p.timeoutMs) ?? parseTimeoutMsFromError(p.error);
11907
+ const parts = [];
11908
+ if (elapsed)
11909
+ parts.push(`跑了 ${elapsed}`);
11910
+ if (timeoutMs !== undefined)
11911
+ parts.push(`timeout ${formatTimeoutLabel(timeoutMs)}`);
11912
+ const head = `⏱️ ${label}「${desc}」已超时`;
11913
+ return parts.length > 0 ? `${head}(${parts.join(",")})
11914
+ 助手随后补充结论与下一步选项。` : `${head}
11915
+ 助手随后补充结论与下一步选项。`;
11916
+ }
11917
+ if (type === "task.background.completed") {
11918
+ const head = `✅ ${label}「${desc}」已完成`;
11919
+ return elapsed ? `${head}(耗时 ${elapsed})
11920
+ 助手随后补充交付摘要。` : `${head}
11921
+ 助手随后补充交付摘要。`;
11922
+ }
11923
+ const bgStatus = type.replace("task.background.", "");
11924
+ return `ℹ️ ${label}「${desc}」${bgStatus}${elapsed ? `(耗时 ${elapsed})` : ""}`;
11925
+ }
11926
+ var DEFAULT_SEND_TIMEOUT_MS = 5000;
11927
+ var MAX_IDEMPOTENCY_KEY_LEN = 50;
11928
+ function deriveTelemetryIdempotencyKey(eventId, chatId) {
11929
+ return deriveNoticeIdempotencyKey("telemetry", eventId, chatId);
11930
+ }
11931
+ function deriveRuleNoticeIdempotencyKey(eventId, chatId) {
11932
+ return deriveNoticeIdempotencyKey("rule", eventId, chatId);
11933
+ }
11934
+ function deriveNoticeIdempotencyKey(namespace, eventId, chatId) {
11935
+ const anchor = pickString(eventId) ?? `ts-${Date.now()}-${Math.random()}`;
11936
+ return deriveIdempotencyKey([namespace, anchor, chatId]);
11937
+ }
11938
+ function buildLarkSendArgs(input) {
11939
+ const { chatId, text, profile, idempotencyKey } = input;
11940
+ const args = [
11941
+ "im",
11942
+ "+messages-send",
11943
+ "--chat-id",
11944
+ chatId,
11945
+ "--markdown",
11946
+ normalizeLarkAtMentions(text),
11947
+ "--as",
11948
+ "bot"
11949
+ ];
11950
+ if (idempotencyKey) {
11951
+ args.push("--idempotency-key", idempotencyKey.slice(0, MAX_IDEMPOTENCY_KEY_LEN));
11952
+ }
11953
+ if (profile)
11954
+ args.unshift("--profile", profile);
11955
+ return args;
11956
+ }
11957
+ function sendLarkChatMarkdown(options) {
11958
+ const { chatId, text, profile, idempotencyKey } = options;
11959
+ const timeoutMs = options.timeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
11960
+ if (!chatId) {
11961
+ return Promise.reject(new Error("sendLarkChatMarkdown: empty chatId"));
11962
+ }
11963
+ return new Promise((resolve, reject) => {
11964
+ let settled = false;
11965
+ let timer;
11966
+ const finish = (err) => {
11967
+ if (settled)
11968
+ return;
11969
+ settled = true;
11970
+ if (timer)
11971
+ clearTimeout(timer);
11972
+ if (err)
11973
+ reject(err);
11974
+ else
11975
+ resolve();
11976
+ };
11977
+ const args = buildLarkSendArgs({ chatId, text, profile, idempotencyKey });
11978
+ let proc;
11979
+ try {
11980
+ proc = spawn("lark-cli", args, {
11981
+ shell: false,
11982
+ stdio: ["ignore", "pipe", "pipe"]
11983
+ });
11984
+ } catch (err) {
11985
+ finish(err instanceof Error ? err : new Error(String(err)));
11986
+ return;
11987
+ }
11988
+ let stderr = "";
11989
+ proc.stderr?.on("data", (chunk) => {
11990
+ stderr += chunk.toString();
11991
+ });
11992
+ timer = setTimeout(() => {
11993
+ try {
11994
+ proc.kill("SIGKILL");
11995
+ } catch {}
11996
+ finish(new Error(`lark-cli timed out after ${timeoutMs}ms`));
11997
+ }, timeoutMs);
11998
+ timer.unref?.();
11999
+ proc.on("close", (code) => {
12000
+ if (code === 0)
12001
+ finish();
12002
+ else
12003
+ finish(new Error(`lark-cli exited with code ${code}: ${stderr}`));
12004
+ });
12005
+ proc.on("error", (err) => finish(err));
12006
+ });
12007
+ }
12008
+ function targetFromEventMetadata(metadata) {
12009
+ if (!metadata)
12010
+ return;
12011
+ const replyChannel = metadata.replyChannel;
12012
+ const chatId = pickString(replyChannel?.chatId) ?? pickString(metadata.chatId);
12013
+ if (!chatId)
12014
+ return;
12015
+ const profile = pickString(replyChannel?.profile) ?? pickString(metadata.profile);
12016
+ return profile ? { chatId, profile } : { chatId };
12017
+ }
12018
+ async function targetFromTriggerEvent(eventStore, triggerEventId) {
12019
+ if (!eventStore || !triggerEventId)
12020
+ return;
12021
+ let persisted;
12022
+ try {
12023
+ persisted = await eventStore.getEventById(triggerEventId);
12024
+ } catch {
12025
+ return;
12026
+ }
12027
+ if (!persisted || typeof persisted !== "object")
12028
+ return;
12029
+ const metadata = persisted.metadata;
12030
+ if (!metadata || typeof metadata !== "object")
12031
+ return;
12032
+ return targetFromEventMetadata(metadata);
12033
+ }
12034
+
12035
+ // src/commands/shared/self-echo-filter.ts
12036
+ var BOT_SENDER_TYPES = new Set(["bot", "app"]);
12037
+ function pickString2(v) {
12038
+ return typeof v === "string" && v.length > 0 ? v : undefined;
12039
+ }
12040
+ function extractSenderIdentity(event) {
12041
+ if (!event)
12042
+ return {};
12043
+ const metadata = event.metadata;
12044
+ const payload = event.payload;
12045
+ const payloadMeta = payload?.metadata;
12046
+ const rawEvent = payload?.rawEvent;
12047
+ const innerEvent = rawEvent?.event;
12048
+ const innerSender = innerEvent?.sender;
12049
+ const topSender = rawEvent?.sender;
12050
+ const senderType = pickString2(metadata?.senderType) ?? pickString2(payloadMeta?.senderType) ?? pickString2(rawEvent?.sender_type) ?? pickString2(innerSender?.sender_type) ?? pickString2(topSender?.sender_type) ?? pickString2(payload?.senderType);
12051
+ const nestedSenderId = innerSender?.sender_id ?? topSender?.sender_id;
12052
+ const senderId = pickString2(metadata?.senderId) ?? pickString2(payloadMeta?.senderId) ?? pickString2(payload?.senderId) ?? pickString2(rawEvent?.sender_id) ?? (typeof nestedSenderId === "string" ? pickString2(nestedSenderId) : pickString2(nestedSenderId?.open_id) ?? pickString2(nestedSenderId?.user_id) ?? pickString2(nestedSenderId?.union_id));
12053
+ return {
12054
+ ...senderType ? { senderType } : {},
12055
+ ...senderId ? { senderId } : {}
12056
+ };
12057
+ }
12058
+ function isSelfEchoEvent(event, options = {}) {
12059
+ const { senderType, senderId } = extractSenderIdentity(event);
12060
+ if (options.enabled === false) {
12061
+ return {
12062
+ skip: false,
12063
+ reason: "disabled",
12064
+ ...senderType ? { senderType } : {},
12065
+ ...senderId ? { senderId } : {}
12066
+ };
12067
+ }
12068
+ if (senderType && BOT_SENDER_TYPES.has(senderType.toLowerCase())) {
12069
+ return {
12070
+ skip: true,
12071
+ reason: "bot-sender",
12072
+ ...senderType ? { senderType } : {},
12073
+ ...senderId ? { senderId } : {}
12074
+ };
12075
+ }
12076
+ if (senderId && options.selfBotIds && options.selfBotIds.length > 0) {
12077
+ if (options.selfBotIds.includes(senderId)) {
12078
+ return {
12079
+ skip: true,
12080
+ reason: "self-bot-id",
12081
+ ...senderType ? { senderType } : {},
12082
+ senderId
12083
+ };
12084
+ }
12085
+ }
12086
+ return {
12087
+ skip: false,
12088
+ ...senderType ? { senderType } : {},
12089
+ ...senderId ? { senderId } : {}
12090
+ };
12091
+ }
12092
+ var SELF_ECHO_FILTER_ENABLED_ENV = "ROY_AGENT_SELF_ECHO_FILTER";
12093
+ function readSelfEchoFilterEnabled(env = process.env) {
12094
+ const raw = env[SELF_ECHO_FILTER_ENABLED_ENV];
12095
+ if (raw === undefined)
12096
+ return true;
12097
+ const v = raw.trim().toLowerCase();
12098
+ return !(v === "0" || v === "false" || v === "off" || v === "no");
12099
+ }
12100
+
12101
+ // src/commands/shared/event-handler.ts
11787
12102
  function parseLarkPerTaskChatId(contextJson) {
11788
12103
  if (!contextJson)
11789
12104
  return;
@@ -11836,6 +12151,15 @@ class EventHandler {
11836
12151
  resolvedSessionByTrigger = new Map;
11837
12152
  eventStore = null;
11838
12153
  getHandlerForEsType = null;
12154
+ telemetrySender = (notice) => sendLarkChatMarkdown(notice);
12155
+ selfEchoFilter = {
12156
+ enabled: true,
12157
+ selfBotIds: []
12158
+ };
12159
+ selfEchoDroppedCount = 0;
12160
+ getSelfEchoDroppedCount() {
12161
+ return this.selfEchoDroppedCount;
12162
+ }
11839
12163
  constructor(options) {
11840
12164
  this.env = options.env;
11841
12165
  this.eventTypes = options.eventTypes;
@@ -11850,6 +12174,11 @@ class EventHandler {
11850
12174
  this.sessionComponent = options.sessionComponent ?? null;
11851
12175
  this.eventStore = options.eventStore ?? null;
11852
12176
  this.getHandlerForEsType = options.getHandlerForEsType ?? null;
12177
+ this.telemetrySender = options.telemetrySender ?? ((notice) => sendLarkChatMarkdown(notice));
12178
+ this.selfEchoFilter = {
12179
+ enabled: options.selfEchoFilter?.enabled ?? readSelfEchoFilterEnabled(),
12180
+ selfBotIds: options.selfEchoFilter?.selfBotIds ?? []
12181
+ };
11853
12182
  }
11854
12183
  start() {
11855
12184
  this.isStopped = false;
@@ -11896,13 +12225,82 @@ class EventHandler {
11896
12225
  if (this.isStopped) {
11897
12226
  return;
11898
12227
  }
11899
- const formatted = await this.formatEvent(event);
12228
+ if (this.selfEchoFilter.enabled) {
12229
+ const verdict = isSelfEchoEvent(event, {
12230
+ selfBotIds: this.selfEchoFilter.selfBotIds
12231
+ });
12232
+ if (verdict.skip) {
12233
+ this.selfEchoDroppedCount += 1;
12234
+ console.error(`[EventHandler] self-echo event dropped (reason=${verdict.reason}` + `, senderType=${verdict.senderType ?? "-"}` + `, senderId=${verdict.senderId ?? "-"}` + `, type=${event.type})`);
12235
+ return;
12236
+ }
12237
+ }
12238
+ if (isTelemetryEvent(event.type)) {
12239
+ this.sendTelemetryNotice(event);
12240
+ return;
12241
+ }
12242
+ const ruleNotice = isRuleNoticeEvent(event.type) ? await this.sendRuleNotice(event) : undefined;
12243
+ const formatted = await this.formatEvent(event, { ruleNotice });
11900
12244
  this.enqueue(formatted);
11901
12245
  }
11902
- async formatEvent(event) {
12246
+ async resolveNoticeTarget(event) {
12247
+ const metadata = event.metadata;
12248
+ const target = targetFromEventMetadata(metadata);
12249
+ if (target)
12250
+ return target;
12251
+ const triggerEventId = typeof metadata?.triggerEventId === "string" ? metadata.triggerEventId : undefined;
12252
+ return targetFromTriggerEvent(this.eventStore, triggerEventId);
12253
+ }
12254
+ async sendRuleNotice(event) {
12255
+ try {
12256
+ const target = await this.resolveNoticeTarget(event);
12257
+ if (!target) {
12258
+ return { attempted: true, delivered: false, error: "no-target" };
12259
+ }
12260
+ const text = buildTerminalNoticeText(event.type, event.payload);
12261
+ await this.telemetrySender({
12262
+ chatId: target.chatId,
12263
+ ...target.profile ? { profile: target.profile } : {},
12264
+ text,
12265
+ idempotencyKey: deriveRuleNoticeIdempotencyKey(event.id, target.chatId)
12266
+ });
12267
+ return {
12268
+ attempted: true,
12269
+ delivered: true,
12270
+ chatId: target.chatId,
12271
+ text,
12272
+ sentAt: Date.now()
12273
+ };
12274
+ } catch (err) {
12275
+ console.error(`[EventHandler] rule notice failed (swallowed) type=${event.type}`, err);
12276
+ return {
12277
+ attempted: true,
12278
+ delivered: false,
12279
+ error: err instanceof Error ? err.message : String(err)
12280
+ };
12281
+ }
12282
+ }
12283
+ async sendTelemetryNotice(event) {
12284
+ try {
12285
+ const target = await this.resolveNoticeTarget(event);
12286
+ if (!target) {
12287
+ return;
12288
+ }
12289
+ const text = buildTelemetryNoticeText(event.type, event.payload);
12290
+ await this.telemetrySender({
12291
+ chatId: target.chatId,
12292
+ ...target.profile ? { profile: target.profile } : {},
12293
+ text,
12294
+ idempotencyKey: deriveTelemetryIdempotencyKey(event.id, target.chatId)
12295
+ });
12296
+ } catch (err) {
12297
+ console.error(`[EventHandler] telemetry notice failed (swallowed) type=${event.type}`, err);
12298
+ }
12299
+ }
12300
+ async formatEvent(event, opts = {}) {
11903
12301
  if (NOTIFY_V2_TERMINAL_TYPES.has(event.type) && event.metadata?.triggerEventId && this.eventStore && this.getHandlerForEsType) {
11904
12302
  try {
11905
- const v2Formatted = await this.formatEventViaESPluginV2(event);
12303
+ const v2Formatted = await this.formatEventViaESPluginV2(event, opts.ruleNotice);
11906
12304
  if (v2Formatted) {
11907
12305
  return v2Formatted;
11908
12306
  }
@@ -11912,7 +12310,26 @@ class EventHandler {
11912
12310
  }
11913
12311
  return this.formatter.formatWithEvent(event);
11914
12312
  }
11915
- async formatEventViaESPluginV2(event) {
12313
+ buildNotifyChannelInfo(triggerEvent, handler, profile) {
12314
+ const meta = triggerEvent.metadata ?? {};
12315
+ const ctx = handler.extractReplyContext?.(triggerEvent, profile);
12316
+ const chatId = ctx?.chatId || meta.chatId || undefined;
12317
+ const messageId = ctx?.messageId || meta.messageId || undefined;
12318
+ const senderId = ctx?.senderOpenId || meta.senderId || undefined;
12319
+ const resolvedProfile = ctx?.profile ?? profile ?? meta.profile;
12320
+ const rawChatType = meta.chatType;
12321
+ const chatType = rawChatType === "group" || rawChatType === "p2p" ? rawChatType : "unknown";
12322
+ return {
12323
+ esType: triggerEvent.esType ?? handler.type,
12324
+ ...chatId ? { chatId } : {},
12325
+ chatType,
12326
+ ...messageId ? { messageId } : {},
12327
+ ...senderId ? { senderId } : {},
12328
+ ...resolvedProfile ? { profile: resolvedProfile } : {},
12329
+ replyKind: chatId ? messageId ? "reply" : "send" : "none"
12330
+ };
12331
+ }
12332
+ async formatEventViaESPluginV2(event, ruleNotice) {
11916
12333
  const triggerEventId = event.metadata.triggerEventId;
11917
12334
  const triggerEvent = await this.eventStore.getEventById(triggerEventId);
11918
12335
  if (!triggerEvent) {
@@ -11927,17 +12344,21 @@ class EventHandler {
11927
12344
  summary: typeof payload?.result === "string" ? payload.result : typeof payload?.error === "string" ? payload.error : "(无结果)"
11928
12345
  };
11929
12346
  const profile = triggerEvent.metadata?.profile ?? undefined;
12347
+ const channel = this.buildNotifyChannelInfo(triggerEvent, handler, profile);
11930
12348
  const prompt = handler.buildNotifyHandlePrompt({
11931
12349
  notifyEvent: {
11932
12350
  type: event.type,
11933
12351
  taskId: typeof payload?.associatedTaskId === "number" ? payload.associatedTaskId : undefined,
11934
12352
  description: typeof payload?.description === "string" ? payload.description : undefined,
11935
12353
  result: typeof payload?.result === "string" ? payload.result : undefined,
11936
- error: typeof payload?.error === "string" ? payload.error : undefined
12354
+ error: typeof payload?.error === "string" ? payload.error : undefined,
12355
+ subSessionId: typeof payload?.subSessionId === "string" ? payload.subSessionId : undefined
11937
12356
  },
11938
12357
  triggerEvent,
11939
12358
  subAgentResult,
11940
- profile
12359
+ profile,
12360
+ channel,
12361
+ ...ruleNotice ? { ruleNotice } : {}
11941
12362
  });
11942
12363
  if (handler.postProcessNotifyEvent) {
11943
12364
  const notifyEventForHook = {
@@ -12387,18 +12808,36 @@ __legacyDecorateClassTS([
12387
12808
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12388
12809
  ], EventHandler.prototype, "handleEvent", null);
12389
12810
  __legacyDecorateClassTS([
12390
- TracedAs5("cli.event-handler.formatEvent", { recordParams: true, recordResult: false }),
12811
+ TracedAs5("event_handler.rule_notice", { recordParams: true, recordResult: false }),
12391
12812
  __legacyMetadataTS("design:type", Function),
12392
12813
  __legacyMetadataTS("design:paramtypes", [
12393
12814
  typeof EnvEvent === "undefined" ? Object : EnvEvent
12394
12815
  ]),
12395
12816
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12817
+ ], EventHandler.prototype, "sendRuleNotice", null);
12818
+ __legacyDecorateClassTS([
12819
+ TracedAs5("event_handler.telemetry_notice", { recordParams: true, recordResult: false }),
12820
+ __legacyMetadataTS("design:type", Function),
12821
+ __legacyMetadataTS("design:paramtypes", [
12822
+ typeof EnvEvent === "undefined" ? Object : EnvEvent
12823
+ ]),
12824
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12825
+ ], EventHandler.prototype, "sendTelemetryNotice", null);
12826
+ __legacyDecorateClassTS([
12827
+ TracedAs5("cli.event-handler.formatEvent", { recordParams: true, recordResult: false }),
12828
+ __legacyMetadataTS("design:type", Function),
12829
+ __legacyMetadataTS("design:paramtypes", [
12830
+ typeof EnvEvent === "undefined" ? Object : EnvEvent,
12831
+ Object
12832
+ ]),
12833
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12396
12834
  ], EventHandler.prototype, "formatEvent", null);
12397
12835
  __legacyDecorateClassTS([
12398
12836
  TracedAs5("event_handler.process_notify", { recordParams: true, recordResult: false }),
12399
12837
  __legacyMetadataTS("design:type", Function),
12400
12838
  __legacyMetadataTS("design:paramtypes", [
12401
- typeof EnvEvent === "undefined" ? Object : EnvEvent
12839
+ typeof EnvEvent === "undefined" ? Object : EnvEvent,
12840
+ typeof RuleNoticeInfo === "undefined" ? Object : RuleNoticeInfo
12402
12841
  ]),
12403
12842
  __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12404
12843
  ], EventHandler.prototype, "formatEventViaESPluginV2", null);
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/dist/roy-agent-linux-x64/bin/roy-agent
3
- size: 109885568 bytes
4
- sha256: 3a69d105f14b338232ff69fa3b1210da25fb37594d63457ccbf30f7fe3d973a5
3
+ size: 109906048 bytes
4
+ sha256: a97336c59bd5ce3cada998cc8b03fec204414ec9ecc0995b494c0a3f6613d1b2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-agent-cli",
3
- "version": "1.7.57",
3
+ "version": "1.7.59",
4
4
  "type": "module",
5
5
  "description": "CLI for roy-agent - Non-interactive command execution",
6
6
  "main": "./dist/index.js",