auramaxx 0.0.1

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 (418) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +77 -0
  3. package/apps/desktop-electron/main.js +428 -0
  4. package/bin/auramaxx.js +1063 -0
  5. package/docs/ADAPTERS.md +466 -0
  6. package/docs/AGENT_SETUP.md +159 -0
  7. package/docs/API.md +127 -0
  8. package/docs/APPS.md +199 -0
  9. package/docs/ARCHITECTURE.md +235 -0
  10. package/docs/AUTH.md +318 -0
  11. package/docs/BEST-PRACTICES.md +82 -0
  12. package/docs/CLI.md +141 -0
  13. package/docs/DESKTOP_ELECTRON.md +26 -0
  14. package/docs/DEVELOPING-APPS.md +453 -0
  15. package/docs/MCP.md +122 -0
  16. package/docs/PACKAGING_POLICY.md +19 -0
  17. package/docs/PERMISSION.md +137 -0
  18. package/docs/PROTOCOL.md +142 -0
  19. package/docs/README.md +50 -0
  20. package/docs/SKILLS.md +132 -0
  21. package/docs/TROUBLESHOOTING.md +376 -0
  22. package/docs/WORKSPACE.md +673 -0
  23. package/docs/agent-auth.md +14 -0
  24. package/docs/api/authentication.md +79 -0
  25. package/docs/api/secrets/api-keys.md +28 -0
  26. package/docs/api/secrets/credentials.md +80 -0
  27. package/docs/api/secrets/sharing.md +48 -0
  28. package/docs/api/system.md +41 -0
  29. package/docs/api/wallets/apps-strategies.md +66 -0
  30. package/docs/api/wallets/core.md +46 -0
  31. package/docs/api/wallets/data-portfolio.md +42 -0
  32. package/docs/aura-file.md +48 -0
  33. package/docs/core-concepts/FEATURES.md +114 -0
  34. package/docs/credentials.md +120 -0
  35. package/docs/external/HOW_TO_AURAMAXX/GETTING_SECRETS.md +33 -0
  36. package/docs/external/HOW_TO_AURAMAXX/README.md +45 -0
  37. package/docs/external/getting-started.md +10 -0
  38. package/docs/external/overview.md +19 -0
  39. package/docs/external/persona-paths.md +7 -0
  40. package/docs/external/share-secret.md +76 -0
  41. package/docs/external/why-aura.md +7 -0
  42. package/docs/security.md +227 -0
  43. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  44. package/docs/wallet/AI.md +508 -0
  45. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  46. package/docs/wallet/README.md +47 -0
  47. package/docs/wallet/STRATEGY.md +89 -0
  48. package/next.config.ts +28 -0
  49. package/package.json +167 -0
  50. package/postcss.config.mjs +8 -0
  51. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  52. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  53. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  54. package/prisma/migrations/20260222090000_update_admin_ttl_default/migration.sql +10 -0
  55. package/prisma/migrations/migration_lock.toml +3 -0
  56. package/prisma/schema.prisma +447 -0
  57. package/public/logo.webp +0 -0
  58. package/scripts/add-app.js +245 -0
  59. package/server/abi/SwapHelper.json +438 -0
  60. package/server/cli/approval.ts +447 -0
  61. package/server/cli/commands/actions.ts +474 -0
  62. package/server/cli/commands/api.ts +220 -0
  63. package/server/cli/commands/apikey.ts +277 -0
  64. package/server/cli/commands/app.ts +204 -0
  65. package/server/cli/commands/auth.ts +464 -0
  66. package/server/cli/commands/cron.ts +24 -0
  67. package/server/cli/commands/diary.ts +274 -0
  68. package/server/cli/commands/doctor.ts +1247 -0
  69. package/server/cli/commands/env.ts +476 -0
  70. package/server/cli/commands/experimental.ts +69 -0
  71. package/server/cli/commands/init.ts +798 -0
  72. package/server/cli/commands/lock.ts +157 -0
  73. package/server/cli/commands/mcp.ts +285 -0
  74. package/server/cli/commands/quickhack.ts +86 -0
  75. package/server/cli/commands/release-check.ts +231 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/service.ts +320 -0
  78. package/server/cli/commands/shell-hook.ts +512 -0
  79. package/server/cli/commands/skill.ts +216 -0
  80. package/server/cli/commands/start.ts +139 -0
  81. package/server/cli/commands/status.ts +59 -0
  82. package/server/cli/commands/stop.ts +36 -0
  83. package/server/cli/commands/token.ts +180 -0
  84. package/server/cli/commands/unlock.ts +50 -0
  85. package/server/cli/commands/vault.ts +1323 -0
  86. package/server/cli/commands/wallet.ts +209 -0
  87. package/server/cli/index.ts +280 -0
  88. package/server/cli/lib/approval-poll.ts +94 -0
  89. package/server/cli/lib/aura-parser.ts +64 -0
  90. package/server/cli/lib/credential-create.ts +74 -0
  91. package/server/cli/lib/credential-resolve.ts +280 -0
  92. package/server/cli/lib/dotenv-migrate.ts +116 -0
  93. package/server/cli/lib/dotenv-parser.ts +146 -0
  94. package/server/cli/lib/escalation.ts +57 -0
  95. package/server/cli/lib/http.ts +91 -0
  96. package/server/cli/lib/init-steps.ts +76 -0
  97. package/server/cli/lib/local-agent-trust.ts +45 -0
  98. package/server/cli/lib/lock-unlock-helper.ts +71 -0
  99. package/server/cli/lib/process.ts +162 -0
  100. package/server/cli/lib/prompt.ts +294 -0
  101. package/server/cli/lib/theme.ts +240 -0
  102. package/server/cli/socket.ts +579 -0
  103. package/server/cli/transport-client.ts +50 -0
  104. package/server/cron/index.ts +137 -0
  105. package/server/cron/job.ts +31 -0
  106. package/server/cron/jobs/balance-sync.ts +436 -0
  107. package/server/cron/jobs/incoming-scan.ts +506 -0
  108. package/server/cron/jobs/native-price.ts +70 -0
  109. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  110. package/server/cron/jobs/strategy-runner.ts +175 -0
  111. package/server/cron/scheduler.ts +125 -0
  112. package/server/index.ts +420 -0
  113. package/server/lib/adapters/factory.ts +119 -0
  114. package/server/lib/adapters/index.ts +19 -0
  115. package/server/lib/adapters/router.ts +297 -0
  116. package/server/lib/adapters/telegram.ts +645 -0
  117. package/server/lib/adapters/types.ts +89 -0
  118. package/server/lib/adapters/webhook.ts +95 -0
  119. package/server/lib/address.ts +49 -0
  120. package/server/lib/agent-auth/contracts.ts +1194 -0
  121. package/server/lib/agent-profiles.ts +419 -0
  122. package/server/lib/ai.ts +285 -0
  123. package/server/lib/api-registry/contracts.ts +86 -0
  124. package/server/lib/api-registry/validation.ts +172 -0
  125. package/server/lib/apikey-migration.ts +258 -0
  126. package/server/lib/app-installer.ts +505 -0
  127. package/server/lib/app-tokens.ts +247 -0
  128. package/server/lib/approval-link.ts +27 -0
  129. package/server/lib/auth.ts +314 -0
  130. package/server/lib/auto-execute.ts +160 -0
  131. package/server/lib/batch.ts +242 -0
  132. package/server/lib/cold.ts +1048 -0
  133. package/server/lib/config.ts +408 -0
  134. package/server/lib/credential-access-audit.ts +85 -0
  135. package/server/lib/credential-access-policy.ts +111 -0
  136. package/server/lib/credential-health.ts +343 -0
  137. package/server/lib/credential-import.ts +608 -0
  138. package/server/lib/credential-scope.ts +102 -0
  139. package/server/lib/credential-shares.ts +190 -0
  140. package/server/lib/credential-transport.ts +533 -0
  141. package/server/lib/credential-vault.ts +77 -0
  142. package/server/lib/credentials.ts +422 -0
  143. package/server/lib/crypto.ts +8 -0
  144. package/server/lib/db.ts +58 -0
  145. package/server/lib/defaults.ts +386 -0
  146. package/server/lib/dex/index.ts +80 -0
  147. package/server/lib/dex/relay.ts +235 -0
  148. package/server/lib/dex/types.ts +59 -0
  149. package/server/lib/dex/uniswap.ts +370 -0
  150. package/server/lib/diary.ts +34 -0
  151. package/server/lib/dont-ask-again-policy.ts +41 -0
  152. package/server/lib/e2e-agent/artifacts.ts +36 -0
  153. package/server/lib/e2e-agent/contracts.ts +112 -0
  154. package/server/lib/e2e-agent/validation.ts +135 -0
  155. package/server/lib/encrypt.ts +114 -0
  156. package/server/lib/error.ts +20 -0
  157. package/server/lib/events.ts +217 -0
  158. package/server/lib/feature-flags.ts +93 -0
  159. package/server/lib/hot.ts +357 -0
  160. package/server/lib/human-action-summary.ts +80 -0
  161. package/server/lib/key-fingerprint.ts +28 -0
  162. package/server/lib/logger.ts +340 -0
  163. package/server/lib/network.ts +137 -0
  164. package/server/lib/notifications.ts +230 -0
  165. package/server/lib/oauth2-refresh.ts +241 -0
  166. package/server/lib/oursecret.ts +71 -0
  167. package/server/lib/passkey-credential.ts +360 -0
  168. package/server/lib/passkey.ts +68 -0
  169. package/server/lib/permissions.ts +299 -0
  170. package/server/lib/pino.ts +24 -0
  171. package/server/lib/policy-preview.ts +138 -0
  172. package/server/lib/price.ts +338 -0
  173. package/server/lib/prices.ts +34 -0
  174. package/server/lib/project-scope.ts +297 -0
  175. package/server/lib/resolve-action.ts +328 -0
  176. package/server/lib/resolve.ts +36 -0
  177. package/server/lib/secret-gist-share.ts +296 -0
  178. package/server/lib/sessions.ts +634 -0
  179. package/server/lib/socket-path.ts +56 -0
  180. package/server/lib/solana/connection.ts +26 -0
  181. package/server/lib/solana/jupiter.ts +128 -0
  182. package/server/lib/solana/transfer.ts +108 -0
  183. package/server/lib/solana/wallet.ts +136 -0
  184. package/server/lib/strategy/emits.ts +21 -0
  185. package/server/lib/strategy/engine.ts +1305 -0
  186. package/server/lib/strategy/executor.ts +115 -0
  187. package/server/lib/strategy/hook-context.ts +159 -0
  188. package/server/lib/strategy/hooks.ts +990 -0
  189. package/server/lib/strategy/index.ts +28 -0
  190. package/server/lib/strategy/installer.ts +305 -0
  191. package/server/lib/strategy/loader.ts +256 -0
  192. package/server/lib/strategy/message.ts +237 -0
  193. package/server/lib/strategy/repository.ts +218 -0
  194. package/server/lib/strategy/session-logger.ts +693 -0
  195. package/server/lib/strategy/sources.ts +288 -0
  196. package/server/lib/strategy/state.ts +189 -0
  197. package/server/lib/strategy/templates.ts +403 -0
  198. package/server/lib/strategy/tick.ts +404 -0
  199. package/server/lib/strategy/types.ts +230 -0
  200. package/server/lib/swap.ts +3 -0
  201. package/server/lib/temp.ts +86 -0
  202. package/server/lib/token-metadata.ts +86 -0
  203. package/server/lib/token-safety.ts +200 -0
  204. package/server/lib/token-search.ts +444 -0
  205. package/server/lib/totp.ts +194 -0
  206. package/server/lib/transactions.ts +123 -0
  207. package/server/lib/transport.ts +84 -0
  208. package/server/lib/txhistory/decoder.ts +262 -0
  209. package/server/lib/txhistory/enricher.ts +652 -0
  210. package/server/lib/txhistory/index.ts +391 -0
  211. package/server/lib/txhistory/signatures.ts +59 -0
  212. package/server/lib/update-check.ts +35 -0
  213. package/server/lib/verified-summary.ts +414 -0
  214. package/server/lib/view-registry.ts +80 -0
  215. package/server/mcp/profile-policy.ts +30 -0
  216. package/server/mcp/server.ts +1589 -0
  217. package/server/mcp/tools.ts +276 -0
  218. package/server/middleware/auth.ts +119 -0
  219. package/server/middleware/requestLogger.ts +84 -0
  220. package/server/routes/actions.ts +539 -0
  221. package/server/routes/adapters.ts +711 -0
  222. package/server/routes/addressbook.ts +113 -0
  223. package/server/routes/ai.ts +34 -0
  224. package/server/routes/apikeys.ts +343 -0
  225. package/server/routes/apps.ts +601 -0
  226. package/server/routes/auth.ts +406 -0
  227. package/server/routes/backup.ts +404 -0
  228. package/server/routes/batch.ts +270 -0
  229. package/server/routes/bookmarks.ts +162 -0
  230. package/server/routes/credential-shares.ts +380 -0
  231. package/server/routes/credential-vaults.ts +159 -0
  232. package/server/routes/credentials.ts +1782 -0
  233. package/server/routes/dashboard.ts +97 -0
  234. package/server/routes/defaults.ts +124 -0
  235. package/server/routes/flags.ts +11 -0
  236. package/server/routes/fund.ts +225 -0
  237. package/server/routes/heartbeat.ts +375 -0
  238. package/server/routes/import.ts +364 -0
  239. package/server/routes/launch.ts +665 -0
  240. package/server/routes/lock.ts +54 -0
  241. package/server/routes/logs.ts +68 -0
  242. package/server/routes/nuke.ts +111 -0
  243. package/server/routes/passkey-credentials.ts +99 -0
  244. package/server/routes/passkey.ts +366 -0
  245. package/server/routes/portfolio.ts +217 -0
  246. package/server/routes/price.ts +63 -0
  247. package/server/routes/resolve.ts +31 -0
  248. package/server/routes/security.ts +45 -0
  249. package/server/routes/send-evm.ts +241 -0
  250. package/server/routes/send-solana.ts +281 -0
  251. package/server/routes/send.ts +178 -0
  252. package/server/routes/setup.ts +210 -0
  253. package/server/routes/strategy.ts +894 -0
  254. package/server/routes/swap-evm.ts +352 -0
  255. package/server/routes/swap-solana.ts +176 -0
  256. package/server/routes/swap.ts +356 -0
  257. package/server/routes/token.ts +247 -0
  258. package/server/routes/unlock.ts +467 -0
  259. package/server/routes/views.ts +41 -0
  260. package/server/routes/wallet-assets.ts +361 -0
  261. package/server/routes/wallet-transactions.ts +515 -0
  262. package/server/routes/wallet.ts +709 -0
  263. package/server/types.ts +146 -0
  264. package/shared/credential-field-schema.ts +248 -0
  265. package/skills/auramaxx/HEARTBEAT.md +78 -0
  266. package/skills/auramaxx/SKILL.md +745 -0
  267. package/skills/auramaxx/docs/AGENT_SETUP.md +155 -0
  268. package/skills/auramaxx/docs/API.md +127 -0
  269. package/skills/auramaxx/docs/AUTH.md +318 -0
  270. package/skills/auramaxx/docs/CLI.md +130 -0
  271. package/skills/auramaxx/docs/MCP.md +122 -0
  272. package/skills/auramaxx/docs/TROUBLESHOOTING.md +357 -0
  273. package/skills/auramaxx/docs/WORKSPACE.md +673 -0
  274. package/skills/auramaxx/docs/security.md +227 -0
  275. package/skills/task-lifecycle/SKILL.md +378 -0
  276. package/src/app/api/[...doc]/page.tsx +36 -0
  277. package/src/app/api/agent-requests/route.ts +30 -0
  278. package/src/app/api/apps/install/route.ts +132 -0
  279. package/src/app/api/apps/manifests/route.ts +16 -0
  280. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  281. package/src/app/api/docs/plain/route.ts +74 -0
  282. package/src/app/api/events/route.ts +92 -0
  283. package/src/app/api/page.tsx +290 -0
  284. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  285. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  286. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  287. package/src/app/api/workspace/[id]/route.ts +168 -0
  288. package/src/app/api/workspace/auth.ts +40 -0
  289. package/src/app/api/workspace/config/route.ts +121 -0
  290. package/src/app/api/workspace/import/route.ts +127 -0
  291. package/src/app/api/workspace/route.ts +116 -0
  292. package/src/app/app-legacy-do-not-use/page.tsx +2245 -0
  293. package/src/app/apple-icon.png +0 -0
  294. package/src/app/approve/[actionId]/page.tsx +409 -0
  295. package/src/app/docs/DocsPageContent.tsx +269 -0
  296. package/src/app/docs/[...doc]/page.tsx +41 -0
  297. package/src/app/docs/page.tsx +38 -0
  298. package/src/app/favicon.ico +0 -0
  299. package/src/app/globals.css +819 -0
  300. package/src/app/health/page.tsx +5 -0
  301. package/src/app/hello/page.tsx +102 -0
  302. package/src/app/icon.png +0 -0
  303. package/src/app/layout.tsx +39 -0
  304. package/src/app/page.tsx +1964 -0
  305. package/src/app/privacy/page.tsx +63 -0
  306. package/src/app/providers.tsx +87 -0
  307. package/src/app/share/[token]/page.tsx +295 -0
  308. package/src/app/terms/page.tsx +80 -0
  309. package/src/components/ChainSelector.tsx +44 -0
  310. package/src/components/HumanActionBar.tsx +697 -0
  311. package/src/components/NotificationDrawer.tsx +387 -0
  312. package/src/components/PasskeyEnrollmentPrompt.tsx +235 -0
  313. package/src/components/apps/AgentKeysApp.tsx +490 -0
  314. package/src/components/apps/App.tsx +153 -0
  315. package/src/components/apps/AppGrid.tsx +15 -0
  316. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  317. package/src/components/apps/DraggableApp.tsx +562 -0
  318. package/src/components/apps/IFrameApp.tsx +73 -0
  319. package/src/components/apps/LogsApp.tsx +360 -0
  320. package/src/components/apps/SendApp.tsx +394 -0
  321. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  322. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  323. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  324. package/src/components/apps/TokenApp.tsx +319 -0
  325. package/src/components/apps/TransactionsApp.tsx +438 -0
  326. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  327. package/src/components/apps/index.ts +13 -0
  328. package/src/components/design-system/Button.tsx +88 -0
  329. package/src/components/design-system/ChainIndicator.tsx +65 -0
  330. package/src/components/design-system/ChainSelector.tsx +147 -0
  331. package/src/components/design-system/ConfirmationModal.tsx +107 -0
  332. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  333. package/src/components/design-system/DownloadButton.tsx +149 -0
  334. package/src/components/design-system/Drawer.tsx +133 -0
  335. package/src/components/design-system/FilterDropdown.tsx +183 -0
  336. package/src/components/design-system/ItemPicker.tsx +157 -0
  337. package/src/components/design-system/Modal.tsx +296 -0
  338. package/src/components/design-system/Popover.tsx +142 -0
  339. package/src/components/design-system/TextInput.tsx +85 -0
  340. package/src/components/design-system/Toggle.tsx +65 -0
  341. package/src/components/design-system/TyvekCollapsibleSection.tsx +55 -0
  342. package/src/components/design-system/index.ts +14 -0
  343. package/src/components/docs/ClientSideMarkdown.tsx +51 -0
  344. package/src/components/docs/DocsSearchBar.tsx +118 -0
  345. package/src/components/docs/DocsThemeToggle.tsx +38 -0
  346. package/src/components/docs/PersistentDocGroup.tsx +91 -0
  347. package/src/components/docs/ShareUrlButton.tsx +33 -0
  348. package/src/components/docs/SidebarScrollMemory.tsx +56 -0
  349. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  350. package/src/components/icons/ChainIcons.tsx +72 -0
  351. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  352. package/src/components/layout/ContentArea.tsx +21 -0
  353. package/src/components/layout/CreateViewModal.tsx +88 -0
  354. package/src/components/layout/LeftRail.tsx +114 -0
  355. package/src/components/layout/TabBar.tsx +284 -0
  356. package/src/components/layout/WalletSidebar.tsx +1030 -0
  357. package/src/components/layout/index.ts +6 -0
  358. package/src/components/marketing/AuraMaxxSpecOverlay.tsx +653 -0
  359. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  360. package/src/components/vault/ApiKeysConsole.tsx +1272 -0
  361. package/src/components/vault/AuditConsole.tsx +600 -0
  362. package/src/components/vault/CredentialDetail.tsx +625 -0
  363. package/src/components/vault/CredentialEmpty.tsx +55 -0
  364. package/src/components/vault/CredentialField.tsx +583 -0
  365. package/src/components/vault/CredentialForm.tsx +1484 -0
  366. package/src/components/vault/CredentialList.tsx +265 -0
  367. package/src/components/vault/CredentialRow.tsx +130 -0
  368. package/src/components/vault/CredentialShareModal.tsx +273 -0
  369. package/src/components/vault/CredentialVault.tsx +1662 -0
  370. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  371. package/src/components/vault/DocsConsole.tsx +113 -0
  372. package/src/components/vault/ImportCredentialsModal.tsx +578 -0
  373. package/src/components/vault/LargeTypeModal.tsx +88 -0
  374. package/src/components/vault/PasswordGenerator.tsx +232 -0
  375. package/src/components/vault/TOTPDisplay.tsx +108 -0
  376. package/src/components/vault/TotpSetupPanel.tsx +198 -0
  377. package/src/components/vault/VaultSidebar.tsx +881 -0
  378. package/src/components/vault/credentialFormName.ts +91 -0
  379. package/src/components/vault/hooks/useVaultKeyboardShortcuts.ts +69 -0
  380. package/src/components/vault/types.ts +56 -0
  381. package/src/context/AuthContext.tsx +365 -0
  382. package/src/context/PriceContext.tsx +113 -0
  383. package/src/context/ThemeContext.tsx +164 -0
  384. package/src/context/WebSocketContext.tsx +269 -0
  385. package/src/context/WorkspaceContext.tsx +668 -0
  386. package/src/hooks/index.ts +4 -0
  387. package/src/hooks/useAgentActions.ts +552 -0
  388. package/src/hooks/useBalance.ts +103 -0
  389. package/src/hooks/useBalances.ts +129 -0
  390. package/src/hooks/useTheme.ts +156 -0
  391. package/src/instrumentation.ts +12 -0
  392. package/src/lib/api-docs.ts +154 -0
  393. package/src/lib/api.ts +474 -0
  394. package/src/lib/app-loader.ts +148 -0
  395. package/src/lib/app-registry.ts +178 -0
  396. package/src/lib/app-sdk.ts +157 -0
  397. package/src/lib/audit-console-adapter.ts +151 -0
  398. package/src/lib/auth-client.ts +75 -0
  399. package/src/lib/config.ts +74 -0
  400. package/src/lib/credential-field-schema.ts +11 -0
  401. package/src/lib/crypto.ts +112 -0
  402. package/src/lib/db.ts +21 -0
  403. package/src/lib/docs.ts +544 -0
  404. package/src/lib/events.ts +363 -0
  405. package/src/lib/pino.ts +24 -0
  406. package/src/lib/theme-handlers.ts +168 -0
  407. package/src/lib/theme.ts +351 -0
  408. package/src/lib/tokenData.ts +378 -0
  409. package/src/lib/totp-import.ts +57 -0
  410. package/src/lib/vault-crypto.ts +129 -0
  411. package/src/lib/view-registry.ts +57 -0
  412. package/src/lib/websocket-server.ts +302 -0
  413. package/src/lib/websocket-setup.ts +79 -0
  414. package/src/lib/wordlist.ts +2050 -0
  415. package/src/lib/workspace-handlers.ts +285 -0
  416. package/start.sh +170 -0
  417. package/tailwind.config.ts +99 -0
  418. package/tsconfig.json +42 -0
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Extracted resolve logic from `POST /actions/:id/resolve`.
3
+ *
4
+ * Called by both the HTTP route handler and the ApprovalRouter (direct in-process).
5
+ */
6
+
7
+ import { prisma } from './db';
8
+ import { events, emitWalletEvent } from './events';
9
+ import { createToken, getTokenHash, escrowToken, type AgentTokenPayload } from './auth';
10
+ import { isValidAgentPubkey, normalizeAgentPubkey } from './credential-transport';
11
+ import { isUnlocked, getColdWalletAddress } from './cold';
12
+ import { normalizeAddress } from './address';
13
+ import { getDefault } from './defaults';
14
+ import { logger } from './logger';
15
+ import { getErrorMessage } from './error';
16
+ import { autoExecuteAction } from './auto-execute';
17
+
18
+ export interface ResolveActionOptions {
19
+ walletAccess?: string[];
20
+ limits?: Record<string, number>;
21
+ }
22
+
23
+ export interface ResolveActionResult {
24
+ success: boolean;
25
+ statusCode: 200 | 400 | 401 | 404;
26
+ data: Record<string, unknown>;
27
+ }
28
+
29
+ export async function resolveAction(
30
+ actionId: string,
31
+ approved: boolean,
32
+ opts?: ResolveActionOptions,
33
+ ): Promise<ResolveActionResult> {
34
+ const id = actionId;
35
+ const walletAccess = opts?.walletAccess;
36
+ const overrideLimits = opts?.limits;
37
+
38
+ if (typeof approved !== 'boolean') {
39
+ return { success: false, statusCode: 400, data: { success: false, error: 'approved (boolean) is required' } };
40
+ }
41
+
42
+ const request = await prisma.humanAction.findUnique({ where: { id } });
43
+ if (!request || request.status !== 'pending') {
44
+ return { success: false, statusCode: 404, data: { success: false, error: 'Action not found or already resolved' } };
45
+ }
46
+
47
+ if (request.type === 'strategy:message') {
48
+ return { success: false, statusCode: 400, data: { success: false, error: 'Internal message jobs are not manually resolvable' } };
49
+ }
50
+
51
+ // Handle rejection for all types
52
+ if (!approved) {
53
+ await prisma.humanAction.update({
54
+ where: { id },
55
+ data: { status: 'rejected', resolvedAt: new Date() },
56
+ });
57
+
58
+ events.actionResolved({ id, type: request.type, approved: false, resolvedBy: 'dashboard' });
59
+ logger.actionResolved(id, request.type, false, 'dashboard');
60
+
61
+ // Notify app of rejection via app:emit
62
+ if (request.type === 'action') {
63
+ let meta: { agentId?: string } = {};
64
+ try { meta = JSON.parse(request.metadata || '{}'); } catch {}
65
+ emitWalletEvent('app:emit', {
66
+ strategyId: (meta.agentId || '').replace(/^app:/, ''),
67
+ channel: 'action:resolved',
68
+ data: { requestId: id, approved: false },
69
+ });
70
+ }
71
+
72
+ return { success: true, statusCode: 200, data: { success: true, approved: false } };
73
+ }
74
+
75
+ // === APPROVAL ===
76
+
77
+ // Strategy approvals
78
+ if (request.type === 'strategy:approve') {
79
+ await prisma.humanAction.update({
80
+ where: { id },
81
+ data: { status: 'approved', resolvedAt: new Date() },
82
+ });
83
+
84
+ events.actionResolved({ id, type: request.type, approved: true, resolvedBy: 'dashboard' });
85
+ return { success: true, statusCode: 200, data: { success: true, approved: true } };
86
+ }
87
+
88
+ // Auth / agent_access / action approvals — generate token
89
+ if (request.type === 'auth' || request.type === 'agent_access' || request.type === 'action') {
90
+ if (!isUnlocked()) {
91
+ return { success: false, statusCode: 401, data: { success: false, error: 'Wallet is locked. Unlock first.' } };
92
+ }
93
+
94
+ let metadata: {
95
+ agentId?: string;
96
+ limit?: number;
97
+ permissions?: string[];
98
+ ttl?: number;
99
+ secretHash?: string;
100
+ limits?: { fund?: number; send?: number; swap?: number };
101
+ walletAccess?: string[];
102
+ credentialAccess?: AgentTokenPayload['credentialAccess'];
103
+ pubkey?: string;
104
+ strategyId?: string;
105
+ summary?: string;
106
+ action?: { endpoint?: string; method?: string; body?: Record<string, unknown> };
107
+ } = {};
108
+ if (request.metadata) {
109
+ try { metadata = JSON.parse(request.metadata); } catch { /* ignore */ }
110
+ }
111
+
112
+ const agentId = metadata.agentId || `agent-${id.slice(0, 8)}`;
113
+ const defaultFundLimit = await getDefault<number>('limits.fund', 0);
114
+ const defaultSendLimit = await getDefault<number>('limits.send', 0.1);
115
+ const defaultSwapLimit = await getDefault<number>('limits.swap', 0.1);
116
+ const defaultPermissions = await getDefault<string[]>('permissions.default', ['wallet:create:hot', 'send:hot', 'swap', 'fund', 'action:create']);
117
+ const defaultTtl = await getDefault<number>('ttl.agent', 3600);
118
+ const limit = overrideLimits?.fund ?? metadata.limit ?? defaultFundLimit;
119
+ const permissions = metadata.permissions || defaultPermissions;
120
+ const ttl = metadata.ttl || defaultTtl;
121
+ let normalizedPubkey = metadata.pubkey;
122
+ if (normalizedPubkey) {
123
+ if (!isValidAgentPubkey(normalizedPubkey)) {
124
+ return { success: false, statusCode: 400, data: { success: false, error: 'Stored pubkey is invalid for token issuance' } };
125
+ }
126
+ normalizedPubkey = normalizeAgentPubkey(normalizedPubkey);
127
+ }
128
+ if (!normalizedPubkey) {
129
+ return { success: false, statusCode: 400, data: { success: false, error: 'pubkey is required when approving token issuance' } };
130
+ }
131
+
132
+ const finalWalletAccess = walletAccess
133
+ ? walletAccess.map((addr: string) => normalizeAddress(addr))
134
+ : metadata.walletAccess;
135
+
136
+ // Build limits: per-token overrides > request metadata > system defaults
137
+ const baseLimits = { fund: limit, send: defaultSendLimit, swap: defaultSwapLimit };
138
+ const finalLimits = overrideLimits
139
+ ? { ...baseLimits, ...overrideLimits }
140
+ : metadata.limits
141
+ ? { ...baseLimits, ...metadata.limits }
142
+ : baseLimits;
143
+
144
+ const token = await createToken(agentId, limit, permissions, ttl, {
145
+ limits: finalLimits,
146
+ walletAccess: finalWalletAccess,
147
+ credentialAccess: metadata.credentialAccess,
148
+ agentPubkey: normalizedPubkey,
149
+ });
150
+
151
+ // Escrow the raw token in memory — never store it in the DB
152
+ escrowToken(id, token);
153
+
154
+ // Update request status with tokenHash (not raw token) for audit/display
155
+ await prisma.humanAction.update({
156
+ where: { id },
157
+ data: {
158
+ status: 'approved',
159
+ resolvedAt: new Date(),
160
+ metadata: JSON.stringify({
161
+ ...metadata,
162
+ tokenHash: getTokenHash(token),
163
+ limits: finalLimits,
164
+ walletAccess: finalWalletAccess,
165
+ pubkey: normalizedPubkey,
166
+ credentialAccess: metadata.credentialAccess,
167
+ }),
168
+ },
169
+ });
170
+
171
+ // Log the approval
172
+ await prisma.log.create({
173
+ data: {
174
+ walletAddress: getColdWalletAddress() || 'system',
175
+ title: 'Agent Access Approved',
176
+ description: `Generated token for ${agentId} with ${limit} ETH limit`,
177
+ },
178
+ });
179
+
180
+ events.tokenCreated({
181
+ tokenHash: getTokenHash(token),
182
+ agentId,
183
+ limit,
184
+ permissions,
185
+ expiresAt: Date.now() + ttl * 1000,
186
+ });
187
+ events.actionResolved({ id, type: request.type, approved: true, resolvedBy: 'dashboard' });
188
+ logger.actionResolved(id, request.type, true, 'dashboard');
189
+
190
+ // Notify app of approval via app:emit (always, even with auto-execute)
191
+ if (request.type === 'action') {
192
+ emitWalletEvent('app:emit', {
193
+ strategyId: (metadata.agentId || '').replace(/^app:/, ''),
194
+ channel: 'action:resolved',
195
+ data: { requestId: id, approved: true },
196
+ });
197
+ }
198
+
199
+ // Auto-execute pre-computed action if present in metadata
200
+ if (metadata.action && (request.type === 'action' || request.type === 'auth')) {
201
+ const action = metadata.action as { endpoint?: string; method?: string; body?: Record<string, unknown> };
202
+ if (action.endpoint && action.method) {
203
+ await autoExecuteAction(
204
+ { endpoint: action.endpoint, method: action.method, body: action.body },
205
+ { requestId: id, agentId: metadata.agentId || '', summary: metadata.summary, token },
206
+ );
207
+ }
208
+ }
209
+
210
+ return {
211
+ success: true,
212
+ statusCode: 200,
213
+ data: {
214
+ success: true,
215
+ token,
216
+ agentId,
217
+ limit,
218
+ limits: finalLimits,
219
+ permissions,
220
+ walletAccess: finalWalletAccess,
221
+ expiresIn: ttl,
222
+ },
223
+ };
224
+ }
225
+
226
+ // Permission update approvals — generate token with updated permissions
227
+ if (request.type === 'permission_update') {
228
+ if (!isUnlocked()) {
229
+ return { success: false, statusCode: 401, data: { success: false, error: 'Wallet is locked. Unlock first.' } };
230
+ }
231
+
232
+ let metadata: {
233
+ agentId?: string;
234
+ tokenHash?: string;
235
+ requestedPermissions?: string[];
236
+ requestedWalletAccess?: string[];
237
+ requestedLimits?: { fund?: number; send?: number; swap?: number };
238
+ requestedPubkey?: string;
239
+ secretHash?: string;
240
+ } = {};
241
+ if (request.metadata) {
242
+ try { metadata = JSON.parse(request.metadata); } catch { /* ignore */ }
243
+ }
244
+
245
+ const agentId = metadata.agentId || `agent-${id.slice(0, 8)}`;
246
+ const newPermissions = overrideLimits?.permissions ?? metadata.requestedPermissions ?? [];
247
+ const newWalletAccess = walletAccess
248
+ ? walletAccess.map((addr: string) => normalizeAddress(addr))
249
+ : metadata.requestedWalletAccess;
250
+ const newLimits = overrideLimits || metadata.requestedLimits;
251
+ let normalizedPubkey = metadata.requestedPubkey;
252
+ if (normalizedPubkey) {
253
+ if (!isValidAgentPubkey(normalizedPubkey)) {
254
+ return { success: false, statusCode: 400, data: { success: false, error: 'requestedPubkey is invalid' } };
255
+ }
256
+ normalizedPubkey = normalizeAgentPubkey(normalizedPubkey);
257
+ }
258
+ if (!normalizedPubkey) {
259
+ return { success: false, statusCode: 400, data: { success: false, error: 'requestedPubkey is required for token issuance' } };
260
+ }
261
+
262
+ const ttl = await getDefault<number>('ttl.agent', 3600);
263
+ const token = await createToken(agentId, newLimits?.fund ?? 0, newPermissions, ttl, {
264
+ limits: newLimits,
265
+ walletAccess: newWalletAccess,
266
+ agentPubkey: normalizedPubkey,
267
+ });
268
+
269
+ // Escrow the raw token in memory — never store it in the DB
270
+ escrowToken(id, token);
271
+
272
+ await prisma.humanAction.update({
273
+ where: { id },
274
+ data: {
275
+ status: 'approved',
276
+ resolvedAt: new Date(),
277
+ metadata: JSON.stringify({
278
+ ...metadata,
279
+ tokenHash: getTokenHash(token),
280
+ approvedPermissions: newPermissions,
281
+ approvedWalletAccess: newWalletAccess,
282
+ approvedLimits: newLimits,
283
+ requestedPubkey: normalizedPubkey,
284
+ }),
285
+ },
286
+ });
287
+
288
+ await prisma.log.create({
289
+ data: {
290
+ walletAddress: getColdWalletAddress() || 'system',
291
+ title: 'Permission Update Approved',
292
+ description: `Updated permissions for ${agentId}`,
293
+ },
294
+ });
295
+
296
+ events.tokenCreated({
297
+ tokenHash: getTokenHash(token),
298
+ agentId,
299
+ limit: newLimits?.fund ?? 0,
300
+ permissions: newPermissions,
301
+ expiresAt: Date.now() + ttl * 1000,
302
+ });
303
+ events.actionResolved({ id, type: request.type, approved: true, resolvedBy: 'dashboard' });
304
+
305
+ return {
306
+ success: true,
307
+ statusCode: 200,
308
+ data: {
309
+ success: true,
310
+ token,
311
+ agentId,
312
+ permissions: newPermissions,
313
+ walletAccess: newWalletAccess,
314
+ limits: newLimits,
315
+ },
316
+ };
317
+ }
318
+
319
+ // For other types (fund_transfer, etc.), update DB and emit event
320
+ await prisma.humanAction.update({
321
+ where: { id },
322
+ data: { status: approved ? 'approved' : 'rejected', resolvedAt: new Date() },
323
+ });
324
+
325
+ events.actionResolved({ id, type: request.type, approved, resolvedBy: 'dashboard' });
326
+
327
+ return { success: true, statusCode: 200, data: { success: true, approved } };
328
+ }
@@ -0,0 +1,36 @@
1
+ import { ethers } from 'ethers';
2
+ import { getRpcUrl } from './config';
3
+
4
+ /**
5
+ * Resolve an ENS name (.eth) to an Ethereum address.
6
+ * Uses ethers built-in provider.resolveName() which handles ENS natively.
7
+ * ENS resolution always uses Ethereum mainnet (ENS is deployed on L1).
8
+ */
9
+ export async function resolveName(name: string): Promise<{ address: string; name: string }> {
10
+ if (!name || typeof name !== 'string') {
11
+ throw new Error('Name is required');
12
+ }
13
+
14
+ // Only support .eth names for now (.sol is out of scope)
15
+ if (!name.endsWith('.eth')) {
16
+ throw new Error(`Unsupported name format: ${name}. Only .eth names are supported.`);
17
+ }
18
+
19
+ // ENS lives on Ethereum mainnet — always resolve against L1
20
+ const rpcUrl = await getRpcUrl('ethereum');
21
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
22
+
23
+ const address = await provider.resolveName(name);
24
+ if (!address) {
25
+ throw new Error(`Could not resolve: ${name}`);
26
+ }
27
+
28
+ return { address, name };
29
+ }
30
+
31
+ /**
32
+ * Check if a string looks like an ENS name (contains a dot).
33
+ */
34
+ export function looksLikeName(value: string): boolean {
35
+ return value.includes('.') && !value.startsWith('0x') && !value.match(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/);
36
+ }
@@ -0,0 +1,296 @@
1
+ import { spawn } from 'child_process';
2
+ import {
3
+ canonicalizeCredentialFieldKey,
4
+ getCredentialPrimaryFieldKey,
5
+ } from '../../shared/credential-field-schema';
6
+
7
+ export type SecretGistAccessMode = 'anyone' | 'password';
8
+ export type SecretGistErrorCode = 'GH_MISSING' | 'GH_AUTH_REQUIRED' | 'GH_CREATE_FAILED';
9
+
10
+ export interface SecretGistField {
11
+ key: string;
12
+ value: string;
13
+ sensitive?: boolean;
14
+ }
15
+
16
+ export class SecretGistError extends Error {
17
+ code: SecretGistErrorCode;
18
+ remediation: string;
19
+ detail?: string;
20
+
21
+ constructor(
22
+ code: SecretGistErrorCode,
23
+ message: string,
24
+ remediation: string,
25
+ detail?: string,
26
+ ) {
27
+ super(message);
28
+ this.name = 'SecretGistError';
29
+ this.code = code;
30
+ this.remediation = remediation;
31
+ this.detail = detail;
32
+ }
33
+ }
34
+
35
+ export interface SecretGistInput {
36
+ credentialId: string;
37
+ credentialName: string;
38
+ credentialType?: string;
39
+ shareUrl: string;
40
+ accessMode: SecretGistAccessMode;
41
+ oneTimeOnly: boolean;
42
+ expiresAfter: string;
43
+ fields?: SecretGistField[];
44
+ }
45
+
46
+ export interface SecretGistDraft {
47
+ title: string;
48
+ filename: string;
49
+ marker: string;
50
+ identifier: string;
51
+ content: string;
52
+ }
53
+
54
+ export interface SecretGistResult extends SecretGistDraft {
55
+ url: string;
56
+ }
57
+
58
+ interface GhCommandResult {
59
+ code: number;
60
+ stdout: string;
61
+ stderr: string;
62
+ spawnError: NodeJS.ErrnoException | null;
63
+ }
64
+
65
+ function normalizeInlineText(raw: string): string {
66
+ return raw.replace(/\s+/g, ' ').trim();
67
+ }
68
+
69
+ function normalizeFieldValue(raw: string): string {
70
+ return raw.replace(/\r?\n/g, '\\n').trim();
71
+ }
72
+
73
+ function normalizeLookupKey(type: string | undefined, key: string): string {
74
+ const trimmed = key.trim();
75
+ if (!trimmed) return '';
76
+ if (!type) return trimmed.toLowerCase();
77
+ return canonicalizeCredentialFieldKey(type, trimmed).toLowerCase();
78
+ }
79
+
80
+ function formatFieldLabel(raw: string): string {
81
+ const trimmed = normalizeInlineText(raw);
82
+ if (!trimmed) return 'FIELD';
83
+ return trimmed.replace(/\s+/g, '_').toUpperCase();
84
+ }
85
+
86
+ function resolvePrimaryField(fields: SecretGistField[], type?: string): { index: number; value: string } {
87
+ if (fields.length === 0) return { index: -1, value: '(none)' };
88
+
89
+ if (type) {
90
+ const mappedKey = normalizeLookupKey(type, getCredentialPrimaryFieldKey(type));
91
+ if (mappedKey) {
92
+ const mappedSensitiveIndex = fields.findIndex((field) =>
93
+ normalizeLookupKey(type, field.key) === mappedKey && field.sensitive !== false);
94
+ if (mappedSensitiveIndex >= 0) {
95
+ return { index: mappedSensitiveIndex, value: fields[mappedSensitiveIndex].value };
96
+ }
97
+ const mappedIndex = fields.findIndex((field) => normalizeLookupKey(type, field.key) === mappedKey);
98
+ if (mappedIndex >= 0) {
99
+ return { index: mappedIndex, value: fields[mappedIndex].value };
100
+ }
101
+ }
102
+ }
103
+
104
+ const valueKeyIndex = fields.findIndex((field) => normalizeLookupKey(type, field.key) === 'value');
105
+ if (valueKeyIndex >= 0) {
106
+ return { index: valueKeyIndex, value: fields[valueKeyIndex].value };
107
+ }
108
+
109
+ const firstSensitiveIndex = fields.findIndex((field) => field.sensitive !== false);
110
+ if (firstSensitiveIndex >= 0) {
111
+ return { index: firstSensitiveIndex, value: fields[firstSensitiveIndex].value };
112
+ }
113
+
114
+ return { index: 0, value: fields[0].value };
115
+ }
116
+
117
+ function sanitizeFilenameSlug(raw: string): string {
118
+ return raw
119
+ .toLowerCase()
120
+ .replace(/[^a-z0-9]+/g, '-')
121
+ .replace(/^-+|-+$/g, '')
122
+ .slice(0, 48);
123
+ }
124
+
125
+ function extractFirstUrl(raw: string): string | null {
126
+ const match = raw.match(/https?:\/\/[^\s]+/i);
127
+ if (!match) return null;
128
+ return match[0].replace(/[)\],.]+$/, '');
129
+ }
130
+
131
+ function looksLikeAuthFailure(raw: string): boolean {
132
+ const lower = raw.toLowerCase();
133
+ return lower.includes('gh auth login')
134
+ || lower.includes('not logged in')
135
+ || lower.includes('authenticate')
136
+ || lower.includes('authentication');
137
+ }
138
+
139
+ function missingGhError(): SecretGistError {
140
+ return new SecretGistError(
141
+ 'GH_MISSING',
142
+ 'GitHub CLI (`gh`) is not installed. Secret gist sharing requires `gh`.',
143
+ 'Install GitHub CLI from https://cli.github.com/ and run `gh auth login`, then retry.',
144
+ );
145
+ }
146
+
147
+ function unauthenticatedGhError(detail?: string): SecretGistError {
148
+ return new SecretGistError(
149
+ 'GH_AUTH_REQUIRED',
150
+ 'GitHub CLI is not authenticated for gist creation.',
151
+ 'Run `gh auth login` (or `gh auth status`) and retry the share command.',
152
+ detail,
153
+ );
154
+ }
155
+
156
+ function gistCreateError(detail?: string): SecretGistError {
157
+ return new SecretGistError(
158
+ 'GH_CREATE_FAILED',
159
+ 'Failed to create secret gist via GitHub CLI.',
160
+ 'Verify `gh auth status` succeeds and retry `gh gist create` (without `--public`).',
161
+ detail,
162
+ );
163
+ }
164
+
165
+ function runGh(args: string[], stdinText?: string): Promise<GhCommandResult> {
166
+ return new Promise((resolve) => {
167
+ let stdout = '';
168
+ let stderr = '';
169
+ let settled = false;
170
+
171
+ const finish = (result: GhCommandResult) => {
172
+ if (settled) return;
173
+ settled = true;
174
+ resolve(result);
175
+ };
176
+
177
+ const child = spawn('gh', args, {
178
+ stdio: ['pipe', 'pipe', 'pipe'],
179
+ });
180
+
181
+ child.stdout.on('data', (chunk: Buffer | string) => {
182
+ stdout += chunk.toString();
183
+ });
184
+ child.stderr.on('data', (chunk: Buffer | string) => {
185
+ stderr += chunk.toString();
186
+ });
187
+
188
+ child.on('error', (error: NodeJS.ErrnoException) => {
189
+ finish({
190
+ code: 127,
191
+ stdout,
192
+ stderr,
193
+ spawnError: error,
194
+ });
195
+ });
196
+
197
+ child.on('close', (code) => {
198
+ finish({
199
+ code: typeof code === 'number' ? code : 1,
200
+ stdout,
201
+ stderr,
202
+ spawnError: null,
203
+ });
204
+ });
205
+
206
+ if (stdinText) {
207
+ child.stdin.write(stdinText);
208
+ }
209
+ child.stdin.end();
210
+ });
211
+ }
212
+
213
+ function isMissingGh(result: GhCommandResult): boolean {
214
+ return result.spawnError?.code === 'ENOENT';
215
+ }
216
+
217
+ export function buildSecretGistDraft(input: SecretGistInput): SecretGistDraft {
218
+ const normalizedName = normalizeInlineText(input.credentialName) || 'credential';
219
+ const filenameSlug = sanitizeFilenameSlug(normalizedName) || 'credential';
220
+ const title = 'AURAMAXX.SH';
221
+ const filename = `auramaxx-sh-${filenameSlug}.txt`;
222
+ const marker = '';
223
+ const identifier = '';
224
+
225
+ const normalizedFields = (input.fields || [])
226
+ .map((field) => ({
227
+ key: normalizeInlineText(field.key || 'field'),
228
+ value: normalizeFieldValue(String(field.value || '')),
229
+ sensitive: field.sensitive,
230
+ }))
231
+ .filter((field) => field.key.length > 0 && field.value.length > 0);
232
+
233
+ const primary = resolvePrimaryField(normalizedFields, input.credentialType);
234
+ const otherFields = normalizedFields.filter((_, index) => index !== primary.index);
235
+
236
+ const lines = [
237
+ '------------------------------',
238
+ 'AURAMAXX.SH',
239
+ '------------------------------',
240
+ `NAME: ${normalizedName}`,
241
+ `VALUE: ${normalizeFieldValue(primary.value) || '(none)'}`,
242
+ '',
243
+ ];
244
+
245
+ for (const field of otherFields) {
246
+ lines.push(`${formatFieldLabel(field.key)}: ${field.value}`);
247
+ }
248
+
249
+ return {
250
+ title,
251
+ filename,
252
+ marker,
253
+ identifier,
254
+ content: `${lines.join('\n')}\n`,
255
+ };
256
+ }
257
+
258
+ export async function createSecretGist(input: SecretGistInput): Promise<SecretGistResult> {
259
+ const authCheck = await runGh(['auth', 'status']);
260
+ if (isMissingGh(authCheck)) {
261
+ throw missingGhError();
262
+ }
263
+ if (authCheck.code !== 0) {
264
+ const detail = normalizeInlineText(`${authCheck.stderr}\n${authCheck.stdout}`.trim());
265
+ throw unauthenticatedGhError(detail || undefined);
266
+ }
267
+
268
+ const draft = buildSecretGistDraft(input);
269
+ const createResult = await runGh(
270
+ // `gh gist create` defaults to secret/private. Newer gh versions do not support `--private`.
271
+ ['gist', 'create', '--filename', draft.filename, '--desc', draft.title, '-'],
272
+ draft.content,
273
+ );
274
+
275
+ if (isMissingGh(createResult)) {
276
+ throw missingGhError();
277
+ }
278
+ if (createResult.code !== 0) {
279
+ const detail = normalizeInlineText(`${createResult.stderr}\n${createResult.stdout}`.trim());
280
+ if (looksLikeAuthFailure(detail)) {
281
+ throw unauthenticatedGhError(detail || undefined);
282
+ }
283
+ throw gistCreateError(detail || undefined);
284
+ }
285
+
286
+ const combinedOutput = `${createResult.stdout}\n${createResult.stderr}`;
287
+ const url = extractFirstUrl(combinedOutput);
288
+ if (!url) {
289
+ throw gistCreateError('gh gist create succeeded but no gist URL was returned.');
290
+ }
291
+
292
+ return {
293
+ ...draft,
294
+ url,
295
+ };
296
+ }