@hasna/mementos 0.14.85 → 0.14.86

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 (564) hide show
  1. package/bun.lock +63 -4
  2. package/dist/cli/index.js +419 -188
  3. package/dist/diagnostics/historical-project-registration-receipt.js +36 -17
  4. package/dist/index.js +139 -50
  5. package/dist/mcp/index.js +181 -60
  6. package/dist/pg-sync-worker.js +7 -5
  7. package/dist/project-registration.js +108 -36
  8. package/dist/sdk/index.js +1 -0
  9. package/dist/server/index.js +384 -280
  10. package/dist/storage.js +63 -26
  11. package/hasna.contract.json +5 -4
  12. package/package.json +4 -3
  13. package/dist/cli/__fixtures__/clean-fallback-stub-server.d.ts +0 -2
  14. package/dist/cli/__fixtures__/clean-fallback-stub-server.d.ts.map +0 -1
  15. package/dist/cli/brains.d.ts +0 -3
  16. package/dist/cli/brains.d.ts.map +0 -1
  17. package/dist/cli/commands/agent.d.ts +0 -3
  18. package/dist/cli/commands/agent.d.ts.map +0 -1
  19. package/dist/cli/commands/consolidation.d.ts +0 -3
  20. package/dist/cli/commands/consolidation.d.ts.map +0 -1
  21. package/dist/cli/commands/entity.d.ts +0 -3
  22. package/dist/cli/commands/entity.d.ts.map +0 -1
  23. package/dist/cli/commands/graph.d.ts +0 -3
  24. package/dist/cli/commands/graph.d.ts.map +0 -1
  25. package/dist/cli/commands/info-context.d.ts +0 -3
  26. package/dist/cli/commands/info-context.d.ts.map +0 -1
  27. package/dist/cli/commands/info-history.d.ts +0 -3
  28. package/dist/cli/commands/info-history.d.ts.map +0 -1
  29. package/dist/cli/commands/info-report.d.ts +0 -3
  30. package/dist/cli/commands/info-report.d.ts.map +0 -1
  31. package/dist/cli/commands/info-stale.d.ts +0 -3
  32. package/dist/cli/commands/info-stale.d.ts.map +0 -1
  33. package/dist/cli/commands/info-stats.d.ts +0 -3
  34. package/dist/cli/commands/info-stats.d.ts.map +0 -1
  35. package/dist/cli/commands/info.d.ts +0 -12
  36. package/dist/cli/commands/info.d.ts.map +0 -1
  37. package/dist/cli/commands/init.d.ts +0 -3
  38. package/dist/cli/commands/init.d.ts.map +0 -1
  39. package/dist/cli/commands/io-backup.d.ts +0 -3
  40. package/dist/cli/commands/io-backup.d.ts.map +0 -1
  41. package/dist/cli/commands/io-clean.d.ts +0 -3
  42. package/dist/cli/commands/io-clean.d.ts.map +0 -1
  43. package/dist/cli/commands/io-export.d.ts +0 -3
  44. package/dist/cli/commands/io-export.d.ts.map +0 -1
  45. package/dist/cli/commands/io-import.d.ts +0 -3
  46. package/dist/cli/commands/io-import.d.ts.map +0 -1
  47. package/dist/cli/commands/io-restore.d.ts +0 -3
  48. package/dist/cli/commands/io-restore.d.ts.map +0 -1
  49. package/dist/cli/commands/io.d.ts +0 -12
  50. package/dist/cli/commands/io.d.ts.map +0 -1
  51. package/dist/cli/commands/memory-cmd-bulk.d.ts +0 -3
  52. package/dist/cli/commands/memory-cmd-bulk.d.ts.map +0 -1
  53. package/dist/cli/commands/memory-cmd-chain.d.ts +0 -3
  54. package/dist/cli/commands/memory-cmd-chain.d.ts.map +0 -1
  55. package/dist/cli/commands/memory-cmd-crud.d.ts +0 -3
  56. package/dist/cli/commands/memory-cmd-crud.d.ts.map +0 -1
  57. package/dist/cli/commands/memory-cmd-diff.d.ts +0 -3
  58. package/dist/cli/commands/memory-cmd-diff.d.ts.map +0 -1
  59. package/dist/cli/commands/memory-cmd-list.d.ts +0 -3
  60. package/dist/cli/commands/memory-cmd-list.d.ts.map +0 -1
  61. package/dist/cli/commands/memory-cmd-recall-exit.d.ts +0 -3
  62. package/dist/cli/commands/memory-cmd-recall-exit.d.ts.map +0 -1
  63. package/dist/cli/commands/memory-cmd-recall.d.ts +0 -3
  64. package/dist/cli/commands/memory-cmd-recall.d.ts.map +0 -1
  65. package/dist/cli/commands/memory-cmd-remove.d.ts +0 -3
  66. package/dist/cli/commands/memory-cmd-remove.d.ts.map +0 -1
  67. package/dist/cli/commands/memory-cmd-search.d.ts +0 -3
  68. package/dist/cli/commands/memory-cmd-search.d.ts.map +0 -1
  69. package/dist/cli/commands/memory-cmd-tail.d.ts +0 -3
  70. package/dist/cli/commands/memory-cmd-tail.d.ts.map +0 -1
  71. package/dist/cli/commands/memory-cmd-util.d.ts +0 -3
  72. package/dist/cli/commands/memory-cmd-util.d.ts.map +0 -1
  73. package/dist/cli/commands/memory-cmd-view.d.ts +0 -3
  74. package/dist/cli/commands/memory-cmd-view.d.ts.map +0 -1
  75. package/dist/cli/commands/memory-cmd-watch.d.ts +0 -3
  76. package/dist/cli/commands/memory-cmd-watch.d.ts.map +0 -1
  77. package/dist/cli/commands/memory-cmd-when-to-use.d.ts +0 -3
  78. package/dist/cli/commands/memory-cmd-when-to-use.d.ts.map +0 -1
  79. package/dist/cli/commands/memory.d.ts +0 -3
  80. package/dist/cli/commands/memory.d.ts.map +0 -1
  81. package/dist/cli/commands/project-panel.d.ts +0 -3
  82. package/dist/cli/commands/project-panel.d.ts.map +0 -1
  83. package/dist/cli/commands/project.d.ts +0 -3
  84. package/dist/cli/commands/project.d.ts.map +0 -1
  85. package/dist/cli/commands/relation.d.ts +0 -3
  86. package/dist/cli/commands/relation.d.ts.map +0 -1
  87. package/dist/cli/commands/storage.d.ts +0 -3
  88. package/dist/cli/commands/storage.d.ts.map +0 -1
  89. package/dist/cli/commands/system-auto-memory.d.ts +0 -3
  90. package/dist/cli/commands/system-auto-memory.d.ts.map +0 -1
  91. package/dist/cli/commands/system-completions.d.ts +0 -13
  92. package/dist/cli/commands/system-completions.d.ts.map +0 -1
  93. package/dist/cli/commands/system-config.d.ts +0 -3
  94. package/dist/cli/commands/system-config.d.ts.map +0 -1
  95. package/dist/cli/commands/system-doctor.d.ts +0 -3
  96. package/dist/cli/commands/system-doctor.d.ts.map +0 -1
  97. package/dist/cli/commands/system-hooks.d.ts +0 -3
  98. package/dist/cli/commands/system-hooks.d.ts.map +0 -1
  99. package/dist/cli/commands/system-mcp.d.ts +0 -3
  100. package/dist/cli/commands/system-mcp.d.ts.map +0 -1
  101. package/dist/cli/commands/system-misc.d.ts +0 -3
  102. package/dist/cli/commands/system-misc.d.ts.map +0 -1
  103. package/dist/cli/commands/system-profile.d.ts +0 -3
  104. package/dist/cli/commands/system-profile.d.ts.map +0 -1
  105. package/dist/cli/commands/system-session.d.ts +0 -3
  106. package/dist/cli/commands/system-session.d.ts.map +0 -1
  107. package/dist/cli/commands/system-sessions.d.ts +0 -3
  108. package/dist/cli/commands/system-sessions.d.ts.map +0 -1
  109. package/dist/cli/commands/system-synthesis.d.ts +0 -3
  110. package/dist/cli/commands/system-synthesis.d.ts.map +0 -1
  111. package/dist/cli/commands/system-synthesized-profile.d.ts +0 -3
  112. package/dist/cli/commands/system-synthesized-profile.d.ts.map +0 -1
  113. package/dist/cli/commands/system-tools.d.ts +0 -3
  114. package/dist/cli/commands/system-tools.d.ts.map +0 -1
  115. package/dist/cli/commands/system-watch.d.ts +0 -3
  116. package/dist/cli/commands/system-watch.d.ts.map +0 -1
  117. package/dist/cli/commands/system.d.ts +0 -3
  118. package/dist/cli/commands/system.d.ts.map +0 -1
  119. package/dist/cli/exit-codes.d.ts +0 -13
  120. package/dist/cli/exit-codes.d.ts.map +0 -1
  121. package/dist/cli/global-options.d.ts +0 -27
  122. package/dist/cli/global-options.d.ts.map +0 -1
  123. package/dist/cli/helpers.d.ts +0 -150
  124. package/dist/cli/helpers.d.ts.map +0 -1
  125. package/dist/cli/index.d.ts +0 -3
  126. package/dist/cli/index.d.ts.map +0 -1
  127. package/dist/cli/register-all.d.ts +0 -17
  128. package/dist/cli/register-all.d.ts.map +0 -1
  129. package/dist/cli/startup-side-effects.d.ts +0 -9
  130. package/dist/cli/startup-side-effects.d.ts.map +0 -1
  131. package/dist/db/__fixtures__/fail-closed-stub-server.d.ts +0 -2
  132. package/dist/db/__fixtures__/fail-closed-stub-server.d.ts.map +0 -1
  133. package/dist/db/acl.d.ts +0 -34
  134. package/dist/db/acl.d.ts.map +0 -1
  135. package/dist/db/agents.d.ts +0 -21
  136. package/dist/db/agents.d.ts.map +0 -1
  137. package/dist/db/analytics.d.ts +0 -120
  138. package/dist/db/analytics.d.ts.map +0 -1
  139. package/dist/db/api-mode.d.ts +0 -127
  140. package/dist/db/api-mode.d.ts.map +0 -1
  141. package/dist/db/audit.d.ts +0 -53
  142. package/dist/db/audit.d.ts.map +0 -1
  143. package/dist/db/database.d.ts +0 -26
  144. package/dist/db/database.d.ts.map +0 -1
  145. package/dist/db/entities.d.ts +0 -62
  146. package/dist/db/entities.d.ts.map +0 -1
  147. package/dist/db/entity-memories.d.ts +0 -34
  148. package/dist/db/entity-memories.d.ts.map +0 -1
  149. package/dist/db/feedback.d.ts +0 -9
  150. package/dist/db/feedback.d.ts.map +0 -1
  151. package/dist/db/locks.d.ts +0 -63
  152. package/dist/db/locks.d.ts.map +0 -1
  153. package/dist/db/machines.d.ts +0 -23
  154. package/dist/db/machines.d.ts.map +0 -1
  155. package/dist/db/memories.d.ts +0 -193
  156. package/dist/db/memories.d.ts.map +0 -1
  157. package/dist/db/memory-links.d.ts +0 -21
  158. package/dist/db/memory-links.d.ts.map +0 -1
  159. package/dist/db/memory-project-link.d.ts +0 -13
  160. package/dist/db/memory-project-link.d.ts.map +0 -1
  161. package/dist/db/migrations.d.ts +0 -3
  162. package/dist/db/migrations.d.ts.map +0 -1
  163. package/dist/db/pg-migrate.d.ts +0 -27
  164. package/dist/db/pg-migrate.d.ts.map +0 -1
  165. package/dist/db/pg-migrations.d.ts +0 -2
  166. package/dist/db/pg-migrations.d.ts.map +0 -1
  167. package/dist/db/projects.d.ts +0 -27
  168. package/dist/db/projects.d.ts.map +0 -1
  169. package/dist/db/ratings.d.ts +0 -23
  170. package/dist/db/ratings.d.ts.map +0 -1
  171. package/dist/db/relations.d.ts +0 -49
  172. package/dist/db/relations.d.ts.map +0 -1
  173. package/dist/db/session-jobs.d.ts +0 -49
  174. package/dist/db/session-jobs.d.ts.map +0 -1
  175. package/dist/db/store-backend.d.ts +0 -42
  176. package/dist/db/store-backend.d.ts.map +0 -1
  177. package/dist/db/subscriptions.d.ts +0 -24
  178. package/dist/db/subscriptions.d.ts.map +0 -1
  179. package/dist/db/synthesis.d.ts +0 -101
  180. package/dist/db/synthesis.d.ts.map +0 -1
  181. package/dist/db/tasks.d.ts +0 -89
  182. package/dist/db/tasks.d.ts.map +0 -1
  183. package/dist/db/tool-events.d.ts +0 -27
  184. package/dist/db/tool-events.d.ts.map +0 -1
  185. package/dist/db/webhook_hooks.d.ts +0 -25
  186. package/dist/db/webhook_hooks.d.ts.map +0 -1
  187. package/dist/diagnostics/historical-project-registration-receipt.d.ts +0 -39
  188. package/dist/diagnostics/historical-project-registration-receipt.d.ts.map +0 -1
  189. package/dist/generated/storage-kit/backend.d.ts +0 -20
  190. package/dist/generated/storage-kit/backend.d.ts.map +0 -1
  191. package/dist/generated/storage-kit/health.d.ts +0 -20
  192. package/dist/generated/storage-kit/health.d.ts.map +0 -1
  193. package/dist/generated/storage-kit/index.d.ts +0 -8
  194. package/dist/generated/storage-kit/index.d.ts.map +0 -1
  195. package/dist/generated/storage-kit/migrations.d.ts +0 -48
  196. package/dist/generated/storage-kit/migrations.d.ts.map +0 -1
  197. package/dist/generated/storage-kit/own.d.ts +0 -11
  198. package/dist/generated/storage-kit/own.d.ts.map +0 -1
  199. package/dist/generated/storage-kit/pool.d.ts +0 -35
  200. package/dist/generated/storage-kit/pool.d.ts.map +0 -1
  201. package/dist/generated/storage-kit/query.d.ts +0 -36
  202. package/dist/generated/storage-kit/query.d.ts.map +0 -1
  203. package/dist/generated/storage-kit/tls.d.ts +0 -53
  204. package/dist/generated/storage-kit/tls.d.ts.map +0 -1
  205. package/dist/index.d.ts +0 -45
  206. package/dist/index.d.ts.map +0 -1
  207. package/dist/lib/activation-matcher.d.ts +0 -17
  208. package/dist/lib/activation-matcher.d.ts.map +0 -1
  209. package/dist/lib/asmr/categorizer.d.ts +0 -31
  210. package/dist/lib/asmr/categorizer.d.ts.map +0 -1
  211. package/dist/lib/asmr/context-agent.d.ts +0 -4
  212. package/dist/lib/asmr/context-agent.d.ts.map +0 -1
  213. package/dist/lib/asmr/ensemble.d.ts +0 -23
  214. package/dist/lib/asmr/ensemble.d.ts.map +0 -1
  215. package/dist/lib/asmr/fact-agent.d.ts +0 -4
  216. package/dist/lib/asmr/fact-agent.d.ts.map +0 -1
  217. package/dist/lib/asmr/index.d.ts +0 -7
  218. package/dist/lib/asmr/index.d.ts.map +0 -1
  219. package/dist/lib/asmr/orchestrator.d.ts +0 -4
  220. package/dist/lib/asmr/orchestrator.d.ts.map +0 -1
  221. package/dist/lib/asmr/recall.d.ts +0 -3
  222. package/dist/lib/asmr/recall.d.ts.map +0 -1
  223. package/dist/lib/asmr/temporal-agent.d.ts +0 -4
  224. package/dist/lib/asmr/temporal-agent.d.ts.map +0 -1
  225. package/dist/lib/asmr/types.d.ts +0 -27
  226. package/dist/lib/asmr/types.d.ts.map +0 -1
  227. package/dist/lib/auto-inject-orchestrator.d.ts +0 -57
  228. package/dist/lib/auto-inject-orchestrator.d.ts.map +0 -1
  229. package/dist/lib/auto-memory-queue.d.ts +0 -48
  230. package/dist/lib/auto-memory-queue.d.ts.map +0 -1
  231. package/dist/lib/auto-memory.d.ts +0 -19
  232. package/dist/lib/auto-memory.d.ts.map +0 -1
  233. package/dist/lib/bench.d.ts +0 -20
  234. package/dist/lib/bench.d.ts.map +0 -1
  235. package/dist/lib/built-in-hooks.d.ts +0 -12
  236. package/dist/lib/built-in-hooks.d.ts.map +0 -1
  237. package/dist/lib/channel-pusher.d.ts +0 -39
  238. package/dist/lib/channel-pusher.d.ts.map +0 -1
  239. package/dist/lib/config.d.ts +0 -9
  240. package/dist/lib/config.d.ts.map +0 -1
  241. package/dist/lib/connectors/files.d.ts +0 -8
  242. package/dist/lib/connectors/files.d.ts.map +0 -1
  243. package/dist/lib/connectors/github.d.ts +0 -7
  244. package/dist/lib/connectors/github.d.ts.map +0 -1
  245. package/dist/lib/connectors/index.d.ts +0 -12
  246. package/dist/lib/connectors/index.d.ts.map +0 -1
  247. package/dist/lib/connectors/notion.d.ts +0 -7
  248. package/dist/lib/connectors/notion.d.ts.map +0 -1
  249. package/dist/lib/connectors/types.d.ts +0 -27
  250. package/dist/lib/connectors/types.d.ts.map +0 -1
  251. package/dist/lib/consolidation.d.ts +0 -52
  252. package/dist/lib/consolidation.d.ts.map +0 -1
  253. package/dist/lib/context-extractor.d.ts +0 -14
  254. package/dist/lib/context-extractor.d.ts.map +0 -1
  255. package/dist/lib/context.d.ts +0 -36
  256. package/dist/lib/context.d.ts.map +0 -1
  257. package/dist/lib/contradiction.d.ts +0 -50
  258. package/dist/lib/contradiction.d.ts.map +0 -1
  259. package/dist/lib/decay.d.ts +0 -35
  260. package/dist/lib/decay.d.ts.map +0 -1
  261. package/dist/lib/dedup.d.ts +0 -33
  262. package/dist/lib/dedup.d.ts.map +0 -1
  263. package/dist/lib/duration.d.ts +0 -28
  264. package/dist/lib/duration.d.ts.map +0 -1
  265. package/dist/lib/embeddings.d.ts +0 -20
  266. package/dist/lib/embeddings.d.ts.map +0 -1
  267. package/dist/lib/enum-validation.d.ts +0 -20
  268. package/dist/lib/enum-validation.d.ts.map +0 -1
  269. package/dist/lib/export-v1.d.ts +0 -30
  270. package/dist/lib/export-v1.d.ts.map +0 -1
  271. package/dist/lib/extractor.d.ts +0 -9
  272. package/dist/lib/extractor.d.ts.map +0 -1
  273. package/dist/lib/extractors/audio.d.ts +0 -8
  274. package/dist/lib/extractors/audio.d.ts.map +0 -1
  275. package/dist/lib/extractors/index.d.ts +0 -12
  276. package/dist/lib/extractors/index.d.ts.map +0 -1
  277. package/dist/lib/extractors/ocr.d.ts +0 -7
  278. package/dist/lib/extractors/ocr.d.ts.map +0 -1
  279. package/dist/lib/extractors/pdf.d.ts +0 -7
  280. package/dist/lib/extractors/pdf.d.ts.map +0 -1
  281. package/dist/lib/extractors/types.d.ts +0 -12
  282. package/dist/lib/extractors/types.d.ts.map +0 -1
  283. package/dist/lib/file-deps.d.ts +0 -27
  284. package/dist/lib/file-deps.d.ts.map +0 -1
  285. package/dist/lib/focus.d.ts +0 -58
  286. package/dist/lib/focus.d.ts.map +0 -1
  287. package/dist/lib/gatherer.d.ts +0 -16
  288. package/dist/lib/gatherer.d.ts.map +0 -1
  289. package/dist/lib/gdpr.d.ts +0 -39
  290. package/dist/lib/gdpr.d.ts.map +0 -1
  291. package/dist/lib/hooks.d.ts +0 -50
  292. package/dist/lib/hooks.d.ts.map +0 -1
  293. package/dist/lib/importers/index.d.ts +0 -38
  294. package/dist/lib/importers/index.d.ts.map +0 -1
  295. package/dist/lib/injector.d.ts +0 -89
  296. package/dist/lib/injector.d.ts.map +0 -1
  297. package/dist/lib/machine-visibility.d.ts +0 -6
  298. package/dist/lib/machine-visibility.d.ts.map +0 -1
  299. package/dist/lib/matryoshka.d.ts +0 -50
  300. package/dist/lib/matryoshka.d.ts.map +0 -1
  301. package/dist/lib/memory-lock.d.ts +0 -58
  302. package/dist/lib/memory-lock.d.ts.map +0 -1
  303. package/dist/lib/model-config.d.ts +0 -14
  304. package/dist/lib/model-config.d.ts.map +0 -1
  305. package/dist/lib/open-sessions-connector.d.ts +0 -60
  306. package/dist/lib/open-sessions-connector.d.ts.map +0 -1
  307. package/dist/lib/package-version.d.ts +0 -3
  308. package/dist/lib/package-version.d.ts.map +0 -1
  309. package/dist/lib/poisoning.d.ts +0 -19
  310. package/dist/lib/poisoning.d.ts.map +0 -1
  311. package/dist/lib/poll.d.ts +0 -17
  312. package/dist/lib/poll.d.ts.map +0 -1
  313. package/dist/lib/procedural-extractor.d.ts +0 -21
  314. package/dist/lib/procedural-extractor.d.ts.map +0 -1
  315. package/dist/lib/profile-sync.d.ts +0 -20
  316. package/dist/lib/profile-sync.d.ts.map +0 -1
  317. package/dist/lib/profile-synthesizer.d.ts +0 -20
  318. package/dist/lib/profile-synthesizer.d.ts.map +0 -1
  319. package/dist/lib/project-detect.d.ts +0 -18
  320. package/dist/lib/project-detect.d.ts.map +0 -1
  321. package/dist/lib/project-panel.d.ts +0 -7
  322. package/dist/lib/project-panel.d.ts.map +0 -1
  323. package/dist/lib/providers/anthropic.d.ts +0 -21
  324. package/dist/lib/providers/anthropic.d.ts.map +0 -1
  325. package/dist/lib/providers/base.d.ts +0 -96
  326. package/dist/lib/providers/base.d.ts.map +0 -1
  327. package/dist/lib/providers/cerebras.d.ts +0 -20
  328. package/dist/lib/providers/cerebras.d.ts.map +0 -1
  329. package/dist/lib/providers/grok.d.ts +0 -19
  330. package/dist/lib/providers/grok.d.ts.map +0 -1
  331. package/dist/lib/providers/index.d.ts +0 -7
  332. package/dist/lib/providers/index.d.ts.map +0 -1
  333. package/dist/lib/providers/openai-compat.d.ts +0 -18
  334. package/dist/lib/providers/openai-compat.d.ts.map +0 -1
  335. package/dist/lib/providers/openai.d.ts +0 -20
  336. package/dist/lib/providers/openai.d.ts.map +0 -1
  337. package/dist/lib/providers/registry.d.ts +0 -38
  338. package/dist/lib/providers/registry.d.ts.map +0 -1
  339. package/dist/lib/quality.d.ts +0 -16
  340. package/dist/lib/quality.d.ts.map +0 -1
  341. package/dist/lib/redact.d.ts +0 -10
  342. package/dist/lib/redact.d.ts.map +0 -1
  343. package/dist/lib/reflection.d.ts +0 -83
  344. package/dist/lib/reflection.d.ts.map +0 -1
  345. package/dist/lib/retention.d.ts +0 -17
  346. package/dist/lib/retention.d.ts.map +0 -1
  347. package/dist/lib/retired-storage-mode.d.ts +0 -11
  348. package/dist/lib/retired-storage-mode.d.ts.map +0 -1
  349. package/dist/lib/search.d.ts +0 -52
  350. package/dist/lib/search.d.ts.map +0 -1
  351. package/dist/lib/session-auto-resolve.d.ts +0 -28
  352. package/dist/lib/session-auto-resolve.d.ts.map +0 -1
  353. package/dist/lib/session-processor.d.ts +0 -38
  354. package/dist/lib/session-processor.d.ts.map +0 -1
  355. package/dist/lib/session-queue.d.ts +0 -28
  356. package/dist/lib/session-queue.d.ts.map +0 -1
  357. package/dist/lib/session-registry.d.ts +0 -47
  358. package/dist/lib/session-registry.d.ts.map +0 -1
  359. package/dist/lib/session-start-briefing.d.ts +0 -10
  360. package/dist/lib/session-start-briefing.d.ts.map +0 -1
  361. package/dist/lib/session-watcher.d.ts +0 -30
  362. package/dist/lib/session-watcher.d.ts.map +0 -1
  363. package/dist/lib/storage-sync.d.ts +0 -45
  364. package/dist/lib/storage-sync.d.ts.map +0 -1
  365. package/dist/lib/sync.d.ts +0 -10
  366. package/dist/lib/sync.d.ts.map +0 -1
  367. package/dist/lib/synthesis/corpus-builder.d.ts +0 -30
  368. package/dist/lib/synthesis/corpus-builder.d.ts.map +0 -1
  369. package/dist/lib/synthesis/executor.d.ts +0 -14
  370. package/dist/lib/synthesis/executor.d.ts.map +0 -1
  371. package/dist/lib/synthesis/index.d.ts +0 -37
  372. package/dist/lib/synthesis/index.d.ts.map +0 -1
  373. package/dist/lib/synthesis/llm-analyzer.d.ts +0 -18
  374. package/dist/lib/synthesis/llm-analyzer.d.ts.map +0 -1
  375. package/dist/lib/synthesis/metrics.d.ts +0 -13
  376. package/dist/lib/synthesis/metrics.d.ts.map +0 -1
  377. package/dist/lib/synthesis/scheduler.d.ts +0 -18
  378. package/dist/lib/synthesis/scheduler.d.ts.map +0 -1
  379. package/dist/lib/synthesis/validator.d.ts +0 -19
  380. package/dist/lib/synthesis/validator.d.ts.map +0 -1
  381. package/dist/lib/task-runner.d.ts +0 -37
  382. package/dist/lib/task-runner.d.ts.map +0 -1
  383. package/dist/lib/tool-lesson-extractor.d.ts +0 -24
  384. package/dist/lib/tool-lesson-extractor.d.ts.map +0 -1
  385. package/dist/lib/tool-memory-synthesizer.d.ts +0 -28
  386. package/dist/lib/tool-memory-synthesizer.d.ts.map +0 -1
  387. package/dist/lib/topic-clusterer.d.ts +0 -21
  388. package/dist/lib/topic-clusterer.d.ts.map +0 -1
  389. package/dist/lib/when-to-use-generator.d.ts +0 -22
  390. package/dist/lib/when-to-use-generator.d.ts.map +0 -1
  391. package/dist/mcp/http.d.ts +0 -17
  392. package/dist/mcp/http.d.ts.map +0 -1
  393. package/dist/mcp/index.d.ts +0 -6
  394. package/dist/mcp/index.d.ts.map +0 -1
  395. package/dist/mcp/memory-broadcast.d.ts +0 -12
  396. package/dist/mcp/memory-broadcast.d.ts.map +0 -1
  397. package/dist/mcp/tools/agent-tools.d.ts +0 -3
  398. package/dist/mcp/tools/agent-tools.d.ts.map +0 -1
  399. package/dist/mcp/tools/auto-memory-tools.d.ts +0 -5
  400. package/dist/mcp/tools/auto-memory-tools.d.ts.map +0 -1
  401. package/dist/mcp/tools/bulk-tools.d.ts +0 -3
  402. package/dist/mcp/tools/bulk-tools.d.ts.map +0 -1
  403. package/dist/mcp/tools/consolidation-tools.d.ts +0 -3
  404. package/dist/mcp/tools/consolidation-tools.d.ts.map +0 -1
  405. package/dist/mcp/tools/focus-tools.d.ts +0 -3
  406. package/dist/mcp/tools/focus-tools.d.ts.map +0 -1
  407. package/dist/mcp/tools/graph-entity-tools.d.ts +0 -3
  408. package/dist/mcp/tools/graph-entity-tools.d.ts.map +0 -1
  409. package/dist/mcp/tools/graph-query-tools.d.ts +0 -3
  410. package/dist/mcp/tools/graph-query-tools.d.ts.map +0 -1
  411. package/dist/mcp/tools/graph-relation-tools.d.ts +0 -3
  412. package/dist/mcp/tools/graph-relation-tools.d.ts.map +0 -1
  413. package/dist/mcp/tools/graph-tools.d.ts +0 -3
  414. package/dist/mcp/tools/graph-tools.d.ts.map +0 -1
  415. package/dist/mcp/tools/graph-utils.d.ts +0 -5
  416. package/dist/mcp/tools/graph-utils.d.ts.map +0 -1
  417. package/dist/mcp/tools/hook-tools.d.ts +0 -3
  418. package/dist/mcp/tools/hook-tools.d.ts.map +0 -1
  419. package/dist/mcp/tools/lock-tools.d.ts +0 -3
  420. package/dist/mcp/tools/lock-tools.d.ts.map +0 -1
  421. package/dist/mcp/tools/memory-audit.d.ts +0 -3
  422. package/dist/mcp/tools/memory-audit.d.ts.map +0 -1
  423. package/dist/mcp/tools/memory-crud.d.ts +0 -3
  424. package/dist/mcp/tools/memory-crud.d.ts.map +0 -1
  425. package/dist/mcp/tools/memory-health.d.ts +0 -3
  426. package/dist/mcp/tools/memory-health.d.ts.map +0 -1
  427. package/dist/mcp/tools/memory-history.d.ts +0 -3
  428. package/dist/mcp/tools/memory-history.d.ts.map +0 -1
  429. package/dist/mcp/tools/memory-inject.d.ts +0 -3
  430. package/dist/mcp/tools/memory-inject.d.ts.map +0 -1
  431. package/dist/mcp/tools/memory-io.d.ts +0 -3
  432. package/dist/mcp/tools/memory-io.d.ts.map +0 -1
  433. package/dist/mcp/tools/memory-lifecycle.d.ts +0 -3
  434. package/dist/mcp/tools/memory-lifecycle.d.ts.map +0 -1
  435. package/dist/mcp/tools/memory-search.d.ts +0 -3
  436. package/dist/mcp/tools/memory-search.d.ts.map +0 -1
  437. package/dist/mcp/tools/memory-stats.d.ts +0 -3
  438. package/dist/mcp/tools/memory-stats.d.ts.map +0 -1
  439. package/dist/mcp/tools/memory-tools.d.ts +0 -17
  440. package/dist/mcp/tools/memory-tools.d.ts.map +0 -1
  441. package/dist/mcp/tools/memory-utils.d.ts +0 -27
  442. package/dist/mcp/tools/memory-utils.d.ts.map +0 -1
  443. package/dist/mcp/tools/memory-validation.d.ts +0 -3
  444. package/dist/mcp/tools/memory-validation.d.ts.map +0 -1
  445. package/dist/mcp/tools/project-tools.d.ts +0 -3
  446. package/dist/mcp/tools/project-tools.d.ts.map +0 -1
  447. package/dist/mcp/tools/session-tools.d.ts +0 -3
  448. package/dist/mcp/tools/session-tools.d.ts.map +0 -1
  449. package/dist/mcp/tools/storage-tools.d.ts +0 -3
  450. package/dist/mcp/tools/storage-tools.d.ts.map +0 -1
  451. package/dist/mcp/tools/synthesis-tools.d.ts +0 -3
  452. package/dist/mcp/tools/synthesis-tools.d.ts.map +0 -1
  453. package/dist/mcp/tools/system-tools-events.d.ts +0 -3
  454. package/dist/mcp/tools/system-tools-events.d.ts.map +0 -1
  455. package/dist/mcp/tools/system-tools-memory-admin.d.ts +0 -3
  456. package/dist/mcp/tools/system-tools-memory-admin.d.ts.map +0 -1
  457. package/dist/mcp/tools/system-tools-shared.d.ts +0 -23
  458. package/dist/mcp/tools/system-tools-shared.d.ts.map +0 -1
  459. package/dist/mcp/tools/system-tools.d.ts +0 -3
  460. package/dist/mcp/tools/system-tools.d.ts.map +0 -1
  461. package/dist/mcp/tools/tool-registry.d.ts +0 -30
  462. package/dist/mcp/tools/tool-registry.d.ts.map +0 -1
  463. package/dist/mcp/tools/utility-tools.d.ts +0 -3
  464. package/dist/mcp/tools/utility-tools.d.ts.map +0 -1
  465. package/dist/memory-project-link/index.d.ts +0 -2
  466. package/dist/memory-project-link/index.d.ts.map +0 -1
  467. package/dist/memory-project-link/schema.d.ts +0 -5
  468. package/dist/memory-project-link/schema.d.ts.map +0 -1
  469. package/dist/pg-sync-worker.d.ts +0 -2
  470. package/dist/pg-sync-worker.d.ts.map +0 -1
  471. package/dist/project-registration/authority.d.ts +0 -43
  472. package/dist/project-registration/authority.d.ts.map +0 -1
  473. package/dist/project-registration/historical-receipt.d.ts +0 -38
  474. package/dist/project-registration/historical-receipt.d.ts.map +0 -1
  475. package/dist/project-registration/http.d.ts +0 -32
  476. package/dist/project-registration/http.d.ts.map +0 -1
  477. package/dist/project-registration/identity.d.ts +0 -20
  478. package/dist/project-registration/identity.d.ts.map +0 -1
  479. package/dist/project-registration/index.d.ts +0 -11
  480. package/dist/project-registration/index.d.ts.map +0 -1
  481. package/dist/project-registration/project-references.d.ts +0 -71
  482. package/dist/project-registration/project-references.d.ts.map +0 -1
  483. package/dist/project-registration/project-resources.d.ts +0 -22
  484. package/dist/project-registration/project-resources.d.ts.map +0 -1
  485. package/dist/project-registration/schema.d.ts +0 -5
  486. package/dist/project-registration/schema.d.ts.map +0 -1
  487. package/dist/project-registration/types.d.ts +0 -319
  488. package/dist/project-registration/types.d.ts.map +0 -1
  489. package/dist/project-registration.d.ts +0 -2
  490. package/dist/project-registration.d.ts.map +0 -1
  491. package/dist/sdk/index.d.ts +0 -978
  492. package/dist/sdk/index.d.ts.map +0 -1
  493. package/dist/server/auth.d.ts +0 -11
  494. package/dist/server/auth.d.ts.map +0 -1
  495. package/dist/server/helpers.d.ts +0 -22
  496. package/dist/server/helpers.d.ts.map +0 -1
  497. package/dist/server/index.d.ts +0 -14
  498. package/dist/server/index.d.ts.map +0 -1
  499. package/dist/server/openapi.d.ts +0 -2
  500. package/dist/server/openapi.d.ts.map +0 -1
  501. package/dist/server/router.d.ts +0 -17
  502. package/dist/server/router.d.ts.map +0 -1
  503. package/dist/server/routes/agents.d.ts +0 -2
  504. package/dist/server/routes/agents.d.ts.map +0 -1
  505. package/dist/server/routes/entities.d.ts +0 -2
  506. package/dist/server/routes/entities.d.ts.map +0 -1
  507. package/dist/server/routes/memories-bulk.d.ts +0 -2
  508. package/dist/server/routes/memories-bulk.d.ts.map +0 -1
  509. package/dist/server/routes/memories-crud.d.ts +0 -2
  510. package/dist/server/routes/memories-crud.d.ts.map +0 -1
  511. package/dist/server/routes/memories-io.d.ts +0 -2
  512. package/dist/server/routes/memories-io.d.ts.map +0 -1
  513. package/dist/server/routes/memories-misc.d.ts +0 -2
  514. package/dist/server/routes/memories-misc.d.ts.map +0 -1
  515. package/dist/server/routes/memories-search.d.ts +0 -2
  516. package/dist/server/routes/memories-search.d.ts.map +0 -1
  517. package/dist/server/routes/memories-stats.d.ts +0 -2
  518. package/dist/server/routes/memories-stats.d.ts.map +0 -1
  519. package/dist/server/routes/memories.d.ts +0 -19
  520. package/dist/server/routes/memories.d.ts.map +0 -1
  521. package/dist/server/routes/memory-project-link.d.ts +0 -2
  522. package/dist/server/routes/memory-project-link.d.ts.map +0 -1
  523. package/dist/server/routes/project-registration.d.ts +0 -2
  524. package/dist/server/routes/project-registration.d.ts.map +0 -1
  525. package/dist/server/routes/projects.d.ts +0 -2
  526. package/dist/server/routes/projects.d.ts.map +0 -1
  527. package/dist/server/routes/system-auto-memory.d.ts +0 -2
  528. package/dist/server/routes/system-auto-memory.d.ts.map +0 -1
  529. package/dist/server/routes/system-chain.d.ts +0 -2
  530. package/dist/server/routes/system-chain.d.ts.map +0 -1
  531. package/dist/server/routes/system-consolidation.d.ts +0 -2
  532. package/dist/server/routes/system-consolidation.d.ts.map +0 -1
  533. package/dist/server/routes/system-hooks.d.ts +0 -2
  534. package/dist/server/routes/system-hooks.d.ts.map +0 -1
  535. package/dist/server/routes/system-sessions.d.ts +0 -2
  536. package/dist/server/routes/system-sessions.d.ts.map +0 -1
  537. package/dist/server/routes/system-subscriptions.d.ts +0 -2
  538. package/dist/server/routes/system-subscriptions.d.ts.map +0 -1
  539. package/dist/server/routes/system-synthesis.d.ts +0 -2
  540. package/dist/server/routes/system-synthesis.d.ts.map +0 -1
  541. package/dist/server/routes/system-tools.d.ts +0 -2
  542. package/dist/server/routes/system-tools.d.ts.map +0 -1
  543. package/dist/server/routes/system.d.ts +0 -2
  544. package/dist/server/routes/system.d.ts.map +0 -1
  545. package/dist/server/routes/tasks.d.ts +0 -2
  546. package/dist/server/routes/tasks.d.ts.map +0 -1
  547. package/dist/storage.d.ts +0 -266
  548. package/dist/storage.d.ts.map +0 -1
  549. package/dist/test-support/memories-page-stub-server.d.ts +0 -2
  550. package/dist/test-support/memories-page-stub-server.d.ts.map +0 -1
  551. package/dist/test-support/memories-page-stub.d.ts +0 -28
  552. package/dist/test-support/memories-page-stub.d.ts.map +0 -1
  553. package/dist/test-support/preload-local-store.d.ts +0 -2
  554. package/dist/test-support/preload-local-store.d.ts.map +0 -1
  555. package/dist/test-support/project-authority-identity.d.ts +0 -8
  556. package/dist/test-support/project-authority-identity.d.ts.map +0 -1
  557. package/dist/test-support/store-isolation.d.ts +0 -108
  558. package/dist/test-support/store-isolation.d.ts.map +0 -1
  559. package/dist/test-support/strip-ansi.d.ts +0 -3
  560. package/dist/test-support/strip-ansi.d.ts.map +0 -1
  561. package/dist/types/hooks.d.ts +0 -136
  562. package/dist/types/hooks.d.ts.map +0 -1
  563. package/dist/types/index.d.ts +0 -472
  564. package/dist/types/index.d.ts.map +0 -1
