@openclaw/signal 0.0.0 → 2026.6.11

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 (49) hide show
  1. package/README.md +12 -2
  2. package/dist/accounts-hOCHbEhX.js +40 -0
  3. package/dist/api.js +16 -0
  4. package/dist/approval-handler.runtime-CeJI1wow.js +158 -0
  5. package/dist/approval-resolver-BR0MioAA.js +15 -0
  6. package/dist/channel-LmY2UpOt.js +619 -0
  7. package/dist/channel-config-api.js +2 -0
  8. package/dist/channel-entry.js +18 -0
  9. package/dist/channel-plugin-api.js +2 -0
  10. package/dist/channel.runtime-B0-YpkC4.js +65 -0
  11. package/dist/config-api-KS-qhQvD.js +2 -0
  12. package/dist/config-schema-BiojLEsX.js +27 -0
  13. package/dist/contract-api.js +3 -0
  14. package/dist/identity-B6O4k8xg.js +130 -0
  15. package/dist/index.js +18 -0
  16. package/dist/install-signal-cli-CXgTF3de.js +243 -0
  17. package/dist/message-actions-Bue0g2Kc.js +548 -0
  18. package/dist/monitor-CUhIKHJo.js +1404 -0
  19. package/dist/probe-BQ_Izoya.js +48 -0
  20. package/dist/reaction-runtime-api-C_PQ45D9.js +1074 -0
  21. package/dist/reaction-runtime-api.js +2 -0
  22. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  23. package/dist/runtime-api.js +18 -0
  24. package/dist/secret-contract-api.js +5 -0
  25. package/dist/send-CBlFUkY_.js +599 -0
  26. package/dist/send.runtime-CfaZd8X4.js +2 -0
  27. package/dist/setup-entry.js +11 -0
  28. package/node_modules/ws/LICENSE +20 -0
  29. package/node_modules/ws/README.md +548 -0
  30. package/node_modules/ws/browser.js +8 -0
  31. package/node_modules/ws/index.js +22 -0
  32. package/node_modules/ws/lib/buffer-util.js +131 -0
  33. package/node_modules/ws/lib/constants.js +19 -0
  34. package/node_modules/ws/lib/event-target.js +292 -0
  35. package/node_modules/ws/lib/extension.js +203 -0
  36. package/node_modules/ws/lib/limiter.js +55 -0
  37. package/node_modules/ws/lib/permessage-deflate.js +528 -0
  38. package/node_modules/ws/lib/receiver.js +760 -0
  39. package/node_modules/ws/lib/sender.js +607 -0
  40. package/node_modules/ws/lib/stream.js +161 -0
  41. package/node_modules/ws/lib/subprotocol.js +62 -0
  42. package/node_modules/ws/lib/validation.js +152 -0
  43. package/node_modules/ws/lib/websocket-server.js +562 -0
  44. package/node_modules/ws/lib/websocket.js +1407 -0
  45. package/node_modules/ws/package.json +70 -0
  46. package/node_modules/ws/wrapper.mjs +21 -0
  47. package/npm-shrinkwrap.json +36 -0
  48. package/openclaw.plugin.json +771 -0
  49. package/package.json +77 -7
