@openclaw/signal 2026.11.3 → 2026.11.5-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 (179) hide show
  1. package/dist/.setup/{accounts-B0Pba1-q.mjs → accounts-enJKL3ci.mjs} +4 -8
  2. package/dist/.setup/api-CrasQEKI.mjs +14 -0
  3. package/dist/.setup/{api-CbN3mye4.mjs → api-DljZsfUn.mjs} +9 -11
  4. package/dist/.setup/{approval-auth-DhUKkSkA.mjs → approval-auth-B_5Ytx8K.mjs} +7 -11
  5. package/dist/.setup/{approval-handler.runtime-CsEcBZoc.mjs → approval-handler.runtime-0RbVmTxx.mjs} +7 -8
  6. package/dist/.setup/{approval-reactions-JsqCEOHK.mjs → approval-reactions-CvqVSSx8.mjs} +16 -24
  7. package/dist/.setup/{channel-CM-rLLPN.mjs → channel-ByJj8fSh.mjs} +417 -372
  8. package/dist/.setup/{client-Duwqbgqi.mjs → client-CesmEjRc.mjs} +170 -186
  9. package/dist/.setup/{config-schema-DvxZ18SD.mjs → config-schema-BCmW0BLB.mjs} +2 -5
  10. package/dist/.setup/{doctor-contract-api-BIdVW0PF.mjs → doctor-contract-api-CcLwIhsD.mjs} +88 -95
  11. package/dist/.setup/{identity-B3JyPqGO.mjs → identity-vKtR3DrM.mjs} +39 -2
  12. package/dist/.setup/{install-signal-cli-hYVLYGXe.mjs → install-signal-cli-DvLDZfpP.mjs} +95 -109
  13. package/dist/.setup/{transport-url-CAC0JcuI.mjs → legacy-transport-D_cZC3bS.mjs} +18 -1
  14. package/dist/.setup/{monitor-C6u1JV2C.mjs → monitor-Cf5sihwl.mjs} +166 -239
  15. package/dist/.setup/{probe-D_93QCe0.mjs → probe-Caq5Y4kA.mjs} +3 -3
  16. package/dist/.setup/{send-CM7-016e.mjs → send-BJuOWLky.mjs} +34 -66
  17. package/dist/.setup/{setup-surface-DvKLwYrl.mjs → setup-surface-DQ1yFZmY.mjs} +3 -3
  18. package/dist/.setup/{transport-detection-CmlgOybe.mjs → transport-detection-DvR6X_UQ.mjs} +3 -3
  19. package/dist/.setup/{transport-policy-B6C_LogW.mjs → transport-policy-zIR3lRUj.mjs} +1 -1
  20. package/dist/.setup/transport-probes.runtime-CoH6UFtc.mjs +1 -0
  21. package/dist/.source-module-urls/b02c526df8b90083105b63e5b51d5c8bbfe02676df72f6be8dd8f825817b32b9.json +1 -0
  22. package/dist/api.js +9 -11
  23. package/dist/channel-config-api.js +1 -2
  24. package/dist/channel-plugin-api.js +1 -2
  25. package/dist/contract-api.js +3 -4
  26. package/dist/doctor-contract-api.js +1 -2
  27. package/dist/runtime-api.js +1 -2
  28. package/dist/setup-entry.js +1 -1
  29. package/node_modules/@openclaw/fs-safe/CHANGELOG.md +94 -0
  30. package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
  31. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +1 -1
  32. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +3 -1
  33. package/node_modules/@openclaw/fs-safe/dist/copy-path-admission.js +2 -2
  34. package/node_modules/@openclaw/fs-safe/dist/copy-root-file-sync.js +8 -1
  35. package/node_modules/@openclaw/fs-safe/dist/file-open-error.d.ts +2 -0
  36. package/node_modules/@openclaw/fs-safe/dist/file-open-error.js +14 -0
  37. package/node_modules/@openclaw/fs-safe/dist/file-sync.d.ts +2 -1
  38. package/node_modules/@openclaw/fs-safe/dist/file-sync.js +6 -1
  39. package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +3 -0
  40. package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +1 -0
  41. package/node_modules/@openclaw/fs-safe/dist/native-config.js +14 -3
  42. package/node_modules/@openclaw/fs-safe/dist/native-operations.js +2 -0
  43. package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js +9 -2
  44. package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +40 -32
  45. package/node_modules/@openclaw/fs-safe/dist/output.js +6 -0
  46. package/node_modules/@openclaw/fs-safe/dist/owner-dacl.d.ts +2 -0
  47. package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +1 -0
  48. package/node_modules/@openclaw/fs-safe/dist/path.js +5 -1
  49. package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +25 -2
  50. package/node_modules/@openclaw/fs-safe/dist/publication-handle.d.ts +4 -0
  51. package/node_modules/@openclaw/fs-safe/dist/publication-handle.js +32 -0
  52. package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.d.ts +2 -1
  53. package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +19 -9
  54. package/node_modules/@openclaw/fs-safe/dist/publish-file.js +23 -24
  55. package/node_modules/@openclaw/fs-safe/dist/publish-rename-fallback.d.ts +21 -0
  56. package/node_modules/@openclaw/fs-safe/dist/publish-rename-fallback.js +102 -0
  57. package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +2 -0
  58. package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.d.ts +3 -1
  59. package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.js +8 -5
  60. package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +3 -0
  61. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +2 -1
  62. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +19 -9
  63. package/node_modules/@openclaw/fs-safe/dist/root-file-final-admission.js +3 -3
  64. package/node_modules/@openclaw/fs-safe/dist/root-path-existing.d.ts +2 -2
  65. package/node_modules/@openclaw/fs-safe/dist/root-path-existing.js +27 -13
  66. package/node_modules/@openclaw/fs-safe/dist/root-path.js +2 -2
  67. package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.d.ts +3 -0
  68. package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +18 -3
  69. package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +1 -1
  70. package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +68 -21
  71. package/node_modules/@openclaw/fs-safe/dist/watch-io-error.d.ts +2 -0
  72. package/node_modules/@openclaw/fs-safe/dist/watch-io-error.js +27 -0
  73. package/node_modules/@openclaw/fs-safe/dist/watch-io-worker.d.ts +1 -0
  74. package/node_modules/@openclaw/fs-safe/dist/watch-io-worker.js +93 -0
  75. package/node_modules/@openclaw/fs-safe/dist/watch-io.d.ts +47 -0
  76. package/node_modules/@openclaw/fs-safe/dist/watch-io.js +236 -0
  77. package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +1 -1
  78. package/node_modules/@openclaw/fs-safe/dist/watch-native.js +3 -3
  79. package/node_modules/@openclaw/fs-safe/dist/watch-probe.d.ts +16 -0
  80. package/node_modules/@openclaw/fs-safe/dist/watch-probe.js +135 -0
  81. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.d.ts +1 -1
  82. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.js +86 -24
  83. package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +4 -0
  84. package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +78 -16
  85. package/node_modules/@openclaw/fs-safe/dist/watch-stream.d.ts +2 -0
  86. package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +23 -0
  87. package/node_modules/@openclaw/fs-safe/dist/watch-types.d.ts +3 -1
  88. package/node_modules/@openclaw/fs-safe/dist/watch.js +60 -13
  89. package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.d.ts +1 -1
  90. package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.js +1 -0
  91. package/node_modules/@openclaw/fs-safe/dist/windows-security-helper.exe +0 -0
  92. package/node_modules/@openclaw/fs-safe/docs/advanced.md +5 -2
  93. package/node_modules/@openclaw/fs-safe/docs/compiler-qualification.md +392 -0
  94. package/node_modules/@openclaw/fs-safe/docs/config.md +7 -1
  95. package/node_modules/@openclaw/fs-safe/docs/contributing.md +25 -5
  96. package/node_modules/@openclaw/fs-safe/docs/copy.md +10 -0
  97. package/node_modules/@openclaw/fs-safe/docs/durability.md +9 -3
  98. package/node_modules/@openclaw/fs-safe/docs/errors.md +13 -0
  99. package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +6 -4
  100. package/node_modules/@openclaw/fs-safe/docs/native-helper.md +6 -4
  101. package/node_modules/@openclaw/fs-safe/docs/output.md +4 -2
  102. package/node_modules/@openclaw/fs-safe/docs/path.md +5 -2
  103. package/node_modules/@openclaw/fs-safe/docs/permissions.md +15 -0
  104. package/node_modules/@openclaw/fs-safe/docs/security-model.md +9 -0
  105. package/node_modules/@openclaw/fs-safe/docs/staged-file.md +2 -0
  106. package/node_modules/@openclaw/fs-safe/docs/testing.md +1 -1
  107. package/node_modules/@openclaw/fs-safe/docs/watch.md +62 -5
  108. package/node_modules/@openclaw/fs-safe/docs/writing.md +6 -1
  109. package/node_modules/@openclaw/fs-safe/package.json +18 -16
  110. package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
  111. package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
  112. package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
  113. package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
  114. package/node_modules/@openclaw/fs-safe-freebsd-arm64/fs-safe-native.node +0 -0
  115. package/node_modules/@openclaw/fs-safe-freebsd-arm64/package.json +1 -1
  116. package/node_modules/@openclaw/fs-safe-freebsd-x64/fs-safe-native.node +0 -0
  117. package/node_modules/@openclaw/fs-safe-freebsd-x64/package.json +1 -1
  118. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
  119. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
  120. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
  121. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
  122. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
  123. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
  124. package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
  125. package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
  126. package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/fs-safe-native.node +0 -0
  127. package/node_modules/@openclaw/fs-safe-win32-arm64-msvc/package.json +1 -1
  128. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
  129. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
  130. package/node_modules/zod/package.json +1 -1
  131. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  132. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  133. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  134. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  135. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  136. package/node_modules/zod/src/v4/core/util.ts +13 -0
  137. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  138. package/node_modules/zod/v4/core/compile.cjs +8 -0
  139. package/node_modules/zod/v4/core/compile.js +8 -0
  140. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  141. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  142. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  143. package/node_modules/zod/v4/core/schemas.js +30 -0
  144. package/node_modules/zod/v4/core/util.cjs +15 -0
  145. package/node_modules/zod/v4/core/util.d.cts +2 -0
  146. package/node_modules/zod/v4/core/util.d.ts +2 -0
  147. package/node_modules/zod/v4/core/util.js +14 -0
  148. package/node_modules/zod/v4/core/versions.cjs +1 -1
  149. package/node_modules/zod/v4/core/versions.js +1 -1
  150. package/openclaw.plugin.json +0 -30
  151. package/package.json +6 -8
  152. package/dist/.setup/api-CJBtD3lT.mjs +0 -16
  153. package/dist/.setup/client-adapter-Chnbch_z.mjs +0 -30
  154. package/dist/.setup/legacy-transport-QIpaMNST.mjs +0 -18
  155. package/dist/.setup/normalize-D7kSomXt.mjs +0 -39
  156. package/dist/.setup/reaction-runtime-api-mdO4k0yv.mjs +0 -65
  157. package/dist/.setup/reaction-targets-BgPLDHBf.mjs +0 -72
  158. package/dist/.setup/rpc-context-BAXcX7dI.mjs +0 -13
  159. package/dist/.setup/transport-probes.runtime-D-xIMRcn.mjs +0 -2
  160. package/dist/reaction-runtime-api.js +0 -2
  161. package/node_modules/ws/LICENSE +0 -20
  162. package/node_modules/ws/README.md +0 -548
  163. package/node_modules/ws/browser.js +0 -8
  164. package/node_modules/ws/index.js +0 -22
  165. package/node_modules/ws/lib/buffer-util.js +0 -131
  166. package/node_modules/ws/lib/constants.js +0 -19
  167. package/node_modules/ws/lib/event-target.js +0 -292
  168. package/node_modules/ws/lib/extension.js +0 -203
  169. package/node_modules/ws/lib/limiter.js +0 -55
  170. package/node_modules/ws/lib/permessage-deflate.js +0 -530
  171. package/node_modules/ws/lib/receiver.js +0 -743
  172. package/node_modules/ws/lib/sender.js +0 -607
  173. package/node_modules/ws/lib/stream.js +0 -161
  174. package/node_modules/ws/lib/subprotocol.js +0 -62
  175. package/node_modules/ws/lib/validation.js +0 -152
  176. package/node_modules/ws/lib/websocket-server.js +0 -562
  177. package/node_modules/ws/lib/websocket.js +0 -1421
  178. package/node_modules/ws/package.json +0 -74
  179. package/node_modules/ws/wrapper.mjs +0 -21
