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,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Security Manager
|
|
4
|
+
*
|
|
5
|
+
* Handles user authorization for channel access.
|
|
6
|
+
* Supports three modes:
|
|
7
|
+
* - open: Anyone can use the bot
|
|
8
|
+
* - allowlist: Only pre-approved users
|
|
9
|
+
* - pairing: Users must enter a pairing code generated in the desktop app
|
|
10
|
+
*
|
|
11
|
+
* Implements concurrent access safety using mutex locks to prevent race conditions
|
|
12
|
+
* in pairing operations.
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.SecurityManager = void 0;
|
|
49
|
+
const crypto = __importStar(require("crypto"));
|
|
50
|
+
const repositories_1 = require("../database/repositories");
|
|
51
|
+
const concurrency_1 = require("../security/concurrency");
|
|
52
|
+
const context_policy_1 = require("./context-policy");
|
|
53
|
+
class SecurityManager {
|
|
54
|
+
constructor(db) {
|
|
55
|
+
this.userRepo = new repositories_1.ChannelUserRepository(db);
|
|
56
|
+
this.pairingIdempotency = new concurrency_1.IdempotencyManager(5 * 60 * 1000); // 5 min TTL
|
|
57
|
+
this.contextPolicyManager = new context_policy_1.ContextPolicyManager(db);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the context policy manager for direct access to context policies
|
|
61
|
+
*/
|
|
62
|
+
getContextPolicyManager() {
|
|
63
|
+
return this.contextPolicyManager;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if a message sender is allowed to interact
|
|
67
|
+
* Supports per-context (DM vs group) security policies
|
|
68
|
+
*/
|
|
69
|
+
async checkAccess(channel, message, isGroup) {
|
|
70
|
+
const securityConfig = channel.securityConfig;
|
|
71
|
+
// Determine context type
|
|
72
|
+
// Priority: 1) Explicit isGroup parameter, 2) Channel type check, 3) Inference from IDs
|
|
73
|
+
let contextType;
|
|
74
|
+
if (isGroup !== undefined) {
|
|
75
|
+
// Explicit parameter takes precedence
|
|
76
|
+
contextType = isGroup ? 'group' : 'dm';
|
|
77
|
+
}
|
|
78
|
+
else if (SecurityManager.DM_ONLY_CHANNELS.includes(channel.type)) {
|
|
79
|
+
// Channels that don't support groups always use DM context
|
|
80
|
+
contextType = 'dm';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Infer from message - chatId different from userId typically means group
|
|
84
|
+
// This works for Telegram, Discord, Slack, etc.
|
|
85
|
+
contextType = message.chatId !== message.userId ? 'group' : 'dm';
|
|
86
|
+
}
|
|
87
|
+
// Get context-specific policy (creates default if doesn't exist)
|
|
88
|
+
const contextPolicy = this.contextPolicyManager.getPolicy(channel.id, contextType);
|
|
89
|
+
// Use context policy's security mode, falling back to channel default
|
|
90
|
+
const mode = contextPolicy.securityMode || securityConfig.mode;
|
|
91
|
+
// Get denied tools for this context
|
|
92
|
+
const deniedTools = contextPolicy.toolRestrictions || [];
|
|
93
|
+
// Get or create user record
|
|
94
|
+
let user = this.userRepo.findByChannelUserId(channel.id, message.userId);
|
|
95
|
+
if (!user) {
|
|
96
|
+
// Create new user record
|
|
97
|
+
user = this.userRepo.create({
|
|
98
|
+
channelId: channel.id,
|
|
99
|
+
channelUserId: message.userId,
|
|
100
|
+
displayName: message.userName,
|
|
101
|
+
allowed: mode === 'open', // Auto-allow in open mode
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Update display name if changed
|
|
106
|
+
if (user.displayName !== message.userName) {
|
|
107
|
+
this.userRepo.update(user.id, { displayName: message.userName });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Check based on security mode
|
|
111
|
+
switch (mode) {
|
|
112
|
+
case 'open':
|
|
113
|
+
// Everyone is allowed
|
|
114
|
+
return { allowed: true, user, contextType, deniedTools };
|
|
115
|
+
case 'allowlist': {
|
|
116
|
+
// Check if user is in allowlist
|
|
117
|
+
if (user.allowed) {
|
|
118
|
+
return { allowed: true, user, contextType, deniedTools };
|
|
119
|
+
}
|
|
120
|
+
// Check if user ID is in config allowlist
|
|
121
|
+
const allowedUsers = securityConfig.allowedUsers || [];
|
|
122
|
+
if (allowedUsers.includes(message.userId)) {
|
|
123
|
+
// Add to allowed users
|
|
124
|
+
this.userRepo.update(user.id, { allowed: true });
|
|
125
|
+
return {
|
|
126
|
+
allowed: true,
|
|
127
|
+
user: { ...user, allowed: true },
|
|
128
|
+
contextType,
|
|
129
|
+
deniedTools,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
allowed: false,
|
|
134
|
+
user,
|
|
135
|
+
reason: 'User not in allowlist',
|
|
136
|
+
contextType,
|
|
137
|
+
deniedTools,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
case 'pairing':
|
|
141
|
+
// Check if user has been paired
|
|
142
|
+
if (user.allowed) {
|
|
143
|
+
return { allowed: true, user, contextType, deniedTools };
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
allowed: false,
|
|
147
|
+
user,
|
|
148
|
+
reason: 'Pairing required',
|
|
149
|
+
pairingRequired: true,
|
|
150
|
+
contextType,
|
|
151
|
+
deniedTools,
|
|
152
|
+
};
|
|
153
|
+
default:
|
|
154
|
+
return {
|
|
155
|
+
allowed: false,
|
|
156
|
+
reason: `Unknown security mode: ${mode}`,
|
|
157
|
+
contextType,
|
|
158
|
+
deniedTools,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Generate a pairing code for a channel
|
|
164
|
+
* Creates a placeholder entry that can be claimed by any user who enters the code
|
|
165
|
+
* Uses mutex to prevent race conditions in concurrent code generation
|
|
166
|
+
*/
|
|
167
|
+
generatePairingCode(channel, _userId, _displayName) {
|
|
168
|
+
// Use synchronous mutex key for this channel to prevent concurrent generation issues
|
|
169
|
+
const mutexKey = `pairing:generate:${channel.id}`;
|
|
170
|
+
// Generate code (synchronous operation, but we track idempotency)
|
|
171
|
+
const code = this.createPairingCode();
|
|
172
|
+
const ttl = channel.securityConfig.pairingCodeTTL || 300; // 5 minutes default
|
|
173
|
+
const expiresAt = Date.now() + ttl * 1000;
|
|
174
|
+
// Create a placeholder user entry with the pairing code
|
|
175
|
+
// Use a unique placeholder ID so multiple codes can exist
|
|
176
|
+
const placeholderId = `pending_${code}_${Date.now()}`;
|
|
177
|
+
this.userRepo.create({
|
|
178
|
+
channelId: channel.id,
|
|
179
|
+
channelUserId: placeholderId,
|
|
180
|
+
displayName: 'Pending User',
|
|
181
|
+
allowed: false,
|
|
182
|
+
pairingCode: code,
|
|
183
|
+
pairingExpiresAt: expiresAt,
|
|
184
|
+
});
|
|
185
|
+
return code;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Verify a pairing code
|
|
189
|
+
* Looks up the code across all users in the channel and grants access to the caller
|
|
190
|
+
* Uses idempotency to prevent double-verification race conditions
|
|
191
|
+
*/
|
|
192
|
+
async verifyPairingCode(channel, userId, code) {
|
|
193
|
+
// Generate idempotency key for this verification attempt
|
|
194
|
+
const idempotencyKey = concurrency_1.IdempotencyManager.generateKey('pairing:verify', channel.id, userId, code.toUpperCase());
|
|
195
|
+
// Check if this exact verification is already in progress or completed
|
|
196
|
+
const existing = this.pairingIdempotency.check(idempotencyKey);
|
|
197
|
+
if (existing.exists && existing.status === 'completed') {
|
|
198
|
+
return existing.result;
|
|
199
|
+
}
|
|
200
|
+
// Use mutex to ensure only one verification happens at a time per channel
|
|
201
|
+
const mutexKey = `pairing:verify:${channel.id}`;
|
|
202
|
+
return await concurrency_1.pairingMutex.withLock(mutexKey, async () => {
|
|
203
|
+
// Double-check idempotency after acquiring lock
|
|
204
|
+
const recheck = this.pairingIdempotency.check(idempotencyKey);
|
|
205
|
+
if (recheck.exists && recheck.status === 'completed') {
|
|
206
|
+
return recheck.result;
|
|
207
|
+
}
|
|
208
|
+
// Start tracking this operation
|
|
209
|
+
this.pairingIdempotency.start(idempotencyKey);
|
|
210
|
+
try {
|
|
211
|
+
const result = await this.doVerifyPairingCode(channel, userId, code);
|
|
212
|
+
this.pairingIdempotency.complete(idempotencyKey, result);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
this.pairingIdempotency.fail(idempotencyKey, error);
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
async doVerifyPairingCode(channel, userId, code) {
|
|
222
|
+
// First check if user is already allowed
|
|
223
|
+
const existingUser = this.userRepo.findByChannelUserId(channel.id, userId);
|
|
224
|
+
if (existingUser?.allowed) {
|
|
225
|
+
return { success: true, user: existingUser };
|
|
226
|
+
}
|
|
227
|
+
// Brute-force protection: Check if user is locked out due to too many failed attempts
|
|
228
|
+
if (existingUser && existingUser.pairingAttempts >= SecurityManager.MAX_PAIRING_ATTEMPTS) {
|
|
229
|
+
// Check if lockout period has passed (use dedicated lockoutUntil field)
|
|
230
|
+
const lockoutUntil = existingUser.lockoutUntil;
|
|
231
|
+
if (lockoutUntil && Date.now() < lockoutUntil) {
|
|
232
|
+
const remainingMinutes = Math.ceil((lockoutUntil - Date.now()) / 60000);
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
error: `Too many failed attempts. Please wait ${remainingMinutes} minute(s) before trying again.`,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
// Lockout expired - reset attempts (keep pairingExpiresAt unchanged)
|
|
239
|
+
this.userRepo.update(existingUser.id, {
|
|
240
|
+
pairingAttempts: 0,
|
|
241
|
+
lockoutUntil: undefined,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
// Look up the pairing code across all users in the channel
|
|
245
|
+
const codeOwner = this.userRepo.findByPairingCode(channel.id, code.toUpperCase());
|
|
246
|
+
if (!codeOwner) {
|
|
247
|
+
// Code not found - increment attempts on the requesting user if they exist
|
|
248
|
+
if (existingUser) {
|
|
249
|
+
const newAttempts = existingUser.pairingAttempts + 1;
|
|
250
|
+
const updates = {
|
|
251
|
+
pairingAttempts: newAttempts,
|
|
252
|
+
};
|
|
253
|
+
// Set lockout timestamp if max attempts reached (uses dedicated lockoutUntil field)
|
|
254
|
+
if (newAttempts >= SecurityManager.MAX_PAIRING_ATTEMPTS) {
|
|
255
|
+
updates.lockoutUntil = Date.now() + SecurityManager.PAIRING_LOCKOUT_MS;
|
|
256
|
+
}
|
|
257
|
+
this.userRepo.update(existingUser.id, updates);
|
|
258
|
+
// Warn user about remaining attempts
|
|
259
|
+
const remaining = SecurityManager.MAX_PAIRING_ATTEMPTS - newAttempts;
|
|
260
|
+
if (remaining > 0) {
|
|
261
|
+
return { success: false, error: `Invalid pairing code. ${remaining} attempt(s) remaining.` };
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
return { success: false, error: 'Too many failed attempts. Please wait 15 minutes before trying again.' };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return { success: false, error: 'Invalid pairing code' };
|
|
268
|
+
}
|
|
269
|
+
// Check expiration
|
|
270
|
+
if (codeOwner.pairingExpiresAt && Date.now() > codeOwner.pairingExpiresAt) {
|
|
271
|
+
// Clear expired code
|
|
272
|
+
this.userRepo.update(codeOwner.id, {
|
|
273
|
+
pairingCode: undefined,
|
|
274
|
+
pairingExpiresAt: undefined,
|
|
275
|
+
});
|
|
276
|
+
return { success: false, error: 'Pairing code has expired. Please request a new one.' };
|
|
277
|
+
}
|
|
278
|
+
// Code is valid! Grant access to the requesting user
|
|
279
|
+
if (existingUser) {
|
|
280
|
+
// Update existing user to be allowed
|
|
281
|
+
this.userRepo.update(existingUser.id, {
|
|
282
|
+
allowed: true,
|
|
283
|
+
pairingCode: undefined,
|
|
284
|
+
pairingExpiresAt: undefined,
|
|
285
|
+
pairingAttempts: 0,
|
|
286
|
+
lockoutUntil: undefined,
|
|
287
|
+
});
|
|
288
|
+
// Clear the code from wherever it was stored
|
|
289
|
+
if (codeOwner.id !== existingUser.id) {
|
|
290
|
+
this.userRepo.update(codeOwner.id, {
|
|
291
|
+
pairingCode: undefined,
|
|
292
|
+
pairingExpiresAt: undefined,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return { success: true, user: { ...existingUser, allowed: true } };
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// This shouldn't happen since checkAccess creates the user, but handle it
|
|
299
|
+
return { success: false, error: 'User record not found' };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Revoke a user's access
|
|
304
|
+
*/
|
|
305
|
+
revokeAccess(channelId, userId) {
|
|
306
|
+
const user = this.userRepo.findByChannelUserId(channelId, userId);
|
|
307
|
+
if (user) {
|
|
308
|
+
this.userRepo.update(user.id, { allowed: false });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Grant a user access directly (for allowlist management)
|
|
313
|
+
*/
|
|
314
|
+
grantAccess(channelId, userId, displayName) {
|
|
315
|
+
let user = this.userRepo.findByChannelUserId(channelId, userId);
|
|
316
|
+
if (user) {
|
|
317
|
+
this.userRepo.update(user.id, { allowed: true });
|
|
318
|
+
}
|
|
319
|
+
else if (displayName) {
|
|
320
|
+
this.userRepo.create({
|
|
321
|
+
channelId,
|
|
322
|
+
channelUserId: userId,
|
|
323
|
+
displayName,
|
|
324
|
+
allowed: true,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get all users for a channel
|
|
330
|
+
* Automatically cleans up expired pending pairing entries before returning
|
|
331
|
+
*/
|
|
332
|
+
getChannelUsers(channelId) {
|
|
333
|
+
// Cleanup expired pending entries first
|
|
334
|
+
this.cleanupExpiredPending(channelId);
|
|
335
|
+
return this.userRepo.findByChannelId(channelId);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Cleanup expired pending pairing entries for a channel
|
|
339
|
+
* These are placeholder entries created when generating pairing codes that have expired
|
|
340
|
+
* Returns the number of deleted entries
|
|
341
|
+
*/
|
|
342
|
+
cleanupExpiredPending(channelId) {
|
|
343
|
+
return this.userRepo.deleteExpiredPending(channelId);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get allowed users for a channel
|
|
347
|
+
*/
|
|
348
|
+
getAllowedUsers(channelId) {
|
|
349
|
+
return this.userRepo.findAllowedByChannelId(channelId);
|
|
350
|
+
}
|
|
351
|
+
// Private methods
|
|
352
|
+
/**
|
|
353
|
+
* Create a random pairing code
|
|
354
|
+
*/
|
|
355
|
+
createPairingCode() {
|
|
356
|
+
// Generate 6-character alphanumeric code
|
|
357
|
+
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // Exclude similar chars (I, O, 1, 0)
|
|
358
|
+
let code = '';
|
|
359
|
+
const randomBytes = crypto.randomBytes(6);
|
|
360
|
+
for (let i = 0; i < 6; i++) {
|
|
361
|
+
code += chars[randomBytes[i] % chars.length];
|
|
362
|
+
}
|
|
363
|
+
return code;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
exports.SecurityManager = SecurityManager;
|
|
367
|
+
// Channels that don't support group chats - always use DM context
|
|
368
|
+
SecurityManager.DM_ONLY_CHANNELS = ['email', 'imessage', 'bluebubbles'];
|
|
369
|
+
/**
|
|
370
|
+
* Internal pairing verification logic (called within mutex)
|
|
371
|
+
*/
|
|
372
|
+
// Maximum pairing attempts before lockout (brute-force protection)
|
|
373
|
+
SecurityManager.MAX_PAIRING_ATTEMPTS = 5;
|
|
374
|
+
// Lockout duration in milliseconds (15 minutes)
|
|
375
|
+
SecurityManager.PAIRING_LOCKOUT_MS = 15 * 60 * 1000;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Session Manager
|
|
4
|
+
*
|
|
5
|
+
* Manages channel sessions linking chats to CoWork tasks.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SessionManager = void 0;
|
|
9
|
+
const repositories_1 = require("../database/repositories");
|
|
10
|
+
class SessionManager {
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.sessionRepo = new repositories_1.ChannelSessionRepository(db);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get or create a session for a chat
|
|
16
|
+
*/
|
|
17
|
+
async getOrCreateSession(channel, chatId, userId, defaultWorkspaceId) {
|
|
18
|
+
// Look for existing session
|
|
19
|
+
let session = this.sessionRepo.findByChatId(channel.id, chatId);
|
|
20
|
+
if (session) {
|
|
21
|
+
// Update last activity
|
|
22
|
+
this.sessionRepo.update(session.id, {
|
|
23
|
+
lastActivityAt: Date.now(),
|
|
24
|
+
});
|
|
25
|
+
return { ...session, lastActivityAt: Date.now() };
|
|
26
|
+
}
|
|
27
|
+
// Create new session
|
|
28
|
+
session = this.sessionRepo.create({
|
|
29
|
+
channelId: channel.id,
|
|
30
|
+
chatId,
|
|
31
|
+
userId,
|
|
32
|
+
workspaceId: defaultWorkspaceId,
|
|
33
|
+
state: 'idle',
|
|
34
|
+
});
|
|
35
|
+
return session;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get session by ID
|
|
39
|
+
*/
|
|
40
|
+
getSession(sessionId) {
|
|
41
|
+
return this.sessionRepo.findById(sessionId);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get session by task ID
|
|
45
|
+
*/
|
|
46
|
+
getSessionByTaskId(taskId) {
|
|
47
|
+
return this.sessionRepo.findByTaskId(taskId);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Update session state
|
|
51
|
+
*/
|
|
52
|
+
updateSessionState(sessionId, state) {
|
|
53
|
+
this.sessionRepo.update(sessionId, {
|
|
54
|
+
state,
|
|
55
|
+
lastActivityAt: Date.now(),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Link a session to a task
|
|
60
|
+
*/
|
|
61
|
+
linkSessionToTask(sessionId, taskId) {
|
|
62
|
+
this.sessionRepo.update(sessionId, {
|
|
63
|
+
taskId,
|
|
64
|
+
state: 'active',
|
|
65
|
+
lastActivityAt: Date.now(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Unlink session from task
|
|
70
|
+
*/
|
|
71
|
+
unlinkSessionFromTask(sessionId) {
|
|
72
|
+
this.sessionRepo.update(sessionId, {
|
|
73
|
+
taskId: undefined,
|
|
74
|
+
state: 'idle',
|
|
75
|
+
lastActivityAt: Date.now(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set session workspace
|
|
80
|
+
*/
|
|
81
|
+
setSessionWorkspace(sessionId, workspaceId) {
|
|
82
|
+
this.sessionRepo.update(sessionId, {
|
|
83
|
+
workspaceId,
|
|
84
|
+
lastActivityAt: Date.now(),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Update session context
|
|
89
|
+
*/
|
|
90
|
+
updateSessionContext(sessionId, context) {
|
|
91
|
+
const session = this.sessionRepo.findById(sessionId);
|
|
92
|
+
if (session) {
|
|
93
|
+
const mergedContext = { ...session.context, ...context };
|
|
94
|
+
this.sessionRepo.update(sessionId, {
|
|
95
|
+
context: mergedContext,
|
|
96
|
+
lastActivityAt: Date.now(),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get active sessions for a channel
|
|
102
|
+
*/
|
|
103
|
+
getActiveSessions(channelId) {
|
|
104
|
+
return this.sessionRepo.findActiveByChannelId(channelId);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Clean up old idle sessions
|
|
108
|
+
*/
|
|
109
|
+
cleanupOldSessions(maxAgeMs = 24 * 60 * 60 * 1000) {
|
|
110
|
+
// This would require a new method in the repository
|
|
111
|
+
// For now, we'll skip automated cleanup
|
|
112
|
+
console.log('Session cleanup not yet implemented');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.SessionManager = SessionManager;
|