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,1063 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Channel Gateway
|
|
4
|
+
*
|
|
5
|
+
* Main entry point for multi-channel messaging support.
|
|
6
|
+
* Manages channel adapters, routing, and sessions.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.createAutoTunnel = exports.getAvailableTunnelProviders = exports.TunnelManager = exports.EmailClient = exports.createEmailAdapter = exports.EmailAdapter = exports.BlueBubblesClient = exports.createBlueBubblesAdapter = exports.BlueBubblesAdapter = exports.LineClient = exports.createLineAdapter = exports.LineAdapter = exports.TwitchClient = exports.createTwitchAdapter = exports.TwitchAdapter = exports.MatrixClient = exports.createMatrixAdapter = exports.MatrixAdapter = exports.MattermostClient = exports.createMattermostAdapter = exports.MattermostAdapter = exports.SignalClient = exports.createSignalAdapter = exports.SignalAdapter = exports.createImessageAdapter = exports.ImessageAdapter = exports.createWhatsAppAdapter = exports.WhatsAppAdapter = exports.createSlackAdapter = exports.SlackAdapter = exports.createDiscordAdapter = exports.DiscordAdapter = exports.createTelegramAdapter = exports.TelegramAdapter = exports.ChannelGateway = void 0;
|
|
24
|
+
const router_1 = require("./router");
|
|
25
|
+
const security_1 = require("./security");
|
|
26
|
+
const session_1 = require("./session");
|
|
27
|
+
const telegram_1 = require("./channels/telegram");
|
|
28
|
+
const discord_1 = require("./channels/discord");
|
|
29
|
+
const slack_1 = require("./channels/slack");
|
|
30
|
+
const whatsapp_1 = require("./channels/whatsapp");
|
|
31
|
+
const imessage_1 = require("./channels/imessage");
|
|
32
|
+
const signal_1 = require("./channels/signal");
|
|
33
|
+
const mattermost_1 = require("./channels/mattermost");
|
|
34
|
+
const matrix_1 = require("./channels/matrix");
|
|
35
|
+
const twitch_1 = require("./channels/twitch");
|
|
36
|
+
const line_1 = require("./channels/line");
|
|
37
|
+
const bluebubbles_1 = require("./channels/bluebubbles");
|
|
38
|
+
const email_1 = require("./channels/email");
|
|
39
|
+
const repositories_1 = require("../database/repositories");
|
|
40
|
+
const personality_manager_1 = require("../settings/personality-manager");
|
|
41
|
+
const channelMessages_1 = require("../../shared/channelMessages");
|
|
42
|
+
const types_1 = require("../../shared/types");
|
|
43
|
+
const DEFAULT_CONFIG = {
|
|
44
|
+
autoConnect: true,
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Channel Gateway - Main class for managing multi-channel messaging
|
|
48
|
+
*/
|
|
49
|
+
class ChannelGateway {
|
|
50
|
+
constructor(db, config = {}) {
|
|
51
|
+
this.initialized = false;
|
|
52
|
+
this.daemonListeners = [];
|
|
53
|
+
this.db = db;
|
|
54
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
55
|
+
// Initialize components
|
|
56
|
+
this.router = new router_1.MessageRouter(db, config.router, config.agentDaemon);
|
|
57
|
+
this.securityManager = new security_1.SecurityManager(db);
|
|
58
|
+
this.sessionManager = new session_1.SessionManager(db);
|
|
59
|
+
this.channelRepo = new repositories_1.ChannelRepository(db);
|
|
60
|
+
this.userRepo = new repositories_1.ChannelUserRepository(db);
|
|
61
|
+
this.sessionRepo = new repositories_1.ChannelSessionRepository(db);
|
|
62
|
+
this.messageRepo = new repositories_1.ChannelMessageRepository(db);
|
|
63
|
+
// Listen for agent daemon events to send responses back to channels
|
|
64
|
+
if (config.agentDaemon) {
|
|
65
|
+
this.agentDaemon = config.agentDaemon;
|
|
66
|
+
this.setupAgentDaemonListeners(config.agentDaemon);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the channel message context from personality settings
|
|
71
|
+
*/
|
|
72
|
+
getMessageContext() {
|
|
73
|
+
try {
|
|
74
|
+
if (personality_manager_1.PersonalityManager.isInitialized()) {
|
|
75
|
+
const settings = personality_manager_1.PersonalityManager.loadSettings();
|
|
76
|
+
return {
|
|
77
|
+
agentName: settings.agentName || 'CoWork',
|
|
78
|
+
userName: settings.relationship?.userName,
|
|
79
|
+
personality: settings.activePersonality || 'professional',
|
|
80
|
+
emojiUsage: settings.responseStyle?.emojiUsage || 'minimal',
|
|
81
|
+
quirks: settings.quirks || types_1.DEFAULT_QUIRKS,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error('[ChannelGateway] Failed to load personality settings:', error);
|
|
87
|
+
}
|
|
88
|
+
return channelMessages_1.DEFAULT_CHANNEL_CONTEXT;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Set up listeners for agent daemon events
|
|
92
|
+
*/
|
|
93
|
+
setupAgentDaemonListeners(agentDaemon) {
|
|
94
|
+
// Track the last assistant message for each task to send as completion result
|
|
95
|
+
const lastMessages = new Map();
|
|
96
|
+
// Listen for assistant messages (streaming responses)
|
|
97
|
+
// Note: daemon emits { taskId, message } not { taskId, content }
|
|
98
|
+
const onAssistantMessage = (data) => {
|
|
99
|
+
const message = data.message;
|
|
100
|
+
if (message && message.length > 10) {
|
|
101
|
+
// Keep the BEST (longest substantive) answer, not just the last one
|
|
102
|
+
// This prevents confused step messages from overwriting good answers
|
|
103
|
+
const existingMessage = lastMessages.get(data.taskId);
|
|
104
|
+
const isConfusedMessage = message.toLowerCase().includes("don't have") ||
|
|
105
|
+
message.toLowerCase().includes("please provide") ||
|
|
106
|
+
message.toLowerCase().includes("i cannot") ||
|
|
107
|
+
message.toLowerCase().includes("not available");
|
|
108
|
+
// Only overwrite if new message is better (longer and not confused)
|
|
109
|
+
if (!existingMessage || (!isConfusedMessage && message.length >= existingMessage.length)) {
|
|
110
|
+
lastMessages.set(data.taskId, message);
|
|
111
|
+
}
|
|
112
|
+
// Always stream updates to channel (so user sees progress)
|
|
113
|
+
this.router.sendTaskUpdate(data.taskId, message);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
agentDaemon.on('assistant_message', onAssistantMessage);
|
|
117
|
+
this.daemonListeners.push({ event: 'assistant_message', handler: onAssistantMessage });
|
|
118
|
+
// Listen for task completion
|
|
119
|
+
const onTaskCompleted = (data) => {
|
|
120
|
+
// Use the last assistant message as the result
|
|
121
|
+
const result = lastMessages.get(data.taskId);
|
|
122
|
+
this.router.handleTaskCompletion(data.taskId, result);
|
|
123
|
+
lastMessages.delete(data.taskId);
|
|
124
|
+
};
|
|
125
|
+
agentDaemon.on('task_completed', onTaskCompleted);
|
|
126
|
+
this.daemonListeners.push({ event: 'task_completed', handler: onTaskCompleted });
|
|
127
|
+
// Listen for task errors
|
|
128
|
+
// Note: daemon emits { taskId, error } or { taskId, message }
|
|
129
|
+
const onError = (data) => {
|
|
130
|
+
const errorMsg = data.error || data.message || 'Unknown error';
|
|
131
|
+
this.router.handleTaskFailure(data.taskId, errorMsg);
|
|
132
|
+
lastMessages.delete(data.taskId);
|
|
133
|
+
};
|
|
134
|
+
agentDaemon.on('error', onError);
|
|
135
|
+
this.daemonListeners.push({ event: 'error', handler: onError });
|
|
136
|
+
// Listen for tool errors (individual tool execution failures)
|
|
137
|
+
const onToolError = (data) => {
|
|
138
|
+
const toolName = data.tool || 'Unknown tool';
|
|
139
|
+
const errorMsg = data.error || 'Unknown error';
|
|
140
|
+
const message = (0, channelMessages_1.getChannelMessage)('toolError', this.getMessageContext(), { tool: toolName, error: errorMsg });
|
|
141
|
+
this.router.sendTaskUpdate(data.taskId, message);
|
|
142
|
+
};
|
|
143
|
+
agentDaemon.on('tool_error', onToolError);
|
|
144
|
+
this.daemonListeners.push({ event: 'tool_error', handler: onToolError });
|
|
145
|
+
// Listen for follow-up message completion
|
|
146
|
+
// Track if any assistant messages were sent during follow-up
|
|
147
|
+
const followUpMessagesSent = new Map();
|
|
148
|
+
const originalOnAssistantMessage = onAssistantMessage;
|
|
149
|
+
// Override to track follow-up messages
|
|
150
|
+
agentDaemon.off('assistant_message', onAssistantMessage);
|
|
151
|
+
const trackingAssistantMessage = (data) => {
|
|
152
|
+
followUpMessagesSent.set(data.taskId, true);
|
|
153
|
+
originalOnAssistantMessage(data);
|
|
154
|
+
};
|
|
155
|
+
agentDaemon.on('assistant_message', trackingAssistantMessage);
|
|
156
|
+
// Update the stored handler
|
|
157
|
+
const assistantIdx = this.daemonListeners.findIndex(l => l.event === 'assistant_message');
|
|
158
|
+
if (assistantIdx >= 0) {
|
|
159
|
+
this.daemonListeners[assistantIdx] = { event: 'assistant_message', handler: trackingAssistantMessage };
|
|
160
|
+
}
|
|
161
|
+
const onFollowUpCompleted = async (data) => {
|
|
162
|
+
// If no assistant messages were sent during the follow-up, send a confirmation
|
|
163
|
+
if (!followUpMessagesSent.get(data.taskId)) {
|
|
164
|
+
const message = (0, channelMessages_1.getChannelMessage)('followUpProcessed', this.getMessageContext());
|
|
165
|
+
this.router.sendTaskUpdate(data.taskId, message);
|
|
166
|
+
}
|
|
167
|
+
followUpMessagesSent.delete(data.taskId);
|
|
168
|
+
// Send any artifacts (images, screenshots) created during the follow-up
|
|
169
|
+
await this.router.sendArtifacts(data.taskId);
|
|
170
|
+
};
|
|
171
|
+
agentDaemon.on('follow_up_completed', onFollowUpCompleted);
|
|
172
|
+
this.daemonListeners.push({ event: 'follow_up_completed', handler: onFollowUpCompleted });
|
|
173
|
+
// Listen for follow-up failures
|
|
174
|
+
const onFollowUpFailed = (data) => {
|
|
175
|
+
const errorMsg = data.error || 'Unknown error';
|
|
176
|
+
const message = (0, channelMessages_1.getChannelMessage)('followUpFailed', this.getMessageContext(), { error: errorMsg });
|
|
177
|
+
this.router.sendTaskUpdate(data.taskId, message);
|
|
178
|
+
followUpMessagesSent.delete(data.taskId);
|
|
179
|
+
};
|
|
180
|
+
agentDaemon.on('follow_up_failed', onFollowUpFailed);
|
|
181
|
+
this.daemonListeners.push({ event: 'follow_up_failed', handler: onFollowUpFailed });
|
|
182
|
+
// Listen for approval requests - forward to Discord/Telegram
|
|
183
|
+
const onApprovalRequested = (data) => {
|
|
184
|
+
this.router.sendApprovalRequest(data.taskId, data.approval);
|
|
185
|
+
};
|
|
186
|
+
agentDaemon.on('approval_requested', onApprovalRequested);
|
|
187
|
+
this.daemonListeners.push({ event: 'approval_requested', handler: onApprovalRequested });
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Initialize the gateway
|
|
191
|
+
*/
|
|
192
|
+
async initialize(mainWindow) {
|
|
193
|
+
if (this.initialized)
|
|
194
|
+
return;
|
|
195
|
+
if (mainWindow) {
|
|
196
|
+
this.router.setMainWindow(mainWindow);
|
|
197
|
+
}
|
|
198
|
+
// Load and register enabled channels
|
|
199
|
+
await this.loadChannels();
|
|
200
|
+
// Auto-connect if configured
|
|
201
|
+
if (this.config.autoConnect) {
|
|
202
|
+
await this.router.connectAll();
|
|
203
|
+
}
|
|
204
|
+
this.initialized = true;
|
|
205
|
+
console.log('Channel Gateway initialized');
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Set the main window for IPC communication
|
|
209
|
+
*/
|
|
210
|
+
setMainWindow(window) {
|
|
211
|
+
this.router.setMainWindow(window);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Shutdown the gateway
|
|
215
|
+
*/
|
|
216
|
+
async shutdown() {
|
|
217
|
+
// Clean up daemon event listeners
|
|
218
|
+
if (this.agentDaemon) {
|
|
219
|
+
for (const { event, handler } of this.daemonListeners) {
|
|
220
|
+
this.agentDaemon.off(event, handler);
|
|
221
|
+
}
|
|
222
|
+
this.daemonListeners = [];
|
|
223
|
+
}
|
|
224
|
+
await this.router.disconnectAll();
|
|
225
|
+
this.initialized = false;
|
|
226
|
+
console.log('Channel Gateway shutdown');
|
|
227
|
+
}
|
|
228
|
+
// Channel Management
|
|
229
|
+
/**
|
|
230
|
+
* Add a new Telegram channel
|
|
231
|
+
*/
|
|
232
|
+
async addTelegramChannel(name, botToken, securityMode = 'pairing') {
|
|
233
|
+
// Check if Telegram channel already exists
|
|
234
|
+
const existing = this.channelRepo.findByType('telegram');
|
|
235
|
+
if (existing) {
|
|
236
|
+
throw new Error('Telegram channel already configured. Update or remove it first.');
|
|
237
|
+
}
|
|
238
|
+
// Create channel record
|
|
239
|
+
const channel = this.channelRepo.create({
|
|
240
|
+
type: 'telegram',
|
|
241
|
+
name,
|
|
242
|
+
enabled: false, // Don't enable until tested
|
|
243
|
+
config: { botToken },
|
|
244
|
+
securityConfig: {
|
|
245
|
+
mode: securityMode,
|
|
246
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
247
|
+
maxPairingAttempts: 5,
|
|
248
|
+
rateLimitPerMinute: 30,
|
|
249
|
+
},
|
|
250
|
+
status: 'disconnected',
|
|
251
|
+
});
|
|
252
|
+
return channel;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Add a new Discord channel
|
|
256
|
+
*/
|
|
257
|
+
async addDiscordChannel(name, botToken, applicationId, guildIds, securityMode = 'pairing') {
|
|
258
|
+
// Check if Discord channel already exists
|
|
259
|
+
const existing = this.channelRepo.findByType('discord');
|
|
260
|
+
if (existing) {
|
|
261
|
+
throw new Error('Discord channel already configured. Update or remove it first.');
|
|
262
|
+
}
|
|
263
|
+
// Create channel record
|
|
264
|
+
const channel = this.channelRepo.create({
|
|
265
|
+
type: 'discord',
|
|
266
|
+
name,
|
|
267
|
+
enabled: false, // Don't enable until tested
|
|
268
|
+
config: { botToken, applicationId, guildIds },
|
|
269
|
+
securityConfig: {
|
|
270
|
+
mode: securityMode,
|
|
271
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
272
|
+
maxPairingAttempts: 5,
|
|
273
|
+
rateLimitPerMinute: 30,
|
|
274
|
+
},
|
|
275
|
+
status: 'disconnected',
|
|
276
|
+
});
|
|
277
|
+
return channel;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Add a new Slack channel
|
|
281
|
+
*/
|
|
282
|
+
async addSlackChannel(name, botToken, appToken, signingSecret, securityMode = 'pairing') {
|
|
283
|
+
// Check if Slack channel already exists
|
|
284
|
+
const existing = this.channelRepo.findByType('slack');
|
|
285
|
+
if (existing) {
|
|
286
|
+
throw new Error('Slack channel already configured. Update or remove it first.');
|
|
287
|
+
}
|
|
288
|
+
// Create channel record
|
|
289
|
+
const channel = this.channelRepo.create({
|
|
290
|
+
type: 'slack',
|
|
291
|
+
name,
|
|
292
|
+
enabled: false, // Don't enable until tested
|
|
293
|
+
config: { botToken, appToken, signingSecret },
|
|
294
|
+
securityConfig: {
|
|
295
|
+
mode: securityMode,
|
|
296
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
297
|
+
maxPairingAttempts: 5,
|
|
298
|
+
rateLimitPerMinute: 30,
|
|
299
|
+
},
|
|
300
|
+
status: 'disconnected',
|
|
301
|
+
});
|
|
302
|
+
return channel;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Add a new WhatsApp channel
|
|
306
|
+
*/
|
|
307
|
+
async addWhatsAppChannel(name, allowedNumbers, securityMode = 'pairing', selfChatMode = true, responsePrefix = '🤖') {
|
|
308
|
+
// Check if WhatsApp channel already exists
|
|
309
|
+
const existing = this.channelRepo.findByType('whatsapp');
|
|
310
|
+
if (existing) {
|
|
311
|
+
throw new Error('WhatsApp channel already configured. Update or remove it first.');
|
|
312
|
+
}
|
|
313
|
+
// Create channel record
|
|
314
|
+
const channel = this.channelRepo.create({
|
|
315
|
+
type: 'whatsapp',
|
|
316
|
+
name,
|
|
317
|
+
enabled: false, // Don't enable until QR code is scanned
|
|
318
|
+
config: {
|
|
319
|
+
allowedNumbers,
|
|
320
|
+
selfChatMode,
|
|
321
|
+
responsePrefix,
|
|
322
|
+
},
|
|
323
|
+
securityConfig: {
|
|
324
|
+
mode: securityMode,
|
|
325
|
+
allowedUsers: allowedNumbers,
|
|
326
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
327
|
+
maxPairingAttempts: 5,
|
|
328
|
+
rateLimitPerMinute: 30,
|
|
329
|
+
},
|
|
330
|
+
status: 'disconnected',
|
|
331
|
+
});
|
|
332
|
+
return channel;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Add a new iMessage channel
|
|
336
|
+
*/
|
|
337
|
+
async addImessageChannel(name, cliPath, dbPath, allowedContacts, securityMode = 'pairing', dmPolicy = 'pairing', groupPolicy = 'allowlist') {
|
|
338
|
+
// Check if iMessage channel already exists
|
|
339
|
+
const existing = this.channelRepo.findByType('imessage');
|
|
340
|
+
if (existing) {
|
|
341
|
+
throw new Error('iMessage channel already configured. Update or remove it first.');
|
|
342
|
+
}
|
|
343
|
+
// Create channel record
|
|
344
|
+
const channel = this.channelRepo.create({
|
|
345
|
+
type: 'imessage',
|
|
346
|
+
name,
|
|
347
|
+
enabled: false, // Don't enable until connected
|
|
348
|
+
config: {
|
|
349
|
+
cliPath,
|
|
350
|
+
dbPath,
|
|
351
|
+
allowedContacts,
|
|
352
|
+
dmPolicy,
|
|
353
|
+
groupPolicy,
|
|
354
|
+
},
|
|
355
|
+
securityConfig: {
|
|
356
|
+
mode: securityMode,
|
|
357
|
+
allowedUsers: allowedContacts,
|
|
358
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
359
|
+
maxPairingAttempts: 5,
|
|
360
|
+
rateLimitPerMinute: 30,
|
|
361
|
+
},
|
|
362
|
+
status: 'disconnected',
|
|
363
|
+
});
|
|
364
|
+
return channel;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Add a new Signal channel
|
|
368
|
+
*/
|
|
369
|
+
async addSignalChannel(name, phoneNumber, dataDir, securityMode = 'pairing', mode = 'native', trustMode = 'tofu', dmPolicy = 'pairing', groupPolicy = 'allowlist', sendReadReceipts = true, sendTypingIndicators = true) {
|
|
370
|
+
// Check if Signal channel already exists
|
|
371
|
+
const existing = this.channelRepo.findByType('signal');
|
|
372
|
+
if (existing) {
|
|
373
|
+
throw new Error('Signal channel already configured. Update or remove it first.');
|
|
374
|
+
}
|
|
375
|
+
// Create channel record
|
|
376
|
+
const channel = this.channelRepo.create({
|
|
377
|
+
type: 'signal',
|
|
378
|
+
name,
|
|
379
|
+
enabled: false, // Don't enable until connected
|
|
380
|
+
config: {
|
|
381
|
+
phoneNumber,
|
|
382
|
+
dataDir,
|
|
383
|
+
mode,
|
|
384
|
+
trustMode,
|
|
385
|
+
dmPolicy,
|
|
386
|
+
groupPolicy,
|
|
387
|
+
sendReadReceipts,
|
|
388
|
+
sendTypingIndicators,
|
|
389
|
+
},
|
|
390
|
+
securityConfig: {
|
|
391
|
+
mode: securityMode,
|
|
392
|
+
allowedUsers: [],
|
|
393
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
394
|
+
maxPairingAttempts: 5,
|
|
395
|
+
rateLimitPerMinute: 30,
|
|
396
|
+
},
|
|
397
|
+
status: 'disconnected',
|
|
398
|
+
});
|
|
399
|
+
return channel;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Add a new Mattermost channel
|
|
403
|
+
*/
|
|
404
|
+
async addMattermostChannel(name, serverUrl, token, teamId, securityMode = 'pairing') {
|
|
405
|
+
// Check if Mattermost channel already exists
|
|
406
|
+
const existing = this.channelRepo.findByType('mattermost');
|
|
407
|
+
if (existing) {
|
|
408
|
+
throw new Error('Mattermost channel already configured. Update or remove it first.');
|
|
409
|
+
}
|
|
410
|
+
// Create channel record
|
|
411
|
+
const channel = this.channelRepo.create({
|
|
412
|
+
type: 'mattermost',
|
|
413
|
+
name,
|
|
414
|
+
enabled: false, // Don't enable until connected
|
|
415
|
+
config: {
|
|
416
|
+
serverUrl,
|
|
417
|
+
token,
|
|
418
|
+
teamId,
|
|
419
|
+
},
|
|
420
|
+
securityConfig: {
|
|
421
|
+
mode: securityMode,
|
|
422
|
+
allowedUsers: [],
|
|
423
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
424
|
+
maxPairingAttempts: 5,
|
|
425
|
+
rateLimitPerMinute: 30,
|
|
426
|
+
},
|
|
427
|
+
status: 'disconnected',
|
|
428
|
+
});
|
|
429
|
+
return channel;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Add a new Matrix channel
|
|
433
|
+
*/
|
|
434
|
+
async addMatrixChannel(name, homeserver, userId, accessToken, deviceId, roomIds, securityMode = 'pairing') {
|
|
435
|
+
// Check if Matrix channel already exists
|
|
436
|
+
const existing = this.channelRepo.findByType('matrix');
|
|
437
|
+
if (existing) {
|
|
438
|
+
throw new Error('Matrix channel already configured. Update or remove it first.');
|
|
439
|
+
}
|
|
440
|
+
// Create channel record
|
|
441
|
+
const channel = this.channelRepo.create({
|
|
442
|
+
type: 'matrix',
|
|
443
|
+
name,
|
|
444
|
+
enabled: false, // Don't enable until connected
|
|
445
|
+
config: {
|
|
446
|
+
homeserver,
|
|
447
|
+
userId,
|
|
448
|
+
accessToken,
|
|
449
|
+
deviceId,
|
|
450
|
+
roomIds,
|
|
451
|
+
},
|
|
452
|
+
securityConfig: {
|
|
453
|
+
mode: securityMode,
|
|
454
|
+
allowedUsers: [],
|
|
455
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
456
|
+
maxPairingAttempts: 5,
|
|
457
|
+
rateLimitPerMinute: 30,
|
|
458
|
+
},
|
|
459
|
+
status: 'disconnected',
|
|
460
|
+
});
|
|
461
|
+
return channel;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Add a new Twitch channel
|
|
465
|
+
*/
|
|
466
|
+
async addTwitchChannel(name, username, oauthToken, channels, allowWhispers = false, securityMode = 'pairing') {
|
|
467
|
+
// Check if Twitch channel already exists
|
|
468
|
+
const existing = this.channelRepo.findByType('twitch');
|
|
469
|
+
if (existing) {
|
|
470
|
+
throw new Error('Twitch channel already configured. Update or remove it first.');
|
|
471
|
+
}
|
|
472
|
+
// Create channel record
|
|
473
|
+
const channel = this.channelRepo.create({
|
|
474
|
+
type: 'twitch',
|
|
475
|
+
name,
|
|
476
|
+
enabled: false, // Don't enable until connected
|
|
477
|
+
config: {
|
|
478
|
+
username,
|
|
479
|
+
oauthToken,
|
|
480
|
+
channels,
|
|
481
|
+
allowWhispers,
|
|
482
|
+
},
|
|
483
|
+
securityConfig: {
|
|
484
|
+
mode: securityMode,
|
|
485
|
+
allowedUsers: [],
|
|
486
|
+
pairingCodeTTL: 300, // 5 minutes
|
|
487
|
+
maxPairingAttempts: 5,
|
|
488
|
+
rateLimitPerMinute: 30,
|
|
489
|
+
},
|
|
490
|
+
status: 'disconnected',
|
|
491
|
+
});
|
|
492
|
+
return channel;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Add a new LINE channel
|
|
496
|
+
*/
|
|
497
|
+
async addLineChannel(name, channelAccessToken, channelSecret, webhookPort = 3100, securityMode = 'pairing') {
|
|
498
|
+
// Check if LINE channel already exists
|
|
499
|
+
const existing = this.channelRepo.findByType('line');
|
|
500
|
+
if (existing) {
|
|
501
|
+
throw new Error('LINE channel already configured. Update or remove it first.');
|
|
502
|
+
}
|
|
503
|
+
// Create channel record
|
|
504
|
+
const channel = this.channelRepo.create({
|
|
505
|
+
type: 'line',
|
|
506
|
+
name,
|
|
507
|
+
enabled: false, // Don't enable until connected
|
|
508
|
+
config: {
|
|
509
|
+
channelAccessToken,
|
|
510
|
+
channelSecret,
|
|
511
|
+
webhookPort,
|
|
512
|
+
},
|
|
513
|
+
securityConfig: {
|
|
514
|
+
mode: securityMode,
|
|
515
|
+
allowedUsers: [],
|
|
516
|
+
pairingCodeTTL: 300,
|
|
517
|
+
maxPairingAttempts: 5,
|
|
518
|
+
rateLimitPerMinute: 30,
|
|
519
|
+
},
|
|
520
|
+
status: 'disconnected',
|
|
521
|
+
});
|
|
522
|
+
return channel;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Add a new BlueBubbles channel
|
|
526
|
+
*/
|
|
527
|
+
async addBlueBubblesChannel(name, serverUrl, password, webhookPort = 3101, allowedContacts, securityMode = 'pairing') {
|
|
528
|
+
// Check if BlueBubbles channel already exists
|
|
529
|
+
const existing = this.channelRepo.findByType('bluebubbles');
|
|
530
|
+
if (existing) {
|
|
531
|
+
throw new Error('BlueBubbles channel already configured. Update or remove it first.');
|
|
532
|
+
}
|
|
533
|
+
// Create channel record
|
|
534
|
+
const channel = this.channelRepo.create({
|
|
535
|
+
type: 'bluebubbles',
|
|
536
|
+
name,
|
|
537
|
+
enabled: false, // Don't enable until connected
|
|
538
|
+
config: {
|
|
539
|
+
serverUrl,
|
|
540
|
+
password,
|
|
541
|
+
webhookPort,
|
|
542
|
+
allowedContacts,
|
|
543
|
+
},
|
|
544
|
+
securityConfig: {
|
|
545
|
+
mode: securityMode,
|
|
546
|
+
allowedUsers: allowedContacts || [],
|
|
547
|
+
pairingCodeTTL: 300,
|
|
548
|
+
maxPairingAttempts: 5,
|
|
549
|
+
rateLimitPerMinute: 30,
|
|
550
|
+
},
|
|
551
|
+
status: 'disconnected',
|
|
552
|
+
});
|
|
553
|
+
return channel;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Add a new Email channel
|
|
557
|
+
*/
|
|
558
|
+
async addEmailChannel(name, email, password, imapHost, smtpHost, displayName, allowedSenders, subjectFilter, securityMode = 'pairing') {
|
|
559
|
+
// Check if Email channel already exists
|
|
560
|
+
const existing = this.channelRepo.findByType('email');
|
|
561
|
+
if (existing) {
|
|
562
|
+
throw new Error('Email channel already configured. Update or remove it first.');
|
|
563
|
+
}
|
|
564
|
+
// Create channel record
|
|
565
|
+
const channel = this.channelRepo.create({
|
|
566
|
+
type: 'email',
|
|
567
|
+
name,
|
|
568
|
+
enabled: false, // Don't enable until connected
|
|
569
|
+
config: {
|
|
570
|
+
email,
|
|
571
|
+
password,
|
|
572
|
+
imapHost,
|
|
573
|
+
smtpHost,
|
|
574
|
+
displayName,
|
|
575
|
+
allowedSenders,
|
|
576
|
+
subjectFilter,
|
|
577
|
+
},
|
|
578
|
+
securityConfig: {
|
|
579
|
+
mode: securityMode,
|
|
580
|
+
allowedUsers: allowedSenders || [],
|
|
581
|
+
pairingCodeTTL: 300,
|
|
582
|
+
maxPairingAttempts: 5,
|
|
583
|
+
rateLimitPerMinute: 30,
|
|
584
|
+
},
|
|
585
|
+
status: 'disconnected',
|
|
586
|
+
});
|
|
587
|
+
return channel;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Update a channel configuration
|
|
591
|
+
*/
|
|
592
|
+
updateChannel(channelId, updates) {
|
|
593
|
+
this.channelRepo.update(channelId, updates);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Enable a channel and connect
|
|
597
|
+
*/
|
|
598
|
+
async enableChannel(channelId) {
|
|
599
|
+
const channel = this.channelRepo.findById(channelId);
|
|
600
|
+
if (!channel) {
|
|
601
|
+
throw new Error('Channel not found');
|
|
602
|
+
}
|
|
603
|
+
// Create and register adapter if not already done
|
|
604
|
+
let adapter = this.router.getAdapter(channel.type);
|
|
605
|
+
if (!adapter) {
|
|
606
|
+
adapter = this.createAdapterForChannel(channel);
|
|
607
|
+
this.router.registerAdapter(adapter);
|
|
608
|
+
}
|
|
609
|
+
// Update channel state
|
|
610
|
+
this.channelRepo.update(channelId, { enabled: true });
|
|
611
|
+
// Connect
|
|
612
|
+
await adapter.connect();
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Disable a channel and disconnect
|
|
616
|
+
*/
|
|
617
|
+
async disableChannel(channelId) {
|
|
618
|
+
const channel = this.channelRepo.findById(channelId);
|
|
619
|
+
if (!channel) {
|
|
620
|
+
throw new Error('Channel not found');
|
|
621
|
+
}
|
|
622
|
+
const adapter = this.router.getAdapter(channel.type);
|
|
623
|
+
if (adapter) {
|
|
624
|
+
await adapter.disconnect();
|
|
625
|
+
}
|
|
626
|
+
this.channelRepo.update(channelId, { enabled: false, status: 'disconnected' });
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Enable WhatsApp channel and set up QR code forwarding
|
|
630
|
+
* This method connects the WhatsApp adapter and forwards QR codes to the renderer
|
|
631
|
+
*/
|
|
632
|
+
async enableWhatsAppWithQRForwarding(channelId) {
|
|
633
|
+
const channel = this.channelRepo.findById(channelId);
|
|
634
|
+
if (!channel || channel.type !== 'whatsapp') {
|
|
635
|
+
throw new Error('WhatsApp channel not found');
|
|
636
|
+
}
|
|
637
|
+
// Create and register adapter if not already done
|
|
638
|
+
let adapter = this.router.getAdapter('whatsapp');
|
|
639
|
+
if (!adapter) {
|
|
640
|
+
adapter = this.createAdapterForChannel(channel);
|
|
641
|
+
this.router.registerAdapter(adapter);
|
|
642
|
+
}
|
|
643
|
+
// Set up QR code forwarding to renderer
|
|
644
|
+
const mainWindow = this.router.getMainWindow();
|
|
645
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
646
|
+
adapter.onQrCode((qr) => {
|
|
647
|
+
console.log('WhatsApp QR code received, forwarding to renderer');
|
|
648
|
+
if (!mainWindow.isDestroyed()) {
|
|
649
|
+
mainWindow.webContents.send('whatsapp:qr-code', qr);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
adapter.onStatusChange((status, error) => {
|
|
653
|
+
console.log(`WhatsApp status changed to: ${status}`);
|
|
654
|
+
if (!mainWindow.isDestroyed()) {
|
|
655
|
+
mainWindow.webContents.send('whatsapp:status', { status, error: error?.message });
|
|
656
|
+
if (status === 'connected') {
|
|
657
|
+
mainWindow.webContents.send('whatsapp:connected');
|
|
658
|
+
// Update channel status in database
|
|
659
|
+
this.channelRepo.update(channelId, {
|
|
660
|
+
enabled: true,
|
|
661
|
+
status: 'connected',
|
|
662
|
+
botUsername: adapter?.botUsername,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
else if (status === 'error') {
|
|
666
|
+
this.channelRepo.update(channelId, { status: 'error' });
|
|
667
|
+
}
|
|
668
|
+
else if (status === 'disconnected') {
|
|
669
|
+
this.channelRepo.update(channelId, { status: 'disconnected' });
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// Update channel state to connecting
|
|
675
|
+
this.channelRepo.update(channelId, { enabled: true, status: 'connecting' });
|
|
676
|
+
// Connect (this will trigger QR code generation)
|
|
677
|
+
await adapter.connect();
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Get WhatsApp channel info including QR code
|
|
681
|
+
*/
|
|
682
|
+
async getWhatsAppInfo() {
|
|
683
|
+
const channel = this.channelRepo.findByType('whatsapp');
|
|
684
|
+
if (!channel) {
|
|
685
|
+
return {};
|
|
686
|
+
}
|
|
687
|
+
const adapter = this.router.getAdapter('whatsapp');
|
|
688
|
+
if (!adapter) {
|
|
689
|
+
return { status: channel.status };
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
qrCode: adapter.qrCode,
|
|
693
|
+
phoneNumber: adapter.botUsername,
|
|
694
|
+
status: adapter.status,
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Logout from WhatsApp and clear credentials
|
|
699
|
+
*/
|
|
700
|
+
async whatsAppLogout() {
|
|
701
|
+
const adapter = this.router.getAdapter('whatsapp');
|
|
702
|
+
if (adapter) {
|
|
703
|
+
await adapter.logout();
|
|
704
|
+
}
|
|
705
|
+
const channel = this.channelRepo.findByType('whatsapp');
|
|
706
|
+
if (channel) {
|
|
707
|
+
this.channelRepo.update(channel.id, { enabled: false, status: 'disconnected', botUsername: undefined });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Remove a channel
|
|
712
|
+
*/
|
|
713
|
+
async removeChannel(channelId) {
|
|
714
|
+
await this.disableChannel(channelId);
|
|
715
|
+
// Delete associated data first (to avoid foreign key constraint errors)
|
|
716
|
+
this.messageRepo.deleteByChannelId(channelId);
|
|
717
|
+
this.sessionRepo.deleteByChannelId(channelId);
|
|
718
|
+
this.userRepo.deleteByChannelId(channelId);
|
|
719
|
+
// Now delete the channel
|
|
720
|
+
this.channelRepo.delete(channelId);
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Test a channel connection without enabling it
|
|
724
|
+
*/
|
|
725
|
+
async testChannel(channelId) {
|
|
726
|
+
const channel = this.channelRepo.findById(channelId);
|
|
727
|
+
if (!channel) {
|
|
728
|
+
return { success: false, error: 'Channel not found' };
|
|
729
|
+
}
|
|
730
|
+
try {
|
|
731
|
+
const adapter = this.createAdapterForChannel(channel);
|
|
732
|
+
await adapter.connect();
|
|
733
|
+
const info = await adapter.getInfo();
|
|
734
|
+
await adapter.disconnect();
|
|
735
|
+
return {
|
|
736
|
+
success: true,
|
|
737
|
+
botUsername: info.botUsername,
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
return {
|
|
742
|
+
success: false,
|
|
743
|
+
error: error instanceof Error ? error.message : String(error),
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Get all channels
|
|
749
|
+
*/
|
|
750
|
+
getChannels() {
|
|
751
|
+
return this.channelRepo.findAll();
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Get a channel by ID
|
|
755
|
+
*/
|
|
756
|
+
getChannel(channelId) {
|
|
757
|
+
return this.channelRepo.findById(channelId);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Get channel by type
|
|
761
|
+
*/
|
|
762
|
+
getChannelByType(type) {
|
|
763
|
+
return this.channelRepo.findByType(type);
|
|
764
|
+
}
|
|
765
|
+
// User Management
|
|
766
|
+
/**
|
|
767
|
+
* Generate a pairing code for a user
|
|
768
|
+
*/
|
|
769
|
+
generatePairingCode(channelId, userId, displayName) {
|
|
770
|
+
const channel = this.channelRepo.findById(channelId);
|
|
771
|
+
if (!channel) {
|
|
772
|
+
throw new Error('Channel not found');
|
|
773
|
+
}
|
|
774
|
+
return this.securityManager.generatePairingCode(channel, userId, displayName);
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Grant access to a user
|
|
778
|
+
*/
|
|
779
|
+
grantUserAccess(channelId, userId, displayName) {
|
|
780
|
+
this.securityManager.grantAccess(channelId, userId, displayName);
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Revoke user access
|
|
784
|
+
*/
|
|
785
|
+
revokeUserAccess(channelId, userId) {
|
|
786
|
+
this.securityManager.revokeAccess(channelId, userId);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Get users for a channel
|
|
790
|
+
* Automatically cleans up expired pending pairing entries
|
|
791
|
+
*/
|
|
792
|
+
getChannelUsers(channelId) {
|
|
793
|
+
// Use securityManager to trigger cleanup of expired pending entries
|
|
794
|
+
return this.securityManager.getChannelUsers(channelId);
|
|
795
|
+
}
|
|
796
|
+
// Messaging
|
|
797
|
+
/**
|
|
798
|
+
* Send a message to a channel chat
|
|
799
|
+
*/
|
|
800
|
+
async sendMessage(channelType, chatId, text, options) {
|
|
801
|
+
return this.router.sendMessage(channelType, {
|
|
802
|
+
chatId,
|
|
803
|
+
text,
|
|
804
|
+
replyTo: options?.replyTo,
|
|
805
|
+
parseMode: options?.parseMode,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Send a message to a session's chat
|
|
810
|
+
*/
|
|
811
|
+
async sendMessageToSession(sessionId, text, options) {
|
|
812
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
813
|
+
if (!session) {
|
|
814
|
+
console.error('Session not found:', sessionId);
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
const channel = this.channelRepo.findById(session.channelId);
|
|
818
|
+
if (!channel) {
|
|
819
|
+
console.error('Channel not found:', session.channelId);
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
return this.router.sendMessage(channel.type, {
|
|
823
|
+
chatId: session.chatId,
|
|
824
|
+
text,
|
|
825
|
+
replyTo: options?.replyTo,
|
|
826
|
+
parseMode: options?.parseMode,
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
// Events
|
|
830
|
+
/**
|
|
831
|
+
* Register an event handler
|
|
832
|
+
*/
|
|
833
|
+
onEvent(handler) {
|
|
834
|
+
this.router.onEvent(handler);
|
|
835
|
+
}
|
|
836
|
+
// Task response methods
|
|
837
|
+
/**
|
|
838
|
+
* Send a task update to the channel
|
|
839
|
+
*/
|
|
840
|
+
async sendTaskUpdate(taskId, text) {
|
|
841
|
+
return this.router.sendTaskUpdate(taskId, text);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Handle task completion
|
|
845
|
+
*/
|
|
846
|
+
async handleTaskCompletion(taskId, result) {
|
|
847
|
+
return this.router.handleTaskCompletion(taskId, result);
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Handle task failure
|
|
851
|
+
*/
|
|
852
|
+
async handleTaskFailure(taskId, error) {
|
|
853
|
+
return this.router.handleTaskFailure(taskId, error);
|
|
854
|
+
}
|
|
855
|
+
// Private methods
|
|
856
|
+
/**
|
|
857
|
+
* Load and register channel adapters
|
|
858
|
+
*/
|
|
859
|
+
async loadChannels() {
|
|
860
|
+
const channels = this.channelRepo.findAll();
|
|
861
|
+
for (const channel of channels) {
|
|
862
|
+
try {
|
|
863
|
+
const adapter = this.createAdapterForChannel(channel);
|
|
864
|
+
this.router.registerAdapter(adapter);
|
|
865
|
+
}
|
|
866
|
+
catch (error) {
|
|
867
|
+
console.error(`Failed to create adapter for channel ${channel.type}:`, error);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Create an adapter for a channel
|
|
873
|
+
*/
|
|
874
|
+
createAdapterForChannel(channel) {
|
|
875
|
+
switch (channel.type) {
|
|
876
|
+
case 'telegram':
|
|
877
|
+
return (0, telegram_1.createTelegramAdapter)({
|
|
878
|
+
enabled: channel.enabled,
|
|
879
|
+
botToken: channel.config.botToken,
|
|
880
|
+
webhookUrl: channel.config.webhookUrl,
|
|
881
|
+
});
|
|
882
|
+
case 'discord':
|
|
883
|
+
return (0, discord_1.createDiscordAdapter)({
|
|
884
|
+
enabled: channel.enabled,
|
|
885
|
+
botToken: channel.config.botToken,
|
|
886
|
+
applicationId: channel.config.applicationId,
|
|
887
|
+
guildIds: channel.config.guildIds,
|
|
888
|
+
});
|
|
889
|
+
case 'slack':
|
|
890
|
+
return (0, slack_1.createSlackAdapter)({
|
|
891
|
+
enabled: channel.enabled,
|
|
892
|
+
botToken: channel.config.botToken,
|
|
893
|
+
appToken: channel.config.appToken,
|
|
894
|
+
signingSecret: channel.config.signingSecret,
|
|
895
|
+
});
|
|
896
|
+
case 'whatsapp':
|
|
897
|
+
return (0, whatsapp_1.createWhatsAppAdapter)({
|
|
898
|
+
enabled: channel.enabled,
|
|
899
|
+
allowedNumbers: channel.config.allowedNumbers,
|
|
900
|
+
printQrToTerminal: true, // For debugging
|
|
901
|
+
selfChatMode: channel.config.selfChatMode ?? true,
|
|
902
|
+
responsePrefix: channel.config.responsePrefix ?? '🤖',
|
|
903
|
+
});
|
|
904
|
+
case 'imessage':
|
|
905
|
+
return (0, imessage_1.createImessageAdapter)({
|
|
906
|
+
enabled: channel.enabled,
|
|
907
|
+
cliPath: channel.config.cliPath,
|
|
908
|
+
dbPath: channel.config.dbPath,
|
|
909
|
+
dmPolicy: channel.config.dmPolicy,
|
|
910
|
+
groupPolicy: channel.config.groupPolicy,
|
|
911
|
+
allowedContacts: channel.config.allowedContacts,
|
|
912
|
+
responsePrefix: channel.config.responsePrefix,
|
|
913
|
+
});
|
|
914
|
+
case 'signal':
|
|
915
|
+
return (0, signal_1.createSignalAdapter)({
|
|
916
|
+
enabled: channel.enabled,
|
|
917
|
+
phoneNumber: channel.config.phoneNumber,
|
|
918
|
+
cliPath: channel.config.cliPath,
|
|
919
|
+
dataDir: channel.config.dataDir,
|
|
920
|
+
mode: channel.config.mode,
|
|
921
|
+
socketPath: channel.config.socketPath,
|
|
922
|
+
trustMode: channel.config.trustMode,
|
|
923
|
+
dmPolicy: channel.config.dmPolicy,
|
|
924
|
+
groupPolicy: channel.config.groupPolicy,
|
|
925
|
+
allowedNumbers: channel.config.allowedNumbers,
|
|
926
|
+
sendReadReceipts: channel.config.sendReadReceipts,
|
|
927
|
+
sendTypingIndicators: channel.config.sendTypingIndicators,
|
|
928
|
+
responsePrefix: channel.config.responsePrefix,
|
|
929
|
+
});
|
|
930
|
+
case 'mattermost':
|
|
931
|
+
return (0, mattermost_1.createMattermostAdapter)({
|
|
932
|
+
enabled: channel.enabled,
|
|
933
|
+
serverUrl: channel.config.serverUrl,
|
|
934
|
+
token: channel.config.token,
|
|
935
|
+
teamId: channel.config.teamId,
|
|
936
|
+
responsePrefix: channel.config.responsePrefix,
|
|
937
|
+
});
|
|
938
|
+
case 'matrix':
|
|
939
|
+
return (0, matrix_1.createMatrixAdapter)({
|
|
940
|
+
enabled: channel.enabled,
|
|
941
|
+
homeserver: channel.config.homeserver,
|
|
942
|
+
userId: channel.config.userId,
|
|
943
|
+
accessToken: channel.config.accessToken,
|
|
944
|
+
deviceId: channel.config.deviceId,
|
|
945
|
+
roomIds: channel.config.roomIds,
|
|
946
|
+
sendTypingIndicators: channel.config.sendTypingIndicators,
|
|
947
|
+
sendReadReceipts: channel.config.sendReadReceipts,
|
|
948
|
+
responsePrefix: channel.config.responsePrefix,
|
|
949
|
+
});
|
|
950
|
+
case 'twitch':
|
|
951
|
+
return (0, twitch_1.createTwitchAdapter)({
|
|
952
|
+
enabled: channel.enabled,
|
|
953
|
+
username: channel.config.username,
|
|
954
|
+
oauthToken: channel.config.oauthToken,
|
|
955
|
+
channels: channel.config.channels,
|
|
956
|
+
allowWhispers: channel.config.allowWhispers,
|
|
957
|
+
responsePrefix: channel.config.responsePrefix,
|
|
958
|
+
});
|
|
959
|
+
case 'line':
|
|
960
|
+
return (0, line_1.createLineAdapter)({
|
|
961
|
+
enabled: channel.enabled,
|
|
962
|
+
channelAccessToken: channel.config.channelAccessToken,
|
|
963
|
+
channelSecret: channel.config.channelSecret,
|
|
964
|
+
webhookPort: channel.config.webhookPort,
|
|
965
|
+
webhookPath: channel.config.webhookPath,
|
|
966
|
+
responsePrefix: channel.config.responsePrefix,
|
|
967
|
+
});
|
|
968
|
+
case 'bluebubbles':
|
|
969
|
+
return (0, bluebubbles_1.createBlueBubblesAdapter)({
|
|
970
|
+
enabled: channel.enabled,
|
|
971
|
+
serverUrl: channel.config.serverUrl,
|
|
972
|
+
password: channel.config.password,
|
|
973
|
+
webhookPort: channel.config.webhookPort,
|
|
974
|
+
webhookPath: channel.config.webhookPath,
|
|
975
|
+
pollInterval: channel.config.pollInterval,
|
|
976
|
+
allowedContacts: channel.config.allowedContacts,
|
|
977
|
+
responsePrefix: channel.config.responsePrefix,
|
|
978
|
+
});
|
|
979
|
+
case 'email':
|
|
980
|
+
return (0, email_1.createEmailAdapter)({
|
|
981
|
+
enabled: channel.enabled,
|
|
982
|
+
imapHost: channel.config.imapHost,
|
|
983
|
+
imapPort: channel.config.imapPort,
|
|
984
|
+
imapSecure: channel.config.imapSecure,
|
|
985
|
+
smtpHost: channel.config.smtpHost,
|
|
986
|
+
smtpPort: channel.config.smtpPort,
|
|
987
|
+
smtpSecure: channel.config.smtpSecure,
|
|
988
|
+
email: channel.config.email,
|
|
989
|
+
password: channel.config.password,
|
|
990
|
+
displayName: channel.config.displayName,
|
|
991
|
+
mailbox: channel.config.mailbox,
|
|
992
|
+
pollInterval: channel.config.pollInterval,
|
|
993
|
+
markAsRead: channel.config.markAsRead,
|
|
994
|
+
allowedSenders: channel.config.allowedSenders,
|
|
995
|
+
subjectFilter: channel.config.subjectFilter,
|
|
996
|
+
responsePrefix: channel.config.responsePrefix,
|
|
997
|
+
});
|
|
998
|
+
default:
|
|
999
|
+
throw new Error(`Unsupported channel type: ${channel.type}`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
exports.ChannelGateway = ChannelGateway;
|
|
1004
|
+
// Re-export types and components
|
|
1005
|
+
__exportStar(require("./channels/types"), exports);
|
|
1006
|
+
__exportStar(require("./router"), exports);
|
|
1007
|
+
__exportStar(require("./session"), exports);
|
|
1008
|
+
__exportStar(require("./security"), exports);
|
|
1009
|
+
__exportStar(require("./channel-registry"), exports);
|
|
1010
|
+
var telegram_2 = require("./channels/telegram");
|
|
1011
|
+
Object.defineProperty(exports, "TelegramAdapter", { enumerable: true, get: function () { return telegram_2.TelegramAdapter; } });
|
|
1012
|
+
Object.defineProperty(exports, "createTelegramAdapter", { enumerable: true, get: function () { return telegram_2.createTelegramAdapter; } });
|
|
1013
|
+
var discord_2 = require("./channels/discord");
|
|
1014
|
+
Object.defineProperty(exports, "DiscordAdapter", { enumerable: true, get: function () { return discord_2.DiscordAdapter; } });
|
|
1015
|
+
Object.defineProperty(exports, "createDiscordAdapter", { enumerable: true, get: function () { return discord_2.createDiscordAdapter; } });
|
|
1016
|
+
var slack_2 = require("./channels/slack");
|
|
1017
|
+
Object.defineProperty(exports, "SlackAdapter", { enumerable: true, get: function () { return slack_2.SlackAdapter; } });
|
|
1018
|
+
Object.defineProperty(exports, "createSlackAdapter", { enumerable: true, get: function () { return slack_2.createSlackAdapter; } });
|
|
1019
|
+
var whatsapp_2 = require("./channels/whatsapp");
|
|
1020
|
+
Object.defineProperty(exports, "WhatsAppAdapter", { enumerable: true, get: function () { return whatsapp_2.WhatsAppAdapter; } });
|
|
1021
|
+
Object.defineProperty(exports, "createWhatsAppAdapter", { enumerable: true, get: function () { return whatsapp_2.createWhatsAppAdapter; } });
|
|
1022
|
+
var imessage_2 = require("./channels/imessage");
|
|
1023
|
+
Object.defineProperty(exports, "ImessageAdapter", { enumerable: true, get: function () { return imessage_2.ImessageAdapter; } });
|
|
1024
|
+
Object.defineProperty(exports, "createImessageAdapter", { enumerable: true, get: function () { return imessage_2.createImessageAdapter; } });
|
|
1025
|
+
var signal_2 = require("./channels/signal");
|
|
1026
|
+
Object.defineProperty(exports, "SignalAdapter", { enumerable: true, get: function () { return signal_2.SignalAdapter; } });
|
|
1027
|
+
Object.defineProperty(exports, "createSignalAdapter", { enumerable: true, get: function () { return signal_2.createSignalAdapter; } });
|
|
1028
|
+
var signal_client_1 = require("./channels/signal-client");
|
|
1029
|
+
Object.defineProperty(exports, "SignalClient", { enumerable: true, get: function () { return signal_client_1.SignalClient; } });
|
|
1030
|
+
var mattermost_2 = require("./channels/mattermost");
|
|
1031
|
+
Object.defineProperty(exports, "MattermostAdapter", { enumerable: true, get: function () { return mattermost_2.MattermostAdapter; } });
|
|
1032
|
+
Object.defineProperty(exports, "createMattermostAdapter", { enumerable: true, get: function () { return mattermost_2.createMattermostAdapter; } });
|
|
1033
|
+
var mattermost_client_1 = require("./channels/mattermost-client");
|
|
1034
|
+
Object.defineProperty(exports, "MattermostClient", { enumerable: true, get: function () { return mattermost_client_1.MattermostClient; } });
|
|
1035
|
+
var matrix_2 = require("./channels/matrix");
|
|
1036
|
+
Object.defineProperty(exports, "MatrixAdapter", { enumerable: true, get: function () { return matrix_2.MatrixAdapter; } });
|
|
1037
|
+
Object.defineProperty(exports, "createMatrixAdapter", { enumerable: true, get: function () { return matrix_2.createMatrixAdapter; } });
|
|
1038
|
+
var matrix_client_1 = require("./channels/matrix-client");
|
|
1039
|
+
Object.defineProperty(exports, "MatrixClient", { enumerable: true, get: function () { return matrix_client_1.MatrixClient; } });
|
|
1040
|
+
var twitch_2 = require("./channels/twitch");
|
|
1041
|
+
Object.defineProperty(exports, "TwitchAdapter", { enumerable: true, get: function () { return twitch_2.TwitchAdapter; } });
|
|
1042
|
+
Object.defineProperty(exports, "createTwitchAdapter", { enumerable: true, get: function () { return twitch_2.createTwitchAdapter; } });
|
|
1043
|
+
var twitch_client_1 = require("./channels/twitch-client");
|
|
1044
|
+
Object.defineProperty(exports, "TwitchClient", { enumerable: true, get: function () { return twitch_client_1.TwitchClient; } });
|
|
1045
|
+
var line_2 = require("./channels/line");
|
|
1046
|
+
Object.defineProperty(exports, "LineAdapter", { enumerable: true, get: function () { return line_2.LineAdapter; } });
|
|
1047
|
+
Object.defineProperty(exports, "createLineAdapter", { enumerable: true, get: function () { return line_2.createLineAdapter; } });
|
|
1048
|
+
var line_client_1 = require("./channels/line-client");
|
|
1049
|
+
Object.defineProperty(exports, "LineClient", { enumerable: true, get: function () { return line_client_1.LineClient; } });
|
|
1050
|
+
var bluebubbles_2 = require("./channels/bluebubbles");
|
|
1051
|
+
Object.defineProperty(exports, "BlueBubblesAdapter", { enumerable: true, get: function () { return bluebubbles_2.BlueBubblesAdapter; } });
|
|
1052
|
+
Object.defineProperty(exports, "createBlueBubblesAdapter", { enumerable: true, get: function () { return bluebubbles_2.createBlueBubblesAdapter; } });
|
|
1053
|
+
var bluebubbles_client_1 = require("./channels/bluebubbles-client");
|
|
1054
|
+
Object.defineProperty(exports, "BlueBubblesClient", { enumerable: true, get: function () { return bluebubbles_client_1.BlueBubblesClient; } });
|
|
1055
|
+
var email_2 = require("./channels/email");
|
|
1056
|
+
Object.defineProperty(exports, "EmailAdapter", { enumerable: true, get: function () { return email_2.EmailAdapter; } });
|
|
1057
|
+
Object.defineProperty(exports, "createEmailAdapter", { enumerable: true, get: function () { return email_2.createEmailAdapter; } });
|
|
1058
|
+
var email_client_1 = require("./channels/email-client");
|
|
1059
|
+
Object.defineProperty(exports, "EmailClient", { enumerable: true, get: function () { return email_client_1.EmailClient; } });
|
|
1060
|
+
var tunnel_1 = require("./tunnel");
|
|
1061
|
+
Object.defineProperty(exports, "TunnelManager", { enumerable: true, get: function () { return tunnel_1.TunnelManager; } });
|
|
1062
|
+
Object.defineProperty(exports, "getAvailableTunnelProviders", { enumerable: true, get: function () { return tunnel_1.getAvailableTunnelProviders; } });
|
|
1063
|
+
Object.defineProperty(exports, "createAutoTunnel", { enumerable: true, get: function () { return tunnel_1.createAutoTunnel; } });
|