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,64 @@
1
+ <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <pattern id="dots-m56" x="0" y="0" width="3" height="3" patternUnits="userSpaceOnUse">
4
+ <circle cx="1.5" cy="1.5" r="0.5" fill="#000000" fill-opacity="0.03"/>
5
+ </pattern>
6
+
7
+ <!-- Angular slash clip — carves visible channel through the filled wallet -->
8
+ <clipPath id="slash-cut">
9
+ <polygon points="0,0 56,0 56,22 38,28 56,34 56,56 0,56 0,34 18,28 0,22"/>
10
+ </clipPath>
11
+
12
+ <!-- Fragment clips for displaced echoes -->
13
+ <clipPath id="frag-tl">
14
+ <polygon points="0,0 30,0 18,28 0,22"/>
15
+ </clipPath>
16
+ <clipPath id="frag-br">
17
+ <polygon points="38,28 56,34 56,56 26,56"/>
18
+ </clipPath>
19
+
20
+ <clipPath id="bounds">
21
+ <rect width="56" height="56"/>
22
+ </clipPath>
23
+ </defs>
24
+
25
+ <!-- Background -->
26
+ <rect width="56" height="56" fill="#ffffff"/>
27
+ <rect width="56" height="56" fill="url(#dots-m56)"/>
28
+
29
+ <g clip-path="url(#bounds)">
30
+
31
+ <!-- WALLET — filled silhouette, slashed by clip-path -->
32
+ <g clip-path="url(#slash-cut)">
33
+ <!-- Wallet body -->
34
+ <rect x="11" y="14" width="34" height="30" rx="1.5" fill="#0a0a0a"/>
35
+ <!-- Flap -->
36
+ <path d="M 13,14 L 13,11 Q 13,9 15,9 L 41,9 Q 43,9 43,11 L 43,14" fill="#0a0a0a"/>
37
+
38
+ <!-- Interior lines scored into the fill -->
39
+ <!-- Fold -->
40
+ <line x1="11" y1="29" x2="45" y2="29" stroke="#ffffff" stroke-width="1"/>
41
+ <!-- Card edge -->
42
+ <line x1="15" y1="18" x2="28" y2="18" stroke="#ffffff" stroke-width="0.8"/>
43
+ </g>
44
+
45
+ <!-- Displaced echo — top-left -->
46
+ <g clip-path="url(#frag-tl)" opacity="0.15">
47
+ <rect x="9.5" y="12.5" width="34" height="30" rx="1.5" fill="#0a0a0a"/>
48
+ <path d="M 11.5,12.5 L 11.5,9.5 Q 11.5,7.5 13.5,7.5 L 39.5,7.5 Q 41.5,7.5 41.5,9.5 L 41.5,12.5" fill="#0a0a0a"/>
49
+ </g>
50
+
51
+ <!-- Displaced echo — bottom-right -->
52
+ <g clip-path="url(#frag-br)" opacity="0.15">
53
+ <rect x="12.5" y="15.5" width="34" height="30" rx="1.5" fill="#0a0a0a"/>
54
+ </g>
55
+
56
+ </g>
57
+
58
+ <!-- Main Border -->
59
+ <rect x="0.5" y="0.5" width="55" height="55" stroke="#d1d5db" stroke-width="1" fill="none"/>
60
+
61
+ <!-- Corner Marks -->
62
+ <path d="M 8 4.5 L 4.5 4.5 L 4.5 8" stroke="#9ca3af" stroke-width="1" fill="none" stroke-linecap="square"/>
63
+ <path d="M 48 51.5 L 51.5 51.5 L 51.5 48" stroke="#9ca3af" stroke-width="1" fill="none" stroke-linecap="square"/>
64
+ </svg>
Binary file
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Add a app to the AuraWallet dashboard via WebSocket.
4
+ *
5
+ * Usage:
6
+ * node scripts/add-app.js <appType> [options]
7
+ *
8
+ * Examples:
9
+ * # Inline dynamic app
10
+ * node scripts/add-app.js dynamic --code "function Hi() { return <div>Hello</div>; }"
11
+ *
12
+ * # File-based dynamic app (agents: use tmp/, then rm after)
13
+ * node scripts/add-app.js dynamic --file tmp/app.jsx --id "my-app"
14
+ *
15
+ * # Iframe app
16
+ * node scripts/add-app.js iframe --url "https://example.com" --title "My Chart"
17
+ *
18
+ * # Built-in apps
19
+ * node scripts/add-app.js wallets
20
+ * node scripts/add-app.js logs --x 400 --y 100
21
+ *
22
+ * # Custom app (from src/components/apps/custom/)
23
+ * node scripts/add-app.js custom:ExampleApp --message "Hello"
24
+ *
25
+ * # Position and size
26
+ * node scripts/add-app.js iframe --url "https://example.com" --x 100 --y 200 --width 500 --height 400
27
+ *
28
+ * # Target a specific workspace
29
+ * node scripts/add-app.js logs --workspace "home"
30
+ */
31
+
32
+ const WebSocket = require('ws');
33
+ const fs = require('fs');
34
+ const path = require('path');
35
+
36
+ const WS_BASE_URL = process.env.WORKSPACE_WS_URL || 'ws://localhost:4748';
37
+ const AUTH_TOKEN = process.env.AURA_TOKEN;
38
+
39
+ // Build WebSocket URL with optional token
40
+ function getWsUrl() {
41
+ if (AUTH_TOKEN) {
42
+ return `${WS_BASE_URL}?token=${encodeURIComponent(AUTH_TOKEN)}`;
43
+ }
44
+ return WS_BASE_URL;
45
+ }
46
+
47
+ // Parse command line arguments
48
+ function parseArgs(args) {
49
+ const result = { _: [] };
50
+ let i = 0;
51
+
52
+ while (i < args.length) {
53
+ const arg = args[i];
54
+
55
+ if (arg.startsWith('--')) {
56
+ const key = arg.slice(2);
57
+ const next = args[i + 1];
58
+
59
+ if (next && !next.startsWith('--')) {
60
+ // Try to parse as number
61
+ const num = parseFloat(next);
62
+ result[key] = isNaN(num) ? next : num;
63
+ i += 2;
64
+ } else {
65
+ result[key] = true;
66
+ i += 1;
67
+ }
68
+ } else {
69
+ result._.push(arg);
70
+ i += 1;
71
+ }
72
+ }
73
+
74
+ return result;
75
+ }
76
+
77
+ function printUsage() {
78
+ console.log(`
79
+ Usage: node scripts/add-app.js <appType> [options]
80
+
81
+ Authentication:
82
+ Set AURA_TOKEN env var with a valid token that has workspace:modify permission.
83
+ Example: export AURA_TOKEN="your-agent-token"
84
+
85
+ App Types:
86
+ Built-in (singleton):
87
+ wallets, logs, send, agentKeys, status, launch
88
+
89
+ Multi-instance:
90
+ iframe --url <url> [--title <title>]
91
+ dynamic --code <code> | --file <path>
92
+ custom:* --<key> <value> (passed as config)
93
+
94
+ Options:
95
+ --id <id> Custom app ID (for multi-instance apps)
96
+ --workspace <id> Target workspace ID (default: active workspace)
97
+ --x <number> X position (default: 20)
98
+ --y <number> Y position (default: 20)
99
+ --width <number> App width
100
+ --height <number> App height
101
+
102
+ Examples:
103
+ # Set token first
104
+ export AURA_TOKEN="your-agent-token"
105
+
106
+ # Inline dynamic app
107
+ node scripts/add-app.js dynamic --code "function Hi() { return <div>Hello</div>; }"
108
+
109
+ # File-based dynamic app (use tmp/, then rm after)
110
+ node scripts/add-app.js dynamic --file tmp/app.jsx --id "my-app"
111
+
112
+ # Iframe
113
+ node scripts/add-app.js iframe --url "https://dexscreener.com/base/0x123"
114
+
115
+ # Built-in apps
116
+ node scripts/add-app.js wallets --x 400 --y 100
117
+
118
+ # Custom app (from src/components/apps/custom/)
119
+ node scripts/add-app.js custom:ExampleApp --message "Hello"
120
+ `);
121
+ }
122
+
123
+ async function main() {
124
+ const args = parseArgs(process.argv.slice(2));
125
+ const appType = args._[0];
126
+
127
+ if (!appType || args.help) {
128
+ printUsage();
129
+ process.exit(args.help ? 0 : 1);
130
+ }
131
+
132
+ // Build config from remaining args
133
+ const config = {};
134
+ const reserved = ['_', 'id', 'workspace', 'x', 'y', 'width', 'height', 'file', 'code', 'url', 'title'];
135
+
136
+ // Handle specific app types
137
+ if (appType === 'iframe') {
138
+ if (!args.url) {
139
+ console.error('Error: iframe app requires --url');
140
+ process.exit(1);
141
+ }
142
+ config.url = args.url;
143
+ if (args.title) config.title = args.title;
144
+ } else if (appType === 'dynamic') {
145
+ if (args.file) {
146
+ const filePath = path.resolve(args.file);
147
+ if (!fs.existsSync(filePath)) {
148
+ console.error(`Error: File not found: ${filePath}`);
149
+ process.exit(1);
150
+ }
151
+ config.code = fs.readFileSync(filePath, 'utf-8');
152
+ } else if (args.code) {
153
+ config.code = args.code;
154
+ } else {
155
+ console.error('Error: dynamic app requires --code or --file');
156
+ process.exit(1);
157
+ }
158
+ } else {
159
+ // Pass through any non-reserved args as config
160
+ for (const [key, value] of Object.entries(args)) {
161
+ if (!reserved.includes(key)) {
162
+ config[key] = value;
163
+ }
164
+ }
165
+ }
166
+
167
+ // Connect to WebSocket with optional authentication
168
+ const wsUrl = getWsUrl();
169
+ const ws = new WebSocket(wsUrl);
170
+
171
+ ws.on('error', (err) => {
172
+ console.error('WebSocket error:', err.message);
173
+ console.log('Make sure the Next.js app is running on port 4748');
174
+ if (!AUTH_TOKEN) {
175
+ console.log('Tip: Set AURA_TOKEN env var for authenticated mutations');
176
+ }
177
+ process.exit(1);
178
+ });
179
+
180
+ ws.on('open', () => {
181
+ // Request current workspace state
182
+ ws.send(JSON.stringify({
183
+ type: 'workspace:state:request',
184
+ timestamp: Date.now(),
185
+ source: 'agent',
186
+ data: { requestId: 'add-app-script' }
187
+ }));
188
+ });
189
+
190
+ ws.on('message', (rawData) => {
191
+ const msg = JSON.parse(rawData.toString());
192
+
193
+ // Handle permission errors
194
+ if (msg.type === 'error') {
195
+ console.error('Error:', msg.error);
196
+ if (msg.error.includes('Permission denied')) {
197
+ console.log('Tip: Set AURA_TOKEN env var with a token that has workspace:modify permission');
198
+ }
199
+ ws.close();
200
+ process.exit(1);
201
+ }
202
+
203
+ if (msg.type === 'workspace:state:response') {
204
+ const workspaceId = args.workspace || msg.data.activeWorkspaceId;
205
+
206
+ const appData = {
207
+ workspaceId,
208
+ appType,
209
+ x: args.x || 20,
210
+ y: args.y || 20
211
+ };
212
+
213
+ if (args.id) appData.id = args.id;
214
+ if (args.width) appData.width = args.width;
215
+ if (args.height) appData.height = args.height;
216
+ if (Object.keys(config).length > 0) appData.config = config;
217
+
218
+ // Wait for token validation to complete (race condition workaround)
219
+ // The server validates tokens asynchronously, so we need a brief delay
220
+ setTimeout(() => {
221
+ ws.send(JSON.stringify({
222
+ type: 'app:added',
223
+ timestamp: Date.now(),
224
+ source: 'agent',
225
+ data: appData
226
+ }));
227
+
228
+ // Wait for potential error response, then assume success
229
+ setTimeout(() => {
230
+ console.log('App added:', appType);
231
+ if (args.id) console.log(' ID:', args.id);
232
+ console.log(' Workspace:', workspaceId);
233
+ console.log(' Position:', `(${appData.x}, ${appData.y})`);
234
+ if (Object.keys(config).length > 0) {
235
+ console.log(' Config:', JSON.stringify(config, null, 2).split('\n').map((l, i) => i === 0 ? l : ' ' + l).join('\n'));
236
+ }
237
+ ws.close();
238
+ process.exit(0);
239
+ }, 300);
240
+ }, 150);
241
+ }
242
+ });
243
+ }
244
+
245
+ main();
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+
3
+ # Initialize AuraWallet for first-time setup
4
+
5
+ set -e
6
+
7
+ echo "╔════════════════════════════════════════════╗"
8
+ echo "║ AURA WALLET - INIT ║"
9
+ echo "╚════════════════════════════════════════════╝"
10
+ echo ""
11
+
12
+ # Get script directory and project root
13
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
15
+
16
+ cd "$PROJECT_ROOT"
17
+
18
+ # Data directory lives outside the repo for safety
19
+ DATA_DIR="$HOME/.aurawallet"
20
+
21
+ # 1. Install dependencies
22
+ echo "→ Installing dependencies..."
23
+ npm install
24
+
25
+ # 2. Create data directory
26
+ echo ""
27
+ echo "→ Creating data directory at $DATA_DIR..."
28
+ mkdir -p "$DATA_DIR" "$DATA_DIR/hot" "$DATA_DIR/pending"
29
+
30
+ # 3. Run Prisma migrations against the data dir
31
+ echo ""
32
+ echo "→ Running database migrations..."
33
+ DATABASE_URL="file:$DATA_DIR/aurawallet.db" npx prisma migrate dev --name init 2>/dev/null || \
34
+ DATABASE_URL="file:$DATA_DIR/aurawallet.db" npx prisma migrate deploy
35
+
36
+ # 4. Generate Prisma client
37
+ echo ""
38
+ echo "→ Generating Prisma client..."
39
+ npx prisma generate
40
+
41
+ # 5. Create tmp folder for agent apps
42
+ echo ""
43
+ echo "→ Creating tmp/ folder..."
44
+ mkdir -p tmp
45
+
46
+ # 6. Create backups folder for db backups
47
+ echo ""
48
+ echo "→ Creating backups/ folder..."
49
+ mkdir -p backups
50
+
51
+ echo ""
52
+ echo "╔════════════════════════════════════════════╗"
53
+ echo "║ INIT COMPLETE ║"
54
+ echo "╠════════════════════════════════════════════╣"
55
+ echo "║ Data: $DATA_DIR"
56
+ echo "║ Run ./start.sh to start the servers ║"
57
+ echo "╚════════════════════════════════════════════╝"
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ import { ensureDataDir } from '../server/lib/config';
4
+ import { hasColdWallet, isUnlocked, unlock } from '../server/lib/cold';
5
+ import { migrateApiKeysFromDatabase } from '../server/lib/apikey-migration';
6
+ import { prisma } from '../server/lib/db';
7
+
8
+ async function main() {
9
+ ensureDataDir();
10
+
11
+ if (hasColdWallet() && !isUnlocked()) {
12
+ const password = process.env.VAULT_PASSWORD;
13
+ if (!password) {
14
+ throw new Error('Vault is locked. Set VAULT_PASSWORD to run API key migration.');
15
+ }
16
+ if (!unlock(password)) {
17
+ throw new Error('Failed to unlock vault using VAULT_PASSWORD.');
18
+ }
19
+ }
20
+
21
+ const result = await migrateApiKeysFromDatabase();
22
+ console.log('[apikey-migration] migrated:', result.migrated, 'skipped:', result.skipped);
23
+ if (result.reason) {
24
+ console.log('[apikey-migration] reason:', result.reason);
25
+ }
26
+ }
27
+
28
+ main()
29
+ .catch((error) => {
30
+ console.error('[apikey-migration] failed:', error instanceof Error ? error.message : String(error));
31
+ process.exitCode = 1;
32
+ })
33
+ .finally(async () => {
34
+ await prisma.$disconnect();
35
+ });
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -u
4
+
5
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+ cd "$ROOT_DIR"
7
+ CLI_CMD="AURA_FORCE_NODE_TSX=1 node ./bin/aurawallet.js"
8
+
9
+ RUN_ID="$(date -u +"%Y-%m-%dT%H-%M-%SZ")"
10
+ ARTIFACT_ROOT="$ROOT_DIR/logs/sandbox-agent-flow/$RUN_ID"
11
+ COMMANDS_DIR="$ARTIFACT_ROOT/commands"
12
+ SUMMARY_PATH="$ARTIFACT_ROOT/summary.txt"
13
+ JSON_PATH="$ARTIFACT_ROOT/report.json"
14
+
15
+ mkdir -p "$COMMANDS_DIR"
16
+
17
+ STEP_NAMES=()
18
+ STEP_RESULTS=()
19
+ STEP_EXIT_CODES=()
20
+ STEP_TIMEOUTS=()
21
+ STEP_DURATIONS=()
22
+ STEP_LOGS=()
23
+
24
+ sanitize_name() {
25
+ echo "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//'
26
+ }
27
+
28
+ run_step() {
29
+ local name="$1"
30
+ local timeout_s="$2"
31
+ local command="$3"
32
+ local non_blocking="${4:-false}"
33
+
34
+ local step_index=$(( ${#STEP_NAMES[@]} + 1 ))
35
+ local slug
36
+ slug="$(sanitize_name "$name")"
37
+ local logfile="$COMMANDS_DIR/$(printf "%03d" "$step_index")-${slug}.log"
38
+ local start_ts
39
+ start_ts="$(date +%s)"
40
+ local result="PASS"
41
+ local exit_code=0
42
+
43
+ {
44
+ echo "# step: $name"
45
+ echo "# timeout_seconds: $timeout_s"
46
+ echo "# command: $command"
47
+ echo
48
+ } > "$logfile"
49
+
50
+ bash -lc "$command" >> "$logfile" 2>&1 &
51
+ local pid=$!
52
+
53
+ while kill -0 "$pid" 2>/dev/null; do
54
+ local now_ts
55
+ now_ts="$(date +%s)"
56
+ if (( now_ts - start_ts >= timeout_s )); then
57
+ kill -TERM "$pid" 2>/dev/null || true
58
+ sleep 1
59
+ kill -KILL "$pid" 2>/dev/null || true
60
+ wait "$pid" 2>/dev/null || true
61
+ result="TIMEOUT"
62
+ exit_code=124
63
+ break
64
+ fi
65
+ sleep 1
66
+ done
67
+
68
+ if [[ "$result" != "TIMEOUT" ]]; then
69
+ wait "$pid"
70
+ exit_code=$?
71
+ if [[ "$exit_code" -ne 0 ]]; then
72
+ if [[ "$non_blocking" == "true" ]]; then
73
+ result="WARN"
74
+ else
75
+ result="FAIL"
76
+ fi
77
+ fi
78
+ fi
79
+
80
+ local end_ts
81
+ end_ts="$(date +%s)"
82
+ local duration_s=$(( end_ts - start_ts ))
83
+
84
+ STEP_NAMES+=("$name")
85
+ STEP_RESULTS+=("$result")
86
+ STEP_EXIT_CODES+=("$exit_code")
87
+ STEP_TIMEOUTS+=("$timeout_s")
88
+ STEP_DURATIONS+=("$duration_s")
89
+ STEP_LOGS+=("$logfile")
90
+
91
+ printf "[%s] %s (exit=%s, duration=%ss)\n" "$result" "$name" "$exit_code" "$duration_s"
92
+ }
93
+
94
+ echo "Sandbox Agent Flow"
95
+ echo "Run ID: $RUN_ID"
96
+ echo "Artifacts: $ARTIFACT_ROOT"
97
+ echo
98
+ echo "Human prerequisite:"
99
+ echo "1) Run npm run sandbox:agent in another terminal"
100
+ echo "2) Complete dashboard onboarding/unlock at http://localhost:5747"
101
+ echo
102
+
103
+ run_step "preflight-health" 20 "curl -sf http://127.0.0.1:5242/health"
104
+ run_step "preflight-setup" 20 "curl -sf http://127.0.0.1:5242/setup"
105
+
106
+ run_step "cli-help" 30 "$CLI_CMD --help"
107
+ run_step "cli-doctor-json" 45 "$CLI_CMD doctor --json"
108
+ run_step "cli-doctor-strict-advisory" 45 "$CLI_CMD doctor --strict" "true"
109
+ run_step "cli-env-help" 30 "$CLI_CMD env --help"
110
+ run_step "cli-shell-hook-help" 30 "$CLI_CMD shell-hook --help"
111
+ run_step "cli-vault-list" 45 "$CLI_CMD vault list"
112
+ run_step "cli-restore-list" 45 "$CLI_CMD restore --list"
113
+
114
+ run_step "security-logs-unauth" 20 "curl -i http://127.0.0.1:5242/logs"
115
+ run_step "security-import-unauth" 20 "curl -i -X POST http://127.0.0.1:5242/credentials/import"
116
+
117
+ run_step "app-list-before" 30 "$CLI_CMD app list"
118
+ run_step "app-install-local" 60 "$CLI_CMD app install ./apps/agent-chat --name sandbox-agent-chat --force"
119
+ run_step "app-remove-local" 60 "$CLI_CMD app remove sandbox-agent-chat --yes"
120
+
121
+ run_step "mcp-tests" 120 "npx vitest run --config server/vitest.config.ts server/tests/mcp/server.test.ts server/tests/mcp/tools.test.ts"
122
+ run_step "mcp-install-smoke" 45 "TMP_HOME=\$(mktemp -d); mkdir -p \"\$TMP_HOME/.cursor\"; HOME=\"\$TMP_HOME\" $CLI_CMD mcp --install; test -f \"\$TMP_HOME/.cursor/mcp.json\"; grep -n '\"aurawallet\"' \"\$TMP_HOME/.cursor/mcp.json\""
123
+ run_step "mcp-runtime-smoke" 15 "node -e 'const {spawn}=require(\"child_process\");const p=spawn(\"node\",[\"./bin/aurawallet.js\",\"mcp\"],{stdio:[\"ignore\",\"pipe\",\"pipe\"]});let done=false;const t=setTimeout(()=>{if(!done){done=true;p.kill(\"SIGTERM\");process.stdout.write(\"mcp-started\\n\");process.exit(0)}},1500);p.on(\"exit\",(code)=>{if(!done){done=true;clearTimeout(t);process.stderr.write(\"mcp-exited-early:\"+code+\"\\n\");process.exit(1);}});'"
124
+
125
+ run_step "package-dry-run" 90 "HUSKY=0 npm pack --dry-run --json --ignore-scripts --cache /tmp/npm-cache"
126
+ run_step "package-skill-mcp-smoke" 120 "TMP_PKG=\$(mktemp -d); HUSKY=0 npm pack --pack-destination \"\$TMP_PKG\" --ignore-scripts --cache /tmp/npm-cache; tar -tzf \"\$TMP_PKG\"/aurawallet-*.tgz | grep -E 'skills/aurawallet/SKILL.md|server/cli/commands/mcp.ts|server/cli/commands/app.ts|bin/aurawallet.js'"
127
+
128
+ pass_count=0
129
+ warn_count=0
130
+ fail_count=0
131
+ timeout_count=0
132
+
133
+ {
134
+ echo "Sandbox Agent Flow Summary"
135
+ echo "Run ID: $RUN_ID"
136
+ echo "Artifact Root: $ARTIFACT_ROOT"
137
+ echo
138
+ printf "%-3s %-28s %-8s %-6s %-8s %s\n" "No" "Step" "Result" "Code" "Duration" "Log"
139
+ printf "%-3s %-28s %-8s %-6s %-8s %s\n" "---" "----------------------------" "--------" "------" "--------" "---"
140
+ } > "$SUMMARY_PATH"
141
+
142
+ for i in "${!STEP_NAMES[@]}"; do
143
+ step_no=$(( i + 1 ))
144
+ name="${STEP_NAMES[$i]}"
145
+ result="${STEP_RESULTS[$i]}"
146
+ code="${STEP_EXIT_CODES[$i]}"
147
+ duration="${STEP_DURATIONS[$i]}"
148
+ log="${STEP_LOGS[$i]}"
149
+
150
+ if [[ "$result" == "PASS" ]]; then
151
+ pass_count=$(( pass_count + 1 ))
152
+ elif [[ "$result" == "WARN" ]]; then
153
+ warn_count=$(( warn_count + 1 ))
154
+ elif [[ "$result" == "TIMEOUT" ]]; then
155
+ timeout_count=$(( timeout_count + 1 ))
156
+ fail_count=$(( fail_count + 1 ))
157
+ else
158
+ fail_count=$(( fail_count + 1 ))
159
+ fi
160
+
161
+ printf "%-3s %-28s %-8s %-6s %-8s %s\n" "$step_no" "$name" "$result" "$code" "$duration" "$log" >> "$SUMMARY_PATH"
162
+ done
163
+
164
+ node - "$RUN_ID" "$ARTIFACT_ROOT" "$JSON_PATH" \
165
+ "$pass_count" "$warn_count" "$fail_count" "$timeout_count" \
166
+ "$(printf "%s\n" "${STEP_NAMES[@]}")" \
167
+ "$(printf "%s\n" "${STEP_RESULTS[@]}")" \
168
+ "$(printf "%s\n" "${STEP_EXIT_CODES[@]}")" \
169
+ "$(printf "%s\n" "${STEP_DURATIONS[@]}")" \
170
+ "$(printf "%s\n" "${STEP_LOGS[@]}")" <<'NODE'
171
+ const fs = require('fs');
172
+ const [
173
+ ,
174
+ ,
175
+ runId,
176
+ artifactRoot,
177
+ jsonPath,
178
+ passCount,
179
+ warnCount,
180
+ failCount,
181
+ timeoutCount,
182
+ namesRaw,
183
+ resultsRaw,
184
+ codesRaw,
185
+ durationsRaw,
186
+ logsRaw,
187
+ ] = process.argv;
188
+
189
+ function splitLines(value) {
190
+ return value.split('\n').filter(Boolean);
191
+ }
192
+
193
+ const names = splitLines(namesRaw);
194
+ const results = splitLines(resultsRaw);
195
+ const codes = splitLines(codesRaw);
196
+ const durations = splitLines(durationsRaw);
197
+ const logs = splitLines(logsRaw);
198
+
199
+ const steps = names.map((name, i) => ({
200
+ name,
201
+ result: results[i] || 'UNKNOWN',
202
+ exitCode: Number(codes[i] || 1),
203
+ durationSeconds: Number(durations[i] || 0),
204
+ logPath: logs[i] || '',
205
+ }));
206
+
207
+ const report = {
208
+ schemaVersion: 'sandbox-agent-flow/v1',
209
+ runId,
210
+ artifactRoot,
211
+ summary: {
212
+ passCount: Number(passCount),
213
+ warnCount: Number(warnCount),
214
+ failCount: Number(failCount),
215
+ timeoutCount: Number(timeoutCount),
216
+ },
217
+ steps,
218
+ };
219
+
220
+ fs.writeFileSync(jsonPath, JSON.stringify(report, null, 2) + '\n', 'utf8');
221
+ NODE
222
+
223
+ {
224
+ echo
225
+ echo "Totals: pass=$pass_count warn=$warn_count fail=$fail_count timeout=$timeout_count"
226
+ echo "JSON report: $JSON_PATH"
227
+ } >> "$SUMMARY_PATH"
228
+
229
+ cat "$SUMMARY_PATH"
230
+
231
+ if [[ "$fail_count" -gt 0 ]]; then
232
+ exit 1
233
+ fi
234
+
235
+ exit 0