@fased/fased 0.1.67 → 0.1.69

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 (187) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +20 -22
  3. package/config/sat-runtime.env +6 -2
  4. package/config/signer-protocol-v2.json +10 -0
  5. package/dist/agents/tools/wallet-action-tool.js +2 -0
  6. package/dist/agents/tools/wallet-tool.js +5 -3
  7. package/dist/brand.js +1 -1
  8. package/dist/build-info.json +3 -3
  9. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  10. package/dist/cli/program/register.wallet.js +119 -5
  11. package/dist/commands/wallet.js +1286 -74
  12. package/dist/config/sat-runtime-ids.js +6 -1
  13. package/dist/control-ui/assets/{app-De8gTtZU.js → app-BLFLoFPk.js} +1526 -1526
  14. package/dist/control-ui/assets/{federation-DgA9e-Pn.js → federation-SGMAnM_8.js} +2 -2
  15. package/dist/control-ui/assets/{index-DYYBRBOS.js → index-S88kp5ZQ.js} +3 -3
  16. package/dist/control-ui/assets/{mining-Dg-3ll0F.js → mining-ClI8RW4u.js} +2 -2
  17. package/dist/control-ui/assets/{wallet-DvStR_AT.js → wallet-CRIhDQbW.js} +325 -156
  18. package/dist/control-ui/index.html +1 -1
  19. package/dist/control-ui/version.json +1 -1
  20. package/dist/gateway/server-http.js +394 -55
  21. package/dist/mining/mainnet-sync.js +67 -5
  22. package/dist/operator/operator-readiness.js +1 -1
  23. package/dist/plugin-sdk/{actions-DRu135h0.js → actions-B-Vwj64K.js} +3 -3
  24. package/dist/plugin-sdk/{allow-list-DyAxs4yw.js → allow-list-Bf45HfoP.js} +1 -1
  25. package/dist/plugin-sdk/{audio-preflight-Dq_rJtqH.js → audio-preflight-CS7Q_7-R.js} +26 -25
  26. package/dist/plugin-sdk/{audit-C5d2z5U1.js → audit-CUULWG22.js} +1 -1
  27. package/dist/plugin-sdk/{channel-access-configure-DaI5wevh.js → channel-access-configure-BoUsC-Ys.js} +1 -1
  28. package/dist/plugin-sdk/{channel-adapters.discord-BS4S4Svh.js → channel-adapters.discord-DSiR4X2Y.js} +1 -1
  29. package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
  30. package/dist/plugin-sdk/channel-plugin-common.js +1 -1
  31. package/dist/plugin-sdk/{chunk-CyoyqpbG.js → chunk-CBpl-AiQ.js} +1 -1
  32. package/dist/plugin-sdk/{chunk-items-Dunoq4Er.js → chunk-items-BLBZNORg.js} +1 -1
  33. package/dist/plugin-sdk/command-status.js +26 -25
  34. package/dist/plugin-sdk/{commands-registry-BfqdEWdF.js → commands-registry-G5KXSi_y.js} +1 -1
  35. package/dist/plugin-sdk/{config-schema--vl89M7d.js → config-schema-BiBOUW89.js} +431 -125
  36. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  37. package/dist/plugin-sdk/{diagnostic-DLL_zekv.js → diagnostic-sYs6Agr-.js} +1 -1
  38. package/dist/plugin-sdk/{directory-live-CSuYxdwk.js → directory-live-BXMpuYAF.js} +1 -1
  39. package/dist/plugin-sdk/{directory-live-Dw7ZgC9_.js → directory-live-Rn1BzPof.js} +1 -1
  40. package/dist/plugin-sdk/discord.d.ts +4 -4
  41. package/dist/plugin-sdk/discord.js +20 -20
  42. package/dist/plugin-sdk/{draft-stream-controls-BqchW1vi.js → draft-stream-controls-CMNdKSx-.js} +1 -1
  43. package/dist/plugin-sdk/{guilds-CDhRIX57.js → guilds-Dkwl0yHv.js} +1 -1
  44. package/dist/plugin-sdk/{handle-action-hvwapMKg.js → handle-action-CRdM6B-8.js} +15 -15
  45. package/dist/plugin-sdk/index.d.ts +15 -15
  46. package/dist/plugin-sdk/index.js +28 -27
  47. package/dist/plugin-sdk/{login-Ca583Okc.js → login-D7WnK8-P.js} +1 -1
  48. package/dist/plugin-sdk/{login-qr-CGciBSNP.js → login-qr-CRueOKZK.js} +2 -114
  49. package/dist/plugin-sdk/{markdown-tables-DCOXEUfZ.js → markdown-tables-d7GlUs5R.js} +1 -1
  50. package/dist/plugin-sdk/{media-CAdQF5TG.js → media-BAoaxCrt.js} +1 -1
  51. package/dist/plugin-sdk/{monitor-DrTy_4CL.js → monitor-WXdn4mR-.js} +34 -33
  52. package/dist/plugin-sdk/{monitor-CV1sr0p2.js → monitor-xzVAPbg2.js} +44 -43
  53. package/dist/plugin-sdk/{openresponses-http-BAjgURZa.js → openresponses-http-DnI1LFgq.js} +26 -25
  54. package/dist/plugin-sdk/{outbound-attachment-QqTnIhZL.js → outbound-attachment-CyXM3cAv.js} +1 -1
  55. package/dist/plugin-sdk/{outbound-BgVDdHxx.js → outbound-zB6llMGW.js} +6 -6
  56. package/dist/plugin-sdk/{pairing-message-BjIJYVvp.d.ts → pairing-message-CiTcdD6m.d.ts} +1 -1
  57. package/dist/plugin-sdk/{pairing-store-BChahgI2.js → pairing-store-B6J2C0vP.js} +1 -1
  58. package/dist/plugin-sdk/{pi-model-discovery-runtime-DxTMz_XF.js → pi-model-discovery-runtime-6JzLw9Gk.js} +1 -1
  59. package/dist/plugin-sdk/{probe-CJb5uR8B.js → probe-BM7Oe40M.js} +2 -2
  60. package/dist/plugin-sdk/{probe-l_whvGLY.js → probe-CMPksimh.js} +1 -1
  61. package/dist/plugin-sdk/{probe-BFroeK3g.js → probe-oVp12D6L.js} +1 -1
  62. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
  63. package/dist/plugin-sdk/{pw-ai-DlxqX6Es.js → pw-ai-DZYLDC-S.js} +1 -1
  64. package/dist/plugin-sdk/qr-image-B4MlMG4N.js +115 -0
  65. package/dist/plugin-sdk/{replies-ChYo5ZQM.js → replies-CY-V0Zob.js} +3 -3
  66. package/dist/plugin-sdk/{resolve-channels-87LZrFk_.js → resolve-channels-1HtDcMqh.js} +2 -2
  67. package/dist/plugin-sdk/{resolve-channels-_-nV-EK2.js → resolve-channels-CU72Qh2j.js} +1 -1
  68. package/dist/plugin-sdk/{resolve-outbound-target-D-KGgHJZ.js → resolve-outbound-target-nQSBVYz9.js} +2 -2
  69. package/dist/plugin-sdk/{resolve-route-C8tvQm8Z.js → resolve-route-Dufnu2cT.js} +1 -1
  70. package/dist/plugin-sdk/{resolve-users-DN9VQBwv.js → resolve-users-Bk_ss2vC.js} +1 -1
  71. package/dist/plugin-sdk/{resolve-users-V6dHh_2B.js → resolve-users-IevCOk4W.js} +2 -2
  72. package/dist/plugin-sdk/{runtime-2B9_WKoI.js → runtime-CXSQwMaR.js} +1 -1
  73. package/dist/plugin-sdk/{runtime-dependency-nup8niQL.js → runtime-dependency-DczkvPxn.js} +9 -9
  74. package/dist/plugin-sdk/sat-runtime.d.ts +105 -10
  75. package/dist/plugin-sdk/sat-runtime.js +26 -25
  76. package/dist/plugin-sdk/{send-DCO441U7.js → send-BXBS_mRK.js} +8 -8
  77. package/dist/plugin-sdk/{send-CFzGKJXo.js → send-D-HfKQZm.js} +4 -4
  78. package/dist/plugin-sdk/{send-B6KkGKZD.js → send-D1j12ZgX.js} +5 -5
  79. package/dist/plugin-sdk/{send-q9HXrSwK.js → send-DWKm6yay.js} +10 -10
  80. package/dist/plugin-sdk/{send-gDoGA-7e.js → send-Di1Jit3L.js} +7 -7
  81. package/dist/plugin-sdk/{skill-commands-FKEPLS7T.js → skill-commands-iJtvpqgb.js} +2 -2
  82. package/dist/plugin-sdk/{slack-DSC6T2KW.js → slack-CkIRVDUK.js} +45 -44
  83. package/dist/plugin-sdk/{slack-actions-DhbMcp8M.js → slack-actions-BzUEszJa.js} +10 -10
  84. package/dist/plugin-sdk/slack.d.ts +4 -4
  85. package/dist/plugin-sdk/slack.js +6 -6
  86. package/dist/plugin-sdk/{sticker-cache-C0l_5IKg.js → sticker-cache-Dpap5ce_.js} +2 -2
  87. package/dist/plugin-sdk/{tables-B3jr0Pvq.js → tables-_1W36GII.js} +2 -2
  88. package/dist/plugin-sdk/{targets-CtSbTxYX.js → targets-DDbNnLnB.js} +2 -2
  89. package/dist/plugin-sdk/{telegram-actions-BwGBIVDE.js → telegram-actions-Cewdga8H.js} +30 -29
  90. package/dist/plugin-sdk/telegram.d.ts +4 -4
  91. package/dist/plugin-sdk/telegram.js +3 -3
  92. package/dist/plugin-sdk/{thread-bindings.lifecycle-QbkNl-m6.js → thread-bindings.lifecycle-Y9T3CQGf.js} +3 -3
  93. package/dist/plugin-sdk/{thread-bindings.state-D9hg_M1c.js → thread-bindings.state-D2oOWDpv.js} +1 -1
  94. package/dist/plugin-sdk/{tmp-fased-dir-DXnGKKgi.d.ts → tmp-fased-dir-BSEHc8MQ.d.ts} +8 -2
  95. package/dist/plugin-sdk/{types-eG9aYqXF.d.ts → types-BakzIzGN.d.ts} +1 -1
  96. package/dist/plugin-sdk/{types-Cegc86EP.d.ts → types-CzF0YQqK.d.ts} +3 -3
  97. package/dist/plugin-sdk/{web-C_AH5PyB.js → web-DGWi7i3B.js} +33 -32
  98. package/dist/plugin-sdk/{whatsapp-actions-Bj_rOncr.js → whatsapp-actions-Blu9-eX-.js} +9 -9
  99. package/dist/plugin-sdk/{whatsapp-heartbeat-B1WHkJIg.js → whatsapp-heartbeat-DjmQM7hq.js} +2 -2
  100. package/dist/plugin-sdk/whatsapp.d.ts +9 -9
  101. package/dist/plugin-sdk/whatsapp.js +7 -7
  102. package/dist/plugin-sdk/{wsl-J-HscWxS.js → wsl-CTvIWvZz.js} +1 -1
  103. package/dist/plugin-sdk/{zod-schema.providers-core-FaYR6KdD.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
  104. package/dist/wallet/local-socket-signer-lifecycle.js +107 -3
  105. package/dist/wallet/local-socket-signer-protocol.js +97 -10
  106. package/dist/wallet/mining-wallet-retirement.js +256 -0
  107. package/dist/wallet/providers/local-socket-signer-adapter.js +10 -0
  108. package/dist/wallet/signer-network-admin.js +11 -118
  109. package/dist/wallet/signer-protocol-v2.generated.js +10 -0
  110. package/dist/wallet/solana-assets.js +9 -3
  111. package/dist/wallet/solana-rpc-read-fetch.js +65 -0
  112. package/dist/wallet/wallet-agent-selection.js +6 -10
  113. package/dist/wallet/wallet-provider-registry.js +70 -29
  114. package/dist/wallet/wallet-send-approvals.js +6 -2
  115. package/dist/wallet/wallet-status.js +63 -1
  116. package/dist/web/login-qr.js +1 -1
  117. package/dist/wizard/onboarding.js +86 -84
  118. package/dist/wizard/onboarding.wallet.js +10 -1
  119. package/extensions/acpx/package.json +1 -1
  120. package/extensions/bluebubbles/package.json +1 -1
  121. package/extensions/copilot-proxy/package.json +1 -1
  122. package/extensions/diagnostics-otel/package.json +1 -1
  123. package/extensions/fased-federation/package.json +1 -1
  124. package/extensions/google-gemini-cli-auth/package.json +1 -1
  125. package/extensions/imessage/package.json +1 -1
  126. package/extensions/irc/package.json +1 -1
  127. package/extensions/line/package.json +1 -1
  128. package/extensions/llm-task/package.json +1 -1
  129. package/extensions/lobster/package.json +1 -1
  130. package/extensions/matrix/CHANGELOG.md +12 -0
  131. package/extensions/matrix/package.json +1 -1
  132. package/extensions/mattermost/package.json +1 -1
  133. package/extensions/memory-core/package.json +2 -2
  134. package/extensions/memory-lancedb/package.json +1 -1
  135. package/extensions/minimax-portal-auth/package.json +1 -1
  136. package/extensions/msteams/CHANGELOG.md +12 -0
  137. package/extensions/msteams/package.json +1 -1
  138. package/extensions/nextcloud-talk/package.json +1 -1
  139. package/extensions/nostr/CHANGELOG.md +12 -0
  140. package/extensions/nostr/package.json +1 -1
  141. package/extensions/open-prose/package.json +1 -1
  142. package/extensions/sat-mining/package.json +1 -1
  143. package/extensions/signal/package.json +1 -1
  144. package/extensions/synology-chat/package.json +1 -1
  145. package/extensions/tlon/package.json +1 -1
  146. package/extensions/twitch/CHANGELOG.md +12 -0
  147. package/extensions/twitch/package.json +1 -1
  148. package/extensions/voice-call/CHANGELOG.md +12 -0
  149. package/extensions/voice-call/package.json +1 -1
  150. package/extensions/zalo/CHANGELOG.md +12 -0
  151. package/extensions/zalo/package.json +1 -1
  152. package/extensions/zalouser/CHANGELOG.md +12 -0
  153. package/extensions/zalouser/package.json +1 -1
  154. package/install.sh +286 -107
  155. package/package.json +4 -2
  156. package/scripts/fased-managed-updater.mjs +10 -2
  157. package/scripts/install-fased-signerd.sh +4 -8
  158. package/scripts/install-managed-runtime.mjs +10 -7
  159. package/scripts/install-runtime-profile.sh +27 -0
  160. package/scripts/start-managed.sh +13 -1
  161. /package/dist/plugin-sdk/{active-listener-B_NMtgPL.js → active-listener-p9Ooc1qj.js} +0 -0
  162. /package/dist/plugin-sdk/{blocks-input-Bg-8S2pl.js → blocks-input-DiZaqaN7.js} +0 -0
  163. /package/dist/plugin-sdk/{channel-access-CcFRdRPO.js → channel-access-B0aZBSd2.js} +0 -0
  164. /package/dist/plugin-sdk/{channel-activity-DBDMQ3yI.js → channel-activity-F07DjroV.js} +0 -0
  165. /package/dist/plugin-sdk/{channel-core-CFRs8LPy.js → channel-core-DoF4X04L.js} +0 -0
  166. /package/dist/plugin-sdk/{client-pI228AVT.js → client-DLY-kWF_.js} +0 -0
  167. /package/dist/plugin-sdk/{command-poll-backoff-yJU83wEq.js → command-poll-backoff-NAePk3eL.js} +0 -0
  168. /package/dist/plugin-sdk/{date-time-uUevHscU.js → date-time-ChY_tHoG.js} +0 -0
  169. /package/dist/plugin-sdk/{draft-stream-loop-CrOPfV3F.js → draft-stream-loop-DMBwjjd1.js} +0 -0
  170. /package/dist/plugin-sdk/{fetch-BtmoPIlf.js → fetch-B0v6OTUZ.js} +0 -0
  171. /package/dist/plugin-sdk/{filesystem-manager-DoI8IBNF.js → filesystem-manager-BzuIJ9K9.js} +0 -0
  172. /package/dist/plugin-sdk/{gateway-registry-DZDsqicG.js → gateway-registry-Bgl2GFgy.js} +0 -0
  173. /package/dist/plugin-sdk/{inbound-context-DrAcXE0y.js → inbound-context-CQnfFFQ9.js} +0 -0
  174. /package/dist/plugin-sdk/{pi-model-discovery-BX_JLcEJ.js → pi-model-discovery-BHNVyRny.js} +0 -0
  175. /package/dist/plugin-sdk/{polls-DKQXVfJp.js → polls-DXd67TD8.js} +0 -0
  176. /package/dist/plugin-sdk/{proxy-DWpYcsvR.js → proxy-CLRUdShp.js} +0 -0
  177. /package/dist/plugin-sdk/{qmd-manager-CgRaTxUq.js → qmd-manager-B8Vnu0ND.js} +0 -0
  178. /package/dist/plugin-sdk/{render-e7fENCYH.js → render-DrBfVs0u.js} +0 -0
  179. /package/dist/plugin-sdk/{reply-reference-Bqk-7HXE.js → reply-reference-BnAk5Wjb.js} +0 -0
  180. /package/dist/plugin-sdk/{retry-policy-C6SjKjQA.js → retry-policy-CXh1owkc.js} +0 -0
  181. /package/dist/plugin-sdk/{sandbox-paths-Dx2lUqCu.js → sandbox-paths-Bzh1CuZc.js} +0 -0
  182. /package/dist/plugin-sdk/{session-DHD4ZKyG.js → session-iuGR_rdi.js} +0 -0
  183. /package/dist/plugin-sdk/{shared-CBgp_GBw.js → shared-D1AD2Ejn.js} +0 -0
  184. /package/dist/plugin-sdk/{target-errors-Ckufe179.js → target-errors-DfS1sLR9.js} +0 -0
  185. /package/dist/plugin-sdk/{tool-loop-detection-Bp8bPJLs.js → tool-loop-detection-sDZl27w7.js} +0 -0
  186. /package/dist/plugin-sdk/{ui-Be8cLHIS.js → ui-GQDYm_jw.js} +0 -0
  187. /package/dist/plugin-sdk/{with-timeout-ckWB8rTo.js → with-timeout-CVV8tytk.js} +0 -0
@@ -1,3 +1,4 @@
1
+ import { fetchPinnedSolanaRpcRead } from "./solana-rpc-read-fetch.js";
1
2
  import { PublicKey } from "@solana/web3.js";
2
3
 
3
4
  //#region src/wallet/solana-assets.ts
@@ -427,10 +428,11 @@ function formatTokenAmount(raw, decimals) {
427
428
  }
428
429
  }
