squish-memory 1.0.1 → 1.0.2

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 (278) hide show
  1. package/.env.mcp.example +4 -0
  2. package/README.md +35 -17
  3. package/config/plugin-manifest.json +1 -1
  4. package/dist/api/web/web.js +27 -1
  5. package/dist/commands/mcp-server.js +1 -1
  6. package/dist/core/mcp/server.js +27 -1
  7. package/dist/core/mcp/types.d.ts +4 -4
  8. package/dist/core/memory/memories.js +9 -6
  9. package/dist/core/scheduler/cron-scheduler.js +66 -13
  10. package/dist/db/adapter.js +88 -20
  11. package/dist/db/bootstrap.js +145 -71
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +195 -49
  14. package/generated/mcp/manifest.json +23 -23
  15. package/package.json +30 -18
  16. package/scripts/install-interactive.mjs +7 -4
  17. package/skills/memory-guide/SKILL.md +94 -18
  18. package/skills/squish-cli/SKILL.md +61 -21
  19. package/skills/squish-mcp/SKILL.md +46 -2
  20. package/skills/squish-memory/SKILL.md +30 -16
  21. package/dist/algorithms/analytics/token-estimator.d.ts.map +0 -1
  22. package/dist/algorithms/analytics/token-estimator.js.map +0 -1
  23. package/dist/algorithms/detection/hash-filters.d.ts.map +0 -1
  24. package/dist/algorithms/detection/hash-filters.js.map +0 -1
  25. package/dist/algorithms/detection/semantic-ranker.d.ts.map +0 -1
  26. package/dist/algorithms/detection/semantic-ranker.js.map +0 -1
  27. package/dist/algorithms/detection/two-stage-detector.d.ts.map +0 -1
  28. package/dist/algorithms/detection/two-stage-detector.js.map +0 -1
  29. package/dist/algorithms/handlers/approve-merge.d.ts.map +0 -1
  30. package/dist/algorithms/handlers/approve-merge.js.map +0 -1
  31. package/dist/algorithms/handlers/detect-duplicates.d.ts.map +0 -1
  32. package/dist/algorithms/handlers/detect-duplicates.js.map +0 -1
  33. package/dist/algorithms/handlers/get-stats.d.ts.map +0 -1
  34. package/dist/algorithms/handlers/get-stats.js.map +0 -1
  35. package/dist/algorithms/handlers/list-proposals.d.ts.map +0 -1
  36. package/dist/algorithms/handlers/list-proposals.js.map +0 -1
  37. package/dist/algorithms/handlers/preview-merge.d.ts.map +0 -1
  38. package/dist/algorithms/handlers/preview-merge.js.map +0 -1
  39. package/dist/algorithms/handlers/reject-merge.d.ts.map +0 -1
  40. package/dist/algorithms/handlers/reject-merge.js.map +0 -1
  41. package/dist/algorithms/handlers/reverse-merge.d.ts.map +0 -1
  42. package/dist/algorithms/handlers/reverse-merge.js.map +0 -1
  43. package/dist/algorithms/safety/safety-checks.d.ts.map +0 -1
  44. package/dist/algorithms/safety/safety-checks.js.map +0 -1
  45. package/dist/algorithms/strategies/merge-strategies.d.ts.map +0 -1
  46. package/dist/algorithms/strategies/merge-strategies.js.map +0 -1
  47. package/dist/algorithms/utils/response-builder.d.ts.map +0 -1
  48. package/dist/algorithms/utils/response-builder.js.map +0 -1
  49. package/dist/api/web/index.d.ts.map +0 -1
  50. package/dist/api/web/index.js.map +0 -1
  51. package/dist/api/web/web-server.d.ts.map +0 -1
  52. package/dist/api/web/web-server.js.map +0 -1
  53. package/dist/api/web/web.d.ts.map +0 -1
  54. package/dist/api/web/web.js.map +0 -1
  55. package/dist/commands/managed-sync.d.ts.map +0 -1
  56. package/dist/commands/managed-sync.js.map +0 -1
  57. package/dist/commands/mcp-server.d.ts.map +0 -1
  58. package/dist/commands/mcp-server.js.map +0 -1
  59. package/dist/config.d.ts.map +0 -1
  60. package/dist/config.js.map +0 -1
  61. package/dist/core/agent-memory.d.ts.map +0 -1
  62. package/dist/core/agent-memory.js.map +0 -1
  63. package/dist/core/associations.d.ts.map +0 -1
  64. package/dist/core/associations.js.map +0 -1
  65. package/dist/core/cache.d.ts.map +0 -1
  66. package/dist/core/cache.js.map +0 -1
  67. package/dist/core/consolidation.d.ts.map +0 -1
  68. package/dist/core/consolidation.js.map +0 -1
  69. package/dist/core/context-paging.d.ts.map +0 -1
  70. package/dist/core/context-paging.js.map +0 -1
  71. package/dist/core/context.d.ts.map +0 -1
  72. package/dist/core/context.js.map +0 -1
  73. package/dist/core/core-memory.d.ts.map +0 -1
  74. package/dist/core/core-memory.js.map +0 -1
  75. package/dist/core/database.d.ts.map +0 -1
  76. package/dist/core/database.js.map +0 -1
  77. package/dist/core/embeddings/google-multimodal.d.ts.map +0 -1
  78. package/dist/core/embeddings/google-multimodal.js.map +0 -1
  79. package/dist/core/embeddings/qmd-client.d.ts.map +0 -1
  80. package/dist/core/embeddings/qmd-client.js.map +0 -1
  81. package/dist/core/embeddings.d.ts.map +0 -1
  82. package/dist/core/embeddings.js.map +0 -1
  83. package/dist/core/governance.d.ts.map +0 -1
  84. package/dist/core/governance.js.map +0 -1
  85. package/dist/core/index.d.ts.map +0 -1
  86. package/dist/core/index.js.map +0 -1
  87. package/dist/core/layers/generator.d.ts.map +0 -1
  88. package/dist/core/layers/generator.js.map +0 -1
  89. package/dist/core/lifecycle.d.ts.map +0 -1
  90. package/dist/core/lifecycle.js.map +0 -1
  91. package/dist/core/local-embeddings.d.ts.map +0 -1
  92. package/dist/core/local-embeddings.js.map +0 -1
  93. package/dist/core/logger.d.ts.map +0 -1
  94. package/dist/core/logger.js.map +0 -1
  95. package/dist/core/mcp/client.d.ts.map +0 -1
  96. package/dist/core/mcp/client.js.map +0 -1
  97. package/dist/core/mcp/index.d.ts.map +0 -1
  98. package/dist/core/mcp/index.js.map +0 -1
  99. package/dist/core/mcp/server.d.ts.map +0 -1
  100. package/dist/core/mcp/server.js.map +0 -1
  101. package/dist/core/mcp/standalone-server.d.ts.map +0 -1
  102. package/dist/core/mcp/standalone-server.js.map +0 -1
  103. package/dist/core/mcp/tools.d.ts.map +0 -1
  104. package/dist/core/mcp/tools.js.map +0 -1
  105. package/dist/core/mcp/types.d.ts.map +0 -1
  106. package/dist/core/mcp/types.js.map +0 -1
  107. package/dist/core/memory/bridge-discovery.d.ts.map +0 -1
  108. package/dist/core/memory/bridge-discovery.js.map +0 -1
  109. package/dist/core/memory/categorizer.d.ts.map +0 -1
  110. package/dist/core/memory/categorizer.js.map +0 -1
  111. package/dist/core/memory/conflict-detector.d.ts.map +0 -1
  112. package/dist/core/memory/conflict-detector.js.map +0 -1
  113. package/dist/core/memory/consolidation.d.ts.map +0 -1
  114. package/dist/core/memory/consolidation.js.map +0 -1
  115. package/dist/core/memory/context-collector.d.ts.map +0 -1
  116. package/dist/core/memory/context-collector.js.map +0 -1
  117. package/dist/core/memory/contradiction-resolver.d.ts.map +0 -1
  118. package/dist/core/memory/contradiction-resolver.js.map +0 -1
  119. package/dist/core/memory/edit-workflow.d.ts.map +0 -1
  120. package/dist/core/memory/edit-workflow.js.map +0 -1
  121. package/dist/core/memory/entity-extractor.d.ts.map +0 -1
  122. package/dist/core/memory/entity-extractor.js.map +0 -1
  123. package/dist/core/memory/entity-resolver.d.ts.map +0 -1
  124. package/dist/core/memory/entity-resolver.js.map +0 -1
  125. package/dist/core/memory/fact-extractor.d.ts.map +0 -1
  126. package/dist/core/memory/fact-extractor.js.map +0 -1
  127. package/dist/core/memory/feedback-tracker.d.ts.map +0 -1
  128. package/dist/core/memory/feedback-tracker.js.map +0 -1
  129. package/dist/core/memory/hybrid-retrieval.d.ts.map +0 -1
  130. package/dist/core/memory/hybrid-retrieval.js.map +0 -1
  131. package/dist/core/memory/hybrid-scorer.d.ts.map +0 -1
  132. package/dist/core/memory/hybrid-scorer.js.map +0 -1
  133. package/dist/core/memory/hybrid-search.d.ts.map +0 -1
  134. package/dist/core/memory/hybrid-search.js.map +0 -1
  135. package/dist/core/memory/importance.d.ts.map +0 -1
  136. package/dist/core/memory/importance.js.map +0 -1
  137. package/dist/core/memory/index.d.ts.map +0 -1
  138. package/dist/core/memory/index.js.map +0 -1
  139. package/dist/core/memory/memories.d.ts.map +0 -1
  140. package/dist/core/memory/memories.js.map +0 -1
  141. package/dist/core/memory/memory-manager.d.ts.map +0 -1
  142. package/dist/core/memory/memory-manager.js.map +0 -1
  143. package/dist/core/memory/progressive-disclosure.d.ts.map +0 -1
  144. package/dist/core/memory/progressive-disclosure.js.map +0 -1
  145. package/dist/core/memory/query-processor.d.ts.map +0 -1
  146. package/dist/core/memory/query-processor.js.map +0 -1
  147. package/dist/core/memory/query-rewriter.d.ts.map +0 -1
  148. package/dist/core/memory/query-rewriter.js.map +0 -1
  149. package/dist/core/memory/response-analyzer.d.ts.map +0 -1
  150. package/dist/core/memory/response-analyzer.js.map +0 -1
  151. package/dist/core/memory/serialization.d.ts.map +0 -1
  152. package/dist/core/memory/serialization.js.map +0 -1
  153. package/dist/core/memory/stats.d.ts.map +0 -1
  154. package/dist/core/memory/stats.js.map +0 -1
  155. package/dist/core/memory/telemetry.d.ts.map +0 -1
  156. package/dist/core/memory/telemetry.js.map +0 -1
  157. package/dist/core/memory/temporal-facts.d.ts.map +0 -1
  158. package/dist/core/memory/temporal-facts.js.map +0 -1
  159. package/dist/core/memory/temporal-parser.d.ts.map +0 -1
  160. package/dist/core/memory/temporal-parser.js.map +0 -1
  161. package/dist/core/memory/trigger-detector.d.ts.map +0 -1
  162. package/dist/core/memory/trigger-detector.js.map +0 -1
  163. package/dist/core/memory/write-gate.d.ts.map +0 -1
  164. package/dist/core/memory/write-gate.js.map +0 -1
  165. package/dist/core/namespaces/index.d.ts.map +0 -1
  166. package/dist/core/namespaces/index.js.map +0 -1
  167. package/dist/core/namespaces/uri-parser.d.ts.map +0 -1
  168. package/dist/core/namespaces/uri-parser.js.map +0 -1
  169. package/dist/core/observations.d.ts.map +0 -1
  170. package/dist/core/observations.js.map +0 -1
  171. package/dist/core/privacy.d.ts.map +0 -1
  172. package/dist/core/privacy.js.map +0 -1
  173. package/dist/core/projects.d.ts.map +0 -1
  174. package/dist/core/projects.js.map +0 -1
  175. package/dist/core/redis.d.ts.map +0 -1
  176. package/dist/core/redis.js.map +0 -1
  177. package/dist/core/requirements.d.ts.map +0 -1
  178. package/dist/core/requirements.js.map +0 -1
  179. package/dist/core/scheduler/cron-scheduler.d.ts.map +0 -1
  180. package/dist/core/scheduler/cron-scheduler.js.map +0 -1
  181. package/dist/core/scheduler/heartbeat.d.ts.map +0 -1
  182. package/dist/core/scheduler/heartbeat.js.map +0 -1
  183. package/dist/core/scheduler/index.d.ts.map +0 -1
  184. package/dist/core/scheduler/index.js.map +0 -1
  185. package/dist/core/scheduler/job-runner.d.ts.map +0 -1
  186. package/dist/core/scheduler/job-runner.js.map +0 -1
  187. package/dist/core/search/conversations.d.ts.map +0 -1
  188. package/dist/core/search/conversations.js.map +0 -1
  189. package/dist/core/search/entities.d.ts.map +0 -1
  190. package/dist/core/search/entities.js.map +0 -1
  191. package/dist/core/search/folder-context.d.ts.map +0 -1
  192. package/dist/core/search/folder-context.js.map +0 -1
  193. package/dist/core/search/index.d.ts.map +0 -1
  194. package/dist/core/search/index.js.map +0 -1
  195. package/dist/core/search/qmd-search.d.ts.map +0 -1
  196. package/dist/core/search/qmd-search.js.map +0 -1
  197. package/dist/core/secret-detector.d.ts.map +0 -1
  198. package/dist/core/secret-detector.js.map +0 -1
  199. package/dist/core/session/auto-load.d.ts.map +0 -1
  200. package/dist/core/session/auto-load.js.map +0 -1
  201. package/dist/core/session/index.d.ts.map +0 -1
  202. package/dist/core/session/index.js.map +0 -1
  203. package/dist/core/session/types.d.ts.map +0 -1
  204. package/dist/core/session/types.js.map +0 -1
  205. package/dist/core/session-hooks/self-iteration-job.d.ts.map +0 -1
  206. package/dist/core/session-hooks/self-iteration-job.js.map +0 -1
  207. package/dist/core/session-hooks/session-hooks.d.ts.map +0 -1
  208. package/dist/core/session-hooks/session-hooks.js.map +0 -1
  209. package/dist/core/snapshots/cleanup.d.ts.map +0 -1
  210. package/dist/core/snapshots/cleanup.js.map +0 -1
  211. package/dist/core/snapshots/comparison.d.ts.map +0 -1
  212. package/dist/core/snapshots/comparison.js.map +0 -1
  213. package/dist/core/snapshots/creation.d.ts.map +0 -1
  214. package/dist/core/snapshots/creation.js.map +0 -1
  215. package/dist/core/snapshots/retrieval.d.ts.map +0 -1
  216. package/dist/core/snapshots/retrieval.js.map +0 -1
  217. package/dist/core/snapshots/stats.d.ts.map +0 -1
  218. package/dist/core/snapshots/stats.js.map +0 -1
  219. package/dist/core/snapshots.d.ts.map +0 -1
  220. package/dist/core/snapshots.js.map +0 -1
  221. package/dist/core/summarization/cleanup.d.ts.map +0 -1
  222. package/dist/core/summarization/cleanup.js.map +0 -1
  223. package/dist/core/summarization/queries.d.ts.map +0 -1
  224. package/dist/core/summarization/queries.js.map +0 -1
  225. package/dist/core/summarization/stats.d.ts.map +0 -1
  226. package/dist/core/summarization/stats.js.map +0 -1
  227. package/dist/core/summarization/strategies.d.ts.map +0 -1
  228. package/dist/core/summarization/strategies.js.map +0 -1
  229. package/dist/core/summarization.d.ts.map +0 -1
  230. package/dist/core/summarization.js.map +0 -1
  231. package/dist/core/sync/qmd-sync.d.ts.map +0 -1
  232. package/dist/core/sync/qmd-sync.js.map +0 -1
  233. package/dist/core/temporal-facts.d.ts.map +0 -1
  234. package/dist/core/temporal-facts.js.map +0 -1
  235. package/dist/core/tracing/collector.d.ts.map +0 -1
  236. package/dist/core/tracing/collector.js.map +0 -1
  237. package/dist/core/tracing/visualizer.d.ts.map +0 -1
  238. package/dist/core/tracing/visualizer.js.map +0 -1
  239. package/dist/core/utils/cleanup-operations.d.ts.map +0 -1
  240. package/dist/core/utils/cleanup-operations.js.map +0 -1
  241. package/dist/core/utils/content-extraction.d.ts.map +0 -1
  242. package/dist/core/utils/content-extraction.js.map +0 -1
  243. package/dist/core/utils/filter-builder.d.ts.map +0 -1
  244. package/dist/core/utils/filter-builder.js.map +0 -1
  245. package/dist/core/utils/history-traversal.d.ts.map +0 -1
  246. package/dist/core/utils/history-traversal.js.map +0 -1
  247. package/dist/core/utils/memory-operations.d.ts.map +0 -1
  248. package/dist/core/utils/memory-operations.js.map +0 -1
  249. package/dist/core/utils/query-operations.d.ts.map +0 -1
  250. package/dist/core/utils/query-operations.js.map +0 -1
  251. package/dist/core/utils/summarization-helpers.d.ts.map +0 -1
  252. package/dist/core/utils/summarization-helpers.js.map +0 -1
  253. package/dist/core/utils/temporal-queries.d.ts.map +0 -1
  254. package/dist/core/utils/temporal-queries.js.map +0 -1
  255. package/dist/core/utils/version-management.d.ts.map +0 -1
  256. package/dist/core/utils/version-management.js.map +0 -1
  257. package/dist/core/utils.d.ts.map +0 -1
  258. package/dist/core/utils.js.map +0 -1
  259. package/dist/core/worker.d.ts.map +0 -1
  260. package/dist/core/worker.js.map +0 -1
  261. package/dist/db/adapter.d.ts.map +0 -1
  262. package/dist/db/adapter.js.map +0 -1
  263. package/dist/db/bootstrap.d.ts.map +0 -1
  264. package/dist/db/bootstrap.js.map +0 -1
  265. package/dist/db/index.d.ts.map +0 -1
  266. package/dist/db/index.js.map +0 -1
  267. package/dist/db/schema.d.ts.map +0 -1
  268. package/dist/db/schema.js.map +0 -1
  269. package/dist/drizzle/schema-sqlite.d.ts.map +0 -1
  270. package/dist/drizzle/schema-sqlite.js.map +0 -1
  271. package/dist/drizzle/schema.d.ts.map +0 -1
  272. package/dist/drizzle/schema.js.map +0 -1
  273. package/dist/index.d.ts.map +0 -1
  274. package/dist/index.js.map +0 -1
  275. package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts.map +0 -1
  276. package/packages/plugin-claude-code/dist/plugin-wrapper.js.map +0 -1
  277. package/packages/plugin-openclaw/dist/index.d.ts.map +0 -1
  278. package/packages/plugin-openclaw/dist/index.js.map +0 -1
