@hasna/mementos 0.14.84 → 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 (556) hide show
  1. package/bun.lock +63 -4
  2. package/dist/cli/index.js +769 -261
  3. package/dist/diagnostics/historical-project-registration-receipt.js +1675 -0
  4. package/dist/index.js +343 -85
  5. package/dist/mcp/index.js +419 -99
  6. package/dist/pg-sync-worker.js +7 -5
  7. package/dist/project-registration.js +309 -68
  8. package/dist/sdk/index.js +123 -30
  9. package/dist/server/index.js +677 -317
  10. package/dist/storage.js +63 -26
  11. package/hasna.contract.json +5 -4
  12. package/package.json +6 -4
  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 -119
  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 -107
  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 -137
  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/generated/storage-kit/backend.d.ts +0 -20
  188. package/dist/generated/storage-kit/backend.d.ts.map +0 -1
  189. package/dist/generated/storage-kit/health.d.ts +0 -20
  190. package/dist/generated/storage-kit/health.d.ts.map +0 -1
  191. package/dist/generated/storage-kit/index.d.ts +0 -8
  192. package/dist/generated/storage-kit/index.d.ts.map +0 -1
  193. package/dist/generated/storage-kit/migrations.d.ts +0 -48
  194. package/dist/generated/storage-kit/migrations.d.ts.map +0 -1
  195. package/dist/generated/storage-kit/own.d.ts +0 -11
  196. package/dist/generated/storage-kit/own.d.ts.map +0 -1
  197. package/dist/generated/storage-kit/pool.d.ts +0 -35
  198. package/dist/generated/storage-kit/pool.d.ts.map +0 -1
  199. package/dist/generated/storage-kit/query.d.ts +0 -36
  200. package/dist/generated/storage-kit/query.d.ts.map +0 -1
  201. package/dist/generated/storage-kit/tls.d.ts +0 -53
  202. package/dist/generated/storage-kit/tls.d.ts.map +0 -1
  203. package/dist/index.d.ts +0 -45
  204. package/dist/index.d.ts.map +0 -1
  205. package/dist/lib/activation-matcher.d.ts +0 -17
  206. package/dist/lib/activation-matcher.d.ts.map +0 -1
  207. package/dist/lib/asmr/categorizer.d.ts +0 -31
  208. package/dist/lib/asmr/categorizer.d.ts.map +0 -1
  209. package/dist/lib/asmr/context-agent.d.ts +0 -4
  210. package/dist/lib/asmr/context-agent.d.ts.map +0 -1
  211. package/dist/lib/asmr/ensemble.d.ts +0 -23
  212. package/dist/lib/asmr/ensemble.d.ts.map +0 -1
  213. package/dist/lib/asmr/fact-agent.d.ts +0 -4
  214. package/dist/lib/asmr/fact-agent.d.ts.map +0 -1
  215. package/dist/lib/asmr/index.d.ts +0 -7
  216. package/dist/lib/asmr/index.d.ts.map +0 -1
  217. package/dist/lib/asmr/orchestrator.d.ts +0 -4
  218. package/dist/lib/asmr/orchestrator.d.ts.map +0 -1
  219. package/dist/lib/asmr/recall.d.ts +0 -3
  220. package/dist/lib/asmr/recall.d.ts.map +0 -1
  221. package/dist/lib/asmr/temporal-agent.d.ts +0 -4
  222. package/dist/lib/asmr/temporal-agent.d.ts.map +0 -1
  223. package/dist/lib/asmr/types.d.ts +0 -27
  224. package/dist/lib/asmr/types.d.ts.map +0 -1
  225. package/dist/lib/auto-inject-orchestrator.d.ts +0 -57
  226. package/dist/lib/auto-inject-orchestrator.d.ts.map +0 -1
  227. package/dist/lib/auto-memory-queue.d.ts +0 -48
  228. package/dist/lib/auto-memory-queue.d.ts.map +0 -1
  229. package/dist/lib/auto-memory.d.ts +0 -19
  230. package/dist/lib/auto-memory.d.ts.map +0 -1
  231. package/dist/lib/bench.d.ts +0 -20
  232. package/dist/lib/bench.d.ts.map +0 -1
  233. package/dist/lib/built-in-hooks.d.ts +0 -12
  234. package/dist/lib/built-in-hooks.d.ts.map +0 -1
  235. package/dist/lib/channel-pusher.d.ts +0 -39
  236. package/dist/lib/channel-pusher.d.ts.map +0 -1
  237. package/dist/lib/config.d.ts +0 -9
  238. package/dist/lib/config.d.ts.map +0 -1
  239. package/dist/lib/connectors/files.d.ts +0 -8
  240. package/dist/lib/connectors/files.d.ts.map +0 -1
  241. package/dist/lib/connectors/github.d.ts +0 -7
  242. package/dist/lib/connectors/github.d.ts.map +0 -1
  243. package/dist/lib/connectors/index.d.ts +0 -12
  244. package/dist/lib/connectors/index.d.ts.map +0 -1
  245. package/dist/lib/connectors/notion.d.ts +0 -7
  246. package/dist/lib/connectors/notion.d.ts.map +0 -1
  247. package/dist/lib/connectors/types.d.ts +0 -27
  248. package/dist/lib/connectors/types.d.ts.map +0 -1
  249. package/dist/lib/consolidation.d.ts +0 -52
  250. package/dist/lib/consolidation.d.ts.map +0 -1
  251. package/dist/lib/context-extractor.d.ts +0 -14
  252. package/dist/lib/context-extractor.d.ts.map +0 -1
  253. package/dist/lib/context.d.ts +0 -36
  254. package/dist/lib/context.d.ts.map +0 -1
  255. package/dist/lib/contradiction.d.ts +0 -50
  256. package/dist/lib/contradiction.d.ts.map +0 -1
  257. package/dist/lib/decay.d.ts +0 -35
  258. package/dist/lib/decay.d.ts.map +0 -1
  259. package/dist/lib/dedup.d.ts +0 -33
  260. package/dist/lib/dedup.d.ts.map +0 -1
  261. package/dist/lib/duration.d.ts +0 -28
  262. package/dist/lib/duration.d.ts.map +0 -1
  263. package/dist/lib/embeddings.d.ts +0 -20
  264. package/dist/lib/embeddings.d.ts.map +0 -1
  265. package/dist/lib/enum-validation.d.ts +0 -20
  266. package/dist/lib/enum-validation.d.ts.map +0 -1
  267. package/dist/lib/export-v1.d.ts +0 -30
  268. package/dist/lib/export-v1.d.ts.map +0 -1
  269. package/dist/lib/extractor.d.ts +0 -9
  270. package/dist/lib/extractor.d.ts.map +0 -1
  271. package/dist/lib/extractors/audio.d.ts +0 -8
  272. package/dist/lib/extractors/audio.d.ts.map +0 -1
  273. package/dist/lib/extractors/index.d.ts +0 -12
  274. package/dist/lib/extractors/index.d.ts.map +0 -1
  275. package/dist/lib/extractors/ocr.d.ts +0 -7
  276. package/dist/lib/extractors/ocr.d.ts.map +0 -1
  277. package/dist/lib/extractors/pdf.d.ts +0 -7
  278. package/dist/lib/extractors/pdf.d.ts.map +0 -1
  279. package/dist/lib/extractors/types.d.ts +0 -12
  280. package/dist/lib/extractors/types.d.ts.map +0 -1
  281. package/dist/lib/file-deps.d.ts +0 -27
  282. package/dist/lib/file-deps.d.ts.map +0 -1
  283. package/dist/lib/focus.d.ts +0 -58
  284. package/dist/lib/focus.d.ts.map +0 -1
  285. package/dist/lib/gatherer.d.ts +0 -16
  286. package/dist/lib/gatherer.d.ts.map +0 -1
  287. package/dist/lib/gdpr.d.ts +0 -39
  288. package/dist/lib/gdpr.d.ts.map +0 -1
  289. package/dist/lib/hooks.d.ts +0 -50
  290. package/dist/lib/hooks.d.ts.map +0 -1
  291. package/dist/lib/importers/index.d.ts +0 -38
  292. package/dist/lib/importers/index.d.ts.map +0 -1
  293. package/dist/lib/injector.d.ts +0 -89
  294. package/dist/lib/injector.d.ts.map +0 -1
  295. package/dist/lib/machine-visibility.d.ts +0 -6
  296. package/dist/lib/machine-visibility.d.ts.map +0 -1
  297. package/dist/lib/matryoshka.d.ts +0 -50
  298. package/dist/lib/matryoshka.d.ts.map +0 -1
  299. package/dist/lib/memory-lock.d.ts +0 -58
  300. package/dist/lib/memory-lock.d.ts.map +0 -1
  301. package/dist/lib/model-config.d.ts +0 -14
  302. package/dist/lib/model-config.d.ts.map +0 -1
  303. package/dist/lib/open-sessions-connector.d.ts +0 -60
  304. package/dist/lib/open-sessions-connector.d.ts.map +0 -1
  305. package/dist/lib/package-version.d.ts +0 -3
  306. package/dist/lib/package-version.d.ts.map +0 -1
  307. package/dist/lib/poisoning.d.ts +0 -19
  308. package/dist/lib/poisoning.d.ts.map +0 -1
  309. package/dist/lib/poll.d.ts +0 -17
  310. package/dist/lib/poll.d.ts.map +0 -1
  311. package/dist/lib/procedural-extractor.d.ts +0 -21
  312. package/dist/lib/procedural-extractor.d.ts.map +0 -1
  313. package/dist/lib/profile-sync.d.ts +0 -20
  314. package/dist/lib/profile-sync.d.ts.map +0 -1
  315. package/dist/lib/profile-synthesizer.d.ts +0 -20
  316. package/dist/lib/profile-synthesizer.d.ts.map +0 -1
  317. package/dist/lib/project-detect.d.ts +0 -18
  318. package/dist/lib/project-detect.d.ts.map +0 -1
  319. package/dist/lib/project-panel.d.ts +0 -7
  320. package/dist/lib/project-panel.d.ts.map +0 -1
  321. package/dist/lib/providers/anthropic.d.ts +0 -21
  322. package/dist/lib/providers/anthropic.d.ts.map +0 -1
  323. package/dist/lib/providers/base.d.ts +0 -96
  324. package/dist/lib/providers/base.d.ts.map +0 -1
  325. package/dist/lib/providers/cerebras.d.ts +0 -20
  326. package/dist/lib/providers/cerebras.d.ts.map +0 -1
  327. package/dist/lib/providers/grok.d.ts +0 -19
  328. package/dist/lib/providers/grok.d.ts.map +0 -1
  329. package/dist/lib/providers/index.d.ts +0 -7
  330. package/dist/lib/providers/index.d.ts.map +0 -1
  331. package/dist/lib/providers/openai-compat.d.ts +0 -18
  332. package/dist/lib/providers/openai-compat.d.ts.map +0 -1
  333. package/dist/lib/providers/openai.d.ts +0 -20
  334. package/dist/lib/providers/openai.d.ts.map +0 -1
  335. package/dist/lib/providers/registry.d.ts +0 -38
  336. package/dist/lib/providers/registry.d.ts.map +0 -1
  337. package/dist/lib/quality.d.ts +0 -16
  338. package/dist/lib/quality.d.ts.map +0 -1
  339. package/dist/lib/redact.d.ts +0 -10
  340. package/dist/lib/redact.d.ts.map +0 -1
  341. package/dist/lib/reflection.d.ts +0 -83
  342. package/dist/lib/reflection.d.ts.map +0 -1
  343. package/dist/lib/retention.d.ts +0 -17
  344. package/dist/lib/retention.d.ts.map +0 -1
  345. package/dist/lib/retired-storage-mode.d.ts +0 -11
  346. package/dist/lib/retired-storage-mode.d.ts.map +0 -1
  347. package/dist/lib/search.d.ts +0 -52
  348. package/dist/lib/search.d.ts.map +0 -1
  349. package/dist/lib/session-auto-resolve.d.ts +0 -28
  350. package/dist/lib/session-auto-resolve.d.ts.map +0 -1
  351. package/dist/lib/session-processor.d.ts +0 -38
  352. package/dist/lib/session-processor.d.ts.map +0 -1
  353. package/dist/lib/session-queue.d.ts +0 -28
  354. package/dist/lib/session-queue.d.ts.map +0 -1
  355. package/dist/lib/session-registry.d.ts +0 -47
  356. package/dist/lib/session-registry.d.ts.map +0 -1
  357. package/dist/lib/session-start-briefing.d.ts +0 -10
  358. package/dist/lib/session-start-briefing.d.ts.map +0 -1
  359. package/dist/lib/session-watcher.d.ts +0 -30
  360. package/dist/lib/session-watcher.d.ts.map +0 -1
  361. package/dist/lib/storage-sync.d.ts +0 -45
  362. package/dist/lib/storage-sync.d.ts.map +0 -1
  363. package/dist/lib/sync.d.ts +0 -10
  364. package/dist/lib/sync.d.ts.map +0 -1
  365. package/dist/lib/synthesis/corpus-builder.d.ts +0 -30
  366. package/dist/lib/synthesis/corpus-builder.d.ts.map +0 -1
  367. package/dist/lib/synthesis/executor.d.ts +0 -14
  368. package/dist/lib/synthesis/executor.d.ts.map +0 -1
  369. package/dist/lib/synthesis/index.d.ts +0 -37
  370. package/dist/lib/synthesis/index.d.ts.map +0 -1
  371. package/dist/lib/synthesis/llm-analyzer.d.ts +0 -18
  372. package/dist/lib/synthesis/llm-analyzer.d.ts.map +0 -1
  373. package/dist/lib/synthesis/metrics.d.ts +0 -13
  374. package/dist/lib/synthesis/metrics.d.ts.map +0 -1
  375. package/dist/lib/synthesis/scheduler.d.ts +0 -18
  376. package/dist/lib/synthesis/scheduler.d.ts.map +0 -1
  377. package/dist/lib/synthesis/validator.d.ts +0 -19
  378. package/dist/lib/synthesis/validator.d.ts.map +0 -1
  379. package/dist/lib/task-runner.d.ts +0 -37
  380. package/dist/lib/task-runner.d.ts.map +0 -1
  381. package/dist/lib/tool-lesson-extractor.d.ts +0 -24
  382. package/dist/lib/tool-lesson-extractor.d.ts.map +0 -1
  383. package/dist/lib/tool-memory-synthesizer.d.ts +0 -28
  384. package/dist/lib/tool-memory-synthesizer.d.ts.map +0 -1
  385. package/dist/lib/topic-clusterer.d.ts +0 -21
  386. package/dist/lib/topic-clusterer.d.ts.map +0 -1
  387. package/dist/lib/when-to-use-generator.d.ts +0 -22
  388. package/dist/lib/when-to-use-generator.d.ts.map +0 -1
  389. package/dist/mcp/http.d.ts +0 -17
  390. package/dist/mcp/http.d.ts.map +0 -1
  391. package/dist/mcp/index.d.ts +0 -6
  392. package/dist/mcp/index.d.ts.map +0 -1
  393. package/dist/mcp/memory-broadcast.d.ts +0 -12
  394. package/dist/mcp/memory-broadcast.d.ts.map +0 -1
  395. package/dist/mcp/tools/agent-tools.d.ts +0 -3
  396. package/dist/mcp/tools/agent-tools.d.ts.map +0 -1
  397. package/dist/mcp/tools/auto-memory-tools.d.ts +0 -5
  398. package/dist/mcp/tools/auto-memory-tools.d.ts.map +0 -1
  399. package/dist/mcp/tools/bulk-tools.d.ts +0 -3
  400. package/dist/mcp/tools/bulk-tools.d.ts.map +0 -1
  401. package/dist/mcp/tools/consolidation-tools.d.ts +0 -3
  402. package/dist/mcp/tools/consolidation-tools.d.ts.map +0 -1
  403. package/dist/mcp/tools/focus-tools.d.ts +0 -3
  404. package/dist/mcp/tools/focus-tools.d.ts.map +0 -1
  405. package/dist/mcp/tools/graph-entity-tools.d.ts +0 -3
  406. package/dist/mcp/tools/graph-entity-tools.d.ts.map +0 -1
  407. package/dist/mcp/tools/graph-query-tools.d.ts +0 -3
  408. package/dist/mcp/tools/graph-query-tools.d.ts.map +0 -1
  409. package/dist/mcp/tools/graph-relation-tools.d.ts +0 -3
  410. package/dist/mcp/tools/graph-relation-tools.d.ts.map +0 -1
  411. package/dist/mcp/tools/graph-tools.d.ts +0 -3
  412. package/dist/mcp/tools/graph-tools.d.ts.map +0 -1
  413. package/dist/mcp/tools/graph-utils.d.ts +0 -5
  414. package/dist/mcp/tools/graph-utils.d.ts.map +0 -1
  415. package/dist/mcp/tools/hook-tools.d.ts +0 -3
  416. package/dist/mcp/tools/hook-tools.d.ts.map +0 -1
  417. package/dist/mcp/tools/lock-tools.d.ts +0 -3
  418. package/dist/mcp/tools/lock-tools.d.ts.map +0 -1
  419. package/dist/mcp/tools/memory-audit.d.ts +0 -3
  420. package/dist/mcp/tools/memory-audit.d.ts.map +0 -1
  421. package/dist/mcp/tools/memory-crud.d.ts +0 -3
  422. package/dist/mcp/tools/memory-crud.d.ts.map +0 -1
  423. package/dist/mcp/tools/memory-health.d.ts +0 -3
  424. package/dist/mcp/tools/memory-health.d.ts.map +0 -1
  425. package/dist/mcp/tools/memory-history.d.ts +0 -3
  426. package/dist/mcp/tools/memory-history.d.ts.map +0 -1
  427. package/dist/mcp/tools/memory-inject.d.ts +0 -3
  428. package/dist/mcp/tools/memory-inject.d.ts.map +0 -1
  429. package/dist/mcp/tools/memory-io.d.ts +0 -3
  430. package/dist/mcp/tools/memory-io.d.ts.map +0 -1
  431. package/dist/mcp/tools/memory-lifecycle.d.ts +0 -3
  432. package/dist/mcp/tools/memory-lifecycle.d.ts.map +0 -1
  433. package/dist/mcp/tools/memory-search.d.ts +0 -3
  434. package/dist/mcp/tools/memory-search.d.ts.map +0 -1
  435. package/dist/mcp/tools/memory-stats.d.ts +0 -3
  436. package/dist/mcp/tools/memory-stats.d.ts.map +0 -1
  437. package/dist/mcp/tools/memory-tools.d.ts +0 -17
  438. package/dist/mcp/tools/memory-tools.d.ts.map +0 -1
  439. package/dist/mcp/tools/memory-utils.d.ts +0 -27
  440. package/dist/mcp/tools/memory-utils.d.ts.map +0 -1
  441. package/dist/mcp/tools/memory-validation.d.ts +0 -3
  442. package/dist/mcp/tools/memory-validation.d.ts.map +0 -1
  443. package/dist/mcp/tools/project-tools.d.ts +0 -3
  444. package/dist/mcp/tools/project-tools.d.ts.map +0 -1
  445. package/dist/mcp/tools/session-tools.d.ts +0 -3
  446. package/dist/mcp/tools/session-tools.d.ts.map +0 -1
  447. package/dist/mcp/tools/storage-tools.d.ts +0 -3
  448. package/dist/mcp/tools/storage-tools.d.ts.map +0 -1
  449. package/dist/mcp/tools/synthesis-tools.d.ts +0 -3
  450. package/dist/mcp/tools/synthesis-tools.d.ts.map +0 -1
  451. package/dist/mcp/tools/system-tools-events.d.ts +0 -3
  452. package/dist/mcp/tools/system-tools-events.d.ts.map +0 -1
  453. package/dist/mcp/tools/system-tools-memory-admin.d.ts +0 -3
  454. package/dist/mcp/tools/system-tools-memory-admin.d.ts.map +0 -1
  455. package/dist/mcp/tools/system-tools-shared.d.ts +0 -23
  456. package/dist/mcp/tools/system-tools-shared.d.ts.map +0 -1
  457. package/dist/mcp/tools/system-tools.d.ts +0 -3
  458. package/dist/mcp/tools/system-tools.d.ts.map +0 -1
  459. package/dist/mcp/tools/tool-registry.d.ts +0 -30
  460. package/dist/mcp/tools/tool-registry.d.ts.map +0 -1
  461. package/dist/mcp/tools/utility-tools.d.ts +0 -3
  462. package/dist/mcp/tools/utility-tools.d.ts.map +0 -1
  463. package/dist/memory-project-link/index.d.ts +0 -2
  464. package/dist/memory-project-link/index.d.ts.map +0 -1
  465. package/dist/memory-project-link/schema.d.ts +0 -5
  466. package/dist/memory-project-link/schema.d.ts.map +0 -1
  467. package/dist/pg-sync-worker.d.ts +0 -2
  468. package/dist/pg-sync-worker.d.ts.map +0 -1
  469. package/dist/project-registration/authority.d.ts +0 -43
  470. package/dist/project-registration/authority.d.ts.map +0 -1
  471. package/dist/project-registration/http.d.ts +0 -32
  472. package/dist/project-registration/http.d.ts.map +0 -1
  473. package/dist/project-registration/identity.d.ts +0 -20
  474. package/dist/project-registration/identity.d.ts.map +0 -1
  475. package/dist/project-registration/index.d.ts +0 -11
  476. package/dist/project-registration/index.d.ts.map +0 -1
  477. package/dist/project-registration/project-references.d.ts +0 -71
  478. package/dist/project-registration/project-references.d.ts.map +0 -1
  479. package/dist/project-registration/project-resources.d.ts +0 -22
  480. package/dist/project-registration/project-resources.d.ts.map +0 -1
  481. package/dist/project-registration/schema.d.ts +0 -5
  482. package/dist/project-registration/schema.d.ts.map +0 -1
  483. package/dist/project-registration/types.d.ts +0 -293
  484. package/dist/project-registration/types.d.ts.map +0 -1
  485. package/dist/project-registration.d.ts +0 -2
  486. package/dist/project-registration.d.ts.map +0 -1
  487. package/dist/sdk/index.d.ts +0 -971
  488. package/dist/sdk/index.d.ts.map +0 -1
  489. package/dist/server/auth.d.ts +0 -11
  490. package/dist/server/auth.d.ts.map +0 -1
  491. package/dist/server/helpers.d.ts +0 -22
  492. package/dist/server/helpers.d.ts.map +0 -1
  493. package/dist/server/index.d.ts +0 -14
  494. package/dist/server/index.d.ts.map +0 -1
  495. package/dist/server/openapi.d.ts +0 -2
  496. package/dist/server/openapi.d.ts.map +0 -1
  497. package/dist/server/router.d.ts +0 -17
  498. package/dist/server/router.d.ts.map +0 -1
  499. package/dist/server/routes/agents.d.ts +0 -2
  500. package/dist/server/routes/agents.d.ts.map +0 -1
  501. package/dist/server/routes/entities.d.ts +0 -2
  502. package/dist/server/routes/entities.d.ts.map +0 -1
  503. package/dist/server/routes/memories-bulk.d.ts +0 -2
  504. package/dist/server/routes/memories-bulk.d.ts.map +0 -1
  505. package/dist/server/routes/memories-crud.d.ts +0 -2
  506. package/dist/server/routes/memories-crud.d.ts.map +0 -1
  507. package/dist/server/routes/memories-io.d.ts +0 -2
  508. package/dist/server/routes/memories-io.d.ts.map +0 -1
  509. package/dist/server/routes/memories-misc.d.ts +0 -2
  510. package/dist/server/routes/memories-misc.d.ts.map +0 -1
  511. package/dist/server/routes/memories-search.d.ts +0 -2
  512. package/dist/server/routes/memories-search.d.ts.map +0 -1
  513. package/dist/server/routes/memories-stats.d.ts +0 -2
  514. package/dist/server/routes/memories-stats.d.ts.map +0 -1
  515. package/dist/server/routes/memories.d.ts +0 -19
  516. package/dist/server/routes/memories.d.ts.map +0 -1
  517. package/dist/server/routes/memory-project-link.d.ts +0 -2
  518. package/dist/server/routes/memory-project-link.d.ts.map +0 -1
  519. package/dist/server/routes/project-registration.d.ts +0 -2
  520. package/dist/server/routes/project-registration.d.ts.map +0 -1
  521. package/dist/server/routes/projects.d.ts +0 -2
  522. package/dist/server/routes/projects.d.ts.map +0 -1
  523. package/dist/server/routes/system-auto-memory.d.ts +0 -2
  524. package/dist/server/routes/system-auto-memory.d.ts.map +0 -1
  525. package/dist/server/routes/system-chain.d.ts +0 -2
  526. package/dist/server/routes/system-chain.d.ts.map +0 -1
  527. package/dist/server/routes/system-consolidation.d.ts +0 -2
  528. package/dist/server/routes/system-consolidation.d.ts.map +0 -1
  529. package/dist/server/routes/system-hooks.d.ts +0 -2
  530. package/dist/server/routes/system-hooks.d.ts.map +0 -1
  531. package/dist/server/routes/system-sessions.d.ts +0 -2
  532. package/dist/server/routes/system-sessions.d.ts.map +0 -1
  533. package/dist/server/routes/system-subscriptions.d.ts +0 -2
  534. package/dist/server/routes/system-subscriptions.d.ts.map +0 -1
  535. package/dist/server/routes/system-synthesis.d.ts +0 -2
  536. package/dist/server/routes/system-synthesis.d.ts.map +0 -1
  537. package/dist/server/routes/system-tools.d.ts +0 -2
  538. package/dist/server/routes/system-tools.d.ts.map +0 -1
  539. package/dist/server/routes/system.d.ts +0 -2
  540. package/dist/server/routes/system.d.ts.map +0 -1
  541. package/dist/server/routes/tasks.d.ts +0 -2
  542. package/dist/server/routes/tasks.d.ts.map +0 -1
  543. package/dist/storage.d.ts +0 -266
  544. package/dist/storage.d.ts.map +0 -1
  545. package/dist/test-support/preload-local-store.d.ts +0 -2
  546. package/dist/test-support/preload-local-store.d.ts.map +0 -1
  547. package/dist/test-support/project-authority-identity.d.ts +0 -8
  548. package/dist/test-support/project-authority-identity.d.ts.map +0 -1
  549. package/dist/test-support/store-isolation.d.ts +0 -108
  550. package/dist/test-support/store-isolation.d.ts.map +0 -1
  551. package/dist/test-support/strip-ansi.d.ts +0 -3
  552. package/dist/test-support/strip-ansi.d.ts.map +0 -1
  553. package/dist/types/hooks.d.ts +0 -136
  554. package/dist/types/hooks.d.ts.map +0 -1
  555. package/dist/types/index.d.ts +0 -472
  556. package/dist/types/index.d.ts.map +0 -1
