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,182 @@
|
|
|
1
|
+
import { ipcMain, BrowserWindow } from 'electron';
|
|
2
|
+
import { IPC_CHANNELS, HeartbeatConfig } from '../../shared/types';
|
|
3
|
+
import { AgentRoleRepository } from '../agents/AgentRoleRepository';
|
|
4
|
+
import { TaskSubscriptionRepository, SubscriptionReason } from '../agents/TaskSubscriptionRepository';
|
|
5
|
+
import { StandupReportService } from '../reports/StandupReportService';
|
|
6
|
+
import { HeartbeatService } from '../agents/HeartbeatService';
|
|
7
|
+
import { rateLimiter } from '../utils/rate-limiter';
|
|
8
|
+
import { validateInput, UUIDSchema } from '../utils/validation';
|
|
9
|
+
|
|
10
|
+
// Get main window for event broadcasting
|
|
11
|
+
let mainWindowGetter: (() => BrowserWindow | null) | null = null;
|
|
12
|
+
|
|
13
|
+
function getMainWindow(): BrowserWindow | null {
|
|
14
|
+
return mainWindowGetter?.() ?? null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Rate limit check helper
|
|
19
|
+
*/
|
|
20
|
+
function checkRateLimit(channel: string): void {
|
|
21
|
+
if (!rateLimiter.check(channel)) {
|
|
22
|
+
throw new Error(`Rate limit exceeded for ${channel}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Dependencies for Mission Control handlers
|
|
28
|
+
*/
|
|
29
|
+
export interface MissionControlDeps {
|
|
30
|
+
agentRoleRepo: AgentRoleRepository;
|
|
31
|
+
taskSubscriptionRepo: TaskSubscriptionRepository;
|
|
32
|
+
standupService: StandupReportService;
|
|
33
|
+
heartbeatService: HeartbeatService;
|
|
34
|
+
getMainWindow: () => BrowserWindow | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Set up Mission Control IPC handlers
|
|
39
|
+
*/
|
|
40
|
+
export function setupMissionControlHandlers(deps: MissionControlDeps): void {
|
|
41
|
+
mainWindowGetter = deps.getMainWindow;
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
agentRoleRepo,
|
|
45
|
+
taskSubscriptionRepo,
|
|
46
|
+
standupService,
|
|
47
|
+
heartbeatService,
|
|
48
|
+
} = deps;
|
|
49
|
+
|
|
50
|
+
// ============ Heartbeat Handlers ============
|
|
51
|
+
|
|
52
|
+
ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_CONFIG, async (_, agentRoleId: string) => {
|
|
53
|
+
const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
54
|
+
const role = agentRoleRepo.findById(validated);
|
|
55
|
+
if (!role) {
|
|
56
|
+
throw new Error('Agent role not found');
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
heartbeatEnabled: role.heartbeatEnabled,
|
|
60
|
+
heartbeatIntervalMinutes: role.heartbeatIntervalMinutes,
|
|
61
|
+
heartbeatStaggerOffset: role.heartbeatStaggerOffset,
|
|
62
|
+
lastHeartbeatAt: role.lastHeartbeatAt,
|
|
63
|
+
heartbeatStatus: role.heartbeatStatus,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
ipcMain.handle(IPC_CHANNELS.HEARTBEAT_UPDATE_CONFIG, async (_, agentRoleId: string, config: HeartbeatConfig) => {
|
|
68
|
+
checkRateLimit(IPC_CHANNELS.HEARTBEAT_UPDATE_CONFIG);
|
|
69
|
+
const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
70
|
+
const result = agentRoleRepo.updateHeartbeatConfig(validated, config);
|
|
71
|
+
if (result) {
|
|
72
|
+
heartbeatService.updateAgentConfig(validated, config);
|
|
73
|
+
getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, {
|
|
74
|
+
type: 'config_updated',
|
|
75
|
+
agentRoleId: validated,
|
|
76
|
+
config,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
ipcMain.handle(IPC_CHANNELS.HEARTBEAT_TRIGGER, async (_, agentRoleId: string) => {
|
|
83
|
+
checkRateLimit(IPC_CHANNELS.HEARTBEAT_TRIGGER);
|
|
84
|
+
const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
85
|
+
const result = await heartbeatService.triggerHeartbeat(validated);
|
|
86
|
+
getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, {
|
|
87
|
+
type: 'triggered',
|
|
88
|
+
agentRoleId: validated,
|
|
89
|
+
result,
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_STATUS, async (_, agentRoleId: string) => {
|
|
95
|
+
const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
96
|
+
return heartbeatService.getStatus(validated);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
ipcMain.handle(IPC_CHANNELS.HEARTBEAT_GET_ALL_STATUS, async () => {
|
|
100
|
+
return heartbeatService.getAllStatus();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Forward heartbeat events to renderer
|
|
104
|
+
heartbeatService.on('heartbeat', (event) => {
|
|
105
|
+
getMainWindow()?.webContents.send(IPC_CHANNELS.HEARTBEAT_EVENT, event);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// ============ Task Subscription Handlers ============
|
|
109
|
+
|
|
110
|
+
ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_LIST, async (_, taskId: string) => {
|
|
111
|
+
const validated = validateInput(UUIDSchema, taskId, 'task ID');
|
|
112
|
+
return taskSubscriptionRepo.getSubscribers(validated);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_ADD, async (_, taskId: string, agentRoleId: string, reason: SubscriptionReason) => {
|
|
116
|
+
checkRateLimit(IPC_CHANNELS.SUBSCRIPTION_ADD);
|
|
117
|
+
const validatedTaskId = validateInput(UUIDSchema, taskId, 'task ID');
|
|
118
|
+
const validatedAgentRoleId = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
119
|
+
const subscription = taskSubscriptionRepo.subscribe(validatedTaskId, validatedAgentRoleId, reason);
|
|
120
|
+
getMainWindow()?.webContents.send(IPC_CHANNELS.SUBSCRIPTION_EVENT, {
|
|
121
|
+
type: 'added',
|
|
122
|
+
subscription,
|
|
123
|
+
});
|
|
124
|
+
return subscription;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_REMOVE, async (_, taskId: string, agentRoleId: string) => {
|
|
128
|
+
checkRateLimit(IPC_CHANNELS.SUBSCRIPTION_REMOVE);
|
|
129
|
+
const validatedTaskId = validateInput(UUIDSchema, taskId, 'task ID');
|
|
130
|
+
const validatedAgentRoleId = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
131
|
+
const success = taskSubscriptionRepo.unsubscribe(validatedTaskId, validatedAgentRoleId);
|
|
132
|
+
if (success) {
|
|
133
|
+
getMainWindow()?.webContents.send(IPC_CHANNELS.SUBSCRIPTION_EVENT, {
|
|
134
|
+
type: 'removed',
|
|
135
|
+
taskId: validatedTaskId,
|
|
136
|
+
agentRoleId: validatedAgentRoleId,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return { success };
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_GET_SUBSCRIBERS, async (_, taskId: string) => {
|
|
143
|
+
const validated = validateInput(UUIDSchema, taskId, 'task ID');
|
|
144
|
+
return taskSubscriptionRepo.getSubscribers(validated);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
ipcMain.handle(IPC_CHANNELS.SUBSCRIPTION_GET_FOR_AGENT, async (_, agentRoleId: string) => {
|
|
148
|
+
const validated = validateInput(UUIDSchema, agentRoleId, 'agent role ID');
|
|
149
|
+
return taskSubscriptionRepo.getSubscriptionsForAgent(validated);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ============ Standup Report Handlers ============
|
|
153
|
+
|
|
154
|
+
ipcMain.handle(IPC_CHANNELS.STANDUP_GENERATE, async (_, workspaceId: string) => {
|
|
155
|
+
checkRateLimit(IPC_CHANNELS.STANDUP_GENERATE);
|
|
156
|
+
const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
|
|
157
|
+
return standupService.generateReport(validated);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
ipcMain.handle(IPC_CHANNELS.STANDUP_GET_LATEST, async (_, workspaceId: string) => {
|
|
161
|
+
const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
|
|
162
|
+
return standupService.getLatest(validated);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
ipcMain.handle(IPC_CHANNELS.STANDUP_LIST, async (_, workspaceId: string, limit?: number) => {
|
|
166
|
+
const validated = validateInput(UUIDSchema, workspaceId, 'workspace ID');
|
|
167
|
+
return standupService.list({ workspaceId: validated, limit });
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
ipcMain.handle(IPC_CHANNELS.STANDUP_DELIVER, async (_, reportId: string, channelType: string, channelId: string) => {
|
|
171
|
+
checkRateLimit(IPC_CHANNELS.STANDUP_DELIVER);
|
|
172
|
+
const validatedReportId = validateInput(UUIDSchema, reportId, 'report ID');
|
|
173
|
+
const report = standupService.findById(validatedReportId);
|
|
174
|
+
if (!report) {
|
|
175
|
+
throw new Error('Standup report not found');
|
|
176
|
+
}
|
|
177
|
+
await standupService.deliverReport(report, { channelType, channelId });
|
|
178
|
+
return { success: true };
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
console.log('[MissionControl] Handlers initialized');
|
|
182
|
+
}
|
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { pathToFileURL } from 'url';
|
|
3
|
+
import { app, BrowserWindow, ipcMain, dialog, session, shell, Notification } from 'electron';
|
|
4
|
+
import { DatabaseManager } from './database/schema';
|
|
5
|
+
import { SecureSettingsRepository } from './database/SecureSettingsRepository';
|
|
6
|
+
import { setupIpcHandlers, getNotificationService } from './ipc/handlers';
|
|
7
|
+
import { setupMissionControlHandlers } from './ipc/mission-control-handlers';
|
|
8
|
+
import { TaskSubscriptionRepository } from './agents/TaskSubscriptionRepository';
|
|
9
|
+
import { StandupReportService } from './reports/StandupReportService';
|
|
10
|
+
import { HeartbeatService, HeartbeatServiceDeps } from './agents/HeartbeatService';
|
|
11
|
+
import { AgentRoleRepository } from './agents/AgentRoleRepository';
|
|
12
|
+
import { MentionRepository } from './agents/MentionRepository';
|
|
13
|
+
import { ActivityRepository } from './activity/ActivityRepository';
|
|
14
|
+
import { WorkingStateRepository } from './agents/WorkingStateRepository';
|
|
15
|
+
import { AgentDaemon } from './agent/daemon';
|
|
16
|
+
import { TaskRepository, WorkspaceRepository } from './database/repositories';
|
|
17
|
+
import { LLMProviderFactory } from './agent/llm';
|
|
18
|
+
import { SearchProviderFactory } from './agent/search';
|
|
19
|
+
import { ChannelGateway } from './gateway';
|
|
20
|
+
import { updateManager } from './updater';
|
|
21
|
+
import { migrateEnvToSettings } from './utils/env-migration';
|
|
22
|
+
import { GuardrailManager } from './guardrails/guardrail-manager';
|
|
23
|
+
import { AppearanceManager } from './settings/appearance-manager';
|
|
24
|
+
import { PersonalityManager } from './settings/personality-manager';
|
|
25
|
+
import { MCPClientManager } from './mcp/client/MCPClientManager';
|
|
26
|
+
import { trayManager } from './tray';
|
|
27
|
+
import { CronService, setCronService, getCronStorePath } from './cron';
|
|
28
|
+
import { MemoryService } from './memory/MemoryService';
|
|
29
|
+
import { setupControlPlaneHandlers, shutdownControlPlane } from './control-plane';
|
|
30
|
+
// Live Canvas feature
|
|
31
|
+
import { registerCanvasScheme, registerCanvasProtocol, CanvasManager } from './canvas';
|
|
32
|
+
import { setupCanvasHandlers, cleanupCanvasHandlers } from './ipc/canvas-handlers';
|
|
33
|
+
|
|
34
|
+
let mainWindow: BrowserWindow | null = null;
|
|
35
|
+
let dbManager: DatabaseManager;
|
|
36
|
+
let agentDaemon: AgentDaemon;
|
|
37
|
+
let channelGateway: ChannelGateway;
|
|
38
|
+
let cronService: CronService | null = null;
|
|
39
|
+
|
|
40
|
+
// Suppress GPU-related Chromium errors that occur with transparent windows and vibrancy
|
|
41
|
+
// These are cosmetic errors that don't affect functionality
|
|
42
|
+
app.commandLine.appendSwitch('disable-gpu-driver-bug-workarounds');
|
|
43
|
+
app.commandLine.appendSwitch('enable-gpu-rasterization');
|
|
44
|
+
app.commandLine.appendSwitch('ignore-gpu-blocklist');
|
|
45
|
+
|
|
46
|
+
// Register canvas:// protocol scheme (must be called before app.ready)
|
|
47
|
+
registerCanvasScheme();
|
|
48
|
+
|
|
49
|
+
function createWindow() {
|
|
50
|
+
mainWindow = new BrowserWindow({
|
|
51
|
+
width: 1600,
|
|
52
|
+
height: 1000,
|
|
53
|
+
minWidth: 1200,
|
|
54
|
+
minHeight: 800,
|
|
55
|
+
center: true,
|
|
56
|
+
titleBarStyle: 'hiddenInset',
|
|
57
|
+
vibrancy: 'under-window',
|
|
58
|
+
visualEffectState: 'active',
|
|
59
|
+
transparent: true,
|
|
60
|
+
backgroundColor: '#00000000',
|
|
61
|
+
webPreferences: {
|
|
62
|
+
nodeIntegration: false,
|
|
63
|
+
contextIsolation: true,
|
|
64
|
+
webviewTag: true, // Enable webview for canvas interactive mode
|
|
65
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Load the app
|
|
70
|
+
if (process.env.NODE_ENV === 'development') {
|
|
71
|
+
mainWindow.loadURL('http://localhost:5173');
|
|
72
|
+
mainWindow.webContents.openDevTools();
|
|
73
|
+
} else {
|
|
74
|
+
mainWindow.loadFile(path.join(__dirname, '../../renderer/index.html'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
mainWindow.on('closed', () => {
|
|
78
|
+
mainWindow = null;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Open external links in the system browser instead of inside the app
|
|
82
|
+
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
83
|
+
// Open all new window requests in external browser
|
|
84
|
+
shell.openExternal(url);
|
|
85
|
+
return { action: 'deny' };
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
mainWindow.webContents.on('will-navigate', (event, url) => {
|
|
89
|
+
// Allow navigation to the app itself (dev server or file://), block external URLs
|
|
90
|
+
const appUrl = process.env.NODE_ENV === 'development'
|
|
91
|
+
? 'http://localhost:5173'
|
|
92
|
+
: `file://${path.join(__dirname, '../../renderer')}`;
|
|
93
|
+
|
|
94
|
+
if (!url.startsWith(appUrl)) {
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
shell.openExternal(url);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
app.whenReady().then(async () => {
|
|
102
|
+
// Set up Content Security Policy for production builds
|
|
103
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
104
|
+
const appRoot = pathToFileURL(path.join(__dirname, '../../renderer')).toString();
|
|
105
|
+
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
|
106
|
+
if (!details.url.startsWith(appRoot)) {
|
|
107
|
+
callback({ responseHeaders: details.responseHeaders });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
callback({
|
|
111
|
+
responseHeaders: {
|
|
112
|
+
...details.responseHeaders,
|
|
113
|
+
'Content-Security-Policy': [
|
|
114
|
+
"default-src 'self'; " +
|
|
115
|
+
"script-src 'self'; " +
|
|
116
|
+
"style-src 'self' 'unsafe-inline'; " + // Allow inline styles for React
|
|
117
|
+
"img-src 'self' data: https:; " + // Allow images from self, data URIs, and HTTPS
|
|
118
|
+
"font-src 'self' data:; " + // Allow fonts from self and data URIs
|
|
119
|
+
"connect-src 'self' https:; " + // Allow API calls to HTTPS endpoints
|
|
120
|
+
"frame-ancestors 'none'; " + // Prevent embedding in iframes
|
|
121
|
+
"form-action 'self';" // Restrict form submissions
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Initialize database first - required for SecureSettingsRepository
|
|
129
|
+
dbManager = new DatabaseManager();
|
|
130
|
+
|
|
131
|
+
// Initialize secure settings repository for encrypted settings storage
|
|
132
|
+
// This MUST be done before provider factories so they can migrate legacy settings
|
|
133
|
+
new SecureSettingsRepository(dbManager.getDatabase());
|
|
134
|
+
console.log('[Main] SecureSettingsRepository initialized');
|
|
135
|
+
|
|
136
|
+
// Initialize provider factories (loads settings from disk, migrates legacy files)
|
|
137
|
+
LLMProviderFactory.initialize();
|
|
138
|
+
SearchProviderFactory.initialize();
|
|
139
|
+
GuardrailManager.initialize();
|
|
140
|
+
AppearanceManager.initialize();
|
|
141
|
+
PersonalityManager.initialize();
|
|
142
|
+
|
|
143
|
+
// Migrate .env configuration to Settings (one-time upgrade path)
|
|
144
|
+
const migrationResult = await migrateEnvToSettings();
|
|
145
|
+
|
|
146
|
+
// Initialize agent daemon
|
|
147
|
+
agentDaemon = new AgentDaemon(dbManager);
|
|
148
|
+
await agentDaemon.initialize();
|
|
149
|
+
|
|
150
|
+
// Initialize Memory Service for cross-session context
|
|
151
|
+
try {
|
|
152
|
+
MemoryService.initialize(dbManager);
|
|
153
|
+
console.log('[Main] Memory Service initialized');
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('[Main] Failed to initialize Memory Service:', error);
|
|
156
|
+
// Don't fail app startup if memory init fails
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Initialize MCP Client Manager - auto-connects enabled servers on startup
|
|
160
|
+
try {
|
|
161
|
+
const mcpClientManager = MCPClientManager.getInstance();
|
|
162
|
+
await mcpClientManager.initialize();
|
|
163
|
+
console.log('[Main] MCP Client Manager initialized');
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error('[Main] Failed to initialize MCP Client Manager:', error);
|
|
166
|
+
// Don't fail app startup if MCP init fails
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Initialize Cron Service for scheduled task execution
|
|
170
|
+
try {
|
|
171
|
+
cronService = new CronService({
|
|
172
|
+
cronEnabled: true,
|
|
173
|
+
storePath: getCronStorePath(),
|
|
174
|
+
maxConcurrentRuns: 3, // Allow up to 3 concurrent jobs
|
|
175
|
+
// Webhook configuration (disabled by default, can be enabled in settings)
|
|
176
|
+
webhook: {
|
|
177
|
+
enabled: false, // Set to true to enable webhook triggers
|
|
178
|
+
port: 9876,
|
|
179
|
+
host: '127.0.0.1',
|
|
180
|
+
// secret: 'your-secret-here', // Uncomment and set for secure webhooks
|
|
181
|
+
},
|
|
182
|
+
createTask: async (params) => {
|
|
183
|
+
const task = await agentDaemon.createTask({
|
|
184
|
+
title: params.title,
|
|
185
|
+
prompt: params.prompt,
|
|
186
|
+
workspaceId: params.workspaceId,
|
|
187
|
+
});
|
|
188
|
+
return { id: task.id };
|
|
189
|
+
},
|
|
190
|
+
// Channel delivery handler - sends job results to messaging platforms
|
|
191
|
+
deliverToChannel: async (params) => {
|
|
192
|
+
if (!channelGateway) {
|
|
193
|
+
console.warn('[Cron] Cannot deliver to channel - gateway not initialized');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Build the message
|
|
198
|
+
const statusEmoji = params.status === 'ok' ? '✅' : params.status === 'error' ? '❌' : '⏱️';
|
|
199
|
+
let message = `${statusEmoji} **Scheduled Task: ${params.jobName}**\n\n`;
|
|
200
|
+
|
|
201
|
+
if (params.status === 'ok') {
|
|
202
|
+
message += `Task completed successfully.\n`;
|
|
203
|
+
} else if (params.status === 'error') {
|
|
204
|
+
message += `Task failed.\n`;
|
|
205
|
+
} else {
|
|
206
|
+
message += `Task timed out.\n`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (params.error) {
|
|
210
|
+
message += `\n**Error:** ${params.error}\n`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (params.taskId && !params.summaryOnly) {
|
|
214
|
+
message += `\n_Task ID: ${params.taskId}_`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Find the channel to verify it exists
|
|
218
|
+
const channels = channelGateway.getChannels();
|
|
219
|
+
const channel = channels.find(
|
|
220
|
+
(ch) => ch.type === params.channelType && ch.id === params.channelId
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (!channel) {
|
|
224
|
+
console.warn(`[Cron] Channel not found: ${params.channelType}:${params.channelId}`);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
// Send the message via the gateway
|
|
230
|
+
await channelGateway.sendMessage(
|
|
231
|
+
params.channelType as any,
|
|
232
|
+
params.channelId,
|
|
233
|
+
message,
|
|
234
|
+
{ parseMode: 'markdown' }
|
|
235
|
+
);
|
|
236
|
+
console.log(`[Cron] Delivered to ${params.channelType}:${params.channelId}`);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
console.error(`[Cron] Failed to deliver to ${params.channelType}:${params.channelId}:`, err);
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
onEvent: async (evt) => {
|
|
242
|
+
// Forward cron events to renderer
|
|
243
|
+
if (mainWindow?.webContents) {
|
|
244
|
+
mainWindow.webContents.send('cron:event', evt);
|
|
245
|
+
}
|
|
246
|
+
console.log('[Cron] Event:', evt.action, evt.jobId);
|
|
247
|
+
|
|
248
|
+
// Show desktop notification when scheduled task finishes
|
|
249
|
+
if (evt.action === 'finished') {
|
|
250
|
+
const statusEmoji = evt.status === 'ok' ? '✅' : evt.status === 'error' ? '❌' : '⏱️';
|
|
251
|
+
const statusText = evt.status === 'ok' ? 'completed' : evt.status === 'error' ? 'failed' : 'timed out';
|
|
252
|
+
|
|
253
|
+
// Add in-app notification
|
|
254
|
+
const notificationService = getNotificationService();
|
|
255
|
+
if (notificationService) {
|
|
256
|
+
try {
|
|
257
|
+
// Get job name for the notification
|
|
258
|
+
const job = cronService ? await cronService.get(evt.jobId) : null;
|
|
259
|
+
const jobName = job?.name || 'Scheduled Task';
|
|
260
|
+
await notificationService.add({
|
|
261
|
+
type: evt.status === 'ok' ? 'task_completed' : 'task_failed',
|
|
262
|
+
title: `${statusEmoji} ${jobName} ${statusText}`,
|
|
263
|
+
message: evt.error || (evt.status === 'ok' ? 'Task completed successfully.' : 'Task did not complete.'),
|
|
264
|
+
taskId: evt.taskId,
|
|
265
|
+
cronJobId: evt.jobId,
|
|
266
|
+
workspaceId: job?.workspaceId,
|
|
267
|
+
});
|
|
268
|
+
} catch (err) {
|
|
269
|
+
console.error('[Cron] Failed to add in-app notification:', err);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Show macOS notification
|
|
274
|
+
if (Notification.isSupported()) {
|
|
275
|
+
const notification = new Notification({
|
|
276
|
+
title: `${statusEmoji} Scheduled Task ${statusText}`,
|
|
277
|
+
body: evt.error ? `Error: ${evt.error}` : 'Click to view results in the app.',
|
|
278
|
+
silent: false,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
notification.on('click', () => {
|
|
282
|
+
// Bring the main window to focus
|
|
283
|
+
if (mainWindow) {
|
|
284
|
+
if (mainWindow.isMinimized()) mainWindow.restore();
|
|
285
|
+
mainWindow.focus();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
notification.show();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
log: {
|
|
294
|
+
debug: (msg, data) => console.log(`[Cron] ${msg}`, data ?? ''),
|
|
295
|
+
info: (msg, data) => console.log(`[Cron] ${msg}`, data ?? ''),
|
|
296
|
+
warn: (msg, data) => console.warn(`[Cron] ${msg}`, data ?? ''),
|
|
297
|
+
error: (msg, data) => console.error(`[Cron] ${msg}`, data ?? ''),
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
setCronService(cronService);
|
|
301
|
+
await cronService.start();
|
|
302
|
+
console.log('[Main] Cron Service initialized');
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error('[Main] Failed to initialize Cron Service:', error);
|
|
305
|
+
// Don't fail app startup if cron init fails
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Initialize channel gateway with agent daemon for task processing
|
|
309
|
+
channelGateway = new ChannelGateway(dbManager.getDatabase(), {
|
|
310
|
+
autoConnect: true, // Auto-connect enabled channels on startup
|
|
311
|
+
agentDaemon,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Setup IPC handlers
|
|
315
|
+
await setupIpcHandlers(dbManager, agentDaemon, channelGateway);
|
|
316
|
+
|
|
317
|
+
// Initialize Mission Control services
|
|
318
|
+
try {
|
|
319
|
+
const db = dbManager.getDatabase();
|
|
320
|
+
const agentRoleRepo = new AgentRoleRepository(db);
|
|
321
|
+
|
|
322
|
+
// Sync any new default agents to existing workspaces
|
|
323
|
+
const addedAgents = agentRoleRepo.syncNewDefaults();
|
|
324
|
+
if (addedAgents.length > 0) {
|
|
325
|
+
console.log(`[Main] Added ${addedAgents.length} new default agent(s)`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const mentionRepo = new MentionRepository(db);
|
|
329
|
+
const activityRepo = new ActivityRepository(db);
|
|
330
|
+
const workingStateRepo = new WorkingStateRepository(db);
|
|
331
|
+
const taskSubscriptionRepo = new TaskSubscriptionRepository(db);
|
|
332
|
+
const standupService = new StandupReportService(db);
|
|
333
|
+
|
|
334
|
+
// Create repositories for heartbeat service
|
|
335
|
+
const taskRepo = new TaskRepository(db);
|
|
336
|
+
const workspaceRepo = new WorkspaceRepository(db);
|
|
337
|
+
|
|
338
|
+
// Initialize HeartbeatService with dependencies
|
|
339
|
+
const heartbeatDeps: HeartbeatServiceDeps = {
|
|
340
|
+
agentRoleRepo,
|
|
341
|
+
mentionRepo,
|
|
342
|
+
activityRepo,
|
|
343
|
+
workingStateRepo,
|
|
344
|
+
createTask: async (workspaceId, prompt, title, _agentRoleId) => {
|
|
345
|
+
// Create task via agentDaemon (doesn't support assignedAgentRoleId directly)
|
|
346
|
+
const task = await agentDaemon.createTask({
|
|
347
|
+
title,
|
|
348
|
+
prompt,
|
|
349
|
+
workspaceId,
|
|
350
|
+
});
|
|
351
|
+
// Note: Task assignment would need to be done separately if needed
|
|
352
|
+
return task;
|
|
353
|
+
},
|
|
354
|
+
getTasksForAgent: (agentRoleId, workspaceId) => {
|
|
355
|
+
// Get assigned tasks for the agent using the task repository
|
|
356
|
+
const tasks = workspaceId
|
|
357
|
+
? taskRepo.findByWorkspace(workspaceId)
|
|
358
|
+
: taskRepo.findByStatus(['pending', 'running']);
|
|
359
|
+
return tasks.filter((t: { assignedAgentRoleId?: string }) => t.assignedAgentRoleId === agentRoleId);
|
|
360
|
+
},
|
|
361
|
+
getDefaultWorkspaceId: () => {
|
|
362
|
+
// Get the first workspace as default
|
|
363
|
+
const workspaces = workspaceRepo.findAll();
|
|
364
|
+
return workspaces[0]?.id;
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const heartbeatService = new HeartbeatService(heartbeatDeps);
|
|
369
|
+
await heartbeatService.start();
|
|
370
|
+
|
|
371
|
+
// Setup Mission Control IPC handlers
|
|
372
|
+
setupMissionControlHandlers({
|
|
373
|
+
agentRoleRepo,
|
|
374
|
+
taskSubscriptionRepo,
|
|
375
|
+
standupService,
|
|
376
|
+
heartbeatService,
|
|
377
|
+
getMainWindow: () => mainWindow,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
console.log('[Main] Mission Control services initialized');
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error('[Main] Failed to initialize Mission Control:', error);
|
|
383
|
+
// Don't fail app startup if Mission Control init fails
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Register canvas:// protocol handler (must be after app.ready)
|
|
387
|
+
registerCanvasProtocol();
|
|
388
|
+
|
|
389
|
+
// Create window
|
|
390
|
+
createWindow();
|
|
391
|
+
|
|
392
|
+
// Initialize gateway with main window reference
|
|
393
|
+
if (mainWindow) {
|
|
394
|
+
await channelGateway.initialize(mainWindow);
|
|
395
|
+
// Initialize update manager with main window reference
|
|
396
|
+
updateManager.setMainWindow(mainWindow);
|
|
397
|
+
|
|
398
|
+
// Initialize Live Canvas handlers and set main window reference
|
|
399
|
+
setupCanvasHandlers(mainWindow, agentDaemon);
|
|
400
|
+
CanvasManager.getInstance().setMainWindow(mainWindow);
|
|
401
|
+
|
|
402
|
+
// Restore persisted canvas sessions from disk
|
|
403
|
+
await CanvasManager.getInstance().restoreSessions();
|
|
404
|
+
|
|
405
|
+
// Initialize control plane (WebSocket gateway)
|
|
406
|
+
setupControlPlaneHandlers(mainWindow);
|
|
407
|
+
|
|
408
|
+
// Initialize menu bar tray (macOS native companion)
|
|
409
|
+
if (process.platform === 'darwin') {
|
|
410
|
+
await trayManager.initialize(mainWindow, channelGateway, dbManager, agentDaemon);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Show migration notification after window is ready
|
|
414
|
+
if (migrationResult.migrated && migrationResult.migratedKeys.length > 0) {
|
|
415
|
+
mainWindow.webContents.once('did-finish-load', () => {
|
|
416
|
+
dialog.showMessageBox(mainWindow!, {
|
|
417
|
+
type: 'info',
|
|
418
|
+
title: 'Configuration Migrated',
|
|
419
|
+
message: 'Your API credentials have been migrated',
|
|
420
|
+
detail: `The following credentials were migrated from your .env file to secure Settings storage:\n\n` +
|
|
421
|
+
`${migrationResult.migratedKeys.map(k => `• ${k}`).join('\n')}\n\n` +
|
|
422
|
+
`Your .env file has been renamed to .env.migrated. ` +
|
|
423
|
+
`You can safely delete it after verifying your settings work correctly.\n\n` +
|
|
424
|
+
`Open Settings (gear icon) to review your configuration.`,
|
|
425
|
+
buttons: ['OK'],
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
app.on('activate', () => {
|
|
432
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
433
|
+
createWindow();
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
app.on('window-all-closed', () => {
|
|
439
|
+
if (process.platform !== 'darwin') {
|
|
440
|
+
app.quit();
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
app.on('before-quit', async () => {
|
|
445
|
+
// Destroy tray
|
|
446
|
+
trayManager.destroy();
|
|
447
|
+
|
|
448
|
+
// Stop cron service (async to properly shutdown webhook server)
|
|
449
|
+
if (cronService) {
|
|
450
|
+
await cronService.stop();
|
|
451
|
+
setCronService(null);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Cleanup canvas manager (close all windows and watchers)
|
|
455
|
+
await cleanupCanvasHandlers();
|
|
456
|
+
|
|
457
|
+
// Shutdown control plane (WebSocket gateway and Tailscale)
|
|
458
|
+
await shutdownControlPlane();
|
|
459
|
+
|
|
460
|
+
if (channelGateway) {
|
|
461
|
+
await channelGateway.shutdown();
|
|
462
|
+
}
|
|
463
|
+
// Disconnect all MCP servers
|
|
464
|
+
try {
|
|
465
|
+
const mcpClientManager = MCPClientManager.getInstance();
|
|
466
|
+
await mcpClientManager.shutdown();
|
|
467
|
+
} catch (error) {
|
|
468
|
+
console.error('[Main] Failed to shutdown MCP servers:', error);
|
|
469
|
+
}
|
|
470
|
+
// Shutdown Memory Service
|
|
471
|
+
try {
|
|
472
|
+
MemoryService.shutdown();
|
|
473
|
+
} catch (error) {
|
|
474
|
+
console.error('[Main] Failed to shutdown Memory Service:', error);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (dbManager) {
|
|
478
|
+
dbManager.close();
|
|
479
|
+
}
|
|
480
|
+
if (agentDaemon) {
|
|
481
|
+
agentDaemon.shutdown();
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Handle folder selection
|
|
486
|
+
ipcMain.handle('dialog:selectFolder', async () => {
|
|
487
|
+
const result = await dialog.showOpenDialog({
|
|
488
|
+
properties: ['openDirectory'],
|
|
489
|
+
title: 'Select Workspace Folder',
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
if (!result.canceled && result.filePaths.length > 0) {
|
|
493
|
+
return result.filePaths[0];
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
});
|