@plebeiantech/lat.md 0.12.3-fork.8 → 0.13.4-fork.1

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 (330) hide show
  1. package/README.md +27 -3
  2. package/dist/src/cli/agent-invocation.d.ts +6 -0
  3. package/dist/src/cli/agent-invocation.js +23 -0
  4. package/dist/src/cli/checklist-menu.d.ts +2 -1
  5. package/dist/src/cli/checklist-menu.js +3 -2
  6. package/dist/src/cli/fork-instructions.d.ts +1 -0
  7. package/dist/src/cli/fork-instructions.js +8 -32
  8. package/dist/src/cli/fork-scaffold.js +2 -2
  9. package/dist/src/cli/graph.d.ts +1 -1
  10. package/dist/src/cli/hook.d.ts +26 -0
  11. package/dist/src/cli/hook.js +115 -64
  12. package/dist/src/cli/index.js +147 -70
  13. package/dist/src/cli/init-preferences.d.ts +4 -0
  14. package/dist/src/cli/init-preferences.js +36 -0
  15. package/dist/src/cli/init.d.ts +2 -1
  16. package/dist/src/cli/init.js +100 -60
  17. package/dist/src/cli/reindex.d.ts +1 -1
  18. package/dist/src/cli/reindex.js +7 -10
  19. package/dist/src/cli/search.d.ts +14 -4
  20. package/dist/src/cli/search.js +115 -101
  21. package/dist/src/cli/ui-build-server.d.ts +12 -0
  22. package/dist/src/cli/ui-build-server.js +26 -0
  23. package/dist/src/cli/ui-build.d.ts +1 -1
  24. package/dist/src/cli/ui-build.js +1 -1
  25. package/dist/src/cli/ui.d.ts +1 -1
  26. package/dist/src/cli/ui.js +1 -1
  27. package/dist/src/fork/antigravity-hook.d.ts +47 -0
  28. package/dist/src/fork/antigravity-hook.js +424 -0
  29. package/dist/src/fork/antigravity-init.d.ts +17 -0
  30. package/dist/src/fork/antigravity-init.js +124 -0
  31. package/dist/src/fork/upstream-drift.js +1 -1
  32. package/dist/src/fork/upstream-guard.d.ts +1 -1
  33. package/dist/src/fork/upstream-guard.js +8 -7
  34. package/dist/src/graph-export.js +7 -7
  35. package/dist/src/knowledge/index.js +2 -2
  36. package/dist/src/mcp/server.js +34 -18
  37. package/dist/src/search/cache.d.ts +3 -0
  38. package/dist/src/search/cache.js +104 -0
  39. package/dist/src/search/chunks.d.ts +23 -0
  40. package/dist/src/search/chunks.js +200 -0
  41. package/dist/src/search/db.d.ts +28 -16
  42. package/dist/src/search/db.js +100 -40
  43. package/dist/src/search/embedder.d.ts +2 -1
  44. package/dist/src/search/embedder.js +7 -6
  45. package/dist/src/search/index.d.ts +6 -2
  46. package/dist/src/search/index.js +176 -53
  47. package/dist/src/search/lexical.d.ts +6 -0
  48. package/dist/src/search/lexical.js +36 -0
  49. package/dist/src/search/lock.d.ts +5 -0
  50. package/dist/src/search/lock.js +45 -0
  51. package/dist/src/search/query.d.ts +26 -0
  52. package/dist/src/search/query.js +103 -0
  53. package/dist/src/search/search.d.ts +16 -7
  54. package/dist/src/search/search.js +165 -21
  55. package/dist/src/search/types.d.ts +15 -0
  56. package/dist/src/view/client/assets/GraphView-D_xnk0bP.js +456 -0
  57. package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  58. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  59. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  60. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  61. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  62. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  63. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  64. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  65. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  66. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  67. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  68. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  69. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  70. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  71. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  72. package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  73. package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  74. package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  75. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  76. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  77. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  78. package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  79. package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  80. package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  81. package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  82. package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  83. package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  84. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  85. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  86. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  87. package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  88. package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  89. package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  90. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  91. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  92. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  93. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  94. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  95. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  96. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  97. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  98. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  99. package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  100. package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  101. package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  102. package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  103. package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  104. package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  105. package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  106. package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  107. package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  108. package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  109. package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  110. package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  111. package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  112. package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  113. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  114. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  115. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  116. package/dist/src/view/client/assets/MarkdownEditor-bjqt_FoF.js +28 -0
  117. package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
  118. package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
  119. package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  120. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-kWGvtRnL.js +1 -0
  121. package/dist/src/view/client/assets/arc-BPAFd7cP.js +1 -0
  122. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-CsY39oIR.js +36 -0
  123. package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-DHGBG7BJ.js +129 -0
  124. package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-vywK4eb7.js +38 -0
  125. package/dist/src/view/client/assets/channel-CX71L_qV.js +1 -0
  126. package/dist/src/view/client/assets/chunk-2Q5K7J3B-Do3Hz_ci.js +1 -0
  127. package/dist/src/view/client/assets/chunk-5VM5RSS4-B5R1lSeY.js +15 -0
  128. package/dist/src/view/client/assets/chunk-F27PBJKO-Dm55FM_W.js +1 -0
  129. package/dist/src/view/client/assets/chunk-IMKFNOWR-ChptrvvM.js +231 -0
  130. package/dist/src/view/client/assets/chunk-JWPE2WC7-BRQBjrKS.js +1 -0
  131. package/dist/src/view/client/assets/chunk-POPQ4Y6H-CainVZIL.js +1 -0
  132. package/dist/src/view/client/assets/chunk-SVP7TREG-DsKsNGmM.js +88 -0
  133. package/dist/src/view/client/assets/chunk-TICWLB2K-BctkMcJc.js +206 -0
  134. package/dist/src/view/client/assets/chunk-XXDRQBXY-BN7SgOUT.js +1 -0
  135. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-B1VyU6zO.js +1 -0
  136. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-B1VyU6zO.js +1 -0
  137. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-BszzwrMe.js +1 -0
  138. package/dist/src/view/client/assets/cynefin-OW5HDTMX-CdRyAkPs.js +166 -0
  139. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-BLvKPZ1u.js +62 -0
  140. package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
  141. package/dist/src/view/client/assets/dagre-GXQ25YYZ-V68w_l65.js +4 -0
  142. package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
  143. package/dist/src/view/client/assets/diagram-S7CK7UJ4-C2i4eEMg.js +30 -0
  144. package/dist/src/view/client/assets/diagram-UQ7AKVKN-BiwWh5jC.js +41 -0
  145. package/dist/src/view/client/assets/diagram-VSXAHHWV-hkKR_vyS.js +3 -0
  146. package/dist/src/view/client/assets/diagram-VX7I27RA-DzRCSMAc.js +24 -0
  147. package/dist/src/view/client/assets/diagram-Z3DM3KII-fhSFPxyK.js +24 -0
  148. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-CCEUDKSA.js +1 -0
  149. package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-FJ2IMyTi.js +99 -0
  150. package/dist/src/view/client/assets/flowDiagram-HODETNUW-BvasdLeK.js +168 -0
  151. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-CiwkBZvY.js +292 -0
  152. package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  153. package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  154. package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  155. package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  156. package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  157. package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  158. package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  159. package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  160. package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  161. package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  162. package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  163. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-DYlP2_js.js +106 -0
  164. package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
  165. package/dist/src/view/client/assets/index-CQ7EOox7.css +1 -0
  166. package/dist/src/view/client/assets/index-CynNDkxt.js +13 -0
  167. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DRPB2c48.js +2 -0
  168. package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
  169. package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-8VV429Cv.js +70 -0
  170. package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-Dzmwnf83.js +139 -0
  171. package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-pYyZZ1i-.js +89 -0
  172. package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
  173. package/dist/src/view/client/assets/layout-GF9k6yGo.js +1 -0
  174. package/dist/src/view/client/assets/linear-Yt2sSOYV.js +1 -0
  175. package/dist/src/view/client/assets/logo-RR_KBOAT.svg +149 -0
  176. package/dist/src/view/client/assets/maplibre-gl-CDX6Zuow.js +800 -0
  177. package/dist/src/view/client/assets/mermaid.core-ChWYCHN0.js +310 -0
  178. package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-Cc4fQvf1.js +96 -0
  179. package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
  180. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-C0SsB8bZ.js +1 -0
  181. package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-DIJpqERZ.js +39 -0
  182. package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC--d-gl6j-.js +7 -0
  183. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BQxwTt7z.js +1 -0
  184. package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-B_oTeD2A.js +84 -0
  185. package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-DLukmE8X.js +40 -0
  186. package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-BNjVB2sc.js +162 -0
  187. package/dist/src/view/client/assets/sizeCapture-INFHLROL-BZecQTOw.js +1 -0
  188. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Bu1urvXC.js +1 -0
  189. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-5pc_697G.js +1 -0
  190. package/dist/src/view/client/assets/swimlanes-42K2YHIH-bLAlcepB.js +1 -0
  191. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-BbOpZjpp.js +8 -0
  192. package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
  193. package/dist/src/view/client/assets/timeline-definition-24CTP7MA-tbwCNvcA.js +120 -0
  194. package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-D8U8Fk0N.js +34 -0
  195. package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-LHBVIeNb.js +78 -0
  196. package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-CN4tfaFV.js +7 -0
  197. package/dist/src/view/client/index.html +2 -2
  198. package/dist/src/view/client-shell.d.ts +2 -0
  199. package/dist/src/view/client-shell.js +5 -0
  200. package/dist/src/view/diagnostics.d.ts +3 -2
  201. package/dist/src/view/diagnostics.js +49 -58
  202. package/dist/src/view/document-edit.d.ts +8 -0
  203. package/dist/src/view/document-edit.js +25 -0
  204. package/dist/src/view/document-route.d.ts +14 -0
  205. package/dist/src/view/document-route.js +137 -0
  206. package/dist/src/view/document-tree.d.ts +18 -0
  207. package/dist/src/view/document-tree.js +139 -0
  208. package/dist/src/view/external-document-tree.d.ts +3 -0
  209. package/dist/src/view/external-document-tree.js +674 -0
  210. package/dist/src/view/git-diff.js +202 -2
  211. package/dist/src/view/git.js +1 -1
  212. package/dist/src/view/graph.d.ts +4 -3
  213. package/dist/src/view/graph.js +100 -9
  214. package/dist/src/view/highlight.d.ts +10 -2
  215. package/dist/src/view/highlight.js +50648 -3166
  216. package/dist/src/view/markdown.d.ts +3 -2
  217. package/dist/src/view/markdown.js +256 -54
  218. package/dist/src/view/preindexed-search.d.ts +15 -0
  219. package/dist/src/view/preindexed-search.js +25 -0
  220. package/dist/src/view/protocol.d.ts +53 -7
  221. package/dist/src/view/publication.d.ts +2 -0
  222. package/dist/src/view/publication.js +78 -0
  223. package/dist/src/view/references.d.ts +11 -26
  224. package/dist/src/view/references.js +121 -112
  225. package/dist/src/view/repository.d.ts +14 -4
  226. package/dist/src/view/repository.js +260 -19
  227. package/dist/src/view/request-security.d.ts +5 -0
  228. package/dist/src/view/request-security.js +46 -0
  229. package/dist/src/view/search-result.d.ts +4 -0
  230. package/dist/src/view/search-result.js +25 -0
  231. package/dist/src/view/search.d.ts +7 -2
  232. package/dist/src/view/search.js +23 -34
  233. package/dist/src/view/server-build.d.ts +21 -0
  234. package/dist/src/view/server-build.js +145 -0
  235. package/dist/src/view/server-deployment.d.ts +31 -0
  236. package/dist/src/view/server-deployment.js +123 -0
  237. package/dist/src/view/server-index-worker.d.ts +6 -0
  238. package/dist/src/view/server-index-worker.js +14 -0
  239. package/dist/src/view/server.d.ts +11 -2
  240. package/dist/src/view/server.js +245 -73
  241. package/dist/src/view/source-target.d.ts +2 -0
  242. package/dist/src/view/source-target.js +49 -8
  243. package/dist/src/view/static-build.d.ts +18 -2
  244. package/dist/src/view/static-build.js +449 -110
  245. package/dist/src/view/static-protocol.d.ts +26 -2
  246. package/dist/src/view/static-protocol.js +5 -0
  247. package/dist/src/view/store.d.ts +20 -3
  248. package/dist/src/view/store.js +304 -48
  249. package/dist/src/view/table-of-contents.d.ts +2 -2
  250. package/dist/src/view/table-of-contents.js +2 -22
  251. package/dist/src/view/vercel-build.d.ts +24 -0
  252. package/dist/src/view/vercel-build.js +152 -0
  253. package/dist/src/view/vercel-server-build.d.ts +10 -0
  254. package/dist/src/view/vercel-server-build.js +61 -0
  255. package/dist/vendor/lat.md-server/cli.d.ts +2 -0
  256. package/dist/vendor/lat.md-server/cli.js +12 -0
  257. package/dist/vendor/lat.md-server/index.d.ts +38 -0
  258. package/dist/vendor/lat.md-server/index.js +128 -0
  259. package/package.json +68 -22
  260. package/plugins/lat-md/README.md +61 -0
  261. package/plugins/lat-md/hooks.json +38 -0
  262. package/plugins/lat-md/plugin.json +9 -0
  263. package/plugins/lat-md/rules/AGENTS.md +344 -0
  264. package/plugins/lat-md/skills/lat-md/SKILL.md +210 -0
  265. package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +226 -0
  266. package/templates/AGENTS.md +26 -7
  267. package/templates/cursor-rules.md +23 -7
  268. package/templates/fork/conventions.md +133 -11
  269. package/templates/opencode-plugin.ts +9 -9
  270. package/templates/pi-extension.ts +11 -11
  271. package/templates/skill/SKILL.md +35 -3
  272. package/dist/src/cli/check-coverage.d.ts +0 -2
  273. package/dist/src/cli/check-coverage.js +0 -71
  274. package/dist/src/cli/check-frontmatter.d.ts +0 -12
  275. package/dist/src/cli/check-frontmatter.js +0 -44
  276. package/dist/src/cli/check-mode.d.ts +0 -21
  277. package/dist/src/cli/check-mode.js +0 -364
  278. package/dist/src/cli/check-status.d.ts +0 -74
  279. package/dist/src/cli/check-status.js +0 -217
  280. package/dist/src/cli/check.d.ts +0 -45
  281. package/dist/src/cli/check.js +0 -781
  282. package/dist/src/cli/context.d.ts +0 -11
  283. package/dist/src/cli/context.js +0 -58
  284. package/dist/src/cli/expand.d.ts +0 -8
  285. package/dist/src/cli/expand.js +0 -94
  286. package/dist/src/cli/gen-index.d.ts +0 -45
  287. package/dist/src/cli/gen-index.js +0 -235
  288. package/dist/src/cli/link-scheme.d.ts +0 -54
  289. package/dist/src/cli/link-scheme.js +0 -101
  290. package/dist/src/cli/locate.d.ts +0 -2
  291. package/dist/src/cli/locate.js +0 -17
  292. package/dist/src/cli/refs.d.ts +0 -22
  293. package/dist/src/cli/refs.js +0 -229
  294. package/dist/src/cli/section.d.ts +0 -43
  295. package/dist/src/cli/section.js +0 -252
  296. package/dist/src/cli/select-menu.d.ts +0 -13
  297. package/dist/src/cli/select-menu.js +0 -100
  298. package/dist/src/code-refs.d.ts +0 -17
  299. package/dist/src/code-refs.js +0 -298
  300. package/dist/src/config.d.ts +0 -29
  301. package/dist/src/config.js +0 -83
  302. package/dist/src/context.d.ts +0 -23
  303. package/dist/src/context.js +0 -11
  304. package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
  305. package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
  306. package/dist/src/extensions/wiki-link/index.d.ts +0 -4
  307. package/dist/src/extensions/wiki-link/index.js +0 -3
  308. package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
  309. package/dist/src/extensions/wiki-link/syntax.js +0 -121
  310. package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
  311. package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
  312. package/dist/src/extensions/wiki-link/types.d.ts +0 -34
  313. package/dist/src/format.d.ts +0 -8
  314. package/dist/src/format.js +0 -43
  315. package/dist/src/init-version.d.ts +0 -10
  316. package/dist/src/init-version.js +0 -49
  317. package/dist/src/lattice.d.ts +0 -109
  318. package/dist/src/lattice.js +0 -817
  319. package/dist/src/parser.d.ts +0 -3
  320. package/dist/src/parser.js +0 -18
  321. package/dist/src/source-parser.d.ts +0 -27
  322. package/dist/src/source-parser.js +0 -916
  323. package/dist/src/untrusted.d.ts +0 -18
  324. package/dist/src/untrusted.js +0 -93
  325. package/dist/src/view/client/assets/index-VZwPPiFE.js +0 -334
  326. package/dist/src/view/client/assets/index-W8ktvNj9.css +0 -1
  327. package/dist/src/view/client/assets/logo-CNF8zs47.svg +0 -182
  328. package/dist/src/walk.d.ts +0 -18
  329. package/dist/src/walk.js +0 -27
  330. /package/dist/src/{extensions/wiki-link → search}/types.js +0 -0
