@openclaw/signal 2026.7.2-beta.4 → 2026.7.2-beta.7

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 (25) hide show
  1. package/dist/api.js +6 -6
  2. package/dist/{approval-handler.runtime-C2qf7D0D.js → approval-handler.runtime-C-XYgcxE.js} +4 -4
  3. package/dist/{approval-reactions-5uyOazxW.js → approval-reactions-DtL47gSK.js} +2 -2
  4. package/dist/{channel-DQ9i00A8.js → channel-CmbWaYlm.js} +20 -39
  5. package/dist/channel-config-api.js +1 -1
  6. package/dist/channel-plugin-api.js +1 -1
  7. package/dist/{channel.runtime-DWQdFD2O.js → channel.runtime-BRDaqr5-.js} +1 -1
  8. package/dist/{client-yjbwtufN.js → client-BazXTH7O.js} +5 -19
  9. package/dist/{client-adapter-Bm0ZRqJn.js → client-adapter-mXGeEHQJ.js} +1 -1
  10. package/dist/{config-schema-DLvpQPN5.js → config-schema-Y3dFGwdL.js} +1 -3
  11. package/dist/{doctor-contract-api-DbUCknbC.js → doctor-contract-api-Dcte-QYB.js} +29 -34
  12. package/dist/doctor-contract-api.js +1 -1
  13. package/dist/{monitor-C0aBYlJ0.js → monitor-BvIzkrYW.js} +61 -106
  14. package/dist/{probe-2yf2hpcc.js → probe-Br9abaGp.js} +37 -39
  15. package/dist/{question-reactions-DJ1xQzVF.js → question-reactions-Ds48FtEu.js} +1 -1
  16. package/dist/{reaction-runtime-api-Bka61qO9.js → reaction-runtime-api-BjeDyKcz.js} +1 -1
  17. package/dist/reaction-runtime-api.js +1 -1
  18. package/dist/runtime-api.js +6 -6
  19. package/dist/{send-BZAqAa8p.js → send-B_Ks4MZr.js} +21 -3
  20. package/dist/{send.runtime-CcA5Qei9.js → send.runtime-CbuXycZT.js} +1 -1
  21. package/dist/{transport-detection-CiZWiMYa.js → transport-detection-Da06-LOL.js} +12 -46
  22. package/dist/{transport-detection.runtime-BgjcIyww.js → transport-detection.runtime-D_190UUL.js} +1 -1
  23. package/dist/{transport-probes.runtime-CbnZn38-.js → transport-probes.runtime-CV6Qs0Og.js} +1 -1
  24. package/package.json +4 -5
  25. package/npm-shrinkwrap.json +0 -46
package/dist/api.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DrStJjiK.js";
2
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-BQ4OzXXk.js";
3
- import { a as signalMessageActions, c as markdownToSignalText, l as markdownToSignalTextChunks, o as resolveSignalReactionLevel, t as detectSignalTransport } from "./transport-detection-CiZWiMYa.js";
4
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-Bka61qO9.js";
5
- import { a as normalizeSignalAccountInput, d as probeSignalTransport, f as writeSignalAccountTransport, l as signalSetupContract, n as createSignalPluginBase, p as resolveSignalOutboundTarget, r as signalSetupWizard, t as signalPlugin, u as prepareSignalManagedNativeTransport } from "./channel-DQ9i00A8.js";
3
+ import { a as signalMessageActions, c as markdownToSignalText, l as markdownToSignalTextChunks, o as resolveSignalReactionLevel, t as detectSignalTransport } from "./transport-detection-Da06-LOL.js";
4
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
5
+ import { a as normalizeSignalAccountInput, d as probeSignalTransport, f as writeSignalAccountTransport, l as signalSetupContract, n as createSignalPluginBase, p as resolveSignalOutboundTarget, r as signalSetupWizard, t as signalPlugin, u as prepareSignalManagedNativeTransport } from "./channel-CmbWaYlm.js";
6
6
  import { i as installSignalCli, o as looksLikeArchive, r as extractSignalCliArchive, s as pickAsset } from "./install-signal-cli-qJF7iC4h.js";
7
- import { t as monitorSignalProvider } from "./monitor-C0aBYlJ0.js";
8
- import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-BZAqAa8p.js";
9
- import { t as probeSignal } from "./probe-2yf2hpcc.js";
7
+ import { t as monitorSignalProvider } from "./monitor-BvIzkrYW.js";
8
+ import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-B_Ks4MZr.js";
9
+ import { t as probeSignal } from "./probe-Br9abaGp.js";
10
10
  //#region extensions/signal/src/channel.setup.ts
11
11
  const signalSetupPlugin = { ...createSignalPluginBase({
12
12
  setupWizard: signalSetupWizard,
@@ -1,8 +1,8 @@
1
1
  import { r as resolveDefaultSignalAccountId } from "./accounts-DrStJjiK.js";
2
2
  import { d as normalizeSignalMessagingTarget } from "./identity-BQ4OzXXk.js";
3
3
  import { o as resolveSignalTarget } from "./runtime-JPrGlV7h.js";
4
- import { d as unregisterSignalApprovalReactionTarget, i as hasSignalApprovalReactionApprovers, l as resolveSignalApprovalConversationKey, o as registerSignalApprovalReactionTarget, u as resolveSignalApprovalTargetAuthorKeys } from "./approval-reactions-5uyOazxW.js";
5
- import { r as sendTypingSignal, t as sendMessageSignal } from "./send-BZAqAa8p.js";
4
+ import { d as unregisterSignalApprovalReactionTarget, i as hasSignalApprovalReactionApprovers, l as resolveSignalApprovalConversationKey, o as registerSignalApprovalReactionTarget, u as resolveSignalApprovalTargetAuthorKeys } from "./approval-reactions-DtL47gSK.js";
5
+ import { r as sendTypingSignal, t as sendMessageSignal } from "./send-B_Ks4MZr.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";
@@ -109,7 +109,7 @@ const signalApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
109
109
  accountId: preparedTarget.accountId,
110
110
  ...preparedTarget.baseUrl ? { baseUrl: preparedTarget.baseUrl } : {},
111
111
  ...preparedTarget.account ? { account: preparedTarget.account } : {},
112
- textMode: "plain"
112
+ textMode: "markdown"
113
113
  });
114
114
  if (!result.messageId || result.messageId === "unknown") return null;
115
115
  const conversationKey = resolveSignalApprovalConversationKey(preparedTarget.to);
@@ -131,7 +131,7 @@ const signalApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
131
131
  accountId: entry.accountId,
132
132
  ...entry.baseUrl ? { baseUrl: entry.baseUrl } : {},
133
133
  ...entry.account ? { account: entry.account } : {},
134
- textMode: "plain"
134
+ textMode: "markdown"
135
135
  });
136
136
  }
137
137
  },
@@ -193,7 +193,7 @@ function addSignalApprovalReactionHintToText(params) {
193
193
  return addApprovalReactionHintToText(params);
194
194
  }
