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,1221 @@
1
+ import { app, BrowserWindow, ipcMain, dialog, shell, Notification, Tray, Menu, globalShortcut, nativeImage } from 'electron';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs/promises';
4
+ import { spawn, ChildProcess } from 'child_process';
5
+ import log from 'electron-log';
6
+ import Store from 'electron-store';
7
+ import { autoUpdater } from 'electron-updater';
8
+ import { AgentOrchestrator } from './agents/AgentOrchestrator';
9
+ import { GitWorktreeManager } from './git/GitWorktreeManager';
10
+ import { SkillsManager } from './skills/SkillsManager';
11
+ import { AutomationScheduler } from './automations/AutomationScheduler';
12
+ import { DatabaseManager } from './DatabaseManager';
13
+ import { SettingsManager } from './SettingsManager';
14
+ import { AIProviderManager } from './providers/AIProviderManager';
15
+ import { SecurityManager } from './security/SecurityManager';
16
+ import { AuditLogger } from './security/AuditLogger';
17
+ import { BackupManager } from './backup/BackupManager';
18
+ import { MigrationManager } from './backup/MigrationManager';
19
+ import { APIServer } from './api/APIServer';
20
+ import { PluginManager } from './plugins/PluginManager';
21
+ import { CoworkManager } from './cowork/CoworkManager';
22
+ import { GitHubPRMonitor } from './github/GitHubPRMonitor';
23
+ import { MCPManager } from './mcp/MCPManager';
24
+ import { AIPairProgramming } from './pair/AIPairProgramming';
25
+ import { ErrorTracker } from './monitoring/ErrorTracker';
26
+ import { metrics, startSystemMetrics } from './monitoring/MetricsCollector';
27
+ import { NotificationManager } from './notifications/NotificationManager';
28
+ import { SmartCodeAssistant } from './assistant/SmartCodeAssistant';
29
+ import { z } from 'zod';
30
+
31
+ // Validation schemas
32
+ const AgentConfigSchema = z.object({
33
+ name: z.string().min(1).max(100),
34
+ projectPath: z.string().min(1),
35
+ providerId: z.string(),
36
+ model: z.string(),
37
+ skills: z.array(z.string()).optional(),
38
+ systemPrompt: z.string().optional(),
39
+ }).strict();
40
+
41
+ const store = new Store();
42
+ let mainWindow: BrowserWindow | null = null;
43
+ let agentOrchestrator: AgentOrchestrator;
44
+ let gitWorktreeManager: GitWorktreeManager;
45
+ let skillsManager: SkillsManager;
46
+ let automationScheduler: AutomationScheduler;
47
+ let dbManager: DatabaseManager;
48
+ let settingsManager: SettingsManager;
49
+ let aiProviderManager: AIProviderManager;
50
+ let securityManager: SecurityManager;
51
+ let auditLogger: AuditLogger;
52
+ let backupManager: BackupManager;
53
+ let migrationManager: MigrationManager;
54
+ let apiServer: APIServer;
55
+ let pluginManager: PluginManager;
56
+ let coworkManager: CoworkManager;
57
+ let githubPRMonitor: GitHubPRMonitor;
58
+ let mcpManager: MCPManager;
59
+ let aiPairProgramming: AIPairProgramming;
60
+ let errorTracker: ErrorTracker;
61
+ let notificationManager: NotificationManager;
62
+ let smartCodeAssistant: SmartCodeAssistant;
63
+
64
+ log.info('Starting Codex Linux...');
65
+
66
+ function createWindow(): void {
67
+ mainWindow = new BrowserWindow({
68
+ width: 1600,
69
+ height: 1000,
70
+ minWidth: 1200,
71
+ minHeight: 800,
72
+ titleBarStyle: 'hiddenInset',
73
+ webPreferences: {
74
+ nodeIntegration: false,
75
+ contextIsolation: true,
76
+ preload: path.join(__dirname, 'preload.js'),
77
+ sandbox: false
78
+ },
79
+ show: false,
80
+ icon: path.join(__dirname, '../../assets/icon.png')
81
+ });
82
+
83
+ if (process.env.VITE_DEV_SERVER_URL) {
84
+ mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
85
+ mainWindow.webContents.openDevTools();
86
+ } else {
87
+ mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
88
+ }
89
+
90
+ mainWindow.once('ready-to-show', () => {
91
+ mainWindow?.show();
92
+ });
93
+
94
+ mainWindow.on('closed', () => {
95
+ mainWindow = null;
96
+ });
97
+ }
98
+
99
+ let tray: Tray | null = null;
100
+
101
+ function createTray(): void {
102
+ const iconPath = path.join(__dirname, '../../assets/icon.png');
103
+
104
+ try {
105
+ const icon = nativeImage.createFromPath(iconPath);
106
+ tray = new Tray(icon.isEmpty() ? nativeImage.createEmpty() : icon);
107
+
108
+ const contextMenu = Menu.buildFromTemplate([
109
+ {
110
+ label: 'Show Codex',
111
+ click: () => {
112
+ if (mainWindow) {
113
+ mainWindow.show();
114
+ mainWindow.focus();
115
+ }
116
+ }
117
+ },
118
+ { type: 'separator' },
119
+ {
120
+ label: 'New Agent',
121
+ click: () => {
122
+ if (mainWindow) {
123
+ mainWindow.show();
124
+ mainWindow.webContents.send('create-new-agent');
125
+ }
126
+ }
127
+ },
128
+ {
129
+ label: 'Open Settings',
130
+ click: () => {
131
+ if (mainWindow) {
132
+ mainWindow.show();
133
+ mainWindow.webContents.send('open-settings');
134
+ }
135
+ }
136
+ },
137
+ { type: 'separator' },
138
+ {
139
+ label: 'Quit',
140
+ click: () => {
141
+ app.quit();
142
+ }
143
+ }
144
+ ]);
145
+
146
+ tray.setToolTip('Codex Linux');
147
+ tray.setContextMenu(contextMenu);
148
+
149
+ tray.on('click', () => {
150
+ if (mainWindow) {
151
+ if (mainWindow.isVisible()) {
152
+ mainWindow.hide();
153
+ } else {
154
+ mainWindow.show();
155
+ mainWindow.focus();
156
+ }
157
+ }
158
+ });
159
+
160
+ log.info('System tray initialized');
161
+ } catch (error) {
162
+ log.warn('Failed to create system tray:', error);
163
+ }
164
+ }
165
+
166
+ function registerGlobalShortcuts(): void {
167
+ try {
168
+ globalShortcut.register('CommandOrControl+Shift+C', () => {
169
+ if (mainWindow) {
170
+ if (mainWindow.isVisible()) {
171
+ mainWindow.hide();
172
+ } else {
173
+ mainWindow.show();
174
+ mainWindow.focus();
175
+ }
176
+ }
177
+ });
178
+
179
+ globalShortcut.register('CommandOrControl+Shift+N', () => {
180
+ if (mainWindow) {
181
+ mainWindow.show();
182
+ mainWindow.webContents.send('create-new-agent');
183
+ }
184
+ });
185
+
186
+ globalShortcut.register('CommandOrControl+Shift+K', () => {
187
+ if (mainWindow) {
188
+ mainWindow.show();
189
+ mainWindow.webContents.send('open-search');
190
+ }
191
+ });
192
+
193
+ log.info('Global shortcuts registered');
194
+ } catch (error) {
195
+ log.warn('Failed to register global shortcuts:', error);
196
+ }
197
+ }
198
+
199
+ async function initializeServices(): Promise<void> {
200
+ try {
201
+ // Initialize security first
202
+ securityManager = new SecurityManager();
203
+ await securityManager.initialize();
204
+ log.info('Security manager initialized');
205
+
206
+ // Initialize database
207
+ dbManager = new DatabaseManager();
208
+ await dbManager.initialize();
209
+ log.info('Database initialized');
210
+
211
+ // Run migrations
212
+ migrationManager = new MigrationManager(dbManager);
213
+ await migrationManager.initialize();
214
+ log.info('Migrations completed');
215
+
216
+ // Initialize settings
217
+ settingsManager = new SettingsManager(store);
218
+ log.info('Settings manager initialized');
219
+
220
+ // Initialize AI provider manager
221
+ aiProviderManager = new AIProviderManager(settingsManager);
222
+ log.info('AI provider manager initialized');
223
+
224
+ // Initialize notification manager
225
+ notificationManager = new NotificationManager();
226
+ log.info('Notification manager initialized');
227
+
228
+ // Initialize Git worktree manager
229
+ gitWorktreeManager = new GitWorktreeManager();
230
+ log.info('Git worktree manager initialized');
231
+
232
+ // Initialize skills manager
233
+ skillsManager = new SkillsManager();
234
+ await skillsManager.initialize();
235
+ log.info('Skills manager initialized');
236
+
237
+ // Initialize automation scheduler
238
+ automationScheduler = new AutomationScheduler();
239
+ automationScheduler.setNotificationManager(notificationManager);
240
+ await automationScheduler.initialize();
241
+ log.info('Automation scheduler initialized');
242
+
243
+ // Initialize agent orchestrator
244
+ agentOrchestrator = new AgentOrchestrator(
245
+ aiProviderManager,
246
+ gitWorktreeManager,
247
+ skillsManager,
248
+ dbManager
249
+ );
250
+ await agentOrchestrator.initialize();
251
+ log.info('Agent orchestrator initialized');
252
+
253
+ agentOrchestrator.on('changes:created', (payload: { agentId: string; changeId: string }) => {
254
+ if (mainWindow) {
255
+ mainWindow.webContents.send('changes:created', payload);
256
+ }
257
+ });
258
+
259
+ agentOrchestrator.on('agent:taskCompleted', (payload: any) => {
260
+ if (mainWindow) {
261
+ mainWindow.webContents.send('agent:taskCompleted', payload);
262
+ }
263
+ });
264
+
265
+ agentOrchestrator.on('agent:taskStarted', (payload: any) => {
266
+ if (mainWindow) {
267
+ mainWindow.webContents.send('agent:taskStarted', payload);
268
+ }
269
+ });
270
+
271
+ agentOrchestrator.on('agent:taskFailed', (payload: any) => {
272
+ if (mainWindow) {
273
+ mainWindow.webContents.send('agent:taskFailed', payload);
274
+ }
275
+ });
276
+
277
+ agentOrchestrator.on('agent:paused', (payload: any) => {
278
+ if (mainWindow) {
279
+ mainWindow.webContents.send('agent:paused', payload);
280
+ }
281
+ });
282
+
283
+ agentOrchestrator.on('agent:resumed', (payload: any) => {
284
+ if (mainWindow) {
285
+ mainWindow.webContents.send('agent:resumed', payload);
286
+ }
287
+ });
288
+
289
+ agentOrchestrator.on('agent:stopped', (payload: any) => {
290
+ if (mainWindow) {
291
+ mainWindow.webContents.send('agent:stopped', payload);
292
+ }
293
+ });
294
+
295
+ // Initialize backup manager
296
+ backupManager = new BackupManager();
297
+ await backupManager.initialize();
298
+ log.info('Backup manager initialized');
299
+
300
+ // Initialize plugin manager
301
+ pluginManager = new PluginManager();
302
+ await pluginManager.initialize();
303
+ log.info('Plugin manager initialized');
304
+
305
+ // Initialize cowork manager
306
+ coworkManager = new CoworkManager(
307
+ agentOrchestrator,
308
+ dbManager,
309
+ notificationManager
310
+ );
311
+ await coworkManager.initialize();
312
+ log.info('Cowork manager initialized');
313
+
314
+ // Initialize AI pair programming
315
+ aiPairProgramming = new AIPairProgramming(
316
+ agentOrchestrator,
317
+ aiProviderManager
318
+ );
319
+ log.info('AI pair programming initialized');
320
+
321
+ // Initialize smart code assistant
322
+ smartCodeAssistant = new SmartCodeAssistant(aiProviderManager);
323
+ log.info('Smart code assistant initialized');
324
+
325
+ // Initialize MCP manager
326
+ mcpManager = new MCPManager();
327
+ await mcpManager.initialize();
328
+ log.info('MCP manager initialized');
329
+
330
+ // Initialize audit logger
331
+ auditLogger = new AuditLogger();
332
+ await auditLogger.initialize();
333
+ log.info('Audit logger initialized');
334
+
335
+ const sentryDsn = settingsManager.get('sentryDsn');
336
+ if (sentryDsn) {
337
+ errorTracker = new ErrorTracker();
338
+ errorTracker.initialize(sentryDsn);
339
+ log.info('Error tracker initialized');
340
+ }
341
+
342
+ // Start system metrics
343
+ startSystemMetrics();
344
+ log.info('System metrics started');
345
+
346
+ // Initialize API server
347
+ apiServer = new APIServer(
348
+ agentOrchestrator,
349
+ securityManager,
350
+ auditLogger
351
+ );
352
+ await apiServer.start();
353
+ log.info('API server started on port 3001');
354
+
355
+ // Initialize GitHub PR Monitor if token available
356
+ const githubToken = settingsManager.get('githubToken');
357
+ if (githubToken) {
358
+ githubPRMonitor = new GitHubPRMonitor(
359
+ githubToken,
360
+ agentOrchestrator,
361
+ gitWorktreeManager,
362
+ notificationManager
363
+ );
364
+ await githubPRMonitor.initialize();
365
+ log.info('GitHub PR monitor initialized');
366
+ }
367
+
368
+ } catch (error) {
369
+ log.error('Failed to initialize services:', error);
370
+ throw error;
371
+ }
372
+ }
373
+
374
+ // App event handlers
375
+ app.whenReady().then(async () => {
376
+ try {
377
+ await initializeServices();
378
+ createWindow();
379
+ createTray();
380
+ registerGlobalShortcuts();
381
+ setupIPC();
382
+ setupAutoUpdater();
383
+ setupAutoUpdaterIPC();
384
+
385
+ app.on('activate', () => {
386
+ if (BrowserWindow.getAllWindows().length === 0) {
387
+ createWindow();
388
+ }
389
+ });
390
+ } catch (error) {
391
+ log.error('Failed to start application:', error);
392
+ dialog.showErrorBox(
393
+ 'Startup Error',
394
+ 'Failed to initialize Codex Linux. Please check the logs.'
395
+ );
396
+ app.quit();
397
+ }
398
+ });
399
+
400
+ app.on('window-all-closed', () => {
401
+ if (process.platform !== 'darwin') {
402
+ app.quit();
403
+ }
404
+ });
405
+
406
+ app.on('before-quit', async () => {
407
+ await cleanup();
408
+ });
409
+
410
+ function setupAutoUpdater(): void {
411
+ if (app.isPackaged) {
412
+ autoUpdater.logger = log;
413
+ autoUpdater.autoDownload = true;
414
+ autoUpdater.autoInstallOnAppQuit = true;
415
+
416
+ autoUpdater.on('checking-for-update', () => {
417
+ log.info('Checking for updates...');
418
+ });
419
+
420
+ autoUpdater.on('update-available', (info) => {
421
+ log.info('Update available:', info.version);
422
+ if (mainWindow) {
423
+ mainWindow.webContents.send('update-available', info);
424
+ }
425
+ });
426
+
427
+ autoUpdater.on('update-not-available', () => {
428
+ log.info('No updates available');
429
+ });
430
+
431
+ autoUpdater.on('download-progress', (progress) => {
432
+ log.info(`Download progress: ${progress.percent}%`);
433
+ if (mainWindow) {
434
+ mainWindow.webContents.send('update-progress', progress);
435
+ }
436
+ });
437
+
438
+ autoUpdater.on('update-downloaded', (info) => {
439
+ log.info('Update downloaded:', info.version);
440
+ if (mainWindow) {
441
+ mainWindow.webContents.send('update-downloaded', info);
442
+ }
443
+
444
+ if (Notification.isSupported()) {
445
+ new Notification({
446
+ title: 'Update Ready',
447
+ body: `Codex Linux ${info.version} is ready to install. Restart to update.`
448
+ }).show();
449
+ }
450
+ });
451
+
452
+ autoUpdater.on('error', (error) => {
453
+ log.error('Auto-updater error:', error);
454
+ });
455
+
456
+ autoUpdater.checkForUpdatesAndNotify().catch(err => {
457
+ log.warn('Failed to check for updates:', err);
458
+ });
459
+ }
460
+ }
461
+
462
+ function setupAutoUpdaterIPC(): void {
463
+ ipcMain.handle('update:check', async () => {
464
+ if (!app.isPackaged) {
465
+ return { available: false, message: 'Updates only work in packaged app' };
466
+ }
467
+ try {
468
+ const result = await autoUpdater.checkForUpdates();
469
+ return { available: !!result?.updateInfo, version: result?.updateInfo?.version };
470
+ } catch (error) {
471
+ log.error('Update check failed:', error);
472
+ return { available: false, message: 'Update check failed' };
473
+ }
474
+ });
475
+
476
+ ipcMain.handle('update:download', async () => {
477
+ if (!app.isPackaged) {
478
+ return { success: false, message: 'Updates only work in packaged app' };
479
+ }
480
+ try {
481
+ await autoUpdater.downloadUpdate();
482
+ return { success: true };
483
+ } catch (error) {
484
+ log.error('Update download failed:', error);
485
+ return { success: false, message: 'Update download failed' };
486
+ }
487
+ });
488
+
489
+ ipcMain.handle('update:install', () => {
490
+ autoUpdater.quitAndInstall(false, true);
491
+ });
492
+ }
493
+
494
+ async function cleanup(): Promise<void> {
495
+ log.info('Starting cleanup...');
496
+
497
+ try {
498
+ globalShortcut.unregisterAll();
499
+ tray?.destroy();
500
+ tray = null;
501
+
502
+ if (agentOrchestrator) {
503
+ agentOrchestrator.removeAllListeners('changes:created');
504
+ agentOrchestrator.removeAllListeners('agent:taskCompleted');
505
+ agentOrchestrator.removeAllListeners('agent:taskStarted');
506
+ agentOrchestrator.removeAllListeners('agent:taskFailed');
507
+ agentOrchestrator.removeAllListeners('agent:paused');
508
+ agentOrchestrator.removeAllListeners('agent:resumed');
509
+ agentOrchestrator.removeAllListeners('agent:stopped');
510
+ }
511
+
512
+ await Promise.all([
513
+ agentOrchestrator?.cleanup(),
514
+ automationScheduler?.cleanup(),
515
+ coworkManager?.cleanup(),
516
+ apiServer?.stop(),
517
+ pluginManager?.cleanup(),
518
+ mcpManager?.cleanup(),
519
+ githubPRMonitor?.cleanup(),
520
+ backupManager?.cleanup?.(),
521
+ auditLogger?.cleanup?.(),
522
+ dbManager?.close()
523
+ ]);
524
+
525
+ log.info('Cleanup completed');
526
+ } catch (error) {
527
+ log.error('Error during cleanup:', error);
528
+ }
529
+ }
530
+
531
+ function setupIPC(): void {
532
+ // Window controls
533
+ ipcMain.handle('window:minimize', () => {
534
+ mainWindow?.minimize();
535
+ });
536
+
537
+ ipcMain.handle('window:maximize', () => {
538
+ if (mainWindow?.isMaximized()) {
539
+ mainWindow.unmaximize();
540
+ } else {
541
+ mainWindow?.maximize();
542
+ }
543
+ });
544
+
545
+ ipcMain.handle('window:close', () => {
546
+ mainWindow?.close();
547
+ });
548
+
549
+ // File system operations
550
+ ipcMain.handle('dialog:selectFolder', async () => {
551
+ if (!mainWindow) {
552
+ throw new Error('No main window available');
553
+ }
554
+ const result = await dialog.showOpenDialog(mainWindow, {
555
+ properties: ['openDirectory']
556
+ });
557
+ return result.filePaths[0] || null;
558
+ });
559
+
560
+ ipcMain.handle('dialog:selectFile', async (event, filters) => {
561
+ if (!mainWindow) {
562
+ throw new Error('No main window available');
563
+ }
564
+ const result = await dialog.showOpenDialog(mainWindow, {
565
+ properties: ['openFile'],
566
+ filters
567
+ });
568
+ return result.filePaths[0] || null;
569
+ });
570
+
571
+ ipcMain.handle('shell:openExternal', (event, url: string) => {
572
+ shell.openExternal(url);
573
+ });
574
+
575
+ ipcMain.handle('shell:openPath', (event, path: string) => {
576
+ shell.openPath(path);
577
+ });
578
+
579
+ // Agent operations with validation
580
+ ipcMain.handle('agent:create', async (event, config) => {
581
+ try {
582
+ const validatedConfig = AgentConfigSchema.parse(config);
583
+ const result = await agentOrchestrator.createAgent(validatedConfig as any);
584
+ await auditLogger.log('agent_created', { agentId: result.id });
585
+ return result;
586
+ } catch (error) {
587
+ log.error('Failed to create agent:', error);
588
+ throw error;
589
+ }
590
+ });
591
+
592
+ ipcMain.handle('agent:list', async () => {
593
+ return await agentOrchestrator.listAgents();
594
+ });
595
+
596
+ ipcMain.handle('agent:get', async (event, agentId: string) => {
597
+ return await agentOrchestrator.getAgent(agentId);
598
+ });
599
+
600
+ ipcMain.handle('agent:sendMessage', async (event, agentId: string, message: string) => {
601
+ try {
602
+ return await agentOrchestrator.sendMessage(agentId, message);
603
+ } catch (error) {
604
+ log.error('Failed to send message:', error);
605
+ throw error;
606
+ }
607
+ });
608
+
609
+ ipcMain.handle('agent:sendMessageStream', async (event, agentId: string, message: string) => {
610
+ try {
611
+ const stream = await agentOrchestrator.sendMessageStream(agentId, message, {
612
+ onChunk: (chunk: string) => {
613
+ event.sender.send('agent:streamChunk', { agentId, chunk });
614
+ },
615
+ onComplete: () => {
616
+ event.sender.send('agent:streamEnd', { agentId });
617
+ },
618
+ onError: (error: Error) => {
619
+ event.sender.send('agent:streamError', { agentId, error: error.message });
620
+ }
621
+ });
622
+
623
+ return { success: true };
624
+ } catch (error) {
625
+ log.error('Failed to start stream:', error);
626
+ throw error;
627
+ }
628
+ });
629
+
630
+ ipcMain.handle('agent:executeTask', async (event, agentId: string, task: string) => {
631
+ return await agentOrchestrator.executeTask(agentId, task);
632
+ });
633
+
634
+ ipcMain.handle('agent:pause', async (event, agentId: string) => {
635
+ return await agentOrchestrator.pauseAgent(agentId);
636
+ });
637
+
638
+ ipcMain.handle('agent:resume', async (event, agentId: string) => {
639
+ return await agentOrchestrator.resumeAgent(agentId);
640
+ });
641
+
642
+ ipcMain.handle('agent:stop', async (event, agentId: string) => {
643
+ return await agentOrchestrator.stopAgent(agentId);
644
+ });
645
+
646
+ ipcMain.handle('agent:delete', async (event, agentId: string) => {
647
+ try {
648
+ await agentOrchestrator.deleteAgent(agentId);
649
+ await auditLogger.log('agent_deleted', { agentId });
650
+ return { success: true };
651
+ } catch (error) {
652
+ log.error('Failed to delete agent:', error);
653
+ throw error;
654
+ }
655
+ });
656
+
657
+ // Worktree operations
658
+ ipcMain.handle('worktree:create', async (event, repoPath: string, name: string) => {
659
+ return await gitWorktreeManager.createWorktree(repoPath, name);
660
+ });
661
+
662
+ ipcMain.handle('worktree:list', async (event, repoPath: string) => {
663
+ return await gitWorktreeManager.listWorktrees(repoPath);
664
+ });
665
+
666
+ ipcMain.handle('worktree:remove', async (event, repoPath: string, name: string) => {
667
+ return await gitWorktreeManager.removeWorktree(repoPath, name);
668
+ });
669
+
670
+ // Skills operations
671
+ ipcMain.handle('skills:list', async () => {
672
+ return await skillsManager.listSkills();
673
+ });
674
+
675
+ ipcMain.handle('skills:get', async (event, skillId: string) => {
676
+ return await skillsManager.getSkill(skillId);
677
+ });
678
+
679
+ ipcMain.handle('skills:create', async (event, skillConfig) => {
680
+ return await skillsManager.createSkill(skillConfig);
681
+ });
682
+
683
+ ipcMain.handle('skills:update', async (event, skillId: string, skillConfig) => {
684
+ return await skillsManager.updateSkill(skillId, skillConfig);
685
+ });
686
+
687
+ ipcMain.handle('skills:delete', async (event, skillId: string) => {
688
+ return await skillsManager.deleteSkill(skillId);
689
+ });
690
+
691
+ ipcMain.handle('skills:applyToAgent', async (event, agentId: string, skillIds: string[]) => {
692
+ return await agentOrchestrator.applySkills(agentId, skillIds);
693
+ });
694
+
695
+ // Automation operations
696
+ ipcMain.handle('automation:list', async () => {
697
+ return await automationScheduler.listAutomations();
698
+ });
699
+
700
+ ipcMain.handle('automation:create', async (event, config) => {
701
+ return await automationScheduler.createAutomation(config);
702
+ });
703
+
704
+ ipcMain.handle('automation:update', async (event, automationId: string, config) => {
705
+ return await automationScheduler.updateAutomation(automationId, config);
706
+ });
707
+
708
+ ipcMain.handle('automation:delete', async (event, automationId: string) => {
709
+ return await automationScheduler.deleteAutomation(automationId);
710
+ });
711
+
712
+ ipcMain.handle('automation:toggle', async (event, automationId: string, enabled: boolean) => {
713
+ return await automationScheduler.toggleAutomation(automationId, enabled);
714
+ });
715
+
716
+ // Settings operations
717
+ ipcMain.handle('settings:get', (event, key: string) => {
718
+ return settingsManager.getAny(key);
719
+ });
720
+
721
+ ipcMain.handle('settings:set', (event, key: string, value: any) => {
722
+ settingsManager.setAny(key, value);
723
+ });
724
+
725
+ ipcMain.handle('settings:getAll', () => {
726
+ return settingsManager.getAll();
727
+ });
728
+
729
+ // AI Provider operations
730
+ ipcMain.handle('providers:list', () => {
731
+ return aiProviderManager.listProviders();
732
+ });
733
+
734
+ ipcMain.handle('providers:getActive', () => {
735
+ return aiProviderManager.getActiveProvider();
736
+ });
737
+
738
+ ipcMain.handle('providers:setActive', (event, providerId: string) => {
739
+ return aiProviderManager.setActiveProvider(providerId);
740
+ });
741
+
742
+ ipcMain.handle('providers:configure', (event, providerId: string, config: any) => {
743
+ return aiProviderManager.configureProvider(providerId, config);
744
+ });
745
+
746
+ ipcMain.handle('providers:test', async (event, providerId: string) => {
747
+ return await aiProviderManager.testProvider(providerId);
748
+ });
749
+
750
+ // File system operations
751
+ ipcMain.handle('fs:readdir', async (event, dirPath: string, options?: { withFileTypes?: boolean }) => {
752
+ try {
753
+ const normalizedPath = path.normalize(dirPath);
754
+ if (normalizedPath.includes('..')) {
755
+ throw new Error('Path traversal not allowed');
756
+ }
757
+ const entries = await fs.readdir(normalizedPath, { withFileTypes: true });
758
+ return entries.map((entry: any) => ({
759
+ name: entry.name,
760
+ isDirectory: entry.isDirectory(),
761
+ isFile: entry.isFile()
762
+ }));
763
+ } catch (error) {
764
+ log.error('Failed to read directory:', error);
765
+ throw error;
766
+ }
767
+ });
768
+
769
+ ipcMain.handle('fs:readFile', async (event, filePath: string, encoding?: BufferEncoding) => {
770
+ try {
771
+ const normalizedPath = path.normalize(filePath);
772
+ if (normalizedPath.includes('..')) {
773
+ throw new Error('Path traversal not allowed');
774
+ }
775
+ const content = await fs.readFile(normalizedPath, encoding || 'utf-8');
776
+ return content;
777
+ } catch (error) {
778
+ log.error('Failed to read file:', error);
779
+ throw error;
780
+ }
781
+ });
782
+
783
+ ipcMain.handle('fs:writeFile', async (event, filePath: string, content: string) => {
784
+ if (!filePath || typeof filePath !== 'string') {
785
+ throw new Error('File path is required');
786
+ }
787
+ const normalizedPath = path.normalize(filePath);
788
+ if (normalizedPath.includes('..') || normalizedPath.startsWith('/etc') || normalizedPath.startsWith('/root') || normalizedPath.startsWith('/sys') || normalizedPath.startsWith('/proc')) {
789
+ throw new Error('Path traversal or restricted path not allowed');
790
+ }
791
+ try {
792
+ await fs.writeFile(normalizedPath, content, 'utf-8');
793
+ } catch (error) {
794
+ log.error('Failed to write file:', error);
795
+ throw error;
796
+ }
797
+ });
798
+
799
+ ipcMain.handle('fs:stat', async (event, filePath: string) => {
800
+ try {
801
+ const normalizedPath = path.normalize(filePath);
802
+ if (normalizedPath.includes('..')) {
803
+ throw new Error('Path traversal not allowed');
804
+ }
805
+ const stats = await fs.stat(normalizedPath);
806
+ return {
807
+ isFile: stats.isFile(),
808
+ isDirectory: stats.isDirectory(),
809
+ size: stats.size,
810
+ mtime: stats.mtime,
811
+ ctime: stats.ctime
812
+ };
813
+ } catch (error) {
814
+ log.error('Failed to stat file:', error);
815
+ throw error;
816
+ }
817
+ });
818
+
819
+ // Terminal operations
820
+ const ALLOWED_COMMANDS = new Set([
821
+ 'npm', 'node', 'pnpm', 'yarn', 'bun', 'deno',
822
+ 'git', 'docker', 'docker-compose', 'kubectl',
823
+ 'python', 'python3', 'pip', 'pip3',
824
+ 'make', 'cmake', 'gcc', 'g++', 'clang', 'rustc',
825
+ 'cargo', 'go', 'java', 'javac', 'gradle', 'maven',
826
+ 'ls', 'cat', 'grep', 'find', 'chmod', 'chown', 'mkdir', 'rm', 'rmdir', 'cp', 'mv', 'touch',
827
+ 'code', 'codex', 'opencode'
828
+ ]);
829
+ const terminalProcesses = new Map<number, ChildProcess>();
830
+ let terminalIdCounter = 0;
831
+
832
+ function parseCommandLine(command: string): string[] {
833
+ const args: string[] = [];
834
+ let current = '';
835
+ let inQuote = false;
836
+ let quoteChar = '';
837
+
838
+ for (let i = 0; i < command.length; i++) {
839
+ const char = command[i];
840
+ if ((char === '"' || char === "'") && !inQuote) {
841
+ inQuote = true;
842
+ quoteChar = char;
843
+ } else if (char === quoteChar && inQuote) {
844
+ inQuote = false;
845
+ quoteChar = '';
846
+ } else if (char === ' ' && !inQuote) {
847
+ if (current) {
848
+ args.push(current);
849
+ current = '';
850
+ }
851
+ } else {
852
+ current += char;
853
+ }
854
+ }
855
+ if (current) args.push(current);
856
+ return args;
857
+ }
858
+
859
+ ipcMain.handle('terminal:execute', async (event, { command, cwd }: { command: string; cwd: string }) => {
860
+ if (!command || typeof command !== 'string') {
861
+ throw new Error('Command is required');
862
+ }
863
+ if (!cwd || typeof cwd !== 'string') {
864
+ throw new Error('CWD is required');
865
+ }
866
+
867
+ const parsedArgs = parseCommandLine(command);
868
+ if (parsedArgs.length === 0) {
869
+ throw new Error('Command is required');
870
+ }
871
+
872
+ const cmd = parsedArgs[0];
873
+ const args = parsedArgs.slice(1);
874
+
875
+ if (!ALLOWED_COMMANDS.has(cmd)) {
876
+ throw new Error(`Command "${cmd}" is not allowed. Allowed commands: ${[...ALLOWED_COMMANDS].join(', ')}`);
877
+ }
878
+
879
+ const currentTerminalId = ++terminalIdCounter;
880
+
881
+ return new Promise((resolve) => {
882
+ const proc = spawn(cmd, args, {
883
+ cwd,
884
+ shell: false,
885
+ env: { ...process.env, FORCE_COLOR: '1' }
886
+ });
887
+
888
+ terminalProcesses.set(currentTerminalId, proc);
889
+
890
+ let stdout = '';
891
+ let stderr = '';
892
+
893
+ proc.stdout?.on('data', (data) => {
894
+ stdout += data.toString();
895
+ });
896
+
897
+ proc.stderr?.on('data', (data) => {
898
+ stderr += data.toString();
899
+ });
900
+
901
+ const cleanup = () => {
902
+ terminalProcesses.delete(currentTerminalId);
903
+ };
904
+
905
+ proc.on('close', (code) => {
906
+ cleanup();
907
+ resolve({
908
+ stdout,
909
+ stderr,
910
+ exitCode: code,
911
+ error: code !== 0 ? `Process exited with code ${code}` : null
912
+ });
913
+ });
914
+
915
+ proc.on('error', (error) => {
916
+ cleanup();
917
+ resolve({
918
+ stdout,
919
+ stderr,
920
+ exitCode: -1,
921
+ error: error.message
922
+ });
923
+ });
924
+ });
925
+ });
926
+
927
+ ipcMain.handle('terminal:kill', () => {
928
+ for (const [id, proc] of terminalProcesses) {
929
+ proc.kill();
930
+ terminalProcesses.delete(id);
931
+ }
932
+ });
933
+
934
+ // Code changes operations
935
+ ipcMain.handle('changes:list', async (event, agentId?: string) => {
936
+ return await dbManager.getCodeChanges(agentId);
937
+ });
938
+
939
+ ipcMain.handle('changes:approve', async (event, changeId: string) => {
940
+ return await dbManager.approveCodeChange(changeId);
941
+ });
942
+
943
+ ipcMain.handle('changes:reject', async (event, changeId: string, comment?: string) => {
944
+ return await dbManager.rejectCodeChange(changeId, comment);
945
+ });
946
+
947
+ ipcMain.handle('changes:apply', async (event, changeId: string) => {
948
+ return await dbManager.applyCodeChange(changeId);
949
+ });
950
+
951
+ // Checkpoints operations
952
+ ipcMain.handle('checkpoints:list', async (event, agentId?: string) => {
953
+ return await dbManager.listCheckpoints(agentId);
954
+ });
955
+
956
+ ipcMain.handle('checkpoints:restore', async (event, checkpointId: string) => {
957
+ return await dbManager.restoreCheckpoint(checkpointId);
958
+ });
959
+
960
+ ipcMain.handle('checkpoints:restoreLast', async (event, agentId: string) => {
961
+ return await dbManager.restoreLastCheckpoint(agentId);
962
+ });
963
+
964
+ // Agent queue operations
965
+ ipcMain.handle('queue:list', async (event, agentId: string) => {
966
+ return await dbManager.listAgentQueueItems(agentId);
967
+ });
968
+
969
+ ipcMain.handle('queue:enqueue', async (event, agentId: string, type: 'message' | 'task', content: string) => {
970
+ return await dbManager.enqueueAgentQueueItem(agentId, type, content);
971
+ });
972
+
973
+ ipcMain.handle('queue:delete', async (event, agentId: string, itemId: string) => {
974
+ return await dbManager.deleteAgentQueueItem(agentId, itemId);
975
+ });
976
+
977
+ ipcMain.handle('queue:moveUp', async (event, agentId: string, itemId: string) => {
978
+ return await dbManager.moveAgentQueueItemUp(agentId, itemId);
979
+ });
980
+
981
+ ipcMain.handle('queue:claimNext', async (event, agentId: string) => {
982
+ return await dbManager.claimNextAgentQueueItem(agentId);
983
+ });
984
+
985
+ ipcMain.handle('queue:complete', async (event, agentId: string, itemId: string, outcome: 'completed' | 'failed', error?: string) => {
986
+ return await dbManager.completeAgentQueueItem(agentId, itemId, outcome, error);
987
+ });
988
+
989
+ ipcMain.handle('queue:history', async (event, agentId: string, limit?: number) => {
990
+ return await dbManager.getQueueHistory(agentId, limit);
991
+ });
992
+
993
+ // Git operations
994
+ ipcMain.handle('git:status', async (event, repoPath: string) => {
995
+ return await gitWorktreeManager.getChanges(repoPath);
996
+ });
997
+
998
+ ipcMain.handle('git:commit', async (event, { repoPath, message, files }: { repoPath: string; message: string; files?: string[] }) => {
999
+ return await gitWorktreeManager.commitChanges(repoPath, message, files);
1000
+ });
1001
+
1002
+ ipcMain.handle('git:diff', async (event, { repoPath, filePath }: { repoPath: string; filePath?: string }) => {
1003
+ return await gitWorktreeManager.getDiff(repoPath, filePath);
1004
+ });
1005
+
1006
+ // Search operations
1007
+ ipcMain.handle('search:files', async (event, { query, path, pattern }: { query: string; path: string; pattern?: string }) => {
1008
+ try {
1009
+ const results: Array<{ path: string; matches: Array<{ line: number; content: string }> }> = [];
1010
+
1011
+ async function searchDir(dirPath: string) {
1012
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
1013
+
1014
+ for (const entry of entries) {
1015
+ const fullPath = `${dirPath}/${entry.name}`;
1016
+
1017
+ if (entry.isDirectory()) {
1018
+ if (!entry.name.startsWith('.') &&
1019
+ entry.name !== 'node_modules' &&
1020
+ entry.name !== 'dist' &&
1021
+ entry.name !== 'build') {
1022
+ await searchDir(fullPath);
1023
+ }
1024
+ } else if (entry.isFile()) {
1025
+ if (pattern && !entry.name.match(pattern)) continue;
1026
+
1027
+ try {
1028
+ const content = await fs.readFile(fullPath, 'utf-8');
1029
+ const lines = content.split('\n');
1030
+ const matches: Array<{ line: number; content: string }> = [];
1031
+
1032
+ lines.forEach((line, index) => {
1033
+ if (line.toLowerCase().includes(query.toLowerCase())) {
1034
+ matches.push({ line: index + 1, content: line.trim() });
1035
+ }
1036
+ });
1037
+
1038
+ if (matches.length > 0) {
1039
+ results.push({ path: fullPath, matches });
1040
+ }
1041
+ } catch {
1042
+ // Skip binary or unreadable files
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+
1048
+ await searchDir(path);
1049
+ return results;
1050
+ } catch (error) {
1051
+ log.error('Search failed:', error);
1052
+ throw error;
1053
+ }
1054
+ });
1055
+
1056
+ // Audit log operations
1057
+ ipcMain.handle('audit:recent', async (event, limit: number = 100) => {
1058
+ return await auditLogger.getRecentEvents(limit);
1059
+ });
1060
+
1061
+ ipcMain.handle('audit:byAction', async (event, action: string, limit: number = 100) => {
1062
+ return await auditLogger.getEventsByAction(action, limit);
1063
+ });
1064
+
1065
+ ipcMain.handle('audit:export', async (event, exportPath: string) => {
1066
+ await auditLogger.exportLogs(exportPath);
1067
+ return { success: true };
1068
+ });
1069
+ ipcMain.handle('notification:show', (event, { title, body }: { title: string; body: string }) => {
1070
+ if (Notification.isSupported()) {
1071
+ new Notification({
1072
+ title,
1073
+ body,
1074
+ icon: path.join(__dirname, '../../assets/icon.png')
1075
+ }).show();
1076
+ }
1077
+ });
1078
+
1079
+ // Export/Import
1080
+ ipcMain.handle('data:export', async (event, exportPath: string) => {
1081
+ try {
1082
+ const data = {
1083
+ agents: await dbManager.getAllAgents(),
1084
+ automations: await automationScheduler.listAutomations(),
1085
+ skills: await skillsManager.listSkills(),
1086
+ settings: settingsManager.getAll(),
1087
+ exportedAt: new Date().toISOString()
1088
+ };
1089
+
1090
+ await fs.writeFile(exportPath, JSON.stringify(data, null, 2), 'utf-8');
1091
+ return true;
1092
+ } catch (error) {
1093
+ log.error('Export failed:', error);
1094
+ throw error;
1095
+ }
1096
+ });
1097
+
1098
+ ipcMain.handle('data:import', async (event, importPath: string) => {
1099
+ try {
1100
+ const normalizedPath = path.normalize(importPath);
1101
+ if (normalizedPath.includes('..')) {
1102
+ throw new Error('Path traversal not allowed');
1103
+ }
1104
+ const content = await fs.readFile(normalizedPath, 'utf-8');
1105
+ let data: any;
1106
+ try {
1107
+ data = JSON.parse(content);
1108
+ } catch {
1109
+ throw new Error('Invalid JSON format');
1110
+ }
1111
+
1112
+ if (!data || typeof data !== 'object') {
1113
+ throw new Error('Invalid import data: must be an object');
1114
+ }
1115
+
1116
+ if (data.agents) {
1117
+ if (!Array.isArray(data.agents)) {
1118
+ throw new Error('Invalid import data: agents must be an array');
1119
+ }
1120
+ for (const agent of data.agents) {
1121
+ if (!agent.name || !agent.projectPath || typeof agent.name !== 'string' || typeof agent.projectPath !== 'string') {
1122
+ throw new Error('Invalid agent: name and projectPath are required strings');
1123
+ }
1124
+ if (agent.projectPath.includes('..') || agent.projectPath.startsWith('/etc') || agent.projectPath.startsWith('/root')) {
1125
+ throw new Error('Invalid agent projectPath: path traversal or restricted path not allowed');
1126
+ }
1127
+ await dbManager.createAgent(agent);
1128
+ }
1129
+ }
1130
+
1131
+ if (data.automations) {
1132
+ if (!Array.isArray(data.automations)) {
1133
+ throw new Error('Invalid import data: automations must be an array');
1134
+ }
1135
+ for (const automation of data.automations) {
1136
+ if (!automation.name || !automation.trigger) {
1137
+ throw new Error('Invalid automation: name and trigger are required');
1138
+ }
1139
+ await automationScheduler.createAutomation(automation);
1140
+ }
1141
+ }
1142
+
1143
+ if (data.settings) {
1144
+ if (typeof data.settings !== 'object' || Array.isArray(data.settings)) {
1145
+ throw new Error('Invalid import data: settings must be an object');
1146
+ }
1147
+ for (const [key, value] of Object.entries(data.settings)) {
1148
+ if (typeof key !== 'string') {
1149
+ throw new Error('Invalid settings: keys must be strings');
1150
+ }
1151
+ settingsManager.setAny(key, value);
1152
+ }
1153
+ }
1154
+
1155
+ return true;
1156
+ } catch (error) {
1157
+ log.error('Import failed:', error);
1158
+ throw error;
1159
+ }
1160
+ });
1161
+
1162
+ // Cowork operations
1163
+ ipcMain.handle('cowork:create', async (event, name: string, objective: string, projectPath: string, options: any) => {
1164
+ return await coworkManager.createSession(name, objective, projectPath, options);
1165
+ });
1166
+
1167
+ ipcMain.handle('cowork:start', async (event, sessionId: string) => {
1168
+ return await coworkManager.startSession(sessionId);
1169
+ });
1170
+
1171
+ ipcMain.handle('cowork:pause', async (event, sessionId: string) => {
1172
+ return await coworkManager.pauseSession(sessionId);
1173
+ });
1174
+
1175
+ ipcMain.handle('cowork:stop', async (event, sessionId: string) => {
1176
+ return await coworkManager.stopSession(sessionId);
1177
+ });
1178
+
1179
+ ipcMain.handle('cowork:list', async () => {
1180
+ return coworkManager.getSessions();
1181
+ });
1182
+
1183
+ // Pair programming operations
1184
+ ipcMain.handle('pair:start', async (event, projectPath: string, mode: string, userId: string) => {
1185
+ const validModes = ['collaborative', 'teacher', 'reviewer'];
1186
+ const validMode = validModes.includes(mode) ? mode as 'collaborative' | 'teacher' | 'reviewer' : 'collaborative';
1187
+ return await aiPairProgramming.startSession(projectPath, validMode, userId);
1188
+ });
1189
+
1190
+ ipcMain.handle('pair:chat', async (event, sessionId: string, message: string) => {
1191
+ return await aiPairProgramming.chat(sessionId, message);
1192
+ });
1193
+
1194
+ ipcMain.handle('pair:end', async (event, sessionId: string) => {
1195
+ return await aiPairProgramming.endSession(sessionId);
1196
+ });
1197
+
1198
+ // Smart code assistant
1199
+ ipcMain.handle('assistant:inlineCompletion', async (event, filePath: string, content: string, position: any) => {
1200
+ return await smartCodeAssistant.provideInlineCompletion(filePath, content, position);
1201
+ });
1202
+
1203
+ ipcMain.handle('assistant:suggestFixes', async (event, filePath: string, content: string) => {
1204
+ return await smartCodeAssistant.suggestFixes(filePath, content);
1205
+ });
1206
+
1207
+ ipcMain.handle('assistant:explain', async (event, code: string) => {
1208
+ return await smartCodeAssistant.explainCode(code, 'detailed');
1209
+ });
1210
+
1211
+ // Metrics
1212
+ ipcMain.handle('metrics:get', () => {
1213
+ return metrics.getStats();
1214
+ });
1215
+
1216
+ ipcMain.handle('metrics:export', () => {
1217
+ return metrics.exportMetrics();
1218
+ });
1219
+
1220
+ log.info('IPC handlers setup completed');
1221
+ }