@openclaw/signal 2026.7.2-beta.5 → 2026.8.1-beta.2

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 (29) hide show
  1. package/dist/api.js +7 -7
  2. package/dist/{approval-handler.runtime-C-XYgcxE.js → approval-handler.runtime-Bi5yNhnj.js} +2 -2
  3. package/dist/{approval-reactions-DtL47gSK.js → approval-reactions-BulCzhdB.js} +15 -45
  4. package/dist/{channel-CBIljGCH.js → channel-CzDJMDtX.js} +50 -91
  5. package/dist/channel-config-api.js +1 -1
  6. package/dist/channel-plugin-api.js +1 -1
  7. package/dist/{channel.runtime-B8GXmuol.js → channel.runtime-D12iYzJB.js} +2 -2
  8. package/dist/{client-BazXTH7O.js → client-CvnR8_XA.js} +31 -34
  9. package/dist/{client-adapter-mXGeEHQJ.js → client-adapter-D9SNPaNx.js} +13 -6
  10. package/dist/{config-schema-DLvpQPN5.js → config-schema-CkMIK7zp.js} +4 -7
  11. package/dist/contract-api.js +1 -1
  12. package/dist/{doctor-contract-api-DbUCknbC.js → doctor-contract-api-Dnp5eQQJ.js} +46 -54
  13. package/dist/doctor-contract-api.js +1 -1
  14. package/dist/{install-signal-cli-qJF7iC4h.js → install-signal-cli-Cpiyk0k1.js} +8 -5
  15. package/dist/{monitor-CHBkf7lk.js → monitor-DiN2hKnG.js} +177 -126
  16. package/dist/{probe-Br9abaGp.js → probe-C_THuQzn.js} +23 -7
  17. package/dist/question-reactions-ByjH5qST.js +80 -0
  18. package/dist/{reaction-runtime-api-BjeDyKcz.js → reaction-runtime-api-Cf6QHcE5.js} +8 -19
  19. package/dist/reaction-runtime-api.js +1 -1
  20. package/dist/runtime-api.js +7 -7
  21. package/dist/{send-B_Ks4MZr.js → send-BvGgByMd.js} +12 -3
  22. package/dist/{send.runtime-CbuXycZT.js → send.runtime-CtTBBrjL.js} +1 -1
  23. package/dist/{transport-detection-Da06-LOL.js → transport-detection-BItHawMq.js} +50 -145
  24. package/dist/{transport-detection.runtime-D_190UUL.js → transport-detection.runtime-DoiwPcrG.js} +1 -1
  25. package/dist/{transport-probes.runtime-CV6Qs0Og.js → transport-probes.runtime-BsJdp0oI.js} +1 -1
  26. package/openclaw.plugin.json +4 -1
  27. package/package.json +5 -5
  28. package/dist/approval-resolver-B3m0D2R0.js +0 -16
  29. package/dist/question-reactions-Ds48FtEu.js +0 -109
@@ -1,9 +1,14 @@
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";
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-CvnR8_XA.js";
2
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
2
3
  //#region extensions/signal/src/client-adapter.ts
4
+ /**
5
+ * Signal client adapter - unified interface for both native signal-cli and bbernhard container.
6
+ *
7
+ * This adapter provides a single API that routes to the concrete account transport.
8
+ * Exports mirror client.ts names so consumers
9
+ * only need to change their import path.
10
+ */
3
11
  const DEFAULT_TIMEOUT_MS = 1e4;
4
- function formatErrorMessage(error) {
5
- return error instanceof Error ? error.message : String(error);
6
- }
7
12
  function usesContainer(kind) {
8
13
  return kind === "container";
9
14
  }
