@wopr-network/platform-ui-core 1.27.7 → 1.27.9

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 (353) hide show
  1. package/next.config.ts +1 -2
  2. package/package.json +17 -17
  3. package/src/__tests__/account-switcher.test.tsx +21 -20
  4. package/src/__tests__/activity-page.test.tsx +2 -6
  5. package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
  6. package/src/__tests__/admin-api.test.ts +1 -6
  7. package/src/__tests__/admin-gpu-api.test.ts +1 -3
  8. package/src/__tests__/admin-marketplace-api.test.ts +1 -4
  9. package/src/__tests__/admin-middleware.test.ts +76 -83
  10. package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
  11. package/src/__tests__/api-401-redirect.test.ts +46 -9
  12. package/src/__tests__/api-client.test.ts +3 -5
  13. package/src/__tests__/api-config.test.ts +22 -42
  14. package/src/__tests__/api-fleet-resources.test.ts +1 -2
  15. package/src/__tests__/api-fleet-trpc.test.ts +2 -8
  16. package/src/__tests__/api-null-guards.test.ts +3 -1
  17. package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
  18. package/src/__tests__/auth-password-reset.test.tsx +7 -21
  19. package/src/__tests__/auth-redirect.test.tsx +8 -2
  20. package/src/__tests__/auth.test.tsx +25 -23
  21. package/src/__tests__/auto-topup-card.test.tsx +4 -12
  22. package/src/__tests__/backups-tab.test.tsx +3 -4
  23. package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
  24. package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
  25. package/src/__tests__/billing.test.tsx +8 -39
  26. package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
  27. package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
  28. package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
  29. package/src/__tests__/bot-settings-restart.test.tsx +1 -3
  30. package/src/__tests__/bot-settings.test.tsx +2 -6
  31. package/src/__tests__/brand.test.ts +6 -26
  32. package/src/__tests__/buy-credits-panel.test.tsx +1 -3
  33. package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
  34. package/src/__tests__/capability-conflicts.test.ts +2 -8
  35. package/src/__tests__/capability-resolver.test.tsx +2 -12
  36. package/src/__tests__/channel-wizard.test.tsx +4 -17
  37. package/src/__tests__/chat/chat-panel.test.tsx +1 -4
  38. package/src/__tests__/chat-store.test.ts +5 -15
  39. package/src/__tests__/command-center.test.tsx +10 -12
  40. package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
  41. package/src/__tests__/confirmation-tracker.test.tsx +3 -18
  42. package/src/__tests__/coupon-input.test.tsx +1 -3
  43. package/src/__tests__/create-instance.test.tsx +1 -3
  44. package/src/__tests__/credit-balance.test.tsx +4 -12
  45. package/src/__tests__/credits.test.tsx +32 -85
  46. package/src/__tests__/email-verification-banner.test.tsx +2 -6
  47. package/src/__tests__/error-boundaries.test.tsx +0 -1
  48. package/src/__tests__/fetch-pricing.test.ts +2 -1
  49. package/src/__tests__/field-oauth.test.tsx +2 -6
  50. package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
  51. package/src/__tests__/fixtures/mock-manifests.ts +2 -4
  52. package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
  53. package/src/__tests__/fleet-health-update.test.tsx +1 -8
  54. package/src/__tests__/gpu-dashboard.test.tsx +2 -6
  55. package/src/__tests__/instance-detail.test.tsx +3 -9
  56. package/src/__tests__/instance-list.test.tsx +1 -5
  57. package/src/__tests__/layout-snapshots.test.tsx +64 -11
  58. package/src/__tests__/marketplace-admin.test.tsx +2 -6
  59. package/src/__tests__/marketplace.test.tsx +11 -35
  60. package/src/__tests__/merge-api-rates.test.ts +1 -6
  61. package/src/__tests__/middleware.test.ts +32 -219
  62. package/src/__tests__/next-config-headers.test.ts +1 -3
  63. package/src/__tests__/notifications.test.tsx +4 -11
  64. package/src/__tests__/oauth-buttons.test.tsx +36 -59
  65. package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
  66. package/src/__tests__/observability.test.tsx +23 -36
  67. package/src/__tests__/onboarding-page.test.tsx +4 -6
  68. package/src/__tests__/org-billing-api.test.tsx +1 -6
  69. package/src/__tests__/plugin-install-flow.test.tsx +28 -58
  70. package/src/__tests__/plugin-registry.test.tsx +3 -11
  71. package/src/__tests__/plugin-tool-sync.test.ts +1 -3
  72. package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
  73. package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
  74. package/src/__tests__/portfolio-chart.test.tsx +2 -6
  75. package/src/__tests__/promotion-form.test.tsx +2 -6
  76. package/src/__tests__/promotions-list.test.tsx +1 -3
  77. package/src/__tests__/provider-key-api.test.ts +2 -1
  78. package/src/__tests__/resend-verification-button.test.tsx +8 -24
  79. package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
  80. package/src/__tests__/settings.test.tsx +11 -21
  81. package/src/__tests__/setup-checklist.test.tsx +3 -9
  82. package/src/__tests__/setup.ts +25 -6
  83. package/src/__tests__/snapshot-api.test.ts +2 -1
  84. package/src/__tests__/step-superpowers.test.tsx +1 -3
  85. package/src/__tests__/tenant-context.test.tsx +1 -6
  86. package/src/__tests__/tenant-keys-api.test.ts +3 -4
  87. package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
  88. package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
  89. package/src/__tests__/transaction-history.test.tsx +190 -238
  90. package/src/__tests__/trpc-types.test.ts +2 -6
  91. package/src/__tests__/use-chat.test.ts +1 -3
  92. package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
  93. package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
  94. package/src/__tests__/use-webmcp.test.ts +1 -3
  95. package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
  96. package/src/__tests__/verify-page.test.tsx +4 -13
  97. package/src/__tests__/verify-redirect.test.tsx +2 -6
  98. package/src/app/(auth)/error.tsx +1 -7
  99. package/src/app/(auth)/forgot-password/page.tsx +4 -18
  100. package/src/app/(auth)/login/page.tsx +5 -22
  101. package/src/app/(auth)/reset-password/page.tsx +2 -12
  102. package/src/app/(auth)/signup/page.tsx +10 -44
  103. package/src/app/(auth)/verify/page.tsx +47 -0
  104. package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
  105. package/src/app/(dashboard)/billing/error.tsx +2 -10
  106. package/src/app/(dashboard)/billing/layout.tsx +12 -62
  107. package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
  108. package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
  109. package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
  110. package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
  111. package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
  112. package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
  113. package/src/app/(dashboard)/changesets/error.tsx +1 -7
  114. package/src/app/(dashboard)/chat/page.tsx +2 -6
  115. package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
  116. package/src/app/(dashboard)/error.tsx +1 -7
  117. package/src/app/(dashboard)/layout.tsx +15 -36
  118. package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
  119. package/src/app/(dashboard)/marketplace/error.tsx +1 -7
  120. package/src/app/(dashboard)/marketplace/page.tsx +6 -27
  121. package/src/app/(dashboard)/not-found.tsx +2 -5
  122. package/src/app/(dashboard)/onboarding/page.tsx +5 -22
  123. package/src/app/(dashboard)/settings/account/page.tsx +1 -6
  124. package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
  125. package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
  126. package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
  127. package/src/app/(dashboard)/settings/error.tsx +2 -10
  128. package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
  129. package/src/app/(dashboard)/settings/org/page.tsx +13 -56
  130. package/src/app/(dashboard)/settings/page.tsx +1 -0
  131. package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
  132. package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
  133. package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
  134. package/src/app/(dashboard)/settings/security/page.tsx +31 -111
  135. package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
  136. package/src/app/admin/error.tsx +1 -7
  137. package/src/app/admin/fleet-updates/error.tsx +1 -7
  138. package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
  139. package/src/app/admin/layout.tsx +4 -0
  140. package/src/app/admin/payment-methods/page.tsx +9 -38
  141. package/src/app/admin/products/error.tsx +2 -7
  142. package/src/app/admin/products/page.tsx +1 -4
  143. package/src/app/admin/promotions/[id]/page.tsx +9 -38
  144. package/src/app/admin/promotions/page.tsx +9 -36
  145. package/src/app/admin/rate-overrides/page.tsx +9 -45
  146. package/src/app/auth/callback/[provider]/page.tsx +1 -8
  147. package/src/app/auth/verify/page.tsx +9 -36
  148. package/src/app/channels/error.tsx +2 -10
  149. package/src/app/channels/layout.tsx +9 -0
  150. package/src/app/channels/page.tsx +8 -20
  151. package/src/app/channels/setup/[plugin]/page.tsx +3 -5
  152. package/src/app/error.tsx +1 -7
  153. package/src/app/fleet/error.tsx +1 -7
  154. package/src/app/fleet/layout.tsx +5 -0
  155. package/src/app/fleet/settings/page.tsx +1 -3
  156. package/src/app/global-error.tsx +2 -10
  157. package/src/app/globals.css +1 -4
  158. package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
  159. package/src/app/instances/error.tsx +2 -10
  160. package/src/app/instances/instance-list-client.tsx +20 -69
  161. package/src/app/instances/layout.tsx +9 -0
  162. package/src/app/instances/new/create-instance-client.tsx +10 -31
  163. package/src/app/layout.tsx +2 -10
  164. package/src/app/not-found.tsx +1 -3
  165. package/src/app/page.tsx +1 -2
  166. package/src/app/plugins/error.tsx +2 -10
  167. package/src/app/plugins/layout.tsx +5 -0
  168. package/src/app/plugins/page.tsx +16 -48
  169. package/src/app/pricing/error.tsx +1 -7
  170. package/src/app/privacy/page.tsx +93 -150
  171. package/src/app/status/error.tsx +1 -7
  172. package/src/app/terms/page.tsx +89 -144
  173. package/src/components/account-switcher.tsx +25 -52
  174. package/src/components/admin/accounting-dashboard.tsx +1 -3
  175. package/src/components/admin/admin-guard.tsx +1 -3
  176. package/src/components/admin/admin-nav.tsx +1 -3
  177. package/src/components/admin/affiliate-dashboard.tsx +25 -94
  178. package/src/components/admin/audit-log-table.tsx +13 -49
  179. package/src/components/admin/billing-health-dashboard.tsx +7 -25
  180. package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
  181. package/src/components/admin/bulk-actions-bar.tsx +1 -3
  182. package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
  183. package/src/components/admin/bulk-export-dialog.tsx +6 -32
  184. package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
  185. package/src/components/admin/bulk-grant-dialog.tsx +4 -15
  186. package/src/components/admin/bulk-preview-dialog.tsx +3 -12
  187. package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
  188. package/src/components/admin/bulk-select-all-banner.tsx +1 -6
  189. package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
  190. package/src/components/admin/bulk-undo-toast.tsx +1 -2
  191. package/src/components/admin/compliance-dashboard.tsx +31 -101
  192. package/src/components/admin/gpu-dashboard.tsx +21 -70
  193. package/src/components/admin/grant-credits-dialog.tsx +4 -17
  194. package/src/components/admin/incident-dashboard.tsx +10 -25
  195. package/src/components/admin/inference-dashboard.tsx +14 -54
  196. package/src/components/admin/marketplace-admin.tsx +18 -60
  197. package/src/components/admin/migrations-dashboard.tsx +9 -42
  198. package/src/components/admin/onboarding-dashboard.tsx +14 -64
  199. package/src/components/admin/pool-config-dashboard.tsx +4 -10
  200. package/src/components/admin/products/fleet-form.tsx +2 -11
  201. package/src/components/admin/products/nav-editor.tsx +3 -10
  202. package/src/components/admin/promotions/promotion-form.tsx +9 -42
  203. package/src/components/admin/roles-dashboard.tsx +7 -34
  204. package/src/components/admin/suspend-dialog.tsx +4 -11
  205. package/src/components/admin/tenant-notes-panel.tsx +1 -3
  206. package/src/components/admin/tenant-row-actions.tsx +4 -20
  207. package/src/components/admin/tenant-table.tsx +12 -49
  208. package/src/components/auth/auth-redirect.tsx +11 -3
  209. package/src/components/auth/email-verification-result-banner.tsx +1 -3
  210. package/src/components/auth/resend-verification-button.tsx +2 -10
  211. package/src/components/auth/wopr-wordmark.tsx +1 -3
  212. package/src/components/billing/add-payment-method-dialog.tsx +1 -2
  213. package/src/components/billing/affiliate-dashboard.tsx +4 -16
  214. package/src/components/billing/amount-selector.tsx +1 -3
  215. package/src/components/billing/auto-topup-card.tsx +2 -11
  216. package/src/components/billing/buy-credits-panel.tsx +14 -17
  217. package/src/components/billing/byok-callout.tsx +6 -8
  218. package/src/components/billing/confirmation-tracker.tsx +4 -14
  219. package/src/components/billing/credit-balance-badge.tsx +22 -0
  220. package/src/components/billing/credit-balance.tsx +3 -9
  221. package/src/components/billing/crypto-checkout.tsx +5 -24
  222. package/src/components/billing/degraded-state-banner.tsx +1 -3
  223. package/src/components/billing/deposit-view.tsx +301 -41
  224. package/src/components/billing/dividend-banner.tsx +1 -3
  225. package/src/components/billing/dividend-eligibility.tsx +3 -12
  226. package/src/components/billing/dividend-pool-stats.tsx +6 -20
  227. package/src/components/billing/first-dividend-dialog.tsx +2 -2
  228. package/src/components/billing/org-billing-page.tsx +8 -31
  229. package/src/components/billing/payment-method-picker.tsx +2 -10
  230. package/src/components/billing/suspension-banner.tsx +2 -7
  231. package/src/components/billing/transaction-history.tsx +10 -58
  232. package/src/components/billing/unified-checkout.tsx +547 -0
  233. package/src/components/bot-settings/backups-tab.tsx +9 -33
  234. package/src/components/bot-settings/bot-settings-client.tsx +32 -134
  235. package/src/components/bot-settings/resources-tab.tsx +2 -9
  236. package/src/components/bot-settings/storage-tab.tsx +19 -48
  237. package/src/components/bot-settings/vps-info-panel.tsx +3 -11
  238. package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
  239. package/src/components/brand-hydrator.tsx +13 -0
  240. package/src/components/channel-wizard/field-interactive.tsx +1 -3
  241. package/src/components/channel-wizard/field-qr.tsx +10 -39
  242. package/src/components/channel-wizard/step-renderer.tsx +5 -28
  243. package/src/components/channel-wizard/wizard.tsx +6 -31
  244. package/src/components/chat/chat-message.tsx +1 -4
  245. package/src/components/chat/chat-panel.tsx +4 -18
  246. package/src/components/chat/chat-widget.tsx +3 -14
  247. package/src/components/dashboard/command-center.tsx +15 -61
  248. package/src/components/fleet/update-settings-card.tsx +7 -23
  249. package/src/components/instance-update-banner.tsx +130 -0
  250. package/src/components/instances/friends-tab.test.tsx +2 -9
  251. package/src/components/instances/friends-tab.tsx +18 -74
  252. package/src/components/instances/update-available-badge.tsx +2 -11
  253. package/src/components/landing/hero.tsx +3 -9
  254. package/src/components/landing/landing-page.tsx +1 -3
  255. package/src/components/landing/portfolio-chart.tsx +4 -9
  256. package/src/components/landing/story-sections.tsx +1 -3
  257. package/src/components/landing/terminal-sequence.tsx +4 -17
  258. package/src/components/marketplace/empty-state.tsx +2 -6
  259. package/src/components/marketplace/first-visit-hero.tsx +1 -3
  260. package/src/components/marketplace/install-wizard.tsx +20 -77
  261. package/src/components/marketplace/marketplace-tabs.tsx +1 -4
  262. package/src/components/marketplace/plugin-card.tsx +2 -9
  263. package/src/components/marketplace/superpower-content.tsx +1 -3
  264. package/src/components/marketplace/terminal-search.tsx +2 -8
  265. package/src/components/oauth-buttons.tsx +29 -14
  266. package/src/components/observability/fleet-health.tsx +5 -18
  267. package/src/components/observability/health-overview.tsx +7 -20
  268. package/src/components/observability/logs-viewer.tsx +8 -32
  269. package/src/components/observability/metrics-dashboard.tsx +2 -15
  270. package/src/components/onboarding/fallback-setup.tsx +6 -25
  271. package/src/components/onboarding/setup-checklist.tsx +18 -51
  272. package/src/components/onboarding/step-superpowers.tsx +1 -4
  273. package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
  274. package/src/components/pricing/dividend-calculator.tsx +6 -12
  275. package/src/components/pricing/dividend-stats.tsx +5 -17
  276. package/src/components/pricing/pricing-page.tsx +17 -36
  277. package/src/components/settings/create-org-wizard.tsx +2 -5
  278. package/src/components/sidebar.tsx +7 -42
  279. package/src/components/sidecar-frame.tsx +78 -0
  280. package/src/components/status/status-page.tsx +6 -28
  281. package/src/components/ui/alert-dialog.tsx +8 -25
  282. package/src/components/ui/badge.tsx +2 -8
  283. package/src/components/ui/banner.tsx +1 -6
  284. package/src/components/ui/card.tsx +5 -24
  285. package/src/components/ui/checkbox.tsx +1 -5
  286. package/src/components/ui/collapsible.tsx +3 -8
  287. package/src/components/ui/dialog.tsx +4 -10
  288. package/src/components/ui/dropdown-menu.tsx +9 -18
  289. package/src/components/ui/form.tsx +2 -16
  290. package/src/components/ui/popover.tsx +3 -23
  291. package/src/components/ui/progress.tsx +1 -5
  292. package/src/components/ui/radio-group.tsx +3 -15
  293. package/src/components/ui/select.tsx +4 -17
  294. package/src/components/ui/sheet.tsx +5 -19
  295. package/src/components/ui/skeleton.tsx +1 -7
  296. package/src/components/ui/table.tsx +5 -22
  297. package/src/components/ui/tabs.tsx +3 -13
  298. package/src/components/ui/tooltip.tsx +1 -1
  299. package/src/components/unified-sidebar.tsx +493 -0
  300. package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
  301. package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
  302. package/src/hooks/use-credit-balance.ts +27 -0
  303. package/src/hooks/use-my-org-role.ts +1 -3
  304. package/src/hooks/use-plugin-registry.ts +8 -14
  305. package/src/hooks/use-plugin-setup-chat.ts +2 -5
  306. package/src/hooks/use-sidecar-bridge.tsx +148 -0
  307. package/src/hooks/use-webmcp.ts +1 -4
  308. package/src/lib/__tests__/admin-api.test.ts +1 -3
  309. package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
  310. package/src/lib/__tests__/api-fetch.test.ts +4 -16
  311. package/src/lib/__tests__/org-billing-api.test.ts +1 -3
  312. package/src/lib/__tests__/pricing-data.test.ts +0 -8
  313. package/src/lib/__tests__/settings-api.test.ts +1 -3
  314. package/src/lib/admin-affiliate-api.ts +2 -7
  315. package/src/lib/admin-api.ts +6 -26
  316. package/src/lib/admin-incident-api.ts +11 -19
  317. package/src/lib/admin-marketplace-api.ts +1 -5
  318. package/src/lib/api-config.test.ts +5 -50
  319. package/src/lib/api.ts +143 -122
  320. package/src/lib/auth-client.ts +1 -2
  321. package/src/lib/bot-settings-data.ts +11 -36
  322. package/src/lib/brand-config.ts +56 -115
  323. package/src/lib/brand.ts +2 -15
  324. package/src/lib/chat/use-chat.ts +2 -7
  325. package/src/lib/cost-comparison-data.test.ts +1 -3
  326. package/src/lib/cost-comparison-data.ts +1 -4
  327. package/src/lib/errors.ts +1 -4
  328. package/src/lib/fetch-utils.test.ts +26 -9
  329. package/src/lib/fetch-utils.ts +40 -11
  330. package/src/lib/logger.ts +2 -0
  331. package/src/lib/marketplace-data.ts +3 -11
  332. package/src/lib/oauth-errors.ts +2 -4
  333. package/src/lib/onboarding-data.ts +3 -11
  334. package/src/lib/org-api.ts +2 -10
  335. package/src/lib/org-billing-api.ts +5 -19
  336. package/src/lib/plugin/tool-definitions.ts +1 -2
  337. package/src/lib/require-auth.ts +57 -0
  338. package/src/lib/settings-api.ts +1 -4
  339. package/src/lib/sidecar-routes.ts +43 -0
  340. package/src/lib/trpc-server.ts +49 -0
  341. package/src/lib/trpc-types.ts +4 -6
  342. package/src/lib/trpc.tsx +12 -4
  343. package/src/lib/validate-redirect-url.ts +1 -4
  344. package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
  345. package/src/lib/webmcp/register.ts +1 -4
  346. package/src/lib/webmcp/tools.ts +2 -9
  347. package/src/proxy.ts +35 -212
  348. package/src/types/missing-deps.d.ts +2 -8
  349. package/tsconfig.json +1 -8
  350. package/biome.json +0 -52
  351. package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
  352. package/src/__tests__/billing-byok-callout.test.tsx +0 -76
  353. package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
