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,69 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleName</key>
6
+ <string>AgentVault Wallet</string>
7
+ <key>CFBundleDisplayName</key>
8
+ <string>AgentVault Wallet</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>com.agentvault.wallet</string>
11
+ <key>CFBundleVersion</key>
12
+ <string>1</string>
13
+ <key>CFBundleShortVersionString</key>
14
+ <string>1.0.0</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>APPL</string>
17
+ <key>CFBundleExecutable</key>
18
+ <string>$(EXECUTABLE_NAME)</string>
19
+ <key>CFBundleInfoDictionaryVersion</key>
20
+ <string>6.0</string>
21
+ <key>LSMinimumSystemVersion</key>
22
+ <string>14.0</string>
23
+ <key>LSApplicationCategoryType</key>
24
+ <string>public.app-category.finance</string>
25
+ <key>NSMainNibFile</key>
26
+ <string></string>
27
+ <key>NSPrincipalClass</key>
28
+ <string>NSApplication</string>
29
+ <key>NSHumanReadableCopyright</key>
30
+ <string>Copyright 2024 AgentVault. All rights reserved.</string>
31
+ <key>CFBundleDocumentTypes</key>
32
+ <array>
33
+ <dict>
34
+ <key>CFBundleTypeName</key>
35
+ <string>AgentVault Backup</string>
36
+ <key>CFBundleTypeExtensions</key>
37
+ <array>
38
+ <string>avbackup</string>
39
+ </array>
40
+ <key>CFBundleTypeRole</key>
41
+ <string>Editor</string>
42
+ <key>LSHandlerRank</key>
43
+ <string>Owner</string>
44
+ <key>CFBundleTypeIconFiles</key>
45
+ <array/>
46
+ </dict>
47
+ </array>
48
+ <key>UTExportedTypeDeclarations</key>
49
+ <array>
50
+ <dict>
51
+ <key>UTTypeIdentifier</key>
52
+ <string>com.agentvault.backup</string>
53
+ <key>UTTypeDescription</key>
54
+ <string>AgentVault Wallet Backup</string>
55
+ <key>UTTypeConformsTo</key>
56
+ <array>
57
+ <string>public.data</string>
58
+ </array>
59
+ <key>UTTypeTagSpecification</key>
60
+ <dict>
61
+ <key>public.filename-extension</key>
62
+ <array>
63
+ <string>avbackup</string>
64
+ </array>
65
+ </dict>
66
+ </dict>
67
+ </array>
68
+ </dict>
69
+ </plist>
@@ -0,0 +1,270 @@
1
+ import Foundation
2
+
3
+ /// Handles wallet backup creation and restoration.
4
+ /// Backups are encrypted with AES-256-GCM using a user-provided password.
5
+ final class BackupService {
6
+
7
+ static let shared = BackupService()
8
+
9
+ private let crypto = CryptoService.shared
10
+ private let keychain = KeychainService.shared
11
+ private let fileManager = FileManager.default
12
+
13
+ enum BackupError: LocalizedError {
14
+ case noWalletsToBackup
15
+ case serializationFailed
16
+ case fileWriteFailed(String)
17
+ case fileReadFailed(String)
18
+ case invalidBackupFormat
19
+ case versionMismatch(Int)
20
+ case decryptionFailed
21
+ case corruptedBackup
22
+
23
+ var errorDescription: String? {
24
+ switch self {
25
+ case .noWalletsToBackup:
26
+ return "No wallets to back up"
27
+ case .serializationFailed:
28
+ return "Failed to serialize wallet data"
29
+ case .fileWriteFailed(let path):
30
+ return "Failed to write backup file to \(path)"
31
+ case .fileReadFailed(let path):
32
+ return "Failed to read backup file at \(path)"
33
+ case .invalidBackupFormat:
34
+ return "The selected file is not a valid AgentVault backup"
35
+ case .versionMismatch(let v):
36
+ return "Backup version \(v) is not supported by this app version"
37
+ case .decryptionFailed:
38
+ return "Failed to decrypt backup — incorrect password?"
39
+ case .corruptedBackup:
40
+ return "Backup file appears to be corrupted"
41
+ }
42
+ }
43
+ }
44
+
45
+ private init() {}
46
+
47
+ // MARK: - Backup Creation
48
+
49
+ /// Create an encrypted backup of all provided wallets
50
+ func createBackup(wallets: [Wallet], password: String) throws -> Data {
51
+ guard !wallets.isEmpty else {
52
+ throw BackupError.noWalletsToBackup
53
+ }
54
+
55
+ // Collect secrets for each wallet
56
+ var secrets: [[String: String]] = []
57
+ for wallet in wallets {
58
+ var entry: [String: String] = [
59
+ "id": wallet.id.uuidString,
60
+ "chain": wallet.chain.rawValue,
61
+ ]
62
+
63
+ if let mnemonic = try? keychain.getMnemonic(forWalletId: wallet.id) {
64
+ entry["mnemonic"] = mnemonic
65
+ }
66
+ if let privateKey = try? keychain.getPrivateKey(forWalletId: wallet.id) {
67
+ entry["privateKey"] = privateKey
68
+ }
69
+ if let jwkData = try? keychain.getJWK(forWalletId: wallet.id) {
70
+ entry["jwk"] = String(data: jwkData, encoding: .utf8)
71
+ }
72
+
73
+ secrets.append(entry)
74
+ }
75
+
76
+ // Serialize secrets to JSON
77
+ guard let secretsData = try? JSONSerialization.data(withJSONObject: secrets, options: []) else {
78
+ throw BackupError.serializationFailed
79
+ }
80
+
81
+ // Encrypt secrets
82
+ let encrypted = try crypto.encrypt(data: secretsData, password: password)
83
+
84
+ // Build backup entries
85
+ let entries = wallets.map { wallet in
86
+ WalletBackupEntry(
87
+ id: wallet.id,
88
+ name: wallet.name,
89
+ chain: wallet.chain,
90
+ address: wallet.address,
91
+ createdAt: wallet.createdAt,
92
+ derivationPath: wallet.derivationPath,
93
+ hasMnemonicBackup: wallet.hasMnemonicBackup
94
+ )
95
+ }
96
+
97
+ // Create backup structure
98
+ let backup = WalletBackup(
99
+ version: WalletBackup.currentVersion,
100
+ createdAt: Date(),
101
+ appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0",
102
+ wallets: entries,
103
+ encryptedPayload: encrypted.ciphertext,
104
+ salt: encrypted.salt,
105
+ iv: encrypted.nonce
106
+ )
107
+
108
+ // Encode to JSON
109
+ let encoder = JSONEncoder()
110
+ encoder.dateEncodingStrategy = .iso8601
111
+ encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
112
+
113
+ guard let backupData = try? encoder.encode(backup) else {
114
+ throw BackupError.serializationFailed
115
+ }
116
+
117
+ return backupData
118
+ }
119
+
120
+ /// Write backup data to a file
121
+ func writeBackup(_ data: Data, to url: URL) throws {
122
+ do {
123
+ try data.write(to: url, options: [.atomic, .completeFileProtection])
124
+ } catch {
125
+ throw BackupError.fileWriteFailed(url.path)
126
+ }
127
+ }
128
+
129
+ // MARK: - Backup Restoration
130
+
131
+ /// Read and validate a backup file, returning the metadata (before decryption)
132
+ func readBackupMetadata(from url: URL) throws -> WalletBackup {
133
+ guard let data = try? Data(contentsOf: url) else {
134
+ throw BackupError.fileReadFailed(url.path)
135
+ }
136
+
137
+ let decoder = JSONDecoder()
138
+ decoder.dateDecodingStrategy = .iso8601
139
+
140
+ guard let backup = try? decoder.decode(WalletBackup.self, from: data) else {
141
+ throw BackupError.invalidBackupFormat
142
+ }
143
+
144
+ guard backup.version <= WalletBackup.currentVersion else {
145
+ throw BackupError.versionMismatch(backup.version)
146
+ }
147
+
148
+ return backup
149
+ }
150
+
151
+ /// Decrypt and extract wallet secrets from a backup
152
+ func restoreSecrets(from backup: WalletBackup, password: String) throws -> [RestoredWalletSecret] {
153
+ let encrypted = CryptoService.EncryptedData(
154
+ ciphertext: backup.encryptedPayload,
155
+ nonce: backup.iv,
156
+ tag: Data(repeating: 0, count: 16), // Tag is embedded in ciphertext for our format
157
+ salt: backup.salt
158
+ )
159
+
160
+ let decryptedData: Data
161
+ do {
162
+ decryptedData = try crypto.decrypt(encrypted: encrypted, password: password)
163
+ } catch {
164
+ throw BackupError.decryptionFailed
165
+ }
166
+
167
+ guard let secrets = try? JSONSerialization.jsonObject(with: decryptedData) as? [[String: String]] else {
168
+ throw BackupError.corruptedBackup
169
+ }
170
+
171
+ return secrets.compactMap { entry in
172
+ guard let idStr = entry["id"],
173
+ let id = UUID(uuidString: idStr),
174
+ let chainStr = entry["chain"],
175
+ let chain = Chain(rawValue: chainStr) else {
176
+ return nil
177
+ }
178
+
179
+ return RestoredWalletSecret(
180
+ walletId: id,
181
+ chain: chain,
182
+ mnemonic: entry["mnemonic"],
183
+ privateKey: entry["privateKey"],
184
+ jwkJSON: entry["jwk"]
185
+ )
186
+ }
187
+ }
188
+
189
+ /// Save restored secrets to Keychain
190
+ func saveRestoredSecrets(_ secrets: [RestoredWalletSecret]) throws {
191
+ for secret in secrets {
192
+ if let mnemonic = secret.mnemonic {
193
+ try keychain.saveMnemonic(mnemonic, forWalletId: secret.walletId)
194
+ }
195
+ if let privateKey = secret.privateKey {
196
+ try keychain.savePrivateKey(privateKey, forWalletId: secret.walletId)
197
+ }
198
+ if let jwkJSON = secret.jwkJSON, let jwkData = jwkJSON.data(using: .utf8) {
199
+ try keychain.saveJWK(jwkData, forWalletId: secret.walletId)
200
+ }
201
+ }
202
+ }
203
+
204
+ // MARK: - Backup File Management
205
+
206
+ /// Default backup directory
207
+ var defaultBackupDirectory: URL {
208
+ let appSupport = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
209
+ let backupDir = appSupport.appendingPathComponent("AgentVaultWallet/Backups", isDirectory: true)
210
+ try? fileManager.createDirectory(at: backupDir, withIntermediateDirectories: true)
211
+ return backupDir
212
+ }
213
+
214
+ /// Generate a default backup filename
215
+ func defaultBackupFilename() -> String {
216
+ let formatter = DateFormatter()
217
+ formatter.dateFormat = "yyyy-MM-dd_HHmmss"
218
+ return "agentvault-backup-\(formatter.string(from: Date())).avbackup"
219
+ }
220
+
221
+ /// List existing backup files in the default directory
222
+ func listBackups() -> [BackupFileInfo] {
223
+ guard let contents = try? fileManager.contentsOfDirectory(
224
+ at: defaultBackupDirectory,
225
+ includingPropertiesForKeys: [.creationDateKey, .fileSizeKey],
226
+ options: .skipsHiddenFiles
227
+ ) else { return [] }
228
+
229
+ return contents
230
+ .filter { $0.pathExtension == "avbackup" }
231
+ .compactMap { url -> BackupFileInfo? in
232
+ let attrs = try? fileManager.attributesOfItem(atPath: url.path)
233
+ let size = attrs?[.size] as? Int ?? 0
234
+ let created = attrs?[.creationDate] as? Date ?? Date()
235
+ let walletCount = (try? readBackupMetadata(from: url))?.wallets.count
236
+
237
+ return BackupFileInfo(
238
+ url: url,
239
+ filename: url.lastPathComponent,
240
+ createdAt: created,
241
+ fileSize: size,
242
+ walletCount: walletCount
243
+ )
244
+ }
245
+ .sorted { $0.createdAt > $1.createdAt }
246
+ }
247
+ }
248
+
249
+ /// Secrets extracted from a backup for a single wallet
250
+ struct RestoredWalletSecret {
251
+ let walletId: UUID
252
+ let chain: Chain
253
+ let mnemonic: String?
254
+ let privateKey: String?
255
+ let jwkJSON: String?
256
+ }
257
+
258
+ /// Metadata about a backup file on disk
259
+ struct BackupFileInfo: Identifiable {
260
+ let id = UUID()
261
+ let url: URL
262
+ let filename: String
263
+ let createdAt: Date
264
+ let fileSize: Int
265
+ let walletCount: Int?
266
+
267
+ var formattedSize: String {
268
+ ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
269
+ }
270
+ }