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.
- package/LICENSE +21 -0
- package/README.md +1638 -0
- package/bin/cowork.js +42 -0
- package/build/entitlements.mac.plist +16 -0
- package/build/icon.icns +0 -0
- package/build/icon.png +0 -0
- package/dist/electron/electron/activity/ActivityRepository.js +190 -0
- package/dist/electron/electron/agent/browser/browser-service.js +639 -0
- package/dist/electron/electron/agent/context-manager.js +225 -0
- package/dist/electron/electron/agent/custom-skill-loader.js +566 -0
- package/dist/electron/electron/agent/daemon.js +975 -0
- package/dist/electron/electron/agent/executor.js +3561 -0
- package/dist/electron/electron/agent/llm/anthropic-provider.js +155 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +202 -0
- package/dist/electron/electron/agent/llm/gemini-provider.js +375 -0
- package/dist/electron/electron/agent/llm/index.js +34 -0
- package/dist/electron/electron/agent/llm/ollama-provider.js +263 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +101 -0
- package/dist/electron/electron/agent/llm/openai-provider.js +657 -0
- package/dist/electron/electron/agent/llm/openrouter-provider.js +232 -0
- package/dist/electron/electron/agent/llm/pricing.js +160 -0
- package/dist/electron/electron/agent/llm/provider-factory.js +880 -0
- package/dist/electron/electron/agent/llm/types.js +178 -0
- package/dist/electron/electron/agent/queue-manager.js +378 -0
- package/dist/electron/electron/agent/sandbox/docker-sandbox.js +402 -0
- package/dist/electron/electron/agent/sandbox/macos-sandbox.js +407 -0
- package/dist/electron/electron/agent/sandbox/runner.js +410 -0
- package/dist/electron/electron/agent/sandbox/sandbox-factory.js +228 -0
- package/dist/electron/electron/agent/sandbox/security-utils.js +258 -0
- package/dist/electron/electron/agent/search/brave-provider.js +119 -0
- package/dist/electron/electron/agent/search/google-provider.js +100 -0
- package/dist/electron/electron/agent/search/index.js +28 -0
- package/dist/electron/electron/agent/search/provider-factory.js +395 -0
- package/dist/electron/electron/agent/search/serpapi-provider.js +112 -0
- package/dist/electron/electron/agent/search/tavily-provider.js +90 -0
- package/dist/electron/electron/agent/search/types.js +40 -0
- package/dist/electron/electron/agent/security/index.js +12 -0
- package/dist/electron/electron/agent/security/input-sanitizer.js +303 -0
- package/dist/electron/electron/agent/security/output-filter.js +217 -0
- package/dist/electron/electron/agent/skill-eligibility.js +281 -0
- package/dist/electron/electron/agent/skill-registry.js +396 -0
- package/dist/electron/electron/agent/skills/document.js +878 -0
- package/dist/electron/electron/agent/skills/image-generator.js +225 -0
- package/dist/electron/electron/agent/skills/organizer.js +141 -0
- package/dist/electron/electron/agent/skills/presentation.js +367 -0
- package/dist/electron/electron/agent/skills/spreadsheet.js +165 -0
- package/dist/electron/electron/agent/tools/browser-tools.js +523 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +384 -0
- package/dist/electron/electron/agent/tools/canvas-tools.js +530 -0
- package/dist/electron/electron/agent/tools/cron-tools.js +577 -0
- package/dist/electron/electron/agent/tools/edit-tools.js +194 -0
- package/dist/electron/electron/agent/tools/file-tools.js +719 -0
- package/dist/electron/electron/agent/tools/glob-tools.js +283 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +387 -0
- package/dist/electron/electron/agent/tools/image-tools.js +111 -0
- package/dist/electron/electron/agent/tools/mention-tools.js +282 -0
- package/dist/electron/electron/agent/tools/node-tools.js +476 -0
- package/dist/electron/electron/agent/tools/registry.js +2719 -0
- package/dist/electron/electron/agent/tools/search-tools.js +91 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +574 -0
- package/dist/electron/electron/agent/tools/skill-tools.js +274 -0
- package/dist/electron/electron/agent/tools/system-tools.js +578 -0
- package/dist/electron/electron/agent/tools/web-fetch-tools.js +444 -0
- package/dist/electron/electron/agent/tools/x-tools.js +264 -0
- package/dist/electron/electron/agents/AgentRoleRepository.js +420 -0
- package/dist/electron/electron/agents/HeartbeatService.js +356 -0
- package/dist/electron/electron/agents/MentionRepository.js +197 -0
- package/dist/electron/electron/agents/TaskSubscriptionRepository.js +168 -0
- package/dist/electron/electron/agents/WorkingStateRepository.js +229 -0
- package/dist/electron/electron/canvas/canvas-manager.js +714 -0
- package/dist/electron/electron/canvas/canvas-preload.js +53 -0
- package/dist/electron/electron/canvas/canvas-protocol.js +195 -0
- package/dist/electron/electron/canvas/canvas-store.js +174 -0
- package/dist/electron/electron/canvas/index.js +13 -0
- package/dist/electron/electron/control-plane/client.js +364 -0
- package/dist/electron/electron/control-plane/handlers.js +572 -0
- package/dist/electron/electron/control-plane/index.js +41 -0
- package/dist/electron/electron/control-plane/node-manager.js +264 -0
- package/dist/electron/electron/control-plane/protocol.js +194 -0
- package/dist/electron/electron/control-plane/remote-client.js +437 -0
- package/dist/electron/electron/control-plane/server.js +640 -0
- package/dist/electron/electron/control-plane/settings.js +369 -0
- package/dist/electron/electron/control-plane/ssh-tunnel.js +549 -0
- package/dist/electron/electron/cron/index.js +30 -0
- package/dist/electron/electron/cron/schedule.js +190 -0
- package/dist/electron/electron/cron/service.js +614 -0
- package/dist/electron/electron/cron/store.js +155 -0
- package/dist/electron/electron/cron/types.js +82 -0
- package/dist/electron/electron/cron/webhook.js +258 -0
- package/dist/electron/electron/database/SecureSettingsRepository.js +444 -0
- package/dist/electron/electron/database/TaskLabelRepository.js +120 -0
- package/dist/electron/electron/database/repositories.js +1781 -0
- package/dist/electron/electron/database/schema.js +978 -0
- package/dist/electron/electron/extensions/index.js +33 -0
- package/dist/electron/electron/extensions/loader.js +313 -0
- package/dist/electron/electron/extensions/registry.js +485 -0
- package/dist/electron/electron/extensions/types.js +11 -0
- package/dist/electron/electron/gateway/channel-registry.js +1102 -0
- package/dist/electron/electron/gateway/channels/bluebubbles-client.js +479 -0
- package/dist/electron/electron/gateway/channels/bluebubbles.js +432 -0
- package/dist/electron/electron/gateway/channels/discord.js +975 -0
- package/dist/electron/electron/gateway/channels/email-client.js +593 -0
- package/dist/electron/electron/gateway/channels/email.js +443 -0
- package/dist/electron/electron/gateway/channels/google-chat.js +631 -0
- package/dist/electron/electron/gateway/channels/imessage-client.js +363 -0
- package/dist/electron/electron/gateway/channels/imessage.js +465 -0
- package/dist/electron/electron/gateway/channels/index.js +36 -0
- package/dist/electron/electron/gateway/channels/line-client.js +470 -0
- package/dist/electron/electron/gateway/channels/line.js +479 -0
- package/dist/electron/electron/gateway/channels/matrix-client.js +432 -0
- package/dist/electron/electron/gateway/channels/matrix.js +592 -0
- package/dist/electron/electron/gateway/channels/mattermost-client.js +394 -0
- package/dist/electron/electron/gateway/channels/mattermost.js +496 -0
- package/dist/electron/electron/gateway/channels/signal-client.js +500 -0
- package/dist/electron/electron/gateway/channels/signal.js +582 -0
- package/dist/electron/electron/gateway/channels/slack.js +415 -0
- package/dist/electron/electron/gateway/channels/teams.js +596 -0
- package/dist/electron/electron/gateway/channels/telegram.js +1390 -0
- package/dist/electron/electron/gateway/channels/twitch-client.js +502 -0
- package/dist/electron/electron/gateway/channels/twitch.js +396 -0
- package/dist/electron/electron/gateway/channels/types.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +953 -0
- package/dist/electron/electron/gateway/context-policy.js +268 -0
- package/dist/electron/electron/gateway/index.js +1063 -0
- package/dist/electron/electron/gateway/infrastructure.js +496 -0
- package/dist/electron/electron/gateway/router.js +2700 -0
- package/dist/electron/electron/gateway/security.js +375 -0
- package/dist/electron/electron/gateway/session.js +115 -0
- package/dist/electron/electron/gateway/tunnel.js +503 -0
- package/dist/electron/electron/guardrails/guardrail-manager.js +348 -0
- package/dist/electron/electron/hooks/gmail-watcher.js +300 -0
- package/dist/electron/electron/hooks/index.js +46 -0
- package/dist/electron/electron/hooks/mappings.js +381 -0
- package/dist/electron/electron/hooks/server.js +480 -0
- package/dist/electron/electron/hooks/settings.js +447 -0
- package/dist/electron/electron/hooks/types.js +41 -0
- package/dist/electron/electron/ipc/canvas-handlers.js +158 -0
- package/dist/electron/electron/ipc/handlers.js +3138 -0
- package/dist/electron/electron/ipc/mission-control-handlers.js +141 -0
- package/dist/electron/electron/main.js +448 -0
- package/dist/electron/electron/mcp/client/MCPClientManager.js +330 -0
- package/dist/electron/electron/mcp/client/MCPServerConnection.js +437 -0
- package/dist/electron/electron/mcp/client/transports/SSETransport.js +304 -0
- package/dist/electron/electron/mcp/client/transports/StdioTransport.js +307 -0
- package/dist/electron/electron/mcp/client/transports/WebSocketTransport.js +329 -0
- package/dist/electron/electron/mcp/host/MCPHostServer.js +354 -0
- package/dist/electron/electron/mcp/host/ToolAdapter.js +100 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +497 -0
- package/dist/electron/electron/mcp/settings.js +446 -0
- package/dist/electron/electron/mcp/types.js +59 -0
- package/dist/electron/electron/memory/MemoryService.js +435 -0
- package/dist/electron/electron/notifications/index.js +17 -0
- package/dist/electron/electron/notifications/service.js +118 -0
- package/dist/electron/electron/notifications/store.js +144 -0
- package/dist/electron/electron/preload.js +842 -0
- package/dist/electron/electron/reports/StandupReportService.js +272 -0
- package/dist/electron/electron/security/concurrency.js +293 -0
- package/dist/electron/electron/security/index.js +15 -0
- package/dist/electron/electron/security/policy-manager.js +435 -0
- package/dist/electron/electron/settings/appearance-manager.js +193 -0
- package/dist/electron/electron/settings/personality-manager.js +724 -0
- package/dist/electron/electron/settings/x-manager.js +58 -0
- package/dist/electron/electron/tailscale/exposure.js +188 -0
- package/dist/electron/electron/tailscale/index.js +28 -0
- package/dist/electron/electron/tailscale/settings.js +205 -0
- package/dist/electron/electron/tailscale/tailscale.js +355 -0
- package/dist/electron/electron/tray/QuickInputWindow.js +568 -0
- package/dist/electron/electron/tray/TrayManager.js +895 -0
- package/dist/electron/electron/tray/index.js +9 -0
- package/dist/electron/electron/updater/index.js +6 -0
- package/dist/electron/electron/updater/update-manager.js +418 -0
- package/dist/electron/electron/utils/env-migration.js +209 -0
- package/dist/electron/electron/utils/process.js +102 -0
- package/dist/electron/electron/utils/rate-limiter.js +104 -0
- package/dist/electron/electron/utils/validation.js +419 -0
- package/dist/electron/electron/utils/x-cli.js +177 -0
- package/dist/electron/electron/voice/VoiceService.js +507 -0
- package/dist/electron/electron/voice/index.js +14 -0
- package/dist/electron/electron/voice/voice-settings-manager.js +359 -0
- package/dist/electron/shared/channelMessages.js +170 -0
- package/dist/electron/shared/types.js +1185 -0
- package/package.json +159 -0
- package/resources/skills/1password.json +10 -0
- package/resources/skills/add-documentation.json +31 -0
- package/resources/skills/analyze-csv.json +17 -0
- package/resources/skills/apple-notes.json +10 -0
- package/resources/skills/apple-reminders.json +10 -0
- package/resources/skills/auto-commenter.json +10 -0
- package/resources/skills/bear-notes.json +10 -0
- package/resources/skills/bird.json +35 -0
- package/resources/skills/blogwatcher.json +10 -0
- package/resources/skills/blucli.json +10 -0
- package/resources/skills/bluebubbles.json +10 -0
- package/resources/skills/camsnap.json +10 -0
- package/resources/skills/clean-imports.json +18 -0
- package/resources/skills/code-review.json +18 -0
- package/resources/skills/coding-agent.json +10 -0
- package/resources/skills/compare-files.json +23 -0
- package/resources/skills/convert-code.json +34 -0
- package/resources/skills/create-changelog.json +24 -0
- package/resources/skills/debug-error.json +17 -0
- package/resources/skills/dependency-check.json +10 -0
- package/resources/skills/discord.json +10 -0
- package/resources/skills/eightctl.json +10 -0
- package/resources/skills/explain-code.json +29 -0
- package/resources/skills/extract-todos.json +18 -0
- package/resources/skills/food-order.json +10 -0
- package/resources/skills/gemini.json +10 -0
- package/resources/skills/generate-readme.json +10 -0
- package/resources/skills/gifgrep.json +10 -0
- package/resources/skills/git-commit.json +10 -0
- package/resources/skills/github.json +10 -0
- package/resources/skills/gog.json +10 -0
- package/resources/skills/goplaces.json +10 -0
- package/resources/skills/himalaya.json +10 -0
- package/resources/skills/imsg.json +10 -0
- package/resources/skills/karpathy-guidelines.json +12 -0
- package/resources/skills/last30days.json +26 -0
- package/resources/skills/local-places.json +10 -0
- package/resources/skills/mcporter.json +10 -0
- package/resources/skills/model-usage.json +10 -0
- package/resources/skills/nano-banana-pro.json +10 -0
- package/resources/skills/nano-pdf.json +10 -0
- package/resources/skills/notion.json +10 -0
- package/resources/skills/obsidian.json +10 -0
- package/resources/skills/openai-image-gen.json +10 -0
- package/resources/skills/openai-whisper-api.json +10 -0
- package/resources/skills/openai-whisper.json +10 -0
- package/resources/skills/openhue.json +10 -0
- package/resources/skills/oracle.json +10 -0
- package/resources/skills/ordercli.json +10 -0
- package/resources/skills/peekaboo.json +10 -0
- package/resources/skills/project-structure.json +10 -0
- package/resources/skills/proofread.json +17 -0
- package/resources/skills/refactor-code.json +31 -0
- package/resources/skills/rename-symbol.json +23 -0
- package/resources/skills/sag.json +10 -0
- package/resources/skills/security-audit.json +18 -0
- package/resources/skills/session-logs.json +10 -0
- package/resources/skills/sherpa-onnx-tts.json +10 -0
- package/resources/skills/skill-creator.json +15 -0
- package/resources/skills/skill-hub.json +29 -0
- package/resources/skills/slack.json +10 -0
- package/resources/skills/songsee.json +10 -0
- package/resources/skills/sonoscli.json +10 -0
- package/resources/skills/spotify-player.json +10 -0
- package/resources/skills/startup-cfo.json +55 -0
- package/resources/skills/summarize-folder.json +18 -0
- package/resources/skills/summarize.json +10 -0
- package/resources/skills/things-mac.json +10 -0
- package/resources/skills/tmux.json +10 -0
- package/resources/skills/translate.json +36 -0
- package/resources/skills/trello.json +10 -0
- package/resources/skills/video-frames.json +10 -0
- package/resources/skills/voice-call.json +10 -0
- package/resources/skills/wacli.json +10 -0
- package/resources/skills/weather.json +10 -0
- package/resources/skills/write-tests.json +31 -0
- package/src/electron/activity/ActivityRepository.ts +238 -0
- package/src/electron/agent/browser/browser-service.ts +721 -0
- package/src/electron/agent/context-manager.ts +257 -0
- package/src/electron/agent/custom-skill-loader.ts +634 -0
- package/src/electron/agent/daemon.ts +1097 -0
- package/src/electron/agent/executor.ts +4017 -0
- package/src/electron/agent/llm/anthropic-provider.ts +175 -0
- package/src/electron/agent/llm/bedrock-provider.ts +236 -0
- package/src/electron/agent/llm/gemini-provider.ts +422 -0
- package/src/electron/agent/llm/index.ts +9 -0
- package/src/electron/agent/llm/ollama-provider.ts +347 -0
- package/src/electron/agent/llm/openai-oauth.ts +127 -0
- package/src/electron/agent/llm/openai-provider.ts +686 -0
- package/src/electron/agent/llm/openrouter-provider.ts +273 -0
- package/src/electron/agent/llm/pricing.ts +180 -0
- package/src/electron/agent/llm/provider-factory.ts +971 -0
- package/src/electron/agent/llm/types.ts +291 -0
- package/src/electron/agent/queue-manager.ts +408 -0
- package/src/electron/agent/sandbox/docker-sandbox.ts +453 -0
- package/src/electron/agent/sandbox/macos-sandbox.ts +426 -0
- package/src/electron/agent/sandbox/runner.ts +453 -0
- package/src/electron/agent/sandbox/sandbox-factory.ts +337 -0
- package/src/electron/agent/sandbox/security-utils.ts +251 -0
- package/src/electron/agent/search/brave-provider.ts +141 -0
- package/src/electron/agent/search/google-provider.ts +131 -0
- package/src/electron/agent/search/index.ts +6 -0
- package/src/electron/agent/search/provider-factory.ts +450 -0
- package/src/electron/agent/search/serpapi-provider.ts +138 -0
- package/src/electron/agent/search/tavily-provider.ts +108 -0
- package/src/electron/agent/search/types.ts +118 -0
- package/src/electron/agent/security/index.ts +20 -0
- package/src/electron/agent/security/input-sanitizer.ts +380 -0
- package/src/electron/agent/security/output-filter.ts +259 -0
- package/src/electron/agent/skill-eligibility.ts +334 -0
- package/src/electron/agent/skill-registry.ts +457 -0
- package/src/electron/agent/skills/document.ts +1070 -0
- package/src/electron/agent/skills/image-generator.ts +272 -0
- package/src/electron/agent/skills/organizer.ts +131 -0
- package/src/electron/agent/skills/presentation.ts +418 -0
- package/src/electron/agent/skills/spreadsheet.ts +166 -0
- package/src/electron/agent/tools/browser-tools.ts +546 -0
- package/src/electron/agent/tools/builtin-settings.ts +422 -0
- package/src/electron/agent/tools/canvas-tools.ts +572 -0
- package/src/electron/agent/tools/cron-tools.ts +723 -0
- package/src/electron/agent/tools/edit-tools.ts +196 -0
- package/src/electron/agent/tools/file-tools.ts +811 -0
- package/src/electron/agent/tools/glob-tools.ts +303 -0
- package/src/electron/agent/tools/grep-tools.ts +432 -0
- package/src/electron/agent/tools/image-tools.ts +126 -0
- package/src/electron/agent/tools/mention-tools.ts +371 -0
- package/src/electron/agent/tools/node-tools.ts +550 -0
- package/src/electron/agent/tools/registry.ts +3052 -0
- package/src/electron/agent/tools/search-tools.ts +111 -0
- package/src/electron/agent/tools/shell-tools.ts +651 -0
- package/src/electron/agent/tools/skill-tools.ts +340 -0
- package/src/electron/agent/tools/system-tools.ts +665 -0
- package/src/electron/agent/tools/web-fetch-tools.ts +528 -0
- package/src/electron/agent/tools/x-tools.ts +267 -0
- package/src/electron/agents/AgentRoleRepository.ts +557 -0
- package/src/electron/agents/HeartbeatService.ts +469 -0
- package/src/electron/agents/MentionRepository.ts +242 -0
- package/src/electron/agents/TaskSubscriptionRepository.ts +231 -0
- package/src/electron/agents/WorkingStateRepository.ts +278 -0
- package/src/electron/canvas/canvas-manager.ts +818 -0
- package/src/electron/canvas/canvas-preload.ts +102 -0
- package/src/electron/canvas/canvas-protocol.ts +174 -0
- package/src/electron/canvas/canvas-store.ts +200 -0
- package/src/electron/canvas/index.ts +8 -0
- package/src/electron/control-plane/client.ts +527 -0
- package/src/electron/control-plane/handlers.ts +723 -0
- package/src/electron/control-plane/index.ts +51 -0
- package/src/electron/control-plane/node-manager.ts +322 -0
- package/src/electron/control-plane/protocol.ts +269 -0
- package/src/electron/control-plane/remote-client.ts +517 -0
- package/src/electron/control-plane/server.ts +853 -0
- package/src/electron/control-plane/settings.ts +401 -0
- package/src/electron/control-plane/ssh-tunnel.ts +624 -0
- package/src/electron/cron/index.ts +9 -0
- package/src/electron/cron/schedule.ts +217 -0
- package/src/electron/cron/service.ts +743 -0
- package/src/electron/cron/store.ts +165 -0
- package/src/electron/cron/types.ts +291 -0
- package/src/electron/cron/webhook.ts +303 -0
- package/src/electron/database/SecureSettingsRepository.ts +514 -0
- package/src/electron/database/TaskLabelRepository.ts +148 -0
- package/src/electron/database/repositories.ts +2397 -0
- package/src/electron/database/schema.ts +1017 -0
- package/src/electron/extensions/index.ts +18 -0
- package/src/electron/extensions/loader.ts +336 -0
- package/src/electron/extensions/registry.ts +546 -0
- package/src/electron/extensions/types.ts +372 -0
- package/src/electron/gateway/channel-registry.ts +1267 -0
- package/src/electron/gateway/channels/bluebubbles-client.ts +641 -0
- package/src/electron/gateway/channels/bluebubbles.ts +509 -0
- package/src/electron/gateway/channels/discord.ts +1150 -0
- package/src/electron/gateway/channels/email-client.ts +708 -0
- package/src/electron/gateway/channels/email.ts +516 -0
- package/src/electron/gateway/channels/google-chat.ts +760 -0
- package/src/electron/gateway/channels/imessage-client.ts +473 -0
- package/src/electron/gateway/channels/imessage.ts +520 -0
- package/src/electron/gateway/channels/index.ts +21 -0
- package/src/electron/gateway/channels/line-client.ts +598 -0
- package/src/electron/gateway/channels/line.ts +559 -0
- package/src/electron/gateway/channels/matrix-client.ts +632 -0
- package/src/electron/gateway/channels/matrix.ts +655 -0
- package/src/electron/gateway/channels/mattermost-client.ts +526 -0
- package/src/electron/gateway/channels/mattermost.ts +550 -0
- package/src/electron/gateway/channels/signal-client.ts +722 -0
- package/src/electron/gateway/channels/signal.ts +666 -0
- package/src/electron/gateway/channels/slack.ts +458 -0
- package/src/electron/gateway/channels/teams.ts +681 -0
- package/src/electron/gateway/channels/telegram.ts +1727 -0
- package/src/electron/gateway/channels/twitch-client.ts +665 -0
- package/src/electron/gateway/channels/twitch.ts +468 -0
- package/src/electron/gateway/channels/types.ts +1002 -0
- package/src/electron/gateway/channels/whatsapp.ts +1101 -0
- package/src/electron/gateway/context-policy.ts +382 -0
- package/src/electron/gateway/index.ts +1274 -0
- package/src/electron/gateway/infrastructure.ts +645 -0
- package/src/electron/gateway/router.ts +3206 -0
- package/src/electron/gateway/security.ts +422 -0
- package/src/electron/gateway/session.ts +144 -0
- package/src/electron/gateway/tunnel.ts +626 -0
- package/src/electron/guardrails/guardrail-manager.ts +380 -0
- package/src/electron/hooks/gmail-watcher.ts +355 -0
- package/src/electron/hooks/index.ts +30 -0
- package/src/electron/hooks/mappings.ts +404 -0
- package/src/electron/hooks/server.ts +574 -0
- package/src/electron/hooks/settings.ts +466 -0
- package/src/electron/hooks/types.ts +245 -0
- package/src/electron/ipc/canvas-handlers.ts +223 -0
- package/src/electron/ipc/handlers.ts +3661 -0
- package/src/electron/ipc/mission-control-handlers.ts +182 -0
- package/src/electron/main.ts +496 -0
- package/src/electron/mcp/client/MCPClientManager.ts +406 -0
- package/src/electron/mcp/client/MCPServerConnection.ts +514 -0
- package/src/electron/mcp/client/transports/SSETransport.ts +360 -0
- package/src/electron/mcp/client/transports/StdioTransport.ts +355 -0
- package/src/electron/mcp/client/transports/WebSocketTransport.ts +384 -0
- package/src/electron/mcp/host/MCPHostServer.ts +388 -0
- package/src/electron/mcp/host/ToolAdapter.ts +140 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +565 -0
- package/src/electron/mcp/settings.ts +468 -0
- package/src/electron/mcp/types.ts +371 -0
- package/src/electron/memory/MemoryService.ts +523 -0
- package/src/electron/notifications/index.ts +16 -0
- package/src/electron/notifications/service.ts +161 -0
- package/src/electron/notifications/store.ts +163 -0
- package/src/electron/preload.ts +2845 -0
- package/src/electron/reports/StandupReportService.ts +356 -0
- package/src/electron/security/concurrency.ts +333 -0
- package/src/electron/security/index.ts +17 -0
- package/src/electron/security/policy-manager.ts +539 -0
- package/src/electron/settings/appearance-manager.ts +182 -0
- package/src/electron/settings/personality-manager.ts +800 -0
- package/src/electron/settings/x-manager.ts +62 -0
- package/src/electron/tailscale/exposure.ts +262 -0
- package/src/electron/tailscale/index.ts +34 -0
- package/src/electron/tailscale/settings.ts +218 -0
- package/src/electron/tailscale/tailscale.ts +379 -0
- package/src/electron/tray/QuickInputWindow.ts +609 -0
- package/src/electron/tray/TrayManager.ts +1005 -0
- package/src/electron/tray/index.ts +6 -0
- package/src/electron/updater/index.ts +1 -0
- package/src/electron/updater/update-manager.ts +447 -0
- package/src/electron/utils/env-migration.ts +203 -0
- package/src/electron/utils/process.ts +124 -0
- package/src/electron/utils/rate-limiter.ts +130 -0
- package/src/electron/utils/validation.ts +493 -0
- package/src/electron/utils/x-cli.ts +198 -0
- package/src/electron/voice/VoiceService.ts +583 -0
- package/src/electron/voice/index.ts +9 -0
- package/src/electron/voice/voice-settings-manager.ts +403 -0
- package/src/renderer/App.tsx +775 -0
- package/src/renderer/components/ActivityFeed.tsx +407 -0
- package/src/renderer/components/ActivityFeedItem.tsx +285 -0
- package/src/renderer/components/AgentRoleCard.tsx +343 -0
- package/src/renderer/components/AgentRoleEditor.tsx +805 -0
- package/src/renderer/components/AgentSquadSettings.tsx +295 -0
- package/src/renderer/components/AgentWorkingStatePanel.tsx +411 -0
- package/src/renderer/components/AppearanceSettings.tsx +122 -0
- package/src/renderer/components/ApprovalDialog.tsx +100 -0
- package/src/renderer/components/BlueBubblesSettings.tsx +505 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +307 -0
- package/src/renderer/components/CanvasPreview.tsx +1189 -0
- package/src/renderer/components/CommandOutput.tsx +202 -0
- package/src/renderer/components/ContextPolicySettings.tsx +523 -0
- package/src/renderer/components/ControlPlaneSettings.tsx +1134 -0
- package/src/renderer/components/DisclaimerModal.tsx +124 -0
- package/src/renderer/components/DiscordSettings.tsx +436 -0
- package/src/renderer/components/EmailSettings.tsx +606 -0
- package/src/renderer/components/ExtensionsSettings.tsx +542 -0
- package/src/renderer/components/FileViewer.tsx +224 -0
- package/src/renderer/components/GoogleChatSettings.tsx +535 -0
- package/src/renderer/components/GuardrailSettings.tsx +487 -0
- package/src/renderer/components/HooksSettings.tsx +581 -0
- package/src/renderer/components/ImessageSettings.tsx +484 -0
- package/src/renderer/components/LineSettings.tsx +483 -0
- package/src/renderer/components/MCPRegistryBrowser.tsx +386 -0
- package/src/renderer/components/MCPSettings.tsx +943 -0
- package/src/renderer/components/MainContent.tsx +2433 -0
- package/src/renderer/components/MatrixSettings.tsx +510 -0
- package/src/renderer/components/MattermostSettings.tsx +473 -0
- package/src/renderer/components/MemorySettings.tsx +247 -0
- package/src/renderer/components/MentionBadge.tsx +87 -0
- package/src/renderer/components/MentionInput.tsx +409 -0
- package/src/renderer/components/MentionList.tsx +476 -0
- package/src/renderer/components/MissionControlPanel.tsx +1995 -0
- package/src/renderer/components/NodesSettings.tsx +316 -0
- package/src/renderer/components/NotificationPanel.tsx +481 -0
- package/src/renderer/components/Onboarding/AwakeningOrb.tsx +44 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +443 -0
- package/src/renderer/components/Onboarding/TypewriterText.tsx +102 -0
- package/src/renderer/components/Onboarding/index.ts +3 -0
- package/src/renderer/components/OnboardingModal.tsx +698 -0
- package/src/renderer/components/PairingCodeDisplay.tsx +324 -0
- package/src/renderer/components/PersonalitySettings.tsx +597 -0
- package/src/renderer/components/QueueSettings.tsx +119 -0
- package/src/renderer/components/QuickTaskFAB.tsx +71 -0
- package/src/renderer/components/RightPanel.tsx +413 -0
- package/src/renderer/components/ScheduledTasksSettings.tsx +1328 -0
- package/src/renderer/components/SearchSettings.tsx +328 -0
- package/src/renderer/components/Settings.tsx +1504 -0
- package/src/renderer/components/Sidebar.tsx +344 -0
- package/src/renderer/components/SignalSettings.tsx +673 -0
- package/src/renderer/components/SkillHubBrowser.tsx +458 -0
- package/src/renderer/components/SkillParameterModal.tsx +185 -0
- package/src/renderer/components/SkillsSettings.tsx +451 -0
- package/src/renderer/components/SlackSettings.tsx +442 -0
- package/src/renderer/components/StandupReportViewer.tsx +614 -0
- package/src/renderer/components/TaskBoard.tsx +498 -0
- package/src/renderer/components/TaskBoardCard.tsx +357 -0
- package/src/renderer/components/TaskBoardColumn.tsx +211 -0
- package/src/renderer/components/TaskLabelManager.tsx +472 -0
- package/src/renderer/components/TaskQueuePanel.tsx +144 -0
- package/src/renderer/components/TaskQuickActions.tsx +492 -0
- package/src/renderer/components/TaskTimeline.tsx +216 -0
- package/src/renderer/components/TaskView.tsx +162 -0
- package/src/renderer/components/TeamsSettings.tsx +518 -0
- package/src/renderer/components/TelegramSettings.tsx +421 -0
- package/src/renderer/components/Toast.tsx +76 -0
- package/src/renderer/components/TraySettings.tsx +189 -0
- package/src/renderer/components/TwitchSettings.tsx +511 -0
- package/src/renderer/components/UpdateSettings.tsx +295 -0
- package/src/renderer/components/VoiceIndicator.tsx +270 -0
- package/src/renderer/components/VoiceSettings.tsx +867 -0
- package/src/renderer/components/WhatsAppSettings.tsx +721 -0
- package/src/renderer/components/WorkingStateEditor.tsx +309 -0
- package/src/renderer/components/WorkingStateHistory.tsx +481 -0
- package/src/renderer/components/WorkspaceSelector.tsx +150 -0
- package/src/renderer/components/XSettings.tsx +311 -0
- package/src/renderer/global.d.ts +9 -0
- package/src/renderer/hooks/useAgentContext.ts +153 -0
- package/src/renderer/hooks/useOnboardingFlow.ts +548 -0
- package/src/renderer/hooks/useVoiceInput.ts +268 -0
- package/src/renderer/index.html +12 -0
- package/src/renderer/main.tsx +10 -0
- package/src/renderer/public/cowork-os-logo.png +0 -0
- package/src/renderer/quick-input.html +164 -0
- package/src/renderer/styles/index.css +14504 -0
- package/src/renderer/utils/agentMessages.ts +749 -0
- package/src/renderer/utils/voice-directives.ts +169 -0
- package/src/shared/channelMessages.ts +213 -0
- package/src/shared/types.ts +3608 -0
- package/tsconfig.electron.json +26 -0
- package/tsconfig.json +26 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.ts +23 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSETransport - MCP transport over Server-Sent Events (SSE)
|
|
3
|
+
*
|
|
4
|
+
* Uses SSE (EventSource) for server-to-client messages and
|
|
5
|
+
* HTTP POST requests for client-to-server messages.
|
|
6
|
+
* This enables web-based MCP servers.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { EventSource } from 'eventsource';
|
|
11
|
+
import {
|
|
12
|
+
MCPTransport,
|
|
13
|
+
MCPServerConfig,
|
|
14
|
+
JSONRPCRequest,
|
|
15
|
+
JSONRPCResponse,
|
|
16
|
+
JSONRPCNotification,
|
|
17
|
+
} from '../../types';
|
|
18
|
+
|
|
19
|
+
interface PendingRequest {
|
|
20
|
+
resolve: (result: any) => void;
|
|
21
|
+
reject: (error: Error) => void;
|
|
22
|
+
timeout: ReturnType<typeof setTimeout>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class SSETransport extends EventEmitter implements MCPTransport {
|
|
26
|
+
private config: MCPServerConfig;
|
|
27
|
+
private eventSource: EventSource | null = null;
|
|
28
|
+
private messageHandler: ((message: JSONRPCResponse | JSONRPCNotification) => void) | null = null;
|
|
29
|
+
private closeHandler: ((error?: Error) => void) | null = null;
|
|
30
|
+
private errorHandler: ((error: Error) => void) | null = null;
|
|
31
|
+
private pendingRequests: Map<string | number, PendingRequest> = new Map();
|
|
32
|
+
private connected = false;
|
|
33
|
+
private requestId = 0;
|
|
34
|
+
private abortController: AbortController | null = null;
|
|
35
|
+
|
|
36
|
+
constructor(config: MCPServerConfig) {
|
|
37
|
+
super();
|
|
38
|
+
this.config = config;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Connect to the MCP server via SSE
|
|
43
|
+
*/
|
|
44
|
+
async connect(): Promise<void> {
|
|
45
|
+
if (this.connected || this.eventSource) {
|
|
46
|
+
throw new Error('Already connected');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { url } = this.config;
|
|
50
|
+
|
|
51
|
+
if (!url) {
|
|
52
|
+
throw new Error('No URL specified for SSE transport');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const timeout = setTimeout(() => {
|
|
57
|
+
this.cleanup();
|
|
58
|
+
reject(new Error(`Connection timeout: server did not respond within ${this.config.connectionTimeout || 30000}ms`));
|
|
59
|
+
}, this.config.connectionTimeout || 30000);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Build SSE URL with auth headers if needed
|
|
63
|
+
const sseUrl = this.buildUrl(url, '/sse');
|
|
64
|
+
console.log(`[MCP SSETransport] Connecting to: ${sseUrl}`);
|
|
65
|
+
|
|
66
|
+
// Create EventSource for server-to-client messages
|
|
67
|
+
// Note: EventSource doesn't support custom headers, so we use URL params for auth
|
|
68
|
+
this.eventSource = new EventSource(sseUrl);
|
|
69
|
+
|
|
70
|
+
this.eventSource.onopen = () => {
|
|
71
|
+
clearTimeout(timeout);
|
|
72
|
+
this.connected = true;
|
|
73
|
+
console.log(`[MCP SSETransport] Connected successfully`);
|
|
74
|
+
resolve();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
this.eventSource.onmessage = (event) => {
|
|
78
|
+
this.handleMessage(event.data);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
this.eventSource.onerror = (error) => {
|
|
82
|
+
console.error(`[MCP SSETransport] EventSource error:`, error);
|
|
83
|
+
if (!this.connected) {
|
|
84
|
+
clearTimeout(timeout);
|
|
85
|
+
reject(new Error('Failed to connect to SSE endpoint'));
|
|
86
|
+
} else {
|
|
87
|
+
this.errorHandler?.(new Error('SSE connection error'));
|
|
88
|
+
this.closeHandler?.(new Error('SSE connection lost'));
|
|
89
|
+
}
|
|
90
|
+
this.cleanup();
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Handle named events (some servers use event types)
|
|
94
|
+
this.eventSource.addEventListener('message', (event) => {
|
|
95
|
+
this.handleMessage(event.data);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
this.eventSource.addEventListener('error', () => {
|
|
99
|
+
if (this.connected) {
|
|
100
|
+
this.closeHandler?.(new Error('SSE stream closed'));
|
|
101
|
+
this.cleanup();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
console.error(`[MCP SSETransport] Failed to connect:`, error);
|
|
108
|
+
reject(error);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Disconnect from the MCP server
|
|
115
|
+
*/
|
|
116
|
+
async disconnect(): Promise<void> {
|
|
117
|
+
console.log(`[MCP SSETransport] Disconnecting...`);
|
|
118
|
+
|
|
119
|
+
// Abort any pending requests
|
|
120
|
+
this.abortController?.abort();
|
|
121
|
+
|
|
122
|
+
// Reject all pending requests
|
|
123
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
124
|
+
clearTimeout(pending.timeout);
|
|
125
|
+
pending.reject(new Error('Transport disconnected'));
|
|
126
|
+
}
|
|
127
|
+
this.pendingRequests.clear();
|
|
128
|
+
|
|
129
|
+
this.cleanup();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Send a JSON-RPC request via HTTP POST and wait for response
|
|
134
|
+
*/
|
|
135
|
+
async sendRequest(method: string, params?: Record<string, any>): Promise<any> {
|
|
136
|
+
if (!this.connected) {
|
|
137
|
+
throw new Error('Not connected');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const id = ++this.requestId;
|
|
141
|
+
const request: JSONRPCRequest = {
|
|
142
|
+
jsonrpc: '2.0',
|
|
143
|
+
id,
|
|
144
|
+
method,
|
|
145
|
+
params,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const timeout = setTimeout(() => {
|
|
150
|
+
this.pendingRequests.delete(id);
|
|
151
|
+
reject(new Error(`Request timeout for method: ${method}`));
|
|
152
|
+
}, this.config.requestTimeout || 60000);
|
|
153
|
+
|
|
154
|
+
this.pendingRequests.set(id, { resolve, reject, timeout });
|
|
155
|
+
|
|
156
|
+
// Send via HTTP POST
|
|
157
|
+
this.postMessage(request).catch((error) => {
|
|
158
|
+
this.pendingRequests.delete(id);
|
|
159
|
+
clearTimeout(timeout);
|
|
160
|
+
reject(error);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Send a JSON-RPC message (request or notification)
|
|
167
|
+
*/
|
|
168
|
+
async send(message: JSONRPCRequest | JSONRPCNotification): Promise<void> {
|
|
169
|
+
if (!this.connected) {
|
|
170
|
+
throw new Error('Not connected');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await this.postMessage(message);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Post a message to the server via HTTP
|
|
178
|
+
*/
|
|
179
|
+
private async postMessage(message: JSONRPCRequest | JSONRPCNotification): Promise<void> {
|
|
180
|
+
const { url } = this.config;
|
|
181
|
+
if (!url) {
|
|
182
|
+
throw new Error('No URL configured');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const postUrl = this.buildUrl(url, '/message');
|
|
186
|
+
this.abortController = new AbortController();
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const headers: Record<string, string> = {
|
|
190
|
+
'Content-Type': 'application/json',
|
|
191
|
+
...this.config.headers,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Add auth headers
|
|
195
|
+
this.addAuthHeaders(headers);
|
|
196
|
+
|
|
197
|
+
const response = await fetch(postUrl, {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers,
|
|
200
|
+
body: JSON.stringify(message),
|
|
201
|
+
signal: this.abortController.signal,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Some servers return the response in the HTTP response body
|
|
209
|
+
const contentType = response.headers.get('content-type');
|
|
210
|
+
if (contentType?.includes('application/json')) {
|
|
211
|
+
const responseData = await response.json();
|
|
212
|
+
if (responseData && typeof responseData === 'object' && 'id' in responseData) {
|
|
213
|
+
this.handleJsonRpcResponse(responseData);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} catch (error: any) {
|
|
217
|
+
if (error.name === 'AbortError') {
|
|
218
|
+
throw new Error('Request aborted');
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Register message handler
|
|
226
|
+
*/
|
|
227
|
+
onMessage(handler: (message: JSONRPCResponse | JSONRPCNotification) => void): void {
|
|
228
|
+
this.messageHandler = handler;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Register close handler
|
|
233
|
+
*/
|
|
234
|
+
onClose(handler: (error?: Error) => void): void {
|
|
235
|
+
this.closeHandler = handler;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Register error handler
|
|
240
|
+
*/
|
|
241
|
+
onError(handler: (error: Error) => void): void {
|
|
242
|
+
this.errorHandler = handler;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Check if transport is connected
|
|
247
|
+
*/
|
|
248
|
+
isConnected(): boolean {
|
|
249
|
+
// EventSource readyState: 0=CONNECTING, 1=OPEN, 2=CLOSED
|
|
250
|
+
return this.connected && this.eventSource?.readyState === 1;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Handle incoming SSE message
|
|
255
|
+
*/
|
|
256
|
+
private handleMessage(data: string): void {
|
|
257
|
+
try {
|
|
258
|
+
const message = JSON.parse(data);
|
|
259
|
+
this.handleJsonRpcResponse(message);
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error(`[MCP SSETransport] Failed to parse message: ${data}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Handle a parsed JSON-RPC message
|
|
267
|
+
*/
|
|
268
|
+
private handleJsonRpcResponse(message: any): void {
|
|
269
|
+
// Check if this is a response to a pending request
|
|
270
|
+
if ('id' in message && message.id !== null) {
|
|
271
|
+
const pending = this.pendingRequests.get(message.id);
|
|
272
|
+
if (pending) {
|
|
273
|
+
this.pendingRequests.delete(message.id);
|
|
274
|
+
clearTimeout(pending.timeout);
|
|
275
|
+
|
|
276
|
+
if ('error' in message && message.error) {
|
|
277
|
+
pending.reject(new Error(message.error.message || 'Unknown error'));
|
|
278
|
+
} else {
|
|
279
|
+
pending.resolve(message.result);
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Otherwise, pass to message handler (notifications)
|
|
286
|
+
this.messageHandler?.(message as JSONRPCResponse | JSONRPCNotification);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Build URL with optional path
|
|
291
|
+
*/
|
|
292
|
+
private buildUrl(baseUrl: string, path: string): string {
|
|
293
|
+
const url = new URL(baseUrl);
|
|
294
|
+
|
|
295
|
+
// Append path if base URL doesn't already have it
|
|
296
|
+
if (!url.pathname.endsWith(path)) {
|
|
297
|
+
url.pathname = url.pathname.replace(/\/$/, '') + path;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Add auth params for SSE (since EventSource doesn't support headers)
|
|
301
|
+
if (this.config.auth) {
|
|
302
|
+
if (this.config.auth.type === 'bearer' && this.config.auth.token) {
|
|
303
|
+
url.searchParams.set('token', this.config.auth.token);
|
|
304
|
+
} else if (this.config.auth.type === 'api-key' && this.config.auth.apiKey) {
|
|
305
|
+
url.searchParams.set('api_key', this.config.auth.apiKey);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return url.toString();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Add authentication headers
|
|
314
|
+
*/
|
|
315
|
+
private addAuthHeaders(headers: Record<string, string>): void {
|
|
316
|
+
if (!this.config.auth) return;
|
|
317
|
+
|
|
318
|
+
switch (this.config.auth.type) {
|
|
319
|
+
case 'bearer':
|
|
320
|
+
if (this.config.auth.token) {
|
|
321
|
+
headers['Authorization'] = `Bearer ${this.config.auth.token}`;
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
case 'api-key':
|
|
325
|
+
if (this.config.auth.apiKey) {
|
|
326
|
+
const headerName = this.config.auth.headerName || 'X-API-Key';
|
|
327
|
+
headers[headerName] = this.config.auth.apiKey;
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
case 'basic':
|
|
331
|
+
if (this.config.auth.username && this.config.auth.password) {
|
|
332
|
+
const credentials = Buffer.from(
|
|
333
|
+
`${this.config.auth.username}:${this.config.auth.password}`
|
|
334
|
+
).toString('base64');
|
|
335
|
+
headers['Authorization'] = `Basic ${credentials}`;
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Cleanup resources
|
|
343
|
+
*/
|
|
344
|
+
private cleanup(): void {
|
|
345
|
+
this.connected = false;
|
|
346
|
+
|
|
347
|
+
// Clear all pending requests
|
|
348
|
+
for (const [, pending] of this.pendingRequests) {
|
|
349
|
+
clearTimeout(pending.timeout);
|
|
350
|
+
}
|
|
351
|
+
this.pendingRequests.clear();
|
|
352
|
+
|
|
353
|
+
if (this.eventSource) {
|
|
354
|
+
this.eventSource.close();
|
|
355
|
+
this.eventSource = null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this.abortController = null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StdioTransport - MCP transport over stdio (stdin/stdout)
|
|
3
|
+
*
|
|
4
|
+
* This is the primary transport for MCP servers that are launched as
|
|
5
|
+
* child processes and communicate via JSON-RPC over stdin/stdout.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn, ChildProcess } from 'child_process';
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import {
|
|
11
|
+
MCPTransport,
|
|
12
|
+
MCPServerConfig,
|
|
13
|
+
JSONRPCRequest,
|
|
14
|
+
JSONRPCResponse,
|
|
15
|
+
JSONRPCNotification,
|
|
16
|
+
} from '../../types';
|
|
17
|
+
|
|
18
|
+
interface PendingRequest {
|
|
19
|
+
resolve: (result: any) => void;
|
|
20
|
+
reject: (error: Error) => void;
|
|
21
|
+
timeout: ReturnType<typeof setTimeout>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class StdioTransport extends EventEmitter implements MCPTransport {
|
|
25
|
+
private process: ChildProcess | null = null;
|
|
26
|
+
private config: MCPServerConfig;
|
|
27
|
+
private messageHandler: ((message: JSONRPCResponse | JSONRPCNotification) => void) | null = null;
|
|
28
|
+
private closeHandler: ((error?: Error) => void) | null = null;
|
|
29
|
+
private errorHandler: ((error: Error) => void) | null = null;
|
|
30
|
+
private pendingRequests: Map<string | number, PendingRequest> = new Map();
|
|
31
|
+
private buffer = '';
|
|
32
|
+
private stderrBuffer = ''; // Capture stderr for better error messages
|
|
33
|
+
private connected = false;
|
|
34
|
+
private requestId = 0;
|
|
35
|
+
|
|
36
|
+
constructor(config: MCPServerConfig) {
|
|
37
|
+
super();
|
|
38
|
+
this.config = config;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Connect to the MCP server by spawning the process
|
|
43
|
+
*/
|
|
44
|
+
async connect(): Promise<void> {
|
|
45
|
+
if (this.connected || this.process) {
|
|
46
|
+
throw new Error('Already connected');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { command, args = [], env, cwd } = this.config;
|
|
50
|
+
|
|
51
|
+
if (!command) {
|
|
52
|
+
throw new Error('No command specified for stdio transport');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const timeout = setTimeout(() => {
|
|
57
|
+
this.cleanup();
|
|
58
|
+
reject(new Error(`Connection timeout: server did not respond within ${this.config.connectionTimeout || 30000}ms`));
|
|
59
|
+
}, this.config.connectionTimeout || 30000);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Merge environment variables
|
|
63
|
+
const processEnv = {
|
|
64
|
+
...process.env,
|
|
65
|
+
...env,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
console.log(`[MCP StdioTransport] Spawning: ${command} ${args.join(' ')}`);
|
|
69
|
+
|
|
70
|
+
this.process = spawn(command, args, {
|
|
71
|
+
cwd: cwd || process.cwd(),
|
|
72
|
+
env: processEnv,
|
|
73
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
74
|
+
shell: false,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Handle stdout (JSON-RPC messages from server)
|
|
78
|
+
this.process.stdout?.on('data', (data: Buffer) => {
|
|
79
|
+
this.handleData(data);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Handle stderr (logging/errors from server)
|
|
83
|
+
this.process.stderr?.on('data', (data: Buffer) => {
|
|
84
|
+
const text = data.toString();
|
|
85
|
+
console.log(`[MCP StdioTransport] Server stderr: ${text}`);
|
|
86
|
+
// Capture stderr for better error messages (limit to last 1000 chars)
|
|
87
|
+
this.stderrBuffer += text;
|
|
88
|
+
if (this.stderrBuffer.length > 1000) {
|
|
89
|
+
this.stderrBuffer = this.stderrBuffer.slice(-1000);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Handle process errors
|
|
94
|
+
this.process.on('error', (error) => {
|
|
95
|
+
clearTimeout(timeout);
|
|
96
|
+
console.error(`[MCP StdioTransport] Process error:`, error);
|
|
97
|
+
this.errorHandler?.(error);
|
|
98
|
+
if (!this.connected) {
|
|
99
|
+
reject(error);
|
|
100
|
+
}
|
|
101
|
+
this.cleanup();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Handle process exit
|
|
105
|
+
this.process.on('exit', (code, signal) => {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
// Build error message including stderr output for better diagnostics
|
|
108
|
+
let message = `Process exited with code ${code}`;
|
|
109
|
+
if (signal) {
|
|
110
|
+
message += `, signal ${signal}`;
|
|
111
|
+
}
|
|
112
|
+
// Include stderr in error message if there was an error exit
|
|
113
|
+
if (code !== 0 && this.stderrBuffer.trim()) {
|
|
114
|
+
const stderrSnippet = this.stderrBuffer.trim().slice(-500); // Last 500 chars
|
|
115
|
+
message += `: ${stderrSnippet}`;
|
|
116
|
+
}
|
|
117
|
+
console.log(`[MCP StdioTransport] ${message}`);
|
|
118
|
+
|
|
119
|
+
if (!this.connected) {
|
|
120
|
+
reject(new Error(message));
|
|
121
|
+
} else {
|
|
122
|
+
this.closeHandler?.(code !== 0 ? new Error(message) : undefined);
|
|
123
|
+
}
|
|
124
|
+
this.cleanup();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Handle process close
|
|
128
|
+
this.process.on('close', (code) => {
|
|
129
|
+
if (this.connected) {
|
|
130
|
+
let message = `Process closed with code ${code}`;
|
|
131
|
+
if (code !== 0 && this.stderrBuffer.trim()) {
|
|
132
|
+
const stderrSnippet = this.stderrBuffer.trim().slice(-500);
|
|
133
|
+
message += `: ${stderrSnippet}`;
|
|
134
|
+
}
|
|
135
|
+
this.closeHandler?.(code !== 0 ? new Error(message) : undefined);
|
|
136
|
+
}
|
|
137
|
+
this.cleanup();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Mark as connected once process is spawned
|
|
141
|
+
// The actual MCP handshake will be done by MCPServerConnection
|
|
142
|
+
this.connected = true;
|
|
143
|
+
clearTimeout(timeout);
|
|
144
|
+
console.log(`[MCP StdioTransport] Process spawned successfully`);
|
|
145
|
+
resolve();
|
|
146
|
+
|
|
147
|
+
} catch (error) {
|
|
148
|
+
clearTimeout(timeout);
|
|
149
|
+
console.error(`[MCP StdioTransport] Failed to spawn process:`, error);
|
|
150
|
+
reject(error);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Disconnect from the MCP server
|
|
157
|
+
*/
|
|
158
|
+
async disconnect(): Promise<void> {
|
|
159
|
+
if (!this.process) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.log(`[MCP StdioTransport] Disconnecting...`);
|
|
164
|
+
|
|
165
|
+
// Reject all pending requests
|
|
166
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
167
|
+
clearTimeout(pending.timeout);
|
|
168
|
+
pending.reject(new Error('Transport disconnected'));
|
|
169
|
+
}
|
|
170
|
+
this.pendingRequests.clear();
|
|
171
|
+
|
|
172
|
+
// Try graceful shutdown first
|
|
173
|
+
if (this.process.stdin?.writable) {
|
|
174
|
+
try {
|
|
175
|
+
this.process.stdin.end();
|
|
176
|
+
} catch {
|
|
177
|
+
// Ignore errors during shutdown
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Give process time to exit gracefully
|
|
182
|
+
await new Promise<void>((resolve) => {
|
|
183
|
+
const forceKillTimeout = setTimeout(() => {
|
|
184
|
+
if (this.process && !this.process.killed) {
|
|
185
|
+
console.log(`[MCP StdioTransport] Force killing process`);
|
|
186
|
+
this.process.kill('SIGKILL');
|
|
187
|
+
}
|
|
188
|
+
resolve();
|
|
189
|
+
}, 5000);
|
|
190
|
+
|
|
191
|
+
if (this.process) {
|
|
192
|
+
this.process.once('exit', () => {
|
|
193
|
+
clearTimeout(forceKillTimeout);
|
|
194
|
+
resolve();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Send SIGTERM first
|
|
198
|
+
this.process.kill('SIGTERM');
|
|
199
|
+
} else {
|
|
200
|
+
clearTimeout(forceKillTimeout);
|
|
201
|
+
resolve();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
this.cleanup();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Send a JSON-RPC request and wait for response
|
|
210
|
+
*/
|
|
211
|
+
async sendRequest(method: string, params?: Record<string, any>): Promise<any> {
|
|
212
|
+
if (!this.connected || !this.process?.stdin?.writable) {
|
|
213
|
+
throw new Error('Not connected');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const id = ++this.requestId;
|
|
217
|
+
const request: JSONRPCRequest = {
|
|
218
|
+
jsonrpc: '2.0',
|
|
219
|
+
id,
|
|
220
|
+
method,
|
|
221
|
+
params,
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
return new Promise((resolve, reject) => {
|
|
225
|
+
const timeout = setTimeout(() => {
|
|
226
|
+
this.pendingRequests.delete(id);
|
|
227
|
+
reject(new Error(`Request timeout for method: ${method}`));
|
|
228
|
+
}, this.config.requestTimeout || 60000);
|
|
229
|
+
|
|
230
|
+
this.pendingRequests.set(id, { resolve, reject, timeout });
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const message = JSON.stringify(request) + '\n';
|
|
234
|
+
this.process!.stdin!.write(message);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
this.pendingRequests.delete(id);
|
|
237
|
+
clearTimeout(timeout);
|
|
238
|
+
reject(error);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Send a JSON-RPC message (request or notification)
|
|
245
|
+
*/
|
|
246
|
+
async send(message: JSONRPCRequest | JSONRPCNotification): Promise<void> {
|
|
247
|
+
if (!this.connected || !this.process?.stdin?.writable) {
|
|
248
|
+
throw new Error('Not connected');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const data = JSON.stringify(message) + '\n';
|
|
253
|
+
this.process.stdin.write(data);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new Error(`Failed to send message: ${error}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Register message handler
|
|
261
|
+
*/
|
|
262
|
+
onMessage(handler: (message: JSONRPCResponse | JSONRPCNotification) => void): void {
|
|
263
|
+
this.messageHandler = handler;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Register close handler
|
|
268
|
+
*/
|
|
269
|
+
onClose(handler: (error?: Error) => void): void {
|
|
270
|
+
this.closeHandler = handler;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Register error handler
|
|
275
|
+
*/
|
|
276
|
+
onError(handler: (error: Error) => void): void {
|
|
277
|
+
this.errorHandler = handler;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Check if transport is connected
|
|
282
|
+
*/
|
|
283
|
+
isConnected(): boolean {
|
|
284
|
+
return this.connected && !!this.process && !this.process.killed;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Handle incoming data from stdout
|
|
289
|
+
*/
|
|
290
|
+
private handleData(data: Buffer): void {
|
|
291
|
+
this.buffer += data.toString();
|
|
292
|
+
|
|
293
|
+
// Process complete lines (JSON-RPC messages are newline-delimited)
|
|
294
|
+
let newlineIndex: number;
|
|
295
|
+
while ((newlineIndex = this.buffer.indexOf('\n')) !== -1) {
|
|
296
|
+
const line = this.buffer.slice(0, newlineIndex).trim();
|
|
297
|
+
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
298
|
+
|
|
299
|
+
if (line) {
|
|
300
|
+
try {
|
|
301
|
+
const message = JSON.parse(line);
|
|
302
|
+
this.handleMessage(message);
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error(`[MCP StdioTransport] Failed to parse message: ${line}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Handle a parsed JSON-RPC message
|
|
312
|
+
*/
|
|
313
|
+
private handleMessage(message: any): void {
|
|
314
|
+
// Check if this is a response to a pending request
|
|
315
|
+
if ('id' in message && message.id !== null) {
|
|
316
|
+
const pending = this.pendingRequests.get(message.id);
|
|
317
|
+
if (pending) {
|
|
318
|
+
this.pendingRequests.delete(message.id);
|
|
319
|
+
clearTimeout(pending.timeout);
|
|
320
|
+
|
|
321
|
+
if ('error' in message && message.error) {
|
|
322
|
+
pending.reject(new Error(message.error.message || 'Unknown error'));
|
|
323
|
+
} else {
|
|
324
|
+
pending.resolve(message.result);
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Otherwise, pass to message handler (notifications)
|
|
331
|
+
this.messageHandler?.(message as JSONRPCResponse | JSONRPCNotification);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Cleanup resources
|
|
336
|
+
*/
|
|
337
|
+
private cleanup(): void {
|
|
338
|
+
this.connected = false;
|
|
339
|
+
this.buffer = '';
|
|
340
|
+
this.stderrBuffer = '';
|
|
341
|
+
|
|
342
|
+
// Clear all pending requests
|
|
343
|
+
for (const [, pending] of this.pendingRequests) {
|
|
344
|
+
clearTimeout(pending.timeout);
|
|
345
|
+
}
|
|
346
|
+
this.pendingRequests.clear();
|
|
347
|
+
|
|
348
|
+
if (this.process) {
|
|
349
|
+
this.process.removeAllListeners();
|
|
350
|
+
this.process.stdout?.removeAllListeners();
|
|
351
|
+
this.process.stderr?.removeAllListeners();
|
|
352
|
+
this.process = null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|