@plebeiantech/lat.md 0.12.3-fork.2 → 0.12.3-fork.20

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 (341) hide show
  1. package/README.md +31 -2
  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/comment-guard.d.ts +14 -0
  7. package/dist/src/cli/comment-guard.js +10 -33
  8. package/dist/src/cli/comment-reminder.d.ts +65 -6
  9. package/dist/src/cli/comment-reminder.js +164 -28
  10. package/dist/src/cli/fork-instructions.d.ts +20 -0
  11. package/dist/src/cli/fork-instructions.js +184 -0
  12. package/dist/src/cli/fork-scaffold.d.ts +106 -0
  13. package/dist/src/cli/fork-scaffold.js +490 -0
  14. package/dist/src/cli/graph.d.ts +1 -1
  15. package/dist/src/cli/hook.d.ts +26 -0
  16. package/dist/src/cli/hook.js +118 -46
  17. package/dist/src/cli/index.js +166 -64
  18. package/dist/src/cli/init-preferences.d.ts +4 -0
  19. package/dist/src/cli/init-preferences.js +36 -0
  20. package/dist/src/cli/init.d.ts +2 -1
  21. package/dist/src/cli/init.js +107 -50
  22. package/dist/src/cli/reindex.d.ts +1 -1
  23. package/dist/src/cli/reindex.js +7 -10
  24. package/dist/src/cli/search.d.ts +14 -4
  25. package/dist/src/cli/search.js +116 -100
  26. package/dist/src/cli/ui-build-server.d.ts +12 -0
  27. package/dist/src/cli/ui-build-server.js +26 -0
  28. package/dist/src/cli/ui-build.d.ts +4 -0
  29. package/dist/src/cli/ui-build.js +13 -0
  30. package/dist/src/cli/ui.d.ts +1 -1
  31. package/dist/src/cli/ui.js +18 -2
  32. package/dist/src/fork/antigravity-hook.d.ts +47 -0
  33. package/dist/src/fork/antigravity-hook.js +424 -0
  34. package/dist/src/fork/antigravity-init.d.ts +17 -0
  35. package/dist/src/fork/antigravity-init.js +124 -0
  36. package/dist/src/fork/upstream-drift-cli.js +2 -0
  37. package/dist/src/fork/upstream-drift.d.ts +26 -0
  38. package/dist/src/fork/upstream-drift.js +185 -0
  39. package/dist/src/fork/upstream-guard-cli.d.ts +1 -0
  40. package/dist/src/fork/upstream-guard-cli.js +2 -0
  41. package/dist/src/fork/upstream-guard.d.ts +72 -0
  42. package/dist/src/fork/upstream-guard.js +445 -0
  43. package/dist/src/graph-export.d.ts +2 -0
  44. package/dist/src/graph-export.js +38 -19
  45. package/dist/src/knowledge/claude-memory.d.ts +1 -0
  46. package/dist/src/knowledge/claude-memory.js +33 -4
  47. package/dist/src/knowledge/index.js +2 -2
  48. package/dist/src/mcp/server.js +34 -18
  49. package/dist/src/search/cache.d.ts +3 -0
  50. package/dist/src/search/cache.js +104 -0
  51. package/dist/src/search/chunks.d.ts +23 -0
  52. package/dist/src/search/chunks.js +197 -0
  53. package/dist/src/search/db.d.ts +28 -16
  54. package/dist/src/search/db.js +106 -40
  55. package/dist/src/search/embedder.d.ts +2 -1
  56. package/dist/src/search/embedder.js +7 -6
  57. package/dist/src/search/index.d.ts +6 -2
  58. package/dist/src/search/index.js +176 -53
  59. package/dist/src/search/lexical.d.ts +6 -0
  60. package/dist/src/search/lexical.js +36 -0
  61. package/dist/src/search/lock.d.ts +5 -0
  62. package/dist/src/search/lock.js +45 -0
  63. package/dist/src/search/query.d.ts +26 -0
  64. package/dist/src/search/query.js +103 -0
  65. package/dist/src/search/search.d.ts +17 -7
  66. package/dist/src/search/search.js +164 -14
  67. package/dist/src/search/types.d.ts +15 -0
  68. package/dist/src/search/types.js +1 -0
  69. package/dist/src/view/client/assets/GraphView-Dij8mAA_.js +456 -0
  70. package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  71. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  72. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  73. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  74. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  75. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  76. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  77. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  78. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  79. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  80. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  81. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  82. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  83. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  84. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  85. package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  86. package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  87. package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  88. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  89. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  90. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  91. package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  92. package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  93. package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  94. package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  95. package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  96. package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  97. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  98. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  99. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  100. package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  101. package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  102. package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  103. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  104. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  105. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  106. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  107. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  108. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  109. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  110. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  111. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  112. package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  113. package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  114. package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  115. package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  116. package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  117. package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  118. package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  119. package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  120. package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  121. package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  122. package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  123. package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  124. package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  125. package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  126. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  127. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  128. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  129. package/dist/src/view/client/assets/MarkdownEditor-88Wbt0M1.js +28 -0
  130. package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
  131. package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
  132. package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  133. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-y0DlYa8E.js +1 -0
  134. package/dist/src/view/client/assets/arc-FlMu8dnO.js +1 -0
  135. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-DA_uWZW1.js +36 -0
  136. package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-BHQ5LU85.js +129 -0
  137. package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-BRucKCt2.js +38 -0
  138. package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
  139. package/dist/src/view/client/assets/chunk-2Q5K7J3B-BJPcFivt.js +1 -0
  140. package/dist/src/view/client/assets/chunk-5VM5RSS4-v2q99bGz.js +15 -0
  141. package/dist/src/view/client/assets/chunk-F27PBJKO-CcHOuJCs.js +1 -0
  142. package/dist/src/view/client/assets/chunk-IMKFNOWR-DNxYuJNq.js +231 -0
  143. package/dist/src/view/client/assets/chunk-JWPE2WC7-C0eHKvLW.js +1 -0
  144. package/dist/src/view/client/assets/chunk-POPQ4Y6H-57CWp2Ve.js +1 -0
  145. package/dist/src/view/client/assets/chunk-SVP7TREG-BqcoxIJw.js +88 -0
  146. package/dist/src/view/client/assets/chunk-TICWLB2K-DRUJR5zH.js +206 -0
  147. package/dist/src/view/client/assets/chunk-XXDRQBXY-Dez0oRoM.js +1 -0
  148. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
  149. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
  150. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-BHtud6Hg.js +1 -0
  151. package/dist/src/view/client/assets/cynefin-OW5HDTMX-BjBW8VGk.js +166 -0
  152. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-DwGuD7oF.js +62 -0
  153. package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
  154. package/dist/src/view/client/assets/dagre-GXQ25YYZ-C5zSlGK9.js +4 -0
  155. package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
  156. package/dist/src/view/client/assets/diagram-S7CK7UJ4-C_NhA3bj.js +30 -0
  157. package/dist/src/view/client/assets/diagram-UQ7AKVKN-az7QPYNb.js +41 -0
  158. package/dist/src/view/client/assets/diagram-VSXAHHWV-BRvDuM8_.js +3 -0
  159. package/dist/src/view/client/assets/diagram-VX7I27RA-BWLgF6S-.js +24 -0
  160. package/dist/src/view/client/assets/diagram-Z3DM3KII-DV3d6mL5.js +24 -0
  161. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-yUXrEAvK.js +1 -0
  162. package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-D35FN1Pt.js +99 -0
  163. package/dist/src/view/client/assets/flowDiagram-HODETNUW-BciZqsjT.js +168 -0
  164. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-BysPGgXS.js +292 -0
  165. package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  166. package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  167. package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  168. package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  169. package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  170. package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  171. package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  172. package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  173. package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  174. package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  175. package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  176. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js +106 -0
  177. package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
  178. package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
  179. package/dist/src/view/client/assets/index-DG0Ez15D.css +1 -0
  180. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-D3HZrDRb.js +2 -0
  181. package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
  182. package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-BXyVIXTU.js +70 -0
  183. package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-D4-1NxVU.js +139 -0
  184. package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-4Gu_5yBA.js +89 -0
  185. package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
  186. package/dist/src/view/client/assets/layout-Jf1K3TMM.js +1 -0
  187. package/dist/src/view/client/assets/linear-DWfwzUT_.js +1 -0
  188. package/dist/src/view/client/assets/logo-RR_KBOAT.svg +149 -0
  189. package/dist/src/view/client/assets/maplibre-gl-CDX6Zuow.js +800 -0
  190. package/dist/src/view/client/assets/mermaid.core-DMx_DAl8.js +310 -0
  191. package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-8pxY_RWi.js +96 -0
  192. package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
  193. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-DNAw_O5t.js +1 -0
  194. package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-uuvRCDkC.js +39 -0
  195. package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC-BER2O4Aq.js +7 -0
  196. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-CxEsJ_0n.js +1 -0
  197. package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-yS9rspca.js +84 -0
  198. package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-Bqt70a2j.js +40 -0
  199. package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-BvOOEJNr.js +162 -0
  200. package/dist/src/view/client/assets/sizeCapture-INFHLROL-CvO_Pjjo.js +1 -0
  201. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-KLmVOZkq.js +1 -0
  202. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
  203. package/dist/src/view/client/assets/swimlanes-42K2YHIH-DC1r4_sq.js +1 -0
  204. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
  205. package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
  206. package/dist/src/view/client/assets/timeline-definition-24CTP7MA-ChXLOuBL.js +120 -0
  207. package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-D9_h25-Y.js +34 -0
  208. package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-CsQJGGW0.js +78 -0
  209. package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-DGMuPMlm.js +7 -0
  210. package/dist/src/view/client/index.html +2 -2
  211. package/dist/src/view/client-shell.d.ts +2 -0
  212. package/dist/src/view/client-shell.js +5 -0
  213. package/dist/src/view/diagnostics.d.ts +3 -2
  214. package/dist/src/view/diagnostics.js +49 -58
  215. package/dist/src/view/document-edit.d.ts +8 -0
  216. package/dist/src/view/document-edit.js +25 -0
  217. package/dist/src/view/document-route.d.ts +14 -0
  218. package/dist/src/view/document-route.js +126 -0
  219. package/dist/src/view/document-tree.d.ts +18 -0
  220. package/dist/src/view/document-tree.js +139 -0
  221. package/dist/src/view/external-document-tree.d.ts +3 -0
  222. package/dist/src/view/external-document-tree.js +674 -0
  223. package/dist/src/view/git-diff.js +205 -1
  224. package/dist/src/view/git.js +1 -1
  225. package/dist/src/view/graph.d.ts +7 -0
  226. package/dist/src/view/graph.js +267 -0
  227. package/dist/src/view/highlight.d.ts +10 -2
  228. package/dist/src/view/highlight.js +4547 -1363
  229. package/dist/src/view/markdown.d.ts +8 -3
  230. package/dist/src/view/markdown.js +308 -41
  231. package/dist/src/view/preindexed-search.d.ts +15 -0
  232. package/dist/src/view/preindexed-search.js +25 -0
  233. package/dist/src/view/protocol.d.ts +95 -6
  234. package/dist/src/view/protocol.js +1 -1
  235. package/dist/src/view/publication.d.ts +2 -0
  236. package/dist/src/view/publication.js +78 -0
  237. package/dist/src/view/references.d.ts +13 -26
  238. package/dist/src/view/references.js +150 -119
  239. package/dist/src/view/repository.d.ts +18 -5
  240. package/dist/src/view/repository.js +269 -27
  241. package/dist/src/view/request-security.d.ts +5 -0
  242. package/dist/src/view/request-security.js +46 -0
  243. package/dist/src/view/search-result.d.ts +4 -0
  244. package/dist/src/view/search-result.js +25 -0
  245. package/dist/src/view/search.d.ts +7 -2
  246. package/dist/src/view/search.js +23 -33
  247. package/dist/src/view/server-build.d.ts +21 -0
  248. package/dist/src/view/server-build.js +145 -0
  249. package/dist/src/view/server-deployment.d.ts +31 -0
  250. package/dist/src/view/server-deployment.js +94 -0
  251. package/dist/src/view/server-index-worker.d.ts +6 -0
  252. package/dist/src/view/server-index-worker.js +14 -0
  253. package/dist/src/view/server.d.ts +14 -2
  254. package/dist/src/view/server.js +254 -51
  255. package/dist/src/view/source-target.d.ts +10 -0
  256. package/dist/src/view/source-target.js +43 -0
  257. package/dist/src/view/static-build.d.ts +32 -0
  258. package/dist/src/view/static-build.js +741 -0
  259. package/dist/src/view/static-protocol.d.ts +47 -0
  260. package/dist/src/view/static-protocol.js +15 -0
  261. package/dist/src/view/store.d.ts +26 -3
  262. package/dist/src/view/store.js +325 -44
  263. package/dist/src/view/table-of-contents.d.ts +9 -0
  264. package/dist/src/view/table-of-contents.js +83 -0
  265. package/dist/src/view/vercel-build.d.ts +24 -0
  266. package/dist/src/view/vercel-build.js +140 -0
  267. package/dist/src/view/vercel-server-build.d.ts +10 -0
  268. package/dist/src/view/vercel-server-build.js +61 -0
  269. package/dist/vendor/lat.md-server/cli.d.ts +2 -0
  270. package/dist/vendor/lat.md-server/cli.js +12 -0
  271. package/dist/vendor/lat.md-server/index.d.ts +38 -0
  272. package/dist/vendor/lat.md-server/index.js +128 -0
  273. package/package.json +72 -25
  274. package/plugins/lat-md/README.md +61 -0
  275. package/plugins/lat-md/hooks.json +38 -0
  276. package/plugins/lat-md/plugin.json +9 -0
  277. package/plugins/lat-md/rules/AGENTS.md +118 -0
  278. package/plugins/lat-md/skills/lat-md/SKILL.md +178 -0
  279. package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +182 -0
  280. package/templates/AGENTS.md +19 -18
  281. package/templates/cursor-rules.md +14 -5
  282. package/templates/fork/conventions.md +173 -0
  283. package/templates/opencode-plugin.ts +9 -9
  284. package/templates/pi-extension.ts +11 -11
  285. package/templates/skill/SKILL.md +28 -17
  286. package/dist/src/cli/check-frontmatter.d.ts +0 -12
  287. package/dist/src/cli/check-frontmatter.js +0 -44
  288. package/dist/src/cli/check-mode.d.ts +0 -6
  289. package/dist/src/cli/check-mode.js +0 -303
  290. package/dist/src/cli/check-status.d.ts +0 -74
  291. package/dist/src/cli/check-status.js +0 -217
  292. package/dist/src/cli/check.d.ts +0 -45
  293. package/dist/src/cli/check.js +0 -777
  294. package/dist/src/cli/context.d.ts +0 -11
  295. package/dist/src/cli/context.js +0 -58
  296. package/dist/src/cli/expand.d.ts +0 -8
  297. package/dist/src/cli/expand.js +0 -94
  298. package/dist/src/cli/gen-index.d.ts +0 -45
  299. package/dist/src/cli/gen-index.js +0 -235
  300. package/dist/src/cli/link-scheme.d.ts +0 -54
  301. package/dist/src/cli/link-scheme.js +0 -101
  302. package/dist/src/cli/locate.d.ts +0 -2
  303. package/dist/src/cli/locate.js +0 -17
  304. package/dist/src/cli/refs.d.ts +0 -22
  305. package/dist/src/cli/refs.js +0 -229
  306. package/dist/src/cli/section.d.ts +0 -43
  307. package/dist/src/cli/section.js +0 -252
  308. package/dist/src/cli/select-menu.d.ts +0 -13
  309. package/dist/src/cli/select-menu.js +0 -100
  310. package/dist/src/code-refs.d.ts +0 -17
  311. package/dist/src/code-refs.js +0 -277
  312. package/dist/src/config.d.ts +0 -29
  313. package/dist/src/config.js +0 -83
  314. package/dist/src/context.d.ts +0 -23
  315. package/dist/src/context.js +0 -11
  316. package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
  317. package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
  318. package/dist/src/extensions/wiki-link/index.d.ts +0 -4
  319. package/dist/src/extensions/wiki-link/index.js +0 -3
  320. package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
  321. package/dist/src/extensions/wiki-link/syntax.js +0 -121
  322. package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
  323. package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
  324. package/dist/src/extensions/wiki-link/types.d.ts +0 -34
  325. package/dist/src/format.d.ts +0 -8
  326. package/dist/src/format.js +0 -43
  327. package/dist/src/init-version.d.ts +0 -10
  328. package/dist/src/init-version.js +0 -49
  329. package/dist/src/lattice.d.ts +0 -108
  330. package/dist/src/lattice.js +0 -816
  331. package/dist/src/parser.d.ts +0 -3
  332. package/dist/src/parser.js +0 -18
  333. package/dist/src/source-parser.d.ts +0 -27
  334. package/dist/src/source-parser.js +0 -916
  335. package/dist/src/untrusted.d.ts +0 -24
  336. package/dist/src/untrusted.js +0 -97
  337. package/dist/src/view/client/assets/index-B0n0u03y.css +0 -1
  338. package/dist/src/view/client/assets/index-xm2_px4q.js +0 -23
  339. package/dist/src/walk.d.ts +0 -18
  340. package/dist/src/walk.js +0 -27
  341. /package/dist/src/{extensions/wiki-link/types.js → fork/upstream-drift-cli.d.ts} +0 -0
