@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.
- package/README.md +31 -2
- package/dist/src/cli/agent-invocation.d.ts +6 -0
- package/dist/src/cli/agent-invocation.js +23 -0
- package/dist/src/cli/checklist-menu.d.ts +2 -1
- package/dist/src/cli/checklist-menu.js +3 -2
- package/dist/src/cli/comment-guard.d.ts +14 -0
- package/dist/src/cli/comment-guard.js +10 -33
- package/dist/src/cli/comment-reminder.d.ts +65 -6
- package/dist/src/cli/comment-reminder.js +164 -28
- package/dist/src/cli/fork-instructions.d.ts +20 -0
- package/dist/src/cli/fork-instructions.js +184 -0
- package/dist/src/cli/fork-scaffold.d.ts +106 -0
- package/dist/src/cli/fork-scaffold.js +490 -0
- package/dist/src/cli/graph.d.ts +1 -1
- package/dist/src/cli/hook.d.ts +26 -0
- package/dist/src/cli/hook.js +118 -46
- package/dist/src/cli/index.js +166 -64
- package/dist/src/cli/init-preferences.d.ts +4 -0
- package/dist/src/cli/init-preferences.js +36 -0
- package/dist/src/cli/init.d.ts +2 -1
- package/dist/src/cli/init.js +107 -50
- package/dist/src/cli/reindex.d.ts +1 -1
- package/dist/src/cli/reindex.js +7 -10
- package/dist/src/cli/search.d.ts +14 -4
- package/dist/src/cli/search.js +116 -100
- package/dist/src/cli/ui-build-server.d.ts +12 -0
- package/dist/src/cli/ui-build-server.js +26 -0
- package/dist/src/cli/ui-build.d.ts +4 -0
- package/dist/src/cli/ui-build.js +13 -0
- package/dist/src/cli/ui.d.ts +1 -1
- package/dist/src/cli/ui.js +18 -2
- package/dist/src/fork/antigravity-hook.d.ts +47 -0
- package/dist/src/fork/antigravity-hook.js +424 -0
- package/dist/src/fork/antigravity-init.d.ts +17 -0
- package/dist/src/fork/antigravity-init.js +124 -0
- package/dist/src/fork/upstream-drift-cli.js +2 -0
- package/dist/src/fork/upstream-drift.d.ts +26 -0
- package/dist/src/fork/upstream-drift.js +185 -0
- package/dist/src/fork/upstream-guard-cli.d.ts +1 -0
- package/dist/src/fork/upstream-guard-cli.js +2 -0
- package/dist/src/fork/upstream-guard.d.ts +72 -0
- package/dist/src/fork/upstream-guard.js +445 -0
- package/dist/src/graph-export.d.ts +2 -0
- package/dist/src/graph-export.js +38 -19
- package/dist/src/knowledge/claude-memory.d.ts +1 -0
- package/dist/src/knowledge/claude-memory.js +33 -4
- package/dist/src/knowledge/index.js +2 -2
- package/dist/src/mcp/server.js +34 -18
- package/dist/src/search/cache.d.ts +3 -0
- package/dist/src/search/cache.js +104 -0
- package/dist/src/search/chunks.d.ts +23 -0
- package/dist/src/search/chunks.js +197 -0
- package/dist/src/search/db.d.ts +28 -16
- package/dist/src/search/db.js +106 -40
- package/dist/src/search/embedder.d.ts +2 -1
- package/dist/src/search/embedder.js +7 -6
- package/dist/src/search/index.d.ts +6 -2
- package/dist/src/search/index.js +176 -53
- package/dist/src/search/lexical.d.ts +6 -0
- package/dist/src/search/lexical.js +36 -0
- package/dist/src/search/lock.d.ts +5 -0
- package/dist/src/search/lock.js +45 -0
- package/dist/src/search/query.d.ts +26 -0
- package/dist/src/search/query.js +103 -0
- package/dist/src/search/search.d.ts +17 -7
- package/dist/src/search/search.js +164 -14
- package/dist/src/search/types.d.ts +15 -0
- package/dist/src/search/types.js +1 -0
- package/dist/src/view/client/assets/GraphView-Dij8mAA_.js +456 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/src/view/client/assets/MarkdownEditor-88Wbt0M1.js +28 -0
- package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
- package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
- package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-y0DlYa8E.js +1 -0
- package/dist/src/view/client/assets/arc-FlMu8dnO.js +1 -0
- package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-DA_uWZW1.js +36 -0
- package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-BHQ5LU85.js +129 -0
- package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-BRucKCt2.js +38 -0
- package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
- package/dist/src/view/client/assets/chunk-2Q5K7J3B-BJPcFivt.js +1 -0
- package/dist/src/view/client/assets/chunk-5VM5RSS4-v2q99bGz.js +15 -0
- package/dist/src/view/client/assets/chunk-F27PBJKO-CcHOuJCs.js +1 -0
- package/dist/src/view/client/assets/chunk-IMKFNOWR-DNxYuJNq.js +231 -0
- package/dist/src/view/client/assets/chunk-JWPE2WC7-C0eHKvLW.js +1 -0
- package/dist/src/view/client/assets/chunk-POPQ4Y6H-57CWp2Ve.js +1 -0
- package/dist/src/view/client/assets/chunk-SVP7TREG-BqcoxIJw.js +88 -0
- package/dist/src/view/client/assets/chunk-TICWLB2K-DRUJR5zH.js +206 -0
- package/dist/src/view/client/assets/chunk-XXDRQBXY-Dez0oRoM.js +1 -0
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-BHtud6Hg.js +1 -0
- package/dist/src/view/client/assets/cynefin-OW5HDTMX-BjBW8VGk.js +166 -0
- package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-DwGuD7oF.js +62 -0
- package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
- package/dist/src/view/client/assets/dagre-GXQ25YYZ-C5zSlGK9.js +4 -0
- package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/src/view/client/assets/diagram-S7CK7UJ4-C_NhA3bj.js +30 -0
- package/dist/src/view/client/assets/diagram-UQ7AKVKN-az7QPYNb.js +41 -0
- package/dist/src/view/client/assets/diagram-VSXAHHWV-BRvDuM8_.js +3 -0
- package/dist/src/view/client/assets/diagram-VX7I27RA-BWLgF6S-.js +24 -0
- package/dist/src/view/client/assets/diagram-Z3DM3KII-DV3d6mL5.js +24 -0
- package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-yUXrEAvK.js +1 -0
- package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-D35FN1Pt.js +99 -0
- package/dist/src/view/client/assets/flowDiagram-HODETNUW-BciZqsjT.js +168 -0
- package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-BysPGgXS.js +292 -0
- package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js +106 -0
- package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
- package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
- package/dist/src/view/client/assets/index-DG0Ez15D.css +1 -0
- package/dist/src/view/client/assets/infoDiagram-27XIBGKW-D3HZrDRb.js +2 -0
- package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-BXyVIXTU.js +70 -0
- package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-D4-1NxVU.js +139 -0
- package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-4Gu_5yBA.js +89 -0
- package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/src/view/client/assets/layout-Jf1K3TMM.js +1 -0
- package/dist/src/view/client/assets/linear-DWfwzUT_.js +1 -0
- package/dist/src/view/client/assets/logo-RR_KBOAT.svg +149 -0
- package/dist/src/view/client/assets/maplibre-gl-CDX6Zuow.js +800 -0
- package/dist/src/view/client/assets/mermaid.core-DMx_DAl8.js +310 -0
- package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-8pxY_RWi.js +96 -0
- package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-DNAw_O5t.js +1 -0
- package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-uuvRCDkC.js +39 -0
- package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC-BER2O4Aq.js +7 -0
- package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-CxEsJ_0n.js +1 -0
- package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-yS9rspca.js +84 -0
- package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-Bqt70a2j.js +40 -0
- package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-BvOOEJNr.js +162 -0
- package/dist/src/view/client/assets/sizeCapture-INFHLROL-CvO_Pjjo.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-D77RDMKH-KLmVOZkq.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
- package/dist/src/view/client/assets/swimlanes-42K2YHIH-DC1r4_sq.js +1 -0
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
- package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
- package/dist/src/view/client/assets/timeline-definition-24CTP7MA-ChXLOuBL.js +120 -0
- package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-D9_h25-Y.js +34 -0
- package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-CsQJGGW0.js +78 -0
- package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-DGMuPMlm.js +7 -0
- package/dist/src/view/client/index.html +2 -2
- package/dist/src/view/client-shell.d.ts +2 -0
- package/dist/src/view/client-shell.js +5 -0
- package/dist/src/view/diagnostics.d.ts +3 -2
- package/dist/src/view/diagnostics.js +49 -58
- package/dist/src/view/document-edit.d.ts +8 -0
- package/dist/src/view/document-edit.js +25 -0
- package/dist/src/view/document-route.d.ts +14 -0
- package/dist/src/view/document-route.js +126 -0
- package/dist/src/view/document-tree.d.ts +18 -0
- package/dist/src/view/document-tree.js +139 -0
- package/dist/src/view/external-document-tree.d.ts +3 -0
- package/dist/src/view/external-document-tree.js +674 -0
- package/dist/src/view/git-diff.js +205 -1
- package/dist/src/view/git.js +1 -1
- package/dist/src/view/graph.d.ts +7 -0
- package/dist/src/view/graph.js +267 -0
- package/dist/src/view/highlight.d.ts +10 -2
- package/dist/src/view/highlight.js +4547 -1363
- package/dist/src/view/markdown.d.ts +8 -3
- package/dist/src/view/markdown.js +308 -41
- package/dist/src/view/preindexed-search.d.ts +15 -0
- package/dist/src/view/preindexed-search.js +25 -0
- package/dist/src/view/protocol.d.ts +95 -6
- package/dist/src/view/protocol.js +1 -1
- package/dist/src/view/publication.d.ts +2 -0
- package/dist/src/view/publication.js +78 -0
- package/dist/src/view/references.d.ts +13 -26
- package/dist/src/view/references.js +150 -119
- package/dist/src/view/repository.d.ts +18 -5
- package/dist/src/view/repository.js +269 -27
- package/dist/src/view/request-security.d.ts +5 -0
- package/dist/src/view/request-security.js +46 -0
- package/dist/src/view/search-result.d.ts +4 -0
- package/dist/src/view/search-result.js +25 -0
- package/dist/src/view/search.d.ts +7 -2
- package/dist/src/view/search.js +23 -33
- package/dist/src/view/server-build.d.ts +21 -0
- package/dist/src/view/server-build.js +145 -0
- package/dist/src/view/server-deployment.d.ts +31 -0
- package/dist/src/view/server-deployment.js +94 -0
- package/dist/src/view/server-index-worker.d.ts +6 -0
- package/dist/src/view/server-index-worker.js +14 -0
- package/dist/src/view/server.d.ts +14 -2
- package/dist/src/view/server.js +254 -51
- package/dist/src/view/source-target.d.ts +10 -0
- package/dist/src/view/source-target.js +43 -0
- package/dist/src/view/static-build.d.ts +32 -0
- package/dist/src/view/static-build.js +741 -0
- package/dist/src/view/static-protocol.d.ts +47 -0
- package/dist/src/view/static-protocol.js +15 -0
- package/dist/src/view/store.d.ts +26 -3
- package/dist/src/view/store.js +325 -44
- package/dist/src/view/table-of-contents.d.ts +9 -0
- package/dist/src/view/table-of-contents.js +83 -0
- package/dist/src/view/vercel-build.d.ts +24 -0
- package/dist/src/view/vercel-build.js +140 -0
- package/dist/src/view/vercel-server-build.d.ts +10 -0
- package/dist/src/view/vercel-server-build.js +61 -0
- package/dist/vendor/lat.md-server/cli.d.ts +2 -0
- package/dist/vendor/lat.md-server/cli.js +12 -0
- package/dist/vendor/lat.md-server/index.d.ts +38 -0
- package/dist/vendor/lat.md-server/index.js +128 -0
- package/package.json +72 -25
- package/plugins/lat-md/README.md +61 -0
- package/plugins/lat-md/hooks.json +38 -0
- package/plugins/lat-md/plugin.json +9 -0
- package/plugins/lat-md/rules/AGENTS.md +118 -0
- package/plugins/lat-md/skills/lat-md/SKILL.md +178 -0
- package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +182 -0
- package/templates/AGENTS.md +19 -18
- package/templates/cursor-rules.md +14 -5
- package/templates/fork/conventions.md +173 -0
- package/templates/opencode-plugin.ts +9 -9
- package/templates/pi-extension.ts +11 -11
- package/templates/skill/SKILL.md +28 -17
- package/dist/src/cli/check-frontmatter.d.ts +0 -12
- package/dist/src/cli/check-frontmatter.js +0 -44
- package/dist/src/cli/check-mode.d.ts +0 -6
- package/dist/src/cli/check-mode.js +0 -303
- package/dist/src/cli/check-status.d.ts +0 -74
- package/dist/src/cli/check-status.js +0 -217
- package/dist/src/cli/check.d.ts +0 -45
- package/dist/src/cli/check.js +0 -777
- package/dist/src/cli/context.d.ts +0 -11
- package/dist/src/cli/context.js +0 -58
- package/dist/src/cli/expand.d.ts +0 -8
- package/dist/src/cli/expand.js +0 -94
- package/dist/src/cli/gen-index.d.ts +0 -45
- package/dist/src/cli/gen-index.js +0 -235
- package/dist/src/cli/link-scheme.d.ts +0 -54
- package/dist/src/cli/link-scheme.js +0 -101
- package/dist/src/cli/locate.d.ts +0 -2
- package/dist/src/cli/locate.js +0 -17
- package/dist/src/cli/refs.d.ts +0 -22
- package/dist/src/cli/refs.js +0 -229
- package/dist/src/cli/section.d.ts +0 -43
- package/dist/src/cli/section.js +0 -252
- package/dist/src/cli/select-menu.d.ts +0 -13
- package/dist/src/cli/select-menu.js +0 -100
- package/dist/src/code-refs.d.ts +0 -17
- package/dist/src/code-refs.js +0 -277
- package/dist/src/config.d.ts +0 -29
- package/dist/src/config.js +0 -83
- package/dist/src/context.d.ts +0 -23
- package/dist/src/context.js +0 -11
- package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
- package/dist/src/extensions/wiki-link/index.d.ts +0 -4
- package/dist/src/extensions/wiki-link/index.js +0 -3
- package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
- package/dist/src/extensions/wiki-link/syntax.js +0 -121
- package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
- package/dist/src/extensions/wiki-link/types.d.ts +0 -34
- package/dist/src/format.d.ts +0 -8
- package/dist/src/format.js +0 -43
- package/dist/src/init-version.d.ts +0 -10
- package/dist/src/init-version.js +0 -49
- package/dist/src/lattice.d.ts +0 -108
- package/dist/src/lattice.js +0 -816
- package/dist/src/parser.d.ts +0 -3
- package/dist/src/parser.js +0 -18
- package/dist/src/source-parser.d.ts +0 -27
- package/dist/src/source-parser.js +0 -916
- package/dist/src/untrusted.d.ts +0 -24
- package/dist/src/untrusted.js +0 -97
- package/dist/src/view/client/assets/index-B0n0u03y.css +0 -1
- package/dist/src/view/client/assets/index-xm2_px4q.js +0 -23
- package/dist/src/walk.d.ts +0 -18
- package/dist/src/walk.js +0 -27
- /package/dist/src/{extensions/wiki-link/types.js → fork/upstream-drift-cli.d.ts} +0 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
import { createPublicationPolicy } from './publication.js';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { cp, lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile, } from 'node:fs/promises';
|
|
4
|
+
import { dirname, join, parse, relative, resolve, sep } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { isDocumentPath } from '@plebeiantech/lat.md-core/document-formats';
|
|
7
|
+
import { DEFAULT_VIEW_LOGO_TEXT } from './protocol.js';
|
|
8
|
+
import { documentTreeUrls, rewriteDocumentTreeUrls } from './document-tree.js';
|
|
9
|
+
import { VIEW_STATIC_BOOTSTRAP_ID, viewStaticDocumentRequest, viewStaticSourceKey, } from './static-protocol.js';
|
|
10
|
+
import { createViewStore } from './store.js';
|
|
11
|
+
import { rewriteClientAssetUrls } from './client-shell.js';
|
|
12
|
+
import { documentResourcePath, documentPath, documentUrl, rawDocumentPath, validateDocumentRoutes, } from './document-route.js';
|
|
13
|
+
const defaultClientDir = fileURLToPath(new URL('./client/', import.meta.url));
|
|
14
|
+
const VIEW_BUILD_MOVE_MAX_RETRIES = 10;
|
|
15
|
+
const VIEW_BUILD_MOVE_RETRY_DELAY_MS = 150;
|
|
16
|
+
function isInside(parent, child) {
|
|
17
|
+
const rel = relative(parent, child);
|
|
18
|
+
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`));
|
|
19
|
+
}
|
|
20
|
+
export function normalizeStaticViewBasePath(value) {
|
|
21
|
+
const path = value.startsWith('/') ? value : `/${value}`;
|
|
22
|
+
const parsed = new URL(path, 'http://lat.local');
|
|
23
|
+
if (parsed.origin !== 'http://lat.local' ||
|
|
24
|
+
parsed.search ||
|
|
25
|
+
parsed.hash ||
|
|
26
|
+
value.includes('://')) {
|
|
27
|
+
throw new Error('Static UI base path must be an absolute URL path');
|
|
28
|
+
}
|
|
29
|
+
return parsed.pathname.endsWith('/')
|
|
30
|
+
? parsed.pathname
|
|
31
|
+
: `${parsed.pathname}/`;
|
|
32
|
+
}
|
|
33
|
+
function staticViewPayloadDir(outputDir, basePath) {
|
|
34
|
+
const segments = basePath
|
|
35
|
+
.slice(1, -1)
|
|
36
|
+
.split('/')
|
|
37
|
+
.filter(Boolean)
|
|
38
|
+
.map((segment) => {
|
|
39
|
+
const decoded = decodeURIComponent(segment);
|
|
40
|
+
if (decoded === '.' ||
|
|
41
|
+
decoded === '..' ||
|
|
42
|
+
decoded.includes('/') ||
|
|
43
|
+
decoded.includes('\\')) {
|
|
44
|
+
throw new Error('Static UI base path contains an unsafe segment');
|
|
45
|
+
}
|
|
46
|
+
return decoded;
|
|
47
|
+
});
|
|
48
|
+
return join(outputDir, ...segments);
|
|
49
|
+
}
|
|
50
|
+
function decodeHtmlUrlAttribute(value) {
|
|
51
|
+
return value.replace(/&(amp|#38|#x26);/gi, '&');
|
|
52
|
+
}
|
|
53
|
+
/** Convert a live view route to its physical static-directory URL. */
|
|
54
|
+
export function staticViewUrl(value, basePath, entryPath) {
|
|
55
|
+
if (!value || !value.startsWith('/') || value.startsWith('//'))
|
|
56
|
+
return value;
|
|
57
|
+
let url;
|
|
58
|
+
try {
|
|
59
|
+
url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
if (url.origin !== 'http://lat.local')
|
|
65
|
+
return value;
|
|
66
|
+
const markdownPath = documentPath(url.pathname.replace(/\/$/, ''));
|
|
67
|
+
if (markdownPath || rawDocumentPath(url.pathname)) {
|
|
68
|
+
const route = url.pathname.slice(1).replace(/\/+$/, '');
|
|
69
|
+
const suffix = `${url.search}${url.hash}`;
|
|
70
|
+
if (entryPath && markdownPath === entryPath) {
|
|
71
|
+
return `${basePath}${suffix}`;
|
|
72
|
+
}
|
|
73
|
+
return `${basePath}${route}${suffix}`;
|
|
74
|
+
}
|
|
75
|
+
if (url.pathname.startsWith('/resources/')) {
|
|
76
|
+
const route = url.pathname.slice(1);
|
|
77
|
+
return `${basePath}${route}${url.search}${url.hash}`;
|
|
78
|
+
}
|
|
79
|
+
for (const prefix of ['/code/', '/external/']) {
|
|
80
|
+
if (!url.pathname.startsWith(prefix))
|
|
81
|
+
continue;
|
|
82
|
+
const route = url.pathname.slice(1).replace(/\/+$/, '');
|
|
83
|
+
return `${basePath}${route}/${url.search}${url.hash}`;
|
|
84
|
+
}
|
|
85
|
+
if (url.pathname === '/graph') {
|
|
86
|
+
return `${basePath}graph/${url.search}${url.hash}`;
|
|
87
|
+
}
|
|
88
|
+
if (url.pathname === '/' || url.pathname === '/search') {
|
|
89
|
+
return `${basePath}${url.pathname.slice(1)}${url.search}${url.hash}`;
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
function documentPathFromUrl(value) {
|
|
94
|
+
return documentPath(value.pathname) ?? rawDocumentPath(value.pathname);
|
|
95
|
+
}
|
|
96
|
+
function rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths) {
|
|
97
|
+
const direct = staticViewUrl(value, basePath, entryPath);
|
|
98
|
+
if (direct !== value || !sourcePath || value.startsWith('#'))
|
|
99
|
+
return direct;
|
|
100
|
+
let resolved;
|
|
101
|
+
try {
|
|
102
|
+
const externalAt = sourcePath.indexOf(':');
|
|
103
|
+
const currentRoute = externalAt > 0 && !documentPaths.has(sourcePath)
|
|
104
|
+
? `/external/${encodeURIComponent(sourcePath.slice(0, externalAt))}/${sourcePath
|
|
105
|
+
.slice(externalAt + 1)
|
|
106
|
+
.split('/')
|
|
107
|
+
.map(encodeURIComponent)
|
|
108
|
+
.join('/')}`
|
|
109
|
+
: documentUrl(sourcePath);
|
|
110
|
+
resolved = new URL(decodeHtmlUrlAttribute(value), `http://lat.local${currentRoute}`);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
const documentPath = documentPathFromUrl(resolved);
|
|
116
|
+
if (resolved.pathname.startsWith('/external/')) {
|
|
117
|
+
return staticViewUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`, basePath, entryPath);
|
|
118
|
+
}
|
|
119
|
+
if (resolved.origin !== 'http://lat.local' ||
|
|
120
|
+
!documentPath ||
|
|
121
|
+
!documentPaths.has(documentPath)) {
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
return staticViewUrl(`${documentUrl(documentPath)}${resolved.search}${resolved.hash}`, basePath, entryPath);
|
|
125
|
+
}
|
|
126
|
+
function rewriteDocumentLinks(tree, basePath, entryPath, sourcePath, documentPaths) {
|
|
127
|
+
return rewriteDocumentTreeUrls(tree, (value) => rewriteHtmlLink(value, basePath, entryPath, sourcePath, documentPaths));
|
|
128
|
+
}
|
|
129
|
+
function rewriteMarkdownReference(reference, basePath, entryPath, sourcePath, documentPaths) {
|
|
130
|
+
return {
|
|
131
|
+
...reference,
|
|
132
|
+
paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sourcePath, documentPaths),
|
|
133
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
|
|
137
|
+
return reference.kind === 'markdown'
|
|
138
|
+
? rewriteMarkdownReference(reference, basePath, entryPath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
|
|
139
|
+
: {
|
|
140
|
+
...reference,
|
|
141
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function rewriteDocument(document, basePath, entryPath, sectionPaths, documentPaths) {
|
|
145
|
+
return {
|
|
146
|
+
...document,
|
|
147
|
+
tree: rewriteDocumentLinks(document.tree, basePath, entryPath, document.path, documentPaths),
|
|
148
|
+
gitTree: null,
|
|
149
|
+
backReferences: document.backReferences.map((section) => ({
|
|
150
|
+
...section,
|
|
151
|
+
references: section.references.map((reference) => rewriteBackReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
|
|
152
|
+
})),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths) {
|
|
156
|
+
const sectionPath = reference.sectionId.split('#', 1)[0];
|
|
157
|
+
return {
|
|
158
|
+
...reference,
|
|
159
|
+
paragraphTree: rewriteDocumentLinks(reference.paragraphTree, basePath, entryPath, sectionPaths.get(sectionPath) ?? null, documentPaths),
|
|
160
|
+
url: staticViewUrl(reference.url, basePath, entryPath),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function rewriteSource(source, basePath, entryPath, sectionPaths, documentPaths) {
|
|
164
|
+
return {
|
|
165
|
+
...source,
|
|
166
|
+
context: source.context
|
|
167
|
+
? rewriteSourceReference(source.context, basePath, entryPath, sectionPaths, documentPaths)
|
|
168
|
+
: null,
|
|
169
|
+
otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, entryPath, sectionPaths, documentPaths)),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function rewriteGraph(graph, basePath, entryPath) {
|
|
173
|
+
return {
|
|
174
|
+
...graph,
|
|
175
|
+
nodes: graph.nodes.map(({ gitStatus: _gitStatus, ...node }) => ({
|
|
176
|
+
...node,
|
|
177
|
+
url: staticViewUrl(node.url, basePath, entryPath),
|
|
178
|
+
})),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function positiveInteger(value) {
|
|
182
|
+
const parsed = Number(value);
|
|
183
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
|
|
184
|
+
}
|
|
185
|
+
function sourceRequest(value) {
|
|
186
|
+
let url;
|
|
187
|
+
try {
|
|
188
|
+
url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
if (url.origin !== 'http://lat.local' || !url.pathname.startsWith('/code/'))
|
|
194
|
+
return null;
|
|
195
|
+
let path;
|
|
196
|
+
let symbol;
|
|
197
|
+
try {
|
|
198
|
+
path = url.pathname
|
|
199
|
+
.slice('/code/'.length)
|
|
200
|
+
.split('/')
|
|
201
|
+
.map(decodeURIComponent)
|
|
202
|
+
.join('/');
|
|
203
|
+
if (path.split('/').some((part) => !part || part === '.' || part === '..') ||
|
|
204
|
+
path.includes('\\') ||
|
|
205
|
+
path.includes('\0') ||
|
|
206
|
+
/^[a-z]:/i.test(path))
|
|
207
|
+
return null;
|
|
208
|
+
// Encoded separators cannot create extra route components after decoding.
|
|
209
|
+
if (/%(?:2f|5c)/i.test(url.pathname))
|
|
210
|
+
return null;
|
|
211
|
+
symbol = decodeURIComponent(url.hash.slice(1));
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
path,
|
|
218
|
+
symbol,
|
|
219
|
+
from: url.searchParams.get('from') ?? '',
|
|
220
|
+
line: positiveInteger(url.searchParams.get('line')),
|
|
221
|
+
at: positiveInteger(url.searchParams.get('at')),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function externalRequest(value, external) {
|
|
225
|
+
let url;
|
|
226
|
+
try {
|
|
227
|
+
url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
if (url.origin !== 'http://lat.local' ||
|
|
233
|
+
!url.pathname.startsWith('/external/'))
|
|
234
|
+
return null;
|
|
235
|
+
try {
|
|
236
|
+
const parts = url.pathname
|
|
237
|
+
.slice('/external/'.length)
|
|
238
|
+
.split('/')
|
|
239
|
+
.map(decodeURIComponent);
|
|
240
|
+
const handle = parts.shift() ?? '';
|
|
241
|
+
const path = parts.join('/');
|
|
242
|
+
if (!handle || !path)
|
|
243
|
+
return null;
|
|
244
|
+
const fragment = decodeURIComponent(url.hash.slice(1));
|
|
245
|
+
const target = `${handle}:${path}${fragment ? `#${fragment}` : ''}`;
|
|
246
|
+
const parsed = external?.parse(target);
|
|
247
|
+
if (parsed) {
|
|
248
|
+
if (!isDocumentPath(parsed.resolvedPath)) {
|
|
249
|
+
return parsed.identity;
|
|
250
|
+
}
|
|
251
|
+
const hash = parsed.identity.indexOf('#');
|
|
252
|
+
return hash === -1 ? parsed.identity : parsed.identity.slice(0, hash);
|
|
253
|
+
}
|
|
254
|
+
return `${handle}:${path}${isDocumentPath(path) || !fragment ? '' : `#${fragment}`}`;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function externalRequestsFromDocument(document, requests, external, externalBase) {
|
|
261
|
+
const add = (value) => {
|
|
262
|
+
let candidate = value;
|
|
263
|
+
if (externalBase && !value.startsWith('#')) {
|
|
264
|
+
try {
|
|
265
|
+
const colon = externalBase.indexOf(':');
|
|
266
|
+
const base = `/external/${encodeURIComponent(externalBase.slice(0, colon))}/${externalBase
|
|
267
|
+
.slice(colon + 1)
|
|
268
|
+
.split('/')
|
|
269
|
+
.map(encodeURIComponent)
|
|
270
|
+
.join('/')}`;
|
|
271
|
+
const resolved = new URL(decodeHtmlUrlAttribute(value), `http://lat.local${base}`);
|
|
272
|
+
if (resolved.origin === 'http://lat.local') {
|
|
273
|
+
candidate = `${resolved.pathname}${resolved.hash}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Leave malformed links to the renderer rather than exporting them.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const request = externalRequest(candidate, external);
|
|
281
|
+
if (request)
|
|
282
|
+
requests.add(request);
|
|
283
|
+
};
|
|
284
|
+
for (const value of documentTreeUrls(document.tree))
|
|
285
|
+
add(value);
|
|
286
|
+
for (const section of document.backReferences) {
|
|
287
|
+
for (const reference of section.references) {
|
|
288
|
+
add(reference.url);
|
|
289
|
+
if (reference.kind === 'markdown') {
|
|
290
|
+
for (const value of documentTreeUrls(reference.paragraphTree))
|
|
291
|
+
add(value);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function externalRequestsFromSource(source, requests, external) {
|
|
297
|
+
for (const reference of [
|
|
298
|
+
...(source.context ? [source.context] : []),
|
|
299
|
+
...source.otherReferences,
|
|
300
|
+
]) {
|
|
301
|
+
for (const value of documentTreeUrls(reference.paragraphTree)) {
|
|
302
|
+
const request = externalRequest(value, external);
|
|
303
|
+
if (request)
|
|
304
|
+
requests.add(request);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function sourceRequestsFromDocument(document, requests) {
|
|
309
|
+
const add = (value) => {
|
|
310
|
+
const request = sourceRequest(value);
|
|
311
|
+
if (request)
|
|
312
|
+
requests.set(viewStaticSourceKey(request), request);
|
|
313
|
+
};
|
|
314
|
+
for (const value of documentTreeUrls(document.tree))
|
|
315
|
+
add(value);
|
|
316
|
+
for (const section of document.backReferences) {
|
|
317
|
+
for (const reference of section.references) {
|
|
318
|
+
add(reference.url);
|
|
319
|
+
if (reference.kind === 'markdown') {
|
|
320
|
+
for (const value of documentTreeUrls(reference.paragraphTree))
|
|
321
|
+
add(value);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function sourceRequestsFromSource(source, requests) {
|
|
327
|
+
const references = [
|
|
328
|
+
...(source.context ? [source.context] : []),
|
|
329
|
+
...source.otherReferences,
|
|
330
|
+
];
|
|
331
|
+
for (const reference of references) {
|
|
332
|
+
for (const value of documentTreeUrls(reference.paragraphTree)) {
|
|
333
|
+
const request = sourceRequest(value);
|
|
334
|
+
if (request)
|
|
335
|
+
requests.set(viewStaticSourceKey(request), request);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function serializeJson(value) {
|
|
340
|
+
return `${JSON.stringify(value)}\n`;
|
|
341
|
+
}
|
|
342
|
+
function dataFile(kind, content) {
|
|
343
|
+
const digest = createHash('sha256')
|
|
344
|
+
.update(content)
|
|
345
|
+
.digest('hex')
|
|
346
|
+
.slice(0, 20);
|
|
347
|
+
return `data/${kind}/${digest}.json`;
|
|
348
|
+
}
|
|
349
|
+
async function writeJson(path, value) {
|
|
350
|
+
await mkdir(dirname(path), { recursive: true });
|
|
351
|
+
await writeFile(path, serializeJson(value));
|
|
352
|
+
}
|
|
353
|
+
async function writeDataJson(outputDir, kind, value) {
|
|
354
|
+
const content = serializeJson(value);
|
|
355
|
+
const path = dataFile(kind, content);
|
|
356
|
+
await mkdir(dirname(join(outputDir, path)), { recursive: true });
|
|
357
|
+
await writeFile(join(outputDir, path), content);
|
|
358
|
+
return path;
|
|
359
|
+
}
|
|
360
|
+
async function outputExists(path) {
|
|
361
|
+
try {
|
|
362
|
+
await lstat(path);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
if (error.code === 'ENOENT')
|
|
367
|
+
return false;
|
|
368
|
+
throw error;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/** Refuse build targets that exist or could replace the project itself. */
|
|
372
|
+
export async function validateViewBuildOutput(outputDir, projectRoot, kind = 'Static', force = false) {
|
|
373
|
+
if (outputDir === parse(outputDir).root ||
|
|
374
|
+
outputDir === projectRoot ||
|
|
375
|
+
isInside(outputDir, projectRoot)) {
|
|
376
|
+
throw new Error(`${kind} UI output must not contain the project root`);
|
|
377
|
+
}
|
|
378
|
+
if (!force && (await outputExists(outputDir))) {
|
|
379
|
+
throw new Error(`${kind} UI output already exists: ${outputDir}. Use --force to replace it.`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const defaultViewBuildMoveDependencies = {
|
|
383
|
+
move: rename,
|
|
384
|
+
wait: (milliseconds) => new Promise((resolveWait) => setTimeout(resolveWait, milliseconds)),
|
|
385
|
+
};
|
|
386
|
+
/** Commit a staged build after transient filesystem locks have cleared. */
|
|
387
|
+
export async function moveViewBuildOutput(stagingDir, outputDir, dependencies = defaultViewBuildMoveDependencies) {
|
|
388
|
+
for (let retries = 0;; retries += 1) {
|
|
389
|
+
try {
|
|
390
|
+
await dependencies.move(stagingDir, outputDir);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
const code = error.code;
|
|
395
|
+
if (retries >= VIEW_BUILD_MOVE_MAX_RETRIES ||
|
|
396
|
+
(code !== 'EBUSY' && code !== 'EPERM' && code !== 'ENOTEMPTY')) {
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
await dependencies.wait(VIEW_BUILD_MOVE_RETRY_DELAY_MS);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Remove abandoned staging after transient filesystem locks have cleared. */
|
|
404
|
+
export async function removeViewBuildStaging(stagingDir) {
|
|
405
|
+
await rm(stagingDir, {
|
|
406
|
+
recursive: true,
|
|
407
|
+
force: true,
|
|
408
|
+
maxRetries: VIEW_BUILD_MOVE_MAX_RETRIES,
|
|
409
|
+
retryDelay: VIEW_BUILD_MOVE_RETRY_DELAY_MS,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
function sectionDocumentPaths(documents) {
|
|
413
|
+
const result = new Map();
|
|
414
|
+
for (const path of documents.keys()) {
|
|
415
|
+
result.set(`lat.md/${path.slice(0, -'.md'.length)}`, path);
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
function clientShell(html, basePath, entry, searchApi) {
|
|
420
|
+
const assets = rewriteClientAssetUrls(html, basePath);
|
|
421
|
+
const configValue = encodeURIComponent(JSON.stringify({ basePath, entry, searchApi }));
|
|
422
|
+
const config = `<meta name="lat-static-view" content="${configValue}">`;
|
|
423
|
+
return assets.includes('</head>')
|
|
424
|
+
? assets.replace('</head>', ` ${config}\n </head>`)
|
|
425
|
+
: `${config}\n${assets}`;
|
|
426
|
+
}
|
|
427
|
+
function bootstrapShell(shell, manifest, responses = {}) {
|
|
428
|
+
const bootstrap = { manifest, responses };
|
|
429
|
+
const value = JSON.stringify(bootstrap).replaceAll('<', '\\u003c');
|
|
430
|
+
const data = `<script id="${VIEW_STATIC_BOOTSTRAP_ID}" type="application/json">${value}</script>`;
|
|
431
|
+
return shell.includes('</head>')
|
|
432
|
+
? shell.replace('</head>', ` ${data}\n </head>`)
|
|
433
|
+
: `${data}\n${shell}`;
|
|
434
|
+
}
|
|
435
|
+
const REDIRECT_SCRIPT_PATH = 'data/redirect.js';
|
|
436
|
+
const REDIRECT_SCRIPT = `const meta = document.querySelector('meta[name="lat-redirect"]');
|
|
437
|
+
if (meta) {
|
|
438
|
+
try {
|
|
439
|
+
window.location.replace(decodeURIComponent(meta.content) + window.location.search + window.location.hash);
|
|
440
|
+
} catch {}
|
|
441
|
+
}
|
|
442
|
+
`;
|
|
443
|
+
function redirectShell(target, basePath) {
|
|
444
|
+
const escaped = target.replaceAll('&', '&').replaceAll('"', '"');
|
|
445
|
+
const scriptUrl = `${basePath}${REDIRECT_SCRIPT_PATH}`
|
|
446
|
+
.replaceAll('&', '&')
|
|
447
|
+
.replaceAll('"', '"');
|
|
448
|
+
return `<!doctype html>
|
|
449
|
+
<html lang="en">
|
|
450
|
+
<head>
|
|
451
|
+
<meta charset="UTF-8" />
|
|
452
|
+
<meta name="lat-redirect" content="${encodeURIComponent(target)}" />
|
|
453
|
+
<title>lat.md</title>
|
|
454
|
+
<script src="${scriptUrl}" defer></script>
|
|
455
|
+
</head>
|
|
456
|
+
<body><a href="${escaped}">Open lat.md</a></body>
|
|
457
|
+
</html>
|
|
458
|
+
`;
|
|
459
|
+
}
|
|
460
|
+
/** All authored route writes must remain strictly below the payload root. */
|
|
461
|
+
function publicationOutputPath(root, ...parts) {
|
|
462
|
+
if (parts.some((part) => part.includes('\\') ||
|
|
463
|
+
part.includes('\0') ||
|
|
464
|
+
part.split('/').some((segment) => segment === '..' || segment === '.')))
|
|
465
|
+
throw new Error('Unsafe export route');
|
|
466
|
+
const path = resolve(root, ...parts);
|
|
467
|
+
const rel = relative(root, path);
|
|
468
|
+
if (!rel ||
|
|
469
|
+
rel.startsWith(`..${sep}`) ||
|
|
470
|
+
rel === '..' ||
|
|
471
|
+
/^[a-z]:/i.test(rel) ||
|
|
472
|
+
rel.startsWith(sep))
|
|
473
|
+
throw new Error('Export route is outside the output directory');
|
|
474
|
+
return path;
|
|
475
|
+
}
|
|
476
|
+
async function writeRouteShell(outputDir, route, shell) {
|
|
477
|
+
const path = publicationOutputPath(outputDir, route, 'index.html');
|
|
478
|
+
await mkdir(dirname(path), { recursive: true });
|
|
479
|
+
await writeFile(path, shell);
|
|
480
|
+
}
|
|
481
|
+
/** Build a serverless snapshot of the current read-only Lat UI. */
|
|
482
|
+
export async function buildStaticView(ctx, requestedOutput, options = {}) {
|
|
483
|
+
const outputDir = resolve(ctx.projectRoot, requestedOutput);
|
|
484
|
+
const basePath = normalizeStaticViewBasePath(options.basePath ?? '/');
|
|
485
|
+
const clientDir = options.clientDir ?? defaultClientDir;
|
|
486
|
+
const logoText = options.logoText ?? DEFAULT_VIEW_LOGO_TEXT;
|
|
487
|
+
await validateViewBuildOutput(outputDir, ctx.projectRoot, 'Static', options.force);
|
|
488
|
+
await mkdir(dirname(outputDir), { recursive: true });
|
|
489
|
+
const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-static-staging-'));
|
|
490
|
+
let store;
|
|
491
|
+
try {
|
|
492
|
+
store = await createViewStore(ctx.latDir, ctx.projectRoot, {
|
|
493
|
+
codeExcludePaths: [outputDir, ...(options.codeExcludePaths ?? [])],
|
|
494
|
+
git: false,
|
|
495
|
+
watch: false,
|
|
496
|
+
externalIgnoreLocal: true,
|
|
497
|
+
externalCa: options.externalCa,
|
|
498
|
+
publishable: await createPublicationPolicy(ctx.projectRoot),
|
|
499
|
+
});
|
|
500
|
+
const clientHtml = await readFile(join(clientDir, 'index.html'), 'utf8');
|
|
501
|
+
const payloadDir = staticViewPayloadDir(stagingDir, basePath);
|
|
502
|
+
await mkdir(payloadDir, { recursive: true });
|
|
503
|
+
await cp(clientDir, payloadDir, { recursive: true });
|
|
504
|
+
const index = { ...store.getIndex(), git: null, logoText };
|
|
505
|
+
validateDocumentRoutes(index.files);
|
|
506
|
+
const shell = clientShell(clientHtml, basePath, index.entry, options.searchApi);
|
|
507
|
+
const documents = new Map();
|
|
508
|
+
const documentResources = new Set();
|
|
509
|
+
const sourceRequests = new Map();
|
|
510
|
+
const externalRequests = new Set();
|
|
511
|
+
for (const file of index.externalFiles) {
|
|
512
|
+
externalRequests.add(file.target);
|
|
513
|
+
}
|
|
514
|
+
for (const path of index.files) {
|
|
515
|
+
const document = await store.getDocument(path);
|
|
516
|
+
documents.set(path, document);
|
|
517
|
+
for (const url of documentTreeUrls(document.tree)) {
|
|
518
|
+
let parsed;
|
|
519
|
+
try {
|
|
520
|
+
parsed = new URL(url, 'http://lat.local');
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (parsed.origin !== 'http://lat.local')
|
|
526
|
+
continue;
|
|
527
|
+
const resourcePath = documentResourcePath(parsed.pathname);
|
|
528
|
+
if (resourcePath)
|
|
529
|
+
documentResources.add(resourcePath);
|
|
530
|
+
}
|
|
531
|
+
sourceRequestsFromDocument(document, sourceRequests);
|
|
532
|
+
externalRequestsFromDocument(document, externalRequests, store.snapshot.external);
|
|
533
|
+
}
|
|
534
|
+
const documentPaths = new Set(documents.keys());
|
|
535
|
+
const sectionPaths = sectionDocumentPaths(documents);
|
|
536
|
+
const graph = store.getGraph();
|
|
537
|
+
for (const node of graph.nodes) {
|
|
538
|
+
const request = sourceRequest(node.url);
|
|
539
|
+
if (request)
|
|
540
|
+
sourceRequests.set(viewStaticSourceKey(request), request);
|
|
541
|
+
if (node.externalTarget)
|
|
542
|
+
externalRequests.add(node.externalTarget);
|
|
543
|
+
}
|
|
544
|
+
const externals = new Map();
|
|
545
|
+
const pendingExternal = [...externalRequests];
|
|
546
|
+
for (let index = 0; index < pendingExternal.length; index++) {
|
|
547
|
+
const target = pendingExternal[index];
|
|
548
|
+
if (externals.has(target))
|
|
549
|
+
continue;
|
|
550
|
+
let external;
|
|
551
|
+
try {
|
|
552
|
+
external = await store.getExternal(target);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
throw new Error(`Could not export external source ${target}: ${error.message}`);
|
|
556
|
+
}
|
|
557
|
+
externals.set(target, external);
|
|
558
|
+
const before = externalRequests.size;
|
|
559
|
+
if (external.kind === 'markdown') {
|
|
560
|
+
externalRequestsFromDocument(external.document, externalRequests, store.snapshot.external, external.document.path);
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
externalRequestsFromSource(external.source, externalRequests, store.snapshot.external);
|
|
564
|
+
}
|
|
565
|
+
if (externalRequests.size > before) {
|
|
566
|
+
for (const next of externalRequests) {
|
|
567
|
+
if (!externals.has(next) && !pendingExternal.includes(next)) {
|
|
568
|
+
pendingExternal.push(next);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const sources = new Map();
|
|
574
|
+
const pending = [...sourceRequests.keys()];
|
|
575
|
+
for (let index = 0; index < pending.length; index++) {
|
|
576
|
+
const key = pending[index];
|
|
577
|
+
if (sources.has(key))
|
|
578
|
+
continue;
|
|
579
|
+
const request = sourceRequests.get(key);
|
|
580
|
+
const origin = request.from && request.line > 0
|
|
581
|
+
? { sectionId: request.from, line: request.line }
|
|
582
|
+
: undefined;
|
|
583
|
+
let source;
|
|
584
|
+
try {
|
|
585
|
+
source = await store.getSource(request.path, request.symbol, origin, request.at);
|
|
586
|
+
}
|
|
587
|
+
catch (error) {
|
|
588
|
+
const target = `${request.path}${request.symbol ? `#${request.symbol}` : ''}`;
|
|
589
|
+
throw new Error(`Could not export source ${target}: ${error.message}`);
|
|
590
|
+
}
|
|
591
|
+
sources.set(key, source);
|
|
592
|
+
const before = sourceRequests.size;
|
|
593
|
+
sourceRequestsFromSource(source, sourceRequests);
|
|
594
|
+
if (sourceRequests.size > before) {
|
|
595
|
+
for (const next of sourceRequests.keys()) {
|
|
596
|
+
if (!sources.has(next) && !pending.includes(next))
|
|
597
|
+
pending.push(next);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const rewrittenGraph = rewriteGraph(graph, basePath, index.entry);
|
|
602
|
+
const manifest = {
|
|
603
|
+
version: 1,
|
|
604
|
+
index,
|
|
605
|
+
graph: await writeDataJson(payloadDir, 'graphs', rewrittenGraph),
|
|
606
|
+
documents: {},
|
|
607
|
+
sources: {},
|
|
608
|
+
externals: {},
|
|
609
|
+
};
|
|
610
|
+
const documentBootstraps = new Map();
|
|
611
|
+
for (const [path, document] of documents) {
|
|
612
|
+
const rewritten = rewriteDocument(document, basePath, index.entry, sectionPaths, documentPaths);
|
|
613
|
+
manifest.documents[path] = await writeDataJson(payloadDir, 'documents', rewritten);
|
|
614
|
+
const source = await store.getDocumentSource(path);
|
|
615
|
+
const rawPath = publicationOutputPath(payloadDir, path);
|
|
616
|
+
await mkdir(dirname(rawPath), { recursive: true });
|
|
617
|
+
await writeFile(rawPath, source.content);
|
|
618
|
+
const route = path.slice(0, -'.md'.length);
|
|
619
|
+
documentBootstraps.set(route, {
|
|
620
|
+
request: viewStaticDocumentRequest(path),
|
|
621
|
+
document: rewritten,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
for (const path of [...documentResources].sort()) {
|
|
625
|
+
let content;
|
|
626
|
+
try {
|
|
627
|
+
content = await store.getDocumentResource(path);
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
throw new Error(`Could not export document resource ${path}: ${error.message}`);
|
|
631
|
+
}
|
|
632
|
+
const outputPath = publicationOutputPath(payloadDir, 'resources', path);
|
|
633
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
634
|
+
await writeFile(outputPath, content);
|
|
635
|
+
}
|
|
636
|
+
const sourceFiles = new Map();
|
|
637
|
+
for (const [key, source] of sources) {
|
|
638
|
+
const rewritten = rewriteSource(source, basePath, index.entry, sectionPaths, documentPaths);
|
|
639
|
+
const { path, content, highlightedLines, ...view } = rewritten;
|
|
640
|
+
let fileDataPath = sourceFiles.get(path);
|
|
641
|
+
if (!fileDataPath) {
|
|
642
|
+
fileDataPath = await writeDataJson(payloadDir, 'source-files', {
|
|
643
|
+
path,
|
|
644
|
+
content,
|
|
645
|
+
highlightedLines,
|
|
646
|
+
});
|
|
647
|
+
sourceFiles.set(path, fileDataPath);
|
|
648
|
+
}
|
|
649
|
+
const viewDataPath = await writeDataJson(payloadDir, 'source-views', view);
|
|
650
|
+
manifest.sources[key] = { file: fileDataPath, view: viewDataPath };
|
|
651
|
+
}
|
|
652
|
+
const externalSourceFiles = new Map();
|
|
653
|
+
const externalRoutes = new Set();
|
|
654
|
+
for (const [target, external] of externals) {
|
|
655
|
+
if (external.kind === 'markdown') {
|
|
656
|
+
const dataPath = await writeDataJson(payloadDir, 'external-documents', {
|
|
657
|
+
...external,
|
|
658
|
+
document: rewriteDocument(external.document, basePath, index.entry, sectionPaths, documentPaths),
|
|
659
|
+
});
|
|
660
|
+
manifest.externals[target] = { kind: 'markdown', document: dataPath };
|
|
661
|
+
const colon = external.document.path.indexOf(':');
|
|
662
|
+
externalRoutes.add(`external/${external.document.path.slice(0, colon)}/${external.document.path.slice(colon + 1)}`);
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
const rewritten = rewriteSource(external.source, basePath, index.entry, sectionPaths, documentPaths);
|
|
666
|
+
const { path, content, highlightedLines, ...sourceView } = rewritten;
|
|
667
|
+
let fileDataPath = externalSourceFiles.get(path);
|
|
668
|
+
if (!fileDataPath) {
|
|
669
|
+
fileDataPath = await writeDataJson(payloadDir, 'external-source-files', {
|
|
670
|
+
path,
|
|
671
|
+
content,
|
|
672
|
+
highlightedLines,
|
|
673
|
+
});
|
|
674
|
+
externalSourceFiles.set(path, fileDataPath);
|
|
675
|
+
}
|
|
676
|
+
const view = {
|
|
677
|
+
kind: 'source',
|
|
678
|
+
target: external.target,
|
|
679
|
+
source: sourceView,
|
|
680
|
+
};
|
|
681
|
+
const viewDataPath = await writeDataJson(payloadDir, 'external-source-views', view);
|
|
682
|
+
manifest.externals[target] = {
|
|
683
|
+
kind: 'source',
|
|
684
|
+
file: fileDataPath,
|
|
685
|
+
view: viewDataPath,
|
|
686
|
+
};
|
|
687
|
+
const colon = path.indexOf(':');
|
|
688
|
+
externalRoutes.add(`external/${path.slice(0, colon)}/${path.slice(colon + 1)}`);
|
|
689
|
+
}
|
|
690
|
+
await writeJson(join(payloadDir, 'data/manifest.json'), manifest);
|
|
691
|
+
const entryRoute = index.entry.slice(0, -'.md'.length);
|
|
692
|
+
const entryBootstrap = documentBootstraps.get(entryRoute);
|
|
693
|
+
if (!entryBootstrap) {
|
|
694
|
+
throw new Error(`Static UI entry document is missing: ${index.entry}`);
|
|
695
|
+
}
|
|
696
|
+
for (const [route, initial] of documentBootstraps) {
|
|
697
|
+
if (route === entryRoute)
|
|
698
|
+
continue;
|
|
699
|
+
await writeRouteShell(payloadDir, route, bootstrapShell(shell, manifest, {
|
|
700
|
+
[initial.request]: initial.document,
|
|
701
|
+
}));
|
|
702
|
+
}
|
|
703
|
+
const genericShell = bootstrapShell(shell, manifest);
|
|
704
|
+
for (const path of sourceFiles.keys()) {
|
|
705
|
+
await writeRouteShell(payloadDir, `code/${path}`, genericShell);
|
|
706
|
+
}
|
|
707
|
+
for (const route of externalRoutes) {
|
|
708
|
+
await writeRouteShell(payloadDir, route, genericShell);
|
|
709
|
+
}
|
|
710
|
+
await writeRouteShell(payloadDir, 'graph', bootstrapShell(shell, manifest, { '/api/graph': rewrittenGraph }));
|
|
711
|
+
if (options.searchApi) {
|
|
712
|
+
await writeRouteShell(payloadDir, 'search', genericShell);
|
|
713
|
+
}
|
|
714
|
+
const redirectScriptPath = join(payloadDir, REDIRECT_SCRIPT_PATH);
|
|
715
|
+
await mkdir(dirname(redirectScriptPath), { recursive: true });
|
|
716
|
+
await writeFile(redirectScriptPath, REDIRECT_SCRIPT);
|
|
717
|
+
await writeFile(join(payloadDir, 'index.html'), bootstrapShell(shell, manifest, {
|
|
718
|
+
[entryBootstrap.request]: entryBootstrap.document,
|
|
719
|
+
}));
|
|
720
|
+
await writeRouteShell(payloadDir, entryRoute, redirectShell(basePath, basePath));
|
|
721
|
+
if (payloadDir !== stagingDir) {
|
|
722
|
+
await writeFile(join(stagingDir, 'index.html'), redirectShell(basePath, basePath));
|
|
723
|
+
}
|
|
724
|
+
if (options.force) {
|
|
725
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
726
|
+
}
|
|
727
|
+
await moveViewBuildOutput(stagingDir, outputDir);
|
|
728
|
+
return {
|
|
729
|
+
documents: documents.size,
|
|
730
|
+
outputDir,
|
|
731
|
+
sources: sources.size + externals.size,
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
await removeViewBuildStaging(stagingDir);
|
|
736
|
+
throw error;
|
|
737
|
+
}
|
|
738
|
+
finally {
|
|
739
|
+
await store?.close();
|
|
740
|
+
}
|
|
741
|
+
}
|