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
@@ -0,0 +1,940 @@
1
+ #!/usr/bin/env node
2
+
3
+ // CRITICAL: Redirect console.log to stderr to prevent JSON-RPC stream corruption
4
+ // MCP stdio requires stdout to contain ONLY valid JSON-RPC messages
5
+ console.log = console.error;
6
+ console.info = console.error;
7
+
8
+ // Check for silent mode BEFORE any imports to prevent log spam during module load
9
+ const EARLY_SILENT = process.argv.includes('--silent') || process.env.SQUISH_MCP_SILENT === 'true';
10
+ if (EARLY_SILENT) {
11
+ // Suppress scheduler spam during module load
12
+ // We'll restore AFTER imports are done
13
+ process.env.SQUISH_QUIET = 'true';
14
+ }
15
+
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
19
+ import express from "express";
20
+ import { z } from "zod";
21
+ import { config } from "../../../config.js";
22
+ import { getDb } from "../../../db/index.js";
23
+ import { getSchema } from "../../../db/schema.js";
24
+ import { eq } from "drizzle-orm";
25
+ export function startWorker() {
26
+ throw new Error('[DEBUG] startWorker called - need to find where!');
27
+ }
28
+ import { initializeScheduler } from "../../../core/scheduler/cron-scheduler.js";
29
+ import { parseDate, filterByDateRange } from "../../../core/lib/utils.js";
30
+ import {
31
+ buildContextState,
32
+ buildHealthState,
33
+ buildInspectState,
34
+ buildStatsState,
35
+ resolveProjectScope,
36
+ } from "../../../core/runtime/trust-state.js";
37
+ import { rememberMemory, search as searchMemories, getMemory, getRecent, type MemoryType } from "../../../core/memory/memories.js";
38
+ import { getQMDClient } from "../../../core/embeddings/qmd-client.js";
39
+ import { createAssociation, getRelatedMemories, type AssociationType } from "../../../core/associations.js";
40
+ import { createLearning } from "../../../core/ingestion/learnings.js";
41
+ import { getAllProjects } from "../../../core/projects.js";
42
+ import { logger } from "../../../core/logger.js";
43
+
44
+ const SERVER_NAME = "squish-memory";
45
+ const SERVER_VERSION = "1.2.0";
46
+
47
+ // Create server lazily (only when needed) - avoids init overhead during module load
48
+ let SQUISH_SERVER: McpServer | null = null;
49
+ let SQUISH_TOOL_COUNT = 0;
50
+
51
+ function getSquishServer(): { server: McpServer; toolCount: number } {
52
+ if (!SQUISH_SERVER) {
53
+ const result = createSquishServer();
54
+ SQUISH_SERVER = result.server;
55
+ SQUISH_TOOL_COUNT = result.toolCount;
56
+ const silent = process.env.SQUISH_MCP_SILENT === 'true';
57
+ if (!silent) console.error(`[MCP] Server created with ${SQUISH_TOOL_COUNT} tools`);
58
+ }
59
+ return { server: SQUISH_SERVER!, toolCount: SQUISH_TOOL_COUNT };
60
+ }
61
+
62
+ function parseArgs(): { mode: "stdio" | "http"; port: number; health: boolean } {
63
+ const args = process.argv.slice(2);
64
+ let mode: "stdio" | "http" = "stdio";
65
+ let port = config.mcpServerPort || 8767;
66
+ let health = false;
67
+
68
+ for (let i = 0; i < args.length; i++) {
69
+ if (args[i] === "--http" || args[i] === "-h") {
70
+ mode = "http";
71
+ } else if (args[i] === "--stdio" || args[i] === "-s") {
72
+ mode = "stdio";
73
+ } else if (args[i] === "--port" || args[i] === "-p") {
74
+ port = parseInt(args[i + 1], 10) || 8767;
75
+ i++;
76
+ } else if (args[i] === "--health" || args[i] === "--check") {
77
+ health = true;
78
+ }
79
+ }
80
+
81
+ if (process.env.SQUISH_MCP_MODE === "http") {
82
+ mode = "http";
83
+ }
84
+
85
+ return { mode, port, health };
86
+ }
87
+
88
+ function safeRegisterTool(
89
+ server: McpServer,
90
+ name: string,
91
+ definition: any,
92
+ handler: any
93
+ ): boolean {
94
+ try {
95
+ server.registerTool(name, definition, handler);
96
+ console.error(`[MCP] Registered tool: ${name}`);
97
+ return true;
98
+ } catch (error) {
99
+ console.error(`[MCP] Failed to register tool ${name}:`, error);
100
+ return false;
101
+ }
102
+ }
103
+
104
+ function createSquishServer(): { server: McpServer; toolCount: number } {
105
+ const server = new McpServer(
106
+ { name: SERVER_NAME, version: SERVER_VERSION },
107
+ { capabilities: { tools: {} } }
108
+ );
109
+
110
+ let toolCount = 0;
111
+
112
+ console.error(`[MCP] Starting tool registration...`);
113
+
114
+ // squish_timeline - 3-layer progressive disclosure
115
+ if (safeRegisterTool(
116
+ server,
117
+ "squish_timeline",
118
+ {
119
+ description: "3-layer progressive disclosure - index (~50 tokens), timeline (~200 tokens), detail (~2000 tokens)",
120
+ inputSchema: {
121
+ query: z.string().describe("Search query"),
122
+ depth: z.enum(["index", "timeline", "detail"]).default("index").describe("Progressive disclosure depth"),
123
+ limit: z.number().min(1).max(100).default(10).describe("Max results"),
124
+ project: z.string().optional().describe("Project path")
125
+ }
126
+ },
127
+ async ({ query, depth = "index", limit = 10, project }: { query: string; depth?: "index" | "timeline" | "detail"; limit?: number; project?: string }) => {
128
+ const { getTimeline } = await import('../../../core/adapters/timeline.js');
129
+ const result = await getTimeline(query, depth, limit, project);
130
+
131
+ const formatted = result.results.map((r: any, i: number) => {
132
+ if (depth === "index") {
133
+ return `${i + 1}. ${r.title}`;
134
+ } else if (depth === "timeline") {
135
+ return `${i + 1}. [${r.type}] ${r.content} (${r.tags?.join(', ') || 'no tags'})`;
136
+ } else {
137
+ return `${i + 1}. [${r.type}] ${r.content?.substring(0, 200)}...`;
138
+ }
139
+ }).join("\n");
140
+
141
+ return { content: [{ type: "text", text: `Timeline (${depth}, ~${result.tokenEstimate} tokens):\n\n${formatted}` }] };
142
+ }
143
+ )) toolCount++;
144
+
145
+ // squish_remember - UNIFIED MEMORY WRITE
146
+ // Single smart write path: auto-detects intent and routes to memory or learning
147
+ if (safeRegisterTool(
148
+ server,
149
+ "squish_remember",
150
+ {
151
+ description: "Store any memory or learning. System auto-detects type and routes appropriately. This is THE memory write tool for agents - handles hot/cold tiers, confidence, and all memory types.",
152
+ inputSchema: {
153
+ content: z.string().describe("What to remember - can be a fact, decision, lesson, observation, or note"),
154
+ project: z.string().optional().describe("Project path (auto-detected if not provided)"),
155
+ tags: z.array(z.string()).optional().describe("Optional tags for organization"),
156
+ tier: z.enum(["hot", "cold"]).default("hot").describe("Memory tier: hot=active/frequently accessed, cold=archived (simplified, warm removed)"),
157
+ type: z.enum(["observation", "fact", "decision", "context", "preference", "note"]).optional().describe("Memory type - auto-detected if not provided"),
158
+ learningType: z.enum(["success", "failure", "fix", "insight"]).optional().describe("Learning type when routing to learning storage"),
159
+ confidence: z.number().min(0).max(100).optional().describe("Confidence level 0-100 (default: auto-calculated)"),
160
+ source: z.string().optional().describe("Source of memory: mcp, cli, voice, chat, document (default: mcp)"),
161
+ route: z.enum(["auto", "memory", "learning", "note"]).default("auto").describe("Force routing: auto=detect, memory=store as memory, learning=store as learning, note=store as note"),
162
+ pin: z.boolean().default(false).describe("Pin memory to prevent pruning/consolidation"),
163
+ unpin: z.boolean().default(false).describe("Unpin memory")
164
+ }
165
+ },
166
+ async ({ content, project, tags = [], tier = "hot", type, learningType, confidence, source, route = "auto", pin = false, unpin = false }: {
167
+ content: string;
168
+ project?: string;
169
+ tags?: string[];
170
+ tier?: "hot" | "cold";
171
+ type?: "observation" | "fact" | "decision" | "context" | "preference" | "note";
172
+ learningType?: "success" | "failure" | "fix" | "insight";
173
+ confidence?: number;
174
+ source?: string;
175
+ route?: "auto" | "memory" | "learning" | "note";
176
+ pin?: boolean;
177
+ unpin?: boolean;
178
+ }) => {
179
+ // Import detection function
180
+ const { detectMemorySignals } = await import('../../../core/memory/trigger-detector.js');
181
+ const signals = detectMemorySignals(content);
182
+
183
+ let routing: "memory" | "learning" | "note" = "memory";
184
+ let inferredType = type || signals.suggestedType;
185
+ let routingReason = "";
186
+
187
+ // Check for learning patterns if auto mode
188
+ if (route === "auto") {
189
+ const hasLessonPattern = /(\bfailed\s+because\b|\blesson\s+learned\b|\bnext\s+time\b|\broot\s+cause\b|\bsuccess\b.*\bbecause\b|\bi\s+learned\b|\binsight\b)/i.test(content);
190
+ const hasLearningType = /(\bsuccess\b|\bfailure\b|\bfix\b|\binsight\b)/i.test(content);
191
+
192
+ // Enhanced learning detection from rationale patterns
193
+ const hasHackPattern = /(\bHACK\b|\bworkaround\b|\btemporary\s+fix\b)/i.test(content);
194
+ const hasFixmePattern = /(\bFIXME\b|\bXXX\b|\bbug\b.*\bfix\b)/i.test(content);
195
+
196
+ if (hasLessonPattern || hasLearningType || hasHackPattern || hasFixmePattern) {
197
+ routing = "learning";
198
+ if (hasHackPattern || hasFixmePattern) {
199
+ routingReason = "Detected code pattern (HACK/FIXME)";
200
+ } else {
201
+ routingReason = "Detected learning pattern in content";
202
+ }
203
+ } else if (signals.suggestedType === 'task') {
204
+ routing = "memory";
205
+ routingReason = "Detected TODO pattern";
206
+ } else if (signals.suggestedType === 'observation' && /\b(note|note\s+that|log|remember)\b/i.test(content)) {
207
+ routing = "note";
208
+ routingReason = "Detected note pattern";
209
+ } else {
210
+ routing = "memory";
211
+ routingReason = `Detected as ${inferredType}`;
212
+ }
213
+ } else if (route === "learning") {
214
+ routing = "learning";
215
+ routingReason = "Override: forced to learning";
216
+ } else if (route === "note") {
217
+ routing = "note";
218
+ routingReason = "Override: forced to note";
219
+ } else {
220
+ routing = "memory";
221
+ routingReason = "Override: forced to memory";
222
+ }
223
+
224
+ let result: any;
225
+
226
+ if (routing === "learning") {
227
+ // Determine learning type from content or override
228
+ let finalLearningType = learningType || "insight";
229
+ if (!learningType) {
230
+ if (/(\bsuccess\b|\bworked\b|\bfinished\b)/i.test(content)) finalLearningType = "success";
231
+ else if (/(\bfailed\b|\berror\b|\bbroke\b)/i.test(content)) finalLearningType = "failure";
232
+ else if (/(\bfix\b|\b workaround\b|\bsolved\b)/i.test(content)) finalLearningType = "fix";
233
+ }
234
+
235
+ const learning = await createLearning({
236
+ type: finalLearningType,
237
+ content,
238
+ project,
239
+ autoLink: true
240
+ });
241
+ result = { id: learning.id, type: "learning", learningType: finalLearningType, content };
242
+ } else {
243
+ // Store as memory with all options
244
+ const memory = await rememberMemory({
245
+ content,
246
+ type: inferredType as any,
247
+ tags,
248
+ project,
249
+ tier,
250
+ source: source || 'mcp'
251
+ });
252
+
253
+ // Handle pin/unpin after creation
254
+ if (pin) {
255
+ const { pinMemory } = await import('../../../core/security/governance.js');
256
+ await pinMemory(memory.id);
257
+ } else if (unpin) {
258
+ const { unpinMemory } = await import('../../../core/security/governance.js');
259
+ await unpinMemory(memory.id);
260
+ }
261
+
262
+ result = { id: memory.id, type: "memory", memoryType: inferredType, tier, content, pined: pin };
263
+
264
+ // Auto-update knowledge graph (fire-and-forget)
265
+ const { addMemoryToGraph } = await import('../../../core/graph/graph-builder.js');
266
+ const graphResult = await addMemoryToGraph(memory.id).catch((e: Error) => {
267
+ console.warn('[Graph] Auto-update failed:', e.message);
268
+ return null;
269
+ });
270
+ if (graphResult) {
271
+ (result as any).graph = { entities: graphResult.entitiesCreated, relations: graphResult.relationsCreated };
272
+ }
273
+ }
274
+
275
+ return {
276
+ content: [{
277
+ type: "text",
278
+ text: `Remembered: ${result.id}\nRouting: ${routing}\nType: ${routing === "learning" ? result.learningType : result.memoryType}\nTier: ${routing === "memory" ? tier : 'N/A'}\nPriority: ${signals.priority}\nConfidence: ${signals.confidence}\nPined: ${(result as any).pinned}\nReason: ${routingReason}\n\n${content.substring(0, 100)}${content.length > 100 ? '...' : ''}`
279
+ }]
280
+ };
281
+ }
282
+ )) toolCount++;
283
+
284
+ // squish_recall - Retrieve a memory by ID or query
285
+ if (safeRegisterTool(
286
+ server,
287
+ "squish_recall",
288
+ {
289
+ description: "Recall memories by query, or retrieve a specific memory by ID",
290
+ inputSchema: {
291
+ query: z.string().describe("Query text or memory ID to recall"),
292
+ limit: z.number().min(1).max(100).default(5).describe("Maximum results for query recall"),
293
+ project: z.string().optional().describe("Project path filter"),
294
+ type: z.enum(["observation", "fact", "decision", "context", "preference", "note", "task"]).optional().describe("Filter by memory type"),
295
+ place: z.string().optional().describe("Filter by place (inbox, ref, wip, sandbox, board, sparks, archive)")
296
+ }
297
+ },
298
+ async ({ query, limit = 5, project, type, place }: { query: string; limit?: number; project?: string; type?: MemoryType; place?: string }) => {
299
+ 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);
300
+
301
+ if (isUuid) {
302
+ const memory = await getMemory(query);
303
+ if (!memory) {
304
+ return { content: [{ type: "text", text: `Memory not found: ${query}` }], isError: true };
305
+ }
306
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, count: 1, results: [memory] }, null, 2) }] };
307
+ }
308
+
309
+ const results = await searchMemories({
310
+ query,
311
+ limit,
312
+ project,
313
+ type,
314
+ placeType: place
315
+ });
316
+
317
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, count: results.length, results }, null, 2) }] };
318
+ }
319
+ )) toolCount++;
320
+
321
+ // squish_forget - Delete a memory by ID, or bulk delete with filters
322
+ if (safeRegisterTool(
323
+ server,
324
+ "squish_forget",
325
+ {
326
+ description: "Delete a memory by ID, or bulk delete with filters (older-than, search, type)",
327
+ inputSchema: {
328
+ memoryId: z.string().optional().describe("Memory ID to delete (single)"),
329
+ olderThan: z.string().optional().describe("Bulk delete memories older than (e.g., '30 days', '6 months')"),
330
+ search: z.string().optional().describe("Search query to match specific memories"),
331
+ type: z.string().optional().describe("Filter by memory type"),
332
+ confirm: z.boolean().optional().describe("Actually delete (default is dry-run)"),
333
+ limit: z.number().optional().describe("Max memories to delete"),
334
+ project: z.string().optional().describe("Project path (defaults to current)")
335
+ }
336
+ },
337
+ async ({ memoryId, olderThan, search, type, confirm = false, limit = 100, project }: { memoryId?: string; olderThan?: string; search?: string; type?: string; confirm?: boolean; limit?: number; project?: string }) => {
338
+ const db = await getDb();
339
+ const schema = await getSchema();
340
+ const sqliteDb = db as any;
341
+ const proj = project || process.cwd();
342
+
343
+ // Single memory deletion
344
+ if (memoryId) {
345
+ await sqliteDb.delete(schema.memories).where(eq(schema.memories.id, memoryId));
346
+ return { content: [{ type: "text", text: `Memory deleted: ${memoryId}` }] };
347
+ }
348
+
349
+ // Bulk deletion
350
+ if (!olderThan && !search) {
351
+ return { content: [{ type: "text", text: "Error: Provide memoryId or use --older-than / --search for bulk delete" }], isError: true };
352
+ }
353
+
354
+ const results = await searchMemories({ query: search || '', type: type as MemoryType, limit, project: proj });
355
+
356
+ let filtered = results;
357
+ if (olderThan) {
358
+ filtered = filterByDateRange(results, '', olderThan);
359
+ }
360
+
361
+ const deleted = [];
362
+ if (confirm) {
363
+ for (const mem of filtered) {
364
+ await sqliteDb.delete(schema.memories).where(eq(schema.memories.id, mem.id));
365
+ deleted.push(mem.id);
366
+ }
367
+ }
368
+
369
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, matched: filtered.length, deleted: deleted.length, dryRun: !confirm }, null, 2) }] };
370
+ }
371
+ )) toolCount++;
372
+
373
+
374
+ // squish_link - Unified graph operations (find related, add links, list)
375
+ if (safeRegisterTool(
376
+ server,
377
+ "squish_link",
378
+ {
379
+ description: "Manage memory associations: find related memories, add links, or list associations",
380
+ inputSchema: {
381
+ action: z.enum(["find", "add", "list"]).describe("Action: find, add, or list"),
382
+ memoryId: z.string().optional().describe("Memory ID (for find action)"),
383
+ fromMemoryId: z.string().optional().describe("Source memory ID (for add action)"),
384
+ toMemoryId: z.string().optional().describe("Target memory ID (for add action)"),
385
+ type: z.string().optional().describe("Association type (for add action): relates_to, supports, contradicts, supersedes, duplicate"),
386
+ weight: z.number().min(0).max(1).default(0.5).describe("Association strength (0-1)"),
387
+ depth: z.number().min(1).max(5).default(2).describe("Graph traversal depth (for find action)"),
388
+ minWeight: z.number().min(0).max(1).default(0.3).describe("Minimum weight (for find action)")
389
+ }
390
+ },
391
+ async ({ action, memoryId, fromMemoryId, toMemoryId, type = "relates_to", weight = 0.5, depth = 2, minWeight = 0.3 }: { action: "find" | "add" | "list"; memoryId?: string; fromMemoryId?: string; toMemoryId?: string; type?: string; weight?: number; depth?: number; minWeight?: number }) => {
392
+ if (action === "find") {
393
+ if (!memoryId) {
394
+ return { content: [{ type: "text", text: "Error: memoryId required for find action" }], isError: true };
395
+ }
396
+ const related = await getRelatedMemories(memoryId, depth * 5);
397
+ const filtered = related.filter((r: any) => r.weight >= minWeight);
398
+ const formatted = filtered.map((r: any, i: number) =>
399
+ `${i + 1}. [${r.type || "memory"}] ${r.content?.substring(0, 100)}... (weight: ${r.weight?.toFixed(2)})`
400
+ ).join("\n");
401
+ return { content: [{ type: "text", text: `Found ${filtered.length} related memories:\n\n${formatted}` }] };
402
+ }
403
+
404
+ if (action === "add") {
405
+ if (!fromMemoryId || !toMemoryId) {
406
+ return { content: [{ type: "text", text: "Error: fromMemoryId and toMemoryId required for add action" }], isError: true };
407
+ }
408
+ await createAssociation(fromMemoryId, toMemoryId, type as AssociationType, weight);
409
+
410
+ // Auto-update knowledge graph (fire-and-forget)
411
+ try {
412
+ const { addMemoryToGraph } = await import('../../../core/graph/graph-builder.js');
413
+ await Promise.all([
414
+ addMemoryToGraph(fromMemoryId).catch(() => null),
415
+ addMemoryToGraph(toMemoryId).catch(() => null)
416
+ ]);
417
+ } catch (e) {
418
+ // Ignore graph errors
419
+ }
420
+
421
+ return { content: [{ type: "text", text: `Association created: ${fromMemoryId} -> ${toMemoryId} (${type})` }] };
422
+ }
423
+
424
+ if (action === "list") {
425
+ const db = await getDb();
426
+ const schema = await getSchema();
427
+ const sqliteDb = db as any;
428
+ const associations = await sqliteDb.select().from(schema.memoryAssociations).limit(100);
429
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, count: associations.length, associations }, null, 2) }] };
430
+ }
431
+
432
+ return { content: [{ type: "text", text: "Error: invalid action. Use find, add, or list" }], isError: true };
433
+ }
434
+ )) toolCount++;
435
+
436
+ // squish_context - Get project context or list registered projects
437
+ if (safeRegisterTool(
438
+ server,
439
+ "squish_context",
440
+ {
441
+ description: "Get project context or list registered projects",
442
+ inputSchema: {
443
+ project: z.string().optional().describe("Project path"),
444
+ limit: z.number().min(1).max(50).default(10).describe("Maximum memories to return"),
445
+ listProjects: z.boolean().optional().describe("List registered projects instead of loading context")
446
+ }
447
+ },
448
+ async ({ project, limit = 10, listProjects = false }: { project?: string; limit?: number; listProjects?: boolean }) => {
449
+ if (listProjects) {
450
+ const projects = await getAllProjects();
451
+ const scope = await resolveProjectScope(project);
452
+ return {
453
+ content: [{
454
+ type: "text",
455
+ text: JSON.stringify({
456
+ ok: true,
457
+ count: projects.length,
458
+ currentProject: scope.currentProject,
459
+ otherProjects: scope.otherProjects,
460
+ projects: projects.map((entry) => ({
461
+ id: entry.id,
462
+ name: entry.name,
463
+ path: entry.path,
464
+ resolution: entry.path === '.' ? 'legacy-placeholder' : (entry.metadata?.source === 'mcp' ? 'auto-created' : 'inferred'),
465
+ })),
466
+ nextStep: scope.nextStep,
467
+ }, null, 2),
468
+ }],
469
+ };
470
+ }
471
+
472
+ const context = await buildContextState(project, limit);
473
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, ...context }, null, 2) }] };
474
+ }
475
+ )) toolCount++;
476
+
477
+ // squish_health - Check Squish system health status
478
+ if (safeRegisterTool(
479
+ server,
480
+ "squish_health",
481
+ {
482
+ description: "Check Squish system health status",
483
+ inputSchema: {
484
+ project: z.string().optional().describe("Project path")
485
+ }
486
+ },
487
+ async ({ project }: { project?: string }): Promise<{ content: Array<{ type: string; text: string }> }> => {
488
+ const qmdClient = await getQMDClient();
489
+ const qmdAvailable = await qmdClient.isAvailable();
490
+ const health = await buildHealthState(project);
491
+
492
+ return { content: [{ type: "text", text: JSON.stringify({
493
+ ok: health.severity !== "broken",
494
+ version: SERVER_VERSION,
495
+ qmd: qmdAvailable ? "available" : "unavailable",
496
+ timestamp: new Date().toISOString(),
497
+ ...health,
498
+ }, null, 2) }] };
499
+ }
500
+ )) toolCount++;
501
+
502
+ // squish_stats - Get memory statistics for a project
503
+ if (safeRegisterTool(
504
+ server,
505
+ "squish_stats",
506
+ {
507
+ description: "Get memory statistics for a project",
508
+ inputSchema: {
509
+ project: z.string().optional().describe("Project path (defaults to current)")
510
+ }
511
+ },
512
+ async ({ project }: { project?: string }) => {
513
+ const stats = await buildStatsState(project || process.cwd());
514
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, ...stats }, null, 2) }] };
515
+ }
516
+ )) toolCount++;
517
+
518
+ // squish_inspect - Explain why a memory was retained
519
+ if (safeRegisterTool(
520
+ server,
521
+ "squish_inspect",
522
+ {
523
+ description: "Explain why a memory was retained, where it was routed, and whether raw fallback exists",
524
+ inputSchema: {
525
+ memoryId: z.string().uuid().describe("Memory ID to inspect")
526
+ }
527
+ },
528
+ async ({ memoryId }: { memoryId: string }) => {
529
+ const inspection = await buildInspectState(memoryId);
530
+ if (!inspection) {
531
+ return { content: [{ type: "text", text: `Memory not found: ${memoryId}` }], isError: true };
532
+ }
533
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, inspection }, null, 2) }] };
534
+ }
535
+ )) toolCount++;
536
+
537
+ // squish_pin - Pin or unpin a memory to prevent consolidation
538
+ if (safeRegisterTool(
539
+ server,
540
+ "squish_pin",
541
+ {
542
+ description: "Pin or unpin a memory to prevent consolidation",
543
+ inputSchema: {
544
+ memoryId: z.string().uuid().describe("Memory ID"),
545
+ pinned: z.boolean().default(true).describe("Pin (true) or unpin (false)")
546
+ }
547
+ },
548
+ async ({ memoryId, pinned }: { memoryId: string; pinned: boolean }) => {
549
+ const db = await getDb();
550
+ const schema = await getSchema();
551
+ const sqliteDb = db as any;
552
+
553
+ await sqliteDb.update(schema.memories)
554
+ .set({ isPinned: pinned })
555
+ .where(eq(schema.memories.id, memoryId));
556
+
557
+ return { content: [{ type: "text", text: `Memory ${memoryId} ${pinned ? 'pinned' : 'unpinned'}` }] };
558
+ }
559
+ )) toolCount++;
560
+
561
+ // squish_recent - Get recent memories by period
562
+ if (safeRegisterTool(
563
+ server,
564
+ "squish_recent",
565
+ {
566
+ description: "Get recent memories by period (today, yesterday, thisweek, 7days, 30days, or custom)",
567
+ inputSchema: {
568
+ period: z.string().optional().describe("Period: today, yesterday, thisweek, 7days, 14days, 30days, 90days"),
569
+ since: z.string().optional().describe("Start date (alternative to period, e.g., '3 days', '2026-01-01')"),
570
+ until: z.string().optional().describe("End date (alternative to period, e.g., 'now', '2026-01-15')"),
571
+ limit: z.number().optional().describe("Max results to return"),
572
+ project: z.string().optional().describe("Project path (defaults to current)")
573
+ }
574
+ },
575
+ async ({ period = 'today', since, until, limit = 10, project }: { period?: string; since?: string; until?: string; limit?: number; project?: string }) => {
576
+ const proj = project || process.cwd();
577
+ let sinceDate: string, untilDate: string;
578
+
579
+ if (since && until) {
580
+ sinceDate = since;
581
+ untilDate = until;
582
+ } else if (since) {
583
+ sinceDate = since;
584
+ untilDate = 'now';
585
+ } else {
586
+ const periodMap: Record<string, [string, string]> = {
587
+ today: ['today', 'now'],
588
+ yesterday: ['yesterday', 'today'],
589
+ thisweek: ['thisweek', 'now'],
590
+ '7days': ['7 days', 'now'],
591
+ '14days': ['14 days', 'now'],
592
+ '30days': ['30 days', 'now'],
593
+ '90days': ['90 days', 'now'],
594
+ };
595
+ const mapped = periodMap[period];
596
+ if (mapped) {
597
+ [sinceDate, untilDate] = mapped;
598
+ } else {
599
+ sinceDate = period;
600
+ untilDate = 'now';
601
+ }
602
+ }
603
+
604
+ const results = await getRecent(proj, 100);
605
+ const filtered = filterByDateRange(results, sinceDate, untilDate);
606
+ const limited = filtered.slice(0, limit);
607
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, period, since: sinceDate, until: untilDate, count: limited.length, results: limited }, null, 2) }] };
608
+ }
609
+ )) toolCount++;
610
+
611
+ // squish_stale - Show stale memories
612
+ if (safeRegisterTool(
613
+ server,
614
+ "squish_stale",
615
+ {
616
+ description: "Show stale memories (old, low-confidence, or rarely accessed)",
617
+ inputSchema: {
618
+ days: z.number().optional().describe("Show memories older than N days"),
619
+ limit: z.number().optional().describe("Max results to return"),
620
+ project: z.string().optional().describe("Project path (defaults to current)")
621
+ }
622
+ },
623
+ async ({ days = 30, limit = 20, project }: { days?: number; limit?: number; project?: string }) => {
624
+ const proj = project || process.cwd();
625
+ const cutoffDate = new Date(Date.now() - days * 86400000);
626
+ const results = await getRecent(proj, 500);
627
+ const stale = results.filter((m: any) => {
628
+ const created = m.createdAt ? new Date(m.createdAt) : null;
629
+ const isOld = created && created < cutoffDate;
630
+ const isLowConfidence = m.confidenceLevel === 'outdated' || m.confidenceLevel === 'speculative';
631
+ const hasLowImportance = (m.importance || 50) < 40;
632
+ return isOld || isLowConfidence || hasLowImportance;
633
+ });
634
+ const limited = stale.slice(0, limit);
635
+ const summary = {
636
+ totalStale: stale.length,
637
+ old: stale.filter((m: any) => m.createdAt && new Date(m.createdAt) < cutoffDate).length,
638
+ lowConfidence: stale.filter((m: any) => m.confidenceLevel === 'outdated' || m.confidenceLevel === 'speculative').length,
639
+ lowImportance: stale.filter((m: any) => (m.importance || 50) < 40).length,
640
+ };
641
+ return { content: [{ type: "text", text: JSON.stringify({ ok: true, summary, memories: limited }, null, 2) }] };
642
+ }
643
+ )) toolCount++;
644
+
645
+ console.error(`[MCP] Tool registration complete. Registered ${toolCount} tools.`);
646
+
647
+ return { server, toolCount };
648
+ }
649
+
650
+ async function runStdio(server: McpServer, toolCount: number, lazyHooks?: { startWorkerIfNeeded: () => Promise<void>; startSchedulerIfNeeded: () => Promise<void> }): Promise<void> {
651
+ // Don't start worker/scheduler here - only start on first actual tool call
652
+ // This fixes MCP stdio initialization timing
653
+
654
+ const silent = process.env.SQUISH_MCP_SILENT === 'true';
655
+ if (!silent) console.error(`[MCP] Starting in STDIO mode...`);
656
+ const transport = new StdioServerTransport();
657
+
658
+ transport.onclose = () => {
659
+ if (!silent) console.error(`[MCP] STDIO transport closed`);
660
+ };
661
+
662
+ await server.connect(transport);
663
+ if (!silent) console.error(`[MCP] Connected via stdio. ${toolCount} tools available.`);
664
+
665
+ // Keep process alive - wait for stdin to close or process signals
666
+ await new Promise<void>((resolve) => {
667
+ process.stdin.on('close', () => {
668
+ console.error(`[MCP] STDIO stdin closed, shutting down`);
669
+ resolve();
670
+ });
671
+
672
+ process.on('SIGINT', () => {
673
+ console.error(`[MCP] Received SIGINT, shutting down`);
674
+ resolve();
675
+ });
676
+
677
+ process.on('SIGTERM', () => {
678
+ console.error(`[MCP] Received SIGTERM, shutting down`);
679
+ resolve();
680
+ });
681
+ });
682
+ }
683
+
684
+ async function runHttp(server: McpServer, port: number, lazyHooks?: { startWorkerIfNeeded: () => Promise<void>; startSchedulerIfNeeded: () => Promise<void> }): Promise<void> {
685
+ // Don't start worker/scheduler here - only when tools are called
686
+
687
+ const silent = process.env.SQUISH_MCP_SILENT === 'true';
688
+ if (!silent) console.error(`[MCP] Starting in Streamable HTTP mode on port ${port}...`);
689
+
690
+ const app = express();
691
+ app.use(express.json({ strict: false }));
692
+
693
+ // Store transports by session ID
694
+ const transports = new Map<string, StreamableHTTPServerTransport>();
695
+
696
+ // Helper to check if request is an initialization request
697
+ function isInitializeRequest(body: any): boolean {
698
+ return body?.method === 'initialize';
699
+ }
700
+
701
+ // Health check endpoint
702
+ app.get("/health", (req, res) => {
703
+ res.json({ status: "ok", server: SERVER_NAME, version: SERVER_VERSION });
704
+ });
705
+
706
+ // Streamable HTTP POST endpoint
707
+ app.post("/mcp", async (req, res) => {
708
+ const sessionId = req.headers["mcp-session-id"] as string | undefined;
709
+ const body = req.body;
710
+
711
+ let transport: StreamableHTTPServerTransport | undefined;
712
+ let serverToUse: McpServer | undefined;
713
+
714
+ // Check if we have an existing transport for this session
715
+ if (sessionId && transports.has(sessionId)) {
716
+ transport = transports.get(sessionId);
717
+ serverToUse = server;
718
+ }
719
+
720
+ // If no existing transport, create new one (only for initialize requests)
721
+ if (!transport) {
722
+ if (!isInitializeRequest(body)) {
723
+ res.status(400).json({
724
+ jsonrpc: '2.0',
725
+ error: { code: -32000, message: 'Bad Request: No valid session ID and not an initialize request' },
726
+ id: body?.id || null
727
+ });
728
+ return;
729
+ }
730
+
731
+ // Create NEW server instance for this session (required - can't reuse)
732
+ const { server: newServer } = createSquishServer();
733
+ serverToUse = newServer;
734
+
735
+ // Create new transport with JSON response mode
736
+ transport = new StreamableHTTPServerTransport({
737
+ sessionIdGenerator: () => crypto.randomUUID(),
738
+ enableJsonResponse: true,
739
+ onsessioninitialized: (newSessionId: string) => {
740
+ console.error(`[MCP] Session initialized: ${newSessionId}`);
741
+ transports.set(newSessionId, transport!);
742
+ }
743
+ });
744
+
745
+ // Connect the NEW session-specific server to this transport
746
+ try {
747
+ await serverToUse.connect(transport);
748
+ } catch (connectError: any) {
749
+ // Ignore "Already connected" errors - can happen if server was used before
750
+ if (connectError.message?.includes('Already connected')) {
751
+ console.error(`[MCP] Server already connected, creating fresh server...`);
752
+ const { server: freshServer } = createSquishServer();
753
+ serverToUse = freshServer;
754
+ await serverToUse.connect(transport);
755
+ } else {
756
+ console.error(`[MCP] Connect error:`, connectError.message);
757
+ }
758
+ }
759
+
760
+ // Set up onclose handler
761
+ transport.onclose = () => {
762
+ const sid = transport?.sessionId;
763
+ if (sid) {
764
+ console.error(`[MCP] Session closed: ${sid}`);
765
+ transports.delete(sid);
766
+ }
767
+ };
768
+
769
+ transport.onerror = (error) => {
770
+ console.error(`[MCP] Transport error:`, error);
771
+ };
772
+ }
773
+
774
+ try {
775
+ // Handle the request with the parsed body
776
+ await transport.handleRequest(req, res, body);
777
+ } catch (error) {
778
+ console.error(`[MCP] Error handling request:`, error);
779
+ if (!res.headersSent) {
780
+ res.status(500).json({ error: "Internal server error" });
781
+ }
782
+ }
783
+ });
784
+
785
+ // Streamable HTTP GET endpoint (for SSE)
786
+ app.get("/mcp", async (req, res) => {
787
+ const sessionId = req.headers["mcp-session-id"] as string | undefined;
788
+
789
+ if (!sessionId || !transports.has(sessionId)) {
790
+ res.status(400).send('Invalid or missing session ID');
791
+ return;
792
+ }
793
+
794
+ const transport = transports.get(sessionId)!;
795
+
796
+ try {
797
+ await transport.handleRequest(req, res);
798
+ } catch (error) {
799
+ console.error(`[MCP] Error handling GET request:`, error);
800
+ if (!res.headersSent) {
801
+ res.status(500).json({ error: "Internal server error" });
802
+ }
803
+ }
804
+ });
805
+
806
+ // DELETE endpoint to close session
807
+ app.delete("/mcp", async (req, res) => {
808
+ const sessionId = req.headers["mcp-session-id"] as string | undefined;
809
+
810
+ if (!sessionId || !transports.has(sessionId)) {
811
+ res.status(400).send('Invalid or missing session ID');
812
+ return;
813
+ }
814
+
815
+ const transport = transports.get(sessionId)!;
816
+
817
+ try {
818
+ await transport.handleRequest(req, res);
819
+ } catch (error) {
820
+ console.error(`[MCP] Error handling DELETE request:`, error);
821
+ if (!res.headersSent) {
822
+ res.status(500).json({ error: "Internal server error" });
823
+ }
824
+ }
825
+ });
826
+
827
+ await new Promise<void>((resolve) => app.listen(port, () => {
828
+ console.error(`[MCP] HTTP server listening on port ${port}`);
829
+ console.error(`[MCP] Streamable HTTP endpoint: http://localhost:${port}/mcp`);
830
+ console.error(`[MCP] Health: http://localhost:${port}/health`);
831
+ resolve();
832
+ }));
833
+ }
834
+
835
+ async function runHealthCheck(): Promise<void> {
836
+ const silent = process.env.SQUISH_MCP_SILENT === 'true';
837
+
838
+ if (!silent) console.error(`[MCP] Running health check...`);
839
+
840
+ try {
841
+ const { server, toolCount } = createSquishServer();
842
+ if (!silent) console.error(`[MCP] Health check passed. Server initialized with ${toolCount} tools.`);
843
+ process.exit(0);
844
+ } catch (error) {
845
+ console.error(`[MCP] Health check failed:`, error);
846
+ process.exit(1);
847
+ }
848
+ }
849
+
850
+ async function main(): Promise<void> {
851
+ try {
852
+ const { mode, port, health } = parseArgs();
853
+
854
+ // Check for silent mode - minimal output for MCP stdio
855
+ const silent = process.argv.includes('--silent') || process.env.SQUISH_MCP_SILENT === 'true';
856
+
857
+ if (!silent) {
858
+ console.error(`[${SERVER_NAME}] v${SERVER_VERSION} initializing...`);
859
+ console.error(`[${SERVER_NAME}] Mode: ${config.isManagedMode ? "managed" : "local"}`);
860
+ console.error(`[${SERVER_NAME}] Embeddings: ${config.embeddingsProvider}`);
861
+ }
862
+
863
+ if (health) {
864
+ await runHealthCheck();
865
+ return;
866
+ }
867
+
868
+ // DEFERRED: Start background worker only when actually needed
869
+ // This speeds up MCP startup significantly for MCP use cases
870
+ // Workers can be started lazily on first actual operation
871
+ const noWorker = process.env.SQUISH_MCP_NO_WORKER === 'true' || process.argv.includes('--no-worker');
872
+ const workerStarted = { current: false };
873
+
874
+ const startWorkerIfNeeded = async () => {
875
+ if (!workerStarted.current && !noWorker) {
876
+ try {
877
+ await startWorker();
878
+ if (!silent) console.error(`[${SERVER_NAME}] Background worker started`);
879
+ } catch (error) {
880
+ // Silently fail - worker is optional for MCP
881
+ }
882
+ workerStarted.current = true;
883
+ }
884
+ };
885
+
886
+ // DEFERRED: Scheduler - only initialize lazily
887
+ const schedulerStarted = { current: false };
888
+
889
+ const startSchedulerIfNeeded = async () => {
890
+ if (!schedulerStarted.current) {
891
+ try {
892
+ await initializeScheduler();
893
+ if (!silent) console.error(`[${SERVER_NAME}] Cron scheduler initialized`);
894
+ } catch (error) {
895
+ // Silently fail - scheduler is optional
896
+ }
897
+ schedulerStarted.current = true;
898
+ }
899
+ };
900
+
901
+ // Hook into server operations to lazy-start worker/scheduler
902
+ // This keeps MCP fast but ensures services start when needed
903
+ const lazyHooks = {
904
+ startWorkerIfNeeded,
905
+ startSchedulerIfNeeded
906
+ };
907
+
908
+ const shutdown = async () => {
909
+ if (!silent) console.error(`[${SERVER_NAME}] Shutting down...`);
910
+ try {
911
+ if (workerStarted.current) {
912
+ await stopWorker();
913
+ if (!silent) console.error(`[${SERVER_NAME}] Background worker stopped`);
914
+ }
915
+ } catch (error) {
916
+ // Ignore shutdown errors
917
+ }
918
+ process.exit(0);
919
+ };
920
+
921
+ process.on("SIGINT", shutdown);
922
+ process.on("SIGTERM", shutdown);
923
+
924
+ const { server, toolCount } = getSquishServer();
925
+
926
+ if (mode === "stdio") {
927
+ await runStdio(server, toolCount, lazyHooks);
928
+ } else {
929
+ await runHttp(server, port, lazyHooks);
930
+ }
931
+ } catch (error) {
932
+ console.error(`[${SERVER_NAME}] Fatal error:`, error);
933
+ process.exit(1);
934
+ }
935
+ }
936
+
937
+ main().catch((error) => {
938
+ console.error(`[${SERVER_NAME}] Fatal error:`, error);
939
+ process.exit(1);
940
+ });