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,447 @@
1
+ /**
2
+ * Terminal Approval Interface
3
+ *
4
+ * Connects to the WebSocket server to receive ACTION_CREATED events
5
+ * and presents an interactive terminal UI for approve/reject decisions.
6
+ */
7
+
8
+ import * as readline from 'readline';
9
+ import { WebSocket } from 'ws';
10
+ import { getErrorMessage } from '../lib/error';
11
+
12
+ interface HumanAction {
13
+ id: string;
14
+ type: string;
15
+ agentId: string;
16
+ limit: number;
17
+ permissions: string[];
18
+ ttl: number;
19
+ createdAt: number;
20
+ }
21
+
22
+ interface ApprovalManagerOptions {
23
+ serverUrl: string;
24
+ getToken: () => string | null;
25
+ autoApprove?: boolean;
26
+ headless?: boolean; // Skip terminal interface (for --password-stdin mode)
27
+ }
28
+
29
+ export class ApprovalManager {
30
+ private ws: WebSocket | null = null;
31
+ private pendingRequests: Map<string, HumanAction> = new Map();
32
+ private rl: readline.Interface | null = null;
33
+ private options: ApprovalManagerOptions;
34
+ private reconnectTimeout: NodeJS.Timeout | null = null;
35
+ private isRunning = false;
36
+
37
+ constructor(options: ApprovalManagerOptions) {
38
+ this.options = options;
39
+ }
40
+
41
+ /**
42
+ * Start the approval manager
43
+ */
44
+ async start(): Promise<void> {
45
+ this.isRunning = true;
46
+
47
+ // Fetch any existing pending requests
48
+ await this.fetchPendingRequests();
49
+
50
+ // Connect to WebSocket
51
+ this.connectWebSocket();
52
+
53
+ // Set up terminal interface (skip in headless mode)
54
+ if (!this.options.headless) {
55
+ this.setupTerminalInterface();
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Stop the approval manager
61
+ */
62
+ stop(): void {
63
+ this.isRunning = false;
64
+
65
+ if (this.reconnectTimeout) {
66
+ clearTimeout(this.reconnectTimeout);
67
+ this.reconnectTimeout = null;
68
+ }
69
+
70
+ if (this.ws) {
71
+ this.ws.close();
72
+ this.ws = null;
73
+ }
74
+
75
+ if (this.rl) {
76
+ this.rl.close();
77
+ this.rl = null;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Fetch existing pending requests from the server
83
+ */
84
+ private async fetchPendingRequests(): Promise<void> {
85
+ try {
86
+ const token = this.options.getToken();
87
+ if (!token) return;
88
+
89
+ const response = await fetch(`${this.options.serverUrl}/actions/pending`, {
90
+ headers: { Authorization: `Bearer ${token}` }
91
+ });
92
+
93
+ if (response.ok) {
94
+ const data = await response.json() as { success?: boolean; actions?: HumanAction[] };
95
+ const requests = data.actions || [];
96
+ for (const req of requests) {
97
+ this.addRequest(req);
98
+ }
99
+ if (requests.length > 0) {
100
+ console.log(`\nFound ${requests.length} pending request(s).`);
101
+ this.displayQueue();
102
+ }
103
+ }
104
+ } catch {
105
+ // Silently ignore - will get requests via WebSocket
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Connect to the WebSocket server
111
+ */
112
+ private connectWebSocket(): void {
113
+ const wsUrl = process.env.WS_URL || 'ws://localhost:4748';
114
+
115
+ try {
116
+ this.ws = new WebSocket(wsUrl);
117
+
118
+ this.ws.on('open', () => {
119
+ console.log('WebSocket connected - listening for events');
120
+ });
121
+
122
+ this.ws.on('message', (data: Buffer) => {
123
+ try {
124
+ const event = JSON.parse(data.toString());
125
+ this.handleEvent(event);
126
+ } catch {
127
+ // Ignore malformed messages
128
+ }
129
+ });
130
+
131
+ this.ws.on('close', () => {
132
+ if (this.isRunning) {
133
+ console.log('WebSocket disconnected, reconnecting in 3s...');
134
+ this.reconnectTimeout = setTimeout(() => {
135
+ this.connectWebSocket();
136
+ }, 3000);
137
+ }
138
+ });
139
+
140
+ this.ws.on('error', (error) => {
141
+ console.error('WebSocket error:', error.message);
142
+ });
143
+ } catch (error) {
144
+ console.error('Failed to connect WebSocket:', error);
145
+ if (this.isRunning) {
146
+ this.reconnectTimeout = setTimeout(() => {
147
+ this.connectWebSocket();
148
+ }, 3000);
149
+ }
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Handle incoming WebSocket event
155
+ */
156
+ private handleEvent(event: { type: string; data: unknown }): void {
157
+ switch (event.type) {
158
+ case 'action:created':
159
+ this.handleRequestCreated(event.data as HumanAction);
160
+ break;
161
+ case 'action:resolved':
162
+ this.handleRequestResolved((event.data as { id: string }).id);
163
+ break;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Handle new request created
169
+ */
170
+ private handleRequestCreated(request: HumanAction): void {
171
+ this.addRequest(request);
172
+
173
+ console.log('\n┌─────────────────────────────────────────────────────────────┐');
174
+ console.log('│ NEW AGENT REQUEST │');
175
+ console.log('├─────────────────────────────────────────────────────────────┤');
176
+ console.log(`│ ID: ${request.id.substring(0, 40).padEnd(45)}│`);
177
+ console.log(`│ Agent: ${request.agentId.substring(0, 40).padEnd(45)}│`);
178
+ console.log(`│ Type: ${request.type.padEnd(45)}│`);
179
+ console.log(`│ Limit: ${(request.limit + ' ETH').padEnd(45)}│`);
180
+ console.log(`│ Permissions: ${request.permissions.slice(0, 3).join(', ').substring(0, 40).padEnd(45)}│`);
181
+ console.log(`│ TTL: ${(request.ttl + 's').padEnd(45)}│`);
182
+ console.log('└─────────────────────────────────────────────────────────────┘');
183
+
184
+ if (this.options.autoApprove) {
185
+ console.log('Auto-approving (--auto-approve enabled)...');
186
+ this.resolveAction(request.id, true);
187
+ } else {
188
+ console.log('\nEnter request number to review, or:');
189
+ console.log(' a <id> - approve r <id> - reject l - list pending\n');
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Handle request resolved (approved or rejected)
195
+ */
196
+ private handleRequestResolved(requestId: string): void {
197
+ this.pendingRequests.delete(requestId);
198
+ }
199
+
200
+ /**
201
+ * Add request to pending queue
202
+ */
203
+ private addRequest(request: HumanAction): void {
204
+ this.pendingRequests.set(request.id, {
205
+ ...request,
206
+ createdAt: Date.now()
207
+ });
208
+ }
209
+
210
+ /**
211
+ * Display the pending request queue
212
+ */
213
+ private displayQueue(): void {
214
+ const requests = Array.from(this.pendingRequests.values());
215
+
216
+ if (requests.length === 0) {
217
+ console.log('\nNo pending requests.\n');
218
+ return;
219
+ }
220
+
221
+ console.log('\n┌─────────────────────────────────────────────────────────────┐');
222
+ console.log('│ PENDING REQUESTS │');
223
+ console.log('├─────────────────────────────────────────────────────────────┤');
224
+
225
+ requests.forEach((req, index) => {
226
+ const shortId = req.id.substring(0, 8);
227
+ const agent = req.agentId.substring(0, 20).padEnd(20);
228
+ const type = req.type.substring(0, 15).padEnd(15);
229
+ console.log(`│ ${(index + 1).toString().padStart(2)}. [${shortId}] ${agent} ${type} ${req.limit} ETH │`);
230
+ });
231
+
232
+ console.log('└─────────────────────────────────────────────────────────────┘');
233
+ console.log('\nCommands: a <id> approve, r <id> reject, <num> review, l list\n');
234
+ }
235
+
236
+ /**
237
+ * Set up terminal interface for user input
238
+ */
239
+ private setupTerminalInterface(): void {
240
+ this.rl = readline.createInterface({
241
+ input: process.stdin,
242
+ output: process.stdout,
243
+ prompt: 'aura> '
244
+ });
245
+
246
+ this.rl.on('line', (line) => {
247
+ this.handleCommand(line.trim());
248
+ this.rl?.prompt();
249
+ });
250
+
251
+ this.rl.on('close', () => {
252
+ // Interface closed
253
+ });
254
+
255
+ // Initial prompt
256
+ this.rl.prompt();
257
+ }
258
+
259
+ /**
260
+ * Handle user command
261
+ */
262
+ private handleCommand(input: string): void {
263
+ if (!input) return;
264
+
265
+ const parts = input.split(/\s+/);
266
+ const cmd = parts[0].toLowerCase();
267
+ const arg = parts[1];
268
+
269
+ switch (cmd) {
270
+ case 'l':
271
+ case 'list':
272
+ this.displayQueue();
273
+ break;
274
+
275
+ case 'a':
276
+ case 'approve':
277
+ if (arg) {
278
+ this.approveByIdOrNumber(arg);
279
+ } else {
280
+ console.log('Usage: a <id or number>');
281
+ }
282
+ break;
283
+
284
+ case 'r':
285
+ case 'reject':
286
+ if (arg) {
287
+ this.rejectByIdOrNumber(arg);
288
+ } else {
289
+ console.log('Usage: r <id or number>');
290
+ }
291
+ break;
292
+
293
+ case 'h':
294
+ case 'help':
295
+ this.showHelp();
296
+ break;
297
+
298
+ case 'q':
299
+ case 'quit':
300
+ console.log('Use Ctrl+C to exit.');
301
+ break;
302
+
303
+ default:
304
+ // Check if it's a number (review by index)
305
+ const num = parseInt(cmd, 10);
306
+ if (!isNaN(num)) {
307
+ this.reviewByNumber(num);
308
+ } else {
309
+ console.log(`Unknown command: ${cmd}. Type 'h' for help.`);
310
+ }
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Show help
316
+ */
317
+ private showHelp(): void {
318
+ console.log(`
319
+ Commands:
320
+ l, list List all pending requests
321
+ a, approve <id> Approve request by ID or number
322
+ r, reject <id> Reject request by ID or number
323
+ <number> Review request details by queue number
324
+ h, help Show this help
325
+ Ctrl+C Exit CLI
326
+ `);
327
+ }
328
+
329
+ /**
330
+ * Review request by queue number
331
+ */
332
+ private reviewByNumber(num: number): void {
333
+ const requests = Array.from(this.pendingRequests.values());
334
+ const index = num - 1;
335
+
336
+ if (index < 0 || index >= requests.length) {
337
+ console.log(`Invalid number. Use 1-${requests.length}`);
338
+ return;
339
+ }
340
+
341
+ const req = requests[index];
342
+ console.log(`
343
+ ┌─────────────────────────────────────────────────────────────┐
344
+ │ REQUEST DETAILS │
345
+ ├─────────────────────────────────────────────────────────────┤
346
+ │ ID: ${req.id}
347
+ │ Agent: ${req.agentId}
348
+ │ Type: ${req.type}
349
+ │ Limit: ${req.limit} ETH
350
+ │ Permissions: ${req.permissions.join(', ')}
351
+ │ TTL: ${req.ttl}s (${Math.round(req.ttl / 60)} minutes)
352
+ └─────────────────────────────────────────────────────────────┘
353
+
354
+ a ${num} - approve r ${num} - reject
355
+ `);
356
+ }
357
+
358
+ /**
359
+ * Approve by ID or queue number
360
+ */
361
+ private approveByIdOrNumber(arg: string): void {
362
+ const id = this.resolveRequestId(arg);
363
+ if (id) {
364
+ this.resolveAction(id, true);
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Reject by ID or queue number
370
+ */
371
+ private rejectByIdOrNumber(arg: string): void {
372
+ const id = this.resolveRequestId(arg);
373
+ if (id) {
374
+ this.resolveAction(id, false);
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Resolve argument to request ID
380
+ */
381
+ private resolveRequestId(arg: string): string | null {
382
+ // Try as number first
383
+ const num = parseInt(arg, 10);
384
+ if (!isNaN(num)) {
385
+ const requests = Array.from(this.pendingRequests.values());
386
+ const index = num - 1;
387
+ if (index >= 0 && index < requests.length) {
388
+ return requests[index].id;
389
+ }
390
+ console.log(`Invalid number. Use 1-${requests.length}`);
391
+ return null;
392
+ }
393
+
394
+ // Try as ID (partial match)
395
+ const matching = Array.from(this.pendingRequests.keys()).filter(
396
+ id => id.startsWith(arg) || id.includes(arg)
397
+ );
398
+
399
+ if (matching.length === 1) {
400
+ return matching[0];
401
+ } else if (matching.length > 1) {
402
+ console.log('Ambiguous ID, matches:', matching.map(id => id.substring(0, 12)).join(', '));
403
+ return null;
404
+ } else {
405
+ console.log('Request not found:', arg);
406
+ return null;
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Resolve an action (approve or reject)
412
+ */
413
+ private async resolveAction(requestId: string, approved: boolean): Promise<void> {
414
+ const token = this.options.getToken();
415
+ if (!token) {
416
+ console.log('Error: No admin token available');
417
+ return;
418
+ }
419
+
420
+ try {
421
+ const response = await fetch(`${this.options.serverUrl}/actions/${requestId}/resolve`, {
422
+ method: 'POST',
423
+ headers: {
424
+ 'Content-Type': 'application/json',
425
+ Authorization: `Bearer ${token}`
426
+ },
427
+ body: JSON.stringify({ approved })
428
+ });
429
+
430
+ const data = await response.json() as { success?: boolean; error?: string; agentId?: string; token?: string };
431
+
432
+ if (response.ok && data.success) {
433
+ if (approved) {
434
+ console.log(`✓ Request approved. Token created for ${data.agentId}`);
435
+ } else {
436
+ console.log(`✓ Request rejected`);
437
+ }
438
+ this.pendingRequests.delete(requestId);
439
+ } else {
440
+ console.log(`✗ Failed to ${approved ? 'approve' : 'reject'}: ${data.error || 'Unknown error'}`);
441
+ }
442
+ } catch (error) {
443
+ const message = getErrorMessage(error);
444
+ console.log(`✗ Error ${approved ? 'approving' : 'rejecting'} request: ${message}`);
445
+ }
446
+ }
447
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * aurawallet app — Manage installed apps
3
+ *
4
+ * Usage:
5
+ * npx aurawallet app install <source> [--name <id>] [--force]
6
+ * npx aurawallet app remove <id> [--yes]
7
+ * npx aurawallet app list
8
+ * npx aurawallet app update <id>
9
+ */
10
+
11
+ import {
12
+ installApp,
13
+ removeApp,
14
+ listApps,
15
+ updateApp,
16
+ } from '../../lib/app-installer';
17
+ import { promptConfirm } from '../lib/prompt';
18
+ import { getErrorMessage } from '../../lib/error';
19
+
20
+ const args = process.argv.slice(2);
21
+
22
+ function getFlag(name: string): boolean {
23
+ return args.includes(`--${name}`);
24
+ }
25
+
26
+ function getFlagValue(name: string): string | undefined {
27
+ const idx = args.indexOf(`--${name}`);
28
+ if (idx === -1 || idx + 1 >= args.length) return undefined;
29
+ return args[idx + 1];
30
+ }
31
+
32
+ function showHelp() {
33
+ console.log(`
34
+ aurawallet app — Manage installed apps
35
+
36
+ Usage:
37
+ npx aurawallet app install <source> [--name <id>] [--force]
38
+ npx aurawallet app remove <id> [--yes]
39
+ npx aurawallet app list
40
+ npx aurawallet app update <id>
41
+
42
+ Sources:
43
+ Local path ./path/to/app or /absolute/path
44
+ Git repo github.com/user/repo
45
+ Tarball https://example.com/app.tar.gz
46
+ Zip https://example.com/app.zip
47
+ Subdirectory github.com/user/repo#path=apps/my-app
48
+
49
+ Options:
50
+ --name <id> Override the app folder name
51
+ --force Overwrite existing app with same ID
52
+ --yes Skip removal confirmation
53
+
54
+ Examples:
55
+ npx aurawallet app install github.com/user/my-app
56
+ npx aurawallet app install ./my-local-app --name custom-id
57
+ npx aurawallet app list
58
+ npx aurawallet app remove my-app
59
+ npx aurawallet app update my-app
60
+ `);
61
+ }
62
+
63
+ async function main() {
64
+ const subcommand = args[0];
65
+
66
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
67
+ showHelp();
68
+ process.exit(0);
69
+ }
70
+
71
+ switch (subcommand) {
72
+ case 'install': {
73
+ const source = args[1];
74
+ if (!source || source.startsWith('--')) {
75
+ console.error(' Error: Missing source argument\n');
76
+ console.error(' Usage: npx aurawallet app install <source> [--name <id>] [--force]');
77
+ process.exit(1);
78
+ }
79
+
80
+ const name = getFlagValue('name');
81
+ const force = getFlag('force');
82
+
83
+ console.log(`\n Installing app from: ${source}`);
84
+ if (name) console.log(` App ID: ${name}`);
85
+ if (force) console.log(` Force: overwrite existing`);
86
+ console.log('');
87
+
88
+ try {
89
+ const result = installApp(source, { name, force });
90
+ console.log(` ┌─────────────────────────────────────────┐`);
91
+ console.log(` │ App installed successfully │`);
92
+ console.log(` ├─────────────────────────────────────────┤`);
93
+ console.log(` │ ID: ${result.id.padEnd(32)}│`);
94
+ console.log(` │ Name: ${result.name.padEnd(32)}│`);
95
+ console.log(` │ Source: ${result.source.type.padEnd(32)}│`);
96
+ console.log(` │ Path: apps/${result.id.padEnd(23)}│`);
97
+ console.log(` └─────────────────────────────────────────┘`);
98
+ console.log('');
99
+ console.log(' App will appear in the App Store under INSTALLED.');
100
+ console.log(' Restart the server or use the dashboard to load it.\n');
101
+ } catch (err) {
102
+ const msg = getErrorMessage(err);
103
+ console.error(` Error: ${msg}\n`);
104
+ process.exit(1);
105
+ }
106
+ break;
107
+ }
108
+
109
+ case 'remove': {
110
+ const id = args[1];
111
+ if (!id || id.startsWith('--')) {
112
+ console.error(' Error: Missing app ID\n');
113
+ console.error(' Usage: npx aurawallet app remove <id> [--yes]');
114
+ process.exit(1);
115
+ }
116
+
117
+ const skipConfirm = getFlag('yes');
118
+
119
+ if (!skipConfirm) {
120
+ const confirmed = await promptConfirm(` Remove app "${id}"?`);
121
+ if (!confirmed) {
122
+ console.log(' Cancelled.\n');
123
+ process.exit(0);
124
+ }
125
+ }
126
+
127
+ try {
128
+ removeApp(id);
129
+ console.log(`\n App "${id}" removed.\n`);
130
+ console.log(' Note: App token will be revoked on next server restart.\n');
131
+ } catch (err) {
132
+ const msg = getErrorMessage(err);
133
+ console.error(` Error: ${msg}\n`);
134
+ process.exit(1);
135
+ }
136
+ break;
137
+ }
138
+
139
+ case 'list': {
140
+ const apps = listApps();
141
+
142
+ if (apps.length === 0) {
143
+ console.log('\n No apps installed.\n');
144
+ console.log(' Install a app:');
145
+ console.log(' npx aurawallet app install <source>\n');
146
+ process.exit(0);
147
+ }
148
+
149
+ console.log(`\n Installed Apps (${apps.length})\n`);
150
+
151
+ for (const w of apps) {
152
+ const sourceLabel = w.source
153
+ ? `${w.source.type} — ${w.source.url}`
154
+ : 'local (no .source.json)';
155
+ const perms = w.permissions.length > 0
156
+ ? w.permissions.join(', ')
157
+ : 'none';
158
+
159
+ console.log(` ┌ ${w.name} (${w.id})`);
160
+ console.log(` │ ${w.description || '(no description)'}`);
161
+ console.log(` │ Permissions: ${perms}`);
162
+ console.log(` │ Source: ${sourceLabel}`);
163
+ if (w.source?.installedAt) {
164
+ console.log(` │ Installed: ${w.source.installedAt}`);
165
+ }
166
+ console.log(` └──`);
167
+ console.log('');
168
+ }
169
+ break;
170
+ }
171
+
172
+ case 'update': {
173
+ const id = args[1];
174
+ if (!id || id.startsWith('--')) {
175
+ console.error(' Error: Missing app ID\n');
176
+ console.error(' Usage: npx aurawallet app update <id>');
177
+ process.exit(1);
178
+ }
179
+
180
+ console.log(`\n Updating app "${id}"...\n`);
181
+
182
+ try {
183
+ const result = updateApp(id);
184
+ console.log(` App "${result.id}" updated from ${result.source.type} source.`);
185
+ console.log(` Restart the server to load changes.\n`);
186
+ } catch (err) {
187
+ const msg = getErrorMessage(err);
188
+ console.error(` Error: ${msg}\n`);
189
+ process.exit(1);
190
+ }
191
+ break;
192
+ }
193
+
194
+ default:
195
+ console.error(` Unknown subcommand: ${subcommand}\n`);
196
+ showHelp();
197
+ process.exit(1);
198
+ }
199
+ }
200
+
201
+ main().catch((error) => {
202
+ console.error('Error:', getErrorMessage(error));
203
+ process.exit(1);
204
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * aurawallet cron — Run the cron server standalone
3
+ * Useful for development or running cron separately from the main server.
4
+ */
5
+
6
+ import { findProjectRoot } from '../lib/process';
7
+ import { execFileSync } from 'child_process';
8
+ import path from 'path';
9
+
10
+ const root = findProjectRoot();
11
+ const cronEntry = path.join(root, 'server', 'cron', 'index.ts');
12
+
13
+ console.log('Starting AuraWallet Cron Server...\n');
14
+
15
+ try {
16
+ execFileSync('npx', ['tsx', cronEntry], {
17
+ cwd: root,
18
+ stdio: 'inherit',
19
+ env: process.env,
20
+ });
21
+ } catch (error: unknown) {
22
+ const exitCode = (error as { status?: number }).status || 1;
23
+ process.exit(exitCode);
24
+ }