@wlfi-agent/cli 1.4.13 → 1.4.15

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 (289) hide show
  1. package/Cargo.lock +3968 -0
  2. package/Cargo.toml +50 -0
  3. package/README.md +426 -6
  4. package/crates/vault-cli-admin/Cargo.toml +26 -0
  5. package/crates/vault-cli-admin/src/io_utils.rs +500 -0
  6. package/crates/vault-cli-admin/src/main.rs +3990 -0
  7. package/crates/vault-cli-admin/src/shared_config.rs +624 -0
  8. package/crates/vault-cli-admin/src/tui/amounts.rs +180 -0
  9. package/crates/vault-cli-admin/src/tui/token_rpc.rs +250 -0
  10. package/crates/vault-cli-admin/src/tui/utils.rs +82 -0
  11. package/crates/vault-cli-admin/src/tui.rs +3410 -0
  12. package/crates/vault-cli-agent/Cargo.toml +24 -0
  13. package/crates/vault-cli-agent/src/io_utils.rs +576 -0
  14. package/crates/vault-cli-agent/src/main.rs +833 -0
  15. package/crates/vault-cli-daemon/Cargo.toml +28 -0
  16. package/crates/vault-cli-daemon/src/bin/wlfi-agent-system-keychain.rs +216 -0
  17. package/crates/vault-cli-daemon/src/main.rs +644 -0
  18. package/crates/vault-cli-daemon/src/relay_sync.rs +894 -0
  19. package/crates/vault-cli-daemon/tests/system_keychain_helper_acl.rs +167 -0
  20. package/crates/vault-daemon/Cargo.toml +32 -0
  21. package/crates/vault-daemon/src/daemon_parts/api_impl_and_utils.rs +1041 -0
  22. package/crates/vault-daemon/src/daemon_parts/core_helpers.rs +1256 -0
  23. package/crates/vault-daemon/src/daemon_parts/types_api_rpc.rs +622 -0
  24. package/crates/vault-daemon/src/lib.rs +54 -0
  25. package/crates/vault-daemon/src/persistence.rs +441 -0
  26. package/crates/vault-daemon/src/tests.rs +237 -0
  27. package/crates/vault-daemon/src/tests_parts/part1.rs +1224 -0
  28. package/crates/vault-daemon/src/tests_parts/part2.rs +1021 -0
  29. package/crates/vault-daemon/src/tests_parts/part3.rs +835 -0
  30. package/crates/vault-daemon/src/tests_parts/part4.rs +604 -0
  31. package/crates/vault-domain/Cargo.toml +20 -0
  32. package/crates/vault-domain/src/action.rs +849 -0
  33. package/crates/vault-domain/src/address.rs +51 -0
  34. package/crates/vault-domain/src/approval.rs +90 -0
  35. package/crates/vault-domain/src/constants.rs +4 -0
  36. package/crates/vault-domain/src/error.rs +54 -0
  37. package/crates/vault-domain/src/keys.rs +71 -0
  38. package/crates/vault-domain/src/lib.rs +42 -0
  39. package/crates/vault-domain/src/nonce.rs +102 -0
  40. package/crates/vault-domain/src/policy.rs +172 -0
  41. package/crates/vault-domain/src/request.rs +53 -0
  42. package/crates/vault-domain/src/scope.rs +24 -0
  43. package/crates/vault-domain/src/session.rs +50 -0
  44. package/crates/vault-domain/src/signature.rs +34 -0
  45. package/crates/vault-domain/src/tests.rs +651 -0
  46. package/crates/vault-domain/src/u128_as_decimal_string.rs +44 -0
  47. package/crates/vault-policy/Cargo.toml +17 -0
  48. package/crates/vault-policy/src/engine.rs +301 -0
  49. package/crates/vault-policy/src/error.rs +81 -0
  50. package/crates/vault-policy/src/lib.rs +17 -0
  51. package/crates/vault-policy/src/report.rs +34 -0
  52. package/crates/vault-policy/src/tests.rs +891 -0
  53. package/crates/vault-policy/src/tests_explain.rs +78 -0
  54. package/crates/vault-sdk-agent/Cargo.toml +21 -0
  55. package/crates/vault-sdk-agent/src/lib.rs +711 -0
  56. package/crates/vault-signer/Cargo.toml +25 -0
  57. package/crates/vault-signer/src/lib.rs +731 -0
  58. package/crates/vault-signer/tests/secure_enclave_acl.rs +54 -0
  59. package/crates/vault-transport-unix/Cargo.toml +24 -0
  60. package/crates/vault-transport-unix/src/lib.rs +1640 -0
  61. package/crates/vault-transport-xpc/Cargo.toml +25 -0
  62. package/crates/vault-transport-xpc/src/client_codec_api.rs +635 -0
  63. package/crates/vault-transport-xpc/src/lib.rs +680 -0
  64. package/crates/vault-transport-xpc/src/tests.rs +818 -0
  65. package/crates/vault-transport-xpc/tests/e2e_flow.rs +773 -0
  66. package/dist/cli.cjs +35088 -0
  67. package/dist/cli.cjs.map +1 -0
  68. package/package.json +45 -41
  69. package/packages/cache/.turbo/turbo-build.log +52 -0
  70. package/packages/cache/dist/chunk-2QFWMUXT.cjs +43 -0
  71. package/packages/cache/dist/chunk-2QFWMUXT.cjs.map +1 -0
  72. package/packages/cache/dist/chunk-4U63TZTQ.js +43 -0
  73. package/packages/cache/dist/chunk-4U63TZTQ.js.map +1 -0
  74. package/packages/cache/dist/chunk-ALQ6H7KG.cjs +404 -0
  75. package/packages/cache/dist/chunk-ALQ6H7KG.cjs.map +1 -0
  76. package/packages/cache/dist/chunk-FGJEEF5N.js +404 -0
  77. package/packages/cache/dist/chunk-FGJEEF5N.js.map +1 -0
  78. package/packages/cache/dist/chunk-UYNEHZHB.cjs +45 -0
  79. package/packages/cache/dist/chunk-UYNEHZHB.cjs.map +1 -0
  80. package/packages/cache/dist/chunk-VXVMPG3W.js +45 -0
  81. package/packages/cache/dist/chunk-VXVMPG3W.js.map +1 -0
  82. package/packages/cache/dist/client/index.cjs +11 -0
  83. package/packages/cache/dist/client/index.cjs.map +1 -0
  84. package/packages/cache/dist/client/index.d.cts +15 -0
  85. package/packages/cache/dist/client/index.d.ts +15 -0
  86. package/packages/cache/dist/client/index.js +11 -0
  87. package/packages/cache/dist/client/index.js.map +1 -0
  88. package/packages/cache/dist/errors/index.cjs +11 -0
  89. package/packages/cache/dist/errors/index.cjs.map +1 -0
  90. package/packages/cache/dist/errors/index.d.cts +26 -0
  91. package/packages/cache/dist/errors/index.d.ts +26 -0
  92. package/packages/cache/dist/errors/index.js +11 -0
  93. package/packages/cache/dist/errors/index.js.map +1 -0
  94. package/packages/cache/dist/index.cjs +29 -0
  95. package/packages/cache/dist/index.cjs.map +1 -0
  96. package/packages/cache/dist/index.d.cts +4 -0
  97. package/packages/cache/dist/index.d.ts +4 -0
  98. package/packages/cache/dist/index.js +29 -0
  99. package/packages/cache/dist/index.js.map +1 -0
  100. package/packages/cache/dist/service/index.cjs +15 -0
  101. package/packages/cache/dist/service/index.cjs.map +1 -0
  102. package/packages/cache/dist/service/index.d.cts +184 -0
  103. package/packages/cache/dist/service/index.d.ts +184 -0
  104. package/packages/cache/dist/service/index.js +15 -0
  105. package/packages/cache/dist/service/index.js.map +1 -0
  106. package/packages/cache/node_modules/.bin/jiti +17 -0
  107. package/packages/cache/node_modules/.bin/tsc +17 -0
  108. package/packages/cache/node_modules/.bin/tsserver +17 -0
  109. package/packages/cache/node_modules/.bin/tsup +17 -0
  110. package/packages/cache/node_modules/.bin/tsup-node +17 -0
  111. package/packages/cache/node_modules/.bin/tsx +17 -0
  112. package/packages/cache/node_modules/.bin/vitest +17 -0
  113. package/packages/cache/package.json +48 -0
  114. package/packages/cache/src/client/index.ts +56 -0
  115. package/packages/cache/src/errors/index.ts +53 -0
  116. package/packages/cache/src/index.ts +3 -0
  117. package/packages/cache/src/service/index.test.ts +263 -0
  118. package/packages/cache/src/service/index.ts +678 -0
  119. package/packages/cache/tsconfig.json +13 -0
  120. package/packages/cache/tsup.config.ts +13 -0
  121. package/packages/cache/vitest.config.ts +16 -0
  122. package/packages/config/.turbo/turbo-build.log +18 -0
  123. package/packages/config/dist/index.cjs +1037 -0
  124. package/packages/config/dist/index.cjs.map +1 -0
  125. package/packages/config/dist/index.d.ts +131 -0
  126. package/packages/config/node_modules/.bin/jiti +17 -0
  127. package/packages/config/node_modules/.bin/tsc +17 -0
  128. package/packages/config/node_modules/.bin/tsserver +17 -0
  129. package/packages/config/node_modules/.bin/tsup +17 -0
  130. package/packages/config/node_modules/.bin/tsup-node +17 -0
  131. package/packages/config/node_modules/.bin/tsx +17 -0
  132. package/packages/config/package.json +21 -0
  133. package/packages/config/src/index.js +1 -0
  134. package/packages/config/src/index.ts +1282 -0
  135. package/packages/config/tsconfig.json +4 -0
  136. package/packages/rpc/.turbo/turbo-build.log +32 -0
  137. package/packages/rpc/dist/_esm-BCLXDO2R.cjs +3660 -0
  138. package/packages/rpc/dist/_esm-BCLXDO2R.cjs.map +1 -0
  139. package/packages/rpc/dist/ccip-OWJLAW55.cjs +16 -0
  140. package/packages/rpc/dist/ccip-OWJLAW55.cjs.map +1 -0
  141. package/packages/rpc/dist/chunk-APQIFZ3B.cjs +6247 -0
  142. package/packages/rpc/dist/chunk-APQIFZ3B.cjs.map +1 -0
  143. package/packages/rpc/dist/chunk-CDO2GWRD.cjs +410 -0
  144. package/packages/rpc/dist/chunk-CDO2GWRD.cjs.map +1 -0
  145. package/packages/rpc/dist/chunk-QGTNTFJ7.cjs +2249 -0
  146. package/packages/rpc/dist/chunk-QGTNTFJ7.cjs.map +1 -0
  147. package/packages/rpc/dist/chunk-TZDTAHWR.cjs +44 -0
  148. package/packages/rpc/dist/chunk-TZDTAHWR.cjs.map +1 -0
  149. package/packages/rpc/dist/index.cjs +7342 -0
  150. package/packages/rpc/dist/index.cjs.map +1 -0
  151. package/packages/rpc/dist/index.d.ts +3857 -0
  152. package/packages/rpc/dist/secp256k1-WCNM675D.cjs +18 -0
  153. package/packages/rpc/dist/secp256k1-WCNM675D.cjs.map +1 -0
  154. package/packages/rpc/node_modules/.bin/jiti +17 -0
  155. package/packages/rpc/node_modules/.bin/tsc +17 -0
  156. package/packages/rpc/node_modules/.bin/tsserver +17 -0
  157. package/packages/rpc/node_modules/.bin/tsup +17 -0
  158. package/packages/rpc/node_modules/.bin/tsup-node +17 -0
  159. package/packages/rpc/node_modules/.bin/tsx +17 -0
  160. package/packages/rpc/package.json +25 -0
  161. package/packages/rpc/src/index.ts +206 -0
  162. package/packages/rpc/tsconfig.json +4 -0
  163. package/packages/typescript/base.json +36 -0
  164. package/packages/typescript/nextjs.json +17 -0
  165. package/packages/typescript/package.json +10 -0
  166. package/packages/ui/.turbo/turbo-build.log +44 -0
  167. package/packages/ui/dist/chunk-MOAFBKSA.js +11 -0
  168. package/packages/ui/dist/chunk-MOAFBKSA.js.map +1 -0
  169. package/packages/ui/dist/components/badge.d.ts +12 -0
  170. package/packages/ui/dist/components/badge.js +31 -0
  171. package/packages/ui/dist/components/badge.js.map +1 -0
  172. package/packages/ui/dist/components/button.d.ts +13 -0
  173. package/packages/ui/dist/components/button.js +40 -0
  174. package/packages/ui/dist/components/button.js.map +1 -0
  175. package/packages/ui/dist/components/card.d.ts +10 -0
  176. package/packages/ui/dist/components/card.js +39 -0
  177. package/packages/ui/dist/components/card.js.map +1 -0
  178. package/packages/ui/dist/components/input.d.ts +5 -0
  179. package/packages/ui/dist/components/input.js +28 -0
  180. package/packages/ui/dist/components/input.js.map +1 -0
  181. package/packages/ui/dist/components/label.d.ts +5 -0
  182. package/packages/ui/dist/components/label.js +13 -0
  183. package/packages/ui/dist/components/label.js.map +1 -0
  184. package/packages/ui/dist/components/separator.d.ts +5 -0
  185. package/packages/ui/dist/components/separator.js +13 -0
  186. package/packages/ui/dist/components/separator.js.map +1 -0
  187. package/packages/ui/dist/components/textarea.d.ts +5 -0
  188. package/packages/ui/dist/components/textarea.js +27 -0
  189. package/packages/ui/dist/components/textarea.js.map +1 -0
  190. package/packages/ui/dist/tailwind.d.ts +56 -0
  191. package/packages/ui/dist/tailwind.js +60 -0
  192. package/packages/ui/dist/tailwind.js.map +1 -0
  193. package/packages/ui/dist/utils/cn.d.ts +5 -0
  194. package/packages/ui/dist/utils/cn.js +7 -0
  195. package/packages/ui/dist/utils/cn.js.map +1 -0
  196. package/packages/ui/node_modules/.bin/jiti +17 -0
  197. package/packages/ui/node_modules/.bin/tsc +17 -0
  198. package/packages/ui/node_modules/.bin/tsserver +17 -0
  199. package/packages/ui/node_modules/.bin/tsup +17 -0
  200. package/packages/ui/node_modules/.bin/tsup-node +17 -0
  201. package/packages/ui/node_modules/.bin/tsx +17 -0
  202. package/packages/ui/package.json +69 -0
  203. package/packages/ui/src/components/badge.tsx +27 -0
  204. package/packages/ui/src/components/button.tsx +40 -0
  205. package/packages/ui/src/components/card.tsx +31 -0
  206. package/packages/ui/src/components/input.tsx +21 -0
  207. package/packages/ui/src/components/label.tsx +6 -0
  208. package/packages/ui/src/components/separator.tsx +6 -0
  209. package/packages/ui/src/components/textarea.tsx +20 -0
  210. package/packages/ui/src/globals.css +70 -0
  211. package/packages/ui/src/tailwind.ts +56 -0
  212. package/packages/ui/src/utils/cn.ts +6 -0
  213. package/packages/ui/tsconfig.json +20 -0
  214. package/packages/ui/tsup.config.ts +20 -0
  215. package/pnpm-workspace.yaml +4 -0
  216. package/scripts/install-rust-binaries.mjs +84 -0
  217. package/scripts/launchd/install-user-daemon.sh +358 -0
  218. package/scripts/launchd/run-vault-daemon.sh +5 -0
  219. package/scripts/launchd/run-wlfi-agent-daemon.sh +73 -0
  220. package/scripts/launchd/uninstall-user-daemon.sh +103 -0
  221. package/src/cli.ts +2121 -0
  222. package/src/lib/admin-guard.js +1 -0
  223. package/src/lib/admin-guard.ts +185 -0
  224. package/src/lib/admin-passthrough.ts +33 -0
  225. package/src/lib/admin-reset.ts +751 -0
  226. package/src/lib/admin-setup.ts +1612 -0
  227. package/src/lib/agent-auth-clear.js +1 -0
  228. package/src/lib/agent-auth-clear.ts +58 -0
  229. package/src/lib/agent-auth-forwarding.js +1 -0
  230. package/src/lib/agent-auth-forwarding.ts +149 -0
  231. package/src/lib/agent-auth-migrate.js +1 -0
  232. package/src/lib/agent-auth-migrate.ts +150 -0
  233. package/src/lib/agent-auth-revoke.ts +103 -0
  234. package/src/lib/agent-auth-rotate.ts +107 -0
  235. package/src/lib/agent-auth-token.js +1 -0
  236. package/src/lib/agent-auth-token.ts +25 -0
  237. package/src/lib/agent-auth.ts +89 -0
  238. package/src/lib/asset-broadcast.js +1 -0
  239. package/src/lib/asset-broadcast.ts +285 -0
  240. package/src/lib/bootstrap-artifacts.js +1 -0
  241. package/src/lib/bootstrap-artifacts.ts +205 -0
  242. package/src/lib/bootstrap-credentials.js +1 -0
  243. package/src/lib/bootstrap-credentials.ts +832 -0
  244. package/src/lib/config-amounts.js +1 -0
  245. package/src/lib/config-amounts.ts +189 -0
  246. package/src/lib/config-mutation.ts +27 -0
  247. package/src/lib/fs-trust.js +1 -0
  248. package/src/lib/fs-trust.ts +537 -0
  249. package/src/lib/keychain.js +1 -0
  250. package/src/lib/keychain.ts +225 -0
  251. package/src/lib/local-admin-access.ts +106 -0
  252. package/src/lib/network-selection.js +1 -0
  253. package/src/lib/network-selection.ts +71 -0
  254. package/src/lib/passthrough-security.js +1 -0
  255. package/src/lib/passthrough-security.ts +114 -0
  256. package/src/lib/rpc-guard.js +1 -0
  257. package/src/lib/rpc-guard.ts +7 -0
  258. package/src/lib/rust-spawn-options.js +1 -0
  259. package/src/lib/rust-spawn-options.ts +98 -0
  260. package/src/lib/rust.js +1 -0
  261. package/src/lib/rust.ts +143 -0
  262. package/src/lib/signed-tx.js +1 -0
  263. package/src/lib/signed-tx.ts +116 -0
  264. package/src/lib/status-repair-cli.ts +116 -0
  265. package/src/lib/sudo.js +1 -0
  266. package/src/lib/sudo.ts +172 -0
  267. package/src/lib/vault-password-forwarding.js +1 -0
  268. package/src/lib/vault-password-forwarding.ts +155 -0
  269. package/src/lib/wallet-profile.js +1 -0
  270. package/src/lib/wallet-profile.ts +332 -0
  271. package/src/lib/wallet-repair.js +1 -0
  272. package/src/lib/wallet-repair.ts +304 -0
  273. package/src/lib/wallet-setup.js +1 -0
  274. package/src/lib/wallet-setup.ts +1466 -0
  275. package/src/lib/wallet-status.js +1 -0
  276. package/src/lib/wallet-status.ts +640 -0
  277. package/tsconfig.base.json +17 -0
  278. package/tsconfig.json +10 -0
  279. package/tsup.config.ts +25 -0
  280. package/turbo.json +41 -0
  281. package/LICENSE.md +0 -1
  282. package/dist/wlfa/index.cjs +0 -250
  283. package/dist/wlfa/index.d.cts +0 -1
  284. package/dist/wlfa/index.d.ts +0 -1
  285. package/dist/wlfa/index.js +0 -250
  286. package/dist/wlfc/index.cjs +0 -1839
  287. package/dist/wlfc/index.d.cts +0 -1
  288. package/dist/wlfc/index.d.ts +0 -1
  289. package/dist/wlfc/index.js +0 -1839
