squish-memory 1.0.2 → 1.1.5

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 (341) hide show
  1. package/.env.example +130 -0
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +150 -287
  4. package/config/hooks/claude-code-hooks.json +39 -0
  5. package/config/hooks/cursor-hooks.json +30 -0
  6. package/config/hooks/opencode-hooks.json +30 -0
  7. package/config/hooks/windsurf-hooks.json +30 -0
  8. package/config/mcp-mode-semantics.json +23 -21
  9. package/config/plugin-manifest.json +101 -152
  10. package/{plugin.json → config/plugin.json} +2 -2
  11. package/config/settings.json +52 -51
  12. package/{commands → core/commands}/init.md +39 -39
  13. package/dist/config.d.ts +28 -4
  14. package/dist/config.js +97 -29
  15. package/dist/core/adapters/config/claude-code.d.ts +45 -0
  16. package/dist/core/adapters/config/claude-code.js +113 -0
  17. package/dist/core/adapters/config/cursor.d.ts +26 -0
  18. package/dist/core/adapters/config/cursor.js +74 -0
  19. package/dist/core/adapters/config/opencode.d.ts +23 -0
  20. package/dist/core/adapters/config/opencode.js +73 -0
  21. package/dist/core/adapters/config/windsurf.d.ts +26 -0
  22. package/dist/core/adapters/config/windsurf.js +74 -0
  23. package/dist/core/adapters/index.d.ts +45 -0
  24. package/dist/core/adapters/index.js +84 -0
  25. package/dist/core/adapters/scripts/install-adapter.d.ts +19 -0
  26. package/dist/core/adapters/scripts/install-adapter.js +149 -0
  27. package/dist/core/adapters/timeline.d.ts +23 -0
  28. package/dist/core/adapters/timeline.js +88 -0
  29. package/dist/core/adapters/types.d.ts +157 -0
  30. package/dist/core/adapters/types.js +50 -0
  31. package/dist/{algorithms → core/algorithms}/analytics/token-estimator.d.ts +1 -1
  32. package/dist/{algorithms → core/algorithms}/analytics/token-estimator.js +3 -3
  33. package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.d.ts +1 -1
  34. package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.js +1 -1
  35. package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.d.ts +1 -1
  36. package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.js +7 -10
  37. package/dist/{algorithms → core/algorithms}/handlers/approve-merge.js +4 -4
  38. package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.js +3 -3
  39. package/dist/{algorithms → core/algorithms}/handlers/get-stats.js +3 -3
  40. package/dist/{algorithms → core/algorithms}/handlers/list-proposals.js +3 -3
  41. package/dist/{algorithms → core/algorithms}/handlers/preview-merge.js +3 -3
  42. package/dist/{algorithms → core/algorithms}/handlers/reject-merge.js +3 -3
  43. package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.js +3 -3
  44. package/dist/core/algorithms/index.d.ts +21 -0
  45. package/dist/core/algorithms/index.js +26 -0
  46. package/dist/core/algorithms/operations/cache-maintenance.d.ts +12 -0
  47. package/dist/core/algorithms/operations/cache-maintenance.js +157 -0
  48. package/dist/{algorithms → core/algorithms}/safety/safety-checks.d.ts +1 -1
  49. package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.d.ts +19 -1
  50. package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.js +74 -123
  51. package/dist/core/algorithms/types.d.ts +133 -0
  52. package/dist/core/algorithms/types.js +5 -0
  53. package/dist/core/associations.d.ts +1 -2
  54. package/dist/core/associations.js +1 -2
  55. package/dist/core/autosave.d.ts +19 -0
  56. package/dist/core/autosave.js +16 -0
  57. package/dist/{commands → core/commands}/managed-sync.js +5 -5
  58. package/dist/core/commands/mcp-server.js +739 -0
  59. package/dist/core/context/agent-context.d.ts +106 -0
  60. package/dist/core/context/agent-context.js +274 -0
  61. package/dist/core/{context-paging.d.ts → context/context-paging.d.ts} +2 -12
  62. package/dist/core/{context-paging.js → context/context-paging.js} +19 -39
  63. package/dist/core/context/context-window.d.ts +40 -0
  64. package/dist/core/context/context-window.js +177 -0
  65. package/dist/core/context/context.js +22 -0
  66. package/dist/core/embeddings.d.ts +1 -1
  67. package/dist/core/embeddings.js +54 -2
  68. package/dist/core/error-handling.d.ts +63 -0
  69. package/dist/core/error-handling.js +173 -0
  70. package/dist/core/external-folder/index.d.ts +102 -0
  71. package/dist/core/external-folder/index.js +294 -0
  72. package/dist/core/hooks/agent-hooks.d.ts +74 -0
  73. package/dist/core/hooks/agent-hooks.js +244 -0
  74. package/dist/core/hooks/auto-tagger.d.ts +19 -0
  75. package/dist/core/hooks/auto-tagger.js +155 -0
  76. package/dist/core/hooks/capture-filter.d.ts +41 -0
  77. package/dist/core/hooks/capture-filter.js +128 -0
  78. package/dist/core/index.d.ts +6 -6
  79. package/dist/core/index.js +6 -6
  80. package/dist/core/{agent-memory.js → ingestion/agent-memory.js} +5 -7
  81. package/dist/core/{core-memory.js → ingestion/core-memory.js} +4 -4
  82. package/dist/core/ingestion/learnings.d.ts +57 -0
  83. package/dist/core/ingestion/learnings.js +202 -0
  84. package/dist/core/lib/db-client.d.ts +114 -0
  85. package/dist/core/lib/db-client.js +130 -0
  86. package/dist/core/lib/schemas.d.ts +129 -0
  87. package/dist/core/lib/schemas.js +87 -0
  88. package/dist/core/{utils.d.ts → lib/utils.d.ts} +1 -0
  89. package/dist/core/{utils.js → lib/utils.js} +31 -15
  90. package/dist/core/lib/validation.d.ts +38 -0
  91. package/dist/core/lib/validation.js +151 -0
  92. package/dist/core/lifecycle.d.ts +7 -0
  93. package/dist/core/lifecycle.js +140 -20
  94. package/dist/core/local-embeddings.d.ts +6 -1
  95. package/dist/core/local-embeddings.js +6 -15
  96. package/dist/core/logger.js +7 -1
  97. package/dist/core/mcp/tools.js +35 -3
  98. package/dist/core/memory/categorizer.js +1 -0
  99. package/dist/core/memory/conflict-detector.js +1 -1
  100. package/dist/core/memory/consolidation.d.ts +1 -10
  101. package/dist/core/memory/consolidation.js +2 -11
  102. package/dist/core/memory/context-collector.js +1 -1
  103. package/dist/core/memory/edit-workflow.js +1 -1
  104. package/dist/core/memory/entity-resolver.js +7 -7
  105. package/dist/core/memory/fact-extractor.js +12 -12
  106. package/dist/core/memory/feedback-tracker.js +1 -1
  107. package/dist/core/memory/hooks.d.ts +88 -0
  108. package/dist/core/memory/hooks.js +174 -0
  109. package/dist/core/memory/hybrid-retrieval.js +2 -2
  110. package/dist/core/memory/hybrid-search.d.ts +1 -6
  111. package/dist/core/memory/hybrid-search.js +70 -84
  112. package/dist/core/memory/importance.d.ts +8 -13
  113. package/dist/core/memory/importance.js +47 -74
  114. package/dist/core/memory/loader.d.ts +31 -0
  115. package/dist/core/memory/loader.js +141 -0
  116. package/dist/core/memory/markdown/markdown-storage.d.ts +72 -0
  117. package/dist/core/memory/markdown/markdown-storage.js +243 -0
  118. package/dist/core/memory/memories.d.ts +12 -4
  119. package/dist/core/memory/memories.js +192 -180
  120. package/dist/core/memory/memory-lifecycle.d.ts +8 -0
  121. package/dist/core/memory/memory-lifecycle.js +55 -0
  122. package/dist/core/memory/migrate.d.ts +21 -0
  123. package/dist/core/memory/migrate.js +134 -0
  124. package/dist/core/memory/normalization.d.ts +22 -0
  125. package/dist/core/memory/normalization.js +26 -0
  126. package/dist/core/memory/progressive-disclosure.js +1 -1
  127. package/dist/core/memory/query-rewriter.js +9 -9
  128. package/dist/core/memory/serialization.d.ts +4 -0
  129. package/dist/core/memory/serialization.js +49 -0
  130. package/dist/core/memory/stats.d.ts +5 -0
  131. package/dist/core/memory/stats.js +63 -12
  132. package/dist/core/memory/temporal-facts.js +21 -0
  133. package/dist/core/memory/write-gate.js +1 -1
  134. package/dist/core/obsidian-vault.d.ts +30 -0
  135. package/dist/core/obsidian-vault.js +94 -0
  136. package/dist/core/places/index.d.ts +14 -0
  137. package/dist/core/places/index.js +14 -0
  138. package/dist/core/places/memory-places.d.ts +68 -0
  139. package/dist/core/places/memory-places.js +261 -0
  140. package/dist/core/places/places.d.ts +88 -0
  141. package/dist/core/places/places.js +314 -0
  142. package/dist/core/places/rules.d.ts +74 -0
  143. package/dist/core/places/rules.js +240 -0
  144. package/dist/core/places/walking.d.ts +56 -0
  145. package/dist/core/places/walking.js +121 -0
  146. package/dist/core/projects.d.ts +5 -0
  147. package/dist/core/projects.js +39 -18
  148. package/dist/core/responses.d.ts +96 -0
  149. package/dist/core/responses.js +122 -0
  150. package/dist/core/scheduler/cron-scheduler.js +29 -7
  151. package/dist/core/scheduler/index.d.ts +1 -1
  152. package/dist/core/scheduler/index.js +1 -1
  153. package/dist/core/scheduler/job-runner.js +1 -1
  154. package/dist/core/search/conversations.js +40 -42
  155. package/dist/core/search/entities.js +6 -9
  156. package/dist/core/search/graph-boost.d.ts +7 -0
  157. package/dist/core/search/graph-boost.js +23 -0
  158. package/dist/core/search/qmd-search.js +4 -4
  159. package/dist/core/security/encrypt.d.ts +6 -0
  160. package/dist/core/security/encrypt.js +47 -0
  161. package/dist/core/{governance.d.ts → security/governance.d.ts} +6 -1
  162. package/dist/core/security/governance.js +79 -0
  163. package/dist/core/session/auto-load.js +6 -6
  164. package/dist/core/session/index.d.ts +1 -1
  165. package/dist/core/session/index.js +1 -1
  166. package/dist/core/session/self-iteration-job.d.ts +20 -0
  167. package/dist/core/session/self-iteration-job.js +282 -0
  168. package/dist/core/session/session-hooks.d.ts +18 -0
  169. package/dist/core/session/session-hooks.js +58 -0
  170. package/dist/core/session-hooks/self-iteration-job.js +35 -35
  171. package/dist/core/{cache.js → storage/cache.js} +2 -2
  172. package/dist/core/sync/qmd-sync.d.ts +1 -13
  173. package/dist/core/sync/qmd-sync.js +1 -13
  174. package/dist/core/toon.d.ts +43 -0
  175. package/dist/core/toon.js +160 -0
  176. package/dist/core/utils/memory-operations.js +1 -1
  177. package/dist/core/utils/vector-operations.d.ts +71 -0
  178. package/dist/core/utils/vector-operations.js +129 -0
  179. package/dist/db/adapter.d.ts +3 -3
  180. package/dist/db/adapter.js +99 -88
  181. package/dist/db/bootstrap.js +820 -522
  182. package/dist/{drizzle → db/drizzle}/schema-sqlite.d.ts +74 -25
  183. package/dist/{drizzle → db/drizzle}/schema-sqlite.js +91 -24
  184. package/dist/{drizzle → db/drizzle}/schema.d.ts +79 -32
  185. package/dist/{drizzle → db/drizzle}/schema.js +106 -35
  186. package/dist/db/drizzle.config.d.ts +3 -0
  187. package/dist/db/drizzle.config.js +12 -0
  188. package/dist/db/index.d.ts +1 -5
  189. package/dist/db/index.js +51 -8
  190. package/dist/db/neon.d.ts +8 -0
  191. package/dist/db/neon.js +20 -0
  192. package/dist/db/schema/index.d.ts +40 -0
  193. package/dist/db/schema/index.js +105 -0
  194. package/dist/db/schema/tables/context-sessions.d.ts +9 -0
  195. package/dist/db/schema/tables/context-sessions.js +37 -0
  196. package/dist/db/schema/tables/conversations.d.ts +9 -0
  197. package/dist/db/schema/tables/conversations.js +47 -0
  198. package/dist/db/schema/tables/core-memory.d.ts +9 -0
  199. package/dist/db/schema/tables/core-memory.js +41 -0
  200. package/dist/db/schema/tables/entities.d.ts +9 -0
  201. package/dist/db/schema/tables/entities.js +39 -0
  202. package/dist/db/schema/tables/entity-relations.d.ts +9 -0
  203. package/dist/db/schema/tables/entity-relations.js +31 -0
  204. package/dist/db/schema/tables/learnings.d.ts +9 -0
  205. package/dist/db/schema/tables/learnings.js +66 -0
  206. package/dist/db/schema/tables/memories.d.ts +9 -0
  207. package/dist/db/schema/tables/memories.js +161 -0
  208. package/dist/db/schema/tables/memory-associations.d.ts +9 -0
  209. package/dist/db/schema/tables/memory-associations.js +39 -0
  210. package/dist/db/schema/tables/memory-hash-cache.d.ts +9 -0
  211. package/dist/db/schema/tables/memory-hash-cache.js +29 -0
  212. package/dist/db/schema/tables/memory-merge-history.d.ts +9 -0
  213. package/dist/db/schema/tables/memory-merge-history.js +33 -0
  214. package/dist/db/schema/tables/memory-merge-proposals.d.ts +9 -0
  215. package/dist/db/schema/tables/memory-merge-proposals.js +39 -0
  216. package/dist/db/schema/tables/messages.d.ts +9 -0
  217. package/dist/db/schema/tables/messages.js +41 -0
  218. package/dist/db/schema/tables/namespaces.d.ts +9 -0
  219. package/dist/db/schema/tables/namespaces.js +37 -0
  220. package/dist/db/schema/tables/projects.d.ts +9 -0
  221. package/dist/db/schema/tables/projects.js +31 -0
  222. package/dist/db/schema/tables/users.d.ts +9 -0
  223. package/dist/db/schema/tables/users.js +27 -0
  224. package/dist/db/schema.d.ts +1 -1
  225. package/dist/db/schema.js +2 -2
  226. package/dist/db/supabase.d.ts +9 -0
  227. package/dist/db/supabase.js +24 -0
  228. package/dist/index.d.ts +2 -14
  229. package/dist/index.js +1320 -640
  230. package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
  231. package/dist/webui/server.d.ts +5 -0
  232. package/dist/{api/web/web.js → webui/server.js} +511 -508
  233. package/generated/mcp/manifest.json +1 -1
  234. package/{.mcp.json → mcp.json.example} +1 -1
  235. package/package.json +159 -181
  236. package/scripts/README.md +60 -0
  237. package/scripts/copy-runtime-assets.mjs +26 -0
  238. package/scripts/generate-mcp.mjs +264 -264
  239. package/scripts/github-release.sh +4 -4
  240. package/scripts/install-claude-code.sh +85 -0
  241. package/scripts/install-cursor.sh +56 -0
  242. package/scripts/install-hooks.sh +73 -0
  243. package/scripts/install-interactive.mjs +357 -677
  244. package/scripts/install-opencode.sh +75 -0
  245. package/scripts/install-windsurf.sh +67 -0
  246. package/skills/squish-memory/SKILL.md +104 -114
  247. package/skills/squish-memory/{install.mjs → scripts/install.mjs} +2 -2
  248. package/skills/squish-memory/{install.sh → scripts/install.sh} +2 -2
  249. package/skills/squish-memory/write_skill.js +2 -0
  250. package/.claude-plugin/marketplace.json +0 -20
  251. package/.claude-plugin/plugin.json +0 -32
  252. package/.env.mcp.example +0 -60
  253. package/QUICK-START.md +0 -71
  254. package/bin/squish-add.mjs +0 -32
  255. package/bin/squish-rm.mjs +0 -21
  256. package/commands/observe.md +0 -5
  257. package/dist/api/web/index.d.ts +0 -3
  258. package/dist/api/web/index.js +0 -4
  259. package/dist/api/web/web-server.d.ts +0 -3
  260. package/dist/api/web/web-server.js +0 -6
  261. package/dist/api/web/web.d.ts +0 -4
  262. package/dist/commands/mcp-server.js +0 -393
  263. package/dist/core/context.js +0 -24
  264. package/dist/core/governance.js +0 -64
  265. package/dist/core/observations.d.ts +0 -26
  266. package/dist/core/observations.js +0 -110
  267. package/dist/core/requirements.d.ts +0 -20
  268. package/dist/core/requirements.js +0 -35
  269. package/hooks/hooks.json +0 -52
  270. package/hooks/post-tool-use.js +0 -26
  271. package/hooks/session-end.js +0 -28
  272. package/hooks/session-start.js +0 -33
  273. package/hooks/user-prompt-submit.js +0 -26
  274. package/hooks/utils.js +0 -153
  275. package/npx-installer.js +0 -208
  276. package/packages/plugin-claude-code/README.md +0 -73
  277. package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts +0 -35
  278. package/packages/plugin-claude-code/dist/plugin-wrapper.js +0 -191
  279. package/packages/plugin-claude-code/package.json +0 -31
  280. package/packages/plugin-openclaw/README.md +0 -70
  281. package/packages/plugin-openclaw/dist/index.d.ts +0 -49
  282. package/packages/plugin-openclaw/dist/index.js +0 -262
  283. package/packages/plugin-openclaw/openclaw.plugin.json +0 -94
  284. package/packages/plugin-openclaw/package.json +0 -31
  285. package/packages/plugin-opencode/install.mjs +0 -217
  286. package/packages/plugin-opencode/package.json +0 -21
  287. package/scripts/db/check-db.mjs +0 -88
  288. package/scripts/db/fix-all-columns.mjs +0 -52
  289. package/scripts/db/fix-schema-all.mjs +0 -55
  290. package/scripts/db/fix-schema-full.mjs +0 -46
  291. package/scripts/db/fix-schema.mjs +0 -38
  292. package/scripts/db/init-db.mjs +0 -13
  293. package/scripts/db/recreate-db.mjs +0 -14
  294. package/scripts/install-mcp.mjs +0 -116
  295. package/scripts/install-web.sh +0 -120
  296. package/scripts/install.mjs +0 -340
  297. package/scripts/openclaw-bootstrap.mjs +0 -127
  298. package/scripts/package-release.sh +0 -71
  299. package/scripts/test/test-all-systems.mjs +0 -139
  300. package/scripts/test/test-memory-system.mjs +0 -139
  301. package/scripts/test/test-v0.5.0.mjs +0 -210
  302. package/skills/memory-guide/SKILL.md +0 -332
  303. package/skills/squish-cli/SKILL.md +0 -240
  304. package/skills/squish-mcp/SKILL.md +0 -355
  305. package/skills/squish-memory/claude-desktop.json +0 -12
  306. package/skills/squish-memory/openclaw.json +0 -13
  307. package/skills/squish-memory/opencode.json +0 -14
  308. package/skills/squish-memory/skill.json +0 -32
  309. /package/{commands → core/commands}/context-paging.md +0 -0
  310. /package/{commands → core/commands}/context-status.md +0 -0
  311. /package/{commands → core/commands}/context.md +0 -0
  312. /package/{commands → core/commands}/core-memory.md +0 -0
  313. /package/{commands → core/commands}/health.md +0 -0
  314. /package/{commands → core/commands}/merge.md +0 -0
  315. /package/{commands → core/commands}/recall.md +0 -0
  316. /package/{commands → core/commands}/remember.md +0 -0
  317. /package/{commands → core/commands}/search.md +0 -0
  318. /package/dist/{algorithms → core/algorithms}/detection/hash-filters.d.ts +0 -0
  319. /package/dist/{algorithms → core/algorithms}/detection/hash-filters.js +0 -0
  320. /package/dist/{algorithms → core/algorithms}/handlers/approve-merge.d.ts +0 -0
  321. /package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.d.ts +0 -0
  322. /package/dist/{algorithms → core/algorithms}/handlers/get-stats.d.ts +0 -0
  323. /package/dist/{algorithms → core/algorithms}/handlers/list-proposals.d.ts +0 -0
  324. /package/dist/{algorithms → core/algorithms}/handlers/preview-merge.d.ts +0 -0
  325. /package/dist/{algorithms → core/algorithms}/handlers/reject-merge.d.ts +0 -0
  326. /package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.d.ts +0 -0
  327. /package/dist/{algorithms → core/algorithms}/safety/safety-checks.js +0 -0
  328. /package/dist/{algorithms → core/algorithms}/utils/response-builder.d.ts +0 -0
  329. /package/dist/{algorithms → core/algorithms}/utils/response-builder.js +0 -0
  330. /package/dist/{commands → core/commands}/managed-sync.d.ts +0 -0
  331. /package/dist/{commands → core/commands}/mcp-server.d.ts +0 -0
  332. /package/dist/core/{context.d.ts → context/context.d.ts} +0 -0
  333. /package/dist/core/{agent-memory.d.ts → ingestion/agent-memory.d.ts} +0 -0
  334. /package/dist/core/{core-memory.d.ts → ingestion/core-memory.d.ts} +0 -0
  335. /package/dist/core/{privacy.d.ts → security/privacy.d.ts} +0 -0
  336. /package/dist/core/{privacy.js → security/privacy.js} +0 -0
  337. /package/dist/core/{secret-detector.d.ts → security/secret-detector.d.ts} +0 -0
  338. /package/dist/core/{secret-detector.js → security/secret-detector.js} +0 -0
  339. /package/dist/core/{cache.d.ts → storage/cache.d.ts} +0 -0
  340. /package/dist/core/{database.d.ts → storage/database.d.ts} +0 -0
  341. /package/dist/core/{database.js → storage/database.js} +0 -0
