@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,136 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { EntityId, MemoryScopeKey } from './ids';
3
+ /**
4
+ * The FileTree storage address an {@link IIdentityCodec} maps a domain key to.
5
+ * @public
6
+ */
7
+ export interface IIdentityCodecResult {
8
+ /** Scope path segment (may be multi-level, e.g. `conversations/<id>`). */
9
+ readonly scope: MemoryScopeKey;
10
+ /** Filename stem (the part before `.md`). Filename-safe after encoding. */
11
+ readonly idStem: string;
12
+ /**
13
+ * Whether this kind uses a versioned layout (temporal: multiple files per
14
+ * entity) vs. a flat layout (one file per entity). Non-temporal = always
15
+ * `false`.
16
+ */
17
+ readonly isVersioned: boolean;
18
+ }
19
+ /**
20
+ * Maps a consumer-supplied domain key ⇄ a FileTree storage address. Injected
21
+ * per kind so the store never touches raw domain keys: the codec owns all
22
+ * filename escaping and the flat-vs-versioned layout dispatch.
23
+ * @public
24
+ */
25
+ export interface IIdentityCodec {
26
+ /**
27
+ * Encode a consumer-supplied entity id to a FileTree address. Deterministic
28
+ * and pure — no I/O.
29
+ */
30
+ encode(entityId: EntityId): Result<IIdentityCodecResult>;
31
+ /**
32
+ * Decode a FileTree address back to the original {@link EntityId}. The exact
33
+ * inverse of {@link IIdentityCodec.encode | encode} for non-versioned kinds.
34
+ */
35
+ decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
36
+ /**
37
+ * Assert that `encode(decode(scope, stem)).idStem === stem`. Used by the
38
+ * store's `verifyFilenameId` check on load.
39
+ */
40
+ verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
41
+ }
42
+ /**
43
+ /**
44
+ * Identity codec for the knowledge kind family. A knowledge entity is keyed
45
+ * by its consumer-supplied `docId`, which is used verbatim as the filename
46
+ * stem under the flat `knowledge` scope.
47
+ *
48
+ * @remarks
49
+ * - `encode`: scope = `knowledge`, idStem = `docId`, `isVersioned = false`.
50
+ * - `decode`: brands the stem back to an {@link EntityId}.
51
+ * - Escaping: the `docId` must match the POSIX portable filename set.
52
+ * - Layout: `vault/knowledge/<docId>.md`.
53
+ * @public
54
+ */
55
+ export declare class KnowledgeIdentityCodec implements IIdentityCodec {
56
+ /** The fixed scope for every knowledge entity. */
57
+ static readonly scope: MemoryScopeKey;
58
+ /** {@inheritDoc IIdentityCodec.encode} */
59
+ encode(entityId: EntityId): Result<IIdentityCodecResult>;
60
+ /** {@inheritDoc IIdentityCodec.decode} */
61
+ decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
62
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
63
+ verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
64
+ }
65
+ /**
66
+ * Identity codec for the long-term-memory (LTM) kind family. An LTM entity is
67
+ * keyed by its `conversationId`, used verbatim as the filename stem under the
68
+ * flat `conversations` scope.
69
+ *
70
+ * @remarks
71
+ * - `encode`: scope = `conversations`, idStem = `conversationId`, `isVersioned = false`.
72
+ * - `decode`: brands the stem back to an {@link EntityId}.
73
+ * - Escaping: the `conversationId` must match the POSIX portable filename set.
74
+ * - Layout: `vault/conversations/<conversationId>.md`.
75
+ *
76
+ * An LTM file (`conversations/<id>.md`) and the MTM subtree
77
+ * (`conversations/<id>/turn-N.md`) coexist — a file and a same-named directory
78
+ * are independent on every supported FileTree backend.
79
+ * @public
80
+ */
81
+ export declare class LtmIdentityCodec implements IIdentityCodec {
82
+ /** The fixed scope for every LTM entity. */
83
+ static readonly scope: MemoryScopeKey;
84
+ /** {@inheritDoc IIdentityCodec.encode} */
85
+ encode(entityId: EntityId): Result<IIdentityCodecResult>;
86
+ /** {@inheritDoc IIdentityCodec.decode} */
87
+ decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
88
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
89
+ verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
90
+ }
91
+ /**
92
+ * Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is
93
+ * keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a
94
+ * per-conversation subtree.
95
+ *
96
+ * @remarks
97
+ * - `encode`: splits the entity id on `:`; scope =
98
+ * `conversations/<conversationId>` (multi-segment), idStem = `turn-<turnIndex>`,
99
+ * `isVersioned = false`.
100
+ * - `decode`: reverses scope `conversations/<id>` + stem `turn-<N>` to the
101
+ * composite `<id>:<N>`.
102
+ * - Escaping: `conversationId` must match the POSIX portable filename set (so it
103
+ * contains no `/` or `:`); `turnIndex` must be a non-negative integer string,
104
+ * preserved verbatim so the round-trip is exact.
105
+ * - Layout: `vault/conversations/<conversationId>/turn-<N>.md`. The `/` in the
106
+ * scope is handled by the store's multi-segment scope resolver.
107
+ *
108
+ * **Verbatim turn index (caller-canonicalization note).** The turn index is
109
+ * preserved exactly — `conv-1:7` and `conv-1:007` are DISTINCT entities mapping
110
+ * to distinct files (`turn-7.md` / `turn-007.md`). Verbatim preservation is what
111
+ * makes the round-trip exact, but it means a caller that formats turn indices
112
+ * inconsistently (some zero-padded, some not) will silently mint separate
113
+ * entities. Callers should canonicalize to one form (e.g. no leading zeros).
114
+ * @public
115
+ */
116
+ export declare class MtmIdentityCodec implements IIdentityCodec {
117
+ /** The top-level scope segment under which every MTM subtree lives. */
118
+ static readonly rootScopeSegment: string;
119
+ /** The fixed filename-stem prefix for a turn record. */
120
+ static readonly turnStemPrefix: string;
121
+ /** A non-negative integer string (the turn index), preserved verbatim. */
122
+ private static readonly _turnIndexRe;
123
+ /** {@inheritDoc IIdentityCodec.encode} */
124
+ encode(entityId: EntityId): Result<IIdentityCodecResult>;
125
+ /** {@inheritDoc IIdentityCodec.decode} */
126
+ decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
127
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
128
+ verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
129
+ /** Validate and extract the `conversationId` from a `conversations/<id>` scope. */
130
+ private static _conversationIdFromScope;
131
+ /** Validate and extract the turn-index digits from a `turn-<N>` stem. */
132
+ private static _turnIndexFromStem;
133
+ /** Assert a string is a non-negative integer (the turn index). */
134
+ private static _assertTurnIndex;
135
+ }
136
+ //# sourceMappingURL=identityCodec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identityCodec.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/identityCodec.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAW,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG1D;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAEzD;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErE;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;CACpE;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,sBAAuB,YAAW,cAAc;IAC3D,kDAAkD;IAClD,gBAAuB,KAAK,EAAE,cAAc,CAAiC;IAE7E,0CAA0C;IACnC,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAM/D,0CAA0C;IACnC,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;IAS3E,mDAAmD;IAC5C,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;CAc1E;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAiB,YAAW,cAAc;IACrD,4CAA4C;IAC5C,gBAAuB,KAAK,EAAE,cAAc,CAAqC;IAEjF,0CAA0C;IACnC,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAM/D,0CAA0C;IACnC,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;IAO3E,mDAAmD;IAC5C,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;CAc1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,gBAAiB,YAAW,cAAc;IACrD,uEAAuE;IACvE,gBAAuB,gBAAgB,EAAE,MAAM,CAAmB;IAClE,wDAAwD;IACxD,gBAAuB,cAAc,EAAE,MAAM,CAAW;IAExD,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAEvD,0CAA0C;IACnC,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAkB/D,0CAA0C;IACnC,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;IAQ3E,mDAAmD;IAC5C,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;IAezE,mFAAmF;IACnF,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAavC,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAOjC,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAMhC"}
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MtmIdentityCodec = exports.LtmIdentityCodec = exports.KnowledgeIdentityCodec = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ const ids_1 = require("./ids");
10
+ const filenameSafety_1 = require("./filenameSafety");
11
+ /**
12
+ /**
13
+ * Identity codec for the knowledge kind family. A knowledge entity is keyed
14
+ * by its consumer-supplied `docId`, which is used verbatim as the filename
15
+ * stem under the flat `knowledge` scope.
16
+ *
17
+ * @remarks
18
+ * - `encode`: scope = `knowledge`, idStem = `docId`, `isVersioned = false`.
19
+ * - `decode`: brands the stem back to an {@link EntityId}.
20
+ * - Escaping: the `docId` must match the POSIX portable filename set.
21
+ * - Layout: `vault/knowledge/<docId>.md`.
22
+ * @public
23
+ */
24
+ class KnowledgeIdentityCodec {
25
+ /** {@inheritDoc IIdentityCodec.encode} */
26
+ encode(entityId) {
27
+ return (0, filenameSafety_1.assertPortableFilenameStem)(entityId).onSuccess((idStem) => (0, ts_utils_1.succeed)({ scope: KnowledgeIdentityCodec.scope, idStem, isVersioned: false }));
28
+ }
29
+ /** {@inheritDoc IIdentityCodec.decode} */
30
+ decode(scope, encodedStem) {
31
+ if (scope !== KnowledgeIdentityCodec.scope) {
32
+ return (0, ts_utils_1.fail)(`knowledge codec: scope '${scope}' does not match expected scope '${KnowledgeIdentityCodec.scope}'`);
33
+ }
34
+ return (0, filenameSafety_1.assertPortableFilenameStem)(encodedStem).onSuccess((stem) => ids_1.Convert.entityId.convert(stem));
35
+ }
36
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
37
+ verifyRoundTrip(scope, stem) {
38
+ return this.decode(scope, stem)
39
+ .onSuccess((entityId) => this.encode(entityId))
40
+ .onSuccess((encoded) => {
41
+ /* 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 */
42
+ if (encoded.idStem !== stem) {
43
+ return (0, ts_utils_1.fail)(`knowledge codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`);
44
+ }
45
+ /* c8 ignore stop */
46
+ return (0, ts_utils_1.succeed)(true);
47
+ });
48
+ }
49
+ }
50
+ exports.KnowledgeIdentityCodec = KnowledgeIdentityCodec;
51
+ /** The fixed scope for every knowledge entity. */
52
+ KnowledgeIdentityCodec.scope = 'knowledge';
53
+ /**
54
+ * Identity codec for the long-term-memory (LTM) kind family. An LTM entity is
55
+ * keyed by its `conversationId`, used verbatim as the filename stem under the
56
+ * flat `conversations` scope.
57
+ *
58
+ * @remarks
59
+ * - `encode`: scope = `conversations`, idStem = `conversationId`, `isVersioned = false`.
60
+ * - `decode`: brands the stem back to an {@link EntityId}.
61
+ * - Escaping: the `conversationId` must match the POSIX portable filename set.
62
+ * - Layout: `vault/conversations/<conversationId>.md`.
63
+ *
64
+ * An LTM file (`conversations/<id>.md`) and the MTM subtree
65
+ * (`conversations/<id>/turn-N.md`) coexist — a file and a same-named directory
66
+ * are independent on every supported FileTree backend.
67
+ * @public
68
+ */
69
+ class LtmIdentityCodec {
70
+ /** {@inheritDoc IIdentityCodec.encode} */
71
+ encode(entityId) {
72
+ return (0, filenameSafety_1.assertPortableFilenameStem)(entityId).onSuccess((idStem) => (0, ts_utils_1.succeed)({ scope: LtmIdentityCodec.scope, idStem, isVersioned: false }));
73
+ }
74
+ /** {@inheritDoc IIdentityCodec.decode} */
75
+ decode(scope, encodedStem) {
76
+ if (scope !== LtmIdentityCodec.scope) {
77
+ return (0, ts_utils_1.fail)(`LTM codec: scope '${scope}' does not match expected scope '${LtmIdentityCodec.scope}'`);
78
+ }
79
+ return (0, filenameSafety_1.assertPortableFilenameStem)(encodedStem).onSuccess((stem) => ids_1.Convert.entityId.convert(stem));
80
+ }
81
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
82
+ verifyRoundTrip(scope, stem) {
83
+ return this.decode(scope, stem)
84
+ .onSuccess((entityId) => this.encode(entityId))
85
+ .onSuccess((encoded) => {
86
+ /* c8 ignore start -- defensive: LTM encode(decode(stem)).idStem always equals stem when both succeed (identity mapping); guard preserves the contract for direct callers */
87
+ if (encoded.idStem !== stem) {
88
+ return (0, ts_utils_1.fail)(`LTM codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`);
89
+ }
90
+ /* c8 ignore stop */
91
+ return (0, ts_utils_1.succeed)(true);
92
+ });
93
+ }
94
+ }
95
+ exports.LtmIdentityCodec = LtmIdentityCodec;
96
+ /** The fixed scope for every LTM entity. */
97
+ LtmIdentityCodec.scope = 'conversations';
98
+ /**
99
+ * Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is
100
+ * keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a
101
+ * per-conversation subtree.
102
+ *
103
+ * @remarks
104
+ * - `encode`: splits the entity id on `:`; scope =
105
+ * `conversations/<conversationId>` (multi-segment), idStem = `turn-<turnIndex>`,
106
+ * `isVersioned = false`.
107
+ * - `decode`: reverses scope `conversations/<id>` + stem `turn-<N>` to the
108
+ * composite `<id>:<N>`.
109
+ * - Escaping: `conversationId` must match the POSIX portable filename set (so it
110
+ * contains no `/` or `:`); `turnIndex` must be a non-negative integer string,
111
+ * preserved verbatim so the round-trip is exact.
112
+ * - Layout: `vault/conversations/<conversationId>/turn-<N>.md`. The `/` in the
113
+ * scope is handled by the store's multi-segment scope resolver.
114
+ *
115
+ * **Verbatim turn index (caller-canonicalization note).** The turn index is
116
+ * preserved exactly — `conv-1:7` and `conv-1:007` are DISTINCT entities mapping
117
+ * to distinct files (`turn-7.md` / `turn-007.md`). Verbatim preservation is what
118
+ * makes the round-trip exact, but it means a caller that formats turn indices
119
+ * inconsistently (some zero-padded, some not) will silently mint separate
120
+ * entities. Callers should canonicalize to one form (e.g. no leading zeros).
121
+ * @public
122
+ */
123
+ class MtmIdentityCodec {
124
+ /** {@inheritDoc IIdentityCodec.encode} */
125
+ encode(entityId) {
126
+ const parts = entityId.split(':');
127
+ if (parts.length !== 2) {
128
+ return (0, ts_utils_1.fail)(`MTM codec: entity id '${entityId}' must be a '<conversationId>:<turnIndex>' composite`);
129
+ }
130
+ const [conversationId, turnIndex] = parts;
131
+ return (0, filenameSafety_1.assertPortableFilenameStem)(conversationId)
132
+ .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
133
+ .onSuccess(() => MtmIdentityCodec._assertTurnIndex(turnIndex))
134
+ .onSuccess(() => (0, ts_utils_1.succeed)({
135
+ scope: `${MtmIdentityCodec.rootScopeSegment}/${conversationId}`,
136
+ idStem: `${MtmIdentityCodec.turnStemPrefix}${turnIndex}`,
137
+ isVersioned: false
138
+ }));
139
+ }
140
+ /** {@inheritDoc IIdentityCodec.decode} */
141
+ decode(scope, encodedStem) {
142
+ return MtmIdentityCodec._conversationIdFromScope(scope).onSuccess((conversationId) => MtmIdentityCodec._turnIndexFromStem(encodedStem).onSuccess((turnIndex) => ids_1.Convert.entityId.convert(`${conversationId}:${turnIndex}`)));
143
+ }
144
+ /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
145
+ verifyRoundTrip(scope, stem) {
146
+ return this.decode(scope, stem)
147
+ .onSuccess((entityId) => this.encode(entityId))
148
+ .onSuccess((encoded) => {
149
+ /* 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 */
150
+ if (encoded.idStem !== stem || encoded.scope !== scope) {
151
+ return (0, ts_utils_1.fail)(`MTM codec: round-trip mismatch for scope '${scope}' stem '${stem}' (re-encoded to scope '${encoded.scope}' stem '${encoded.idStem}')`);
152
+ }
153
+ /* c8 ignore stop */
154
+ return (0, ts_utils_1.succeed)(true);
155
+ });
156
+ }
157
+ /** Validate and extract the `conversationId` from a `conversations/<id>` scope. */
158
+ static _conversationIdFromScope(scope) {
159
+ const segments = scope.split('/');
160
+ if (segments.length !== 2 || segments[0] !== MtmIdentityCodec.rootScopeSegment) {
161
+ return (0, ts_utils_1.fail)(`MTM codec: scope '${scope}' must be '${MtmIdentityCodec.rootScopeSegment}/<conversationId>'`);
162
+ }
163
+ const conversationId = segments[1];
164
+ return (0, filenameSafety_1.assertPortableFilenameStem)(conversationId)
165
+ .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
166
+ .onSuccess(() => (0, ts_utils_1.succeed)(conversationId));
167
+ }
168
+ /** Validate and extract the turn-index digits from a `turn-<N>` stem. */
169
+ static _turnIndexFromStem(stem) {
170
+ if (!stem.startsWith(MtmIdentityCodec.turnStemPrefix)) {
171
+ return (0, ts_utils_1.fail)(`MTM codec: stem '${stem}' must begin with '${MtmIdentityCodec.turnStemPrefix}'`);
172
+ }
173
+ return MtmIdentityCodec._assertTurnIndex(stem.slice(MtmIdentityCodec.turnStemPrefix.length));
174
+ }
175
+ /** Assert a string is a non-negative integer (the turn index). */
176
+ static _assertTurnIndex(turnIndex) {
177
+ if (!MtmIdentityCodec._turnIndexRe.test(turnIndex)) {
178
+ return (0, ts_utils_1.fail)(`MTM codec: turnIndex '${turnIndex}' must be a non-negative integer`);
179
+ }
180
+ return (0, ts_utils_1.succeed)(turnIndex);
181
+ }
182
+ }
183
+ exports.MtmIdentityCodec = MtmIdentityCodec;
184
+ /** The top-level scope segment under which every MTM subtree lives. */
185
+ MtmIdentityCodec.rootScopeSegment = 'conversations';
186
+ /** The fixed filename-stem prefix for a turn record. */
187
+ MtmIdentityCodec.turnStemPrefix = 'turn-';
188
+ /** A non-negative integer string (the turn index), preserved verbatim. */
189
+ MtmIdentityCodec._turnIndexRe = /^\d+$/;
190
+ //# 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,55 @@
1
+ import { Brand, Converter } from '@fgv/ts-utils';
2
+ /**
3
+ * Stable file-stem identifier for a memory record. Equals the codec-produced
4
+ * `idStem` and the on-disk filename stem (`verifyFilenameId` enforces the
5
+ * round-trip).
6
+ * @public
7
+ */
8
+ export type MemoryId = Brand<string, 'MemoryId'>;
9
+ /**
10
+ * Consumer-supplied domain key. The stable entity identity across versions;
11
+ * the package never mints identity. Equals {@link MemoryId} for non-temporal
12
+ * kinds.
13
+ * @public
14
+ */
15
+ export type EntityId = Brand<string, 'EntityId'>;
16
+ /**
17
+ * Open-vocabulary record classifier. Consumers register one body
18
+ * {@link https://www.npmjs.com/package/@fgv/ts-utils | Converter} per kind.
19
+ * @public
20
+ */
21
+ export type Kind = Brand<string, 'Kind'>;
22
+ /**
23
+ * Open-vocabulary tag label.
24
+ * @public
25
+ */
26
+ export type Tag = Brand<string, 'Tag'>;
27
+ /**
28
+ * Scope path segment. May be multi-segment (`/`-separated) for kinds whose
29
+ * codec maps an entity into a sub-tree (e.g. MTM: `conversations/<id>`). The
30
+ * codec — not this brand — owns filename-safe escaping, so the converter
31
+ * validates only the non-empty/length/whitespace hygiene shared by every
32
+ * brand.
33
+ * @public
34
+ */
35
+ export type MemoryScopeKey = Brand<string, 'MemoryScopeKey'>;
36
+ /**
37
+ * Open-vocabulary link-relation type for an attributed {@link IEdge}.
38
+ * @public
39
+ */
40
+ export type LinkType = Brand<string, 'LinkType'>;
41
+ /**
42
+ * Converters for the branded identifier scalars. Each validates an `unknown`
43
+ * value into the corresponding brand, enforcing the shared hygiene
44
+ * (non-empty, length-capped, trimmed).
45
+ * @public
46
+ */
47
+ export declare const Convert: {
48
+ readonly memoryId: Converter<MemoryId>;
49
+ readonly entityId: Converter<EntityId>;
50
+ readonly kind: Converter<Kind>;
51
+ readonly tag: Converter<Tag>;
52
+ readonly scopeKey: Converter<MemoryScopeKey>;
53
+ readonly linkType: Converter<LinkType>;
54
+ };
55
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/ids.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAqC,MAAM,eAAe,CAAC;AAGpF;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE7D;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAoCjD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE;IACpB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CAwB/B,CAAC"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.Convert = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ const filenameSafety_1 = require("./filenameSafety");
10
+ /**
11
+ * Maximum length of any branded identifier in the library. Picked to be
12
+ * larger than any reasonable id a consumer would supply while still bounded
13
+ * to defuse adversarial inputs (e.g. multi-megabyte ids used as map keys).
14
+ */
15
+ const MAX_BRAND_LENGTH = 256;
16
+ /**
17
+ * Builds a `Converter` for one of the branded id scalars in this library.
18
+ * All brands share the same hygiene: non-empty, length-capped, and free of
19
+ * leading/trailing whitespace. Filename-safety and single-segment
20
+ * constraints are intentionally NOT enforced here — the per-kind
21
+ * {@link IIdentityCodec} owns escaping so that multi-segment scope keys
22
+ * (`conversations/<id>`) and composite entity ids (`<id>:<turn>`) validate
23
+ * cleanly.
24
+ *
25
+ * Not exported — the per-brand `Convert.<brand>` constants are the public
26
+ * surface.
27
+ */
28
+ function brandedIdConverter(brand) {
29
+ return ts_utils_1.Converters.string.map((from) => {
30
+ if (from.length === 0) {
31
+ return (0, ts_utils_1.fail)(`${brand}: must be a non-empty string`);
32
+ }
33
+ if (from.length > MAX_BRAND_LENGTH) {
34
+ return (0, ts_utils_1.fail)(`${brand}: exceeds maximum length ${MAX_BRAND_LENGTH} (got ${from.length})`);
35
+ }
36
+ if (from !== from.trim()) {
37
+ return (0, ts_utils_1.fail)(`${brand}: must not have leading or trailing whitespace`);
38
+ }
39
+ return (0, ts_utils_1.succeed)(from);
40
+ });
41
+ }
42
+ /**
43
+ * Converters for the branded identifier scalars. Each validates an `unknown`
44
+ * value into the corresponding brand, enforcing the shared hygiene
45
+ * (non-empty, length-capped, trimmed).
46
+ * @public
47
+ */
48
+ exports.Convert = {
49
+ /**
50
+ * Validates an `unknown` value as a {@link MemoryId}. Unlike the other
51
+ * brands, `MemoryId` IS the on-disk filename stem (`id === idStem`, enforced
52
+ * by the store's `verifyFilenameId`), so it additionally enforces the
53
+ * portable-filename-stem contract — rejecting path-unsafe ids (`a/b`,
54
+ * `conv-1:7`) at convert time rather than letting them surface as a file-path
55
+ * failure later. (`EntityId` stays relaxed: a domain key may legitimately be
56
+ * a composite like `conv-1:7`; the codec maps it to a safe stem.)
57
+ */
58
+ memoryId: brandedIdConverter('MemoryId').map((id) => (0, filenameSafety_1.assertPortableFilenameStem)(id).onSuccess(() => (0, ts_utils_1.succeed)(id))),
59
+ /** Validates an `unknown` value as an {@link EntityId}. */
60
+ entityId: brandedIdConverter('EntityId'),
61
+ /** Validates an `unknown` value as a {@link Kind}. */
62
+ kind: brandedIdConverter('Kind'),
63
+ /** Validates an `unknown` value as a {@link Tag}. */
64
+ tag: brandedIdConverter('Tag'),
65
+ /** Validates an `unknown` value as a {@link MemoryScopeKey}. */
66
+ scopeKey: brandedIdConverter('MemoryScopeKey'),
67
+ /** Validates an `unknown` value as a {@link LinkType}. */
68
+ linkType: brandedIdConverter('LinkType')
69
+ };
70
+ //# 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,4CAAoF;AACpF,qDAA8D;AA+C9D;;;;GAIG;AACH,MAAM,gBAAgB,GAAW,GAAG,CAAC;AAErC;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAmB,KAAa;IACzD,OAAO,qBAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAY,EAAa,EAAE;QACvD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,IAAA,eAAI,EAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACnC,OAAO,IAAA,eAAI,EAAC,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,IAAA,eAAI,EAAC,GAAG,KAAK,gDAAgD,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,IAAA,kBAAO,EAAC,IAAoB,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACU,QAAA,OAAO,GAOhB;IACF;;;;;;;;OAQG;IACH,QAAQ,EAAE,kBAAkB,CAAW,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC5D,IAAA,2CAA0B,EAAC,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAA,kBAAO,EAAC,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"]}
@@ -0,0 +1,6 @@
1
+ export * from './ids';
2
+ export * from './envelope';
3
+ export * from './filenameSafety';
4
+ export * from './identityCodec';
5
+ export * from './writePolicy';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/index.ts"],"names":[],"mappings":"AAKA,cAAc,OAAO,CAAC;AACtB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ __exportStar(require("./ids"), exports);
22
+ __exportStar(require("./envelope"), exports);
23
+ __exportStar(require("./filenameSafety"), exports);
24
+ __exportStar(require("./identityCodec"), exports);
25
+ __exportStar(require("./writePolicy"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/types/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,wCAAsB;AACtB,6CAA2B;AAC3B,mDAAiC;AACjC,kDAAgC;AAChC,gDAA8B","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './ids';\nexport * from './envelope';\nexport * from './filenameSafety';\nexport * from './identityCodec';\nexport * from './writePolicy';\n"]}