@@ -19,7 +24,7 @@ async function signalRpcRequest(method, params, opts) {
19
24
  */
20
25
  async function signalCheck(baseUrl, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
21
26
  try {
22
- return usesContainer(options.transportKind) ? await containerCheck(baseUrl, timeoutMs) : await signalCheck$1(baseUrl, timeoutMs);
27
+ return usesContainer(options.transportKind) ? await containerCheck(baseUrl, timeoutMs, options.account) : await signalCheck$1(baseUrl, timeoutMs);
23
28
  } catch (error) {
24
29
  return {
25
30
  ok: false,
@@ -42,6 +47,7 @@ async function streamSignalEvents(params) {
42
47
  event: "receive",
43
48
  data: JSON.stringify(event)
44
49
  }),
50
+ onStreamOpen: params.onStreamOpen,
45
51
  logger: params.logger
46
52
  });
47
53
  return streamSignalEvents$1({
@@ -49,7 +55,8 @@ async function streamSignalEvents(params) {
49
55
  account: params.account,
50
56
  abortSignal: params.abortSignal,
51
57
  timeoutMs: params.timeoutMs,
52
- onEvent: (event) => params.onEvent(event)
58
+ onEvent: (event) => params.onEvent(event),
59
+ onStreamOpen: params.onStreamOpen
53
60
  });
54
61
  }
55
62
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
2
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId, resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
4
4
  import { ChannelDeliveryStreamingConfigSchema, ChannelSendReadReceiptsSchema, ExecutableTokenSchema, ReplyToModeSchema, buildChannelConfigSchema, buildChannelReactionShape, buildCommonChannelAccountShape, buildGroupEntrySchema, requireAllowlistAllowFrom, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
5
5
  import { z } from "zod";
@@ -60,15 +60,12 @@ const SIGNAL_RETIRED_TRANSPORT_KEYS = [
60
60
  "ignoreStories"
61
61
  ];
62
62
  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
63
  function projectSignalConfigForUpdateValidation(value) {
67
- if (process.env.OPENCLAW_UPDATE_IN_PROGRESS !== "1" || !isRecord$1(value)) return value;
64
+ if (process.env.OPENCLAW_UPDATE_IN_PROGRESS !== "1" || !isRecord(value)) return value;
68
65
  const next = { ...value };
69
66
  for (const key of SIGNAL_RETIRED_TRANSPORT_KEYS) delete next[key];
70
- if (isRecord$1(value.accounts)) next.accounts = Object.fromEntries(Object.entries(value.accounts).map(([accountId, account]) => {
71
- if (!isRecord$1(account)) return [accountId, account];
67
+ if (isRecord(value.accounts)) next.accounts = Object.fromEntries(Object.entries(value.accounts).map(([accountId, account]) => {
68
+ if (!isRecord(account)) return [accountId, account];
72
69
  const nextAccount = { ...account };
73
70
  for (const key of SIGNAL_RETIRED_TRANSPORT_KEYS) delete nextAccount[key];
74
71
  return [accountId, nextAccount];
@@ -1,3 +1,3 @@
1
1
  import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-BQ4OzXXk.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-qJF7iC4h.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-Cpiyk0k1.js";
3
3
  export { MAX_SIGNAL_CLI_EXTRACTED_BYTES, downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeArchive, looksLikeSignalTargetId, normalizeSignalMessagingTarget, pickAsset };
@@ -1,6 +1,7 @@
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
+ import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
3
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
3
- import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
4
+ import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor-migrations";
4
5
  //#region extensions/signal/src/config-compat.ts
5
6
  const LEGACY_TRANSPORT_FIELDS = [
6
7
  "configPath",
@@ -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;
@@ -42,16 +40,13 @@ function isSignalTransportConfig(value) {
42
40
  return false;
43
41
  }
44
42
  }
45
- function optionalString(value) {
46
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
47
- }
48
43
  function inherited(entry, parent, key) {
49
44
  return Object.hasOwn(entry, key) ? entry[key] : parent[key];
50
45
  }
51
46
  function legacyBaseUrl(entry, parent) {
52
- const url = optionalString(inherited(entry, parent, "httpUrl"));
47
+ const url = normalizeOptionalString(inherited(entry, parent, "httpUrl"));
53
48
  if (url) return normalizeSignalTransportUrl(url);
54
- const host = optionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1";
49
+ const host = normalizeOptionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1";
55
50
  const rawPort = inherited(entry, parent, "httpPort");
56
51
  return buildSignalTransportHttpUrl(host, typeof rawPort === "number" ? rawPort : 8080);
57
52
  }
@@ -59,11 +54,11 @@ function hasLegacyFields(entry) {
59
54
  return LEGACY_TRANSPORT_FIELDS.some((field) => Object.hasOwn(entry, field));
60
55
  }
61
56
  function wasLegacySignalAccountConfigured(entry, parent) {
62
- return Boolean(optionalString(inherited(entry, parent, "account")) || optionalString(inherited(entry, parent, "configPath")) || optionalString(inherited(entry, parent, "httpUrl")) || optionalString(inherited(entry, parent, "httpHost")) || optionalString(inherited(entry, parent, "cliPath")) || typeof inherited(entry, parent, "httpPort") === "number" || typeof inherited(entry, parent, "autoStart") === "boolean");
57
+ return Boolean(normalizeOptionalString(inherited(entry, parent, "account")) || normalizeOptionalString(inherited(entry, parent, "configPath")) || normalizeOptionalString(inherited(entry, parent, "httpUrl")) || normalizeOptionalString(inherited(entry, parent, "httpHost")) || normalizeOptionalString(inherited(entry, parent, "cliPath")) || typeof inherited(entry, parent, "httpPort") === "number" || typeof inherited(entry, parent, "autoStart") === "boolean");
63
58
  }
64
59
  function hasInvalidLegacyHttpUrl(entries, parent) {
65
60
  return entries.some((entry) => {
66
- const httpUrl = optionalString(inherited(entry, parent, "httpUrl"));
61
+ const httpUrl = normalizeOptionalString(inherited(entry, parent, "httpUrl"));
67
62
  if (!httpUrl) return false;
68
63
  try {
69
64
  normalizeSignalTransportUrl(httpUrl);
@@ -75,10 +70,10 @@ function hasInvalidLegacyHttpUrl(entries, parent) {
75
70
  }
76
71
  function findInvalidLegacyDerivedEndpoint(entries, parent) {
77
72
  for (const entry of entries) {
78
- if (optionalString(inherited(entry, parent, "httpUrl"))) continue;
73
+ if (normalizeOptionalString(inherited(entry, parent, "httpUrl"))) continue;
79
74
  const rawPort = inherited(entry, parent, "httpPort");
80
75
  if (rawPort !== void 0 && !isValidSignalManagedNativePort(rawPort)) return "port";
81
- const host = optionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1";
76
+ const host = normalizeOptionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1";
82
77
  try {
83
78
  buildSignalTransportHttpUrl(host, typeof rawPort === "number" ? rawPort : 8080);
84
79
  } catch {
@@ -91,19 +86,19 @@ function hasInvalidManagedTransportPort(transports) {
91
86
  }
92
87
  function requiresDetection(entry, parent, apiMode) {
93
88
  if (apiMode !== void 0 && apiMode !== "auto") return false;
94
- return Boolean(optionalString(inherited(entry, parent, "httpUrl"))) || !resolveLegacyAutoStart(entry, parent);
89
+ return Boolean(normalizeOptionalString(inherited(entry, parent, "httpUrl"))) || !resolveLegacyAutoStart(entry, parent);
95
90
  }
96
91
  function resolveLegacyAutoStart(entry, parent) {
97
92
  const autoStart = inherited(entry, parent, "autoStart");
98
93
  if (typeof autoStart === "boolean") return autoStart;
99
- return !optionalString(inherited(entry, parent, "httpUrl"));
94
+ return !normalizeOptionalString(inherited(entry, parent, "httpUrl"));
100
95
  }
101
96
  function resolveManagedConnectionUrl(entry, parent) {
102
- const httpUrl = optionalString(inherited(entry, parent, "httpUrl"));
97
+ const httpUrl = normalizeOptionalString(inherited(entry, parent, "httpUrl"));
103
98
  if (!httpUrl) return;
104
99
  const normalizedUrl = normalizeSignalTransportUrl(httpUrl);
105
100
  const endpoint = new URL(normalizedUrl);
106
- const bindHost = (optionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1").replace(/^\[|\]$/g, "").toLowerCase();
101
+ const bindHost = (normalizeOptionalString(inherited(entry, parent, "httpHost")) ?? "127.0.0.1").replace(/^\[|\]$/g, "").toLowerCase();
107
102
  const rawBindPort = inherited(entry, parent, "httpPort");
108
103
  const bindPort = typeof rawBindPort === "number" ? rawBindPort : 8080;
109
104
  const endpointHost = endpoint.hostname.replace(/^\[|\]$/g, "").toLowerCase();
@@ -112,10 +107,10 @@ function resolveManagedConnectionUrl(entry, parent) {
112
107
  }
113
108
  function buildManagedNativeTransport(entry, parent) {
114
109
  const value = (key) => inherited(entry, parent, key);
115
- const configPath = optionalString(value("configPath"));
116
- const cliPath = optionalString(value("cliPath"));
110
+ const configPath = normalizeOptionalString(value("configPath"));
111
+ const cliPath = normalizeOptionalString(value("cliPath"));
117
112
  const url = resolveManagedConnectionUrl(entry, parent);
118
- const httpHost = optionalString(value("httpHost"));
113
+ const httpHost = normalizeOptionalString(value("httpHost"));
119
114
  const httpPort = value("httpPort");
120
115
  const startupTimeoutMs = value("startupTimeoutMs");
121
116
  const receiveMode = value("receiveMode");
@@ -154,7 +149,7 @@ function resolveLegacyTransportWithoutDetection(params) {
154
149
  async function resolveLegacyTransport(params) {
155
150
  const resolved = resolveLegacyTransportWithoutDetection(params);
156
151
  if (resolved) return resolved;
157
- const account = optionalString(inherited(params.entry, params.parent, "account"));
152
+ const account = normalizeOptionalString(inherited(params.entry, params.parent, "account"));
158
153
  try {
159
154
  const detected = await params.detect?.({
160
155
  url: legacyBaseUrl(params.entry, params.parent),
@@ -172,11 +167,11 @@ function clearLegacyTransportFields(entry) {
172
167
  }
173
168
  function hasRootSignalAccount(entries) {
174
169
  const root = entries[0];
175
- return entries.length === 1 || Boolean(optionalString(root?.account)) || isSignalTransportConfig(root?.transport);
170
+ return entries.length === 1 || Boolean(normalizeOptionalString(root?.account)) || isSignalTransportConfig(root?.transport);
176
171
  }
177
172
  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);
173
+ const accounts = isRecord(entries[0]?.accounts) ? entries[0].accounts : {};
174
+ return Object.entries(accounts).filter(([, entry]) => isRecord(entry)).map(([accountId]) => accountId);
180
175
  }
181
176
  function isDefaultSignalAccountId(accountId) {
182
177
  return Boolean(accountId?.trim()) && normalizeAccountId(accountId) === DEFAULT_ACCOUNT_ID;
@@ -186,10 +181,10 @@ function resolveSignalAccountKey(accounts, accountId) {
186
181
  return Object.keys(accounts).find((key) => Boolean(key.trim()) && normalizeAccountId(key) === normalizedAccountId);
187
182
  }
188
183
  function nestedDefaultOwnsEffectiveTransport(entries) {
189
- const accounts = isRecord$1(entries[0]?.accounts) ? entries[0].accounts : {};
184
+ const accounts = isRecord(entries[0]?.accounts) ? entries[0].accounts : {};
190
185
  const nestedDefaultKey = resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID);
191
186
  const nestedDefault = nestedDefaultKey ? accounts[nestedDefaultKey] : void 0;
192
- return isRecord$1(nestedDefault) && (isSignalTransportConfig(nestedDefault.transport) || hasLegacyFields(nestedDefault));
187
+ return isRecord(nestedDefault) && (isSignalTransportConfig(nestedDefault.transport) || hasLegacyFields(nestedDefault));
193
188
  }
194
189
  function isDiscardedTransportEntry(entries, index) {
195
190
  if (index === 0) return !hasRootSignalAccount(entries) || nestedDefaultOwnsEffectiveTransport(entries);
@@ -204,23 +199,23 @@ function shouldMaterializeTransport(entries, index) {
204
199
  function clearLegacySignalTransportFieldsForAccount(params) {
205
200
  const next = structuredClone(params.cfg);
206
201
  const signal = next.channels?.signal;
207
- if (!isRecord$1(signal)) return next;
202
+ if (!isRecord(signal)) return next;
208
203
  if (isDefaultSignalAccountId(params.accountId)) {
209
204
  clearLegacyTransportFields(signal);
210
205
  delete signal.apiMode;
211
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : void 0;
206
+ const accounts = isRecord(signal.accounts) ? signal.accounts : void 0;
212
207
  const nestedDefaultKey = accounts ? resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID) : void 0;
213
208
  const nestedDefault = nestedDefaultKey ? accounts?.[nestedDefaultKey] : void 0;
214
- if (isRecord$1(nestedDefault)) {
209
+ if (isRecord(nestedDefault)) {
215
210
  clearLegacyTransportFields(nestedDefault);
216
211
  delete nestedDefault.transport;
217
212
  }
218
213
  return next;
219
214
  }
220
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : void 0;
215
+ const accounts = isRecord(signal.accounts) ? signal.accounts : void 0;
221
216
  const accountKey = accounts ? resolveSignalAccountKey(accounts, params.accountId) : void 0;
222
217
  const account = accountKey ? accounts?.[accountKey] : void 0;
223
- if (isRecord$1(account)) clearLegacyTransportFields(account);
218
+ if (isRecord(account)) clearLegacyTransportFields(account);
224
219
  return next;
225
220
  }
226
221
  function allocateMigratedManagedPorts(params) {
@@ -239,12 +234,12 @@ function allocateMigratedManagedPorts(params) {
239
234
  const localConnectionPort = resolveLocalSignalTransportPort(transport.url);
240
235
  if (localConnectionPort !== void 0) reservedPorts.add(localConnectionPort);
241
236
  }
242
- if (index === canonicalDefaultIndex || isRecord$1(params.entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
237
+ if (index === canonicalDefaultIndex || isRecord(params.entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
243
238
  }
244
239
  return params.transports.map((transport, index) => {
245
240
  if (!transport || index === 0 && canonicalDefaultIndex !== 0) return transport;
246
241
  if (transport.kind !== "managed-native") return transport;
247
- if (isRecord$1(params.entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
242
+ if (isRecord(params.entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
248
243
  const rawPreferredPort = params.entries[index]?.httpPort;
249
244
  const preferredPort = typeof rawPreferredPort === "number" ? rawPreferredPort : transport.httpPort;
250
245
  const httpPort = allocateSignalManagedNativePort({
@@ -258,10 +253,10 @@ function allocateMigratedManagedPorts(params) {
258
253
  function applyMigratedSignalTransports(params) {
259
254
  const next = structuredClone(params.cfg);
260
255
  const nextSignal = next.channels?.signal;
261
- if (!isRecord$1(nextSignal)) return;
256
+ if (!isRecord(nextSignal)) return;
262
257
  const accountIds = signalAccountIds(params.entries);
263
- const nextAccounts = isRecord$1(nextSignal.accounts) ? nextSignal.accounts : {};
264
- const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord$1)];
258
+ const nextAccounts = isRecord(nextSignal.accounts) ? nextSignal.accounts : {};
259
+ const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord)];
265
260
  const rootIsAccount = hasRootSignalAccount(params.entries);
266
261
  const canonicalRootTransport = isSignalTransportConfig(params.entries[0]?.transport) ? params.entries[0].transport : void 0;
267
262
  for (const [index, entry] of nextEntries.entries()) {
@@ -280,37 +275,37 @@ function applyMigratedSignalTransports(params) {
280
275
  }
281
276
  function hasContainerTransportWithoutEffectiveAccount(cfg) {
282
277
  const signal = cfg.channels?.signal;
283
- if (!isRecord$1(signal)) return false;
284
- const accounts = isRecord$1(signal.accounts) ? signal.accounts : {};
278
+ if (!isRecord(signal)) return false;
279
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
285
280
  const rootTransport = isSignalTransportConfig(signal.transport) ? signal.transport : void 0;
286
281
  const defaultKey = resolveSignalAccountKey(accounts, DEFAULT_ACCOUNT_ID);
287
282
  const defaultEntry = defaultKey ? accounts[defaultKey] : void 0;
288
- const defaultAccount = isRecord$1(defaultEntry) && defaultEntry.account !== void 0 ? optionalString(defaultEntry.account) : optionalString(signal.account);
283
+ const defaultAccount = isRecord(defaultEntry) && defaultEntry.account !== void 0 ? normalizeOptionalString(defaultEntry.account) : normalizeOptionalString(signal.account);
289
284
  const channelEnabled = signal.enabled !== false;
290
- const defaultEnabled = !isRecord$1(defaultEntry) || defaultEntry.enabled !== false;
285
+ const defaultEnabled = !isRecord(defaultEntry) || defaultEntry.enabled !== false;
291
286
  if (rootTransport?.kind === "container" && channelEnabled && defaultEnabled && !defaultAccount) return true;
292
287
  for (const [accountId, entry] of Object.entries(accounts)) {
293
- if (!isRecord$1(entry)) continue;
288
+ if (!isRecord(entry)) continue;
294
289
  if (!channelEnabled || entry.enabled === false) continue;
295
290
  const isDefaultAccount = isDefaultSignalAccountId(accountId);
296
291
  if ((isDefaultAccount && rootTransport ? rootTransport : isSignalTransportConfig(entry.transport) ? entry.transport : void 0)?.kind !== "container" || isDefaultAccount && rootTransport) continue;
297
- if (!(entry.account === void 0 ? optionalString(signal.account) : optionalString(entry.account))) return true;
292
+ if (!(entry.account === void 0 ? normalizeOptionalString(signal.account) : normalizeOptionalString(entry.account))) return true;
298
293
  }
299
294
  return false;
300
295
  }
301
296
  async function migrateLegacySignalTransportConfig(params) {
302
297
  const signal = params.cfg.channels?.signal;
303
- if (!isRecord$1(signal)) return {
298
+ if (!isRecord(signal)) return {
304
299
  config: params.cfg,
305
300
  changes: []
306
301
  };
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 {
302
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
303
+ if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord(entry) && hasLegacyFields(entry)))) return {
309
304
  config: params.cfg,
310
305
  changes: []
311
306
  };
312
307
  const apiMode = signal.apiMode;
313
- const entries = [signal, ...Object.values(accounts).filter(isRecord$1)];
308
+ const entries = [signal, ...Object.values(accounts).filter(isRecord)];
314
309
  const legacyResolutionEntries = entries.filter((_, index) => shouldMaterializeTransport(entries, index)).filter((entry) => !isSignalTransportConfig(entry.transport));
315
310
  const invalidDerivedEndpoint = findInvalidLegacyDerivedEndpoint(legacyResolutionEntries, signal);
316
311
  if (invalidDerivedEndpoint) return {
@@ -369,16 +364,16 @@ async function migrateLegacySignalTransportConfig(params) {
369
364
  }
370
365
  function migrateLegacySignalTransportConfigSync(cfg) {
371
366
  const signal = cfg.channels?.signal;
372
- if (!isRecord$1(signal)) return {
367
+ if (!isRecord(signal)) return {
373
368
  config: cfg,
374
369
  changes: []
375
370
  };
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 {
371
+ const accounts = isRecord(signal.accounts) ? signal.accounts : {};
372
+ if (!(Object.hasOwn(signal, "apiMode") || hasLegacyFields(signal) || Object.values(accounts).some((entry) => isRecord(entry) && hasLegacyFields(entry)))) return {
378
373
  config: cfg,
379
374
  changes: []
380
375
  };
381
- const entries = [signal, ...Object.values(accounts).filter(isRecord$1)];
376
+ const entries = [signal, ...Object.values(accounts).filter(isRecord)];
382
377
  const legacyResolutionEntries = entries.filter((_, index) => shouldMaterializeTransport(entries, index)).filter((entry) => !isSignalTransportConfig(entry.transport));
383
378
  const invalidDerivedEndpoint = findInvalidLegacyDerivedEndpoint(legacyResolutionEntries, signal);
384
379
  if (invalidDerivedEndpoint) return {
@@ -445,9 +440,6 @@ const RETIRED_SIGNAL_ACCOUNT_TRANSPORT_FIELDS = [
445
440
  "receiveMode",
446
441
  "ignoreStories"
447
442
  ];
448
- function isRecord(value) {
449
- return typeof value === "object" && value !== null && !Array.isArray(value);
450
- }
451
443
  function hasRetiredSignalAccountTransportFields(value) {
452
444
  return isRecord(value) && RETIRED_SIGNAL_ACCOUNT_TRANSPORT_FIELDS.some((field) => Object.hasOwn(value, field));
453
445
  }
@@ -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-Dnp5eQQJ.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,10 +1,10 @@
1
1
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
3
- import nodePath from "node:path";
4
3
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
4
  import { CONFIG_DIR, extractArchive, resolveBrewExecutable } from "openclaw/plugin-sdk/setup-tools";
6
5
  import { createWriteStream } from "node:fs";
7
6
  import fs from "node:fs/promises";
7
+ import path from "node:path";
8
8
  import { Readable, Transform } from "node:stream";
9
9
  import { pipeline } from "node:stream/promises";
10
10
  import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
@@ -107,7 +107,10 @@ async function downloadToFile(url, dest, maxRedirects = 5, maxBytes = MAX_SIGNAL
107
107
  if (rawLength !== null) {
108
108
  const trimmedLength = rawLength.trim();
109
109
  const declaredLength = CONTENT_LENGTH_RE.test(trimmedLength) ? Number(trimmedLength) : NaN;
110
- if (Number.isFinite(declaredLength) && declaredLength > maxBytes) throw new Error(`signal-cli archive exceeds the ${maxBytes}-byte download cap (declared ${declaredLength}).`);
110
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
111
+ await cancelUnusedResponseBody(response);
112
+ throw new Error(`signal-cli archive exceeds the ${maxBytes}-byte download cap (declared ${declaredLength}).`);
113
+ }
111
114
  }
112
115
  let totalBytes = 0;
113
116
  const body = response.body;
@@ -131,7 +134,7 @@ async function findSignalCliBinary(root) {
131
134
  if (depth > 3) return;
132
135
  const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
133
136
  for (const entry of entries) {
134
- const full = nodePath.join(dir, entry.name);
137
+ const full = path.join(dir, entry.name);
135
138
  if (entry.isDirectory()) await enqueue(full, depth + 1);
136
139
  else if (entry.isFile() && entry.name === "signal-cli") candidates.push(full);
137
140
  }
@@ -151,7 +154,7 @@ async function resolveBrewSignalCliPath(brewExe) {
151
154
  });
152
155
  if (result.code === 0 && result.stdout.trim()) {
153
156
  const prefix = result.stdout.trim();
154
- const candidate = nodePath.join(prefix, "bin", "signal-cli");
157
+ const candidate = path.join(prefix, "bin", "signal-cli");
155
158
  try {
156
159
  await fs.access(candidate);
157
160
  return candidate;
@@ -246,7 +249,7 @@ async function installSignalCliFromRelease(runtime) {
246
249
  }, async (archivePath) => {
247
250
  runtime.log(`Downloading signal-cli ${releaseInfo.version} (${asset.name})…`);
248
251
  await downloadToFile(asset.browser_download_url, archivePath);
249
- const installRoot = nodePath.join(CONFIG_DIR, "tools", "signal-cli", releaseInfo.version);
252
+ const installRoot = path.join(CONFIG_DIR, "tools", "signal-cli", releaseInfo.version);
250
253
  await fs.mkdir(installRoot, { recursive: true });
251
254
  if (!looksLikeArchive(normalizeLowercaseStringOrEmpty(asset.name))) return {
252
255
  ok: false,