@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 @@
1
+ {"version":3,"file":"fileTreeMemoryStore.js","sourceRoot":"","sources":["../../../src/packlets/store/fileTreeMemoryStore.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Hash, Logging, Result, fail, mapResults, succeed } from '@fgv/ts-utils';\nimport { FileTree } from '@fgv/ts-json-base';\nimport {\n AdmissionDecision,\n DEFAULT_DEDUP_SCOPE,\n DedupScope,\n EntityId,\n IIdentityCodec,\n IMemoryEnvelope,\n IMemoryRecord,\n IProvenance,\n IWritePolicy,\n Kind,\n KnowledgeLwwPolicy,\n MemoryId,\n MemoryScopeKey,\n Tag\n} from '../types';\nimport { IBodyConverterRegistry as IRegistry, parseMemoryFile, serializeMemoryFile } from '../converters';\nimport { IIndexedMemoryRecord, IMemoryIndex, MemoryIndex } from '../index';\nimport {\n IMemoryObservationRecord,\n IMemoryObserver,\n MemoryObservationOutcome,\n MemoryObservationPhase\n} from '../observe';\nimport { IVectorIndex, MemoryEmbedder } from '../vector';\nimport { defaultMemoryScopeEncoding } from './scopeEncoding';\n\n/** The on-disk extension for a memory record file. */\nconst MEMORY_FILE_EXTENSION: string = '.md';\n\n/**\n * Filter for {@link IMemoryStore.list}. All present fields are ANDed together.\n * @public\n */\nexport interface IMemoryStoreListFilter {\n /** Restrict to records in this scope. */\n readonly scope?: MemoryScopeKey;\n /** Restrict to records of this kind. */\n readonly kind?: Kind;\n /** Restrict to records carrying this tag (exact match). */\n readonly tag?: Tag;\n /**\n * For temporal kinds: return only records valid at this epoch ms. No-op in\n * B1 (no temporal kinds wired).\n */\n readonly asOf?: number;\n}\n\n/**\n * The writable, FileTree-backed, content-hash-deduped memory store.\n * @public\n */\nexport interface IMemoryStore {\n /**\n * Keyed read by entity id. Resolves `entityId` to a storage address via the\n * registered {@link IIdentityCodec} for `kind`. Returns `undefined` when no\n * record exists.\n */\n get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;\n\n /**\n * Direct read by `(scope, MemoryId)`. Returns `undefined` when not found.\n */\n getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;\n\n /**\n * List records, filtered in-memory over the derived index.\n */\n list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;\n\n /**\n * Write a record. Validates the body, computes a content hash, deduplicates\n * (scope-wide, before policy), applies the kind's {@link IWritePolicy}, stamps\n * transaction-time metadata (`created` / `updated` / `seq` / `contentHash`),\n * writes the file, and patches the index. Returns the written record — or the\n * existing record unchanged on a dedup no-op.\n */\n put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;\n\n /**\n * Delete a record by `(kind, entityId)`. Non-temporal kinds physically delete\n * the file. Returns the {@link MemoryId} of the deleted record.\n */\n delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;\n}\n\n/**\n * Parameters for {@link FileTreeMemoryStore.create}.\n * @public\n */\nexport interface IFileTreeMemoryStoreCreateParams {\n /** Root directory under which scope-encoded sub-trees live. Must be mutable. */\n readonly root: FileTree.IMutableFileTreeDirectoryItem;\n /** Per-kind body converter registry. Gates every body on write and read. */\n readonly registry: IRegistry;\n /** Per-kind write policies. Kinds without an entry use a default LWW policy. */\n readonly writePolicies?: ReadonlyMap<Kind, IWritePolicy>;\n /** Per-kind identity codecs. */\n readonly codecs?: ReadonlyMap<Kind, IIdentityCodec>;\n /** Default codec for kinds without an explicit entry. */\n readonly defaultCodec?: IIdentityCodec;\n /** Scope encoding. Defaults to {@link defaultMemoryScopeEncoding}. */\n readonly scopeEncoding?: (scope: MemoryScopeKey) => Result<string>;\n /**\n * Transaction-time clock. Defaults to `Date.now`. Injectable so tests can\n * make `created` / `updated` deterministic. Also stamps observation\n * `timestamp`s.\n */\n readonly clock?: () => number;\n /**\n * Optional observers fired once per public `get` / `put` / `delete` call.\n * Purely additive — when absent, no observation records are produced and the\n * store behaves exactly as it did without this parameter. Observer errors\n * never affect the store operation (swallowed, logged to {@link\n * IFileTreeMemoryStoreCreateParams.logger | logger} at `warn`).\n */\n readonly observers?: ReadonlyArray<IMemoryObserver>;\n /**\n * Diagnostic logger for swallowed observer failures. Defaults to a\n * `Logging.NoOpLogger`.\n */\n readonly logger?: Logging.ILogger;\n /**\n * Optional vector index for semantic recall. Wired together with\n * {@link IFileTreeMemoryStoreCreateParams.embed | embed}: when both are present\n * the store embeds each written record and maintains the index on\n * `put` / `delete` / cap-cull eviction. Absent (or `embed` absent) → no\n * embedding work happens and the store behaves exactly as it does without this\n * parameter (the additive, zero-overhead-when-unwired default — mirrors the\n * observer hook).\n */\n readonly vectorIndex?: IVectorIndex;\n /**\n * Optional embedder applied to each record on write, wired together with\n * {@link IFileTreeMemoryStoreCreateParams.vectorIndex | vectorIndex}. The\n * consumer supplies it (e.g. `callProviderEmbedding` or in-process\n * transformers); the store never calls an embedding provider directly, so the\n * core stays embedder-agnostic. Embedding/index maintenance is **best-effort**:\n * a failed (or throwing) `embed` / `add` / `remove` is logged at `warn` via\n * {@link IFileTreeMemoryStoreCreateParams.logger | logger} and the record\n * operation still succeeds — the vector index is a derived view that a later\n * `rebuild` reconciles, so a vector failure never fails an authoritative write.\n */\n readonly embed?: MemoryEmbedder;\n}\n\n/**\n * The internal outcome of a locked `put`: the written (or existing, on a\n * dedup no-op) record plus the {@link MemoryId}s evicted by a `cull-oldest`\n * admission decision. The eviction file-deletes and index patches happen\n * inside the write-lock; the `evicted` ids are surfaced so the public `put`\n * can fire one `'delete'` observation per evicted record AFTER the lock\n * releases — consistent with the post-op firing of the other observation\n * hooks, and avoiding observer re-entrancy into the still-held write-lock.\n */\ninterface IPutOutcome {\n readonly record: IMemoryRecord<unknown>;\n readonly evicted: ReadonlyArray<MemoryId>;\n}\n\n/**\n * The resolved storage address + content hash for a put, produced by the\n * synchronous prefix of `_putLocked` and handed to the async write tail.\n */\ninterface IResolvedWriteAddress {\n readonly scope: MemoryScopeKey;\n readonly idStem: string;\n readonly hash: string;\n}\n\ninterface IInternalParams {\n readonly root: FileTree.IMutableFileTreeDirectoryItem;\n readonly registry: IRegistry;\n readonly writePolicies: ReadonlyMap<Kind, IWritePolicy>;\n readonly codecs: ReadonlyMap<Kind, IIdentityCodec>;\n readonly defaultCodec?: IIdentityCodec;\n readonly defaultPolicy: IWritePolicy;\n readonly scopeEncoding: (scope: MemoryScopeKey) => Result<string>;\n readonly clock: () => number;\n readonly index: IMemoryIndex;\n readonly observers: ReadonlyArray<IMemoryObserver>;\n readonly logger: Logging.ILogger;\n readonly vectorIndex?: IVectorIndex;\n readonly embed?: MemoryEmbedder;\n}\n\n/**\n * Flat-layout, FileTree-backed {@link IMemoryStore}. The FileTree is the source\n * of truth; the {@link IMemoryIndex} is a derived in-memory view patched on\n * every write. Concurrent writes are serialized through a per-instance async\n * write-lock so the index and the on-disk files never interleave.\n *\n * @remarks\n * B1 supports flat (non-versioned) layout only and string (markdown) bodies.\n * A codec reporting `isVersioned: true`, or a non-string body, fails loudly —\n * the versioned/temporal write path is a fast-follow.\n * @public\n */\nexport class FileTreeMemoryStore implements IMemoryStore {\n private readonly _root: FileTree.IMutableFileTreeDirectoryItem;\n private readonly _registry: IRegistry;\n private readonly _writePolicies: ReadonlyMap<Kind, IWritePolicy>;\n private readonly _codecs: ReadonlyMap<Kind, IIdentityCodec>;\n private readonly _defaultCodec: IIdentityCodec | undefined;\n private readonly _defaultPolicy: IWritePolicy;\n private readonly _scopeEncoding: (scope: MemoryScopeKey) => Result<string>;\n private readonly _clock: () => number;\n private readonly _index: IMemoryIndex;\n private readonly _hasher: Hash.Crc32Normalizer;\n private readonly _observers: ReadonlyArray<IMemoryObserver>;\n private readonly _logger: Logging.ILogger;\n private readonly _vectorIndex: IVectorIndex | undefined;\n private readonly _embed: MemoryEmbedder | undefined;\n\n /** Monotonic write counter; incremented inside the write-lock on each put. */\n private _seq: number;\n /**\n * Monotonic observation-sequence counter. A distinct authority from `_seq`\n * (the envelope write counter): it numbers the audit stream so a single\n * {@link MemoryObservationStore} fed by this store sees strictly increasing\n * `seq`, satisfying the ring buffer's cursor contract.\n */\n private _observationSeq: number;\n /** Tail of the write-lock promise chain that serializes mutating ops. */\n private _writeTail: Promise<unknown>;\n\n /**\n * The record-level mutable-field vocabulary: maps a declared mutable field\n * name to its canonical location on a record. Used to project an incoming\n * record into a merge-patch on update. B1 ships the knowledge-LWW surface\n * (body + envelope metadata); body-internal mutable fields (Phase-C cap-cull)\n * extend this map.\n */\n private static readonly _mutableFieldAccessors: ReadonlyMap<\n string,\n (record: IMemoryRecord<unknown>) => unknown\n > = new Map<string, (record: IMemoryRecord<unknown>) => unknown>([\n ['body', (r) => r.body],\n ['tags', (r) => r.envelope.tags],\n ['links', (r) => r.envelope.links],\n ['provenance', (r) => r.envelope.provenance],\n ['embeddingRef', (r) => r.envelope.embeddingRef]\n ]);\n\n private constructor(params: IInternalParams) {\n this._root = params.root;\n this._registry = params.registry;\n this._writePolicies = params.writePolicies;\n this._codecs = params.codecs;\n this._defaultCodec = params.defaultCodec;\n this._defaultPolicy = params.defaultPolicy;\n this._scopeEncoding = params.scopeEncoding;\n this._clock = params.clock;\n this._index = params.index;\n this._hasher = new Hash.Crc32Normalizer();\n this._observers = params.observers;\n this._logger = params.logger;\n this._vectorIndex = params.vectorIndex;\n this._embed = params.embed;\n this._seq = 0;\n this._observationSeq = 0;\n this._writeTail = Promise.resolve();\n }\n\n /**\n * Family-convention factory. Builds the derived index and a default LWW\n * policy, then performs an initial FileTree walk so an existing vault is\n * indexed (and the `seq` counter resumes past the highest persisted `seq`).\n */\n public static create(params: IFileTreeMemoryStoreCreateParams): Result<FileTreeMemoryStore> {\n return KnowledgeLwwPolicy.create().onSuccess((defaultPolicy) =>\n MemoryIndex.create().onSuccess((index) => {\n const store: FileTreeMemoryStore = new FileTreeMemoryStore({\n root: params.root,\n registry: params.registry,\n writePolicies: params.writePolicies ?? new Map<Kind, IWritePolicy>(),\n codecs: params.codecs ?? new Map<Kind, IIdentityCodec>(),\n defaultCodec: params.defaultCodec,\n defaultPolicy,\n scopeEncoding: params.scopeEncoding ?? defaultMemoryScopeEncoding,\n clock: params.clock ?? Date.now,\n index,\n observers: params.observers ?? [],\n logger: params.logger ?? new Logging.NoOpLogger(),\n vectorIndex: params.vectorIndex,\n embed: params.embed\n });\n return store._initialIndex().onSuccess(() => succeed(store));\n })\n );\n }\n\n /** {@inheritDoc IMemoryStore.get} */\n public async get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>> {\n const result: Result<IMemoryRecord<unknown> | undefined> = this._codecFor(kind).onSuccess((codec) =>\n codec.encode(entityId).onSuccess((addr) => {\n if (addr.isVersioned) {\n return fail(`memory get '${entityId}': versioned/temporal layout not yet supported`);\n }\n return this._readRecord(addr.scope, addr.idStem);\n })\n );\n await this._fireObservation('read', kind, entityId, {\n outcome: result.isSuccess() ? 'success' : 'failure',\n id: result.isSuccess() ? result.value?.envelope.id : undefined,\n error: result.isFailure() ? result.message : undefined\n });\n return result;\n }\n\n /** {@inheritDoc IMemoryStore.getById} */\n public async getById(\n scope: MemoryScopeKey,\n id: MemoryId\n ): Promise<Result<IMemoryRecord<unknown> | undefined>> {\n return this._readRecord(scope, id);\n }\n\n /** {@inheritDoc IMemoryStore.list} */\n public async list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n const matches: IMemoryRecord<unknown>[] = this._index\n .entries()\n .filter((entry) => {\n if (filter?.scope !== undefined && entry.scope !== filter.scope) {\n return false;\n }\n if (filter?.kind !== undefined && entry.record.envelope.kind !== filter.kind) {\n return false;\n }\n if (filter?.tag !== undefined && !entry.record.envelope.tags.includes(filter.tag)) {\n return false;\n }\n return true;\n })\n .map((entry) => entry.record);\n return succeed(matches);\n }\n\n /** {@inheritDoc IMemoryStore.put} */\n public async put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>> {\n const result: Result<IPutOutcome> = await this._enqueue(() => this._putLocked(record));\n await this._fireObservation('write', record.envelope.kind, record.envelope.entityId, {\n outcome: result.isSuccess() ? 'success' : 'failure',\n id: result.isSuccess() ? result.value.record.envelope.id : record.envelope.id,\n provenance: record.envelope.provenance,\n error: result.isFailure() ? result.message : undefined\n });\n // Fire one `'delete'` observation per record evicted by cap-cull. The\n // evicted records are always in the same `(scope, kind)` cohort as the\n // incoming record, so resolving the scope from the incoming `entityId`\n // yields the evicted record's scope; the observation records the evicted\n // record's own `id`. A no-op / first-write / reject path yields no\n // evictions, so this loop is empty there.\n if (result.isSuccess()) {\n for (const evictedId of result.value.evicted) {\n await this._fireObservation('delete', record.envelope.kind, record.envelope.entityId, {\n outcome: 'success',\n id: evictedId\n });\n }\n }\n return result.onSuccess((outcome) => succeed(outcome.record));\n }\n\n /** {@inheritDoc IMemoryStore.delete} */\n public async delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>> {\n const result: Result<MemoryId> = await this._enqueue(() => this._deleteLocked(kind, entityId));\n await this._fireObservation('delete', kind, entityId, {\n outcome: result.isSuccess() ? 'success' : 'failure',\n id: result.isSuccess() ? result.value : undefined,\n error: result.isFailure() ? result.message : undefined\n });\n return result;\n }\n\n /**\n * Serialize a mutating task behind the write-lock. Tasks run in submission\n * order; a failed task does not break the chain for subsequent ones.\n */\n private _enqueue<T>(task: () => Promise<Result<T>>): Promise<Result<T>> {\n const result: Promise<Result<T>> = this._writeTail.then(task);\n this._writeTail = result.then(\n () => undefined,\n () => undefined\n );\n return result;\n }\n\n /**\n * Build and fan out one observation record for a completed op. A no-op when no\n * observers are wired (the additive-default path pays nothing). The store is\n * the seq authority — it mints `seq` / `timestamp` so every observer sees the\n * same record. The scope is resolved best-effort via the codec.\n */\n private async _fireObservation(\n phase: MemoryObservationPhase,\n kind: Kind,\n entityId: EntityId,\n details: {\n readonly outcome: MemoryObservationOutcome;\n readonly id?: MemoryId;\n readonly provenance?: IProvenance;\n readonly error?: string;\n }\n ): Promise<void> {\n if (this._observers.length === 0) {\n return;\n }\n const record: IMemoryObservationRecord = {\n seq: ++this._observationSeq,\n timestamp: this._clock(),\n phase,\n scope: this._scopeBestEffort(kind, entityId),\n id: details.id,\n kind,\n outcome: details.outcome,\n error: details.error,\n provenance: details.provenance\n };\n const awaited: Promise<void>[] = [];\n for (const observer of this._observers) {\n if (observer.fireAndForget === true) {\n // Intentionally not awaited: a fire-and-forget observer must not extend\n // the store op's latency. `_safeObserve` swallows internally; the\n // `.catch` keeps the detached promise from being flagged as floating.\n this._safeObserve(observer, record).catch(() => undefined);\n } else {\n awaited.push(this._safeObserve(observer, record));\n }\n }\n await Promise.all(awaited);\n }\n\n /** Invoke one observer, swallowing any failure or throw (logged at `warn`). */\n private async _safeObserve(observer: IMemoryObserver, record: IMemoryObservationRecord): Promise<void> {\n try {\n const observed: Result<unknown> = await observer.observe(record);\n if (observed.isFailure()) {\n this._warnSwallowed(`memory observer failed (swallowed): ${observed.message}`);\n }\n } catch (error) {\n this._warnSwallowed(`memory observer threw (swallowed): ${String(error)}`);\n }\n }\n\n /**\n * Log a swallowed-issue warning (observer failure or best-effort vector\n * maintenance), tolerating a logger that itself throws — diagnostic logging\n * must never make a store op reject.\n */\n private _warnSwallowed(message: string): void {\n try {\n this._logger.warn(message);\n } catch {\n // Diagnostic logging must not affect the store operation.\n }\n }\n\n /** Resolve a scope for an observation, best-effort (undefined when unresolvable). */\n private _scopeBestEffort(kind: Kind, entityId: EntityId): MemoryScopeKey | undefined {\n return this._codecFor(kind)\n .onSuccess((codec) => codec.encode(entityId))\n .onSuccess((addr) => succeed(addr.scope))\n .orDefault();\n }\n\n private async _putLocked(record: IMemoryRecord<unknown>): Promise<Result<IPutOutcome>> {\n const envelope: IMemoryEnvelope = record.envelope;\n if (typeof record.body !== 'string') {\n return fail(\n `memory put '${envelope.id}': only string (markdown) bodies are supported (got ${typeof record.body})`\n );\n }\n const body: string = record.body;\n // Resolve the synchronous prefix (body validation → codec address → content\n // hash) into a small descriptor, then bridge to the async write tail (which\n // embeds on write). Keeping the sync prefix intact preserves the exact\n // dedup/policy ordering of the original; only the embed step is new.\n return this._registry\n .convert(envelope.kind, body)\n .withErrorFormat((msg) => `memory put '${envelope.id}': invalid body: ${msg}`)\n .onSuccess(() => this._codecFor(envelope.kind))\n .onSuccess(\n (codec): Result<IResolvedWriteAddress> =>\n codec.encode(envelope.entityId).onSuccess((addr): Result<IResolvedWriteAddress> => {\n if (addr.isVersioned) {\n return fail(`memory put '${envelope.entityId}': versioned/temporal layout not yet supported`);\n }\n if (envelope.id !== addr.idStem) {\n return fail(\n `memory put: envelope id '${envelope.id}' does not match codec-derived stem '${addr.idStem}'`\n );\n }\n return this._contentHash(envelope.kind, body, envelope.links).onSuccess((hash) =>\n succeed({ scope: addr.scope, idStem: addr.idStem, hash })\n );\n })\n )\n .thenOnSuccess((resolved) =>\n this._writeResolved(record, body, resolved.scope, resolved.idStem, resolved.hash)\n );\n }\n\n /**\n * Run dedup → policy → stamp → embed → write for a resolved address and content\n * hash. Async because the embed-on-write hook (when wired) does a network call\n * or in-process inference; the whole chain runs inside the write-lock so the\n * vector index, the on-disk file, and the derived index never interleave.\n */\n private async _writeResolved(\n record: IMemoryRecord<unknown>,\n body: string,\n scope: MemoryScopeKey,\n idStem: string,\n hash: string\n ): Promise<Result<IPutOutcome>> {\n const policy: IWritePolicy = this._policyFor(record.envelope.kind);\n const dedupScope: DedupScope = policy.dedupScope ?? DEFAULT_DEDUP_SCOPE;\n // Content-hash dedup runs BEFORE policy. Its granularity is the kind's\n // `dedupScope`:\n // - 'content': an identical { kind, body, links } triple ANYWHERE in the\n // scope (even under a different id) is a no-op (knowledge family).\n // - 'entity' (default): only an identical re-put of the SAME id is a no-op;\n // two distinct entities with identical content never collapse (experience\n // families). The same-id check is folded into the `_readRecord` below.\n // (Tags / provenance are metadata and are NOT part of the hash; see\n // design-lock §2.5.)\n if (dedupScope === 'content') {\n const duplicate: IMemoryRecord<unknown> | undefined = this._findByContentHash(scope, hash);\n if (duplicate !== undefined) {\n return succeed({ record: duplicate, evicted: [] });\n }\n }\n return this._readRecord(scope, idStem).thenOnSuccess((existing) => {\n if (dedupScope === 'entity' && existing !== undefined && existing.envelope.contentHash === hash) {\n // Entity-scoped dedup: an identical re-put of the same entity is a no-op.\n return Promise.resolve(succeed({ record: existing, evicted: [] }));\n }\n // The admission cohort is the set of records the policy's cap applies to:\n // every record in this scope of this kind EXCEPT the target id. On a first\n // write the post-write count is `cohort.length + 1`; on an update the prior\n // same-id record is excluded so the count is still `cohort.length + 1`\n // (a replace, not a grow). The same-id `existing` record is threaded\n // separately into `_buildRecord` for the merge-patch. Knowledge LWW ignores\n // this argument, so its behavior is unchanged by the wider cohort.\n const cohort: ReadonlyArray<IMemoryRecord<unknown>> = this._admissionCohort(\n scope,\n record.envelope.kind,\n idStem\n );\n return policy\n .admit(record, cohort)\n .thenOnSuccess((decision) =>\n this._admitWrite(record, body, scope, idStem, hash, policy, existing, decision)\n );\n });\n }\n\n /**\n * Build → embed → persist → evict for an admitted write.\n *\n * The durable record store is authoritative; the vector index is a **derived,\n * rebuildable** view, so vector maintenance is **best-effort** — a failed embed\n * or `add` is logged and the durable write still succeeds (the index can be\n * rebuilt via {@link InMemoryCosineIndex.rebuild}). Only genuine record-store\n * failures (body/codec/policy, persist, file eviction) fail the `put`.\n *\n * Ordering: the embed + `add` run immediately before the single `_persist` so\n * the index-returned `embeddingRef` lands in one durable write (a post-persist\n * stamp would need a second write whose failure path is effectively untestable).\n * Build and persist the replacement BEFORE evicting the cull-oldest cohort, so a\n * later eviction failure never loses data with nothing written in its place.\n */\n private async _admitWrite(\n record: IMemoryRecord<unknown>,\n body: string,\n scope: MemoryScopeKey,\n idStem: string,\n hash: string,\n policy: IWritePolicy,\n existing: IMemoryRecord<unknown> | undefined,\n decision: AdmissionDecision\n ): Promise<Result<IPutOutcome>> {\n if (decision.decision === 'reject') {\n return fail(`memory put: rejected by policy: ${decision.reason}`);\n }\n return this._buildRecord(record, body, existing, policy, hash)\n .thenOnSuccess((built) => this._embedOnWrite(built))\n .onSuccess((embeddedBuilt) => this._persist(embeddedBuilt, scope, idStem))\n .thenOnSuccess(async (persisted) => {\n // Everything after the authoritative `_persist` commit is best-effort and\n // never turns a committed write into a `Failure`:\n // - a cull-oldest eviction that fails is logged (the per-(scope,kind)\n // cap may be transiently exceeded; the next write's admission restores\n // it), and only the successfully-evicted ids flow onward;\n // - vector pruning of the evicted cohort is likewise best-effort.\n const evicted: ReadonlyArray<MemoryId> = this._applyEvictions(decision, scope);\n await this._removeEvictedVectors(evicted);\n return succeed({ record: persisted, evicted });\n });\n }\n\n /**\n * Best-effort embed-on-write. When a vector index AND an embedder are wired,\n * embeds the built record, `add`s the vector (replace semantics handle a same-id\n * re-embed — no explicit remove), and stamps the returned `embeddingRef`. A\n * failure (returned `fail` OR a thrown/rejected hook) is logged and the\n * unembedded record is returned unchanged — the put still persists, and the\n * derived index is reconciled by a later `rebuild`. A pass-through no-op when\n * unwired (byte-identical record).\n *\n * Always succeeds (`Result` is the chain's shape, never a vector-induced\n * failure).\n */\n private async _embedOnWrite(built: IMemoryRecord<string>): Promise<Result<IMemoryRecord<string>>> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n return succeed(built);\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n const embed: MemoryEmbedder = this._embed;\n const embedded: Result<Float32Array> = await this._tryVectorOp(\n () => embed(built),\n `embedding '${built.envelope.id}'`\n );\n if (embedded.isFailure()) {\n return succeed(built);\n }\n const added: Result<string> = await this._tryVectorOp(\n () => vectorIndex.add(built.envelope.id, embedded.value),\n `vector add for '${built.envelope.id}'`\n );\n if (added.isFailure()) {\n return succeed(built);\n }\n return succeed({ envelope: { ...built.envelope, embeddingRef: added.value }, body: built.body });\n }\n\n /**\n * Evict the records named by a `cull-oldest` decision, best-effort. Runs only\n * after the authoritative `_persist`, so a failed eviction is logged (never\n * fatal) and the cap self-corrects on the next admission. Returns the ids that\n * were actually evicted (so observations / vector pruning cover only those).\n * `accept` / `reject` decisions evict nothing.\n */\n private _applyEvictions(decision: AdmissionDecision, scope: MemoryScopeKey): ReadonlyArray<MemoryId> {\n if (decision.decision !== 'cull-oldest') {\n return [];\n }\n const evicted: MemoryId[] = [];\n for (const id of decision.evict) {\n const result: Result<MemoryId> = this._evict(scope, id);\n if (result.isSuccess()) {\n evicted.push(result.value);\n } else {\n this._warnSwallowed(\n `memory put: best-effort eviction of '${id}' failed (cap may be transiently exceeded; restored on the next write): ${result.message}`\n );\n }\n }\n return evicted;\n }\n\n /** Best-effort vector removal for each evicted record (never fails the put). */\n private async _removeEvictedVectors(evicted: ReadonlyArray<MemoryId>): Promise<void> {\n for (const id of evicted) {\n await this._removeVectorBestEffort(id);\n }\n }\n\n /**\n * Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a\n * `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds\n * regardless, since the index is rebuildable.\n */\n private async _tryVectorOp<T>(op: () => Promise<Result<T>>, label: string): Promise<Result<T>> {\n let result: Result<T>;\n try {\n result = await op();\n } catch (err) {\n result = fail(`${label} threw: ${String(err)}`);\n }\n if (result.isFailure()) {\n this._warnSwallowed(\n `memory: ${label} failed (best-effort; vector index left for rebuild): ${result.message}`\n );\n }\n return result;\n }\n\n /**\n * Best-effort vector removal. A no-op unless the full vector lifecycle is wired\n * (both an index AND an embedder), so an unwired store does no vector work and\n * behaves byte-identically. Failures are logged, never surfaced — a committed\n * delete/eviction must not fail because a derived index could not be pruned.\n */\n private async _removeVectorBestEffort(id: MemoryId): Promise<void> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n return;\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n await this._tryVectorOp(() => vectorIndex.remove(id), `vector removal for '${id}'`);\n }\n\n /**\n * Build the record to persist. On a first write the incoming envelope is the\n * base (final content equals the incoming content, so the dedup `hash` is\n * reused). On an update the incoming record's mutable fields are projected into\n * a merge-patch and the policy's `applyUpdate` merges them over the existing\n * record (preserving `created`); the persisted body and `contentHash` are then\n * taken from the policy's actual output, so a body-transforming policy is never\n * bypassed and the stored hash always matches the stored `{ kind, body, links }`.\n * The store stamps the transaction-time metadata it owns\n * (`created` / `updated` / `seq` / `contentHash`).\n */\n private _buildRecord(\n incoming: IMemoryRecord<unknown>,\n body: string,\n existing: IMemoryRecord<unknown> | undefined,\n policy: IWritePolicy,\n hash: string\n ): Result<IMemoryRecord<string>> {\n const now: number = this._clock();\n const seq: number = ++this._seq;\n if (existing === undefined) {\n return succeed({\n envelope: { ...incoming.envelope, created: now, updated: now, seq, contentHash: hash },\n body\n });\n }\n const patch: Record<string, unknown> = this._projectMutablePatch(incoming, policy.mutableFields);\n return policy\n .applyUpdate(existing, patch)\n .withErrorFormat((msg) => `memory put '${incoming.envelope.id}': update failed: ${msg}`)\n .onSuccess((updated) => {\n if (typeof updated.body !== 'string') {\n return fail(\n `memory put '${incoming.envelope.id}': policy returned a non-string body (${typeof updated.body})`\n );\n }\n const finalBody: string = updated.body;\n return this._contentHash(updated.envelope.kind, finalBody, updated.envelope.links).onSuccess(\n (finalHash) =>\n succeed({\n envelope: {\n ...updated.envelope,\n created: existing.envelope.created,\n updated: now,\n seq,\n contentHash: finalHash\n },\n body: finalBody\n })\n );\n });\n }\n\n /** Serialize and write a fully-stamped record, then patch the index. */\n private _persist(\n record: IMemoryRecord<string>,\n scope: MemoryScopeKey,\n idStem: string\n ): Result<IMemoryRecord<unknown>> {\n return serializeMemoryFile(record.envelope, record.body)\n .onSuccess((raw) => this._writeFile(scope, idStem, raw))\n .onSuccess(() => this._index.patch('put', { scope, record }))\n .onSuccess(() => succeed(record));\n }\n\n private async _deleteLocked(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>> {\n return this._codecFor(kind)\n .onSuccess((codec) => codec.encode(entityId))\n .thenOnSuccess((addr) => {\n if (addr.isVersioned) {\n return Promise.resolve(\n fail<MemoryId>(`memory delete '${entityId}': versioned/temporal layout not yet supported`)\n );\n }\n return this._readRecord(addr.scope, addr.idStem).thenOnSuccess((existing) => {\n if (existing === undefined) {\n return Promise.resolve(fail<MemoryId>(`memory delete '${entityId}': no record found`));\n }\n // Delete the record file + index entry (authoritative), then prune the\n // vector best-effort: a committed delete must not fail because the\n // derived index could not be pruned.\n return this._deleteFile(addr.scope, addr.idStem)\n .onSuccess(() => this._index.patch('delete', { scope: addr.scope, record: existing }))\n .thenOnSuccess(async () => {\n await this._removeVectorBestEffort(existing.envelope.id);\n return succeed(existing.envelope.id);\n });\n });\n });\n }\n\n /** Evict (physically delete) a single record file by id, patching the index. */\n private _evict(scope: MemoryScopeKey, id: MemoryId): Result<MemoryId> {\n return this._readRecord(scope, id).onSuccess((existing) => {\n if (existing === undefined) {\n return fail(`memory put: cannot evict '${id}' in scope '${scope}': not found`);\n }\n return this._deleteFile(scope, id)\n .onSuccess(() => this._index.patch('delete', { scope, record: existing }))\n .onSuccess(() => succeed(id));\n });\n }\n\n /** Project the incoming record's mutable fields into a merge-patch. */\n private _projectMutablePatch(\n record: IMemoryRecord<unknown>,\n mutableFields: ReadonlyArray<string>\n ): Record<string, unknown> {\n const patch: Record<string, unknown> = {};\n for (const field of mutableFields) {\n const accessor: ((record: IMemoryRecord<unknown>) => unknown) | undefined =\n FileTreeMemoryStore._mutableFieldAccessors.get(field);\n if (accessor !== undefined) {\n const value: unknown = accessor(record);\n if (value !== undefined) {\n patch[field] = value;\n }\n }\n }\n return patch;\n }\n\n /**\n * The admission cohort for a write: every indexed record in `scope` of `kind`\n * except the one at `idStem` (the record being written or updated). This is\n * the set a per-kind cap (e.g. {@link MemoryCapCullPolicy}) counts against, so\n * a bounded-ring policy can keep a per-scope/per-kind family within\n * `maxRecords`. Excluding the target id makes the post-write count uniform\n * across first-writes and updates.\n */\n private _admissionCohort(\n scope: MemoryScopeKey,\n kind: Kind,\n idStem: string\n ): ReadonlyArray<IMemoryRecord<unknown>> {\n return this._index\n .entries()\n .filter(\n (entry) =>\n entry.scope === scope && entry.record.envelope.kind === kind && entry.record.envelope.id !== idStem\n )\n .map((entry) => entry.record);\n }\n\n /** Find a record in `scope` whose `contentHash` equals `hash`, if any. */\n private _findByContentHash(scope: MemoryScopeKey, hash: string): IMemoryRecord<unknown> | undefined {\n const match: IIndexedMemoryRecord | undefined = this._index\n .entries()\n .find((entry) => entry.scope === scope && entry.record.envelope.contentHash === hash);\n return match?.record;\n }\n\n private _contentHash(kind: Kind, body: string, links: IMemoryEnvelope['links']): Result<string> {\n return this._hasher.computeHash({ kind, body, links });\n }\n\n private _codecFor(kind: Kind): Result<IIdentityCodec> {\n const codec: IIdentityCodec | undefined = this._codecs.get(kind) ?? this._defaultCodec;\n if (codec === undefined) {\n return fail(`no identity codec registered for kind '${kind}'`);\n }\n return succeed(codec);\n }\n\n private _policyFor(kind: Kind): IWritePolicy {\n return this._writePolicies.get(kind) ?? this._defaultPolicy;\n }\n\n /**\n * Read and validate the record at `<scope>/<idStem>.md`, returning `undefined`\n * when the scope directory or file is absent. Verifies the on-disk id ↔\n * filename round-trip on every load.\n */\n private _readRecord(scope: MemoryScopeKey, idStem: string): Result<IMemoryRecord<unknown> | undefined> {\n return this._resolveScopeDir(scope).onSuccess((scopeDir) => {\n if (scopeDir === undefined) {\n return succeed(undefined);\n }\n return scopeDir.getChildren().onSuccess((children) => {\n const targetName: string = `${idStem}${MEMORY_FILE_EXTENSION}`;\n const file: FileTree.IFileTreeFileItem | undefined = children.find(\n (c): c is FileTree.IFileTreeFileItem => c.type === 'file' && c.name === targetName\n );\n if (file === undefined) {\n return succeed(undefined);\n }\n return file\n .getRawContents()\n .onSuccess((raw) => parseMemoryFile(raw, this._registry))\n .onSuccess((parsedRecord) => this._verifyLoaded(scope, file, parsedRecord));\n });\n });\n }\n\n /** Enforce `envelope.id === filename stem` and the codec round-trip on load. */\n private _verifyLoaded(\n scope: MemoryScopeKey,\n file: FileTree.IFileTreeFileItem,\n record: IMemoryRecord<unknown>\n ): Result<IMemoryRecord<unknown>> {\n if (record.envelope.id !== file.baseName) {\n return fail(\n `memory file '${file.absolutePath}': envelope id '${record.envelope.id}' does not match filename stem '${file.baseName}'`\n );\n }\n return this._codecFor(record.envelope.kind)\n .onSuccess((codec) => codec.verifyRoundTrip(scope, file.baseName))\n .withErrorFormat((msg) => `memory file '${file.absolutePath}': ${msg}`)\n .onSuccess(() => succeed(record));\n }\n\n /**\n * Resolve the directory for a scope, returning `undefined` when it does not\n * exist. Navigation only — does not create. Folds the path segments through\n * `getChildren` so an absent segment short-circuits to `undefined`.\n */\n private _resolveScopeDir(scope: MemoryScopeKey): Result<FileTree.IFileTreeDirectoryItem | undefined> {\n return this._scopeEncoding(scope).onSuccess((encoded) => {\n const segments: string[] = encoded.split('/').filter((s) => s.length > 0);\n return segments.reduce<Result<FileTree.IFileTreeDirectoryItem | undefined>>(\n (acc, segment) =>\n acc.onSuccess((current) => {\n if (current === undefined) {\n return succeed(undefined);\n }\n return current\n .getChildren()\n .onSuccess((children) =>\n succeed(\n children.find(\n (c): c is FileTree.IFileTreeDirectoryItem => c.type === 'directory' && c.name === segment\n )\n )\n );\n }),\n succeed(this._root)\n );\n });\n }\n\n /** Ensure the scope directory exists, creating segments as needed. */\n private _ensureScopeDir(scope: MemoryScopeKey): Result<FileTree.IMutableFileTreeDirectoryItem> {\n return this._scopeEncoding(scope).onSuccess((encoded) => {\n const segments: string[] = encoded.split('/').filter((s) => s.length > 0);\n return segments.reduce<Result<FileTree.IMutableFileTreeDirectoryItem>>(\n (acc, segment) =>\n acc.onSuccess((current) =>\n current.getChildren().onSuccess((children) => {\n const existing: FileTree.FileTreeItem | undefined = children.find(\n (c) => c.type === 'directory' && c.name === segment\n );\n if (existing === undefined) {\n return current.createChildDirectory(segment);\n }\n /* c8 ignore next 3 -- defensive: a child of a mutable in-memory/fs tree is itself mutable; the guard protects against a read-only adapter handed in as root */\n if (!FileTree.isMutableDirectoryItem(existing)) {\n return fail(`${existing.absolutePath}: directory is not mutable`);\n }\n return succeed(existing);\n })\n ),\n succeed(this._root)\n );\n });\n }\n\n /** Write (create or overwrite) `<scope>/<idStem>.md` with `raw`. */\n private _writeFile(scope: MemoryScopeKey, idStem: string, raw: string): Result<true> {\n return this._ensureScopeDir(scope).onSuccess((scopeDir) =>\n scopeDir.getChildren().onSuccess((children) => {\n const fileName: string = `${idStem}${MEMORY_FILE_EXTENSION}`;\n const existing: FileTree.FileTreeItem | undefined = children.find(\n (c) => c.type === 'file' && c.name === fileName\n );\n if (existing === undefined) {\n return scopeDir.createChildFile(fileName, raw).onSuccess(() => succeed(true));\n }\n /* c8 ignore next 3 -- defensive: a file in a mutable tree is mutable; guards a read-only adapter */\n if (!FileTree.isMutableFileItem(existing)) {\n return fail(`${existing.absolutePath}: file is not mutable`);\n }\n return existing.setRawContents(raw).onSuccess(() => succeed(true));\n })\n );\n }\n\n /**\n * Physically delete `<scope>/<idStem>.md`. The scope-missing and file-missing\n * guards are unreachable through the callers (`delete` / `_evict` both read the\n * record first, so the directory and file exist) but are kept so a future\n * direct caller degrades loudly rather than silently.\n */\n private _deleteFile(scope: MemoryScopeKey, idStem: string): Result<true> {\n return this._resolveScopeDir(scope).onSuccess((scopeDir) => {\n /* c8 ignore next 3 -- unreachable: callers read the record (hence the scope dir) first */\n if (scopeDir === undefined) {\n return fail(`memory delete: scope '${scope}' not found`);\n }\n const fileName: string = `${idStem}${MEMORY_FILE_EXTENSION}`;\n return scopeDir.getChildren().onSuccess((children) => {\n const file: FileTree.FileTreeItem | undefined = children.find(\n (c) => c.type === 'file' && c.name === fileName\n );\n /* c8 ignore next 3 -- unreachable: callers read the record (hence the file) first */\n if (file === undefined) {\n return fail(`memory delete: file '${fileName}' not found in scope '${scope}'`);\n }\n /* c8 ignore next 3 -- defensive: a file in a mutable tree is mutable; guards a read-only adapter */\n if (!FileTree.isMutableFileItem(file)) {\n return fail(`${file.absolutePath}: file is not mutable`);\n }\n return file.delete().onSuccess(() => succeed(true));\n });\n });\n }\n\n /**\n * Walk the FileTree once and rebuild the index. Also resumes the `seq`\n * counter past the highest persisted `seq` so new writes stay monotonic.\n */\n private _initialIndex(): Result<true> {\n return this._collectEntries(this._root, []).onSuccess((entries) =>\n this._index.rebuild(entries).onSuccess(() => {\n for (const entry of entries) {\n if (entry.record.envelope.seq > this._seq) {\n this._seq = entry.record.envelope.seq;\n }\n }\n return succeed(true);\n })\n );\n }\n\n /** Recursively collect every `.md` record under `dir` (scope = path segments). */\n private _collectEntries(\n dir: FileTree.IFileTreeDirectoryItem,\n scopeSegments: ReadonlyArray<string>\n ): Result<ReadonlyArray<IIndexedMemoryRecord>> {\n return dir.getChildren().onSuccess((children) => {\n const results: Result<ReadonlyArray<IIndexedMemoryRecord>>[] = children.map((child) => {\n if (child.type === 'directory') {\n return this._collectEntries(child, [...scopeSegments, child.name]);\n }\n if (!child.name.endsWith(MEMORY_FILE_EXTENSION) || scopeSegments.length === 0) {\n // Skip non-record files and any record-shaped file sitting at the root\n // (records always live under at least one scope segment).\n return succeed<ReadonlyArray<IIndexedMemoryRecord>>([]);\n }\n const scope: MemoryScopeKey = scopeSegments.join('/') as MemoryScopeKey;\n return child\n .getRawContents()\n .onSuccess((raw) => parseMemoryFile(raw, this._registry))\n .onSuccess((parsedRecord) => this._verifyLoaded(scope, child, parsedRecord))\n .onSuccess((verified) =>\n succeed<ReadonlyArray<IIndexedMemoryRecord>>([{ scope, record: verified }])\n );\n });\n return mapResults(results).onSuccess((perChild) =>\n succeed<ReadonlyArray<IIndexedMemoryRecord>>(perChild.flat())\n );\n });\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ export * from './fileTreeMemoryStore';
6
+ export * from './scopeEncoding';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/store/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './fileTreeMemoryStore';\nexport * from './scopeEncoding';\n"]}
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import { fail, mapResults, succeed } from '@fgv/ts-utils';
6
+ import { assertPortableFilenameStem } from '../types';
7
+ /**
8
+ * Encode a {@link MemoryScopeKey} to its on-disk directory path. The scope may
9
+ * be multi-segment (`/`-separated) — each component is validated independently
10
+ * against the POSIX portable filename set (via
11
+ * {@link assertPortableFilenameStem}), then rejoined with `/`.
12
+ *
13
+ * @remarks
14
+ * This is the day-one multi-segment scope resolver design-lock §9.1 calls for:
15
+ * the knowledge scope is the single segment `knowledge`, while the Phase-C MTM
16
+ * scope `conversations/<conversationId>` is two segments. Validating each
17
+ * segment independently (rather than the whole path as one stem, which the
18
+ * `ts-prompt-assist` default encoding does) keeps the Phase-C codec additive —
19
+ * no scope-encoding change is needed when MTM ships.
20
+ * @public
21
+ */
22
+ export function defaultMemoryScopeEncoding(scope) {
23
+ // `''.split('/')` yields `['']`, never `[]`, so a single empty-segment check
24
+ // covers the empty-scope case too.
25
+ const segments = scope.split('/');
26
+ if (segments.some((s) => s.length === 0)) {
27
+ return fail(`scope '${scope}': must not contain empty path segments`);
28
+ }
29
+ return mapResults(segments.map((segment) => assertPortableFilenameStem(segment).withErrorFormat((msg) => `scope '${scope}': ${msg}`))).onSuccess((validated) => succeed(validated.join('/')));
30
+ }
31
+ //# sourceMappingURL=scopeEncoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeEncoding.js","sourceRoot":"","sources":["../../../src/packlets/store/scopeEncoding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAkB,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAEtE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAqB;IAC9D,6EAA6E;IAC7E,mCAAmC;IACnC,MAAM,QAAQ,GAAa,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC,UAAU,KAAK,yCAAyC,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,UAAU,CACf,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACvB,0BAA0B,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,KAAK,MAAM,GAAG,EAAE,CAAC,CACzF,CACF,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, mapResults, succeed } from '@fgv/ts-utils';\nimport { MemoryScopeKey, assertPortableFilenameStem } from '../types';\n\n/**\n * Encode a {@link MemoryScopeKey} to its on-disk directory path. The scope may\n * be multi-segment (`/`-separated) — each component is validated independently\n * against the POSIX portable filename set (via\n * {@link assertPortableFilenameStem}), then rejoined with `/`.\n *\n * @remarks\n * This is the day-one multi-segment scope resolver design-lock §9.1 calls for:\n * the knowledge scope is the single segment `knowledge`, while the Phase-C MTM\n * scope `conversations/<conversationId>` is two segments. Validating each\n * segment independently (rather than the whole path as one stem, which the\n * `ts-prompt-assist` default encoding does) keeps the Phase-C codec additive —\n * no scope-encoding change is needed when MTM ships.\n * @public\n */\nexport function defaultMemoryScopeEncoding(scope: MemoryScopeKey): Result<string> {\n // `''.split('/')` yields `['']`, never `[]`, so a single empty-segment check\n // covers the empty-scope case too.\n const segments: string[] = scope.split('/');\n if (segments.some((s) => s.length === 0)) {\n return fail(`scope '${scope}': must not contain empty path segments`);\n }\n return mapResults(\n segments.map((segment) =>\n assertPortableFilenameStem(segment).withErrorFormat((msg) => `scope '${scope}': ${msg}`)\n )\n ).onSuccess((validated) => succeed(validated.join('/')));\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { EntityId, Kind, LinkType, MemoryId, Tag } from './ids';\n\n/**\n * Origin of a provenance attribution. Open vocabulary: the three named\n * sources are conventional, but the `(string & {})` arm admits any other\n * source string without resignature.\n * @public\n */\nexport type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {});\n\n/**\n * Structured provenance for a record or an edge. Never a flat enum — the\n * `[key: string]: unknown` index signature lets a consumer attach an opaque\n * domain payload (e.g. PersonAIlity's sentiment / epistemic blocks) without\n * changing this interface, while still satisfying the no-`any` rule.\n * @public\n */\nexport interface IProvenance {\n /** Where the attribution came from. */\n readonly source: ProvenanceSource;\n /** Optional human or agent identifier responsible for the write. */\n readonly by?: string;\n /** Optional model identifier, when a model produced the content. */\n readonly model?: string;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Back-link to the source experience record. Enables the cross-kind provenance spine. */\n readonly derivedFrom?: MemoryId;\n /** Opaque extension payload — consumer-owned, never interpreted by the store. */\n readonly [key: string]: unknown;\n}\n\n/**\n * An attributed link between two records. Carries the relation type, the\n * target id, and optional confidence / provenance / world-truth validity.\n * Replaces bare string references (e.g. PersonAIlity's `IMtmRef` becomes an\n * `IEdge` with `type: LinkType('mtm-ref')`).\n * @public\n */\nexport interface IEdge {\n /** Open-vocabulary relation type. */\n readonly type: LinkType;\n /** The linked-to record. */\n readonly target: MemoryId;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Optional structured provenance for the link itself. */\n readonly provenance?: IProvenance;\n /** World-truth validity start (epoch ms). Present only on temporal edges. */\n readonly valid_at?: number;\n /**\n * World-truth validity end (epoch ms). `null` = still valid; absent = no\n * temporal extent.\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent (no temporal extent); design-lock §2.3\n readonly invalid_at?: number | null;\n}\n\n/**\n * Optional bi-temporal validity block on an envelope. Present only on\n * temporal kinds; absent = zero cost for atemporal kinds.\n * @public\n */\nexport interface ITemporalBlock {\n /** World-truth validity start (epoch ms). */\n readonly valid_at?: number;\n /** World-truth validity end (epoch ms). `null` = still valid. */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent; design-lock §2.4\n readonly invalid_at?: number | null;\n}\n\n/**\n * The invariant identity + transaction-time envelope carried by every memory\n * record, independent of the per-kind body.\n * @public\n */\nexport interface IMemoryEnvelope {\n // --- Core identity ---\n /** Stable file-stem identifier. MUST equal the on-disk filename stem. */\n readonly id: MemoryId;\n /** Consumer-supplied domain key. Equals {@link IMemoryEnvelope.id | id} for non-temporal kinds. */\n readonly entityId: EntityId;\n /** Consumer-registered kind; dispatches the body Converter. */\n readonly kind: Kind;\n /** Open-vocabulary tags. */\n readonly tags: ReadonlyArray<Tag>;\n /** Attributed outbound edges. */\n readonly links: ReadonlyArray<IEdge>;\n\n // --- Transaction-time metadata (always present) ---\n /** Epoch ms of the first write. Immutable after creation. */\n readonly created: number;\n /** Epoch ms of the most recent write. */\n readonly updated: number;\n /**\n * Monotonic write counter within the store instance, assigned by the store\n * on every successful put. Enables stable cursor paging over observation\n * records without a full walk.\n */\n readonly seq: number;\n /**\n * Content hash over the canonical `{ kind, body, links }`. The dedup key:\n * an exact match is a no-op upsert that returns the existing record.\n */\n readonly contentHash: string;\n /** Structured provenance (never a flat enum). */\n readonly provenance: IProvenance;\n\n // --- Optional temporal block ---\n /** Bi-temporal validity. Present only on temporal kinds. */\n readonly temporal?: ITemporalBlock;\n\n /**\n * Vector-index entry reference, set by the vector index on write. `null` =\n * not embedded; absent = same as `null` (backwards-compat seam).\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is the explicit \"not embedded\" sentinel distinct from absent (backwards-compat seam); design-lock §2.5\n readonly embeddingRef?: string | null;\n}\n\n/**\n * A complete memory record: the invariant {@link IMemoryEnvelope} plus the\n * typed, per-kind body. The store's public surface uses\n * `IMemoryRecord<unknown>`; consumers narrow `TBody` by checking\n * `envelope.kind` and validating through the registered Converter.\n * @public\n */\nexport interface IMemoryRecord<TBody = unknown> {\n /** The invariant identity + transaction-time envelope. */\n readonly envelope: IMemoryEnvelope;\n /** The per-kind, Converter-validated body. */\n readonly body: TBody;\n}\n"]}
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import { fail, succeed } from '@fgv/ts-utils';
6
+ /**
7
+ * Reserved Windows device basenames. Includes `COM0..9` and `LPT0..9` — the
8
+ * 0-suffixed variants were added in Windows 11 / Server 2022. Matched
9
+ * case-insensitively against the basename (text before the first `.`).
10
+ */
11
+ const RESERVED_WIN_DEVICES = new Set([
12
+ 'CON',
13
+ 'PRN',
14
+ 'AUX',
15
+ 'NUL',
16
+ ...Array.from({ length: 10 }, (__v, i) => `COM${i}`),
17
+ ...Array.from({ length: 10 }, (__v, i) => `LPT${i}`)
18
+ ]);
19
+ const PORTABLE_FILENAME_RE = /^[A-Za-z0-9._-]+$/;
20
+ /**
21
+ * Validates a single filename stem against the POSIX portable filename set
22
+ * (`[A-Za-z0-9._-]`), rejecting a leading or trailing `.` and reserved Windows
23
+ * device names. This is the cross-platform filename-stem contract for the
24
+ * package: {@link MemoryId} values, the concrete {@link IIdentityCodec}
25
+ * implementations, and the store's `verifyFilenameId` all gate on it.
26
+ *
27
+ * @remarks
28
+ * A trailing `.` is rejected because Windows silently strips trailing dots from
29
+ * filenames, so such a stem would not round-trip verbatim through the file
30
+ * layer even though it is otherwise portable-set-valid.
31
+ * @public
32
+ */
33
+ export function assertPortableFilenameStem(stem) {
34
+ if (stem.length === 0) {
35
+ return fail('idStem: must be a non-empty string');
36
+ }
37
+ if (stem.startsWith('.')) {
38
+ return fail(`idStem '${stem}': may not begin with '.'`);
39
+ }
40
+ if (stem.endsWith('.')) {
41
+ return fail(`idStem '${stem}': may not end with '.' (Windows strips trailing dots)`);
42
+ }
43
+ if (!PORTABLE_FILENAME_RE.test(stem)) {
44
+ return fail(`idStem '${stem}': contains characters outside the POSIX portable filename set ([A-Za-z0-9._-])`);
45
+ }
46
+ const basename = stem.split('.')[0];
47
+ if (RESERVED_WIN_DEVICES.has(basename.toUpperCase())) {
48
+ return fail(`idStem '${stem}': basename '${basename}' matches a reserved Windows device name`);
49
+ }
50
+ return succeed(stem);
51
+ }
52
+ //# sourceMappingURL=filenameSafety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filenameSafety.js","sourceRoot":"","sources":["../../../src/packlets/types/filenameSafety.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;GAIG;AACH,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAS;IAChE,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;IACpD,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;CACrD,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAW,mBAAmB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,WAAW,IAAI,2BAA2B,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,WAAW,IAAI,wDAAwD,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CACT,WAAW,IAAI,iFAAiF,CACjG,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAW,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC,WAAW,IAAI,gBAAgB,QAAQ,0CAA0C,CAAC,CAAC;IACjG,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\n\n/**\n * Reserved Windows device basenames. Includes `COM0..9` and `LPT0..9` — the\n * 0-suffixed variants were added in Windows 11 / Server 2022. Matched\n * case-insensitively against the basename (text before the first `.`).\n */\nconst RESERVED_WIN_DEVICES: ReadonlySet<string> = new Set<string>([\n 'CON',\n 'PRN',\n 'AUX',\n 'NUL',\n ...Array.from({ length: 10 }, (__v, i) => `COM${i}`),\n ...Array.from({ length: 10 }, (__v, i) => `LPT${i}`)\n]);\n\nconst PORTABLE_FILENAME_RE: RegExp = /^[A-Za-z0-9._-]+$/;\n\n/**\n * Validates a single filename stem against the POSIX portable filename set\n * (`[A-Za-z0-9._-]`), rejecting a leading or trailing `.` and reserved Windows\n * device names. This is the cross-platform filename-stem contract for the\n * package: {@link MemoryId} values, the concrete {@link IIdentityCodec}\n * implementations, and the store's `verifyFilenameId` all gate on it.\n *\n * @remarks\n * A trailing `.` is rejected because Windows silently strips trailing dots from\n * filenames, so such a stem would not round-trip verbatim through the file\n * layer even though it is otherwise portable-set-valid.\n * @public\n */\nexport function assertPortableFilenameStem(stem: string): Result<string> {\n if (stem.length === 0) {\n return fail('idStem: must be a non-empty string');\n }\n if (stem.startsWith('.')) {\n return fail(`idStem '${stem}': may not begin with '.'`);\n }\n if (stem.endsWith('.')) {\n return fail(`idStem '${stem}': may not end with '.' (Windows strips trailing dots)`);\n }\n if (!PORTABLE_FILENAME_RE.test(stem)) {\n return fail(\n `idStem '${stem}': contains characters outside the POSIX portable filename set ([A-Za-z0-9._-])`\n );\n }\n const basename: string = stem.split('.')[0];\n if (RESERVED_WIN_DEVICES.has(basename.toUpperCase())) {\n return fail(`idStem '${stem}': basename '${basename}' matches a reserved Windows device name`);\n }\n return succeed(stem);\n}\n"]}
@@ -0,0 +1,184 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import { fail, succeed } from '@fgv/ts-utils';
6
+ import { Convert } from './ids';
7
+ import { assertPortableFilenameStem } from './filenameSafety';
8
+ /**
9
+ /**
10
+ * Identity codec for the knowledge kind family. A knowledge entity is keyed
11
+ * by its consumer-supplied `docId`, which is used verbatim as the filename
12
+ * stem under the flat `knowledge` scope.
13
+ *
14
+ * @remarks
15
+ * - `encode`: scope = `knowledge`, idStem = `docId`, `isVersioned = false`.
16
+ * - `decode`: brands the stem back to an {@link EntityId}.
17
+ * - Escaping: the `docId` must match the POSIX portable filename set.
18
+ * - Layout: `vault/knowledge/<docId>.md`.
19
+ * @public
20
+ */
21
+ export class KnowledgeIdentityCodec {
22
+ /** {@inheritDoc IIdentityCodec.encode} */
23
+ encode(entityId) {
24
+ return assertPortableFilenameStem(entityId).onSuccess((idStem) => succeed({ scope: KnowledgeIdentityCodec.scope, idStem, isVersioned: false }));
25
+ }
26
+ /** {@inheritDoc IIdentityCodec.decode} */
27
+ decode(scope, encodedStem) {
28
+ if (scope !== KnowledgeIdentityCodec.scope) {
29
+ return fail(`knowledge codec: scope '${scope}' does not match expected scope '${KnowledgeIdentityCodec.scope}'`);
30
+ }
31
+ return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));
32
+ }
33
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
34
+ verifyRoundTrip(scope, stem) {
35
+ return this.decode(scope, stem)
36
+ .onSuccess((entityId) => this.encode(entityId))
37
+ .onSuccess((encoded) => {
38
+ /* c8 ignore start -- defensive: for the identity (knowledge) codec, encode(decode(stem)).idStem always equals stem when both succeed; the guard exists for the non-identity codecs (LTM/MTM, Phase C) that reuse this contract */
39
+ if (encoded.idStem !== stem) {
40
+ return fail(`knowledge codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`);
41
+ }
42
+ /* c8 ignore stop */
43
+ return succeed(true);
44
+ });
45
+ }
46
+ }
47
+ /** The fixed scope for every knowledge entity. */
48
+ KnowledgeIdentityCodec.scope = 'knowledge';
49
+ /**
50
+ * Identity codec for the long-term-memory (LTM) kind family. An LTM entity is
51
+ * keyed by its `conversationId`, used verbatim as the filename stem under the
52
+ * flat `conversations` scope.
53
+ *
54
+ * @remarks
55
+ * - `encode`: scope = `conversations`, idStem = `conversationId`, `isVersioned = false`.
56
+ * - `decode`: brands the stem back to an {@link EntityId}.
57
+ * - Escaping: the `conversationId` must match the POSIX portable filename set.
58
+ * - Layout: `vault/conversations/<conversationId>.md`.
59
+ *
60
+ * An LTM file (`conversations/<id>.md`) and the MTM subtree
61
+ * (`conversations/<id>/turn-N.md`) coexist — a file and a same-named directory
62
+ * are independent on every supported FileTree backend.
63
+ * @public
64
+ */
65
+ export class LtmIdentityCodec {
66
+ /** {@inheritDoc IIdentityCodec.encode} */
67
+ encode(entityId) {
68
+ return assertPortableFilenameStem(entityId).onSuccess((idStem) => succeed({ scope: LtmIdentityCodec.scope, idStem, isVersioned: false }));
69
+ }
70
+ /** {@inheritDoc IIdentityCodec.decode} */
71
+ decode(scope, encodedStem) {
72
+ if (scope !== LtmIdentityCodec.scope) {
73
+ return fail(`LTM codec: scope '${scope}' does not match expected scope '${LtmIdentityCodec.scope}'`);
74
+ }
75
+ return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));
76
+ }
77
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
78
+ verifyRoundTrip(scope, stem) {
79
+ return this.decode(scope, stem)
80
+ .onSuccess((entityId) => this.encode(entityId))
81
+ .onSuccess((encoded) => {
82
+ /* c8 ignore start -- defensive: LTM encode(decode(stem)).idStem always equals stem when both succeed (identity mapping); guard preserves the contract for direct callers */
83
+ if (encoded.idStem !== stem) {
84
+ return fail(`LTM codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`);
85
+ }
86
+ /* c8 ignore stop */
87
+ return succeed(true);
88
+ });
89
+ }
90
+ }
91
+ /** The fixed scope for every LTM entity. */
92
+ LtmIdentityCodec.scope = 'conversations';
93
+ /**
94
+ * Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is
95
+ * keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a
96
+ * per-conversation subtree.
97
+ *
98
+ * @remarks
99
+ * - `encode`: splits the entity id on `:`; scope =
100
+ * `conversations/<conversationId>` (multi-segment), idStem = `turn-<turnIndex>`,
101
+ * `isVersioned = false`.
102
+ * - `decode`: reverses scope `conversations/<id>` + stem `turn-<N>` to the
103
+ * composite `<id>:<N>`.
104
+ * - Escaping: `conversationId` must match the POSIX portable filename set (so it
105
+ * contains no `/` or `:`); `turnIndex` must be a non-negative integer string,
106
+ * preserved verbatim so the round-trip is exact.
107
+ * - Layout: `vault/conversations/<conversationId>/turn-<N>.md`. The `/` in the
108
+ * scope is handled by the store's multi-segment scope resolver.
109
+ *
110
+ * **Verbatim turn index (caller-canonicalization note).** The turn index is
111
+ * preserved exactly — `conv-1:7` and `conv-1:007` are DISTINCT entities mapping
112
+ * to distinct files (`turn-7.md` / `turn-007.md`). Verbatim preservation is what
113
+ * makes the round-trip exact, but it means a caller that formats turn indices
114
+ * inconsistently (some zero-padded, some not) will silently mint separate
115
+ * entities. Callers should canonicalize to one form (e.g. no leading zeros).
116
+ * @public
117
+ */
118
+ export class MtmIdentityCodec {
119
+ /** {@inheritDoc IIdentityCodec.encode} */
120
+ encode(entityId) {
121
+ const parts = entityId.split(':');
122
+ if (parts.length !== 2) {
123
+ return fail(`MTM codec: entity id '${entityId}' must be a '<conversationId>:<turnIndex>' composite`);
124
+ }
125
+ const [conversationId, turnIndex] = parts;
126
+ return assertPortableFilenameStem(conversationId)
127
+ .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
128
+ .onSuccess(() => MtmIdentityCodec._assertTurnIndex(turnIndex))
129
+ .onSuccess(() => succeed({
130
+ scope: `${MtmIdentityCodec.rootScopeSegment}/${conversationId}`,
131
+ idStem: `${MtmIdentityCodec.turnStemPrefix}${turnIndex}`,
132
+ isVersioned: false
133
+ }));
134
+ }
135
+ /** {@inheritDoc IIdentityCodec.decode} */
136
+ decode(scope, encodedStem) {
137
+ return MtmIdentityCodec._conversationIdFromScope(scope).onSuccess((conversationId) => MtmIdentityCodec._turnIndexFromStem(encodedStem).onSuccess((turnIndex) => Convert.entityId.convert(`${conversationId}:${turnIndex}`)));
138
+ }
139
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
140
+ verifyRoundTrip(scope, stem) {
141
+ return this.decode(scope, stem)
142
+ .onSuccess((entityId) => this.encode(entityId))
143
+ .onSuccess((encoded) => {
144
+ /* c8 ignore start -- defensive: MTM encode(decode(scope, stem)) reproduces the same scope+stem whenever both succeed (no normalization); guard preserves the contract for direct callers */
145
+ if (encoded.idStem !== stem || encoded.scope !== scope) {
146
+ return fail(`MTM codec: round-trip mismatch for scope '${scope}' stem '${stem}' (re-encoded to scope '${encoded.scope}' stem '${encoded.idStem}')`);
147
+ }
148
+ /* c8 ignore stop */
149
+ return succeed(true);
150
+ });
151
+ }
152
+ /** Validate and extract the `conversationId` from a `conversations/<id>` scope. */
153
+ static _conversationIdFromScope(scope) {
154
+ const segments = scope.split('/');
155
+ if (segments.length !== 2 || segments[0] !== MtmIdentityCodec.rootScopeSegment) {
156
+ return fail(`MTM codec: scope '${scope}' must be '${MtmIdentityCodec.rootScopeSegment}/<conversationId>'`);
157
+ }
158
+ const conversationId = segments[1];
159
+ return assertPortableFilenameStem(conversationId)
160
+ .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
161
+ .onSuccess(() => succeed(conversationId));
162
+ }
163
+ /** Validate and extract the turn-index digits from a `turn-<N>` stem. */
164
+ static _turnIndexFromStem(stem) {
165
+ if (!stem.startsWith(MtmIdentityCodec.turnStemPrefix)) {
166
+ return fail(`MTM codec: stem '${stem}' must begin with '${MtmIdentityCodec.turnStemPrefix}'`);
167
+ }
168
+ return MtmIdentityCodec._assertTurnIndex(stem.slice(MtmIdentityCodec.turnStemPrefix.length));
169
+ }
170
+ /** Assert a string is a non-negative integer (the turn index). */
171
+ static _assertTurnIndex(turnIndex) {
172
+ if (!MtmIdentityCodec._turnIndexRe.test(turnIndex)) {
173
+ return fail(`MTM codec: turnIndex '${turnIndex}' must be a non-negative integer`);
174
+ }
175
+ return succeed(turnIndex);
176
+ }
177
+ }
178
+ /** The top-level scope segment under which every MTM subtree lives. */
179
+ MtmIdentityCodec.rootScopeSegment = 'conversations';
180
+ /** The fixed filename-stem prefix for a turn record. */
181
+ MtmIdentityCodec.turnStemPrefix = 'turn-';
182
+ /** A non-negative integer string (the turn index), preserved verbatim. */
183
+ MtmIdentityCodec._turnIndexRe = /^\d+$/;
184
+ //# sourceMappingURL=identityCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identityCodec.js","sourceRoot":"","sources":["../../../src/packlets/types/identityCodec.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 { Convert, EntityId, MemoryScopeKey } from './ids';\nimport { assertPortableFilenameStem } from './filenameSafety';\n\n/**\n * The FileTree storage address an {@link IIdentityCodec} maps a domain key to.\n * @public\n */\nexport interface IIdentityCodecResult {\n /** Scope path segment (may be multi-level, e.g. `conversations/<id>`). */\n readonly scope: MemoryScopeKey;\n /** Filename stem (the part before `.md`). Filename-safe after encoding. */\n readonly idStem: string;\n /**\n * Whether this kind uses a versioned layout (temporal: multiple files per\n * entity) vs. a flat layout (one file per entity). Non-temporal = always\n * `false`.\n */\n readonly isVersioned: boolean;\n}\n\n/**\n * Maps a consumer-supplied domain key ⇄ a FileTree storage address. Injected\n * per kind so the store never touches raw domain keys: the codec owns all\n * filename escaping and the flat-vs-versioned layout dispatch.\n * @public\n */\nexport interface IIdentityCodec {\n /**\n * Encode a consumer-supplied entity id to a FileTree address. Deterministic\n * and pure — no I/O.\n */\n encode(entityId: EntityId): Result<IIdentityCodecResult>;\n\n /**\n * Decode a FileTree address back to the original {@link EntityId}. The exact\n * inverse of {@link IIdentityCodec.encode | encode} for non-versioned kinds.\n */\n decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;\n\n /**\n * Assert that `encode(decode(scope, stem)).idStem === stem`. Used by the\n * store's `verifyFilenameId` check on load.\n */\n verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;\n}\n\n/**\n/**\n * Identity codec for the knowledge kind family. A knowledge entity is keyed\n * by its consumer-supplied `docId`, which is used verbatim as the filename\n * stem under the flat `knowledge` scope.\n *\n * @remarks\n * - `encode`: scope = `knowledge`, idStem = `docId`, `isVersioned = false`.\n * - `decode`: brands the stem back to an {@link EntityId}.\n * - Escaping: the `docId` must match the POSIX portable filename set.\n * - Layout: `vault/knowledge/<docId>.md`.\n * @public\n */\nexport class KnowledgeIdentityCodec implements IIdentityCodec {\n /** The fixed scope for every knowledge entity. */\n public static readonly scope: MemoryScopeKey = 'knowledge' as MemoryScopeKey;\n\n /** {@inheritDoc IIdentityCodec.encode} */\n public encode(entityId: EntityId): Result<IIdentityCodecResult> {\n return assertPortableFilenameStem(entityId).onSuccess((idStem) =>\n succeed({ scope: KnowledgeIdentityCodec.scope, idStem, isVersioned: false })\n );\n }\n\n /** {@inheritDoc IIdentityCodec.decode} */\n public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {\n if (scope !== KnowledgeIdentityCodec.scope) {\n return fail(\n `knowledge codec: scope '${scope}' does not match expected scope '${KnowledgeIdentityCodec.scope}'`\n );\n }\n return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));\n }\n\n /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */\n public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {\n return this.decode(scope, stem)\n .onSuccess((entityId) => this.encode(entityId))\n .onSuccess((encoded) => {\n /* c8 ignore start -- defensive: for the identity (knowledge) codec, encode(decode(stem)).idStem always equals stem when both succeed; the guard exists for the non-identity codecs (LTM/MTM, Phase C) that reuse this contract */\n if (encoded.idStem !== stem) {\n return fail(\n `knowledge codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`\n );\n }\n /* c8 ignore stop */\n return succeed(true);\n });\n }\n}\n\n/**\n * Identity codec for the long-term-memory (LTM) kind family. An LTM entity is\n * keyed by its `conversationId`, used verbatim as the filename stem under the\n * flat `conversations` scope.\n *\n * @remarks\n * - `encode`: scope = `conversations`, idStem = `conversationId`, `isVersioned = false`.\n * - `decode`: brands the stem back to an {@link EntityId}.\n * - Escaping: the `conversationId` must match the POSIX portable filename set.\n * - Layout: `vault/conversations/<conversationId>.md`.\n *\n * An LTM file (`conversations/<id>.md`) and the MTM subtree\n * (`conversations/<id>/turn-N.md`) coexist — a file and a same-named directory\n * are independent on every supported FileTree backend.\n * @public\n */\nexport class LtmIdentityCodec implements IIdentityCodec {\n /** The fixed scope for every LTM entity. */\n public static readonly scope: MemoryScopeKey = 'conversations' as MemoryScopeKey;\n\n /** {@inheritDoc IIdentityCodec.encode} */\n public encode(entityId: EntityId): Result<IIdentityCodecResult> {\n return assertPortableFilenameStem(entityId).onSuccess((idStem) =>\n succeed({ scope: LtmIdentityCodec.scope, idStem, isVersioned: false })\n );\n }\n\n /** {@inheritDoc IIdentityCodec.decode} */\n public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {\n if (scope !== LtmIdentityCodec.scope) {\n return fail(`LTM codec: scope '${scope}' does not match expected scope '${LtmIdentityCodec.scope}'`);\n }\n return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));\n }\n\n /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */\n public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {\n return this.decode(scope, stem)\n .onSuccess((entityId) => this.encode(entityId))\n .onSuccess((encoded) => {\n /* c8 ignore start -- defensive: LTM encode(decode(stem)).idStem always equals stem when both succeed (identity mapping); guard preserves the contract for direct callers */\n if (encoded.idStem !== stem) {\n return fail(\n `LTM codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`\n );\n }\n /* c8 ignore stop */\n return succeed(true);\n });\n }\n}\n\n/**\n * Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is\n * keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a\n * per-conversation subtree.\n *\n * @remarks\n * - `encode`: splits the entity id on `:`; scope =\n * `conversations/<conversationId>` (multi-segment), idStem = `turn-<turnIndex>`,\n * `isVersioned = false`.\n * - `decode`: reverses scope `conversations/<id>` + stem `turn-<N>` to the\n * composite `<id>:<N>`.\n * - Escaping: `conversationId` must match the POSIX portable filename set (so it\n * contains no `/` or `:`); `turnIndex` must be a non-negative integer string,\n * preserved verbatim so the round-trip is exact.\n * - Layout: `vault/conversations/<conversationId>/turn-<N>.md`. The `/` in the\n * scope is handled by the store's multi-segment scope resolver.\n *\n * **Verbatim turn index (caller-canonicalization note).** The turn index is\n * preserved exactly — `conv-1:7` and `conv-1:007` are DISTINCT entities mapping\n * to distinct files (`turn-7.md` / `turn-007.md`). Verbatim preservation is what\n * makes the round-trip exact, but it means a caller that formats turn indices\n * inconsistently (some zero-padded, some not) will silently mint separate\n * entities. Callers should canonicalize to one form (e.g. no leading zeros).\n * @public\n */\nexport class MtmIdentityCodec implements IIdentityCodec {\n /** The top-level scope segment under which every MTM subtree lives. */\n public static readonly rootScopeSegment: string = 'conversations';\n /** The fixed filename-stem prefix for a turn record. */\n public static readonly turnStemPrefix: string = 'turn-';\n\n /** A non-negative integer string (the turn index), preserved verbatim. */\n private static readonly _turnIndexRe: RegExp = /^\\d+$/;\n\n /** {@inheritDoc IIdentityCodec.encode} */\n public encode(entityId: EntityId): Result<IIdentityCodecResult> {\n const parts: string[] = entityId.split(':');\n if (parts.length !== 2) {\n return fail(`MTM codec: entity id '${entityId}' must be a '<conversationId>:<turnIndex>' composite`);\n }\n const [conversationId, turnIndex] = parts;\n return assertPortableFilenameStem(conversationId)\n .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)\n .onSuccess(() => MtmIdentityCodec._assertTurnIndex(turnIndex))\n .onSuccess(() =>\n succeed({\n scope: `${MtmIdentityCodec.rootScopeSegment}/${conversationId}` as MemoryScopeKey,\n idStem: `${MtmIdentityCodec.turnStemPrefix}${turnIndex}`,\n isVersioned: false\n })\n );\n }\n\n /** {@inheritDoc IIdentityCodec.decode} */\n public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {\n return MtmIdentityCodec._conversationIdFromScope(scope).onSuccess((conversationId) =>\n MtmIdentityCodec._turnIndexFromStem(encodedStem).onSuccess((turnIndex) =>\n Convert.entityId.convert(`${conversationId}:${turnIndex}`)\n )\n );\n }\n\n /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */\n public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {\n return this.decode(scope, stem)\n .onSuccess((entityId) => this.encode(entityId))\n .onSuccess((encoded) => {\n /* c8 ignore start -- defensive: MTM encode(decode(scope, stem)) reproduces the same scope+stem whenever both succeed (no normalization); guard preserves the contract for direct callers */\n if (encoded.idStem !== stem || encoded.scope !== scope) {\n return fail(\n `MTM codec: round-trip mismatch for scope '${scope}' stem '${stem}' (re-encoded to scope '${encoded.scope}' stem '${encoded.idStem}')`\n );\n }\n /* c8 ignore stop */\n return succeed(true);\n });\n }\n\n /** Validate and extract the `conversationId` from a `conversations/<id>` scope. */\n private static _conversationIdFromScope(scope: MemoryScopeKey): Result<string> {\n const segments: string[] = scope.split('/');\n if (segments.length !== 2 || segments[0] !== MtmIdentityCodec.rootScopeSegment) {\n return fail(\n `MTM codec: scope '${scope}' must be '${MtmIdentityCodec.rootScopeSegment}/<conversationId>'`\n );\n }\n const conversationId: string = segments[1];\n return assertPortableFilenameStem(conversationId)\n .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)\n .onSuccess(() => succeed(conversationId));\n }\n\n /** Validate and extract the turn-index digits from a `turn-<N>` stem. */\n private static _turnIndexFromStem(stem: string): Result<string> {\n if (!stem.startsWith(MtmIdentityCodec.turnStemPrefix)) {\n return fail(`MTM codec: stem '${stem}' must begin with '${MtmIdentityCodec.turnStemPrefix}'`);\n }\n return MtmIdentityCodec._assertTurnIndex(stem.slice(MtmIdentityCodec.turnStemPrefix.length));\n }\n\n /** Assert a string is a non-negative integer (the turn index). */\n private static _assertTurnIndex(turnIndex: string): Result<string> {\n if (!MtmIdentityCodec._turnIndexRe.test(turnIndex)) {\n return fail(`MTM codec: turnIndex '${turnIndex}' must be a non-negative integer`);\n }\n return succeed(turnIndex);\n }\n}\n"]}
@@ -0,0 +1,67 @@
1
+ /*
2
+ * Copyright (c) 2026 Erik Fortune
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import { Converters, fail, succeed } from '@fgv/ts-utils';
6
+ import { assertPortableFilenameStem } from './filenameSafety';
7
+ /**
8
+ * Maximum length of any branded identifier in the library. Picked to be
9
+ * larger than any reasonable id a consumer would supply while still bounded
10
+ * to defuse adversarial inputs (e.g. multi-megabyte ids used as map keys).
11
+ */
12
+ const MAX_BRAND_LENGTH = 256;
13
+ /**
14
+ * Builds a `Converter` for one of the branded id scalars in this library.
15
+ * All brands share the same hygiene: non-empty, length-capped, and free of
16
+ * leading/trailing whitespace. Filename-safety and single-segment
17
+ * constraints are intentionally NOT enforced here — the per-kind
18
+ * {@link IIdentityCodec} owns escaping so that multi-segment scope keys
19
+ * (`conversations/<id>`) and composite entity ids (`<id>:<turn>`) validate
20
+ * cleanly.
21
+ *
22
+ * Not exported — the per-brand `Convert.<brand>` constants are the public
23
+ * surface.
24
+ */
25
+ function brandedIdConverter(brand) {
26
+ return Converters.string.map((from) => {
27
+ if (from.length === 0) {
28
+ return fail(`${brand}: must be a non-empty string`);
29
+ }
30
+ if (from.length > MAX_BRAND_LENGTH) {
31
+ return fail(`${brand}: exceeds maximum length ${MAX_BRAND_LENGTH} (got ${from.length})`);
32
+ }
33
+ if (from !== from.trim()) {
34
+ return fail(`${brand}: must not have leading or trailing whitespace`);
35
+ }
36
+ return succeed(from);
37
+ });
38
+ }
39
+ /**
40
+ * Converters for the branded identifier scalars. Each validates an `unknown`
41
+ * value into the corresponding brand, enforcing the shared hygiene
42
+ * (non-empty, length-capped, trimmed).
43
+ * @public
44
+ */
45
+ export const Convert = {
46
+ /**
47
+ * Validates an `unknown` value as a {@link MemoryId}. Unlike the other
48
+ * brands, `MemoryId` IS the on-disk filename stem (`id === idStem`, enforced
49
+ * by the store's `verifyFilenameId`), so it additionally enforces the
50
+ * portable-filename-stem contract — rejecting path-unsafe ids (`a/b`,
51
+ * `conv-1:7`) at convert time rather than letting them surface as a file-path
52
+ * failure later. (`EntityId` stays relaxed: a domain key may legitimately be
53
+ * a composite like `conv-1:7`; the codec maps it to a safe stem.)
54
+ */
55
+ memoryId: brandedIdConverter('MemoryId').map((id) => assertPortableFilenameStem(id).onSuccess(() => succeed(id))),
56
+ /** Validates an `unknown` value as an {@link EntityId}. */
57
+ entityId: brandedIdConverter('EntityId'),
58
+ /** Validates an `unknown` value as a {@link Kind}. */
59
+ kind: brandedIdConverter('Kind'),
60
+ /** Validates an `unknown` value as a {@link Tag}. */
61
+ tag: brandedIdConverter('Tag'),
62
+ /** Validates an `unknown` value as a {@link MemoryScopeKey}. */
63
+ scopeKey: brandedIdConverter('MemoryScopeKey'),
64
+ /** Validates an `unknown` value as a {@link LinkType}. */
65
+ linkType: brandedIdConverter('LinkType')
66
+ };
67
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../../src/packlets/types/ids.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoB,UAAU,EAAU,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AA+C9D;;;;GAIG;AACH,MAAM,gBAAgB,GAAW,GAAG,CAAC;AAErC;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAmB,KAAa;IACzD,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAY,EAAa,EAAE;QACvD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,GAAG,KAAK,4BAA4B,gBAAgB,SAAS,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,GAAG,KAAK,gDAAgD,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,OAAO,CAAC,IAAoB,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAOhB;IACF;;;;;;;;OAQG;IACH,QAAQ,EAAE,kBAAkB,CAAW,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC5D,0BAA0B,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAC5D;IACD,2DAA2D;IAC3D,QAAQ,EAAE,kBAAkB,CAAW,UAAU,CAAC;IAClD,sDAAsD;IACtD,IAAI,EAAE,kBAAkB,CAAO,MAAM,CAAC;IACtC,qDAAqD;IACrD,GAAG,EAAE,kBAAkB,CAAM,KAAK,CAAC;IACnC,gEAAgE;IAChE,QAAQ,EAAE,kBAAkB,CAAiB,gBAAgB,CAAC;IAC9D,0DAA0D;IAC1D,QAAQ,EAAE,kBAAkB,CAAW,UAAU,CAAC;CAC1C,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Brand, Converter, Converters, Result, fail, succeed } from '@fgv/ts-utils';\nimport { assertPortableFilenameStem } from './filenameSafety';\n\n/**\n * Stable file-stem identifier for a memory record. Equals the codec-produced\n * `idStem` and the on-disk filename stem (`verifyFilenameId` enforces the\n * round-trip).\n * @public\n */\nexport type MemoryId = Brand<string, 'MemoryId'>;\n\n/**\n * Consumer-supplied domain key. The stable entity identity across versions;\n * the package never mints identity. Equals {@link MemoryId} for non-temporal\n * kinds.\n * @public\n */\nexport type EntityId = Brand<string, 'EntityId'>;\n\n/**\n * Open-vocabulary record classifier. Consumers register one body\n * {@link https://www.npmjs.com/package/@fgv/ts-utils | Converter} per kind.\n * @public\n */\nexport type Kind = Brand<string, 'Kind'>;\n\n/**\n * Open-vocabulary tag label.\n * @public\n */\nexport type Tag = Brand<string, 'Tag'>;\n\n/**\n * Scope path segment. May be multi-segment (`/`-separated) for kinds whose\n * codec maps an entity into a sub-tree (e.g. MTM: `conversations/<id>`). The\n * codec — not this brand — owns filename-safe escaping, so the converter\n * validates only the non-empty/length/whitespace hygiene shared by every\n * brand.\n * @public\n */\nexport type MemoryScopeKey = Brand<string, 'MemoryScopeKey'>;\n\n/**\n * Open-vocabulary link-relation type for an attributed {@link IEdge}.\n * @public\n */\nexport type LinkType = Brand<string, 'LinkType'>;\n\n/**\n * Maximum length of any branded identifier in the library. Picked to be\n * larger than any reasonable id a consumer would supply while still bounded\n * to defuse adversarial inputs (e.g. multi-megabyte ids used as map keys).\n */\nconst MAX_BRAND_LENGTH: number = 256;\n\n/**\n * Builds a `Converter` for one of the branded id scalars in this library.\n * All brands share the same hygiene: non-empty, length-capped, and free of\n * leading/trailing whitespace. Filename-safety and single-segment\n * constraints are intentionally NOT enforced here — the per-kind\n * {@link IIdentityCodec} owns escaping so that multi-segment scope keys\n * (`conversations/<id>`) and composite entity ids (`<id>:<turn>`) validate\n * cleanly.\n *\n * Not exported — the per-brand `Convert.<brand>` constants are the public\n * surface.\n */\nfunction brandedIdConverter<T extends string>(brand: string): Converter<T> {\n return Converters.string.map((from: string): Result<T> => {\n if (from.length === 0) {\n return fail(`${brand}: must be a non-empty string`);\n }\n if (from.length > MAX_BRAND_LENGTH) {\n return fail(`${brand}: exceeds maximum length ${MAX_BRAND_LENGTH} (got ${from.length})`);\n }\n if (from !== from.trim()) {\n return fail(`${brand}: must not have leading or trailing whitespace`);\n }\n return succeed(from as unknown as T);\n });\n}\n\n/**\n * Converters for the branded identifier scalars. Each validates an `unknown`\n * value into the corresponding brand, enforcing the shared hygiene\n * (non-empty, length-capped, trimmed).\n * @public\n */\nexport const Convert: {\n readonly memoryId: Converter<MemoryId>;\n readonly entityId: Converter<EntityId>;\n readonly kind: Converter<Kind>;\n readonly tag: Converter<Tag>;\n readonly scopeKey: Converter<MemoryScopeKey>;\n readonly linkType: Converter<LinkType>;\n} = {\n /**\n * Validates an `unknown` value as a {@link MemoryId}. Unlike the other\n * brands, `MemoryId` IS the on-disk filename stem (`id === idStem`, enforced\n * by the store's `verifyFilenameId`), so it additionally enforces the\n * portable-filename-stem contract — rejecting path-unsafe ids (`a/b`,\n * `conv-1:7`) at convert time rather than letting them surface as a file-path\n * failure later. (`EntityId` stays relaxed: a domain key may legitimately be\n * a composite like `conv-1:7`; the codec maps it to a safe stem.)\n */\n memoryId: brandedIdConverter<MemoryId>('MemoryId').map((id) =>\n assertPortableFilenameStem(id).onSuccess(() => succeed(id))\n ),\n /** Validates an `unknown` value as an {@link EntityId}. */\n entityId: brandedIdConverter<EntityId>('EntityId'),\n /** Validates an `unknown` value as a {@link Kind}. */\n kind: brandedIdConverter<Kind>('Kind'),\n /** Validates an `unknown` value as a {@link Tag}. */\n tag: brandedIdConverter<Tag>('Tag'),\n /** Validates an `unknown` value as a {@link MemoryScopeKey}. */\n scopeKey: brandedIdConverter<MemoryScopeKey>('MemoryScopeKey'),\n /** Validates an `unknown` value as a {@link LinkType}. */\n linkType: brandedIdConverter<LinkType>('LinkType')\n} as const;\n"]}