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,494 @@
1
+ /**
2
+ * Contradiction Resolver
3
+ * Detects and auto-resolves contradictions when writing new memories
4
+ * Implements supersession logic for outdated information
5
+ */
6
+
7
+ import { eq, and, inArray } from 'drizzle-orm';
8
+ import { getDb } from '../../db/index.js';
9
+ import { getSchema } from '../../db/schema.js';
10
+ import { logger } from '../logger.js';
11
+ import { createAssociation } from '../associations.js';
12
+
13
+ export interface ContradictionResult {
14
+ hasContradiction: boolean;
15
+ supersededMemories: string[];
16
+ confidence: number;
17
+ reason: string;
18
+ }
19
+
20
+ export interface ContradictionCheck {
21
+ newContent: string;
22
+ newType: string;
23
+ projectId?: string;
24
+ entities?: string[];
25
+ }
26
+
27
+ /**
28
+ * Calculate temporal relationship between two time periods
29
+ * Returns: 'existing_is_newer', 'existing_is_older', 'overlapping', or 'unknown'
30
+ */
31
+ function calculateTemporalRelationship(
32
+ existingValidFrom: string | null,
33
+ existingValidTo: string | null,
34
+ newTime: Date
35
+ ): 'existing_is_newer' | 'existing_is_older' | 'overlapping' | 'unknown' {
36
+ if (!existingValidFrom && !existingValidTo) {
37
+ return 'unknown';
38
+ }
39
+
40
+ const existingFrom = existingValidFrom ? new Date(existingValidFrom) : null;
41
+ const existingTo = existingValidTo ? new Date(existingValidTo) : null;
42
+
43
+ // If existing fact is completely in the future compared to new time
44
+ if (existingFrom && existingFrom > newTime) {
45
+ return 'existing_is_newer';
46
+ }
47
+
48
+ // If existing fact is completely in the past compared to new time
49
+ if (existingTo && existingTo < newTime) {
50
+ return 'existing_is_older';
51
+ }
52
+
53
+ // If time periods overlap or we can't determine
54
+ return 'overlapping';
55
+ }
56
+
57
+ /**
58
+ * Check if two temporal periods conflict (don't overlap reasonably)
59
+ */
60
+ function checkTemporalPeriodConflict(
61
+ existingStart: string | null,
62
+ existingEnd: string | null,
63
+ newStart: Date,
64
+ newEnd: Date | null
65
+ ): boolean {
66
+ // If we don't have enough info, assume no conflict
67
+ if (!existingStart || !existingEnd) {
68
+ return false;
69
+ }
70
+
71
+ const existingStartDate = new Date(existingStart);
72
+ const existingEndDate = new Date(existingEnd);
73
+
74
+ // Normalize newEnd (use distant future if null)
75
+ const normalizedNewEnd = newEnd || new Date(8640000000000000); // Far future
76
+
77
+ // Check if periods overlap
78
+ const overlaps = !(existingStartDate > normalizedNewEnd ||
79
+ existingEndDate < newStart);
80
+
81
+ // Conflict if they don't overlap
82
+ return !overlaps;
83
+ }
84
+
85
+ // Patterns that indicate updated/corrected information
86
+ const UPDATE_PATTERNS = [
87
+ /\b(now|currently|actually|in fact|correct(ed)?|update(d)?)\b/gi,
88
+ /\b(changed to|switched to|moved to)\b/gi,
89
+ /\b(formerly|previously|used to be)\b/gi,
90
+ /\binstead of\b/gi,
91
+ /\b(no longer|not anymore)\b/gi,
92
+ /\b(as of|starting|beginning|from now|effective)\s+(\d{4}|\w+\s+\d{1,2})/gi, // Temporal updates
93
+ ];
94
+
95
+ // Negation patterns
96
+ const NEGATION_PATTERNS = [
97
+ /\b(not|no|never|don't|doesn't|didn't|won't|wouldn't|shouldn't|can't|cannot)\b/gi,
98
+ ];
99
+
100
+ // Temporal sensitivity patterns - content that is likely time-sensitive
101
+ const TEMPORAL_SENSITIVITY_PATTERNS = [
102
+ /\b(date|time|version|release|deadline|schedule|timeline)\b/i,
103
+ /\b(\d{4}|january|february|march|april|may|june|july|august|september|october|november|december)\b/i,
104
+ /\b(today|tomorrow|yesterday|next\s+week|last\s+week|this\s+week)\b/i,
105
+ ];
106
+
107
+ // Key entity extraction for contradiction detection
108
+ function extractKeyEntities(content: string): string[] {
109
+ // Simple extraction of capitalized phrases and key terms
110
+ const entities: string[] = [];
111
+
112
+ // Match capitalized multi-word phrases (likely proper nouns)
113
+ const properNouns = content.match(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+\b/g) || [];
114
+ entities.push(...properNouns);
115
+
116
+ // Match quoted strings (often important values)
117
+ const quoted = content.match(/"([^"]+)"|'([^']+)'/g) || [];
118
+ entities.push(...quoted.map(q => q.replace(/['"]/g, '')));
119
+
120
+ // Match key-value patterns
121
+ const keyValues = content.match(/(\w+)\s*[=:]\s*(\S+)/g) || [];
122
+ entities.push(...keyValues);
123
+
124
+ return [...new Set(entities)];
125
+ }
126
+
127
+ // Calculate content similarity (Jaccard on words)
128
+ function calculateSimilarity(a: string, b: string): number {
129
+ const tokensA = new Set(a.toLowerCase().split(/\s+/).filter(t => t.length > 2));
130
+ const tokensB = new Set(b.toLowerCase().split(/\s+/).filter(t => t.length > 2));
131
+
132
+ const intersection = new Set([...tokensA].filter(x => tokensB.has(x)));
133
+ const union = new Set([...tokensA, ...tokensB]);
134
+
135
+ return union.size > 0 ? intersection.size / union.size : 0;
136
+ }
137
+
138
+ // Check if content has negation
139
+ function hasNegation(content: string): boolean {
140
+ return NEGATION_PATTERNS.some(pattern => pattern.test(content));
141
+ }
142
+
143
+ // Check if content indicates an update
144
+ function hasUpdateIndicator(content: string): boolean {
145
+ return UPDATE_PATTERNS.some(pattern => pattern.test(content));
146
+ }
147
+
148
+ // Extract the "subject" of a memory (what it's about)
149
+ function extractSubject(content: string): string {
150
+ // Take first significant clause
151
+ const sentences = content.split(/[.!?\n]/);
152
+ const firstSentence = sentences[0]?.trim() || content;
153
+
154
+ // Limit to first 100 chars for subject matching
155
+ return firstSentence.substring(0, 100).toLowerCase();
156
+ }
157
+
158
+ /**
159
+ * Detect contradictions between new memory and existing memories
160
+ */
161
+ export async function detectContradictions(check: ContradictionCheck): Promise<ContradictionResult> {
162
+ const result: ContradictionResult = {
163
+ hasContradiction: false,
164
+ supersededMemories: [],
165
+ confidence: 0,
166
+ reason: '',
167
+ };
168
+
169
+ try {
170
+ const db = await getDb();
171
+ const schema = await getSchema();
172
+
173
+ // Get memories from same project with similar content
174
+ const whereClause = check.projectId
175
+ ? eq(schema.memories.projectId, check.projectId)
176
+ : undefined;
177
+
178
+ const existingMemories = await (db as any)
179
+ .select()
180
+ .from(schema.memories)
181
+ .where(whereClause)
182
+ .limit(100);
183
+
184
+ if (existingMemories.length === 0) {
185
+ return result;
186
+ }
187
+
188
+ const newSubject = extractSubject(check.newContent);
189
+ const newEntities = extractKeyEntities(check.newContent);
190
+ const newHasNegation = hasNegation(check.newContent);
191
+ const newHasUpdate = hasUpdateIndicator(check.newContent);
192
+
193
+ const toSupersede: string[] = [];
194
+ let maxConfidence = 0;
195
+ let reasons: string[] = [];
196
+
197
+ for (const existing of existingMemories) {
198
+ // Skip already superseded memories
199
+ if (existing.status === 'superseded' || existing.status === 'merged') {
200
+ continue;
201
+ }
202
+
203
+ // Skip protected memories
204
+ if (existing.isProtected) {
205
+ continue;
206
+ }
207
+
208
+ const existingSubject = extractSubject(existing.content);
209
+ const similarity = calculateSimilarity(check.newContent, existing.content);
210
+ const subjectSimilarity = calculateSimilarity(newSubject, existingSubject);
211
+
212
+ // Check for entity overlap
213
+ const existingEntities = extractKeyEntities(existing.content);
214
+ const entityOverlap = newEntities.filter(e =>
215
+ existingEntities.some(ee => ee.toLowerCase().includes(e.toLowerCase()) ||
216
+ e.toLowerCase().includes(ee.toLowerCase()))
217
+ );
218
+
219
+ // Calculate temporal relationship between memories
220
+ const temporalRelationship = calculateTemporalRelationship(
221
+ existing.validFrom,
222
+ existing.validTo,
223
+ new Date() // current time for new memory
224
+ );
225
+
226
+ // Detect contradiction scenarios with temporal awareness
227
+
228
+ // Scenario 1: High similarity with negation in new content
229
+ if (similarity > 0.5 && newHasNegation && subjectSimilarity > 0.4) {
230
+ // Adjust confidence based on temporal relevance
231
+ let temporalFactor = 1.0;
232
+ if (temporalRelationship === 'existing_is_newer') {
233
+ temporalFactor = 0.7; // Lower confidence if existing is newer
234
+ } else if (temporalRelationship === 'existing_is_older') {
235
+ temporalFactor = 1.2; // Higher confidence if existing is older
236
+ }
237
+
238
+ toSupersede.push(existing.id);
239
+ maxConfidence = Math.max(maxConfidence, similarity * 0.9 * temporalFactor);
240
+ reasons.push(`negation of similar content (${(similarity * 100).toFixed(0)}% similar)`);
241
+ continue;
242
+ }
243
+
244
+ // Scenario 2: Update indicator with overlapping subject
245
+ if (newHasUpdate && subjectSimilarity > 0.5) {
246
+ // Boost confidence for updates when existing is older
247
+ let temporalFactor = 1.0;
248
+ if (temporalRelationship === 'existing_is_older') {
249
+ temporalFactor = 1.3; // Higher confidence for updating older info
250
+ }
251
+
252
+ toSupersede.push(existing.id);
253
+ maxConfidence = Math.max(maxConfidence, subjectSimilarity * 0.85 * temporalFactor);
254
+ reasons.push(`update to existing information`);
255
+ continue;
256
+ }
257
+
258
+ // Scenario 3: Same type, high subject similarity, different conclusion
259
+ if (existing.type === check.newType && subjectSimilarity > 0.6) {
260
+ // Check if conclusions differ
261
+ const existingHasNegation = hasNegation(existing.content);
262
+
263
+ // XOR: one has negation, other doesn't
264
+ if (newHasNegation !== existingHasNegation) {
265
+ // Adjust confidence based on temporal relationship
266
+ let temporalFactor = 1.0;
267
+ if (temporalRelationship === 'existing_is_newer') {
268
+ temporalFactor = 0.8; // Lower confidence if contradicting newer info
269
+ } else if (temporalRelationship === 'existing_is_older') {
270
+ temporalFactor = 1.1; // Higher confidence if contradicting older info
271
+ }
272
+
273
+ toSupersede.push(existing.id);
274
+ maxConfidence = Math.max(maxConfidence, subjectSimilarity * 0.8 * temporalFactor);
275
+ reasons.push(`contradicting statement about same topic`);
276
+ continue;
277
+ }
278
+ }
279
+
280
+ // Scenario 4: Entity overlap with correction signals
281
+ if (entityOverlap.length >= 2 && similarity > 0.3) {
282
+ const correctionSignals = /\b(fixed|changed|updated|replaced|removed|added)\b/i.test(check.newContent);
283
+ if (correctionSignals) {
284
+ // Consider temporal relevance for corrections
285
+ let temporalFactor = 1.0;
286
+ if (temporalRelationship === 'existing_is_older') {
287
+ temporalFactor = 1.2; // Higher confidence for correcting older info
288
+ }
289
+
290
+ toSupersede.push(existing.id);
291
+ maxConfidence = Math.max(maxConfidence, 0.75 * temporalFactor);
292
+ reasons.push(`correction involving ${entityOverlap.slice(0, 2).join(', ')}`);
293
+ continue;
294
+ }
295
+ }
296
+
297
+ // Scenario 5: Very high similarity (near-duplicate) - supersede older
298
+ if (similarity > 0.85) {
299
+ // Prefer to supersede older memories with newer ones
300
+ let temporalFactor = 1.0;
301
+ if (temporalRelationship === 'existing_is_older') {
302
+ temporalFactor = 1.1; // Slight boost for superseding older
303
+ } else if (temporalRelationship === 'existing_is_newer') {
304
+ temporalFactor = 0.9; // Slight reduction for superseding newer
305
+ }
306
+
307
+ toSupersede.push(existing.id);
308
+ maxConfidence = Math.max(maxConfidence, similarity * temporalFactor);
309
+ reasons.push(`near-duplicate replacement`);
310
+ continue;
311
+ }
312
+
313
+ // Scenario 6: Temporal inconsistency - same subject but different time periods
314
+ if (subjectSimilarity > 0.7 && similarity > 0.4 &&
315
+ existing.validFrom && existing.validTo) {
316
+ // Check if temporal periods don't overlap reasonably
317
+ const newValidFrom = new Date(); // When we learned this
318
+ const newValidTo = null; // Open-ended by default
319
+
320
+ const hasTemporalConflict = checkTemporalPeriodConflict(
321
+ existing.validFrom, existing.validTo,
322
+ newValidFrom, newValidTo
323
+ );
324
+
325
+ if (hasTemporalConflict) {
326
+ toSupersede.push(existing.id);
327
+ maxConfidence = Math.max(maxConfidence, 0.8);
328
+ reasons.push(`temporal inconsistency with existing fact`);
329
+ continue;
330
+ }
331
+ }
332
+ }
333
+
334
+ if (toSupersede.length > 0) {
335
+ result.hasContradiction = true;
336
+ result.supersededMemories = [...new Set(toSupersede)]; // Dedupe
337
+ result.confidence = maxConfidence;
338
+ result.reason = reasons[0] || 'contradiction detected';
339
+ }
340
+
341
+ } catch (error) {
342
+ logger.error('Error detecting contradictions', error);
343
+ }
344
+
345
+ return result;
346
+ }
347
+
348
+ /**
349
+ * Apply supersession to memories - archive old ones and create associations
350
+ */
351
+ export async function applySupersession(
352
+ newMemoryId: string,
353
+ supersededIds: string[],
354
+ confidence: number
355
+ ): Promise<void> {
356
+ if (supersededIds.length === 0) return;
357
+
358
+ try {
359
+ const db = await getDb();
360
+ const schema = await getSchema();
361
+ const now = new Date();
362
+
363
+ // Update superseded memories
364
+ await (db as any)
365
+ .update(schema.memories)
366
+ .set({
367
+ status: 'superseded',
368
+ supersededBy: newMemoryId,
369
+ supersededAt: now,
370
+ updatedAt: now,
371
+ })
372
+ .where(inArray(schema.memories.id, supersededIds));
373
+
374
+ // Create associations for traceability
375
+ for (const oldId of supersededIds) {
376
+ await createAssociation(newMemoryId, oldId, 'supersedes', confidence);
377
+ }
378
+
379
+ logger.info('Applied supersession', {
380
+ newMemoryId,
381
+ supersededCount: supersededIds.length,
382
+ confidence,
383
+ });
384
+
385
+ } catch (error) {
386
+ logger.error('Error applying supersession', error);
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Check for temporal contradictions (facts that are no longer valid)
392
+ */
393
+ export async function checkTemporalContradictions(
394
+ content: string,
395
+ projectId?: string
396
+ ): Promise<string[]> {
397
+ const supersededIds: string[] = [];
398
+
399
+ try {
400
+ // Look for temporal update patterns
401
+ const temporalUpdates = content.match(
402
+ /\b(as of|starting|beginning|from now|effective)\s+(\d{4}|\w+\s+\d{1,2})/gi
403
+ );
404
+
405
+ if (!temporalUpdates || temporalUpdates.length === 0) {
406
+ return supersededIds;
407
+ }
408
+
409
+ const db = await getDb();
410
+ const schema = await getSchema();
411
+
412
+ // Find memories with overlapping subject but older validTo dates
413
+ const subject = extractSubject(content);
414
+
415
+ const whereClause = projectId
416
+ ? and(
417
+ eq(schema.memories.projectId, projectId),
418
+ eq(schema.memories.status, 'active')
419
+ )
420
+ : eq(schema.memories.status, 'active');
421
+
422
+ const candidates = await (db as any)
423
+ .select()
424
+ .from(schema.memories)
425
+ .where(whereClause)
426
+ .limit(50);
427
+
428
+ for (const candidate of candidates) {
429
+ const candidateSubject = extractSubject(candidate.content);
430
+ const similarity = calculateSimilarity(subject, candidateSubject);
431
+
432
+ if (similarity > 0.5 && candidate.validTo) {
433
+ const validToDate = new Date(candidate.validTo);
434
+ const now = new Date();
435
+
436
+ // If the candidate's validity period has passed
437
+ if (validToDate < now) {
438
+ supersededIds.push(candidate.id);
439
+ }
440
+ }
441
+ }
442
+
443
+ } catch (error) {
444
+ logger.error('Error checking temporal contradictions', error);
445
+ }
446
+
447
+ return supersededIds;
448
+ }
449
+
450
+ /**
451
+ * Integrated contradiction resolution for the write path
452
+ * Call this before storing a new memory
453
+ */
454
+ export async function resolveContradictions(
455
+ content: string,
456
+ type: string,
457
+ projectId?: string
458
+ ): Promise<{
459
+ shouldProceed: boolean;
460
+ supersededIds: string[];
461
+ confidence: number;
462
+ reason: string;
463
+ }> {
464
+ // Detect standard contradictions
465
+ const contradictionResult = await detectContradictions({
466
+ newContent: content,
467
+ newType: type,
468
+ projectId,
469
+ });
470
+
471
+ // Also check temporal contradictions
472
+ const temporalSuperseded = await checkTemporalContradictions(content, projectId);
473
+
474
+ // Combine results
475
+ const allSuperseded = [
476
+ ...new Set([
477
+ ...contradictionResult.supersededMemories,
478
+ ...temporalSuperseded,
479
+ ]),
480
+ ];
481
+
482
+ const maxConfidence = Math.max(
483
+ contradictionResult.confidence,
484
+ temporalSuperseded.length > 0 ? 0.7 : 0
485
+ );
486
+
487
+ return {
488
+ shouldProceed: true, // Always proceed, but track supersessions
489
+ supersededIds: allSuperseded,
490
+ confidence: maxConfidence,
491
+ reason: contradictionResult.reason ||
492
+ (temporalSuperseded.length > 0 ? 'temporal supersession' : ''),
493
+ };
494
+ }
@@ -0,0 +1,174 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { eq, and, sql } from 'drizzle-orm';
3
+ import { getDb } from '../../db/index.js';
4
+ import { getSchema } from '../../db/schema.js';
5
+ import { createDatabaseClient } from '../storage/database.js';
6
+ import { MemoryRecord } from './memories.js';
7
+ import { Conflict } from './conflict-detector.js';
8
+
9
+ export interface EditProposal {
10
+ id: string;
11
+ memoryId: string;
12
+ currentContent: string;
13
+ proposedContent: string;
14
+ reason: string;
15
+ conflictWarnings: string[];
16
+ status: 'pending' | 'approved' | 'rejected' | 'expired';
17
+ version: number;
18
+ createdAt: Date;
19
+ reviewedAt?: Date;
20
+ reviewNotes?: string;
21
+ }
22
+
23
+ export async function createEditProposal(
24
+ memoryId: string,
25
+ currentContent: string,
26
+ proposedContent: string,
27
+ reason: string,
28
+ userId?: string
29
+ ): Promise<EditProposal> {
30
+ const db = createDatabaseClient(await getDb());
31
+ const schema = await getSchema();
32
+ const { memoryEditProposals } = schema;
33
+
34
+ const proposalId = randomUUID();
35
+ const now = new Date();
36
+
37
+ await db.insert(memoryEditProposals).values({
38
+ id: proposalId,
39
+ memoryId,
40
+ currentContent,
41
+ proposedContent,
42
+ reason,
43
+ conflictWarnings: [],
44
+ status: 'pending',
45
+ version: 1,
46
+ createdAt: now,
47
+ userId,
48
+ });
49
+
50
+ // Run conflict detection
51
+ const conflicts = await detectConflicts(memoryId, proposedContent);
52
+ await db.update(memoryEditProposals)
53
+ .set({ conflictWarnings: conflicts })
54
+ .where(eq(memoryEditProposals.id, proposalId));
55
+
56
+ return {
57
+ id: proposalId,
58
+ memoryId,
59
+ currentContent,
60
+ proposedContent,
61
+ reason,
62
+ conflictWarnings: conflicts,
63
+ status: 'pending',
64
+ version: 1,
65
+ createdAt: now,
66
+ };
67
+ }
68
+
69
+ export async function approveEditProposal(proposalId: string): Promise<boolean> {
70
+ const db = createDatabaseClient(await getDb());
71
+ const schema = await getSchema();
72
+ const { memoryEditProposals, memories } = schema;
73
+
74
+ // Get proposal
75
+ const proposal = await db.select()
76
+ .from(memoryEditProposals)
77
+ .where(eq(memoryEditProposals.id, proposalId))
78
+ .limit(1);
79
+
80
+ if (proposal.length === 0) return false;
81
+
82
+ // Update memory content
83
+ await db.update(memories)
84
+ .set({
85
+ content: proposal[0].proposedContent,
86
+ version: sql`${memories.version} + 1`,
87
+ updatedAt: new Date()
88
+ })
89
+ .where(eq(memories.id, proposal[0].memoryId));
90
+
91
+ // Mark proposal as approved
92
+ await db.update(memoryEditProposals)
93
+ .set({ status: 'approved', reviewedAt: new Date() })
94
+ .where(eq(memoryEditProposals.id, proposalId));
95
+
96
+ return true;
97
+ }
98
+
99
+ export async function rejectEditProposal(proposalId: string, reviewNotes: string): Promise<boolean> {
100
+ const db = createDatabaseClient(await getDb());
101
+ const schema = await getSchema();
102
+ const { memoryEditProposals } = schema;
103
+
104
+ await db.update(memoryEditProposals)
105
+ .set({ status: 'rejected', reviewNotes, reviewedAt: new Date() })
106
+ .where(eq(memoryEditProposals.id, proposalId));
107
+
108
+ return true;
109
+ }
110
+
111
+ export async function detectConflicts(memoryId: string, proposedContent: string): Promise<string[]> {
112
+ const db = createDatabaseClient(await getDb());
113
+ const schema = await getSchema();
114
+ const { memories } = schema;
115
+
116
+ // Get current memory
117
+ const currentMemory = await db.select()
118
+ .from(memories)
119
+ .where(eq(memories.id, memoryId))
120
+ .limit(1);
121
+
122
+ if (currentMemory.length === 0) return [];
123
+
124
+ const conflicts: string[] = [];
125
+
126
+ // Check for temporal contradictions
127
+ if (currentMemory[0].validFrom && currentMemory[0].validTo) {
128
+ const now = new Date();
129
+ if (now < new Date(currentMemory[0].validFrom) || now > new Date(currentMemory[0].validTo)) {
130
+ conflicts.push('Current time is outside validity period');
131
+ }
132
+ }
133
+
134
+ // Check for semantic contradictions with other memories
135
+ const similarMemories = await db.select()
136
+ .from(memories)
137
+ .where(
138
+ and(
139
+ eq(memories.projectId, currentMemory[0].projectId),
140
+ sql`memories.id != ${memoryId}`,
141
+ sql`memories.content ILIKE ${proposedContent}`
142
+ )
143
+ )
144
+ .limit(5);
145
+
146
+ for (const memory of similarMemories) {
147
+ if (memory.id !== memoryId) {
148
+ conflicts.push(`Potential contradiction with memory ${memory.id}`);
149
+ }
150
+ }
151
+
152
+ return conflicts;
153
+ }
154
+
155
+ export async function getEditProposals(
156
+ memoryId?: string,
157
+ status?: 'pending' | 'approved' | 'rejected'
158
+ ): Promise<EditProposal[]> {
159
+ const db = createDatabaseClient(await getDb());
160
+ const schema = await getSchema();
161
+ const { memoryEditProposals } = schema;
162
+
163
+ let query = db.select().from(memoryEditProposals);
164
+
165
+ if (memoryId) {
166
+ query = query.where(eq(memoryEditProposals.memoryId, memoryId));
167
+ }
168
+ if (status) {
169
+ query = query.where(eq(memoryEditProposals.status, status));
170
+ }
171
+
172
+ const proposals = await query;
173
+ return proposals as EditProposal[];
174
+ }