@openclaw/signal 2026.7.2-beta.7 → 2026.8.1-beta.3

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 (33) hide show
  1. package/dist/{accounts-DrStJjiK.js → accounts-DO4HMqaK.js} +2 -2
  2. package/dist/api.js +9 -9
  3. package/dist/{runtime-JPrGlV7h.js → approval-auth-BY6uuApE.js} +2 -9
  4. package/dist/{approval-handler.runtime-C-XYgcxE.js → approval-handler.runtime-Co6EVTqY.js} +4 -4
  5. package/dist/{approval-reactions-DtL47gSK.js → approval-reactions-cs3Ox9Ow.js} +67 -189
  6. package/dist/channel-config-api.js +1 -1
  7. package/dist/channel-plugin-api.js +1 -1
  8. package/dist/{channel-CmbWaYlm.js → channel-zIopSllO.js} +64 -99
  9. package/dist/{channel.runtime-BRDaqr5-.js → channel.runtime-CpDBElG8.js} +3 -3
  10. package/dist/{client-BazXTH7O.js → client-CvnR8_XA.js} +31 -34
  11. package/dist/{client-adapter-mXGeEHQJ.js → client-adapter-D9SNPaNx.js} +13 -6
  12. package/dist/{config-schema-Y3dFGwdL.js → config-schema-CkMIK7zp.js} +4 -5
  13. package/dist/contract-api.js +1 -1
  14. package/dist/{doctor-contract-api-Dcte-QYB.js → doctor-contract-api-Dnp5eQQJ.js} +19 -22
  15. package/dist/doctor-contract-api.js +1 -1
  16. package/dist/{install-signal-cli-qJF7iC4h.js → install-signal-cli-Cpiyk0k1.js} +8 -5
  17. package/dist/{monitor-BvIzkrYW.js → monitor-BLFIkpH0.js} +305 -142
  18. package/dist/{probe-Br9abaGp.js → probe-B0E_cXQw.js} +23 -7
  19. package/dist/question-reactions-BaatFqJ7.js +80 -0
  20. package/dist/{reaction-runtime-api-BjeDyKcz.js → reaction-runtime-api-YGD6hhDh.js} +10 -21
  21. package/dist/reaction-runtime-api.js +1 -1
  22. package/dist/rpc-context-dXSy4NtF.js +15 -0
  23. package/dist/runtime-api.js +8 -9
  24. package/dist/{send-B_Ks4MZr.js → send-BNl5folj.js} +14 -23
  25. package/dist/{send.runtime-CbuXycZT.js → send.runtime-DnMoKk27.js} +1 -1
  26. package/dist/{transport-detection-Da06-LOL.js → transport-detection-D_M79R5f.js} +60 -148
  27. package/dist/{transport-detection.runtime-D_190UUL.js → transport-detection.runtime-DKuuIHvf.js} +1 -1
  28. package/dist/{transport-probes.runtime-CV6Qs0Og.js → transport-probes.runtime-BsJdp0oI.js} +1 -1
  29. package/openclaw.plugin.json +4 -1
  30. package/package.json +5 -5
  31. package/dist/approval-resolver-B3m0D2R0.js +0 -16
  32. package/dist/question-reactions-Ds48FtEu.js +0 -109
  33. package/dist/rpc-context-CZUoE0-A.js +0 -17
@@ -1,19 +1,26 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.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";
2
+ import { t as detectSignalTransport } from "./transport-detection-D_M79R5f.js";
3
+ import { n as signalRpcRequest, t as signalCheck } from "./client-adapter-D9SNPaNx.js";
4
4
  import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
5
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
6
  //#region extensions/signal/src/probe.ts
7
- var probe_exports = /* @__PURE__ */ __exportAll({ probeSignal: () => probeSignal });
7
+ var probe_exports = /* @__PURE__ */ __exportAll({
8
+ probeSignal: () => probeSignal,
9
+ probeSignalAccount: () => probeSignalAccount
10
+ });
8
11
  function parseSignalVersion(value) {
9
12
  if (typeof value === "string" && value.trim()) return value.trim();
10
13
  if (typeof value === "object" && value !== null) {
11
- const version = value.version;
14
+ const { version, versions } = value;
12
15
  if (typeof version === "string" && version.trim()) return version.trim();
16
+ if (Array.isArray(versions)) {
17
+ const normalizedVersions = versions.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
18
+ if (normalizedVersions.length > 0) return normalizedVersions.join(", ");
19
+ }
13
20
  }
14
21
  return null;
15
22
  }
