agentvault 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/README.md +1 -1
  3. package/dist/cli/commands/approve.js +5 -5
  4. package/dist/cli/commands/archive.js +5 -5
  5. package/dist/cli/commands/backup.js +5 -5
  6. package/dist/cli/commands/cloud-backup.js +12 -12
  7. package/dist/cli/commands/decrypt.js +2 -2
  8. package/dist/cli/commands/deploy.js +1 -1
  9. package/dist/cli/commands/exec.js +2 -2
  10. package/dist/cli/commands/fetch.js +4 -4
  11. package/dist/cli/commands/inference.js +5 -5
  12. package/dist/cli/commands/init.d.ts +1 -1
  13. package/dist/cli/commands/init.js +16 -16
  14. package/dist/cli/commands/list.js +4 -4
  15. package/dist/cli/commands/package.js +2 -2
  16. package/dist/cli/commands/profile.js +1 -1
  17. package/dist/cli/commands/rebuild.js +2 -2
  18. package/dist/cli/commands/show.js +1 -1
  19. package/dist/cli/commands/status.d.ts +1 -1
  20. package/dist/cli/commands/status.js +8 -8
  21. package/dist/cli/commands/trace.js +1 -1
  22. package/dist/cli/commands/wallet-export.js +1 -1
  23. package/dist/cli/commands/wallet-sign.js +1 -1
  24. package/dist/cli/commands/wallet.d.ts +1 -1
  25. package/dist/cli/commands/wallet.js +1 -1
  26. package/dist/cli/index.d.ts +2 -2
  27. package/dist/cli/index.js +3 -3
  28. package/dist/src/archival/archive-manager.d.ts +85 -0
  29. package/dist/src/archival/archive-manager.js +294 -0
  30. package/dist/src/archival/arweave-client.d.ts +88 -0
  31. package/dist/src/archival/arweave-client.js +223 -0
  32. package/dist/src/archival/index.d.ts +8 -0
  33. package/{src/archival/index.ts → dist/src/archival/index.js} +1 -1
  34. package/dist/src/backup/backup.d.ts +67 -0
  35. package/dist/src/backup/backup.js +231 -0
  36. package/dist/src/backup/index.d.ts +7 -0
  37. package/{src/backup/index.ts → dist/src/backup/index.js} +1 -1
  38. package/dist/src/cloud-storage/cloud-sync.d.ts +49 -0
  39. package/dist/src/cloud-storage/cloud-sync.js +372 -0
  40. package/dist/src/cloud-storage/index.d.ts +11 -0
  41. package/{src/cloud-storage/index.ts → dist/src/cloud-storage/index.js} +1 -1
  42. package/dist/src/cloud-storage/provider-detector.d.ts +34 -0
  43. package/dist/src/cloud-storage/provider-detector.js +158 -0
  44. package/{src/cloud-storage/types.ts → dist/src/cloud-storage/types.d.ts} +40 -53
  45. package/dist/src/cloud-storage/types.js +10 -0
  46. package/dist/src/debugging/index.d.ts +6 -0
  47. package/{src/debugging/index.ts → dist/src/debugging/index.js} +1 -1
  48. package/dist/src/debugging/logs.d.ts +32 -0
  49. package/dist/src/debugging/logs.js +158 -0
  50. package/dist/src/debugging/types.d.ts +91 -0
  51. package/dist/src/debugging/types.js +5 -0
  52. package/dist/src/deployment/deployer.d.ts +52 -0
  53. package/dist/src/deployment/deployer.js +211 -0
  54. package/dist/src/deployment/icpClient.d.ts +144 -0
  55. package/dist/src/deployment/icpClient.js +545 -0
  56. package/dist/src/deployment/index.d.ts +11 -0
  57. package/dist/src/deployment/index.js +14 -0
  58. package/dist/src/deployment/promotion.d.ts +32 -0
  59. package/dist/src/deployment/promotion.js +114 -0
  60. package/dist/src/deployment/types.d.ts +101 -0
  61. package/dist/src/deployment/types.js +5 -0
  62. package/dist/src/icp/batch.d.ts +112 -0
  63. package/dist/src/icp/batch.js +273 -0
  64. package/dist/src/icp/cycles.d.ts +29 -0
  65. package/{src/icp/cycles.ts → dist/src/icp/cycles.js} +8 -22
  66. package/dist/src/icp/environment.d.ts +60 -0
  67. package/dist/src/icp/environment.js +183 -0
  68. package/dist/src/icp/icpcli.d.ts +204 -0
  69. package/dist/src/icp/icpcli.js +374 -0
  70. package/dist/src/icp/icwasm.d.ts +94 -0
  71. package/dist/src/icp/icwasm.js +197 -0
  72. package/dist/src/icp/identity.d.ts +50 -0
  73. package/{src/icp/identity.ts → dist/src/icp/identity.js} +15 -28
  74. package/dist/src/icp/index.d.ts +16 -0
  75. package/dist/src/icp/index.js +20 -0
  76. package/dist/src/icp/optimization.d.ts +16 -0
  77. package/dist/src/icp/optimization.js +225 -0
  78. package/dist/src/icp/tokens.d.ts +24 -0
  79. package/{src/icp/tokens.ts → dist/src/icp/tokens.js} +5 -12
  80. package/dist/src/icp/tool-detector.d.ts +31 -0
  81. package/dist/src/icp/tool-detector.js +104 -0
  82. package/dist/src/icp/types.d.ts +493 -0
  83. package/dist/src/icp/types.js +7 -0
  84. package/dist/src/index.d.ts +12 -0
  85. package/dist/src/index.js +18 -0
  86. package/dist/src/inference/bittensor-client.d.ts +108 -0
  87. package/dist/src/inference/bittensor-client.js +224 -0
  88. package/dist/src/inference/index.d.ts +8 -0
  89. package/{src/inference/index.ts → dist/src/inference/index.js} +1 -1
  90. package/dist/src/inference/inference-manager.d.ts +76 -0
  91. package/dist/src/inference/inference-manager.js +228 -0
  92. package/dist/src/metrics/index.d.ts +7 -0
  93. package/{src/metrics/index.ts → dist/src/metrics/index.js} +1 -1
  94. package/dist/src/metrics/metrics.d.ts +39 -0
  95. package/dist/src/metrics/metrics.js +129 -0
  96. package/dist/src/monitoring/alerting.d.ts +51 -0
  97. package/dist/src/monitoring/alerting.js +169 -0
  98. package/dist/src/monitoring/health.d.ts +40 -0
  99. package/dist/src/monitoring/health.js +164 -0
  100. package/dist/src/monitoring/index.d.ts +10 -0
  101. package/dist/src/monitoring/index.js +12 -0
  102. package/dist/src/monitoring/info.d.ts +15 -0
  103. package/dist/src/monitoring/info.js +109 -0
  104. package/dist/src/monitoring/types.d.ts +93 -0
  105. package/dist/src/monitoring/types.js +7 -0
  106. package/dist/src/network/index.d.ts +5 -0
  107. package/{src/network/index.ts → dist/src/network/index.js} +1 -1
  108. package/dist/src/network/network-config.d.ts +31 -0
  109. package/dist/src/network/network-config.js +109 -0
  110. package/dist/src/packaging/compiler.d.ts +61 -0
  111. package/dist/src/packaging/compiler.js +562 -0
  112. package/dist/src/packaging/config-persistence.d.ts +46 -0
  113. package/dist/src/packaging/config-persistence.js +108 -0
  114. package/dist/src/packaging/config-schemas.d.ts +115 -0
  115. package/dist/src/packaging/config-schemas.js +43 -0
  116. package/dist/src/packaging/detector.d.ts +26 -0
  117. package/dist/src/packaging/detector.js +193 -0
  118. package/dist/src/packaging/index.d.ts +16 -0
  119. package/dist/src/packaging/index.js +22 -0
  120. package/dist/src/packaging/packager.d.ts +31 -0
  121. package/dist/src/packaging/packager.js +90 -0
  122. package/dist/src/packaging/parsers/clawdbot.d.ts +19 -0
  123. package/dist/src/packaging/parsers/clawdbot.js +231 -0
  124. package/dist/src/packaging/parsers/cline.d.ts +26 -0
  125. package/dist/src/packaging/parsers/cline.js +185 -0
  126. package/dist/src/packaging/parsers/generic.d.ts +27 -0
  127. package/dist/src/packaging/parsers/generic.js +228 -0
  128. package/dist/src/packaging/parsers/goose.d.ts +26 -0
  129. package/dist/src/packaging/parsers/goose.js +175 -0
  130. package/dist/src/packaging/parsers/index.d.ts +11 -0
  131. package/{src/packaging/parsers/index.ts → dist/src/packaging/parsers/index.js} +1 -1
  132. package/dist/src/packaging/serializer.d.ts +108 -0
  133. package/dist/src/packaging/serializer.js +153 -0
  134. package/dist/src/packaging/types.d.ts +131 -0
  135. package/dist/src/packaging/types.js +5 -0
  136. package/dist/src/packaging/wasmedge-compiler.d.ts +76 -0
  137. package/dist/src/packaging/wasmedge-compiler.js +349 -0
  138. package/dist/src/security/index.d.ts +11 -0
  139. package/{src/security/index.ts → dist/src/security/index.js} +1 -4
  140. package/dist/src/security/multisig.d.ts +102 -0
  141. package/dist/src/security/multisig.js +283 -0
  142. package/dist/src/security/types.d.ts +207 -0
  143. package/dist/src/security/types.js +217 -0
  144. package/dist/src/security/vetkeys.d.ts +179 -0
  145. package/dist/src/security/vetkeys.js +499 -0
  146. package/dist/src/testing/index.d.ts +6 -0
  147. package/{src/testing/index.ts → dist/src/testing/index.js} +1 -1
  148. package/dist/src/testing/local-runner.d.ts +23 -0
  149. package/dist/src/testing/local-runner.js +226 -0
  150. package/dist/src/testing/types.d.ts +98 -0
  151. package/dist/src/testing/types.js +5 -0
  152. package/dist/src/wallet/cbor-serializer.d.ts +82 -0
  153. package/dist/src/wallet/cbor-serializer.js +282 -0
  154. package/dist/src/wallet/chain-dispatcher.d.ts +112 -0
  155. package/dist/src/wallet/chain-dispatcher.js +241 -0
  156. package/dist/src/wallet/cross-chain-aggregator.d.ts +119 -0
  157. package/dist/src/wallet/cross-chain-aggregator.js +235 -0
  158. package/dist/src/wallet/index.d.ts +16 -0
  159. package/dist/src/wallet/index.js +22 -0
  160. package/dist/src/wallet/key-derivation.d.ts +117 -0
  161. package/dist/src/wallet/key-derivation.js +325 -0
  162. package/dist/src/wallet/providers/base-provider.d.ts +111 -0
  163. package/dist/src/wallet/providers/base-provider.js +58 -0
  164. package/dist/src/wallet/providers/cketh-provider.d.ts +104 -0
  165. package/dist/src/wallet/providers/cketh-provider.js +343 -0
  166. package/dist/src/wallet/providers/polkadot-provider.d.ts +115 -0
  167. package/dist/src/wallet/providers/polkadot-provider.js +407 -0
  168. package/dist/src/wallet/providers/solana-provider.d.ts +102 -0
  169. package/dist/src/wallet/providers/solana-provider.js +393 -0
  170. package/dist/src/wallet/transaction-queue.d.ts +133 -0
  171. package/dist/src/wallet/transaction-queue.js +195 -0
  172. package/dist/src/wallet/types.d.ts +167 -0
  173. package/dist/src/wallet/types.js +5 -0
  174. package/dist/src/wallet/vetkeys-adapter.d.ts +134 -0
  175. package/dist/src/wallet/vetkeys-adapter.js +313 -0
  176. package/dist/src/wallet/wallet-manager.d.ts +202 -0
  177. package/dist/src/wallet/wallet-manager.js +451 -0
  178. package/dist/src/wallet/wallet-storage.d.ts +131 -0
  179. package/dist/src/wallet/wallet-storage.js +274 -0
  180. package/macos-wallet-app/AgentVaultWallet/App/AgentVaultWalletApp.swift +54 -0
  181. package/macos-wallet-app/AgentVaultWallet/Models/AppState.swift +102 -0
  182. package/macos-wallet-app/AgentVaultWallet/Models/Chain.swift +121 -0
  183. package/macos-wallet-app/AgentVaultWallet/Models/Wallet.swift +98 -0
  184. package/macos-wallet-app/AgentVaultWallet/Resources/AgentVaultWallet.entitlements +27 -0
  185. package/macos-wallet-app/AgentVaultWallet/Resources/Info.plist +69 -0
  186. package/macos-wallet-app/AgentVaultWallet/Services/BackupService.swift +270 -0
  187. package/macos-wallet-app/AgentVaultWallet/Services/CLIBridge.swift +367 -0
  188. package/macos-wallet-app/AgentVaultWallet/Services/CryptoService.swift +157 -0
  189. package/macos-wallet-app/AgentVaultWallet/Services/FileService.swift +120 -0
  190. package/macos-wallet-app/AgentVaultWallet/Services/KeychainService.swift +219 -0
  191. package/macos-wallet-app/AgentVaultWallet/Utilities/Constants.swift +44 -0
  192. package/macos-wallet-app/AgentVaultWallet/Utilities/Extensions.swift +115 -0
  193. package/macos-wallet-app/AgentVaultWallet/ViewModels/BackupViewModel.swift +237 -0
  194. package/macos-wallet-app/AgentVaultWallet/ViewModels/CreateWalletViewModel.swift +137 -0
  195. package/macos-wallet-app/AgentVaultWallet/ViewModels/ImportWalletViewModel.swift +179 -0
  196. package/macos-wallet-app/AgentVaultWallet/ViewModels/WalletStore.swift +286 -0
  197. package/macos-wallet-app/AgentVaultWallet/Views/Backup/BackupView.swift +235 -0
  198. package/macos-wallet-app/AgentVaultWallet/Views/Backup/RestoreView.swift +316 -0
  199. package/macos-wallet-app/AgentVaultWallet/Views/Create/CreateWalletFlow.swift +438 -0
  200. package/macos-wallet-app/AgentVaultWallet/Views/Import/ImportWalletFlow.swift +399 -0
  201. package/macos-wallet-app/AgentVaultWallet/Views/MainView.swift +134 -0
  202. package/macos-wallet-app/AgentVaultWallet/Views/Settings/SettingsView.swift +276 -0
  203. package/macos-wallet-app/AgentVaultWallet/Views/Sidebar/SidebarView.swift +133 -0
  204. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/DashboardView.swift +233 -0
  205. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/WalletDetailView.swift +281 -0
  206. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/WalletListView.swift +280 -0
  207. package/macos-wallet-app/AgentVaultWallet/Views/Welcome/WelcomeView.swift +176 -0
  208. package/macos-wallet-app/Makefile +47 -0
  209. package/macos-wallet-app/project.yml +40 -0
  210. package/macos-wallet-app/setup.sh +73 -0
  211. package/package.json +10 -2
  212. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-28-967Z.json +0 -28
  213. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-29-032Z.backup +0 -1
  214. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-373Z.json +0 -28
  215. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-428Z.backup +0 -1
  216. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-132Z.json +0 -28
  217. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-247Z.backup +0 -1
  218. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-216Z.json +0 -28
  219. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-283Z.backup +0 -1
  220. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-772Z.backup +0 -1
  221. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-793Z.json +0 -28
  222. package/backups/test-backup.json +0 -28
  223. package/scripts/dev-dashboard.mjs +0 -84
  224. package/site/README.md +0 -63
  225. package/site/docusaurus.config.ts +0 -148
  226. package/site/package-lock.json +0 -18383
  227. package/site/package.json +0 -47
  228. package/site/sidebars.ts +0 -86
  229. package/site/static/.gitkeep +0 -0
  230. package/site/static/img/logo.svg +0 -28
  231. package/site/static/img/og-image.svg +0 -35
  232. package/src/archival/archive-manager.ts +0 -372
  233. package/src/archival/arweave-client.ts +0 -289
  234. package/src/backup/backup.ts +0 -315
  235. package/src/cloud-storage/cloud-sync.ts +0 -461
  236. package/src/cloud-storage/provider-detector.ts +0 -198
  237. package/src/debugging/logs.ts +0 -193
  238. package/src/debugging/types.ts +0 -100
  239. package/src/deployment/deployer.ts +0 -274
  240. package/src/deployment/icpClient.ts +0 -620
  241. package/src/deployment/index.ts +0 -46
  242. package/src/deployment/promotion.ts +0 -161
  243. package/src/deployment/types.ts +0 -111
  244. package/src/icp/batch.ts +0 -374
  245. package/src/icp/environment.ts +0 -215
  246. package/src/icp/icpcli.ts +0 -438
  247. package/src/icp/icwasm.ts +0 -222
  248. package/src/icp/index.ts +0 -94
  249. package/src/icp/optimization.ts +0 -242
  250. package/src/icp/tool-detector.ts +0 -110
  251. package/src/icp/types.ts +0 -574
  252. package/src/index.ts +0 -25
  253. package/src/inference/bittensor-client.ts +0 -304
  254. package/src/inference/inference-manager.ts +0 -327
  255. package/src/metrics/metrics.ts +0 -186
  256. package/src/monitoring/alerting.ts +0 -190
  257. package/src/monitoring/health.ts +0 -197
  258. package/src/monitoring/index.ts +0 -38
  259. package/src/monitoring/info.ts +0 -114
  260. package/src/monitoring/types.ts +0 -99
  261. package/src/network/network-config.ts +0 -129
  262. package/src/packaging/compiler.ts +0 -647
  263. package/src/packaging/config-persistence.ts +0 -135
  264. package/src/packaging/config-schemas.ts +0 -156
  265. package/src/packaging/detector.ts +0 -220
  266. package/src/packaging/index.ts +0 -90
  267. package/src/packaging/packager.ts +0 -118
  268. package/src/packaging/parsers/clawdbot.ts +0 -278
  269. package/src/packaging/parsers/cline.ts +0 -223
  270. package/src/packaging/parsers/generic.ts +0 -266
  271. package/src/packaging/parsers/goose.ts +0 -214
  272. package/src/packaging/serializer.ts +0 -260
  273. package/src/packaging/types.ts +0 -144
  274. package/src/packaging/wasmedge-compiler.ts +0 -406
  275. package/src/security/multisig.ts +0 -415
  276. package/src/security/types.ts +0 -416
  277. package/src/security/vetkeys.ts +0 -655
  278. package/src/testing/local-runner.ts +0 -264
  279. package/src/testing/types.ts +0 -104
  280. package/src/wallet/cbor-serializer.ts +0 -323
  281. package/src/wallet/chain-dispatcher.ts +0 -313
  282. package/src/wallet/cross-chain-aggregator.ts +0 -346
  283. package/src/wallet/index.ts +0 -76
  284. package/src/wallet/key-derivation.ts +0 -425
  285. package/src/wallet/providers/base-provider.ts +0 -154
  286. package/src/wallet/providers/cketh-provider.ts +0 -434
  287. package/src/wallet/providers/polkadot-provider.ts +0 -503
  288. package/src/wallet/providers/solana-provider.ts +0 -490
  289. package/src/wallet/transaction-queue.ts +0 -284
  290. package/src/wallet/types.ts +0 -178
  291. package/src/wallet/vetkeys-adapter.ts +0 -431
  292. package/src/wallet/wallet-manager.ts +0 -597
  293. package/src/wallet/wallet-storage.ts +0 -380
