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.
Files changed (499) hide show
  1. package/.env.example +32 -16
  2. package/CHANGELOG.md +147 -0
  3. package/README.md +120 -78
  4. package/{scripts → bin}/dependency-manager.mjs +217 -217
  5. package/{scripts → bin}/detect-clients.mjs +78 -78
  6. package/bin/install-interactive.mjs +321 -0
  7. package/bin/squish-mcp.mjs +46 -0
  8. package/bin/squish.mjs +33 -0
  9. package/config/mcp-migration-map.json +1 -6
  10. package/config/mcp-mode-semantics.json +19 -23
  11. package/config/mcp-remote-auth.json +3 -26
  12. package/config/mcp-universal.schema.json +5 -35
  13. package/config/settings.json +107 -52
  14. package/config.js +5 -0
  15. package/config.ts +218 -0
  16. package/core/adapters/config/claude-code.ts +133 -0
  17. package/core/adapters/config/cursor.ts +90 -0
  18. package/core/adapters/config/opencode.ts +89 -0
  19. package/core/adapters/config/windsurf.ts +90 -0
  20. package/core/adapters/index.ts +102 -0
  21. package/core/adapters/timeline.ts +116 -0
  22. package/core/adapters/types.ts +166 -0
  23. package/core/agent-preferences.ts +140 -0
  24. package/core/algorithms/analytics/token-estimator.ts +216 -0
  25. package/core/algorithms/detection/hash-filters.ts +260 -0
  26. package/core/algorithms/detection/semantic-ranker.ts +194 -0
  27. package/core/algorithms/detection/two-stage-detector.ts +421 -0
  28. package/core/algorithms/handlers/approve-merge.ts +215 -0
  29. package/core/algorithms/handlers/detect-duplicates.ts +192 -0
  30. package/core/algorithms/handlers/get-stats.ts +132 -0
  31. package/core/algorithms/handlers/list-proposals.ts +130 -0
  32. package/core/algorithms/handlers/preview-merge.ts +139 -0
  33. package/core/algorithms/handlers/reject-merge.ts +93 -0
  34. package/core/algorithms/handlers/reverse-merge.ts +155 -0
  35. package/core/algorithms/index.ts +39 -0
  36. package/core/algorithms/operations/cache-maintenance.ts +182 -0
  37. package/core/algorithms/safety/safety-checks.ts +256 -0
  38. package/core/algorithms/strategies/merge-strategies.ts +381 -0
  39. package/core/algorithms/types.ts +140 -0
  40. package/core/algorithms/utils/response-builder.ts +61 -0
  41. package/core/associations.ts +363 -0
  42. package/core/beliefs/decay.ts +289 -0
  43. package/core/beliefs/extractor.ts +131 -0
  44. package/core/beliefs/store.ts +557 -0
  45. package/core/beliefs/types.ts +38 -0
  46. package/core/commands/mcp-server.ts +5 -0
  47. package/core/compression.ts +177 -0
  48. package/core/config.js +2 -0
  49. package/core/consolidation.ts +330 -0
  50. package/core/context/agent-context.ts +388 -0
  51. package/core/context/context-paging.ts +449 -0
  52. package/core/context/context-window.ts +234 -0
  53. package/core/context/context.ts +35 -0
  54. package/core/embeddings/embeddings.ts +616 -0
  55. package/core/embeddings/google-multimodal.ts +200 -0
  56. package/{dist/core/local-embeddings.js → core/embeddings/local-embeddings.ts} +12 -11
  57. package/core/embeddings/qmd-client.ts +495 -0
  58. package/core/embeddings/transformers-local.ts +261 -0
  59. package/core/embeddings.js +4 -0
  60. package/core/error-handling.ts +206 -0
  61. package/core/external +219 -0
  62. package/core/graph/entity-deduplicator.ts +232 -0
  63. package/core/graph/graph-builder.ts +257 -0
  64. package/core/graph/graph-traversal.ts +490 -0
  65. package/core/graph/index.ts +24 -0
  66. package/core/graph/llm-entity-extractor.ts +402 -0
  67. package/core/graph/multi-hop-retrieval.ts +317 -0
  68. package/core/graph/relationship-extractor.ts +465 -0
  69. package/core/hooks/agent-hooks.ts +653 -0
  70. package/core/hooks/auto-tagger.ts +149 -0
  71. package/core/hooks/capture-filter.ts +169 -0
  72. package/core/hot-cache.ts +388 -0
  73. package/core/index.ts +10 -0
  74. package/core/ingestion/agent-memory.ts +167 -0
  75. package/core/ingestion/core-memory.ts +326 -0
  76. package/core/ingestion/learnings.ts +260 -0
  77. package/core/ingestion/signal-engine.ts +266 -0
  78. package/core/integrations/obsidian-vault.ts +197 -0
  79. package/core/layers/generator.ts +115 -0
  80. package/core/lib/db-client.ts +168 -0
  81. package/core/lib/parse-embedding.ts +59 -0
  82. package/core/lib/schemas.ts +102 -0
  83. package/core/lib/types.ts +49 -0
  84. package/core/lib/utils.ts +151 -0
  85. package/core/lib/validation.ts +180 -0
  86. package/core/lifecycle.ts +353 -0
  87. package/core/logger.ts +59 -0
  88. package/core/memory/bridge-discovery.ts +395 -0
  89. package/core/memory/categorizer.ts +390 -0
  90. package/core/memory/conflict-detector.ts +62 -0
  91. package/core/memory/consolidation.ts +372 -0
  92. package/core/memory/context-collector.ts +75 -0
  93. package/core/memory/contradiction-resolver.ts +494 -0
  94. package/core/memory/edit-workflow.ts +174 -0
  95. package/core/memory/entity-extractor.ts +426 -0
  96. package/core/memory/entity-resolver.ts +89 -0
  97. package/core/memory/explain.ts +112 -0
  98. package/core/memory/fact-deriver.ts +300 -0
  99. package/core/memory/fact-extractor.ts +120 -0
  100. package/core/memory/feedback-tracker.ts +200 -0
  101. package/core/memory/hooks.ts +230 -0
  102. package/core/memory/hybrid-retrieval.ts +65 -0
  103. package/core/memory/hybrid-scorer.ts +325 -0
  104. package/core/memory/hybrid-search.ts +748 -0
  105. package/core/memory/importance.ts +319 -0
  106. package/core/memory/index.ts +11 -0
  107. package/core/memory/loader.ts +178 -0
  108. package/core/memory/markdown/markdown-storage.ts +318 -0
  109. package/core/memory/memories.ts +565 -0
  110. package/core/memory/memory-lifecycle.ts +51 -0
  111. package/core/memory/memory-manager.ts +53 -0
  112. package/core/memory/migrate.ts +173 -0
  113. package/core/memory/normalization.ts +30 -0
  114. package/core/memory/path-strengthener.ts +211 -0
  115. package/core/memory/progressive-disclosure.ts +392 -0
  116. package/core/memory/query-processor.ts +130 -0
  117. package/core/memory/query-rewriter.ts +153 -0
  118. package/core/memory/response-analyzer.ts +81 -0
  119. package/core/memory/retrieval-feedback.ts +276 -0
  120. package/core/memory/serialization.ts +83 -0
  121. package/core/memory/stale-cleaner.ts +147 -0
  122. package/core/memory/stats.ts +181 -0
  123. package/core/memory/telemetry.ts +392 -0
  124. package/core/memory/temporal-facts.ts +356 -0
  125. package/core/memory/temporal-parser.ts +477 -0
  126. package/core/memory/trigger-detector.ts +104 -0
  127. package/core/memory/write-gate.ts +288 -0
  128. package/core/places/index.ts +14 -0
  129. package/core/places/memory-places.ts +339 -0
  130. package/core/places/places.ts +406 -0
  131. package/core/places/rules.ts +308 -0
  132. package/core/places/walking.ts +192 -0
  133. package/core/projects +89 -0
  134. package/core/projects.ts +131 -0
  135. package/core/redis.ts +82 -0
  136. package/core/responses.ts +187 -0
  137. package/core/runtime/trust-report.ts +195 -0
  138. package/core/runtime/trust-state.ts +360 -0
  139. package/core/scheduler/cron-scheduler.ts +581 -0
  140. package/core/scheduler/heartbeat.ts +91 -0
  141. package/core/scheduler/index.ts +8 -0
  142. package/core/scheduler/job-runner.ts +197 -0
  143. package/core/search/conversations.ts +166 -0
  144. package/core/search/entities.ts +46 -0
  145. package/core/search/folder-context.ts +154 -0
  146. package/core/search/graph-boost.ts +22 -0
  147. package/core/search/index.ts +4 -0
  148. package/core/search/qmd-wrapper.ts +84 -0
  149. package/core/security/encrypt.ts +51 -0
  150. package/core/security/governance.ts +102 -0
  151. package/core/security/privacy.ts +108 -0
  152. package/core/security/secret-detector.ts +122 -0
  153. package/core/session/auto-load.ts +160 -0
  154. package/core/session/entity-tracker.ts +363 -0
  155. package/core/session/index.ts +7 -0
  156. package/core/session/reference-resolver.ts +158 -0
  157. package/core/session/self-iteration-job.ts +478 -0
  158. package/core/session/session-hooks.ts +69 -0
  159. package/core/session/types.ts +36 -0
  160. package/core/session/working-set.ts +275 -0
  161. package/core/snapshots/cleanup.ts +13 -0
  162. package/core/snapshots/comparison.ts +59 -0
  163. package/core/snapshots/creation.ts +139 -0
  164. package/core/snapshots/retrieval.ts +44 -0
  165. package/core/snapshots/stats.ts +63 -0
  166. package/core/storage/cache.ts +241 -0
  167. package/core/storage/database.ts +23 -0
  168. package/core/summarization/cleanup.ts +13 -0
  169. package/core/summarization/queries.ts +32 -0
  170. package/core/summarization/stats.ts +64 -0
  171. package/core/summarization/strategies.ts +52 -0
  172. package/core/summarization.ts +248 -0
  173. package/core/temporal-facts.ts +244 -0
  174. package/core/tracing/collector.ts +470 -0
  175. package/core/tracing/visualizer.ts +195 -0
  176. package/core/utils/cleanup-operations.ts +50 -0
  177. package/core/utils/content-extraction.ts +95 -0
  178. package/core/utils/filter-builder.ts +56 -0
  179. package/core/utils/history-traversal.ts +63 -0
  180. package/core/utils/memory-operations.ts +56 -0
  181. package/core/utils/query-operations.ts +83 -0
  182. package/core/utils/summarization-helpers.ts +45 -0
  183. package/core/utils/temporal-queries.ts +39 -0
  184. package/core/utils/vector-operations.ts +135 -0
  185. package/core/utils/version-management.ts +74 -0
  186. package/core/worker.ts +324 -0
  187. package/db/adapter.ts +215 -0
  188. package/db/bootstrap.ts +1055 -0
  189. package/db/drizzle/migrations/0000_needy_cerebro.sql +402 -0
  190. package/db/drizzle/migrations/meta/0000_snapshot.json +3451 -0
  191. package/db/drizzle/migrations/meta/_journal.json +13 -0
  192. package/db/drizzle/schema-sqlite.ts +1032 -0
  193. package/db/drizzle/schema.ts +1128 -0
  194. package/db/drizzle.config.ts +12 -0
  195. package/db/index.ts +83 -0
  196. package/db/init.sql +5 -0
  197. package/db/migrations/associations.ts +35 -0
  198. package/db/migrations/beliefs.ts +89 -0
  199. package/db/migrations/core-memory.ts +35 -0
  200. package/db/migrations/fts.ts +59 -0
  201. package/db/migrations/index.ts +54 -0
  202. package/db/migrations/indexes.ts +36 -0
  203. package/db/migrations/learnings.ts +34 -0
  204. package/db/migrations/maintenance.ts +68 -0
  205. package/db/migrations/memories.ts +22 -0
  206. package/db/migrations/memory-places.ts +35 -0
  207. package/db/migrations/places.ts +49 -0
  208. package/db/migrations/projects.ts +21 -0
  209. package/db/migrations/tier-conversion.ts +24 -0
  210. package/db/neon.ts +22 -0
  211. package/db/schema/beliefs.ts +50 -0
  212. package/db/schema/generator.ts +159 -0
  213. package/db/schema/index.ts +58 -0
  214. package/db/schema/learnings.ts +32 -0
  215. package/db/schema/memories.ts +83 -0
  216. package/db/schema/projects.ts +33 -0
  217. package/db/schema.ts +13 -0
  218. package/db/supabase.ts +27 -0
  219. package/dist/config.d.ts +40 -17
  220. package/dist/config.js +150 -198
  221. package/dist/core/adapters/types.d.ts +13 -33
  222. package/dist/core/adapters/types.js +1 -1
  223. package/dist/core/agent-preferences.d.ts +16 -0
  224. package/dist/core/agent-preferences.js +124 -0
  225. package/dist/core/algorithms/safety/safety-checks.d.ts +1 -5
  226. package/dist/core/algorithms/types.d.ts +0 -8
  227. package/dist/core/associations.d.ts +3 -1
  228. package/dist/core/associations.js +37 -1
  229. package/dist/core/beliefs/decay.d.ts +27 -0
  230. package/dist/core/beliefs/decay.js +217 -0
  231. package/dist/core/beliefs/extractor.d.ts +9 -0
  232. package/dist/core/beliefs/extractor.js +113 -0
  233. package/dist/core/beliefs/store.d.ts +46 -0
  234. package/dist/core/beliefs/store.js +466 -0
  235. package/dist/core/beliefs/types.d.ts +28 -0
  236. package/dist/core/beliefs/types.js +2 -0
  237. package/dist/core/commands/mcp-server.d.ts +0 -1
  238. package/dist/core/commands/mcp-server.js +4 -737
  239. package/dist/core/commands/remember.d.ts +24 -0
  240. package/dist/core/commands/remember.js +144 -0
  241. package/dist/core/{toon.d.ts → compression.d.ts} +6 -4
  242. package/dist/core/{toon.js → compression.js} +8 -8
  243. package/dist/core/context/agent-context.js +1 -1
  244. package/dist/core/embeddings/embeddings.d.ts +29 -0
  245. package/dist/core/embeddings/embeddings.js +546 -0
  246. package/dist/core/embeddings/google-multimodal.js +6 -2
  247. package/dist/core/{local-embeddings.d.ts → embeddings/local-embeddings.d.ts} +1 -1
  248. package/dist/core/embeddings/local-embeddings.js +11 -0
  249. package/dist/core/embeddings/qmd-client.js +1 -1
  250. package/dist/core/embeddings/transformers-local.d.ts +64 -0
  251. package/dist/core/embeddings/transformers-local.js +213 -0
  252. package/dist/core/embeddings.d.ts +1 -28
  253. package/dist/core/embeddings.js +2 -453
  254. package/dist/core/graph/entity-deduplicator.d.ts +24 -0
  255. package/dist/core/graph/entity-deduplicator.js +183 -0
  256. package/dist/core/graph/graph-builder.d.ts +46 -0
  257. package/dist/core/graph/graph-builder.js +174 -0
  258. package/dist/core/graph/graph-traversal.d.ts +80 -0
  259. package/dist/core/graph/graph-traversal.js +315 -0
  260. package/dist/core/graph/index.d.ts +19 -0
  261. package/dist/core/graph/index.js +13 -0
  262. package/dist/core/graph/llm-entity-extractor.d.ts +49 -0
  263. package/dist/core/graph/llm-entity-extractor.js +313 -0
  264. package/dist/core/graph/multi-hop-retrieval.d.ts +48 -0
  265. package/dist/core/graph/multi-hop-retrieval.js +215 -0
  266. package/dist/core/graph/relationship-extractor.d.ts +48 -0
  267. package/dist/core/graph/relationship-extractor.js +351 -0
  268. package/dist/core/hooks/agent-hooks.d.ts +10 -1
  269. package/dist/core/hooks/agent-hooks.js +301 -24
  270. package/dist/core/hot-cache.d.ts +86 -0
  271. package/dist/core/hot-cache.js +285 -0
  272. package/dist/core/index.d.ts +9 -9
  273. package/dist/core/index.js +9 -12
  274. package/dist/core/ingestion/core-memory.d.ts +2 -2
  275. package/dist/core/ingestion/core-memory.js +3 -3
  276. package/dist/core/ingestion/learnings.js +3 -0
  277. package/dist/core/ingestion/signal-engine.d.ts +41 -0
  278. package/dist/core/ingestion/signal-engine.js +201 -0
  279. package/dist/core/{obsidian-vault.d.ts → integrations/obsidian-vault.d.ts} +2 -1
  280. package/dist/core/{obsidian-vault.js → integrations/obsidian-vault.js} +69 -7
  281. package/dist/core/lib/parse-embedding.d.ts +9 -0
  282. package/dist/core/lib/parse-embedding.js +58 -0
  283. package/dist/core/lib/schemas.d.ts +57 -54
  284. package/dist/core/lib/types.d.ts +45 -0
  285. package/dist/core/lib/types.js +6 -0
  286. package/dist/core/lib/utils.d.ts +4 -0
  287. package/dist/core/lib/utils.js +55 -0
  288. package/dist/core/lifecycle.d.ts +0 -1
  289. package/dist/core/lifecycle.js +13 -23
  290. package/dist/core/logger.d.ts +1 -0
  291. package/dist/core/logger.js +14 -8
  292. package/dist/core/mcp/tools.d.ts +0 -2
  293. package/dist/core/mcp/tools.js +0 -87
  294. package/dist/core/mcp/types.d.ts +25 -253
  295. package/dist/core/mcp/types.js +2 -2
  296. package/dist/core/memory/categorizer.js +1 -0
  297. package/dist/core/memory/consolidation.js +2 -28
  298. package/dist/core/memory/entity-extractor.d.ts +4 -0
  299. package/dist/core/memory/entity-extractor.js +30 -16
  300. package/dist/core/memory/explain.d.ts +18 -0
  301. package/dist/core/memory/explain.js +92 -0
  302. package/dist/core/memory/fact-deriver.d.ts +31 -0
  303. package/dist/core/memory/fact-deriver.js +236 -0
  304. package/dist/core/memory/hybrid-retrieval.d.ts +14 -16
  305. package/dist/core/memory/hybrid-retrieval.js +25 -127
  306. package/dist/core/memory/hybrid-scorer.js +6 -23
  307. package/dist/core/memory/hybrid-search.d.ts +10 -7
  308. package/dist/core/memory/hybrid-search.js +458 -221
  309. package/dist/core/memory/importance.d.ts +0 -17
  310. package/dist/core/memory/importance.js +1 -58
  311. package/dist/core/memory/index.d.ts +1 -0
  312. package/dist/core/memory/index.js +1 -0
  313. package/dist/core/memory/memories.d.ts +13 -17
  314. package/dist/core/memory/memories.js +78 -75
  315. package/dist/core/memory/memory-lifecycle.d.ts +2 -2
  316. package/dist/core/memory/memory-lifecycle.js +10 -18
  317. package/dist/core/memory/normalization.d.ts +1 -16
  318. package/dist/core/memory/path-strengthener.d.ts +39 -0
  319. package/dist/core/memory/path-strengthener.js +150 -0
  320. package/dist/core/memory/query-processor.js +37 -3
  321. package/dist/core/memory/retrieval-feedback.d.ts +70 -0
  322. package/dist/core/memory/retrieval-feedback.js +213 -0
  323. package/dist/core/memory/stale-cleaner.d.ts +26 -0
  324. package/dist/core/memory/stale-cleaner.js +97 -0
  325. package/dist/core/memory/stats.d.ts +10 -0
  326. package/dist/core/memory/stats.js +8 -3
  327. package/dist/core/memory/trigger-detector.d.ts +8 -1
  328. package/dist/core/memory/trigger-detector.js +42 -5
  329. package/dist/core/places/index.d.ts +1 -1
  330. package/dist/core/places/index.js +1 -1
  331. package/dist/core/places/places.d.ts +13 -13
  332. package/dist/core/places/places.js +27 -27
  333. package/dist/core/places/rules.js +23 -23
  334. package/dist/core/places/walking.d.ts +3 -3
  335. package/dist/core/places/walking.js +7 -7
  336. package/dist/core/projects.js +8 -0
  337. package/dist/core/runtime/trust-report.d.ts +102 -0
  338. package/dist/core/runtime/trust-report.js +107 -0
  339. package/dist/core/runtime/trust-state.d.ts +12 -0
  340. package/dist/core/runtime/trust-state.js +309 -0
  341. package/dist/core/scheduler/cron-scheduler.d.ts +1 -1
  342. package/dist/core/scheduler/cron-scheduler.js +164 -3
  343. package/dist/core/scheduler/job-runner.js +1 -1
  344. package/dist/core/search/qmd-wrapper.d.ts +36 -0
  345. package/dist/core/search/qmd-wrapper.js +58 -0
  346. package/dist/core/session/auto-load.js +28 -3
  347. package/dist/core/session/entity-tracker.d.ts +62 -0
  348. package/dist/core/session/entity-tracker.js +287 -0
  349. package/dist/core/session/reference-resolver.d.ts +26 -0
  350. package/dist/core/session/reference-resolver.js +121 -0
  351. package/dist/core/session/self-iteration-job.d.ts +15 -0
  352. package/dist/core/session/self-iteration-job.js +163 -58
  353. package/dist/core/session/working-set.d.ts +50 -0
  354. package/dist/core/session/working-set.js +212 -0
  355. package/dist/core/snapshots/creation.d.ts +2 -8
  356. package/dist/core/snapshots/creation.js +3 -12
  357. package/dist/core/utils/summarization-helpers.d.ts +0 -4
  358. package/dist/core/utils/summarization-helpers.js +1 -6
  359. package/dist/db/bootstrap.d.ts +2 -0
  360. package/dist/db/bootstrap.js +229 -280
  361. package/dist/db/drizzle/schema-sqlite.d.ts +702 -1
  362. package/dist/db/drizzle/schema-sqlite.js +83 -4
  363. package/dist/db/drizzle/schema.d.ts +653 -1
  364. package/dist/db/drizzle/schema.js +93 -4
  365. package/dist/db/migrations/associations.d.ts +6 -0
  366. package/dist/db/migrations/associations.js +29 -0
  367. package/dist/db/migrations/beliefs.d.ts +10 -0
  368. package/dist/db/migrations/beliefs.js +76 -0
  369. package/dist/db/migrations/core-memory.d.ts +6 -0
  370. package/dist/db/migrations/core-memory.js +29 -0
  371. package/dist/db/migrations/fts.d.ts +6 -0
  372. package/dist/db/migrations/fts.js +52 -0
  373. package/dist/db/migrations/index.d.ts +25 -0
  374. package/dist/db/migrations/index.js +51 -0
  375. package/dist/db/migrations/indexes.d.ts +6 -0
  376. package/dist/db/migrations/indexes.js +30 -0
  377. package/dist/db/migrations/learnings.d.ts +7 -0
  378. package/dist/db/migrations/learnings.js +26 -0
  379. package/dist/db/migrations/maintenance.d.ts +6 -0
  380. package/dist/db/migrations/maintenance.js +61 -0
  381. package/dist/db/migrations/memories.d.ts +7 -0
  382. package/dist/db/migrations/memories.js +16 -0
  383. package/dist/db/migrations/memory-places.d.ts +6 -0
  384. package/dist/db/migrations/memory-places.js +29 -0
  385. package/dist/db/migrations/places.d.ts +6 -0
  386. package/dist/db/migrations/places.js +43 -0
  387. package/dist/db/migrations/projects.d.ts +3 -0
  388. package/dist/db/migrations/projects.js +13 -0
  389. package/dist/db/migrations/tier-conversion.d.ts +7 -0
  390. package/dist/db/migrations/tier-conversion.js +20 -0
  391. package/dist/db/schema/beliefs.d.ts +9 -0
  392. package/dist/db/schema/beliefs.js +46 -0
  393. package/dist/db/schema/generator.d.ts +38 -0
  394. package/dist/db/schema/generator.js +108 -0
  395. package/dist/db/schema/index.d.ts +19 -20
  396. package/dist/db/schema/index.js +25 -79
  397. package/dist/db/schema/learnings.d.ts +7 -0
  398. package/dist/db/schema/learnings.js +30 -0
  399. package/dist/db/schema/memories.d.ts +7 -0
  400. package/dist/db/schema/memories.js +81 -0
  401. package/dist/db/schema/projects.d.ts +4 -0
  402. package/dist/db/schema/projects.js +31 -0
  403. package/dist/packages/mcp/src/index.d.ts +3 -0
  404. package/dist/packages/mcp/src/index.js +733 -0
  405. package/mcp.json.example +8 -11
  406. package/package.json +57 -76
  407. package/packages/cli/package.json +22 -0
  408. package/packages/cli/src/commands/clean.ts +68 -0
  409. package/packages/cli/src/commands/context.ts +79 -0
  410. package/packages/cli/src/commands/doctor.ts +357 -0
  411. package/packages/cli/src/commands/forget.ts +72 -0
  412. package/packages/cli/src/commands/health.ts +36 -0
  413. package/packages/cli/src/commands/inspect.ts +41 -0
  414. package/packages/cli/src/commands/link.ts +50 -0
  415. package/packages/cli/src/commands/migrate.ts +93 -0
  416. package/packages/cli/src/commands/recall.ts +99 -0
  417. package/packages/cli/src/commands/recent.ts +57 -0
  418. package/packages/cli/src/commands/remember.ts +139 -0
  419. package/packages/cli/src/commands/run.ts +58 -0
  420. package/packages/cli/src/commands/stale.ts +43 -0
  421. package/packages/cli/src/commands/stats.ts +42 -0
  422. package/packages/cli/src/index.ts +57 -0
  423. package/packages/cli/tsconfig.json +24 -0
  424. package/packages/mcp/package.json +26 -0
  425. package/packages/mcp/src/index.ts +877 -0
  426. package/packages/mcp/tsconfig.json +20 -0
  427. package/skills/squish-memory/SKILL.md +38 -35
  428. package/skills/squish-memory/{scripts/install.sh → install.sh} +1 -1
  429. package/skills/squish-memory/references/claude-desktop.json +12 -0
  430. package/skills/squish-memory/references/openclaw.json +13 -0
  431. package/skills/squish-memory/references/opencode.json +14 -0
  432. package/config/hooks/claude-code-hooks.json +0 -39
  433. package/config/hooks/cursor-hooks.json +0 -30
  434. package/config/hooks/opencode-hooks.json +0 -30
  435. package/config/hooks/windsurf-hooks.json +0 -30
  436. package/config/mcp-cli-fallback-policy.json +0 -22
  437. package/config/mcp.json +0 -38
  438. package/config/plugin-manifest.json +0 -101
  439. package/config/plugin-manifest.schema.json +0 -244
  440. package/config/plugin.json +0 -32
  441. package/config/remote-memory-policy.json +0 -32
  442. package/core/commands/context-paging.md +0 -51
  443. package/core/commands/context-status.md +0 -22
  444. package/core/commands/context.md +0 -5
  445. package/core/commands/core-memory.md +0 -56
  446. package/core/commands/health.md +0 -5
  447. package/core/commands/init.md +0 -39
  448. package/core/commands/merge.md +0 -113
  449. package/core/commands/recall.md +0 -5
  450. package/core/commands/remember.md +0 -11
  451. package/core/commands/search.md +0 -10
  452. package/dist/core/commands/managed-sync.d.ts +0 -10
  453. package/dist/core/commands/managed-sync.js +0 -64
  454. package/dist/core/external-folder/index.d.ts +0 -102
  455. package/dist/core/external-folder/index.js +0 -294
  456. package/dist/core/namespaces/index.d.ts +0 -71
  457. package/dist/core/namespaces/index.js +0 -305
  458. package/dist/core/namespaces/uri-parser.d.ts +0 -31
  459. package/dist/core/namespaces/uri-parser.js +0 -74
  460. package/dist/core/search/qmd-search.d.ts +0 -61
  461. package/dist/core/search/qmd-search.js +0 -178
  462. package/dist/core/session-hooks/self-iteration-job.d.ts +0 -20
  463. package/dist/core/session-hooks/self-iteration-job.js +0 -282
  464. package/dist/core/session-hooks/session-hooks.d.ts +0 -18
  465. package/dist/core/session-hooks/session-hooks.js +0 -58
  466. package/dist/core/snapshots.d.ts +0 -29
  467. package/dist/core/snapshots.js +0 -220
  468. package/dist/core/sync/qmd-sync.d.ts +0 -94
  469. package/dist/core/sync/qmd-sync.js +0 -201
  470. package/dist/index.d.ts +0 -7
  471. package/dist/index.js +0 -1677
  472. package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
  473. package/dist/webui/server.d.ts +0 -5
  474. package/dist/webui/server.js +0 -642
  475. package/generated/mcp/manifest.json +0 -23
  476. package/generated/mcp/mcp-servers.json +0 -25
  477. package/generated/mcp/mcporter.json +0 -34
  478. package/generated/mcp/openclaw-memory-qmd.json +0 -17
  479. package/generated/mcp/runtime.json +0 -12
  480. package/scripts/README.md +0 -60
  481. package/scripts/build-release.sh +0 -36
  482. package/scripts/check-secrets.js +0 -132
  483. package/scripts/copy-runtime-assets.mjs +0 -26
  484. package/scripts/generate-mcp.mjs +0 -264
  485. package/scripts/github-release.sh +0 -77
  486. package/scripts/init-dirs.mjs +0 -13
  487. package/scripts/install-claude-code.sh +0 -85
  488. package/scripts/install-cursor.sh +0 -56
  489. package/scripts/install-hooks.sh +0 -73
  490. package/scripts/install-interactive.mjs +0 -357
  491. package/scripts/install-opencode.sh +0 -75
  492. package/scripts/install-plugin.mjs +0 -415
  493. package/scripts/install-windsurf.sh +0 -67
  494. package/scripts/remote-preflight.mjs +0 -62
  495. package/scripts/squish-fallback.mjs +0 -132
  496. package/scripts/test-interactive.mjs +0 -131
  497. package/scripts/verify-mcp.mjs +0 -214
  498. package/skills/squish-memory/scripts/install.mjs +0 -335
  499. package/skills/squish-memory/write_skill.js +0 -2