16
- async function probeSignal(baseUrl, timeoutMs, options = {}) {
23
+ async function probeSignalTransport(baseUrl, timeoutMs, options, account) {
17
24
  return await runChannelProbe(void 0, async () => {
18
25
  const result = {
19
26
  ok: false,
@@ -30,7 +37,10 @@ async function probeSignal(baseUrl, timeoutMs, options = {}) {
30
37
  error: formatErrorMessage(error)
31
38
  };
32
39
  }
33
- const check = await signalCheck(baseUrl, timeoutMs, { transportKind });
40
+ const check = await signalCheck(baseUrl, timeoutMs, {
41
+ transportKind,
42
+ ...account && transportKind === "container" ? { account } : {}
43
+ });
34
44
  if (!check.ok) return {
35
45
  ...result,
36
46
  status: check.status ?? null,
@@ -47,11 +57,17 @@ async function probeSignal(baseUrl, timeoutMs, options = {}) {
47
57
  }
48
58
  return {
49
59
  ...result,
50
- ok: true,
60
+ ok: result.error === null,
51
61
  status: check.status ?? null
52
62
  };
53
63
  });
54
64
  }
65
+ async function probeSignal(baseUrl, timeoutMs, options = {}) {
66
+ return await probeSignalTransport(baseUrl, timeoutMs, options);
67
+ }
68
+ async function probeSignalAccount(params) {
69
+ return await probeSignalTransport(params.baseUrl, params.timeoutMs, { transportKind: params.transportKind }, params.account);
70
+ }
55
71
  async function resolveProbeTransportKind(baseUrl, timeoutMs, options) {
56
72
  if (options.transportKind) return options.transportKind;
57
73
  if (options.apiMode === "container") return "container";
@@ -0,0 +1,80 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { i as resolveSignalTarget } from "./approval-auth-BY6uuApE.js";
3
+ import { c as resolveSignalApprovalTargetAuthorKeys, s as resolveSignalApprovalConversationKey } from "./approval-reactions-cs3Ox9Ow.js";
4
+ import { createQuestionReactionTargetStore, questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
5
+ import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
+ //#region extensions/signal/src/question-reactions.ts
7
+ var question_reactions_exports = /* @__PURE__ */ __exportAll({
8
+ maybeResolveSignalQuestionReaction: () => maybeResolveSignalQuestionReaction,
9
+ registerSignalQuestionReactionTargetForDeliveredPayload: () => registerSignalQuestionReactionTargetForDeliveredPayload
10
+ });
11
+ function buildKey(identity) {
12
+ const values = [
13
+ identity.accountId,
14
+ identity.conversationKey,
15
+ identity.messageId
16
+ ].map((value) => value.trim());
17
+ return values.every(Boolean) ? values.join(":") : null;
18
+ }
19
+ const questionReactionTargets = createQuestionReactionTargetStore({
20
+ channel: "signal",
21
+ channelDisplayName: "Signal",
22
+ buildKey,
23
+ identityMatches: (stored, incoming) => Boolean(stored && incoming?.some((authorKey) => stored.includes(authorKey))),
24
+ registerChannelDelivery: questionGatewayRuntime.registerChannelDelivery,
25
+ resolveReaction: questionGatewayRuntime.resolveReaction
26
+ });
27
+ function resolveConversationKey(params) {
28
+ try {
29
+ return resolveSignalTarget({
30
+ cfg: params.cfg,
31
+ accountId: params.accountId,
32
+ input: params.to
33
+ })?.to ?? resolveSignalApprovalConversationKey(params.to);
34
+ } catch {
35
+ return resolveSignalApprovalConversationKey(params.to);
36
+ }
37
+ }
38
+ function registerSignalQuestionReactionTargetForDeliveredPayload(params) {
39
+ const binding = questionGatewayRuntime.readReactionBinding(params.payload);
40
+ if (params.target.channel !== "signal" || !binding) return false;
41
+ const conversationKey = resolveConversationKey({
42
+ cfg: params.cfg,
43
+ ...params.target
44
+ });
45
+ const targetAuthorKeys = resolveSignalApprovalTargetAuthorKeys(params);
46
+ if (!conversationKey || targetAuthorKeys.length === 0) return false;
47
+ const accountId = normalizeAccountId(params.target.accountId ?? void 0);
48
+ let registered = false;
49
+ for (const result of params.results) {
50
+ const messageId = result.channel === "signal" ? result.messageId.trim() : "";
51
+ if (!messageId || messageId === "unknown") continue;
52
+ registered = questionReactionTargets.register(binding, {
53
+ accountId,
54
+ conversationKey,
55
+ messageId
56
+ }, targetAuthorKeys) || registered;
57
+ }
58
+ return registered;
59
+ }
60
+ async function maybeResolveSignalQuestionReaction(params) {
61
+ if (params.isRemove) return false;
62
+ const optionIndex = questionGatewayRuntime.resolveReactionIndex(params.reactionKey);
63
+ if (optionIndex === void 0) return false;
64
+ const authorKeys = resolveSignalApprovalTargetAuthorKeys(params);
65
+ return await questionReactionTargets.resolve({
66
+ identities: [{
67
+ accountId: params.accountId,
68
+ conversationKey: params.conversationKey,
69
+ messageId: params.messageId
70
+ }],
71
+ optionIndex,
72
+ cfg: params.cfg,
73
+ senderId: params.actorId,
74
+ gatewayUrl: params.gatewayUrl,
75
+ metadata: authorKeys,
76
+ logDebug: params.logDebug
77
+ });
78
+ }
79
+ //#endregion
80
+ export { question_reactions_exports as n, registerSignalQuestionReactionTargetForDeliveredPayload as r, maybeResolveSignalQuestionReaction as t };
@@ -1,6 +1,6 @@
1
- import { i as resolveSignalAccount } from "./accounts-DrStJjiK.js";
2
- import { n as signalRpcRequest } from "./client-adapter-mXGeEHQJ.js";
3
- import { t as resolveSignalRpcContext } from "./rpc-context-CZUoE0-A.js";
1
+ import { i as resolveSignalAccount } from "./accounts-DO4HMqaK.js";
2
+ import { n as signalRpcRequest } from "./client-adapter-D9SNPaNx.js";
3
+ import { t as resolveSignalRpcContext } from "./rpc-context-dXSy4NtF.js";
4
4
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
6
6
  //#region extensions/signal/src/send-reactions.ts
@@ -37,16 +37,17 @@ async function sendReactionSignalCore(params) {
37
37
  const { baseUrl, account } = resolveSignalRpcContext(params.opts, accountInfo);
38
38
  const normalizedRecipient = normalizeSignalUuid(params.recipient);
39
39
  const groupId = params.opts.groupId?.trim();
40
- if (!normalizedRecipient && !groupId) throw new Error(params.errors.missingRecipient);
41
- if (!Number.isFinite(params.targetTimestamp) || params.targetTimestamp <= 0) throw new Error(params.errors.invalidTargetTimestamp);
40
+ const operation = `Signal reaction${params.remove ? " removal" : ""}`;
41
+ if (!normalizedRecipient && !groupId) throw new Error(`Recipient or groupId is required for ${operation}`);
42
+ if (!Number.isFinite(params.targetTimestamp) || params.targetTimestamp <= 0) throw new Error(`Valid targetTimestamp is required for ${operation}`);
42
43
  const normalizedEmoji = params.emoji?.trim();
43
- if (!normalizedEmoji) throw new Error(params.errors.missingEmoji);
44
+ if (!normalizedEmoji) throw new Error(`Emoji is required for ${operation}`);
44
45
  const targetAuthorParams = resolveTargetAuthorParams({
45
46
  targetAuthor: params.opts.targetAuthor,
46
47
  targetAuthorUuid: params.opts.targetAuthorUuid,
47
48
  fallback: normalizedRecipient
48
49
  });
49
- if (groupId && !targetAuthorParams.targetAuthor) throw new Error(params.errors.missingTargetAuthor);
50
+ if (groupId && !targetAuthorParams.targetAuthor) throw new Error(`targetAuthor is required for group reaction${params.remove ? " removal" : "s"}`);
50
51
  const requestParams = {
51
52
  emoji: normalizedEmoji,
52
53
  targetTimestamp: params.targetTimestamp,
@@ -78,13 +79,7 @@ async function sendReactionSignal(recipient, targetTimestamp, emoji, opts) {
78
79
  targetTimestamp,
79
80
  emoji,
80
81
  remove: false,
81
- opts,
82
- errors: {
83
- missingRecipient: "Recipient or groupId is required for Signal reaction",
84
- invalidTargetTimestamp: "Valid targetTimestamp is required for Signal reaction",
85
- missingEmoji: "Emoji is required for Signal reaction",
86
- missingTargetAuthor: "targetAuthor is required for group reactions"
87
- }
82
+ opts
88
83
  });
89
84
  }
90
85
  /**
@@ -100,13 +95,7 @@ async function removeReactionSignal(recipient, targetTimestamp, emoji, opts) {
100
95
  targetTimestamp,
101
96
  emoji,
102
97
  remove: true,
103
- opts,
104
- errors: {
105
- missingRecipient: "Recipient or groupId is required for Signal reaction removal",
106
- invalidTargetTimestamp: "Valid targetTimestamp is required for Signal reaction removal",
107
- missingEmoji: "Emoji is required for Signal reaction removal",
108
- missingTargetAuthor: "targetAuthor is required for group reaction removal"
109
- }
98
+ opts
110
99
  });
111
100
  }
112
101
  //#endregion
@@ -1,2 +1,2 @@
1
- import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-BjeDyKcz.js";
1
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-YGD6hhDh.js";
2
2
  export { removeReactionSignal, sendReactionSignal };
@@ -0,0 +1,15 @@
1
+ import "./accounts-DO4HMqaK.js";
2
+ //#region extensions/signal/src/rpc-context.ts
3
+ function resolveSignalRpcContext(opts, accountInfo) {
4
+ const baseUrlOverride = opts.baseUrl?.trim();
5
+ const accountOverride = opts.account?.trim();
6
+ if ((!baseUrlOverride || !accountOverride) && !accountInfo) throw new Error("Signal account config is required when baseUrl or account is missing");
7
+ const baseUrl = baseUrlOverride || accountInfo?.baseUrl;
8
+ if (!baseUrl) throw new Error("Signal base URL is required");
9
+ return {
10
+ baseUrl,
11
+ account: accountOverride || accountInfo?.config.account?.trim() || void 0
12
+ };
13
+ }
14
+ //#endregion
15
+ export { resolveSignalRpcContext as t };
@@ -1,13 +1,12 @@
1
- import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DrStJjiK.js";
1
+ import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DO4HMqaK.js";
2
2
  import { d as normalizeSignalMessagingTarget, u as looksLikeSignalTargetId } from "./identity-BQ4OzXXk.js";
3
- import { n as setSignalRuntime } from "./runtime-JPrGlV7h.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
- import { i as installSignalCli } from "./install-signal-cli-qJF7iC4h.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";
3
+ import { a as setSignalRuntime, c as resolveSignalReactionLevel, s as signalMessageActions } from "./transport-detection-D_M79R5f.js";
4
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-YGD6hhDh.js";
5
+ import { n as SignalConfigSchema } from "./config-schema-CkMIK7zp.js";
6
+ import { i as installSignalCli } from "./install-signal-cli-Cpiyk0k1.js";
7
+ import { t as monitorSignalProvider } from "./monitor-BLFIkpH0.js";
8
+ import { t as sendMessageSignal } from "./send-BNl5folj.js";
9
+ import { t as probeSignal } from "./probe-B0E_cXQw.js";
11
10
  import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
12
11
  import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
13
12
  import { buildBaseAccountStatusSnapshot, buildBaseChannelStatusSummary, collectStatusIssuesFromLastError, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
@@ -1,9 +1,8 @@
1
- import { i as resolveSignalAccount } from "./accounts-DrStJjiK.js";
1
+ import { i as resolveSignalAccount } from "./accounts-DO4HMqaK.js";
2
2
  import { d as normalizeSignalMessagingTarget } from "./identity-BQ4OzXXk.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
- import { t as resolveSignalRpcContext } from "./rpc-context-CZUoE0-A.js";
6
- import { c as registerSignalApprovalReactionTargetForOutboundMessage, n as appendSignalApprovalReactionHintForOutboundMessage } from "./approval-reactions-DtL47gSK.js";
3
+ import { n as registerSignalReplyContext, u as markdownToSignalText } from "./transport-detection-D_M79R5f.js";
4
+ import { n as signalRpcRequest } from "./client-adapter-D9SNPaNx.js";
5
+ import { t as resolveSignalRpcContext } from "./rpc-context-dXSy4NtF.js";
7
6
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
8
7
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
9
8
  import { kindFromMime, resolveOutboundAttachmentFromUrl } from "openclaw/plugin-sdk/media-runtime";
@@ -113,6 +112,15 @@ function resolveSignalQuoteParams(opts) {
113
112
  }
114
113
  function isSignalQuoteMetadataRejection(error) {
115
114
  const normalized = normalizeLowercaseStringOrEmpty(error instanceof Error ? error.message : String(error));
115
+ const rpcCode = /^signal rpc (-?\d+):/u.exec(normalized)?.[1];
116
+ if (rpcCode !== void 0) {
117
+ if (rpcCode !== "-32602") return false;
118
+ } else {
119
+ const restStatusText = /^signal rest (\d{3}):/u.exec(normalized)?.[1];
120
+ if (!restStatusText) return false;
121
+ const restStatus = Number(restStatusText);
122
+ if (restStatus < 400 || restStatus >= 500 || restStatus === 408 || restStatus === 429) return false;
123
+ }
116
124
  if (!normalized.includes("quote")) return false;
117
125
  return normalized.includes("reject") || normalized.includes("invalid") || normalized.includes("unrecognized") || normalized.includes("unsupported") || normalized.includes("not found") || normalized.includes("no such") || normalized.includes("unknown");
118
126
  }
@@ -126,15 +134,7 @@ async function sendMessageSignal(to, text, opts) {
126
134
  const target = parseTarget(to);
127
135
  const targetAuthor = normalizeOptionalString(account);
128
136
  const targetAuthorUuid = normalizeOptionalString(accountInfo.config.accountUuid);
129
- const outboundText = appendSignalApprovalReactionHintForOutboundMessage({
130
- cfg,
131
- accountId: accountInfo.accountId,
132
- to,
133
- text: text ?? "",
134
- targetAuthor,
135
- targetAuthorUuid
136
- });
137
- let message = outboundText;
137
+ let message = text ?? "";
138
138
  let outboundMedia;
139
139
  let textStyles = [];
140
140
  const textMode = opts.textMode ?? "markdown";
@@ -214,15 +214,6 @@ async function sendMessageSignal(to, text, opts) {
214
214
  media: outboundMedia ? [outboundMedia] : void 0,
215
215
  sourceTimestamp: timestamp
216
216
  });
217
- registerSignalApprovalReactionTargetForOutboundMessage({
218
- cfg,
219
- accountId: accountInfo.accountId,
220
- to,
221
- messageId,
222
- text: outboundText,
223
- targetAuthor,
224
- targetAuthorUuid
225
- });
226
217
  return {
227
218
  messageId,
228
219
  timestamp,
@@ -1,2 +1,2 @@
1
- import { r as sendTypingSignal, t as sendMessageSignal } from "./send-B_Ks4MZr.js";
1
+ import { r as sendTypingSignal, t as sendMessageSignal } from "./send-BNl5folj.js";
2
2
  export { sendMessageSignal, sendTypingSignal };
@@ -1,8 +1,8 @@
1
1
  import { u as normalizeSignalTransportUrl } from "./transport-policy-DxvSMHp9.js";
2
- import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DrStJjiK.js";
2
+ import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId, t as listEnabledSignalAccounts } from "./accounts-DO4HMqaK.js";
3
3
  import { d as normalizeSignalMessagingTarget } from "./identity-BQ4OzXXk.js";
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-BjeDyKcz.js";
4
+ import { n as signalApprovalAuth, t as getSignalApprovalApprovers } from "./approval-auth-BY6uuApE.js";
5
+ import { n as sendReactionSignal, t as removeReactionSignal } from "./reaction-runtime-api-YGD6hhDh.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";
@@ -10,38 +10,71 @@ 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
12
  import { FormatCapabilityProfile, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithAttributedRanges } from "openclaw/plugin-sdk/text-chunking";
13
- import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
13
+ import { createApproverRestrictedNativeApprovalCapabilityFromForwardingRoutes } 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, createNativeApprovalMessagingTargetResolvers, shouldSuppressLocalNativeExecApprovalPrompt } from "openclaw/plugin-sdk/approval-native-runtime";
15
+ import { 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";
19
19
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
20
20
  import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-reply-runtime";
21
21
  import { isMessagePresentationInteractiveBlock, normalizeMessagePresentation, renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
22
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
22
23
  //#region extensions/signal/src/approval-native.ts
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
- });
28
24
  function isSignalApprovalTransportEnabled(params) {
29
25
  return resolveSignalAccount({
30
26
  cfg: params.cfg,
31
27
  accountId: params.accountId
32
28
  }).enabled;
33
29
  }
34
- const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToSignal, canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToSignal, isNativeApprovalHandlerConfigured: isSignalNativeApprovalHandlerConfiguredBase, isSessionApprovalEligible: isSignalSessionApprovalEligible, shouldHandleApprovalRequest: shouldHandleSignalApprovalRequest } = createNativeApprovalChannelRouteGates({
30
+ const signalApproval = createApproverRestrictedNativeApprovalCapabilityFromForwardingRoutes({
35
31
  channel: "signal",
36
- defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE,
37
- isTransportEnabled: isSignalApprovalTransportEnabled,
38
- listAccountIds: listSignalAccountIds,
39
- resolveDefaultAccountId: resolveDefaultSignalAccountId,
40
- normalizeForwardTarget: normalizeSignalForwardTarget,
41
- resolveTurnSourceTarget: resolveTurnSourceSignalOriginTarget
32
+ channelLabel: "Signal",
33
+ authorizeActorAction: (params) => signalApprovalAuth.authorizeActorAction(params),
34
+ routing: {
35
+ defaultForwardingMode: "session",
36
+ isTransportEnabled: isSignalApprovalTransportEnabled,
37
+ listAccountIds: listSignalAccountIds,
38
+ resolveDefaultAccountId: resolveDefaultSignalAccountId,
39
+ normalizeTo: normalizeSignalMessagingTarget,
40
+ resolveApprovers: getSignalApprovalApprovers,
41
+ suppressExplicitTargetFallback: false,
42
+ isOriginTargetAllowed: ({ cfg, accountId, target }) => !isSignalGroupTarget(target.to) || getSignalApprovalApprovers({
43
+ cfg,
44
+ accountId
45
+ }).length > 0
46
+ },
47
+ describeExecApprovalSetup: ({ accountId }) => {
48
+ return `Signal supports native exec approvals for this account when \`approvals.exec.enabled\` is true and the route allows Signal. Link Signal and keep the gateway running; configure \`${accountId && accountId !== "default" ? `channels.signal.accounts.${accountId}` : "channels.signal"}.allowFrom\` to restrict approvers.`;
49
+ },
50
+ render: {
51
+ exec: { buildPendingPayload: ({ request, nowMs }) => buildApprovalReactionPendingContentForRequest({
52
+ request,
53
+ nowMs
54
+ }).manualFallbackPayload },
55
+ plugin: { buildPendingPayload: ({ request, nowMs }) => buildApprovalReactionPendingContentForRequest({
56
+ request,
57
+ nowMs
58
+ }).manualFallbackPayload }
59
+ },
60
+ createNativeRuntime: (routing) => createLazyChannelApprovalNativeRuntimeAdapter({
61
+ eventKinds: ["exec", "plugin"],
62
+ isConfigured: ({ cfg, accountId, context }) => Boolean(context) && routing.isNativeApprovalHandlerConfigured({
63
+ cfg,
64
+ accountId
65
+ }),
66
+ shouldHandle: ({ cfg, accountId, context, approvalKind, request }) => Boolean(context) && routing.shouldHandleApprovalRequest({
67
+ cfg,
68
+ accountId,
69
+ approvalKind,
70
+ request
71
+ }),
72
+ load: async () => (await import("./approval-handler.runtime-Co6EVTqY.js")).signalApprovalNativeRuntime
73
+ })
42
74
  });
75
+ const signalApprovalRouting = signalApproval.routing;
43
76
  function isSignalNativeApprovalHandlerConfigured(params) {
44
- return isSignalNativeApprovalHandlerConfiguredBase(params);
77
+ return signalApprovalRouting.isNativeApprovalHandlerConfigured(params);
45
78
  }
46
79
  function resolveSignalSessionTargetFromSessionKey(sessionKey) {
47
80
  const rest = parseAgentSessionKey(sessionKey)?.rest ?? normalizeOptionalString(sessionKey);
@@ -62,137 +95,10 @@ function shouldSuppressLocalSignalExecApprovalPrompt(params) {
62
95
  }
63
96
  });
64
97
  }
65
- const resolveSignalOriginTargetBase = createChannelNativeOriginTargetResolver({
66
- channel: "signal",
67
- shouldHandleRequest: shouldHandleSignalApprovalRequest,
68
- resolveTurnSourceTarget: resolveTurnSourceSignalOriginTarget,
69
- resolveSessionTarget: resolveSessionSignalOriginTarget,
70
- normalizeTarget: normalizeSignalApprovalTarget
71
- });
72
98
  function isSignalGroupTarget(to) {
73
99
  return normalizeLowercaseStringOrEmpty(to).startsWith("group:");
74
100
  }
75
- function resolveSignalOriginTarget(params) {
76
- const target = resolveSignalOriginTargetBase(params);
77
- if (!target) return null;
78
- if (isSignalGroupTarget(target.to) && getSignalApprovalApprovers({
79
- cfg: params.cfg,
80
- accountId: params.accountId
81
- }).length === 0) return null;
82
- return target;
83
- }
84
- const resolveSignalApproverDmTargets = createChannelApproverDmTargetResolver({
85
- shouldHandleRequest: shouldHandleSignalApprovalRequest,
86
- resolveApprovers: getSignalApprovalApprovers,
87
- mapApprover: (approver, params) => {
88
- const to = normalizeSignalMessagingTarget(approver);
89
- if (!to) return null;
90
- return {
91
- to,
92
- accountId: normalizeOptionalString(params.accountId)
93
- };
94
- }
95
- });
96
- const shouldSuppressSignalForwardingFallback = createNativeApprovalForwardingFallbackSuppressor({
97
- channel: "signal",
98
- normalizeForwardTarget: normalizeSignalForwardTarget,
99
- resolveAccountId: ({ forwardingTarget, request }) => forwardingTarget.accountId ?? normalizeOptionalString(request.request.turnSourceAccountId),
100
- resolveForwardingTargetForMatch: ({ forwardingTarget, accountId }) => ({
101
- ...forwardingTarget,
102
- accountId
103
- }),
104
- isSessionRouteEligible: isSignalSessionApprovalEligible,
105
- resolveOriginTarget: resolveSignalOriginTarget,
106
- resolveApproverDmTargets: resolveSignalApproverDmTargets
107
- });
108
- function buildSignalExecPendingPayload(params) {
109
- return buildApprovalReactionPendingContentForRequest(params).manualFallbackPayload;
110
- }
111
- function buildSignalPluginPendingPayload(params) {
112
- return buildApprovalReactionPendingContentForRequest(params).manualFallbackPayload;
113
- }
114
- const signalApprovalCapability = createChannelApprovalCapability({
115
- ...signalApprovalAuth,
116
- getActionAvailabilityState: ({ cfg, accountId, approvalKind }) => (approvalKind ? canApprovalPotentiallyRouteToSignal({
117
- cfg,
118
- accountId,
119
- approvalKind
120
- }) : canAnyApprovalPotentiallyRouteToSignal({
121
- cfg,
122
- accountId
123
- })) ? { kind: "enabled" } : { kind: "disabled" },
124
- getExecInitiatingSurfaceState: ({ cfg, accountId }) => canApprovalPotentiallyRouteToSignal({
125
- cfg,
126
- accountId,
127
- approvalKind: "exec"
128
- }) ? { kind: "enabled" } : { kind: "disabled" },
129
- describeExecApprovalSetup: ({ accountId }) => {
130
- return `Signal supports native exec approvals for this account when \`approvals.exec.enabled\` is true and the route allows Signal. Link Signal and keep the gateway running; configure \`${accountId && accountId !== "default" ? `channels.signal.accounts.${accountId}` : "channels.signal"}.allowFrom\` to restrict approvers.`;
131
- },
132
- delivery: {
133
- hasConfiguredDmRoute: ({ cfg }) => listSignalAccountIds(cfg).some((accountId) => {
134
- if (!canAnyApprovalPotentiallyRouteToSignal({
135
- cfg,
136
- accountId,
137
- nativeSessionOnly: true
138
- })) return false;
139
- return getSignalApprovalApprovers({
140
- cfg,
141
- accountId
142
- }).length > 0;
143
- }),
144
- shouldSuppressForwardingFallback: shouldSuppressSignalForwardingFallback
145
- },
146
- render: {
147
- exec: { buildPendingPayload: ({ request, nowMs }) => buildSignalExecPendingPayload({
148
- request,
149
- nowMs
150
- }) },
151
- plugin: { buildPendingPayload: ({ request, nowMs }) => buildSignalPluginPendingPayload({
152
- request,
153
- nowMs
154
- }) }
155
- },
156
- native: {
157
- describeDeliveryCapabilities: ({ cfg, accountId, approvalKind, request }) => {
158
- const originTarget = resolveSignalOriginTarget({
159
- cfg,
160
- accountId,
161
- approvalKind,
162
- request
163
- });
164
- const approverTargets = resolveSignalApproverDmTargets({
165
- cfg,
166
- accountId,
167
- approvalKind,
168
- request
169
- });
170
- return {
171
- enabled: Boolean(originTarget) || approverTargets.length > 0,
172
- preferredSurface: originTarget ? "origin" : "approver-dm",
173
- supportsOriginSurface: Boolean(originTarget),
174
- supportsApproverDmSurface: approverTargets.length > 0,
175
- notifyOriginWhenDmOnly: true
176
- };
177
- },
178
- resolveOriginTarget: resolveSignalOriginTarget,
179
- resolveApproverDmTargets: resolveSignalApproverDmTargets
180
- },
181
- nativeRuntime: createLazyChannelApprovalNativeRuntimeAdapter({
182
- eventKinds: ["exec", "plugin"],
183
- isConfigured: ({ cfg, accountId, context }) => Boolean(context) && isSignalNativeApprovalHandlerConfigured({
184
- cfg,
185
- accountId
186
- }),
187
- shouldHandle: ({ cfg, accountId, context, approvalKind, request }) => Boolean(context) && shouldHandleSignalApprovalRequest({
188
- cfg,
189
- accountId,
190
- approvalKind,
191
- request
192
- }),
193
- load: async () => (await import("./approval-handler.runtime-C-XYgcxE.js")).signalApprovalNativeRuntime
194
- })
195
- });
101
+ const signalApprovalCapability = signalApproval.capability;
196
102
  //#endregion
197
103
  //#region extensions/signal/src/format.ts
198
104
  const SIGNAL_STYLE_MAP = {
@@ -459,6 +365,12 @@ const signalReplyAuthorState = {
459
365
  persistentStoreDisabled: false
460
366
  };
461
367
  //#endregion
368
+ //#region extensions/signal/src/runtime.ts
369
+ const { setRuntime: setSignalRuntime, tryGetRuntime: getOptionalSignalRuntime } = createPluginRuntimeStore({
370
+ pluginId: "signal",
371
+ errorMessage: "Signal runtime not initialized"
372
+ });
373
+ //#endregion
462
374
  //#region extensions/signal/src/reply-authors.ts
463
375
  const PERSISTENT_NAMESPACE = "signal.reply-authors.v1";
464
376
  const PERSISTENT_MAX_ENTRIES = 5e3;
@@ -633,7 +545,7 @@ const DEFAULT_PROBE_TIMEOUT_MS = 1e4;
633
545
  async function detectSignalTransport(params) {
634
546
  const url = normalizeSignalTransportUrl(params.url);
635
547
  const timeoutMs = params.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
636
- const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-CV6Qs0Og.js");
548
+ const probes = params.probeNative && params.probeContainer ? void 0 : await import("./transport-probes.runtime-BsJdp0oI.js");
637
549
  const probeNative = params.probeNative ?? probes?.nativeCheck;
638
550
  const probeContainer = params.probeContainer ?? probes?.containerCheck;
639
551
  if (!probeNative || !probeContainer) throw new Error("Signal transport probes are unavailable");
@@ -649,4 +561,4 @@ async function detectSignalTransport(params) {
649
561
  throw new Error(`Signal transport not reachable at ${url}`);
650
562
  }
651
563
  //#endregion
652
- export { signalMessageActions as a, markdownToSignalText as c, shouldSuppressLocalSignalExecApprovalPrompt as d, signalApprovalCapability as f, materializeSignalPresentationFallback as i, markdownToSignalTextChunks as l, registerSignalReplyContext as n, resolveSignalReactionLevel as o, resolveSignalReplyContextWithPersistence as r, formatSignalMediaText as s, detectSignalTransport as t, isSignalNativeApprovalHandlerConfigured as u };
564
+ export { setSignalRuntime as a, resolveSignalReactionLevel as c, markdownToSignalTextChunks as d, isSignalNativeApprovalHandlerConfigured as f, getOptionalSignalRuntime as i, formatSignalMediaText as l, signalApprovalCapability as m, registerSignalReplyContext as n, materializeSignalPresentationFallback as o, shouldSuppressLocalSignalExecApprovalPrompt as p, resolveSignalReplyContextWithPersistence as r, signalMessageActions as s, detectSignalTransport as t, markdownToSignalText as u };
@@ -1,2 +1,2 @@
1
- import { t as detectSignalTransport } from "./transport-detection-Da06-LOL.js";
1
+ import { t as detectSignalTransport } from "./transport-detection-D_M79R5f.js";
2
2
  export { detectSignalTransport };
@@ -1,2 +1,2 @@
1
- import { i as containerCheck, t as signalCheck } from "./client-BazXTH7O.js";
1
+ import { i as containerCheck, t as signalCheck } from "./client-CvnR8_XA.js";
2
2
  export { containerCheck, signalCheck as nativeCheck };
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "id": "signal",
3
+ "doctorContract": {
4
+ "configRepair": true
5
+ },
3
6
  "icon": "https://cdn.simpleicons.org/signal",
4
7
  "activation": {
5
8
  "onStartup": false
@@ -1011,7 +1014,7 @@
1011
1014
  "additionalProperties": false
1012
1015
  },
1013
1016
  "label": "Signal",
1014
- "description": "signal-cli linked device; more setup (David Reagans: \"Hop on Discord.\").",
1017
+ "description": "signal-cli linked device with additional setup for the local REST bridge.",
1015
1018
  "uiHints": {
1016
1019
  "": {
1017
1020
  "label": "Signal",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/signal",
3
- "version": "2026.7.2-beta.7",
3
+ "version": "2026.8.1-beta.3",
4
4
  "description": "OpenClaw Signal channel plugin",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -25,7 +25,7 @@
25
25
  "detailLabel": "Signal REST",
26
26
  "docsPath": "/channels/signal",
27
27
  "docsLabel": "signal",
28
- "blurb": "signal-cli linked device; more setup (David Reagans: \"Hop on Discord.\").",
28
+ "blurb": "signal-cli linked device with additional setup for the local REST bridge.",
29
29
  "systemImage": "antenna.radiowaves.left.and.right",
30
30
  "markdownCapable": true,
31
31
  "setup": {
@@ -93,10 +93,10 @@
93
93
  "allowInvalidConfigRecovery": true
94
94
  },
95
95
  "compat": {
96
- "pluginApi": ">=2026.7.2-beta.7"
96
+ "pluginApi": ">=2026.8.1-beta.3"
97
97
  },
98
98
  "build": {
99
- "openclawVersion": "2026.7.2-beta.7",
99
+ "openclawVersion": "2026.8.1-beta.3",
100
100
  "bundledDist": false
101
101
  },
102
102
  "release": {
@@ -118,7 +118,7 @@
118
118
  "README.md"
119
119
  ],
120
120
  "peerDependencies": {
121
- "openclaw": ">=2026.7.2-beta.7"
121
+ "openclaw": ">=2026.8.1-beta.3"
122
122
  },
123
123
  "peerDependenciesMeta": {
124
124
  "openclaw": {