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,456 @@
1
+ /**
2
+ * aurawallet env — Load env vars from vault via .aura file
3
+ *
4
+ * Usage:
5
+ * npx aurawallet env -- <cmd> [args] Run command with vault-injected env vars
6
+ * npx aurawallet env inject Write .env file from .aura mappings
7
+ * npx aurawallet env check Verify all mapped credentials exist
8
+ * npx aurawallet env list Show mappings without values
9
+ */
10
+
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+ import { spawn } from 'child_process';
14
+ import {
15
+ generateEphemeralKeypair,
16
+ bootstrapViaSocket,
17
+ decryptWithPrivateKey,
18
+ createReadToken,
19
+ } from '../../lib/credential-transport';
20
+ import { serverUrl, fetchSetupStatus } from '../lib/http';
21
+ import { getErrorMessage } from '../../lib/error';
22
+ import { createCredentialViaApi, getPrimaryVaultId } from '../lib/credential-create';
23
+ import { migrateDotenv } from '../lib/dotenv-migrate';
24
+ import { promptInput } from '../lib/prompt';
25
+ import {
26
+ type AuraMapping,
27
+ type CredentialMeta,
28
+ type DecryptedCredential,
29
+ searchCredential,
30
+ readCredential,
31
+ resolveMappings as sharedResolveMappings,
32
+ } from '../lib/credential-resolve';
33
+ import { parseAuraFile } from '../lib/aura-parser';
34
+
35
+ // ── Pre-flight check: server running + vault exists ──
36
+
37
+ function isConnectionError(err: unknown): boolean {
38
+ const msg = getErrorMessage(err).toLowerCase();
39
+ if (msg.includes('econnrefused') || msg.includes('fetch failed') || msg.includes('enoent')) return true;
40
+
41
+ const anyErr = err as { code?: unknown; errno?: unknown };
42
+ const code = typeof anyErr?.code === 'string' ? anyErr.code : undefined;
43
+ if (code === 'ECONNREFUSED' || code === 'ECONNRESET' || code === 'ENOTFOUND') return true;
44
+ const errno = typeof anyErr?.errno === 'number' ? anyErr.errno : undefined;
45
+ return errno === -61 || errno === -111; // macOS/WASI ECONNREFUSED codes
46
+ }
47
+
48
+ export async function checkServerAndVault(): Promise<void> {
49
+ try {
50
+ const status = await fetchSetupStatus();
51
+ if (!status.hasWallet) {
52
+ console.error('No vault found. Run `aura init` to set up.');
53
+ process.exit(1);
54
+ }
55
+ } catch (err: unknown) {
56
+ const msg = getErrorMessage(err);
57
+ if (isConnectionError(err)) {
58
+ console.error('Aura server not running. Run `aura start` first.');
59
+ } else {
60
+ console.error(`Cannot connect to Aura server: ${msg}`);
61
+ }
62
+ process.exit(1);
63
+ }
64
+ }
65
+
66
+ // ── Ephemeral RSA keypair ──
67
+
68
+ const keypair = generateEphemeralKeypair();
69
+
70
+ // ── Auth: socket or AURA_TOKEN env var ──
71
+
72
+ async function getAuthToken(): Promise<string> {
73
+ const envToken = process.env.AURA_TOKEN;
74
+ if (envToken) return envToken;
75
+ return bootstrapViaSocket('cli-env', keypair);
76
+ }
77
+
78
+ // ── .aura file parsing ──
79
+
80
+ function findAuraFile(): string | null {
81
+ let dir = process.cwd();
82
+ while (true) {
83
+ const candidate = path.join(dir, '.aura');
84
+ if (fs.existsSync(candidate)) return candidate;
85
+ const parent = path.dirname(dir);
86
+ if (parent === dir) return null;
87
+ dir = parent;
88
+ }
89
+ }
90
+
91
+ // parseAuraFile moved to ../lib/aura-parser.ts
92
+ export { parseAuraFile } from '../lib/aura-parser';
93
+
94
+ // ── Resolve mappings to env vars (delegates to shared module, audit finding #3) ──
95
+
96
+ async function resolveMappings(
97
+ mappings: AuraMapping[],
98
+ token: string,
99
+ readToken: string,
100
+ ): Promise<{ resolved: Map<string, string>; errors: string[]; missing: AuraMapping[] }> {
101
+ const base = serverUrl();
102
+ const decryptFn = (encrypted: string) => decryptWithPrivateKey(encrypted, keypair.privateKeyPem);
103
+ return sharedResolveMappings(mappings, base, token, readToken, decryptFn);
104
+ }
105
+
106
+ // ── Env value escaping for .env file ──
107
+
108
+ /**
109
+ * Escape a value for safe inclusion in a .env file.
110
+ * Handles newlines, backslashes, dollar signs, and quotes.
111
+ */
112
+ export function escapeEnvValue(value: string): string {
113
+ // Always double-quote and escape special chars
114
+ const escaped = value
115
+ .replace(/\\/g, '\\\\')
116
+ .replace(/\$/g, '\\$')
117
+ .replace(/"/g, '\\"')
118
+ .replace(/\n/g, '\\n')
119
+ .replace(/\r/g, '\\r');
120
+ return `"${escaped}"`;
121
+ }
122
+
123
+ // ── Subcommands ──
124
+
125
+ function suggestFromDotenvIfPresent(): void {
126
+ const envPath = path.join(process.cwd(), '.env');
127
+ if (fs.existsSync(envPath)) {
128
+ console.error('Tip: Found a .env file in this directory. Run `aura init --from-dotenv` to migrate it.');
129
+ }
130
+ }
131
+
132
+ export async function cmdRun(cmdArgs: string[]): Promise<void> {
133
+ if (cmdArgs.length === 0) {
134
+ console.error('Usage: npx aurawallet env -- <command> [args]');
135
+ process.exit(1);
136
+ }
137
+
138
+ await checkServerAndVault();
139
+
140
+ const auraFile = findAuraFile();
141
+ if (!auraFile) {
142
+ console.error('No .aura file found in current or parent directories.');
143
+ suggestFromDotenvIfPresent();
144
+ process.exit(1);
145
+ }
146
+
147
+ const mappings = parseAuraFile(auraFile);
148
+ if (mappings.length === 0) {
149
+ console.error('No mappings found in .aura file.');
150
+ process.exit(1);
151
+ }
152
+
153
+ const token = await getAuthToken();
154
+ const readToken = await createReadToken(serverUrl(), token, keypair, 'cli-env-reader');
155
+ let { resolved, errors, missing } = await resolveMappings(mappings, token, readToken);
156
+
157
+ // Interactive creation for missing credentials (TTY only)
158
+ if (missing.length > 0 && process.stdin.isTTY) {
159
+ try {
160
+ const vaultId = await getPrimaryVaultId(token);
161
+ const created = await interactiveCreateMissing(missing, token, vaultId);
162
+ for (const [key, value] of created) {
163
+ resolved.set(key, value);
164
+ }
165
+ errors = errors.filter(e => !missing.some(m => e.includes(m.envVar) && created.has(m.envVar)));
166
+ missing = missing.filter(m => !created.has(m.envVar));
167
+ } catch (err) {
168
+ console.error(` Interactive setup failed: ${getErrorMessage(err)}`);
169
+ }
170
+ }
171
+
172
+ if (errors.length > 0 && missing.length > 0) {
173
+ for (const err of errors) console.error(` ✗ ${err}`);
174
+ console.error(`\n${errors.length} of ${mappings.length} credentials failed to resolve.`);
175
+ process.exit(1);
176
+ }
177
+
178
+ console.error(`✓ Resolved ${resolved.size} credentials from vault`);
179
+
180
+ const env = { ...process.env };
181
+ for (const [key, value] of resolved) {
182
+ env[key] = value;
183
+ }
184
+
185
+ const child = spawn(cmdArgs[0], cmdArgs.slice(1), {
186
+ stdio: 'inherit',
187
+ env,
188
+ shell: false,
189
+ });
190
+
191
+ const forwardSignal = (sig: NodeJS.Signals) => child.kill(sig);
192
+ process.on('SIGINT', forwardSignal);
193
+ process.on('SIGTERM', forwardSignal);
194
+
195
+ child.on('exit', (code, signal) => {
196
+ process.off('SIGINT', forwardSignal);
197
+ process.off('SIGTERM', forwardSignal);
198
+ if (signal) {
199
+ process.kill(process.pid, signal);
200
+ } else {
201
+ process.exit(code ?? 1);
202
+ }
203
+ });
204
+ }
205
+
206
+ export async function cmdInject(): Promise<void> {
207
+ await checkServerAndVault();
208
+
209
+ const auraFile = findAuraFile();
210
+ if (!auraFile) {
211
+ console.error('No .aura file found in current or parent directories.');
212
+ suggestFromDotenvIfPresent();
213
+ process.exit(1);
214
+ }
215
+
216
+ const mappings = parseAuraFile(auraFile);
217
+ if (mappings.length === 0) {
218
+ console.error('No mappings found in .aura file.');
219
+ process.exit(1);
220
+ }
221
+
222
+ const token = await getAuthToken();
223
+ const readToken = await createReadToken(serverUrl(), token, keypair, 'cli-env-reader');
224
+ const { resolved, errors } = await resolveMappings(mappings, token, readToken);
225
+
226
+ if (errors.length > 0) {
227
+ for (const err of errors) console.error(` ✗ ${err}`);
228
+ console.error(`\n${errors.length} of ${mappings.length} credentials failed to resolve.`);
229
+ process.exit(1);
230
+ }
231
+
232
+ // Write .env in same directory as .aura
233
+ const envPath = path.join(path.dirname(auraFile), '.env');
234
+ const lines = ['# Generated by aurawallet env inject — DO NOT COMMIT'];
235
+ for (const [key, value] of resolved) {
236
+ lines.push(`${key}=${escapeEnvValue(value)}`);
237
+ }
238
+
239
+ // Write with restrictive permissions (0600 — owner read/write only)
240
+ const fd = fs.openSync(envPath, 'w', 0o600);
241
+ fs.writeSync(fd, lines.join('\n') + '\n');
242
+ fs.closeSync(fd);
243
+
244
+ console.log(`✓ Resolved ${resolved.size} credentials from vault`);
245
+ console.log(`✓ Wrote .env (${resolved.size} variables, mode 0600)`);
246
+
247
+ // Check .gitignore
248
+ const gitignorePath = path.join(path.dirname(auraFile), '.gitignore');
249
+ if (fs.existsSync(gitignorePath)) {
250
+ const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
251
+ if (!gitignore.includes('.env')) {
252
+ console.log('⚠ Make sure .env is in .gitignore!');
253
+ }
254
+ } else {
255
+ console.log('⚠ No .gitignore found — make sure .env is not committed!');
256
+ }
257
+ }
258
+
259
+ export async function cmdCheck(): Promise<void> {
260
+ await checkServerAndVault();
261
+
262
+ const auraFile = findAuraFile();
263
+ if (!auraFile) {
264
+ console.error('No .aura file found in current or parent directories.');
265
+ suggestFromDotenvIfPresent();
266
+ process.exit(1);
267
+ }
268
+
269
+ console.log(`.aura: ${auraFile}`);
270
+
271
+ const mappings = parseAuraFile(auraFile);
272
+ if (mappings.length === 0) {
273
+ console.log('No mappings found.');
274
+ return;
275
+ }
276
+
277
+ const token = await getAuthToken();
278
+ let allOk = true;
279
+
280
+ for (const mapping of mappings) {
281
+ const meta = await searchCredential(serverUrl(), token, mapping.credentialName);
282
+ if (meta) {
283
+ console.log(` ✓ ${mapping.envVar} → ${mapping.credentialName}/${mapping.field} (found)`);
284
+ } else {
285
+ console.log(` ✗ ${mapping.envVar} → ${mapping.credentialName}/${mapping.field} (not found)`);
286
+ allOk = false;
287
+ }
288
+ }
289
+
290
+ console.log('');
291
+ if (allOk) {
292
+ console.log(`All ${mappings.length} credentials resolved successfully.`);
293
+ } else {
294
+ console.log('Some credentials could not be found.');
295
+ process.exit(1);
296
+ }
297
+ }
298
+
299
+ function cmdList(): void {
300
+ const auraFile = findAuraFile();
301
+ if (!auraFile) {
302
+ console.error('No .aura file found in current or parent directories.');
303
+ suggestFromDotenvIfPresent();
304
+ process.exit(1);
305
+ }
306
+
307
+ console.log(`.aura: ${auraFile}`);
308
+ const mappings = parseAuraFile(auraFile);
309
+
310
+ if (mappings.length === 0) {
311
+ console.log('No mappings found.');
312
+ return;
313
+ }
314
+
315
+ for (const m of mappings) {
316
+ const ref = m.vault ? `@${m.vault}/${m.credentialName}/${m.field}` : `${m.credentialName}/${m.field}`;
317
+ console.log(` ${m.envVar} → ${ref}`);
318
+ }
319
+ }
320
+
321
+ // ── Init (from-dotenv migration) ──
322
+
323
+ async function cmdInit(): Promise<void> {
324
+ await checkServerAndVault();
325
+
326
+ const args = process.argv.slice(2);
327
+ const fromIdx = args.indexOf('--from');
328
+ const fromPath = fromIdx >= 0 && fromIdx + 1 < args.length ? args[fromIdx + 1] : undefined;
329
+ const dryRun = args.includes('--dry-run');
330
+ const noGroup = args.includes('--no-group');
331
+
332
+ const envPath = fromPath || path.join(process.cwd(), '.env');
333
+
334
+ const token = await getAuthToken();
335
+
336
+ await migrateDotenv({
337
+ token,
338
+ envPath,
339
+ noGroup,
340
+ dryRun,
341
+ });
342
+ }
343
+
344
+ // ── Interactive credential creation for missing entries ──
345
+
346
+ async function interactiveCreateMissing(
347
+ missingMappings: AuraMapping[],
348
+ token: string,
349
+ vaultId: string,
350
+ ): Promise<Map<string, string>> {
351
+ const resolved = new Map<string, string>();
352
+
353
+ const byCredential = new Map<string, AuraMapping[]>();
354
+ for (const m of missingMappings) {
355
+ const list = byCredential.get(m.credentialName) || [];
356
+ list.push(m);
357
+ byCredential.set(m.credentialName, list);
358
+ }
359
+
360
+ console.log(`\n ${missingMappings.length} credential(s) not found. Let's create them:\n`);
361
+
362
+ for (const [credName, mappings] of byCredential) {
363
+ const fields: Array<{ key: string; value: string }> = [];
364
+
365
+ for (const m of mappings) {
366
+ const value = await promptInput(` Enter value for ${m.envVar} (→ ${credName}/${m.field})`);
367
+ if (!value) {
368
+ console.log(` Skipped ${m.envVar}`);
369
+ continue;
370
+ }
371
+ fields.push({ key: m.field, value });
372
+ resolved.set(m.envVar, value);
373
+ }
374
+
375
+ if (fields.length > 0) {
376
+ const result = await createCredentialViaApi({ token, vaultId, name: credName, fields });
377
+ if (result.success) {
378
+ console.log(` ✓ Created credential: ${credName}`);
379
+ } else {
380
+ console.error(` ✗ Failed to create ${credName}: ${result.error}`);
381
+ for (const f of fields) {
382
+ const mapping = mappings.find(m => m.field === f.key);
383
+ if (mapping) resolved.delete(mapping.envVar);
384
+ }
385
+ }
386
+ }
387
+ }
388
+
389
+ return resolved;
390
+ }
391
+
392
+ // ── Help ──
393
+
394
+ function showHelp(): void {
395
+ console.log(`
396
+ aurawallet env — Load env vars from vault
397
+
398
+ Usage:
399
+ npx aurawallet env -- <cmd> [args] Run command with vault-injected env vars
400
+ npx aurawallet env inject Write .env file from .aura mappings
401
+ npx aurawallet env check Verify all mapped credentials exist
402
+ npx aurawallet env list Show mappings without values
403
+ npx aurawallet env init Migrate .env to vault + .aura
404
+ [--from <path>] [--dry-run] [--no-group]
405
+
406
+ Auth: Uses Unix socket by default. Set AURA_TOKEN env var for headless/CI.
407
+
408
+ The .aura file maps env var names to vault credential references:
409
+
410
+ # .aura
411
+ DATABASE_URL=database-prod/url
412
+ STRIPE_KEY=stripe/secret_key
413
+ AGENT_TOKEN=@agent/openai/api_key # from 'agent' vault
414
+ `);
415
+ }
416
+
417
+ // ── Main ──
418
+
419
+ async function main(): Promise<void> {
420
+ const args = process.argv.slice(2);
421
+
422
+ const dashIdx = args.indexOf('--');
423
+ if (dashIdx !== -1) {
424
+ const cmdArgs = args.slice(dashIdx + 1);
425
+ return cmdRun(cmdArgs);
426
+ }
427
+
428
+ const subcommand = args[0];
429
+
430
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
431
+ showHelp();
432
+ process.exit(0);
433
+ }
434
+
435
+ switch (subcommand) {
436
+ case 'init':
437
+ return cmdInit();
438
+ case 'inject':
439
+ return cmdInject();
440
+ case 'check':
441
+ return cmdCheck();
442
+ case 'list':
443
+ return cmdList();
444
+ default:
445
+ console.error(`Unknown subcommand: ${subcommand}`);
446
+ showHelp();
447
+ process.exit(1);
448
+ }
449
+ }
450
+
451
+ if (require.main === module) {
452
+ main().catch((err) => {
453
+ console.error(`Error: ${getErrorMessage(err)}`);
454
+ process.exit(1);
455
+ });
456
+ }