@@ -0,0 +1 @@
1
+ export * from './wallet-status.ts';
@@ -0,0 +1,640 @@
1
+ import fs from 'node:fs';
2
+ import {
3
+ assertSafeRpcUrl,
4
+ defaultConfig,
5
+ defaultDaemonSocketPath,
6
+ defaultStateFilePath,
7
+ readConfig,
8
+ redactConfig,
9
+ resolveRustBinaryPath,
10
+ type WlfiConfig,
11
+ } from '../../packages/config/src/index.js';
12
+ import {
13
+ type BootstrapArtifactCheck,
14
+ listAutoGeneratedBootstrapArtifacts,
15
+ } from './bootstrap-artifacts.js';
16
+ import {
17
+ assertTrustedDaemonSocketPath,
18
+ assertTrustedExecutablePath,
19
+ assertTrustedRootPrivateFilePath,
20
+ } from './fs-trust.js';
21
+ import {
22
+ AGENT_AUTH_TOKEN_KEYCHAIN_SERVICE,
23
+ assertValidAgentKeyId,
24
+ hasAgentAuthTokenInKeychain,
25
+ readAgentAuthTokenFromKeychain,
26
+ } from './keychain.js';
27
+ import type { RustBinaryName } from './rust.js';
28
+
29
+ export interface WalletStatusBinaryCheck {
30
+ name: RustBinaryName;
31
+ path: string;
32
+ installed: boolean;
33
+ trusted: boolean;
34
+ error: string | null;
35
+ }
36
+
37
+ export interface WalletStatusChainProfileCheck {
38
+ key: string;
39
+ chainId: number | null;
40
+ chainName: string | null;
41
+ rpcUrlConfigured: boolean;
42
+ rpcUrlTrusted: boolean | null;
43
+ error: string | null;
44
+ }
45
+
46
+ export interface WalletStatusResult {
47
+ platform: NodeJS.Platform;
48
+ config: {
49
+ readable: boolean;
50
+ error: string | null;
51
+ values: Record<string, unknown>;
52
+ };
53
+ agent: {
54
+ agentKeyId: string | null;
55
+ agentKeyIdValid: boolean;
56
+ keychain: {
57
+ supported: boolean;
58
+ service: string | null;
59
+ tokenStored: boolean;
60
+ error: string | null;
61
+ };
62
+ legacyConfigToken: {
63
+ present: boolean;
64
+ keychainMatch: boolean | null;
65
+ error: string | null;
66
+ };
67
+ };
68
+ chain: {
69
+ chainId: number | null;
70
+ chainName: string | null;
71
+ rpcUrlConfigured: boolean;
72
+ rpcUrlTrusted: boolean | null;
73
+ error: string | null;
74
+ };
75
+ chainProfiles: WalletStatusChainProfileCheck[];
76
+ bootstrapFiles: BootstrapArtifactCheck[];
77
+ daemonSocket: {
78
+ path: string;
79
+ trusted: boolean;
80
+ error: string | null;
81
+ };
82
+ stateFile: {
83
+ path: string;
84
+ present: boolean;
85
+ trusted: boolean;
86
+ error: string | null;
87
+ };
88
+ binaries: WalletStatusBinaryCheck[];
89
+ security: {
90
+ ready: boolean;
91
+ warnings: string[];
92
+ };
93
+ }
94
+
95
+ export interface WalletStatusExitOptions {
96
+ strict?: boolean;
97
+ }
98
+
99
+ interface WalletStatusDeps {
100
+ platform?: NodeJS.Platform;
101
+ readConfig?: () => WlfiConfig;
102
+ hasAgentAuthToken?: (agentKeyId: string) => boolean;
103
+ readAgentAuthToken?: (agentKeyId: string) => string | null;
104
+ assertTrustedDaemonSocketPath?: (targetPath: string, label?: string) => string;
105
+ assertTrustedStateFilePath?: (targetPath: string, label?: string) => string;
106
+ assertTrustedExecutablePath?: (targetPath: string) => void;
107
+ resolveRustBinaryPath?: (binaryName: RustBinaryName, config?: WlfiConfig) => string;
108
+ existsSync?: (targetPath: string) => boolean;
109
+ listBootstrapFiles?: () => BootstrapArtifactCheck[];
110
+ }
111
+
112
+ const RUST_BINARIES: RustBinaryName[] = [
113
+ 'wlfi-agent-daemon',
114
+ 'wlfi-agent-admin',
115
+ 'wlfi-agent-agent',
116
+ ];
117
+
118
+ function renderError(error: unknown): string {
119
+ return error instanceof Error ? error.message : String(error);
120
+ }
121
+
122
+ function presentString(value: string | undefined): string | null {
123
+ const normalized = value?.trim();
124
+ return normalized ? normalized : null;
125
+ }
126
+
127
+ function presentSecret(value: string | undefined): string | null {
128
+ if (typeof value !== 'string') {
129
+ return null;
130
+ }
131
+
132
+ return value.length > 0 ? value : null;
133
+ }
134
+
135
+ function resolveChainStatus(config: WlfiConfig): WalletStatusResult['chain'] {
136
+ const rpcUrl = presentString(config.rpcUrl);
137
+ if (!rpcUrl) {
138
+ return {
139
+ chainId: config.chainId ?? null,
140
+ chainName: presentString(config.chainName),
141
+ rpcUrlConfigured: false,
142
+ rpcUrlTrusted: null,
143
+ error: null,
144
+ };
145
+ }
146
+
147
+ try {
148
+ assertSafeRpcUrl(rpcUrl, 'configured rpcUrl');
149
+ return {
150
+ chainId: config.chainId ?? null,
151
+ chainName: presentString(config.chainName),
152
+ rpcUrlConfigured: true,
153
+ rpcUrlTrusted: true,
154
+ error: null,
155
+ };
156
+ } catch (error) {
157
+ return {
158
+ chainId: config.chainId ?? null,
159
+ chainName: presentString(config.chainName),
160
+ rpcUrlConfigured: true,
161
+ rpcUrlTrusted: false,
162
+ error: renderError(error),
163
+ };
164
+ }
165
+ }
166
+
167
+ function resolveChainProfileStatuses(config: WlfiConfig): WalletStatusChainProfileCheck[] {
168
+ return Object.entries(config.chains ?? {}).map(([key, profile]) => {
169
+ const chainId = typeof profile?.chainId === 'number' ? profile.chainId : null;
170
+ const chainName = typeof profile?.name === 'string' ? presentString(profile.name) : null;
171
+ const rpcUrl = typeof profile?.rpcUrl === 'string' ? presentString(profile.rpcUrl) : null;
172
+
173
+ if (!rpcUrl) {
174
+ return {
175
+ key,
176
+ chainId,
177
+ chainName,
178
+ rpcUrlConfigured: false,
179
+ rpcUrlTrusted: null,
180
+ error: null,
181
+ };
182
+ }
183
+
184
+ try {
185
+ assertSafeRpcUrl(rpcUrl, `chain profile '${key}' rpcUrl`);
186
+ return {
187
+ key,
188
+ chainId,
189
+ chainName,
190
+ rpcUrlConfigured: true,
191
+ rpcUrlTrusted: true,
192
+ error: null,
193
+ };
194
+ } catch (error) {
195
+ return {
196
+ key,
197
+ chainId,
198
+ chainName,
199
+ rpcUrlConfigured: true,
200
+ rpcUrlTrusted: false,
201
+ error: renderError(error),
202
+ };
203
+ }
204
+ });
205
+ }
206
+
207
+ function resolveConfigSnapshot(loadConfig: () => WlfiConfig): {
208
+ config: WlfiConfig;
209
+ readable: boolean;
210
+ error: string | null;
211
+ } {
212
+ try {
213
+ return {
214
+ config: loadConfig(),
215
+ readable: true,
216
+ error: null,
217
+ };
218
+ } catch (error) {
219
+ return {
220
+ config: defaultConfig(),
221
+ readable: false,
222
+ error: renderError(error),
223
+ };
224
+ }
225
+ }
226
+
227
+ function resolveAgentStatus(
228
+ config: WlfiConfig,
229
+ platform: NodeJS.Platform,
230
+ hasAgentAuthToken: (agentKeyId: string) => boolean,
231
+ readAgentAuthToken: (agentKeyId: string) => string | null,
232
+ ): WalletStatusResult['agent'] {
233
+ const agentKeyId = presentString(config.agentKeyId);
234
+ const legacyConfigToken = presentSecret(config.agentAuthToken);
235
+
236
+ if (!agentKeyId) {
237
+ return {
238
+ agentKeyId: null,
239
+ agentKeyIdValid: false,
240
+ keychain: {
241
+ supported: platform === 'darwin',
242
+ service: platform === 'darwin' ? AGENT_AUTH_TOKEN_KEYCHAIN_SERVICE : null,
243
+ tokenStored: false,
244
+ error: null,
245
+ },
246
+ legacyConfigToken: {
247
+ present: legacyConfigToken !== null,
248
+ keychainMatch: null,
249
+ error: null,
250
+ },
251
+ };
252
+ }
253
+
254
+ try {
255
+ const normalizedAgentKeyId = assertValidAgentKeyId(agentKeyId);
256
+ let tokenStored = false;
257
+ let keychainError: string | null = null;
258
+ let legacyConfigTokenMatch: boolean | null = null;
259
+ let legacyConfigTokenError: string | null = null;
260
+
261
+ try {
262
+ tokenStored = hasAgentAuthToken(normalizedAgentKeyId);
263
+ } catch (error) {
264
+ keychainError = renderError(error);
265
+ }
266
+
267
+ if (legacyConfigToken !== null && platform === 'darwin') {
268
+ try {
269
+ const keychainToken = readAgentAuthToken(normalizedAgentKeyId);
270
+ legacyConfigTokenMatch =
271
+ keychainToken === null ? null : keychainToken === legacyConfigToken;
272
+ } catch (error) {
273
+ legacyConfigTokenError = renderError(error);
274
+ }
275
+ }
276
+
277
+ return {
278
+ agentKeyId: normalizedAgentKeyId,
279
+ agentKeyIdValid: true,
280
+ keychain: {
281
+ supported: platform === 'darwin',
282
+ service: platform === 'darwin' ? AGENT_AUTH_TOKEN_KEYCHAIN_SERVICE : null,
283
+ tokenStored,
284
+ error: keychainError,
285
+ },
286
+ legacyConfigToken: {
287
+ present: legacyConfigToken !== null,
288
+ keychainMatch: legacyConfigTokenMatch,
289
+ error: legacyConfigTokenError,
290
+ },
291
+ };
292
+ } catch (error) {
293
+ return {
294
+ agentKeyId,
295
+ agentKeyIdValid: false,
296
+ keychain: {
297
+ supported: platform === 'darwin',
298
+ service: platform === 'darwin' ? AGENT_AUTH_TOKEN_KEYCHAIN_SERVICE : null,
299
+ tokenStored: false,
300
+ error: renderError(error),
301
+ },
302
+ legacyConfigToken: {
303
+ present: legacyConfigToken !== null,
304
+ keychainMatch: null,
305
+ error: null,
306
+ },
307
+ };
308
+ }
309
+ }
310
+
311
+ function resolveDaemonSocketStatus(
312
+ config: WlfiConfig,
313
+ assertTrustedSocketPath: (targetPath: string, label?: string) => string,
314
+ ): WalletStatusResult['daemonSocket'] {
315
+ const daemonSocketPath = config.daemonSocket ?? defaultDaemonSocketPath();
316
+ try {
317
+ return {
318
+ path: assertTrustedSocketPath(daemonSocketPath),
319
+ trusted: true,
320
+ error: null,
321
+ };
322
+ } catch (error) {
323
+ return {
324
+ path: daemonSocketPath,
325
+ trusted: false,
326
+ error: renderError(error),
327
+ };
328
+ }
329
+ }
330
+
331
+ function resolveStateFileStatus(
332
+ config: WlfiConfig,
333
+ assertTrustedStateFilePath: (targetPath: string, label?: string) => string,
334
+ existsSync: (targetPath: string) => boolean,
335
+ ): WalletStatusResult['stateFile'] {
336
+ const stateFilePath = config.stateFile ?? defaultStateFilePath();
337
+ const present = existsSync(stateFilePath);
338
+
339
+ try {
340
+ return {
341
+ path: assertTrustedStateFilePath(stateFilePath),
342
+ present,
343
+ trusted: true,
344
+ error: null,
345
+ };
346
+ } catch (error) {
347
+ return {
348
+ path: stateFilePath,
349
+ present,
350
+ trusted: false,
351
+ error: renderError(error),
352
+ };
353
+ }
354
+ }
355
+
356
+ function resolveBinaryStatus(
357
+ config: WlfiConfig,
358
+ binaryName: RustBinaryName,
359
+ deps: Required<
360
+ Pick<WalletStatusDeps, 'assertTrustedExecutablePath' | 'existsSync' | 'resolveRustBinaryPath'>
361
+ >,
362
+ ): WalletStatusBinaryCheck {
363
+ const binaryPath = deps.resolveRustBinaryPath(binaryName, config);
364
+ if (!deps.existsSync(binaryPath)) {
365
+ return {
366
+ name: binaryName,
367
+ path: binaryPath,
368
+ installed: false,
369
+ trusted: false,
370
+ error: 'binary is not installed',
371
+ };
372
+ }
373
+
374
+ try {
375
+ deps.assertTrustedExecutablePath(binaryPath);
376
+ return {
377
+ name: binaryName,
378
+ path: binaryPath,
379
+ installed: true,
380
+ trusted: true,
381
+ error: null,
382
+ };
383
+ } catch (error) {
384
+ return {
385
+ name: binaryName,
386
+ path: binaryPath,
387
+ installed: true,
388
+ trusted: false,
389
+ error: renderError(error),
390
+ };
391
+ }
392
+ }
393
+
394
+ function buildWarnings(result: Omit<WalletStatusResult, 'security'>): string[] {
395
+ const warnings: string[] = [];
396
+
397
+ if (!result.config.readable) {
398
+ warnings.push(`config is unreadable: ${result.config.error}`);
399
+ }
400
+ if (result.config.readable && result.agent.legacyConfigToken.present) {
401
+ if (result.agent.legacyConfigToken.keychainMatch === true) {
402
+ warnings.push(
403
+ 'legacy agentAuthToken is duplicated in config.json and macOS Keychain; run `wlfi-agent config agent-auth migrate` to scrub plaintext config storage',
404
+ );
405
+ } else if (result.agent.legacyConfigToken.keychainMatch === false) {
406
+ warnings.push(
407
+ 'legacy agentAuthToken in config.json differs from the macOS Keychain token for the configured agentKeyId; avoid `--allow-legacy-agent-auth-source` until migrated',
408
+ );
409
+ } else {
410
+ warnings.push(
411
+ 'legacy agentAuthToken is still present in config.json; migrate it to macOS Keychain',
412
+ );
413
+ }
414
+ }
415
+ if (result.agent.legacyConfigToken.error) {
416
+ warnings.push(
417
+ `legacy agentAuthToken could not be compared with macOS Keychain: ${result.agent.legacyConfigToken.error}`,
418
+ );
419
+ }
420
+ if (!result.agent.agentKeyId) {
421
+ warnings.push('agentKeyId is not configured');
422
+ } else if (!result.agent.agentKeyIdValid) {
423
+ warnings.push('configured agentKeyId is not a valid UUID');
424
+ }
425
+ if (result.agent.agentKeyIdValid && result.agent.keychain.error) {
426
+ warnings.push(`macOS Keychain status check failed: ${result.agent.keychain.error}`);
427
+ } else if (result.agent.agentKeyIdValid && !result.agent.keychain.supported) {
428
+ warnings.push('macOS Keychain integration is unavailable on this platform');
429
+ } else if (result.agent.agentKeyIdValid && !result.agent.keychain.tokenStored) {
430
+ warnings.push(
431
+ 'macOS Keychain does not contain an agent auth token for the configured agentKeyId',
432
+ );
433
+ }
434
+ if (!result.daemonSocket.trusted) {
435
+ warnings.push(`daemon socket is not trusted: ${result.daemonSocket.error}`);
436
+ }
437
+ if (!result.stateFile.trusted) {
438
+ warnings.push(`state file is not trusted: ${result.stateFile.error}`);
439
+ }
440
+ for (const binary of result.binaries) {
441
+ if (!binary.installed) {
442
+ warnings.push(`${binary.name} is not installed at ${binary.path}`);
443
+ } else if (!binary.trusted) {
444
+ warnings.push(`${binary.name} is not trusted: ${binary.error}`);
445
+ }
446
+ }
447
+ if (result.chain.rpcUrlConfigured && result.chain.rpcUrlTrusted === false) {
448
+ warnings.push(`configured rpcUrl is not trusted: ${result.chain.error}`);
449
+ }
450
+ if (result.chain.chainId !== null && !result.chain.rpcUrlConfigured) {
451
+ warnings.push('active chain is configured without an rpcUrl');
452
+ }
453
+ for (const profile of result.chainProfiles) {
454
+ if (profile.rpcUrlConfigured && profile.rpcUrlTrusted === false) {
455
+ warnings.push(`chain profile '${profile.key}' rpcUrl is not trusted: ${profile.error}`);
456
+ }
457
+ }
458
+ for (const bootstrapFile of result.bootstrapFiles) {
459
+ if (bootstrapFile.status === 'plaintext') {
460
+ warnings.push(
461
+ `bootstrap file '${bootstrapFile.path}' still contains plaintext bootstrap secrets; delete or redact it securely`,
462
+ );
463
+ }
464
+ if (
465
+ bootstrapFile.leaseExpired &&
466
+ (bootstrapFile.status === 'plaintext' || bootstrapFile.status === 'redacted')
467
+ ) {
468
+ warnings.push(
469
+ `bootstrap file '${bootstrapFile.path}' has an expired setup lease; do not rely on it for wallet recovery or metadata backfill`,
470
+ );
471
+ } else if (bootstrapFile.status === 'invalid') {
472
+ warnings.push(
473
+ `bootstrap file '${bootstrapFile.path}' is malformed or incomplete: ${bootstrapFile.error}`,
474
+ );
475
+ } else if (bootstrapFile.status === 'untrusted') {
476
+ warnings.push(
477
+ `bootstrap file '${bootstrapFile.path}' is not trusted: ${bootstrapFile.error}`,
478
+ );
479
+ }
480
+ }
481
+
482
+ return warnings;
483
+ }
484
+
485
+ function summarizeAgentAuthStorage(result: WalletStatusResult): string {
486
+ if (!result.agent.agentKeyId) {
487
+ return 'not configured';
488
+ }
489
+ if (!result.agent.agentKeyIdValid) {
490
+ return 'configured agentKeyId is invalid';
491
+ }
492
+ if (!result.agent.keychain.supported) {
493
+ return 'macOS Keychain integration unavailable on this platform';
494
+ }
495
+ if (result.agent.keychain.error) {
496
+ return `macOS Keychain check failed: ${result.agent.keychain.error}`;
497
+ }
498
+ return result.agent.keychain.tokenStored
499
+ ? 'stored in macOS Keychain'
500
+ : 'missing from macOS Keychain';
501
+ }
502
+
503
+ function summarizeChain(result: WalletStatusResult): string {
504
+ if (result.chain.chainName && result.chain.chainId !== null) {
505
+ return `${result.chain.chainName} (${result.chain.chainId})`;
506
+ }
507
+ if (result.chain.chainName) {
508
+ return result.chain.chainName;
509
+ }
510
+ if (result.chain.chainId !== null) {
511
+ return `chainId ${result.chain.chainId}`;
512
+ }
513
+ return 'unconfigured';
514
+ }
515
+
516
+ function summarizeRpcTrust(result: WalletStatusResult): string {
517
+ if (!result.chain.rpcUrlConfigured) {
518
+ return 'not configured';
519
+ }
520
+ if (result.chain.rpcUrlTrusted === false) {
521
+ return `untrusted: ${result.chain.error}`;
522
+ }
523
+ return 'trusted';
524
+ }
525
+
526
+ function summarizeStateFile(result: WalletStatusResult): string {
527
+ const presence = result.stateFile.present ? 'present' : 'missing';
528
+ if (result.stateFile.trusted) {
529
+ return `${presence}, trusted`;
530
+ }
531
+ return `${presence}, untrusted: ${result.stateFile.error}`;
532
+ }
533
+
534
+ function summarizeDaemonSocket(result: WalletStatusResult): string {
535
+ if (result.daemonSocket.trusted) {
536
+ return 'trusted';
537
+ }
538
+ return `untrusted: ${result.daemonSocket.error}`;
539
+ }
540
+
541
+ export function formatWalletStatusText(result: WalletStatusResult): string {
542
+ const trustedBinaryCount = result.binaries.filter(
543
+ (binary) => binary.installed && binary.trusted,
544
+ ).length;
545
+ const lines = [
546
+ result.security.ready ? 'wallet status: ready' : 'wallet status: attention required',
547
+ `platform: ${result.platform}`,
548
+ `agent key id: ${result.agent.agentKeyId ?? '<unconfigured>'}`,
549
+ `agent auth token: ${summarizeAgentAuthStorage(result)}`,
550
+ `active chain: ${summarizeChain(result)}`,
551
+ `rpc url: ${summarizeRpcTrust(result)}`,
552
+ `daemon socket: ${result.daemonSocket.path} (${summarizeDaemonSocket(result)})`,
553
+ `state file: ${result.stateFile.path} (${summarizeStateFile(result)})`,
554
+ `bootstrap artifacts: ${result.bootstrapFiles.length === 0 ? 'none detected' : `${result.bootstrapFiles.length} detected`}`,
555
+ `rust binaries: ${trustedBinaryCount}/${result.binaries.length} trusted`,
556
+ ];
557
+
558
+ if (result.security.warnings.length === 0) {
559
+ lines.push('warnings: none');
560
+ return lines.join('\n');
561
+ }
562
+
563
+ lines.push(`warnings (${result.security.warnings.length}):`);
564
+ for (const warning of result.security.warnings) {
565
+ lines.push(`- ${warning}`);
566
+ }
567
+
568
+ return lines.join('\n');
569
+ }
570
+
571
+ export function getWalletStatus(deps: WalletStatusDeps = {}): WalletStatusResult {
572
+ const platform = deps.platform ?? process.platform;
573
+ const loadConfig = deps.readConfig ?? readConfig;
574
+ const resolveBinaryPath = deps.resolveRustBinaryPath ?? resolveRustBinaryPath;
575
+ const trustDaemonSocketPath = deps.assertTrustedDaemonSocketPath ?? assertTrustedDaemonSocketPath;
576
+ const trustStateFilePath =
577
+ deps.assertTrustedStateFilePath ??
578
+ ((targetPath: string, label = 'State file') =>
579
+ assertTrustedRootPrivateFilePath(targetPath, label, {
580
+ allowMissing: true,
581
+ }));
582
+ const trustExecutablePath = deps.assertTrustedExecutablePath ?? assertTrustedExecutablePath;
583
+ const hasAgentAuthToken = deps.hasAgentAuthToken ?? hasAgentAuthTokenInKeychain;
584
+ const readAgentAuthToken = deps.readAgentAuthToken ?? readAgentAuthTokenFromKeychain;
585
+ const existsSync = deps.existsSync ?? fs.existsSync;
586
+ const listBootstrapFiles = deps.listBootstrapFiles ?? listAutoGeneratedBootstrapArtifacts;
587
+
588
+ const configSnapshot = resolveConfigSnapshot(loadConfig);
589
+ const agent = resolveAgentStatus(
590
+ configSnapshot.config,
591
+ platform,
592
+ hasAgentAuthToken,
593
+ readAgentAuthToken,
594
+ );
595
+ const daemonSocket = resolveDaemonSocketStatus(configSnapshot.config, trustDaemonSocketPath);
596
+ const stateFile = resolveStateFileStatus(configSnapshot.config, trustStateFilePath, existsSync);
597
+ const binaries = RUST_BINARIES.map((binaryName) =>
598
+ resolveBinaryStatus(configSnapshot.config, binaryName, {
599
+ assertTrustedExecutablePath: trustExecutablePath,
600
+ existsSync,
601
+ resolveRustBinaryPath: resolveBinaryPath,
602
+ }),
603
+ );
604
+
605
+ const resultWithoutSecurity = {
606
+ platform,
607
+ config: {
608
+ readable: configSnapshot.readable,
609
+ error: configSnapshot.error,
610
+ values: redactConfig(configSnapshot.config),
611
+ },
612
+ agent,
613
+ chain: resolveChainStatus(configSnapshot.config),
614
+ chainProfiles: resolveChainProfileStatuses(configSnapshot.config),
615
+ bootstrapFiles: listBootstrapFiles(),
616
+ daemonSocket,
617
+ stateFile,
618
+ binaries,
619
+ };
620
+
621
+ const warnings = buildWarnings(resultWithoutSecurity);
622
+ return {
623
+ ...resultWithoutSecurity,
624
+ security: {
625
+ ready: warnings.length === 0,
626
+ warnings,
627
+ },
628
+ };
629
+ }
630
+
631
+ export function resolveWalletStatusExitCode(
632
+ result: WalletStatusResult,
633
+ options: WalletStatusExitOptions = {},
634
+ ): number {
635
+ if (!options.strict) {
636
+ return 0;
637
+ }
638
+
639
+ return result.security.ready ? 0 : 1;
640
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "declaration": true,
13
+ "sourceMap": true,
14
+ "types": ["node"],
15
+ "noEmit": false
16
+ }
17
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "."
5
+ },
6
+ "include": [
7
+ "src/**/*.ts",
8
+ "tsup.config.ts"
9
+ ]
10
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: {
5
+ cli: 'src/cli.ts'
6
+ },
7
+ format: ['cjs'],
8
+ platform: 'node',
9
+ target: 'node20',
10
+ clean: true,
11
+ sourcemap: true,
12
+ dts: false,
13
+ banner: {
14
+ js: '#!/usr/bin/env node'
15
+ },
16
+ outExtension() {
17
+ return { js: '.cjs' };
18
+ },
19
+ noExternal: [
20
+ '@wlfi-agent/config',
21
+ '@wlfi-agent/rpc',
22
+ 'commander',
23
+ 'viem'
24
+ ]
25
+ });