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,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Preload Script
|
|
3
|
+
*
|
|
4
|
+
* Exposes a secure bridge between the canvas content and the main process.
|
|
5
|
+
* This preload script is loaded into canvas BrowserWindows and provides:
|
|
6
|
+
* - A2UI (Agent-to-UI) action sending
|
|
7
|
+
* - Session information retrieval
|
|
8
|
+
* - Agent update notifications
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
12
|
+
|
|
13
|
+
// Type definitions for the canvas API
|
|
14
|
+
interface CanvasAPI {
|
|
15
|
+
/**
|
|
16
|
+
* Send an A2UI action to the agent
|
|
17
|
+
* @param actionName - Name of the action (e.g., 'button_click', 'form_submit')
|
|
18
|
+
* @param componentId - Optional ID of the component that triggered the action
|
|
19
|
+
* @param context - Optional context data to send with the action
|
|
20
|
+
*/
|
|
21
|
+
sendA2UIAction: (
|
|
22
|
+
actionName: string,
|
|
23
|
+
componentId?: string,
|
|
24
|
+
context?: Record<string, unknown>
|
|
25
|
+
) => Promise<void>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get information about the current canvas session
|
|
29
|
+
*/
|
|
30
|
+
getSessionInfo: () => Promise<{
|
|
31
|
+
id: string;
|
|
32
|
+
taskId: string;
|
|
33
|
+
workspaceId: string;
|
|
34
|
+
title?: string;
|
|
35
|
+
} | null>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Register a callback for agent updates
|
|
39
|
+
* @param callback - Function to call when agent sends an update
|
|
40
|
+
*/
|
|
41
|
+
onAgentUpdate: (callback: (data: unknown) => void) => void;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Request a snapshot of the current canvas
|
|
45
|
+
*/
|
|
46
|
+
requestSnapshot: () => Promise<{
|
|
47
|
+
imageBase64: string;
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
} | null>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Log a message to the main process console
|
|
54
|
+
*/
|
|
55
|
+
log: (message: string, data?: unknown) => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Create the canvas API
|
|
59
|
+
const canvasAPI: CanvasAPI = {
|
|
60
|
+
sendA2UIAction: async (actionName, componentId, context) => {
|
|
61
|
+
await ipcRenderer.invoke('canvas:a2ui-action-from-window', {
|
|
62
|
+
actionName,
|
|
63
|
+
componentId,
|
|
64
|
+
context,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
getSessionInfo: async () => {
|
|
69
|
+
return ipcRenderer.invoke('canvas:get-session-from-window');
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
onAgentUpdate: (callback) => {
|
|
73
|
+
ipcRenderer.on('canvas:agent-update', (_event, data) => {
|
|
74
|
+
callback(data);
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
requestSnapshot: async () => {
|
|
79
|
+
return ipcRenderer.invoke('canvas:request-snapshot-from-window');
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
log: (message, data) => {
|
|
83
|
+
ipcRenderer.send('canvas:log', { message, data });
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const shouldExposeCanvasApi = (() => {
|
|
88
|
+
try {
|
|
89
|
+
const location = (globalThis as { location?: { protocol?: string } }).location;
|
|
90
|
+
return location?.protocol === 'canvas:';
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
})();
|
|
95
|
+
|
|
96
|
+
if (shouldExposeCanvasApi) {
|
|
97
|
+
// Expose the API to trusted canvas:// content only
|
|
98
|
+
contextBridge.exposeInMainWorld('coworkCanvas', canvasAPI);
|
|
99
|
+
console.log('[CanvasPreload] Canvas preload script loaded (canvas://)');
|
|
100
|
+
} else {
|
|
101
|
+
console.log('[CanvasPreload] Canvas preload script loaded (no API exposed)');
|
|
102
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Protocol Handler
|
|
3
|
+
*
|
|
4
|
+
* Registers a custom 'canvas://' URL scheme that serves files from
|
|
5
|
+
* canvas session directories to the canvas BrowserWindows.
|
|
6
|
+
*
|
|
7
|
+
* URL Format: canvas://{sessionId}/{filename}
|
|
8
|
+
* Example: canvas://abc123-def456/index.html
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { protocol } from 'electron';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import { CanvasManager } from './canvas-manager';
|
|
15
|
+
|
|
16
|
+
// MIME type mapping
|
|
17
|
+
const MIME_TYPES: Record<string, string> = {
|
|
18
|
+
'.html': 'text/html',
|
|
19
|
+
'.htm': 'text/html',
|
|
20
|
+
'.css': 'text/css',
|
|
21
|
+
'.js': 'application/javascript',
|
|
22
|
+
'.mjs': 'application/javascript',
|
|
23
|
+
'.json': 'application/json',
|
|
24
|
+
'.png': 'image/png',
|
|
25
|
+
'.jpg': 'image/jpeg',
|
|
26
|
+
'.jpeg': 'image/jpeg',
|
|
27
|
+
'.gif': 'image/gif',
|
|
28
|
+
'.svg': 'image/svg+xml',
|
|
29
|
+
'.webp': 'image/webp',
|
|
30
|
+
'.ico': 'image/x-icon',
|
|
31
|
+
'.woff': 'font/woff',
|
|
32
|
+
'.woff2': 'font/woff2',
|
|
33
|
+
'.ttf': 'font/ttf',
|
|
34
|
+
'.otf': 'font/otf',
|
|
35
|
+
'.eot': 'application/vnd.ms-fontobject',
|
|
36
|
+
'.wasm': 'application/wasm',
|
|
37
|
+
'.mp3': 'audio/mpeg',
|
|
38
|
+
'.mp4': 'video/mp4',
|
|
39
|
+
'.webm': 'video/webm',
|
|
40
|
+
'.ogg': 'audio/ogg',
|
|
41
|
+
'.wav': 'audio/wav',
|
|
42
|
+
'.pdf': 'application/pdf',
|
|
43
|
+
'.xml': 'application/xml',
|
|
44
|
+
'.txt': 'text/plain',
|
|
45
|
+
'.md': 'text/markdown',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get MIME type for a file extension
|
|
50
|
+
*/
|
|
51
|
+
function getMimeType(filePath: string): string {
|
|
52
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
53
|
+
return MIME_TYPES[ext] || 'application/octet-stream';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create an error response
|
|
58
|
+
*/
|
|
59
|
+
function createErrorResponse(statusCode: number, message: string): Response {
|
|
60
|
+
return new Response(message, {
|
|
61
|
+
status: statusCode,
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'text/plain',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Register the canvas:// protocol scheme as privileged
|
|
70
|
+
* Must be called before app.ready
|
|
71
|
+
*/
|
|
72
|
+
export function registerCanvasScheme(): void {
|
|
73
|
+
protocol.registerSchemesAsPrivileged([
|
|
74
|
+
{
|
|
75
|
+
scheme: 'canvas',
|
|
76
|
+
privileges: {
|
|
77
|
+
standard: true,
|
|
78
|
+
secure: true,
|
|
79
|
+
supportFetchAPI: true,
|
|
80
|
+
corsEnabled: true,
|
|
81
|
+
stream: true,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Register the canvas:// protocol handler
|
|
89
|
+
* Must be called after app.ready
|
|
90
|
+
*/
|
|
91
|
+
export function registerCanvasProtocol(): void {
|
|
92
|
+
protocol.handle('canvas', async (request) => {
|
|
93
|
+
try {
|
|
94
|
+
const url = new URL(request.url);
|
|
95
|
+
const sessionId = url.hostname;
|
|
96
|
+
let filePath = decodeURIComponent(url.pathname);
|
|
97
|
+
|
|
98
|
+
// Security: prevent path traversal attacks
|
|
99
|
+
if (filePath.includes('..') || filePath.includes('//')) {
|
|
100
|
+
console.warn(`[CanvasProtocol] Blocked path traversal attempt: ${filePath}`);
|
|
101
|
+
return createErrorResponse(403, 'Forbidden: Invalid path');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Get the canvas manager
|
|
105
|
+
const manager = CanvasManager.getInstance();
|
|
106
|
+
const session = manager.getSession(sessionId);
|
|
107
|
+
|
|
108
|
+
if (!session) {
|
|
109
|
+
console.warn(`[CanvasProtocol] Session not found: ${sessionId}`);
|
|
110
|
+
return createErrorResponse(404, 'Session not found');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Default to index.html for root requests
|
|
114
|
+
if (filePath === '/' || filePath === '') {
|
|
115
|
+
filePath = '/index.html';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Remove leading slash
|
|
119
|
+
const relativePath = filePath.startsWith('/') ? filePath.slice(1) : filePath;
|
|
120
|
+
const fullPath = path.join(session.sessionDir, relativePath);
|
|
121
|
+
|
|
122
|
+
// Security: ensure the resolved path is within the session directory
|
|
123
|
+
const resolvedPath = path.resolve(fullPath);
|
|
124
|
+
const resolvedSessionDir = path.resolve(session.sessionDir);
|
|
125
|
+
if (!resolvedPath.startsWith(resolvedSessionDir)) {
|
|
126
|
+
console.warn(`[CanvasProtocol] Path escape attempt: ${fullPath}`);
|
|
127
|
+
return createErrorResponse(403, 'Forbidden: Path outside session');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check if file exists
|
|
131
|
+
if (!fs.existsSync(fullPath)) {
|
|
132
|
+
console.warn(`[CanvasProtocol] File not found: ${fullPath}`);
|
|
133
|
+
return createErrorResponse(404, 'File not found');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Get file stats
|
|
137
|
+
const stats = fs.statSync(fullPath);
|
|
138
|
+
if (stats.isDirectory()) {
|
|
139
|
+
// Try index.html in directory
|
|
140
|
+
const indexPath = path.join(fullPath, 'index.html');
|
|
141
|
+
if (fs.existsSync(indexPath)) {
|
|
142
|
+
const content = fs.readFileSync(indexPath);
|
|
143
|
+
return new Response(content, {
|
|
144
|
+
status: 200,
|
|
145
|
+
headers: {
|
|
146
|
+
'Content-Type': 'text/html',
|
|
147
|
+
'Content-Length': content.length.toString(),
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return createErrorResponse(403, 'Directory listing not allowed');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Read and serve the file
|
|
155
|
+
const content = fs.readFileSync(fullPath);
|
|
156
|
+
const mimeType = getMimeType(fullPath);
|
|
157
|
+
|
|
158
|
+
return new Response(content, {
|
|
159
|
+
status: 200,
|
|
160
|
+
headers: {
|
|
161
|
+
'Content-Type': mimeType,
|
|
162
|
+
'Content-Length': content.length.toString(),
|
|
163
|
+
'Cache-Control': 'no-cache', // Disable caching for development
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
} catch (error: unknown) {
|
|
167
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
168
|
+
console.error('[CanvasProtocol] Error handling request:', error);
|
|
169
|
+
return createErrorResponse(500, `Internal error: ${message}`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
console.log('[CanvasProtocol] Registered canvas:// protocol handler');
|
|
174
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Store - File-based persistence for canvas sessions
|
|
3
|
+
* Uses atomic writes with temporary files for data safety
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { app } from 'electron';
|
|
9
|
+
import type { CanvasSession } from '../../shared/types';
|
|
10
|
+
|
|
11
|
+
export interface CanvasStoreFile {
|
|
12
|
+
version: number;
|
|
13
|
+
sessions: CanvasSession[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Lazy-evaluated paths (app.getPath() is not available until app is ready)
|
|
17
|
+
let _canvasDir: string | null = null;
|
|
18
|
+
let _canvasStorePath: string | null = null;
|
|
19
|
+
|
|
20
|
+
export function getCanvasDir(): string {
|
|
21
|
+
if (!_canvasDir) {
|
|
22
|
+
_canvasDir = path.join(app.getPath('userData'), 'canvas');
|
|
23
|
+
}
|
|
24
|
+
return _canvasDir;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getCanvasStorePath(): string {
|
|
28
|
+
if (!_canvasStorePath) {
|
|
29
|
+
_canvasStorePath = path.join(getCanvasDir(), 'sessions.json');
|
|
30
|
+
}
|
|
31
|
+
return _canvasStorePath;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Maximum sessions to keep (to prevent unbounded growth)
|
|
35
|
+
const MAX_SESSIONS = 50;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validate a single canvas session object
|
|
39
|
+
*/
|
|
40
|
+
function isValidSession(s: unknown): s is CanvasSession {
|
|
41
|
+
if (!s || typeof s !== 'object') return false;
|
|
42
|
+
const session = s as Record<string, unknown>;
|
|
43
|
+
const mode = session.mode;
|
|
44
|
+
const isValidMode = mode === undefined || mode === 'html' || mode === 'browser';
|
|
45
|
+
const url = session.url;
|
|
46
|
+
const isValidUrl = url === undefined || typeof url === 'string';
|
|
47
|
+
return (
|
|
48
|
+
typeof session.id === 'string' &&
|
|
49
|
+
typeof session.taskId === 'string' &&
|
|
50
|
+
typeof session.workspaceId === 'string' &&
|
|
51
|
+
typeof session.sessionDir === 'string' &&
|
|
52
|
+
isValidMode &&
|
|
53
|
+
isValidUrl &&
|
|
54
|
+
typeof session.status === 'string' &&
|
|
55
|
+
['active', 'paused', 'closed'].includes(session.status as string) &&
|
|
56
|
+
typeof session.createdAt === 'number' &&
|
|
57
|
+
typeof session.lastUpdatedAt === 'number'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Load canvas sessions from the store file
|
|
63
|
+
* Returns empty array if file doesn't exist or is invalid
|
|
64
|
+
*/
|
|
65
|
+
export async function loadCanvasStore(storePath?: string): Promise<CanvasStoreFile> {
|
|
66
|
+
const effectivePath = storePath || getCanvasStorePath();
|
|
67
|
+
try {
|
|
68
|
+
const raw = await fs.promises.readFile(effectivePath, 'utf-8');
|
|
69
|
+
const parsed = JSON.parse(raw) as Partial<CanvasStoreFile> | null;
|
|
70
|
+
const sessions = Array.isArray(parsed?.sessions) ? parsed.sessions : [];
|
|
71
|
+
|
|
72
|
+
// Validate and filter sessions
|
|
73
|
+
const validSessions = sessions.filter((s): s is CanvasSession => {
|
|
74
|
+
if (!isValidSession(s)) return false;
|
|
75
|
+
|
|
76
|
+
// Also verify the session directory still exists
|
|
77
|
+
try {
|
|
78
|
+
return fs.existsSync(s.sessionDir);
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
version: 1,
|
|
86
|
+
sessions: validSessions,
|
|
87
|
+
};
|
|
88
|
+
} catch {
|
|
89
|
+
// File doesn't exist or is invalid - return empty store
|
|
90
|
+
return { version: 1, sessions: [] };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Load canvas store synchronously (for initialization)
|
|
96
|
+
*/
|
|
97
|
+
export function loadCanvasStoreSync(storePath?: string): CanvasStoreFile {
|
|
98
|
+
const effectivePath = storePath || getCanvasStorePath();
|
|
99
|
+
try {
|
|
100
|
+
const raw = fs.readFileSync(effectivePath, 'utf-8');
|
|
101
|
+
const parsed = JSON.parse(raw) as Partial<CanvasStoreFile> | null;
|
|
102
|
+
const sessions = Array.isArray(parsed?.sessions) ? parsed.sessions : [];
|
|
103
|
+
|
|
104
|
+
// Validate and filter sessions
|
|
105
|
+
const validSessions = sessions.filter((s): s is CanvasSession => {
|
|
106
|
+
if (!isValidSession(s)) return false;
|
|
107
|
+
|
|
108
|
+
// Also verify the session directory still exists
|
|
109
|
+
try {
|
|
110
|
+
return fs.existsSync(s.sessionDir);
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
version: 1,
|
|
118
|
+
sessions: validSessions,
|
|
119
|
+
};
|
|
120
|
+
} catch {
|
|
121
|
+
return { version: 1, sessions: [] };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Save canvas sessions to the store file
|
|
127
|
+
* Uses atomic writes to prevent data corruption
|
|
128
|
+
*/
|
|
129
|
+
export async function saveCanvasStore(
|
|
130
|
+
store: CanvasStoreFile,
|
|
131
|
+
storePath?: string
|
|
132
|
+
): Promise<void> {
|
|
133
|
+
const effectivePath = storePath || getCanvasStorePath();
|
|
134
|
+
|
|
135
|
+
// Ensure directory exists
|
|
136
|
+
await fs.promises.mkdir(path.dirname(effectivePath), { recursive: true });
|
|
137
|
+
|
|
138
|
+
// Only keep non-closed sessions, and limit to max
|
|
139
|
+
let sessionsToSave = store.sessions.filter(s => s.status !== 'closed');
|
|
140
|
+
|
|
141
|
+
// Trim to max sessions (keep most recent)
|
|
142
|
+
if (sessionsToSave.length > MAX_SESSIONS) {
|
|
143
|
+
sessionsToSave = sessionsToSave
|
|
144
|
+
.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt)
|
|
145
|
+
.slice(0, MAX_SESSIONS);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const storeToSave: CanvasStoreFile = {
|
|
149
|
+
version: 1,
|
|
150
|
+
sessions: sessionsToSave,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Generate temp file path with process ID and random suffix
|
|
154
|
+
const tmp = `${effectivePath}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
155
|
+
|
|
156
|
+
// Write to temp file
|
|
157
|
+
const json = JSON.stringify(storeToSave, null, 2);
|
|
158
|
+
await fs.promises.writeFile(tmp, json, 'utf-8');
|
|
159
|
+
|
|
160
|
+
// Atomic rename
|
|
161
|
+
await fs.promises.rename(tmp, effectivePath);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Save canvas store synchronously
|
|
166
|
+
*/
|
|
167
|
+
export function saveCanvasStoreSync(
|
|
168
|
+
store: CanvasStoreFile,
|
|
169
|
+
storePath?: string
|
|
170
|
+
): void {
|
|
171
|
+
const effectivePath = storePath || getCanvasStorePath();
|
|
172
|
+
|
|
173
|
+
// Ensure directory exists
|
|
174
|
+
fs.mkdirSync(path.dirname(effectivePath), { recursive: true });
|
|
175
|
+
|
|
176
|
+
// Only keep non-closed sessions, and limit to max
|
|
177
|
+
let sessionsToSave = store.sessions.filter(s => s.status !== 'closed');
|
|
178
|
+
|
|
179
|
+
// Trim to max sessions (keep most recent)
|
|
180
|
+
if (sessionsToSave.length > MAX_SESSIONS) {
|
|
181
|
+
sessionsToSave = sessionsToSave
|
|
182
|
+
.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt)
|
|
183
|
+
.slice(0, MAX_SESSIONS);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const storeToSave: CanvasStoreFile = {
|
|
187
|
+
version: 1,
|
|
188
|
+
sessions: sessionsToSave,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Generate temp file path
|
|
192
|
+
const tmp = `${effectivePath}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
193
|
+
|
|
194
|
+
// Write to temp file
|
|
195
|
+
const json = JSON.stringify(storeToSave, null, 2);
|
|
196
|
+
fs.writeFileSync(tmp, json, 'utf-8');
|
|
197
|
+
|
|
198
|
+
// Atomic rename
|
|
199
|
+
fs.renameSync(tmp, effectivePath);
|
|
200
|
+
}
|