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,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Service
|
|
3
|
+
*
|
|
4
|
+
* Core service for the persistent memory system.
|
|
5
|
+
* Handles capture, compression, search, and context injection.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import type { DatabaseManager } from '../database/schema';
|
|
10
|
+
import {
|
|
11
|
+
MemoryRepository,
|
|
12
|
+
MemorySummaryRepository,
|
|
13
|
+
MemorySettingsRepository,
|
|
14
|
+
Memory,
|
|
15
|
+
MemorySettings,
|
|
16
|
+
MemorySearchResult,
|
|
17
|
+
MemoryTimelineEntry,
|
|
18
|
+
MemoryType,
|
|
19
|
+
MemoryStats,
|
|
20
|
+
} from '../database/repositories';
|
|
21
|
+
import { LLMProviderFactory } from '../agent/llm';
|
|
22
|
+
import { estimateTokens } from '../agent/context-manager';
|
|
23
|
+
import { InputSanitizer } from '../agent/security';
|
|
24
|
+
|
|
25
|
+
// Privacy patterns to exclude - matches common sensitive data patterns
|
|
26
|
+
const SENSITIVE_PATTERNS = [
|
|
27
|
+
/api[_-]?key/i,
|
|
28
|
+
/secret/i,
|
|
29
|
+
/password/i,
|
|
30
|
+
/passwd/i,
|
|
31
|
+
/token/i,
|
|
32
|
+
/credential/i,
|
|
33
|
+
/auth/i,
|
|
34
|
+
/bearer\s+[a-zA-Z0-9\-_]+/i,
|
|
35
|
+
/ssh[_-]?key/i,
|
|
36
|
+
/private[_-]?key/i,
|
|
37
|
+
/\.env/i,
|
|
38
|
+
/aws[_-]?access/i,
|
|
39
|
+
/aws[_-]?secret/i,
|
|
40
|
+
/-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/i,
|
|
41
|
+
/ghp_[a-zA-Z0-9]+/i, // GitHub personal access token
|
|
42
|
+
/gho_[a-zA-Z0-9]+/i, // GitHub OAuth token
|
|
43
|
+
/sk-[a-zA-Z0-9]+/i, // OpenAI API key format
|
|
44
|
+
/xox[baprs]-[a-zA-Z0-9-]+/i, // Slack tokens
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Events for reactive updates
|
|
48
|
+
const memoryEvents = new EventEmitter();
|
|
49
|
+
|
|
50
|
+
// Minimum tokens before compression is worthwhile
|
|
51
|
+
const MIN_TOKENS_FOR_COMPRESSION = 100;
|
|
52
|
+
|
|
53
|
+
// Compression batch size
|
|
54
|
+
const COMPRESSION_BATCH_SIZE = 10;
|
|
55
|
+
|
|
56
|
+
// Cleanup interval (1 hour)
|
|
57
|
+
const CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
|
|
58
|
+
|
|
59
|
+
// Compression delay between items (avoid rate limits)
|
|
60
|
+
const COMPRESSION_DELAY_MS = 200;
|
|
61
|
+
|
|
62
|
+
export class MemoryService {
|
|
63
|
+
private static memoryRepo: MemoryRepository;
|
|
64
|
+
private static summaryRepo: MemorySummaryRepository;
|
|
65
|
+
private static settingsRepo: MemorySettingsRepository;
|
|
66
|
+
private static initialized = false;
|
|
67
|
+
private static compressionQueue: string[] = [];
|
|
68
|
+
private static compressionInProgress = false;
|
|
69
|
+
private static cleanupIntervalHandle?: ReturnType<typeof setInterval>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Initialize the memory service
|
|
73
|
+
*/
|
|
74
|
+
static initialize(dbManager: DatabaseManager): void {
|
|
75
|
+
if (this.initialized) return;
|
|
76
|
+
|
|
77
|
+
const db = dbManager.getDatabase();
|
|
78
|
+
this.memoryRepo = new MemoryRepository(db);
|
|
79
|
+
this.summaryRepo = new MemorySummaryRepository(db);
|
|
80
|
+
this.settingsRepo = new MemorySettingsRepository(db);
|
|
81
|
+
this.initialized = true;
|
|
82
|
+
|
|
83
|
+
// Start periodic cleanup
|
|
84
|
+
this.cleanupIntervalHandle = setInterval(() => this.runCleanup(), CLEANUP_INTERVAL_MS);
|
|
85
|
+
|
|
86
|
+
console.log('[MemoryService] Initialized');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Subscribe to memory events
|
|
91
|
+
*/
|
|
92
|
+
static onMemoryChanged(
|
|
93
|
+
callback: (data: { type: string; workspaceId: string }) => void
|
|
94
|
+
): () => void {
|
|
95
|
+
memoryEvents.on('memoryChanged', callback);
|
|
96
|
+
return () => memoryEvents.off('memoryChanged', callback);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Capture an observation from task execution
|
|
101
|
+
*/
|
|
102
|
+
static async capture(
|
|
103
|
+
workspaceId: string,
|
|
104
|
+
taskId: string | undefined,
|
|
105
|
+
type: MemoryType,
|
|
106
|
+
content: string,
|
|
107
|
+
isPrivate = false
|
|
108
|
+
): Promise<Memory | null> {
|
|
109
|
+
this.ensureInitialized();
|
|
110
|
+
|
|
111
|
+
// Check settings
|
|
112
|
+
const settings = this.settingsRepo.getOrCreate(workspaceId);
|
|
113
|
+
if (!settings.enabled || !settings.autoCapture) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check privacy mode
|
|
118
|
+
if (settings.privacyMode === 'disabled') {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check excluded patterns
|
|
123
|
+
if (this.shouldExclude(content, settings)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check for sensitive content
|
|
128
|
+
const containsSensitive = this.containsSensitiveData(content);
|
|
129
|
+
const finalIsPrivate = isPrivate || containsSensitive || settings.privacyMode === 'strict';
|
|
130
|
+
|
|
131
|
+
// Estimate tokens
|
|
132
|
+
const tokens = estimateTokens(content);
|
|
133
|
+
|
|
134
|
+
// Truncate very long content
|
|
135
|
+
const truncatedContent =
|
|
136
|
+
content.length > 10000 ? content.slice(0, 10000) + '\n[... truncated]' : content;
|
|
137
|
+
|
|
138
|
+
// Create memory
|
|
139
|
+
const memory = this.memoryRepo.create({
|
|
140
|
+
workspaceId,
|
|
141
|
+
taskId,
|
|
142
|
+
type,
|
|
143
|
+
content: truncatedContent,
|
|
144
|
+
tokens,
|
|
145
|
+
isCompressed: false,
|
|
146
|
+
isPrivate: finalIsPrivate,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Queue for compression if enabled and large enough
|
|
150
|
+
if (settings.compressionEnabled && tokens > MIN_TOKENS_FOR_COMPRESSION && !finalIsPrivate) {
|
|
151
|
+
this.compressionQueue.push(memory.id);
|
|
152
|
+
this.processCompressionQueue();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Emit event
|
|
156
|
+
memoryEvents.emit('memoryChanged', { type: 'created', workspaceId });
|
|
157
|
+
|
|
158
|
+
return memory;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Search memories - Layer 1 of progressive retrieval
|
|
163
|
+
* Returns IDs + brief snippets (~50 tokens each)
|
|
164
|
+
*/
|
|
165
|
+
static search(workspaceId: string, query: string, limit = 20): MemorySearchResult[] {
|
|
166
|
+
this.ensureInitialized();
|
|
167
|
+
return this.memoryRepo.search(workspaceId, query, limit);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get timeline context - Layer 2 of progressive retrieval
|
|
172
|
+
* Returns surrounding memories for context
|
|
173
|
+
*/
|
|
174
|
+
static getTimelineContext(memoryId: string, windowSize = 5): MemoryTimelineEntry[] {
|
|
175
|
+
this.ensureInitialized();
|
|
176
|
+
return this.memoryRepo.getTimelineContext(memoryId, windowSize);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get full details - Layer 3 of progressive retrieval
|
|
181
|
+
* Only called for specific memories when needed
|
|
182
|
+
*/
|
|
183
|
+
static getFullDetails(ids: string[]): Memory[] {
|
|
184
|
+
this.ensureInitialized();
|
|
185
|
+
return this.memoryRepo.getFullDetails(ids);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get memories for a specific task
|
|
190
|
+
*/
|
|
191
|
+
static getByTask(taskId: string): Memory[] {
|
|
192
|
+
this.ensureInitialized();
|
|
193
|
+
return this.memoryRepo.findByTask(taskId);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get recent memories for a workspace
|
|
198
|
+
*/
|
|
199
|
+
static getRecent(workspaceId: string, limit = 20): Memory[] {
|
|
200
|
+
this.ensureInitialized();
|
|
201
|
+
return this.memoryRepo.getRecentForWorkspace(workspaceId, limit);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get context for injection at task start
|
|
206
|
+
* Returns a formatted string suitable for system prompt
|
|
207
|
+
*/
|
|
208
|
+
static getContextForInjection(workspaceId: string, taskPrompt: string): string {
|
|
209
|
+
this.ensureInitialized();
|
|
210
|
+
|
|
211
|
+
const settings = this.settingsRepo.getOrCreate(workspaceId);
|
|
212
|
+
if (!settings.enabled) {
|
|
213
|
+
return '';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Get recent memories (summaries preferred)
|
|
217
|
+
const recentMemories = this.memoryRepo.getRecentForWorkspace(workspaceId, 5);
|
|
218
|
+
|
|
219
|
+
// Search for relevant memories based on task prompt
|
|
220
|
+
let relevantMemories: MemorySearchResult[] = [];
|
|
221
|
+
if (taskPrompt && taskPrompt.length > 10) {
|
|
222
|
+
try {
|
|
223
|
+
// Extract key terms for search
|
|
224
|
+
const searchTerms = this.extractSearchTerms(taskPrompt);
|
|
225
|
+
if (searchTerms) {
|
|
226
|
+
relevantMemories = this.memoryRepo.search(workspaceId, searchTerms, 5);
|
|
227
|
+
// Filter out memories that are already in recent
|
|
228
|
+
const recentIds = new Set(recentMemories.map((m) => m.id));
|
|
229
|
+
relevantMemories = relevantMemories.filter((m) => !recentIds.has(m.id));
|
|
230
|
+
}
|
|
231
|
+
} catch {
|
|
232
|
+
// Search failed, continue without relevant memories
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (recentMemories.length === 0 && relevantMemories.length === 0) {
|
|
237
|
+
return '';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const parts: string[] = ['<memory_context>'];
|
|
241
|
+
parts.push('The following memories from previous sessions may be relevant:');
|
|
242
|
+
|
|
243
|
+
// Add recent memories (summaries only for token efficiency)
|
|
244
|
+
if (recentMemories.length > 0) {
|
|
245
|
+
parts.push('\n## Recent Activity');
|
|
246
|
+
for (const memory of recentMemories) {
|
|
247
|
+
const rawText = memory.summary || this.truncate(memory.content, 150);
|
|
248
|
+
// Sanitize memory content to prevent injection via stored memories
|
|
249
|
+
const text = InputSanitizer.sanitizeMemoryContent(rawText);
|
|
250
|
+
const date = new Date(memory.createdAt).toLocaleDateString();
|
|
251
|
+
parts.push(`- [${memory.type}] (${date}) ${text}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Add relevant memories
|
|
256
|
+
if (relevantMemories.length > 0) {
|
|
257
|
+
parts.push('\n## Relevant to Current Task');
|
|
258
|
+
for (const result of relevantMemories) {
|
|
259
|
+
const date = new Date(result.createdAt).toLocaleDateString();
|
|
260
|
+
// Sanitize memory content to prevent injection via stored memories
|
|
261
|
+
const sanitizedSnippet = InputSanitizer.sanitizeMemoryContent(result.snippet);
|
|
262
|
+
parts.push(`- [${result.type}] (${date}) ${sanitizedSnippet}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
parts.push('</memory_context>');
|
|
267
|
+
|
|
268
|
+
return parts.join('\n');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get or create settings for a workspace
|
|
273
|
+
*/
|
|
274
|
+
static getSettings(workspaceId: string): MemorySettings {
|
|
275
|
+
this.ensureInitialized();
|
|
276
|
+
return this.settingsRepo.getOrCreate(workspaceId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Update settings for a workspace
|
|
281
|
+
*/
|
|
282
|
+
static updateSettings(
|
|
283
|
+
workspaceId: string,
|
|
284
|
+
updates: Partial<Omit<MemorySettings, 'workspaceId'>>
|
|
285
|
+
): void {
|
|
286
|
+
this.ensureInitialized();
|
|
287
|
+
this.settingsRepo.update(workspaceId, updates);
|
|
288
|
+
memoryEvents.emit('memoryChanged', { type: 'settingsUpdated', workspaceId });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Get storage statistics for a workspace
|
|
293
|
+
*/
|
|
294
|
+
static getStats(workspaceId: string): MemoryStats {
|
|
295
|
+
this.ensureInitialized();
|
|
296
|
+
return this.memoryRepo.getStats(workspaceId);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Delete all memories for a workspace
|
|
301
|
+
*/
|
|
302
|
+
static clearWorkspace(workspaceId: string): void {
|
|
303
|
+
this.ensureInitialized();
|
|
304
|
+
this.memoryRepo.deleteByWorkspace(workspaceId);
|
|
305
|
+
this.summaryRepo.deleteByWorkspace(workspaceId);
|
|
306
|
+
memoryEvents.emit('memoryChanged', { type: 'cleared', workspaceId });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Process compression queue asynchronously
|
|
311
|
+
*/
|
|
312
|
+
private static async processCompressionQueue(): Promise<void> {
|
|
313
|
+
if (this.compressionInProgress || this.compressionQueue.length === 0) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this.compressionInProgress = true;
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
// Process in batches
|
|
321
|
+
const batch = this.compressionQueue.splice(0, COMPRESSION_BATCH_SIZE);
|
|
322
|
+
|
|
323
|
+
for (const memoryId of batch) {
|
|
324
|
+
await this.compressMemory(memoryId);
|
|
325
|
+
// Small delay to avoid overwhelming the LLM
|
|
326
|
+
await new Promise((resolve) => setTimeout(resolve, COMPRESSION_DELAY_MS));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Continue if more items
|
|
330
|
+
if (this.compressionQueue.length > 0) {
|
|
331
|
+
setTimeout(() => this.processCompressionQueue(), 1000);
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error('[MemoryService] Compression queue error:', error);
|
|
335
|
+
} finally {
|
|
336
|
+
this.compressionInProgress = false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Compress a single memory using LLM
|
|
342
|
+
*/
|
|
343
|
+
private static async compressMemory(memoryId: string): Promise<void> {
|
|
344
|
+
const memory = this.memoryRepo.findById(memoryId);
|
|
345
|
+
if (!memory || memory.isCompressed || memory.summary) return;
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
// Get LLM provider for compression
|
|
349
|
+
const provider = LLMProviderFactory.createProvider();
|
|
350
|
+
const settings = LLMProviderFactory.getSettings();
|
|
351
|
+
const modelId = LLMProviderFactory.getModelId(
|
|
352
|
+
settings.modelKey,
|
|
353
|
+
settings.providerType,
|
|
354
|
+
settings.ollama?.model,
|
|
355
|
+
settings.gemini?.model,
|
|
356
|
+
settings.openrouter?.model,
|
|
357
|
+
settings.openai?.model
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const response = await provider.createMessage({
|
|
361
|
+
model: modelId,
|
|
362
|
+
maxTokens: 100,
|
|
363
|
+
system: 'You are a helpful assistant that summarizes text concisely.',
|
|
364
|
+
messages: [
|
|
365
|
+
{
|
|
366
|
+
role: 'user',
|
|
367
|
+
content: `Summarize this observation in 1-2 sentences (max 50 words). Focus on the key insight, decision, or action taken. Be concise and factual.
|
|
368
|
+
|
|
369
|
+
Observation:
|
|
370
|
+
${memory.content}
|
|
371
|
+
|
|
372
|
+
Summary:`,
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Extract summary from response
|
|
378
|
+
let summary = '';
|
|
379
|
+
for (const content of response.content) {
|
|
380
|
+
if (content.type === 'text') {
|
|
381
|
+
summary += content.text;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
summary = summary.trim();
|
|
385
|
+
|
|
386
|
+
if (summary) {
|
|
387
|
+
const summaryTokens = estimateTokens(summary);
|
|
388
|
+
this.memoryRepo.update(memoryId, {
|
|
389
|
+
summary,
|
|
390
|
+
tokens: summaryTokens,
|
|
391
|
+
isCompressed: true,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
} catch (error) {
|
|
395
|
+
// Log but don't fail - compression is optional enhancement
|
|
396
|
+
console.warn('[MemoryService] Compression failed for memory:', memoryId, error);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Run periodic cleanup based on retention policies
|
|
402
|
+
*/
|
|
403
|
+
private static async runCleanup(): Promise<void> {
|
|
404
|
+
if (!this.initialized) return;
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
// Get all workspaces with memories
|
|
408
|
+
const workspacesWithMemories = new Set<string>();
|
|
409
|
+
|
|
410
|
+
// Find unique workspace IDs from recent memories
|
|
411
|
+
const recentMemories = this.memoryRepo.getUncompressed(1000);
|
|
412
|
+
for (const memory of recentMemories) {
|
|
413
|
+
workspacesWithMemories.add(memory.workspaceId);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Process each workspace
|
|
417
|
+
for (const workspaceId of workspacesWithMemories) {
|
|
418
|
+
const settings = this.settingsRepo.getOrCreate(workspaceId);
|
|
419
|
+
const retentionMs = settings.retentionDays * 24 * 60 * 60 * 1000;
|
|
420
|
+
const cutoff = Date.now() - retentionMs;
|
|
421
|
+
|
|
422
|
+
const deleted = this.memoryRepo.deleteOlderThan(workspaceId, cutoff);
|
|
423
|
+
if (deleted > 0) {
|
|
424
|
+
console.log(`[MemoryService] Cleaned up ${deleted} old memories for workspace ${workspaceId}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error('[MemoryService] Cleanup failed:', error);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Extract search terms from task prompt
|
|
434
|
+
*/
|
|
435
|
+
private static extractSearchTerms(prompt: string): string {
|
|
436
|
+
// Remove common words and extract meaningful terms
|
|
437
|
+
const stopWords = new Set([
|
|
438
|
+
'a', 'an', 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
439
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
440
|
+
'should', 'may', 'might', 'can', 'must', 'shall', 'to', 'of', 'in',
|
|
441
|
+
'for', 'on', 'with', 'at', 'by', 'from', 'up', 'about', 'into',
|
|
442
|
+
'over', 'after', 'beneath', 'under', 'above', 'and', 'or', 'but',
|
|
443
|
+
'if', 'then', 'else', 'when', 'where', 'why', 'how', 'all', 'each',
|
|
444
|
+
'every', 'both', 'few', 'more', 'most', 'other', 'some', 'such',
|
|
445
|
+
'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too',
|
|
446
|
+
'very', 'just', 'also', 'now', 'please', 'help', 'me', 'i', 'my',
|
|
447
|
+
'want', 'need', 'like', 'make', 'create', 'add', 'update', 'fix',
|
|
448
|
+
]);
|
|
449
|
+
|
|
450
|
+
const words = prompt
|
|
451
|
+
.toLowerCase()
|
|
452
|
+
.replace(/[^\w\s]/g, ' ')
|
|
453
|
+
.split(/\s+/)
|
|
454
|
+
.filter((word) => word.length > 2 && !stopWords.has(word));
|
|
455
|
+
|
|
456
|
+
// Take first 5 meaningful words for search
|
|
457
|
+
return words.slice(0, 5).join(' OR ');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Check if content should be excluded
|
|
462
|
+
*/
|
|
463
|
+
private static shouldExclude(content: string, settings: MemorySettings): boolean {
|
|
464
|
+
if (!settings.excludedPatterns || settings.excludedPatterns.length === 0) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
for (const pattern of settings.excludedPatterns) {
|
|
469
|
+
try {
|
|
470
|
+
const regex = new RegExp(pattern, 'i');
|
|
471
|
+
if (regex.test(content)) {
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
// Invalid regex pattern, skip
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Check if content contains sensitive data
|
|
484
|
+
*/
|
|
485
|
+
private static containsSensitiveData(content: string): boolean {
|
|
486
|
+
for (const pattern of SENSITIVE_PATTERNS) {
|
|
487
|
+
if (pattern.test(content)) {
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Truncate text to specified length
|
|
496
|
+
*/
|
|
497
|
+
private static truncate(text: string, maxLength: number): string {
|
|
498
|
+
if (text.length <= maxLength) return text;
|
|
499
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Ensure service is initialized
|
|
504
|
+
*/
|
|
505
|
+
private static ensureInitialized(): void {
|
|
506
|
+
if (!this.initialized) {
|
|
507
|
+
throw new Error('[MemoryService] Not initialized. Call MemoryService.initialize() first.');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Shutdown the service
|
|
513
|
+
*/
|
|
514
|
+
static shutdown(): void {
|
|
515
|
+
if (this.cleanupIntervalHandle) {
|
|
516
|
+
clearInterval(this.cleanupIntervalHandle);
|
|
517
|
+
this.cleanupIntervalHandle = undefined;
|
|
518
|
+
}
|
|
519
|
+
memoryEvents.removeAllListeners();
|
|
520
|
+
this.initialized = false;
|
|
521
|
+
console.log('[MemoryService] Shutdown complete');
|
|
522
|
+
}
|
|
523
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { NotificationService } from './service';
|
|
6
|
+
export type { NotificationEvent, NotificationEventType, NotificationServiceConfig } from './service';
|
|
7
|
+
export {
|
|
8
|
+
loadNotificationStore,
|
|
9
|
+
loadNotificationStoreSync,
|
|
10
|
+
saveNotificationStore,
|
|
11
|
+
saveNotificationStoreSync,
|
|
12
|
+
getNotificationStorePath,
|
|
13
|
+
getNotificationDir,
|
|
14
|
+
DEFAULT_NOTIFICATION_STORE_PATH,
|
|
15
|
+
DEFAULT_NOTIFICATION_DIR,
|
|
16
|
+
} from './store';
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification Service - Manages in-app notifications
|
|
3
|
+
* Provides CRUD operations and emits events for UI updates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import type { AppNotification, NotificationType, NotificationStoreFile } from '../../shared/types';
|
|
8
|
+
import {
|
|
9
|
+
loadNotificationStore,
|
|
10
|
+
loadNotificationStoreSync,
|
|
11
|
+
saveNotificationStore,
|
|
12
|
+
getNotificationStorePath,
|
|
13
|
+
} from './store';
|
|
14
|
+
|
|
15
|
+
export type NotificationEventType = 'added' | 'updated' | 'removed' | 'cleared';
|
|
16
|
+
|
|
17
|
+
export interface NotificationEvent {
|
|
18
|
+
type: NotificationEventType;
|
|
19
|
+
notification?: AppNotification;
|
|
20
|
+
notifications?: AppNotification[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface NotificationServiceConfig {
|
|
24
|
+
storePath?: string;
|
|
25
|
+
onEvent?: (event: NotificationEvent) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class NotificationService {
|
|
29
|
+
private notifications: AppNotification[] = [];
|
|
30
|
+
private storePath: string;
|
|
31
|
+
private onEvent?: (event: NotificationEvent) => void;
|
|
32
|
+
|
|
33
|
+
constructor(config: NotificationServiceConfig = {}) {
|
|
34
|
+
this.storePath = config.storePath || getNotificationStorePath();
|
|
35
|
+
this.onEvent = config.onEvent;
|
|
36
|
+
|
|
37
|
+
// Load notifications synchronously on startup
|
|
38
|
+
const store = loadNotificationStoreSync(this.storePath);
|
|
39
|
+
this.notifications = store.notifications;
|
|
40
|
+
console.log(`[Notifications] Loaded ${this.notifications.length} notifications from store`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get all notifications (sorted by date, newest first)
|
|
45
|
+
*/
|
|
46
|
+
list(): AppNotification[] {
|
|
47
|
+
return [...this.notifications].sort((a, b) => b.createdAt - a.createdAt);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get unread count
|
|
52
|
+
*/
|
|
53
|
+
getUnreadCount(): number {
|
|
54
|
+
return this.notifications.filter((n) => !n.read).length;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Add a new notification
|
|
59
|
+
*/
|
|
60
|
+
async add(params: {
|
|
61
|
+
type: NotificationType;
|
|
62
|
+
title: string;
|
|
63
|
+
message: string;
|
|
64
|
+
taskId?: string;
|
|
65
|
+
cronJobId?: string;
|
|
66
|
+
workspaceId?: string;
|
|
67
|
+
}): Promise<AppNotification> {
|
|
68
|
+
const notification: AppNotification = {
|
|
69
|
+
id: randomUUID(),
|
|
70
|
+
type: params.type,
|
|
71
|
+
title: params.title,
|
|
72
|
+
message: params.message,
|
|
73
|
+
read: false,
|
|
74
|
+
createdAt: Date.now(),
|
|
75
|
+
taskId: params.taskId,
|
|
76
|
+
cronJobId: params.cronJobId,
|
|
77
|
+
workspaceId: params.workspaceId,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
this.notifications.unshift(notification);
|
|
81
|
+
await this.save();
|
|
82
|
+
|
|
83
|
+
this.emit({ type: 'added', notification });
|
|
84
|
+
return notification;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Mark a notification as read
|
|
89
|
+
*/
|
|
90
|
+
async markRead(id: string): Promise<AppNotification | null> {
|
|
91
|
+
const notification = this.notifications.find((n) => n.id === id);
|
|
92
|
+
if (!notification) return null;
|
|
93
|
+
|
|
94
|
+
notification.read = true;
|
|
95
|
+
await this.save();
|
|
96
|
+
|
|
97
|
+
this.emit({ type: 'updated', notification });
|
|
98
|
+
return notification;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Mark all notifications as read
|
|
103
|
+
*/
|
|
104
|
+
async markAllRead(): Promise<void> {
|
|
105
|
+
const unread = this.notifications.filter((n) => !n.read);
|
|
106
|
+
if (unread.length === 0) return;
|
|
107
|
+
|
|
108
|
+
for (const n of unread) {
|
|
109
|
+
n.read = true;
|
|
110
|
+
}
|
|
111
|
+
await this.save();
|
|
112
|
+
|
|
113
|
+
this.emit({ type: 'updated', notifications: this.notifications });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Delete a notification
|
|
118
|
+
*/
|
|
119
|
+
async delete(id: string): Promise<boolean> {
|
|
120
|
+
const index = this.notifications.findIndex((n) => n.id === id);
|
|
121
|
+
if (index === -1) return false;
|
|
122
|
+
|
|
123
|
+
const [removed] = this.notifications.splice(index, 1);
|
|
124
|
+
await this.save();
|
|
125
|
+
|
|
126
|
+
this.emit({ type: 'removed', notification: removed });
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Delete all notifications
|
|
132
|
+
*/
|
|
133
|
+
async deleteAll(): Promise<void> {
|
|
134
|
+
if (this.notifications.length === 0) return;
|
|
135
|
+
|
|
136
|
+
this.notifications = [];
|
|
137
|
+
await this.save();
|
|
138
|
+
|
|
139
|
+
this.emit({ type: 'cleared' });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Save notifications to disk
|
|
144
|
+
*/
|
|
145
|
+
private async save(): Promise<void> {
|
|
146
|
+
const store: NotificationStoreFile = {
|
|
147
|
+
version: 1,
|
|
148
|
+
notifications: this.notifications,
|
|
149
|
+
};
|
|
150
|
+
await saveNotificationStore(store, this.storePath);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Emit an event to listeners
|
|
155
|
+
*/
|
|
156
|
+
private emit(event: NotificationEvent): void {
|
|
157
|
+
if (this.onEvent) {
|
|
158
|
+
this.onEvent(event);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|