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,1041 @@
1
+ import * as Dialog from '@radix-ui/react-dialog';
2
+ import { useState, useEffect } from 'react';
3
+ import { toast } from 'react-toastify';
4
+ import { motion } from 'framer-motion';
5
+ import { Octokit } from '@octokit/rest';
6
+ import { classNames } from '~/utils/classNames';
7
+ import { getLocalStorage } from '~/lib/persistence/localStorage';
8
+ import type { GitHubUserResponse, GitHubRepoInfo } from '~/types/GitHub';
9
+ import { logStore } from '~/lib/stores/logs';
10
+ import { chatId } from '~/lib/persistence/useChatHistory';
11
+ import { useStore } from '@nanostores/react';
12
+ import { GitHubAuthDialog } from '~/components/@settings/tabs/github/components/GitHubAuthDialog';
13
+ import { SearchInput, EmptyState, StatusIndicator, Badge } from '~/components/ui';
14
+
15
+ interface GitHubDeploymentDialogProps {
16
+ isOpen: boolean;
17
+ onClose: () => void;
18
+ projectName: string;
19
+ files: Record<string, string>;
20
+ }
21
+
22
+ export function GitHubDeploymentDialog({ isOpen, onClose, projectName, files }: GitHubDeploymentDialogProps) {
23
+ const [repoName, setRepoName] = useState('');
24
+ const [isPrivate, setIsPrivate] = useState(false);
25
+ const [isLoading, setIsLoading] = useState(false);
26
+ const [user, setUser] = useState<GitHubUserResponse | null>(null);
27
+ const [recentRepos, setRecentRepos] = useState<GitHubRepoInfo[]>([]);
28
+ const [filteredRepos, setFilteredRepos] = useState<GitHubRepoInfo[]>([]);
29
+ const [repoSearchQuery, setRepoSearchQuery] = useState('');
30
+ const [isFetchingRepos, setIsFetchingRepos] = useState(false);
31
+ const [showSuccessDialog, setShowSuccessDialog] = useState(false);
32
+ const [createdRepoUrl, setCreatedRepoUrl] = useState('');
33
+ const [pushedFiles, setPushedFiles] = useState<{ path: string; size: number }[]>([]);
34
+ const [showAuthDialog, setShowAuthDialog] = useState(false);
35
+ const currentChatId = useStore(chatId);
36
+
37
+ /*
38
+ * Load GitHub connection on mount
39
+ * Helper function to sanitize repository name
40
+ */
41
+ const sanitizeRepoName = (name: string): string => {
42
+ return (
43
+ name
44
+ .toLowerCase()
45
+ // Replace spaces and underscores with hyphens
46
+ .replace(/[\s_]+/g, '-')
47
+ // Remove special characters except hyphens and alphanumeric
48
+ .replace(/[^a-z0-9-]/g, '')
49
+ // Remove multiple consecutive hyphens
50
+ .replace(/-+/g, '-')
51
+ // Remove leading/trailing hyphens
52
+ .replace(/^-+|-+$/g, '')
53
+ // Ensure it's not empty and has reasonable length
54
+ .substring(0, 100) || 'my-project'
55
+ );
56
+ };
57
+
58
+ useEffect(() => {
59
+ if (isOpen) {
60
+ const connection = getLocalStorage('github_connection');
61
+
62
+ // Set a default repository name based on the project name with proper sanitization
63
+ setRepoName(sanitizeRepoName(projectName));
64
+
65
+ if (connection?.user && connection?.token) {
66
+ setUser(connection.user);
67
+
68
+ // Only fetch if we have both user and token
69
+ if (connection.token.trim()) {
70
+ fetchRecentRepos(connection.token);
71
+ }
72
+ }
73
+ }
74
+ }, [isOpen, projectName]);
75
+
76
+ // Filter repositories based on search query
77
+ useEffect(() => {
78
+ if (recentRepos.length === 0) {
79
+ setFilteredRepos([]);
80
+ return;
81
+ }
82
+
83
+ if (!repoSearchQuery.trim()) {
84
+ setFilteredRepos(recentRepos);
85
+ return;
86
+ }
87
+
88
+ const query = repoSearchQuery.toLowerCase().trim();
89
+ const filtered = recentRepos.filter(
90
+ (repo) =>
91
+ repo.name.toLowerCase().includes(query) ||
92
+ (repo.description && repo.description.toLowerCase().includes(query)) ||
93
+ (repo.language && repo.language.toLowerCase().includes(query)),
94
+ );
95
+
96
+ setFilteredRepos(filtered);
97
+ }, [recentRepos, repoSearchQuery]);
98
+
99
+ const fetchRecentRepos = async (token: string) => {
100
+ if (!token) {
101
+ logStore.logError('No GitHub token available');
102
+ toast.error('GitHub authentication required');
103
+
104
+ return;
105
+ }
106
+
107
+ try {
108
+ setIsFetchingRepos(true);
109
+
110
+ // Fetch ALL repos by paginating through all pages
111
+ let allRepos: GitHubRepoInfo[] = [];
112
+ let page = 1;
113
+ let hasMore = true;
114
+
115
+ while (hasMore) {
116
+ const requestUrl = `https://api.github.com/user/repos?sort=updated&per_page=100&page=${page}&affiliation=owner,organization_member`;
117
+ const response = await fetch(requestUrl, {
118
+ headers: {
119
+ Accept: 'application/vnd.github.v3+json',
120
+ Authorization: `Bearer ${token.trim()}`,
121
+ },
122
+ });
123
+
124
+ if (!response.ok) {
125
+ let errorData: { message?: string } = {};
126
+
127
+ try {
128
+ errorData = await response.json();
129
+ } catch {
130
+ errorData = { message: 'Could not parse error response' };
131
+ }
132
+
133
+ if (response.status === 401) {
134
+ toast.error('GitHub token expired. Please reconnect your account.');
135
+
136
+ // Clear invalid token
137
+ const connection = getLocalStorage('github_connection');
138
+
139
+ if (connection) {
140
+ localStorage.removeItem('github_connection');
141
+ setUser(null);
142
+ }
143
+ } else if (response.status === 403 && response.headers.get('x-ratelimit-remaining') === '0') {
144
+ // Rate limit exceeded
145
+ const resetTime = response.headers.get('x-ratelimit-reset');
146
+ const resetDate = resetTime ? new Date(parseInt(resetTime) * 1000).toLocaleTimeString() : 'soon';
147
+ toast.error(`GitHub API rate limit exceeded. Limit resets at ${resetDate}`);
148
+ } else {
149
+ logStore.logError('Failed to fetch GitHub repositories', {
150
+ status: response.status,
151
+ statusText: response.statusText,
152
+ error: errorData,
153
+ });
154
+ toast.error(`Failed to fetch repositories: ${errorData.message || response.statusText}`);
155
+ }
156
+
157
+ return;
158
+ }
159
+
160
+ try {
161
+ const repos = (await response.json()) as GitHubRepoInfo[];
162
+ allRepos = allRepos.concat(repos);
163
+
164
+ if (repos.length < 100) {
165
+ hasMore = false;
166
+ } else {
167
+ page += 1;
168
+ }
169
+ } catch (parseError) {
170
+ logStore.logError('Failed to parse GitHub repositories response', { parseError });
171
+ toast.error('Failed to parse repository data');
172
+ setRecentRepos([]);
173
+
174
+ return;
175
+ }
176
+ }
177
+
178
+ setRecentRepos(allRepos);
179
+ } catch (error) {
180
+ logStore.logError('Failed to fetch GitHub repositories', { error });
181
+ toast.error('Failed to fetch recent repositories');
182
+ } finally {
183
+ setIsFetchingRepos(false);
184
+ }
185
+ };
186
+
187
+ // Function to create a new repository or push to an existing one
188
+ const handleSubmit = async (e: React.FormEvent) => {
189
+ e.preventDefault();
190
+
191
+ const connection = getLocalStorage('github_connection');
192
+
193
+ if (!connection?.token || !connection?.user) {
194
+ toast.error('Please connect your GitHub account in Settings > Connections first');
195
+ return;
196
+ }
197
+
198
+ if (!repoName.trim()) {
199
+ toast.error('Repository name is required');
200
+ return;
201
+ }
202
+
203
+ // Validate repository name
204
+ const sanitizedName = sanitizeRepoName(repoName);
205
+
206
+ if (!sanitizedName || sanitizedName.length < 1) {
207
+ toast.error('Repository name must contain at least one alphanumeric character');
208
+ return;
209
+ }
210
+
211
+ if (sanitizedName.length > 100) {
212
+ toast.error('Repository name is too long (maximum 100 characters)');
213
+ return;
214
+ }
215
+
216
+ // Update the repo name field with the sanitized version if it was changed
217
+ if (sanitizedName !== repoName) {
218
+ setRepoName(sanitizedName);
219
+ toast.info(`Repository name sanitized to: ${sanitizedName}`);
220
+ }
221
+
222
+ setIsLoading(true);
223
+
224
+ try {
225
+ // Initialize Octokit with the GitHub token
226
+ const octokit = new Octokit({ auth: connection.token });
227
+ let repoExists = false;
228
+
229
+ try {
230
+ // Check if the repository already exists - ensure repo name is properly sanitized
231
+ const sanitizedRepoName = sanitizeRepoName(repoName);
232
+ const { data: existingRepo } = await octokit.repos.get({
233
+ owner: connection.user.login,
234
+ repo: sanitizedRepoName,
235
+ });
236
+
237
+ repoExists = true;
238
+
239
+ // If we get here, the repo exists - confirm overwrite
240
+ let confirmMessage = `Repository "${repoName}" already exists. Do you want to update it? This will add or modify files in the repository.`;
241
+
242
+ // Add visibility change warning if needed
243
+ if (existingRepo.private !== isPrivate) {
244
+ const visibilityChange = isPrivate
245
+ ? 'This will also change the repository from public to private.'
246
+ : 'This will also change the repository from private to public.';
247
+
248
+ confirmMessage += `\n\n${visibilityChange}`;
249
+ }
250
+
251
+ const confirmOverwrite = window.confirm(confirmMessage);
252
+
253
+ if (!confirmOverwrite) {
254
+ setIsLoading(false);
255
+ return;
256
+ }
257
+
258
+ // If visibility needs to be updated
259
+ if (existingRepo.private !== isPrivate) {
260
+ await octokit.repos.update({
261
+ owner: connection.user.login,
262
+ repo: sanitizedRepoName,
263
+ private: isPrivate,
264
+ });
265
+ }
266
+ } catch (error: any) {
267
+ // 404 means repo doesn't exist, which is what we want for new repos
268
+ if (error.status !== 404) {
269
+ throw error;
270
+ }
271
+ }
272
+
273
+ // Create repository if it doesn't exist
274
+ if (!repoExists) {
275
+ const sanitizedRepoName = sanitizeRepoName(repoName);
276
+ const { data: newRepo } = await octokit.repos.createForAuthenticatedUser({
277
+ name: sanitizedRepoName,
278
+ private: isPrivate,
279
+
280
+ // Initialize with a README to avoid empty repository issues
281
+ auto_init: true,
282
+
283
+ // Create a .gitignore file for the project
284
+ gitignore_template: 'Node',
285
+ });
286
+
287
+ // Set the URL for success dialog
288
+ setCreatedRepoUrl(newRepo.html_url);
289
+
290
+ // Since we created the repo with auto_init, we need to wait for GitHub to initialize it
291
+ console.log('Created new repository with auto_init, waiting for GitHub to initialize it...');
292
+
293
+ // Wait a moment for GitHub to set up the initial commit
294
+ await new Promise((resolve) => setTimeout(resolve, 2000));
295
+ } else {
296
+ // Set URL for existing repo
297
+ const sanitizedRepoName = sanitizeRepoName(repoName);
298
+ setCreatedRepoUrl(`https://github.com/${connection.user.login}/${sanitizedRepoName}`);
299
+ }
300
+
301
+ // Process files to upload
302
+ const fileEntries = Object.entries(files);
303
+
304
+ // Filter out files and format them for display
305
+ const fileList = fileEntries.map(([filePath, content]) => {
306
+ // The paths are already properly formatted in the GitHubDeploy component
307
+ return {
308
+ path: filePath,
309
+ size: new TextEncoder().encode(content).length,
310
+ };
311
+ });
312
+
313
+ setPushedFiles(fileList);
314
+
315
+ /*
316
+ * Now we need to handle the repository, whether it's new or existing
317
+ * Get the default branch for the repository
318
+ */
319
+ let defaultBranch: string;
320
+ let baseSha: string | null = null;
321
+
322
+ try {
323
+ // For both new and existing repos, get the repository info
324
+ const sanitizedRepoName = sanitizeRepoName(repoName);
325
+ const { data: repo } = await octokit.repos.get({
326
+ owner: connection.user.login,
327
+ repo: sanitizedRepoName,
328
+ });
329
+ defaultBranch = repo.default_branch || 'main';
330
+ console.log(`Repository default branch: ${defaultBranch}`);
331
+
332
+ // For a newly created repo (or existing one), get the reference to the default branch
333
+ try {
334
+ const { data: refData } = await octokit.git.getRef({
335
+ owner: connection.user.login,
336
+ repo: sanitizedRepoName,
337
+ ref: `heads/${defaultBranch}`,
338
+ });
339
+
340
+ baseSha = refData.object.sha;
341
+ console.log(`Found existing reference with SHA: ${baseSha}`);
342
+
343
+ // Get the latest commit to use as a base for our tree
344
+ const { data: commitData } = await octokit.git.getCommit({
345
+ owner: connection.user.login,
346
+ repo: sanitizedRepoName,
347
+ commit_sha: baseSha,
348
+ });
349
+
350
+ // Store the base tree SHA for tree creation
351
+ baseSha = commitData.tree.sha;
352
+ console.log(`Using base tree SHA: ${baseSha}`);
353
+ } catch (refError) {
354
+ console.error('Error getting reference:', refError);
355
+ baseSha = null;
356
+ }
357
+ } catch (repoError) {
358
+ console.error('Error getting repository info:', repoError);
359
+ defaultBranch = 'main';
360
+ baseSha = null;
361
+ }
362
+
363
+ try {
364
+ console.log('Creating tree for repository');
365
+
366
+ // Create a tree with all files
367
+ const tree = fileEntries.map(([filePath, content]) => ({
368
+ path: filePath, // We've already formatted the paths correctly
369
+ mode: '100644' as const, // Regular file
370
+ type: 'blob' as const,
371
+ content,
372
+ }));
373
+
374
+ console.log(`Creating tree with ${tree.length} files using base: ${baseSha || 'none'}`);
375
+
376
+ // Create a tree with all the files, using the base tree if available
377
+ const sanitizedRepoName = sanitizeRepoName(repoName);
378
+ const { data: treeData } = await octokit.git.createTree({
379
+ owner: connection.user.login,
380
+ repo: sanitizedRepoName,
381
+ tree,
382
+ base_tree: baseSha || undefined,
383
+ });
384
+
385
+ console.log('Tree created successfully', treeData.sha);
386
+
387
+ // Get the current reference to use as parent for our commit
388
+ let parentCommitSha: string | null = null;
389
+
390
+ try {
391
+ const { data: refData } = await octokit.git.getRef({
392
+ owner: connection.user.login,
393
+ repo: sanitizedRepoName,
394
+ ref: `heads/${defaultBranch}`,
395
+ });
396
+ parentCommitSha = refData.object.sha;
397
+ console.log(`Found parent commit: ${parentCommitSha}`);
398
+ } catch (refError) {
399
+ console.log('No reference found, this is a brand new repo', refError);
400
+ parentCommitSha = null;
401
+ }
402
+
403
+ // Create a commit with the tree
404
+ console.log('Creating commit');
405
+
406
+ const { data: commitData } = await octokit.git.createCommit({
407
+ owner: connection.user.login,
408
+ repo: sanitizedRepoName,
409
+ message: !repoExists ? 'Initial commit from Bolt.diy' : 'Update from Bolt.diy',
410
+ tree: treeData.sha,
411
+ parents: parentCommitSha ? [parentCommitSha] : [], // Use parent if available
412
+ });
413
+
414
+ console.log('Commit created successfully', commitData.sha);
415
+
416
+ // Update the reference to point to the new commit
417
+ try {
418
+ console.log(`Updating reference: heads/${defaultBranch} to ${commitData.sha}`);
419
+ await octokit.git.updateRef({
420
+ owner: connection.user.login,
421
+ repo: sanitizedRepoName,
422
+ ref: `heads/${defaultBranch}`,
423
+ sha: commitData.sha,
424
+ force: true, // Use force to ensure the update works
425
+ });
426
+ console.log('Reference updated successfully');
427
+ } catch (refError) {
428
+ console.log('Failed to update reference, attempting to create it', refError);
429
+
430
+ // If the reference doesn't exist, create it (shouldn't happen with auto_init, but just in case)
431
+ try {
432
+ await octokit.git.createRef({
433
+ owner: connection.user.login,
434
+ repo: sanitizedRepoName,
435
+ ref: `refs/heads/${defaultBranch}`,
436
+ sha: commitData.sha,
437
+ });
438
+ console.log('Reference created successfully');
439
+ } catch (createRefError) {
440
+ console.error('Error creating reference:', createRefError);
441
+
442
+ const errorMsg =
443
+ typeof createRefError === 'object' && createRefError !== null && 'message' in createRefError
444
+ ? String(createRefError.message)
445
+ : 'Unknown error';
446
+ throw new Error(`Failed to create Git reference: ${errorMsg}`);
447
+ }
448
+ }
449
+ } catch (gitError) {
450
+ console.error('Error with git operations:', gitError);
451
+
452
+ const gitErrorMsg =
453
+ typeof gitError === 'object' && gitError !== null && 'message' in gitError
454
+ ? String(gitError.message)
455
+ : 'Unknown error';
456
+ throw new Error(`Failed during git operations: ${gitErrorMsg}`);
457
+ }
458
+
459
+ // Save the repository information for this chat
460
+ const sanitizedRepoName = sanitizeRepoName(repoName);
461
+ localStorage.setItem(
462
+ `github-repo-${currentChatId}`,
463
+ JSON.stringify({
464
+ owner: connection.user.login,
465
+ name: sanitizedRepoName,
466
+ url: `https://github.com/${connection.user.login}/${sanitizedRepoName}`,
467
+ }),
468
+ );
469
+
470
+ // Show success dialog
471
+ setShowSuccessDialog(true);
472
+ } catch (error) {
473
+ console.error('Error pushing to GitHub:', error);
474
+
475
+ // Attempt to extract more specific error information
476
+ let errorMessage = 'Failed to push to GitHub';
477
+ let isRetryable = false;
478
+
479
+ if (error instanceof Error) {
480
+ const errorMsg = error.message.toLowerCase();
481
+
482
+ if (errorMsg.includes('network') || errorMsg.includes('fetch failed') || errorMsg.includes('connection')) {
483
+ errorMessage = 'Network error. Please check your internet connection and try again.';
484
+ isRetryable = true;
485
+ } else if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) {
486
+ errorMessage = 'GitHub authentication failed. Please check your access token in Settings > Connections.';
487
+ } else if (errorMsg.includes('403') || errorMsg.includes('forbidden')) {
488
+ errorMessage =
489
+ 'Access denied. Your GitHub token may not have sufficient permissions to create/modify repositories.';
490
+ } else if (errorMsg.includes('404') || errorMsg.includes('not found')) {
491
+ errorMessage = 'Repository or resource not found. Please check the repository name and your permissions.';
492
+ } else if (errorMsg.includes('422') || errorMsg.includes('validation failed')) {
493
+ if (errorMsg.includes('name already exists')) {
494
+ errorMessage =
495
+ 'A repository with this name already exists in your account. Please choose a different name.';
496
+ } else {
497
+ errorMessage = 'Repository validation failed. Please check the repository name and settings.';
498
+ }
499
+ } else if (errorMsg.includes('rate limit') || errorMsg.includes('429')) {
500
+ errorMessage = 'GitHub API rate limit exceeded. Please wait a moment and try again.';
501
+ isRetryable = true;
502
+ } else if (errorMsg.includes('timeout')) {
503
+ errorMessage = 'Request timed out. Please check your connection and try again.';
504
+ isRetryable = true;
505
+ } else {
506
+ errorMessage = `GitHub error: ${error.message}`;
507
+ }
508
+ } else if (typeof error === 'object' && error !== null) {
509
+ // Octokit errors
510
+ if ('message' in error) {
511
+ errorMessage = `GitHub API error: ${error.message as string}`;
512
+ }
513
+
514
+ // GitHub API errors
515
+ if ('documentation_url' in error) {
516
+ console.log('GitHub API documentation:', error.documentation_url);
517
+ }
518
+ }
519
+
520
+ // Show error with retry suggestion if applicable
521
+ const finalMessage = isRetryable ? `${errorMessage} Click to retry.` : errorMessage;
522
+ toast.error(finalMessage);
523
+
524
+ // Log detailed error for debugging
525
+ console.error('Detailed GitHub deployment error:', {
526
+ error,
527
+ repoName: sanitizeRepoName(repoName),
528
+ user: connection?.user?.login,
529
+ isRetryable,
530
+ });
531
+ } finally {
532
+ setIsLoading(false);
533
+ }
534
+ };
535
+
536
+ const handleClose = () => {
537
+ setRepoName('');
538
+ setIsPrivate(false);
539
+ setShowSuccessDialog(false);
540
+ setCreatedRepoUrl('');
541
+ onClose();
542
+ };
543
+
544
+ const handleAuthDialogClose = () => {
545
+ setShowAuthDialog(false);
546
+
547
+ // Refresh user data after auth
548
+ const connection = getLocalStorage('github_connection');
549
+
550
+ if (connection?.user && connection?.token) {
551
+ setUser(connection.user);
552
+ fetchRecentRepos(connection.token);
553
+ }
554
+ };
555
+
556
+ // Success Dialog
557
+ if (showSuccessDialog) {
558
+ return (
559
+ <Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
560
+ <Dialog.Portal>
561
+ <Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
562
+ <div className="fixed inset-0 flex items-center justify-center z-[9999]">
563
+ <motion.div
564
+ initial={{ opacity: 0, scale: 0.95 }}
565
+ animate={{ opacity: 1, scale: 1 }}
566
+ exit={{ opacity: 0, scale: 0.95 }}
567
+ transition={{ duration: 0.2 }}
568
+ className="w-[90vw] md:w-[600px] max-h-[85vh] overflow-y-auto"
569
+ >
570
+ <Dialog.Content
571
+ className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
572
+ aria-describedby="success-dialog-description"
573
+ >
574
+ <Dialog.Title className="sr-only">Successfully pushed to GitHub</Dialog.Title>
575
+ <div className="p-6 space-y-4">
576
+ <div className="flex items-center justify-between">
577
+ <div className="flex items-center gap-3">
578
+ <div className="w-10 h-10 rounded-xl bg-green-500/10 flex items-center justify-center text-green-500">
579
+ <div className="i-ph:check-circle w-5 h-5" />
580
+ </div>
581
+ <div>
582
+ <h3 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
583
+ Successfully pushed to GitHub
584
+ </h3>
585
+ <p
586
+ id="success-dialog-description"
587
+ className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
588
+ >
589
+ Your code is now available on GitHub
590
+ </p>
591
+ </div>
592
+ </div>
593
+ <Dialog.Close asChild>
594
+ <button
595
+ onClick={handleClose}
596
+ className="p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
597
+ >
598
+ <span className="i-ph:x block w-5 h-5" aria-hidden="true" />
599
+ <span className="sr-only">Close dialog</span>
600
+ </button>
601
+ </Dialog.Close>
602
+ </div>
603
+
604
+ <div className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg p-4 text-left border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
605
+ <p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark mb-2 flex items-center gap-2">
606
+ <span className="i-ph:github-logo w-4 h-4 text-purple-500" />
607
+ Repository URL
608
+ </p>
609
+ <div className="flex items-center gap-2">
610
+ <code className="flex-1 text-sm bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-4 px-3 py-2 rounded border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark font-mono">
611
+ {createdRepoUrl}
612
+ </code>
613
+ <motion.button
614
+ onClick={() => {
615
+ navigator.clipboard.writeText(createdRepoUrl);
616
+ toast.success('URL copied to clipboard');
617
+ }}
618
+ className="p-2 text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textSecondary-dark dark:hover:text-bolt-elements-textPrimary-dark bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-4 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
619
+ whileHover={{ scale: 1.05 }}
620
+ whileTap={{ scale: 0.95 }}
621
+ >
622
+ <div className="i-ph:copy w-4 h-4" />
623
+ </motion.button>
624
+ </div>
625
+ </div>
626
+
627
+ <div className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg p-4 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
628
+ <p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark mb-2 flex items-center gap-2">
629
+ <span className="i-ph:files w-4 h-4 text-purple-500" />
630
+ Pushed Files ({pushedFiles.length})
631
+ </p>
632
+ <div className="max-h-[200px] overflow-y-auto custom-scrollbar pr-2">
633
+ {pushedFiles.slice(0, 100).map((file) => (
634
+ <div
635
+ key={file.path}
636
+ className="flex items-center justify-between py-1.5 text-sm text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark border-b border-bolt-elements-borderColor/30 dark:border-bolt-elements-borderColor-dark/30 last:border-0"
637
+ >
638
+ <span className="font-mono truncate flex-1 text-xs">{file.path}</span>
639
+ <span className="text-xs px-2 py-0.5 rounded-full bg-bolt-elements-background-depth-3 dark:bg-bolt-elements-background-depth-4 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark ml-2">
640
+ {(file.size / 1024).toFixed(1)} KB
641
+ </span>
642
+ </div>
643
+ ))}
644
+ {pushedFiles.length > 100 && (
645
+ <div className="py-2 text-center text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
646
+ +{pushedFiles.length - 100} more files
647
+ </div>
648
+ )}
649
+ </div>
650
+ </div>
651
+
652
+ <div className="flex justify-end gap-2 pt-2">
653
+ <motion.a
654
+ href={createdRepoUrl}
655
+ target="_blank"
656
+ rel="noopener noreferrer"
657
+ className="px-4 py-2 rounded-lg bg-purple-500 text-white hover:bg-purple-600 text-sm inline-flex items-center gap-2"
658
+ whileHover={{ scale: 1.02 }}
659
+ whileTap={{ scale: 0.98 }}
660
+ >
661
+ <div className="i-ph:github-logo w-4 h-4" />
662
+ View Repository
663
+ </motion.a>
664
+ <motion.button
665
+ onClick={() => {
666
+ navigator.clipboard.writeText(createdRepoUrl);
667
+ toast.success('URL copied to clipboard');
668
+ }}
669
+ className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm inline-flex items-center gap-2 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
670
+ whileHover={{ scale: 1.02 }}
671
+ whileTap={{ scale: 0.98 }}
672
+ >
673
+ <div className="i-ph:copy w-4 h-4" />
674
+ Copy URL
675
+ </motion.button>
676
+ <motion.button
677
+ onClick={handleClose}
678
+ className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
679
+ whileHover={{ scale: 1.02 }}
680
+ whileTap={{ scale: 0.98 }}
681
+ >
682
+ Close
683
+ </motion.button>
684
+ </div>
685
+ </div>
686
+ </Dialog.Content>
687
+ </motion.div>
688
+ </div>
689
+ </Dialog.Portal>
690
+ </Dialog.Root>
691
+ );
692
+ }
693
+
694
+ if (!user) {
695
+ return (
696
+ <Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
697
+ <Dialog.Portal>
698
+ <Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
699
+ <div className="fixed inset-0 flex items-center justify-center z-[9999]">
700
+ <motion.div
701
+ initial={{ opacity: 0, scale: 0.95 }}
702
+ animate={{ opacity: 1, scale: 1 }}
703
+ exit={{ opacity: 0, scale: 0.95 }}
704
+ transition={{ duration: 0.2 }}
705
+ className="w-[90vw] md:w-[500px]"
706
+ >
707
+ <Dialog.Content
708
+ className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg p-6 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
709
+ aria-describedby="connection-required-description"
710
+ >
711
+ <Dialog.Title className="sr-only">GitHub Connection Required</Dialog.Title>
712
+ <div className="relative text-center space-y-4">
713
+ <Dialog.Close asChild>
714
+ <button
715
+ onClick={handleClose}
716
+ className="absolute right-0 top-0 p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
717
+ >
718
+ <span className="i-ph:x block w-5 h-5" aria-hidden="true" />
719
+ <span className="sr-only">Close dialog</span>
720
+ </button>
721
+ </Dialog.Close>
722
+ <motion.div
723
+ initial={{ scale: 0.8 }}
724
+ animate={{ scale: 1 }}
725
+ transition={{ delay: 0.1 }}
726
+ className="mx-auto w-16 h-16 rounded-xl bg-bolt-elements-background-depth-3 flex items-center justify-center text-purple-500"
727
+ >
728
+ <div className="i-ph:github-logo w-8 h-8" />
729
+ </motion.div>
730
+ <h3 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
731
+ GitHub Connection Required
732
+ </h3>
733
+ <p
734
+ id="connection-required-description"
735
+ className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark max-w-md mx-auto"
736
+ >
737
+ To deploy your code to GitHub, you need to connect your GitHub account first.
738
+ </p>
739
+ <div className="pt-2 flex justify-center gap-3">
740
+ <motion.button
741
+ className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark text-sm hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
742
+ whileHover={{ scale: 1.02 }}
743
+ whileTap={{ scale: 0.98 }}
744
+ onClick={handleClose}
745
+ >
746
+ Close
747
+ </motion.button>
748
+ <motion.button
749
+ onClick={() => setShowAuthDialog(true)}
750
+ className="px-4 py-2 rounded-lg bg-purple-500 text-white text-sm hover:bg-purple-600 inline-flex items-center gap-2"
751
+ whileHover={{ scale: 1.02 }}
752
+ whileTap={{ scale: 0.98 }}
753
+ >
754
+ <div className="i-ph:github-logo w-4 h-4" />
755
+ Connect GitHub Account
756
+ </motion.button>
757
+ </div>
758
+ </div>
759
+ </Dialog.Content>
760
+ </motion.div>
761
+ </div>
762
+ </Dialog.Portal>
763
+
764
+ {/* GitHub Auth Dialog */}
765
+ <GitHubAuthDialog isOpen={showAuthDialog} onClose={handleAuthDialogClose} />
766
+ </Dialog.Root>
767
+ );
768
+ }
769
+
770
+ return (
771
+ <Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
772
+ <Dialog.Portal>
773
+ <Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
774
+ <div className="fixed inset-0 flex items-center justify-center z-[9999]">
775
+ <motion.div
776
+ initial={{ opacity: 0, scale: 0.95 }}
777
+ animate={{ opacity: 1, scale: 1 }}
778
+ exit={{ opacity: 0, scale: 0.95 }}
779
+ transition={{ duration: 0.2 }}
780
+ className="w-[90vw] md:w-[500px]"
781
+ >
782
+ <Dialog.Content
783
+ className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
784
+ aria-describedby="push-dialog-description"
785
+ >
786
+ <div className="p-6">
787
+ <div className="flex items-center gap-4 mb-6">
788
+ <motion.div
789
+ initial={{ scale: 0.8 }}
790
+ animate={{ scale: 1 }}
791
+ transition={{ delay: 0.1 }}
792
+ className="w-10 h-10 rounded-xl bg-bolt-elements-background-depth-3 flex items-center justify-center text-purple-500"
793
+ >
794
+ <div className="i-ph:github-logo w-5 h-5" />
795
+ </motion.div>
796
+ <div>
797
+ <Dialog.Title className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
798
+ Deploy to GitHub
799
+ </Dialog.Title>
800
+ <p
801
+ id="push-dialog-description"
802
+ className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
803
+ >
804
+ Deploy your code to a new or existing GitHub repository
805
+ </p>
806
+ </div>
807
+ <Dialog.Close asChild>
808
+ <button
809
+ onClick={handleClose}
810
+ className="ml-auto p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
811
+ >
812
+ <span className="i-ph:x block w-5 h-5" aria-hidden="true" />
813
+ <span className="sr-only">Close dialog</span>
814
+ </button>
815
+ </Dialog.Close>
816
+ </div>
817
+
818
+ <div className="flex items-center gap-3 mb-6 p-4 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
819
+ <div className="relative">
820
+ <img src={user.avatar_url} alt={user.login} className="w-10 h-10 rounded-full" />
821
+ <div className="absolute -bottom-1 -right-1 w-5 h-5 rounded-full bg-purple-500 flex items-center justify-center text-white">
822
+ <div className="i-ph:github-logo w-3 h-3" />
823
+ </div>
824
+ </div>
825
+ <div>
826
+ <p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
827
+ {user.name || user.login}
828
+ </p>
829
+ <p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
830
+ @{user.login}
831
+ </p>
832
+ </div>
833
+ </div>
834
+
835
+ <form onSubmit={handleSubmit} className="space-y-4">
836
+ <div className="space-y-2">
837
+ <label
838
+ htmlFor="repoName"
839
+ className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
840
+ >
841
+ Repository Name
842
+ </label>
843
+ <div className="relative">
844
+ <div className="absolute left-3 top-1/2 -translate-y-1/2 text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark">
845
+ <span className="i-ph:git-branch w-4 h-4" />
846
+ </div>
847
+ <input
848
+ id="repoName"
849
+ type="text"
850
+ value={repoName}
851
+ onChange={(e) => {
852
+ const value = e.target.value;
853
+ setRepoName(value);
854
+
855
+ // Show real-time feedback for invalid characters
856
+ const sanitized = sanitizeRepoName(value);
857
+
858
+ if (value && value !== sanitized) {
859
+ // Show preview of sanitized name without being too intrusive
860
+ e.target.setAttribute('data-sanitized', sanitized);
861
+ } else {
862
+ e.target.removeAttribute('data-sanitized');
863
+ }
864
+ }}
865
+ placeholder="my-awesome-project"
866
+ className="w-full pl-10 px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark placeholder-bolt-elements-textTertiary dark:placeholder-bolt-elements-textTertiary-dark focus:outline-none focus:ring-2 focus:ring-purple-500"
867
+ required
868
+ maxLength={100}
869
+ pattern="[a-zA-Z0-9\-_\s]+"
870
+ title="Repository name can contain letters, numbers, hyphens, underscores, and spaces"
871
+ />
872
+ </div>
873
+ {repoName && sanitizeRepoName(repoName) !== repoName && (
874
+ <p className="text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark mt-1">
875
+ Will be created as:{' '}
876
+ <span className="font-mono text-purple-600 dark:text-purple-400">
877
+ {sanitizeRepoName(repoName)}
878
+ </span>
879
+ </p>
880
+ )}
881
+ </div>
882
+
883
+ <div className="space-y-2">
884
+ <div className="flex items-center justify-between mb-2">
885
+ <label className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
886
+ Recent Repositories
887
+ </label>
888
+ <span className="text-xs text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark">
889
+ {filteredRepos.length} of {recentRepos.length}
890
+ </span>
891
+ </div>
892
+
893
+ <div className="mb-2">
894
+ <SearchInput
895
+ placeholder="Search repositories..."
896
+ value={repoSearchQuery}
897
+ onChange={(e) => setRepoSearchQuery(e.target.value)}
898
+ onClear={() => setRepoSearchQuery('')}
899
+ className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-sm"
900
+ />
901
+ </div>
902
+
903
+ {recentRepos.length === 0 && !isFetchingRepos ? (
904
+ <EmptyState
905
+ icon="i-ph:github-logo"
906
+ title="No repositories found"
907
+ description="We couldn't find any repositories in your GitHub account."
908
+ variant="compact"
909
+ />
910
+ ) : (
911
+ <div className="space-y-2 max-h-[200px] overflow-y-auto pr-2 custom-scrollbar">
912
+ {filteredRepos.length === 0 && repoSearchQuery.trim() !== '' ? (
913
+ <EmptyState
914
+ icon="i-ph:magnifying-glass"
915
+ title="No matching repositories"
916
+ description="Try a different search term"
917
+ variant="compact"
918
+ />
919
+ ) : (
920
+ filteredRepos.map((repo) => (
921
+ <motion.button
922
+ key={repo.full_name}
923
+ type="button"
924
+ onClick={() => setRepoName(repo.name)}
925
+ className="w-full p-3 text-left rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 transition-colors group border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark hover:border-purple-500/30"
926
+ whileHover={{ scale: 1.01 }}
927
+ whileTap={{ scale: 0.99 }}
928
+ >
929
+ <div className="flex items-center justify-between">
930
+ <div className="flex items-center gap-2">
931
+ <div className="i-ph:git-branch w-4 h-4 text-purple-500" />
932
+ <span className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark group-hover:text-purple-500">
933
+ {repo.name}
934
+ </span>
935
+ </div>
936
+ {repo.private && (
937
+ <Badge variant="primary" size="sm" icon="i-ph:lock w-3 h-3">
938
+ Private
939
+ </Badge>
940
+ )}
941
+ </div>
942
+ {repo.description && (
943
+ <p className="mt-1 text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark line-clamp-2">
944
+ {repo.description}
945
+ </p>
946
+ )}
947
+ <div className="mt-2 flex items-center gap-2 flex-wrap">
948
+ {repo.language && (
949
+ <Badge variant="subtle" size="sm" icon="i-ph:code w-3 h-3">
950
+ {repo.language}
951
+ </Badge>
952
+ )}
953
+ <Badge variant="subtle" size="sm" icon="i-ph:star w-3 h-3">
954
+ {repo.stargazers_count.toLocaleString()}
955
+ </Badge>
956
+ <Badge variant="subtle" size="sm" icon="i-ph:git-fork w-3 h-3">
957
+ {repo.forks_count.toLocaleString()}
958
+ </Badge>
959
+ <Badge variant="subtle" size="sm" icon="i-ph:clock w-3 h-3">
960
+ {new Date(repo.updated_at).toLocaleDateString()}
961
+ </Badge>
962
+ </div>
963
+ </motion.button>
964
+ ))
965
+ )}
966
+ </div>
967
+ )}
968
+ </div>
969
+
970
+ {isFetchingRepos && (
971
+ <div className="flex items-center justify-center py-4">
972
+ <StatusIndicator status="loading" pulse={true} label="Loading repositories..." />
973
+ </div>
974
+ )}
975
+
976
+ <div className="p-3 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
977
+ <div className="flex items-center gap-2">
978
+ <input
979
+ type="checkbox"
980
+ id="private"
981
+ checked={isPrivate}
982
+ onChange={(e) => setIsPrivate(e.target.checked)}
983
+ className="rounded border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-purple-500 focus:ring-purple-500 dark:bg-bolt-elements-background-depth-3"
984
+ />
985
+ <label
986
+ htmlFor="private"
987
+ className="text-sm text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark"
988
+ >
989
+ Make repository private
990
+ </label>
991
+ </div>
992
+ <p className="text-xs text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark mt-2 ml-6">
993
+ Private repositories are only visible to you and people you share them with
994
+ </p>
995
+ </div>
996
+
997
+ <div className="pt-4 flex gap-2">
998
+ <motion.button
999
+ type="button"
1000
+ onClick={handleClose}
1001
+ className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
1002
+ whileHover={{ scale: 1.02 }}
1003
+ whileTap={{ scale: 0.98 }}
1004
+ >
1005
+ Cancel
1006
+ </motion.button>
1007
+ <motion.button
1008
+ type="submit"
1009
+ disabled={isLoading}
1010
+ className={classNames(
1011
+ 'flex-1 px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 text-sm inline-flex items-center justify-center gap-2',
1012
+ isLoading ? 'opacity-50 cursor-not-allowed' : '',
1013
+ )}
1014
+ whileHover={!isLoading ? { scale: 1.02 } : {}}
1015
+ whileTap={!isLoading ? { scale: 0.98 } : {}}
1016
+ >
1017
+ {isLoading ? (
1018
+ <>
1019
+ <div className="i-ph:spinner-gap animate-spin w-4 h-4" />
1020
+ Deploying...
1021
+ </>
1022
+ ) : (
1023
+ <>
1024
+ <div className="i-ph:github-logo w-4 h-4" />
1025
+ Deploy to GitHub
1026
+ </>
1027
+ )}
1028
+ </motion.button>
1029
+ </div>
1030
+ </form>
1031
+ </div>
1032
+ </Dialog.Content>
1033
+ </motion.div>
1034
+ </div>
1035
+ </Dialog.Portal>
1036
+
1037
+ {/* GitHub Auth Dialog */}
1038
+ <GitHubAuthDialog isOpen={showAuthDialog} onClose={handleAuthDialogClose} />
1039
+ </Dialog.Root>
1040
+ );
1041
+ }