@@ -0,0 +1,399 @@
1
+ import SwiftUI
2
+ import UniformTypeIdentifiers
3
+
4
+ /// Multi-step wizard for importing an existing wallet
5
+ struct ImportWalletFlow: View {
6
+ @EnvironmentObject var walletStore: WalletStore
7
+ @EnvironmentObject var appState: AppState
8
+ @StateObject private var vm = ImportWalletViewModel()
9
+ @Environment(\.dismiss) private var dismiss
10
+
11
+ var body: some View {
12
+ VStack(spacing: 0) {
13
+ header
14
+ Divider()
15
+
16
+ ScrollView {
17
+ stepContent
18
+ .padding(24)
19
+ .frame(maxWidth: .infinity)
20
+ }
21
+
22
+ Divider()
23
+ footer
24
+ }
25
+ .background(.background)
26
+ .fileImporter(
27
+ isPresented: $vm.showFileImporter,
28
+ allowedContentTypes: vm.allowedFileTypes,
29
+ allowsMultipleSelection: false
30
+ ) { result in
31
+ switch result {
32
+ case .success(let urls):
33
+ vm.selectedFileURL = urls.first
34
+ case .failure(let error):
35
+ vm.errorMessage = error.localizedDescription
36
+ }
37
+ }
38
+ }
39
+
40
+ private var header: some View {
41
+ VStack(spacing: 12) {
42
+ Text("Import Wallet")
43
+ .font(.title2.bold())
44
+
45
+ HStack(spacing: 4) {
46
+ ForEach(0..<5) { step in
47
+ RoundedRectangle(cornerRadius: 2)
48
+ .fill(step <= vm.currentStep.rawValue ? Color.accentColor : Color.secondary.opacity(0.2))
49
+ .frame(height: 3)
50
+ }
51
+ }
52
+ .padding(.horizontal, 32)
53
+
54
+ Text(vm.currentStep.title)
55
+ .font(.subheadline)
56
+ .foregroundStyle(.secondary)
57
+ }
58
+ .padding(.top, 20)
59
+ .padding(.bottom, 12)
60
+ }
61
+
62
+ @ViewBuilder
63
+ private var stepContent: some View {
64
+ switch vm.currentStep {
65
+ case .selectChain:
66
+ ChainPickerView(selectedChain: $vm.selectedChain)
67
+
68
+ case .selectMethod:
69
+ ImportMethodPickerView(
70
+ methods: vm.availableMethods,
71
+ selected: $vm.selectedMethod
72
+ )
73
+
74
+ case .enterInput:
75
+ ImportInputView(vm: vm)
76
+
77
+ case .nameWallet:
78
+ WalletNameInputView(
79
+ name: $vm.walletName,
80
+ chain: vm.selectedChain,
81
+ defaultName: "\(vm.selectedChain.displayName) Import"
82
+ )
83
+
84
+ case .importing:
85
+ VStack(spacing: 20) {
86
+ ProgressView()
87
+ .scaleEffect(1.5)
88
+ Text("Importing your \(vm.selectedChain.displayName) wallet...")
89
+ .foregroundStyle(.secondary)
90
+ }
91
+ .frame(maxWidth: .infinity, minHeight: 200)
92
+
93
+ case .complete:
94
+ ImportCompleteView(wallet: vm.importedWallet, chain: vm.selectedChain)
95
+ }
96
+
97
+ if let error = vm.errorMessage {
98
+ HStack {
99
+ Image(systemName: "exclamationmark.triangle.fill")
100
+ .foregroundStyle(.red)
101
+ Text(error)
102
+ .font(.callout)
103
+ .foregroundStyle(.red)
104
+ }
105
+ .padding()
106
+ .background(.red.opacity(0.1), in: RoundedRectangle(cornerRadius: 8))
107
+ }
108
+ }
109
+
110
+ private var footer: some View {
111
+ HStack {
112
+ if vm.currentStep.rawValue > 0 && vm.currentStep != .importing && vm.currentStep != .complete {
113
+ Button("Back") { vm.goBack() }
114
+ .buttonStyle(.bordered)
115
+ }
116
+
117
+ Spacer()
118
+
119
+ if vm.currentStep == .complete {
120
+ Button("Done") { dismiss() }
121
+ .buttonStyle(.borderedProminent)
122
+ } else if vm.currentStep == .importing {
123
+ // No buttons during import
124
+ } else if vm.currentStep == .nameWallet {
125
+ HStack(spacing: 12) {
126
+ Button("Cancel") { dismiss() }
127
+ .buttonStyle(.bordered)
128
+
129
+ Button("Import") {
130
+ Task { await vm.importWallet(store: walletStore) }
131
+ }
132
+ .buttonStyle(.borderedProminent)
133
+ .disabled(!vm.canProceed)
134
+ }
135
+ } else {
136
+ HStack(spacing: 12) {
137
+ Button("Cancel") { dismiss() }
138
+ .buttonStyle(.bordered)
139
+
140
+ Button("Next") { vm.goToNext() }
141
+ .buttonStyle(.borderedProminent)
142
+ .disabled(!vm.canProceed)
143
+ }
144
+ }
145
+ }
146
+ .padding(16)
147
+ }
148
+ }
149
+
150
+ // MARK: - Import Method Picker
151
+
152
+ struct ImportMethodPickerView: View {
153
+ let methods: [ImportMethod]
154
+ @Binding var selected: ImportMethod
155
+
156
+ var body: some View {
157
+ VStack(spacing: 16) {
158
+ Text("How would you like to import?")
159
+ .font(.headline)
160
+
161
+ VStack(spacing: 10) {
162
+ ForEach(methods) { method in
163
+ ImportMethodCard(method: method, isSelected: selected == method)
164
+ .onTapGesture { selected = method }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ struct ImportMethodCard: View {
172
+ let method: ImportMethod
173
+ let isSelected: Bool
174
+
175
+ var body: some View {
176
+ HStack(spacing: 14) {
177
+ Image(systemName: method.iconName)
178
+ .font(.title3)
179
+ .foregroundStyle(isSelected ? .accentColor : .secondary)
180
+ .frame(width: 32)
181
+
182
+ VStack(alignment: .leading, spacing: 3) {
183
+ Text(method.displayName)
184
+ .font(.headline)
185
+ Text(method.description)
186
+ .font(.caption)
187
+ .foregroundStyle(.secondary)
188
+ }
189
+
190
+ Spacer()
191
+
192
+ if isSelected {
193
+ Image(systemName: "checkmark.circle.fill")
194
+ .foregroundStyle(.accentColor)
195
+ }
196
+ }
197
+ .padding(14)
198
+ .background(
199
+ RoundedRectangle(cornerRadius: 10)
200
+ .fill(isSelected ? Color.accentColor.opacity(0.08) : Color.clear)
201
+ )
202
+ .overlay(
203
+ RoundedRectangle(cornerRadius: 10)
204
+ .stroke(isSelected ? Color.accentColor : Color.secondary.opacity(0.2), lineWidth: isSelected ? 2 : 1)
205
+ )
206
+ }
207
+ }
208
+
209
+ // MARK: - Import Input
210
+
211
+ struct ImportInputView: View {
212
+ @ObservedObject var vm: ImportWalletViewModel
213
+
214
+ var body: some View {
215
+ VStack(spacing: 20) {
216
+ switch vm.selectedMethod {
217
+ case .mnemonic:
218
+ mnemonicInput
219
+
220
+ case .privateKey:
221
+ privateKeyInput
222
+
223
+ case .jwkFile, .pemFile, .keystoreJSON:
224
+ fileInput
225
+ }
226
+ }
227
+ }
228
+
229
+ private var mnemonicInput: some View {
230
+ VStack(spacing: 16) {
231
+ Text("Enter Recovery Phrase")
232
+ .font(.headline)
233
+
234
+ Text("Type or paste your 12 or 24-word recovery phrase below.")
235
+ .font(.callout)
236
+ .foregroundStyle(.secondary)
237
+ .multilineTextAlignment(.center)
238
+
239
+ TextEditor(text: $vm.inputText)
240
+ .font(.system(.body, design: .monospaced))
241
+ .frame(height: 100)
242
+ .padding(8)
243
+ .background(
244
+ RoundedRectangle(cornerRadius: 8)
245
+ .stroke(Color.secondary.opacity(0.3))
246
+ )
247
+ .overlay(alignment: .topLeading) {
248
+ if vm.inputText.isEmpty {
249
+ Text(vm.inputPlaceholder)
250
+ .font(.system(.body, design: .monospaced))
251
+ .foregroundStyle(.tertiary)
252
+ .padding(12)
253
+ .allowsHitTesting(false)
254
+ }
255
+ }
256
+
257
+ // Word count indicator
258
+ let wordCount = vm.inputText
259
+ .trimmingCharacters(in: .whitespacesAndNewlines)
260
+ .components(separatedBy: .whitespaces)
261
+ .filter { !$0.isEmpty }
262
+ .count
263
+
264
+ HStack {
265
+ Text("\(wordCount) words")
266
+ .font(.caption)
267
+ .foregroundStyle(wordCount == 12 || wordCount == 24 ? .green : .secondary)
268
+
269
+ Spacer()
270
+
271
+ if wordCount > 0 && wordCount != 12 && wordCount != 24 {
272
+ Text("Expected 12 or 24 words")
273
+ .font(.caption)
274
+ .foregroundStyle(.orange)
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ private var privateKeyInput: some View {
281
+ VStack(spacing: 16) {
282
+ Text("Enter Private Key")
283
+ .font(.headline)
284
+
285
+ Text("Paste your private key below. It will be stored securely in your Mac's Keychain.")
286
+ .font(.callout)
287
+ .foregroundStyle(.secondary)
288
+ .multilineTextAlignment(.center)
289
+
290
+ SecureField(vm.inputPlaceholder, text: $vm.inputText)
291
+ .textFieldStyle(.roundedBorder)
292
+ .font(.system(.body, design: .monospaced))
293
+
294
+ HStack {
295
+ Image(systemName: "lock.fill")
296
+ .foregroundStyle(.green)
297
+ .font(.caption)
298
+ Text("Your private key is encrypted in the macOS Keychain")
299
+ .font(.caption)
300
+ .foregroundStyle(.secondary)
301
+ }
302
+ }
303
+ }
304
+
305
+ private var fileInput: some View {
306
+ VStack(spacing: 16) {
307
+ Text("Select \(vm.selectedMethod.displayName)")
308
+ .font(.headline)
309
+
310
+ if let url = vm.selectedFileURL {
311
+ HStack {
312
+ Image(systemName: "doc.fill")
313
+ .foregroundStyle(.accentColor)
314
+ Text(url.lastPathComponent)
315
+ .lineLimit(1)
316
+ .truncationMode(.middle)
317
+
318
+ Spacer()
319
+
320
+ Button("Change") {
321
+ vm.showFileImporter = true
322
+ }
323
+ .buttonStyle(.bordered)
324
+ .controlSize(.small)
325
+ }
326
+ .padding()
327
+ .background(.quaternary, in: RoundedRectangle(cornerRadius: 8))
328
+ } else {
329
+ Button {
330
+ vm.showFileImporter = true
331
+ } label: {
332
+ VStack(spacing: 12) {
333
+ Image(systemName: "doc.badge.plus")
334
+ .font(.system(size: 36))
335
+ .foregroundStyle(.secondary)
336
+ Text("Click to select a file")
337
+ .font(.callout)
338
+ .foregroundStyle(.secondary)
339
+ Text(vm.selectedMethod.description)
340
+ .font(.caption)
341
+ .foregroundStyle(.tertiary)
342
+ }
343
+ .frame(maxWidth: .infinity, minHeight: 120)
344
+ .background(
345
+ RoundedRectangle(cornerRadius: 12, style: .continuous)
346
+ .strokeBorder(style: StrokeStyle(lineWidth: 2, dash: [8, 4]))
347
+ .foregroundStyle(.secondary.opacity(0.3))
348
+ )
349
+ }
350
+ .buttonStyle(.plain)
351
+ }
352
+
353
+ // Password field for keystore files
354
+ if vm.selectedMethod == .keystoreJSON {
355
+ VStack(alignment: .leading, spacing: 8) {
356
+ Text("Keystore Password")
357
+ .font(.callout.bold())
358
+ SecureField("Enter the password for this keystore file", text: $vm.passwordInput)
359
+ .textFieldStyle(.roundedBorder)
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+
366
+ // MARK: - Import Complete
367
+
368
+ struct ImportCompleteView: View {
369
+ let wallet: Wallet?
370
+ let chain: Chain
371
+
372
+ var body: some View {
373
+ VStack(spacing: 20) {
374
+ Image(systemName: "checkmark.circle.fill")
375
+ .font(.system(size: 56))
376
+ .foregroundStyle(.green)
377
+
378
+ Text("Wallet Imported!")
379
+ .font(.title2.bold())
380
+
381
+ if let wallet = wallet {
382
+ VStack(spacing: 12) {
383
+ InfoRow(label: "Network", value: chain.displayName)
384
+ InfoRow(label: "Name", value: wallet.name)
385
+ InfoRow(label: "Address", value: wallet.shortAddress)
386
+ }
387
+ .padding()
388
+ .background(.quaternary.opacity(0.5), in: RoundedRectangle(cornerRadius: 12))
389
+
390
+ Button("Copy Address") {
391
+ NSPasteboard.general.clearContents()
392
+ NSPasteboard.general.setString(wallet.address, forType: .string)
393
+ }
394
+ .buttonStyle(.bordered)
395
+ .controlSize(.small)
396
+ }
397
+ }
398
+ }
399
+ }
@@ -0,0 +1,134 @@
1
+ import SwiftUI
2
+
3
+ /// Root view with sidebar navigation and main content area
4
+ struct MainView: View {
5
+ @EnvironmentObject var walletStore: WalletStore
6
+ @EnvironmentObject var appState: AppState
7
+
8
+ var body: some View {
9
+ Group {
10
+ if appState.isFirstLaunch {
11
+ WelcomeView()
12
+ } else {
13
+ NavigationSplitView {
14
+ SidebarView()
15
+ } detail: {
16
+ detailView
17
+ }
18
+ .sheet(item: $appState.activeSheet) { sheet in
19
+ sheetContent(for: sheet)
20
+ }
21
+ .alert(item: $appState.alert) { alert in
22
+ Alert(
23
+ title: Text(alert.title),
24
+ message: Text(alert.message),
25
+ dismissButton: .default(Text("OK"))
26
+ )
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ @ViewBuilder
33
+ private var detailView: some View {
34
+ switch appState.selectedDestination {
35
+ case .dashboard:
36
+ DashboardView()
37
+ case .walletList:
38
+ WalletListView()
39
+ case .walletDetail(let id):
40
+ if let wallet = walletStore.wallets.first(where: { $0.id == id }) {
41
+ WalletDetailView(wallet: wallet)
42
+ } else {
43
+ ContentUnavailableView("Wallet Not Found",
44
+ systemImage: "wallet.pass",
45
+ description: Text("This wallet may have been deleted."))
46
+ }
47
+ case .backup:
48
+ BackupRestoreView()
49
+ case .settings:
50
+ SettingsView()
51
+ }
52
+ }
53
+
54
+ @ViewBuilder
55
+ private func sheetContent(for sheet: ActiveSheet) -> some View {
56
+ switch sheet {
57
+ case .createWallet:
58
+ CreateWalletFlow()
59
+ .frame(width: 560, height: 520)
60
+ case .importWallet:
61
+ ImportWalletFlow()
62
+ .frame(width: 560, height: 520)
63
+ case .backup:
64
+ BackupView()
65
+ .frame(width: 520, height: 480)
66
+ case .restore:
67
+ RestoreView()
68
+ .frame(width: 520, height: 480)
69
+ case .walletDetail(let wallet):
70
+ WalletDetailView(wallet: wallet)
71
+ .frame(width: 500, height: 400)
72
+ case .mnemonicReveal(let id):
73
+ if let wallet = walletStore.wallets.first(where: { $0.id == id }) {
74
+ MnemonicRevealSheet(wallet: wallet)
75
+ .frame(width: 480, height: 400)
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ /// Mnemonic reveal sheet with security confirmation
82
+ struct MnemonicRevealSheet: View {
83
+ let wallet: Wallet
84
+ @EnvironmentObject var walletStore: WalletStore
85
+ @Environment(\.dismiss) private var dismiss
86
+ @State private var confirmed = false
87
+ @State private var mnemonic: String?
88
+
89
+ var body: some View {
90
+ VStack(spacing: 20) {
91
+ Image(systemName: "exclamationmark.shield.fill")
92
+ .font(.system(size: 40))
93
+ .foregroundStyle(.orange)
94
+
95
+ Text("Reveal Recovery Phrase")
96
+ .font(.title2.bold())
97
+
98
+ Text("Your recovery phrase gives full access to this wallet. Never share it with anyone.")
99
+ .font(.body)
100
+ .foregroundStyle(.secondary)
101
+ .multilineTextAlignment(.center)
102
+ .padding(.horizontal)
103
+
104
+ if let mnemonic = mnemonic {
105
+ MnemonicGridView(words: mnemonic.components(separatedBy: " "))
106
+ .padding()
107
+
108
+ Button("Copy to Clipboard") {
109
+ NSPasteboard.general.clearContents()
110
+ NSPasteboard.general.setString(mnemonic, forType: .string)
111
+
112
+ // Auto-clear clipboard after 60 seconds
113
+ DispatchQueue.main.asyncAfter(deadline: .now() + 60) {
114
+ NSPasteboard.general.clearContents()
115
+ }
116
+ }
117
+ .buttonStyle(.bordered)
118
+ } else {
119
+ Toggle("I understand the risks of revealing my recovery phrase", isOn: $confirmed)
120
+ .padding(.horizontal)
121
+
122
+ Button("Reveal Phrase") {
123
+ mnemonic = walletStore.getMnemonic(for: wallet)
124
+ }
125
+ .buttonStyle(.borderedProminent)
126
+ .disabled(!confirmed)
127
+ }
128
+
129
+ Button("Close") { dismiss() }
130
+ .buttonStyle(.bordered)
131
+ }
132
+ .padding(24)
133
+ }
134
+ }