agentvault 1.0.1 → 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 (292) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/dist/cli/commands/approve.js +5 -5
  3. package/dist/cli/commands/archive.js +5 -5
  4. package/dist/cli/commands/backup.js +5 -5
  5. package/dist/cli/commands/cloud-backup.js +12 -12
  6. package/dist/cli/commands/decrypt.js +2 -2
  7. package/dist/cli/commands/deploy.js +1 -1
  8. package/dist/cli/commands/exec.js +2 -2
  9. package/dist/cli/commands/fetch.js +4 -4
  10. package/dist/cli/commands/inference.js +5 -5
  11. package/dist/cli/commands/init.d.ts +1 -1
  12. package/dist/cli/commands/init.js +16 -16
  13. package/dist/cli/commands/list.js +4 -4
  14. package/dist/cli/commands/package.js +2 -2
  15. package/dist/cli/commands/profile.js +1 -1
  16. package/dist/cli/commands/rebuild.js +2 -2
  17. package/dist/cli/commands/show.js +1 -1
  18. package/dist/cli/commands/status.d.ts +1 -1
  19. package/dist/cli/commands/status.js +8 -8
  20. package/dist/cli/commands/trace.js +1 -1
  21. package/dist/cli/commands/wallet-export.js +1 -1
  22. package/dist/cli/commands/wallet-sign.js +1 -1
  23. package/dist/cli/commands/wallet.d.ts +1 -1
  24. package/dist/cli/commands/wallet.js +1 -1
  25. package/dist/cli/index.d.ts +2 -2
  26. package/dist/cli/index.js +3 -3
  27. package/dist/src/archival/archive-manager.d.ts +85 -0
  28. package/dist/src/archival/archive-manager.js +294 -0
  29. package/dist/src/archival/arweave-client.d.ts +88 -0
  30. package/dist/src/archival/arweave-client.js +223 -0
  31. package/dist/src/archival/index.d.ts +8 -0
  32. package/{src/archival/index.ts → dist/src/archival/index.js} +1 -1
  33. package/dist/src/backup/backup.d.ts +67 -0
  34. package/dist/src/backup/backup.js +231 -0
  35. package/dist/src/backup/index.d.ts +7 -0
  36. package/{src/backup/index.ts → dist/src/backup/index.js} +1 -1
  37. package/dist/src/cloud-storage/cloud-sync.d.ts +49 -0
  38. package/dist/src/cloud-storage/cloud-sync.js +372 -0
  39. package/dist/src/cloud-storage/index.d.ts +11 -0
  40. package/{src/cloud-storage/index.ts → dist/src/cloud-storage/index.js} +1 -1
  41. package/dist/src/cloud-storage/provider-detector.d.ts +34 -0
  42. package/dist/src/cloud-storage/provider-detector.js +158 -0
  43. package/{src/cloud-storage/types.ts → dist/src/cloud-storage/types.d.ts} +40 -53
  44. package/dist/src/cloud-storage/types.js +10 -0
  45. package/dist/src/debugging/index.d.ts +6 -0
  46. package/{src/debugging/index.ts → dist/src/debugging/index.js} +1 -1
  47. package/dist/src/debugging/logs.d.ts +32 -0
  48. package/dist/src/debugging/logs.js +158 -0
  49. package/dist/src/debugging/types.d.ts +91 -0
  50. package/dist/src/debugging/types.js +5 -0
  51. package/dist/src/deployment/deployer.d.ts +52 -0
  52. package/dist/src/deployment/deployer.js +211 -0
  53. package/dist/src/deployment/icpClient.d.ts +144 -0
  54. package/dist/src/deployment/icpClient.js +545 -0
  55. package/dist/src/deployment/index.d.ts +11 -0
  56. package/dist/src/deployment/index.js +14 -0
  57. package/dist/src/deployment/promotion.d.ts +32 -0
  58. package/dist/src/deployment/promotion.js +114 -0
  59. package/dist/src/deployment/types.d.ts +101 -0
  60. package/dist/src/deployment/types.js +5 -0
  61. package/dist/src/icp/batch.d.ts +112 -0
  62. package/dist/src/icp/batch.js +273 -0
  63. package/dist/src/icp/cycles.d.ts +29 -0
  64. package/{src/icp/cycles.ts → dist/src/icp/cycles.js} +8 -22
  65. package/dist/src/icp/environment.d.ts +60 -0
  66. package/dist/src/icp/environment.js +183 -0
  67. package/dist/src/icp/icpcli.d.ts +204 -0
  68. package/dist/src/icp/icpcli.js +374 -0
  69. package/dist/src/icp/icwasm.d.ts +94 -0
  70. package/dist/src/icp/icwasm.js +197 -0
  71. package/dist/src/icp/identity.d.ts +50 -0
  72. package/{src/icp/identity.ts → dist/src/icp/identity.js} +15 -28
  73. package/dist/src/icp/index.d.ts +16 -0
  74. package/dist/src/icp/index.js +20 -0
  75. package/dist/src/icp/optimization.d.ts +16 -0
  76. package/dist/src/icp/optimization.js +225 -0
  77. package/dist/src/icp/tokens.d.ts +24 -0
  78. package/{src/icp/tokens.ts → dist/src/icp/tokens.js} +5 -12
  79. package/dist/src/icp/tool-detector.d.ts +31 -0
  80. package/dist/src/icp/tool-detector.js +104 -0
  81. package/dist/src/icp/types.d.ts +493 -0
  82. package/dist/src/icp/types.js +7 -0
  83. package/dist/src/index.d.ts +12 -0
  84. package/dist/src/index.js +18 -0
  85. package/dist/src/inference/bittensor-client.d.ts +108 -0
  86. package/dist/src/inference/bittensor-client.js +224 -0
  87. package/dist/src/inference/index.d.ts +8 -0
  88. package/{src/inference/index.ts → dist/src/inference/index.js} +1 -1
  89. package/dist/src/inference/inference-manager.d.ts +76 -0
  90. package/dist/src/inference/inference-manager.js +228 -0
  91. package/dist/src/metrics/index.d.ts +7 -0
  92. package/{src/metrics/index.ts → dist/src/metrics/index.js} +1 -1
  93. package/dist/src/metrics/metrics.d.ts +39 -0
  94. package/dist/src/metrics/metrics.js +129 -0
  95. package/dist/src/monitoring/alerting.d.ts +51 -0
  96. package/dist/src/monitoring/alerting.js +169 -0
  97. package/dist/src/monitoring/health.d.ts +40 -0
  98. package/dist/src/monitoring/health.js +164 -0
  99. package/dist/src/monitoring/index.d.ts +10 -0
  100. package/dist/src/monitoring/index.js +12 -0
  101. package/dist/src/monitoring/info.d.ts +15 -0
  102. package/dist/src/monitoring/info.js +109 -0
  103. package/dist/src/monitoring/types.d.ts +93 -0
  104. package/dist/src/monitoring/types.js +7 -0
  105. package/dist/src/network/index.d.ts +5 -0
  106. package/{src/network/index.ts → dist/src/network/index.js} +1 -1
  107. package/dist/src/network/network-config.d.ts +31 -0
  108. package/dist/src/network/network-config.js +109 -0
  109. package/dist/src/packaging/compiler.d.ts +61 -0
  110. package/dist/src/packaging/compiler.js +562 -0
  111. package/dist/src/packaging/config-persistence.d.ts +46 -0
  112. package/dist/src/packaging/config-persistence.js +108 -0
  113. package/dist/src/packaging/config-schemas.d.ts +115 -0
  114. package/dist/src/packaging/config-schemas.js +43 -0
  115. package/dist/src/packaging/detector.d.ts +26 -0
  116. package/dist/src/packaging/detector.js +193 -0
  117. package/dist/src/packaging/index.d.ts +16 -0
  118. package/dist/src/packaging/index.js +22 -0
  119. package/dist/src/packaging/packager.d.ts +31 -0
  120. package/dist/src/packaging/packager.js +90 -0
  121. package/dist/src/packaging/parsers/clawdbot.d.ts +19 -0
  122. package/dist/src/packaging/parsers/clawdbot.js +231 -0
  123. package/dist/src/packaging/parsers/cline.d.ts +26 -0
  124. package/dist/src/packaging/parsers/cline.js +185 -0
  125. package/dist/src/packaging/parsers/generic.d.ts +27 -0
  126. package/dist/src/packaging/parsers/generic.js +228 -0
  127. package/dist/src/packaging/parsers/goose.d.ts +26 -0
  128. package/dist/src/packaging/parsers/goose.js +175 -0
  129. package/dist/src/packaging/parsers/index.d.ts +11 -0
  130. package/{src/packaging/parsers/index.ts → dist/src/packaging/parsers/index.js} +1 -1
  131. package/dist/src/packaging/serializer.d.ts +108 -0
  132. package/dist/src/packaging/serializer.js +153 -0
  133. package/dist/src/packaging/types.d.ts +131 -0
  134. package/dist/src/packaging/types.js +5 -0
  135. package/dist/src/packaging/wasmedge-compiler.d.ts +76 -0
  136. package/dist/src/packaging/wasmedge-compiler.js +349 -0
  137. package/dist/src/security/index.d.ts +11 -0
  138. package/{src/security/index.ts → dist/src/security/index.js} +1 -4
  139. package/dist/src/security/multisig.d.ts +102 -0
  140. package/dist/src/security/multisig.js +283 -0
  141. package/dist/src/security/types.d.ts +207 -0
  142. package/dist/src/security/types.js +217 -0
  143. package/dist/src/security/vetkeys.d.ts +179 -0
  144. package/dist/src/security/vetkeys.js +499 -0
  145. package/dist/src/testing/index.d.ts +6 -0
  146. package/{src/testing/index.ts → dist/src/testing/index.js} +1 -1
  147. package/dist/src/testing/local-runner.d.ts +23 -0
  148. package/dist/src/testing/local-runner.js +226 -0
  149. package/dist/src/testing/types.d.ts +98 -0
  150. package/dist/src/testing/types.js +5 -0
  151. package/dist/src/wallet/cbor-serializer.d.ts +82 -0
  152. package/dist/src/wallet/cbor-serializer.js +282 -0
  153. package/dist/src/wallet/chain-dispatcher.d.ts +112 -0
  154. package/dist/src/wallet/chain-dispatcher.js +241 -0
  155. package/dist/src/wallet/cross-chain-aggregator.d.ts +119 -0
  156. package/dist/src/wallet/cross-chain-aggregator.js +235 -0
  157. package/dist/src/wallet/index.d.ts +16 -0
  158. package/dist/src/wallet/index.js +22 -0
  159. package/dist/src/wallet/key-derivation.d.ts +117 -0
  160. package/dist/src/wallet/key-derivation.js +325 -0
  161. package/dist/src/wallet/providers/base-provider.d.ts +111 -0
  162. package/dist/src/wallet/providers/base-provider.js +58 -0
  163. package/dist/src/wallet/providers/cketh-provider.d.ts +104 -0
  164. package/dist/src/wallet/providers/cketh-provider.js +343 -0
  165. package/dist/src/wallet/providers/polkadot-provider.d.ts +115 -0
  166. package/dist/src/wallet/providers/polkadot-provider.js +407 -0
  167. package/dist/src/wallet/providers/solana-provider.d.ts +102 -0
  168. package/dist/src/wallet/providers/solana-provider.js +393 -0
  169. package/dist/src/wallet/transaction-queue.d.ts +133 -0
  170. package/dist/src/wallet/transaction-queue.js +195 -0
  171. package/dist/src/wallet/types.d.ts +167 -0
  172. package/dist/src/wallet/types.js +5 -0
  173. package/dist/src/wallet/vetkeys-adapter.d.ts +134 -0
  174. package/dist/src/wallet/vetkeys-adapter.js +313 -0
  175. package/dist/src/wallet/wallet-manager.d.ts +202 -0
  176. package/dist/src/wallet/wallet-manager.js +451 -0
  177. package/dist/src/wallet/wallet-storage.d.ts +131 -0
  178. package/dist/src/wallet/wallet-storage.js +274 -0
  179. package/macos-wallet-app/AgentVaultWallet/App/AgentVaultWalletApp.swift +54 -0
  180. package/macos-wallet-app/AgentVaultWallet/Models/AppState.swift +102 -0
  181. package/macos-wallet-app/AgentVaultWallet/Models/Chain.swift +121 -0
  182. package/macos-wallet-app/AgentVaultWallet/Models/Wallet.swift +98 -0
  183. package/macos-wallet-app/AgentVaultWallet/Resources/AgentVaultWallet.entitlements +27 -0
  184. package/macos-wallet-app/AgentVaultWallet/Resources/Info.plist +69 -0
  185. package/macos-wallet-app/AgentVaultWallet/Services/BackupService.swift +270 -0
  186. package/macos-wallet-app/AgentVaultWallet/Services/CLIBridge.swift +367 -0
  187. package/macos-wallet-app/AgentVaultWallet/Services/CryptoService.swift +157 -0
  188. package/macos-wallet-app/AgentVaultWallet/Services/FileService.swift +120 -0
  189. package/macos-wallet-app/AgentVaultWallet/Services/KeychainService.swift +219 -0
  190. package/macos-wallet-app/AgentVaultWallet/Utilities/Constants.swift +44 -0
  191. package/macos-wallet-app/AgentVaultWallet/Utilities/Extensions.swift +115 -0
  192. package/macos-wallet-app/AgentVaultWallet/ViewModels/BackupViewModel.swift +237 -0
  193. package/macos-wallet-app/AgentVaultWallet/ViewModels/CreateWalletViewModel.swift +137 -0
  194. package/macos-wallet-app/AgentVaultWallet/ViewModels/ImportWalletViewModel.swift +179 -0
  195. package/macos-wallet-app/AgentVaultWallet/ViewModels/WalletStore.swift +286 -0
  196. package/macos-wallet-app/AgentVaultWallet/Views/Backup/BackupView.swift +235 -0
  197. package/macos-wallet-app/AgentVaultWallet/Views/Backup/RestoreView.swift +316 -0
  198. package/macos-wallet-app/AgentVaultWallet/Views/Create/CreateWalletFlow.swift +438 -0
  199. package/macos-wallet-app/AgentVaultWallet/Views/Import/ImportWalletFlow.swift +399 -0
  200. package/macos-wallet-app/AgentVaultWallet/Views/MainView.swift +134 -0
  201. package/macos-wallet-app/AgentVaultWallet/Views/Settings/SettingsView.swift +276 -0
  202. package/macos-wallet-app/AgentVaultWallet/Views/Sidebar/SidebarView.swift +133 -0
  203. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/DashboardView.swift +233 -0
  204. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/WalletDetailView.swift +281 -0
  205. package/macos-wallet-app/AgentVaultWallet/Views/Wallet/WalletListView.swift +280 -0
  206. package/macos-wallet-app/AgentVaultWallet/Views/Welcome/WelcomeView.swift +176 -0
  207. package/macos-wallet-app/Makefile +47 -0
  208. package/macos-wallet-app/project.yml +40 -0
  209. package/macos-wallet-app/setup.sh +73 -0
  210. package/package.json +10 -2
  211. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-28-967Z.json +0 -28
  212. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-29-032Z.backup +0 -1
  213. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-373Z.json +0 -28
  214. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-428Z.backup +0 -1
  215. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-132Z.json +0 -28
  216. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-247Z.backup +0 -1
  217. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-216Z.json +0 -28
  218. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-283Z.backup +0 -1
  219. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-772Z.backup +0 -1
  220. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-793Z.json +0 -28
  221. package/backups/test-backup.json +0 -28
  222. package/scripts/dev-dashboard.mjs +0 -84
  223. package/site/README.md +0 -63
  224. package/site/docusaurus.config.ts +0 -148
  225. package/site/package-lock.json +0 -18383
  226. package/site/package.json +0 -47
  227. package/site/sidebars.ts +0 -86
  228. package/site/static/.gitkeep +0 -0
  229. package/site/static/img/logo.svg +0 -28
  230. package/site/static/img/og-image.svg +0 -35
  231. package/src/archival/archive-manager.ts +0 -372
  232. package/src/archival/arweave-client.ts +0 -289
  233. package/src/backup/backup.ts +0 -315
  234. package/src/cloud-storage/cloud-sync.ts +0 -461
  235. package/src/cloud-storage/provider-detector.ts +0 -198
  236. package/src/debugging/logs.ts +0 -193
  237. package/src/debugging/types.ts +0 -100
  238. package/src/deployment/deployer.ts +0 -274
  239. package/src/deployment/icpClient.ts +0 -620
  240. package/src/deployment/index.ts +0 -46
  241. package/src/deployment/promotion.ts +0 -161
  242. package/src/deployment/types.ts +0 -111
  243. package/src/icp/batch.ts +0 -374
  244. package/src/icp/environment.ts +0 -215
  245. package/src/icp/icpcli.ts +0 -438
  246. package/src/icp/icwasm.ts +0 -222
  247. package/src/icp/index.ts +0 -94
  248. package/src/icp/optimization.ts +0 -242
  249. package/src/icp/tool-detector.ts +0 -110
  250. package/src/icp/types.ts +0 -574
  251. package/src/index.ts +0 -25
  252. package/src/inference/bittensor-client.ts +0 -304
  253. package/src/inference/inference-manager.ts +0 -327
  254. package/src/metrics/metrics.ts +0 -186
  255. package/src/monitoring/alerting.ts +0 -190
  256. package/src/monitoring/health.ts +0 -197
  257. package/src/monitoring/index.ts +0 -38
  258. package/src/monitoring/info.ts +0 -114
  259. package/src/monitoring/types.ts +0 -99
  260. package/src/network/network-config.ts +0 -129
  261. package/src/packaging/compiler.ts +0 -647
  262. package/src/packaging/config-persistence.ts +0 -135
  263. package/src/packaging/config-schemas.ts +0 -156
  264. package/src/packaging/detector.ts +0 -220
  265. package/src/packaging/index.ts +0 -90
  266. package/src/packaging/packager.ts +0 -118
  267. package/src/packaging/parsers/clawdbot.ts +0 -278
  268. package/src/packaging/parsers/cline.ts +0 -223
  269. package/src/packaging/parsers/generic.ts +0 -266
  270. package/src/packaging/parsers/goose.ts +0 -214
  271. package/src/packaging/serializer.ts +0 -260
  272. package/src/packaging/types.ts +0 -144
  273. package/src/packaging/wasmedge-compiler.ts +0 -406
  274. package/src/security/multisig.ts +0 -415
  275. package/src/security/types.ts +0 -416
  276. package/src/security/vetkeys.ts +0 -655
  277. package/src/testing/local-runner.ts +0 -264
  278. package/src/testing/types.ts +0 -104
  279. package/src/wallet/cbor-serializer.ts +0 -323
  280. package/src/wallet/chain-dispatcher.ts +0 -313
  281. package/src/wallet/cross-chain-aggregator.ts +0 -346
  282. package/src/wallet/index.ts +0 -76
  283. package/src/wallet/key-derivation.ts +0 -425
  284. package/src/wallet/providers/base-provider.ts +0 -154
  285. package/src/wallet/providers/cketh-provider.ts +0 -434
  286. package/src/wallet/providers/polkadot-provider.ts +0 -503
  287. package/src/wallet/providers/solana-provider.ts +0 -490
  288. package/src/wallet/transaction-queue.ts +0 -284
  289. package/src/wallet/types.ts +0 -178
  290. package/src/wallet/vetkeys-adapter.ts +0 -431
  291. package/src/wallet/wallet-manager.ts +0 -597
  292. 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
+ }