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,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Settings Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages webhook configuration with encrypted storage.
|
|
5
|
+
* Settings are stored encrypted in the database using SecureSettingsRepository.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { app, safeStorage } from 'electron';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import crypto from 'crypto';
|
|
12
|
+
import {
|
|
13
|
+
HooksConfig,
|
|
14
|
+
GmailHooksConfig,
|
|
15
|
+
HookMappingConfig,
|
|
16
|
+
DEFAULT_HOOKS_CONFIG,
|
|
17
|
+
DEFAULT_HOOKS_PATH,
|
|
18
|
+
DEFAULT_HOOKS_MAX_BODY_BYTES,
|
|
19
|
+
DEFAULT_GMAIL_LABEL,
|
|
20
|
+
DEFAULT_GMAIL_SERVE_BIND,
|
|
21
|
+
DEFAULT_GMAIL_SERVE_PORT,
|
|
22
|
+
DEFAULT_GMAIL_SERVE_PATH,
|
|
23
|
+
DEFAULT_GMAIL_MAX_BYTES,
|
|
24
|
+
DEFAULT_GMAIL_RENEW_MINUTES,
|
|
25
|
+
DEFAULT_GMAIL_SUBSCRIPTION,
|
|
26
|
+
DEFAULT_GMAIL_TOPIC,
|
|
27
|
+
} from './types';
|
|
28
|
+
import { SecureSettingsRepository } from '../database/SecureSettingsRepository';
|
|
29
|
+
|
|
30
|
+
const LEGACY_SETTINGS_FILE = 'hooks-settings.json';
|
|
31
|
+
const MASKED_VALUE = '***configured***';
|
|
32
|
+
const ENCRYPTED_PREFIX = 'encrypted:';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Generate a secure random token
|
|
36
|
+
*/
|
|
37
|
+
export function generateHookToken(bytes = 24): string {
|
|
38
|
+
return crypto.randomBytes(bytes).toString('hex');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Encrypt a secret using OS keychain via safeStorage
|
|
43
|
+
*/
|
|
44
|
+
function encryptSecret(value?: string): string | undefined {
|
|
45
|
+
if (!value || !value.trim()) return undefined;
|
|
46
|
+
const trimmed = value.trim();
|
|
47
|
+
if (trimmed === MASKED_VALUE) return undefined;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (safeStorage.isEncryptionAvailable()) {
|
|
51
|
+
const encrypted = safeStorage.encryptString(trimmed);
|
|
52
|
+
return ENCRYPTED_PREFIX + encrypted.toString('base64');
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.warn('[Hooks Settings] Failed to encrypt secret, storing masked:', error);
|
|
56
|
+
}
|
|
57
|
+
// Fallback to masked value if encryption fails
|
|
58
|
+
return MASKED_VALUE;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Decrypt a secret that was encrypted with safeStorage
|
|
63
|
+
*/
|
|
64
|
+
function decryptSecret(value?: string): string | undefined {
|
|
65
|
+
if (!value) return undefined;
|
|
66
|
+
if (value === MASKED_VALUE) return undefined;
|
|
67
|
+
|
|
68
|
+
if (value.startsWith(ENCRYPTED_PREFIX)) {
|
|
69
|
+
try {
|
|
70
|
+
if (safeStorage.isEncryptionAvailable()) {
|
|
71
|
+
const encrypted = Buffer.from(value.slice(ENCRYPTED_PREFIX.length), 'base64');
|
|
72
|
+
const decrypted = safeStorage.decryptString(encrypted);
|
|
73
|
+
return decrypted;
|
|
74
|
+
} else {
|
|
75
|
+
console.error('[Hooks Settings] safeStorage encryption not available - cannot decrypt secrets');
|
|
76
|
+
}
|
|
77
|
+
} catch (error: any) {
|
|
78
|
+
console.error('[Hooks Settings] Failed to decrypt secret:', error.message || error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// If not encrypted and not masked, return as-is (for backwards compatibility)
|
|
83
|
+
if (value !== MASKED_VALUE && !value.startsWith(ENCRYPTED_PREFIX)) {
|
|
84
|
+
return value.trim() || undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Encrypt all credentials in settings before saving to disk
|
|
92
|
+
*/
|
|
93
|
+
function encryptSettings(settings: HooksConfig): HooksConfig {
|
|
94
|
+
return {
|
|
95
|
+
...settings,
|
|
96
|
+
token: encryptSecret(settings.token) || '',
|
|
97
|
+
gmail: settings.gmail ? {
|
|
98
|
+
...settings.gmail,
|
|
99
|
+
pushToken: encryptSecret(settings.gmail.pushToken),
|
|
100
|
+
} : undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Decrypt all credentials in settings after loading from disk
|
|
106
|
+
*/
|
|
107
|
+
function decryptSettings(settings: HooksConfig): HooksConfig {
|
|
108
|
+
return {
|
|
109
|
+
...settings,
|
|
110
|
+
token: decryptSecret(settings.token) || '',
|
|
111
|
+
gmail: settings.gmail ? {
|
|
112
|
+
...settings.gmail,
|
|
113
|
+
pushToken: decryptSecret(settings.gmail.pushToken),
|
|
114
|
+
} : undefined,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Hooks Settings Manager
|
|
120
|
+
*/
|
|
121
|
+
export class HooksSettingsManager {
|
|
122
|
+
private static legacySettingsPath: string;
|
|
123
|
+
private static cachedSettings: HooksConfig | null = null;
|
|
124
|
+
private static initialized = false;
|
|
125
|
+
private static migrationCompleted = false;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Initialize the settings manager (must be called after app is ready)
|
|
129
|
+
*/
|
|
130
|
+
static initialize(): void {
|
|
131
|
+
if (this.initialized) return;
|
|
132
|
+
|
|
133
|
+
const userDataPath = app.getPath('userData');
|
|
134
|
+
this.legacySettingsPath = path.join(userDataPath, LEGACY_SETTINGS_FILE);
|
|
135
|
+
this.initialized = true;
|
|
136
|
+
|
|
137
|
+
console.log('[Hooks Settings] Initialized');
|
|
138
|
+
|
|
139
|
+
// Migrate from legacy JSON file to encrypted database
|
|
140
|
+
this.migrateFromLegacyFile();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Migrate settings from legacy JSON file to encrypted database
|
|
145
|
+
*/
|
|
146
|
+
private static migrateFromLegacyFile(): void {
|
|
147
|
+
if (this.migrationCompleted) return;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
if (!SecureSettingsRepository.isInitialized()) {
|
|
151
|
+
console.log('[Hooks Settings] SecureSettingsRepository not yet initialized, skipping migration');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
156
|
+
|
|
157
|
+
if (repository.exists('hooks')) {
|
|
158
|
+
this.migrationCompleted = true;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!fs.existsSync(this.legacySettingsPath)) {
|
|
163
|
+
console.log('[Hooks Settings] No legacy settings file found');
|
|
164
|
+
this.migrationCompleted = true;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log('[Hooks Settings] Migrating settings from legacy JSON file to encrypted database...');
|
|
169
|
+
|
|
170
|
+
// Create backup before migration
|
|
171
|
+
const backupPath = this.legacySettingsPath + '.migration-backup';
|
|
172
|
+
fs.copyFileSync(this.legacySettingsPath, backupPath);
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const data = fs.readFileSync(this.legacySettingsPath, 'utf-8');
|
|
176
|
+
const parsed = JSON.parse(data);
|
|
177
|
+
|
|
178
|
+
const merged: HooksConfig = {
|
|
179
|
+
...DEFAULT_HOOKS_CONFIG,
|
|
180
|
+
...parsed,
|
|
181
|
+
mappings: parsed.mappings || [],
|
|
182
|
+
presets: parsed.presets || [],
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Decrypt any existing encrypted values before saving to the new encrypted database
|
|
186
|
+
const decrypted = decryptSettings(merged);
|
|
187
|
+
|
|
188
|
+
repository.save('hooks', decrypted);
|
|
189
|
+
console.log('[Hooks Settings] Settings migrated to encrypted database');
|
|
190
|
+
|
|
191
|
+
// Migration successful - delete backup and original
|
|
192
|
+
fs.unlinkSync(backupPath);
|
|
193
|
+
fs.unlinkSync(this.legacySettingsPath);
|
|
194
|
+
console.log('[Hooks Settings] Migration complete, cleaned up legacy files');
|
|
195
|
+
|
|
196
|
+
this.migrationCompleted = true;
|
|
197
|
+
} catch (migrationError) {
|
|
198
|
+
console.error('[Hooks Settings] Migration failed, backup preserved at:', backupPath);
|
|
199
|
+
throw migrationError;
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('[Hooks Settings] Migration failed:', error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Load settings from encrypted database
|
|
208
|
+
*/
|
|
209
|
+
static loadSettings(): HooksConfig {
|
|
210
|
+
this.ensureInitialized();
|
|
211
|
+
|
|
212
|
+
if (this.cachedSettings) {
|
|
213
|
+
return this.cachedSettings;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
if (SecureSettingsRepository.isInitialized()) {
|
|
218
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
219
|
+
const stored = repository.load<HooksConfig>('hooks');
|
|
220
|
+
if (stored) {
|
|
221
|
+
const merged: HooksConfig = {
|
|
222
|
+
...DEFAULT_HOOKS_CONFIG,
|
|
223
|
+
...stored,
|
|
224
|
+
mappings: stored.mappings || [],
|
|
225
|
+
presets: stored.presets || [],
|
|
226
|
+
};
|
|
227
|
+
this.cachedSettings = merged;
|
|
228
|
+
console.log('[Hooks Settings] Loaded settings from encrypted database');
|
|
229
|
+
return this.cachedSettings;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error('[Hooks Settings] Failed to load settings:', error);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log('[Hooks Settings] No settings found, using defaults');
|
|
237
|
+
this.cachedSettings = { ...DEFAULT_HOOKS_CONFIG };
|
|
238
|
+
return this.cachedSettings;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Save settings to encrypted database
|
|
243
|
+
*/
|
|
244
|
+
static saveSettings(settings: HooksConfig): void {
|
|
245
|
+
this.ensureInitialized();
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
if (!SecureSettingsRepository.isInitialized()) {
|
|
249
|
+
throw new Error('SecureSettingsRepository not initialized');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const repository = SecureSettingsRepository.getInstance();
|
|
253
|
+
repository.save('hooks', settings);
|
|
254
|
+
this.cachedSettings = settings;
|
|
255
|
+
console.log('[Hooks Settings] Saved settings to encrypted database');
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error('[Hooks Settings] Failed to save settings:', error);
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Clear the settings cache (forces reload on next access)
|
|
264
|
+
*/
|
|
265
|
+
static clearCache(): void {
|
|
266
|
+
this.cachedSettings = null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Get default settings
|
|
271
|
+
*/
|
|
272
|
+
static getDefaults(): HooksConfig {
|
|
273
|
+
return { ...DEFAULT_HOOKS_CONFIG };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Update hooks configuration
|
|
278
|
+
*/
|
|
279
|
+
static updateConfig(updates: Partial<HooksConfig>): HooksConfig {
|
|
280
|
+
const settings = this.loadSettings();
|
|
281
|
+
const updated = { ...settings, ...updates };
|
|
282
|
+
this.saveSettings(updated);
|
|
283
|
+
return updated;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Enable hooks with a new token if not already configured
|
|
288
|
+
*/
|
|
289
|
+
static enableHooks(): HooksConfig {
|
|
290
|
+
const settings = this.loadSettings();
|
|
291
|
+
if (!settings.token) {
|
|
292
|
+
settings.token = generateHookToken();
|
|
293
|
+
}
|
|
294
|
+
settings.enabled = true;
|
|
295
|
+
this.saveSettings(settings);
|
|
296
|
+
return settings;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Disable hooks
|
|
301
|
+
*/
|
|
302
|
+
static disableHooks(): HooksConfig {
|
|
303
|
+
const settings = this.loadSettings();
|
|
304
|
+
settings.enabled = false;
|
|
305
|
+
this.saveSettings(settings);
|
|
306
|
+
return settings;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Regenerate the hook token
|
|
311
|
+
*/
|
|
312
|
+
static regenerateToken(): string {
|
|
313
|
+
const settings = this.loadSettings();
|
|
314
|
+
settings.token = generateHookToken();
|
|
315
|
+
this.saveSettings(settings);
|
|
316
|
+
return settings.token;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Add or update a preset
|
|
321
|
+
*/
|
|
322
|
+
static addPreset(preset: string): HooksConfig {
|
|
323
|
+
const settings = this.loadSettings();
|
|
324
|
+
const presets = new Set(settings.presets);
|
|
325
|
+
presets.add(preset);
|
|
326
|
+
settings.presets = Array.from(presets);
|
|
327
|
+
this.saveSettings(settings);
|
|
328
|
+
return settings;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Remove a preset
|
|
333
|
+
*/
|
|
334
|
+
static removePreset(preset: string): HooksConfig {
|
|
335
|
+
const settings = this.loadSettings();
|
|
336
|
+
settings.presets = settings.presets.filter((p) => p !== preset);
|
|
337
|
+
this.saveSettings(settings);
|
|
338
|
+
return settings;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Add a custom mapping
|
|
343
|
+
*/
|
|
344
|
+
static addMapping(mapping: HookMappingConfig): HooksConfig {
|
|
345
|
+
const settings = this.loadSettings();
|
|
346
|
+
settings.mappings.push(mapping);
|
|
347
|
+
this.saveSettings(settings);
|
|
348
|
+
return settings;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Update a mapping by ID
|
|
353
|
+
*/
|
|
354
|
+
static updateMapping(id: string, updates: Partial<HookMappingConfig>): HooksConfig | null {
|
|
355
|
+
const settings = this.loadSettings();
|
|
356
|
+
const index = settings.mappings.findIndex((m) => m.id === id);
|
|
357
|
+
if (index === -1) return null;
|
|
358
|
+
|
|
359
|
+
settings.mappings[index] = { ...settings.mappings[index], ...updates };
|
|
360
|
+
this.saveSettings(settings);
|
|
361
|
+
return settings;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Remove a mapping by ID
|
|
366
|
+
*/
|
|
367
|
+
static removeMapping(id: string): HooksConfig {
|
|
368
|
+
const settings = this.loadSettings();
|
|
369
|
+
settings.mappings = settings.mappings.filter((m) => m.id !== id);
|
|
370
|
+
this.saveSettings(settings);
|
|
371
|
+
return settings;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Configure Gmail hooks
|
|
376
|
+
*/
|
|
377
|
+
static configureGmail(gmailConfig: GmailHooksConfig): HooksConfig {
|
|
378
|
+
const settings = this.loadSettings();
|
|
379
|
+
settings.gmail = {
|
|
380
|
+
...settings.gmail,
|
|
381
|
+
...gmailConfig,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Auto-add gmail preset if account is configured
|
|
385
|
+
if (gmailConfig.account && !settings.presets.includes('gmail')) {
|
|
386
|
+
settings.presets.push('gmail');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
this.saveSettings(settings);
|
|
390
|
+
return settings;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get Gmail configuration with defaults filled in
|
|
395
|
+
*/
|
|
396
|
+
static getGmailConfig(): GmailHooksConfig {
|
|
397
|
+
const settings = this.loadSettings();
|
|
398
|
+
const gmail = settings.gmail || {};
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
account: gmail.account,
|
|
402
|
+
label: gmail.label || DEFAULT_GMAIL_LABEL,
|
|
403
|
+
topic: gmail.topic || DEFAULT_GMAIL_TOPIC,
|
|
404
|
+
subscription: gmail.subscription || DEFAULT_GMAIL_SUBSCRIPTION,
|
|
405
|
+
pushToken: gmail.pushToken,
|
|
406
|
+
hookUrl: gmail.hookUrl,
|
|
407
|
+
includeBody: gmail.includeBody ?? true,
|
|
408
|
+
maxBytes: gmail.maxBytes || DEFAULT_GMAIL_MAX_BYTES,
|
|
409
|
+
renewEveryMinutes: gmail.renewEveryMinutes || DEFAULT_GMAIL_RENEW_MINUTES,
|
|
410
|
+
model: gmail.model,
|
|
411
|
+
thinking: gmail.thinking,
|
|
412
|
+
allowUnsafeExternalContent: gmail.allowUnsafeExternalContent,
|
|
413
|
+
serve: {
|
|
414
|
+
bind: gmail.serve?.bind || DEFAULT_GMAIL_SERVE_BIND,
|
|
415
|
+
port: gmail.serve?.port || DEFAULT_GMAIL_SERVE_PORT,
|
|
416
|
+
path: gmail.serve?.path || DEFAULT_GMAIL_SERVE_PATH,
|
|
417
|
+
},
|
|
418
|
+
tailscale: {
|
|
419
|
+
mode: gmail.tailscale?.mode || 'off',
|
|
420
|
+
path: gmail.tailscale?.path || DEFAULT_GMAIL_SERVE_PATH,
|
|
421
|
+
target: gmail.tailscale?.target,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Get settings for UI display (masks sensitive data)
|
|
428
|
+
*/
|
|
429
|
+
static getSettingsForDisplay(): HooksConfig {
|
|
430
|
+
const settings = this.loadSettings();
|
|
431
|
+
|
|
432
|
+
return {
|
|
433
|
+
...settings,
|
|
434
|
+
token: settings.token ? MASKED_VALUE : '',
|
|
435
|
+
gmail: settings.gmail ? {
|
|
436
|
+
...settings.gmail,
|
|
437
|
+
pushToken: settings.gmail.pushToken ? MASKED_VALUE : undefined,
|
|
438
|
+
} : undefined,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Check if hooks are properly configured
|
|
444
|
+
*/
|
|
445
|
+
static isConfigured(): boolean {
|
|
446
|
+
const settings = this.loadSettings();
|
|
447
|
+
return settings.enabled && !!settings.token;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Check if Gmail hooks are configured
|
|
452
|
+
*/
|
|
453
|
+
static isGmailConfigured(): boolean {
|
|
454
|
+
const settings = this.loadSettings();
|
|
455
|
+
return !!(settings.gmail?.account && settings.gmail?.topic && settings.gmail?.pushToken);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Ensure the manager is initialized
|
|
460
|
+
*/
|
|
461
|
+
private static ensureInitialized(): void {
|
|
462
|
+
if (!this.initialized) {
|
|
463
|
+
this.initialize();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Configuration Types
|
|
3
|
+
*
|
|
4
|
+
* Webhook ingress for wake and isolated agent runs.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ChannelType } from '../../shared/types';
|
|
8
|
+
|
|
9
|
+
// ============ Hook Configuration ============
|
|
10
|
+
|
|
11
|
+
export interface HooksConfig {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
token: string;
|
|
14
|
+
path: string;
|
|
15
|
+
maxBodyBytes: number;
|
|
16
|
+
presets: string[];
|
|
17
|
+
mappings: HookMappingConfig[];
|
|
18
|
+
transformsDir?: string;
|
|
19
|
+
gmail?: GmailHooksConfig;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface GmailHooksConfig {
|
|
23
|
+
account?: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
topic?: string;
|
|
26
|
+
subscription?: string;
|
|
27
|
+
pushToken?: string;
|
|
28
|
+
hookUrl?: string;
|
|
29
|
+
includeBody?: boolean;
|
|
30
|
+
maxBytes?: number;
|
|
31
|
+
renewEveryMinutes?: number;
|
|
32
|
+
model?: string;
|
|
33
|
+
thinking?: string;
|
|
34
|
+
allowUnsafeExternalContent?: boolean;
|
|
35
|
+
serve?: {
|
|
36
|
+
bind?: string;
|
|
37
|
+
port?: number;
|
|
38
|
+
path?: string;
|
|
39
|
+
};
|
|
40
|
+
tailscale?: {
|
|
41
|
+
mode?: 'off' | 'serve' | 'funnel';
|
|
42
|
+
path?: string;
|
|
43
|
+
target?: string;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ============ Hook Mapping Configuration ============
|
|
48
|
+
|
|
49
|
+
export interface HookMappingConfig {
|
|
50
|
+
id?: string;
|
|
51
|
+
match?: {
|
|
52
|
+
path?: string;
|
|
53
|
+
source?: string;
|
|
54
|
+
};
|
|
55
|
+
action?: 'wake' | 'agent';
|
|
56
|
+
wakeMode?: 'now' | 'next-heartbeat';
|
|
57
|
+
name?: string;
|
|
58
|
+
sessionKey?: string;
|
|
59
|
+
messageTemplate?: string;
|
|
60
|
+
textTemplate?: string;
|
|
61
|
+
deliver?: boolean;
|
|
62
|
+
allowUnsafeExternalContent?: boolean;
|
|
63
|
+
channel?: HookMessageChannel;
|
|
64
|
+
to?: string;
|
|
65
|
+
model?: string;
|
|
66
|
+
thinking?: string;
|
|
67
|
+
timeoutSeconds?: number;
|
|
68
|
+
transform?: {
|
|
69
|
+
module: string;
|
|
70
|
+
export?: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type HookMessageChannel = ChannelType | 'last';
|
|
75
|
+
|
|
76
|
+
// ============ Resolved Hook Mapping ============
|
|
77
|
+
|
|
78
|
+
export interface HookMappingResolved {
|
|
79
|
+
id: string;
|
|
80
|
+
matchPath?: string;
|
|
81
|
+
matchSource?: string;
|
|
82
|
+
action: 'wake' | 'agent';
|
|
83
|
+
wakeMode?: 'now' | 'next-heartbeat';
|
|
84
|
+
name?: string;
|
|
85
|
+
sessionKey?: string;
|
|
86
|
+
messageTemplate?: string;
|
|
87
|
+
textTemplate?: string;
|
|
88
|
+
deliver?: boolean;
|
|
89
|
+
allowUnsafeExternalContent?: boolean;
|
|
90
|
+
channel?: HookMessageChannel;
|
|
91
|
+
to?: string;
|
|
92
|
+
model?: string;
|
|
93
|
+
thinking?: string;
|
|
94
|
+
timeoutSeconds?: number;
|
|
95
|
+
transform?: HookMappingTransformResolved;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface HookMappingTransformResolved {
|
|
99
|
+
modulePath: string;
|
|
100
|
+
exportName?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============ Hook Payloads ============
|
|
104
|
+
|
|
105
|
+
export interface WakeHookPayload {
|
|
106
|
+
text: string;
|
|
107
|
+
mode?: 'now' | 'next-heartbeat';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface AgentHookPayload {
|
|
111
|
+
message: string;
|
|
112
|
+
name?: string;
|
|
113
|
+
sessionKey?: string;
|
|
114
|
+
wakeMode?: 'now' | 'next-heartbeat';
|
|
115
|
+
deliver?: boolean;
|
|
116
|
+
channel?: HookMessageChannel;
|
|
117
|
+
to?: string;
|
|
118
|
+
model?: string;
|
|
119
|
+
thinking?: string;
|
|
120
|
+
timeoutSeconds?: number;
|
|
121
|
+
workspaceId?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ============ Hook Actions ============
|
|
125
|
+
|
|
126
|
+
export type HookAction =
|
|
127
|
+
| {
|
|
128
|
+
kind: 'wake';
|
|
129
|
+
text: string;
|
|
130
|
+
mode: 'now' | 'next-heartbeat';
|
|
131
|
+
}
|
|
132
|
+
| {
|
|
133
|
+
kind: 'agent';
|
|
134
|
+
message: string;
|
|
135
|
+
name?: string;
|
|
136
|
+
wakeMode: 'now' | 'next-heartbeat';
|
|
137
|
+
sessionKey?: string;
|
|
138
|
+
deliver?: boolean;
|
|
139
|
+
allowUnsafeExternalContent?: boolean;
|
|
140
|
+
channel?: HookMessageChannel;
|
|
141
|
+
to?: string;
|
|
142
|
+
model?: string;
|
|
143
|
+
thinking?: string;
|
|
144
|
+
timeoutSeconds?: number;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export type HookMappingResult =
|
|
148
|
+
| { ok: true; action: HookAction }
|
|
149
|
+
| { ok: true; action: null; skipped: true }
|
|
150
|
+
| { ok: false; error: string };
|
|
151
|
+
|
|
152
|
+
// ============ Hook Context ============
|
|
153
|
+
|
|
154
|
+
export interface HookMappingContext {
|
|
155
|
+
payload: Record<string, unknown>;
|
|
156
|
+
headers: Record<string, string>;
|
|
157
|
+
url: URL;
|
|
158
|
+
path: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ============ Resolved Hooks Config ============
|
|
162
|
+
|
|
163
|
+
export interface HooksConfigResolved {
|
|
164
|
+
basePath: string;
|
|
165
|
+
token: string;
|
|
166
|
+
maxBodyBytes: number;
|
|
167
|
+
mappings: HookMappingResolved[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ============ Gmail Runtime Config ============
|
|
171
|
+
|
|
172
|
+
export interface GmailHookRuntimeConfig {
|
|
173
|
+
account: string;
|
|
174
|
+
label: string;
|
|
175
|
+
topic: string;
|
|
176
|
+
subscription: string;
|
|
177
|
+
pushToken: string;
|
|
178
|
+
hookToken: string;
|
|
179
|
+
hookUrl: string;
|
|
180
|
+
includeBody: boolean;
|
|
181
|
+
maxBytes: number;
|
|
182
|
+
renewEveryMinutes: number;
|
|
183
|
+
serve: {
|
|
184
|
+
bind: string;
|
|
185
|
+
port: number;
|
|
186
|
+
path: string;
|
|
187
|
+
};
|
|
188
|
+
tailscale: {
|
|
189
|
+
mode: 'off' | 'serve' | 'funnel';
|
|
190
|
+
path: string;
|
|
191
|
+
target?: string;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ============ Hook Server Events ============
|
|
196
|
+
|
|
197
|
+
export interface HookServerEvent {
|
|
198
|
+
action: 'started' | 'stopped' | 'request' | 'error';
|
|
199
|
+
timestamp: number;
|
|
200
|
+
path?: string;
|
|
201
|
+
method?: string;
|
|
202
|
+
statusCode?: number;
|
|
203
|
+
error?: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============ Default Values ============
|
|
207
|
+
|
|
208
|
+
export const DEFAULT_HOOKS_PATH = '/hooks';
|
|
209
|
+
export const DEFAULT_HOOKS_MAX_BODY_BYTES = 256 * 1024; // 256KB
|
|
210
|
+
export const DEFAULT_HOOKS_PORT = 9877;
|
|
211
|
+
|
|
212
|
+
export const DEFAULT_GMAIL_LABEL = 'INBOX';
|
|
213
|
+
export const DEFAULT_GMAIL_TOPIC = 'cowork-gmail-watch';
|
|
214
|
+
export const DEFAULT_GMAIL_SUBSCRIPTION = 'cowork-gmail-watch-push';
|
|
215
|
+
export const DEFAULT_GMAIL_SERVE_BIND = '127.0.0.1';
|
|
216
|
+
export const DEFAULT_GMAIL_SERVE_PORT = 8788;
|
|
217
|
+
export const DEFAULT_GMAIL_SERVE_PATH = '/gmail-pubsub';
|
|
218
|
+
export const DEFAULT_GMAIL_MAX_BYTES = 20_000;
|
|
219
|
+
export const DEFAULT_GMAIL_RENEW_MINUTES = 12 * 60; // 12 hours
|
|
220
|
+
|
|
221
|
+
export const DEFAULT_HOOKS_CONFIG: HooksConfig = {
|
|
222
|
+
enabled: false,
|
|
223
|
+
token: '',
|
|
224
|
+
path: DEFAULT_HOOKS_PATH,
|
|
225
|
+
maxBodyBytes: DEFAULT_HOOKS_MAX_BODY_BYTES,
|
|
226
|
+
presets: [],
|
|
227
|
+
mappings: [],
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// ============ Gmail Preset Mapping ============
|
|
231
|
+
|
|
232
|
+
export const GMAIL_PRESET_MAPPING: HookMappingConfig = {
|
|
233
|
+
id: 'gmail',
|
|
234
|
+
match: { path: 'gmail' },
|
|
235
|
+
action: 'agent',
|
|
236
|
+
wakeMode: 'now',
|
|
237
|
+
name: 'Gmail',
|
|
238
|
+
sessionKey: 'hook:gmail:{{messages[0].id}}',
|
|
239
|
+
messageTemplate:
|
|
240
|
+
'New email from {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}\n{{messages[0].body}}',
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export const HOOK_PRESET_MAPPINGS: Record<string, HookMappingConfig[]> = {
|
|
244
|
+
gmail: [GMAIL_PRESET_MAPPING],
|
|
245
|
+
};
|