429
430
  async function fetchSolanaRpc(rpcUrl, method, params) {
431
+ let release;
430
432
  try {
431
- const response = await fetch(rpcUrl, {
432
- method: "POST",
433
- headers: { "Content-Type": "application/json" },
433
+ const guarded = await fetchPinnedSolanaRpcRead({
434
+ rpcUrl,
435
+ timeoutMs: 1e4,
434
436
  body: JSON.stringify({
435
437
  jsonrpc: "2.0",
436
438
  id: 1,
@@ -438,6 +440,8 @@ async function fetchSolanaRpc(rpcUrl, method, params) {
438
440
  params
439
441
  })
440
442
  });
443
+ release = guarded.release;
444
+ const response = guarded.response;
441
445
  if (!response.ok) {
442
446
  recordSolanaAssetRpcMethod(method, "failure");
443
447
  return null;
@@ -452,6 +456,8 @@ async function fetchSolanaRpc(rpcUrl, method, params) {
452
456
  } catch {
453
457
  recordSolanaAssetRpcMethod(method, "failure");
454
458
  return null;
459
+ } finally {
460
+ await release?.();
455
461
  }
456
462
  }
457
463
  async function fetchSolanaMetadataFromMintViaRpc(params) {
@@ -0,0 +1,65 @@
1
+ import { closeDispatcher, createPinnedDispatcher, resolvePinnedHostnameWithPolicy } from "../infra/net/ssrf.js";
2
+
3
+ //#region src/wallet/solana-rpc-read-fetch.ts
4
+ function normalizeRpcHostname(hostname) {
5
+ const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
6
+ return normalized.startsWith("[") && normalized.endsWith("]") ? normalized.slice(1, -1) : normalized;
7
+ }
8
+ function isLoopbackRpcHostname(hostname) {
9
+ const normalized = normalizeRpcHostname(hostname);
10
+ return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
11
+ }
12
+ function isLoopbackRpcAddress(address) {
13
+ const normalized = normalizeRpcHostname(address);
14
+ return normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/.test(normalized) || /^::ffff:127(?:\.\d{1,3}){3}$/.test(normalized);
15
+ }
16
+ async function resolveWithTimeout(hostname, policy, timeoutMs) {
17
+ let timer;
18
+ try {
19
+ return await Promise.race([resolvePinnedHostnameWithPolicy(hostname, { policy }), new Promise((_resolve, reject) => {
20
+ timer = setTimeout(() => reject(new Error("stored Solana RPC hostname resolution timed out")), Math.max(250, timeoutMs));
21
+ timer.unref?.();
22
+ })]);
23
+ } finally {
24
+ if (timer) {
25
+ clearTimeout(timer);
26
+ }
27
+ }
28
+ }
29
+ async function fetchPinnedSolanaRpcRead(params) {
30
+ const parsed = new URL(params.rpcUrl);
31
+ const hostname = normalizeRpcHostname(parsed.hostname);
32
+ const loopback = isLoopbackRpcHostname(hostname);
33
+ if (!hostname || parsed.username || parsed.password || parsed.hash || parsed.protocol !== "https:" && !(parsed.protocol === "http:" && loopback)) {
34
+ throw new Error("stored Solana RPC URL is not safe for Gateway reads");
35
+ }
36
+ const policy = {
37
+ hostnameAllowlist: [hostname],
38
+ ...loopback ? { allowPrivateNetwork: true } : {}
39
+ };
40
+ const pinned = await resolveWithTimeout(hostname, policy, params.timeoutMs);
41
+ if (loopback && !pinned.addresses.every(isLoopbackRpcAddress)) {
42
+ throw new Error("stored Local Solana RPC hostname did not resolve only to loopback addresses");
43
+ }
44
+ const dispatcher = createPinnedDispatcher(pinned);
45
+ try {
46
+ const response = await fetch(parsed.toString(), {
47
+ method: "POST",
48
+ headers: { "content-type": "application/json" },
49
+ body: params.body,
50
+ redirect: "error",
51
+ signal: AbortSignal.timeout(Math.max(250, params.timeoutMs)),
52
+ dispatcher
53
+ });
54
+ return {
55
+ response,
56
+ release: async () => closeDispatcher(dispatcher)
57
+ };
58
+ } catch (error) {
59
+ await closeDispatcher(dispatcher);
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ //#endregion
65
+ export { fetchPinnedSolanaRpcRead };
@@ -42,16 +42,12 @@ function resolveWalletActionSelection(params) {
42
42
  providerId: params.providerId,
43
43
  env
44
44
  });
45
- } else if (registry.defaultWalletId) {
46
- const fallback = registry.wallets.find((entry) => entry.id === registry.defaultWalletId);
47
- selection = fallback ? {
48
- walletId: fallback.id,
49
- walletName: fallback.name,
50
- providerId: fallback.providerId,
51
- source: "fallback"
52
- } : { source: "none" };
53
45
  } else {
54
- selection = { source: "none" };
46
+ selection = resolveWalletSelection({
47
+ agentId: params.agentId,
48
+ skillWalletId: params.skillWalletId,
49
+ env
50
+ });
55
51
  }
56
52
  } catch (error) {
57
53
  const message = error instanceof Error ? error.message : "wallet selection failed";
@@ -61,7 +57,7 @@ function resolveWalletActionSelection(params) {
61
57
  throw new WalletActionSelectionError("wallet_not_found", message);
62
58
  }
63
59
  if (!selection.walletId) {
64
- throw new WalletActionSelectionError("wallet_handle_required", "Agent wallet handle, walletId, or default Agent wallet required");
60
+ throw new WalletActionSelectionError("wallet_handle_required", "Select an Agent wallet: use an explicit wallet, skill override, Agent assignment, or Default Agent wallet fallback");
65
61
  }
66
62
  const wallet = registry.wallets.find((entry) => entry.id === selection.walletId);
67
63
  if (!wallet) {
@@ -479,9 +479,6 @@ function upsertNamedWallet(params) {
479
479
  updatedAt: now
480
480
  };
481
481
  registry.wallets = [...registry.wallets.filter((entry) => entry.id !== next.id), next].toSorted((a, b) => a.createdAt.localeCompare(b.createdAt));
482
- if (!registry.defaultWalletId || !registry.wallets.some((wallet) => wallet.id === registry.defaultWalletId)) {
483
- registry.defaultWalletId = resolveWalletUserRole(next) === "agent" ? next.id : undefined;
484
- }
485
482
  writeWalletProviderRegistry(registry, env);
486
483
  return next;
487
484
  }
@@ -497,6 +494,10 @@ function deleteNamedWallet(params) {
497
494
  walletId,
498
495
  env
499
496
  });
497
+ const targetWallet = registry.wallets.find((wallet) => wallet.id === walletId);
498
+ if (resolveWalletUserRole(targetWallet) === "mining") {
499
+ throw new Error("Mining wallets cannot be deleted directly; use Retire and replace Mining wallet so signer acknowledgement precedes registry detachment");
500
+ }
500
501
  const before = registry.wallets.length;
501
502
  registry.wallets = registry.wallets.filter((entry) => entry.id !== walletId);
502
503
  for (const [agentId, assignedWalletId] of Object.entries(registry.assignments)) {
@@ -514,6 +515,50 @@ function deleteNamedWallet(params) {
514
515
  registry
515
516
  };
516
517
  }
518
+ function replaceRetiredMiningWallet(params) {
519
+ const env = params.env ?? process.env;
520
+ const registry = readWalletProviderRegistry(env);
521
+ const sourceWalletId = params.sourceWalletId.trim();
522
+ if (!/^sha256:[0-9a-f]{64}$/u.test(params.signerAcknowledgement.rotationId) || !/^sha256:[0-9a-f]{64}$/u.test(params.signerAcknowledgement.sourceRetiredPolicyHash) || !/^sha256:[0-9a-f]{64}$/u.test(params.signerAcknowledgement.successorPolicyHash) || params.signerAcknowledgement.successorPublicKey !== params.successor.addresses?.solana || params.successor.metadata?.rotationId !== params.signerAcknowledgement.rotationId || params.successor.metadata?.policyHash !== params.signerAcknowledgement.successorPolicyHash) {
523
+ throw new Error("signer retirement acknowledgement is missing or does not match the successor");
524
+ }
525
+ const sourceIndex = registry.wallets.findIndex((wallet) => wallet.id === sourceWalletId);
526
+ if (sourceIndex < 0) {
527
+ const existing = registry.wallets.find((wallet) => wallet.id === params.successor.id);
528
+ if (existing?.providerId === "local-socket-signer" && existing.addresses?.solana === params.successor.addresses?.solana && resolveWalletUserRole(existing) === "mining") {
529
+ return existing;
530
+ }
531
+ throw new Error("retired Mining source registration is missing");
532
+ }
533
+ const source = registry.wallets[sourceIndex];
534
+ if (resolveWalletUserRole(source) !== "mining") {
535
+ throw new Error("source registration is not the active Mining wallet");
536
+ }
537
+ if (params.successor.id === sourceWalletId || registry.wallets.some((wallet) => wallet.id === params.successor.id)) {
538
+ throw new Error("Mining successor registration must use a new wallet id");
539
+ }
540
+ assertNamedWalletDeletionSafe({
541
+ walletId: sourceWalletId,
542
+ env
543
+ });
544
+ const now = nowIso();
545
+ const successor = {
546
+ ...params.successor,
547
+ createdAt: now,
548
+ updatedAt: now
549
+ };
550
+ registry.wallets.splice(sourceIndex, 1, successor);
551
+ for (const [agentId, assignedWalletId] of Object.entries(registry.assignments)) {
552
+ if (assignedWalletId === sourceWalletId) {
553
+ delete registry.assignments[agentId];
554
+ }
555
+ }
556
+ if (registry.defaultWalletId === sourceWalletId) {
557
+ registry.defaultWalletId = undefined;
558
+ }
559
+ writeWalletProviderRegistry(registry, env);
560
+ return successor;
561
+ }
517
562
  function setAgentWalletAssignment(params) {
518
563
  const env = params.env ?? process.env;
519
564
  const registry = readWalletProviderRegistry(env);
@@ -527,9 +572,13 @@ function setAgentWalletAssignment(params) {
527
572
  writeWalletProviderRegistry(registry, env);
528
573
  return registry;
529
574
  }
530
- if (!registry.wallets.some((wallet) => wallet.id === walletId)) {
575
+ const wallet = registry.wallets.find((entry) => entry.id === walletId);
576
+ if (!wallet) {
531
577
  throw new Error("walletId does not exist");
532
578
  }
579
+ if (resolveWalletUserRole(wallet) !== "agent") {
580
+ throw new Error("only Agent wallets can be assigned to an Agent");
581
+ }
533
582
  registry.assignments[agentId] = walletId;
534
583
  writeWalletProviderRegistry(registry, env);
535
584
  return registry;
@@ -548,23 +597,9 @@ function setDefaultWallet(params) {
548
597
  throw new Error("walletId does not exist");
549
598
  }
550
599
  const purpose = resolveWalletUserRole(targetWallet);
551
- if (purpose && purpose !== "agent") {
552
- throw new Error("only Agent wallets can become the primary Agent fallback");
600
+ if (purpose !== "agent") {
601
+ throw new Error("only an explicit Agent wallet can become the Default Agent wallet fallback");
553
602
  }
554
- registry.wallets = registry.wallets.map((wallet) => {
555
- if (wallet.id !== walletId) {
556
- return wallet;
557
- }
558
- return {
559
- ...wallet,
560
- metadata: {
561
- ...wallet.metadata,
562
- role: "agent",
563
- purpose: "agent"
564
- },
565
- updatedAt: nowIso()
566
- };
567
- });
568
603
  registry.defaultWalletId = walletId;
569
604
  writeWalletProviderRegistry(registry, env);
570
605
  return registry;
@@ -588,12 +623,15 @@ function setNamedWalletRole(params) {
588
623
  },
589
624
  updatedAt: nowIso()
590
625
  } : wallet);
591
- if (params.role === "agent" && !registry.defaultWalletId) {
592
- registry.defaultWalletId = walletId;
626
+ if (params.role !== "agent" && registry.defaultWalletId === walletId) {
627
+ registry.defaultWalletId = undefined;
593
628
  }
594
- if (params.role === "vault" && registry.defaultWalletId === walletId) {
595
- const nextDefault = registry.wallets.find((wallet) => wallet.id !== walletId && resolveWalletUserRole(wallet) === "agent");
596
- registry.defaultWalletId = nextDefault?.id;
629
+ if (params.role !== "agent") {
630
+ for (const [agentId, assignedWalletId] of Object.entries(registry.assignments)) {
631
+ if (assignedWalletId === walletId) {
632
+ delete registry.assignments[agentId];
633
+ }
634
+ }
597
635
  }
598
636
  writeWalletProviderRegistry(registry, env);
599
637
  return registry;
@@ -603,7 +641,8 @@ function resolveWalletSelectionForAgent(params) {
603
641
  const registry = readWalletProviderRegistry(env);
604
642
  const directAgent = params.agentId?.trim();
605
643
  const directWalletId = directAgent ? registry.assignments[directAgent] : undefined;
606
- const walletId = directWalletId ?? registry.defaultWalletId;
644
+ const skillWalletId = params.skillWalletId?.trim();
645
+ const walletId = skillWalletId ?? directWalletId ?? registry.defaultWalletId;
607
646
  if (!walletId) {
608
647
  return {};
609
648
  }
@@ -614,7 +653,8 @@ function resolveWalletSelectionForAgent(params) {
614
653
  return {
615
654
  walletId: wallet.id,
616
655
  walletName: wallet.name,
617
- providerId: wallet.providerId
656
+ providerId: wallet.providerId,
657
+ source: skillWalletId ? "skill" : directWalletId ? "agent" : "default"
618
658
  };
619
659
  }
620
660
  function resolveWalletSelection(params) {
@@ -676,16 +716,17 @@ function resolveWalletSelection(params) {
676
716
  }
677
717
  const fallback = resolveWalletSelectionForAgent({
678
718
  agentId: params.agentId,
719
+ skillWalletId: params.skillWalletId,
679
720
  env
680
721
  });
681
722
  if (fallback.walletId || fallback.providerId) {
682
723
  return {
683
724
  ...fallback,
684
- source: "fallback"
725
+ source: fallback.source ?? "fallback"
685
726
  };
686
727
  }
687
728
  return { source: "none" };
688
729
  }
689
730
 
690
731
  //#endregion
691
- export { WALLET_PROVIDER_IDS, checkNamedWalletDeletionSafety, deleteNamedWallet, normalizeWalletUserRole, readWalletProviderRegistry, resolveWalletSelection, resolveWalletUserRole, setAgentWalletAssignment, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, setWalletProvidersEnabled, upsertNamedWallet };
732
+ export { WALLET_PROVIDER_IDS, checkNamedWalletDeletionSafety, deleteNamedWallet, normalizeWalletUserRole, readWalletProviderRegistry, replaceRetiredMiningWallet, resolveWalletSelection, resolveWalletUserRole, setAgentWalletAssignment, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, setWalletProvidersEnabled, upsertNamedWallet, writeWalletProviderRegistry };
@@ -2126,7 +2126,11 @@ async function approveWalletSendRequest(params) {
2126
2126
  request
2127
2127
  };
2128
2128
  }
2129
- if (storedReview.state === "prepared" && !params.reviewAuthorization) {
2129
+ const controlUIAuthorization = storedReview.state === "prepared" && !params.reviewAuthorization && (storedReview.intentType === "solana.nativeTransfer" || storedReview.intentType === "solana.splTransferChecked") ? {
2130
+ type: "control-ui",
2131
+ proof: { proofId: storedReview.nonce }
2132
+ } : undefined;
2133
+ if (storedReview.state === "prepared" && !params.reviewAuthorization && !controlUIAuthorization) {
2130
2134
  if (claim.recovered && request.status === "executing") {
2131
2135
  await withApprovalMutationLock(env, () => {
2132
2136
  file = loadFile(env);
@@ -2151,7 +2155,7 @@ async function approveWalletSendRequest(params) {
2151
2155
  request
2152
2156
  };
2153
2157
  }
2154
- const executionAuthorization = storedReview.state === "prepared" ? params.reviewAuthorization : undefined;
2158
+ const executionAuthorization = storedReview.state === "prepared" ? params.reviewAuthorization ?? controlUIAuthorization : undefined;
2155
2159
  let executed;
2156
2160
  try {
2157
2161
  executed = await provider.executeSignerReview({
@@ -1,10 +1,12 @@
1
1
  import { loadConfig } from "../config/io.js";
2
2
  import "../config/config.js";
3
- import { ensureWalletStateDir, resolveWalletRuntimeConfig, resolveWalletStatePaths } from "./wallet-runtime-config.js";
3
+ import { ensureWalletStateDir, resolveLocalSignerSocketPath, resolveWalletRuntimeConfig, resolveWalletStatePaths } from "./wallet-runtime-config.js";
4
4
  import { readWalletProviderRegistry } from "./wallet-provider-registry.js";
5
5
  import { resolveWalletPolicyConfig } from "./wallet-policy.js";
6
6
  import { redactWalletDiagnosticText, walletDiagnosticErrorMessage, walletDiagnosticErrorString } from "./wallet-redaction.js";
7
7
  import { createWalletProviderAdapter, resolveWalletProviderId } from "./wallet-provider-resolver.js";
8
+ import { readSignerOwnedWalletReadiness } from "./local-socket-signer-lifecycle.js";
9
+ import { normalizeNativeSignerWalletId } from "./native-signer-wallet-id.js";
8
10
  import { readWalletApprovalAuthSnapshot } from "./wallet-approval-auth.js";
9
11
 
10
12
  //#region src/wallet/wallet-status.ts
@@ -26,8 +28,12 @@ async function readWalletStatusSnapshot(params) {
26
28
  const statePaths = resolveWalletStatePaths(effectiveEnv);
27
29
  const approvalAuth = readWalletApprovalAuthSnapshot(effectiveEnv, cfg);
28
30
  const checkedAt = new Date().toISOString();
31
+ const registeredWallets = params?.walletId ? providerRegistry.wallets.filter((wallet) => wallet.id === params.walletId) : providerRegistry.wallets;
29
32
  let providerHealth = {
30
33
  ok: false,
34
+ provider: providerId,
35
+ configured: false,
36
+ checkedAt,
31
37
  details: "provider health probe unavailable"
32
38
  };
33
39
  let addresses;
@@ -53,6 +59,9 @@ async function readWalletStatusSnapshot(params) {
53
59
  } catch (err) {
54
60
  providerHealth = {
55
61
  ok: false,
62
+ provider: providerId,
63
+ configured: false,
64
+ checkedAt,
56
65
  details: walletDiagnosticErrorString(err)
57
66
  };
58
67
  }
@@ -71,6 +80,58 @@ async function readWalletStatusSnapshot(params) {
71
80
  summary: "Real-chain settlement depends on the configured wallet provider and RPC connectivity."
72
81
  },
73
82
  chains: resolved.chains,
83
+ wallets: await Promise.all(registeredWallets.map(async (wallet) => {
84
+ if (wallet.providerId !== "local-socket-signer") {
85
+ return {
86
+ id: wallet.id,
87
+ name: wallet.name,
88
+ providerId: wallet.providerId,
89
+ addresses: wallet.addresses,
90
+ readiness: {
91
+ keystore: Boolean(wallet.addresses?.solana),
92
+ rpc: serviceHealthy,
93
+ ready: serviceHealthy && Boolean(wallet.addresses?.solana)
94
+ }
95
+ };
96
+ }
97
+ const metadataSignerWalletId = typeof wallet.metadata?.signerWalletId === "string" ? wallet.metadata.signerWalletId.trim() : "";
98
+ const signerWalletId = metadataSignerWalletId || normalizeNativeSignerWalletId(wallet.id);
99
+ try {
100
+ const signer = await readSignerOwnedWalletReadiness({
101
+ socketPath: resolveLocalSignerSocketPath(effectiveEnv),
102
+ walletId: signerWalletId
103
+ });
104
+ const addressMatches = typeof wallet.addresses?.solana === "string" && wallet.addresses.solana === signer.publicKey;
105
+ const roleMatches = typeof wallet.metadata?.role === "string" && wallet.metadata.role === signer.role;
106
+ const ready = signer.ready && addressMatches && roleMatches;
107
+ return {
108
+ id: wallet.id,
109
+ name: wallet.name,
110
+ providerId: wallet.providerId,
111
+ addresses: wallet.addresses,
112
+ readiness: {
113
+ keystore: signer.keyReady,
114
+ rpc: signer.networkReady,
115
+ ready,
116
+ ...!ready && signer.ready ? { error: "registry address or immutable role does not match live signer state" } : {},
117
+ signer
118
+ }
119
+ };
120
+ } catch (error) {
121
+ return {
122
+ id: wallet.id,
123
+ name: wallet.name,
124
+ providerId: wallet.providerId,
125
+ addresses: wallet.addresses,
126
+ readiness: {
127
+ keystore: false,
128
+ rpc: false,
129
+ ready: false,
130
+ error: walletDiagnosticErrorMessage(error)
131
+ }
132
+ };
133
+ }
134
+ })),
74
135
  service: {
75
136
  host: resolved.service.host,
76
137
  port: resolved.service.port,
@@ -90,6 +151,7 @@ async function readWalletStatusSnapshot(params) {
90
151
  }
91
152
  },
92
153
  approvalAuth,
154
+ ...providerHealth.nativeSignerApproval ? { nativeSignerApproval: providerHealth.nativeSignerApproval } : {},
93
155
  addresses,
94
156
  paths: {
95
157
  rootDir: paths.rootDir,
@@ -5,8 +5,8 @@ import { loadConfig } from "../config/io.js";
5
5
  import "../config/config.js";
6
6
  import { logoutWeb, readWebSelfId, webAuthExists } from "./auth-store.js";
7
7
  import { resolveWhatsAppAccount } from "./accounts.js";
8
- import { createWaSocket, formatError, getStatusCode, waitForWaConnection } from "./session.js";
9
8
  import { renderQrPngBase64 } from "./qr-image.js";
9
+ import { createWaSocket, formatError, getStatusCode, waitForWaConnection } from "./session.js";
10
10
  import { randomUUID } from "node:crypto";
11
11
  import { DisconnectReason } from "@whiskeysockets/baileys";
12
12