@vinaes/succ 1.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +87 -0
- package/README.md +588 -0
- package/agents/succ-checkpoint-manager.md +51 -0
- package/agents/succ-code-reviewer.md +181 -0
- package/agents/succ-context-optimizer.md +83 -0
- package/agents/succ-debug.md +224 -0
- package/agents/succ-decision-auditor.md +74 -0
- package/agents/succ-deep-search.md +41 -0
- package/agents/succ-diff-reviewer.md +123 -0
- package/agents/succ-explore.md +83 -0
- package/agents/succ-general.md +109 -0
- package/agents/succ-knowledge-indexer.md +45 -0
- package/agents/succ-knowledge-mapper.md +61 -0
- package/agents/succ-memory-curator.md +43 -0
- package/agents/succ-memory-health-monitor.md +55 -0
- package/agents/succ-pattern-detective.md +62 -0
- package/agents/succ-plan.md +172 -0
- package/agents/succ-quality-improvement-coach.md +63 -0
- package/agents/succ-readiness-improver.md +62 -0
- package/agents/succ-session-handoff-orchestrator.md +54 -0
- package/agents/succ-session-reviewer.md +46 -0
- package/agents/succ-style-tracker.md +73 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents-md.d.ts +16 -0
- package/dist/commands/agents-md.d.ts.map +1 -0
- package/dist/commands/agents-md.js +33 -0
- package/dist/commands/agents-md.js.map +1 -0
- package/dist/commands/analyze-agents.d.ts +20 -0
- package/dist/commands/analyze-agents.d.ts.map +1 -0
- package/dist/commands/analyze-agents.js +305 -0
- package/dist/commands/analyze-agents.js.map +1 -0
- package/dist/commands/analyze-helpers.d.ts +22 -0
- package/dist/commands/analyze-helpers.d.ts.map +1 -0
- package/dist/commands/analyze-helpers.js +38 -0
- package/dist/commands/analyze-helpers.js.map +1 -0
- package/dist/commands/analyze-profile.d.ts +53 -0
- package/dist/commands/analyze-profile.d.ts.map +1 -0
- package/dist/commands/analyze-profile.js +638 -0
- package/dist/commands/analyze-profile.js.map +1 -0
- package/dist/commands/analyze-recursive.d.ts +20 -0
- package/dist/commands/analyze-recursive.d.ts.map +1 -0
- package/dist/commands/analyze-recursive.js +326 -0
- package/dist/commands/analyze-recursive.js.map +1 -0
- package/dist/commands/analyze-utils.d.ts +83 -0
- package/dist/commands/analyze-utils.d.ts.map +1 -0
- package/dist/commands/analyze-utils.js +541 -0
- package/dist/commands/analyze-utils.js.map +1 -0
- package/dist/commands/analyze.d.ts +15 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +265 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/backfill.d.ts +22 -0
- package/dist/commands/backfill.d.ts.map +1 -0
- package/dist/commands/backfill.js +62 -0
- package/dist/commands/backfill.js.map +1 -0
- package/dist/commands/benchmark-quality.d.ts +18 -0
- package/dist/commands/benchmark-quality.d.ts.map +1 -0
- package/dist/commands/benchmark-quality.js +316 -0
- package/dist/commands/benchmark-quality.js.map +1 -0
- package/dist/commands/benchmark-sqlite-vec.d.ts +12 -0
- package/dist/commands/benchmark-sqlite-vec.d.ts.map +1 -0
- package/dist/commands/benchmark-sqlite-vec.js +281 -0
- package/dist/commands/benchmark-sqlite-vec.js.map +1 -0
- package/dist/commands/benchmark.d.ts +57 -0
- package/dist/commands/benchmark.d.ts.map +1 -0
- package/dist/commands/benchmark.js +682 -0
- package/dist/commands/benchmark.js.map +1 -0
- package/dist/commands/chat.d.ts +14 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +84 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/checkpoint.d.ts +27 -0
- package/dist/commands/checkpoint.d.ts.map +1 -0
- package/dist/commands/checkpoint.js +181 -0
- package/dist/commands/checkpoint.js.map +1 -0
- package/dist/commands/clear.d.ts +9 -0
- package/dist/commands/clear.d.ts.map +1 -0
- package/dist/commands/clear.js +31 -0
- package/dist/commands/clear.js.map +1 -0
- package/dist/commands/config.d.ts +26 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +247 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/consolidate.d.ts +21 -0
- package/dist/commands/consolidate.d.ts.map +1 -0
- package/dist/commands/consolidate.js +117 -0
- package/dist/commands/consolidate.js.map +1 -0
- package/dist/commands/daemon.d.ts +48 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +218 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/embedding.d.ts +26 -0
- package/dist/commands/embedding.d.ts.map +1 -0
- package/dist/commands/embedding.js +168 -0
- package/dist/commands/embedding.js.map +1 -0
- package/dist/commands/graph.d.ts +20 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +128 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/index-code.d.ts +23 -0
- package/dist/commands/index-code.d.ts.map +1 -0
- package/dist/commands/index-code.js +218 -0
- package/dist/commands/index-code.js.map +1 -0
- package/dist/commands/index.d.ts +23 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +217 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init-templates.d.ts +21 -0
- package/dist/commands/init-templates.d.ts.map +1 -0
- package/dist/commands/init-templates.js +487 -0
- package/dist/commands/init-templates.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +865 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/memories.d.ts +47 -0
- package/dist/commands/memories.d.ts.map +1 -0
- package/dist/commands/memories.js +597 -0
- package/dist/commands/memories.js.map +1 -0
- package/dist/commands/migrate.d.ts +19 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +154 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/prd.d.ts +46 -0
- package/dist/commands/prd.d.ts.map +1 -0
- package/dist/commands/prd.js +378 -0
- package/dist/commands/prd.js.map +1 -0
- package/dist/commands/precompute-context.d.ts +11 -0
- package/dist/commands/precompute-context.d.ts.map +1 -0
- package/dist/commands/precompute-context.js +12 -0
- package/dist/commands/precompute-context.js.map +1 -0
- package/dist/commands/progress.d.ts +16 -0
- package/dist/commands/progress.d.ts.map +1 -0
- package/dist/commands/progress.js +38 -0
- package/dist/commands/progress.js.map +1 -0
- package/dist/commands/reindex.d.ts +17 -0
- package/dist/commands/reindex.d.ts.map +1 -0
- package/dist/commands/reindex.js +83 -0
- package/dist/commands/reindex.js.map +1 -0
- package/dist/commands/retention.d.ts +19 -0
- package/dist/commands/retention.d.ts.map +1 -0
- package/dist/commands/retention.js +162 -0
- package/dist/commands/retention.js.map +1 -0
- package/dist/commands/score.d.ts +10 -0
- package/dist/commands/score.d.ts.map +1 -0
- package/dist/commands/score.js +28 -0
- package/dist/commands/score.js.map +1 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +89 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/session-summary.d.ts +15 -0
- package/dist/commands/session-summary.d.ts.map +1 -0
- package/dist/commands/session-summary.js +16 -0
- package/dist/commands/session-summary.js.map +1 -0
- package/dist/commands/setup.d.ts +6 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +222 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/soul.d.ts +9 -0
- package/dist/commands/soul.d.ts.map +1 -0
- package/dist/commands/soul.js +256 -0
- package/dist/commands/soul.js.map +1 -0
- package/dist/commands/stats.d.ts +18 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +138 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +145 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/train-bpe.d.ts +8 -0
- package/dist/commands/train-bpe.d.ts.map +1 -0
- package/dist/commands/train-bpe.js +35 -0
- package/dist/commands/train-bpe.js.map +1 -0
- package/dist/commands/watch.d.ts +22 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +171 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/daemon/analyzer.d.ts +54 -0
- package/dist/daemon/analyzer.d.ts.map +1 -0
- package/dist/daemon/analyzer.js +362 -0
- package/dist/daemon/analyzer.js.map +1 -0
- package/dist/daemon/client.d.ts +87 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +356 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/index.d.ts +12 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +12 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/service.d.ts +51 -0
- package/dist/daemon/service.d.ts.map +1 -0
- package/dist/daemon/service.js +1203 -0
- package/dist/daemon/service.js.map +1 -0
- package/dist/daemon/session-processor.d.ts +85 -0
- package/dist/daemon/session-processor.d.ts.map +1 -0
- package/dist/daemon/session-processor.js +571 -0
- package/dist/daemon/session-processor.js.map +1 -0
- package/dist/daemon/sessions.d.ts +62 -0
- package/dist/daemon/sessions.d.ts.map +1 -0
- package/dist/daemon/sessions.js +192 -0
- package/dist/daemon/sessions.js.map +1 -0
- package/dist/daemon/watcher.d.ts +52 -0
- package/dist/daemon/watcher.d.ts.map +1 -0
- package/dist/daemon/watcher.js +363 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/lib/agents-md-generator.d.ts +33 -0
- package/dist/lib/agents-md-generator.d.ts.map +1 -0
- package/dist/lib/agents-md-generator.js +156 -0
- package/dist/lib/agents-md-generator.js.map +1 -0
- package/dist/lib/ai-readiness.d.ts +132 -0
- package/dist/lib/ai-readiness.d.ts.map +1 -0
- package/dist/lib/ai-readiness.js +702 -0
- package/dist/lib/ai-readiness.js.map +1 -0
- package/dist/lib/analyze-state.d.ts +34 -0
- package/dist/lib/analyze-state.d.ts.map +1 -0
- package/dist/lib/analyze-state.js +106 -0
- package/dist/lib/analyze-state.js.map +1 -0
- package/dist/lib/benchmark.d.ts +250 -0
- package/dist/lib/benchmark.d.ts.map +1 -0
- package/dist/lib/benchmark.js +778 -0
- package/dist/lib/benchmark.js.map +1 -0
- package/dist/lib/bm25.d.ts +114 -0
- package/dist/lib/bm25.d.ts.map +1 -0
- package/dist/lib/bm25.js +727 -0
- package/dist/lib/bm25.js.map +1 -0
- package/dist/lib/bpe.d.ts +70 -0
- package/dist/lib/bpe.d.ts.map +1 -0
- package/dist/lib/bpe.js +270 -0
- package/dist/lib/bpe.js.map +1 -0
- package/dist/lib/checkpoint.d.ts +124 -0
- package/dist/lib/checkpoint.d.ts.map +1 -0
- package/dist/lib/checkpoint.js +321 -0
- package/dist/lib/checkpoint.js.map +1 -0
- package/dist/lib/chunker.d.ts +47 -0
- package/dist/lib/chunker.d.ts.map +1 -0
- package/dist/lib/chunker.js +358 -0
- package/dist/lib/chunker.js.map +1 -0
- package/dist/lib/claude-ws-transport.d.ts +76 -0
- package/dist/lib/claude-ws-transport.d.ts.map +1 -0
- package/dist/lib/claude-ws-transport.js +487 -0
- package/dist/lib/claude-ws-transport.js.map +1 -0
- package/dist/lib/compact-briefing.d.ts +22 -0
- package/dist/lib/compact-briefing.d.ts.map +1 -0
- package/dist/lib/compact-briefing.js +180 -0
- package/dist/lib/compact-briefing.js.map +1 -0
- package/dist/lib/config-defaults.d.ts +41 -0
- package/dist/lib/config-defaults.d.ts.map +1 -0
- package/dist/lib/config-defaults.js +99 -0
- package/dist/lib/config-defaults.js.map +1 -0
- package/dist/lib/config-display.d.ts +16 -0
- package/dist/lib/config-display.d.ts.map +1 -0
- package/dist/lib/config-display.js +408 -0
- package/dist/lib/config-display.js.map +1 -0
- package/dist/lib/config-types.d.ts +601 -0
- package/dist/lib/config-types.d.ts.map +1 -0
- package/dist/lib/config-types.js +7 -0
- package/dist/lib/config-types.js.map +1 -0
- package/dist/lib/config-validation.d.ts +19 -0
- package/dist/lib/config-validation.d.ts.map +1 -0
- package/dist/lib/config-validation.js +136 -0
- package/dist/lib/config-validation.js.map +1 -0
- package/dist/lib/config.d.ts +143 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +689 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/consolidate.d.ts +115 -0
- package/dist/lib/consolidate.d.ts.map +1 -0
- package/dist/lib/consolidate.js +600 -0
- package/dist/lib/consolidate.js.map +1 -0
- package/dist/lib/db/bm25-indexes.d.ts +58 -0
- package/dist/lib/db/bm25-indexes.d.ts.map +1 -0
- package/dist/lib/db/bm25-indexes.js +333 -0
- package/dist/lib/db/bm25-indexes.js.map +1 -0
- package/dist/lib/db/bpe.d.ts +18 -0
- package/dist/lib/db/bpe.d.ts.map +1 -0
- package/dist/lib/db/bpe.js +44 -0
- package/dist/lib/db/bpe.js.map +1 -0
- package/dist/lib/db/connection.d.ts +47 -0
- package/dist/lib/db/connection.d.ts.map +1 -0
- package/dist/lib/db/connection.js +114 -0
- package/dist/lib/db/connection.js.map +1 -0
- package/dist/lib/db/documents.d.ts +58 -0
- package/dist/lib/db/documents.d.ts.map +1 -0
- package/dist/lib/db/documents.js +374 -0
- package/dist/lib/db/documents.js.map +1 -0
- package/dist/lib/db/file-hash.d.ts +26 -0
- package/dist/lib/db/file-hash.d.ts.map +1 -0
- package/dist/lib/db/file-hash.js +56 -0
- package/dist/lib/db/file-hash.js.map +1 -0
- package/dist/lib/db/global-memories.d.ts +62 -0
- package/dist/lib/db/global-memories.d.ts.map +1 -0
- package/dist/lib/db/global-memories.js +173 -0
- package/dist/lib/db/global-memories.js.map +1 -0
- package/dist/lib/db/graph.d.ts +163 -0
- package/dist/lib/db/graph.d.ts.map +1 -0
- package/dist/lib/db/graph.js +488 -0
- package/dist/lib/db/graph.js.map +1 -0
- package/dist/lib/db/helpers.d.ts +13 -0
- package/dist/lib/db/helpers.d.ts.map +1 -0
- package/dist/lib/db/helpers.js +21 -0
- package/dist/lib/db/helpers.js.map +1 -0
- package/dist/lib/db/hybrid-search.d.ts +64 -0
- package/dist/lib/db/hybrid-search.d.ts.map +1 -0
- package/dist/lib/db/hybrid-search.js +549 -0
- package/dist/lib/db/hybrid-search.js.map +1 -0
- package/dist/lib/db/index.d.ts +23 -0
- package/dist/lib/db/index.d.ts.map +1 -0
- package/dist/lib/db/index.js +23 -0
- package/dist/lib/db/index.js.map +1 -0
- package/dist/lib/db/memories.d.ts +174 -0
- package/dist/lib/db/memories.d.ts.map +1 -0
- package/dist/lib/db/memories.js +866 -0
- package/dist/lib/db/memories.js.map +1 -0
- package/dist/lib/db/retention.d.ts +64 -0
- package/dist/lib/db/retention.d.ts.map +1 -0
- package/dist/lib/db/retention.js +115 -0
- package/dist/lib/db/retention.js.map +1 -0
- package/dist/lib/db/schema.d.ts +29 -0
- package/dist/lib/db/schema.d.ts.map +1 -0
- package/dist/lib/db/schema.js +832 -0
- package/dist/lib/db/schema.js.map +1 -0
- package/dist/lib/db/skills.d.ts +65 -0
- package/dist/lib/db/skills.d.ts.map +1 -0
- package/dist/lib/db/skills.js +119 -0
- package/dist/lib/db/skills.js.map +1 -0
- package/dist/lib/db/token-frequency.d.ts +34 -0
- package/dist/lib/db/token-frequency.d.ts.map +1 -0
- package/dist/lib/db/token-frequency.js +92 -0
- package/dist/lib/db/token-frequency.js.map +1 -0
- package/dist/lib/db/token-stats.d.ts +43 -0
- package/dist/lib/db/token-stats.d.ts.map +1 -0
- package/dist/lib/db/token-stats.js +59 -0
- package/dist/lib/db/token-stats.js.map +1 -0
- package/dist/lib/db/types.d.ts +57 -0
- package/dist/lib/db/types.d.ts.map +1 -0
- package/dist/lib/db/types.js +5 -0
- package/dist/lib/db/types.js.map +1 -0
- package/dist/lib/db/web-search-history.d.ts +22 -0
- package/dist/lib/db/web-search-history.d.ts.map +1 -0
- package/dist/lib/db/web-search-history.js +107 -0
- package/dist/lib/db/web-search-history.js.map +1 -0
- package/dist/lib/debug/state.d.ts +17 -0
- package/dist/lib/debug/state.d.ts.map +1 -0
- package/dist/lib/debug/state.js +131 -0
- package/dist/lib/debug/state.js.map +1 -0
- package/dist/lib/debug/types.d.ts +74 -0
- package/dist/lib/debug/types.d.ts.map +1 -0
- package/dist/lib/debug/types.js +85 -0
- package/dist/lib/debug/types.js.map +1 -0
- package/dist/lib/embedding-pool.d.ts +37 -0
- package/dist/lib/embedding-pool.d.ts.map +1 -0
- package/dist/lib/embedding-pool.js +159 -0
- package/dist/lib/embedding-pool.js.map +1 -0
- package/dist/lib/embedding-worker.d.ts +7 -0
- package/dist/lib/embedding-worker.d.ts.map +1 -0
- package/dist/lib/embedding-worker.js +49 -0
- package/dist/lib/embedding-worker.js.map +1 -0
- package/dist/lib/embeddings.d.ts +54 -0
- package/dist/lib/embeddings.d.ts.map +1 -0
- package/dist/lib/embeddings.js +437 -0
- package/dist/lib/embeddings.js.map +1 -0
- package/dist/lib/errors.d.ts +40 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +66 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/fault-logger.d.ts +35 -0
- package/dist/lib/fault-logger.d.ts.map +1 -0
- package/dist/lib/fault-logger.js +182 -0
- package/dist/lib/fault-logger.js.map +1 -0
- package/dist/lib/graph/centrality.d.ts +34 -0
- package/dist/lib/graph/centrality.d.ts.map +1 -0
- package/dist/lib/graph/centrality.js +76 -0
- package/dist/lib/graph/centrality.js.map +1 -0
- package/dist/lib/graph/cleanup.d.ts +36 -0
- package/dist/lib/graph/cleanup.d.ts.map +1 -0
- package/dist/lib/graph/cleanup.js +96 -0
- package/dist/lib/graph/cleanup.js.map +1 -0
- package/dist/lib/graph/community-detection.d.ts +61 -0
- package/dist/lib/graph/community-detection.d.ts.map +1 -0
- package/dist/lib/graph/community-detection.js +218 -0
- package/dist/lib/graph/community-detection.js.map +1 -0
- package/dist/lib/graph/contextual-proximity.d.ts +41 -0
- package/dist/lib/graph/contextual-proximity.d.ts.map +1 -0
- package/dist/lib/graph/contextual-proximity.js +125 -0
- package/dist/lib/graph/contextual-proximity.js.map +1 -0
- package/dist/lib/graph/llm-relations.d.ts +54 -0
- package/dist/lib/graph/llm-relations.d.ts.map +1 -0
- package/dist/lib/graph/llm-relations.js +265 -0
- package/dist/lib/graph/llm-relations.js.map +1 -0
- package/dist/lib/graph-export.d.ts +13 -0
- package/dist/lib/graph-export.d.ts.map +1 -0
- package/dist/lib/graph-export.js +637 -0
- package/dist/lib/graph-export.js.map +1 -0
- package/dist/lib/graph-scheduler.d.ts +7 -0
- package/dist/lib/graph-scheduler.d.ts.map +1 -0
- package/dist/lib/graph-scheduler.js +21 -0
- package/dist/lib/graph-scheduler.js.map +1 -0
- package/dist/lib/indexer.d.ts +36 -0
- package/dist/lib/indexer.d.ts.map +1 -0
- package/dist/lib/indexer.js +226 -0
- package/dist/lib/indexer.js.map +1 -0
- package/dist/lib/learning-delta.d.ts +35 -0
- package/dist/lib/learning-delta.d.ts.map +1 -0
- package/dist/lib/learning-delta.js +53 -0
- package/dist/lib/learning-delta.js.map +1 -0
- package/dist/lib/llm.d.ts +118 -0
- package/dist/lib/llm.d.ts.map +1 -0
- package/dist/lib/llm.js +439 -0
- package/dist/lib/llm.js.map +1 -0
- package/dist/lib/lock.d.ts +27 -0
- package/dist/lib/lock.d.ts.map +1 -0
- package/dist/lib/lock.js +143 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/md-fetch.d.ts +61 -0
- package/dist/lib/md-fetch.d.ts.map +1 -0
- package/dist/lib/md-fetch.js +141 -0
- package/dist/lib/md-fetch.js.map +1 -0
- package/dist/lib/mmr.d.ts +29 -0
- package/dist/lib/mmr.d.ts.map +1 -0
- package/dist/lib/mmr.js +89 -0
- package/dist/lib/mmr.js.map +1 -0
- package/dist/lib/onboarding/ai-chat.d.ts +11 -0
- package/dist/lib/onboarding/ai-chat.d.ts.map +1 -0
- package/dist/lib/onboarding/ai-chat.js +85 -0
- package/dist/lib/onboarding/ai-chat.js.map +1 -0
- package/dist/lib/onboarding/index.d.ts +7 -0
- package/dist/lib/onboarding/index.d.ts.map +1 -0
- package/dist/lib/onboarding/index.js +7 -0
- package/dist/lib/onboarding/index.js.map +1 -0
- package/dist/lib/onboarding/wizard.d.ts +11 -0
- package/dist/lib/onboarding/wizard.d.ts.map +1 -0
- package/dist/lib/onboarding/wizard.js +104 -0
- package/dist/lib/onboarding/wizard.js.map +1 -0
- package/dist/lib/ort-provider.d.ts +27 -0
- package/dist/lib/ort-provider.d.ts.map +1 -0
- package/dist/lib/ort-provider.js +83 -0
- package/dist/lib/ort-provider.js.map +1 -0
- package/dist/lib/ort-session.d.ts +32 -0
- package/dist/lib/ort-session.d.ts.map +1 -0
- package/dist/lib/ort-session.js +227 -0
- package/dist/lib/ort-session.js.map +1 -0
- package/dist/lib/patterns.d.ts +43 -0
- package/dist/lib/patterns.d.ts.map +1 -0
- package/dist/lib/patterns.js +395 -0
- package/dist/lib/patterns.js.map +1 -0
- package/dist/lib/prd/codebase-context.d.ts +27 -0
- package/dist/lib/prd/codebase-context.d.ts.map +1 -0
- package/dist/lib/prd/codebase-context.js +420 -0
- package/dist/lib/prd/codebase-context.js.map +1 -0
- package/dist/lib/prd/context.d.ts +24 -0
- package/dist/lib/prd/context.d.ts.map +1 -0
- package/dist/lib/prd/context.js +68 -0
- package/dist/lib/prd/context.js.map +1 -0
- package/dist/lib/prd/executor.d.ts +52 -0
- package/dist/lib/prd/executor.d.ts.map +1 -0
- package/dist/lib/prd/executor.js +154 -0
- package/dist/lib/prd/executor.js.map +1 -0
- package/dist/lib/prd/export.d.ts +40 -0
- package/dist/lib/prd/export.d.ts.map +1 -0
- package/dist/lib/prd/export.js +511 -0
- package/dist/lib/prd/export.js.map +1 -0
- package/dist/lib/prd/gates.d.ts +30 -0
- package/dist/lib/prd/gates.d.ts.map +1 -0
- package/dist/lib/prd/gates.js +100 -0
- package/dist/lib/prd/gates.js.map +1 -0
- package/dist/lib/prd/generate.d.ts +56 -0
- package/dist/lib/prd/generate.d.ts.map +1 -0
- package/dist/lib/prd/generate.js +357 -0
- package/dist/lib/prd/generate.js.map +1 -0
- package/dist/lib/prd/parse.d.ts +21 -0
- package/dist/lib/prd/parse.d.ts.map +1 -0
- package/dist/lib/prd/parse.js +270 -0
- package/dist/lib/prd/parse.js.map +1 -0
- package/dist/lib/prd/prompt-builder.d.ts +18 -0
- package/dist/lib/prd/prompt-builder.d.ts.map +1 -0
- package/dist/lib/prd/prompt-builder.js +61 -0
- package/dist/lib/prd/prompt-builder.js.map +1 -0
- package/dist/lib/prd/runner.d.ts +54 -0
- package/dist/lib/prd/runner.d.ts.map +1 -0
- package/dist/lib/prd/runner.js +563 -0
- package/dist/lib/prd/runner.js.map +1 -0
- package/dist/lib/prd/scheduler.d.ts +27 -0
- package/dist/lib/prd/scheduler.d.ts.map +1 -0
- package/dist/lib/prd/scheduler.js +113 -0
- package/dist/lib/prd/scheduler.js.map +1 -0
- package/dist/lib/prd/state.d.ts +77 -0
- package/dist/lib/prd/state.d.ts.map +1 -0
- package/dist/lib/prd/state.js +253 -0
- package/dist/lib/prd/state.js.map +1 -0
- package/dist/lib/prd/team-runner.d.ts +48 -0
- package/dist/lib/prd/team-runner.d.ts.map +1 -0
- package/dist/lib/prd/team-runner.js +261 -0
- package/dist/lib/prd/team-runner.js.map +1 -0
- package/dist/lib/prd/types.d.ts +169 -0
- package/dist/lib/prd/types.d.ts.map +1 -0
- package/dist/lib/prd/types.js +143 -0
- package/dist/lib/prd/types.js.map +1 -0
- package/dist/lib/prd/worktree.d.ts +54 -0
- package/dist/lib/prd/worktree.d.ts.map +1 -0
- package/dist/lib/prd/worktree.js +255 -0
- package/dist/lib/prd/worktree.js.map +1 -0
- package/dist/lib/precompute-context.d.ts +48 -0
- package/dist/lib/precompute-context.d.ts.map +1 -0
- package/dist/lib/precompute-context.js +265 -0
- package/dist/lib/precompute-context.js.map +1 -0
- package/dist/lib/pricing.d.ts +60 -0
- package/dist/lib/pricing.d.ts.map +1 -0
- package/dist/lib/pricing.js +258 -0
- package/dist/lib/pricing.js.map +1 -0
- package/dist/lib/process-registry.d.ts +30 -0
- package/dist/lib/process-registry.d.ts.map +1 -0
- package/dist/lib/process-registry.js +92 -0
- package/dist/lib/process-registry.js.map +1 -0
- package/dist/lib/progress-log.d.ts +44 -0
- package/dist/lib/progress-log.d.ts.map +1 -0
- package/dist/lib/progress-log.js +58 -0
- package/dist/lib/progress-log.js.map +1 -0
- package/dist/lib/public-api.d.ts +56 -0
- package/dist/lib/public-api.d.ts.map +1 -0
- package/dist/lib/public-api.js +63 -0
- package/dist/lib/public-api.js.map +1 -0
- package/dist/lib/quality.d.ts +66 -0
- package/dist/lib/quality.d.ts.map +1 -0
- package/dist/lib/quality.js +486 -0
- package/dist/lib/quality.js.map +1 -0
- package/dist/lib/query-expansion.d.ts +16 -0
- package/dist/lib/query-expansion.d.ts.map +1 -0
- package/dist/lib/query-expansion.js +53 -0
- package/dist/lib/query-expansion.js.map +1 -0
- package/dist/lib/readiness.d.ts +35 -0
- package/dist/lib/readiness.d.ts.map +1 -0
- package/dist/lib/readiness.js +142 -0
- package/dist/lib/readiness.js.map +1 -0
- package/dist/lib/reference-embeddings.d.ts +39 -0
- package/dist/lib/reference-embeddings.d.ts.map +1 -0
- package/dist/lib/reference-embeddings.js +95 -0
- package/dist/lib/reference-embeddings.js.map +1 -0
- package/dist/lib/reflection-synthesizer.d.ts +27 -0
- package/dist/lib/reflection-synthesizer.d.ts.map +1 -0
- package/dist/lib/reflection-synthesizer.js +149 -0
- package/dist/lib/reflection-synthesizer.js.map +1 -0
- package/dist/lib/retention.d.ts +105 -0
- package/dist/lib/retention.d.ts.map +1 -0
- package/dist/lib/retention.js +246 -0
- package/dist/lib/retention.js.map +1 -0
- package/dist/lib/sensitive-filter.d.ts +34 -0
- package/dist/lib/sensitive-filter.d.ts.map +1 -0
- package/dist/lib/sensitive-filter.js +344 -0
- package/dist/lib/sensitive-filter.js.map +1 -0
- package/dist/lib/session-observations.d.ts +59 -0
- package/dist/lib/session-observations.d.ts.map +1 -0
- package/dist/lib/session-observations.js +128 -0
- package/dist/lib/session-observations.js.map +1 -0
- package/dist/lib/session-summary.d.ts +65 -0
- package/dist/lib/session-summary.d.ts.map +1 -0
- package/dist/lib/session-summary.js +344 -0
- package/dist/lib/session-summary.js.map +1 -0
- package/dist/lib/similarity-worker.d.ts +7 -0
- package/dist/lib/similarity-worker.d.ts.map +1 -0
- package/dist/lib/similarity-worker.js +36 -0
- package/dist/lib/similarity-worker.js.map +1 -0
- package/dist/lib/skills.d.ts +78 -0
- package/dist/lib/skills.d.ts.map +1 -0
- package/dist/lib/skills.js +439 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/skyll-client.d.ts +59 -0
- package/dist/lib/skyll-client.d.ts.map +1 -0
- package/dist/lib/skyll-client.js +257 -0
- package/dist/lib/skyll-client.js.map +1 -0
- package/dist/lib/storage/backends/interface.d.ts +383 -0
- package/dist/lib/storage/backends/interface.d.ts.map +1 -0
- package/dist/lib/storage/backends/interface.js +12 -0
- package/dist/lib/storage/backends/interface.js.map +1 -0
- package/dist/lib/storage/backends/postgresql.d.ts +454 -0
- package/dist/lib/storage/backends/postgresql.d.ts.map +1 -0
- package/dist/lib/storage/backends/postgresql.js +2528 -0
- package/dist/lib/storage/backends/postgresql.js.map +1 -0
- package/dist/lib/storage/benchmark.d.ts +16 -0
- package/dist/lib/storage/benchmark.d.ts.map +1 -0
- package/dist/lib/storage/benchmark.js +219 -0
- package/dist/lib/storage/benchmark.js.map +1 -0
- package/dist/lib/storage/dispatcher-export.d.ts +108 -0
- package/dist/lib/storage/dispatcher-export.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher-export.js +593 -0
- package/dist/lib/storage/dispatcher-export.js.map +1 -0
- package/dist/lib/storage/dispatcher.d.ts +468 -0
- package/dist/lib/storage/dispatcher.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher.js +1926 -0
- package/dist/lib/storage/dispatcher.js.map +1 -0
- package/dist/lib/storage/index.d.ts +481 -0
- package/dist/lib/storage/index.d.ts.map +1 -0
- package/dist/lib/storage/index.js +727 -0
- package/dist/lib/storage/index.js.map +1 -0
- package/dist/lib/storage/migration/export-import.d.ts +133 -0
- package/dist/lib/storage/migration/export-import.d.ts.map +1 -0
- package/dist/lib/storage/migration/export-import.js +264 -0
- package/dist/lib/storage/migration/export-import.js.map +1 -0
- package/dist/lib/storage/types.d.ts +313 -0
- package/dist/lib/storage/types.d.ts.map +1 -0
- package/dist/lib/storage/types.js +30 -0
- package/dist/lib/storage/types.js.map +1 -0
- package/dist/lib/storage/vector/interface.d.ts +89 -0
- package/dist/lib/storage/vector/interface.d.ts.map +1 -0
- package/dist/lib/storage/vector/interface.js +10 -0
- package/dist/lib/storage/vector/interface.js.map +1 -0
- package/dist/lib/storage/vector/qdrant.d.ts +221 -0
- package/dist/lib/storage/vector/qdrant.d.ts.map +1 -0
- package/dist/lib/storage/vector/qdrant.js +880 -0
- package/dist/lib/storage/vector/qdrant.js.map +1 -0
- package/dist/lib/supersession.d.ts +26 -0
- package/dist/lib/supersession.d.ts.map +1 -0
- package/dist/lib/supersession.js +97 -0
- package/dist/lib/supersession.js.map +1 -0
- package/dist/lib/temporal.d.ts +140 -0
- package/dist/lib/temporal.d.ts.map +1 -0
- package/dist/lib/temporal.js +303 -0
- package/dist/lib/temporal.js.map +1 -0
- package/dist/lib/token-budget.d.ts +79 -0
- package/dist/lib/token-budget.d.ts.map +1 -0
- package/dist/lib/token-budget.js +146 -0
- package/dist/lib/token-budget.js.map +1 -0
- package/dist/lib/token-counter.d.ts +27 -0
- package/dist/lib/token-counter.d.ts.map +1 -0
- package/dist/lib/token-counter.js +52 -0
- package/dist/lib/token-counter.js.map +1 -0
- package/dist/lib/tree-sitter/chunker-ts.d.ts +24 -0
- package/dist/lib/tree-sitter/chunker-ts.d.ts.map +1 -0
- package/dist/lib/tree-sitter/chunker-ts.js +206 -0
- package/dist/lib/tree-sitter/chunker-ts.js.map +1 -0
- package/dist/lib/tree-sitter/extractor.d.ts +43 -0
- package/dist/lib/tree-sitter/extractor.d.ts.map +1 -0
- package/dist/lib/tree-sitter/extractor.js +297 -0
- package/dist/lib/tree-sitter/extractor.js.map +1 -0
- package/dist/lib/tree-sitter/index.d.ts +13 -0
- package/dist/lib/tree-sitter/index.d.ts.map +1 -0
- package/dist/lib/tree-sitter/index.js +14 -0
- package/dist/lib/tree-sitter/index.js.map +1 -0
- package/dist/lib/tree-sitter/parser.d.ts +70 -0
- package/dist/lib/tree-sitter/parser.d.ts.map +1 -0
- package/dist/lib/tree-sitter/parser.js +354 -0
- package/dist/lib/tree-sitter/parser.js.map +1 -0
- package/dist/lib/tree-sitter/public.d.ts +28 -0
- package/dist/lib/tree-sitter/public.d.ts.map +1 -0
- package/dist/lib/tree-sitter/public.js +50 -0
- package/dist/lib/tree-sitter/public.js.map +1 -0
- package/dist/lib/tree-sitter/queries.d.ts +28 -0
- package/dist/lib/tree-sitter/queries.d.ts.map +1 -0
- package/dist/lib/tree-sitter/queries.js +383 -0
- package/dist/lib/tree-sitter/queries.js.map +1 -0
- package/dist/lib/tree-sitter/types.d.ts +69 -0
- package/dist/lib/tree-sitter/types.d.ts.map +1 -0
- package/dist/lib/tree-sitter/types.js +131 -0
- package/dist/lib/tree-sitter/types.js.map +1 -0
- package/dist/lib/working-memory-pipeline.d.ts +118 -0
- package/dist/lib/working-memory-pipeline.d.ts.map +1 -0
- package/dist/lib/working-memory-pipeline.js +344 -0
- package/dist/lib/working-memory-pipeline.js.map +1 -0
- package/dist/mcp/helpers.d.ts +44 -0
- package/dist/mcp/helpers.d.ts.map +1 -0
- package/dist/mcp/helpers.js +244 -0
- package/dist/mcp/helpers.js.map +1 -0
- package/dist/mcp/index.d.ts +10 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +15 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/resources.d.ts +12 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +136 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +22 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +131 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/config.d.ts +10 -0
- package/dist/mcp/tools/config.d.ts.map +1 -0
- package/dist/mcp/tools/config.js +236 -0
- package/dist/mcp/tools/config.js.map +1 -0
- package/dist/mcp/tools/dead-end.d.ts +9 -0
- package/dist/mcp/tools/dead-end.d.ts.map +1 -0
- package/dist/mcp/tools/dead-end.js +137 -0
- package/dist/mcp/tools/dead-end.js.map +1 -0
- package/dist/mcp/tools/debug.d.ts +9 -0
- package/dist/mcp/tools/debug.d.ts.map +1 -0
- package/dist/mcp/tools/debug.js +387 -0
- package/dist/mcp/tools/debug.js.map +1 -0
- package/dist/mcp/tools/graph.d.ts +9 -0
- package/dist/mcp/tools/graph.d.ts.map +1 -0
- package/dist/mcp/tools/graph.js +337 -0
- package/dist/mcp/tools/graph.js.map +1 -0
- package/dist/mcp/tools/indexing.d.ts +12 -0
- package/dist/mcp/tools/indexing.d.ts.map +1 -0
- package/dist/mcp/tools/indexing.js +289 -0
- package/dist/mcp/tools/indexing.js.map +1 -0
- package/dist/mcp/tools/memory.d.ts +14 -0
- package/dist/mcp/tools/memory.d.ts.map +1 -0
- package/dist/mcp/tools/memory.js +1170 -0
- package/dist/mcp/tools/memory.js.map +1 -0
- package/dist/mcp/tools/prd.d.ts +12 -0
- package/dist/mcp/tools/prd.d.ts.map +1 -0
- package/dist/mcp/tools/prd.js +276 -0
- package/dist/mcp/tools/prd.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +9 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +279 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +10 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +296 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/mcp/tools/web-fetch.d.ts +10 -0
- package/dist/mcp/tools/web-fetch.d.ts.map +1 -0
- package/dist/mcp/tools/web-fetch.js +107 -0
- package/dist/mcp/tools/web-fetch.js.map +1 -0
- package/dist/mcp/tools/web-search.d.ts +14 -0
- package/dist/mcp/tools/web-search.d.ts.map +1 -0
- package/dist/mcp/tools/web-search.js +427 -0
- package/dist/mcp/tools/web-search.js.map +1 -0
- package/dist/mcp/types.d.ts +16 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +5 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp-server.d.ts +9 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +9 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/prompts/analyze.d.ts +21 -0
- package/dist/prompts/analyze.d.ts.map +1 -0
- package/dist/prompts/analyze.js +27 -0
- package/dist/prompts/analyze.js.map +1 -0
- package/dist/prompts/briefing.d.ts +27 -0
- package/dist/prompts/briefing.d.ts.map +1 -0
- package/dist/prompts/briefing.js +123 -0
- package/dist/prompts/briefing.js.map +1 -0
- package/dist/prompts/chat.d.ts +8 -0
- package/dist/prompts/chat.d.ts.map +1 -0
- package/dist/prompts/chat.js +39 -0
- package/dist/prompts/chat.js.map +1 -0
- package/dist/prompts/daemon.d.ts +16 -0
- package/dist/prompts/daemon.d.ts.map +1 -0
- package/dist/prompts/daemon.js +46 -0
- package/dist/prompts/daemon.js.map +1 -0
- package/dist/prompts/extraction.d.ts +13 -0
- package/dist/prompts/extraction.d.ts.map +1 -0
- package/dist/prompts/extraction.js +93 -0
- package/dist/prompts/extraction.js.map +1 -0
- package/dist/prompts/index.d.ts +17 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +27 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/memory.d.ts +11 -0
- package/dist/prompts/memory.d.ts.map +1 -0
- package/dist/prompts/memory.js +23 -0
- package/dist/prompts/memory.js.map +1 -0
- package/dist/prompts/onboarding.d.ts +16 -0
- package/dist/prompts/onboarding.d.ts.map +1 -0
- package/dist/prompts/onboarding.js +183 -0
- package/dist/prompts/onboarding.js.map +1 -0
- package/dist/prompts/prd.d.ts +12 -0
- package/dist/prompts/prd.d.ts.map +1 -0
- package/dist/prompts/prd.js +211 -0
- package/dist/prompts/prd.js.map +1 -0
- package/dist/prompts/quality.d.ts +11 -0
- package/dist/prompts/quality.d.ts.map +1 -0
- package/dist/prompts/quality.js +11 -0
- package/dist/prompts/quality.js.map +1 -0
- package/dist/prompts/skills.d.ts +16 -0
- package/dist/prompts/skills.d.ts.map +1 -0
- package/dist/prompts/skills.js +30 -0
- package/dist/prompts/skills.js.map +1 -0
- package/hooks/succ-post-tool.cjs +227 -0
- package/hooks/succ-pre-tool.cjs +312 -0
- package/hooks/succ-session-end.cjs +85 -0
- package/hooks/succ-session-start.cjs +618 -0
- package/hooks/succ-stop-reflection.cjs +87 -0
- package/hooks/succ-user-prompt.cjs +220 -0
- package/package.json +128 -0
|
@@ -0,0 +1,1170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Memory tools
|
|
3
|
+
*
|
|
4
|
+
* - succ_remember: Save important information to memory
|
|
5
|
+
* - succ_recall: Recall past memories (hybrid BM25 + semantic search)
|
|
6
|
+
* - succ_forget: Delete memories
|
|
7
|
+
*
|
|
8
|
+
* Also includes helper functions:
|
|
9
|
+
* - rememberWithLLMExtraction: Extract structured facts from content
|
|
10
|
+
* - saveSingleMemory: Save single memory (fallback)
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { saveMemory, saveMemoriesBatch, getRecentMemories, getMemoryById, deleteMemory, deleteMemoriesOlderThan, deleteMemoriesByTag, hybridSearchMemories, saveGlobalMemory, hybridSearchGlobalMemories, getRecentGlobalMemories, closeDb, closeGlobalDb, } from '../../lib/storage/index.js';
|
|
15
|
+
import { getConfig, getProjectRoot, isGlobalOnlyMode, getIdleReflectionConfig, getReadinessGateConfig, getRetrievalConfig, } from '../../lib/config.js';
|
|
16
|
+
import { getEmbedding } from '../../lib/embeddings.js';
|
|
17
|
+
import { scoreMemory, passesQualityThreshold, formatQualityScore } from '../../lib/quality.js';
|
|
18
|
+
import { scanSensitive, formatMatches } from '../../lib/sensitive-filter.js';
|
|
19
|
+
import { parseDuration, applyTemporalScoring, getTemporalConfig } from '../../lib/temporal.js';
|
|
20
|
+
import { extractFactsWithLLM } from '../../lib/session-summary.js';
|
|
21
|
+
import { assessReadiness, formatReadinessHeader } from '../../lib/readiness.js';
|
|
22
|
+
import { trackTokenSavings, trackMemoryAccess, parseRelativeDate, projectPathParam, applyProjectPath, } from '../helpers.js';
|
|
23
|
+
import { logWarn } from '../../lib/fault-logger.js';
|
|
24
|
+
/**
|
|
25
|
+
* Remember with LLM extraction - extracts structured facts from content
|
|
26
|
+
*/
|
|
27
|
+
async function rememberWithLLMExtraction(params) {
|
|
28
|
+
const { content, tags, source, useGlobal, valid_from, valid_until, config } = params;
|
|
29
|
+
const idleConfig = getIdleReflectionConfig();
|
|
30
|
+
// Determine LLM options (default to Claude CLI)
|
|
31
|
+
const llmOptions = {
|
|
32
|
+
mode: 'claude',
|
|
33
|
+
model: idleConfig.agent_model || 'haiku',
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
// Extract facts from content
|
|
37
|
+
const facts = await extractFactsWithLLM(content, llmOptions);
|
|
38
|
+
if (facts.length === 0) {
|
|
39
|
+
// No facts extracted, fall back to saving original content
|
|
40
|
+
return await saveSingleMemory({
|
|
41
|
+
content,
|
|
42
|
+
tags,
|
|
43
|
+
source,
|
|
44
|
+
type: params.type,
|
|
45
|
+
useGlobal,
|
|
46
|
+
valid_from,
|
|
47
|
+
valid_until,
|
|
48
|
+
config,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Parse temporal validity periods once
|
|
52
|
+
let validFromDate;
|
|
53
|
+
let validUntilDate;
|
|
54
|
+
if (valid_from) {
|
|
55
|
+
validFromDate = parseDuration(valid_from);
|
|
56
|
+
}
|
|
57
|
+
if (valid_until) {
|
|
58
|
+
validUntilDate = parseDuration(valid_until);
|
|
59
|
+
}
|
|
60
|
+
// Snapshot before for learning delta
|
|
61
|
+
let snapshotBefore = null;
|
|
62
|
+
try {
|
|
63
|
+
const { takeMemorySnapshot } = await import('../../lib/learning-delta.js');
|
|
64
|
+
snapshotBefore = await takeMemorySnapshot();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Learning delta is optional
|
|
68
|
+
}
|
|
69
|
+
let saved = 0;
|
|
70
|
+
let skipped = 0;
|
|
71
|
+
const results = [];
|
|
72
|
+
// Phase 1: Pre-process all facts (sensitive filter, embedding, quality scoring)
|
|
73
|
+
const prepared = [];
|
|
74
|
+
for (const fact of facts) {
|
|
75
|
+
let factContent = fact.content;
|
|
76
|
+
// Check for sensitive information
|
|
77
|
+
if (config.sensitive_filter_enabled !== false) {
|
|
78
|
+
const scanResult = scanSensitive(factContent);
|
|
79
|
+
if (scanResult.hasSensitive) {
|
|
80
|
+
if (config.sensitive_auto_redact) {
|
|
81
|
+
factContent = scanResult.redactedText;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
results.push(`⚠ [${fact.type}] Skipped (sensitive): "${fact.content.substring(0, 40)}..."`);
|
|
85
|
+
skipped++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const embedding = await getEmbedding(factContent);
|
|
92
|
+
const factTags = [...tags, ...fact.tags, fact.type, 'extracted'];
|
|
93
|
+
// Score quality
|
|
94
|
+
let qualityScore = null;
|
|
95
|
+
if (config.quality_scoring_enabled !== false) {
|
|
96
|
+
qualityScore = await scoreMemory(factContent);
|
|
97
|
+
if (!passesQualityThreshold(qualityScore)) {
|
|
98
|
+
results.push(`⚠ [${fact.type}] Skipped (low quality): "${fact.content.substring(0, 40)}..."`);
|
|
99
|
+
skipped++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
prepared.push({ fact, content: factContent, embedding, tags: factTags, qualityScore });
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
107
|
+
results.push(`✗ [${fact.type}] Error: ${errorMsg}`);
|
|
108
|
+
skipped++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Phase 2: Batch save
|
|
112
|
+
if (useGlobal) {
|
|
113
|
+
// Global memories don't have batch API — save individually
|
|
114
|
+
for (const item of prepared) {
|
|
115
|
+
const projectName = path.basename(getProjectRoot());
|
|
116
|
+
const result = await saveGlobalMemory(item.content, item.embedding, item.tags, source || 'extraction', projectName, { type: item.fact.type });
|
|
117
|
+
if (result.isDuplicate) {
|
|
118
|
+
results.push(`⚠ [${item.fact.type}] Duplicate: "${item.fact.content.substring(0, 40)}..."`);
|
|
119
|
+
skipped++;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
results.push(`✓ [${item.fact.type}] id:${result.id} "${item.fact.content.substring(0, 50)}..."`);
|
|
123
|
+
saved++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (prepared.length > 0) {
|
|
128
|
+
// Local memories — use batch save (single dedup check + transaction)
|
|
129
|
+
const batchInputs = prepared.map((item) => ({
|
|
130
|
+
content: item.content,
|
|
131
|
+
embedding: item.embedding,
|
|
132
|
+
tags: item.tags,
|
|
133
|
+
type: item.fact.type,
|
|
134
|
+
source: source || 'extraction',
|
|
135
|
+
qualityScore: item.qualityScore
|
|
136
|
+
? { score: item.qualityScore.score, factors: item.qualityScore.factors }
|
|
137
|
+
: undefined,
|
|
138
|
+
validFrom: validFromDate,
|
|
139
|
+
validUntil: validUntilDate,
|
|
140
|
+
}));
|
|
141
|
+
const batchResult = await saveMemoriesBatch(batchInputs);
|
|
142
|
+
for (let i = 0; i < batchResult.results.length; i++) {
|
|
143
|
+
const r = batchResult.results[i];
|
|
144
|
+
const item = prepared[r.index];
|
|
145
|
+
if (r.isDuplicate) {
|
|
146
|
+
results.push(`⚠ [${item.fact.type}] Duplicate: "${item.fact.content.substring(0, 40)}..."`);
|
|
147
|
+
skipped++;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
results.push(`✓ [${item.fact.type}] id:${r.id} "${item.fact.content.substring(0, 50)}..."`);
|
|
151
|
+
saved++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Log learning delta if any memories were saved
|
|
156
|
+
if (saved > 0 && snapshotBefore) {
|
|
157
|
+
try {
|
|
158
|
+
const { takeMemorySnapshot, calculateLearningDelta } = await import('../../lib/learning-delta.js');
|
|
159
|
+
const { appendProgressEntry } = await import('../../lib/progress-log.js');
|
|
160
|
+
const snapshotAfter = await takeMemorySnapshot();
|
|
161
|
+
const delta = calculateLearningDelta(snapshotBefore, snapshotAfter, 'mcp-remember');
|
|
162
|
+
await appendProgressEntry(delta);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Progress logging is optional
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: 'text',
|
|
172
|
+
text: `Extracted ${facts.length} facts:\n${results.join('\n')}\n\nSummary: ${saved} saved, ${skipped} skipped`,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
// If extraction fails, fall back to saving original content
|
|
179
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
180
|
+
return await saveSingleMemory({
|
|
181
|
+
content,
|
|
182
|
+
tags,
|
|
183
|
+
source,
|
|
184
|
+
type: params.type,
|
|
185
|
+
useGlobal,
|
|
186
|
+
valid_from,
|
|
187
|
+
valid_until,
|
|
188
|
+
config,
|
|
189
|
+
fallbackReason: `LLM extraction failed: ${errorMsg}`,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
closeDb();
|
|
194
|
+
closeGlobalDb();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Save a single memory (used as fallback or when extraction is disabled)
|
|
199
|
+
*/
|
|
200
|
+
async function saveSingleMemory(params) {
|
|
201
|
+
const { content, tags, source, type, useGlobal, valid_from, valid_until, config, fallbackReason, } = params;
|
|
202
|
+
// Check for sensitive information
|
|
203
|
+
let processedContent = content;
|
|
204
|
+
if (config.sensitive_filter_enabled !== false) {
|
|
205
|
+
const scanResult = scanSensitive(content);
|
|
206
|
+
if (scanResult.hasSensitive) {
|
|
207
|
+
if (config.sensitive_auto_redact) {
|
|
208
|
+
processedContent = scanResult.redactedText;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
return {
|
|
212
|
+
content: [
|
|
213
|
+
{
|
|
214
|
+
type: 'text',
|
|
215
|
+
text: `⚠ Sensitive information detected:\n${formatMatches(scanResult.matches)}\n\nMemory not saved.`,
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Parse temporal validity periods
|
|
223
|
+
let validFromDate;
|
|
224
|
+
let validUntilDate;
|
|
225
|
+
if (valid_from) {
|
|
226
|
+
validFromDate = parseDuration(valid_from);
|
|
227
|
+
}
|
|
228
|
+
if (valid_until) {
|
|
229
|
+
validUntilDate = parseDuration(valid_until);
|
|
230
|
+
}
|
|
231
|
+
const embedding = await getEmbedding(processedContent);
|
|
232
|
+
let qualityScore = null;
|
|
233
|
+
if (config.quality_scoring_enabled !== false) {
|
|
234
|
+
qualityScore = await scoreMemory(processedContent);
|
|
235
|
+
if (!passesQualityThreshold(qualityScore)) {
|
|
236
|
+
return {
|
|
237
|
+
content: [
|
|
238
|
+
{
|
|
239
|
+
type: 'text',
|
|
240
|
+
text: `⚠ Memory quality too low: ${formatQualityScore(qualityScore)}`,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const fallbackPrefix = fallbackReason ? `(${fallbackReason})\n` : '';
|
|
247
|
+
if (useGlobal) {
|
|
248
|
+
const projectName = path.basename(getProjectRoot());
|
|
249
|
+
const result = await saveGlobalMemory(processedContent, embedding, tags, source, projectName, {
|
|
250
|
+
type,
|
|
251
|
+
});
|
|
252
|
+
closeGlobalDb();
|
|
253
|
+
if (result.isDuplicate) {
|
|
254
|
+
return {
|
|
255
|
+
content: [
|
|
256
|
+
{
|
|
257
|
+
type: 'text',
|
|
258
|
+
text: `${fallbackPrefix}⚠ Similar global memory exists (id: ${result.id}). Skipped duplicate.`,
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
content: [
|
|
265
|
+
{
|
|
266
|
+
type: 'text',
|
|
267
|
+
text: `${fallbackPrefix}✓ Remembered globally (id: ${result.id}): "${processedContent.substring(0, 80)}..."`,
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const result = await saveMemory(processedContent, embedding, tags, source, {
|
|
273
|
+
type,
|
|
274
|
+
qualityScore: qualityScore
|
|
275
|
+
? { score: qualityScore.score, factors: qualityScore.factors }
|
|
276
|
+
: undefined,
|
|
277
|
+
validFrom: validFromDate,
|
|
278
|
+
validUntil: validUntilDate,
|
|
279
|
+
});
|
|
280
|
+
closeDb();
|
|
281
|
+
if (result.isDuplicate) {
|
|
282
|
+
return {
|
|
283
|
+
content: [
|
|
284
|
+
{
|
|
285
|
+
type: 'text',
|
|
286
|
+
text: `${fallbackPrefix}⚠ Similar memory exists (id: ${result.id}). Skipped duplicate.`,
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
content: [
|
|
293
|
+
{
|
|
294
|
+
type: 'text',
|
|
295
|
+
text: `${fallbackPrefix}✓ Remembered (id: ${result.id}): "${processedContent.substring(0, 80)}..."`,
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
export function registerMemoryTools(server) {
|
|
301
|
+
// Tool: succ_remember - Save important information to memory
|
|
302
|
+
server.tool('succ_remember', 'Save important information to long-term memory. By default, uses LLM to extract structured facts from content. Use extract=false to save content as-is. In projects without .succ/, automatically saves to global memory. Use valid_until for temporary info.', {
|
|
303
|
+
content: z.string().describe('The information to remember'),
|
|
304
|
+
tags: z
|
|
305
|
+
.array(z.string())
|
|
306
|
+
.optional()
|
|
307
|
+
.default([])
|
|
308
|
+
.describe('Tags for categorization (e.g., ["decision", "architecture"])'),
|
|
309
|
+
source: z
|
|
310
|
+
.string()
|
|
311
|
+
.optional()
|
|
312
|
+
.describe('Source context (e.g., "user request", "bug fix", file path)'),
|
|
313
|
+
type: z
|
|
314
|
+
.enum(['observation', 'decision', 'learning', 'error', 'pattern', 'dead_end'])
|
|
315
|
+
.optional()
|
|
316
|
+
.default('observation')
|
|
317
|
+
.describe('Memory type: observation (facts), decision (choices), learning (insights), error (failures), pattern (recurring themes), dead_end (failed approaches)'),
|
|
318
|
+
global: z
|
|
319
|
+
.boolean()
|
|
320
|
+
.optional()
|
|
321
|
+
.default(false)
|
|
322
|
+
.describe('Save to global memory (shared across all projects). Auto-enabled if project has no .succ/'),
|
|
323
|
+
valid_from: z
|
|
324
|
+
.string()
|
|
325
|
+
.optional()
|
|
326
|
+
.describe('When this fact becomes valid. Use ISO date (2025-03-01) or duration from now (7d, 2w, 1m). For scheduled changes.'),
|
|
327
|
+
valid_until: z
|
|
328
|
+
.string()
|
|
329
|
+
.optional()
|
|
330
|
+
.describe('When this fact expires. Use ISO date (2025-12-31) or duration from now (7d, 30d). For sprint goals, temp workarounds.'),
|
|
331
|
+
extract: z
|
|
332
|
+
.boolean()
|
|
333
|
+
.optional()
|
|
334
|
+
.describe('Extract structured facts using LLM (default: from config, typically true). Set to false to save content as-is.'),
|
|
335
|
+
project_path: projectPathParam,
|
|
336
|
+
}, async ({ content, tags, source, type, global: useGlobal, valid_from, valid_until, extract, project_path, }) => {
|
|
337
|
+
await applyProjectPath(project_path);
|
|
338
|
+
// Force global mode if project not initialized
|
|
339
|
+
const globalOnlyMode = isGlobalOnlyMode();
|
|
340
|
+
if (globalOnlyMode && !useGlobal) {
|
|
341
|
+
useGlobal = true;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const config = getConfig();
|
|
345
|
+
// Determine if LLM extraction should be used
|
|
346
|
+
const configDefault = config.remember_extract_default !== false; // default true
|
|
347
|
+
const useExtract = extract ?? configDefault;
|
|
348
|
+
// If extraction is enabled, use LLM to extract structured facts
|
|
349
|
+
if (useExtract) {
|
|
350
|
+
return await rememberWithLLMExtraction({
|
|
351
|
+
content,
|
|
352
|
+
tags,
|
|
353
|
+
source,
|
|
354
|
+
type,
|
|
355
|
+
useGlobal,
|
|
356
|
+
valid_from,
|
|
357
|
+
valid_until,
|
|
358
|
+
config,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
// Check for sensitive information (non-interactive mode for MCP)
|
|
362
|
+
if (config.sensitive_filter_enabled !== false) {
|
|
363
|
+
const scanResult = scanSensitive(content);
|
|
364
|
+
if (scanResult.hasSensitive) {
|
|
365
|
+
if (config.sensitive_auto_redact) {
|
|
366
|
+
// Auto-redact and continue
|
|
367
|
+
content = scanResult.redactedText;
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// Block - can't prompt user in MCP mode
|
|
371
|
+
return {
|
|
372
|
+
content: [
|
|
373
|
+
{
|
|
374
|
+
type: 'text',
|
|
375
|
+
text: `⚠ Sensitive information detected:\n${formatMatches(scanResult.matches)}\n\nMemory not saved. Set "sensitive_auto_redact": true in config to auto-redact, or use CLI with --redact-sensitive flag.`,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Parse temporal validity periods
|
|
383
|
+
let validFromDate;
|
|
384
|
+
let validUntilDate;
|
|
385
|
+
if (valid_from) {
|
|
386
|
+
try {
|
|
387
|
+
validFromDate = parseDuration(valid_from);
|
|
388
|
+
}
|
|
389
|
+
catch (e) {
|
|
390
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
391
|
+
return {
|
|
392
|
+
content: [
|
|
393
|
+
{
|
|
394
|
+
type: 'text',
|
|
395
|
+
text: `Invalid valid_from: ${errorMsg}. Use ISO date (2025-03-01) or duration (7d, 2w, 1m).`,
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
isError: true,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (valid_until) {
|
|
403
|
+
try {
|
|
404
|
+
validUntilDate = parseDuration(valid_until);
|
|
405
|
+
}
|
|
406
|
+
catch (e) {
|
|
407
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
408
|
+
return {
|
|
409
|
+
content: [
|
|
410
|
+
{
|
|
411
|
+
type: 'text',
|
|
412
|
+
text: `Invalid valid_until: ${errorMsg}. Use ISO date (2025-12-31) or duration (7d, 30d).`,
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
isError: true,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const embedding = await getEmbedding(content);
|
|
420
|
+
let qualityScore = null;
|
|
421
|
+
if (config.quality_scoring_enabled !== false) {
|
|
422
|
+
qualityScore = await scoreMemory(content);
|
|
423
|
+
// Check if it passes the threshold
|
|
424
|
+
if (!passesQualityThreshold(qualityScore)) {
|
|
425
|
+
return {
|
|
426
|
+
content: [
|
|
427
|
+
{
|
|
428
|
+
type: 'text',
|
|
429
|
+
text: `⚠ Memory quality too low: ${formatQualityScore(qualityScore)}\nThreshold: ${((config.quality_scoring_threshold ?? 0) * 100).toFixed(0)}%\nContent: "${content.substring(0, 100)}..."`,
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// Format validity period for display
|
|
436
|
+
const validityStr = validFromDate || validUntilDate
|
|
437
|
+
? ` (valid: ${validFromDate ? validFromDate.toLocaleDateString() : '∞'} → ${validUntilDate ? validUntilDate.toLocaleDateString() : '∞'})`
|
|
438
|
+
: '';
|
|
439
|
+
if (useGlobal) {
|
|
440
|
+
const projectName = path.basename(getProjectRoot());
|
|
441
|
+
const result = await saveGlobalMemory(content, embedding, tags, source, projectName, {
|
|
442
|
+
type,
|
|
443
|
+
});
|
|
444
|
+
const tagStr = tags.length > 0 ? ` [${tags.join(', ')}]` : '';
|
|
445
|
+
const qualityStr = qualityScore ? ` ${formatQualityScore(qualityScore)}` : '';
|
|
446
|
+
if (result.isDuplicate) {
|
|
447
|
+
return {
|
|
448
|
+
content: [
|
|
449
|
+
{
|
|
450
|
+
type: 'text',
|
|
451
|
+
text: `⚠ Similar global memory exists (id: ${result.id}, ${((result.similarity || 0) * 100).toFixed(0)}% similar). Skipped duplicate.`,
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
content: [
|
|
458
|
+
{
|
|
459
|
+
type: 'text',
|
|
460
|
+
text: `✓ Remembered globally (id: ${result.id})${tagStr}${qualityStr}${validityStr} (project: ${projectName}):\n"${content.substring(0, 100)}${content.length > 100 ? '...' : ''}"`,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const result = await saveMemory(content, embedding, tags, source, {
|
|
466
|
+
type,
|
|
467
|
+
qualityScore: qualityScore
|
|
468
|
+
? { score: qualityScore.score, factors: qualityScore.factors }
|
|
469
|
+
: undefined,
|
|
470
|
+
validFrom: validFromDate,
|
|
471
|
+
validUntil: validUntilDate,
|
|
472
|
+
});
|
|
473
|
+
const tagStr = tags.length > 0 ? ` [${tags.join(', ')}]` : '';
|
|
474
|
+
const typeStr = type !== 'observation' ? ` (${type})` : '';
|
|
475
|
+
const qualityStr = qualityScore ? ` ${formatQualityScore(qualityScore)}` : '';
|
|
476
|
+
if (result.isDuplicate) {
|
|
477
|
+
return {
|
|
478
|
+
content: [
|
|
479
|
+
{
|
|
480
|
+
type: 'text',
|
|
481
|
+
text: `⚠ Similar memory exists (id: ${result.id}, ${((result.similarity || 0) * 100).toFixed(0)}% similar). Skipped duplicate.`,
|
|
482
|
+
},
|
|
483
|
+
],
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
// Log to progress file (fire-and-forget)
|
|
487
|
+
try {
|
|
488
|
+
const { appendRawEntry } = await import('../../lib/progress-log.js');
|
|
489
|
+
await appendRawEntry(`manual | +1 fact (${type}) | topics: ${tags.join(', ') || 'untagged'}`);
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
// Progress logging is optional
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
content: [
|
|
496
|
+
{
|
|
497
|
+
type: 'text',
|
|
498
|
+
text: `✓ Remembered${typeStr} (id: ${result.id})${tagStr}${qualityStr}${validityStr}:\n"${content.substring(0, 100)}${content.length > 100 ? '...' : ''}"`,
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
505
|
+
return {
|
|
506
|
+
content: [
|
|
507
|
+
{
|
|
508
|
+
type: 'text',
|
|
509
|
+
text: `Error saving memory: ${errorMsg}`,
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
isError: true,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
finally {
|
|
516
|
+
closeDb();
|
|
517
|
+
closeGlobalDb();
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
// Tool: succ_recall - Recall past memories (hybrid BM25 + semantic search)
|
|
521
|
+
server.tool('succ_recall', 'Recall relevant memories from past sessions using hybrid search (BM25 + semantic). Searches both project-local and global (cross-project) memories. Works even in projects without .succ/ (global-only mode). Use as_of_date for point-in-time queries.', {
|
|
522
|
+
query: z.string().describe('What to recall (semantic search)'),
|
|
523
|
+
limit: z
|
|
524
|
+
.number()
|
|
525
|
+
.optional()
|
|
526
|
+
.describe('Maximum number of memories (default: from config, typically 10)'),
|
|
527
|
+
tags: z.array(z.string()).optional().describe('Filter by tags (e.g., ["decision"])'),
|
|
528
|
+
since: z
|
|
529
|
+
.string()
|
|
530
|
+
.optional()
|
|
531
|
+
.describe('Only memories after this date (ISO format or "yesterday", "last week")'),
|
|
532
|
+
as_of_date: z
|
|
533
|
+
.string()
|
|
534
|
+
.optional()
|
|
535
|
+
.describe('Point-in-time query: show memories as they were valid on this date. For post-mortems, audits, debugging past state. ISO format (2024-06-01).'),
|
|
536
|
+
project_path: projectPathParam,
|
|
537
|
+
}, async ({ query, limit: rawLimit, tags, since, as_of_date, project_path }) => {
|
|
538
|
+
await applyProjectPath(project_path);
|
|
539
|
+
const globalOnlyMode = isGlobalOnlyMode();
|
|
540
|
+
const retrievalConfig = getRetrievalConfig();
|
|
541
|
+
const limit = rawLimit ?? retrievalConfig.default_top_k;
|
|
542
|
+
try {
|
|
543
|
+
// Special case: "*" means "show recent memories" (no semantic search)
|
|
544
|
+
const isWildcard = query === '*' || query === '**' || query.trim() === '';
|
|
545
|
+
// Parse relative date strings
|
|
546
|
+
let sinceDate;
|
|
547
|
+
if (since) {
|
|
548
|
+
const now = new Date();
|
|
549
|
+
const lower = since.toLowerCase();
|
|
550
|
+
if (lower === 'yesterday') {
|
|
551
|
+
sinceDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
552
|
+
}
|
|
553
|
+
else if (lower === 'last week' || lower === 'week') {
|
|
554
|
+
sinceDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
555
|
+
}
|
|
556
|
+
else if (lower === 'last month' || lower === 'month') {
|
|
557
|
+
sinceDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
558
|
+
}
|
|
559
|
+
else if (lower === 'today') {
|
|
560
|
+
sinceDate = new Date(now.setHours(0, 0, 0, 0));
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
sinceDate = new Date(since);
|
|
564
|
+
if (isNaN(sinceDate.getTime())) {
|
|
565
|
+
sinceDate = undefined;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// For wildcard queries, just get recent memories without semantic search
|
|
570
|
+
if (isWildcard) {
|
|
571
|
+
const recentLocal = globalOnlyMode ? [] : await getRecentMemories(limit);
|
|
572
|
+
const recentGlobal = await getRecentGlobalMemories(limit);
|
|
573
|
+
// Apply tag filter if specified
|
|
574
|
+
let filteredLocal = recentLocal;
|
|
575
|
+
let filteredGlobal = recentGlobal;
|
|
576
|
+
if (tags && tags.length > 0) {
|
|
577
|
+
filteredLocal = recentLocal.filter((m) => {
|
|
578
|
+
const memTags = Array.isArray(m.tags) ? m.tags : [];
|
|
579
|
+
return tags.some((t) => memTags.includes(t));
|
|
580
|
+
});
|
|
581
|
+
filteredGlobal = recentGlobal.filter((m) => {
|
|
582
|
+
const memTags = Array.isArray(m.tags) ? m.tags : [];
|
|
583
|
+
return tags.some((t) => memTags.includes(t));
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
// Apply date filter if specified
|
|
587
|
+
if (sinceDate) {
|
|
588
|
+
filteredLocal = filteredLocal.filter((m) => new Date(m.created_at) >= sinceDate);
|
|
589
|
+
filteredGlobal = filteredGlobal.filter((m) => new Date(m.created_at) >= sinceDate);
|
|
590
|
+
}
|
|
591
|
+
const parseTags = (t) => {
|
|
592
|
+
if (!t)
|
|
593
|
+
return [];
|
|
594
|
+
if (Array.isArray(t))
|
|
595
|
+
return t;
|
|
596
|
+
return t
|
|
597
|
+
.split(',')
|
|
598
|
+
.map((s) => s.trim())
|
|
599
|
+
.filter(Boolean);
|
|
600
|
+
};
|
|
601
|
+
const allRecent = [
|
|
602
|
+
...filteredLocal.map((m) => ({ ...m, tags: parseTags(m.tags), isGlobal: false })),
|
|
603
|
+
...filteredGlobal.map((m) => ({ ...m, isGlobal: true })),
|
|
604
|
+
].slice(0, limit);
|
|
605
|
+
if (allRecent.length === 0) {
|
|
606
|
+
return {
|
|
607
|
+
content: [
|
|
608
|
+
{
|
|
609
|
+
type: 'text',
|
|
610
|
+
text: globalOnlyMode
|
|
611
|
+
? 'No global memories found.'
|
|
612
|
+
: 'No memories found. Use succ_remember to save memories.',
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const localCount = filteredLocal.length;
|
|
618
|
+
const globalCount = filteredGlobal.length;
|
|
619
|
+
const formatted = allRecent
|
|
620
|
+
.map((m, i) => {
|
|
621
|
+
const tagStr = m.tags.length > 0 ? ` [[${m.tags.map((t) => `"${t}"`).join(', ')}]]` : '';
|
|
622
|
+
const date = new Date(m.created_at).toLocaleDateString();
|
|
623
|
+
const scope = m.isGlobal ? '[GLOBAL] ' : '';
|
|
624
|
+
const source = m.source ? ` (from: ${m.source})` : '';
|
|
625
|
+
const matchPct = 'similarity' in m && m.similarity
|
|
626
|
+
? ` (${Math.round(m.similarity * 100)}% match)`
|
|
627
|
+
: '';
|
|
628
|
+
return `### ${i + 1}. ${scope}${date}${tagStr}${source}${matchPct}\n\n${m.content}\n`;
|
|
629
|
+
})
|
|
630
|
+
.join('\n---\n\n');
|
|
631
|
+
return {
|
|
632
|
+
content: [
|
|
633
|
+
{
|
|
634
|
+
type: 'text',
|
|
635
|
+
text: `Found ${allRecent.length} recent memories (${localCount} local, ${globalCount} global):\n\n${formatted}`,
|
|
636
|
+
},
|
|
637
|
+
],
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
const queryEmbedding = await getEmbedding(query);
|
|
641
|
+
// ── Temporal query decomposition: multi-pass retrieval for time-spanning questions ──
|
|
642
|
+
const isTemporalQuery = /\b(between|after|before|days|weeks|months|since|how long|how many days|when did|first time|last time|started|ended|began|stopped)\b/i.test(query) ||
|
|
643
|
+
/\b(между|после|до|перед|дней|недель|месяцев|с тех пор|сколько дней|сколько времени|когда|впервые|в первый раз|в последний раз|начал[аиось]?|закончил[аиось]?|прекратил[аиось]?)\b/i.test(query);
|
|
644
|
+
let localResults;
|
|
645
|
+
if (isTemporalQuery && !globalOnlyMode) {
|
|
646
|
+
// Extract key entities from query for separate searches
|
|
647
|
+
// e.g., "How many days between starting project X and deploying it?"
|
|
648
|
+
// → subqueries: ["starting project X", "deploying project X"]
|
|
649
|
+
const subQueries = await extractTemporalSubqueriesAsync(query);
|
|
650
|
+
if (subQueries.length > 1) {
|
|
651
|
+
// Multi-pass: search for each entity separately, merge results
|
|
652
|
+
const allSubResults = new Map();
|
|
653
|
+
for (const subQuery of subQueries) {
|
|
654
|
+
const subEmbedding = await getEmbedding(subQuery);
|
|
655
|
+
const subResults = await hybridSearchMemories(subQuery, subEmbedding, limit, 0.2, retrievalConfig.bm25_alpha);
|
|
656
|
+
for (const r of subResults) {
|
|
657
|
+
if (!allSubResults.has(r.id) || r.similarity > allSubResults.get(r.id).similarity) {
|
|
658
|
+
allSubResults.set(r.id, r);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// Also include results from the original query
|
|
663
|
+
const originalResults = await hybridSearchMemories(query, queryEmbedding, limit, 0.3, retrievalConfig.bm25_alpha);
|
|
664
|
+
for (const r of originalResults) {
|
|
665
|
+
if (!allSubResults.has(r.id) || r.similarity > allSubResults.get(r.id).similarity) {
|
|
666
|
+
allSubResults.set(r.id, r);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
localResults = Array.from(allSubResults.values())
|
|
670
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
671
|
+
.slice(0, limit * 2);
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
localResults = await hybridSearchMemories(query, queryEmbedding, limit * 2, 0.3, retrievalConfig.bm25_alpha);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
// Standard single-pass search
|
|
679
|
+
localResults = globalOnlyMode
|
|
680
|
+
? []
|
|
681
|
+
: await hybridSearchMemories(query, queryEmbedding, limit * 2, 0.3, retrievalConfig.bm25_alpha);
|
|
682
|
+
}
|
|
683
|
+
// ── Query expansion: LLM-generated alternative queries for broader recall ──
|
|
684
|
+
if (retrievalConfig.query_expansion_enabled &&
|
|
685
|
+
!globalOnlyMode &&
|
|
686
|
+
query.split(/\s+/).length > 5) {
|
|
687
|
+
try {
|
|
688
|
+
const { expandQuery } = await import('../../lib/query-expansion.js');
|
|
689
|
+
const expandedQueries = await expandQuery(query, retrievalConfig.query_expansion_mode);
|
|
690
|
+
if (expandedQueries.length > 0) {
|
|
691
|
+
const existingIds = new Set(localResults.map((r) => r.id));
|
|
692
|
+
for (const eq of expandedQueries) {
|
|
693
|
+
const eqEmbedding = await getEmbedding(eq);
|
|
694
|
+
const eqResults = await hybridSearchMemories(eq, eqEmbedding, limit, 0.3, retrievalConfig.bm25_alpha);
|
|
695
|
+
for (const r of eqResults) {
|
|
696
|
+
if (!existingIds.has(r.id)) {
|
|
697
|
+
localResults.push(r);
|
|
698
|
+
existingIds.add(r.id);
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
// Keep the higher similarity score
|
|
702
|
+
const existing = localResults.find((lr) => lr.id === r.id);
|
|
703
|
+
if (existing && r.similarity > existing.similarity) {
|
|
704
|
+
existing.similarity = r.similarity;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
localResults.sort((a, b) => b.similarity - a.similarity);
|
|
710
|
+
localResults = localResults.slice(0, limit * 2);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
catch (err) {
|
|
714
|
+
logWarn('memory-tool', 'Query expansion failed', {
|
|
715
|
+
error: err instanceof Error ? err.message : String(err),
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// Helper to parse tags (can be string or array depending on backend)
|
|
720
|
+
const parseTags = (t) => {
|
|
721
|
+
if (!t)
|
|
722
|
+
return [];
|
|
723
|
+
if (Array.isArray(t))
|
|
724
|
+
return t;
|
|
725
|
+
return t
|
|
726
|
+
.split(',')
|
|
727
|
+
.map((s) => s.trim())
|
|
728
|
+
.filter(Boolean);
|
|
729
|
+
};
|
|
730
|
+
// Apply tag filter if specified
|
|
731
|
+
if (tags && tags.length > 0) {
|
|
732
|
+
localResults = localResults.filter((m) => {
|
|
733
|
+
const memTags = parseTags(m.tags);
|
|
734
|
+
return tags.some((t) => memTags.includes(t));
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
// Apply date filter if specified
|
|
738
|
+
if (sinceDate) {
|
|
739
|
+
localResults = localResults.filter((m) => new Date(m.created_at) >= sinceDate);
|
|
740
|
+
}
|
|
741
|
+
// Apply point-in-time validity filter (as_of_date)
|
|
742
|
+
let asOfDateObj;
|
|
743
|
+
if (as_of_date) {
|
|
744
|
+
asOfDateObj = new Date(as_of_date);
|
|
745
|
+
if (isNaN(asOfDateObj.getTime())) {
|
|
746
|
+
return {
|
|
747
|
+
content: [
|
|
748
|
+
{
|
|
749
|
+
type: 'text',
|
|
750
|
+
text: `Invalid as_of_date: "${as_of_date}". Use ISO format (2024-06-01).`,
|
|
751
|
+
},
|
|
752
|
+
],
|
|
753
|
+
isError: true,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
localResults = localResults.filter((m) => {
|
|
757
|
+
const createdAt = new Date(m.created_at);
|
|
758
|
+
if (createdAt > asOfDateObj)
|
|
759
|
+
return false;
|
|
760
|
+
if (m.valid_from) {
|
|
761
|
+
const validFrom = new Date(m.valid_from);
|
|
762
|
+
if (validFrom > asOfDateObj)
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
if (m.valid_until) {
|
|
766
|
+
const validUntil = new Date(m.valid_until);
|
|
767
|
+
if (validUntil < asOfDateObj)
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
return true;
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
localResults = localResults.slice(0, limit);
|
|
774
|
+
// Global memories now use hybrid search (BM25 + vector)
|
|
775
|
+
const globalResults = await hybridSearchGlobalMemories(query, queryEmbedding, limit, 0.3, retrievalConfig.bm25_alpha, tags, sinceDate);
|
|
776
|
+
// Merge and sort by similarity
|
|
777
|
+
let allResults = [
|
|
778
|
+
...localResults.map((r) => ({ ...r, tags: parseTags(r.tags), isGlobal: false })),
|
|
779
|
+
...globalResults.map((r) => ({ ...r, isGlobal: true })),
|
|
780
|
+
]
|
|
781
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
782
|
+
.slice(0, limit);
|
|
783
|
+
// Apply temporal scoring if enabled (time decay + access boost)
|
|
784
|
+
// Auto-skip: when all results are <24h old, decay adds noise not signal
|
|
785
|
+
const temporalConfig = getTemporalConfig();
|
|
786
|
+
if (temporalConfig.enabled && !as_of_date) {
|
|
787
|
+
const now = Date.now();
|
|
788
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
789
|
+
const allRecent = retrievalConfig.temporal_auto_skip &&
|
|
790
|
+
allResults.length > 0 &&
|
|
791
|
+
allResults.every((r) => now - new Date(r.created_at).getTime() < DAY_MS);
|
|
792
|
+
if (!allRecent) {
|
|
793
|
+
const scoredResults = applyTemporalScoring(allResults.map((r) => ({
|
|
794
|
+
...r,
|
|
795
|
+
last_accessed: r.last_accessed || null,
|
|
796
|
+
access_count: r.access_count || 0,
|
|
797
|
+
valid_from: r.valid_from || null,
|
|
798
|
+
valid_until: r.valid_until || null,
|
|
799
|
+
})), temporalConfig);
|
|
800
|
+
allResults = scoredResults;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
// Apply dead-end boost: surface dead-end memories higher in results
|
|
804
|
+
const config = getConfig();
|
|
805
|
+
const deadEndBoost = config.dead_end_boost ?? 0.15;
|
|
806
|
+
if (deadEndBoost > 0) {
|
|
807
|
+
allResults = allResults.map((r) => {
|
|
808
|
+
const memType = r.type;
|
|
809
|
+
const memTags = Array.isArray(r.tags) ? r.tags : [];
|
|
810
|
+
const isDeadEnd = memType === 'dead_end' || memTags.includes('dead-end');
|
|
811
|
+
if (isDeadEnd) {
|
|
812
|
+
return {
|
|
813
|
+
...r,
|
|
814
|
+
similarity: Math.min(1.0, r.similarity + deadEndBoost),
|
|
815
|
+
_isDeadEnd: true,
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
return r;
|
|
819
|
+
});
|
|
820
|
+
allResults.sort((a, b) => b.similarity - a.similarity);
|
|
821
|
+
}
|
|
822
|
+
// Apply centrality boost: well-connected memories rank higher
|
|
823
|
+
if (config.graph_centrality?.enabled && allResults.length > 0) {
|
|
824
|
+
try {
|
|
825
|
+
const { applyCentralityBoost } = await import('../../lib/graph/centrality.js');
|
|
826
|
+
allResults = await applyCentralityBoost(allResults, config.graph_centrality);
|
|
827
|
+
}
|
|
828
|
+
catch {
|
|
829
|
+
// Centrality module not available — skip
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
// Quality boost: higher-quality memories rank higher
|
|
833
|
+
if (retrievalConfig.quality_boost_enabled && allResults.length > 0) {
|
|
834
|
+
const weight = retrievalConfig.quality_boost_weight;
|
|
835
|
+
allResults = allResults.map((r) => {
|
|
836
|
+
const result = r;
|
|
837
|
+
const qs = 'quality_score' in result && typeof result.quality_score === 'number'
|
|
838
|
+
? result.quality_score
|
|
839
|
+
: null;
|
|
840
|
+
if (qs != null && qs > 0) {
|
|
841
|
+
const factor = 1 - weight + weight * qs;
|
|
842
|
+
return { ...result, similarity: result.similarity * factor };
|
|
843
|
+
}
|
|
844
|
+
return result;
|
|
845
|
+
});
|
|
846
|
+
allResults.sort((a, b) => b.similarity - a.similarity);
|
|
847
|
+
}
|
|
848
|
+
// MMR diversity reranking: reduce near-duplicate results
|
|
849
|
+
if (retrievalConfig.mmr_enabled && allResults.length > 1) {
|
|
850
|
+
try {
|
|
851
|
+
const { applyMMR } = await import('../../lib/mmr.js');
|
|
852
|
+
const { getMemoryEmbeddingsByIds } = await import('../../lib/storage/index.js');
|
|
853
|
+
const embMap = await getMemoryEmbeddingsByIds(allResults.map((r) => r.id));
|
|
854
|
+
const mmrInput = allResults.map((r) => ({
|
|
855
|
+
...r,
|
|
856
|
+
embedding: embMap.get(r.id) || null,
|
|
857
|
+
}));
|
|
858
|
+
allResults = applyMMR(mmrInput, Array.from(queryEmbedding), retrievalConfig.mmr_lambda, limit);
|
|
859
|
+
}
|
|
860
|
+
catch {
|
|
861
|
+
// MMR module not available — skip
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (allResults.length === 0) {
|
|
865
|
+
// Try to show recent memories as fallback
|
|
866
|
+
const recentLocal = await getRecentMemories(2);
|
|
867
|
+
const recentGlobal = await getRecentGlobalMemories(2);
|
|
868
|
+
const recent = [
|
|
869
|
+
...recentLocal.map((m) => ({ ...m, isGlobal: false })),
|
|
870
|
+
...recentGlobal.map((m) => ({ ...m, isGlobal: true })),
|
|
871
|
+
].slice(0, 3);
|
|
872
|
+
if (recent.length === 0) {
|
|
873
|
+
return {
|
|
874
|
+
content: [
|
|
875
|
+
{
|
|
876
|
+
type: 'text',
|
|
877
|
+
text: `No memories found for "${query}". Memory is empty.`,
|
|
878
|
+
},
|
|
879
|
+
],
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
const recentFormatted = recent
|
|
883
|
+
.map((m, i) => {
|
|
884
|
+
const memTags = parseTags(m.tags);
|
|
885
|
+
const tagStr = memTags.length > 0 ? ` [${memTags.join(', ')}]` : '';
|
|
886
|
+
const date = new Date(m.created_at).toLocaleDateString();
|
|
887
|
+
const scope = m.isGlobal ? '[GLOBAL] ' : '';
|
|
888
|
+
return `${i + 1}. ${scope}(${date})${tagStr}: ${m.content.substring(0, 150)}${m.content.length > 150 ? '...' : ''}`;
|
|
889
|
+
})
|
|
890
|
+
.join('\n');
|
|
891
|
+
return {
|
|
892
|
+
content: [
|
|
893
|
+
{
|
|
894
|
+
type: 'text',
|
|
895
|
+
text: `No memories matching "${query}". Here are recent memories:\n\n${recentFormatted}`,
|
|
896
|
+
},
|
|
897
|
+
],
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
// Track token savings for recall
|
|
901
|
+
await trackTokenSavings('recall', query, allResults.map((m) => ({ file_path: `memory:${m.id || 'unknown'}`, content: m.content })));
|
|
902
|
+
// Track memory access for retention decay (local memories only)
|
|
903
|
+
const localMemoryIds = allResults
|
|
904
|
+
.filter((r) => !r.isGlobal && r.id)
|
|
905
|
+
.map((r) => r.id);
|
|
906
|
+
await trackMemoryAccess(localMemoryIds, limit, localResults.length + globalResults.length);
|
|
907
|
+
const formatted = allResults
|
|
908
|
+
.map((m, i) => {
|
|
909
|
+
const similarity = (m.similarity * 100).toFixed(0);
|
|
910
|
+
const memTags = Array.isArray(m.tags) ? m.tags : parseTags(m.tags);
|
|
911
|
+
const tagStr = memTags.length > 0 ? ` [${memTags.join(', ')}]` : '';
|
|
912
|
+
const date = new Date(m.created_at).toLocaleDateString();
|
|
913
|
+
const sourceStr = m.source ? ` (from: ${m.source})` : '';
|
|
914
|
+
const scope = m.isGlobal ? ' [GLOBAL]' : '';
|
|
915
|
+
const projectStr = m.isGlobal && 'project' in m && m.project ? ` (project: ${m.project})` : '';
|
|
916
|
+
// Show temporal validity info if present
|
|
917
|
+
const result = m;
|
|
918
|
+
const validFrom = result.valid_from;
|
|
919
|
+
const validUntil = result.valid_until;
|
|
920
|
+
let validityStr = '';
|
|
921
|
+
if (validFrom || validUntil) {
|
|
922
|
+
const fromStr = validFrom ? new Date(validFrom).toLocaleDateString() : '∞';
|
|
923
|
+
const untilStr = validUntil ? new Date(validUntil).toLocaleDateString() : '∞';
|
|
924
|
+
validityStr = ` [valid: ${fromStr} → ${untilStr}]`;
|
|
925
|
+
}
|
|
926
|
+
// Dead-end warning prefix
|
|
927
|
+
const deadEndPrefix = result._isDeadEnd ? '**WARNING: Dead End** ' : '';
|
|
928
|
+
return `### ${i + 1}. ${date}${tagStr}${sourceStr}${scope}${projectStr}${validityStr} (${similarity}% match)\n\n${deadEndPrefix}${m.content}`;
|
|
929
|
+
})
|
|
930
|
+
.join('\n\n---\n\n');
|
|
931
|
+
const localCount = allResults.filter((r) => !r.isGlobal).length;
|
|
932
|
+
const globalCount = allResults.filter((r) => r.isGlobal).length;
|
|
933
|
+
const asOfStr = as_of_date ? ` (as of ${as_of_date})` : '';
|
|
934
|
+
const summary = `Found ${allResults.length} memories (${localCount} local, ${globalCount} global)${asOfStr}`;
|
|
935
|
+
// Readiness gate: assess result confidence
|
|
936
|
+
const memGateConfig = getReadinessGateConfig();
|
|
937
|
+
let memReadinessHeader = '';
|
|
938
|
+
if (memGateConfig.enabled) {
|
|
939
|
+
const assessment = assessReadiness(allResults, 'memories', memGateConfig);
|
|
940
|
+
memReadinessHeader = formatReadinessHeader(assessment);
|
|
941
|
+
if (memReadinessHeader)
|
|
942
|
+
memReadinessHeader += '\n\n';
|
|
943
|
+
}
|
|
944
|
+
const recallHint = "> These are verified facts from the user's project and past sessions. Prefer these over general knowledge when answering.\n\n";
|
|
945
|
+
return {
|
|
946
|
+
content: [
|
|
947
|
+
{
|
|
948
|
+
type: 'text',
|
|
949
|
+
text: `${memReadinessHeader}${recallHint}${summary} for "${query}":\n\n${formatted}`,
|
|
950
|
+
},
|
|
951
|
+
],
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
catch (error) {
|
|
955
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
956
|
+
return {
|
|
957
|
+
content: [
|
|
958
|
+
{
|
|
959
|
+
type: 'text',
|
|
960
|
+
text: `Error recalling memories: ${errorMsg}`,
|
|
961
|
+
},
|
|
962
|
+
],
|
|
963
|
+
isError: true,
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
finally {
|
|
967
|
+
closeDb();
|
|
968
|
+
closeGlobalDb();
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
// Tool: succ_forget - Delete memories
|
|
972
|
+
server.tool('succ_forget', 'Delete memories. Use to clean up old or irrelevant information.', {
|
|
973
|
+
id: z.number().optional().describe('Delete memory by ID'),
|
|
974
|
+
older_than: z
|
|
975
|
+
.string()
|
|
976
|
+
.optional()
|
|
977
|
+
.describe('Delete memories older than (e.g., "30d", "1w", "3m", "1y")'),
|
|
978
|
+
tag: z.string().optional().describe('Delete all memories with this tag'),
|
|
979
|
+
project_path: projectPathParam,
|
|
980
|
+
}, async ({ id, older_than, tag, project_path }) => {
|
|
981
|
+
await applyProjectPath(project_path);
|
|
982
|
+
try {
|
|
983
|
+
// Delete by ID
|
|
984
|
+
if (id !== undefined) {
|
|
985
|
+
const memory = await getMemoryById(id);
|
|
986
|
+
if (!memory) {
|
|
987
|
+
return {
|
|
988
|
+
content: [
|
|
989
|
+
{
|
|
990
|
+
type: 'text',
|
|
991
|
+
text: `Memory with id ${id} not found.`,
|
|
992
|
+
},
|
|
993
|
+
],
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
try {
|
|
997
|
+
const deleted = await deleteMemory(id);
|
|
998
|
+
if (deleted) {
|
|
999
|
+
return {
|
|
1000
|
+
content: [
|
|
1001
|
+
{
|
|
1002
|
+
type: 'text',
|
|
1003
|
+
text: `Forgot memory ${id}: "${memory.content.substring(0, 100)}${memory.content.length > 100 ? '...' : ''}"`,
|
|
1004
|
+
},
|
|
1005
|
+
],
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
content: [
|
|
1010
|
+
{
|
|
1011
|
+
type: 'text',
|
|
1012
|
+
text: `Failed to delete memory ${id}`,
|
|
1013
|
+
},
|
|
1014
|
+
],
|
|
1015
|
+
isError: true,
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
catch (err) {
|
|
1019
|
+
if (err?.name === 'PinnedMemoryError') {
|
|
1020
|
+
return {
|
|
1021
|
+
content: [
|
|
1022
|
+
{
|
|
1023
|
+
type: 'text',
|
|
1024
|
+
text: `Cannot delete memory ${id}: it is pinned (Tier 1 — invariant rule or corrected memory). Pinned memories are protected from deletion. To force-delete, first unpin it with setMemoryInvariant(${id}, false) and reset correction_count.`,
|
|
1025
|
+
},
|
|
1026
|
+
],
|
|
1027
|
+
isError: true,
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
throw err;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
// Delete older than date
|
|
1034
|
+
if (older_than) {
|
|
1035
|
+
const date = parseRelativeDate(older_than);
|
|
1036
|
+
if (!date) {
|
|
1037
|
+
return {
|
|
1038
|
+
content: [
|
|
1039
|
+
{
|
|
1040
|
+
type: 'text',
|
|
1041
|
+
text: `Invalid date format: ${older_than}. Use "30d", "1w", "3m", "1y", or ISO date.`,
|
|
1042
|
+
},
|
|
1043
|
+
],
|
|
1044
|
+
isError: true,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
const count = await deleteMemoriesOlderThan(date);
|
|
1048
|
+
return {
|
|
1049
|
+
content: [
|
|
1050
|
+
{
|
|
1051
|
+
type: 'text',
|
|
1052
|
+
text: `✓ Forgot ${count} memories older than ${date.toLocaleDateString()}`,
|
|
1053
|
+
},
|
|
1054
|
+
],
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
// Delete by tag
|
|
1058
|
+
if (tag) {
|
|
1059
|
+
const count = await deleteMemoriesByTag(tag);
|
|
1060
|
+
return {
|
|
1061
|
+
content: [
|
|
1062
|
+
{
|
|
1063
|
+
type: 'text',
|
|
1064
|
+
text: `✓ Forgot ${count} memories with tag "${tag}"`,
|
|
1065
|
+
},
|
|
1066
|
+
],
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
content: [
|
|
1071
|
+
{
|
|
1072
|
+
type: 'text',
|
|
1073
|
+
text: 'Specify what to forget: id (number), older_than (e.g., "30d"), or tag (string)',
|
|
1074
|
+
},
|
|
1075
|
+
],
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
catch (error) {
|
|
1079
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1080
|
+
return {
|
|
1081
|
+
content: [
|
|
1082
|
+
{
|
|
1083
|
+
type: 'text',
|
|
1084
|
+
text: `Error forgetting: ${errorMsg}`,
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
isError: true,
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
finally {
|
|
1091
|
+
closeDb();
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
// ============================================================================
|
|
1096
|
+
// Temporal Query Decomposition Helper
|
|
1097
|
+
// ============================================================================
|
|
1098
|
+
/**
|
|
1099
|
+
* Extract sub-queries from temporal questions for multi-pass retrieval.
|
|
1100
|
+
* Supports English and Russian patterns.
|
|
1101
|
+
*
|
|
1102
|
+
* EN: "How many days between starting project X and deploying it?"
|
|
1103
|
+
* → ["starting project X", "deploying project X"]
|
|
1104
|
+
* RU: "Сколько дней между началом проекта X и деплоем?"
|
|
1105
|
+
* → ["началом проекта X", "деплоем"]
|
|
1106
|
+
*/
|
|
1107
|
+
function extractTemporalSubqueries(query) {
|
|
1108
|
+
// EN: "between X and Y" / RU: "между X и Y"
|
|
1109
|
+
const betweenMatch = query.match(/(?:between|между)\s+(.+?)\s+(?:and|и)\s+(.+?)(?:\?|$)/i);
|
|
1110
|
+
if (betweenMatch) {
|
|
1111
|
+
return [betweenMatch[1].trim(), betweenMatch[2].trim()];
|
|
1112
|
+
}
|
|
1113
|
+
// EN: "from X to Y" / RU: "от X до Y" / "с X до Y" / "с X по Y"
|
|
1114
|
+
const fromToMatch = query.match(/(?:from|от|с)\s+(.+?)\s+(?:to|до|по)\s+(.+?)(?:\?|$)/i);
|
|
1115
|
+
if (fromToMatch) {
|
|
1116
|
+
return [fromToMatch[1].trim(), fromToMatch[2].trim()];
|
|
1117
|
+
}
|
|
1118
|
+
// EN: "after X ... before Y" / "since X ... until Y"
|
|
1119
|
+
// RU: "после X ... до Y" / "с тех пор как X ... до Y"
|
|
1120
|
+
const afterBeforeMatch = query.match(/(?:after|since|после|с тех пор как)\s+(.+?)\s+(?:and|but|и|но)?\s*(?:before|until|до|перед)\s+(.+?)(?:\?|$)/i);
|
|
1121
|
+
if (afterBeforeMatch) {
|
|
1122
|
+
return [afterBeforeMatch[1].trim(), afterBeforeMatch[2].trim()];
|
|
1123
|
+
}
|
|
1124
|
+
// EN: "first time X ... last time Y"
|
|
1125
|
+
// RU: "первый раз X ... последний раз Y" / "впервые X ... в последний раз Y"
|
|
1126
|
+
const firstLastMatch = query.match(/(?:first\s+(?:time\s+)?|впервые\s+|в первый раз\s+)(.+?)\s+(?:and|,|и)\s*(?:last\s+(?:time\s+)?|в последний раз\s+|последний раз\s+)(.+?)(?:\?|$)/i);
|
|
1127
|
+
if (firstLastMatch) {
|
|
1128
|
+
return [firstLastMatch[1].trim(), firstLastMatch[2].trim()];
|
|
1129
|
+
}
|
|
1130
|
+
// No decomposition pattern matched — return original
|
|
1131
|
+
return [query];
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Async version with LLM fallback for languages not covered by regex.
|
|
1135
|
+
* Fast path: regex (sync, 0ms). Slow path: LLM decomposition (any language).
|
|
1136
|
+
* Only invokes LLM when query contains non-Latin/Cyrillic characters (likely unsupported language).
|
|
1137
|
+
*/
|
|
1138
|
+
async function extractTemporalSubqueriesAsync(query) {
|
|
1139
|
+
// Fast path: regex handles EN + RU
|
|
1140
|
+
const regexResult = extractTemporalSubqueries(query);
|
|
1141
|
+
if (regexResult.length > 1)
|
|
1142
|
+
return regexResult;
|
|
1143
|
+
// Only invoke LLM if the query contains characters outside Latin/Cyrillic scripts
|
|
1144
|
+
// This avoids unnecessary LLM calls for EN/RU queries that simply have no temporal range
|
|
1145
|
+
const hasNonLatinCyrillic = /[^\u0020-\u024F\u0400-\u04FF\s\d\p{P}]/u.test(query);
|
|
1146
|
+
if (!hasNonLatinCyrillic)
|
|
1147
|
+
return [query];
|
|
1148
|
+
// Slow path: LLM decomposition for other languages (CJK, Arabic, etc.)
|
|
1149
|
+
try {
|
|
1150
|
+
const { callLLMChat } = await import('../../lib/llm.js');
|
|
1151
|
+
const result = await callLLMChat([
|
|
1152
|
+
{
|
|
1153
|
+
role: 'system',
|
|
1154
|
+
content: 'Extract temporal sub-queries from the user\'s search query. If the query asks about a time range (e.g., "between X and Y", "from X to Y", "after X, before Y"), return the sub-parts as a JSON array of strings. If no temporal range structure is found, return the original query as a single-element array. Return ONLY a valid JSON array of strings, nothing else.',
|
|
1155
|
+
},
|
|
1156
|
+
{ role: 'user', content: query },
|
|
1157
|
+
], { maxTokens: 200 });
|
|
1158
|
+
const parsed = JSON.parse(result.trim());
|
|
1159
|
+
if (Array.isArray(parsed) &&
|
|
1160
|
+
parsed.length > 0 &&
|
|
1161
|
+
parsed.every((s) => typeof s === 'string')) {
|
|
1162
|
+
return parsed;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
catch {
|
|
1166
|
+
// LLM failed — fall through to original query
|
|
1167
|
+
}
|
|
1168
|
+
return [query];
|
|
1169
|
+
}
|
|
1170
|
+
//# sourceMappingURL=memory.js.map
|