@openclaw/signal 2026.7.1-beta.6 → 2026.7.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +8 -8
- package/dist/{approval-handler.runtime-DDQ4ZRyc.js → approval-handler.runtime-I1SMFwwR.js} +4 -4
- package/dist/{approval-reactions-UFmUPD0A.js → approval-reactions-ChcS2rQN.js} +34 -25
- package/dist/{approval-resolver-BR0MioAA.js → approval-resolver-B3m0D2R0.js} +2 -1
- package/dist/{channel-Cnhy1RwG.js → channel-DK8XZHPe.js} +132 -42
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-CQN0RaFx.js → channel.runtime-BbDh5UIr.js} +3 -2
- package/dist/{client-adapter-C9mB2Jz8.js → client-adapter-aEM0kGhC.js} +52 -18
- package/dist/config-api-DIg1lInT.js +3 -0
- package/dist/{config-schema-BiojLEsX.js → config-schema-CfVNH0DB.js} +7 -9
- package/dist/contract-api.js +3 -3
- package/dist/doctor-contract-api.js +16 -0
- package/dist/{identity-C8-yk4J9.js → identity-BF8taj7g.js} +7 -4
- package/dist/{install-signal-cli-ik8VPaGg.js → install-signal-cli-CtusY3tN.js} +43 -32
- package/dist/{monitor-Bee8O5Ay.js → monitor-BdzH3U64.js} +331 -126
- package/dist/{probe-Cnht8Ihg.js → probe-CbWkI24J.js} +1 -1
- package/dist/{reaction-runtime-api-EQ7cc7-Y.js → reaction-runtime-api-DifyinAU.js} +1 -1
- package/dist/reaction-runtime-api.js +1 -1
- package/dist/{message-actions-3OLDgjis.js → reply-authors-osU_SY4J.js} +212 -9
- package/dist/{approval-auth-CsHNcAiy.js → runtime-BZ9hnS3a.js} +34 -24
- package/dist/runtime-api.js +9 -9
- package/dist/{send-CUJy6WPt.js → send-BWtA6h3J.js} +14 -9
- package/dist/{send.runtime-CEi5oyCG.js → send.runtime-D4WBNNgn.js} +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +72 -48
- package/package.json +4 -4
- package/dist/config-api-KS-qhQvD.js +0 -2
|
@@ -2,8 +2,7 @@ import { detectMime, parseMediaContentLength } from "openclaw/plugin-sdk/media-r
|
|
|
2
2
|
import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
3
3
|
import nodePath from "node:path";
|
|
4
4
|
import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
|
|
5
|
-
import {
|
|
6
|
-
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
5
|
+
import { readResponseTextPrefix, readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
7
6
|
import { readRegularFile } from "openclaw/plugin-sdk/security-runtime";
|
|
8
7
|
import WebSocket from "ws";
|
|
9
8
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
@@ -21,7 +20,10 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
|
21
20
|
*/
|
|
22
21
|
const DEFAULT_TIMEOUT_MS$2 = 1e4;
|
|
23
22
|
const DEFAULT_ATTACHMENT_RESPONSE_MAX_BYTES = 1048576;
|
|
24
|
-
const
|
|
23
|
+
const SIGNAL_REST_ERROR_RESPONSE_MAX_BYTES = 16 * 1024;
|
|
24
|
+
const SIGNAL_REST_SUCCESS_RESPONSE_MAX_BYTES = 16 * 1024 * 1024;
|
|
25
|
+
const WS_MAX_PAYLOAD = 1024 * 1024;
|
|
26
|
+
const WS_HANDSHAKE_MS = 3e4;
|
|
25
27
|
const DEFAULT_SIGNAL_CONTAINER_MAX_ATTACHMENT_BYTES = 8 * 1024 * 1024;
|
|
26
28
|
const CONTAINER_TEXT_STYLE_MARKERS = {
|
|
27
29
|
BOLD: "**",
|
|
@@ -62,10 +64,34 @@ function normalizeMaxResponseBytes(value) {
|
|
|
62
64
|
function readContentLength(res) {
|
|
63
65
|
return parseMediaContentLength(res.headers?.get("content-length") ?? null) ?? void 0;
|
|
64
66
|
}
|
|
65
|
-
|
|
67
|
+
function signalRestIdleTimeoutError({ chunkTimeoutMs }) {
|
|
68
|
+
return /* @__PURE__ */ new Error(`Signal REST response body stalled after ${chunkTimeoutMs}ms`);
|
|
69
|
+
}
|
|
70
|
+
function signalAttachmentIdleTimeoutError({ chunkTimeoutMs }) {
|
|
71
|
+
return /* @__PURE__ */ new Error(`Signal REST attachment response body stalled after ${chunkTimeoutMs}ms`);
|
|
72
|
+
}
|
|
73
|
+
async function readSignalRestText(res, bodyIdleTimeoutMs) {
|
|
74
|
+
const bytes = await readResponseWithLimit(res, SIGNAL_REST_SUCCESS_RESPONSE_MAX_BYTES, {
|
|
75
|
+
chunkTimeoutMs: bodyIdleTimeoutMs,
|
|
76
|
+
onIdleTimeout: signalRestIdleTimeoutError,
|
|
77
|
+
onOverflow: ({ maxBytes }) => /* @__PURE__ */ new Error(`Signal REST: text response exceeds ${maxBytes} bytes`)
|
|
78
|
+
});
|
|
79
|
+
return new TextDecoder().decode(bytes);
|
|
80
|
+
}
|
|
81
|
+
async function readSignalRestErrorText(res, bodyIdleTimeoutMs) {
|
|
82
|
+
return (await readResponseTextPrefix(res, SIGNAL_REST_ERROR_RESPONSE_MAX_BYTES, {
|
|
83
|
+
chunkTimeoutMs: bodyIdleTimeoutMs,
|
|
84
|
+
onIdleTimeout: signalRestIdleTimeoutError
|
|
85
|
+
})).text;
|
|
86
|
+
}
|
|
87
|
+
async function readCappedResponseBuffer(res, maxResponseBytes, bodyIdleTimeoutMs) {
|
|
66
88
|
const contentLength = readContentLength(res);
|
|
67
89
|
if (contentLength !== void 0 && contentLength > maxResponseBytes) throw new Error("Signal REST attachment exceeded size limit");
|
|
68
|
-
return await readResponseWithLimit(res, maxResponseBytes, {
|
|
90
|
+
return await readResponseWithLimit(res, maxResponseBytes, {
|
|
91
|
+
chunkTimeoutMs: bodyIdleTimeoutMs,
|
|
92
|
+
onIdleTimeout: signalAttachmentIdleTimeoutError,
|
|
93
|
+
onOverflow: () => /* @__PURE__ */ new Error("Signal REST attachment exceeded size limit")
|
|
94
|
+
});
|
|
69
95
|
}
|
|
70
96
|
async function releaseUnreadResponseBody(res) {
|
|
71
97
|
if (res?.bodyUsed !== true) await res?.body?.cancel().catch(() => void 0);
|
|
@@ -122,7 +148,7 @@ function containerReceiveCheck(normalizedBaseUrl, account, timeoutMs) {
|
|
|
122
148
|
resolve(result);
|
|
123
149
|
};
|
|
124
150
|
try {
|
|
125
|
-
ws = new WebSocket(wsUrl, { maxPayload:
|
|
151
|
+
ws = new WebSocket(wsUrl, { maxPayload: WS_MAX_PAYLOAD });
|
|
126
152
|
} catch (err) {
|
|
127
153
|
settle({
|
|
128
154
|
ok: false,
|
|
@@ -174,13 +200,15 @@ async function containerRestRequest(endpoint, opts, method = "GET", body) {
|
|
|
174
200
|
headers: { "Content-Type": "application/json" }
|
|
175
201
|
};
|
|
176
202
|
if (body) init.body = JSON.stringify(body);
|
|
177
|
-
const
|
|
203
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS$2;
|
|
204
|
+
const bodyIdleTimeoutMs = resolveTimerTimeoutMs(timeoutMs, DEFAULT_TIMEOUT_MS$2);
|
|
205
|
+
const res = await fetchWithTimeout(url, init, timeoutMs);
|
|
178
206
|
if (res.status === 204) return;
|
|
179
207
|
if (!res.ok) {
|
|
180
|
-
const errorText = await
|
|
208
|
+
const errorText = await readSignalRestErrorText(res, bodyIdleTimeoutMs).catch(() => "");
|
|
181
209
|
throw new Error(`Signal REST ${res.status}: ${errorText || res.statusText}`);
|
|
182
210
|
}
|
|
183
|
-
const text = await
|
|
211
|
+
const text = await readSignalRestText(res, bodyIdleTimeoutMs);
|
|
184
212
|
if (!text) return;
|
|
185
213
|
try {
|
|
186
214
|
return JSON.parse(text);
|
|
@@ -195,9 +223,11 @@ async function containerFetchAttachment(attachmentId, opts) {
|
|
|
195
223
|
const url = `${normalizeBaseUrl$1(opts.baseUrl)}/v1/attachments/${encodeURIComponent(attachmentId)}`;
|
|
196
224
|
let res;
|
|
197
225
|
try {
|
|
198
|
-
|
|
226
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS$2;
|
|
227
|
+
const bodyIdleTimeoutMs = resolveTimerTimeoutMs(timeoutMs, DEFAULT_TIMEOUT_MS$2);
|
|
228
|
+
res = await fetchWithTimeout(url, { method: "GET" }, timeoutMs);
|
|
199
229
|
if (!res.ok) return null;
|
|
200
|
-
return await readCappedResponseBuffer(res, normalizeMaxResponseBytes(opts.maxResponseBytes));
|
|
230
|
+
return await readCappedResponseBuffer(res, normalizeMaxResponseBytes(opts.maxResponseBytes), bodyIdleTimeoutMs);
|
|
201
231
|
} finally {
|
|
202
232
|
await releaseUnreadResponseBody(res);
|
|
203
233
|
}
|
|
@@ -227,7 +257,10 @@ async function streamContainerEvents(params) {
|
|
|
227
257
|
}
|
|
228
258
|
};
|
|
229
259
|
try {
|
|
230
|
-
ws = new WebSocket(wsUrl, {
|
|
260
|
+
ws = new WebSocket(wsUrl, {
|
|
261
|
+
maxPayload: WS_MAX_PAYLOAD,
|
|
262
|
+
handshakeTimeout: WS_HANDSHAKE_MS
|
|
263
|
+
});
|
|
231
264
|
} catch (err) {
|
|
232
265
|
logError(`[signal-ws] failed to create WebSocket: ${err instanceof Error ? err.message : String(err)}`);
|
|
233
266
|
reject(toLintErrorObject$1(err, "Non-Error rejection"));
|
|
@@ -317,11 +350,10 @@ function renderContainerStyledText(text, styles) {
|
|
|
317
350
|
...spans.flatMap((span) => [span.start, span.end])
|
|
318
351
|
])].toSorted((a, b) => a - b);
|
|
319
352
|
let rendered = "";
|
|
320
|
-
for (
|
|
321
|
-
const pos = positions[i];
|
|
353
|
+
for (const [index, pos] of positions.entries()) {
|
|
322
354
|
for (const span of spans.filter((candidate) => candidate.end === pos).toSorted((a, b) => b.start - a.start)) rendered += span.marker;
|
|
323
355
|
for (const span of spans.filter((candidate) => candidate.start === pos).toSorted((a, b) => b.end - a.end)) rendered += span.marker;
|
|
324
|
-
const next = positions[
|
|
356
|
+
const next = positions[index + 1];
|
|
325
357
|
if (next !== void 0 && next > pos) rendered += escapeContainerStyledText(text.slice(pos, next));
|
|
326
358
|
}
|
|
327
359
|
return rendered;
|
|
@@ -453,13 +485,14 @@ async function containerRpcRequest(method, params, opts) {
|
|
|
453
485
|
const groupId = p.groupId;
|
|
454
486
|
const formattedGroupId = groupId ? formatGroupIdForContainer(groupId) : void 0;
|
|
455
487
|
const finalRecipients = recipients.length > 0 ? recipients : usernames.length > 0 ? usernames : formattedGroupId ? [formattedGroupId] : [];
|
|
456
|
-
const textStyles = p["text-style"]?.
|
|
488
|
+
const textStyles = p["text-style"]?.flatMap((s) => {
|
|
457
489
|
const [start, length, style] = s.split(":");
|
|
458
|
-
return
|
|
490
|
+
if (start === void 0 || length === void 0 || style === void 0) return [];
|
|
491
|
+
return [{
|
|
459
492
|
start: Number(start),
|
|
460
493
|
length: Number(length),
|
|
461
494
|
style
|
|
462
|
-
};
|
|
495
|
+
}];
|
|
463
496
|
});
|
|
464
497
|
const quoteTimestamp = normalizeContainerQuoteTimestamp(p.quoteTimestamp ?? p["quote-timestamp"]);
|
|
465
498
|
const quoteAuthor = normalizeContainerQuoteText(p.quoteAuthor ?? p["quote-author"]);
|
|
@@ -789,6 +822,7 @@ async function streamSignalEvents$1(params) {
|
|
|
789
822
|
}
|
|
790
823
|
if (line.startsWith(":")) return;
|
|
791
824
|
const [rawField, ...rest] = line.split(":");
|
|
825
|
+
if (rawField === void 0) return;
|
|
792
826
|
const field = rawField.trim();
|
|
793
827
|
const rawValue = rest.join(":");
|
|
794
828
|
const value = rawValue.startsWith(" ") ? rawValue.slice(1) : rawValue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { n as buildChannelConfigSchema, t as SignalConfigSchema } from "./config-api-
|
|
1
|
+
import { n as buildChannelConfigSchema, t as SignalConfigSchema } from "./config-api-DIg1lInT.js";
|
|
2
|
+
import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
|
|
2
3
|
//#endregion
|
|
3
4
|
//#region extensions/signal/src/config-schema.ts
|
|
4
5
|
const SignalChannelConfigSchema = buildChannelConfigSchema(SignalConfigSchema, { uiHints: {
|
|
@@ -6,14 +7,11 @@ const SignalChannelConfigSchema = buildChannelConfigSchema(SignalConfigSchema, {
|
|
|
6
7
|
label: "Signal",
|
|
7
8
|
help: "Signal channel provider configuration including account identity and DM policy behavior. Keep account mapping explicit so routing remains stable across multi-device setups."
|
|
8
9
|
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
label: "Signal Config Writes",
|
|
15
|
-
help: "Allow Signal to write config in response to channel events/commands (default: true)."
|
|
16
|
-
},
|
|
10
|
+
...createChannelConfigUiHints({
|
|
11
|
+
channelLabel: "Signal",
|
|
12
|
+
dmPolicy: { channelKey: "signal" },
|
|
13
|
+
configWrites: true
|
|
14
|
+
}),
|
|
17
15
|
account: {
|
|
18
16
|
label: "Signal Account",
|
|
19
17
|
help: "Signal account identifier (phone/number handle) used to bind this channel config to a specific Signal identity. Keep this aligned with your linked device/session state."
|
package/dist/contract-api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-
|
|
2
|
-
import { a as
|
|
3
|
-
export { downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeArchive, looksLikeSignalTargetId, normalizeSignalMessagingTarget, pickAsset };
|
|
1
|
+
import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-BF8taj7g.js";
|
|
2
|
+
import { a as installSignalCliFromRelease, i as installSignalCli, n as downloadToFile, o as looksLikeArchive, r as extractSignalCliArchive, s as pickAsset, t as MAX_SIGNAL_CLI_EXTRACTED_BYTES } from "./install-signal-cli-CtusY3tN.js";
|
|
3
|
+
export { MAX_SIGNAL_CLI_EXTRACTED_BYTES, downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeArchive, looksLikeSignalTargetId, normalizeSignalMessagingTarget, pickAsset };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
|
|
2
|
+
//#region extensions/signal/doctor-contract-api.ts
|
|
3
|
+
const streamingAliasMigration = defineChannelAliasMigration({
|
|
4
|
+
channelId: "signal",
|
|
5
|
+
streaming: {
|
|
6
|
+
defaultMode: "partial",
|
|
7
|
+
deliveryOnly: true
|
|
8
|
+
},
|
|
9
|
+
accountStreamingReplacesRoot: true
|
|
10
|
+
});
|
|
11
|
+
const legacyConfigRules = streamingAliasMigration.legacyConfigRules;
|
|
12
|
+
function normalizeCompatibilityConfig({ cfg }) {
|
|
13
|
+
return streamingAliasMigration.normalizeChannelConfig({ cfg });
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { legacyConfigRules, normalizeCompatibilityConfig };
|
|
@@ -61,15 +61,16 @@ function stripSignalPrefix(value) {
|
|
|
61
61
|
}
|
|
62
62
|
function resolveSignalSender(params) {
|
|
63
63
|
const sourceNumber = params.sourceNumber?.trim();
|
|
64
|
+
const sourceUuid = params.sourceUuid?.trim();
|
|
64
65
|
if (sourceNumber) {
|
|
65
66
|
const e164 = normalizeE164(sourceNumber);
|
|
66
67
|
if (e164) return {
|
|
67
68
|
kind: "phone",
|
|
68
69
|
raw: sourceNumber,
|
|
69
|
-
e164
|
|
70
|
+
e164,
|
|
71
|
+
...sourceUuid ? { aliases: { uuid: sourceUuid } } : {}
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
|
-
const sourceUuid = params.sourceUuid?.trim();
|
|
73
74
|
if (sourceUuid) return {
|
|
74
75
|
kind: "uuid",
|
|
75
76
|
raw: sourceUuid
|
|
@@ -124,9 +125,11 @@ function isSignalSenderAllowed(sender, allowFrom) {
|
|
|
124
125
|
if (allowFrom.length === 0) return false;
|
|
125
126
|
const parsed = allowFrom.map(parseSignalAllowEntry).filter((entry) => entry !== null);
|
|
126
127
|
if (parsed.some((entry) => entry.kind === "any")) return true;
|
|
128
|
+
const senderE164 = sender.kind === "phone" ? sender.e164 : sender.aliases?.e164;
|
|
129
|
+
const senderUuid = sender.kind === "uuid" ? sender.raw : sender.aliases?.uuid;
|
|
127
130
|
return parsed.some((entry) => {
|
|
128
|
-
if (entry.kind === "phone"
|
|
129
|
-
if (entry.kind === "uuid"
|
|
131
|
+
if (entry.kind === "phone") return senderE164 !== void 0 && entry.e164 === senderE164;
|
|
132
|
+
if (entry.kind === "uuid") return senderUuid !== void 0 && entry.raw === senderUuid;
|
|
130
133
|
return false;
|
|
131
134
|
});
|
|
132
135
|
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
3
3
|
import nodePath from "node:path";
|
|
4
|
-
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
5
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
6
5
|
import { CONFIG_DIR, extractArchive, resolveBrewExecutable } from "openclaw/plugin-sdk/setup-tools";
|
|
7
6
|
import { createWriteStream } from "node:fs";
|
|
8
7
|
import fs from "node:fs/promises";
|
|
9
8
|
import { Readable, Transform } from "node:stream";
|
|
10
9
|
import { pipeline } from "node:stream/promises";
|
|
10
|
+
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
11
11
|
import { runPluginCommandWithTimeout } from "openclaw/plugin-sdk/run-command";
|
|
12
12
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { withTempDownloadPath } from "openclaw/plugin-sdk/temp-path";
|
|
14
14
|
//#region extensions/signal/src/install-signal-cli.ts
|
|
15
15
|
const MAX_SIGNAL_CLI_ARCHIVE_BYTES = 256 * 1024 * 1024;
|
|
16
|
+
/** @internal Exported for testing. */
|
|
17
|
+
const MAX_SIGNAL_CLI_EXTRACTED_BYTES = 384 * 1024 * 1024;
|
|
16
18
|
const SIGNAL_CLI_DOWNLOAD_TIMEOUT_MS = 5 * 6e4;
|
|
17
19
|
const SIGNAL_CLI_RELEASE_INFO_TIMEOUT_MS = 3e4;
|
|
18
20
|
const CONTENT_LENGTH_RE = /^\d+$/;
|
|
@@ -21,7 +23,13 @@ async function extractSignalCliArchive(archivePath, installRoot, timeoutMs) {
|
|
|
21
23
|
await extractArchive({
|
|
22
24
|
archivePath,
|
|
23
25
|
destDir: installRoot,
|
|
24
|
-
timeoutMs
|
|
26
|
+
timeoutMs,
|
|
27
|
+
limits: {
|
|
28
|
+
maxArchiveBytes: MAX_SIGNAL_CLI_ARCHIVE_BYTES,
|
|
29
|
+
maxEntries: 32,
|
|
30
|
+
maxEntryBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES,
|
|
31
|
+
maxExtractedBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES
|
|
32
|
+
}
|
|
25
33
|
});
|
|
26
34
|
}
|
|
27
35
|
/** @internal Exported for testing. */
|
|
@@ -202,36 +210,39 @@ async function installSignalCliFromRelease(runtime) {
|
|
|
202
210
|
ok: false,
|
|
203
211
|
error: "No compatible release asset found for this platform."
|
|
204
212
|
};
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
};
|
|
215
|
-
try {
|
|
216
|
-
await extractSignalCliArchive(archivePath, installRoot, 6e4);
|
|
217
|
-
} catch (err) {
|
|
218
|
-
const message = formatErrorMessage(err);
|
|
219
|
-
return {
|
|
213
|
+
return await withTempDownloadPath({
|
|
214
|
+
prefix: "openclaw-signal",
|
|
215
|
+
fileName: asset.name
|
|
216
|
+
}, async (archivePath) => {
|
|
217
|
+
runtime.log(`Downloading signal-cli ${version} (${asset.name})…`);
|
|
218
|
+
await downloadToFile(asset.browser_download_url, archivePath);
|
|
219
|
+
const installRoot = nodePath.join(CONFIG_DIR, "tools", "signal-cli", version);
|
|
220
|
+
await fs.mkdir(installRoot, { recursive: true });
|
|
221
|
+
if (!looksLikeArchive(normalizeLowercaseStringOrEmpty(asset.name))) return {
|
|
220
222
|
ok: false,
|
|
221
|
-
error: `
|
|
223
|
+
error: `Unsupported archive type: ${asset.name}`
|
|
222
224
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
cliPath
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
try {
|
|
226
|
+
await extractSignalCliArchive(archivePath, installRoot, 6e4);
|
|
227
|
+
} catch (err) {
|
|
228
|
+
const message = formatErrorMessage(err);
|
|
229
|
+
return {
|
|
230
|
+
ok: false,
|
|
231
|
+
error: `Failed to extract ${asset.name}: ${message}`
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const cliPath = await findSignalCliBinary(installRoot);
|
|
235
|
+
if (!cliPath) return {
|
|
236
|
+
ok: false,
|
|
237
|
+
error: `signal-cli binary not found after extracting ${asset.name}`
|
|
238
|
+
};
|
|
239
|
+
await fs.chmod(cliPath, 493).catch(() => {});
|
|
240
|
+
return {
|
|
241
|
+
ok: true,
|
|
242
|
+
cliPath,
|
|
243
|
+
version
|
|
244
|
+
};
|
|
245
|
+
});
|
|
235
246
|
}
|
|
236
247
|
async function installSignalCli(runtime) {
|
|
237
248
|
if (process.platform === "win32") return {
|
|
@@ -242,4 +253,4 @@ async function installSignalCli(runtime) {
|
|
|
242
253
|
return installSignalCliViaBrew(runtime);
|
|
243
254
|
}
|
|
244
255
|
//#endregion
|
|
245
|
-
export {
|
|
256
|
+
export { installSignalCliFromRelease as a, installSignalCli as i, downloadToFile as n, looksLikeArchive as o, extractSignalCliArchive as r, pickAsset as s, MAX_SIGNAL_CLI_EXTRACTED_BYTES as t };
|