@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
@@ -3,21 +3,23 @@ import { loadConfig, writeConfigFile } from "../config/io.js";
3
3
  import "../config/config.js";
4
4
  import { hasLegacyEmbeddedKeystoreConfig, hasLegacyEmbeddedKeystoreMaterialHint, throwLegacyEmbeddedKeystoreMigrationRequired } from "../wallet/legacy-embedded-keystore.js";
5
5
  import { ensureWalletStateDir, isLocalSignerExternallyManaged, resolveLocalSignerControlSocketPath, resolveLocalSignerMasterKeyPath, resolveLocalSignerSidecarPaths, resolveLocalSignerSocketPath, resolveLocalSignerStateDbPath } from "../wallet/wallet-runtime-config.js";
6
- import { normalizeWalletUserRole, readWalletProviderRegistry, resolveWalletUserRole, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, upsertNamedWallet } from "../wallet/wallet-provider-registry.js";
6
+ import { normalizeWalletUserRole, readWalletProviderRegistry, replaceRetiredMiningWallet, resolveWalletUserRole, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, upsertNamedWallet, writeWalletProviderRegistry } from "../wallet/wallet-provider-registry.js";
7
7
  import { buildWalletProviderCapabilityMatrix } from "../wallet/wallet-provider-capabilities.js";
8
8
  import { redactWalletDiagnosticText } from "../wallet/wallet-redaction.js";
9
9
  import { callLocalSocketSigner, probeLocalSocketSignerHealth, requireLocalSocketSignerPath } from "../wallet/providers/local-socket-signer-adapter.js";
10
10
  import { readWalletProviderSecretStatus, saveWalletProviderSecret } from "../wallet/wallet-secrets-store.js";
11
11
  import { createWalletProviderAdapter, resolveWalletProviderId } from "../wallet/wallet-provider-resolver.js";
12
- import { readWalletStatusSnapshot, resolveWalletConfigForRuntime } from "../wallet/wallet-status.js";
13
- import { createLockedSignerOwnedWallet } from "../wallet/local-socket-signer-lifecycle.js";
12
+ import { activateSignerOwnedRoleBaseline, createRoleReadySignerOwnedWallet, readSignerOwnedWallet, readSignerOwnedWalletReadiness } from "../wallet/local-socket-signer-lifecycle.js";
14
13
  import { normalizeNativeSignerWalletId } from "../wallet/native-signer-wallet-id.js";
14
+ import { readWalletStatusSnapshot, resolveWalletConfigForRuntime } from "../wallet/wallet-status.js";
15
+ import { buildMiningRetirementEvidence, verifyMiningRecoveryPackage, writeMiningRetirementReceipt } from "../wallet/mining-wallet-retirement.js";
15
16
  import { configureSignerOwnedWalletNetwork } from "../wallet/signer-network-admin.js";
16
17
  import { listWalletInboundEvents, pollWalletInboundEvents, reconcileWalletInboundEvents } from "../wallet/wallet-inbound-events.js";
17
18
  import { buildWalletCanaryReport, runWalletProviderCanaryReport } from "../wallet/wallet-canary.js";
18
19
  import { installSignerdBinary, resolveSignerdBinaryPath, restartLocalSocketSigner, writeLocalSignerEnvFile } from "../wizard/onboarding.wallet.js";
19
20
  import fs from "node:fs";
20
21
  import path from "node:path";
22
+ import { spawnSync } from "node:child_process";
21
23
  import { createInterface } from "node:readline/promises";
22
24
 
23
25
  //#region src/commands/wallet.ts
@@ -261,10 +263,6 @@ function rpcEnvKeyFor(chain, walletId) {
261
263
  }
262
264
  return "FASED_WALLET_SOLANA_RPC_URL";
263
265
  }
