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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reverses/undoes a completed merge and restores original memories.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Memory } from '../../../db/drizzle/schema.js';
|
|
6
|
+
import { getDb } from '../../../db/index.js';
|
|
7
|
+
import { getSchema } from '../../../db/schema.js';
|
|
8
|
+
import { createDatabaseClient } from '../../../core/storage/database.js';
|
|
9
|
+
import { eq } from 'drizzle-orm';
|
|
10
|
+
|
|
11
|
+
interface ReverseMergeInput {
|
|
12
|
+
mergeHistoryId: string;
|
|
13
|
+
reason?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ReverseMergeResponse {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
data?: {
|
|
20
|
+
mergeHistoryId: string;
|
|
21
|
+
canonicalMemoryId: string;
|
|
22
|
+
restoredMemoryIds: string[];
|
|
23
|
+
reversedAt: string;
|
|
24
|
+
};
|
|
25
|
+
error?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function handleReverseMerge(input: ReverseMergeInput): Promise<ReverseMergeResponse> {
|
|
29
|
+
try {
|
|
30
|
+
const { mergeHistoryId, reason } = input;
|
|
31
|
+
|
|
32
|
+
if (!mergeHistoryId) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
message: 'mergeHistoryId is required',
|
|
36
|
+
error: 'mergeHistoryId is required',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const db = createDatabaseClient(await getDb());
|
|
41
|
+
const schema = await getSchema();
|
|
42
|
+
|
|
43
|
+
// Step 1: Load merge history record
|
|
44
|
+
const [history] = await db
|
|
45
|
+
.select()
|
|
46
|
+
.from(schema.memoryMergeHistory)
|
|
47
|
+
.where(eq(schema.memoryMergeHistory.id, mergeHistoryId));
|
|
48
|
+
|
|
49
|
+
if (!history) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
message: 'Merge history record not found',
|
|
53
|
+
error: `Merge history ${mergeHistoryId} not found`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check if already reversed
|
|
58
|
+
if (history.isReversed) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
message: 'Merge already reversed',
|
|
62
|
+
error: 'This merge has already been reversed',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Step 2: Load and mark canonical memory as inactive
|
|
67
|
+
const [canonicalMemory] = await db
|
|
68
|
+
.select()
|
|
69
|
+
.from(schema.memories)
|
|
70
|
+
.where(eq(schema.memories.id, history.canonicalMemoryId));
|
|
71
|
+
|
|
72
|
+
if (!canonicalMemory) {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
message: 'Canonical memory not found',
|
|
76
|
+
error: `Canonical memory ${history.canonicalMemoryId} not found`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const now = new Date();
|
|
81
|
+
|
|
82
|
+
// Step 3: Restore source memories from snapshot
|
|
83
|
+
const sourceSnapshot = (history.sourceMemoriesSnapshot as unknown as Array<Record<string, any>>) || [];
|
|
84
|
+
const sourceMemoryIds = (history.sourceMemoryIds as unknown as string[]) || [];
|
|
85
|
+
|
|
86
|
+
if (sourceSnapshot.length === 0) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
message: 'No snapshot data to restore from',
|
|
90
|
+
error: 'Merge history has no source memories snapshot',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Restore each memory from snapshot
|
|
95
|
+
for (const snapshotData of sourceSnapshot) {
|
|
96
|
+
const memoryId = snapshotData.id;
|
|
97
|
+
|
|
98
|
+
// Load current state of the memory (should be marked as merged)
|
|
99
|
+
const [currentMemory] = await db
|
|
100
|
+
.select()
|
|
101
|
+
.from(schema.memories)
|
|
102
|
+
.where(eq(schema.memories.id, memoryId));
|
|
103
|
+
|
|
104
|
+
if (currentMemory) {
|
|
105
|
+
// Restore to original state
|
|
106
|
+
await db
|
|
107
|
+
.update(schema.memories)
|
|
108
|
+
.set({
|
|
109
|
+
isMerged: false,
|
|
110
|
+
mergedIntoId: null,
|
|
111
|
+
mergedAt: null,
|
|
112
|
+
isActive: true,
|
|
113
|
+
updatedAt: now,
|
|
114
|
+
})
|
|
115
|
+
.where(eq(schema.memories.id, memoryId));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Step 4: Deactivate canonical memory
|
|
120
|
+
await db
|
|
121
|
+
.update(schema.memories)
|
|
122
|
+
.set({
|
|
123
|
+
isActive: false,
|
|
124
|
+
updatedAt: now,
|
|
125
|
+
})
|
|
126
|
+
.where(eq(schema.memories.id, history.canonicalMemoryId));
|
|
127
|
+
|
|
128
|
+
// Step 5: Update merge history record
|
|
129
|
+
await db
|
|
130
|
+
.update(schema.memoryMergeHistory)
|
|
131
|
+
.set({
|
|
132
|
+
isReversed: true,
|
|
133
|
+
reversedAt: now,
|
|
134
|
+
reversedBy: canonicalMemory.userId,
|
|
135
|
+
})
|
|
136
|
+
.where(eq(schema.memoryMergeHistory.id, mergeHistoryId));
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
ok: true,
|
|
140
|
+
message: `Merge reversed successfully. Restored ${sourceMemoryIds.length} memories`,
|
|
141
|
+
data: {
|
|
142
|
+
mergeHistoryId,
|
|
143
|
+
canonicalMemoryId: history.canonicalMemoryId,
|
|
144
|
+
restoredMemoryIds: sourceMemoryIds,
|
|
145
|
+
reversedAt: now.toISOString(),
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
message: 'Failed to reverse merge',
|
|
152
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Merging Feature - Barrel Exports
|
|
3
|
+
*
|
|
4
|
+
* Provides a clean public API for memory merging functionality
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
|
|
10
|
+
// Detection
|
|
11
|
+
export { detectDuplicates, analyzeMergePair, getDetectionStats } from './detection/two-stage-detector.js';
|
|
12
|
+
export { SimHashFilter, MinHashFilter, findCandidatePairs } from './detection/hash-filters.js';
|
|
13
|
+
export { rankCandidates, analyzePair } from './detection/semantic-ranker.js';
|
|
14
|
+
|
|
15
|
+
// Merge Strategies
|
|
16
|
+
export { getMergeStrategy, mergeMemories, MERGE_STRATEGIES } from './strategies/merge-strategies.js';
|
|
17
|
+
export type { MergeStrategy, MergedMemory } from './strategies/merge-strategies.js';
|
|
18
|
+
|
|
19
|
+
// Safety
|
|
20
|
+
export { runSafetyChecks, checkBlockers, formatSafetyResults, describeSafetyChecks } from './safety/safety-checks.js';
|
|
21
|
+
|
|
22
|
+
// Analytics & Tokens
|
|
23
|
+
export {
|
|
24
|
+
estimateTokensSaved,
|
|
25
|
+
calculateProjectTokenSavings,
|
|
26
|
+
estimateMergeSavingsPreview,
|
|
27
|
+
getTokenStatistics,
|
|
28
|
+
formatTokenCount,
|
|
29
|
+
formatSavingsReport,
|
|
30
|
+
} from './analytics/token-estimator.js';
|
|
31
|
+
|
|
32
|
+
// Handlers (MCP Tools)
|
|
33
|
+
export { handleDetectDuplicates } from './handlers/detect-duplicates.js';
|
|
34
|
+
export { handleListProposals } from './handlers/list-proposals.js';
|
|
35
|
+
export { handlePreviewMerge } from './handlers/preview-merge.js';
|
|
36
|
+
export { handleApproveMerge } from './handlers/approve-merge.js';
|
|
37
|
+
export { handleRejectMerge } from './handlers/reject-merge.js';
|
|
38
|
+
export { handleReverseMerge } from './handlers/reverse-merge.js';
|
|
39
|
+
export { handleGetMergeStats } from './handlers/get-stats.js';
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash cache maintenance - SimHash/MinHash signatures for duplicate detection
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getDb } from '../../../db/index.js';
|
|
6
|
+
import { getSchema } from '../../../db/schema.js';
|
|
7
|
+
import { createDatabaseClient } from '../../../core/storage/database.js';
|
|
8
|
+
import { eq } from 'drizzle-orm';
|
|
9
|
+
import { SimHashFilter, MinHashFilter } from '../detection/hash-filters.js';
|
|
10
|
+
import crypto from 'crypto';
|
|
11
|
+
import { logger } from '../../../core/logger.js';
|
|
12
|
+
|
|
13
|
+
function hashContent(content: string): string {
|
|
14
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function updateCache(memoryId: string): Promise<boolean> {
|
|
18
|
+
try {
|
|
19
|
+
const db = createDatabaseClient(await getDb());
|
|
20
|
+
const schema = await getSchema();
|
|
21
|
+
|
|
22
|
+
// Load the memory
|
|
23
|
+
const [memory] = await db
|
|
24
|
+
.select()
|
|
25
|
+
.from(schema.memories)
|
|
26
|
+
.where(eq(schema.memories.id, memoryId));
|
|
27
|
+
|
|
28
|
+
if (!memory) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Generate hashes
|
|
33
|
+
const simhashFilter = new SimHashFilter();
|
|
34
|
+
const minhashFilter = new MinHashFilter();
|
|
35
|
+
|
|
36
|
+
const simhash = simhashFilter.generateHash(memory.content);
|
|
37
|
+
const minhash = minhashFilter.generateSignature(memory.content);
|
|
38
|
+
const contentHash = hashContent(memory.content);
|
|
39
|
+
|
|
40
|
+
// Upsert cache entry
|
|
41
|
+
const now = new Date();
|
|
42
|
+
|
|
43
|
+
// Check if entry exists
|
|
44
|
+
const [existing] = await db
|
|
45
|
+
.select()
|
|
46
|
+
.from(schema.memoryHashCache)
|
|
47
|
+
.where(eq(schema.memoryHashCache.memoryId, memoryId));
|
|
48
|
+
|
|
49
|
+
if (existing) {
|
|
50
|
+
// Update existing
|
|
51
|
+
await db
|
|
52
|
+
.update(schema.memoryHashCache)
|
|
53
|
+
.set({
|
|
54
|
+
simhash,
|
|
55
|
+
minhash: minhash,
|
|
56
|
+
contentHash,
|
|
57
|
+
lastUpdated: now,
|
|
58
|
+
})
|
|
59
|
+
.where(eq(schema.memoryHashCache.memoryId, memoryId));
|
|
60
|
+
} else {
|
|
61
|
+
// Create new
|
|
62
|
+
await db.insert(schema.memoryHashCache).values({
|
|
63
|
+
memoryId,
|
|
64
|
+
projectId: memory.projectId,
|
|
65
|
+
simhash,
|
|
66
|
+
minhash: minhash,
|
|
67
|
+
contentHash,
|
|
68
|
+
lastUpdated: now,
|
|
69
|
+
} as any);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return true;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.error(`Failed to update hash cache for ${memoryId}`, error);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function rebuildCache(projectId: string): Promise<{
|
|
80
|
+
processed: number;
|
|
81
|
+
succeeded: number;
|
|
82
|
+
failed: number;
|
|
83
|
+
}> {
|
|
84
|
+
try {
|
|
85
|
+
const db = createDatabaseClient(await getDb());
|
|
86
|
+
const schema = await getSchema();
|
|
87
|
+
|
|
88
|
+
// Get all memories in project
|
|
89
|
+
const memories: any[] = await db
|
|
90
|
+
.select()
|
|
91
|
+
.from(schema.memories)
|
|
92
|
+
.where(eq(schema.memories.projectId, projectId));
|
|
93
|
+
|
|
94
|
+
let succeeded = 0;
|
|
95
|
+
let failed = 0;
|
|
96
|
+
|
|
97
|
+
for (const memory of memories) {
|
|
98
|
+
const ok = await updateCache(memory.id);
|
|
99
|
+
if (ok) {
|
|
100
|
+
succeeded++;
|
|
101
|
+
} else {
|
|
102
|
+
failed++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
processed: memories.length,
|
|
108
|
+
succeeded,
|
|
109
|
+
failed,
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logger.error(`Failed to rebuild hash cache for project ${projectId}`, error);
|
|
113
|
+
return { processed: 0, succeeded: 0, failed: 0 };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function isStale(memoryId: string): Promise<boolean> {
|
|
118
|
+
try {
|
|
119
|
+
const db = createDatabaseClient(await getDb());
|
|
120
|
+
const schema = await getSchema();
|
|
121
|
+
|
|
122
|
+
const [memory] = await db
|
|
123
|
+
.select()
|
|
124
|
+
.from(schema.memories)
|
|
125
|
+
.where(eq(schema.memories.id, memoryId));
|
|
126
|
+
|
|
127
|
+
if (!memory) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const [cacheEntry] = await db
|
|
132
|
+
.select()
|
|
133
|
+
.from(schema.memoryHashCache)
|
|
134
|
+
.where(eq(schema.memoryHashCache.memoryId, memoryId));
|
|
135
|
+
|
|
136
|
+
if (!cacheEntry) {
|
|
137
|
+
return true; // No cache entry = stale
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const currentContentHash = hashContent(memory.content);
|
|
141
|
+
return currentContentHash !== cacheEntry.contentHash;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
logger.error('Failed to check hash cache staleness', error);
|
|
144
|
+
return true; // Assume stale on error
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function cleanupOrphaned(projectId: string): Promise<number> {
|
|
149
|
+
try {
|
|
150
|
+
const db = createDatabaseClient(await getDb());
|
|
151
|
+
const schema = await getSchema();
|
|
152
|
+
|
|
153
|
+
// Get all cache entries for project
|
|
154
|
+
const cacheEntries: any[] = await db
|
|
155
|
+
.select()
|
|
156
|
+
.from(schema.memoryHashCache)
|
|
157
|
+
.where(eq(schema.memoryHashCache.projectId, projectId));
|
|
158
|
+
|
|
159
|
+
let deleted = 0;
|
|
160
|
+
|
|
161
|
+
for (const entry of cacheEntries) {
|
|
162
|
+
// Check if memory exists
|
|
163
|
+
const [memory] = await db
|
|
164
|
+
.select()
|
|
165
|
+
.from(schema.memories)
|
|
166
|
+
.where(eq(schema.memories.id, entry.memoryId));
|
|
167
|
+
|
|
168
|
+
if (!memory) {
|
|
169
|
+
// Memory doesn't exist, delete cache entry
|
|
170
|
+
await db
|
|
171
|
+
.delete(schema.memoryHashCache)
|
|
172
|
+
.where(eq(schema.memoryHashCache.memoryId, entry.memoryId));
|
|
173
|
+
deleted++;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return deleted;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
logger.error('Failed to cleanup orphaned hash cache', error);
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety checks to prevent bad merges.
|
|
3
|
+
* Checks run before creating merge proposals and are categorized as BLOCKER or WARNING.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Memory } from '../../../db/drizzle/schema.js';
|
|
7
|
+
import type { SafetyCheckResult } from '../../lib/types.js';
|
|
8
|
+
|
|
9
|
+
export interface SafetyCheck {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
type: 'blocker' | 'warning'; // How to treat failures
|
|
13
|
+
check(memories: Memory[], metadata?: Record<string, unknown>): SafetyCheckResult;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PASSED_RESULT: SafetyCheckResult = { passed: true, warnings: [], blockers: [] };
|
|
17
|
+
|
|
18
|
+
function createBlockerCheck(
|
|
19
|
+
name: string,
|
|
20
|
+
description: string,
|
|
21
|
+
checkFn: (memories: Memory[], metadata?: Record<string, unknown>) => { passed: boolean; blockers: string[] }
|
|
22
|
+
): SafetyCheck {
|
|
23
|
+
return {
|
|
24
|
+
name,
|
|
25
|
+
description,
|
|
26
|
+
type: 'blocker',
|
|
27
|
+
check: (memories, metadata) => {
|
|
28
|
+
const result = checkFn(memories, metadata);
|
|
29
|
+
return result.passed ? PASSED_RESULT : { passed: false, warnings: [], blockers: result.blockers };
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function createWarningCheck(
|
|
35
|
+
name: string,
|
|
36
|
+
description: string,
|
|
37
|
+
checkFn: (memories: Memory[], metadata?: Record<string, unknown>) => { warnings: string[] }
|
|
38
|
+
): SafetyCheck {
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
description,
|
|
42
|
+
type: 'warning',
|
|
43
|
+
check: (memories, metadata) => {
|
|
44
|
+
const result = checkFn(memories, metadata);
|
|
45
|
+
return { passed: true, warnings: result.warnings, blockers: [] };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const SAFETY_CHECKS: SafetyCheck[] = [
|
|
51
|
+
createBlockerCheck(
|
|
52
|
+
'immutability',
|
|
53
|
+
'Prevent merging immutable memories',
|
|
54
|
+
(memories) => {
|
|
55
|
+
const immutableMemories = memories.filter((m) => !m.isMergeable);
|
|
56
|
+
if (immutableMemories.length === 0) {
|
|
57
|
+
return { passed: true, blockers: [] };
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
passed: false,
|
|
61
|
+
blockers: [
|
|
62
|
+
`Cannot merge: ${immutableMemories.length} memory(ies) marked as immutable`,
|
|
63
|
+
`IDs: ${immutableMemories.map((m) => m.id).join(', ')}`,
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
|
|
69
|
+
createBlockerCheck(
|
|
70
|
+
'type_consistency',
|
|
71
|
+
'Ensure all memories are same type',
|
|
72
|
+
(memories) => {
|
|
73
|
+
const types = new Set(memories.map((m) => m.type));
|
|
74
|
+
if (types.size <= 1) {
|
|
75
|
+
return { passed: true, blockers: [] };
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
passed: false,
|
|
79
|
+
blockers: [
|
|
80
|
+
`Cannot merge different types: ${Array.from(types).join(', ')}`,
|
|
81
|
+
'All memories must be same type (fact, preference, decision, etc.)',
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
|
|
87
|
+
createBlockerCheck(
|
|
88
|
+
'already_merged',
|
|
89
|
+
'Prevent re-merging of previously merged memories',
|
|
90
|
+
(memories) => {
|
|
91
|
+
const alreadyMerged = memories.filter((m) => m.isMerged);
|
|
92
|
+
if (alreadyMerged.length === 0) {
|
|
93
|
+
return { passed: true, blockers: [] };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
passed: false,
|
|
97
|
+
blockers: [
|
|
98
|
+
`Cannot merge: ${alreadyMerged.length} memory(ies) already merged`,
|
|
99
|
+
'Already-merged memories should not be re-merged. Undo previous merge first.',
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
|
|
105
|
+
createBlockerCheck(
|
|
106
|
+
'min_similarity',
|
|
107
|
+
'Ensure similarity is above minimum threshold',
|
|
108
|
+
(memories, metadata) => {
|
|
109
|
+
const minThreshold = 0.70;
|
|
110
|
+
if (!metadata || !('similarityScore' in metadata)) {
|
|
111
|
+
return { passed: true, blockers: [] };
|
|
112
|
+
}
|
|
113
|
+
const similarity = metadata.similarityScore as number;
|
|
114
|
+
if (similarity >= minThreshold) {
|
|
115
|
+
return { passed: true, blockers: [] };
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
passed: false,
|
|
119
|
+
blockers: [
|
|
120
|
+
`Similarity too low: ${(similarity * 100).toFixed(1)}%`,
|
|
121
|
+
`Minimum required: ${(minThreshold * 100).toFixed(0)}%`,
|
|
122
|
+
'Increase similarity threshold or select more similar memories',
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
),
|
|
127
|
+
|
|
128
|
+
createWarningCheck(
|
|
129
|
+
'multi_user',
|
|
130
|
+
'Warn about merging memories from different users',
|
|
131
|
+
(memories) => {
|
|
132
|
+
const users = new Set(memories.map((m) => m.userId).filter(Boolean));
|
|
133
|
+
if (users.size <= 1) {
|
|
134
|
+
return { warnings: [] };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
warnings: [
|
|
138
|
+
`Merging memories from ${users.size} different users`,
|
|
139
|
+
'This is usually not recommended. Ensure you want to consolidate user-specific memories.',
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
|
|
145
|
+
createWarningCheck(
|
|
146
|
+
'privacy',
|
|
147
|
+
'Warn about mixing private and non-private memories',
|
|
148
|
+
(memories) => {
|
|
149
|
+
const privacyStates = new Set(memories.map((m) => m.isPrivate));
|
|
150
|
+
if (privacyStates.size <= 1) {
|
|
151
|
+
return { warnings: [] };
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
warnings: [
|
|
155
|
+
'Merging private and non-private memories',
|
|
156
|
+
'The merged result will inherit the privacy setting of the canonical memory',
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
),
|
|
161
|
+
|
|
162
|
+
createWarningCheck(
|
|
163
|
+
'secrets',
|
|
164
|
+
'Warn about merging memories with detected secrets',
|
|
165
|
+
(memories) => {
|
|
166
|
+
const withSecrets = memories.filter((m) => m.hasSecrets);
|
|
167
|
+
if (withSecrets.length === 0) {
|
|
168
|
+
return { warnings: [] };
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
warnings: [
|
|
172
|
+
`${withSecrets.length} memory(ies) contain detected secrets`,
|
|
173
|
+
'Ensure merged content does not expose sensitive information',
|
|
174
|
+
'Consider redacting secrets before merging',
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
|
|
180
|
+
createBlockerCheck(
|
|
181
|
+
'active_status',
|
|
182
|
+
'Ensure all memories are active',
|
|
183
|
+
(memories) => {
|
|
184
|
+
const inactive = memories.filter((m) => !m.isActive);
|
|
185
|
+
if (inactive.length === 0) {
|
|
186
|
+
return { passed: true, blockers: [] };
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
passed: false,
|
|
190
|
+
blockers: [
|
|
191
|
+
`Cannot merge: ${inactive.length} memory(ies) are inactive (archived/expired)`,
|
|
192
|
+
'Only active memories can be merged',
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
export function runSafetyChecks(
|
|
200
|
+
memories: Memory[],
|
|
201
|
+
metadata?: Record<string, unknown>
|
|
202
|
+
): SafetyCheckResult {
|
|
203
|
+
const results = SAFETY_CHECKS.map((check) => check.check(memories, metadata));
|
|
204
|
+
|
|
205
|
+
const allBlockers = results.flatMap((r) => r.blockers);
|
|
206
|
+
const allWarnings = results.flatMap((r) => r.warnings);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
passed: allBlockers.length === 0,
|
|
210
|
+
warnings: allWarnings,
|
|
211
|
+
blockers: allBlockers,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function checkBlockers(memories: Memory[]): boolean {
|
|
216
|
+
const blockerChecks = SAFETY_CHECKS.filter((c) => c.type === 'blocker');
|
|
217
|
+
|
|
218
|
+
for (const check of blockerChecks) {
|
|
219
|
+
const result = check.check(memories);
|
|
220
|
+
if (!result.passed) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function formatSafetyResults(result: SafetyCheckResult): string {
|
|
229
|
+
if (result.passed && result.warnings.length === 0) {
|
|
230
|
+
return 'All safety checks passed';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const lines: string[] = [];
|
|
234
|
+
|
|
235
|
+
if (!result.passed && result.blockers.length > 0) {
|
|
236
|
+
lines.push('BLOCKERS (merge prevented):');
|
|
237
|
+
for (const blocker of result.blockers) {
|
|
238
|
+
lines.push(` ✗ ${blocker}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (result.warnings.length > 0) {
|
|
243
|
+
lines.push('WARNINGS (merge allowed with caution):');
|
|
244
|
+
for (const warning of result.warnings) {
|
|
245
|
+
lines.push(` ⚠ ${warning}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return lines.join('\n');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function describeSafetyChecks(): string {
|
|
253
|
+
return SAFETY_CHECKS.map(
|
|
254
|
+
(check) => `${check.name} [${check.type}]: ${check.description}`
|
|
255
|
+
).join('\n');
|
|
256
|
+
}
|