@openclaw/signal 2026.7.1-beta.6 → 2026.7.2-beta.1
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/api.js +8 -8
- package/dist/{approval-handler.runtime-DDQ4ZRyc.js → approval-handler.runtime-I1SMFwwR.js} +4 -4
- package/dist/{approval-reactions-UFmUPD0A.js → approval-reactions-ChcS2rQN.js} +34 -25
- package/dist/{approval-resolver-BR0MioAA.js → approval-resolver-B3m0D2R0.js} +2 -1
- package/dist/{channel-Cnhy1RwG.js → channel-DK8XZHPe.js} +132 -42
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-CQN0RaFx.js → channel.runtime-BbDh5UIr.js} +3 -2
- package/dist/{client-adapter-C9mB2Jz8.js → client-adapter-aEM0kGhC.js} +52 -18
- package/dist/config-api-DIg1lInT.js +3 -0
- package/dist/{config-schema-BiojLEsX.js → config-schema-CfVNH0DB.js} +7 -9
- package/dist/contract-api.js +3 -3
- package/dist/doctor-contract-api.js +16 -0
- package/dist/{identity-C8-yk4J9.js → identity-BF8taj7g.js} +7 -4
- package/dist/{install-signal-cli-ik8VPaGg.js → install-signal-cli-CtusY3tN.js} +43 -32
- package/dist/{monitor-Bee8O5Ay.js → monitor-BdzH3U64.js} +331 -126
- package/dist/{probe-Cnht8Ihg.js → probe-CbWkI24J.js} +1 -1
- package/dist/{reaction-runtime-api-EQ7cc7-Y.js → reaction-runtime-api-DifyinAU.js} +1 -1
- package/dist/reaction-runtime-api.js +1 -1
- package/dist/{message-actions-3OLDgjis.js → reply-authors-osU_SY4J.js} +212 -9
- package/dist/{approval-auth-CsHNcAiy.js → runtime-BZ9hnS3a.js} +34 -24
- package/dist/runtime-api.js +9 -9
- package/dist/{send-CUJy6WPt.js → send-BWtA6h3J.js} +14 -9
- package/dist/{send.runtime-CEi5oyCG.js → send.runtime-D4WBNNgn.js} +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +72 -48
- package/package.json +4 -4
- package/dist/config-api-KS-qhQvD.js +0 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { a as resolveSignalReplyToMode, i as resolveSignalAccount } from "./accounts-Bz4HtP0g.js";
|
|
3
|
-
import { a as normalizeSignalAllowRecipient, c as resolveSignalSender, d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, l as looksLikeUuid, n as formatSignalSenderDisplay, o as resolveSignalPeerId, r as formatSignalSenderId, s as resolveSignalRecipient, t as formatSignalPairingIdLine } from "./identity-
|
|
4
|
-
import { a as isSignalNativeApprovalHandlerConfigured,
|
|
5
|
-
import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-
|
|
6
|
-
import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-
|
|
7
|
-
import { a as maybeResolveSignalApprovalReaction, l as resolveSignalApprovalConversationKey, s as registerSignalApprovalReactionTargetForDeliveredPayload, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-
|
|
8
|
-
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-
|
|
9
|
-
import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";
|
|
3
|
+
import { a as normalizeSignalAllowRecipient, c as resolveSignalSender, d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, l as looksLikeUuid, n as formatSignalSenderDisplay, o as resolveSignalPeerId, r as formatSignalSenderId, s as resolveSignalRecipient, t as formatSignalPairingIdLine } from "./identity-BF8taj7g.js";
|
|
4
|
+
import { a as resolveSignalReactionLevel, c as isSignalNativeApprovalHandlerConfigured, r as materializeSignalPresentationFallback, t as registerSignalReplyContext } from "./reply-authors-osU_SY4J.js";
|
|
5
|
+
import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-aEM0kGhC.js";
|
|
6
|
+
import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-DifyinAU.js";
|
|
7
|
+
import { a as maybeResolveSignalApprovalReaction, l as resolveSignalApprovalConversationKey, s as registerSignalApprovalReactionTargetForDeliveredPayload, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-ChcS2rQN.js";
|
|
8
|
+
import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-BWtA6h3J.js";
|
|
9
|
+
import { createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
10
10
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
11
11
|
import { detectMime, estimateBase64DecodedBytes, kindFromMime, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
|
|
12
12
|
import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
@@ -15,6 +15,7 @@ import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plu
|
|
|
15
15
|
import { normalizeE164, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
16
16
|
import nodePath from "node:path";
|
|
17
17
|
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
18
|
+
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
18
19
|
import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
19
20
|
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
20
21
|
import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
@@ -26,18 +27,23 @@ import { resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy,
|
|
|
26
27
|
import { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runtime";
|
|
27
28
|
import { spawn } from "node:child_process";
|
|
28
29
|
import os from "node:os";
|
|
30
|
+
import { createInterface } from "node:readline";
|
|
31
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
29
32
|
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
30
33
|
import { DEFAULT_EMOJIS, DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
|
|
31
34
|
import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, runChannelInboundEvent, shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-inbound";
|
|
32
|
-
import {
|
|
35
|
+
import { isControlCommandMessage } from "openclaw/plugin-sdk/command-detection";
|
|
33
36
|
import { recordInboundSession, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
34
37
|
import { createInternalHookEvent, fireAndForgetHook, toInternalMessageReceivedContext, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
|
|
35
38
|
import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
|
|
36
39
|
import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
37
40
|
import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
38
41
|
import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
42
|
+
import { listChatCommands, maybeResolveTextAlias, normalizeCommandBody } from "openclaw/plugin-sdk/command-auth-native";
|
|
43
|
+
import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
|
|
39
44
|
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
40
45
|
//#region extensions/signal/src/daemon.ts
|
|
46
|
+
const SIGNAL_DAEMON_STOP_KILL_TIMEOUT_MS = 1500;
|
|
41
47
|
function formatSignalDaemonExit(exit) {
|
|
42
48
|
return `signal daemon exited (source=${exit.source} code=${exit.code ?? "null"} signal=${exit.signal ?? "null"})`;
|
|
43
49
|
}
|
|
@@ -53,12 +59,11 @@ function classifySignalCliLogLine(line) {
|
|
|
53
59
|
return "log";
|
|
54
60
|
}
|
|
55
61
|
function bindSignalCliOutput(params) {
|
|
56
|
-
params.stream
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
+
if (!params.stream) return;
|
|
63
|
+
createInterface({ input: params.stream }).on("line", (line) => {
|
|
64
|
+
const kind = classifySignalCliLogLine(line);
|
|
65
|
+
if (kind === "log") params.log(`signal-cli: ${line.trim()}`);
|
|
66
|
+
else if (kind === "error") params.error(`signal-cli: ${line.trim()}`);
|
|
62
67
|
});
|
|
63
68
|
}
|
|
64
69
|
function resolveSignalCliConfigPath(raw) {
|
|
@@ -91,6 +96,7 @@ function spawnSignalDaemon(opts) {
|
|
|
91
96
|
const error = opts.runtime?.error ?? (() => {});
|
|
92
97
|
let exited = false;
|
|
93
98
|
let settledExit = false;
|
|
99
|
+
let stopPromise;
|
|
94
100
|
let resolveExit;
|
|
95
101
|
const exitedPromise = new Promise((resolve) => {
|
|
96
102
|
resolveExit = resolve;
|
|
@@ -131,19 +137,42 @@ function spawnSignalDaemon(opts) {
|
|
|
131
137
|
});
|
|
132
138
|
});
|
|
133
139
|
child.on("error", (err) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
if (child.pid === void 0) {
|
|
141
|
+
error(`signal-cli spawn error: ${String(err)}`);
|
|
142
|
+
settleExit({
|
|
143
|
+
source: "spawn-error",
|
|
144
|
+
code: null,
|
|
145
|
+
signal: null
|
|
146
|
+
});
|
|
147
|
+
} else error(`signal-cli process error: ${String(err)}`);
|
|
140
148
|
});
|
|
141
149
|
return {
|
|
142
150
|
pid: child.pid ?? void 0,
|
|
143
151
|
exited: exitedPromise,
|
|
144
152
|
isExited: () => exited,
|
|
145
153
|
stop: () => {
|
|
146
|
-
if (
|
|
154
|
+
if (exited) return Promise.resolve();
|
|
155
|
+
if (stopPromise) return stopPromise;
|
|
156
|
+
if (!child.killed) try {
|
|
157
|
+
child.kill("SIGTERM");
|
|
158
|
+
} catch (err) {
|
|
159
|
+
error(`signal-cli stop error: ${String(err)}`);
|
|
160
|
+
}
|
|
161
|
+
stopPromise = new Promise((resolve) => {
|
|
162
|
+
const timeout = setTimeout(() => {
|
|
163
|
+
if (!exited) try {
|
|
164
|
+
child.kill("SIGKILL");
|
|
165
|
+
} catch (err) {
|
|
166
|
+
error(`signal-cli force-stop error: ${String(err)}`);
|
|
167
|
+
}
|
|
168
|
+
}, SIGNAL_DAEMON_STOP_KILL_TIMEOUT_MS);
|
|
169
|
+
timeout.unref?.();
|
|
170
|
+
exitedPromise.then(() => {
|
|
171
|
+
clearTimeout(timeout);
|
|
172
|
+
resolve();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
return stopPromise;
|
|
147
176
|
}
|
|
148
177
|
};
|
|
149
178
|
}
|
|
@@ -214,8 +243,8 @@ function signalSubjectInput(params) {
|
|
|
214
243
|
return {
|
|
215
244
|
stableId: formatSignalSenderId(params.sender),
|
|
216
245
|
aliases: {
|
|
217
|
-
phone: params.sender.kind === "phone" ? params.sender.e164 :
|
|
218
|
-
uuid: params.sender.kind === "uuid" ? params.sender.raw :
|
|
246
|
+
phone: params.sender.kind === "phone" ? params.sender.e164 : params.sender.aliases?.e164,
|
|
247
|
+
uuid: params.sender.kind === "uuid" ? params.sender.raw : params.sender.aliases?.uuid,
|
|
219
248
|
group: params.groupId
|
|
220
249
|
}
|
|
221
250
|
};
|
|
@@ -281,6 +310,96 @@ async function handleSignalDirectMessageAccess(params) {
|
|
|
281
310
|
return false;
|
|
282
311
|
}
|
|
283
312
|
//#endregion
|
|
313
|
+
//#region extensions/signal/src/monitor/event-handler.control-lane.ts
|
|
314
|
+
const SIGNAL_ACTIVE_RUN_CONTROL_COMMAND_KEYS = /* @__PURE__ */ new Set([
|
|
315
|
+
"approve",
|
|
316
|
+
"commands",
|
|
317
|
+
"context",
|
|
318
|
+
"help",
|
|
319
|
+
"status",
|
|
320
|
+
"steer",
|
|
321
|
+
"tasks",
|
|
322
|
+
"tools",
|
|
323
|
+
"whoami"
|
|
324
|
+
]);
|
|
325
|
+
function resolveSignalConversationId(entry) {
|
|
326
|
+
return (entry.isGroup ? entry.groupId : entry.senderPeerId)?.trim() || null;
|
|
327
|
+
}
|
|
328
|
+
function resolveSignalInboundDebounceKey(accountId, entry) {
|
|
329
|
+
const conversationId = resolveSignalConversationId(entry);
|
|
330
|
+
if (!conversationId || !entry.senderPeerId) return null;
|
|
331
|
+
return `signal:${accountId}:${conversationId}:${entry.senderPeerId}`;
|
|
332
|
+
}
|
|
333
|
+
function resolveSignalInboundConversationKey(accountId, entry) {
|
|
334
|
+
const conversationId = resolveSignalConversationId(entry);
|
|
335
|
+
return conversationId ? `signal:${accountId}:${conversationId}` : null;
|
|
336
|
+
}
|
|
337
|
+
function isSignalActiveRunControlText(text) {
|
|
338
|
+
if (isAbortRequestText(text)) return true;
|
|
339
|
+
const normalizedBody = normalizeCommandBody(text.trim());
|
|
340
|
+
const alias = maybeResolveTextAlias(normalizedBody);
|
|
341
|
+
if (!alias) return false;
|
|
342
|
+
const command = listChatCommands().find((entry) => entry.textAliases.some((candidate) => candidate.trim().toLowerCase() === alias));
|
|
343
|
+
if (command?.key === "queue") return normalizedBody.slice(alias.length).trim() === "";
|
|
344
|
+
return command ? SIGNAL_ACTIVE_RUN_CONTROL_COMMAND_KEYS.has(command.key) : false;
|
|
345
|
+
}
|
|
346
|
+
function resolveSignalControlLaneKey(accountId, entry) {
|
|
347
|
+
if (!entry.commandAuthorized || !isSignalActiveRunControlText(entry.commandBody)) return null;
|
|
348
|
+
const conversationId = resolveSignalConversationId(entry);
|
|
349
|
+
return conversationId ? `signal:${accountId}:${conversationId}:control` : null;
|
|
350
|
+
}
|
|
351
|
+
function createSignalPendingInboundRegistry(accountId) {
|
|
352
|
+
const trackedEntries = /* @__PURE__ */ new WeakMap();
|
|
353
|
+
const countsByConversation = /* @__PURE__ */ new Map();
|
|
354
|
+
const track = (entry) => {
|
|
355
|
+
if (trackedEntries.has(entry)) return;
|
|
356
|
+
const conversationKey = resolveSignalInboundConversationKey(accountId, entry);
|
|
357
|
+
const inboundKey = resolveSignalInboundDebounceKey(accountId, entry);
|
|
358
|
+
if (!conversationKey || !inboundKey) return;
|
|
359
|
+
const counts = countsByConversation.get(conversationKey) ?? /* @__PURE__ */ new Map();
|
|
360
|
+
counts.set(inboundKey, (counts.get(inboundKey) ?? 0) + 1);
|
|
361
|
+
countsByConversation.set(conversationKey, counts);
|
|
362
|
+
trackedEntries.set(entry, {
|
|
363
|
+
conversationKey,
|
|
364
|
+
inboundKey
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
const complete = (entries) => {
|
|
368
|
+
for (const entry of entries) {
|
|
369
|
+
const tracked = trackedEntries.get(entry);
|
|
370
|
+
if (!tracked) continue;
|
|
371
|
+
trackedEntries.delete(entry);
|
|
372
|
+
const counts = countsByConversation.get(tracked.conversationKey);
|
|
373
|
+
const nextCount = (counts?.get(tracked.inboundKey) ?? 0) - 1;
|
|
374
|
+
if (nextCount > 0) {
|
|
375
|
+
counts?.set(tracked.inboundKey, nextCount);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
counts?.delete(tracked.inboundKey);
|
|
379
|
+
if (counts?.size === 0) countsByConversation.delete(tracked.conversationKey);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
const cancelPendingOnAbort = (entry, cancelKey) => {
|
|
383
|
+
if (!entry.commandAuthorized || !isAbortRequestText(entry.commandBody)) return;
|
|
384
|
+
const conversationKey = resolveSignalInboundConversationKey(accountId, entry);
|
|
385
|
+
if (!conversationKey) return;
|
|
386
|
+
for (const inboundKey of countsByConversation.get(conversationKey)?.keys() ?? []) cancelKey(inboundKey);
|
|
387
|
+
};
|
|
388
|
+
const completeAfter = (flush) => async (entries) => {
|
|
389
|
+
try {
|
|
390
|
+
await flush(entries);
|
|
391
|
+
} finally {
|
|
392
|
+
complete(entries);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
return {
|
|
396
|
+
track,
|
|
397
|
+
complete,
|
|
398
|
+
completeAfter,
|
|
399
|
+
cancelPendingOnAbort
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
//#endregion
|
|
284
403
|
//#region extensions/signal/src/monitor/inbound-context.ts
|
|
285
404
|
function resolveSignalQuoteContext(params) {
|
|
286
405
|
const contextVisibilityMode = resolveChannelContextVisibilityMode({
|
|
@@ -328,6 +447,41 @@ function clampBounds(start, length, textLength) {
|
|
|
328
447
|
end: Math.min(textLength, safeStart + Math.max(0, Math.trunc(length)))
|
|
329
448
|
};
|
|
330
449
|
}
|
|
450
|
+
function isValidStructuredMention(message, mention) {
|
|
451
|
+
if (!mention || !(mention.uuid || mention.number)) return false;
|
|
452
|
+
const { start, length } = mention;
|
|
453
|
+
if (typeof start !== "number" || typeof length !== "number") return false;
|
|
454
|
+
return Number.isInteger(start) && Number.isInteger(length) && start >= 0 && length > 0 && start + length <= message.length;
|
|
455
|
+
}
|
|
456
|
+
function normalizeAccountPhone(account) {
|
|
457
|
+
const trimmed = account?.trim();
|
|
458
|
+
return trimmed ? normalizeE164(trimmed) : void 0;
|
|
459
|
+
}
|
|
460
|
+
function resolveSignalNativeMentionFacts(params) {
|
|
461
|
+
const validMentions = (params.mentions ?? []).filter((mention) => isValidStructuredMention(params.message, mention));
|
|
462
|
+
const botUuid = params.accountUuid?.trim();
|
|
463
|
+
const botPhone = normalizeAccountPhone(params.account);
|
|
464
|
+
const canDetectBotMention = Boolean(botUuid || botPhone);
|
|
465
|
+
const mentionsBot = validMentions.some((mention) => {
|
|
466
|
+
const mentionUuid = mention.uuid?.trim();
|
|
467
|
+
if (botUuid && mentionUuid === botUuid) return true;
|
|
468
|
+
const mentionNumber = mention.number?.trim();
|
|
469
|
+
return Boolean(botPhone && mentionNumber && normalizeE164(mentionNumber) === botPhone);
|
|
470
|
+
});
|
|
471
|
+
return {
|
|
472
|
+
canDetectBotMention,
|
|
473
|
+
hasAnyMention: validMentions.length > 0,
|
|
474
|
+
mentionsBot
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function resolveSignalMentionFacts(identity, message, mentions) {
|
|
478
|
+
return resolveSignalNativeMentionFacts({
|
|
479
|
+
message,
|
|
480
|
+
mentions,
|
|
481
|
+
account: identity.account,
|
|
482
|
+
accountUuid: identity.accountUuid
|
|
483
|
+
});
|
|
484
|
+
}
|
|
331
485
|
function renderSignalMentions(message, mentions) {
|
|
332
486
|
if (!message || !mentions?.length) return message;
|
|
333
487
|
let normalized = message;
|
|
@@ -344,6 +498,15 @@ function renderSignalMentions(message, mentions) {
|
|
|
344
498
|
}
|
|
345
499
|
//#endregion
|
|
346
500
|
//#region extensions/signal/src/monitor/event-handler.ts
|
|
501
|
+
const REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE = /reply session initialization conflicted for \S+/u;
|
|
502
|
+
const RETRYABLE_FLUSH_RETRY_DELAYS_MS = [
|
|
503
|
+
1e3,
|
|
504
|
+
2e3,
|
|
505
|
+
4e3
|
|
506
|
+
];
|
|
507
|
+
function isSignalReplySessionInitConflictError(error) {
|
|
508
|
+
return collectErrorGraphCandidates(error, (current) => [current.cause, current.error]).some((candidate) => REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE.test(formatErrorMessage(candidate)));
|
|
509
|
+
}
|
|
347
510
|
function formatAttachmentKindCount(kind, count) {
|
|
348
511
|
if (kind === "attachment") return `${count} file${count > 1 ? "s" : ""}`;
|
|
349
512
|
return `${count} ${kind}${count > 1 ? "s" : ""}`;
|
|
@@ -404,6 +567,7 @@ async function finalizeSignalStatusReaction(params) {
|
|
|
404
567
|
await params.controller.restoreInitial();
|
|
405
568
|
}
|
|
406
569
|
function createSignalEventHandler(deps) {
|
|
570
|
+
const activeEnqueueEntries = /* @__PURE__ */ new WeakSet();
|
|
407
571
|
async function handleSignalInboundMessage(entry) {
|
|
408
572
|
const fromLabel = formatInboundFromLabel({
|
|
409
573
|
isGroup: entry.isGroup,
|
|
@@ -461,11 +625,12 @@ function createSignalEventHandler(deps) {
|
|
|
461
625
|
historyKey,
|
|
462
626
|
limit: deps.historyLimit
|
|
463
627
|
}) : void 0;
|
|
464
|
-
const
|
|
628
|
+
const replyToMode = resolveSignalReplyToMode({
|
|
465
629
|
cfg: deps.cfg,
|
|
466
630
|
accountId: deps.accountId,
|
|
467
631
|
chatType: entry.isGroup ? "group" : "direct"
|
|
468
|
-
})
|
|
632
|
+
});
|
|
633
|
+
const replyThreading = resolveBatchedReplyThreadingPolicy(replyToMode, entry.isBatched === true);
|
|
469
634
|
const media = entry.mediaPaths && entry.mediaPaths.length > 0 ? entry.mediaPaths.map((path, index) => ({
|
|
470
635
|
path,
|
|
471
636
|
url: path,
|
|
@@ -618,6 +783,7 @@ function createSignalEventHandler(deps) {
|
|
|
618
783
|
replyToId: ctxPayload.ReplyToId,
|
|
619
784
|
author: entry.senderRecipient,
|
|
620
785
|
body: entry.nativeReplyBody ?? entry.bodyText,
|
|
786
|
+
allowImplicitCurrentMessage: replyToMode !== "off" && replyThreading?.implicitCurrentMessage !== "deny",
|
|
621
787
|
state: { hasReplied: false }
|
|
622
788
|
};
|
|
623
789
|
const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
|
|
@@ -753,14 +919,75 @@ function createSignalEventHandler(deps) {
|
|
|
753
919
|
}
|
|
754
920
|
});
|
|
755
921
|
}
|
|
756
|
-
|
|
922
|
+
async function flushSignalInboundEntries(entries) {
|
|
923
|
+
const last = entries.at(-1);
|
|
924
|
+
if (!last) return;
|
|
925
|
+
if (entries.length === 1) {
|
|
926
|
+
await handleSignalInboundMessage(last);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const combinedText = entries.map((entry) => entry.bodyText).filter(Boolean).join("\\n");
|
|
930
|
+
const combinedCommandBody = entries.map((entry) => entry.commandBody).filter(Boolean).join("\\n");
|
|
931
|
+
if (!combinedText.trim()) return;
|
|
932
|
+
await handleSignalInboundMessage({
|
|
933
|
+
...last,
|
|
934
|
+
bodyText: combinedText,
|
|
935
|
+
commandBody: combinedCommandBody,
|
|
936
|
+
isBatched: true,
|
|
937
|
+
nativeReplyBody: last.nativeReplyBody ?? last.bodyText,
|
|
938
|
+
mediaPath: void 0,
|
|
939
|
+
mediaType: void 0,
|
|
940
|
+
mediaPaths: void 0,
|
|
941
|
+
mediaTypes: void 0
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
async function retrySignalInboundFlush(entries, initialError) {
|
|
945
|
+
let lastError = initialError;
|
|
946
|
+
for (const [attemptIndex, delayMs] of RETRYABLE_FLUSH_RETRY_DELAYS_MS.entries()) {
|
|
947
|
+
const attempt = attemptIndex + 1;
|
|
948
|
+
logVerbose(`signal: reply session init conflict, retrying ${entries.length} inbound message(s) in ${delayMs}ms (attempt ${attempt}/${RETRYABLE_FLUSH_RETRY_DELAYS_MS.length})`);
|
|
949
|
+
try {
|
|
950
|
+
await setTimeout$1(delayMs, void 0, {
|
|
951
|
+
ref: false,
|
|
952
|
+
signal: deps.abortSignal
|
|
953
|
+
});
|
|
954
|
+
} catch (err) {
|
|
955
|
+
if (deps.abortSignal?.aborted) return;
|
|
956
|
+
throw err;
|
|
957
|
+
}
|
|
958
|
+
if (deps.abortSignal?.aborted) return;
|
|
959
|
+
try {
|
|
960
|
+
await flushSignalInboundEntries(entries);
|
|
961
|
+
return;
|
|
962
|
+
} catch (err) {
|
|
963
|
+
if (deps.abortSignal?.aborted) return;
|
|
964
|
+
lastError = err;
|
|
965
|
+
if (!isSignalReplySessionInitConflictError(err)) throw err;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
throw lastError;
|
|
969
|
+
}
|
|
970
|
+
const flushDebouncedSignalInboundEntries = async (entries) => {
|
|
971
|
+
if (!entries.some((entry) => activeEnqueueEntries.has(entry)) && deps.abortSignal?.aborted) return;
|
|
972
|
+
try {
|
|
973
|
+
await flushSignalInboundEntries(entries);
|
|
974
|
+
} catch (err) {
|
|
975
|
+
if (!isSignalReplySessionInitConflictError(err)) throw err;
|
|
976
|
+
if (deps.abortSignal?.aborted) return;
|
|
977
|
+
const retryTask = retrySignalInboundFlush(entries, err);
|
|
978
|
+
deps.runTrackedTask?.(() => retryTask.catch(() => void 0));
|
|
979
|
+
await retryTask;
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
const reportSignalInboundFlushError = (err) => {
|
|
983
|
+
deps.runtime.error?.(`signal debounce flush failed: ${String(err)}`);
|
|
984
|
+
};
|
|
985
|
+
const pendingInboundRegistry = createSignalPendingInboundRegistry(deps.accountId);
|
|
986
|
+
const flushNormalSignalInboundEntries = pendingInboundRegistry.completeAfter(flushDebouncedSignalInboundEntries);
|
|
987
|
+
const { debouncer } = createChannelInboundDebouncer({
|
|
757
988
|
cfg: deps.cfg,
|
|
758
989
|
channel: "signal",
|
|
759
|
-
buildKey: (entry) =>
|
|
760
|
-
const conversationId = entry.isGroup ? entry.groupId ?? "unknown" : entry.senderPeerId;
|
|
761
|
-
if (!conversationId || !entry.senderPeerId) return null;
|
|
762
|
-
return `signal:${deps.accountId}:${conversationId}:${entry.senderPeerId}`;
|
|
763
|
-
},
|
|
990
|
+
buildKey: (entry) => resolveSignalInboundDebounceKey(deps.accountId, entry),
|
|
764
991
|
shouldDebounce: (entry) => {
|
|
765
992
|
return shouldDebounceTextInbound({
|
|
766
993
|
text: entry.commandBody,
|
|
@@ -768,31 +995,18 @@ function createSignalEventHandler(deps) {
|
|
|
768
995
|
hasMedia: Boolean(entry.mediaPath || entry.mediaType || entry.mediaPaths?.length)
|
|
769
996
|
});
|
|
770
997
|
},
|
|
771
|
-
onFlush:
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
bodyText: combinedText,
|
|
784
|
-
commandBody: combinedCommandBody,
|
|
785
|
-
isBatched: true,
|
|
786
|
-
nativeReplyBody: last.nativeReplyBody ?? last.bodyText,
|
|
787
|
-
mediaPath: void 0,
|
|
788
|
-
mediaType: void 0,
|
|
789
|
-
mediaPaths: void 0,
|
|
790
|
-
mediaTypes: void 0
|
|
791
|
-
});
|
|
792
|
-
},
|
|
793
|
-
onError: (err) => {
|
|
794
|
-
deps.runtime.error?.(`signal debounce flush failed: ${String(err)}`);
|
|
795
|
-
}
|
|
998
|
+
onFlush: flushNormalSignalInboundEntries,
|
|
999
|
+
onError: reportSignalInboundFlushError,
|
|
1000
|
+
onCancel: pendingInboundRegistry.complete
|
|
1001
|
+
});
|
|
1002
|
+
const { debouncer: controlDebouncer } = createChannelInboundDebouncer({
|
|
1003
|
+
cfg: deps.cfg,
|
|
1004
|
+
channel: "signal",
|
|
1005
|
+
serializeImmediate: true,
|
|
1006
|
+
buildKey: (entry) => resolveSignalControlLaneKey(deps.accountId, entry),
|
|
1007
|
+
shouldDebounce: () => false,
|
|
1008
|
+
onFlush: flushDebouncedSignalInboundEntries,
|
|
1009
|
+
onError: reportSignalInboundFlushError
|
|
796
1010
|
});
|
|
797
1011
|
async function handleReactionOnlyInbound(params) {
|
|
798
1012
|
if (params.hasBodyContent) return false;
|
|
@@ -878,10 +1092,11 @@ function createSignalEventHandler(deps) {
|
|
|
878
1092
|
if ("syncMessage" in envelope) return;
|
|
879
1093
|
const dataMessage = envelope.dataMessage ?? envelope.editMessage?.dataMessage;
|
|
880
1094
|
const reaction = deps.isSignalReactionMessage(envelope.reactionMessage) ? envelope.reactionMessage : deps.isSignalReactionMessage(dataMessage?.reaction) ? dataMessage?.reaction : null;
|
|
881
|
-
const
|
|
1095
|
+
const rawMessage = dataMessage?.message ?? "";
|
|
1096
|
+
const messageText = renderSignalMentions(rawMessage, dataMessage?.mentions).trim();
|
|
882
1097
|
const groupId = dataMessage?.groupInfo?.groupId ?? reaction?.groupInfo?.groupId ?? void 0;
|
|
883
1098
|
const isGroup = Boolean(groupId);
|
|
884
|
-
const hasControlCommandInMessage =
|
|
1099
|
+
const hasControlCommandInMessage = isControlCommandMessage(messageText, deps.cfg);
|
|
885
1100
|
const senderDisplay = formatSignalSenderDisplay(sender);
|
|
886
1101
|
const { senderAccess, commandAccess } = await resolveSignalAccessState({
|
|
887
1102
|
accountId: deps.accountId,
|
|
@@ -966,8 +1181,16 @@ function createSignalEventHandler(deps) {
|
|
|
966
1181
|
groupId,
|
|
967
1182
|
senderPeerId
|
|
968
1183
|
});
|
|
1184
|
+
const inboundTimestamp = typeof envelope.timestamp === "number" ? envelope.timestamp : typeof dataMessage.timestamp === "number" ? dataMessage.timestamp : void 0;
|
|
1185
|
+
const nativeReplyTargetTimestamp = typeof envelope.editMessage?.targetSentTimestamp === "number" ? envelope.editMessage.targetSentTimestamp : inboundTimestamp;
|
|
1186
|
+
const messageId = typeof inboundTimestamp === "number" ? String(inboundTimestamp) : void 0;
|
|
1187
|
+
const replyToId = typeof nativeReplyTargetTimestamp === "number" ? String(nativeReplyTargetTimestamp) : void 0;
|
|
1188
|
+
const signalToRaw = isGroup ? `group:${groupId}` : `signal:${senderRecipient}`;
|
|
1189
|
+
const signalTo = normalizeSignalMessagingTarget(signalToRaw) ?? signalToRaw;
|
|
969
1190
|
const mentionRegexes = buildMentionRegexes(deps.cfg, route.agentId);
|
|
970
|
-
const
|
|
1191
|
+
const textWasMentioned = isGroup && matchesMentionPatterns(messageText, mentionRegexes);
|
|
1192
|
+
const nativeMentionFacts = resolveSignalMentionFacts(deps, rawMessage, dataMessage?.mentions);
|
|
1193
|
+
const wasMentioned = isGroup && (textWasMentioned || nativeMentionFacts.mentionsBot);
|
|
971
1194
|
const requireMention = isGroup && resolveChannelGroupRequireMention({
|
|
972
1195
|
cfg: deps.cfg,
|
|
973
1196
|
channel: "signal",
|
|
@@ -975,12 +1198,12 @@ function createSignalEventHandler(deps) {
|
|
|
975
1198
|
accountId: deps.accountId,
|
|
976
1199
|
configuredGroupDefaultsToNoMention: true
|
|
977
1200
|
});
|
|
978
|
-
const canDetectMention = mentionRegexes.length > 0;
|
|
1201
|
+
const canDetectMention = mentionRegexes.length > 0 || nativeMentionFacts.canDetectBotMention;
|
|
979
1202
|
const mentionDecision = resolveInboundMentionDecision({
|
|
980
1203
|
facts: {
|
|
981
1204
|
canDetectMention,
|
|
982
1205
|
wasMentioned,
|
|
983
|
-
hasAnyMention:
|
|
1206
|
+
hasAnyMention: nativeMentionFacts.hasAnyMention,
|
|
984
1207
|
implicitMentionKinds: []
|
|
985
1208
|
},
|
|
986
1209
|
policy: {
|
|
@@ -1020,6 +1243,14 @@ function createSignalEventHandler(deps) {
|
|
|
1020
1243
|
messageId: typeof envelope.timestamp === "number" ? String(envelope.timestamp) : void 0
|
|
1021
1244
|
}
|
|
1022
1245
|
});
|
|
1246
|
+
await registerSignalReplyContext({
|
|
1247
|
+
accountId: deps.accountId,
|
|
1248
|
+
to: signalTo,
|
|
1249
|
+
replyToId,
|
|
1250
|
+
author: senderRecipient,
|
|
1251
|
+
body: pendingBodyText,
|
|
1252
|
+
sourceTimestamp: inboundTimestamp
|
|
1253
|
+
});
|
|
1023
1254
|
const signalGroupPolicy = resolveChannelGroupPolicy({
|
|
1024
1255
|
cfg: deps.cfg,
|
|
1025
1256
|
channel: "signal",
|
|
@@ -1098,8 +1329,6 @@ function createSignalEventHandler(deps) {
|
|
|
1098
1329
|
});
|
|
1099
1330
|
}
|
|
1100
1331
|
if (!bodyText) return;
|
|
1101
|
-
const inboundTimestamp = typeof envelope.timestamp === "number" ? envelope.timestamp : typeof dataMessage.timestamp === "number" ? dataMessage.timestamp : void 0;
|
|
1102
|
-
const nativeReplyTargetTimestamp = typeof envelope.editMessage?.targetSentTimestamp === "number" ? envelope.editMessage.targetSentTimestamp : inboundTimestamp;
|
|
1103
1332
|
if (deps.sendReadReceipts && !deps.readReceiptsViaDaemon && !isGroup && inboundTimestamp) try {
|
|
1104
1333
|
await sendReadReceiptSignal(`signal:${senderRecipient}`, inboundTimestamp, {
|
|
1105
1334
|
cfg: deps.cfg,
|
|
@@ -1112,9 +1341,15 @@ function createSignalEventHandler(deps) {
|
|
|
1112
1341
|
}
|
|
1113
1342
|
else if (deps.sendReadReceipts && !deps.readReceiptsViaDaemon && !isGroup && !inboundTimestamp) logVerbose(`signal read receipt skipped (missing timestamp) for ${senderDisplay}`);
|
|
1114
1343
|
const senderName = envelope.sourceName ?? senderDisplay;
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1344
|
+
await registerSignalReplyContext({
|
|
1345
|
+
accountId: deps.accountId,
|
|
1346
|
+
to: signalTo,
|
|
1347
|
+
replyToId,
|
|
1348
|
+
author: senderRecipient,
|
|
1349
|
+
body: bodyText,
|
|
1350
|
+
sourceTimestamp: inboundTimestamp
|
|
1351
|
+
});
|
|
1352
|
+
const entry = {
|
|
1118
1353
|
senderName,
|
|
1119
1354
|
senderDisplay,
|
|
1120
1355
|
senderRecipient,
|
|
@@ -1138,7 +1373,16 @@ function createSignalEventHandler(deps) {
|
|
|
1138
1373
|
replyToBody: visibleQuoteText || void 0,
|
|
1139
1374
|
replyToSender: visibleQuoteSender,
|
|
1140
1375
|
replyToIsQuote: visibleQuoteText ? true : void 0
|
|
1141
|
-
}
|
|
1376
|
+
};
|
|
1377
|
+
pendingInboundRegistry.cancelPendingOnAbort(entry, debouncer.cancelKey);
|
|
1378
|
+
const inboundLane = resolveSignalControlLaneKey(deps.accountId, entry) ? controlDebouncer : debouncer;
|
|
1379
|
+
if (inboundLane === debouncer) pendingInboundRegistry.track(entry);
|
|
1380
|
+
activeEnqueueEntries.add(entry);
|
|
1381
|
+
try {
|
|
1382
|
+
await inboundLane.enqueue(entry);
|
|
1383
|
+
} finally {
|
|
1384
|
+
activeEnqueueEntries.delete(entry);
|
|
1385
|
+
}
|
|
1142
1386
|
};
|
|
1143
1387
|
}
|
|
1144
1388
|
//#endregion
|
|
@@ -1209,8 +1453,8 @@ function resolveRuntime(opts) {
|
|
|
1209
1453
|
function createSignalMonitorTaskRunner(runtime) {
|
|
1210
1454
|
const inFlight = /* @__PURE__ */ new Set();
|
|
1211
1455
|
return {
|
|
1212
|
-
|
|
1213
|
-
const trackedTask = Promise.resolve().then(task).catch((err) => runtime.error?.(`
|
|
1456
|
+
runTask(task) {
|
|
1457
|
+
const trackedTask = Promise.resolve().then(task).catch((err) => runtime.error?.(`signal monitor task failed: ${String(err)}`)).finally(() => inFlight.delete(trackedTask));
|
|
1214
1458
|
inFlight.add(trackedTask);
|
|
1215
1459
|
},
|
|
1216
1460
|
async waitForIdle() {
|
|
@@ -1218,58 +1462,16 @@ function createSignalMonitorTaskRunner(runtime) {
|
|
|
1218
1462
|
}
|
|
1219
1463
|
};
|
|
1220
1464
|
}
|
|
1221
|
-
function mergeAbortSignals(a, b) {
|
|
1222
|
-
if (!a && !b) return {
|
|
1223
|
-
signal: void 0,
|
|
1224
|
-
dispose: () => {}
|
|
1225
|
-
};
|
|
1226
|
-
if (!a) return {
|
|
1227
|
-
signal: b,
|
|
1228
|
-
dispose: () => {}
|
|
1229
|
-
};
|
|
1230
|
-
if (!b) return {
|
|
1231
|
-
signal: a,
|
|
1232
|
-
dispose: () => {}
|
|
1233
|
-
};
|
|
1234
|
-
const controller = new AbortController();
|
|
1235
|
-
const abortFrom = (source) => {
|
|
1236
|
-
if (!controller.signal.aborted) controller.abort(source.reason);
|
|
1237
|
-
};
|
|
1238
|
-
if (a.aborted) {
|
|
1239
|
-
abortFrom(a);
|
|
1240
|
-
return {
|
|
1241
|
-
signal: controller.signal,
|
|
1242
|
-
dispose: () => {}
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
if (b.aborted) {
|
|
1246
|
-
abortFrom(b);
|
|
1247
|
-
return {
|
|
1248
|
-
signal: controller.signal,
|
|
1249
|
-
dispose: () => {}
|
|
1250
|
-
};
|
|
1251
|
-
}
|
|
1252
|
-
const onAbortA = () => abortFrom(a);
|
|
1253
|
-
const onAbortB = () => abortFrom(b);
|
|
1254
|
-
a.addEventListener("abort", onAbortA, { once: true });
|
|
1255
|
-
b.addEventListener("abort", onAbortB, { once: true });
|
|
1256
|
-
return {
|
|
1257
|
-
signal: controller.signal,
|
|
1258
|
-
dispose: () => {
|
|
1259
|
-
a.removeEventListener("abort", onAbortA);
|
|
1260
|
-
b.removeEventListener("abort", onAbortB);
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
}
|
|
1264
1465
|
function createSignalDaemonLifecycle(params) {
|
|
1265
1466
|
let daemonHandle = null;
|
|
1266
1467
|
let daemonStopRequested = false;
|
|
1267
1468
|
let daemonExitError;
|
|
1268
1469
|
const daemonAbortController = new AbortController();
|
|
1269
|
-
const
|
|
1470
|
+
const abortSignal = params.abortSignal ? AbortSignal.any([params.abortSignal, daemonAbortController.signal]) : daemonAbortController.signal;
|
|
1270
1471
|
const stop = () => {
|
|
1271
1472
|
daemonStopRequested = true;
|
|
1272
|
-
|
|
1473
|
+
if (!daemonAbortController.signal.aborted) daemonAbortController.abort(params.abortSignal?.reason ?? /* @__PURE__ */ new Error("Signal monitor stopped"));
|
|
1474
|
+
return daemonHandle?.stop() ?? Promise.resolve();
|
|
1273
1475
|
};
|
|
1274
1476
|
const attach = (handle) => {
|
|
1275
1477
|
daemonHandle = handle;
|
|
@@ -1284,8 +1486,7 @@ function createSignalDaemonLifecycle(params) {
|
|
|
1284
1486
|
attach,
|
|
1285
1487
|
stop,
|
|
1286
1488
|
getExitError,
|
|
1287
|
-
abortSignal
|
|
1288
|
-
dispose: mergedAbort.dispose
|
|
1489
|
+
abortSignal
|
|
1289
1490
|
};
|
|
1290
1491
|
}
|
|
1291
1492
|
function normalizeAllowList(raw) {
|
|
@@ -1403,14 +1604,15 @@ async function deliverReplies(params) {
|
|
|
1403
1604
|
});
|
|
1404
1605
|
for (const payload of replies) {
|
|
1405
1606
|
const deliveryResults = [];
|
|
1607
|
+
const presentationPayload = materializeSignalPresentationFallback(payload);
|
|
1406
1608
|
const deliveredPayload = addSignalApprovalReactionHintToStructuredPayload({
|
|
1407
1609
|
cfg: params.cfg,
|
|
1408
1610
|
accountId,
|
|
1409
1611
|
to: target,
|
|
1410
|
-
payload,
|
|
1612
|
+
payload: presentationPayload,
|
|
1411
1613
|
targetAuthor: account,
|
|
1412
1614
|
targetAuthorUuid: accountUuid
|
|
1413
|
-
}) ??
|
|
1615
|
+
}) ?? presentationPayload;
|
|
1414
1616
|
const reply = resolveSendableOutboundReplyParts(deliveredPayload);
|
|
1415
1617
|
const nextNativeReply = createSignalNativeReplyResolver({
|
|
1416
1618
|
payload: deliveredPayload,
|
|
@@ -1471,12 +1673,15 @@ async function deliverReplies(params) {
|
|
|
1471
1673
|
function resolveSignalNativeReplyOptions(params) {
|
|
1472
1674
|
if (params.payload.replyToCurrent === false) return {};
|
|
1473
1675
|
const payloadReplyToId = normalizeOptionalString(params.payload.replyToId);
|
|
1676
|
+
const isExplicitCurrentReply = params.payload.replyToTag === true || params.payload.replyToCurrent === true;
|
|
1677
|
+
if (!payloadReplyToId && !isExplicitCurrentReply && params.replyContext?.allowImplicitCurrentMessage === false) return {};
|
|
1474
1678
|
const contextReplyToId = normalizeOptionalString(params.replyContext?.replyToId);
|
|
1475
|
-
if (!
|
|
1679
|
+
if (!contextReplyToId || payloadReplyToId && payloadReplyToId !== contextReplyToId) return {};
|
|
1680
|
+
const replyToId = payloadReplyToId ?? contextReplyToId;
|
|
1476
1681
|
const replyToAuthor = normalizeOptionalString(params.replyContext?.author);
|
|
1477
|
-
if (!replyToAuthor) return { replyToId
|
|
1682
|
+
if (!replyToAuthor) return { replyToId };
|
|
1478
1683
|
return {
|
|
1479
|
-
replyToId
|
|
1684
|
+
replyToId,
|
|
1480
1685
|
replyToAuthor,
|
|
1481
1686
|
replyToBody: params.replyContext?.body ?? ""
|
|
1482
1687
|
};
|
|
@@ -1603,12 +1808,14 @@ async function monitorSignalProvider(opts = {}) {
|
|
|
1603
1808
|
});
|
|
1604
1809
|
const handleEvent = createSignalEventHandler({
|
|
1605
1810
|
runtime,
|
|
1811
|
+
abortSignal: daemonLifecycle.abortSignal,
|
|
1812
|
+
runTrackedTask: (task) => monitorTaskRunner.runTask(task),
|
|
1606
1813
|
cfg,
|
|
1607
1814
|
baseUrl,
|
|
1608
1815
|
account,
|
|
1609
1816
|
accountUuid: accountInfo.config.accountUuid,
|
|
1610
1817
|
accountId: accountInfo.accountId,
|
|
1611
|
-
blockStreaming: accountInfo.config
|
|
1818
|
+
blockStreaming: resolveChannelStreamingBlockEnabled(accountInfo.config),
|
|
1612
1819
|
historyLimit,
|
|
1613
1820
|
groupHistories,
|
|
1614
1821
|
textLimit,
|
|
@@ -1645,7 +1852,7 @@ async function monitorSignalProvider(opts = {}) {
|
|
|
1645
1852
|
apiMode: configuredApiMode,
|
|
1646
1853
|
policy: opts.reconnectPolicy,
|
|
1647
1854
|
onEvent: (event) => {
|
|
1648
|
-
monitorTaskRunner.
|
|
1855
|
+
monitorTaskRunner.runTask(() => handleEvent(event));
|
|
1649
1856
|
}
|
|
1650
1857
|
});
|
|
1651
1858
|
const daemonExitError = daemonLifecycle.getExitError();
|
|
@@ -1655,10 +1862,8 @@ async function monitorSignalProvider(opts = {}) {
|
|
|
1655
1862
|
if (opts.abortSignal?.aborted && !daemonExitError) return;
|
|
1656
1863
|
throw err;
|
|
1657
1864
|
} finally {
|
|
1658
|
-
await monitorTaskRunner.waitForIdle();
|
|
1659
|
-
daemonLifecycle.dispose();
|
|
1865
|
+
await Promise.all([daemonLifecycle.stop(), monitorTaskRunner.waitForIdle()]);
|
|
1660
1866
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
1661
|
-
daemonLifecycle.stop();
|
|
1662
1867
|
}
|
|
1663
1868
|
}
|
|
1664
1869
|
//#endregion
|