195
195
  function resolveStandaloneApprovalPromptKind(text) {
196
- const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
196
+ const firstLine = text.split(/\r?\n/).map((line) => line.replace(/\*\*/g, "").trim()).find(Boolean);
197
197
  if (/^(?:🔒\s*)?Exec approval required$/.test(firstLine ?? "")) return "exec";
198
198
  if (/^(?:(?:🛡️|🛡|🚨|ℹ️|ℹ)\s*)?Plugin approval required$/.test(firstLine ?? "")) return "plugin";
199
199
  return null;
@@ -210,7 +210,7 @@ function normalizeApprovalDecision(value) {
210
210
  const APPROVAL_ID_LINE_RE = /^\s*ID:\s*([A-Za-z0-9][A-Za-z0-9._:-]*)\s*$/i;
211
211
  const APPROVE_REPLY_COMMAND_LINE_RE = /^\s*Reply with:\s*\/approve(?:@[^\s]+)?\s+([A-Za-z0-9][A-Za-z0-9._:-]*)\s+(.+)$/i;
212
212
  function extractSignalApprovalPromptBinding(text) {
213
- const lines = text.split(/\r?\n/);
213
+ const lines = text.split(/\r?\n/).map((line) => line.replace(/\*\*/g, ""));
214
214
  const idHeaderMatch = lines.map((line) => line.match(APPROVAL_ID_LINE_RE)).find((match) => Boolean(match));
215
215
  if (!idHeaderMatch) return null;
216
216
  const approvalId = idHeaderMatch[1];
@@ -2,9 +2,9 @@ import { a as isSignalManagedNativeConnectionUrlForBind, i as assignSignalManage
2
2
  import { a as resolveSignalAccountConfig, i as resolveSignalAccount, n as listSignalAccountIds, o as resolveSignalReplyToMode, r as resolveDefaultSignalAccountId, s as resolveSignalTransport } from "./accounts-DrStJjiK.js";
3
3
  import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-BQ4OzXXk.js";
4
4
  import { a as listSignalAliasDirectoryEntries, o as resolveSignalTarget } from "./runtime-JPrGlV7h.js";
5
- import { a as signalMessageActions, d as shouldSuppressLocalSignalExecApprovalPrompt, f as signalApprovalCapability, i as materializeSignalPresentationFallback, l as markdownToSignalTextChunks, o as resolveSignalReactionLevel, r as resolveSignalReplyContextWithPersistence, s as formatSignalMediaText, t as detectSignalTransport } from "./transport-detection-CiZWiMYa.js";
6
- import { i as migrateLegacySignalTransportConfig, n as normalizeCompatibilityConfig, r as clearLegacySignalTransportFieldsForAccount } from "./doctor-contract-api-DbUCknbC.js";
7
- import { t as SignalChannelConfigSchema } from "./config-schema-DLvpQPN5.js";
5
+ import { a as signalMessageActions, d as shouldSuppressLocalSignalExecApprovalPrompt, f as signalApprovalCapability, i as materializeSignalPresentationFallback, l as markdownToSignalTextChunks, o as resolveSignalReactionLevel, r as resolveSignalReplyContextWithPersistence, s as formatSignalMediaText, t as detectSignalTransport } from "./transport-detection-Da06-LOL.js";
6
+ import { i as migrateLegacySignalTransportConfig, n as normalizeCompatibilityConfig, r as clearLegacySignalTransportFieldsForAccount } from "./doctor-contract-api-Dcte-QYB.js";
7
+ import { t as SignalChannelConfigSchema } from "./config-schema-Y3dFGwdL.js";
8
8
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
9
9
  import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
10
10
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
@@ -24,8 +24,10 @@ import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking"
24
24
  import { normalizeAccountId as normalizeAccountId$1, resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
25
25
  import { normalizeE164 } from "openclaw/plugin-sdk/text-utility-runtime";
26
26
  import { createChannelPluginBase, getChatChannelMeta } from "openclaw/plugin-sdk/core";
27
+ import { parseAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
28
+ import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
27
29
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
28
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, createCliPathTextInput, createDelegatedSetupWizardProxy, createDelegatedTextInputShouldPrompt, createPatchedAccountSetupAdapter, createSetupInputPresenceValidator, createSetupTranslator, mergeAllowFromEntries, parseSetupEntriesAllowingWildcard, patchChannelConfigForAccount, promptParsedAllowFromForAccount, setAccountAllowFromForChannel, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup-runtime";
30
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, createCliPathTextInput, createDelegatedSetupWizardProxy, createDelegatedTextInputShouldPrompt, createPatchedAccountSetupAdapter, createSetupInputPresenceValidator, createSetupTranslator, patchChannelConfigForAccount, promptParsedAllowFromForAccount, setAccountAllowFromForChannel, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup-runtime";
29
31
  import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
30
32
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
31
33
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
@@ -211,8 +213,8 @@ async function probeSignalTransport(params) {
211
213
  accountId: params.accountId,
212
214
  overrides: managedTransportOptions(params.transport)
213
215
  }) : params.transport);
214
- if (resolved.kind === "container") return (params.probeContainer ?? (await import("./transport-probes.runtime-CbnZn38-.js")).containerCheck)(resolved.baseUrl, timeoutMs, params.account);
215
- return (params.probeNative ?? (await import("./transport-probes.runtime-CbnZn38-.js")).nativeCheck)(resolved.baseUrl, timeoutMs);
216
+ if (resolved.kind === "container") return (params.probeContainer ?? (await import("./transport-probes.runtime-CV6Qs0Og.js")).containerCheck)(resolved.baseUrl, timeoutMs, params.account);
217
+ return (params.probeNative ?? (await import("./transport-probes.runtime-CV6Qs0Og.js")).nativeCheck)(resolved.baseUrl, timeoutMs);
216
218
  }
217
219
  function writeSignalAccountTransport(params) {
218
220
  const transport = normalizeTransport(params.transport);
@@ -309,7 +311,7 @@ function isUuidLike(value) {
309
311
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
310
312
  }
311
313
  function parseSignalAllowFromEntries(raw) {
312
- return parseSetupEntriesAllowingWildcard(raw, (entry) => {
314
+ return parseAllowFromEntries(raw, (entry) => {
313
315
  if (normalizeLowercaseStringOrEmpty(entry).startsWith("uuid:")) {
314
316
  const id = entry.slice(5).trim();
315
317
  if (!id) return { error: "Invalid uuid entry" };
@@ -400,37 +402,16 @@ async function promptSignalAllowFrom(params) {
400
402
  })
401
403
  });
402
404
  }
403
- const signalDmPolicy = {
405
+ const signalDmPolicy = createChannelDmPolicy({
404
406
  label: "Signal",
405
407
  channel,
406
- policyKey: "channels.signal.dmPolicy",
407
- allowFromKey: "channels.signal.allowFrom",
408
- resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultSignalAccountId(cfg)) !== DEFAULT_ACCOUNT_ID$2 ? {
409
- policyKey: `channels.signal.accounts.${accountId ?? resolveDefaultSignalAccountId(cfg)}.dmPolicy`,
410
- allowFromKey: `channels.signal.accounts.${accountId ?? resolveDefaultSignalAccountId(cfg)}.allowFrom`
411
- } : {
412
- policyKey: "channels.signal.dmPolicy",
413
- allowFromKey: "channels.signal.allowFrom"
414
- },
415
- getCurrent: (cfg, accountId) => resolveSignalAccount({
408
+ resolveAccount: (cfg, accountId) => resolveSignalAccount({
416
409
  cfg,
417
410
  accountId: accountId ?? resolveDefaultSignalAccountId(cfg)
418
- }).config.dmPolicy ?? "pairing",
419
- setPolicy: (cfg, policy, accountId) => patchChannelConfigForAccount({
420
- cfg,
421
- channel,
422
- accountId: accountId ?? resolveDefaultSignalAccountId(cfg),
423
- patch: policy === "open" ? {
424
- dmPolicy: "open",
425
- allowFrom: mergeAllowFromEntries(resolveSignalAccount({
426
- cfg,
427
- accountId: accountId ?? resolveDefaultSignalAccountId(cfg)
428
- }).config.allowFrom, ["*"])
429
- } : { dmPolicy: policy },
430
- setupSurface: signalSetupAdapter
431
411
  }),
412
+ setupSurface: () => signalSetupAdapter,
432
413
  promptAllowFrom: promptSignalAllowFrom
433
- };
414
+ });
434
415
  function resolveSignalCliPath(params) {
435
416
  const transport = resolveSignalAccount({
436
417
  cfg: params.cfg,
@@ -587,7 +568,7 @@ function createSignalSetupWizardProxy(loadWizard) {
587
568
  const signalDoctor = {
588
569
  normalizeCompatibilityConfig,
589
570
  cleanStaleConfig: async ({ cfg }) => {
590
- const { detectSignalTransport } = await import("./transport-detection.runtime-BgjcIyww.js");
571
+ const { detectSignalTransport } = await import("./transport-detection.runtime-D_190UUL.js");
591
572
  return await migrateLegacySignalTransportConfig({
592
573
  cfg,
593
574
  detect: detectSignalTransport
@@ -598,7 +579,7 @@ const signalDoctor = {
598
579
  //#region extensions/signal/src/shared.ts
599
580
  const SIGNAL_CHANNEL = "signal";
600
581
  async function loadSignalChannelRuntime() {
601
- return await import("./channel.runtime-DWQdFD2O.js");
582
+ return await import("./channel.runtime-BRDaqr5-.js");
602
583
  }
603
584
  const signalSetupWizard = createSignalSetupWizardProxy(async () => (await loadSignalChannelRuntime()).signalSetupWizard);
604
585
  const signalConfigAdapter = {
@@ -682,10 +663,10 @@ function createSignalPluginBase(params) {
682
663
  }
683
664
  //#endregion
684
665
  //#region extensions/signal/src/channel.ts
685
- const loadSignalMonitorModule = createLazyRuntimeModule(() => import("./monitor-C0aBYlJ0.js").then((n) => n.n));
686
- const loadSignalProbeModule = createLazyRuntimeModule(() => import("./probe-2yf2hpcc.js").then((n) => n.n));
687
- const loadSignalSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CcA5Qei9.js"));
688
- const loadSignalApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-5uyOazxW.js").then((n) => n.r));
666
+ const loadSignalMonitorModule = createLazyRuntimeModule(() => import("./monitor-BvIzkrYW.js").then((n) => n.n));
667
+ const loadSignalProbeModule = createLazyRuntimeModule(() => import("./probe-Br9abaGp.js").then((n) => n.n));
668
+ const loadSignalSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CbuXycZT.js"));
669
+ const loadSignalApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-DtL47gSK.js").then((n) => n.r));
689
670
  async function resolveSignalSendContext(params) {
690
671
  return {
691
672
  send: resolveOutboundSendDep(params.deps, "signal") ?? (await loadSignalSendRuntime()).sendMessageSignal,
@@ -917,7 +898,7 @@ async function registerDeliveredSignalApprovalPayloadForReactions(params) {
917
898
  const targetAuthor = normalizeOptionalString(account.config.account);
918
899
  const targetAuthorUuid = normalizeOptionalString(account.config.accountUuid);
919
900
  if (!targetAuthor && !targetAuthorUuid) return;
920
- const { registerSignalQuestionReactionTargetForDeliveredPayload } = await import("./question-reactions-DJ1xQzVF.js").then((n) => n.n);
901
+ const { registerSignalQuestionReactionTargetForDeliveredPayload } = await import("./question-reactions-Ds48FtEu.js").then((n) => n.n);
921
902
  registerSignalQuestionReactionTargetForDeliveredPayload({
922
903
  cfg: params.cfg,
923
904
  target: {
@@ -1,2 +1,2 @@
1
- import { t as SignalChannelConfigSchema } from "./config-schema-DLvpQPN5.js";
1
+ import { t as SignalChannelConfigSchema } from "./config-schema-Y3dFGwdL.js";
2
2
  export { SignalChannelConfigSchema };
@@ -1,2 +1,2 @@
1
- import { t as signalPlugin } from "./channel-DQ9i00A8.js";
1
+ import { t as signalPlugin } from "./channel-CmbWaYlm.js";
2
2
  export { signalPlugin };
@@ -1,5 +1,5 @@
1
1
  import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-DrStJjiK.js";
2
- import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-DQ9i00A8.js";
2
+ import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-CmbWaYlm.js";
3
3
  import { i as installSignalCli } from "./install-signal-cli-qJF7iC4h.js";
4
4
  import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
5
5
  import { createDetectedBinaryStatus, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
@@ -1,6 +1,7 @@
1
1
  import { detectMime, parseMediaContentLength } from "openclaw/plugin-sdk/media-runtime";
2
2
  import { parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
3
3
  import nodePath from "node:path";
4
+ import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
4
5
  import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
5
6
  import { readResponseTextPrefix, readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
6
7
  import { readRegularFile } from "openclaw/plugin-sdk/security-runtime";
@@ -9,7 +10,6 @@ import { Buffer as Buffer$1 } from "node:buffer";
9
10
  import http from "node:http";
10
11
  import https from "node:https";
11
12
  import { generateSecureUuid } from "openclaw/plugin-sdk/core";
12
- import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
13
13
  //#region extensions/signal/src/client-container.ts
14
14
  /**
15
15
  * Signal client for bbernhard/signal-cli-rest-api container.
@@ -313,7 +313,7 @@ async function streamContainerEvents(params) {
313
313
  if (settled) return;
314
314
  settled = true;
315
315
  cleanup();
316
- reject(toLintErrorObject$1(error, "Signal WebSocket receive handler failed"));
316
+ reject(toErrorObject(error, "Signal WebSocket receive handler failed"));
317
317
  };
318
318
  try {
319
319
  ws = new WebSocket(wsUrl, {
@@ -322,7 +322,7 @@ async function streamContainerEvents(params) {
322
322
  });
323
323
  } catch (err) {
324
324
  logError(`[signal-ws] failed to create WebSocket: ${err instanceof Error ? err.message : String(err)}`);
325
- reject(toLintErrorObject$1(err, "Non-Error rejection"));
325
+ reject(toErrorObject(err, "Non-Error rejection"));
326
326
  return;
327
327
  }
328
328
  ws.on("open", () => {
@@ -634,13 +634,6 @@ async function containerRpcRequest(method, params, opts) {
634
634
  default: throw new Error(`Unsupported container RPC method: ${method}`);
635
635
  }
636
636
  }
637
- function toLintErrorObject$1(value, fallbackMessage) {
638
- if (value instanceof Error) return value;
639
- if (typeof value === "string") return new Error(value);
640
- const error = new Error(fallbackMessage, { cause: value });
641
- if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
642
- return error;
643
- }
644
637
  //#endregion
645
638
  //#region extensions/signal/src/client.ts
646
639
  const DEFAULT_TIMEOUT_MS = 1e4;
@@ -712,7 +705,7 @@ function requestSignalHttpText(url, options) {
712
705
  if (settled) return;
713
706
  settled = true;
714
707
  cleanup();
715
- reject(toLintErrorObject(error, "Non-Error rejection"));
708
+ reject(toErrorObject(error, "Non-Error rejection"));
716
709
  };
717
710
  const resolveOnce = (response) => {
718
711
  if (settled) return;
@@ -832,7 +825,7 @@ function openSignalEventStream(url, abortSignal, timeoutMs = DEFAULT_TIMEOUT_MS)
832
825
  if (settled) return;
833
826
  settled = true;
834
827
  cleanup();
835
- reject(toLintErrorObject(error, "Non-Error rejection"));
828
+ reject(toErrorObject(error, "Non-Error rejection"));
836
829
  };
837
830
  const request = client.request(url, {
838
831
  method: "GET",
@@ -936,12 +929,5 @@ async function streamSignalEvents(params) {
936
929
  }
937
930
  await flushEvent();
938
931
  }
939
- function toLintErrorObject(value, fallbackMessage) {
940
- if (value instanceof Error) return value;
941
- if (typeof value === "string") return new Error(value);
942
- const error = new Error(fallbackMessage, { cause: value });
943
- if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
944
- return error;
945
- }
946
932
  //#endregion
947
933
  export { containerRpcRequest as a, containerCheck as i, signalRpcRequest as n, streamContainerEvents as o, streamSignalEvents as r, signalCheck as t };
@@ -1,4 +1,4 @@
1
- import { a as containerRpcRequest, i as containerCheck, n as signalRpcRequest$1, o as streamContainerEvents, r as streamSignalEvents$1, t as signalCheck$1 } from "./client-yjbwtufN.js";
1
+ import { a as containerRpcRequest, i as containerCheck, n as signalRpcRequest$1, o as streamContainerEvents, r as streamSignalEvents$1, t as signalCheck$1 } from "./client-BazXTH7O.js";
2
2
  //#region extensions/signal/src/client-adapter.ts
3
3
  const DEFAULT_TIMEOUT_MS = 1e4;
4
4
  function formatErrorMessage(error) {
@@ -1,6 +1,7 @@
1
1
  import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
2
2
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId, resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
4
+ import { isRecord as isRecord$1 } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
4
5
  import { ChannelDeliveryStreamingConfigSchema, ChannelSendReadReceiptsSchema, ExecutableTokenSchema, ReplyToModeSchema, buildChannelConfigSchema, buildChannelReactionShape, buildCommonChannelAccountShape, buildGroupEntrySchema, requireAllowlistAllowFrom, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
5
6
  import { z } from "zod";
6
7
  //#region extensions/signal/src/config-ui-hints.ts
@@ -60,9 +61,6 @@ const SIGNAL_RETIRED_TRANSPORT_KEYS = [
60
61
  "ignoreStories"
61
62
  ];
62
63
  const SignalTransportUrlSchema = z.string().url().regex(/^[Hh][Tt][Tt][Pp][Ss]?:\/\/(?![^/?#]*@)/, "Expected http:// or https:// URL without embedded credentials");
63
- function isRecord$1(value) {
64
- return typeof value === "object" && value !== null && !Array.isArray(value);
65
- }
66
64
  function projectSignalConfigForUpdateValidation(value) {
67
65
  if (process.env.OPENCLAW_UPDATE_IN_PROGRESS !== "1" || !isRecord$1(value)) return value;
68
66
  const next = { ...value };
@@ -1,5 +1,6 @@
1
1
  import { a as isSignalManagedNativeConnectionUrlForBind, c as buildSignalTransportHttpUrl, i as assignSignalManagedNativePort, o as isValidSignalManagedNativePort, r as allocateSignalManagedNativePort, s as resolveLocalSignalTransportPort, u as normalizeSignalTransportUrl } from "./transport-policy-DxvSMHp9.js";
2
2
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
3
+ import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
3
4
  import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
4
5
  //#region extensions/signal/src/config-compat.ts
5
6
  const LEGACY_TRANSPORT_FIELDS = [
@@ -18,11 +19,8 @@ const PENDING_LEGACY_INVALID_URL_WARNING = "- channels.signal: legacy httpUrl is
18
19
  const PENDING_LEGACY_INVALID_HOST_WARNING = "- channels.signal: legacy httpHost is invalid; keep the current config, correct httpHost, then run openclaw doctor --fix.";
19
20
  const PENDING_LEGACY_INVALID_PORT_WARNING = "- channels.signal: legacy httpPort must be an integer between 1 and 65535; correct httpPort, then run openclaw doctor --fix.";
20
21
  const PENDING_LEGACY_CONTAINER_ACCOUNT_WARNING = "- channels.signal: legacy container transport requires an account number; add channels.signal.account (or the relevant channels.signal.accounts.*.account) and rerun openclaw doctor --fix.";
21
- function isRecord$1(value) {
22
- return typeof value === "object" && value !== null && !Array.isArray(value);
23
- }
24
22
  function isSignalTransportConfig(value) {
25
- if (!isRecord$1(value)) return false;
23
+ if (!isRecord(value)) return false;
26
24
  if (value.kind === "managed-native") {
27
25
  if (value.httpPort !== void 0 && !isValidSignalManagedNativePort(value.httpPort)) return false;
28
26
  if (value.url === void 0) return true;
@@ -175,8 +173,8 @@ function hasRootSignalAccount(entries) {
175
173
  return entries.length === 1 || Boolean(optionalString(root?.account)) || isSignalTransportConfig(root?.transport);
176
174
  }
177
175
  function signalAccountIds(entries) {
178
- const accounts = isRecord$1(entries[0]?.accounts) ? entries[0].accounts : {};
179
- return Object.entries(accounts).filter(([, entry]) => isRecord$1(entry)).map(([accountId]) => accountId);
176
+ const accounts = isRecord(entries[0]?.accounts) ? entries[0].accounts : {};
177
+ return Object.entries(accounts).filter(([, entry]) => isRecord(entry)).map(([accountId]) => accountId);
180
178
  }
181
179
  function isDefaultSignalAccountId(accountId) {
182
180
  return Boolean(accountId?.trim()) && normalizeAccountId(accountId) === DEFAULT_ACCOUNT_ID;
@@ -186,10 +184,10 @@ function resolveSignalAccountKey(accounts, accountId) {
186
184
  return Object.keys(accounts).find((key) => Boolean(key.trim()) && normalizeAccountId(key) === normalizedAccountId);
187
185
  }
188
186
  function nestedDefaultOwnsEffectiveTransport(entries) {
189
- const accounts = isRecord$1(entries[0]?.accounts) ? entries[0].accounts : {};
187
+ const accounts = isRecord(entries[0]?.accounts) ? entries[0].accounts : {};
190
188
  const nestedDefaultKey = resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID);
191
189
  const nestedDefault = nestedDefaultKey ? accounts[nestedDefaultKey] : void 0;
192
- return isRecord$1(nestedDefault) && (isSignalTransportConfig(nestedDefault.transport) || hasLegacyFields(nestedDefault));
190
+ return isRecord(nestedDefault) && (isSignalTransportConfig(nestedDefault.transport) || hasLegacyFields(nestedDefault));
193
191
  }
194
192
  function isDiscardedTransportEntry(entries, index) {
195
193
  if (index === 0) return !hasRootSignalAccount(entries) || nestedDefaultOwnsEffectiveTransport(entries);
@@ -204,23 +202,23 @@ function shouldMaterializeTransport(entries, index) {
204
202
  function clearLegacySignalTransportFieldsForAccount(params) {
205
203
  const next = structuredClone(params.cfg);
206
204
  const signal = next.channels?.signal;
207
- if (!isRecord$1(signal)) return next;
205
+ if (!isRecord(signal)) return next;
208
206
  if (isDefaultSignalAccountId(params.accountId)) {
209
207
  clearLegacyTransportFields(signal);
210
208
  delete signal.apiMode;
211
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : void 0;
209
+ const accounts = isRecord(signal.accounts) ? signal.accounts : void 0;
212
210
  const nestedDefaultKey = accounts ? resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID) : void 0;
213
211
  const nestedDefault = nestedDefaultKey ? accounts?.[nestedDefaultKey] : void 0;
214
- if (isRecord$1(nestedDefault)) {
212
+ if (isRecord(nestedDefault)) {
215
213
  clearLegacyTransportFields(nestedDefault);
216
214
  delete nestedDefault.transport;
217
215
  }
218
216
  return next;
219
217
  }
220
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : void 0;
218
+ const accounts = isRecord(signal.accounts) ? signal.accounts : void 0;
221
219
  const accountKey = accounts ? resolveSignalAccountKey(accounts, params.accountId) : void 0;
222
220
  const account = accountKey ? accounts?.[accountKey] : void 0;
223
- if (isRecord$1(account)) clearLegacyTransportFields(account);
221
+ if (isRecord(account)) clearLegacyTransportFields(account);
224
222
  return next;
225
223
  }
226
224
  function allocateMigratedManagedPorts(params) {
@@ -239,12 +237,12 @@ function allocateMigratedManagedPorts(params) {
239
237
  const localConnectionPort = resolveLocalSignalTransportPort(transport.url);
240
238
  if (localConnectionPort !== void 0) reservedPorts.add(localConnectionPort);
241
239
  }
242
- if (index === canonicalDefaultIndex || isRecord$1(params.entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
240
+ if (index === canonicalDefaultIndex || isRecord(params.entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
243
241
  }
244
242
  return params.transports.map((transport, index) => {
245
243
  if (!transport || index === 0 && canonicalDefaultIndex !== 0) return transport;
246
244
  if (transport.kind !== "managed-native") return transport;
247
- if (isRecord$1(params.entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
245
+ if (isRecord(params.entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
248
246
  const rawPreferredPort = params.entries[index]?.httpPort;
249
247
  const preferredPort = typeof rawPreferredPort === "number" ? rawPreferredPort : transport.httpPort;
250
248
  const httpPort = allocateSignalManagedNativePort({
@@ -258,10 +256,10 @@ function allocateMigratedManagedPorts(params) {
258
256
  function applyMigratedSignalTransports(params) {
259
257
  const next = structuredClone(params.cfg);
260
258
  const nextSignal = next.channels?.signal;
261
- if (!isRecord$1(nextSignal)) return;
259
+ if (!isRecord(nextSignal)) return;
262
260
  const accountIds = signalAccountIds(params.entries);
263
- const nextAccounts = isRecord$1(nextSignal.accounts) ? nextSignal.accounts : {};
264
- const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord$1)];
261
+ const nextAccounts = isRecord(nextSignal.accounts) ? nextSignal.accounts : {};
262
+ const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord)];
265
263
  const rootIsAccount = hasRootSignalAccount(params.entries);
266
264
  const canonicalRootTransport = isSignalTransportConfig(params.entries[0]?.transport) ? params.entries[0].transport : void 0;
267
265
  for (const [index, entry] of nextEntries.entries()) {
@@ -280,17 +278,17 @@ function applyMigratedSignalTransports(params) {
280
278
  }
281
279
  function hasContainerTransportWithoutEffectiveAccount(cfg) {
282
280
  const signal = cfg.channels?.signal;
283
- if (!isRecord$1(signal)) return false;
284
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : {};
281
+ if (!isRecord(signal)) return false;
282
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
285
283
  const rootTransport = isSignalTransportConfig(signal.transport) ? signal.transport : void 0;
286
284
  const defaultKey = resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID);
287
285
  const defaultEntry = defaultKey ? accounts[defaultKey] : void 0;
288
- const defaultAccount = isRecord$1(defaultEntry) && defaultEntry.account !== void 0 ? optionalString(defaultEntry.account) : optionalString(signal.account);
286
+ const defaultAccount = isRecord(defaultEntry) && defaultEntry.account !== void 0 ? optionalString(defaultEntry.account) : optionalString(signal.account);
289
287
  const channelEnabled = signal.enabled !== false;
290
- const defaultEnabled = !isRecord$1(defaultEntry) || defaultEntry.enabled !== false;
288
+ const defaultEnabled = !isRecord(defaultEntry) || defaultEntry.enabled !== false;
291
289
  if (rootTransport?.kind === "container" && channelEnabled && defaultEnabled && !defaultAccount) return true;
292
290
  for (const [accountId, entry] of Object.entries(accounts)) {
293
- if (!isRecord$1(entry)) continue;
291
+ if (!isRecord(entry)) continue;
294
292
  if (!channelEnabled || entry.enabled === false) continue;
295
293
  const isDefaultAccount = isDefaultSignalAccountId(accountId);
296
294
  if ((isDefaultAccount && rootTransport ? rootTransport : isSignalTransportConfig(entry.transport) ? entry.transport : void 0)?.kind !== "container" || isDefaultAccount && rootTransport) continue;
@@ -300,17 +298,17 @@ function hasContainerTransportWithoutEffectiveAccount(cfg) {
300
298
  }
301
299
  async function migrateLegacySignalTransportConfig(params) {
302
300
  const signal = params.cfg.channels?.signal;
303
- if (!isRecord$1(signal)) return {
301
+ if (!isRecord(signal)) return {
304
302
  config: params.cfg,
305
303
  changes: []
306
304
  };
307
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : {};
308
- if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord$1(entry) && hasLegacyFields(entry)))) return {
305
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
306
+ if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord(entry) && hasLegacyFields(entry)))) return {
309
307
  config: params.cfg,
310
308
  changes: []
311
309
  };
312
310
  const apiMode = signal.apiMode;
313
- const entries = [signal, ...Object.values(accounts).filter(isRecord$1)];
311
+ const entries = [signal, ...Object.values(accounts).filter(isRecord)];
314
312
  const legacyResolutionEntries = entries.filter((_, index) => shouldMaterializeTransport(entries, index)).filter((entry) => !isSignalTransportConfig(entry.transport));
315
313
  const invalidDerivedEndpoint = findInvalidLegacyDerivedEndpoint(legacyResolutionEntries, signal);
316
314
  if (invalidDerivedEndpoint) return {
@@ -369,16 +367,16 @@ async function migrateLegacySignalTransportConfig(params) {
369
367
  }
370
368
  function migrateLegacySignalTransportConfigSync(cfg) {
371
369
  const signal = cfg.channels?.signal;
372
- if (!isRecord$1(signal)) return {
370
+ if (!isRecord(signal)) return {
373
371
  config: cfg,
374
372
  changes: []
375
373
  };
376
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : {};
377
- if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord$1(entry) && hasLegacyFields(entry)))) return {
374
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
375
+ if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord(entry) && hasLegacyFields(entry)))) return {
378
376
  config: cfg,
379
377
  changes: []
380
378
  };
381
- const entries = [signal, ...Object.values(accounts).filter(isRecord$1)];
379
+ const entries = [signal, ...Object.values(accounts).filter(isRecord)];
382
380
  const legacyResolutionEntries = entries.filter((_, index) => shouldMaterializeTransport(entries, index)).filter((entry) => !isSignalTransportConfig(entry.transport));
383
381
  const invalidDerivedEndpoint = findInvalidLegacyDerivedEndpoint(legacyResolutionEntries, signal);
384
382
  if (invalidDerivedEndpoint) return {
@@ -445,9 +443,6 @@ const RETIRED_SIGNAL_ACCOUNT_TRANSPORT_FIELDS = [
445
443
  "receiveMode",
446
444
  "ignoreStories"
447
445
  ];
448
- function isRecord(value) {
449
- return typeof value === "object" && value !== null && !Array.isArray(value);
450
- }
451
446
  function hasRetiredSignalAccountTransportFields(value) {
452
447
  return isRecord(value) && RETIRED_SIGNAL_ACCOUNT_TRANSPORT_FIELDS.some((field) => Object.hasOwn(value, field));
453
448
  }
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-api-DbUCknbC.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-api-Dcte-QYB.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -2,23 +2,24 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { i as resolveSignalAccount, o as resolveSignalReplyToMode } from "./accounts-DrStJjiK.js";
3
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-BQ4OzXXk.js";
4
4
  import { t as getOptionalSignalRuntime } from "./runtime-JPrGlV7h.js";
5
- import { i as materializeSignalPresentationFallback, n as registerSignalReplyContext, o as resolveSignalReactionLevel, s as formatSignalMediaText, u as isSignalNativeApprovalHandlerConfigured } from "./transport-detection-CiZWiMYa.js";
6
- import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-Bm0ZRqJn.js";
7
- import { n as sendReactionSignal } from "./reaction-runtime-api-Bka61qO9.js";
8
- import { a as maybeResolveSignalApprovalReaction, l as resolveSignalApprovalConversationKey, s as registerSignalApprovalReactionTargetForDeliveredPayload, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-5uyOazxW.js";
9
- import { r as registerSignalQuestionReactionTargetForDeliveredPayload, t as maybeResolveSignalQuestionReaction } from "./question-reactions-DJ1xQzVF.js";
10
- import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-BZAqAa8p.js";
11
- import { bindIngressLifecycleToReplyOptions, createChannelIngressMonitor, createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
5
+ import { i as materializeSignalPresentationFallback, n as registerSignalReplyContext, o as resolveSignalReactionLevel, s as formatSignalMediaText, u as isSignalNativeApprovalHandlerConfigured } from "./transport-detection-Da06-LOL.js";
6
+ import { n as signalRpcRequest, r as streamSignalEvents, t as signalCheck } from "./client-adapter-mXGeEHQJ.js";
7
+ import { n as sendReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
8
+ import { a as maybeResolveSignalApprovalReaction, l as resolveSignalApprovalConversationKey, s as registerSignalApprovalReactionTargetForDeliveredPayload, t as addSignalApprovalReactionHintToStructuredPayload } from "./approval-reactions-DtL47gSK.js";
9
+ import { r as registerSignalQuestionReactionTargetForDeliveredPayload, t as maybeResolveSignalQuestionReaction } from "./question-reactions-Ds48FtEu.js";
10
+ import { n as sendReadReceiptSignal, r as sendTypingSignal, t as sendMessageSignal } from "./send-B_Ks4MZr.js";
11
+ import { bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
12
12
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
13
- import { detectMime, estimateBase64DecodedBytes, kindFromMime, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
13
+ import { canonicalizeBase64, detectMime, estimateBase64DecodedBytes, kindFromMime, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
14
14
  import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
15
- import { normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
15
+ import { normalizeNullableString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
16
16
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
17
17
  import { normalizeE164, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
18
- import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toHistoryMediaEntries, toInboundMediaFacts } from "openclaw/plugin-sdk/channel-inbound";
18
+ import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toHistoryMediaEntries, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
19
19
  import nodePath from "node:path";
20
- import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
21
20
  import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
21
+ import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
22
+ import { isRecord as isRecord$1 } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
22
23
  import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
23
24
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
24
25
  import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
@@ -34,12 +35,12 @@ import { createInterface } from "node:readline";
34
35
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
35
36
  import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
36
37
  import { DEFAULT_EMOJIS, DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
38
+ import { createChannelIngressResolver, defineStableChannelIngressIdentity, fanInChannelIngressLifecycles } from "openclaw/plugin-sdk/channel-ingress-runtime";
37
39
  import { isControlCommandMessage } from "openclaw/plugin-sdk/command-detection";
38
40
  import { createInternalHookEvent, fireAndForgetHook, toInternalMessageReceivedContext, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
39
41
  import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
40
42
  import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
41
43
  import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
42
- import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
43
44
  import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
44
45
  import { listChatCommands, maybeResolveTextAlias, normalizeCommandBody } from "openclaw/plugin-sdk/command-auth-native";
45
46
  import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
@@ -387,17 +388,9 @@ function createSignalPendingInboundRegistry(accountId) {
387
388
  if (!conversationKey) return;
388
389
  for (const inboundKey of countsByConversation.get(conversationKey)?.keys() ?? []) cancelKey(inboundKey);
389
390
  };
390
- const completeAfter = (flush) => async (entries) => {
391
- try {
392
- await flush(entries);
393
- } finally {
394
- complete(entries);
395
- }
396
- };
397
391
  return {
398
392
  track,
399
393
  complete,
400
- completeAfter,
401
394
  cancelPendingOnAbort
402
395
  };
403
396
  }
@@ -612,7 +605,7 @@ function createSignalEventHandler(deps) {
612
605
  chatType: entry.isGroup ? "group" : "direct"
613
606
  });
614
607
  const replyThreading = resolveBatchedReplyThreadingPolicy(replyToMode, entry.isBatched === true);
615
- const media = toInboundMediaFacts(entry.media);
608
+ const media = await toInboundMediaFactsWithMetadata(entry.media);
616
609
  const ctxPayload = buildChannelInboundEventContext({
617
610
  channel: "signal",
618
611
  supplemental: { quote: entry.replyToBody ? {
@@ -664,7 +657,7 @@ function createSignalEventHandler(deps) {
664
657
  }
665
658
  });
666
659
  if (shouldLogVerbose()) {
667
- const preview = truncateUtf16Safe(body, 200).replace(/\\n/g, "\\\\n");
660
+ const preview = truncateUtf16Safe(body, 200).replace(/\r/g, "\\r").replace(/\n/g, "\\n");
668
661
  logVerbose(`signal inbound: from=${ctxPayload.From} len=${body.length} preview="${preview}"`);
669
662
  }
670
663
  const statusReactionTimestamp = resolveSignalStatusReactionTimestamp(entry);
@@ -682,7 +675,6 @@ function createSignalEventHandler(deps) {
682
675
  isDirect: !entry.isGroup,
683
676
  isGroup: entry.isGroup,
684
677
  isMentionableGroup: entry.isGroup,
685
- requireMention: entry.requireMention === true,
686
678
  canDetectMention: entry.canDetectMention === true,
687
679
  effectiveWasMentioned: entry.wasMentioned === true
688
680
  }));
@@ -872,50 +864,14 @@ function createSignalEventHandler(deps) {
872
864
  }
873
865
  });
874
866
  }
875
- function buildFlushIngressLifecycle(entries) {
876
- const lifecycles = entries.map((entry) => entry.turnAdoptionLifecycle).filter((lifecycle) => lifecycle !== void 0);
877
- const [firstLifecycle] = lifecycles;
878
- if (!firstLifecycle) return {
879
- lifecycle: void 0,
880
- settle: async () => {}
881
- };
882
- let handedOff = false;
883
- const adoptAll = async () => {
884
- for (const lifecycle of lifecycles) await lifecycle.onAdopted();
885
- };
886
- return {
887
- lifecycle: {
888
- abortSignal: lifecycles.length === 1 ? firstLifecycle.abortSignal : AbortSignal.any(lifecycles.map((lifecycle) => lifecycle.abortSignal)),
889
- onAdopted: async () => {
890
- handedOff = true;
891
- await adoptAll();
892
- },
893
- onDeferred: () => {
894
- handedOff = true;
895
- for (const lifecycle of lifecycles) lifecycle.onDeferred();
896
- },
897
- onAdoptionFinalizing: () => {
898
- for (const lifecycle of lifecycles) lifecycle.onAdoptionFinalizing();
899
- },
900
- onAbandoned: async () => {
901
- handedOff = true;
902
- await Promise.all(lifecycles.map((lifecycle) => Promise.resolve(lifecycle.onAbandoned())));
903
- }
904
- },
905
- settle: async () => {
906
- if (!handedOff) await adoptAll();
907
- }
908
- };
909
- }
910
- async function flushSignalInboundEntries(entries) {
867
+ async function flushSignalInboundEntries(entries, lifecycle, settle) {
911
868
  const last = entries.at(-1);
912
869
  if (!last) return;
913
- const { lifecycle, settle } = buildFlushIngressLifecycle(entries);
914
870
  if (entries.length === 1) {
915
- await handleSignalInboundMessage(lifecycle ? {
871
+ await handleSignalInboundMessage({
916
872
  ...last,
917
873
  turnAdoptionLifecycle: lifecycle
918
- } : last);
874
+ });
919
875
  await settle();
920
876
  return;
921
877
  }
@@ -929,14 +885,14 @@ function createSignalEventHandler(deps) {
929
885
  ...last,
930
886
  bodyText: combinedText,
931
887
  commandBody: combinedCommandBody,
932
- ...lifecycle ? { turnAdoptionLifecycle: lifecycle } : {},
888
+ turnAdoptionLifecycle: lifecycle,
933
889
  isBatched: true,
934
890
  nativeReplyBody: last.nativeReplyBody ?? last.bodyText,
935
891
  media: entries.flatMap((entry) => entry.media ?? [])
936
892
  });
937
893
  await settle();
938
894
  }
939
- async function retrySignalInboundFlush(entries, initialError) {
895
+ async function retrySignalInboundFlush(entries, lifecycle, settle, initialError) {
940
896
  let lastError = initialError;
941
897
  for (const [attemptIndex, delayMs] of RETRYABLE_FLUSH_RETRY_DELAYS_MS.entries()) {
942
898
  const attempt = attemptIndex + 1;
@@ -952,7 +908,7 @@ function createSignalEventHandler(deps) {
952
908
  }
953
909
  if (deps.abortSignal?.aborted) return;
954
910
  try {
955
- await flushSignalInboundEntries(entries);
911
+ await flushSignalInboundEntries(entries, lifecycle, settle);
956
912
  return;
957
913
  } catch (err) {
958
914
  if (deps.abortSignal?.aborted) return;
@@ -962,26 +918,41 @@ function createSignalEventHandler(deps) {
962
918
  }
963
919
  throw lastError;
964
920
  }
965
- const flushDebouncedSignalInboundEntries = async (entries) => {
966
- if (!entries.some((entry) => activeEnqueueEntries.has(entry)) && deps.abortSignal?.aborted) return;
967
- try {
968
- await flushSignalInboundEntries(entries);
969
- } catch (err) {
970
- if (!isSignalReplySessionInitConflictError(err)) throw err;
971
- if (deps.abortSignal?.aborted) return;
972
- const retryTask = retrySignalInboundFlush(entries, err).catch(async (terminalError) => {
973
- await Promise.all(entries.map((entry) => Promise.resolve(entry.turnAdoptionLifecycle?.onAbandoned())));
974
- throw terminalError;
975
- });
976
- deps.runTrackedTask?.(() => retryTask.catch(() => void 0));
977
- await retryTask;
978
- }
921
+ const flushDebouncedSignalInboundEntries = (entries, createFlush) => {
922
+ const { lifecycle, settle } = fanInChannelIngressLifecycles(entries.map((entry) => entry.turnAdoptionLifecycle));
923
+ return createFlush({
924
+ lifecycle,
925
+ dispatch: async (admissionLifecycle) => {
926
+ if (!entries.some((entry) => activeEnqueueEntries.has(entry)) && deps.abortSignal?.aborted) return;
927
+ try {
928
+ await flushSignalInboundEntries(entries, admissionLifecycle, settle);
929
+ } catch (err) {
930
+ if (!isSignalReplySessionInitConflictError(err)) throw err;
931
+ if (deps.abortSignal?.aborted) return;
932
+ await retrySignalInboundFlush(entries, admissionLifecycle, settle, err).catch(async (terminalError) => {
933
+ await Promise.all(entries.map((entry) => Promise.resolve(entry.turnAdoptionLifecycle?.onAbandoned())));
934
+ throw terminalError;
935
+ });
936
+ }
937
+ }
938
+ });
979
939
  };
980
940
  const reportSignalInboundFlushError = (err) => {
981
941
  deps.runtime.error?.(`signal debounce flush failed: ${String(err)}`);
982
942
  };
983
943
  const pendingInboundRegistry = createSignalPendingInboundRegistry(deps.accountId);
984
- const flushNormalSignalInboundEntries = pendingInboundRegistry.completeAfter(flushDebouncedSignalInboundEntries);
944
+ const trackSignalInboundFlush = (flush) => {
945
+ deps.runTrackedTask?.(() => flush.completion.catch(() => void 0));
946
+ return flush;
947
+ };
948
+ const flushNormalSignalInboundEntries = (entries, createFlush) => {
949
+ const flush = flushDebouncedSignalInboundEntries(entries, createFlush);
950
+ const completion = flush.completion.finally(() => pendingInboundRegistry.complete(entries));
951
+ return trackSignalInboundFlush({
952
+ admission: flush.admission,
953
+ completion
954
+ });
955
+ };
985
956
  const { debouncer } = createChannelInboundDebouncer({
986
957
  cfg: deps.cfg,
987
958
  channel: "signal",
@@ -1001,7 +972,7 @@ function createSignalEventHandler(deps) {
1001
972
  serializeImmediate: true,
1002
973
  buildKey: (entry) => resolveSignalControlLaneKey(deps.accountId, entry),
1003
974
  shouldDebounce: () => false,
1004
- onFlush: flushDebouncedSignalInboundEntries,
975
+ onFlush: (entries, createFlush) => trackSignalInboundFlush(flushDebouncedSignalInboundEntries(entries, createFlush)),
1005
976
  onError: reportSignalInboundFlushError
1006
977
  });
1007
978
  async function handleReactionOnlyInbound(params) {
@@ -1400,24 +1371,8 @@ function registerSignalReactionTargetsForDeliveredPayload(params) {
1400
1371
  }
1401
1372
  //#endregion
1402
1373
  //#region extensions/signal/src/signal-ingress.ts
1403
- const SIGNAL_INGRESS_COMPLETED_TTL_MS = 720 * 60 * 60 * 1e3;
1404
- const SIGNAL_INGRESS_COMPLETED_MAX_ENTRIES = 1e3;
1405
- const SIGNAL_INGRESS_FAILED_TTL_MS = 720 * 60 * 60 * 1e3;
1406
- const SIGNAL_INGRESS_FAILED_MAX_ENTRIES = 1e3;
1407
1374
  const SIGNAL_INGRESS_DRAIN_INTERVAL_MS = 1e3;
1408
- var SignalIngressPermanentError = class extends Error {
1409
- constructor(reason, message, options) {
1410
- super(message, options);
1411
- this.reason = reason;
1412
- this.name = "SignalIngressPermanentError";
1413
- }
1414
- };
1415
- function isRecord$1(value) {
1416
- return typeof value === "object" && value !== null && !Array.isArray(value);
1417
- }
1418
- function normalizeRawString(value) {
1419
- return typeof value === "string" && value.trim() ? value.trim() : null;
1420
- }
1375
+ const SignalIngressPermanentError = createChannelIngressError("SignalIngressPermanentError", { withReason: true });
1421
1376
  function normalizeTimestamp(value) {
1422
1377
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
1423
1378
  }
@@ -1442,15 +1397,15 @@ function inspectSignalIngressEvent(event) {
1442
1397
  const dataMessage = resolveDataMessage(envelope);
1443
1398
  const reactionMessage = isRecord$1(envelope.reactionMessage) ? envelope.reactionMessage : null;
1444
1399
  if (!dataMessage && !reactionMessage) return null;
1445
- const senderUuid = normalizeRawString(envelope.sourceUuid);
1446
- const senderNumber = normalizeRawString(envelope.sourceNumber);
1400
+ const senderUuid = normalizeNullableString(envelope.sourceUuid);
1401
+ const senderNumber = normalizeNullableString(envelope.sourceNumber);
1447
1402
  const senderKey = senderUuid ? `uuid:${senderUuid}` : senderNumber ? `number:${senderNumber}` : null;
1448
1403
  if (!senderKey) throw new SignalIngressPermanentError("missing-sender", "Signal dispatchable envelope is missing sourceUuid/sourceNumber");
1449
1404
  const timestamp = normalizeTimestamp(envelope.timestamp) ?? normalizeTimestamp(dataMessage?.timestamp);
1450
1405
  if (timestamp === null) throw new SignalIngressPermanentError("missing-timestamp", "Signal dispatchable envelope is missing a stable timestamp");
1451
1406
  const dataGroup = isRecord$1(dataMessage?.groupInfo) ? dataMessage.groupInfo : null;
1452
1407
  const reactionGroup = isRecord$1(reactionMessage?.groupInfo) ? reactionMessage.groupInfo : null;
1453
- const groupId = normalizeRawString(dataGroup?.groupId) ?? normalizeRawString(reactionGroup?.groupId);
1408
+ const groupId = normalizeNullableString(dataGroup?.groupId) ?? normalizeNullableString(reactionGroup?.groupId);
1454
1409
  return {
1455
1410
  eventId: JSON.stringify([senderKey, timestamp]),
1456
1411
  laneKey: groupId ? `group:${groupId}` : `direct:${senderKey}`
@@ -1494,10 +1449,8 @@ async function startSignalIngressMonitor(params) {
1494
1449
  pollIntervalMs: SIGNAL_INGRESS_DRAIN_INTERVAL_MS,
1495
1450
  retention: {
1496
1451
  pruneIntervalMs: 0,
1497
- completedTtlMs: SIGNAL_INGRESS_COMPLETED_TTL_MS,
1498
- completedMaxEntries: SIGNAL_INGRESS_COMPLETED_MAX_ENTRIES,
1499
- failedTtlMs: SIGNAL_INGRESS_FAILED_TTL_MS,
1500
- failedMaxEntries: SIGNAL_INGRESS_FAILED_MAX_ENTRIES
1452
+ completedMaxEntries: 1e3,
1453
+ failedMaxEntries: 1e3
1501
1454
  },
1502
1455
  appendRetryDelaysMs: [0],
1503
1456
  drain: {
@@ -1715,7 +1668,9 @@ async function fetchAttachment(params) {
1715
1668
  });
1716
1669
  if (!result?.data) return null;
1717
1670
  if (estimateBase64DecodedBytes(result.data) > params.maxBytes) throw new Error(`Signal attachment ${attachment.id} exceeds ${(params.maxBytes / (1024 * 1024)).toFixed(0)}MB limit`);
1718
- const buffer = Buffer.from(result.data, "base64");
1671
+ const canonicalData = canonicalizeBase64(result.data);
1672
+ if (!canonicalData) throw new Error(`Signal attachment ${attachment.id} returned malformed base64 data`);
1673
+ const buffer = Buffer.from(canonicalData, "base64");
1719
1674
  const originalFilename = normalizeOptionalString(attachment.filename ?? void 0);
1720
1675
  const saved = await saveMediaBuffer(buffer, normalizeOptionalString(attachment.contentType ?? void 0) ?? await detectMime({
1721
1676
  buffer,
@@ -1,6 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { t as detectSignalTransport } from "./transport-detection-CiZWiMYa.js";
3
- import { n as signalRpcRequest, t as signalCheck } from "./client-adapter-Bm0ZRqJn.js";
2
+ import { t as detectSignalTransport } from "./transport-detection-Da06-LOL.js";
3
+ import { n as signalRpcRequest, t as signalCheck } from "./client-adapter-mXGeEHQJ.js";
4
+ import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
4
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
6
  //#region extensions/signal/src/probe.ts
6
7
  var probe_exports = /* @__PURE__ */ __exportAll({ probeSignal: () => probeSignal });
@@ -13,46 +14,43 @@ function parseSignalVersion(value) {
13
14
  return null;
14
15
  }
15
16
  async function probeSignal(baseUrl, timeoutMs, options = {}) {
16
- const started = Date.now();
17
- const result = {
18
- ok: false,
19
- status: null,
20
- error: null,
21
- elapsedMs: 0,
22
- version: null
23
- };
24
- let transportKind;
25
- try {
26
- transportKind = await resolveProbeTransportKind(baseUrl, timeoutMs, options);
27
- } catch (error) {
17
+ return await runChannelProbe(void 0, async () => {
18
+ const result = {
19
+ ok: false,
20
+ status: null,
21
+ error: null,
22
+ version: null
23
+ };
24
+ let transportKind;
25
+ try {
26
+ transportKind = await resolveProbeTransportKind(baseUrl, timeoutMs, options);
27
+ } catch (error) {
28
+ return {
29
+ ...result,
30
+ error: formatErrorMessage(error)
31
+ };
32
+ }
33
+ const check = await signalCheck(baseUrl, timeoutMs, { transportKind });
34
+ if (!check.ok) return {
35
+ ...result,
36
+ status: check.status ?? null,
37
+ error: check.error ?? "unreachable"
38
+ };
39
+ try {
40
+ result.version = parseSignalVersion(await signalRpcRequest("version", void 0, {
41
+ baseUrl,
42
+ timeoutMs,
43
+ transportKind
44
+ }));
45
+ } catch (error) {
46
+ result.error = formatErrorMessage(error);
47
+ }
28
48
  return {
29
49
  ...result,
30
- error: formatErrorMessage(error),
31
- elapsedMs: Date.now() - started
50
+ ok: true,
51
+ status: check.status ?? null
32
52
  };
33
- }
34
- const check = await signalCheck(baseUrl, timeoutMs, { transportKind });
35
- if (!check.ok) return {
36
- ...result,
37
- status: check.status ?? null,
38
- error: check.error ?? "unreachable",
39
- elapsedMs: Date.now() - started
40
- };
41
- try {
42
- result.version = parseSignalVersion(await signalRpcRequest("version", void 0, {
43
- baseUrl,
44
- timeoutMs,
45
- transportKind
46
- }));
47
- } catch (err) {
48
- result.error = formatErrorMessage(err);
49
- }
50
- return {
51
- ...result,
52
- ok: true,
53
- status: check.status ?? null,
54
- elapsedMs: Date.now() - started
55
- };
53
+ });
56
54
  }
57
55
  async function resolveProbeTransportKind(baseUrl, timeoutMs, options) {
58
56
  if (options.transportKind) return options.transportKind;
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { o as resolveSignalTarget } from "./runtime-JPrGlV7h.js";
3
- import { l as resolveSignalApprovalConversationKey, u as resolveSignalApprovalTargetAuthorKeys } from "./approval-reactions-5uyOazxW.js";
3
+ import { l as resolveSignalApprovalConversationKey, u as resolveSignalApprovalTargetAuthorKeys } from "./approval-reactions-DtL47gSK.js";
4
4
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
6
  //#region extensions/signal/src/question-reactions.ts
@@ -1,5 +1,5 @@
1
1
  import { i as resolveSignalAccount } from "./accounts-DrStJjiK.js";
2
- import { n as signalRpcRequest } from "./client-adapter-Bm0ZRqJn.js";
2
+ import { n as signalRpcRequest } from "./client-adapter-mXGeEHQJ.js";
3
3
  import { t as resolveSignalRpcContext } from "./rpc-context-CZUoE0-A.js";
4
4
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -1,2 +1,2 @@
1
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-Bka61qO9.js";
1
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
2
2
  export { removeReactionSignal, sendReactionSignal };
@@ -1,13 +1,13 @@
1
1
  import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DrStJjiK.js";
2
2
  import { d as normalizeSignalMessagingTarget, u as looksLikeSignalTargetId } from "./identity-BQ4OzXXk.js";
3
3
  import { n as setSignalRuntime } from "./runtime-JPrGlV7h.js";
4
- import { a as signalMessageActions, o as resolveSignalReactionLevel } from "./transport-detection-CiZWiMYa.js";
5
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-Bka61qO9.js";
6
- import { n as SignalConfigSchema } from "./config-schema-DLvpQPN5.js";
4
+ import { a as signalMessageActions, o as resolveSignalReactionLevel } from "./transport-detection-Da06-LOL.js";
5
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
6
+ import { n as SignalConfigSchema } from "./config-schema-Y3dFGwdL.js";
7
7
  import { i as installSignalCli } from "./install-signal-cli-qJF7iC4h.js";
8
- import { t as monitorSignalProvider } from "./monitor-C0aBYlJ0.js";
9
- import { t as sendMessageSignal } from "./send-BZAqAa8p.js";
10
- import { t as probeSignal } from "./probe-2yf2hpcc.js";
8
+ import { t as monitorSignalProvider } from "./monitor-BvIzkrYW.js";
9
+ import { t as sendMessageSignal } from "./send-B_Ks4MZr.js";
10
+ import { t as probeSignal } from "./probe-Br9abaGp.js";
11
11
  import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
12
12
  import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
13
13
  import { buildBaseAccountStatusSnapshot, buildBaseChannelStatusSummary, collectStatusIssuesFromLastError, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
@@ -1,15 +1,32 @@
1
1
  import { i as resolveSignalAccount } from "./accounts-DrStJjiK.js";
2
2
  import { d as normalizeSignalMessagingTarget } from "./identity-BQ4OzXXk.js";
3
- import { c as markdownToSignalText, n as registerSignalReplyContext } from "./transport-detection-CiZWiMYa.js";
4
- import { n as signalRpcRequest } from "./client-adapter-Bm0ZRqJn.js";
3
+ import { c as markdownToSignalText, n as registerSignalReplyContext } from "./transport-detection-Da06-LOL.js";
4
+ import { n as signalRpcRequest } from "./client-adapter-mXGeEHQJ.js";
5
5
  import { t as resolveSignalRpcContext } from "./rpc-context-CZUoE0-A.js";
6
- import { c as registerSignalApprovalReactionTargetForOutboundMessage, n as appendSignalApprovalReactionHintForOutboundMessage } from "./approval-reactions-5uyOazxW.js";
6
+ import { c as registerSignalApprovalReactionTargetForOutboundMessage, n as appendSignalApprovalReactionHintForOutboundMessage } from "./approval-reactions-DtL47gSK.js";
7
7
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
8
8
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
9
9
  import { kindFromMime, resolveOutboundAttachmentFromUrl } from "openclaw/plugin-sdk/media-runtime";
10
10
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
11
11
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
12
12
  //#region extensions/signal/src/send.ts
13
+ function assertSignalRecipientDelivery(result, target) {
14
+ if (!Array.isArray(result?.results)) return;
15
+ const failures = [];
16
+ let hasSuccessfulRecipient = false;
17
+ for (const entry of result.results) {
18
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
19
+ const record = entry;
20
+ const type = normalizeOptionalString(record.type);
21
+ if (type && normalizeLowercaseStringOrEmpty(type) !== "success" || record.success === false) {
22
+ failures.push(type ?? normalizeOptionalString(record.error) ?? normalizeOptionalString(record.message) ?? "recipient delivery failed");
23
+ continue;
24
+ }
25
+ if (normalizeLowercaseStringOrEmpty(type) === "success" || record.success === true) hasSuccessfulRecipient = true;
26
+ }
27
+ if (failures.length === 0 || target.type === "group" && hasSuccessfulRecipient) return;
28
+ throw new Error(`Signal send failed for ${failures.length} recipient${failures.length === 1 ? "" : "s"}: ${[...new Set(failures)].join(", ")}`);
29
+ }
13
30
  async function resolveSignalRpcAccountInfo(opts) {
14
31
  if (!opts.cfg) throw new Error("Signal RPC account resolution requires a resolved runtime config. Load and resolve config at the command or gateway boundary, then pass cfg through the runtime path.");
15
32
  return resolveSignalAccount({
@@ -184,6 +201,7 @@ async function sendMessageSignal(to, text, opts) {
184
201
  nativeReplyStatus = "fallback";
185
202
  }
186
203
  else result = await signalRpcRequest("send", params, sendOpts);
204
+ assertSignalRecipientDelivery(result, target);
187
205
  const timestamp = result?.timestamp;
188
206
  const messageId = timestamp ? String(timestamp) : "unknown";
189
207
  const replyAuthor = targetAuthor ?? targetAuthorUuid;
@@ -1,2 +1,2 @@
1
- import { r as sendTypingSignal, t as sendMessageSignal } from "./send-BZAqAa8p.js";
1
+ import { r as sendTypingSignal, t as sendMessageSignal } from "./send-B_Ks4MZr.js";
2
2
  export { sendMessageSignal, sendTypingSignal };
@@ -2,17 +2,17 @@ import { u as normalizeSignalTransportUrl } from "./transport-policy-DxvSMHp9.js
2
2
  import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DrStJjiK.js";
3
3
  import { d as normalizeSignalMessagingTarget } from "./identity-BQ4OzXXk.js";
4
4
  import { i as signalApprovalAuth, r as getSignalApprovalApprovers, t as getOptionalSignalRuntime } from "./runtime-JPrGlV7h.js";
5
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-Bka61qO9.js";
5
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
6
6
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
7
7
  import { kindFromMime } from "openclaw/plugin-sdk/media-runtime";
8
8
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
9
9
  import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
10
10
  import { resolveReactionLevel } from "openclaw/plugin-sdk/status-helpers";
11
11
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
12
- import { markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithAttributedRanges } from "openclaw/plugin-sdk/text-chunking";
12
+ import { FormatCapabilityProfile, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithAttributedRanges } from "openclaw/plugin-sdk/text-chunking";
13
13
  import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
14
14
  import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
15
- import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, shouldSuppressLocalNativeExecApprovalPrompt } from "openclaw/plugin-sdk/approval-native-runtime";
15
+ import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, createNativeApprovalMessagingTargetResolvers, shouldSuppressLocalNativeExecApprovalPrompt } from "openclaw/plugin-sdk/approval-native-runtime";
16
16
  import { buildApprovalReactionPendingContentForRequest } from "openclaw/plugin-sdk/approval-reaction-runtime";
17
17
  import { formatMediaPlaceholderText } from "openclaw/plugin-sdk/channel-inbound";
18
18
  import { createActionGate, jsonResult, readStringParam, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
@@ -21,38 +21,16 @@ import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-reply
21
21
  import { isMessagePresentationInteractiveBlock, normalizeMessagePresentation, renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
22
22
  //#region extensions/signal/src/approval-native.ts
23
23
  const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
24
+ const { normalizeForwardTarget: normalizeSignalForwardTarget, normalizeTarget: normalizeSignalApprovalTarget, resolveSessionTarget: resolveSessionSignalOriginTarget, resolveTurnSourceTarget: resolveTurnSourceSignalOriginTarget } = createNativeApprovalMessagingTargetResolvers({
25
+ channel: "signal",
26
+ normalizeTo: normalizeSignalMessagingTarget
27
+ });
24
28
  function isSignalApprovalTransportEnabled(params) {
25
29
  return resolveSignalAccount({
26
30
  cfg: params.cfg,
27
31
  accountId: params.accountId
28
32
  }).enabled;
29
33
  }
30
- function normalizeSignalForwardTarget(target) {
31
- if (normalizeLowercaseStringOrEmpty(target.channel) !== "signal") return null;
32
- const to = normalizeSignalMessagingTarget(target.to);
33
- if (!to) return null;
34
- return {
35
- to,
36
- accountId: normalizeOptionalString(target.accountId),
37
- threadId: target.threadId ?? null
38
- };
39
- }
40
- function resolveTurnSourceSignalOriginTarget(request) {
41
- if (normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel) !== "signal") return null;
42
- const to = normalizeSignalMessagingTarget(request.request.turnSourceTo ?? "");
43
- if (!to) return null;
44
- return {
45
- to,
46
- accountId: normalizeOptionalString(request.request.turnSourceAccountId)
47
- };
48
- }
49
- function resolveSessionSignalOriginTarget(sessionTarget) {
50
- const to = normalizeSignalMessagingTarget(sessionTarget.to);
51
- return to ? {
52
- to,
53
- accountId: normalizeOptionalString(sessionTarget.accountId)
54
- } : null;
55
- }
56
34
  const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToSignal, canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToSignal, isNativeApprovalHandlerConfigured: isSignalNativeApprovalHandlerConfiguredBase, isSessionApprovalEligible: isSignalSessionApprovalEligible, shouldHandleApprovalRequest: shouldHandleSignalApprovalRequest } = createNativeApprovalChannelRouteGates({
57
35
  channel: "signal",
58
36
  defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE,
@@ -89,13 +67,7 @@ const resolveSignalOriginTargetBase = createChannelNativeOriginTargetResolver({
89
67
  shouldHandleRequest: shouldHandleSignalApprovalRequest,
90
68
  resolveTurnSourceTarget: resolveTurnSourceSignalOriginTarget,
91
69
  resolveSessionTarget: resolveSessionSignalOriginTarget,
92
- normalizeTarget: (target) => {
93
- const to = normalizeSignalMessagingTarget(target.to);
94
- return to ? {
95
- ...target,
96
- to
97
- } : null;
98
- }
70
+ normalizeTarget: normalizeSignalApprovalTarget
99
71
  });
100
72
  function isSignalGroupTarget(to) {
101
73
  return normalizeLowercaseStringOrEmpty(to).startsWith("group:");
@@ -218,7 +190,7 @@ const signalApprovalCapability = createChannelApprovalCapability({
218
190
  approvalKind,
219
191
  request
220
192
  }),
221
- load: async () => (await import("./approval-handler.runtime-C2qf7D0D.js")).signalApprovalNativeRuntime
193
+ load: async () => (await import("./approval-handler.runtime-C-XYgcxE.js")).signalApprovalNativeRuntime
222
194
  })
223
195
  });
224
196
  //#endregion
@@ -231,16 +203,10 @@ const SIGNAL_STYLE_MAP = {
231
203
  code_block: "MONOSPACE",
232
204
  spoiler: "SPOILER"
233
205
  };
234
- const SIGNAL_FORMAT_PROFILE = {
206
+ const SIGNAL_FORMAT_PROFILE = FormatCapabilityProfile.define({
235
207
  mechanism: "ranges",
236
208
  constructs: {
237
- bold: "native",
238
- italic: "native",
239
209
  underline: "strip",
240
- strikethrough: "native",
241
- spoiler: "native",
242
- codeInline: "native",
243
- codeBlock: "native",
244
210
  codeLanguage: "fallback",
245
211
  linkLabel: "fallback",
246
212
  heading: "fallback",
@@ -256,7 +222,7 @@ const SIGNAL_FORMAT_PROFILE = {
256
222
  limit: 4e3,
257
223
  unit: "chars"
258
224
  }
259
- };
225
+ });
260
226
  function stripEquivalentSignalLinks(ir) {
261
227
  const normalize = (value) => normalizeLowercaseStringOrEmpty(value).replace(/^(?:https?:\/\/)?(?:www\.)?/, "").replace(/\/+$/, "");
262
228
  return {
@@ -667,7 +633,7 @@ const DEFAULT_PROBE_TIMEOUT_MS = 1e4;
667
633
  async function detectSignalTransport(params) {
668
634
  const url = normalizeSignalTransportUrl(params.url);
669
635
  const timeoutMs = params.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
670
- const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-CbnZn38-.js");
636
+ const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-CV6Qs0Og.js");
671
637
  const probeNative = params.probeNative ?? probes?.nativeCheck;
672
638
  const probeContainer = params.probeContainer ?? probes?.containerCheck;
673
639
  if (!probeNative || !probeContainer) throw new Error("Signal transport probes are unavailable");
@@ -1,2 +1,2 @@
1
- import { t as detectSignalTransport } from "./transport-detection-CiZWiMYa.js";
1
+ import { t as detectSignalTransport } from "./transport-detection-Da06-LOL.js";
2
2
  export { detectSignalTransport };
@@ -1,2 +1,2 @@
1
- import { i as containerCheck, t as signalCheck } from "./client-yjbwtufN.js";
1
+ import { i as containerCheck, t as signalCheck } from "./client-BazXTH7O.js";
2
2
  export { containerCheck, signalCheck as nativeCheck };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/signal",
3
- "version": "2026.7.2-beta.4",
3
+ "version": "2026.7.2-beta.7",
4
4
  "description": "OpenClaw Signal channel plugin",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -93,10 +93,10 @@
93
93
  "allowInvalidConfigRecovery": true
94
94
  },
95
95
  "compat": {
96
- "pluginApi": ">=2026.7.2-beta.4"
96
+ "pluginApi": ">=2026.7.2-beta.7"
97
97
  },
98
98
  "build": {
99
- "openclawVersion": "2026.7.2-beta.4",
99
+ "openclawVersion": "2026.7.2-beta.7",
100
100
  "bundledDist": false
101
101
  },
102
102
  "release": {
@@ -115,11 +115,10 @@
115
115
  "files": [
116
116
  "dist/**",
117
117
  "openclaw.plugin.json",
118
- "npm-shrinkwrap.json",
119
118
  "README.md"
120
119
  ],
121
120
  "peerDependencies": {
122
- "openclaw": ">=2026.7.2-beta.4"
121
+ "openclaw": ">=2026.7.2-beta.7"
123
122
  },
124
123
  "peerDependenciesMeta": {
125
124
  "openclaw": {
@@ -1,46 +0,0 @@
1
- {
2
- "name": "@openclaw/signal",
3
- "version": "2026.7.2-beta.4",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "@openclaw/signal",
9
- "version": "2026.7.2-beta.4",
10
- "dependencies": {
11
- "ws": "8.21.1",
12
- "zod": "4.4.3"
13
- }
14
- },
15
- "node_modules/ws": {
16
- "version": "8.21.1",
17
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
18
- "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
19
- "license": "MIT",
20
- "engines": {
21
- "node": ">=10.0.0"
22
- },
23
- "peerDependencies": {
24
- "bufferutil": "^4.0.1",
25
- "utf-8-validate": ">=5.0.2"
26
- },
27
- "peerDependenciesMeta": {
28
- "bufferutil": {
29
- "optional": true
30
- },
31
- "utf-8-validate": {
32
- "optional": true
33
- }
34
- }
35
- },
36
- "node_modules/zod": {
37
- "version": "4.4.3",
38
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
39
- "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
40
- "license": "MIT",
41
- "funding": {
42
- "url": "https://github.com/sponsors/colinhacks"
43
- }
44
- }
45
- }
46
- }