cowork-os 0.3.21

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 (526) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1638 -0
  3. package/bin/cowork.js +42 -0
  4. package/build/entitlements.mac.plist +16 -0
  5. package/build/icon.icns +0 -0
  6. package/build/icon.png +0 -0
  7. package/dist/electron/electron/activity/ActivityRepository.js +190 -0
  8. package/dist/electron/electron/agent/browser/browser-service.js +639 -0
  9. package/dist/electron/electron/agent/context-manager.js +225 -0
  10. package/dist/electron/electron/agent/custom-skill-loader.js +566 -0
  11. package/dist/electron/electron/agent/daemon.js +975 -0
  12. package/dist/electron/electron/agent/executor.js +3561 -0
  13. package/dist/electron/electron/agent/llm/anthropic-provider.js +155 -0
  14. package/dist/electron/electron/agent/llm/bedrock-provider.js +202 -0
  15. package/dist/electron/electron/agent/llm/gemini-provider.js +375 -0
  16. package/dist/electron/electron/agent/llm/index.js +34 -0
  17. package/dist/electron/electron/agent/llm/ollama-provider.js +263 -0
  18. package/dist/electron/electron/agent/llm/openai-oauth.js +101 -0
  19. package/dist/electron/electron/agent/llm/openai-provider.js +657 -0
  20. package/dist/electron/electron/agent/llm/openrouter-provider.js +232 -0
  21. package/dist/electron/electron/agent/llm/pricing.js +160 -0
  22. package/dist/electron/electron/agent/llm/provider-factory.js +880 -0
  23. package/dist/electron/electron/agent/llm/types.js +178 -0
  24. package/dist/electron/electron/agent/queue-manager.js +378 -0
  25. package/dist/electron/electron/agent/sandbox/docker-sandbox.js +402 -0
  26. package/dist/electron/electron/agent/sandbox/macos-sandbox.js +407 -0
  27. package/dist/electron/electron/agent/sandbox/runner.js +410 -0
  28. package/dist/electron/electron/agent/sandbox/sandbox-factory.js +228 -0
  29. package/dist/electron/electron/agent/sandbox/security-utils.js +258 -0
  30. package/dist/electron/electron/agent/search/brave-provider.js +119 -0
  31. package/dist/electron/electron/agent/search/google-provider.js +100 -0
  32. package/dist/electron/electron/agent/search/index.js +28 -0
  33. package/dist/electron/electron/agent/search/provider-factory.js +395 -0
  34. package/dist/electron/electron/agent/search/serpapi-provider.js +112 -0
  35. package/dist/electron/electron/agent/search/tavily-provider.js +90 -0
  36. package/dist/electron/electron/agent/search/types.js +40 -0
  37. package/dist/electron/electron/agent/security/index.js +12 -0
  38. package/dist/electron/electron/agent/security/input-sanitizer.js +303 -0
  39. package/dist/electron/electron/agent/security/output-filter.js +217 -0
  40. package/dist/electron/electron/agent/skill-eligibility.js +281 -0
  41. package/dist/electron/electron/agent/skill-registry.js +396 -0
  42. package/dist/electron/electron/agent/skills/document.js +878 -0
  43. package/dist/electron/electron/agent/skills/image-generator.js +225 -0
  44. package/dist/electron/electron/agent/skills/organizer.js +141 -0
  45. package/dist/electron/electron/agent/skills/presentation.js +367 -0
  46. package/dist/electron/electron/agent/skills/spreadsheet.js +165 -0
  47. package/dist/electron/electron/agent/tools/browser-tools.js +523 -0
  48. package/dist/electron/electron/agent/tools/builtin-settings.js +384 -0
  49. package/dist/electron/electron/agent/tools/canvas-tools.js +530 -0
  50. package/dist/electron/electron/agent/tools/cron-tools.js +577 -0
  51. package/dist/electron/electron/agent/tools/edit-tools.js +194 -0
  52. package/dist/electron/electron/agent/tools/file-tools.js +719 -0
  53. package/dist/electron/electron/agent/tools/glob-tools.js +283 -0
  54. package/dist/electron/electron/agent/tools/grep-tools.js +387 -0
  55. package/dist/electron/electron/agent/tools/image-tools.js +111 -0
  56. package/dist/electron/electron/agent/tools/mention-tools.js +282 -0
  57. package/dist/electron/electron/agent/tools/node-tools.js +476 -0
  58. package/dist/electron/electron/agent/tools/registry.js +2719 -0
  59. package/dist/electron/electron/agent/tools/search-tools.js +91 -0
  60. package/dist/electron/electron/agent/tools/shell-tools.js +574 -0
  61. package/dist/electron/electron/agent/tools/skill-tools.js +274 -0
  62. package/dist/electron/electron/agent/tools/system-tools.js +578 -0
  63. package/dist/electron/electron/agent/tools/web-fetch-tools.js +444 -0
  64. package/dist/electron/electron/agent/tools/x-tools.js +264 -0
  65. package/dist/electron/electron/agents/AgentRoleRepository.js +420 -0
  66. package/dist/electron/electron/agents/HeartbeatService.js +356 -0
  67. package/dist/electron/electron/agents/MentionRepository.js +197 -0
  68. package/dist/electron/electron/agents/TaskSubscriptionRepository.js +168 -0
  69. package/dist/electron/electron/agents/WorkingStateRepository.js +229 -0
  70. package/dist/electron/electron/canvas/canvas-manager.js +714 -0
  71. package/dist/electron/electron/canvas/canvas-preload.js +53 -0
  72. package/dist/electron/electron/canvas/canvas-protocol.js +195 -0
  73. package/dist/electron/electron/canvas/canvas-store.js +174 -0
  74. package/dist/electron/electron/canvas/index.js +13 -0
  75. package/dist/electron/electron/control-plane/client.js +364 -0
  76. package/dist/electron/electron/control-plane/handlers.js +572 -0
  77. package/dist/electron/electron/control-plane/index.js +41 -0
  78. package/dist/electron/electron/control-plane/node-manager.js +264 -0
  79. package/dist/electron/electron/control-plane/protocol.js +194 -0
  80. package/dist/electron/electron/control-plane/remote-client.js +437 -0
  81. package/dist/electron/electron/control-plane/server.js +640 -0
  82. package/dist/electron/electron/control-plane/settings.js +369 -0
  83. package/dist/electron/electron/control-plane/ssh-tunnel.js +549 -0
  84. package/dist/electron/electron/cron/index.js +30 -0
  85. package/dist/electron/electron/cron/schedule.js +190 -0
  86. package/dist/electron/electron/cron/service.js +614 -0
  87. package/dist/electron/electron/cron/store.js +155 -0
  88. package/dist/electron/electron/cron/types.js +82 -0
  89. package/dist/electron/electron/cron/webhook.js +258 -0
  90. package/dist/electron/electron/database/SecureSettingsRepository.js +444 -0
  91. package/dist/electron/electron/database/TaskLabelRepository.js +120 -0
  92. package/dist/electron/electron/database/repositories.js +1781 -0
  93. package/dist/electron/electron/database/schema.js +978 -0
  94. package/dist/electron/electron/extensions/index.js +33 -0
  95. package/dist/electron/electron/extensions/loader.js +313 -0
  96. package/dist/electron/electron/extensions/registry.js +485 -0
  97. package/dist/electron/electron/extensions/types.js +11 -0
  98. package/dist/electron/electron/gateway/channel-registry.js +1102 -0
  99. package/dist/electron/electron/gateway/channels/bluebubbles-client.js +479 -0
  100. package/dist/electron/electron/gateway/channels/bluebubbles.js +432 -0
  101. package/dist/electron/electron/gateway/channels/discord.js +975 -0
  102. package/dist/electron/electron/gateway/channels/email-client.js +593 -0
  103. package/dist/electron/electron/gateway/channels/email.js +443 -0
  104. package/dist/electron/electron/gateway/channels/google-chat.js +631 -0
  105. package/dist/electron/electron/gateway/channels/imessage-client.js +363 -0
  106. package/dist/electron/electron/gateway/channels/imessage.js +465 -0
  107. package/dist/electron/electron/gateway/channels/index.js +36 -0
  108. package/dist/electron/electron/gateway/channels/line-client.js +470 -0
  109. package/dist/electron/electron/gateway/channels/line.js +479 -0
  110. package/dist/electron/electron/gateway/channels/matrix-client.js +432 -0
  111. package/dist/electron/electron/gateway/channels/matrix.js +592 -0
  112. package/dist/electron/electron/gateway/channels/mattermost-client.js +394 -0
  113. package/dist/electron/electron/gateway/channels/mattermost.js +496 -0
  114. package/dist/electron/electron/gateway/channels/signal-client.js +500 -0
  115. package/dist/electron/electron/gateway/channels/signal.js +582 -0
  116. package/dist/electron/electron/gateway/channels/slack.js +415 -0
  117. package/dist/electron/electron/gateway/channels/teams.js +596 -0
  118. package/dist/electron/electron/gateway/channels/telegram.js +1390 -0
  119. package/dist/electron/electron/gateway/channels/twitch-client.js +502 -0
  120. package/dist/electron/electron/gateway/channels/twitch.js +396 -0
  121. package/dist/electron/electron/gateway/channels/types.js +8 -0
  122. package/dist/electron/electron/gateway/channels/whatsapp.js +953 -0
  123. package/dist/electron/electron/gateway/context-policy.js +268 -0
  124. package/dist/electron/electron/gateway/index.js +1063 -0
  125. package/dist/electron/electron/gateway/infrastructure.js +496 -0
  126. package/dist/electron/electron/gateway/router.js +2700 -0
  127. package/dist/electron/electron/gateway/security.js +375 -0
  128. package/dist/electron/electron/gateway/session.js +115 -0
  129. package/dist/electron/electron/gateway/tunnel.js +503 -0
  130. package/dist/electron/electron/guardrails/guardrail-manager.js +348 -0
  131. package/dist/electron/electron/hooks/gmail-watcher.js +300 -0
  132. package/dist/electron/electron/hooks/index.js +46 -0
  133. package/dist/electron/electron/hooks/mappings.js +381 -0
  134. package/dist/electron/electron/hooks/server.js +480 -0
  135. package/dist/electron/electron/hooks/settings.js +447 -0
  136. package/dist/electron/electron/hooks/types.js +41 -0
  137. package/dist/electron/electron/ipc/canvas-handlers.js +158 -0
  138. package/dist/electron/electron/ipc/handlers.js +3138 -0
  139. package/dist/electron/electron/ipc/mission-control-handlers.js +141 -0
  140. package/dist/electron/electron/main.js +448 -0
  141. package/dist/electron/electron/mcp/client/MCPClientManager.js +330 -0
  142. package/dist/electron/electron/mcp/client/MCPServerConnection.js +437 -0
  143. package/dist/electron/electron/mcp/client/transports/SSETransport.js +304 -0
  144. package/dist/electron/electron/mcp/client/transports/StdioTransport.js +307 -0
  145. package/dist/electron/electron/mcp/client/transports/WebSocketTransport.js +329 -0
  146. package/dist/electron/electron/mcp/host/MCPHostServer.js +354 -0
  147. package/dist/electron/electron/mcp/host/ToolAdapter.js +100 -0
  148. package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +497 -0
  149. package/dist/electron/electron/mcp/settings.js +446 -0
  150. package/dist/electron/electron/mcp/types.js +59 -0
  151. package/dist/electron/electron/memory/MemoryService.js +435 -0
  152. package/dist/electron/electron/notifications/index.js +17 -0
  153. package/dist/electron/electron/notifications/service.js +118 -0
  154. package/dist/electron/electron/notifications/store.js +144 -0
  155. package/dist/electron/electron/preload.js +842 -0
  156. package/dist/electron/electron/reports/StandupReportService.js +272 -0
  157. package/dist/electron/electron/security/concurrency.js +293 -0
  158. package/dist/electron/electron/security/index.js +15 -0
  159. package/dist/electron/electron/security/policy-manager.js +435 -0
  160. package/dist/electron/electron/settings/appearance-manager.js +193 -0
  161. package/dist/electron/electron/settings/personality-manager.js +724 -0
  162. package/dist/electron/electron/settings/x-manager.js +58 -0
  163. package/dist/electron/electron/tailscale/exposure.js +188 -0
  164. package/dist/electron/electron/tailscale/index.js +28 -0
  165. package/dist/electron/electron/tailscale/settings.js +205 -0
  166. package/dist/electron/electron/tailscale/tailscale.js +355 -0
  167. package/dist/electron/electron/tray/QuickInputWindow.js +568 -0
  168. package/dist/electron/electron/tray/TrayManager.js +895 -0
  169. package/dist/electron/electron/tray/index.js +9 -0
  170. package/dist/electron/electron/updater/index.js +6 -0
  171. package/dist/electron/electron/updater/update-manager.js +418 -0
  172. package/dist/electron/electron/utils/env-migration.js +209 -0
  173. package/dist/electron/electron/utils/process.js +102 -0
  174. package/dist/electron/electron/utils/rate-limiter.js +104 -0
  175. package/dist/electron/electron/utils/validation.js +419 -0
  176. package/dist/electron/electron/utils/x-cli.js +177 -0
  177. package/dist/electron/electron/voice/VoiceService.js +507 -0
  178. package/dist/electron/electron/voice/index.js +14 -0
  179. package/dist/electron/electron/voice/voice-settings-manager.js +359 -0
  180. package/dist/electron/shared/channelMessages.js +170 -0
  181. package/dist/electron/shared/types.js +1185 -0
  182. package/package.json +159 -0
  183. package/resources/skills/1password.json +10 -0
  184. package/resources/skills/add-documentation.json +31 -0
  185. package/resources/skills/analyze-csv.json +17 -0
  186. package/resources/skills/apple-notes.json +10 -0
  187. package/resources/skills/apple-reminders.json +10 -0
  188. package/resources/skills/auto-commenter.json +10 -0
  189. package/resources/skills/bear-notes.json +10 -0
  190. package/resources/skills/bird.json +35 -0
  191. package/resources/skills/blogwatcher.json +10 -0
  192. package/resources/skills/blucli.json +10 -0
  193. package/resources/skills/bluebubbles.json +10 -0
  194. package/resources/skills/camsnap.json +10 -0
  195. package/resources/skills/clean-imports.json +18 -0
  196. package/resources/skills/code-review.json +18 -0
  197. package/resources/skills/coding-agent.json +10 -0
  198. package/resources/skills/compare-files.json +23 -0
  199. package/resources/skills/convert-code.json +34 -0
  200. package/resources/skills/create-changelog.json +24 -0
  201. package/resources/skills/debug-error.json +17 -0
  202. package/resources/skills/dependency-check.json +10 -0
  203. package/resources/skills/discord.json +10 -0
  204. package/resources/skills/eightctl.json +10 -0
  205. package/resources/skills/explain-code.json +29 -0
  206. package/resources/skills/extract-todos.json +18 -0
  207. package/resources/skills/food-order.json +10 -0
  208. package/resources/skills/gemini.json +10 -0
  209. package/resources/skills/generate-readme.json +10 -0
  210. package/resources/skills/gifgrep.json +10 -0
  211. package/resources/skills/git-commit.json +10 -0
  212. package/resources/skills/github.json +10 -0
  213. package/resources/skills/gog.json +10 -0
  214. package/resources/skills/goplaces.json +10 -0
  215. package/resources/skills/himalaya.json +10 -0
  216. package/resources/skills/imsg.json +10 -0
  217. package/resources/skills/karpathy-guidelines.json +12 -0
  218. package/resources/skills/last30days.json +26 -0
  219. package/resources/skills/local-places.json +10 -0
  220. package/resources/skills/mcporter.json +10 -0
  221. package/resources/skills/model-usage.json +10 -0
  222. package/resources/skills/nano-banana-pro.json +10 -0
  223. package/resources/skills/nano-pdf.json +10 -0
  224. package/resources/skills/notion.json +10 -0
  225. package/resources/skills/obsidian.json +10 -0
  226. package/resources/skills/openai-image-gen.json +10 -0
  227. package/resources/skills/openai-whisper-api.json +10 -0
  228. package/resources/skills/openai-whisper.json +10 -0
  229. package/resources/skills/openhue.json +10 -0
  230. package/resources/skills/oracle.json +10 -0
  231. package/resources/skills/ordercli.json +10 -0
  232. package/resources/skills/peekaboo.json +10 -0
  233. package/resources/skills/project-structure.json +10 -0
  234. package/resources/skills/proofread.json +17 -0
  235. package/resources/skills/refactor-code.json +31 -0
  236. package/resources/skills/rename-symbol.json +23 -0
  237. package/resources/skills/sag.json +10 -0
  238. package/resources/skills/security-audit.json +18 -0
  239. package/resources/skills/session-logs.json +10 -0
  240. package/resources/skills/sherpa-onnx-tts.json +10 -0
  241. package/resources/skills/skill-creator.json +15 -0
  242. package/resources/skills/skill-hub.json +29 -0
  243. package/resources/skills/slack.json +10 -0
  244. package/resources/skills/songsee.json +10 -0
  245. package/resources/skills/sonoscli.json +10 -0
  246. package/resources/skills/spotify-player.json +10 -0
  247. package/resources/skills/startup-cfo.json +55 -0
  248. package/resources/skills/summarize-folder.json +18 -0
  249. package/resources/skills/summarize.json +10 -0
  250. package/resources/skills/things-mac.json +10 -0
  251. package/resources/skills/tmux.json +10 -0
  252. package/resources/skills/translate.json +36 -0
  253. package/resources/skills/trello.json +10 -0
  254. package/resources/skills/video-frames.json +10 -0
  255. package/resources/skills/voice-call.json +10 -0
  256. package/resources/skills/wacli.json +10 -0
  257. package/resources/skills/weather.json +10 -0
  258. package/resources/skills/write-tests.json +31 -0
  259. package/src/electron/activity/ActivityRepository.ts +238 -0
  260. package/src/electron/agent/browser/browser-service.ts +721 -0
  261. package/src/electron/agent/context-manager.ts +257 -0
  262. package/src/electron/agent/custom-skill-loader.ts +634 -0
  263. package/src/electron/agent/daemon.ts +1097 -0
  264. package/src/electron/agent/executor.ts +4017 -0
  265. package/src/electron/agent/llm/anthropic-provider.ts +175 -0
  266. package/src/electron/agent/llm/bedrock-provider.ts +236 -0
  267. package/src/electron/agent/llm/gemini-provider.ts +422 -0
  268. package/src/electron/agent/llm/index.ts +9 -0
  269. package/src/electron/agent/llm/ollama-provider.ts +347 -0
  270. package/src/electron/agent/llm/openai-oauth.ts +127 -0
  271. package/src/electron/agent/llm/openai-provider.ts +686 -0
  272. package/src/electron/agent/llm/openrouter-provider.ts +273 -0
  273. package/src/electron/agent/llm/pricing.ts +180 -0
  274. package/src/electron/agent/llm/provider-factory.ts +971 -0
  275. package/src/electron/agent/llm/types.ts +291 -0
  276. package/src/electron/agent/queue-manager.ts +408 -0
  277. package/src/electron/agent/sandbox/docker-sandbox.ts +453 -0
  278. package/src/electron/agent/sandbox/macos-sandbox.ts +426 -0
  279. package/src/electron/agent/sandbox/runner.ts +453 -0
  280. package/src/electron/agent/sandbox/sandbox-factory.ts +337 -0
  281. package/src/electron/agent/sandbox/security-utils.ts +251 -0
  282. package/src/electron/agent/search/brave-provider.ts +141 -0
  283. package/src/electron/agent/search/google-provider.ts +131 -0
  284. package/src/electron/agent/search/index.ts +6 -0
  285. package/src/electron/agent/search/provider-factory.ts +450 -0
  286. package/src/electron/agent/search/serpapi-provider.ts +138 -0
  287. package/src/electron/agent/search/tavily-provider.ts +108 -0
  288. package/src/electron/agent/search/types.ts +118 -0
  289. package/src/electron/agent/security/index.ts +20 -0
  290. package/src/electron/agent/security/input-sanitizer.ts +380 -0
  291. package/src/electron/agent/security/output-filter.ts +259 -0
  292. package/src/electron/agent/skill-eligibility.ts +334 -0
  293. package/src/electron/agent/skill-registry.ts +457 -0
  294. package/src/electron/agent/skills/document.ts +1070 -0
  295. package/src/electron/agent/skills/image-generator.ts +272 -0
  296. package/src/electron/agent/skills/organizer.ts +131 -0
  297. package/src/electron/agent/skills/presentation.ts +418 -0
  298. package/src/electron/agent/skills/spreadsheet.ts +166 -0
  299. package/src/electron/agent/tools/browser-tools.ts +546 -0
  300. package/src/electron/agent/tools/builtin-settings.ts +422 -0
  301. package/src/electron/agent/tools/canvas-tools.ts +572 -0
  302. package/src/electron/agent/tools/cron-tools.ts +723 -0
  303. package/src/electron/agent/tools/edit-tools.ts +196 -0
  304. package/src/electron/agent/tools/file-tools.ts +811 -0
  305. package/src/electron/agent/tools/glob-tools.ts +303 -0
  306. package/src/electron/agent/tools/grep-tools.ts +432 -0
  307. package/src/electron/agent/tools/image-tools.ts +126 -0
  308. package/src/electron/agent/tools/mention-tools.ts +371 -0
  309. package/src/electron/agent/tools/node-tools.ts +550 -0
  310. package/src/electron/agent/tools/registry.ts +3052 -0
  311. package/src/electron/agent/tools/search-tools.ts +111 -0
  312. package/src/electron/agent/tools/shell-tools.ts +651 -0
  313. package/src/electron/agent/tools/skill-tools.ts +340 -0
  314. package/src/electron/agent/tools/system-tools.ts +665 -0
  315. package/src/electron/agent/tools/web-fetch-tools.ts +528 -0
  316. package/src/electron/agent/tools/x-tools.ts +267 -0
  317. package/src/electron/agents/AgentRoleRepository.ts +557 -0
  318. package/src/electron/agents/HeartbeatService.ts +469 -0
  319. package/src/electron/agents/MentionRepository.ts +242 -0
  320. package/src/electron/agents/TaskSubscriptionRepository.ts +231 -0
  321. package/src/electron/agents/WorkingStateRepository.ts +278 -0
  322. package/src/electron/canvas/canvas-manager.ts +818 -0
  323. package/src/electron/canvas/canvas-preload.ts +102 -0
  324. package/src/electron/canvas/canvas-protocol.ts +174 -0
  325. package/src/electron/canvas/canvas-store.ts +200 -0
  326. package/src/electron/canvas/index.ts +8 -0
  327. package/src/electron/control-plane/client.ts +527 -0
  328. package/src/electron/control-plane/handlers.ts +723 -0
  329. package/src/electron/control-plane/index.ts +51 -0
  330. package/src/electron/control-plane/node-manager.ts +322 -0
  331. package/src/electron/control-plane/protocol.ts +269 -0
  332. package/src/electron/control-plane/remote-client.ts +517 -0
  333. package/src/electron/control-plane/server.ts +853 -0
  334. package/src/electron/control-plane/settings.ts +401 -0
  335. package/src/electron/control-plane/ssh-tunnel.ts +624 -0
  336. package/src/electron/cron/index.ts +9 -0
  337. package/src/electron/cron/schedule.ts +217 -0
  338. package/src/electron/cron/service.ts +743 -0
  339. package/src/electron/cron/store.ts +165 -0
  340. package/src/electron/cron/types.ts +291 -0
  341. package/src/electron/cron/webhook.ts +303 -0
  342. package/src/electron/database/SecureSettingsRepository.ts +514 -0
  343. package/src/electron/database/TaskLabelRepository.ts +148 -0
  344. package/src/electron/database/repositories.ts +2397 -0
  345. package/src/electron/database/schema.ts +1017 -0
  346. package/src/electron/extensions/index.ts +18 -0
  347. package/src/electron/extensions/loader.ts +336 -0
  348. package/src/electron/extensions/registry.ts +546 -0
  349. package/src/electron/extensions/types.ts +372 -0
  350. package/src/electron/gateway/channel-registry.ts +1267 -0
  351. package/src/electron/gateway/channels/bluebubbles-client.ts +641 -0
  352. package/src/electron/gateway/channels/bluebubbles.ts +509 -0
  353. package/src/electron/gateway/channels/discord.ts +1150 -0
  354. package/src/electron/gateway/channels/email-client.ts +708 -0
  355. package/src/electron/gateway/channels/email.ts +516 -0
  356. package/src/electron/gateway/channels/google-chat.ts +760 -0
  357. package/src/electron/gateway/channels/imessage-client.ts +473 -0
  358. package/src/electron/gateway/channels/imessage.ts +520 -0
  359. package/src/electron/gateway/channels/index.ts +21 -0
  360. package/src/electron/gateway/channels/line-client.ts +598 -0
  361. package/src/electron/gateway/channels/line.ts +559 -0
  362. package/src/electron/gateway/channels/matrix-client.ts +632 -0
  363. package/src/electron/gateway/channels/matrix.ts +655 -0
  364. package/src/electron/gateway/channels/mattermost-client.ts +526 -0
  365. package/src/electron/gateway/channels/mattermost.ts +550 -0
  366. package/src/electron/gateway/channels/signal-client.ts +722 -0
  367. package/src/electron/gateway/channels/signal.ts +666 -0
  368. package/src/electron/gateway/channels/slack.ts +458 -0
  369. package/src/electron/gateway/channels/teams.ts +681 -0
  370. package/src/electron/gateway/channels/telegram.ts +1727 -0
  371. package/src/electron/gateway/channels/twitch-client.ts +665 -0
  372. package/src/electron/gateway/channels/twitch.ts +468 -0
  373. package/src/electron/gateway/channels/types.ts +1002 -0
  374. package/src/electron/gateway/channels/whatsapp.ts +1101 -0
  375. package/src/electron/gateway/context-policy.ts +382 -0
  376. package/src/electron/gateway/index.ts +1274 -0
  377. package/src/electron/gateway/infrastructure.ts +645 -0
  378. package/src/electron/gateway/router.ts +3206 -0
  379. package/src/electron/gateway/security.ts +422 -0
  380. package/src/electron/gateway/session.ts +144 -0
  381. package/src/electron/gateway/tunnel.ts +626 -0
  382. package/src/electron/guardrails/guardrail-manager.ts +380 -0
  383. package/src/electron/hooks/gmail-watcher.ts +355 -0
  384. package/src/electron/hooks/index.ts +30 -0
  385. package/src/electron/hooks/mappings.ts +404 -0
  386. package/src/electron/hooks/server.ts +574 -0
  387. package/src/electron/hooks/settings.ts +466 -0
  388. package/src/electron/hooks/types.ts +245 -0
  389. package/src/electron/ipc/canvas-handlers.ts +223 -0
  390. package/src/electron/ipc/handlers.ts +3661 -0
  391. package/src/electron/ipc/mission-control-handlers.ts +182 -0
  392. package/src/electron/main.ts +496 -0
  393. package/src/electron/mcp/client/MCPClientManager.ts +406 -0
  394. package/src/electron/mcp/client/MCPServerConnection.ts +514 -0
  395. package/src/electron/mcp/client/transports/SSETransport.ts +360 -0
  396. package/src/electron/mcp/client/transports/StdioTransport.ts +355 -0
  397. package/src/electron/mcp/client/transports/WebSocketTransport.ts +384 -0
  398. package/src/electron/mcp/host/MCPHostServer.ts +388 -0
  399. package/src/electron/mcp/host/ToolAdapter.ts +140 -0
  400. package/src/electron/mcp/registry/MCPRegistryManager.ts +565 -0
  401. package/src/electron/mcp/settings.ts +468 -0
  402. package/src/electron/mcp/types.ts +371 -0
  403. package/src/electron/memory/MemoryService.ts +523 -0
  404. package/src/electron/notifications/index.ts +16 -0
  405. package/src/electron/notifications/service.ts +161 -0
  406. package/src/electron/notifications/store.ts +163 -0
  407. package/src/electron/preload.ts +2845 -0
  408. package/src/electron/reports/StandupReportService.ts +356 -0
  409. package/src/electron/security/concurrency.ts +333 -0
  410. package/src/electron/security/index.ts +17 -0
  411. package/src/electron/security/policy-manager.ts +539 -0
  412. package/src/electron/settings/appearance-manager.ts +182 -0
  413. package/src/electron/settings/personality-manager.ts +800 -0
  414. package/src/electron/settings/x-manager.ts +62 -0
  415. package/src/electron/tailscale/exposure.ts +262 -0
  416. package/src/electron/tailscale/index.ts +34 -0
  417. package/src/electron/tailscale/settings.ts +218 -0
  418. package/src/electron/tailscale/tailscale.ts +379 -0
  419. package/src/electron/tray/QuickInputWindow.ts +609 -0
  420. package/src/electron/tray/TrayManager.ts +1005 -0
  421. package/src/electron/tray/index.ts +6 -0
  422. package/src/electron/updater/index.ts +1 -0
  423. package/src/electron/updater/update-manager.ts +447 -0
  424. package/src/electron/utils/env-migration.ts +203 -0
  425. package/src/electron/utils/process.ts +124 -0
  426. package/src/electron/utils/rate-limiter.ts +130 -0
  427. package/src/electron/utils/validation.ts +493 -0
  428. package/src/electron/utils/x-cli.ts +198 -0
  429. package/src/electron/voice/VoiceService.ts +583 -0
  430. package/src/electron/voice/index.ts +9 -0
  431. package/src/electron/voice/voice-settings-manager.ts +403 -0
  432. package/src/renderer/App.tsx +775 -0
  433. package/src/renderer/components/ActivityFeed.tsx +407 -0
  434. package/src/renderer/components/ActivityFeedItem.tsx +285 -0
  435. package/src/renderer/components/AgentRoleCard.tsx +343 -0
  436. package/src/renderer/components/AgentRoleEditor.tsx +805 -0
  437. package/src/renderer/components/AgentSquadSettings.tsx +295 -0
  438. package/src/renderer/components/AgentWorkingStatePanel.tsx +411 -0
  439. package/src/renderer/components/AppearanceSettings.tsx +122 -0
  440. package/src/renderer/components/ApprovalDialog.tsx +100 -0
  441. package/src/renderer/components/BlueBubblesSettings.tsx +505 -0
  442. package/src/renderer/components/BuiltinToolsSettings.tsx +307 -0
  443. package/src/renderer/components/CanvasPreview.tsx +1189 -0
  444. package/src/renderer/components/CommandOutput.tsx +202 -0
  445. package/src/renderer/components/ContextPolicySettings.tsx +523 -0
  446. package/src/renderer/components/ControlPlaneSettings.tsx +1134 -0
  447. package/src/renderer/components/DisclaimerModal.tsx +124 -0
  448. package/src/renderer/components/DiscordSettings.tsx +436 -0
  449. package/src/renderer/components/EmailSettings.tsx +606 -0
  450. package/src/renderer/components/ExtensionsSettings.tsx +542 -0
  451. package/src/renderer/components/FileViewer.tsx +224 -0
  452. package/src/renderer/components/GoogleChatSettings.tsx +535 -0
  453. package/src/renderer/components/GuardrailSettings.tsx +487 -0
  454. package/src/renderer/components/HooksSettings.tsx +581 -0
  455. package/src/renderer/components/ImessageSettings.tsx +484 -0
  456. package/src/renderer/components/LineSettings.tsx +483 -0
  457. package/src/renderer/components/MCPRegistryBrowser.tsx +386 -0
  458. package/src/renderer/components/MCPSettings.tsx +943 -0
  459. package/src/renderer/components/MainContent.tsx +2433 -0
  460. package/src/renderer/components/MatrixSettings.tsx +510 -0
  461. package/src/renderer/components/MattermostSettings.tsx +473 -0
  462. package/src/renderer/components/MemorySettings.tsx +247 -0
  463. package/src/renderer/components/MentionBadge.tsx +87 -0
  464. package/src/renderer/components/MentionInput.tsx +409 -0
  465. package/src/renderer/components/MentionList.tsx +476 -0
  466. package/src/renderer/components/MissionControlPanel.tsx +1995 -0
  467. package/src/renderer/components/NodesSettings.tsx +316 -0
  468. package/src/renderer/components/NotificationPanel.tsx +481 -0
  469. package/src/renderer/components/Onboarding/AwakeningOrb.tsx +44 -0
  470. package/src/renderer/components/Onboarding/Onboarding.tsx +443 -0
  471. package/src/renderer/components/Onboarding/TypewriterText.tsx +102 -0
  472. package/src/renderer/components/Onboarding/index.ts +3 -0
  473. package/src/renderer/components/OnboardingModal.tsx +698 -0
  474. package/src/renderer/components/PairingCodeDisplay.tsx +324 -0
  475. package/src/renderer/components/PersonalitySettings.tsx +597 -0
  476. package/src/renderer/components/QueueSettings.tsx +119 -0
  477. package/src/renderer/components/QuickTaskFAB.tsx +71 -0
  478. package/src/renderer/components/RightPanel.tsx +413 -0
  479. package/src/renderer/components/ScheduledTasksSettings.tsx +1328 -0
  480. package/src/renderer/components/SearchSettings.tsx +328 -0
  481. package/src/renderer/components/Settings.tsx +1504 -0
  482. package/src/renderer/components/Sidebar.tsx +344 -0
  483. package/src/renderer/components/SignalSettings.tsx +673 -0
  484. package/src/renderer/components/SkillHubBrowser.tsx +458 -0
  485. package/src/renderer/components/SkillParameterModal.tsx +185 -0
  486. package/src/renderer/components/SkillsSettings.tsx +451 -0
  487. package/src/renderer/components/SlackSettings.tsx +442 -0
  488. package/src/renderer/components/StandupReportViewer.tsx +614 -0
  489. package/src/renderer/components/TaskBoard.tsx +498 -0
  490. package/src/renderer/components/TaskBoardCard.tsx +357 -0
  491. package/src/renderer/components/TaskBoardColumn.tsx +211 -0
  492. package/src/renderer/components/TaskLabelManager.tsx +472 -0
  493. package/src/renderer/components/TaskQueuePanel.tsx +144 -0
  494. package/src/renderer/components/TaskQuickActions.tsx +492 -0
  495. package/src/renderer/components/TaskTimeline.tsx +216 -0
  496. package/src/renderer/components/TaskView.tsx +162 -0
  497. package/src/renderer/components/TeamsSettings.tsx +518 -0
  498. package/src/renderer/components/TelegramSettings.tsx +421 -0
  499. package/src/renderer/components/Toast.tsx +76 -0
  500. package/src/renderer/components/TraySettings.tsx +189 -0
  501. package/src/renderer/components/TwitchSettings.tsx +511 -0
  502. package/src/renderer/components/UpdateSettings.tsx +295 -0
  503. package/src/renderer/components/VoiceIndicator.tsx +270 -0
  504. package/src/renderer/components/VoiceSettings.tsx +867 -0
  505. package/src/renderer/components/WhatsAppSettings.tsx +721 -0
  506. package/src/renderer/components/WorkingStateEditor.tsx +309 -0
  507. package/src/renderer/components/WorkingStateHistory.tsx +481 -0
  508. package/src/renderer/components/WorkspaceSelector.tsx +150 -0
  509. package/src/renderer/components/XSettings.tsx +311 -0
  510. package/src/renderer/global.d.ts +9 -0
  511. package/src/renderer/hooks/useAgentContext.ts +153 -0
  512. package/src/renderer/hooks/useOnboardingFlow.ts +548 -0
  513. package/src/renderer/hooks/useVoiceInput.ts +268 -0
  514. package/src/renderer/index.html +12 -0
  515. package/src/renderer/main.tsx +10 -0
  516. package/src/renderer/public/cowork-os-logo.png +0 -0
  517. package/src/renderer/quick-input.html +164 -0
  518. package/src/renderer/styles/index.css +14504 -0
  519. package/src/renderer/utils/agentMessages.ts +749 -0
  520. package/src/renderer/utils/voice-directives.ts +169 -0
  521. package/src/shared/channelMessages.ts +213 -0
  522. package/src/shared/types.ts +3608 -0
  523. package/tsconfig.electron.json +26 -0
  524. package/tsconfig.json +26 -0
  525. package/tsconfig.node.json +10 -0
  526. package/vite.config.ts +23 -0
