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,81 @@
|
|
|
1
|
+
/** Response Analyzer - Analyze LLM responses for memory references (Echo/Fizzle tracking) */
|
|
2
|
+
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
|
+
|
|
5
|
+
export interface AnalysisResult {
|
|
6
|
+
referencedMemoryIds: string[];
|
|
7
|
+
referenceCount: number;
|
|
8
|
+
hasReferences: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const REFERENCE_PATTERNS = [
|
|
12
|
+
/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,
|
|
13
|
+
/as (?:i |we )?(?:mentioned|noted|remembered|recalled|stored|saved)/gi,
|
|
14
|
+
/(?:based|drawing) on (?:my|our|the) (?:memory|previous|earlier)/gi,
|
|
15
|
+
/(?:i |we )?(?:recall|remember|noted) (?:that |earlier )?/gi,
|
|
16
|
+
/from (?:my|our|the) (?:memory|notes|records)/gi,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export function analyzeResponseForMemoryReferences(
|
|
20
|
+
responseText: string,
|
|
21
|
+
injectedMemoryIds: string[],
|
|
22
|
+
injectedMemoryContent: Map<string, string>
|
|
23
|
+
): AnalysisResult {
|
|
24
|
+
const referencedMemoryIds: string[] = [];
|
|
25
|
+
const responseLower = responseText.toLowerCase();
|
|
26
|
+
|
|
27
|
+
for (const memoryId of injectedMemoryIds) {
|
|
28
|
+
if (responseText.includes(memoryId)) {
|
|
29
|
+
referencedMemoryIds.push(memoryId);
|
|
30
|
+
logger.debug(`[ResponseAnalyzer] Direct reference found: ${memoryId}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const [memoryId, content] of injectedMemoryContent) {
|
|
35
|
+
if (referencedMemoryIds.includes(memoryId)) continue;
|
|
36
|
+
|
|
37
|
+
const contentWords = content.toLowerCase().split(/\s+/).filter(w => w.length > 3);
|
|
38
|
+
if (contentWords.length < 5) continue;
|
|
39
|
+
|
|
40
|
+
let matchCount = 0;
|
|
41
|
+
for (const word of contentWords) {
|
|
42
|
+
if (responseLower.includes(word)) {
|
|
43
|
+
matchCount++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const matchRatio = matchCount / contentWords.length;
|
|
48
|
+
if (matchRatio > 0.5) {
|
|
49
|
+
referencedMemoryIds.push(memoryId);
|
|
50
|
+
logger.debug(`[ResponseAnalyzer] Content match (${(matchRatio * 100).toFixed(0)}%): ${memoryId}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const pattern of REFERENCE_PATTERNS) {
|
|
55
|
+
const matches = responseText.match(pattern);
|
|
56
|
+
if (matches && matches.length > 0) {
|
|
57
|
+
logger.debug(`[ResponseAnalyzer] Reference pattern found: ${matches.length} matches`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const result: AnalysisResult = {
|
|
62
|
+
referencedMemoryIds: [...new Set(referencedMemoryIds)],
|
|
63
|
+
referenceCount: referencedMemoryIds.length,
|
|
64
|
+
hasReferences: referencedMemoryIds.length > 0,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (result.hasReferences) {
|
|
68
|
+
logger.info(`[ResponseAnalyzer] Found ${result.referenceCount} memory references`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function mightContainMemoryReferences(responseText: string): boolean {
|
|
75
|
+
const responseLower = responseText.toLowerCase();
|
|
76
|
+
const quickPatterns = [
|
|
77
|
+
'remember', 'recall', 'mentioned', 'noted', 'earlier',
|
|
78
|
+
'previous', 'as i', 'as we', 'from my', 'from our',
|
|
79
|
+
];
|
|
80
|
+
return quickPatterns.some(pattern => responseLower.includes(pattern));
|
|
81
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieval Feedback System
|
|
3
|
+
*
|
|
4
|
+
* Tracks whether retrieved memories were useful in responses.
|
|
5
|
+
* Strengthens useful paths, prunes stale nodes, tunes edge weights.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { eq, and, sql } from 'drizzle-orm';
|
|
9
|
+
import { getDb } from '../../db/index.js';
|
|
10
|
+
import { getSchema } from '../../db/schema.js';
|
|
11
|
+
import { logger } from '../logger.js';
|
|
12
|
+
|
|
13
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
export interface RetrievalFeedback {
|
|
16
|
+
memoryId: string;
|
|
17
|
+
query: string;
|
|
18
|
+
wasUseful: boolean;
|
|
19
|
+
cited: boolean; // Was the memory cited in the response?
|
|
20
|
+
responseId?: string;
|
|
21
|
+
timestamp: Date;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface FeedbackStats {
|
|
25
|
+
totalRetrievals: number;
|
|
26
|
+
usefulRetrievals: number;
|
|
27
|
+
citedRetrievals: number;
|
|
28
|
+
usefulnessRate: number;
|
|
29
|
+
citationRate: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── In-Memory Feedback Buffer ───────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
const feedbackBuffer = new Map<string, RetrievalFeedback[]>();
|
|
35
|
+
const MAX_BUFFER_SIZE = 1000;
|
|
36
|
+
const FLUSH_INTERVAL_MS = 60000; // 1 minute
|
|
37
|
+
|
|
38
|
+
let flushTimer: ReturnType<typeof setInterval> | null = null;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Record that a memory was retrieved for a query.
|
|
42
|
+
* Call this when a memory appears in search results.
|
|
43
|
+
*/
|
|
44
|
+
export function recordRetrieval(
|
|
45
|
+
memoryId: string,
|
|
46
|
+
query: string,
|
|
47
|
+
options?: { sessionId?: string }
|
|
48
|
+
): void {
|
|
49
|
+
const key = options?.sessionId || 'default';
|
|
50
|
+
const buffer = feedbackBuffer.get(key) || [];
|
|
51
|
+
|
|
52
|
+
buffer.push({
|
|
53
|
+
memoryId,
|
|
54
|
+
query,
|
|
55
|
+
wasUseful: false, // Will be updated later
|
|
56
|
+
cited: false,
|
|
57
|
+
timestamp: new Date(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Trim buffer if too large
|
|
61
|
+
if (buffer.length > MAX_BUFFER_SIZE) {
|
|
62
|
+
buffer.splice(0, buffer.length - MAX_BUFFER_SIZE);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
feedbackBuffer.set(key, buffer);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Record that a retrieved memory was actually useful.
|
|
70
|
+
* Call this when a memory is cited or referenced in a response.
|
|
71
|
+
*/
|
|
72
|
+
export function recordUsefulRetrieval(
|
|
73
|
+
memoryId: string,
|
|
74
|
+
query: string,
|
|
75
|
+
options?: {
|
|
76
|
+
cited?: boolean;
|
|
77
|
+
responseId?: string;
|
|
78
|
+
sessionId?: string;
|
|
79
|
+
}
|
|
80
|
+
): void {
|
|
81
|
+
const key = options?.sessionId || 'default';
|
|
82
|
+
const buffer = feedbackBuffer.get(key) || [];
|
|
83
|
+
|
|
84
|
+
// Find the existing retrieval record and update it
|
|
85
|
+
const existing = buffer.find(f => f.memoryId === memoryId && f.query === query && !f.wasUseful);
|
|
86
|
+
if (existing) {
|
|
87
|
+
existing.wasUseful = true;
|
|
88
|
+
existing.cited = options?.cited ?? false;
|
|
89
|
+
existing.responseId = options?.responseId;
|
|
90
|
+
} else {
|
|
91
|
+
// Add a new record
|
|
92
|
+
buffer.push({
|
|
93
|
+
memoryId,
|
|
94
|
+
query,
|
|
95
|
+
wasUseful: true,
|
|
96
|
+
cited: options?.cited ?? false,
|
|
97
|
+
responseId: options?.responseId,
|
|
98
|
+
timestamp: new Date(),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
feedbackBuffer.set(key, buffer);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Record that a memory was cited in a response.
|
|
107
|
+
* This is stronger feedback than just "useful" - it means the memory
|
|
108
|
+
* was explicitly referenced.
|
|
109
|
+
*/
|
|
110
|
+
export function recordCitation(
|
|
111
|
+
memoryId: string,
|
|
112
|
+
responseId: string,
|
|
113
|
+
options?: { sessionId?: string }
|
|
114
|
+
): void {
|
|
115
|
+
const key = options?.sessionId || 'default';
|
|
116
|
+
const buffer = feedbackBuffer.get(key) || [];
|
|
117
|
+
|
|
118
|
+
// Mark all retrievals of this memory as useful
|
|
119
|
+
for (const feedback of buffer) {
|
|
120
|
+
if (feedback.memoryId === memoryId) {
|
|
121
|
+
feedback.wasUseful = true;
|
|
122
|
+
feedback.cited = true;
|
|
123
|
+
feedback.responseId = responseId;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
feedbackBuffer.set(key, buffer);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get feedback statistics for a specific memory.
|
|
132
|
+
*/
|
|
133
|
+
export function getRetrievalStats(memoryId: string): FeedbackStats {
|
|
134
|
+
let totalRetrievals = 0;
|
|
135
|
+
let usefulRetrievals = 0;
|
|
136
|
+
let citedRetrievals = 0;
|
|
137
|
+
|
|
138
|
+
for (const [, buffer] of feedbackBuffer) {
|
|
139
|
+
for (const feedback of buffer) {
|
|
140
|
+
if (feedback.memoryId === memoryId) {
|
|
141
|
+
totalRetrievals++;
|
|
142
|
+
if (feedback.wasUseful) usefulRetrievals++;
|
|
143
|
+
if (feedback.cited) citedRetrievals++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
totalRetrievals,
|
|
150
|
+
usefulRetrievals,
|
|
151
|
+
citedRetrievals,
|
|
152
|
+
usefulnessRate: totalRetrievals > 0 ? usefulRetrievals / totalRetrievals : 0,
|
|
153
|
+
citationRate: totalRetrievals > 0 ? citedRetrievals / totalRetrievals : 0,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get overall feedback statistics.
|
|
159
|
+
*/
|
|
160
|
+
export function getOverallFeedbackStats(): FeedbackStats {
|
|
161
|
+
let totalRetrievals = 0;
|
|
162
|
+
let usefulRetrievals = 0;
|
|
163
|
+
let citedRetrievals = 0;
|
|
164
|
+
|
|
165
|
+
for (const [, buffer] of feedbackBuffer) {
|
|
166
|
+
for (const feedback of buffer) {
|
|
167
|
+
totalRetrievals++;
|
|
168
|
+
if (feedback.wasUseful) usefulRetrievals++;
|
|
169
|
+
if (feedback.cited) citedRetrievals++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
totalRetrievals,
|
|
175
|
+
usefulRetrievals,
|
|
176
|
+
citedRetrievals,
|
|
177
|
+
usefulnessRate: totalRetrievals > 0 ? usefulRetrievals / totalRetrievals : 0,
|
|
178
|
+
citationRate: totalRetrievals > 0 ? citedRetrievals / totalRetrievals : 0,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Flush feedback to the database, updating association weights.
|
|
184
|
+
*/
|
|
185
|
+
export async function flushFeedback(): Promise<{
|
|
186
|
+
strengthened: number;
|
|
187
|
+
weakened: number;
|
|
188
|
+
total: number;
|
|
189
|
+
}> {
|
|
190
|
+
const db = await getDb();
|
|
191
|
+
const schema = await getSchema();
|
|
192
|
+
|
|
193
|
+
let strengthened = 0;
|
|
194
|
+
let weakened = 0;
|
|
195
|
+
let total = 0;
|
|
196
|
+
|
|
197
|
+
for (const [, buffer] of feedbackBuffer) {
|
|
198
|
+
for (const feedback of buffer) {
|
|
199
|
+
total++;
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// Get associations involving this memory
|
|
203
|
+
const associations = await (db as any)
|
|
204
|
+
.select()
|
|
205
|
+
.from(schema.memoryAssociations)
|
|
206
|
+
.where(
|
|
207
|
+
sql`${schema.memoryAssociations.fromMemoryId} = ${feedback.memoryId} OR ${schema.memoryAssociations.toMemoryId} = ${feedback.memoryId}`
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
for (const assoc of associations) {
|
|
211
|
+
if (feedback.wasUseful) {
|
|
212
|
+
// Strengthen: increase weight and coactivation count
|
|
213
|
+
await (db as any)
|
|
214
|
+
.update(schema.memoryAssociations)
|
|
215
|
+
.set({
|
|
216
|
+
weight: sql`${schema.memoryAssociations.weight} + 1`,
|
|
217
|
+
coactivationCount: sql`${schema.memoryAssociations.coactivationCount} + 1`,
|
|
218
|
+
lastCoactivatedAt: new Date(),
|
|
219
|
+
})
|
|
220
|
+
.where(eq(schema.memoryAssociations.id, assoc.id));
|
|
221
|
+
strengthened++;
|
|
222
|
+
} else {
|
|
223
|
+
// Weaken: decrease weight slightly (but don't go below 1)
|
|
224
|
+
await (db as any)
|
|
225
|
+
.update(schema.memoryAssociations)
|
|
226
|
+
.set({
|
|
227
|
+
weight: sql`GREATEST(${schema.memoryAssociations.weight} - 0.5, 1)`,
|
|
228
|
+
})
|
|
229
|
+
.where(eq(schema.memoryAssociations.id, assoc.id));
|
|
230
|
+
weakened++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
logger.debug('Error updating association weights', {
|
|
235
|
+
memoryId: feedback.memoryId,
|
|
236
|
+
error: error as Error,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Clear the buffer after flushing
|
|
243
|
+
feedbackBuffer.clear();
|
|
244
|
+
|
|
245
|
+
logger.info('Feedback flushed', { strengthened, weakened, total });
|
|
246
|
+
|
|
247
|
+
return { strengthened, weakened, total };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Start the periodic feedback flush timer.
|
|
252
|
+
*/
|
|
253
|
+
export function startFeedbackFlushTimer(): void {
|
|
254
|
+
if (flushTimer) return;
|
|
255
|
+
|
|
256
|
+
flushTimer = setInterval(async () => {
|
|
257
|
+
try {
|
|
258
|
+
await flushFeedback();
|
|
259
|
+
} catch (error) {
|
|
260
|
+
logger.error('Error flushing feedback', { error: error as Error });
|
|
261
|
+
}
|
|
262
|
+
}, FLUSH_INTERVAL_MS);
|
|
263
|
+
|
|
264
|
+
logger.info('Feedback flush timer started', { intervalMs: FLUSH_INTERVAL_MS });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Stop the periodic feedback flush timer.
|
|
269
|
+
*/
|
|
270
|
+
export function stopFeedbackFlushTimer(): void {
|
|
271
|
+
if (flushTimer) {
|
|
272
|
+
clearInterval(flushTimer);
|
|
273
|
+
flushTimer = null;
|
|
274
|
+
logger.info('Feedback flush timer stopped');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { config } from '../../config.js';
|
|
2
|
+
|
|
3
|
+
export function normalizeTags(tags?: string[]): string[] {
|
|
4
|
+
return (tags || []).map((tag) => tag.trim()).filter((tag) => tag.length > 0);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function toSqliteJson(value: unknown): string | null {
|
|
8
|
+
if (value === undefined || value === null) return null;
|
|
9
|
+
return JSON.stringify(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function fromSqliteJson<T>(value: string | null | undefined): T | null {
|
|
13
|
+
if (!value) return null;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(value) as T;
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function toSqliteTags(tags?: string[]): string | null {
|
|
22
|
+
if (!tags || tags.length === 0) return null;
|
|
23
|
+
return JSON.stringify(tags);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function fromSqliteTags(value: string | null | undefined): string[] {
|
|
27
|
+
if (!value) return [];
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(value);
|
|
30
|
+
return Array.isArray(parsed) ? parsed.map(String) : [];
|
|
31
|
+
} catch {
|
|
32
|
+
return value.split(',').map((tag) => tag.trim()).filter(Boolean);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// High-level helpers that abstract away team mode vs local mode
|
|
37
|
+
|
|
38
|
+
export function serializeTags(tags?: string[]): string[] | string | null | undefined {
|
|
39
|
+
if (config.isTeamMode) {
|
|
40
|
+
// PostgreSQL: store as array directly (or null if empty)
|
|
41
|
+
return tags && tags.length > 0 ? tags : null;
|
|
42
|
+
} else {
|
|
43
|
+
// SQLite: store as JSON string (or null)
|
|
44
|
+
return toSqliteTags(tags);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function deserializeTags(value: string[] | string | null | undefined): string[] {
|
|
49
|
+
if (config.isTeamMode) {
|
|
50
|
+
// PostgreSQL: value is already an array or null/undefined
|
|
51
|
+
return Array.isArray(value) ? value : [];
|
|
52
|
+
} else {
|
|
53
|
+
// SQLite: value is a JSON string or null/undefined
|
|
54
|
+
if (typeof value === 'string' || value === null || value === undefined) {
|
|
55
|
+
return fromSqliteTags(value);
|
|
56
|
+
}
|
|
57
|
+
// Unexpected type, return empty array
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function serializeMetadata(metadata: Record<string, unknown> | null | undefined): Record<string, unknown> | string | null {
|
|
63
|
+
if (config.isTeamMode) {
|
|
64
|
+
// PostgreSQL: store object directly (or null if null/undefined, keep empty object as-is)
|
|
65
|
+
return metadata === undefined || metadata === null ? null : metadata;
|
|
66
|
+
} else {
|
|
67
|
+
// SQLite: store as JSON string (or null)
|
|
68
|
+
return toSqliteJson(metadata);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function deserializeMetadata(value: Record<string, unknown> | string | null | undefined): Record<string, unknown> | null {
|
|
73
|
+
if (config.isTeamMode) {
|
|
74
|
+
// PostgreSQL: value is already an object or null/undefined
|
|
75
|
+
return value == null ? null : (value as Record<string, unknown>);
|
|
76
|
+
} else {
|
|
77
|
+
// SQLite: value is a JSON string or null/undefined
|
|
78
|
+
if (typeof value === 'string' || value === null) {
|
|
79
|
+
return fromSqliteJson<Record<string, unknown>>(value);
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stale Memory Cleaner
|
|
3
|
+
* Deletes memories that are old, low-confidence, and low-importance
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getDb } from '../../db/index.js';
|
|
7
|
+
import { getSchema } from '../../db/schema.js';
|
|
8
|
+
import { lt, or, and, eq, lte } from 'drizzle-orm';
|
|
9
|
+
|
|
10
|
+
export interface StaleMemory {
|
|
11
|
+
id: string;
|
|
12
|
+
content: string;
|
|
13
|
+
type: string;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
confidenceLevel: string | null;
|
|
16
|
+
importanceScore: number | null;
|
|
17
|
+
isPinned: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface StaleMemoryQuery {
|
|
21
|
+
olderThanDays: number;
|
|
22
|
+
confidenceLevels: string[];
|
|
23
|
+
minImportance: number;
|
|
24
|
+
projectId?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function getStaleMemories(query: StaleMemoryQuery): Promise<StaleMemory[]> {
|
|
28
|
+
const db = await getDb();
|
|
29
|
+
if (!db) return [];
|
|
30
|
+
|
|
31
|
+
const schema = await getSchema();
|
|
32
|
+
const sqliteDb = db as any;
|
|
33
|
+
|
|
34
|
+
const cutoffDate = new Date(Date.now() - query.olderThanDays * 24 * 60 * 60 * 1000);
|
|
35
|
+
|
|
36
|
+
// Build conditions
|
|
37
|
+
const conditions = [
|
|
38
|
+
// Not pinned
|
|
39
|
+
or(
|
|
40
|
+
eq((schema.memories as any).isPinned, false),
|
|
41
|
+
eq((schema.memories as any).isPinned, null)
|
|
42
|
+
),
|
|
43
|
+
// Older than cutoff
|
|
44
|
+
lt((schema.memories as any).createdAt, cutoffDate),
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Confidence level filter
|
|
48
|
+
if (query.confidenceLevels.length > 0) {
|
|
49
|
+
conditions.push(
|
|
50
|
+
or(
|
|
51
|
+
...query.confidenceLevels.map(level =>
|
|
52
|
+
eq((schema.memories as any).confidenceLevel, level)
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Importance filter (below threshold)
|
|
59
|
+
conditions.push(lte((schema.memories as any).importanceScore, query.minImportance));
|
|
60
|
+
|
|
61
|
+
// Project filter if specified
|
|
62
|
+
if (query.projectId) {
|
|
63
|
+
conditions.push(eq((schema.memories as any).projectId, query.projectId));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const results = await sqliteDb
|
|
68
|
+
.select({
|
|
69
|
+
id: schema.memories.id,
|
|
70
|
+
content: schema.memories.content,
|
|
71
|
+
type: schema.memories.type,
|
|
72
|
+
createdAt: schema.memories.createdAt,
|
|
73
|
+
confidenceLevel: (schema.memories as any).confidenceLevel,
|
|
74
|
+
importanceScore: (schema.memories as any).importanceScore,
|
|
75
|
+
isPinned: (schema.memories as any).isPinned,
|
|
76
|
+
})
|
|
77
|
+
.from(schema.memories)
|
|
78
|
+
.where(and(...conditions.filter(Boolean)));
|
|
79
|
+
|
|
80
|
+
return results.map((r: any) => ({
|
|
81
|
+
...r,
|
|
82
|
+
isPinned: Boolean(r.isPinned),
|
|
83
|
+
}));
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('[StaleCleaner] Error querying stale memories:', error);
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function deleteMemoryPermanently(memoryId: string): Promise<void> {
|
|
91
|
+
const db = await getDb();
|
|
92
|
+
if (!db) return;
|
|
93
|
+
|
|
94
|
+
const schema = await getSchema();
|
|
95
|
+
const sqliteDb = db as any;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
// Delete associated records first
|
|
99
|
+
await sqliteDb.delete(schema.memoryAssociations).where(
|
|
100
|
+
or(
|
|
101
|
+
eq((schema.memoryAssociations as any).fromMemoryId, memoryId),
|
|
102
|
+
eq((schema.memoryAssociations as any).toMemoryId, memoryId)
|
|
103
|
+
)
|
|
104
|
+
).catch(() => {}); // Ignore if table doesn't exist
|
|
105
|
+
|
|
106
|
+
// Delete memory tags
|
|
107
|
+
await sqliteDb.delete((schema as any).memoryTags).where(
|
|
108
|
+
eq((schema as any).memoryTags.memoryId, memoryId)
|
|
109
|
+
).catch(() => {}); // Ignore if table doesn't exist
|
|
110
|
+
|
|
111
|
+
// Delete the memory itself
|
|
112
|
+
await sqliteDb.delete(schema.memories).where(eq(schema.memories.id, memoryId));
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(`[StaleCleaner] Error deleting memory ${memoryId}:`, error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function runAutoClean(options?: Partial<StaleMemoryQuery>): Promise<{
|
|
120
|
+
deleted: number;
|
|
121
|
+
summary: Record<string, unknown>;
|
|
122
|
+
}> {
|
|
123
|
+
const defaultOptions: StaleMemoryQuery = {
|
|
124
|
+
olderThanDays: options?.olderThanDays || 30,
|
|
125
|
+
confidenceLevels: options?.confidenceLevels || ['outdated', 'speculative'],
|
|
126
|
+
minImportance: options?.minImportance || 40,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const stale = await getStaleMemories(defaultOptions);
|
|
130
|
+
let deleted = 0;
|
|
131
|
+
|
|
132
|
+
for (const memory of stale) {
|
|
133
|
+
if (!memory.isPinned) {
|
|
134
|
+
await deleteMemoryPermanently(memory.id);
|
|
135
|
+
deleted++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
deleted,
|
|
141
|
+
summary: {
|
|
142
|
+
scanned: stale.length,
|
|
143
|
+
skippedPinned: stale.length - deleted,
|
|
144
|
+
criteria: defaultOptions,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|