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,200 @@
1
+ import { logger } from '../logger.js';
2
+ import { config } from '../../config.js';
3
+
4
+ export interface MultimodalInput {
5
+ text?: string;
6
+ image?: Buffer | string;
7
+ video?: string;
8
+ }
9
+
10
+ export interface GoogleMultimodalResponse {
11
+ embedding: number[];
12
+ textEmbedding?: number[];
13
+ imageEmbedding?: number[];
14
+ videoEmbedding?: number[];
15
+ }
16
+
17
+ export async function getGoogleMultimodalEmbedding(
18
+ input: MultimodalInput
19
+ ): Promise<GoogleMultimodalResponse | null> {
20
+ if (!config.googleCloudApiKey && !config.googleCloudProject) {
21
+ logger.debug('Google Cloud credentials not configured');
22
+ return null;
23
+ }
24
+
25
+ if (!config.googleEmbeddingModel) {
26
+ logger.debug('Google embedding model not configured');
27
+ return null;
28
+ }
29
+
30
+ try {
31
+ const endpoint = config.googleCloudLocation === 'global'
32
+ ? `https://aiplatform.googleapis.com/v1/projects/${config.googleCloudProject}/locations/${config.googleCloudLocation}/publishers/google/models/${config.googleEmbeddingModel}:predict`
33
+ : `https://${config.googleCloudLocation}-aiplatform.googleapis.com/v1/projects/${config.googleCloudProject}/locations/${config.googleCloudLocation}/publishers/google/models/${config.googleEmbeddingModel}:predict`;
34
+
35
+ const instances: any[] = [];
36
+
37
+ if (input.text) {
38
+ instances.push({ text: input.text });
39
+ }
40
+
41
+ if (input.image) {
42
+ const imageBytes = typeof input.image === 'string'
43
+ ? input.image
44
+ : input.image.toString('base64');
45
+
46
+ instances.push({
47
+ image: {
48
+ bytesBase64Encoded: imageBytes,
49
+ },
50
+ });
51
+ }
52
+
53
+ if (input.video) {
54
+ instances.push({
55
+ video: {
56
+ gcsUri: input.video,
57
+ },
58
+ });
59
+ }
60
+
61
+ if (instances.length === 0) {
62
+ return null;
63
+ }
64
+
65
+ const response = await fetch(endpoint, {
66
+ method: 'POST',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ 'Authorization': `Bearer ${await getGoogleAccessToken()}`,
70
+ },
71
+ body: JSON.stringify({
72
+ instances,
73
+ parameters: {
74
+ dimension: 1408,
75
+ },
76
+ }),
77
+ });
78
+
79
+ if (!response.ok) {
80
+ const errorText = await response.text();
81
+ logger.warn(`Google Multimodal embeddings failed: ${response.status} ${errorText}`);
82
+ return null;
83
+ }
84
+
85
+ const data = await response.json() as { predictions?: any[] };
86
+ const predictions = data.predictions || [];
87
+
88
+ const result: GoogleMultimodalResponse = {
89
+ embedding: predictions[0]?.embedding || [],
90
+ };
91
+
92
+ if (input.text && predictions[0]?.textEmbedding) {
93
+ result.textEmbedding = predictions[0].textEmbedding;
94
+ }
95
+
96
+ if (input.image && predictions[0]?.imageEmbedding) {
97
+ result.imageEmbedding = predictions[0].imageEmbedding;
98
+ }
99
+
100
+ if (input.video && predictions[0]?.videoEmbedding) {
101
+ result.videoEmbedding = predictions[0].videoEmbedding;
102
+ }
103
+
104
+ return result.embedding.length > 0 ? result : null;
105
+ } catch (error) {
106
+ logger.error('Google Multimodal embedding error:', error);
107
+ return null;
108
+ }
109
+ }
110
+
111
+ let cachedAccessToken: string | null = null;
112
+ let tokenExpiry: number = 0;
113
+
114
+ async function getGoogleAccessToken(): Promise<string> {
115
+ if (config.googleCloudApiKey) {
116
+ return config.googleCloudApiKey;
117
+ }
118
+
119
+ if (cachedAccessToken && Date.now() < tokenExpiry) {
120
+ return cachedAccessToken;
121
+ }
122
+
123
+ if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
124
+ throw new Error('Google Application Credentials not set');
125
+ }
126
+
127
+ try {
128
+ const credentials = JSON.parse(
129
+ await import('fs').then(fs =>
130
+ fs.promises.readFile(process.env.GOOGLE_APPLICATION_CREDENTIALS!, 'utf-8')
131
+ )
132
+ );
133
+
134
+ const now = Math.floor(Date.now() / 1000);
135
+ const jwt = await createJWT(credentials);
136
+
137
+ const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
138
+ method: 'POST',
139
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
140
+ body: new URLSearchParams({
141
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
142
+ assertion: jwt,
143
+ }),
144
+ });
145
+
146
+ if (!tokenResponse.ok) {
147
+ throw new Error('Failed to get Google access token');
148
+ }
149
+
150
+ const tokenData = await tokenResponse.json() as { access_token: string; expires_in: number };
151
+ cachedAccessToken = tokenData.access_token;
152
+ tokenExpiry = now + tokenData.expires_in - 60;
153
+
154
+ return cachedAccessToken;
155
+ } catch (error) {
156
+ logger.error('Failed to get Google access token:', error);
157
+ throw error;
158
+ }
159
+ }
160
+
161
+ async function createJWT(credentials: any): Promise<string> {
162
+ const now = Math.floor(Date.now() / 1000);
163
+
164
+ const header = {
165
+ alg: 'RS256',
166
+ typ: 'JWT',
167
+ };
168
+
169
+ const payload = {
170
+ iss: credentials.client_email,
171
+ sub: credentials.client_email,
172
+ aud: 'https://oauth2.googleapis.com/token',
173
+ iat: now,
174
+ exp: now + 3600,
175
+ scope: 'https://www.googleapis.com/auth/cloud-platform',
176
+ };
177
+
178
+ const crypto = await import('crypto');
179
+
180
+ const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
181
+ const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
182
+
183
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
184
+
185
+ const sign = crypto.createSign('RSA-SHA256');
186
+ sign.update(signatureInput);
187
+ const signature = sign.sign(credentials.private_key, 'base64url');
188
+
189
+ return `${signatureInput}.${signature}`;
190
+ }
191
+
192
+ export function isMultimodalInput(input: any): input is MultimodalInput {
193
+ return (
194
+ typeof input === 'object' &&
195
+ (typeof input.text === 'string' ||
196
+ Buffer.isBuffer(input.image) ||
197
+ typeof input.image === 'string' ||
198
+ typeof input.video === 'string')
199
+ );
200
+ }
@@ -1,11 +1,12 @@
1
- /**
2
- * Utility functions for local embeddings
3
- * Note: Actual embedding generation is in core/embeddings.ts
4
- */
5
- import { cosineSimilarity as vectorCosineSimilarity } from './utils/vector-operations.js';
6
- /**
7
- * @deprecated Use cosineSimilarity from core/utils/vector-operations.ts directly.
8
- * This re-export is for backward compatibility and will be removed in v1.2.0.
9
- */
10
- export const cosineSimilarity = vectorCosineSimilarity;
11
- //# sourceMappingURL=local-embeddings.js.map
1
+ /**
2
+ * Utility functions for local embeddings
3
+ * Note: Actual embedding generation is in core/embeddings.ts
4
+ */
5
+
6
+ import { cosineSimilarity as vectorCosineSimilarity } from '../utils/vector-operations.js';
7
+
8
+ /**
9
+ * @deprecated Use cosineSimilarity from core/utils/vector-operations.ts directly.
10
+ * This re-export is for backward compatibility and will be removed in v1.2.0.
11
+ */
12
+ export const cosineSimilarity = vectorCosineSimilarity;
@@ -0,0 +1,495 @@
1
+ /**
2
+ * QMD MCP Client
3
+ *
4
+ * Connects to QMD (Quick Markdown Search) MCP server for hybrid search capabilities.
5
+ * QMD provides BM25 full-text search, vector semantic search, and LLM re-ranking.
6
+ *
7
+ * Installation: bun install -g qmd
8
+ * GitHub: https://github.com/tobi/qmd
9
+ *
10
+ * QMD MCP Tools:
11
+ * - qmd_search: Fast BM25 keyword search
12
+ * - qmd_vsearch: Semantic vector search
13
+ * - qmd_query: Hybrid search with re-ranking (best quality)
14
+ * - qmd_get: Retrieve document by path or docid
15
+ * - qmd_multi_get: Retrieve multiple documents
16
+ * - qmd_status: Index health and collection info
17
+ */
18
+
19
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
20
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
21
+ import { spawn } from 'child_process';
22
+ import { logger } from '../logger';
23
+
24
+ export interface QMDSearchOptions {
25
+ query: string;
26
+ collection?: string;
27
+ limit?: number;
28
+ minScore?: number;
29
+ }
30
+
31
+ export interface QMDSearchResult {
32
+ docid: string;
33
+ path: string;
34
+ title: string;
35
+ context: string;
36
+ score: number;
37
+ snippet: string;
38
+ }
39
+
40
+ export interface QMDStatusResult {
41
+ indexHealth: string;
42
+ collections: Array<{
43
+ name: string;
44
+ path: string;
45
+ documentCount: number;
46
+ }>;
47
+ }
48
+
49
+ export interface QMDGetOptions {
50
+ pathOrDocid: string;
51
+ full?: boolean;
52
+ maxBytes?: number;
53
+ }
54
+
55
+ /**
56
+ * QMD MCP Client class
57
+ *
58
+ * Manages connection to QMD MCP server and provides methods for
59
+ * search, document retrieval, and status checking.
60
+ */
61
+ export class QMDClient {
62
+ private client: Client | null = null;
63
+ private transport: StdioClientTransport | null = null;
64
+ private connected = false;
65
+ private connecting = false;
66
+
67
+ /**
68
+ * Check if QMD is installed on the system
69
+ */
70
+ async checkQMDInstalled(): Promise<boolean> {
71
+ return new Promise((resolve) => {
72
+ const process = spawn('qmd', ['--version'], {
73
+ stdio: 'ignore',
74
+ shell: true
75
+ });
76
+
77
+ process.on('close', (code) => {
78
+ resolve(code === 0);
79
+ });
80
+
81
+ process.on('error', () => {
82
+ resolve(false);
83
+ });
84
+
85
+ // Timeout after 5 seconds
86
+ setTimeout(() => {
87
+ process.kill();
88
+ resolve(false);
89
+ }, 5000);
90
+ });
91
+ }
92
+
93
+ /**
94
+ * Connect to QMD MCP server
95
+ * QMD must be installed: bun install -g qmd
96
+ */
97
+ async connect(): Promise<boolean> {
98
+ if (this.connected || this.connecting) {
99
+ return this.connected;
100
+ }
101
+
102
+ this.connecting = true;
103
+
104
+ try {
105
+ // Check if QMD is installed
106
+ const installed = await this.checkQMDInstalled();
107
+ if (!installed) {
108
+ logger.warn('QMD is not installed. Install with: bun install -g qmd');
109
+ this.connecting = false;
110
+ return false;
111
+ }
112
+
113
+ this.transport = new StdioClientTransport({
114
+ command: 'qmd',
115
+ args: ['mcp'],
116
+ stderr: 'inherit'
117
+ });
118
+
119
+ this.client = new Client(
120
+ { name: 'squish-qmd-client', version: '1.0.0' },
121
+ { capabilities: {} }
122
+ );
123
+
124
+ await this.client.connect(this.transport);
125
+ this.connected = true;
126
+ this.connecting = false;
127
+ logger.info('Connected to QMD MCP server');
128
+ return true;
129
+ } catch (error) {
130
+ logger.warn(`QMD MCP connection failed: ${error}`);
131
+ this.connected = false;
132
+ this.connecting = false;
133
+ return false;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Check if QMD is available
139
+ */
140
+ async isAvailable(): Promise<boolean> {
141
+ if (this.connected && this.client) {
142
+ return true;
143
+ }
144
+ return await this.connect();
145
+ }
146
+
147
+ /**
148
+ * Fast BM25 keyword search
149
+ * Uses SQLite FTS5 for fast full-text search
150
+ */
151
+ async search(options: QMDSearchOptions): Promise<QMDSearchResult[]> {
152
+ if (!this.connected || !this.client) {
153
+ throw new Error('QMD client not connected');
154
+ }
155
+
156
+ const result = await this.client.callTool({
157
+ name: 'qmd_search',
158
+ arguments: {
159
+ query: options.query,
160
+ collection: options.collection,
161
+ n: options.limit || 10,
162
+ minScore: options.minScore || 0
163
+ }
164
+ }) as any;
165
+
166
+ return this.parseSearchResults(result);
167
+ }
168
+
169
+ /**
170
+ * Semantic vector search
171
+ * Uses embedding-based similarity search
172
+ */
173
+ async vsearch(options: QMDSearchOptions): Promise<QMDSearchResult[]> {
174
+ if (!this.connected || !this.client) {
175
+ throw new Error('QMD client not connected');
176
+ }
177
+
178
+ const result = await this.client.callTool({
179
+ name: 'qmd_vsearch',
180
+ arguments: {
181
+ query: options.query,
182
+ collection: options.collection,
183
+ n: options.limit || 10,
184
+ minScore: options.minScore || 0
185
+ }
186
+ }) as any;
187
+
188
+ return this.parseSearchResults(result);
189
+ }
190
+
191
+ /**
192
+ * Hybrid search with re-ranking (best quality)
193
+ * Combines BM25 + vector search + LLM re-ranking
194
+ */
195
+ async query(options: QMDSearchOptions): Promise<QMDSearchResult[]> {
196
+ if (!this.connected || !this.client) {
197
+ throw new Error('QMD client not connected');
198
+ }
199
+
200
+ const result = await this.client.callTool({
201
+ name: 'qmd_query',
202
+ arguments: {
203
+ query: options.query,
204
+ collection: options.collection,
205
+ n: options.limit || 10,
206
+ minScore: options.minScore || 0
207
+ }
208
+ }) as any;
209
+
210
+ return this.parseSearchResults(result);
211
+ }
212
+
213
+ /**
214
+ * Get QMD index status and collection info
215
+ */
216
+ async status(): Promise<QMDStatusResult | null> {
217
+ if (!this.connected || !this.client) {
218
+ return null;
219
+ }
220
+
221
+ try {
222
+ const result = await this.client.callTool({
223
+ name: 'qmd_status',
224
+ arguments: {}
225
+ }) as any;
226
+
227
+ return this.parseStatusResult(result);
228
+ } catch (error) {
229
+ logger.debug(`QMD status check failed: ${error}`);
230
+ return null;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Get document by path or docid
236
+ */
237
+ async get(options: QMDGetOptions): Promise<string> {
238
+ if (!this.connected || !this.client) {
239
+ throw new Error('QMD client not connected');
240
+ }
241
+
242
+ const args: Record<string, any> = {
243
+ path: options.pathOrDocid
244
+ };
245
+
246
+ if (options.full !== undefined) {
247
+ args.full = options.full;
248
+ }
249
+ if (options.maxBytes !== undefined) {
250
+ args['max-bytes'] = options.maxBytes;
251
+ }
252
+
253
+ const result = await this.client.callTool({
254
+ name: 'qmd_get',
255
+ arguments: args
256
+ }) as any;
257
+
258
+ return this.parseGetResult(result);
259
+ }
260
+
261
+ /**
262
+ * Get multiple documents by glob pattern or list
263
+ */
264
+ async multiGet(patternOrList: string | string[], options?: { maxBytes?: number; limit?: number }): Promise<string[]> {
265
+ if (!this.connected || !this.client) {
266
+ throw new Error('QMD client not connected');
267
+ }
268
+
269
+ const args: Record<string, any> = {
270
+ pattern: Array.isArray(patternOrList) ? patternOrList.join(',') : patternOrList
271
+ };
272
+
273
+ if (options?.maxBytes !== undefined) {
274
+ args['max-bytes'] = options.maxBytes;
275
+ }
276
+ if (options?.limit !== undefined) {
277
+ args.l = options.limit;
278
+ }
279
+
280
+ const result = await this.client.callTool({
281
+ name: 'qmd_multi_get',
282
+ arguments: args
283
+ }) as any;
284
+
285
+ return this.parseMultiGetResult(result);
286
+ }
287
+
288
+ /**
289
+ * Disconnect from QMD MCP server
290
+ */
291
+ async disconnect(): Promise<void> {
292
+ if (this.client) {
293
+ try {
294
+ await this.client.close();
295
+ } catch (error) {
296
+ logger.debug(`Error closing QMD client: ${error}`);
297
+ }
298
+ this.connected = false;
299
+ this.client = null;
300
+ this.transport = null;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Parse search results from QMD response
306
+ */
307
+ private parseSearchResults(result: any): QMDSearchResult[] {
308
+ if (!result || !result.content) {
309
+ return [];
310
+ }
311
+
312
+ const content = result.content;
313
+
314
+ // Handle text output format
315
+ if (typeof content === 'string') {
316
+ return this.parseTextSearchResults(content);
317
+ }
318
+
319
+ // Handle array content format
320
+ if (Array.isArray(content)) {
321
+ const textContent = content
322
+ .filter((item: any) => item.type === 'text')
323
+ .map((item: any) => item.text)
324
+ .join('\n');
325
+ return this.parseTextSearchResults(textContent);
326
+ }
327
+
328
+ return [];
329
+ }
330
+
331
+ /**
332
+ * Parse QMD's text output format into structured results
333
+ */
334
+ private parseTextSearchResults(text: string): QMDSearchResult[] {
335
+ const results: QMDSearchResult[] = [];
336
+ const lines = text.split('\n');
337
+
338
+ let currentResult: Partial<QMDSearchResult> | null = null;
339
+
340
+ for (const line of lines) {
341
+ // Match path line: "docs/guide.md:42 #a1b2c3"
342
+ const pathMatch = line.match(/^([^\s:]+):(\d+)\s+([#a-zA-Z0-9]+)?/);
343
+ if (pathMatch) {
344
+ if (currentResult && currentResult.path) {
345
+ results.push(this.finalizeResult(currentResult));
346
+ }
347
+ currentResult = {
348
+ path: pathMatch[1],
349
+ docid: pathMatch[3] || '',
350
+ score: 0,
351
+ snippet: ''
352
+ };
353
+ continue;
354
+ }
355
+
356
+ // Match score line: "Score: 93%"
357
+ const scoreMatch = line.match(/^Score:\s+(\d+)%/);
358
+ if (scoreMatch && currentResult) {
359
+ currentResult.score = parseInt(scoreMatch[1]) / 100;
360
+ continue;
361
+ }
362
+
363
+ // Match title line: "Title: Some Title"
364
+ const titleMatch = line.match(/^Title:\s+(.+)/);
365
+ if (titleMatch && currentResult) {
366
+ currentResult.title = titleMatch[1];
367
+ continue;
368
+ }
369
+
370
+ // Match context line: "Context: Some context"
371
+ const contextMatch = line.match(/^Context:\s+(.+)/);
372
+ if (contextMatch && currentResult) {
373
+ currentResult.context = contextMatch[1];
374
+ continue;
375
+ }
376
+
377
+ // Collect snippet content
378
+ if (currentResult && line.trim() && !line.startsWith('---')) {
379
+ currentResult.snippet += line + '\n';
380
+ }
381
+ }
382
+
383
+ // Don't forget the last result
384
+ if (currentResult && currentResult.path) {
385
+ results.push(this.finalizeResult(currentResult));
386
+ }
387
+
388
+ return results;
389
+ }
390
+
391
+ /**
392
+ * Finalize a parsed result with defaults
393
+ */
394
+ private finalizeResult(result: Partial<QMDSearchResult>): QMDSearchResult {
395
+ return {
396
+ path: result.path || '',
397
+ docid: result.docid || '',
398
+ title: result.title || result.path?.split('/').pop() || '',
399
+ context: result.context || '',
400
+ score: result.score || 0,
401
+ snippet: (result.snippet || '').trim()
402
+ };
403
+ }
404
+
405
+ /**
406
+ * Parse status result
407
+ */
408
+ private parseStatusResult(result: any): QMDStatusResult | null {
409
+ if (!result || !result.content) {
410
+ return null;
411
+ }
412
+
413
+ const content = result.content;
414
+ if (typeof content === 'string') {
415
+ try {
416
+ return JSON.parse(content);
417
+ } catch {
418
+ return null;
419
+ }
420
+ }
421
+
422
+ if (Array.isArray(content)) {
423
+ const textContent = content
424
+ .filter((item: any) => item.type === 'text')
425
+ .map((item: any) => item.text)
426
+ .join('');
427
+ try {
428
+ return JSON.parse(textContent);
429
+ } catch {
430
+ return null;
431
+ }
432
+ }
433
+
434
+ return null;
435
+ }
436
+
437
+ /**
438
+ * Parse get result
439
+ */
440
+ private parseGetResult(result: any): string {
441
+ if (!result || !result.content) {
442
+ return '';
443
+ }
444
+
445
+ const content = result.content;
446
+ if (typeof content === 'string') {
447
+ return content;
448
+ }
449
+
450
+ if (Array.isArray(content)) {
451
+ return content
452
+ .filter((item: any) => item.type === 'text')
453
+ .map((item: any) => item.text)
454
+ .join('\n');
455
+ }
456
+
457
+ return '';
458
+ }
459
+
460
+ /**
461
+ * Parse multi-get result
462
+ */
463
+ private parseMultiGetResult(result: any): string[] {
464
+ const text = this.parseGetResult(result);
465
+ if (!text) {
466
+ return [];
467
+ }
468
+
469
+ // Split by document separators and return individual documents
470
+ return text.split(/\n---+\n/).filter(doc => doc.trim());
471
+ }
472
+ }
473
+
474
+ // Singleton instance
475
+ let qmdClientInstance: QMDClient | null = null;
476
+
477
+ /**
478
+ * Get the singleton QMD client instance
479
+ */
480
+ export async function getQMDClient(): Promise<QMDClient> {
481
+ if (!qmdClientInstance) {
482
+ qmdClientInstance = new QMDClient();
483
+ }
484
+ return qmdClientInstance;
485
+ }
486
+
487
+ /**
488
+ * Reset the singleton QMD client (useful for testing)
489
+ */
490
+ export function resetQMDClient(): void {
491
+ if (qmdClientInstance) {
492
+ qmdClientInstance.disconnect().catch(() => {});
493
+ qmdClientInstance = null;
494
+ }
495
+ }