package/dist/cli/index.js CHANGED
@@ -1011,7 +1011,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1011
1011
  this._exitCallback = (err) => {
1012
1012
  if (err.code !== "commander.executeSubCommandAsync") {
1013
1013
  throw err;
1014
- } else {}
1014
+ }
1015
1015
  };
1016
1016
  }
1017
1017
  return this;
@@ -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)
@@ -3171,7 +3208,16 @@ x-api-key: ${cfg.apiKey}
3171
3208
  function apiJson(method, path, body, options) {
3172
3209
  const raw = apiRequestRaw(method, path, body);
3173
3210
  if (raw.status >= 200 && raw.status < 300) {
3174
- const data = raw.body.trim() ? JSON.parse(raw.body) : undefined;
3211
+ let data;
3212
+ if (raw.body.trim()) {
3213
+ try {
3214
+ data = JSON.parse(raw.body);
3215
+ } catch (e) {
3216
+ throw new ApiRequestError(`mementos cloud ${method} ${path} returned status ${raw.status} with a body that is not valid JSON (${e instanceof Error ? e.message : String(e)}) \u2014 the response is truncated or the server is unhealthy`, raw.status, raw.body.slice(0, 500));
3217
+ }
3218
+ } else {
3219
+ data = undefined;
3220
+ }
3175
3221
  return { status: raw.status, data };
3176
3222
  }
3177
3223
  if (raw.status === 404 && options?.allow404) {
@@ -5258,8 +5304,12 @@ __export(exports_memories, {
5258
5304
  updateMemory: () => updateMemory,
5259
5305
  touchMemory: () => touchMemory,
5260
5306
  semanticSearch: () => semanticSearch,
5307
+ reservedAgentIdViolation: () => reservedAgentIdViolation,
5261
5308
  parseMemoryRow: () => parseMemoryRow,
5309
+ listMemoryHistoryPage: () => listMemoryHistoryPage,
5262
5310
  listMemoryHistory: () => listMemoryHistory,
5311
+ listMemoriesPage: () => listMemoriesPage,
5312
+ listMemoriesBounded: () => listMemoriesBounded,
5263
5313
  listMemories: () => listMemories,
5264
5314
  listLowTrustMemories: () => listLowTrustMemories,
5265
5315
  indexMemoryEmbedding: () => indexMemoryEmbedding,
@@ -5273,6 +5323,8 @@ __export(exports_memories, {
5273
5323
  getMemoriesByKey: () => getMemoriesByKey,
5274
5324
  deleteMemory: () => deleteMemory,
5275
5325
  createMemory: () => createMemory,
5326
+ countMemoryHistory: () => countMemoryHistory,
5327
+ countMemories: () => countMemories,
5276
5328
  cleanExpiredMemories: () => cleanExpiredMemories,
5277
5329
  bulkUpsertMemories: () => bulkUpsertMemories,
5278
5330
  bulkDeleteMemories: () => bulkDeleteMemories
@@ -5324,7 +5376,20 @@ function parseMemoryRow(row) {
5324
5376
  accessed_at: row["accessed_at"] || null
5325
5377
  };
5326
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
+ }
5327
5388
  function createMemory(input, dedupeMode = "merge", db) {
5389
+ const reservedViolation = reservedAgentIdViolation(input.agent_id);
5390
+ if (reservedViolation) {
5391
+ throw new Error(reservedViolation);
5392
+ }
5328
5393
  if (!db && isApiMode()) {
5329
5394
  const { status, data } = apiJson("POST", "/memories", { ...input, dedupe: dedupeMode });
5330
5395
  if (!data || !data.id) {
@@ -5374,7 +5439,8 @@ function createMemory(input, dedupeMode = "merge", db) {
5374
5439
  importance = ?, metadata = ?, expires_at = ?,
5375
5440
  when_to_use = ?,
5376
5441
  pinned = COALESCE(pinned, 0),
5377
- version = version + 1, updated_at = ?
5442
+ version = version + 1, updated_at = ?,
5443
+ updated_by_agent = ?
5378
5444
  WHERE id = ?`, [
5379
5445
  safeValue,
5380
5446
  input.category || "knowledge",
@@ -5385,6 +5451,7 @@ function createMemory(input, dedupeMode = "merge", db) {
5385
5451
  expiresAt,
5386
5452
  input.when_to_use || null,
5387
5453
  timestamp,
5454
+ input.agent_id || null,
5388
5455
  existing.id
5389
5456
  ]);
5390
5457
  d.run("DELETE FROM memory_tags WHERE memory_id = ?", [existing.id]);
@@ -5489,6 +5556,12 @@ function bulkUpsertMemories(memories, db) {
5489
5556
  errors.push(`Rejected "${key}": ${formatEnumViolation(violation)}`);
5490
5557
  continue;
5491
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
+ }
5492
5565
  const timestamp = now();
5493
5566
  let tags = [];
5494
5567
  const rawTags = mem["tags"];
@@ -5639,29 +5712,7 @@ function getMemoriesByKey(key, scope, agentId, projectId, db) {
5639
5712
  const rows = d.query(sql).all(...params);
5640
5713
  return rows.map(parseMemoryRow);
5641
5714
  }
5642
- function listMemories(filter, db) {
5643
- if (!db && isApiMode()) {
5644
- const f = filter || {};
5645
- const q = toQuery({
5646
- key: f.key,
5647
- scope: f.scope,
5648
- category: f.category,
5649
- status: f.status,
5650
- tags: f.tags,
5651
- min_importance: f.min_importance,
5652
- pinned: f.pinned,
5653
- agent_id: f.agent_id,
5654
- project_id: f.project_id,
5655
- session_id: f.session_id,
5656
- namespace: f.namespace,
5657
- as_of: f.as_of,
5658
- limit: f.limit,
5659
- offset: f.offset
5660
- });
5661
- const { data } = apiJson("GET", `/memories${q}`);
5662
- return data?.memories ?? [];
5663
- }
5664
- const d = db || getDatabase();
5715
+ function buildMemoryListConditions(filter) {
5665
5716
  const conditions = [];
5666
5717
  const params = [];
5667
5718
  if (filter) {
@@ -5773,21 +5824,114 @@ function listMemories(filter, db) {
5773
5824
  } else {
5774
5825
  conditions.push("status = 'active'");
5775
5826
  }
5827
+ return { conditions, params };
5828
+ }
5829
+ function listMemoriesPage(filter, db) {
5830
+ const f = filter || {};
5831
+ if (!db && isApiMode()) {
5832
+ const q = toQuery({
5833
+ key: f.key,
5834
+ scope: f.scope,
5835
+ category: f.category,
5836
+ status: f.status,
5837
+ tags: f.tags,
5838
+ min_importance: f.min_importance,
5839
+ pinned: f.pinned,
5840
+ agent_id: f.agent_id,
5841
+ project_id: f.project_id,
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,
5848
+ namespace: f.namespace,
5849
+ as_of: f.as_of,
5850
+ limit: f.limit,
5851
+ offset: f.offset
5852
+ });
5853
+ const { data } = apiJson("GET", `/memories${q}`);
5854
+ return {
5855
+ rows: data?.memories ?? [],
5856
+ has_more: data?.has_more,
5857
+ next_cursor: data?.next_cursor ?? null
5858
+ };
5859
+ }
5860
+ const d = db || getDatabase();
5861
+ const { conditions, params } = buildMemoryListConditions(f);
5776
5862
  let sql = "SELECT * FROM memories";
5777
5863
  if (conditions.length > 0) {
5778
5864
  sql += ` WHERE ${conditions.join(" AND ")}`;
5779
5865
  }
5780
5866
  sql += " ORDER BY importance DESC, created_at DESC";
5781
- if (filter?.limit) {
5867
+ if (f.limit) {
5782
5868
  sql += " LIMIT ?";
5783
- params.push(filter.limit);
5869
+ params.push(f.limit);
5784
5870
  }
5785
- if (filter?.offset) {
5871
+ if (f.offset) {
5786
5872
  sql += " OFFSET ?";
5787
- params.push(filter.offset);
5873
+ params.push(f.offset);
5788
5874
  }
5789
5875
  const rows = d.query(sql).all(...params);
5790
- return rows.map(parseMemoryRow);
5876
+ const parsed = rows.map(parseMemoryRow);
5877
+ const hasMore = f.limit !== undefined && parsed.length === f.limit;
5878
+ return {
5879
+ rows: parsed,
5880
+ has_more: hasMore,
5881
+ next_cursor: hasMore ? (f.offset ?? 0) + parsed.length : null
5882
+ };
5883
+ }
5884
+ function listMemories(filter, db) {
5885
+ return listMemoriesPage(filter, db).rows;
5886
+ }
5887
+ function listMemoriesBounded(filter = {}, target, db) {
5888
+ const pageSize = 1000;
5889
+ const maxPages = 1000;
5890
+ const want = target === undefined ? undefined : target + 1;
5891
+ const rows = [];
5892
+ const seenCursors = new Set;
5893
+ let cursor = filter.offset ?? 0;
5894
+ let pages = 0;
5895
+ for (;; ) {
5896
+ if (want !== undefined && rows.length >= want)
5897
+ break;
5898
+ if (++pages > maxPages) {
5899
+ throw new Error(`memories list traversal exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
5900
+ }
5901
+ const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
5902
+ const page = listMemoriesPage({ ...filter, limit, offset: cursor }, db);
5903
+ rows.push(...page.rows);
5904
+ if (page.has_more === false)
5905
+ break;
5906
+ if (page.has_more === undefined && page.rows.length < limit)
5907
+ break;
5908
+ if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
5909
+ throw new Error("memories list page claimed more results without a next cursor \u2014 aborting");
5910
+ }
5911
+ const next = page.next_cursor ?? cursor + page.rows.length;
5912
+ if (seenCursors.has(next)) {
5913
+ throw new Error("memories list traversal repeated a cursor \u2014 aborting");
5914
+ }
5915
+ seenCursors.add(next);
5916
+ cursor = next;
5917
+ }
5918
+ const hasMore = target !== undefined && rows.length > target;
5919
+ const trimmed = hasMore ? rows.slice(0, target) : rows;
5920
+ return {
5921
+ rows: trimmed,
5922
+ has_more: hasMore,
5923
+ next_cursor: hasMore ? (filter.offset ?? 0) + trimmed.length : null
5924
+ };
5925
+ }
5926
+ function countMemories(filter, db) {
5927
+ const d = db || getDatabase();
5928
+ const { conditions, params } = buildMemoryListConditions(filter);
5929
+ let sql = "SELECT COUNT(*) AS c FROM memories";
5930
+ if (conditions.length > 0) {
5931
+ sql += ` WHERE ${conditions.join(" AND ")}`;
5932
+ }
5933
+ const row = d.query(sql).get(...params);
5934
+ return row?.c ?? 0;
5791
5935
  }
5792
5936
  function getMemoryBriefing(opts, db) {
5793
5937
  const limit = opts.limit ?? 20;
@@ -5849,13 +5993,17 @@ function listLowTrustMemories(opts = {}, db) {
5849
5993
  const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
5850
5994
  return rows.map(parseMemoryRow);
5851
5995
  }
5852
- function listMemoryHistory(opts = {}, db) {
5996
+ function listMemoryHistoryPage(opts = {}, db) {
5853
5997
  const limit = opts.limit ?? 20;
5854
5998
  const offset = opts.offset ?? 0;
5855
5999
  if (!db && isApiMode()) {
5856
6000
  const q = toQuery({ limit, offset });
5857
6001
  const { data } = apiJson("GET", `/memories/history${q}`);
5858
- return data?.memories ?? [];
6002
+ return {
6003
+ rows: data?.memories ?? [],
6004
+ has_more: data?.has_more,
6005
+ next_cursor: data?.next_cursor ?? null
6006
+ };
5859
6007
  }
5860
6008
  const d = db || getDatabase();
5861
6009
  const params = [limit];
@@ -5865,7 +6013,21 @@ function listMemoryHistory(opts = {}, db) {
5865
6013
  params.push(offset);
5866
6014
  }
5867
6015
  const rows = d.query(sql).all(...params);
5868
- return rows.map(parseMemoryRow);
6016
+ const parsed = rows.map(parseMemoryRow);
6017
+ const hasMore = parsed.length === limit;
6018
+ return {
6019
+ rows: parsed,
6020
+ has_more: hasMore,
6021
+ next_cursor: hasMore ? offset + parsed.length : null
6022
+ };
6023
+ }
6024
+ function listMemoryHistory(opts = {}, db) {
6025
+ return listMemoryHistoryPage(opts, db).rows;
6026
+ }
6027
+ function countMemoryHistory(db) {
6028
+ const d = db || getDatabase();
6029
+ const row = d.query("SELECT COUNT(*) AS c FROM memories WHERE status = 'active' AND accessed_at IS NOT NULL").get();
6030
+ return row?.c ?? 0;
5869
6031
  }
5870
6032
  function getMemoryChain(sequenceGroup, projectId, db) {
5871
6033
  if (!db && isApiMode()) {
@@ -5962,20 +6124,29 @@ function updateMemory(id, input, db) {
5962
6124
  sets.push("when_to_use = ?");
5963
6125
  params.push(input.when_to_use ?? null);
5964
6126
  }
6127
+ if (input.updated_by_agent !== undefined) {
6128
+ sets.push("updated_by_agent = ?");
6129
+ params.push(input.updated_by_agent ?? null);
6130
+ }
5965
6131
  if (input.tags !== undefined) {
5966
6132
  sets.push("tags = ?");
5967
6133
  params.push(JSON.stringify(input.tags));
5968
- d.run("DELETE FROM memory_tags WHERE memory_id = ?", [memoryId]);
5969
- const insertTag = d.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
5970
- for (const tag of input.tags) {
5971
- insertTag.run(memoryId, tag);
5972
- }
5973
6134
  }
5974
6135
  params.push(memoryId);
5975
- const result = d.run(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`, params);
5976
- if (result.changes === 0) {
5977
- 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.`);
5978
- }
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
+ });
5979
6150
  const updated = getMemory(memoryId, d);
5980
6151
  if (input.value !== undefined) {
5981
6152
  try {
@@ -6146,7 +6317,7 @@ async function semanticSearch(queryText, options = {}, db) {
6146
6317
  scored.sort((a, b) => b.score - a.score);
6147
6318
  return scored.slice(0, limit);
6148
6319
  }
6149
- var RECALL_PROMOTE_THRESHOLD = 3;
6320
+ var RESERVED_AGENT_IDS, RECALL_PROMOTE_THRESHOLD = 3;
6150
6321
  var init_memories = __esm(() => {
6151
6322
  init_types();
6152
6323
  init_database();
@@ -6156,9 +6327,32 @@ var init_memories = __esm(() => {
6156
6327
  init_poisoning();
6157
6328
  init_entity_memories();
6158
6329
  init_api_mode();
6330
+ RESERVED_AGENT_IDS = new Set([
6331
+ "agent-a",
6332
+ "agent-x",
6333
+ "agent-z",
6334
+ "nonexistent-agent"
6335
+ ]);
6159
6336
  });
6160
6337
 
6161
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
+ }
6162
6356
  function parseAgentRow(row) {
6163
6357
  return {
6164
6358
  id: row["id"],
@@ -6361,17 +6555,17 @@ var init_agents = __esm(() => {
6361
6555
  });
6362
6556
 
6363
6557
  // src/lib/package-version.ts
6364
- import { readFileSync as readFileSync2 } from "fs";
6365
- 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";
6366
6560
  import { fileURLToPath as fileURLToPath2 } from "url";
6367
6561
  function getMementosPackageVersion() {
6368
6562
  const here = dirname2(fileURLToPath2(import.meta.url));
6369
6563
  for (const candidate of [
6370
- join5(here, "..", "..", "package.json"),
6371
- join5(here, "..", "package.json")
6564
+ join6(here, "..", "..", "package.json"),
6565
+ join6(here, "..", "package.json")
6372
6566
  ]) {
6373
6567
  try {
6374
- const parsed = JSON.parse(readFileSync2(candidate, "utf8"));
6568
+ const parsed = JSON.parse(readFileSync3(candidate, "utf8"));
6375
6569
  if (typeof parsed.version === "string" && parsed.version.trim())
6376
6570
  return parsed.version;
6377
6571
  } catch {}
@@ -6391,6 +6585,92 @@ var init_types2 = __esm(() => {
6391
6585
  ];
6392
6586
  });
6393
6587
 
6588
+ // src/project-registration/historical-receipt.ts
6589
+ function supportsFleetResourcesHistoricalReceiptLookup(capability) {
6590
+ return capability.authority_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.authority_id && capability.tenant_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.tenant_id && capability.corpus_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.corpus_id;
6591
+ }
6592
+ var ROOT_TENANT_ID = "adfd95c7-ee8b-52cb-ae47-4ae65dae3313", FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION, FLEET_RESOURCES_HISTORICAL_RECEIPT, FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY, FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY;
6593
+ var init_historical_receipt = __esm(() => {
6594
+ FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION = {
6595
+ authority: "mementos",
6596
+ authority_route: "mementos.project-registration.v1",
6597
+ package_version: "1.0.0-rc.3",
6598
+ authority_id: "mementos",
6599
+ tenant_id: "default",
6600
+ corpus_id: "default",
6601
+ operation_id: "op-cli-register-full",
6602
+ step_id: "mementos_project",
6603
+ resource_kind: "project",
6604
+ direction: "forward",
6605
+ target_selector: "wks_005285827590a93b70e5",
6606
+ target_id: "mm_project_f75606ef14e51fb577a15882ba0ab8ed333b2c29",
6607
+ idempotency_key: "prk_786cdc6babddeae1be8d5078d0f75322d1ea1010ac5d8a50",
6608
+ receipt_id: "mmpr_a647f9908a33bb64bf137f584202590f91b72a33",
6609
+ request_digest: "8eb0e3fee26fdb7edb8a444aeddaaedb79a84a5a36e742ae03616f62b19f5c22",
6610
+ precondition_digest: "0b6c22fcf75d835f9f27308b1a9d40e8902e48a97da370fd56df5acacfcd968e",
6611
+ result_revision: "2026-08-09T13:37:43.068Z",
6612
+ result_digest: "26fb0dd5c5e20909d3653ab0ddd8fa45e5142728e4e66d595e2419f7ed40b036",
6613
+ created_at: "2026-08-09T13:37:43.068Z",
6614
+ identity_digest: "1108dd972c90e4989036fb6ecec7dde10f54641a697bd53cfcd64017f589ace7",
6615
+ target_digest: "72789fcd60668eeb66ee068936d3afa96deadcb007228830c64b6de783b6dcef",
6616
+ operation_digest: "d7e37bfb2c0d28f8c4086c53224cd855d14694f32807b74c102b61a99963f3c0",
6617
+ idempotency_digest: "b56d8ec37efb818759cdd2ee3b58bc1401ac13384c8d64c1813bb5c198b1e376",
6618
+ receipt_digest: "52ce90c5de6817989f107d9d27e06156962a2b9c365e34e16a57aa37886501a2",
6619
+ response_digest: "2fa3ed508f5f192c18753b1205ced996340fdf02f735420d32db897fc239805c"
6620
+ };
6621
+ FLEET_RESOURCES_HISTORICAL_RECEIPT = {
6622
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id,
6623
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
6624
+ route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
6625
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
6626
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
6627
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
6628
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
6629
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
6630
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
6631
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
6632
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
6633
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
6634
+ request_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.request_digest,
6635
+ precondition_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.precondition_digest,
6636
+ outcome: "accepted",
6637
+ reason: null,
6638
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
6639
+ result_revision: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_revision,
6640
+ result_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_digest,
6641
+ duplicate_of_receipt_id: null,
6642
+ accepted_receipt_id: null,
6643
+ created_by_operation: true,
6644
+ created_at: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.created_at
6645
+ };
6646
+ FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY = {
6647
+ authority_id: "mementos",
6648
+ tenant_id: ROOT_TENANT_ID,
6649
+ corpus_id: "mementos:postgresql"
6650
+ };
6651
+ FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY = {
6652
+ source: {
6653
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
6654
+ authority_route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
6655
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
6656
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
6657
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
6658
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
6659
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
6660
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
6661
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
6662
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
6663
+ target_selector: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_selector,
6664
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
6665
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
6666
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id
6667
+ },
6668
+ destination: FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY,
6669
+ lookup_only: true,
6670
+ immutable_receipt: true
6671
+ };
6672
+ });
6673
+
6394
6674
  // src/project-registration/identity.ts
6395
6675
  function configuredValue(override, envKey) {
6396
6676
  return override?.trim() || process.env[envKey]?.trim() || null;
@@ -6417,12 +6697,13 @@ function resolveMementosProjectAuthorityIdentity(options = {}) {
6417
6697
  }
6418
6698
  function buildMementosProjectRegistrationCapability(options = {}) {
6419
6699
  const identity = resolveMementosProjectAuthorityIdentity(options);
6420
- return {
6700
+ const capability = {
6421
6701
  authority: "mementos",
6422
6702
  route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
6423
6703
  package_version: options.packageVersion ?? getMementosPackageVersion(),
6424
6704
  ...identity,
6425
6705
  supported_resources: ["project"],
6706
+ supported_historical_lookup_identities: [],
6426
6707
  conditional_create: true,
6427
6708
  immutable_receipts: true,
6428
6709
  exact_terminal_lookup: true,
@@ -6441,11 +6722,18 @@ function buildMementosProjectRegistrationCapability(options = {}) {
6441
6722
  stable_keyset_pagination: true,
6442
6723
  explicit_membership_only: true
6443
6724
  };
6725
+ if (supportsFleetResourcesHistoricalReceiptLookup(capability)) {
6726
+ capability.supported_historical_lookup_identities = [
6727
+ FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY
6728
+ ];
6729
+ }
6730
+ return capability;
6444
6731
  }
6445
6732
  var MEMENTOS_PROJECT_AUTHORITY_ENV, MementosProjectAuthorityIdentityError;
6446
6733
  var init_identity = __esm(() => {
6447
6734
  init_package_version();
6448
6735
  init_types2();
6736
+ init_historical_receipt();
6449
6737
  MEMENTOS_PROJECT_AUTHORITY_ENV = {
6450
6738
  authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
6451
6739
  tenantId: "MEMENTOS_PROJECT_TENANT_ID",
@@ -7272,6 +7560,7 @@ __export(exports_helpers, {
7272
7560
  colorImportance: () => colorImportance,
7273
7561
  colorEntityType: () => colorEntityType,
7274
7562
  colorCategory: () => colorCategory,
7563
+ collectPagedRows: () => collectPagedRows,
7275
7564
  VALID_SCOPES: () => VALID_SCOPES,
7276
7565
  VALID_CATEGORIES: () => VALID_CATEGORIES,
7277
7566
  DEFAULT_SNIPPET_LENGTH: () => DEFAULT_SNIPPET_LENGTH,
@@ -7279,13 +7568,13 @@ __export(exports_helpers, {
7279
7568
  DEFAULT_COMPACT_LIMIT: () => DEFAULT_COMPACT_LIMIT
7280
7569
  });
7281
7570
  import chalk from "chalk";
7282
- import { readFileSync as readFileSync3 } from "fs";
7283
- 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";
7284
7573
  import { fileURLToPath as fileURLToPath3 } from "url";
7285
7574
  function getPackageVersion() {
7286
7575
  try {
7287
- const pkgPath = join6(dirname3(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
7288
- 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"));
7289
7578
  return pkg.version || "0.0.0";
7290
7579
  } catch {
7291
7580
  return "0.0.0";
@@ -7358,6 +7647,39 @@ function truncateText(value, max = DEFAULT_SNIPPET_LENGTH) {
7358
7647
  return normalized.slice(0, max);
7359
7648
  return `${normalized.slice(0, max - 3)}...`;
7360
7649
  }
7650
+ function collectPagedRows(fetchPage, target, offset, opts = {}) {
7651
+ const pageSize = opts.pageSize ?? 1000;
7652
+ const maxPages = opts.maxPages ?? 1000;
7653
+ const want = target === undefined ? undefined : target + 1;
7654
+ const rows = [];
7655
+ const seenCursors = new Set;
7656
+ let cursor = offset;
7657
+ let pages = 0;
7658
+ for (;; ) {
7659
+ if (want !== undefined && rows.length >= want)
7660
+ break;
7661
+ if (++pages > maxPages) {
7662
+ throw new Error(`pagination exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
7663
+ }
7664
+ const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
7665
+ const page = fetchPage(cursor, limit);
7666
+ rows.push(...page.rows);
7667
+ if (page.has_more === false)
7668
+ break;
7669
+ if (page.has_more === undefined && page.rows.length < limit)
7670
+ break;
7671
+ if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
7672
+ throw new Error("pagination claimed more results without a next cursor \u2014 aborting");
7673
+ }
7674
+ const next = page.next_cursor ?? cursor + page.rows.length;
7675
+ if (seenCursors.has(next)) {
7676
+ throw new Error("pagination repeated a cursor \u2014 aborting");
7677
+ }
7678
+ seenCursors.add(next);
7679
+ cursor = next;
7680
+ }
7681
+ return { rows, hasMore: target !== undefined && rows.length > target };
7682
+ }
7361
7683
  function printPageHint(opts) {
7362
7684
  const hints = [];
7363
7685
  const offset = opts.offset ?? 0;
@@ -7811,16 +8133,16 @@ function validateConfigKeyValue(key, value, DEFAULT_CONFIG) {
7811
8133
  return null;
7812
8134
  }
7813
8135
  function getConfigPath() {
7814
- const { homedir: homedir3 } = __require("os");
7815
- return join6(homedir3(), ".hasna", "mementos", "config.json");
8136
+ const { homedir: homedir4 } = __require("os");
8137
+ return join7(homedir4(), ".hasna", "mementos", "config.json");
7816
8138
  }
7817
8139
  function readFileConfig() {
7818
- const { existsSync: existsSync4 } = __require("fs");
8140
+ const { existsSync: existsSync5 } = __require("fs");
7819
8141
  const configPath = getConfigPath();
7820
- if (!existsSync4(configPath))
8142
+ if (!existsSync5(configPath))
7821
8143
  return {};
7822
8144
  try {
7823
- const data = JSON.parse(readFileSync3(configPath, "utf-8"));
8145
+ const data = JSON.parse(readFileSync4(configPath, "utf-8"));
7824
8146
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
7825
8147
  throw new Error("expected a JSON object");
7826
8148
  }
@@ -7831,10 +8153,10 @@ function readFileConfig() {
7831
8153
  }
7832
8154
  }
7833
8155
  function writeFileConfig(data) {
7834
- const { existsSync: existsSync4, writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = __require("fs");
8156
+ const { existsSync: existsSync5, writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = __require("fs");
7835
8157
  const configPath = getConfigPath();
7836
8158
  const dir = dirname3(configPath);
7837
- if (!existsSync4(dir))
8159
+ if (!existsSync5(dir))
7838
8160
  mkdirSync3(dir, { recursive: true });
7839
8161
  writeFileSync3(configPath, JSON.stringify(data, null, 2) + `
7840
8162
  `, "utf-8");
@@ -8262,7 +8584,7 @@ function buildFilterConditions(filter) {
8262
8584
  const conditions = [];
8263
8585
  const params = [];
8264
8586
  conditions.push("m.status = 'active'");
8265
- 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'))");
8266
8588
  if (!filter)
8267
8589
  return { conditions, params };
8268
8590
  if (filter.scope) {
@@ -10342,7 +10664,7 @@ async function detectContradiction(newKey, newValue, options = {}, db) {
10342
10664
  conditions.push("project_id = ?");
10343
10665
  params.push(project_id);
10344
10666
  }
10345
- 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'))");
10346
10668
  const sql = `SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY importance DESC LIMIT 10`;
10347
10669
  const rows = d.query(sql).all(...params);
10348
10670
  if (rows.length === 0) {
@@ -11536,10 +11858,12 @@ var init_synthesis2 = __esm(() => {
11536
11858
  var exports_session_jobs = {};
11537
11859
  __export(exports_session_jobs, {
11538
11860
  updateSessionJob: () => updateSessionJob,
11861
+ recoverStaleProcessingJobs: () => recoverStaleProcessingJobs,
11539
11862
  listSessionJobs: () => listSessionJobs,
11540
11863
  getSessionJob: () => getSessionJob,
11541
11864
  getNextPendingJob: () => getNextPendingJob,
11542
- createSessionJob: () => createSessionJob
11865
+ createSessionJob: () => createSessionJob,
11866
+ claimSessionJob: () => claimSessionJob
11543
11867
  });
11544
11868
  function parseJobRow(row) {
11545
11869
  return {
@@ -11669,6 +11993,18 @@ function getNextPendingJob(db) {
11669
11993
  return null;
11670
11994
  return parseJobRow(row);
11671
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
+ }
11672
12008
  var init_session_jobs = __esm(() => {
11673
12009
  init_database();
11674
12010
  init_api_mode();
@@ -12207,7 +12543,11 @@ async function processSessionJob(jobId, db) {
12207
12543
  return result;
12208
12544
  }
12209
12545
  try {
12210
- 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
+ }
12211
12551
  } catch (e) {
12212
12552
  result.errors.push(`Failed to mark job as processing: ${String(e)}`);
12213
12553
  return result;
@@ -12330,6 +12670,9 @@ function startSessionQueueWorker() {
12330
12670
  return;
12331
12671
  _workerStarted = true;
12332
12672
  setInterval(() => {
12673
+ try {
12674
+ recoverStaleProcessingJobs(30 * 60 * 1000);
12675
+ } catch {}
12333
12676
  _processNext();
12334
12677
  }, 5000);
12335
12678
  }
@@ -12383,13 +12726,13 @@ __export(exports_session_registry, {
12383
12726
  closeRegistry: () => closeRegistry,
12384
12727
  cleanStaleSessions: () => cleanStaleSessions
12385
12728
  });
12386
- import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
12387
- 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";
12388
12731
  function getDb() {
12389
12732
  if (_db2)
12390
12733
  return _db2;
12391
12734
  const dir = dirname6(DB_PATH);
12392
- if (!existsSync8(dir))
12735
+ if (!existsSync9(dir))
12393
12736
  mkdirSync5(dir, { recursive: true });
12394
12737
  _db2 = new SqliteAdapter(DB_PATH);
12395
12738
  _db2.run("PRAGMA journal_mode = WAL");
@@ -12564,7 +12907,7 @@ function closeRegistry() {
12564
12907
  var DB_PATH, _db2 = null;
12565
12908
  var init_session_registry = __esm(() => {
12566
12909
  init_storage();
12567
- 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");
12568
12911
  });
12569
12912
 
12570
12913
  // src/db/pg-migrations.ts
@@ -27040,7 +27383,7 @@ class JSONSchemaGenerator {
27040
27383
  if (val === undefined) {
27041
27384
  if (this.unrepresentable === "throw") {
27042
27385
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
27043
- } else {}
27386
+ }
27044
27387
  } else if (typeof val === "bigint") {
27045
27388
  if (this.unrepresentable === "throw") {
27046
27389
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -48690,7 +49033,7 @@ var require_tracestate_impl = __commonJS((exports) => {
48690
49033
  const value = listMember.slice(i + 1, part.length);
48691
49034
  if ((0, tracestate_validators_1.validateKey)(key) && (0, tracestate_validators_1.validateValue)(value)) {
48692
49035
  agg.set(key, value);
48693
- } else {}
49036
+ }
48694
49037
  }
48695
49038
  return agg;
48696
49039
  }, new Map);
@@ -62045,8 +62388,8 @@ var {
62045
62388
 
62046
62389
  // src/cli/index.tsx
62047
62390
  init_database();
62048
- import { readFileSync as readFileSync9 } from "fs";
62049
- 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";
62050
62393
  import { fileURLToPath as fileURLToPath5 } from "url";
62051
62394
 
62052
62395
  // src/db/machines.ts
@@ -63487,6 +63830,7 @@ import { createHash as createHash3 } from "crypto";
63487
63830
  init_projects();
63488
63831
  init_types2();
63489
63832
  init_identity();
63833
+ init_historical_receipt();
63490
63834
  function canonicalMementosProjectRegistrationJson(value) {
63491
63835
  return JSON.stringify(canonicalize2(value));
63492
63836
  }
@@ -64044,6 +64388,18 @@ function registerCrudCommands(program2) {
64044
64388
  }
64045
64389
  resolvedAgentId = ag.id;
64046
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
+ }
64047
64403
  const input = {
64048
64404
  key,
64049
64405
  value,
@@ -64053,7 +64409,7 @@ function registerCrudCommands(program2) {
64053
64409
  tags: mergedTags,
64054
64410
  summary: opts.summary,
64055
64411
  ttl_ms: opts.ttl ? parseDuration(opts.ttl) : undefined,
64056
- source: opts.source,
64412
+ source: requestedSource,
64057
64413
  agent_id: resolvedAgentId,
64058
64414
  session_id: globalOpts.session
64059
64415
  };
@@ -64120,6 +64476,10 @@ function registerCrudCommands(program2) {
64120
64476
  const updateInput = {
64121
64477
  version: existing.version
64122
64478
  };
64479
+ const writingName = resolveWritingAgentName();
64480
+ if (writingName) {
64481
+ updateInput.updated_by_agent = getAgent(writingName)?.id ?? registerAgent(writingName).id;
64482
+ }
64123
64483
  if (opts.value !== undefined)
64124
64484
  updateInput.value = opts.value;
64125
64485
  if (opts.importance !== undefined)
@@ -64147,7 +64507,7 @@ function registerCrudCommands(program2) {
64147
64507
  if (violation)
64148
64508
  throw new Error(formatEnumViolation(violation));
64149
64509
  }
64150
- const changedFields = Object.keys(updateInput).filter((k) => k !== "version");
64510
+ const changedFields = Object.keys(updateInput).filter((k) => k !== "version" && k !== "updated_by_agent");
64151
64511
  if (changedFields.length === 0) {
64152
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.`);
64153
64513
  }
@@ -64177,8 +64537,7 @@ function registerCrudCommands(program2) {
64177
64537
  }
64178
64538
  const matches = getMemoriesByKey(keyOrId, opts.scope, opts.agent, opts.project);
64179
64539
  if (matches.length === 0) {
64180
- 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);
64181
- if (isApiMode() && looksLikeId && deleteMemory(keyOrId)) {
64540
+ if (isApiMode() && keyOrId.length > 0 && deleteMemory(keyOrId)) {
64182
64541
  if (globalOpts.json) {
64183
64542
  outputJson({ deleted: keyOrId });
64184
64543
  } else {
@@ -64750,7 +65109,7 @@ function registerRemoveCommand(program2) {
64750
65109
  if (mem)
64751
65110
  id = mem.id;
64752
65111
  }
64753
- 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) {
64754
65113
  id = nameOrId;
64755
65114
  }
64756
65115
  if (!id) {
@@ -64878,15 +65237,17 @@ function registerListCommand(program2) {
64878
65237
  const fmt = getOutputFormat(program2, opts.format);
64879
65238
  const isStructured = fmt === "json" || fmt === "csv" || fmt === "yaml";
64880
65239
  const requestedLimit = opts.limit;
64881
- const limit = positiveIntOrDefault(requestedLimit, isStructured ? 50 : DEFAULT_COMPACT_LIMIT);
64882
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65240
+ const limit = requestedLimit === undefined ? isStructured ? undefined : DEFAULT_COMPACT_LIMIT : positiveIntOrDefault(requestedLimit, isStructured ? 50 : DEFAULT_COMPACT_LIMIT);
65241
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
64883
65242
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
64884
65243
  const projectPath = opts.project || globalOpts.project;
64885
65244
  let projectId;
64886
65245
  if (projectPath) {
64887
65246
  const project = getProject(resolve7(projectPath));
64888
- if (project)
64889
- projectId = project.id;
65247
+ if (!project) {
65248
+ throw new Error(`Project not found: ${projectPath}`);
65249
+ }
65250
+ projectId = project.id;
64890
65251
  }
64891
65252
  const filter = {
64892
65253
  scope: opts.scope,
@@ -64896,16 +65257,24 @@ function registerListCommand(program2) {
64896
65257
  pinned: opts.pinned ? true : undefined,
64897
65258
  agent_id: agentId,
64898
65259
  project_id: projectId,
64899
- limit: isStructured ? limit : limit + 1,
64900
- offset,
64901
65260
  status: opts.status,
64902
65261
  session_id: opts.session || globalOpts.session
64903
65262
  };
64904
- const fetched = listMemories(filter);
64905
- const hasMore = !isStructured && fetched.length > limit;
64906
- const memories = hasMore ? fetched.slice(0, limit) : fetched;
65263
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65264
+ const page = listMemoriesPage({
65265
+ ...filter,
65266
+ limit: pageLimit,
65267
+ offset: cursor
65268
+ });
65269
+ return {
65270
+ rows: page.rows,
65271
+ has_more: page.has_more,
65272
+ next_cursor: page.next_cursor
65273
+ };
65274
+ }, limit, offset);
65275
+ const memories = hasMore && limit !== undefined ? collected.slice(0, limit) : collected;
64907
65276
  if (fmt === "json") {
64908
- outputJson(fetched);
65277
+ outputJson(memories);
64909
65278
  return;
64910
65279
  }
64911
65280
  if (fmt === "csv") {
@@ -64933,7 +65302,7 @@ function registerListCommand(program2) {
64933
65302
  }
64934
65303
  printPageHint({
64935
65304
  shown: memories.length,
64936
- limit,
65305
+ limit: limit ?? memories.length,
64937
65306
  offset,
64938
65307
  hasMore,
64939
65308
  command: "mementos list",
@@ -64973,7 +65342,10 @@ function getMemoryStats(db) {
64973
65342
  const byCategory = d.query("SELECT category, COUNT(*) as c FROM memories WHERE status = 'active' GROUP BY category").all();
64974
65343
  const byStatus = d.query("SELECT status, COUNT(*) as c FROM memories WHERE status = 'active' GROUP BY status").all();
64975
65344
  const pinnedCount = d.query("SELECT COUNT(*) as c FROM memories WHERE pinned = 1 AND status = 'active'").get().c;
64976
- 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;
64977
65349
  const stats = {
64978
65350
  total,
64979
65351
  by_scope: { global: 0, shared: 0, private: 0, working: 0 },
@@ -64981,7 +65353,9 @@ function getMemoryStats(db) {
64981
65353
  by_status: { active: 0, archived: 0, expired: 0 },
64982
65354
  by_agent: {},
64983
65355
  pinned_count: pinnedCount,
64984
- expired_count: expiredCount
65356
+ expired_count: expiredCount,
65357
+ expires_at_count: expiresAtCount,
65358
+ expired_due_count: expiredDueCount
64985
65359
  };
64986
65360
  for (const row of byScope)
64987
65361
  if (row.scope in stats.by_scope)
@@ -65015,7 +65389,9 @@ function normalizeStats(data) {
65015
65389
  by_status: { active: 0, archived: 0, expired: 0, ...data?.by_status ?? {} },
65016
65390
  by_agent: data?.by_agent ?? {},
65017
65391
  pinned_count: data?.pinned_count ?? 0,
65018
- 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
65019
65395
  };
65020
65396
  }
65021
65397
  function getMemoryReport(filter = {}, db) {
@@ -65068,19 +65444,31 @@ function getMemoryReport(filter = {}, db) {
65068
65444
  top_agents: topAgents
65069
65445
  };
65070
65446
  }
65071
- function getStaleMemories(filter = {}, db) {
65447
+ function getStaleMemoriesPage(filter = {}, db) {
65072
65448
  const days = Math.min(filter.days || 30, 365);
65073
65449
  const limit = filter.limit ?? 20;
65074
65450
  const offset = filter.offset ?? 0;
65075
65451
  if (!db && isApiMode()) {
65076
- 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 });
65077
65453
  const { data } = apiJson("GET", `/memories/stale${q}`);
65078
- return data?.memories ?? [];
65454
+ const rows2 = data?.memories ?? [];
65455
+ return {
65456
+ rows: rows2,
65457
+ total: data?.total ?? rows2.length,
65458
+ has_more: data?.has_more,
65459
+ next_cursor: data?.next_cursor ?? null
65460
+ };
65079
65461
  }
65080
65462
  const d = db || getDatabase();
65081
65463
  const cutoffDate = new Date(Date.now() - days * 86400000).toISOString();
65082
- 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 < ?)"];
65083
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
+ }
65084
65472
  if (filter.project_id) {
65085
65473
  conds.push("project_id = ?");
65086
65474
  params.push(filter.project_id);
@@ -65089,13 +65477,22 @@ function getStaleMemories(filter = {}, db) {
65089
65477
  conds.push("agent_id = ?");
65090
65478
  params.push(filter.agent_id);
65091
65479
  }
65092
- let sql = `SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${conds.join(" AND ")} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`;
65480
+ const where = conds.join(" AND ");
65481
+ const countRow = d.query(`SELECT COUNT(*) AS c FROM memories WHERE ${where}`).get(...params);
65482
+ let sql = `SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${where} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`;
65093
65483
  params.push(limit);
65094
65484
  if (offset) {
65095
65485
  sql += " OFFSET ?";
65096
65486
  params.push(offset);
65097
65487
  }
65098
- return d.query(sql).all(...params);
65488
+ const rows = d.query(sql).all(...params);
65489
+ const hasMore = rows.length === limit;
65490
+ return {
65491
+ rows,
65492
+ total: countRow?.c ?? 0,
65493
+ has_more: hasMore,
65494
+ next_cursor: hasMore ? offset + rows.length : null
65495
+ };
65099
65496
  }
65100
65497
 
65101
65498
  // src/cli/commands/info-stats.ts
@@ -65248,14 +65645,14 @@ init_projects();
65248
65645
  init_helpers();
65249
65646
  function registerStaleCommand(program2) {
65250
65647
  const handleError = makeHandleError(program2);
65251
- 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) => {
65252
65649
  try {
65253
65650
  const globalOpts = program2.opts();
65254
65651
  const days = opts.days || 30;
65255
65652
  const fmt = getOutputFormat(program2, opts.format);
65256
65653
  const isJson = fmt === "json";
65257
65654
  const limit = positiveIntOrDefault(opts.limit, isJson ? 20 : DEFAULT_COMPACT_LIMIT);
65258
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65655
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
65259
65656
  const projectPath = opts.project || globalOpts.project;
65260
65657
  let projectId;
65261
65658
  if (projectPath) {
@@ -65264,17 +65661,37 @@ function registerStaleCommand(program2) {
65264
65661
  projectId = project.id;
65265
65662
  }
65266
65663
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
65267
- const rows = getStaleMemories({
65268
- days,
65269
- project_id: projectId,
65270
- agent_id: agentId,
65271
- limit: isJson ? limit : limit + 1,
65272
- offset
65273
- });
65274
- const hasMore = !isJson && rows.length > limit;
65275
- const displayRows = hasMore ? rows.slice(0, limit) : rows;
65664
+ let staleTotal = 0;
65665
+ let firstPage = true;
65666
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65667
+ const page = getStaleMemoriesPage({
65668
+ days,
65669
+ pinned: opts.pinned ? true : undefined,
65670
+ project_id: projectId,
65671
+ agent_id: agentId,
65672
+ limit: pageLimit,
65673
+ offset: cursor
65674
+ });
65675
+ if (firstPage) {
65676
+ staleTotal = page.total;
65677
+ firstPage = false;
65678
+ }
65679
+ return {
65680
+ rows: page.rows,
65681
+ has_more: page.has_more,
65682
+ next_cursor: page.next_cursor
65683
+ };
65684
+ }, limit, offset);
65685
+ const displayRows = hasMore ? collected.slice(0, limit) : collected;
65276
65686
  if (fmt === "json") {
65277
- outputJson({ stale_count: rows.length, threshold_days: days, memories: rows });
65687
+ outputJson({
65688
+ stale_count: staleTotal,
65689
+ returned: displayRows.length,
65690
+ threshold_days: days,
65691
+ has_more: hasMore,
65692
+ next_cursor: hasMore ? offset + displayRows.length : null,
65693
+ memories: displayRows
65694
+ });
65278
65695
  return;
65279
65696
  }
65280
65697
  if (displayRows.length === 0) {
@@ -65313,13 +65730,20 @@ function registerHistoryCommand(program2) {
65313
65730
  try {
65314
65731
  const globalOpts = program2.opts();
65315
65732
  const isJson = Boolean(globalOpts.json);
65316
- const limit = positiveIntOrDefault(opts.limit, isJson ? 20 : DEFAULT_SEARCH_LIMIT);
65317
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65318
- const fetched = listMemoryHistory({ limit: isJson ? limit : limit + 1, offset });
65319
- const hasMore = !isJson && fetched.length > limit;
65320
- const memories = hasMore ? fetched.slice(0, limit) : fetched;
65733
+ const requestedLimit = opts.limit;
65734
+ const limit = requestedLimit === undefined ? isJson ? undefined : DEFAULT_SEARCH_LIMIT : positiveIntOrDefault(requestedLimit, isJson ? 20 : DEFAULT_SEARCH_LIMIT);
65735
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
65736
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65737
+ const page = listMemoryHistoryPage({ limit: pageLimit, offset: cursor });
65738
+ return {
65739
+ rows: page.rows,
65740
+ has_more: page.has_more,
65741
+ next_cursor: page.next_cursor
65742
+ };
65743
+ }, limit, offset);
65744
+ const memories = hasMore && limit !== undefined ? collected.slice(0, limit) : collected;
65321
65745
  if (globalOpts.json) {
65322
- outputJson(fetched);
65746
+ outputJson(memories);
65323
65747
  return;
65324
65748
  }
65325
65749
  if (memories.length === 0) {
@@ -65337,7 +65761,7 @@ function registerHistoryCommand(program2) {
65337
65761
  }
65338
65762
  printPageHint({
65339
65763
  shown: memories.length,
65340
- limit,
65764
+ limit: limit ?? memories.length,
65341
65765
  offset,
65342
65766
  hasMore,
65343
65767
  command: "mementos history",
@@ -65529,10 +65953,9 @@ function registerExportCommand(program2) {
65529
65953
  scope: opts.scope,
65530
65954
  category: opts.category,
65531
65955
  agent_id: agentId,
65532
- project_id: projectId,
65533
- limit: 1e4
65956
+ project_id: projectId
65534
65957
  };
65535
- const memories = listMemories(filter);
65958
+ const memories = listMemoriesBounded(filter, 1e4).rows;
65536
65959
  outputJson(memories);
65537
65960
  } catch (e) {
65538
65961
  handleError(e);
@@ -65545,7 +65968,7 @@ init_memories();
65545
65968
  init_helpers();
65546
65969
  import chalk18 from "chalk";
65547
65970
  import { resolve as resolve12 } from "path";
65548
- import { readFileSync as readFileSync4 } from "fs";
65971
+ import { readFileSync as readFileSync5 } from "fs";
65549
65972
  function registerImportCommand(program2) {
65550
65973
  const handleError = makeHandleError(program2);
65551
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) => {
@@ -65555,7 +65978,7 @@ function registerImportCommand(program2) {
65555
65978
  if (file === "-" || !file && !process.stdin.isTTY) {
65556
65979
  raw = await Bun.stdin.text();
65557
65980
  } else if (file) {
65558
- raw = readFileSync4(resolve12(file), "utf-8");
65981
+ raw = readFileSync5(resolve12(file), "utf-8");
65559
65982
  } else {
65560
65983
  console.error(chalk18.red("No input: provide a file path, use '-' for stdin, or pipe data."));
65561
65984
  process.exit(1);
@@ -65585,14 +66008,14 @@ function registerImportCommand(program2) {
65585
66008
  import chalk19 from "chalk";
65586
66009
 
65587
66010
  // src/lib/config.ts
65588
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
65589
- import { homedir as homedir3 } from "os";
65590
- 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";
65591
66014
  function isInMemoryDb2(path) {
65592
66015
  return path === ":memory:" || path.startsWith("file::memory:");
65593
66016
  }
65594
66017
  function homeDir() {
65595
- return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
66018
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir4();
65596
66019
  }
65597
66020
  var DEFAULT_CONFIG = {
65598
66021
  default_scope: "private",
@@ -65650,11 +66073,11 @@ function isValidCategory(value) {
65650
66073
  return VALID_CATEGORIES2.includes(value);
65651
66074
  }
65652
66075
  function loadConfig() {
65653
- const configPath = join7(homeDir(), ".hasna", "mementos", "config.json");
66076
+ const configPath = join8(homeDir(), ".hasna", "mementos", "config.json");
65654
66077
  let fileConfig = {};
65655
- if (existsSync4(configPath)) {
66078
+ if (existsSync5(configPath)) {
65656
66079
  try {
65657
- const raw = readFileSync5(configPath, "utf-8");
66080
+ const raw = readFileSync6(configPath, "utf-8");
65658
66081
  fileConfig = JSON.parse(raw);
65659
66082
  } catch {}
65660
66083
  }
@@ -65680,8 +66103,8 @@ function findFileWalkingUp(filename) {
65680
66103
  let dir = process.cwd();
65681
66104
  const legacyHomeMementosDb = resolve13(homeDir(), ".mementos", "mementos.db");
65682
66105
  while (true) {
65683
- const candidate = join7(dir, filename);
65684
- if (existsSync4(candidate) && resolve13(candidate) !== legacyHomeMementosDb) {
66106
+ const candidate = join8(dir, filename);
66107
+ if (existsSync5(candidate) && resolve13(candidate) !== legacyHomeMementosDb) {
65685
66108
  return candidate;
65686
66109
  }
65687
66110
  const parent = dirname4(dir);
@@ -65694,7 +66117,7 @@ function findFileWalkingUp(filename) {
65694
66117
  function findGitRoot2() {
65695
66118
  let dir = process.cwd();
65696
66119
  while (true) {
65697
- if (existsSync4(join7(dir, ".git"))) {
66120
+ if (existsSync5(join8(dir, ".git"))) {
65698
66121
  return dir;
65699
66122
  }
65700
66123
  const parent = dirname4(dir);
@@ -65705,27 +66128,27 @@ function findGitRoot2() {
65705
66128
  }
65706
66129
  }
65707
66130
  function profilesDir() {
65708
- return join7(homeDir(), ".hasna", "mementos", "profiles");
66131
+ return join8(homeDir(), ".hasna", "mementos", "profiles");
65709
66132
  }
65710
66133
  function globalConfigPath() {
65711
- return join7(homeDir(), ".hasna", "mementos", "config.json");
66134
+ return join8(homeDir(), ".hasna", "mementos", "config.json");
65712
66135
  }
65713
66136
  function readGlobalConfig() {
65714
66137
  const p = globalConfigPath();
65715
- if (!existsSync4(p))
66138
+ if (!existsSync5(p))
65716
66139
  return {};
65717
66140
  try {
65718
- return JSON.parse(readFileSync5(p, "utf-8"));
66141
+ return JSON.parse(readFileSync6(p, "utf-8"));
65719
66142
  } catch {
65720
66143
  return {};
65721
66144
  }
65722
66145
  }
65723
66146
  function readGlobalConfigForWrite() {
65724
66147
  const p = globalConfigPath();
65725
- if (!existsSync4(p))
66148
+ if (!existsSync5(p))
65726
66149
  return {};
65727
66150
  try {
65728
- const data = JSON.parse(readFileSync5(p, "utf-8"));
66151
+ const data = JSON.parse(readFileSync6(p, "utf-8"));
65729
66152
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
65730
66153
  throw new Error("expected a JSON object");
65731
66154
  }
@@ -65758,13 +66181,13 @@ function setActiveProfile(name) {
65758
66181
  }
65759
66182
  function listProfiles() {
65760
66183
  const dir = profilesDir();
65761
- if (!existsSync4(dir))
66184
+ if (!existsSync5(dir))
65762
66185
  return [];
65763
66186
  return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
65764
66187
  }
65765
66188
  function deleteProfile(name) {
65766
- const dbPath = join7(profilesDir(), `${name}.db`);
65767
- if (!existsSync4(dbPath))
66189
+ const dbPath = join8(profilesDir(), `${name}.db`);
66190
+ if (!existsSync5(dbPath))
65768
66191
  return false;
65769
66192
  unlinkSync2(dbPath);
65770
66193
  if (getActiveProfile() === name)
@@ -65773,10 +66196,10 @@ function deleteProfile(name) {
65773
66196
  }
65774
66197
  function getDbPath2() {
65775
66198
  const _home = homeDir();
65776
- const _newDir = join7(_home, ".hasna", "mementos");
65777
- const _oldDir = join7(_home, ".mementos");
65778
- if (!existsSync4(_newDir) && existsSync4(_oldDir)) {
65779
- 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 });
65780
66203
  cpSync2(_oldDir, _newDir, { recursive: true });
65781
66204
  }
65782
66205
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
@@ -65790,7 +66213,7 @@ function getDbPath2() {
65790
66213
  }
65791
66214
  const profile = getActiveProfile();
65792
66215
  if (profile) {
65793
- const profilePath = join7(profilesDir(), `${profile}.db`);
66216
+ const profilePath = join8(profilesDir(), `${profile}.db`);
65794
66217
  ensureDir2(dirname4(profilePath));
65795
66218
  return profilePath;
65796
66219
  }
@@ -65798,21 +66221,21 @@ function getDbPath2() {
65798
66221
  if (dbScope === "project") {
65799
66222
  const gitRoot = findGitRoot2();
65800
66223
  if (gitRoot) {
65801
- const dbPath = join7(gitRoot, ".mementos", "mementos.db");
66224
+ const dbPath = join8(gitRoot, ".mementos", "mementos.db");
65802
66225
  ensureDir2(dirname4(dbPath));
65803
66226
  return dbPath;
65804
66227
  }
65805
66228
  }
65806
- const found = findFileWalkingUp(join7(".mementos", "mementos.db"));
66229
+ const found = findFileWalkingUp(join8(".mementos", "mementos.db"));
65807
66230
  if (found) {
65808
66231
  return found;
65809
66232
  }
65810
- const fallback = join7(homeDir(), ".hasna", "mementos", "mementos.db");
66233
+ const fallback = join8(homeDir(), ".hasna", "mementos", "mementos.db");
65811
66234
  ensureDir2(dirname4(fallback));
65812
66235
  return fallback;
65813
66236
  }
65814
66237
  function ensureDir2(dir) {
65815
- if (!existsSync4(dir)) {
66238
+ if (!existsSync5(dir)) {
65816
66239
  mkdirSync3(dir, { recursive: true });
65817
66240
  }
65818
66241
  }
@@ -65930,7 +66353,7 @@ init_database();
65930
66353
  init_helpers();
65931
66354
  import chalk20 from "chalk";
65932
66355
  import { resolve as resolve14, dirname as dirname5 } from "path";
65933
- 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";
65934
66357
  function registerBackupCommand(program2) {
65935
66358
  const handleError = makeHandleError(program2);
65936
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) => {
@@ -65939,7 +66362,7 @@ function registerBackupCommand(program2) {
65939
66362
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
65940
66363
  const backupsDir = resolve14(home, ".hasna", "mementos", "backups");
65941
66364
  if (opts.list) {
65942
- if (!existsSync5(backupsDir)) {
66365
+ if (!existsSync6(backupsDir)) {
65943
66366
  if (globalOpts.json) {
65944
66367
  outputJson({ backups: [] });
65945
66368
  return;
@@ -65981,7 +66404,7 @@ function registerBackupCommand(program2) {
65981
66404
  return;
65982
66405
  }
65983
66406
  const dbPath = getDbPath();
65984
- if (!existsSync5(dbPath)) {
66407
+ if (!existsSync6(dbPath)) {
65985
66408
  console.error(chalk20.red(`Database not found at ${dbPath}`));
65986
66409
  process.exit(1);
65987
66410
  }
@@ -65989,7 +66412,7 @@ function registerBackupCommand(program2) {
65989
66412
  if (targetPath) {
65990
66413
  dest = resolve14(targetPath);
65991
66414
  } else {
65992
- if (!existsSync5(backupsDir)) {
66415
+ if (!existsSync6(backupsDir)) {
65993
66416
  mkdirSync4(backupsDir, { recursive: true });
65994
66417
  }
65995
66418
  const now3 = new Date;
@@ -65997,7 +66420,7 @@ function registerBackupCommand(program2) {
65997
66420
  dest = resolve14(backupsDir, `mementos-${ts}.db`);
65998
66421
  }
65999
66422
  const destDir = dirname5(dest);
66000
- if (!existsSync5(destDir)) {
66423
+ if (!existsSync6(destDir)) {
66001
66424
  mkdirSync4(destDir, { recursive: true });
66002
66425
  }
66003
66426
  copyFileSync(dbPath, dest);
@@ -66018,29 +66441,31 @@ function registerBackupCommand(program2) {
66018
66441
  // src/cli/commands/io-restore.ts
66019
66442
  init_database();
66020
66443
  init_api_mode();
66444
+ init_memories();
66021
66445
  init_helpers();
66022
66446
  import chalk21 from "chalk";
66023
66447
  import { resolve as resolve15 } from "path";
66024
- 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
+ }
66025
66459
  function registerRestoreCommand(program2) {
66026
66460
  const handleError = makeHandleError(program2);
66027
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) => {
66028
66462
  try {
66029
66463
  const globalOpts = program2.opts();
66030
- if (isApiMode()) {
66031
- 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.";
66032
- if (globalOpts.json) {
66033
- outputJson({ error: msg });
66034
- } else {
66035
- console.error(chalk21.red(msg));
66036
- }
66037
- process.exit(1);
66038
- }
66039
66464
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
66040
66465
  const backupsDir = resolve15(home, ".hasna", "mementos", "backups");
66041
66466
  let source;
66042
66467
  if (opts.latest) {
66043
- if (!existsSync6(backupsDir)) {
66468
+ if (!existsSync7(backupsDir)) {
66044
66469
  console.error(chalk21.red("No backups directory found."));
66045
66470
  process.exit(1);
66046
66471
  }
@@ -66060,16 +66485,82 @@ function registerRestoreCommand(program2) {
66060
66485
  console.error(chalk21.red("Provide a backup file path or use --latest"));
66061
66486
  process.exit(1);
66062
66487
  }
66063
- if (!existsSync6(source)) {
66488
+ if (!existsSync7(source)) {
66064
66489
  console.error(chalk21.red(`Backup file not found: ${source}`));
66065
66490
  process.exit(1);
66066
66491
  }
66067
- const dbPath = getDbPath();
66068
66492
  const backupStat = statSync2(source);
66069
66493
  const backupSizeMB = (backupStat.size / (1024 * 1024)).toFixed(1);
66070
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();
66071
66562
  let currentCount = 0;
66072
- if (existsSync6(dbPath)) {
66563
+ if (existsSync7(dbPath)) {
66073
66564
  try {
66074
66565
  const db = getDatabase();
66075
66566
  const row = db.query("SELECT COUNT(*) as count FROM memories").get();
@@ -67323,11 +67814,11 @@ init_memories();
67323
67814
  init_agents();
67324
67815
  init_projects();
67325
67816
  import chalk27 from "chalk";
67326
- import { join as join8 } from "path";
67327
- import { homedir as homedir4 } from "os";
67817
+ import { join as join9 } from "path";
67818
+ import { homedir as homedir5 } from "os";
67328
67819
  import {
67329
- readFileSync as readFileSync6,
67330
- existsSync as existsSync7,
67820
+ readFileSync as readFileSync7,
67821
+ existsSync as existsSync8,
67331
67822
  accessSync,
67332
67823
  statSync as statSync3,
67333
67824
  constants as fsConstants
@@ -67362,7 +67853,7 @@ function registerDoctorCommand(program2) {
67362
67853
  checks.push({ name: "Version", status: "ok", detail: version });
67363
67854
  const dbPath = getDbPath();
67364
67855
  let db = null;
67365
- if (dbPath !== ":memory:" && existsSync7(dbPath)) {
67856
+ if (dbPath !== ":memory:" && existsSync8(dbPath)) {
67366
67857
  try {
67367
67858
  accessSync(dbPath, fsConstants.R_OK | fsConstants.W_OK);
67368
67859
  checks.push({ name: "Database file", status: "ok", detail: dbPath });
@@ -67381,7 +67872,7 @@ function registerDoctorCommand(program2) {
67381
67872
  checks.push({ name: "Database connection", status: "fail", detail: e instanceof Error ? e.message : String(e) });
67382
67873
  }
67383
67874
  try {
67384
- if (dbPath !== ":memory:" && existsSync7(dbPath)) {
67875
+ if (dbPath !== ":memory:" && existsSync8(dbPath)) {
67385
67876
  const stats = statSync3(dbPath);
67386
67877
  const sizeKb = (stats.size / 1024).toFixed(1);
67387
67878
  const sizeMb = (stats.size / (1024 * 1024)).toFixed(2);
@@ -67514,9 +68005,9 @@ function registerDoctorCommand(program2) {
67514
68005
  checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
67515
68006
  }
67516
68007
  try {
67517
- const settingsFilePath = join8(homedir4(), ".claude", "settings.json");
67518
- if (existsSync7(settingsFilePath)) {
67519
- 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"));
67520
68011
  const hooksObj = settings["hooks"] || {};
67521
68012
  const stopHooks = hooksObj["Stop"] || [];
67522
68013
  const hasMementos = stopHooks.some((e) => e.hooks?.some((h) => h.command && h.command.includes("mementos")));
@@ -67532,11 +68023,11 @@ function registerDoctorCommand(program2) {
67532
68023
  checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
67533
68024
  }
67534
68025
  if (process.platform === "darwin") {
67535
- const plistFilePath = join8(homedir4(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
68026
+ const plistFilePath = join9(homedir5(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
67536
68027
  checks.push({
67537
68028
  name: "Auto-start",
67538
- status: existsSync7(plistFilePath) ? "ok" : "warn",
67539
- 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"
67540
68031
  });
67541
68032
  } else {
67542
68033
  checks.push({ name: "Auto-start", status: "ok", detail: `n/a on ${process.platform}` });
@@ -67615,9 +68106,9 @@ async function runCloudDoctor(globalOpts, checks) {
67615
68106
  checks.push({ name: "MCP server", status: "warn", detail: "could not check (is claude CLI installed?)" });
67616
68107
  }
67617
68108
  try {
67618
- const settingsFilePath = join8(homedir4(), ".claude", "settings.json");
67619
- if (existsSync7(settingsFilePath)) {
67620
- 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"));
67621
68112
  const hooksObj = settings["hooks"] || {};
67622
68113
  const stopHooks = hooksObj["Stop"] || [];
67623
68114
  const hasMementos = stopHooks.some((e) => e.hooks?.some((h) => h.command && h.command.includes("mementos")));
@@ -67633,11 +68124,11 @@ async function runCloudDoctor(globalOpts, checks) {
67633
68124
  checks.push({ name: "Stop hook", status: "warn", detail: "could not check stop hook" });
67634
68125
  }
67635
68126
  if (process.platform === "darwin") {
67636
- const plistFilePath = join8(homedir4(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
68127
+ const plistFilePath = join9(homedir5(), "Library", "LaunchAgents", "com.hasna.mementos.plist");
67637
68128
  checks.push({
67638
68129
  name: "Auto-start",
67639
- status: existsSync7(plistFilePath) ? "ok" : "warn",
67640
- 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"
67641
68132
  });
67642
68133
  } else {
67643
68134
  checks.push({ name: "Auto-start", status: "ok", detail: `n/a on ${process.platform}` });
@@ -69163,6 +69654,7 @@ function syncMemoriesTable(source, target, local, direction, currentMachineId) {
69163
69654
  const countResult = source.get(`SELECT COUNT(*) as cnt FROM "${MEMORY_TABLE}"`);
69164
69655
  stat.total_rows = countResult?.cnt ?? 0;
69165
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;
69166
69658
  for (const row of rows) {
69167
69659
  try {
69168
69660
  const sourceMachine = sourceMachineRef(row, currentMachineId);
@@ -69221,18 +69713,34 @@ function syncMemoriesTable(source, target, local, direction, currentMachineId) {
69221
69713
  clearMemoryEmbedding(winnerDb, String(winner["id"]));
69222
69714
  stat.synced_rows++;
69223
69715
  } catch (error) {
69716
+ erroredRowIds.add(String(row["id"] ?? "unknown"));
69224
69717
  stat.errors.push(`Memory ${String(row["id"] ?? "unknown")}: ${error instanceof Error ? error.message : String(error)}`);
69225
69718
  }
69226
69719
  }
69227
69720
  if (rows.length === 0) {
69228
69721
  stat.skipped_rows = stat.total_rows;
69229
69722
  }
69230
- upsertMemorySyncMeta(local, {
69231
- table_name: MEMORY_TABLE,
69232
- direction,
69233
- last_synced_at: new Date().toISOString(),
69234
- last_synced_row_count: stat.synced_rows
69235
- });
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
+ }
69236
69744
  } catch (error) {
69237
69745
  stat.errors.push(error instanceof Error ? error.message : String(error));
69238
69746
  }
@@ -69622,19 +70130,19 @@ function registerStorageCommands(program2) {
69622
70130
  // src/cli/commands/init.ts
69623
70131
  import chalk41 from "chalk";
69624
70132
  import {
69625
- readFileSync as readFileSync7,
70133
+ readFileSync as readFileSync8,
69626
70134
  writeFileSync as writeFileSync4,
69627
- existsSync as existsSync9,
70135
+ existsSync as existsSync10,
69628
70136
  copyFileSync as copyFileSync3,
69629
70137
  mkdirSync as mkdirSync6
69630
70138
  } from "fs";
69631
- import { dirname as dirname7, join as join10 } from "path";
69632
- import { homedir as homedir5 } from "os";
70139
+ import { dirname as dirname7, join as join11 } from "path";
70140
+ import { homedir as homedir6 } from "os";
69633
70141
  import { fileURLToPath as fileURLToPath4 } from "url";
69634
70142
  function registerInitCommand(program2) {
69635
70143
  program2.command("init").description("One-command setup: register MCP, install stop hook, configure auto-start").action(async () => {
69636
70144
  const { platform: platform2 } = process;
69637
- const home = homedir5();
70145
+ const home = homedir6();
69638
70146
  const isMac = platform2 === "darwin";
69639
70147
  console.log("");
69640
70148
  console.log(chalk41.bold(" mementos \u2014 setting up your memory layer"));
@@ -69689,17 +70197,17 @@ function registerInitCommand(program2) {
69689
70197
  } else {
69690
70198
  console.log(chalk41.green(" \u2713 MCP server registered with Claude Code"));
69691
70199
  }
69692
- const hooksDir = join10(home, ".claude", "hooks");
69693
- const hookDest = join10(hooksDir, "mementos-stop-hook.ts");
69694
- 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");
69695
70203
  const hookCommand = `bun ${hookDest}`;
69696
70204
  let hookAlreadyInstalled = false;
69697
70205
  let hookError = null;
69698
70206
  try {
69699
70207
  let settings = {};
69700
- if (existsSync9(settingsPath)) {
70208
+ if (existsSync10(settingsPath)) {
69701
70209
  try {
69702
- settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
70210
+ settings = JSON.parse(readFileSync8(settingsPath, "utf-8"));
69703
70211
  } catch {
69704
70212
  settings = {};
69705
70213
  }
@@ -69710,19 +70218,19 @@ function registerInitCommand(program2) {
69710
70218
  if (alreadyHasMementos) {
69711
70219
  hookAlreadyInstalled = true;
69712
70220
  } else {
69713
- if (!existsSync9(hooksDir)) {
70221
+ if (!existsSync10(hooksDir)) {
69714
70222
  mkdirSync6(hooksDir, { recursive: true });
69715
70223
  }
69716
- if (!existsSync9(hookDest)) {
70224
+ if (!existsSync10(hookDest)) {
69717
70225
  const packageDir = dirname7(dirname7(fileURLToPath4(import.meta.url)));
69718
70226
  const candidatePaths = [
69719
- join10(packageDir, "scripts", "hooks", "claude-stop-hook.ts"),
69720
- join10(packageDir, "..", "scripts", "hooks", "claude-stop-hook.ts"),
69721
- 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")
69722
70230
  ];
69723
70231
  let hookSourceFound = false;
69724
70232
  for (const src of candidatePaths) {
69725
- if (existsSync9(src)) {
70233
+ if (existsSync10(src)) {
69726
70234
  copyFileSync3(src, hookDest);
69727
70235
  hookSourceFound = true;
69728
70236
  break;
@@ -69788,7 +70296,7 @@ main().catch(() => {});
69788
70296
  if (!isMac) {
69789
70297
  console.log(chalk41.dim(` \xB7 Auto-start skipped (not macOS \u2014 platform: ${platform2})`));
69790
70298
  } else {
69791
- const plistPath = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70299
+ const plistPath = join11(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
69792
70300
  const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
69793
70301
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
69794
70302
  <plist version="1.0">
@@ -69813,11 +70321,11 @@ main().catch(() => {});
69813
70321
  </plist>
69814
70322
  `;
69815
70323
  try {
69816
- if (existsSync9(plistPath)) {
70324
+ if (existsSync10(plistPath)) {
69817
70325
  autoStartAlreadyInstalled = true;
69818
70326
  } else {
69819
- const launchAgentsDir = join10(home, "Library", "LaunchAgents");
69820
- if (!existsSync9(launchAgentsDir)) {
70327
+ const launchAgentsDir = join11(home, "Library", "LaunchAgents");
70328
+ if (!existsSync10(launchAgentsDir)) {
69821
70329
  mkdirSync6(launchAgentsDir, { recursive: true });
69822
70330
  }
69823
70331
  writeFileSync4(plistPath, plistContent, "utf-8");
@@ -69833,7 +70341,7 @@ main().catch(() => {});
69833
70341
  console.log(chalk41.green(" \u2713 Auto-start configured (starts on login)"));
69834
70342
  }
69835
70343
  if (!autoStartAlreadyInstalled && !autoStartError) {
69836
- const plistPath2 = join10(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
70344
+ const plistPath2 = join11(home, "Library", "LaunchAgents", "com.hasna.mementos.plist");
69837
70345
  const loadResult = await run(["launchctl", "load", plistPath2]);
69838
70346
  if (!loadResult.ok) {
69839
70347
  console.log(chalk41.dim(` \xB7 launchctl load: ${loadResult.output || "already loaded"}`));
@@ -70947,13 +71455,13 @@ function lessonTagForCli(kind) {
70947
71455
 
70948
71456
  // src/cli/brains.ts
70949
71457
  import {
70950
- existsSync as existsSync11,
71458
+ existsSync as existsSync12,
70951
71459
  mkdirSync as mkdirSync8,
70952
71460
  writeFileSync as writeFileSync6,
70953
71461
  readdirSync as readdirSync4
70954
71462
  } from "fs";
70955
- import { homedir as homedir7 } from "os";
70956
- import { join as join12 } from "path";
71463
+ import { homedir as homedir8 } from "os";
71464
+ import { join as join13 } from "path";
70957
71465
  import chalk43 from "chalk";
70958
71466
 
70959
71467
  // src/lib/gatherer.ts
@@ -71008,7 +71516,7 @@ ${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120
71008
71516
  };
71009
71517
  }
71010
71518
  var gatherTrainingData = async (options = {}) => {
71011
- const allMemories = listMemories({ status: "active" });
71519
+ const allMemories = listMemoriesBounded({ status: "active" }, undefined).rows;
71012
71520
  const filtered = options.since ? allMemories.filter((m) => new Date(m.created_at) >= options.since) : allMemories;
71013
71521
  const sorted = filtered.slice().sort((a, b) => b.importance - a.importance);
71014
71522
  const fetchSet = options.limit ? sorted.slice(0, options.limit * 3) : sorted;
@@ -71030,24 +71538,24 @@ var gatherTrainingData = async (options = {}) => {
71030
71538
  };
71031
71539
 
71032
71540
  // src/lib/model-config.ts
71033
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
71034
- import { homedir as homedir6 } from "os";
71035
- 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";
71036
71544
  var DEFAULT_MODEL = "gpt-4o-mini";
71037
- var CONFIG_DIR = join11(homedir6(), ".hasna", "mementos");
71038
- 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");
71039
71547
  function readConfig() {
71040
- if (!existsSync10(CONFIG_PATH))
71548
+ if (!existsSync11(CONFIG_PATH))
71041
71549
  return {};
71042
71550
  try {
71043
- const raw = readFileSync8(CONFIG_PATH, "utf-8");
71551
+ const raw = readFileSync9(CONFIG_PATH, "utf-8");
71044
71552
  return JSON.parse(raw);
71045
71553
  } catch {
71046
71554
  return {};
71047
71555
  }
71048
71556
  }
71049
71557
  function writeConfig(config2) {
71050
- if (!existsSync10(CONFIG_DIR)) {
71558
+ if (!existsSync11(CONFIG_DIR)) {
71051
71559
  mkdirSync7(CONFIG_DIR, { recursive: true });
71052
71560
  }
71053
71561
  writeFileSync5(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
@@ -71095,12 +71603,12 @@ function makeBrainsCommand() {
71095
71603
  limit: opts.limit,
71096
71604
  since
71097
71605
  });
71098
- const outputDir = opts.output ?? join12(homedir7(), ".hasna", "mementos", "training");
71099
- if (!existsSync11(outputDir)) {
71606
+ const outputDir = opts.output ?? join13(homedir8(), ".hasna", "mementos", "training");
71607
+ if (!existsSync12(outputDir)) {
71100
71608
  mkdirSync8(outputDir, { recursive: true });
71101
71609
  }
71102
71610
  const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
71103
- const outputPath = join12(outputDir, `mementos-training-${timestamp2}.jsonl`);
71611
+ const outputPath = join13(outputDir, `mementos-training-${timestamp2}.jsonl`);
71104
71612
  const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
71105
71613
  `);
71106
71614
  writeFileSync6(outputPath, jsonl + `
@@ -71124,8 +71632,8 @@ function makeBrainsCommand() {
71124
71632
  try {
71125
71633
  let datasetPath = opts.dataset;
71126
71634
  if (!datasetPath) {
71127
- const trainingDir = join12(homedir7(), ".hasna", "mementos", "training");
71128
- if (!existsSync11(trainingDir)) {
71635
+ const trainingDir = join13(homedir8(), ".hasna", "mementos", "training");
71636
+ if (!existsSync12(trainingDir)) {
71129
71637
  printError("No training data found. Run `mementos brains gather` first.");
71130
71638
  process.exit(1);
71131
71639
  }
@@ -71135,9 +71643,9 @@ function makeBrainsCommand() {
71135
71643
  printError("No JSONL training files found. Run `mementos brains gather` first.");
71136
71644
  process.exit(1);
71137
71645
  }
71138
- datasetPath = join12(trainingDir, latestFile);
71646
+ datasetPath = join13(trainingDir, latestFile);
71139
71647
  }
71140
- if (!datasetPath || !existsSync11(datasetPath)) {
71648
+ if (!datasetPath || !existsSync12(datasetPath)) {
71141
71649
  printError(`Dataset file not found: ${datasetPath ?? "(unresolved)"}`);
71142
71650
  process.exit(1);
71143
71651
  }
@@ -71263,8 +71771,8 @@ function registerAllCommands(program2) {
71263
71771
  // src/cli/index.tsx
71264
71772
  function getPackageVersion2() {
71265
71773
  try {
71266
- const pkgPath = join13(dirname8(fileURLToPath5(import.meta.url)), "..", "..", "package.json");
71267
- 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"));
71268
71776
  return pkg.version || "0.0.0";
71269
71777
  } catch {
71270
71778
  return "0.0.0";