codex-linux 1.0.0

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 (367) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.eslintrc.json +27 -0
  3. package/.github/workflows/ci.yml +156 -0
  4. package/.huskyrc +7 -0
  5. package/.lintstagedrc +13 -0
  6. package/.prettierrc +12 -0
  7. package/CLAUDE.md +163 -0
  8. package/DESIGN_SUPERIOR.md +73 -0
  9. package/Dockerfile +64 -0
  10. package/INSTALLATION.md +152 -0
  11. package/LICENSE +21 -0
  12. package/README.md +245 -0
  13. package/assets/skills/code-review/instructions.md +102 -0
  14. package/assets/skills/code-review/skill.yaml +15 -0
  15. package/assets/skills/refactoring/instructions.md +149 -0
  16. package/assets/skills/refactoring/skill.yaml +15 -0
  17. package/assets/skills/testing/skill.yaml +15 -0
  18. package/commitlint.config.js +23 -0
  19. package/dist/main/DatabaseManager.js +763 -0
  20. package/dist/main/DatabaseManager.js.map +1 -0
  21. package/dist/main/SettingsManager.js +61 -0
  22. package/dist/main/SettingsManager.js.map +1 -0
  23. package/dist/main/agents/AgentOrchestrator.js +787 -0
  24. package/dist/main/agents/AgentOrchestrator.js.map +1 -0
  25. package/dist/main/agents/AgentSDK.js +219 -0
  26. package/dist/main/agents/AgentSDK.js.map +1 -0
  27. package/dist/main/agents/AgentTools.js +348 -0
  28. package/dist/main/agents/AgentTools.js.map +1 -0
  29. package/dist/main/agents/CodeIndex.js +233 -0
  30. package/dist/main/agents/CodeIndex.js.map +1 -0
  31. package/dist/main/agents/EmbeddingService.js +80 -0
  32. package/dist/main/agents/EmbeddingService.js.map +1 -0
  33. package/dist/main/agents/NativeToolCalling.js +206 -0
  34. package/dist/main/agents/NativeToolCalling.js.map +1 -0
  35. package/dist/main/api/APIServer.js +278 -0
  36. package/dist/main/api/APIServer.js.map +1 -0
  37. package/dist/main/api/RateLimiter.js +138 -0
  38. package/dist/main/api/RateLimiter.js.map +1 -0
  39. package/dist/main/api/WebSocketManager.js +300 -0
  40. package/dist/main/api/WebSocketManager.js.map +1 -0
  41. package/dist/main/assistant/ContextOptimizer.js +192 -0
  42. package/dist/main/assistant/ContextOptimizer.js.map +1 -0
  43. package/dist/main/assistant/PredictedOutputManager.js +172 -0
  44. package/dist/main/assistant/PredictedOutputManager.js.map +1 -0
  45. package/dist/main/assistant/PromptCacheManager.js +193 -0
  46. package/dist/main/assistant/PromptCacheManager.js.map +1 -0
  47. package/dist/main/assistant/PromptOptimizer.js +626 -0
  48. package/dist/main/assistant/PromptOptimizer.js.map +1 -0
  49. package/dist/main/assistant/SmartCodeAssistant.js +224 -0
  50. package/dist/main/assistant/SmartCodeAssistant.js.map +1 -0
  51. package/dist/main/auth/SessionManager.js +300 -0
  52. package/dist/main/auth/SessionManager.js.map +1 -0
  53. package/dist/main/automations/AdvancedWebhookSystem.js +212 -0
  54. package/dist/main/automations/AdvancedWebhookSystem.js.map +1 -0
  55. package/dist/main/automations/AutomationScheduler.js +269 -0
  56. package/dist/main/automations/AutomationScheduler.js.map +1 -0
  57. package/dist/main/automations/BatchProcessingSystem.js +159 -0
  58. package/dist/main/automations/BatchProcessingSystem.js.map +1 -0
  59. package/dist/main/automations/BrowserAutomationManager.js +195 -0
  60. package/dist/main/automations/BrowserAutomationManager.js.map +1 -0
  61. package/dist/main/automations/GitHubActionsManager.js +129 -0
  62. package/dist/main/automations/GitHubActionsManager.js.map +1 -0
  63. package/dist/main/automations/GitLabCIManager.js +122 -0
  64. package/dist/main/automations/GitLabCIManager.js.map +1 -0
  65. package/dist/main/automations/PriorityQueueManager.js +240 -0
  66. package/dist/main/automations/PriorityQueueManager.js.map +1 -0
  67. package/dist/main/background/BackgroundModeManager.js +117 -0
  68. package/dist/main/background/BackgroundModeManager.js.map +1 -0
  69. package/dist/main/backup/BackupManager.js +254 -0
  70. package/dist/main/backup/BackupManager.js.map +1 -0
  71. package/dist/main/backup/MigrationManager.js +114 -0
  72. package/dist/main/backup/MigrationManager.js.map +1 -0
  73. package/dist/main/commands/SlashCommandManager.js +399 -0
  74. package/dist/main/commands/SlashCommandManager.js.map +1 -0
  75. package/dist/main/config/ClaudeMdParser.js +519 -0
  76. package/dist/main/config/ClaudeMdParser.js.map +1 -0
  77. package/dist/main/config/CustomizationManager.js +381 -0
  78. package/dist/main/config/CustomizationManager.js.map +1 -0
  79. package/dist/main/config/LaunchConfigManager.js +211 -0
  80. package/dist/main/config/LaunchConfigManager.js.map +1 -0
  81. package/dist/main/config/SettingsManager.js +166 -0
  82. package/dist/main/config/SettingsManager.js.map +1 -0
  83. package/dist/main/connectors/ConnectorManager.js +151 -0
  84. package/dist/main/connectors/ConnectorManager.js.map +1 -0
  85. package/dist/main/connectors/DatabaseConnector.js +222 -0
  86. package/dist/main/connectors/DatabaseConnector.js.map +1 -0
  87. package/dist/main/cowork/CoworkManager.js +324 -0
  88. package/dist/main/cowork/CoworkManager.js.map +1 -0
  89. package/dist/main/evals/AgentEvalFramework.js +538 -0
  90. package/dist/main/evals/AgentEvalFramework.js.map +1 -0
  91. package/dist/main/evals/GraderManager.js +285 -0
  92. package/dist/main/evals/GraderManager.js.map +1 -0
  93. package/dist/main/git/GitWorktreeManager.js +214 -0
  94. package/dist/main/git/GitWorktreeManager.js.map +1 -0
  95. package/dist/main/github/GitHubPRMonitor.js +244 -0
  96. package/dist/main/github/GitHubPRMonitor.js.map +1 -0
  97. package/dist/main/ide/ContinueInManager.js +181 -0
  98. package/dist/main/ide/ContinueInManager.js.map +1 -0
  99. package/dist/main/ide/IDEIntegration.js +277 -0
  100. package/dist/main/ide/IDEIntegration.js.map +1 -0
  101. package/dist/main/integrations/LinearManager.js +252 -0
  102. package/dist/main/integrations/LinearManager.js.map +1 -0
  103. package/dist/main/integrations/SlackBotManager.js +247 -0
  104. package/dist/main/integrations/SlackBotManager.js.map +1 -0
  105. package/dist/main/lsp/LSPManager.js +394 -0
  106. package/dist/main/lsp/LSPManager.js.map +1 -0
  107. package/dist/main/main.js +1087 -0
  108. package/dist/main/main.js.map +1 -0
  109. package/dist/main/mcp/MCPConfigurationManager.js +281 -0
  110. package/dist/main/mcp/MCPConfigurationManager.js.map +1 -0
  111. package/dist/main/mcp/MCPManager.js +710 -0
  112. package/dist/main/mcp/MCPManager.js.map +1 -0
  113. package/dist/main/mcp/MCPRegistry.js +272 -0
  114. package/dist/main/mcp/MCPRegistry.js.map +1 -0
  115. package/dist/main/monitoring/ErrorRecoveryManager.js +268 -0
  116. package/dist/main/monitoring/ErrorRecoveryManager.js.map +1 -0
  117. package/dist/main/monitoring/ErrorTracker.js +57 -0
  118. package/dist/main/monitoring/ErrorTracker.js.map +1 -0
  119. package/dist/main/monitoring/MetricsCollector.js +155 -0
  120. package/dist/main/monitoring/MetricsCollector.js.map +1 -0
  121. package/dist/main/monitoring/TraceGradingSystem.js +148 -0
  122. package/dist/main/monitoring/TraceGradingSystem.js.map +1 -0
  123. package/dist/main/notifications/NotificationManager.js +67 -0
  124. package/dist/main/notifications/NotificationManager.js.map +1 -0
  125. package/dist/main/pair/AIPairProgramming.js +200 -0
  126. package/dist/main/pair/AIPairProgramming.js.map +1 -0
  127. package/dist/main/plugins/PluginManager.js +222 -0
  128. package/dist/main/plugins/PluginManager.js.map +1 -0
  129. package/dist/main/plugins/PluginMarketplace.js +237 -0
  130. package/dist/main/plugins/PluginMarketplace.js.map +1 -0
  131. package/dist/main/preload.js +189 -0
  132. package/dist/main/preload.js.map +1 -0
  133. package/dist/main/preview/PreviewSessionManager.js +170 -0
  134. package/dist/main/preview/PreviewSessionManager.js.map +1 -0
  135. package/dist/main/providers/AIProviderManager.js +327 -0
  136. package/dist/main/providers/AIProviderManager.js.map +1 -0
  137. package/dist/main/providers/FineTuningManager.js +276 -0
  138. package/dist/main/providers/FineTuningManager.js.map +1 -0
  139. package/dist/main/providers/FreeModelsProvider.js +1104 -0
  140. package/dist/main/providers/FreeModelsProvider.js.map +1 -0
  141. package/dist/main/realtime/RealtimeManager.js +116 -0
  142. package/dist/main/realtime/RealtimeManager.js.map +1 -0
  143. package/dist/main/remote/CloudEnvironmentManager.js +232 -0
  144. package/dist/main/remote/CloudEnvironmentManager.js.map +1 -0
  145. package/dist/main/remote/RemoteSessionManager.js +255 -0
  146. package/dist/main/remote/RemoteSessionManager.js.map +1 -0
  147. package/dist/main/search/DeepResearchManager.js +335 -0
  148. package/dist/main/search/DeepResearchManager.js.map +1 -0
  149. package/dist/main/search/WebSearchIntegration.js +147 -0
  150. package/dist/main/search/WebSearchIntegration.js.map +1 -0
  151. package/dist/main/security/AdminConsoleManager.js +223 -0
  152. package/dist/main/security/AdminConsoleManager.js.map +1 -0
  153. package/dist/main/security/AuditLogger.js +136 -0
  154. package/dist/main/security/AuditLogger.js.map +1 -0
  155. package/dist/main/security/PermissionManager.js +144 -0
  156. package/dist/main/security/PermissionManager.js.map +1 -0
  157. package/dist/main/security/SSOManager.js +173 -0
  158. package/dist/main/security/SSOManager.js.map +1 -0
  159. package/dist/main/security/SecurityManager.js +152 -0
  160. package/dist/main/security/SecurityManager.js.map +1 -0
  161. package/dist/main/skills/SkillsManager.js +223 -0
  162. package/dist/main/skills/SkillsManager.js.map +1 -0
  163. package/dist/main/ssh/SSHManager.js +65 -0
  164. package/dist/main/ssh/SSHManager.js.map +1 -0
  165. package/dist/main/streaming/StreamingManager.js +225 -0
  166. package/dist/main/streaming/StreamingManager.js.map +1 -0
  167. package/dist/main/sync/CloudSyncManager.js +422 -0
  168. package/dist/main/sync/CloudSyncManager.js.map +1 -0
  169. package/dist/main/types.js +28 -0
  170. package/dist/main/types.js.map +1 -0
  171. package/dist/main/verification/AutoVerifyManager.js +235 -0
  172. package/dist/main/verification/AutoVerifyManager.js.map +1 -0
  173. package/dist/main/vision/ComputerUseManager.js +376 -0
  174. package/dist/main/vision/ComputerUseManager.js.map +1 -0
  175. package/dist/main/vision/ImageVideoGenerationManager.js +401 -0
  176. package/dist/main/vision/ImageVideoGenerationManager.js.map +1 -0
  177. package/dist/main/vision/VisionManager.js +172 -0
  178. package/dist/main/vision/VisionManager.js.map +1 -0
  179. package/dist/renderer/assets/main-DJlZQBCA.js +304 -0
  180. package/dist/renderer/assets/main-N33ZXEr8.css +1 -0
  181. package/dist/renderer/index.html +21 -0
  182. package/dist/renderer/manifest.json +42 -0
  183. package/dist/renderer/sw.ts +109 -0
  184. package/dist/shared/types.js +35 -0
  185. package/dist/shared/types.js.map +1 -0
  186. package/docker-compose.yml +65 -0
  187. package/docs/API.md +307 -0
  188. package/docs/USER_GUIDE.md +476 -0
  189. package/examples/plugins/sample-plugin/package.json +41 -0
  190. package/examples/plugins/sample-plugin/src/index.ts +75 -0
  191. package/index.html +20 -0
  192. package/jest.config.js +39 -0
  193. package/package.json +180 -0
  194. package/packages/cli/package.json +29 -0
  195. package/packages/cli/src/commands/agents.ts +199 -0
  196. package/packages/cli/src/commands/tasks.ts +61 -0
  197. package/packages/cli/src/index.ts +91 -0
  198. package/packages/cli/src/utils/api.ts +45 -0
  199. package/packages/cli/src/utils/config.ts +61 -0
  200. package/packages/npm-installer/bin/codex-linux +126 -0
  201. package/packages/npm-installer/lib/download.js +273 -0
  202. package/packages/npm-installer/package.json +42 -0
  203. package/packages/vscode-extension/package.json +167 -0
  204. package/packages/vscode-extension/src/api.ts +68 -0
  205. package/packages/vscode-extension/src/extension.ts +161 -0
  206. package/packages/vscode-extension/src/panels/chatPanel.ts +265 -0
  207. package/packages/vscode-extension/src/panels/createAgentPanel.ts +227 -0
  208. package/packages/vscode-extension/src/providers/agentsProvider.ts +80 -0
  209. package/postcss.config.js +6 -0
  210. package/public/manifest.json +42 -0
  211. package/public/sw.ts +109 -0
  212. package/scripts/install-dev.sh +103 -0
  213. package/scripts/install.sh +275 -0
  214. package/src/main/DatabaseManager.ts +950 -0
  215. package/src/main/SettingsManager.ts +63 -0
  216. package/src/main/agents/AgentOrchestrator.ts +930 -0
  217. package/src/main/agents/AgentSDK.ts +269 -0
  218. package/src/main/agents/AgentTools.ts +380 -0
  219. package/src/main/agents/CodeIndex.ts +240 -0
  220. package/src/main/agents/EmbeddingService.ts +88 -0
  221. package/src/main/agents/NativeToolCalling.ts +245 -0
  222. package/src/main/api/APIServer.ts +316 -0
  223. package/src/main/api/RateLimiter.ts +165 -0
  224. package/src/main/api/WebSocketManager.ts +398 -0
  225. package/src/main/assistant/ContextOptimizer.ts +214 -0
  226. package/src/main/assistant/PredictedOutputManager.ts +265 -0
  227. package/src/main/assistant/PromptCacheManager.ts +280 -0
  228. package/src/main/assistant/PromptOptimizer.ts +746 -0
  229. package/src/main/assistant/SmartCodeAssistant.ts +234 -0
  230. package/src/main/auth/SessionManager.ts +415 -0
  231. package/src/main/automations/AdvancedWebhookSystem.ts +281 -0
  232. package/src/main/automations/AutomationScheduler.ts +272 -0
  233. package/src/main/automations/BatchProcessingSystem.ts +207 -0
  234. package/src/main/automations/BrowserAutomationManager.ts +203 -0
  235. package/src/main/automations/GitHubActionsManager.ts +151 -0
  236. package/src/main/automations/GitLabCIManager.ts +206 -0
  237. package/src/main/automations/PriorityQueueManager.ts +328 -0
  238. package/src/main/background/BackgroundModeManager.ts +130 -0
  239. package/src/main/backup/BackupManager.ts +287 -0
  240. package/src/main/backup/MigrationManager.ts +132 -0
  241. package/src/main/commands/SlashCommandManager.ts +407 -0
  242. package/src/main/config/ClaudeMdParser.ts +539 -0
  243. package/src/main/config/CustomizationManager.ts +493 -0
  244. package/src/main/config/LaunchConfigManager.ts +212 -0
  245. package/src/main/config/SettingsManager.ts +163 -0
  246. package/src/main/connectors/ConnectorManager.ts +175 -0
  247. package/src/main/connectors/DatabaseConnector.ts +212 -0
  248. package/src/main/cowork/CoworkManager.ts +431 -0
  249. package/src/main/evals/AgentEvalFramework.ts +665 -0
  250. package/src/main/evals/GraderManager.ts +417 -0
  251. package/src/main/git/GitWorktreeManager.ts +211 -0
  252. package/src/main/github/GitHubPRMonitor.ts +317 -0
  253. package/src/main/ide/ContinueInManager.ts +180 -0
  254. package/src/main/ide/IDEIntegration.ts +288 -0
  255. package/src/main/integrations/LinearManager.ts +327 -0
  256. package/src/main/integrations/SlackBotManager.ts +312 -0
  257. package/src/main/lsp/LSPManager.ts +445 -0
  258. package/src/main/main.ts +1221 -0
  259. package/src/main/mcp/MCPConfigurationManager.ts +281 -0
  260. package/src/main/mcp/MCPManager.ts +799 -0
  261. package/src/main/mcp/MCPRegistry.ts +273 -0
  262. package/src/main/monitoring/ErrorRecoveryManager.ts +359 -0
  263. package/src/main/monitoring/ErrorTracker.ts +60 -0
  264. package/src/main/monitoring/MetricsCollector.ts +196 -0
  265. package/src/main/monitoring/TraceGradingSystem.ts +196 -0
  266. package/src/main/notifications/NotificationManager.ts +96 -0
  267. package/src/main/pair/AIPairProgramming.ts +290 -0
  268. package/src/main/plugins/PluginManager.ts +266 -0
  269. package/src/main/plugins/PluginMarketplace.ts +318 -0
  270. package/src/main/preload.ts +215 -0
  271. package/src/main/preview/PreviewSessionManager.ts +186 -0
  272. package/src/main/providers/AIProviderManager.ts +394 -0
  273. package/src/main/providers/FineTuningManager.ts +390 -0
  274. package/src/main/providers/FreeModelsProvider.ts +1156 -0
  275. package/src/main/realtime/RealtimeManager.ts +147 -0
  276. package/src/main/remote/CloudEnvironmentManager.ts +253 -0
  277. package/src/main/remote/RemoteSessionManager.ts +323 -0
  278. package/src/main/search/DeepResearchManager.ts +458 -0
  279. package/src/main/search/WebSearchIntegration.ts +203 -0
  280. package/src/main/security/AdminConsoleManager.ts +244 -0
  281. package/src/main/security/AuditLogger.ts +143 -0
  282. package/src/main/security/PermissionManager.ts +184 -0
  283. package/src/main/security/SSOManager.ts +241 -0
  284. package/src/main/security/SecurityManager.ts +139 -0
  285. package/src/main/skills/SkillsManager.ts +218 -0
  286. package/src/main/ssh/SSHManager.ts +86 -0
  287. package/src/main/streaming/StreamingManager.ts +306 -0
  288. package/src/main/sync/CloudSyncManager.ts +532 -0
  289. package/src/main/verification/AutoVerifyManager.ts +285 -0
  290. package/src/main/vision/ComputerUseManager.ts +475 -0
  291. package/src/main/vision/ImageVideoGenerationManager.ts +526 -0
  292. package/src/main/vision/VisionManager.ts +186 -0
  293. package/src/renderer/App.tsx +314 -0
  294. package/src/renderer/components/AdvancedSettingsPanel.tsx +225 -0
  295. package/src/renderer/components/AgentPanel.tsx +760 -0
  296. package/src/renderer/components/AppPreview.tsx +220 -0
  297. package/src/renderer/components/AuditTrailPanel.tsx +148 -0
  298. package/src/renderer/components/AutomationPanel.tsx +220 -0
  299. package/src/renderer/components/ChatInterface.tsx +595 -0
  300. package/src/renderer/components/ChatTab.tsx +296 -0
  301. package/src/renderer/components/CodeEditor.tsx +257 -0
  302. package/src/renderer/components/CodeReviewPanel.tsx +256 -0
  303. package/src/renderer/components/CodeWorkspace.tsx +192 -0
  304. package/src/renderer/components/CodebaseDashboard.tsx +295 -0
  305. package/src/renderer/components/ComputerUsePanel.tsx +262 -0
  306. package/src/renderer/components/ConnectorsPanel.tsx +471 -0
  307. package/src/renderer/components/ContextMenu.tsx +155 -0
  308. package/src/renderer/components/ContextUsageDisplay.tsx +248 -0
  309. package/src/renderer/components/CoworkPanel.tsx +415 -0
  310. package/src/renderer/components/DiffViewer.tsx +452 -0
  311. package/src/renderer/components/ErrorBoundary.tsx +273 -0
  312. package/src/renderer/components/ExtendedThinkingToggle.tsx +244 -0
  313. package/src/renderer/components/FileAttachments.tsx +247 -0
  314. package/src/renderer/components/FileExplorer.tsx +242 -0
  315. package/src/renderer/components/FileExplorerPanel.tsx +302 -0
  316. package/src/renderer/components/GitPanel.tsx +154 -0
  317. package/src/renderer/components/Header.tsx +113 -0
  318. package/src/renderer/components/MCPPanel.tsx +326 -0
  319. package/src/renderer/components/MentionAutocomplete.tsx +239 -0
  320. package/src/renderer/components/PermissionPanel.tsx +159 -0
  321. package/src/renderer/components/PermissionSelector.tsx +203 -0
  322. package/src/renderer/components/PluginMarketplace.tsx +325 -0
  323. package/src/renderer/components/PromptOptimizerPanel.tsx +399 -0
  324. package/src/renderer/components/SearchPanel.tsx +173 -0
  325. package/src/renderer/components/SearchReplace.tsx +284 -0
  326. package/src/renderer/components/SessionSidebar.tsx +367 -0
  327. package/src/renderer/components/SettingsPanel.tsx +426 -0
  328. package/src/renderer/components/Sidebar.tsx +100 -0
  329. package/src/renderer/components/SkillsPanel.tsx +245 -0
  330. package/src/renderer/components/SplitPane.tsx +173 -0
  331. package/src/renderer/components/Terminal.tsx +190 -0
  332. package/src/renderer/components/VoiceCommand.tsx +129 -0
  333. package/src/renderer/components/WorktreePanel.tsx +163 -0
  334. package/src/renderer/components/ui/AriaComponents.tsx +193 -0
  335. package/src/renderer/components/ui/Button.tsx +68 -0
  336. package/src/renderer/components/ui/Card.tsx +102 -0
  337. package/src/renderer/components/ui/Input.tsx +44 -0
  338. package/src/renderer/components/ui/Skeleton.tsx +55 -0
  339. package/src/renderer/components/ui/VirtualList.tsx +196 -0
  340. package/src/renderer/i18n/I18nProvider.tsx +101 -0
  341. package/src/renderer/i18n/de.ts +161 -0
  342. package/src/renderer/i18n/en.ts +163 -0
  343. package/src/renderer/i18n/es.ts +161 -0
  344. package/src/renderer/i18n/fr.ts +161 -0
  345. package/src/renderer/i18n/index.ts +44 -0
  346. package/src/renderer/index.css +129 -0
  347. package/src/renderer/lib/accessibility.tsx +287 -0
  348. package/src/renderer/lib/hooks.ts +304 -0
  349. package/src/renderer/lib/utils.ts +6 -0
  350. package/src/renderer/main.tsx +25 -0
  351. package/src/renderer/styles/minimalist.css +539 -0
  352. package/src/renderer/sw.ts +180 -0
  353. package/src/renderer/types.d.ts +138 -0
  354. package/src/shared/types.ts +813 -0
  355. package/supabase/schema.sql +234 -0
  356. package/tailwind.config.js +78 -0
  357. package/tests/e2e/package.json +15 -0
  358. package/tests/e2e/playwright.config.ts +31 -0
  359. package/tests/e2e/specs/app.spec.ts +194 -0
  360. package/tests/setup.ts +99 -0
  361. package/tests/unit/AgentOrchestrator.test.ts +274 -0
  362. package/tests/unit/DatabaseManager.test.ts +262 -0
  363. package/tests/unit/GitWorktreeManager.test.ts +150 -0
  364. package/tests/unit/SecurityManager.test.ts +110 -0
  365. package/tsconfig.main.json +22 -0
  366. package/tsconfig.renderer.json +27 -0
  367. package/vite.config.ts +28 -0
