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,666 @@
1
+ /**
2
+ * Signal Channel Adapter
3
+ *
4
+ * Implements the ChannelAdapter interface for Signal messaging.
5
+ * Uses signal-cli under the hood for communication.
6
+ *
7
+ * Features:
8
+ * - End-to-end encrypted messaging
9
+ * - Message deduplication
10
+ * - Read receipts and typing indicators
11
+ * - Group messaging support
12
+ * - Attachment support
13
+ * - Reaction support
14
+ *
15
+ * Requirements:
16
+ * - signal-cli installed and configured
17
+ * - Phone number registered with Signal
18
+ */
19
+
20
+ import {
21
+ ChannelAdapter,
22
+ ChannelStatus,
23
+ IncomingMessage,
24
+ OutgoingMessage,
25
+ MessageHandler,
26
+ ErrorHandler,
27
+ StatusHandler,
28
+ ChannelInfo,
29
+ SignalConfig,
30
+ MessageAttachment,
31
+ CallbackQuery,
32
+ CallbackQueryHandler,
33
+ } from './types';
34
+ import {
35
+ SignalClient,
36
+ SignalMessage,
37
+ SignalDataMessage,
38
+ SignalAttachment,
39
+ } from './signal-client';
40
+ import * as fs from 'fs';
41
+ import * as path from 'path';
42
+ import * as os from 'os';
43
+
44
+ /**
45
+ * Signal adapter configuration with defaults
46
+ */
47
+ interface SignalAdapterConfig extends SignalConfig {
48
+ /** Poll interval for receiving messages in ms (default: 1000) */
49
+ pollInterval?: number;
50
+ }
51
+
52
+ export class SignalAdapter implements ChannelAdapter {
53
+ readonly type = 'signal' as const;
54
+
55
+ private client: SignalClient | null = null;
56
+ private _status: ChannelStatus = 'disconnected';
57
+ private _botUsername?: string;
58
+ private messageHandlers: MessageHandler[] = [];
59
+ private errorHandlers: ErrorHandler[] = [];
60
+ private statusHandlers: StatusHandler[] = [];
61
+ private callbackQueryHandlers: CallbackQueryHandler[] = [];
62
+ private config: SignalAdapterConfig;
63
+
64
+ // Message deduplication
65
+ private processedMessages: Map<string, number> = new Map();
66
+ private readonly DEDUP_CACHE_TTL = 60000; // 1 minute
67
+ private readonly DEDUP_CACHE_MAX_SIZE = 1000;
68
+ private dedupCleanupTimer?: ReturnType<typeof setInterval>;
69
+
70
+ // Attachments directory
71
+ private attachmentsDir: string;
72
+
73
+ constructor(config: SignalAdapterConfig) {
74
+ this.config = {
75
+ deduplicationEnabled: true,
76
+ sendReadReceipts: true,
77
+ sendTypingIndicators: true,
78
+ maxAttachmentMb: 100,
79
+ pollInterval: 1000,
80
+ trustMode: 'tofu',
81
+ ...config,
82
+ };
83
+
84
+ // Set up attachments directory
85
+ this.attachmentsDir = path.join(os.tmpdir(), 'cowork-signal-attachments');
86
+ if (!fs.existsSync(this.attachmentsDir)) {
87
+ fs.mkdirSync(this.attachmentsDir, { recursive: true });
88
+ }
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 Signal
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 Signal client
111
+ this.client = new SignalClient({
112
+ phoneNumber: this.config.phoneNumber,
113
+ cliPath: this.config.cliPath,
114
+ dataDir: this.config.dataDir,
115
+ mode: this.config.mode,
116
+ socketPath: this.config.socketPath,
117
+ verbose: process.env.NODE_ENV === 'development',
118
+ });
119
+
120
+ // Check installation
121
+ const installCheck = await this.client.checkInstallation();
122
+ if (!installCheck.installed) {
123
+ throw new Error(installCheck.error || 'signal-cli not installed');
124
+ }
125
+ console.log(`signal-cli version: ${installCheck.version}`);
126
+
127
+ // Check registration
128
+ const regCheck = await this.client.checkRegistration();
129
+ if (!regCheck.registered) {
130
+ throw new Error(regCheck.error || 'Phone number not registered');
131
+ }
132
+
133
+ // Set up event handlers
134
+ this.client.on('message', (message: SignalMessage) => {
135
+ this.handleIncomingMessage(message);
136
+ });
137
+
138
+ this.client.on('error', (error: Error) => {
139
+ this.handleError(error, 'client');
140
+ });
141
+
142
+ this.client.on('connected', () => {
143
+ console.log('Signal client connected');
144
+ });
145
+
146
+ this.client.on('disconnected', () => {
147
+ console.log('Signal client disconnected');
148
+ if (this._status === 'connected') {
149
+ this.setStatus('disconnected');
150
+ }
151
+ });
152
+
153
+ // Start receiving messages
154
+ await this.client.startReceiving();
155
+
156
+ // Set bot username to phone number
157
+ this._botUsername = this.config.phoneNumber;
158
+
159
+ // Start deduplication cleanup
160
+ if (this.config.deduplicationEnabled) {
161
+ this.startDedupCleanup();
162
+ }
163
+
164
+ this.setStatus('connected');
165
+ console.log(`Signal adapter connected for ${this.config.phoneNumber}`);
166
+ } catch (error) {
167
+ const err = error instanceof Error ? error : new Error(String(error));
168
+ this.setStatus('error', err);
169
+ throw err;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Disconnect from Signal
175
+ */
176
+ async disconnect(): Promise<void> {
177
+ // Stop dedup cleanup
178
+ if (this.dedupCleanupTimer) {
179
+ clearInterval(this.dedupCleanupTimer);
180
+ this.dedupCleanupTimer = undefined;
181
+ }
182
+
183
+ // Clear caches
184
+ this.processedMessages.clear();
185
+
186
+ // Stop client
187
+ if (this.client) {
188
+ await this.client.stopReceiving();
189
+ this.client = null;
190
+ }
191
+
192
+ this._botUsername = undefined;
193
+ this.setStatus('disconnected');
194
+ }
195
+
196
+ /**
197
+ * Send a message
198
+ */
199
+ async sendMessage(message: OutgoingMessage): Promise<string> {
200
+ if (!this.client || this._status !== 'connected') {
201
+ throw new Error('Signal client is not connected');
202
+ }
203
+
204
+ // Prepare attachments
205
+ const attachmentPaths: string[] = [];
206
+ if (message.attachments) {
207
+ for (const attachment of message.attachments) {
208
+ const filePath = await this.prepareAttachment(attachment);
209
+ if (filePath) {
210
+ attachmentPaths.push(filePath);
211
+ }
212
+ }
213
+ }
214
+
215
+ // Add response prefix if configured
216
+ let text = message.text;
217
+ if (this.config.responsePrefix) {
218
+ text = `${this.config.responsePrefix} ${text}`;
219
+ }
220
+
221
+ // Send the message
222
+ const result = await this.client.sendMessage(message.chatId, text, {
223
+ attachments: attachmentPaths.length > 0 ? attachmentPaths : undefined,
224
+ quote: message.replyTo ? {
225
+ timestamp: parseInt(message.replyTo, 10),
226
+ author: message.chatId,
227
+ } : undefined,
228
+ });
229
+
230
+ return result.timestamp.toString();
231
+ }
232
+
233
+ /**
234
+ * Prepare an attachment for sending
235
+ */
236
+ private async prepareAttachment(attachment: MessageAttachment): Promise<string | null> {
237
+ if (attachment.url && fs.existsSync(attachment.url)) {
238
+ return attachment.url;
239
+ }
240
+
241
+ if (attachment.data) {
242
+ const fileName = attachment.fileName || `attachment_${Date.now()}`;
243
+ const filePath = path.join(this.attachmentsDir, fileName);
244
+ fs.writeFileSync(filePath, attachment.data);
245
+ return filePath;
246
+ }
247
+
248
+ return null;
249
+ }
250
+
251
+ /**
252
+ * Edit a message (not supported by Signal)
253
+ */
254
+ async editMessage(chatId: string, messageId: string, text: string): Promise<void> {
255
+ throw new Error('Signal does not support message editing');
256
+ }
257
+
258
+ /**
259
+ * Delete a message
260
+ */
261
+ async deleteMessage(chatId: string, messageId: string): Promise<void> {
262
+ // Signal supports remote delete but it's complex
263
+ // For now, just log a warning
264
+ console.warn('Signal message deletion not fully implemented');
265
+ }
266
+
267
+ /**
268
+ * Send a document/file
269
+ */
270
+ async sendDocument(chatId: string, filePath: string, caption?: string): Promise<string> {
271
+ if (!this.client || this._status !== 'connected') {
272
+ throw new Error('Signal client is not connected');
273
+ }
274
+
275
+ const text = caption || path.basename(filePath);
276
+ const result = await this.client.sendMessage(chatId, text, {
277
+ attachments: [filePath],
278
+ });
279
+
280
+ return result.timestamp.toString();
281
+ }
282
+
283
+ /**
284
+ * Send a photo/image
285
+ */
286
+ async sendPhoto(chatId: string, filePath: string, caption?: string): Promise<string> {
287
+ return this.sendDocument(chatId, filePath, caption);
288
+ }
289
+
290
+ /**
291
+ * Register a message handler
292
+ */
293
+ onMessage(handler: MessageHandler): void {
294
+ this.messageHandlers.push(handler);
295
+ }
296
+
297
+ /**
298
+ * Register a callback query handler (not supported by Signal)
299
+ */
300
+ onCallbackQuery(handler: CallbackQueryHandler): void {
301
+ this.callbackQueryHandlers.push(handler);
302
+ }
303
+
304
+ /**
305
+ * Answer callback query (not supported by Signal)
306
+ */
307
+ async answerCallbackQuery(queryId: string, text?: string, showAlert?: boolean): Promise<void> {
308
+ // Signal doesn't have inline keyboards
309
+ console.warn('Signal does not support callback queries');
310
+ }
311
+
312
+ /**
313
+ * Register an error handler
314
+ */
315
+ onError(handler: ErrorHandler): void {
316
+ this.errorHandlers.push(handler);
317
+ }
318
+
319
+ /**
320
+ * Register a status change handler
321
+ */
322
+ onStatusChange(handler: StatusHandler): void {
323
+ this.statusHandlers.push(handler);
324
+ }
325
+
326
+ /**
327
+ * Get channel info
328
+ */
329
+ async getInfo(): Promise<ChannelInfo> {
330
+ return {
331
+ type: 'signal',
332
+ status: this._status,
333
+ botId: this.config.phoneNumber,
334
+ botUsername: this.config.phoneNumber,
335
+ botDisplayName: `Signal (${this.config.phoneNumber})`,
336
+ extra: {
337
+ mode: this.config.mode,
338
+ trustMode: this.config.trustMode,
339
+ },
340
+ };
341
+ }
342
+
343
+ // ============================================================================
344
+ // Extended Features
345
+ // ============================================================================
346
+
347
+ /**
348
+ * Send typing indicator
349
+ */
350
+ async sendTyping(chatId: string): Promise<void> {
351
+ if (!this.client || !this.config.sendTypingIndicators) {
352
+ return;
353
+ }
354
+
355
+ try {
356
+ await this.client.sendTyping(chatId);
357
+ } catch (error) {
358
+ // Ignore typing indicator errors
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Stop typing indicator
364
+ */
365
+ async stopTyping(chatId: string): Promise<void> {
366
+ if (!this.client || !this.config.sendTypingIndicators) {
367
+ return;
368
+ }
369
+
370
+ try {
371
+ await this.client.sendTyping(chatId, true);
372
+ } catch (error) {
373
+ // Ignore typing indicator errors
374
+ }
375
+ }
376
+
377
+ /**
378
+ * Add reaction to a message
379
+ */
380
+ async addReaction(chatId: string, messageId: string, emoji: string): Promise<void> {
381
+ if (!this.client || this._status !== 'connected') {
382
+ throw new Error('Signal client is not connected');
383
+ }
384
+
385
+ await this.client.sendReaction(
386
+ chatId,
387
+ emoji,
388
+ chatId, // targetAuthor
389
+ parseInt(messageId, 10)
390
+ );
391
+ }
392
+
393
+ /**
394
+ * Remove reaction from a message
395
+ */
396
+ async removeReaction(chatId: string, messageId: string, emoji: string): Promise<void> {
397
+ if (!this.client || this._status !== 'connected') {
398
+ throw new Error('Signal client is not connected');
399
+ }
400
+
401
+ await this.client.sendReaction(
402
+ chatId,
403
+ emoji,
404
+ chatId, // targetAuthor
405
+ parseInt(messageId, 10),
406
+ true // remove
407
+ );
408
+ }
409
+
410
+ /**
411
+ * Send read receipt
412
+ */
413
+ async sendReadReceipt(sender: string, messageTimestamp: number): Promise<void> {
414
+ if (!this.client || !this.config.sendReadReceipts) {
415
+ return;
416
+ }
417
+
418
+ try {
419
+ await this.client.sendReadReceipt(sender, [messageTimestamp]);
420
+ } catch (error) {
421
+ // Ignore read receipt errors
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Get contacts
427
+ */
428
+ async getContacts(): Promise<Array<{ number: string; name?: string }>> {
429
+ if (!this.client || this._status !== 'connected') {
430
+ throw new Error('Signal client is not connected');
431
+ }
432
+
433
+ return this.client.getContacts();
434
+ }
435
+
436
+ /**
437
+ * Get groups
438
+ */
439
+ async getGroups(): Promise<Array<{ id: string; name: string; members: string[] }>> {
440
+ if (!this.client || this._status !== 'connected') {
441
+ throw new Error('Signal client is not connected');
442
+ }
443
+
444
+ return this.client.getGroups();
445
+ }
446
+
447
+ /**
448
+ * Trust a contact's identity
449
+ */
450
+ async trustIdentity(phoneNumber: string): Promise<void> {
451
+ if (!this.client || this._status !== 'connected') {
452
+ throw new Error('Signal client is not connected');
453
+ }
454
+
455
+ await this.client.trustIdentity(phoneNumber, this.config.trustMode === 'always');
456
+ }
457
+
458
+ // ============================================================================
459
+ // Private Methods
460
+ // ============================================================================
461
+
462
+ /**
463
+ * Handle incoming Signal message
464
+ */
465
+ private async handleIncomingMessage(signalMessage: SignalMessage): Promise<void> {
466
+ const envelope = signalMessage.envelope;
467
+ const dataMessage = envelope.dataMessage;
468
+
469
+ // Skip non-data messages
470
+ if (!dataMessage?.message) {
471
+ return;
472
+ }
473
+
474
+ // Generate message ID from timestamp
475
+ const messageId = envelope.timestamp.toString();
476
+
477
+ // Check for duplicates
478
+ if (this.config.deduplicationEnabled && this.isMessageProcessed(messageId)) {
479
+ console.log(`Skipping duplicate Signal message ${messageId}`);
480
+ return;
481
+ }
482
+
483
+ // Mark as processed
484
+ if (this.config.deduplicationEnabled) {
485
+ this.markMessageProcessed(messageId);
486
+ }
487
+
488
+ // Check access policy
489
+ if (!this.isAllowedSender(envelope.source)) {
490
+ console.log(`Ignoring message from unauthorized sender: ${envelope.source}`);
491
+ return;
492
+ }
493
+
494
+ // Convert to IncomingMessage
495
+ const message: IncomingMessage = {
496
+ messageId,
497
+ channel: 'signal',
498
+ userId: envelope.source,
499
+ userName: envelope.source, // Signal doesn't provide names in messages
500
+ chatId: dataMessage.groupInfo?.groupId || envelope.source,
501
+ text: dataMessage.message,
502
+ timestamp: new Date(envelope.timestamp),
503
+ replyTo: dataMessage.quote?.id?.toString(),
504
+ attachments: this.convertAttachments(dataMessage.attachments),
505
+ raw: signalMessage,
506
+ };
507
+
508
+ // Send read receipt
509
+ if (this.config.sendReadReceipts) {
510
+ await this.sendReadReceipt(envelope.source, envelope.timestamp);
511
+ }
512
+
513
+ // Notify handlers
514
+ for (const handler of this.messageHandlers) {
515
+ try {
516
+ await handler(message);
517
+ } catch (error) {
518
+ console.error('Error in Signal message handler:', error);
519
+ this.handleError(
520
+ error instanceof Error ? error : new Error(String(error)),
521
+ 'messageHandler'
522
+ );
523
+ }
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Convert Signal attachments to MessageAttachment format
529
+ */
530
+ private convertAttachments(attachments?: SignalAttachment[]): MessageAttachment[] | undefined {
531
+ if (!attachments || attachments.length === 0) {
532
+ return undefined;
533
+ }
534
+
535
+ return attachments.map(att => {
536
+ let type: MessageAttachment['type'] = 'file';
537
+
538
+ if (att.contentType.startsWith('image/')) {
539
+ type = 'image';
540
+ } else if (att.contentType.startsWith('audio/')) {
541
+ type = 'audio';
542
+ } else if (att.contentType.startsWith('video/')) {
543
+ type = 'video';
544
+ }
545
+
546
+ return {
547
+ type,
548
+ url: att.localPath,
549
+ mimeType: att.contentType,
550
+ fileName: att.filename,
551
+ size: att.size,
552
+ };
553
+ });
554
+ }
555
+
556
+ /**
557
+ * Check if sender is allowed
558
+ */
559
+ private isAllowedSender(sender: string): boolean {
560
+ // Skip messages from self
561
+ if (sender === this.config.phoneNumber) {
562
+ return false;
563
+ }
564
+
565
+ // Check allowlist if configured
566
+ if (this.config.allowedNumbers && this.config.allowedNumbers.length > 0) {
567
+ // Normalize phone numbers for comparison
568
+ const normalizedSender = sender.replace(/[^+\d]/g, '');
569
+ return this.config.allowedNumbers.some(num => {
570
+ const normalizedNum = num.replace(/[^+\d]/g, '');
571
+ return normalizedSender === normalizedNum || normalizedSender.endsWith(normalizedNum);
572
+ });
573
+ }
574
+
575
+ // Check DM policy
576
+ switch (this.config.dmPolicy) {
577
+ case 'disabled':
578
+ return false;
579
+ case 'allowlist':
580
+ return false; // No allowlist configured
581
+ case 'pairing':
582
+ // TODO: Implement pairing code system
583
+ return true;
584
+ case 'open':
585
+ default:
586
+ return true;
587
+ }
588
+ }
589
+
590
+ /**
591
+ * Check if message was already processed
592
+ */
593
+ private isMessageProcessed(messageId: string): boolean {
594
+ return this.processedMessages.has(messageId);
595
+ }
596
+
597
+ /**
598
+ * Mark message as processed
599
+ */
600
+ private markMessageProcessed(messageId: string): void {
601
+ this.processedMessages.set(messageId, Date.now());
602
+
603
+ // Prevent unbounded growth
604
+ if (this.processedMessages.size > this.DEDUP_CACHE_MAX_SIZE) {
605
+ this.cleanupDedupCache();
606
+ }
607
+ }
608
+
609
+ /**
610
+ * Start periodic dedup cache cleanup
611
+ */
612
+ private startDedupCleanup(): void {
613
+ this.dedupCleanupTimer = setInterval(() => {
614
+ this.cleanupDedupCache();
615
+ }, this.DEDUP_CACHE_TTL);
616
+ }
617
+
618
+ /**
619
+ * Clean up old entries from dedup cache
620
+ */
621
+ private cleanupDedupCache(): void {
622
+ const now = Date.now();
623
+ for (const [messageId, timestamp] of this.processedMessages) {
624
+ if (now - timestamp > this.DEDUP_CACHE_TTL) {
625
+ this.processedMessages.delete(messageId);
626
+ }
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Handle errors
632
+ */
633
+ private handleError(error: Error, context?: string): void {
634
+ for (const handler of this.errorHandlers) {
635
+ try {
636
+ handler(error, context);
637
+ } catch (e) {
638
+ console.error('Error in error handler:', e);
639
+ }
640
+ }
641
+ }
642
+
643
+ /**
644
+ * Set status and notify handlers
645
+ */
646
+ private setStatus(status: ChannelStatus, error?: Error): void {
647
+ this._status = status;
648
+ for (const handler of this.statusHandlers) {
649
+ try {
650
+ handler(status, error);
651
+ } catch (e) {
652
+ console.error('Error in status handler:', e);
653
+ }
654
+ }
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Create a Signal adapter from configuration
660
+ */
661
+ export function createSignalAdapter(config: SignalConfig): SignalAdapter {
662
+ if (!config.phoneNumber) {
663
+ throw new Error('Signal phone number is required');
664
+ }
665
+ return new SignalAdapter(config);
666
+ }