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,719 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.FileTools = void 0;
40
+ const fs = __importStar(require("fs/promises"));
41
+ const path = __importStar(require("path"));
42
+ const electron_1 = require("electron");
43
+ const guardrail_manager_1 = require("../../guardrails/guardrail-manager");
44
+ const mammoth_1 = __importDefault(require("mammoth"));
45
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
46
+ const pdfParseModule = require('pdf-parse');
47
+ // Handle both ESM default export and CommonJS module.exports
48
+ const pdfParse = (typeof pdfParseModule === 'function' ? pdfParseModule : pdfParseModule.default);
49
+ // Limits to prevent context overflow
50
+ const MAX_FILE_SIZE = 100 * 1024; // 100KB max for file reads
51
+ const MAX_DIR_ENTRIES = 100; // Max files to list per directory
52
+ const MAX_SEARCH_RESULTS = 50; // Max search results
53
+ const MAX_NAME_PAD = 48; // Cap for aligned directory listings
54
+ /**
55
+ * FileTools implements safe file operations within the workspace
56
+ */
57
+ class FileTools {
58
+ constructor(workspace, daemon, taskId) {
59
+ this.workspace = workspace;
60
+ this.daemon = daemon;
61
+ this.taskId = taskId;
62
+ }
63
+ /**
64
+ * Update the workspace for this tool
65
+ */
66
+ setWorkspace(workspace) {
67
+ this.workspace = workspace;
68
+ }
69
+ /**
70
+ * Check if a path is in a protected system location
71
+ */
72
+ isProtectedPath(absolutePath) {
73
+ const normalizedPath = path.normalize(absolutePath).toLowerCase();
74
+ return FileTools.PROTECTED_PATHS.some(protectedPath => normalizedPath.startsWith(protectedPath.toLowerCase()));
75
+ }
76
+ /**
77
+ * Check if path is allowed based on allowedPaths configuration
78
+ */
79
+ isPathAllowed(absolutePath) {
80
+ const allowedPaths = this.workspace.permissions.allowedPaths;
81
+ if (!allowedPaths || allowedPaths.length === 0) {
82
+ return false;
83
+ }
84
+ const normalizedPath = path.normalize(absolutePath);
85
+ return allowedPaths.some(allowed => {
86
+ const normalizedAllowed = path.normalize(allowed);
87
+ // Check if the path starts with or equals an allowed path
88
+ return normalizedPath === normalizedAllowed ||
89
+ normalizedPath.startsWith(normalizedAllowed + path.sep);
90
+ });
91
+ }
92
+ /**
93
+ * Resolve path, supporting both workspace-relative and absolute paths
94
+ * When unrestrictedFileAccess is enabled, allows absolute paths anywhere (except protected locations)
95
+ * When allowedPaths is configured, allows specific paths outside workspace
96
+ */
97
+ resolvePath(inputPath, operation = 'read') {
98
+ const normalizedWorkspace = path.resolve(this.workspace.path);
99
+ // Handle absolute paths
100
+ if (path.isAbsolute(inputPath)) {
101
+ const absolutePath = path.normalize(inputPath);
102
+ // Check if it's inside workspace (always allowed)
103
+ const relativeToWorkspace = path.relative(normalizedWorkspace, absolutePath);
104
+ if (!relativeToWorkspace.startsWith('..') && !path.isAbsolute(relativeToWorkspace)) {
105
+ return absolutePath;
106
+ }
107
+ // Outside workspace - check permissions
108
+ if (this.workspace.isTemp || this.workspace.permissions.unrestrictedFileAccess) {
109
+ // With unrestricted access, block protected paths for writes
110
+ if (operation !== 'read' && this.isProtectedPath(absolutePath)) {
111
+ throw new Error(`Cannot ${operation} protected system path: ${absolutePath}`);
112
+ }
113
+ return absolutePath;
114
+ }
115
+ // Check if in allowed paths
116
+ if (this.isPathAllowed(absolutePath)) {
117
+ if (operation !== 'read' && this.isProtectedPath(absolutePath)) {
118
+ throw new Error(`Cannot ${operation} protected system path: ${absolutePath}`);
119
+ }
120
+ return absolutePath;
121
+ }
122
+ throw new Error('Path is outside workspace boundary. Enable "Unrestricted File Access" in workspace settings ' +
123
+ 'or add specific paths to "Allowed Paths" to access files outside the workspace.');
124
+ }
125
+ // Handle relative paths (relative to workspace)
126
+ const resolved = path.resolve(normalizedWorkspace, inputPath);
127
+ const relative = path.relative(normalizedWorkspace, resolved);
128
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
129
+ // Path escapes workspace via ../ traversal
130
+ if (this.workspace.isTemp || this.workspace.permissions.unrestrictedFileAccess) {
131
+ if (operation !== 'read' && this.isProtectedPath(resolved)) {
132
+ throw new Error(`Cannot ${operation} protected system path: ${resolved}`);
133
+ }
134
+ return resolved;
135
+ }
136
+ if (this.isPathAllowed(resolved)) {
137
+ if (operation !== 'read' && this.isProtectedPath(resolved)) {
138
+ throw new Error(`Cannot ${operation} protected system path: ${resolved}`);
139
+ }
140
+ return resolved;
141
+ }
142
+ throw new Error('Path traversal outside workspace is not allowed. Enable "Unrestricted File Access" ' +
143
+ 'in workspace settings to access files outside the workspace.');
144
+ }
145
+ return resolved;
146
+ }
147
+ /**
148
+ * Check if operation is allowed based on permissions
149
+ */
150
+ checkPermission(operation) {
151
+ if (operation === 'read' && !this.workspace.permissions.read) {
152
+ throw new Error('Read permission not granted');
153
+ }
154
+ if (operation === 'write' && !this.workspace.permissions.write) {
155
+ throw new Error('Write permission not granted');
156
+ }
157
+ if (operation === 'delete' && !this.workspace.permissions.delete) {
158
+ throw new Error('Delete permission not granted');
159
+ }
160
+ }
161
+ /**
162
+ * Read file contents (with size limit to prevent context overflow)
163
+ * Supports plain text, DOCX, and PDF files
164
+ */
165
+ async readFile(relativePath) {
166
+ // Validate input
167
+ if (!relativePath || typeof relativePath !== 'string') {
168
+ throw new Error('Invalid path: path must be a non-empty string');
169
+ }
170
+ this.checkPermission('read');
171
+ const fullPath = this.resolvePath(relativePath, 'read');
172
+ const ext = path.extname(fullPath).toLowerCase();
173
+ try {
174
+ const stats = await fs.stat(fullPath);
175
+ // Handle DOCX files
176
+ if (ext === '.docx') {
177
+ return await this.readDocxFile(fullPath, stats.size);
178
+ }
179
+ // Handle PDF files
180
+ if (ext === '.pdf') {
181
+ return await this.readPdfFile(fullPath, stats.size);
182
+ }
183
+ // Handle plain text files
184
+ // Check file size before reading
185
+ if (stats.size > MAX_FILE_SIZE) {
186
+ // Read only the first portion of large files
187
+ const fileHandle = await fs.open(fullPath, 'r');
188
+ try {
189
+ const buffer = Buffer.alloc(MAX_FILE_SIZE);
190
+ await fileHandle.read(buffer, 0, MAX_FILE_SIZE, 0);
191
+ const content = buffer.toString('utf-8');
192
+ return {
193
+ content: content + `\n\n[... File truncated. Showing first ${Math.round(MAX_FILE_SIZE / 1024)}KB of ${Math.round(stats.size / 1024)}KB ...]`,
194
+ size: stats.size,
195
+ truncated: true,
196
+ };
197
+ }
198
+ finally {
199
+ await fileHandle.close();
200
+ }
201
+ }
202
+ const content = await fs.readFile(fullPath, 'utf-8');
203
+ return {
204
+ content,
205
+ size: stats.size,
206
+ };
207
+ }
208
+ catch (error) {
209
+ throw new Error(`Failed to read file: ${error.message}`);
210
+ }
211
+ }
212
+ /**
213
+ * Read DOCX file and extract text content
214
+ */
215
+ async readDocxFile(fullPath, size) {
216
+ try {
217
+ const result = await mammoth_1.default.extractRawText({ path: fullPath });
218
+ let content = result.value;
219
+ // Check if extracted text exceeds limit
220
+ const truncated = content.length > MAX_FILE_SIZE;
221
+ if (truncated) {
222
+ content = content.slice(0, MAX_FILE_SIZE) +
223
+ `\n\n[... Content truncated. Showing first ${Math.round(MAX_FILE_SIZE / 1024)}KB of extracted text ...]`;
224
+ }
225
+ // Add any warnings from mammoth
226
+ if (result.messages && result.messages.length > 0) {
227
+ const warnings = result.messages.map(m => m.message).join('\n');
228
+ content = `[Document warnings: ${warnings}]\n\n${content}`;
229
+ }
230
+ return {
231
+ content,
232
+ size,
233
+ truncated,
234
+ format: 'docx',
235
+ };
236
+ }
237
+ catch (error) {
238
+ throw new Error(`Failed to read DOCX file: ${error.message}`);
239
+ }
240
+ }
241
+ /**
242
+ * Read PDF file and extract text content
243
+ */
244
+ async readPdfFile(fullPath, size) {
245
+ try {
246
+ const dataBuffer = await fs.readFile(fullPath);
247
+ const data = await pdfParse(dataBuffer);
248
+ let content = data.text;
249
+ // Add metadata header
250
+ const metadata = [];
251
+ if (data.numpages)
252
+ metadata.push(`Pages: ${data.numpages}`);
253
+ if (data.info?.Title)
254
+ metadata.push(`Title: ${data.info.Title}`);
255
+ if (data.info?.Author)
256
+ metadata.push(`Author: ${data.info.Author}`);
257
+ if (metadata.length > 0) {
258
+ content = `[PDF Metadata: ${metadata.join(' | ')}]\n\n${content}`;
259
+ }
260
+ // Check if extracted text exceeds limit
261
+ const truncated = content.length > MAX_FILE_SIZE;
262
+ if (truncated) {
263
+ content = content.slice(0, MAX_FILE_SIZE) +
264
+ `\n\n[... Content truncated. Showing first ${Math.round(MAX_FILE_SIZE / 1024)}KB of extracted text ...]`;
265
+ }
266
+ return {
267
+ content,
268
+ size,
269
+ truncated,
270
+ format: 'pdf',
271
+ };
272
+ }
273
+ catch (error) {
274
+ throw new Error(`Failed to read PDF file: ${error.message}`);
275
+ }
276
+ }
277
+ /**
278
+ * Write file contents
279
+ */
280
+ async writeFile(relativePath, content) {
281
+ // Validate inputs before proceeding
282
+ if (!relativePath || typeof relativePath !== 'string') {
283
+ throw new Error('Invalid path: path must be a non-empty string');
284
+ }
285
+ // Check for binary file extensions that shouldn't be written with write_file
286
+ const ext = path.extname(relativePath).toLowerCase();
287
+ const binaryExtensions = ['.docx', '.xlsx', '.pptx', '.pdf', '.zip', '.png', '.jpg', '.jpeg', '.gif', '.mp3', '.mp4', '.exe', '.dmg'];
288
+ if (binaryExtensions.includes(ext)) {
289
+ const suggestions = {
290
+ '.docx': 'Use "create_document" or "edit_document" tool instead',
291
+ '.xlsx': 'Use "create_spreadsheet" tool instead',
292
+ '.pptx': 'Use "create_presentation" tool instead',
293
+ '.pdf': 'Use "create_document" with format="pdf" instead',
294
+ };
295
+ const suggestion = suggestions[ext] || 'Use the appropriate skill tool for binary files';
296
+ throw new Error(`Cannot use write_file for binary file type "${ext}". ` +
297
+ `The write_file tool is for text files only. ${suggestion}.`);
298
+ }
299
+ if (content === undefined || content === null) {
300
+ throw new Error('Invalid content: content parameter is required but was not provided');
301
+ }
302
+ if (typeof content !== 'string') {
303
+ throw new Error(`Invalid content: expected string but received ${typeof content}`);
304
+ }
305
+ this.checkPermission('write');
306
+ const fullPath = this.resolvePath(relativePath, 'write');
307
+ // Check file size against guardrail limits
308
+ const contentSizeBytes = Buffer.byteLength(content, 'utf-8');
309
+ const sizeCheck = guardrail_manager_1.GuardrailManager.isFileSizeExceeded(contentSizeBytes);
310
+ if (sizeCheck.exceeded) {
311
+ throw new Error(`File size limit exceeded: ${sizeCheck.sizeMB.toFixed(2)}MB exceeds limit of ${sizeCheck.limitMB}MB.\n` +
312
+ `You can adjust this limit in Settings > Guardrails.`);
313
+ }
314
+ try {
315
+ // Ensure directory exists
316
+ await fs.mkdir(path.dirname(fullPath), { recursive: true });
317
+ // Write file
318
+ await fs.writeFile(fullPath, content, 'utf-8');
319
+ // Log artifact
320
+ this.daemon.logEvent(this.taskId, 'file_created', {
321
+ path: relativePath,
322
+ size: content.length,
323
+ });
324
+ return {
325
+ success: true,
326
+ path: relativePath,
327
+ };
328
+ }
329
+ catch (error) {
330
+ throw new Error(`Failed to write file: ${error.message}`);
331
+ }
332
+ }
333
+ /**
334
+ * List directory contents (limited to prevent context overflow)
335
+ */
336
+ async listDirectory(relativePath = '.') {
337
+ // Validate and normalize input (use default if null/undefined)
338
+ const pathToUse = (relativePath && typeof relativePath === 'string') ? relativePath : '.';
339
+ this.checkPermission('read');
340
+ const fullPath = this.resolvePath(pathToUse, 'read');
341
+ try {
342
+ const entries = await fs.readdir(fullPath, { withFileTypes: true });
343
+ const totalCount = entries.length;
344
+ // Limit entries to prevent large responses
345
+ const limitedEntries = entries.slice(0, MAX_DIR_ENTRIES);
346
+ const files = await Promise.all(limitedEntries.map(async (entry) => {
347
+ const entryPath = path.join(fullPath, entry.name);
348
+ try {
349
+ const stats = await fs.stat(entryPath);
350
+ return {
351
+ name: entry.name,
352
+ type: entry.isDirectory() ? 'directory' : 'file',
353
+ size: stats.size,
354
+ };
355
+ }
356
+ catch {
357
+ return {
358
+ name: entry.name,
359
+ type: 'file',
360
+ size: 0,
361
+ };
362
+ }
363
+ }));
364
+ return {
365
+ files,
366
+ totalCount,
367
+ truncated: totalCount > MAX_DIR_ENTRIES,
368
+ };
369
+ }
370
+ catch (error) {
371
+ throw new Error(`Failed to list directory: ${error.message}`);
372
+ }
373
+ }
374
+ /**
375
+ * List directory contents in a compact, size-aware format
376
+ * Mirrors MCP filesystem output for easier agent consumption.
377
+ */
378
+ async listDirectoryWithSizes(relativePath = '.') {
379
+ const pathToUse = (relativePath && typeof relativePath === 'string') ? relativePath : '.';
380
+ this.checkPermission('read');
381
+ const fullPath = this.resolvePath(pathToUse, 'read');
382
+ try {
383
+ const entries = await fs.readdir(fullPath, { withFileTypes: true });
384
+ const totalCount = entries.length;
385
+ const limitedEntries = entries.slice(0, MAX_DIR_ENTRIES);
386
+ const files = await Promise.all(limitedEntries.map(async (entry) => {
387
+ const entryPath = path.join(fullPath, entry.name);
388
+ try {
389
+ const stats = await fs.stat(entryPath);
390
+ return {
391
+ name: entry.name,
392
+ type: entry.isDirectory() ? 'directory' : 'file',
393
+ size: stats.size,
394
+ };
395
+ }
396
+ catch {
397
+ return {
398
+ name: entry.name,
399
+ type: entry.isDirectory() ? 'directory' : 'file',
400
+ size: 0,
401
+ };
402
+ }
403
+ }));
404
+ const combinedSize = files.reduce((sum, entry) => sum + (entry.type === 'file' ? entry.size : 0), 0);
405
+ const output = this.formatDirectoryListing(files, combinedSize);
406
+ return {
407
+ output,
408
+ files,
409
+ totalCount,
410
+ truncated: totalCount > MAX_DIR_ENTRIES,
411
+ combinedSize,
412
+ };
413
+ }
414
+ catch (error) {
415
+ throw new Error(`Failed to list directory: ${error.message}`);
416
+ }
417
+ }
418
+ /**
419
+ * Get file or directory metadata
420
+ */
421
+ async getFileInfo(relativePath) {
422
+ if (!relativePath || typeof relativePath !== 'string') {
423
+ throw new Error('Invalid path: path must be a non-empty string');
424
+ }
425
+ this.checkPermission('read');
426
+ const fullPath = this.resolvePath(relativePath, 'read');
427
+ try {
428
+ const stats = await fs.stat(fullPath);
429
+ const permissions = (stats.mode & 0o777).toString(8);
430
+ return {
431
+ size: stats.size,
432
+ created: stats.birthtime.toISOString(),
433
+ modified: stats.mtime.toISOString(),
434
+ accessed: stats.atime.toISOString(),
435
+ isDirectory: stats.isDirectory(),
436
+ isFile: stats.isFile(),
437
+ permissions,
438
+ };
439
+ }
440
+ catch (error) {
441
+ throw new Error(`Failed to get file info: ${error.message}`);
442
+ }
443
+ }
444
+ /**
445
+ * Rename or move file
446
+ */
447
+ async renameFile(oldPath, newPath) {
448
+ // Validate inputs
449
+ if (!oldPath || typeof oldPath !== 'string') {
450
+ throw new Error('Invalid oldPath: must be a non-empty string');
451
+ }
452
+ if (!newPath || typeof newPath !== 'string') {
453
+ throw new Error('Invalid newPath: must be a non-empty string');
454
+ }
455
+ this.checkPermission('write');
456
+ const oldFullPath = this.resolvePath(oldPath, 'write');
457
+ const newFullPath = this.resolvePath(newPath, 'write');
458
+ try {
459
+ // Ensure target directory exists
460
+ await fs.mkdir(path.dirname(newFullPath), { recursive: true });
461
+ await fs.rename(oldFullPath, newFullPath);
462
+ this.daemon.logEvent(this.taskId, 'file_modified', {
463
+ action: 'rename',
464
+ from: oldPath,
465
+ to: newPath,
466
+ });
467
+ return { success: true };
468
+ }
469
+ catch (error) {
470
+ throw new Error(`Failed to rename file: ${error.message}`);
471
+ }
472
+ }
473
+ /**
474
+ * Copy file (supports binary files like DOCX, PDF, images, etc.)
475
+ */
476
+ async copyFile(sourcePath, destPath) {
477
+ // Validate inputs
478
+ if (!sourcePath || typeof sourcePath !== 'string') {
479
+ throw new Error('Invalid sourcePath: must be a non-empty string');
480
+ }
481
+ if (!destPath || typeof destPath !== 'string') {
482
+ throw new Error('Invalid destPath: must be a non-empty string');
483
+ }
484
+ this.checkPermission('read');
485
+ this.checkPermission('write');
486
+ const sourceFullPath = this.resolvePath(sourcePath, 'read');
487
+ const destFullPath = this.resolvePath(destPath, 'write');
488
+ try {
489
+ // Ensure target directory exists
490
+ await fs.mkdir(path.dirname(destFullPath), { recursive: true });
491
+ // Copy file using binary buffer (preserves exact content)
492
+ await fs.copyFile(sourceFullPath, destFullPath);
493
+ this.daemon.logEvent(this.taskId, 'file_created', {
494
+ path: destPath,
495
+ copiedFrom: sourcePath,
496
+ });
497
+ return {
498
+ success: true,
499
+ path: destPath,
500
+ };
501
+ }
502
+ catch (error) {
503
+ throw new Error(`Failed to copy file: ${error.message}`);
504
+ }
505
+ }
506
+ /**
507
+ * Delete file (requires approval)
508
+ * Uses shell.trashItem() for protected locations like /Applications
509
+ * Note: We don't check workspace.permissions.delete here because
510
+ * delete operations always require explicit user approval via requestApproval()
511
+ */
512
+ async deleteFile(relativePath) {
513
+ // Validate input
514
+ if (!relativePath || typeof relativePath !== 'string') {
515
+ throw new Error('Invalid path: path must be a non-empty string');
516
+ }
517
+ const fullPath = this.resolvePath(relativePath, 'delete');
518
+ // Request user approval
519
+ const approved = await this.daemon.requestApproval(this.taskId, 'delete_file', `Delete file: ${relativePath}`, { path: relativePath });
520
+ if (!approved) {
521
+ throw new Error('User denied file deletion');
522
+ }
523
+ try {
524
+ // For .app bundles on macOS, use shell.trashItem directly (safer and expected behavior)
525
+ if (fullPath.endsWith('.app')) {
526
+ await electron_1.shell.trashItem(fullPath);
527
+ this.daemon.logEvent(this.taskId, 'file_deleted', {
528
+ path: relativePath,
529
+ movedToTrash: true,
530
+ });
531
+ return { success: true, movedToTrash: true };
532
+ }
533
+ // For other files/directories, try direct deletion
534
+ const stats = await fs.stat(fullPath);
535
+ if (stats.isDirectory()) {
536
+ // Use force: true to handle read-only files and special cases
537
+ await fs.rm(fullPath, { recursive: true, force: true });
538
+ }
539
+ else {
540
+ await fs.unlink(fullPath);
541
+ }
542
+ this.daemon.logEvent(this.taskId, 'file_deleted', {
543
+ path: relativePath,
544
+ });
545
+ return { success: true };
546
+ }
547
+ catch (error) {
548
+ // If deletion fails, try moving to Trash as fallback
549
+ // This handles EPERM, EACCES, ENOTEMPTY and other filesystem errors
550
+ if (error.code === 'EPERM' || error.code === 'EACCES' || error.code === 'ENOTEMPTY' || error.code === 'EBUSY') {
551
+ try {
552
+ await electron_1.shell.trashItem(fullPath);
553
+ this.daemon.logEvent(this.taskId, 'file_deleted', {
554
+ path: relativePath,
555
+ movedToTrash: true,
556
+ });
557
+ return { success: true, movedToTrash: true };
558
+ }
559
+ catch (trashError) {
560
+ throw new Error(`Failed to delete file: ${error.code}. Could not move to Trash: ${trashError.message}`);
561
+ }
562
+ }
563
+ throw new Error(`Failed to delete file: ${error.message}`);
564
+ }
565
+ }
566
+ /**
567
+ * Create directory
568
+ */
569
+ async createDirectory(relativePath) {
570
+ // Validate input
571
+ if (!relativePath || typeof relativePath !== 'string') {
572
+ throw new Error('Invalid path: path must be a non-empty string');
573
+ }
574
+ this.checkPermission('write');
575
+ const fullPath = this.resolvePath(relativePath, 'write');
576
+ try {
577
+ await fs.mkdir(fullPath, { recursive: true });
578
+ this.daemon.logEvent(this.taskId, 'file_created', {
579
+ path: relativePath,
580
+ type: 'directory',
581
+ });
582
+ return { success: true };
583
+ }
584
+ catch (error) {
585
+ throw new Error(`Failed to create directory: ${error.message}`);
586
+ }
587
+ }
588
+ /**
589
+ * Search files by name or content (limited to prevent context overflow)
590
+ */
591
+ async searchFiles(query, relativePath = '.') {
592
+ // Validate input
593
+ if (!query || typeof query !== 'string') {
594
+ throw new Error('Invalid query: query must be a non-empty string');
595
+ }
596
+ this.checkPermission('read');
597
+ const fullPath = this.resolvePath(relativePath, 'read');
598
+ const matches = [];
599
+ let filesSearched = 0;
600
+ const maxFilesToSearch = 500; // Limit files to search for performance
601
+ const searchRecursive = async (dir) => {
602
+ if (matches.length >= MAX_SEARCH_RESULTS || filesSearched >= maxFilesToSearch) {
603
+ return;
604
+ }
605
+ let entries;
606
+ try {
607
+ entries = await fs.readdir(dir, { withFileTypes: true });
608
+ }
609
+ catch {
610
+ return; // Skip directories we can't read
611
+ }
612
+ for (const entry of entries) {
613
+ if (matches.length >= MAX_SEARCH_RESULTS || filesSearched >= maxFilesToSearch) {
614
+ break;
615
+ }
616
+ const entryPath = path.join(dir, entry.name);
617
+ const relPath = path.relative(this.workspace.path, entryPath);
618
+ // Skip hidden files/directories and node_modules
619
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') {
620
+ continue;
621
+ }
622
+ // Check filename match
623
+ if (entry.name.toLowerCase().includes(query.toLowerCase())) {
624
+ matches.push({
625
+ path: relPath,
626
+ type: 'filename',
627
+ });
628
+ }
629
+ // Search content for small files only
630
+ if (entry.isFile()) {
631
+ filesSearched++;
632
+ try {
633
+ const stats = await fs.stat(entryPath);
634
+ // Only search small text files
635
+ if (stats.size < 50 * 1024) {
636
+ const content = await fs.readFile(entryPath, 'utf-8');
637
+ if (content.toLowerCase().includes(query.toLowerCase())) {
638
+ if (!matches.some(m => m.path === relPath)) {
639
+ matches.push({
640
+ path: relPath,
641
+ type: 'content',
642
+ });
643
+ }
644
+ }
645
+ }
646
+ }
647
+ catch {
648
+ // Skip binary files or files that can't be read
649
+ }
650
+ }
651
+ else if (entry.isDirectory()) {
652
+ await searchRecursive(entryPath);
653
+ }
654
+ }
655
+ };
656
+ try {
657
+ await searchRecursive(fullPath);
658
+ return {
659
+ matches: matches.slice(0, MAX_SEARCH_RESULTS),
660
+ totalFound: matches.length,
661
+ truncated: matches.length >= MAX_SEARCH_RESULTS,
662
+ };
663
+ }
664
+ catch (error) {
665
+ throw new Error(`Search failed: ${error.message}`);
666
+ }
667
+ }
668
+ /**
669
+ * Format directory listing to match MCP-style output
670
+ */
671
+ formatDirectoryListing(entries, combinedSize) {
672
+ const maxNameLength = entries.reduce((max, entry) => Math.max(max, entry.name.length), 0);
673
+ const namePad = Math.min(Math.max(maxNameLength + 2, 16), MAX_NAME_PAD);
674
+ const lines = entries.map(entry => {
675
+ const label = entry.type === 'directory' ? '[DIR]' : '[FILE]';
676
+ const name = entry.name.padEnd(namePad, ' ');
677
+ const size = entry.type === 'file' ? this.formatBytes(entry.size) : '';
678
+ return `${label} ${name}${size}`.trimEnd();
679
+ });
680
+ const fileCount = entries.filter(entry => entry.type === 'file').length;
681
+ const dirCount = entries.filter(entry => entry.type === 'directory').length;
682
+ lines.push('');
683
+ lines.push(`Total: ${fileCount} files, ${dirCount} directories`);
684
+ lines.push(`Combined size: ${this.formatBytes(combinedSize)}`);
685
+ return lines.join('\n');
686
+ }
687
+ /**
688
+ * Human-readable byte formatting
689
+ */
690
+ formatBytes(bytes) {
691
+ if (bytes < 1024)
692
+ return `${bytes} B`;
693
+ const kb = bytes / 1024;
694
+ if (kb < 1024)
695
+ return `${kb.toFixed(2)} KB`;
696
+ const mb = kb / 1024;
697
+ if (mb < 1024)
698
+ return `${mb.toFixed(2)} MB`;
699
+ const gb = mb / 1024;
700
+ return `${gb.toFixed(2)} GB`;
701
+ }
702
+ }
703
+ exports.FileTools = FileTools;
704
+ /**
705
+ * Dangerous paths that should never be written to, even with unrestricted access
706
+ */
707
+ FileTools.PROTECTED_PATHS = [
708
+ '/System',
709
+ '/Library',
710
+ '/usr',
711
+ '/bin',
712
+ '/sbin',
713
+ '/etc',
714
+ '/var',
715
+ '/private',
716
+ 'C:\\Windows',
717
+ 'C:\\Program Files',
718
+ 'C:\\Program Files (x86)',
719
+ ];