@openclaw/signal 2026.7.1-beta.2 → 2026.7.1-beta.4

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.
Files changed (24) hide show
  1. package/dist/{accounts-B7Rz3_xV.js → accounts-Bz4HtP0g.js} +20 -2
  2. package/dist/api.js +9 -9
  3. package/dist/{approval-auth-DPVK9A_l.js → approval-auth-CsHNcAiy.js} +2 -2
  4. package/dist/{approval-handler.runtime-BZLgs7EM.js → approval-handler.runtime-DDQ4ZRyc.js} +5 -5
  5. package/dist/{approval-reactions-5x1kmQEq.js → approval-reactions-UFmUPD0A.js} +113 -28
  6. package/dist/{channel-BfWp-F-r.js → channel-Cnhy1RwG.js} +42 -23
  7. package/dist/channel-plugin-api.js +1 -1
  8. package/dist/{channel.runtime-Ks7GIWM1.js → channel.runtime-CQN0RaFx.js} +3 -3
  9. package/dist/{client-adapter-Dm8-wT2n.js → client-adapter-C9mB2Jz8.js} +41 -11
  10. package/dist/contract-api.js +2 -2
  11. package/dist/{identity-B6O4k8xg.js → identity-C8-yk4J9.js} +12 -8
  12. package/dist/{install-signal-cli-TwhJ0DGy.js → install-signal-cli-ik8VPaGg.js} +7 -7
  13. package/dist/{message-actions-Cs9XckSd.js → message-actions-3OLDgjis.js} +6 -6
  14. package/dist/{monitor-C9SiyrFt.js → monitor-Bee8O5Ay.js} +120 -27
  15. package/dist/{probe-BL2BqTbG.js → probe-Cnht8Ihg.js} +1 -1
  16. package/dist/{reaction-runtime-api-BkAxQPGs.js → reaction-runtime-api-EQ7cc7-Y.js} +3 -3
  17. package/dist/reaction-runtime-api.js +1 -1
  18. package/dist/{rpc-context-DbFMe7am.js → rpc-context-DsHWh2hc.js} +1 -1
  19. package/dist/runtime-api.js +9 -9
  20. package/dist/{send-CLzc3RUg.js → send-CUJy6WPt.js} +84 -11
  21. package/dist/{send.runtime-DgijYwpJ.js → send.runtime-CEi5oyCG.js} +1 -1
  22. package/npm-shrinkwrap.json +2 -2
  23. package/openclaw.plugin.json +132 -0
  24. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
1
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
- import { createAccountListHelpers, normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
2
+ import { createAccountListHelpers, normalizeAccountId, resolveAccountEntry, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
3
3
  //#region extensions/signal/src/accounts.ts
4
4
  const { listAccountIds, resolveDefaultAccountId } = createAccountListHelpers("signal", { implicitDefaultAccount: { channelKeys: ["account"] } });
5
5
  const listSignalAccountIds = listAccountIds;
@@ -37,5 +37,23 @@ function listEnabledSignalAccounts(cfg) {
37
37
  accountId
38
38
  })).filter((account) => account.enabled);
39
39
  }
40
+ function normalizeSignalReplyToMode(value) {
41
+ return value === "off" || value === "first" || value === "all" || value === "batched" ? value : void 0;
42
+ }
43
+ function resolveSignalReplyToMode(params) {
44
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSignalAccountId(params.cfg));
45
+ const signalConfig = params.cfg.channels?.signal;
46
+ const accountConfig = resolveAccountEntry(signalConfig?.accounts, accountId);
47
+ const chatType = params.chatType === "direct" || params.chatType === "group" ? params.chatType : void 0;
48
+ if (chatType) {
49
+ const accountScoped = normalizeSignalReplyToMode(accountConfig?.replyToModeByChatType?.[chatType]);
50
+ if (accountScoped) return accountScoped;
51
+ const accountDefault = normalizeSignalReplyToMode(accountConfig?.replyToMode);
52
+ if (accountDefault) return accountDefault;
53
+ const channelScoped = normalizeSignalReplyToMode(signalConfig?.replyToModeByChatType?.[chatType]);
54
+ if (channelScoped) return channelScoped;
55
+ }
56
+ return normalizeSignalReplyToMode(accountConfig?.replyToMode) ?? normalizeSignalReplyToMode(signalConfig?.replyToMode) ?? "all";
57
+ }
40
58
  //#endregion
