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,655 @@
1
+ /**
2
+ * Matrix Channel Adapter
3
+ *
4
+ * Implements the ChannelAdapter interface for Matrix messaging.
5
+ * Uses the Matrix Client-Server API for communication.
6
+ *
7
+ * Features:
8
+ * - Real-time message receiving via sync
9
+ * - Room-based messaging
10
+ * - End-to-end encryption support (room-level)
11
+ * - File attachment support
12
+ * - Message reactions
13
+ * - Typing indicators
14
+ * - Read receipts
15
+ *
16
+ * Requirements:
17
+ * - Matrix homeserver URL
18
+ * - Access token
19
+ * - User ID
20
+ */
21
+
22
+ import {
23
+ ChannelAdapter,
24
+ ChannelStatus,
25
+ IncomingMessage,
26
+ OutgoingMessage,
27
+ MessageHandler,
28
+ ErrorHandler,
29
+ StatusHandler,
30
+ ChannelInfo,
31
+ MatrixConfig,
32
+ MessageAttachment,
33
+ } from './types';
34
+ import { MatrixClient, MatrixRoomEvent, MatrixUser } from './matrix-client';
35
+ import * as fs from 'fs';
36
+ import * as path from 'path';
37
+ import * as os from 'os';
38
+
39
+ export class MatrixAdapter implements ChannelAdapter {
40
+ readonly type = 'matrix' as const;
41
+
42
+ private client: MatrixClient | null = null;
43
+ private _status: ChannelStatus = 'disconnected';
44
+ private _botUsername?: string;
45
+ private messageHandlers: MessageHandler[] = [];
46
+ private errorHandlers: ErrorHandler[] = [];
47
+ private statusHandlers: StatusHandler[] = [];
48
+ private config: MatrixConfig;
49
+
50
+ // User cache
51
+ private userCache: Map<string, MatrixUser> = new Map();
52
+
53
+ // Message deduplication
54
+ private processedMessages: Map<string, number> = new Map();
55
+ private readonly DEDUP_CACHE_TTL = 60000; // 1 minute
56
+ private readonly DEDUP_CACHE_MAX_SIZE = 1000;
57
+ private dedupCleanupTimer?: ReturnType<typeof setInterval>;
58
+
59
+ // Attachments directory
60
+ private attachmentsDir: string;
61
+
62
+ constructor(config: MatrixConfig) {
63
+ this.config = {
64
+ deduplicationEnabled: true,
65
+ sendTypingIndicators: true,
66
+ sendReadReceipts: true,
67
+ ...config,
68
+ };
69
+
70
+ // Set up attachments directory
71
+ this.attachmentsDir = path.join(os.tmpdir(), 'cowork-matrix-attachments');
72
+ if (!fs.existsSync(this.attachmentsDir)) {
73
+ fs.mkdirSync(this.attachmentsDir, { recursive: true });
74
+ }
75
+ }
76
+
77
+ get status(): ChannelStatus {
78
+ return this._status;
79
+ }
80
+
81
+ get botUsername(): string | undefined {
82
+ return this._botUsername;
83
+ }
84
+
85
+ /**
86
+ * Connect to Matrix
87
+ */
88
+ async connect(): Promise<void> {
89
+ if (this._status === 'connected' || this._status === 'connecting') {
90
+ return;
91
+ }
92
+
93
+ this.setStatus('connecting');
94
+
95
+ try {
96
+ // Create Matrix client
97
+ this.client = new MatrixClient({
98
+ homeserver: this.config.homeserver,
99
+ userId: this.config.userId,
100
+ accessToken: this.config.accessToken,
101
+ deviceId: this.config.deviceId,
102
+ roomIds: this.config.roomIds,
103
+ verbose: process.env.NODE_ENV === 'development',
104
+ });
105
+
106
+ // Check connection
107
+ const check = await this.client.checkConnection();
108
+ if (!check.success) {
109
+ throw new Error(check.error || 'Failed to connect to Matrix');
110
+ }
111
+
112
+ // Get bot user profile
113
+ const profile = await this.client.getUserProfile();
114
+ this._botUsername = profile.displayname || this.config.userId;
115
+
116
+ // Set up event handlers
117
+ this.client.on('message', (event: MatrixRoomEvent) => {
118
+ this.handleIncomingEvent(event);
119
+ });
120
+
121
+ this.client.on('error', (error: Error) => {
122
+ this.handleError(error, 'client');
123
+ });
124
+
125
+ this.client.on('connected', () => {
126
+ console.log('Matrix client connected');
127
+ });
128
+
129
+ this.client.on('disconnected', () => {
130
+ console.log('Matrix client disconnected');
131
+ if (this._status === 'connected') {
132
+ this.setStatus('disconnected');
133
+ }
134
+ });
135
+
136
+ // Start receiving messages
137
+ await this.client.startReceiving();
138
+
139
+ // Start deduplication cleanup
140
+ if (this.config.deduplicationEnabled) {
141
+ this.startDedupCleanup();
142
+ }
143
+
144
+ this.setStatus('connected');
145
+ console.log(`Matrix adapter connected as ${this._botUsername}`);
146
+ } catch (error) {
147
+ const err = error instanceof Error ? error : new Error(String(error));
148
+ this.setStatus('error', err);
149
+ throw err;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Disconnect from Matrix
155
+ */
156
+ async disconnect(): Promise<void> {
157
+ // Stop dedup cleanup
158
+ if (this.dedupCleanupTimer) {
159
+ clearInterval(this.dedupCleanupTimer);
160
+ this.dedupCleanupTimer = undefined;
161
+ }
162
+
163
+ // Clear caches
164
+ this.processedMessages.clear();
165
+ this.userCache.clear();
166
+
167
+ // Stop client
168
+ if (this.client) {
169
+ await this.client.stopReceiving();
170
+ this.client = null;
171
+ }
172
+
173
+ this._botUsername = undefined;
174
+ this.setStatus('disconnected');
175
+ }
176
+
177
+ /**
178
+ * Send a message
179
+ */
180
+ async sendMessage(message: OutgoingMessage): Promise<string> {
181
+ if (!this.client || this._status !== 'connected') {
182
+ throw new Error('Matrix client is not connected');
183
+ }
184
+
185
+ // Handle attachments first
186
+ if (message.attachments && message.attachments.length > 0) {
187
+ for (const attachment of message.attachments) {
188
+ await this.sendAttachment(message.chatId, attachment);
189
+ }
190
+ }
191
+
192
+ // Add response prefix if configured
193
+ let text = message.text;
194
+ if (this.config.responsePrefix) {
195
+ text = `${this.config.responsePrefix} ${text}`;
196
+ }
197
+
198
+ // Prepare formatted content for markdown
199
+ let formattedBody: string | undefined;
200
+ if (message.parseMode === 'markdown' || message.parseMode === 'html') {
201
+ formattedBody = text; // Matrix supports HTML; markdown would need conversion
202
+ }
203
+
204
+ // Send the message
205
+ const eventId = await this.client.sendMessage(message.chatId, text, {
206
+ formattedBody,
207
+ format: formattedBody ? 'org.matrix.custom.html' : undefined,
208
+ replyTo: message.replyTo,
209
+ });
210
+
211
+ return eventId;
212
+ }
213
+
214
+ /**
215
+ * Send an attachment
216
+ */
217
+ private async sendAttachment(
218
+ roomId: string,
219
+ attachment: MessageAttachment
220
+ ): Promise<string | null> {
221
+ if (!this.client) return null;
222
+
223
+ let filePath: string;
224
+
225
+ if (attachment.url && fs.existsSync(attachment.url)) {
226
+ filePath = attachment.url;
227
+ } else if (attachment.data) {
228
+ const fileName = attachment.fileName || `attachment_${Date.now()}`;
229
+ filePath = path.join(this.attachmentsDir, fileName);
230
+ fs.writeFileSync(filePath, attachment.data);
231
+ } else {
232
+ return null;
233
+ }
234
+
235
+ try {
236
+ // Upload media
237
+ const uploadResult = await this.client.uploadMedia(filePath, attachment.mimeType);
238
+ const mxcUrl = uploadResult.content_uri;
239
+ const fileName = attachment.fileName || path.basename(filePath);
240
+
241
+ // Send based on type
242
+ if (attachment.type === 'image') {
243
+ return await this.client.sendImage(roomId, mxcUrl, fileName, {
244
+ mimetype: attachment.mimeType,
245
+ size: attachment.size,
246
+ });
247
+ } else {
248
+ return await this.client.sendFile(roomId, mxcUrl, fileName, {
249
+ mimetype: attachment.mimeType,
250
+ size: attachment.size,
251
+ });
252
+ }
253
+ } catch (error) {
254
+ console.error('Failed to send attachment:', error);
255
+ return null;
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Edit a message (Matrix uses redaction + new message)
261
+ */
262
+ async editMessage(chatId: string, messageId: string, text: string): Promise<void> {
263
+ // Matrix doesn't have native edit - we'd need to use m.replace relation
264
+ // For simplicity, we'll throw an error indicating this limitation
265
+ console.warn('Matrix message editing requires m.replace relation - not fully implemented');
266
+ throw new Error('Matrix message editing not fully supported');
267
+ }
268
+
269
+ /**
270
+ * Delete a message (redact)
271
+ */
272
+ async deleteMessage(chatId: string, messageId: string): Promise<void> {
273
+ if (!this.client || this._status !== 'connected') {
274
+ throw new Error('Matrix client is not connected');
275
+ }
276
+
277
+ await this.client.redactMessage(chatId, messageId);
278
+ }
279
+
280
+ /**
281
+ * Send a document/file
282
+ */
283
+ async sendDocument(chatId: string, filePath: string, caption?: string): Promise<string> {
284
+ if (!this.client || this._status !== 'connected') {
285
+ throw new Error('Matrix client is not connected');
286
+ }
287
+
288
+ const uploadResult = await this.client.uploadMedia(filePath);
289
+ const mxcUrl = uploadResult.content_uri;
290
+ const fileName = path.basename(filePath);
291
+ const stats = fs.statSync(filePath);
292
+
293
+ // Send the file
294
+ const eventId = await this.client.sendFile(chatId, mxcUrl, caption || fileName, {
295
+ size: stats.size,
296
+ });
297
+
298
+ return eventId;
299
+ }
300
+
301
+ /**
302
+ * Send a photo/image
303
+ */
304
+ async sendPhoto(chatId: string, filePath: string, caption?: string): Promise<string> {
305
+ if (!this.client || this._status !== 'connected') {
306
+ throw new Error('Matrix client is not connected');
307
+ }
308
+
309
+ const uploadResult = await this.client.uploadMedia(filePath);
310
+ const mxcUrl = uploadResult.content_uri;
311
+ const fileName = path.basename(filePath);
312
+ const stats = fs.statSync(filePath);
313
+
314
+ // Send the image
315
+ const eventId = await this.client.sendImage(chatId, mxcUrl, caption || fileName, {
316
+ size: stats.size,
317
+ });
318
+
319
+ return eventId;
320
+ }
321
+
322
+ /**
323
+ * Register a message handler
324
+ */
325
+ onMessage(handler: MessageHandler): void {
326
+ this.messageHandlers.push(handler);
327
+ }
328
+
329
+ /**
330
+ * Register an error handler
331
+ */
332
+ onError(handler: ErrorHandler): void {
333
+ this.errorHandlers.push(handler);
334
+ }
335
+
336
+ /**
337
+ * Register a status change handler
338
+ */
339
+ onStatusChange(handler: StatusHandler): void {
340
+ this.statusHandlers.push(handler);
341
+ }
342
+
343
+ /**
344
+ * Get channel info
345
+ */
346
+ async getInfo(): Promise<ChannelInfo> {
347
+ return {
348
+ type: 'matrix',
349
+ status: this._status,
350
+ botId: this.config.userId,
351
+ botUsername: this._botUsername,
352
+ botDisplayName: `Matrix (${this._botUsername})`,
353
+ extra: {
354
+ homeserver: this.config.homeserver,
355
+ userId: this.config.userId,
356
+ },
357
+ };
358
+ }
359
+
360
+ // ============================================================================
361
+ // Extended Features
362
+ // ============================================================================
363
+
364
+ /**
365
+ * Send typing indicator
366
+ */
367
+ async sendTyping(chatId: string): Promise<void> {
368
+ if (!this.client || !this.config.sendTypingIndicators) {
369
+ return;
370
+ }
371
+
372
+ try {
373
+ await this.client.sendTyping(chatId, true);
374
+ } catch (error) {
375
+ // Ignore typing indicator errors
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Stop typing indicator
381
+ */
382
+ async stopTyping(chatId: string): Promise<void> {
383
+ if (!this.client || !this.config.sendTypingIndicators) {
384
+ return;
385
+ }
386
+
387
+ try {
388
+ await this.client.sendTyping(chatId, false);
389
+ } catch (error) {
390
+ // Ignore typing indicator errors
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Add reaction to a message
396
+ */
397
+ async addReaction(chatId: string, messageId: string, emoji: string): Promise<void> {
398
+ if (!this.client || this._status !== 'connected') {
399
+ throw new Error('Matrix client is not connected');
400
+ }
401
+
402
+ await this.client.sendReaction(chatId, messageId, emoji);
403
+ }
404
+
405
+ /**
406
+ * Send read receipt
407
+ */
408
+ async sendReadReceipt(roomId: string, eventId: string): Promise<void> {
409
+ if (!this.client || !this.config.sendReadReceipts) {
410
+ return;
411
+ }
412
+
413
+ try {
414
+ await this.client.sendReadReceipt(roomId, eventId);
415
+ } catch (error) {
416
+ // Ignore read receipt errors
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Join a room
422
+ */
423
+ async joinRoom(roomIdOrAlias: string): Promise<string> {
424
+ if (!this.client || this._status !== 'connected') {
425
+ throw new Error('Matrix client is not connected');
426
+ }
427
+
428
+ return this.client.joinRoom(roomIdOrAlias);
429
+ }
430
+
431
+ /**
432
+ * Leave a room
433
+ */
434
+ async leaveRoom(roomId: string): Promise<void> {
435
+ if (!this.client || this._status !== 'connected') {
436
+ throw new Error('Matrix client is not connected');
437
+ }
438
+
439
+ await this.client.leaveRoom(roomId);
440
+ }
441
+
442
+ // ============================================================================
443
+ // Private Methods
444
+ // ============================================================================
445
+
446
+ /**
447
+ * Handle incoming Matrix event
448
+ */
449
+ private async handleIncomingEvent(event: MatrixRoomEvent): Promise<void> {
450
+ // Get message body
451
+ const body = event.content.body;
452
+ if (!body) {
453
+ return;
454
+ }
455
+
456
+ // Check for duplicates
457
+ if (this.config.deduplicationEnabled && this.isMessageProcessed(event.event_id)) {
458
+ console.log(`Skipping duplicate Matrix message ${event.event_id}`);
459
+ return;
460
+ }
461
+
462
+ // Mark as processed
463
+ if (this.config.deduplicationEnabled) {
464
+ this.markMessageProcessed(event.event_id);
465
+ }
466
+
467
+ // Get user info
468
+ let userName = event.sender;
469
+ try {
470
+ const user = await this.getCachedUser(event.sender);
471
+ userName = user.displayname || event.sender;
472
+ } catch (error) {
473
+ console.error('Failed to get user info:', error);
474
+ }
475
+
476
+ // Convert attachments
477
+ const attachments = this.convertAttachments(event);
478
+
479
+ // Get reply-to
480
+ const replyTo = event.content['m.relates_to']?.['m.in_reply_to']?.event_id;
481
+
482
+ // Convert to IncomingMessage
483
+ const message: IncomingMessage = {
484
+ messageId: event.event_id,
485
+ channel: 'matrix',
486
+ userId: event.sender,
487
+ userName,
488
+ chatId: event.room_id,
489
+ text: body,
490
+ timestamp: new Date(event.origin_server_ts),
491
+ replyTo,
492
+ attachments,
493
+ raw: event,
494
+ };
495
+
496
+ // Send read receipt
497
+ if (this.config.sendReadReceipts) {
498
+ await this.sendReadReceipt(event.room_id, event.event_id);
499
+ }
500
+
501
+ // Notify handlers
502
+ for (const handler of this.messageHandlers) {
503
+ try {
504
+ await handler(message);
505
+ } catch (error) {
506
+ console.error('Error in Matrix message handler:', error);
507
+ this.handleError(
508
+ error instanceof Error ? error : new Error(String(error)),
509
+ 'messageHandler'
510
+ );
511
+ }
512
+ }
513
+ }
514
+
515
+ /**
516
+ * Convert Matrix media content to MessageAttachment format
517
+ */
518
+ private convertAttachments(event: MatrixRoomEvent): MessageAttachment[] | undefined {
519
+ const msgtype = event.content.msgtype;
520
+ const url = event.content.url;
521
+
522
+ if (!url || !msgtype) {
523
+ return undefined;
524
+ }
525
+
526
+ // Only handle media message types
527
+ if (!['m.image', 'm.file', 'm.audio', 'm.video'].includes(msgtype)) {
528
+ return undefined;
529
+ }
530
+
531
+ let type: MessageAttachment['type'] = 'file';
532
+ switch (msgtype) {
533
+ case 'm.image':
534
+ type = 'image';
535
+ break;
536
+ case 'm.audio':
537
+ type = 'audio';
538
+ break;
539
+ case 'm.video':
540
+ type = 'video';
541
+ break;
542
+ }
543
+
544
+ return [
545
+ {
546
+ type,
547
+ url: this.client?.getMediaUrl(url),
548
+ mimeType: event.content.info?.mimetype,
549
+ fileName: event.content.body,
550
+ size: event.content.info?.size,
551
+ },
552
+ ];
553
+ }
554
+
555
+ /**
556
+ * Get user info with caching
557
+ */
558
+ private async getCachedUser(userId: string): Promise<MatrixUser> {
559
+ const cached = this.userCache.get(userId);
560
+ if (cached) {
561
+ return cached;
562
+ }
563
+
564
+ if (!this.client) {
565
+ throw new Error('Client not connected');
566
+ }
567
+
568
+ const user = await this.client.getUserProfile(userId);
569
+ this.userCache.set(userId, user);
570
+ return user;
571
+ }
572
+
573
+ /**
574
+ * Check if message was already processed
575
+ */
576
+ private isMessageProcessed(messageId: string): boolean {
577
+ return this.processedMessages.has(messageId);
578
+ }
579
+
580
+ /**
581
+ * Mark message as processed
582
+ */
583
+ private markMessageProcessed(messageId: string): void {
584
+ this.processedMessages.set(messageId, Date.now());
585
+
586
+ // Prevent unbounded growth
587
+ if (this.processedMessages.size > this.DEDUP_CACHE_MAX_SIZE) {
588
+ this.cleanupDedupCache();
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Start periodic dedup cache cleanup
594
+ */
595
+ private startDedupCleanup(): void {
596
+ this.dedupCleanupTimer = setInterval(() => {
597
+ this.cleanupDedupCache();
598
+ }, this.DEDUP_CACHE_TTL);
599
+ }
600
+
601
+ /**
602
+ * Clean up old entries from dedup cache
603
+ */
604
+ private cleanupDedupCache(): void {
605
+ const now = Date.now();
606
+ for (const [messageId, timestamp] of this.processedMessages) {
607
+ if (now - timestamp > this.DEDUP_CACHE_TTL) {
608
+ this.processedMessages.delete(messageId);
609
+ }
610
+ }
611
+ }
612
+
613
+ /**
614
+ * Handle errors
615
+ */
616
+ private handleError(error: Error, context?: string): void {
617
+ for (const handler of this.errorHandlers) {
618
+ try {
619
+ handler(error, context);
620
+ } catch (e) {
621
+ console.error('Error in error handler:', e);
622
+ }
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Set status and notify handlers
628
+ */
629
+ private setStatus(status: ChannelStatus, error?: Error): void {
630
+ this._status = status;
631
+ for (const handler of this.statusHandlers) {
632
+ try {
633
+ handler(status, error);
634
+ } catch (e) {
635
+ console.error('Error in status handler:', e);
636
+ }
637
+ }
638
+ }
639
+ }
640
+
641
+ /**
642
+ * Create a Matrix adapter from configuration
643
+ */
644
+ export function createMatrixAdapter(config: MatrixConfig): MatrixAdapter {
645
+ if (!config.homeserver) {
646
+ throw new Error('Matrix homeserver URL is required');
647
+ }
648
+ if (!config.userId) {
649
+ throw new Error('Matrix user ID is required');
650
+ }
651
+ if (!config.accessToken) {
652
+ throw new Error('Matrix access token is required');
653
+ }
654
+ return new MatrixAdapter(config);
655
+ }