@@ -1,7 +1,5 @@
1
- import { a as normalizeSignalTransportUrl, r as buildSignalTransportHttpUrl, s as resolveSignalAccountKey, t as assertSignalSocketTransport } from "./transport-url-CAC0JcuI.mjs";
2
- import { a as isSignalManagedNativeConnectionUrlForBind, c as resolveLocalSignalTransportPort, i as assignSignalManagedNativePort, o as isValidSignalManagedNativePort, r as allocateSignalManagedNativePort } from "./transport-policy-B6C_LogW.mjs";
3
- import { n as hasLegacySignalTransportFields, t as LEGACY_SIGNAL_TRANSPORT_FIELDS } from "./legacy-transport-QIpaMNST.mjs";
4
- import "node:module";
1
+ import { a as buildSignalTransportHttpUrl, l as resolveSignalAccountKey, n as hasLegacySignalTransportFields, r as assertSignalSocketTransport, s as normalizeSignalTransportUrl, t as LEGACY_SIGNAL_TRANSPORT_FIELDS } from "./legacy-transport-D_cZC3bS.mjs";
2
+ import { a as isSignalManagedNativeConnectionUrlForBind, c as resolveLocalSignalTransportPort, i as assignSignalManagedNativePort, o as isValidSignalManagedNativePort, r as allocateSignalManagedNativePort } from "./transport-policy-zIR3lRUj.mjs";
5
3
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
4
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
7
5
  //#region \0rolldown/runtime.js