@@ -0,0 +1,313 @@
1
+ /**
2
+ * LLM Entity Extractor
3
+ *
4
+ * Extracts named entities and relationships from memory content using
5
+ * LLM-powered analysis. Falls back to regex extraction when LLM is unavailable.
6
+ */
7
+ import { logger } from '../logger.js';
8
+ import { config } from '../../config.js';
9
+ import { extractEntities as regexExtractEntities, } from '../memory/entity-extractor.js';
10
+ // ─── LLM Prompt ─────────────────────────────────────────────────────────────
11
+ const ENTITY_EXTRACTION_PROMPT = `You are an entity and relationship extractor for an AI memory system. Given text, extract:
12
+
13
+ 1. ENTITIES: Named things mentioned (people, projects, systems, tools, concepts, events)
14
+ 2. RELATIONSHIPS: How entities connect to each other
15
+
16
+ Return ONLY valid JSON in this exact format:
17
+ {
18
+ "entities": [
19
+ {"name": "Alice", "type": "person", "confidence": 0.95},
20
+ {"name": "Project Atlas", "type": "concept", "confidence": 0.9}
21
+ ],
22
+ "relations": [
23
+ {"from": "Alice", "to": "Project Atlas", "type": "works_on", "confidence": 0.85, "context": "Alice is the tech lead on Project Atlas"},
24
+ {"from": "Project Atlas", "to": "PostgreSQL", "type": "uses", "confidence": 0.9, "context": "Project Atlas uses PostgreSQL for its primary datastore"}
25
+ ]
26
+ }
27
+
28
+ Entity types: person, file, function, class, concept, tool, date, location, pattern, technique, other
29
+ Relation types: works_on, depends_on, manages, uses, caused, located_in, belongs_to, reports_to, occurred_on, affects, contains, implements, extends, related_to, part_of, owns, created, resolved, blocks
30
+
31
+ Rules:
32
+ - Extract only explicitly mentioned entities and relationships
33
+ - Use the most specific relation type available
34
+ - Include confidence scores (0-1)
35
+ - Keep entity names as they appear in text (preserve capitalization)
36
+ - For ambiguous relationships, use "related_to"
37
+ - Do NOT invent entities or relationships not present in the text`;
38
+ // ─── LLM Call Abstraction ───────────────────────────────────────────────────
39
+ /**
40
+ * Call an LLM for entity extraction.
41
+ * Uses OpenAI-compatible API (works with OpenAI, Ollama, LM Studio, local endpoints).
42
+ */
43
+ async function callLLM(prompt, content) {
44
+ // Determine which provider to use for extraction
45
+ const provider = config.llmProvider;
46
+ const endpoint = config.llmEndpoint || config.lmStudioUrl || config.ollamaUrl;
47
+ const model = config.llmExtractionModel;
48
+ if (!model) {
49
+ logger.debug('LLM extraction model not configured; using regex fallback');
50
+ return null;
51
+ }
52
+ // Try OpenAI first if configured and provider matches
53
+ if ((provider === 'openai' || !provider) && config.openAiApiKey) {
54
+ try {
55
+ const chatUrl = config.openAiApiUrl.replace('/embeddings', '/chat/completions');
56
+ const response = await fetch(chatUrl, {
57
+ method: 'POST',
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ Authorization: `Bearer ${config.openAiApiKey}`,
61
+ },
62
+ body: JSON.stringify({
63
+ model,
64
+ messages: [
65
+ { role: 'system', content: prompt },
66
+ { role: 'user', content },
67
+ ],
68
+ temperature: 0.1,
69
+ max_tokens: 2000,
70
+ }),
71
+ });
72
+ if (!response.ok) {
73
+ logger.warn(`LLM entity extraction failed (OpenAI): ${response.status}`);
74
+ return null;
75
+ }
76
+ const payload = await response.json();
77
+ return payload.choices?.[0]?.message?.content ?? null;
78
+ }
79
+ catch (error) {
80
+ logger.warn('LLM entity extraction error (OpenAI):', { error: error });
81
+ }
82
+ }
83
+ // Try Ollama if configured and provider matches
84
+ if ((provider === 'ollama' || !provider) && config.ollamaUrl) {
85
+ try {
86
+ const response = await fetch(`${config.ollamaUrl}/api/chat`, {
87
+ method: 'POST',
88
+ headers: { 'Content-Type': 'application/json' },
89
+ body: JSON.stringify({
90
+ model,
91
+ messages: [
92
+ { role: 'system', content: prompt },
93
+ { role: 'user', content },
94
+ ],
95
+ stream: false,
96
+ options: { temperature: 0.1 },
97
+ }),
98
+ });
99
+ if (!response.ok) {
100
+ logger.warn(`Ollama entity extraction failed: ${response.status}`);
101
+ return null;
102
+ }
103
+ const payload = await response.json();
104
+ return payload.message?.content ?? null;
105
+ }
106
+ catch (error) {
107
+ logger.warn('LLM entity extraction error (Ollama):', { error: error });
108
+ }
109
+ }
110
+ // Try LM Studio / custom endpoint if configured and provider matches
111
+ if ((provider === 'lmstudio' || provider === 'local' || !provider) && (config.lmStudioUrl || endpoint)) {
112
+ try {
113
+ const baseUrl = endpoint || config.lmStudioUrl;
114
+ if (!baseUrl)
115
+ return null;
116
+ const response = await fetch(`${baseUrl}/v1/chat/completions`, {
117
+ method: 'POST',
118
+ headers: { 'Content-Type': 'application/json' },
119
+ body: JSON.stringify({
120
+ model,
121
+ messages: [
122
+ { role: 'system', content: prompt },
123
+ { role: 'user', content },
124
+ ],
125
+ temperature: 0.1,
126
+ max_tokens: 2000,
127
+ }),
128
+ });
129
+ if (!response.ok) {
130
+ logger.warn(`LM Studio entity extraction failed: ${response.status}`);
131
+ return null;
132
+ }
133
+ const payload = await response.json();
134
+ return payload.choices?.[0]?.message?.content ?? null;
135
+ }
136
+ catch (error) {
137
+ logger.warn('LLM entity extraction error (LM Studio):', { error: error });
138
+ }
139
+ }
140
+ return null;
141
+ }
142
+ // ─── JSON Parsing ────────────────────────────────────────────────────────────
143
+ /**
144
+ * Parse LLM response into structured extraction result.
145
+ * Handles various response formats (raw JSON, markdown code blocks, etc.)
146
+ */
147
+ function parseLLMResponse(response) {
148
+ // Try to extract JSON from the response
149
+ let jsonStr = response.trim();
150
+ // Handle markdown code blocks
151
+ const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
152
+ if (codeBlockMatch) {
153
+ jsonStr = codeBlockMatch[1].trim();
154
+ }
155
+ // Try to find JSON object in the response
156
+ const jsonMatch = jsonStr.match(/\{[\s\S]*\}/);
157
+ if (!jsonMatch) {
158
+ logger.debug('No JSON found in LLM response');
159
+ return null;
160
+ }
161
+ try {
162
+ const parsed = JSON.parse(jsonMatch[0]);
163
+ // Validate structure
164
+ if (!parsed.entities || !Array.isArray(parsed.entities)) {
165
+ logger.debug('LLM response missing entities array');
166
+ return null;
167
+ }
168
+ const entities = parsed.entities
169
+ .filter((e) => e.name && e.type)
170
+ .map((e) => ({
171
+ name: String(e.name),
172
+ type: validateEntityType(String(e.type)),
173
+ confidence: typeof e.confidence === 'number' ? Math.min(1, Math.max(0, e.confidence)) : 0.8,
174
+ startIndex: 0,
175
+ endIndex: 0,
176
+ context: String(e.context || ''),
177
+ normalized: e.normalized ? String(e.normalized) : undefined,
178
+ }));
179
+ const relations = (parsed.relations || [])
180
+ .filter((r) => r.from && r.to && r.type)
181
+ .map((r) => ({
182
+ fromEntity: String(r.from),
183
+ toEntity: String(r.to),
184
+ relationType: validateRelationType(String(r.type)),
185
+ confidence: typeof r.confidence === 'number' ? Math.min(1, Math.max(0, r.confidence)) : 0.7,
186
+ context: String(r.context || ''),
187
+ }));
188
+ return { entities, relations };
189
+ }
190
+ catch (error) {
191
+ logger.debug('Failed to parse LLM response as JSON', { error: error });
192
+ return null;
193
+ }
194
+ }
195
+ function validateEntityType(type) {
196
+ const validTypes = ['person', 'file', 'function', 'class', 'concept', 'tool', 'date', 'location', 'pattern', 'technique', 'other'];
197
+ const lower = type.toLowerCase();
198
+ if (validTypes.includes(lower))
199
+ return lower;
200
+ return 'other';
201
+ }
202
+ function validateRelationType(type) {
203
+ const validTypes = [
204
+ 'works_on', 'depends_on', 'manages', 'uses', 'caused', 'located_in',
205
+ 'belongs_to', 'reports_to', 'occurred_on', 'affects', 'contains',
206
+ 'implements', 'extends', 'related_to', 'part_of', 'owns', 'created',
207
+ 'resolved', 'blocks',
208
+ ];
209
+ const lower = type.toLowerCase();
210
+ if (validTypes.includes(lower))
211
+ return lower;
212
+ return 'related_to';
213
+ }
214
+ // ─── Main Extraction Functions ───────────────────────────────────────────────
215
+ /**
216
+ * Extract entities and relationships from text using LLM.
217
+ * Falls back to regex extraction when LLM is unavailable.
218
+ */
219
+ export async function extractEntitiesAndRelations(content, options) {
220
+ const { preferLLM = true, maxContentLength = 4000 } = options || {};
221
+ // Truncate very long content
222
+ const truncatedContent = content.length > maxContentLength
223
+ ? content.substring(0, maxContentLength) + '...'
224
+ : content;
225
+ // Try LLM extraction first if preferred
226
+ if (preferLLM) {
227
+ const llmResult = await extractWithLLM(truncatedContent);
228
+ if (llmResult) {
229
+ logger.debug('LLM entity extraction succeeded', {
230
+ entityCount: llmResult.entities.length,
231
+ relationCount: llmResult.relations.length,
232
+ });
233
+ return { ...llmResult, source: 'llm' };
234
+ }
235
+ }
236
+ // Fall back to regex extraction
237
+ const regexEntities = await regexExtractEntities(content);
238
+ if (regexEntities.length > 0) {
239
+ logger.debug('Regex entity extraction fallback', {
240
+ entityCount: regexEntities.length,
241
+ });
242
+ return {
243
+ entities: regexEntities,
244
+ relations: [], // Regex extraction doesn't produce relations
245
+ source: 'regex',
246
+ };
247
+ }
248
+ return { entities: [], relations: [], source: 'none' };
249
+ }
250
+ /**
251
+ * Extract entities and relations using LLM.
252
+ */
253
+ async function extractWithLLM(content) {
254
+ const response = await callLLM(ENTITY_EXTRACTION_PROMPT, content);
255
+ if (!response)
256
+ return null;
257
+ const parsed = parseLLMResponse(response);
258
+ if (!parsed)
259
+ return null;
260
+ // Validate that extracted entities actually appear in the content
261
+ const validatedEntities = parsed.entities.filter((entity) => {
262
+ // Allow entities whose name or a significant substring appears in content
263
+ const nameLower = entity.name.toLowerCase();
264
+ const contentLower = content.toLowerCase();
265
+ // Check if the entity name or a key part of it appears in content
266
+ const words = nameLower.split(/\s+/);
267
+ return words.some(word => word.length > 2 && contentLower.includes(word));
268
+ });
269
+ // Validate that relation entities exist in the entity list
270
+ const entityNames = new Set(validatedEntities.map(e => e.name.toLowerCase()));
271
+ const validatedRelations = parsed.relations.filter((relation) => {
272
+ const fromExists = entityNames.has(relation.fromEntity.toLowerCase());
273
+ const toExists = entityNames.has(relation.toEntity.toLowerCase());
274
+ // Allow relations where at least one entity is known
275
+ // (the LLM might use slightly different names)
276
+ return fromExists || toExists ||
277
+ // Also allow if both entity names appear in the content
278
+ (content.toLowerCase().includes(relation.fromEntity.toLowerCase()) &&
279
+ content.toLowerCase().includes(relation.toEntity.toLowerCase()));
280
+ });
281
+ return {
282
+ entities: validatedEntities,
283
+ relations: validatedRelations,
284
+ };
285
+ }
286
+ /**
287
+ * Extract entities and relations from multiple memories in batch.
288
+ * More efficient than calling extractEntitiesAndRelations for each memory.
289
+ */
290
+ export async function batchExtractEntitiesAndRelations(contents, options) {
291
+ const { batchSize = 5 } = options || {};
292
+ const results = [];
293
+ // Process in batches to avoid overwhelming the LLM
294
+ for (let i = 0; i < contents.length; i += batchSize) {
295
+ const batch = contents.slice(i, i + batchSize);
296
+ const batchResults = await Promise.all(batch.map(content => extractEntitiesAndRelations(content, options)));
297
+ results.push(...batchResults);
298
+ }
299
+ return results;
300
+ }
301
+ /**
302
+ * Get the extraction prompt for testing/debugging purposes.
303
+ */
304
+ export function getExtractionPrompt() {
305
+ return ENTITY_EXTRACTION_PROMPT;
306
+ }
307
+ /**
308
+ * Parse an LLM response for testing/debugging purposes.
309
+ */
310
+ export function testParseLLMResponse(response) {
311
+ return parseLLMResponse(response);
312
+ }
313
+ //# sourceMappingURL=llm-entity-extractor.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Multi-Hop Retrieval
3
+ *
4
+ * Combines vector search with graph traversal to answer queries that
5
+ * require following relationships across entities.
6
+ */
7
+ import { type SearchResult } from '../memory/hybrid-search.js';
8
+ import { type TraversalPath } from './graph-traversal.js';
9
+ export interface MultiHopResult extends SearchResult {
10
+ /** How this result was found: 'vector' (direct search) or 'graph' (via traversal) */
11
+ retrievalPath: 'vector' | 'graph' | 'both';
12
+ /** The graph path that led to this result (if found via graph) */
13
+ graphPath?: TraversalPath;
14
+ /** Entities that connected this result to the query */
15
+ connectingEntities?: string[];
16
+ /** Hybrid score for backward compatibility */
17
+ hybridScore?: number;
18
+ }
19
+ export interface MultiHopSearchOptions {
20
+ /** Search query */
21
+ query: string;
22
+ /** Project path for scoping */
23
+ project?: string;
24
+ /** Maximum number of results */
25
+ limit?: number;
26
+ /** Maximum graph traversal depth */
27
+ maxHops?: number;
28
+ /** Whether to include vector-only results */
29
+ includeVectorResults?: boolean;
30
+ /** Whether to include graph-expanded results */
31
+ includeGraphResults?: boolean;
32
+ /** Minimum graph path weight to include */
33
+ minPathWeight?: number;
34
+ /** Session ID for context */
35
+ sessionId?: string;
36
+ }
37
+ /**
38
+ * Perform multi-hop search combining vector search with graph traversal.
39
+ */
40
+ export declare function multiHopSearch(options: MultiHopSearchOptions): Promise<MultiHopResult[]>;
41
+ /** Check if query needs multi-hop graph traversal. */
42
+ export declare function needsMultiHop(query: string): boolean;
43
+ /**
44
+ * Get a human-readable explanation of how a multi-hop result was found.
45
+ */
46
+ export declare function explainRetrievalPath(result: MultiHopResult): string;
47
+ export declare const wouldBenefitFromMultiHop: typeof needsMultiHop;
48
+ //# sourceMappingURL=multi-hop-retrieval.d.ts.map
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Multi-Hop Retrieval
3
+ *
4
+ * Combines vector search with graph traversal to answer queries that
5
+ * require following relationships across entities.
6
+ */
7
+ import { eq } from 'drizzle-orm';
8
+ import { getDb } from '../../db/index.js';
9
+ import { getSchema } from '../../db/schema.js';
10
+ import { hybridSearch } from '../memory/hybrid-search.js';
11
+ import { extractEntitiesAndRelations } from './llm-entity-extractor.js';
12
+ import { extractEntityNames } from '../memory/entity-extractor.js';
13
+ import { findEntitiesByName, findPaths, traverse } from './graph-traversal.js';
14
+ import { logger } from '../logger.js';
15
+ import { config } from '../../config.js';
16
+ // ─── Main Multi-Hop Search ──────────────────────────────────────────────────
17
+ /**
18
+ * Perform multi-hop search combining vector search with graph traversal.
19
+ */
20
+ export async function multiHopSearch(options) {
21
+ const { query, project, limit = 10, maxHops = 3, includeVectorResults = true, includeGraphResults = true, minPathWeight = 1, sessionId, } = options;
22
+ const results = [];
23
+ const seenMemoryIds = new Set();
24
+ // Step 1: Extract query entities (respect global LLM config)
25
+ let queryEntityNames;
26
+ try {
27
+ const extraction = await extractEntitiesAndRelations(query, { preferLLM: config.llmEnabled });
28
+ queryEntityNames = extraction.entities.map(e => e.name);
29
+ logger.debug('Multi-hop search: entity extraction succeeded', {
30
+ query: query.substring(0, 100),
31
+ entities: queryEntityNames,
32
+ source: extraction.source,
33
+ });
34
+ }
35
+ catch (error) {
36
+ // LLM failed or disabled - fall back to simple keyword extraction
37
+ logger.debug('Multi-hop search: entity extraction failed, falling back to keywords', { error });
38
+ const simpleEntities = extractEntityNames(query);
39
+ queryEntityNames = simpleEntities;
40
+ logger.debug('Multi-hop search: keyword extraction', {
41
+ entities: queryEntityNames,
42
+ });
43
+ }
44
+ // Step 2: Vector search (baseline results)
45
+ if (includeVectorResults) {
46
+ const vectorResults = await hybridSearch({
47
+ query,
48
+ project,
49
+ limit: limit * 2, // Get more candidates for reranking
50
+ });
51
+ for (const result of vectorResults) {
52
+ if (!seenMemoryIds.has(result.id)) {
53
+ seenMemoryIds.add(result.id);
54
+ results.push({
55
+ ...result,
56
+ retrievalPath: 'vector',
57
+ });
58
+ }
59
+ }
60
+ }
61
+ // Step 3: Graph expansion (if we have entities)
62
+ if (includeGraphResults && queryEntityNames.length > 0 && project) {
63
+ const graphResults = await expandViaGraph(queryEntityNames, project, maxHops, minPathWeight, limit);
64
+ // Find memories connected to graph-expanded entities
65
+ for (const graphResult of graphResults) {
66
+ // Search for memories mentioning the expanded entities
67
+ const expandedMemories = await hybridSearch({
68
+ query: graphResult.entityName,
69
+ project,
70
+ limit: 5,
71
+ });
72
+ for (const memory of expandedMemories) {
73
+ if (!seenMemoryIds.has(memory.id)) {
74
+ seenMemoryIds.add(memory.id);
75
+ results.push({
76
+ ...memory,
77
+ retrievalPath: 'graph',
78
+ graphPath: graphResult.path,
79
+ connectingEntities: [graphResult.entityName],
80
+ });
81
+ }
82
+ }
83
+ }
84
+ }
85
+ // Step 4: Rank combined results
86
+ // Vector results keep their hybrid score, graph results get a boost
87
+ // for being connected to query entities via the knowledge graph
88
+ const ranked = rankMultiHopResults(results, queryEntityNames);
89
+ return ranked.slice(0, limit);
90
+ }
91
+ /**
92
+ * Expand query entities via the knowledge graph to find related entities.
93
+ */
94
+ async function expandViaGraph(queryEntityNames, project, maxHops, minPathWeight, limit) {
95
+ const db = await getDb();
96
+ const schema = await getSchema();
97
+ const results = [];
98
+ const seenEntities = new Set();
99
+ // Get project ID
100
+ const projectRows = await db
101
+ .select({ id: schema.projects.id })
102
+ .from(schema.projects)
103
+ .where(eq(schema.projects.path, project))
104
+ .limit(1);
105
+ if (projectRows.length === 0)
106
+ return [];
107
+ const projectId = projectRows[0].id;
108
+ // For each query entity, find it in the graph and expand
109
+ for (const entityName of queryEntityNames) {
110
+ const entities = await findEntitiesByName(entityName, projectId, { limit: 3 });
111
+ for (const entity of entities) {
112
+ if (seenEntities.has(entity.id))
113
+ continue;
114
+ seenEntities.add(entity.id);
115
+ // Traverse the graph from this entity
116
+ const neighbors = await traverse(entity.id, {
117
+ maxDepth: maxHops,
118
+ minWeight: minPathWeight,
119
+ limit: 20,
120
+ });
121
+ for (const neighbor of neighbors) {
122
+ if (seenEntities.has(neighbor.id))
123
+ continue;
124
+ seenEntities.add(neighbor.id);
125
+ // Find the path from query entity to this neighbor
126
+ const paths = await findPaths(entity.id, neighbor.id, {
127
+ maxHops,
128
+ minWeight: minPathWeight,
129
+ maxPaths: 1,
130
+ });
131
+ if (paths.length > 0) {
132
+ const path = paths[0];
133
+ // Score based on path length and weight
134
+ const relevanceScore = 1 / (1 + path.hopCount) * (1 / (1 + path.totalWeight * 0.1));
135
+ results.push({
136
+ entityName: neighbor.name,
137
+ entityId: neighbor.id,
138
+ path,
139
+ relevanceScore,
140
+ });
141
+ }
142
+ }
143
+ }
144
+ }
145
+ // Sort by relevance score
146
+ results.sort((a, b) => b.relevanceScore - a.relevanceScore);
147
+ return results.slice(0, limit);
148
+ }
149
+ // ─── Result Ranking ──────────────────────────────────────────────────────────
150
+ /**
151
+ * Rank multi-hop results combining vector score with graph connectivity.
152
+ */
153
+ function rankMultiHopResults(results, queryEntityNames) {
154
+ return results
155
+ .map(result => {
156
+ let score = result.similarity || 0;
157
+ // Boost for graph-connected results
158
+ if (result.retrievalPath === 'graph' || result.retrievalPath === 'both') {
159
+ score *= 1.2; // 20% boost for graph connectivity
160
+ }
161
+ // Boost for matching query entities in content
162
+ const contentLower = (result.content || '').toLowerCase();
163
+ for (const entity of queryEntityNames) {
164
+ if (contentLower.includes(entity.toLowerCase())) {
165
+ score *= 1.1; // 10% boost per entity match
166
+ }
167
+ }
168
+ // Boost for shorter graph paths (more direct connections)
169
+ if (result.graphPath) {
170
+ const pathBonus = 1 / (1 + result.graphPath.hopCount * 0.2);
171
+ score *= (1 + pathBonus * 0.15); // Up to 15% bonus for short paths
172
+ }
173
+ return {
174
+ ...result,
175
+ similarity: Math.round(score * 1000) / 1000,
176
+ hybridScore: Math.round(score * 100) / 100, // Backward compat
177
+ };
178
+ })
179
+ .sort((a, b) => (b.similarity || 0) - (a.similarity || 0));
180
+ }
181
+ // ─── Utility ────────────────────────────────────────────────────────────────
182
+ /** Check if query needs multi-hop graph traversal. */
183
+ export function needsMultiHop(query) {
184
+ // Queries with relationship indicators benefit from multi-hop
185
+ const relationshipPatterns = [
186
+ /\b(affected by|caused by|related to|connected to|depends? on|works? on|uses?|manages?)\b/i,
187
+ /\b(who|what|which|how)\b.*\b(project|team|system|service|database)\b/i,
188
+ /\b(impact|affect|influence|caus\w+|result|lead to)\b/i,
189
+ ];
190
+ return relationshipPatterns.some(pattern => pattern.test(query));
191
+ }
192
+ /**
193
+ * Get a human-readable explanation of how a multi-hop result was found.
194
+ */
195
+ export function explainRetrievalPath(result) {
196
+ if (result.retrievalPath === 'vector') {
197
+ return `Found via semantic search (score: ${result.similarity?.toFixed(2)})`;
198
+ }
199
+ if (result.retrievalPath === 'graph' && result.graphPath) {
200
+ const pathSteps = result.graphPath.nodes
201
+ .map(n => n.name)
202
+ .join(' → ');
203
+ return `Found via knowledge graph: ${pathSteps} (hops: ${result.graphPath.hopCount})`;
204
+ }
205
+ if (result.retrievalPath === 'both' && result.graphPath) {
206
+ const pathSteps = result.graphPath.nodes
207
+ .map(n => n.name)
208
+ .join(' → ');
209
+ return `Found via both search and graph: ${pathSteps} (score: ${result.similarity?.toFixed(2)})`;
210
+ }
211
+ return `Found via ${result.retrievalPath} search`;
212
+ }
213
+ // Backward compatibility alias
214
+ export const wouldBenefitFromMultiHop = needsMultiHop;
215
+ //# sourceMappingURL=multi-hop-retrieval.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Relationship Extractor
3
+ *
4
+ * Populates entity_relations table with typed relationships extracted
5
+ * from memory content.
6
+ */
7
+ import { type RelationType } from './llm-entity-extractor.js';
8
+ export interface StoredRelation {
9
+ id: string;
10
+ fromEntityId: string;
11
+ toEntityId: string;
12
+ fromEntityName: string;
13
+ toEntityName: string;
14
+ relationType: RelationType;
15
+ weight: number;
16
+ properties: Record<string, unknown> | null;
17
+ }
18
+ /**
19
+ * Extract entities and relations from memory content and store them in the database.
20
+ * Returns the stored entities and relations.
21
+ */
22
+ export declare function extractAndStoreRelations(memoryId: string, content: string, projectId: string, options?: {
23
+ preferLLM?: boolean;
24
+ maxContentLength?: number;
25
+ }): Promise<{
26
+ entities: number;
27
+ relations: number;
28
+ source: 'llm' | 'regex' | 'fallback';
29
+ }>;
30
+ /**
31
+ * Get all relations for a set of entity IDs.
32
+ * Used by graph traversal to find connected entities.
33
+ */
34
+ export declare function getEntityRelations(entityIds: string[], relationTypes?: RelationType[]): Promise<StoredRelation[]>;
35
+ /**
36
+ * Get all entities for a project.
37
+ */
38
+ export declare function getProjectEntities(projectId: string, limit?: number): Promise<Array<{
39
+ id: string;
40
+ name: string;
41
+ type: string;
42
+ description: string | null;
43
+ }>>;
44
+ /**
45
+ * Delete all entities and relations for a project (for graph rebuild).
46
+ */
47
+ export declare function clearProjectGraph(projectId: string): Promise<void>;
48
+ //# sourceMappingURL=relationship-extractor.d.ts.map