squish-memory 1.1.5 → 1.2.0
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/.env.example +32 -16
- package/CHANGELOG.md +147 -0
- package/README.md +120 -78
- package/{scripts → bin}/dependency-manager.mjs +217 -217
- package/{scripts → bin}/detect-clients.mjs +78 -78
- package/bin/install-interactive.mjs +321 -0
- package/bin/squish-mcp.mjs +46 -0
- package/bin/squish.mjs +33 -0
- package/config/mcp-migration-map.json +1 -6
- package/config/mcp-mode-semantics.json +19 -23
- package/config/mcp-remote-auth.json +3 -26
- package/config/mcp-universal.schema.json +5 -35
- package/config/settings.json +107 -52
- package/config.js +5 -0
- package/config.ts +218 -0
- package/core/adapters/config/claude-code.ts +133 -0
- package/core/adapters/config/cursor.ts +90 -0
- package/core/adapters/config/opencode.ts +89 -0
- package/core/adapters/config/windsurf.ts +90 -0
- package/core/adapters/index.ts +102 -0
- package/core/adapters/timeline.ts +116 -0
- package/core/adapters/types.ts +166 -0
- package/core/agent-preferences.ts +140 -0
- package/core/algorithms/analytics/token-estimator.ts +216 -0
- package/core/algorithms/detection/hash-filters.ts +260 -0
- package/core/algorithms/detection/semantic-ranker.ts +194 -0
- package/core/algorithms/detection/two-stage-detector.ts +421 -0
- package/core/algorithms/handlers/approve-merge.ts +215 -0
- package/core/algorithms/handlers/detect-duplicates.ts +192 -0
- package/core/algorithms/handlers/get-stats.ts +132 -0
- package/core/algorithms/handlers/list-proposals.ts +130 -0
- package/core/algorithms/handlers/preview-merge.ts +139 -0
- package/core/algorithms/handlers/reject-merge.ts +93 -0
- package/core/algorithms/handlers/reverse-merge.ts +155 -0
- package/core/algorithms/index.ts +39 -0
- package/core/algorithms/operations/cache-maintenance.ts +182 -0
- package/core/algorithms/safety/safety-checks.ts +256 -0
- package/core/algorithms/strategies/merge-strategies.ts +381 -0
- package/core/algorithms/types.ts +140 -0
- package/core/algorithms/utils/response-builder.ts +61 -0
- package/core/associations.ts +363 -0
- package/core/beliefs/decay.ts +289 -0
- package/core/beliefs/extractor.ts +131 -0
- package/core/beliefs/store.ts +557 -0
- package/core/beliefs/types.ts +38 -0
- package/core/commands/mcp-server.ts +5 -0
- package/core/compression.ts +177 -0
- package/core/config.js +2 -0
- package/core/consolidation.ts +330 -0
- package/core/context/agent-context.ts +388 -0
- package/core/context/context-paging.ts +449 -0
- package/core/context/context-window.ts +234 -0
- package/core/context/context.ts +35 -0
- package/core/embeddings/embeddings.ts +616 -0
- package/core/embeddings/google-multimodal.ts +200 -0
- package/{dist/core/local-embeddings.js → core/embeddings/local-embeddings.ts} +12 -11
- package/core/embeddings/qmd-client.ts +495 -0
- package/core/embeddings/transformers-local.ts +261 -0
- package/core/embeddings.js +4 -0
- package/core/error-handling.ts +206 -0
- package/core/external +219 -0
- package/core/graph/entity-deduplicator.ts +232 -0
- package/core/graph/graph-builder.ts +257 -0
- package/core/graph/graph-traversal.ts +490 -0
- package/core/graph/index.ts +24 -0
- package/core/graph/llm-entity-extractor.ts +402 -0
- package/core/graph/multi-hop-retrieval.ts +317 -0
- package/core/graph/relationship-extractor.ts +465 -0
- package/core/hooks/agent-hooks.ts +653 -0
- package/core/hooks/auto-tagger.ts +149 -0
- package/core/hooks/capture-filter.ts +169 -0
- package/core/hot-cache.ts +388 -0
- package/core/index.ts +10 -0
- package/core/ingestion/agent-memory.ts +167 -0
- package/core/ingestion/core-memory.ts +326 -0
- package/core/ingestion/learnings.ts +260 -0
- package/core/ingestion/signal-engine.ts +266 -0
- package/core/integrations/obsidian-vault.ts +197 -0
- package/core/layers/generator.ts +115 -0
- package/core/lib/db-client.ts +168 -0
- package/core/lib/parse-embedding.ts +59 -0
- package/core/lib/schemas.ts +102 -0
- package/core/lib/types.ts +49 -0
- package/core/lib/utils.ts +151 -0
- package/core/lib/validation.ts +180 -0
- package/core/lifecycle.ts +353 -0
- package/core/logger.ts +59 -0
- package/core/memory/bridge-discovery.ts +395 -0
- package/core/memory/categorizer.ts +390 -0
- package/core/memory/conflict-detector.ts +62 -0
- package/core/memory/consolidation.ts +372 -0
- package/core/memory/context-collector.ts +75 -0
- package/core/memory/contradiction-resolver.ts +494 -0
- package/core/memory/edit-workflow.ts +174 -0
- package/core/memory/entity-extractor.ts +426 -0
- package/core/memory/entity-resolver.ts +89 -0
- package/core/memory/explain.ts +112 -0
- package/core/memory/fact-deriver.ts +300 -0
- package/core/memory/fact-extractor.ts +120 -0
- package/core/memory/feedback-tracker.ts +200 -0
- package/core/memory/hooks.ts +230 -0
- package/core/memory/hybrid-retrieval.ts +65 -0
- package/core/memory/hybrid-scorer.ts +325 -0
- package/core/memory/hybrid-search.ts +748 -0
- package/core/memory/importance.ts +319 -0
- package/core/memory/index.ts +11 -0
- package/core/memory/loader.ts +178 -0
- package/core/memory/markdown/markdown-storage.ts +318 -0
- package/core/memory/memories.ts +565 -0
- package/core/memory/memory-lifecycle.ts +51 -0
- package/core/memory/memory-manager.ts +53 -0
- package/core/memory/migrate.ts +173 -0
- package/core/memory/normalization.ts +30 -0
- package/core/memory/path-strengthener.ts +211 -0
- package/core/memory/progressive-disclosure.ts +392 -0
- package/core/memory/query-processor.ts +130 -0
- package/core/memory/query-rewriter.ts +153 -0
- package/core/memory/response-analyzer.ts +81 -0
- package/core/memory/retrieval-feedback.ts +276 -0
- package/core/memory/serialization.ts +83 -0
- package/core/memory/stale-cleaner.ts +147 -0
- package/core/memory/stats.ts +181 -0
- package/core/memory/telemetry.ts +392 -0
- package/core/memory/temporal-facts.ts +356 -0
- package/core/memory/temporal-parser.ts +477 -0
- package/core/memory/trigger-detector.ts +104 -0
- package/core/memory/write-gate.ts +288 -0
- package/core/places/index.ts +14 -0
- package/core/places/memory-places.ts +339 -0
- package/core/places/places.ts +406 -0
- package/core/places/rules.ts +308 -0
- package/core/places/walking.ts +192 -0
- package/core/projects +89 -0
- package/core/projects.ts +131 -0
- package/core/redis.ts +82 -0
- package/core/responses.ts +187 -0
- package/core/runtime/trust-report.ts +195 -0
- package/core/runtime/trust-state.ts +360 -0
- package/core/scheduler/cron-scheduler.ts +581 -0
- package/core/scheduler/heartbeat.ts +91 -0
- package/core/scheduler/index.ts +8 -0
- package/core/scheduler/job-runner.ts +197 -0
- package/core/search/conversations.ts +166 -0
- package/core/search/entities.ts +46 -0
- package/core/search/folder-context.ts +154 -0
- package/core/search/graph-boost.ts +22 -0
- package/core/search/index.ts +4 -0
- package/core/search/qmd-wrapper.ts +84 -0
- package/core/security/encrypt.ts +51 -0
- package/core/security/governance.ts +102 -0
- package/core/security/privacy.ts +108 -0
- package/core/security/secret-detector.ts +122 -0
- package/core/session/auto-load.ts +160 -0
- package/core/session/entity-tracker.ts +363 -0
- package/core/session/index.ts +7 -0
- package/core/session/reference-resolver.ts +158 -0
- package/core/session/self-iteration-job.ts +478 -0
- package/core/session/session-hooks.ts +69 -0
- package/core/session/types.ts +36 -0
- package/core/session/working-set.ts +275 -0
- package/core/snapshots/cleanup.ts +13 -0
- package/core/snapshots/comparison.ts +59 -0
- package/core/snapshots/creation.ts +139 -0
- package/core/snapshots/retrieval.ts +44 -0
- package/core/snapshots/stats.ts +63 -0
- package/core/storage/cache.ts +241 -0
- package/core/storage/database.ts +23 -0
- package/core/summarization/cleanup.ts +13 -0
- package/core/summarization/queries.ts +32 -0
- package/core/summarization/stats.ts +64 -0
- package/core/summarization/strategies.ts +52 -0
- package/core/summarization.ts +248 -0
- package/core/temporal-facts.ts +244 -0
- package/core/tracing/collector.ts +470 -0
- package/core/tracing/visualizer.ts +195 -0
- package/core/utils/cleanup-operations.ts +50 -0
- package/core/utils/content-extraction.ts +95 -0
- package/core/utils/filter-builder.ts +56 -0
- package/core/utils/history-traversal.ts +63 -0
- package/core/utils/memory-operations.ts +56 -0
- package/core/utils/query-operations.ts +83 -0
- package/core/utils/summarization-helpers.ts +45 -0
- package/core/utils/temporal-queries.ts +39 -0
- package/core/utils/vector-operations.ts +135 -0
- package/core/utils/version-management.ts +74 -0
- package/core/worker.ts +324 -0
- package/db/adapter.ts +215 -0
- package/db/bootstrap.ts +1055 -0
- package/db/drizzle/migrations/0000_needy_cerebro.sql +402 -0
- package/db/drizzle/migrations/meta/0000_snapshot.json +3451 -0
- package/db/drizzle/migrations/meta/_journal.json +13 -0
- package/db/drizzle/schema-sqlite.ts +1032 -0
- package/db/drizzle/schema.ts +1128 -0
- package/db/drizzle.config.ts +12 -0
- package/db/index.ts +83 -0
- package/db/init.sql +5 -0
- package/db/migrations/associations.ts +35 -0
- package/db/migrations/beliefs.ts +89 -0
- package/db/migrations/core-memory.ts +35 -0
- package/db/migrations/fts.ts +59 -0
- package/db/migrations/index.ts +54 -0
- package/db/migrations/indexes.ts +36 -0
- package/db/migrations/learnings.ts +34 -0
- package/db/migrations/maintenance.ts +68 -0
- package/db/migrations/memories.ts +22 -0
- package/db/migrations/memory-places.ts +35 -0
- package/db/migrations/places.ts +49 -0
- package/db/migrations/projects.ts +21 -0
- package/db/migrations/tier-conversion.ts +24 -0
- package/db/neon.ts +22 -0
- package/db/schema/beliefs.ts +50 -0
- package/db/schema/generator.ts +159 -0
- package/db/schema/index.ts +58 -0
- package/db/schema/learnings.ts +32 -0
- package/db/schema/memories.ts +83 -0
- package/db/schema/projects.ts +33 -0
- package/db/schema.ts +13 -0
- package/db/supabase.ts +27 -0
- package/dist/config.d.ts +40 -17
- package/dist/config.js +150 -198
- package/dist/core/adapters/types.d.ts +13 -33
- package/dist/core/adapters/types.js +1 -1
- package/dist/core/agent-preferences.d.ts +16 -0
- package/dist/core/agent-preferences.js +124 -0
- package/dist/core/algorithms/safety/safety-checks.d.ts +1 -5
- package/dist/core/algorithms/types.d.ts +0 -8
- package/dist/core/associations.d.ts +3 -1
- package/dist/core/associations.js +37 -1
- package/dist/core/beliefs/decay.d.ts +27 -0
- package/dist/core/beliefs/decay.js +217 -0
- package/dist/core/beliefs/extractor.d.ts +9 -0
- package/dist/core/beliefs/extractor.js +113 -0
- package/dist/core/beliefs/store.d.ts +46 -0
- package/dist/core/beliefs/store.js +466 -0
- package/dist/core/beliefs/types.d.ts +28 -0
- package/dist/core/beliefs/types.js +2 -0
- package/dist/core/commands/mcp-server.d.ts +0 -1
- package/dist/core/commands/mcp-server.js +4 -737
- package/dist/core/commands/remember.d.ts +24 -0
- package/dist/core/commands/remember.js +144 -0
- package/dist/core/{toon.d.ts → compression.d.ts} +6 -4
- package/dist/core/{toon.js → compression.js} +8 -8
- package/dist/core/context/agent-context.js +1 -1
- package/dist/core/embeddings/embeddings.d.ts +29 -0
- package/dist/core/embeddings/embeddings.js +546 -0
- package/dist/core/embeddings/google-multimodal.js +6 -2
- package/dist/core/{local-embeddings.d.ts → embeddings/local-embeddings.d.ts} +1 -1
- package/dist/core/embeddings/local-embeddings.js +11 -0
- package/dist/core/embeddings/qmd-client.js +1 -1
- package/dist/core/embeddings/transformers-local.d.ts +64 -0
- package/dist/core/embeddings/transformers-local.js +213 -0
- package/dist/core/embeddings.d.ts +1 -28
- package/dist/core/embeddings.js +2 -453
- package/dist/core/graph/entity-deduplicator.d.ts +24 -0
- package/dist/core/graph/entity-deduplicator.js +183 -0
- package/dist/core/graph/graph-builder.d.ts +46 -0
- package/dist/core/graph/graph-builder.js +174 -0
- package/dist/core/graph/graph-traversal.d.ts +80 -0
- package/dist/core/graph/graph-traversal.js +315 -0
- package/dist/core/graph/index.d.ts +19 -0
- package/dist/core/graph/index.js +13 -0
- package/dist/core/graph/llm-entity-extractor.d.ts +49 -0
- package/dist/core/graph/llm-entity-extractor.js +313 -0
- package/dist/core/graph/multi-hop-retrieval.d.ts +48 -0
- package/dist/core/graph/multi-hop-retrieval.js +215 -0
- package/dist/core/graph/relationship-extractor.d.ts +48 -0
- package/dist/core/graph/relationship-extractor.js +351 -0
- package/dist/core/hooks/agent-hooks.d.ts +10 -1
- package/dist/core/hooks/agent-hooks.js +301 -24
- package/dist/core/hot-cache.d.ts +86 -0
- package/dist/core/hot-cache.js +285 -0
- package/dist/core/index.d.ts +9 -9
- package/dist/core/index.js +9 -12
- package/dist/core/ingestion/core-memory.d.ts +2 -2
- package/dist/core/ingestion/core-memory.js +3 -3
- package/dist/core/ingestion/learnings.js +3 -0
- package/dist/core/ingestion/signal-engine.d.ts +41 -0
- package/dist/core/ingestion/signal-engine.js +201 -0
- package/dist/core/{obsidian-vault.d.ts → integrations/obsidian-vault.d.ts} +2 -1
- package/dist/core/{obsidian-vault.js → integrations/obsidian-vault.js} +69 -7
- package/dist/core/lib/parse-embedding.d.ts +9 -0
- package/dist/core/lib/parse-embedding.js +58 -0
- package/dist/core/lib/schemas.d.ts +57 -54
- package/dist/core/lib/types.d.ts +45 -0
- package/dist/core/lib/types.js +6 -0
- package/dist/core/lib/utils.d.ts +4 -0
- package/dist/core/lib/utils.js +55 -0
- package/dist/core/lifecycle.d.ts +0 -1
- package/dist/core/lifecycle.js +13 -23
- package/dist/core/logger.d.ts +1 -0
- package/dist/core/logger.js +14 -8
- package/dist/core/mcp/tools.d.ts +0 -2
- package/dist/core/mcp/tools.js +0 -87
- package/dist/core/mcp/types.d.ts +25 -253
- package/dist/core/mcp/types.js +2 -2
- package/dist/core/memory/categorizer.js +1 -0
- package/dist/core/memory/consolidation.js +2 -28
- package/dist/core/memory/entity-extractor.d.ts +4 -0
- package/dist/core/memory/entity-extractor.js +30 -16
- package/dist/core/memory/explain.d.ts +18 -0
- package/dist/core/memory/explain.js +92 -0
- package/dist/core/memory/fact-deriver.d.ts +31 -0
- package/dist/core/memory/fact-deriver.js +236 -0
- package/dist/core/memory/hybrid-retrieval.d.ts +14 -16
- package/dist/core/memory/hybrid-retrieval.js +25 -127
- package/dist/core/memory/hybrid-scorer.js +6 -23
- package/dist/core/memory/hybrid-search.d.ts +10 -7
- package/dist/core/memory/hybrid-search.js +458 -221
- package/dist/core/memory/importance.d.ts +0 -17
- package/dist/core/memory/importance.js +1 -58
- package/dist/core/memory/index.d.ts +1 -0
- package/dist/core/memory/index.js +1 -0
- package/dist/core/memory/memories.d.ts +13 -17
- package/dist/core/memory/memories.js +78 -75
- package/dist/core/memory/memory-lifecycle.d.ts +2 -2
- package/dist/core/memory/memory-lifecycle.js +10 -18
- package/dist/core/memory/normalization.d.ts +1 -16
- package/dist/core/memory/path-strengthener.d.ts +39 -0
- package/dist/core/memory/path-strengthener.js +150 -0
- package/dist/core/memory/query-processor.js +37 -3
- package/dist/core/memory/retrieval-feedback.d.ts +70 -0
- package/dist/core/memory/retrieval-feedback.js +213 -0
- package/dist/core/memory/stale-cleaner.d.ts +26 -0
- package/dist/core/memory/stale-cleaner.js +97 -0
- package/dist/core/memory/stats.d.ts +10 -0
- package/dist/core/memory/stats.js +8 -3
- package/dist/core/memory/trigger-detector.d.ts +8 -1
- package/dist/core/memory/trigger-detector.js +42 -5
- package/dist/core/places/index.d.ts +1 -1
- package/dist/core/places/index.js +1 -1
- package/dist/core/places/places.d.ts +13 -13
- package/dist/core/places/places.js +27 -27
- package/dist/core/places/rules.js +23 -23
- package/dist/core/places/walking.d.ts +3 -3
- package/dist/core/places/walking.js +7 -7
- package/dist/core/projects.js +8 -0
- package/dist/core/runtime/trust-report.d.ts +102 -0
- package/dist/core/runtime/trust-report.js +107 -0
- package/dist/core/runtime/trust-state.d.ts +12 -0
- package/dist/core/runtime/trust-state.js +309 -0
- package/dist/core/scheduler/cron-scheduler.d.ts +1 -1
- package/dist/core/scheduler/cron-scheduler.js +164 -3
- package/dist/core/scheduler/job-runner.js +1 -1
- package/dist/core/search/qmd-wrapper.d.ts +36 -0
- package/dist/core/search/qmd-wrapper.js +58 -0
- package/dist/core/session/auto-load.js +28 -3
- package/dist/core/session/entity-tracker.d.ts +62 -0
- package/dist/core/session/entity-tracker.js +287 -0
- package/dist/core/session/reference-resolver.d.ts +26 -0
- package/dist/core/session/reference-resolver.js +121 -0
- package/dist/core/session/self-iteration-job.d.ts +15 -0
- package/dist/core/session/self-iteration-job.js +163 -58
- package/dist/core/session/working-set.d.ts +50 -0
- package/dist/core/session/working-set.js +212 -0
- package/dist/core/snapshots/creation.d.ts +2 -8
- package/dist/core/snapshots/creation.js +3 -12
- package/dist/core/utils/summarization-helpers.d.ts +0 -4
- package/dist/core/utils/summarization-helpers.js +1 -6
- package/dist/db/bootstrap.d.ts +2 -0
- package/dist/db/bootstrap.js +229 -280
- package/dist/db/drizzle/schema-sqlite.d.ts +702 -1
- package/dist/db/drizzle/schema-sqlite.js +83 -4
- package/dist/db/drizzle/schema.d.ts +653 -1
- package/dist/db/drizzle/schema.js +93 -4
- package/dist/db/migrations/associations.d.ts +6 -0
- package/dist/db/migrations/associations.js +29 -0
- package/dist/db/migrations/beliefs.d.ts +10 -0
- package/dist/db/migrations/beliefs.js +76 -0
- package/dist/db/migrations/core-memory.d.ts +6 -0
- package/dist/db/migrations/core-memory.js +29 -0
- package/dist/db/migrations/fts.d.ts +6 -0
- package/dist/db/migrations/fts.js +52 -0
- package/dist/db/migrations/index.d.ts +25 -0
- package/dist/db/migrations/index.js +51 -0
- package/dist/db/migrations/indexes.d.ts +6 -0
- package/dist/db/migrations/indexes.js +30 -0
- package/dist/db/migrations/learnings.d.ts +7 -0
- package/dist/db/migrations/learnings.js +26 -0
- package/dist/db/migrations/maintenance.d.ts +6 -0
- package/dist/db/migrations/maintenance.js +61 -0
- package/dist/db/migrations/memories.d.ts +7 -0
- package/dist/db/migrations/memories.js +16 -0
- package/dist/db/migrations/memory-places.d.ts +6 -0
- package/dist/db/migrations/memory-places.js +29 -0
- package/dist/db/migrations/places.d.ts +6 -0
- package/dist/db/migrations/places.js +43 -0
- package/dist/db/migrations/projects.d.ts +3 -0
- package/dist/db/migrations/projects.js +13 -0
- package/dist/db/migrations/tier-conversion.d.ts +7 -0
- package/dist/db/migrations/tier-conversion.js +20 -0
- package/dist/db/schema/beliefs.d.ts +9 -0
- package/dist/db/schema/beliefs.js +46 -0
- package/dist/db/schema/generator.d.ts +38 -0
- package/dist/db/schema/generator.js +108 -0
- package/dist/db/schema/index.d.ts +19 -20
- package/dist/db/schema/index.js +25 -79
- package/dist/db/schema/learnings.d.ts +7 -0
- package/dist/db/schema/learnings.js +30 -0
- package/dist/db/schema/memories.d.ts +7 -0
- package/dist/db/schema/memories.js +81 -0
- package/dist/db/schema/projects.d.ts +4 -0
- package/dist/db/schema/projects.js +31 -0
- package/dist/packages/mcp/src/index.d.ts +3 -0
- package/dist/packages/mcp/src/index.js +733 -0
- package/mcp.json.example +8 -11
- package/package.json +57 -76
- package/packages/cli/package.json +22 -0
- package/packages/cli/src/commands/clean.ts +68 -0
- package/packages/cli/src/commands/context.ts +79 -0
- package/packages/cli/src/commands/doctor.ts +357 -0
- package/packages/cli/src/commands/forget.ts +72 -0
- package/packages/cli/src/commands/health.ts +36 -0
- package/packages/cli/src/commands/inspect.ts +41 -0
- package/packages/cli/src/commands/link.ts +50 -0
- package/packages/cli/src/commands/migrate.ts +93 -0
- package/packages/cli/src/commands/recall.ts +99 -0
- package/packages/cli/src/commands/recent.ts +57 -0
- package/packages/cli/src/commands/remember.ts +139 -0
- package/packages/cli/src/commands/run.ts +58 -0
- package/packages/cli/src/commands/stale.ts +43 -0
- package/packages/cli/src/commands/stats.ts +42 -0
- package/packages/cli/src/index.ts +57 -0
- package/packages/cli/tsconfig.json +24 -0
- package/packages/mcp/package.json +26 -0
- package/packages/mcp/src/index.ts +877 -0
- package/packages/mcp/tsconfig.json +20 -0
- package/skills/squish-memory/SKILL.md +38 -35
- package/skills/squish-memory/{scripts/install.sh → install.sh} +1 -1
- package/skills/squish-memory/references/claude-desktop.json +12 -0
- package/skills/squish-memory/references/openclaw.json +13 -0
- package/skills/squish-memory/references/opencode.json +14 -0
- package/config/hooks/claude-code-hooks.json +0 -39
- package/config/hooks/cursor-hooks.json +0 -30
- package/config/hooks/opencode-hooks.json +0 -30
- package/config/hooks/windsurf-hooks.json +0 -30
- package/config/mcp-cli-fallback-policy.json +0 -22
- package/config/mcp.json +0 -38
- package/config/plugin-manifest.json +0 -101
- package/config/plugin-manifest.schema.json +0 -244
- package/config/plugin.json +0 -32
- package/config/remote-memory-policy.json +0 -32
- package/core/commands/context-paging.md +0 -51
- package/core/commands/context-status.md +0 -22
- package/core/commands/context.md +0 -5
- package/core/commands/core-memory.md +0 -56
- package/core/commands/health.md +0 -5
- package/core/commands/init.md +0 -39
- package/core/commands/merge.md +0 -113
- package/core/commands/recall.md +0 -5
- package/core/commands/remember.md +0 -11
- package/core/commands/search.md +0 -10
- package/dist/core/commands/managed-sync.d.ts +0 -10
- package/dist/core/commands/managed-sync.js +0 -64
- package/dist/core/external-folder/index.d.ts +0 -102
- package/dist/core/external-folder/index.js +0 -294
- package/dist/core/namespaces/index.d.ts +0 -71
- package/dist/core/namespaces/index.js +0 -305
- package/dist/core/namespaces/uri-parser.d.ts +0 -31
- package/dist/core/namespaces/uri-parser.js +0 -74
- package/dist/core/search/qmd-search.d.ts +0 -61
- package/dist/core/search/qmd-search.js +0 -178
- package/dist/core/session-hooks/self-iteration-job.d.ts +0 -20
- package/dist/core/session-hooks/self-iteration-job.js +0 -282
- package/dist/core/session-hooks/session-hooks.d.ts +0 -18
- package/dist/core/session-hooks/session-hooks.js +0 -58
- package/dist/core/snapshots.d.ts +0 -29
- package/dist/core/snapshots.js +0 -220
- package/dist/core/sync/qmd-sync.d.ts +0 -94
- package/dist/core/sync/qmd-sync.js +0 -201
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -1677
- package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
- package/dist/webui/server.d.ts +0 -5
- package/dist/webui/server.js +0 -642
- package/generated/mcp/manifest.json +0 -23
- package/generated/mcp/mcp-servers.json +0 -25
- package/generated/mcp/mcporter.json +0 -34
- package/generated/mcp/openclaw-memory-qmd.json +0 -17
- package/generated/mcp/runtime.json +0 -12
- package/scripts/README.md +0 -60
- package/scripts/build-release.sh +0 -36
- package/scripts/check-secrets.js +0 -132
- package/scripts/copy-runtime-assets.mjs +0 -26
- package/scripts/generate-mcp.mjs +0 -264
- package/scripts/github-release.sh +0 -77
- package/scripts/init-dirs.mjs +0 -13
- package/scripts/install-claude-code.sh +0 -85
- package/scripts/install-cursor.sh +0 -56
- package/scripts/install-hooks.sh +0 -73
- package/scripts/install-interactive.mjs +0 -357
- package/scripts/install-opencode.sh +0 -75
- package/scripts/install-plugin.mjs +0 -415
- package/scripts/install-windsurf.sh +0 -67
- package/scripts/remote-preflight.mjs +0 -62
- package/scripts/squish-fallback.mjs +0 -132
- package/scripts/test-interactive.mjs +0 -131
- package/scripts/verify-mcp.mjs +0 -214
- package/skills/squish-memory/scripts/install.mjs +0 -335
- package/skills/squish-memory/write_skill.js +0 -2
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { eq, desc, and, sql } from 'drizzle-orm';
|
|
3
|
+
import { getDb } from '../../db/index.js';
|
|
4
|
+
import { getSchema } from '../../db/schema.js';
|
|
5
|
+
import { createDatabaseClient } from '../storage/database.js';
|
|
6
|
+
|
|
7
|
+
export interface LightweightIndex {
|
|
8
|
+
id: string;
|
|
9
|
+
memoryId: string;
|
|
10
|
+
contentHash: string;
|
|
11
|
+
contentPreview: string;
|
|
12
|
+
keyTerms: string[];
|
|
13
|
+
category: string;
|
|
14
|
+
importance: number;
|
|
15
|
+
createdAt: Date;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MemoryPreview {
|
|
19
|
+
id: string;
|
|
20
|
+
type: string;
|
|
21
|
+
contentPreview: string;
|
|
22
|
+
keyTerms: string[];
|
|
23
|
+
category: string;
|
|
24
|
+
importance: number;
|
|
25
|
+
lastAccessedAt?: Date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FullMemoryLoad {
|
|
29
|
+
id: string;
|
|
30
|
+
content: string;
|
|
31
|
+
summary?: string;
|
|
32
|
+
tags: string[];
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TokenBudgetStatus {
|
|
37
|
+
budget: number;
|
|
38
|
+
used: number;
|
|
39
|
+
remaining: number;
|
|
40
|
+
loadedCount: number;
|
|
41
|
+
preloadCount: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const PREVIEW_TOKENS = 50;
|
|
45
|
+
const MAX_PRELOAD_CANDIDATES = 20;
|
|
46
|
+
const TOKEN_ESTIMATE_CHARS = 4;
|
|
47
|
+
|
|
48
|
+
export async function createLightweightIndex(
|
|
49
|
+
memoryId: string,
|
|
50
|
+
content: string,
|
|
51
|
+
category: string,
|
|
52
|
+
importance: number
|
|
53
|
+
): Promise<LightweightIndex> {
|
|
54
|
+
const db = createDatabaseClient(await getDb());
|
|
55
|
+
const schema = await getSchema();
|
|
56
|
+
|
|
57
|
+
const contentHash = hashContent(content);
|
|
58
|
+
const contentPreview = extractPreview(content);
|
|
59
|
+
const keyTerms = extractKeyTerms(content);
|
|
60
|
+
|
|
61
|
+
const index: LightweightIndex = {
|
|
62
|
+
id: randomUUID(),
|
|
63
|
+
memoryId,
|
|
64
|
+
contentHash,
|
|
65
|
+
contentPreview,
|
|
66
|
+
keyTerms,
|
|
67
|
+
category,
|
|
68
|
+
importance,
|
|
69
|
+
createdAt: new Date(),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
await db.insert(schema.lightweightMemoryIndices).values({
|
|
73
|
+
id: index.id,
|
|
74
|
+
memoryId: index.memoryId,
|
|
75
|
+
contentHash: index.contentHash,
|
|
76
|
+
contentPreview: index.contentPreview,
|
|
77
|
+
keyTerms: JSON.stringify(index.keyTerms),
|
|
78
|
+
category: index.category,
|
|
79
|
+
importanceScore: index.importance,
|
|
80
|
+
createdAt: index.createdAt,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return index;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function searchLightweightIndices(
|
|
87
|
+
projectId: string,
|
|
88
|
+
query: string,
|
|
89
|
+
limit: number = 10
|
|
90
|
+
): Promise<MemoryPreview[]> {
|
|
91
|
+
const db = createDatabaseClient(await getDb());
|
|
92
|
+
const schema = await getSchema();
|
|
93
|
+
|
|
94
|
+
const queryLower = query.toLowerCase();
|
|
95
|
+
const queryTerms = queryLower.split(/\s+/).filter((t) => t.length > 2);
|
|
96
|
+
|
|
97
|
+
const results = await db
|
|
98
|
+
.select({
|
|
99
|
+
id: schema.lightweightMemoryIndices.id,
|
|
100
|
+
memoryId: schema.lightweightMemoryIndices.memoryId,
|
|
101
|
+
contentPreview: schema.lightweightMemoryIndices.contentPreview,
|
|
102
|
+
keyTerms: schema.lightweightMemoryIndices.keyTerms,
|
|
103
|
+
category: schema.lightweightMemoryIndices.category,
|
|
104
|
+
importanceScore: schema.lightweightMemoryIndices.importanceScore,
|
|
105
|
+
lastAccessedAt: schema.memories.lastAccessedAt,
|
|
106
|
+
})
|
|
107
|
+
.from(schema.lightweightMemoryIndices)
|
|
108
|
+
.leftJoin(
|
|
109
|
+
schema.memories,
|
|
110
|
+
eq(schema.lightweightMemoryIndices.memoryId, schema.memories.id)
|
|
111
|
+
)
|
|
112
|
+
.where(eq(schema.lightweightMemoryIndices.memoryId, schema.memories.id))
|
|
113
|
+
.limit(limit * 2);
|
|
114
|
+
|
|
115
|
+
const scored = results.map((row: any) => {
|
|
116
|
+
let score = (row.importanceScore as number) ?? 50;
|
|
117
|
+
const keyTerms: string[] = typeof row.keyTerms === 'string'
|
|
118
|
+
? JSON.parse(row.keyTerms as string)
|
|
119
|
+
: (row.keyTerms as string[]) ?? [];
|
|
120
|
+
const termsLower = keyTerms.map((t: string) => t.toLowerCase());
|
|
121
|
+
|
|
122
|
+
for (const term of queryTerms) {
|
|
123
|
+
if (row.contentPreview.toLowerCase().includes(term)) {
|
|
124
|
+
score += 10;
|
|
125
|
+
}
|
|
126
|
+
if (termsLower.some((t: string) => t.includes(term))) {
|
|
127
|
+
score += 15;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
id: row.id as string,
|
|
133
|
+
memoryId: row.memoryId as string,
|
|
134
|
+
contentPreview: row.contentPreview as string,
|
|
135
|
+
keyTerms,
|
|
136
|
+
category: row.category as string,
|
|
137
|
+
importance: (row.importanceScore as number) ?? 50,
|
|
138
|
+
lastAccessedAt: row.lastAccessedAt as Date | undefined,
|
|
139
|
+
score,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
scored.sort((a: any, b: any) => b.score - a.score);
|
|
144
|
+
|
|
145
|
+
return scored.slice(0, limit).map((item: any) => ({
|
|
146
|
+
id: item.memoryId,
|
|
147
|
+
type: 'preview',
|
|
148
|
+
contentPreview: item.contentPreview,
|
|
149
|
+
keyTerms: item.keyTerms,
|
|
150
|
+
category: item.category,
|
|
151
|
+
importance: item.importance,
|
|
152
|
+
lastAccessedAt: item.lastAccessedAt,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function loadFullMemory(memoryId: string): Promise<FullMemoryLoad | null> {
|
|
157
|
+
const db = createDatabaseClient(await getDb());
|
|
158
|
+
const schema = await getSchema();
|
|
159
|
+
|
|
160
|
+
const rows = await db
|
|
161
|
+
.select()
|
|
162
|
+
.from(schema.memories)
|
|
163
|
+
.where(eq(schema.memories.id, memoryId))
|
|
164
|
+
.limit(1);
|
|
165
|
+
|
|
166
|
+
if (rows.length === 0) return null;
|
|
167
|
+
|
|
168
|
+
const row = rows[0];
|
|
169
|
+
return {
|
|
170
|
+
id: row.id,
|
|
171
|
+
content: row.content,
|
|
172
|
+
summary: row.summary ?? undefined,
|
|
173
|
+
tags: Array.isArray(row.tags) ? row.tags : [],
|
|
174
|
+
metadata: row.metadata ?? undefined,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export async function estimateTokenCount(text: string): Promise<number> {
|
|
179
|
+
return Math.ceil(text.length / TOKEN_ESTIMATE_CHARS);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export async function allocateTokenBudget(
|
|
183
|
+
sessionId: string,
|
|
184
|
+
budget: number
|
|
185
|
+
): Promise<TokenBudgetStatus> {
|
|
186
|
+
const db = createDatabaseClient(await getDb());
|
|
187
|
+
const schema = await getSchema();
|
|
188
|
+
|
|
189
|
+
const [session] = await db
|
|
190
|
+
.select()
|
|
191
|
+
.from(schema.contextPagingSessions)
|
|
192
|
+
.where(eq(schema.contextPagingSessions.sessionId, sessionId))
|
|
193
|
+
.limit(1);
|
|
194
|
+
|
|
195
|
+
if (!session) {
|
|
196
|
+
return {
|
|
197
|
+
budget,
|
|
198
|
+
used: 0,
|
|
199
|
+
remaining: budget,
|
|
200
|
+
loadedCount: 0,
|
|
201
|
+
preloadCount: 0,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const tokensUsed = session.tokensUsed ?? 0;
|
|
206
|
+
const loadedCount = (session.loadedMemoryIds as string[])?.length ?? 0;
|
|
207
|
+
const preloadCount = (session.preloadCandidateIds as string[])?.length ?? 0;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
budget,
|
|
211
|
+
used: tokensUsed,
|
|
212
|
+
remaining: Math.max(0, budget - tokensUsed),
|
|
213
|
+
loadedCount,
|
|
214
|
+
preloadCount,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function preloadCandidateMemories(
|
|
219
|
+
sessionId: string,
|
|
220
|
+
projectId: string,
|
|
221
|
+
budget: number,
|
|
222
|
+
excludeLoadedIds: string[]
|
|
223
|
+
): Promise<string[]> {
|
|
224
|
+
const status = await allocateTokenBudget(sessionId, budget);
|
|
225
|
+
const availableTokens = status.remaining;
|
|
226
|
+
|
|
227
|
+
if (availableTokens < PREVIEW_TOKENS * 2) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const db = createDatabaseClient(await getDb());
|
|
232
|
+
const schema = await getSchema();
|
|
233
|
+
|
|
234
|
+
const rows = await db
|
|
235
|
+
.select({
|
|
236
|
+
id: schema.memories.id,
|
|
237
|
+
content: schema.memories.content,
|
|
238
|
+
importanceScore: schema.memories.importanceScore,
|
|
239
|
+
lastAccessedAt: schema.memories.lastAccessedAt,
|
|
240
|
+
})
|
|
241
|
+
.from(schema.memories)
|
|
242
|
+
.where(
|
|
243
|
+
and(
|
|
244
|
+
eq(schema.memories.projectId, projectId),
|
|
245
|
+
eq(schema.memories.isActive, true),
|
|
246
|
+
excludeLoadedIds.length > 0
|
|
247
|
+
? sql`${schema.memories.id} NOT IN (${excludeLoadedIds.map(id => `'${id.replace(/'/g, "''")}'`).join(',')})`
|
|
248
|
+
: sql`TRUE`
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
.orderBy(desc(schema.memories.importanceScore), desc(schema.memories.lastAccessedAt))
|
|
252
|
+
.limit(MAX_PRELOAD_CANDIDATES);
|
|
253
|
+
|
|
254
|
+
const candidates: string[] = [];
|
|
255
|
+
let tokensForPreload = Math.min(availableTokens - PREVIEW_TOKENS, availableTokens * 0.3);
|
|
256
|
+
|
|
257
|
+
for (const row of rows) {
|
|
258
|
+
const tokens = await estimateTokenCount(row.content ?? '');
|
|
259
|
+
if (tokens <= tokensForPreload) {
|
|
260
|
+
candidates.push(row.id as string);
|
|
261
|
+
tokensForPreload -= tokens;
|
|
262
|
+
}
|
|
263
|
+
if (candidates.length >= 5) break;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
await db
|
|
267
|
+
.update(schema.contextPagingSessions)
|
|
268
|
+
.set({
|
|
269
|
+
preloadCandidateIds: candidates,
|
|
270
|
+
updatedAt: new Date(),
|
|
271
|
+
})
|
|
272
|
+
.where(eq(schema.contextPagingSessions.sessionId, sessionId));
|
|
273
|
+
|
|
274
|
+
return candidates;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export async function getPreloadCandidates(sessionId: string): Promise<MemoryPreview[]> {
|
|
278
|
+
const db = createDatabaseClient(await getDb());
|
|
279
|
+
const schema = await getSchema();
|
|
280
|
+
|
|
281
|
+
const [session] = await db
|
|
282
|
+
.select()
|
|
283
|
+
.from(schema.contextPagingSessions)
|
|
284
|
+
.where(eq(schema.contextPagingSessions.sessionId, sessionId))
|
|
285
|
+
.limit(1);
|
|
286
|
+
|
|
287
|
+
if (!session) return [];
|
|
288
|
+
|
|
289
|
+
const candidateIds = (session.preloadCandidateIds as string[]) ?? [];
|
|
290
|
+
if (candidateIds.length === 0) return [];
|
|
291
|
+
|
|
292
|
+
const previews: MemoryPreview[] = [];
|
|
293
|
+
for (const memoryId of candidateIds.slice(0, 5)) {
|
|
294
|
+
const [index] = await db
|
|
295
|
+
.select()
|
|
296
|
+
.from(schema.lightweightMemoryIndices)
|
|
297
|
+
.where(eq(schema.lightweightMemoryIndices.memoryId, memoryId))
|
|
298
|
+
.limit(1);
|
|
299
|
+
|
|
300
|
+
if (index) {
|
|
301
|
+
const keyTerms: string[] = typeof index.keyTerms === 'string'
|
|
302
|
+
? JSON.parse(index.keyTerms as string)
|
|
303
|
+
: (index.keyTerms as string[]) ?? [];
|
|
304
|
+
|
|
305
|
+
previews.push({
|
|
306
|
+
id: index.memoryId as string,
|
|
307
|
+
type: 'preload',
|
|
308
|
+
contentPreview: index.contentPreview as string,
|
|
309
|
+
keyTerms,
|
|
310
|
+
category: index.category as string,
|
|
311
|
+
importance: (index.importanceScore as number) ?? 50,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return previews;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export async function updateIndexImportance(
|
|
320
|
+
memoryId: string,
|
|
321
|
+
importance: number
|
|
322
|
+
): Promise<void> {
|
|
323
|
+
const db = createDatabaseClient(await getDb());
|
|
324
|
+
const schema = await getSchema();
|
|
325
|
+
|
|
326
|
+
await db
|
|
327
|
+
.update(schema.lightweightMemoryIndices)
|
|
328
|
+
.set({
|
|
329
|
+
importanceScore: importance,
|
|
330
|
+
})
|
|
331
|
+
.where(eq(schema.lightweightMemoryIndices.memoryId, memoryId));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function deleteLightweightIndex(memoryId: string): Promise<void> {
|
|
335
|
+
const db = createDatabaseClient(await getDb());
|
|
336
|
+
const schema = await getSchema();
|
|
337
|
+
|
|
338
|
+
await db
|
|
339
|
+
.delete(schema.lightweightMemoryIndices)
|
|
340
|
+
.where(eq(schema.lightweightMemoryIndices.memoryId, memoryId));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function hashContent(content: string): string {
|
|
344
|
+
let hash = 0;
|
|
345
|
+
for (let i = 0; i < content.length; i++) {
|
|
346
|
+
const char = content.charCodeAt(i);
|
|
347
|
+
hash = ((hash << 5) - hash) + char;
|
|
348
|
+
hash = hash & hash;
|
|
349
|
+
}
|
|
350
|
+
return Math.abs(hash).toString(36);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function extractPreview(content: string): string {
|
|
354
|
+
const firstPeriod = content.indexOf('.');
|
|
355
|
+
const firstNewline = content.indexOf('\n');
|
|
356
|
+
|
|
357
|
+
let endIndex = content.length;
|
|
358
|
+
if (firstPeriod > 0 && firstPeriod < 100) {
|
|
359
|
+
endIndex = firstPeriod + 1;
|
|
360
|
+
} else if (firstNewline > 0 && firstNewline < 100) {
|
|
361
|
+
endIndex = firstNewline;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return content.substring(0, Math.min(endIndex, 150)).trim();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function extractKeyTerms(content: string): string[] {
|
|
368
|
+
const words = content.toLowerCase()
|
|
369
|
+
.replace(/[^\w\s]/g, ' ')
|
|
370
|
+
.split(/\s+/)
|
|
371
|
+
.filter((w) => w.length > 3);
|
|
372
|
+
|
|
373
|
+
const stopWords = new Set([
|
|
374
|
+
'this', 'that', 'with', 'from', 'have', 'been', 'were', 'they',
|
|
375
|
+
'their', 'which', 'about', 'would', 'could', 'should', 'there',
|
|
376
|
+
'what', 'when', 'where', 'who', 'will', 'just', 'like', 'into',
|
|
377
|
+
'than', 'then', 'both', 'each', 'more', 'most', 'other', 'some',
|
|
378
|
+
'such', 'only', 'over', 'very', 'also', 'back', 'after', 'being',
|
|
379
|
+
]);
|
|
380
|
+
|
|
381
|
+
const termCounts: Record<string, number> = {};
|
|
382
|
+
for (const word of words) {
|
|
383
|
+
if (!stopWords.has(word) && !/^\d+$/.test(word)) {
|
|
384
|
+
termCounts[word] = (termCounts[word] ?? 0) + 1;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return Object.entries(termCounts)
|
|
389
|
+
.sort((a, b) => b[1] - a[1])
|
|
390
|
+
.slice(0, 5)
|
|
391
|
+
.map(([term]) => term);
|
|
392
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Processor - Phase 4
|
|
3
|
+
* Expands queries for better retrieval coverage
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ProcessedQuery {
|
|
7
|
+
original: string;
|
|
8
|
+
expanded: string[];
|
|
9
|
+
entities: string[];
|
|
10
|
+
synonyms: Map<string, string[]>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Simple synonym expansion without LLM calls
|
|
15
|
+
* Fast, deterministic, no API costs
|
|
16
|
+
*/
|
|
17
|
+
export function expandQuery(query: string): ProcessedQuery {
|
|
18
|
+
const synonyms = new Map<string, string[]>();
|
|
19
|
+
|
|
20
|
+
// Define common synonym mappings
|
|
21
|
+
const synonymMap: Record<string, string[]> = {
|
|
22
|
+
'manager': ['manager', 'boss', 'supervisor', 'lead'],
|
|
23
|
+
'team': ['team', 'group', 'staff', 'crew'],
|
|
24
|
+
'project': ['project', 'initiative', 'endeavor', 'work'],
|
|
25
|
+
'start': ['start', 'begin', 'commence', 'initiate'],
|
|
26
|
+
'budget': ['budget', 'funding', 'cost', 'allocation'],
|
|
27
|
+
'language': ['language', 'tech', 'stack', 'technology'],
|
|
28
|
+
'feature': ['feature', 'capability', 'function', 'aspect'],
|
|
29
|
+
'based': ['based', 'located', 'situated', 'headquartered'],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const lowerQuery = query.toLowerCase();
|
|
33
|
+
|
|
34
|
+
// Find matching synonyms
|
|
35
|
+
for (const [key, values] of Object.entries(synonymMap)) {
|
|
36
|
+
if (lowerQuery.includes(key)) {
|
|
37
|
+
synonyms.set(key, values);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Generate expanded queries by substituting synonyms
|
|
42
|
+
const expanded: string[] = [query]; // Original
|
|
43
|
+
|
|
44
|
+
// Add one variation per synonym found
|
|
45
|
+
for (const [term, variants] of synonyms) {
|
|
46
|
+
for (const variant of variants) {
|
|
47
|
+
if (variant !== term) {
|
|
48
|
+
expanded.push(query.replace(new RegExp(term, 'gi'), variant));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract entities (capitalized words), filtering common stopwords
|
|
54
|
+
const STOP_WORDS = new Set([
|
|
55
|
+
'The', 'A', 'An', 'This', 'That', 'These', 'Those',
|
|
56
|
+
'I', 'You', 'We', 'They', 'He', 'She', 'It',
|
|
57
|
+
'What', 'When', 'Where', 'Why', 'How',
|
|
58
|
+
'My', 'Your', 'Our', 'Their', 'Its',
|
|
59
|
+
'If', 'But', 'Or', 'And', 'So', 'Then',
|
|
60
|
+
'Just', 'Only', 'Also', 'Very', 'Too',
|
|
61
|
+
'Has', 'Have', 'Had', 'Does', 'Did', 'Will', 'Would', 'Could', 'Should',
|
|
62
|
+
'Can', 'May', 'Might', 'Must', 'Shall',
|
|
63
|
+
'With', 'Without', 'From', 'Into', 'About', 'After', 'Before', 'Between',
|
|
64
|
+
'During', 'Through', 'Under', 'Over', 'Above', 'Below',
|
|
65
|
+
'All', 'Some', 'Any', 'No', 'Not', 'Each', 'Every', 'Most', 'Many', 'Much',
|
|
66
|
+
'Few', 'Both', 'Either', 'Neither', 'Another', 'Other',
|
|
67
|
+
'Such', 'Same', 'Different', 'New', 'Old', 'First', 'Last', 'Next', 'Last',
|
|
68
|
+
'See', 'Get', 'Make', 'Do', 'Say', 'Tell', 'Know', 'Think', 'Want', 'Use',
|
|
69
|
+
'Find', 'Give', 'Take', 'Show', 'Send', 'Put', 'Keep', 'Let', 'Begin', 'Seem',
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
// Common tech stack terms that ARE entities (preserves known entities)
|
|
73
|
+
const TECH_TERMS = new Set([
|
|
74
|
+
'TypeScript', 'JavaScript', 'Python', 'Java', 'Go', 'Rust', 'Ruby', 'PHP',
|
|
75
|
+
'React', 'Vue', 'Angular', 'Svelte', 'Next', 'Nuxt', 'Astro',
|
|
76
|
+
'Node', 'Express', 'Fastify', 'Deno', 'Bun',
|
|
77
|
+
'PostgreSQL', 'MySQL', 'MongoDB', 'Redis', 'SQLite', 'DynamoDB',
|
|
78
|
+
'AWS', 'GCP', 'Azure', 'Docker', 'Kubernetes', 'Terraform',
|
|
79
|
+
'OpenAI', 'Anthropic', 'Google', 'Meta', 'Microsoft', 'Apple',
|
|
80
|
+
'HTML', 'CSS', 'Tailwind', 'GraphQL', 'REST', 'gRPC', 'WebSocket',
|
|
81
|
+
'CI', 'CD', 'Git', 'GitHub', 'GitLab', 'Bitbucket',
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
const entityMatches = query.match(/\b[A-Z][a-z]{2,}\b/g) || [];
|
|
85
|
+
const entities = [...new Set(entityMatches)].filter(e => {
|
|
86
|
+
// Always include known tech terms
|
|
87
|
+
if (TECH_TERMS.has(e)) return true;
|
|
88
|
+
// Filter out stopwords
|
|
89
|
+
return !STOP_WORDS.has(e);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
original: query,
|
|
94
|
+
expanded: [...new Set(expanded)], // Deduplicate
|
|
95
|
+
entities,
|
|
96
|
+
synonyms,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Multi-query search combiner
|
|
102
|
+
* Searches with multiple query variants and merges results
|
|
103
|
+
*/
|
|
104
|
+
export async function multiQuerySearch<T>(
|
|
105
|
+
queries: string[],
|
|
106
|
+
searchFn: (query: string) => Promise<T[]>,
|
|
107
|
+
dedupeKey: (item: T) => string
|
|
108
|
+
): Promise<T[]> {
|
|
109
|
+
const allResults: T[] = [];
|
|
110
|
+
|
|
111
|
+
// Search with each query variant
|
|
112
|
+
for (const query of queries) {
|
|
113
|
+
const results = await searchFn(query);
|
|
114
|
+
allResults.push(...results);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Deduplicate by key
|
|
118
|
+
const seen = new Set<string>();
|
|
119
|
+
const unique: T[] = [];
|
|
120
|
+
|
|
121
|
+
for (const item of allResults) {
|
|
122
|
+
const key = dedupeKey(item);
|
|
123
|
+
if (!seen.has(key)) {
|
|
124
|
+
seen.add(key);
|
|
125
|
+
unique.push(item);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return unique;
|
|
130
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/** Query Rewriter - Rewrite user queries for better retrieval using LLM */
|
|
2
|
+
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
|
+
import { config } from '../../config.js';
|
|
5
|
+
import { formatContextForLLM, type ContextMessage } from './context-collector.js';
|
|
6
|
+
import { expandQuery } from './query-processor.js';
|
|
7
|
+
|
|
8
|
+
export interface RewriteResult {
|
|
9
|
+
original: string;
|
|
10
|
+
rewritten: string;
|
|
11
|
+
expansions: string[];
|
|
12
|
+
intent: 'search' | 'recall' | 'question' | 'context';
|
|
13
|
+
confidence: number;
|
|
14
|
+
method: 'llm' | 'synonym' | 'none';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const REWRITE_SYSTEM_PROMPT = `You are a search query optimizer. Given a conversation context and a user's latest message, rewrite the message into the single most effective search query to retrieve relevant memories.
|
|
18
|
+
|
|
19
|
+
Rules:
|
|
20
|
+
1. Output ONLY the optimized search query - no explanations or extra text
|
|
21
|
+
2. Remove filler words (please, can you, etc.)
|
|
22
|
+
3. Focus on the core information need
|
|
23
|
+
4. Preserve important entities (names, dates, technical terms)
|
|
24
|
+
5. Add synonyms for key terms if helpful
|
|
25
|
+
6. Consider what memories would be most relevant
|
|
26
|
+
7. If the message is about recalling something specific, include those details`;
|
|
27
|
+
|
|
28
|
+
export async function rewriteQuery(
|
|
29
|
+
query: string,
|
|
30
|
+
context: ContextMessage[]
|
|
31
|
+
): Promise<RewriteResult> {
|
|
32
|
+
if (!config.queryRewritingEnabled) {
|
|
33
|
+
return {
|
|
34
|
+
original: query,
|
|
35
|
+
rewritten: query,
|
|
36
|
+
expansions: [],
|
|
37
|
+
intent: detectIntent(query),
|
|
38
|
+
confidence: 1.0,
|
|
39
|
+
method: 'none',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (config.queryRewritingFallbackEnabled) {
|
|
44
|
+
try {
|
|
45
|
+
const llmResult = await rewriteWithLLM(query, context);
|
|
46
|
+
if (llmResult) return llmResult;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.warn(`[QueryRewriter] LLM rewrite failed, falling back to synonym: ${error instanceof Error ? error.message : String(error)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (config.queryRewritingFallbackEnabled) {
|
|
53
|
+
const expanded = expandQuery(query);
|
|
54
|
+
return {
|
|
55
|
+
original: query,
|
|
56
|
+
rewritten: expanded.expanded[0] || query,
|
|
57
|
+
expansions: expanded.expanded.slice(1),
|
|
58
|
+
intent: detectIntent(query),
|
|
59
|
+
confidence: 0.7,
|
|
60
|
+
method: 'synonym',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
original: query,
|
|
66
|
+
rewritten: query,
|
|
67
|
+
expansions: [],
|
|
68
|
+
intent: detectIntent(query),
|
|
69
|
+
confidence: 1.0,
|
|
70
|
+
method: 'none',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function rewriteWithLLM(
|
|
75
|
+
query: string,
|
|
76
|
+
context: ContextMessage[]
|
|
77
|
+
): Promise<RewriteResult | null> {
|
|
78
|
+
if (context.length < 2) return null;
|
|
79
|
+
|
|
80
|
+
const lastUserMsg = context.filter(m => m.role === 'user').pop()?.content || '';
|
|
81
|
+
|
|
82
|
+
const pronounPattern = /\b(it|that|this|they|them|those|these|he|she|his|her)\b/i;
|
|
83
|
+
const hasPronouns = pronounPattern.test(query);
|
|
84
|
+
|
|
85
|
+
const vaguePattern = /\b(the thing|the stuff|what (we|I) (talked|discussed|mentioned))\b/i;
|
|
86
|
+
const hasVagueRef = vaguePattern.test(query);
|
|
87
|
+
|
|
88
|
+
if (!hasPronouns && !hasVagueRef) return null;
|
|
89
|
+
|
|
90
|
+
let rewritten = query;
|
|
91
|
+
|
|
92
|
+
const entityPattern = /\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/g;
|
|
93
|
+
const contextEntities = lastUserMsg.match(entityPattern) || [];
|
|
94
|
+
|
|
95
|
+
const techPattern = /\b([a-z]+\.(?:ts|js|py|json|md)|@[a-z]+\/[a-z]+|\b[A-Z]{2,}\b)\b/gi;
|
|
96
|
+
const techTerms = lastUserMsg.match(techPattern) || [];
|
|
97
|
+
|
|
98
|
+
if (contextEntities.length > 0 && hasPronouns) {
|
|
99
|
+
const mostLikelyEntity = contextEntities[contextEntities.length - 1];
|
|
100
|
+
if (!query.toLowerCase().includes(mostLikelyEntity.toLowerCase())) {
|
|
101
|
+
rewritten = `${query} ${mostLikelyEntity}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const firstTechTerm = techTerms[0];
|
|
106
|
+
if (firstTechTerm && !query.includes(firstTechTerm)) {
|
|
107
|
+
rewritten = `${rewritten} ${firstTechTerm}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (rewritten !== query) {
|
|
111
|
+
logger.info(`[QueryRewriter] Rewrote "${query}" -> "${rewritten}"`);
|
|
112
|
+
return {
|
|
113
|
+
original: query,
|
|
114
|
+
rewritten,
|
|
115
|
+
expansions: [],
|
|
116
|
+
intent: detectIntent(query),
|
|
117
|
+
confidence: 0.8,
|
|
118
|
+
method: 'llm',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function detectIntent(query: string): 'search' | 'recall' | 'question' | 'context' {
|
|
126
|
+
const lower = query.toLowerCase();
|
|
127
|
+
|
|
128
|
+
if (/\b(remember|recall|what did (we|I)|what was|retrieve)\b/.test(lower)) {
|
|
129
|
+
return 'recall';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (/^(what|who|when|where|why|how|which|is|are|can|do|does)/.test(lower)) {
|
|
133
|
+
return 'question';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (/\b(context|background|about|regarding|concerning)\b/.test(lower)) {
|
|
137
|
+
return 'context';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return 'search';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function wouldBenefitFromRewrite(query: string): boolean {
|
|
144
|
+
if (query.split(/\s+/).length < 3) return true;
|
|
145
|
+
|
|
146
|
+
const pronounPattern = /\b(it|that|this|they|them|those|these|he|she|his|her)\b/i;
|
|
147
|
+
if (pronounPattern.test(query)) return true;
|
|
148
|
+
|
|
149
|
+
const vaguePattern = /\b(the thing|the stuff|what (we|I) (talked|discussed|mentioned))\b/i;
|
|
150
|
+
if (vaguePattern.test(query)) return true;
|
|
151
|
+
|
|
152
|
+
return false;
|
|
153
|
+
}
|