squish-memory 1.1.5 → 1.2.1

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 (646) 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 +44 -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/{dist/core/algorithms/index.js → core/algorithms/index.ts} +39 -26
  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/{dist/core/lib/db-client.d.ts → core/lib/db-client.ts} +168 -114
  81. package/core/lib/parse-embedding.ts +59 -0
  82. package/{dist/core/lib/schemas.js → core/lib/schemas.ts} +102 -87
  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/{dist/core/memory/index.js → core/memory/index.ts} +11 -10
  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/{dist/core/places/index.js → core/places/index.ts} +12 -12
  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 +590 -0
  140. package/core/scheduler/heartbeat.ts +91 -0
  141. package/{dist/core/scheduler/index.js → core/scheduler/index.ts} +8 -8
  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/{dist/core/search/index.js → core/search/index.ts} +4 -5
  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/{dist/core/session/index.js → core/session/index.ts} +7 -7
  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/{dist/core/snapshots/cleanup.js → core/snapshots/cleanup.ts} +13 -12
  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/{dist/core/summarization/cleanup.js → core/summarization/cleanup.ts} +13 -12
  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/{dist/core/utils/vector-operations.js → core/utils/vector-operations.ts} +135 -129
  185. package/core/utils/version-management.ts +74 -0
  186. package/core/worker.ts +333 -0
  187. package/db/adapter.ts +215 -0
  188. package/{dist/db/bootstrap.js → db/bootstrap.ts} +388 -418
  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/mcp.json.example +8 -11
  220. package/package.json +140 -159
  221. package/packages/cli/package.json +22 -0
  222. package/packages/cli/src/commands/clean.ts +68 -0
  223. package/packages/cli/src/commands/context.ts +79 -0
  224. package/packages/cli/src/commands/doctor.ts +357 -0
  225. package/packages/cli/src/commands/forget.ts +72 -0
  226. package/packages/cli/src/commands/health.ts +36 -0
  227. package/packages/cli/src/commands/inspect.ts +41 -0
  228. package/packages/cli/src/commands/link.ts +50 -0
  229. package/packages/cli/src/commands/migrate.ts +93 -0
  230. package/packages/cli/src/commands/recall.ts +99 -0
  231. package/packages/cli/src/commands/recent.ts +57 -0
  232. package/packages/cli/src/commands/remember.ts +139 -0
  233. package/packages/cli/src/commands/run.ts +58 -0
  234. package/packages/cli/src/commands/stale.ts +43 -0
  235. package/packages/cli/src/commands/stats.ts +42 -0
  236. package/packages/cli/src/index.ts +57 -0
  237. package/packages/cli/tsconfig.json +24 -0
  238. package/packages/mcp/package.json +26 -0
  239. package/packages/mcp/src/index.ts +940 -0
  240. package/packages/mcp/tsconfig.json +20 -0
  241. package/skills/squish-memory/SKILL.md +38 -35
  242. package/skills/squish-memory/{scripts/install.sh → install.sh} +1 -1
  243. package/skills/squish-memory/references/claude-desktop.json +12 -0
  244. package/skills/squish-memory/references/openclaw.json +13 -0
  245. package/skills/squish-memory/references/opencode.json +14 -0
  246. package/config/hooks/claude-code-hooks.json +0 -39
  247. package/config/hooks/cursor-hooks.json +0 -30
  248. package/config/hooks/opencode-hooks.json +0 -30
  249. package/config/hooks/windsurf-hooks.json +0 -30
  250. package/config/mcp-cli-fallback-policy.json +0 -22
  251. package/config/mcp.json +0 -38
  252. package/config/plugin-manifest.json +0 -101
  253. package/config/plugin-manifest.schema.json +0 -244
  254. package/config/plugin.json +0 -32
  255. package/config/remote-memory-policy.json +0 -32
  256. package/core/commands/context-paging.md +0 -51
  257. package/core/commands/context-status.md +0 -22
  258. package/core/commands/context.md +0 -5
  259. package/core/commands/core-memory.md +0 -56
  260. package/core/commands/health.md +0 -5
  261. package/core/commands/init.md +0 -39
  262. package/core/commands/merge.md +0 -113
  263. package/core/commands/recall.md +0 -5
  264. package/core/commands/remember.md +0 -11
  265. package/core/commands/search.md +0 -10
  266. package/dist/config.d.ts +0 -83
  267. package/dist/config.js +0 -242
  268. package/dist/core/adapters/config/claude-code.d.ts +0 -45
  269. package/dist/core/adapters/config/claude-code.js +0 -113
  270. package/dist/core/adapters/config/cursor.d.ts +0 -26
  271. package/dist/core/adapters/config/cursor.js +0 -74
  272. package/dist/core/adapters/config/opencode.d.ts +0 -23
  273. package/dist/core/adapters/config/opencode.js +0 -73
  274. package/dist/core/adapters/config/windsurf.d.ts +0 -26
  275. package/dist/core/adapters/config/windsurf.js +0 -74
  276. package/dist/core/adapters/index.d.ts +0 -45
  277. package/dist/core/adapters/index.js +0 -84
  278. package/dist/core/adapters/scripts/install-adapter.d.ts +0 -19
  279. package/dist/core/adapters/scripts/install-adapter.js +0 -149
  280. package/dist/core/adapters/timeline.d.ts +0 -23
  281. package/dist/core/adapters/timeline.js +0 -88
  282. package/dist/core/adapters/types.d.ts +0 -157
  283. package/dist/core/adapters/types.js +0 -50
  284. package/dist/core/algorithms/analytics/token-estimator.d.ts +0 -50
  285. package/dist/core/algorithms/analytics/token-estimator.js +0 -154
  286. package/dist/core/algorithms/detection/hash-filters.d.ts +0 -47
  287. package/dist/core/algorithms/detection/hash-filters.js +0 -190
  288. package/dist/core/algorithms/detection/semantic-ranker.d.ts +0 -32
  289. package/dist/core/algorithms/detection/semantic-ranker.js +0 -118
  290. package/dist/core/algorithms/detection/two-stage-detector.d.ts +0 -52
  291. package/dist/core/algorithms/detection/two-stage-detector.js +0 -299
  292. package/dist/core/algorithms/handlers/approve-merge.d.ts +0 -22
  293. package/dist/core/algorithms/handlers/approve-merge.js +0 -179
  294. package/dist/core/algorithms/handlers/detect-duplicates.d.ts +0 -47
  295. package/dist/core/algorithms/handlers/detect-duplicates.js +0 -145
  296. package/dist/core/algorithms/handlers/get-stats.d.ts +0 -39
  297. package/dist/core/algorithms/handlers/get-stats.js +0 -88
  298. package/dist/core/algorithms/handlers/list-proposals.d.ts +0 -45
  299. package/dist/core/algorithms/handlers/list-proposals.js +0 -83
  300. package/dist/core/algorithms/handlers/preview-merge.d.ts +0 -39
  301. package/dist/core/algorithms/handlers/preview-merge.js +0 -93
  302. package/dist/core/algorithms/handlers/reject-merge.d.ts +0 -28
  303. package/dist/core/algorithms/handlers/reject-merge.js +0 -69
  304. package/dist/core/algorithms/handlers/reverse-merge.d.ts +0 -21
  305. package/dist/core/algorithms/handlers/reverse-merge.js +0 -121
  306. package/dist/core/algorithms/index.d.ts +0 -21
  307. package/dist/core/algorithms/operations/cache-maintenance.d.ts +0 -12
  308. package/dist/core/algorithms/operations/cache-maintenance.js +0 -157
  309. package/dist/core/algorithms/safety/safety-checks.d.ts +0 -22
  310. package/dist/core/algorithms/safety/safety-checks.js +0 -179
  311. package/dist/core/algorithms/strategies/merge-strategies.d.ts +0 -50
  312. package/dist/core/algorithms/strategies/merge-strategies.js +0 -288
  313. package/dist/core/algorithms/types.d.ts +0 -133
  314. package/dist/core/algorithms/types.js +0 -5
  315. package/dist/core/algorithms/utils/response-builder.d.ts +0 -28
  316. package/dist/core/algorithms/utils/response-builder.js +0 -37
  317. package/dist/core/associations.d.ts +0 -31
  318. package/dist/core/associations.js +0 -248
  319. package/dist/core/autosave.d.ts +0 -19
  320. package/dist/core/autosave.js +0 -16
  321. package/dist/core/commands/managed-sync.d.ts +0 -10
  322. package/dist/core/commands/managed-sync.js +0 -64
  323. package/dist/core/commands/mcp-server.d.ts +0 -3
  324. package/dist/core/commands/mcp-server.js +0 -739
  325. package/dist/core/consolidation.d.ts +0 -37
  326. package/dist/core/consolidation.js +0 -248
  327. package/dist/core/context/agent-context.d.ts +0 -106
  328. package/dist/core/context/agent-context.js +0 -274
  329. package/dist/core/context/context-paging.d.ts +0 -80
  330. package/dist/core/context/context-paging.js +0 -328
  331. package/dist/core/context/context-window.d.ts +0 -40
  332. package/dist/core/context/context-window.js +0 -177
  333. package/dist/core/context/context.d.ts +0 -7
  334. package/dist/core/context/context.js +0 -22
  335. package/dist/core/embeddings/google-multimodal.d.ts +0 -14
  336. package/dist/core/embeddings/google-multimodal.js +0 -142
  337. package/dist/core/embeddings/qmd-client.d.ts +0 -136
  338. package/dist/core/embeddings/qmd-client.js +0 -403
  339. package/dist/core/embeddings.d.ts +0 -29
  340. package/dist/core/embeddings.js +0 -454
  341. package/dist/core/error-handling.d.ts +0 -63
  342. package/dist/core/error-handling.js +0 -173
  343. package/dist/core/external-folder/index.d.ts +0 -102
  344. package/dist/core/external-folder/index.js +0 -294
  345. package/dist/core/hooks/agent-hooks.d.ts +0 -74
  346. package/dist/core/hooks/agent-hooks.js +0 -244
  347. package/dist/core/hooks/auto-tagger.d.ts +0 -19
  348. package/dist/core/hooks/auto-tagger.js +0 -155
  349. package/dist/core/hooks/capture-filter.d.ts +0 -41
  350. package/dist/core/hooks/capture-filter.js +0 -128
  351. package/dist/core/index.d.ts +0 -10
  352. package/dist/core/index.js +0 -14
  353. package/dist/core/ingestion/agent-memory.d.ts +0 -22
  354. package/dist/core/ingestion/agent-memory.js +0 -109
  355. package/dist/core/ingestion/core-memory.d.ts +0 -78
  356. package/dist/core/ingestion/core-memory.js +0 -226
  357. package/dist/core/ingestion/learnings.d.ts +0 -57
  358. package/dist/core/ingestion/learnings.js +0 -202
  359. package/dist/core/layers/generator.d.ts +0 -25
  360. package/dist/core/layers/generator.js +0 -76
  361. package/dist/core/lib/db-client.js +0 -130
  362. package/dist/core/lib/schemas.d.ts +0 -129
  363. package/dist/core/lib/utils.d.ts +0 -14
  364. package/dist/core/lib/utils.js +0 -90
  365. package/dist/core/lib/validation.d.ts +0 -38
  366. package/dist/core/lib/validation.js +0 -151
  367. package/dist/core/lifecycle.d.ts +0 -26
  368. package/dist/core/lifecycle.js +0 -302
  369. package/dist/core/local-embeddings.d.ts +0 -11
  370. package/dist/core/logger.d.ts +0 -16
  371. package/dist/core/logger.js +0 -40
  372. package/dist/core/mcp/client.d.ts +0 -17
  373. package/dist/core/mcp/client.js +0 -101
  374. package/dist/core/mcp/index.d.ts +0 -6
  375. package/dist/core/mcp/index.js +0 -6
  376. package/dist/core/mcp/server.d.ts +0 -18
  377. package/dist/core/mcp/server.js +0 -157
  378. package/dist/core/mcp/standalone-server.d.ts +0 -13
  379. package/dist/core/mcp/standalone-server.js +0 -46
  380. package/dist/core/mcp/tools.d.ts +0 -9
  381. package/dist/core/mcp/tools.js +0 -365
  382. package/dist/core/mcp/types.d.ts +0 -315
  383. package/dist/core/mcp/types.js +0 -48
  384. package/dist/core/memory/bridge-discovery.d.ts +0 -50
  385. package/dist/core/memory/bridge-discovery.js +0 -291
  386. package/dist/core/memory/categorizer.d.ts +0 -27
  387. package/dist/core/memory/categorizer.js +0 -305
  388. package/dist/core/memory/conflict-detector.d.ts +0 -7
  389. package/dist/core/memory/conflict-detector.js +0 -43
  390. package/dist/core/memory/consolidation.d.ts +0 -42
  391. package/dist/core/memory/consolidation.js +0 -303
  392. package/dist/core/memory/context-collector.d.ts +0 -10
  393. package/dist/core/memory/context-collector.js +0 -56
  394. package/dist/core/memory/contradiction-resolver.d.ts +0 -40
  395. package/dist/core/memory/contradiction-resolver.js +0 -368
  396. package/dist/core/memory/edit-workflow.d.ts +0 -19
  397. package/dist/core/memory/edit-workflow.js +0 -120
  398. package/dist/core/memory/entity-extractor.d.ts +0 -33
  399. package/dist/core/memory/entity-extractor.js +0 -336
  400. package/dist/core/memory/entity-resolver.d.ts +0 -23
  401. package/dist/core/memory/entity-resolver.js +0 -64
  402. package/dist/core/memory/fact-extractor.d.ts +0 -24
  403. package/dist/core/memory/fact-extractor.js +0 -89
  404. package/dist/core/memory/feedback-tracker.d.ts +0 -12
  405. package/dist/core/memory/feedback-tracker.js +0 -155
  406. package/dist/core/memory/hooks.d.ts +0 -88
  407. package/dist/core/memory/hooks.js +0 -174
  408. package/dist/core/memory/hybrid-retrieval.d.ts +0 -29
  409. package/dist/core/memory/hybrid-retrieval.js +0 -139
  410. package/dist/core/memory/hybrid-scorer.d.ts +0 -40
  411. package/dist/core/memory/hybrid-scorer.js +0 -284
  412. package/dist/core/memory/hybrid-search.d.ts +0 -20
  413. package/dist/core/memory/hybrid-search.js +0 -359
  414. package/dist/core/memory/importance.d.ts +0 -63
  415. package/dist/core/memory/importance.js +0 -298
  416. package/dist/core/memory/index.d.ts +0 -8
  417. package/dist/core/memory/loader.d.ts +0 -31
  418. package/dist/core/memory/loader.js +0 -141
  419. package/dist/core/memory/markdown/markdown-storage.d.ts +0 -72
  420. package/dist/core/memory/markdown/markdown-storage.js +0 -243
  421. package/dist/core/memory/memories.d.ts +0 -47
  422. package/dist/core/memory/memories.js +0 -449
  423. package/dist/core/memory/memory-lifecycle.d.ts +0 -8
  424. package/dist/core/memory/memory-lifecycle.js +0 -55
  425. package/dist/core/memory/memory-manager.d.ts +0 -15
  426. package/dist/core/memory/memory-manager.js +0 -46
  427. package/dist/core/memory/migrate.d.ts +0 -21
  428. package/dist/core/memory/migrate.js +0 -134
  429. package/dist/core/memory/normalization.d.ts +0 -22
  430. package/dist/core/memory/normalization.js +0 -26
  431. package/dist/core/memory/progressive-disclosure.d.ts +0 -43
  432. package/dist/core/memory/progressive-disclosure.js +0 -280
  433. package/dist/core/memory/query-processor.d.ts +0 -21
  434. package/dist/core/memory/query-processor.js +0 -72
  435. package/dist/core/memory/query-rewriter.d.ts +0 -13
  436. package/dist/core/memory/query-rewriter.js +0 -118
  437. package/dist/core/memory/response-analyzer.d.ts +0 -9
  438. package/dist/core/memory/response-analyzer.js +0 -61
  439. package/dist/core/memory/serialization.d.ts +0 -10
  440. package/dist/core/memory/serialization.js +0 -84
  441. package/dist/core/memory/stats.d.ts +0 -22
  442. package/dist/core/memory/stats.js +0 -138
  443. package/dist/core/memory/telemetry.d.ts +0 -69
  444. package/dist/core/memory/telemetry.js +0 -313
  445. package/dist/core/memory/temporal-facts.d.ts +0 -41
  446. package/dist/core/memory/temporal-facts.js +0 -283
  447. package/dist/core/memory/temporal-parser.d.ts +0 -32
  448. package/dist/core/memory/temporal-parser.js +0 -385
  449. package/dist/core/memory/trigger-detector.d.ts +0 -14
  450. package/dist/core/memory/trigger-detector.js +0 -42
  451. package/dist/core/memory/write-gate.d.ts +0 -54
  452. package/dist/core/memory/write-gate.js +0 -210
  453. package/dist/core/namespaces/index.d.ts +0 -71
  454. package/dist/core/namespaces/index.js +0 -305
  455. package/dist/core/namespaces/uri-parser.d.ts +0 -31
  456. package/dist/core/namespaces/uri-parser.js +0 -74
  457. package/dist/core/obsidian-vault.d.ts +0 -30
  458. package/dist/core/obsidian-vault.js +0 -94
  459. package/dist/core/places/index.d.ts +0 -14
  460. package/dist/core/places/memory-places.d.ts +0 -68
  461. package/dist/core/places/memory-places.js +0 -261
  462. package/dist/core/places/places.d.ts +0 -88
  463. package/dist/core/places/places.js +0 -314
  464. package/dist/core/places/rules.d.ts +0 -74
  465. package/dist/core/places/rules.js +0 -240
  466. package/dist/core/places/walking.d.ts +0 -56
  467. package/dist/core/places/walking.js +0 -121
  468. package/dist/core/projects.d.ts +0 -17
  469. package/dist/core/projects.js +0 -108
  470. package/dist/core/redis.d.ts +0 -11
  471. package/dist/core/redis.js +0 -69
  472. package/dist/core/responses.d.ts +0 -96
  473. package/dist/core/responses.js +0 -122
  474. package/dist/core/scheduler/cron-scheduler.d.ts +0 -32
  475. package/dist/core/scheduler/cron-scheduler.js +0 -332
  476. package/dist/core/scheduler/heartbeat.d.ts +0 -11
  477. package/dist/core/scheduler/heartbeat.js +0 -73
  478. package/dist/core/scheduler/index.d.ts +0 -8
  479. package/dist/core/scheduler/job-runner.d.ts +0 -11
  480. package/dist/core/scheduler/job-runner.js +0 -164
  481. package/dist/core/search/conversations.d.ts +0 -25
  482. package/dist/core/search/conversations.js +0 -110
  483. package/dist/core/search/entities.d.ts +0 -12
  484. package/dist/core/search/entities.js +0 -31
  485. package/dist/core/search/folder-context.d.ts +0 -25
  486. package/dist/core/search/folder-context.js +0 -119
  487. package/dist/core/search/graph-boost.d.ts +0 -7
  488. package/dist/core/search/graph-boost.js +0 -23
  489. package/dist/core/search/index.d.ts +0 -4
  490. package/dist/core/search/qmd-search.d.ts +0 -61
  491. package/dist/core/search/qmd-search.js +0 -178
  492. package/dist/core/security/encrypt.d.ts +0 -6
  493. package/dist/core/security/encrypt.js +0 -47
  494. package/dist/core/security/governance.d.ts +0 -26
  495. package/dist/core/security/governance.js +0 -79
  496. package/dist/core/security/privacy.d.ts +0 -23
  497. package/dist/core/security/privacy.js +0 -82
  498. package/dist/core/security/secret-detector.d.ts +0 -32
  499. package/dist/core/security/secret-detector.js +0 -88
  500. package/dist/core/session/auto-load.d.ts +0 -6
  501. package/dist/core/session/auto-load.js +0 -119
  502. package/dist/core/session/index.d.ts +0 -7
  503. package/dist/core/session/self-iteration-job.d.ts +0 -20
  504. package/dist/core/session/self-iteration-job.js +0 -282
  505. package/dist/core/session/session-hooks.d.ts +0 -18
  506. package/dist/core/session/session-hooks.js +0 -58
  507. package/dist/core/session/types.d.ts +0 -26
  508. package/dist/core/session/types.js +0 -10
  509. package/dist/core/session-hooks/self-iteration-job.d.ts +0 -20
  510. package/dist/core/session-hooks/self-iteration-job.js +0 -282
  511. package/dist/core/session-hooks/session-hooks.d.ts +0 -18
  512. package/dist/core/session-hooks/session-hooks.js +0 -58
  513. package/dist/core/snapshots/cleanup.d.ts +0 -9
  514. package/dist/core/snapshots/comparison.d.ts +0 -19
  515. package/dist/core/snapshots/comparison.js +0 -43
  516. package/dist/core/snapshots/creation.d.ts +0 -19
  517. package/dist/core/snapshots/creation.js +0 -126
  518. package/dist/core/snapshots/retrieval.d.ts +0 -7
  519. package/dist/core/snapshots/retrieval.js +0 -41
  520. package/dist/core/snapshots/stats.d.ts +0 -11
  521. package/dist/core/snapshots/stats.js +0 -52
  522. package/dist/core/snapshots.d.ts +0 -29
  523. package/dist/core/snapshots.js +0 -220
  524. package/dist/core/storage/cache.d.ts +0 -13
  525. package/dist/core/storage/cache.js +0 -202
  526. package/dist/core/storage/database.d.ts +0 -12
  527. package/dist/core/storage/database.js +0 -12
  528. package/dist/core/summarization/cleanup.d.ts +0 -9
  529. package/dist/core/summarization/queries.d.ts +0 -9
  530. package/dist/core/summarization/queries.js +0 -28
  531. package/dist/core/summarization/stats.d.ts +0 -14
  532. package/dist/core/summarization/stats.js +0 -52
  533. package/dist/core/summarization/strategies.d.ts +0 -24
  534. package/dist/core/summarization/strategies.js +0 -28
  535. package/dist/core/summarization.d.ts +0 -37
  536. package/dist/core/summarization.js +0 -188
  537. package/dist/core/sync/qmd-sync.d.ts +0 -94
  538. package/dist/core/sync/qmd-sync.js +0 -201
  539. package/dist/core/temporal-facts.d.ts +0 -54
  540. package/dist/core/temporal-facts.js +0 -193
  541. package/dist/core/toon.d.ts +0 -43
  542. package/dist/core/toon.js +0 -160
  543. package/dist/core/tracing/collector.d.ts +0 -111
  544. package/dist/core/tracing/collector.js +0 -350
  545. package/dist/core/tracing/visualizer.d.ts +0 -32
  546. package/dist/core/tracing/visualizer.js +0 -165
  547. package/dist/core/utils/cleanup-operations.d.ts +0 -13
  548. package/dist/core/utils/cleanup-operations.js +0 -44
  549. package/dist/core/utils/content-extraction.d.ts +0 -19
  550. package/dist/core/utils/content-extraction.js +0 -75
  551. package/dist/core/utils/filter-builder.d.ts +0 -13
  552. package/dist/core/utils/filter-builder.js +0 -44
  553. package/dist/core/utils/history-traversal.d.ts +0 -13
  554. package/dist/core/utils/history-traversal.js +0 -50
  555. package/dist/core/utils/memory-operations.d.ts +0 -17
  556. package/dist/core/utils/memory-operations.js +0 -43
  557. package/dist/core/utils/query-operations.d.ts +0 -18
  558. package/dist/core/utils/query-operations.js +0 -65
  559. package/dist/core/utils/summarization-helpers.d.ts +0 -21
  560. package/dist/core/utils/summarization-helpers.js +0 -38
  561. package/dist/core/utils/temporal-queries.d.ts +0 -13
  562. package/dist/core/utils/temporal-queries.js +0 -27
  563. package/dist/core/utils/vector-operations.d.ts +0 -71
  564. package/dist/core/utils/version-management.d.ts +0 -9
  565. package/dist/core/utils/version-management.js +0 -61
  566. package/dist/core/worker.d.ts +0 -82
  567. package/dist/core/worker.js +0 -272
  568. package/dist/db/adapter.d.ts +0 -7
  569. package/dist/db/adapter.js +0 -175
  570. package/dist/db/bootstrap.d.ts +0 -9
  571. package/dist/db/drizzle/schema-sqlite.d.ts +0 -4837
  572. package/dist/db/drizzle/schema-sqlite.js +0 -684
  573. package/dist/db/drizzle/schema.d.ts +0 -4082
  574. package/dist/db/drizzle/schema.js +0 -770
  575. package/dist/db/drizzle.config.d.ts +0 -3
  576. package/dist/db/drizzle.config.js +0 -12
  577. package/dist/db/index.d.ts +0 -7
  578. package/dist/db/index.js +0 -89
  579. package/dist/db/neon.d.ts +0 -8
  580. package/dist/db/neon.js +0 -20
  581. package/dist/db/schema/index.d.ts +0 -40
  582. package/dist/db/schema/index.js +0 -105
  583. package/dist/db/schema/tables/context-sessions.d.ts +0 -9
  584. package/dist/db/schema/tables/context-sessions.js +0 -37
  585. package/dist/db/schema/tables/conversations.d.ts +0 -9
  586. package/dist/db/schema/tables/conversations.js +0 -47
  587. package/dist/db/schema/tables/core-memory.d.ts +0 -9
  588. package/dist/db/schema/tables/core-memory.js +0 -41
  589. package/dist/db/schema/tables/entities.d.ts +0 -9
  590. package/dist/db/schema/tables/entities.js +0 -39
  591. package/dist/db/schema/tables/entity-relations.d.ts +0 -9
  592. package/dist/db/schema/tables/entity-relations.js +0 -31
  593. package/dist/db/schema/tables/learnings.d.ts +0 -9
  594. package/dist/db/schema/tables/learnings.js +0 -66
  595. package/dist/db/schema/tables/memories.d.ts +0 -9
  596. package/dist/db/schema/tables/memories.js +0 -161
  597. package/dist/db/schema/tables/memory-associations.d.ts +0 -9
  598. package/dist/db/schema/tables/memory-associations.js +0 -39
  599. package/dist/db/schema/tables/memory-hash-cache.d.ts +0 -9
  600. package/dist/db/schema/tables/memory-hash-cache.js +0 -29
  601. package/dist/db/schema/tables/memory-merge-history.d.ts +0 -9
  602. package/dist/db/schema/tables/memory-merge-history.js +0 -33
  603. package/dist/db/schema/tables/memory-merge-proposals.d.ts +0 -9
  604. package/dist/db/schema/tables/memory-merge-proposals.js +0 -39
  605. package/dist/db/schema/tables/messages.d.ts +0 -9
  606. package/dist/db/schema/tables/messages.js +0 -41
  607. package/dist/db/schema/tables/namespaces.d.ts +0 -9
  608. package/dist/db/schema/tables/namespaces.js +0 -37
  609. package/dist/db/schema/tables/projects.d.ts +0 -9
  610. package/dist/db/schema/tables/projects.js +0 -31
  611. package/dist/db/schema/tables/users.d.ts +0 -9
  612. package/dist/db/schema/tables/users.js +0 -27
  613. package/dist/db/schema.d.ts +0 -3
  614. package/dist/db/schema.js +0 -11
  615. package/dist/db/supabase.d.ts +0 -9
  616. package/dist/db/supabase.js +0 -24
  617. package/dist/index.d.ts +0 -7
  618. package/dist/index.js +0 -1677
  619. package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
  620. package/dist/webui/server.d.ts +0 -5
  621. package/dist/webui/server.js +0 -642
  622. package/generated/mcp/manifest.json +0 -23
  623. package/generated/mcp/mcp-servers.json +0 -25
  624. package/generated/mcp/mcporter.json +0 -34
  625. package/generated/mcp/openclaw-memory-qmd.json +0 -17
  626. package/generated/mcp/runtime.json +0 -12
  627. package/scripts/README.md +0 -60
  628. package/scripts/build-release.sh +0 -36
  629. package/scripts/check-secrets.js +0 -132
  630. package/scripts/copy-runtime-assets.mjs +0 -26
  631. package/scripts/generate-mcp.mjs +0 -264
  632. package/scripts/github-release.sh +0 -77
  633. package/scripts/init-dirs.mjs +0 -13
  634. package/scripts/install-claude-code.sh +0 -85
  635. package/scripts/install-cursor.sh +0 -56
  636. package/scripts/install-hooks.sh +0 -73
  637. package/scripts/install-interactive.mjs +0 -357
  638. package/scripts/install-opencode.sh +0 -75
  639. package/scripts/install-plugin.mjs +0 -415
  640. package/scripts/install-windsurf.sh +0 -67
  641. package/scripts/remote-preflight.mjs +0 -62
  642. package/scripts/squish-fallback.mjs +0 -132
  643. package/scripts/test-interactive.mjs +0 -131
  644. package/scripts/verify-mcp.mjs +0 -214
  645. package/skills/squish-memory/scripts/install.mjs +0 -335
  646. package/skills/squish-memory/write_skill.js +0 -2
