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,1013 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { Switch } from '~/components/ui/Switch';
4
+ import { logStore, type LogEntry } from '~/lib/stores/logs';
5
+ import { useStore } from '@nanostores/react';
6
+ import { classNames } from '~/utils/classNames';
7
+ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
8
+ import { Dialog, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
9
+ import { jsPDF } from 'jspdf';
10
+ import { toast } from 'react-toastify';
11
+
12
+ interface SelectOption {
13
+ value: string;
14
+ label: string;
15
+ icon?: string;
16
+ color?: string;
17
+ }
18
+
19
+ const logLevelOptions: SelectOption[] = [
20
+ {
21
+ value: 'all',
22
+ label: 'All Types',
23
+ icon: 'i-ph:funnel',
24
+ color: '#9333ea',
25
+ },
26
+ {
27
+ value: 'provider',
28
+ label: 'LLM',
29
+ icon: 'i-ph:robot',
30
+ color: '#10b981',
31
+ },
32
+ {
33
+ value: 'api',
34
+ label: 'API',
35
+ icon: 'i-ph:cloud',
36
+ color: '#3b82f6',
37
+ },
38
+ {
39
+ value: 'error',
40
+ label: 'Errors',
41
+ icon: 'i-ph:warning-circle',
42
+ color: '#ef4444',
43
+ },
44
+ {
45
+ value: 'warning',
46
+ label: 'Warnings',
47
+ icon: 'i-ph:warning',
48
+ color: '#f59e0b',
49
+ },
50
+ {
51
+ value: 'info',
52
+ label: 'Info',
53
+ icon: 'i-ph:info',
54
+ color: '#3b82f6',
55
+ },
56
+ {
57
+ value: 'debug',
58
+ label: 'Debug',
59
+ icon: 'i-ph:bug',
60
+ color: '#6b7280',
61
+ },
62
+ ];
63
+
64
+ interface LogEntryItemProps {
65
+ log: LogEntry;
66
+ isExpanded: boolean;
67
+ use24Hour: boolean;
68
+ showTimestamp: boolean;
69
+ }
70
+
71
+ const LogEntryItem = ({ log, isExpanded: forceExpanded, use24Hour, showTimestamp }: LogEntryItemProps) => {
72
+ const [localExpanded, setLocalExpanded] = useState(forceExpanded);
73
+
74
+ useEffect(() => {
75
+ setLocalExpanded(forceExpanded);
76
+ }, [forceExpanded]);
77
+
78
+ const timestamp = useMemo(() => {
79
+ const date = new Date(log.timestamp);
80
+ return date.toLocaleTimeString('en-US', { hour12: !use24Hour });
81
+ }, [log.timestamp, use24Hour]);
82
+
83
+ const style = useMemo(() => {
84
+ if (log.category === 'provider') {
85
+ return {
86
+ icon: 'i-ph:robot',
87
+ color: 'text-emerald-500 dark:text-emerald-400',
88
+ bg: 'hover:bg-emerald-500/10 dark:hover:bg-emerald-500/20',
89
+ badge: 'text-emerald-500 bg-emerald-50 dark:bg-emerald-500/10',
90
+ };
91
+ }
92
+
93
+ if (log.category === 'api') {
94
+ return {
95
+ icon: 'i-ph:cloud',
96
+ color: 'text-blue-500 dark:text-blue-400',
97
+ bg: 'hover:bg-blue-500/10 dark:hover:bg-blue-500/20',
98
+ badge: 'text-blue-500 bg-blue-50 dark:bg-blue-500/10',
99
+ };
100
+ }
101
+
102
+ switch (log.level) {
103
+ case 'error':
104
+ return {
105
+ icon: 'i-ph:warning-circle',
106
+ color: 'text-red-500 dark:text-red-400',
107
+ bg: 'hover:bg-red-500/10 dark:hover:bg-red-500/20',
108
+ badge: 'text-red-500 bg-red-50 dark:bg-red-500/10',
109
+ };
110
+ case 'warning':
111
+ return {
112
+ icon: 'i-ph:warning',
113
+ color: 'text-yellow-500 dark:text-yellow-400',
114
+ bg: 'hover:bg-yellow-500/10 dark:hover:bg-yellow-500/20',
115
+ badge: 'text-yellow-500 bg-yellow-50 dark:bg-yellow-500/10',
116
+ };
117
+ case 'debug':
118
+ return {
119
+ icon: 'i-ph:bug',
120
+ color: 'text-gray-500 dark:text-gray-400',
121
+ bg: 'hover:bg-gray-500/10 dark:hover:bg-gray-500/20',
122
+ badge: 'text-gray-500 bg-gray-50 dark:bg-gray-500/10',
123
+ };
124
+ default:
125
+ return {
126
+ icon: 'i-ph:info',
127
+ color: 'text-blue-500 dark:text-blue-400',
128
+ bg: 'hover:bg-blue-500/10 dark:hover:bg-blue-500/20',
129
+ badge: 'text-blue-500 bg-blue-50 dark:bg-blue-500/10',
130
+ };
131
+ }
132
+ }, [log.level, log.category]);
133
+
134
+ const renderDetails = (details: any) => {
135
+ if (log.category === 'provider') {
136
+ return (
137
+ <div className="flex flex-col gap-2">
138
+ <div className="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
139
+ <span>Model: {details.model}</span>
140
+ <span>•</span>
141
+ <span>Tokens: {details.totalTokens}</span>
142
+ <span>•</span>
143
+ <span>Duration: {details.duration}ms</span>
144
+ </div>
145
+ {details.prompt && (
146
+ <div className="flex flex-col gap-1">
147
+ <div className="text-xs font-medium text-gray-700 dark:text-gray-300">Prompt:</div>
148
+ <pre className="text-xs text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded p-2 whitespace-pre-wrap">
149
+ {details.prompt}
150
+ </pre>
151
+ </div>
152
+ )}
153
+ {details.response && (
154
+ <div className="flex flex-col gap-1">
155
+ <div className="text-xs font-medium text-gray-700 dark:text-gray-300">Response:</div>
156
+ <pre className="text-xs text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded p-2 whitespace-pre-wrap">
157
+ {details.response}
158
+ </pre>
159
+ </div>
160
+ )}
161
+ </div>
162
+ );
163
+ }
164
+
165
+ if (log.category === 'api') {
166
+ return (
167
+ <div className="flex flex-col gap-2">
168
+ <div className="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
169
+ <span className={details.method === 'GET' ? 'text-green-500' : 'text-blue-500'}>{details.method}</span>
170
+ <span>•</span>
171
+ <span>Status: {details.statusCode}</span>
172
+ <span>•</span>
173
+ <span>Duration: {details.duration}ms</span>
174
+ </div>
175
+ <div className="text-xs text-gray-600 dark:text-gray-400 break-all">{details.url}</div>
176
+ {details.request && (
177
+ <div className="flex flex-col gap-1">
178
+ <div className="text-xs font-medium text-gray-700 dark:text-gray-300">Request:</div>
179
+ <pre className="text-xs text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded p-2 whitespace-pre-wrap">
180
+ {JSON.stringify(details.request, null, 2)}
181
+ </pre>
182
+ </div>
183
+ )}
184
+ {details.response && (
185
+ <div className="flex flex-col gap-1">
186
+ <div className="text-xs font-medium text-gray-700 dark:text-gray-300">Response:</div>
187
+ <pre className="text-xs text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded p-2 whitespace-pre-wrap">
188
+ {JSON.stringify(details.response, null, 2)}
189
+ </pre>
190
+ </div>
191
+ )}
192
+ {details.error && (
193
+ <div className="flex flex-col gap-1">
194
+ <div className="text-xs font-medium text-red-500">Error:</div>
195
+ <pre className="text-xs text-red-400 bg-red-50 dark:bg-red-500/10 rounded p-2 whitespace-pre-wrap">
196
+ {JSON.stringify(details.error, null, 2)}
197
+ </pre>
198
+ </div>
199
+ )}
200
+ </div>
201
+ );
202
+ }
203
+
204
+ return (
205
+ <pre className="text-xs text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded whitespace-pre-wrap">
206
+ {JSON.stringify(details, null, 2)}
207
+ </pre>
208
+ );
209
+ };
210
+
211
+ return (
212
+ <motion.div
213
+ initial={{ opacity: 0, y: 20 }}
214
+ animate={{ opacity: 1, y: 0 }}
215
+ className={classNames(
216
+ 'flex flex-col gap-2',
217
+ 'rounded-lg p-4',
218
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
219
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
220
+ style.bg,
221
+ 'transition-all duration-200',
222
+ )}
223
+ >
224
+ <div className="flex items-start justify-between gap-4">
225
+ <div className="flex items-start gap-3">
226
+ <span className={classNames('text-lg', style.icon, style.color)} />
227
+ <div className="flex flex-col gap-1">
228
+ <div className="text-sm font-medium text-gray-900 dark:text-white">{log.message}</div>
229
+ {log.details && (
230
+ <>
231
+ <button
232
+ onClick={() => setLocalExpanded(!localExpanded)}
233
+ className="text-xs text-gray-500 dark:text-gray-400 hover:text-purple-500 dark:hover:text-purple-400 transition-colors"
234
+ >
235
+ {localExpanded ? 'Hide' : 'Show'} Details
236
+ </button>
237
+ {localExpanded && renderDetails(log.details)}
238
+ </>
239
+ )}
240
+ <div className="flex items-center gap-2">
241
+ <div className={classNames('px-2 py-0.5 rounded text-xs font-medium uppercase', style.badge)}>
242
+ {log.level}
243
+ </div>
244
+ {log.category && (
245
+ <div className="px-2 py-0.5 rounded-full text-xs bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400">
246
+ {log.category}
247
+ </div>
248
+ )}
249
+ </div>
250
+ </div>
251
+ </div>
252
+ {showTimestamp && <time className="shrink-0 text-xs text-gray-500 dark:text-gray-400">{timestamp}</time>}
253
+ </div>
254
+ </motion.div>
255
+ );
256
+ };
257
+
258
+ interface ExportFormat {
259
+ id: string;
260
+ label: string;
261
+ icon: string;
262
+ handler: () => void;
263
+ }
264
+
265
+ export function EventLogsTab() {
266
+ const logs = useStore(logStore.logs);
267
+ const [selectedLevel, setSelectedLevel] = useState<'all' | string>('all');
268
+ const [searchQuery, setSearchQuery] = useState('');
269
+ const [use24Hour, setUse24Hour] = useState(false);
270
+ const [autoExpand, setAutoExpand] = useState(false);
271
+ const [showTimestamps, setShowTimestamps] = useState(true);
272
+ const [showLevelFilter, setShowLevelFilter] = useState(false);
273
+ const [isRefreshing, setIsRefreshing] = useState(false);
274
+ const levelFilterRef = useRef<HTMLDivElement>(null);
275
+
276
+ const filteredLogs = useMemo(() => {
277
+ const allLogs = Object.values(logs);
278
+
279
+ if (selectedLevel === 'all') {
280
+ return allLogs.filter((log) =>
281
+ searchQuery ? log.message.toLowerCase().includes(searchQuery.toLowerCase()) : true,
282
+ );
283
+ }
284
+
285
+ return allLogs.filter((log) => {
286
+ const matchesType = log.category === selectedLevel || log.level === selectedLevel;
287
+ const matchesSearch = searchQuery ? log.message.toLowerCase().includes(searchQuery.toLowerCase()) : true;
288
+
289
+ return matchesType && matchesSearch;
290
+ });
291
+ }, [logs, selectedLevel, searchQuery]);
292
+
293
+ // Add performance tracking on mount
294
+ useEffect(() => {
295
+ const startTime = performance.now();
296
+
297
+ logStore.logInfo('Event Logs tab mounted', {
298
+ type: 'component_mount',
299
+ message: 'Event Logs tab component mounted',
300
+ component: 'EventLogsTab',
301
+ });
302
+
303
+ return () => {
304
+ const duration = performance.now() - startTime;
305
+ logStore.logPerformanceMetric('EventLogsTab', 'mount-duration', duration);
306
+ };
307
+ }, []);
308
+
309
+ // Log filter changes
310
+ const handleLevelFilterChange = useCallback(
311
+ (newLevel: string) => {
312
+ logStore.logInfo('Log level filter changed', {
313
+ type: 'filter_change',
314
+ message: `Log level filter changed from ${selectedLevel} to ${newLevel}`,
315
+ component: 'EventLogsTab',
316
+ previousLevel: selectedLevel,
317
+ newLevel,
318
+ });
319
+ setSelectedLevel(newLevel as string);
320
+ setShowLevelFilter(false);
321
+ },
322
+ [selectedLevel],
323
+ );
324
+
325
+ // Log search changes with debounce
326
+ useEffect(() => {
327
+ const timeoutId = setTimeout(() => {
328
+ if (searchQuery) {
329
+ logStore.logInfo('Log search performed', {
330
+ type: 'search',
331
+ message: `Search performed with query "${searchQuery}" (${filteredLogs.length} results)`,
332
+ component: 'EventLogsTab',
333
+ query: searchQuery,
334
+ resultsCount: filteredLogs.length,
335
+ });
336
+ }
337
+ }, 1000);
338
+
339
+ return () => clearTimeout(timeoutId);
340
+ }, [searchQuery, filteredLogs.length]);
341
+
342
+ // Enhanced refresh handler
343
+ const handleRefresh = useCallback(async () => {
344
+ const startTime = performance.now();
345
+ setIsRefreshing(true);
346
+
347
+ try {
348
+ await logStore.refreshLogs();
349
+
350
+ const duration = performance.now() - startTime;
351
+
352
+ logStore.logSuccess('Logs refreshed successfully', {
353
+ type: 'refresh',
354
+ message: `Successfully refreshed ${Object.keys(logs).length} logs`,
355
+ component: 'EventLogsTab',
356
+ duration,
357
+ logsCount: Object.keys(logs).length,
358
+ });
359
+ } catch (error) {
360
+ logStore.logError('Failed to refresh logs', error, {
361
+ type: 'refresh_error',
362
+ message: 'Failed to refresh logs',
363
+ component: 'EventLogsTab',
364
+ });
365
+ } finally {
366
+ setTimeout(() => setIsRefreshing(false), 500);
367
+ }
368
+ }, [logs]);
369
+
370
+ // Log preference changes
371
+ const handlePreferenceChange = useCallback((type: string, value: boolean) => {
372
+ logStore.logInfo('Log preference changed', {
373
+ type: 'preference_change',
374
+ message: `Log preference "${type}" changed to ${value}`,
375
+ component: 'EventLogsTab',
376
+ preference: type,
377
+ value,
378
+ });
379
+
380
+ switch (type) {
381
+ case 'timestamps':
382
+ setShowTimestamps(value);
383
+ break;
384
+ case '24hour':
385
+ setUse24Hour(value);
386
+ break;
387
+ case 'autoExpand':
388
+ setAutoExpand(value);
389
+ break;
390
+ }
391
+ }, []);
392
+
393
+ // Close filters when clicking outside
394
+ useEffect(() => {
395
+ const handleClickOutside = (event: MouseEvent) => {
396
+ if (levelFilterRef.current && !levelFilterRef.current.contains(event.target as Node)) {
397
+ setShowLevelFilter(false);
398
+ }
399
+ };
400
+
401
+ document.addEventListener('mousedown', handleClickOutside);
402
+
403
+ return () => {
404
+ document.removeEventListener('mousedown', handleClickOutside);
405
+ };
406
+ }, []);
407
+
408
+ const selectedLevelOption = logLevelOptions.find((opt) => opt.value === selectedLevel);
409
+
410
+ // Export functions
411
+ const exportAsJSON = () => {
412
+ try {
413
+ const exportData = {
414
+ timestamp: new Date().toISOString(),
415
+ logs: filteredLogs,
416
+ filters: {
417
+ level: selectedLevel,
418
+ searchQuery,
419
+ },
420
+ preferences: {
421
+ use24Hour,
422
+ showTimestamps,
423
+ autoExpand,
424
+ },
425
+ };
426
+
427
+ const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
428
+ const url = window.URL.createObjectURL(blob);
429
+ const a = document.createElement('a');
430
+ a.href = url;
431
+ a.download = `bolt-event-logs-${new Date().toISOString()}.json`;
432
+ document.body.appendChild(a);
433
+ a.click();
434
+ window.URL.revokeObjectURL(url);
435
+ document.body.removeChild(a);
436
+ toast.success('Event logs exported successfully as JSON');
437
+ } catch (error) {
438
+ console.error('Failed to export JSON:', error);
439
+ toast.error('Failed to export event logs as JSON');
440
+ }
441
+ };
442
+
443
+ const exportAsCSV = () => {
444
+ try {
445
+ // Convert logs to CSV format
446
+ const headers = ['Timestamp', 'Level', 'Category', 'Message', 'Details'];
447
+ const csvData = [
448
+ headers,
449
+ ...filteredLogs.map((log) => [
450
+ new Date(log.timestamp).toISOString(),
451
+ log.level,
452
+ log.category || '',
453
+ log.message,
454
+ log.details ? JSON.stringify(log.details) : '',
455
+ ]),
456
+ ];
457
+
458
+ const csvContent = csvData
459
+ .map((row) => row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(','))
460
+ .join('\n');
461
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
462
+ const url = window.URL.createObjectURL(blob);
463
+ const a = document.createElement('a');
464
+ a.href = url;
465
+ a.download = `bolt-event-logs-${new Date().toISOString()}.csv`;
466
+ document.body.appendChild(a);
467
+ a.click();
468
+ window.URL.revokeObjectURL(url);
469
+ document.body.removeChild(a);
470
+ toast.success('Event logs exported successfully as CSV');
471
+ } catch (error) {
472
+ console.error('Failed to export CSV:', error);
473
+ toast.error('Failed to export event logs as CSV');
474
+ }
475
+ };
476
+
477
+ const exportAsPDF = () => {
478
+ try {
479
+ // Create new PDF document
480
+ const doc = new jsPDF();
481
+ const lineHeight = 7;
482
+ let yPos = 20;
483
+ const margin = 20;
484
+ const pageWidth = doc.internal.pageSize.getWidth();
485
+ const maxLineWidth = pageWidth - 2 * margin;
486
+
487
+ // Helper function to add section header
488
+ const addSectionHeader = (title: string) => {
489
+ // Check if we need a new page
490
+ if (yPos > doc.internal.pageSize.getHeight() - 30) {
491
+ doc.addPage();
492
+ yPos = margin;
493
+ }
494
+
495
+ doc.setFillColor('#F3F4F6');
496
+ doc.rect(margin - 2, yPos - 5, pageWidth - 2 * (margin - 2), lineHeight + 6, 'F');
497
+ doc.setFont('helvetica', 'bold');
498
+ doc.setTextColor('#111827');
499
+ doc.setFontSize(12);
500
+ doc.text(title.toUpperCase(), margin, yPos);
501
+ yPos += lineHeight * 2;
502
+ };
503
+
504
+ // Add title and header
505
+ doc.setFillColor('#6366F1');
506
+ doc.rect(0, 0, pageWidth, 50, 'F');
507
+ doc.setTextColor('#FFFFFF');
508
+ doc.setFontSize(24);
509
+ doc.setFont('helvetica', 'bold');
510
+ doc.text('Event Logs Report', margin, 35);
511
+
512
+ // Add subtitle with bolt.diy
513
+ doc.setFontSize(12);
514
+ doc.setFont('helvetica', 'normal');
515
+ doc.text('bolt.diy - AI Development Platform', margin, 45);
516
+ yPos = 70;
517
+
518
+ // Add report summary section
519
+ addSectionHeader('Report Summary');
520
+
521
+ doc.setFontSize(10);
522
+ doc.setFont('helvetica', 'normal');
523
+ doc.setTextColor('#374151');
524
+
525
+ const summaryItems = [
526
+ { label: 'Generated', value: new Date().toLocaleString() },
527
+ { label: 'Total Logs', value: filteredLogs.length.toString() },
528
+ { label: 'Filter Applied', value: selectedLevel === 'all' ? 'All Types' : selectedLevel },
529
+ { label: 'Search Query', value: searchQuery || 'None' },
530
+ { label: 'Time Format', value: use24Hour ? '24-hour' : '12-hour' },
531
+ ];
532
+
533
+ summaryItems.forEach((item) => {
534
+ doc.setFont('helvetica', 'bold');
535
+ doc.text(`${item.label}:`, margin, yPos);
536
+ doc.setFont('helvetica', 'normal');
537
+ doc.text(item.value, margin + 60, yPos);
538
+ yPos += lineHeight;
539
+ });
540
+
541
+ yPos += lineHeight * 2;
542
+
543
+ // Add statistics section
544
+ addSectionHeader('Log Statistics');
545
+
546
+ // Calculate statistics
547
+ const stats = {
548
+ error: filteredLogs.filter((log) => log.level === 'error').length,
549
+ warning: filteredLogs.filter((log) => log.level === 'warning').length,
550
+ info: filteredLogs.filter((log) => log.level === 'info').length,
551
+ debug: filteredLogs.filter((log) => log.level === 'debug').length,
552
+ provider: filteredLogs.filter((log) => log.category === 'provider').length,
553
+ api: filteredLogs.filter((log) => log.category === 'api').length,
554
+ };
555
+
556
+ // Create two columns for statistics
557
+ const leftStats = [
558
+ { label: 'Error Logs', value: stats.error, color: '#DC2626' },
559
+ { label: 'Warning Logs', value: stats.warning, color: '#F59E0B' },
560
+ { label: 'Info Logs', value: stats.info, color: '#3B82F6' },
561
+ ];
562
+
563
+ const rightStats = [
564
+ { label: 'Debug Logs', value: stats.debug, color: '#6B7280' },
565
+ { label: 'LLM Logs', value: stats.provider, color: '#10B981' },
566
+ { label: 'API Logs', value: stats.api, color: '#3B82F6' },
567
+ ];
568
+
569
+ const colWidth = (pageWidth - 2 * margin) / 2;
570
+
571
+ // Draw statistics in two columns
572
+ leftStats.forEach((stat, index) => {
573
+ doc.setTextColor(stat.color);
574
+ doc.setFont('helvetica', 'bold');
575
+ doc.text(stat.value.toString(), margin, yPos);
576
+ doc.setTextColor('#374151');
577
+ doc.setFont('helvetica', 'normal');
578
+ doc.text(stat.label, margin + 20, yPos);
579
+
580
+ if (rightStats[index]) {
581
+ doc.setTextColor(rightStats[index].color);
582
+ doc.setFont('helvetica', 'bold');
583
+ doc.text(rightStats[index].value.toString(), margin + colWidth, yPos);
584
+ doc.setTextColor('#374151');
585
+ doc.setFont('helvetica', 'normal');
586
+ doc.text(rightStats[index].label, margin + colWidth + 20, yPos);
587
+ }
588
+
589
+ yPos += lineHeight;
590
+ });
591
+
592
+ yPos += lineHeight * 2;
593
+
594
+ // Add logs section
595
+ addSectionHeader('Event Logs');
596
+
597
+ // Helper function to add a log entry with improved formatting
598
+ const addLogEntry = (log: LogEntry) => {
599
+ const entryHeight = 20 + (log.details ? 40 : 0); // Estimate entry height
600
+
601
+ // Check if we need a new page
602
+ if (yPos + entryHeight > doc.internal.pageSize.getHeight() - 20) {
603
+ doc.addPage();
604
+ yPos = margin;
605
+ }
606
+
607
+ // Add timestamp and level
608
+ const timestamp = new Date(log.timestamp).toLocaleString(undefined, {
609
+ year: 'numeric',
610
+ month: '2-digit',
611
+ day: '2-digit',
612
+ hour: '2-digit',
613
+ minute: '2-digit',
614
+ second: '2-digit',
615
+ hour12: !use24Hour,
616
+ });
617
+
618
+ // Draw log level badge background
619
+ const levelColors: Record<string, string> = {
620
+ error: '#FEE2E2',
621
+ warning: '#FEF3C7',
622
+ info: '#DBEAFE',
623
+ debug: '#F3F4F6',
624
+ };
625
+
626
+ const textColors: Record<string, string> = {
627
+ error: '#DC2626',
628
+ warning: '#F59E0B',
629
+ info: '#3B82F6',
630
+ debug: '#6B7280',
631
+ };
632
+
633
+ const levelWidth = doc.getTextWidth(log.level.toUpperCase()) + 10;
634
+ doc.setFillColor(levelColors[log.level] || '#F3F4F6');
635
+ doc.roundedRect(margin, yPos - 4, levelWidth, lineHeight + 4, 1, 1, 'F');
636
+
637
+ // Add log level text
638
+ doc.setTextColor(textColors[log.level] || '#6B7280');
639
+ doc.setFont('helvetica', 'bold');
640
+ doc.setFontSize(8);
641
+ doc.text(log.level.toUpperCase(), margin + 5, yPos);
642
+
643
+ // Add timestamp
644
+ doc.setTextColor('#6B7280');
645
+ doc.setFont('helvetica', 'normal');
646
+ doc.setFontSize(9);
647
+ doc.text(timestamp, margin + levelWidth + 10, yPos);
648
+
649
+ // Add category if present
650
+ if (log.category) {
651
+ const categoryX = margin + levelWidth + doc.getTextWidth(timestamp) + 20;
652
+ doc.setFillColor('#F3F4F6');
653
+
654
+ const categoryWidth = doc.getTextWidth(log.category) + 10;
655
+ doc.roundedRect(categoryX, yPos - 4, categoryWidth, lineHeight + 4, 2, 2, 'F');
656
+ doc.setTextColor('#6B7280');
657
+ doc.text(log.category, categoryX + 5, yPos);
658
+ }
659
+
660
+ yPos += lineHeight * 1.5;
661
+
662
+ // Add message
663
+ doc.setTextColor('#111827');
664
+ doc.setFontSize(10);
665
+
666
+ const messageLines = doc.splitTextToSize(log.message, maxLineWidth - 10);
667
+ doc.text(messageLines, margin + 5, yPos);
668
+ yPos += messageLines.length * lineHeight;
669
+
670
+ // Add details if present
671
+ if (log.details) {
672
+ doc.setTextColor('#6B7280');
673
+ doc.setFontSize(8);
674
+
675
+ const detailsStr = JSON.stringify(log.details, null, 2);
676
+ const detailsLines = doc.splitTextToSize(detailsStr, maxLineWidth - 15);
677
+
678
+ // Add details background
679
+ doc.setFillColor('#F9FAFB');
680
+ doc.roundedRect(margin + 5, yPos - 2, maxLineWidth - 10, detailsLines.length * lineHeight + 8, 1, 1, 'F');
681
+
682
+ doc.text(detailsLines, margin + 10, yPos + 4);
683
+ yPos += detailsLines.length * lineHeight + 10;
684
+ }
685
+
686
+ // Add separator line
687
+ doc.setDrawColor('#E5E7EB');
688
+ doc.setLineWidth(0.1);
689
+ doc.line(margin, yPos, pageWidth - margin, yPos);
690
+ yPos += lineHeight * 1.5;
691
+ };
692
+
693
+ // Add all logs
694
+ filteredLogs.forEach((log) => {
695
+ addLogEntry(log);
696
+ });
697
+
698
+ // Add footer to all pages
699
+ const totalPages = doc.internal.pages.length - 1;
700
+
701
+ for (let i = 1; i <= totalPages; i++) {
702
+ doc.setPage(i);
703
+ doc.setFontSize(8);
704
+ doc.setTextColor('#9CA3AF');
705
+
706
+ // Add page numbers
707
+ doc.text(`Page ${i} of ${totalPages}`, pageWidth / 2, doc.internal.pageSize.getHeight() - 10, {
708
+ align: 'center',
709
+ });
710
+
711
+ // Add footer text
712
+ doc.text('Generated by bolt.diy', margin, doc.internal.pageSize.getHeight() - 10);
713
+
714
+ const dateStr = new Date().toLocaleDateString();
715
+ doc.text(dateStr, pageWidth - margin, doc.internal.pageSize.getHeight() - 10, { align: 'right' });
716
+ }
717
+
718
+ // Save the PDF
719
+ doc.save(`bolt-event-logs-${new Date().toISOString()}.pdf`);
720
+ toast.success('Event logs exported successfully as PDF');
721
+ } catch (error) {
722
+ console.error('Failed to export PDF:', error);
723
+ toast.error('Failed to export event logs as PDF');
724
+ }
725
+ };
726
+
727
+ const exportAsText = () => {
728
+ try {
729
+ const textContent = filteredLogs
730
+ .map((log) => {
731
+ const timestamp = new Date(log.timestamp).toLocaleString();
732
+ let content = `[${timestamp}] ${log.level.toUpperCase()}: ${log.message}\n`;
733
+
734
+ if (log.category) {
735
+ content += `Category: ${log.category}\n`;
736
+ }
737
+
738
+ if (log.details) {
739
+ content += `Details:\n${JSON.stringify(log.details, null, 2)}\n`;
740
+ }
741
+
742
+ return content + '-'.repeat(80) + '\n';
743
+ })
744
+ .join('\n');
745
+
746
+ const blob = new Blob([textContent], { type: 'text/plain' });
747
+ const url = window.URL.createObjectURL(blob);
748
+ const a = document.createElement('a');
749
+ a.href = url;
750
+ a.download = `bolt-event-logs-${new Date().toISOString()}.txt`;
751
+ document.body.appendChild(a);
752
+ a.click();
753
+ window.URL.revokeObjectURL(url);
754
+ document.body.removeChild(a);
755
+ toast.success('Event logs exported successfully as text file');
756
+ } catch (error) {
757
+ console.error('Failed to export text file:', error);
758
+ toast.error('Failed to export event logs as text file');
759
+ }
760
+ };
761
+
762
+ const exportFormats: ExportFormat[] = [
763
+ {
764
+ id: 'json',
765
+ label: 'Export as JSON',
766
+ icon: 'i-ph:file-js',
767
+ handler: exportAsJSON,
768
+ },
769
+ {
770
+ id: 'csv',
771
+ label: 'Export as CSV',
772
+ icon: 'i-ph:file-csv',
773
+ handler: exportAsCSV,
774
+ },
775
+ {
776
+ id: 'pdf',
777
+ label: 'Export as PDF',
778
+ icon: 'i-ph:file-pdf',
779
+ handler: exportAsPDF,
780
+ },
781
+ {
782
+ id: 'txt',
783
+ label: 'Export as Text',
784
+ icon: 'i-ph:file-text',
785
+ handler: exportAsText,
786
+ },
787
+ ];
788
+
789
+ const ExportButton = () => {
790
+ const [isOpen, setIsOpen] = useState(false);
791
+
792
+ const handleOpenChange = useCallback((open: boolean) => {
793
+ setIsOpen(open);
794
+ }, []);
795
+
796
+ const handleFormatClick = useCallback((handler: () => void) => {
797
+ handler();
798
+ setIsOpen(false);
799
+ }, []);
800
+
801
+ return (
802
+ <DialogRoot open={isOpen} onOpenChange={handleOpenChange}>
803
+ <button
804
+ onClick={() => setIsOpen(true)}
805
+ className={classNames(
806
+ 'group flex items-center gap-2',
807
+ 'rounded-lg px-3 py-1.5',
808
+ 'text-sm text-gray-900 dark:text-white',
809
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
810
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
811
+ 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
812
+ 'transition-all duration-200',
813
+ )}
814
+ >
815
+ <span className="i-ph:download text-lg text-gray-500 dark:text-gray-400 group-hover:text-purple-500 transition-colors" />
816
+ Export
817
+ </button>
818
+
819
+ <Dialog showCloseButton>
820
+ <div className="p-6">
821
+ <DialogTitle className="flex items-center gap-2">
822
+ <div className="i-ph:download w-5 h-5" />
823
+ Export Event Logs
824
+ </DialogTitle>
825
+
826
+ <div className="mt-4 flex flex-col gap-2">
827
+ {exportFormats.map((format) => (
828
+ <button
829
+ key={format.id}
830
+ onClick={() => handleFormatClick(format.handler)}
831
+ className={classNames(
832
+ 'flex items-center gap-3 px-4 py-3 text-sm rounded-lg transition-colors w-full text-left',
833
+ 'bg-white dark:bg-[#0A0A0A]',
834
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
835
+ 'hover:bg-purple-50 dark:hover:bg-[#1a1a1a]',
836
+ 'hover:border-purple-200 dark:hover:border-purple-900/30',
837
+ 'text-bolt-elements-textPrimary',
838
+ )}
839
+ >
840
+ <div className={classNames(format.icon, 'w-5 h-5')} />
841
+ <div>
842
+ <div className="font-medium">{format.label}</div>
843
+ <div className="text-xs text-bolt-elements-textSecondary mt-0.5">
844
+ {format.id === 'json' && 'Export as a structured JSON file'}
845
+ {format.id === 'csv' && 'Export as a CSV spreadsheet'}
846
+ {format.id === 'pdf' && 'Export as a formatted PDF document'}
847
+ {format.id === 'txt' && 'Export as a formatted text file'}
848
+ </div>
849
+ </div>
850
+ </button>
851
+ ))}
852
+ </div>
853
+ </div>
854
+ </Dialog>
855
+ </DialogRoot>
856
+ );
857
+ };
858
+
859
+ return (
860
+ <div className="flex h-full flex-col gap-6">
861
+ <div className="flex items-center justify-between">
862
+ <DropdownMenu.Root open={showLevelFilter} onOpenChange={setShowLevelFilter}>
863
+ <DropdownMenu.Trigger asChild>
864
+ <button
865
+ className={classNames(
866
+ 'flex items-center gap-2',
867
+ 'rounded-lg px-3 py-1.5',
868
+ 'text-sm text-gray-900 dark:text-white',
869
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
870
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
871
+ 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
872
+ 'transition-all duration-200',
873
+ )}
874
+ >
875
+ <span
876
+ className={classNames('text-lg', selectedLevelOption?.icon || 'i-ph:funnel')}
877
+ style={{ color: selectedLevelOption?.color }}
878
+ />
879
+ {selectedLevelOption?.label || 'All Types'}
880
+ <span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
881
+ </button>
882
+ </DropdownMenu.Trigger>
883
+
884
+ <DropdownMenu.Portal>
885
+ <DropdownMenu.Content
886
+ className="min-w-[200px] bg-white dark:bg-[#0A0A0A] rounded-lg shadow-lg py-1 z-[250] animate-in fade-in-0 zoom-in-95 border border-[#E5E5E5] dark:border-[#1A1A1A]"
887
+ sideOffset={5}
888
+ align="start"
889
+ side="bottom"
890
+ >
891
+ {logLevelOptions.map((option) => (
892
+ <DropdownMenu.Item
893
+ key={option.value}
894
+ className="group flex items-center px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-purple-500/10 dark:hover:bg-purple-500/20 cursor-pointer transition-colors"
895
+ onClick={() => handleLevelFilterChange(option.value)}
896
+ >
897
+ <div className="mr-3 flex h-5 w-5 items-center justify-center">
898
+ <div
899
+ className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
900
+ style={{ color: option.color }}
901
+ />
902
+ </div>
903
+ <span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
904
+ </DropdownMenu.Item>
905
+ ))}
906
+ </DropdownMenu.Content>
907
+ </DropdownMenu.Portal>
908
+ </DropdownMenu.Root>
909
+
910
+ <div className="flex items-center gap-4">
911
+ <div className="flex items-center gap-2">
912
+ <Switch
913
+ checked={showTimestamps}
914
+ onCheckedChange={(value) => handlePreferenceChange('timestamps', value)}
915
+ className="data-[state=checked]:bg-purple-500"
916
+ />
917
+ <span className="text-sm text-gray-500 dark:text-gray-400">Show Timestamps</span>
918
+ </div>
919
+
920
+ <div className="flex items-center gap-2">
921
+ <Switch
922
+ checked={use24Hour}
923
+ onCheckedChange={(value) => handlePreferenceChange('24hour', value)}
924
+ className="data-[state=checked]:bg-purple-500"
925
+ />
926
+ <span className="text-sm text-gray-500 dark:text-gray-400">24h Time</span>
927
+ </div>
928
+
929
+ <div className="flex items-center gap-2">
930
+ <Switch
931
+ checked={autoExpand}
932
+ onCheckedChange={(value) => handlePreferenceChange('autoExpand', value)}
933
+ className="data-[state=checked]:bg-purple-500"
934
+ />
935
+ <span className="text-sm text-gray-500 dark:text-gray-400">Auto Expand</span>
936
+ </div>
937
+
938
+ <div className="w-px h-4 bg-gray-200 dark:bg-gray-700" />
939
+
940
+ <button
941
+ onClick={handleRefresh}
942
+ className={classNames(
943
+ 'group flex items-center gap-2',
944
+ 'rounded-lg px-3 py-1.5',
945
+ 'text-sm text-gray-900 dark:text-white',
946
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
947
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
948
+ 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
949
+ 'transition-all duration-200',
950
+ { 'animate-spin': isRefreshing },
951
+ )}
952
+ >
953
+ <span className="i-ph:arrows-clockwise text-lg text-gray-500 dark:text-gray-400 group-hover:text-purple-500 transition-colors" />
954
+ Refresh
955
+ </button>
956
+
957
+ <ExportButton />
958
+ </div>
959
+ </div>
960
+
961
+ <div className="flex flex-col gap-4">
962
+ <div className="relative">
963
+ <input
964
+ type="text"
965
+ placeholder="Search logs..."
966
+ value={searchQuery}
967
+ onChange={(e) => setSearchQuery(e.target.value)}
968
+ className={classNames(
969
+ 'w-full px-4 py-2 pl-10 rounded-lg',
970
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
971
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
972
+ 'text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400',
973
+ 'focus:outline-none focus:ring-2 focus:ring-purple-500/20 focus:border-purple-500',
974
+ 'transition-all duration-200',
975
+ )}
976
+ />
977
+ <div className="absolute left-3 top-1/2 -translate-y-1/2">
978
+ <div className="i-ph:magnifying-glass text-lg text-gray-500 dark:text-gray-400" />
979
+ </div>
980
+ </div>
981
+
982
+ {filteredLogs.length === 0 ? (
983
+ <motion.div
984
+ initial={{ opacity: 0, y: 20 }}
985
+ animate={{ opacity: 1, y: 0 }}
986
+ className={classNames(
987
+ 'flex flex-col items-center justify-center gap-4',
988
+ 'rounded-lg p-8 text-center',
989
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
990
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
991
+ )}
992
+ >
993
+ <span className="i-ph:clipboard-text text-4xl text-gray-400 dark:text-gray-600" />
994
+ <div className="flex flex-col gap-1">
995
+ <h3 className="text-sm font-medium text-gray-900 dark:text-white">No Logs Found</h3>
996
+ <p className="text-sm text-gray-500 dark:text-gray-400">Try adjusting your search or filters</p>
997
+ </div>
998
+ </motion.div>
999
+ ) : (
1000
+ filteredLogs.map((log) => (
1001
+ <LogEntryItem
1002
+ key={log.id}
1003
+ log={log}
1004
+ isExpanded={autoExpand}
1005
+ use24Hour={use24Hour}
1006
+ showTimestamp={showTimestamps}
1007
+ />
1008
+ ))
1009
+ )}
1010
+ </div>
1011
+ </div>
1012
+ );
1013
+ }