crca 1.4.0__py3-none-any.whl

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 (501) hide show
  1. .github/ISSUE_TEMPLATE/bug_report.md +65 -0
  2. .github/ISSUE_TEMPLATE/feature_request.md +41 -0
  3. .github/PULL_REQUEST_TEMPLATE.md +20 -0
  4. .github/workflows/publish-manual.yml +61 -0
  5. .github/workflows/publish.yml +64 -0
  6. .gitignore +214 -0
  7. CRCA.py +4156 -0
  8. LICENSE +201 -0
  9. MANIFEST.in +43 -0
  10. PKG-INFO +5035 -0
  11. README.md +4959 -0
  12. __init__.py +17 -0
  13. branches/CRCA-Q.py +2728 -0
  14. branches/crca_cg/corposwarm.py +9065 -0
  15. branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
  16. branches/crca_cg/package.json +5 -0
  17. branches/crca_cg/test_bolt_integration.py +446 -0
  18. branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
  19. branches/crca_cg/test_new_features.py +163 -0
  20. branches/crca_sd/__init__.py +149 -0
  21. branches/crca_sd/crca_sd_core.py +770 -0
  22. branches/crca_sd/crca_sd_governance.py +1325 -0
  23. branches/crca_sd/crca_sd_mpc.py +1130 -0
  24. branches/crca_sd/crca_sd_realtime.py +1844 -0
  25. branches/crca_sd/crca_sd_tui.py +1133 -0
  26. crca-1.4.0.dist-info/METADATA +5035 -0
  27. crca-1.4.0.dist-info/RECORD +501 -0
  28. crca-1.4.0.dist-info/WHEEL +4 -0
  29. crca-1.4.0.dist-info/licenses/LICENSE +201 -0
  30. docs/CRCA-Q.md +2333 -0
  31. examples/config.yaml.example +25 -0
  32. examples/crca_sd_example.py +513 -0
  33. examples/data_broker_example.py +294 -0
  34. examples/logistics_corporation.py +861 -0
  35. examples/palantir_example.py +299 -0
  36. examples/policy_bench.py +934 -0
  37. examples/pridnestrovia-sd.py +705 -0
  38. examples/pridnestrovia_realtime.py +1902 -0
  39. prompts/__init__.py +10 -0
  40. prompts/default_crca.py +101 -0
  41. pyproject.toml +151 -0
  42. requirements.txt +76 -0
  43. schemas/__init__.py +43 -0
  44. schemas/mcpSchemas.py +51 -0
  45. schemas/policy.py +458 -0
  46. templates/__init__.py +38 -0
  47. templates/base_specialized_agent.py +195 -0
  48. templates/drift_detection.py +325 -0
  49. templates/examples/causal_agent_template.py +309 -0
  50. templates/examples/drag_drop_example.py +213 -0
  51. templates/examples/logistics_agent_template.py +207 -0
  52. templates/examples/trading_agent_template.py +206 -0
  53. templates/feature_mixins.py +253 -0
  54. templates/graph_management.py +442 -0
  55. templates/llm_integration.py +194 -0
  56. templates/module_registry.py +276 -0
  57. templates/mpc_planner.py +280 -0
  58. templates/policy_loop.py +1168 -0
  59. templates/prediction_framework.py +448 -0
  60. templates/statistical_methods.py +778 -0
  61. tests/sanity.yml +31 -0
  62. tests/sanity_check +406 -0
  63. tests/test_core.py +47 -0
  64. tests/test_crca_excel.py +166 -0
  65. tests/test_crca_sd.py +780 -0
  66. tests/test_data_broker.py +424 -0
  67. tests/test_palantir.py +349 -0
  68. tools/__init__.py +38 -0
  69. tools/actuators.py +437 -0
  70. tools/bolt.diy/Dockerfile +103 -0
  71. tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
  72. tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
  73. tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
  74. tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
  75. tools/bolt.diy/app/components/@settings/index.ts +12 -0
  76. tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
  77. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
  78. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
  79. tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
  80. tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
  81. tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
  82. tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
  83. tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
  84. tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
  85. tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
  86. tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
  87. tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
  88. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
  89. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
  90. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
  91. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
  92. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
  93. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
  94. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
  95. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
  96. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
  97. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
  98. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
  99. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
  100. tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
  101. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
  102. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
  103. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
  104. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
  105. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
  106. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
  107. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
  108. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
  109. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
  110. tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
  111. tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
  112. tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
  113. tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
  114. tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
  115. tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
  116. tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
  117. tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
  118. tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
  119. tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
  120. tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
  121. tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
  122. tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
  123. tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
  124. tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
  125. tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
  126. tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
  127. tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
  128. tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
  129. tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
  130. tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
  131. tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
  132. tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
  133. tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
  134. tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
  135. tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
  136. tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
  137. tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
  138. tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
  139. tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
  140. tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
  141. tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
  142. tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
  143. tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
  144. tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
  145. tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
  146. tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
  147. tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
  148. tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
  149. tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
  150. tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
  151. tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
  152. tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
  153. tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
  154. tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
  155. tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
  156. tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
  157. tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
  158. tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
  159. tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
  160. tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
  161. tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
  162. tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
  163. tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
  164. tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
  165. tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
  166. tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
  167. tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
  168. tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
  169. tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
  170. tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
  171. tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
  172. tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
  173. tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
  174. tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
  175. tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
  176. tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
  177. tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
  178. tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
  179. tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
  180. tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
  181. tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
  182. tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
  183. tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
  184. tools/bolt.diy/app/components/header/Header.tsx +42 -0
  185. tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
  186. tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
  187. tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
  188. tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
  189. tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
  190. tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
  191. tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
  192. tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
  193. tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
  194. tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
  195. tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
  196. tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
  197. tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
  198. tools/bolt.diy/app/components/txt +1 -0
  199. tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
  200. tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
  201. tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
  202. tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
  203. tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
  204. tools/bolt.diy/app/components/ui/Button.tsx +46 -0
  205. tools/bolt.diy/app/components/ui/Card.tsx +55 -0
  206. tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
  207. tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
  208. tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
  209. tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
  210. tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
  211. tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
  212. tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
  213. tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
  214. tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
  215. tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
  216. tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
  217. tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
  218. tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
  219. tools/bolt.diy/app/components/ui/Input.tsx +22 -0
  220. tools/bolt.diy/app/components/ui/Label.tsx +20 -0
  221. tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
  222. tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
  223. tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
  224. tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
  225. tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
  226. tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
  227. tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
  228. tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
  229. tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
  230. tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
  231. tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
  232. tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
  233. tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
  234. tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
  235. tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
  236. tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
  237. tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
  238. tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
  239. tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
  240. tools/bolt.diy/app/components/ui/index.ts +38 -0
  241. tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
  242. tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
  243. tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
  244. tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
  245. tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
  246. tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
  247. tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
  248. tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
  249. tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
  250. tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
  251. tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
  252. tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
  253. tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
  254. tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
  255. tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
  256. tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
  257. tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
  258. tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
  259. tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
  260. tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
  261. tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
  262. tools/bolt.diy/app/entry.client.tsx +7 -0
  263. tools/bolt.diy/app/entry.server.tsx +80 -0
  264. tools/bolt.diy/app/root.tsx +156 -0
  265. tools/bolt.diy/app/routes/_index.tsx +175 -0
  266. tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
  267. tools/bolt.diy/app/routes/api.chat.ts +463 -0
  268. tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
  269. tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
  270. tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
  271. tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
  272. tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
  273. tools/bolt.diy/app/routes/api.git-info.ts +69 -0
  274. tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
  275. tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
  276. tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
  277. tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
  278. tools/bolt.diy/app/routes/api.github-template.ts +242 -0
  279. tools/bolt.diy/app/routes/api.github-user.ts +287 -0
  280. tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
  281. tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
  282. tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
  283. tools/bolt.diy/app/routes/api.health.ts +8 -0
  284. tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
  285. tools/bolt.diy/app/routes/api.mandate.ts +351 -0
  286. tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
  287. tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
  288. tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
  289. tools/bolt.diy/app/routes/api.models.ts +90 -0
  290. tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
  291. tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
  292. tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
  293. tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
  294. tools/bolt.diy/app/routes/api.supabase.ts +56 -0
  295. tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
  296. tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
  297. tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
  298. tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
  299. tools/bolt.diy/app/routes/api.update.ts +21 -0
  300. tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
  301. tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
  302. tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
  303. tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
  304. tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
  305. tools/bolt.diy/app/routes/git.tsx +25 -0
  306. tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
  307. tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
  308. tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
  309. tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
  310. tools/bolt.diy/app/styles/animations.scss +49 -0
  311. tools/bolt.diy/app/styles/components/code.scss +9 -0
  312. tools/bolt.diy/app/styles/components/editor.scss +135 -0
  313. tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
  314. tools/bolt.diy/app/styles/components/terminal.scss +3 -0
  315. tools/bolt.diy/app/styles/components/toast.scss +23 -0
  316. tools/bolt.diy/app/styles/diff-view.css +72 -0
  317. tools/bolt.diy/app/styles/index.scss +73 -0
  318. tools/bolt.diy/app/styles/variables.scss +255 -0
  319. tools/bolt.diy/app/styles/z-index.scss +37 -0
  320. tools/bolt.diy/app/types/GitHub.ts +182 -0
  321. tools/bolt.diy/app/types/GitLab.ts +103 -0
  322. tools/bolt.diy/app/types/actions.ts +85 -0
  323. tools/bolt.diy/app/types/artifact.ts +5 -0
  324. tools/bolt.diy/app/types/context.ts +26 -0
  325. tools/bolt.diy/app/types/design-scheme.ts +93 -0
  326. tools/bolt.diy/app/types/global.d.ts +13 -0
  327. tools/bolt.diy/app/types/mandate.ts +333 -0
  328. tools/bolt.diy/app/types/model.ts +25 -0
  329. tools/bolt.diy/app/types/netlify.ts +94 -0
  330. tools/bolt.diy/app/types/supabase.ts +54 -0
  331. tools/bolt.diy/app/types/template.ts +8 -0
  332. tools/bolt.diy/app/types/terminal.ts +9 -0
  333. tools/bolt.diy/app/types/theme.ts +1 -0
  334. tools/bolt.diy/app/types/vercel.ts +67 -0
  335. tools/bolt.diy/app/utils/buffer.ts +29 -0
  336. tools/bolt.diy/app/utils/classNames.ts +65 -0
  337. tools/bolt.diy/app/utils/constants.ts +147 -0
  338. tools/bolt.diy/app/utils/debounce.ts +13 -0
  339. tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
  340. tools/bolt.diy/app/utils/diff.spec.ts +11 -0
  341. tools/bolt.diy/app/utils/diff.ts +117 -0
  342. tools/bolt.diy/app/utils/easings.ts +3 -0
  343. tools/bolt.diy/app/utils/fileLocks.ts +96 -0
  344. tools/bolt.diy/app/utils/fileUtils.ts +121 -0
  345. tools/bolt.diy/app/utils/folderImport.ts +73 -0
  346. tools/bolt.diy/app/utils/formatSize.ts +12 -0
  347. tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
  348. tools/bolt.diy/app/utils/githubStats.ts +9 -0
  349. tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
  350. tools/bolt.diy/app/utils/logger.ts +162 -0
  351. tools/bolt.diy/app/utils/markdown.ts +155 -0
  352. tools/bolt.diy/app/utils/mobile.ts +4 -0
  353. tools/bolt.diy/app/utils/os.ts +4 -0
  354. tools/bolt.diy/app/utils/path.ts +19 -0
  355. tools/bolt.diy/app/utils/projectCommands.ts +197 -0
  356. tools/bolt.diy/app/utils/promises.ts +19 -0
  357. tools/bolt.diy/app/utils/react.ts +6 -0
  358. tools/bolt.diy/app/utils/sampler.ts +49 -0
  359. tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
  360. tools/bolt.diy/app/utils/shell.ts +384 -0
  361. tools/bolt.diy/app/utils/stacktrace.ts +27 -0
  362. tools/bolt.diy/app/utils/stripIndent.ts +23 -0
  363. tools/bolt.diy/app/utils/terminal.ts +11 -0
  364. tools/bolt.diy/app/utils/unreachable.ts +3 -0
  365. tools/bolt.diy/app/vite-env.d.ts +2 -0
  366. tools/bolt.diy/assets/entitlements.mac.plist +25 -0
  367. tools/bolt.diy/assets/icons/icon.icns +0 -0
  368. tools/bolt.diy/assets/icons/icon.ico +0 -0
  369. tools/bolt.diy/assets/icons/icon.png +0 -0
  370. tools/bolt.diy/bindings.js +78 -0
  371. tools/bolt.diy/bindings.sh +33 -0
  372. tools/bolt.diy/docker-compose.yaml +145 -0
  373. tools/bolt.diy/electron/main/index.ts +201 -0
  374. tools/bolt.diy/electron/main/tsconfig.json +30 -0
  375. tools/bolt.diy/electron/main/ui/menu.ts +29 -0
  376. tools/bolt.diy/electron/main/ui/window.ts +54 -0
  377. tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
  378. tools/bolt.diy/electron/main/utils/constants.ts +4 -0
  379. tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
  380. tools/bolt.diy/electron/main/utils/reload.ts +35 -0
  381. tools/bolt.diy/electron/main/utils/serve.ts +71 -0
  382. tools/bolt.diy/electron/main/utils/store.ts +3 -0
  383. tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
  384. tools/bolt.diy/electron/main/vite.config.ts +44 -0
  385. tools/bolt.diy/electron/preload/index.ts +22 -0
  386. tools/bolt.diy/electron/preload/tsconfig.json +7 -0
  387. tools/bolt.diy/electron/preload/vite.config.ts +31 -0
  388. tools/bolt.diy/electron-builder.yml +64 -0
  389. tools/bolt.diy/electron-update.yml +4 -0
  390. tools/bolt.diy/eslint.config.mjs +57 -0
  391. tools/bolt.diy/functions/[[path]].ts +12 -0
  392. tools/bolt.diy/icons/angular.svg +1 -0
  393. tools/bolt.diy/icons/astro.svg +8 -0
  394. tools/bolt.diy/icons/chat.svg +1 -0
  395. tools/bolt.diy/icons/expo-brand.svg +1 -0
  396. tools/bolt.diy/icons/expo.svg +4 -0
  397. tools/bolt.diy/icons/logo-text.svg +1 -0
  398. tools/bolt.diy/icons/logo.svg +4 -0
  399. tools/bolt.diy/icons/mcp.svg +1 -0
  400. tools/bolt.diy/icons/nativescript.svg +1 -0
  401. tools/bolt.diy/icons/netlify.svg +10 -0
  402. tools/bolt.diy/icons/nextjs.svg +1 -0
  403. tools/bolt.diy/icons/nuxt.svg +1 -0
  404. tools/bolt.diy/icons/qwik.svg +1 -0
  405. tools/bolt.diy/icons/react.svg +1 -0
  406. tools/bolt.diy/icons/remix.svg +24 -0
  407. tools/bolt.diy/icons/remotion.svg +1 -0
  408. tools/bolt.diy/icons/shadcn.svg +21 -0
  409. tools/bolt.diy/icons/slidev.svg +60 -0
  410. tools/bolt.diy/icons/solidjs.svg +1 -0
  411. tools/bolt.diy/icons/stars.svg +1 -0
  412. tools/bolt.diy/icons/svelte.svg +1 -0
  413. tools/bolt.diy/icons/typescript.svg +1 -0
  414. tools/bolt.diy/icons/vite.svg +1 -0
  415. tools/bolt.diy/icons/vue.svg +1 -0
  416. tools/bolt.diy/load-context.ts +9 -0
  417. tools/bolt.diy/notarize.cjs +31 -0
  418. tools/bolt.diy/package.json +218 -0
  419. tools/bolt.diy/playwright.config.preview.ts +35 -0
  420. tools/bolt.diy/pre-start.cjs +26 -0
  421. tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
  422. tools/bolt.diy/public/apple-touch-icon.png +0 -0
  423. tools/bolt.diy/public/favicon.ico +0 -0
  424. tools/bolt.diy/public/favicon.svg +4 -0
  425. tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
  426. tools/bolt.diy/public/icons/Anthropic.svg +4 -0
  427. tools/bolt.diy/public/icons/Cohere.svg +4 -0
  428. tools/bolt.diy/public/icons/Deepseek.svg +5 -0
  429. tools/bolt.diy/public/icons/Default.svg +4 -0
  430. tools/bolt.diy/public/icons/Google.svg +4 -0
  431. tools/bolt.diy/public/icons/Groq.svg +4 -0
  432. tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
  433. tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
  434. tools/bolt.diy/public/icons/LMStudio.svg +5 -0
  435. tools/bolt.diy/public/icons/Mistral.svg +4 -0
  436. tools/bolt.diy/public/icons/Ollama.svg +4 -0
  437. tools/bolt.diy/public/icons/OpenAI.svg +4 -0
  438. tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
  439. tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
  440. tools/bolt.diy/public/icons/Perplexity.svg +4 -0
  441. tools/bolt.diy/public/icons/Together.svg +4 -0
  442. tools/bolt.diy/public/icons/xAI.svg +5 -0
  443. tools/bolt.diy/public/inspector-script.js +292 -0
  444. tools/bolt.diy/public/logo-dark-styled.png +0 -0
  445. tools/bolt.diy/public/logo-dark.png +0 -0
  446. tools/bolt.diy/public/logo-light-styled.png +0 -0
  447. tools/bolt.diy/public/logo-light.png +0 -0
  448. tools/bolt.diy/public/logo.svg +15 -0
  449. tools/bolt.diy/public/social_preview_index.jpg +0 -0
  450. tools/bolt.diy/scripts/clean.js +45 -0
  451. tools/bolt.diy/scripts/electron-dev.mjs +181 -0
  452. tools/bolt.diy/scripts/setup-env.sh +41 -0
  453. tools/bolt.diy/scripts/update-imports.sh +7 -0
  454. tools/bolt.diy/scripts/update.sh +52 -0
  455. tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
  456. tools/bolt.diy/services/execution-governor/config.ts +42 -0
  457. tools/bolt.diy/services/execution-governor/index.ts +683 -0
  458. tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
  459. tools/bolt.diy/services/execution-governor/package.json +31 -0
  460. tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
  461. tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
  462. tools/bolt.diy/services/execution-governor/types.ts +145 -0
  463. tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
  464. tools/bolt.diy/services/headless-executor/executor.ts +210 -0
  465. tools/bolt.diy/services/headless-executor/index.ts +323 -0
  466. tools/bolt.diy/services/headless-executor/package.json +27 -0
  467. tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
  468. tools/bolt.diy/services/headless-executor/types.ts +38 -0
  469. tools/bolt.diy/test-workflows.sh +240 -0
  470. tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
  471. tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
  472. tools/bolt.diy/tests/mandates/complex.json +53 -0
  473. tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
  474. tools/bolt.diy/tests/mandates/simple.json +35 -0
  475. tools/bolt.diy/tsconfig.json +37 -0
  476. tools/bolt.diy/types/istextorbinary.d.ts +15 -0
  477. tools/bolt.diy/uno.config.ts +279 -0
  478. tools/bolt.diy/vite-electron.config.ts +76 -0
  479. tools/bolt.diy/vite.config.ts +112 -0
  480. tools/bolt.diy/worker-configuration.d.ts +22 -0
  481. tools/bolt.diy/wrangler.toml +6 -0
  482. tools/code_generator.py +461 -0
  483. tools/file_operations.py +465 -0
  484. tools/mandate_generator.py +337 -0
  485. tools/mcpClientUtils.py +1216 -0
  486. tools/sensors.py +285 -0
  487. utils/Agent_types.py +15 -0
  488. utils/AnyToStr.py +0 -0
  489. utils/HHCS.py +277 -0
  490. utils/__init__.py +30 -0
  491. utils/agent.py +3627 -0
  492. utils/aop.py +2948 -0
  493. utils/canonical.py +143 -0
  494. utils/conversation.py +1195 -0
  495. utils/doctrine_versioning +230 -0
  496. utils/formatter.py +474 -0
  497. utils/ledger.py +311 -0
  498. utils/out_types.py +16 -0
  499. utils/rollback.py +339 -0
  500. utils/router.py +929 -0
  501. utils/tui.py +1908 -0