@@ -154,22 +152,6 @@ function resolveLegacyTransportWithoutDetection(params) {
154
152
  };
155
153
  return buildManagedNativeTransport(params.entry, params.parent);
156
154
  }
157
- async function resolveLegacyTransport(params) {
158
- const resolved = resolveLegacyTransportWithoutDetection(params);
159
- if (resolved) return resolved;
160
- const account = normalizeOptionalString(inherited(params.entry, params.parent, "account"));
161
- try {
162
- const detected = await params.detect?.({
163
- url: legacyBaseUrl(params.entry, params.parent),
164
- ...account ? { account } : {}
165
- });
166
- if (detected?.kind === "external-native" && resolveLegacyAutoStart(params.entry, params.parent)) return buildManagedNativeTransport(params.entry, params.parent);
167
- return detected;
168
- } catch {
169
- if (resolveLegacyAutoStart(params.entry, params.parent)) return buildManagedNativeTransport(params.entry, params.parent);
170
- return;
171
- }
172
- }
173
155
  function clearLegacyTransportFields(entry) {
174
156
  for (const field of LEGACY_SIGNAL_TRANSPORT_FIELDS) delete entry[field];
175
157
  }
@@ -228,62 +210,6 @@ function clearLegacySignalTransportFieldsForAccount(params) {
228
210
  if (isRecord(account)) clearLegacyTransportFields(account);
229
211
  return next;
230
212
  }
