@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,154 @@
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.InMemoryCosineIndex = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ /**
10
+ * The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
11
+ * `Float32Array` per record and answers a query by computing cosine similarity
12
+ * against every stored vector, returning the top-k by descending score.
13
+ *
14
+ * @remarks
15
+ * This is the **complete** vector implementation for the fgv regime — large-N is
16
+ * explicitly out of scope (the seam stays open for a consumer to swap an external
17
+ * ANN backend once N grows beyond "thousands of records"). No external dependency
18
+ * and no ANN structure: a linear scan over a few thousand vectors is well within
19
+ * an interactive budget.
20
+ *
21
+ * The index has a single dimension established by the first vector added; every
22
+ * subsequent `add` and every `query` vector must match that dimension or fail
23
+ * loudly — a mismatched dimension is an embedder-wiring bug, never a silent
24
+ * zero-similarity result. {@link InMemoryCosineIndex.rebuild | rebuild} clears
25
+ * the index, so a re-embed with a different model (hence dimension) is supported.
26
+ *
27
+ * Persistence (a JSON sidecar) is deliberately out of scope for this layer — the
28
+ * index is in-memory and rebuilt from the store via `rebuild`; a sidecar is a
29
+ * future nicety.
30
+ * @public
31
+ */
32
+ class InMemoryCosineIndex {
33
+ constructor() {
34
+ this._vectors = new Map();
35
+ this._dimension = undefined;
36
+ }
37
+ /** The number of vectors currently held. */
38
+ get size() {
39
+ return this._vectors.size;
40
+ }
41
+ /** Family-convention factory. */
42
+ static create() {
43
+ return (0, ts_utils_1.succeed)(new InMemoryCosineIndex());
44
+ }
45
+ /** {@inheritDoc IVectorIndex.add} */
46
+ add(id, vector) {
47
+ if (vector.length === 0) {
48
+ return Promise.resolve((0, ts_utils_1.fail)(`vector index: cannot add '${id}': empty vector`));
49
+ }
50
+ if (this._dimension === undefined) {
51
+ this._dimension = vector.length;
52
+ }
53
+ else if (vector.length !== this._dimension) {
54
+ return Promise.resolve((0, ts_utils_1.fail)(`vector index: cannot add '${id}': dimension ${vector.length} does not match index dimension ${this._dimension}`));
55
+ }
56
+ // Defensive copy: the caller may reuse or mutate the buffer after `add`, and
57
+ // the index must keep serving the embedding it was given.
58
+ this._vectors.set(id, Float32Array.from(vector));
59
+ // The in-memory index keys entries by id, so the id IS the entry reference.
60
+ return Promise.resolve((0, ts_utils_1.succeed)(id));
61
+ }
62
+ /** {@inheritDoc IVectorIndex.remove} */
63
+ remove(id) {
64
+ this._vectors.delete(id);
65
+ return Promise.resolve((0, ts_utils_1.succeed)(id));
66
+ }
67
+ /** {@inheritDoc IVectorIndex.query} */
68
+ query(vector, topK) {
69
+ if (topK <= 0 || this._vectors.size === 0) {
70
+ return Promise.resolve((0, ts_utils_1.succeed)([]));
71
+ }
72
+ if (vector.length !== this._dimension) {
73
+ return Promise.resolve((0, ts_utils_1.fail)(`vector index: query dimension ${vector.length} does not match index dimension ${this._dimension}`));
74
+ }
75
+ const queryMagnitude = InMemoryCosineIndex._magnitude(vector);
76
+ const hits = [];
77
+ for (const [id, stored] of this._vectors) {
78
+ hits.push({ id, score: InMemoryCosineIndex._cosine(vector, queryMagnitude, stored) });
79
+ }
80
+ // Descending by score; a `seq`-free tiebreak is unnecessary here because the
81
+ // caller (SemanticRetriever) re-resolves hits against the record index.
82
+ hits.sort((a, b) => b.score - a.score);
83
+ return Promise.resolve((0, ts_utils_1.succeed)(hits.length > topK ? hits.slice(0, topK) : hits));
84
+ }
85
+ /**
86
+ * Re-embed every record from `source` and rebuild the index from scratch.
87
+ * Clears the current contents (and the established dimension) first, so a
88
+ * re-embed with a different model is supported. Returns the number of vectors
89
+ * indexed.
90
+ *
91
+ * On any failure (list, embed, or add) the index is rolled back to empty
92
+ * rather than left in a partially-rebuilt state — a caller that retries a query
93
+ * after a failed rebuild sees a clean empty index, never a half-populated one.
94
+ *
95
+ * @param source - The record source to re-embed (an {@link IMemoryStore}
96
+ * satisfies this structurally).
97
+ * @param embed - The embedder applied to each record.
98
+ */
99
+ async rebuild(source, embed) {
100
+ // Reset up front so the "any failure leaves the index empty" contract holds
101
+ // even when the listing itself fails (no stale vectors survive a failed
102
+ // rebuild).
103
+ this._reset();
104
+ const listed = await source.list();
105
+ if (listed.isFailure()) {
106
+ return (0, ts_utils_1.fail)(`vector index rebuild: failed to list records: ${listed.message}`);
107
+ }
108
+ for (const record of listed.value) {
109
+ const embedded = await embed(record);
110
+ if (embedded.isFailure()) {
111
+ this._reset();
112
+ return (0, ts_utils_1.fail)(`vector index rebuild: embedding '${record.envelope.id}' failed: ${embedded.message}`);
113
+ }
114
+ const added = await this.add(record.envelope.id, embedded.value);
115
+ if (added.isFailure()) {
116
+ this._reset();
117
+ return (0, ts_utils_1.fail)(`vector index rebuild: ${added.message}`);
118
+ }
119
+ }
120
+ return (0, ts_utils_1.succeed)(this._vectors.size);
121
+ }
122
+ /** Empty the index and forget the established dimension. */
123
+ _reset() {
124
+ this._vectors.clear();
125
+ this._dimension = undefined;
126
+ }
127
+ /** The Euclidean magnitude (L2 norm) of a vector. */
128
+ static _magnitude(vector) {
129
+ let sum = 0;
130
+ for (let i = 0; i < vector.length; i++) {
131
+ sum += vector[i] * vector[i];
132
+ }
133
+ return Math.sqrt(sum);
134
+ }
135
+ /**
136
+ * Cosine similarity between the query (whose magnitude is precomputed once and
137
+ * reused across the scan) and a stored vector. A zero-magnitude vector on
138
+ * either side yields `0` rather than `NaN` — a degenerate vector is simply
139
+ * maximally dissimilar, not an error.
140
+ */
141
+ static _cosine(query, queryMagnitude, stored) {
142
+ const storedMagnitude = InMemoryCosineIndex._magnitude(stored);
143
+ if (queryMagnitude === 0 || storedMagnitude === 0) {
144
+ return 0;
145
+ }
146
+ let dot = 0;
147
+ for (let i = 0; i < query.length; i++) {
148
+ dot += query[i] * stored[i];
149
+ }
150
+ return dot / (queryMagnitude * storedMagnitude);
151
+ }
152
+ }
153
+ exports.InMemoryCosineIndex = InMemoryCosineIndex;
154
+ //# sourceMappingURL=inMemoryCosineIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inMemoryCosineIndex.js","sourceRoot":"","sources":["../../../src/packlets/vector/inMemoryCosineIndex.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord, MemoryId } from '../types';\nimport { IMemoryRecordSource, IVectorIndex, IVectorQueryHit, MemoryEmbedder } from './vectorIndex';\n\n/**\n * The brute-force, in-memory cosine {@link IVectorIndex}. Stores one\n * `Float32Array` per record and answers a query by computing cosine similarity\n * against every stored vector, returning the top-k by descending score.\n *\n * @remarks\n * This is the **complete** vector implementation for the fgv regime — large-N is\n * explicitly out of scope (the seam stays open for a consumer to swap an external\n * ANN backend once N grows beyond \"thousands of records\"). No external dependency\n * and no ANN structure: a linear scan over a few thousand vectors is well within\n * an interactive budget.\n *\n * The index has a single dimension established by the first vector added; every\n * subsequent `add` and every `query` vector must match that dimension or fail\n * loudly — a mismatched dimension is an embedder-wiring bug, never a silent\n * zero-similarity result. {@link InMemoryCosineIndex.rebuild | rebuild} clears\n * the index, so a re-embed with a different model (hence dimension) is supported.\n *\n * Persistence (a JSON sidecar) is deliberately out of scope for this layer — the\n * index is in-memory and rebuilt from the store via `rebuild`; a sidecar is a\n * future nicety.\n * @public\n */\nexport class InMemoryCosineIndex implements IVectorIndex {\n private readonly _vectors: Map<MemoryId, Float32Array>;\n /** The dimension of every stored vector; `undefined` until the first `add`. */\n private _dimension: number | undefined;\n\n private constructor() {\n this._vectors = new Map<MemoryId, Float32Array>();\n this._dimension = undefined;\n }\n\n /** The number of vectors currently held. */\n public get size(): number {\n return this._vectors.size;\n }\n\n /** Family-convention factory. */\n public static create(): Result<InMemoryCosineIndex> {\n return succeed(new InMemoryCosineIndex());\n }\n\n /** {@inheritDoc IVectorIndex.add} */\n public add(id: MemoryId, vector: Float32Array): Promise<Result<string>> {\n if (vector.length === 0) {\n return Promise.resolve(fail(`vector index: cannot add '${id}': empty vector`));\n }\n if (this._dimension === undefined) {\n this._dimension = vector.length;\n } else if (vector.length !== this._dimension) {\n return Promise.resolve(\n fail(\n `vector index: cannot add '${id}': dimension ${vector.length} does not match index dimension ${this._dimension}`\n )\n );\n }\n // Defensive copy: the caller may reuse or mutate the buffer after `add`, and\n // the index must keep serving the embedding it was given.\n this._vectors.set(id, Float32Array.from(vector));\n // The in-memory index keys entries by id, so the id IS the entry reference.\n return Promise.resolve(succeed(id as string));\n }\n\n /** {@inheritDoc IVectorIndex.remove} */\n public remove(id: MemoryId): Promise<Result<MemoryId>> {\n this._vectors.delete(id);\n return Promise.resolve(succeed(id));\n }\n\n /** {@inheritDoc IVectorIndex.query} */\n public query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>> {\n if (topK <= 0 || this._vectors.size === 0) {\n return Promise.resolve(succeed([]));\n }\n if (vector.length !== this._dimension) {\n return Promise.resolve(\n fail(\n `vector index: query dimension ${vector.length} does not match index dimension ${this._dimension}`\n )\n );\n }\n const queryMagnitude: number = InMemoryCosineIndex._magnitude(vector);\n const hits: IVectorQueryHit[] = [];\n for (const [id, stored] of this._vectors) {\n hits.push({ id, score: InMemoryCosineIndex._cosine(vector, queryMagnitude, stored) });\n }\n // Descending by score; a `seq`-free tiebreak is unnecessary here because the\n // caller (SemanticRetriever) re-resolves hits against the record index.\n hits.sort((a, b) => b.score - a.score);\n return Promise.resolve(succeed(hits.length > topK ? hits.slice(0, topK) : hits));\n }\n\n /**\n * Re-embed every record from `source` and rebuild the index from scratch.\n * Clears the current contents (and the established dimension) first, so a\n * re-embed with a different model is supported. Returns the number of vectors\n * indexed.\n *\n * On any failure (list, embed, or add) the index is rolled back to empty\n * rather than left in a partially-rebuilt state — a caller that retries a query\n * after a failed rebuild sees a clean empty index, never a half-populated one.\n *\n * @param source - The record source to re-embed (an {@link IMemoryStore}\n * satisfies this structurally).\n * @param embed - The embedder applied to each record.\n */\n public async rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder): Promise<Result<number>> {\n // Reset up front so the \"any failure leaves the index empty\" contract holds\n // even when the listing itself fails (no stale vectors survive a failed\n // rebuild).\n this._reset();\n const listed: Result<ReadonlyArray<IMemoryRecord<unknown>>> = await source.list();\n if (listed.isFailure()) {\n return fail(`vector index rebuild: failed to list records: ${listed.message}`);\n }\n for (const record of listed.value) {\n const embedded: Result<Float32Array> = await embed(record);\n if (embedded.isFailure()) {\n this._reset();\n return fail(`vector index rebuild: embedding '${record.envelope.id}' failed: ${embedded.message}`);\n }\n const added: Result<string> = await this.add(record.envelope.id, embedded.value);\n if (added.isFailure()) {\n this._reset();\n return fail(`vector index rebuild: ${added.message}`);\n }\n }\n return succeed(this._vectors.size);\n }\n\n /** Empty the index and forget the established dimension. */\n private _reset(): void {\n this._vectors.clear();\n this._dimension = undefined;\n }\n\n /** The Euclidean magnitude (L2 norm) of a vector. */\n private static _magnitude(vector: Float32Array): number {\n let sum: number = 0;\n for (let i: number = 0; i < vector.length; i++) {\n sum += vector[i] * vector[i];\n }\n return Math.sqrt(sum);\n }\n\n /**\n * Cosine similarity between the query (whose magnitude is precomputed once and\n * reused across the scan) and a stored vector. A zero-magnitude vector on\n * either side yields `0` rather than `NaN` — a degenerate vector is simply\n * maximally dissimilar, not an error.\n */\n private static _cosine(query: Float32Array, queryMagnitude: number, stored: Float32Array): number {\n const storedMagnitude: number = InMemoryCosineIndex._magnitude(stored);\n if (queryMagnitude === 0 || storedMagnitude === 0) {\n return 0;\n }\n let dot: number = 0;\n for (let i: number = 0; i < query.length; i++) {\n dot += query[i] * stored[i];\n }\n return dot / (queryMagnitude * storedMagnitude);\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './vectorIndex';
2
+ export * from './inMemoryCosineIndex';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/index.ts"],"names":[],"mappings":"AAKA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,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("./vectorIndex"), exports);
22
+ __exportStar(require("./inMemoryCosineIndex"), exports);
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/vector/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,gDAA8B;AAC9B,wDAAsC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './vectorIndex';\nexport * from './inMemoryCosineIndex';\n"]}
@@ -0,0 +1,68 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { IMemoryRecord, MemoryId } from '../types';
3
+ /**
4
+ * A single hit returned by {@link IVectorIndex.query}: the matched record id and
5
+ * the backend's similarity score (higher = more similar; the exact scale is
6
+ * backend-defined). Hits are returned in descending score order.
7
+ * @public
8
+ */
9
+ export interface IVectorQueryHit {
10
+ /** The id of the matched record. */
11
+ readonly id: MemoryId;
12
+ /** Backend similarity score; higher is more similar. */
13
+ readonly score: number;
14
+ }
15
+ /**
16
+ * The vector-index seam an embedding backend implements to make
17
+ * {@link SemanticRetriever | semantic recall} operational.
18
+ *
19
+ * @remarks
20
+ * Vectors cross this seam as `Float32Array` (the in-memory representation an
21
+ * embedding model produces); `number[]` is reserved for the JSON-wire edges
22
+ * (e.g. a provider's embedding response). The in-package brute-force cosine
23
+ * implementation is {@link InMemoryCosineIndex}; a consumer can swap an external
24
+ * ANN backend behind the same seam once N grows beyond the in-memory regime.
25
+ *
26
+ * Every operation returns a `Result` (async, since a real backend does I/O) so
27
+ * failure is explicit and never throws across the seam.
28
+ * @public
29
+ */
30
+ export interface IVectorIndex {
31
+ /**
32
+ * Add (or replace) the embedding for `id`. Returns the opaque
33
+ * {@link IMemoryEnvelope.embeddingRef | embeddingRef} the store stamps onto
34
+ * the envelope so a later read knows the record is embedded.
35
+ */
36
+ add(id: MemoryId, vector: Float32Array): Promise<Result<string>>;
37
+ /**
38
+ * Remove the embedding for `id`. Returns the removed id. Idempotent — removing
39
+ * an id with no embedding still succeeds (returns the id).
40
+ */
41
+ remove(id: MemoryId): Promise<Result<MemoryId>>;
42
+ /**
43
+ * Return the `topK` nearest records to `vector`, in descending score order.
44
+ */
45
+ query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
46
+ }
47
+ /**
48
+ * Embeds a complete record into a vector for the store's embed-on-write hook.
49
+ * Async and `Result`-returning, since a real embedder does a network call (cloud
50
+ * provider) or in-process model inference. The consumer wires this — the core
51
+ * package never calls an embedding provider directly, staying embedder-agnostic.
52
+ * @public
53
+ */
54
+ export type MemoryEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<Float32Array>>;
55
+ /**
56
+ * The minimal record-source surface {@link InMemoryCosineIndex.rebuild} reads to
57
+ * re-embed an entire vault. {@link IMemoryStore} satisfies it structurally (its
58
+ * `list` accepts an optional filter, which is assignable to this no-argument
59
+ * shape), so a consumer passes the store directly — without the vector packlet
60
+ * taking a dependency on the store packlet (which depends on the vector packlet
61
+ * for {@link IVectorIndex}, so the reverse import would be a cycle).
62
+ * @public
63
+ */
64
+ export interface IMemoryRecordSource {
65
+ /** List every record in the vault. */
66
+ list(): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
67
+ }
68
+ //# sourceMappingURL=vectorIndex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/vectorIndex.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEjE;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEhD;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAC5F;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAE/F;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CAChE"}
@@ -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=vectorIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorIndex.js","sourceRoot":"","sources":["../../../src/packlets/vector/vectorIndex.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 { IMemoryRecord, MemoryId } from '../types';\n\n/**\n * A single hit returned by {@link IVectorIndex.query}: the matched record id and\n * the backend's similarity score (higher = more similar; the exact scale is\n * backend-defined). Hits are returned in descending score order.\n * @public\n */\nexport interface IVectorQueryHit {\n /** The id of the matched record. */\n readonly id: MemoryId;\n /** Backend similarity score; higher is more similar. */\n readonly score: number;\n}\n\n/**\n * The vector-index seam an embedding backend implements to make\n * {@link SemanticRetriever | semantic recall} operational.\n *\n * @remarks\n * Vectors cross this seam as `Float32Array` (the in-memory representation an\n * embedding model produces); `number[]` is reserved for the JSON-wire edges\n * (e.g. a provider's embedding response). The in-package brute-force cosine\n * implementation is {@link InMemoryCosineIndex}; a consumer can swap an external\n * ANN backend behind the same seam once N grows beyond the in-memory regime.\n *\n * Every operation returns a `Result` (async, since a real backend does I/O) so\n * failure is explicit and never throws across the seam.\n * @public\n */\nexport interface IVectorIndex {\n /**\n * Add (or replace) the embedding for `id`. Returns the opaque\n * {@link IMemoryEnvelope.embeddingRef | embeddingRef} the store stamps onto\n * the envelope so a later read knows the record is embedded.\n */\n add(id: MemoryId, vector: Float32Array): Promise<Result<string>>;\n\n /**\n * Remove the embedding for `id`. Returns the removed id. Idempotent — removing\n * an id with no embedding still succeeds (returns the id).\n */\n remove(id: MemoryId): Promise<Result<MemoryId>>;\n\n /**\n * Return the `topK` nearest records to `vector`, in descending score order.\n */\n query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;\n}\n\n/**\n * Embeds a complete record into a vector for the store's embed-on-write hook.\n * Async and `Result`-returning, since a real embedder does a network call (cloud\n * provider) or in-process model inference. The consumer wires this — the core\n * package never calls an embedding provider directly, staying embedder-agnostic.\n * @public\n */\nexport type MemoryEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<Float32Array>>;\n\n/**\n * The minimal record-source surface {@link InMemoryCosineIndex.rebuild} reads to\n * re-embed an entire vault. {@link IMemoryStore} satisfies it structurally (its\n * `list` accepts an optional filter, which is assignable to this no-argument\n * shape), so a consumer passes the store directly — without the vector packlet\n * taking a dependency on the store packlet (which depends on the vector packlet\n * for {@link IVectorIndex}, so the reverse import would be a cycle).\n * @public\n */\nexport interface IMemoryRecordSource {\n /** List every record in the vault. */\n list(): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import '@fgv/ts-utils-jest';
2
+ //# sourceMappingURL=bodyConverterRegistry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodyConverterRegistry.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/converters/bodyConverterRegistry.test.ts"],"names":[],"mappings":"AAKA,OAAO,oBAAoB,CAAC"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ require("@fgv/ts-utils-jest");
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ const ts_json_base_1 = require("@fgv/ts-json-base");
10
+ const converters_1 = require("../../../packlets/converters");
11
+ const knowledgeKind = 'knowledge';
12
+ const profileKind = 'profile';
13
+ describe('BodyConverterRegistry', () => {
14
+ let registry;
15
+ beforeEach(() => {
16
+ registry = converters_1.BodyConverterRegistry.create().orThrow();
17
+ });
18
+ test('create succeeds', () => {
19
+ expect(converters_1.BodyConverterRegistry.create()).toSucceed();
20
+ });
21
+ describe('register / has / convert', () => {
22
+ test('registers a Converter and converts a matching body', () => {
23
+ registry.register(knowledgeKind, ts_utils_1.Converters.string);
24
+ expect(registry.has(knowledgeKind)).toBe(true);
25
+ expect(registry.convert(knowledgeKind, 'a knowledge doc')).toSucceedWith('a knowledge doc');
26
+ });
27
+ test('a registered Converter rejects an invalid body', () => {
28
+ registry.register(knowledgeKind, ts_utils_1.Converters.string);
29
+ expect(registry.convert(knowledgeKind, 42)).toFail();
30
+ });
31
+ test('has returns false for an unregistered kind', () => {
32
+ expect(registry.has(knowledgeKind)).toBe(false);
33
+ });
34
+ test('convert fails for an unregistered kind', () => {
35
+ expect(registry.convert(knowledgeKind, 'x')).toFailWith(/no converter registered for kind 'knowledge'/i);
36
+ });
37
+ test('register replaces a prior registration for the same kind', () => {
38
+ registry.register(knowledgeKind, ts_utils_1.Converters.string);
39
+ registry.register(knowledgeKind, ts_utils_1.Converters.number);
40
+ expect(registry.convert(knowledgeKind, 7)).toSucceedWith(7);
41
+ expect(registry.convert(knowledgeKind, 'x')).toFail();
42
+ });
43
+ });
44
+ describe('getConverter', () => {
45
+ test('returns the registered converter', () => {
46
+ registry.register(knowledgeKind, ts_utils_1.Converters.string);
47
+ expect(registry.getConverter(knowledgeKind)).toSucceedAndSatisfy((converter) => {
48
+ expect(converter.convert('hello')).toSucceedWith('hello');
49
+ });
50
+ });
51
+ test('fails for an unregistered kind', () => {
52
+ expect(registry.getConverter(knowledgeKind)).toFailWith(/no converter registered for kind/i);
53
+ });
54
+ });
55
+ describe('registerSchema', () => {
56
+ const profileSchema = ts_json_base_1.JsonSchema.object({
57
+ name: ts_json_base_1.JsonSchema.string(),
58
+ age: ts_json_base_1.JsonSchema.integer()
59
+ });
60
+ test('registers a JsonSchema validator and validates a matching body', () => {
61
+ registry.registerSchema(profileKind, profileSchema);
62
+ expect(registry.has(profileKind)).toBe(true);
63
+ expect(registry.convert(profileKind, { name: 'Ada', age: 36 })).toSucceedWith({
64
+ name: 'Ada',
65
+ age: 36
66
+ });
67
+ });
68
+ test('a registered schema rejects an invalid body', () => {
69
+ registry.registerSchema(profileKind, profileSchema);
70
+ expect(registry.convert(profileKind, { name: 'Ada' })).toFail();
71
+ });
72
+ });
73
+ });
74
+ //# sourceMappingURL=bodyConverterRegistry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodyConverterRegistry.test.js","sourceRoot":"","sources":["../../../../src/test/unit/converters/bodyConverterRegistry.test.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,8BAA4B;AAC5B,4CAA2C;AAC3C,oDAA+C;AAC/C,6DAAqE;AAGrE,MAAM,aAAa,GAAS,WAAmB,CAAC;AAChD,MAAM,WAAW,GAAS,SAAiB,CAAC;AAE5C,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,QAA+B,CAAC;IAEpC,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,kCAAqB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,kCAAqB,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC9D,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,qBAAU,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QAC9F,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;YAC1D,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,qBAAU,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACtD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CACrD,+CAA+C,CAChD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;YACpE,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,qBAAU,CAAC,MAAM,CAAC,CAAC;YACpD,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,qBAAU,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC5C,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,qBAAU,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,SAAS,EAAE,EAAE;gBAC7E,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,mCAAmC,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,MAAM,aAAa,GAAG,yBAAU,CAAC,MAAM,CAAC;YACtC,IAAI,EAAE,yBAAU,CAAC,MAAM,EAAE;YACzB,GAAG,EAAE,yBAAU,CAAC,OAAO,EAAE;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,gEAAgE,EAAE,GAAG,EAAE;YAC1E,QAAQ,CAAC,cAAc,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;gBAC5E,IAAI,EAAE,KAAK;gBACX,GAAG,EAAE,EAAE;aACR,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACvD,QAAQ,CAAC,cAAc,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport '@fgv/ts-utils-jest';\nimport { Converters } from '@fgv/ts-utils';\nimport { JsonSchema } from '@fgv/ts-json-base';\nimport { BodyConverterRegistry } from '../../../packlets/converters';\nimport { Kind } from '../../../packlets/types';\n\nconst knowledgeKind: Kind = 'knowledge' as Kind;\nconst profileKind: Kind = 'profile' as Kind;\n\ndescribe('BodyConverterRegistry', () => {\n let registry: BodyConverterRegistry;\n\n beforeEach(() => {\n registry = BodyConverterRegistry.create().orThrow();\n });\n\n test('create succeeds', () => {\n expect(BodyConverterRegistry.create()).toSucceed();\n });\n\n describe('register / has / convert', () => {\n test('registers a Converter and converts a matching body', () => {\n registry.register(knowledgeKind, Converters.string);\n expect(registry.has(knowledgeKind)).toBe(true);\n expect(registry.convert(knowledgeKind, 'a knowledge doc')).toSucceedWith('a knowledge doc');\n });\n\n test('a registered Converter rejects an invalid body', () => {\n registry.register(knowledgeKind, Converters.string);\n expect(registry.convert(knowledgeKind, 42)).toFail();\n });\n\n test('has returns false for an unregistered kind', () => {\n expect(registry.has(knowledgeKind)).toBe(false);\n });\n\n test('convert fails for an unregistered kind', () => {\n expect(registry.convert(knowledgeKind, 'x')).toFailWith(\n /no converter registered for kind 'knowledge'/i\n );\n });\n\n test('register replaces a prior registration for the same kind', () => {\n registry.register(knowledgeKind, Converters.string);\n registry.register(knowledgeKind, Converters.number);\n expect(registry.convert(knowledgeKind, 7)).toSucceedWith(7);\n expect(registry.convert(knowledgeKind, 'x')).toFail();\n });\n });\n\n describe('getConverter', () => {\n test('returns the registered converter', () => {\n registry.register(knowledgeKind, Converters.string);\n expect(registry.getConverter(knowledgeKind)).toSucceedAndSatisfy((converter) => {\n expect(converter.convert('hello')).toSucceedWith('hello');\n });\n });\n\n test('fails for an unregistered kind', () => {\n expect(registry.getConverter(knowledgeKind)).toFailWith(/no converter registered for kind/i);\n });\n });\n\n describe('registerSchema', () => {\n const profileSchema = JsonSchema.object({\n name: JsonSchema.string(),\n age: JsonSchema.integer()\n });\n\n test('registers a JsonSchema validator and validates a matching body', () => {\n registry.registerSchema(profileKind, profileSchema);\n expect(registry.has(profileKind)).toBe(true);\n expect(registry.convert(profileKind, { name: 'Ada', age: 36 })).toSucceedWith({\n name: 'Ada',\n age: 36\n });\n });\n\n test('a registered schema rejects an invalid body', () => {\n registry.registerSchema(profileKind, profileSchema);\n expect(registry.convert(profileKind, { name: 'Ada' })).toFail();\n });\n });\n});\n"]}
@@ -0,0 +1,2 @@
1
+ import '@fgv/ts-utils-jest';
2
+ //# sourceMappingURL=envelopeConverter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelopeConverter.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/converters/envelopeConverter.test.ts"],"names":[],"mappings":"AAKA,OAAO,oBAAoB,CAAC"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ require("@fgv/ts-utils-jest");
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ const converters_1 = require("../../../packlets/converters");
10
+ const validEnvelopeObject = {
11
+ id: 'intro-to-rust',
12
+ entityId: 'intro-to-rust',
13
+ kind: 'knowledge',
14
+ tags: ['rust', 'systems'],
15
+ links: [{ type: 'related', target: 'ownership' }],
16
+ created: 1000,
17
+ updated: 2000,
18
+ seq: 5,
19
+ contentHash: 'crc-abc',
20
+ provenance: { source: 'agent', by: 'curator' }
21
+ };
22
+ describe('provenanceConverter', () => {
23
+ test('validates the known fields', () => {
24
+ expect(converters_1.provenanceConverter.convert({ source: 'human', by: 'erik', model: 'gpt', confidence: 0.9 })).toSucceedWith({ source: 'human', by: 'erik', model: 'gpt', confidence: 0.9 });
25
+ });
26
+ test('preserves opaque extension keys verbatim', () => {
27
+ expect(converters_1.provenanceConverter.convert({ source: 'agent', sentiment: { score: 0.5 }, epistemic: 'belief' })).toSucceedAndSatisfy((p) => {
28
+ expect(p.source).toBe('agent');
29
+ expect(p.sentiment).toEqual({ score: 0.5 });
30
+ expect(p.epistemic).toBe('belief');
31
+ });
32
+ });
33
+ test('accepts an arbitrary source string (open vocabulary)', () => {
34
+ expect(converters_1.provenanceConverter.convert({ source: 'host-ingest' })).toSucceedWith({ source: 'host-ingest' });
35
+ });
36
+ test('fails when source is missing', () => {
37
+ expect(converters_1.provenanceConverter.convert({ by: 'erik' })).toFail();
38
+ });
39
+ test('fails on a non-object', () => {
40
+ expect(converters_1.provenanceConverter.convert('nope')).toFail();
41
+ });
42
+ });
43
+ describe('edgeConverter', () => {
44
+ test('validates a full attributed edge', () => {
45
+ expect(converters_1.edgeConverter.convert({
46
+ type: 'mtm-ref',
47
+ target: 'turn-3',
48
+ confidence: 0.8,
49
+ provenance: { source: 'agent' },
50
+ valid_at: 100,
51
+ invalid_at: 200
52
+ })).toSucceedAndSatisfy((edge) => {
53
+ expect(edge.type).toBe('mtm-ref');
54
+ expect(edge.target).toBe('turn-3');
55
+ expect(edge.confidence).toBe(0.8);
56
+ expect(edge.provenance).toEqual({ source: 'agent' });
57
+ expect(edge.valid_at).toBe(100);
58
+ expect(edge.invalid_at).toBe(200);
59
+ });
60
+ });
61
+ test('validates a minimal edge', () => {
62
+ expect(converters_1.edgeConverter.convert({ type: 'related', target: 'ownership' })).toSucceedAndSatisfy((edge) => {
63
+ expect(edge.type).toBe('related');
64
+ expect(edge.target).toBe('ownership');
65
+ expect(edge.confidence).toBeUndefined();
66
+ });
67
+ });
68
+ test('accepts a null invalid_at (still valid)', () => {
69
+ expect(converters_1.edgeConverter.convert({ type: 'related', target: 'x', invalid_at: null })).toSucceedAndSatisfy((edge) => {
70
+ expect(edge.invalid_at).toBeNull();
71
+ });
72
+ });
73
+ test('fails when invalid_at is neither a number nor null', () => {
74
+ expect(converters_1.edgeConverter.convert({ type: 'related', target: 'x', invalid_at: 'soon' })).toFail();
75
+ });
76
+ test('fails when target is missing', () => {
77
+ expect(converters_1.edgeConverter.convert({ type: 'related' })).toFail();
78
+ });
79
+ });
80
+ describe('temporalConverter', () => {
81
+ test('validates a temporal block', () => {
82
+ expect(converters_1.temporalConverter.convert({ valid_at: 1, invalid_at: null })).toSucceedWith({
83
+ valid_at: 1,
84
+ invalid_at: null
85
+ });
86
+ });
87
+ test('validates an empty temporal block', () => {
88
+ expect(converters_1.temporalConverter.convert({})).toSucceedWith({});
89
+ });
90
+ });
91
+ describe('envelopeConverter', () => {
92
+ test('validates a full envelope without optional blocks', () => {
93
+ expect(converters_1.envelopeConverter.convert(validEnvelopeObject)).toSucceedAndSatisfy((envelope) => {
94
+ expect(envelope.id).toBe('intro-to-rust');
95
+ expect(envelope.tags).toEqual(['rust', 'systems']);
96
+ expect(envelope.links).toHaveLength(1);
97
+ expect(envelope.temporal).toBeUndefined();
98
+ expect(envelope.embeddingRef).toBeUndefined();
99
+ });
100
+ });
101
+ test('validates a temporal envelope with a string embeddingRef', () => {
102
+ expect(converters_1.envelopeConverter.convert(Object.assign(Object.assign({}, validEnvelopeObject), { temporal: { valid_at: 10 }, embeddingRef: 'vec-1' }))).toSucceedAndSatisfy((envelope) => {
103
+ expect(envelope.temporal).toEqual({ valid_at: 10 });
104
+ expect(envelope.embeddingRef).toBe('vec-1');
105
+ });
106
+ });
107
+ test('accepts a null embeddingRef (not embedded)', () => {
108
+ expect(converters_1.envelopeConverter.convert(Object.assign(Object.assign({}, validEnvelopeObject), { embeddingRef: null }))).toSucceedAndSatisfy((envelope) => {
109
+ expect(envelope.embeddingRef).toBeNull();
110
+ });
111
+ });
112
+ test('fails when embeddingRef is neither a string nor null', () => {
113
+ expect(converters_1.envelopeConverter.convert(Object.assign(Object.assign({}, validEnvelopeObject), { embeddingRef: 42 }))).toFail();
114
+ });
115
+ test('fails when a required field is missing', () => {
116
+ const missing = Object.assign({}, validEnvelopeObject);
117
+ delete missing.contentHash;
118
+ expect(converters_1.envelopeConverter.convert(missing)).toFail();
119
+ });
120
+ });
121
+ describe('envelopeYamlConverter', () => {
122
+ test('parses an envelope from a YAML string', () => {
123
+ const yaml = (0, converters_1.serializeMemoryFile)(converters_1.envelopeConverter.convert(validEnvelopeObject).orThrow(), 'body text').orThrow();
124
+ const frontmatter = (0, converters_1.splitFrontmatter)(yaml).orThrow().frontmatter;
125
+ expect(converters_1.envelopeYamlConverter.convert(frontmatter)).toSucceedAndSatisfy((envelope) => {
126
+ expect(envelope.id).toBe('intro-to-rust');
127
+ });
128
+ });
129
+ test('fails on a YAML string that is not an object', () => {
130
+ expect(converters_1.envelopeYamlConverter.convert('just a scalar')).toFail();
131
+ });
132
+ });
133
+ describe('splitFrontmatter / joinFrontmatter', () => {
134
+ test('splits a well-formed memory file', () => {
135
+ const raw = '---\nid: x\nkind: knowledge\n---\nThe body.\nSecond line.';
136
+ expect((0, converters_1.splitFrontmatter)(raw)).toSucceedWith({
137
+ frontmatter: 'id: x\nkind: knowledge',
138
+ body: 'The body.\nSecond line.'
139
+ });
140
+ });
141
+ test('strips trailing CR so CRLF-authored files parse identically to LF', () => {
142
+ const raw = '---\r\nid: x\r\nkind: knowledge\r\n---\r\nThe body.\r\nSecond line.';
143
+ expect((0, converters_1.splitFrontmatter)(raw)).toSucceedWith({
144
+ frontmatter: 'id: x\nkind: knowledge',
145
+ body: 'The body.\nSecond line.'
146
+ });
147
+ });
148
+ test('fails when the opening delimiter is missing', () => {
149
+ expect((0, converters_1.splitFrontmatter)('no frontmatter here')).toFailWith(/missing opening frontmatter delimiter/i);
150
+ });
151
+ test('fails when the closing delimiter is missing', () => {
152
+ expect((0, converters_1.splitFrontmatter)('---\nid: x\nstill going')).toFailWith(/missing closing frontmatter delimiter/i);
153
+ });
154
+ test('join adds a trailing newline to the frontmatter when absent', () => {
155
+ expect((0, converters_1.joinFrontmatter)('id: x', 'body')).toBe('---\nid: x\n---\nbody');
156
+ });
157
+ test('join does not double the trailing newline when present', () => {
158
+ expect((0, converters_1.joinFrontmatter)('id: x\n', 'body')).toBe('---\nid: x\n---\nbody');
159
+ });
160
+ test('split and join round-trip', () => {
161
+ const raw = '---\nid: x\n---\nbody content';
162
+ const parts = (0, converters_1.splitFrontmatter)(raw).orThrow();
163
+ expect((0, converters_1.joinFrontmatter)(parts.frontmatter, parts.body)).toBe(raw);
164
+ });
165
+ });
166
+ describe('parseMemoryFile / serializeMemoryFile', () => {
167
+ let registry;
168
+ const knowledgeKind = 'knowledge';
169
+ beforeEach(() => {
170
+ registry = converters_1.BodyConverterRegistry.create().orThrow();
171
+ registry.register(knowledgeKind, ts_utils_1.Converters.string);
172
+ });
173
+ test('serializes then parses a record round-trip', () => {
174
+ const envelope = converters_1.envelopeConverter.convert(validEnvelopeObject).orThrow();
175
+ const file = (0, converters_1.serializeMemoryFile)(envelope, 'The knowledge body.').orThrow();
176
+ expect((0, converters_1.parseMemoryFile)(file, registry)).toSucceedAndSatisfy((record) => {
177
+ expect(record.envelope.id).toBe('intro-to-rust');
178
+ expect(record.body).toBe('The knowledge body.');
179
+ });
180
+ });
181
+ test('fails when the frontmatter cannot be split', () => {
182
+ expect((0, converters_1.parseMemoryFile)('no delimiters', registry)).toFailWith(/missing opening frontmatter delimiter/i);
183
+ });
184
+ test('fails with envelope context when the envelope is invalid', () => {
185
+ const file = '---\nid: x\n---\nbody';
186
+ expect((0, converters_1.parseMemoryFile)(file, registry)).toFailWith(/invalid envelope/i);
187
+ });
188
+ test('fails with body context when the body fails the registered converter', () => {
189
+ const envelope = converters_1.envelopeConverter.convert(Object.assign(Object.assign({}, validEnvelopeObject), { kind: 'unregistered' })).orThrow();
190
+ const file = (0, converters_1.serializeMemoryFile)(envelope, 'body').orThrow();
191
+ expect((0, converters_1.parseMemoryFile)(file, registry)).toFailWith(/invalid body.*no converter registered/i);
192
+ });
193
+ test('serialize fails (with id context) when the envelope cannot be dumped to YAML', () => {
194
+ const unserializable = Object.assign(Object.assign({}, validEnvelopeObject), { weird: BigInt(10) });
195
+ expect((0, converters_1.serializeMemoryFile)(unserializable, 'body')).toFailWith(/failed to serialize envelope/i);
196
+ });
197
+ });
198
+ //# sourceMappingURL=envelopeConverter.test.js.map