auramaxx 1.0.0-alpha.4

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 (363) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +112 -0
  3. package/bin/aurawallet.js +121 -0
  4. package/docs/ADAPTERS.md +467 -0
  5. package/docs/API.md +2679 -0
  6. package/docs/APPS.md +198 -0
  7. package/docs/ARCHITECTURE.md +350 -0
  8. package/docs/AUTH.md +698 -0
  9. package/docs/BEST-PRACTICES.md +121 -0
  10. package/docs/CLI.md +61 -0
  11. package/docs/DEVELOPING-APPS.md +452 -0
  12. package/docs/EXTENSION.md +97 -0
  13. package/docs/JOBS.md +33 -0
  14. package/docs/MCP.md +76 -0
  15. package/docs/PROTOCOL.md +142 -0
  16. package/docs/SETUP.md +219 -0
  17. package/docs/WORKSPACE.md +672 -0
  18. package/docs/agent-auth.md +63 -0
  19. package/docs/aura-file.md +48 -0
  20. package/docs/credentials.md +53 -0
  21. package/docs/external/getting-started.md +65 -0
  22. package/docs/external/overview.md +45 -0
  23. package/docs/external/use-cases.md +48 -0
  24. package/docs/external/why-aura.md +35 -0
  25. package/docs/jobs/connect-agent.md +77 -0
  26. package/docs/jobs/migrate-from-dotenv.md +79 -0
  27. package/docs/jobs/recover-from-lockout.md +72 -0
  28. package/docs/jobs/secure-ci.md +63 -0
  29. package/docs/oauth2.md +42 -0
  30. package/docs/passkeys.md +60 -0
  31. package/docs/security.md +540 -0
  32. package/docs/specs/aura-open-protocol.md +61 -0
  33. package/docs/specs/aura-provider-plugin.md +24 -0
  34. package/docs/specs/aura-registry-model.md +31 -0
  35. package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
  36. package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
  37. package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
  38. package/docs/specs/fixtures/valid-basic.aura +4 -0
  39. package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
  40. package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
  41. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  42. package/docs/totp.md +40 -0
  43. package/docs/wallet/AI.md +508 -0
  44. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  45. package/docs/wallet/README.md +47 -0
  46. package/docs/wallet/STRATEGY.md +89 -0
  47. package/next.config.ts +21 -0
  48. package/package.json +151 -0
  49. package/postcss.config.mjs +8 -0
  50. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  51. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  52. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  53. package/prisma/migrations/migration_lock.toml +3 -0
  54. package/prisma/schema.prisma +447 -0
  55. package/public/logo-chevron.svg +31 -0
  56. package/public/logo-concentric.svg +31 -0
  57. package/public/logo-crosshatch.svg +39 -0
  58. package/public/logo-dashed.svg +39 -0
  59. package/public/logo-horizontal.svg +31 -0
  60. package/public/logo-m56.svg +64 -0
  61. package/public/logo.webp +0 -0
  62. package/scripts/add-app.js +245 -0
  63. package/scripts/init.sh +57 -0
  64. package/scripts/migrate-apikeys-to-credentials.ts +35 -0
  65. package/scripts/sandbox-agent-flow.sh +235 -0
  66. package/scripts/sandbox.sh +175 -0
  67. package/scripts/validate-job-docs.mjs +125 -0
  68. package/server/abi/SwapHelper.json +438 -0
  69. package/server/cli/approval.ts +447 -0
  70. package/server/cli/commands/app.ts +204 -0
  71. package/server/cli/commands/cron.ts +24 -0
  72. package/server/cli/commands/doctor.ts +1007 -0
  73. package/server/cli/commands/env.ts +456 -0
  74. package/server/cli/commands/init.ts +752 -0
  75. package/server/cli/commands/mcp.ts +125 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/shell-hook.ts +468 -0
  78. package/server/cli/commands/start.ts +62 -0
  79. package/server/cli/commands/status.ts +59 -0
  80. package/server/cli/commands/stop.ts +14 -0
  81. package/server/cli/commands/token.ts +180 -0
  82. package/server/cli/commands/unlock.ts +49 -0
  83. package/server/cli/commands/vault.ts +417 -0
  84. package/server/cli/index.ts +328 -0
  85. package/server/cli/lib/aura-parser.ts +64 -0
  86. package/server/cli/lib/credential-create.ts +74 -0
  87. package/server/cli/lib/credential-resolve.ts +254 -0
  88. package/server/cli/lib/dotenv-migrate.ts +116 -0
  89. package/server/cli/lib/dotenv-parser.ts +146 -0
  90. package/server/cli/lib/http.ts +91 -0
  91. package/server/cli/lib/init-steps.ts +76 -0
  92. package/server/cli/lib/local-agent-trust.ts +45 -0
  93. package/server/cli/lib/process.ts +136 -0
  94. package/server/cli/lib/prompt.ts +85 -0
  95. package/server/cli/lib/theme.ts +240 -0
  96. package/server/cli/socket.ts +570 -0
  97. package/server/cli/transport-client.ts +50 -0
  98. package/server/cron/index.ts +137 -0
  99. package/server/cron/job.ts +31 -0
  100. package/server/cron/jobs/balance-sync.ts +436 -0
  101. package/server/cron/jobs/incoming-scan.ts +506 -0
  102. package/server/cron/jobs/native-price.ts +70 -0
  103. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  104. package/server/cron/jobs/strategy-runner.ts +175 -0
  105. package/server/cron/scheduler.ts +125 -0
  106. package/server/index.ts +406 -0
  107. package/server/lib/adapters/factory.ts +110 -0
  108. package/server/lib/adapters/index.ts +19 -0
  109. package/server/lib/adapters/router.ts +297 -0
  110. package/server/lib/adapters/telegram.ts +645 -0
  111. package/server/lib/adapters/types.ts +89 -0
  112. package/server/lib/adapters/webhook.ts +95 -0
  113. package/server/lib/address.ts +49 -0
  114. package/server/lib/agent-auth/contracts.ts +1194 -0
  115. package/server/lib/agent-profiles.ts +328 -0
  116. package/server/lib/ai.ts +285 -0
  117. package/server/lib/api-registry/contracts.ts +86 -0
  118. package/server/lib/api-registry/validation.ts +172 -0
  119. package/server/lib/apikey-migration.ts +189 -0
  120. package/server/lib/app-installer.ts +505 -0
  121. package/server/lib/app-tokens.ts +247 -0
  122. package/server/lib/auth.ts +314 -0
  123. package/server/lib/batch.ts +242 -0
  124. package/server/lib/cold.ts +874 -0
  125. package/server/lib/config.ts +381 -0
  126. package/server/lib/credential-access-audit.ts +85 -0
  127. package/server/lib/credential-access-policy.ts +110 -0
  128. package/server/lib/credential-health.ts +343 -0
  129. package/server/lib/credential-import.ts +487 -0
  130. package/server/lib/credential-scope.ts +87 -0
  131. package/server/lib/credential-shares.ts +190 -0
  132. package/server/lib/credential-transport.ts +342 -0
  133. package/server/lib/credential-vault.ts +77 -0
  134. package/server/lib/credentials.ts +333 -0
  135. package/server/lib/crypto.ts +8 -0
  136. package/server/lib/db.ts +15 -0
  137. package/server/lib/defaults.ts +366 -0
  138. package/server/lib/dex/index.ts +80 -0
  139. package/server/lib/dex/relay.ts +235 -0
  140. package/server/lib/dex/types.ts +59 -0
  141. package/server/lib/dex/uniswap.ts +370 -0
  142. package/server/lib/e2e-agent/artifacts.ts +36 -0
  143. package/server/lib/e2e-agent/contracts.ts +112 -0
  144. package/server/lib/e2e-agent/validation.ts +135 -0
  145. package/server/lib/encrypt.ts +128 -0
  146. package/server/lib/error.ts +20 -0
  147. package/server/lib/events.ts +205 -0
  148. package/server/lib/hot.ts +357 -0
  149. package/server/lib/key-fingerprint.ts +28 -0
  150. package/server/lib/logger.ts +331 -0
  151. package/server/lib/network.ts +137 -0
  152. package/server/lib/notifications.ts +219 -0
  153. package/server/lib/oauth2-refresh.ts +241 -0
  154. package/server/lib/oursecret.ts +54 -0
  155. package/server/lib/passkey-credential.ts +360 -0
  156. package/server/lib/passkey.ts +68 -0
  157. package/server/lib/permissions.ts +248 -0
  158. package/server/lib/pino.ts +24 -0
  159. package/server/lib/policy-preview.ts +138 -0
  160. package/server/lib/price.ts +338 -0
  161. package/server/lib/prices.ts +34 -0
  162. package/server/lib/project-scope.ts +239 -0
  163. package/server/lib/resolve-action.ts +427 -0
  164. package/server/lib/resolve.ts +36 -0
  165. package/server/lib/sessions.ts +632 -0
  166. package/server/lib/solana/connection.ts +26 -0
  167. package/server/lib/solana/jupiter.ts +128 -0
  168. package/server/lib/solana/transfer.ts +108 -0
  169. package/server/lib/solana/wallet.ts +136 -0
  170. package/server/lib/strategy/emits.ts +21 -0
  171. package/server/lib/strategy/engine.ts +1305 -0
  172. package/server/lib/strategy/executor.ts +115 -0
  173. package/server/lib/strategy/hook-context.ts +158 -0
  174. package/server/lib/strategy/hooks.ts +990 -0
  175. package/server/lib/strategy/index.ts +28 -0
  176. package/server/lib/strategy/installer.ts +305 -0
  177. package/server/lib/strategy/loader.ts +256 -0
  178. package/server/lib/strategy/message.ts +235 -0
  179. package/server/lib/strategy/repository.ts +218 -0
  180. package/server/lib/strategy/session-logger.ts +693 -0
  181. package/server/lib/strategy/sources.ts +288 -0
  182. package/server/lib/strategy/state.ts +189 -0
  183. package/server/lib/strategy/templates.ts +403 -0
  184. package/server/lib/strategy/tick.ts +404 -0
  185. package/server/lib/strategy/types.ts +230 -0
  186. package/server/lib/swap.ts +3 -0
  187. package/server/lib/temp.ts +86 -0
  188. package/server/lib/token-metadata.ts +86 -0
  189. package/server/lib/token-safety.ts +200 -0
  190. package/server/lib/token-search.ts +444 -0
  191. package/server/lib/totp.ts +194 -0
  192. package/server/lib/transactions.ts +123 -0
  193. package/server/lib/transport.ts +75 -0
  194. package/server/lib/txhistory/decoder.ts +262 -0
  195. package/server/lib/txhistory/enricher.ts +652 -0
  196. package/server/lib/txhistory/index.ts +391 -0
  197. package/server/lib/txhistory/signatures.ts +59 -0
  198. package/server/lib/verified-summary.ts +421 -0
  199. package/server/mcp/profile-policy.ts +30 -0
  200. package/server/mcp/server.ts +619 -0
  201. package/server/mcp/tools.ts +523 -0
  202. package/server/middleware/auth.ts +119 -0
  203. package/server/middleware/requestLogger.ts +84 -0
  204. package/server/routes/actions.ts +459 -0
  205. package/server/routes/adapters.ts +703 -0
  206. package/server/routes/addressbook.ts +113 -0
  207. package/server/routes/ai.ts +34 -0
  208. package/server/routes/apikeys.ts +295 -0
  209. package/server/routes/apps.ts +601 -0
  210. package/server/routes/auth.ts +457 -0
  211. package/server/routes/backup.ts +340 -0
  212. package/server/routes/batch.ts +270 -0
  213. package/server/routes/bookmarks.ts +162 -0
  214. package/server/routes/credential-shares.ts +198 -0
  215. package/server/routes/credential-vaults.ts +154 -0
  216. package/server/routes/credentials.ts +1290 -0
  217. package/server/routes/dashboard.ts +71 -0
  218. package/server/routes/defaults.ts +124 -0
  219. package/server/routes/fund.ts +229 -0
  220. package/server/routes/import.ts +352 -0
  221. package/server/routes/launch.ts +665 -0
  222. package/server/routes/lock.ts +54 -0
  223. package/server/routes/logs.ts +68 -0
  224. package/server/routes/nuke.ts +111 -0
  225. package/server/routes/passkey-credentials.ts +99 -0
  226. package/server/routes/passkey.ts +346 -0
  227. package/server/routes/portfolio.ts +217 -0
  228. package/server/routes/price.ts +63 -0
  229. package/server/routes/resolve.ts +31 -0
  230. package/server/routes/security.ts +45 -0
  231. package/server/routes/send-evm.ts +241 -0
  232. package/server/routes/send-solana.ts +281 -0
  233. package/server/routes/send.ts +178 -0
  234. package/server/routes/setup.ts +210 -0
  235. package/server/routes/strategy.ts +894 -0
  236. package/server/routes/swap-evm.ts +353 -0
  237. package/server/routes/swap-solana.ts +177 -0
  238. package/server/routes/swap.ts +356 -0
  239. package/server/routes/token.ts +247 -0
  240. package/server/routes/unlock.ts +403 -0
  241. package/server/routes/wallet-assets.ts +361 -0
  242. package/server/routes/wallet-transactions.ts +515 -0
  243. package/server/routes/wallet.ts +710 -0
  244. package/server/types.ts +146 -0
  245. package/skills/aurawallet/SKILL.md +739 -0
  246. package/skills/aurawallet-setup/SKILL.md +74 -0
  247. package/skills/security-review/SKILL.md +148 -0
  248. package/src/app/api/agent-requests/route.ts +30 -0
  249. package/src/app/api/apps/install/route.ts +126 -0
  250. package/src/app/api/apps/manifests/route.ts +16 -0
  251. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  252. package/src/app/api/events/route.ts +92 -0
  253. package/src/app/api/page.tsx +212 -0
  254. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  255. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  256. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  257. package/src/app/api/workspace/[id]/route.ts +168 -0
  258. package/src/app/api/workspace/auth.ts +34 -0
  259. package/src/app/api/workspace/config/route.ts +106 -0
  260. package/src/app/api/workspace/import/route.ts +127 -0
  261. package/src/app/api/workspace/route.ts +116 -0
  262. package/src/app/app/page.tsx +2122 -0
  263. package/src/app/apple-icon.png +0 -0
  264. package/src/app/docs/page.tsx +178 -0
  265. package/src/app/favicon.ico +0 -0
  266. package/src/app/globals.css +572 -0
  267. package/src/app/health/page.tsx +5 -0
  268. package/src/app/hello/page.tsx +15 -0
  269. package/src/app/icon.png +0 -0
  270. package/src/app/layout.tsx +34 -0
  271. package/src/app/page.tsx +986 -0
  272. package/src/app/providers.tsx +90 -0
  273. package/src/app/share/[token]/page.tsx +295 -0
  274. package/src/components/ChainSelector.tsx +144 -0
  275. package/src/components/HumanActionBar.tsx +695 -0
  276. package/src/components/NotificationDrawer.tsx +129 -0
  277. package/src/components/apps/AgentKeysApp.tsx +490 -0
  278. package/src/components/apps/App.tsx +153 -0
  279. package/src/components/apps/AppGrid.tsx +15 -0
  280. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  281. package/src/components/apps/DraggableApp.tsx +562 -0
  282. package/src/components/apps/IFrameApp.tsx +73 -0
  283. package/src/components/apps/LogsApp.tsx +360 -0
  284. package/src/components/apps/SendApp.tsx +394 -0
  285. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  286. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  287. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  288. package/src/components/apps/TokenApp.tsx +319 -0
  289. package/src/components/apps/TransactionsApp.tsx +438 -0
  290. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  291. package/src/components/apps/index.ts +13 -0
  292. package/src/components/design-system/Button.tsx +53 -0
  293. package/src/components/design-system/ChainIndicator.tsx +65 -0
  294. package/src/components/design-system/ChainSelector.tsx +137 -0
  295. package/src/components/design-system/ConfirmationModal.tsx +106 -0
  296. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  297. package/src/components/design-system/Drawer.tsx +123 -0
  298. package/src/components/design-system/FilterDropdown.tsx +72 -0
  299. package/src/components/design-system/Modal.tsx +206 -0
  300. package/src/components/design-system/Popover.tsx +142 -0
  301. package/src/components/design-system/TextInput.tsx +85 -0
  302. package/src/components/design-system/Toggle.tsx +58 -0
  303. package/src/components/design-system/index.ts +11 -0
  304. package/src/components/docs/DocsThemeToggle.tsx +49 -0
  305. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  306. package/src/components/icons/ChainIcons.tsx +72 -0
  307. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  308. package/src/components/layout/ContentArea.tsx +21 -0
  309. package/src/components/layout/TabBar.tsx +278 -0
  310. package/src/components/layout/WalletSidebar.tsx +1033 -0
  311. package/src/components/layout/index.ts +4 -0
  312. package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
  313. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  314. package/src/components/vault/ApiKeysConsole.tsx +1080 -0
  315. package/src/components/vault/AuditConsole.tsx +584 -0
  316. package/src/components/vault/CredentialDetail.tsx +455 -0
  317. package/src/components/vault/CredentialEmpty.tsx +55 -0
  318. package/src/components/vault/CredentialField.tsx +361 -0
  319. package/src/components/vault/CredentialForm.tsx +1212 -0
  320. package/src/components/vault/CredentialList.tsx +165 -0
  321. package/src/components/vault/CredentialRow.tsx +97 -0
  322. package/src/components/vault/CredentialShareModal.tsx +178 -0
  323. package/src/components/vault/CredentialVault.tsx +754 -0
  324. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  325. package/src/components/vault/ImportCredentialsModal.tsx +515 -0
  326. package/src/components/vault/LargeTypeModal.tsx +64 -0
  327. package/src/components/vault/PasswordGenerator.tsx +224 -0
  328. package/src/components/vault/TOTPDisplay.tsx +123 -0
  329. package/src/components/vault/VaultSidebar.tsx +413 -0
  330. package/src/components/vault/types.ts +54 -0
  331. package/src/context/AuthContext.tsx +337 -0
  332. package/src/context/PriceContext.tsx +113 -0
  333. package/src/context/ThemeContext.tsx +164 -0
  334. package/src/context/WebSocketContext.tsx +269 -0
  335. package/src/context/WorkspaceContext.tsx +668 -0
  336. package/src/hooks/index.ts +3 -0
  337. package/src/hooks/useAgentActions.ts +368 -0
  338. package/src/hooks/useBalance.ts +103 -0
  339. package/src/hooks/useBalances.ts +129 -0
  340. package/src/instrumentation.ts +12 -0
  341. package/src/lib/api.ts +449 -0
  342. package/src/lib/app-loader.ts +148 -0
  343. package/src/lib/app-registry.ts +178 -0
  344. package/src/lib/app-sdk.ts +157 -0
  345. package/src/lib/audit-console-adapter.ts +151 -0
  346. package/src/lib/auth-client.ts +75 -0
  347. package/src/lib/config.ts +74 -0
  348. package/src/lib/crypto.ts +112 -0
  349. package/src/lib/db.ts +21 -0
  350. package/src/lib/docs.ts +390 -0
  351. package/src/lib/events.ts +361 -0
  352. package/src/lib/pino.ts +24 -0
  353. package/src/lib/theme-handlers.ts +168 -0
  354. package/src/lib/theme.ts +351 -0
  355. package/src/lib/tokenData.ts +378 -0
  356. package/src/lib/vault-crypto.ts +129 -0
  357. package/src/lib/websocket-server.ts +302 -0
  358. package/src/lib/websocket-setup.ts +79 -0
  359. package/src/lib/wordlist.ts +2050 -0
  360. package/src/lib/workspace-handlers.ts +285 -0
  361. package/start.sh +80 -0
  362. package/tailwind.config.ts +99 -0
  363. package/tsconfig.json +42 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * aurawallet mcp — Start the MCP server (stdio transport)
