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,1089 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { toast } from 'react-toastify';
4
+ import { useStore } from '@nanostores/react';
5
+ import { classNames } from '~/utils/classNames';
6
+ import { Button } from '~/components/ui/Button';
7
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '~/components/ui/Collapsible';
8
+ import {
9
+ supabaseConnection,
10
+ isConnecting,
11
+ isFetchingStats,
12
+ isFetchingApiKeys,
13
+ updateSupabaseConnection,
14
+ fetchSupabaseStats,
15
+ fetchProjectApiKeys,
16
+ initializeSupabaseConnection,
17
+ type SupabaseProject,
18
+ } from '~/lib/stores/supabase';
19
+
20
+ interface ConnectionTestResult {
21
+ status: 'success' | 'error' | 'testing';
22
+ message: string;
23
+ timestamp?: number;
24
+ }
25
+
26
+ interface ProjectAction {
27
+ name: string;
28
+ icon: string;
29
+ action: (projectId: string) => Promise<void>;
30
+ requiresConfirmation?: boolean;
31
+ variant?: 'default' | 'destructive' | 'outline';
32
+ }
33
+
34
+ // Supabase logo SVG component
35
+ const SupabaseLogo = () => (
36
+ <svg viewBox="0 0 109 113" className="w-5 h-5">
37
+ <path
38
+ fill="currentColor"
39
+ d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z"
40
+ />
41
+ <path
42
+ fillOpacity="0.2"
43
+ fill="currentColor"
44
+ d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z"
45
+ />
46
+ <path
47
+ fill="currentColor"
48
+ d="M45.317 2.07103C48.1765 -1.53037 53.9745 0.442937 54.0434 5.041L54.4849 72.2922H9.83113C1.64038 72.2922 -2.92775 62.8321 2.1655 56.4175L45.317 2.07103Z"
49
+ />
50
+ </svg>
51
+ );
52
+
53
+ export default function SupabaseTab() {
54
+ const connection = useStore(supabaseConnection);
55
+ const connecting = useStore(isConnecting);
56
+ const fetchingStats = useStore(isFetchingStats);
57
+ const fetchingApiKeys = useStore(isFetchingApiKeys);
58
+
59
+ const [tokenInput, setTokenInput] = useState('');
60
+ const [isProjectsExpanded, setIsProjectsExpanded] = useState(false);
61
+ const [connectionTest, setConnectionTest] = useState<ConnectionTestResult | null>(null);
62
+ const [isProjectActionLoading, setIsProjectActionLoading] = useState(false);
63
+ const [selectedProjectId, setSelectedProjectId] = useState<string>('');
64
+
65
+ // Connection testing function - uses server-side API to test environment token
66
+ const testConnection = async () => {
67
+ setConnectionTest({
68
+ status: 'testing',
69
+ message: 'Testing connection...',
70
+ });
71
+
72
+ try {
73
+ const response = await fetch('/api/supabase-user', {
74
+ method: 'GET',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ },
78
+ });
79
+
80
+ if (response.ok) {
81
+ const data = (await response.json()) as any;
82
+ setConnectionTest({
83
+ status: 'success',
84
+ message: `Connected successfully using environment token. Found ${data.projects?.length || 0} projects`,
85
+ timestamp: Date.now(),
86
+ });
87
+ } else {
88
+ const errorData = (await response.json().catch(() => ({}))) as { error?: string };
89
+ setConnectionTest({
90
+ status: 'error',
91
+ message: `Connection failed: ${errorData.error || `${response.status} ${response.statusText}`}`,
92
+ timestamp: Date.now(),
93
+ });
94
+ }
95
+ } catch (error) {
96
+ setConnectionTest({
97
+ status: 'error',
98
+ message: `Connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
99
+ timestamp: Date.now(),
100
+ });
101
+ }
102
+ };
103
+
104
+ // Project actions
105
+ const projectActions: ProjectAction[] = [
106
+ {
107
+ name: 'Get API Keys',
108
+ icon: 'i-ph:key',
109
+ action: async (projectId: string) => {
110
+ try {
111
+ await fetchProjectApiKeys(projectId, connection.token);
112
+ toast.success('API keys fetched successfully');
113
+ } catch (err: unknown) {
114
+ const error = err instanceof Error ? err.message : 'Unknown error';
115
+ toast.error(`Failed to fetch API keys: ${error}`);
116
+ }
117
+ },
118
+ },
119
+ {
120
+ name: 'View Dashboard',
121
+ icon: 'i-ph:layout',
122
+ action: async (projectId: string) => {
123
+ window.open(`https://supabase.com/dashboard/project/${projectId}`, '_blank');
124
+ },
125
+ },
126
+ {
127
+ name: 'View Database',
128
+ icon: 'i-ph:database',
129
+ action: async (projectId: string) => {
130
+ window.open(`https://supabase.com/dashboard/project/${projectId}/editor`, '_blank');
131
+ },
132
+ },
133
+ {
134
+ name: 'View Auth',
135
+ icon: 'i-ph:user-circle',
136
+ action: async (projectId: string) => {
137
+ window.open(`https://supabase.com/dashboard/project/${projectId}/auth/users`, '_blank');
138
+ },
139
+ },
140
+ {
141
+ name: 'View Storage',
142
+ icon: 'i-ph:folder',
143
+ action: async (projectId: string) => {
144
+ window.open(`https://supabase.com/dashboard/project/${projectId}/storage/buckets`, '_blank');
145
+ },
146
+ },
147
+ {
148
+ name: 'View Functions',
149
+ icon: 'i-ph:code',
150
+ action: async (projectId: string) => {
151
+ window.open(`https://supabase.com/dashboard/project/${projectId}/functions`, '_blank');
152
+ },
153
+ },
154
+ {
155
+ name: 'View Logs',
156
+ icon: 'i-ph:scroll',
157
+ action: async (projectId: string) => {
158
+ window.open(`https://supabase.com/dashboard/project/${projectId}/logs`, '_blank');
159
+ },
160
+ },
161
+ {
162
+ name: 'View Settings',
163
+ icon: 'i-ph:gear',
164
+ action: async (projectId: string) => {
165
+ window.open(`https://supabase.com/dashboard/project/${projectId}/settings`, '_blank');
166
+ },
167
+ },
168
+ {
169
+ name: 'View API Docs',
170
+ icon: 'i-ph:book',
171
+ action: async (projectId: string) => {
172
+ window.open(`https://supabase.com/dashboard/project/${projectId}/api`, '_blank');
173
+ },
174
+ },
175
+ {
176
+ name: 'View Realtime',
177
+ icon: 'i-ph:radio',
178
+ action: async (projectId: string) => {
179
+ window.open(`https://supabase.com/dashboard/project/${projectId}/realtime`, '_blank');
180
+ },
181
+ },
182
+ {
183
+ name: 'View Edge Functions',
184
+ icon: 'i-ph:terminal',
185
+ action: async (projectId: string) => {
186
+ window.open(`https://supabase.com/dashboard/project/${projectId}/functions`, '_blank');
187
+ },
188
+ },
189
+ ];
190
+
191
+ // Initialize connection on component mount - check server-side token first
192
+ useEffect(() => {
193
+ const initializeConnection = async () => {
194
+ try {
195
+ // First try to initialize using server-side token
196
+ await initializeSupabaseConnection();
197
+
198
+ // If no connection was established, the user will need to manually enter a token
199
+ const currentState = supabaseConnection.get();
200
+
201
+ if (!currentState.user) {
202
+ console.log('No server-side Supabase token available, manual connection required');
203
+ }
204
+ } catch (error) {
205
+ console.error('Failed to initialize Supabase connection:', error);
206
+ }
207
+ };
208
+ initializeConnection();
209
+ }, []);
210
+
211
+ useEffect(() => {
212
+ const fetchProjects = async () => {
213
+ if (connection.user && connection.token && !connection.stats) {
214
+ await fetchSupabaseStats(connection.token);
215
+ }
216
+ };
217
+ fetchProjects();
218
+ }, [connection.user, connection.token]);
219
+
220
+ const handleConnect = async () => {
221
+ if (!tokenInput) {
222
+ toast.error('Please enter a Supabase access token');
223
+ return;
224
+ }
225
+
226
+ isConnecting.set(true);
227
+
228
+ try {
229
+ await fetchSupabaseStats(tokenInput);
230
+ updateSupabaseConnection({
231
+ token: tokenInput,
232
+ isConnected: true,
233
+ });
234
+ toast.success('Successfully connected to Supabase');
235
+ setTokenInput('');
236
+ } catch (error) {
237
+ console.error('Auth error:', error);
238
+ toast.error('Failed to connect to Supabase');
239
+ updateSupabaseConnection({ user: null, token: '' });
240
+ } finally {
241
+ isConnecting.set(false);
242
+ }
243
+ };
244
+
245
+ const handleDisconnect = () => {
246
+ updateSupabaseConnection({
247
+ user: null,
248
+ token: '',
249
+ stats: undefined,
250
+ selectedProjectId: undefined,
251
+ isConnected: false,
252
+ project: undefined,
253
+ credentials: undefined,
254
+ });
255
+ setConnectionTest(null);
256
+ setSelectedProjectId('');
257
+ toast.success('Disconnected from Supabase');
258
+ };
259
+
260
+ const handleProjectAction = async (projectId: string, action: ProjectAction) => {
261
+ if (action.requiresConfirmation) {
262
+ if (!confirm(`Are you sure you want to ${action.name.toLowerCase()}?`)) {
263
+ return;
264
+ }
265
+ }
266
+
267
+ setIsProjectActionLoading(true);
268
+ await action.action(projectId);
269
+ setIsProjectActionLoading(false);
270
+ };
271
+
272
+ const handleProjectSelect = async (projectId: string) => {
273
+ setSelectedProjectId(projectId);
274
+ updateSupabaseConnection({ selectedProjectId: projectId });
275
+
276
+ if (projectId && connection.token) {
277
+ try {
278
+ await fetchProjectApiKeys(projectId, connection.token);
279
+ } catch (error) {
280
+ console.error('Failed to fetch API keys:', error);
281
+ }
282
+ }
283
+ };
284
+
285
+ const renderProjects = () => {
286
+ if (fetchingStats) {
287
+ return (
288
+ <div className="flex items-center gap-2 text-sm text-bolt-elements-textSecondary">
289
+ <div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
290
+ Fetching Supabase projects...
291
+ </div>
292
+ );
293
+ }
294
+
295
+ return (
296
+ <Collapsible open={isProjectsExpanded} onOpenChange={setIsProjectsExpanded}>
297
+ <CollapsibleTrigger asChild>
298
+ <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">
299
+ <div className="flex items-center gap-2">
300
+ <div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
301
+ <span className="text-sm font-medium text-bolt-elements-textPrimary">
302
+ Your Projects ({connection.stats?.totalProjects || 0})
303
+ </span>
304
+ </div>
305
+ <div
306
+ className={classNames(
307
+ 'i-ph:caret-down w-4 h-4 transform transition-transform duration-200 text-bolt-elements-textSecondary',
308
+ isProjectsExpanded ? 'rotate-180' : '',
309
+ )}
310
+ />
311
+ </div>
312
+ </CollapsibleTrigger>
313
+ <CollapsibleContent className="overflow-hidden">
314
+ <div className="space-y-4 mt-4">
315
+ {/* Supabase Overview Dashboard */}
316
+ {connection.stats?.projects?.length ? (
317
+ <div className="mb-6 p-4 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
318
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Supabase Overview</h4>
319
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
320
+ <div className="text-center">
321
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
322
+ {connection.stats.totalProjects}
323
+ </div>
324
+ <div className="text-xs text-bolt-elements-textSecondary">Total Projects</div>
325
+ </div>
326
+ <div className="text-center">
327
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
328
+ {connection.stats.projects.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY').length}
329
+ </div>
330
+ <div className="text-xs text-bolt-elements-textSecondary">Active Projects</div>
331
+ </div>
332
+ <div className="text-center">
333
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
334
+ {new Set(connection.stats.projects.map((p: SupabaseProject) => p.region)).size}
335
+ </div>
336
+ <div className="text-xs text-bolt-elements-textSecondary">Regions Used</div>
337
+ </div>
338
+ <div className="text-center">
339
+ <div className="text-2xl font-bold text-bolt-elements-textPrimary">
340
+ {connection.stats.projects.filter((p: SupabaseProject) => p.status !== 'ACTIVE_HEALTHY').length}
341
+ </div>
342
+ <div className="text-xs text-bolt-elements-textSecondary">Inactive Projects</div>
343
+ </div>
344
+ </div>
345
+ </div>
346
+ ) : null}
347
+
348
+ {connection.stats?.projects?.length ? (
349
+ <div className="grid gap-3">
350
+ {connection.stats.projects.map((project: SupabaseProject) => (
351
+ <div
352
+ key={project.id}
353
+ className={classNames(
354
+ 'p-4 rounded-lg border transition-colors bg-bolt-elements-background-depth-1 cursor-pointer',
355
+ selectedProjectId === project.id
356
+ ? 'border-bolt-elements-item-contentAccent bg-bolt-elements-item-backgroundActive/10'
357
+ : 'border-bolt-elements-borderColor hover:border-bolt-elements-borderColorActive/70',
358
+ )}
359
+ onClick={() => handleProjectSelect(project.id)}
360
+ >
361
+ <div className="flex items-center justify-between">
362
+ <div className="flex-1">
363
+ <h5 className="text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2">
364
+ <div className="i-ph:database w-4 h-4 text-bolt-elements-borderColorActive" />
365
+ {project.name}
366
+ </h5>
367
+ <div className="flex items-center gap-2 mt-2 text-xs text-bolt-elements-textSecondary">
368
+ <span className="flex items-center gap-1">
369
+ <div className="i-ph:globe w-3 h-3" />
370
+ {project.region}
371
+ </span>
372
+ <span>•</span>
373
+ <span className="flex items-center gap-1">
374
+ <div className="i-ph:clock w-3 h-3" />
375
+ {new Date(project.created_at).toLocaleDateString()}
376
+ </span>
377
+ <span>•</span>
378
+ <span
379
+ className={classNames(
380
+ 'flex items-center gap-1 px-2 py-0.5 rounded-full text-xs',
381
+ project.status === 'ACTIVE_HEALTHY'
382
+ ? 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400'
383
+ : project.status === 'SUSPENDED'
384
+ ? 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400'
385
+ : project.status === 'INACTIVE'
386
+ ? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400'
387
+ : 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400',
388
+ )}
389
+ >
390
+ <div
391
+ className={classNames(
392
+ 'w-2 h-2 rounded-full',
393
+ project.status === 'ACTIVE_HEALTHY'
394
+ ? 'bg-green-500'
395
+ : project.status === 'SUSPENDED'
396
+ ? 'bg-red-500'
397
+ : project.status === 'INACTIVE'
398
+ ? 'bg-yellow-500'
399
+ : 'bg-gray-500',
400
+ )}
401
+ />
402
+ {project.status.replace('_', ' ')}
403
+ </span>
404
+ </div>
405
+
406
+ {/* Project Details Grid */}
407
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mt-3 pt-3 border-t border-bolt-elements-borderColor">
408
+ <div className="text-center">
409
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
410
+ {project.stats?.database?.tables ?? '--'}
411
+ </div>
412
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
413
+ <div className="i-ph:table w-3 h-3" />
414
+ Tables
415
+ </div>
416
+ </div>
417
+ <div className="text-center">
418
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
419
+ {project.stats?.storage?.buckets ?? '--'}
420
+ </div>
421
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
422
+ <div className="i-ph:folder w-3 h-3" />
423
+ Buckets
424
+ </div>
425
+ </div>
426
+ <div className="text-center">
427
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
428
+ {project.stats?.functions?.deployed ?? '--'}
429
+ </div>
430
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
431
+ <div className="i-ph:code w-3 h-3" />
432
+ Functions
433
+ </div>
434
+ </div>
435
+ <div className="text-center">
436
+ <div className="text-sm font-semibold text-bolt-elements-textPrimary">
437
+ {project.stats?.database?.size_mb ? `${project.stats.database.size_mb} MB` : '--'}
438
+ </div>
439
+ <div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
440
+ <div className="i-ph:database w-3 h-3" />
441
+ DB Size
442
+ </div>
443
+ </div>
444
+ </div>
445
+ </div>
446
+ </div>
447
+
448
+ {selectedProjectId === project.id && (
449
+ <div className="space-y-4 mt-4 pt-4 border-t border-bolt-elements-borderColor">
450
+ <div className="flex flex-wrap items-center gap-1">
451
+ {projectActions.map((action) => (
452
+ <Button
453
+ key={action.name}
454
+ variant={action.variant || 'outline'}
455
+ size="sm"
456
+ onClick={(e) => {
457
+ e.stopPropagation();
458
+ handleProjectAction(project.id, action);
459
+ }}
460
+ disabled={isProjectActionLoading || (action.name === 'Get API Keys' && fetchingApiKeys)}
461
+ className="flex items-center gap-1 text-xs px-2 py-1 text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary"
462
+ >
463
+ <div className={`${action.icon} w-2.5 h-2.5`} />
464
+ {action.name === 'Get API Keys' && fetchingApiKeys ? 'Fetching...' : action.name}
465
+ </Button>
466
+ ))}
467
+ </div>
468
+
469
+ {/* Project Details */}
470
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
471
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
472
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
473
+ <div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
474
+ Database Schema
475
+ </h6>
476
+ <div className="space-y-1 text-xs text-bolt-elements-textSecondary">
477
+ <div className="flex justify-between">
478
+ <span>Tables:</span>
479
+ <span>{project.stats?.database?.tables ?? '--'}</span>
480
+ </div>
481
+ <div className="flex justify-between">
482
+ <span>Views:</span>
483
+ <span>{project.stats?.database?.views ?? '--'}</span>
484
+ </div>
485
+ <div className="flex justify-between">
486
+ <span>Functions:</span>
487
+ <span>{project.stats?.database?.functions ?? '--'}</span>
488
+ </div>
489
+ <div className="flex justify-between">
490
+ <span>Size:</span>
491
+ <span>
492
+ {project.stats?.database?.size_mb ? `${project.stats.database.size_mb} MB` : '--'}
493
+ </span>
494
+ </div>
495
+ </div>
496
+ </div>
497
+
498
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
499
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
500
+ <div className="i-ph:folder w-4 h-4 text-bolt-elements-item-contentAccent" />
501
+ Storage
502
+ </h6>
503
+ <div className="space-y-1 text-xs text-bolt-elements-textSecondary">
504
+ <div className="flex justify-between">
505
+ <span>Buckets:</span>
506
+ <span>{project.stats?.storage?.buckets ?? '--'}</span>
507
+ </div>
508
+ <div className="flex justify-between">
509
+ <span>Files:</span>
510
+ <span>{project.stats?.storage?.files ?? '--'}</span>
511
+ </div>
512
+ <div className="flex justify-between">
513
+ <span>Used:</span>
514
+ <span>
515
+ {project.stats?.storage?.used_gb ? `${project.stats.storage.used_gb} GB` : '--'}
516
+ </span>
517
+ </div>
518
+ <div className="flex justify-between">
519
+ <span>Available:</span>
520
+ <span>
521
+ {project.stats?.storage?.available_gb
522
+ ? `${project.stats.storage.available_gb} GB`
523
+ : '--'}
524
+ </span>
525
+ </div>
526
+ </div>
527
+ </div>
528
+ </div>
529
+
530
+ {connection.credentials && (
531
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
532
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
533
+ <div className="i-ph:key w-4 h-4 text-bolt-elements-item-contentAccent" />
534
+ Project Credentials
535
+ </h6>
536
+ <div className="space-y-2">
537
+ <div>
538
+ <label className="text-xs text-bolt-elements-textSecondary">Supabase URL:</label>
539
+ <div className="flex items-center gap-2 mt-1">
540
+ <input
541
+ type="text"
542
+ value={connection.credentials.supabaseUrl || ''}
543
+ readOnly
544
+ className="flex-1 px-2 py-1 text-xs bg-bolt-elements-background border border-bolt-elements-borderColor rounded"
545
+ />
546
+ <Button
547
+ size="icon"
548
+ variant="outline"
549
+ onClick={(e) => {
550
+ e.stopPropagation();
551
+
552
+ if (connection.credentials?.supabaseUrl) {
553
+ navigator.clipboard.writeText(connection.credentials.supabaseUrl);
554
+ toast.success('URL copied to clipboard');
555
+ }
556
+ }}
557
+ className="w-8 h-8"
558
+ >
559
+ <div className="i-ph:copy w-3 h-3" />
560
+ </Button>
561
+ </div>
562
+ </div>
563
+ <div>
564
+ <label className="text-xs text-bolt-elements-textSecondary">Anon Key:</label>
565
+ <div className="flex items-center gap-2 mt-1">
566
+ <input
567
+ type="password"
568
+ value={connection.credentials.anonKey || ''}
569
+ readOnly
570
+ className="flex-1 px-2 py-1 text-xs bg-bolt-elements-background border border-bolt-elements-borderColor rounded"
571
+ />
572
+ <Button
573
+ size="icon"
574
+ variant="outline"
575
+ onClick={(e) => {
576
+ e.stopPropagation();
577
+
578
+ if (connection.credentials?.anonKey) {
579
+ navigator.clipboard.writeText(connection.credentials.anonKey);
580
+ toast.success('Key copied to clipboard');
581
+ }
582
+ }}
583
+ className="w-8 h-8"
584
+ >
585
+ <div className="i-ph:copy w-3 h-3" />
586
+ </Button>
587
+ </div>
588
+ </div>
589
+ </div>
590
+ </div>
591
+ )}
592
+ </div>
593
+ )}
594
+ </div>
595
+ ))}
596
+ </div>
597
+ ) : (
598
+ <div className="text-sm text-bolt-elements-textSecondary flex items-center gap-2 p-4">
599
+ <div className="i-ph:info w-4 h-4" />
600
+ No projects found in your Supabase account
601
+ </div>
602
+ )}
603
+ </div>
604
+ </CollapsibleContent>
605
+ </Collapsible>
606
+ );
607
+ };
608
+
609
+ return (
610
+ <div className="space-y-6">
611
+ {/* Header */}
612
+ <motion.div
613
+ className="flex items-center justify-between gap-2"
614
+ initial={{ opacity: 0, y: 20 }}
615
+ animate={{ opacity: 1, y: 0 }}
616
+ transition={{ delay: 0.1 }}
617
+ >
618
+ <div className="flex items-center gap-2">
619
+ <div className="text-[#3ECF8E]">
620
+ <SupabaseLogo />
621
+ </div>
622
+ <h2 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
623
+ Supabase Integration
624
+ </h2>
625
+ </div>
626
+ <div className="flex items-center gap-2">
627
+ {connection.user && (
628
+ <Button
629
+ onClick={testConnection}
630
+ disabled={connectionTest?.status === 'testing'}
631
+ variant="outline"
632
+ size="sm"
633
+ className="flex items-center gap-2 hover:bg-bolt-elements-item-backgroundActive/10 hover:text-bolt-elements-textPrimary dark:hover:bg-bolt-elements-item-backgroundActive/10 dark:hover:text-bolt-elements-textPrimary transition-colors"
634
+ >
635
+ {connectionTest?.status === 'testing' ? (
636
+ <>
637
+ <div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
638
+ Testing...
639
+ </>
640
+ ) : (
641
+ <>
642
+ <div className="i-ph:plug-charging w-4 h-4" />
643
+ Test Connection
644
+ </>
645
+ )}
646
+ </Button>
647
+ )}
648
+ </div>
649
+ </motion.div>
650
+
651
+ <p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
652
+ Connect and manage your Supabase projects with database access, authentication, and storage controls
653
+ </p>
654
+
655
+ {/* Connection Test Results */}
656
+ {connectionTest && (
657
+ <motion.div
658
+ className={classNames('p-4 rounded-lg border', {
659
+ 'bg-green-50 border-green-200 dark:bg-green-900/20 dark:border-green-700':
660
+ connectionTest.status === 'success',
661
+ 'bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-700': connectionTest.status === 'error',
662
+ 'bg-blue-50 border-blue-200 dark:bg-blue-900/20 dark:border-blue-700': connectionTest.status === 'testing',
663
+ })}
664
+ initial={{ opacity: 0, y: 10 }}
665
+ animate={{ opacity: 1, y: 0 }}
666
+ >
667
+ <div className="flex items-center gap-2">
668
+ {connectionTest.status === 'success' && (
669
+ <div className="i-ph:check-circle w-5 h-5 text-green-600 dark:text-green-400" />
670
+ )}
671
+ {connectionTest.status === 'error' && (
672
+ <div className="i-ph:warning-circle w-5 h-5 text-red-600 dark:text-red-400" />
673
+ )}
674
+ {connectionTest.status === 'testing' && (
675
+ <div className="i-ph:spinner-gap w-5 h-5 animate-spin text-blue-600 dark:text-blue-400" />
676
+ )}
677
+ <span
678
+ className={classNames('text-sm font-medium', {
679
+ 'text-green-800 dark:text-green-200': connectionTest.status === 'success',
680
+ 'text-red-800 dark:text-red-200': connectionTest.status === 'error',
681
+ 'text-blue-800 dark:text-blue-200': connectionTest.status === 'testing',
682
+ })}
683
+ >
684
+ {connectionTest.message}
685
+ </span>
686
+ </div>
687
+ {connectionTest.timestamp && (
688
+ <p className="text-xs text-gray-500 mt-1">{new Date(connectionTest.timestamp).toLocaleString()}</p>
689
+ )}
690
+ </motion.div>
691
+ )}
692
+
693
+ {/* Main Connection Component */}
694
+ <motion.div
695
+ className="bg-bolt-elements-background dark:bg-bolt-elements-background border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor rounded-lg"
696
+ initial={{ opacity: 0, y: 20 }}
697
+ animate={{ opacity: 1, y: 0 }}
698
+ transition={{ delay: 0.2 }}
699
+ >
700
+ <div className="p-6 space-y-6">
701
+ {!connection.user ? (
702
+ <div className="space-y-4">
703
+ <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">
704
+ <p className="flex items-center gap-1 mb-1">
705
+ <span className="i-ph:lightbulb w-3.5 h-3.5 text-bolt-elements-icon-success dark:text-bolt-elements-icon-success" />
706
+ <span className="font-medium">Tip:</span> You can also set the{' '}
707
+ <code className="px-1 py-0.5 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 rounded">
708
+ VITE_SUPABASE_ACCESS_TOKEN
709
+ </code>{' '}
710
+ environment variable to connect automatically.
711
+ </p>
712
+ </div>
713
+
714
+ <div>
715
+ <label className="block text-sm text-bolt-elements-textSecondary mb-2">Access Token</label>
716
+ <input
717
+ type="password"
718
+ value={tokenInput}
719
+ onChange={(e) => setTokenInput(e.target.value)}
720
+ disabled={connecting}
721
+ placeholder="Enter your Supabase access token"
722
+ className={classNames(
723
+ 'w-full px-3 py-2 rounded-lg text-sm',
724
+ 'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
725
+ 'border border-[#E5E5E5] dark:border-[#333333]',
726
+ 'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
727
+ 'focus:outline-none focus:ring-1 focus:ring-bolt-elements-borderColorActive',
728
+ 'disabled:opacity-50',
729
+ )}
730
+ />
731
+ <div className="mt-2 text-sm text-bolt-elements-textSecondary">
732
+ <a
733
+ href="https://supabase.com/dashboard/account/tokens"
734
+ target="_blank"
735
+ rel="noopener noreferrer"
736
+ className="text-bolt-elements-borderColorActive hover:underline inline-flex items-center gap-1"
737
+ >
738
+ Get your token
739
+ <div className="i-ph:arrow-square-out w-4 h-4" />
740
+ </a>
741
+ </div>
742
+ </div>
743
+
744
+ <button
745
+ onClick={handleConnect}
746
+ disabled={connecting || !tokenInput}
747
+ className={classNames(
748
+ 'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
749
+ 'bg-[#303030] text-white',
750
+ 'hover:bg-[#5E41D0] hover:text-white',
751
+ 'disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200',
752
+ 'transform active:scale-95',
753
+ )}
754
+ >
755
+ {connecting ? (
756
+ <>
757
+ <div className="i-ph:spinner-gap animate-spin" />
758
+ Connecting...
759
+ </>
760
+ ) : (
761
+ <>
762
+ <div className="i-ph:plug-charging w-4 h-4" />
763
+ Connect
764
+ </>
765
+ )}
766
+ </button>
767
+ </div>
768
+ ) : (
769
+ <div className="space-y-6">
770
+ <div className="flex items-center justify-between">
771
+ <div className="flex items-center gap-3">
772
+ <button
773
+ onClick={handleDisconnect}
774
+ className={classNames(
775
+ 'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
776
+ 'bg-red-500 text-white',
777
+ 'hover:bg-red-600',
778
+ )}
779
+ >
780
+ <div className="i-ph:plug w-4 h-4" />
781
+ Disconnect
782
+ </button>
783
+ <span className="text-sm text-bolt-elements-textSecondary flex items-center gap-1">
784
+ <div className="i-ph:check-circle w-4 h-4 text-green-500" />
785
+ Connected to Supabase
786
+ </span>
787
+ </div>
788
+ </div>
789
+
790
+ {connection.user && (
791
+ <div className="space-y-4">
792
+ <div className="flex items-center gap-4 p-4 bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 rounded-lg">
793
+ <div className="w-12 h-12 rounded-full bg-gradient-to-br from-green-400 to-green-600 flex items-center justify-center">
794
+ <div className="i-ph:user w-6 h-6 text-white" />
795
+ </div>
796
+ <div className="flex-1">
797
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary">{connection.user.email}</h4>
798
+ <p className="text-sm text-bolt-elements-textSecondary">
799
+ {connection.user.role} • Member since{' '}
800
+ {new Date(connection.user.created_at).toLocaleDateString()}
801
+ </p>
802
+ <div className="flex items-center gap-4 mt-2 text-xs text-bolt-elements-textSecondary">
803
+ <span className="flex items-center gap-1">
804
+ <div className="i-ph:buildings w-3 h-3" />
805
+ {connection.stats?.totalProjects || 0} Projects
806
+ </span>
807
+ <span className="flex items-center gap-1">
808
+ <div className="i-ph:globe w-3 h-3" />
809
+ {new Set(connection.stats?.projects?.map((p: SupabaseProject) => p.region) || []).size}{' '}
810
+ Regions
811
+ </span>
812
+ <span className="flex items-center gap-1">
813
+ <div className="i-ph:activity w-3 h-3" />
814
+ {connection.stats?.projects?.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY')
815
+ .length || 0}{' '}
816
+ Active
817
+ </span>
818
+ </div>
819
+ </div>
820
+ </div>
821
+
822
+ {/* Advanced Analytics */}
823
+ <div className="mb-6 space-y-4">
824
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary">Performance Analytics</h4>
825
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
826
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
827
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
828
+ <div className="i-ph:chart-line w-4 h-4 text-bolt-elements-item-contentAccent" />
829
+ Database Health
830
+ </h6>
831
+ <div className="space-y-1">
832
+ {(() => {
833
+ const totalProjects = connection.stats?.totalProjects || 0;
834
+ const activeProjects =
835
+ connection.stats?.projects?.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY')
836
+ .length || 0;
837
+ const healthRate =
838
+ totalProjects > 0 ? Math.round((activeProjects / totalProjects) * 100) : 0;
839
+ const avgTablesPerProject =
840
+ totalProjects > 0
841
+ ? Math.round(
842
+ (connection.stats?.projects?.reduce(
843
+ (sum, p) => sum + (p.stats?.database?.tables || 0),
844
+ 0,
845
+ ) || 0) / totalProjects,
846
+ )
847
+ : 0;
848
+
849
+ return [
850
+ { label: 'Health Rate', value: `${healthRate}%` },
851
+ { label: 'Active Projects', value: activeProjects },
852
+ { label: 'Avg Tables/Project', value: avgTablesPerProject },
853
+ ];
854
+ })().map((item, idx) => (
855
+ <div key={idx} className="flex justify-between text-xs">
856
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
857
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
858
+ </div>
859
+ ))}
860
+ </div>
861
+ </div>
862
+
863
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
864
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
865
+ <div className="i-ph:shield-check w-4 h-4 text-bolt-elements-item-contentAccent" />
866
+ Auth & Security
867
+ </h6>
868
+ <div className="space-y-1">
869
+ {(() => {
870
+ const totalProjects = connection.stats?.totalProjects || 0;
871
+ const projectsWithAuth =
872
+ connection.stats?.projects?.filter((p) => p.stats?.auth?.users !== undefined).length || 0;
873
+ const authEnabledRate =
874
+ totalProjects > 0 ? Math.round((projectsWithAuth / totalProjects) * 100) : 0;
875
+ const totalUsers =
876
+ connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.auth?.users || 0), 0) || 0;
877
+
878
+ return [
879
+ { label: 'Auth Enabled', value: `${authEnabledRate}%` },
880
+ { label: 'Total Users', value: totalUsers },
881
+ {
882
+ label: 'Avg Users/Project',
883
+ value: totalProjects > 0 ? Math.round(totalUsers / totalProjects) : 0,
884
+ },
885
+ ];
886
+ })().map((item, idx) => (
887
+ <div key={idx} className="flex justify-between text-xs">
888
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
889
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
890
+ </div>
891
+ ))}
892
+ </div>
893
+ </div>
894
+
895
+ <div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
896
+ <h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
897
+ <div className="i-ph:globe w-4 h-4 text-bolt-elements-item-contentAccent" />
898
+ Regional Distribution
899
+ </h6>
900
+ <div className="space-y-1">
901
+ {(() => {
902
+ const regions =
903
+ connection.stats?.projects?.reduce(
904
+ (acc, p: SupabaseProject) => {
905
+ acc[p.region] = (acc[p.region] || 0) + 1;
906
+ return acc;
907
+ },
908
+ {} as Record<string, number>,
909
+ ) || {};
910
+
911
+ return Object.entries(regions)
912
+ .sort(([, a], [, b]) => b - a)
913
+ .slice(0, 3)
914
+ .map(([region, count]) => ({ label: region.toUpperCase(), value: count }));
915
+ })().map((item, idx) => (
916
+ <div key={idx} className="flex justify-between text-xs">
917
+ <span className="text-bolt-elements-textSecondary">{item.label}:</span>
918
+ <span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
919
+ </div>
920
+ ))}
921
+ </div>
922
+ </div>
923
+ </div>
924
+ </div>
925
+
926
+ {/* Resource Utilization */}
927
+ <div className="mb-6">
928
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-2">Resource Overview</h4>
929
+ <div className="grid grid-cols-2 md:grid-cols-5 gap-4">
930
+ {(() => {
931
+ const totalDatabase =
932
+ connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.size_mb || 0), 0) ||
933
+ 0;
934
+ const totalStorage =
935
+ connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.used_gb || 0), 0) ||
936
+ 0;
937
+ const totalFunctions =
938
+ connection.stats?.projects?.reduce(
939
+ (sum, p) => sum + (p.stats?.functions?.deployed || 0),
940
+ 0,
941
+ ) || 0;
942
+ const totalTables =
943
+ connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.tables || 0), 0) ||
944
+ 0;
945
+ const totalBuckets =
946
+ connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.buckets || 0), 0) ||
947
+ 0;
948
+
949
+ return [
950
+ {
951
+ label: 'Database',
952
+ value: totalDatabase > 0 ? `${totalDatabase} MB` : '--',
953
+ icon: 'i-ph:database',
954
+ color: 'text-blue-500',
955
+ bgColor: 'bg-blue-100 dark:bg-blue-900/20',
956
+ textColor: 'text-blue-800 dark:text-blue-400',
957
+ },
958
+ {
959
+ label: 'Storage',
960
+ value: totalStorage > 0 ? `${totalStorage} GB` : '--',
961
+ icon: 'i-ph:folder',
962
+ color: 'text-green-500',
963
+ bgColor: 'bg-green-100 dark:bg-green-900/20',
964
+ textColor: 'text-green-800 dark:text-green-400',
965
+ },
966
+ {
967
+ label: 'Functions',
968
+ value: totalFunctions,
969
+ icon: 'i-ph:code',
970
+ color: 'text-purple-500',
971
+ bgColor: 'bg-purple-100 dark:bg-purple-900/20',
972
+ textColor: 'text-purple-800 dark:text-purple-400',
973
+ },
974
+ {
975
+ label: 'Tables',
976
+ value: totalTables,
977
+ icon: 'i-ph:table',
978
+ color: 'text-orange-500',
979
+ bgColor: 'bg-orange-100 dark:bg-orange-900/20',
980
+ textColor: 'text-orange-800 dark:text-orange-400',
981
+ },
982
+ {
983
+ label: 'Buckets',
984
+ value: totalBuckets,
985
+ icon: 'i-ph:archive',
986
+ color: 'text-teal-500',
987
+ bgColor: 'bg-teal-100 dark:bg-teal-900/20',
988
+ textColor: 'text-teal-800 dark:text-teal-400',
989
+ },
990
+ ];
991
+ })().map((metric, index) => (
992
+ <div
993
+ key={index}
994
+ className={`flex flex-col p-3 rounded-lg border border-bolt-elements-borderColor ${metric.bgColor}`}
995
+ >
996
+ <div className="flex items-center gap-2 mb-1">
997
+ <div className={`${metric.icon} w-4 h-4 ${metric.color}`} />
998
+ <span className="text-xs text-bolt-elements-textSecondary">{metric.label}</span>
999
+ </div>
1000
+ <span className={`text-lg font-medium ${metric.textColor}`}>{metric.value}</span>
1001
+ </div>
1002
+ ))}
1003
+ </div>
1004
+ </div>
1005
+
1006
+ {/* Usage Metrics */}
1007
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
1008
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
1009
+ <div className="flex items-center gap-2 mb-2">
1010
+ <div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
1011
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Database</span>
1012
+ </div>
1013
+ <div className="text-sm text-bolt-elements-textSecondary">
1014
+ <div>
1015
+ Tables:{' '}
1016
+ {connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.tables || 0), 0) ||
1017
+ '--'}
1018
+ </div>
1019
+ <div>
1020
+ Size:{' '}
1021
+ {(() => {
1022
+ const totalSize =
1023
+ connection.stats?.projects?.reduce(
1024
+ (sum, p) => sum + (p.stats?.database?.size_mb || 0),
1025
+ 0,
1026
+ ) || 0;
1027
+ return totalSize > 0 ? `${totalSize} MB` : '--';
1028
+ })()}
1029
+ </div>
1030
+ </div>
1031
+ </div>
1032
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
1033
+ <div className="flex items-center gap-2 mb-2">
1034
+ <div className="i-ph:folder w-4 h-4 text-bolt-elements-item-contentAccent" />
1035
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Storage</span>
1036
+ </div>
1037
+ <div className="text-sm text-bolt-elements-textSecondary">
1038
+ <div>
1039
+ Buckets:{' '}
1040
+ {connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.buckets || 0), 0) ||
1041
+ '--'}
1042
+ </div>
1043
+ <div>
1044
+ Used:{' '}
1045
+ {(() => {
1046
+ const totalUsed =
1047
+ connection.stats?.projects?.reduce(
1048
+ (sum, p) => sum + (p.stats?.storage?.used_gb || 0),
1049
+ 0,
1050
+ ) || 0;
1051
+ return totalUsed > 0 ? `${totalUsed} GB` : '--';
1052
+ })()}
1053
+ </div>
1054
+ </div>
1055
+ </div>
1056
+ <div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
1057
+ <div className="flex items-center gap-2 mb-2">
1058
+ <div className="i-ph:code w-4 h-4 text-bolt-elements-item-contentAccent" />
1059
+ <span className="text-xs font-medium text-bolt-elements-textPrimary">Functions</span>
1060
+ </div>
1061
+ <div className="text-sm text-bolt-elements-textSecondary">
1062
+ <div>
1063
+ Deployed:{' '}
1064
+ {connection.stats?.projects?.reduce(
1065
+ (sum, p) => sum + (p.stats?.functions?.deployed || 0),
1066
+ 0,
1067
+ ) || '--'}
1068
+ </div>
1069
+ <div>
1070
+ Invocations:{' '}
1071
+ {connection.stats?.projects?.reduce(
1072
+ (sum, p) => sum + (p.stats?.functions?.invocations || 0),
1073
+ 0,
1074
+ ) || '--'}
1075
+ </div>
1076
+ </div>
1077
+ </div>
1078
+ </div>
1079
+ </div>
1080
+ )}
1081
+
1082
+ {renderProjects()}
1083
+ </div>
1084
+ )}
1085
+ </div>
1086
+ </motion.div>
1087
+ </div>
1088
+ );
1089
+ }