agent-relay 2.0.22 → 2.0.24

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 (534) hide show
  1. package/bin/relay-pty-linux-arm64 +0 -0
  2. package/dist/src/cli/index.d.ts +3 -3
  3. package/dist/src/cli/index.js +58 -74
  4. package/package.json +21 -62
  5. package/packages/api-types/package.json +1 -1
  6. package/packages/bridge/package.json +8 -8
  7. package/packages/cli-tester/package.json +1 -1
  8. package/packages/config/package.json +2 -2
  9. package/packages/continuity/package.json +1 -1
  10. package/packages/daemon/dist/orchestrator.js +19 -1
  11. package/packages/daemon/package.json +12 -12
  12. package/packages/hooks/package.json +4 -4
  13. package/packages/mcp/package.json +2 -2
  14. package/packages/memory/package.json +2 -2
  15. package/packages/policy/package.json +2 -2
  16. package/packages/protocol/package.json +1 -1
  17. package/packages/resiliency/package.json +1 -1
  18. package/packages/sdk/package.json +2 -2
  19. package/packages/spawner/package.json +1 -1
  20. package/packages/state/package.json +1 -1
  21. package/packages/storage/package.json +2 -2
  22. package/packages/telemetry/package.json +1 -1
  23. package/packages/trajectory/package.json +2 -2
  24. package/packages/user-directory/package.json +2 -2
  25. package/packages/utils/dist/update-checker.js +4 -0
  26. package/packages/utils/package.json +1 -1
  27. package/packages/wrapper/package.json +6 -6
  28. package/deploy/init-db.sql +0 -5
  29. package/deploy/scripts/setup-fly-workspaces.sh +0 -69
  30. package/deploy/scripts/setup-railway.sh +0 -75
  31. package/deploy/workspace/codex.config.toml +0 -20
  32. package/deploy/workspace/entrypoint-browser.sh +0 -118
  33. package/deploy/workspace/entrypoint.sh +0 -612
  34. package/deploy/workspace/gh-credential-relay +0 -90
  35. package/deploy/workspace/gh-relay +0 -156
  36. package/deploy/workspace/git-credential-relay +0 -330
  37. package/deploy/workspace/git-credential-relay.test.sh +0 -230
  38. package/dist/dashboard/out/404.html +0 -1
  39. package/dist/dashboard/out/_next/static/91mkGYq3qbG8WHE6VytQ8/_buildManifest.js +0 -1
  40. package/dist/dashboard/out/_next/static/91mkGYq3qbG8WHE6VytQ8/_ssgManifest.js +0 -1
  41. package/dist/dashboard/out/_next/static/chunks/116-a883fca163f3a5bc.js +0 -1
  42. package/dist/dashboard/out/_next/static/chunks/117-c8afed19e821a35d.js +0 -2
  43. package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +0 -1
  44. package/dist/dashboard/out/_next/static/chunks/320-a6304232cd0ee2ce.js +0 -1
  45. package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +0 -9
  46. package/dist/dashboard/out/_next/static/chunks/631-16b905e5920f9b59.js +0 -1
  47. package/dist/dashboard/out/_next/static/chunks/648-acb2ff9f77cbfbd3.js +0 -1
  48. package/dist/dashboard/out/_next/static/chunks/766-2aea80818f7eb0d8.js +0 -1
  49. package/dist/dashboard/out/_next/static/chunks/83-26d2bde54616ee90.js +0 -1
  50. package/dist/dashboard/out/_next/static/chunks/847-f1f467060f32afff.js +0 -1
  51. package/dist/dashboard/out/_next/static/chunks/891-5cb1513eeb97a891.js +0 -1
  52. package/dist/dashboard/out/_next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +0 -1
  53. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-9914652442f7e4fb.js +0 -1
  54. package/dist/dashboard/out/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js +0 -1
  55. package/dist/dashboard/out/_next/static/chunks/app/cloud/link/page-fa1d5842aa90e8a6.js +0 -1
  56. package/dist/dashboard/out/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +0 -1
  57. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-113060009ef35bc2.js +0 -1
  58. package/dist/dashboard/out/_next/static/chunks/app/history/page-9965d2483011b846.js +0 -1
  59. package/dist/dashboard/out/_next/static/chunks/app/layout-6b91e33784c20610.js +0 -1
  60. package/dist/dashboard/out/_next/static/chunks/app/login/page-435eceb0073be027.js +0 -1
  61. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-1e37ef8e73940b40.js +0 -1
  62. package/dist/dashboard/out/_next/static/chunks/app/page-8119d4246743574e.js +0 -1
  63. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-9db3ebdfa567a7c9.js +0 -1
  64. package/dist/dashboard/out/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +0 -1
  65. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-4dbe33f0f7691b7c.js +0 -1
  66. package/dist/dashboard/out/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +0 -1
  67. package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +0 -18
  68. package/dist/dashboard/out/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +0 -1
  69. package/dist/dashboard/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
  70. package/dist/dashboard/out/_next/static/chunks/main-311c3db74dcfadb7.js +0 -1
  71. package/dist/dashboard/out/_next/static/chunks/main-app-fdbeb09028f57c9f.js +0 -1
  72. package/dist/dashboard/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
  73. package/dist/dashboard/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
  74. package/dist/dashboard/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  75. package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +0 -1
  76. package/dist/dashboard/out/_next/static/css/4034f236dd1a3178.css +0 -1
  77. package/dist/dashboard/out/_next/static/css/6892f8422896ef7a.css +0 -1
  78. package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
  79. package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
  80. package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
  81. package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
  82. package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
  83. package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +0 -45
  84. package/dist/dashboard/out/alt-logos/logo.svg +0 -38
  85. package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
  86. package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
  87. package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
  88. package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
  89. package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
  90. package/dist/dashboard/out/alt-logos/monogram-logo.svg +0 -38
  91. package/dist/dashboard/out/app/onboarding.html +0 -1
  92. package/dist/dashboard/out/app/onboarding.txt +0 -7
  93. package/dist/dashboard/out/app.html +0 -1
  94. package/dist/dashboard/out/app.txt +0 -7
  95. package/dist/dashboard/out/apple-icon.png +0 -0
  96. package/dist/dashboard/out/cloud/link.html +0 -1
  97. package/dist/dashboard/out/cloud/link.txt +0 -7
  98. package/dist/dashboard/out/complete-profile.html +0 -5
  99. package/dist/dashboard/out/complete-profile.txt +0 -7
  100. package/dist/dashboard/out/connect-repos.html +0 -1
  101. package/dist/dashboard/out/connect-repos.txt +0 -7
  102. package/dist/dashboard/out/history.html +0 -1
  103. package/dist/dashboard/out/history.txt +0 -7
  104. package/dist/dashboard/out/index.html +0 -1
  105. package/dist/dashboard/out/index.txt +0 -7
  106. package/dist/dashboard/out/login.html +0 -5
  107. package/dist/dashboard/out/login.txt +0 -7
  108. package/dist/dashboard/out/metrics.html +0 -1
  109. package/dist/dashboard/out/metrics.txt +0 -7
  110. package/dist/dashboard/out/pricing.html +0 -13
  111. package/dist/dashboard/out/pricing.txt +0 -7
  112. package/dist/dashboard/out/providers/setup/claude.html +0 -1
  113. package/dist/dashboard/out/providers/setup/claude.txt +0 -8
  114. package/dist/dashboard/out/providers/setup/codex.html +0 -1
  115. package/dist/dashboard/out/providers/setup/codex.txt +0 -8
  116. package/dist/dashboard/out/providers/setup/cursor.html +0 -1
  117. package/dist/dashboard/out/providers/setup/cursor.txt +0 -8
  118. package/dist/dashboard/out/providers.html +0 -1
  119. package/dist/dashboard/out/providers.txt +0 -7
  120. package/dist/dashboard/out/signup.html +0 -6
  121. package/dist/dashboard/out/signup.txt +0 -7
  122. package/dist/src/cloud/index.d.ts +0 -8
  123. package/dist/src/cloud/index.js +0 -8
  124. package/dist/src/dashboard-server/index.d.ts +0 -8
  125. package/dist/src/dashboard-server/index.js +0 -8
  126. package/packages/cloud/dist/api/admin.d.ts +0 -8
  127. package/packages/cloud/dist/api/admin.js +0 -225
  128. package/packages/cloud/dist/api/auth.d.ts +0 -20
  129. package/packages/cloud/dist/api/auth.js +0 -138
  130. package/packages/cloud/dist/api/billing.d.ts +0 -7
  131. package/packages/cloud/dist/api/billing.js +0 -564
  132. package/packages/cloud/dist/api/cli-pty-runner.d.ts +0 -53
  133. package/packages/cloud/dist/api/cli-pty-runner.js +0 -175
  134. package/packages/cloud/dist/api/codex-auth-helper.d.ts +0 -21
  135. package/packages/cloud/dist/api/codex-auth-helper.js +0 -327
  136. package/packages/cloud/dist/api/consensus.d.ts +0 -13
  137. package/packages/cloud/dist/api/consensus.js +0 -261
  138. package/packages/cloud/dist/api/coordinators.d.ts +0 -8
  139. package/packages/cloud/dist/api/coordinators.js +0 -750
  140. package/packages/cloud/dist/api/daemons.d.ts +0 -12
  141. package/packages/cloud/dist/api/daemons.js +0 -535
  142. package/packages/cloud/dist/api/email-auth.d.ts +0 -11
  143. package/packages/cloud/dist/api/email-auth.js +0 -347
  144. package/packages/cloud/dist/api/generic-webhooks.d.ts +0 -8
  145. package/packages/cloud/dist/api/generic-webhooks.js +0 -129
  146. package/packages/cloud/dist/api/git.d.ts +0 -8
  147. package/packages/cloud/dist/api/git.js +0 -269
  148. package/packages/cloud/dist/api/github-app.d.ts +0 -11
  149. package/packages/cloud/dist/api/github-app.js +0 -223
  150. package/packages/cloud/dist/api/middleware/planLimits.d.ts +0 -43
  151. package/packages/cloud/dist/api/middleware/planLimits.js +0 -202
  152. package/packages/cloud/dist/api/monitoring.d.ts +0 -11
  153. package/packages/cloud/dist/api/monitoring.js +0 -578
  154. package/packages/cloud/dist/api/nango-auth.d.ts +0 -9
  155. package/packages/cloud/dist/api/nango-auth.js +0 -741
  156. package/packages/cloud/dist/api/onboarding.d.ts +0 -15
  157. package/packages/cloud/dist/api/onboarding.js +0 -679
  158. package/packages/cloud/dist/api/policy.d.ts +0 -8
  159. package/packages/cloud/dist/api/policy.js +0 -229
  160. package/packages/cloud/dist/api/provider-env.d.ts +0 -26
  161. package/packages/cloud/dist/api/provider-env.js +0 -141
  162. package/packages/cloud/dist/api/providers.d.ts +0 -7
  163. package/packages/cloud/dist/api/providers.js +0 -574
  164. package/packages/cloud/dist/api/repos.d.ts +0 -8
  165. package/packages/cloud/dist/api/repos.js +0 -577
  166. package/packages/cloud/dist/api/sessions.d.ts +0 -11
  167. package/packages/cloud/dist/api/sessions.js +0 -302
  168. package/packages/cloud/dist/api/teams.d.ts +0 -7
  169. package/packages/cloud/dist/api/teams.js +0 -281
  170. package/packages/cloud/dist/api/test-helpers.d.ts +0 -10
  171. package/packages/cloud/dist/api/test-helpers.js +0 -745
  172. package/packages/cloud/dist/api/usage.d.ts +0 -7
  173. package/packages/cloud/dist/api/usage.js +0 -111
  174. package/packages/cloud/dist/api/webhooks.d.ts +0 -8
  175. package/packages/cloud/dist/api/webhooks.js +0 -645
  176. package/packages/cloud/dist/api/workspaces.d.ts +0 -25
  177. package/packages/cloud/dist/api/workspaces.js +0 -1799
  178. package/packages/cloud/dist/billing/index.d.ts +0 -9
  179. package/packages/cloud/dist/billing/index.js +0 -9
  180. package/packages/cloud/dist/billing/plans.d.ts +0 -39
  181. package/packages/cloud/dist/billing/plans.js +0 -245
  182. package/packages/cloud/dist/billing/service.d.ts +0 -80
  183. package/packages/cloud/dist/billing/service.js +0 -388
  184. package/packages/cloud/dist/billing/types.d.ts +0 -141
  185. package/packages/cloud/dist/billing/types.js +0 -7
  186. package/packages/cloud/dist/config.d.ts +0 -5
  187. package/packages/cloud/dist/config.js +0 -5
  188. package/packages/cloud/dist/db/bulk-ingest.d.ts +0 -89
  189. package/packages/cloud/dist/db/bulk-ingest.js +0 -268
  190. package/packages/cloud/dist/db/drizzle.d.ts +0 -290
  191. package/packages/cloud/dist/db/drizzle.js +0 -1422
  192. package/packages/cloud/dist/db/index.d.ts +0 -56
  193. package/packages/cloud/dist/db/index.js +0 -70
  194. package/packages/cloud/dist/db/schema.d.ts +0 -5117
  195. package/packages/cloud/dist/db/schema.js +0 -656
  196. package/packages/cloud/dist/index.d.ts +0 -11
  197. package/packages/cloud/dist/index.js +0 -38
  198. package/packages/cloud/dist/provisioner/index.d.ts +0 -207
  199. package/packages/cloud/dist/provisioner/index.js +0 -2118
  200. package/packages/cloud/dist/server.d.ts +0 -17
  201. package/packages/cloud/dist/server.js +0 -2034
  202. package/packages/cloud/dist/services/auto-scaler.d.ts +0 -152
  203. package/packages/cloud/dist/services/auto-scaler.js +0 -439
  204. package/packages/cloud/dist/services/capacity-manager.d.ts +0 -148
  205. package/packages/cloud/dist/services/capacity-manager.js +0 -449
  206. package/packages/cloud/dist/services/ci-agent-spawner.d.ts +0 -49
  207. package/packages/cloud/dist/services/ci-agent-spawner.js +0 -373
  208. package/packages/cloud/dist/services/cloud-message-bus.d.ts +0 -28
  209. package/packages/cloud/dist/services/cloud-message-bus.js +0 -19
  210. package/packages/cloud/dist/services/compute-enforcement.d.ts +0 -57
  211. package/packages/cloud/dist/services/compute-enforcement.js +0 -175
  212. package/packages/cloud/dist/services/coordinator.d.ts +0 -62
  213. package/packages/cloud/dist/services/coordinator.js +0 -389
  214. package/packages/cloud/dist/services/index.d.ts +0 -17
  215. package/packages/cloud/dist/services/index.js +0 -25
  216. package/packages/cloud/dist/services/intro-expiration.d.ts +0 -60
  217. package/packages/cloud/dist/services/intro-expiration.js +0 -252
  218. package/packages/cloud/dist/services/mention-handler.d.ts +0 -65
  219. package/packages/cloud/dist/services/mention-handler.js +0 -405
  220. package/packages/cloud/dist/services/nango.d.ts +0 -219
  221. package/packages/cloud/dist/services/nango.js +0 -424
  222. package/packages/cloud/dist/services/persistence.d.ts +0 -131
  223. package/packages/cloud/dist/services/persistence.js +0 -200
  224. package/packages/cloud/dist/services/planLimits.d.ts +0 -147
  225. package/packages/cloud/dist/services/planLimits.js +0 -335
  226. package/packages/cloud/dist/services/presence-registry.d.ts +0 -56
  227. package/packages/cloud/dist/services/presence-registry.js +0 -91
  228. package/packages/cloud/dist/services/scaling-orchestrator.d.ts +0 -159
  229. package/packages/cloud/dist/services/scaling-orchestrator.js +0 -502
  230. package/packages/cloud/dist/services/scaling-policy.d.ts +0 -121
  231. package/packages/cloud/dist/services/scaling-policy.js +0 -415
  232. package/packages/cloud/dist/services/ssh-security.d.ts +0 -31
  233. package/packages/cloud/dist/services/ssh-security.js +0 -63
  234. package/packages/cloud/dist/services/workspace-keepalive.d.ts +0 -76
  235. package/packages/cloud/dist/services/workspace-keepalive.js +0 -234
  236. package/packages/cloud/dist/shims/consensus.d.ts +0 -23
  237. package/packages/cloud/dist/shims/consensus.js +0 -5
  238. package/packages/cloud/dist/webhooks/index.d.ts +0 -24
  239. package/packages/cloud/dist/webhooks/index.js +0 -29
  240. package/packages/cloud/dist/webhooks/parsers/github.d.ts +0 -8
  241. package/packages/cloud/dist/webhooks/parsers/github.js +0 -234
  242. package/packages/cloud/dist/webhooks/parsers/index.d.ts +0 -23
  243. package/packages/cloud/dist/webhooks/parsers/index.js +0 -30
  244. package/packages/cloud/dist/webhooks/parsers/linear.d.ts +0 -9
  245. package/packages/cloud/dist/webhooks/parsers/linear.js +0 -258
  246. package/packages/cloud/dist/webhooks/parsers/slack.d.ts +0 -9
  247. package/packages/cloud/dist/webhooks/parsers/slack.js +0 -214
  248. package/packages/cloud/dist/webhooks/responders/github.d.ts +0 -8
  249. package/packages/cloud/dist/webhooks/responders/github.js +0 -73
  250. package/packages/cloud/dist/webhooks/responders/index.d.ts +0 -23
  251. package/packages/cloud/dist/webhooks/responders/index.js +0 -30
  252. package/packages/cloud/dist/webhooks/responders/linear.d.ts +0 -9
  253. package/packages/cloud/dist/webhooks/responders/linear.js +0 -149
  254. package/packages/cloud/dist/webhooks/responders/slack.d.ts +0 -20
  255. package/packages/cloud/dist/webhooks/responders/slack.js +0 -178
  256. package/packages/cloud/dist/webhooks/router.d.ts +0 -25
  257. package/packages/cloud/dist/webhooks/router.js +0 -504
  258. package/packages/cloud/dist/webhooks/rules-engine.d.ts +0 -24
  259. package/packages/cloud/dist/webhooks/rules-engine.js +0 -287
  260. package/packages/cloud/dist/webhooks/types.d.ts +0 -186
  261. package/packages/cloud/dist/webhooks/types.js +0 -8
  262. package/packages/cloud/package.json +0 -60
  263. package/packages/dashboard/README.md +0 -48
  264. package/packages/dashboard/dist/health-worker-manager.d.ts +0 -62
  265. package/packages/dashboard/dist/health-worker-manager.js +0 -144
  266. package/packages/dashboard/dist/health-worker.d.ts +0 -9
  267. package/packages/dashboard/dist/health-worker.js +0 -79
  268. package/packages/dashboard/dist/index.d.ts +0 -20
  269. package/packages/dashboard/dist/index.js +0 -19
  270. package/packages/dashboard/dist/metrics.d.ts +0 -105
  271. package/packages/dashboard/dist/metrics.js +0 -193
  272. package/packages/dashboard/dist/needs-attention.d.ts +0 -24
  273. package/packages/dashboard/dist/needs-attention.js +0 -78
  274. package/packages/dashboard/dist/server.d.ts +0 -25
  275. package/packages/dashboard/dist/server.js +0 -5270
  276. package/packages/dashboard/dist/start.d.ts +0 -6
  277. package/packages/dashboard/dist/start.js +0 -13
  278. package/packages/dashboard/dist/types/threading.d.ts +0 -8
  279. package/packages/dashboard/dist/types/threading.js +0 -2
  280. package/packages/dashboard/dist/user-bridge.d.ts +0 -154
  281. package/packages/dashboard/dist/user-bridge.js +0 -372
  282. package/packages/dashboard/package.json +0 -65
  283. package/packages/dashboard/ui/app/app/onboarding/page.tsx +0 -394
  284. package/packages/dashboard/ui/app/app/page.tsx +0 -667
  285. package/packages/dashboard/ui/app/apple-icon.png +0 -0
  286. package/packages/dashboard/ui/app/cloud/link/page.tsx +0 -464
  287. package/packages/dashboard/ui/app/complete-profile/page.tsx +0 -204
  288. package/packages/dashboard/ui/app/connect-repos/page.tsx +0 -410
  289. package/packages/dashboard/ui/app/favicon.png +0 -0
  290. package/packages/dashboard/ui/app/globals.css +0 -59
  291. package/packages/dashboard/ui/app/history/page.tsx +0 -658
  292. package/packages/dashboard/ui/app/layout.tsx +0 -25
  293. package/packages/dashboard/ui/app/login/page.tsx +0 -424
  294. package/packages/dashboard/ui/app/metrics/page.tsx +0 -751
  295. package/packages/dashboard/ui/app/page.tsx +0 -59
  296. package/packages/dashboard/ui/app/pricing/page.tsx +0 -7
  297. package/packages/dashboard/ui/app/providers/page.tsx +0 -193
  298. package/packages/dashboard/ui/app/providers/setup/[provider]/ProviderSetupClient.tsx +0 -148
  299. package/packages/dashboard/ui/app/providers/setup/[provider]/constants.ts +0 -35
  300. package/packages/dashboard/ui/app/providers/setup/[provider]/page.tsx +0 -42
  301. package/packages/dashboard/ui/app/signup/page.tsx +0 -533
  302. package/packages/dashboard/ui/index.ts +0 -49
  303. package/packages/dashboard/ui/landing/LandingPage.tsx +0 -713
  304. package/packages/dashboard/ui/landing/PricingPage.tsx +0 -559
  305. package/packages/dashboard/ui/landing/index.ts +0 -6
  306. package/packages/dashboard/ui/landing/styles.css +0 -2850
  307. package/packages/dashboard/ui/lib/agent-merge.ts +0 -35
  308. package/packages/dashboard/ui/lib/api.ts +0 -1155
  309. package/packages/dashboard/ui/lib/cloudApi.ts +0 -877
  310. package/packages/dashboard/ui/lib/colors.ts +0 -218
  311. package/packages/dashboard/ui/lib/hierarchy.ts +0 -242
  312. package/packages/dashboard/ui/lib/stuckDetection.ts +0 -142
  313. package/packages/dashboard/ui/next-env.d.ts +0 -5
  314. package/packages/dashboard/ui/next.config.js +0 -41
  315. package/packages/dashboard/ui/package-lock.json +0 -2882
  316. package/packages/dashboard/ui/package.json +0 -33
  317. package/packages/dashboard/ui/postcss.config.js +0 -5
  318. package/packages/dashboard/ui/react-components/ActivityFeed.tsx +0 -216
  319. package/packages/dashboard/ui/react-components/AddWorkspaceModal.tsx +0 -170
  320. package/packages/dashboard/ui/react-components/AgentCard.tsx +0 -587
  321. package/packages/dashboard/ui/react-components/AgentList.tsx +0 -411
  322. package/packages/dashboard/ui/react-components/AgentProfilePanel.tsx +0 -564
  323. package/packages/dashboard/ui/react-components/App.tsx +0 -3033
  324. package/packages/dashboard/ui/react-components/BillingPanel.tsx +0 -922
  325. package/packages/dashboard/ui/react-components/BillingResult.tsx +0 -447
  326. package/packages/dashboard/ui/react-components/BroadcastComposer.tsx +0 -690
  327. package/packages/dashboard/ui/react-components/ChannelAdminPanel.tsx +0 -773
  328. package/packages/dashboard/ui/react-components/ChannelBrowser.tsx +0 -385
  329. package/packages/dashboard/ui/react-components/ChannelChat.tsx +0 -261
  330. package/packages/dashboard/ui/react-components/ChannelSidebar.tsx +0 -399
  331. package/packages/dashboard/ui/react-components/CloudSessionProvider.tsx +0 -130
  332. package/packages/dashboard/ui/react-components/CommandPalette.tsx +0 -815
  333. package/packages/dashboard/ui/react-components/ConfirmationDialog.tsx +0 -133
  334. package/packages/dashboard/ui/react-components/ConversationHistory.tsx +0 -518
  335. package/packages/dashboard/ui/react-components/CoordinatorPanel.tsx +0 -944
  336. package/packages/dashboard/ui/react-components/DecisionQueue.tsx +0 -717
  337. package/packages/dashboard/ui/react-components/DirectMessageView.tsx +0 -164
  338. package/packages/dashboard/ui/react-components/FileAutocomplete.tsx +0 -368
  339. package/packages/dashboard/ui/react-components/FleetOverview.tsx +0 -278
  340. package/packages/dashboard/ui/react-components/LogViewer.tsx +0 -310
  341. package/packages/dashboard/ui/react-components/LogViewerPanel.tsx +0 -482
  342. package/packages/dashboard/ui/react-components/Logo.tsx +0 -284
  343. package/packages/dashboard/ui/react-components/MentionAutocomplete.tsx +0 -384
  344. package/packages/dashboard/ui/react-components/MessageComposer.tsx +0 -457
  345. package/packages/dashboard/ui/react-components/MessageList.tsx +0 -649
  346. package/packages/dashboard/ui/react-components/MessageSenderName.tsx +0 -91
  347. package/packages/dashboard/ui/react-components/MessageStatusIndicator.tsx +0 -142
  348. package/packages/dashboard/ui/react-components/NewConversationModal.tsx +0 -400
  349. package/packages/dashboard/ui/react-components/NotificationToast.tsx +0 -488
  350. package/packages/dashboard/ui/react-components/OnlineUsersIndicator.tsx +0 -164
  351. package/packages/dashboard/ui/react-components/Pagination.tsx +0 -124
  352. package/packages/dashboard/ui/react-components/PricingPlans.tsx +0 -386
  353. package/packages/dashboard/ui/react-components/ProjectList.tsx +0 -625
  354. package/packages/dashboard/ui/react-components/ProviderAuthFlow.tsx +0 -853
  355. package/packages/dashboard/ui/react-components/ProviderConnectionList.tsx +0 -378
  356. package/packages/dashboard/ui/react-components/ProvisioningProgress.tsx +0 -730
  357. package/packages/dashboard/ui/react-components/RepoAccessPanel.tsx +0 -549
  358. package/packages/dashboard/ui/react-components/ServerCard.tsx +0 -202
  359. package/packages/dashboard/ui/react-components/SessionExpiredModal.tsx +0 -128
  360. package/packages/dashboard/ui/react-components/SpawnModal.tsx +0 -804
  361. package/packages/dashboard/ui/react-components/TaskAssignmentUI.tsx +0 -375
  362. package/packages/dashboard/ui/react-components/TerminalProviderSetup.tsx +0 -608
  363. package/packages/dashboard/ui/react-components/ThemeProvider.tsx +0 -325
  364. package/packages/dashboard/ui/react-components/ThinkingIndicator.tsx +0 -231
  365. package/packages/dashboard/ui/react-components/ThreadList.tsx +0 -198
  366. package/packages/dashboard/ui/react-components/ThreadPanel.tsx +0 -346
  367. package/packages/dashboard/ui/react-components/TrajectoryViewer.tsx +0 -698
  368. package/packages/dashboard/ui/react-components/TypingIndicator.tsx +0 -69
  369. package/packages/dashboard/ui/react-components/UsageBanner.tsx +0 -231
  370. package/packages/dashboard/ui/react-components/UserProfilePanel.tsx +0 -233
  371. package/packages/dashboard/ui/react-components/WorkspaceContext.tsx +0 -107
  372. package/packages/dashboard/ui/react-components/WorkspaceSelector.tsx +0 -234
  373. package/packages/dashboard/ui/react-components/WorkspaceStatusIndicator.tsx +0 -370
  374. package/packages/dashboard/ui/react-components/XTermInteractive.tsx +0 -510
  375. package/packages/dashboard/ui/react-components/XTermLogViewer.tsx +0 -719
  376. package/packages/dashboard/ui/react-components/channels/ChannelDialogs.tsx +0 -1411
  377. package/packages/dashboard/ui/react-components/channels/ChannelHeader.tsx +0 -317
  378. package/packages/dashboard/ui/react-components/channels/ChannelMessageList.tsx +0 -463
  379. package/packages/dashboard/ui/react-components/channels/ChannelViewV1.tsx +0 -146
  380. package/packages/dashboard/ui/react-components/channels/MessageInput.tsx +0 -288
  381. package/packages/dashboard/ui/react-components/channels/SearchInput.tsx +0 -172
  382. package/packages/dashboard/ui/react-components/channels/SearchResults.tsx +0 -336
  383. package/packages/dashboard/ui/react-components/channels/api.ts +0 -697
  384. package/packages/dashboard/ui/react-components/channels/index.ts +0 -76
  385. package/packages/dashboard/ui/react-components/channels/mockApi.ts +0 -344
  386. package/packages/dashboard/ui/react-components/channels/types.ts +0 -566
  387. package/packages/dashboard/ui/react-components/hooks/index.ts +0 -57
  388. package/packages/dashboard/ui/react-components/hooks/useAgentLogs.ts +0 -394
  389. package/packages/dashboard/ui/react-components/hooks/useAgents.ts +0 -127
  390. package/packages/dashboard/ui/react-components/hooks/useBroadcastDedup.ts +0 -86
  391. package/packages/dashboard/ui/react-components/hooks/useChannelAdmin.ts +0 -329
  392. package/packages/dashboard/ui/react-components/hooks/useChannelBrowser.ts +0 -239
  393. package/packages/dashboard/ui/react-components/hooks/useChannelCommands.ts +0 -138
  394. package/packages/dashboard/ui/react-components/hooks/useChannels.ts +0 -328
  395. package/packages/dashboard/ui/react-components/hooks/useDebounce.ts +0 -29
  396. package/packages/dashboard/ui/react-components/hooks/useDirectMessage.ts +0 -141
  397. package/packages/dashboard/ui/react-components/hooks/useMessages.ts +0 -309
  398. package/packages/dashboard/ui/react-components/hooks/useOrchestrator.ts +0 -364
  399. package/packages/dashboard/ui/react-components/hooks/usePinnedAgents.ts +0 -140
  400. package/packages/dashboard/ui/react-components/hooks/usePresence.ts +0 -340
  401. package/packages/dashboard/ui/react-components/hooks/useRecentRepos.ts +0 -130
  402. package/packages/dashboard/ui/react-components/hooks/useSession.ts +0 -209
  403. package/packages/dashboard/ui/react-components/hooks/useTrajectory.ts +0 -265
  404. package/packages/dashboard/ui/react-components/hooks/useWebSocket.ts +0 -169
  405. package/packages/dashboard/ui/react-components/hooks/useWorkspaceMembers.ts +0 -120
  406. package/packages/dashboard/ui/react-components/hooks/useWorkspaceRepos.ts +0 -73
  407. package/packages/dashboard/ui/react-components/hooks/useWorkspaceStatus.ts +0 -237
  408. package/packages/dashboard/ui/react-components/index.ts +0 -81
  409. package/packages/dashboard/ui/react-components/layout/Header.tsx +0 -355
  410. package/packages/dashboard/ui/react-components/layout/RepoContextHeader.tsx +0 -361
  411. package/packages/dashboard/ui/react-components/layout/Sidebar.archive.test.tsx +0 -126
  412. package/packages/dashboard/ui/react-components/layout/Sidebar.test.tsx +0 -691
  413. package/packages/dashboard/ui/react-components/layout/Sidebar.tsx +0 -930
  414. package/packages/dashboard/ui/react-components/layout/index.ts +0 -7
  415. package/packages/dashboard/ui/react-components/settings/BillingSettingsPanel.tsx +0 -564
  416. package/packages/dashboard/ui/react-components/settings/SettingsPage.tsx +0 -544
  417. package/packages/dashboard/ui/react-components/settings/TeamSettingsPanel.tsx +0 -560
  418. package/packages/dashboard/ui/react-components/settings/WorkspaceSettingsPanel.tsx +0 -1386
  419. package/packages/dashboard/ui/react-components/settings/index.ts +0 -11
  420. package/packages/dashboard/ui/react-components/settings/types.ts +0 -53
  421. package/packages/dashboard/ui/react-components/utils/messageFormatting.tsx +0 -370
  422. package/packages/dashboard/ui/tailwind.config.js +0 -148
  423. package/packages/dashboard/ui/types/index.ts +0 -304
  424. package/packages/dashboard/ui/types/threading.ts +0 -7
  425. package/packages/dashboard/ui-dist/404.html +0 -1
  426. package/packages/dashboard/ui-dist/_next/static/91mkGYq3qbG8WHE6VytQ8/_buildManifest.js +0 -1
  427. package/packages/dashboard/ui-dist/_next/static/91mkGYq3qbG8WHE6VytQ8/_ssgManifest.js +0 -1
  428. package/packages/dashboard/ui-dist/_next/static/T2rV14eEU5OweDeV29SvG/_buildManifest.js +0 -1
  429. package/packages/dashboard/ui-dist/_next/static/T2rV14eEU5OweDeV29SvG/_ssgManifest.js +0 -1
  430. package/packages/dashboard/ui-dist/_next/static/chunks/116-a883fca163f3a5bc.js +0 -1
  431. package/packages/dashboard/ui-dist/_next/static/chunks/117-c8afed19e821a35d.js +0 -2
  432. package/packages/dashboard/ui-dist/_next/static/chunks/282-980c2eb8fff20123.js +0 -1
  433. package/packages/dashboard/ui-dist/_next/static/chunks/320-a6304232cd0ee2ce.js +0 -1
  434. package/packages/dashboard/ui-dist/_next/static/chunks/532-bace199897eeab37.js +0 -9
  435. package/packages/dashboard/ui-dist/_next/static/chunks/631-16b905e5920f9b59.js +0 -1
  436. package/packages/dashboard/ui-dist/_next/static/chunks/648-acb2ff9f77cbfbd3.js +0 -1
  437. package/packages/dashboard/ui-dist/_next/static/chunks/766-2aea80818f7eb0d8.js +0 -1
  438. package/packages/dashboard/ui-dist/_next/static/chunks/83-26d2bde54616ee90.js +0 -1
  439. package/packages/dashboard/ui-dist/_next/static/chunks/847-f1f467060f32afff.js +0 -1
  440. package/packages/dashboard/ui-dist/_next/static/chunks/891-5cb1513eeb97a891.js +0 -1
  441. package/packages/dashboard/ui-dist/_next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +0 -1
  442. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/onboarding/page-9914652442f7e4fb.js +0 -1
  443. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js +0 -1
  444. package/packages/dashboard/ui-dist/_next/static/chunks/app/cloud/link/page-fa1d5842aa90e8a6.js +0 -1
  445. package/packages/dashboard/ui-dist/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +0 -1
  446. package/packages/dashboard/ui-dist/_next/static/chunks/app/connect-repos/page-113060009ef35bc2.js +0 -1
  447. package/packages/dashboard/ui-dist/_next/static/chunks/app/history/page-9965d2483011b846.js +0 -1
  448. package/packages/dashboard/ui-dist/_next/static/chunks/app/layout-6b91e33784c20610.js +0 -1
  449. package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-435eceb0073be027.js +0 -1
  450. package/packages/dashboard/ui-dist/_next/static/chunks/app/metrics/page-1e37ef8e73940b40.js +0 -1
  451. package/packages/dashboard/ui-dist/_next/static/chunks/app/page-8119d4246743574e.js +0 -1
  452. package/packages/dashboard/ui-dist/_next/static/chunks/app/pricing/page-9db3ebdfa567a7c9.js +0 -1
  453. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +0 -1
  454. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/setup/[provider]/page-4dbe33f0f7691b7c.js +0 -1
  455. package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +0 -1
  456. package/packages/dashboard/ui-dist/_next/static/chunks/e868780c-48e5f147c90a3a41.js +0 -18
  457. package/packages/dashboard/ui-dist/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +0 -1
  458. package/packages/dashboard/ui-dist/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
  459. package/packages/dashboard/ui-dist/_next/static/chunks/main-311c3db74dcfadb7.js +0 -1
  460. package/packages/dashboard/ui-dist/_next/static/chunks/main-app-fdbeb09028f57c9f.js +0 -1
  461. package/packages/dashboard/ui-dist/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
  462. package/packages/dashboard/ui-dist/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
  463. package/packages/dashboard/ui-dist/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  464. package/packages/dashboard/ui-dist/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +0 -1
  465. package/packages/dashboard/ui-dist/_next/static/css/4034f236dd1a3178.css +0 -1
  466. package/packages/dashboard/ui-dist/_next/static/css/6892f8422896ef7a.css +0 -1
  467. package/packages/dashboard/ui-dist/_next/static/l8L2OscDSR2vsMIlWcC48/_buildManifest.js +0 -1
  468. package/packages/dashboard/ui-dist/_next/static/l8L2OscDSR2vsMIlWcC48/_ssgManifest.js +0 -1
  469. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-128.png +0 -0
  470. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-256.png +0 -0
  471. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-32.png +0 -0
  472. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-512.png +0 -0
  473. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-64.png +0 -0
  474. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo.svg +0 -45
  475. package/packages/dashboard/ui-dist/alt-logos/logo.svg +0 -38
  476. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-128.png +0 -0
  477. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-256.png +0 -0
  478. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-32.png +0 -0
  479. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-512.png +0 -0
  480. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-64.png +0 -0
  481. package/packages/dashboard/ui-dist/alt-logos/monogram-logo.svg +0 -38
  482. package/packages/dashboard/ui-dist/app/onboarding.html +0 -1
  483. package/packages/dashboard/ui-dist/app/onboarding.txt +0 -7
  484. package/packages/dashboard/ui-dist/app.html +0 -1
  485. package/packages/dashboard/ui-dist/app.txt +0 -7
  486. package/packages/dashboard/ui-dist/apple-icon.png +0 -0
  487. package/packages/dashboard/ui-dist/cloud/link.html +0 -1
  488. package/packages/dashboard/ui-dist/cloud/link.txt +0 -7
  489. package/packages/dashboard/ui-dist/complete-profile.html +0 -5
  490. package/packages/dashboard/ui-dist/complete-profile.txt +0 -7
  491. package/packages/dashboard/ui-dist/connect-repos.html +0 -1
  492. package/packages/dashboard/ui-dist/connect-repos.txt +0 -7
  493. package/packages/dashboard/ui-dist/history.html +0 -1
  494. package/packages/dashboard/ui-dist/history.txt +0 -7
  495. package/packages/dashboard/ui-dist/index.html +0 -1
  496. package/packages/dashboard/ui-dist/index.txt +0 -7
  497. package/packages/dashboard/ui-dist/login.html +0 -5
  498. package/packages/dashboard/ui-dist/login.txt +0 -7
  499. package/packages/dashboard/ui-dist/metrics.html +0 -1
  500. package/packages/dashboard/ui-dist/metrics.txt +0 -7
  501. package/packages/dashboard/ui-dist/pricing.html +0 -13
  502. package/packages/dashboard/ui-dist/pricing.txt +0 -7
  503. package/packages/dashboard/ui-dist/providers/setup/claude.html +0 -1
  504. package/packages/dashboard/ui-dist/providers/setup/claude.txt +0 -8
  505. package/packages/dashboard/ui-dist/providers/setup/codex.html +0 -1
  506. package/packages/dashboard/ui-dist/providers/setup/codex.txt +0 -8
  507. package/packages/dashboard/ui-dist/providers/setup/cursor.html +0 -1
  508. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +0 -8
  509. package/packages/dashboard/ui-dist/providers.html +0 -1
  510. package/packages/dashboard/ui-dist/providers.txt +0 -7
  511. package/packages/dashboard/ui-dist/signup.html +0 -6
  512. package/packages/dashboard/ui-dist/signup.txt +0 -7
  513. package/packages/dashboard-server/dist/health-worker-manager.d.ts +0 -62
  514. package/packages/dashboard-server/dist/health-worker-manager.js +0 -144
  515. package/packages/dashboard-server/dist/health-worker.d.ts +0 -9
  516. package/packages/dashboard-server/dist/health-worker.js +0 -79
  517. package/packages/dashboard-server/dist/index.d.ts +0 -18
  518. package/packages/dashboard-server/dist/index.js +0 -17
  519. package/packages/dashboard-server/dist/metrics.d.ts +0 -105
  520. package/packages/dashboard-server/dist/metrics.js +0 -193
  521. package/packages/dashboard-server/dist/needs-attention.d.ts +0 -24
  522. package/packages/dashboard-server/dist/needs-attention.js +0 -78
  523. package/packages/dashboard-server/dist/server.d.ts +0 -25
  524. package/packages/dashboard-server/dist/server.js +0 -5158
  525. package/packages/dashboard-server/dist/start.d.ts +0 -6
  526. package/packages/dashboard-server/dist/start.js +0 -13
  527. package/packages/dashboard-server/dist/types/threading.d.ts +0 -8
  528. package/packages/dashboard-server/dist/types/threading.js +0 -2
  529. package/packages/dashboard-server/dist/user-bridge.d.ts +0 -158
  530. package/packages/dashboard-server/dist/user-bridge.js +0 -390
  531. package/packages/dashboard-server/package.json +0 -55
  532. package/scripts/run-migrations.js +0 -43
  533. package/scripts/setup-stripe-products.ts +0 -312
  534. package/scripts/verify-schema.js +0 -134
