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,356 @@
1
+ import Database from 'better-sqlite3';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { StandupReport, Task, BoardColumn } from '../../shared/types';
4
+
5
+ /**
6
+ * Query for standup reports
7
+ */
8
+ export interface StandupListQuery {
9
+ workspaceId: string;
10
+ limit?: number;
11
+ startDate?: string; // YYYY-MM-DD
12
+ endDate?: string; // YYYY-MM-DD
13
+ }
14
+
15
+ /**
16
+ * Channel configuration for report delivery
17
+ */
18
+ export interface DeliveryConfig {
19
+ channelType: string; // telegram, discord, slack, etc.
20
+ channelId: string;
21
+ }
22
+
23
+ /**
24
+ * Service for generating and managing daily standup reports
25
+ */
26
+ export class StandupReportService {
27
+ constructor(
28
+ private db: Database.Database,
29
+ private deliverToChannel?: (report: StandupReport, config: DeliveryConfig) => Promise<void>
30
+ ) {}
31
+
32
+ /**
33
+ * Generate a standup report for a workspace
34
+ * Aggregates task status from the past 24 hours
35
+ */
36
+ async generateReport(workspaceId: string, date: Date = new Date()): Promise<StandupReport> {
37
+ const reportDate = this.formatDate(date);
38
+ const yesterday = date.getTime() - 24 * 60 * 60 * 1000;
39
+
40
+ // Check if report already exists for this date
41
+ const existing = this.getByDate(workspaceId, reportDate);
42
+ if (existing) {
43
+ return existing;
44
+ }
45
+
46
+ // Get completed tasks (done column, updated in last 24h)
47
+ const completedTasks = this.getTasksByColumn(workspaceId, 'done', yesterday);
48
+
49
+ // Get in-progress tasks
50
+ const inProgressTasks = this.getTasksByColumn(workspaceId, 'in_progress');
51
+
52
+ // Get blocked tasks (status = 'blocked' or 'failed')
53
+ const blockedTasks = this.getBlockedTasks(workspaceId);
54
+
55
+ // Generate summary
56
+ const summary = this.buildSummary(completedTasks, inProgressTasks, blockedTasks);
57
+
58
+ const report: StandupReport = {
59
+ id: uuidv4(),
60
+ workspaceId,
61
+ reportDate,
62
+ completedTaskIds: completedTasks.map(t => t.id),
63
+ inProgressTaskIds: inProgressTasks.map(t => t.id),
64
+ blockedTaskIds: blockedTasks.map(t => t.id),
65
+ summary,
66
+ createdAt: Date.now(),
67
+ };
68
+
69
+ // Save to database
70
+ this.save(report);
71
+
72
+ return report;
73
+ }
74
+
75
+ /**
76
+ * Deliver a standup report to a configured channel
77
+ */
78
+ async deliverReport(report: StandupReport, config: DeliveryConfig): Promise<void> {
79
+ if (!this.deliverToChannel) {
80
+ throw new Error('No delivery handler configured');
81
+ }
82
+
83
+ await this.deliverToChannel(report, config);
84
+
85
+ // Update report with delivery info
86
+ const deliveredToChannel = `${config.channelType}:${config.channelId}`;
87
+ const stmt = this.db.prepare(
88
+ 'UPDATE standup_reports SET delivered_to_channel = ? WHERE id = ?'
89
+ );
90
+ stmt.run(deliveredToChannel, report.id);
91
+ }
92
+
93
+ /**
94
+ * Get the latest standup report for a workspace
95
+ */
96
+ getLatest(workspaceId: string): StandupReport | undefined {
97
+ const stmt = this.db.prepare(`
98
+ SELECT * FROM standup_reports
99
+ WHERE workspace_id = ?
100
+ ORDER BY created_at DESC
101
+ LIMIT 1
102
+ `);
103
+ const row = stmt.get(workspaceId) as any;
104
+ return row ? this.mapRowToReport(row) : undefined;
105
+ }
106
+
107
+ /**
108
+ * Get a standup report by date
109
+ */
110
+ getByDate(workspaceId: string, reportDate: string): StandupReport | undefined {
111
+ const stmt = this.db.prepare(`
112
+ SELECT * FROM standup_reports
113
+ WHERE workspace_id = ? AND report_date = ?
114
+ `);
115
+ const row = stmt.get(workspaceId, reportDate) as any;
116
+ return row ? this.mapRowToReport(row) : undefined;
117
+ }
118
+
119
+ /**
120
+ * List standup reports for a workspace
121
+ */
122
+ list(query: StandupListQuery): StandupReport[] {
123
+ const conditions: string[] = ['workspace_id = ?'];
124
+ const params: any[] = [query.workspaceId];
125
+
126
+ if (query.startDate) {
127
+ conditions.push('report_date >= ?');
128
+ params.push(query.startDate);
129
+ }
130
+
131
+ if (query.endDate) {
132
+ conditions.push('report_date <= ?');
133
+ params.push(query.endDate);
134
+ }
135
+
136
+ let sql = `SELECT * FROM standup_reports WHERE ${conditions.join(' AND ')} ORDER BY report_date DESC`;
137
+
138
+ if (query.limit) {
139
+ sql += ` LIMIT ${query.limit}`;
140
+ }
141
+
142
+ const stmt = this.db.prepare(sql);
143
+ const rows = stmt.all(...params) as any[];
144
+ return rows.map(row => this.mapRowToReport(row));
145
+ }
146
+
147
+ /**
148
+ * Find a report by ID
149
+ */
150
+ findById(id: string): StandupReport | undefined {
151
+ const stmt = this.db.prepare('SELECT * FROM standup_reports WHERE id = ?');
152
+ const row = stmt.get(id) as any;
153
+ return row ? this.mapRowToReport(row) : undefined;
154
+ }
155
+
156
+ /**
157
+ * Delete old reports (cleanup)
158
+ */
159
+ deleteOlderThan(workspaceId: string, daysToKeep: number): number {
160
+ const cutoffDate = new Date();
161
+ cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
162
+ const cutoffStr = this.formatDate(cutoffDate);
163
+
164
+ const stmt = this.db.prepare(
165
+ 'DELETE FROM standup_reports WHERE workspace_id = ? AND report_date < ?'
166
+ );
167
+ const result = stmt.run(workspaceId, cutoffStr);
168
+ return result.changes;
169
+ }
170
+
171
+ /**
172
+ * Format the standup report as a message for delivery
173
+ */
174
+ formatReportMessage(report: StandupReport, tasks: Map<string, Task>): string {
175
+ const lines: string[] = [
176
+ `**Daily Standup Report - ${report.reportDate}**`,
177
+ '',
178
+ ];
179
+
180
+ // Completed section
181
+ if (report.completedTaskIds.length > 0) {
182
+ lines.push('**Completed Today:**');
183
+ for (const taskId of report.completedTaskIds) {
184
+ const task = tasks.get(taskId);
185
+ if (task) {
186
+ lines.push(`- ${task.title}`);
187
+ }
188
+ }
189
+ lines.push('');
190
+ }
191
+
192
+ // In Progress section
193
+ if (report.inProgressTaskIds.length > 0) {
194
+ lines.push('**In Progress:**');
195
+ for (const taskId of report.inProgressTaskIds) {
196
+ const task = tasks.get(taskId);
197
+ if (task) {
198
+ lines.push(`- ${task.title}`);
199
+ }
200
+ }
201
+ lines.push('');
202
+ }
203
+
204
+ // Blocked section
205
+ if (report.blockedTaskIds.length > 0) {
206
+ lines.push('**Blocked:**');
207
+ for (const taskId of report.blockedTaskIds) {
208
+ const task = tasks.get(taskId);
209
+ if (task) {
210
+ lines.push(`- ${task.title}`);
211
+ }
212
+ }
213
+ lines.push('');
214
+ }
215
+
216
+ // Summary
217
+ lines.push('**Summary:**');
218
+ lines.push(report.summary);
219
+
220
+ return lines.join('\n');
221
+ }
222
+
223
+ /**
224
+ * Save a report to the database
225
+ */
226
+ private save(report: StandupReport): void {
227
+ const stmt = this.db.prepare(`
228
+ INSERT INTO standup_reports (
229
+ id, workspace_id, report_date, completed_task_ids,
230
+ in_progress_task_ids, blocked_task_ids, summary,
231
+ delivered_to_channel, created_at
232
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
233
+ `);
234
+
235
+ stmt.run(
236
+ report.id,
237
+ report.workspaceId,
238
+ report.reportDate,
239
+ JSON.stringify(report.completedTaskIds),
240
+ JSON.stringify(report.inProgressTaskIds),
241
+ JSON.stringify(report.blockedTaskIds),
242
+ report.summary,
243
+ report.deliveredToChannel || null,
244
+ report.createdAt
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Get tasks by board column with optional time filter
250
+ */
251
+ private getTasksByColumn(
252
+ workspaceId: string,
253
+ column: BoardColumn,
254
+ updatedAfter?: number
255
+ ): Task[] {
256
+ let sql = `
257
+ SELECT * FROM tasks
258
+ WHERE workspace_id = ? AND board_column = ?
259
+ `;
260
+ const params: any[] = [workspaceId, column];
261
+
262
+ if (updatedAfter) {
263
+ sql += ' AND updated_at >= ?';
264
+ params.push(updatedAfter);
265
+ }
266
+
267
+ sql += ' ORDER BY updated_at DESC';
268
+
269
+ const stmt = this.db.prepare(sql);
270
+ const rows = stmt.all(...params) as any[];
271
+ return rows.map(row => this.mapRowToTask(row));
272
+ }
273
+
274
+ /**
275
+ * Get blocked tasks (status = blocked or failed)
276
+ */
277
+ private getBlockedTasks(workspaceId: string): Task[] {
278
+ const stmt = this.db.prepare(`
279
+ SELECT * FROM tasks
280
+ WHERE workspace_id = ? AND status IN ('blocked', 'failed')
281
+ ORDER BY updated_at DESC
282
+ `);
283
+ const rows = stmt.all(workspaceId) as any[];
284
+ return rows.map(row => this.mapRowToTask(row));
285
+ }
286
+
287
+ /**
288
+ * Build a summary from task lists
289
+ */
290
+ private buildSummary(
291
+ completed: Task[],
292
+ inProgress: Task[],
293
+ blocked: Task[]
294
+ ): string {
295
+ const parts: string[] = [];
296
+
297
+ if (completed.length > 0) {
298
+ parts.push(`${completed.length} task${completed.length === 1 ? '' : 's'} completed`);
299
+ }
300
+
301
+ if (inProgress.length > 0) {
302
+ parts.push(`${inProgress.length} task${inProgress.length === 1 ? '' : 's'} in progress`);
303
+ }
304
+
305
+ if (blocked.length > 0) {
306
+ parts.push(`${blocked.length} task${blocked.length === 1 ? '' : 's'} blocked`);
307
+ }
308
+
309
+ if (parts.length === 0) {
310
+ return 'No task activity today.';
311
+ }
312
+
313
+ return parts.join(', ') + '.';
314
+ }
315
+
316
+ /**
317
+ * Format date as YYYY-MM-DD
318
+ */
319
+ private formatDate(date: Date): string {
320
+ return date.toISOString().split('T')[0];
321
+ }
322
+
323
+ /**
324
+ * Map database row to StandupReport
325
+ */
326
+ private mapRowToReport(row: any): StandupReport {
327
+ return {
328
+ id: row.id,
329
+ workspaceId: row.workspace_id,
330
+ reportDate: row.report_date,
331
+ completedTaskIds: JSON.parse(row.completed_task_ids || '[]'),
332
+ inProgressTaskIds: JSON.parse(row.in_progress_task_ids || '[]'),
333
+ blockedTaskIds: JSON.parse(row.blocked_task_ids || '[]'),
334
+ summary: row.summary,
335
+ deliveredToChannel: row.delivered_to_channel || undefined,
336
+ createdAt: row.created_at,
337
+ };
338
+ }
339
+
340
+ /**
341
+ * Map database row to Task (minimal mapping for standup)
342
+ */
343
+ private mapRowToTask(row: any): Task {
344
+ return {
345
+ id: row.id,
346
+ title: row.title,
347
+ prompt: row.prompt,
348
+ status: row.status,
349
+ workspaceId: row.workspace_id,
350
+ createdAt: row.created_at,
351
+ updatedAt: row.updated_at,
352
+ boardColumn: row.board_column,
353
+ assignedAgentRoleId: row.assigned_agent_role_id,
354
+ };
355
+ }
356
+ }
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Concurrency Safety Module
3
+ *
4
+ * Provides mutex locks and idempotency guarantees for critical operations.
5
+ */
6
+
7
+ /**
8
+ * Simple async mutex for protecting critical sections
9
+ * Prevents race conditions in pairing, approval, and state changes
10
+ */
11
+ export class AsyncMutex {
12
+ private locked = false;
13
+ private queue: Array<() => void> = [];
14
+
15
+ /**
16
+ * Acquire the lock. Returns a release function.
17
+ */
18
+ async acquire(): Promise<() => void> {
19
+ return new Promise((resolve) => {
20
+ const tryAcquire = () => {
21
+ if (!this.locked) {
22
+ this.locked = true;
23
+ resolve(() => this.release());
24
+ } else {
25
+ this.queue.push(tryAcquire);
26
+ }
27
+ };
28
+ tryAcquire();
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Release the lock
34
+ */
35
+ private release(): void {
36
+ this.locked = false;
37
+ const next = this.queue.shift();
38
+ if (next) {
39
+ next();
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Execute a function with the lock held
45
+ */
46
+ async withLock<T>(fn: () => Promise<T>): Promise<T> {
47
+ const release = await this.acquire();
48
+ try {
49
+ return await fn();
50
+ } finally {
51
+ release();
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Check if the lock is currently held
57
+ */
58
+ isLocked(): boolean {
59
+ return this.locked;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Named mutex manager for managing multiple locks by key
65
+ */
66
+ export class NamedMutexManager {
67
+ private mutexes: Map<string, AsyncMutex> = new Map();
68
+
69
+ /**
70
+ * Get or create a mutex for a given key
71
+ */
72
+ getMutex(key: string): AsyncMutex {
73
+ let mutex = this.mutexes.get(key);
74
+ if (!mutex) {
75
+ mutex = new AsyncMutex();
76
+ this.mutexes.set(key, mutex);
77
+ }
78
+ return mutex;
79
+ }
80
+
81
+ /**
82
+ * Execute a function with the named lock held
83
+ */
84
+ async withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {
85
+ return this.getMutex(key).withLock(fn);
86
+ }
87
+
88
+ /**
89
+ * Clean up unused mutexes
90
+ */
91
+ cleanup(): void {
92
+ for (const [key, mutex] of this.mutexes.entries()) {
93
+ if (!mutex.isLocked()) {
94
+ this.mutexes.delete(key);
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Idempotency key entry
102
+ */
103
+ interface IdempotencyEntry {
104
+ key: string;
105
+ result: any;
106
+ createdAt: number;
107
+ expiresAt: number;
108
+ status: 'pending' | 'completed' | 'failed';
109
+ }
110
+
111
+ /**
112
+ * Idempotency Manager
113
+ *
114
+ * Ensures operations are idempotent by tracking operation keys and their results.
115
+ * Implements C6-style approval safety: prevents duplicate approvals/denials.
116
+ */
117
+ export class IdempotencyManager {
118
+ private entries: Map<string, IdempotencyEntry> = new Map();
119
+ private defaultTTLMs: number;
120
+ private cleanupIntervalId?: ReturnType<typeof setInterval>;
121
+
122
+ constructor(defaultTTLMs = 5 * 60 * 1000) { // 5 minutes default
123
+ this.defaultTTLMs = defaultTTLMs;
124
+
125
+ // Periodic cleanup of expired entries
126
+ this.cleanupIntervalId = setInterval(() => {
127
+ this.cleanupExpired();
128
+ }, 60 * 1000); // Every minute
129
+ }
130
+
131
+ /**
132
+ * Generate an idempotency key for an operation
133
+ */
134
+ static generateKey(operation: string, ...args: (string | number | undefined)[]): string {
135
+ const parts = [operation, ...args.filter(a => a !== undefined)];
136
+ return parts.join(':');
137
+ }
138
+
139
+ /**
140
+ * Check if an operation with this key is already in progress or completed
141
+ */
142
+ check(key: string): { exists: boolean; status?: 'pending' | 'completed' | 'failed'; result?: any } {
143
+ const entry = this.entries.get(key);
144
+
145
+ if (!entry) {
146
+ return { exists: false };
147
+ }
148
+
149
+ // Check if expired
150
+ if (Date.now() > entry.expiresAt) {
151
+ this.entries.delete(key);
152
+ return { exists: false };
153
+ }
154
+
155
+ return {
156
+ exists: true,
157
+ status: entry.status,
158
+ result: entry.result,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Start tracking an operation (mark as pending)
164
+ * Returns false if operation is already in progress
165
+ */
166
+ start(key: string, ttlMs?: number): boolean {
167
+ const existing = this.check(key);
168
+
169
+ if (existing.exists) {
170
+ // Already in progress or completed
171
+ return false;
172
+ }
173
+
174
+ const now = Date.now();
175
+ this.entries.set(key, {
176
+ key,
177
+ result: undefined,
178
+ createdAt: now,
179
+ expiresAt: now + (ttlMs || this.defaultTTLMs),
180
+ status: 'pending',
181
+ });
182
+
183
+ return true;
184
+ }
185
+
186
+ /**
187
+ * Mark an operation as completed with its result
188
+ */
189
+ complete(key: string, result: any): void {
190
+ const entry = this.entries.get(key);
191
+ if (entry) {
192
+ entry.status = 'completed';
193
+ entry.result = result;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Mark an operation as failed
199
+ */
200
+ fail(key: string, error?: any): void {
201
+ const entry = this.entries.get(key);
202
+ if (entry) {
203
+ entry.status = 'failed';
204
+ entry.result = error;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Remove an entry (for retry scenarios)
210
+ */
211
+ remove(key: string): void {
212
+ this.entries.delete(key);
213
+ }
214
+
215
+ /**
216
+ * Execute an operation with idempotency guarantee
217
+ * If operation was already completed, returns cached result
218
+ * If operation is in progress, waits and returns result
219
+ */
220
+ async execute<T>(
221
+ key: string,
222
+ operation: () => Promise<T>,
223
+ ttlMs?: number
224
+ ): Promise<{ result: T; cached: boolean }> {
225
+ const existing = this.check(key);
226
+
227
+ if (existing.exists && existing.status === 'completed') {
228
+ return { result: existing.result as T, cached: true };
229
+ }
230
+
231
+ if (existing.exists && existing.status === 'pending') {
232
+ // Wait for completion
233
+ const result = await this.waitForCompletion<T>(key);
234
+ return { result, cached: true };
235
+ }
236
+
237
+ // Start new operation
238
+ if (!this.start(key, ttlMs)) {
239
+ // Race condition: another call started between check and start
240
+ const result = await this.waitForCompletion<T>(key);
241
+ return { result, cached: true };
242
+ }
243
+
244
+ try {
245
+ const result = await operation();
246
+ this.complete(key, result);
247
+ return { result, cached: false };
248
+ } catch (error) {
249
+ this.fail(key, error);
250
+ throw error;
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Wait for a pending operation to complete
256
+ */
257
+ private async waitForCompletion<T>(key: string, timeoutMs = 30000): Promise<T> {
258
+ const startTime = Date.now();
259
+
260
+ while (Date.now() - startTime < timeoutMs) {
261
+ const entry = this.entries.get(key);
262
+
263
+ if (!entry || Date.now() > entry.expiresAt) {
264
+ throw new Error(`Operation ${key} expired or not found`);
265
+ }
266
+
267
+ if (entry.status === 'completed') {
268
+ return entry.result as T;
269
+ }
270
+
271
+ if (entry.status === 'failed') {
272
+ throw entry.result || new Error(`Operation ${key} failed`);
273
+ }
274
+
275
+ // Wait a bit before checking again
276
+ await new Promise(resolve => setTimeout(resolve, 100));
277
+ }
278
+
279
+ throw new Error(`Timeout waiting for operation ${key}`);
280
+ }
281
+
282
+ /**
283
+ * Clean up expired entries
284
+ */
285
+ private cleanupExpired(): void {
286
+ const now = Date.now();
287
+ for (const [key, entry] of this.entries.entries()) {
288
+ if (now > entry.expiresAt) {
289
+ this.entries.delete(key);
290
+ }
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Get statistics about the idempotency cache
296
+ */
297
+ getStats(): { total: number; pending: number; completed: number; failed: number } {
298
+ let pending = 0;
299
+ let completed = 0;
300
+ let failed = 0;
301
+
302
+ for (const entry of this.entries.values()) {
303
+ switch (entry.status) {
304
+ case 'pending': pending++; break;
305
+ case 'completed': completed++; break;
306
+ case 'failed': failed++; break;
307
+ }
308
+ }
309
+
310
+ return {
311
+ total: this.entries.size,
312
+ pending,
313
+ completed,
314
+ failed,
315
+ };
316
+ }
317
+
318
+ /**
319
+ * Clean up and stop background tasks
320
+ */
321
+ destroy(): void {
322
+ if (this.cleanupIntervalId) {
323
+ clearInterval(this.cleanupIntervalId);
324
+ this.cleanupIntervalId = undefined;
325
+ }
326
+ this.entries.clear();
327
+ }
328
+ }
329
+
330
+ // Global instances for common use cases
331
+ export const pairingMutex = new NamedMutexManager();
332
+ export const approvalIdempotency = new IdempotencyManager(5 * 60 * 1000); // 5 min TTL
333
+ export const taskIdempotency = new IdempotencyManager(60 * 1000); // 1 min TTL for task creation
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Security Module
3
+ *
4
+ * Exports all security-related components for the application.
5
+ */
6
+
7
+ export {
8
+ SecurityPolicyManager,
9
+ createPolicyManager,
10
+ isToolAllowedQuick,
11
+ type PolicyCheckResult,
12
+ type PolicyLayer,
13
+ type LayerDecision,
14
+ type PolicyContext,
15
+ } from './policy-manager';
16
+
17
+ export { AsyncMutex, IdempotencyManager } from './concurrency';