squish-memory 1.0.0 → 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 (300) hide show
  1. package/.env.mcp.example +18 -11
  2. package/README.md +59 -24
  3. package/bin/squish-add.mjs +32 -0
  4. package/bin/squish-rm.mjs +21 -0
  5. package/config/plugin-manifest.json +1 -1
  6. package/config/settings.json +51 -0
  7. package/dist/api/web/web.js +479 -452
  8. package/dist/commands/mcp-server.js +7 -3
  9. package/dist/config.d.ts +10 -10
  10. package/dist/config.js +78 -23
  11. package/dist/core/embeddings.d.ts +1 -1
  12. package/dist/core/embeddings.js +10 -67
  13. package/dist/core/local-embeddings.d.ts +3 -11
  14. package/dist/core/local-embeddings.js +2 -76
  15. package/dist/core/mcp/server.js +27 -1
  16. package/dist/core/mcp/types.d.ts +4 -4
  17. package/dist/core/memory/context-collector.js +3 -2
  18. package/dist/core/memory/feedback-tracker.js +10 -6
  19. package/dist/core/memory/hybrid-search.js +32 -32
  20. package/dist/core/memory/memories.js +55 -52
  21. package/dist/core/memory/query-rewriter.js +9 -9
  22. package/dist/core/memory/stats.js +5 -5
  23. package/dist/core/namespaces/index.js +20 -11
  24. package/dist/core/scheduler/cron-scheduler.js +78 -20
  25. package/dist/core/scheduler/job-runner.js +8 -5
  26. package/dist/core/search/conversations.js +33 -33
  27. package/dist/core/session-hooks/self-iteration-job.js +43 -39
  28. package/dist/core/session-hooks/session-hooks.js +6 -3
  29. package/dist/core/tracing/collector.js +25 -13
  30. package/dist/db/adapter.d.ts +6 -1
  31. package/dist/db/adapter.js +122 -126
  32. package/dist/db/bootstrap.js +622 -548
  33. package/dist/db/index.d.ts +5 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.js +195 -49
  36. package/generated/mcp/manifest.json +23 -23
  37. package/package.json +72 -59
  38. package/scripts/install-interactive.mjs +7 -4
  39. package/skills/memory-guide/SKILL.md +94 -18
  40. package/skills/squish-cli/SKILL.md +61 -21
  41. package/skills/squish-mcp/SKILL.md +46 -2
  42. package/skills/squish-memory/SKILL.md +30 -16
  43. package/dist/algorithms/analytics/token-estimator.d.ts.map +0 -1
  44. package/dist/algorithms/analytics/token-estimator.js.map +0 -1
  45. package/dist/algorithms/detection/hash-filters.d.ts.map +0 -1
  46. package/dist/algorithms/detection/hash-filters.js.map +0 -1
  47. package/dist/algorithms/detection/semantic-ranker.d.ts.map +0 -1
  48. package/dist/algorithms/detection/semantic-ranker.js.map +0 -1
  49. package/dist/algorithms/detection/two-stage-detector.d.ts.map +0 -1
  50. package/dist/algorithms/detection/two-stage-detector.js.map +0 -1
  51. package/dist/algorithms/handlers/approve-merge.d.ts.map +0 -1
  52. package/dist/algorithms/handlers/approve-merge.js.map +0 -1
  53. package/dist/algorithms/handlers/detect-duplicates.d.ts.map +0 -1
  54. package/dist/algorithms/handlers/detect-duplicates.js.map +0 -1
  55. package/dist/algorithms/handlers/get-stats.d.ts.map +0 -1
  56. package/dist/algorithms/handlers/get-stats.js.map +0 -1
  57. package/dist/algorithms/handlers/list-proposals.d.ts.map +0 -1
  58. package/dist/algorithms/handlers/list-proposals.js.map +0 -1
  59. package/dist/algorithms/handlers/preview-merge.d.ts.map +0 -1
  60. package/dist/algorithms/handlers/preview-merge.js.map +0 -1
  61. package/dist/algorithms/handlers/reject-merge.d.ts.map +0 -1
  62. package/dist/algorithms/handlers/reject-merge.js.map +0 -1
  63. package/dist/algorithms/handlers/reverse-merge.d.ts.map +0 -1
  64. package/dist/algorithms/handlers/reverse-merge.js.map +0 -1
  65. package/dist/algorithms/safety/safety-checks.d.ts.map +0 -1
  66. package/dist/algorithms/safety/safety-checks.js.map +0 -1
  67. package/dist/algorithms/strategies/merge-strategies.d.ts.map +0 -1
  68. package/dist/algorithms/strategies/merge-strategies.js.map +0 -1
  69. package/dist/algorithms/utils/response-builder.d.ts.map +0 -1
  70. package/dist/algorithms/utils/response-builder.js.map +0 -1
  71. package/dist/api/web/index.d.ts.map +0 -1
  72. package/dist/api/web/index.js.map +0 -1
  73. package/dist/api/web/web-server.d.ts.map +0 -1
  74. package/dist/api/web/web-server.js.map +0 -1
  75. package/dist/api/web/web.d.ts.map +0 -1
  76. package/dist/api/web/web.js.map +0 -1
  77. package/dist/commands/managed-sync.d.ts.map +0 -1
  78. package/dist/commands/managed-sync.js.map +0 -1
  79. package/dist/commands/mcp-server.d.ts.map +0 -1
  80. package/dist/commands/mcp-server.js.map +0 -1
  81. package/dist/config.d.ts.map +0 -1
  82. package/dist/config.js.map +0 -1
  83. package/dist/core/agent-memory.d.ts.map +0 -1
  84. package/dist/core/agent-memory.js.map +0 -1
  85. package/dist/core/associations.d.ts.map +0 -1
  86. package/dist/core/associations.js.map +0 -1
  87. package/dist/core/cache.d.ts.map +0 -1
  88. package/dist/core/cache.js.map +0 -1
  89. package/dist/core/consolidation.d.ts.map +0 -1
  90. package/dist/core/consolidation.js.map +0 -1
  91. package/dist/core/context-paging.d.ts.map +0 -1
  92. package/dist/core/context-paging.js.map +0 -1
  93. package/dist/core/context.d.ts.map +0 -1
  94. package/dist/core/context.js.map +0 -1
  95. package/dist/core/core-memory.d.ts.map +0 -1
  96. package/dist/core/core-memory.js.map +0 -1
  97. package/dist/core/database.d.ts.map +0 -1
  98. package/dist/core/database.js.map +0 -1
  99. package/dist/core/embeddings/google-multimodal.d.ts.map +0 -1
  100. package/dist/core/embeddings/google-multimodal.js.map +0 -1
  101. package/dist/core/embeddings/qmd-client.d.ts.map +0 -1
  102. package/dist/core/embeddings/qmd-client.js.map +0 -1
  103. package/dist/core/embeddings.d.ts.map +0 -1
  104. package/dist/core/embeddings.js.map +0 -1
  105. package/dist/core/governance.d.ts.map +0 -1
  106. package/dist/core/governance.js.map +0 -1
  107. package/dist/core/index.d.ts.map +0 -1
  108. package/dist/core/index.js.map +0 -1
  109. package/dist/core/layers/generator.d.ts.map +0 -1
  110. package/dist/core/layers/generator.js.map +0 -1
  111. package/dist/core/lifecycle.d.ts.map +0 -1
  112. package/dist/core/lifecycle.js.map +0 -1
  113. package/dist/core/local-embeddings.d.ts.map +0 -1
  114. package/dist/core/local-embeddings.js.map +0 -1
  115. package/dist/core/logger.d.ts.map +0 -1
  116. package/dist/core/logger.js.map +0 -1
  117. package/dist/core/mcp/client.d.ts.map +0 -1
  118. package/dist/core/mcp/client.js.map +0 -1
  119. package/dist/core/mcp/index.d.ts.map +0 -1
  120. package/dist/core/mcp/index.js.map +0 -1
  121. package/dist/core/mcp/server.d.ts.map +0 -1
  122. package/dist/core/mcp/server.js.map +0 -1
  123. package/dist/core/mcp/standalone-server.d.ts.map +0 -1
  124. package/dist/core/mcp/standalone-server.js.map +0 -1
  125. package/dist/core/mcp/tools.d.ts.map +0 -1
  126. package/dist/core/mcp/tools.js.map +0 -1
  127. package/dist/core/mcp/types.d.ts.map +0 -1
  128. package/dist/core/mcp/types.js.map +0 -1
  129. package/dist/core/memory/bridge-discovery.d.ts.map +0 -1
  130. package/dist/core/memory/bridge-discovery.js.map +0 -1
  131. package/dist/core/memory/categorizer.d.ts.map +0 -1
  132. package/dist/core/memory/categorizer.js.map +0 -1
  133. package/dist/core/memory/conflict-detector.d.ts.map +0 -1
  134. package/dist/core/memory/conflict-detector.js.map +0 -1
  135. package/dist/core/memory/consolidation.d.ts.map +0 -1
  136. package/dist/core/memory/consolidation.js.map +0 -1
  137. package/dist/core/memory/context-collector.d.ts.map +0 -1
  138. package/dist/core/memory/context-collector.js.map +0 -1
  139. package/dist/core/memory/contradiction-resolver.d.ts.map +0 -1
  140. package/dist/core/memory/contradiction-resolver.js.map +0 -1
  141. package/dist/core/memory/edit-workflow.d.ts.map +0 -1
  142. package/dist/core/memory/edit-workflow.js.map +0 -1
  143. package/dist/core/memory/entity-extractor.d.ts.map +0 -1
  144. package/dist/core/memory/entity-extractor.js.map +0 -1
  145. package/dist/core/memory/entity-resolver.d.ts.map +0 -1
  146. package/dist/core/memory/entity-resolver.js.map +0 -1
  147. package/dist/core/memory/fact-extractor.d.ts.map +0 -1
  148. package/dist/core/memory/fact-extractor.js.map +0 -1
  149. package/dist/core/memory/feedback-tracker.d.ts.map +0 -1
  150. package/dist/core/memory/feedback-tracker.js.map +0 -1
  151. package/dist/core/memory/hybrid-retrieval.d.ts.map +0 -1
  152. package/dist/core/memory/hybrid-retrieval.js.map +0 -1
  153. package/dist/core/memory/hybrid-scorer.d.ts.map +0 -1
  154. package/dist/core/memory/hybrid-scorer.js.map +0 -1
  155. package/dist/core/memory/hybrid-search.d.ts.map +0 -1
  156. package/dist/core/memory/hybrid-search.js.map +0 -1
  157. package/dist/core/memory/importance.d.ts.map +0 -1
  158. package/dist/core/memory/importance.js.map +0 -1
  159. package/dist/core/memory/index.d.ts.map +0 -1
  160. package/dist/core/memory/index.js.map +0 -1
  161. package/dist/core/memory/memories.d.ts.map +0 -1
  162. package/dist/core/memory/memories.js.map +0 -1
  163. package/dist/core/memory/memory-manager.d.ts.map +0 -1
  164. package/dist/core/memory/memory-manager.js.map +0 -1
  165. package/dist/core/memory/progressive-disclosure.d.ts.map +0 -1
  166. package/dist/core/memory/progressive-disclosure.js.map +0 -1
  167. package/dist/core/memory/query-processor.d.ts.map +0 -1
  168. package/dist/core/memory/query-processor.js.map +0 -1
  169. package/dist/core/memory/query-rewriter.d.ts.map +0 -1
  170. package/dist/core/memory/query-rewriter.js.map +0 -1
  171. package/dist/core/memory/response-analyzer.d.ts.map +0 -1
  172. package/dist/core/memory/response-analyzer.js.map +0 -1
  173. package/dist/core/memory/serialization.d.ts.map +0 -1
  174. package/dist/core/memory/serialization.js.map +0 -1
  175. package/dist/core/memory/stats.d.ts.map +0 -1
  176. package/dist/core/memory/stats.js.map +0 -1
  177. package/dist/core/memory/telemetry.d.ts.map +0 -1
  178. package/dist/core/memory/telemetry.js.map +0 -1
  179. package/dist/core/memory/temporal-facts.d.ts.map +0 -1
  180. package/dist/core/memory/temporal-facts.js.map +0 -1
  181. package/dist/core/memory/temporal-parser.d.ts.map +0 -1
  182. package/dist/core/memory/temporal-parser.js.map +0 -1
  183. package/dist/core/memory/trigger-detector.d.ts.map +0 -1
  184. package/dist/core/memory/trigger-detector.js.map +0 -1
  185. package/dist/core/memory/write-gate.d.ts.map +0 -1
  186. package/dist/core/memory/write-gate.js.map +0 -1
  187. package/dist/core/namespaces/index.d.ts.map +0 -1
  188. package/dist/core/namespaces/index.js.map +0 -1
  189. package/dist/core/namespaces/uri-parser.d.ts.map +0 -1
  190. package/dist/core/namespaces/uri-parser.js.map +0 -1
  191. package/dist/core/observations.d.ts.map +0 -1
  192. package/dist/core/observations.js.map +0 -1
  193. package/dist/core/privacy.d.ts.map +0 -1
  194. package/dist/core/privacy.js.map +0 -1
  195. package/dist/core/projects.d.ts.map +0 -1
  196. package/dist/core/projects.js.map +0 -1
  197. package/dist/core/redis.d.ts.map +0 -1
  198. package/dist/core/redis.js.map +0 -1
  199. package/dist/core/requirements.d.ts.map +0 -1
  200. package/dist/core/requirements.js.map +0 -1
  201. package/dist/core/scheduler/cron-scheduler.d.ts.map +0 -1
  202. package/dist/core/scheduler/cron-scheduler.js.map +0 -1
  203. package/dist/core/scheduler/heartbeat.d.ts.map +0 -1
  204. package/dist/core/scheduler/heartbeat.js.map +0 -1
  205. package/dist/core/scheduler/index.d.ts.map +0 -1
  206. package/dist/core/scheduler/index.js.map +0 -1
  207. package/dist/core/scheduler/job-runner.d.ts.map +0 -1
  208. package/dist/core/scheduler/job-runner.js.map +0 -1
  209. package/dist/core/search/conversations.d.ts.map +0 -1
  210. package/dist/core/search/conversations.js.map +0 -1
  211. package/dist/core/search/entities.d.ts.map +0 -1
  212. package/dist/core/search/entities.js.map +0 -1
  213. package/dist/core/search/folder-context.d.ts.map +0 -1
  214. package/dist/core/search/folder-context.js.map +0 -1
  215. package/dist/core/search/index.d.ts.map +0 -1
  216. package/dist/core/search/index.js.map +0 -1
  217. package/dist/core/search/qmd-search.d.ts.map +0 -1
  218. package/dist/core/search/qmd-search.js.map +0 -1
  219. package/dist/core/secret-detector.d.ts.map +0 -1
  220. package/dist/core/secret-detector.js.map +0 -1
  221. package/dist/core/session/auto-load.d.ts.map +0 -1
  222. package/dist/core/session/auto-load.js.map +0 -1
  223. package/dist/core/session/index.d.ts.map +0 -1
  224. package/dist/core/session/index.js.map +0 -1
  225. package/dist/core/session/types.d.ts.map +0 -1
  226. package/dist/core/session/types.js.map +0 -1
  227. package/dist/core/session-hooks/self-iteration-job.d.ts.map +0 -1
  228. package/dist/core/session-hooks/self-iteration-job.js.map +0 -1
  229. package/dist/core/session-hooks/session-hooks.d.ts.map +0 -1
  230. package/dist/core/session-hooks/session-hooks.js.map +0 -1
  231. package/dist/core/snapshots/cleanup.d.ts.map +0 -1
  232. package/dist/core/snapshots/cleanup.js.map +0 -1
  233. package/dist/core/snapshots/comparison.d.ts.map +0 -1
  234. package/dist/core/snapshots/comparison.js.map +0 -1
  235. package/dist/core/snapshots/creation.d.ts.map +0 -1
  236. package/dist/core/snapshots/creation.js.map +0 -1
  237. package/dist/core/snapshots/retrieval.d.ts.map +0 -1
  238. package/dist/core/snapshots/retrieval.js.map +0 -1
  239. package/dist/core/snapshots/stats.d.ts.map +0 -1
  240. package/dist/core/snapshots/stats.js.map +0 -1
  241. package/dist/core/snapshots.d.ts.map +0 -1
  242. package/dist/core/snapshots.js.map +0 -1
  243. package/dist/core/summarization/cleanup.d.ts.map +0 -1
  244. package/dist/core/summarization/cleanup.js.map +0 -1
  245. package/dist/core/summarization/queries.d.ts.map +0 -1
  246. package/dist/core/summarization/queries.js.map +0 -1
  247. package/dist/core/summarization/stats.d.ts.map +0 -1
  248. package/dist/core/summarization/stats.js.map +0 -1
  249. package/dist/core/summarization/strategies.d.ts.map +0 -1
  250. package/dist/core/summarization/strategies.js.map +0 -1
  251. package/dist/core/summarization.d.ts.map +0 -1
  252. package/dist/core/summarization.js.map +0 -1
  253. package/dist/core/sync/qmd-sync.d.ts.map +0 -1
  254. package/dist/core/sync/qmd-sync.js.map +0 -1
  255. package/dist/core/temporal-facts.d.ts.map +0 -1
  256. package/dist/core/temporal-facts.js.map +0 -1
  257. package/dist/core/tracing/collector.d.ts.map +0 -1
  258. package/dist/core/tracing/collector.js.map +0 -1
  259. package/dist/core/tracing/visualizer.d.ts.map +0 -1
  260. package/dist/core/tracing/visualizer.js.map +0 -1
  261. package/dist/core/utils/cleanup-operations.d.ts.map +0 -1
  262. package/dist/core/utils/cleanup-operations.js.map +0 -1
  263. package/dist/core/utils/content-extraction.d.ts.map +0 -1
  264. package/dist/core/utils/content-extraction.js.map +0 -1
  265. package/dist/core/utils/filter-builder.d.ts.map +0 -1
  266. package/dist/core/utils/filter-builder.js.map +0 -1
  267. package/dist/core/utils/history-traversal.d.ts.map +0 -1
  268. package/dist/core/utils/history-traversal.js.map +0 -1
  269. package/dist/core/utils/memory-operations.d.ts.map +0 -1
  270. package/dist/core/utils/memory-operations.js.map +0 -1
  271. package/dist/core/utils/query-operations.d.ts.map +0 -1
  272. package/dist/core/utils/query-operations.js.map +0 -1
  273. package/dist/core/utils/summarization-helpers.d.ts.map +0 -1
  274. package/dist/core/utils/summarization-helpers.js.map +0 -1
  275. package/dist/core/utils/temporal-queries.d.ts.map +0 -1
  276. package/dist/core/utils/temporal-queries.js.map +0 -1
  277. package/dist/core/utils/version-management.d.ts.map +0 -1
  278. package/dist/core/utils/version-management.js.map +0 -1
  279. package/dist/core/utils.d.ts.map +0 -1
  280. package/dist/core/utils.js.map +0 -1
  281. package/dist/core/worker.d.ts.map +0 -1
  282. package/dist/core/worker.js.map +0 -1
  283. package/dist/db/adapter.d.ts.map +0 -1
  284. package/dist/db/adapter.js.map +0 -1
  285. package/dist/db/bootstrap.d.ts.map +0 -1
  286. package/dist/db/bootstrap.js.map +0 -1
  287. package/dist/db/index.d.ts.map +0 -1
  288. package/dist/db/index.js.map +0 -1
  289. package/dist/db/schema.d.ts.map +0 -1
  290. package/dist/db/schema.js.map +0 -1
  291. package/dist/drizzle/schema-sqlite.d.ts.map +0 -1
  292. package/dist/drizzle/schema-sqlite.js.map +0 -1
  293. package/dist/drizzle/schema.d.ts.map +0 -1
  294. package/dist/drizzle/schema.js.map +0 -1
  295. package/dist/index.d.ts.map +0 -1
  296. package/dist/index.js.map +0 -1
  297. package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts.map +0 -1
  298. package/packages/plugin-claude-code/dist/plugin-wrapper.js.map +0 -1
  299. package/packages/plugin-openclaw/dist/index.d.ts.map +0 -1
  300. package/packages/plugin-openclaw/dist/index.js.map +0 -1