3
+ *
4
+ * Spawned by MCP clients (Claude Code, Claude Desktop, Cursor, etc.) via config:
5
+ * { "command": "npx", "args": ["aurawallet", "mcp"], "env": { "AURA_TOKEN": "<token>" } }
6
+ *
7
+ * Flags:
8
+ * --install Auto-detect IDEs and write MCP config entries
9
+ */
10
+
11
+ import fs from 'fs';
12
+ import path from 'path';
13
+ import os from 'os';
14
+ import { getErrorMessage } from '../../lib/error';
15
+
16
+ const args = process.argv.slice(2);
17
+
18
+ if (args.includes('--install')) {
19
+ installMcpConfigs();
20
+ } else {
21
+ // The MCP server runs on import — connects stdio transport and registers tools
22
+ import('../../mcp/server.js');
23
+ }
24
+
25
+ interface IdeTarget {
26
+ name: string;
27
+ configPath: string;
28
+ global: boolean;
29
+ }
30
+
31
+ function installMcpConfigs(): void {
32
+ const home = os.homedir();
33
+
34
+ const targets: IdeTarget[] = [
35
+ {
36
+ name: 'Claude Desktop',
37
+ configPath: path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
38
+ global: true,
39
+ },
40
+ {
41
+ name: 'Cursor',
42
+ configPath: path.join(home, '.cursor', 'mcp.json'),
43
+ global: true,
44
+ },
45
+ {
46
+ name: 'VS Code',
47
+ configPath: path.join(process.cwd(), '.vscode', 'mcp.json'),
48
+ global: false,
49
+ },
50
+ {
51
+ name: 'Windsurf',
52
+ configPath: path.join(home, '.windsurf', 'mcp.json'),
53
+ global: true,
54
+ },
55
+ ];
56
+
57
+ const mcpEntry = {
58
+ command: 'npx',
59
+ args: ['aurawallet', 'mcp'],
60
+ };
61
+
62
+ console.log('\n AuraWallet MCP Installer');
63
+ console.log(' ───────────────────────\n');
64
+
65
+ let updated = 0;
66
+ let skipped = 0;
67
+ let notFound = 0;
68
+ let errors = 0;
69
+
70
+ for (const target of targets) {
71
+ const configDir = path.dirname(target.configPath);
72
+
73
+ // Only touch configs for IDEs that are actually present.
74
+ // Do not create new IDE directories implicitly.
75
+ if (!fs.existsSync(configDir)) {
76
+ console.log(` ${target.name}: not found (${configDir} not found)`);
77
+ notFound++;
78
+ continue;
79
+ }
80
+
81
+ // Read existing config or start fresh. If the file is malformed, skip it
82
+ // instead of overwriting user data with {}.
83
+ let config: Record<string, unknown> = {};
84
+ if (fs.existsSync(target.configPath)) {
85
+ try {
86
+ const raw = fs.readFileSync(target.configPath, 'utf-8');
87
+ config = JSON.parse(raw);
88
+ } catch (error) {
89
+ const message = getErrorMessage(error);
90
+ console.log(` ${target.name}: skipped (invalid JSON in ${target.configPath}: ${message})`);
91
+ errors++;
92
+ continue;
93
+ }
94
+ }
95
+
96
+ // Check if aurawallet entry already exists
97
+ if (
98
+ config.mcpServers !== undefined &&
99
+ (typeof config.mcpServers !== 'object' || config.mcpServers === null || Array.isArray(config.mcpServers))
100
+ ) {
101
+ console.log(` ${target.name}: skipped (mcpServers must be an object in ${target.configPath})`);
102
+ errors++;
103
+ continue;
104
+ }
105
+
106
+ const mcpServers = (config.mcpServers || {}) as Record<string, unknown>;
107
+ if (mcpServers.aurawallet) {
108
+ console.log(` ${target.name}: already configured`);
109
+ skipped++;
110
+ continue;
111
+ }
112
+
113
+ // Merge the entry
114
+ mcpServers.aurawallet = mcpEntry;
115
+ config.mcpServers = mcpServers;
116
+
117
+ fs.writeFileSync(target.configPath, JSON.stringify(config, null, 2) + '\n');
118
+ console.log(` ${target.name}: configured (${target.configPath})`);
119
+ updated++;
120
+ }
121
+
122
+ console.log('');
123
+ console.log(` Done: ${updated} updated, ${skipped} already configured, ${notFound} not found, ${errors} skipped due to errors`);
124
+ console.log('');
125
+ }
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * npx aurawallet restore — Restore from a backup
4
+ *
5
+ * Usage:
6
+ * npx aurawallet restore --list # List available backups
7
+ * npx aurawallet restore --latest # Restore most recent backup
8
+ * npx aurawallet restore <filename> # Restore specific backup
9
+ * npx aurawallet restore --dry-run <file> # Preview without modifying
10
+ * npx aurawallet restore --dry-run --latest # Preview latest restore
11
+ */
12
+
13
+ import { readdir, stat, copyFile, unlink, rename } from 'fs/promises';
14
+ import { join } from 'path';
15
+ import { existsSync, mkdirSync } from 'fs';
16
+ import { execSync } from 'child_process';
17
+ import { createServer } from 'net';
18
+ import { getDbPath } from '../../lib/config';
19
+ import { getBackupsDir, ensureBackupsDir, verifyIntegrity } from '../../routes/backup';
20
+
21
+ const DATA_DIR = join(getDbPath(), '..');
22
+ const CREDENTIALS_DIR = join(DATA_DIR, 'credentials');
23
+
24
+ interface BackupEntry {
25
+ filename: string;
26
+ timestamp: string;
27
+ size: number;
28
+ date: Date;
29
+ }
30
+
31
+ async function listBackups(): Promise<BackupEntry[]> {
32
+ const backupsDir = getBackupsDir();
33
+ ensureBackupsDir();
34
+
35
+ const files = await readdir(backupsDir);
36
+ const backups: BackupEntry[] = [];
37
+
38
+ for (const file of files) {
39
+ if (file.startsWith('aurawallet.db.') && file.endsWith('.bak')) {
40
+ const match = file.match(/aurawallet\.db\.(\d{8}_\d{6})\.bak/);
41
+ if (!match) continue;
42
+ const filePath = join(backupsDir, file);
43
+ const fileStat = await stat(filePath);
44
+ backups.push({
45
+ filename: file,
46
+ timestamp: match[1],
47
+ size: fileStat.size,
48
+ date: fileStat.mtime,
49
+ });
50
+ }
51
+ }
52
+
53
+ backups.sort((a, b) => b.date.getTime() - a.date.getTime());
54
+ return backups;
55
+ }
56
+
57
+ function formatSize(bytes: number): string {
58
+ if (bytes < 1024) return `${bytes} B`;
59
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
60
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
61
+ }
62
+
63
+ function formatTimestamp(ts: string): string {
64
+ // YYYYMMDD_HHMMSS -> YYYY-MM-DD HH:MM:SS
65
+ return `${ts.slice(0, 4)}-${ts.slice(4, 6)}-${ts.slice(6, 8)} ${ts.slice(9, 11)}:${ts.slice(11, 13)}:${ts.slice(13, 15)}`;
66
+ }
67
+
68
+ async function checkServerRunning(): Promise<boolean> {
69
+ return new Promise((resolve) => {
70
+ const server = createServer();
71
+ server.once('error', (error: NodeJS.ErrnoException) => {
72
+ if (error.code === 'EADDRINUSE') {
73
+ resolve(true);
74
+ } else {
75
+ resolve(false);
76
+ }
77
+ });
78
+ server.once('listening', () => {
79
+ server.close();
80
+ resolve(false);
81
+ });
82
+ server.listen(4242, '127.0.0.1');
83
+ });
84
+ }
85
+
86
+ async function createPreRestoreBackup(): Promise<string> {
87
+ const dbFile = getDbPath();
88
+ if (!existsSync(dbFile)) return '';
89
+
90
+ const backupsDir = getBackupsDir();
91
+ ensureBackupsDir();
92
+
93
+ const now = new Date();
94
+ const timestamp = now.toISOString().replace(/[-:]/g, '').replace('T', '_').split('.')[0];
95
+ const filename = `pre-restore.${timestamp}.bak`;
96
+ const backupPath = join(backupsDir, filename);
97
+
98
+ await copyFile(dbFile, backupPath);
99
+ return filename;
100
+ }
101
+
102
+ async function restoreCredentials(backupsDir: string, timestamp: string): Promise<number> {
103
+ const allFiles = await readdir(backupsDir);
104
+ const credBackups = allFiles.filter(
105
+ (f) => f.startsWith(`credentials.${timestamp}.cred-`) && f.endsWith('.json')
106
+ );
107
+
108
+ if (credBackups.length === 0) return 0;
109
+
110
+ if (!existsSync(CREDENTIALS_DIR)) {
111
+ mkdirSync(CREDENTIALS_DIR, { recursive: true });
112
+ }
113
+
114
+ // Remove existing credentials
115
+ if (existsSync(CREDENTIALS_DIR)) {
116
+ const existing = await readdir(CREDENTIALS_DIR);
117
+ for (const f of existing) {
118
+ if (f.startsWith('cred-') && f.endsWith('.json')) {
119
+ await unlink(join(CREDENTIALS_DIR, f));
120
+ }
121
+ }
122
+ }
123
+
124
+ // Copy from backup
125
+ for (const f of credBackups) {
126
+ const destName = f.replace(`credentials.${timestamp}.`, '');
127
+ await copyFile(join(backupsDir, f), join(CREDENTIALS_DIR, destName));
128
+ }
129
+
130
+ return credBackups.length;
131
+ }
132
+
133
+ async function runMigrations(): Promise<number> {
134
+ try {
135
+ const output = execSync('npx prisma migrate deploy', {
136
+ cwd: join(__dirname, '..', '..', '..'),
137
+ env: { ...process.env, DATABASE_URL: `file:${getDbPath()}` },
138
+ encoding: 'utf-8',
139
+ stdio: ['pipe', 'pipe', 'pipe'],
140
+ });
141
+
142
+ // Count applied migrations from output
143
+ const matches = output.match(/(\d+) migration/);
144
+ return matches ? parseInt(matches[1], 10) : 0;
145
+ } catch (error: any) {
146
+ const errMsg = error.stderr || error.message || 'Unknown error';
147
+ console.error(`\n ✗ Migration FAILED: ${errMsg}`);
148
+ console.error(' This is a critical error — the restored DB may have an incompatible schema.');
149
+ throw new Error(`Migration failed: ${errMsg}`);
150
+ }
151
+ }
152
+
153
+ async function main() {
154
+ const args = process.argv.slice(2);
155
+ const listFlag = args.includes('--list');
156
+ const latestFlag = args.includes('--latest');
157
+ const dryRun = args.includes('--dry-run');
158
+ const filename = args.find((a) => !a.startsWith('--'));
159
+
160
+ if (!listFlag && !latestFlag && !filename) {
161
+ console.log(`
162
+ aurawallet restore — Restore from a backup
163
+
164
+ Usage:
165
+ npx aurawallet restore --list List available backups
166
+ npx aurawallet restore --latest Restore most recent backup
167
+ npx aurawallet restore <filename> Restore specific backup
168
+ npx aurawallet restore --dry-run --latest Preview without modifying
169
+ `);
170
+ process.exit(0);
171
+ }
172
+
173
+ // --list: show backups and exit
174
+ if (listFlag) {
175
+ const backups = await listBackups();
176
+ if (backups.length === 0) {
177
+ console.log('No backups found.');
178
+ process.exit(0);
179
+ }
180
+
181
+ console.log(`\n Available backups (${backups.length}):\n`);
182
+ for (const b of backups) {
183
+ console.log(` ${b.filename} ${formatTimestamp(b.timestamp)} ${formatSize(b.size)}`);
184
+ }
185
+ console.log();
186
+ process.exit(0);
187
+ }
188
+
189
+ // Determine which backup to restore
190
+ let targetFilename: string;
191
+ if (latestFlag) {
192
+ const backups = await listBackups();
193
+ if (backups.length === 0) {
194
+ console.error('No backups found.');
195
+ process.exit(1);
196
+ }
197
+ targetFilename = backups[0].filename;
198
+ } else {
199
+ targetFilename = filename!;
200
+ }
201
+
202
+ // Validate filename
203
+ if (!targetFilename.match(/^aurawallet\.db\.\d{8}_\d{6}\.bak$/)) {
204
+ console.error(`Invalid backup filename: ${targetFilename}`);
205
+ process.exit(1);
206
+ }
207
+
208
+ const backupsDir = getBackupsDir();
209
+ const backupPath = join(backupsDir, targetFilename);
210
+
211
+ if (!existsSync(backupPath)) {
212
+ console.error(`Backup not found: ${targetFilename}`);
213
+ process.exit(1);
214
+ }
215
+
216
+ const backupStat = await stat(backupPath);
217
+ const tsMatch = targetFilename.match(/aurawallet\.db\.(\d{8}_\d{6})\.bak/)!;
218
+ const timestamp = tsMatch[1];
219
+
220
+ // Count matching credential backups
221
+ const allFiles = await readdir(backupsDir);
222
+ const credCount = allFiles.filter(
223
+ (f) => f.startsWith(`credentials.${timestamp}.cred-`) && f.endsWith('.json')
224
+ ).length;
225
+
226
+ console.log(`\n Restore target: ${targetFilename}`);
227
+ console.log(` Created: ${formatTimestamp(timestamp)}`);
228
+ console.log(` Size: ${formatSize(backupStat.size)}`);
229
+ console.log(` Credentials: ${credCount} file(s)`);
230
+
231
+ // Verify backup integrity
232
+ console.log('\n Verifying backup integrity...');
233
+ if (!verifyIntegrity(backupPath)) {
234
+ console.error(' ✗ Backup FAILED integrity check. Aborting.');
235
+ process.exit(1);
236
+ }
237
+ console.log(' ✓ Backup integrity OK');
238
+
239
+ if (dryRun) {
240
+ console.log('\n --dry-run: No changes made.\n');
241
+ process.exit(0);
242
+ }
243
+
244
+ // Check if server is running
245
+ const serverRunning = await checkServerRunning();
246
+ if (serverRunning) {
247
+ console.log('\n ⚠️ WARNING: Server appears to be running on port 4242.');
248
+ console.log(' Stop it first with `npx aurawallet stop` for clean restore.');
249
+ console.log(' Proceeding anyway...\n');
250
+ }
251
+
252
+ // Pre-restore safety backup
253
+ const preRestoreName = await createPreRestoreBackup();
254
+ if (preRestoreName) {
255
+ console.log(` Pre-restore backup: ${preRestoreName}`);
256
+ }
257
+
258
+ // Restore DB
259
+ const dbPath = getDbPath();
260
+ const tempPath = dbPath + '.restore-tmp';
261
+ await copyFile(backupPath, tempPath);
262
+ await rename(tempPath, dbPath);
263
+ console.log(' ✓ Database restored');
264
+
265
+ // Restore credentials
266
+ const restoredCreds = await restoreCredentials(backupsDir, timestamp);
267
+ console.log(` ✓ Credentials restored: ${restoredCreds} file(s)`);
268
+
269
+ // Run migrations
270
+ console.log(' Running schema migrations...');
271
+ let migrationsApplied: number;
272
+ try {
273
+ migrationsApplied = await runMigrations();
274
+ } catch {
275
+ if (preRestoreName) {
276
+ console.error(`\n Reverting to pre-restore backup: ${preRestoreName}`);
277
+ const revertTemp = dbPath + '.revert-tmp';
278
+ await copyFile(join(backupsDir, preRestoreName), revertTemp);
279
+ await rename(revertTemp, dbPath);
280
+ console.error(' ✓ Reverted to pre-restore state.');
281
+ }
282
+ process.exit(1);
283
+ }
284
+ console.log(` ✓ Migrations applied: ${migrationsApplied}`);
285
+
286
+ // Final integrity check
287
+ console.log(' Verifying restored database...');
288
+ if (!verifyIntegrity(dbPath)) {
289
+ console.error(' ✗ Restored DB FAILED integrity check!');
290
+ console.error(` Safety backup available: ${preRestoreName}`);
291
+ process.exit(1);
292
+ }
293
+ console.log(' ✓ Restored database integrity OK');
294
+
295
+ // Clean up old pre-restore backups (keep last 3)
296
+ const allBackupFiles = await readdir(backupsDir);
297
+ const preRestoreFiles = allBackupFiles
298
+ .filter(f => f.startsWith('pre-restore.') && f.endsWith('.bak'))
299
+ .sort()
300
+ .reverse();
301
+ if (preRestoreFiles.length > 3) {
302
+ for (let i = 3; i < preRestoreFiles.length; i++) {
303
+ await unlink(join(backupsDir, preRestoreFiles[i]));
304
+ }
305
+ console.log(` ✓ Cleaned up ${preRestoreFiles.length - 3} old pre-restore backup(s)`);
306
+ }
307
+
308
+ console.log(`\n ✅ Restore complete!\n`);
309
+ }
310
+
311
+ main().catch((err) => {
312
+ console.error('Restore failed:', err.message || err);
313
+ process.exit(1);
314
+ });