package/dist/index.js DELETED
@@ -1,1677 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Squish - Universal Memory Plugin System
4
- * CLI + MCP server for persistent memory with hybrid search and encryption
5
- */
6
- import 'dotenv/config';
7
- import fs from 'node:fs';
8
- import { existsSync } from 'node:fs';
9
- import os from 'node:os';
10
- import path from 'node:path';
11
- import { fileURLToPath } from 'node:url';
12
- import { spawn, spawnSync } from 'node:child_process';
13
- import { Command } from 'commander';
14
- import { logger } from './core/logger.js';
15
- import { checkDatabaseHealth, config, getDb } from './db/index.js';
16
- import { getSchema } from './db/schema.js';
17
- import { eq } from 'drizzle-orm';
18
- import { checkRedisHealth } from './core/storage/cache.js';
19
- import { rememberMemory, getMemory, search, getRecent, setConfidence } from './core/memory/memories.js';
20
- import { serializeTags } from './core/memory/serialization.js';
21
- import { createLearning } from './core/ingestion/learnings.js';
22
- import { getMemoryStats } from './core/memory/stats.js';
23
- import { ensureProject, getAllProjects, getOrCreateProject } from './core/projects.js';
24
- import { startWebServer } from './webui/server.js';
25
- import { getRelatedMemories, createAssociation } from './core/associations.js';
26
- import { pinMemory, unpinMemory } from './core/security/governance.js';
27
- import { determineOverallStatus } from './core/lib/utils.js';
28
- import { validateLimit } from './core/lib/validation.js';
29
- import { runDeduplicationJob, runFullConsolidationJob } from './core/consolidation.js';
30
- import { ensureDataDirectory } from './db/bootstrap.js';
31
- import { getDataDir } from './config.js';
32
- import { handleSessionStart, handlePostToolUse, handleSessionEnd, handlePreCompact, } from './core/hooks/agent-hooks.js';
33
- import { initializeDefaultPlaces, walkPlace, walkAllPlaces, quickTour, } from './core/places/index.js';
34
- const VERSION = '1.1.5';
35
- // Output Formatting Utilities
36
- // ============================================================================
37
- function formatOutput(data, pretty = false) {
38
- if (!pretty) {
39
- return JSON.stringify(data, null, 2);
40
- }
41
- if (Array.isArray(data)) {
42
- return data.map((item, i) => `${i + 1}. ${formatItem(item)}`).join('\n');
43
- }
44
- if (data.results) {
45
- return data.results.map((item, i) => `${i + 1}. ${formatItem(item)}`).join('\n');
46
- }
47
- if (data.matches) {
48
- return data.matches.map((item, i) => `${i + 1}. ${formatItem(item)}`).join('\n');
49
- }
50
- if (data.count !== undefined) {
51
- let output = `\nFound ${data.count} results:\n`;
52
- if (data.results) {
53
- output += data.results.map((item, i) => ` ${i + 1}. ${formatItem(item)}`).join('\n');
54
- }
55
- return output;
56
- }
57
- return JSON.stringify(data, null, 2);
58
- }
59
- function formatItem(item) {
60
- if (typeof item === 'string')
61
- return item.substring(0, 100);
62
- const content = item.content || item.summary || item.memory?.content || '';
63
- const type = item.type || '';
64
- return `[${type}] ${content.substring(0, 80)}${content.length > 80 ? '...' : ''}`;
65
- }
66
- function printSuccess(message) {
67
- console.log(`\n ✓ ${message}\n`);
68
- }
69
- function printError(message) {
70
- console.error(`\n ✗ ${message}\n`);
71
- }
72
- function printInfo(message) {
73
- console.log(`\n ℹ ${message}\n`);
74
- }
75
- // Config Management (for project path persistence)
76
- // ============================================================================
77
- const USER_CONFIG_PATH = path.join(os.homedir(), '.squish', 'config.json');
78
- function loadUserConfig() {
79
- try {
80
- if (fs.existsSync(USER_CONFIG_PATH)) {
81
- return JSON.parse(fs.readFileSync(USER_CONFIG_PATH, 'utf-8'));
82
- }
83
- }
84
- catch (e) { }
85
- return {};
86
- }
87
- function saveUserConfig(config) {
88
- const dir = path.dirname(USER_CONFIG_PATH);
89
- if (!fs.existsSync(dir))
90
- fs.mkdirSync(dir, { recursive: true });
91
- fs.writeFileSync(USER_CONFIG_PATH, JSON.stringify(config, null, 2));
92
- }
93
- function getDefaultProjectPath() {
94
- const userConfig = loadUserConfig();
95
- if (userConfig.project)
96
- return userConfig.project;
97
- return process.cwd();
98
- }
99
- function resolveProjectPath(projectOption) {
100
- if (projectOption)
101
- return projectOption;
102
- return getDefaultProjectPath();
103
- }
104
- // Date parsing for time-based queries
105
- // ============================================================================
106
- function parseDate(input) {
107
- if (!input)
108
- return null;
109
- const now = new Date();
110
- const lower = input.toLowerCase().trim();
111
- // Direct date parse
112
- const parsed = new Date(input);
113
- if (!isNaN(parsed.getTime()))
114
- return parsed;
115
- // Relative parsing
116
- const dayMatch = lower.match(/(\d+)\s*day/i);
117
- const weekMatch = lower.match(/(\d+)\s*week/i);
118
- const monthMatch = lower.match(/(\d+)\s*month/i);
119
- if (lower === 'today') {
120
- const d = new Date(now);
121
- d.setHours(0, 0, 0, 0);
122
- return d;
123
- }
124
- if (lower === 'yesterday')
125
- return new Date(now.getTime() - 86400000);
126
- if (lower === 'thisweek' || lower === 'this week') {
127
- const d = new Date(now);
128
- d.setDate(d.getDate() - d.getDay());
129
- d.setHours(0, 0, 0, 0);
130
- return d;
131
- }
132
- if (lower === 'lastweek' || lower === 'last week') {
133
- const d = new Date(now);
134
- d.setDate(d.getDate() - d.getDay() - 7);
135
- return d;
136
- }
137
- if (dayMatch)
138
- return new Date(now.getTime() - parseInt(dayMatch[1]) * 86400000);
139
- if (weekMatch)
140
- return new Date(now.getTime() - parseInt(weekMatch[1]) * 604800000);
141
- if (monthMatch)
142
- return new Date(now.getTime() - parseInt(monthMatch[1]) * 2592000000);
143
- return null;
144
- }
145
- function filterByDateRange(items, since, until) {
146
- const sinceDate = parseDate(since || '');
147
- const untilDate = parseDate(until || '');
148
- return items.filter(item => {
149
- if (!item.createdAt)
150
- return true;
151
- const created = new Date(item.createdAt);
152
- if (sinceDate && created < sinceDate)
153
- return false;
154
- if (untilDate && created > untilDate)
155
- return false;
156
- return true;
157
- });
158
- }
159
- // Load plugin manifest for self-verification
160
- function loadPluginManifest() {
161
- try {
162
- const manifestPath = path.join(getDefaultProjectPath(), 'config', 'plugin-manifest.json');
163
- if (fs.existsSync(manifestPath)) {
164
- return JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
165
- }
166
- }
167
- catch (error) {
168
- logger.warn('Could not load plugin manifest:', error?.message || error);
169
- }
170
- return null;
171
- }
172
- function verifyManifest(manifest) {
173
- if (!manifest) {
174
- return { ok: false, errors: ['Manifest not found'] };
175
- }
176
- const errors = [];
177
- const required = ['id', 'name', 'version', 'capabilities', 'targets', 'dependencies'];
178
- required.forEach((field) => {
179
- if (!manifest[field]) {
180
- errors.push(`Missing required field: ${field}`);
181
- }
182
- });
183
- if (manifest.version !== VERSION) {
184
- errors.push(`Version mismatch: manifest=${manifest.version}, binary=${VERSION}`);
185
- }
186
- const expectedTargets = ['claude-code', 'openclaw', 'opencode', 'codex', 'cursor', 'vscode', 'windsurf'];
187
- expectedTargets.forEach((target) => {
188
- if (!manifest.targets[target]) {
189
- errors.push(`Missing target: ${target}`);
190
- }
191
- });
192
- return { ok: errors.length === 0, errors };
193
- }
194
- async function buildHealthStatus() {
195
- const dbHealth = await checkDatabaseHealth();
196
- const redisHealth = await checkRedisHealth();
197
- const database = dbHealth ? 'ok' : 'error';
198
- const cache = config.redisEnabled ? (redisHealth ? 'ok' : 'error') : 'unavailable';
199
- const overallStatus = config.redisEnabled
200
- ? determineOverallStatus(database, redisHealth)
201
- : (dbHealth ? 'ok' : 'error');
202
- return {
203
- ok: overallStatus === 'ok',
204
- version: VERSION,
205
- mode: config.isTeamMode ? 'team' : 'local',
206
- database,
207
- cache,
208
- dataDirectory: config.dataDir,
209
- dataDirectoryExists: fs.existsSync(config.dataDir),
210
- status: overallStatus,
211
- timestamp: new Date().toISOString(),
212
- };
213
- }
214
- // HELPER FUNCTIONS
215
- // ============================================================================
216
- function showHelp() {
217
- console.log(`
218
- Squish Memory v${VERSION} - Universal Memory Plugin System
219
-
220
- Usage:
221
- squish Start interactive wizard
222
- squish run mcp Start MCP server
223
- squish run web Start Web UI only
224
- squish <command> [options] Run CLI commands for agents
225
-
226
- CLI Commands (for agents):
227
- squish config [action] Manage Squish configuration
228
- squish remember <content> Store a memory
229
- squish note <content> Save a quick note
230
- squish learn <type> <text> Record learning: success, failure, fix, insight
231
- squish search <query> Search memories (--pretty for human output)
232
- squish recall <query> Search or get by ID (--pretty for human output)
233
- squish recent --period Recent memories (today/yesterday/thisweek/7days/30days)
234
- squish update <memoryId> Update memory
235
- squish forget <memoryId> Delete memory (single or bulk with --older-than --search)
236
- squish pin <memoryId> Pin/unpin memory
237
- squish confidence <id> Set confidence
238
- squish tag <action> Manage tags
239
- squish stale Show stale memories
240
- squish link <action> Manage links (find/add/list)
241
- squish migrate Migrate memories between .squish directories
242
- squish clean Dedup + consolidate (maintenance)
243
- squish context Show context or list projects
244
- squish stats View memory statistics
245
-
246
- Examples:
247
- squish run mcp # Start MCP server (for agents)
248
- squish run web # Start Web UI only
249
- squish config set project /repo/path
250
- squish remember "Hello" # Store memory
251
- squish note "Ship v1 first" # Save a quick note
252
- squish learn observation "Updated auth flow" --action edit
253
- squish learn fix "Patched auth middleware" --target middleware.ts
254
- squish search "query" # Search memories
255
- squish context --list-projects
256
- squish clean # Run deduplication and consolidation
257
-
258
- For more info: https://github.com/michielhdoteth/squish
259
- `);
260
- }
261
- async function runInteractiveInstaller() {
262
- const { select } = await import('@clack/prompts');
263
- const { isCancel } = await import('@clack/prompts');
264
- const { log } = await import('@clack/prompts');
265
- const { intro, outro } = await import('@clack/prompts');
266
- intro(`Squish Memory v${VERSION}`);
267
- const options = [
268
- { value: 'mcp', label: 'Start MCP Server (for AI Assistants: Claude Code, OpenCode, etc.)' },
269
- { value: 'web', label: 'Start Web UI Only' },
270
- { value: 'health', label: 'Health & Stats' },
271
- { value: 'help', label: 'Show Help' },
272
- { value: 'exit', label: 'Exit' }
273
- ];
274
- const selected = await select({
275
- message: 'What would you like to do?',
276
- options: options,
277
- });
278
- if (isCancel(selected)) {
279
- outro('Cancelled');
280
- process.exit(0);
281
- return;
282
- }
283
- switch (selected) {
284
- case 'mcp':
285
- log.step('Starting MCP server...');
286
- const { spawn } = await import('child_process');
287
- spawn('npx', ['squish-mcp'], { stdio: 'inherit', shell: true });
288
- break;
289
- case 'web':
290
- log.step('Starting Web UI...');
291
- await runWebOnly();
292
- break;
293
- case 'health':
294
- log.step('Checking health...');
295
- await runCliCommand('health');
296
- await runCliCommand('stats');
297
- break;
298
- case 'help':
299
- showHelp();
300
- process.exit(0);
301
- break;
302
- case 'exit':
303
- outro('Goodbye! 👋');
304
- process.exit(0);
305
- break;
306
- }
307
- }
308
- async function runCliCommand(command) {
309
- // Run CLI command programmatically
310
- const program = new Command();
311
- program.hook('preAction', async () => {
312
- await ensureDataDirectory();
313
- });
314
- if (command === 'health') {
315
- const status = await buildHealthStatus();
316
- console.log(`\n Squish Memory v${VERSION}`);
317
- console.log(` ====================`);
318
- console.log(` Mode: ${status.mode}`);
319
- console.log(` Database: ${status.database}`);
320
- console.log(` Cache: ${status.cache}`);
321
- console.log(` Data Dir: ${status.dataDirectory}`);
322
- console.log(` Status: ${status.ok ? 'HEALTHY' : 'UNHEALTHY'}\n`);
323
- }
324
- else if (command === 'stats') {
325
- const stats = await getMemoryStats(getDefaultProjectPath());
326
- console.log(JSON.stringify({ ok: true, ...stats }, null, 2));
327
- }
328
- }
329
- async function spawnInstallerWizard() {
330
- const distDir = path.dirname(fileURLToPath(import.meta.url));
331
- const packageDir = path.dirname(distDir);
332
- const installScript = path.join(packageDir, 'scripts', 'install-interactive.mjs');
333
- if (!fs.existsSync(installScript)) {
334
- console.error('Installer not found at:', installScript);
335
- process.exit(1);
336
- }
337
- console.log('\nLaunching full installer wizard...\n');
338
- const result = spawnSync('node', [`"${installScript}"`], {
339
- stdio: 'inherit',
340
- shell: true,
341
- cwd: packageDir
342
- });
343
- process.exit(result.status || 0);
344
- }
345
- function isDatabaseInitialized() {
346
- try {
347
- const dataDir = getDataDir();
348
- const dbPath = path.join(dataDir, 'squish.db');
349
- return existsSync(dataDir) && existsSync(dbPath);
350
- }
351
- catch (error) {
352
- return false;
353
- }
354
- }
355
- async function runWebOnly() {
356
- console.log(`[squish] Starting Web UI only...`);
357
- await ensureDataDirectory();
358
- await startWebServer();
359
- }
360
- // CLI MODE DETECTION
361
- // ============================================================================
362
- const args = process.argv.slice(2);
363
- const firstArg = args[0];
364
- // Detect command type
365
- const isNoArgs = args.length === 0;
366
- const isRunCommand = firstArg === 'run';
367
- const isHelpCommand = firstArg === '--help' || firstArg === '-h' || firstArg === 'help';
368
- if (isNoArgs) {
369
- // Check if database exists - if not, run installer automatically
370
- if (!isDatabaseInitialized()) {
371
- console.log(`[squish] No existing database found. Launching installer wizard...\n`);
372
- await spawnInstallerWizard();
373
- }
374
- else {
375
- // INTERACTIVE WIZARD (default when no args) ===
376
- runInteractiveInstaller().catch((e) => {
377
- console.error('Installer error:', e.message);
378
- process.exit(1);
379
- });
380
- }
381
- }
382
- else if (isRunCommand) {
383
- // RUN SUBCOMMAND ===
384
- const subcommand = args[1];
385
- if (subcommand === 'mcp') {
386
- (async () => {
387
- try {
388
- // Initialize data directory before starting MCP
389
- await ensureDataDirectory();
390
- // Start MCP server as child process (stdio mode for agents)
391
- const mcpProcess = spawn('npx', ['squish-mcp'], {
392
- stdio: 'inherit',
393
- shell: true
394
- });
395
- // Forward MCP exit code when it exits
396
- mcpProcess.on('exit', (code) => {
397
- process.exit(code ?? 0);
398
- });
399
- // Clean shutdown: forward signals to MCP child
400
- const cleanup = () => {
401
- mcpProcess.kill('SIGTERM');
402
- setTimeout(() => process.exit(0), 100);
403
- };
404
- process.on('SIGINT', cleanup);
405
- process.on('SIGTERM', cleanup);
406
- }
407
- catch (error) {
408
- console.error('[squish] Failed to start MCP server:', error.message);
409
- process.exit(1);
410
- }
411
- })();
412
- }
413
- else if (subcommand === 'web') {
414
- runWebOnly().catch((e) => {
415
- logger.error('Web server error', e);
416
- process.exit(1);
417
- });
418
- }
419
- else {
420
- console.log(`
421
- Usage: squish run <command>
422
-
423
- Commands:
424
- mcp Start MCP server (for agents like Claude Code)
425
- web Start Web UI only
426
-
427
- Examples:
428
- squish run mcp # Start MCP server (agents connect automatically)
429
- squish run web # Start Web UI at http://localhost:37777
430
- `);
431
- process.exit(subcommand ? 1 : 0);
432
- }
433
- }
434
- else if (isHelpCommand) {
435
- // SHOW HELP ===
436
- showHelp();
437
- process.exit(0);
438
- }
439
- else {
440
- // CLI MODE (for agents/OpenClaw) ===
441
- runCliMode().catch((e) => {
442
- console.error(JSON.stringify({ error: e.message }, null, 2));
443
- process.exit(1);
444
- });
445
- }
446
- // CLI MODE (for OpenClaw bash execution)
447
- // ============================================================================
448
- async function runCliMode() {
449
- const program = new Command();
450
- program
451
- .name('squish')
452
- .description('Squish - Persistent memory for AI assistants')
453
- .version(VERSION);
454
- // Initialize data directory before any command
455
- program.hook('preAction', async () => {
456
- await ensureDataDirectory();
457
- });
458
- // squish config [get] [key] or squish config set <key> <value>
459
- program
460
- .command('config')
461
- .description('Manage Squish configuration')
462
- .argument('[action]', 'get, set, or list', 'list')
463
- .argument('[key]', 'Config key (e.g., project)')
464
- .argument('[value]', 'Config value (for set action)')
465
- .action(async (action, key, value) => {
466
- const userConfig = loadUserConfig();
467
- if (action === 'set') {
468
- if (!key || value === undefined) {
469
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish config set <key> <value>' }, null, 2));
470
- process.exit(1);
471
- }
472
- userConfig[key] = value;
473
- saveUserConfig(userConfig);
474
- console.log(JSON.stringify({ ok: true, message: `Set ${key} = ${value}` }, null, 2));
475
- }
476
- else if (action === 'get') {
477
- if (!key) {
478
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish config get <key>' }, null, 2));
479
- process.exit(1);
480
- }
481
- console.log(JSON.stringify({ ok: true, [key]: userConfig[key] || null }, null, 2));
482
- }
483
- else {
484
- console.log(JSON.stringify({ ok: true, config: userConfig }, null, 2));
485
- }
486
- });
487
- // squish mount /path/to/folder - Enable external memory
488
- program
489
- .command('mount')
490
- .description('Mount an external folder as memory storage')
491
- .argument('[path]', 'Path to external folder (or "status" or "unmount")')
492
- .action(async (pathOrAction) => {
493
- const { getExternalMemory } = await import('./core/external-folder/index.js');
494
- const externalMemory = getExternalMemory();
495
- if (pathOrAction === 'status') {
496
- // Show mount status
497
- const status = await externalMemory.getStatus();
498
- console.log(JSON.stringify({ ok: true, status }, null, 2));
499
- }
500
- else if (pathOrAction === 'unmount') {
501
- // Unmount
502
- externalMemory.unmount();
503
- console.log(JSON.stringify({ ok: true, message: 'External memory unmounted' }, null, 2));
504
- }
505
- else if (pathOrAction) {
506
- // Mount at path
507
- const result = await externalMemory.mount(pathOrAction);
508
- if (result.success) {
509
- console.log(JSON.stringify({ ok: true, message: `Mounted at ${pathOrAction}` }, null, 2));
510
- }
511
- else {
512
- console.log(JSON.stringify({ ok: false, error: result.error }, null, 2));
513
- }
514
- }
515
- else {
516
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish mount <path> or squish mount status' }, null, 2));
517
- }
518
- });
519
- // squish remember "content" --type fact --tags tag1,tag2
520
- program
521
- .command('remember <content>')
522
- .description('Store a memory')
523
- .option('-t, --type <type>', 'Memory type (observation, fact, decision, context, preference)', 'observation')
524
- .option('-T, --tags <tags>', 'Comma-separated tags', '')
525
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
526
- .option('-s, --source <source>', 'Source of this memory (e.g., "voice", "chat", "document")')
527
- .option('-r, --reasoning <reasoning>', 'Why this memory is important')
528
- .option('-c, --context <context>', 'What triggered this memory')
529
- .option('-e, --examples <examples>', 'When to apply this knowledge')
530
- .option('-x, --exceptions <exceptions>', 'When NOT to apply this')
531
- .option('-m, --memory', 'Store as markdown file in .squish/memory/ (not in database)', false)
532
- .option('-H, --hot', 'Store in hot tier (active, high priority) in database', false)
533
- .option('-C, --cold', 'Store in cold tier (archived, lower priority) in database', false)
534
- .action(async (content, options) => {
535
- try {
536
- // Markdown file storage (not in database)
537
- if (options.memory) {
538
- const { saveToMarkdown } = await import('./core/memory/markdown/markdown-storage.js');
539
- const memoryFile = await saveToMarkdown({
540
- content,
541
- type: options.type,
542
- tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
543
- project: options.project,
544
- source: options.source,
545
- reasoning: options.reasoning,
546
- memoryContext: options.context,
547
- examples: options.examples,
548
- exceptions: options.exceptions,
549
- });
550
- // Trigger hooks
551
- const { triggerMemoryCreated } = await import('./core/memory/hooks.js');
552
- await triggerMemoryCreated({
553
- memoryId: memoryFile.id,
554
- content: memoryFile.content,
555
- type: memoryFile.type,
556
- tags: memoryFile.tags,
557
- project: memoryFile.project,
558
- source: memoryFile.source,
559
- tier: 'hot',
560
- });
561
- console.log(JSON.stringify({ ok: true, memory: true, ...memoryFile }, null, 2));
562
- return;
563
- }
564
- // Database storage: determine tier
565
- const tier = options.cold ? 'cold' : 'hot';
566
- const result = await rememberMemory({
567
- content,
568
- type: options.type,
569
- tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
570
- project: options.project,
571
- source: options.source,
572
- reasoning: options.reasoning,
573
- memoryContext: options.context,
574
- examples: options.examples,
575
- exceptions: options.exceptions,
576
- tier,
577
- });
578
- // Trigger hooks for DB storage
579
- const { triggerMemoryCreated } = await import('./core/memory/hooks.js');
580
- await triggerMemoryCreated({
581
- memoryId: result.id,
582
- content: result.content,
583
- type: result.type,
584
- tags: result.tags,
585
- project: result.projectId || undefined,
586
- source: options.source || 'cli',
587
- tier,
588
- });
589
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
590
- }
591
- catch (error) {
592
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
593
- process.exit(1);
594
- }
595
- });
596
- // squish search "query" --type fact --limit 10 --since "3 days ago" --place workshop
597
- program
598
- .command('search <query>')
599
- .description('Search memories')
600
- .option('-t, --type <type>', 'Filter by memory type')
601
- .option('-l, --limit <number>', 'Max results', '10')
602
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
603
- .option('-s, --since <date>', 'Filter: created after this date (e.g., "3 days ago", "2026-01-01")')
604
- .option('-u, --until <date>', 'Filter: created before this date (e.g., "yesterday", "2026-01-15")')
605
- .option('-P, --pretty', 'Human-friendly output', false)
606
- .option('-m, --memory', 'Search memory files instead of database', false)
607
- .option('--place <type>', 'Filter by place type: entry_hall, library, workshop, lab, office, garden, archive')
608
- .action(async (query, options) => {
609
- try {
610
- // Markdown file search
611
- if (options.memory) {
612
- const { getMarkdownMemories } = await import('./core/memory/markdown/markdown-storage.js');
613
- const memoryFiles = await getMarkdownMemories({
614
- type: options.type,
615
- project: options.project,
616
- });
617
- // Simple text search (can be enhanced with QMD later)
618
- const searchLower = query.toLowerCase();
619
- const filtered = memoryFiles.filter(m => m.content.toLowerCase().includes(searchLower) ||
620
- m.tags.some(t => t.toLowerCase().includes(searchLower))).slice(0, validateLimit(options.limit, 10, 1, 100));
621
- if (options.pretty) {
622
- console.log(`\n Memory Search: "${query}"`);
623
- console.log(` Found ${filtered.length} results:\n`);
624
- filtered.forEach((r, i) => {
625
- console.log(` ${i + 1}. [${r.type || 'memory'}] ${(r.content || '').substring(0, 60)}...`);
626
- });
627
- console.log('');
628
- }
629
- else {
630
- console.log(JSON.stringify({ ok: true, query, source: 'memory', count: filtered.length, results: filtered }, null, 2));
631
- }
632
- return;
633
- }
634
- // Database search
635
- const results = await search({
636
- query,
637
- type: options.type,
638
- limit: validateLimit(options.limit, 10, 1, 100) * 2,
639
- project: options.project,
640
- });
641
- const filtered = filterByDateRange(results, options.since, options.until);
642
- let limited = filtered.slice(0, validateLimit(options.limit, 10, 1, 100));
643
- // Add place info to results
644
- const { getMemoryPlace } = await import('./core/places/index.js');
645
- const limitedWithPlace = await Promise.all(limited.map(async (r) => {
646
- const placeId = await getMemoryPlace(r.id);
647
- return { ...r, placeId };
648
- }));
649
- // Filter by place if specified
650
- if (options.place) {
651
- const placeFiltered = [];
652
- for (const r of limitedWithPlace) {
653
- if (r.placeId) {
654
- const { getPlace } = await import('./core/places/index.js');
655
- const place = await getPlace(r.placeId);
656
- if (place && place.placeType === options.place) {
657
- placeFiltered.push({ ...r, place: place.name || null, placeType: place.placeType || null });
658
- }
659
- }
660
- }
661
- limited = placeFiltered;
662
- }
663
- else if (limitedWithPlace.length > 0) {
664
- // Add place info to results even without filter
665
- for (const r of limitedWithPlace) {
666
- if (r.placeId) {
667
- const { getPlace } = await import('./core/places/index.js');
668
- const place = await getPlace(r.placeId);
669
- if (place) {
670
- r.place = place.name || null;
671
- r.placeType = place.placeType || null;
672
- }
673
- }
674
- }
675
- limited = limitedWithPlace;
676
- }
677
- if (options.pretty) {
678
- console.log(`\n Search: "${query}"`);
679
- console.log(` Found ${limited.length} results:\n`);
680
- limited.forEach((r, i) => {
681
- const placeTag = r.place ? ` (${r.place})` : '';
682
- console.log(` ${i + 1}. [${r.type || 'memory'}] ${(r.content || '').substring(0, 60)}...${placeTag}`);
683
- });
684
- console.log('');
685
- }
686
- else {
687
- console.log(JSON.stringify({ ok: true, query, count: limited.length, since: options.since, until: options.until, placeFilter: options.place || null, results: limited }, null, 2));
688
- }
689
- }
690
- catch (error) {
691
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
692
- process.exit(1);
693
- }
694
- });
695
- // squish forget <memoryId> -- Delete single or bulk delete memories
696
- program
697
- .command('forget [memoryId]')
698
- .description('Delete a memory by ID, or bulk delete with filters')
699
- .option('-o, --older-than <date>', 'Bulk delete memories older than (e.g., "30 days", "6 months")')
700
- .option('-t, --type <type>', 'Filter by memory type')
701
- .option('-s, --search <query>', 'Search query to match specific memories')
702
- .option('-c, --confirm', 'Actually delete (default is dry-run)', false)
703
- .option('-l, --limit <number>', 'Max memories to delete', '100')
704
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
705
- .action(async (memoryId, options) => {
706
- try {
707
- // Single memory deletion
708
- if (memoryId) {
709
- const db = await getDb();
710
- const schema = await getSchema();
711
- const sqliteDb = db;
712
- // Get memory content before deleting for hook
713
- const [memory] = await sqliteDb.select().from(schema.memories).where(eq(schema.memories.id, memoryId));
714
- await sqliteDb.delete(schema.memories).where(eq(schema.memories.id, memoryId));
715
- // Trigger memoryDeleted hook
716
- if (memory) {
717
- const { triggerMemoryDeleted } = await import('./core/memory/hooks.js');
718
- await triggerMemoryDeleted({
719
- memoryId: memory.id,
720
- content: memory.content,
721
- type: memory.type,
722
- tags: typeof memory.tags === 'string' ? memory.tags.split(',') : [],
723
- project: memory.projectId || undefined,
724
- source: memory.source || undefined,
725
- tier: memory.tier,
726
- });
727
- }
728
- console.log(JSON.stringify({ ok: true, message: `Memory ${memoryId} deleted` }, null, 2));
729
- return;
730
- }
731
- // Bulk deletion
732
- if (!options.olderThan && !options.search) {
733
- console.log(JSON.stringify({ ok: false, error: 'Provide memory ID or use --older-than / --search for bulk delete' }, null, 2));
734
- process.exit(1);
735
- }
736
- const query = options.search || '';
737
- const limit = validateLimit(options.limit, 100, 1, 100);
738
- const results = await search({ query, type: options.type, limit, project: options.project });
739
- let filtered = results;
740
- if (options.olderThan) {
741
- filtered = filterByDateRange(results, '', options.olderThan);
742
- }
743
- const db = await getDb();
744
- const schema = await getSchema();
745
- const sqliteDb = db;
746
- const deleted = [];
747
- for (const mem of filtered) {
748
- await sqliteDb.delete(schema.memories).where(eq(schema.memories.id, mem.id));
749
- deleted.push(mem.id);
750
- }
751
- console.log(JSON.stringify({ ok: true, matched: filtered.length, deleted: deleted.length, dryRun: !options.confirm }, null, 2));
752
- }
753
- catch (error) {
754
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
755
- process.exit(1);
756
- }
757
- });
758
- // squish link - Unified graph operations (find related, add links, list associations)
759
- program
760
- .command('link')
761
- .description('Manage memory associations: find, add, list')
762
- .argument('<action>', 'Action: find, add, or list')
763
- .argument('[args...]', 'Additional arguments')
764
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
765
- .action(async (action, args, options) => {
766
- try {
767
- // link find <memoryId> [--depth N] [--min-weight N]
768
- if (action === 'find') {
769
- const memoryId = args[0];
770
- if (!memoryId) {
771
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish link find <memoryId> [--depth N] [--min-weight N]' }, null, 2));
772
- process.exit(1);
773
- }
774
- const depth = validateLimit(args[1], 2, 1, 5);
775
- const minWeight = parseFloat(args[2]) || 0.3;
776
- const related = await getRelatedMemories(memoryId, depth * 5);
777
- const filtered = related.filter((r) => r.weight >= minWeight);
778
- console.log(JSON.stringify({ ok: true, count: filtered.length, related: filtered }, null, 2));
779
- return;
780
- }
781
- // link add <fromId> <toId> <type>
782
- if (action === 'add') {
783
- const fromMemoryId = args[0];
784
- const toMemoryId = args[1];
785
- const type = args[2] || 'relates_to';
786
- if (!fromMemoryId || !toMemoryId) {
787
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish link add <fromId> <toId> <type>' }, null, 2));
788
- process.exit(1);
789
- }
790
- await createAssociation(fromMemoryId, toMemoryId, type, 0.5);
791
- console.log(JSON.stringify({ ok: true, message: `Linked ${fromMemoryId} -> ${toMemoryId} (${type})` }, null, 2));
792
- return;
793
- }
794
- // link list - List all associations
795
- if (action === 'list') {
796
- const db = await getDb();
797
- const schema = await getSchema();
798
- const sqliteDb = db;
799
- const associations = await sqliteDb.select().from(schema.memoryAssociations).limit(100);
800
- console.log(JSON.stringify({ ok: true, count: associations.length, associations }, null, 2));
801
- return;
802
- }
803
- console.log(JSON.stringify({ ok: false, error: 'Usage: squish link <find|add|list> [args]' }, null, 2));
804
- }
805
- catch (error) {
806
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
807
- process.exit(1);
808
- }
809
- });
810
- // squish learn <type> <content> - Record learning: success, failure, fix, or insight
811
- program
812
- .command('learn <type> <content>')
813
- .description('Record learning: success, failure, fix, or insight')
814
- .option('-c, --context <context>', 'Additional context about what happened')
815
- .option('-a, --action <action>', 'Action performed')
816
- .option('-t, --target <target>', 'Target file or resource')
817
- .option('-m, --memory-id <memoryId>', 'Optional memory ID to link this learning to')
818
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
819
- .action(async (type, content, options) => {
820
- try {
821
- const validTypes = ['success', 'failure', 'fix', 'insight'];
822
- if (!validTypes.includes(type)) {
823
- console.log(JSON.stringify({ ok: false, error: `Invalid type. Must be: ${validTypes.join(', ')}` }, null, 2));
824
- process.exit(1);
825
- }
826
- const learning = await createLearning({
827
- type: type,
828
- content,
829
- context: options.context,
830
- action: options.action,
831
- target: options.target,
832
- project: options.project,
833
- memoryId: options.memoryId,
834
- });
835
- console.log(JSON.stringify({ ok: true, learning }, null, 2));
836
- }
837
- catch (error) {
838
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
839
- process.exit(1);
840
- }
841
- });
842
- program
843
- .command('update <memoryId>')
844
- .description('Update a memory')
845
- .option('-c, --content <content>', 'New content')
846
- .option('-t, --type <type>', 'New type (observation, fact, decision, context, preference)')
847
- .option('-T, --tags <tags>', 'Comma-separated tags')
848
- .action(async (memoryId, options) => {
849
- try {
850
- const updates = {};
851
- if (options.content)
852
- updates.content = options.content;
853
- if (options.type)
854
- updates.type = options.type;
855
- if (options.tags)
856
- updates.tags = serializeTags(options.tags.split(','));
857
- const db = await getDb();
858
- const schema = await getSchema();
859
- const sqliteDb = db;
860
- // Get old memory for hook
861
- const [oldMemory] = await sqliteDb.select().from(schema.memories).where(eq(schema.memories.id, memoryId));
862
- await sqliteDb.update(schema.memories).set(updates).where(eq(schema.memories.id, memoryId));
863
- // Trigger memoryUpdated hook
864
- if (oldMemory) {
865
- const { triggerMemoryUpdated } = await import('./core/memory/hooks.js');
866
- const newContent = options.content || oldMemory.content;
867
- await triggerMemoryUpdated({
868
- memoryId: oldMemory.id,
869
- content: newContent,
870
- type: options.type || oldMemory.type,
871
- tags: options.tags ? options.tags.split(',') : (typeof oldMemory.tags === 'string' ? oldMemory.tags.split(',') : []),
872
- project: oldMemory.projectId || undefined,
873
- source: oldMemory.source || undefined,
874
- tier: oldMemory.tier,
875
- importance: oldMemory.importanceScore || oldMemory.relevanceScore || 50,
876
- }, oldMemory.content);
877
- }
878
- console.log(JSON.stringify({ ok: true, message: `Memory ${memoryId} updated` }, null, 2));
879
- }
880
- catch (error) {
881
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
882
- process.exit(1);
883
- }
884
- });
885
- // squish recall <query or memoryId> - Search or get by ID
886
- program
887
- .command('recall <query>')
888
- .description('Search memories by query or get by ID (if UUID provided)')
889
- .option('-l, --limit <number>', 'Max results', '5')
890
- .option('-t, --type <type>', 'Filter by memory type')
891
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
892
- .option('-s, --since <date>', 'Filter: created after this date (e.g., "3 days ago", "yesterday")')
893
- .option('-u, --until <date>', 'Filter: created before this date (e.g., "today", "2026-01-15")')
894
- .option('-P, --pretty', 'Human-friendly output', false)
895
- .option('--place <type>', 'Filter by place type: entry_hall, library, workshop, lab, office, garden, archive')
896
- .action(async (query, options) => {
897
- try {
898
- const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(query);
899
- if (isUUID) {
900
- const memory = await getMemory(query);
901
- // Add place info to single memory retrieval
902
- if (memory) {
903
- const { getMemoryPlace, getPlace } = await import('./core/places/index.js');
904
- const placeId = await getMemoryPlace(memory.id);
905
- if (placeId) {
906
- const place = await getPlace(placeId);
907
- memory.place = place?.name || null;
908
- memory.placeType = place?.placeType || null;
909
- }
910
- }
911
- if (options.pretty && memory) {
912
- const placeInfo = memory.place ? ` (${memory.place})` : '';
913
- console.log(`\n Memory: ${memory.id}`);
914
- console.log(` Type: ${memory.type}`);
915
- console.log(` Content: ${memory.content}\n`);
916
- if (placeInfo)
917
- console.log(` Place: ${memory.place}\n`);
918
- }
919
- else {
920
- console.log(JSON.stringify({ ok: true, found: !!memory, memory }, null, 2));
921
- }
922
- }
923
- else {
924
- const results = await search({
925
- query,
926
- type: options.type,
927
- limit: validateLimit(options.limit, 5, 1, 100) * 2,
928
- project: options.project,
929
- });
930
- const filtered = filterByDateRange(results, options.since, options.until);
931
- let limited = filtered.slice(0, validateLimit(options.limit, 5, 1, 100));
932
- // Add place info to results
933
- const { getMemoryPlace, getPlace } = await import('./core/places/index.js');
934
- const limitedWithPlace = await Promise.all(limited.map(async (r) => {
935
- const placeId = await getMemoryPlace(r.id);
936
- let placeInfo = {};
937
- if (placeId) {
938
- const place = await getPlace(placeId);
939
- placeInfo = { place: place?.name || null, placeType: place?.placeType || null };
940
- }
941
- return { ...r, ...placeInfo };
942
- }));
943
- // Filter by place if specified
944
- if (options.place) {
945
- limited = limitedWithPlace.filter((r) => r.placeType === options.place);
946
- }
947
- else {
948
- limited = limitedWithPlace;
949
- }
950
- if (options.pretty) {
951
- console.log(`\n Recall: "${query}"`);
952
- console.log(` Found ${limited.length} matches:\n`);
953
- limited.forEach((r, i) => {
954
- const placeTag = r.place ? ` (${r.place})` : '';
955
- console.log(` ${i + 1}. [${r.type || 'memory'}] ${(r.content || '').substring(0, 60)}...${placeTag} (${(r.similarity ?? 0).toFixed(2)})`);
956
- });
957
- console.log('');
958
- }
959
- else {
960
- const matches = limited.map((r) => ({
961
- id: r.id,
962
- score: r.similarity ?? 0,
963
- type: r.type,
964
- content: r.content.length > 200 ? r.content.slice(0, 200) + '...' : r.content,
965
- tags: r.tags,
966
- place: r.place,
967
- placeType: r.placeType,
968
- }));
969
- console.log(JSON.stringify({ ok: true, query, count: matches.length, since: options.since, until: options.until, placeFilter: options.place || null, matches }, null, 2));
970
- }
971
- }
972
- }
973
- catch (error) {
974
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
975
- process.exit(1);
976
- }
977
- });
978
- // squish recent --period <period> - Show recent memories
979
- program
980
- .command('recent')
981
- .description('Show recent memories by period')
982
- .option('-p, --period <period>', 'Period: today, yesterday, thisweek, 7days, 30days, or custom like "3 days"', 'today')
983
- .option('-s, --since <date>', 'Start date (alternative to --period)')
984
- .option('-u, --until <date>', 'End date (alternative to --period)')
985
- .option('-l, --limit <number>', 'Max results', '10')
986
- .option('-P, --project <project>', 'Project path', getDefaultProjectPath())
987
- .action(async (options) => {
988
- try {
989
- let since, until;
990
- if (options.since && options.until) {
991
- since = options.since;
992
- until = options.until;
993
- }
994
- else if (options.since) {
995
- since = options.since;
996
- until = 'now';
997
- }
998
- else {
999
- const periodMap = {
1000
- today: ['today', 'now'],
1001
- yesterday: ['yesterday', 'today'],
1002
- thisweek: ['thisweek', 'now'],
1003
- '7days': ['7 days', 'now'],
1004
- '14days': ['14 days', 'now'],
1005
- '30days': ['30 days', 'now'],
1006
- '90days': ['90 days', 'now'],
1007
- };
1008
- const mapped = periodMap[options.period];
1009
- if (mapped) {
1010
- [since, until] = mapped;
1011
- }
1012
- else {
1013
- since = options.period;
1014
- until = 'now';
1015
- }
1016
- }
1017
- const results = await getRecent(options.project, 100);
1018
- const filtered = filterByDateRange(results, since, until);
1019
- const limited = filtered.slice(0, validateLimit(options.limit, 10, 1, 100));
1020
- console.log(JSON.stringify({ ok: true, period: options.period, since, until, count: limited.length, results: limited }, null, 2));
1021
- }
1022
- catch (error) {
1023
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1024
- process.exit(1);
1025
- }
1026
- });
1027
- // squish confidence <memoryId> [level] - Set or view confidence level
1028
- program
1029
- .command('confidence <memoryId> [level]')
1030
- .description('Set or view confidence level (certain/speculative/outdated)')
1031
- .action(async (memoryId, level) => {
1032
- try {
1033
- if (!level) {
1034
- const memory = await getMemory(String(memoryId));
1035
- if (!memory) {
1036
- console.log(JSON.stringify({ ok: false, error: 'Memory not found' }, null, 2));
1037
- process.exit(1);
1038
- }
1039
- console.log(JSON.stringify({ ok: true, memoryId, confidenceLevel: memory.confidenceLevel ?? 'certain' }, null, 2));
1040
- }
1041
- else {
1042
- const validLevels = ['certain', 'speculative', 'outdated'];
1043
- if (!validLevels.includes(level)) {
1044
- console.log(JSON.stringify({ ok: false, error: 'Invalid level. Use: certain, speculative, or outdated' }, null, 2));
1045
- process.exit(1);
1046
- }
1047
- await setConfidence(String(memoryId), level);
1048
- console.log(JSON.stringify({ ok: true, memoryId, confidenceLevel: level }, null, 2));
1049
- }
1050
- }
1051
- catch (error) {
1052
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1053
- process.exit(1);
1054
- }
1055
- });
1056
- // squish pin <memoryId> [--unpin]
1057
- program
1058
- .command('pin <memoryId>')
1059
- .description('Pin/unpin a memory to prevent pruning/consolidation')
1060
- .option('-u, --unpin', 'Unpin the memory instead of pinning', false)
1061
- .action(async (memoryId, options) => {
1062
- try {
1063
- if (options.unpin) {
1064
- await unpinMemory(String(memoryId));
1065
- console.log(JSON.stringify({ ok: true, memoryId, pinned: false }, null, 2));
1066
- }
1067
- else {
1068
- await pinMemory(String(memoryId));
1069
- console.log(JSON.stringify({ ok: true, memoryId, pinned: true }, null, 2));
1070
- }
1071
- }
1072
- catch (error) {
1073
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1074
- process.exit(1);
1075
- }
1076
- });
1077
- // squish tag add <tag> --search <query> --confirm
1078
- // squish tag remove <tag> --older-than "30 days" --confirm
1079
- program
1080
- .command('tag')
1081
- .description('Manage tags on memories (bulk)')
1082
- .argument('<action>', 'add or remove')
1083
- .argument('<tag>', 'Tag name')
1084
- .option('-s, --search <query>', 'Search query to match memories')
1085
- .option('-o, --older-than <date>', 'Only tag memories older than (e.g., "30 days")')
1086
- .option('-t, --type <type>', 'Filter by memory type')
1087
- .option('-c, --confirm', 'Actually execute the changes (default is dry-run)', false)
1088
- .option('-l, --limit <number>', 'Max memories to process', '50')
1089
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1090
- .action(async (action, tag, options) => {
1091
- try {
1092
- if (!options.search && !options.olderThan) {
1093
- console.log(JSON.stringify({ ok: false, error: 'Provide --search <query> or --older-than <date>' }, null, 2));
1094
- process.exit(1);
1095
- }
1096
- const limit = validateLimit(options.limit, 50, 1, 100);
1097
- let results;
1098
- const searchInput = { query: options.search, limit, project: options.project };
1099
- if (options.type)
1100
- searchInput.type = options.type;
1101
- if (options.search) {
1102
- results = await search(searchInput);
1103
- }
1104
- else {
1105
- results = await getRecent(options.project, limit * 2);
1106
- }
1107
- let filtered = results;
1108
- if (options.olderThan) {
1109
- filtered = filterByDateRange(results, '', options.olderThan);
1110
- }
1111
- const db = await getDb();
1112
- const schema = await getSchema();
1113
- if (action === 'add') {
1114
- const updated = [];
1115
- for (const mem of filtered) {
1116
- try {
1117
- const tags = new Set((mem.tags || []));
1118
- if (!tags.has(tag)) {
1119
- tags.add(tag);
1120
- await db.update(schema.memories)
1121
- .set({ tags: serializeTags(Array.from(tags)), updatedAt: new Date() })
1122
- .where(eq(schema.memories.id, mem.id));
1123
- updated.push(mem.id);
1124
- }
1125
- }
1126
- catch (e) {
1127
- console.error('DEBUG: error updating', mem.id, e.message);
1128
- throw e;
1129
- }
1130
- }
1131
- console.log(JSON.stringify({ ok: true, action: 'add', tag, matched: filtered.length, updated: updated.length, dryRun: !options.confirm }, null, 2));
1132
- }
1133
- else if (action === 'remove') {
1134
- const updated = [];
1135
- for (const mem of filtered) {
1136
- const tags = new Set((mem.tags || []));
1137
- if (tags.has(tag)) {
1138
- tags.delete(tag);
1139
- await db.update(schema.memories)
1140
- .set({ tags: serializeTags(Array.from(tags)), updatedAt: new Date() })
1141
- .where(eq(schema.memories.id, mem.id));
1142
- updated.push(mem.id);
1143
- }
1144
- }
1145
- console.log(JSON.stringify({ ok: true, action: 'remove', tag, matched: filtered.length, updated: updated.length, dryRun: !options.confirm }, null, 2));
1146
- }
1147
- else {
1148
- console.log(JSON.stringify({ ok: false, error: 'Use: squish tag add <tag> or squish tag remove <tag>' }, null, 2));
1149
- process.exit(1);
1150
- }
1151
- }
1152
- catch (error) {
1153
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1154
- process.exit(1);
1155
- }
1156
- });
1157
- // squish stale --days 30 - Show old, low-confidence, unaccessed memories
1158
- program
1159
- .command('stale')
1160
- .description('Show stale memories (old, low-confidence, or rarely accessed)')
1161
- .option('-d, --days <number>', 'Show memories older than N days', '30')
1162
- .option('-c, --confidence <level>', 'Max confidence level to show (outdated, speculative)', 'speculative')
1163
- .option('-l, --limit <number>', 'Max results', '20')
1164
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1165
- .action(async (options) => {
1166
- try {
1167
- const days = validateLimit(options.days, 30, 1, 365);
1168
- const cutoffDate = new Date(Date.now() - days * 86400000);
1169
- // Get recent memories - larger limit to find stale ones
1170
- const results = await getRecent(options.project, 500);
1171
- const stale = results.filter((m) => {
1172
- const created = m.createdAt ? new Date(m.createdAt) : null;
1173
- const isOld = created && created < cutoffDate;
1174
- const isLowConfidence = m.confidenceLevel === 'outdated' || m.confidenceLevel === 'speculative';
1175
- const hasLowImportance = (m.importance || 50) < 40;
1176
- return isOld || isLowConfidence || hasLowImportance;
1177
- });
1178
- const limited = stale.slice(0, validateLimit(options.limit, 20, 1, 100));
1179
- const summary = {
1180
- totalStale: stale.length,
1181
- old: stale.filter((m) => m.createdAt && new Date(m.createdAt) < cutoffDate).length,
1182
- lowConfidence: stale.filter((m) => m.confidenceLevel === 'outdated' || m.confidenceLevel === 'speculative').length,
1183
- lowImportance: stale.filter((m) => (m.importance || 50) < 40).length,
1184
- };
1185
- console.log(JSON.stringify({ ok: true, summary, memories: limited }, null, 2));
1186
- }
1187
- catch (error) {
1188
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1189
- process.exit(1);
1190
- }
1191
- });
1192
- // squish stats
1193
- program
1194
- .command('stats')
1195
- .description('View statistics')
1196
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1197
- .option('-m, --memory', 'Show memory file storage stats instead of database', false)
1198
- .action(async (options) => {
1199
- try {
1200
- // Memory file stats
1201
- if (options.memory) {
1202
- const { getMemoryStats, isMemoryStorageAvailable } = await import('./core/memory/markdown/markdown-storage.js');
1203
- const available = isMemoryStorageAvailable();
1204
- if (!available) {
1205
- console.log(JSON.stringify({ ok: false, error: 'Memory file storage not available' }, null, 2));
1206
- process.exit(1);
1207
- }
1208
- const stats = await getMemoryStats();
1209
- console.log(JSON.stringify({ ok: true, source: 'memory', ...stats }, null, 2));
1210
- return;
1211
- }
1212
- // Database stats
1213
- const stats = await getMemoryStats(options.project);
1214
- console.log(JSON.stringify({ ok: true, ...stats }, null, 2));
1215
- }
1216
- catch (error) {
1217
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1218
- process.exit(1);
1219
- }
1220
- });
1221
- // squish install
1222
- program
1223
- .command('install')
1224
- .description('Run the interactive installer wizard')
1225
- .action(async () => {
1226
- await spawnInstallerWizard();
1227
- });
1228
- // squish note "my thought here" - quick brain dump
1229
- program
1230
- .command('note <content>')
1231
- .description('Quick brain dump - store a raw memory to process later')
1232
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1233
- .action(async (content, options) => {
1234
- try {
1235
- const result = await rememberMemory({
1236
- content,
1237
- type: 'observation',
1238
- tags: ['note', 'quick'],
1239
- project: options.project,
1240
- });
1241
- console.log(JSON.stringify({ ok: true, message: 'Note saved', id: result.id }, null, 2));
1242
- }
1243
- catch (error) {
1244
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1245
- process.exit(1);
1246
- }
1247
- });
1248
- // squish context - Show project context (memories + observations + places)
1249
- program
1250
- .command('context')
1251
- .description('Show project context or list available projects')
1252
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1253
- .option('-l, --limit <number>', 'Number of items to show', '10')
1254
- .option('-i, --include <items>', 'What to include: memories, observations, entities, places', 'memories,observations,places')
1255
- .option('--list-projects', 'List registered projects instead of loading context', false)
1256
- .option('-j, --json', 'Output as JSON', false)
1257
- .option('--place <type>', 'Filter by place type: entry_hall, library, workshop, lab, office, garden, archive')
1258
- .option('--tier <level>', 'Disclosure level: quick (place names), medium (top 3), full (all)', 'medium')
1259
- .option('--has-memories', 'Only show places with memories', true)
1260
- .option('--sync', 'Recalculate memory counts for all places', false)
1261
- .option('--archive', 'Move memories > 30 days to Archive place', false)
1262
- .option('--task <description>', 'Task description for auto-place detection (e.g., "fix bug", "design API")')
1263
- .action(async (options) => {
1264
- try {
1265
- // Auto-detect place from task if provided
1266
- let placeFilter = options.place || null;
1267
- if (options.task && !placeFilter) {
1268
- // Simple keyword detection
1269
- const task = options.task.toLowerCase();
1270
- if (task.includes('fix') || task.includes('bug') || task.includes('error'))
1271
- placeFilter = 'workshop';
1272
- else if (task.includes('design') || task.includes('plan') || task.includes('api'))
1273
- placeFilter = 'library';
1274
- else if (task.includes('task') || task.includes('todo') || task.includes('manage'))
1275
- placeFilter = 'office';
1276
- else if (task.includes('test') || task.includes('experiment'))
1277
- placeFilter = 'lab';
1278
- if (placeFilter)
1279
- console.log(`Auto-detected place: ${placeFilter}`);
1280
- }
1281
- if (options.listProjects) {
1282
- const projects = await getAllProjects();
1283
- if (options.json) {
1284
- console.log(JSON.stringify({ ok: true, count: projects.length, projects }, null, 2));
1285
- }
1286
- else {
1287
- console.log(`\n Registered Projects (${projects.length})`);
1288
- console.log(` ================================`);
1289
- for (const project of projects) {
1290
- console.log(`\n ${project.name}`);
1291
- console.log(` Path: ${project.path}`);
1292
- console.log(` ID: ${project.id}`);
1293
- }
1294
- console.log('');
1295
- }
1296
- return;
1297
- }
1298
- // Get project context
1299
- const projectPath = resolveProjectPath(options.project);
1300
- await ensureProject(projectPath);
1301
- const project = await getOrCreateProject(projectPath);
1302
- if (!project) {
1303
- console.log(JSON.stringify({ ok: false, error: 'Project not found' }, null, 2));
1304
- process.exit(1);
1305
- }
1306
- const limit = parseInt(options.limit);
1307
- const include = (options.include || 'memories,observations,places').split(',');
1308
- const tier = options.tier || 'full';
1309
- const hasMemoriesOnly = options.hasMemories !== false; // Default true now
1310
- const existingPlaceFilter = options.place || null;
1311
- const result = { project: project.name, tier };
1312
- // Get memories
1313
- if (include.includes('memories')) {
1314
- const memories = await getRecent(projectPath, limit);
1315
- result.memories = memories.map((m) => ({
1316
- id: m.id,
1317
- type: m.type,
1318
- content: m.content?.substring(0, 100),
1319
- tags: m.tags,
1320
- }));
1321
- }
1322
- // Get observations (learnings)
1323
- if (include.includes('observations')) {
1324
- const { getObservations } = await import('./core/ingestion/learnings.js');
1325
- const observations = await getObservations(projectPath, limit);
1326
- result.observations = observations.map((o) => ({
1327
- id: o.id,
1328
- type: o.type,
1329
- content: o.content?.substring(0, 100),
1330
- }));
1331
- }
1332
- // Get places (spatial memory) with filtering
1333
- if (include.includes('places')) {
1334
- const { initializeDefaultPlaces, getProjectPlaces, walkPlace, getPlaceByType, syncAllPlaceMemoryCounts } = await import('./core/places/index.js');
1335
- await initializeDefaultPlaces(project.id);
1336
- // Sync memory counts if requested
1337
- if (options.sync) {
1338
- await syncAllPlaceMemoryCounts(project.id);
1339
- console.log('Synced memory counts for all places.');
1340
- }
1341
- // Auto-archive old memories if requested
1342
- if (options.archive) {
1343
- const { autoArchiveOldMemories } = await import('./core/places/index.js');
1344
- const archiveResult = await autoArchiveOldMemories(project.id, 30);
1345
- console.log(`Archived ${archiveResult.archived} old memories to Archive (${archiveResult.failed} failed).`);
1346
- }
1347
- let places = await getProjectPlaces(project.id);
1348
- // Apply --has-memories filter
1349
- if (hasMemoriesOnly) {
1350
- places = places.filter((p) => p.memoryCount > 0);
1351
- }
1352
- // Apply --place filter (from --place or --task auto-detect)
1353
- if (placeFilter) {
1354
- const filtered = places.filter((p) => p.placeType === placeFilter);
1355
- if (filtered.length > 0) {
1356
- places = filtered;
1357
- }
1358
- }
1359
- // Format places based on tier
1360
- if (tier === 'quick') {
1361
- // Just place names (~50 tokens)
1362
- result.places = places.map((p) => ({
1363
- name: p.name,
1364
- type: p.placeType,
1365
- }));
1366
- }
1367
- else if (tier === 'medium') {
1368
- // Top 3 memories per place (~170 tokens)
1369
- const placesWithMemories = [];
1370
- for (const p of places) {
1371
- if (p.memoryCount > 0) {
1372
- const walkResult = await walkPlace(project.id, p.placeType, {
1373
- tokenBudget: 170,
1374
- maxMemoriesPerPlace: 3,
1375
- compressWithToon: false,
1376
- });
1377
- placesWithMemories.push({
1378
- name: p.name,
1379
- type: p.placeType,
1380
- purpose: p.purpose,
1381
- memories: p.memoryCount,
1382
- preview: walkResult?.memories.slice(0, 3).map((m) => m.content?.substring(0, 80)) || [],
1383
- });
1384
- }
1385
- }
1386
- result.places = placesWithMemories;
1387
- }
1388
- else {
1389
- // Full - all memories (~500 tokens)
1390
- result.places = places.map((p) => ({
1391
- name: p.name,
1392
- type: p.placeType,
1393
- purpose: p.purpose,
1394
- memories: p.memoryCount,
1395
- }));
1396
- }
1397
- }
1398
- if (options.json) {
1399
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1400
- }
1401
- else {
1402
- // Human readable output
1403
- console.log(`\n=== ${project.name} Context ===\n`);
1404
- if (result.places && result.places.length > 0) {
1405
- console.log('Spatial Memory Places:');
1406
- result.places.forEach((p) => {
1407
- if (tier === 'quick') {
1408
- console.log(` ${p.name} (${p.type})`);
1409
- }
1410
- else if (tier === 'medium') {
1411
- console.log(` ${p.name} (${p.memories} memories) - ${p.purpose}`);
1412
- if (p.preview && p.preview.length > 0) {
1413
- p.preview.forEach((m) => {
1414
- console.log(` - ${m}...`);
1415
- });
1416
- }
1417
- }
1418
- else {
1419
- console.log(` ${p.name} (${p.memories} memories) - ${p.purpose}`);
1420
- }
1421
- });
1422
- console.log('');
1423
- }
1424
- if (result.memories && result.memories.length > 0) {
1425
- console.log('Recent Memories:');
1426
- result.memories.slice(0, 5).forEach((m) => {
1427
- console.log(` [${m.type}] ${m.content}`);
1428
- });
1429
- console.log('');
1430
- }
1431
- }
1432
- }
1433
- catch (error) {
1434
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1435
- process.exit(1);
1436
- }
1437
- });
1438
- // squish migrate - Migrate memories between databases
1439
- program
1440
- .command('migrate')
1441
- .description('Migrate memories from one .squish directory to another')
1442
- .option('-f, --from <path>', 'Source .squish directory (read from)', '')
1443
- .option('-t, --to <path>', 'Target .squish directory (write to)', '')
1444
- .option('--delete-source', 'Delete source after migration (use with caution)', false)
1445
- .option('--dry-run', 'Preview migration without applying', false)
1446
- .action(async (options) => {
1447
- try {
1448
- if (!options.from || !options.to) {
1449
- console.log(JSON.stringify({
1450
- ok: false,
1451
- error: 'Usage: squish migrate --from /path/to/old/.squish --to /path/to/new/.squish'
1452
- }, null, 2));
1453
- process.exit(1);
1454
- }
1455
- const sourcePath = path.join(options.from, 'squish.db');
1456
- const targetPath = path.join(options.to, 'squish.db');
1457
- if (!existsSync(sourcePath)) {
1458
- console.log(JSON.stringify({ ok: false, error: `Source database not found: ${sourcePath}` }, null, 2));
1459
- process.exit(1);
1460
- }
1461
- if (!existsSync(targetPath)) {
1462
- console.log(JSON.stringify({ ok: false, error: `Target database not found: ${targetPath}` }, null, 2));
1463
- process.exit(1);
1464
- }
1465
- console.log(`Migrating memories from:\n ${options.from}\nto:\n ${options.to}\n`);
1466
- // Import database modules dynamically
1467
- const { migrateMemories } = await import('./core/memory/migrate.js');
1468
- const result = await migrateMemories(options.from, options.to, {
1469
- dryRun: options.dryRun,
1470
- deleteSource: options.deleteSource
1471
- });
1472
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1473
- }
1474
- catch (error) {
1475
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1476
- process.exit(1);
1477
- }
1478
- });
1479
- // squish clean - Run deduplication and consolidation
1480
- program
1481
- .command('clean')
1482
- .description('Run maintenance: deduplication + consolidation')
1483
- .option('-t, --threshold <number>', 'Similarity threshold for dedup (0-1)', '0.85')
1484
- .option('-d, --min-age <days>', 'Minimum age for consolidation', '90')
1485
- .option('-i, --max-importance <number>', 'Max importance to consolidate (0-100)', '30')
1486
- .option('-c, --min-cluster <number>', 'Minimum cluster size', '3')
1487
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1488
- .option('--dry-run', 'Preview changes without applying', false)
1489
- .action(async (options) => {
1490
- try {
1491
- console.log('Running maintenance: deduplication + consolidation...\n');
1492
- // Step 1: Deduplication
1493
- console.log('Step 1: Finding duplicate memories...');
1494
- const dedupResult = await runDeduplicationJob(options.project);
1495
- console.log(` Found ${dedupResult.duplicatesFound} duplicates, merged ${dedupResult.mergedCount}`);
1496
- // Step 2: Consolidation
1497
- console.log('\nStep 2: Consolidating old memories...');
1498
- const consolidateResult = await runFullConsolidationJob(options.project);
1499
- console.log(` Clustered ${consolidateResult.clustered}, merged ${consolidateResult.merged}, consolidated ${consolidateResult.consolidated}`);
1500
- console.log(JSON.stringify({
1501
- ok: true,
1502
- dedup: {
1503
- duplicatesFound: dedupResult.duplicatesFound,
1504
- mergedCount: dedupResult.mergedCount,
1505
- tokensRecovered: dedupResult.tokensRecovered
1506
- },
1507
- consolidate: {
1508
- clustered: consolidateResult.clustered,
1509
- merged: consolidateResult.merged,
1510
- consolidated: consolidateResult.consolidated
1511
- }
1512
- }, null, 2));
1513
- }
1514
- catch (error) {
1515
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1516
- }
1517
- });
1518
- // squish hooks session-start --agent claude-code --mode startup
1519
- program
1520
- .command('hooks')
1521
- .description('Handle agent hooks (session-start, post-tool-use, session-end, pre-compact)')
1522
- .argument('<event>', 'Event type: session-start, post-tool-use, session-end, pre-compact')
1523
- .option('-a, --agent <agent>', 'Agent type: claude-code, opencode, cursor, windsurf', 'claude-code')
1524
- .option('-m, --mode <mode>', 'Mode for session-start: startup, resume, compact', 'startup')
1525
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1526
- .option('-t, --tool <tool>', 'Tool name for post-tool-use')
1527
- .option('--tool-input <json>', 'Tool input as JSON string')
1528
- .option('--tool-result <json>', 'Tool result as JSON string')
1529
- .option('--wip <work>', 'Work in progress for session-end')
1530
- .action(async (event, options) => {
1531
- try {
1532
- const agentType = options.agent;
1533
- const projectPath = options.project;
1534
- let result;
1535
- switch (event) {
1536
- case 'session-start':
1537
- result = await handleSessionStart({
1538
- projectPath,
1539
- mode: options.mode,
1540
- agentType,
1541
- });
1542
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1543
- break;
1544
- case 'post-tool-use':
1545
- if (!options.tool) {
1546
- console.log(JSON.stringify({ ok: false, error: '--tool required for post-tool-use' }, null, 2));
1547
- process.exit(1);
1548
- }
1549
- const toolInput = options.toolInput ? JSON.parse(options.toolInput) : {};
1550
- const toolResult = options.toolResult ? JSON.parse(options.toolResult) : {};
1551
- result = await handlePostToolUse({
1552
- toolName: options.tool,
1553
- toolInput,
1554
- toolResult,
1555
- projectPath,
1556
- agentType,
1557
- });
1558
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1559
- break;
1560
- case 'session-end':
1561
- result = await handleSessionEnd({
1562
- projectPath,
1563
- agentType,
1564
- workInProgress: options.wip,
1565
- });
1566
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1567
- break;
1568
- case 'pre-compact':
1569
- result = await handlePreCompact({
1570
- projectPath,
1571
- agentType,
1572
- });
1573
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1574
- break;
1575
- default:
1576
- console.log(JSON.stringify({ ok: false, error: `Unknown event: ${event}` }, null, 2));
1577
- process.exit(1);
1578
- }
1579
- }
1580
- catch (error) {
1581
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1582
- process.exit(1);
1583
- }
1584
- });
1585
- // squish walk - Walk through spatial memory places
1586
- program
1587
- .command('walk [place]')
1588
- .description('Walk through spatial memory places (entry_hall, library, workshop, lab, office, garden, archive, or --all)')
1589
- .option('-a, --all', 'Walk all places in order', false)
1590
- .option('-t, --tokens <number>', 'Max tokens budget (default: 170)', '170')
1591
- .option('-m, --max <number>', 'Max memories per place', '10')
1592
- .option('-p, --project <project>', 'Project path', getDefaultProjectPath())
1593
- .option('-q, --quick', 'Quick tour (place names only)', false)
1594
- .option('-j, --json', 'Output as JSON', false)
1595
- .action(async (place, options) => {
1596
- try {
1597
- const projectPath = resolveProjectPath(options.project);
1598
- await ensureProject(projectPath);
1599
- const project = await getOrCreateProject(projectPath);
1600
- if (!project) {
1601
- console.log(JSON.stringify({ ok: false, error: 'Project not found' }, null, 2));
1602
- process.exit(1);
1603
- }
1604
- // Ensure places are initialized
1605
- await initializeDefaultPlaces(project.id);
1606
- if (options.quick) {
1607
- const tour = await quickTour(project.id);
1608
- if (options.json) {
1609
- console.log(JSON.stringify({ ok: true, ...tour }, null, 2));
1610
- }
1611
- else {
1612
- console.log(`\n=== Spatial Memory Tour ===\n`);
1613
- console.log(`Total Memories: ${tour.totalMemories}\n`);
1614
- for (const p of tour.places) {
1615
- console.log(`${p.name} (${p.memoryCount} memories)`);
1616
- console.log(` ${p.purpose}\n`);
1617
- }
1618
- }
1619
- return;
1620
- }
1621
- const tokenBudget = parseInt(options.tokens);
1622
- const maxMemories = parseInt(options.max);
1623
- if (options.all) {
1624
- const results = await walkAllPlaces(project.id, {
1625
- tokenBudget: Math.floor(tokenBudget / 7),
1626
- maxMemoriesPerPlace: maxMemories,
1627
- compressWithToon: true,
1628
- });
1629
- if (options.json) {
1630
- console.log(JSON.stringify({ ok: true, places: results }, null, 2));
1631
- }
1632
- else {
1633
- console.log(`\n=== Walking All Places ===\n`);
1634
- for (const r of results) {
1635
- console.log(`## ${r.place.name} (${r.memories.length} memories, ~${r.totalTokens} tokens)`);
1636
- r.memories.forEach((m, i) => {
1637
- console.log(` ${i + 1}. ${m.content.substring(0, 60)}...`);
1638
- });
1639
- console.log('');
1640
- }
1641
- }
1642
- }
1643
- else if (place) {
1644
- const validPlaces = ['entry_hall', 'library', 'workshop', 'lab', 'office', 'garden', 'archive'];
1645
- const placeType = validPlaces.includes(place) ? place : 'workshop';
1646
- const result = await walkPlace(project.id, placeType, {
1647
- tokenBudget,
1648
- maxMemoriesPerPlace: maxMemories,
1649
- compressWithToon: true,
1650
- });
1651
- if (options.json) {
1652
- console.log(JSON.stringify({ ok: true, ...result }, null, 2));
1653
- }
1654
- else if (result) {
1655
- console.log(`\n=== ${result.place.name} ===\n`);
1656
- console.log(`Purpose: ${result.place.purpose || 'N/A'}\n`);
1657
- result.memories.forEach((m, i) => {
1658
- console.log(`${i + 1}. [${m.type}] ${m.content.substring(0, 80)}`);
1659
- });
1660
- console.log(`\n~${result.totalTokens} tokens`);
1661
- }
1662
- else {
1663
- console.log(JSON.stringify({ ok: false, error: `Place not found: ${place}` }, null, 2));
1664
- }
1665
- }
1666
- }
1667
- catch (error) {
1668
- console.log(JSON.stringify({ ok: false, error: error.message }, null, 2));
1669
- process.exit(1);
1670
- }
1671
- });
1672
- await program.parseAsync(process.argv);
1673
- }
1674
- // MCP server: core/commands/mcp-server.ts
1675
- // Run with: npx squish-mcp
1676
- // ============================================================================
1677
- //# sourceMappingURL=index.js.map