231
- function allocateMigratedManagedPorts(params) {
232
- const reservedPorts = /* @__PURE__ */ new Set();
233
- const rootIsAccount = hasRootSignalAccount(params.entries);
234
- const nestedDefaultIndex = resolveNestedDefaultEntryIndex(params.entries);
235
- const canonicalDefaultIndex = isSignalTransportConfig(params.entries[0]?.transport) ? 0 : nestedDefaultIndex !== void 0 ? nestedDefaultIndex : rootIsAccount ? 0 : void 0;
236
- for (const [index, transport] of params.transports.entries()) {
237
- if (!transport || index === 0 && canonicalDefaultIndex !== 0) continue;
238
- if (transport.kind === "managed-native" && transport.socketPath !== void 0) continue;
239
- if (transport.kind !== "managed-native") {
240
- const localPort = resolveLocalSignalTransportPort(transport.url);
241
- if (localPort !== void 0) reservedPorts.add(localPort);
242
- continue;
243
- }
244
- if (transport.url && !isSignalManagedNativeConnectionUrlForBind(transport)) {
245
- const localConnectionPort = resolveLocalSignalTransportPort(transport.url);
246
- if (localConnectionPort !== void 0) reservedPorts.add(localConnectionPort);
247
- }
248
- if (index === canonicalDefaultIndex || isRecord(params.entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
249
- }
250
- return params.transports.map((transport, index) => {
251
- if (!transport || index === 0 && canonicalDefaultIndex !== 0) return transport;
252
- if (transport.kind !== "managed-native" || transport.socketPath !== void 0) return transport;
253
- if (isRecord(params.entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
254
- const rawPreferredPort = params.entries[index]?.httpPort;
255
- const preferredPort = typeof rawPreferredPort === "number" ? rawPreferredPort : transport.httpPort;
256
- const httpPort = allocateSignalManagedNativePort({
257
- reservedPorts,
258
- ...typeof preferredPort === "number" ? { preferredPort } : {}
259
- });
260
- reservedPorts.add(httpPort);
261
- return assignSignalManagedNativePort(transport, httpPort);
262
- });
263
- }
264
- function applyMigratedSignalTransports(params) {
265
- const next = structuredClone(params.cfg);
266
- const nextSignal = next.channels?.signal;
267
- if (!isRecord(nextSignal)) return;
268
- const nestedDefaultIndex = resolveNestedDefaultEntryIndex(params.entries);
269
- const nextAccounts = isRecord(nextSignal.accounts) ? nextSignal.accounts : {};
270
- const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord)];
271
- const rootIsAccount = hasRootSignalAccount(params.entries);
272
- const canonicalRootTransport = isSignalTransportConfig(params.entries[0]?.transport) ? params.entries[0].transport : void 0;
273
- for (const [index, entry] of nextEntries.entries()) {
274
- if (index === nestedDefaultIndex) {
275
- const defaultTransport = canonicalRootTransport ?? params.transports[index];
276
- if (defaultTransport) nextSignal.transport = defaultTransport;
277
- else delete nextSignal.transport;
278
- delete entry.transport;
279
- } else if (index === 0 && !rootIsAccount) delete entry.transport;
280
- else if (params.transports[index]) entry.transport = params.transports[index];
281
- else delete entry.transport;
282
- clearLegacyTransportFields(entry);
283
- }
284
- delete nextSignal.apiMode;
285
- return next;
286
- }
287
213
  function hasContainerTransportWithoutEffectiveAccount(cfg) {
288
214
  const signal = cfg.channels?.signal;
289
215
  if (!isRecord(signal)) return false;
@@ -338,20 +264,64 @@ function prepareLegacySignalTransportMigration(cfg) {
338
264
  }
339
265
  function finishLegacySignalTransportMigration(cfg, entries, resolvedTransports) {
340
266
  if (hasInvalidManagedTransportPort(resolvedTransports)) return pendingSignalTransportMigration(cfg, PENDING_LEGACY_INVALID_PORT_WARNING);
341
- const transports = allocateMigratedManagedPorts({
342
- entries,
343
- transports: resolvedTransports
344
- });
267
+ function allocateMigratedManagedPorts() {
268
+ const reservedPorts = /* @__PURE__ */ new Set();
269
+ const rootIsAccount = hasRootSignalAccount(entries);
270
+ const nestedDefaultIndex = resolveNestedDefaultEntryIndex(entries);
271
+ const canonicalDefaultIndex = isSignalTransportConfig(entries[0]?.transport) ? 0 : nestedDefaultIndex !== void 0 ? nestedDefaultIndex : rootIsAccount ? 0 : void 0;
272
+ for (const [index, transport] of resolvedTransports.entries()) {
273
+ if (!transport || index === 0 && canonicalDefaultIndex !== 0) continue;
274
+ if (transport.kind === "managed-native" && transport.socketPath !== void 0) continue;
275
+ if (transport.kind !== "managed-native") {
276
+ const localPort = resolveLocalSignalTransportPort(transport.url);
277
+ if (localPort !== void 0) reservedPorts.add(localPort);
278
+ continue;
279
+ }
280
+ if (transport.url && !isSignalManagedNativeConnectionUrlForBind(transport)) {
281
+ const localConnectionPort = resolveLocalSignalTransportPort(transport.url);
282
+ if (localConnectionPort !== void 0) reservedPorts.add(localConnectionPort);
283
+ }
284
+ if (index === canonicalDefaultIndex || isRecord(entries[index]?.transport)) reservedPorts.add(transport.httpPort ?? 8080);
285
+ }
286
+ return resolvedTransports.map((transport, index) => {
287
+ if (!transport || index === 0 && canonicalDefaultIndex !== 0) return transport;
288
+ if (transport.kind !== "managed-native" || transport.socketPath !== void 0) return transport;
289
+ if (isRecord(entries[index]?.transport) || index === canonicalDefaultIndex) return transport;
290
+ const rawPreferredPort = entries[index]?.httpPort;
291
+ const preferredPort = typeof rawPreferredPort === "number" ? rawPreferredPort : transport.httpPort;
292
+ const httpPort = allocateSignalManagedNativePort({
293
+ reservedPorts,
294
+ ...typeof preferredPort === "number" ? { preferredPort } : {}
295
+ });
296
+ reservedPorts.add(httpPort);
297
+ return assignSignalManagedNativePort(transport, httpPort);
298
+ });
299
+ }
300
+ const transports = allocateMigratedManagedPorts();
345
301
  if (transports.some((transport, index) => shouldMaterializeTransport(entries, index) && !transport)) return pendingSignalTransportMigration(cfg, PENDING_LEGACY_TRANSPORT_WARNING);
346
- const next = applyMigratedSignalTransports({
347
- cfg,
348
- entries,
349
- transports
350
- });
351
- if (!next) return {
302
+ const next = structuredClone(cfg);
303
+ const nextSignal = next.channels?.signal;
304
+ if (!isRecord(nextSignal)) return {
352
305
  config: cfg,
353
306
  changes: []
354
307
  };
308
+ const nestedDefaultIndex = resolveNestedDefaultEntryIndex(entries);
309
+ const nextAccounts = isRecord(nextSignal.accounts) ? nextSignal.accounts : {};
310
+ const nextEntries = [nextSignal, ...Object.values(nextAccounts).filter(isRecord)];
311
+ const rootIsAccount = hasRootSignalAccount(entries);
312
+ const canonicalRootTransport = isSignalTransportConfig(entries[0]?.transport) ? entries[0].transport : void 0;
313
+ for (const [index, entry] of nextEntries.entries()) {
314
+ if (index === nestedDefaultIndex) {
315
+ const defaultTransport = canonicalRootTransport ?? transports[index];
316
+ if (defaultTransport) nextSignal.transport = defaultTransport;
317
+ else delete nextSignal.transport;
318
+ delete entry.transport;
319
+ } else if (index === 0 && !rootIsAccount) delete entry.transport;
320
+ else if (transports[index]) entry.transport = transports[index];
321
+ else delete entry.transport;
322
+ clearLegacyTransportFields(entry);
323
+ }
324
+ delete nextSignal.apiMode;
355
325
  if (hasContainerTransportWithoutEffectiveAccount(next)) return pendingSignalTransportMigration(cfg, PENDING_LEGACY_CONTAINER_ACCOUNT_WARNING);
356
326
  return {
357
327
  config: next,
@@ -363,12 +333,28 @@ async function migrateLegacySignalTransportConfig(params) {
363
333
  if ("config" in prepared) return prepared;
364
334
  const { signal, apiMode, entries, legacyResolutionEntries } = prepared;
365
335
  if (!params.detect && legacyResolutionEntries.some((entry) => requiresDetection(entry, signal, apiMode))) return pendingSignalTransportMigration(params.cfg, PENDING_LEGACY_TRANSPORT_WARNING);
366
- const resolvedTransports = await Promise.all(entries.map(async (entry, index) => !shouldMaterializeTransport(entries, index) ? void 0 : await resolveLegacyTransport({
367
- entry,
368
- parent: signal,
369
- apiMode,
370
- detect: params.detect
371
- })));
336
+ const resolvedTransports = await Promise.all(entries.map(async (entry, index) => {
337
+ if (!shouldMaterializeTransport(entries, index)) return;
338
+ const detect = params.detect;
339
+ const resolved = resolveLegacyTransportWithoutDetection({
340
+ entry,
341
+ parent: signal,
342
+ apiMode
343
+ });
344
+ if (resolved) return resolved;
345
+ const account = normalizeOptionalString(inherited(entry, signal, "account"));
346
+ try {
347
+ const detected = await detect?.({
348
+ url: legacyBaseUrl(entry, signal),
349
+ ...account ? { account } : {}
350
+ });
351
+ if (detected?.kind === "external-native" && resolveLegacyAutoStart(entry, signal)) return buildManagedNativeTransport(entry, signal);
352
+ return detected;
353
+ } catch {
354
+ if (resolveLegacyAutoStart(entry, signal)) return buildManagedNativeTransport(entry, signal);
355
+ return;
356
+ }
357
+ }));
372
358
  return finishLegacySignalTransportMigration(params.cfg, entries, resolvedTransports);
373
359
  }
374
360
  function migrateLegacySignalTransportConfigSync(cfg) {
@@ -559,7 +545,9 @@ function repairSignalAccountKeys({ cfg }) {
559
545
  const groups = /* @__PURE__ */ new Map();
560
546
  for (const key of Object.keys(accounts)) if (key) {
561
547
  const id = normalizeAccountId(key);
562
- groups.set(id, [...groups.get(id) ?? [], key]);
548
+ const keys = groups.get(id);
549
+ if (keys) keys.push(key);
550
+ else groups.set(id, [key]);
563
551
  }
564
552
  const moves = /* @__PURE__ */ new Map();
565
553
  const warnings = [];
@@ -576,9 +564,14 @@ function repairSignalAccountKeys({ cfg }) {
576
564
  moves.set(key, id);
577
565
  }
578
566
  }
567
+ if (!moves.size) return {
568
+ config: cfg,
569
+ changes: [],
570
+ warnings
571
+ };
579
572
  const repaired = Object.fromEntries(Object.entries(accounts).map(([key, entry]) => [moves.get(key) ?? key, entry]));
580
573
  return {
581
- config: moves.size ? {
574
+ config: {
582
575
  ...cfg,
583
576
  channels: {
584
577
  ...cfg.channels,
@@ -587,7 +580,7 @@ function repairSignalAccountKeys({ cfg }) {
587
580
  accounts: repaired
588
581
  }
589
582
  }
590
- } : cfg,
583
+ },
591
584
  changes: [...moves].map(([from, to]) => `Moved Signal account "${from}" to channels.signal.accounts.${to}.`),
592
585
  warnings
593
586
  };
@@ -1,6 +1,43 @@
1
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  import { normalizeE164 } from "openclaw/plugin-sdk/text-utility-runtime";
3
3
  import { resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
4
+ //#region extensions/signal/src/normalize.ts
5
+ function normalizeSignalReactionRecipient(raw) {
6
+ const withoutSignal = raw.trim().replace(/^signal:/i, "").trim();
7
+ return /^uuid:/i.test(withoutSignal) ? withoutSignal.slice(5).trim() : withoutSignal;
8
+ }
9
+ function normalizeSignalMessagingTarget(raw) {
10
+ const normalized = raw.trim().replace(/^signal:/i, "").trim();
11
+ const prefix = /^(group|username|u|uuid):/i.exec(normalized)?.[0];
12
+ if (!prefix) return normalizeLowercaseStringOrEmpty(normalized) || void 0;
13
+ const id = normalized.slice(prefix.length).trim();
14
+ if (!id) return;
15
+ switch (prefix.toLowerCase()) {
16
+ case "group:": return `group:${id}`;
17
+ case "username:":
18
+ case "u:": return normalizeLowercaseStringOrEmpty(`username:${id}`);
19
+ default: return normalizeLowercaseStringOrEmpty(id);
20
+ }
21
+ }
22
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
23
+ const UUID_COMPACT_PATTERN = /^[0-9a-f]{32}$/i;
24
+ function looksLikeSignalTargetId(raw, normalized) {
25
+ const candidates = normalizeStringEntries([raw, normalized ?? ""]);
26
+ for (const candidate of candidates) {
27
+ if (/^(signal:)?(group:|username:|u:)/i.test(candidate)) return true;
28
+ if (/^(signal:)?uuid:/i.test(candidate)) {
29
+ const stripped = candidate.replace(/^signal:/i, "").replace(/^uuid:/i, "").trim();
30
+ if (!stripped) continue;
31
+ if (UUID_PATTERN.test(stripped) || UUID_COMPACT_PATTERN.test(stripped)) return true;
32
+ continue;
33
+ }
34
+ const withoutSignalPrefix = candidate.replace(/^signal:/i, "").trim();
35
+ if (UUID_PATTERN.test(withoutSignalPrefix) || UUID_COMPACT_PATTERN.test(withoutSignalPrefix)) return true;
36
+ if (/^\+?\d{3,}$/.test(withoutSignalPrefix)) return true;
37
+ }
38
+ return false;
39
+ }
40
+ //#endregion
4
41
  //#region extensions/signal/src/uuid.ts
5
42
  const UUID_HYPHENATED_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6
43
  const UUID_COMPACT_RE = /^[0-9a-f]{32}$/i;
@@ -94,4 +131,4 @@ function isSignalSenderAllowed(sender, allowFrom) {
94
131
  }).allowed;
95
132
  }
96
133
  //#endregion
97
- export { normalizeSignalAllowRecipient as a, resolveSignalSender as c, isSignalSenderAllowed as i, looksLikeUuid as l, formatSignalSenderDisplay as n, resolveSignalPeerId as o, formatSignalSenderId as r, resolveSignalRecipient as s, formatSignalPairingIdLine as t };
134
+ export { normalizeSignalAllowRecipient as a, resolveSignalSender as c, normalizeSignalMessagingTarget as d, normalizeSignalReactionRecipient as f, isSignalSenderAllowed as i, looksLikeUuid as l, formatSignalSenderDisplay as n, resolveSignalPeerId as o, formatSignalSenderId as r, resolveSignalRecipient as s, formatSignalPairingIdLine as t, looksLikeSignalTargetId as u };
@@ -17,45 +17,10 @@ const SIGNAL_CLI_DOWNLOAD_TIMEOUT_MS = 3e5;
17
17
  const SIGNAL_CLI_RELEASE_INFO_TIMEOUT_MS = 3e4;
18
18
  const CONTENT_LENGTH_RE = /^\d+$/;
19
19
  /** @internal Exported for testing. */
20
- async function extractSignalCliArchive(archivePath, installRoot, timeoutMs) {
21
- await extractArchive({
22
- archivePath,
23
- destDir: installRoot,
24
- timeoutMs,
25
- limits: {
26
- maxArchiveBytes: MAX_SIGNAL_CLI_ARCHIVE_BYTES,
27
- maxEntries: 32,
28
- maxEntryBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES,
29
- maxExtractedBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES
30
- }
31
- });
32
- }
33
- function normalizeReleaseAsset(value) {
34
- if (!isRecord(value)) return;
35
- const name = normalizeOptionalString(value.name);
36
- const browserDownloadUrl = normalizeOptionalString(value.browser_download_url);
37
- return name && browserDownloadUrl ? {
38
- name,
39
- browser_download_url: browserDownloadUrl
40
- } : void 0;
41
- }
42
- function normalizeSignalCliRelease(value) {
43
- const tagName = normalizeOptionalString(value.tag_name);
44
- const version = normalizeOptionalString(tagName?.replace(/^v/, ""));
45
- if (!version || !Array.isArray(value.assets)) return;
46
- return {
47
- version,
48
- assets: value.assets.flatMap((asset) => {
49
- const normalized = normalizeReleaseAsset(asset);
50
- return normalized ? [normalized] : [];
51
- })
52
- };
53
- }
54
- /** @internal Exported for testing. */
55
- async function downloadToFile(url, dest, maxRedirects = 5, maxBytes = MAX_SIGNAL_CLI_ARCHIVE_BYTES) {
20
+ async function downloadToFile(url, dest) {
56
21
  const { response, release } = await fetchWithSsrFGuard({
57
22
  url,
58
- maxRedirects,
23
+ maxRedirects: 5,
59
24
  requireHttps: true,
60
25
  timeoutMs: SIGNAL_CLI_DOWNLOAD_TIMEOUT_MS,
61
26
  capture: false,
@@ -67,20 +32,20 @@ async function downloadToFile(url, dest, maxRedirects = 5, maxBytes = MAX_SIGNAL
67
32
  if (rawLength !== null) {
68
33
  const trimmedLength = rawLength.trim();
69
34
  const declaredLength = CONTENT_LENGTH_RE.test(trimmedLength) ? Number(trimmedLength) : NaN;
70
- if (Number.isFinite(declaredLength) && declaredLength > maxBytes) throw new Error(`signal-cli archive exceeds the ${maxBytes}-byte download cap (declared ${declaredLength}).`);
35
+ if (Number.isFinite(declaredLength) && declaredLength > MAX_SIGNAL_CLI_ARCHIVE_BYTES) throw new Error(`signal-cli archive exceeds the ${MAX_SIGNAL_CLI_ARCHIVE_BYTES}-byte download cap (declared ${declaredLength}).`);
71
36
  }
72
37
  const body = response.body;
73
38
  async function* chunks() {
74
39
  yield* body.values({ preventCancel: true });
75
40
  }
76
41
  await (await root(path.dirname(dest))).create(path.basename(dest), chunks(), {
77
- maxBytes,
42
+ maxBytes: MAX_SIGNAL_CLI_ARCHIVE_BYTES,
78
43
  mkdir: false,
79
44
  durable: false,
80
45
  mode: 438 & ~process.umask()
81
46
  });
82
47
  } catch (error) {
83
- if (extractErrorCode(error) === "too-large") throw new Error(`signal-cli archive exceeded the ${maxBytes}-byte download cap.`, { cause: error });
48
+ if (extractErrorCode(error) === "too-large") throw new Error(`signal-cli archive exceeded the ${MAX_SIGNAL_CLI_ARCHIVE_BYTES}-byte download cap.`, { cause: error });
84
49
  throw error;
85
50
  } finally {
86
51
  await release();
@@ -154,83 +119,104 @@ async function installSignalCliViaBrew(runtime) {
154
119
  version
155
120
  };
156
121
  }
157
- /** @internal Exported for testing. */
158
- async function installSignalCliFromRelease(runtime) {
159
- const { response, release } = await fetchWithSsrFGuard({
160
- url: "https://api.github.com/repos/AsamK/signal-cli/releases/latest",
161
- maxRedirects: 5,
162
- requireHttps: true,
163
- timeoutMs: SIGNAL_CLI_RELEASE_INFO_TIMEOUT_MS,
164
- capture: false,
165
- auditContext: "signal-cli-release-info",
166
- init: { headers: {
167
- "User-Agent": "openclaw",
168
- Accept: "application/vnd.github+json"
169
- } }
170
- });
171
- let releaseInfo;
172
- try {
173
- if (!response.ok) return {
174
- ok: false,
175
- error: `Failed to fetch release info (${response.status})`
176
- };
177
- try {
178
- const normalized = normalizeSignalCliRelease(await readProviderJsonObjectResponse(response, "signal.release-info"));
179
- if (!normalized) throw new Error("Unexpected signal-cli release info");
180
- releaseInfo = normalized;
181
- } catch {
182
- return {
183
- ok: false,
184
- error: "Failed to parse signal-cli release info."
185
- };
186
- }
187
- } finally {
188
- await release();
189
- }
190
- const archives = releaseInfo.assets.filter((asset) => /\.(?:tar\.gz|tgz|zip)$/.test(normalizeLowercaseStringOrEmpty(asset.name)));
191
- const byName = (pattern) => archives.find((asset) => pattern.test(normalizeLowercaseStringOrEmpty(asset.name)));
192
- const asset = byName(/linux-native/) || byName(/linux/) || archives[0];
193
- if (!asset) return {
122
+ async function installSignalCli(runtime) {
123
+ if (process.platform === "win32") return {
194
124
  ok: false,
195
- error: "No compatible release asset found for this platform."
125
+ error: "Signal CLI auto-install is not supported on Windows yet."
196
126
  };
197
- return await withTempDownloadPath({
198
- prefix: "openclaw-signal",
199
- fileName: asset.name
200
- }, async (archivePath) => {
201
- runtime.log(`Downloading signal-cli ${releaseInfo.version} (${asset.name})…`);
202
- await downloadToFile(asset.browser_download_url, archivePath);
203
- const installRoot = path.join(CONFIG_DIR, "tools", "signal-cli", releaseInfo.version);
204
- await fs.mkdir(installRoot, { recursive: true });
127
+ if (process.platform === "linux" && process.arch === "x64") {
128
+ const { response, release } = await fetchWithSsrFGuard({
129
+ url: "https://api.github.com/repos/AsamK/signal-cli/releases/latest",
130
+ maxRedirects: 5,
131
+ requireHttps: true,
132
+ timeoutMs: SIGNAL_CLI_RELEASE_INFO_TIMEOUT_MS,
133
+ capture: false,
134
+ auditContext: "signal-cli-release-info",
135
+ init: { headers: {
136
+ "User-Agent": "openclaw",
137
+ Accept: "application/vnd.github+json"
138
+ } }
139
+ });
140
+ let releaseInfo;
205
141
  try {
206
- await extractSignalCliArchive(archivePath, installRoot, 6e4);
207
- } catch (err) {
208
- const message = formatErrorMessage(err);
209
- return {
142
+ if (!response.ok) return {
210
143
  ok: false,
211
- error: `Failed to extract ${asset.name}: ${message}`
144
+ error: `Failed to fetch release info (${response.status})`
212
145
  };
146
+ try {
147
+ const payload = await readProviderJsonObjectResponse(response, "signal.release-info");
148
+ const tagName = normalizeOptionalString(payload.tag_name);
149
+ const version = normalizeOptionalString(tagName?.replace(/^v/, ""));
150
+ if (!version || !Array.isArray(payload.assets)) throw new Error("Unexpected signal-cli release info");
151
+ releaseInfo = {
152
+ version,
153
+ assets: payload.assets.flatMap((asset) => {
154
+ if (!isRecord(asset)) return [];
155
+ const name = normalizeOptionalString(asset.name);
156
+ const browserDownloadUrl = normalizeOptionalString(asset.browser_download_url);
157
+ return name && browserDownloadUrl ? [{
158
+ name,
159
+ browser_download_url: browserDownloadUrl
160
+ }] : [];
161
+ })
162
+ };
163
+ } catch {
164
+ return {
165
+ ok: false,
166
+ error: "Failed to parse signal-cli release info."
167
+ };
168
+ }
169
+ } finally {
170
+ await release();
213
171
  }
214
- const cliPath = await findSignalCliBinary(installRoot);
215
- if (!cliPath) return {
172
+ const archives = releaseInfo.assets.filter((asset) => /\.(?:tar\.gz|tgz|zip)$/.test(normalizeLowercaseStringOrEmpty(asset.name)));
173
+ const byName = (pattern) => archives.find((asset) => pattern.test(normalizeLowercaseStringOrEmpty(asset.name)));
174
+ const asset = byName(/linux-native/) || byName(/linux/) || archives[0];
175
+ if (!asset) return {
216
176
  ok: false,
217
- error: `signal-cli binary not found after extracting ${asset.name}`
218
- };
219
- await fs.chmod(cliPath, 493).catch(() => {});
220
- return {
221
- ok: true,
222
- cliPath,
223
- version: releaseInfo.version
177
+ error: "No compatible release asset found for this platform."
224
178
  };
225
- });
226
- }
227
- async function installSignalCli(runtime) {
228
- if (process.platform === "win32") return {
229
- ok: false,
230
- error: "Signal CLI auto-install is not supported on Windows yet."
231
- };
232
- if (process.platform === "linux" && process.arch === "x64") return installSignalCliFromRelease(runtime);
179
+ return await withTempDownloadPath({
180
+ prefix: "openclaw-signal",
181
+ fileName: asset.name
182
+ }, async (archivePath) => {
183
+ runtime.log(`Downloading signal-cli ${releaseInfo.version} (${asset.name})…`);
184
+ await downloadToFile(asset.browser_download_url, archivePath);
185
+ const installRoot = path.join(CONFIG_DIR, "tools", "signal-cli", releaseInfo.version);
186
+ await fs.mkdir(installRoot, { recursive: true });
187
+ try {
188
+ await extractArchive({
189
+ archivePath,
190
+ destDir: installRoot,
191
+ timeoutMs: 6e4,
192
+ limits: {
193
+ maxArchiveBytes: MAX_SIGNAL_CLI_ARCHIVE_BYTES,
194
+ maxEntries: 32,
195
+ maxEntryBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES,
196
+ maxExtractedBytes: MAX_SIGNAL_CLI_EXTRACTED_BYTES
197
+ }
198
+ });
199
+ } catch (err) {
200
+ const message = formatErrorMessage(err);
201
+ return {
202
+ ok: false,
203
+ error: `Failed to extract ${asset.name}: ${message}`
204
+ };
205
+ }
206
+ const cliPath = await findSignalCliBinary(installRoot);
207
+ if (!cliPath) return {
208
+ ok: false,
209
+ error: `signal-cli binary not found after extracting ${asset.name}`
210
+ };
211
+ await fs.chmod(cliPath, 493).catch(() => {});
212
+ return {
213
+ ok: true,
214
+ cliPath,
215
+ version: releaseInfo.version
216
+ };
217
+ });
218
+ }
233
219
  return installSignalCliViaBrew(runtime);
234
220
  }
235
221
  //#endregion
236
- export { installSignalCliFromRelease as i, extractSignalCliArchive as n, installSignalCli as r, downloadToFile as t };
222
+ export { installSignalCli as n, downloadToFile as t };
@@ -1,4 +1,5 @@
1
1
  import { pathToFileURL } from "node:url";
2
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
2
3
  import { normalizeAccountId, resolveAccountKey } from "openclaw/plugin-sdk/account-resolution";
3
4
  import { isIP } from "node:net";
4
5
  import path from "node:path";
@@ -52,4 +53,20 @@ function buildSignalSocketUrl(socketPath) {
52
53
  return `unix://${pathToFileURL(socketPath).pathname}`;
53
54
  }
54
55
  //#endregion
55
- export { normalizeSignalTransportUrl as a, normalizeSignalTransportHost as i, buildSignalSocketUrl as n, resolveSignalAccountEntry as o, buildSignalTransportHttpUrl as r, resolveSignalAccountKey as s, assertSignalSocketTransport as t };
56
+ //#region extensions/signal/src/legacy-transport.ts
57
+ const LEGACY_SIGNAL_TRANSPORT_FIELDS = [
58
+ "configPath",
59
+ "httpUrl",
60
+ "httpHost",
61
+ "httpPort",
62
+ "cliPath",
63
+ "autoStart",
64
+ "startupTimeoutMs",
65
+ "receiveMode",
66
+ "ignoreStories"
67
+ ];
68
+ function hasLegacySignalTransportFields(value) {
69
+ return isRecord(value) && LEGACY_SIGNAL_TRANSPORT_FIELDS.some((field) => Object.hasOwn(value, field));
70
+ }
71
+ //#endregion
72
+ export { buildSignalTransportHttpUrl as a, resolveSignalAccountEntry as c, buildSignalSocketUrl as i, resolveSignalAccountKey as l, hasLegacySignalTransportFields as n, normalizeSignalTransportHost as o, assertSignalSocketTransport as r, normalizeSignalTransportUrl as s, LEGACY_SIGNAL_TRANSPORT_FIELDS as t };