41
- export { resolveSignalAccount as i, listSignalAccountIds as n, resolveDefaultSignalAccountId as r, listEnabledSignalAccounts as t };
59
+ export { resolveSignalReplyToMode as a, resolveSignalAccount as i, listSignalAccountIds as n, resolveDefaultSignalAccountId as r, listEnabledSignalAccounts as t };
package/dist/api.js CHANGED
@@ -1,12 +1,12 @@
1
- import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-B7Rz3_xV.js";
2
- 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, u as looksLikeSignalTargetId } from "./identity-B6O4k8xg.js";
3
- import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, r as markdownToSignalText, t as signalMessageActions } from "./message-actions-Cs9XckSd.js";
4
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BkAxQPGs.js";
5
- import { a as normalizeSignalAccountInput, l as signalSetupAdapter, n as createSignalPluginBase, r as signalSetupWizard, t as signalPlugin, u as resolveSignalOutboundTarget } from "./channel-BfWp-F-r.js";
6
- import { a as looksLikeArchive, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli } from "./install-signal-cli-TwhJ0DGy.js";
7
- import { t as monitorSignalProvider } from "./monitor-C9SiyrFt.js";
8
- import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-CLzc3RUg.js";
9
- import { t as probeSignal } from "./probe-BL2BqTbG.js";
1
+ import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-Bz4HtP0g.js";
2
+ 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, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
3
+ import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, r as markdownToSignalText, t as signalMessageActions } from "./message-actions-3OLDgjis.js";
4
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-EQ7cc7-Y.js";
5
+ import { a as normalizeSignalAccountInput, l as signalSetupAdapter, n as createSignalPluginBase, r as signalSetupWizard, t as signalPlugin, u as resolveSignalOutboundTarget } from "./channel-Cnhy1RwG.js";
6
+ import { a as looksLikeArchive, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli } from "./install-signal-cli-ik8VPaGg.js";
7
+ import { t as monitorSignalProvider } from "./monitor-Bee8O5Ay.js";
8
+ import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-CUJy6WPt.js";
9
+ import { t as probeSignal } from "./probe-Cnht8Ihg.js";
10
10
  //#region extensions/signal/src/channel.setup.ts