@@ -2,14 +2,16 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
4
  import { dirname } from 'node:path';
5
- import { findLatticeDir } from '../lattice.js';
6
- import { plainStyler } from '../context.js';
7
- import { locateCommand } from '../cli/locate.js';
8
- import { sectionCommand } from '../cli/section.js';
5
+ import { findLatticeDir } from '@plebeiantech/lat.md-core/project-discovery';
6
+ import { plainStyler, } from '@plebeiantech/lat.md-core/context';
7
+ import { locateCommand } from '@plebeiantech/lat.md-core/cli/locate';
8
+ import { sectionCommand } from '@plebeiantech/lat.md-core/cli/section';
9
9
  import { searchCommand } from '../cli/search.js';
10
- import { expandCommand } from '../cli/expand.js';
11
- import { checkAllCommand } from '../cli/check.js';
12
- import { refsCommand } from '../cli/refs.js';
10
+ import { DEFAULT_SEARCH_LIMIT, DEFAULT_MIN_SIMILARITY, } from '../search/search.js';
11
+ import { expandCommand } from '@plebeiantech/lat.md-core/cli/expand';
12
+ import { checkAllCommand } from '@plebeiantech/lat.md-core/cli/check';
13
+ import { refsCommand } from '@plebeiantech/lat.md-core/cli/refs';
14
+ import { externalListCommand, externalShowCommand, } from '@plebeiantech/lat.md-core/cli/external';
13
15
  function toMcp(result) {
14
16
  const content = [{ type: 'text', text: result.output }];
15
17
  return result.isError ? { content, isError: true } : { content };
@@ -27,24 +29,34 @@ export async function startMcpServer() {
27
29
  styler: plainStyler,
28
30
  mode: 'mcp',
29
31
  };
32
+ const requestContext = () => ({ ...ctx, analysis: undefined });
30
33
  const server = new McpServer({
31
34
  name: 'lat',
32
35
  version: '1.0.0',
33
36
  });
34
- server.tool('lat_locate', 'Find sections by name (exact, fuzzy, subsequence matching)', { query: z.string().describe('Section name or id to search for') }, async ({ query }) => toMcp(await locateCommand(ctx, query)));
35
- server.tool('lat_section', 'Show a section with its content, outgoing wiki link targets, and incoming references', {
36
- query: z.string().describe('Section id to look up (short or full form)'),
37
- }, async ({ query }) => toMcp(await sectionCommand(ctx, query)));
38
- server.tool('lat_search', 'Semantic search across lat.md sections using embeddings', {
37
+ server.tool('lat_locate', 'Find sections by name (exact, fuzzy, subsequence matching)', { query: z.string().describe('Section name or id to search for') }, async ({ query }) => toMcp(await locateCommand(requestContext(), query)));
38
+ server.tool('lat_section', 'Show a local section or exact external target with content and references', {
39
+ query: z
40
+ .string()
41
+ .describe('Local section id or exact handle:path#fragment target'),
42
+ }, async ({ query }) => toMcp(await sectionCommand(requestContext(), query)));
43
+ server.tool('lat_search', 'Hybrid lexical and semantic search across lat.md sections', {
39
44
  query: z.string().describe('Search query in natural language'),
40
45
  limit: z
41
46
  .number()
42
47
  .optional()
43
- .default(5)
44
- .describe('Max results (default 5)'),
45
- }, async ({ query, limit }) => toMcp(await searchCommand(ctx, query, { limit })));
46
- server.tool('lat_expand', 'Expand [[refs]] in text to resolved lat.md section paths with context', { text: z.string().describe('Text containing [[refs]] to expand') }, async ({ text: input }) => toMcp(await expandCommand(ctx, input)));
47
- server.tool('lat_check', 'Run full lat.md validation: links, code references, indexes, and section structure', {}, async () => toMcp(await checkAllCommand(ctx)));
48
+ .default(DEFAULT_SEARCH_LIMIT)
49
+ .describe(`Max results (default ${DEFAULT_SEARCH_LIMIT})`),
50
+ minSimilarity: z
51
+ .number()
52
+ .min(0)
53
+ .max(1)
54
+ .optional()
55
+ .default(DEFAULT_MIN_SIMILARITY)
56
+ .describe('Minimum cosine similarity score (default 0.20)'),
57
+ }, async ({ query, limit, minSimilarity }) => toMcp(await searchCommand(requestContext(), query, { limit, minSimilarity })));
58
+ server.tool('lat_expand', 'Expand [[refs]] in text to resolved lat.md section paths with context', { text: z.string().describe('Text containing [[refs]] to expand') }, async ({ text: input }) => toMcp(await expandCommand(requestContext(), input)));
59
+ server.tool('lat_check', 'Run full lat.md validation: links, code references, indexes, and section structure', {}, async () => toMcp(await checkAllCommand(requestContext())));
48
60
  server.tool('lat_refs', 'Find sections that reference a given section via wiki links or @lat code comments', {
49
61
  query: z.string().describe('Section id to find references for'),
50
62
  scope: z
@@ -52,7 +64,11 @@ export async function startMcpServer() {
52
64
  .optional()
53
65
  .default('md+code')
54
66
  .describe('Where to search: md, code, or md+code'),
55
- }, async ({ query, scope }) => toMcp(await refsCommand(ctx, query, scope)));
67
+ }, async ({ query, scope }) => toMcp(await refsCommand(requestContext(), query, scope)));
68
+ server.tool('lat_external_list', 'List configured external sources without fetching or changing caches', {}, async () => toMcp(await externalListCommand(ctx, true)));
69
+ server.tool('lat_external_show', 'Show one configured external source or exact external target without fetching it', {
70
+ source: z.string().describe('External source handle or exact target'),
71
+ }, async ({ source }) => toMcp(await externalShowCommand(ctx, source, true)));
56
72
  const transport = new StdioServerTransport();
