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,523 @@
1
+ /**
2
+ * Memory Service
3
+ *
4
+ * Core service for the persistent memory system.
5
+ * Handles capture, compression, search, and context injection.
6
+ */
7
+
8
+ import { EventEmitter } from 'events';
9
+ import type { DatabaseManager } from '../database/schema';
10
+ import {
11
+ MemoryRepository,
12
+ MemorySummaryRepository,
13
+ MemorySettingsRepository,
14
+ Memory,
15
+ MemorySettings,
16
+ MemorySearchResult,
17
+ MemoryTimelineEntry,
18
+ MemoryType,
19
+ MemoryStats,
20
+ } from '../database/repositories';
21
+ import { LLMProviderFactory } from '../agent/llm';
22
+ import { estimateTokens } from '../agent/context-manager';
23
+ import { InputSanitizer } from '../agent/security';
24
+
25
+ // Privacy patterns to exclude - matches common sensitive data patterns
26
+ const SENSITIVE_PATTERNS = [
27
+ /api[_-]?key/i,
28
+ /secret/i,
29
+ /password/i,
30
+ /passwd/i,
31
+ /token/i,
32
+ /credential/i,
33
+ /auth/i,
34
+ /bearer\s+[a-zA-Z0-9\-_]+/i,
35
+ /ssh[_-]?key/i,
36
+ /private[_-]?key/i,
37
+ /\.env/i,
38
+ /aws[_-]?access/i,
39
+ /aws[_-]?secret/i,
40
+ /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/i,
41
+ /ghp_[a-zA-Z0-9]+/i, // GitHub personal access token
42
+ /gho_[a-zA-Z0-9]+/i, // GitHub OAuth token
43
+ /sk-[a-zA-Z0-9]+/i, // OpenAI API key format
44
+ /xox[baprs]-[a-zA-Z0-9-]+/i, // Slack tokens
45
+ ];
46
+
47
+ // Events for reactive updates
48
+ const memoryEvents = new EventEmitter();
49
+
50
+ // Minimum tokens before compression is worthwhile
51
+ const MIN_TOKENS_FOR_COMPRESSION = 100;
52
+
53
+ // Compression batch size
54
+ const COMPRESSION_BATCH_SIZE = 10;
55
+
56
+ // Cleanup interval (1 hour)
57
+ const CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
58
+
59
+ // Compression delay between items (avoid rate limits)
60
+ const COMPRESSION_DELAY_MS = 200;
61
+
62
+ export class MemoryService {
63
+ private static memoryRepo: MemoryRepository;
64
+ private static summaryRepo: MemorySummaryRepository;
65
+ private static settingsRepo: MemorySettingsRepository;
66
+ private static initialized = false;
67
+ private static compressionQueue: string[] = [];
68
+ private static compressionInProgress = false;
69
+ private static cleanupIntervalHandle?: ReturnType<typeof setInterval>;
70
+
71
+ /**
72
+ * Initialize the memory service
73
+ */
74
+ static initialize(dbManager: DatabaseManager): void {
75
+ if (this.initialized) return;
76
+
77
+ const db = dbManager.getDatabase();
78
+ this.memoryRepo = new MemoryRepository(db);
79
+ this.summaryRepo = new MemorySummaryRepository(db);
80
+ this.settingsRepo = new MemorySettingsRepository(db);
81
+ this.initialized = true;
82
+
83
+ // Start periodic cleanup
84
+ this.cleanupIntervalHandle = setInterval(() => this.runCleanup(), CLEANUP_INTERVAL_MS);
85
+
86
+ console.log('[MemoryService] Initialized');
87
+ }
88
+
89
+ /**
90
+ * Subscribe to memory events
91
+ */
92
+ static onMemoryChanged(
93
+ callback: (data: { type: string; workspaceId: string }) => void
94
+ ): () => void {
95
+ memoryEvents.on('memoryChanged', callback);
96
+ return () => memoryEvents.off('memoryChanged', callback);
97
+ }
98
+
99
+ /**
100
+ * Capture an observation from task execution
101
+ */
102
+ static async capture(
103
+ workspaceId: string,
104
+ taskId: string | undefined,
105
+ type: MemoryType,
106
+ content: string,
107
+ isPrivate = false
108
+ ): Promise<Memory | null> {
109
+ this.ensureInitialized();
110
+
111
+ // Check settings
112
+ const settings = this.settingsRepo.getOrCreate(workspaceId);
113
+ if (!settings.enabled || !settings.autoCapture) {
114
+ return null;
115
+ }
116
+
117
+ // Check privacy mode
118
+ if (settings.privacyMode === 'disabled') {
119
+ return null;
120
+ }
121
+
122
+ // Check excluded patterns
123
+ if (this.shouldExclude(content, settings)) {
124
+ return null;
125
+ }
126
+
127
+ // Check for sensitive content
128
+ const containsSensitive = this.containsSensitiveData(content);
129
+ const finalIsPrivate = isPrivate || containsSensitive || settings.privacyMode === 'strict';
130
+
131
+ // Estimate tokens
132
+ const tokens = estimateTokens(content);
133
+
134
+ // Truncate very long content
135
+ const truncatedContent =
136
+ content.length > 10000 ? content.slice(0, 10000) + '\n[... truncated]' : content;
137
+
138
+ // Create memory
139
+ const memory = this.memoryRepo.create({
140
+ workspaceId,
141
+ taskId,
142
+ type,
143
+ content: truncatedContent,
144
+ tokens,
145
+ isCompressed: false,
146
+ isPrivate: finalIsPrivate,
147
+ });
148
+
149
+ // Queue for compression if enabled and large enough
150
+ if (settings.compressionEnabled && tokens > MIN_TOKENS_FOR_COMPRESSION && !finalIsPrivate) {
151
+ this.compressionQueue.push(memory.id);
152
+ this.processCompressionQueue();
153
+ }
154
+
155
+ // Emit event
156
+ memoryEvents.emit('memoryChanged', { type: 'created', workspaceId });
157
+
158
+ return memory;
159
+ }
160
+
161
+ /**
162
+ * Search memories - Layer 1 of progressive retrieval
163
+ * Returns IDs + brief snippets (~50 tokens each)
164
+ */
165
+ static search(workspaceId: string, query: string, limit = 20): MemorySearchResult[] {
166
+ this.ensureInitialized();
167
+ return this.memoryRepo.search(workspaceId, query, limit);
168
+ }
169
+
170
+ /**
171
+ * Get timeline context - Layer 2 of progressive retrieval
172
+ * Returns surrounding memories for context
173
+ */
174
+ static getTimelineContext(memoryId: string, windowSize = 5): MemoryTimelineEntry[] {
175
+ this.ensureInitialized();
176
+ return this.memoryRepo.getTimelineContext(memoryId, windowSize);
177
+ }
178
+
179
+ /**
180
+ * Get full details - Layer 3 of progressive retrieval
181
+ * Only called for specific memories when needed
182
+ */
183
+ static getFullDetails(ids: string[]): Memory[] {
184
+ this.ensureInitialized();
185
+ return this.memoryRepo.getFullDetails(ids);
186
+ }
187
+
188
+ /**
189
+ * Get memories for a specific task
190
+ */
191
+ static getByTask(taskId: string): Memory[] {
192
+ this.ensureInitialized();
193
+ return this.memoryRepo.findByTask(taskId);
194
+ }
195
+
196
+ /**
197
+ * Get recent memories for a workspace
198
+ */
199
+ static getRecent(workspaceId: string, limit = 20): Memory[] {
200
+ this.ensureInitialized();
201
+ return this.memoryRepo.getRecentForWorkspace(workspaceId, limit);
202
+ }
203
+
204
+ /**
205
+ * Get context for injection at task start
206
+ * Returns a formatted string suitable for system prompt
207
+ */
208
+ static getContextForInjection(workspaceId: string, taskPrompt: string): string {
209
+ this.ensureInitialized();
210
+
211
+ const settings = this.settingsRepo.getOrCreate(workspaceId);
212
+ if (!settings.enabled) {
213
+ return '';
214
+ }
215
+
216
+ // Get recent memories (summaries preferred)
217
+ const recentMemories = this.memoryRepo.getRecentForWorkspace(workspaceId, 5);
218
+
219
+ // Search for relevant memories based on task prompt
220
+ let relevantMemories: MemorySearchResult[] = [];
221
+ if (taskPrompt && taskPrompt.length > 10) {
222
+ try {
223
+ // Extract key terms for search
224
+ const searchTerms = this.extractSearchTerms(taskPrompt);
225
+ if (searchTerms) {
226
+ relevantMemories = this.memoryRepo.search(workspaceId, searchTerms, 5);
227
+ // Filter out memories that are already in recent
228
+ const recentIds = new Set(recentMemories.map((m) => m.id));
229
+ relevantMemories = relevantMemories.filter((m) => !recentIds.has(m.id));
230
+ }
231
+ } catch {
232
+ // Search failed, continue without relevant memories
233
+ }
234
+ }
235
+
236
+ if (recentMemories.length === 0 && relevantMemories.length === 0) {
237
+ return '';
238
+ }
239
+
240
+ const parts: string[] = ['<memory_context>'];
241
+ parts.push('The following memories from previous sessions may be relevant:');
242
+
243
+ // Add recent memories (summaries only for token efficiency)
244
+ if (recentMemories.length > 0) {
245
+ parts.push('\n## Recent Activity');
246
+ for (const memory of recentMemories) {
247
+ const rawText = memory.summary || this.truncate(memory.content, 150);
248
+ // Sanitize memory content to prevent injection via stored memories
249
+ const text = InputSanitizer.sanitizeMemoryContent(rawText);
250
+ const date = new Date(memory.createdAt).toLocaleDateString();
251
+ parts.push(`- [${memory.type}] (${date}) ${text}`);
252
+ }
253
+ }
254
+
255
+ // Add relevant memories
256
+ if (relevantMemories.length > 0) {
257
+ parts.push('\n## Relevant to Current Task');
258
+ for (const result of relevantMemories) {
259
+ const date = new Date(result.createdAt).toLocaleDateString();
260
+ // Sanitize memory content to prevent injection via stored memories
261
+ const sanitizedSnippet = InputSanitizer.sanitizeMemoryContent(result.snippet);
262
+ parts.push(`- [${result.type}] (${date}) ${sanitizedSnippet}`);
263
+ }
264
+ }
265
+
266
+ parts.push('</memory_context>');
267
+
268
+ return parts.join('\n');
269
+ }
270
+
271
+ /**
272
+ * Get or create settings for a workspace
273
+ */
274
+ static getSettings(workspaceId: string): MemorySettings {
275
+ this.ensureInitialized();
276
+ return this.settingsRepo.getOrCreate(workspaceId);
277
+ }
278
+
279
+ /**
280
+ * Update settings for a workspace
281
+ */
282
+ static updateSettings(
283
+ workspaceId: string,
284
+ updates: Partial<Omit<MemorySettings, 'workspaceId'>>
285
+ ): void {
286
+ this.ensureInitialized();
287
+ this.settingsRepo.update(workspaceId, updates);
288
+ memoryEvents.emit('memoryChanged', { type: 'settingsUpdated', workspaceId });
289
+ }
290
+
291
+ /**
292
+ * Get storage statistics for a workspace
293
+ */
294
+ static getStats(workspaceId: string): MemoryStats {
295
+ this.ensureInitialized();
296
+ return this.memoryRepo.getStats(workspaceId);
297
+ }
298
+
299
+ /**
300
+ * Delete all memories for a workspace
301
+ */
302
+ static clearWorkspace(workspaceId: string): void {
303
+ this.ensureInitialized();
304
+ this.memoryRepo.deleteByWorkspace(workspaceId);
305
+ this.summaryRepo.deleteByWorkspace(workspaceId);
306
+ memoryEvents.emit('memoryChanged', { type: 'cleared', workspaceId });
307
+ }
308
+
309
+ /**
310
+ * Process compression queue asynchronously
311
+ */
312
+ private static async processCompressionQueue(): Promise<void> {
313
+ if (this.compressionInProgress || this.compressionQueue.length === 0) {
314
+ return;
315
+ }
316
+
317
+ this.compressionInProgress = true;
318
+
319
+ try {
320
+ // Process in batches
321
+ const batch = this.compressionQueue.splice(0, COMPRESSION_BATCH_SIZE);
322
+
323
+ for (const memoryId of batch) {
324
+ await this.compressMemory(memoryId);
325
+ // Small delay to avoid overwhelming the LLM
326
+ await new Promise((resolve) => setTimeout(resolve, COMPRESSION_DELAY_MS));
327
+ }
328
+
329
+ // Continue if more items
330
+ if (this.compressionQueue.length > 0) {
331
+ setTimeout(() => this.processCompressionQueue(), 1000);
332
+ }
333
+ } catch (error) {
334
+ console.error('[MemoryService] Compression queue error:', error);
335
+ } finally {
336
+ this.compressionInProgress = false;
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Compress a single memory using LLM
342
+ */
343
+ private static async compressMemory(memoryId: string): Promise<void> {
344
+ const memory = this.memoryRepo.findById(memoryId);
345
+ if (!memory || memory.isCompressed || memory.summary) return;
346
+
347
+ try {
348
+ // Get LLM provider for compression
349
+ const provider = LLMProviderFactory.createProvider();
350
+ const settings = LLMProviderFactory.getSettings();
351
+ const modelId = LLMProviderFactory.getModelId(
352
+ settings.modelKey,
353
+ settings.providerType,
354
+ settings.ollama?.model,
355
+ settings.gemini?.model,
356
+ settings.openrouter?.model,
357
+ settings.openai?.model
358
+ );
359
+
360
+ const response = await provider.createMessage({
361
+ model: modelId,
362
+ maxTokens: 100,
363
+ system: 'You are a helpful assistant that summarizes text concisely.',
364
+ messages: [
365
+ {
366
+ role: 'user',
367
+ content: `Summarize this observation in 1-2 sentences (max 50 words). Focus on the key insight, decision, or action taken. Be concise and factual.
368
+
369
+ Observation:
370
+ ${memory.content}
371
+
372
+ Summary:`,
373
+ },
374
+ ],
375
+ });
376
+
377
+ // Extract summary from response
378
+ let summary = '';
379
+ for (const content of response.content) {
380
+ if (content.type === 'text') {
381
+ summary += content.text;
382
+ }
383
+ }
384
+ summary = summary.trim();
385
+
386
+ if (summary) {
387
+ const summaryTokens = estimateTokens(summary);
388
+ this.memoryRepo.update(memoryId, {
389
+ summary,
390
+ tokens: summaryTokens,
391
+ isCompressed: true,
392
+ });
393
+ }
394
+ } catch (error) {
395
+ // Log but don't fail - compression is optional enhancement
396
+ console.warn('[MemoryService] Compression failed for memory:', memoryId, error);
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Run periodic cleanup based on retention policies
402
+ */
403
+ private static async runCleanup(): Promise<void> {
404
+ if (!this.initialized) return;
405
+
406
+ try {
407
+ // Get all workspaces with memories
408
+ const workspacesWithMemories = new Set<string>();
409
+
410
+ // Find unique workspace IDs from recent memories
411
+ const recentMemories = this.memoryRepo.getUncompressed(1000);
412
+ for (const memory of recentMemories) {
413
+ workspacesWithMemories.add(memory.workspaceId);
414
+ }
415
+
416
+ // Process each workspace
417
+ for (const workspaceId of workspacesWithMemories) {
418
+ const settings = this.settingsRepo.getOrCreate(workspaceId);
419
+ const retentionMs = settings.retentionDays * 24 * 60 * 60 * 1000;
420
+ const cutoff = Date.now() - retentionMs;
421
+
422
+ const deleted = this.memoryRepo.deleteOlderThan(workspaceId, cutoff);
423
+ if (deleted > 0) {
424
+ console.log(`[MemoryService] Cleaned up ${deleted} old memories for workspace ${workspaceId}`);
425
+ }
426
+ }
427
+ } catch (error) {
428
+ console.error('[MemoryService] Cleanup failed:', error);
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Extract search terms from task prompt
434
+ */
435
+ private static extractSearchTerms(prompt: string): string {
436
+ // Remove common words and extract meaningful terms
437
+ const stopWords = new Set([
438
+ 'a', 'an', 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
439
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
440
+ 'should', 'may', 'might', 'can', 'must', 'shall', 'to', 'of', 'in',
441
+ 'for', 'on', 'with', 'at', 'by', 'from', 'up', 'about', 'into',
442
+ 'over', 'after', 'beneath', 'under', 'above', 'and', 'or', 'but',
443
+ 'if', 'then', 'else', 'when', 'where', 'why', 'how', 'all', 'each',
444
+ 'every', 'both', 'few', 'more', 'most', 'other', 'some', 'such',
445
+ 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too',
446
+ 'very', 'just', 'also', 'now', 'please', 'help', 'me', 'i', 'my',
447
+ 'want', 'need', 'like', 'make', 'create', 'add', 'update', 'fix',
448
+ ]);
449
+
450
+ const words = prompt
451
+ .toLowerCase()
452
+ .replace(/[^\w\s]/g, ' ')
453
+ .split(/\s+/)
454
+ .filter((word) => word.length > 2 && !stopWords.has(word));
455
+
456
+ // Take first 5 meaningful words for search
457
+ return words.slice(0, 5).join(' OR ');
458
+ }
459
+
460
+ /**
461
+ * Check if content should be excluded
462
+ */
463
+ private static shouldExclude(content: string, settings: MemorySettings): boolean {
464
+ if (!settings.excludedPatterns || settings.excludedPatterns.length === 0) {
465
+ return false;
466
+ }
467
+
468
+ for (const pattern of settings.excludedPatterns) {
469
+ try {
470
+ const regex = new RegExp(pattern, 'i');
471
+ if (regex.test(content)) {
472
+ return true;
473
+ }
474
+ } catch {
475
+ // Invalid regex pattern, skip
476
+ }
477
+ }
478
+
479
+ return false;
480
+ }
481
+
482
+ /**
483
+ * Check if content contains sensitive data
484
+ */
485
+ private static containsSensitiveData(content: string): boolean {
486
+ for (const pattern of SENSITIVE_PATTERNS) {
487
+ if (pattern.test(content)) {
488
+ return true;
489
+ }
490
+ }
491
+ return false;
492
+ }
493
+
494
+ /**
495
+ * Truncate text to specified length
496
+ */
497
+ private static truncate(text: string, maxLength: number): string {
498
+ if (text.length <= maxLength) return text;
499
+ return text.slice(0, maxLength - 3) + '...';
500
+ }
501
+
502
+ /**
503
+ * Ensure service is initialized
504
+ */
505
+ private static ensureInitialized(): void {
506
+ if (!this.initialized) {
507
+ throw new Error('[MemoryService] Not initialized. Call MemoryService.initialize() first.');
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Shutdown the service
513
+ */
514
+ static shutdown(): void {
515
+ if (this.cleanupIntervalHandle) {
516
+ clearInterval(this.cleanupIntervalHandle);
517
+ this.cleanupIntervalHandle = undefined;
518
+ }
519
+ memoryEvents.removeAllListeners();
520
+ this.initialized = false;
521
+ console.log('[MemoryService] Shutdown complete');
522
+ }
523
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Notification module exports
3
+ */
4
+
5
+ export { NotificationService } from './service';
6
+ export type { NotificationEvent, NotificationEventType, NotificationServiceConfig } from './service';
7
+ export {
8
+ loadNotificationStore,
9
+ loadNotificationStoreSync,
10
+ saveNotificationStore,
11
+ saveNotificationStoreSync,
12
+ getNotificationStorePath,
13
+ getNotificationDir,
14
+ DEFAULT_NOTIFICATION_STORE_PATH,
15
+ DEFAULT_NOTIFICATION_DIR,
16
+ } from './store';
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Notification Service - Manages in-app notifications
3
+ * Provides CRUD operations and emits events for UI updates
4
+ */
5
+
6
+ import { randomUUID } from 'node:crypto';
7
+ import type { AppNotification, NotificationType, NotificationStoreFile } from '../../shared/types';
8
+ import {
9
+ loadNotificationStore,
10
+ loadNotificationStoreSync,
11
+ saveNotificationStore,
12
+ getNotificationStorePath,
13
+ } from './store';
14
+
15
+ export type NotificationEventType = 'added' | 'updated' | 'removed' | 'cleared';
16
+
17
+ export interface NotificationEvent {
18
+ type: NotificationEventType;
19
+ notification?: AppNotification;
20
+ notifications?: AppNotification[];
21
+ }
22
+
23
+ export interface NotificationServiceConfig {
24
+ storePath?: string;
25
+ onEvent?: (event: NotificationEvent) => void;
26
+ }
27
+
28
+ export class NotificationService {
29
+ private notifications: AppNotification[] = [];
30
+ private storePath: string;
31
+ private onEvent?: (event: NotificationEvent) => void;
32
+
33
+ constructor(config: NotificationServiceConfig = {}) {
34
+ this.storePath = config.storePath || getNotificationStorePath();
35
+ this.onEvent = config.onEvent;
36
+
37
+ // Load notifications synchronously on startup
38
+ const store = loadNotificationStoreSync(this.storePath);
39
+ this.notifications = store.notifications;
40
+ console.log(`[Notifications] Loaded ${this.notifications.length} notifications from store`);
41
+ }
42
+
43
+ /**
44
+ * Get all notifications (sorted by date, newest first)
45
+ */
46
+ list(): AppNotification[] {
47
+ return [...this.notifications].sort((a, b) => b.createdAt - a.createdAt);
48
+ }
49
+
50
+ /**
51
+ * Get unread count
52
+ */
53
+ getUnreadCount(): number {
54
+ return this.notifications.filter((n) => !n.read).length;
55
+ }
56
+
57
+ /**
58
+ * Add a new notification
59
+ */
60
+ async add(params: {
61
+ type: NotificationType;
62
+ title: string;
63
+ message: string;
64
+ taskId?: string;
65
+ cronJobId?: string;
66
+ workspaceId?: string;
67
+ }): Promise<AppNotification> {
68
+ const notification: AppNotification = {
69
+ id: randomUUID(),
70
+ type: params.type,
71
+ title: params.title,
72
+ message: params.message,
73
+ read: false,
74
+ createdAt: Date.now(),
75
+ taskId: params.taskId,
76
+ cronJobId: params.cronJobId,
77
+ workspaceId: params.workspaceId,
78
+ };
79
+
80
+ this.notifications.unshift(notification);
81
+ await this.save();
82
+
83
+ this.emit({ type: 'added', notification });
84
+ return notification;
85
+ }
86
+
87
+ /**
88
+ * Mark a notification as read
89
+ */
90
+ async markRead(id: string): Promise<AppNotification | null> {
91
+ const notification = this.notifications.find((n) => n.id === id);
92
+ if (!notification) return null;
93
+
94
+ notification.read = true;
95
+ await this.save();
96
+
97
+ this.emit({ type: 'updated', notification });
98
+ return notification;
99
+ }
100
+
101
+ /**
102
+ * Mark all notifications as read
103
+ */
104
+ async markAllRead(): Promise<void> {
105
+ const unread = this.notifications.filter((n) => !n.read);
106
+ if (unread.length === 0) return;
107
+
108
+ for (const n of unread) {
109
+ n.read = true;
110
+ }
111
+ await this.save();
112
+
113
+ this.emit({ type: 'updated', notifications: this.notifications });
114
+ }
115
+
116
+ /**
117
+ * Delete a notification
118
+ */
119
+ async delete(id: string): Promise<boolean> {
120
+ const index = this.notifications.findIndex((n) => n.id === id);
121
+ if (index === -1) return false;
122
+
123
+ const [removed] = this.notifications.splice(index, 1);
124
+ await this.save();
125
+
126
+ this.emit({ type: 'removed', notification: removed });
127
+ return true;
128
+ }
129
+
130
+ /**
131
+ * Delete all notifications
132
+ */
133
+ async deleteAll(): Promise<void> {
134
+ if (this.notifications.length === 0) return;
135
+
136
+ this.notifications = [];
137
+ await this.save();
138
+
139
+ this.emit({ type: 'cleared' });
140
+ }
141
+
142
+ /**
143
+ * Save notifications to disk
144
+ */
145
+ private async save(): Promise<void> {
146
+ const store: NotificationStoreFile = {
147
+ version: 1,
148
+ notifications: this.notifications,
149
+ };
150
+ await saveNotificationStore(store, this.storePath);
151
+ }
152
+
153
+ /**
154
+ * Emit an event to listeners
155
+ */
156
+ private emit(event: NotificationEvent): void {
157
+ if (this.onEvent) {
158
+ this.onEvent(event);
159
+ }
160
+ }
161
+ }