@@ -73,22 +73,22 @@ async function bm25Search(input, options) {
73
73
  // For empty query with no filters, use "1=1" to match all
74
74
  const whereClause = conditions.length > 0 ? conditions.join(' AND ') : '1=1';
75
75
  // Build query based on whether we have a search term or not
76
- const statement = sqlite.prepare(`
77
- SELECT
78
- m.id as id,
79
- m.project_id as projectId,
80
- m.type as type,
81
- m.content as content,
82
- m.summary as summary,
83
- m.tags as tags,
84
- m.metadata as metadata,
85
- ${isEmptyQuery ? '0 as bm25Score' : 'bm25(memories_fts) as bm25Score'},
86
- m.created_at as createdAt
87
- FROM memories m
88
- ${isEmptyQuery ? '' : 'INNER JOIN memories_fts ON m.rowid = memories_fts.rowid'}
89
- WHERE ${whereClause}
90
- ${isEmptyQuery ? 'ORDER BY m.created_at DESC' : 'ORDER BY bm25(memories_fts)'}
91
- LIMIT ?
76
+ const statement = sqlite.prepare(`
77
+ SELECT
78
+ m.id as id,
79
+ m.project_id as projectId,
80
+ m.type as type,
81
+ m.content as content,
82
+ m.summary as summary,
83
+ m.tags as tags,
84
+ m.metadata as metadata,
85
+ ${isEmptyQuery ? '0 as bm25Score' : 'bm25(memories_fts) as bm25Score'},
86
+ m.created_at as createdAt
87
+ FROM memories m
88
+ ${isEmptyQuery ? '' : 'INNER JOIN memories_fts ON m.rowid = memories_fts.rowid'}
89
+ WHERE ${whereClause}
90
+ ${isEmptyQuery ? 'ORDER BY m.created_at DESC' : 'ORDER BY bm25(memories_fts)'}
91
+ LIMIT ?
92
92
  `);
93
93
  const rows = statement.all(...params, limit * 3);
94
94
  // Return as ranked results (lower BM25 score = better rank)
@@ -154,22 +154,22 @@ async function vectorSearch(input, options) {
154
154
  ? 'WHERE ' + conditions.join(' AND ')
155
155
  : '';
156
156
  // Fetch candidates for vector search
157
- const statement = sqlite.prepare(`
158
- SELECT
159
- m.id as id,
160
- m.project_id as projectId,
161
- m.type as type,
162
- m.content as content,
163
- m.summary as summary,
164
- m.tags as tags,
165
- m.metadata as metadata,
166
- m.embedding as embedding,
167
- m.embedding_json as embeddingJson,
168
- m.created_at as createdAt
169
- FROM memories m
170
- ${whereClause}
171
- ORDER BY m.created_at DESC
172
- LIMIT ?
157
+ const statement = sqlite.prepare(`
158
+ SELECT
159
+ m.id as id,
160
+ m.project_id as projectId,
161
+ m.type as type,
162
+ m.content as content,
163
+ m.summary as summary,
164
+ m.tags as tags,
165
+ m.metadata as metadata,
166
+ m.embedding as embedding,
167
+ m.embedding_json as embeddingJson,
168
+ m.created_at as createdAt
169
+ FROM memories m
170
+ ${whereClause}
171
+ ORDER BY m.created_at DESC
172
+ LIMIT ?
173
173
  `);
174
174
  const rows = statement.all(...params, limit * 3);
175
175
  // If no embedding available, return results ordered by recency
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'crypto';
2
- import { desc, eq } from 'drizzle-orm';
2
+ import { eq } from 'drizzle-orm';
3
3
  import { getDb } from '../../db/index.js';
4
4
  import { getSchema } from '../../db/schema.js';
5
5
  import { config } from '../../config.js';
@@ -143,14 +143,17 @@ export async function getMemoryById(id, incrementAccess = true) {
143
143
  export async function getRecentMemories(projectPath, limit) {
144
144
  try {
145
145
  const db = createDatabaseClient(await getDb());
146
- const schema = await getSchema();
146
+ const sqlite = db.$client;
147
147
  const project = await getProjectByPath(projectPath);
148
148
  if (!project)
149
149
  return [];
150
- const rows = await db.select().from(schema.memories)
151
- .where(eq(schema.memories.projectId, project.id))
152
- .orderBy(desc(schema.memories.createdAt))
153
- .limit(limit);
150
+ // Use raw SQL to avoid drizzle column name issues
151
+ const rows = sqlite.prepare(`
152
+ SELECT * FROM memories
153
+ WHERE project_id = ?
154
+ ORDER BY created_at DESC
155
+ LIMIT ?
156
+ `).all(project.id, limit);
154
157
  return rows.map((row) => normalizeMemory(row));
155
158
  }
156
159
  catch (error) {
@@ -257,22 +260,22 @@ async function searchMemoriesSqlite(input, tags, limit) {
257
260
  const whereClause = conditions.length > 0 ? 'WHERE ' + conditions.join(' AND ') : '';
258
261
  // Fetch memories with embeddings for semantic search
259
262
  const fetchLimit = Math.max(limit * 3, 50); // Fetch more for re-ranking
260
- const statement = sqlite.prepare(`
261
- SELECT
262
- m.id as id,
263
- m.project_id as projectId,
264
- m.type as type,
265
- m.content as content,
266
- m.summary as summary,
267
- m.tags as tags,
268
- m.metadata as metadata,
269
- m.embedding as embedding,
270
- m.embedding_json as embeddingJson,
271
- m.created_at as createdAt
272
- FROM memories m
273
- ${whereClause}
274
- ORDER BY m.created_at DESC
275
- LIMIT ?
263
+ const statement = sqlite.prepare(`
264
+ SELECT
265
+ m.id as id,
266
+ m.project_id as projectId,
267
+ m.type as type,
268
+ m.content as content,
269
+ m.summary as summary,
270
+ m.tags as tags,
271
+ m.metadata as metadata,
272
+ m.embedding as embedding,
273
+ m.embedding_json as embeddingJson,
274
+ m.created_at as createdAt
275
+ FROM memories m
276
+ ${whereClause}
277
+ ORDER BY m.created_at DESC
278
+ LIMIT ?
276
279
  `);
277
280
  const rows = statement.all(...params, fetchLimit);
278
281
  if (rows.length === 0)
@@ -326,42 +329,42 @@ async function searchMemoriesPostgres(input, tags, limit) {
326
329
  const whereClause = whereParts.length ? `WHERE ${whereParts.join(' AND ')}` : '';
327
330
  const embedding = await getEmbedding(input.query);
328
331
  if (embedding) {
329
- const rows = await db.$client.query(`SELECT
330
- id,
331
- project_id as "projectId",
332
- type,
333
- content,
334
- summary,
335
- tags,
336
- metadata,
337
- created_at as "createdAt",
338
- valid_from as "validFrom",
339
- valid_to as "validTo",
340
- recorded_at as "recordedAt"
341
- FROM memories
342
- ${whereClause}
343
- ORDER BY created_at DESC
332
+ const rows = await db.$client.query(`SELECT
333
+ id,
334
+ project_id as "projectId",
335
+ type,
336
+ content,
337
+ summary,
338
+ tags,
339
+ metadata,
340
+ created_at as "createdAt",
341
+ valid_from as "validFrom",
342
+ valid_to as "validTo",
343
+ recorded_at as "recordedAt"
344
+ FROM memories
345
+ ${whereClause}
346
+ ORDER BY created_at DESC
344
347
  LIMIT $${values.length + 1}`, [...values, limit]);
345
348
  return rows.rows.map((row) => ({
346
349
  ...normalizeMemory(row),
347
350
  similarity: row.similarity ?? 0,
348
351
  }));
349
352
  }
350
- const rows = await db.$client.query(`SELECT
351
- id,
352
- project_id as "projectId",
353
- type,
354
- content,
355
- summary,
356
- tags,
357
- metadata,
358
- created_at as "createdAt",
359
- valid_from as "validFrom",
360
- valid_to as "validTo",
361
- recorded_at as "recordedAt"
362
- FROM memories
363
- ${whereClause}
364
- ORDER BY created_at DESC
353
+ const rows = await db.$client.query(`SELECT
354
+ id,
355
+ project_id as "projectId",
356
+ type,
357
+ content,
358
+ summary,
359
+ tags,
360
+ metadata,
361
+ created_at as "createdAt",
362
+ valid_from as "validFrom",
363
+ valid_to as "validTo",
364
+ recorded_at as "recordedAt"
365
+ FROM memories
366
+ ${whereClause}
367
+ ORDER BY created_at DESC
365
368
  LIMIT $${values.length + 1}`, [...values, limit]);
366
369
  return rows.rows.map((row) => ({
367
370
  ...normalizeMemory(row),
@@ -2,15 +2,15 @@
2
2
  import { logger } from '../logger.js';
3
3
  import { config } from '../../config.js';
4
4
  import { expandQuery } from './query-processor.js';
5
- const REWRITE_SYSTEM_PROMPT = `You are a search query optimizer. Given a conversation context and a user's latest message, rewrite the message into the single most effective search query to retrieve relevant memories.
6
-
7
- Rules:
8
- 1. Output ONLY the optimized search query - no explanations or extra text
9
- 2. Remove filler words (please, can you, etc.)
10
- 3. Focus on the core information need
11
- 4. Preserve important entities (names, dates, technical terms)
12
- 5. Add synonyms for key terms if helpful
13
- 6. Consider what memories would be most relevant
5
+ const REWRITE_SYSTEM_PROMPT = `You are a search query optimizer. Given a conversation context and a user's latest message, rewrite the message into the single most effective search query to retrieve relevant memories.
6
+
7
+ Rules:
8
+ 1. Output ONLY the optimized search query - no explanations or extra text
9
+ 2. Remove filler words (please, can you, etc.)
10
+ 3. Focus on the core information need
11
+ 4. Preserve important entities (names, dates, technical terms)
12
+ 5. Add synonyms for key terms if helpful
13
+ 6. Consider what memories would be most relevant
14
14
  7. If the message is about recalling something specific, include those details`;
15
15
  export async function rewriteQuery(query, context) {
16
16
  if (!config.queryRewritingEnabled) {
@@ -36,11 +36,11 @@ export async function getMemoryStats(projectPath = process.cwd()) {
36
36
  // Count by type
37
37
  if (config.isTeamMode) {
38
38
  // PostgreSQL - use raw query for GROUP BY
39
- const typeCounts = await db.execute(sql `
40
- SELECT type, COUNT(*) as count
41
- FROM memories
42
- ${project ? sql `WHERE project_id = ${project.id}` : sql ``}
43
- GROUP BY type
39
+ const typeCounts = await db.execute(sql `
40
+ SELECT type, COUNT(*) as count
41
+ FROM memories
42
+ ${project ? sql `WHERE project_id = ${project.id}` : sql ``}
43
+ GROUP BY type
44
44
  `);
45
45
  for (const row of typeCounts.rows) {
46
46
  stats.byType[row.type] = Number(row.count);
@@ -15,7 +15,8 @@ export async function createNamespace(input) {
15
15
  const schema = await getSchema();
16
16
  const id = randomUUID();
17
17
  // Check if namespace with same name exists under parent
18
- const existing = await db.select()
18
+ const sqliteDb = db;
19
+ const existing = await sqliteDb.select()
19
20
  .from(schema.namespaces)
20
21
  .where(and(eq(schema.namespaces.projectId, input.projectId), eq(schema.namespaces.name, input.name), input.parentId
21
22
  ? eq(schema.namespaces.parentId, input.parentId)
@@ -26,7 +27,7 @@ export async function createNamespace(input) {
26
27
  }
27
28
  // Build namespace path
28
29
  const path = await buildNamespacePath(input.projectId, input.name, input.parentId ?? null);
29
- await db.insert(schema.namespaces).values({
30
+ await sqliteDb.insert(schema.namespaces).values({
30
31
  id,
31
32
  projectId: input.projectId,
32
33
  name: input.name,
@@ -58,7 +59,8 @@ async function buildNamespacePath(projectId, name, parentId) {
58
59
  }
59
60
  const db = await getDb();
60
61
  const schema = await getSchema();
61
- const [parent] = await db.select()
62
+ const sqliteDb = db;
63
+ const [parent] = await sqliteDb.select()
62
64
  .from(schema.namespaces)
63
65
  .where(eq(schema.namespaces.id, parentId))
64
66
  .limit(1);
@@ -75,7 +77,8 @@ export async function getNamespaceById(id) {
75
77
  if (!db)
76
78
  return null;
77
79
  const schema = await getSchema();
78
- const [row] = await db.select()
80
+ const sqliteDb = db;
81
+ const [row] = await sqliteDb.select()
79
82
  .from(schema.namespaces)
80
83
  .where(eq(schema.namespaces.id, id))
81
84
  .limit(1);
@@ -104,11 +107,12 @@ export async function resolveNamespacePath(projectId, path) {
104
107
  if (!db)
105
108
  return null;
106
109
  const schema = await getSchema();
110
+ const sqliteDb = db;
107
111
  let parentId = null;
108
112
  let targetNamespace = null;
109
113
  // Traverse path segments
110
114
  for (const segment of path) {
111
- const [result] = await db.select()
115
+ const [result] = await sqliteDb.select()
112
116
  .from(schema.namespaces)
113
117
  .where(and(eq(schema.namespaces.projectId, projectId), eq(schema.namespaces.name, segment), parentId
114
118
  ? eq(schema.namespaces.parentId, parentId)
@@ -129,8 +133,9 @@ export async function getNamespaceTree(projectId) {
129
133
  if (!db)
130
134
  return [];
131
135
  const schema = await getSchema();
136
+ const sqliteDb = db;
132
137
  // Get all namespaces for project
133
- const all = await db.select()
138
+ const all = await sqliteDb.select()
134
139
  .from(schema.namespaces)
135
140
  .where(eq(schema.namespaces.projectId, projectId))
136
141
  .orderBy(schema.namespaces.name);
@@ -167,6 +172,7 @@ export async function getDefaultNamespaces(projectId) {
167
172
  if (!db)
168
173
  return [];
169
174
  const schema = await getSchema();
175
+ const sqliteDb = db;
170
176
  const created = [];
171
177
  const defaults = [
172
178
  { name: 'user', type: 'user', description: 'User-specific memories and preferences' },
@@ -175,7 +181,7 @@ export async function getDefaultNamespaces(projectId) {
175
181
  ];
176
182
  const defaultNames = ['user', 'agent', 'project'];
177
183
  // Check all default namespaces at once with IN clause
178
- const existing = await db.select()
184
+ const existing = await sqliteDb.select()
179
185
  .from(schema.namespaces)
180
186
  .where(and(eq(schema.namespaces.projectId, projectId), eq(schema.namespaces.name, defaultNames[0]), eq(schema.namespaces.type, 'user'), isNull(schema.namespaces.parentId)));
181
187
  if (existing.length > 0) {
@@ -199,7 +205,7 @@ export async function getDefaultNamespaces(projectId) {
199
205
  }
200
206
  // Check remaining defaults sequentially (agent and project)
201
207
  for (const defName of defaultNames.slice(1)) {
202
- const existing = await db.select()
208
+ const existing = await sqliteDb.select()
203
209
  .from(schema.namespaces)
204
210
  .where(and(eq(schema.namespaces.projectId, projectId), eq(schema.namespaces.name, defName), eq(schema.namespaces.type, defName), isNull(schema.namespaces.parentId)))
205
211
  .limit(1);
@@ -237,6 +243,7 @@ export async function listNamespaces(options = {}) {
237
243
  if (!db)
238
244
  return [];
239
245
  const schema = await getSchema();
246
+ const sqliteDb = db;
240
247
  const conditions = [];
241
248
  if (options.projectId) {
242
249
  conditions.push(eq(schema.namespaces.projectId, options.projectId));
@@ -252,7 +259,7 @@ export async function listNamespaces(options = {}) {
252
259
  conditions.push(eq(schema.namespaces.parentId, options.parentId));
253
260
  }
254
261
  }
255
- const rows = await db.select()
262
+ const rows = await sqliteDb.select()
256
263
  .from(schema.namespaces)
257
264
  .where(conditions.length > 0 ? and(...conditions) : undefined)
258
265
  .orderBy(schema.namespaces.name);
@@ -276,7 +283,8 @@ export async function deleteNamespace(id) {
276
283
  if (!db)
277
284
  return;
278
285
  const schema = await getSchema();
279
- await db.delete(schema.namespaces).where(eq(schema.namespaces.id, id));
286
+ const sqliteDb = db;
287
+ await sqliteDb.delete(schema.namespaces).where(eq(schema.namespaces.id, id));
280
288
  logger.info(`[Namespaces] Deleted namespace: ${id}`);
281
289
  }
282
290
  /**
@@ -287,7 +295,8 @@ export async function updateNamespace(id, updates) {
287
295
  if (!db)
288
296
  return;
289
297
  const schema = await getSchema();
290
- await db.update(schema.namespaces).set({
298
+ const sqliteDb = db;
299
+ await sqliteDb.update(schema.namespaces).set({
291
300
  ...updates,
292
301
  updatedAt: new Date(),
293
302
  }).where(eq(schema.namespaces.id, id));
@@ -26,7 +26,8 @@ export async function initializeScheduler() {
26
26
  }
27
27
  try {
28
28
  await ensureDefaultJobs(db);
29
- const jobs = await db
29
+ const sqliteDb = db;
30
+ const jobs = await sqliteDb
30
31
  .select()
31
32
  .from(maintenanceJobs)
32
33
  .where(eq(maintenanceJobs.enabled, true));
@@ -64,18 +65,61 @@ async function ensureDefaultJobs(db) {
64
65
  },
65
66
  ];
66
67
  for (const job of defaultJobs) {
67
- const existing = await db
68
- .select()
69
- .from(maintenanceJobs)
70
- .where(eq(maintenanceJobs.jobName, job.jobName))
71
- .limit(1);
68
+ let existing;
69
+ try {
70
+ existing = await db
71
+ .select()
72
+ .from(maintenanceJobs)
73
+ .where(eq(maintenanceJobs.jobName, job.jobName))
74
+ .limit(1);
75
+ }
76
+ catch (queryError) {
77
+ logger.error(`[Scheduler] Query failed for job ${job.jobName}:`, queryError.message);
78
+ // Try raw SQL fallback
79
+ try {
80
+ const rawDb = db.$client;
81
+ if (rawDb && typeof rawDb.prepare === 'function') {
82
+ existing = rawDb.prepare('SELECT * FROM maintenance_jobs WHERE job_name = ?').all(job.jobName);
83
+ }
84
+ }
85
+ catch (fallbackError) {
86
+ logger.error(`[Scheduler] Fallback query also failed:`, fallbackError.message);
87
+ throw queryError;
88
+ }
89
+ }
72
90
  if (existing.length === 0) {
73
- await db.insert(maintenanceJobs).values({
74
- ...job,
75
- totalRuns: 0,
76
- successCount: 0,
77
- failureCount: 0,
78
- });
91
+ try {
92
+ await db.insert(maintenanceJobs).values({
93
+ jobName: job.jobName,
94
+ jobType: job.jobType,
95
+ cronExpression: job.cronExpression,
96
+ enabled: job.enabled,
97
+ jobConfig: job.jobConfig,
98
+ totalRuns: 0,
99
+ successCount: 0,
100
+ failureCount: 0,
101
+ lastRunAt: null,
102
+ nextRunAt: null,
103
+ lastRunDuration: null,
104
+ lastRunStatus: null,
105
+ lastRunError: null,
106
+ });
107
+ }
108
+ catch (insertError) {
109
+ // Fallback to raw SQL if drizzle insert fails
110
+ logger.warn(`[Scheduler] Drizzle insert failed, using raw SQL: ${insertError.message}`);
111
+ const rawDb = db.$client;
112
+ if (rawDb && typeof rawDb.prepare === 'function') {
113
+ const stmt = rawDb.prepare(`
114
+ INSERT INTO maintenance_jobs
115
+ (id, job_name, job_type, cron_expression, enabled, job_config,
116
+ total_runs, success_count, failure_count, last_run_at, next_run_at,
117
+ last_run_duration, last_run_status, last_run_error)
118
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
119
+ `);
120
+ stmt.run(crypto.randomUUID(), job.jobName, job.jobType, job.cronExpression, job.enabled ? 1 : 0, JSON.stringify(job.jobConfig), 0, 0, 0, null, null, null, null, null);
121
+ }
122
+ }
79
123
  logger.info(`[Scheduler] Created default job: ${job.jobName}`);
80
124
  // Register self-iteration handler
81
125
  if (job.jobName === 'self_iteration') {
@@ -108,12 +152,13 @@ export async function scheduleJob(job) {
108
152
  const nextRun = getNextRunTime(job.cronExpression);
109
153
  const db = await getDb();
110
154
  if (db) {
111
- await db
155
+ const sqliteDb = db;
156
+ await sqliteDb
112
157
  .update(maintenanceJobs)
113
158
  .set({ nextRunAt: nextRun })
114
159
  .where(eq(maintenanceJobs.id, job.id));
115
160
  }
116
- logger.info(`[Scheduler] Scheduled ${job.jobName} with cron: ${job.cronExpression}, next run: ${nextRun?.toISOString()}`);
161
+ logger.info(`[Scheduler] Scheduled ${job.jobName} with cron: ${job.cronExpression}${nextRun ? `, next run: ${nextRun.toISOString()}` : ''}`);
117
162
  }
118
163
  export async function executeJob(job) {
119
164
  const db = await getDb();
@@ -147,11 +192,12 @@ export async function executeJob(job) {
147
192
  }
148
193
  const completedAt = new Date();
149
194
  if (db) {
150
- const [currentJob] = await db
195
+ const sqliteDb = db;
196
+ const [currentJob] = await sqliteDb
151
197
  .select()
152
198
  .from(maintenanceJobs)
153
199
  .where(eq(maintenanceJobs.id, job.id));
154
- await db
200
+ await sqliteDb
155
201
  .update(maintenanceJobs)
156
202
  .set({
157
203
  lastRunAt: startedAt,
@@ -164,7 +210,7 @@ export async function executeJob(job) {
164
210
  nextRunAt: job.cronExpression ? getNextRunTime(job.cronExpression) : null,
165
211
  })
166
212
  .where(eq(maintenanceJobs.id, job.id));
167
- await db.insert(maintenanceJobHistory).values({
213
+ await sqliteDb.insert(maintenanceJobHistory).values({
168
214
  jobId: job.id,
169
215
  startedAt,
170
216
  completedAt,
@@ -180,13 +226,23 @@ function getNextRunTime(cronExpression) {
180
226
  try {
181
227
  const now = new Date();
182
228
  const parts = cronExpression.split(' ');
183
- if (parts[2] === '*' && parts[3] === '*' && parts[4] === '*') {
229
+ // Daily jobs: MM HH * * *
230
+ if (parts[2] === '*' && parts[3] === '*' && parts[4] === '*' && parts[1] !== '*') {
184
231
  const next = new Date(now);
185
232
  next.setHours(parseInt(parts[1]), parseInt(parts[0]), 0, 0);
186
233
  if (next <= now)
187
234
  next.setDate(next.getDate() + 1);
188
235
  return next;
189
236
  }
237
+ // Hourly jobs: MM * * * *
238
+ if (parts[1] === '*' && parts[2] === '*' && parts[3] === '*' && parts[4] === '*') {
239
+ const next = new Date(now);
240
+ next.setMinutes(parseInt(parts[0]), 0, 0);
241
+ if (next <= now)
242
+ next.setHours(next.getHours() + 1);
243
+ return next;
244
+ }
245
+ // Weekly jobs: MM HH * * D
190
246
  if (parts[4] !== '*') {
191
247
  const dayOfWeek = parseInt(parts[4]);
192
248
  const next = new Date(now);
@@ -205,7 +261,8 @@ export async function getScheduledJobs() {
205
261
  const db = await getDb();
206
262
  if (!db)
207
263
  return [];
208
- const jobs = await db.select().from(maintenanceJobs);
264
+ const sqliteDb = db;
265
+ const jobs = await sqliteDb.select().from(maintenanceJobs);
209
266
  return jobs.map((job) => ({
210
267
  id: job.id,
211
268
  jobName: job.jobName,
@@ -222,7 +279,8 @@ export async function getOverdueJobs() {
222
279
  if (!db)
223
280
  return [];
224
281
  const now = new Date();
225
- const jobs = await db.select().from(maintenanceJobs);
282
+ const sqliteDb = db;
283
+ const jobs = await sqliteDb.select().from(maintenanceJobs);
226
284
  return jobs
227
285
  .filter((job) => {
228
286
  if (!job.enabled)
@@ -113,7 +113,8 @@ async function boostFrequentlyAccessed() {
113
113
  const db = await getDb();
114
114
  if (!db)
115
115
  return 0;
116
- const frequentlyAccessed = await db
116
+ const sqliteDb = db;
117
+ const frequentlyAccessed = await sqliteDb
117
118
  .select()
118
119
  .from(memories)
119
120
  .where(gt(memories.accessCount, 3));
@@ -121,7 +122,7 @@ async function boostFrequentlyAccessed() {
121
122
  for (const memory of frequentlyAccessed) {
122
123
  const currentPriority = memory.retrievalPriority ?? 50;
123
124
  const newPriority = Math.min(100, currentPriority + 5);
124
- await db
125
+ await sqliteDb
125
126
  .update(memories)
126
127
  .set({ retrievalPriority: newPriority })
127
128
  .where(eq(memories.id, memory.id));
@@ -134,13 +135,14 @@ async function archiveStaleMemories(daysOld) {
134
135
  if (!db)
135
136
  return 0;
136
137
  const staleThreshold = new Date(Date.now() - daysOld * 24 * 60 * 60 * 1000);
137
- const staleMemories = await db
138
+ const sqliteDb = db;
139
+ const staleMemories = await sqliteDb
138
140
  .select()
139
141
  .from(memories)
140
142
  .where(and(lt(memories.lastAccessedAt, staleThreshold), lt(memories.importanceScore, 30), eq(memories.isProtected, false), eq(memories.isPinned, false)));
141
143
  let archived = 0;
142
144
  for (const memory of staleMemories) {
143
- await db
145
+ await sqliteDb
144
146
  .update(memories)
145
147
  .set({ tier: 'cold' })
146
148
  .where(eq(memories.id, memory.id));
@@ -153,7 +155,8 @@ async function cleanupOldFeedbackRecords(daysOld) {
153
155
  if (!db)
154
156
  return 0;
155
157
  const oldThreshold = new Date(Date.now() - daysOld * 24 * 60 * 60 * 1000);
156
- await db
158
+ const sqliteDb = db;
159
+ await sqliteDb
157
160
  .delete(memoryFeedback)
158
161
  .where(lt(memoryFeedback.createdAt, oldThreshold));
159
162
  return 0;