@@ -0,0 +1,909 @@
1
+ import React, { useEffect, useState, useMemo, useCallback } from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { toast } from 'react-toastify';
4
+ import { useStore } from '@nanostores/react';
5
+ import { logStore } from '~/lib/stores/logs';
6
+ import type { VercelUserResponse } from '~/types/vercel';
7
+ import { classNames } from '~/utils/classNames';
8
+ import { Button } from '~/components/ui/Button';
9
+ import { ServiceHeader, ConnectionTestIndicator } from '~/components/@settings/shared/service-integration';
10
+ import { useConnectionTest } from '~/lib/hooks';
11
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '~/components/ui/Collapsible';
12
+ import Cookies from 'js-cookie';
13
+ import {
14
+ vercelConnection,
15
+ isConnecting,
16
+ isFetchingStats,
17
+ updateVercelConnection,
18
+ fetchVercelStats,
19
+ fetchVercelStatsViaAPI,
20
+ initializeVercelConnection,
21
+ } from '~/lib/stores/vercel';
22
+
23
+ interface ProjectAction {
24
+ name: string;
25
+ icon: string;
26
+ action: (projectId: string) => Promise<void>;
27
+ requiresConfirmation?: boolean;
28
+ variant?: 'default' | 'destructive' | 'outline';
29
+ }
30
+
31
+ // Vercel logo SVG component
32
+ const VercelLogo = () => (
33
+ <svg viewBox="0 0 24 24" className="w-5 h-5">
34
+ <path fill="currentColor" d="m12 2 10 18H2z" />
35
+ </svg>
36
+ );
37
+
38
+ export default function VercelTab() {
39
+ const connection = useStore(vercelConnection);
40
+ const connecting = useStore(isConnecting);
41
+ const fetchingStats = useStore(isFetchingStats);
42
+ const [isProjectsExpanded, setIsProjectsExpanded] = useState(false);
43
+ const [isProjectActionLoading, setIsProjectActionLoading] = useState(false);
44
+
45
+ // Use shared connection test hook
46
+ const {
47
+ testResult: connectionTest,
48
+ testConnection,
49
+ isTestingConnection,
50
+ } = useConnectionTest({
51
+ testEndpoint: '/api/vercel-user',
52
+ serviceName: 'Vercel',
53
+ getUserIdentifier: (data: VercelUserResponse) =>
54
+ data.username || data.user?.username || data.email || data.user?.email || 'Vercel User',
55
+ });
56
+
57
+ // Memoize project actions to prevent unnecessary re-renders
58
+ const projectActions: ProjectAction[] = useMemo(
59
+ () => [
60
+ {
61
+ name: 'Redeploy',
62
+ icon: 'i-ph:arrows-clockwise',
63
+ action: async (projectId: string) => {
64
+ try {
65
+ const response = await fetch(`https://api.vercel.com/v1/deployments`, {
66
+ method: 'POST',
67
+ headers: {
68
+ Authorization: `Bearer ${connection.token}`,
69
+ 'Content-Type': 'application/json',
70
+ },
71
+ body: JSON.stringify({
72
+ name: projectId,
73
+ target: 'production',
74
+ }),
75
+ });
76
+
77
+ if (!response.ok) {
78
+ throw new Error('Failed to redeploy project');
79
+ }
80
+
81
+ toast.success('Project redeployment initiated');
82
+ await fetchVercelStats(connection.token);
83
+ } catch (err: unknown) {
84
+ const error = err instanceof Error ? err.message : 'Unknown error';
85
+ toast.error(`Failed to redeploy project: ${error}`);
86
+ }
87
+ },
88
+ },
89
+ {
90
+ name: 'View Dashboard',
91
+ icon: 'i-ph:layout',
92
+ action: async (projectId: string) => {
93
+ window.open(`https://vercel.com/dashboard/${projectId}`, '_blank');
94
+ },
95
+ },
96
+ {
97
+ name: 'View Deployments',
98
+ icon: 'i-ph:rocket',
99
+ action: async (projectId: string) => {
100
+ window.open(`https://vercel.com/dashboard/${projectId}/deployments`, '_blank');
101
+ },
102
+ },
103
+ {
104
+ name: 'View Functions',
105
+ icon: 'i-ph:code',
106
+ action: async (projectId: string) => {
107
+ window.open(`https://vercel.com/dashboard/${projectId}/functions`, '_blank');
108
+ },
109
+ },
110
+ {
111
+ name: 'View Analytics',
112
+ icon: 'i-ph:chart-bar',
113
+ action: async (projectId: string) => {
114
+ const project = connection.stats?.projects.find((p) => p.id === projectId);
115
+
116
+ if (project) {
117
+ window.open(`https://vercel.com/${connection.user?.username}/${project.name}/analytics`, '_blank');
118
+ }
119
+ },
120
+ },
121
+ {
122
+ name: 'View Domains',
123
+ icon: 'i-ph:globe',
124
+ action: async (projectId: string) => {
125
+ window.open(`https://vercel.com/dashboard/${projectId}/domains`, '_blank');
126
+ },
127
+ },
128
+ {
129
+ name: 'View Settings',
130
+ icon: 'i-ph:gear',
131
+ action: async (projectId: string) => {
132
+ window.open(`https://vercel.com/dashboard/${projectId}/settings`, '_blank');
133
+ },
134
+ },
135
+ {
136
+ name: 'View Logs',
137
+ icon: 'i-ph:scroll',
138
+ action: async (projectId: string) => {
139
+ window.open(`https://vercel.com/dashboard/${projectId}/logs`, '_blank');
140
+ },
141
+ },
142
+ {
143
+ name: 'Delete Project',
144
+ icon: 'i-ph:trash',
145
+ action: async (projectId: string) => {
146
+ try {
147
+ const response = await fetch(`https://api.vercel.com/v1/projects/${projectId}`, {
148
+ method: 'DELETE',
149
+ headers: {
150
+ Authorization: `Bearer ${connection.token}`,
151
+ },
152
+ });
153
+
154
+ if (!response.ok) {
155
+ throw new Error('Failed to delete project');
156
+ }
157
+
158
+ toast.success('Project deleted successfully');
159
+ await fetchVercelStats(connection.token);
160
+ } catch (err: unknown) {
161
+ const error = err instanceof Error ? err.message : 'Unknown error';
162
+ toast.error(`Failed to delete project: ${error}`);
163
+ }
164
+ },
165
+ requiresConfirmation: true,
166
+ variant: 'destructive',
167
+ },
168
+ ],
169
+ [connection.token],
170
+ ); // Only re-create when token changes
171
+
172
+ // Initialize connection on component mount - check server-side token first
173
+ useEffect(() => {
174
+ const initializeConnection = async () => {
175
+ try {
176
+ // First try to initialize using server-side token
177
+ await initializeVercelConnection();
178
+
179
+ // If no connection was established, the user will need to manually enter a token
180
+ const currentState = vercelConnection.get();
181
+
182
+ if (!currentState.user) {
183
+ console.log('No server-side Vercel token available, manual connection required');
184
+ }
185
+ } catch (error) {
186
+ console.error('Failed to initialize Vercel connection:', error);
187
+ }
188
+ };
189
+ initializeConnection();
190
+ }, []);
191
+
192
+ useEffect(() => {
193
+ const fetchProjects = async () => {
194
+ if (connection.user) {
195
+ // Use server-side API if we have a connected user
196
+ try {
197
+ await fetchVercelStatsViaAPI(connection.token);
198
+ } catch {
199
+ // Fallback to direct API if server-side fails and we have a token
200
+ if (connection.token) {
201
+ await fetchVercelStats(connection.token);
202
+ }
203
+ }
204
+ }
205
+ };
206
+ fetchProjects();
207
+ }, [connection.user, connection.token]);
208
+
209
+ const handleConnect = async (event: React.FormEvent) => {
210
+ event.preventDefault();
211
+ isConnecting.set(true);
212
+
213
+ try {
214
+ const token = connection.token;
215
+
216
+ if (!token.trim()) {
217
+ throw new Error('Token is required');
218
+ }
219
+
220
+ // First test the token directly with Vercel API
221
+ const testResponse = await fetch('https://api.vercel.com/v2/user', {
222
+ headers: {
223
+ Authorization: `Bearer ${token}`,
224
+ 'User-Agent': 'bolt.diy-app',
225
+ },
226
+ });
227
+
228
+ if (!testResponse.ok) {
229
+ if (testResponse.status === 401) {
230
+ throw new Error('Invalid Vercel token');
231
+ }
232
+
233
+ throw new Error(`Vercel API error: ${testResponse.status}`);
234
+ }
235
+
236
+ const userData = (await testResponse.json()) as VercelUserResponse;
237
+
238
+ // Set cookies for server-side API access
239
+ Cookies.set('VITE_VERCEL_ACCESS_TOKEN', token, { expires: 365 });
240
+
241
+ // Normalize the user data structure
242
+ const normalizedUser = userData.user || {
243
+ id: userData.id || '',
244
+ username: userData.username || '',
245
+ email: userData.email || '',
246
+ name: userData.name || '',
247
+ avatar: userData.avatar,
248
+ };
249
+
250
+ updateVercelConnection({
251
+ user: normalizedUser,
252
+ token,
253
+ });
254
+
255
+ await fetchVercelStats(token);
256
+ toast.success('Successfully connected to Vercel');
257
+ } catch (error) {
258
+ console.error('Auth error:', error);
259
+ logStore.logError('Failed to authenticate with Vercel', { error });
260
+
261
+ const errorMessage = error instanceof Error ? error.message : 'Failed to connect to Vercel';
262
+ toast.error(errorMessage);
263
+ updateVercelConnection({ user: null, token: '' });
264
+ } finally {
265
+ isConnecting.set(false);
266
+ }
267
+ };
268
+
269
+ const handleDisconnect = () => {
270
+ // Clear Vercel-related cookies
271
+ Cookies.remove('VITE_VERCEL_ACCESS_TOKEN');
272
+
273
+ updateVercelConnection({ user: null, token: '' });
274
+ toast.success('Disconnected from Vercel');
275
+ };
276
+
277
+ const handleProjectAction = useCallback(async (projectId: string, action: ProjectAction) => {
278
+ if (action.requiresConfirmation) {
279
+ if (!confirm(`Are you sure you want to ${action.name.toLowerCase()}?`)) {
280
+ return;
281
+ }
282
+ }
283
+
284
+ setIsProjectActionLoading(true);
285
+ await action.action(projectId);
286
+ setIsProjectActionLoading(false);
287
+ }, []);
288
+
289
+ const renderProjects = useCallback(() => {
290
+ if (fetchingStats) {
291
+ return (
292
+ <div className="flex items-center gap-2 text-sm text-bolt-elements-textSecondary">
293
+ <div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
294
+ Fetching Vercel projects...
295
+ </div>
296
+ );
297
+ }
298
+
299
+ return (
300
+ <Collapsible open={isProjectsExpanded} onOpenChange={setIsProjectsExpanded}>
301
+ <CollapsibleTrigger asChild>
302
+ <div className="flex items-center justify-between p-4 rounded-lg bg-bolt-elements-background dark:bg-bolt-elements-background-depth-2 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor hover:border-bolt-elements-borderColorActive/70 dark:hover:border-bolt-elements-borderColorActive/70 transition-all duration-200 cursor-pointer">
303
+ <div className="flex items-center gap-2">
304
+ <div className="i-ph:buildings w-4 h-4 text-bolt-elements-item-contentAccent" />
305
+ <span className="text-sm font-medium text-bolt-elements-textPrimary">
306
+ Your Projects ({connection.stats?.totalProjects || 0})
307
+ </span>
308
+ </div>
309
+ <div
310
+ className={classNames(
311
+ 'i-ph:caret-down w-4 h-4 transform transition-transform duration-200 text-bolt-elements-textSecondary',
312
+ isProjectsExpanded ? 'rotate-180' : '',
313
+ )}
314
+ />
315
+ </div>
316
+ </CollapsibleTrigger>
317
+ <CollapsibleContent className="overflow-hidden">
318
+ <div className="space-y-4 mt-4">
319
+ {/* Vercel Overview Dashboard */}
320
+ {connection.stats?.projects?.length ? (
321
+ <div className="mb-6 p-4 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
322
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Vercel Overview</h4>
323
+ <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
324
+ <div className="text-center">
325
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
326
+ {connection.stats.totalProjects}
327
+ </div>
328
+ <div className="text-xs text-bolt-elements-textSecondary">Total Projects</div>
329
+ </div>
330
+ <div className="text-center">
331
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
332
+ {
333
+ connection.stats.projects.filter(
334
+ (p) => p.targets?.production?.alias && p.targets.production.alias.length > 0,
335
+ ).length
336
+ }
337
+ </div>
338
+ <div className="text-xs text-bolt-elements-textSecondary">Deployed Projects</div>
339
+ </div>
340
+ <div className="text-center">
341
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
342
+ {new Set(connection.stats.projects.map((p) => p.framework).filter(Boolean)).size}
343
+ </div>
344
+ <div className="text-xs text-bolt-elements-textSecondary">Frameworks Used</div>
345
+ </div>
346
+ <div className="text-center">
347
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
348
+ {connection.stats.projects.filter((p) => p.latestDeployments?.[0]?.state === 'READY').length}
349
+ </div>
350
+ <div className="text-xs text-bolt-elements-textSecondary">Active Deployments</div>
351
+ </div>
352
+ </div>
353
+ </div>
354
+ ) : null}
355
+
356
+ {/* Performance Analytics */}
357
+ {connection.stats?.projects?.length ? (
358
+ <div className="mb-6 space-y-4">
359
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary">Performance Analytics</h4>
360
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
361
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
362
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
363
+ <div className="i-ph:rocket w-4 h-4 text-bolt-elements-item-contentAccent" />
364
+ Deployment Health
365
+ </h6>
366
+ <div className="space-y-1">
367
+ {(() => {
368
+ const totalDeployments = connection.stats.projects.reduce(
369
+ (sum, p) => sum + (p.latestDeployments?.length || 0),
370
+ 0,
371
+ );
372
+ const readyDeployments = connection.stats.projects.filter(
373
+ (p) => p.latestDeployments?.[0]?.state === 'READY',
374
+ ).length;
375
+ const errorDeployments = connection.stats.projects.filter(
376
+ (p) => p.latestDeployments?.[0]?.state === 'ERROR',
377
+ ).length;
378
+ const successRate =
379
+ totalDeployments > 0
380
+ ? Math.round((readyDeployments / connection.stats.projects.length) * 100)
381
+ : 0;
382
+
383
+ return [
384
+ { label: 'Success Rate', value: `${successRate}%` },
385
+ { label: 'Active', value: readyDeployments },
386
+ { label: 'Failed', value: errorDeployments },
387
+ ];
388
+ })().map((item, idx) => (
389
+ <div key={idx} className="flex justify-between text-xs">
390
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
391
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
392
+ </div>
393
+ ))}
394
+ </div>
395
+ </div>
396
+
397
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
398
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
399
+ <div className="i-ph:chart-bar w-4 h-4 text-bolt-elements-item-contentAccent" />
400
+ Framework Distribution
401
+ </h6>
402
+ <div className="space-y-1">
403
+ {(() => {
404
+ const frameworks = connection.stats.projects.reduce(
405
+ (acc, p) => {
406
+ if (p.framework) {
407
+ acc[p.framework] = (acc[p.framework] || 0) + 1;
408
+ }
409
+
410
+ return acc;
411
+ },
412
+ {} as Record<string, number>,
413
+ );
414
+
415
+ return Object.entries(frameworks)
416
+ .sort(([, a], [, b]) => b - a)
417
+ .slice(0, 3)
418
+ .map(([framework, count]) => ({ label: framework, value: count }));
419
+ })().map((item, idx) => (
420
+ <div key={idx} className="flex justify-between text-xs">
421
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
422
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
423
+ </div>
424
+ ))}
425
+ </div>
426
+ </div>
427
+
428
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
429
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
430
+ <div className="i-ph:activity w-4 h-4 text-bolt-elements-item-contentAccent" />
431
+ Activity Summary
432
+ </h6>
433
+ <div className="space-y-1">
434
+ {(() => {
435
+ const now = Date.now();
436
+ const recentDeployments = connection.stats.projects.filter((p) => {
437
+ const lastDeploy = p.latestDeployments?.[0]?.created;
438
+ return lastDeploy && now - new Date(lastDeploy).getTime() < 7 * 24 * 60 * 60 * 1000;
439
+ }).length;
440
+ const totalDomains = connection.stats.projects.reduce(
441
+ (sum, p) => sum + (p.targets?.production?.alias ? p.targets.production.alias.length : 0),
442
+ 0,
443
+ );
444
+ const avgDomainsPerProject =
445
+ connection.stats.projects.length > 0
446
+ ? Math.round((totalDomains / connection.stats.projects.length) * 10) / 10
447
+ : 0;
448
+
449
+ return [
450
+ { label: 'Recent deploys', value: recentDeployments },
451
+ { label: 'Total domains', value: totalDomains },
452
+ { label: 'Avg domains/project', value: avgDomainsPerProject },
453
+ ];
454
+ })().map((item, idx) => (
455
+ <div key={idx} className="flex justify-between text-xs">
456
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
457
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
458
+ </div>
459
+ ))}
460
+ </div>
461
+ </div>
462
+ </div>
463
+ </div>
464
+ ) : null}
465
+
466
+ {/* Project Health Overview */}
467
+ {connection.stats?.projects?.length ? (
468
+ <div className="mb-6">
469
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-2">Project Health Overview</h4>
470
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
471
+ {(() => {
472
+ const healthyProjects = connection.stats.projects.filter(
473
+ (p) =>
474
+ p.latestDeployments?.[0]?.state === 'READY' && (p.targets?.production?.alias?.length ?? 0) > 0,
475
+ ).length;
476
+ const needsAttention = connection.stats.projects.filter(
477
+ (p) =>
478
+ p.latestDeployments?.[0]?.state === 'ERROR' || p.latestDeployments?.[0]?.state === 'CANCELED',
479
+ ).length;
480
+ const withCustomDomain = connection.stats.projects.filter((p) =>
481
+ p.targets?.production?.alias?.some((alias: string) => !alias.includes('.vercel.app')),
482
+ ).length;
483
+ const buildingProjects = connection.stats.projects.filter(
484
+ (p) => p.latestDeployments?.[0]?.state === 'BUILDING',
485
+ ).length;
486
+
487
+ return [
488
+ {
489
+ label: 'Healthy',
490
+ value: healthyProjects,
491
+ icon: 'i-ph:check-circle',
492
+ color: 'text-green-500',
493
+ bgColor: 'bg-green-100 dark:bg-green-900/20',
494
+ textColor: 'text-green-800 dark:text-green-400',
495
+ },
496
+ {
497
+ label: 'Custom Domain',
498
+ value: withCustomDomain,
499
+ icon: 'i-ph:globe',
500
+ color: 'text-blue-500',
501
+ bgColor: 'bg-blue-100 dark:bg-blue-900/20',
502
+ textColor: 'text-blue-800 dark:text-blue-400',
503
+ },
504
+ {
505
+ label: 'Building',
506
+ value: buildingProjects,
507
+ icon: 'i-ph:gear',
508
+ color: 'text-yellow-500',
509
+ bgColor: 'bg-yellow-100 dark:bg-yellow-900/20',
510
+ textColor: 'text-yellow-800 dark:text-yellow-400',
511
+ },
512
+ {
513
+ label: 'Issues',
514
+ value: needsAttention,
515
+ icon: 'i-ph:warning',
516
+ color: 'text-red-500',
517
+ bgColor: 'bg-red-100 dark:bg-red-900/20',
518
+ textColor: 'text-red-800 dark:text-red-400',
519
+ },
520
+ ];
521
+ })().map((metric, index) => (
522
+ <div
523
+ key={index}
524
+ className={`flex flex-col p-3 rounded-lg border border-bolt-elements-borderColor ${metric.bgColor}`}
525
+ >
526
+ <div className="flex items-center gap-2 mb-1">
527
+ <div className={`${metric.icon} w-4 h-4 ${metric.color}`} />
528
+ <span className="text-xs text-bolt-elements-textSecondary">{metric.label}</span>
529
+ </div>
530
+ <span className={`text-lg font-medium ${metric.textColor}`}>{metric.value}</span>
531
+ </div>
532
+ ))}
533
+ </div>
534
+ </div>
535
+ ) : null}
536
+
537
+ {connection.stats?.projects?.length ? (
538
+ <div className="grid gap-3">
539
+ {connection.stats.projects.map((project) => (
540
+ <div
541
+ key={project.id}
542
+ className="p-4 rounded-lg border border-bolt-elements-borderColor hover:border-bolt-elements-borderColorActive/70 transition-colors bg-bolt-elements-background-depth-1"
543
+ >
544
+ <div className="flex items-center justify-between">
545
+ <div className="flex-1">
546
+ <h5 className="text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2">
547
+ <div className="i-ph:globe w-4 h-4 text-bolt-elements-borderColorActive" />
548
+ {project.name}
549
+ </h5>
550
+ <div className="flex items-center gap-2 mt-2 text-xs text-bolt-elements-textSecondary">
551
+ {project.targets?.production?.alias && project.targets.production.alias.length > 0 ? (
552
+ <>
553
+ <a
554
+ href={`https://${project.targets.production.alias.find((a: string) => a.endsWith('.vercel.app') && !a.includes('-projects.vercel.app')) || project.targets.production.alias[0]}`}
555
+ target="_blank"
556
+ rel="noopener noreferrer"
557
+ className="hover:text-bolt-elements-borderColorActive underline"
558
+ >
559
+ {project.targets.production.alias.find(
560
+ (a: string) => a.endsWith('.vercel.app') && !a.includes('-projects.vercel.app'),
561
+ ) || project.targets.production.alias[0]}
562
+ </a>
563
+ <span>•</span>
564
+ <span className="flex items-center gap-1">
565
+ <div className="i-ph:clock w-3 h-3" />
566
+ {new Date(project.createdAt).toLocaleDateString()}
567
+ </span>
568
+ </>
569
+ ) : project.latestDeployments && project.latestDeployments.length > 0 ? (
570
+ <>
571
+ <a
572
+ href={`https://${project.latestDeployments[0].url}`}
573
+ target="_blank"
574
+ rel="noopener noreferrer"
575
+ className="hover:text-bolt-elements-borderColorActive underline"
576
+ >
577
+ {project.latestDeployments[0].url}
578
+ </a>
579
+ <span>•</span>
580
+ <span className="flex items-center gap-1">
581
+ <div className="i-ph:clock w-3 h-3" />
582
+ {new Date(project.latestDeployments[0].created).toLocaleDateString()}
583
+ </span>
584
+ </>
585
+ ) : null}
586
+ </div>
587
+
588
+ {/* Project Details Grid */}
589
+ <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3 mt-3 pt-3 border-t border-bolt-elements-borderColor">
590
+ <div className="text-center">
591
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
592
+ {/* Deployments - This would be fetched from API */}
593
+ --
594
+ </div>
595
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
596
+ <div className="i-ph:rocket w-3 h-3" />
597
+ Deployments
598
+ </div>
599
+ </div>
600
+ <div className="text-center">
601
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
602
+ {/* Domains - This would be fetched from API */}
603
+ --
604
+ </div>
605
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
606
+ <div className="i-ph:globe w-3 h-3" />
607
+ Domains
608
+ </div>
609
+ </div>
610
+ <div className="text-center">
611
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
612
+ {/* Team Members - This would be fetched from API */}
613
+ --
614
+ </div>
615
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
616
+ <div className="i-ph:users w-3 h-3" />
617
+ Team
618
+ </div>
619
+ </div>
620
+ <div className="text-center">
621
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
622
+ {/* Bandwidth - This would be fetched from API */}
623
+ --
624
+ </div>
625
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
626
+ <div className="i-ph:activity w-3 h-3" />
627
+ Bandwidth
628
+ </div>
629
+ </div>
630
+ </div>
631
+ </div>
632
+ <div className="flex items-center gap-2">
633
+ {project.latestDeployments && project.latestDeployments.length > 0 && (
634
+ <div
635
+ className={classNames(
636
+ 'flex items-center gap-1 px-2 py-1 rounded-full text-xs',
637
+ project.latestDeployments[0].state === 'READY'
638
+ ? 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400'
639
+ : project.latestDeployments[0].state === 'ERROR'
640
+ ? 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400'
641
+ : 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400',
642
+ )}
643
+ >
644
+ <div
645
+ className={classNames(
646
+ 'w-2 h-2 rounded-full',
647
+ project.latestDeployments[0].state === 'READY'
648
+ ? 'bg-green-500'
649
+ : project.latestDeployments[0].state === 'ERROR'
650
+ ? 'bg-red-500'
651
+ : 'bg-yellow-500',
652
+ )}
653
+ />
654
+ {project.latestDeployments[0].state}
655
+ </div>
656
+ )}
657
+ {project.framework && (
658
+ <div className="text-xs text-bolt-elements-textSecondary px-2 py-1 rounded-md bg-bolt-elements-background-depth-2">
659
+ <span className="flex items-center gap-1">
660
+ <div className="i-ph:code w-3 h-3" />
661
+ {project.framework}
662
+ </span>
663
+ </div>
664
+ )}
665
+ <Button
666
+ variant="outline"
667
+ size="sm"
668
+ onClick={() => window.open(`https://vercel.com/dashboard/${project.id}`, '_blank')}
669
+ className="flex items-center gap-1 text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary"
670
+ >
671
+ <div className="i-ph:arrow-square-out w-3 h-3" />
672
+ View
673
+ </Button>
674
+ </div>
675
+ </div>
676
+
677
+ <div className="flex items-center flex-wrap gap-1 mt-3 pt-3 border-t border-bolt-elements-borderColor">
678
+ {projectActions.map((action) => (
679
+ <Button
680
+ key={action.name}
681
+ variant={action.variant || 'outline'}
682
+ size="sm"
683
+ onClick={() => handleProjectAction(project.id, action)}
684
+ disabled={isProjectActionLoading}
685
+ className="flex items-center gap-1 text-xs px-2 py-1 text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary"
686
+ >
687
+ <div className={`${action.icon} w-2.5 h-2.5`} />
688
+ {action.name}
689
+ </Button>
690
+ ))}
691
+ </div>
692
+ </div>
693
+ ))}
694
+ </div>
695
+ ) : (
696
+ <div className="text-sm text-bolt-elements-textSecondary flex items-center gap-2 p-4">
697
+ <div className="i-ph:info w-4 h-4" />
698
+ No projects found in your Vercel account
699
+ </div>
700
+ )}
701
+ </div>
702
+ </CollapsibleContent>
703
+ </Collapsible>
704
+ );
705
+ }, [
706
+ connection.stats,
707
+ fetchingStats,
708
+ isProjectsExpanded,
709
+ isProjectActionLoading,
710
+ handleProjectAction,
711
+ projectActions,
712
+ ]);
713
+
714
+ console.log('connection', connection);
715
+
716
+ return (
717
+ <div className="space-y-6">
718
+ <ServiceHeader
719
+ icon={VercelLogo}
720
+ title="Vercel Integration"
721
+ description="Connect and manage your Vercel projects with advanced deployment controls and analytics"
722
+ onTestConnection={connection.user ? () => testConnection() : undefined}
723
+ isTestingConnection={isTestingConnection}
724
+ />
725
+
726
+ <ConnectionTestIndicator testResult={connectionTest} />
727
+
728
+ {/* Main Connection Component */}
729
+ <motion.div
730
+ className="bg-bolt-elements-background dark:bg-bolt-elements-background border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor rounded-lg"
731
+ initial={{ opacity: 0, y: 20 }}
732
+ animate={{ opacity: 1, y: 0 }}
733
+ transition={{ delay: 0.2 }}
734
+ >
735
+ <div className="p-6 space-y-6">
736
+ {!connection.user ? (
737
+ <div className="space-y-4">
738
+ <div className="text-xs text-bolt-elements-textSecondary bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 p-3 rounded-lg mb-4">
739
+ <p className="flex items-center gap-1 mb-1">
740
+ <span className="i-ph:lightbulb w-3.5 h-3.5 text-bolt-elements-icon-success dark:text-bolt-elements-icon-success" />
741
+ <span className="font-medium">Tip:</span> You can also set the{' '}
742
+ <code className="px-1 py-0.5 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 rounded">
743
+ VITE_VERCEL_ACCESS_TOKEN
744
+ </code>{' '}
745
+ environment variable to connect automatically.
746
+ </p>
747
+ </div>
748
+
749
+ <div>
750
+ <label className="block text-sm text-bolt-elements-textSecondary mb-2">Personal Access Token</label>
751
+ <input
752
+ type="password"
753
+ value={connection.token}
754
+ onChange={(e) => updateVercelConnection({ ...connection, token: e.target.value })}
755
+ disabled={connecting}
756
+ placeholder="Enter your Vercel personal access token"
757
+ className={classNames(
758
+ 'w-full px-3 py-2 rounded-lg text-sm',
759
+ 'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
760
+ 'border border-[#E5E5E5] dark:border-[#333333]',
761
+ 'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
762
+ 'focus:outline-none focus:ring-1 focus:ring-bolt-elements-borderColorActive',
763
+ 'disabled:opacity-50',
764
+ )}
765
+ />
766
+ <div className="mt-2 text-sm text-bolt-elements-textSecondary">
767
+ <a
768
+ href="https://vercel.com/account/tokens"
769
+ target="_blank"
770
+ rel="noopener noreferrer"
771
+ className="text-bolt-elements-borderColorActive hover:underline inline-flex items-center gap-1"
772
+ >
773
+ Get your token
774
+ <div className="i-ph:arrow-square-out w-4 h-4" />
775
+ </a>
776
+ </div>
777
+ </div>
778
+
779
+ <button
780
+ onClick={handleConnect}
781
+ disabled={connecting || !connection.token}
782
+ className={classNames(
783
+ 'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
784
+ 'bg-[#303030] text-white',
785
+ 'hover:bg-[#5E41D0] hover:text-white',
786
+ 'disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200',
787
+ 'transform active:scale-95',
788
+ )}
789
+ >
790
+ {connecting ? (
791
+ <>
792
+ <div className="i-ph:spinner-gap animate-spin" />
793
+ Connecting...
794
+ </>
795
+ ) : (
796
+ <>
797
+ <div className="i-ph:plug-charging w-4 h-4" />
798
+ Connect
799
+ </>
800
+ )}
801
+ </button>
802
+ </div>
803
+ ) : (
804
+ <div className="space-y-6">
805
+ <div className="flex items-center justify-between">
806
+ <div className="flex items-center gap-3">
807
+ <button
808
+ onClick={handleDisconnect}
809
+ className={classNames(
810
+ 'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
811
+ 'bg-red-500 text-white',
812
+ 'hover:bg-red-600',
813
+ )}
814
+ >
815
+ <div className="i-ph:plug w-4 h-4" />
816
+ Disconnect
817
+ </button>
818
+ <span className="text-sm text-bolt-elements-textSecondary flex items-center gap-1">
819
+ <div className="i-ph:check-circle w-4 h-4 text-green-500" />
820
+ Connected to Vercel
821
+ </span>
822
+ </div>
823
+ </div>
824
+
825
+ <div className="space-y-4">
826
+ <div className="flex items-center gap-4 p-4 bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 rounded-lg">
827
+ <img
828
+ src={`https://vercel.com/api/www/avatar?u=${connection.user?.username}`}
829
+ referrerPolicy="no-referrer"
830
+ crossOrigin="anonymous"
831
+ alt="User Avatar"
832
+ className="w-12 h-12 rounded-full border-2 border-bolt-elements-borderColorActive"
833
+ />
834
+ <div className="flex-1">
835
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary">
836
+ {connection.user?.username || 'Vercel User'}
837
+ </h4>
838
+ <p className="text-sm text-bolt-elements-textSecondary">
839
+ {connection.user?.email || 'No email available'}
840
+ </p>
841
+ <div className="flex items-center gap-4 mt-2 text-xs text-bolt-elements-textSecondary">
842
+ <span className="flex items-center gap-1">
843
+ <div className="i-ph:buildings w-3 h-3" />
844
+ {connection.stats?.totalProjects || 0} Projects
845
+ </span>
846
+ <span className="flex items-center gap-1">
847
+ <div className="i-ph:check-circle w-3 h-3" />
848
+ {connection.stats?.projects.filter((p) => p.latestDeployments?.[0]?.state === 'READY').length ||
849
+ 0}{' '}
850
+ Live
851
+ </span>
852
+ <span className="flex items-center gap-1">
853
+ <div className="i-ph:users w-3 h-3" />
854
+ {/* Team size would be fetched from API */}
855
+ --
856
+ </span>
857
+ </div>
858
+ </div>
859
+ </div>
860
+
861
+ {/* Usage Metrics */}
862
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
863
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
864
+ <div className="flex items-center gap-2 mb-2">
865
+ <div className="i-ph:buildings w-4 h-4 text-bolt-elements-item-contentAccent" />
866
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Projects</span>
867
+ </div>
868
+ <div className="text-sm text-bolt-elements-textSecondary">
869
+ <div>
870
+ Active:{' '}
871
+ {connection.stats?.projects.filter((p) => p.latestDeployments?.[0]?.state === 'READY').length ||
872
+ 0}
873
+ </div>
874
+ <div>Total: {connection.stats?.totalProjects || 0}</div>
875
+ </div>
876
+ </div>
877
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
878
+ <div className="flex items-center gap-2 mb-2">
879
+ <div className="i-ph:globe w-4 h-4 text-bolt-elements-item-contentAccent" />
880
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Domains</span>
881
+ </div>
882
+ <div className="text-sm text-bolt-elements-textSecondary">
883
+ {/* Domain usage would be fetched from API */}
884
+ <div>Custom: --</div>
885
+ <div>Vercel: --</div>
886
+ </div>
887
+ </div>
888
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
889
+ <div className="flex items-center gap-2 mb-2">
890
+ <div className="i-ph:activity w-4 h-4 text-bolt-elements-item-contentAccent" />
891
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Usage</span>
892
+ </div>
893
+ <div className="text-sm text-bolt-elements-textSecondary">
894
+ {/* Usage metrics would be fetched from API */}
895
+ <div>Bandwidth: --</div>
896
+ <div>Requests: --</div>
897
+ </div>
898
+ </div>
899
+ </div>
900
+ </div>
901
+
902
+ {renderProjects()}
903
+ </div>
904
+ )}
905
+ </div>
906
+ </motion.div>
907
+ </div>
908
+ );
909
+ }