@@ -0,0 +1,182 @@
1
+ import { ipcMain, BrowserWindow } from 'electron';
2
+ import { IPC_CHANNELS, HeartbeatConfig } from '../../shared/types';
3
+ import { AgentRoleRepository } from '../agents/AgentRoleRepository';
4
+ import { TaskSubscriptionRepository, SubscriptionReason } from '../agents/TaskSubscriptionRepository';
5
+ import { StandupReportService } from '../reports/StandupReportService';
6
+ import { HeartbeatService } from '../agents/HeartbeatService';
7
+ import { rateLimiter } from '../utils/rate-limiter';
8
+ import { validateInput, UUIDSchema } from '../utils/validation';
9
+
10
+ // Get main window for event broadcasting
11
+ let mainWindowGetter: (() => BrowserWindow | null) | null = null;
12
+
13
+ function getMainWindow(): BrowserWindow | null {
14
+ return mainWindowGetter?.() ?? null;
15
+ }
16
+
17
+ /**
18
+ * Rate limit check helper
19
+ */
20
+ function checkRateLimit(channel: string): void {
21
+ if (!rateLimiter.check(channel)) {
22
+ throw new Error(`Rate limit exceeded for ${channel}`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Dependencies for Mission Control handlers
28
+ */
29
+ export interface MissionControlDeps {
30
+ agentRoleRepo: AgentRoleRepository;
31
+ taskSubscriptionRepo: TaskSubscriptionRepository;
32
+ standupService: StandupReportService;
33
+ heartbeatService: HeartbeatService;
34
+ getMainWindow: () => BrowserWindow | null;
35
+ }
36
+
37
+ /**
38
+ * Set up Mission Control IPC handlers
39
+ */
40
+ export function setupMissionControlHandlers(deps: MissionControlDeps): void {
41
+ mainWindowGetter = deps.getMainWindow;
42
+
43
+ const {
44
+ agentRoleRepo,
45
+ taskSubscriptionRepo,
46
+ standupService,
47
+ heartbeatService,
48
+ } = deps;
49
+
50
+ // ============ Heartbeat Handlers ============
51
+
52
+ ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_CONFIG, async (_, agentRoleId: string) => {
53
+ const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
54
+ const role = agentRoleRepo.findById(validated);
55
+ if (!role) {
56
+ throw new Error('Agent role not found');
57
+ }
58
+ return {
59
+ heartbeatEnabled: role.heartbeatEnabled,
60
+ heartbeatIntervalMinutes: role.heartbeatIntervalMinutes,
61
+ heartbeatStaggerOffset: role.heartbeatStaggerOffset,
62
+ lastHeartbeatAt: role.lastHeartbeatAt,
63
+ heartbeatStatus: role.heartbeatStatus,
64
+ };
65
+ });
66
+
67
+ ipcMain.handle(IPC_CHANNELS.HEARTBEAT_UPDATE_CONFIG, async (_, agentRoleId: string, config: HeartbeatConfig) => {
68
+ checkRateLimit(IPC_CHANNELS.HEARTBEAT_UPDATE_CONFIG);
69
+ const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
70
+ const result = agentRoleRepo.updateHeartbeatConfig(validated, config);
71
+ if (result) {
72
+ heartbeatService.updateAgentConfig(validated, config);
73
+ getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, {
74
+ type: 'config_updated',
75
+ agentRoleId: validated,
76
+ config,
77
+ });
78
+ }
79
+ return result;
80
+ });
81
+
82
+ ipcMain.handle(IPC_CHANNELS.HEARTBEAT_TRIGGER, async (_, agentRoleId: string) => {
83
+ checkRateLimit(IPC_CHANNELS.HEARTBEAT_TRIGGER);
84
+ const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
85
+ const result = await heartbeatService.triggerHeartbeat(validated);
86
+ getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, {
87
+ type: 'triggered',
88
+ agentRoleId: validated,
89
+ result,
90
+ });
91
+ return result;
92
+ });
93
+
94
+ ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_STATUS, async (_, agentRoleId: string) => {
95
+ const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
96
+ return heartbeatService.getStatus(validated);
97
+ });
98
+
99
+ ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_ALL_STATUS, async () => {
100
+ return heartbeatService.getAllStatus();
101
+ });
102
+
103
+ // Forward heartbeat events to renderer
104
+ heartbeatService.on('heartbeat', (event) => {
105
+ getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, event);
106
+ });
107
+
108
+ // ============ Task Subscription Handlers ============
109
+
110
+ ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_LIST, async (_, taskId: string) => {
111
+ const validated = validateInput(UUIDSchema, taskId, 'task ID');
112
+ return taskSubscriptionRepo.getSubscribers(validated);
113
+ });
114
+
115
+ ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_ADD, async (_, taskId: string, agentRoleId: string, reason: SubscriptionReason) => {
116
+ checkRateLimit(IPC_CHANNELS.SUBSCRIPTION_ADD);
117
+ const validatedTaskId = validateInput(UUIDSchema, taskId, 'task ID');
118
+ const validatedAgentRoleId = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
119
+ const subscription = taskSubscriptionRepo.subscribe(validatedTaskId, validatedAgentRoleId, reason);
120
+ getMainWindow()?.webContents.send(IPC_CHANNELS.SUBSCRIPTION_EVENT, {
121
+ type: 'added',
122
+ subscription,
123
+ });
124
+ return subscription;
125
+ });
126
+
127
+ ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_REMOVE, async (_, taskId: string, agentRoleId: string) => {
128
+ checkRateLimit(IPC_CHANNELS.SUBSCRIPTION_REMOVE);
129
+ const validatedTaskId = validateInput(UUIDSchema, taskId, 'task ID');
130
+ const validatedAgentRoleId = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
131
+ const success = taskSubscriptionRepo.unsubscribe(validatedTaskId, validatedAgentRoleId);
132
+ if (success) {
133
+ getMainWindow()?.webContents.send(IPC_CHANNELS.SUBSCRIPTION_EVENT, {
134
+ type: 'removed',
135
+ taskId: validatedTaskId,
136
+ agentRoleId: validatedAgentRoleId,
137
+ });
138
+ }
139
+ return { success };
140
+ });
141
+
142
+ ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_GET_SUBSCRIBERS, async (_, taskId: string) => {
143
+ const validated = validateInput(UUIDSchema, taskId, 'task ID');
144
+ return taskSubscriptionRepo.getSubscribers(validated);
145
+ });
146
+
147
+ ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_GET_FOR_AGENT, async (_, agentRoleId: string) => {
148
+ const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
149
+ return taskSubscriptionRepo.getSubscriptionsForAgent(validated);
150
+ });
151
+
152
+ // ============ Standup Report Handlers ============
153
+
154
+ ipcMain.handle(IPC_CHANNELS.STANDUP_GENERATE, async (_, workspaceId: string) => {
155
+ checkRateLimit(IPC_CHANNELS.STANDUP_GENERATE);
156
+ const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
157
+ return standupService.generateReport(validated);
158
+ });
159
+
160
+ ipcMain.handle(IPC_CHANNELS.STANDUP_GET_LATEST, async (_, workspaceId: string) => {
161
+ const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
162
+ return standupService.getLatest(validated);
163
+ });
164
+
165
+ ipcMain.handle(IPC_CHANNELS.STANDUP_LIST, async (_, workspaceId: string, limit?: number) => {
166
+ const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
167
+ return standupService.list({ workspaceId: validated, limit });
168
+ });
169
+
170
+ ipcMain.handle(IPC_CHANNELS.STANDUP_DELIVER, async (_, reportId: string, channelType: string, channelId: string) => {
171
+ checkRateLimit(IPC_CHANNELS.STANDUP_DELIVER);
172
+ const validatedReportId = validateInput(UUIDSchema, reportId, 'report ID');
173
+ const report = standupService.findById(validatedReportId);
174
+ if (!report) {
175
+ throw new Error('Standup report not found');
176
+ }
177
+ await standupService.deliverReport(report, { channelType, channelId });
178
+ return { success: true };
179
+ });
180
+
181
+ console.log('[MissionControl] Handlers initialized');
182
+ }
@@ -0,0 +1,496 @@
1
+ import path from 'path';
2
+ import { pathToFileURL } from 'url';
3
+ import { app, BrowserWindow, ipcMain, dialog, session, shell, Notification } from 'electron';
4
+ import { DatabaseManager } from './database/schema';
5
+ import { SecureSettingsRepository } from './database/SecureSettingsRepository';
6
+ import { setupIpcHandlers, getNotificationService } from './ipc/handlers';
7
+ import { setupMissionControlHandlers } from './ipc/mission-control-handlers';
8
+ import { TaskSubscriptionRepository } from './agents/TaskSubscriptionRepository';
9
+ import { StandupReportService } from './reports/StandupReportService';
10
+ import { HeartbeatService, HeartbeatServiceDeps } from './agents/HeartbeatService';
11
+ import { AgentRoleRepository } from './agents/AgentRoleRepository';
12
+ import { MentionRepository } from './agents/MentionRepository';
13
+ import { ActivityRepository } from './activity/ActivityRepository';
14
+ import { WorkingStateRepository } from './agents/WorkingStateRepository';
15
+ import { AgentDaemon } from './agent/daemon';
16
+ import { TaskRepository, WorkspaceRepository } from './database/repositories';
17
+ import { LLMProviderFactory } from './agent/llm';
18
+ import { SearchProviderFactory } from './agent/search';
19
+ import { ChannelGateway } from './gateway';
20
+ import { updateManager } from './updater';
21
+ import { migrateEnvToSettings } from './utils/env-migration';
22
+ import { GuardrailManager } from './guardrails/guardrail-manager';
23
+ import { AppearanceManager } from './settings/appearance-manager';
24
+ import { PersonalityManager } from './settings/personality-manager';
25
+ import { MCPClientManager } from './mcp/client/MCPClientManager';
26
+ import { trayManager } from './tray';
27
+ import { CronService, setCronService, getCronStorePath } from './cron';
28
+ import { MemoryService } from './memory/MemoryService';
29
+ import { setupControlPlaneHandlers, shutdownControlPlane } from './control-plane';
30
+ // Live Canvas feature
31
+ import { registerCanvasScheme, registerCanvasProtocol, CanvasManager } from './canvas';
32
+ import { setupCanvasHandlers, cleanupCanvasHandlers } from './ipc/canvas-handlers';
33
+
34
+ let mainWindow: BrowserWindow | null = null;
35
+ let dbManager: DatabaseManager;
36
+ let agentDaemon: AgentDaemon;
37
+ let channelGateway: ChannelGateway;
38
+ let cronService: CronService | null = null;
39
+
40
+ // Suppress GPU-related Chromium errors that occur with transparent windows and vibrancy
41
+ // These are cosmetic errors that don't affect functionality
42
+ app.commandLine.appendSwitch('disable-gpu-driver-bug-workarounds');
43
+ app.commandLine.appendSwitch('enable-gpu-rasterization');
44
+ app.commandLine.appendSwitch('ignore-gpu-blocklist');
45
+
46
+ // Register canvas:// protocol scheme (must be called before app.ready)
47
+ registerCanvasScheme();
48
+
49
+ function createWindow() {
50
+ mainWindow = new BrowserWindow({
51
+ width: 1600,
52
+ height: 1000,
53
+ minWidth: 1200,
54
+ minHeight: 800,
55
+ center: true,
56
+ titleBarStyle: 'hiddenInset',
57
+ vibrancy: 'under-window',
58
+ visualEffectState: 'active',
59
+ transparent: true,
60
+ backgroundColor: '#00000000',
61
+ webPreferences: {
62
+ nodeIntegration: false,
63
+ contextIsolation: true,
64
+ webviewTag: true, // Enable webview for canvas interactive mode
65
+ preload: path.join(__dirname, 'preload.js'),
66
+ },
67
+ });
68
+
69
+ // Load the app
70
+ if (process.env.NODE_ENV === 'development') {
71
+ mainWindow.loadURL('http://localhost:5173');
72
+ mainWindow.webContents.openDevTools();
73
+ } else {
74
+ mainWindow.loadFile(path.join(__dirname, '../../renderer/index.html'));
75
+ }
76
+
77
+ mainWindow.on('closed', () => {
78
+ mainWindow = null;
79
+ });
80
+
81
+ // Open external links in the system browser instead of inside the app
82
+ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
83
+ // Open all new window requests in external browser
84
+ shell.openExternal(url);
85
+ return { action: 'deny' };
86
+ });
87
+
88
+ mainWindow.webContents.on('will-navigate', (event, url) => {
89
+ // Allow navigation to the app itself (dev server or file://), block external URLs
90
+ const appUrl = process.env.NODE_ENV === 'development'
91
+ ? 'http://localhost:5173'
92
+ : `file://${path.join(__dirname, '../../renderer')}`;
93
+
94
+ if (!url.startsWith(appUrl)) {
95
+ event.preventDefault();
96
+ shell.openExternal(url);
97
+ }
98
+ });
99
+ }
100
+
101
+ app.whenReady().then(async () => {
102
+ // Set up Content Security Policy for production builds
103
+ if (process.env.NODE_ENV !== 'development') {
104
+ const appRoot = pathToFileURL(path.join(__dirname, '../../renderer')).toString();
105
+ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
106
+ if (!details.url.startsWith(appRoot)) {
107
+ callback({ responseHeaders: details.responseHeaders });
108
+ return;
109
+ }
110
+ callback({
111
+ responseHeaders: {
112
+ ...details.responseHeaders,
113
+ 'Content-Security-Policy': [
114
+ "default-src 'self'; " +
115
+ "script-src 'self'; " +
116
+ "style-src 'self' 'unsafe-inline'; " + // Allow inline styles for React
117
+ "img-src 'self' data: https:; " + // Allow images from self, data URIs, and HTTPS
118
+ "font-src 'self' data:; " + // Allow fonts from self and data URIs
119
+ "connect-src 'self' https:; " + // Allow API calls to HTTPS endpoints
120
+ "frame-ancestors 'none'; " + // Prevent embedding in iframes
121
+ "form-action 'self';" // Restrict form submissions
122
+ ],
123
+ },
124
+ });
125
+ });
126
+ }
127
+
128
+ // Initialize database first - required for SecureSettingsRepository
129
+ dbManager = new DatabaseManager();
130
+
131
+ // Initialize secure settings repository for encrypted settings storage
132
+ // This MUST be done before provider factories so they can migrate legacy settings
133
+ new SecureSettingsRepository(dbManager.getDatabase());
134
+ console.log('[Main] SecureSettingsRepository initialized');
135
+
136
+ // Initialize provider factories (loads settings from disk, migrates legacy files)
137
+ LLMProviderFactory.initialize();
138
+ SearchProviderFactory.initialize();
139
+ GuardrailManager.initialize();
140
+ AppearanceManager.initialize();
141
+ PersonalityManager.initialize();
142
+
143
+ // Migrate .env configuration to Settings (one-time upgrade path)
144
+ const migrationResult = await migrateEnvToSettings();
145
+
146
+ // Initialize agent daemon
147
+ agentDaemon = new AgentDaemon(dbManager);
148
+ await agentDaemon.initialize();
149
+
150
+ // Initialize Memory Service for cross-session context
151
+ try {
152
+ MemoryService.initialize(dbManager);
153
+ console.log('[Main] Memory Service initialized');
154
+ } catch (error) {
155
+ console.error('[Main] Failed to initialize Memory Service:', error);
156
+ // Don't fail app startup if memory init fails
157
+ }
158
+
159
+ // Initialize MCP Client Manager - auto-connects enabled servers on startup
160
+ try {
161
+ const mcpClientManager = MCPClientManager.getInstance();
162
+ await mcpClientManager.initialize();
163
+ console.log('[Main] MCP Client Manager initialized');
164
+ } catch (error) {
165
+ console.error('[Main] Failed to initialize MCP Client Manager:', error);
166
+ // Don't fail app startup if MCP init fails
167
+ }
168
+
169
+ // Initialize Cron Service for scheduled task execution
170
+ try {
171
+ cronService = new CronService({
172
+ cronEnabled: true,
173
+ storePath: getCronStorePath(),
174
+ maxConcurrentRuns: 3, // Allow up to 3 concurrent jobs
175
+ // Webhook configuration (disabled by default, can be enabled in settings)
176
+ webhook: {
177
+ enabled: false, // Set to true to enable webhook triggers
178
+ port: 9876,
179
+ host: '127.0.0.1',
180
+ // secret: 'your-secret-here', // Uncomment and set for secure webhooks
181
+ },
182
+ createTask: async (params) => {
183
+ const task = await agentDaemon.createTask({
184
+ title: params.title,
185
+ prompt: params.prompt,
186
+ workspaceId: params.workspaceId,
187
+ });
188
+ return { id: task.id };
189
+ },
190
+ // Channel delivery handler - sends job results to messaging platforms
191
+ deliverToChannel: async (params) => {
192
+ if (!channelGateway) {
193
+ console.warn('[Cron] Cannot deliver to channel - gateway not initialized');
194
+ return;
195
+ }
196
+
197
+ // Build the message
198
+ const statusEmoji = params.status === 'ok' ? '✅' : params.status === 'error' ? '❌' : '⏱️';
199
+ let message = `${statusEmoji} **Scheduled Task: ${params.jobName}**\n\n`;
200
+
201
+ if (params.status === 'ok') {
202
+ message += `Task completed successfully.\n`;
203
+ } else if (params.status === 'error') {
204
+ message += `Task failed.\n`;
205
+ } else {
206
+ message += `Task timed out.\n`;
207
+ }
208
+
209
+ if (params.error) {
210
+ message += `\n**Error:** ${params.error}\n`;
211
+ }
212
+
213
+ if (params.taskId && !params.summaryOnly) {
214
+ message += `\n_Task ID: ${params.taskId}_`;
215
+ }
216
+
217
+ // Find the channel to verify it exists
218
+ const channels = channelGateway.getChannels();
219
+ const channel = channels.find(
220
+ (ch) => ch.type === params.channelType && ch.id === params.channelId
221
+ );
222
+
223
+ if (!channel) {
224
+ console.warn(`[Cron] Channel not found: ${params.channelType}:${params.channelId}`);
225
+ return;
226
+ }
227
+
228
+ try {
229
+ // Send the message via the gateway
230
+ await channelGateway.sendMessage(
231
+ params.channelType as any,
232
+ params.channelId,
233
+ message,
234
+ { parseMode: 'markdown' }
235
+ );
236
+ console.log(`[Cron] Delivered to ${params.channelType}:${params.channelId}`);
237
+ } catch (err) {
238
+ console.error(`[Cron] Failed to deliver to ${params.channelType}:${params.channelId}:`, err);
239
+ }
240
+ },
241
+ onEvent: async (evt) => {
242
+ // Forward cron events to renderer
243
+ if (mainWindow?.webContents) {
244
+ mainWindow.webContents.send('cron:event', evt);
245
+ }
246
+ console.log('[Cron] Event:', evt.action, evt.jobId);
247
+
248
+ // Show desktop notification when scheduled task finishes
249
+ if (evt.action === 'finished') {
250
+ const statusEmoji = evt.status === 'ok' ? '✅' : evt.status === 'error' ? '❌' : '⏱️';
251
+ const statusText = evt.status === 'ok' ? 'completed' : evt.status === 'error' ? 'failed' : 'timed out';
252
+
253
+ // Add in-app notification
254
+ const notificationService = getNotificationService();
255
+ if (notificationService) {
256
+ try {
257
+ // Get job name for the notification
258
+ const job = cronService ? await cronService.get(evt.jobId) : null;
259
+ const jobName = job?.name || 'Scheduled Task';
260
+ await notificationService.add({
261
+ type: evt.status === 'ok' ? 'task_completed' : 'task_failed',
262
+ title: `${statusEmoji} ${jobName} ${statusText}`,
263
+ message: evt.error || (evt.status === 'ok' ? 'Task completed successfully.' : 'Task did not complete.'),
264
+ taskId: evt.taskId,
265
+ cronJobId: evt.jobId,
266
+ workspaceId: job?.workspaceId,
267
+ });
268
+ } catch (err) {
269
+ console.error('[Cron] Failed to add in-app notification:', err);
270
+ }
271
+ }
272
+
273
+ // Show macOS notification
274
+ if (Notification.isSupported()) {
275
+ const notification = new Notification({
276
+ title: `${statusEmoji} Scheduled Task ${statusText}`,
277
+ body: evt.error ? `Error: ${evt.error}` : 'Click to view results in the app.',
278
+ silent: false,
279
+ });
280
+
281
+ notification.on('click', () => {
282
+ // Bring the main window to focus
283
+ if (mainWindow) {
284
+ if (mainWindow.isMinimized()) mainWindow.restore();
285
+ mainWindow.focus();
286
+ }
287
+ });
288
+
289
+ notification.show();
290
+ }
291
+ }
292
+ },
293
+ log: {
294
+ debug: (msg, data) => console.log(`[Cron] ${msg}`, data ?? ''),
295
+ info: (msg, data) => console.log(`[Cron] ${msg}`, data ?? ''),
296
+ warn: (msg, data) => console.warn(`[Cron] ${msg}`, data ?? ''),
297
+ error: (msg, data) => console.error(`[Cron] ${msg}`, data ?? ''),
298
+ },
299
+ });
300
+ setCronService(cronService);
301
+ await cronService.start();
302
+ console.log('[Main] Cron Service initialized');
303
+ } catch (error) {
304
+ console.error('[Main] Failed to initialize Cron Service:', error);
305
+ // Don't fail app startup if cron init fails
306
+ }
307
+
308
+ // Initialize channel gateway with agent daemon for task processing
309
+ channelGateway = new ChannelGateway(dbManager.getDatabase(), {
310
+ autoConnect: true, // Auto-connect enabled channels on startup
311
+ agentDaemon,
312
+ });
313
+
314
+ // Setup IPC handlers
315
+ await setupIpcHandlers(dbManager, agentDaemon, channelGateway);
316
+
317
+ // Initialize Mission Control services
318
+ try {
319
+ const db = dbManager.getDatabase();
320
+ const agentRoleRepo = new AgentRoleRepository(db);
321
+
322
+ // Sync any new default agents to existing workspaces
323
+ const addedAgents = agentRoleRepo.syncNewDefaults();
324
+ if (addedAgents.length > 0) {
325
+ console.log(`[Main] Added ${addedAgents.length} new default agent(s)`);
326
+ }
327
+
328
+ const mentionRepo = new MentionRepository(db);
329
+ const activityRepo = new ActivityRepository(db);
330
+ const workingStateRepo = new WorkingStateRepository(db);
331
+ const taskSubscriptionRepo = new TaskSubscriptionRepository(db);
332
+ const standupService = new StandupReportService(db);
333
+
334
+ // Create repositories for heartbeat service
335
+ const taskRepo = new TaskRepository(db);
336
+ const workspaceRepo = new WorkspaceRepository(db);
337
+
338
+ // Initialize HeartbeatService with dependencies
339
+ const heartbeatDeps: HeartbeatServiceDeps = {
340
+ agentRoleRepo,
341
+ mentionRepo,
342
+ activityRepo,
343
+ workingStateRepo,
344
+ createTask: async (workspaceId, prompt, title, _agentRoleId) => {
345
+ // Create task via agentDaemon (doesn't support assignedAgentRoleId directly)
346
+ const task = await agentDaemon.createTask({
347
+ title,
348
+ prompt,
349
+ workspaceId,
350
+ });
351
+ // Note: Task assignment would need to be done separately if needed
352
+ return task;
353
+ },
354
+ getTasksForAgent: (agentRoleId, workspaceId) => {
355
+ // Get assigned tasks for the agent using the task repository
356
+ const tasks = workspaceId
357
+ ? taskRepo.findByWorkspace(workspaceId)
358
+ : taskRepo.findByStatus(['pending', 'running']);
359
+ return tasks.filter((t: { assignedAgentRoleId?: string }) => t.assignedAgentRoleId === agentRoleId);
360
+ },
361
+ getDefaultWorkspaceId: () => {
362
+ // Get the first workspace as default
363
+ const workspaces = workspaceRepo.findAll();
364
+ return workspaces[0]?.id;
365
+ },
366
+ };
367
+
368
+ const heartbeatService = new HeartbeatService(heartbeatDeps);
369
+ await heartbeatService.start();
370
+
371
+ // Setup Mission Control IPC handlers
372
+ setupMissionControlHandlers({
373
+ agentRoleRepo,
374
+ taskSubscriptionRepo,
375
+ standupService,
376
+ heartbeatService,
377
+ getMainWindow: () => mainWindow,
378
+ });
379
+
380
+ console.log('[Main] Mission Control services initialized');
381
+ } catch (error) {
382
+ console.error('[Main] Failed to initialize Mission Control:', error);
383
+ // Don't fail app startup if Mission Control init fails
384
+ }
385
+
386
+ // Register canvas:// protocol handler (must be after app.ready)
387
+ registerCanvasProtocol();
388
+
389
+ // Create window
390
+ createWindow();
391
+
392
+ // Initialize gateway with main window reference
393
+ if (mainWindow) {
394
+ await channelGateway.initialize(mainWindow);
395
+ // Initialize update manager with main window reference
396
+ updateManager.setMainWindow(mainWindow);
397
+
398
+ // Initialize Live Canvas handlers and set main window reference
399
+ setupCanvasHandlers(mainWindow, agentDaemon);
400
+ CanvasManager.getInstance().setMainWindow(mainWindow);
401
+
402
+ // Restore persisted canvas sessions from disk
403
+ await CanvasManager.getInstance().restoreSessions();
404
+
405
+ // Initialize control plane (WebSocket gateway)
406
+ setupControlPlaneHandlers(mainWindow);
407
+
408
+ // Initialize menu bar tray (macOS native companion)
409
+ if (process.platform === 'darwin') {
410
+ await trayManager.initialize(mainWindow, channelGateway, dbManager, agentDaemon);
411
+ }
412
+
413
+ // Show migration notification after window is ready
414
+ if (migrationResult.migrated && migrationResult.migratedKeys.length > 0) {
415
+ mainWindow.webContents.once('did-finish-load', () => {
416
+ dialog.showMessageBox(mainWindow!, {
417
+ type: 'info',
418
+ title: 'Configuration Migrated',
419
+ message: 'Your API credentials have been migrated',
420
+ detail: `The following credentials were migrated from your .env file to secure Settings storage:\n\n` +
421
+ `${migrationResult.migratedKeys.map(k => `• ${k}`).join('\n')}\n\n` +
422
+ `Your .env file has been renamed to .env.migrated. ` +
423
+ `You can safely delete it after verifying your settings work correctly.\n\n` +
424
+ `Open Settings (gear icon) to review your configuration.`,
425
+ buttons: ['OK'],
426
+ });
427
+ });
428
+ }
429
+ }
430
+
431
+ app.on('activate', () => {
432
+ if (BrowserWindow.getAllWindows().length === 0) {
433
+ createWindow();
434
+ }
435
+ });
436
+ });
437
+
438
+ app.on('window-all-closed', () => {
439
+ if (process.platform !== 'darwin') {
440
+ app.quit();
441
+ }
442
+ });
443
+
444
+ app.on('before-quit', async () => {
445
+ // Destroy tray
446
+ trayManager.destroy();
447
+
448
+ // Stop cron service (async to properly shutdown webhook server)
449
+ if (cronService) {
450
+ await cronService.stop();
451
+ setCronService(null);
452
+ }
453
+
454
+ // Cleanup canvas manager (close all windows and watchers)
455
+ await cleanupCanvasHandlers();
456
+
457
+ // Shutdown control plane (WebSocket gateway and Tailscale)
458
+ await shutdownControlPlane();
459
+
460
+ if (channelGateway) {
461
+ await channelGateway.shutdown();
462
+ }
463
+ // Disconnect all MCP servers
464
+ try {
465
+ const mcpClientManager = MCPClientManager.getInstance();
466
+ await mcpClientManager.shutdown();
467
+ } catch (error) {
468
+ console.error('[Main] Failed to shutdown MCP servers:', error);
469
+ }
470
+ // Shutdown Memory Service
471
+ try {
472
+ MemoryService.shutdown();
473
+ } catch (error) {
474
+ console.error('[Main] Failed to shutdown Memory Service:', error);
475
+ }
476
+
477
+ if (dbManager) {
478
+ dbManager.close();
479
+ }
480
+ if (agentDaemon) {
481
+ agentDaemon.shutdown();
482
+ }
483
+ });
484
+
485
+ // Handle folder selection
486
+ ipcMain.handle('dialog:selectFolder', async () => {
487
+ const result = await dialog.showOpenDialog({
488
+ properties: ['openDirectory'],
489
+ title: 'Select Workspace Folder',
490
+ });
491
+
492
+ if (!result.canceled && result.filePaths.length > 0) {
493
+ return result.filePaths[0];
494
+ }
495
+ return null;
496
+ });