@@ -330,6 +330,44 @@ CREATE TABLE IF NOT EXISTS memory_hash_cache (
330
330
 
331
331
  CREATE INDEX IF NOT EXISTS memory_hash_cache_project_id_idx ON memory_hash_cache(project_id);
332
332
  CREATE INDEX IF NOT EXISTS memory_hash_cache_simhash_idx ON memory_hash_cache(simhash);
333
+
334
+ -- Namespaces table (v1.0.x) - Hierarchical organization
335
+ CREATE TABLE IF NOT EXISTS namespaces (
336
+ id TEXT PRIMARY KEY,
337
+ project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
338
+ name TEXT NOT NULL,
339
+ path TEXT,
340
+ description TEXT,
341
+ parent_id TEXT REFERENCES namespaces(id) ON DELETE SET NULL,
342
+ created_at INTEGER DEFAULT (strftime('%s','now')) NOT NULL,
343
+ updated_at INTEGER DEFAULT (strftime('%s','now')) NOT NULL
344
+ );
345
+ CREATE INDEX IF NOT EXISTS namespaces_project_idx ON namespaces(project_id);
346
+ CREATE INDEX IF NOT EXISTS namespaces_parent_idx ON namespaces(parent_id);
347
+
348
+ -- Maintenance jobs table (v1.0.x) - Cron scheduler
349
+ CREATE TABLE IF NOT EXISTS maintenance_jobs (
350
+ id TEXT PRIMARY KEY,
351
+ job_name TEXT NOT NULL UNIQUE,
352
+ job_type TEXT NOT NULL,
353
+ cron_expression TEXT,
354
+ enabled INTEGER DEFAULT 1 NOT NULL,
355
+ last_run_at INTEGER,
356
+ last_run_duration INTEGER,
357
+ last_run_status TEXT,
358
+ last_run_error TEXT,
359
+ total_runs INTEGER DEFAULT 0,
360
+ success_count INTEGER DEFAULT 0,
361
+ failure_count INTEGER DEFAULT 0,
362
+ job_config TEXT,
363
+ next_run_at INTEGER,
364
+ created_at INTEGER DEFAULT (strftime('%s','now')) NOT NULL,
365
+ updated_at INTEGER DEFAULT (strftime('%s','now')) NOT NULL
366
+ );
367
+ CREATE INDEX IF NOT EXISTS maintenance_jobs_name_idx ON maintenance_jobs(job_name);
368
+ CREATE INDEX IF NOT EXISTS maintenance_jobs_next_run_idx ON maintenance_jobs(next_run_at);
369
+ CREATE INDEX IF NOT EXISTS maintenance_jobs_type_idx ON maintenance_jobs(job_type);
370
+ CREATE INDEX IF NOT EXISTS maintenance_jobs_enabled_idx ON maintenance_jobs(enabled);
333
371
  `;
334
372
  const postgresStatements = [
335
373
  `CREATE EXTENSION IF NOT EXISTS pgcrypto;`,
@@ -565,97 +603,71 @@ async function runSqliteMigrations(sqlite) {
565
603
  // No migrations needed
566
604
  return;
567
605
  }
568
- // Migrations for memories table
606
+ // Migrations for memories table (deduplicated, ordered by version)
569
607
  const memoriesMigrations = [
608
+ // Base columns (v0.1.x - v0.5.x)
570
609
  { col: 'embedding', sql: 'ALTER TABLE memories ADD COLUMN embedding BLOB' },
571
- { col: 'is_private', sql: 'ALTER TABLE memories ADD COLUMN is_private INTEGER DEFAULT 0' },
572
- { col: 'has_secrets', sql: 'ALTER TABLE memories ADD COLUMN has_secrets INTEGER DEFAULT 0' },
573
610
  { col: 'relevance_score', sql: 'ALTER TABLE memories ADD COLUMN relevance_score INTEGER DEFAULT 50' },
611
+ // Merge tracking (v0.6.x)
574
612
  { col: 'is_merged', sql: 'ALTER TABLE memories ADD COLUMN is_merged INTEGER DEFAULT 0' },
575
613
  { col: 'merged_into_id', sql: 'ALTER TABLE memories ADD COLUMN merged_into_id TEXT' },
576
614
  { col: 'is_mergeable', sql: 'ALTER TABLE memories ADD COLUMN is_mergeable INTEGER DEFAULT 1' },
577
615
  { col: 'is_canonical', sql: 'ALTER TABLE memories ADD COLUMN is_canonical INTEGER DEFAULT 0' },
578
- // v0.8.0: Importance scoring
616
+ { col: 'merged_at', sql: 'ALTER TABLE memories ADD COLUMN merged_at INTEGER' },
617
+ { col: 'merge_source_ids', sql: 'ALTER TABLE memories ADD COLUMN merge_source_ids TEXT' },
618
+ { col: 'merge_version', sql: 'ALTER TABLE memories ADD COLUMN merge_version INTEGER DEFAULT 1' },
619
+ // Importance scoring (v0.8.0)
579
620
  { col: 'importance_score', sql: 'ALTER TABLE memories ADD COLUMN importance_score INTEGER DEFAULT 50' },
580
621
  { col: 'importance_decay_rate', sql: 'ALTER TABLE memories ADD COLUMN importance_decay_rate INTEGER DEFAULT 30' },
581
622
  { col: 'last_importance_recalc', sql: 'ALTER TABLE memories ADD COLUMN last_importance_recalc INTEGER' },
582
- // v0.8.0: Consolidation
623
+ // Consolidation (v0.8.0)
583
624
  { col: 'consolidated_into', sql: 'ALTER TABLE memories ADD COLUMN consolidated_into TEXT' },
584
625
  { col: 'consolidated_at', sql: 'ALTER TABLE memories ADD COLUMN consolidated_at INTEGER' },
585
626
  { col: 'is_consolidated', sql: 'ALTER TABLE memories ADD COLUMN is_consolidated INTEGER DEFAULT 0' },
586
- { col: 'merged_at', sql: 'ALTER TABLE memories ADD COLUMN merged_at INTEGER' },
627
+ // Memory lifecycle (v0.8.0)
587
628
  { col: 'sector', sql: 'ALTER TABLE memories ADD COLUMN sector TEXT DEFAULT "episodic"' },
588
629
  { col: 'tier', sql: 'ALTER TABLE memories ADD COLUMN tier TEXT DEFAULT "hot"' },
589
630
  { col: 'context_status', sql: 'ALTER TABLE memories ADD COLUMN context_status TEXT DEFAULT "out-of-context"' },
590
631
  { col: 'decay_rate', sql: 'ALTER TABLE memories ADD COLUMN decay_rate INTEGER DEFAULT 30' },
591
632
  { col: 'coactivation_score', sql: 'ALTER TABLE memories ADD COLUMN coactivation_score INTEGER DEFAULT 0' },
592
633
  { col: 'last_decay_at', sql: 'ALTER TABLE memories ADD COLUMN last_decay_at INTEGER DEFAULT (strftime(\'%s\',\'now\'))' },
634
+ // Agent tracking (v0.8.0)
593
635
  { col: 'agent_id', sql: 'ALTER TABLE memories ADD COLUMN agent_id TEXT' },
594
636
  { col: 'agent_role', sql: 'ALTER TABLE memories ADD COLUMN agent_role TEXT' },
595
637
  { col: 'retrieval_priority', sql: 'ALTER TABLE memories ADD COLUMN retrieval_priority INTEGER DEFAULT 50' },
596
- // v0.9.0: New schema columns
638
+ // Data governance (v0.9.0)
597
639
  { col: 'recorded_at', sql: 'ALTER TABLE memories ADD COLUMN recorded_at INTEGER DEFAULT (strftime(\'%s\',\'now\'))' },
598
640
  { col: 'confidence', sql: 'ALTER TABLE memories ADD COLUMN confidence INTEGER DEFAULT 100' },
599
- { col: 'is_private', sql: 'ALTER TABLE memories ADD COLUMN is_private INTEGER DEFAULT 0' },
600
- { col: 'has_secrets', sql: 'ALTER TABLE memories ADD COLUMN has_secrets INTEGER DEFAULT 0' },
601
641
  { col: 'valid_from', sql: 'ALTER TABLE memories ADD COLUMN valid_from INTEGER' },
602
642
  { col: 'valid_to', sql: 'ALTER TABLE memories ADD COLUMN valid_to INTEGER' },
603
643
  { col: 'superseded_by', sql: 'ALTER TABLE memories ADD COLUMN superseded_by TEXT' },
604
644
  { col: 'version', sql: 'ALTER TABLE memories ADD COLUMN version INTEGER DEFAULT 1' },
605
- { col: 'merge_source_ids', sql: 'ALTER TABLE memories ADD COLUMN merge_source_ids TEXT' },
606
- { col: 'merge_version', sql: 'ALTER TABLE memories ADD COLUMN merge_version INTEGER DEFAULT 1' },
607
- { col: 'user_id', sql: 'ALTER TABLE memories ADD COLUMN user_id TEXT' },
608
- { col: 'confidence', sql: 'ALTER TABLE memories ADD COLUMN confidence INTEGER DEFAULT 100' },
609
645
  { col: 'is_active', sql: 'ALTER TABLE memories ADD COLUMN is_active INTEGER DEFAULT 1' },
610
646
  { col: 'expires_at', sql: 'ALTER TABLE memories ADD COLUMN expires_at INTEGER' },
611
- { col: 'decay_rate', sql: 'ALTER TABLE memories ADD COLUMN decay_rate INTEGER DEFAULT 30' },
612
- { col: 'coactivation_score', sql: 'ALTER TABLE memories ADD COLUMN coactivation_score INTEGER DEFAULT 0' },
613
- { col: 'last_decay_at', sql: 'ALTER TABLE memories ADD COLUMN last_decay_at INTEGER' },
614
- { col: 'agent_id', sql: 'ALTER TABLE memories ADD COLUMN agent_id TEXT' },
615
- { col: 'agent_role', sql: 'ALTER TABLE memories ADD COLUMN agent_role TEXT' },
616
- { col: 'retrieval_priority', sql: 'ALTER TABLE memories ADD COLUMN retrieval_priority INTEGER DEFAULT 50' },
617
- // v0.8.0: Consolidation
618
- { col: 'consolidated_into', sql: 'ALTER TABLE memories ADD COLUMN consolidated_into TEXT' },
619
- { col: 'consolidated_at', sql: 'ALTER TABLE memories ADD COLUMN consolidated_at INTEGER' },
620
- { col: 'is_consolidated', sql: 'ALTER TABLE memories ADD COLUMN is_consolidated INTEGER DEFAULT 0' },
621
- { col: 'merged_at', sql: 'ALTER TABLE memories ADD COLUMN merged_at INTEGER' },
622
- { col: 'sector', sql: 'ALTER TABLE memories ADD COLUMN sector TEXT DEFAULT "episodic"' },
623
- { col: 'tier', sql: 'ALTER TABLE memories ADD COLUMN tier TEXT DEFAULT "hot"' },
624
- { col: 'context_status', sql: 'ALTER TABLE memories ADD COLUMN context_status TEXT DEFAULT "out-of-context"' },
625
- { col: 'decay_rate', sql: 'ALTER TABLE memories ADD COLUMN decay_rate INTEGER DEFAULT 30' },
626
- { col: 'coactivation_score', sql: 'ALTER TABLE memories ADD COLUMN coactivation_score INTEGER DEFAULT 0' },
627
- { col: 'last_decay_at', sql: 'ALTER TABLE memories ADD COLUMN last_decay_at INTEGER DEFAULT (strftime(\'%s\',\'now\'))' },
628
- { col: 'agent_id', sql: 'ALTER TABLE memories ADD COLUMN agent_id TEXT' },
629
- { col: 'agent_role', sql: 'ALTER TABLE memories ADD COLUMN agent_role TEXT' },
647
+ // Privacy & access (v0.9.0)
648
+ { col: 'is_private', sql: 'ALTER TABLE memories ADD COLUMN is_private INTEGER DEFAULT 0' },
649
+ { col: 'has_secrets', sql: 'ALTER TABLE memories ADD COLUMN has_secrets INTEGER DEFAULT 0' },
630
650
  { col: 'visibility_scope', sql: 'ALTER TABLE memories ADD COLUMN visibility_scope TEXT DEFAULT "private"' },
631
651
  { col: 'is_protected', sql: 'ALTER TABLE memories ADD COLUMN is_protected INTEGER DEFAULT 0' },
632
652
  { col: 'is_pinned', sql: 'ALTER TABLE memories ADD COLUMN is_pinned INTEGER DEFAULT 0' },
633
653
  { col: 'is_immutable', sql: 'ALTER TABLE memories ADD COLUMN is_immutable INTEGER DEFAULT 0' },
634
654
  { col: 'write_scope', sql: 'ALTER TABLE memories ADD COLUMN write_scope TEXT' },
635
655
  { col: 'read_scope', sql: 'ALTER TABLE memories ADD COLUMN read_scope TEXT' },
656
+ // Usage tracking (v0.9.0)
636
657
  { col: 'triggered_by', sql: 'ALTER TABLE memories ADD COLUMN triggered_by TEXT' },
637
658
  { col: 'capture_reason', sql: 'ALTER TABLE memories ADD COLUMN capture_reason TEXT' },
638
659
  { col: 'last_used_at', sql: 'ALTER TABLE memories ADD COLUMN last_used_at INTEGER' },
639
660
  { col: 'usage_count', sql: 'ALTER TABLE memories ADD COLUMN usage_count INTEGER DEFAULT 0' },
640
- { col: 'valid_from', sql: 'ALTER TABLE memories ADD COLUMN valid_from INTEGER' },
641
- { col: 'valid_to', sql: 'ALTER TABLE memories ADD COLUMN valid_to INTEGER' },
642
- { col: 'superseded_by', sql: 'ALTER TABLE memories ADD COLUMN superseded_by TEXT' },
643
- { col: 'version', sql: 'ALTER TABLE memories ADD COLUMN version INTEGER DEFAULT 1' },
644
- { col: 'merge_source_ids', sql: 'ALTER TABLE memories ADD COLUMN merge_source_ids TEXT' },
645
- { col: 'merge_version', sql: 'ALTER TABLE memories ADD COLUMN merge_version INTEGER DEFAULT 1' },
646
661
  { col: 'user_id', sql: 'ALTER TABLE memories ADD COLUMN user_id TEXT' },
647
- { col: 'confidence', sql: 'ALTER TABLE memories ADD COLUMN confidence INTEGER DEFAULT 100' },
648
- { col: 'is_active', sql: 'ALTER TABLE memories ADD COLUMN is_active INTEGER DEFAULT 1' },
649
- { col: 'expires_at', sql: 'ALTER TABLE memories ADD COLUMN expires_at INTEGER' },
650
- { col: 'decay_rate', sql: 'ALTER TABLE memories ADD COLUMN decay_rate INTEGER DEFAULT 30' },
651
- { col: 'coactivation_score', sql: 'ALTER TABLE memories ADD COLUMN coactivation_score INTEGER DEFAULT 0' },
652
- { col: 'last_decay_at', sql: 'ALTER TABLE memories ADD COLUMN last_decay_at INTEGER' },
653
- { col: 'agent_id', sql: 'ALTER TABLE memories ADD COLUMN agent_id TEXT' },
654
- { col: 'agent_role', sql: 'ALTER TABLE memories ADD COLUMN agent_role TEXT' },
655
- { col: 'retrieval_priority', sql: 'ALTER TABLE memories ADD COLUMN retrieval_priority INTEGER DEFAULT 50' },
656
- { col: 'importance_score', sql: 'ALTER TABLE memories ADD COLUMN importance_score INTEGER DEFAULT 50' },
657
- { col: 'importance_decay_rate', sql: 'ALTER TABLE memories ADD COLUMN importance_decay_rate INTEGER DEFAULT 30' },
658
- { col: 'last_importance_recalc', sql: 'ALTER TABLE memories ADD COLUMN last_importance_recalc INTEGER' },
662
+ // Layer tracking (v0.9.x)
663
+ { col: 'has_l0_abstract', sql: 'ALTER TABLE memories ADD COLUMN has_l0_abstract INTEGER DEFAULT 0' },
664
+ { col: 'has_l1_overview', sql: 'ALTER TABLE memories ADD COLUMN has_l1_overview INTEGER DEFAULT 0' },
665
+ { col: 'last_layer_update', sql: 'ALTER TABLE memories ADD COLUMN last_layer_update INTEGER' },
666
+ // Namespace support (v1.0.x)
667
+ { col: 'namespace_id', sql: 'ALTER TABLE memories ADD COLUMN namespace_id TEXT REFERENCES namespaces(id) ON DELETE SET NULL' },
668
+ { col: 'namespace_path', sql: 'ALTER TABLE memories ADD COLUMN namespace_path TEXT' },
669
+ // Token tracking (v1.0.x)
670
+ { col: 'tokens_estimate', sql: 'ALTER TABLE memories ADD COLUMN tokens_estimate INTEGER DEFAULT 0' },
659
671
  ];
660
672
  // Get existing columns for memories table
661
673
  const tableInfo = sqlite.prepare("PRAGMA table_info(memories)").all();
@@ -676,28 +688,90 @@ async function runSqliteMigrations(sqlite) {
676
688
  throw new Error(`Migration failed for column ${migration.col}: ${msg}`);
677
689
  }
678
690
  }
679
- // v0.9.2: Add tokens_estimate to core_memory
680
- const coreMemoryTableCheck = sqlite.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='core_memory'").get();
681
- if (coreMemoryTableCheck) {
682
- const coreMemoryInfo = sqlite.prepare("PRAGMA table_info(core_memory)").all();
683
- const existingCoreMemoryColumns = new Set(coreMemoryInfo.map(col => col.name));
684
- const coreMemoryMigrations = [
685
- { col: 'tokens_estimate', sql: 'ALTER TABLE core_memory ADD COLUMN tokens_estimate INTEGER DEFAULT 0 NOT NULL' },
686
- ];
687
- for (const migration of coreMemoryMigrations) {
688
- if (!existingCoreMemoryColumns.has(migration.col)) {
689
- try {
690
- sqlite.exec(migration.sql);
691
- logger.info(`Migration: Added column ${migration.col} to core_memory table`);
691
+ }
692
+ }
693
+ // v0.9.2: Add tokens_estimate to core_memory
694
+ const coreMemoryTableCheck = sqlite.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='core_memory'").get();
695
+ if (coreMemoryTableCheck) {
696
+ const coreMemoryInfo = sqlite.prepare("PRAGMA table_info(core_memory)").all();
697
+ const existingCoreMemoryColumns = new Set(coreMemoryInfo.map(col => col.name));
698
+ const coreMemoryMigrations = [
699
+ { col: 'tokens_estimate', sql: 'ALTER TABLE core_memory ADD COLUMN tokens_estimate INTEGER DEFAULT 0 NOT NULL' },
700
+ ];
701
+ for (const migration of coreMemoryMigrations) {
702
+ if (!existingCoreMemoryColumns.has(migration.col)) {
703
+ try {
704
+ sqlite.exec(migration.sql);
705
+ logger.info(`Migration: Added column ${migration.col} to core_memory table`);
706
+ }
707
+ catch (error) {
708
+ const msg = error instanceof Error ? error.message : String(error);
709
+ if (msg.includes('duplicate column name')) {
710
+ logger.debug(`Migration skipped for ${migration.col}: column already exists`);
711
+ }
712
+ else {
713
+ throw new Error(`Migration failed for column ${migration.col}: ${msg}`);
714
+ }
715
+ }
716
+ }
717
+ }
718
+ }
719
+ // Migrations for maintenance_jobs table (v1.0.x)
720
+ const maintenanceJobsTableCheck = sqlite.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='maintenance_jobs'").get();
721
+ if (maintenanceJobsTableCheck) {
722
+ const maintenanceJobsInfo = sqlite.prepare("PRAGMA table_info(maintenance_jobs)").all();
723
+ const existingMaintenanceJobsColumns = new Set(maintenanceJobsInfo.map(col => col.name));
724
+ // Check if table has wrong schema (camelCase columns from bug in earlier version)
725
+ const hasCamelCaseColumns = existingMaintenanceJobsColumns.has('jobName') ||
726
+ existingMaintenanceJobsColumns.has('jobType') ||
727
+ existingMaintenanceJobsColumns.has('cronExpression');
728
+ if (hasCamelCaseColumns) {
729
+ // Table has incorrect camelCase schema - need to recreate it
730
+ logger.warn('Maintenance jobs table has incorrect schema (camelCase columns). Recreating...');
731
+ try {
732
+ // Drop the malformed table
733
+ sqlite.exec('DROP TABLE IF EXISTS maintenance_jobs');
734
+ // Recreate with correct schema - it will be created by the schema SQL
735
+ logger.info('Dropped malformed maintenance_jobs table. It will be recreated with correct schema.');
736
+ }
737
+ catch (error) {
738
+ logger.error('Failed to recreate maintenance_jobs table:', error);
739
+ }
740
+ }
741
+ else {
742
+ // Normal migrations for correct schema
743
+ const maintenanceJobsMigrations = [
744
+ { col: 'schedule', sql: 'ALTER TABLE maintenance_jobs DROP COLUMN schedule' },
745
+ { col: 'cron_expression', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN cron_expression TEXT' },
746
+ { col: 'last_run_at', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN last_run_at INTEGER' },
747
+ { col: 'last_run_duration', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN last_run_duration INTEGER' },
748
+ { col: 'last_run_status', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN last_run_status TEXT' },
749
+ { col: 'last_run_error', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN last_run_error TEXT' },
750
+ { col: 'total_runs', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN total_runs INTEGER DEFAULT 0' },
751
+ { col: 'success_count', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN success_count INTEGER DEFAULT 0' },
752
+ { col: 'failure_count', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN failure_count INTEGER DEFAULT 0' },
753
+ { col: 'job_config', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN job_config TEXT' },
754
+ { col: 'next_run_at', sql: 'ALTER TABLE maintenance_jobs ADD COLUMN next_run_at INTEGER' },
755
+ { col: 'run_count', sql: 'ALTER TABLE maintenance_jobs DROP COLUMN run_count' },
756
+ ];
757
+ for (const migration of maintenanceJobsMigrations) {
758
+ // For DROP migrations, only run if column EXISTS
759
+ // For ADD migrations, only run if column does NOT exist
760
+ const shouldRun = migration.sql.startsWith('ALTER TABLE maintenance_jobs DROP COLUMN')
761
+ ? existingMaintenanceJobsColumns.has(migration.col)
762
+ : !existingMaintenanceJobsColumns.has(migration.col);
763
+ if (shouldRun) {
764
+ try {
765
+ sqlite.exec(migration.sql);
766
+ logger.info(`Migration: ${migration.col} on maintenance_jobs table`);
767
+ }
768
+ catch (error) {
769
+ const msg = error instanceof Error ? error.message : String(error);
770
+ if (msg.includes('duplicate column name') || msg.includes('no such column')) {
771
+ logger.debug(`Migration skipped for ${migration.col}: ${msg.includes('duplicate column name') ? 'column already exists' : 'column does not exist'}`);
692
772
  }
693
- catch (error) {
694
- const msg = error instanceof Error ? error.message : String(error);
695
- if (msg.includes('duplicate column name')) {
696
- logger.debug(`Migration skipped for ${migration.col}: column already exists`);
697
- }
698
- else {
699
- throw new Error(`Migration failed for column ${migration.col}: ${msg}`);
700
- }
773
+ else {
774
+ throw new Error(`Migration failed for column ${migration.col}: ${msg}`);
701
775
  }
702
776
  }
703
777
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Squish v1.0.0 - Universal Memory Plugin System
3
+ * Squish v1.0.2 - Universal Memory Plugin System
4
4
  *
5
5
  * Modes:
6
6
  * - CLI Mode: For any MCP client bash execution (e.g., `squish remember "text"`)
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Squish v1.0.0 - Universal Memory Plugin System
3
+ * Squish v1.0.2 - Universal Memory Plugin System
4
4
  *
5
5
  * Modes:
6
6
  * - CLI Mode: For any MCP client bash execution (e.g., `squish remember "text"`)
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import 'dotenv/config';
19
19
  import fs from 'node:fs';
20
+ import { existsSync } from 'node:fs';
20
21
  import os from 'node:os';
21
22
  import path from 'node:path';
22
23
  import { fileURLToPath } from 'node:url';
@@ -48,11 +49,12 @@ import { searchWithQMD, isQMDAvailable } from './core/search/qmd-search.js';
48
49
  import { initializeCoreMemory, getCoreMemory, editCoreMemorySection, appendCoreMemorySection, getCoreMemoryStats, } from './core/core-memory.js';
49
50
  import { loadMemoryToContext, evictMemoryFromContext, viewLoadedMemories, getContextStatus, } from './core/context-paging.js';
50
51
  import { ensureDataDirectory } from './db/bootstrap.js';
52
+ import { getDataDir } from './config.js';
51
53
  import { performAutoLoad, shouldAutoLoad, getAutoLoadConfig } from './core/session/auto-load.js';
52
54
  import { initializeScheduler, registerJobHandler } from './core/scheduler/cron-scheduler.js';
53
55
  import { startHeartbeatChecking, heartbeat } from './core/scheduler/heartbeat.js';
54
56
  import { runNightlyJob, runWeeklyJob } from './core/scheduler/job-runner.js';
55
- const VERSION = '1.0.1';
57
+ const VERSION = '1.0.2';
56
58
  // Load plugin manifest for self-verification
57
59
  function loadPluginManifest() {
58
60
  try {
@@ -89,21 +91,197 @@ function verifyManifest(manifest) {
89
91
  return { ok: errors.length === 0, errors };
90
92
  }
91
93
  // ============================================================================
92
- // CLI MODE DETECTION
94
+ // HELPER FUNCTIONS
93
95
  // ============================================================================
94
- const args = process.argv.slice(2);
95
- const hasCliArgs = args.length > 0 && args[0] !== '--mcp';
96
- if (hasCliArgs) {
97
- // === CLI MODE (for OpenClaw) ===
98
- runCliMode().catch((e) => {
99
- console.error(JSON.stringify({ error: e.message }, null, 2));
96
+ function showHelp() {
97
+ console.log(`
98
+ Squish Memory v${VERSION} - Universal Memory Plugin System
99
+
100
+ Usage:
101
+ squish Start interactive wizard
102
+ squish run mcp Start MCP server
103
+ squish run web Start Web UI only
104
+ squish <command> [options] Run CLI commands for agents
105
+
106
+ CLI Commands (for agents):
107
+ squish remember <content> Store a memory
108
+ squish search <query> Search memories
109
+ squish health Check system health
110
+ squish stats View statistics
111
+ squish core_memory Manage core memory
112
+
113
+ Examples:
114
+ squish run mcp # Start MCP server (for Claude Code)
115
+ squish run web # Start Web UI only
116
+ squish remember "Hello" # Store memory via CLI
117
+ squish search "query" # Search memories via CLI
118
+
119
+ For more info: https://github.com/michielhdoteth/squish
120
+ `);
121
+ }
122
+ async function runInteractiveInstaller() {
123
+ const { select } = await import('@clack/prompts');
124
+ const { isCancel } = await import('@clack/prompts');
125
+ const { log } = await import('@clack/prompts');
126
+ const { intro, outro } = await import('@clack/prompts');
127
+ intro(`Squish Memory v${VERSION}`);
128
+ const options = [
129
+ { value: 'mcp', label: 'Start MCP Server (for AI Assistants: Claude Code, OpenCode, etc.)' },
130
+ { value: 'web', label: 'Start Web UI Only' },
131
+ { value: 'health', label: 'Health & Stats' },
132
+ { value: 'help', label: 'Show Help' },
133
+ { value: 'exit', label: 'Exit' }
134
+ ];
135
+ const selected = await select({
136
+ message: 'What would you like to do?',
137
+ options: options,
138
+ });
139
+ if (isCancel(selected)) {
140
+ outro('Cancelled');
141
+ process.exit(0);
142
+ return;
143
+ }
144
+ switch (selected) {
145
+ case 'mcp':
146
+ log.step('Starting MCP server...');
147
+ await runMcpMode();
148
+ break;
149
+ case 'web':
150
+ log.step('Starting Web UI...');
151
+ await runWebOnly();
152
+ break;
153
+ case 'health':
154
+ log.step('Checking health...');
155
+ await runCliCommand('health');
156
+ await runCliCommand('stats');
157
+ break;
158
+ case 'help':
159
+ showHelp();
160
+ process.exit(0);
161
+ break;
162
+ case 'exit':
163
+ outro('Goodbye! 👋');
164
+ process.exit(0);
165
+ break;
166
+ }
167
+ }
168
+ async function runCliCommand(command) {
169
+ // Run CLI command programmatically
170
+ const program = new Command();
171
+ program.hook('preAction', async () => {
172
+ await ensureDataDirectory();
173
+ });
174
+ if (command === 'health') {
175
+ const dbHealth = await checkDatabaseHealth();
176
+ const redisHealth = await checkRedisHealth();
177
+ const dataDir = process.env.SQUISH_DATA_DIR || path.join(os.homedir(), '.squish');
178
+ const dirExists = fs.existsSync(dataDir);
179
+ console.log(`\n Squish Memory v${VERSION}`);
180
+ console.log(` ====================`);
181
+ console.log(` Mode: ${config.isTeamMode ? 'team' : 'local'}`);
182
+ console.log(` Database: ${dbHealth ? 'ok' : 'error'}`);
183
+ console.log(` Cache: ${redisHealth ? 'ok' : 'unavailable'}`);
184
+ console.log(` Data Dir: ${dataDir}`);
185
+ console.log(` Status: ${dbHealth ? 'HEALTHY' : 'UNHEALTHY'}\n`);
186
+ }
187
+ else if (command === 'stats') {
188
+ const stats = await getMemoryStats(process.cwd());
189
+ console.log(JSON.stringify({ ok: true, ...stats }, null, 2));
190
+ }
191
+ }
192
+ async function spawnInstallerWizard() {
193
+ const distDir = path.dirname(fileURLToPath(import.meta.url));
194
+ const packageDir = path.dirname(distDir);
195
+ const installScript = path.join(packageDir, 'scripts', 'install-interactive.mjs');
196
+ if (!fs.existsSync(installScript)) {
197
+ console.error('Installer not found at:', installScript);
100
198
  process.exit(1);
199
+ }
200
+ console.log('\nLaunching full installer wizard...\n');
201
+ const result = spawnSync('node', [`"${installScript}"`], {
202
+ stdio: 'inherit',
203
+ shell: true,
204
+ cwd: packageDir
101
205
  });
206
+ process.exit(result.status || 0);
207
+ }
208
+ function isDatabaseInitialized() {
209
+ try {
210
+ const dataDir = getDataDir();
211
+ const dbPath = path.join(dataDir, 'squish.db');
212
+ return existsSync(dataDir) && existsSync(dbPath);
213
+ }
214
+ catch (error) {
215
+ return false;
216
+ }
217
+ }
218
+ async function runWebOnly() {
219
+ console.log(`[squish] Starting Web UI only...`);
220
+ await ensureDataDirectory();
221
+ startWebServer();
222
+ }
223
+ // ============================================================================
224
+ // CLI MODE DETECTION
225
+ // ============================================================================
226
+ const args = process.argv.slice(2);
227
+ const firstArg = args[0];
228
+ // Detect command type
229
+ const isNoArgs = args.length === 0;
230
+ const isRunCommand = firstArg === 'run';
231
+ const isHelpCommand = firstArg === '--help' || firstArg === '-h' || firstArg === 'help';
232
+ if (isNoArgs) {
233
+ // Check if database exists - if not, run installer automatically
234
+ if (!isDatabaseInitialized()) {
235
+ console.log(`[squish] No existing database found. Launching installer wizard...\n`);
236
+ await spawnInstallerWizard();
237
+ }
238
+ else {
239
+ // === INTERACTIVE WIZARD (default when no args) ===
240
+ runInteractiveInstaller().catch((e) => {
241
+ console.error('Installer error:', e.message);
242
+ process.exit(1);
243
+ });
244
+ }
245
+ }
246
+ else if (isRunCommand) {
247
+ // === RUN SUBCOMMAND ===
248
+ const subcommand = args[1];
249
+ if (subcommand === 'mcp') {
250
+ runMcpMode().catch((e) => {
251
+ logger.error('Fatal error', e);
252
+ process.exit(1);
253
+ });
254
+ }
255
+ else if (subcommand === 'web') {
256
+ runWebOnly().catch((e) => {
257
+ logger.error('Web server error', e);
258
+ process.exit(1);
259
+ });
260
+ }
261
+ else {
262
+ console.log(`
263
+ Usage: squish run <command>
264
+
265
+ Commands:
266
+ mcp Start MCP server
267
+ web Start Web UI only
268
+
269
+ Examples:
270
+ squish run mcp # Start MCP server with web UI
271
+ squish run web # Start Web UI only
272
+ `);
273
+ process.exit(subcommand ? 1 : 0);
274
+ }
275
+ }
276
+ else if (isHelpCommand) {
277
+ // === SHOW HELP ===
278
+ showHelp();
279
+ process.exit(0);
102
280
  }
103
281
  else {
104
- // === MCP MODE (for Claude Code) - DEFAULT ===
105
- runMcpMode().catch((e) => {
106
- logger.error('Fatal error', e);
282
+ // === CLI MODE (for agents/OpenClaw) ===
283
+ runCliMode().catch((e) => {
284
+ console.error(JSON.stringify({ error: e.message }, null, 2));
107
285
  process.exit(1);
108
286
  });
109
287
  }
@@ -365,7 +543,7 @@ async function runCliMode() {
365
543
  // squish stats
366
544
  program
367
545
  .command('stats')
368
- .description('Get memory statistics')
546
+ .description('View statistics')
369
547
  .option('-p, --project <project>', 'Project path', process.cwd())
370
548
  .action(async (options) => {
371
549
  try {
@@ -377,44 +555,12 @@ async function runCliMode() {
377
555
  process.exit(1);
378
556
  }
379
557
  });
380
- // squish install (for OpenClaw self-install)
558
+ // squish install
381
559
  program
382
560
  .command('install')
383
- .description('Install Squish for OpenClaw (self-configure MCP)')
384
- .option('-o, --openclaw-dir <dir>', 'OpenClaw directory')
385
- .option('-n, --dry-run', 'Show what would be done without making changes', false)
386
- .option('--skip-install', 'Skip global npm install step', false)
387
- .action(async (options) => {
388
- // Find the install script - it's in scripts/ relative to the package root
389
- // When running from dist/index.js, scripts is at ../scripts/
390
- const distDir = path.dirname(fileURLToPath(import.meta.url));
391
- const packageDir = path.dirname(distDir);
392
- const installScript = path.join(packageDir, 'scripts', 'install.mjs');
393
- // Check if the script exists
394
- if (!fs.existsSync(installScript)) {
395
- console.log(JSON.stringify({
396
- ok: false,
397
- error: `Install script not found at: ${installScript}`,
398
- hint: 'Please ensure squish-memory is installed correctly'
399
- }, null, 2));
400
- process.exit(1);
401
- }
402
- // Build command with quoted path for Windows compatibility
403
- const args = [`"${installScript}"`];
404
- if (options.dryRun)
405
- args.push('--dry-run');
406
- if (options.openclawDir)
407
- args.push('--openclaw-dir', `"${options.openclawDir}"`);
408
- if (options.skipInstall)
409
- args.push('--skip-install');
410
- const result = spawnSync('node', args, {
411
- stdio: 'inherit',
412
- shell: true,
413
- cwd: packageDir
414
- });
415
- if (result.status !== 0) {
416
- process.exit(result.status || 1);
417
- }
561
+ .description('Run the interactive installer wizard')
562
+ .action(async () => {
563
+ await spawnInstallerWizard();
418
564
  });
419
565
  await program.parseAsync(process.argv);
420
566
  }
@@ -1,23 +1,23 @@
1
- {
2
- "mode": "universal",
3
- "generatedAt": "2026-03-14T16:50:48.822Z",
4
- "source": "config/mcp.json",
5
- "files": [
6
- {
7
- "file": "mcp-servers.json",
8
- "sha256": "2c90cc52893f55bc92cc4f29c77bfeeb635c1c73fa46038d287548caeb35ca6a"
9
- },
10
- {
11
- "file": "mcporter.json",
12
- "sha256": "af42e1c03d44f66fcbe2a9b7694f1d3a126527147c66b760236e72348e1e4573"
13
- },
14
- {
15
- "file": "openclaw-memory-qmd.json",
16
- "sha256": "8a158ff45e98e0db7a7aff41dba7be76652b72aea82443773f9efc7fb056d615"
17
- },
18
- {
19
- "file": "runtime.json",
20
- "sha256": "4afbdec03de92c6a29fc24df32f01305c2e9cf69ed2d02866a01e361492d14b6"
21
- }
22
- ]
23
- }
1
+ {
2
+ "mode": "universal",
3
+ "generatedAt": "2026-03-18T18:13:29.152Z",
4
+ "source": "config/mcp.json",
5
+ "files": [
6
+ {
7
+ "file": "mcp-servers.json",
8
+ "sha256": "2c90cc52893f55bc92cc4f29c77bfeeb635c1c73fa46038d287548caeb35ca6a"
9
+ },
10
+ {
11
+ "file": "mcporter.json",
12
+ "sha256": "af42e1c03d44f66fcbe2a9b7694f1d3a126527147c66b760236e72348e1e4573"
13
+ },
14
+ {
15
+ "file": "openclaw-memory-qmd.json",
16
+ "sha256": "8a158ff45e98e0db7a7aff41dba7be76652b72aea82443773f9efc7fb056d615"
17
+ },
18
+ {
19
+ "file": "runtime.json",
20
+ "sha256": "4afbdec03de92c6a29fc24df32f01305c2e9cf69ed2d02866a01e361492d14b6"
21
+ }
22
+ ]
23
+ }