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,406 @@
1
+ /**
2
+ * Places Module - Spatial memory organization
3
+ *
4
+ * Provides spatial "places" for memory organization:
5
+ * - Inbox: New memories, unprocessed
6
+ * - Ref: Reference, patterns, research
7
+ * - WIP: Active work, implementations
8
+ * - Sandbox: Experiments, tests
9
+ * - Board: Decisions, planning, roadmap
10
+ * - Sparks: Ideas, future concepts
11
+ * - Archive: Completed, historical
12
+ */
13
+
14
+ import { randomUUID } from 'crypto';
15
+ import { eq, and, isNull, desc } from 'drizzle-orm';
16
+ import { getDb } from '../../db/index.js';
17
+ import { getSchema } from '../../db/schema.js';
18
+ import { logger } from '../logger.js';
19
+
20
+ // Place types matching the 7 default places
21
+ export type PlaceType =
22
+ | 'inbox'
23
+ | 'ref'
24
+ | 'wip'
25
+ | 'sandbox'
26
+ | 'board'
27
+ | 'sparks'
28
+ | 'archive';
29
+
30
+ export interface Place {
31
+ id: string;
32
+ projectId: string;
33
+ name: string;
34
+ placeType: PlaceType;
35
+ parentId: string | null;
36
+ sortOrder: number;
37
+ positionX: number;
38
+ positionY: number;
39
+ description: string | null;
40
+ purpose: string | null;
41
+ memoryCount: number;
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ }
45
+
46
+ export interface PlaceCreateInput {
47
+ projectId: string;
48
+ name: string;
49
+ placeType: PlaceType;
50
+ parentId?: string | null;
51
+ sortOrder?: number;
52
+ description?: string;
53
+ purpose?: string;
54
+ }
55
+
56
+ export interface PlaceUpdateInput {
57
+ name?: string;
58
+ description?: string;
59
+ purpose?: string;
60
+ sortOrder?: number;
61
+ positionX?: number;
62
+ positionY?: number;
63
+ }
64
+
65
+ // Default places configuration
66
+ export const DEFAULT_PLACES: Omit<PlaceCreateInput, 'projectId'>[] = [
67
+ { name: 'Inbox', placeType: 'inbox', sortOrder: 0, description: 'New memories, unprocessed', purpose: 'Quick inbox for incoming memories' },
68
+ { name: 'Ref', placeType: 'ref', sortOrder: 1, description: 'Reference, patterns, research', purpose: 'Reference knowledge and learned patterns' },
69
+ { name: 'WIP', placeType: 'wip', sortOrder: 2, description: 'Active work, implementations', purpose: 'Active development and recent changes' },
70
+ { name: 'Sandbox', placeType: 'sandbox', sortOrder: 3, description: 'Experiments, tests', purpose: 'Testing and exploration results' },
71
+ { name: 'Board', placeType: 'board', sortOrder: 4, description: 'Decisions, planning, roadmap', purpose: 'Project direction and decisions' },
72
+ { name: 'Sparks', placeType: 'sparks', sortOrder: 5, description: 'Ideas, future concepts', purpose: 'Brainstorming and upcoming plans' },
73
+ { name: 'Archive', placeType: 'archive', sortOrder: 6, description: 'Completed, historical', purpose: 'Reference for completed work' },
74
+ ];
75
+
76
+ /**
77
+ * Create a new place
78
+ */
79
+ export async function createPlace(input: PlaceCreateInput): Promise<Place> {
80
+ const db = await getDb();
81
+ if (!db) {
82
+ throw new Error('Database unavailable');
83
+ }
84
+
85
+ const schema = await getSchema();
86
+ const sqliteDb = db as any;
87
+ const id = randomUUID();
88
+
89
+ // Check for duplicate
90
+ const existing = await sqliteDb.select()
91
+ .from(schema.places)
92
+ .where(and(
93
+ eq(schema.places.projectId, input.projectId),
94
+ eq(schema.places.name, input.name),
95
+ input.parentId
96
+ ? eq(schema.places.parentId, input.parentId)
97
+ : isNull(schema.places.parentId)
98
+ ))
99
+ .limit(1);
100
+
101
+ if (existing.length > 0) {
102
+ throw new Error(`Place "${input.name}" already exists`);
103
+ }
104
+
105
+ await sqliteDb.insert(schema.places).values({
106
+ id,
107
+ projectId: input.projectId,
108
+ name: input.name,
109
+ placeType: input.placeType,
110
+ parentId: input.parentId || null,
111
+ sortOrder: input.sortOrder ?? 0,
112
+ positionX: 0,
113
+ positionY: 0,
114
+ description: input.description || null,
115
+ purpose: input.purpose || null,
116
+ memoryCount: 0,
117
+ });
118
+
119
+ logger.info(`[Places] Created place: ${input.name} (${input.placeType})`);
120
+
121
+ return {
122
+ id,
123
+ projectId: input.projectId,
124
+ name: input.name,
125
+ placeType: input.placeType,
126
+ parentId: input.parentId || null,
127
+ sortOrder: input.sortOrder ?? 0,
128
+ positionX: 0,
129
+ positionY: 0,
130
+ description: input.description || null,
131
+ purpose: input.purpose || null,
132
+ memoryCount: 0,
133
+ createdAt: new Date(),
134
+ updatedAt: new Date(),
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Get a place by ID
140
+ */
141
+ export async function getPlace(id: string): Promise<Place | null> {
142
+ const db = await getDb();
143
+ if (!db) return null;
144
+
145
+ const schema = await getSchema();
146
+ const sqliteDb = db as any;
147
+
148
+ const result = await sqliteDb.select()
149
+ .from(schema.places)
150
+ .where(eq(schema.places.id, id))
151
+ .limit(1);
152
+
153
+ if (result.length === 0) return null;
154
+
155
+ const row = result[0];
156
+ return {
157
+ id: row.id,
158
+ projectId: row.project_id,
159
+ name: row.name,
160
+ placeType: (row.place_type || row.placeType || 'custom') as PlaceType,
161
+ parentId: row.parent_id || row.parentId || null,
162
+ sortOrder: row.sort_order ?? row.sortOrder ?? 0,
163
+ positionX: row.position_x ?? row.positionX ?? 0,
164
+ positionY: row.position_y ?? row.positionY ?? 0,
165
+ description: row.description,
166
+ purpose: row.purpose,
167
+ memoryCount: row.memory_count ?? row.memoryCount ?? 0,
168
+ createdAt: new Date(row.created_at || row.createdAt || Date.now()),
169
+ updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
170
+ };
171
+ }
172
+
173
+ /**
174
+ * Get places for a project, ordered by sort_order
175
+ */
176
+ export async function getProjectPlaces(projectId: string): Promise<Place[]> {
177
+ const db = await getDb();
178
+ if (!db) return [];
179
+
180
+ const schema = await getSchema();
181
+ const sqliteDb = db as any;
182
+
183
+ const results = await sqliteDb.select()
184
+ .from(schema.places)
185
+ .where(eq(schema.places.projectId, projectId))
186
+ .orderBy(schema.places.sortOrder);
187
+
188
+ return results.map((row: any) => ({
189
+ id: row.id,
190
+ projectId: row.project_id,
191
+ name: row.name,
192
+ placeType: (row.place_type || row.placeType) as PlaceType,
193
+ parentId: row.parent_id || row.parentId,
194
+ sortOrder: row.sort_order ?? row.sortOrder ?? 0,
195
+ positionX: row.position_x ?? row.positionX ?? 0,
196
+ positionY: row.position_y ?? row.positionY ?? 0,
197
+ description: row.description,
198
+ purpose: row.purpose,
199
+ memoryCount: row.memory_count ?? row.memoryCount ?? 0,
200
+ createdAt: new Date(row.created_at || row.createdAt),
201
+ updatedAt: new Date(row.updated_at || row.updatedAt),
202
+ }));
203
+ }
204
+
205
+ /**
206
+ * Get place by type for a project
207
+ */
208
+ export async function getPlaceByType(projectId: string, placeType: PlaceType): Promise<Place | null> {
209
+ const db = await getDb();
210
+ if (!db) return null;
211
+
212
+ const schema = await getSchema();
213
+ const sqliteDb = db as any;
214
+
215
+ const result = await sqliteDb.select()
216
+ .from(schema.places)
217
+ .where(and(
218
+ eq(schema.places.projectId, projectId),
219
+ eq(schema.places.placeType, placeType)
220
+ ))
221
+ .limit(1);
222
+
223
+ if (result.length === 0) return null;
224
+
225
+ const row = result[0];
226
+ return {
227
+ id: row.id,
228
+ projectId: row.project_id,
229
+ name: row.name,
230
+ placeType: (row.place_type || row.placeType || 'custom') as PlaceType,
231
+ parentId: row.parent_id || row.parentId || null,
232
+ sortOrder: row.sort_order ?? row.sortOrder ?? 0,
233
+ positionX: row.position_x ?? row.positionX ?? 0,
234
+ positionY: row.position_y ?? row.positionY ?? 0,
235
+ description: row.description,
236
+ purpose: row.purpose,
237
+ memoryCount: row.memory_count ?? row.memoryCount ?? 0,
238
+ createdAt: new Date(row.created_at || row.createdAt || Date.now()),
239
+ updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
240
+ };
241
+ }
242
+
243
+ /**
244
+ * Update a place
245
+ */
246
+ export async function updatePlace(id: string, input: PlaceUpdateInput): Promise<Place | null> {
247
+ const db = await getDb();
248
+ if (!db) return null;
249
+
250
+ const schema = await getSchema();
251
+ const sqliteDb = db as any;
252
+
253
+ const updateData: any = {};
254
+ if (input.name !== undefined) updateData.name = input.name;
255
+ if (input.description !== undefined) updateData.description = input.description;
256
+ if (input.purpose !== undefined) updateData.purpose = input.purpose;
257
+ if (input.sortOrder !== undefined) updateData.sortOrder = input.sortOrder;
258
+ if (input.positionX !== undefined) updateData.positionX = input.positionX;
259
+ if (input.positionY !== undefined) updateData.positionY = input.positionY;
260
+
261
+ if (Object.keys(updateData).length === 0) {
262
+ return getPlace(id);
263
+ }
264
+
265
+ await sqliteDb.update(schema.places)
266
+ .set(updateData)
267
+ .where(eq(schema.places.id, id));
268
+
269
+ return getPlace(id);
270
+ }
271
+
272
+ /**
273
+ * Delete a place
274
+ */
275
+ export async function deletePlace(id: string): Promise<boolean> {
276
+ const db = await getDb();
277
+ if (!db) return false;
278
+
279
+ const schema = await getSchema();
280
+ const sqliteDb = db as any;
281
+
282
+ await sqliteDb.delete(schema.places).where(eq(schema.places.id, id));
283
+ logger.info(`[Places] Deleted place: ${id}`);
284
+
285
+ return true;
286
+ }
287
+
288
+ /**
289
+ * Initialize default 7 places for a project
290
+ */
291
+ export async function initializeDefaultPlaces(projectId: string): Promise<Place[]> {
292
+ const created: Place[] = [];
293
+
294
+ for (const placeConfig of DEFAULT_PLACES) {
295
+ // Check if place of this type already exists
296
+ const existing = await getPlaceByType(projectId, placeConfig.placeType);
297
+
298
+ if (existing) {
299
+ created.push(existing);
300
+ continue;
301
+ }
302
+
303
+ const place = await createPlace({
304
+ projectId,
305
+ name: placeConfig.name,
306
+ placeType: placeConfig.placeType,
307
+ parentId: null,
308
+ sortOrder: placeConfig.sortOrder,
309
+ description: placeConfig.description,
310
+ purpose: placeConfig.purpose,
311
+ });
312
+
313
+ created.push(place);
314
+ }
315
+
316
+ // Also initialize default rules if none exist
317
+ const { initializeDefaultRules } = await import('./rules.js');
318
+ await initializeDefaultRules(projectId);
319
+
320
+ logger.info(`[Places] Initialized ${created.length} default places for project: ${projectId}`);
321
+ return created;
322
+ }
323
+
324
+ /**
325
+ * Get place by loci index
326
+ */
327
+ export async function getPlaceByLociIndex(projectId: string, sortOrder: number): Promise<Place | null> {
328
+ const db = await getDb();
329
+ if (!db) return null;
330
+
331
+ const schema = await getSchema();
332
+ const sqliteDb = db as any;
333
+
334
+ const result = await sqliteDb.select()
335
+ .from(schema.places)
336
+ .where(and(
337
+ eq(schema.places.projectId, projectId),
338
+ eq(schema.places.sortOrder, sortOrder)
339
+ ))
340
+ .limit(1);
341
+
342
+ if (result.length === 0) return null;
343
+
344
+ const row = result[0];
345
+ return {
346
+ id: row.id,
347
+ projectId: row.project_id,
348
+ name: row.name,
349
+ placeType: (row.place_type || row.placeType || 'custom') as PlaceType,
350
+ parentId: row.parent_id || row.parentId || null,
351
+ sortOrder: row.sort_order ?? row.sortOrder ?? 0,
352
+ positionX: row.position_x ?? row.positionX ?? 0,
353
+ positionY: row.position_y ?? row.positionY ?? 0,
354
+ description: row.description,
355
+ purpose: row.purpose,
356
+ memoryCount: row.memory_count ?? row.memoryCount ?? 0,
357
+ createdAt: new Date(row.created_at || row.createdAt || Date.now()),
358
+ updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
359
+ };
360
+ }
361
+
362
+ /**
363
+ * Update memory count for a place
364
+ */
365
+ export async function updatePlaceMemoryCount(placeId: string): Promise<void> {
366
+ const db = await getDb();
367
+ if (!db) return;
368
+
369
+ const schema = await getSchema();
370
+ const sqliteDb = db as any;
371
+
372
+ // Count memories in this place
373
+ const countResult = await sqliteDb.select({ count: schema.memoryPlaces.id })
374
+ .from(schema.memoryPlaces)
375
+ .where(eq(schema.memoryPlaces.placeId, placeId));
376
+
377
+ const count = countResult.length;
378
+
379
+ await sqliteDb.update(schema.places)
380
+ .set({ memoryCount: count })
381
+ .where(eq(schema.places.id, placeId));
382
+ }
383
+
384
+ /**
385
+ * Sync all place memory counts - recalculate counts for all places in a project
386
+ * Useful for fixing counts after bulk operations or data recovery
387
+ */
388
+ export async function syncAllPlaceMemoryCounts(projectId: string): Promise<void> {
389
+ const db = await getDb();
390
+ if (!db) return;
391
+
392
+ const schema = await getSchema();
393
+ const sqliteDb = db as any;
394
+
395
+ // Get all places for this project
396
+ const allPlaces = await sqliteDb.select()
397
+ .from(schema.places)
398
+ .where(eq(schema.places.projectId, projectId));
399
+
400
+ // Update each place's memory count
401
+ for (const place of allPlaces) {
402
+ await updatePlaceMemoryCount(place.id);
403
+ }
404
+
405
+ logger.info(`[Places] Synced memory counts for ${allPlaces.length} places`);
406
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Places Rules Engine - Auto-assignment logic
3
+ *
4
+ * Evaluates which place a memory should be assigned to based on:
5
+ * - Tool used (Write, Edit, Task, etc.)
6
+ * - Content keywords
7
+ * - Tags
8
+ * - Memory type
9
+ */
10
+
11
+ import { randomUUID } from 'crypto';
12
+ import { eq, and, desc } from 'drizzle-orm';
13
+ import { getDb } from '../../db/index.js';
14
+ import { getSchema } from '../../db/schema.js';
15
+ import { logger } from '../logger.js';
16
+ import type { PlaceType } from './places.js';
17
+
18
+ export interface PlaceRule {
19
+ id: string;
20
+ projectId: string;
21
+ name: string;
22
+ placeType: PlaceType;
23
+ matchTool: string | null;
24
+ matchKeyword: string | null;
25
+ matchTag: string | null;
26
+ matchMemoryType: string | null;
27
+ priority: number;
28
+ enabled: boolean;
29
+ createdAt: Date;
30
+ updatedAt: Date;
31
+ }
32
+
33
+ export interface PlaceRuleCreateInput {
34
+ projectId: string;
35
+ name: string;
36
+ placeType: PlaceType;
37
+ matchTool?: string;
38
+ matchKeyword?: string;
39
+ matchTag?: string;
40
+ matchMemoryType?: string;
41
+ priority?: number;
42
+ enabled?: boolean;
43
+ }
44
+
45
+ export interface RuleMatchInput {
46
+ toolName?: string;
47
+ content?: string;
48
+ tags?: string[];
49
+ memoryType?: string;
50
+ }
51
+
52
+ /**
53
+ * Default auto-assignment rules
54
+ */
55
+ export const DEFAULT_RULES: Omit<PlaceRuleCreateInput, 'projectId'>[] = [
56
+ // WIP - Implementation, code, fixes
57
+ { name: 'Write to WIP', placeType: 'wip', matchTool: 'Write', priority: 100 },
58
+ { name: 'Edit to WIP', placeType: 'wip', matchTool: 'Edit', priority: 100 },
59
+ { name: 'MultiEdit to WIP', placeType: 'wip', matchTool: 'MultiEdit', priority: 100 },
60
+ { name: 'Fix keyword to WIP', placeType: 'wip', matchKeyword: 'fix', priority: 80 },
61
+ { name: 'Bug keyword to WIP', placeType: 'wip', matchKeyword: 'bug', priority: 80 },
62
+
63
+ // Sandbox - Experiments, tests
64
+ { name: 'Test to Sandbox', placeType: 'sandbox', matchTool: 'Bash', matchKeyword: 'test', priority: 90 },
65
+ { name: 'Test tag to Sandbox', placeType: 'sandbox', matchTag: 'test', priority: 85 },
66
+
67
+ // Board - Decisions, planning
68
+ { name: 'Task to Board', placeType: 'board', matchTool: 'Task', priority: 100 },
69
+ { name: 'TodoWrite to Board', placeType: 'board', matchTool: 'TodoWrite', priority: 100 },
70
+ { name: 'Decision keyword to Board', placeType: 'board', matchKeyword: 'decided', priority: 70 },
71
+ { name: 'Planning keyword to Board', placeType: 'board', matchKeyword: 'will implement', priority: 70 },
72
+
73
+ // Ref - Research, patterns
74
+ { name: 'Search to Ref', placeType: 'ref', matchTool: 'grep', priority: 90 },
75
+ { name: 'WebFetch to Ref', placeType: 'ref', matchTool: 'WebFetch', priority: 85 },
76
+ { name: 'Research keyword to Ref', placeType: 'ref', matchKeyword: 'research', priority: 80 },
77
+ { name: 'Pattern keyword to Ref', placeType: 'ref', matchKeyword: 'pattern', priority: 75 },
78
+
79
+ // Sparks - Ideas, future
80
+ { name: 'Idea keyword to Sparks', placeType: 'sparks', matchKeyword: 'idea', priority: 80 },
81
+ { name: 'Explore keyword to Sparks', placeType: 'sparks', matchKeyword: 'explore', priority: 75 },
82
+ { name: 'Future keyword to Sparks', placeType: 'sparks', matchKeyword: 'will add', priority: 70 },
83
+ ];
84
+
85
+ /**
86
+ * Create a place rule
87
+ */
88
+ export async function createPlaceRule(input: PlaceRuleCreateInput): Promise<PlaceRule> {
89
+ const db = await getDb();
90
+ if (!db) {
91
+ throw new Error('Database unavailable');
92
+ }
93
+
94
+ const schema = await getSchema();
95
+ const sqliteDb = db as any;
96
+ const id = randomUUID();
97
+
98
+ await sqliteDb.insert(schema.placeRules).values({
99
+ id,
100
+ projectId: input.projectId,
101
+ name: input.name,
102
+ placeType: input.placeType,
103
+ matchTool: input.matchTool || null,
104
+ matchKeyword: input.matchKeyword || null,
105
+ matchTag: input.matchTag || null,
106
+ matchMemoryType: input.matchMemoryType || null,
107
+ priority: input.priority ?? 0,
108
+ enabled: input.enabled !== false ? 1 : 0,
109
+ });
110
+
111
+ logger.info(`[PlaceRules] Created rule: ${input.name} -> ${input.placeType}`);
112
+
113
+ return {
114
+ id,
115
+ projectId: input.projectId,
116
+ name: input.name,
117
+ placeType: input.placeType,
118
+ matchTool: input.matchTool || null,
119
+ matchKeyword: input.matchKeyword || null,
120
+ matchTag: input.matchTag || null,
121
+ matchMemoryType: input.matchMemoryType || null,
122
+ priority: input.priority ?? 0,
123
+ enabled: input.enabled ?? true,
124
+ createdAt: new Date(),
125
+ updatedAt: new Date(),
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Get rules for a project
131
+ */
132
+ export async function getProjectRules(projectId: string): Promise<PlaceRule[]> {
133
+ const db = await getDb();
134
+ if (!db) return [];
135
+
136
+ const schema = await getSchema();
137
+ const sqliteDb = db as any;
138
+
139
+ const results = await sqliteDb.select()
140
+ .from(schema.placeRules)
141
+ .where(eq(schema.placeRules.projectId, projectId))
142
+ .orderBy(desc(schema.placeRules.priority));
143
+
144
+ return results.map((row: any) => ({
145
+ id: row.id,
146
+ projectId: row.project_id,
147
+ name: row.name,
148
+ placeType: (row.place_type || row.placeType || 'custom') as PlaceType,
149
+ matchTool: row.match_tool || row.matchTool,
150
+ matchKeyword: row.match_keyword || row.matchKeyword,
151
+ matchTag: row.match_tag || row.matchTag,
152
+ matchMemoryType: row.match_memory_type || row.matchMemoryType,
153
+ priority: row.priority ?? 0,
154
+ enabled: row.enabled === 1 || row.enabled === true,
155
+ createdAt: new Date(row.created_at || Date.now()),
156
+ updatedAt: new Date(row.updated_at || Date.now()),
157
+ }));
158
+ }
159
+
160
+ /**
161
+ * Check if a rule matches the input
162
+ */
163
+ export function matchesRule(rule: PlaceRule, input: RuleMatchInput): boolean {
164
+ // Check tool match
165
+ if (rule.matchTool && input.toolName) {
166
+ if (input.toolName.toLowerCase() !== rule.matchTool.toLowerCase()) {
167
+ return false;
168
+ }
169
+ }
170
+
171
+ // Check keyword match
172
+ if (rule.matchKeyword && input.content) {
173
+ const contentLower = input.content.toLowerCase();
174
+ if (!contentLower.includes(rule.matchKeyword.toLowerCase())) {
175
+ return false;
176
+ }
177
+ }
178
+
179
+ // Check tag match
180
+ if (rule.matchTag && input.tags) {
181
+ const hasTag = input.tags.some(t =>
182
+ t.toLowerCase() === rule.matchTag!.toLowerCase()
183
+ );
184
+ if (!hasTag) {
185
+ return false;
186
+ }
187
+ }
188
+
189
+ // Check memory type match
190
+ if (rule.matchMemoryType && input.memoryType) {
191
+ if (input.memoryType.toLowerCase() !== rule.matchMemoryType.toLowerCase()) {
192
+ return false;
193
+ }
194
+ }
195
+
196
+ return true;
197
+ }
198
+
199
+ /**
200
+ * Find matching place for a memory based on rules
201
+ */
202
+ export async function findMatchingPlace(
203
+ projectId: string,
204
+ input: RuleMatchInput
205
+ ): Promise<PlaceType | null> {
206
+ const rules = await getProjectRules(projectId);
207
+
208
+ // Sort by priority (highest first)
209
+ const sortedRules = rules
210
+ .filter(r => r.enabled)
211
+ .sort((a, b) => b.priority - a.priority);
212
+
213
+ for (const rule of sortedRules) {
214
+ if (matchesRule(rule, input)) {
215
+ logger.info(`[PlaceRules] Matched rule "${rule.name}" -> ${rule.placeType}`);
216
+ return rule.placeType;
217
+ }
218
+ }
219
+
220
+ return null;
221
+ }
222
+
223
+ /**
224
+ * Initialize default rules for a project
225
+ */
226
+ export async function initializeDefaultRules(projectId: string): Promise<PlaceRule[]> {
227
+ const created: PlaceRule[] = [];
228
+
229
+ for (const ruleConfig of DEFAULT_RULES) {
230
+ const rule = await createPlaceRule({
231
+ projectId,
232
+ ...ruleConfig,
233
+ });
234
+ created.push(rule);
235
+ }
236
+
237
+ logger.info(`[PlaceRules] Initialized ${created.length} default rules for project: ${projectId}`);
238
+ return created;
239
+ }
240
+
241
+ /**
242
+ * Delete a rule
243
+ */
244
+ export async function deletePlaceRule(id: string): Promise<boolean> {
245
+ const db = await getDb();
246
+ if (!db) return false;
247
+
248
+ const schema = await getSchema();
249
+ const sqliteDb = db as any;
250
+
251
+ await sqliteDb.delete(schema.placeRules).where(eq(schema.placeRules.id, id));
252
+ logger.info(`[PlaceRules] Deleted rule: ${id}`);
253
+
254
+ return true;
255
+ }
256
+
257
+ /**
258
+ * Update a rule
259
+ */
260
+ export async function updatePlaceRule(
261
+ id: string,
262
+ updates: Partial<PlaceRuleCreateInput>
263
+ ): Promise<PlaceRule | null> {
264
+ const db = await getDb();
265
+ if (!db) return null;
266
+
267
+ const schema = await getSchema();
268
+ const sqliteDb = db as any;
269
+
270
+ const updateData: any = {};
271
+ if (updates.name !== undefined) updateData.name = updates.name;
272
+ if (updates.placeType !== undefined) updateData.placeType = updates.placeType;
273
+ if (updates.matchTool !== undefined) updateData.matchTool = updates.matchTool;
274
+ if (updates.matchKeyword !== undefined) updateData.matchKeyword = updates.matchKeyword;
275
+ if (updates.matchTag !== undefined) updateData.matchTag = updates.matchTag;
276
+ if (updates.matchMemoryType !== undefined) updateData.matchMemoryType = updates.matchMemoryType;
277
+ if (updates.priority !== undefined) updateData.priority = updates.priority;
278
+ if (updates.enabled !== undefined) updateData.enabled = updates.enabled;
279
+
280
+ if (Object.keys(updateData).length === 0) return null;
281
+
282
+ await sqliteDb.update(schema.placeRules)
283
+ .set(updateData)
284
+ .where(eq(schema.placeRules.id, id));
285
+
286
+ const result = await sqliteDb.select()
287
+ .from(schema.placeRules)
288
+ .where(eq(schema.placeRules.id, id))
289
+ .limit(1);
290
+
291
+ if (result.length === 0) return null;
292
+
293
+ const row = result[0];
294
+ return {
295
+ id: row.id,
296
+ projectId: row.project_id,
297
+ name: row.name,
298
+ placeType: row.place_type as PlaceType,
299
+ matchTool: row.match_tool,
300
+ matchKeyword: row.match_keyword,
301
+ matchTag: row.match_tag,
302
+ matchMemoryType: row.match_memory_type,
303
+ priority: row.priority,
304
+ enabled: row.enabled === 1 || row.enabled === true,
305
+ createdAt: new Date(row.created_at),
306
+ updatedAt: new Date(row.updated_at),
307
+ };
308
+ }