package/dist/cli/index.js CHANGED
@@ -2274,6 +2274,7 @@ function translateSql(sql) {
2274
2274
  let translated = sql.replace(/\?/g, () => `$${++parameterIndex}`);
2275
2275
  const ISO_FMT = `'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'`;
2276
2276
  translated = translated.replace(/datetime\s*\(\s*'now'\s*\)/gi, `to_char(now() AT TIME ZONE 'UTC', ${ISO_FMT})`);
2277
+ translated = translated.replace(/strftime\s*\(\s*'%Y-%m-%dT%H:%M:%fZ'\s*,\s*'now'\s*\)/gi, `to_char(now() AT TIME ZONE 'UTC', ${ISO_FMT})`);
2277
2278
  translated = translated.replace(/datetime\s*\(\s*'now'\s*,\s*'(-?\d+)\s+(minutes?|hours?|days?|seconds?)'\s*\)/gi, (_match, amount, unit) => {
2278
2279
  const parsed = parseInt(String(amount), 10);
2279
2280
  const absolute = Math.abs(parsed);
@@ -2758,16 +2759,24 @@ function transferRows(target, table, rows, options) {
2758
2759
  const conflictColumn = options.conflictColumn ?? "updated_at";
2759
2760
  let written = 0;
2760
2761
  let skipped = 0;
2762
+ let maxSyncedAt = null;
2761
2763
  const errors = [];
2764
+ const bumpMaxSyncedAt = (row) => {
2765
+ const value = row[conflictColumn];
2766
+ if (typeof value === "string" && (maxSyncedAt === null || value > maxSyncedAt)) {
2767
+ maxSyncedAt = value;
2768
+ }
2769
+ };
2762
2770
  if (rows.length === 0) {
2763
- return { written, skipped, errors };
2771
+ return { written, skipped, errors, maxSyncedAt };
2764
2772
  }
2765
2773
  const columns = Object.keys(rows[0] ?? {});
2766
2774
  if (!columns.includes(primaryKey)) {
2767
2775
  return {
2768
2776
  written,
2769
2777
  skipped,
2770
- errors: [`Table "${table}" has no "${primaryKey}" column; skipping`]
2778
+ errors: [`Table "${table}" has no "${primaryKey}" column; skipping`],
2779
+ maxSyncedAt
2771
2780
  };
2772
2781
  }
2773
2782
  const hasConflictColumn = columns.includes(conflictColumn);
@@ -2780,6 +2789,7 @@ function transferRows(target, table, rows, options) {
2780
2789
  const incomingTime = Date.parse(String(row[conflictColumn]));
2781
2790
  if (Number.isFinite(existingTime) && Number.isFinite(incomingTime) && existingTime >= incomingTime) {
2782
2791
  skipped++;
2792
+ bumpMaxSyncedAt(row);
2783
2793
  continue;
2784
2794
  }
2785
2795
  }
@@ -2792,11 +2802,12 @@ function transferRows(target, table, rows, options) {
2792
2802
  target.run(`INSERT INTO "${table}" (${columnList}) VALUES (${placeholders})`, ...columns.map((column) => row[column]));
2793
2803
  }
2794
2804
  written++;
2805
+ bumpMaxSyncedAt(row);
2795
2806
  } catch (error) {
2796
2807
  errors.push(`Row ${String(row[primaryKey] ?? "unknown")}: ${error instanceof Error ? error.message : String(error)}`);
2797
2808
  }
2798
2809
  }
2799
- return { written, skipped, errors };
2810
+ return { written, skipped, errors, maxSyncedAt };
2800
2811
  }
2801
2812
  function incrementalSyncPush(local, remote, tables, options = {}) {
2802
2813
  return runIncrementalSync("push", local, remote, local, tables, options);
@@ -2834,22 +2845,29 @@ function runIncrementalSync(direction, source, target, metaDb, tables, options)
2834
2845
  rows = source.all(`SELECT * FROM "${table}"`);
2835
2846
  stat.first_sync = true;
2836
2847
  }
2848
+ let maxSyncedAt = null;
2837
2849
  for (let offset = 0;offset < rows.length; offset += batchSize) {
2838
2850
  const batch = rows.slice(offset, offset + batchSize);
2839
2851
  const result = transferRows(target, table, batch, options);
2840
2852
  stat.synced_rows += result.written;
2841
2853
  stat.skipped_rows += result.skipped;
2842
2854
  stat.errors.push(...result.errors);
2855
+ if (result.maxSyncedAt !== null && (maxSyncedAt === null || result.maxSyncedAt > maxSyncedAt)) {
2856
+ maxSyncedAt = result.maxSyncedAt;
2857
+ }
2843
2858
  }
2844
2859
  if (rows.length === 0) {
2845
2860
  stat.skipped_rows = stat.total_rows;
2846
2861
  }
2847
- upsertSyncMeta(metaDb, {
2848
- table_name: table,
2849
- last_synced_at: new Date().toISOString(),
2850
- last_synced_row_count: stat.synced_rows,
2851
- direction
2852
- });
2862
+ const nextCursor = maxSyncedAt ?? meta?.last_synced_at ?? null;
2863
+ if (rows.length > 0 && stat.errors.length === 0 && nextCursor !== null) {
2864
+ upsertSyncMeta(metaDb, {
2865
+ table_name: table,
2866
+ last_synced_at: nextCursor,
2867
+ last_synced_row_count: stat.synced_rows,
2868
+ direction
2869
+ });
2870
+ }
2853
2871
  } catch (error) {
2854
2872
  stat.errors.push(`Table "${table}": ${error instanceof Error ? error.message : String(error)}`);
2855
2873
  }