@@ -1,1386 +0,0 @@
1
- /**
2
- * Workspace Settings Panel
3
- *
4
- * Manage workspace configuration including repositories,
5
- * AI providers, custom domains, and agent policies.
6
- *
7
- * Design: Mission Control theme with deep space aesthetic
8
- */
9
-
10
- import React, { useState, useEffect, useCallback } from 'react';
11
- import { cloudApi } from '../../lib/cloudApi';
12
- import { ProviderAuthFlow } from '../ProviderAuthFlow';
13
- import { TerminalProviderSetup } from '../TerminalProviderSetup';
14
- import { RepoAccessPanel } from '../RepoAccessPanel';
15
-
16
- export interface WorkspaceSettingsPanelProps {
17
- workspaceId: string;
18
- csrfToken?: string;
19
- onClose?: () => void;
20
- }
21
-
22
- interface WorkspaceDetails {
23
- id: string;
24
- name: string;
25
- status: string;
26
- publicUrl?: string;
27
- computeProvider: string;
28
- config: {
29
- providers: string[];
30
- repositories: string[];
31
- supervisorEnabled?: boolean;
32
- maxAgents?: number;
33
- };
34
- customDomain?: string;
35
- customDomainStatus?: string;
36
- errorMessage?: string;
37
- repositories: Array<{
38
- id: string;
39
- fullName: string;
40
- syncStatus: string;
41
- lastSyncedAt?: string;
42
- }>;
43
- createdAt: string;
44
- updatedAt: string;
45
- }
46
-
47
- interface AvailableRepo {
48
- id: string;
49
- fullName: string;
50
- isPrivate: boolean;
51
- defaultBranch: string;
52
- syncStatus: string;
53
- hasNangoConnection: boolean;
54
- lastSyncedAt?: string;
55
- }
56
-
57
- interface AIProvider {
58
- id: string;
59
- name: string;
60
- displayName: string;
61
- description: string;
62
- color: string;
63
- cliCommand: string;
64
- apiKeyUrl?: string;
65
- apiKeyName?: string;
66
- supportsOAuth?: boolean;
67
- supportsDeviceFlow?: boolean; // Provider supports device flow (easier for headless environments)
68
- preferApiKey?: boolean; // Show API key input by default (simpler for mobile/containers)
69
- isConnected?: boolean;
70
- comingSoon?: boolean; // Provider is not yet fully tested/available
71
- }
72
-
73
- const AI_PROVIDERS: AIProvider[] = [
74
- {
75
- id: 'anthropic',
76
- name: 'anthropic', // Must be lowercase to match backend validation
77
- displayName: 'Claude',
78
- description: 'Claude Code - recommended for code tasks',
79
- color: '#D97757',
80
- cliCommand: 'claude',
81
- apiKeyUrl: 'https://console.anthropic.com/settings/keys',
82
- apiKeyName: 'API key',
83
- supportsOAuth: true,
84
- },
85
- {
86
- id: 'codex',
87
- name: 'openai', // Must be lowercase to match backend validation
88
- displayName: 'Codex',
89
- description: 'Codex - OpenAI coding assistant',
90
- color: '#10A37F',
91
- cliCommand: 'codex login',
92
- apiKeyUrl: 'https://platform.openai.com/api-keys',
93
- apiKeyName: 'API key',
94
- supportsOAuth: true,
95
- supportsDeviceFlow: true, // Codex supports --device-auth for headless environments
96
- },
97
- {
98
- id: 'google',
99
- name: 'google', // Must be lowercase to match backend validation
100
- displayName: 'Gemini',
101
- description: 'Gemini - Google AI coding assistant',
102
- color: '#4285F4',
103
- cliCommand: 'gemini',
104
- // No apiKeyUrl - Gemini uses interactive terminal where user can choose OAuth or API key
105
- supportsOAuth: true,
106
- },
107
- {
108
- id: 'opencode',
109
- name: 'opencode', // Must be lowercase to match backend validation
110
- displayName: 'OpenCode',
111
- description: 'OpenCode - AI coding assistant',
112
- color: '#00D4AA',
113
- cliCommand: 'opencode',
114
- supportsOAuth: true,
115
- comingSoon: true, // Not yet fully tested
116
- },
117
- {
118
- id: 'droid',
119
- name: 'factory', // Must be lowercase to match backend validation
120
- displayName: 'Droid',
121
- description: 'Droid - Factory AI coding agent',
122
- color: '#6366F1',
123
- cliCommand: 'droid',
124
- supportsOAuth: true,
125
- comingSoon: true, // Not yet fully tested
126
- },
127
- {
128
- id: 'cursor',
129
- name: 'cursor', // Must be lowercase to match backend validation
130
- displayName: 'Cursor',
131
- description: 'Cursor - AI-first code editor agent',
132
- color: '#7C3AED',
133
- cliCommand: 'agent',
134
- supportsOAuth: true,
135
- },
136
- ];
137
-
138
- export function WorkspaceSettingsPanel({
139
- workspaceId,
140
- csrfToken,
141
- onClose,
142
- }: WorkspaceSettingsPanelProps) {
143
- const [workspace, setWorkspace] = useState<WorkspaceDetails | null>(null);
144
- const [availableRepos, setAvailableRepos] = useState<AvailableRepo[]>([]);
145
- const [isLoading, setIsLoading] = useState(true);
146
- const [error, setError] = useState<string | null>(null);
147
- const [activeSection, setActiveSection] = useState<'general' | 'providers' | 'repos' | 'github-access' | 'domain' | 'danger'>('general');
148
-
149
- // Provider connection state
150
- const [providerStatus, setProviderStatus] = useState<Record<string, boolean>>({});
151
- const [connectingProvider, setConnectingProvider] = useState<string | null>(null);
152
- const [apiKeyInput, setApiKeyInput] = useState('');
153
- const [providerError, setProviderError] = useState<string | null>(null);
154
- const [showApiKeyFallback, setShowApiKeyFallback] = useState<Record<string, boolean>>({});
155
- // Device flow preference for providers that support it
156
- const [useDeviceFlow, setUseDeviceFlow] = useState<Record<string, boolean>>({});
157
- // Use terminal-based setup (default for Claude, Cursor, and Gemini - Codex uses CLI helper flow)
158
- const [useTerminalSetup, setUseTerminalSetup] = useState<Record<string, boolean>>({
159
- anthropic: true, // Default to terminal for Claude
160
- cursor: true, // Default to terminal for Cursor
161
- google: true, // Default to terminal for Gemini - allows choosing OAuth or API key
162
- });
163
-
164
- // Provider disconnection state
165
- const [disconnectingProvider, setDisconnectingProvider] = useState<string | null>(null);
166
-
167
- // Repo sync state
168
- const [syncingRepoId, setSyncingRepoId] = useState<string | null>(null);
169
-
170
- // Custom domain form
171
- const [customDomain, setCustomDomain] = useState('');
172
- const [domainLoading, setDomainLoading] = useState(false);
173
- const [domainError, setDomainError] = useState<string | null>(null);
174
- const [domainInstructions, setDomainInstructions] = useState<{
175
- type: string;
176
- name: string;
177
- value: string;
178
- ttl: number;
179
- } | null>(null);
180
-
181
- // Load workspace details
182
- useEffect(() => {
183
- async function loadWorkspace() {
184
- setIsLoading(true);
185
- setError(null);
186
-
187
- const [wsResult, reposResult, providersResult] = await Promise.all([
188
- cloudApi.getWorkspaceDetails(workspaceId),
189
- cloudApi.getRepos(),
190
- cloudApi.getProviders(workspaceId),
191
- ]);
192
-
193
- if (wsResult.success) {
194
- setWorkspace(wsResult.data);
195
- if (wsResult.data.customDomain) {
196
- setCustomDomain(wsResult.data.customDomain);
197
- }
198
- } else {
199
- setError(wsResult.error);
200
- }
201
-
202
- if (reposResult.success) {
203
- setAvailableRepos(reposResult.data.repositories);
204
- }
205
-
206
- // Mark connected providers for this workspace
207
- if (providersResult.success) {
208
- // Map backend IDs to frontend IDs for consistency
209
- const BACKEND_TO_FRONTEND_MAP: Record<string, string> = {
210
- openai: 'codex', // Backend stores 'openai', frontend uses 'codex'
211
- };
212
- const connected: Record<string, boolean> = {};
213
- providersResult.data.providers.forEach((p) => {
214
- if (p.isConnected) {
215
- connected[p.id] = true;
216
- // Also mark the frontend ID as connected if there's a mapping
217
- const frontendId = BACKEND_TO_FRONTEND_MAP[p.id];
218
- if (frontendId) {
219
- connected[frontendId] = true;
220
- }
221
- }
222
- });
223
- setProviderStatus(connected);
224
- }
225
-
226
- setIsLoading(false);
227
- }
228
-
229
- loadWorkspace();
230
- }, [workspaceId]);
231
-
232
- // Start CLI-based OAuth flow for a provider
233
- // This just sets state to show the ProviderAuthFlow component, which handles the actual auth
234
- const startOAuthFlow = (provider: AIProvider) => {
235
- setProviderError(null);
236
- setConnectingProvider(provider.id);
237
- // ProviderAuthFlow will handle the rest when it mounts
238
- };
239
-
240
- // Disconnect a provider
241
- const handleDisconnectProvider = useCallback(async (provider: AIProvider) => {
242
- const confirmed = window.confirm(
243
- `Are you sure you want to disconnect ${provider.displayName}? This will remove the authentication and delete credential files from the workspace.`
244
- );
245
- if (!confirmed) return;
246
-
247
- setDisconnectingProvider(provider.id);
248
- setProviderError(null);
249
-
250
- try {
251
- const result = await cloudApi.disconnectProvider(provider.id, workspaceId);
252
- if (result.success) {
253
- setProviderStatus(prev => {
254
- const updated = { ...prev };
255
- delete updated[provider.id];
256
- return updated;
257
- });
258
- } else {
259
- setProviderError(result.error);
260
- }
261
- } catch (err) {
262
- setProviderError(err instanceof Error ? err.message : 'Failed to disconnect provider');
263
- } finally {
264
- setDisconnectingProvider(null);
265
- }
266
- }, [workspaceId]);
267
-
268
- const submitApiKey = async (provider: AIProvider) => {
269
- if (!apiKeyInput.trim()) {
270
- setProviderError('Please enter an API key');
271
- return;
272
- }
273
-
274
- setProviderError(null);
275
- setConnectingProvider(provider.id);
276
-
277
- try {
278
- const headers: Record<string, string> = { 'Content-Type': 'application/json' };
279
- if (csrfToken) headers['X-CSRF-Token'] = csrfToken;
280
-
281
- const res = await fetch(`/api/onboarding/token/${provider.id}`, {
282
- method: 'POST',
283
- credentials: 'include',
284
- headers,
285
- body: JSON.stringify({ token: apiKeyInput.trim(), workspaceId }),
286
- });
287
-
288
- if (!res.ok) {
289
- const data = await res.json();
290
- throw new Error(data.error || 'Failed to connect');
291
- }
292
-
293
- setProviderStatus(prev => ({ ...prev, [provider.id]: true }));
294
- setApiKeyInput('');
295
- setConnectingProvider(null);
296
- setShowApiKeyFallback(prev => ({ ...prev, [provider.id]: false }));
297
- } catch (err) {
298
- setProviderError(err instanceof Error ? err.message : 'Failed to connect');
299
- setConnectingProvider(null);
300
- }
301
- };
302
-
303
- // Restart workspace
304
- const handleRestart = useCallback(async () => {
305
- if (!workspace) return;
306
-
307
- const confirmed = window.confirm('Are you sure you want to restart this workspace?');
308
- if (!confirmed) return;
309
-
310
- const result = await cloudApi.restartWorkspace(workspace.id);
311
- if (result.success) {
312
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
313
- if (wsResult.success) {
314
- setWorkspace(wsResult.data);
315
- }
316
- } else {
317
- setError(result.error);
318
- }
319
- }, [workspace, workspaceId]);
320
-
321
- // Stop workspace
322
- const handleStop = useCallback(async () => {
323
- if (!workspace) return;
324
-
325
- const confirmed = window.confirm('Are you sure you want to stop this workspace?');
326
- if (!confirmed) return;
327
-
328
- const result = await cloudApi.stopWorkspace(workspace.id);
329
- if (result.success) {
330
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
331
- if (wsResult.success) {
332
- setWorkspace(wsResult.data);
333
- }
334
- } else {
335
- setError(result.error);
336
- }
337
- }, [workspace, workspaceId]);
338
-
339
- // Add repository to workspace
340
- const handleAddRepo = useCallback(async (repoId: string) => {
341
- if (!workspace) return;
342
-
343
- const result = await cloudApi.addReposToWorkspace(workspace.id, [repoId]);
344
- if (result.success) {
345
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
346
- if (wsResult.success) {
347
- setWorkspace(wsResult.data);
348
- }
349
- } else {
350
- setError(result.error);
351
- }
352
- }, [workspace, workspaceId]);
353
-
354
- // Sync repository to workspace (clone/pull)
355
- const handleSyncRepo = useCallback(async (repoId: string) => {
356
- if (!workspace) return;
357
-
358
- setSyncingRepoId(repoId);
359
- setError(null);
360
-
361
- const result = await cloudApi.syncRepo(repoId);
362
- if (result.success) {
363
- // Refresh workspace to get updated sync status
364
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
365
- if (wsResult.success) {
366
- setWorkspace(wsResult.data);
367
- }
368
- } else {
369
- setError(result.error);
370
- }
371
-
372
- setSyncingRepoId(null);
373
- }, [workspace, workspaceId]);
374
-
375
- // Set custom domain
376
- const handleSetDomain = useCallback(async () => {
377
- if (!workspace || !customDomain.trim()) return;
378
-
379
- setDomainLoading(true);
380
- setDomainError(null);
381
- setDomainInstructions(null);
382
-
383
- const result = await cloudApi.setCustomDomain(workspace.id, customDomain.trim());
384
- if (result.success) {
385
- setDomainInstructions(result.data.instructions);
386
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
387
- if (wsResult.success) {
388
- setWorkspace(wsResult.data);
389
- }
390
- } else {
391
- setDomainError(result.error);
392
- }
393
-
394
- setDomainLoading(false);
395
- }, [workspace, customDomain, workspaceId]);
396
-
397
- // Verify custom domain
398
- const handleVerifyDomain = useCallback(async () => {
399
- if (!workspace) return;
400
-
401
- setDomainLoading(true);
402
- setDomainError(null);
403
-
404
- const result = await cloudApi.verifyCustomDomain(workspace.id);
405
- if (result.success) {
406
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
407
- if (wsResult.success) {
408
- setWorkspace(wsResult.data);
409
- }
410
- if (result.data.status === 'active') {
411
- setDomainInstructions(null);
412
- }
413
- } else {
414
- setDomainError(result.error);
415
- }
416
-
417
- setDomainLoading(false);
418
- }, [workspace, workspaceId]);
419
-
420
- // Remove custom domain
421
- const handleRemoveDomain = useCallback(async () => {
422
- if (!workspace) return;
423
-
424
- const confirmed = window.confirm('Are you sure you want to remove the custom domain?');
425
- if (!confirmed) return;
426
-
427
- setDomainLoading(true);
428
- const result = await cloudApi.removeCustomDomain(workspace.id);
429
- if (result.success) {
430
- setCustomDomain('');
431
- setDomainInstructions(null);
432
- const wsResult = await cloudApi.getWorkspaceDetails(workspaceId);
433
- if (wsResult.success) {
434
- setWorkspace(wsResult.data);
435
- }
436
- } else {
437
- setDomainError(result.error);
438
- }
439
- setDomainLoading(false);
440
- }, [workspace, workspaceId]);
441
-
442
- // Delete workspace
443
- const handleDelete = useCallback(async () => {
444
- if (!workspace) return;
445
-
446
- const confirmed = window.confirm(
447
- `Are you sure you want to delete "${workspace.name}"? This action cannot be undone.`
448
- );
449
- if (!confirmed) return;
450
-
451
- const doubleConfirm = window.confirm(
452
- 'This will permanently delete all workspace data. Are you absolutely sure?'
453
- );
454
- if (!doubleConfirm) return;
455
-
456
- const result = await cloudApi.deleteWorkspace(workspace.id);
457
- if (result.success) {
458
- // Redirect to onboarding page with deleted reason
459
- window.location.href = '/app/onboarding?reason=deleted';
460
- } else {
461
- setError(result.error);
462
- }
463
- }, [workspace]);
464
-
465
- if (isLoading) {
466
- return (
467
- <div className="flex items-center justify-center h-64">
468
- <div className="relative">
469
- <div className="w-12 h-12 rounded-full border-2 border-accent-cyan/20 border-t-accent-cyan animate-spin" />
470
- <div className="absolute inset-0 flex items-center justify-center">
471
- <div className="w-4 h-4 rounded-full bg-accent-cyan/40 animate-pulse" />
472
- </div>
473
- </div>
474
- <span className="ml-4 text-text-muted font-mono text-sm tracking-wide">
475
- LOADING WORKSPACE CONFIG...
476
- </span>
477
- </div>
478
- );
479
- }
480
-
481
- if (error && !workspace) {
482
- return (
483
- <div className="p-6">
484
- <div className="p-4 bg-error/10 border border-error/30 rounded-lg text-error flex items-center gap-3">
485
- <AlertIcon />
486
- <span>{error}</span>
487
- </div>
488
- </div>
489
- );
490
- }
491
-
492
- if (!workspace) {
493
- return null;
494
- }
495
-
496
- const unassignedRepos = availableRepos.filter(
497
- (r) => !workspace.repositories.some((wr) => wr.id === r.id)
498
- );
499
-
500
- const sections = [
501
- { id: 'general', label: 'General', icon: <SettingsGearIcon /> },
502
- { id: 'providers', label: 'AI Providers', icon: <ProviderIcon /> },
503
- { id: 'repos', label: 'Repositories', icon: <RepoIcon /> },
504
- { id: 'github-access', label: 'GitHub Access', icon: <GitHubIcon /> },
505
- { id: 'domain', label: 'Domain', icon: <GlobeIcon /> },
506
- { id: 'danger', label: 'Danger', icon: <AlertIcon /> },
507
- ];
508
-
509
- return (
510
- <div className="flex flex-col h-full bg-bg-primary">
511
- {/* Section Navigation - horizontally scrollable on mobile */}
512
- <div
513
- className="flex gap-1 p-2 sm:p-3 border-b border-border-subtle bg-gradient-to-b from-bg-tertiary to-bg-primary overflow-x-auto scrollbar-hide scroll-smooth snap-x snap-mandatory touch-pan-x"
514
- style={{ WebkitOverflowScrolling: 'touch' }}
515
- >
516
- {sections.map((section) => (
517
- <button
518
- key={section.id}
519
- onClick={() => setActiveSection(section.id as typeof activeSection)}
520
- className={`flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-2 sm:py-2.5 rounded-lg text-xs sm:text-sm font-medium transition-all duration-200 whitespace-nowrap shrink-0 snap-start ${
521
- activeSection === section.id
522
- ? 'bg-accent-cyan/15 text-accent-cyan border border-accent-cyan/30 shadow-[0_0_12px_rgba(0,217,255,0.15)]'
523
- : 'text-text-secondary hover:bg-bg-hover hover:text-text-primary border border-transparent'
524
- }`}
525
- >
526
- <span className={activeSection === section.id ? 'text-accent-cyan' : 'text-text-muted'}>
527
- {section.icon}
528
- </span>
529
- {section.label}
530
- </button>
531
- ))}
532
- </div>
533
-
534
- {/* Content */}
535
- <div className="flex-1 overflow-y-auto p-4 sm:p-6">
536
- {error && (
537
- <div className="mb-6 p-4 bg-error/10 border border-error/30 rounded-lg text-error text-sm flex items-center gap-3">
538
- <AlertIcon />
539
- <span className="flex-1">{error}</span>
540
- <button onClick={() => setError(null)} className="text-error/60 hover:text-error">
541
- <CloseIcon />
542
- </button>
543
- </div>
544
- )}
545
-
546
- {/* General Section */}
547
- {activeSection === 'general' && (
548
- <div className="space-y-8">
549
- <SectionHeader
550
- title="Workspace Overview"
551
- subtitle="Core configuration and status"
552
- />
553
-
554
- <div className="grid grid-cols-2 gap-4">
555
- <InfoCard label="Name" value={workspace.name} />
556
- <InfoCard
557
- label="Status"
558
- value={workspace.status.charAt(0).toUpperCase() + workspace.status.slice(1)}
559
- valueColor={
560
- workspace.status === 'running' ? 'text-success' :
561
- workspace.status === 'stopped' ? 'text-amber-400' :
562
- workspace.status === 'error' ? 'text-error' : 'text-text-muted'
563
- }
564
- indicator={workspace.status === 'running'}
565
- />
566
- <InfoCard
567
- label="Public URL"
568
- value={workspace.publicUrl || 'Not available'}
569
- mono
570
- />
571
- <InfoCard
572
- label="Compute Provider"
573
- value={workspace.computeProvider.charAt(0).toUpperCase() + workspace.computeProvider.slice(1)}
574
- />
575
- </div>
576
-
577
- <div>
578
- <SectionHeader title="Actions" subtitle="Manage workspace state" />
579
- <div className="flex gap-3 mt-4">
580
- {workspace.status === 'running' && (
581
- <ActionButton
582
- onClick={handleStop}
583
- variant="warning"
584
- icon={<StopIcon />}
585
- >
586
- Stop Workspace
587
- </ActionButton>
588
- )}
589
- <ActionButton
590
- onClick={handleRestart}
591
- variant="primary"
592
- icon={<RestartIcon />}
593
- >
594
- Restart Workspace
595
- </ActionButton>
596
- </div>
597
- </div>
598
- </div>
599
- )}
600
-
601
- {/* AI Providers Section */}
602
- {activeSection === 'providers' && (
603
- <div className="space-y-8">
604
- <SectionHeader
605
- title="AI Providers"
606
- subtitle="Connect AI providers to spawn agents in this workspace"
607
- />
608
-
609
- {providerError && (
610
- <div className="p-4 bg-error/10 border border-error/30 rounded-lg text-error text-sm flex items-center gap-3">
611
- <AlertIcon />
612
- <span>{providerError}</span>
613
- </div>
614
- )}
615
-
616
- <div className="space-y-4">
617
- {AI_PROVIDERS.map((provider) => (
618
- <div
619
- key={provider.id}
620
- className={`p-5 bg-bg-tertiary rounded-xl border border-border-subtle transition-all duration-200 ${
621
- provider.comingSoon ? 'opacity-60' : 'hover:border-border-medium'
622
- }`}
623
- >
624
- <div className="flex items-center justify-between">
625
- <div className="flex items-center gap-4">
626
- <div
627
- className={`w-12 h-12 rounded-xl flex items-center justify-center text-white font-bold text-lg shadow-lg ${
628
- provider.comingSoon ? 'grayscale' : ''
629
- }`}
630
- style={{
631
- backgroundColor: provider.color,
632
- boxShadow: provider.comingSoon ? 'none' : `0 4px 20px ${provider.color}40`,
633
- }}
634
- >
635
- {provider.displayName[0]}
636
- </div>
637
- <div>
638
- <h4 className="text-base font-semibold text-text-primary flex items-center gap-2">
639
- {provider.displayName}
640
- {provider.comingSoon && (
641
- <span className="px-2 py-0.5 bg-amber-400/20 text-amber-400 text-xs font-medium rounded-full">
642
- Coming Soon
643
- </span>
644
- )}
645
- </h4>
646
- <p className="text-sm text-text-muted">{provider.description}</p>
647
- </div>
648
- </div>
649
-
650
- {provider.comingSoon ? (
651
- <div className="px-4 py-2 bg-bg-card rounded-full border border-border-subtle">
652
- <span className="text-sm text-text-muted">Not available yet</span>
653
- </div>
654
- ) : providerStatus[provider.id] ? (
655
- <div className="flex items-center gap-3">
656
- <div className="flex items-center gap-2 px-4 py-2 bg-success/15 rounded-full border border-success/30">
657
- <div className="w-2 h-2 rounded-full bg-success animate-pulse" />
658
- <span className="text-sm font-medium text-success">Connected</span>
659
- </div>
660
- <button
661
- onClick={() => handleDisconnectProvider(provider)}
662
- disabled={disconnectingProvider === provider.id}
663
- className="px-3 py-2 text-xs font-medium text-error/80 hover:text-error hover:bg-error/10 rounded-lg border border-transparent hover:border-error/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
664
- title={`Disconnect ${provider.displayName}`}
665
- >
666
- {disconnectingProvider === provider.id ? 'Disconnecting...' : 'Disconnect'}
667
- </button>
668
- </div>
669
- ) : null}
670
- </div>
671
-
672
- {!providerStatus[provider.id] && !provider.comingSoon && (
673
- <div className="mt-5 pt-5 border-t border-border-subtle">
674
- {connectingProvider === provider.id && !showApiKeyFallback[provider.id] ? (
675
- useTerminalSetup[provider.id] ? (
676
- <TerminalProviderSetup
677
- provider={{
678
- id: provider.id,
679
- name: provider.name,
680
- displayName: provider.displayName,
681
- color: provider.color,
682
- }}
683
- workspaceId={workspaceId}
684
- csrfToken={csrfToken}
685
- maxHeight="350px"
686
- onSuccess={() => {
687
- setProviderStatus(prev => ({ ...prev, [provider.id]: true }));
688
- setConnectingProvider(null);
689
- }}
690
- onCancel={() => {
691
- setConnectingProvider(null);
692
- }}
693
- onError={(err) => {
694
- setProviderError(err);
695
- setConnectingProvider(null);
696
- }}
697
- onConnectAnother={() => {
698
- // Mark current provider as connected and clear selection
699
- // User can then click another provider to connect
700
- setProviderStatus(prev => ({ ...prev, [provider.id]: true }));
701
- setConnectingProvider(null);
702
- }}
703
- />
704
- ) : (
705
- <ProviderAuthFlow
706
- provider={{
707
- id: provider.id,
708
- name: provider.name,
709
- displayName: provider.displayName,
710
- color: provider.color,
711
- requiresUrlCopy: provider.id === 'codex',
712
- supportsDeviceFlow: provider.supportsDeviceFlow,
713
- }}
714
- workspaceId={workspaceId}
715
- csrfToken={csrfToken}
716
- useDeviceFlow={useDeviceFlow[provider.id] || false}
717
- onSuccess={() => {
718
- setProviderStatus(prev => ({ ...prev, [provider.id]: true }));
719
- setConnectingProvider(null);
720
- }}
721
- onCancel={() => {
722
- setConnectingProvider(null);
723
- }}
724
- onError={(err) => {
725
- setProviderError(err);
726
- setConnectingProvider(null);
727
- }}
728
- />
729
- )
730
- ) : showApiKeyFallback[provider.id] ? (
731
- <div className="space-y-4">
732
- <div className="flex gap-3">
733
- <input
734
- type="password"
735
- placeholder={`Enter ${provider.displayName} ${provider.apiKeyName || 'API key'}`}
736
- value={connectingProvider === provider.id ? apiKeyInput : ''}
737
- onChange={(e) => {
738
- setConnectingProvider(provider.id);
739
- setApiKeyInput(e.target.value);
740
- }}
741
- onFocus={() => setConnectingProvider(provider.id)}
742
- className="flex-1 px-4 py-3 bg-bg-card border border-border-subtle rounded-lg text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:border-accent-cyan focus:ring-1 focus:ring-accent-cyan/30 transition-all"
743
- />
744
- <button
745
- onClick={() => submitApiKey(provider)}
746
- disabled={connectingProvider !== provider.id || !apiKeyInput.trim()}
747
- className="px-5 py-3 bg-accent-cyan text-bg-deep font-semibold rounded-lg text-sm hover:bg-accent-cyan/90 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
748
- >
749
- Connect
750
- </button>
751
- </div>
752
- {provider.apiKeyUrl && (
753
- <p className="text-xs text-text-muted">
754
- Get your API key from{' '}
755
- <a
756
- href={provider.apiKeyUrl}
757
- target="_blank"
758
- rel="noopener noreferrer"
759
- className="text-accent-cyan hover:underline"
760
- >
761
- {new URL(provider.apiKeyUrl).hostname}
762
- </a>
763
- </p>
764
- )}
765
- {provider.supportsOAuth && (
766
- <button
767
- onClick={() => setShowApiKeyFallback(prev => ({ ...prev, [provider.id]: false }))}
768
- className="text-xs text-text-muted hover:text-text-secondary transition-colors"
769
- >
770
- ← Back to OAuth login
771
- </button>
772
- )}
773
- </div>
774
- ) : provider.supportsOAuth ? (
775
- <div className="space-y-3">
776
- {/* CLI info for Codex */}
777
- {provider.id === 'codex' && (
778
- <div className="p-3 bg-accent-cyan/10 border border-accent-cyan/30 rounded-lg">
779
- <p className="text-sm text-accent-cyan font-medium mb-1">CLI-assisted authentication</p>
780
- <p className="text-xs text-accent-cyan/80">
781
- Codex auth uses a CLI command to capture the OAuth callback locally.
782
- Click the button below and we&apos;ll show you a command with a unique session token
783
- to run in your terminal before signing in with OpenAI.
784
- </p>
785
- </div>
786
- )}
787
- {/* Device flow toggle for providers that support it */}
788
- {provider.supportsDeviceFlow && (
789
- <label className="flex items-center gap-2 text-xs text-text-secondary cursor-pointer">
790
- <input
791
- type="checkbox"
792
- checked={useDeviceFlow[provider.id] || false}
793
- onChange={(e) => setUseDeviceFlow(prev => ({
794
- ...prev,
795
- [provider.id]: e.target.checked,
796
- }))}
797
- className="w-4 h-4 rounded border-border-subtle bg-bg-card text-accent-cyan focus:ring-accent-cyan/30 cursor-pointer"
798
- />
799
- Use device flow (easier for containers/headless)
800
- </label>
801
- )}
802
- <button
803
- onClick={() => startOAuthFlow(provider)}
804
- disabled={connectingProvider !== null}
805
- className="w-full py-3 px-4 bg-gradient-to-r from-accent-cyan to-[#00b8d9] text-bg-deep font-semibold rounded-lg text-sm hover:shadow-glow-cyan hover:-translate-y-0.5 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:translate-y-0 disabled:hover:shadow-none transition-all duration-200 flex items-center justify-center gap-2"
806
- >
807
- <LockIcon />
808
- Connect with {provider.displayName}
809
- </button>
810
- {provider.apiKeyUrl && (
811
- <button
812
- onClick={() => setShowApiKeyFallback(prev => ({ ...prev, [provider.id]: true }))}
813
- className="w-full text-xs text-text-muted hover:text-text-secondary transition-colors"
814
- >
815
- Or enter API key manually
816
- </button>
817
- )}
818
- </div>
819
- ) : (
820
- /* Provider doesn't support OAuth - show API key input directly */
821
- <div className="space-y-4">
822
- <div className="flex gap-3">
823
- <input
824
- type="password"
825
- placeholder={`Enter ${provider.displayName} ${provider.apiKeyName || 'API key'}`}
826
- value={connectingProvider === provider.id ? apiKeyInput : ''}
827
- onChange={(e) => {
828
- setConnectingProvider(provider.id);
829
- setApiKeyInput(e.target.value);
830
- }}
831
- onFocus={() => setConnectingProvider(provider.id)}
832
- className="flex-1 px-4 py-3 bg-bg-card border border-border-subtle rounded-lg text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:border-accent-cyan focus:ring-1 focus:ring-accent-cyan/30 transition-all"
833
- />
834
- <button
835
- onClick={() => submitApiKey(provider)}
836
- disabled={connectingProvider !== provider.id || !apiKeyInput.trim()}
837
- className="px-5 py-3 bg-accent-cyan text-bg-deep font-semibold rounded-lg text-sm hover:bg-accent-cyan/90 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
838
- >
839
- Connect
840
- </button>
841
- </div>
842
- {provider.apiKeyUrl && (
843
- <p className="text-xs text-text-muted">
844
- Get your API key from{' '}
845
- <a
846
- href={provider.apiKeyUrl}
847
- target="_blank"
848
- rel="noopener noreferrer"
849
- className="text-accent-cyan hover:underline"
850
- >
851
- {new URL(provider.apiKeyUrl).hostname}
852
- </a>
853
- </p>
854
- )}
855
- <p className="text-xs text-amber-400/80">
856
- OAuth not available for {provider.displayName} in container environments
857
- </p>
858
- </div>
859
- )}
860
- </div>
861
- )}
862
-
863
- <div className="mt-4 pt-4 border-t border-border-subtle">
864
- <p className="text-xs text-text-muted">
865
- CLI: <code className="px-2 py-1 bg-bg-card rounded font-mono">{provider.cliCommand}</code>
866
- </p>
867
- </div>
868
- </div>
869
- ))}
870
- </div>
871
- </div>
872
- )}
873
-
874
- {/* Repositories Section */}
875
- {activeSection === 'repos' && (
876
- <div className="space-y-8">
877
- <SectionHeader
878
- title="Connected Repositories"
879
- subtitle="Repositories linked to this workspace"
880
- />
881
-
882
- <div className="space-y-3">
883
- {workspace.repositories.length > 0 ? (
884
- workspace.repositories.map((repo) => (
885
- <div
886
- key={repo.id}
887
- className="flex items-center justify-between p-4 bg-bg-tertiary rounded-lg border border-border-subtle"
888
- >
889
- <div className="flex items-center gap-3">
890
- <div className="w-10 h-10 rounded-lg bg-bg-card flex items-center justify-center">
891
- <RepoIcon />
892
- </div>
893
- <div>
894
- <p className="text-sm font-medium text-text-primary">{repo.fullName}</p>
895
- <p className="text-xs text-text-muted">
896
- {repo.lastSyncedAt
897
- ? `Synced ${new Date(repo.lastSyncedAt).toLocaleDateString()}`
898
- : 'Not synced'}
899
- </p>
900
- </div>
901
- </div>
902
- <div className="flex items-center gap-3">
903
- <button
904
- onClick={() => handleSyncRepo(repo.id)}
905
- disabled={syncingRepoId === repo.id || workspace.status !== 'running'}
906
- className="px-3 py-1.5 bg-accent-cyan/10 border border-accent-cyan/30 text-accent-cyan rounded-lg text-xs font-semibold hover:bg-accent-cyan/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-1.5"
907
- title={workspace.status !== 'running' ? 'Workspace must be running to sync' : 'Sync repository'}
908
- >
909
- {syncingRepoId === repo.id ? (
910
- <>
911
- <SyncIcon spinning />
912
- Syncing...
913
- </>
914
- ) : (
915
- <>
916
- <SyncIcon />
917
- Sync
918
- </>
919
- )}
920
- </button>
921
- <StatusBadge status={repo.syncStatus} />
922
- </div>
923
- </div>
924
- ))
925
- ) : (
926
- <div className="p-6 bg-bg-tertiary rounded-lg border border-border-subtle border-dashed text-center">
927
- <RepoIcon className="w-8 h-8 mx-auto mb-3 text-text-muted" />
928
- <p className="text-sm text-text-muted">No repositories connected</p>
929
- </div>
930
- )}
931
- </div>
932
-
933
- {unassignedRepos.length > 0 && (
934
- <>
935
- <SectionHeader
936
- title="Available Repositories"
937
- subtitle="Add more repositories to this workspace"
938
- />
939
- <div className="space-y-3">
940
- {unassignedRepos.map((repo) => (
941
- <div
942
- key={repo.id}
943
- className="flex items-center justify-between p-4 bg-bg-tertiary rounded-lg border border-border-subtle hover:border-accent-cyan/30 transition-colors"
944
- >
945
- <div className="flex items-center gap-3">
946
- <div className="w-10 h-10 rounded-lg bg-bg-card flex items-center justify-center">
947
- <RepoIcon />
948
- </div>
949
- <div>
950
- <p className="text-sm font-medium text-text-primary">{repo.fullName}</p>
951
- <p className="text-xs text-text-muted">
952
- {repo.isPrivate ? 'Private' : 'Public'}
953
- </p>
954
- </div>
955
- </div>
956
- <button
957
- onClick={() => handleAddRepo(repo.id)}
958
- className="px-4 py-2 bg-accent-cyan/10 border border-accent-cyan/30 text-accent-cyan rounded-lg text-xs font-semibold hover:bg-accent-cyan/20 transition-colors"
959
- >
960
- Add to Workspace
961
- </button>
962
- </div>
963
- ))}
964
- </div>
965
- </>
966
- )}
967
- </div>
968
- )}
969
-
970
- {/* GitHub Access Section */}
971
- {activeSection === 'github-access' && (
972
- <div className="space-y-6">
973
- <SectionHeader
974
- title="GitHub Repository Access"
975
- subtitle="Repositories you have access to via your GitHub account"
976
- />
977
- <RepoAccessPanel
978
- workspaces={
979
- workspace && workspace.repositories?.length > 0
980
- ? [{
981
- id: workspace.id,
982
- name: workspace.name,
983
- repositoryFullName: workspace.repositories[0].fullName,
984
- status: workspace.status as 'provisioning' | 'running' | 'stopped' | 'error',
985
- }]
986
- : []
987
- }
988
- onWorkspaceCreated={(workspaceId, repoFullName) => {
989
- // Refresh workspace data after creating
990
- cloudApi.getWorkspaceDetails(workspaceId).then(result => {
991
- if (result.success) {
992
- setWorkspace(result.data);
993
- }
994
- });
995
- }}
996
- onOpenWorkspace={(workspaceId) => {
997
- // Navigate to workspace or close settings
998
- if (onClose) {
999
- onClose();
1000
- }
1001
- }}
1002
- csrfToken={csrfToken}
1003
- className="bg-bg-tertiary rounded-xl border border-border-subtle overflow-hidden"
1004
- />
1005
- </div>
1006
- )}
1007
-
1008
- {/* Custom Domain Section */}
1009
- {activeSection === 'domain' && (
1010
- <div className="space-y-8">
1011
- <SectionHeader
1012
- title="Custom Domain"
1013
- subtitle="Connect your own domain to this workspace"
1014
- />
1015
-
1016
- <div className="p-5 bg-gradient-to-r from-accent-purple/10 to-accent-cyan/10 border border-accent-purple/20 rounded-xl">
1017
- <div className="flex items-center gap-3 mb-3">
1018
- <div className="w-10 h-10 rounded-lg bg-accent-purple/20 flex items-center justify-center">
1019
- <GlobeIcon className="text-accent-purple" />
1020
- </div>
1021
- <div>
1022
- <h4 className="text-sm font-semibold text-text-primary">Premium Feature</h4>
1023
- <p className="text-xs text-text-secondary">Requires Team or Enterprise plan</p>
1024
- </div>
1025
- </div>
1026
- </div>
1027
-
1028
- {workspace.customDomain ? (
1029
- <div className="space-y-4">
1030
- <div className="p-5 bg-bg-tertiary rounded-xl border border-border-subtle">
1031
- <div className="flex items-center justify-between mb-3">
1032
- <span className="text-xs text-text-muted uppercase tracking-wide font-semibold">
1033
- Current Domain
1034
- </span>
1035
- <StatusBadge status={workspace.customDomainStatus || 'pending'} />
1036
- </div>
1037
- <p className="text-lg font-mono text-text-primary">{workspace.customDomain}</p>
1038
- </div>
1039
-
1040
- {workspace.customDomainStatus === 'pending' && (
1041
- <ActionButton
1042
- onClick={handleVerifyDomain}
1043
- disabled={domainLoading}
1044
- variant="primary"
1045
- icon={<CheckIcon />}
1046
- fullWidth
1047
- >
1048
- {domainLoading ? 'Verifying...' : 'Verify DNS Configuration'}
1049
- </ActionButton>
1050
- )}
1051
-
1052
- <ActionButton
1053
- onClick={handleRemoveDomain}
1054
- disabled={domainLoading}
1055
- variant="danger"
1056
- icon={<TrashIcon />}
1057
- fullWidth
1058
- >
1059
- Remove Custom Domain
1060
- </ActionButton>
1061
- </div>
1062
- ) : (
1063
- <div className="space-y-4">
1064
- <div>
1065
- <label className="text-xs font-semibold text-text-muted uppercase tracking-wide mb-2 block">
1066
- Domain Name
1067
- </label>
1068
- <input
1069
- type="text"
1070
- value={customDomain}
1071
- onChange={(e) => setCustomDomain(e.target.value)}
1072
- placeholder="workspace.yourdomain.com"
1073
- className="w-full px-4 py-3 bg-bg-tertiary border border-border-subtle rounded-lg text-sm text-text-primary font-mono placeholder:text-text-muted focus:outline-none focus:border-accent-cyan focus:ring-1 focus:ring-accent-cyan/30 transition-all"
1074
- />
1075
- </div>
1076
-
1077
- <ActionButton
1078
- onClick={handleSetDomain}
1079
- disabled={domainLoading || !customDomain.trim()}
1080
- variant="primary"
1081
- icon={<GlobeIcon />}
1082
- fullWidth
1083
- >
1084
- {domainLoading ? 'Setting up...' : 'Set Custom Domain'}
1085
- </ActionButton>
1086
- </div>
1087
- )}
1088
-
1089
- {domainError && (
1090
- <div className="p-4 bg-error/10 border border-error/30 rounded-lg text-error text-sm">
1091
- {domainError}
1092
- </div>
1093
- )}
1094
-
1095
- {domainInstructions && (
1096
- <div className="p-5 bg-bg-tertiary rounded-xl border border-border-subtle space-y-4">
1097
- <h4 className="text-sm font-semibold text-text-primary flex items-center gap-2">
1098
- <InfoIcon />
1099
- DNS Configuration Required
1100
- </h4>
1101
- <p className="text-xs text-text-secondary">
1102
- Add the following DNS record to your domain provider:
1103
- </p>
1104
- <div className="grid grid-cols-3 gap-3">
1105
- <DNSField label="Type" value={domainInstructions.type} />
1106
- <DNSField label="Name" value={domainInstructions.name} />
1107
- <DNSField label="Value" value={domainInstructions.value} />
1108
- </div>
1109
- </div>
1110
- )}
1111
- </div>
1112
- )}
1113
-
1114
- {/* Danger Zone Section */}
1115
- {activeSection === 'danger' && (
1116
- <div className="space-y-8">
1117
- <div className="p-6 bg-error/5 border-2 border-error/20 rounded-xl">
1118
- <div className="flex items-center gap-3 mb-4">
1119
- <div className="w-10 h-10 rounded-lg bg-error/20 flex items-center justify-center">
1120
- <AlertIcon className="text-error" />
1121
- </div>
1122
- <div>
1123
- <h3 className="text-base font-semibold text-error">Danger Zone</h3>
1124
- <p className="text-xs text-text-secondary">
1125
- These actions are destructive and cannot be undone
1126
- </p>
1127
- </div>
1128
- </div>
1129
-
1130
- <div className="p-5 border border-error/30 rounded-lg bg-bg-primary">
1131
- <div className="flex items-center justify-between">
1132
- <div>
1133
- <h4 className="text-sm font-semibold text-text-primary">Delete Workspace</h4>
1134
- <p className="text-xs text-text-muted mt-1">
1135
- Permanently delete this workspace and all its data
1136
- </p>
1137
- </div>
1138
- <button
1139
- onClick={handleDelete}
1140
- className="px-5 py-2.5 bg-error text-white rounded-lg text-sm font-semibold hover:bg-error/90 transition-colors"
1141
- >
1142
- Delete Workspace
1143
- </button>
1144
- </div>
1145
- </div>
1146
- </div>
1147
- </div>
1148
- )}
1149
- </div>
1150
- </div>
1151
- );
1152
- }
1153
-
1154
- // Utility Components
1155
- function SectionHeader({ title, subtitle }: { title: string; subtitle: string }) {
1156
- return (
1157
- <div className="mb-4">
1158
- <h3 className="text-sm font-semibold text-text-muted uppercase tracking-wide">{title}</h3>
1159
- <p className="text-xs text-text-muted mt-1">{subtitle}</p>
1160
- </div>
1161
- );
1162
- }
1163
-
1164
- function InfoCard({
1165
- label,
1166
- value,
1167
- valueColor = 'text-text-primary',
1168
- mono = false,
1169
- indicator = false,
1170
- }: {
1171
- label: string;
1172
- value: string;
1173
- valueColor?: string;
1174
- mono?: boolean;
1175
- indicator?: boolean;
1176
- }) {
1177
- return (
1178
- <div className="p-4 bg-bg-tertiary rounded-lg border border-border-subtle">
1179
- <label className="text-xs text-text-muted uppercase tracking-wide font-medium">{label}</label>
1180
- <div className="flex items-center gap-2 mt-1">
1181
- {indicator && <div className="w-2 h-2 rounded-full bg-success animate-pulse" />}
1182
- <p className={`text-sm font-medium ${valueColor} ${mono ? 'font-mono' : ''} break-all`}>
1183
- {value}
1184
- </p>
1185
- </div>
1186
- </div>
1187
- );
1188
- }
1189
-
1190
- function ActionButton({
1191
- children,
1192
- onClick,
1193
- disabled,
1194
- variant,
1195
- icon,
1196
- fullWidth,
1197
- }: {
1198
- children: React.ReactNode;
1199
- onClick: () => void;
1200
- disabled?: boolean;
1201
- variant: 'primary' | 'warning' | 'danger';
1202
- icon?: React.ReactNode;
1203
- fullWidth?: boolean;
1204
- }) {
1205
- const variants = {
1206
- primary: 'bg-accent-cyan/10 border-accent-cyan/30 text-accent-cyan hover:bg-accent-cyan/20',
1207
- warning: 'bg-amber-400/10 border-amber-400/30 text-amber-400 hover:bg-amber-400/20',
1208
- danger: 'bg-error/10 border-error/30 text-error hover:bg-error/20',
1209
- };
1210
-
1211
- return (
1212
- <button
1213
- onClick={onClick}
1214
- disabled={disabled}
1215
- className={`${fullWidth ? 'w-full' : ''} px-5 py-2.5 border rounded-lg text-sm font-semibold transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 ${variants[variant]}`}
1216
- >
1217
- {icon}
1218
- {children}
1219
- </button>
1220
- );
1221
- }
1222
-
1223
- function StatusBadge({ status }: { status: string }) {
1224
- const styles: Record<string, string> = {
1225
- synced: 'bg-success/15 text-success border-success/30',
1226
- active: 'bg-success/15 text-success border-success/30',
1227
- syncing: 'bg-accent-cyan/15 text-accent-cyan border-accent-cyan/30',
1228
- verifying: 'bg-accent-cyan/15 text-accent-cyan border-accent-cyan/30',
1229
- pending: 'bg-amber-400/15 text-amber-400 border-amber-400/30',
1230
- error: 'bg-error/15 text-error border-error/30',
1231
- };
1232
-
1233
- return (
1234
- <span className={`text-xs px-3 py-1 rounded-full border ${styles[status] || 'bg-bg-hover text-text-muted border-border-subtle'}`}>
1235
- {status}
1236
- </span>
1237
- );
1238
- }
1239
-
1240
- function DNSField({ label, value }: { label: string; value: string }) {
1241
- return (
1242
- <div className="p-3 bg-bg-card rounded-lg">
1243
- <label className="text-xs text-text-muted block mb-1">{label}</label>
1244
- <p className="font-mono text-sm text-text-primary break-all">{value}</p>
1245
- </div>
1246
- );
1247
- }
1248
-
1249
- // Icons
1250
- function SettingsGearIcon() {
1251
- return (
1252
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1253
- <circle cx="12" cy="12" r="3" />
1254
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
1255
- </svg>
1256
- );
1257
- }
1258
-
1259
- function ProviderIcon() {
1260
- return (
1261
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1262
- <path d="M12 2L2 7l10 5 10-5-10-5z" />
1263
- <path d="M2 17l10 5 10-5" />
1264
- <path d="M2 12l10 5 10-5" />
1265
- </svg>
1266
- );
1267
- }
1268
-
1269
- function RepoIcon({ className = '' }: { className?: string }) {
1270
- return (
1271
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={`text-text-muted ${className}`}>
1272
- <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
1273
- </svg>
1274
- );
1275
- }
1276
-
1277
- function GlobeIcon({ className = '' }: { className?: string }) {
1278
- return (
1279
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
1280
- <circle cx="12" cy="12" r="10" />
1281
- <line x1="2" y1="12" x2="22" y2="12" />
1282
- <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
1283
- </svg>
1284
- );
1285
- }
1286
-
1287
- function GitHubIcon() {
1288
- return (
1289
- <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
1290
- <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
1291
- </svg>
1292
- );
1293
- }
1294
-
1295
- function AlertIcon({ className = '' }: { className?: string }) {
1296
- return (
1297
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
1298
- <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
1299
- <line x1="12" y1="9" x2="12" y2="13" />
1300
- <line x1="12" y1="17" x2="12.01" y2="17" />
1301
- </svg>
1302
- );
1303
- }
1304
-
1305
- function LockIcon() {
1306
- return (
1307
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1308
- <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
1309
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
1310
- </svg>
1311
- );
1312
- }
1313
-
1314
- function StopIcon() {
1315
- return (
1316
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1317
- <rect x="6" y="6" width="12" height="12" />
1318
- </svg>
1319
- );
1320
- }
1321
-
1322
- function RestartIcon() {
1323
- return (
1324
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1325
- <path d="M23 4v6h-6" />
1326
- <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
1327
- </svg>
1328
- );
1329
- }
1330
-
1331
- function CheckIcon() {
1332
- return (
1333
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1334
- <polyline points="20 6 9 17 4 12" />
1335
- </svg>
1336
- );
1337
- }
1338
-
1339
- function TrashIcon() {
1340
- return (
1341
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1342
- <polyline points="3 6 5 6 21 6" />
1343
- <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
1344
- </svg>
1345
- );
1346
- }
1347
-
1348
- function CloseIcon() {
1349
- return (
1350
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1351
- <line x1="18" y1="6" x2="6" y2="18" />
1352
- <line x1="6" y1="6" x2="18" y2="18" />
1353
- </svg>
1354
- );
1355
- }
1356
-
1357
- function InfoIcon() {
1358
- return (
1359
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1360
- <circle cx="12" cy="12" r="10" />
1361
- <line x1="12" y1="16" x2="12" y2="12" />
1362
- <line x1="12" y1="8" x2="12.01" y2="8" />
1363
- </svg>
1364
- );
1365
- }
1366
-
1367
- function SyncIcon({ spinning = false }: { spinning?: boolean } = {}) {
1368
- return (
1369
- <svg
1370
- width="12"
1371
- height="12"
1372
- viewBox="0 0 24 24"
1373
- fill="none"
1374
- stroke="currentColor"
1375
- strokeWidth="2"
1376
- strokeLinecap="round"
1377
- strokeLinejoin="round"
1378
- className={spinning ? 'animate-spin' : ''}
1379
- >
1380
- <path d="M23 4v6h-6" />
1381
- <path d="M1 20v-6h6" />
1382
- <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10" />
1383
- <path d="M20.49 15a9 9 0 0 1-14.85 3.36L1 14" />
1384
- </svg>
1385
- );
1386
- }