@@ -0,0 +1,619 @@
1
+ import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId } from "./accounts-hOCHbEhX.js";
2
+ import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-B6O4k8xg.js";
3
+ import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, o as shouldSuppressLocalSignalExecApprovalPrompt, s as signalApprovalCapability, t as signalMessageActions } from "./message-actions-Bue0g2Kc.js";
4
+ import { t as SignalChannelConfigSchema } from "./config-schema-BiojLEsX.js";
5
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
6
+ import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
7
+ import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
8
+ import { defineChannelMessageAdapter, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
9
+ import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
10
+ import { attachChannelToResult, attachChannelToResults } from "openclaw/plugin-sdk/channel-send-result";
11
+ import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
12
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
13
+ import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
14
+ import { chunkText, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
15
+ import { buildOutboundBaseSessionKey } from "openclaw/plugin-sdk/routing";
16
+ import { buildBaseChannelStatusSummary, collectStatusIssuesFromLastError, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
17
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
18
+ import { normalizeE164 } from "openclaw/plugin-sdk/text-utility-runtime";
19
+ import { createChannelPluginBase, getChatChannelMeta } from "openclaw/plugin-sdk/core";
20
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, createCliPathTextInput, createDelegatedSetupWizardProxy, createDelegatedTextInputShouldPrompt, createPatchedAccountSetupAdapter, createSetupInputPresenceValidator, createSetupTranslator, mergeAllowFromEntries, parseSetupEntriesAllowingWildcard, patchChannelConfigForAccount, promptParsedAllowFromForAccount, setAccountAllowFromForChannel, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup-runtime";
21
+ import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
22
+ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
23
+ import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
24
+ import { createRestrictSendersChannelSecurity } from "openclaw/plugin-sdk/channel-policy";
25
+ //#region extensions/signal/src/outbound-session.ts
26
+ function resolveSignalOutboundTarget(target) {
27
+ const stripped = target.replace(/^signal:/i, "").trim();
28
+ const lowered = normalizeLowercaseStringOrEmpty(stripped);
29
+ if (lowered.startsWith("group:")) {
30
+ const groupId = stripped.slice(6).trim();
31
+ if (!groupId) return null;
32
+ return {
33
+ peer: {
34
+ kind: "group",
35
+ id: groupId
36
+ },
37
+ chatType: "group",
38
+ from: `group:${groupId}`,
39
+ to: `group:${groupId}`
40
+ };
41
+ }
42
+ let recipient = stripped.trim();
43
+ if (lowered.startsWith("username:")) recipient = stripped.slice(9).trim();
44
+ else if (lowered.startsWith("u:")) recipient = stripped.slice(2).trim();
45
+ if (!recipient) return null;
46
+ const uuidCandidate = normalizeLowercaseStringOrEmpty(recipient).startsWith("uuid:") ? recipient.slice(5) : recipient;
47
+ const sender = resolveSignalSender({
48
+ sourceUuid: looksLikeUuid(uuidCandidate) ? uuidCandidate : null,
49
+ sourceNumber: looksLikeUuid(uuidCandidate) ? null : recipient
50
+ });
51
+ const peerId = sender ? resolveSignalPeerId(sender) : recipient;
52
+ const displayRecipient = sender ? resolveSignalRecipient(sender) : recipient;
53
+ return {
54
+ peer: {
55
+ kind: "direct",
56
+ id: peerId
57
+ },
58
+ chatType: "direct",
59
+ from: `signal:${displayRecipient}`,
60
+ to: `signal:${displayRecipient}`
61
+ };
62
+ }
63
+ //#endregion
64
+ //#region extensions/signal/src/setup-core.ts
65
+ const t = createSetupTranslator();
66
+ const channel = "signal";
67
+ const MIN_E164_DIGITS = 5;
68
+ const MAX_E164_DIGITS = 15;
69
+ const DIGITS_ONLY = /^\d+$/;
70
+ const INVALID_SIGNAL_ACCOUNT_ERROR = "Invalid E.164 phone number (must start with + and country code, e.g. +15555550123)";
71
+ function normalizeSignalAccountInput(value) {
72
+ const trimmed = normalizeOptionalString(value);
73
+ if (!trimmed) return null;
74
+ const digits = normalizeE164(trimmed).slice(1);
75
+ if (!DIGITS_ONLY.test(digits)) return null;
76
+ if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null;
77
+ return `+${digits}`;
78
+ }
79
+ function isUuidLike(value) {
80
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
81
+ }
82
+ function parseSignalAllowFromEntries(raw) {
83
+ return parseSetupEntriesAllowingWildcard(raw, (entry) => {
84
+ if (normalizeLowercaseStringOrEmpty(entry).startsWith("uuid:")) {
85
+ const id = entry.slice(5).trim();
86
+ if (!id) return { error: "Invalid uuid entry" };
87
+ return { value: `uuid:${id}` };
88
+ }
89
+ if (isUuidLike(entry)) return { value: `uuid:${entry}` };
90
+ const normalized = normalizeSignalAccountInput(entry);
91
+ if (!normalized) return { error: `Invalid entry: ${entry}` };
92
+ return { value: normalized };
93
+ });
94
+ }
95
+ function buildSignalSetupPatch(input) {
96
+ return {
97
+ ...input.signalNumber ? { account: input.signalNumber } : {},
98
+ ...input.cliPath ? { cliPath: input.cliPath } : {},
99
+ ...input.httpUrl ? { httpUrl: input.httpUrl } : {},
100
+ ...input.httpHost ? { httpHost: input.httpHost } : {},
101
+ ...input.httpPort ? { httpPort: Number(input.httpPort) } : {}
102
+ };
103
+ }
104
+ async function promptSignalAllowFrom(params) {
105
+ return promptParsedAllowFromForAccount({
106
+ cfg: params.cfg,
107
+ accountId: params.accountId,
108
+ defaultAccountId: resolveDefaultSignalAccountId(params.cfg),
109
+ prompter: params.prompter,
110
+ noteTitle: t("wizard.signal.allowlistTitle"),
111
+ noteLines: [
112
+ t("wizard.signal.allowlistIntro"),
113
+ t("wizard.signal.examples"),
114
+ "- +15555550123",
115
+ "- uuid:123e4567-e89b-12d3-a456-426614174000",
116
+ t("wizard.signal.multipleEntries"),
117
+ `Docs: ${formatDocsLink("/signal", "signal")}`
118
+ ],
119
+ message: t("wizard.signal.allowFromPrompt"),
120
+ placeholder: "+15555550123, uuid:123e4567-e89b-12d3-a456-426614174000",
121
+ parseEntries: parseSignalAllowFromEntries,
122
+ getExistingAllowFrom: ({ cfg, accountId }) => resolveSignalAccount({
123
+ cfg,
124
+ accountId
125
+ }).config.allowFrom ?? [],
126
+ applyAllowFrom: ({ cfg, accountId, allowFrom }) => setAccountAllowFromForChannel({
127
+ cfg,
128
+ channel,
129
+ accountId,
130
+ allowFrom
131
+ })
132
+ });
133
+ }
134
+ const signalDmPolicy = {
135
+ label: "Signal",
136
+ channel,
137
+ policyKey: "channels.signal.dmPolicy",
138
+ allowFromKey: "channels.signal.allowFrom",
139
+ resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultSignalAccountId(cfg)) !== DEFAULT_ACCOUNT_ID$1 ? {
140
+ policyKey: `channels.signal.accounts.${accountId ?? resolveDefaultSignalAccountId(cfg)}.dmPolicy`,
141
+ allowFromKey: `channels.signal.accounts.${accountId ?? resolveDefaultSignalAccountId(cfg)}.allowFrom`
142
+ } : {
143
+ policyKey: "channels.signal.dmPolicy",
144
+ allowFromKey: "channels.signal.allowFrom"
145
+ },
146
+ getCurrent: (cfg, accountId) => resolveSignalAccount({
147
+ cfg,
148
+ accountId: accountId ?? resolveDefaultSignalAccountId(cfg)
149
+ }).config.dmPolicy ?? "pairing",
150
+ setPolicy: (cfg, policy, accountId) => patchChannelConfigForAccount({
151
+ cfg,
152
+ channel,
153
+ accountId: accountId ?? resolveDefaultSignalAccountId(cfg),
154
+ patch: policy === "open" ? {
155
+ dmPolicy: "open",
156
+ allowFrom: mergeAllowFromEntries(resolveSignalAccount({
157
+ cfg,
158
+ accountId: accountId ?? resolveDefaultSignalAccountId(cfg)
159
+ }).config.allowFrom, ["*"])
160
+ } : { dmPolicy: policy }
161
+ }),
162
+ promptAllowFrom: promptSignalAllowFrom
163
+ };
164
+ function resolveSignalCliPath(params) {
165
+ return (typeof params.credentialValues.cliPath === "string" ? params.credentialValues.cliPath : void 0) ?? resolveSignalAccount({
166
+ cfg: params.cfg,
167
+ accountId: params.accountId
168
+ }).config.cliPath ?? "signal-cli";
169
+ }
170
+ function createSignalCliPathTextInput(shouldPrompt) {
171
+ return createCliPathTextInput({
172
+ inputKey: "cliPath",
173
+ message: "signal-cli path",
174
+ resolvePath: ({ cfg, accountId, credentialValues }) => resolveSignalCliPath({
175
+ cfg,
176
+ accountId,
177
+ credentialValues
178
+ }),
179
+ shouldPrompt,
180
+ helpTitle: "Signal",
181
+ helpLines: ["signal-cli not found. Install it, then rerun this step or set channels.signal.cliPath."]
182
+ });
183
+ }
184
+ const signalNumberTextInput = {
185
+ inputKey: "signalNumber",
186
+ message: t("wizard.signal.botNumberPrompt"),
187
+ currentValue: ({ cfg, accountId }) => normalizeSignalAccountInput(resolveSignalAccount({
188
+ cfg,
189
+ accountId
190
+ }).config.account) ?? void 0,
191
+ keepPrompt: (value) => t("wizard.signal.accountKeep", { value }),
192
+ validate: ({ value }) => normalizeSignalAccountInput(value) ? void 0 : INVALID_SIGNAL_ACCOUNT_ERROR,
193
+ normalizeValue: ({ value }) => normalizeSignalAccountInput(value) ?? value
194
+ };
195
+ const signalCompletionNote = {
196
+ title: t("wizard.signal.nextStepsTitle"),
197
+ lines: [
198
+ t("wizard.signal.nextLinkDevice"),
199
+ t("wizard.signal.nextScanQr"),
200
+ `Then run: ${formatCliCommand("openclaw gateway call channels.status --params '{\"probe\":true}'")}`,
201
+ `Docs: ${formatDocsLink("/signal", "signal")}`
202
+ ]
203
+ };
204
+ const signalSetupAdapter = createPatchedAccountSetupAdapter({
205
+ channelKey: channel,
206
+ validateInput: createSetupInputPresenceValidator({ validate: ({ input }) => {
207
+ if (!input.signalNumber && !input.httpUrl && !input.httpHost && !input.httpPort && !input.cliPath) return "Signal requires --signal-number or --http-url/--http-host/--http-port/--cli-path.";
208
+ return null;
209
+ } }),
210
+ buildPatch: (input) => buildSignalSetupPatch(input)
211
+ });
212
+ function createSignalSetupWizardProxy(loadWizard) {
213
+ return createDelegatedSetupWizardProxy({
214
+ channel,
215
+ loadWizard,
216
+ status: {
217
+ configuredLabel: t("wizard.channels.statusConfigured"),
218
+ unconfiguredLabel: t("wizard.channels.statusNeedsSetup"),
219
+ configuredHint: t("wizard.channels.statusSignalCliFound"),
220
+ unconfiguredHint: t("wizard.channels.statusSignalCliMissing"),
221
+ configuredScore: 1,
222
+ unconfiguredScore: 0
223
+ },
224
+ delegatePrepare: true,
225
+ credentials: [],
226
+ textInputs: [createSignalCliPathTextInput(createDelegatedTextInputShouldPrompt({
227
+ loadWizard,
228
+ inputKey: "cliPath"
229
+ })), signalNumberTextInput],
230
+ completionNote: signalCompletionNote,
231
+ dmPolicy: signalDmPolicy,
232
+ disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
233
+ });
234
+ }
235
+ //#endregion
236
+ //#region extensions/signal/src/shared.ts
237
+ const SIGNAL_CHANNEL = "signal";
238
+ async function loadSignalChannelRuntime() {
239
+ return await import("./channel.runtime-B0-YpkC4.js");
240
+ }
241
+ const signalSetupWizard = createSignalSetupWizardProxy(async () => (await loadSignalChannelRuntime()).signalSetupWizard);
242
+ const signalConfigAdapter = createScopedChannelConfigAdapter({
243
+ sectionKey: SIGNAL_CHANNEL,
244
+ listAccountIds: (cfg) => listSignalAccountIds(cfg),
245
+ resolveAccount: adaptScopedAccountAccessor((params) => resolveSignalAccount(params)),
246
+ defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg),
247
+ clearBaseFields: [
248
+ "account",
249
+ "configPath",
250
+ "httpUrl",
251
+ "httpHost",
252
+ "httpPort",
253
+ "cliPath",
254
+ "name"
255
+ ],
256
+ resolveAllowFrom: (account) => account.config.allowFrom,
257
+ formatAllowFrom: (allowFrom) => normalizeStringifiedEntries(allowFrom).map((entry) => entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))).filter(Boolean),
258
+ resolveDefaultTo: (account) => account.config.defaultTo
259
+ });
260
+ const signalSecurityAdapter = createRestrictSendersChannelSecurity({
261
+ channelKey: SIGNAL_CHANNEL,
262
+ resolveDmPolicy: (account) => account.config.dmPolicy,
263
+ resolveDmAllowFrom: (account) => account.config.allowFrom,
264
+ resolveGroupPolicy: (account) => account.config.groupPolicy,
265
+ surface: "Signal groups",
266
+ openScope: "any member",
267
+ groupPolicyPath: "channels.signal.groupPolicy",
268
+ groupAllowFromPath: "channels.signal.groupAllowFrom",
269
+ mentionGated: false,
270
+ policyPathSuffix: "dmPolicy",
271
+ normalizeDmEntry: (raw) => normalizeE164(raw.replace(/^signal:/i, "").trim())
272
+ });
273
+ function createSignalPluginBase(params) {
274
+ return {
275
+ ...createChannelPluginBase({
276
+ id: SIGNAL_CHANNEL,
277
+ meta: { ...getChatChannelMeta(SIGNAL_CHANNEL) },
278
+ setupWizard: params.setupWizard,
279
+ capabilities: {
280
+ chatTypes: ["direct", "group"],
281
+ media: true,
282
+ reactions: true
283
+ },
284
+ streaming: { blockStreamingCoalesceDefaults: {
285
+ minChars: 1500,
286
+ idleMs: 1e3
287
+ } },
288
+ reload: { configPrefixes: ["channels.signal"] },
289
+ configSchema: SignalChannelConfigSchema,
290
+ config: {
291
+ ...signalConfigAdapter,
292
+ isConfigured: (account) => account.configured,
293
+ describeAccount: (account) => describeAccountSnapshot({
294
+ account,
295
+ configured: account.configured,
296
+ extra: { baseUrl: account.baseUrl }
297
+ })
298
+ },
299
+ security: signalSecurityAdapter,
300
+ setup: params.setup
301
+ }),
302
+ messaging: { defaultMarkdownTableMode: "bullets" }
303
+ };
304
+ }
305
+ //#endregion
306
+ //#region extensions/signal/src/channel.ts
307
+ let signalMonitorModulePromise = null;
308
+ let signalProbeModulePromise = null;
309
+ let signalSendRuntimePromise = null;
310
+ async function loadSignalMonitorModule() {
311
+ signalMonitorModulePromise ??= import("./monitor-CUhIKHJo.js").then((n) => n.n);
312
+ return await signalMonitorModulePromise;
313
+ }
314
+ async function loadSignalProbeModule() {
315
+ signalProbeModulePromise ??= import("./probe-BQ_Izoya.js").then((n) => n.n);
316
+ return await signalProbeModulePromise;
317
+ }
318
+ async function loadSignalSendRuntime() {
319
+ signalSendRuntimePromise ??= import("./send.runtime-CfaZd8X4.js");
320
+ return await signalSendRuntimePromise;
321
+ }
322
+ async function resolveSignalSendContext(params) {
323
+ return {
324
+ send: resolveOutboundSendDep(params.deps, "signal") ?? (await loadSignalSendRuntime()).sendMessageSignal,
325
+ maxBytes: resolveChannelMediaMaxBytes({
326
+ cfg: params.cfg,
327
+ resolveChannelLimitMb: ({ cfg, accountId }) => cfg.channels?.signal?.accounts?.[accountId]?.mediaMaxMb ?? cfg.channels?.signal?.mediaMaxMb,
328
+ accountId: params.accountId
329
+ })
330
+ };
331
+ }
332
+ async function sendSignalOutbound(params) {
333
+ const { send, maxBytes } = await resolveSignalSendContext(params);
334
+ return await send(params.to, params.text, {
335
+ cfg: params.cfg,
336
+ ...params.mediaUrl ? { mediaUrl: params.mediaUrl } : {},
337
+ ...params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {},
338
+ ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {},
339
+ maxBytes,
340
+ accountId: params.accountId ?? void 0
341
+ });
342
+ }
343
+ const signalMessageAdapter = defineChannelMessageAdapter({
344
+ id: "signal",
345
+ durableFinal: { capabilities: {
346
+ text: true,
347
+ media: true
348
+ } },
349
+ send: {
350
+ text: async (ctx) => await sendSignalOutbound({
351
+ cfg: ctx.cfg,
352
+ to: ctx.to,
353
+ text: ctx.text,
354
+ accountId: ctx.accountId ?? void 0,
355
+ deps: ctx.deps
356
+ }),
357
+ media: async (ctx) => await sendSignalOutbound({
358
+ cfg: ctx.cfg,
359
+ to: ctx.to,
360
+ text: ctx.text,
361
+ mediaUrl: ctx.mediaUrl,
362
+ mediaLocalRoots: ctx.mediaLocalRoots,
363
+ mediaReadFile: ctx.mediaReadFile,
364
+ accountId: ctx.accountId ?? void 0,
365
+ deps: ctx.deps
366
+ })
367
+ }
368
+ });
369
+ function inferSignalTargetChatType(rawTo) {
370
+ let to = rawTo.trim();
371
+ if (!to) return;
372
+ if (/^signal:/i.test(to)) to = to.replace(/^signal:/i, "").trim();
373
+ if (!to) return;
374
+ const lower = normalizeLowercaseStringOrEmpty(to);
375
+ if (lower.startsWith("group:")) return "group";
376
+ if (lower.startsWith("username:") || lower.startsWith("u:")) return "direct";
377
+ return "direct";
378
+ }
379
+ function buildSignalBaseSessionKey(params) {
380
+ return buildOutboundBaseSessionKey({
381
+ ...params,
382
+ channel: "signal"
383
+ });
384
+ }
385
+ function resolveSignalOutboundSessionRoute(params) {
386
+ const resolved = resolveSignalOutboundTarget(params.target);
387
+ if (!resolved) return null;
388
+ const baseSessionKey = buildSignalBaseSessionKey({
389
+ cfg: params.cfg,
390
+ agentId: params.agentId,
391
+ accountId: params.accountId,
392
+ peer: resolved.peer
393
+ });
394
+ return {
395
+ sessionKey: baseSessionKey,
396
+ baseSessionKey,
397
+ ...resolved
398
+ };
399
+ }
400
+ async function sendFormattedSignalText(ctx) {
401
+ const { send, maxBytes } = await resolveSignalSendContext({
402
+ cfg: ctx.cfg,
403
+ accountId: ctx.accountId ?? void 0,
404
+ deps: ctx.deps
405
+ });
406
+ const limit = resolveTextChunkLimit(ctx.cfg, "signal", ctx.accountId ?? void 0, { fallbackLimit: 4e3 });
407
+ const tableMode = resolveMarkdownTableMode({
408
+ cfg: ctx.cfg,
409
+ channel: "signal",
410
+ accountId: ctx.accountId ?? void 0
411
+ });
412
+ let chunks = limit === void 0 ? markdownToSignalTextChunks(ctx.text, Number.POSITIVE_INFINITY, { tableMode }) : markdownToSignalTextChunks(ctx.text, limit, { tableMode });
413
+ if (chunks.length === 0 && ctx.text) chunks = [{
414
+ text: ctx.text,
415
+ styles: []
416
+ }];
417
+ const results = [];
418
+ for (const chunk of chunks) {
419
+ ctx.abortSignal?.throwIfAborted();
420
+ const result = await send(ctx.to, chunk.text, {
421
+ cfg: ctx.cfg,
422
+ maxBytes,
423
+ accountId: ctx.accountId ?? void 0,
424
+ textMode: "plain",
425
+ textStyles: chunk.styles
426
+ });
427
+ results.push(result);
428
+ }
429
+ return attachChannelToResults("signal", results);
430
+ }
431
+ async function sendFormattedSignalMedia(ctx) {
432
+ ctx.abortSignal?.throwIfAborted();
433
+ const { send, maxBytes } = await resolveSignalSendContext({
434
+ cfg: ctx.cfg,
435
+ accountId: ctx.accountId ?? void 0,
436
+ deps: ctx.deps
437
+ });
438
+ const tableMode = resolveMarkdownTableMode({
439
+ cfg: ctx.cfg,
440
+ channel: "signal",
441
+ accountId: ctx.accountId ?? void 0
442
+ });
443
+ const formatted = markdownToSignalTextChunks(ctx.text, Number.POSITIVE_INFINITY, { tableMode })[0] ?? {
444
+ text: ctx.text,
445
+ styles: []
446
+ };
447
+ return attachChannelToResult("signal", await send(ctx.to, formatted.text, {
448
+ cfg: ctx.cfg,
449
+ mediaUrl: ctx.mediaUrl,
450
+ mediaLocalRoots: ctx.mediaLocalRoots,
451
+ ...ctx.mediaReadFile ? { mediaReadFile: ctx.mediaReadFile } : {},
452
+ maxBytes,
453
+ accountId: ctx.accountId ?? void 0,
454
+ textMode: "plain",
455
+ textStyles: formatted.styles
456
+ }));
457
+ }
458
+ const signalPlugin = createChatChannelPlugin({
459
+ base: {
460
+ ...createSignalPluginBase({
461
+ setupWizard: signalSetupWizard,
462
+ setup: signalSetupAdapter
463
+ }),
464
+ actions: signalMessageActions,
465
+ approvalCapability: signalApprovalCapability,
466
+ allowlist: buildDmGroupAccountAllowlistAdapter({
467
+ channelId: "signal",
468
+ resolveAccount: resolveSignalAccount,
469
+ normalize: ({ cfg, accountId, values }) => signalConfigAdapter.formatAllowFrom({
470
+ cfg,
471
+ accountId,
472
+ allowFrom: values
473
+ }),
474
+ resolveDmAllowFrom: (account) => account.config.allowFrom,
475
+ resolveGroupAllowFrom: (account) => account.config.groupAllowFrom,
476
+ resolveDmPolicy: (account) => account.config.dmPolicy,
477
+ resolveGroupPolicy: (account) => account.config.groupPolicy
478
+ }),
479
+ agentPrompt: { reactionGuidance: ({ cfg, accountId }) => {
480
+ const level = resolveSignalReactionLevel({
481
+ cfg,
482
+ accountId: accountId ?? void 0
483
+ }).agentReactionGuidance;
484
+ return level ? {
485
+ level,
486
+ channelLabel: "Signal"
487
+ } : void 0;
488
+ } },
489
+ messaging: {
490
+ targetPrefixes: ["signal"],
491
+ normalizeTarget: normalizeSignalMessagingTarget,
492
+ inferTargetChatType: ({ to }) => inferSignalTargetChatType(to),
493
+ resolveOutboundSessionRoute: (params) => resolveSignalOutboundSessionRoute(params),
494
+ targetResolver: {
495
+ looksLikeId: looksLikeSignalTargetId,
496
+ hint: "<E.164|uuid:ID|group:ID|signal:group:ID|signal:+E.164>"
497
+ }
498
+ },
499
+ heartbeat: {
500
+ sendTyping: async ({ cfg, to, accountId }) => {
501
+ await (await loadSignalSendRuntime()).sendTypingSignal(to, {
502
+ cfg,
503
+ ...accountId ? { accountId } : {}
504
+ });
505
+ },
506
+ clearTyping: async ({ cfg, to, accountId }) => {
507
+ await (await loadSignalSendRuntime()).sendTypingSignal(to, {
508
+ cfg,
509
+ ...accountId ? { accountId } : {},
510
+ stop: true
511
+ });
512
+ }
513
+ },
514
+ status: createComputedAccountStatusAdapter({
515
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
516
+ collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("signal", accounts),
517
+ buildChannelSummary: ({ snapshot }) => buildBaseChannelStatusSummary(snapshot, {
518
+ baseUrl: snapshot.baseUrl ?? null,
519
+ probe: snapshot.probe,
520
+ lastProbeAt: snapshot.lastProbeAt ?? null
521
+ }),
522
+ probeAccount: async ({ account, timeoutMs }) => {
523
+ const baseUrl = account.baseUrl;
524
+ const { probeSignal } = await loadSignalProbeModule();
525
+ return await probeSignal(baseUrl, timeoutMs, { apiMode: account.config?.apiMode ?? "auto" });
526
+ },
527
+ formatCapabilitiesProbe: ({ probe }) => probe?.version ? [{ text: `Signal daemon: ${probe.version}` }] : [],
528
+ resolveAccountSnapshot: ({ account }) => ({
529
+ accountId: account.accountId,
530
+ name: account.name,
531
+ enabled: account.enabled,
532
+ configured: account.configured,
533
+ extra: { baseUrl: account.baseUrl }
534
+ })
535
+ }),
536
+ gateway: { startAccount: async (ctx) => {
537
+ const account = ctx.account;
538
+ ctx.setStatus({
539
+ accountId: account.accountId,
540
+ baseUrl: account.baseUrl
541
+ });
542
+ ctx.log?.info(`[${account.accountId}] starting provider (${account.baseUrl})`);
543
+ const { monitorSignalProvider } = await loadSignalMonitorModule();
544
+ return await monitorSignalProvider({
545
+ accountId: account.accountId,
546
+ config: ctx.cfg,
547
+ runtime: ctx.runtime,
548
+ channelRuntime: ctx.channelRuntime,
549
+ abortSignal: ctx.abortSignal,
550
+ mediaMaxMb: account.config.mediaMaxMb
551
+ });
552
+ } },
553
+ message: signalMessageAdapter
554
+ },
555
+ pairing: { text: {
556
+ idLabel: "signalNumber",
557
+ message: PAIRING_APPROVED_MESSAGE,
558
+ normalizeAllowEntry: createPairingPrefixStripper(/^signal:/i),
559
+ notify: async ({ cfg, id, message }) => {
560
+ await (await loadSignalSendRuntime()).sendMessageSignal(id, message, { cfg });
561
+ }
562
+ } },
563
+ security: signalSecurityAdapter,
564
+ outbound: {
565
+ base: {
566
+ deliveryMode: "direct",
567
+ chunker: chunkText,
568
+ chunkerMode: "text",
569
+ textChunkLimit: 4e3,
570
+ shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload, hint }) => shouldSuppressLocalSignalExecApprovalPrompt({
571
+ cfg,
572
+ accountId,
573
+ payload,
574
+ hint
575
+ }),
576
+ sendFormattedText: async ({ cfg, to, text, accountId, deps, abortSignal }) => await sendFormattedSignalText({
577
+ cfg,
578
+ to,
579
+ text,
580
+ accountId,
581
+ deps,
582
+ abortSignal
583
+ }),
584
+ sendFormattedMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, accountId, deps, abortSignal }) => await sendFormattedSignalMedia({
585
+ cfg,
586
+ to,
587
+ text,
588
+ mediaUrl,
589
+ mediaLocalRoots,
590
+ mediaReadFile,
591
+ accountId,
592
+ deps,
593
+ abortSignal
594
+ })
595
+ },
596
+ attachedResults: {
597
+ channel: "signal",
598
+ sendText: async ({ cfg, to, text, accountId, deps }) => await sendSignalOutbound({
599
+ cfg,
600
+ to,
601
+ text,
602
+ accountId: accountId ?? void 0,
603
+ deps
604
+ }),
605
+ sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, accountId, deps }) => await sendSignalOutbound({
606
+ cfg,
607
+ to,
608
+ text,
609
+ mediaUrl,
610
+ mediaLocalRoots,
611
+ mediaReadFile,
612
+ accountId: accountId ?? void 0,
613
+ deps
614
+ })
615
+ }
616
+ }
617
+ });
618
+ //#endregion
619
+ export { normalizeSignalAccountInput as a, signalNumberTextInput as c, createSignalCliPathTextInput as i, signalSetupAdapter as l, createSignalPluginBase as n, signalCompletionNote as o, signalSetupWizard as r, signalDmPolicy as s, signalPlugin as t, resolveSignalOutboundTarget as u };
@@ -0,0 +1,2 @@
1
+ import { t as SignalChannelConfigSchema } from "./config-schema-BiojLEsX.js";
2
+ export { SignalChannelConfigSchema };
@@ -0,0 +1,18 @@
1
+ import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/signal/channel-entry.ts
3
+ var channel_entry_default = defineBundledChannelEntry({
4
+ id: "signal",
5
+ name: "Signal",
6
+ description: "Signal channel plugin",
7
+ importMetaUrl: import.meta.url,
8
+ plugin: {
9
+ specifier: "./api.js",
10
+ exportName: "signalPlugin"
11
+ },
12
+ runtime: {
13
+ specifier: "./runtime-api.js",
14
+ exportName: "setSignalRuntime"
15
+ }
16
+ });
17
+ //#endregion
18
+ export { channel_entry_default as default };
@@ -0,0 +1,2 @@
1
+ import { t as signalPlugin } from "./channel-LmY2UpOt.js";
2
+ export { signalPlugin };