@@ -2877,8 +2895,13 @@ var init_storage = __esm(() => {
2877
2895
  data;
2878
2896
  closed = false;
2879
2897
  lastError = null;
2898
+ generation = 0;
2880
2899
  static DATA_BYTES = 128 * 1024 * 1024;
2881
- static QUERY_TIMEOUT_MS = 60000;
2900
+ static queryTimeoutMs() {
2901
+ const raw = process.env["MEMENTOS_PGSYNC_QUERY_TIMEOUT_MS"]?.trim();
2902
+ const parsed = raw ? Number(raw) : Number.NaN;
2903
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 60000;
2904
+ }
2882
2905
  static resolveWorkerPath() {
2883
2906
  const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
2884
2907
  const here = fileURLToPath(new URL(".", import.meta.url));
@@ -2893,12 +2916,12 @@ var init_storage = __esm(() => {
2893
2916
  }
2894
2917
  return candidates[0];
2895
2918
  }
2896
- constructor(connectionString) {
2897
- const control = new SharedArrayBuffer(8);
2919
+ constructor(connectionString, workerPath) {
2920
+ const control = new SharedArrayBuffer(12);
2898
2921
  const dataSab = new SharedArrayBuffer(PgSyncPool.DATA_BYTES);
2899
2922
  this.status = new Int32Array(control);
2900
2923
  this.data = new Uint8Array(dataSab);
2901
- this.worker = new Worker(PgSyncPool.resolveWorkerPath(), {
2924
+ this.worker = new Worker(workerPath ?? PgSyncPool.resolveWorkerPath(), {
2902
2925
  workerData: {
2903
2926
  dsn: stripSslParams(connectionString),
2904
2927
  ssl: sslConfigFor(connectionString),
@@ -2916,21 +2939,35 @@ var init_storage = __esm(() => {
2916
2939
  throw new Error("PgSyncPool is closed");
2917
2940
  if (this.lastError)
2918
2941
  throw this.lastError;
2942
+ const timeoutMs = PgSyncPool.queryTimeoutMs();
2943
+ const gen = ++this.generation;
2919
2944
  Atomics.store(this.status, 0, 0);
2920
- this.worker.postMessage({ sql, params });
2921
- const waitResult = Atomics.wait(this.status, 0, 0, PgSyncPool.QUERY_TIMEOUT_MS);
2922
- const code = Atomics.load(this.status, 0);
2923
- if (code === 0 || waitResult === "timed-out") {
2924
- if (this.lastError)
2925
- throw this.lastError;
2926
- throw new Error("PostgreSQL query timed out after 60s");
2927
- }
2928
- const len = Atomics.load(this.status, 1);
2929
- const payload = JSON.parse(new TextDecoder().decode(this.data.subarray(0, len)));
2930
- if (code === 2) {
2931
- throw new Error(payload.message ?? "PostgreSQL error");
2945
+ Atomics.store(this.status, 2, 0);
2946
+ this.worker.postMessage({ sql, params, gen });
2947
+ const deadline = Date.now() + timeoutMs;
2948
+ for (;; ) {
2949
+ const remaining = deadline - Date.now();
2950
+ const responding = Atomics.load(this.status, 0);
2951
+ if (responding === gen) {
2952
+ const code = Atomics.load(this.status, 2);
2953
+ const len = Atomics.load(this.status, 1);
2954
+ const payload = JSON.parse(new TextDecoder().decode(this.data.subarray(0, len)));
2955
+ if (code === 2) {
2956
+ throw new Error(payload.message ?? "PostgreSQL error");
2957
+ }
2958
+ return payload;
2959
+ }
2960
+ if (responding !== 0) {
2961
+ Atomics.compareExchange(this.status, 0, responding, 0);
2962
+ continue;
2963
+ }
2964
+ if (remaining <= 0) {
2965
+ if (this.lastError)
2966
+ throw this.lastError;
2967
+ throw new Error(`PostgreSQL query timed out after ${timeoutMs}ms`);
2968
+ }
2969
+ Atomics.wait(this.status, 0, 0, remaining);
2932
2970
  }
2933
- return payload;
2934
2971
  }
2935
2972
  end() {
2936
2973
  if (this.closed)
@@ -5267,6 +5304,7 @@ __export(exports_memories, {
5267
5304
  updateMemory: () => updateMemory,
5268
5305
  touchMemory: () => touchMemory,
5269
5306
  semanticSearch: () => semanticSearch,
5307
+ reservedAgentIdViolation: () => reservedAgentIdViolation,
5270
5308
  parseMemoryRow: () => parseMemoryRow,
5271
5309
  listMemoryHistoryPage: () => listMemoryHistoryPage,
5272
5310
  listMemoryHistory: () => listMemoryHistory,
@@ -5338,7 +5376,20 @@ function parseMemoryRow(row) {
5338
5376
  accessed_at: row["accessed_at"] || null
5339
5377
  };
5340
5378
  }
5379
+ function reservedAgentIdViolation(agentId) {
5380
+ if (!agentId)
5381
+ return null;
5382
+ const normalized = agentId.trim().toLowerCase();
5383
+ if (RESERVED_AGENT_IDS.has(normalized)) {
5384
+ return `Reserved placeholder agent id "${agentId}" cannot own a memory. ` + `Refusing to write: test harnesses must not write memories under placeholder agent ` + `identities. Register a real agent (mementos register-agent <name>) and pass its id.`;
5385
+ }
5386
+ return null;
5387
+ }
5341
5388
  function createMemory(input, dedupeMode = "merge", db) {
5389
+ const reservedViolation = reservedAgentIdViolation(input.agent_id);
5390
+ if (reservedViolation) {
5391
+ throw new Error(reservedViolation);
5392
+ }
5342
5393
  if (!db && isApiMode()) {
5343
5394
  const { status, data } = apiJson("POST", "/memories", { ...input, dedupe: dedupeMode });
5344
5395
  if (!data || !data.id) {
@@ -5388,7 +5439,8 @@ function createMemory(input, dedupeMode = "merge", db) {
5388
5439
  importance = ?, metadata = ?, expires_at = ?,
5389
5440
  when_to_use = ?,
5390
5441
  pinned = COALESCE(pinned, 0),
5391
- version = version + 1, updated_at = ?
5442
+ version = version + 1, updated_at = ?,
5443
+ updated_by_agent = ?
5392
5444
  WHERE id = ?`, [
5393
5445
  safeValue,
5394
5446
  input.category || "knowledge",
@@ -5399,6 +5451,7 @@ function createMemory(input, dedupeMode = "merge", db) {
5399
5451
  expiresAt,
5400
5452
  input.when_to_use || null,
5401
5453
  timestamp,
5454
+ input.agent_id || null,
5402
5455
  existing.id
5403
5456
  ]);
5404
5457
  d.run("DELETE FROM memory_tags WHERE memory_id = ?", [existing.id]);
@@ -5503,6 +5556,12 @@ function bulkUpsertMemories(memories, db) {
5503
5556
  errors.push(`Rejected "${key}": ${formatEnumViolation(violation)}`);
5504
5557
  continue;
5505
5558
  }
5559
+ const agentViolation = reservedAgentIdViolation(typeof mem["agent_id"] === "string" ? mem["agent_id"] : undefined);
5560
+ if (agentViolation) {
5561
+ rejected++;
5562
+ errors.push(`Rejected "${key}": ${agentViolation}`);
5563
+ continue;
5564
+ }
5506
5565
  const timestamp = now();
5507
5566
  let tags = [];
5508
5567
  const rawTags = mem["tags"];
@@ -5781,6 +5840,11 @@ function listMemoriesPage(filter, db) {
5781
5840
  agent_id: f.agent_id,
5782
5841
  project_id: f.project_id,
5783
5842
  session_id: f.session_id,
5843
+ machine_id: f.machine_id,
5844
+ visible_to_machine_id: f.visible_to_machine_id,
5845
+ search: f.search,
5846
+ source: f.source,
5847
+ flag: f.flag,
5784
5848
  namespace: f.namespace,
5785
5849
  as_of: f.as_of,
5786
5850
  limit: f.limit,
@@ -6060,20 +6124,29 @@ function updateMemory(id, input, db) {
6060
6124
  sets.push("when_to_use = ?");
6061
6125
  params.push(input.when_to_use ?? null);
6062
6126
  }
6127
+ if (input.updated_by_agent !== undefined) {
6128
+ sets.push("updated_by_agent = ?");
6129
+ params.push(input.updated_by_agent ?? null);
6130
+ }
6063
6131
  if (input.tags !== undefined) {
6064
6132
  sets.push("tags = ?");
6065
6133
  params.push(JSON.stringify(input.tags));
6066
- d.run("DELETE FROM memory_tags WHERE memory_id = ?", [memoryId]);
6067
- const insertTag = d.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
6068
- for (const tag of input.tags) {
6069
- insertTag.run(memoryId, tag);
6070
- }
6071
6134
  }
6072
6135
  params.push(memoryId);
6073
- const result = d.run(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`, params);
6074
- if (result.changes === 0) {
6075
- throw new Error(`Update affected no rows for memory ${memoryId}: the record was read but not written. ` + `This is a bug in @hasna/mementos, not a bad argument \u2014 please report it.`);
6076
- }
6136
+ d.transaction(() => {
6137
+ const res = d.run(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`, params);
6138
+ if (res.changes === 0) {
6139
+ throw new Error(`Update affected no rows for memory ${memoryId}: the record was read but not written. ` + `This is a bug in @hasna/mementos, not a bad argument \u2014 please report it.`);
6140
+ }
6141
+ if (input.tags !== undefined) {
6142
+ d.run("DELETE FROM memory_tags WHERE memory_id = ?", [memoryId]);
6143
+ const insertTag = d.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
6144
+ for (const tag of input.tags) {
6145
+ insertTag.run(memoryId, tag);
6146
+ }
6147
+ }
6148
+ return res;
6149
+ });
6077
6150
  const updated = getMemory(memoryId, d);
6078
6151
  if (input.value !== undefined) {
6079
6152
  try {
@@ -6244,7 +6317,7 @@ async function semanticSearch(queryText, options = {}, db) {
6244
6317
  scored.sort((a, b) => b.score - a.score);
6245
6318
  return scored.slice(0, limit);
6246
6319
  }
6247
- var RECALL_PROMOTE_THRESHOLD = 3;
6320
+ var RESERVED_AGENT_IDS, RECALL_PROMOTE_THRESHOLD = 3;
6248
6321
  var init_memories = __esm(() => {
6249
6322
  init_types();
6250
6323
  init_database();
@@ -6254,9 +6327,32 @@ var init_memories = __esm(() => {
6254
6327
  init_poisoning();
6255
6328
  init_entity_memories();
6256
6329
  init_api_mode();
6330
+ RESERVED_AGENT_IDS = new Set([
6331
+ "agent-a",
6332
+ "agent-x",
6333
+ "agent-z",
6334
+ "nonexistent-agent"
6335
+ ]);
6257
6336
  });
6258
6337
 
6259
6338
  // src/db/agents.ts
6339
+ import { homedir as homedir3 } from "os";
6340
+ import { join as join5 } from "path";
6341
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
6342
+ function resolveWritingAgentName() {
6343
+ const envName = process.env["MEMENTOS_AGENT"]?.trim();
6344
+ if (envName)
6345
+ return envName;
6346
+ try {
6347
+ const path = join5(homedir3(), ".hasna", "conversations", "agent-id");
6348
+ if (existsSync4(path)) {
6349
+ const fileAgent = readFileSync2(path, "utf8").trim();
6350
+ if (fileAgent)
6351
+ return fileAgent;
6352
+ }
6353
+ } catch {}
6354
+ return null;
6355
+ }
6260
6356
  function parseAgentRow(row) {
6261
6357
  return {
6262
6358
  id: row["id"],
@@ -6459,17 +6555,17 @@ var init_agents = __esm(() => {
6459
6555
  });
6460
6556
 
6461
6557
  // src/lib/package-version.ts
6462
- import { readFileSync as readFileSync2 } from "fs";
6463
- import { dirname as dirname2, join as join5 } from "path";
6558
+ import { readFileSync as readFileSync3 } from "fs";
6559
+ import { dirname as dirname2, join as join6 } from "path";
6464
6560
  import { fileURLToPath as fileURLToPath2 } from "url";
6465
6561
  function getMementosPackageVersion() {
6466
6562
  const here = dirname2(fileURLToPath2(import.meta.url));
6467
6563
  for (const candidate of [
6468
- join5(here, "..", "..", "package.json"),
6469
- join5(here, "..", "package.json")
6564
+ join6(here, "..", "..", "package.json"),
6565
+ join6(here, "..", "package.json")
6470
6566
  ]) {
6471
6567
  try {
6472
- const parsed = JSON.parse(readFileSync2(candidate, "utf8"));
6568
+ const parsed = JSON.parse(readFileSync3(candidate, "utf8"));
6473
6569
  if (typeof parsed.version === "string" && parsed.version.trim())
6474
6570
  return parsed.version;
6475
6571
  } catch {}
@@ -7472,13 +7568,13 @@ __export(exports_helpers, {
7472
7568
  DEFAULT_COMPACT_LIMIT: () => DEFAULT_COMPACT_LIMIT
7473
7569
  });
7474
7570
  import chalk from "chalk";
7475
- import { readFileSync as readFileSync3 } from "fs";
7476
- import { dirname as dirname3, join as join6, resolve as resolve2 } from "path";
7571
+ import { readFileSync as readFileSync4 } from "fs";
7572
+ import { dirname as dirname3, join as join7, resolve as resolve2 } from "path";
7477
7573
  import { fileURLToPath as fileURLToPath3 } from "url";
7478
7574
  function getPackageVersion() {
7479
7575
  try {
7480
- const pkgPath = join6(dirname3(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
7481
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
7576
+ const pkgPath = join7(dirname3(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
7577
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
7482
7578
  return pkg.version || "0.0.0";
7483
7579
  } catch {
7484
7580
  return "0.0.0";
@@ -8037,16 +8133,16 @@ function validateConfigKeyValue(key, value, DEFAULT_CONFIG) {
8037
8133
  return null;
8038
8134
  }
8039
8135
  function getConfigPath() {
8040
- const { homedir: homedir3 } = __require("os");
8041
- return join6(homedir3(), ".hasna", "mementos", "config.json");
8136
+ const { homedir: homedir4 } = __require("os");
8137
+ return join7(homedir4(), ".hasna", "mementos", "config.json");
8042
8138
  }
8043
8139
  function readFileConfig() {
8044
- const { existsSync: existsSync4 } = __require("fs");
8140
+ const { existsSync: existsSync5 } = __require("fs");
8045
8141
  const configPath = getConfigPath();
8046
- if (!existsSync4(configPath))
8142
+ if (!existsSync5(configPath))
8047
8143
  return {};
8048
8144
  try {
8049
- const data = JSON.parse(readFileSync3(configPath, "utf-8"));
8145
+ const data = JSON.parse(readFileSync4(configPath, "utf-8"));
8050
8146
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
8051
8147
  throw new Error("expected a JSON object");
8052
8148
  }
@@ -8057,10 +8153,10 @@ function readFileConfig() {
8057
8153
  }
8058
8154
  }
8059
8155
  function writeFileConfig(data) {
8060
- const { existsSync: existsSync4, writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = __require("fs");
8156
+ const { existsSync: existsSync5, writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = __require("fs");
8061
8157
  const configPath = getConfigPath();
8062
8158
  const dir = dirname3(configPath);
8063
- if (!existsSync4(dir))
8159
+ if (!existsSync5(dir))
8064
8160
  mkdirSync3(dir, { recursive: true });
8065
8161
  writeFileSync3(configPath, JSON.stringify(data, null, 2) + `
8066
8162
  `, "utf-8");
@@ -8488,7 +8584,7 @@ function buildFilterConditions(filter) {
8488
8584
  const conditions = [];
8489
8585
  const params = [];
8490
8586
  conditions.push("m.status = 'active'");
8491
- conditions.push("(m.expires_at IS NULL OR m.expires_at >= datetime('now'))");
8587
+ conditions.push("(m.expires_at IS NULL OR m.expires_at >= strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))");
8492
8588
  if (!filter)
8493
8589
  return { conditions, params };
8494
8590
  if (filter.scope) {
@@ -10568,7 +10664,7 @@ async function detectContradiction(newKey, newValue, options = {}, db) {
10568
10664
  conditions.push("project_id = ?");
10569
10665
  params.push(project_id);
10570
10666
  }
10571
- conditions.push("(valid_until IS NULL OR valid_until > datetime('now'))");
10667
+ conditions.push("(valid_until IS NULL OR valid_until > strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))");
10572
10668
  const sql = `SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY importance DESC LIMIT 10`;
10573
10669
  const rows = d.query(sql).all(...params);
10574
10670
  if (rows.length === 0) {
@@ -11762,10 +11858,12 @@ var init_synthesis2 = __esm(() => {
11762
11858
  var exports_session_jobs = {};
11763
11859
  __export(exports_session_jobs, {
11764
11860
  updateSessionJob: () => updateSessionJob,
11861
+ recoverStaleProcessingJobs: () => recoverStaleProcessingJobs,
11765
11862
  listSessionJobs: () => listSessionJobs,
11766
11863
  getSessionJob: () => getSessionJob,
11767
11864
  getNextPendingJob: () => getNextPendingJob,
11768
- createSessionJob: () => createSessionJob
11865
+ createSessionJob: () => createSessionJob,
11866
+ claimSessionJob: () => claimSessionJob
11769
11867
  });
11770
11868
  function parseJobRow(row) {
11771
11869
  return {
@@ -11895,6 +11993,18 @@ function getNextPendingJob(db) {
11895
11993
  return null;
11896
11994
  return parseJobRow(row);
11897
11995
  }
11996
+ function claimSessionJob(id, db) {
11997
+ const d = db || getDatabase();
11998
+ const startedAt = now();
11999
+ const result = d.run("UPDATE session_memory_jobs SET status = 'processing', started_at = ? WHERE id = ? AND status = 'pending'", [startedAt, id]);
12000
+ return result.changes;
12001
+ }
12002
+ function recoverStaleProcessingJobs(maxAgeMs, db) {
12003
+ const d = db || getDatabase();
12004
+ const cutoff = new Date(Date.now() - maxAgeMs).toISOString();
12005
+ const result = d.run("UPDATE session_memory_jobs SET status = 'pending', started_at = NULL WHERE status = 'processing' AND started_at < ?", [cutoff]);
12006
+ return result.changes;
12007
+ }
11898
12008
  var init_session_jobs = __esm(() => {
11899
12009
  init_database();
11900
12010
  init_api_mode();
@@ -12433,7 +12543,11 @@ async function processSessionJob(jobId, db) {
12433
12543
  return result;
12434
12544
  }
12435
12545
  try {
12436
- updateSessionJob(jobId, { status: "processing", started_at: new Date().toISOString() }, db);
12546
+ const changes = claimSessionJob(jobId, db);
12547
+ if (changes === 0) {
12548
+ result.errors.push(`Job already claimed or not pending: ${jobId}`);
12549
+ return result;
12550
+ }
12437
12551
  } catch (e) {
12438
12552
  result.errors.push(`Failed to mark job as processing: ${String(e)}`);
12439
12553
  return result;
@@ -12556,6 +12670,9 @@ function startSessionQueueWorker() {
12556
12670
  return;
12557
12671
  _workerStarted = true;
12558
12672
  setInterval(() => {
12673
+ try {
12674
+ recoverStaleProcessingJobs(30 * 60 * 1000);
12675
+ } catch {}
12559
12676
  _processNext();
12560
12677
  }, 5000);
12561
12678
  }
@@ -12609,13 +12726,13 @@ __export(exports_session_registry, {
12609
12726
  closeRegistry: () => closeRegistry,
12610
12727
  cleanStaleSessions: () => cleanStaleSessions
12611
12728
  });
12612
- import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
12613
- import { dirname as dirname6, join as join9 } from "path";
12729
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
12730
+ import { dirname as dirname6, join as join10 } from "path";
12614
12731
  function getDb() {
12615
12732
  if (_db2)
12616
12733
  return _db2;
12617
12734
  const dir = dirname6(DB_PATH);
12618
- if (!existsSync8(dir))
12735
+ if (!existsSync9(dir))
12619
12736
  mkdirSync5(dir, { recursive: true });
12620
12737
  _db2 = new SqliteAdapter(DB_PATH);
12621
12738
  _db2.run("PRAGMA journal_mode = WAL");
@@ -12790,7 +12907,7 @@ function closeRegistry() {
12790
12907
  var DB_PATH, _db2 = null;
12791
12908
  var init_session_registry = __esm(() => {
12792
12909
  init_storage();
12793
- DB_PATH = join9(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
12910
+ DB_PATH = join10(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
12794
12911
  });
12795
12912
 
12796
12913
  // src/db/pg-migrations.ts
@@ -62271,8 +62388,8 @@ var {
62271
62388
 
62272
62389
  // src/cli/index.tsx
62273
62390
  init_database();
62274
- import { readFileSync as readFileSync9 } from "fs";
62275
- import { dirname as dirname8, join as join13 } from "path";
62391
+ import { readFileSync as readFileSync10 } from "fs";
62392
+ import { dirname as dirname8, join as join14 } from "path";
62276
62393
  import { fileURLToPath as fileURLToPath5 } from "url";
62277
62394
 
62278
62395
  // src/db/machines.ts
@@ -64271,6 +64388,18 @@ function registerCrudCommands(program2) {
64271
64388
  }
64272
64389
  resolvedAgentId = ag.id;
64273
64390
  }
64391
+ const requestedSource = opts.source;
64392
+ const claimsAgentAuthor = !requestedSource || requestedSource === "agent";
64393
+ if (!resolvedAgentId && claimsAgentAuthor) {
64394
+ const writingName = resolveWritingAgentName();
64395
+ if (writingName) {
64396
+ resolvedAgentId = getAgent(writingName)?.id ?? registerAgent(writingName).id;
64397
+ } else if (requestedSource === "agent") {
64398
+ throw new Error(`No agent identity: an agent-source save needs a writing agent, and none could be resolved.
64399
+ ` + `Pass --agent <name>, set MEMENTOS_AGENT, or write the fleet identity file ` + `(~/.hasna/conversations/agent-id, produced by "conversations agents register").
64400
+ ` + `To write without claiming an agent author, omit --source or pass ` + `--source user|system|auto|imported.`);
64401
+ }
64402
+ }
64274
64403
  const input = {
64275
64404
  key,
64276
64405
  value,
@@ -64280,7 +64409,7 @@ function registerCrudCommands(program2) {
64280
64409
  tags: mergedTags,
64281
64410
  summary: opts.summary,
64282
64411
  ttl_ms: opts.ttl ? parseDuration(opts.ttl) : undefined,
64283
- source: opts.source,
64412
+ source: requestedSource,
64284
64413
  agent_id: resolvedAgentId,
64285
64414
  session_id: globalOpts.session
64286
64415
  };
@@ -64347,6 +64476,10 @@ function registerCrudCommands(program2) {
64347
64476
  const updateInput = {
64348
64477
  version: existing.version
64349
64478
  };
64479
+ const writingName = resolveWritingAgentName();
64480
+ if (writingName) {
64481
+ updateInput.updated_by_agent = getAgent(writingName)?.id ?? registerAgent(writingName).id;
64482
+ }
64350
64483
  if (opts.value !== undefined)
64351
64484
  updateInput.value = opts.value;
64352
64485
  if (opts.importance !== undefined)
@@ -64374,7 +64507,7 @@ function registerCrudCommands(program2) {
64374
64507
  if (violation)
64375
64508
  throw new Error(formatEnumViolation(violation));
64376
64509
  }
64377
- const changedFields = Object.keys(updateInput).filter((k) => k !== "version");
64510
+ const changedFields = Object.keys(updateInput).filter((k) => k !== "version" && k !== "updated_by_agent");
64378
64511
  if (changedFields.length === 0) {
64379
64512
  throw new Error(`Nothing to update: no fields were given for ${existing.key} (${existing.id.slice(0, 8)}). ` + `Pass at least one of --value, --scope, --category, --status, --importance, --tags, --summary, --pin/--unpin. ` + `Note that -s is the global --session, not --scope.`);
64380
64513
  }
@@ -64404,8 +64537,7 @@ function registerCrudCommands(program2) {
64404
64537
  }
64405
64538
  const matches = getMemoriesByKey(keyOrId, opts.scope, opts.agent, opts.project);
64406
64539
  if (matches.length === 0) {
64407
- const looksLikeId = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(keyOrId);
64408
- if (isApiMode() && looksLikeId && deleteMemory(keyOrId)) {
64540
+ if (isApiMode() && keyOrId.length > 0 && deleteMemory(keyOrId)) {
64409
64541
  if (globalOpts.json) {
64410
64542
  outputJson({ deleted: keyOrId });
64411
64543
  } else {
@@ -64977,7 +65109,7 @@ function registerRemoveCommand(program2) {
64977
65109
  if (mem)
64978
65110
  id = mem.id;
64979
65111
  }
64980
- if (!id && isApiMode() && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId)) {
65112
+ if (!id && isApiMode() && nameOrId.length > 0) {
64981
65113
  id = nameOrId;
64982
65114
  }
64983
65115
  if (!id) {
@@ -65210,7 +65342,10 @@ function getMemoryStats(db) {
65210
65342
  const byCategory = d.query("SELECT category, COUNT(*) as c FROM memories WHERE status = 'active' GROUP BY category").all();
65211
65343
  const byStatus = d.query("SELECT status, COUNT(*) as c FROM memories WHERE status = 'active' GROUP BY status").all();
65212
65344
  const pinnedCount = d.query("SELECT COUNT(*) as c FROM memories WHERE pinned = 1 AND status = 'active'").get().c;
65213
- const expiredCount = d.query("SELECT COUNT(*) as c FROM memories WHERE status = 'expired' OR (expires_at IS NOT NULL AND expires_at < datetime('now'))").get().c;
65345
+ const expiredCount = d.query("SELECT COUNT(*) as c FROM memories WHERE status = 'expired'").get().c;
65346
+ const expiresAtCount = d.query("SELECT COUNT(*) as c FROM memories WHERE expires_at IS NOT NULL").get().c;
65347
+ const nowIso = new Date().toISOString();
65348
+ const expiredDueCount = d.query("SELECT COUNT(*) as c FROM memories WHERE status = 'expired' OR (expires_at IS NOT NULL AND expires_at < ?)").get(nowIso).c;
65214
65349
  const stats = {
65215
65350
  total,
65216
65351
  by_scope: { global: 0, shared: 0, private: 0, working: 0 },
@@ -65218,7 +65353,9 @@ function getMemoryStats(db) {
65218
65353
  by_status: { active: 0, archived: 0, expired: 0 },
65219
65354
  by_agent: {},
65220
65355
  pinned_count: pinnedCount,
65221
- expired_count: expiredCount
65356
+ expired_count: expiredCount,
65357
+ expires_at_count: expiresAtCount,
65358
+ expired_due_count: expiredDueCount
65222
65359
  };
65223
65360
  for (const row of byScope)
65224
65361
  if (row.scope in stats.by_scope)
@@ -65252,7 +65389,9 @@ function normalizeStats(data) {
65252
65389
  by_status: { active: 0, archived: 0, expired: 0, ...data?.by_status ?? {} },
65253
65390
  by_agent: data?.by_agent ?? {},
65254
65391
  pinned_count: data?.pinned_count ?? 0,
65255
- expired_count: data?.expired_count ?? 0
65392
+ expired_count: data?.expired_count ?? 0,
65393
+ expires_at_count: data?.expires_at_count ?? 0,
65394
+ expired_due_count: data?.expired_due_count ?? 0
65256
65395
  };
65257
65396
  }
65258
65397
  function getMemoryReport(filter = {}, db) {
@@ -65310,7 +65449,7 @@ function getStaleMemoriesPage(filter = {}, db) {
65310
65449
  const limit = filter.limit ?? 20;
65311
65450
  const offset = filter.offset ?? 0;
65312
65451
  if (!db && isApiMode()) {
65313
- const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id, limit, offset });
65452
+ const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id, pinned: filter.pinned, limit, offset });
65314
65453
  const { data } = apiJson("GET", `/memories/stale${q}`);
65315
65454
  const rows2 = data?.memories ?? [];
65316
65455
  return {
@@ -65322,8 +65461,14 @@ function getStaleMemoriesPage(filter = {}, db) {
65322
65461
  }
65323
65462
  const d = db || getDatabase();
65324
65463
  const cutoffDate = new Date(Date.now() - days * 86400000).toISOString();
65325
- const conds = ["status = 'active'", "(accessed_at IS NULL OR accessed_at < ?)", "pinned = 0"];
65464
+ const conds = ["status = 'active'", "(accessed_at IS NULL OR accessed_at < ?)"];
65326
65465
  const params = [cutoffDate];
65466
+ if (filter.pinned !== undefined) {
65467
+ conds.push("pinned = ?");
65468
+ params.push(filter.pinned ? 1 : 0);
65469
+ } else {
65470
+ conds.push("pinned = 0");
65471
+ }
65327
65472
  if (filter.project_id) {
65328
65473
  conds.push("project_id = ?");
65329
65474
  params.push(filter.project_id);
@@ -65500,7 +65645,7 @@ init_projects();
65500
65645
  init_helpers();
65501
65646
  function registerStaleCommand(program2) {
65502
65647
  const handleError = makeHandleError(program2);
65503
- program2.command("stale").description("Find memories not accessed recently (for cleanup/review)").option("--days <n>", "Stale threshold in days (default: 30)", parseInt).option("--project <path>", "Project filter").option("--agent <name>", "Agent filter").option("--limit <n>", "Max results (default: 20)", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--format <fmt>", "Output format: compact (default), json").option("--verbose", "Show wider memory snippets").action((opts) => {
65648
+ program2.command("stale").description("Find memories not accessed recently (for cleanup/review)").option("--days <n>", "Stale threshold in days (default: 30)", parseInt).option("--pinned", "Review stale PINNED memories (default view excludes pinned)").option("--project <path>", "Project filter").option("--agent <name>", "Agent filter").option("--limit <n>", "Max results (default: 20)", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--format <fmt>", "Output format: compact (default), json").option("--verbose", "Show wider memory snippets").action((opts) => {
65504
65649
  try {
65505
65650
  const globalOpts = program2.opts();
65506
65651
  const days = opts.days || 30;
@@ -65521,6 +65666,7 @@ function registerStaleCommand(program2) {
65521
65666
  const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65522
65667
  const page = getStaleMemoriesPage({
65523
65668
  days,
65669
+ pinned: opts.pinned ? true : undefined,
65524
65670
  project_id: projectId,
65525
65671
  agent_id: agentId,
65526
65672
  limit: pageLimit,
@@ -65822,7 +65968,7 @@ init_memories();
65822
65968
  init_helpers();
65823
65969
  import chalk18 from "chalk";
65824
65970
  import { resolve as resolve12 } from "path";
65825
- import { readFileSync as readFileSync4 } from "fs";
65971
+ import { readFileSync as readFileSync5 } from "fs";
65826
65972
  function registerImportCommand(program2) {
65827
65973
  const handleError = makeHandleError(program2);
65828
65974
  program2.command("import [file]").description("Import memories from a JSON file or stdin (use '-' or pipe data)").option("--overwrite", "Overwrite existing memories (default: merge)").action(async (file, opts) => {
@@ -65832,7 +65978,7 @@ function registerImportCommand(program2) {
65832
65978
  if (file === "-" || !file && !process.stdin.isTTY) {
65833
65979
  raw = await Bun.stdin.text();
65834
65980
  } else if (file) {
65835
- raw = readFileSync4(resolve12(file), "utf-8");
65981
+ raw = readFileSync5(resolve12(file), "utf-8");
65836
65982
  } else {
65837
65983
  console.error(chalk18.red("No input: provide a file path, use '-' for stdin, or pipe data."));
65838
65984
  process.exit(1);
@@ -65862,14 +66008,14 @@ function registerImportCommand(program2) {
65862
66008
  import chalk19 from "chalk";
65863
66009
 
65864
66010
  // src/lib/config.ts
65865
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
65866
- import { homedir as homedir3 } from "os";
65867
- import { basename, dirname as dirname4, join as join7, resolve as resolve13 } from "path";
66011
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
66012
+ import { homedir as homedir4 } from "os";
66013
+ import { basename, dirname as dirname4, join as join8, resolve as resolve13 } from "path";
65868
66014
  function isInMemoryDb2(path) {
65869
66015
  return path === ":memory:" || path.startsWith("file::memory:");
65870
66016
  }
65871
66017
  function homeDir() {
65872
- return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
66018
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir4();
65873
66019
  }
65874
66020
  var DEFAULT_CONFIG = {
65875
66021
  default_scope: "private",
@@ -65927,11 +66073,11 @@ function isValidCategory(value) {
65927
66073
  return VALID_CATEGORIES2.includes(value);
65928
66074
  }
65929
66075
  function loadConfig() {
65930
- const configPath = join7(homeDir(), ".hasna", "mementos", "config.json");
66076
+ const configPath = join8(homeDir(), ".hasna", "mementos", "config.json");
65931
66077
  let fileConfig = {};
65932
- if (existsSync4(configPath)) {
66078
+ if (existsSync5(configPath)) {
65933
66079
  try {
65934
- const raw = readFileSync5(configPath, "utf-8");
66080
+ const raw = readFileSync6(configPath, "utf-8");
65935
66081
  fileConfig = JSON.parse(raw);
65936
66082
  } catch {}
65937
66083
  }
@@ -65957,8 +66103,8 @@ function findFileWalkingUp(filename) {
65957
66103
  let dir = process.cwd();
65958
66104
  const legacyHomeMementosDb = resolve13(homeDir(), ".mementos", "mementos.db");
65959
66105
  while (true) {
65960
- const candidate = join7(dir, filename);
65961
- if (existsSync4(candidate) && resolve13(candidate) !== legacyHomeMementosDb) {
66106
+ const candidate = join8(dir, filename);
66107
+ if (existsSync5(candidate) && resolve13(candidate) !== legacyHomeMementosDb) {
65962
66108
  return candidate;
65963
66109
  }
65964
66110
  const parent = dirname4(dir);
@@ -65971,7 +66117,7 @@ function findFileWalkingUp(filename) {
65971
66117
  function findGitRoot2() {
65972
66118
  let dir = process.cwd();
65973
66119
  while (true) {
65974
- if (existsSync4(join7(dir, ".git"))) {
66120
+ if (existsSync5(join8(dir, ".git"))) {
65975
66121
  return dir;
65976
66122
  }
65977
66123
  const parent = dirname4(dir);
@@ -65982,27 +66128,27 @@ function findGitRoot2() {
65982
66128
  }
65983
66129
  }
65984
66130
  function profilesDir() {
65985
- return join7(homeDir(), ".hasna", "mementos", "profiles");
66131
+ return join8(homeDir(), ".hasna", "mementos", "profiles");
65986
66132
  }
65987
66133
  function globalConfigPath() {
65988
- return join7(homeDir(), ".hasna", "mementos", "config.json");
66134
+ return join8(homeDir(), ".hasna", "mementos", "config.json");
65989
66135
  }
65990
66136
  function readGlobalConfig() {
65991
66137
  const p = globalConfigPath();
65992
- if (!existsSync4(p))
66138
+ if (!existsSync5(p))
65993
66139
  return {};
65994
66140
  try {
65995
- return JSON.parse(readFileSync5(p, "utf-8"));
66141
+ return JSON.parse(readFileSync6(p, "utf-8"));
65996
66142
  } catch {
65997
66143
  return {};
65998
66144
  }
65999
66145
  }
66000
66146
  function readGlobalConfigForWrite() {
66001
66147
  const p = globalConfigPath();
66002
- if (!existsSync4(p))
66148
+ if (!existsSync5(p))
66003
66149
  return {};
66004
66150
  try {
66005
- const data = JSON.parse(readFileSync5(p, "utf-8"));
66151
+ const data = JSON.parse(readFileSync6(p, "utf-8"));
66006
66152
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
66007
66153
  throw new Error("expected a JSON object");
66008
66154
  }
@@ -66035,13 +66181,13 @@ function setActiveProfile(name) {
66035
66181
  }
66036
66182
  function listProfiles() {
66037
66183
  const dir = profilesDir();
66038
- if (!existsSync4(dir))
66184
+ if (!existsSync5(dir))
66039
66185
  return [];
66040
66186
  return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
66041
66187
  }
66042
66188
  function deleteProfile(name) {
66043
- const dbPath = join7(profilesDir(), `${name}.db`);
66044
- if (!existsSync4(dbPath))
66189
+ const dbPath = join8(profilesDir(), `${name}.db`);
66190
+ if (!existsSync5(dbPath))
66045
66191
  return false;
66046
66192
  unlinkSync2(dbPath);
66047
66193
  if (getActiveProfile() === name)
@@ -66050,10 +66196,10 @@ function deleteProfile(name) {
66050
66196
  }
66051
66197
  function getDbPath2() {
66052
66198
  const _home = homeDir();
66053
- const _newDir = join7(_home, ".hasna", "mementos");
66054
- const _oldDir = join7(_home, ".mementos");
66055
- if (!existsSync4(_newDir) && existsSync4(_oldDir)) {
66056
- mkdirSync3(join7(_home, ".hasna"), { recursive: true });
66199
+ const _newDir = join8(_home, ".hasna", "mementos");
66200
+ const _oldDir = join8(_home, ".mementos");
66201
+ if (!existsSync5(_newDir) && existsSync5(_oldDir)) {
66202
+ mkdirSync3(join8(_home, ".hasna"), { recursive: true });
66057
66203
  cpSync2(_oldDir, _newDir, { recursive: true });
66058
66204
  }
66059
66205
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
@@ -66067,7 +66213,7 @@ function getDbPath2() {
66067
66213
  }
66068
66214
  const profile = getActiveProfile();
66069
66215
  if (profile) {
66070
- const profilePath = join7(profilesDir(), `${profile}.db`);
66216
+ const profilePath = join8(profilesDir(), `${profile}.db`);
66071
66217
  ensureDir2(dirname4(profilePath));
66072
66218
  return profilePath;
66073
66219
  }
@@ -66075,21 +66221,21 @@ function getDbPath2() {
66075
66221
  if (dbScope === "project") {
66076
66222
  const gitRoot = findGitRoot2();
66077
66223
  if (gitRoot) {
66078
- const dbPath = join7(gitRoot, ".mementos", "mementos.db");
66224
+ const dbPath = join8(gitRoot, ".mementos", "mementos.db");
66079
66225
  ensureDir2(dirname4(dbPath));
66080
66226
  return dbPath;
66081
66227
  }
66082
66228
  }
66083
- const found = findFileWalkingUp(join7(".mementos", "mementos.db"));
66229
+ const found = findFileWalkingUp(join8(".mementos", "mementos.db"));
66084
66230
  if (found) {
66085
66231
  return found;
66086
66232
  }
66087
- const fallback = join7(homeDir(), ".hasna", "mementos", "mementos.db");
66233
+ const fallback = join8(homeDir(), ".hasna", "mementos", "mementos.db");
66088
66234
  ensureDir2(dirname4(fallback));
66089
66235
  return fallback;
66090
66236
  }
66091
66237
  function ensureDir2(dir) {
66092
- if (!existsSync4(dir)) {
66238
+ if (!existsSync5(dir)) {
66093
66239
  mkdirSync3(dir, { recursive: true });
66094
66240
  }
66095
66241
  }
@@ -66207,7 +66353,7 @@ init_database();
66207
66353
  init_helpers();
66208
66354
  import chalk20 from "chalk";
66209
66355
  import { resolve as resolve14, dirname as dirname5 } from "path";
66210
- import { existsSync as existsSync5, statSync, copyFileSync, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
66356
+ import { existsSync as existsSync6, statSync, copyFileSync, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
66211
66357
  function registerBackupCommand(program2) {
66212
66358
  const handleError = makeHandleError(program2);
66213
66359
  program2.command("backup [path]").description("Backup the SQLite database to a file").option("--list", "List available backups in ~/.hasna/mementos/backups/").action((targetPath, opts) => {
@@ -66216,7 +66362,7 @@ function registerBackupCommand(program2) {
66216
66362
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
66217
66363
  const backupsDir = resolve14(home, ".hasna", "mementos", "backups");
66218
66364
  if (opts.list) {
66219
- if (!existsSync5(backupsDir)) {
66365
+ if (!existsSync6(backupsDir)) {
66220
66366
  if (globalOpts.json) {
66221
66367
  outputJson({ backups: [] });
66222
66368
  return;
@@ -66258,7 +66404,7 @@ function registerBackupCommand(program2) {
66258
66404
  return;
66259
66405
  }
66260
66406
  const dbPath = getDbPath();
66261
- if (!existsSync5(dbPath)) {
66407
+ if (!existsSync6(dbPath)) {
66262
66408
  console.error(chalk20.red(`Database not found at ${dbPath}`));
66263
66409
  process.exit(1);
66264
66410
  }
@@ -66266,7 +66412,7 @@ function registerBackupCommand(program2) {
66266
66412
  if (targetPath) {
66267
66413
  dest = resolve14(targetPath);
66268
66414
  } else {
66269
- if (!existsSync5(backupsDir)) {
66415
+ if (!existsSync6(backupsDir)) {
66270
66416
  mkdirSync4(backupsDir, { recursive: true });
66271
66417
  }
66272
66418
  const now3 = new Date;
@@ -66274,7 +66420,7 @@ function registerBackupCommand(program2) {
66274
66420
  dest = resolve14(backupsDir, `mementos-${ts}.db`);
66275
66421
  }
66276
66422
  const destDir = dirname5(dest);
66277
- if (!existsSync5(destDir)) {
66423
+ if (!existsSync6(destDir)) {
66278
66424
  mkdirSync4(destDir, { recursive: true });
66279
66425
  }
66280
66426
  copyFileSync(dbPath, dest);
@@ -66295,29 +66441,31 @@ function registerBackupCommand(program2) {
66295
66441
  // src/cli/commands/io-restore.ts
66296
66442
  init_database();
66297
66443
  init_api_mode();
66444
+ init_memories();
66298
66445
  init_helpers();
66299
66446
  import chalk21 from "chalk";
66300
66447
  import { resolve as resolve15 } from "path";
66301
- import { existsSync as existsSync6, statSync as statSync2, copyFileSync as copyFileSync2, readdirSync as readdirSync3 } from "fs";
66448
+ import { existsSync as existsSync7, statSync as statSync2, copyFileSync as copyFileSync2, readdirSync as readdirSync3 } from "fs";
66449
+ function readMemoriesFromBackup(source) {
66450
+ const { Database: Database3 } = __require("bun:sqlite");
66451
+ const backupDb = new Database3(source, { readonly: true });
66452
+ try {
66453
+ const rows = backupDb.query("SELECT * FROM memories").all();
66454
+ return { rows, count: rows.length };
66455
+ } finally {
66456
+ backupDb.close();
66457
+ }
66458
+ }
66302
66459
  function registerRestoreCommand(program2) {
66303
66460
  const handleError = makeHandleError(program2);
66304
66461
  program2.command("restore [file]").description("Restore the database from a backup file").option("--latest", "Restore the most recent backup from ~/.hasna/mementos/backups/").option("--force", "Skip confirmation and perform the restore").action((filePath, opts) => {
66305
66462
  try {
66306
66463
  const globalOpts = program2.opts();
66307
- if (isApiMode()) {
66308
- const msg = "restore operates on the local SQLite database and is not available in API mode (the self-hosted cloud store is authoritative). Unset HASNA_MEMENTOS_API_URL / HASNA_MEMENTOS_API_KEY to restore a local db.";
66309
- if (globalOpts.json) {
66310
- outputJson({ error: msg });
66311
- } else {
66312
- console.error(chalk21.red(msg));
66313
- }
66314
- process.exit(1);
66315
- }
66316
66464
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
66317
66465
  const backupsDir = resolve15(home, ".hasna", "mementos", "backups");
66318
66466
  let source;
66319
66467
  if (opts.latest) {
66320
- if (!existsSync6(backupsDir)) {
66468
+ if (!existsSync7(backupsDir)) {
66321
66469
  console.error(chalk21.red("No backups directory found."));
66322
66470
  process.exit(1);
66323
66471
  }
@@ -66337,16 +66485,82 @@ function registerRestoreCommand(program2) {
66337
66485
  console.error(chalk21.red("Provide a backup file path or use --latest"));
66338
66486
  process.exit(1);
66339
66487
  }
66340
- if (!existsSync6(source)) {
66488
+ if (!existsSync7(source)) {
66341
66489
  console.error(chalk21.red(`Backup file not found: ${source}`));
66342
66490
  process.exit(1);
66343
66491
  }
66344
- const dbPath = getDbPath();
66345
66492
  const backupStat = statSync2(source);
66346
66493
  const backupSizeMB = (backupStat.size / (1024 * 1024)).toFixed(1);
66347
66494
  const backupSizeStr = backupStat.size >= 1024 * 1024 ? `${backupSizeMB} MB` : `${(backupStat.size / 1024).toFixed(1)} KB`;
66495
+ if (isApiMode()) {
66496
+ const { rows, count } = readMemoriesFromBackup(source);
66497
+ if (!opts.force) {
66498
+ if (globalOpts.json) {
66499
+ outputJson({
66500
+ action: "restore",
66501
+ source,
66502
+ target: "cloud-api",
66503
+ backup_size: backupStat.size,
66504
+ backup_memories: count,
66505
+ status: "dry_run",
66506
+ message: "Restores the backup's memories into the hosted store; existing store rows are never overwritten. Use --force to confirm."
66507
+ });
66508
+ return;
66509
+ }
66510
+ console.log(chalk21.bold("Restore preview (hosted store):"));
66511
+ console.log(` Source: ${chalk21.cyan(source)} (${backupSizeStr})`);
66512
+ console.log(` Backup memories: ${chalk21.green(String(count))}`);
66513
+ console.log(` Target: hosted store (cloud-api)`);
66514
+ console.log(` Semantics: merges the backup's memories; existing rows are never overwritten`);
66515
+ console.log();
66516
+ console.log(chalk21.yellow("Use --force to confirm restore"));
66517
+ return;
66518
+ }
66519
+ const result = bulkUpsertMemories(rows);
66520
+ if (result.rejected > 0) {
66521
+ const msg = `${result.rejected} of ${result.total} memories were rejected and did not persist. See errors.`;
66522
+ if (globalOpts.json) {
66523
+ outputJson({
66524
+ action: "restore",
66525
+ status: "failed",
66526
+ source,
66527
+ target: "cloud-api",
66528
+ inserted: result.inserted,
66529
+ skipped: result.skipped,
66530
+ rejected: result.rejected,
66531
+ total: result.total,
66532
+ error: msg
66533
+ });
66534
+ } else {
66535
+ console.error(chalk21.red(msg));
66536
+ }
66537
+ process.exit(1);
66538
+ }
66539
+ if (globalOpts.json) {
66540
+ outputJson({
66541
+ action: "restore",
66542
+ source,
66543
+ target: "cloud-api",
66544
+ backup_size: backupStat.size,
66545
+ backup_memories: count,
66546
+ restored_memories: result.inserted,
66547
+ inserted: result.inserted,
66548
+ skipped: result.skipped,
66549
+ rejected: result.rejected,
66550
+ total: result.total,
66551
+ status: "completed"
66552
+ });
66553
+ return;
66554
+ }
66555
+ console.log(`Restored from: ${chalk21.green(source)}`);
66556
+ console.log(` Restored memories: ${chalk21.green(String(result.inserted))} (inserted)`);
66557
+ console.log(` Skipped (already present): ${chalk21.yellow(String(result.skipped))}`);
66558
+ console.log(` Rejected: ${chalk21.yellow(String(result.rejected))}`);
66559
+ return;
66560
+ }
66561
+ const dbPath = getDbPath();
66348
66562
  let currentCount = 0;
66349
- if (existsSync6(dbPath)) {
66563
+ if (existsSync7(dbPath)) {
66350
66564
  try {
66351
66565
  const db = getDatabase();
66352
66566
  const row = db.query("SELECT COUNT(*) as count FROM memories").get();
@@ -67600,11 +67814,11 @@ init_memories();
67600
67814
  init_agents();
67601
67815
  init_projects();
67602
67816
  import chalk27 from "chalk";
67603
- import { join as join8 } from "path";
67604
- import { homedir as homedir4 } from "os";
67817
+ import { join as join9 } from "path";
67818
+ import { homedir as homedir5 } from "os";
67605
67819
  import {
67606
- readFileSync as readFileSync6,
67607
- existsSync as existsSync7,
67820
+ readFileSync as readFileSync7,
67821
+ existsSync as existsSync8,
67608
67822
  accessSync,
67609
67823
  statSync as statSync3,
67610
67824
  constants as fsConstants
@@ -67639,7 +67853,7 @@ function registerDoctorCommand(program2) {
67639
67853
  checks.push({ name: "Version", status: "ok", detail: version });
67640
67854
  const dbPath = getDbPath();
67641
67855
  let db = null;
67642
- if (dbPath !== ":memory:" && existsSync7(dbPath)) {
67856
+ if (dbPath !== ":memory:" && existsSync8(dbPath)) {
67643
67857
  try {
67644
67858
  accessSync(dbPath, fsConstants.R_OK | fsConstants.W_OK);
67645
67859
  checks.push({ name: "Database file", status: "ok", detail: dbPath });
@@ -67658,7 +67872,7 @@ function registerDoctorCommand(program2) {
67658
67872
  checks.push({ name: "Database connection", status: "fail", detail: e instanceof Error ? e.message : String(e) });
67659
67873
  }
67660
67874
  try {
67661
- if (dbPath !== ":memory:" && existsSync7(dbPath)) {
67875
+ if (dbPath !== ":memory:" && existsSync8(dbPath)) {
67662
67876
  const stats = statSync3(dbPath);
67663
67877
  const sizeKb = (stats.size / 1024).toFixed(1);
67664
67878
  const sizeMb = (stats.size / (1024 * 1024)).toFixed(2);
@@ -67791,9 +68005,9 @@ function registerDoctorCommand(program2) {
67791
68005
  checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
67792
68006
  }
67793
68007
  try {
67794
- const settingsFilePath = join8(homedir4(), ".claude", "settings.json");
67795
- if (existsSync7(settingsFilePath)) {
67796
- const settings = JSON.parse(readFileSync6(settingsFilePath, "utf-8"));
68008
+ const settingsFilePath = join9(homedir5(), ".claude", "settings.json");
68009
+ if (existsSync8(settingsFilePath)) {
68010
+ const settings = JSON.parse(readFileSync7(settingsFilePath, "utf-8"));
67797
68011
  const hooksObj = settings["hooks"] || {};
67798
68012
  const stopHooks = hooksObj["Stop"] || [];
67799
68013
  const hasMementos = stopHooks.some((e) => e.hooks?.some((h) => h.command && h.command.includes("mementos")));
@@ -67809,11 +68023,11 @@ function registerDoctorCommand(program2) {
67809
68023
  checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
67810
68024
  }
67811
68025
  if (process.platform === "darwin") {
67812
- const plistFilePath = join8(homedir4(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
68026
+ const plistFilePath = join9(homedir5(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
67813
68027
  checks.push({
67814
68028
  name: "Auto-start",
67815
- status: existsSync7(plistFilePath) ? "ok" : "warn",
67816
- detail: existsSync7(plistFilePath) ? "configured (starts on login)" : "not configured \u2192 run: mementos init"
68029
+ status: existsSync8(plistFilePath) ? "ok" : "warn",
68030
+ detail: existsSync8(plistFilePath) ? "configured (starts on login)" : "not configured \u2192 run: mementos init"
67817
68031
  });
67818
68032
  } else {
67819
68033
  checks.push({ name: "Auto-start", status: "ok", detail: `n/a on ${process.platform}` });
@@ -67892,9 +68106,9 @@ async function runCloudDoctor(globalOpts, checks) {
67892
68106
  checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
67893
68107
  }
67894
68108
  try {
67895
- const settingsFilePath = join8(homedir4(), ".claude", "settings.json");
67896
- if (existsSync7(settingsFilePath)) {
67897
- const settings = JSON.parse(readFileSync6(settingsFilePath, "utf-8"));
68109
+ const settingsFilePath = join9(homedir5(), ".claude", "settings.json");
68110
+ if (existsSync8(settingsFilePath)) {
68111
+ const settings = JSON.parse(readFileSync7(settingsFilePath, "utf-8"));
67898
68112
  const hooksObj = settings["hooks"] || {};
67899
68113
  const stopHooks = hooksObj["Stop"] || [];
67900
68114
  const hasMementos = stopHooks.some((e) => e.hooks?.some((h) => h.command && h.command.includes("mementos")));
@@ -67910,11 +68124,11 @@ async function runCloudDoctor(globalOpts, checks) {
67910
68124
  checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
67911
68125
  }
67912
68126
  if (process.platform === "darwin") {
67913
- const plistFilePath = join8(homedir4(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
68127
+ const plistFilePath = join9(homedir5(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
67914
68128
  checks.push({
67915
68129
  name: "Auto-start",
67916
- status: existsSync7(plistFilePath) ? "ok" : "warn",
67917
- detail: existsSync7(plistFilePath) ? "configured (starts on login)" : "not configured \u2192 run: mementos init"
68130
+ status: existsSync8(plistFilePath) ? "ok" : "warn",
68131
+ detail: existsSync8(plistFilePath) ? "configured (starts on login)" : "not configured \u2192 run: mementos init"
67918
68132
  });
67919
68133
  } else {
67920
68134
  checks.push({ name: "Auto-start", status: "ok", detail: `n/a on ${process.platform}` });
@@ -69440,6 +69654,7 @@ function syncMemoriesTable(source, target, local, direction, currentMachineId) {
69440
69654
  const countResult = source.get(`SELECT COUNT(*) as cnt FROM "${MEMORY_TABLE}"`);
69441
69655
  stat.total_rows = countResult?.cnt ?? 0;
69442
69656
  const rows = since ? source.all(`SELECT * FROM "${MEMORY_TABLE}" WHERE updated_at > ?`, since) : source.all(`SELECT * FROM "${MEMORY_TABLE}"`);
69657
+ const erroredRowIds = new Set;
69443
69658
  for (const row of rows) {
69444
69659
  try {
69445
69660
  const sourceMachine = sourceMachineRef(row, currentMachineId);
@@ -69498,18 +69713,34 @@ function syncMemoriesTable(source, target, local, direction, currentMachineId) {
69498
69713
  clearMemoryEmbedding(winnerDb, String(winner["id"]));
69499
69714
  stat.synced_rows++;
69500
69715
  } catch (error) {
69716
+ erroredRowIds.add(String(row["id"] ?? "unknown"));
69501
69717
  stat.errors.push(`Memory ${String(row["id"] ?? "unknown")}: ${error instanceof Error ? error.message : String(error)}`);
69502
69718
  }
69503
69719
  }
69504
69720
  if (rows.length === 0) {
69505
69721
  stat.skipped_rows = stat.total_rows;
69506
69722
  }
69507
- upsertMemorySyncMeta(local, {
69508
- table_name: MEMORY_TABLE,
69509
- direction,
69510
- last_synced_at: new Date().toISOString(),
69511
- last_synced_row_count: stat.synced_rows
69512
- });
69723
+ if (rows.length > 0 && stat.errors.length === 0) {
69724
+ let maxSyncedAt = null;
69725
+ for (const row of rows) {
69726
+ if (erroredRowIds.has(String(row["id"] ?? "unknown"))) {
69727
+ continue;
69728
+ }
69729
+ const value = row["updated_at"];
69730
+ if (typeof value === "string" && (maxSyncedAt === null || value > maxSyncedAt)) {
69731
+ maxSyncedAt = value;
69732
+ }
69733
+ }
69734
+ const nextCursor = maxSyncedAt ?? syncMeta?.last_synced_at ?? null;
69735
+ if (nextCursor !== null) {
69736
+ upsertMemorySyncMeta(local, {
69737
+ table_name: MEMORY_TABLE,
69738
+ direction,
69739
+ last_synced_at: nextCursor,
69740
+ last_synced_row_count: stat.synced_rows
69741
+ });
69742
+ }
69743
+ }
69513
69744
  } catch (error) {
69514
69745
  stat.errors.push(error instanceof Error ? error.message : String(error));
69515
69746
  }
@@ -69899,19 +70130,19 @@ function registerStorageCommands(program2) {
69899
70130
  // src/cli/commands/init.ts
69900
70131
  import chalk41 from "chalk";
69901
70132
  import {
69902
- readFileSync as readFileSync7,
70133
+ readFileSync as readFileSync8,
69903
70134
  writeFileSync as writeFileSync4,
69904
- existsSync as existsSync9,
70135
+ existsSync as existsSync10,
69905
70136
  copyFileSync as copyFileSync3,
69906
70137
  mkdirSync as mkdirSync6
69907
70138
  } from "fs";
69908
- import { dirname as dirname7, join as join10 } from "path";
69909
- import { homedir as homedir5 } from "os";
70139
+ import { dirname as dirname7, join as join11 } from "path";
70140
+ import { homedir as homedir6 } from "os";
69910
70141
  import { fileURLToPath as fileURLToPath4 } from "url";
69911
70142
  function registerInitCommand(program2) {
69912
70143
  program2.command("init").description("One-command setup: register MCP, install stop hook, configure auto-start").action(async () => {
69913
70144
  const { platform: platform2 } = process;
69914
- const home = homedir5();
70145
+ const home = homedir6();
69915
70146
  const isMac = platform2 === "darwin";
69916
70147
  console.log("");
69917
70148
  console.log(chalk41.bold(" mementos \u2014 setting up your memory layer"));
@@ -69966,17 +70197,17 @@ function registerInitCommand(program2) {
69966
70197
  } else {
69967
70198
  console.log(chalk41.green(" \u2713 MCP server registered with Claude Code"));
69968
70199
  }
69969
- const hooksDir = join10(home, ".claude", "hooks");
69970
- const hookDest = join10(hooksDir, "mementos-stop-hook.ts");
69971
- const settingsPath = join10(home, ".claude", "settings.json");
70200
+ const hooksDir = join11(home, ".claude", "hooks");
70201
+ const hookDest = join11(hooksDir, "mementos-stop-hook.ts");
70202
+ const settingsPath = join11(home, ".claude", "settings.json");
69972
70203
  const hookCommand = `bun ${hookDest}`;
69973
70204
  let hookAlreadyInstalled = false;
69974
70205
  let hookError = null;
69975
70206
  try {
69976
70207
  let settings = {};
69977
- if (existsSync9(settingsPath)) {
70208
+ if (existsSync10(settingsPath)) {
69978
70209
  try {
69979
- settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
70210
+ settings = JSON.parse(readFileSync8(settingsPath, "utf-8"));
69980
70211
  } catch {
69981
70212
  settings = {};
69982
70213
  }
@@ -69987,19 +70218,19 @@ function registerInitCommand(program2) {
69987
70218
  if (alreadyHasMementos) {
69988
70219
  hookAlreadyInstalled = true;
69989
70220
  } else {
69990
- if (!existsSync9(hooksDir)) {
70221
+ if (!existsSync10(hooksDir)) {
69991
70222
  mkdirSync6(hooksDir, { recursive: true });
69992
70223
  }
69993
- if (!existsSync9(hookDest)) {
70224
+ if (!existsSync10(hookDest)) {
69994
70225
  const packageDir = dirname7(dirname7(fileURLToPath4(import.meta.url)));
69995
70226
  const candidatePaths = [
69996
- join10(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
69997
- join10(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
69998
- join10(home, ".bun", "install", "global", "node_modules", "@hasna", "mementos", "scripts", "hooks", "claude-stop-hook.ts")
70227
+ join11(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
70228
+ join11(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
70229
+ join11(home, ".bun", "install", "global", "node_modules", "@hasna", "mementos", "scripts", "hooks", "claude-stop-hook.ts")
69999
70230
  ];
70000
70231
  let hookSourceFound = false;
70001
70232
  for (const src of candidatePaths) {
70002
- if (existsSync9(src)) {
70233
+ if (existsSync10(src)) {
70003
70234
  copyFileSync3(src, hookDest);
70004
70235
  hookSourceFound = true;
70005
70236
  break;
@@ -70065,7 +70296,7 @@ main().catch(() => {});
70065
70296
  if (!isMac) {
70066
70297
  console.log(chalk41.dim(` \xB7 Auto-start skipped (not macOS \u2014 platform: ${platform2})`));
70067
70298
  } else {
70068
- const plistPath = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70299
+ const plistPath = join11(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70069
70300
  const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
70070
70301
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
70071
70302
  <plist version="1.0">
@@ -70090,11 +70321,11 @@ main().catch(() => {});
70090
70321
  </plist>
70091
70322
  `;
70092
70323
  try {
70093
- if (existsSync9(plistPath)) {
70324
+ if (existsSync10(plistPath)) {
70094
70325
  autoStartAlreadyInstalled = true;
70095
70326
  } else {
70096
- const launchAgentsDir = join10(home, "Library", "LaunchAgents");
70097
- if (!existsSync9(launchAgentsDir)) {
70327
+ const launchAgentsDir = join11(home, "Library", "LaunchAgents");
70328
+ if (!existsSync10(launchAgentsDir)) {
70098
70329
  mkdirSync6(launchAgentsDir, { recursive: true });
70099
70330
  }
70100
70331
  writeFileSync4(plistPath, plistContent, "utf-8");
@@ -70110,7 +70341,7 @@ main().catch(() => {});
70110
70341
  console.log(chalk41.green(" \u2713 Auto-start configured (starts on login)"));
70111
70342
  }
70112
70343
  if (!autoStartAlreadyInstalled && !autoStartError) {
70113
- const plistPath2 = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70344
+ const plistPath2 = join11(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70114
70345
  const loadResult = await run(["launchctl", "load", plistPath2]);
70115
70346
  if (!loadResult.ok) {
70116
70347
  console.log(chalk41.dim(` \xB7 launchctl load: ${loadResult.output || "already loaded"}`));
@@ -71224,13 +71455,13 @@ function lessonTagForCli(kind) {
71224
71455
 
71225
71456
  // src/cli/brains.ts
71226
71457
  import {
71227
- existsSync as existsSync11,
71458
+ existsSync as existsSync12,
71228
71459
  mkdirSync as mkdirSync8,
71229
71460
  writeFileSync as writeFileSync6,
71230
71461
  readdirSync as readdirSync4
71231
71462
  } from "fs";
71232
- import { homedir as homedir7 } from "os";
71233
- import { join as join12 } from "path";
71463
+ import { homedir as homedir8 } from "os";
71464
+ import { join as join13 } from "path";
71234
71465
  import chalk43 from "chalk";
71235
71466
 
71236
71467
  // src/lib/gatherer.ts
@@ -71307,24 +71538,24 @@ var gatherTrainingData = async (options = {}) => {
71307
71538
  };
71308
71539
 
71309
71540
  // src/lib/model-config.ts
71310
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
71311
- import { homedir as homedir6 } from "os";
71312
- import { join as join11 } from "path";
71541
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
71542
+ import { homedir as homedir7 } from "os";
71543
+ import { join as join12 } from "path";
71313
71544
  var DEFAULT_MODEL = "gpt-4o-mini";
71314
- var CONFIG_DIR = join11(homedir6(), ".hasna", "mementos");
71315
- var CONFIG_PATH = join11(CONFIG_DIR, "config.json");
71545
+ var CONFIG_DIR = join12(homedir7(), ".hasna", "mementos");
71546
+ var CONFIG_PATH = join12(CONFIG_DIR, "config.json");
71316
71547
  function readConfig() {
71317
- if (!existsSync10(CONFIG_PATH))
71548
+ if (!existsSync11(CONFIG_PATH))
71318
71549
  return {};
71319
71550
  try {
71320
- const raw = readFileSync8(CONFIG_PATH, "utf-8");
71551
+ const raw = readFileSync9(CONFIG_PATH, "utf-8");
71321
71552
  return JSON.parse(raw);
71322
71553
  } catch {
71323
71554
  return {};
71324
71555
  }
71325
71556
  }
71326
71557
  function writeConfig(config2) {
71327
- if (!existsSync10(CONFIG_DIR)) {
71558
+ if (!existsSync11(CONFIG_DIR)) {
71328
71559
  mkdirSync7(CONFIG_DIR, { recursive: true });
71329
71560
  }
71330
71561
  writeFileSync5(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
@@ -71372,12 +71603,12 @@ function makeBrainsCommand() {
71372
71603
  limit: opts.limit,
71373
71604
  since
71374
71605
  });
71375
- const outputDir = opts.output ?? join12(homedir7(), ".hasna", "mementos", "training");
71376
- if (!existsSync11(outputDir)) {
71606
+ const outputDir = opts.output ?? join13(homedir8(), ".hasna", "mementos", "training");
71607
+ if (!existsSync12(outputDir)) {
71377
71608
  mkdirSync8(outputDir, { recursive: true });
71378
71609
  }
71379
71610
  const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
71380
- const outputPath = join12(outputDir, `mementos-training-${timestamp2}.jsonl`);
71611
+ const outputPath = join13(outputDir, `mementos-training-${timestamp2}.jsonl`);
71381
71612
  const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
71382
71613
  `);
71383
71614
  writeFileSync6(outputPath, jsonl + `
@@ -71401,8 +71632,8 @@ function makeBrainsCommand() {
71401
71632
  try {
71402
71633
  let datasetPath = opts.dataset;
71403
71634
  if (!datasetPath) {
71404
- const trainingDir = join12(homedir7(), ".hasna", "mementos", "training");
71405
- if (!existsSync11(trainingDir)) {
71635
+ const trainingDir = join13(homedir8(), ".hasna", "mementos", "training");
71636
+ if (!existsSync12(trainingDir)) {
71406
71637
  printError("No training data found. Run `mementos brains gather` first.");
71407
71638
  process.exit(1);
71408
71639
  }
@@ -71412,9 +71643,9 @@ function makeBrainsCommand() {
71412
71643
  printError("No JSONL training files found. Run `mementos brains gather` first.");
71413
71644
  process.exit(1);
71414
71645
  }
71415
- datasetPath = join12(trainingDir, latestFile);
71646
+ datasetPath = join13(trainingDir, latestFile);
71416
71647
  }
71417
- if (!datasetPath || !existsSync11(datasetPath)) {
71648
+ if (!datasetPath || !existsSync12(datasetPath)) {
71418
71649
  printError(`Dataset file not found: ${datasetPath ?? "(unresolved)"}`);
71419
71650
  process.exit(1);
71420
71651
  }
@@ -71540,8 +71771,8 @@ function registerAllCommands(program2) {
71540
71771
  // src/cli/index.tsx
71541
71772
  function getPackageVersion2() {
71542
71773
  try {
71543
- const pkgPath = join13(dirname8(fileURLToPath5(import.meta.url)), "..", "..", "package.json");
71544
- const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
71774
+ const pkgPath = join14(dirname8(fileURLToPath5(import.meta.url)), "..", "..", "package.json");
71775
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
71545
71776
  return pkg.version || "0.0.0";
71546
71777
  } catch {
71547
71778
  return "0.0.0";