@fgv/ts-agent-memory 5.1.0-36

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 (331) hide show
  1. package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +9 -0
  2. package/.rush/temp/f6a88bfdd66517ccb98c2c7ae1be6e6fe9e15d38.tar.log +282 -0
  3. package/.rush/temp/operation/build/all.log +9 -0
  4. package/.rush/temp/operation/build/log-chunks.jsonl +9 -0
  5. package/.rush/temp/operation/build/state.json +3 -0
  6. package/.rush/temp/shrinkwrap-deps.json +688 -0
  7. package/LICENSE +21 -0
  8. package/README.md +45 -0
  9. package/config/api-extractor.json +343 -0
  10. package/config/jest.config.json +14 -0
  11. package/config/rig.json +4 -0
  12. package/dist/index.js +12 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/packlets/converters/bodyConverterRegistry.js +51 -0
  15. package/dist/packlets/converters/bodyConverterRegistry.js.map +1 -0
  16. package/dist/packlets/converters/envelopeConverter.js +159 -0
  17. package/dist/packlets/converters/envelopeConverter.js.map +1 -0
  18. package/dist/packlets/converters/index.js +7 -0
  19. package/dist/packlets/converters/index.js.map +1 -0
  20. package/dist/packlets/index/index.js +6 -0
  21. package/dist/packlets/index/index.js.map +1 -0
  22. package/dist/packlets/index/memoryIndex.js +170 -0
  23. package/dist/packlets/index/memoryIndex.js.map +1 -0
  24. package/dist/packlets/observe/index.js +7 -0
  25. package/dist/packlets/observe/index.js.map +1 -0
  26. package/dist/packlets/observe/memoryObservationStore.js +119 -0
  27. package/dist/packlets/observe/memoryObservationStore.js.map +1 -0
  28. package/dist/packlets/observe/observer.js +6 -0
  29. package/dist/packlets/observe/observer.js.map +1 -0
  30. package/dist/packlets/retrieve/hybridRetriever.js +135 -0
  31. package/dist/packlets/retrieve/hybridRetriever.js.map +1 -0
  32. package/dist/packlets/retrieve/index.js +12 -0
  33. package/dist/packlets/retrieve/index.js.map +1 -0
  34. package/dist/packlets/retrieve/linkTraversalRetriever.js +143 -0
  35. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -0
  36. package/dist/packlets/retrieve/recencyRetriever.js +33 -0
  37. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -0
  38. package/dist/packlets/retrieve/retriever.js +110 -0
  39. package/dist/packlets/retrieve/retriever.js.map +1 -0
  40. package/dist/packlets/retrieve/semanticRetriever.js +86 -0
  41. package/dist/packlets/retrieve/semanticRetriever.js.map +1 -0
  42. package/dist/packlets/retrieve/structuredFilterRetriever.js +37 -0
  43. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -0
  44. package/dist/packlets/retrieve/tagRetriever.js +37 -0
  45. package/dist/packlets/retrieve/tagRetriever.js.map +1 -0
  46. package/dist/packlets/store/fileTreeMemoryStore.js +698 -0
  47. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -0
  48. package/dist/packlets/store/index.js +7 -0
  49. package/dist/packlets/store/index.js.map +1 -0
  50. package/dist/packlets/store/scopeEncoding.js +31 -0
  51. package/dist/packlets/store/scopeEncoding.js.map +1 -0
  52. package/dist/packlets/types/envelope.js +6 -0
  53. package/dist/packlets/types/envelope.js.map +1 -0
  54. package/dist/packlets/types/filenameSafety.js +52 -0
  55. package/dist/packlets/types/filenameSafety.js.map +1 -0
  56. package/dist/packlets/types/identityCodec.js +184 -0
  57. package/dist/packlets/types/identityCodec.js.map +1 -0
  58. package/dist/packlets/types/ids.js +67 -0
  59. package/dist/packlets/types/ids.js.map +1 -0
  60. package/dist/packlets/types/index.js +10 -0
  61. package/dist/packlets/types/index.js.map +1 -0
  62. package/dist/packlets/types/writePolicy.js +263 -0
  63. package/dist/packlets/types/writePolicy.js.map +1 -0
  64. package/dist/packlets/vector/inMemoryCosineIndex.js +150 -0
  65. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -0
  66. package/dist/packlets/vector/index.js +7 -0
  67. package/dist/packlets/vector/index.js.map +1 -0
  68. package/dist/packlets/vector/vectorIndex.js +6 -0
  69. package/dist/packlets/vector/vectorIndex.js.map +1 -0
  70. package/dist/test/unit/converters/bodyConverterRegistry.test.js +72 -0
  71. package/dist/test/unit/converters/bodyConverterRegistry.test.js.map +1 -0
  72. package/dist/test/unit/converters/envelopeConverter.test.js +196 -0
  73. package/dist/test/unit/converters/envelopeConverter.test.js.map +1 -0
  74. package/dist/test/unit/index/memoryIndex.test.js +152 -0
  75. package/dist/test/unit/index/memoryIndex.test.js.map +1 -0
  76. package/dist/test/unit/observe/memoryObservationStore.test.js +118 -0
  77. package/dist/test/unit/observe/memoryObservationStore.test.js.map +1 -0
  78. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +182 -0
  79. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -0
  80. package/dist/test/unit/retrieve/retrievers.test.js +506 -0
  81. package/dist/test/unit/retrieve/retrievers.test.js.map +1 -0
  82. package/dist/test/unit/store/embedOnWrite.test.js +260 -0
  83. package/dist/test/unit/store/embedOnWrite.test.js.map +1 -0
  84. package/dist/test/unit/store/fileTreeMemoryStore.test.js +647 -0
  85. package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +1 -0
  86. package/dist/test/unit/store/observations.test.js +239 -0
  87. package/dist/test/unit/store/observations.test.js.map +1 -0
  88. package/dist/test/unit/store/scopeEncoding.test.js +24 -0
  89. package/dist/test/unit/store/scopeEncoding.test.js.map +1 -0
  90. package/dist/test/unit/types/identityCodec.test.js +187 -0
  91. package/dist/test/unit/types/identityCodec.test.js.map +1 -0
  92. package/dist/test/unit/types/ids.test.js +84 -0
  93. package/dist/test/unit/types/ids.test.js.map +1 -0
  94. package/dist/test/unit/types/writePolicy.test.js +241 -0
  95. package/dist/test/unit/types/writePolicy.test.js.map +1 -0
  96. package/dist/test/unit/vector/inMemoryCosineIndex.test.js +192 -0
  97. package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -0
  98. package/dist/test/unit/vector/vectorIndex.test.js +42 -0
  99. package/dist/test/unit/vector/vectorIndex.test.js.map +1 -0
  100. package/dist/ts-agent-memory.d.ts +1901 -0
  101. package/dist/tsdoc-metadata.json +11 -0
  102. package/eslint.config.js +15 -0
  103. package/etc/ts-agent-memory.api.md +525 -0
  104. package/lib/index.d.ts +8 -0
  105. package/lib/index.d.ts.map +1 -0
  106. package/lib/index.js +28 -0
  107. package/lib/index.js.map +1 -0
  108. package/lib/packlets/converters/bodyConverterRegistry.d.ts +64 -0
  109. package/lib/packlets/converters/bodyConverterRegistry.d.ts.map +1 -0
  110. package/lib/packlets/converters/bodyConverterRegistry.js +55 -0
  111. package/lib/packlets/converters/bodyConverterRegistry.js.map +1 -0
  112. package/lib/packlets/converters/envelopeConverter.d.ts +70 -0
  113. package/lib/packlets/converters/envelopeConverter.d.ts.map +1 -0
  114. package/lib/packlets/converters/envelopeConverter.js +166 -0
  115. package/lib/packlets/converters/envelopeConverter.js.map +1 -0
  116. package/lib/packlets/converters/index.d.ts +3 -0
  117. package/lib/packlets/converters/index.d.ts.map +1 -0
  118. package/lib/packlets/converters/index.js +23 -0
  119. package/lib/packlets/converters/index.js.map +1 -0
  120. package/lib/packlets/index/index.d.ts +2 -0
  121. package/lib/packlets/index/index.d.ts.map +1 -0
  122. package/lib/packlets/index/index.js +22 -0
  123. package/lib/packlets/index/index.js.map +1 -0
  124. package/lib/packlets/index/memoryIndex.d.ts +127 -0
  125. package/lib/packlets/index/memoryIndex.d.ts.map +1 -0
  126. package/lib/packlets/index/memoryIndex.js +174 -0
  127. package/lib/packlets/index/memoryIndex.js.map +1 -0
  128. package/lib/packlets/observe/index.d.ts +3 -0
  129. package/lib/packlets/observe/index.d.ts.map +1 -0
  130. package/lib/packlets/observe/index.js +23 -0
  131. package/lib/packlets/observe/index.js.map +1 -0
  132. package/lib/packlets/observe/memoryObservationStore.d.ts +91 -0
  133. package/lib/packlets/observe/memoryObservationStore.d.ts.map +1 -0
  134. package/lib/packlets/observe/memoryObservationStore.js +123 -0
  135. package/lib/packlets/observe/memoryObservationStore.js.map +1 -0
  136. package/lib/packlets/observe/observer.d.ts +110 -0
  137. package/lib/packlets/observe/observer.d.ts.map +1 -0
  138. package/lib/packlets/observe/observer.js +7 -0
  139. package/lib/packlets/observe/observer.js.map +1 -0
  140. package/lib/packlets/retrieve/hybridRetriever.d.ts +79 -0
  141. package/lib/packlets/retrieve/hybridRetriever.d.ts.map +1 -0
  142. package/lib/packlets/retrieve/hybridRetriever.js +140 -0
  143. package/lib/packlets/retrieve/hybridRetriever.js.map +1 -0
  144. package/lib/packlets/retrieve/index.d.ts +8 -0
  145. package/lib/packlets/retrieve/index.d.ts.map +1 -0
  146. package/lib/packlets/retrieve/index.js +28 -0
  147. package/lib/packlets/retrieve/index.js.map +1 -0
  148. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +61 -0
  149. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -0
  150. package/lib/packlets/retrieve/linkTraversalRetriever.js +147 -0
  151. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -0
  152. package/lib/packlets/retrieve/recencyRetriever.d.ts +21 -0
  153. package/lib/packlets/retrieve/recencyRetriever.d.ts.map +1 -0
  154. package/lib/packlets/retrieve/recencyRetriever.js +37 -0
  155. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -0
  156. package/lib/packlets/retrieve/retriever.d.ts +133 -0
  157. package/lib/packlets/retrieve/retriever.d.ts.map +1 -0
  158. package/lib/packlets/retrieve/retriever.js +119 -0
  159. package/lib/packlets/retrieve/retriever.js.map +1 -0
  160. package/lib/packlets/retrieve/semanticRetriever.d.ts +69 -0
  161. package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -0
  162. package/lib/packlets/retrieve/semanticRetriever.js +90 -0
  163. package/lib/packlets/retrieve/semanticRetriever.js.map +1 -0
  164. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +22 -0
  165. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -0
  166. package/lib/packlets/retrieve/structuredFilterRetriever.js +41 -0
  167. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -0
  168. package/lib/packlets/retrieve/tagRetriever.d.ts +22 -0
  169. package/lib/packlets/retrieve/tagRetriever.d.ts.map +1 -0
  170. package/lib/packlets/retrieve/tagRetriever.js +41 -0
  171. package/lib/packlets/retrieve/tagRetriever.js.map +1 -0
  172. package/lib/packlets/store/fileTreeMemoryStore.d.ts +327 -0
  173. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -0
  174. package/lib/packlets/store/fileTreeMemoryStore.js +702 -0
  175. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -0
  176. package/lib/packlets/store/index.d.ts +3 -0
  177. package/lib/packlets/store/index.d.ts.map +1 -0
  178. package/lib/packlets/store/index.js +23 -0
  179. package/lib/packlets/store/index.js.map +1 -0
  180. package/lib/packlets/store/scopeEncoding.d.ts +19 -0
  181. package/lib/packlets/store/scopeEncoding.d.ts.map +1 -0
  182. package/lib/packlets/store/scopeEncoding.js +34 -0
  183. package/lib/packlets/store/scopeEncoding.js.map +1 -0
  184. package/lib/packlets/types/envelope.d.ts +119 -0
  185. package/lib/packlets/types/envelope.d.ts.map +1 -0
  186. package/lib/packlets/types/envelope.js +7 -0
  187. package/lib/packlets/types/envelope.js.map +1 -0
  188. package/lib/packlets/types/filenameSafety.d.ts +16 -0
  189. package/lib/packlets/types/filenameSafety.d.ts.map +1 -0
  190. package/lib/packlets/types/filenameSafety.js +55 -0
  191. package/lib/packlets/types/filenameSafety.js.map +1 -0
  192. package/lib/packlets/types/identityCodec.d.ts +136 -0
  193. package/lib/packlets/types/identityCodec.d.ts.map +1 -0
  194. package/lib/packlets/types/identityCodec.js +190 -0
  195. package/lib/packlets/types/identityCodec.js.map +1 -0
  196. package/lib/packlets/types/ids.d.ts +55 -0
  197. package/lib/packlets/types/ids.d.ts.map +1 -0
  198. package/lib/packlets/types/ids.js +70 -0
  199. package/lib/packlets/types/ids.js.map +1 -0
  200. package/lib/packlets/types/index.d.ts +6 -0
  201. package/lib/packlets/types/index.d.ts.map +1 -0
  202. package/lib/packlets/types/index.js +26 -0
  203. package/lib/packlets/types/index.js.map +1 -0
  204. package/lib/packlets/types/writePolicy.d.ts +213 -0
  205. package/lib/packlets/types/writePolicy.d.ts.map +1 -0
  206. package/lib/packlets/types/writePolicy.js +268 -0
  207. package/lib/packlets/types/writePolicy.js.map +1 -0
  208. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +69 -0
  209. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -0
  210. package/lib/packlets/vector/inMemoryCosineIndex.js +154 -0
  211. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -0
  212. package/lib/packlets/vector/index.d.ts +3 -0
  213. package/lib/packlets/vector/index.d.ts.map +1 -0
  214. package/lib/packlets/vector/index.js +23 -0
  215. package/lib/packlets/vector/index.js.map +1 -0
  216. package/lib/packlets/vector/vectorIndex.d.ts +68 -0
  217. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -0
  218. package/lib/packlets/vector/vectorIndex.js +7 -0
  219. package/lib/packlets/vector/vectorIndex.js.map +1 -0
  220. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts +2 -0
  221. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts.map +1 -0
  222. package/lib/test/unit/converters/bodyConverterRegistry.test.js +74 -0
  223. package/lib/test/unit/converters/bodyConverterRegistry.test.js.map +1 -0
  224. package/lib/test/unit/converters/envelopeConverter.test.d.ts +2 -0
  225. package/lib/test/unit/converters/envelopeConverter.test.d.ts.map +1 -0
  226. package/lib/test/unit/converters/envelopeConverter.test.js +198 -0
  227. package/lib/test/unit/converters/envelopeConverter.test.js.map +1 -0
  228. package/lib/test/unit/index/memoryIndex.test.d.ts +2 -0
  229. package/lib/test/unit/index/memoryIndex.test.d.ts.map +1 -0
  230. package/lib/test/unit/index/memoryIndex.test.js +154 -0
  231. package/lib/test/unit/index/memoryIndex.test.js.map +1 -0
  232. package/lib/test/unit/observe/memoryObservationStore.test.d.ts +2 -0
  233. package/lib/test/unit/observe/memoryObservationStore.test.d.ts.map +1 -0
  234. package/lib/test/unit/observe/memoryObservationStore.test.js +120 -0
  235. package/lib/test/unit/observe/memoryObservationStore.test.js.map +1 -0
  236. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts +2 -0
  237. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts.map +1 -0
  238. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +184 -0
  239. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -0
  240. package/lib/test/unit/retrieve/retrievers.test.d.ts +2 -0
  241. package/lib/test/unit/retrieve/retrievers.test.d.ts.map +1 -0
  242. package/lib/test/unit/retrieve/retrievers.test.js +508 -0
  243. package/lib/test/unit/retrieve/retrievers.test.js.map +1 -0
  244. package/lib/test/unit/store/embedOnWrite.test.d.ts +2 -0
  245. package/lib/test/unit/store/embedOnWrite.test.d.ts.map +1 -0
  246. package/lib/test/unit/store/embedOnWrite.test.js +262 -0
  247. package/lib/test/unit/store/embedOnWrite.test.js.map +1 -0
  248. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts +2 -0
  249. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts.map +1 -0
  250. package/lib/test/unit/store/fileTreeMemoryStore.test.js +649 -0
  251. package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +1 -0
  252. package/lib/test/unit/store/observations.test.d.ts +2 -0
  253. package/lib/test/unit/store/observations.test.d.ts.map +1 -0
  254. package/lib/test/unit/store/observations.test.js +241 -0
  255. package/lib/test/unit/store/observations.test.js.map +1 -0
  256. package/lib/test/unit/store/scopeEncoding.test.d.ts +2 -0
  257. package/lib/test/unit/store/scopeEncoding.test.d.ts.map +1 -0
  258. package/lib/test/unit/store/scopeEncoding.test.js +26 -0
  259. package/lib/test/unit/store/scopeEncoding.test.js.map +1 -0
  260. package/lib/test/unit/types/identityCodec.test.d.ts +2 -0
  261. package/lib/test/unit/types/identityCodec.test.d.ts.map +1 -0
  262. package/lib/test/unit/types/identityCodec.test.js +189 -0
  263. package/lib/test/unit/types/identityCodec.test.js.map +1 -0
  264. package/lib/test/unit/types/ids.test.d.ts +2 -0
  265. package/lib/test/unit/types/ids.test.d.ts.map +1 -0
  266. package/lib/test/unit/types/ids.test.js +86 -0
  267. package/lib/test/unit/types/ids.test.js.map +1 -0
  268. package/lib/test/unit/types/writePolicy.test.d.ts +2 -0
  269. package/lib/test/unit/types/writePolicy.test.d.ts.map +1 -0
  270. package/lib/test/unit/types/writePolicy.test.js +243 -0
  271. package/lib/test/unit/types/writePolicy.test.js.map +1 -0
  272. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts +2 -0
  273. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts.map +1 -0
  274. package/lib/test/unit/vector/inMemoryCosineIndex.test.js +194 -0
  275. package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -0
  276. package/lib/test/unit/vector/vectorIndex.test.d.ts +2 -0
  277. package/lib/test/unit/vector/vectorIndex.test.d.ts.map +1 -0
  278. package/lib/test/unit/vector/vectorIndex.test.js +44 -0
  279. package/lib/test/unit/vector/vectorIndex.test.js.map +1 -0
  280. package/package.json +81 -0
  281. package/rush-logs/ts-agent-memory.build.cache.log +3 -0
  282. package/rush-logs/ts-agent-memory.build.log +9 -0
  283. package/src/index.ts +12 -0
  284. package/src/packlets/converters/bodyConverterRegistry.ts +105 -0
  285. package/src/packlets/converters/envelopeConverter.ts +210 -0
  286. package/src/packlets/converters/index.ts +7 -0
  287. package/src/packlets/index/index.ts +6 -0
  288. package/src/packlets/index/memoryIndex.ts +268 -0
  289. package/src/packlets/observe/index.ts +7 -0
  290. package/src/packlets/observe/memoryObservationStore.ts +153 -0
  291. package/src/packlets/observe/observer.ts +119 -0
  292. package/src/packlets/retrieve/hybridRetriever.ts +181 -0
  293. package/src/packlets/retrieve/index.ts +12 -0
  294. package/src/packlets/retrieve/linkTraversalRetriever.ts +169 -0
  295. package/src/packlets/retrieve/recencyRetriever.ts +54 -0
  296. package/src/packlets/retrieve/retriever.ts +207 -0
  297. package/src/packlets/retrieve/semanticRetriever.ts +147 -0
  298. package/src/packlets/retrieve/structuredFilterRetriever.ts +58 -0
  299. package/src/packlets/retrieve/tagRetriever.ts +58 -0
  300. package/src/packlets/store/fileTreeMemoryStore.ts +1073 -0
  301. package/src/packlets/store/index.ts +7 -0
  302. package/src/packlets/store/scopeEncoding.ts +36 -0
  303. package/src/packlets/types/envelope.ts +138 -0
  304. package/src/packlets/types/filenameSafety.ts +57 -0
  305. package/src/packlets/types/identityCodec.ts +263 -0
  306. package/src/packlets/types/ids.ts +124 -0
  307. package/src/packlets/types/index.ts +10 -0
  308. package/src/packlets/types/writePolicy.ts +447 -0
  309. package/src/packlets/vector/inMemoryCosineIndex.ts +173 -0
  310. package/src/packlets/vector/index.ts +7 -0
  311. package/src/packlets/vector/vectorIndex.ts +78 -0
  312. package/src/test/unit/converters/bodyConverterRegistry.test.ts +89 -0
  313. package/src/test/unit/converters/envelopeConverter.test.ts +261 -0
  314. package/src/test/unit/index/memoryIndex.test.ts +187 -0
  315. package/src/test/unit/observe/memoryObservationStore.test.ts +158 -0
  316. package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +230 -0
  317. package/src/test/unit/retrieve/retrievers.test.ts +662 -0
  318. package/src/test/unit/store/embedOnWrite.test.ts +346 -0
  319. package/src/test/unit/store/fileTreeMemoryStore.test.ts +875 -0
  320. package/src/test/unit/store/observations.test.ts +290 -0
  321. package/src/test/unit/store/scopeEncoding.test.ts +37 -0
  322. package/src/test/unit/types/identityCodec.test.ts +266 -0
  323. package/src/test/unit/types/ids.test.ts +94 -0
  324. package/src/test/unit/types/writePolicy.test.ts +325 -0
  325. package/src/test/unit/vector/inMemoryCosineIndex.test.ts +242 -0
  326. package/src/test/unit/vector/vectorIndex.test.ts +48 -0
  327. package/temp/build/lint/_eslint-5eVG3S6w.json +182 -0
  328. package/temp/build/typescript/ts_8nwakTlr.json +1 -0
  329. package/temp/ts-agent-memory.api.json +12438 -0
  330. package/temp/ts-agent-memory.api.md +525 -0
  331. package/tsconfig.json +8 -0
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MemoryIndex = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ /** Shared empty key set for `byKind` / `byTag` misses (avoids per-call allocation). */
10
+ const EMPTY_KEY_SET = new Set();
11
+ /**
12
+ * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /
13
+ * `byTag` / `byRecency` / `backlinks` views incrementally; a `'put'` for an
14
+ * already-indexed key first removes the prior entry's associations so a changed
15
+ * kind / tag / link set never leaves a stale reference behind.
16
+ * @public
17
+ */
18
+ class MemoryIndex {
19
+ constructor() {
20
+ this._byKey = new Map();
21
+ this._byKind = new Map();
22
+ this._byTag = new Map();
23
+ this._backlinks = new Map();
24
+ }
25
+ /** Family-convention factory. */
26
+ static create() {
27
+ return (0, ts_utils_1.succeed)(new MemoryIndex());
28
+ }
29
+ /**
30
+ * The composite primary key for an entry: scope + id, NUL-separated. NUL
31
+ * is excluded from both components (scope segments pass
32
+ * `assertPortableFilenameStem`; `MemoryId` is portable-filename-safe), so it
33
+ * is a collision-proof separator across every scope/id pair the codecs produce.
34
+ */
35
+ static _keyOf(scope, id) {
36
+ return `${scope}\0${id}`;
37
+ }
38
+ /** {@inheritDoc IMemoryIndex.rebuild} */
39
+ rebuild(entries) {
40
+ this._byKey.clear();
41
+ this._byKind.clear();
42
+ this._byTag.clear();
43
+ this._backlinks.clear();
44
+ for (const entry of entries) {
45
+ this._add(entry);
46
+ }
47
+ return (0, ts_utils_1.succeed)(this._byKey.size);
48
+ }
49
+ /** {@inheritDoc IMemoryIndex.patch} */
50
+ patch(op, entry) {
51
+ const key = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);
52
+ // Always drop any prior associations for this key first, so a 'put' that
53
+ // changes kind/tags/links cannot strand a stale reference.
54
+ this._remove(key);
55
+ if (op === 'put') {
56
+ this._add(entry);
57
+ }
58
+ return (0, ts_utils_1.succeed)(entry);
59
+ }
60
+ /** {@inheritDoc IMemoryIndex.entries} */
61
+ entries() {
62
+ return Array.from(this._byKey.values());
63
+ }
64
+ /** {@inheritDoc IMemoryIndex.byKind} */
65
+ byKind(kind) {
66
+ var _a;
67
+ return this._recencyOrdered((_a = this._byKind.get(kind)) !== null && _a !== void 0 ? _a : EMPTY_KEY_SET);
68
+ }
69
+ /** {@inheritDoc IMemoryIndex.byTag} */
70
+ byTag(tag) {
71
+ var _a;
72
+ return this._recencyOrdered((_a = this._byTag.get(tag)) !== null && _a !== void 0 ? _a : EMPTY_KEY_SET);
73
+ }
74
+ /** {@inheritDoc IMemoryIndex.byRecency} */
75
+ byRecency() {
76
+ return this._recencyOrdered(this._byKey.keys());
77
+ }
78
+ /** {@inheritDoc IMemoryIndex.backlinks} */
79
+ backlinks(target) {
80
+ const sources = this._backlinks.get(target);
81
+ return sources === undefined ? [] : Array.from(sources.values());
82
+ }
83
+ /**
84
+ * Resolve a set of composite keys to their records, ordered
85
+ * most-recently-updated first (with a `seq` tiebreak so equal-`updated`
86
+ * records sort deterministically).
87
+ */
88
+ _recencyOrdered(keys) {
89
+ const records = [];
90
+ for (const key of keys) {
91
+ const entry = this._byKey.get(key);
92
+ if (entry !== undefined) {
93
+ records.push(entry.record);
94
+ }
95
+ }
96
+ return records.sort((a, b) => {
97
+ const byUpdated = b.envelope.updated - a.envelope.updated;
98
+ return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;
99
+ });
100
+ }
101
+ /** Insert an entry and register all its derived associations. */
102
+ _add(entry) {
103
+ const key = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);
104
+ const envelope = entry.record.envelope;
105
+ this._byKey.set(key, entry);
106
+ this._addToSetMap(this._byKind, envelope.kind, key);
107
+ for (const tag of envelope.tags) {
108
+ this._addToSetMap(this._byTag, tag, key);
109
+ }
110
+ for (const edge of envelope.links) {
111
+ this._addBacklink(edge.target, key, envelope.id);
112
+ }
113
+ }
114
+ /** Remove the entry at `key` (if present) and all its derived associations. */
115
+ _remove(key) {
116
+ const entry = this._byKey.get(key);
117
+ if (entry === undefined) {
118
+ return;
119
+ }
120
+ const envelope = entry.record.envelope;
121
+ this._byKey.delete(key);
122
+ this._removeFromSetMap(this._byKind, envelope.kind, key);
123
+ for (const tag of envelope.tags) {
124
+ this._removeFromSetMap(this._byTag, tag, key);
125
+ }
126
+ for (const edge of envelope.links) {
127
+ this._removeBacklink(edge.target, key);
128
+ }
129
+ }
130
+ /** Register `sourceId` (keyed by its composite `sourceKey`) as linking at `target`. */
131
+ _addBacklink(target, sourceKey, sourceId) {
132
+ const existing = this._backlinks.get(target);
133
+ if (existing === undefined) {
134
+ this._backlinks.set(target, new Map([[sourceKey, sourceId]]));
135
+ }
136
+ else {
137
+ existing.set(sourceKey, sourceId);
138
+ }
139
+ }
140
+ /** Drop the backlink from `sourceKey` to `target`, removing the target map when empty. */
141
+ _removeBacklink(target, sourceKey) {
142
+ const existing = this._backlinks.get(target);
143
+ if (existing === undefined) {
144
+ return;
145
+ }
146
+ existing.delete(sourceKey);
147
+ if (existing.size === 0) {
148
+ this._backlinks.delete(target);
149
+ }
150
+ }
151
+ /** Add `member` to the set at `mapKey`, creating the set on first use. */
152
+ _addToSetMap(map, mapKey, member) {
153
+ const existing = map.get(mapKey);
154
+ if (existing === undefined) {
155
+ map.set(mapKey, new Set([member]));
156
+ }
157
+ else {
158
+ existing.add(member);
159
+ }
160
+ }
161
+ /** Remove `member` from the set at `mapKey`, dropping the set when empty. */
162
+ _removeFromSetMap(map, mapKey, member) {
163
+ const existing = map.get(mapKey);
164
+ if (existing === undefined) {
165
+ return;
166
+ }
167
+ existing.delete(member);
168
+ if (existing.size === 0) {
169
+ map.delete(mapKey);
170
+ }
171
+ }
172
+ }
173
+ exports.MemoryIndex = MemoryIndex;
174
+ //# sourceMappingURL=memoryIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../../../src/packlets/index/memoryIndex.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord, Kind, MemoryId, MemoryScopeKey, Tag } from '../types';\n\n/**\n * The mutation a {@link IMemoryIndex.patch | patch} applies: a record was\n * written (`'put'`) or removed (`'delete'`).\n * @public\n */\nexport type MemoryIndexPatchOp = 'put' | 'delete';\n\n/** Shared empty key set for `byKind` / `byTag` misses (avoids per-call allocation). */\nconst EMPTY_KEY_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * A memory record paired with the {@link MemoryScopeKey | scope} it lives\n * under. The scope is not carried on the {@link IMemoryEnvelope} (it is derived\n * from the entity id by the codec), so the store threads it alongside the\n * record when patching or rebuilding the index. The `(scope, id)` pair is the\n * index's primary key, keeping records distinct across scopes that reuse a\n * filename stem (e.g. `turn-0` under different conversations in Phase C).\n * @public\n */\nexport interface IIndexedMemoryRecord {\n /** The scope the record is stored under. */\n readonly scope: MemoryScopeKey;\n /** The memory record itself. */\n readonly record: IMemoryRecord<unknown>;\n}\n\n/**\n * The derived, in-memory secondary indexes the store maintains over its\n * records. Never the source of truth — the FileTree is. The index is fully\n * rebuildable from a walk of the store ({@link IMemoryIndex.rebuild}) and is\n * patched incrementally on every write ({@link IMemoryIndex.patch}).\n *\n * @remarks\n * B1 builds the maps; link-traversal BFS over {@link IMemoryIndex.backlinks}\n * is B2. The accessors return records (not bare ids) so the B2 retrievers can\n * consume them directly.\n * @public\n */\nexport interface IMemoryIndex {\n /**\n * Replace the entire index from a full set of records (a store walk).\n * @returns The number of records indexed.\n */\n rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number>;\n\n /**\n * Apply a single incremental change. `'put'` inserts or replaces the entry\n * at its `(scope, id)` key (removing any prior associations first); `'delete'`\n * removes it.\n * @returns The entry that was applied.\n */\n patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord>;\n\n /** Every indexed entry (scope + record). Primary read surface for the store. */\n entries(): ReadonlyArray<IIndexedMemoryRecord>;\n\n /** Records of the given kind, in recency order (most-recently-updated first). */\n byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /** Records carrying the given tag, in recency order. */\n byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /** All records in recency order (most-recently-updated first). */\n byRecency(): ReadonlyArray<IMemoryRecord<unknown>>;\n\n /**\n * The ids of records whose `links` point AT `target` (inbound edges).\n * The seed map for B2 link-traversal.\n */\n backlinks(target: MemoryId): ReadonlyArray<MemoryId>;\n}\n\n/**\n * Default in-memory {@link IMemoryIndex}. Maintains the derived `byKind` /\n * `byTag` / `byRecency` / `backlinks` views incrementally; a `'put'` for an\n * already-indexed key first removes the prior entry's associations so a changed\n * kind / tag / link set never leaves a stale reference behind.\n * @public\n */\nexport class MemoryIndex implements IMemoryIndex {\n /** Primary store: `(scope, id)` composite key → indexed entry. */\n private readonly _byKey: Map<string, IIndexedMemoryRecord>;\n /** kind → set of composite keys. */\n private readonly _byKind: Map<Kind, Set<string>>;\n /** tag → set of composite keys. */\n private readonly _byTag: Map<Tag, Set<string>>;\n /**\n * link target id → (source composite key → source id). Keyed by the source's\n * `(scope, id)` composite — NOT its bare id — so two distinct source records\n * that share an id across scopes (e.g. `turn-0` in different conversations)\n * are tracked independently and removing one never drops the other's edge.\n */\n private readonly _backlinks: Map<MemoryId, Map<string, MemoryId>>;\n\n private constructor() {\n this._byKey = new Map<string, IIndexedMemoryRecord>();\n this._byKind = new Map<Kind, Set<string>>();\n this._byTag = new Map<Tag, Set<string>>();\n this._backlinks = new Map<MemoryId, Map<string, MemoryId>>();\n }\n\n /** Family-convention factory. */\n public static create(): Result<MemoryIndex> {\n return succeed(new MemoryIndex());\n }\n\n /**\n * The composite primary key for an entry: scope + id, NUL-separated. NUL\n * is excluded from both components (scope segments pass\n * `assertPortableFilenameStem`; `MemoryId` is portable-filename-safe), so it\n * is a collision-proof separator across every scope/id pair the codecs produce.\n */\n private static _keyOf(scope: MemoryScopeKey, id: MemoryId): string {\n return `${scope}\\0${id}`;\n }\n\n /** {@inheritDoc IMemoryIndex.rebuild} */\n public rebuild(entries: ReadonlyArray<IIndexedMemoryRecord>): Result<number> {\n this._byKey.clear();\n this._byKind.clear();\n this._byTag.clear();\n this._backlinks.clear();\n for (const entry of entries) {\n this._add(entry);\n }\n return succeed(this._byKey.size);\n }\n\n /** {@inheritDoc IMemoryIndex.patch} */\n public patch(op: MemoryIndexPatchOp, entry: IIndexedMemoryRecord): Result<IIndexedMemoryRecord> {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);\n // Always drop any prior associations for this key first, so a 'put' that\n // changes kind/tags/links cannot strand a stale reference.\n this._remove(key);\n if (op === 'put') {\n this._add(entry);\n }\n return succeed(entry);\n }\n\n /** {@inheritDoc IMemoryIndex.entries} */\n public entries(): ReadonlyArray<IIndexedMemoryRecord> {\n return Array.from(this._byKey.values());\n }\n\n /** {@inheritDoc IMemoryIndex.byKind} */\n public byKind(kind: Kind): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byKind.get(kind) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byTag} */\n public byTag(tag: Tag): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byTag.get(tag) ?? EMPTY_KEY_SET);\n }\n\n /** {@inheritDoc IMemoryIndex.byRecency} */\n public byRecency(): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._recencyOrdered(this._byKey.keys());\n }\n\n /** {@inheritDoc IMemoryIndex.backlinks} */\n public backlinks(target: MemoryId): ReadonlyArray<MemoryId> {\n const sources: Map<string, MemoryId> | undefined = this._backlinks.get(target);\n return sources === undefined ? [] : Array.from(sources.values());\n }\n\n /**\n * Resolve a set of composite keys to their records, ordered\n * most-recently-updated first (with a `seq` tiebreak so equal-`updated`\n * records sort deterministically).\n */\n private _recencyOrdered(keys: Iterable<string>): ReadonlyArray<IMemoryRecord<unknown>> {\n const records: IMemoryRecord<unknown>[] = [];\n for (const key of keys) {\n const entry: IIndexedMemoryRecord | undefined = this._byKey.get(key);\n if (entry !== undefined) {\n records.push(entry.record);\n }\n }\n return records.sort((a, b) => {\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n });\n }\n\n /** Insert an entry and register all its derived associations. */\n private _add(entry: IIndexedMemoryRecord): void {\n const key: string = MemoryIndex._keyOf(entry.scope, entry.record.envelope.id);\n const envelope: IMemoryRecord<unknown>['envelope'] = entry.record.envelope;\n this._byKey.set(key, entry);\n this._addToSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._addToSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._addBacklink(edge.target, key, envelope.id);\n }\n }\n\n /** Remove the entry at `key` (if present) and all its derived associations. */\n private _remove(key: string): void {\n const entry: IIndexedMemoryRecord | undefined = this._byKey.get(key);\n if (entry === undefined) {\n return;\n }\n const envelope: IMemoryRecord<unknown>['envelope'] = entry.record.envelope;\n this._byKey.delete(key);\n this._removeFromSetMap(this._byKind, envelope.kind, key);\n for (const tag of envelope.tags) {\n this._removeFromSetMap(this._byTag, tag, key);\n }\n for (const edge of envelope.links) {\n this._removeBacklink(edge.target, key);\n }\n }\n\n /** Register `sourceId` (keyed by its composite `sourceKey`) as linking at `target`. */\n private _addBacklink(target: MemoryId, sourceKey: string, sourceId: MemoryId): void {\n const existing: Map<string, MemoryId> | undefined = this._backlinks.get(target);\n if (existing === undefined) {\n this._backlinks.set(target, new Map<string, MemoryId>([[sourceKey, sourceId]]));\n } else {\n existing.set(sourceKey, sourceId);\n }\n }\n\n /** Drop the backlink from `sourceKey` to `target`, removing the target map when empty. */\n private _removeBacklink(target: MemoryId, sourceKey: string): void {\n const existing: Map<string, MemoryId> | undefined = this._backlinks.get(target);\n if (existing === undefined) {\n return;\n }\n existing.delete(sourceKey);\n if (existing.size === 0) {\n this._backlinks.delete(target);\n }\n }\n\n /** Add `member` to the set at `mapKey`, creating the set on first use. */\n private _addToSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n map.set(mapKey, new Set<M>([member]));\n } else {\n existing.add(member);\n }\n }\n\n /** Remove `member` from the set at `mapKey`, dropping the set when empty. */\n private _removeFromSetMap<K, M>(map: Map<K, Set<M>>, mapKey: K, member: M): void {\n const existing: Set<M> | undefined = map.get(mapKey);\n if (existing === undefined) {\n return;\n }\n existing.delete(member);\n if (existing.size === 0) {\n map.delete(mapKey);\n }\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './observer';
2
+ export * from './memoryObservationStore';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/observe/index.ts"],"names":[],"mappings":"AAKA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ __exportStar(require("./observer"), exports);
22
+ __exportStar(require("./memoryObservationStore"), exports);
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/observe/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,2DAAyC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './observer';\nexport * from './memoryObservationStore';\n"]}
@@ -0,0 +1,91 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { IMemoryObservationQuery, IMemoryObservationRecord, IMemoryObserver } from './observer';
3
+ /**
4
+ * Construction options for {@link MemoryObservationStore.create}.
5
+ * @public
6
+ */
7
+ export interface IMemoryObservationStoreCreateParams {
8
+ /**
9
+ * Maximum number of observation records retained before the oldest is
10
+ * overwritten. Defaults to `1000`. Must be a positive integer if supplied.
11
+ */
12
+ readonly maxRecords?: number;
13
+ }
14
+ /**
15
+ * The default in-memory observation store: an {@link IMemoryObserver} that
16
+ * retains the records it observes in a bounded ring and answers schema-aware
17
+ * {@link MemoryObservationStore.query | queries} over them.
18
+ *
19
+ * @remarks
20
+ * **Privacy posture — this store is most-permissive by design.** It retains
21
+ * every field of every record verbatim, including any `provenance` and
22
+ * `querySnapshot`. The library bakes in **no** redaction, retention, or
23
+ * field-stripping policy — that is deployment policy, not library policy. A
24
+ * deployment that must redact wraps this store with its own
25
+ * {@link IMemoryObserver} that transforms records before forwarding, or
26
+ * substitutes a different observer entirely. Size is the only bounded
27
+ * dimension, via `maxRecords`.
28
+ *
29
+ * The store composes `RetainingRingBuffer` from `@fgv/ts-utils` (it does not
30
+ * hand-roll a ring) and implements {@link IMemoryObserver} directly — `observe`
31
+ * (the hook) and `query` (the read surface) live on the same class. Wire it via
32
+ * {@link IFileTreeMemoryStoreCreateParams.observers}. `seq` and `timestamp` are
33
+ * assigned by the firing authority (the store) before `observe`, so this store
34
+ * never mints them.
35
+ * @public
36
+ */
37
+ export declare class MemoryObservationStore implements IMemoryObserver {
38
+ /**
39
+ * The bounded ring of observed records. The firing authority assigns each
40
+ * record's `seq`, so the ring's monotonic-`seq` cursor contract is satisfied
41
+ * by that authority's per-instance counter.
42
+ * @internal
43
+ */
44
+ private readonly _buffer;
45
+ /**
46
+ * @param buffer - The pre-constructed backing ring buffer.
47
+ * @internal
48
+ */
49
+ private constructor();
50
+ /**
51
+ * The highest `seq` observed so far. Hold this value and pass it as
52
+ * `sinceSeq` to {@link MemoryObservationStore.query | query} to page only
53
+ * records observed afterward. Stable across ring eviction and
54
+ * {@link MemoryObservationStore.clear | clear}.
55
+ */
56
+ get lastSeq(): number;
57
+ /**
58
+ * The number of records currently retained.
59
+ */
60
+ get size(): number;
61
+ /**
62
+ * Family-convention factory.
63
+ * @param params - {@link IMemoryObservationStoreCreateParams | Construction options}.
64
+ * @returns On success, a new store. Fails if `maxRecords` is supplied and is
65
+ * not a positive integer.
66
+ */
67
+ static create(params?: IMemoryObservationStoreCreateParams): Result<MemoryObservationStore>;
68
+ /**
69
+ * {@inheritDoc IMemoryObserver.observe}
70
+ */
71
+ observe(record: IMemoryObservationRecord): Promise<Result<unknown>>;
72
+ /**
73
+ * Returns retained records, oldest-first, narrowed by the supplied criteria.
74
+ * @param criteria - {@link IMemoryObservationQuery | AND-combined filter criteria}.
75
+ * @returns The matching records, oldest-first.
76
+ */
77
+ query(criteria?: IMemoryObservationQuery): ReadonlyArray<IMemoryObservationRecord>;
78
+ /**
79
+ * Clears all retained records. Does NOT reset
80
+ * {@link MemoryObservationStore.lastSeq | lastSeq}, so a held `sinceSeq`
81
+ * cursor never re-sees a sequence number.
82
+ */
83
+ clear(): void;
84
+ /**
85
+ * Tests a record against the non-`seq`/`limit` criteria (those are applied by
86
+ * the ring buffer itself).
87
+ * @internal
88
+ */
89
+ private static _matches;
90
+ }
91
+ //# sourceMappingURL=memoryObservationStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryObservationStore.d.ts","sourceRoot":"","sources":["../../../src/packlets/observe/memoryObservationStore.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,MAAM,EAAiB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEhG;;;GAGG;AACH,MAAM,WAAW,mCAAmC;IAClD;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAC5D;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4D;IAEpF;;;OAGG;IACH,OAAO;IAIP;;;;;OAKG;IACH,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;;;;OAKG;WACW,MAAM,CAAC,MAAM,CAAC,EAAE,mCAAmC,GAAG,MAAM,CAAC,sBAAsB,CAAC;IAYlG;;OAEG;IACI,OAAO,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAK1E;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,EAAE,uBAAuB,GAAG,aAAa,CAAC,wBAAwB,CAAC;IASzF;;;;OAIG;IACI,KAAK,IAAI,IAAI;IAIpB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;CAqBxB"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MemoryObservationStore = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ /**
10
+ * The default in-memory observation store: an {@link IMemoryObserver} that
11
+ * retains the records it observes in a bounded ring and answers schema-aware
12
+ * {@link MemoryObservationStore.query | queries} over them.
13
+ *
14
+ * @remarks
15
+ * **Privacy posture — this store is most-permissive by design.** It retains
16
+ * every field of every record verbatim, including any `provenance` and
17
+ * `querySnapshot`. The library bakes in **no** redaction, retention, or
18
+ * field-stripping policy — that is deployment policy, not library policy. A
19
+ * deployment that must redact wraps this store with its own
20
+ * {@link IMemoryObserver} that transforms records before forwarding, or
21
+ * substitutes a different observer entirely. Size is the only bounded
22
+ * dimension, via `maxRecords`.
23
+ *
24
+ * The store composes `RetainingRingBuffer` from `@fgv/ts-utils` (it does not
25
+ * hand-roll a ring) and implements {@link IMemoryObserver} directly — `observe`
26
+ * (the hook) and `query` (the read surface) live on the same class. Wire it via
27
+ * {@link IFileTreeMemoryStoreCreateParams.observers}. `seq` and `timestamp` are
28
+ * assigned by the firing authority (the store) before `observe`, so this store
29
+ * never mints them.
30
+ * @public
31
+ */
32
+ class MemoryObservationStore {
33
+ /**
34
+ * @param buffer - The pre-constructed backing ring buffer.
35
+ * @internal
36
+ */
37
+ constructor(buffer) {
38
+ this._buffer = buffer;
39
+ }
40
+ /**
41
+ * The highest `seq` observed so far. Hold this value and pass it as
42
+ * `sinceSeq` to {@link MemoryObservationStore.query | query} to page only
43
+ * records observed afterward. Stable across ring eviction and
44
+ * {@link MemoryObservationStore.clear | clear}.
45
+ */
46
+ get lastSeq() {
47
+ return this._buffer.lastSeq;
48
+ }
49
+ /**
50
+ * The number of records currently retained.
51
+ */
52
+ get size() {
53
+ return this._buffer.size;
54
+ }
55
+ /**
56
+ * Family-convention factory.
57
+ * @param params - {@link IMemoryObservationStoreCreateParams | Construction options}.
58
+ * @returns On success, a new store. Fails if `maxRecords` is supplied and is
59
+ * not a positive integer.
60
+ */
61
+ static create(params) {
62
+ const maxRecords = params === null || params === void 0 ? void 0 : params.maxRecords;
63
+ if (maxRecords !== undefined && (!Number.isInteger(maxRecords) || maxRecords < 1)) {
64
+ return (0, ts_utils_1.fail)(`MemoryObservationStore: maxRecords must be a positive integer (got ${maxRecords})`);
65
+ }
66
+ return (0, ts_utils_1.succeed)(new MemoryObservationStore(new ts_utils_1.Collections.RetainingRingBuffer({ maxRecords })));
67
+ }
68
+ /**
69
+ * {@inheritDoc IMemoryObserver.observe}
70
+ */
71
+ observe(record) {
72
+ this._buffer.push(record);
73
+ return Promise.resolve((0, ts_utils_1.succeed)(record));
74
+ }
75
+ /**
76
+ * Returns retained records, oldest-first, narrowed by the supplied criteria.
77
+ * @param criteria - {@link IMemoryObservationQuery | AND-combined filter criteria}.
78
+ * @returns The matching records, oldest-first.
79
+ */
80
+ query(criteria) {
81
+ return this._buffer.query({
82
+ sinceSeq: criteria === null || criteria === void 0 ? void 0 : criteria.sinceSeq,
83
+ limit: criteria === null || criteria === void 0 ? void 0 : criteria.limit,
84
+ filter: criteria === undefined ? undefined : (record) => MemoryObservationStore._matches(record, criteria)
85
+ });
86
+ }
87
+ /**
88
+ * Clears all retained records. Does NOT reset
89
+ * {@link MemoryObservationStore.lastSeq | lastSeq}, so a held `sinceSeq`
90
+ * cursor never re-sees a sequence number.
91
+ */
92
+ clear() {
93
+ this._buffer.clear();
94
+ }
95
+ /**
96
+ * Tests a record against the non-`seq`/`limit` criteria (those are applied by
97
+ * the ring buffer itself).
98
+ * @internal
99
+ */
100
+ static _matches(record, criteria) {
101
+ if (criteria.since !== undefined && record.timestamp < criteria.since) {
102
+ return false;
103
+ }
104
+ if (criteria.until !== undefined && record.timestamp > criteria.until) {
105
+ return false;
106
+ }
107
+ if (criteria.scope !== undefined && record.scope !== criteria.scope) {
108
+ return false;
109
+ }
110
+ if (criteria.kind !== undefined && record.kind !== criteria.kind) {
111
+ return false;
112
+ }
113
+ if (criteria.phase !== undefined && record.phase !== criteria.phase) {
114
+ return false;
115
+ }
116
+ if (criteria.outcome !== undefined && record.outcome !== criteria.outcome) {
117
+ return false;
118
+ }
119
+ return true;
120
+ }
121
+ }
122
+ exports.MemoryObservationStore = MemoryObservationStore;
123
+ //# sourceMappingURL=memoryObservationStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryObservationStore.js","sourceRoot":"","sources":["../../../src/packlets/observe/memoryObservationStore.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Collections, Result, fail, succeed } from '@fgv/ts-utils';\nimport { IMemoryObservationQuery, IMemoryObservationRecord, IMemoryObserver } from './observer';\n\n/**\n * Construction options for {@link MemoryObservationStore.create}.\n * @public\n */\nexport interface IMemoryObservationStoreCreateParams {\n /**\n * Maximum number of observation records retained before the oldest is\n * overwritten. Defaults to `1000`. Must be a positive integer if supplied.\n */\n readonly maxRecords?: number;\n}\n\n/**\n * The default in-memory observation store: an {@link IMemoryObserver} that\n * retains the records it observes in a bounded ring and answers schema-aware\n * {@link MemoryObservationStore.query | queries} over them.\n *\n * @remarks\n * **Privacy posture — this store is most-permissive by design.** It retains\n * every field of every record verbatim, including any `provenance` and\n * `querySnapshot`. The library bakes in **no** redaction, retention, or\n * field-stripping policy — that is deployment policy, not library policy. A\n * deployment that must redact wraps this store with its own\n * {@link IMemoryObserver} that transforms records before forwarding, or\n * substitutes a different observer entirely. Size is the only bounded\n * dimension, via `maxRecords`.\n *\n * The store composes `RetainingRingBuffer` from `@fgv/ts-utils` (it does not\n * hand-roll a ring) and implements {@link IMemoryObserver} directly — `observe`\n * (the hook) and `query` (the read surface) live on the same class. Wire it via\n * {@link IFileTreeMemoryStoreCreateParams.observers}. `seq` and `timestamp` are\n * assigned by the firing authority (the store) before `observe`, so this store\n * never mints them.\n * @public\n */\nexport class MemoryObservationStore implements IMemoryObserver {\n /**\n * The bounded ring of observed records. The firing authority assigns each\n * record's `seq`, so the ring's monotonic-`seq` cursor contract is satisfied\n * by that authority's per-instance counter.\n * @internal\n */\n private readonly _buffer: Collections.RetainingRingBuffer<IMemoryObservationRecord>;\n\n /**\n * @param buffer - The pre-constructed backing ring buffer.\n * @internal\n */\n private constructor(buffer: Collections.RetainingRingBuffer<IMemoryObservationRecord>) {\n this._buffer = buffer;\n }\n\n /**\n * The highest `seq` observed so far. Hold this value and pass it as\n * `sinceSeq` to {@link MemoryObservationStore.query | query} to page only\n * records observed afterward. Stable across ring eviction and\n * {@link MemoryObservationStore.clear | clear}.\n */\n public get lastSeq(): number {\n return this._buffer.lastSeq;\n }\n\n /**\n * The number of records currently retained.\n */\n public get size(): number {\n return this._buffer.size;\n }\n\n /**\n * Family-convention factory.\n * @param params - {@link IMemoryObservationStoreCreateParams | Construction options}.\n * @returns On success, a new store. Fails if `maxRecords` is supplied and is\n * not a positive integer.\n */\n public static create(params?: IMemoryObservationStoreCreateParams): Result<MemoryObservationStore> {\n const maxRecords: number | undefined = params?.maxRecords;\n if (maxRecords !== undefined && (!Number.isInteger(maxRecords) || maxRecords < 1)) {\n return fail(`MemoryObservationStore: maxRecords must be a positive integer (got ${maxRecords})`);\n }\n return succeed(\n new MemoryObservationStore(\n new Collections.RetainingRingBuffer<IMemoryObservationRecord>({ maxRecords })\n )\n );\n }\n\n /**\n * {@inheritDoc IMemoryObserver.observe}\n */\n public observe(record: IMemoryObservationRecord): Promise<Result<unknown>> {\n this._buffer.push(record);\n return Promise.resolve(succeed(record));\n }\n\n /**\n * Returns retained records, oldest-first, narrowed by the supplied criteria.\n * @param criteria - {@link IMemoryObservationQuery | AND-combined filter criteria}.\n * @returns The matching records, oldest-first.\n */\n public query(criteria?: IMemoryObservationQuery): ReadonlyArray<IMemoryObservationRecord> {\n return this._buffer.query({\n sinceSeq: criteria?.sinceSeq,\n limit: criteria?.limit,\n filter:\n criteria === undefined ? undefined : (record) => MemoryObservationStore._matches(record, criteria)\n });\n }\n\n /**\n * Clears all retained records. Does NOT reset\n * {@link MemoryObservationStore.lastSeq | lastSeq}, so a held `sinceSeq`\n * cursor never re-sees a sequence number.\n */\n public clear(): void {\n this._buffer.clear();\n }\n\n /**\n * Tests a record against the non-`seq`/`limit` criteria (those are applied by\n * the ring buffer itself).\n * @internal\n */\n private static _matches(record: IMemoryObservationRecord, criteria: IMemoryObservationQuery): boolean {\n if (criteria.since !== undefined && record.timestamp < criteria.since) {\n return false;\n }\n if (criteria.until !== undefined && record.timestamp > criteria.until) {\n return false;\n }\n if (criteria.scope !== undefined && record.scope !== criteria.scope) {\n return false;\n }\n if (criteria.kind !== undefined && record.kind !== criteria.kind) {\n return false;\n }\n if (criteria.phase !== undefined && record.phase !== criteria.phase) {\n return false;\n }\n if (criteria.outcome !== undefined && record.outcome !== criteria.outcome) {\n return false;\n }\n return true;\n }\n}\n"]}
@@ -0,0 +1,110 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { IProvenance, Kind, MemoryId, MemoryScopeKey } from '../types';
3
+ /**
4
+ * The store/retriever operation an observation record describes.
5
+ *
6
+ * @remarks
7
+ * `'read'` / `'write'` / `'delete'` are fired post-op by
8
+ * {@link FileTreeMemoryStore} (on `get` / `put` / `delete` respectively) when
9
+ * observers are wired. `'retrieve'` is reserved for retriever-fired
10
+ * observations; no B2 retriever fires one (a single seq authority per
11
+ * observation store is the supported topology), so it never appears in B2 but
12
+ * is part of the vocabulary so a future retriever-firing hook is additive.
13
+ * @public
14
+ */
15
+ export type MemoryObservationPhase = 'read' | 'write' | 'delete' | 'retrieve';
16
+ /**
17
+ * The outcome of the observed operation.
18
+ * @public
19
+ */
20
+ export type MemoryObservationOutcome = 'success' | 'failure';
21
+ /**
22
+ * A single audit record produced by an observed store (or retriever) operation.
23
+ *
24
+ * @remarks
25
+ * `seq` and `timestamp` are assigned by the firing authority (the store) before
26
+ * fan-out, so the same record carries the same `seq` across every observer it
27
+ * lands in. `seq` is strictly increasing per authority, satisfying the
28
+ * `RetainingRingBuffer` cursor contract that {@link MemoryObservationStore}
29
+ * relies on.
30
+ * @public
31
+ */
32
+ export interface IMemoryObservationRecord {
33
+ /**
34
+ * Monotonic 1-based sequence number assigned by the firing authority, stable
35
+ * across a store's ring eviction. The ordering / paging key.
36
+ */
37
+ readonly seq: number;
38
+ /** Milliseconds since epoch when the firing authority produced the record. */
39
+ readonly timestamp: number;
40
+ /** Which operation this record describes. */
41
+ readonly phase: MemoryObservationPhase;
42
+ /** The scope the operation touched, when resolvable. */
43
+ readonly scope?: MemoryScopeKey;
44
+ /** The record id the operation touched, when resolvable. */
45
+ readonly id?: MemoryId;
46
+ /** The kind the operation targeted, when known. */
47
+ readonly kind?: Kind;
48
+ /** Whether the operation succeeded. */
49
+ readonly outcome: MemoryObservationOutcome;
50
+ /** Present on failure: the failure `Result`'s message. */
51
+ readonly error?: string;
52
+ /** Structured provenance of the write, when the operation carried one. */
53
+ readonly provenance?: IProvenance;
54
+ /**
55
+ * For `'retrieve'` observations: an opaque snapshot of the query that drove
56
+ * the retrieval. Carried verbatim; never interpreted by the store.
57
+ */
58
+ readonly querySnapshot?: Readonly<Record<string, unknown>>;
59
+ }
60
+ /**
61
+ * Single-method async observer hook. The store fires `observe` once per public
62
+ * `get` / `put` / `delete` call when observers are wired.
63
+ *
64
+ * @remarks
65
+ * Observer errors never affect the store operation — the store swallows a
66
+ * failed `Result` or a thrown / rejected `observe`, logging it to the injected
67
+ * diagnostic logger at `warn`.
68
+ * @public
69
+ */
70
+ export interface IMemoryObserver {
71
+ /**
72
+ * When `true`, the store dispatches `observe` without awaiting it, so a slow
73
+ * remote observer (SIEM, network sink) does not extend the store operation's
74
+ * latency. Defaults to `false` (awaited), which is correct for the cheap
75
+ * in-memory default {@link MemoryObservationStore}. Errors are swallowed
76
+ * either way.
77
+ */
78
+ readonly fireAndForget?: boolean;
79
+ /**
80
+ * Receives a fully-formed observation record.
81
+ * @param record - The observation record.
82
+ * @returns A `Result` whose failure is swallowed (logged to the store's
83
+ * diagnostic logger). A rejected promise is likewise swallowed.
84
+ */
85
+ observe(record: IMemoryObservationRecord): Promise<Result<unknown>>;
86
+ }
87
+ /**
88
+ * Query criteria for {@link MemoryObservationStore.query}. All supplied criteria
89
+ * are AND-combined.
90
+ * @public
91
+ */
92
+ export interface IMemoryObservationQuery {
93
+ /** Only records with `seq > sinceSeq` (incremental paging cursor). */
94
+ readonly sinceSeq?: number;
95
+ /** Return at most this many records — the most-recent N, still oldest-first. */
96
+ readonly limit?: number;
97
+ /** Only records with `timestamp >= since`. */
98
+ readonly since?: number;
99
+ /** Only records with `timestamp <= until`. */
100
+ readonly until?: number;
101
+ /** Only records that touched this scope. */
102
+ readonly scope?: MemoryScopeKey;
103
+ /** Only records that targeted this kind. */
104
+ readonly kind?: Kind;
105
+ /** Only records of this phase. */
106
+ readonly phase?: MemoryObservationPhase;
107
+ /** Only records with this outcome. */
108
+ readonly outcome?: MemoryObservationOutcome;
109
+ }
110
+ //# sourceMappingURL=observer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/packlets/observe/observer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEvE;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE9E;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;IACvC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;IACvB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAC3C,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5D;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;CACrE;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,sBAAsB,CAAC;IACxC,sCAAsC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;CAC7C"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=observer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/packlets/observe/observer.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result } from '@fgv/ts-utils';\nimport { IProvenance, Kind, MemoryId, MemoryScopeKey } from '../types';\n\n/**\n * The store/retriever operation an observation record describes.\n *\n * @remarks\n * `'read'` / `'write'` / `'delete'` are fired post-op by\n * {@link FileTreeMemoryStore} (on `get` / `put` / `delete` respectively) when\n * observers are wired. `'retrieve'` is reserved for retriever-fired\n * observations; no B2 retriever fires one (a single seq authority per\n * observation store is the supported topology), so it never appears in B2 but\n * is part of the vocabulary so a future retriever-firing hook is additive.\n * @public\n */\nexport type MemoryObservationPhase = 'read' | 'write' | 'delete' | 'retrieve';\n\n/**\n * The outcome of the observed operation.\n * @public\n */\nexport type MemoryObservationOutcome = 'success' | 'failure';\n\n/**\n * A single audit record produced by an observed store (or retriever) operation.\n *\n * @remarks\n * `seq` and `timestamp` are assigned by the firing authority (the store) before\n * fan-out, so the same record carries the same `seq` across every observer it\n * lands in. `seq` is strictly increasing per authority, satisfying the\n * `RetainingRingBuffer` cursor contract that {@link MemoryObservationStore}\n * relies on.\n * @public\n */\nexport interface IMemoryObservationRecord {\n /**\n * Monotonic 1-based sequence number assigned by the firing authority, stable\n * across a store's ring eviction. The ordering / paging key.\n */\n readonly seq: number;\n /** Milliseconds since epoch when the firing authority produced the record. */\n readonly timestamp: number;\n /** Which operation this record describes. */\n readonly phase: MemoryObservationPhase;\n /** The scope the operation touched, when resolvable. */\n readonly scope?: MemoryScopeKey;\n /** The record id the operation touched, when resolvable. */\n readonly id?: MemoryId;\n /** The kind the operation targeted, when known. */\n readonly kind?: Kind;\n /** Whether the operation succeeded. */\n readonly outcome: MemoryObservationOutcome;\n /** Present on failure: the failure `Result`'s message. */\n readonly error?: string;\n /** Structured provenance of the write, when the operation carried one. */\n readonly provenance?: IProvenance;\n /**\n * For `'retrieve'` observations: an opaque snapshot of the query that drove\n * the retrieval. Carried verbatim; never interpreted by the store.\n */\n readonly querySnapshot?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Single-method async observer hook. The store fires `observe` once per public\n * `get` / `put` / `delete` call when observers are wired.\n *\n * @remarks\n * Observer errors never affect the store operation — the store swallows a\n * failed `Result` or a thrown / rejected `observe`, logging it to the injected\n * diagnostic logger at `warn`.\n * @public\n */\nexport interface IMemoryObserver {\n /**\n * When `true`, the store dispatches `observe` without awaiting it, so a slow\n * remote observer (SIEM, network sink) does not extend the store operation's\n * latency. Defaults to `false` (awaited), which is correct for the cheap\n * in-memory default {@link MemoryObservationStore}. Errors are swallowed\n * either way.\n */\n readonly fireAndForget?: boolean;\n /**\n * Receives a fully-formed observation record.\n * @param record - The observation record.\n * @returns A `Result` whose failure is swallowed (logged to the store's\n * diagnostic logger). A rejected promise is likewise swallowed.\n */\n observe(record: IMemoryObservationRecord): Promise<Result<unknown>>;\n}\n\n/**\n * Query criteria for {@link MemoryObservationStore.query}. All supplied criteria\n * are AND-combined.\n * @public\n */\nexport interface IMemoryObservationQuery {\n /** Only records with `seq > sinceSeq` (incremental paging cursor). */\n readonly sinceSeq?: number;\n /** Return at most this many records — the most-recent N, still oldest-first. */\n readonly limit?: number;\n /** Only records with `timestamp >= since`. */\n readonly since?: number;\n /** Only records with `timestamp <= until`. */\n readonly until?: number;\n /** Only records that touched this scope. */\n readonly scope?: MemoryScopeKey;\n /** Only records that targeted this kind. */\n readonly kind?: Kind;\n /** Only records of this phase. */\n readonly phase?: MemoryObservationPhase;\n /** Only records with this outcome. */\n readonly outcome?: MemoryObservationOutcome;\n}\n"]}