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,337 @@
1
+ /**
2
+ * Sandbox Factory
3
+ *
4
+ * Provides a unified interface for sandbox implementations and factory
5
+ * function to create the appropriate sandbox based on platform and availability.
6
+ *
7
+ * Supports:
8
+ * - macOS sandbox-exec (native, preferred on macOS)
9
+ * - Docker containers (cross-platform)
10
+ * - No sandbox (fallback)
11
+ */
12
+
13
+ import { Workspace } from '../../../shared/types';
14
+ import { MacOSSandbox } from './macos-sandbox';
15
+ import { DockerSandbox } from './docker-sandbox';
16
+ import { spawn } from 'child_process';
17
+ import { createSecureTempFile } from './security-utils';
18
+
19
+ /**
20
+ * Sandbox type enumeration
21
+ */
22
+ export type SandboxType = 'macos' | 'docker' | 'none';
23
+
24
+ /**
25
+ * Sandbox execution options
26
+ */
27
+ export interface SandboxOptions {
28
+ /** Working directory for command execution */
29
+ cwd?: string;
30
+ /** Command execution timeout in milliseconds */
31
+ timeout?: number;
32
+ /** Maximum output size in bytes */
33
+ maxOutputSize?: number;
34
+ /** Allow network access */
35
+ allowNetwork?: boolean;
36
+ /** Additional allowed paths for read access */
37
+ allowedReadPaths?: string[];
38
+ /** Additional allowed paths for write access */
39
+ allowedWritePaths?: string[];
40
+ /** Environment variables to pass through */
41
+ envPassthrough?: string[];
42
+ }
43
+
44
+ /**
45
+ * Sandbox execution result
46
+ */
47
+ export interface SandboxResult {
48
+ exitCode: number;
49
+ stdout: string;
50
+ stderr: string;
51
+ killed: boolean;
52
+ timedOut: boolean;
53
+ error?: string;
54
+ }
55
+
56
+ /**
57
+ * Unified sandbox interface
58
+ * All sandbox implementations must implement this interface
59
+ */
60
+ export interface ISandbox {
61
+ /** The type of sandbox implementation */
62
+ readonly type: SandboxType;
63
+
64
+ /**
65
+ * Initialize the sandbox environment
66
+ * Must be called before execute()
67
+ */
68
+ initialize(): Promise<void>;
69
+
70
+ /**
71
+ * Execute a command in the sandbox
72
+ */
73
+ execute(
74
+ command: string,
75
+ args?: string[],
76
+ options?: SandboxOptions
77
+ ): Promise<SandboxResult>;
78
+
79
+ /**
80
+ * Execute code in the sandbox (Python or JavaScript)
81
+ */
82
+ executeCode(
83
+ code: string,
84
+ language: 'python' | 'javascript'
85
+ ): Promise<SandboxResult>;
86
+
87
+ /**
88
+ * Cleanup sandbox resources
89
+ */
90
+ cleanup(): void;
91
+ }
92
+
93
+ /**
94
+ * No-op sandbox implementation for when sandboxing is unavailable
95
+ * Still enforces timeouts and output limits, but no OS-level isolation
96
+ */
97
+ export class NoSandbox implements ISandbox {
98
+ readonly type: SandboxType = 'none';
99
+ private workspace: Workspace;
100
+
101
+ constructor(workspace: Workspace) {
102
+ this.workspace = workspace;
103
+ }
104
+
105
+ async initialize(): Promise<void> {
106
+ // No initialization needed
107
+ }
108
+
109
+ async execute(
110
+ command: string,
111
+ args: string[] = [],
112
+ options: SandboxOptions = {}
113
+ ): Promise<SandboxResult> {
114
+ const timeout = options.timeout ?? 5 * 60 * 1000;
115
+ const maxOutputSize = options.maxOutputSize ?? 100 * 1024;
116
+ const cwd = options.cwd || this.workspace.path;
117
+
118
+ return new Promise((resolve) => {
119
+ let stdout = '';
120
+ let stderr = '';
121
+ let killed = false;
122
+ let timedOut = false;
123
+
124
+ const proc = spawn('/bin/sh', ['-c', `${command} ${args.join(' ')}`], {
125
+ cwd,
126
+ shell: true,
127
+ stdio: ['ignore', 'pipe', 'pipe'],
128
+ });
129
+
130
+ const timeoutHandle = setTimeout(() => {
131
+ timedOut = true;
132
+ killed = true;
133
+ proc.kill('SIGKILL');
134
+ }, timeout);
135
+
136
+ proc.stdout?.on('data', (data: Buffer) => {
137
+ const chunk = data.toString();
138
+ if (stdout.length + chunk.length <= maxOutputSize) {
139
+ stdout += chunk;
140
+ } else if (stdout.length < maxOutputSize) {
141
+ stdout += chunk.slice(0, maxOutputSize - stdout.length);
142
+ stdout += '\n[Output truncated]';
143
+ }
144
+ });
145
+
146
+ proc.stderr?.on('data', (data: Buffer) => {
147
+ const chunk = data.toString();
148
+ if (stderr.length + chunk.length <= maxOutputSize) {
149
+ stderr += chunk;
150
+ } else if (stderr.length < maxOutputSize) {
151
+ stderr += chunk.slice(0, maxOutputSize - stderr.length);
152
+ stderr += '\n[Output truncated]';
153
+ }
154
+ });
155
+
156
+ proc.on('close', (code) => {
157
+ clearTimeout(timeoutHandle);
158
+ resolve({
159
+ exitCode: code ?? 1,
160
+ stdout,
161
+ stderr,
162
+ killed,
163
+ timedOut,
164
+ });
165
+ });
166
+
167
+ proc.on('error', (err) => {
168
+ clearTimeout(timeoutHandle);
169
+ resolve({
170
+ exitCode: 1,
171
+ stdout,
172
+ stderr: err.message,
173
+ killed,
174
+ timedOut,
175
+ error: err.message,
176
+ });
177
+ });
178
+ });
179
+ }
180
+
181
+ async executeCode(
182
+ code: string,
183
+ language: 'python' | 'javascript'
184
+ ): Promise<SandboxResult> {
185
+ const ext = language === 'python' ? '.py' : '.js';
186
+ const { filePath, cleanup } = createSecureTempFile(ext, code);
187
+
188
+ try {
189
+ const interpreter = language === 'python' ? 'python3' : 'node';
190
+ return await this.execute(interpreter, [filePath], {
191
+ timeout: 60 * 1000,
192
+ allowNetwork: false,
193
+ });
194
+ } finally {
195
+ cleanup();
196
+ }
197
+ }
198
+
199
+ cleanup(): void {
200
+ // No cleanup needed
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Cached Docker availability status
206
+ */
207
+ let dockerAvailable: boolean | null = null;
208
+ let dockerCheckPromise: Promise<boolean> | null = null;
209
+
210
+ /**
211
+ * Check if Docker is available and running
212
+ */
213
+ export async function isDockerAvailable(): Promise<boolean> {
214
+ // Return cached result if available
215
+ if (dockerAvailable !== null) {
216
+ return dockerAvailable;
217
+ }
218
+
219
+ // Return existing promise if check is in progress
220
+ if (dockerCheckPromise) {
221
+ return dockerCheckPromise;
222
+ }
223
+
224
+ dockerCheckPromise = new Promise((resolve) => {
225
+ const proc = spawn('docker', ['info'], {
226
+ stdio: ['ignore', 'pipe', 'pipe'],
227
+ });
228
+
229
+ let resolved = false;
230
+
231
+ const timeout = setTimeout(() => {
232
+ if (!resolved) {
233
+ resolved = true;
234
+ proc.kill();
235
+ dockerAvailable = false;
236
+ resolve(false);
237
+ }
238
+ }, 5000);
239
+
240
+ proc.on('close', (code) => {
241
+ clearTimeout(timeout);
242
+ if (!resolved) {
243
+ resolved = true;
244
+ dockerAvailable = code === 0;
245
+ resolve(dockerAvailable);
246
+ }
247
+ });
248
+
249
+ proc.on('error', () => {
250
+ clearTimeout(timeout);
251
+ if (!resolved) {
252
+ resolved = true;
253
+ dockerAvailable = false;
254
+ resolve(false);
255
+ }
256
+ });
257
+ });
258
+
259
+ return dockerCheckPromise;
260
+ }
261
+
262
+ /**
263
+ * Detect the best available sandbox type for the current platform
264
+ */
265
+ export async function detectAvailableSandbox(): Promise<SandboxType> {
266
+ // On macOS, prefer native sandbox-exec
267
+ if (process.platform === 'darwin') {
268
+ return 'macos';
269
+ }
270
+
271
+ // On other platforms, check for Docker
272
+ if (await isDockerAvailable()) {
273
+ return 'docker';
274
+ }
275
+
276
+ // Fallback to no sandbox
277
+ return 'none';
278
+ }
279
+
280
+ /**
281
+ * Create a sandbox instance for the given workspace
282
+ *
283
+ * @param workspace - The workspace to create a sandbox for
284
+ * @param preferredType - Optional preferred sandbox type (overrides auto-detection)
285
+ * @returns An initialized sandbox instance
286
+ */
287
+ export async function createSandbox(
288
+ workspace: Workspace,
289
+ preferredType?: SandboxType | 'auto'
290
+ ): Promise<ISandbox> {
291
+ let sandboxType: SandboxType;
292
+
293
+ if (preferredType && preferredType !== 'auto') {
294
+ // Validate the preferred type is available
295
+ if (preferredType === 'macos' && process.platform !== 'darwin') {
296
+ console.warn(
297
+ 'macOS sandbox requested but not on macOS, falling back to auto-detect'
298
+ );
299
+ sandboxType = await detectAvailableSandbox();
300
+ } else if (preferredType === 'docker' && !(await isDockerAvailable())) {
301
+ console.warn(
302
+ 'Docker sandbox requested but Docker not available, falling back to auto-detect'
303
+ );
304
+ sandboxType = await detectAvailableSandbox();
305
+ } else {
306
+ sandboxType = preferredType;
307
+ }
308
+ } else {
309
+ sandboxType = await detectAvailableSandbox();
310
+ }
311
+
312
+ let sandbox: ISandbox;
313
+
314
+ switch (sandboxType) {
315
+ case 'macos':
316
+ sandbox = new MacOSSandbox(workspace);
317
+ break;
318
+ case 'docker':
319
+ sandbox = new DockerSandbox(workspace);
320
+ break;
321
+ case 'none':
322
+ default:
323
+ sandbox = new NoSandbox(workspace);
324
+ break;
325
+ }
326
+
327
+ await sandbox.initialize();
328
+ return sandbox;
329
+ }
330
+
331
+ /**
332
+ * Reset Docker availability cache (useful for testing or after Docker installation)
333
+ */
334
+ export function resetDockerCache(): void {
335
+ dockerAvailable = null;
336
+ dockerCheckPromise = null;
337
+ }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Security Utilities for Sandbox Operations
3
+ *
4
+ * Provides secure implementations for common operations:
5
+ * - Secure temp file creation (TOCTOU-safe)
6
+ * - Path validation with symlink resolution
7
+ * - String escaping for sandbox profiles
8
+ */
9
+
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import * as os from 'os';
13
+ import * as crypto from 'crypto';
14
+
15
+ /**
16
+ * Create a secure temporary file with random name
17
+ * Uses crypto.randomBytes to prevent predictable filenames (TOCTOU mitigation)
18
+ *
19
+ * @param extension - File extension (e.g., '.py', '.js')
20
+ * @param content - Content to write to the file
21
+ * @returns Object with file path and cleanup function
22
+ */
23
+ export function createSecureTempFile(
24
+ extension: string,
25
+ content: string
26
+ ): { filePath: string; cleanup: () => void } {
27
+ // Generate cryptographically random filename
28
+ const randomBytes = crypto.randomBytes(16).toString('hex');
29
+ const filename = `cowork_${randomBytes}${extension}`;
30
+ const tempDir = os.tmpdir();
31
+
32
+ // Validate temp directory exists and is writable
33
+ if (!fs.existsSync(tempDir)) {
34
+ throw new Error(`Temp directory does not exist: ${tempDir}`);
35
+ }
36
+
37
+ const filePath = path.join(tempDir, filename);
38
+
39
+ // Use O_CREAT | O_EXCL to atomically create file (fails if exists)
40
+ // This prevents TOCTOU race conditions
41
+ const fd = fs.openSync(filePath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY, 0o600);
42
+ try {
43
+ fs.writeSync(fd, content, 0, 'utf8');
44
+ } finally {
45
+ fs.closeSync(fd);
46
+ }
47
+
48
+ const cleanup = () => {
49
+ try {
50
+ if (fs.existsSync(filePath)) {
51
+ fs.unlinkSync(filePath);
52
+ }
53
+ } catch {
54
+ // Ignore cleanup errors
55
+ }
56
+ };
57
+
58
+ return { filePath, cleanup };
59
+ }
60
+
61
+ /**
62
+ * Validate and resolve a path, following symlinks
63
+ * Returns null if path is outside allowed boundaries
64
+ *
65
+ * @param targetPath - Path to validate
66
+ * @param allowedBasePaths - List of allowed base paths
67
+ * @returns Resolved real path or null if invalid/outside boundaries
68
+ */
69
+ export function validateAndResolvePath(
70
+ targetPath: string,
71
+ allowedBasePaths: string[]
72
+ ): string | null {
73
+ // Reject paths with null bytes (path traversal attack vector)
74
+ if (targetPath.includes('\0')) {
75
+ return null;
76
+ }
77
+
78
+ // Normalize the path first
79
+ const normalizedTarget = path.normalize(targetPath);
80
+
81
+ // Check if path exists before attempting to resolve symlinks
82
+ if (!fs.existsSync(normalizedTarget)) {
83
+ // For non-existent paths, just validate against normalized path
84
+ for (const basePath of allowedBasePaths) {
85
+ const normalizedBase = path.resolve(basePath);
86
+ if (path.resolve(normalizedTarget).startsWith(normalizedBase + path.sep) ||
87
+ path.resolve(normalizedTarget) === normalizedBase) {
88
+ return path.resolve(normalizedTarget);
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+
94
+ try {
95
+ // Resolve symlinks to get real path
96
+ const realPath = fs.realpathSync(normalizedTarget);
97
+
98
+ // Check if real path is within allowed boundaries
99
+ for (const basePath of allowedBasePaths) {
100
+ const realBasePath = fs.existsSync(basePath)
101
+ ? fs.realpathSync(basePath)
102
+ : path.resolve(basePath);
103
+
104
+ if (realPath.startsWith(realBasePath + path.sep) || realPath === realBasePath) {
105
+ return realPath;
106
+ }
107
+ }
108
+
109
+ return null;
110
+ } catch {
111
+ // If we can't resolve the path, it's not valid
112
+ return null;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Escape a string for use in macOS sandbox-exec profile
118
+ * Prevents sandbox profile injection attacks
119
+ *
120
+ * @param input - String to escape
121
+ * @returns Escaped string safe for sandbox profile
122
+ */
123
+ export function escapeSandboxProfileString(input: string): string {
124
+ // Validate input doesn't contain null bytes
125
+ if (input.includes('\0')) {
126
+ throw new Error('Path contains null byte, which is not allowed');
127
+ }
128
+
129
+ // Escape characters that have special meaning in sandbox profiles:
130
+ // - Backslash: escape character
131
+ // - Double quote: string delimiter
132
+ // - Parentheses: LISP-like syntax
133
+ // - Semicolon: comment start
134
+ return input
135
+ .replace(/\\/g, '\\\\') // Escape backslashes first
136
+ .replace(/"/g, '\\"') // Escape double quotes
137
+ .replace(/\(/g, '\\(') // Escape open paren
138
+ .replace(/\)/g, '\\)') // Escape close paren
139
+ .replace(/;/g, '\\;'); // Escape semicolons
140
+ }
141
+
142
+ /**
143
+ * Validate a path is safe for sandbox profile inclusion
144
+ * Rejects paths with dangerous characters that could break profile syntax
145
+ *
146
+ * @param pathToValidate - Path to validate
147
+ * @returns true if safe, throws error if not
148
+ */
149
+ export function validatePathForSandboxProfile(pathToValidate: string): boolean {
150
+ // Check for null bytes
151
+ if (pathToValidate.includes('\0')) {
152
+ throw new Error('Path contains null byte');
153
+ }
154
+
155
+ // Check for newlines (could inject new profile lines)
156
+ if (pathToValidate.includes('\n') || pathToValidate.includes('\r')) {
157
+ throw new Error('Path contains newline characters');
158
+ }
159
+
160
+ // Validate path is absolute and normalized
161
+ if (!path.isAbsolute(pathToValidate)) {
162
+ throw new Error('Path must be absolute');
163
+ }
164
+
165
+ return true;
166
+ }
167
+
168
+ /**
169
+ * Escape a value for Docker environment variable
170
+ * Prevents command injection through environment variables
171
+ *
172
+ * @param value - Environment variable value to escape
173
+ * @returns Escaped value safe for Docker -e flag
174
+ */
175
+ export function escapeDockerEnvValue(value: string): string {
176
+ // Reject values with null bytes
177
+ if (value.includes('\0')) {
178
+ throw new Error('Environment value contains null byte');
179
+ }
180
+
181
+ // For Docker, we need to handle shell metacharacters
182
+ // The safest approach is to reject problematic characters
183
+ // or use Docker's --env-file feature for complex values
184
+
185
+ // Check for newlines which could inject additional arguments
186
+ if (value.includes('\n') || value.includes('\r')) {
187
+ throw new Error('Environment value contains newline characters');
188
+ }
189
+
190
+ return value;
191
+ }
192
+
193
+ /**
194
+ * Validate an environment variable name is safe
195
+ *
196
+ * @param name - Environment variable name
197
+ * @returns true if valid, throws if not
198
+ */
199
+ export function validateEnvVarName(name: string): boolean {
200
+ // Standard env var naming: alphanumeric and underscore, starting with letter or underscore
201
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
202
+ throw new Error(`Invalid environment variable name: ${name}`);
203
+ }
204
+
205
+ // Blacklist dangerous environment variables that could affect sandboxed processes
206
+ const dangerousVars = [
207
+ 'LD_PRELOAD',
208
+ 'LD_LIBRARY_PATH',
209
+ 'DYLD_INSERT_LIBRARIES',
210
+ 'DYLD_LIBRARY_PATH',
211
+ 'PYTHONPATH',
212
+ 'NODE_OPTIONS',
213
+ 'NODE_PATH',
214
+ 'PERL5OPT',
215
+ 'RUBYOPT',
216
+ ];
217
+
218
+ if (dangerousVars.includes(name.toUpperCase())) {
219
+ throw new Error(`Dangerous environment variable not allowed: ${name}`);
220
+ }
221
+
222
+ return true;
223
+ }
224
+
225
+ /**
226
+ * Safe environment passthrough that validates and filters variables
227
+ *
228
+ * @param requestedVars - List of environment variable names to pass through
229
+ * @returns Record of safe environment variables
230
+ */
231
+ export function buildSafeEnvironment(
232
+ requestedVars: string[]
233
+ ): Record<string, string | undefined> {
234
+ const safeEnv: Record<string, string | undefined> = {};
235
+
236
+ for (const name of requestedVars) {
237
+ try {
238
+ validateEnvVarName(name);
239
+ const value = process.env[name];
240
+ if (value !== undefined) {
241
+ escapeDockerEnvValue(value); // Validates value is safe
242
+ safeEnv[name] = value;
243
+ }
244
+ } catch {
245
+ // Skip invalid or dangerous variables silently
246
+ console.warn(`[SecurityUtils] Skipping unsafe environment variable: ${name}`);
247
+ }
248
+ }
249
+
250
+ return safeEnv;
251
+ }