57
73
  await server.connect(transport);
58
74
  }
@@ -0,0 +1,3 @@
1
+ import { SearchDb } from './db.js';
2
+ /** Build a private staging database; access locks protect copies and publication of search.db. */
3
+ export declare function writeIndex<T>(latDir: string, cacheDir: string | undefined, rebuild: boolean, work: (db: SearchDb, storedModel: string | null) => Promise<T>): Promise<T>;
@@ -0,0 +1,104 @@
1
+ import { copyFile, mkdir, rename, rm, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { acquireSearchLock, withSearchAccess } from './lock.js';
4
+ import { SearchDb, hasIndex, INDEX_FILE, ensureMeta, getStoredModel, } from './db.js';
5
+ /** Retry transient Windows handles without deleting the usable index first. */
6
+ async function withFileRetry(work) {
7
+ for (let attempt = 0;; attempt++) {
8
+ try {
9
+ await work();
10
+ return;
11
+ }
12
+ catch (error) {
13
+ const code = error.code;
14
+ // Windows may briefly retain a staging handle or a reader handle.
15
+ if (process.platform !== 'win32' ||
16
+ attempt >= 9 ||
17
+ !['EBUSY', 'EPERM', 'EACCES'].includes(code ?? ''))
18
+ throw error;
19
+ await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
20
+ }
21
+ }
22
+ }
23
+ async function removeStaging(path) {
24
+ for (const suffix of ['', '-wal', '-shm', '-journal'])
25
+ await withFileRetry(() => rm(path + suffix, { force: true }));
26
+ }
27
+ /** Build a private staging database; access locks protect copies and publication of search.db. */
28
+ export async function writeIndex(latDir, cacheDir, rebuild, work) {
29
+ const dir = cacheDir ?? join(latDir, '.cache');
30
+ await mkdir(dir, { recursive: true });
31
+ const path = join(dir, '_search.db');
32
+ const activePath = join(dir, INDEX_FILE);
33
+ let db;
34
+ const release = await acquireSearchLock(dir);
35
+ try {
36
+ // A crashed writer may have left a partial database and journal behind.
37
+ await removeStaging(path);
38
+ const existing = hasIndex(dir);
39
+ if (existing && !rebuild) {
40
+ await withSearchAccess(dir, 'exclusive', async () => {
41
+ // Recover/checkpoint a WAL left by a process that died during a query.
42
+ const source = new SearchDb(activePath);
43
+ try {
44
+ await source.checkpoint();
45
+ }
46
+ finally {
47
+ await source.close();
48
+ }
49
+ await copyFile(activePath, path);
50
+ });
51
+ }
52
+ db = new SearchDb(path);
53
+ const model = existing && !rebuild ? await getStoredModel(db) : null;
54
+ await ensureMeta(db);
55
+ const changesBefore = (await db.execute('SELECT total_changes() AS n'))
56
+ .rows[0].n;
57
+ const result = await work(db, model);
58
+ const unchanged = existing &&
59
+ !rebuild &&
60
+ (await db.execute('SELECT total_changes() AS n')).rows[0].n ===
61
+ changesBefore;
62
+ await db.checkpoint();
63
+ await db.close();
64
+ db = undefined;
65
+ if (!unchanged)
66
+ await withSearchAccess(dir, 'exclusive', async () => {
67
+ // Recover old sidecars before replacing their database, including after a crash.
68
+ if (existing) {
69
+ const wal = await stat(activePath + '-wal').catch((error) => {
70
+ if (error.code !== 'ENOENT')
71
+ throw error;
72
+ return undefined;
73
+ });
74
+ // A fresh rebuild must also repair an unreadable database with no WAL.
75
+ if (wal && wal.size > 0) {
76
+ const source = new SearchDb(activePath);
77
+ try {
78
+ await source.checkpoint();
79
+ }
80
+ finally {
81
+ await source.close();
82
+ }
83
+ }
84
+ for (const suffix of ['-wal', '-shm', '-journal'])
85
+ await withFileRetry(() => rm(activePath + suffix, { force: true }));
86
+ }
87
+ await withFileRetry(() => rename(path, activePath));
88
+ });
89
+ return result;
90
+ }
91
+ finally {
92
+ try {
93
+ await db?.close();
94
+ }
95
+ finally {
96
+ try {
97
+ await removeStaging(path);
98
+ }
99
+ finally {
100
+ await release();
101
+ }
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,23 @@
1
+ import type { SourceSpan } from './types.js';
2
+ import type { Embedder } from './embedder.js';
3
+ import type { MarkdownFileAnalysis } from '@plebeiantech/lat.md-core/markdown-analysis';
4
+ import type { Section } from '@plebeiantech/lat.md-core/lattice-model';
5
+ export declare const CHUNK_POLICY = "owned-blocks-v1";
6
+ export type Passage = {
7
+ id: string;
8
+ sectionId: string;
9
+ ordinal: number;
10
+ type: string;
11
+ spans: SourceSpan[];
12
+ text: string;
13
+ input: string;
14
+ inputHash: string;
15
+ heading: string;
16
+ path: string;
17
+ };
18
+ export declare const digest: (text: string) => string;
19
+ export declare function embeddingFingerprint(embedder: Embedder): string;
20
+ /** Find a fitting Unicode-safe prefix without assuming token-count monotonicity. */
21
+ export declare function fittingPrefix(text: string, fits: (text: string) => boolean): number;
22
+ /** Every body block is owned once; headings provide context instead of copied subtrees. */
23
+ export declare function chunkFile(file: MarkdownFileAnalysis, sections: readonly Section[], embedder: Embedder): Passage[];
@@ -0,0 +1,197 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const CHUNK_POLICY = 'owned-blocks-v1';
3
+ export const digest = (text) => createHash('sha256').update(text).digest('hex');
4
+ export function embeddingFingerprint(embedder) {
5
+ return `${CHUNK_POLICY}:${embedder.name}:${embedder.dimensions}:${embedder.maxInputTokens}:${embedder.tokenizerFingerprint}`;
6
+ }
7
+ /** Find a fitting Unicode-safe prefix without assuming token-count monotonicity. */
8
+ export function fittingPrefix(text, fits) {
9
+ if (fits(text))
10
+ return text.length;
11
+ let size = text.length;
12
+ while (size > 0) {
13
+ size = Math.floor(size / 2);
14
+ if (size && /[\uD800-\uDBFF]/.test(text[size - 1]))
15
+ size--;
16
+ if (size && fits(text.slice(0, size)))
17
+ return size;
18
+ }
19
+ return 0;
20
+ }
21
+ /** Every body block is owned once; headings provide context instead of copied subtrees. */
22
+ export function chunkFile(file, sections, embedder) {
23
+ const local = embedder.name.startsWith('local:');
24
+ const target = local ? 192 : 512;
25
+ const contextBudget = local ? 48 : 96;
26
+ const source = file.content;
27
+ const lineStarts = [0];
28
+ for (let i = 0; i < source.length; i++)
29
+ if (source[i] === '\n')
30
+ lineStarts.push(i + 1);
31
+ const lineAt = (offset) => {
32
+ let lo = 0, hi = lineStarts.length;
33
+ while (lo + 1 < hi) {
34
+ const mid = (lo + hi) >>> 1;
35
+ if (lineStarts[mid] <= offset)
36
+ lo = mid;
37
+ else
38
+ hi = mid;
39
+ }
40
+ return lo + 1;
41
+ };
42
+ const own = new Map();
43
+ const ordered = [...sections].sort((a, b) => a.startLine - b.startLine || a.depth - b.depth);
44
+ let sectionIndex = 0;
45
+ let ancestors = [];
46
+ for (const block of file.blocks) {
47
+ if (block.type === 'heading' || block.type === 'yaml')
48
+ continue;
49
+ while (sectionIndex < ordered.length &&
50
+ ordered[sectionIndex].startLine <= block.startLine) {
51
+ const next = ordered[sectionIndex++];
52
+ ancestors = ancestors.filter((s) => s.endLine >= next.startLine);
53
+ ancestors.push(next);
54
+ }
55
+ ancestors = ancestors.filter((s) => s.endLine >= block.endLine);
56
+ const owner = ancestors.at(-1);
57
+ if (!owner)
58
+ throw new Error(`No section owns ${file.path}:${block.startLine}`);
59
+ const blocks = own.get(owner.id) ?? [];
60
+ blocks.push(block);
61
+ own.set(owner.id, blocks);
62
+ }
63
+ const result = [];
64
+ for (const section of sections) {
65
+ const headings = section.id.split('#').slice(1);
66
+ const rawContext = `Section: ${section.heading}\nPage: ${file.headingTitles[0] ?? file.path}\nPath: ${headings.slice(0, -1).join(' > ')}`;
67
+ const contextLength = fittingPrefix(rawContext, (t) => embedder.countTokens(t) <= contextBudget);
68
+ const context = rawContext.slice(0, contextLength);
69
+ const path = headings.slice(0, -1).join(' > ');
70
+ let ordinal = 0;
71
+ const inputFor = (text, extra) => {
72
+ const extraSize = fittingPrefix(extra, (t) => embedder.countTokens(t) <= contextBudget / 2);
73
+ const fullContext = [extra.slice(0, extraSize), context]
74
+ .filter(Boolean)
75
+ .join('\n');
76
+ const n = fittingPrefix(fullContext, (c) => embedder.countTokens(c) <= contextBudget &&
77
+ embedder.countTokens(`${c}\n\n${text}`) <= embedder.maxInputTokens);
78
+ return n ? `${fullContext.slice(0, n)}\n\n${text}` : text;
79
+ };
80
+ const fits = (text, extra = '') => embedder.countTokens(text) <= target &&
81
+ embedder.countTokens(inputFor(text, extra)) <= embedder.maxInputTokens;
82
+ const split = (block, extra = '') => {
83
+ const text = source.slice(block.start, block.end);
84
+ if (fits(text, extra))
85
+ return [
86
+ { start: block.start, end: block.end, type: block.type, extra },
87
+ ];
88
+ if (block.children.length) {
89
+ const pieces = [];
90
+ let start = block.start;
91
+ for (let i = 0; i < block.children.length; i++) {
92
+ const child = block.children[i];
93
+ const end = i + 1 < block.children.length
94
+ ? block.children[i + 1].start
95
+ : block.end;
96
+ let label = extra;
97
+ if (block.type === 'table')
98
+ label = `Row: ${i}\nTable headers: ${source.slice(block.children[0].start, block.children[0].end)}\n${extra}`;
99
+ if (block.type === 'tableRow')
100
+ label = `Column: ${i + 1}\n${extra}`;
101
+ if (block.type === 'listItem')
102
+ label += `\nList item: ${text.split('\n')[0]}`;
103
+ pieces.push(...split({ ...child, start, end }, label));
104
+ start = end;
105
+ }
106
+ return pieces;
107
+ }
108
+ const pieces = [];
109
+ let start = block.start;
110
+ const label = block.type === 'code'
111
+ ? `${extra}\nCode: ${block.language ?? ''}`
112
+ : extra;
113
+ while (start < block.end) {
114
+ const rest = source.slice(start, block.end);
115
+ let n = fittingPrefix(rest, (t) => fits(t, label));
116
+ if (!n)
117
+ throw new Error(`Cannot fit source text at ${file.path}:${lineAt(start)}`);
118
+ if (n < rest.length) {
119
+ const prefix = rest.slice(0, n);
120
+ const boundary = block.type === 'code'
121
+ ? prefix.lastIndexOf('\n') + 1
122
+ : [...prefix.matchAll(/[.!?](?:\s+|$)/g)].at(-1)?.index;
123
+ const preferred = typeof boundary === 'number' && boundary > n / 2
124
+ ? boundary
125
+ : prefix.search(/\s+\S*$/);
126
+ if (preferred > n / 2 && fits(rest.slice(0, preferred), label))
127
+ n = preferred;
128
+ }
129
+ pieces.push({ start, end: start + n, type: block.type, extra: label });
130
+ start += n;
131
+ }
132
+ return pieces;
133
+ };
134
+ const pieces = (own.get(section.id) ?? []).flatMap((block) => split(block));
135
+ if (!pieces.length) {
136
+ const start = lineStarts[section.startLine - 1] ?? 0;
137
+ const end = source.indexOf('\n', start);
138
+ pieces.push(...split({
139
+ type: 'heading',
140
+ start,
141
+ end: end < 0 ? source.length : end,
142
+ startLine: section.startLine,
143
+ endLine: section.startLine,
144
+ children: [],
145
+ }));
146
+ }
147
+ let pending;
148
+ const emit = (piece) => {
149
+ const text = source.slice(piece.start, piece.end);
150
+ if (!text.trim())
151
+ return;
152
+ const input = inputFor(text, piece.extra);
153
+ if (embedder.countTokens(input) > embedder.maxInputTokens)
154
+ throw new Error('Chunk exceeds embedding limit');
155
+ const inputHash = digest(`${embeddingFingerprint(embedder)}\0${input}`);
156
+ result.push({
157
+ id: `${section.id}:${ordinal}`,
158
+ sectionId: section.id,
159
+ ordinal: ordinal++,
160
+ type: piece.type,
161
+ spans: [
162
+ {
163
+ start: piece.start,
164
+ end: piece.end,
165
+ startLine: lineAt(piece.start),
166
+ endLine: lineAt(Math.max(piece.start, piece.end - 1)),
167
+ },
168
+ ],
169
+ text,
170
+ input,
171
+ inputHash,
172
+ heading: section.heading,
173
+ path,
174
+ });
175
+ };
176
+ for (const piece of pieces) {
177
+ if (pending &&
178
+ !pending.extra &&
179
+ !piece.extra &&
180
+ !source.slice(pending.end, piece.start).trim() &&
181
+ fits(source.slice(pending.start, piece.end)))
182
+ pending = {
183
+ ...pending,
184
+ end: piece.end,
185
+ type: pending.type === piece.type ? piece.type : 'mixed',
186
+ };
187
+ else {
188
+ if (pending)
189
+ emit(pending);
190
+ pending = piece;
191
+ }
192
+ }
193
+ if (pending)
194
+ emit(pending);
195
+ }
196
+ return result;
197
+ }
@@ -1,16 +1,28 @@
1
- import { type Client } from '@libsql/client';
2
- export declare function openDb(latDir: string): Client;
3
- /** Create the `meta` key/value table if absent. */
4
- export declare function ensureMeta(db: Client): Promise<void>;
5
- /**
6
- * The embedding backend this index was built with, e.g. `local:minilm-l6-v2:384`
7
- * or `openai:1536`. This record is *authoritative*: it governs which backend
8
- * `lat search` uses. Null when the index has never been built.
9
- */
10
- export declare function getStoredModel(db: Client): Promise<string | null>;
11
- export declare function setStoredModel(db: Client, value: string): Promise<void>;
12
- /** Create the `sections` table (fixed-width vector column) + index if absent. */
13
- export declare function ensureSectionsSchema(db: Client, dimensions: number): Promise<void>;
14
- /** Drop the vector table (used by `lat reindex` before a full rebuild). */
15
- export declare function dropSections(db: Client): Promise<void>;
16
- export declare function closeDb(db: Client): Promise<void>;
1
+ export declare const INDEX_FILE = "search.db";
2
+ export declare const CREATE_PASSAGE_FTS = "CREATE INDEX IF NOT EXISTS chunks_fts ON lexical_chunks USING fts(body,heading,path) WITH (tokenizer='whitespace',weights='body=1.0,heading=2.0,path=0.5')";
3
+ export declare function hasIndex(cacheDir: string): boolean;
4
+ /** Small SQL adapter; callers never depend on a libSQL connection. */
5
+ export declare class SearchDb {
6
+ readonly path: string;
7
+ private readonly published;
8
+ private connection;
9
+ private release;
10
+ constructor(path: string, published?: boolean);
11
+ private get;
12
+ private connect;
13
+ execute(statement: string | {
14
+ sql: string;
15
+ args?: any[];
16
+ }): Promise<{
17
+ rows: any[];
18
+ }>;
19
+ close(): Promise<void>;
20
+ checkpoint(): Promise<void>;
21
+ }
22
+ export declare function openDb(latDir: string, requestedCacheDir?: string, published?: boolean): SearchDb;
23
+ export declare function ensureMeta(db: SearchDb): Promise<void>;
24
+ export declare function getStoredModel(db: SearchDb): Promise<string | null>;
25
+ export declare function setStoredModel(db: SearchDb, value: string): Promise<void>;
26
+ export declare function ensureSectionsSchema(db: SearchDb, _dimensions: number): Promise<void>;
27
+ export declare function dropSections(db: SearchDb): Promise<void>;
28
+ export declare function closeDb(db: SearchDb): Promise<void>;
@@ -1,54 +1,120 @@
1
- import { createClient } from '@libsql/client';
2
- import { mkdirSync } from 'node:fs';
3
- import { join } from 'node:path';
4
- export function openDb(latDir) {
5
- const cacheDir = join(latDir, '.cache');
1
+ import { connect } from '@tursodatabase/database';
2
+ import { existsSync, mkdirSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { acquireSearchAccess } from './lock.js';
5
+ export const INDEX_FILE = 'search.db';
6
+ export const CREATE_PASSAGE_FTS = "CREATE INDEX IF NOT EXISTS chunks_fts ON lexical_chunks USING fts(body,heading,path) WITH (tokenizer='whitespace',weights='body=1.0,heading=2.0,path=0.5')";
7
+ export function hasIndex(cacheDir) {
8
+ return existsSync(join(cacheDir, INDEX_FILE));
9
+ }
10
+ /** Small SQL adapter; callers never depend on a libSQL connection. */
11
+ export class SearchDb {
12
+ path;
13
+ published;
14
+ connection;
15
+ release;
16
+ constructor(path, published = false) {
17
+ this.path = path;
18
+ this.published = published;
19
+ }
20
+ get() {
21
+ return (this.connection ??= this.connect());
22
+ }
23
+ async connect() {
24
+ // Turso 0.7.2 FTS needs writable connections and exclusive process access.
25
+ if (this.published)
26
+ this.release = await acquireSearchAccess(dirname(this.path), 'exclusive');
27
+ try {
28
+ return await connect(this.path, {
29
+ experimental: ['index_method'],
30
+ timeout: 10000,
31
+ });
32
+ }
33
+ catch (error) {
34
+ await this.release?.();
35
+ this.release = undefined;
36
+ throw error;
37
+ }
38
+ }
39
+ async execute(statement) {
40
+ const { sql, args = [] } = typeof statement === 'string' ? { sql: statement } : statement;
41
+ const db = await this.get();
42
+ const prepared = await db.prepare(sql);
43
+ try {
44
+ return { rows: await prepared.all(...args) };
45
+ }
46
+ finally {
47
+ prepared.close();
48
+ }
49
+ }
50
+ async close() {
51
+ try {
52
+ if (this.connection) {
53
+ const db = await this.connection;
54
+ try {
55
+ // Leave a self-contained file for incremental copies and publication.
56
+ if (this.published)
57
+ await this.checkpoint();
58
+ }
59
+ finally {
60
+ await db.close();
61
+ }
62
+ }
63
+ }
64
+ finally {
65
+ this.connection = undefined;
66
+ const release = this.release;
67
+ this.release = undefined;
68
+ await release?.();
69
+ }
70
+ }
71
+ async checkpoint() {
72
+ await this.execute('PRAGMA wal_checkpoint(TRUNCATE)');
73
+ }
74
+ }
75
+ export function openDb(latDir, requestedCacheDir, published = false) {
76
+ const cacheDir = requestedCacheDir ?? join(latDir, '.cache');
6
77
  mkdirSync(cacheDir, { recursive: true });
7
- const client = createClient({
8
- url: `file:${join(cacheDir, 'vectors.db')}`,
9
- });
10
- return client;
78
+ return new SearchDb(join(cacheDir, INDEX_FILE), published);
11
79
  }
12
- /** Create the `meta` key/value table if absent. */
13
80
  export async function ensureMeta(db) {
14
- await db.execute(`CREATE TABLE IF NOT EXISTS meta (
15
- key TEXT PRIMARY KEY,
16
- value TEXT NOT NULL
17
- )`);
18
- }
19
- /**
20
- * The embedding backend this index was built with, e.g. `local:minilm-l6-v2:384`
21
- * or `openai:1536`. This record is *authoritative*: it governs which backend
22
- * `lat search` uses. Null when the index has never been built.
23
- */
81
+ await db.execute('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)');
82
+ }
24
83
  export async function getStoredModel(db) {
25
- const rows = await db.execute("SELECT value FROM meta WHERE key = 'embedding_model'");
84
+ const rows = await db.execute("SELECT value FROM meta WHERE key='embedding_model'");
26
85
  return rows.rows[0]?.value ?? null;
27
86
  }
28
87
  export async function setStoredModel(db, value) {
29
88
  await db.execute({
30
- sql: "INSERT OR REPLACE INTO meta (key, value) VALUES ('embedding_model', ?)",
31
- args: [value],
89
+ sql: 'INSERT OR REPLACE INTO meta VALUES (?,?)',
90
+ args: ['embedding_model', value],
32
91
  });
33
92
  }
34
- /** Create the `sections` table (fixed-width vector column) + index if absent. */
35
- export async function ensureSectionsSchema(db, dimensions) {
36
- await db.execute(`CREATE TABLE IF NOT EXISTS sections (
37
- id TEXT PRIMARY KEY,
38
- file TEXT NOT NULL,
39
- heading TEXT NOT NULL,
40
- content TEXT NOT NULL,
41
- content_hash TEXT NOT NULL,
42
- embedding F32_BLOB(${dimensions}),
43
- updated_at INTEGER NOT NULL
44
- )`);
45
- await db.execute(`CREATE INDEX IF NOT EXISTS sections_vec_idx
46
- ON sections (libsql_vector_idx(embedding))`);
47
- }
48
- /** Drop the vector table (used by `lat reindex` before a full rebuild). */
93
+ export async function ensureSectionsSchema(db, _dimensions) {
94
+ for (const sql of [
95
+ 'CREATE TABLE IF NOT EXISTS sections (id TEXT PRIMARY KEY, file TEXT NOT NULL, heading TEXT NOT NULL, content TEXT NOT NULL, content_hash TEXT NOT NULL, parent_id TEXT, start_line INTEGER, end_line INTEGER)',
96
+ 'CREATE TABLE IF NOT EXISTS embeddings (hash TEXT PRIMARY KEY, embedding BLOB NOT NULL)',
97
+ 'CREATE TABLE IF NOT EXISTS chunks (id INTEGER PRIMARY KEY, source_id TEXT UNIQUE NOT NULL, section_id TEXT NOT NULL, ordinal INTEGER NOT NULL, type TEXT NOT NULL, spans TEXT NOT NULL, body TEXT NOT NULL, heading TEXT NOT NULL, path TEXT NOT NULL, input_hash TEXT NOT NULL)',
98
+ 'CREATE INDEX IF NOT EXISTS chunks_section ON chunks(section_id)',
99
+ 'CREATE TABLE IF NOT EXISTS lexical_chunks (id INTEGER PRIMARY KEY, body TEXT NOT NULL, heading TEXT NOT NULL, path TEXT NOT NULL)',
100
+ 'CREATE TABLE IF NOT EXISTS identifiers (token TEXT NOT NULL, chunk_id INTEGER NOT NULL, PRIMARY KEY(token,chunk_id))',
101
+ ])
102
+ await db.execute(sql);
103
+ const oldIndex = (await db.execute("SELECT tbl_name FROM sqlite_master WHERE name='chunks_fts'")).rows[0];
104
+ if (oldIndex?.tbl_name === 'chunks')
105
+ await db.execute('DROP INDEX chunks_fts');
106
+ await db.execute(CREATE_PASSAGE_FTS);
107
+ }
49
108
  export async function dropSections(db) {
50
- await db.execute('DROP TABLE IF EXISTS sections');
109
+ for (const name of [
110
+ 'identifiers',
111
+ 'lexical_chunks',
112
+ 'chunks',
113
+ 'embeddings',
114
+ 'sections',
115
+ ])
116
+ await db.execute(`DROP TABLE IF EXISTS ${name}`);
51
117
  }
52
118
  export async function closeDb(db) {
53
- db.close();
119
+ await db.close();
54
120
  }
@@ -1,6 +1,7 @@
1
1
  import { EmbeddingAuthError, type Embedder } from '@lat.md/embed';
2
2
  export type { Embedder };
3
3
  export { EmbeddingAuthError };
4
+ export type CreateSearchEngine = (key?: string) => Promise<Embedder>;
4
5
  /** `meta.embedding_model` value for an embedder, e.g. `local:minilm-l6-v2:384`. */
5
6
  export declare function modelKey(embedder: Embedder): string;
6
7
  /** Thrown when the stored index can't be served by the current environment and
@@ -22,4 +23,4 @@ export declare function localEmbedder(): Promise<Embedder>;
22
23
  * regenerable `.cache` was wiped) the durable per-repo preference wins over the
23
24
  * env, so a repo switched to local stays local across cache loss.
24
25
  */
25
- export declare function embedderForIndex(storedModel: string | null, latDir: string): Promise<Embedder>;
26
+ export declare function embedderForIndex(storedModel: string | null, latDir: string, createSearchEngine?: CreateSearchEngine): Promise<Embedder>;