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,681 @@
1
+ /**
2
+ * Microsoft Teams Channel Adapter
3
+ *
4
+ * Implements the ChannelAdapter interface using Microsoft Bot Framework SDK.
5
+ * Supports direct messages, channel mentions, and group chats.
6
+ */
7
+
8
+ import {
9
+ CloudAdapter,
10
+ ConfigurationBotFrameworkAuthentication,
11
+ TurnContext,
12
+ Activity,
13
+ ActivityTypes,
14
+ ConversationReference,
15
+ MessageFactory,
16
+ } from 'botbuilder';
17
+ import * as http from 'http';
18
+ import * as fs from 'fs';
19
+ import * as path from 'path';
20
+ import {
21
+ ChannelAdapter,
22
+ ChannelStatus,
23
+ IncomingMessage,
24
+ OutgoingMessage,
25
+ MessageHandler,
26
+ ErrorHandler,
27
+ StatusHandler,
28
+ ChannelInfo,
29
+ TeamsConfig,
30
+ } from './types';
31
+
32
+ /**
33
+ * Simple TTL cache for message deduplication
34
+ */
35
+ class MessageDeduplicationCache {
36
+ private cache: Map<string, number> = new Map();
37
+ private readonly ttlMs: number;
38
+
39
+ constructor(ttlMs: number = 60000) {
40
+ this.ttlMs = ttlMs;
41
+ // Cleanup expired entries every minute
42
+ setInterval(() => this.cleanup(), 60000);
43
+ }
44
+
45
+ has(messageId: string): boolean {
46
+ const timestamp = this.cache.get(messageId);
47
+ if (!timestamp) return false;
48
+ if (Date.now() - timestamp > this.ttlMs) {
49
+ this.cache.delete(messageId);
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ add(messageId: string): void {
56
+ this.cache.set(messageId, Date.now());
57
+ }
58
+
59
+ private cleanup(): void {
60
+ const now = Date.now();
61
+ for (const [key, timestamp] of this.cache.entries()) {
62
+ if (now - timestamp > this.ttlMs) {
63
+ this.cache.delete(key);
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ export class TeamsAdapter implements ChannelAdapter {
70
+ readonly type = 'teams' as const;
71
+
72
+ private adapter: CloudAdapter | null = null;
73
+ private server: http.Server | null = null;
74
+ private _status: ChannelStatus = 'disconnected';
75
+ private _botUsername?: string;
76
+ private _botId?: string;
77
+ private messageHandlers: MessageHandler[] = [];
78
+ private errorHandlers: ErrorHandler[] = [];
79
+ private statusHandlers: StatusHandler[] = [];
80
+ private config: TeamsConfig;
81
+ private conversationReferences: Map<string, Partial<ConversationReference>> = new Map();
82
+ private deduplicationCache: MessageDeduplicationCache;
83
+ private reconnectAttempts = 0;
84
+ private reconnectTimer: NodeJS.Timeout | null = null;
85
+
86
+ constructor(config: TeamsConfig) {
87
+ this.config = config;
88
+ this.deduplicationCache = new MessageDeduplicationCache();
89
+ }
90
+
91
+ get status(): ChannelStatus {
92
+ return this._status;
93
+ }
94
+
95
+ get botUsername(): string | undefined {
96
+ return this._botUsername;
97
+ }
98
+
99
+ /**
100
+ * Connect to Microsoft Teams via Bot Framework
101
+ */
102
+ async connect(): Promise<void> {
103
+ if (this._status === 'connected' || this._status === 'connecting') {
104
+ return;
105
+ }
106
+
107
+ this.setStatus('connecting');
108
+
109
+ try {
110
+ // Create Bot Framework authentication
111
+ const botFrameworkAuth = new ConfigurationBotFrameworkAuthentication({
112
+ MicrosoftAppId: this.config.appId,
113
+ MicrosoftAppPassword: this.config.appPassword,
114
+ MicrosoftAppTenantId: this.config.tenantId,
115
+ MicrosoftAppType: this.config.tenantId ? 'SingleTenant' : 'MultiTenant',
116
+ });
117
+
118
+ // Create the adapter
119
+ this.adapter = new CloudAdapter(botFrameworkAuth);
120
+
121
+ // Set up error handling for the adapter
122
+ this.adapter.onTurnError = async (context: TurnContext, error: Error) => {
123
+ console.error('Teams adapter turn error:', error);
124
+ this.handleError(error, 'turnError');
125
+
126
+ // Send error message to user
127
+ try {
128
+ await context.sendActivity('Sorry, something went wrong processing your message.');
129
+ } catch (sendError) {
130
+ console.error('Failed to send error message:', sendError);
131
+ }
132
+ };
133
+
134
+ // Set bot info from config
135
+ this._botUsername = this.config.displayName || 'Teams Bot';
136
+
137
+ // Start the HTTP server for receiving webhooks
138
+ await this.startWebhookServer();
139
+
140
+ console.log(`Teams bot "${this._botUsername}" is connected on port ${this.config.webhookPort || 3978}`);
141
+ this.setStatus('connected');
142
+ this.reconnectAttempts = 0;
143
+ } catch (error) {
144
+ const err = error instanceof Error ? error : new Error(String(error));
145
+ this.setStatus('error', err);
146
+ this.scheduleReconnect();
147
+ throw err;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Start the webhook server to receive messages from Teams
153
+ */
154
+ private async startWebhookServer(): Promise<void> {
155
+ const port = this.config.webhookPort || 3978;
156
+
157
+ return new Promise((resolve, reject) => {
158
+ this.server = http.createServer(async (req, res) => {
159
+ if (req.method === 'POST' && req.url === '/api/messages') {
160
+ let body = '';
161
+ req.on('data', chunk => {
162
+ body += chunk.toString();
163
+ });
164
+ req.on('end', async () => {
165
+ try {
166
+ await this.processIncomingActivity(req, res, body);
167
+ } catch (error) {
168
+ console.error('Error processing Teams message:', error);
169
+ res.writeHead(500);
170
+ res.end('Internal Server Error');
171
+ }
172
+ });
173
+ } else if (req.method === 'GET' && req.url === '/api/health') {
174
+ // Health check endpoint
175
+ res.writeHead(200, { 'Content-Type': 'application/json' });
176
+ res.end(JSON.stringify({ status: 'ok', bot: this._botUsername }));
177
+ } else {
178
+ res.writeHead(404);
179
+ res.end('Not Found');
180
+ }
181
+ });
182
+
183
+ this.server.on('error', (error: NodeJS.ErrnoException) => {
184
+ if (error.code === 'EADDRINUSE') {
185
+ reject(new Error(`Port ${port} is already in use. Please choose a different webhook port.`));
186
+ } else if (error.code === 'EACCES') {
187
+ reject(new Error(`Permission denied to use port ${port}. Try a port above 1024.`));
188
+ } else {
189
+ reject(error);
190
+ }
191
+ });
192
+
193
+ this.server.listen(port, () => {
194
+ console.log(`Teams webhook server listening on port ${port}`);
195
+ resolve();
196
+ });
197
+ });
198
+ }
199
+
200
+ /**
201
+ * Process incoming activity from Teams
202
+ */
203
+ private async processIncomingActivity(
204
+ req: http.IncomingMessage,
205
+ res: http.ServerResponse,
206
+ body: string
207
+ ): Promise<void> {
208
+ if (!this.adapter) {
209
+ res.writeHead(500);
210
+ res.end('Adapter not initialized');
211
+ return;
212
+ }
213
+
214
+ try {
215
+ const activity: Activity = JSON.parse(body);
216
+
217
+ // Create a fake request object for the adapter
218
+ const fakeReq = {
219
+ body: activity,
220
+ headers: req.headers,
221
+ method: req.method,
222
+ };
223
+
224
+ await this.adapter.process(fakeReq as any, res as any, async (context: TurnContext) => {
225
+ await this.handleActivity(context);
226
+ });
227
+ } catch (error) {
228
+ console.error('Error parsing Teams activity:', error);
229
+ res.writeHead(400);
230
+ res.end('Bad Request');
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Handle incoming activity from Teams
236
+ */
237
+ private async handleActivity(context: TurnContext): Promise<void> {
238
+ const activity = context.activity;
239
+
240
+ // Store conversation reference for proactive messaging
241
+ const conversationRef = TurnContext.getConversationReference(activity);
242
+ this.conversationReferences.set(activity.conversation.id, conversationRef);
243
+
244
+ // Handle different activity types
245
+ switch (activity.type) {
246
+ case ActivityTypes.Message:
247
+ await this.handleMessage(context, activity);
248
+ break;
249
+
250
+ case ActivityTypes.ConversationUpdate:
251
+ await this.handleConversationUpdate(context, activity);
252
+ break;
253
+
254
+ case ActivityTypes.MessageReaction:
255
+ // Handle reactions if needed
256
+ break;
257
+
258
+ default:
259
+ // Log unhandled activity types for debugging
260
+ console.log(`Unhandled activity type: ${activity.type}`);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Handle incoming message activity
266
+ */
267
+ private async handleMessage(context: TurnContext, activity: Activity): Promise<void> {
268
+ // Skip if no text content
269
+ if (!activity.text) {
270
+ return;
271
+ }
272
+
273
+ // Deduplication check
274
+ const messageId = activity.id || `${activity.conversation.id}-${activity.timestamp}`;
275
+ if (this.config.deduplicationEnabled !== false && this.deduplicationCache.has(messageId)) {
276
+ console.log(`Skipping duplicate Teams message: ${messageId}`);
277
+ return;
278
+ }
279
+ this.deduplicationCache.add(messageId);
280
+
281
+ // Remove bot mention from text
282
+ let text = activity.text;
283
+ if (activity.entities) {
284
+ for (const entity of activity.entities) {
285
+ if (entity.type === 'mention' && entity.mentioned?.id === activity.recipient?.id) {
286
+ // Remove the mention from the text
287
+ const mentionText = entity.text || '';
288
+ text = text.replace(mentionText, '').trim();
289
+ }
290
+ }
291
+ }
292
+
293
+ // Skip empty messages after removing mentions
294
+ if (!text.trim()) {
295
+ return;
296
+ }
297
+
298
+ // Get user info
299
+ const userName = activity.from?.name || 'Unknown User';
300
+ const userId = activity.from?.id || '';
301
+
302
+ // Map to IncomingMessage format
303
+ const incomingMessage: IncomingMessage = {
304
+ messageId: messageId,
305
+ channel: 'teams',
306
+ userId: userId,
307
+ userName: userName,
308
+ chatId: activity.conversation.id,
309
+ text: text.trim(),
310
+ timestamp: activity.timestamp ? new Date(activity.timestamp) : new Date(),
311
+ replyTo: activity.replyToId,
312
+ threadId: activity.conversation.id,
313
+ raw: activity,
314
+ };
315
+
316
+ console.log(`Processing Teams message from ${userName}: ${text.slice(0, 50)}...`);
317
+ await this.handleIncomingMessage(incomingMessage);
318
+ }
319
+
320
+ /**
321
+ * Handle conversation update activity (new members, etc.)
322
+ */
323
+ private async handleConversationUpdate(context: TurnContext, activity: Activity): Promise<void> {
324
+ // Welcome new members
325
+ if (activity.membersAdded) {
326
+ for (const member of activity.membersAdded) {
327
+ // Don't welcome the bot itself
328
+ if (member.id !== activity.recipient?.id) {
329
+ // Could send a welcome message here if desired
330
+ console.log(`New member added to conversation: ${member.name}`);
331
+ }
332
+ }
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Schedule reconnection with exponential backoff
338
+ */
339
+ private scheduleReconnect(): void {
340
+ if (!this.config.autoReconnect) return;
341
+
342
+ const maxAttempts = this.config.maxReconnectAttempts || 5;
343
+ if (this.reconnectAttempts >= maxAttempts) {
344
+ console.error(`Teams: Max reconnection attempts (${maxAttempts}) reached`);
345
+ return;
346
+ }
347
+
348
+ const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
349
+ this.reconnectAttempts++;
350
+
351
+ console.log(`Teams: Scheduling reconnection attempt ${this.reconnectAttempts} in ${delay}ms`);
352
+
353
+ if (this.reconnectTimer) {
354
+ clearTimeout(this.reconnectTimer);
355
+ }
356
+
357
+ this.reconnectTimer = setTimeout(async () => {
358
+ try {
359
+ await this.connect();
360
+ } catch (error) {
361
+ console.error('Teams reconnection failed:', error);
362
+ }
363
+ }, delay);
364
+ }
365
+
366
+ /**
367
+ * Disconnect from Teams
368
+ */
369
+ async disconnect(): Promise<void> {
370
+ if (this.reconnectTimer) {
371
+ clearTimeout(this.reconnectTimer);
372
+ this.reconnectTimer = null;
373
+ }
374
+
375
+ if (this.server) {
376
+ await new Promise<void>((resolve) => {
377
+ this.server!.close(() => resolve());
378
+ });
379
+ this.server = null;
380
+ }
381
+
382
+ this.adapter = null;
383
+ this._botUsername = undefined;
384
+ this._botId = undefined;
385
+ this.conversationReferences.clear();
386
+ this.setStatus('disconnected');
387
+ }
388
+
389
+ /**
390
+ * Send a message to a Teams conversation
391
+ */
392
+ async sendMessage(message: OutgoingMessage): Promise<string> {
393
+ if (!this.adapter || this._status !== 'connected') {
394
+ throw new Error('Teams bot is not connected');
395
+ }
396
+
397
+ // Get conversation reference
398
+ const conversationRef = this.conversationReferences.get(message.chatId);
399
+ if (!conversationRef) {
400
+ throw new Error(`No conversation reference found for chat: ${message.chatId}`);
401
+ }
402
+
403
+ // Process text for Teams compatibility
404
+ let processedText = message.text;
405
+ if (message.parseMode === 'markdown') {
406
+ processedText = this.convertMarkdownForTeams(message.text);
407
+ }
408
+
409
+ // Teams has a 28KB limit per message, but practical limit is ~4000 chars for readability
410
+ const chunks = this.splitMessage(processedText, 4000);
411
+ let lastMessageId = '';
412
+
413
+ try {
414
+ for (const chunk of chunks) {
415
+ await this.adapter.continueConversationAsync(
416
+ this.config.appId,
417
+ conversationRef as ConversationReference,
418
+ async (context: TurnContext) => {
419
+ const response = await context.sendActivity(MessageFactory.text(chunk));
420
+ lastMessageId = response?.id || '';
421
+ }
422
+ );
423
+ }
424
+ } catch (error: unknown) {
425
+ const errorMessage = error instanceof Error ? error.message : String(error);
426
+ console.error('Error sending Teams message:', errorMessage);
427
+ throw error;
428
+ }
429
+
430
+ return lastMessageId;
431
+ }
432
+
433
+ /**
434
+ * Convert GitHub-flavored markdown to Teams format
435
+ * Teams supports a subset of markdown
436
+ */
437
+ private convertMarkdownForTeams(text: string): string {
438
+ let result = text;
439
+
440
+ // Teams supports basic markdown: **bold**, *italic*, ~~strikethrough~~, `code`, ```code blocks```
441
+ // No conversion needed for these
442
+
443
+ // Convert horizontal rules
444
+ result = result.replace(/^[-*]{3,}$/gm, '───────────────────');
445
+
446
+ return result;
447
+ }
448
+
449
+ /**
450
+ * Split message into chunks respecting Teams message limit
451
+ */
452
+ private splitMessage(text: string, maxLength: number): string[] {
453
+ if (text.length <= maxLength) {
454
+ return [text];
455
+ }
456
+
457
+ const chunks: string[] = [];
458
+ let remaining = text;
459
+
460
+ while (remaining.length > 0) {
461
+ if (remaining.length <= maxLength) {
462
+ chunks.push(remaining);
463
+ break;
464
+ }
465
+
466
+ // Find a good breaking point (newline or space)
467
+ let breakIndex = remaining.lastIndexOf('\n', maxLength);
468
+ if (breakIndex === -1 || breakIndex < maxLength / 2) {
469
+ breakIndex = remaining.lastIndexOf(' ', maxLength);
470
+ }
471
+ if (breakIndex === -1 || breakIndex < maxLength / 2) {
472
+ breakIndex = maxLength;
473
+ }
474
+
475
+ chunks.push(remaining.substring(0, breakIndex));
476
+ remaining = remaining.substring(breakIndex).trimStart();
477
+ }
478
+
479
+ return chunks;
480
+ }
481
+
482
+ /**
483
+ * Edit an existing message
484
+ */
485
+ async editMessage(chatId: string, messageId: string, text: string): Promise<void> {
486
+ if (!this.adapter || this._status !== 'connected') {
487
+ throw new Error('Teams bot is not connected');
488
+ }
489
+
490
+ const conversationRef = this.conversationReferences.get(chatId);
491
+ if (!conversationRef) {
492
+ throw new Error(`No conversation reference found for chat: ${chatId}`);
493
+ }
494
+
495
+ await this.adapter.continueConversationAsync(
496
+ this.config.appId,
497
+ conversationRef as ConversationReference,
498
+ async (context: TurnContext) => {
499
+ const activity = MessageFactory.text(text);
500
+ activity.id = messageId;
501
+ await context.updateActivity(activity);
502
+ }
503
+ );
504
+ }
505
+
506
+ /**
507
+ * Delete a message
508
+ */
509
+ async deleteMessage(chatId: string, messageId: string): Promise<void> {
510
+ if (!this.adapter || this._status !== 'connected') {
511
+ throw new Error('Teams bot is not connected');
512
+ }
513
+
514
+ const conversationRef = this.conversationReferences.get(chatId);
515
+ if (!conversationRef) {
516
+ throw new Error(`No conversation reference found for chat: ${chatId}`);
517
+ }
518
+
519
+ await this.adapter.continueConversationAsync(
520
+ this.config.appId,
521
+ conversationRef as ConversationReference,
522
+ async (context: TurnContext) => {
523
+ await context.deleteActivity(messageId);
524
+ }
525
+ );
526
+ }
527
+
528
+ /**
529
+ * Send a document/file to a conversation
530
+ */
531
+ async sendDocument(chatId: string, filePath: string, caption?: string): Promise<string> {
532
+ if (!this.adapter || this._status !== 'connected') {
533
+ throw new Error('Teams bot is not connected');
534
+ }
535
+
536
+ // Check if file exists
537
+ if (!fs.existsSync(filePath)) {
538
+ throw new Error(`File not found: ${filePath}`);
539
+ }
540
+
541
+ const conversationRef = this.conversationReferences.get(chatId);
542
+ if (!conversationRef) {
543
+ throw new Error(`No conversation reference found for chat: ${chatId}`);
544
+ }
545
+
546
+ const fileName = path.basename(filePath);
547
+ const fileBuffer = fs.readFileSync(filePath);
548
+ const base64Content = fileBuffer.toString('base64');
549
+ const contentType = this.getContentType(fileName);
550
+
551
+ let lastMessageId = '';
552
+
553
+ await this.adapter.continueConversationAsync(
554
+ this.config.appId,
555
+ conversationRef as ConversationReference,
556
+ async (context: TurnContext) => {
557
+ // Create attachment
558
+ const attachment = {
559
+ name: fileName,
560
+ contentType: contentType,
561
+ contentUrl: `data:${contentType};base64,${base64Content}`,
562
+ };
563
+
564
+ const activity = MessageFactory.attachment(attachment, caption);
565
+ const response = await context.sendActivity(activity);
566
+ lastMessageId = response?.id || '';
567
+ }
568
+ );
569
+
570
+ return lastMessageId;
571
+ }
572
+
573
+ /**
574
+ * Get content type from file extension
575
+ */
576
+ private getContentType(fileName: string): string {
577
+ const ext = path.extname(fileName).toLowerCase();
578
+ const contentTypes: Record<string, string> = {
579
+ '.pdf': 'application/pdf',
580
+ '.doc': 'application/msword',
581
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
582
+ '.xls': 'application/vnd.ms-excel',
583
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
584
+ '.ppt': 'application/vnd.ms-powerpoint',
585
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
586
+ '.png': 'image/png',
587
+ '.jpg': 'image/jpeg',
588
+ '.jpeg': 'image/jpeg',
589
+ '.gif': 'image/gif',
590
+ '.txt': 'text/plain',
591
+ '.json': 'application/json',
592
+ '.xml': 'application/xml',
593
+ '.zip': 'application/zip',
594
+ };
595
+ return contentTypes[ext] || 'application/octet-stream';
596
+ }
597
+
598
+ /**
599
+ * Register a message handler
600
+ */
601
+ onMessage(handler: MessageHandler): void {
602
+ this.messageHandlers.push(handler);
603
+ }
604
+
605
+ /**
606
+ * Register an error handler
607
+ */
608
+ onError(handler: ErrorHandler): void {
609
+ this.errorHandlers.push(handler);
610
+ }
611
+
612
+ /**
613
+ * Register a status change handler
614
+ */
615
+ onStatusChange(handler: StatusHandler): void {
616
+ this.statusHandlers.push(handler);
617
+ }
618
+
619
+ /**
620
+ * Get channel info
621
+ */
622
+ async getInfo(): Promise<ChannelInfo> {
623
+ return {
624
+ type: 'teams',
625
+ status: this._status,
626
+ botId: this.config.appId,
627
+ botUsername: this._botUsername,
628
+ botDisplayName: this._botUsername,
629
+ };
630
+ }
631
+
632
+ // Private helper methods
633
+
634
+ private async handleIncomingMessage(message: IncomingMessage): Promise<void> {
635
+ for (const handler of this.messageHandlers) {
636
+ try {
637
+ await handler(message);
638
+ } catch (error) {
639
+ console.error('Error in message handler:', error);
640
+ this.handleError(
641
+ error instanceof Error ? error : new Error(String(error)),
642
+ 'messageHandler'
643
+ );
644
+ }
645
+ }
646
+ }
647
+
648
+ private handleError(error: Error, context?: string): void {
649
+ for (const handler of this.errorHandlers) {
650
+ try {
651
+ handler(error, context);
652
+ } catch (e) {
653
+ console.error('Error in error handler:', e);
654
+ }
655
+ }
656
+ }
657
+
658
+ private setStatus(status: ChannelStatus, error?: Error): void {
659
+ this._status = status;
660
+ for (const handler of this.statusHandlers) {
661
+ try {
662
+ handler(status, error);
663
+ } catch (e) {
664
+ console.error('Error in status handler:', e);
665
+ }
666
+ }
667
+ }
668
+ }
669
+
670
+ /**
671
+ * Create a Teams adapter from configuration
672
+ */
673
+ export function createTeamsAdapter(config: TeamsConfig): TeamsAdapter {
674
+ if (!config.appId) {
675
+ throw new Error('Microsoft App ID is required');
676
+ }
677
+ if (!config.appPassword) {
678
+ throw new Error('Microsoft App Password is required');
679
+ }
680
+ return new TeamsAdapter(config);
681
+ }