@@ -6,12 +6,7 @@ import { useRef } from "react";
6
6
  import { Badge } from "@/components/ui/badge";
7
7
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
8
8
  import { brandName } from "@/lib/brand-config";
9
- import {
10
- formatInstallCount,
11
- getCapabilityColor,
12
- hasHostedOption,
13
- type PluginManifest,
14
- } from "@/lib/marketplace-data";
9
+ import { formatInstallCount, getCapabilityColor, hasHostedOption, type PluginManifest } from "@/lib/marketplace-data";
15
10
 
16
11
  interface PluginCardProps {
17
12
  plugin: PluginManifest;
@@ -85,9 +80,7 @@ export function PluginCard({ plugin, index = 0, installed = false }: PluginCardP
85
80
  v{plugin.version}
86
81
  </Badge>
87
82
  </div>
88
- <CardDescription className="mt-1 line-clamp-2">
89
- {plugin.description}
90
- </CardDescription>
83
+ <CardDescription className="mt-1 line-clamp-2">{plugin.description}</CardDescription>
91
84
  </div>
92
85
  </div>
93
86
  </CardHeader>
@@ -61,9 +61,7 @@ const mdComponents = {
61
61
  em: ({ children }: ComponentPropsWithoutRef<"em">) => (
62
62
  <em className="text-lg text-muted-foreground not-italic font-light">{children}</em>
63
63
  ),
64
- ul: ({ children }: ComponentPropsWithoutRef<"ul">) => (
65
- <ul className="space-y-2 ml-1">{children}</ul>
66
- ),
64
+ ul: ({ children }: ComponentPropsWithoutRef<"ul">) => <ul className="space-y-2 ml-1">{children}</ul>,
67
65
  li: ({ children }: ComponentPropsWithoutRef<"li">) => (
68
66
  <li className="flex items-start gap-2 text-sm leading-relaxed">
69
67
  <span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-primary/60" />
@@ -11,11 +11,7 @@ interface TerminalSearchProps {
11
11
  placeholder?: string;
12
12
  }
13
13
 
14
- export function TerminalSearch({
15
- value,
16
- onChange,
17
- placeholder = "Search plugins...",
18
- }: TerminalSearchProps) {
14
+ export function TerminalSearch({ value, onChange, placeholder = "Search plugins..." }: TerminalSearchProps) {
19
15
  const [focused, setFocused] = useState(false);
20
16
  const inputRef = useRef<HTMLInputElement>(null);
21
17
 
@@ -23,9 +19,7 @@ export function TerminalSearch({
23
19
  <search
24
20
  className={cn(
25
21
  "flex items-center gap-2 rounded-sm border px-3 py-2 font-mono text-sm transition-all max-w-sm cursor-text",
26
- focused
27
- ? "border-primary shadow-[0_0_8px_rgba(0,255,65,0.15)]"
28
- : "border-input hover:border-primary/40",
22
+ focused ? "border-primary shadow-[0_0_8px_rgba(0,255,65,0.15)]" : "border-input hover:border-primary/40",
29
23
  )}
30
24
  onClick={() => inputRef.current?.focus()}
31
25
  onKeyDown={(e) => {
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
 
3
- import { useState } from "react";
3
+ import { useEffect, useState } from "react";
4
4
  import { Button } from "@/components/ui/button";
5
5
  import { Separator } from "@/components/ui/separator";
6
+ import { API_BASE_URL } from "@/lib/api-config";
6
7
  import { signIn } from "@/lib/auth-client";
7
- import { trpc } from "@/lib/trpc";
8
8
 
9
9
  const providerLabels: Record<string, string> = {
10
10
  github: "GitHub",
@@ -14,25 +14,42 @@ const providerLabels: Record<string, string> = {
14
14
 
15
15
  interface OAuthButtonsProps {
16
16
  callbackUrl?: string;
17
+ productSlug?: string;
17
18
  }
18
19
 
19
- export function OAuthButtons({ callbackUrl = "/" }: OAuthButtonsProps) {
20
+ export function OAuthButtons({ callbackUrl = "/", productSlug }: OAuthButtonsProps) {
20
21
  const [loading, setLoading] = useState<string | null>(null);
21
- const { data: enabledProviders, isLoading } = trpc.authSocial.enabledSocialProviders.useQuery(
22
- undefined,
23
- { staleTime: Number.POSITIVE_INFINITY },
24
- );
22
+ const [enabledProviders, setEnabledProviders] = useState<string[] | null>(null);
23
+ const [isLoading, setIsLoading] = useState(true);
24
+
25
+ useEffect(() => {
26
+ // Don't pass slug — let the server resolve from Origin header
27
+ const url = productSlug
28
+ ? `${API_BASE_URL}/auth/providers?slug=${encodeURIComponent(productSlug)}`
29
+ : `${API_BASE_URL}/auth/providers`;
30
+ fetch(url)
31
+ .then((r) => r.json())
32
+ .then((data) => setEnabledProviders(Array.isArray(data) ? data : []))
33
+ .catch(() => setEnabledProviders([]))
34
+ .finally(() => setIsLoading(false));
35
+ }, [productSlug]);
25
36
 
26
37
  async function handleOAuth(provider: string) {
27
38
  setLoading(provider);
28
39
  try {
29
- const absoluteCallback = callbackUrl.startsWith("http")
30
- ? callbackUrl
31
- : `${window.location.origin}${callbackUrl}`;
32
- await signIn.social({
40
+ const absoluteCallback = callbackUrl.startsWith("http") ? callbackUrl : `${window.location.origin}${callbackUrl}`;
41
+ const result = await signIn.social({
33
42
  provider,
34
43
  callbackURL: absoluteCallback,
44
+ fetchOptions: { redirect: "manual" },
35
45
  });
46
+ // BetterAuth returns { url, redirect } — navigate the browser explicitly
47
+ // fetch() can't follow cross-origin redirects to GitHub, so we must do it ourselves
48
+ const url = (result as { data?: { url?: string } })?.data?.url ?? (result as { url?: string })?.url;
49
+ if (url) {
50
+ window.location.href = url;
51
+ return; // page navigates away
52
+ }
36
53
  } catch {
37
54
  // signIn.social redirects on success; failure here means the redirect didn't happen
38
55
  } finally {
@@ -48,9 +65,7 @@ export function OAuthButtons({ callbackUrl = "/" }: OAuthButtonsProps) {
48
65
  <>
49
66
  <div className="relative my-4 flex items-center">
50
67
  <Separator className="flex-1" />
51
- <span className="mx-3 text-xs uppercase tracking-wider text-muted-foreground">
52
- or continue with
53
- </span>
68
+ <span className="mx-3 text-xs uppercase tracking-wider text-muted-foreground">or continue with</span>
54
69
  <Separator className="flex-1" />
55
70
  </div>
56
71
  <div className="flex flex-col gap-2">
@@ -6,13 +6,7 @@ import Link from "next/link";
6
6
  import { useEffect, useMemo, useState } from "react";
7
7
  import { Button } from "@/components/ui/button";
8
8
  import { Card, CardContent } from "@/components/ui/card";
9
- import {
10
- Select,
11
- SelectContent,
12
- SelectItem,
13
- SelectTrigger,
14
- SelectValue,
15
- } from "@/components/ui/select";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
16
10
  import { Skeleton } from "@/components/ui/skeleton";
17
11
  import { useImageStatus } from "@/hooks/use-image-status";
18
12
  import type { BotStatusResponse, FleetInstance, HealthStatus } from "@/lib/api";
@@ -149,8 +143,7 @@ export function FleetHealth() {
149
143
 
150
144
  const filtered = sorted.filter((inst) => {
151
145
  if (statusFilter === "healthy") return inst.health === "healthy";
152
- if (statusFilter === "attention")
153
- return inst.health === "degraded" || inst.health === "unhealthy";
146
+ if (statusFilter === "attention") return inst.health === "degraded" || inst.health === "unhealthy";
154
147
  return true;
155
148
  });
156
149
 
@@ -215,9 +208,7 @@ export function FleetHealth() {
215
208
  <div className="flex flex-col gap-3 border-b border-terminal/20 pb-4 sm:flex-row sm:items-center sm:gap-6">
216
209
  <div className="flex items-baseline gap-2">
217
210
  <span className="text-3xl font-bold tabular-nums font-mono">{instances.length}</span>
218
- <span className="text-sm text-muted-foreground">
219
- {instances.length === 1 ? "instance" : "instances"}
220
- </span>
211
+ <span className="text-sm text-muted-foreground">{instances.length === 1 ? "instance" : "instances"}</span>
221
212
  </div>
222
213
 
223
214
  <div className="flex flex-wrap items-center gap-4 text-sm font-mono">
@@ -283,18 +274,14 @@ export function FleetHealth() {
283
274
  </Button>
284
275
 
285
276
  {lastUpdated && (
286
- <span className="text-xs text-muted-foreground font-mono">
287
- Updated {formatRelativeTime(lastUpdated)}
288
- </span>
277
+ <span className="text-xs text-muted-foreground font-mono">Updated {formatRelativeTime(lastUpdated)}</span>
289
278
  )}
290
279
  </div>
291
280
 
292
281
  {/* Instance Grid */}
293
282
  {filtered.length === 0 && instances.length === 0 ? (
294
283
  <div className="rounded-sm border border-terminal/20 bg-terminal/5 px-6 py-12 text-center font-mono">
295
- <p className="text-terminal">
296
- &gt; FLEET EMPTY. NO {productName().toUpperCase()} UNITS DEPLOYED.
297
- </p>
284
+ <p className="text-terminal">&gt; FLEET EMPTY. NO {productName().toUpperCase()} UNITS DEPLOYED.</p>
298
285
  <Link
299
286
  href="/instances/new"
300
287
  className="mt-4 inline-block text-sm text-muted-foreground underline underline-offset-4 hover:text-terminal"
@@ -106,9 +106,7 @@ export function HealthOverview({ instanceId }: { instanceId: string }) {
106
106
  <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
107
107
  <Card>
108
108
  <CardHeader className="pb-2">
109
- <CardTitle className="text-xs font-medium text-muted-foreground">
110
- Health Status
111
- </CardTitle>
109
+ <CardTitle className="text-xs font-medium text-muted-foreground">Health Status</CardTitle>
112
110
  </CardHeader>
113
111
  <CardContent>
114
112
  <HealthBadge status={health.status} />
@@ -124,16 +122,12 @@ export function HealthOverview({ instanceId }: { instanceId: string }) {
124
122
  </Card>
125
123
  <Card>
126
124
  <CardHeader className="pb-2">
127
- <CardTitle className="text-xs font-medium text-muted-foreground">
128
- Active Sessions
129
- </CardTitle>
125
+ <CardTitle className="text-xs font-medium text-muted-foreground">Active Sessions</CardTitle>
130
126
  </CardHeader>
131
127
  <CardContent>
132
128
  <p className="text-lg font-semibold">
133
129
  {health.activeSessions}{" "}
134
- <span className="text-sm font-normal text-muted-foreground">
135
- / {health.totalSessions} total
136
- </span>
130
+ <span className="text-sm font-normal text-muted-foreground">/ {health.totalSessions} total</span>
137
131
  </p>
138
132
  </CardContent>
139
133
  </Card>
@@ -179,9 +173,7 @@ export function HealthOverview({ instanceId }: { instanceId: string }) {
179
173
  key={provider.name}
180
174
  className={cn(
181
175
  "border",
182
- provider.available
183
- ? "bg-emerald-500/5 border-emerald-500/25"
184
- : "bg-red-500/5 border-red-500/25",
176
+ provider.available ? "bg-emerald-500/5 border-emerald-500/25" : "bg-red-500/5 border-red-500/25",
185
177
  )}
186
178
  >
187
179
  <CardContent className="flex items-center justify-between p-4">
@@ -217,6 +209,7 @@ export function HealthOverview({ instanceId }: { instanceId: string }) {
217
209
  const c = healthColors[entry.status];
218
210
  return (
219
211
  <div
212
+ // biome-ignore lint/suspicious/noArrayIndexKey: static list, index key is safe
220
213
  key={`${entry.timestamp}-${i}`}
221
214
  className={cn("h-8 flex-1 rounded-sm", c.dot)}
222
215
  title={`${new Date(entry.timestamp).toLocaleTimeString()} - ${entry.status}`}
@@ -225,16 +218,10 @@ export function HealthOverview({ instanceId }: { instanceId: string }) {
225
218
  })}
226
219
  </div>
227
220
  <div className="mt-2 flex justify-between text-xs text-muted-foreground">
221
+ <span>{health.history.length > 0 ? new Date(health.history[0].timestamp).toLocaleTimeString() : ""}</span>
228
222
  <span>
229
223
  {health.history.length > 0
230
- ? new Date(health.history[0].timestamp).toLocaleTimeString()
231
- : ""}
232
- </span>
233
- <span>
234
- {health.history.length > 0
235
- ? new Date(
236
- health.history[health.history.length - 1].timestamp,
237
- ).toLocaleTimeString()
224
+ ? new Date(health.history[health.history.length - 1].timestamp).toLocaleTimeString()
238
225
  : ""}
239
226
  </span>
240
227
  </div>
@@ -5,13 +5,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { Button } from "@/components/ui/button";
6
6
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7
7
  import { Input } from "@/components/ui/input";
8
- import {
9
- Select,
10
- SelectContent,
11
- SelectItem,
12
- SelectTrigger,
13
- SelectValue,
14
- } from "@/components/ui/select";
8
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
15
9
  import { Skeleton } from "@/components/ui/skeleton";
16
10
  import type { LogEntry, LogLevel } from "@/lib/api";
17
11
  import { getInstanceLogs } from "@/lib/api";
@@ -129,11 +123,7 @@ export function LogsViewer({ instanceId }: { instanceId: string }) {
129
123
  )}
130
124
  </div>
131
125
 
132
- <Button
133
- variant={autoScroll ? "terminal" : "outline"}
134
- size="sm"
135
- onClick={() => setAutoScroll(!autoScroll)}
136
- >
126
+ <Button variant={autoScroll ? "terminal" : "outline"} size="sm" onClick={() => setAutoScroll(!autoScroll)}>
137
127
  {autoScroll ? "Auto-scroll ON" : "Auto-scroll OFF"}
138
128
  </Button>
139
129
  </div>
@@ -154,19 +144,14 @@ export function LogsViewer({ instanceId }: { instanceId: string }) {
154
144
  <Card>
155
145
  <CardHeader className="pb-2">
156
146
  <CardTitle className="text-sm">
157
- Real-time Logs{" "}
158
- <span className="font-normal text-muted-foreground">({filtered.length} entries)</span>
147
+ Real-time Logs <span className="font-normal text-muted-foreground">({filtered.length} entries)</span>
159
148
  </CardTitle>
160
149
  </CardHeader>
161
150
  <CardContent>
162
151
  {loading && logs.length === 0 ? (
163
152
  <div className="h-[400px] space-y-2 rounded-md bg-zinc-950 p-4">
164
153
  {Array.from({ length: 12 }, (_, n) => `sk-${n}`).map((skId, i) => (
165
- <Skeleton
166
- key={skId}
167
- className="h-4 bg-zinc-800"
168
- style={{ width: `${60 + ((i * 17) % 40)}%` }}
169
- />
154
+ <Skeleton key={skId} className="h-4 bg-zinc-800" style={{ width: `${60 + ((i * 17) % 40)}%` }} />
170
155
  ))}
171
156
  </div>
172
157
  ) : (
@@ -180,25 +165,16 @@ export function LogsViewer({ instanceId }: { instanceId: string }) {
180
165
  {filtered.length === 0 ? (
181
166
  <div className="flex h-full flex-col items-center justify-center">
182
167
  <p className="text-zinc-500">No logs match the current filters.</p>
183
- <p className="mt-1 text-zinc-600">
184
- Try broadening your search or changing the level filter.
185
- </p>
168
+ <p className="mt-1 text-zinc-600">Try broadening your search or changing the level filter.</p>
186
169
  </div>
187
170
  ) : (
188
171
  filtered.map((log) => (
189
172
  <div
190
173
  key={log.id}
191
- className={cn(
192
- "flex gap-3 rounded px-2 py-1 hover:bg-zinc-900",
193
- levelBgColors[log.level],
194
- )}
174
+ className={cn("flex gap-3 rounded px-2 py-1 hover:bg-zinc-900", levelBgColors[log.level])}
195
175
  >
196
- <span className="shrink-0 text-zinc-600">
197
- {new Date(log.timestamp).toLocaleTimeString()}
198
- </span>
199
- <span
200
- className={cn("w-12 shrink-0 text-right uppercase", levelColors[log.level])}
201
- >
176
+ <span className="shrink-0 text-zinc-600">{new Date(log.timestamp).toLocaleTimeString()}</span>
177
+ <span className={cn("w-12 shrink-0 text-right uppercase", levelColors[log.level])}>
202
178
  {log.level}
203
179
  </span>
204
180
  <span className="shrink-0 text-zinc-500">[{log.source}]</span>
@@ -2,17 +2,7 @@
2
2
 
3
3
  import { AlertTriangleIcon, RefreshCw } from "lucide-react";
4
4
  import { useCallback, useEffect, useState } from "react";
5
- import {
6
- Bar,
7
- BarChart,
8
- CartesianGrid,
9
- Line,
10
- LineChart,
11
- ResponsiveContainer,
12
- Tooltip,
13
- XAxis,
14
- YAxis,
15
- } from "recharts";
5
+ import { Bar, BarChart, CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
16
6
  import { Button } from "@/components/ui/button";
17
7
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
18
8
  import { Skeleton } from "@/components/ui/skeleton";
@@ -192,10 +182,7 @@ export function MetricsDashboard({ instanceId }: { instanceId: string }) {
192
182
  </ResponsiveContainer>
193
183
  <div className="mt-3 space-y-1">
194
184
  {metrics.tokenUsage.map((t) => (
195
- <div
196
- key={t.provider}
197
- className="flex justify-between text-xs text-muted-foreground"
198
- >
185
+ <div key={t.provider} className="flex justify-between text-xs text-muted-foreground">
199
186
  <span className="capitalize">{t.provider}</span>
200
187
  <span className="font-medium text-foreground">${t.totalCost.toFixed(2)}</span>
201
188
  </div>
@@ -6,13 +6,7 @@ import { Button } from "@/components/ui/button";
6
6
  import { Card, CardContent } from "@/components/ui/card";
7
7
  import { Input } from "@/components/ui/input";
8
8
  import { Label } from "@/components/ui/label";
9
- import {
10
- Select,
11
- SelectContent,
12
- SelectItem,
13
- SelectTrigger,
14
- SelectValue,
15
- } from "@/components/ui/select";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
16
10
  import { quickSetup } from "@/lib/api";
17
11
  import { brandName } from "@/lib/brand-config";
18
12
  import { markOnboardingComplete } from "@/lib/onboarding-store";
@@ -69,20 +63,13 @@ export function FallbackSetup() {
69
63
  <CardContent className="p-6">
70
64
  <div className="flex items-center gap-2 mb-1">
71
65
  <AlertTriangle className="h-4 w-4 text-chart-3" />
72
- <h2 className="text-sm font-mono uppercase tracking-[0.2em] text-chart-3">
73
- MANUAL OVERRIDE
74
- </h2>
66
+ <h2 className="text-sm font-mono uppercase tracking-[0.2em] text-chart-3">MANUAL OVERRIDE</h2>
75
67
  </div>
76
- <p className="text-xs text-muted-foreground mb-6">
77
- Platform {brandName()} unavailable. Configure manually.
78
- </p>
68
+ <p className="text-xs text-muted-foreground mb-6">Platform {brandName()} unavailable. Configure manually.</p>
79
69
 
80
70
  <form onSubmit={handleSubmit} className="space-y-4">
81
71
  <div className="space-y-2">
82
- <Label
83
- htmlFor="fallback-api-key"
84
- className="text-xs uppercase tracking-wider text-muted-foreground"
85
- >
72
+ <Label htmlFor="fallback-api-key" className="text-xs uppercase tracking-wider text-muted-foreground">
86
73
  API KEY
87
74
  </Label>
88
75
  <Input
@@ -97,17 +84,11 @@ export function FallbackSetup() {
97
84
  </div>
98
85
 
99
86
  <div className="space-y-2">
100
- <Label
101
- htmlFor="fallback-channel"
102
- className="text-xs uppercase tracking-wider text-muted-foreground"
103
- >
87
+ <Label htmlFor="fallback-channel" className="text-xs uppercase tracking-wider text-muted-foreground">
104
88
  CHANNEL
105
89
  </Label>
106
90
  <Select value={channel} onValueChange={setChannel}>
107
- <SelectTrigger
108
- id="fallback-channel"
109
- className="bg-secondary border-border font-mono text-sm"
110
- >
91
+ <SelectTrigger id="fallback-channel" className="bg-secondary border-border font-mono text-sm">
111
92
  <SelectValue placeholder="Select channel" />
112
93
  </SelectTrigger>
113
94
  <SelectContent>
@@ -60,18 +60,13 @@ const SUPERPOWER_TO_CAPABILITY: Record<string, string> = {
60
60
  "text-gen": "text-gen",
61
61
  };
62
62
 
63
- function resolveSuperpowerStatuses(
64
- selectedIds: string[],
65
- capabilities: CapabilitySetting[],
66
- ): SuperpowerStatus[] {
63
+ function resolveSuperpowerStatuses(selectedIds: string[], capabilities: CapabilitySetting[]): SuperpowerStatus[] {
67
64
  return selectedIds.map((id) => {
68
65
  const sp = superpowers.find((s) => s.id === id);
69
66
  const capName = SUPERPOWER_TO_CAPABILITY[id];
70
67
  const cap = capName ? capabilities.find((c) => c.capability === capName) : undefined;
71
68
 
72
- const ready = cap
73
- ? cap.mode === "hosted" || (cap.mode === "byok" && cap.keyStatus === "valid")
74
- : !sp?.requiresKey;
69
+ const ready = cap ? cap.mode === "hosted" || (cap.mode === "byok" && cap.keyStatus === "valid") : !sp?.requiresKey;
75
70
 
76
71
  return {
77
72
  id,
@@ -90,9 +85,7 @@ export function SetupChecklist() {
90
85
  const [creditBalance, setCreditBalance] = useState<string | null>(null);
91
86
  const [loading, setLoading] = useState(true);
92
87
  const [hasInstances, setHasInstances] = useState(false);
93
- const [connectedChannels, setConnectedChannels] = useState<Map<string, ChannelInfo["status"]>>(
94
- new Map(),
95
- );
88
+ const [connectedChannels, setConnectedChannels] = useState<Map<string, ChannelInfo["status"]>>(new Map());
96
89
  const [capabilities, setCapabilities] = useState<CapabilitySetting[]>([]);
97
90
  const [allChannels, setAllChannels] = useState<PluginOption[]>(channelPlugins);
98
91
 
@@ -106,13 +99,12 @@ export function SetupChecklist() {
106
99
 
107
100
  async function load() {
108
101
  try {
109
- const [instancesResult, creditsResult, capabilitiesResult, marketplaceResult] =
110
- await Promise.allSettled([
111
- listInstances(),
112
- getCreditBalance(),
113
- listCapabilities(),
114
- listMarketplacePlugins(),
115
- ]);
102
+ const [instancesResult, creditsResult, capabilitiesResult, marketplaceResult] = await Promise.allSettled([
103
+ listInstances(),
104
+ getCreditBalance(),
105
+ listCapabilities(),
106
+ listMarketplacePlugins(),
107
+ ]);
116
108
  if (cancelled) return;
117
109
 
118
110
  if (instancesResult.status === "fulfilled") {
@@ -134,9 +126,7 @@ export function SetupChecklist() {
134
126
 
135
127
  // Fetch channel connection status for each instance
136
128
  const channelMap = new Map<string, ChannelInfo["status"]>();
137
- const channelFetches = instances.map((inst) =>
138
- listChannels(inst.id).catch(() => [] as ChannelInfo[]),
139
- );
129
+ const channelFetches = instances.map((inst) => listChannels(inst.id).catch(() => [] as ChannelInfo[]));
140
130
  const channelResults = await Promise.all(channelFetches);
141
131
  if (!cancelled) {
142
132
  for (const channelList of channelResults) {
@@ -223,12 +213,7 @@ export function SetupChecklist() {
223
213
  <CardHeader className="pb-2">
224
214
  <div className="flex items-center justify-between">
225
215
  <CardTitle className="text-base">Let&apos;s get your {productName()} running</CardTitle>
226
- <Button
227
- data-onboarding-id="dashboard.checklist.dismiss"
228
- variant="ghost"
229
- size="xs"
230
- onClick={handleDismiss}
231
- >
216
+ <Button data-onboarding-id="dashboard.checklist.dismiss" variant="ghost" size="xs" onClick={handleDismiss}>
232
217
  Dismiss
233
218
  </Button>
234
219
  </div>
@@ -237,20 +222,12 @@ export function SetupChecklist() {
237
222
  {/* Channels */}
238
223
  {channels.length > 0 && (
239
224
  <section>
240
- <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
241
- Channels
242
- </h3>
225
+ <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Channels</h3>
243
226
  <div className="space-y-1.5">
244
227
  {channels.map((ch) => (
245
- <div
246
- key={ch.id}
247
- className="flex items-center justify-between rounded-sm px-3 py-2 text-sm"
248
- >
228
+ <div key={ch.id} className="flex items-center justify-between rounded-sm px-3 py-2 text-sm">
249
229
  <div className="flex items-center gap-2">
250
- <span
251
- className="inline-block size-2 rounded-full"
252
- style={{ backgroundColor: ch.color }}
253
- />
230
+ <span className="inline-block size-2 rounded-full" style={{ backgroundColor: ch.color }} />
254
231
  <span className="font-medium">{ch.name}</span>
255
232
  </div>
256
233
  {ch.ready ? (
@@ -275,20 +252,12 @@ export function SetupChecklist() {
275
252
  {/* Superpowers */}
276
253
  {powers.length > 0 && (
277
254
  <section>
278
- <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
279
- Superpowers
280
- </h3>
255
+ <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Superpowers</h3>
281
256
  <div className="space-y-1.5">
282
257
  {powers.map((sp) => (
283
- <div
284
- key={sp.id}
285
- className="flex items-center justify-between rounded-sm px-3 py-2 text-sm"
286
- >
258
+ <div key={sp.id} className="flex items-center justify-between rounded-sm px-3 py-2 text-sm">
287
259
  <div className="flex items-center gap-2">
288
- <span
289
- className="inline-block size-2 rounded-full"
290
- style={{ backgroundColor: sp.color }}
291
- />
260
+ <span className="inline-block size-2 rounded-full" style={{ backgroundColor: sp.color }} />
292
261
  <span className="font-medium">{sp.name}</span>
293
262
  </div>
294
263
  {sp.ready ? (
@@ -312,9 +281,7 @@ export function SetupChecklist() {
312
281
 
313
282
  {/* Credits */}
314
283
  <section>
315
- <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
316
- Credits
317
- </h3>
284
+ <h3 className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Credits</h3>
318
285
  <div className="flex items-center gap-2 rounded-sm px-3 py-2 text-sm">
319
286
  <span className="font-medium">Balance</span>
320
287
  <Badge variant="secondary">{creditBalance ?? "$0.00"}</Badge>
@@ -53,10 +53,7 @@ export function StepSuperpowers({
53
53
  return (
54
54
  <div className="space-y-6">
55
55
  <div className="text-center space-y-2">
56
- <div
57
- className="inline-block font-mono text-xs tracking-[0.3em] text-terminal uppercase"
58
- aria-hidden="true"
59
- >
56
+ <div className="inline-block font-mono text-xs tracking-[0.3em] text-terminal uppercase" aria-hidden="true">
60
57
  STEP {stepNumber} {"//"} {stepCode}
61
58
  </div>
62
59
  <h2 className="text-2xl font-bold tracking-tight">Give your {productName()} superpowers</h2>
@@ -6,13 +6,7 @@ import { useEffect, useRef } from "react";
6
6
  import { ChatInput } from "@/components/chat/chat-input";
7
7
  import { ChatMessage } from "@/components/chat/chat-message";
8
8
  import { Button } from "@/components/ui/button";
9
- import {
10
- Sheet,
11
- SheetContent,
12
- SheetDescription,
13
- SheetHeader,
14
- SheetTitle,
15
- } from "@/components/ui/sheet";
9
+ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet";
16
10
  import type { ChatMessage as ChatMessageType } from "@/lib/chat/types";
17
11
 
18
12
  interface SetupChatPanelProps {
@@ -73,9 +67,7 @@ export function SetupChatPanel({
73
67
  {/* Messages area */}
74
68
  <div className="flex-1 space-y-3 overflow-y-auto px-4 py-4">
75
69
  {messages.length === 0 && !isConnected && (
76
- <p className="font-mono text-sm text-terminal/60 animate-pulse">
77
- &gt; Initializing setup...
78
- </p>
70
+ <p className="font-mono text-sm text-terminal/60 animate-pulse">&gt; Initializing setup...</p>
79
71
  )}
80
72
 
81
73
  <AnimatePresence initial={false}>
@@ -94,19 +86,13 @@ export function SetupChatPanel({
94
86
  >
95
87
  {msg.role === "bot" ? (
96
88
  <div className="flex gap-2">
97
- <span className="mt-0.5 font-mono text-sm text-terminal/40 select-none">
98
- &gt;
99
- </span>
89
+ <span className="mt-0.5 font-mono text-sm text-terminal/40 select-none">&gt;</span>
100
90
  <p className="font-mono text-sm leading-relaxed text-terminal">{msg.content}</p>
101
91
  </div>
102
92
  ) : msg.role === "event" ? (
103
93
  <div className="flex gap-2">
104
- <span className="mt-0.5 font-mono text-sm text-destructive/60 select-none">
105
- !
106
- </span>
107
- <p className="font-mono text-sm leading-relaxed text-destructive">
108
- {msg.content}
109
- </p>
94
+ <span className="mt-0.5 font-mono text-sm text-destructive/60 select-none">!</span>
95
+ <p className="font-mono text-sm leading-relaxed text-destructive">{msg.content}</p>
110
96
  </div>
111
97
  ) : (
112
98
  <ChatMessage message={msg} />
@@ -150,9 +136,7 @@ export function SetupChatPanel({
150
136
  className="flex flex-col items-center justify-center gap-2 py-4"
151
137
  >
152
138
  <CheckCircle2 className="h-8 w-8 text-terminal" />
153
- <span className="font-mono text-sm uppercase tracking-wider text-terminal">
154
- Setup complete
155
- </span>
139
+ <span className="font-mono text-sm uppercase tracking-wider text-terminal">Setup complete</span>
156
140
  </motion.div>
157
141
  )}
158
142
  </AnimatePresence>