@theowlops/boombot 0.0.0-stage → 1.1.1
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/README.md +69 -3
- package/dist/LICENSE +21 -0
- package/dist/bin/boombot.js +16 -0
- package/dist/cli/api-key.js +123 -0
- package/dist/cli/bin-bun.js +17 -0
- package/dist/cli/bin.js +34 -0
- package/dist/cli/cli/cli-error.js +61 -0
- package/dist/cli/cli/dispatch.js +138 -0
- package/dist/cli/cli/help.js +83 -0
- package/dist/cli/cli/parser.js +89 -0
- package/dist/cli/cli/registry.js +185 -0
- package/dist/cli/cli/spec.js +41 -0
- package/dist/cli/cli/suggest.js +125 -0
- package/dist/cli/cli/version.js +30 -0
- package/dist/cli/cli/vocabulary.js +87 -0
- package/dist/cli/commands/doctor.js +365 -0
- package/dist/cli/commands/gateway.js +290 -0
- package/dist/cli/commands/migrate.js +270 -0
- package/dist/cli/commands/plugin.js +97 -0
- package/dist/cli/commands/setup.js +244 -0
- package/dist/cli/config-file.js +133 -0
- package/dist/cli/master-key.js +78 -0
- package/dist/cli/open-browser.js +59 -0
- package/dist/cli/web-assets.js +58 -0
- package/dist/gateway/auth.js +46 -0
- package/dist/gateway/config-format.js +202 -0
- package/dist/gateway/config.js +427 -0
- package/dist/gateway/context.js +1 -0
- package/dist/gateway/env-file.js +129 -0
- package/dist/gateway/events.js +172 -0
- package/dist/gateway/guard/tagging.js +505 -0
- package/dist/gateway/handlers/index.js +66 -0
- package/dist/gateway/handlers/memory.js +54 -0
- package/dist/gateway/handlers/providers.js +73 -0
- package/dist/gateway/handlers/registry.js +39 -0
- package/dist/gateway/handlers/sessions.js +188 -0
- package/dist/gateway/handlers/system.js +12 -0
- package/dist/gateway/handlers/tasks.js +191 -0
- package/dist/gateway/handlers/turn.js +100 -0
- package/dist/gateway/index.js +126 -0
- package/dist/gateway/main.js +23 -0
- package/dist/gateway/server.js +354 -0
- package/dist/gateway/services/context-limits.js +75 -0
- package/dist/gateway/services/history-normalizer.js +42 -0
- package/dist/gateway/services/image-pipeline.js +56 -0
- package/dist/gateway/services/key-roulette-client.js +43 -0
- package/dist/gateway/services/llm-client.js +593 -0
- package/dist/gateway/services/llm-decoder.js +200 -0
- package/dist/gateway/services/local-fallback.js +135 -0
- package/dist/gateway/services/memory.js +511 -0
- package/dist/gateway/services/persistent-memory.js +196 -0
- package/dist/gateway/services/providers.js +44 -0
- package/dist/gateway/services/tasks.js +237 -0
- package/dist/gateway/services/verification.js +124 -0
- package/dist/gateway/services/vision-payload.js +48 -0
- package/dist/gateway/services.js +257 -0
- package/dist/gateway/session-snapshot.js +19 -0
- package/dist/gateway/sessions.js +701 -0
- package/dist/gateway/static.js +239 -0
- package/dist/gateway/turns/clarify-tool.js +57 -0
- package/dist/gateway/turns/cronjob-tool.js +96 -0
- package/dist/gateway/turns/deferred-tools.js +154 -0
- package/dist/gateway/turns/execute-code-tool.js +84 -0
- package/dist/gateway/turns/file-tool-defs.js +178 -0
- package/dist/gateway/turns/file-tool-ops.js +178 -0
- package/dist/gateway/turns/file-tool-scan.js +182 -0
- package/dist/gateway/turns/file-tool.js +302 -0
- package/dist/gateway/turns/index.js +416 -0
- package/dist/gateway/turns/jev-middleware.js +91 -0
- package/dist/gateway/turns/local-reply.js +156 -0
- package/dist/gateway/turns/mcp-client.js +643 -0
- package/dist/gateway/turns/memory-tool.js +171 -0
- package/dist/gateway/turns/middleware.js +96 -0
- package/dist/gateway/turns/python-core.js +397 -0
- package/dist/gateway/turns/routing/index.js +3 -0
- package/dist/gateway/turns/routing/intent-classifier.js +60 -0
- package/dist/gateway/turns/routing/planner-adapter.js +91 -0
- package/dist/gateway/turns/routing/types.js +1 -0
- package/dist/gateway/turns/runtime-deps.js +228 -0
- package/dist/gateway/turns/self-config-tool.js +277 -0
- package/dist/gateway/turns/service-types.js +11 -0
- package/dist/gateway/turns/service.js +820 -0
- package/dist/gateway/turns/session-adapter.js +158 -0
- package/dist/gateway/turns/session-tool.js +49 -0
- package/dist/gateway/turns/shell-tool.js +190 -0
- package/dist/gateway/turns/skill-tool.js +239 -0
- package/dist/gateway/turns/spillover.js +201 -0
- package/dist/gateway/turns/subagent-tool.js +140 -0
- package/dist/gateway/turns/system-prompt.js +121 -0
- package/dist/gateway/turns/tool-schema.js +90 -0
- package/dist/gateway/turns/turn-utils.js +58 -0
- package/dist/gateway/turns/vision-tool.js +120 -0
- package/dist/gateway/types.js +1 -0
- package/dist/native/win32-x64/boombot-native-host.exe +0 -0
- package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
- package/dist/node_modules/@boombot/channels/handlers.js +109 -0
- package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
- package/dist/node_modules/@boombot/channels/index.js +12 -0
- package/dist/node_modules/@boombot/channels/package.json +9 -0
- package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
- package/dist/node_modules/@boombot/channels/service.js +608 -0
- package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
- package/dist/node_modules/@boombot/channels/tool.js +46 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
- package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
- package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
- package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
- package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
- package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
- package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
- package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
- package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
- package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
- package/dist/node_modules/@boombot/core/index.d.ts +9 -0
- package/dist/node_modules/@boombot/core/index.js +9 -0
- package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/jev/index.js +2 -0
- package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
- package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
- package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
- package/dist/node_modules/@boombot/core/jev/types.js +1 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
- package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
- package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
- package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
- package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
- package/dist/node_modules/@boombot/core/memory/index.js +23 -0
- package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
- package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
- package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
- package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
- package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
- package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
- package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
- package/dist/node_modules/@boombot/core/memory/search.js +158 -0
- package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
- package/dist/node_modules/@boombot/core/memory/store.js +289 -0
- package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
- package/dist/node_modules/@boombot/core/memory/types.js +21 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
- package/dist/node_modules/@boombot/core/package.json +9 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
- package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
- package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
- package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/config.js +206 -0
- package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
- package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
- package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
- package/dist/node_modules/@boombot/core/research/factory.js +46 -0
- package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
- package/dist/node_modules/@boombot/core/research/http.js +250 -0
- package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/index.js +10 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
- package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
- package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
- package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
- package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
- package/dist/node_modules/@boombot/core/research/tools.js +251 -0
- package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
- package/dist/node_modules/@boombot/core/research/types.js +8 -0
- package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
- package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
- package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
- package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
- package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
- package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
- package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
- package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
- package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
- package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
- package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
- package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
- package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
- package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
- package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
- package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
- package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
- package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
- package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
- package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
- package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
- package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
- package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
- package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
- package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
- package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
- package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
- package/dist/node_modules/@boombot/plugins/index.js +2 -0
- package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
- package/dist/node_modules/@boombot/plugins/installer.js +487 -0
- package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
- package/dist/node_modules/@boombot/plugins/manager.js +243 -0
- package/dist/node_modules/@boombot/plugins/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
- package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
- package/dist/node_modules/@boombot/protocol/index.js +3 -0
- package/dist/node_modules/@boombot/protocol/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
- package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
- package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
- package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
- package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
- package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
- package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
- package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/index.js +13 -0
- package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
- package/dist/node_modules/@boombot/sandbox/native.js +224 -0
- package/dist/node_modules/@boombot/sandbox/package.json +9 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
- package/dist/node_modules/@boombot/security/index.d.ts +5 -0
- package/dist/node_modules/@boombot/security/index.js +9 -0
- package/dist/node_modules/@boombot/security/package.json +9 -0
- package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
- package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
- package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
- package/dist/node_modules/@boombot/security/security/approval.js +140 -0
- package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
- package/dist/node_modules/@boombot/security/security/audit.js +70 -0
- package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
- package/dist/node_modules/@boombot/security/security/index.js +12 -0
- package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
- package/dist/node_modules/@boombot/security/security/trust.js +87 -0
- package/dist/package.json +5 -0
- package/dist/proto/agent_core.proto +56 -0
- package/dist/python/agent-core-python/pyproject.toml +40 -0
- package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
- package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
- package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
- package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
- package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
- package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
- package/dist/python/agent-core-python/uv.lock +2856 -0
- package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
- package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
- package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
- package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
- package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
- package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
- package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
- package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
- package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
- package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
- package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
- package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
- package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
- package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
- package/dist/web/assets/index-BL8bi7Yt.css +1 -0
- package/dist/web/assets/index-CuPR73Tn.js +73 -0
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +26 -0
- package/dist/web/logo.jpg +0 -0
- package/dist/web/logo.png +0 -0
- package/package.json +51 -4
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { principalScope } from './provider.js';
|
|
2
|
+
import { GLOBAL_SCOPE } from './types.js';
|
|
3
|
+
export function conversationScope(channel, chatId) {
|
|
4
|
+
return { kind: 'conversation', id: `${channel}:${chatId}` };
|
|
5
|
+
}
|
|
6
|
+
export function groupScope(groupName) {
|
|
7
|
+
return { kind: 'group', id: groupName };
|
|
8
|
+
}
|
|
9
|
+
export class ScopeResolver {
|
|
10
|
+
/**
|
|
11
|
+
* Resolve scopes visible to this turn:
|
|
12
|
+
* - Global scope (public facts)
|
|
13
|
+
* - Principal scope (the local agent)
|
|
14
|
+
* - Sender scope (if user authenticated)
|
|
15
|
+
* - Group scope (if group assigned)
|
|
16
|
+
* - Conversation scope (channel + chatId)
|
|
17
|
+
*/
|
|
18
|
+
resolveReadableScopes(ctx, principalId) {
|
|
19
|
+
const scopes = [GLOBAL_SCOPE, principalScope(principalId)];
|
|
20
|
+
if (ctx.senderId) {
|
|
21
|
+
scopes.push(principalScope(ctx.senderId));
|
|
22
|
+
}
|
|
23
|
+
if (ctx.group) {
|
|
24
|
+
scopes.push(groupScope(ctx.group));
|
|
25
|
+
}
|
|
26
|
+
if (ctx.channel && ctx.chatId) {
|
|
27
|
+
scopes.push(conversationScope(ctx.channel, ctx.chatId));
|
|
28
|
+
}
|
|
29
|
+
else if (ctx.channel) {
|
|
30
|
+
scopes.push(principalScope(`channel:${ctx.channel}`));
|
|
31
|
+
}
|
|
32
|
+
return Object.freeze(scopes);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Determine target scope for writing a new memory note.
|
|
36
|
+
* Default rule: narrowest scope first (conversation > group > sender > channel).
|
|
37
|
+
* Global scope is strictly reserved for operators.
|
|
38
|
+
*/
|
|
39
|
+
resolveWritableScope(ctx, requestedScope) {
|
|
40
|
+
if (requestedScope?.kind === 'global') {
|
|
41
|
+
if (ctx.isOperator === true) {
|
|
42
|
+
return GLOBAL_SCOPE;
|
|
43
|
+
}
|
|
44
|
+
// Non-operator requesting global is demoted to narrowest scope
|
|
45
|
+
}
|
|
46
|
+
if (ctx.channel && ctx.chatId) {
|
|
47
|
+
return conversationScope(ctx.channel, ctx.chatId);
|
|
48
|
+
}
|
|
49
|
+
if (ctx.group) {
|
|
50
|
+
return groupScope(ctx.group);
|
|
51
|
+
}
|
|
52
|
+
if (ctx.senderId) {
|
|
53
|
+
return principalScope(ctx.senderId);
|
|
54
|
+
}
|
|
55
|
+
if (ctx.channel) {
|
|
56
|
+
return principalScope(`channel:${ctx.channel}`);
|
|
57
|
+
}
|
|
58
|
+
return GLOBAL_SCOPE;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type MemoryStore } from './store.js';
|
|
2
|
+
import { type MatchMode, type SearchHit, type SearchOptions } from './types.js';
|
|
3
|
+
/** Default snippet markers: visible, and NOT html (no XSS vector). */
|
|
4
|
+
export declare const DEFAULT_HIGHLIGHT_START = "\u27E8";
|
|
5
|
+
export declare const DEFAULT_HIGHLIGHT_END = "\u27E9";
|
|
6
|
+
/**
|
|
7
|
+
* Reduce raw input to safe search terms. Throws on empty / overlong input.
|
|
8
|
+
* This is the single choke point between user input and the FTS engine.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractTerms(rawQuery: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Build a safe FTS5 MATCH expression from sanitized terms.
|
|
13
|
+
* Each term becomes a quoted prefix phrase: `"term"*`.
|
|
14
|
+
* Terms are guaranteed `[\p{L}\p{N}]+`, so no quoting/escaping is needed and
|
|
15
|
+
* no FTS5 syntax can be smuggled in.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildSafeMatchQuery(rawQuery: string, match?: MatchMode): string;
|
|
18
|
+
export interface PrincipalSearchOptions {
|
|
19
|
+
query: string;
|
|
20
|
+
limit?: number;
|
|
21
|
+
match?: MatchMode;
|
|
22
|
+
highlightStart?: string;
|
|
23
|
+
highlightEnd?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convenience wrapper that composes the only scopes a principal may ever
|
|
27
|
+
* see: their own principal scope plus the shared global scope. Hosts should
|
|
28
|
+
* prefer this (or `recallMemory` with a derived `MemoryAuthorization`) over
|
|
29
|
+
* hand-rolling scope lists.
|
|
30
|
+
*/
|
|
31
|
+
export declare function searchForPrincipal(store: MemoryStore, principalId: string, options: PrincipalSearchOptions): SearchHit[];
|
|
32
|
+
/**
|
|
33
|
+
* Full-text search restricted to the given authorized scopes.
|
|
34
|
+
* Ranking: FTS5 bm25 (lower = more relevant), tie-broken by
|
|
35
|
+
* created_at DESC, id ASC — deterministic for identical committed state.
|
|
36
|
+
*/
|
|
37
|
+
export declare function search(store: MemoryStore, options: SearchOptions): SearchHit[];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoped full-text search over the FTS5 index.
|
|
3
|
+
*
|
|
4
|
+
* SECURITY MODEL
|
|
5
|
+
* --------------
|
|
6
|
+
* 1. The raw user query NEVER reaches `MATCH`. `extractTerms()` reduces input
|
|
7
|
+
* to unicode letter/number tokens; `buildSafeMatchQuery()` re-assembles a
|
|
8
|
+
* phrase/prefix query from those tokens only. FTS5 metacharacters (`*`,
|
|
9
|
+
* `"`, `:`, `OR`/`AND`/`NOT`/`NEAR`, column filters like `text:`, braces)
|
|
10
|
+
* cannot survive tokenization, so injection is neutralized by construction.
|
|
11
|
+
* 2. Every query carries an explicit, host-authorized scope list. Results are
|
|
12
|
+
* restricted to the union of those scopes — a principal can never observe
|
|
13
|
+
* another principal's records, even with a matching query.
|
|
14
|
+
* 3. Tombstoned rows are excluded twice: the sync triggers keep them out of
|
|
15
|
+
* the FTS index, and the query predicate filters them again (defense in
|
|
16
|
+
* depth against a corrupt/manual index rebuild).
|
|
17
|
+
* 4. Resource bounds: query length, term count, and result limit are capped.
|
|
18
|
+
* 5. TIMING EXISTENCE ORACLE (low, ACCEPTED RISK — documented, not fixed):
|
|
19
|
+
* SQLite evaluates the FTS5 MATCH (posting-list traversal over the whole
|
|
20
|
+
* index) BEFORE the scope predicate. A term matching an OUT-OF-SCOPE
|
|
21
|
+
* record therefore costs slightly more (~28µs measured on 2k records)
|
|
22
|
+
* than a term matching nothing, so a caller with direct search access, a
|
|
23
|
+
* high-resolution clock, and thousands of samples can distinguish "term
|
|
24
|
+
* exists somewhere out of scope" from "term exists nowhere".
|
|
25
|
+
* Why not fixed structurally:
|
|
26
|
+
* - A "two-phase" query (scope-restricted rowid set first, then MATCH
|
|
27
|
+
* constrained to it) does NOT remove the signal: the FTS engine still
|
|
28
|
+
* traverses the posting list for the term before the rowid filter
|
|
29
|
+
* applies, so the per-match FTS work — the source of the delta — is
|
|
30
|
+
* unchanged. It only adds a second query's worth of noise.
|
|
31
|
+
* - Constant-time FTS is not achievable: match cost inherently depends on
|
|
32
|
+
* posting-list length.
|
|
33
|
+
* - Snippet/bm25 are already computed ONLY for rows passing the scope
|
|
34
|
+
* predicate (WHERE filters before SELECT evaluation), so the residual
|
|
35
|
+
* delta is FTS-internals only.
|
|
36
|
+
* Exploitability remains LOW: single-shot measurements are
|
|
37
|
+
* indistinguishable (asserted by test); only statistical sampling over
|
|
38
|
+
* thousands of interleaved queries leaks existence (never content), and
|
|
39
|
+
* only to a caller the host already granted direct search access.
|
|
40
|
+
*/
|
|
41
|
+
import {} from 'node:sqlite';
|
|
42
|
+
import { validationError } from './errors.js';
|
|
43
|
+
import { validateScope } from './store.js';
|
|
44
|
+
import { GLOBAL_SCOPE, MAX_QUERY_CHARS, MAX_QUERY_TERMS, MAX_SEARCH_LIMIT, MAX_SNIPPET_TOKENS, } from './types.js';
|
|
45
|
+
/** Default snippet markers: visible, and NOT html (no XSS vector). */
|
|
46
|
+
export const DEFAULT_HIGHLIGHT_START = '\u27e8'; // ⟨
|
|
47
|
+
export const DEFAULT_HIGHLIGHT_END = '\u27e9'; // ⟩
|
|
48
|
+
const SNIPPET_ELLIPSIS = '\u2026'; // …
|
|
49
|
+
/** Unicode letters/numbers only — every FTS5 metacharacter is dropped. */
|
|
50
|
+
const TERM_PATTERN = /[\p{L}\p{N}]+/gu;
|
|
51
|
+
/**
|
|
52
|
+
* Reduce raw input to safe search terms. Throws on empty / overlong input.
|
|
53
|
+
* This is the single choke point between user input and the FTS engine.
|
|
54
|
+
*/
|
|
55
|
+
export function extractTerms(rawQuery) {
|
|
56
|
+
if (typeof rawQuery !== 'string')
|
|
57
|
+
throw validationError('query must be a string');
|
|
58
|
+
const trimmed = rawQuery.trim();
|
|
59
|
+
if (trimmed.length === 0)
|
|
60
|
+
throw validationError('query must not be empty');
|
|
61
|
+
if (trimmed.length > MAX_QUERY_CHARS) {
|
|
62
|
+
throw validationError(`query exceeds ${MAX_QUERY_CHARS} characters`);
|
|
63
|
+
}
|
|
64
|
+
const terms = trimmed.match(TERM_PATTERN) ?? [];
|
|
65
|
+
if (terms.length === 0) {
|
|
66
|
+
throw validationError('query contains no searchable terms');
|
|
67
|
+
}
|
|
68
|
+
if (terms.length > MAX_QUERY_TERMS) {
|
|
69
|
+
throw validationError(`query exceeds ${MAX_QUERY_TERMS} terms`);
|
|
70
|
+
}
|
|
71
|
+
return terms;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build a safe FTS5 MATCH expression from sanitized terms.
|
|
75
|
+
* Each term becomes a quoted prefix phrase: `"term"*`.
|
|
76
|
+
* Terms are guaranteed `[\p{L}\p{N}]+`, so no quoting/escaping is needed and
|
|
77
|
+
* no FTS5 syntax can be smuggled in.
|
|
78
|
+
*/
|
|
79
|
+
export function buildSafeMatchQuery(rawQuery, match = 'any') {
|
|
80
|
+
const terms = extractTerms(rawQuery);
|
|
81
|
+
const joiner = match === 'all' ? ' AND ' : ' OR ';
|
|
82
|
+
return terms.map((t) => `"${t}"*`).join(joiner);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convenience wrapper that composes the only scopes a principal may ever
|
|
86
|
+
* see: their own principal scope plus the shared global scope. Hosts should
|
|
87
|
+
* prefer this (or `recallMemory` with a derived `MemoryAuthorization`) over
|
|
88
|
+
* hand-rolling scope lists.
|
|
89
|
+
*/
|
|
90
|
+
export function searchForPrincipal(store, principalId, options) {
|
|
91
|
+
if (typeof principalId !== 'string' || principalId.length === 0) {
|
|
92
|
+
throw validationError('principalId is required');
|
|
93
|
+
}
|
|
94
|
+
return search(store, {
|
|
95
|
+
query: options.query,
|
|
96
|
+
scopes: [
|
|
97
|
+
{ kind: 'principal', id: principalId },
|
|
98
|
+
GLOBAL_SCOPE,
|
|
99
|
+
],
|
|
100
|
+
limit: options.limit,
|
|
101
|
+
match: options.match,
|
|
102
|
+
highlightStart: options.highlightStart,
|
|
103
|
+
highlightEnd: options.highlightEnd,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Full-text search restricted to the given authorized scopes.
|
|
108
|
+
* Ranking: FTS5 bm25 (lower = more relevant), tie-broken by
|
|
109
|
+
* created_at DESC, id ASC — deterministic for identical committed state.
|
|
110
|
+
*/
|
|
111
|
+
export function search(store, options) {
|
|
112
|
+
if (options.scopes.length === 0)
|
|
113
|
+
throw validationError('at least one scope is required');
|
|
114
|
+
for (const scope of options.scopes)
|
|
115
|
+
validateScope(scope);
|
|
116
|
+
const matchQuery = buildSafeMatchQuery(options.query, options.match ?? 'any');
|
|
117
|
+
const limit = Math.min(Math.max(Math.floor(options.limit ?? 20), 1), MAX_SEARCH_LIMIT);
|
|
118
|
+
const hlStart = options.highlightStart ?? DEFAULT_HIGHLIGHT_START;
|
|
119
|
+
const hlEnd = options.highlightEnd ?? DEFAULT_HIGHLIGHT_END;
|
|
120
|
+
if (hlStart.length > 16 || hlEnd.length > 16) {
|
|
121
|
+
throw validationError('highlight markers must be at most 16 chars');
|
|
122
|
+
}
|
|
123
|
+
const scopeClauses = [];
|
|
124
|
+
// Placeholder order in the SQL below: snippet markers, MATCH, scopes, LIMIT.
|
|
125
|
+
const params = [hlStart, hlEnd, matchQuery];
|
|
126
|
+
for (const scope of options.scopes) {
|
|
127
|
+
scopeClauses.push('(m.scope_kind = ? AND m.scope_id = ?)');
|
|
128
|
+
params.push(scope.kind, scope.id);
|
|
129
|
+
}
|
|
130
|
+
params.push(limit);
|
|
131
|
+
const rows = store
|
|
132
|
+
.raw()
|
|
133
|
+
.prepare(
|
|
134
|
+
// NOTE: the FTS5 table is referenced by its real name everywhere —
|
|
135
|
+
// this SQLite build does not resolve an alias inside MATCH/bm25/snippet.
|
|
136
|
+
`SELECT m.id, m.scope_kind, m.scope_id, m.text, m.provenance_json,
|
|
137
|
+
m.created_at, bm25(memory_fts) AS rank,
|
|
138
|
+
snippet(memory_fts, 0, ?, ?, '${SNIPPET_ELLIPSIS}', ${MAX_SNIPPET_TOKENS}) AS snippet
|
|
139
|
+
FROM memory_fts
|
|
140
|
+
JOIN memory_records AS m ON m.rowid = memory_fts.rowid
|
|
141
|
+
WHERE memory_fts MATCH ?
|
|
142
|
+
AND (${scopeClauses.join(' OR ')})
|
|
143
|
+
AND m.tombstoned_at IS NULL
|
|
144
|
+
AND m.deleted_at IS NULL
|
|
145
|
+
ORDER BY rank ASC, m.created_at DESC, m.id ASC
|
|
146
|
+
LIMIT ?`)
|
|
147
|
+
.all(...params);
|
|
148
|
+
return rows.map((row) => {
|
|
149
|
+
const record = {
|
|
150
|
+
id: row.id,
|
|
151
|
+
scope: { kind: row.scope_kind, id: row.scope_id },
|
|
152
|
+
text: row.text,
|
|
153
|
+
provenance: JSON.parse(row.provenance_json),
|
|
154
|
+
createdAt: row.created_at,
|
|
155
|
+
};
|
|
156
|
+
return { record, score: row.rank, snippet: row.snippet };
|
|
157
|
+
});
|
|
158
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { type MemoryAuditEntry, type MemoryProvenance, type MemoryRecord, type MemoryScope } from './types.js';
|
|
3
|
+
export declare const SCHEMA_VERSION = 1;
|
|
4
|
+
export declare function validateScope(scope: MemoryScope): void;
|
|
5
|
+
export declare function validateText(text: string): void;
|
|
6
|
+
/** Redacted view: the full record minus its text (safe for non-audit code paths). */
|
|
7
|
+
export interface RedactedMemoryRecord extends Omit<MemoryRecord, 'text'> {
|
|
8
|
+
readonly text: '[REDACTED]';
|
|
9
|
+
}
|
|
10
|
+
export interface CreateRecordInput {
|
|
11
|
+
id?: string;
|
|
12
|
+
scope: MemoryScope;
|
|
13
|
+
text: string;
|
|
14
|
+
provenance: MemoryProvenance;
|
|
15
|
+
createdAt?: string;
|
|
16
|
+
actorId: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class MemoryStore {
|
|
19
|
+
private readonly db;
|
|
20
|
+
private closed;
|
|
21
|
+
private constructor();
|
|
22
|
+
/** Open (or create) a store. Runs the schema migration exactly once. */
|
|
23
|
+
static open(path: string): MemoryStore;
|
|
24
|
+
/** Direct access for the sibling modules (search/indexer/lifecycle). */
|
|
25
|
+
pin(recordId: string, scope: MemoryScope): void;
|
|
26
|
+
unpin(recordId: string, scope: MemoryScope): void;
|
|
27
|
+
isPinned(recordId: string, scope: MemoryScope): boolean;
|
|
28
|
+
raw(): DatabaseSync;
|
|
29
|
+
close(): void;
|
|
30
|
+
private assertOpen;
|
|
31
|
+
/** Insert a record and index it. Idempotent on duplicate id → CONFLICT. */
|
|
32
|
+
create(input: CreateRecordInput): MemoryRecord;
|
|
33
|
+
/**
|
|
34
|
+
* Privileged read by id, INCLUDING tombstoned rows (audit visibility).
|
|
35
|
+
*
|
|
36
|
+
* SECURITY FIX (tombstone bypass via privileged API, low): the old
|
|
37
|
+
* `get(id)` returned tombstoned rows WITH full text and was NOT
|
|
38
|
+
* scope-checked — any host code path that reached it could trivially
|
|
39
|
+
* bypass revocation (`get(revokedId).text`). The rename forces every
|
|
40
|
+
* caller to acknowledge the privilege, and the text is stripped unless
|
|
41
|
+
* the caller explicitly passes `{ forAudit: true }` (the audit
|
|
42
|
+
* capability). NEVER expose this to principals or plugins.
|
|
43
|
+
*/
|
|
44
|
+
getForAudit(id: string, options: {
|
|
45
|
+
forAudit: true;
|
|
46
|
+
}): MemoryRecord | undefined;
|
|
47
|
+
getForAudit(id: string, options?: {
|
|
48
|
+
forAudit?: false;
|
|
49
|
+
}): RedactedMemoryRecord | undefined;
|
|
50
|
+
/** Raw row update used by lifecycle (tombstone). Bypasses FTS only via trigger. */
|
|
51
|
+
markTombstoned(id: string, at: string): void;
|
|
52
|
+
/** Physical removal; the AFTER DELETE trigger purges the FTS entry. */
|
|
53
|
+
hardDelete(id: string): void;
|
|
54
|
+
insertAudit(auditId: string, memoryId: string, action: MemoryAuditEntry['action'], actorId: string, at: string, detail: string): void;
|
|
55
|
+
auditFor(memoryId: string): MemoryAuditEntry[];
|
|
56
|
+
/** Number of live (indexable) rows. */
|
|
57
|
+
countLive(): number;
|
|
58
|
+
/** Number of rows currently in the FTS index. */
|
|
59
|
+
countIndexed(): number;
|
|
60
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite store for memory records + FTS5 index.
|
|
3
|
+
*
|
|
4
|
+
* Schema is intentionally aligned with the repo's `memory_records` table
|
|
5
|
+
* (migration 2 in `src/storage/migrations.ts`) so this module can later land
|
|
6
|
+
* as migration 7: same `memory_records` shape, plus a `memory_fts` virtual
|
|
7
|
+
* table kept in sync by triggers. Triggers only index rows where
|
|
8
|
+
* `tombstoned_at IS NULL AND deleted_at IS NULL`, so revocation immediately
|
|
9
|
+
* removes a record from search while the row (audit trail) survives.
|
|
10
|
+
*
|
|
11
|
+
* Only `node:sqlite` (Node >= 22) is used. The database handle is
|
|
12
|
+
* synchronous; callers must not run it on a latency-sensitive event loop —
|
|
13
|
+
* the BoomBot spec requires recall to stay off the Gateway event loop.
|
|
14
|
+
*/
|
|
15
|
+
import { randomUUID } from 'node:crypto';
|
|
16
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
17
|
+
import { MemoryFtsError, validationError } from './errors.js';
|
|
18
|
+
import { MAX_SCOPE_ID_CHARS, MAX_TEXT_BYTES, } from './types.js';
|
|
19
|
+
export const SCHEMA_VERSION = 1;
|
|
20
|
+
const DDL = `
|
|
21
|
+
CREATE TABLE memory_records (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
scope_kind TEXT NOT NULL CHECK (scope_kind IN ('principal', 'session', 'global', 'conversation', 'group')),
|
|
24
|
+
scope_id TEXT NOT NULL,
|
|
25
|
+
text TEXT NOT NULL,
|
|
26
|
+
provenance_json TEXT NOT NULL,
|
|
27
|
+
created_at TEXT NOT NULL,
|
|
28
|
+
tombstoned_at TEXT,
|
|
29
|
+
deleted_at TEXT
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
CREATE INDEX memory_records_scope_order
|
|
33
|
+
ON memory_records (scope_kind, scope_id, created_at DESC, id ASC);
|
|
34
|
+
|
|
35
|
+
CREATE VIRTUAL TABLE memory_fts USING fts5(
|
|
36
|
+
text,
|
|
37
|
+
memory_id UNINDEXED,
|
|
38
|
+
tokenize = 'unicode61'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
-- Keep the FTS index in sync. Only live rows are indexed; tombstoned or
|
|
42
|
+
-- soft-deleted rows are removed from the index but kept in memory_records
|
|
43
|
+
-- as the audit trail.
|
|
44
|
+
CREATE TRIGGER memory_fts_after_insert AFTER INSERT ON memory_records
|
|
45
|
+
WHEN NEW.tombstoned_at IS NULL AND NEW.deleted_at IS NULL
|
|
46
|
+
BEGIN
|
|
47
|
+
INSERT INTO memory_fts (rowid, text, memory_id)
|
|
48
|
+
VALUES (NEW.rowid, NEW.text, NEW.id);
|
|
49
|
+
END;
|
|
50
|
+
|
|
51
|
+
CREATE TRIGGER memory_fts_after_delete AFTER DELETE ON memory_records
|
|
52
|
+
BEGIN
|
|
53
|
+
DELETE FROM memory_fts WHERE rowid = OLD.rowid;
|
|
54
|
+
END;
|
|
55
|
+
|
|
56
|
+
CREATE TRIGGER memory_fts_after_update_delete AFTER UPDATE ON memory_records
|
|
57
|
+
BEGIN
|
|
58
|
+
DELETE FROM memory_fts WHERE rowid = OLD.rowid;
|
|
59
|
+
END;
|
|
60
|
+
|
|
61
|
+
CREATE TRIGGER memory_fts_after_update_insert AFTER UPDATE ON memory_records
|
|
62
|
+
WHEN NEW.tombstoned_at IS NULL AND NEW.deleted_at IS NULL
|
|
63
|
+
BEGIN
|
|
64
|
+
INSERT INTO memory_fts (rowid, text, memory_id)
|
|
65
|
+
VALUES (NEW.rowid, NEW.text, NEW.id);
|
|
66
|
+
END;
|
|
67
|
+
|
|
68
|
+
CREATE TABLE memory_audit (
|
|
69
|
+
audit_id TEXT PRIMARY KEY,
|
|
70
|
+
memory_id TEXT NOT NULL,
|
|
71
|
+
action TEXT NOT NULL CHECK (action IN ('create', 'revoke', 'forget', 'reindex')),
|
|
72
|
+
actor_id TEXT NOT NULL,
|
|
73
|
+
at TEXT NOT NULL,
|
|
74
|
+
detail TEXT NOT NULL
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE INDEX memory_audit_record ON memory_audit (memory_id, at DESC);
|
|
78
|
+
`;
|
|
79
|
+
const SCOPE_KINDS = ['principal', 'session', 'global', 'conversation', 'group'];
|
|
80
|
+
export function validateScope(scope) {
|
|
81
|
+
if (!SCOPE_KINDS.includes(scope.kind)) {
|
|
82
|
+
throw validationError(`invalid scope kind '${String(scope.kind)}'`);
|
|
83
|
+
}
|
|
84
|
+
if (typeof scope.id !== 'string' || scope.id.length === 0) {
|
|
85
|
+
throw validationError('scope id must be a non-empty string');
|
|
86
|
+
}
|
|
87
|
+
if (scope.id.length > MAX_SCOPE_ID_CHARS) {
|
|
88
|
+
throw validationError(`scope id exceeds ${MAX_SCOPE_ID_CHARS} chars`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function validateText(text) {
|
|
92
|
+
if (typeof text !== 'string' || text.length === 0) {
|
|
93
|
+
throw validationError('memory text must be a non-empty string');
|
|
94
|
+
}
|
|
95
|
+
if (Buffer.byteLength(text, 'utf8') > MAX_TEXT_BYTES) {
|
|
96
|
+
throw validationError(`memory text exceeds ${MAX_TEXT_BYTES} bytes`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function rowToRecord(row) {
|
|
100
|
+
const record = {
|
|
101
|
+
id: row.id,
|
|
102
|
+
scope: { kind: row.scope_kind, id: row.scope_id },
|
|
103
|
+
text: row.text,
|
|
104
|
+
provenance: JSON.parse(row.provenance_json),
|
|
105
|
+
createdAt: row.created_at,
|
|
106
|
+
};
|
|
107
|
+
if (row.tombstoned_at !== null)
|
|
108
|
+
record.tombstonedAt = row.tombstoned_at;
|
|
109
|
+
return record;
|
|
110
|
+
}
|
|
111
|
+
export class MemoryStore {
|
|
112
|
+
db;
|
|
113
|
+
closed = false;
|
|
114
|
+
constructor(db) {
|
|
115
|
+
this.db = db;
|
|
116
|
+
}
|
|
117
|
+
/** Open (or create) a store. Runs the schema migration exactly once. */
|
|
118
|
+
static open(path) {
|
|
119
|
+
const db = new DatabaseSync(path);
|
|
120
|
+
try {
|
|
121
|
+
db.exec('PRAGMA journal_mode = WAL;');
|
|
122
|
+
db.exec(`CREATE TABLE IF NOT EXISTS memory_pins (
|
|
123
|
+
record_id TEXT NOT NULL,
|
|
124
|
+
scope_kind TEXT NOT NULL,
|
|
125
|
+
scope_id TEXT NOT NULL,
|
|
126
|
+
pinned_at TEXT NOT NULL,
|
|
127
|
+
PRIMARY KEY (record_id, scope_kind, scope_id)
|
|
128
|
+
)`);
|
|
129
|
+
db.exec(`CREATE TABLE IF NOT EXISTS schema_version (
|
|
130
|
+
version INTEGER PRIMARY KEY,
|
|
131
|
+
applied_at TEXT NOT NULL
|
|
132
|
+
)`);
|
|
133
|
+
const row = db
|
|
134
|
+
.prepare(`SELECT version AS v FROM schema_version ORDER BY version DESC LIMIT 1`)
|
|
135
|
+
.get();
|
|
136
|
+
if (row === undefined) {
|
|
137
|
+
db.exec(DDL);
|
|
138
|
+
db.prepare(`INSERT INTO schema_version (version, applied_at) VALUES (?, ?)`).run(SCHEMA_VERSION, new Date().toISOString());
|
|
139
|
+
}
|
|
140
|
+
else if (row.v > SCHEMA_VERSION) {
|
|
141
|
+
throw new MemoryFtsError('MEMORY_FTS_STORAGE', `memory database schema version ${row.v} is newer than supported ${SCHEMA_VERSION}`);
|
|
142
|
+
}
|
|
143
|
+
// Guard against a half-applied schema (e.g. crash mid-DDL on first open).
|
|
144
|
+
const fts = db
|
|
145
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'memory_fts'`)
|
|
146
|
+
.get();
|
|
147
|
+
if (fts === undefined) {
|
|
148
|
+
throw new MemoryFtsError('MEMORY_FTS_STORAGE', 'memory_fts virtual table is missing');
|
|
149
|
+
}
|
|
150
|
+
return new MemoryStore(db);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
db.close();
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Direct access for the sibling modules (search/indexer/lifecycle). */
|
|
158
|
+
pin(recordId, scope) {
|
|
159
|
+
this.assertOpen();
|
|
160
|
+
validateScope(scope);
|
|
161
|
+
this.db
|
|
162
|
+
.prepare(`INSERT OR REPLACE INTO memory_pins (record_id, scope_kind, scope_id, pinned_at) VALUES (?, ?, ?, ?)`)
|
|
163
|
+
.run(recordId, scope.kind, scope.id, new Date().toISOString());
|
|
164
|
+
}
|
|
165
|
+
unpin(recordId, scope) {
|
|
166
|
+
this.assertOpen();
|
|
167
|
+
validateScope(scope);
|
|
168
|
+
this.db
|
|
169
|
+
.prepare(`DELETE FROM memory_pins WHERE record_id = ? AND scope_kind = ? AND scope_id = ?`)
|
|
170
|
+
.run(recordId, scope.kind, scope.id);
|
|
171
|
+
}
|
|
172
|
+
isPinned(recordId, scope) {
|
|
173
|
+
this.assertOpen();
|
|
174
|
+
validateScope(scope);
|
|
175
|
+
const row = this.db
|
|
176
|
+
.prepare(`SELECT 1 FROM memory_pins WHERE record_id = ? AND scope_kind = ? AND scope_id = ? LIMIT 1`)
|
|
177
|
+
.get(recordId, scope.kind, scope.id);
|
|
178
|
+
return row !== undefined;
|
|
179
|
+
}
|
|
180
|
+
raw() {
|
|
181
|
+
this.assertOpen();
|
|
182
|
+
return this.db;
|
|
183
|
+
}
|
|
184
|
+
close() {
|
|
185
|
+
if (!this.closed) {
|
|
186
|
+
this.closed = true;
|
|
187
|
+
this.db.close();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
assertOpen() {
|
|
191
|
+
if (this.closed)
|
|
192
|
+
throw new MemoryFtsError('MEMORY_FTS_STORAGE', 'memory store is closed');
|
|
193
|
+
}
|
|
194
|
+
/** Insert a record and index it. Idempotent on duplicate id → CONFLICT. */
|
|
195
|
+
create(input) {
|
|
196
|
+
this.assertOpen();
|
|
197
|
+
validateScope(input.scope);
|
|
198
|
+
validateText(input.text);
|
|
199
|
+
const id = input.id ?? randomUUID();
|
|
200
|
+
if (id.length === 0 || id.length > 256)
|
|
201
|
+
throw validationError('invalid record id');
|
|
202
|
+
const createdAt = input.createdAt ?? new Date().toISOString();
|
|
203
|
+
const provenance = {
|
|
204
|
+
source: input.provenance.source,
|
|
205
|
+
reference: input.provenance.reference,
|
|
206
|
+
actorId: input.provenance.actorId,
|
|
207
|
+
at: input.provenance.at,
|
|
208
|
+
};
|
|
209
|
+
try {
|
|
210
|
+
this.db
|
|
211
|
+
.prepare(`INSERT INTO memory_records
|
|
212
|
+
(id, scope_kind, scope_id, text, provenance_json, created_at)
|
|
213
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
214
|
+
.run(id, input.scope.kind, input.scope.id, input.text, JSON.stringify(provenance), createdAt);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (error instanceof Error && error.message.includes('UNIQUE constraint failed')) {
|
|
218
|
+
throw new MemoryFtsError('MEMORY_FTS_CONFLICT', `memory record '${id}' already exists`);
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
this.insertAudit(randomUUID(), id, 'create', input.actorId, new Date().toISOString(), 'created');
|
|
223
|
+
const row = this.db
|
|
224
|
+
.prepare(`SELECT * FROM memory_records WHERE id = ?`)
|
|
225
|
+
.get(id);
|
|
226
|
+
if (row === undefined)
|
|
227
|
+
throw new MemoryFtsError('MEMORY_FTS_STORAGE', 'record vanished after insert');
|
|
228
|
+
return rowToRecord(row);
|
|
229
|
+
}
|
|
230
|
+
getForAudit(id, options) {
|
|
231
|
+
this.assertOpen();
|
|
232
|
+
const row = this.db.prepare(`SELECT * FROM memory_records WHERE id = ?`).get(id);
|
|
233
|
+
if (row === undefined)
|
|
234
|
+
return undefined;
|
|
235
|
+
const record = rowToRecord(row);
|
|
236
|
+
if (options?.forAudit === true)
|
|
237
|
+
return record;
|
|
238
|
+
const redacted = { ...record, text: '[REDACTED]' };
|
|
239
|
+
return redacted;
|
|
240
|
+
}
|
|
241
|
+
/** Raw row update used by lifecycle (tombstone). Bypasses FTS only via trigger. */
|
|
242
|
+
markTombstoned(id, at) {
|
|
243
|
+
this.assertOpen();
|
|
244
|
+
this.db
|
|
245
|
+
.prepare(`UPDATE memory_records SET tombstoned_at = ? WHERE id = ? AND tombstoned_at IS NULL`)
|
|
246
|
+
.run(at, id);
|
|
247
|
+
}
|
|
248
|
+
/** Physical removal; the AFTER DELETE trigger purges the FTS entry. */
|
|
249
|
+
hardDelete(id) {
|
|
250
|
+
this.assertOpen();
|
|
251
|
+
this.db.prepare(`DELETE FROM memory_records WHERE id = ?`).run(id);
|
|
252
|
+
this.db.prepare(`DELETE FROM memory_pins WHERE record_id = ?`).run(id);
|
|
253
|
+
}
|
|
254
|
+
insertAudit(auditId, memoryId, action, actorId, at, detail) {
|
|
255
|
+
this.assertOpen();
|
|
256
|
+
this.db
|
|
257
|
+
.prepare(`INSERT INTO memory_audit (audit_id, memory_id, action, actor_id, at, detail)
|
|
258
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
259
|
+
.run(auditId, memoryId, action, actorId, at, detail);
|
|
260
|
+
}
|
|
261
|
+
auditFor(memoryId) {
|
|
262
|
+
this.assertOpen();
|
|
263
|
+
return this.db
|
|
264
|
+
.prepare(`SELECT audit_id, memory_id, action, actor_id, at, detail
|
|
265
|
+
FROM memory_audit WHERE memory_id = ? ORDER BY at ASC`)
|
|
266
|
+
.all(memoryId).map((r) => ({
|
|
267
|
+
auditId: r.audit_id,
|
|
268
|
+
memoryId: r.memory_id,
|
|
269
|
+
action: r.action,
|
|
270
|
+
actorId: r.actor_id,
|
|
271
|
+
at: r.at,
|
|
272
|
+
detail: r.detail,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
/** Number of live (indexable) rows. */
|
|
276
|
+
countLive() {
|
|
277
|
+
this.assertOpen();
|
|
278
|
+
const row = this.db
|
|
279
|
+
.prepare(`SELECT COUNT(*) AS c FROM memory_records WHERE tombstoned_at IS NULL`)
|
|
280
|
+
.get();
|
|
281
|
+
return row.c;
|
|
282
|
+
}
|
|
283
|
+
/** Number of rows currently in the FTS index. */
|
|
284
|
+
countIndexed() {
|
|
285
|
+
this.assertOpen();
|
|
286
|
+
const row = this.db.prepare(`SELECT COUNT(*) AS c FROM memory_fts`).get();
|
|
287
|
+
return row.c;
|
|
288
|
+
}
|
|
289
|
+
}
|