@@ -1,7 +1,8 @@
1
1
  import { createEmbedder, EmbeddingAuthError, } from '@lat.md/embed';
2
2
  import minilm from '@lat.md/embed-minilm-fp16';
3
- import { getLlmKey, getRepoEmbedding } from '../config.js';
3
+ import { getLlmKey, getRepoEmbedding } from '@plebeiantech/lat.md-core/config';
4
4
  export { EmbeddingAuthError };
5
+ const defaultCreateSearchEngine = (key) => key ? createEmbedder({ key }) : createEmbedder({ model: minilm });
5
6
  /** `meta.embedding_model` value for an embedder, e.g. `local:minilm-l6-v2:384`. */
6
7
  export function modelKey(embedder) {
7
8
  return `${embedder.name}:${embedder.dimensions}`;
@@ -33,15 +34,15 @@ export function localEmbedder() {
33
34
  * regenerable `.cache` was wiped) the durable per-repo preference wins over the
34
35
  * env, so a repo switched to local stays local across cache loss.
35
36
  */
36
- export async function embedderForIndex(storedModel, latDir) {
37
+ export async function embedderForIndex(storedModel, latDir, createSearchEngine = defaultCreateSearchEngine) {
37
38
  if (storedModel === null) {
38
39
  if (getRepoEmbedding(latDir) === 'local')
39
- return localEmbedder();
40
+ return createSearchEngine();
40
41
  // No durable preference — decide from the environment, record it later.
41
- return embedderFromEnv();
42
+ return createSearchEngine(getLlmKey());
42
43
  }
43
44
  if (storedModel.startsWith('local:')) {
44
- return localEmbedder(); // ignores LAT_LLM_KEY entirely
45
+ return createSearchEngine(); // ignores LAT_LLM_KEY entirely
45
46
  }
46
47
  // Remote-pinned index: needs a key that resolves to the same model.
47
48
  const key = getLlmKey();
@@ -49,7 +50,7 @@ export async function embedderForIndex(storedModel, latDir) {
49
50
  throw new ReindexRequiredError(`This index was built with '${storedModel}', but no LAT_LLM_KEY is set. ` +
50
51
  `Run 'lat reindex' to switch to the local model or restore the key.`);
51
52
  }
52
- const embedder = await createEmbedder({ key });
53
+ const embedder = await createSearchEngine(key);
53
54
  if (modelKey(embedder) !== storedModel) {
54
55
  throw new ReindexRequiredError(`This index was built with '${storedModel}', but the current key resolves ` +
55
56
  `to '${modelKey(embedder)}'. Run 'lat reindex' to rebuild.`);
@@ -1,9 +1,13 @@
1
- import type { Client } from '@libsql/client';
1
+ import { type SearchDb } from './db.js';
2
+ import { type MarkdownProjectAnalysis } from '@plebeiantech/lat.md-core/project-analysis';
2
3
  import type { Embedder } from './embedder.js';
4
+ export declare function projectFingerprint(project: MarkdownProjectAnalysis): string;
3
5
  export type IndexStats = {
4
6
  added: number;
5
7
  updated: number;
6
8
  removed: number;
7
9
  unchanged: number;
8
10
  };
9
- export declare function indexSections(latDir: string, db: Client, embedder: Embedder, onProgress?: (done: number, total: number) => void): Promise<IndexStats>;
11
+ /** Exact identifier tokens complement FTS's punctuation and long-token handling. */
12
+ export declare function identifierTokens(text: string): string[];
13
+ export declare function indexSections(latDir: string, db: SearchDb, embedder: Embedder, onProgress?: (done: number, total: number) => void, analyzedProject?: MarkdownProjectAnalysis): Promise<IndexStats>;
@@ -1,66 +1,189 @@
1
- import { createHash } from 'node:crypto';
2
- import { readFile } from 'node:fs/promises';
3
- import { dirname, join } from 'node:path';
4
- import { loadAllSections, flattenSections } from '../lattice.js';
5
- function hashContent(text) {
6
- return createHash('sha256').update(text).digest('hex');
1
+ import { PARSER_CACHE_VERSION } from '@plebeiantech/lat.md-core/parser-cache';
2
+ import { synchronizeLexical } from './lexical.js';
3
+ import { dirname } from 'node:path';
4
+ import { CREATE_PASSAGE_FTS } from './db.js';
5
+ import { analyzeMarkdownProject, } from '@plebeiantech/lat.md-core/project-analysis';
6
+ import { chunkFile, digest, embeddingFingerprint } from './chunks.js';
7
+ export function projectFingerprint(project) {
8
+ return digest(`parser:${PARSER_CACHE_VERSION}\n` +
9
+ [...project.files.values()]
10
+ .map((f) => `${f.projectPath}\0${digest(f.content)}`)
11
+ .sort()
12
+ .join('\n'));
7
13
  }
8
- async function sectionContent(section, projectRoot) {
9
- const filePath = join(projectRoot, section.filePath);
10
- const content = await readFile(filePath, 'utf-8');
11
- const lines = content.split('\n');
12
- return lines.slice(section.startLine - 1, section.endLine).join('\n');
14
+ /** Exact identifier tokens complement FTS's punctuation and long-token handling. */
15
+ export function identifierTokens(text) {
16
+ return [
17
+ ...new Set((text.match(/[\p{L}\p{N}_][\p{L}\p{N}_./:#@-]*/gu) ?? [])
18
+ .map((t) => t.toLowerCase())
19
+ .filter((t) => /[_./:#@-]/.test(t) || t.length >= 40)),
20
+ ];
13
21
  }
14
- export async function indexSections(latDir, db, embedder, onProgress) {
15
- const projectRoot = dirname(latDir);
16
- const allSections = await loadAllSections(latDir);
17
- const flat = flattenSections(allSections);
18
- // Build current state: id -> { section, content, hash }
19
- const current = new Map();
20
- for (const s of flat) {
21
- const text = await sectionContent(s, projectRoot);
22
- current.set(s.id, { section: s, content: text, hash: hashContent(text) });
22
+ export async function indexSections(latDir, db, embedder, onProgress, analyzedProject) {
23
+ const project = analyzedProject ??
24
+ (await analyzeMarkdownProject(latDir, dirname(latDir), {
25
+ executor: 'auto',
26
+ }));
27
+ const fingerprint = embeddingFingerprint(embedder);
28
+ const projectHash = projectFingerprint(project);
29
+ const oldFingerprint = (await db.execute("SELECT value FROM meta WHERE key='fingerprint'")).rows[0]?.value;
30
+ if (oldFingerprint && oldFingerprint !== fingerprint)
31
+ throw new Error('Search chunking or embedding model changed; run lat reindex.');
32
+ const byFile = new Map();
33
+ for (const s of project.sections) {
34
+ const list = byFile.get(s.filePath) ?? [];
35
+ list.push(s);
36
+ byFile.set(s.filePath, list);
23
37
  }
24
- // Get existing hashes from DB
25
- const existing = new Map();
26
- const rows = await db.execute('SELECT id, content_hash FROM sections');
27
- for (const row of rows.rows) {
28
- existing.set(row.id, row.content_hash);
38
+ const files = new Map([...project.files.values()].map((f) => [f.projectPath, f]));
39
+ const passages = [...byFile].flatMap(([path, sections]) => {
40
+ const file = files.get(path);
41
+ if (!file)
42
+ throw new Error(`Missing analyzed file: ${path}`);
43
+ return chunkFile(file, sections, embedder);
44
+ });
45
+ const existing = new Map((await db.execute('SELECT id,content_hash FROM sections')).rows.map((r) => [
46
+ r.id,
47
+ r.content_hash,
48
+ ]));
49
+ const sectionHashes = new Map();
50
+ const owned = new Map();
51
+ for (const p of passages) {
52
+ const list = owned.get(p.sectionId) ?? [];
53
+ list.push(p);
54
+ owned.set(p.sectionId, list);
29
55
  }
30
- // Partition into new, changed, unchanged, deleted
31
- const toEmbed = [];
32
- let unchanged = 0;
33
- for (const [id, entry] of current) {
34
- const existingHash = existing.get(id);
35
- if (existingHash === entry.hash) {
36
- unchanged++;
56
+ for (const s of project.sections) {
57
+ sectionHashes.set(s.id, digest(JSON.stringify([
58
+ { ...s, children: undefined },
59
+ (owned.get(s.id) ?? []).map((p) => [p.inputHash, p.spans]),
60
+ ])));
61
+ }
62
+ const changed = new Set([...sectionHashes]
63
+ .filter(([id, hash]) => existing.get(id) !== hash)
64
+ .map(([id]) => id));
65
+ const removed = [...existing.keys()].filter((id) => !sectionHashes.has(id));
66
+ const stats = {
67
+ added: [...changed].filter((id) => !existing.has(id)).length,
68
+ updated: [...changed].filter((id) => existing.has(id)).length,
69
+ removed: removed.length,
70
+ unchanged: project.sections.length - changed.size,
71
+ };
72
+ if (!changed.size && !removed.length && oldFingerprint === fingerprint) {
73
+ // Lexical maintenance can repair old generations without embedding work.
74
+ await db.execute('BEGIN');
75
+ try {
76
+ await synchronizeLexical(db);
77
+ await db.execute({
78
+ sql: "UPDATE meta SET value=? WHERE key='project_hash' AND value<>?",
79
+ args: [projectHash, projectHash],
80
+ });
81
+ await db.execute('COMMIT');
37
82
  }
38
- else {
39
- toEmbed.push({ id, content: entry.content, section: entry.section });
83
+ catch (error) {
84
+ await db.execute('ROLLBACK');
85
+ throw error;
40
86
  }
87
+ return stats;
41
88
  }
42
- const toDelete = [...existing.keys()].filter((id) => !current.has(id));
43
- // Embed new/changed sections
44
- if (toEmbed.length > 0) {
45
- const texts = toEmbed.map((e) => e.content);
46
- const vectors = await embedder.embed(texts, onProgress);
47
- const now = Date.now();
48
- for (let i = 0; i < toEmbed.length; i++) {
49
- const { id, content, section } = toEmbed[i];
50
- const hash = current.get(id).hash;
51
- const vecJson = JSON.stringify(vectors[i]);
89
+ const storedHashes = new Set((await db.execute('SELECT hash FROM embeddings')).rows.map((r) => r.hash));
90
+ const missing = new Map(passages
91
+ .filter((p) => !storedHashes.has(p.inputHash))
92
+ .map((p) => [p.inputHash, p.input]));
93
+ const entries = [...missing];
94
+ const vectors = entries.length
95
+ ? await embedder.embed(entries.map(([, input]) => input), onProgress)
96
+ : [];
97
+ if (vectors.length !== entries.length ||
98
+ vectors.some((v) => v.length !== embedder.dimensions || v.some((n) => !Number.isFinite(n))))
99
+ throw new Error('Embedding backend returned invalid vectors');
100
+ const rebuildFts = !existing.size ||
101
+ // Tantivy retains deleted versions in BM25 statistics until rebuilt.
102
+ stats.updated > 0 ||
103
+ removed.length > 0 ||
104
+ passages.filter((p) => changed.has(p.sectionId)).length > 512;
105
+ await db.execute('BEGIN');
106
+ try {
107
+ if (rebuildFts)
108
+ await db.execute('DROP INDEX IF EXISTS chunks_fts');
109
+ for (let i = 0; i < entries.length; i++)
110
+ await db.execute({
111
+ sql: 'INSERT INTO embeddings VALUES (?,vector32(?))',
112
+ args: [entries[i][0], JSON.stringify(vectors[i])],
113
+ });
114
+ for (const id of [...changed, ...removed]) {
115
+ await db.execute({
116
+ sql: 'DELETE FROM lexical_chunks WHERE id IN (SELECT id FROM chunks WHERE section_id=?)',
117
+ args: [id],
118
+ });
119
+ await db.execute({
120
+ sql: 'DELETE FROM identifiers WHERE chunk_id IN (SELECT id FROM chunks WHERE section_id=?)',
121
+ args: [id],
122
+ });
52
123
  await db.execute({
53
- sql: `INSERT OR REPLACE INTO sections (id, file, heading, content, content_hash, embedding, updated_at)
54
- VALUES (?, ?, ?, ?, ?, vector(?), ?)`,
55
- args: [id, section.file, section.heading, content, hash, vecJson, now],
124
+ sql: 'DELETE FROM chunks WHERE section_id=?',
125
+ args: [id],
56
126
  });
127
+ await db.execute({ sql: 'DELETE FROM sections WHERE id=?', args: [id] });
57
128
  }
129
+ const parents = new Map();
130
+ for (const s of project.sections)
131
+ for (const child of s.children)
132
+ parents.set(child.id, s.id);
133
+ for (const s of project.sections)
134
+ if (changed.has(s.id))
135
+ await db.execute({
136
+ sql: 'INSERT INTO sections VALUES (?,?,?,?,?,?,?,?)',
137
+ args: [
138
+ s.id,
139
+ s.file,
140
+ s.heading,
141
+ s.firstParagraph,
142
+ sectionHashes.get(s.id),
143
+ parents.get(s.id) ?? null,
144
+ s.startLine,
145
+ s.endLine,
146
+ ],
147
+ });
148
+ for (const p of passages)
149
+ if (changed.has(p.sectionId)) {
150
+ const row = (await db.execute({
151
+ sql: 'INSERT INTO chunks(source_id,section_id,ordinal,type,spans,body,heading,path,input_hash) VALUES (?,?,?,?,?,?,?,?,?) RETURNING id',
152
+ args: [
153
+ p.id,
154
+ p.sectionId,
155
+ p.ordinal,
156
+ p.type,
157
+ JSON.stringify(p.spans),
158
+ p.text,
159
+ p.heading,
160
+ p.path,
161
+ p.inputHash,
162
+ ],
163
+ })).rows[0];
164
+ for (const token of identifierTokens(`${p.sectionId}\n${project.sectionById.get(p.sectionId.toLowerCase())?.filePath ?? ''}\n${p.heading}\n${p.path}\n${p.text}`))
165
+ await db.execute({
166
+ sql: 'INSERT INTO identifiers VALUES (?,?)',
167
+ args: [token, row.id],
168
+ });
169
+ }
170
+ await db.execute('DELETE FROM embeddings WHERE hash NOT IN (SELECT input_hash FROM chunks)');
171
+ await db.execute({
172
+ sql: 'INSERT OR REPLACE INTO meta VALUES (?,?)',
173
+ args: ['fingerprint', fingerprint],
174
+ });
175
+ await db.execute({
176
+ sql: 'INSERT OR REPLACE INTO meta VALUES (?,?)',
177
+ args: ['project_hash', projectHash],
178
+ });
179
+ await synchronizeLexical(db);
180
+ if (rebuildFts)
181
+ await db.execute(CREATE_PASSAGE_FTS);
182
+ await db.execute('COMMIT');
58
183
  }
59
- // Delete removed sections
60
- for (const id of toDelete) {
61
- await db.execute({ sql: 'DELETE FROM sections WHERE id = ?', args: [id] });
184
+ catch (error) {
185
+ await db.execute('ROLLBACK');
186
+ throw error;
62
187
  }
63
- const added = toEmbed.filter((e) => !existing.has(e.id)).length;
64
- const updated = toEmbed.filter((e) => existing.has(e.id)).length;
65
- return { added, updated, removed: toDelete.length, unchanged };
188
+ return stats;
66
189
  }
@@ -0,0 +1,6 @@
1
+ import { type SearchDb } from './db.js';
2
+ export declare const LEXICAL_VERSION = "snowball-english-rust-stemmers-1.2.0-v1:unicode-words-v1:live-statistics-v1:turso-fts-v2";
3
+ /** Same analysis for indexed fields and queries; exact identifiers bypass it. */
4
+ export declare function lexicalTokens(text: string): string[];
5
+ /** Populate derived lexical rows, reusing original passages and vectors. */
6
+ export declare function synchronizeLexical(db: SearchDb): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { stemWords, STEMMER_VERSION } from '@lat.md/stemmer';
2
+ import { CREATE_PASSAGE_FTS } from './db.js';
3
+ export const LEXICAL_VERSION = `${STEMMER_VERSION}:unicode-words-v1:live-statistics-v1:turso-fts-v2`;
4
+ /** Same analysis for indexed fields and queries; exact identifiers bypass it. */
5
+ export function lexicalTokens(text) {
6
+ const tokens = text.toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? [];
7
+ const english = tokens.filter((token) => /^[a-z]+$/.test(token));
8
+ const stems = stemWords(english);
9
+ let i = 0;
10
+ return tokens.map((token) => (/^[a-z]+$/.test(token) ? stems[i++] : token));
11
+ }
12
+ /** Populate derived lexical rows, reusing original passages and vectors. */
13
+ export async function synchronizeLexical(db) {
14
+ const version = (await db.execute("SELECT value FROM meta WHERE key='lexical_version'")).rows[0]?.value;
15
+ if (version !== LEXICAL_VERSION) {
16
+ await db.execute('DROP INDEX IF EXISTS chunks_fts');
17
+ await db.execute('DELETE FROM lexical_chunks');
18
+ }
19
+ await db.execute('DELETE FROM lexical_chunks WHERE id NOT IN (SELECT id FROM chunks)');
20
+ const rows = (await db.execute('SELECT id,body,heading,path FROM chunks WHERE id NOT IN (SELECT id FROM lexical_chunks)')).rows;
21
+ for (const row of rows)
22
+ await db.execute({
23
+ sql: 'INSERT INTO lexical_chunks VALUES (?,?,?,?)',
24
+ args: [
25
+ row.id,
26
+ ...[row.body, row.heading, row.path].map((text) => lexicalTokens(text).join(' ')),
27
+ ],
28
+ });
29
+ if (version !== LEXICAL_VERSION) {
30
+ await db.execute(CREATE_PASSAGE_FTS);
31
+ await db.execute({
32
+ sql: 'INSERT OR REPLACE INTO meta VALUES (?,?)',
33
+ args: ['lexical_version', LEXICAL_VERSION],
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,5 @@
1
+ export type LockMode = 'shared' | 'exclusive';
2
+ export declare function acquireSearchLock(cacheDir: string, timeoutMs?: number): Promise<() => Promise<void>>;
3
+ /** A turnstile prevents new readers bypassing a writer waiting for readers to drain. */
4
+ export declare function acquireSearchAccess(cacheDir: string, mode: LockMode, timeoutMs?: number): Promise<() => Promise<void>>;
5
+ export declare function withSearchAccess<T>(cacheDir: string, mode: LockMode, work: () => Promise<T>): Promise<T>;
@@ -0,0 +1,45 @@
1
+ import { open } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { setTimeout } from 'node:timers/promises';
4
+ /** Lock files stay in place so every process locks the same inode. */
5
+ async function acquireFileLock(path, mode, deadline, message) {
6
+ const { tryLock } = await import('fs-native-extensions');
7
+ const handle = await open(path, 'a+');
8
+ try {
9
+ while (!tryLock(handle.fd, { shared: mode === 'shared' })) {
10
+ const remaining = deadline - performance.now();
11
+ if (remaining <= 0)
12
+ throw new Error(message);
13
+ await setTimeout(Math.min(10, remaining));
14
+ }
15
+ return () => handle.close();
16
+ }
17
+ catch (error) {
18
+ await handle.close();
19
+ throw error;
20
+ }
21
+ }
22
+ export function acquireSearchLock(cacheDir, timeoutMs = 120_000) {
23
+ return acquireFileLock(join(cacheDir, 'search-write.lock'), 'exclusive', performance.now() + timeoutMs, 'Search index writer is busy; retry shortly.');
24
+ }
25
+ /** A turnstile prevents new readers bypassing a writer waiting for readers to drain. */
26
+ export async function acquireSearchAccess(cacheDir, mode, timeoutMs = 120_000) {
27
+ const deadline = performance.now() + timeoutMs;
28
+ const message = 'Search database is busy; retry shortly.';
29
+ const releaseGate = await acquireFileLock(join(cacheDir, 'search-access-gate.lock'), 'exclusive', deadline, message);
30
+ try {
31
+ return await acquireFileLock(join(cacheDir, 'search-access.lock'), mode, deadline, message);
32
+ }
33
+ finally {
34
+ await releaseGate();
35
+ }
36
+ }
37
+ export async function withSearchAccess(cacheDir, mode, work) {
38
+ const release = await acquireSearchAccess(cacheDir, mode);
39
+ try {
40
+ return await work();
41
+ }
42
+ finally {
43
+ await release();
44
+ }
45
+ }
@@ -0,0 +1,26 @@
1
+ import type { Section, SectionMatch } from '@plebeiantech/lat.md-core/lattice-model';
2
+ import { type SearchDb } from './db.js';
3
+ import { type CreateSearchEngine } from './embedder.js';
4
+ import { type SearchResult } from './search.js';
5
+ export type IndexedSearchResult = {
6
+ query: string;
7
+ matches: SectionMatch[];
8
+ };
9
+ export type IndexedSearchSession = {
10
+ search: (query: string, limit: number, minSimilarity?: number) => Promise<SearchResult[]>;
11
+ close: () => Promise<void>;
12
+ };
13
+ /** Resolve scored index rows against one already-analyzed project snapshot. */
14
+ export declare function resolveSearchMatches(results: readonly SearchResult[], sectionById: ReadonlyMap<string, Section>): SectionMatch[];
15
+ /** Reuse an embedder with scoped database access for a sequence of index queries. */
16
+ export declare function openIndexedSearchSession(latDir: string, options?: {
17
+ cacheDir?: string;
18
+ createSearchEngine?: CreateSearchEngine;
19
+ }): Promise<IndexedSearchSession>;
20
+ /** Query a finished index and resolve its ids from precomputed section data. */
21
+ export declare function searchIndexedSections(latDir: string, query: string, limit: number, sectionById: ReadonlyMap<string, Section>, options?: {
22
+ cacheDir?: string;
23
+ minSimilarity?: number;
24
+ }): Promise<IndexedSearchResult>;
25
+ export declare function indexMetadata(db: SearchDb): Promise<Map<string, string>>;
26
+ export declare function sameIndexMetadata(a: Map<string, string>, b: Map<string, string>): boolean;
@@ -0,0 +1,103 @@
1
+ import { LEXICAL_VERSION } from './lexical.js';
2
+ import { ReindexRequiredError } from './embedder.js';
3
+ import { existsSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { hasIndex } from './db.js';
6
+ import { closeDb, openDb } from './db.js';
7
+ import { embedderForIndex } from './embedder.js';
8
+ import { searchSections, prepareSearchQuery, } from './search.js';
9
+ /** Resolve scored index rows against one already-analyzed project snapshot. */
10
+ export function resolveSearchMatches(results, sectionById) {
11
+ return results.flatMap((result) => {
12
+ const section = sectionById.get(result.id.toLowerCase());
13
+ return section
14
+ ? [
15
+ {
16
+ section,
17
+ reason: 'hybrid match',
18
+ rankScore: result.rankScore,
19
+ semanticSimilarity: result.semanticSimilarity,
20
+ lexicalScore: result.lexicalScore,
21
+ semanticRank: result.semanticRank,
22
+ lexicalRank: result.lexicalRank,
23
+ evidence: result.evidence,
24
+ diagnostics: result.diagnostics,
25
+ },
26
+ ]
27
+ : [];
28
+ });
29
+ }
30
+ /** Reuse an embedder with scoped database access for a sequence of index queries. */
31
+ export async function openIndexedSearchSession(latDir, options = {}) {
32
+ const cacheDir = options.cacheDir ?? join(latDir, '.cache');
33
+ if (!existsSync(cacheDir) || !hasIndex(cacheDir))
34
+ return { search: async () => [], close: async () => { } };
35
+ const readMetadata = async () => {
36
+ const db = openDb(latDir, options.cacheDir, true);
37
+ try {
38
+ return await indexMetadata(db);
39
+ }
40
+ finally {
41
+ await closeDb(db);
42
+ }
43
+ };
44
+ const initial = await readMetadata();
45
+ const stored = initial.get('embedding_model') ?? null;
46
+ if (stored && initial.get('lexical_version') !== LEXICAL_VERSION)
47
+ throw new ReindexRequiredError('Search lexical index changed; run lat search to update it.');
48
+ const embedder = stored
49
+ ? await embedderForIndex(stored, latDir, options.createSearchEngine)
50
+ : null;
51
+ let closed = false;
52
+ const active = new Set();
53
+ return {
54
+ search(query, limit, minSimilarity) {
55
+ if (closed)
56
+ return Promise.reject(new Error('Search session is closed'));
57
+ const operation = (async () => {
58
+ if (!embedder)
59
+ return [];
60
+ const vector = await prepareSearchQuery(query, embedder, limit, minSimilarity);
61
+ const db = openDb(latDir, options.cacheDir, true);
62
+ try {
63
+ if (!sameIndexMetadata(initial, await indexMetadata(db)))
64
+ throw new ReindexRequiredError('Search index changed; reopen the search session to refresh its documents and model.');
65
+ return await searchSections(db, query, embedder, limit, minSimilarity, vector);
66
+ }
67
+ finally {
68
+ await closeDb(db);
69
+ }
70
+ })();
71
+ active.add(operation);
72
+ void operation.finally(() => active.delete(operation)).catch(() => { });
73
+ return operation;
74
+ },
75
+ async close() {
76
+ closed = true;
77
+ await Promise.allSettled([...active]);
78
+ },
79
+ };
80
+ }
81
+ /** Query a finished index and resolve its ids from precomputed section data. */
82
+ export async function searchIndexedSections(latDir, query, limit, sectionById, options = {}) {
83
+ const session = await openIndexedSearchSession(latDir, options);
84
+ try {
85
+ const results = await session.search(query, limit, options.minSimilarity);
86
+ return {
87
+ query,
88
+ matches: resolveSearchMatches(results, sectionById),
89
+ };
90
+ }
91
+ finally {
92
+ await session.close();
93
+ }
94
+ }
95
+ export async function indexMetadata(db) {
96
+ return new Map((await db.execute('SELECT key,value FROM meta')).rows.map((row) => [
97
+ row.key,
98
+ row.value,
99
+ ]));
100
+ }
101
+ export function sameIndexMetadata(a, b) {
102
+ return (a.size === b.size && [...a].every(([key, value]) => b.get(key) === value));
103
+ }
@@ -1,10 +1,19 @@
1
- import type { Client } from '@libsql/client';
1
+ import type { SearchDb } from './db.js';
2
2
  import type { Embedder } from './embedder.js';
3
- export type SearchResult = {
4
- id: string;
5
- file: string;
6
- heading: string;
7
- content: string;
3
+ import type { SearchResult } from './types.js';
4
+ export type { SearchResult, SearchEvidence, SearchDiagnostics, } from './types.js';
5
+ export declare const DEFAULT_SEARCH_LIMIT = 5;
6
+ export declare const DEFAULT_MIN_SIMILARITY = 0.2;
7
+ export type Candidate = {
8
+ id: number;
9
+ sectionId: string;
8
10
  score: number;
11
+ exact?: boolean;
9
12
  };
10
- export declare function searchSections(db: Client, query: string, embedder: Embedder, limit?: number): Promise<SearchResult[]>;
13
+ export declare function collapse(candidates: Candidate[]): Map<string, Candidate & {
14
+ rank: number;
15
+ }>;
16
+ export declare function literalFtsQuery(query: string): string;
17
+ export declare function searchSections(db: SearchDb, query: string, embedder: Embedder, limit?: number, minSimilarity?: number, preparedVector?: number[]): Promise<SearchResult[]>;
18
+ /** Prepare embeddings before acquiring a database access lock. */
19
+ export declare function prepareSearchQuery(query: string, embedder: Embedder, limit?: number, minSimilarity?: number): Promise<number[]>;