@@ -3,28 +3,62 @@
3
3
  * Each type has different merge semantics to preserve meaning and prevent data loss.
4
4
  */
5
5
  /**
6
- * FACT strategy: Union of information, remove exact duplicates.
7
- * Combines all unique facts into a unified statement with provenance tracking.
6
+ * Base implementation of MergeStrategy with common functionality.
7
+ * Reduces code duplication across specific merge strategies.
8
8
  */
9
- class FactMergeStrategy {
10
- type = 'fact';
9
+ export class BaseMergeStrategy {
11
10
  canMerge(sources) {
12
- // Facts can almost always be merged
13
11
  if (sources.length < 2) {
14
12
  return { ok: false, reason: 'Need at least 2 memories to merge' };
15
13
  }
16
14
  return { ok: true };
17
15
  }
16
+ validateSources(sources) {
17
+ return sources.length >= 2;
18
+ }
19
+ handleEmptySources() {
20
+ return {
21
+ content: '',
22
+ summary: null,
23
+ tags: [],
24
+ metadata: {},
25
+ mergeReason: 'Empty source set',
26
+ conflictWarnings: [],
27
+ };
28
+ }
29
+ mergeTags(sources) {
30
+ const tagSet = new Set();
31
+ for (const source of sources) {
32
+ for (const tag of source.tags || []) {
33
+ tagSet.add(tag);
34
+ }
35
+ }
36
+ return Array.from(tagSet);
37
+ }
38
+ buildBaseMetadata(sources, extra) {
39
+ return {
40
+ mergedFrom: sources.map((m) => m.id),
41
+ mergeCount: sources.length,
42
+ ...extra,
43
+ };
44
+ }
45
+ sortByDate(sources, order = 'desc') {
46
+ const sorted = [...sources].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
47
+ return order === 'asc' ? [...sorted].reverse() : sorted;
48
+ }
49
+ sortChronologically(sources) {
50
+ return [...sources].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
51
+ }
52
+ }
53
+ /**
54
+ * FACT strategy: Union of information, remove exact duplicates.
55
+ * Combines all unique facts into a unified statement with provenance tracking.
56
+ */
57
+ class FactMergeStrategy extends BaseMergeStrategy {
58
+ type = 'fact';
18
59
  merge(sources) {
19
60
  if (sources.length === 0) {
20
- return {
21
- content: '',
22
- summary: null,
23
- tags: [],
24
- metadata: {},
25
- mergeReason: 'Empty source set',
26
- conflictWarnings: [],
27
- };
61
+ return this.handleEmptySources();
28
62
  }
29
63
  // Split content into sentences and deduplicate
30
64
  const sentenceSet = new Set();
@@ -45,27 +79,14 @@ class FactMergeStrategy {
45
79
  // Sort sentences for consistency
46
80
  const mergedSentences = Array.from(sentenceSet).sort();
47
81
  const content = mergedSentences.join('. ') + (mergedSentences.length > 0 ? '.' : '');
48
- // Merge tags (union)
49
- const tagSet = new Set();
50
- for (const source of sources) {
51
- for (const tag of source.tags || []) {
52
- tagSet.add(tag);
53
- }
54
- }
55
- // Create merged metadata with provenance
56
- const metadata = {
57
- mergedFrom: sources.map((m) => ({
58
- id: m.id,
59
- createdAt: m.createdAt,
60
- source: m.source,
61
- })),
62
- mergeCount: sources.length,
82
+ // Build merged metadata with provenance
83
+ const metadata = this.buildBaseMetadata(sources, {
63
84
  timestamps: timestamps.sort(),
64
- };
85
+ });
65
86
  return {
66
87
  content,
67
88
  summary: null,
68
- tags: Array.from(tagSet),
89
+ tags: this.mergeTags(sources),
69
90
  metadata,
70
91
  mergeReason: `Merged ${sources.length} facts by combining all unique statements`,
71
92
  conflictWarnings: [],
@@ -76,27 +97,14 @@ class FactMergeStrategy {
76
97
  * PREFERENCE strategy: Keep latest by timestamp, track evolution history.
77
98
  * Warns if preferences conflict, indicating user changed their mind.
78
99
  */
79
- class PreferenceMergeStrategy {
100
+ class PreferenceMergeStrategy extends BaseMergeStrategy {
80
101
  type = 'preference';
81
- canMerge(sources) {
82
- if (sources.length < 2) {
83
- return { ok: false, reason: 'Need at least 2 memories to merge' };
84
- }
85
- return { ok: true };
86
- }
87
102
  merge(sources) {
88
103
  if (sources.length === 0) {
89
- return {
90
- content: '',
91
- summary: null,
92
- tags: [],
93
- metadata: {},
94
- mergeReason: 'Empty source set',
95
- conflictWarnings: [],
96
- };
104
+ return this.handleEmptySources();
97
105
  }
98
106
  // Sort by creation date (newest first)
99
- const sorted = [...sources].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
107
+ const sorted = this.sortByDate(sources);
100
108
  const latest = sorted[0];
101
109
  const warnings = [];
102
110
  // Check for conflicting preferences
@@ -112,12 +120,10 @@ class PreferenceMergeStrategy {
112
120
  confidence: m.confidence || 100,
113
121
  source: m.source,
114
122
  }));
115
- const metadata = {
116
- mergedFrom: sources.map((m) => m.id),
123
+ const metadata = this.buildBaseMetadata(sources, {
117
124
  preferenceHistory: history,
118
- mergeCount: sources.length,
119
125
  latestAt: latest.createdAt,
120
- };
126
+ });
121
127
  const summary = sources.length > 1
122
128
  ? `Prefers: ${latest.content} (evolved from ${sources.length} preferences)`
123
129
  : null;
@@ -135,27 +141,14 @@ class PreferenceMergeStrategy {
135
141
  * DECISION strategy: Keep latest decision, link to previous ones in timeline.
136
142
  * Warns if decisions contradict, preserving rationale history.
137
143
  */
138
- class DecisionMergeStrategy {
144
+ class DecisionMergeStrategy extends BaseMergeStrategy {
139
145
  type = 'decision';
140
- canMerge(sources) {
141
- if (sources.length < 2) {
142
- return { ok: false, reason: 'Need at least 2 memories to merge' };
143
- }
144
- return { ok: true };
145
- }
146
146
  merge(sources) {
147
147
  if (sources.length === 0) {
148
- return {
149
- content: '',
150
- summary: null,
151
- tags: [],
152
- metadata: {},
153
- mergeReason: 'Empty source set',
154
- conflictWarnings: [],
155
- };
148
+ return this.handleEmptySources();
156
149
  }
157
150
  // Sort by creation date (newest first)
158
- const sorted = [...sources].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
151
+ const sorted = this.sortByDate(sources);
159
152
  const latest = sorted[0];
160
153
  const warnings = [];
161
154
  // Check for conflicting decisions
@@ -170,13 +163,11 @@ class DecisionMergeStrategy {
170
163
  confidence: m.confidence || 100,
171
164
  rationale: m.summary || 'No rationale recorded',
172
165
  }));
173
- const metadata = {
174
- mergedFrom: sources.map((m) => m.id),
166
+ const metadata = this.buildBaseMetadata(sources, {
175
167
  decisionTimeline: timeline,
176
- mergeCount: sources.length,
177
168
  currentDecisionAt: latest.createdAt,
178
169
  supersedes: sorted.slice(1).map((m) => m.id),
179
- };
170
+ });
180
171
  const summary = sources.length > 1 ? `Decided: ${latest.content} (${sources.length} decisions)` : null;
181
172
  return {
182
173
  content: latest.content,
@@ -192,31 +183,17 @@ class DecisionMergeStrategy {
192
183
  * OBSERVATION strategy: Aggregate observations in chronological order.
193
184
  * Preserves temporal patterns and frequency information.
194
185
  */
195
- class ObservationMergeStrategy {
186
+ class ObservationMergeStrategy extends BaseMergeStrategy {
196
187
  type = 'observation';
197
- canMerge(sources) {
198
- if (sources.length < 2) {
199
- return { ok: false, reason: 'Need at least 2 memories to merge' };
200
- }
201
- return { ok: true };
202
- }
203
188
  merge(sources) {
204
189
  if (sources.length === 0) {
205
- return {
206
- content: '',
207
- summary: null,
208
- tags: [],
209
- metadata: {},
210
- mergeReason: 'Empty source set',
211
- conflictWarnings: [],
212
- };
190
+ return this.handleEmptySources();
213
191
  }
214
192
  // Sort chronologically
215
- const sorted = [...sources].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
193
+ const sorted = this.sortChronologically(sources);
216
194
  // Create observation summary
217
195
  const observations = sorted.map((m) => `• ${m.content}`).join('\n');
218
- const metadata = {
219
- mergedFrom: sources.map((m) => m.id),
196
+ const metadata = this.buildBaseMetadata(sources, {
220
197
  observationCount: sources.length,
221
198
  timeSpan: {
222
199
  start: sorted[0].createdAt,
@@ -227,18 +204,11 @@ class ObservationMergeStrategy {
227
204
  content: m.content,
228
205
  createdAt: m.createdAt,
229
206
  })),
230
- };
231
- // Merge tags
232
- const tagSet = new Set();
233
- for (const source of sources) {
234
- for (const tag of source.tags || []) {
235
- tagSet.add(tag);
236
- }
237
- }
207
+ });
238
208
  return {
239
209
  content: `Observations (${sources.length} total):\n${observations}`,
240
210
  summary: `${sources.length} observations over time period`,
241
- tags: Array.from(tagSet),
211
+ tags: this.mergeTags(sources),
242
212
  metadata,
243
213
  mergeReason: `Merged ${sources.length} observations chronologically`,
244
214
  conflictWarnings: [],
@@ -249,24 +219,11 @@ class ObservationMergeStrategy {
249
219
  * CONTEXT strategy: Union of unique context, remove exact duplicates.
250
220
  * Preserves all distinct context items.
251
221
  */
252
- class ContextMergeStrategy {
222
+ class ContextMergeStrategy extends BaseMergeStrategy {
253
223
  type = 'context';
254
- canMerge(sources) {
255
- if (sources.length < 2) {
256
- return { ok: false, reason: 'Need at least 2 memories to merge' };
257
- }
258
- return { ok: true };
259
- }
260
224
  merge(sources) {
261
225
  if (sources.length === 0) {
262
- return {
263
- content: '',
264
- summary: null,
265
- tags: [],
266
- metadata: {},
267
- mergeReason: 'Empty source set',
268
- conflictWarnings: [],
269
- };
226
+ return this.handleEmptySources();
270
227
  }
271
228
  // Deduplicate by content (exact matches)
272
229
  const uniqueContexts = new Map();
@@ -280,23 +237,15 @@ class ContextMergeStrategy {
280
237
  .sort()
281
238
  .map((content) => `• ${content}`)
282
239
  .join('\n');
283
- const metadata = {
284
- mergedFrom: sources.map((m) => m.id),
240
+ const metadata = this.buildBaseMetadata(sources, {
285
241
  uniqueContextCount: uniqueContexts.size,
286
242
  totalContextCount: sources.length,
287
243
  deduplicatedEntries: sources.length - uniqueContexts.size,
288
- };
289
- // Merge tags
290
- const tagSet = new Set();
291
- for (const source of sources) {
292
- for (const tag of source.tags || []) {
293
- tagSet.add(tag);
294
- }
295
- }
244
+ });
296
245
  return {
297
246
  content: contextList,
298
247
  summary: `${uniqueContexts.size} context items (${sources.length} total)`,
299
- tags: Array.from(tagSet),
248
+ tags: this.mergeTags(sources),
300
249
  metadata,
301
250
  mergeReason: `Merged ${sources.length} context records into ${uniqueContexts.size} unique items`,
302
251
  conflictWarnings: [],
@@ -309,6 +258,8 @@ export const MERGE_STRATEGIES = {
309
258
  decision: new DecisionMergeStrategy(),
310
259
  observation: new ObservationMergeStrategy(),
311
260
  context: new ContextMergeStrategy(),
261
+ reflection: new ObservationMergeStrategy(),
262
+ note: new ObservationMergeStrategy(), // jot uses observation strategy
312
263
  };
313
264
  export function getMergeStrategy(type) {
314
265
  const strategy = MERGE_STRATEGIES[type];
@@ -0,0 +1,133 @@
1
+ /**
2
+ * TypeScript types and interfaces for memory merging
3
+ */
4
+ import type { Memory, MemoryMergeProposal } from '../../db/drizzle/schema.js';
5
+ /**
6
+ * Merge proposal status
7
+ */
8
+ export type MergeProposalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
9
+ /**
10
+ * Confidence level for merge suggestions
11
+ */
12
+ export type ConfidenceLevel = 'high' | 'medium' | 'low';
13
+ /**
14
+ * Detection method used to find duplicates
15
+ */
16
+ export type DetectionMethod = 'simhash' | 'minhash' | 'embedding';
17
+ /**
18
+ * Merge strategy type per memory type
19
+ */
20
+ export type MergeStrategyType = 'union' | 'latest' | 'voting' | 'custom';
21
+ /**
22
+ * Memory pair candidate for merging
23
+ */
24
+ export interface MemoryMergePair {
25
+ memory1: Memory;
26
+ memory2: Memory;
27
+ similarityScore: number;
28
+ detectionMethod: DetectionMethod;
29
+ confidenceLevel: ConfidenceLevel;
30
+ mergeReason: string;
31
+ }
32
+ /**
33
+ * Merge proposal with all details
34
+ */
35
+ export interface MergeProposalDetails {
36
+ proposal: MemoryMergeProposal;
37
+ sourceMemories: Memory[];
38
+ previewMerged: {
39
+ content: string;
40
+ summary: string | null;
41
+ tags: string[];
42
+ metadata: Record<string, unknown>;
43
+ };
44
+ analysis: {
45
+ savedTokens: number;
46
+ savedPercentage: number;
47
+ conflictWarnings: string[];
48
+ };
49
+ }
50
+ /**
51
+ * Merge result after approval
52
+ */
53
+ export interface MergeResult {
54
+ proposalId: string;
55
+ canonicalMemoryId: string;
56
+ mergedMemoryIds: string[];
57
+ tokensSaved: number;
58
+ mergedAt: Date;
59
+ mergeHistoryId?: string;
60
+ }
61
+ /**
62
+ * Merge reversal result
63
+ */
64
+ export interface MergeReversal {
65
+ mergeHistoryId: string;
66
+ canonicalMemoryId: string;
67
+ restoredMemoryIds: string[];
68
+ reversedAt: Date;
69
+ }
70
+ /**
71
+ * Detection statistics
72
+ */
73
+ export interface DetectionStatistics {
74
+ totalMemories: number;
75
+ scannedMemories: number;
76
+ candidatesFound: number;
77
+ candidatesRanked: number;
78
+ estimatedTokensSaved: number;
79
+ timeMs: {
80
+ stage1: number;
81
+ stage2: number;
82
+ total: number;
83
+ };
84
+ }
85
+ /**
86
+ * Project merge statistics
87
+ */
88
+ export interface ProjectMergeStatistics {
89
+ projectId: string;
90
+ totalMemories: number;
91
+ mergeableMemories: number;
92
+ mergedMemories: number;
93
+ canonicalMemories: number;
94
+ pendingProposals: number;
95
+ approvedMerges: number;
96
+ rejectedProposals: number;
97
+ reversedMerges: number;
98
+ tokensSaved: {
99
+ total: number;
100
+ formatted: string;
101
+ percentage: number;
102
+ };
103
+ averageMergeSize: number;
104
+ }
105
+ /**
106
+ * Merge safety check result
107
+ */
108
+ export interface SafetyCheckResult {
109
+ passed: boolean;
110
+ warnings: string[];
111
+ blockers: string[];
112
+ }
113
+ /**
114
+ * Hash cache entry for fast duplicate detection
115
+ */
116
+ export interface HashCacheEntry {
117
+ memoryId: string;
118
+ simhash: string;
119
+ minhash: number[];
120
+ contentHash: string;
121
+ lastUpdated: Date;
122
+ }
123
+ /**
124
+ * Stage 1 candidate pair with hash distances
125
+ */
126
+ export interface Stage1CandidatePair {
127
+ memoryId1: string;
128
+ memoryId2: string;
129
+ simhashDistance: number;
130
+ minhashSimilarity: number;
131
+ matched: 'simhash' | 'minhash' | 'both';
132
+ }
133
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TypeScript types and interfaces for memory merging
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -8,8 +8,7 @@ export type AssociationType = 'co_occurred' | 'supersedes' | 'contradicts' | 'su
8
8
  */
9
9
  export declare function createAssociation(fromMemoryId: string, toMemoryId: string, type: AssociationType, weight?: number): Promise<void>;
10
10
  /**
11
- * Track co-activation of multiple memories (they were used together)
12
- * OPTIMIZED: Uses bulk upsert instead of N² individual database operations
11
+ * Track co-activation of multiple memories (used together)
13
12
  */
14
13
  export declare function trackCoactivation(memoryIds: string[]): Promise<void>;
15
14
  /**
@@ -47,8 +47,7 @@ export async function createAssociation(fromMemoryId, toMemoryId, type, weight =
47
47
  }
48
48
  }
49
49
  /**
50
- * Track co-activation of multiple memories (they were used together)
51
- * OPTIMIZED: Uses bulk upsert instead of N² individual database operations
50
+ * Track co-activation of multiple memories (used together)
52
51
  */
53
52
  export async function trackCoactivation(memoryIds) {
54
53
  if (memoryIds.length < 2)
@@ -0,0 +1,19 @@
1
+ export declare function getDefaultAutosaveHook(): {
2
+ getMessageCount: () => number;
3
+ updateConfig: (opts?: {
4
+ enabled?: boolean;
5
+ messageCount?: number;
6
+ hooks?: string[];
7
+ }) => void;
8
+ getConfig: () => {
9
+ enabled: boolean;
10
+ messageCount: number;
11
+ hooks: string[];
12
+ };
13
+ };
14
+ export declare function createAutosaveConfig(): {
15
+ enabled: boolean;
16
+ messageCount: number;
17
+ hooks: string[];
18
+ };
19
+ //# sourceMappingURL=autosave.d.ts.map
@@ -0,0 +1,16 @@
1
+ // Autosave functionality placeholder
2
+ export function getDefaultAutosaveHook() {
3
+ let config = { enabled: false, messageCount: 10, hooks: [] };
4
+ return {
5
+ getMessageCount: () => 0,
6
+ updateConfig: (opts) => {
7
+ if (opts)
8
+ Object.assign(config, opts);
9
+ },
10
+ getConfig: () => ({ ...config })
11
+ };
12
+ }
13
+ export function createAutosaveConfig() {
14
+ return { enabled: false, messageCount: 10, hooks: [] };
15
+ }
16
+ //# sourceMappingURL=autosave.js.map
@@ -1,7 +1,7 @@
1
- import { MCPClient } from '../core/mcp/client.js';
2
- import { config } from '../config.js';
3
- import { logger } from '../core/logger.js';
4
- import { searchMemories, rememberMemory } from '../core/memory/memories.js';
1
+ import { MCPClient } from '../../core/mcp/client.js';
2
+ import { config } from '../../config.js';
3
+ import { logger } from '../../core/logger.js';
4
+ import { search, rememberMemory } from '../../core/memory/memories.js';
5
5
  export class ManagedSync {
6
6
  client;
7
7
  syncEnabled;
@@ -26,7 +26,7 @@ export class ManagedSync {
26
26
  if (!this.syncEnabled)
27
27
  return;
28
28
  try {
29
- const memory = await searchMemories({ query: memoryId, limit: 1 });
29
+ const memory = await search({ query: memoryId, limit: 1 });
30
30
  if (memory.length > 0) {
31
31
  await this.client.callTool('managed_memory_store', {
32
32
  memory: memory[0],