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,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Provider abstraction types
|
|
3
|
+
* Allows switching between Anthropic API and AWS Bedrock
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type LLMProviderType = 'anthropic' | 'bedrock' | 'ollama' | 'gemini' | 'openrouter' | 'openai';
|
|
7
|
+
|
|
8
|
+
export interface LLMProviderConfig {
|
|
9
|
+
type: LLMProviderType;
|
|
10
|
+
model: string;
|
|
11
|
+
// Anthropic-specific
|
|
12
|
+
anthropicApiKey?: string;
|
|
13
|
+
// Bedrock-specific
|
|
14
|
+
awsRegion?: string;
|
|
15
|
+
awsAccessKeyId?: string;
|
|
16
|
+
awsSecretAccessKey?: string;
|
|
17
|
+
awsSessionToken?: string;
|
|
18
|
+
// Use AWS profile instead of explicit credentials
|
|
19
|
+
awsProfile?: string;
|
|
20
|
+
// Ollama-specific
|
|
21
|
+
ollamaBaseUrl?: string;
|
|
22
|
+
ollamaApiKey?: string; // Optional API key for remote Ollama servers
|
|
23
|
+
// Gemini-specific
|
|
24
|
+
geminiApiKey?: string;
|
|
25
|
+
// OpenRouter-specific
|
|
26
|
+
openrouterApiKey?: string;
|
|
27
|
+
// OpenAI-specific
|
|
28
|
+
openaiApiKey?: string;
|
|
29
|
+
openaiAccessToken?: string; // OAuth access token
|
|
30
|
+
openaiRefreshToken?: string; // OAuth refresh token
|
|
31
|
+
openaiTokenExpiresAt?: number; // OAuth token expiry timestamp
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface LLMTool {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
input_schema: {
|
|
38
|
+
type: 'object';
|
|
39
|
+
properties: Record<string, any>;
|
|
40
|
+
required?: string[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface LLMToolUse {
|
|
45
|
+
type: 'tool_use';
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
input: Record<string, any>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface LLMTextContent {
|
|
52
|
+
type: 'text';
|
|
53
|
+
text: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type LLMContent = LLMToolUse | LLMTextContent;
|
|
57
|
+
|
|
58
|
+
export interface LLMToolResult {
|
|
59
|
+
type: 'tool_result';
|
|
60
|
+
tool_use_id: string;
|
|
61
|
+
content: string;
|
|
62
|
+
is_error?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface LLMMessage {
|
|
66
|
+
role: 'user' | 'assistant';
|
|
67
|
+
content: string | LLMContent[] | LLMToolResult[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface LLMRequest {
|
|
71
|
+
model: string;
|
|
72
|
+
maxTokens: number;
|
|
73
|
+
system: string;
|
|
74
|
+
messages: LLMMessage[];
|
|
75
|
+
tools?: LLMTool[];
|
|
76
|
+
/** Optional abort signal to cancel the request */
|
|
77
|
+
signal?: AbortSignal;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface LLMResponse {
|
|
81
|
+
content: LLMContent[];
|
|
82
|
+
stopReason: 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence';
|
|
83
|
+
usage?: {
|
|
84
|
+
inputTokens: number;
|
|
85
|
+
outputTokens: number;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Abstract LLM Provider interface
|
|
91
|
+
*/
|
|
92
|
+
export interface LLMProvider {
|
|
93
|
+
readonly type: LLMProviderType;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Send a message to the LLM and get a response
|
|
97
|
+
*/
|
|
98
|
+
createMessage(request: LLMRequest): Promise<LLMResponse>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Test the provider connection
|
|
102
|
+
*/
|
|
103
|
+
testConnection(): Promise<{ success: boolean; error?: string }>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Available AI models with their IDs for each provider
|
|
108
|
+
* Note: Bedrock uses inference profile IDs (us. prefix) for newer models
|
|
109
|
+
* Note: Ollama models are dynamic and fetched from the server
|
|
110
|
+
*/
|
|
111
|
+
export const MODELS = {
|
|
112
|
+
'opus-4-5': {
|
|
113
|
+
anthropic: 'claude-opus-4-5-20251101',
|
|
114
|
+
bedrock: 'us.anthropic.claude-opus-4-5-20251101-v1:0',
|
|
115
|
+
displayName: 'Opus 4.5',
|
|
116
|
+
},
|
|
117
|
+
'sonnet-4-5': {
|
|
118
|
+
anthropic: 'claude-sonnet-4-5-20250514',
|
|
119
|
+
bedrock: 'us.anthropic.claude-sonnet-4-5-20250514-v1:0',
|
|
120
|
+
displayName: 'Sonnet 4.5',
|
|
121
|
+
},
|
|
122
|
+
'haiku-4-5': {
|
|
123
|
+
anthropic: 'claude-haiku-4-5-20250514',
|
|
124
|
+
bedrock: 'us.anthropic.claude-haiku-4-5-20250514-v1:0',
|
|
125
|
+
displayName: 'Haiku 4.5',
|
|
126
|
+
},
|
|
127
|
+
'sonnet-4': {
|
|
128
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
129
|
+
bedrock: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
|
|
130
|
+
displayName: 'Sonnet 4',
|
|
131
|
+
},
|
|
132
|
+
'sonnet-3-5': {
|
|
133
|
+
anthropic: 'claude-3-5-sonnet-20241022',
|
|
134
|
+
bedrock: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
|
|
135
|
+
displayName: 'Sonnet 3.5',
|
|
136
|
+
},
|
|
137
|
+
'haiku-3-5': {
|
|
138
|
+
anthropic: 'claude-3-5-haiku-20241022',
|
|
139
|
+
bedrock: 'us.anthropic.claude-3-5-haiku-20241022-v1:0',
|
|
140
|
+
displayName: 'Haiku 3.5',
|
|
141
|
+
},
|
|
142
|
+
} as const;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Available Gemini models from Google AI Studio
|
|
146
|
+
*/
|
|
147
|
+
export const GEMINI_MODELS = {
|
|
148
|
+
'gemini-2.5-pro': {
|
|
149
|
+
id: 'gemini-2.5-pro-preview-05-06',
|
|
150
|
+
displayName: 'Gemini 2.5 Pro',
|
|
151
|
+
description: 'Most capable model for complex tasks',
|
|
152
|
+
},
|
|
153
|
+
'gemini-2.5-flash': {
|
|
154
|
+
id: 'gemini-2.5-flash-preview-05-20',
|
|
155
|
+
displayName: 'Gemini 2.5 Flash',
|
|
156
|
+
description: 'Fast and efficient for most tasks',
|
|
157
|
+
},
|
|
158
|
+
'gemini-2.0-flash': {
|
|
159
|
+
id: 'gemini-2.0-flash',
|
|
160
|
+
displayName: 'Gemini 2.0 Flash',
|
|
161
|
+
description: 'Balanced speed and capability',
|
|
162
|
+
},
|
|
163
|
+
'gemini-2.0-flash-lite': {
|
|
164
|
+
id: 'gemini-2.0-flash-lite',
|
|
165
|
+
displayName: 'Gemini 2.0 Flash Lite',
|
|
166
|
+
description: 'Fastest and most cost-effective',
|
|
167
|
+
},
|
|
168
|
+
'gemini-1.5-pro': {
|
|
169
|
+
id: 'gemini-1.5-pro',
|
|
170
|
+
displayName: 'Gemini 1.5 Pro',
|
|
171
|
+
description: 'Previous generation pro model',
|
|
172
|
+
},
|
|
173
|
+
'gemini-1.5-flash': {
|
|
174
|
+
id: 'gemini-1.5-flash',
|
|
175
|
+
displayName: 'Gemini 1.5 Flash',
|
|
176
|
+
description: 'Previous generation flash model',
|
|
177
|
+
},
|
|
178
|
+
} as const;
|
|
179
|
+
|
|
180
|
+
export type GeminiModelKey = keyof typeof GEMINI_MODELS;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Popular OpenRouter models
|
|
184
|
+
* OpenRouter provides access to many models from different providers
|
|
185
|
+
*/
|
|
186
|
+
export const OPENROUTER_MODELS = {
|
|
187
|
+
'anthropic/claude-3.5-sonnet': {
|
|
188
|
+
id: 'anthropic/claude-3.5-sonnet',
|
|
189
|
+
displayName: 'Claude 3.5 Sonnet',
|
|
190
|
+
description: 'Anthropic\'s balanced model',
|
|
191
|
+
},
|
|
192
|
+
'anthropic/claude-3-opus': {
|
|
193
|
+
id: 'anthropic/claude-3-opus',
|
|
194
|
+
displayName: 'Claude 3 Opus',
|
|
195
|
+
description: 'Anthropic\'s most capable model',
|
|
196
|
+
},
|
|
197
|
+
'openai/gpt-4o': {
|
|
198
|
+
id: 'openai/gpt-4o',
|
|
199
|
+
displayName: 'GPT-4o',
|
|
200
|
+
description: 'OpenAI\'s flagship model',
|
|
201
|
+
},
|
|
202
|
+
'openai/gpt-4o-mini': {
|
|
203
|
+
id: 'openai/gpt-4o-mini',
|
|
204
|
+
displayName: 'GPT-4o Mini',
|
|
205
|
+
description: 'OpenAI\'s fast and affordable model',
|
|
206
|
+
},
|
|
207
|
+
'google/gemini-pro-1.5': {
|
|
208
|
+
id: 'google/gemini-pro-1.5',
|
|
209
|
+
displayName: 'Gemini Pro 1.5',
|
|
210
|
+
description: 'Google\'s advanced model',
|
|
211
|
+
},
|
|
212
|
+
'meta-llama/llama-3.1-405b-instruct': {
|
|
213
|
+
id: 'meta-llama/llama-3.1-405b-instruct',
|
|
214
|
+
displayName: 'Llama 3.1 405B',
|
|
215
|
+
description: 'Meta\'s largest open model',
|
|
216
|
+
},
|
|
217
|
+
'mistralai/mistral-large': {
|
|
218
|
+
id: 'mistralai/mistral-large',
|
|
219
|
+
displayName: 'Mistral Large',
|
|
220
|
+
description: 'Mistral\'s flagship model',
|
|
221
|
+
},
|
|
222
|
+
'deepseek/deepseek-chat': {
|
|
223
|
+
id: 'deepseek/deepseek-chat',
|
|
224
|
+
displayName: 'DeepSeek Chat',
|
|
225
|
+
description: 'DeepSeek\'s conversational model',
|
|
226
|
+
},
|
|
227
|
+
} as const;
|
|
228
|
+
|
|
229
|
+
export type OpenRouterModelKey = keyof typeof OPENROUTER_MODELS;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Available OpenAI models
|
|
233
|
+
* Users with ChatGPT Plus/Team/Enterprise subscriptions can use these models
|
|
234
|
+
*/
|
|
235
|
+
export const OPENAI_MODELS = {
|
|
236
|
+
'gpt-4o': {
|
|
237
|
+
id: 'gpt-4o',
|
|
238
|
+
displayName: 'GPT-4o',
|
|
239
|
+
description: 'Most capable model for complex tasks',
|
|
240
|
+
},
|
|
241
|
+
'gpt-4o-mini': {
|
|
242
|
+
id: 'gpt-4o-mini',
|
|
243
|
+
displayName: 'GPT-4o Mini',
|
|
244
|
+
description: 'Fast and affordable for most tasks',
|
|
245
|
+
},
|
|
246
|
+
'gpt-4-turbo': {
|
|
247
|
+
id: 'gpt-4-turbo',
|
|
248
|
+
displayName: 'GPT-4 Turbo',
|
|
249
|
+
description: 'Previous generation flagship',
|
|
250
|
+
},
|
|
251
|
+
'gpt-3.5-turbo': {
|
|
252
|
+
id: 'gpt-3.5-turbo',
|
|
253
|
+
displayName: 'GPT-3.5 Turbo',
|
|
254
|
+
description: 'Fast and cost-effective',
|
|
255
|
+
},
|
|
256
|
+
'o1': {
|
|
257
|
+
id: 'o1',
|
|
258
|
+
displayName: 'o1',
|
|
259
|
+
description: 'Advanced reasoning model',
|
|
260
|
+
},
|
|
261
|
+
'o1-mini': {
|
|
262
|
+
id: 'o1-mini',
|
|
263
|
+
displayName: 'o1 Mini',
|
|
264
|
+
description: 'Fast reasoning model',
|
|
265
|
+
},
|
|
266
|
+
} as const;
|
|
267
|
+
|
|
268
|
+
export type OpenAIModelKey = keyof typeof OPENAI_MODELS;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Popular Ollama models with their details
|
|
272
|
+
* Users can use any model available on their Ollama server
|
|
273
|
+
*/
|
|
274
|
+
export const OLLAMA_MODELS = {
|
|
275
|
+
'llama3.2': { displayName: 'Llama 3.2', size: '3B' },
|
|
276
|
+
'llama3.1': { displayName: 'Llama 3.1', size: '8B' },
|
|
277
|
+
'llama3.1:70b': { displayName: 'Llama 3.1 70B', size: '70B' },
|
|
278
|
+
'mistral': { displayName: 'Mistral', size: '7B' },
|
|
279
|
+
'mixtral': { displayName: 'Mixtral', size: '47B' },
|
|
280
|
+
'codellama': { displayName: 'Code Llama', size: '7B' },
|
|
281
|
+
'deepseek-coder': { displayName: 'DeepSeek Coder', size: '6.7B' },
|
|
282
|
+
'qwen2.5': { displayName: 'Qwen 2.5', size: '7B' },
|
|
283
|
+
'phi3': { displayName: 'Phi-3', size: '3.8B' },
|
|
284
|
+
'gemma2': { displayName: 'Gemma 2', size: '9B' },
|
|
285
|
+
} as const;
|
|
286
|
+
|
|
287
|
+
export type OllamaModelKey = keyof typeof OLLAMA_MODELS;
|
|
288
|
+
|
|
289
|
+
export type ModelKey = keyof typeof MODELS;
|
|
290
|
+
|
|
291
|
+
export const DEFAULT_MODEL: ModelKey = 'opus-4-5';
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Queue Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages parallel task execution with configurable concurrency limits.
|
|
5
|
+
* Provides queue management, status tracking, and settings persistence.
|
|
6
|
+
* Settings are stored encrypted in the database using SecureSettingsRepository.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { app } from 'electron';
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { Task, TaskStatus, QueueSettings, QueueStatus, DEFAULT_QUEUE_SETTINGS } from '../../shared/types';
|
|
13
|
+
import { SecureSettingsRepository } from '../database/SecureSettingsRepository';
|
|
14
|
+
|
|
15
|
+
const LEGACY_SETTINGS_FILE = 'queue-settings.json';
|
|
16
|
+
|
|
17
|
+
// Forward declaration - will be set by daemon
|
|
18
|
+
type DaemonCallbacks = {
|
|
19
|
+
startTaskImmediate: (task: Task) => Promise<void>;
|
|
20
|
+
emitQueueUpdate: (status: QueueStatus) => void;
|
|
21
|
+
getTaskById: (taskId: string) => Task | undefined;
|
|
22
|
+
updateTaskStatus: (taskId: string, status: TaskStatus) => void;
|
|
23
|
+
onTaskTimeout: (taskId: string) => Promise<void>; // Called when a task times out
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export class TaskQueueManager {
|
|
27
|
+
private queuedTaskIds: string[] = []; // FIFO queue of task IDs
|
|
28
|
+
private runningTaskIds: Set<string> = new Set(); // Currently executing task IDs
|
|
29
|
+
private taskStartTimes: Map<string, number> = new Map(); // Track when each task started
|
|
30
|
+
private settings: QueueSettings;
|
|
31
|
+
private legacySettingsPath: string;
|
|
32
|
+
private callbacks: DaemonCallbacks;
|
|
33
|
+
private initialized: boolean = false;
|
|
34
|
+
private timeoutCheckInterval?: ReturnType<typeof setInterval>;
|
|
35
|
+
private static migrationCompleted = false;
|
|
36
|
+
|
|
37
|
+
constructor(callbacks: DaemonCallbacks) {
|
|
38
|
+
this.callbacks = callbacks;
|
|
39
|
+
const userDataPath = app.getPath('userData');
|
|
40
|
+
this.legacySettingsPath = path.join(userDataPath, LEGACY_SETTINGS_FILE);
|
|
41
|
+
|
|
42
|
+
// Migrate from legacy file if needed
|
|
43
|
+
this.migrateFromLegacyFile();
|
|
44
|
+
|
|
45
|
+
this.settings = this.loadSettings();
|
|
46
|
+
|
|
47
|
+
// Start periodic timeout check (every minute)
|
|
48
|
+
this.timeoutCheckInterval = setInterval(() => this.checkForTimedOutTasks(), 60 * 1000);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Migrate settings from legacy JSON file to encrypted database
|
|
53
|
+
*/
|
|
54
|
+
private migrateFromLegacyFile(): void {
|
|
55
|
+
if (TaskQueueManager.migrationCompleted) return;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
if (!SecureSettingsRepository.isInitialized()) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
63
|
+
|
|
64
|
+
if (repository.exists('queue')) {
|
|
65
|
+
TaskQueueManager.migrationCompleted = true;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!fs.existsSync(this.legacySettingsPath)) {
|
|
70
|
+
TaskQueueManager.migrationCompleted = true;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log('[TaskQueueManager] Migrating settings from legacy JSON file to encrypted database...');
|
|
75
|
+
|
|
76
|
+
// Create backup before migration
|
|
77
|
+
const backupPath = this.legacySettingsPath + '.migration-backup';
|
|
78
|
+
fs.copyFileSync(this.legacySettingsPath, backupPath);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const data = fs.readFileSync(this.legacySettingsPath, 'utf-8');
|
|
82
|
+
const parsed = JSON.parse(data);
|
|
83
|
+
const merged = { ...DEFAULT_QUEUE_SETTINGS, ...parsed };
|
|
84
|
+
|
|
85
|
+
repository.save('queue', merged);
|
|
86
|
+
console.log('[TaskQueueManager] Settings migrated to encrypted database');
|
|
87
|
+
|
|
88
|
+
// Migration successful - delete backup and original
|
|
89
|
+
fs.unlinkSync(backupPath);
|
|
90
|
+
fs.unlinkSync(this.legacySettingsPath);
|
|
91
|
+
console.log('[TaskQueueManager] Migration complete, cleaned up legacy files');
|
|
92
|
+
|
|
93
|
+
TaskQueueManager.migrationCompleted = true;
|
|
94
|
+
} catch (migrationError) {
|
|
95
|
+
console.error('[TaskQueueManager] Migration failed, backup preserved at:', backupPath);
|
|
96
|
+
throw migrationError;
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('[TaskQueueManager] Migration failed:', error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Cleanup resources (call on shutdown)
|
|
105
|
+
*/
|
|
106
|
+
destroy(): void {
|
|
107
|
+
if (this.timeoutCheckInterval) {
|
|
108
|
+
clearInterval(this.timeoutCheckInterval);
|
|
109
|
+
this.timeoutCheckInterval = undefined;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Initialize the queue manager - recover queue from database on startup
|
|
115
|
+
* Should be called after database is ready
|
|
116
|
+
*/
|
|
117
|
+
async initialize(
|
|
118
|
+
queuedTasks: Task[],
|
|
119
|
+
runningTasks: Task[]
|
|
120
|
+
): Promise<void> {
|
|
121
|
+
if (this.initialized) {
|
|
122
|
+
console.log('[TaskQueueManager] Already initialized, skipping');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log('[TaskQueueManager] Initializing queue manager');
|
|
127
|
+
console.log(`[TaskQueueManager] Found ${queuedTasks.length} queued tasks, ${runningTasks.length} running tasks`);
|
|
128
|
+
|
|
129
|
+
// Restore queued tasks in FIFO order by creation time
|
|
130
|
+
this.queuedTaskIds = queuedTasks
|
|
131
|
+
.sort((a, b) => a.createdAt - b.createdAt)
|
|
132
|
+
.map(t => t.id);
|
|
133
|
+
|
|
134
|
+
// Track currently running tasks
|
|
135
|
+
runningTasks.forEach(t => this.runningTaskIds.add(t.id));
|
|
136
|
+
|
|
137
|
+
this.initialized = true;
|
|
138
|
+
|
|
139
|
+
// Start processing queue if there are slots available
|
|
140
|
+
await this.processQueue();
|
|
141
|
+
|
|
142
|
+
// Emit initial queue status
|
|
143
|
+
this.emitQueueUpdate();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Enqueue a new task - either start immediately or add to queue
|
|
148
|
+
*
|
|
149
|
+
* Sub-agents (tasks with parentTaskId) bypass the concurrency limit to prevent
|
|
150
|
+
* deadlocks where a parent task waits for sub-agents that are stuck in the queue.
|
|
151
|
+
*/
|
|
152
|
+
async enqueue(task: Task): Promise<void> {
|
|
153
|
+
console.log(`[TaskQueueManager] Enqueueing task ${task.id}: ${task.title}`);
|
|
154
|
+
|
|
155
|
+
// Sub-agents bypass concurrency limits to prevent deadlock
|
|
156
|
+
// (parent would wait forever for sub-agents stuck in queue)
|
|
157
|
+
const isSubAgent = !!task.parentTaskId;
|
|
158
|
+
|
|
159
|
+
if (isSubAgent) {
|
|
160
|
+
console.log(`[TaskQueueManager] Starting sub-agent immediately (bypasses concurrency limit)`);
|
|
161
|
+
await this.startTask(task);
|
|
162
|
+
} else if (this.canStartImmediately()) {
|
|
163
|
+
console.log(`[TaskQueueManager] Starting task immediately (${this.runningTaskIds.size}/${this.settings.maxConcurrentTasks} slots used)`);
|
|
164
|
+
await this.startTask(task);
|
|
165
|
+
} else {
|
|
166
|
+
console.log(`[TaskQueueManager] Queue full, adding task to queue (position: ${this.queuedTaskIds.length + 1})`);
|
|
167
|
+
this.queuedTaskIds.push(task.id);
|
|
168
|
+
this.callbacks.updateTaskStatus(task.id, 'queued');
|
|
169
|
+
this.emitQueueUpdate();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Called when a task finishes (completed, failed, or cancelled)
|
|
175
|
+
*/
|
|
176
|
+
async onTaskFinished(taskId: string): Promise<void> {
|
|
177
|
+
console.log(`[TaskQueueManager] Task ${taskId} finished`);
|
|
178
|
+
|
|
179
|
+
// Remove from running set and clear start time
|
|
180
|
+
this.runningTaskIds.delete(taskId);
|
|
181
|
+
this.taskStartTimes.delete(taskId);
|
|
182
|
+
|
|
183
|
+
// Process next task in queue
|
|
184
|
+
await this.processQueue();
|
|
185
|
+
|
|
186
|
+
// Emit updated status
|
|
187
|
+
this.emitQueueUpdate();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Cancel a queued task (remove from queue without starting)
|
|
192
|
+
* Returns true if task was in queue and removed
|
|
193
|
+
*/
|
|
194
|
+
cancelQueuedTask(taskId: string): boolean {
|
|
195
|
+
const index = this.queuedTaskIds.indexOf(taskId);
|
|
196
|
+
if (index !== -1) {
|
|
197
|
+
console.log(`[TaskQueueManager] Removing task ${taskId} from queue`);
|
|
198
|
+
this.queuedTaskIds.splice(index, 1);
|
|
199
|
+
this.emitQueueUpdate();
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Check if a task is currently in the queue
|
|
207
|
+
*/
|
|
208
|
+
isQueued(taskId: string): boolean {
|
|
209
|
+
return this.queuedTaskIds.includes(taskId);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Check if a task is currently running
|
|
214
|
+
*/
|
|
215
|
+
isRunning(taskId: string): boolean {
|
|
216
|
+
return this.runningTaskIds.has(taskId);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Clear all stuck tasks from the running set
|
|
221
|
+
* This should be used to recover from stuck state when tasks fail to clean up
|
|
222
|
+
* Returns the number of tasks cleared
|
|
223
|
+
*/
|
|
224
|
+
clearStuckTasks(): { clearedRunning: number; clearedQueued: number } {
|
|
225
|
+
const clearedRunning = this.runningTaskIds.size;
|
|
226
|
+
const clearedQueued = this.queuedTaskIds.length;
|
|
227
|
+
|
|
228
|
+
console.log(`[TaskQueueManager] Clearing ${clearedRunning} running tasks and ${clearedQueued} queued tasks`);
|
|
229
|
+
|
|
230
|
+
// Clear running tasks and their start times
|
|
231
|
+
this.runningTaskIds.clear();
|
|
232
|
+
this.taskStartTimes.clear();
|
|
233
|
+
|
|
234
|
+
// Clear queued tasks
|
|
235
|
+
this.queuedTaskIds = [];
|
|
236
|
+
|
|
237
|
+
// Emit update
|
|
238
|
+
this.emitQueueUpdate();
|
|
239
|
+
|
|
240
|
+
return { clearedRunning, clearedQueued };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get current queue status for UI
|
|
245
|
+
*/
|
|
246
|
+
getStatus(): QueueStatus {
|
|
247
|
+
return {
|
|
248
|
+
runningCount: this.runningTaskIds.size,
|
|
249
|
+
queuedCount: this.queuedTaskIds.length,
|
|
250
|
+
runningTaskIds: Array.from(this.runningTaskIds),
|
|
251
|
+
queuedTaskIds: [...this.queuedTaskIds],
|
|
252
|
+
maxConcurrent: this.settings.maxConcurrentTasks,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get current settings
|
|
258
|
+
*/
|
|
259
|
+
getSettings(): QueueSettings {
|
|
260
|
+
return { ...this.settings };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Update settings
|
|
265
|
+
*/
|
|
266
|
+
saveSettings(newSettings: Partial<QueueSettings>): void {
|
|
267
|
+
// Validate maxConcurrentTasks
|
|
268
|
+
if (newSettings.maxConcurrentTasks !== undefined) {
|
|
269
|
+
newSettings.maxConcurrentTasks = Math.max(1, Math.min(10, newSettings.maxConcurrentTasks));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Validate taskTimeoutMinutes (5 min to 4 hours)
|
|
273
|
+
if (newSettings.taskTimeoutMinutes !== undefined) {
|
|
274
|
+
newSettings.taskTimeoutMinutes = Math.max(5, Math.min(240, newSettings.taskTimeoutMinutes));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
this.settings = { ...this.settings, ...newSettings };
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
if (SecureSettingsRepository.isInitialized()) {
|
|
281
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
282
|
+
repository.save('queue', this.settings);
|
|
283
|
+
console.log('[TaskQueueManager] Settings saved to encrypted database');
|
|
284
|
+
} else {
|
|
285
|
+
console.warn('[TaskQueueManager] SecureSettingsRepository not initialized, settings not persisted');
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error('[TaskQueueManager] Failed to save settings:', error);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Process queue in case we increased concurrency
|
|
292
|
+
this.processQueue();
|
|
293
|
+
this.emitQueueUpdate();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ===== Private Methods =====
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Process the queue - start tasks if slots are available
|
|
300
|
+
*/
|
|
301
|
+
private async processQueue(): Promise<void> {
|
|
302
|
+
while (this.canStartImmediately() && this.queuedTaskIds.length > 0) {
|
|
303
|
+
const nextTaskId = this.queuedTaskIds.shift()!;
|
|
304
|
+
const task = this.callbacks.getTaskById(nextTaskId);
|
|
305
|
+
|
|
306
|
+
if (task && task.status === 'queued') {
|
|
307
|
+
console.log(`[TaskQueueManager] Dequeuing task ${nextTaskId}`);
|
|
308
|
+
await this.startTask(task);
|
|
309
|
+
} else {
|
|
310
|
+
console.log(`[TaskQueueManager] Skipping task ${nextTaskId} (not found or status changed)`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Check if we can start a task immediately
|
|
317
|
+
*/
|
|
318
|
+
private canStartImmediately(): boolean {
|
|
319
|
+
return this.runningTaskIds.size < this.settings.maxConcurrentTasks;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Start a task
|
|
324
|
+
*/
|
|
325
|
+
private async startTask(task: Task): Promise<void> {
|
|
326
|
+
this.runningTaskIds.add(task.id);
|
|
327
|
+
this.taskStartTimes.set(task.id, Date.now());
|
|
328
|
+
this.emitQueueUpdate();
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
await this.callbacks.startTaskImmediate(task);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(`[TaskQueueManager] Failed to start task ${task.id}:`, error);
|
|
334
|
+
this.runningTaskIds.delete(task.id);
|
|
335
|
+
this.taskStartTimes.delete(task.id);
|
|
336
|
+
this.emitQueueUpdate();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Emit queue status update
|
|
342
|
+
*/
|
|
343
|
+
private emitQueueUpdate(): void {
|
|
344
|
+
this.callbacks.emitQueueUpdate(this.getStatus());
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Check for tasks that have exceeded the timeout and clear them
|
|
349
|
+
*/
|
|
350
|
+
private async checkForTimedOutTasks(): Promise<void> {
|
|
351
|
+
const now = Date.now();
|
|
352
|
+
const timeoutMs = this.settings.taskTimeoutMinutes * 60 * 1000;
|
|
353
|
+
const timedOutTasks: string[] = [];
|
|
354
|
+
|
|
355
|
+
// Find tasks that have exceeded the timeout
|
|
356
|
+
for (const [taskId, startTime] of this.taskStartTimes) {
|
|
357
|
+
const elapsed = now - startTime;
|
|
358
|
+
if (elapsed > timeoutMs) {
|
|
359
|
+
const elapsedMinutes = Math.round(elapsed / 60000);
|
|
360
|
+
console.log(`[TaskQueueManager] Task ${taskId} has timed out (running for ${elapsedMinutes} minutes, timeout: ${this.settings.taskTimeoutMinutes} minutes)`);
|
|
361
|
+
timedOutTasks.push(taskId);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Process timed out tasks
|
|
366
|
+
for (const taskId of timedOutTasks) {
|
|
367
|
+
try {
|
|
368
|
+
// Notify daemon to handle the timeout (cancel task, cleanup resources)
|
|
369
|
+
await this.callbacks.onTaskTimeout(taskId);
|
|
370
|
+
|
|
371
|
+
// Remove from tracking (daemon will call onTaskFinished which also removes, but do it here just in case)
|
|
372
|
+
this.runningTaskIds.delete(taskId);
|
|
373
|
+
this.taskStartTimes.delete(taskId);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
console.error(`[TaskQueueManager] Error handling timeout for task ${taskId}:`, error);
|
|
376
|
+
// Force remove from tracking even if daemon callback fails
|
|
377
|
+
this.runningTaskIds.delete(taskId);
|
|
378
|
+
this.taskStartTimes.delete(taskId);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// If any tasks were cleared, process the queue and emit update
|
|
383
|
+
if (timedOutTasks.length > 0) {
|
|
384
|
+
await this.processQueue();
|
|
385
|
+
this.emitQueueUpdate();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Load settings from encrypted database
|
|
391
|
+
*/
|
|
392
|
+
private loadSettings(): QueueSettings {
|
|
393
|
+
try {
|
|
394
|
+
if (SecureSettingsRepository.isInitialized()) {
|
|
395
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
396
|
+
const stored = repository.load<QueueSettings>('queue');
|
|
397
|
+
if (stored) {
|
|
398
|
+
// Merge with defaults to handle missing fields
|
|
399
|
+
console.log('[TaskQueueManager] Loaded settings from encrypted database');
|
|
400
|
+
return { ...DEFAULT_QUEUE_SETTINGS, ...stored };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.error('[TaskQueueManager] Failed to load settings:', error);
|
|
405
|
+
}
|
|
406
|
+
return { ...DEFAULT_QUEUE_SETTINGS };
|
|
407
|
+
}
|
|
408
|
+
}
|