264
- function executionFallbackRpcEnvKeyFor(walletId) {
265
- const suffix = walletIdEnvSuffix(walletId);
266
- return suffix ? `FASED_WALLET_SOLANA_EXECUTION_FALLBACK_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_EXECUTION_FALLBACK_RPC_URL";
267
- }
268
266
  function resolveRpcUrlForChain(env, chain, walletId, explicit) {
269
267
  const explicitValue = explicit?.trim();
270
268
  if (explicitValue) {
@@ -381,17 +379,23 @@ async function createSignerOwnedWalletForSetup(params) {
381
379
  const walletId = params.walletId?.trim() || params.role;
382
380
  const hosted = String(params.env.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
383
381
  let cfg = ensureLocalSignerProviderConfig(loadConfig(), params.env);
384
- if (!hosted) {
385
- cfg = setConfigEnvVar(cfg, rpcEnvKeyFor(params.chain, walletId), params.rpcUrl);
386
- }
387
- await writeConfigFile(cfg);
388
382
  const mergedEnv = {
389
383
  ...params.env,
390
384
  ...cfg.env?.vars
391
385
  };
392
386
  const socketPath = resolveLocalSignerSocketPath(mergedEnv);
393
387
  const expectedSignerWalletId = normalizeNativeSignerWalletId(walletId);
394
- const existingSignerIdCollision = findNativeSignerWalletIdCollision(readWalletProviderRegistry(params.env).wallets, walletId, expectedSignerWalletId);
388
+ const registeredWallets = readWalletProviderRegistry(params.env).wallets;
389
+ if (params.role === "mining") {
390
+ const activeMiningWallet = registeredWallets.find((entry) => {
391
+ const role = normalizeWalletUserRole(entry.metadata?.role ?? entry.metadata?.purpose);
392
+ return role === "mining" || entry.id === "mining";
393
+ });
394
+ if (activeMiningWallet && activeMiningWallet.id !== walletId) {
395
+ throw new Error(`Mining already has one active wallet (${activeMiningWallet.id}). Archive it after the safety checks or complete a reviewed replacement before creating ${walletId}.`);
396
+ }
397
+ }
398
+ const existingSignerIdCollision = findNativeSignerWalletIdCollision(registeredWallets, walletId, expectedSignerWalletId);
395
399
  if (existingSignerIdCollision) {
396
400
  throw new Error(`native signer wallet ID ${expectedSignerWalletId} is already registered as ${existingSignerIdCollision.id}; choose a distinct wallet ID`);
397
401
  }
@@ -408,7 +412,14 @@ async function createSignerOwnedWalletForSetup(params) {
408
412
  }
409
413
  let result;
410
414
  try {
411
- result = await createLockedSignerOwnedWallet({
415
+ result = hosted && params.env.FASED_GATEWAY_SERVICE !== "1" ? invokeNativeSignerWalletCreate({
416
+ signerBinPath: "/opt/fased/signer/fased-signerd",
417
+ operatorSocketPath: "/run/fased-signerd/operator.sock",
418
+ walletId: expectedSignerWalletId,
419
+ role: params.role,
420
+ allowExisting: Boolean(params.options.force),
421
+ env: mergedEnv
422
+ }) : await createRoleReadySignerOwnedWallet({
412
423
  socketPath,
413
424
  walletId,
414
425
  role: params.role,
@@ -416,7 +427,7 @@ async function createSignerOwnedWalletForSetup(params) {
416
427
  });
417
428
  } catch (error) {
418
429
  if (hosted) {
419
- throw new Error(`root-managed hosted signer wallet creation failed: ${error instanceof Error ? error.message : String(error)}. Repair only from the provider root console with the exact tagged, attested Hosting release; never run the app checkout with sudo.`, { cause: error });
430
+ throw new Error(`hosted signer wallet creation failed: ${error instanceof Error ? error.message : String(error)}. Confirm the operator socket and exact installed signer release are healthy, then retry the same wallet ID.`, { cause: error });
420
431
  }
421
432
  throw error;
422
433
  }
@@ -428,16 +439,36 @@ async function createSignerOwnedWalletForSetup(params) {
428
439
  if (signerIdCollision) {
429
440
  throw new Error(`native signer wallet ID ${signerWalletId} is already registered as ${signerIdCollision.id}; choose a distinct wallet ID`);
430
441
  }
431
- const executionFallbackRpcUrl = hosted ? "" : [mergedEnv[executionFallbackRpcEnvKeyFor(walletId)], mergedEnv[walletIdEnvSuffix(walletId) ? `FASED_WALLET_SOLANA_WRITE_RPC_FALLBACK_URL__${walletIdEnvSuffix(walletId)}` : "FASED_WALLET_SOLANA_WRITE_RPC_FALLBACK_URL"]].map((value) => String(value ?? "").trim()).find(Boolean) ?? "";
432
- const network = configureSignerOwnedWalletNetwork({
442
+ const operatorLifecycle = hosted && params.env.FASED_GATEWAY_SERVICE !== "1";
443
+ const network = operatorLifecycle ? invokeNativeSignerNetworkSetPrimary({
444
+ signerBinPath: "/opt/fased/signer/fased-signerd",
445
+ socketFlag: "--operator-socket",
446
+ socketPath: "/run/fased-signerd/operator.sock",
447
+ walletId: signerWalletId,
448
+ primaryRpcUrl: params.rpcUrl,
449
+ expectedVersion: 0,
450
+ env: mergedEnv
451
+ }) : await configureSignerOwnedWalletNetwork({
433
452
  walletId: signerWalletId,
434
453
  primaryRpcUrl: params.rpcUrl,
435
- executionFallbackRpcUrl: executionFallbackRpcUrl || undefined,
436
454
  env: mergedEnv,
437
- signerBinPath: hosted ? undefined : resolveSignerdBinaryPath(mergedEnv),
438
- controlSocketPath: hosted ? undefined : resolveLocalSignerControlSocketPath(mergedEnv)
455
+ socketPath
439
456
  });
457
+ cfg = setConfigEnvVar(cfg, rpcEnvKeyFor(params.chain, walletId), params.rpcUrl);
440
458
  await writeConfigFile(cfg);
459
+ const readiness = operatorLifecycle ? invokeNativeSignerWalletReadiness({
460
+ signerBinPath: "/opt/fased/signer/fased-signerd",
461
+ socketFlag: "--operator-socket",
462
+ socketPath: "/run/fased-signerd/operator.sock",
463
+ walletId: signerWalletId,
464
+ env: mergedEnv
465
+ }) : await readSignerOwnedWalletReadiness({
466
+ socketPath,
467
+ walletId: signerWalletId
468
+ });
469
+ if (!readiness.ready || readiness.walletId !== signerWalletId || readiness.publicKey !== result.wallet.publicKey || readiness.role !== params.role || readiness.baselineVersion !== 1 || readiness.policyHash !== result.policy.hash || readiness.policyVersion !== result.policy.version || readiness.networkHash !== network.hash || readiness.networkVersion !== network.version) {
470
+ throw new Error(`Setup incomplete: signer readiness does not match the created ${params.role} wallet lifecycle`);
471
+ }
441
472
  const wallet = upsertNamedWallet({
442
473
  walletId,
443
474
  name: params.options.walletName || "Wallet",
@@ -450,18 +481,37 @@ async function createSignerOwnedWalletForSetup(params) {
450
481
  signerWalletId,
451
482
  policyHash: result.policy.hash,
452
483
  policyVersion: result.policy.version,
453
- policyState: "locked",
484
+ baselineVersion: readiness.baselineVersion,
485
+ policyState: "ready",
454
486
  networkHash: network.hash,
455
487
  networkVersion: network.version,
456
- networkReady: network.ready
488
+ networkReady: network.ready,
489
+ operationLane: readiness.operationLane,
490
+ roleReady: readiness.ready
457
491
  },
458
492
  env: params.env
459
493
  });
460
- if (params.role === "agent") {
461
- setDefaultWallet({
462
- walletId: wallet.id,
463
- env: params.env
464
- });
494
+ if (params.role === "mining") {
495
+ const currentEntry = cfg.plugins?.entries?.["sat-mining"];
496
+ const currentSatConfig = currentEntry?.config && typeof currentEntry.config === "object" && !Array.isArray(currentEntry.config) ? currentEntry.config : {};
497
+ cfg = {
498
+ ...cfg,
499
+ plugins: {
500
+ ...cfg.plugins,
501
+ entries: {
502
+ ...cfg.plugins?.entries,
503
+ "sat-mining": {
504
+ enabled: true,
505
+ ...currentEntry,
506
+ config: {
507
+ ...currentSatConfig,
508
+ walletId: wallet.id
509
+ }
510
+ }
511
+ }
512
+ }
513
+ };
514
+ await writeConfigFile(cfg);
465
515
  }
466
516
  if (params.options.json) {
467
517
  params.runtime.log(JSON.stringify({
@@ -473,24 +523,582 @@ async function createSignerOwnedWalletForSetup(params) {
473
523
  address: result.wallet.publicKey,
474
524
  policyHash: result.policy.hash,
475
525
  policyVersion: result.policy.version,
476
- policyState: "locked",
526
+ baselineVersion: readiness.baselineVersion,
527
+ policyState: "ready",
477
528
  networkVersion: network.version,
478
529
  networkReady: network.ready,
479
- ...network.rootAdminRequired ? {
480
- networkActivation: "root-admin-required",
481
- rootCommand: network.rootCommand
482
- } : {}
530
+ operationLane: readiness.operationLane,
531
+ roleReady: readiness.ready
483
532
  }, null, 2));
484
533
  } else {
485
534
  params.runtime.log(`Signer wallet ID: ${signerWalletId}`);
486
535
  params.runtime.log(`${params.chain.toUpperCase()} address: ${result.wallet.publicKey}`);
487
536
  if (!params.options.noSignerHints) {
488
- params.runtime.log("Signer-owned wallet created with a deny-all policy. Configure explicit operations, destinations, assets, and positive caps before sending.");
489
- if (network.rootAdminRequired && network.rootCommand) {
490
- params.runtime.log("Hosted wallet remains fail-closed until a root administrator activates its RPC network from a root-owned file:");
491
- params.runtime.log(network.rootCommand);
492
- }
537
+ params.runtime.log(`Role baseline active: ${params.role} v${readiness.baselineVersion} (${readiness.operationLane}).`);
538
+ }
539
+ }
540
+ return result;
541
+ }
542
+ function requireOwnerOnlySignerImportFile(rawPath) {
543
+ const importPath = path.resolve(rawPath.trim());
544
+ if (!rawPath.trim() || !path.isAbsolute(rawPath.trim()) || importPath !== rawPath.trim()) {
545
+ throw new Error("--import-file must be an absolute clean path");
546
+ }
547
+ const info = fs.lstatSync(importPath);
548
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) {
549
+ throw new Error("wallet import file must be one regular, non-symlink, single-link file");
550
+ }
551
+ if ((info.mode & 63) !== 0) {
552
+ throw new Error("wallet import file must be owner-only (chmod 600)");
553
+ }
554
+ const effectiveUid = process.geteuid?.();
555
+ if (effectiveUid !== undefined && info.uid !== effectiveUid) {
556
+ throw new Error("wallet import file must be owned by the current terminal user");
557
+ }
558
+ const fd = fs.openSync(importPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
559
+ try {
560
+ const opened = fs.fstatSync(fd);
561
+ if (!opened.isFile() || opened.nlink !== 1 || opened.dev !== info.dev || opened.ino !== info.ino || (opened.mode & 63) !== 0 || effectiveUid !== undefined && opened.uid !== effectiveUid) {
562
+ throw new Error("wallet import file changed or became unsafe before it could be read");
563
+ }
564
+ return {
565
+ path: importPath,
566
+ fd
567
+ };
568
+ } catch (error) {
569
+ fs.closeSync(fd);
570
+ throw error;
571
+ }
572
+ }
573
+ function parseNativeSignerImportResult(params) {
574
+ let value;
575
+ try {
576
+ value = JSON.parse(params.stdout.trim());
577
+ } catch {
578
+ throw new Error("native signer import returned invalid JSON");
579
+ }
580
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
581
+ throw new Error("native signer import returned an invalid result");
582
+ }
583
+ const result = value;
584
+ if (result.wallet?.walletId !== params.walletId || typeof result.wallet.publicKey !== "string" || !result.wallet.publicKey.trim() || !Number.isSafeInteger(result.wallet.version) || result.policy?.walletId !== params.walletId || result.policy.role !== params.role || result.policy.version !== 1 || result.policy.baselineVersion !== 1 || !result.policy.operations?.length || !result.policy.programs?.length || !result.policy.assets?.length || typeof result.policy.hash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(result.policy.hash)) {
585
+ throw new Error("native signer import did not return an active signer-owned role baseline");
586
+ }
587
+ return result;
588
+ }
589
+ function invokeNativeSignerWalletImport(params) {
590
+ const input = requireOwnerOnlySignerImportFile(params.importFile);
591
+ const command = params.signerBinPath;
592
+ const args = [
593
+ "admin",
594
+ "wallet",
595
+ "import",
596
+ params.hosted ? "--operator-socket" : "--control-socket",
597
+ params.controlSocketPath,
598
+ "--wallet-id",
599
+ params.walletId,
600
+ "--baseline-role",
601
+ params.role
602
+ ];
603
+ try {
604
+ const child = spawnSync(command, args, {
605
+ env: {
606
+ HOME: params.env.HOME,
607
+ LANG: params.env.LANG || "C.UTF-8",
608
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
609
+ },
610
+ stdio: [
611
+ input.fd,
612
+ "pipe",
613
+ "pipe"
614
+ ],
615
+ encoding: "utf8",
616
+ maxBuffer: 256 * 1024,
617
+ timeout: 3e4
618
+ });
619
+ if (child.error) {
620
+ throw child.error;
621
+ }
622
+ if (child.status !== 0) {
623
+ const detail = String(child.stderr || "native signer import failed").trim();
624
+ throw new Error(redactWalletDiagnosticText(detail));
625
+ }
626
+ return parseNativeSignerImportResult({
627
+ stdout: String(child.stdout ?? ""),
628
+ walletId: params.walletId,
629
+ role: params.role
630
+ });
631
+ } finally {
632
+ fs.closeSync(input.fd);
633
+ }
634
+ }
635
+ function nativeSignerLifecycleEnv(env) {
636
+ return {
637
+ HOME: env.HOME,
638
+ LANG: env.LANG || "C.UTF-8",
639
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
640
+ };
641
+ }
642
+ function invokeNativeSignerWalletCreate(params) {
643
+ const child = spawnSync(params.signerBinPath, [
644
+ "admin",
645
+ "wallet",
646
+ "create",
647
+ "--operator-socket",
648
+ params.operatorSocketPath,
649
+ "--wallet-id",
650
+ params.walletId,
651
+ "--baseline-role",
652
+ params.role,
653
+ ...params.allowExisting ? ["--allow-existing"] : []
654
+ ], {
655
+ env: nativeSignerLifecycleEnv(params.env),
656
+ stdio: [
657
+ "ignore",
658
+ "pipe",
659
+ "pipe"
660
+ ],
661
+ encoding: "utf8",
662
+ maxBuffer: 256 * 1024,
663
+ timeout: 3e4
664
+ });
665
+ if (child.error) {
666
+ throw child.error;
667
+ }
668
+ if (child.status !== 0) {
669
+ throw new Error(redactWalletDiagnosticText(String(child.stderr || "native signer create failed").trim()));
670
+ }
671
+ return parseNativeSignerImportResult({
672
+ stdout: String(child.stdout ?? ""),
673
+ walletId: params.walletId,
674
+ role: params.role
675
+ });
676
+ }
677
+ function invokeNativeSignerNetworkSetPrimary(params) {
678
+ const input = JSON.stringify({ primaryRpcUrl: params.primaryRpcUrl });
679
+ const child = spawnSync(params.signerBinPath, [
680
+ "admin",
681
+ "network",
682
+ "set-primary",
683
+ params.socketFlag,
684
+ params.socketPath,
685
+ "--wallet-id",
686
+ params.walletId,
687
+ "--expected-version",
688
+ String(params.expectedVersion)
689
+ ], {
690
+ env: nativeSignerLifecycleEnv(params.env),
691
+ input,
692
+ stdio: [
693
+ "pipe",
694
+ "pipe",
695
+ "pipe"
696
+ ],
697
+ encoding: "utf8",
698
+ maxBuffer: 256 * 1024,
699
+ timeout: 6e4
700
+ });
701
+ if (child.error) {
702
+ throw child.error;
703
+ }
704
+ if (child.status !== 0) {
705
+ throw new Error(redactWalletDiagnosticText(String(child.stderr || "native signer RPC update failed").trim()));
706
+ }
707
+ let result;
708
+ try {
709
+ result = JSON.parse(String(child.stdout ?? ""));
710
+ } catch {
711
+ throw new Error("native signer RPC update returned invalid JSON");
712
+ }
713
+ const record = result;
714
+ if (!record || record.walletId !== params.walletId || record.configured !== true || record.ready !== true || !Number.isSafeInteger(record.version) || typeof record.hash !== "string" || !/^hmac-sha256:[0-9a-f]{64}$/.test(record.hash)) {
715
+ throw new Error("native signer RPC update returned an invalid readiness summary");
716
+ }
717
+ return {
718
+ walletId: String(record.walletId),
719
+ configured: true,
720
+ ready: true,
721
+ version: Number(record.version),
722
+ hash: String(record.hash)
723
+ };
724
+ }
725
+ function invokeNativeSignerWalletReadiness(params) {
726
+ const child = spawnSync(params.signerBinPath, [
727
+ "admin",
728
+ "wallet",
729
+ "readiness",
730
+ params.socketFlag,
731
+ params.socketPath,
732
+ "--wallet-id",
733
+ params.walletId
734
+ ], {
735
+ env: nativeSignerLifecycleEnv(params.env),
736
+ stdio: [
737
+ "ignore",
738
+ "pipe",
739
+ "pipe"
740
+ ],
741
+ encoding: "utf8",
742
+ maxBuffer: 256 * 1024,
743
+ timeout: 3e4
744
+ });
745
+ if (child.error) {
746
+ throw child.error;
747
+ }
748
+ if (child.status !== 0) {
749
+ throw new Error(redactWalletDiagnosticText(String(child.stderr || "native signer readiness failed").trim()));
750
+ }
751
+ let result;
752
+ try {
753
+ result = JSON.parse(String(child.stdout ?? ""));
754
+ } catch {
755
+ throw new Error("native signer readiness returned invalid JSON");
756
+ }
757
+ const readiness = result;
758
+ if (!readiness || readiness.walletId !== params.walletId || typeof readiness.publicKey !== "string" || !Number.isSafeInteger(readiness.walletVersion) || typeof readiness.role !== "string" || !Number.isSafeInteger(readiness.policyVersion) || !Number.isSafeInteger(readiness.networkVersion) || typeof readiness.ready !== "boolean") {
759
+ throw new Error("native signer readiness returned an invalid result");
760
+ }
761
+ return readiness;
762
+ }
763
+ function invokeNativeSignerJSON(params) {
764
+ const child = spawnSync(params.signerBinPath, params.args, {
765
+ env: nativeSignerLifecycleEnv(params.env),
766
+ input: params.input,
767
+ stdio: [
768
+ params.input === undefined ? "ignore" : "pipe",
769
+ "pipe",
770
+ "pipe"
771
+ ],
772
+ encoding: "utf8",
773
+ maxBuffer: 512 * 1024,
774
+ timeout: 12e4
775
+ });
776
+ if (child.error) {
777
+ throw child.error;
778
+ }
779
+ if (child.status !== 0) {
780
+ throw new Error(redactWalletDiagnosticText(String(child.stderr || `${params.label} failed`).trim()));
781
+ }
782
+ let parsed;
783
+ try {
784
+ parsed = JSON.parse(String(child.stdout ?? ""));
785
+ } catch {
786
+ throw new Error(`${params.label} returned invalid JSON`);
787
+ }
788
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
789
+ throw new Error(`${params.label} returned an invalid result`);
790
+ }
791
+ return parsed;
792
+ }
793
+ function invokeNativeSignerBalance(params) {
794
+ const result = invokeNativeSignerJSON({
795
+ signerBinPath: params.signerBinPath,
796
+ args: [
797
+ "admin",
798
+ "wallet",
799
+ "balance",
800
+ params.socketFlag,
801
+ params.socketPath,
802
+ "--wallet-id",
803
+ params.walletId
804
+ ],
805
+ env: params.env,
806
+ label: "native signer balance lookup"
807
+ });
808
+ const balance = typeof result.balance === "string" ? result.balance : "";
809
+ if (result.address !== params.publicKey || result.chain !== "solana" || result.unit !== "lamports" || !/^\d+$/u.test(balance)) {
810
+ throw new Error("native signer balance lookup returned an invalid result");
811
+ }
812
+ return balance;
813
+ }
814
+ function parseNativeSignerRotation(value) {
815
+ if (typeof value.rotationId !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(value.rotationId) || typeof value.sourceWalletId !== "string" || typeof value.sourcePublicKey !== "string" || typeof value.successorWalletId !== "string" || typeof value.successorPublicKey !== "string" || value.state !== "prepared" && value.state !== "committed" || !Number.isSafeInteger(value.version)) {
816
+ throw new Error("native signer rotation returned an invalid result");
817
+ }
818
+ return value;
819
+ }
820
+ function invokeNativeSignerRotationCreate(params) {
821
+ return parseNativeSignerRotation(invokeNativeSignerJSON({
822
+ signerBinPath: params.signerBinPath,
823
+ args: [
824
+ "admin",
825
+ "wallet",
826
+ "rotate-successor",
827
+ params.socketFlag,
828
+ params.socketPath,
829
+ "--wallet-id",
830
+ params.sourceWalletId,
831
+ "--successor-wallet-id",
832
+ params.successorWalletId,
833
+ "--expected-source-public-key",
834
+ params.sourcePublicKey,
835
+ "--expected-source-wallet-version",
836
+ String(params.sourceWalletVersion),
837
+ "--expected-source-policy-version",
838
+ String(params.sourcePolicyVersion)
839
+ ],
840
+ env: params.env,
841
+ label: "native signer Mining successor preparation"
842
+ }));
843
+ }
844
+ function invokeNativeSignerRotationStatus(params) {
845
+ try {
846
+ return parseNativeSignerRotation(invokeNativeSignerJSON({
847
+ signerBinPath: params.signerBinPath,
848
+ args: [
849
+ "admin",
850
+ "wallet",
851
+ "rotation-status",
852
+ params.socketFlag,
853
+ params.socketPath,
854
+ "--wallet-id",
855
+ params.sourceWalletId
856
+ ],
857
+ env: params.env,
858
+ label: "native signer Mining rotation status"
859
+ }));
860
+ } catch (error) {
861
+ const message = error instanceof Error ? error.message : String(error);
862
+ if (/rotation.*not found/iu.test(message)) {
863
+ return null;
864
+ }
865
+ throw error;
866
+ }
867
+ }
868
+ function invokeNativeSignerRotationCommit(params) {
869
+ const rotation = params.rotation;
870
+ return parseNativeSignerRotation(invokeNativeSignerJSON({
871
+ signerBinPath: params.signerBinPath,
872
+ args: [
873
+ "admin",
874
+ "wallet",
875
+ "rotation-commit",
876
+ params.socketFlag,
877
+ params.socketPath,
878
+ "--wallet-id",
879
+ rotation.sourceWalletId,
880
+ "--successor-wallet-id",
881
+ rotation.successorWalletId,
882
+ "--rotation-id",
883
+ rotation.rotationId,
884
+ "--expected-source-public-key",
885
+ rotation.sourcePublicKey,
886
+ "--expected-successor-public-key",
887
+ rotation.successorPublicKey,
888
+ "--expected-source-wallet-version",
889
+ String(rotation.prepareExpectedSourceWalletVersion),
890
+ "--expected-source-policy-version",
891
+ String(rotation.prepareExpectedSourcePolicyVersion),
892
+ "--expected-successor-wallet-version",
893
+ "1",
894
+ "--expected-successor-policy-version",
895
+ "1",
896
+ "--expected-rotation-version",
897
+ "1",
898
+ "--expected-successor-network-version",
899
+ String(params.successorNetworkVersion),
900
+ "--expected-successor-network-hash",
901
+ params.successorNetworkHash
902
+ ],
903
+ input: JSON.stringify({
904
+ recoveryPackageHash: params.recoveryPackageHash,
905
+ safetyEvidence: params.safetyEvidence
906
+ }),
907
+ env: params.env,
908
+ label: "native signer Mining retirement commit"
909
+ }));
910
+ }
911
+ function invokeNativeSignerRecoveryImport(params) {
912
+ const input = requireOwnerOnlySignerImportFile(params.recoveryFile);
913
+ try {
914
+ const child = spawnSync(params.signerBinPath, [
915
+ "admin",
916
+ "wallet",
917
+ "recovery-import",
918
+ params.hosted ? "--operator-socket" : "--control-socket",
919
+ params.controlSocketPath,
920
+ "--wallet-id",
921
+ params.walletId,
922
+ "--baseline-role",
923
+ params.role,
924
+ "--recovery-file",
925
+ input.path
926
+ ], {
927
+ env: {
928
+ HOME: params.env.HOME,
929
+ LANG: params.env.LANG || "C.UTF-8",
930
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
931
+ },
932
+ stdio: [
933
+ "inherit",
934
+ "pipe",
935
+ "pipe"
936
+ ],
937
+ encoding: "utf8",
938
+ maxBuffer: 256 * 1024,
939
+ timeout: 12e4
940
+ });
941
+ if (child.error) {
942
+ throw child.error;
943
+ }
944
+ if (child.status !== 0) {
945
+ const detail = String(child.stderr || "native signer recovery import failed").trim();
946
+ throw new Error(redactWalletDiagnosticText(detail));
947
+ }
948
+ return parseNativeSignerImportResult({
949
+ stdout: String(child.stdout ?? ""),
950
+ walletId: params.walletId,
951
+ role: params.role
952
+ });
953
+ } finally {
954
+ fs.closeSync(input.fd);
955
+ }
956
+ }
957
+ async function importSignerOwnedWalletForSetup(params) {
958
+ if (params.chain !== "solana") {
959
+ throw new Error("fased-signerd protocol v2 currently supports Solana wallet import only");
960
+ }
961
+ const hosted = String(params.env.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
962
+ let cfg = ensureLocalSignerProviderConfig(loadConfig(), params.env);
963
+ const mergedEnv = {
964
+ ...params.env,
965
+ ...cfg.env?.vars
966
+ };
967
+ const socketPath = resolveLocalSignerSocketPath(mergedEnv);
968
+ const signerWalletId = normalizeNativeSignerWalletId(params.walletId);
969
+ const registeredWallets = readWalletProviderRegistry(params.env).wallets;
970
+ if (params.role === "mining" && registeredWallets.some((entry) => {
971
+ const role = normalizeWalletUserRole(entry.metadata?.role ?? entry.metadata?.purpose);
972
+ return (role === "mining" || entry.id === "mining") && entry.id !== params.walletId;
973
+ })) {
974
+ throw new Error("Mining already has one active wallet. Complete the guarded Archive/Replace flow first.");
975
+ }
976
+ const collision = findNativeSignerWalletIdCollision(registeredWallets, params.walletId, signerWalletId);
977
+ if (collision) {
978
+ throw new Error(`native signer wallet ID ${signerWalletId} is already registered as ${collision.id}; choose a distinct wallet ID`);
979
+ }
980
+ const signerBinPath = hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(mergedEnv);
981
+ const controlSocketPath = hosted ? "/run/fased-signerd/operator.sock" : resolveLocalSignerControlSocketPath(mergedEnv);
982
+ if (!hosted) {
983
+ writeLocalSignerEnvFile({
984
+ config: cfg,
985
+ env: mergedEnv
986
+ });
987
+ if (!fs.existsSync(signerBinPath)) {
988
+ installSignerdBinary(signerBinPath);
493
989
  }
990
+ await restartLocalSocketSigner(undefined, mergedEnv);
991
+ }
992
+ const result = params.options.mode === "local-signer-recovery-import" ? invokeNativeSignerRecoveryImport({
993
+ hosted,
994
+ signerBinPath,
995
+ controlSocketPath,
996
+ walletId: signerWalletId,
997
+ role: params.role,
998
+ recoveryFile: params.importFile,
999
+ env: mergedEnv
1000
+ }) : invokeNativeSignerWalletImport({
1001
+ hosted,
1002
+ signerBinPath,
1003
+ controlSocketPath,
1004
+ walletId: signerWalletId,
1005
+ role: params.role,
1006
+ importFile: params.importFile,
1007
+ env: mergedEnv
1008
+ });
1009
+ const network = hosted ? invokeNativeSignerNetworkSetPrimary({
1010
+ signerBinPath,
1011
+ socketFlag: "--operator-socket",
1012
+ socketPath: controlSocketPath,
1013
+ walletId: signerWalletId,
1014
+ primaryRpcUrl: params.rpcUrl,
1015
+ expectedVersion: 0,
1016
+ env: mergedEnv
1017
+ }) : await configureSignerOwnedWalletNetwork({
1018
+ walletId: signerWalletId,
1019
+ primaryRpcUrl: params.rpcUrl,
1020
+ env: mergedEnv,
1021
+ socketPath
1022
+ });
1023
+ cfg = setConfigEnvVar(cfg, rpcEnvKeyFor(params.chain, params.walletId), params.rpcUrl);
1024
+ await writeConfigFile(cfg);
1025
+ const readiness = hosted ? invokeNativeSignerWalletReadiness({
1026
+ signerBinPath,
1027
+ socketFlag: "--operator-socket",
1028
+ socketPath: controlSocketPath,
1029
+ walletId: signerWalletId,
1030
+ env: mergedEnv
1031
+ }) : await readSignerOwnedWalletReadiness({
1032
+ socketPath,
1033
+ walletId: signerWalletId
1034
+ });
1035
+ if (!readiness.ready || readiness.publicKey !== result.wallet.publicKey || readiness.role !== params.role || readiness.baselineVersion !== 1 || readiness.policyHash !== result.policy.hash || readiness.policyVersion !== result.policy.version || readiness.networkHash !== network.hash || readiness.networkVersion !== network.version) {
1036
+ throw new Error(`Setup incomplete: signer readiness does not match the imported ${params.role} wallet lifecycle`);
1037
+ }
1038
+ const wallet = upsertNamedWallet({
1039
+ walletId: params.walletId,
1040
+ name: params.options.walletName || "Wallet",
1041
+ providerId: "local-socket-signer",
1042
+ addresses: { solana: result.wallet.publicKey },
1043
+ metadata: {
1044
+ role: params.role,
1045
+ purpose: params.role,
1046
+ keyAuthority: "signer-owned-v2",
1047
+ signerWalletId,
1048
+ policyHash: result.policy.hash,
1049
+ policyVersion: result.policy.version,
1050
+ baselineVersion: readiness.baselineVersion,
1051
+ policyState: "ready",
1052
+ networkHash: network.hash,
1053
+ networkVersion: network.version,
1054
+ networkReady: network.ready,
1055
+ operationLane: readiness.operationLane,
1056
+ roleReady: readiness.ready
1057
+ },
1058
+ env: params.env
1059
+ });
1060
+ if (params.role === "mining") {
1061
+ const currentEntry = cfg.plugins?.entries?.["sat-mining"];
1062
+ const currentConfig = currentEntry?.config && typeof currentEntry.config === "object" && !Array.isArray(currentEntry.config) ? currentEntry.config : {};
1063
+ cfg = {
1064
+ ...cfg,
1065
+ plugins: {
1066
+ ...cfg.plugins,
1067
+ entries: {
1068
+ ...cfg.plugins?.entries,
1069
+ "sat-mining": {
1070
+ enabled: true,
1071
+ ...currentEntry,
1072
+ config: {
1073
+ ...currentConfig,
1074
+ walletId: wallet.id
1075
+ }
1076
+ }
1077
+ }
1078
+ }
1079
+ };
1080
+ await writeConfigFile(cfg);
1081
+ }
1082
+ if (params.options.json) {
1083
+ params.runtime.log(JSON.stringify({
1084
+ ok: true,
1085
+ provider: "local-socket-signer",
1086
+ imported: true,
1087
+ walletId: wallet.id,
1088
+ signerWalletId,
1089
+ role: params.role,
1090
+ address: result.wallet.publicKey,
1091
+ baselineVersion: readiness.baselineVersion,
1092
+ policyState: "ready",
1093
+ networkVersion: network.version,
1094
+ networkReady: network.ready,
1095
+ operationLane: readiness.operationLane,
1096
+ roleReady: readiness.ready
1097
+ }, null, 2));
1098
+ } else {
1099
+ params.runtime.log(`Imported ${params.role} wallet ${wallet.id} into fased-signerd.`);
1100
+ params.runtime.log(`SOLANA address: ${result.wallet.publicKey}`);
1101
+ params.runtime.log(`Readiness: ${readiness.ready ? "ready" : "setup incomplete"} (${readiness.operationLane})`);
494
1102
  }
495
1103
  return result;
496
1104
  }
@@ -591,27 +1199,32 @@ async function walletSetupCommand(runtime = defaultRuntime, options = {}) {
591
1199
  if (!mode) {
592
1200
  runtime.log("Wallet setup modes:");
593
1201
  runtime.log(" local-signer-create Create a signer-owned Solana wallet (default)");
594
- runtime.log(" local-signer-import Show the native signer-only import command");
1202
+ runtime.log(" local-signer-import Import an owner-only Solana keypair into the signer");
1203
+ runtime.log(" local-signer-recovery-import Restore an encrypted signer recovery package");
595
1204
  runtime.log(" turnkey Configure hosted provider (Turnkey)");
596
1205
  runtime.log(" alchemy Configure hosted provider (Alchemy)");
597
1206
  const picked = await prompt("Choose wallet setup mode", "local-signer-create");
598
- mode = picked === "local-signer-create" || picked === "local-signer-import" || picked === "local-signer" || picked === "turnkey" || picked === "alchemy" ? picked : "local-signer-create";
1207
+ mode = picked === "local-signer-create" || picked === "local-signer-import" || picked === "local-signer-recovery-import" || picked === "local-signer" || picked === "turnkey" || picked === "alchemy" ? picked : "local-signer-create";
599
1208
  }
600
1209
  if (mode === "embedded" || mode === "embedded-create" || mode === "embedded-import") {
601
1210
  throwLegacyEmbeddedKeystoreMigrationRequired(`wallet setup mode ${mode} is unavailable`);
602
1211
  }
603
- if (mode !== "local-signer-create" && mode !== "local-signer-import" && mode !== "local-signer" && mode !== "turnkey" && mode !== "alchemy" && mode !== "privy") {
604
- throw new Error(`Unsupported wallet setup mode: ${String(mode)}. ` + "Use one of: local-signer-create, local-signer-import, local-signer, turnkey, alchemy. Privy is unavailable.");
1212
+ if (mode !== "local-signer-create" && mode !== "local-signer-import" && mode !== "local-signer-recovery-import" && mode !== "local-signer" && mode !== "turnkey" && mode !== "alchemy" && mode !== "privy") {
1213
+ throw new Error(`Unsupported wallet setup mode: ${String(mode)}. ` + "Use one of: local-signer-create, local-signer-import, local-signer-recovery-import, local-signer, turnkey, alchemy. Privy is unavailable.");
605
1214
  }
606
1215
  if (mode === "local-signer-create") {
607
1216
  const chain = options.chain ?? "solana";
608
- const walletId = options.walletId ?? ((await prompt("Wallet id (optional, e.g. agent/mining/vault)", "")).trim() || undefined);
1217
+ const roleInput = options.role ?? (interactive ? await prompt("Wallet role (agent|mining|vault)", "") : "");
1218
+ const role = normalizeWalletUserRole(roleInput);
1219
+ if (!role) {
1220
+ throw new Error("--role is required for non-interactive wallet creation and must be agent, mining, or vault");
1221
+ }
1222
+ const walletId = options.walletId ?? ((await prompt("Wallet id", role)).trim() || role);
609
1223
  const rpcUrlFallback = resolveRpcUrlForChain(env, chain, walletId, options.rpcUrl);
610
1224
  const rpcUrl = (await prompt(`${chain.toUpperCase()} RPC URL (required for balances/readiness/send)`, rpcUrlFallback)).trim();
611
1225
  if (!rpcUrl) {
612
1226
  throw new Error(`${chain.toUpperCase()} RPC URL is required for self-hosted wallet setup. ` + "Pass --rpc-url or set FASED_WALLET_<CHAIN>_RPC_URL.");
613
1227
  }
614
- const role = normalizeWalletUserRole(options.role) ?? (walletId?.trim().toLowerCase() === "mining" ? "mining" : walletId?.trim().toLowerCase() === "vault" ? "vault" : "agent");
615
1228
  await createSignerOwnedWalletForSetup({
616
1229
  runtime,
617
1230
  options,
@@ -627,35 +1240,35 @@ async function walletSetupCommand(runtime = defaultRuntime, options = {}) {
627
1240
  await configureLimitOrdersIfRequested();
628
1241
  return;
629
1242
  }
630
- if (mode === "local-signer-import") {
631
- const walletId = normalizeNativeSignerWalletId(options.walletId ?? "agent");
632
- const role = normalizeWalletUserRole(options.role) ?? (walletId === "mining" ? "mining" : walletId === "vault" ? "vault" : "agent");
633
- const hosted = String(env.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
634
- const config = loadConfig();
635
- const effectiveEnv = {
636
- ...env,
637
- ...config.env?.vars
638
- };
639
- if (!hosted) {
640
- writeLocalSignerEnvFile({
641
- config,
642
- env: effectiveEnv
643
- });
644
- const signerBinPath = resolveSignerdBinaryPath(effectiveEnv);
645
- if (!fs.existsSync(signerBinPath)) {
646
- installSignerdBinary(signerBinPath);
647
- }
648
- await restartLocalSocketSigner(undefined, effectiveEnv);
649
- }
650
- const signerBinary = hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(effectiveEnv);
651
- const controlSocket = hosted ? "/run/fased-signerd/control.sock" : resolveLocalSignerControlSocketPath(effectiveEnv);
652
- runtime.log("Wallet import is native-signer-only; Fased Node will not read the key or passphrase.");
653
- runtime.log("Solana CLI keypair import:");
654
- runtime.log(`chmod 600 /absolute/path/to/solana-keypair.json && ${signerBinary} admin wallet import --control-socket ${controlSocket} --wallet-id ${walletId} --locked-role ${role} < /absolute/path/to/solana-keypair.json`);
655
- runtime.log("Legacy encrypted Fased keystore migration:");
656
- runtime.log(`chmod 600 /absolute/path/to/keystore-solana.v1.enc /absolute/path/to/passphrase && ${signerBinary} admin wallet import-legacy --control-socket ${controlSocket} --wallet-id ${walletId} --locked-role ${role} --keystore-path /absolute/path/to/keystore-solana.v1.enc --passphrase-path /absolute/path/to/passphrase`);
657
- runtime.log(`After verifying the returned public address, run: fased wallet finalize-legacy-migration --wallet-id ${options.walletId ?? walletId}`);
658
- runtime.log("Never put a private key or passphrase in the dashboard, Gateway, chat, argv, or an environment variable.");
1243
+ if (mode === "local-signer-import" || mode === "local-signer-recovery-import") {
1244
+ const roleInput = options.role ?? (interactive ? await prompt("Wallet role (agent|mining|vault)", "") : "");
1245
+ const role = normalizeWalletUserRole(roleInput);
1246
+ if (!role) {
1247
+ throw new Error("--role is required for non-interactive wallet import and must be agent, mining, or vault");
1248
+ }
1249
+ const friendlyWalletId = options.walletId ?? (interactive ? await prompt("Wallet id", role) : role);
1250
+ const walletId = friendlyWalletId.trim() || role;
1251
+ const recoveryImport = mode === "local-signer-recovery-import";
1252
+ const importFile = ((recoveryImport ? options.recoveryFile : options.importFile) ?? (interactive ? await prompt(recoveryImport ? "Absolute path to owner-only encrypted recovery package" : "Absolute path to owner-only Solana keypair JSON", "") : "")).trim();
1253
+ if (!importFile) {
1254
+ throw new Error(recoveryImport ? "--recovery-file is required for non-interactive native recovery import" : "--import-file is required for non-interactive native wallet import");
1255
+ }
1256
+ const chain = options.chain ?? "solana";
1257
+ const rpcUrlFallback = resolveRpcUrlForChain(env, chain, walletId, options.rpcUrl);
1258
+ const rpcUrl = (await prompt(`${chain.toUpperCase()} RPC URL (one primary execution RPC)`, rpcUrlFallback)).trim();
1259
+ if (!rpcUrl) {
1260
+ throw new Error("--rpc-url is required for non-interactive native wallet import");
1261
+ }
1262
+ await importSignerOwnedWalletForSetup({
1263
+ runtime,
1264
+ options,
1265
+ env,
1266
+ chain,
1267
+ walletId,
1268
+ rpcUrl,
1269
+ role,
1270
+ importFile
1271
+ });
659
1272
  return;
660
1273
  }
661
1274
  if (mode === "local-signer") {
@@ -743,6 +1356,465 @@ async function walletSetupCommand(runtime = defaultRuntime, options = {}) {
743
1356
  return;
744
1357
  }
745
1358
  }
1359
+ async function walletRpcSetCommand(runtime = defaultRuntime, options) {
1360
+ const walletId = options.walletId.trim();
1361
+ const rpcUrl = options.rpcUrl.trim();
1362
+ if (!walletId) {
1363
+ throw new Error("--wallet-id is required");
1364
+ }
1365
+ if (!rpcUrl) {
1366
+ throw new Error("--rpc-url is required");
1367
+ }
1368
+ const cfg = loadConfig();
1369
+ const effectiveEnv = {
1370
+ ...process.env,
1371
+ ...cfg.env?.vars
1372
+ };
1373
+ const registry = readWalletProviderRegistry(effectiveEnv);
1374
+ const wallet = registry.wallets.find((entry) => entry.id === walletId);
1375
+ if (!wallet || wallet.providerId !== "local-socket-signer") {
1376
+ throw new Error(`native signer wallet not found: ${walletId}`);
1377
+ }
1378
+ const signerWalletId = typeof wallet.metadata?.signerWalletId === "string" && wallet.metadata.signerWalletId.trim() ? wallet.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(wallet.id);
1379
+ const hosted = String(effectiveEnv.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
1380
+ const signerBinPath = hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(effectiveEnv);
1381
+ const socketFlag = hosted ? "--operator-socket" : "--control-socket";
1382
+ const socketPath = hosted ? "/run/fased-signerd/operator.sock" : resolveLocalSignerControlSocketPath(effectiveEnv);
1383
+ const current = hosted ? invokeNativeSignerWalletReadiness({
1384
+ signerBinPath,
1385
+ socketFlag,
1386
+ socketPath,
1387
+ walletId: signerWalletId,
1388
+ env: effectiveEnv
1389
+ }) : await readSignerOwnedWalletReadiness({
1390
+ socketPath: resolveLocalSignerSocketPath(effectiveEnv),
1391
+ walletId: signerWalletId
1392
+ });
1393
+ const network = invokeNativeSignerNetworkSetPrimary({
1394
+ signerBinPath,
1395
+ socketFlag,
1396
+ socketPath,
1397
+ walletId: signerWalletId,
1398
+ primaryRpcUrl: rpcUrl,
1399
+ expectedVersion: current.networkVersion,
1400
+ env: effectiveEnv
1401
+ });
1402
+ const nextConfig = setConfigEnvVar(cfg, rpcEnvKeyFor("solana", walletId), rpcUrl);
1403
+ await writeConfigFile(nextConfig);
1404
+ registry.wallets = registry.wallets.map((entry) => entry.id === wallet.id ? {
1405
+ ...entry,
1406
+ metadata: {
1407
+ ...entry.metadata,
1408
+ networkHash: network.hash,
1409
+ networkVersion: network.version,
1410
+ networkReady: network.ready
1411
+ },
1412
+ updatedAt: new Date().toISOString()
1413
+ } : entry);
1414
+ writeWalletProviderRegistry(registry, effectiveEnv);
1415
+ if (options.json) {
1416
+ runtime.log(JSON.stringify({
1417
+ ok: true,
1418
+ network
1419
+ }, null, 2));
1420
+ return;
1421
+ }
1422
+ runtime.log(`Primary Solana RPC verified for ${wallet.name} (${wallet.id}); signer network v${network.version} is ready.`);
1423
+ }
1424
+ async function walletRecoveryExportCommand(runtime = defaultRuntime, options) {
1425
+ const walletId = options.walletId.trim();
1426
+ const output = options.output.trim();
1427
+ if (!walletId) {
1428
+ throw new Error("--wallet-id is required");
1429
+ }
1430
+ if (!output || !path.isAbsolute(output) || path.resolve(output) !== output) {
1431
+ throw new Error("--output must be an absolute clean path for a new recovery file");
1432
+ }
1433
+ const cfg = loadConfig();
1434
+ const effectiveEnv = {
1435
+ ...process.env,
1436
+ ...cfg.env?.vars
1437
+ };
1438
+ const wallet = readWalletProviderRegistry(effectiveEnv).wallets.find((entry) => entry.id === walletId);
1439
+ if (!wallet || wallet.providerId !== "local-socket-signer") {
1440
+ throw new Error(`native signer wallet not found: ${walletId}`);
1441
+ }
1442
+ const publicKey = wallet.addresses?.solana?.trim() || "";
1443
+ if (!publicKey) {
1444
+ throw new Error(`native signer wallet ${walletId} has no verified Solana public address`);
1445
+ }
1446
+ const hosted = String(effectiveEnv.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
1447
+ const signerWalletId = typeof wallet.metadata?.signerWalletId === "string" && wallet.metadata.signerWalletId.trim() ? wallet.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(wallet.id);
1448
+ const signerBinPath = hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(effectiveEnv);
1449
+ const controlSocketPath = hosted ? "/run/fased-signerd/operator.sock" : resolveLocalSignerControlSocketPath(effectiveEnv);
1450
+ runtime.log(`Creating encrypted recovery package for ${wallet.id}. The signer will ask for and confirm the recovery password without echoing it.`);
1451
+ const child = spawnSync(signerBinPath, [
1452
+ "admin",
1453
+ "wallet",
1454
+ "recovery-export",
1455
+ hosted ? "--operator-socket" : "--control-socket",
1456
+ controlSocketPath,
1457
+ "--wallet-id",
1458
+ signerWalletId,
1459
+ "--expected-public-key",
1460
+ publicKey,
1461
+ "--output",
1462
+ output
1463
+ ], {
1464
+ env: {
1465
+ HOME: effectiveEnv.HOME,
1466
+ LANG: effectiveEnv.LANG || "C.UTF-8",
1467
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
1468
+ },
1469
+ stdio: "inherit",
1470
+ timeout: 12e4
1471
+ });
1472
+ if (child.error) {
1473
+ throw child.error;
1474
+ }
1475
+ if (child.status !== 0) {
1476
+ throw new Error(`encrypted recovery export failed with exit code ${child.status ?? "unknown"}`);
1477
+ }
1478
+ runtime.log(`Encrypted recovery package written: ${output} (owner-only)`);
1479
+ runtime.log(`Wallet: ${wallet.id} · Role: ${resolveWalletUserRole(wallet)} · Address: ${publicKey}`);
1480
+ }
1481
+ async function walletRecoveryImportCommand(runtime = defaultRuntime, options) {
1482
+ await walletSetupCommand(runtime, {
1483
+ mode: "local-signer-recovery-import",
1484
+ chain: "solana",
1485
+ walletId: options.walletId,
1486
+ walletName: options.walletName,
1487
+ role: options.role,
1488
+ recoveryFile: options.recoveryFile,
1489
+ rpcUrl: options.rpcUrl,
1490
+ nonInteractive: true,
1491
+ noDoctor: true,
1492
+ noSignerHints: true
1493
+ });
1494
+ }
1495
+ async function walletRetireCommand(runtime = defaultRuntime, options) {
1496
+ const walletId = options.walletId.trim();
1497
+ const successorWalletId = options.successorWalletId.trim();
1498
+ const successorWalletName = options.successorWalletName.trim();
1499
+ const rpcUrl = options.rpcUrl.trim();
1500
+ if (!walletId || !successorWalletId || !successorWalletName || !rpcUrl) {
1501
+ throw new Error("--wallet-id, --successor-wallet-id, --successor-wallet-name, and --rpc-url are required");
1502
+ }
1503
+ if (walletId === successorWalletId) {
1504
+ throw new Error("Mining successor wallet id must differ from the retired wallet id");
1505
+ }
1506
+ if (!/^[a-zA-Z0-9_-]+$/u.test(successorWalletId)) {
1507
+ throw new Error("--successor-wallet-id must contain only letters, numbers, hyphens, or underscores");
1508
+ }
1509
+ const cfg = loadConfig();
1510
+ const effectiveEnv = {
1511
+ ...process.env,
1512
+ ...cfg.env?.vars
1513
+ };
1514
+ const registry = readWalletProviderRegistry(effectiveEnv);
1515
+ const source = registry.wallets.find((entry) => entry.id === walletId);
1516
+ if (!source || source.providerId !== "local-socket-signer" || resolveWalletUserRole(source) !== "mining") {
1517
+ throw new Error(`active signer-owned Mining wallet not found: ${walletId}`);
1518
+ }
1519
+ const configuredMiningWalletId = resolveConfiguredMiningWalletId(cfg);
1520
+ if (configuredMiningWalletId !== walletId && configuredMiningWalletId !== successorWalletId) {
1521
+ throw new Error(`${walletId} is not the active singleton Mining wallet`);
1522
+ }
1523
+ if (registry.wallets.some((entry) => entry.id === successorWalletId)) {
1524
+ throw new Error(`successor wallet id is already registered: ${successorWalletId}`);
1525
+ }
1526
+ const sourcePublicKey = source.addresses?.solana?.trim() ?? "";
1527
+ if (!sourcePublicKey) {
1528
+ throw new Error("source Mining wallet has no verified Solana address");
1529
+ }
1530
+ const sourceSignerWalletId = typeof source.metadata?.signerWalletId === "string" && source.metadata.signerWalletId.trim() ? source.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(source.id);
1531
+ const successorSignerWalletId = normalizeNativeSignerWalletId(successorWalletId);
1532
+ if (sourceSignerWalletId === successorSignerWalletId) {
1533
+ throw new Error("Mining successor signer wallet id must be distinct");
1534
+ }
1535
+ const recovery = verifyMiningRecoveryPackage({
1536
+ recoveryFile: options.recoveryFile,
1537
+ walletId: sourceSignerWalletId,
1538
+ publicKey: sourcePublicKey
1539
+ });
1540
+ const hosted = String(effectiveEnv.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
1541
+ const signerBinPath = hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(effectiveEnv);
1542
+ const socketFlag = hosted ? "--operator-socket" : "--control-socket";
1543
+ const socketPath = hosted ? "/run/fased-signerd/operator.sock" : resolveLocalSignerControlSocketPath(effectiveEnv);
1544
+ let rotation = invokeNativeSignerRotationStatus({
1545
+ signerBinPath,
1546
+ socketFlag,
1547
+ socketPath,
1548
+ sourceWalletId: sourceSignerWalletId,
1549
+ env: effectiveEnv
1550
+ });
1551
+ if (rotation && rotation.successorWalletId !== successorSignerWalletId) {
1552
+ throw new Error(`source wallet is already bound to immutable successor ${rotation.successorWalletId}`);
1553
+ }
1554
+ if (!rotation && configuredMiningWalletId !== walletId) {
1555
+ throw new Error("Mining configuration changed before the signer prepared a successor");
1556
+ }
1557
+ let evidence;
1558
+ if (!rotation || rotation.state !== "committed") {
1559
+ const sourceReadiness = invokeNativeSignerWalletReadiness({
1560
+ signerBinPath,
1561
+ socketFlag,
1562
+ socketPath,
1563
+ walletId: sourceSignerWalletId,
1564
+ env: effectiveEnv
1565
+ });
1566
+ if (sourceReadiness.publicKey !== sourcePublicKey || sourceReadiness.role !== "mining" || !sourceReadiness.keyReady || !sourceReadiness.policyReady || !sourceReadiness.networkReady) {
1567
+ throw new Error("source Mining wallet is not live and role-ready in the signer");
1568
+ }
1569
+ const signerSOL = invokeNativeSignerBalance({
1570
+ signerBinPath,
1571
+ socketFlag,
1572
+ socketPath,
1573
+ walletId: sourceSignerWalletId,
1574
+ publicKey: sourcePublicKey,
1575
+ env: effectiveEnv
1576
+ });
1577
+ evidence = buildMiningRetirementEvidence({
1578
+ walletId,
1579
+ signerWalletId: sourceSignerWalletId,
1580
+ publicKey: sourcePublicKey,
1581
+ signerSolBalanceLamports: signerSOL,
1582
+ liveStatus: options.liveMiningStatus,
1583
+ env: effectiveEnv
1584
+ });
1585
+ rotation ??= invokeNativeSignerRotationCreate({
1586
+ signerBinPath,
1587
+ socketFlag,
1588
+ socketPath,
1589
+ sourceWalletId: sourceSignerWalletId,
1590
+ successorWalletId: successorSignerWalletId,
1591
+ sourcePublicKey,
1592
+ sourceWalletVersion: Number(sourceReadiness.walletVersion),
1593
+ sourcePolicyVersion: sourceReadiness.policyVersion,
1594
+ env: effectiveEnv
1595
+ });
1596
+ if (rotation.role !== "mining" || rotation.sourcePublicKey !== sourcePublicKey || rotation.successorPublicKey === sourcePublicKey) {
1597
+ throw new Error("signer prepared an invalid Mining successor binding");
1598
+ }
1599
+ let successorReadiness = invokeNativeSignerWalletReadiness({
1600
+ signerBinPath,
1601
+ socketFlag,
1602
+ socketPath,
1603
+ walletId: successorSignerWalletId,
1604
+ env: effectiveEnv
1605
+ });
1606
+ let successorNetwork = {
1607
+ version: successorReadiness.networkVersion,
1608
+ hash: successorReadiness.networkHash ?? "",
1609
+ ready: successorReadiness.networkReady
1610
+ };
1611
+ if (successorNetwork.version === 0) {
1612
+ successorNetwork = invokeNativeSignerNetworkSetPrimary({
1613
+ signerBinPath,
1614
+ socketFlag,
1615
+ socketPath,
1616
+ walletId: successorSignerWalletId,
1617
+ primaryRpcUrl: rpcUrl,
1618
+ expectedVersion: 0,
1619
+ env: effectiveEnv
1620
+ });
1621
+ }
1622
+ if (!successorNetwork.ready || !successorNetwork.hash) {
1623
+ throw new Error("Mining successor RPC is not verified and ready");
1624
+ }
1625
+ rotation = invokeNativeSignerRotationCommit({
1626
+ signerBinPath,
1627
+ socketFlag,
1628
+ socketPath,
1629
+ rotation,
1630
+ successorNetworkVersion: successorNetwork.version,
1631
+ successorNetworkHash: successorNetwork.hash,
1632
+ recoveryPackageHash: recovery.packageHash,
1633
+ safetyEvidence: evidence,
1634
+ env: effectiveEnv
1635
+ });
1636
+ successorReadiness = invokeNativeSignerWalletReadiness({
1637
+ signerBinPath,
1638
+ socketFlag,
1639
+ socketPath,
1640
+ walletId: successorSignerWalletId,
1641
+ env: effectiveEnv
1642
+ });
1643
+ if (rotation.state !== "committed" || successorReadiness.publicKey !== rotation.successorPublicKey || successorReadiness.role !== "mining" || successorReadiness.operationLane !== "mining-typed-sat" || !successorReadiness.ready || successorReadiness.policyHash !== rotation.successorActivatedPolicyHash) {
1644
+ throw new Error("Mining successor did not become authoritatively role-ready after retirement");
1645
+ }
1646
+ }
1647
+ if (rotation.state !== "committed" || rotation.recoveryPackageHash !== recovery.packageHash || !rotation.sourceRetiredPolicyHash || !rotation.successorActivatedPolicyHash || !rotation.safetyEvidenceHash) {
1648
+ throw new Error("signer retirement acknowledgement is incomplete");
1649
+ }
1650
+ const successorReadiness = invokeNativeSignerWalletReadiness({
1651
+ signerBinPath,
1652
+ socketFlag,
1653
+ socketPath,
1654
+ walletId: successorSignerWalletId,
1655
+ env: effectiveEnv
1656
+ });
1657
+ if (successorReadiness.publicKey !== rotation.successorPublicKey || successorReadiness.role !== "mining" || !successorReadiness.ready) {
1658
+ throw new Error("committed Mining successor is not live and ready");
1659
+ }
1660
+ const receipt = {
1661
+ version: 1,
1662
+ kind: "fased-mining-wallet-retirement",
1663
+ rotationId: rotation.rotationId,
1664
+ committedAt: rotation.committedAt,
1665
+ sourceWalletId: walletId,
1666
+ sourceSignerWalletId,
1667
+ sourcePublicKey,
1668
+ sourceRetiredPolicyVersion: rotation.sourceRetiredPolicyVersion,
1669
+ sourceRetiredPolicyHash: rotation.sourceRetiredPolicyHash,
1670
+ successorWalletId,
1671
+ successorSignerWalletId,
1672
+ successorPublicKey: rotation.successorPublicKey,
1673
+ successorPolicyVersion: successorReadiness.policyVersion,
1674
+ successorPolicyHash: successorReadiness.policyHash,
1675
+ successorNetworkVersion: successorReadiness.networkVersion,
1676
+ successorNetworkHash: successorReadiness.networkHash,
1677
+ recoveryPackageHash: rotation.recoveryPackageHash,
1678
+ safetyEvidenceHash: rotation.safetyEvidenceHash,
1679
+ balances: evidence ?? rotation.safetyEvidence ? {
1680
+ solBalanceLamports: (evidence ?? rotation.safetyEvidence).solBalanceLamports,
1681
+ satBalanceRaw: (evidence ?? rotation.safetyEvidence).satBalanceRaw
1682
+ } : undefined
1683
+ };
1684
+ const receiptPath = writeMiningRetirementReceipt({
1685
+ sourceWalletId: walletId,
1686
+ receipt,
1687
+ env: effectiveEnv
1688
+ });
1689
+ const currentEntry = cfg.plugins?.entries?.["sat-mining"];
1690
+ const currentPluginConfig = currentEntry?.config && typeof currentEntry.config === "object" && !Array.isArray(currentEntry.config) ? currentEntry.config : {};
1691
+ await writeConfigFile({
1692
+ ...cfg,
1693
+ plugins: {
1694
+ ...cfg.plugins,
1695
+ entries: {
1696
+ ...cfg.plugins?.entries,
1697
+ "sat-mining": {
1698
+ ...currentEntry,
1699
+ enabled: true,
1700
+ config: {
1701
+ ...currentPluginConfig,
1702
+ walletId: successorWalletId
1703
+ }
1704
+ }
1705
+ }
1706
+ }
1707
+ });
1708
+ replaceRetiredMiningWallet({
1709
+ sourceWalletId: walletId,
1710
+ signerAcknowledgement: {
1711
+ rotationId: rotation.rotationId,
1712
+ sourceRetiredPolicyHash: String(rotation.sourceRetiredPolicyHash),
1713
+ successorPublicKey: rotation.successorPublicKey,
1714
+ successorPolicyHash: successorReadiness.policyHash
1715
+ },
1716
+ successor: {
1717
+ id: successorWalletId,
1718
+ name: successorWalletName,
1719
+ providerId: "local-socket-signer",
1720
+ addresses: { solana: rotation.successorPublicKey },
1721
+ metadata: {
1722
+ role: "mining",
1723
+ purpose: "mining",
1724
+ keyAuthority: "signer-owned-v2",
1725
+ signerWalletId: successorSignerWalletId,
1726
+ policyHash: successorReadiness.policyHash,
1727
+ policyVersion: successorReadiness.policyVersion,
1728
+ baselineVersion: successorReadiness.baselineVersion,
1729
+ policyState: "ready",
1730
+ networkHash: successorReadiness.networkHash,
1731
+ networkVersion: successorReadiness.networkVersion,
1732
+ networkReady: true,
1733
+ operationLane: successorReadiness.operationLane,
1734
+ roleReady: true,
1735
+ predecessorWalletId: walletId,
1736
+ rotationId: rotation.rotationId
1737
+ }
1738
+ },
1739
+ env: effectiveEnv
1740
+ });
1741
+ const result = {
1742
+ ok: true,
1743
+ retiredWalletId: walletId,
1744
+ retiredAddress: sourcePublicKey,
1745
+ successorWalletId,
1746
+ successorAddress: rotation.successorPublicKey,
1747
+ rotationId: rotation.rotationId,
1748
+ receiptPath
1749
+ };
1750
+ if (options.json) {
1751
+ runtime.log(JSON.stringify(result, null, 2));
1752
+ } else {
1753
+ runtime.log(`Retired Mining wallet ${walletId} (${sourcePublicKey}).`);
1754
+ runtime.log(`Active Mining successor: ${successorWalletId} (${rotation.successorPublicKey}).`);
1755
+ runtime.log(`Audit receipt: ${receiptPath}`);
1756
+ }
1757
+ return result;
1758
+ }
1759
+ async function walletRawExportCommand(runtime = defaultRuntime, options) {
1760
+ const walletId = options.walletId.trim();
1761
+ const output = options.output.trim();
1762
+ if (!walletId) {
1763
+ throw new Error("--wallet-id is required");
1764
+ }
1765
+ if (!options.acknowledgeCustodyReduction) {
1766
+ throw new Error("--acknowledge-custody-reduction is required for raw private-key export");
1767
+ }
1768
+ if (!output || !path.isAbsolute(output) || path.resolve(output) !== output) {
1769
+ throw new Error("--output must be an absolute clean path for a new owner-only keypair file");
1770
+ }
1771
+ const cfg = loadConfig();
1772
+ const effectiveEnv = {
1773
+ ...process.env,
1774
+ ...cfg.env?.vars
1775
+ };
1776
+ const wallet = readWalletProviderRegistry(effectiveEnv).wallets.find((entry) => entry.id === walletId);
1777
+ if (!wallet || wallet.providerId !== "local-socket-signer") {
1778
+ throw new Error(`native signer wallet not found: ${walletId}`);
1779
+ }
1780
+ const publicKey = wallet.addresses?.solana?.trim() || "";
1781
+ if (!publicKey) {
1782
+ throw new Error(`native signer wallet ${walletId} has no verified Solana public address`);
1783
+ }
1784
+ const hosted = String(effectiveEnv.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
1785
+ const signerWalletId = typeof wallet.metadata?.signerWalletId === "string" && wallet.metadata.signerWalletId.trim() ? wallet.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(wallet.id);
1786
+ runtime.log("WARNING: raw private-key export reduces signer custody protection.");
1787
+ const child = spawnSync(hosted ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath(effectiveEnv), [
1788
+ "admin",
1789
+ "wallet",
1790
+ "export-raw",
1791
+ hosted ? "--operator-socket" : "--control-socket",
1792
+ hosted ? "/run/fased-signerd/operator.sock" : resolveLocalSignerControlSocketPath(effectiveEnv),
1793
+ "--wallet-id",
1794
+ signerWalletId,
1795
+ "--expected-public-key",
1796
+ publicKey,
1797
+ "--output",
1798
+ output,
1799
+ "--acknowledge-custody-reduction"
1800
+ ], {
1801
+ env: {
1802
+ HOME: effectiveEnv.HOME,
1803
+ LANG: effectiveEnv.LANG || "C.UTF-8",
1804
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
1805
+ },
1806
+ stdio: "inherit",
1807
+ timeout: 12e4
1808
+ });
1809
+ if (child.error) {
1810
+ throw child.error;
1811
+ }
1812
+ if (child.status !== 0) {
1813
+ throw new Error(`raw private-key export failed with exit code ${child.status ?? "unknown"}`);
1814
+ }
1815
+ runtime.log(`Raw private key written: ${output} (owner-only)`);
1816
+ runtime.log(`Wallet: ${wallet.id} · Address: ${publicKey}`);
1817
+ }
746
1818
  async function walletRoleSetCommand(runtime = defaultRuntime, options) {
747
1819
  const walletId = options.walletId.trim();
748
1820
  const role = normalizeWalletRoleForCli(options.role);
@@ -790,10 +1862,56 @@ async function walletRoleSetCommand(runtime = defaultRuntime, options) {
790
1862
  }, null, 2));
791
1863
  return;
792
1864
  }
793
- runtime.log(`${wallet?.name ?? walletId} (${walletId}) set to ${role === "agent" ? "Agent wallet" : "Vault wallet"}${primary ? " and primary Agent fallback" : ""}.`);
1865
+ runtime.log(`${wallet?.name ?? walletId} (${walletId}) set to ${role === "agent" ? "Agent wallet" : "Vault wallet"}${primary ? " and Default Agent wallet fallback" : ""}.`);
794
1866
  }
795
1867
  async function walletStatusCommand(runtime = defaultRuntime, options = {}) {
796
- const status = await readWalletStatusSnapshot();
1868
+ const config = loadConfig();
1869
+ const effectiveEnv = {
1870
+ ...process.env,
1871
+ ...config.env?.vars
1872
+ };
1873
+ const hostedOperator = String(effectiveEnv.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting" && effectiveEnv.FASED_GATEWAY_SERVICE !== "1";
1874
+ if (hostedOperator) {
1875
+ const registered = readWalletProviderRegistry(effectiveEnv).wallets.filter((wallet) => wallet.providerId === "local-socket-signer" && (!options.walletId || wallet.id === options.walletId));
1876
+ if (options.walletId && registered.length === 0) {
1877
+ throw new Error(`native signer wallet not found: ${options.walletId}`);
1878
+ }
1879
+ const wallets = registered.map((wallet) => {
1880
+ const signerWalletId = typeof wallet.metadata?.signerWalletId === "string" && wallet.metadata.signerWalletId.trim() ? wallet.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(wallet.id);
1881
+ return {
1882
+ id: wallet.id,
1883
+ name: wallet.name,
1884
+ signer: invokeNativeSignerWalletReadiness({
1885
+ signerBinPath: "/opt/fased/signer/fased-signerd",
1886
+ socketFlag: "--operator-socket",
1887
+ socketPath: "/run/fased-signerd/operator.sock",
1888
+ walletId: signerWalletId,
1889
+ env: effectiveEnv
1890
+ })
1891
+ };
1892
+ });
1893
+ if (options.json) {
1894
+ runtime.log(JSON.stringify({
1895
+ ok: true,
1896
+ status: {
1897
+ mode: "hosting-operator",
1898
+ wallets
1899
+ }
1900
+ }, null, 2));
1901
+ return;
1902
+ }
1903
+ if (wallets.length === 0) {
1904
+ runtime.log("No signer-owned wallets are registered.");
1905
+ return;
1906
+ }
1907
+ for (const wallet of wallets) {
1908
+ runtime.log(`Wallet ${wallet.name} (${wallet.id}): ${wallet.signer.ready ? "ready" : "setup incomplete"}`);
1909
+ runtime.log(` signer=${wallet.signer.walletId} role=${wallet.signer.role} lane=${wallet.signer.operationLane} baseline=v${wallet.signer.baselineVersion}`);
1910
+ runtime.log(` key=${String(wallet.signer.keyReady)} policy=v${wallet.signer.policyVersion} ${wallet.signer.policyHash} network=v${wallet.signer.networkVersion} ${wallet.signer.networkHash ?? "unconfigured"}`);
1911
+ }
1912
+ return;
1913
+ }
1914
+ const status = await readWalletStatusSnapshot({ walletId: options.walletId });
797
1915
  if (options.json) {
798
1916
  runtime.log(JSON.stringify({
799
1917
  ok: true,
@@ -821,10 +1939,104 @@ async function walletStatusCommand(runtime = defaultRuntime, options = {}) {
821
1939
  if (status.addresses?.solana) {
822
1940
  runtime.log(`Address: ${status.addresses.solana}`);
823
1941
  }
1942
+ for (const wallet of status.wallets ?? []) {
1943
+ const signer = wallet.readiness.signer;
1944
+ runtime.log(`Wallet ${wallet.name} (${wallet.id}): ${wallet.readiness.ready ? "ready" : "setup incomplete"}`);
1945
+ if (signer) {
1946
+ runtime.log(` signer=${signer.walletId} role=${signer.role} lane=${signer.operationLane} baseline=v${signer.baselineVersion}`);
1947
+ runtime.log(` key=${String(signer.keyReady)} policy=v${signer.policyVersion} ${signer.policyHash} network=v${signer.networkVersion} ${signer.networkHash ?? "unconfigured"}`);
1948
+ }
1949
+ if (wallet.readiness.error) {
1950
+ runtime.log(` warning=${wallet.readiness.error}`);
1951
+ }
1952
+ }
824
1953
  if (status.error) {
825
1954
  runtime.log(`Status warning: ${status.error}`);
826
1955
  }
827
1956
  }
1957
+ async function walletPolicyActivateRoleBaselineCommand(runtime = defaultRuntime, options) {
1958
+ if (!options.confirm) {
1959
+ throw new Error("Activate role baseline requires --confirm after reviewing the selected role");
1960
+ }
1961
+ const role = normalizeWalletUserRole(options.role);
1962
+ if (!role) {
1963
+ throw new Error("role must be one of: agent, mining, vault");
1964
+ }
1965
+ const registry = readWalletProviderRegistry(process.env);
1966
+ const wallet = registry.wallets.find((entry) => entry.id === options.walletId.trim());
1967
+ if (!wallet || wallet.providerId !== "local-socket-signer") {
1968
+ throw new Error(`registered signer-owned wallet was not found: ${options.walletId}`);
1969
+ }
1970
+ const registeredRole = resolveWalletUserRole(wallet);
1971
+ if (registeredRole && registeredRole !== role) {
1972
+ throw new Error(`wallet ${wallet.id} has immutable role=${registeredRole}; refusing requested role=${role}`);
1973
+ }
1974
+ const signerWalletId = typeof wallet.metadata?.signerWalletId === "string" && wallet.metadata.signerWalletId.trim() ? wallet.metadata.signerWalletId.trim() : normalizeNativeSignerWalletId(wallet.id);
1975
+ const socketPath = requireLocalSocketSignerPath(process.env);
1976
+ const current = await readSignerOwnedWallet({
1977
+ socketPath,
1978
+ walletId: signerWalletId
1979
+ });
1980
+ if (current.wallet.publicKey !== wallet.addresses?.solana) {
1981
+ throw new Error("registered wallet address does not match the signer-owned wallet");
1982
+ }
1983
+ if (current.policy.role !== role) {
1984
+ throw new Error(`signer-owned wallet ${signerWalletId} has immutable role=${current.policy.role}, not ${role}`);
1985
+ }
1986
+ let policy = current.policy;
1987
+ if (policy.baselineVersion === undefined || policy.baselineVersion === 0) {
1988
+ policy = await activateSignerOwnedRoleBaseline({
1989
+ socketPath,
1990
+ walletId: signerWalletId,
1991
+ role,
1992
+ expectedPolicyVersion: policy.version
1993
+ });
1994
+ } else if (policy.baselineVersion !== 1) {
1995
+ throw new Error(`signer-owned wallet ${signerWalletId} uses unsupported baseline version ${policy.baselineVersion}`);
1996
+ }
1997
+ const readiness = await readSignerOwnedWalletReadiness({
1998
+ socketPath,
1999
+ walletId: signerWalletId
2000
+ });
2001
+ if (readiness.publicKey !== current.wallet.publicKey || readiness.role !== role || readiness.policyHash !== policy.hash || readiness.policyVersion !== policy.version || readiness.baselineVersion !== 1) {
2002
+ throw new Error("Setup incomplete: activated role baseline does not match live signer state");
2003
+ }
2004
+ upsertNamedWallet({
2005
+ walletId: wallet.id,
2006
+ name: wallet.name,
2007
+ providerId: wallet.providerId,
2008
+ addresses: wallet.addresses,
2009
+ metadata: {
2010
+ ...wallet.metadata,
2011
+ role,
2012
+ purpose: role,
2013
+ signerWalletId,
2014
+ policyHash: readiness.policyHash,
2015
+ policyVersion: readiness.policyVersion,
2016
+ baselineVersion: readiness.baselineVersion,
2017
+ policyState: readiness.policyReady ? "ready" : "setup-incomplete",
2018
+ networkHash: readiness.networkHash,
2019
+ networkVersion: readiness.networkVersion,
2020
+ networkReady: readiness.networkReady,
2021
+ operationLane: readiness.operationLane,
2022
+ roleReady: readiness.ready
2023
+ },
2024
+ env: process.env
2025
+ });
2026
+ const payload = {
2027
+ ok: true,
2028
+ walletId: wallet.id,
2029
+ signerWalletId,
2030
+ role,
2031
+ readiness
2032
+ };
2033
+ if (options.json) {
2034
+ runtime.log(JSON.stringify(payload, null, 2));
2035
+ return;
2036
+ }
2037
+ runtime.log(`Activated ${role} role baseline v${readiness.baselineVersion} for ${wallet.name} (${wallet.id}).`);
2038
+ runtime.log(`Readiness: ${readiness.ready ? "ready" : "setup incomplete"} (${readiness.operationLane}).`);
2039
+ }
828
2040
  async function walletKeystoreInitCommand(runtime = defaultRuntime, options = {}) {
829
2041
  void runtime;
830
2042
  void options;
@@ -1509,4 +2721,4 @@ async function walletInboundReconcileCommand(runtime = defaultRuntime, options =
1509
2721
  }
1510
2722
 
1511
2723
  //#endregion
1512
- export { collectWalletSignerDoctorReport, walletCanaryCommand, walletInboundListCommand, walletInboundPollCommand, walletInboundReconcileCommand, walletLegacyMigrationFinalizeCommand, walletLimitOrdersConfigureCommand, walletMigrateCommand, walletPolicyProfileApplyCommand, walletProviderConfigureCommand, walletRoleSetCommand, walletRotateKeysCommand, walletSetupCommand, walletSignerDoctorCommand, walletSignerServeCommand, walletStatusCommand };
2724
+ export { collectWalletSignerDoctorReport, walletCanaryCommand, walletInboundListCommand, walletInboundPollCommand, walletInboundReconcileCommand, walletLegacyMigrationFinalizeCommand, walletLimitOrdersConfigureCommand, walletMigrateCommand, walletPolicyActivateRoleBaselineCommand, walletPolicyProfileApplyCommand, walletProviderConfigureCommand, walletRawExportCommand, walletRecoveryExportCommand, walletRecoveryImportCommand, walletRetireCommand, walletRoleSetCommand, walletRotateKeysCommand, walletRpcSetCommand, walletSetupCommand, walletSignerDoctorCommand, walletSignerServeCommand, walletStatusCommand };