@@ -0,0 +1,159 @@
1
+ import React from 'react';
2
+ import { PermissionRequest } from '../../shared/types';
3
+ import {
4
+ FileEdit,
5
+ Terminal,
6
+ Wrench,
7
+ Check,
8
+ X,
9
+ Clock,
10
+ AlertCircle
11
+ } from 'lucide-react';
12
+
13
+ interface PermissionPanelProps {
14
+ requests: PermissionRequest[];
15
+ onApprove: (requestId: string) => void;
16
+ onReject: (requestId: string) => void;
17
+ onViewDetails?: (request: PermissionRequest) => void;
18
+ }
19
+
20
+ const getActionIcon = (type: string) => {
21
+ switch (type) {
22
+ case 'edit':
23
+ return <FileEdit className="w-4 h-4" />;
24
+ case 'command':
25
+ return <Terminal className="w-4 h-4" />;
26
+ case 'tool':
27
+ return <Wrench className="w-4 h-4" />;
28
+ default:
29
+ return <AlertCircle className="w-4 h-4" />;
30
+ }
31
+ };
32
+
33
+ const getActionColor = (type: string) => {
34
+ switch (type) {
35
+ case 'edit':
36
+ return 'text-blue-500 bg-blue-500/10';
37
+ case 'command':
38
+ return 'text-yellow-500 bg-yellow-500/10';
39
+ case 'tool':
40
+ return 'text-purple-500 bg-purple-500/10';
41
+ default:
42
+ return 'text-gray-500 bg-gray-500/10';
43
+ }
44
+ };
45
+
46
+ export const PermissionPanel: React.FC<PermissionPanelProps> = ({
47
+ requests,
48
+ onApprove,
49
+ onReject,
50
+ onViewDetails
51
+ }) => {
52
+ if (requests.length === 0) {
53
+ return (
54
+ <div className="flex flex-col items-center justify-center h-full text-muted-foreground p-8">
55
+ <Check className="w-16 h-16 mb-4 opacity-30" />
56
+ <h3 className="text-lg font-medium">No Pending Permissions</h3>
57
+ <p className="text-sm mt-2 text-center">
58
+ All actions have been approved or rejected
59
+ </p>
60
+ </div>
61
+ );
62
+ }
63
+
64
+ return (
65
+ <div className="flex flex-col h-full">
66
+ <div className="px-4 py-3 border-b border-border flex items-center justify-between bg-background/50">
67
+ <div className="flex items-center gap-2">
68
+ <Clock className="w-5 h-5 text-yellow-500" />
69
+ <h3 className="font-medium">Pending Permissions</h3>
70
+ </div>
71
+ <span className="text-sm text-muted-foreground">
72
+ {requests.length} pending
73
+ </span>
74
+ </div>
75
+
76
+ <div className="flex-1 overflow-auto p-4 space-y-3">
77
+ {requests.map((request) => (
78
+ <div
79
+ key={request.id}
80
+ className="bg-card border border-border rounded-lg p-4 hover:border-primary/50 transition-colors"
81
+ >
82
+ {/* Header */}
83
+ <div className="flex items-start justify-between mb-3">
84
+ <div className="flex items-center gap-2">
85
+ <div className={`p-2 rounded-lg ${getActionColor(request.type)}`}>
86
+ {getActionIcon(request.type)}
87
+ </div>
88
+ <div>
89
+ <span className="font-medium capitalize">{request.type}</span>
90
+ <span className="text-muted-foreground text-sm ml-2">
91
+ {request.action}
92
+ </span>
93
+ </div>
94
+ </div>
95
+ <span className="text-xs text-muted-foreground">
96
+ {new Date(request.createdAt).toLocaleTimeString()}
97
+ </span>
98
+ </div>
99
+
100
+ {/* Details */}
101
+ {request.details && Object.keys(request.details).length > 0 && (
102
+ <div className="bg-muted/50 rounded-lg p-3 mb-3">
103
+ {request.type === 'edit' && request.details.filePath && (
104
+ <div className="text-sm">
105
+ <span className="text-muted-foreground">File: </span>
106
+ <code className="bg-background px-1.5 py-0.5 rounded text-xs">
107
+ {request.details.filePath}
108
+ </code>
109
+ </div>
110
+ )}
111
+ {request.type === 'command' && request.details.command && (
112
+ <div className="text-sm">
113
+ <span className="text-muted-foreground">Command: </span>
114
+ <code className="bg-background px-1.5 py-0.5 rounded text-xs font-mono">
115
+ {request.details.command}
116
+ </code>
117
+ </div>
118
+ )}
119
+ {request.details.description && (
120
+ <p className="text-sm text-muted-foreground mt-2">
121
+ {request.details.description}
122
+ </p>
123
+ )}
124
+ </div>
125
+ )}
126
+
127
+ {/* Actions */}
128
+ <div className="flex items-center justify-end gap-2">
129
+ {onViewDetails && (
130
+ <button
131
+ onClick={() => onViewDetails(request)}
132
+ className="px-3 py-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
133
+ >
134
+ View Details
135
+ </button>
136
+ )}
137
+ <button
138
+ onClick={() => onReject(request.id)}
139
+ className="flex items-center gap-1.5 px-3 py-1.5 text-sm text-red-500 hover:bg-red-500/10 rounded-lg transition-colors"
140
+ >
141
+ <X className="w-4 h-4" />
142
+ Reject
143
+ </button>
144
+ <button
145
+ onClick={() => onApprove(request.id)}
146
+ className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-green-500/10 text-green-500 hover:bg-green-500/20 rounded-lg transition-colors"
147
+ >
148
+ <Check className="w-4 h-4" />
149
+ Approve
150
+ </button>
151
+ </div>
152
+ </div>
153
+ ))}
154
+ </div>
155
+ </div>
156
+ );
157
+ };
158
+
159
+ export default PermissionPanel;
@@ -0,0 +1,203 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { PermissionMode } from '../../shared/types';
3
+ import {
4
+ Shield,
5
+ ShieldCheck,
6
+ ShieldAlert,
7
+ ShieldOff,
8
+ ChevronDown,
9
+ AlertTriangle
10
+ } from 'lucide-react';
11
+
12
+ interface PermissionSelectorProps {
13
+ currentMode: PermissionMode;
14
+ onModeChange: (mode: PermissionMode) => void;
15
+ allowBypass: boolean;
16
+ disabled?: boolean;
17
+ showDescriptions?: boolean;
18
+ }
19
+
20
+ const permissionModes = [
21
+ {
22
+ mode: PermissionMode.ASK,
23
+ label: 'Ask permissions',
24
+ description: 'Ask before editing files or running commands',
25
+ icon: Shield,
26
+ color: 'text-blue-500',
27
+ bgColor: 'bg-blue-500/10',
28
+ borderColor: 'border-blue-500/30'
29
+ },
30
+ {
31
+ mode: PermissionMode.AUTO_ACCEPT_EDITS,
32
+ label: 'Auto accept edits',
33
+ description: 'Auto-accept file edits, ask for commands',
34
+ icon: ShieldCheck,
35
+ color: 'text-green-500',
36
+ bgColor: 'bg-green-500/10',
37
+ borderColor: 'border-green-500/30'
38
+ },
39
+ {
40
+ mode: PermissionMode.PLAN,
41
+ label: 'Plan mode',
42
+ description: 'Analyze only, no changes or commands',
43
+ icon: ShieldAlert,
44
+ color: 'text-yellow-500',
45
+ bgColor: 'bg-yellow-500/10',
46
+ borderColor: 'border-yellow-500/30'
47
+ },
48
+ {
49
+ mode: PermissionMode.BYPASS,
50
+ label: 'Bypass permissions',
51
+ description: 'Run without any permission prompts',
52
+ icon: ShieldOff,
53
+ color: 'text-red-500',
54
+ bgColor: 'bg-red-500/10',
55
+ borderColor: 'border-red-500/30',
56
+ dangerous: true
57
+ }
58
+ ];
59
+
60
+ export const PermissionSelector: React.FC<PermissionSelectorProps> = ({
61
+ currentMode,
62
+ onModeChange,
63
+ allowBypass,
64
+ disabled = false,
65
+ showDescriptions = true
66
+ }) => {
67
+ const [isOpen, setIsOpen] = useState(false);
68
+ const [showBypassWarning, setShowBypassWarning] = useState(false);
69
+
70
+ const currentConfig = permissionModes.find(m => m.mode === currentMode) || permissionModes[0];
71
+ const Icon = currentConfig.icon;
72
+
73
+ const handleModeSelect = (mode: PermissionMode) => {
74
+ if (mode === PermissionMode.BYPASS && !allowBypass) {
75
+ setShowBypassWarning(true);
76
+ return;
77
+ }
78
+
79
+ onModeChange(mode);
80
+ setIsOpen(false);
81
+ };
82
+
83
+ useEffect(() => {
84
+ const handleClickOutside = () => setIsOpen(false);
85
+ if (isOpen) {
86
+ document.addEventListener('click', handleClickOutside);
87
+ return () => document.removeEventListener('click', handleClickOutside);
88
+ }
89
+ }, [isOpen]);
90
+
91
+ return (
92
+ <div className="relative">
93
+ {/* Selector Button */}
94
+ <button
95
+ onClick={(e) => {
96
+ e.stopPropagation();
97
+ if (!disabled) setIsOpen(!isOpen);
98
+ }}
99
+ disabled={disabled}
100
+ className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-all ${
101
+ disabled
102
+ ? 'opacity-50 cursor-not-allowed bg-muted'
103
+ : 'hover:bg-muted cursor-pointer'
104
+ } ${currentConfig.bgColor} ${currentConfig.borderColor}`}
105
+ >
106
+ <Icon className={`w-4 h-4 ${currentConfig.color}`} />
107
+ <span className="text-sm font-medium">{currentConfig.label}</span>
108
+ {!disabled && <ChevronDown className={`w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : ''}`} />}
109
+ </button>
110
+
111
+ {/* Dropdown Menu */}
112
+ {isOpen && (
113
+ <div className="absolute top-full left-0 mt-1 w-80 bg-card border border-border rounded-lg shadow-lg z-50 overflow-hidden">
114
+ <div className="p-2 space-y-1">
115
+ {permissionModes.map((config) => {
116
+ const ModeIcon = config.icon;
117
+ const isDisabled = config.mode === PermissionMode.BYPASS && !allowBypass;
118
+ const isActive = config.mode === currentMode;
119
+
120
+ return (
121
+ <button
122
+ key={config.mode}
123
+ onClick={(e) => {
124
+ e.stopPropagation();
125
+ handleModeSelect(config.mode);
126
+ }}
127
+ disabled={isDisabled}
128
+ className={`w-full flex items-start gap-3 p-3 rounded-lg text-left transition-all ${
129
+ isActive
130
+ ? `${config.bgColor} ${config.borderColor} border`
131
+ : 'hover:bg-muted'
132
+ } ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
133
+ >
134
+ <div className={`mt-0.5 ${config.color}`}>
135
+ <ModeIcon className="w-5 h-5" />
136
+ </div>
137
+ <div className="flex-1 min-w-0">
138
+ <div className="flex items-center gap-2">
139
+ <span className="font-medium text-sm">{config.label}</span>
140
+ {config.dangerous && (
141
+ <AlertTriangle className="w-3.5 h-3.5 text-red-500" />
142
+ )}
143
+ </div>
144
+ {showDescriptions && (
145
+ <p className="text-xs text-muted-foreground mt-0.5">
146
+ {config.description}
147
+ </p>
148
+ )}
149
+ </div>
150
+ {isActive && (
151
+ <div className={`w-2 h-2 rounded-full ${config.color.replace('text-', 'bg-')}`} />
152
+ )}
153
+ </button>
154
+ );
155
+ })}
156
+ </div>
157
+
158
+ {/* Footer hint */}
159
+ <div className="px-3 py-2 bg-muted/50 border-t border-border">
160
+ <p className="text-xs text-muted-foreground">
161
+ You can change permission mode anytime during a session
162
+ </p>
163
+ </div>
164
+ </div>
165
+ )}
166
+
167
+ {/* Bypass Warning Modal */}
168
+ {showBypassWarning && (
169
+ <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
170
+ <div className="bg-card border border-border rounded-lg p-6 w-[400px] max-w-[90vw]">
171
+ <div className="flex items-center gap-3 mb-4">
172
+ <div className="p-2 bg-red-500/10 rounded-lg">
173
+ <AlertTriangle className="w-6 h-6 text-red-500" />
174
+ </div>
175
+ <h3 className="text-lg font-semibold">Bypass Mode Disabled</h3>
176
+ </div>
177
+
178
+ <p className="text-sm text-muted-foreground mb-4">
179
+ Bypass permission mode is disabled for security reasons. This mode allows
180
+ Claude to run without any permission prompts, which can be dangerous.
181
+ </p>
182
+
183
+ <p className="text-sm mb-6">
184
+ To enable bypass mode, go to <strong>Settings → Security</strong> and
185
+ toggle &quot;Allow bypass permissions mode&quot;.
186
+ </p>
187
+
188
+ <div className="flex justify-end gap-2">
189
+ <button
190
+ onClick={() => setShowBypassWarning(false)}
191
+ className="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90"
192
+ >
193
+ Got it
194
+ </button>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ )}
199
+ </div>
200
+ );
201
+ };
202
+
203
+ export default PermissionSelector;
@@ -0,0 +1,325 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Search, Download, Star, Shield, Zap, Package, X, ExternalLink, Check } from 'lucide-react';
3
+
4
+ export interface Plugin {
5
+ id: string;
6
+ name: string;
7
+ description: string;
8
+ author: string;
9
+ version: string;
10
+ rating: number;
11
+ downloads: number;
12
+ tags: string[];
13
+ icon?: string;
14
+ installed?: boolean;
15
+ updateAvailable?: boolean;
16
+ }
17
+
18
+ interface PluginMarketplaceProps {
19
+ onInstall: (pluginId: string) => void;
20
+ onUninstall: (pluginId: string) => void;
21
+ installedPlugins: string[];
22
+ onClose: () => void;
23
+ }
24
+
25
+ const PLUGIN_CATEGORIES = [
26
+ { id: 'all', label: 'All' },
27
+ { id: 'productivity', label: 'Productivity' },
28
+ { id: 'ai', label: 'AI & ML' },
29
+ { id: 'integrations', label: 'Integrations' },
30
+ { id: 'tools', label: 'Dev Tools' },
31
+ { id: 'custom', label: 'Custom' },
32
+ ];
33
+
34
+ const SAMPLE_PLUGINS: Plugin[] = [
35
+ {
36
+ id: 'code-review',
37
+ name: 'Code Review Pro',
38
+ description: 'Advanced code review with pattern detection and best practices enforcement',
39
+ author: 'Codex Team',
40
+ version: '1.2.0',
41
+ rating: 4.8,
42
+ downloads: 12500,
43
+ tags: ['ai', 'productivity'],
44
+ installed: false,
45
+ },
46
+ {
47
+ id: 'test-generator',
48
+ name: 'Test Generator',
49
+ description: 'Automatically generate unit tests based on code changes and coverage gaps',
50
+ author: 'Codex Team',
51
+ version: '2.0.0',
52
+ rating: 4.6,
53
+ downloads: 8900,
54
+ tags: ['productivity', 'tools'],
55
+ installed: false,
56
+ },
57
+ {
58
+ id: 'github-integration',
59
+ name: 'GitHub Integration',
60
+ description: 'Enhanced GitHub workflow with PR templates, auto-merge, and issue tracking',
61
+ author: 'Community',
62
+ version: '1.5.0',
63
+ rating: 4.5,
64
+ downloads: 15000,
65
+ tags: ['integrations'],
66
+ installed: true,
67
+ },
68
+ {
69
+ id: 'slack-notifications',
70
+ name: 'Slack Notifications',
71
+ description: 'Get real-time notifications in Slack for agent activities and errors',
72
+ author: 'Community',
73
+ version: '1.0.0',
74
+ rating: 4.2,
75
+ downloads: 5200,
76
+ tags: ['integrations'],
77
+ installed: false,
78
+ },
79
+ {
80
+ id: 'context7-docs',
81
+ name: 'Context7 Docs',
82
+ description: 'Fetch always-up-to-date library documentation from Context7',
83
+ author: 'Community',
84
+ version: '1.1.0',
85
+ rating: 4.9,
86
+ downloads: 22000,
87
+ tags: ['ai', 'tools'],
88
+ installed: false,
89
+ },
90
+ {
91
+ id: 'brave-search',
92
+ name: 'Brave Search',
93
+ description: 'Web search capability using Brave Search API',
94
+ author: 'Anthropic',
95
+ version: '1.0.0',
96
+ rating: 4.7,
97
+ downloads: 18000,
98
+ tags: ['ai', 'integrations'],
99
+ installed: false,
100
+ },
101
+ {
102
+ id: 'database-mcp',
103
+ name: 'Database MCP',
104
+ description: 'Connect to PostgreSQL, MySQL, and other databases directly',
105
+ author: 'Community',
106
+ version: '2.1.0',
107
+ rating: 4.4,
108
+ downloads: 7500,
109
+ tags: ['tools', 'integrations'],
110
+ installed: false,
111
+ },
112
+ {
113
+ id: 'figma-integration',
114
+ name: 'Figma Integration',
115
+ description: 'Import designs from Figma and generate UI code automatically',
116
+ author: 'Community',
117
+ version: '0.9.0',
118
+ rating: 4.3,
119
+ downloads: 4100,
120
+ tags: ['integrations', 'ai'],
121
+ installed: false,
122
+ },
123
+ ];
124
+
125
+ function cn(...inputs: (string | undefined | null | boolean)[]): string {
126
+ return inputs.filter(Boolean).join(' ');
127
+ }
128
+
129
+ export const PluginMarketplace: React.FC<PluginMarketplaceProps> = ({
130
+ onInstall,
131
+ onUninstall,
132
+ installedPlugins,
133
+ onClose,
134
+ }) => {
135
+ const [searchQuery, setSearchQuery] = useState('');
136
+ const [selectedCategory, setSelectedCategory] = useState('all');
137
+ const [plugins, setPlugins] = useState<Plugin[]>(SAMPLE_PLUGINS);
138
+ const [installing, setInstalling] = useState<string | null>(null);
139
+
140
+ useEffect(() => {
141
+ setPlugins(SAMPLE_PLUGINS.map(p => ({
142
+ ...p,
143
+ installed: installedPlugins.includes(p.id),
144
+ })));
145
+ }, [installedPlugins]);
146
+
147
+ const filteredPlugins = plugins.filter(plugin => {
148
+ const matchesSearch = plugin.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
149
+ plugin.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
150
+ plugin.tags.some(t => t.includes(searchQuery.toLowerCase()));
151
+
152
+ const matchesCategory = selectedCategory === 'all' ||
153
+ plugin.tags.includes(selectedCategory);
154
+
155
+ return matchesSearch && matchesCategory;
156
+ });
157
+
158
+ const handleInstall = async (pluginId: string) => {
159
+ setInstalling(pluginId);
160
+ await onInstall(pluginId);
161
+ setInstalling(null);
162
+ };
163
+
164
+ const handleUninstall = async (pluginId: string) => {
165
+ setInstalling(pluginId);
166
+ await onUninstall(pluginId);
167
+ setInstalling(null);
168
+ };
169
+
170
+ const formatDownloads = (num: number) => {
171
+ if (num >= 1000) {
172
+ return `${(num / 1000).toFixed(1)}k`;
173
+ }
174
+ return num.toString();
175
+ };
176
+
177
+ return (
178
+ <div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
179
+ <div className="bg-background rounded-xl shadow-2xl w-full max-w-4xl max-h-[80vh] flex flex-col">
180
+ {/* Header */}
181
+ <div className="flex items-center justify-between px-6 py-4 border-b border-border">
182
+ <div className="flex items-center gap-3">
183
+ <div className="p-2 bg-primary/10 rounded-lg">
184
+ <Package className="w-5 h-5 text-primary" />
185
+ </div>
186
+ <div>
187
+ <h2 className="text-lg font-semibold">Plugin Marketplace</h2>
188
+ <p className="text-sm text-muted-foreground">Extend Codex Linux with plugins</p>
189
+ </div>
190
+ </div>
191
+ <button
192
+ onClick={onClose}
193
+ className="p-2 hover:bg-muted rounded-lg transition-colors"
194
+ >
195
+ <X className="w-5 h-5" />
196
+ </button>
197
+ </div>
198
+
199
+ {/* Search & Filters */}
200
+ <div className="px-6 py-4 border-b border-border">
201
+ <div className="flex items-center gap-4">
202
+ <div className="flex-1 relative">
203
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
204
+ <input
205
+ type="text"
206
+ placeholder="Search plugins..."
207
+ value={searchQuery}
208
+ onChange={(e) => setSearchQuery(e.target.value)}
209
+ className="w-full pl-10 pr-4 py-2 bg-muted border-0 rounded-lg text-sm"
210
+ />
211
+ </div>
212
+ </div>
213
+
214
+ <div className="flex items-center gap-2 mt-3 overflow-x-auto">
215
+ {PLUGIN_CATEGORIES.map((category) => (
216
+ <button
217
+ key={category.id}
218
+ onClick={() => setSelectedCategory(category.id)}
219
+ className={cn(
220
+ 'px-3 py-1.5 text-sm rounded-full whitespace-nowrap transition-colors',
221
+ selectedCategory === category.id
222
+ ? 'bg-primary text-primary-foreground'
223
+ : 'bg-muted hover:bg-muted/80'
224
+ )}
225
+ >
226
+ {category.label}
227
+ </button>
228
+ ))}
229
+ </div>
230
+ </div>
231
+
232
+ {/* Plugin List */}
233
+ <div className="flex-1 overflow-y-auto p-6">
234
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
235
+ {filteredPlugins.map((plugin) => (
236
+ <div
237
+ key={plugin.id}
238
+ className="p-4 border border-border rounded-lg hover:border-primary/50 transition-colors"
239
+ >
240
+ <div className="flex items-start justify-between">
241
+ <div className="flex-1">
242
+ <div className="flex items-center gap-2">
243
+ <h3 className="font-medium">{plugin.name}</h3>
244
+ {plugin.installed && (
245
+ <span className="px-1.5 py-0.5 text-xs bg-green-500/10 text-green-500 rounded">
246
+ <Check className="w-3 h-3 inline" /> Installed
247
+ </span>
248
+ )}
249
+ </div>
250
+ <p className="text-sm text-muted-foreground mt-1">{plugin.description}</p>
251
+ </div>
252
+ </div>
253
+
254
+ <div className="flex items-center gap-4 mt-3 text-xs text-muted-foreground">
255
+ <div className="flex items-center gap-1">
256
+ <Star className="w-3.5 h-3.5 text-yellow-500 fill-yellow-500" />
257
+ <span>{plugin.rating}</span>
258
+ </div>
259
+ <div className="flex items-center gap-1">
260
+ <Download className="w-3.5 h-3.5" />
261
+ <span>{formatDownloads(plugin.downloads)}</span>
262
+ </div>
263
+ <span>v{plugin.version}</span>
264
+ </div>
265
+
266
+ <div className="flex items-center justify-between mt-3 pt-3 border-t border-border">
267
+ <span className="text-xs text-muted-foreground">by {plugin.author}</span>
268
+
269
+ {plugin.installed ? (
270
+ <button
271
+ onClick={() => handleUninstall(plugin.id)}
272
+ disabled={installing === plugin.id}
273
+ className="px-3 py-1.5 text-sm text-red-500 hover:bg-red-500/10 rounded-md transition-colors disabled:opacity-50"
274
+ >
275
+ {installing === plugin.id ? 'Uninstalling...' : 'Uninstall'}
276
+ </button>
277
+ ) : (
278
+ <button
279
+ onClick={() => handleInstall(plugin.id)}
280
+ disabled={installing === plugin.id}
281
+ className="px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors disabled:opacity-50 flex items-center gap-1"
282
+ >
283
+ <Download className="w-3.5 h-3.5" />
284
+ {installing === plugin.id ? 'Installing...' : 'Install'}
285
+ </button>
286
+ )}
287
+ </div>
288
+ </div>
289
+ ))}
290
+ </div>
291
+
292
+ {filteredPlugins.length === 0 && (
293
+ <div className="text-center py-12 text-muted-foreground">
294
+ <Search className="w-12 h-12 mx-auto mb-4 opacity-30" />
295
+ <p>No plugins found matching your search</p>
296
+ </div>
297
+ )}
298
+ </div>
299
+
300
+ {/* Footer */}
301
+ <div className="px-6 py-3 border-t border-border flex items-center justify-between text-xs text-muted-foreground">
302
+ <div className="flex items-center gap-4">
303
+ <span className="flex items-center gap-1">
304
+ <Shield className="w-3.5 h-3.5" />
305
+ Verified plugins
306
+ </span>
307
+ <span className="flex items-center gap-1">
308
+ <Zap className="w-3.5 h-3.5" />
309
+ Fast installation
310
+ </span>
311
+ </div>
312
+ <a
313
+ href="#"
314
+ className="flex items-center gap-1 hover:text-primary transition-colors"
315
+ >
316
+ Browse more plugins
317
+ <ExternalLink className="w-3.5 h-3.5" />
318
+ </a>
319
+ </div>
320
+ </div>
321
+ </div>
322
+ );
323
+ };
324
+
325
+ export default PluginMarketplace;