11
11
  const signalSetupPlugin = { ...createSignalPluginBase({
12
12
  setupWizard: signalSetupWizard,
@@ -1,5 +1,5 @@
1
- import { i as resolveSignalAccount } from "./accounts-B7Rz3_xV.js";
2
- import { d as normalizeSignalMessagingTarget, l as looksLikeUuid, u as looksLikeSignalTargetId } from "./identity-B6O4k8xg.js";
1
+ import { i as resolveSignalAccount } from "./accounts-Bz4HtP0g.js";
2
+ import { d as normalizeSignalMessagingTarget, l as looksLikeUuid, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
3
3
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
5
5
  import { normalizeE164 } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -1,8 +1,8 @@
1
- import { r as resolveDefaultSignalAccountId } from "./accounts-B7Rz3_xV.js";
2
- import { d as normalizeSignalMessagingTarget } from "./identity-B6O4k8xg.js";
3
- import { i as resolveSignalTarget } from "./approval-auth-DPVK9A_l.js";
4
- import { a as registerSignalApprovalReactionTarget, c as resolveSignalApprovalTargetAuthorKeys, l as unregisterSignalApprovalReactionTarget, r as hasSignalApprovalReactionApprovers, s as resolveSignalApprovalConversationKey } from "./approval-reactions-5x1kmQEq.js";
5
- import { r as sendTypingSignal, t as sendMessageSignal } from "./send-CLzc3RUg.js";
1
+ import { r as resolveDefaultSignalAccountId } from "./accounts-Bz4HtP0g.js";
2
+ import { d as normalizeSignalMessagingTarget } from "./identity-C8-yk4J9.js";
3
+ import { i as resolveSignalTarget } from "./approval-auth-CsHNcAiy.js";
4
+ import { d as unregisterSignalApprovalReactionTarget, i as hasSignalApprovalReactionApprovers, l as resolveSignalApprovalConversationKey, o as registerSignalApprovalReactionTarget, u as resolveSignalApprovalTargetAuthorKeys } from "./approval-reactions-UFmUPD0A.js";
5
+ import { r as sendTypingSignal, t as sendMessageSignal } from "./send-CUJy6WPt.js";
6
6
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
7
7
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
@@ -1,10 +1,10 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { d as normalizeSignalMessagingTarget, l as looksLikeUuid } from "./identity-B6O4k8xg.js";
3
- import { i as resolveSignalTarget, n as signalApprovalAuth, t as getSignalApprovalApprovers } from "./approval-auth-DPVK9A_l.js";
2
+ import { d as normalizeSignalMessagingTarget, l as looksLikeUuid } from "./identity-C8-yk4J9.js";
3
+ import { i as resolveSignalTarget, n as signalApprovalAuth, t as getSignalApprovalApprovers } from "./approval-auth-CsHNcAiy.js";
4
4
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
- import { buildApprovalReactionHint, createApprovalReactionTargetStore, listApprovalReactionBindings, resolveApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
7
+ import { addApprovalReactionHintToText, buildApprovalReactionHint, createApprovalReactionTargetStore, hasApprovalReactionHintText, listApprovalReactionBindings, resolveApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
8
8
  import { normalizeE164 } from "openclaw/plugin-sdk/text-utility-runtime";
9
9
  import { matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
10
10
  import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-reply-runtime";
@@ -19,13 +19,14 @@ const { setRuntime: setSignalRuntime, getRuntime: getSignalRuntime, tryGetRuntim
19
19
  var approval_reactions_exports = /* @__PURE__ */ __exportAll({
20
20
  addSignalApprovalReactionHintToStructuredPayload: () => addSignalApprovalReactionHintToStructuredPayload,
21
21
  addSignalApprovalReactionHintToText: () => addSignalApprovalReactionHintToText,
22
+ appendSignalApprovalReactionHintForOutboundMessage: () => appendSignalApprovalReactionHintForOutboundMessage,
22
23
  buildSignalApprovalReactionHint: () => buildSignalApprovalReactionHint,
23
24
  clearSignalApprovalReactionTargetsForTest: () => clearSignalApprovalReactionTargetsForTest,
24
25
  hasSignalApprovalReactionApprovers: () => hasSignalApprovalReactionApprovers,
25
- listSignalApprovalReactionBindings: () => listSignalApprovalReactionBindings,
26
26
  maybeResolveSignalApprovalReaction: () => maybeResolveSignalApprovalReaction,
27
27
  registerSignalApprovalReactionTarget: () => registerSignalApprovalReactionTarget,
28
28
  registerSignalApprovalReactionTargetForDeliveredPayload: () => registerSignalApprovalReactionTargetForDeliveredPayload,
29
+ registerSignalApprovalReactionTargetForOutboundMessage: () => registerSignalApprovalReactionTargetForOutboundMessage,
29
30
  resolveSignalApprovalConversationKey: () => resolveSignalApprovalConversationKey,
30
31
  resolveSignalApprovalReactionTargetWithPersistence: () => resolveSignalApprovalReactionTargetWithPersistence,
31
32
  resolveSignalApprovalTargetAuthorKeys: () => resolveSignalApprovalTargetAuthorKeys,
@@ -198,26 +199,46 @@ function listSignalApprovalReactionBindings(allowedDecisions) {
198
199
  function buildSignalApprovalReactionHint(allowedDecisions) {
199
200
  return buildApprovalReactionHint({ allowedDecisions });
200
201
  }
201
- function insertSignalApprovalReactionHintNearHeader(params) {
202
- const lines = params.text.split(/\r?\n/);
203
- const idLineIndex = lines.findIndex((line) => /^ID:\s*\S+/.test(line.trim()));
204
- if (idLineIndex >= 0) {
205
- const before = lines.slice(0, idLineIndex + 1).join("\n");
206
- const after = lines.slice(idLineIndex + 1).join("\n").replace(/^\n+/, "");
207
- return after ? `${before}\n\n${params.hint}\n\n${after}` : `${before}\n\n${params.hint}`;
208
- }
209
- return `${params.hint}\n\n${params.text}`;
210
- }
211
202
  function addSignalApprovalReactionHintToText(params) {
212
- if (hasSignalApprovalReactionHintText(params.text)) return params.text;
213
- const hint = buildSignalApprovalReactionHint(params.allowedDecisions);
214
- return hint ? insertSignalApprovalReactionHintNearHeader({
215
- text: params.text,
216
- hint
217
- }) : params.text;
218
- }
219
- function hasSignalApprovalReactionHintText(text) {
220
- return /(^|\n)React with:\s*(\n|$)/i.test(text ?? "");
203
+ return addApprovalReactionHintToText(params);
204
+ }
205
+ function resolveStandaloneApprovalPromptKind(text) {
206
+ const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
207
+ if (/^(?:🔒\s*)?Exec approval required$/.test(firstLine ?? "")) return "exec";
208
+ if (/^(?:(?:🛡️|🛡|🚨|ℹ️|ℹ)\s*)?Plugin approval required$/.test(firstLine ?? "")) return "plugin";
209
+ return null;
210
+ }
211
+ function isStandaloneApprovalPromptText(text) {
212
+ return resolveStandaloneApprovalPromptKind(text) !== null;
213
+ }
214
+ function normalizeApprovalDecision(value) {
215
+ const normalized = value.trim().toLowerCase();
216
+ if (normalized === "always") return "allow-always";
217
+ if (normalized === "allow-once" || normalized === "allow-always" || normalized === "deny") return normalized;
218
+ return null;
219
+ }
220
+ const APPROVAL_ID_LINE_RE = /^\s*ID:\s*([A-Za-z0-9][A-Za-z0-9._:-]*)\s*$/i;
221
+ const APPROVE_REPLY_COMMAND_LINE_RE = /^\s*Reply with:\s*\/approve(?:@[^\s]+)?\s+([A-Za-z0-9][A-Za-z0-9._:-]*)\s+(.+)$/i;
222
+ function extractSignalApprovalPromptBinding(text) {
223
+ const lines = text.split(/\r?\n/);
224
+ const idHeaderMatch = lines.map((line) => line.match(APPROVAL_ID_LINE_RE)).find((match) => Boolean(match));
225
+ if (!idHeaderMatch) return null;
226
+ const approvalId = idHeaderMatch[1];
227
+ const approvalKind = resolveStandaloneApprovalPromptKind(text) ?? resolveApprovalKindFromId(approvalId);
228
+ const allowedDecisions = [];
229
+ for (const line of lines) {
230
+ const match = line.match(APPROVE_REPLY_COMMAND_LINE_RE);
231
+ if (!match || match[1] !== approvalId) continue;
232
+ for (const decisionText of match[2].split(/[\s|,]+/)) {
233
+ const decision = normalizeApprovalDecision(decisionText);
234
+ if (decision && !allowedDecisions.includes(decision)) allowedDecisions.push(decision);
235
+ }
236
+ }
237
+ return allowedDecisions.length > 0 ? {
238
+ approvalId,
239
+ approvalKind,
240
+ allowedDecisions
241
+ } : null;
221
242
  }
222
243
  function buildTargetRoute(params) {
223
244
  const to = resolveSignalApprovalRouteTarget({
@@ -241,6 +262,36 @@ function buildTargetRoute(params) {
241
262
  }
242
263
  }) ? route : null;
243
264
  }
265
+ function shouldAppendSignalApprovalReactionHintForOutboundMessage(params) {
266
+ const binding = extractSignalApprovalPromptBinding(params.text);
267
+ if (!binding) return false;
268
+ if (resolveSignalApprovalTargetAuthorKeys(params).length === 0) return false;
269
+ if (!hasSignalApprovalReactionApprovers({
270
+ cfg: params.cfg,
271
+ accountId: params.accountId
272
+ })) return false;
273
+ return Boolean(buildTargetRoute({
274
+ cfg: params.cfg,
275
+ accountId: params.accountId,
276
+ to: params.to,
277
+ approvalId: binding.approvalId,
278
+ approvalKind: binding.approvalKind,
279
+ agentId: params.agentId,
280
+ sessionKey: params.sessionKey
281
+ }));
282
+ }
283
+ function appendSignalApprovalReactionHintForOutboundMessage(params) {
284
+ if (!isStandaloneApprovalPromptText(params.text)) return params.text;
285
+ const binding = extractSignalApprovalPromptBinding(params.text);
286
+ if (!binding || !shouldAppendSignalApprovalReactionHintForOutboundMessage({
287
+ ...params,
288
+ text: params.text
289
+ })) return params.text;
290
+ return addSignalApprovalReactionHintToText({
291
+ text: params.text,
292
+ allowedDecisions: binding.allowedDecisions
293
+ });
294
+ }
244
295
  function hasSignalApprovalReactionApprovers(params) {
245
296
  return getSignalApprovalApprovers(params).length > 0;
246
297
  }
@@ -298,8 +349,7 @@ function addSignalApprovalReactionHintToStructuredPayload(params) {
298
349
  };
299
350
  }
300
351
  function readSignalDeliveryVisibleText(result) {
301
- const meta = result.meta;
302
- const visibleText = meta?.signalVisibleText ?? meta?.visibleText;
352
+ const visibleText = result.meta?.signalVisibleText ?? result.meta?.visibleText;
303
353
  return typeof visibleText === "string" ? visibleText : null;
304
354
  }
305
355
  function listDeliveredSignalMessageIdsWithVisibleHint(params) {
@@ -307,14 +357,14 @@ function listDeliveredSignalMessageIdsWithVisibleHint(params) {
307
357
  const resultsWithVisibleText = signalResults.filter((result) => readSignalDeliveryVisibleText(result) !== null);
308
358
  const candidates = resultsWithVisibleText.length > 0 ? resultsWithVisibleText : signalResults;
309
359
  if (resultsWithVisibleText.length === 0 && candidates.length !== 1) return [];
310
- const ids = candidates.filter((result) => resultsWithVisibleText.length > 0 ? hasSignalApprovalReactionHintText(readSignalDeliveryVisibleText(result)) : hasSignalApprovalReactionHintText(params.payload.text)).map((result) => normalizeOptionalString(result.messageId)).filter((messageId) => Boolean(messageId && messageId !== "unknown"));
360
+ const ids = candidates.filter((result) => resultsWithVisibleText.length > 0 ? hasApprovalReactionHintText(readSignalDeliveryVisibleText(result)) : hasApprovalReactionHintText(params.payload.text)).map((result) => normalizeOptionalString(result.messageId)).filter((messageId) => Boolean(messageId && messageId !== "unknown"));
311
361
  return Array.from(new Set(ids));
312
362
  }
313
363
  function registerSignalApprovalReactionTargetForDeliveredPayload(params) {
314
364
  if (normalizeLowercaseStringOrEmpty(params.target.channel) !== "signal") return false;
315
365
  const metadata = getExecApprovalReplyMetadata(params.payload);
316
366
  if (!metadata?.allowedDecisions || metadata.allowedDecisions.length === 0) return false;
317
- if (!hasSignalApprovalReactionHintText(params.payload.text)) return false;
367
+ if (!hasApprovalReactionHintText(params.payload.text)) return false;
318
368
  if (!hasSignalApprovalReactionApprovers({
319
369
  cfg: params.cfg,
320
370
  accountId: params.target.accountId
@@ -355,6 +405,41 @@ function registerSignalApprovalReactionTargetForDeliveredPayload(params) {
355
405
  })) || registered;
356
406
  return registered;
357
407
  }
408
+ function registerSignalApprovalReactionTargetForOutboundMessage(params) {
409
+ if (!isStandaloneApprovalPromptText(params.text)) return false;
410
+ const binding = extractSignalApprovalPromptBinding(params.text);
411
+ if (!binding) return false;
412
+ if (!hasSignalApprovalReactionApprovers({
413
+ cfg: params.cfg,
414
+ accountId: params.accountId
415
+ })) return false;
416
+ const targetAuthorKeys = resolveSignalApprovalTargetAuthorKeys(params);
417
+ if (targetAuthorKeys.length === 0) return false;
418
+ const conversationKey = resolveSignalApprovalConversationKey(params.to);
419
+ if (!conversationKey) return false;
420
+ const route = buildTargetRoute({
421
+ cfg: params.cfg,
422
+ accountId: params.accountId,
423
+ to: params.to,
424
+ approvalId: binding.approvalId,
425
+ approvalKind: binding.approvalKind,
426
+ agentId: params.agentId,
427
+ sessionKey: params.sessionKey
428
+ });
429
+ if (!route) return false;
430
+ return Boolean(registerSignalApprovalReactionTarget({
431
+ accountId: params.accountId,
432
+ conversationKey,
433
+ messageId: params.messageId,
434
+ approvalId: binding.approvalId,
435
+ approvalKind: binding.approvalKind,
436
+ allowedDecisions: binding.allowedDecisions,
437
+ targetAuthorKeys,
438
+ route,
439
+ routeAllowed: true,
440
+ ttlMs: params.ttlMs
441
+ }));
442
+ }
358
443
  function unregisterSignalApprovalReactionTarget(params) {
359
444
  const key = buildReactionTargetKey(params);
360
445
  if (!key) return;
@@ -456,4 +541,4 @@ function clearSignalApprovalReactionTargetsForTest() {
456
541
  resolverRuntimeLoader.clear();
457
542
  }
458
543
  //#endregion
459
- export { registerSignalApprovalReactionTarget as a, resolveSignalApprovalTargetAuthorKeys as c, maybeResolveSignalApprovalReaction as i, unregisterSignalApprovalReactionTarget as l, approval_reactions_exports as n, registerSignalApprovalReactionTargetForDeliveredPayload as o, hasSignalApprovalReactionApprovers as r, resolveSignalApprovalConversationKey as s, addSignalApprovalReactionHintToStructuredPayload as t, setSignalRuntime as u };
544
+ export { maybeResolveSignalApprovalReaction as a, registerSignalApprovalReactionTargetForOutboundMessage as c, unregisterSignalApprovalReactionTarget as d, setSignalRuntime as f, hasSignalApprovalReactionApprovers as i, resolveSignalApprovalConversationKey as l, appendSignalApprovalReactionHintForOutboundMessage as n, registerSignalApprovalReactionTarget as o, approval_reactions_exports as r, registerSignalApprovalReactionTargetForDeliveredPayload as s, addSignalApprovalReactionHintToStructuredPayload as t, resolveSignalApprovalTargetAuthorKeys as u };
@@ -1,14 +1,14 @@
1
- import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId } from "./accounts-B7Rz3_xV.js";
2
- import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-B6O4k8xg.js";
3
- import { i as resolveSignalTarget, r as listSignalAliasDirectoryEntries } from "./approval-auth-DPVK9A_l.js";
4
- import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, o as shouldSuppressLocalSignalExecApprovalPrompt, s as signalApprovalCapability, t as signalMessageActions } from "./message-actions-Cs9XckSd.js";
1
+ import { a as resolveSignalReplyToMode, i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId } from "./accounts-Bz4HtP0g.js";
2
+ import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
3
+ import { i as resolveSignalTarget, r as listSignalAliasDirectoryEntries } from "./approval-auth-CsHNcAiy.js";
4
+ import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, o as shouldSuppressLocalSignalExecApprovalPrompt, s as signalApprovalCapability, t as signalMessageActions } from "./message-actions-3OLDgjis.js";
5
5
  import { t as SignalChannelConfigSchema } from "./config-schema-BiojLEsX.js";
6
6
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
7
7
  import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
8
8
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
9
9
  import { defineChannelMessageAdapter, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
10
10
  import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
11
- import { attachChannelToResult, attachChannelToResults } from "openclaw/plugin-sdk/channel-send-result";
11
+ import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
12
12
  import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
13
13
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
14
14
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
@@ -74,7 +74,10 @@ const INVALID_SIGNAL_ACCOUNT_ERROR = "Invalid E.164 phone number (must start wit
74
74
  function normalizeSignalAccountInput(value) {
75
75
  const trimmed = normalizeOptionalString(value);
76
76
  if (!trimmed) return null;
77
- const digits = normalizeE164(trimmed).slice(1);
77
+ const phoneInput = trimmed.replace(/^signal:/i, "").trim();
78
+ const plusCount = phoneInput.match(/\+/g)?.length ?? 0;
79
+ if (plusCount > 1 || plusCount === 1 && !phoneInput.startsWith("+")) return null;
80
+ const digits = normalizeE164(phoneInput).slice(1);
78
81
  if (!DIGITS_ONLY.test(digits)) return null;
79
82
  if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null;
80
83
  return `+${digits}`;
@@ -237,7 +240,7 @@ function createSignalSetupWizardProxy(loadWizard) {
237
240
  //#region extensions/signal/src/shared.ts
238
241
  const SIGNAL_CHANNEL = "signal";
239
242
  async function loadSignalChannelRuntime() {
240
- return await import("./channel.runtime-Ks7GIWM1.js");
243
+ return await import("./channel.runtime-CQN0RaFx.js");
241
244
  }
242
245
  const signalSetupWizard = createSignalSetupWizardProxy(async () => (await loadSignalChannelRuntime()).signalSetupWizard);
243
246
  const signalConfigAdapter = {
@@ -323,10 +326,10 @@ function createSignalPluginBase(params) {
323
326
  }
324
327
  //#endregion
325
328
  //#region extensions/signal/src/channel.ts
326
- const loadSignalMonitorModule = createLazyRuntimeModule(() => import("./monitor-C9SiyrFt.js").then((n) => n.n));
327
- const loadSignalProbeModule = createLazyRuntimeModule(() => import("./probe-BL2BqTbG.js").then((n) => n.n));
328
- const loadSignalSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-DgijYwpJ.js"));
329
- const loadSignalApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-5x1kmQEq.js").then((n) => n.n));
329
+ const loadSignalMonitorModule = createLazyRuntimeModule(() => import("./monitor-Bee8O5Ay.js").then((n) => n.n));
330
+ const loadSignalProbeModule = createLazyRuntimeModule(() => import("./probe-Cnht8Ihg.js").then((n) => n.n));
331
+ const loadSignalSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CEi5oyCG.js"));
332
+ const loadSignalApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-UFmUPD0A.js").then((n) => n.r));
330
333
  async function resolveSignalSendContext(params) {
331
334
  return {
332
335
  send: resolveOutboundSendDep(params.deps, "signal") ?? (await loadSignalSendRuntime()).sendMessageSignal,
@@ -408,8 +411,11 @@ function buildSignalBaseSessionKey(params) {
408
411
  });
409
412
  }
410
413
  function resolveSignalOutboundSessionRoute(params) {
411
- const resolved = resolveSignalOutboundTarget(params.resolvedTarget?.to ?? params.target);
414
+ const target = params.resolvedTarget?.to ?? params.target;
415
+ const resolved = resolveSignalOutboundTarget(target);
412
416
  if (!resolved) return null;
417
+ const normalizedTarget = target.replace(/^signal:/i, "").trim();
418
+ const recipientSessionExact = resolved.chatType === "group" || /^\+?\d{3,15}$/.test(normalizedTarget) ? true : "direct-alias";
413
419
  const baseSessionKey = buildSignalBaseSessionKey({
414
420
  cfg: params.cfg,
415
421
  agentId: params.agentId,
@@ -419,6 +425,7 @@ function resolveSignalOutboundSessionRoute(params) {
419
425
  return {
420
426
  sessionKey: baseSessionKey,
421
427
  baseSessionKey,
428
+ recipientSessionExact,
422
429
  ...resolved
423
430
  };
424
431
  }
@@ -447,16 +454,17 @@ async function sendFormattedSignalText(ctx) {
447
454
  const results = [];
448
455
  for (const chunk of chunks) {
449
456
  ctx.abortSignal?.throwIfAborted();
450
- const result = await send(to, chunk.text, {
457
+ const deliveryResult = attachChannelToResult("signal", attachSignalVisibleText(await send(to, chunk.text, {
451
458
  cfg: ctx.cfg,
452
459
  maxBytes,
453
460
  accountId: ctx.accountId ?? void 0,
454
461
  textMode: "plain",
455
462
  textStyles: chunk.styles
456
- });
457
- results.push(attachSignalVisibleText(result, chunk.text));
463
+ }), chunk.text));
464
+ results.push(deliveryResult);
465
+ await ctx.onDeliveryResult?.(deliveryResult);
458
466
  }
459
- return attachChannelToResults("signal", results);
467
+ return results;
460
468
  }
461
469
  async function sendFormattedSignalMedia(ctx) {
462
470
  ctx.abortSignal?.throwIfAborted();
@@ -495,14 +503,20 @@ async function registerDeliveredSignalApprovalPayloadForReactions(params) {
495
503
  cfg: params.cfg,
496
504
  accountId: params.target.accountId ?? void 0
497
505
  });
498
- if (!account.config.account) return;
506
+ const targetAuthor = normalizeOptionalString(account.config.account);
507
+ const targetAuthorUuid = normalizeOptionalString(account.config.accountUuid);
508
+ if (!targetAuthor && !targetAuthorUuid) return;
499
509
  const { registerSignalApprovalReactionTargetForDeliveredPayload } = await loadSignalApprovalReactionsModule();
500
510
  registerSignalApprovalReactionTargetForDeliveredPayload({
501
511
  cfg: params.cfg,
502
- target: params.target,
512
+ target: {
513
+ ...params.target,
514
+ accountId: account.accountId
515
+ },
503
516
  payload: params.payload,
504
517
  results: params.results,
505
- targetAuthor: account.config.account
518
+ targetAuthor,
519
+ targetAuthorUuid
506
520
  });
507
521
  }
508
522
  async function renderSignalApprovalPayloadForReactions(params) {
@@ -510,14 +524,17 @@ async function renderSignalApprovalPayloadForReactions(params) {
510
524
  cfg: params.ctx.cfg,
511
525
  accountId: params.ctx.accountId ?? void 0
512
526
  });
513
- if (!account.config.account) return null;
527
+ const targetAuthor = normalizeOptionalString(account.config.account);
528
+ const targetAuthorUuid = normalizeOptionalString(account.config.accountUuid);
529
+ if (!targetAuthor && !targetAuthorUuid) return null;
514
530
  const { addSignalApprovalReactionHintToStructuredPayload } = await loadSignalApprovalReactionsModule();
515
531
  return addSignalApprovalReactionHintToStructuredPayload({
516
532
  cfg: params.ctx.cfg,
517
533
  accountId: params.ctx.accountId ?? void 0,
518
534
  to: params.ctx.to,
519
535
  payload: params.payload,
520
- targetAuthor: account.config.account
536
+ targetAuthor,
537
+ targetAuthorUuid
521
538
  });
522
539
  }
523
540
  const signalPlugin = createChatChannelPlugin({
@@ -661,6 +678,7 @@ const signalPlugin = createChatChannelPlugin({
661
678
  }
662
679
  } },
663
680
  security: signalSecurityAdapter,
681
+ threading: { resolveReplyToMode: (params) => resolveSignalReplyToMode(params) },
664
682
  outbound: {
665
683
  base: {
666
684
  deliveryMode: "direct",
@@ -704,13 +722,14 @@ const signalPlugin = createChatChannelPlugin({
704
722
  }),
705
723
  afterDeliverPayload: async (params) => await registerDeliveredSignalApprovalPayloadForReactions(params),
706
724
  renderPresentation: async (params) => await renderSignalApprovalPayloadForReactions(params),
707
- sendFormattedText: async ({ cfg, to, text, accountId, deps, abortSignal }) => await sendFormattedSignalText({
725
+ sendFormattedText: async ({ cfg, to, text, accountId, deps, abortSignal, onDeliveryResult }) => await sendFormattedSignalText({
708
726
  cfg,
709
727
  to,
710
728
  text,
711
729
  accountId,
712
730
  deps,
713
- abortSignal
731
+ abortSignal,
732
+ onDeliveryResult
714
733
  }),
715
734
  sendFormattedMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, accountId, deps, abortSignal }) => await sendFormattedSignalMedia({
716
735
  cfg,
@@ -1,2 +1,2 @@
1
- import { t as signalPlugin } from "./channel-BfWp-F-r.js";
1
+ import { t as signalPlugin } from "./channel-Cnhy1RwG.js";
2
2
  export { signalPlugin };
@@ -1,6 +1,6 @@
1
- import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-B7Rz3_xV.js";
2
- import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-BfWp-F-r.js";
3
- import { r as installSignalCli } from "./install-signal-cli-TwhJ0DGy.js";
1
+ import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-Bz4HtP0g.js";
2
+ import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-Cnhy1RwG.js";
3
+ import { r as installSignalCli } from "./install-signal-cli-ik8VPaGg.js";
4
4
  import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
5
5
  import { createDetectedBinaryStatus, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
6
6
  //#region extensions/signal/src/setup-surface.ts
@@ -1,10 +1,10 @@
1
1
  import { detectMime, parseMediaContentLength } from "openclaw/plugin-sdk/media-runtime";
2
2
  import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
3
- import fs from "node:fs/promises";
4
- import path from "node:path";
3
+ import nodePath from "node:path";
5
4
  import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
6
5
  import { readProviderTextResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
7
6
  import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
7
+ import { readRegularFile } from "openclaw/plugin-sdk/security-runtime";
8
8
  import WebSocket from "ws";
9
9
  import { Buffer as Buffer$1 } from "node:buffer";
10
10
  import http from "node:http";
@@ -21,6 +21,8 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
21
21
  */
22
22
  const DEFAULT_TIMEOUT_MS$2 = 1e4;
23
23
  const DEFAULT_ATTACHMENT_RESPONSE_MAX_BYTES = 1048576;
24
+ const SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES = 1024 * 1024;
25
+ const DEFAULT_SIGNAL_CONTAINER_MAX_ATTACHMENT_BYTES = 8 * 1024 * 1024;
24
26
  const CONTAINER_TEXT_STYLE_MARKERS = {
25
27
  BOLD: "**",
26
28
  ITALIC: "*",
@@ -120,7 +122,7 @@ function containerReceiveCheck(normalizedBaseUrl, account, timeoutMs) {
120
122
  resolve(result);
121
123
  };
122
124
  try {
123
- ws = new WebSocket(wsUrl);
125
+ ws = new WebSocket(wsUrl, { maxPayload: SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES });
124
126
  } catch (err) {
125
127
  settle({
126
128
  ok: false,
@@ -153,10 +155,11 @@ function containerReceiveCheck(normalizedBaseUrl, account, timeoutMs) {
153
155
  });
154
156
  });
155
157
  ws.once("close", (code, reason) => {
158
+ const reasonText = reason.length > 0 ? `: ${reason.toString("utf8")}` : "";
156
159
  settle({
157
160
  ok: false,
158
161
  status: null,
159
- error: `Signal container receive WebSocket closed before open (${code}${reason.length > 0 ? `: ${reason.toString("utf8")}` : ""})`
162
+ error: `Signal container receive WebSocket closed before open (${code}${reasonText})`
160
163
  });
161
164
  });
162
165
  });
@@ -224,7 +227,7 @@ async function streamContainerEvents(params) {
224
227
  }
225
228
  };
226
229
  try {
227
- ws = new WebSocket(wsUrl);
230
+ ws = new WebSocket(wsUrl, { maxPayload: SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES });
228
231
  } catch (err) {
229
232
  logError(`[signal-ws] failed to create WebSocket: ${err instanceof Error ? err.message : String(err)}`);
230
233
  reject(toLintErrorObject$1(err, "Non-Error rejection"));
@@ -246,7 +249,8 @@ async function streamContainerEvents(params) {
246
249
  logError(`[signal-ws] error: ${err instanceof Error ? err.message : String(err)}`);
247
250
  });
248
251
  ws.on("close", (code, reason) => {
249
- log(`[signal-ws] closed (code=${code}, reason=${reason?.toString() || "no reason"})`);
252
+ const reasonStr = reason?.toString() || "no reason";
253
+ log(`[signal-ws] closed (code=${code}, reason=${reasonStr})`);
250
254
  cleanup();
251
255
  resolve();
252
256
  });
@@ -271,15 +275,20 @@ async function streamContainerEvents(params) {
271
275
  * Convert local file paths to base64 data URIs for the container REST API.
272
276
  * The bbernhard container /v2/send only accepts `base64_attachments` (not file paths).
273
277
  */
274
- async function filesToBase64DataUris(filePaths) {
278
+ async function filesToBase64DataUris(filePaths, maxAttachmentBytes) {
275
279
  const results = [];
280
+ let remainingBytes = maxAttachmentBytes;
276
281
  for (const filePath of filePaths) {
277
- const buffer = await fs.readFile(filePath);
282
+ const { buffer } = await readRegularFile({
283
+ filePath,
284
+ maxBytes: remainingBytes
285
+ });
286
+ remainingBytes -= buffer.byteLength;
278
287
  const mime = await detectMime({
279
288
  buffer,
280
289
  filePath
281
290
  }) ?? "application/octet-stream";
282
- const filename = path.basename(filePath);
291
+ const filename = nodePath.basename(filePath);
283
292
  const b64 = buffer.toString("base64");
284
293
  results.push(`data:${mime};filename=${filename};base64,${b64}`);
285
294
  }
@@ -302,7 +311,7 @@ function renderContainerStyledText(text, styles) {
302
311
  };
303
312
  }).filter((span) => span !== null);
304
313
  if (spans.length === 0) return text;
305
- const positions = [...new Set([
314
+ const positions = [.../* @__PURE__ */ new Set([
306
315
  0,
307
316
  text.length,
308
317
  ...spans.flatMap((span) => [span.start, span.end])
@@ -323,6 +332,12 @@ function parseContainerSendTimestamp(raw) {
323
332
  if (timestamp === void 0) throw new Error("Signal REST send returned invalid timestamp");
324
333
  return timestamp;
325
334
  }
335
+ function normalizeContainerQuoteTimestamp(raw) {
336
+ return parseStrictNonNegativeInteger(raw) ?? void 0;
337
+ }
338
+ function normalizeContainerQuoteText(raw) {
339
+ return typeof raw === "string" ? raw : void 0;
340
+ }
326
341
  /**
327
342
  * Send message via bbernhard container REST API.
328
343
  */
@@ -336,7 +351,16 @@ async function containerSendMessage(params) {
336
351
  payload.message = renderContainerStyledText(params.message, params.textStyles);
337
352
  payload["text_mode"] = "styled";
338
353
  }
339
- if (params.attachments && params.attachments.length > 0) payload.base64_attachments = await filesToBase64DataUris(params.attachments);
354
+ if (params.attachments && params.attachments.length > 0) {
355
+ const configuredMaxBytes = params.maxAttachmentBytes;
356
+ const maxAttachmentBytes = typeof configuredMaxBytes === "number" && Number.isFinite(configuredMaxBytes) && configuredMaxBytes >= 0 ? Math.floor(configuredMaxBytes) : DEFAULT_SIGNAL_CONTAINER_MAX_ATTACHMENT_BYTES;
357
+ payload.base64_attachments = await filesToBase64DataUris(params.attachments, maxAttachmentBytes);
358
+ }
359
+ if (params.quoteTimestamp !== void 0 && params.quoteAuthor) {
360
+ payload.quote_timestamp = params.quoteTimestamp;
361
+ payload.quote_author = params.quoteAuthor;
362
+ payload.quote_message = params.quoteMessage ?? "";
363
+ }
340
364
  const timestamp = parseContainerSendTimestamp((await containerRestRequest("/v2/send", {
341
365
  baseUrl: params.baseUrl,
342
366
  timeoutMs: params.timeoutMs
@@ -437,6 +461,8 @@ async function containerRpcRequest(method, params, opts) {
437
461
  style
438
462
  };
439
463
  });
464
+ const quoteTimestamp = normalizeContainerQuoteTimestamp(p.quoteTimestamp ?? p["quote-timestamp"]);
465
+ const quoteAuthor = normalizeContainerQuoteText(p.quoteAuthor ?? p["quote-author"]);
440
466
  return await containerSendMessage({
441
467
  baseUrl: opts.baseUrl,
442
468
  account: p.account ?? "",
@@ -444,6 +470,10 @@ async function containerRpcRequest(method, params, opts) {
444
470
  message: p.message ?? "",
445
471
  textStyles,
446
472
  attachments: p.attachments,
473
+ maxAttachmentBytes: opts.maxAttachmentBytes,
474
+ quoteTimestamp,
475
+ quoteAuthor: quoteAuthor ? stripUuidPrefix(quoteAuthor) : void 0,
476
+ quoteMessage: normalizeContainerQuoteText(p.quoteMessage ?? p["quote-message"]),
447
477
  timeoutMs: opts.timeoutMs
448
478
  });
449
479
  }
@@ -1,3 +1,3 @@
1
- import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-B6O4k8xg.js";
2
- import { a as looksLikeArchive, i as installSignalCliFromRelease, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli, t as downloadToFile } from "./install-signal-cli-TwhJ0DGy.js";
1
+ import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
2
+ import { a as looksLikeArchive, i as installSignalCliFromRelease, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli, t as downloadToFile } from "./install-signal-cli-ik8VPaGg.js";
3
3
  export { downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeArchive, looksLikeSignalTargetId, normalizeSignalMessagingTarget, pickAsset };