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,653 @@
1
+ /**
2
+ * Agent Hooks - Core Logic
3
+ *
4
+ * Universal hooks for auto-capturing agent activities.
5
+ * Works with Claude Code, OpenCode, Cursor, Windsurf.
6
+ *
7
+ * Hook events:
8
+ * - sessionStart: Inject relevant memories on session start
9
+ * - postToolUse: Record observations after tool execution
10
+ * - sessionEnd: Save snapshot and sync learnings
11
+ * - preCompact: Save state before context compaction
12
+ */
13
+
14
+ import { randomUUID } from 'crypto';
15
+ import { createLearning, type LearningInput } from '../ingestion/learnings.js';
16
+ import { getRecent, search, rememberMemory } from '../memory/memories.js';
17
+ import { config } from '../../config.js';
18
+ import { logger } from '../logger.js';
19
+ import { shouldCaptureTool, categorizeTool } from './capture-filter.js';
20
+ import { inferTags } from './auto-tagger.js';
21
+ import { ensureProject, getProjectByPath } from '../projects.js';
22
+ import { autoAssignMemory, initializeDefaultPlaces } from '../places/index.js';
23
+ import { compressForContext } from '../compression.js';
24
+ import { getAgentPreferences } from '../agent-preferences.js';
25
+ import { classifySignalEvent, distillSignalEvent } from '../ingestion/signal-engine.js';
26
+ import { compactSessionWorkingSet, recordSessionSignal } from '../session/working-set.js';
27
+ import { getDbClient } from '../lib/db-client.js';
28
+ import { eq } from 'drizzle-orm';
29
+ import { serializeMetadata, deserializeMetadata } from '../memory/serialization.js';
30
+ import { addMemoryToGraph } from '../graph/graph-builder.js';
31
+ import { addToHotCache, addSessionContextToHotCache } from '../hot-cache.js';
32
+ import { extractBeliefsFromMemory } from '../beliefs/extractor.js';
33
+ import { upsertBeliefsForMemory, getRecentFailures, getActiveConstraints, getActiveDecisions } from '../beliefs/store.js';
34
+
35
+ /** Session ID for tracking across agents */
36
+ let currentSessionId: string | null = null;
37
+
38
+ /**
39
+ * Generate a new session ID (universal across agents)
40
+ */
41
+ export function generateSessionId(): string {
42
+ currentSessionId = randomUUID();
43
+ return currentSessionId;
44
+ }
45
+
46
+ /**
47
+ * Get current session ID
48
+ */
49
+ export function getCurrentSessionId(): string | null {
50
+ return currentSessionId;
51
+ }
52
+
53
+ /**
54
+ * Set session ID (for resume/continue)
55
+ */
56
+ export function setSessionId(sessionId: string): void {
57
+ currentSessionId = sessionId;
58
+ }
59
+
60
+ /**
61
+ * Session start hook - inject relevant context
62
+ */
63
+ export async function handleSessionStart(params: {
64
+ projectPath: string;
65
+ mode: 'startup' | 'resume' | 'compact';
66
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
67
+ }): Promise<{
68
+ memories: string[];
69
+ sessionId: string;
70
+ count: number;
71
+ preferences?: Array<{key: string; value: string}>;
72
+ beliefs?: {
73
+ failures: string[];
74
+ constraints: string[];
75
+ decisions: string[];
76
+ };
77
+ }> {
78
+ const { projectPath, mode, agentType } = params;
79
+
80
+ // Ensure project exists
81
+ await ensureProject(projectPath);
82
+
83
+ // Generate or get session ID
84
+ if (!currentSessionId) {
85
+ currentSessionId = generateSessionId();
86
+ }
87
+
88
+ logger.info(`[Hooks] Session start: ${mode} (agent: ${agentType}, session: ${currentSessionId})`);
89
+
90
+ // Get recent memories based on mode
91
+ const limit = mode === 'compact' ? 3 : 5;
92
+ const memories = await getRecent(projectPath, limit);
93
+ const compactedWorkingSet = await compactSessionWorkingSet(currentSessionId, projectPath);
94
+
95
+ // Get spatial memory context (places) for context injection
96
+ let placesContext = '';
97
+ try {
98
+ const { initializeDefaultPlaces, getProjectPlaces } = await import('../places/index.js');
99
+ const { getProjectByPath } = await import('../projects.js');
100
+ const project = await getProjectByPath(projectPath);
101
+ if (project) {
102
+ await initializeDefaultPlaces(project.id);
103
+ const places = await getProjectPlaces(project.id);
104
+ if (places.length > 0) {
105
+ const populatedPlaces = places.filter(p => p.memoryCount > 0).slice(0, 3);
106
+ if (populatedPlaces.length > 0) {
107
+ placesContext = '\n\nActive places: ' + populatedPlaces.map(p => `${p.name} (${p.memoryCount})`).join(', ');
108
+ }
109
+ }
110
+ }
111
+ } catch (e) {
112
+ // Don't fail if places not available
113
+ logger.debug(`[Hooks] Places context not available: ${e}`);
114
+ }
115
+
116
+ // Format for injection with compression
117
+ const formatted = memories.map((m, i) => {
118
+ const compressed = compressForContext(m.content || '');
119
+ return `${i + 1}. [${m.type}] ${compressed}`;
120
+ }).join('\n');
121
+
122
+ const workingSetContext = compactedWorkingSet.summary ? `Session working set:\n${compactedWorkingSet.summary}\n\n` : '';
123
+ const allContent = workingSetContext + formatted + placesContext;
124
+
125
+ // Get agent preferences for context injection
126
+ let preferences: Array<{key: string; value: string}> = [];
127
+ try {
128
+ const project = await getProjectByPath(projectPath);
129
+ if (project) {
130
+ preferences = await getAgentPreferences(project.id);
131
+
132
+ // Get beliefs for state reconstruction on session boot
133
+ // This is the "state reconstruction" - active beliefs shape next actions
134
+ const [failures, constraints, decisions] = await Promise.all([
135
+ getRecentFailures(project.id, 5),
136
+ getActiveConstraints(project.id, 10),
137
+ getActiveDecisions(project.id, 10),
138
+ ]);
139
+
140
+ // Format beliefs into context
141
+ const beliefsSection = formatBeliefsForContext(failures, constraints, decisions);
142
+
143
+ // Add beliefs to injected context
144
+ if (beliefsSection) {
145
+ allContent = beliefsSection + '\n\n' + allContent;
146
+ }
147
+
148
+ logger.info(`[Hooks] Injected ${failures.length} failures, ${constraints.length} constraints, ${decisions.length} decisions`);
149
+
150
+ return {
151
+ memories: allContent ? allContent.split('\n') : [],
152
+ sessionId: currentSessionId,
153
+ count: memories.length,
154
+ preferences: preferences.length > 0 ? preferences : undefined,
155
+ beliefs: {
156
+ failures: failures.map(f => f.statement),
157
+ constraints: constraints.map(c => c.statement),
158
+ decisions: decisions.map(d => d.statement),
159
+ },
160
+ };
161
+ }
162
+ } catch (e) {
163
+ logger.debug(`[Hooks] Agent preferences not available: ${e}`);
164
+ }
165
+
166
+ logger.info(`[Hooks] Injected ${memories.length} memories for session start`);
167
+
168
+ return {
169
+ memories: allContent ? allContent.split('\n') : [],
170
+ sessionId: currentSessionId,
171
+ count: memories.length,
172
+ preferences: preferences.length > 0 ? preferences : undefined,
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Format beliefs into context section for session boot
178
+ * This drives "state reconstruction" - agent sees active constraints/failures/decisions
179
+ */
180
+ function formatBeliefsForContext(
181
+ failures: Array<{statement: string; context?: string}>,
182
+ constraints: Array<{statement: string; context?: string}>,
183
+ decisions: Array<{statement: string; context?: string}>
184
+ ): string {
185
+ const sections: string[] = [];
186
+
187
+ if (failures.length > 0) {
188
+ sections.push('AVOID:\n' + failures.map((f, i) =>
189
+ ` ${i + 1}. ${f.statement}${f.context ? ` (${f.context})` : ''}`
190
+ ).join('\n'));
191
+ }
192
+
193
+ if (constraints.length > 0) {
194
+ sections.push('CONSTRAINTS:\n' + constraints.map((c, i) =>
195
+ ` ${i + 1}. ${c.statement}${c.context ? ` (${c.context})` : ''}`
196
+ ).join('\n'));
197
+ }
198
+
199
+ if (decisions.length > 0) {
200
+ sections.push('DECISIONS:\n' + decisions.map((d, i) =>
201
+ ` ${i + 1}. ${d.statement}${d.context ? ` (${d.context})` : ''}`
202
+ ).join('\n'));
203
+ }
204
+
205
+ if (sections.length === 0) return '';
206
+ return sections.join('\n\n');
207
+ }
208
+
209
+ /**
210
+ * Post-tool-use hook - record observations
211
+ */
212
+ export async function handlePostToolUse(params: {
213
+ toolName: string;
214
+ toolInput: Record<string, unknown>;
215
+ toolResult: unknown;
216
+ projectPath: string;
217
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
218
+ }): Promise<{
219
+ captured: boolean;
220
+ memoryId?: string;
221
+ reason?: string;
222
+ }> {
223
+ const { toolName, toolInput, toolResult, projectPath, agentType } = params;
224
+
225
+ // Ensure project exists
226
+ await ensureProject(projectPath);
227
+
228
+ // Ensure session ID exists
229
+ if (!currentSessionId) {
230
+ currentSessionId = generateSessionId();
231
+ }
232
+
233
+ // Check if we should capture this tool
234
+ if (!shouldCaptureTool(toolName)) {
235
+ await recordSessionSignal({
236
+ sessionId: currentSessionId,
237
+ projectPath,
238
+ classification: 'discard',
239
+ distilledContent: `Filtered tool: ${toolName}`,
240
+ toolName,
241
+ target: extractTarget(toolName, toolInput),
242
+ });
243
+ return { captured: false, reason: `Tool ${toolName} filtered out` };
244
+ }
245
+
246
+ // Extract relevant information
247
+ const category = categorizeTool(toolName);
248
+ const target = extractTarget(toolName, toolInput);
249
+ const content = extractContent(toolName, toolInput, toolResult);
250
+ const signalDecision = classifySignalEvent({
251
+ toolName,
252
+ toolInput,
253
+ toolResult,
254
+ sessionId: currentSessionId,
255
+ });
256
+ const distilledContent = distillSignalEvent({
257
+ toolName,
258
+ command: String(toolInput.command || toolInput.cmd || ''),
259
+ content: signalDecision.content || content,
260
+ classification: signalDecision.classification,
261
+ });
262
+
263
+ // Infer tags from context
264
+ const tags = inferTags(toolName, toolInput, distilledContent || content);
265
+
266
+ await recordSessionSignal({
267
+ sessionId: currentSessionId,
268
+ projectPath,
269
+ classification: signalDecision.classification,
270
+ distilledContent,
271
+ toolName,
272
+ target,
273
+ metadata: {
274
+ activeFiles: extractActiveFiles(toolName, toolInput),
275
+ command: String(toolInput.command || toolInput.cmd || ''),
276
+ outcome: inferOutcome(signalDecision, toolResult),
277
+ contentHash: signalDecision.contentHash,
278
+ tokensSaved: signalDecision.estimatedSavings,
279
+ activePlaces: signalDecision.placeHint.placeType ? [signalDecision.placeHint.placeType] : [],
280
+ graphEntities: signalDecision.graphHint.entityTerms,
281
+ placeRouted: Boolean(signalDecision.placeHint.placeType),
282
+ graphEnriched: signalDecision.graphHint.shouldEnrich,
283
+ },
284
+ });
285
+
286
+ if (signalDecision.classification === 'discard') {
287
+ return { captured: false, reason: signalDecision.reasons.join(', ') };
288
+ }
289
+
290
+ if (signalDecision.classification === 'session-only') {
291
+ return { captured: false, reason: 'Stored in session working set only' };
292
+ }
293
+
294
+ try {
295
+ const memory = await rememberMemory({
296
+ content: `[${category}] ${distilledContent || content}`,
297
+ project: projectPath,
298
+ type: category === 'modification' ? 'decision' : category === 'planning' ? 'context' : 'observation',
299
+ source: 'auto-capture',
300
+ metadata: {
301
+ signal: {
302
+ classification: signalDecision.classification,
303
+ reasons: signalDecision.reasons,
304
+ nuanceSuppressed: signalDecision.classification === 'durable-raw+distilled',
305
+ wakeUpPriority: signalDecision.wakeUpPriority,
306
+ },
307
+ placeHint: signalDecision.placeHint,
308
+ graphHint: signalDecision.graphHint,
309
+ target,
310
+ toolName,
311
+ },
312
+ });
313
+
314
+ logger.info(`[Hooks] Captured ${toolName} → ${memory.id} (session: ${currentSessionId})`);
315
+
316
+ let placeAssignment: { assigned: boolean; placeId?: string; placeType?: string } | undefined;
317
+ try {
318
+ const project = await getProjectByPath(projectPath);
319
+ if (project) {
320
+ await initializeDefaultPlaces(project.id);
321
+ placeAssignment = await autoAssignMemory({
322
+ memoryId: memory.id,
323
+ projectId: project.id,
324
+ toolName,
325
+ content: memory.content,
326
+ tags,
327
+ memoryType: memory.type,
328
+ });
329
+ }
330
+ } catch (placeError) {
331
+ logger.warn(`[Hooks] Place assignment failed: ${placeError}`);
332
+ }
333
+
334
+ let graphStatus: {
335
+ enriched: boolean;
336
+ entitiesCreated: number;
337
+ relationsCreated: number;
338
+ source: string;
339
+ entityTerms: string[];
340
+ } = {
341
+ enriched: false,
342
+ entitiesCreated: 0,
343
+ relationsCreated: 0,
344
+ source: 'none',
345
+ entityTerms: signalDecision.graphHint.entityTerms,
346
+ };
347
+
348
+ if (signalDecision.graphHint.shouldEnrich) {
349
+ try {
350
+ const graphResult = await addMemoryToGraph(memory.id, { preferLLM: true });
351
+ graphStatus = {
352
+ enriched: graphResult.entitiesCreated > 0 || graphResult.relationsCreated > 0,
353
+ entitiesCreated: graphResult.entitiesCreated,
354
+ relationsCreated: graphResult.relationsCreated,
355
+ source: graphResult.source,
356
+ entityTerms: signalDecision.graphHint.entityTerms,
357
+ };
358
+ } catch (graphError) {
359
+ logger.warn(`[Hooks] Graph enrichment failed: ${graphError}`);
360
+ }
361
+ }
362
+
363
+ let rawFallbackSnapshotId: string | undefined;
364
+ if (signalDecision.classification === 'durable-raw+distilled') {
365
+ rawFallbackSnapshotId = await attachRawFallbackSnapshot(memory.id, signalDecision.content, signalDecision.reasons);
366
+ }
367
+
368
+ await attachInspectionMetadata(memory.id, {
369
+ classification: signalDecision.classification,
370
+ reasons: signalDecision.reasons,
371
+ rawFallbackSnapshotId,
372
+ nuanceSuppressed: signalDecision.classification === 'durable-raw+distilled',
373
+ placeId: placeAssignment?.placeId,
374
+ placeType: placeAssignment?.placeType,
375
+ graph: graphStatus,
376
+ });
377
+
378
+ try {
379
+ const project = await getProjectByPath(projectPath);
380
+ if (project) {
381
+ const beliefs = extractBeliefsFromMemory({
382
+ memoryId: memory.id,
383
+ content: memory.content,
384
+ type: memory.type,
385
+ metadata: memory.metadata ?? null,
386
+ });
387
+ if (beliefs.length > 0) {
388
+ const storedBeliefs = await upsertBeliefsForMemory({
389
+ projectId: project.id,
390
+ memoryId: memory.id,
391
+ beliefs,
392
+ });
393
+ await attachBeliefInspectionMetadata(memory.id, storedBeliefs);
394
+ }
395
+ }
396
+ } catch (beliefError) {
397
+ logger.warn(`[Hooks] Belief extraction failed: ${beliefError}`);
398
+ }
399
+
400
+ return {
401
+ captured: true,
402
+ memoryId: memory.id,
403
+ };
404
+ } catch (error) {
405
+ logger.error(`[Hooks] Failed to capture:`, error);
406
+ return { captured: false, reason: 'Failed to create learning' };
407
+ }
408
+ }
409
+
410
+ async function attachRawFallbackSnapshot(memoryId: string, rawContent: string, reasons: string[]): Promise<string> {
411
+ const { db, schema } = await getDbClient();
412
+ const snapshotId = randomUUID();
413
+ await db.insert(schema.memorySnapshots).values({
414
+ id: snapshotId,
415
+ memoryId,
416
+ snapshotType: 'periodic',
417
+ content: rawContent,
418
+ metadata: serializeMetadata({
419
+ role: 'raw-fallback',
420
+ reasons,
421
+ createdBy: 'signal-engine',
422
+ }),
423
+ createdAt: new Date(),
424
+ });
425
+ return snapshotId;
426
+ }
427
+
428
+ async function attachInspectionMetadata(memoryId: string, signal: {
429
+ classification: string;
430
+ reasons: string[];
431
+ rawFallbackSnapshotId?: string;
432
+ nuanceSuppressed: boolean;
433
+ placeId?: string;
434
+ placeType?: string;
435
+ graph?: {
436
+ enriched: boolean;
437
+ entitiesCreated: number;
438
+ relationsCreated: number;
439
+ source: string;
440
+ entityTerms: string[];
441
+ };
442
+ }) {
443
+ const { db, schema } = await getDbClient();
444
+ const rows = await db.select().from(schema.memories).where(eq(schema.memories.id, memoryId)).limit(1);
445
+ const row = rows[0];
446
+ if (!row) return;
447
+ const details = deserializeMetadata(row.metadata ?? null) ?? {};
448
+ const next = {
449
+ ...details,
450
+ signal,
451
+ classification: signal.classification,
452
+ reasons: signal.reasons,
453
+ rawFallbackSnapshotId: signal.rawFallbackSnapshotId,
454
+ nuanceSuppressed: signal.nuanceSuppressed,
455
+ placeId: signal.placeId,
456
+ placeType: signal.placeType,
457
+ graph: signal.graph,
458
+ graphStatus: signal.graph
459
+ ? `${signal.graph.enriched ? 'enriched' : 'skipped'} (${signal.graph.entitiesCreated} entities, ${signal.graph.relationsCreated} relations)`
460
+ : 'none',
461
+ };
462
+ await db.update(schema.memories)
463
+ .set({ metadata: serializeMetadata(next), updatedAt: new Date() })
464
+ .where(eq(schema.memories.id, memoryId));
465
+ }
466
+
467
+ async function attachBeliefInspectionMetadata(memoryId: string, beliefs: Array<{
468
+ id: string;
469
+ type: string;
470
+ statement: string;
471
+ status: string;
472
+ confidence: number;
473
+ sourceMemoryIds: string[];
474
+ reason?: string;
475
+ }>) {
476
+ const { db, schema } = await getDbClient();
477
+ const rows = await db.select().from(schema.memories).where(eq(schema.memories.id, memoryId)).limit(1);
478
+ const row = rows[0];
479
+ if (!row) return;
480
+ const details = deserializeMetadata(row.metadata ?? null) ?? {};
481
+ const next = {
482
+ ...details,
483
+ beliefs: beliefs.map((belief) => ({
484
+ id: belief.id,
485
+ type: belief.type,
486
+ statement: belief.statement,
487
+ status: belief.status,
488
+ confidence: belief.confidence,
489
+ sourceMemoryIds: belief.sourceMemoryIds,
490
+ reason: belief.reason,
491
+ })),
492
+ };
493
+ await db.update(schema.memories)
494
+ .set({ metadata: serializeMetadata(next), updatedAt: new Date() })
495
+ .where(eq(schema.memories.id, memoryId));
496
+ }
497
+
498
+ function extractActiveFiles(toolName: string, toolInput: Record<string, unknown>): string[] {
499
+ const path = String(toolInput.filePath || toolInput.path || '');
500
+ if (['Write', 'Edit', 'MultiEdit'].includes(toolName) && path) {
501
+ return [path];
502
+ }
503
+ return [];
504
+ }
505
+
506
+ function inferOutcome(signalDecision: { classification: string }, toolResult: unknown): string | undefined {
507
+ const content = typeof toolResult === 'string' ? toolResult.toLowerCase() : String(toolResult ?? '').toLowerCase();
508
+ if (signalDecision.classification === 'discard') return 'suppressed';
509
+ if (/\bfail|error|exception|traceback\b/.test(content)) return 'failure';
510
+ if (/\bpass|success|completed\b/.test(content)) return 'success';
511
+ return undefined;
512
+ }
513
+
514
+ /**
515
+ * Session end hook - save snapshot and sync to persistent hot cache
516
+ */
517
+ export async function handleSessionEnd(params: {
518
+ projectPath: string;
519
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
520
+ workInProgress?: string;
521
+ }): Promise<{
522
+ snapshotId?: string;
523
+ memoriesSaved: number;
524
+ }> {
525
+ const { projectPath, agentType, workInProgress } = params;
526
+
527
+ // Ensure project exists
528
+ await ensureProject(projectPath);
529
+
530
+ logger.info(`[Hooks] Session end (agent: ${agentType}, session: ${currentSessionId})`);
531
+
532
+ // Save session snapshot as a learning
533
+ if (workInProgress) {
534
+ const snapshot = await createLearning({
535
+ type: 'insight',
536
+ content: `[SESSION SNAPSHOT] ${workInProgress}`,
537
+ action: 'session-end',
538
+ project: projectPath,
539
+ autoLink: false,
540
+ });
541
+
542
+ logger.info(`[Hooks] Saved session snapshot: ${snapshot.id}`);
543
+
544
+ // NEW: Also save to persistent hot cache (survives restart)
545
+ try {
546
+ const workingSet = await compactSessionWorkingSet(projectPath);
547
+ await addSessionContextToHotCache({
548
+ activeFiles: workingSet?.activeFiles || [],
549
+ commands: workingSet?.recentCommands?.slice(-3).map(c => c.command) || [],
550
+ failures: workingSet?.recentFailures?.slice(-2) || [],
551
+ decisions: [], // Could extract from recent signals
552
+ hypotheses: workingSet?.currentHypotheses?.slice(-2) || [],
553
+ }, projectPath);
554
+ logger.info('[Hooks] Saved session context to hot cache');
555
+ } catch (error) {
556
+ logger.warn('[Hooks] Failed to save hot cache', error);
557
+ }
558
+
559
+ currentSessionId = null; // Clear session
560
+
561
+ return {
562
+ snapshotId: snapshot.id,
563
+ memoriesSaved: 1,
564
+ };
565
+ }
566
+
567
+ currentSessionId = null;
568
+
569
+ return {
570
+ memoriesSaved: 0,
571
+ };
572
+ }
573
+
574
+ /**
575
+ * Pre-compact hook - save state for recovery
576
+ */
577
+ export async function handlePreCompact(params: {
578
+ projectPath: string;
579
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
580
+ }): Promise<{
581
+ stateSaved: boolean;
582
+ stateId?: string;
583
+ }> {
584
+ const { projectPath, agentType } = params;
585
+
586
+ // Ensure project exists
587
+ await ensureProject(projectPath);
588
+
589
+ logger.info(`[Hooks] Pre-compact (agent: ${agentType})`);
590
+
591
+ // Get recent work for recovery
592
+ const recent = await getRecent(projectPath, 3);
593
+
594
+ // Save state
595
+ const state = await createLearning({
596
+ type: 'insight',
597
+ content: `[PRE-COMPACT] State saved for recovery. Recent: ${recent.map(r => r.content?.substring(0, 50)).join(' | ')}`,
598
+ action: 'pre-compact',
599
+ project: projectPath,
600
+ autoLink: false,
601
+ });
602
+
603
+ return {
604
+ stateSaved: true,
605
+ stateId: state.id,
606
+ };
607
+ }
608
+
609
+ /**
610
+ * Extract target from tool input
611
+ */
612
+ function extractTarget(toolName: string, toolInput: Record<string, unknown>): string {
613
+ switch (toolName) {
614
+ case 'Write':
615
+ case 'Edit':
616
+ return String(toolInput.filePath || toolInput.path || 'unknown');
617
+ case 'Bash':
618
+ return String(toolInput.command || toolInput.cmd || 'unknown');
619
+ case 'Task':
620
+ return String(toolInput.description || toolInput.name || 'unknown');
621
+ default:
622
+ return 'unknown';
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Extract content summary from tool result
628
+ */
629
+ function extractContent(
630
+ toolName: string,
631
+ toolInput: Record<string, unknown>,
632
+ toolResult: unknown
633
+ ): string {
634
+ switch (toolName) {
635
+ case 'Write':
636
+ return `Wrote: ${toolInput.filePath || toolInput.path}`;
637
+ case 'Edit':
638
+ return `Edited: ${toolInput.filePath || toolInput.path}`;
639
+ case 'Bash':
640
+ const cmd = String(toolInput.command || toolInput.cmd || '');
641
+ if (cmd.includes('commit')) return `Git commit executed`;
642
+ if (cmd.includes('test')) return `Tests run`;
643
+ return `Command: ${cmd.substring(0, 50)}`;
644
+ case 'Task':
645
+ return `Task: ${toolInput.description || toolInput.name || 'unknown'}`;
646
+ default:
647
+ return `Used: ${toolName}`;
648
+ }
649
+ }
650
+
651
+ // Re-export for convenience
652
+ export { shouldCaptureTool, categorizeTool } from './capture-filter.js';
653
+ export { inferTags } from './auto-tagger.js';