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,468 @@
1
+ /**
2
+ * aurawallet shell-hook — Auto-load .aura env vars on cd (like direnv)
3
+ *
4
+ * Usage:
5
+ * aura shell-hook bash Output bash hook script
6
+ * aura shell-hook zsh Output zsh hook script
7
+ * aura shell-hook install Auto-detect shell, add to rc file
8
+ * aura shell-hook allow Whitelist current directory
9
+ * aura shell-hook deny Remove directory from whitelist
10
+ * aura shell-hook status Show whitelist + active dir
11
+ * aura shell-hook resolve Internal: resolve .aura and output export statements
12
+ */
13
+
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+ import * as crypto from 'crypto';
17
+ import * as os from 'os';
18
+ import { getErrorMessage } from '../../lib/error';
19
+ import {
20
+ escapeForShell,
21
+ searchCredential,
22
+ readCredential,
23
+ validateEnvVarName,
24
+ } from '../lib/credential-resolve';
25
+
26
+ // ── Paths ──
27
+
28
+ const AURA_DIR = process.env.WALLET_DATA_DIR || path.join(os.homedir(), '.aurawallet');
29
+ const ALLOWED_FILE = path.join(AURA_DIR, 'shell-allowed.json');
30
+ const CACHE_DIR = path.join(AURA_DIR, 'shell-cache');
31
+ const CACHE_SECRET_FILE = path.join(AURA_DIR, 'shell-cache.secret');
32
+
33
+ // ── Whitelist ──
34
+
35
+ interface AllowedEntry {
36
+ allowedAt: string;
37
+ hash: string;
38
+ }
39
+
40
+ function loadAllowed(): Record<string, AllowedEntry> {
41
+ try {
42
+ return JSON.parse(fs.readFileSync(ALLOWED_FILE, 'utf-8'));
43
+ } catch {
44
+ return {};
45
+ }
46
+ }
47
+
48
+ function saveAllowed(allowed: Record<string, AllowedEntry>): void {
49
+ fs.mkdirSync(path.dirname(ALLOWED_FILE), { recursive: true });
50
+ const fd = fs.openSync(ALLOWED_FILE, 'w', 0o600);
51
+ fs.writeSync(fd, JSON.stringify(allowed, null, 2) + '\n');
52
+ fs.closeSync(fd);
53
+ }
54
+
55
+ function hashFile(filePath: string): string {
56
+ const content = fs.readFileSync(filePath);
57
+ return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
58
+ }
59
+
60
+ // ── Cache ──
61
+
62
+ function getOrCreateCacheSecret(): string {
63
+ try {
64
+ return fs.readFileSync(CACHE_SECRET_FILE, 'utf-8').trim();
65
+ } catch {
66
+ const secret = crypto.randomBytes(32).toString('base64url');
67
+ fs.mkdirSync(path.dirname(CACHE_SECRET_FILE), { recursive: true });
68
+ const fd = fs.openSync(CACHE_SECRET_FILE, 'w', 0o600);
69
+ fs.writeSync(fd, secret);
70
+ fs.closeSync(fd);
71
+ return secret;
72
+ }
73
+ }
74
+
75
+ interface CacheEntry {
76
+ vars: Record<string, string>;
77
+ expiresAt: number;
78
+ auraHash: string;
79
+ }
80
+
81
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
82
+
83
+ function getCacheKey(dir: string): string {
84
+ return crypto.createHash('sha256').update(dir).digest('hex').slice(0, 16);
85
+ }
86
+
87
+ function getCache(dir: string, auraHash: string): Record<string, string> | null {
88
+ try {
89
+ const cacheFile = path.join(CACHE_DIR, `${getCacheKey(dir)}.json`);
90
+ const raw = fs.readFileSync(cacheFile, 'utf-8');
91
+ // Try encrypted format first, fall back to legacy plaintext
92
+ let entry: CacheEntry;
93
+ if (raw.startsWith('{')) {
94
+ // Legacy plaintext — delete it (audit finding #2)
95
+ fs.unlinkSync(cacheFile);
96
+ return null;
97
+ }
98
+ entry = JSON.parse(decryptCacheEntry(raw));
99
+ if (entry.expiresAt > Date.now() && entry.auraHash === auraHash) {
100
+ return entry.vars;
101
+ }
102
+ } catch {
103
+ // Cache miss or decryption failure
104
+ }
105
+ return null;
106
+ }
107
+
108
+ /**
109
+ * Derive a machine- and install-local encryption key for cache at rest.
110
+ * Includes a per-install secret stored under ~/.aurawallet to avoid
111
+ * deterministic, host/user-only key derivation.
112
+ */
113
+ function getCacheEncryptionKey(): Buffer {
114
+ const material = `aurawallet-cache:${AURA_DIR}:${getOrCreateCacheSecret()}`;
115
+ return crypto.createHash('sha256').update(material).digest();
116
+ }
117
+
118
+ function encryptCacheEntry(data: string): string {
119
+ const key = getCacheEncryptionKey();
120
+ const iv = crypto.randomBytes(12);
121
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
122
+ const encrypted = Buffer.concat([cipher.update(data, 'utf-8'), cipher.final()]);
123
+ const tag = cipher.getAuthTag();
124
+ // Format: iv:tag:ciphertext (all base64)
125
+ return `${iv.toString('base64')}:${tag.toString('base64')}:${encrypted.toString('base64')}`;
126
+ }
127
+
128
+ function decryptCacheEntry(blob: string): string {
129
+ const key = getCacheEncryptionKey();
130
+ const [ivB64, tagB64, ctB64] = blob.split(':');
131
+ const iv = Buffer.from(ivB64, 'base64');
132
+ const tag = Buffer.from(tagB64, 'base64');
133
+ const ct = Buffer.from(ctB64, 'base64');
134
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
135
+ decipher.setAuthTag(tag);
136
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString('utf-8');
137
+ }
138
+
139
+ function setCache(dir: string, vars: Record<string, string>, auraHash: string): void {
140
+ fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 });
141
+ const cacheFile = path.join(CACHE_DIR, `${getCacheKey(dir)}.json`);
142
+ const entry: CacheEntry = {
143
+ vars,
144
+ expiresAt: Date.now() + CACHE_TTL_MS,
145
+ auraHash,
146
+ };
147
+ const encrypted = encryptCacheEntry(JSON.stringify(entry));
148
+ const fd = fs.openSync(cacheFile, 'w', 0o600);
149
+ fs.writeSync(fd, encrypted);
150
+ fs.closeSync(fd);
151
+ }
152
+
153
+ // ── Shell hooks ──
154
+
155
+ function bashHook(): string {
156
+ return `# Aura shell hook — auto-load .aura env vars
157
+ _aura_hook() {
158
+ local prev_aura_dir="\${_AURA_DIR:-}"
159
+ local aura_file=""
160
+ local check_dir="$PWD"
161
+
162
+ while [ "$check_dir" != "/" ]; do
163
+ if [ -f "$check_dir/.aura" ]; then
164
+ aura_file="$check_dir/.aura"
165
+ break
166
+ fi
167
+ check_dir="$(dirname "$check_dir")"
168
+ done
169
+
170
+ if [ -n "$aura_file" ]; then
171
+ local aura_dir="$(dirname "$aura_file")"
172
+ if [ "$aura_dir" != "$prev_aura_dir" ]; then
173
+ if [ -n "$prev_aura_dir" ] && [ -n "\${_AURA_VARS:-}" ]; then
174
+ for var in $_AURA_VARS; do unset "$var"; done
175
+ fi
176
+ local output
177
+ output="$(aura shell-hook resolve 2>/dev/null)"
178
+ if [ $? -eq 0 ] && [ -n "$output" ]; then
179
+ eval "$output"
180
+ export _AURA_DIR="$aura_dir"
181
+ fi
182
+ fi
183
+ elif [ -n "$prev_aura_dir" ]; then
184
+ if [ -n "\${_AURA_VARS:-}" ]; then
185
+ for var in $_AURA_VARS; do unset "$var"; done
186
+ fi
187
+ unset _AURA_DIR _AURA_VARS
188
+ fi
189
+ }
190
+
191
+ if [[ ";\${PROMPT_COMMAND:-};" != *";_aura_hook;"* ]]; then
192
+ PROMPT_COMMAND="_aura_hook;\${PROMPT_COMMAND:-}"
193
+ fi
194
+ `;
195
+ }
196
+
197
+ function zshHook(): string {
198
+ return `# Aura shell hook — auto-load .aura env vars
199
+ _aura_hook() {
200
+ local prev_aura_dir="\${_AURA_DIR:-}"
201
+ local aura_file=""
202
+ local check_dir="$PWD"
203
+
204
+ while [[ "$check_dir" != "/" ]]; do
205
+ if [[ -f "$check_dir/.aura" ]]; then
206
+ aura_file="$check_dir/.aura"
207
+ break
208
+ fi
209
+ check_dir="$(dirname "$check_dir")"
210
+ done
211
+
212
+ if [[ -n "$aura_file" ]]; then
213
+ local aura_dir="$(dirname "$aura_file")"
214
+ if [[ "$aura_dir" != "$prev_aura_dir" ]]; then
215
+ if [[ -n "$prev_aura_dir" ]] && [[ -n "\${_AURA_VARS:-}" ]]; then
216
+ for var in \${(z)_AURA_VARS}; do unset "$var"; done
217
+ fi
218
+ local output
219
+ output="$(aura shell-hook resolve 2>/dev/null)"
220
+ if [[ $? -eq 0 ]] && [[ -n "$output" ]]; then
221
+ eval "$output"
222
+ export _AURA_DIR="$aura_dir"
223
+ fi
224
+ fi
225
+ elif [[ -n "$prev_aura_dir" ]]; then
226
+ if [[ -n "\${_AURA_VARS:-}" ]]; then
227
+ for var in \${(z)_AURA_VARS}; do unset "$var"; done
228
+ fi
229
+ unset _AURA_DIR _AURA_VARS
230
+ fi
231
+ }
232
+
233
+ autoload -U add-zsh-hook
234
+ add-zsh-hook chpwd _aura_hook
235
+ _aura_hook
236
+ `;
237
+ }
238
+
239
+ // ── Resolve (internal) ──
240
+
241
+ async function cmdResolve(): Promise<void> {
242
+ let dir = process.cwd();
243
+ let auraFile: string | null = null;
244
+ while (true) {
245
+ const candidate = path.join(dir, '.aura');
246
+ if (fs.existsSync(candidate)) { auraFile = candidate; break; }
247
+ const parent = path.dirname(dir);
248
+ if (parent === dir) break;
249
+ dir = parent;
250
+ }
251
+
252
+ if (!auraFile) process.exit(1);
253
+
254
+ const auraDir = path.dirname(auraFile);
255
+ const auraHash = hashFile(auraFile);
256
+
257
+ // Check whitelist
258
+ const allowed = loadAllowed();
259
+ const entry = allowed[auraDir];
260
+ if (!entry) {
261
+ console.error(`aura: ${auraDir} is not allowed. Run: aura shell-hook allow`);
262
+ process.exit(1);
263
+ }
264
+ if (entry.hash !== auraHash) {
265
+ console.error(`aura: .aura file changed in ${auraDir}. Run: aura shell-hook allow`);
266
+ process.exit(1);
267
+ }
268
+
269
+ // Check cache
270
+ const cached = getCache(auraDir, auraHash);
271
+ if (cached) {
272
+ outputExports(cached);
273
+ return;
274
+ }
275
+
276
+ // Resolve from vault using shared module (audit finding #3)
277
+ const { parseAuraFile } = await import('./env');
278
+ const {
279
+ generateEphemeralKeypair,
280
+ bootstrapViaSocket,
281
+ decryptWithPrivateKey,
282
+ createReadToken,
283
+ } = await import('../../lib/credential-transport');
284
+ const { serverUrl } = await import('../lib/http');
285
+ const { resolveMappings } = await import('../lib/credential-resolve');
286
+
287
+ const keypair = generateEphemeralKeypair();
288
+ const envToken = process.env.AURA_TOKEN;
289
+ const token = envToken || await bootstrapViaSocket('shell-hook', keypair);
290
+ const base = serverUrl();
291
+ const readToken = await createReadToken(base, token, keypair, 'shell-hook-reader');
292
+
293
+ const mappings = parseAuraFile(auraFile);
294
+ const decryptFn = (encrypted: string) => decryptWithPrivateKey(encrypted, keypair.privateKeyPem);
295
+ const { resolved } = await resolveMappings(mappings, base, token, readToken, decryptFn);
296
+
297
+ const vars: Record<string, string> = Object.fromEntries(resolved);
298
+ setCache(auraDir, vars, auraHash);
299
+ outputExports(vars);
300
+ }
301
+
302
+ function outputExports(vars: Record<string, string>): void {
303
+ const varNames: string[] = [];
304
+ for (const [key, value] of Object.entries(vars)) {
305
+ // Validate env var name to prevent injection via key (audit finding #6)
306
+ validateEnvVarName(key);
307
+ // Use ANSI-C $'...' quoting for safe shell escaping (audit finding #1)
308
+ console.log(`export ${key}=${escapeForShell(value)}`);
309
+ varNames.push(key);
310
+ }
311
+ if (varNames.length > 0) {
312
+ console.log(`export _AURA_VARS=${escapeForShell(varNames.join(' '))}`);
313
+ }
314
+ }
315
+
316
+ // ── Install ──
317
+
318
+ function cmdInstall(): void {
319
+ const shell = path.basename(process.env.SHELL || 'bash');
320
+ let rcFile: string;
321
+ let hookCmd: string;
322
+
323
+ switch (shell) {
324
+ case 'zsh':
325
+ rcFile = path.join(os.homedir(), '.zshrc');
326
+ hookCmd = 'eval "$(aura shell-hook zsh)"';
327
+ break;
328
+ case 'bash':
329
+ rcFile = path.join(os.homedir(), '.bashrc');
330
+ hookCmd = 'eval "$(aura shell-hook bash)"';
331
+ break;
332
+ default:
333
+ console.error(`Unsupported shell: ${shell}. Manually add the hook to your rc file.`);
334
+ process.exit(1);
335
+ return;
336
+ }
337
+
338
+ if (fs.existsSync(rcFile)) {
339
+ const content = fs.readFileSync(rcFile, 'utf-8');
340
+ if (content.includes('aura shell-hook')) {
341
+ console.log(`Aura shell hook already installed in ${rcFile}`);
342
+ return;
343
+ }
344
+ }
345
+
346
+ fs.appendFileSync(rcFile, `\n# Aura shell hook — auto-load .aura env vars\n${hookCmd}\n`);
347
+ console.log(`✓ Added shell hook to ${rcFile}`);
348
+ console.log(` Restart your shell or run: source ${rcFile}`);
349
+ }
350
+
351
+ // ── Allow / Deny / Status ──
352
+
353
+ function cmdAllow(dir?: string): void {
354
+ const targetDir = dir ? path.resolve(dir) : process.cwd();
355
+ const auraFile = path.join(targetDir, '.aura');
356
+
357
+ if (!fs.existsSync(auraFile)) {
358
+ console.error(`No .aura file found in ${targetDir}`);
359
+ process.exit(1);
360
+ }
361
+
362
+ const allowed = loadAllowed();
363
+ allowed[targetDir] = {
364
+ allowedAt: new Date().toISOString(),
365
+ hash: hashFile(auraFile),
366
+ };
367
+ saveAllowed(allowed);
368
+ console.log(`✓ Allowed ${targetDir}`);
369
+ }
370
+
371
+ function cmdDeny(dir?: string): void {
372
+ const targetDir = dir ? path.resolve(dir) : process.cwd();
373
+ const allowed = loadAllowed();
374
+ if (allowed[targetDir]) {
375
+ delete allowed[targetDir];
376
+ saveAllowed(allowed);
377
+ console.log(`✓ Denied ${targetDir}`);
378
+ } else {
379
+ console.log(`${targetDir} was not in the whitelist.`);
380
+ }
381
+ }
382
+
383
+ function cmdStatus(): void {
384
+ const allowed = loadAllowed();
385
+ const entries = Object.entries(allowed);
386
+
387
+ if (entries.length === 0) {
388
+ console.log('No directories whitelisted.');
389
+ console.log('Run `aura shell-hook allow` in a directory with a .aura file.');
390
+ return;
391
+ }
392
+
393
+ console.log('Whitelisted directories:\n');
394
+ for (const [dir, entry] of entries) {
395
+ const auraExists = fs.existsSync(path.join(dir, '.aura'));
396
+ let status = auraExists ? '✓' : '✗ .aura missing';
397
+ if (auraExists) {
398
+ const currentHash = hashFile(path.join(dir, '.aura'));
399
+ if (currentHash !== entry.hash) {
400
+ status = '⚠ .aura changed (run allow again)';
401
+ }
402
+ }
403
+ console.log(` ${status} ${dir}`);
404
+ console.log(` Allowed: ${entry.allowedAt}`);
405
+ }
406
+ }
407
+
408
+ // ── Help ──
409
+
410
+ function showHelp(): void {
411
+ console.log(`
412
+ aurawallet shell-hook — Auto-load .aura env vars on cd
413
+
414
+ Usage:
415
+ aura shell-hook bash Output bash hook script
416
+ aura shell-hook zsh Output zsh hook script
417
+ aura shell-hook install Auto-detect shell, add to rc file
418
+ aura shell-hook allow Whitelist current directory
419
+ aura shell-hook deny Remove from whitelist
420
+ aura shell-hook status Show whitelist
421
+
422
+ Quick start:
423
+ aura shell-hook install # One-time setup
424
+ cd my-project # Has .aura file
425
+ aura shell-hook allow # Whitelist this project
426
+ cd ../ && cd my-project # Env vars auto-loaded!
427
+ `);
428
+ }
429
+
430
+ // ── Main ──
431
+
432
+ async function main(): Promise<void> {
433
+ const args = process.argv.slice(2);
434
+ const subcommand = args[0];
435
+
436
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
437
+ showHelp();
438
+ process.exit(0);
439
+ }
440
+
441
+ switch (subcommand) {
442
+ case 'bash':
443
+ process.stdout.write(bashHook());
444
+ return;
445
+ case 'zsh':
446
+ process.stdout.write(zshHook());
447
+ return;
448
+ case 'install':
449
+ return cmdInstall();
450
+ case 'allow':
451
+ return cmdAllow(args[1]);
452
+ case 'deny':
453
+ return cmdDeny(args[1]);
454
+ case 'status':
455
+ return cmdStatus();
456
+ case 'resolve':
457
+ return cmdResolve();
458
+ default:
459
+ console.error(`Unknown subcommand: ${subcommand}`);
460
+ showHelp();
461
+ process.exit(1);
462
+ }
463
+ }
464
+
465
+ main().catch((err) => {
466
+ console.error(`Error: ${getErrorMessage(err)}`);
467
+ process.exit(1);
468
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * aurawallet start — Start wallet servers
3
+ */
4
+
5
+ import { waitForServer } from '../lib/http';
6
+ import { startServer, stopServer } from '../lib/process';
7
+ import { getErrorMessage } from '../../lib/error';
8
+ import { printBanner, printStatus, paint, ANSI } from '../lib/theme';
9
+
10
+ const args = process.argv.slice(2);
11
+ const headless = args.includes('--headless');
12
+
13
+ async function main() {
14
+ printBanner(headless ? 'HEADLESS' : 'STARTING');
15
+
16
+ // Clean slate
17
+ stopServer();
18
+
19
+ // Start servers
20
+ startServer({ headless });
21
+
22
+ // Wait for Express server
23
+ try {
24
+ await waitForServer(15000);
25
+ } catch {
26
+ console.error('Server failed to start within 15 seconds.');
27
+ console.error('Check for port conflicts on :4242');
28
+ stopServer();
29
+ process.exit(1);
30
+ }
31
+
32
+ printBanner(headless ? 'HEADLESS' : 'RUNNING');
33
+ printStatus('Mode', headless ? 'HEADLESS' : 'FULL', true);
34
+ printStatus('Wallet Server', 'http://localhost:4242', true);
35
+ printStatus('WebSocket', 'ws://localhost:4748', true);
36
+ printStatus('Cron Server', 'running (balance sync, price sync)', true);
37
+ if (!headless) {
38
+ printStatus('Dashboard', 'http://localhost:4747/app', true);
39
+ }
40
+ console.log('');
41
+ console.log(` Press ${paint('Ctrl+C', ANSI.bold)} to stop.\n`);
42
+
43
+ // Graceful shutdown
44
+ const shutdown = () => {
45
+ console.log('\nShutting down...');
46
+ stopServer();
47
+ console.log('Goodbye.');
48
+ process.exit(0);
49
+ };
50
+
51
+ process.on('SIGINT', shutdown);
52
+ process.on('SIGTERM', shutdown);
53
+
54
+ // Keep event loop alive so Ctrl+C works
55
+ setInterval(() => {}, 60_000);
56
+ }
57
+
58
+ main().catch((error) => {
59
+ console.error('Error:', getErrorMessage(error));
60
+ stopServer();
61
+ process.exit(1);
62
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * aurawallet status — Health check and wallet status
3
+ */
4
+
5
+ import { serverUrl, fetchJson, isServerRunning } from '../lib/http';
6
+ import { getErrorMessage } from '../../lib/error';
7
+ import { printBanner, printSection, printStatus } from '../lib/theme';
8
+
9
+ interface SetupStatus {
10
+ hasWallet: boolean;
11
+ unlocked: boolean;
12
+ address: string | null;
13
+ }
14
+
15
+ async function main() {
16
+ const url = serverUrl();
17
+
18
+ printBanner('STATUS');
19
+
20
+ // Check Express server
21
+ const serverUp = await isServerRunning();
22
+ printStatus('Wallet Server', url, serverUp);
23
+
24
+ if (!serverUp) {
25
+ console.log('\n Run `npx aurawallet start` to start the server.');
26
+ process.exit(0);
27
+ }
28
+
29
+ // Check dashboard
30
+ let dashboardUp = false;
31
+ try {
32
+ const resp = await fetch('http://localhost:4747/app');
33
+ dashboardUp = resp.ok || resp.status === 200 || resp.status === 304;
34
+ } catch {
35
+ // Not running
36
+ }
37
+ printStatus('Dashboard', 'http://localhost:4747/app', dashboardUp);
38
+
39
+ // Check wallet status
40
+ try {
41
+ const status = await fetchJson<SetupStatus>('/setup');
42
+ console.log('');
43
+ printStatus('Vault', status.hasWallet ? 'created' : 'not created', status.hasWallet);
44
+ printStatus('Unlocked', status.unlocked ? 'yes' : 'no', status.unlocked);
45
+ if (status.address) {
46
+ printStatus('Address', status.address);
47
+ }
48
+ } catch (error) {
49
+ const message = getErrorMessage(error);
50
+ console.log(`\n Could not fetch wallet status: ${message}`);
51
+ }
52
+
53
+ console.log('');
54
+ }
55
+
56
+ main().catch((error) => {
57
+ console.error('Error:', getErrorMessage(error));
58
+ process.exit(1);
59
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * aurawallet stop — Stop running servers
3
+ */
4
+
5
+ import { stopServer, cleanupTempFiles } from '../lib/process';
6
+
7
+ function main() {
8
+ console.log('Stopping AuraWallet...');
9
+ stopServer();
10
+ cleanupTempFiles();
11
+ console.log('Stopped.');
12
+ }
13
+
14
+ main();