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,953 @@
1
+ "use strict";
2
+ /**
3
+ * WhatsApp Channel Adapter
4
+ *
5
+ * Implements the ChannelAdapter interface using Baileys for WhatsApp Web API.
6
+ *
7
+ * Features:
8
+ * - QR code authentication for WhatsApp Web
9
+ * - Multi-file auth state persistence
10
+ * - Message deduplication
11
+ * - Group and DM message handling
12
+ * - Media message support (images, documents, audio, video)
13
+ * - Typing indicators (composing presence)
14
+ * - Message reactions
15
+ * - Auto-reconnection with exponential backoff
16
+ * - Read receipts
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.WhatsAppAdapter = void 0;
53
+ exports.createWhatsAppAdapter = createWhatsAppAdapter;
54
+ const baileys_1 = require("@whiskeysockets/baileys");
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const electron_1 = require("electron");
58
+ class WhatsAppAdapter {
59
+ constructor(config) {
60
+ this.type = 'whatsapp';
61
+ this.sock = null;
62
+ this._status = 'disconnected';
63
+ this.messageHandlers = [];
64
+ this.errorHandlers = [];
65
+ this.statusHandlers = [];
66
+ this.qrCodeHandlers = [];
67
+ // Message deduplication
68
+ this.processedMessages = new Map();
69
+ this.DEDUP_CACHE_TTL = 60000; // 1 minute
70
+ this.DEDUP_CACHE_MAX_SIZE = 1000;
71
+ // Connection state
72
+ this.connectedAtMs = 0;
73
+ this.isReconnecting = false;
74
+ this.backoffAttempt = 0;
75
+ this.DEFAULT_BACKOFF = {
76
+ initialDelay: 2000,
77
+ maxDelay: 30000,
78
+ multiplier: 1.8,
79
+ jitter: 0.25,
80
+ maxAttempts: 10,
81
+ };
82
+ // Group metadata cache
83
+ this.groupMetaCache = new Map();
84
+ this.GROUP_META_TTL_MS = 5 * 60 * 1000; // 5 minutes
85
+ this.config = {
86
+ deduplicationEnabled: true,
87
+ sendReadReceipts: true,
88
+ printQrToTerminal: false,
89
+ selfChatMode: true, // Default to self-chat mode since most users use their own number
90
+ responsePrefix: '🤖', // Default prefix for bot responses
91
+ ...config,
92
+ };
93
+ // In self-chat mode, disable read receipts by default
94
+ if (this.config.selfChatMode && config.sendReadReceipts === undefined) {
95
+ this.config.sendReadReceipts = false;
96
+ }
97
+ // Set auth directory
98
+ this.authDir = config.authDir || path.join(electron_1.app.getPath('userData'), 'whatsapp-auth');
99
+ }
100
+ /**
101
+ * Check if self-chat mode is enabled
102
+ */
103
+ get isSelfChatMode() {
104
+ return this.config.selfChatMode === true;
105
+ }
106
+ /**
107
+ * Get the response prefix for bot messages
108
+ */
109
+ get responsePrefix() {
110
+ return this.config.responsePrefix || '🤖';
111
+ }
112
+ get status() {
113
+ return this._status;
114
+ }
115
+ get botUsername() {
116
+ return this._selfE164;
117
+ }
118
+ /**
119
+ * Get the current QR code (if in login state)
120
+ */
121
+ get qrCode() {
122
+ return this.currentQr;
123
+ }
124
+ /**
125
+ * Check if WhatsApp auth credentials exist
126
+ */
127
+ async hasCredentials() {
128
+ const credsPath = path.join(this.authDir, 'creds.json');
129
+ return fs.existsSync(credsPath);
130
+ }
131
+ /**
132
+ * Connect to WhatsApp Web
133
+ */
134
+ async connect() {
135
+ if (this._status === 'connected' || this._status === 'connecting') {
136
+ return;
137
+ }
138
+ this.setStatus('connecting');
139
+ this.resetBackoff();
140
+ try {
141
+ // Ensure auth directory exists
142
+ await this.ensureDir(this.authDir);
143
+ // Load auth state
144
+ const { state, saveCreds } = await (0, baileys_1.useMultiFileAuthState)(this.authDir);
145
+ // Get latest Baileys version
146
+ const { version } = await (0, baileys_1.fetchLatestBaileysVersion)();
147
+ // Create silent logger to suppress Baileys logs
148
+ const logger = {
149
+ level: 'silent',
150
+ trace: () => { },
151
+ debug: () => { },
152
+ info: () => { },
153
+ warn: () => { },
154
+ error: () => { },
155
+ fatal: () => { },
156
+ child: () => logger,
157
+ };
158
+ // Create WhatsApp socket
159
+ this.sock = (0, baileys_1.makeWASocket)({
160
+ auth: {
161
+ creds: state.creds,
162
+ keys: (0, baileys_1.makeCacheableSignalKeyStore)(state.keys, logger),
163
+ },
164
+ version,
165
+ logger: logger,
166
+ // Note: printQRInTerminal is deprecated - QR codes are handled via connection.update event
167
+ browser: ['CoWork-OS', 'Desktop', '1.0.0'],
168
+ syncFullHistory: false,
169
+ markOnlineOnConnect: false,
170
+ });
171
+ // Handle credential updates
172
+ this.sock.ev.on('creds.update', saveCreds);
173
+ // Handle connection updates
174
+ this.sock.ev.on('connection.update', (update) => {
175
+ this.handleConnectionUpdate(update);
176
+ });
177
+ // Handle incoming messages
178
+ this.sock.ev.on('messages.upsert', (upsert) => {
179
+ this.handleMessagesUpsert(upsert);
180
+ });
181
+ // Start deduplication cleanup
182
+ if (this.config.deduplicationEnabled) {
183
+ this.startDedupCleanup();
184
+ }
185
+ }
186
+ catch (error) {
187
+ const err = error instanceof Error ? error : new Error(String(error));
188
+ this.setStatus('error', err);
189
+ throw err;
190
+ }
191
+ }
192
+ /**
193
+ * Handle connection state updates
194
+ */
195
+ handleConnectionUpdate(update) {
196
+ const { connection, lastDisconnect, qr } = update;
197
+ // Handle QR code for authentication
198
+ if (qr) {
199
+ this.currentQr = qr;
200
+ console.log('WhatsApp QR code received - scan with WhatsApp mobile app');
201
+ // Notify QR handlers
202
+ for (const handler of this.qrCodeHandlers) {
203
+ try {
204
+ handler(qr);
205
+ }
206
+ catch (e) {
207
+ console.error('Error in QR code handler:', e);
208
+ }
209
+ }
210
+ }
211
+ // Handle connection open
212
+ if (connection === 'open') {
213
+ this.currentQr = undefined;
214
+ this.connectedAtMs = Date.now();
215
+ this._selfJid = this.sock?.user?.id;
216
+ this._selfE164 = this._selfJid ? this.jidToE164(this._selfJid) ?? undefined : undefined;
217
+ console.log(`WhatsApp connected as ${this._selfE164 || this._selfJid}`);
218
+ this.setStatus('connected');
219
+ this.resetBackoff();
220
+ // Send available presence
221
+ this.sock?.sendPresenceUpdate('available').catch(() => { });
222
+ }
223
+ // Handle connection close
224
+ if (connection === 'close') {
225
+ this.currentQr = undefined;
226
+ const statusCode = this.getStatusCode(lastDisconnect?.error);
227
+ if (statusCode === baileys_1.DisconnectReason.loggedOut) {
228
+ console.error('WhatsApp session logged out');
229
+ this.setStatus('error', new Error('WhatsApp session logged out. Please re-authenticate.'));
230
+ // Clear credentials on logout
231
+ this.clearCredentials().catch(() => { });
232
+ }
233
+ else if (statusCode === baileys_1.DisconnectReason.restartRequired) {
234
+ console.log('WhatsApp restart required, reconnecting...');
235
+ this.attemptReconnection();
236
+ }
237
+ else {
238
+ console.log(`WhatsApp connection closed (status: ${statusCode}), attempting reconnection...`);
239
+ this.attemptReconnection();
240
+ }
241
+ }
242
+ }
243
+ /**
244
+ * Handle incoming messages
245
+ */
246
+ async handleMessagesUpsert(upsert) {
247
+ if (upsert.type !== 'notify' && upsert.type !== 'append')
248
+ return;
249
+ for (const msg of upsert.messages ?? []) {
250
+ try {
251
+ await this.processInboundMessage(msg, upsert.type);
252
+ }
253
+ catch (error) {
254
+ console.error('Error processing WhatsApp message:', error);
255
+ this.handleError(error instanceof Error ? error : new Error(String(error)), 'messageProcessing');
256
+ }
257
+ }
258
+ }
259
+ /**
260
+ * Process a single inbound message
261
+ */
262
+ async processInboundMessage(msg, upsertType) {
263
+ const id = msg.key?.id;
264
+ const remoteJid = msg.key?.remoteJid;
265
+ if (!remoteJid)
266
+ return;
267
+ // Skip status and broadcast messages
268
+ if (remoteJid.endsWith('@status') || remoteJid.endsWith('@broadcast'))
269
+ return;
270
+ // CRITICAL: In self-chat mode, ONLY process messages from self-chat
271
+ // This prevents the bot from responding to messages sent to other people
272
+ if (this.isSelfChatMode && this._selfJid) {
273
+ // Normalize JIDs by removing device suffix (e.g., "123:5@s.whatsapp.net" -> "123@s.whatsapp.net")
274
+ const normalizeJid = (jid) => jid.replace(/:[\d]+@/, '@');
275
+ const selfJidNormalized = normalizeJid(this._selfJid);
276
+ const remoteJidNormalized = normalizeJid(remoteJid);
277
+ if (remoteJidNormalized !== selfJidNormalized) {
278
+ // Message is NOT in self-chat, silently ignore it
279
+ return;
280
+ }
281
+ }
282
+ // Deduplication
283
+ if (id && this.config.deduplicationEnabled) {
284
+ const dedupeKey = `${remoteJid}:${id}`;
285
+ if (this.processedMessages.has(dedupeKey))
286
+ return;
287
+ this.processedMessages.set(dedupeKey, Date.now());
288
+ // Cleanup if cache is too large
289
+ if (this.processedMessages.size > this.DEDUP_CACHE_MAX_SIZE) {
290
+ this.cleanupDedupCache();
291
+ }
292
+ }
293
+ const isGroup = (0, baileys_1.isJidGroup)(remoteJid) === true;
294
+ const participantJid = msg.key?.participant;
295
+ const from = isGroup ? remoteJid : this.jidToE164(remoteJid) || remoteJid;
296
+ const senderE164 = isGroup
297
+ ? participantJid ? this.jidToE164(participantJid) : null
298
+ : from;
299
+ // Check access control
300
+ if (this.config.allowedNumbers && this.config.allowedNumbers.length > 0) {
301
+ const senderNumber = senderE164?.replace(/[^0-9]/g, '');
302
+ if (senderNumber && !this.config.allowedNumbers.includes(senderNumber)) {
303
+ console.log(`WhatsApp: Ignoring message from unauthorized number: ${senderNumber}`);
304
+ return;
305
+ }
306
+ }
307
+ // Get group metadata if applicable
308
+ let groupSubject;
309
+ if (isGroup && this.sock) {
310
+ const meta = await this.getGroupMeta(remoteJid);
311
+ groupSubject = meta.subject;
312
+ }
313
+ // Extract message text
314
+ const body = this.extractText(msg.message);
315
+ if (!body) {
316
+ // Check for media placeholder
317
+ const mediaPlaceholder = this.extractMediaPlaceholder(msg.message);
318
+ if (!mediaPlaceholder)
319
+ return;
320
+ }
321
+ // Send read receipt
322
+ if (id && this.config.sendReadReceipts && upsertType === 'notify') {
323
+ try {
324
+ await this.sock?.readMessages([{
325
+ remoteJid,
326
+ id,
327
+ participant: participantJid,
328
+ fromMe: false,
329
+ }]);
330
+ }
331
+ catch {
332
+ // Ignore read receipt errors
333
+ }
334
+ }
335
+ // Skip history/offline catch-up messages
336
+ if (upsertType === 'append')
337
+ return;
338
+ const messageTimestampMs = msg.messageTimestamp
339
+ ? Number(msg.messageTimestamp) * 1000
340
+ : undefined;
341
+ // Download audio attachment if present
342
+ const attachments = [];
343
+ if (msg.message?.audioMessage) {
344
+ const audioAttachment = await this.downloadAudioAttachment(msg.message);
345
+ if (audioAttachment) {
346
+ attachments.push(audioAttachment);
347
+ }
348
+ }
349
+ // Create incoming message
350
+ const incomingMessage = {
351
+ messageId: id || `wa-${Date.now()}`,
352
+ channel: 'whatsapp',
353
+ userId: senderE164 || participantJid || remoteJid,
354
+ userName: msg.pushName || senderE164 || 'Unknown',
355
+ chatId: remoteJid,
356
+ text: body || (attachments.length === 0 ? this.extractMediaPlaceholder(msg.message) : '') || '',
357
+ timestamp: messageTimestampMs ? new Date(messageTimestampMs) : new Date(),
358
+ attachments: attachments.length > 0 ? attachments : undefined,
359
+ raw: msg,
360
+ };
361
+ // Notify message handlers
362
+ await this.handleIncomingMessage(incomingMessage);
363
+ }
364
+ /**
365
+ * Disconnect from WhatsApp
366
+ */
367
+ async disconnect() {
368
+ this.resetBackoff();
369
+ // Clear timers
370
+ if (this.dedupCleanupTimer) {
371
+ clearInterval(this.dedupCleanupTimer);
372
+ this.dedupCleanupTimer = undefined;
373
+ }
374
+ // Clear caches
375
+ this.processedMessages.clear();
376
+ this.groupMetaCache.clear();
377
+ this.currentQr = undefined;
378
+ if (this.sock) {
379
+ try {
380
+ this.sock.ws?.close();
381
+ }
382
+ catch {
383
+ // Ignore close errors
384
+ }
385
+ this.sock = null;
386
+ }
387
+ this._selfJid = undefined;
388
+ this._selfE164 = undefined;
389
+ this.setStatus('disconnected');
390
+ }
391
+ /**
392
+ * Convert standard Markdown to WhatsApp-compatible formatting
393
+ * WhatsApp supports: *bold*, _italic_, ~strikethrough~, ```monospace```
394
+ */
395
+ convertMarkdownToWhatsApp(text) {
396
+ let result = text;
397
+ // Convert headers (### Header) to bold text
398
+ result = result.replace(/^#{1,6}\s+(.+)$/gm, '*$1*');
399
+ // Convert **bold** to *bold* (WhatsApp style)
400
+ result = result.replace(/\*\*(.+?)\*\*/g, '*$1*');
401
+ // Convert __bold__ to *bold*
402
+ result = result.replace(/__(.+?)__/g, '*$1*');
403
+ // Convert _italic_ - already WhatsApp compatible, but handle markdown style
404
+ // Note: Single underscores are already WhatsApp italic
405
+ // Convert ~~strikethrough~~ to ~strikethrough~
406
+ result = result.replace(/~~(.+?)~~/g, '~$1~');
407
+ // Convert inline code `code` to monospace (WhatsApp uses triple backticks but single works in some clients)
408
+ // Keep as-is since WhatsApp renders `code` reasonably
409
+ // Convert code blocks ```code``` - already WhatsApp compatible
410
+ // Convert [link text](url) to "link text (url)" since WhatsApp auto-links URLs
411
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ($2)');
412
+ // Convert horizontal rules (---, ***, ___) to a line
413
+ result = result.replace(/^[-*_]{3,}$/gm, '───────────');
414
+ // Clean up excessive newlines
415
+ result = result.replace(/\n{3,}/g, '\n\n');
416
+ return result;
417
+ }
418
+ /**
419
+ * Send a message to a WhatsApp chat
420
+ */
421
+ async sendMessage(message) {
422
+ if (!this.sock || this._status !== 'connected') {
423
+ throw new Error('WhatsApp is not connected');
424
+ }
425
+ const jid = this.toWhatsAppJid(message.chatId);
426
+ let messageId = '';
427
+ // Convert markdown to WhatsApp formatting and apply response prefix
428
+ let textToSend = message.text ? this.convertMarkdownToWhatsApp(message.text) : message.text;
429
+ if (this.isSelfChatMode && textToSend && textToSend.trim()) {
430
+ const prefix = this.responsePrefix;
431
+ // Only add prefix if not already present
432
+ if (!textToSend.startsWith(prefix)) {
433
+ textToSend = `${prefix} ${textToSend}`;
434
+ }
435
+ }
436
+ // Send media attachments first
437
+ if (message.attachments && message.attachments.length > 0) {
438
+ for (const attachment of message.attachments) {
439
+ const result = await this.sendMediaAttachment(jid, attachment, textToSend);
440
+ messageId = result;
441
+ // Clear text after first media with caption
442
+ if (textToSend) {
443
+ textToSend = '';
444
+ }
445
+ }
446
+ }
447
+ // Send text message if no media or text remains
448
+ if (textToSend && textToSend.trim()) {
449
+ // Send composing presence
450
+ await this.sendComposingTo(jid);
451
+ const result = await this.sock.sendMessage(jid, { text: textToSend });
452
+ messageId = result?.key?.id || `wa-${Date.now()}`;
453
+ }
454
+ return messageId;
455
+ }
456
+ /**
457
+ * Send a media attachment
458
+ */
459
+ async sendMediaAttachment(jid, attachment, caption) {
460
+ if (!this.sock)
461
+ throw new Error('WhatsApp is not connected');
462
+ let content;
463
+ if (attachment.type === 'image' && attachment.url) {
464
+ const buffer = fs.readFileSync(attachment.url);
465
+ content = {
466
+ image: buffer,
467
+ caption,
468
+ mimetype: attachment.mimeType || 'image/jpeg',
469
+ };
470
+ }
471
+ else if (attachment.type === 'document' && attachment.url) {
472
+ const buffer = fs.readFileSync(attachment.url);
473
+ content = {
474
+ document: buffer,
475
+ fileName: attachment.fileName || path.basename(attachment.url),
476
+ mimetype: attachment.mimeType || 'application/octet-stream',
477
+ caption,
478
+ };
479
+ }
480
+ else if (attachment.type === 'audio' && attachment.url) {
481
+ const buffer = fs.readFileSync(attachment.url);
482
+ content = {
483
+ audio: buffer,
484
+ mimetype: attachment.mimeType || 'audio/mpeg',
485
+ ptt: true, // Voice note
486
+ };
487
+ }
488
+ else if (attachment.type === 'video' && attachment.url) {
489
+ const buffer = fs.readFileSync(attachment.url);
490
+ content = {
491
+ video: buffer,
492
+ caption,
493
+ mimetype: attachment.mimeType || 'video/mp4',
494
+ };
495
+ }
496
+ else {
497
+ throw new Error(`Unsupported attachment type: ${attachment.type}`);
498
+ }
499
+ const result = await this.sock.sendMessage(jid, content);
500
+ return result?.key?.id || `wa-${Date.now()}`;
501
+ }
502
+ /**
503
+ * Send composing (typing) indicator
504
+ */
505
+ async sendComposingTo(chatId) {
506
+ if (!this.sock)
507
+ return;
508
+ const jid = this.toWhatsAppJid(chatId);
509
+ try {
510
+ await this.sock.sendPresenceUpdate('composing', jid);
511
+ }
512
+ catch {
513
+ // Ignore presence errors
514
+ }
515
+ }
516
+ /**
517
+ * Send typing indicator (alias for sendComposingTo)
518
+ */
519
+ async sendTyping(chatId) {
520
+ await this.sendComposingTo(chatId);
521
+ }
522
+ /**
523
+ * Edit an existing message (not supported by WhatsApp Web API)
524
+ */
525
+ async editMessage(_chatId, _messageId, _text) {
526
+ throw new Error('WhatsApp does not support message editing');
527
+ }
528
+ /**
529
+ * Delete a message
530
+ */
531
+ async deleteMessage(chatId, messageId) {
532
+ if (!this.sock)
533
+ throw new Error('WhatsApp is not connected');
534
+ const jid = this.toWhatsAppJid(chatId);
535
+ await this.sock.sendMessage(jid, {
536
+ delete: {
537
+ remoteJid: jid,
538
+ fromMe: true,
539
+ id: messageId,
540
+ },
541
+ });
542
+ }
543
+ /**
544
+ * Send a document/file
545
+ */
546
+ async sendDocument(chatId, filePath, caption) {
547
+ if (!this.sock)
548
+ throw new Error('WhatsApp is not connected');
549
+ const jid = this.toWhatsAppJid(chatId);
550
+ const buffer = fs.readFileSync(filePath);
551
+ const fileName = path.basename(filePath);
552
+ const result = await this.sock.sendMessage(jid, {
553
+ document: buffer,
554
+ fileName,
555
+ mimetype: 'application/octet-stream',
556
+ caption,
557
+ });
558
+ return result?.key?.id || `wa-${Date.now()}`;
559
+ }
560
+ /**
561
+ * Send a photo/image
562
+ */
563
+ async sendPhoto(chatId, filePath, caption) {
564
+ if (!this.sock)
565
+ throw new Error('WhatsApp is not connected');
566
+ const jid = this.toWhatsAppJid(chatId);
567
+ const buffer = fs.readFileSync(filePath);
568
+ const result = await this.sock.sendMessage(jid, {
569
+ image: buffer,
570
+ caption,
571
+ });
572
+ return result?.key?.id || `wa-${Date.now()}`;
573
+ }
574
+ /**
575
+ * Add a reaction to a message
576
+ */
577
+ async addReaction(chatId, messageId, emoji) {
578
+ if (!this.sock)
579
+ throw new Error('WhatsApp is not connected');
580
+ const jid = this.toWhatsAppJid(chatId);
581
+ await this.sock.sendMessage(jid, {
582
+ react: {
583
+ text: emoji,
584
+ key: {
585
+ remoteJid: jid,
586
+ id: messageId,
587
+ fromMe: false,
588
+ },
589
+ },
590
+ });
591
+ }
592
+ /**
593
+ * Remove a reaction from a message
594
+ */
595
+ async removeReaction(chatId, messageId) {
596
+ await this.addReaction(chatId, messageId, ''); // Empty string removes reaction
597
+ }
598
+ /**
599
+ * Register a message handler
600
+ */
601
+ onMessage(handler) {
602
+ this.messageHandlers.push(handler);
603
+ }
604
+ /**
605
+ * Register a callback query handler (not supported by WhatsApp)
606
+ */
607
+ onCallbackQuery(_handler) {
608
+ // WhatsApp doesn't support inline keyboards/callback queries
609
+ }
610
+ /**
611
+ * Register an error handler
612
+ */
613
+ onError(handler) {
614
+ this.errorHandlers.push(handler);
615
+ }
616
+ /**
617
+ * Register a status change handler
618
+ */
619
+ onStatusChange(handler) {
620
+ this.statusHandlers.push(handler);
621
+ }
622
+ /**
623
+ * Register a QR code handler
624
+ */
625
+ onQrCode(handler) {
626
+ this.qrCodeHandlers.push(handler);
627
+ }
628
+ /**
629
+ * Get channel info
630
+ */
631
+ async getInfo() {
632
+ return {
633
+ type: 'whatsapp',
634
+ status: this._status,
635
+ botId: this._selfJid,
636
+ botUsername: this._selfE164,
637
+ botDisplayName: this._selfE164,
638
+ extra: {
639
+ qrCode: this.currentQr,
640
+ hasCredentials: await this.hasCredentials(),
641
+ },
642
+ };
643
+ }
644
+ /**
645
+ * Logout and clear credentials
646
+ */
647
+ async logout() {
648
+ await this.disconnect();
649
+ await this.clearCredentials();
650
+ }
651
+ /**
652
+ * Clear stored credentials
653
+ */
654
+ async clearCredentials() {
655
+ try {
656
+ if (fs.existsSync(this.authDir)) {
657
+ const files = fs.readdirSync(this.authDir);
658
+ for (const file of files) {
659
+ fs.unlinkSync(path.join(this.authDir, file));
660
+ }
661
+ }
662
+ }
663
+ catch (error) {
664
+ console.error('Error clearing WhatsApp credentials:', error);
665
+ }
666
+ }
667
+ // ============================================================================
668
+ // Private Helper Methods
669
+ // ============================================================================
670
+ /**
671
+ * Handle incoming message notification
672
+ */
673
+ async handleIncomingMessage(message) {
674
+ for (const handler of this.messageHandlers) {
675
+ try {
676
+ await handler(message);
677
+ }
678
+ catch (error) {
679
+ console.error('Error in WhatsApp message handler:', error);
680
+ this.handleError(error instanceof Error ? error : new Error(String(error)), 'messageHandler');
681
+ }
682
+ }
683
+ }
684
+ /**
685
+ * Handle errors
686
+ */
687
+ handleError(error, context) {
688
+ for (const handler of this.errorHandlers) {
689
+ try {
690
+ handler(error, context);
691
+ }
692
+ catch (e) {
693
+ console.error('Error in error handler:', e);
694
+ }
695
+ }
696
+ }
697
+ /**
698
+ * Set status and notify handlers
699
+ */
700
+ setStatus(status, error) {
701
+ this._status = status;
702
+ for (const handler of this.statusHandlers) {
703
+ try {
704
+ handler(status, error);
705
+ }
706
+ catch (e) {
707
+ console.error('Error in status handler:', e);
708
+ }
709
+ }
710
+ }
711
+ /**
712
+ * Attempt reconnection with exponential backoff
713
+ */
714
+ async attemptReconnection() {
715
+ if (this.isReconnecting)
716
+ return;
717
+ const config = this.DEFAULT_BACKOFF;
718
+ if (this.backoffAttempt >= config.maxAttempts) {
719
+ console.error(`WhatsApp: Max reconnection attempts (${config.maxAttempts}) reached`);
720
+ this.setStatus('error', new Error('Max reconnection attempts reached'));
721
+ return;
722
+ }
723
+ this.isReconnecting = true;
724
+ this.backoffAttempt++;
725
+ const delay = this.calculateBackoffDelay(config);
726
+ console.log(`WhatsApp: Reconnection attempt ${this.backoffAttempt}/${config.maxAttempts} in ${delay}ms`);
727
+ this.backoffTimer = setTimeout(async () => {
728
+ try {
729
+ this.sock = null;
730
+ this.isReconnecting = false;
731
+ this.setStatus('disconnected');
732
+ await this.connect();
733
+ }
734
+ catch (error) {
735
+ this.isReconnecting = false;
736
+ console.error('WhatsApp reconnection attempt failed:', error);
737
+ await this.attemptReconnection();
738
+ }
739
+ }, delay);
740
+ }
741
+ /**
742
+ * Calculate backoff delay with jitter
743
+ */
744
+ calculateBackoffDelay(config) {
745
+ let delay = config.initialDelay * Math.pow(config.multiplier, this.backoffAttempt - 1);
746
+ delay = Math.min(delay, config.maxDelay);
747
+ const jitterAmount = delay * config.jitter;
748
+ const jitter = (Math.random() * 2 - 1) * jitterAmount;
749
+ delay = Math.round(delay + jitter);
750
+ return Math.max(1000, delay);
751
+ }
752
+ /**
753
+ * Reset backoff state
754
+ */
755
+ resetBackoff() {
756
+ this.backoffAttempt = 0;
757
+ this.isReconnecting = false;
758
+ if (this.backoffTimer) {
759
+ clearTimeout(this.backoffTimer);
760
+ this.backoffTimer = undefined;
761
+ }
762
+ }
763
+ /**
764
+ * Start deduplication cache cleanup
765
+ */
766
+ startDedupCleanup() {
767
+ this.dedupCleanupTimer = setInterval(() => {
768
+ this.cleanupDedupCache();
769
+ }, this.DEDUP_CACHE_TTL);
770
+ }
771
+ /**
772
+ * Clean up old dedup cache entries
773
+ */
774
+ cleanupDedupCache() {
775
+ const now = Date.now();
776
+ for (const [key, timestamp] of this.processedMessages) {
777
+ if (now - timestamp > this.DEDUP_CACHE_TTL) {
778
+ this.processedMessages.delete(key);
779
+ }
780
+ }
781
+ }
782
+ /**
783
+ * Get group metadata with caching
784
+ */
785
+ async getGroupMeta(jid) {
786
+ const cached = this.groupMetaCache.get(jid);
787
+ if (cached && cached.expires > Date.now()) {
788
+ return cached;
789
+ }
790
+ try {
791
+ const meta = await this.sock?.groupMetadata(jid);
792
+ const entry = {
793
+ subject: meta?.subject,
794
+ expires: Date.now() + this.GROUP_META_TTL_MS,
795
+ };
796
+ this.groupMetaCache.set(jid, entry);
797
+ return entry;
798
+ }
799
+ catch {
800
+ return { subject: undefined };
801
+ }
802
+ }
803
+ /**
804
+ * Convert JID to E.164 phone number format
805
+ */
806
+ jidToE164(jid) {
807
+ if (!jid)
808
+ return null;
809
+ // Remove @s.whatsapp.net or @c.us suffix
810
+ const match = jid.match(/^(\d+)@/);
811
+ if (!match)
812
+ return null;
813
+ return match[1];
814
+ }
815
+ /**
816
+ * Convert phone number/chat ID to WhatsApp JID
817
+ */
818
+ toWhatsAppJid(chatId) {
819
+ // Already a JID
820
+ if (chatId.includes('@'))
821
+ return chatId;
822
+ // Group ID
823
+ if (chatId.includes('-')) {
824
+ return `${chatId}@g.us`;
825
+ }
826
+ // Phone number - remove any non-numeric characters
827
+ const cleaned = chatId.replace(/[^0-9]/g, '');
828
+ return `${cleaned}@s.whatsapp.net`;
829
+ }
830
+ /**
831
+ * Extract text from WhatsApp message
832
+ */
833
+ extractText(message) {
834
+ if (!message)
835
+ return undefined;
836
+ // Direct text message
837
+ if (message.conversation) {
838
+ return message.conversation.trim();
839
+ }
840
+ // Extended text message
841
+ if (message.extendedTextMessage?.text) {
842
+ return message.extendedTextMessage.text.trim();
843
+ }
844
+ // Image/video/document caption
845
+ const caption = message.imageMessage?.caption ||
846
+ message.videoMessage?.caption ||
847
+ message.documentMessage?.caption;
848
+ if (caption)
849
+ return caption.trim();
850
+ return undefined;
851
+ }
852
+ /**
853
+ * Extract media placeholder from message
854
+ */
855
+ extractMediaPlaceholder(message) {
856
+ if (!message)
857
+ return undefined;
858
+ if (message.imageMessage)
859
+ return '<media:image>';
860
+ if (message.videoMessage)
861
+ return '<media:video>';
862
+ if (message.audioMessage)
863
+ return '<media:audio>';
864
+ if (message.documentMessage)
865
+ return '<media:document>';
866
+ if (message.stickerMessage)
867
+ return '<media:sticker>';
868
+ if (message.contactMessage)
869
+ return '<contact>';
870
+ if (message.locationMessage)
871
+ return '<location>';
872
+ return undefined;
873
+ }
874
+ /**
875
+ * Download audio from a WhatsApp message and return as attachment
876
+ */
877
+ async downloadAudioAttachment(message) {
878
+ const audioMessage = message.audioMessage;
879
+ if (!audioMessage)
880
+ return null;
881
+ try {
882
+ console.log('[WhatsApp] Downloading audio message...');
883
+ // Download the audio content
884
+ const stream = await (0, baileys_1.downloadContentFromMessage)(audioMessage, 'audio');
885
+ // Collect the stream into a buffer
886
+ const chunks = [];
887
+ for await (const chunk of stream) {
888
+ chunks.push(chunk);
889
+ }
890
+ const audioBuffer = Buffer.concat(chunks);
891
+ console.log(`[WhatsApp] Downloaded audio: ${audioBuffer.length} bytes`);
892
+ // Determine mime type (usually audio/ogg for voice messages)
893
+ const mimeType = audioMessage.mimetype || 'audio/ogg; codecs=opus';
894
+ const isVoiceNote = audioMessage.ptt === true;
895
+ const fileName = isVoiceNote
896
+ ? `voice_message_${Date.now()}.ogg`
897
+ : `audio_${Date.now()}.${this.getAudioExtension(mimeType)}`;
898
+ return {
899
+ type: 'audio',
900
+ data: audioBuffer,
901
+ mimeType,
902
+ fileName,
903
+ size: audioBuffer.length,
904
+ };
905
+ }
906
+ catch (error) {
907
+ console.error('[WhatsApp] Failed to download audio:', error);
908
+ return null;
909
+ }
910
+ }
911
+ /**
912
+ * Get file extension from mime type
913
+ */
914
+ getAudioExtension(mimeType) {
915
+ if (mimeType.includes('ogg'))
916
+ return 'ogg';
917
+ if (mimeType.includes('mp3') || mimeType.includes('mpeg'))
918
+ return 'mp3';
919
+ if (mimeType.includes('wav'))
920
+ return 'wav';
921
+ if (mimeType.includes('m4a') || mimeType.includes('mp4'))
922
+ return 'm4a';
923
+ if (mimeType.includes('webm'))
924
+ return 'webm';
925
+ return 'audio';
926
+ }
927
+ /**
928
+ * Get status code from disconnect error
929
+ */
930
+ getStatusCode(err) {
931
+ if (!err)
932
+ return undefined;
933
+ const asAny = err;
934
+ return (asAny?.output?.statusCode ||
935
+ asAny?.status ||
936
+ undefined);
937
+ }
938
+ /**
939
+ * Ensure directory exists
940
+ */
941
+ async ensureDir(dirPath) {
942
+ if (!fs.existsSync(dirPath)) {
943
+ fs.mkdirSync(dirPath, { recursive: true });
944
+ }
945
+ }
946
+ }
947
+ exports.WhatsAppAdapter = WhatsAppAdapter;
948
+ /**
949
+ * Create a WhatsApp adapter from configuration
950
+ */
951
+ function createWhatsAppAdapter(config) {
952
+ return new WhatsAppAdapter(config);
953
+ }