@plebeiantech/lat.md 0.12.3-fork.2 → 0.12.3-fork.21
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 +115 -64
- 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 +200 -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-0bPe_Q5I.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-1_8mI7lO.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-BLIuikwY.js +1 -0
- package/dist/src/view/client/assets/arc-D4PzdKSA.js +1 -0
- package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-35Egww62.js +36 -0
- package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-tqNy53-W.js +129 -0
- package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-DZ_GcD9K.js +38 -0
- package/dist/src/view/client/assets/channel-DensupHE.js +1 -0
- package/dist/src/view/client/assets/chunk-2Q5K7J3B-BUjq4Q7b.js +1 -0
- package/dist/src/view/client/assets/chunk-5VM5RSS4-BsIix6I5.js +15 -0
- package/dist/src/view/client/assets/chunk-F27PBJKO-Dxo7UheG.js +1 -0
- package/dist/src/view/client/assets/chunk-IMKFNOWR-C5lzUDK5.js +231 -0
- package/dist/src/view/client/assets/chunk-JWPE2WC7-qCHQlKfY.js +1 -0
- package/dist/src/view/client/assets/chunk-POPQ4Y6H-CDPKw21I.js +1 -0
- package/dist/src/view/client/assets/chunk-SVP7TREG-CD_C-9M-.js +88 -0
- package/dist/src/view/client/assets/chunk-TICWLB2K-ZMatRvad.js +206 -0
- package/dist/src/view/client/assets/chunk-XXDRQBXY-dDs4quwg.js +1 -0
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CV7ArHLW.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CV7ArHLW.js +1 -0
- package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-CwH3-T1N.js +1 -0
- package/dist/src/view/client/assets/cynefin-OW5HDTMX-DodS6r00.js +166 -0
- package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-D7WDoy0K.js +62 -0
- package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
- package/dist/src/view/client/assets/dagre-GXQ25YYZ-yc2GTi5h.js +4 -0
- package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/src/view/client/assets/diagram-S7CK7UJ4-CEP0FGL8.js +30 -0
- package/dist/src/view/client/assets/diagram-UQ7AKVKN-BZIEojBf.js +41 -0
- package/dist/src/view/client/assets/diagram-VSXAHHWV-BSB6COmM.js +3 -0
- package/dist/src/view/client/assets/diagram-VX7I27RA-DqfR3psV.js +24 -0
- package/dist/src/view/client/assets/diagram-Z3DM3KII-B79t0s5P.js +24 -0
- package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-CqbCQhE1.js +1 -0
- package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-BVfoYIhJ.js +99 -0
- package/dist/src/view/client/assets/flowDiagram-HODETNUW-Dfyjm6ib.js +168 -0
- package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-Da9ta_k3.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-BDqlQ6LG.js +106 -0
- package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
- package/dist/src/view/client/assets/index-DG0Ez15D.css +1 -0
- package/dist/src/view/client/assets/index-heNSjszK.js +13 -0
- package/dist/src/view/client/assets/infoDiagram-27XIBGKW-CozIUYm1.js +2 -0
- package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-tkBLr-Tn.js +70 -0
- package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-Dcd_Ofwc.js +139 -0
- package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-CQvZmdAf.js +89 -0
- package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/src/view/client/assets/layout-BxuGL0Ip.js +1 -0
- package/dist/src/view/client/assets/linear-D8tR6G5K.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-BlHZooLK.js +310 -0
- package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-BqvVz5lC.js +96 -0
- package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-BkbOOTxX.js +1 -0
- package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-BToTpG0m.js +39 -0
- package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC-CerD2TfT.js +7 -0
- package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-B2oElPYD.js +1 -0
- package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-BCL8RGFd.js +84 -0
- package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-BqnkNRPm.js +40 -0
- package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-DKSKYknp.js +162 -0
- package/dist/src/view/client/assets/sizeCapture-INFHLROL-D8reQ7IM.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-D77RDMKH-B-Eme-BN.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-yXL-Y-Ym.js +1 -0
- package/dist/src/view/client/assets/swimlanes-42K2YHIH-lK0158X4.js +1 -0
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-CGn5WOGw.js +8 -0
- package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
- package/dist/src/view/client/assets/timeline-definition-24CTP7MA-imh-edhJ.js +120 -0
- package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-Ixwhcd6r.js +34 -0
- package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-Cvr_zzKI.js +78 -0
- package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-BvcmHKlQ.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 +50648 -3166
- package/dist/src/view/markdown.d.ts +8 -3
- package/dist/src/view/markdown.js +311 -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 -20
- package/templates/cursor-rules.md +14 -7
- 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
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, relative } from 'node:path';
|
|
3
|
-
import { listLatticeFiles, parseFrontmatter } from '../lattice.js';
|
|
4
|
-
import { parse } from '../parser.js';
|
|
5
|
-
import { quoteUntrusted } from '../untrusted.js';
|
|
6
|
-
import { toPosix } from '../walk.js';
|
|
7
|
-
export const DIATAXIS_MODES = [
|
|
8
|
-
'tutorial',
|
|
9
|
-
'how-to',
|
|
10
|
-
'reference',
|
|
11
|
-
'explanation',
|
|
12
|
-
];
|
|
13
|
-
/** Directory below lat.md/ that holds each mode. */
|
|
14
|
-
export const MODE_DIRS = {
|
|
15
|
-
tutorial: 'tutorials',
|
|
16
|
-
'how-to': 'how-to',
|
|
17
|
-
reference: 'reference',
|
|
18
|
-
explanation: 'explanation',
|
|
19
|
-
};
|
|
20
|
-
/** Reverse lookup: first path segment -> mode. Built once, not per file. */
|
|
21
|
-
const DIR_TO_MODE = Object.fromEntries(DIATAXIS_MODES.map((mode) => [MODE_DIRS[mode], mode]));
|
|
22
|
-
const OUTCOME_RE = /\b(outcome|by the end|you will (build|learn|have|create)|what you (will )?(build|learn|have|create))\b/i;
|
|
23
|
-
/**
|
|
24
|
-
* Imperative verbs that flag a command inside an explanation document.
|
|
25
|
-
* Deliberately excludes ambiguous verbs (Use, Go, Make, Type, Enter, Call,
|
|
26
|
-
* Import, Export) — each reads naturally as a noun or as descriptive prose
|
|
27
|
-
* at the start of a sentence ("Use cases include...", "Type inference..."),
|
|
28
|
-
* and including them produced false positives in testing.
|
|
29
|
-
*/
|
|
30
|
-
const IMPERATIVE_VERBS = [
|
|
31
|
-
'Run',
|
|
32
|
-
'Install',
|
|
33
|
-
'Add',
|
|
34
|
-
'Set',
|
|
35
|
-
'Open',
|
|
36
|
-
'Create',
|
|
37
|
-
'Delete',
|
|
38
|
-
'Edit',
|
|
39
|
-
'Copy',
|
|
40
|
-
'Move',
|
|
41
|
-
'Click',
|
|
42
|
-
'Press',
|
|
43
|
-
'Configure',
|
|
44
|
-
'Update',
|
|
45
|
-
'Remove',
|
|
46
|
-
'Execute',
|
|
47
|
-
'Choose',
|
|
48
|
-
'Select',
|
|
49
|
-
'Replace',
|
|
50
|
-
'Rename',
|
|
51
|
-
'Restart',
|
|
52
|
-
'Deploy',
|
|
53
|
-
];
|
|
54
|
-
const MAX_IMPERATIVE_ERRORS = 10;
|
|
55
|
-
function orderedListPresent(tree) {
|
|
56
|
-
let found = false;
|
|
57
|
-
const walk = (nodes) => {
|
|
58
|
-
for (const node of nodes) {
|
|
59
|
-
if (node.type === 'list' && node.ordered === true) {
|
|
60
|
-
found = true;
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if ('children' in node) {
|
|
64
|
-
walk(node.children);
|
|
65
|
-
}
|
|
66
|
-
if (found)
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
walk(tree.children);
|
|
71
|
-
return found;
|
|
72
|
-
}
|
|
73
|
-
function outcomeStated(tree) {
|
|
74
|
-
for (const node of tree.children) {
|
|
75
|
-
if (node.type === 'heading' || node.type === 'paragraph') {
|
|
76
|
-
const text = inlineTextOf(node);
|
|
77
|
-
if (OUTCOME_RE.test(text))
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
function inlineTextOf(node) {
|
|
84
|
-
return node.children
|
|
85
|
-
.map((c) => {
|
|
86
|
-
if ('value' in c && typeof c.value === 'string')
|
|
87
|
-
return c.value;
|
|
88
|
-
if ('children' in c)
|
|
89
|
-
return inlineTextOf(c);
|
|
90
|
-
return '';
|
|
91
|
-
})
|
|
92
|
-
.join('');
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Extra top-level paragraphs found under headings, beyond the one
|
|
96
|
-
* `checkSections` already permits as the leading summary. A paragraph
|
|
97
|
-
* before the first heading is the document lead, not narrative prose.
|
|
98
|
-
*/
|
|
99
|
-
function extraParagraphs(tree) {
|
|
100
|
-
const offenders = [];
|
|
101
|
-
let currentHeading = null;
|
|
102
|
-
let seenParagraphUnderHeading = false;
|
|
103
|
-
for (const node of tree.children) {
|
|
104
|
-
if (node.type === 'heading') {
|
|
105
|
-
currentHeading = inlineTextOf(node);
|
|
106
|
-
seenParagraphUnderHeading = false;
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (node.type === 'paragraph') {
|
|
110
|
-
if (currentHeading === null) {
|
|
111
|
-
// Document lead paragraph before any heading — allowed.
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (!seenParagraphUnderHeading) {
|
|
115
|
-
seenParagraphUnderHeading = true;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
offenders.push({
|
|
119
|
-
line: node.position.start.line,
|
|
120
|
-
heading: currentHeading,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return offenders;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Line numbers (1-indexed, inclusive of both ends) that belong to a `code`
|
|
129
|
-
* or `yaml` (frontmatter) node anywhere in the tree. Walking the parsed tree
|
|
130
|
-
* — rather than re-scanning raw text with a fence regex — means a fence of
|
|
131
|
-
* any marker length or an indented code block is recognized correctly, and
|
|
132
|
-
* frontmatter needs no special case: it simply isn't prose in the tree.
|
|
133
|
-
*/
|
|
134
|
-
function nonProseLines(tree) {
|
|
135
|
-
const lines = new Set();
|
|
136
|
-
const markRange = (node) => {
|
|
137
|
-
if (!node.position)
|
|
138
|
-
return;
|
|
139
|
-
for (let line = node.position.start.line; line <= node.position.end.line; line++) {
|
|
140
|
-
lines.add(line);
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
const walk = (nodes) => {
|
|
144
|
-
for (const node of nodes) {
|
|
145
|
-
if (node.type === 'code' || node.type === 'yaml') {
|
|
146
|
-
markRange(node);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
if ('children' in node) {
|
|
150
|
-
walk(node.children);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
walk(tree.children);
|
|
155
|
-
return lines;
|
|
156
|
-
}
|
|
157
|
-
function findImperativeHits(tree, content) {
|
|
158
|
-
const hits = [];
|
|
159
|
-
const lines = content.split('\n');
|
|
160
|
-
const skipLines = nonProseLines(tree);
|
|
161
|
-
for (let i = 0; i < lines.length; i++) {
|
|
162
|
-
const lineNumber = i + 1;
|
|
163
|
-
if (skipLines.has(lineNumber))
|
|
164
|
-
continue;
|
|
165
|
-
const trimmedStart = lines[i].trimStart();
|
|
166
|
-
if (trimmedStart.startsWith('#'))
|
|
167
|
-
continue;
|
|
168
|
-
let text = trimmedStart;
|
|
169
|
-
text = text.replace(/^(?:[-*+]\s+|\d+[.)]\s+)/, '');
|
|
170
|
-
text = text.replace(/^\*\*/, '');
|
|
171
|
-
for (const verb of IMPERATIVE_VERBS) {
|
|
172
|
-
if (text.startsWith(verb + ' ')) {
|
|
173
|
-
hits.push({ line: lineNumber, verb });
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return hits;
|
|
179
|
-
}
|
|
180
|
-
export async function checkMode(latticeDir, projectRoot = dirname(latticeDir)) {
|
|
181
|
-
const files = await listLatticeFiles(latticeDir);
|
|
182
|
-
const errors = [];
|
|
183
|
-
for (const file of files) {
|
|
184
|
-
const content = await readFile(file, 'utf-8');
|
|
185
|
-
const relPath = relative(process.cwd(), file);
|
|
186
|
-
const target = toPosix(relative(projectRoot, file)).replace(/\.md$/, '');
|
|
187
|
-
const fm = parseFrontmatter(content);
|
|
188
|
-
const declaredRaw = fm.raw['mode'];
|
|
189
|
-
// null (bare `mode:` key) is treated as absent; any other non-string is
|
|
190
|
-
// reported below via declaredNonString.
|
|
191
|
-
const declared = declaredRaw === null || declaredRaw === undefined
|
|
192
|
-
? undefined
|
|
193
|
-
: typeof declaredRaw === 'string'
|
|
194
|
-
? declaredRaw
|
|
195
|
-
: undefined;
|
|
196
|
-
const declaredNonString = declaredRaw !== null &&
|
|
197
|
-
declaredRaw !== undefined &&
|
|
198
|
-
typeof declaredRaw !== 'string'
|
|
199
|
-
? declaredRaw
|
|
200
|
-
: undefined;
|
|
201
|
-
const relFromLattice = toPosix(relative(latticeDir, file));
|
|
202
|
-
const firstSegment = relFromLattice.split('/')[0];
|
|
203
|
-
const dirMode = firstSegment && firstSegment !== relFromLattice
|
|
204
|
-
? DIR_TO_MODE[firstSegment]
|
|
205
|
-
: undefined;
|
|
206
|
-
if (declaredNonString !== undefined) {
|
|
207
|
-
errors.push({
|
|
208
|
-
file: relPath,
|
|
209
|
-
line: 1,
|
|
210
|
-
target,
|
|
211
|
-
message: `document declares unknown mode ${quoteUntrusted(JSON.stringify(declaredNonString), 40)} — use one of: tutorial, how-to, reference, explanation`,
|
|
212
|
-
});
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
if (declared !== undefined &&
|
|
216
|
-
!DIATAXIS_MODES.includes(declared)) {
|
|
217
|
-
errors.push({
|
|
218
|
-
file: relPath,
|
|
219
|
-
line: 1,
|
|
220
|
-
target,
|
|
221
|
-
message: `document declares unknown mode ${quoteUntrusted(declared, 40)} — use one of: tutorial, how-to, reference, explanation`,
|
|
222
|
-
});
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
if (declared !== undefined &&
|
|
226
|
-
dirMode !== undefined &&
|
|
227
|
-
declared !== dirMode) {
|
|
228
|
-
errors.push({
|
|
229
|
-
file: relPath,
|
|
230
|
-
line: 1,
|
|
231
|
-
target,
|
|
232
|
-
message: `document is in lat.md/${firstSegment}/ but declares mode: ${declared} — the mode must match the directory that holds it`,
|
|
233
|
-
});
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
const mode = (declared ?? dirMode);
|
|
237
|
-
if (mode === undefined)
|
|
238
|
-
continue;
|
|
239
|
-
const tree = parse(content);
|
|
240
|
-
if (mode === 'how-to') {
|
|
241
|
-
if (!orderedListPresent(tree)) {
|
|
242
|
-
errors.push({
|
|
243
|
-
file: relPath,
|
|
244
|
-
line: 1,
|
|
245
|
-
target,
|
|
246
|
-
message: `a how-to must give ordered steps — add a numbered list`,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (mode === 'tutorial') {
|
|
252
|
-
if (!orderedListPresent(tree)) {
|
|
253
|
-
errors.push({
|
|
254
|
-
file: relPath,
|
|
255
|
-
line: 1,
|
|
256
|
-
target,
|
|
257
|
-
message: `a tutorial must give ordered steps — add a numbered list`,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
if (!outcomeStated(tree)) {
|
|
261
|
-
errors.push({
|
|
262
|
-
file: relPath,
|
|
263
|
-
line: 1,
|
|
264
|
-
target,
|
|
265
|
-
message: `a tutorial must state its outcome — add a heading or sentence saying what the reader will have at the end`,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
if (mode === 'reference') {
|
|
271
|
-
for (const offender of extraParagraphs(tree)) {
|
|
272
|
-
errors.push({
|
|
273
|
-
file: relPath,
|
|
274
|
-
line: offender.line,
|
|
275
|
-
target,
|
|
276
|
-
message: `a reference must not contain narrative prose — this is a second paragraph under "${offender.heading}"; use a list, a table, or a code block instead`,
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
if (mode === 'explanation') {
|
|
282
|
-
const hits = findImperativeHits(tree, content);
|
|
283
|
-
const capped = hits.slice(0, MAX_IMPERATIVE_ERRORS);
|
|
284
|
-
for (const hit of capped) {
|
|
285
|
-
errors.push({
|
|
286
|
-
file: relPath,
|
|
287
|
-
line: hit.line,
|
|
288
|
-
target,
|
|
289
|
-
message: `an explanation must not give commands — line starts with the imperative "${hit.verb}"; describe what happens instead, or move this to a how-to`,
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
if (hits.length > MAX_IMPERATIVE_ERRORS) {
|
|
293
|
-
errors.push({
|
|
294
|
-
file: relPath,
|
|
295
|
-
line: 1,
|
|
296
|
-
target,
|
|
297
|
-
message: `capped at ${MAX_IMPERATIVE_ERRORS} imperative-command errors for this document — fix these first, then re-run`,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return errors;
|
|
303
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Styler } from '../context.js';
|
|
2
|
-
import type { CheckError } from './check.js';
|
|
3
|
-
/**
|
|
4
|
-
* Who wrote a document, and whether a person has checked it.
|
|
5
|
-
*
|
|
6
|
-
* lat.md states that agents write the graph. Without this field an unmarked
|
|
7
|
-
* claim written by an agent reaches the model carrying exactly the authority
|
|
8
|
-
* of one a person read and approved.
|
|
9
|
-
*/
|
|
10
|
-
export declare const DOC_STATUSES: readonly ["human-reviewed", "agent-extracted"];
|
|
11
|
-
export type DocStatus = (typeof DOC_STATUSES)[number];
|
|
12
|
-
export type DocProvenance = {
|
|
13
|
-
/** Raw `status` value, which may not be one this build understands. */
|
|
14
|
-
status?: string;
|
|
15
|
-
/** Raw `reviewed-hash` value, which may not be hex. */
|
|
16
|
-
reviewedHash?: string;
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Read the provenance fields out of a document's frontmatter.
|
|
20
|
-
*
|
|
21
|
-
* Fields live under the top-level `lat:` mapping, so they are read off
|
|
22
|
-
* `LatFrontmatter.raw` rather than being promoted to named fields. Adding a
|
|
23
|
-
* named field would mean editing `parseFrontmatter`, and keeping that function
|
|
24
|
-
* closed to per-feature edits is the whole reason `raw` exists.
|
|
25
|
-
*/
|
|
26
|
-
export declare function readProvenance(content: string): DocProvenance;
|
|
27
|
-
/**
|
|
28
|
-
* Hash the prose a review actually covered.
|
|
29
|
-
*
|
|
30
|
-
* A plain `status` field becomes a lie the moment an agent edits the document:
|
|
31
|
-
* the field still says a person checked the text, but the text is no longer
|
|
32
|
-
* the text that person read. Capturing the content at review time turns that
|
|
33
|
-
* silent failure into a check.
|
|
34
|
-
*
|
|
35
|
-
* Frontmatter is excluded deliberately: adding an unrelated frontmatter key
|
|
36
|
-
* does not change a single claim in the prose, and invalidating a review for
|
|
37
|
-
* it would train authors to re-stamp the hash without re-reading — which
|
|
38
|
-
* costs the field its meaning.
|
|
39
|
-
*
|
|
40
|
-
* Heading TEXT is excluded for the same reason — re-titling a section changes
|
|
41
|
-
* no claim in the prose. But a heading LINE is not: adding or removing a
|
|
42
|
-
* heading changes the document's structure (a new section exists that no one
|
|
43
|
-
* has reviewed), and that must flip the hash even though no non-heading line
|
|
44
|
-
* changed. So each heading line is reduced to its `#` marker (which carries
|
|
45
|
-
* its level and position) rather than dropped outright — retitling a section
|
|
46
|
-
* leaves the marker alone, but appending or removing a heading changes the
|
|
47
|
-
* sequence of markers and therefore the hash. (Swapping two headings of the
|
|
48
|
-
* same level produces the same marker sequence and is not detected — a
|
|
49
|
-
* narrower version of the blind spot this fix closes.)
|
|
50
|
-
*/
|
|
51
|
-
export declare function hashReviewedBody(content: string): string;
|
|
52
|
-
export type ProvenanceNote = {
|
|
53
|
-
kind: 'unreviewed' | 'stale' | 'reviewed';
|
|
54
|
-
text: string;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* The one-line provenance annotation for `lat section` and `lat search`, or
|
|
58
|
-
* null when the document says nothing about its provenance.
|
|
59
|
-
*
|
|
60
|
-
* A document with no `status` produces nothing at all. Most documents in most
|
|
61
|
-
* repositories have no status, and a line on every one of them would be noise
|
|
62
|
-
* that readers learn to skip — which would cost the warning its force on the
|
|
63
|
-
* documents that do carry one.
|
|
64
|
-
*/
|
|
65
|
-
export declare function provenanceNote(content: string): ProvenanceNote | null;
|
|
66
|
-
/** Colourize a note for terminal output. */
|
|
67
|
-
export declare function formatProvenanceNote(note: ProvenanceNote, s: Styler): string;
|
|
68
|
-
/**
|
|
69
|
-
* Report documents whose recorded review no longer describes their text.
|
|
70
|
-
*
|
|
71
|
-
* This is a static validation. It needs no history and no database, and it
|
|
72
|
-
* catches most of what a temporal graph would answer.
|
|
73
|
-
*/
|
|
74
|
-
export declare function checkStatus(latticeDir: string, projectRoot?: string): Promise<CheckError[]>;
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { dirname, relative } from 'node:path';
|
|
4
|
-
import { listLatticeFiles, parseFrontmatter } from '../lattice.js';
|
|
5
|
-
import { toPosix } from '../walk.js';
|
|
6
|
-
import { quoteUntrusted } from '../untrusted.js';
|
|
7
|
-
import { fencedLineMask } from './gen-index.js';
|
|
8
|
-
/**
|
|
9
|
-
* Who wrote a document, and whether a person has checked it.
|
|
10
|
-
*
|
|
11
|
-
* lat.md states that agents write the graph. Without this field an unmarked
|
|
12
|
-
* claim written by an agent reaches the model carrying exactly the authority
|
|
13
|
-
* of one a person read and approved.
|
|
14
|
-
*/
|
|
15
|
-
export const DOC_STATUSES = ['human-reviewed', 'agent-extracted'];
|
|
16
|
-
/**
|
|
17
|
-
* The shortest `reviewed-hash` prefix that is accepted as a match. A full
|
|
18
|
-
* SHA-256 is 64 hex characters and unpleasant to keep in frontmatter, so an
|
|
19
|
-
* author may record an abbreviated form. Eight characters is 32 bits — far
|
|
20
|
-
* past accidental collision for the handful of revisions one document sees,
|
|
21
|
-
* and this value is a staleness signal, not a security boundary.
|
|
22
|
-
*/
|
|
23
|
-
const MIN_HASH_PREFIX = 8;
|
|
24
|
-
const HEX = /^[0-9a-f]+$/i;
|
|
25
|
-
/**
|
|
26
|
-
* Read the provenance fields out of a document's frontmatter.
|
|
27
|
-
*
|
|
28
|
-
* Fields live under the top-level `lat:` mapping, so they are read off
|
|
29
|
-
* `LatFrontmatter.raw` rather than being promoted to named fields. Adding a
|
|
30
|
-
* named field would mean editing `parseFrontmatter`, and keeping that function
|
|
31
|
-
* closed to per-feature edits is the whole reason `raw` exists.
|
|
32
|
-
*/
|
|
33
|
-
export function readProvenance(content) {
|
|
34
|
-
const raw = parseFrontmatter(content).raw;
|
|
35
|
-
const result = {};
|
|
36
|
-
const status = raw['status'];
|
|
37
|
-
if (typeof status === 'string')
|
|
38
|
-
result.status = status;
|
|
39
|
-
const hash = raw['reviewed-hash'];
|
|
40
|
-
if (typeof hash === 'string')
|
|
41
|
-
result.reviewedHash = hash;
|
|
42
|
-
else if (typeof hash === 'number')
|
|
43
|
-
result.reviewedHash = String(hash);
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Hash the prose a review actually covered.
|
|
48
|
-
*
|
|
49
|
-
* A plain `status` field becomes a lie the moment an agent edits the document:
|
|
50
|
-
* the field still says a person checked the text, but the text is no longer
|
|
51
|
-
* the text that person read. Capturing the content at review time turns that
|
|
52
|
-
* silent failure into a check.
|
|
53
|
-
*
|
|
54
|
-
* Frontmatter is excluded deliberately: adding an unrelated frontmatter key
|
|
55
|
-
* does not change a single claim in the prose, and invalidating a review for
|
|
56
|
-
* it would train authors to re-stamp the hash without re-reading — which
|
|
57
|
-
* costs the field its meaning.
|
|
58
|
-
*
|
|
59
|
-
* Heading TEXT is excluded for the same reason — re-titling a section changes
|
|
60
|
-
* no claim in the prose. But a heading LINE is not: adding or removing a
|
|
61
|
-
* heading changes the document's structure (a new section exists that no one
|
|
62
|
-
* has reviewed), and that must flip the hash even though no non-heading line
|
|
63
|
-
* changed. So each heading line is reduced to its `#` marker (which carries
|
|
64
|
-
* its level and position) rather than dropped outright — retitling a section
|
|
65
|
-
* leaves the marker alone, but appending or removing a heading changes the
|
|
66
|
-
* sequence of markers and therefore the hash. (Swapping two headings of the
|
|
67
|
-
* same level produces the same marker sequence and is not detected — a
|
|
68
|
-
* narrower version of the blind spot this fix closes.)
|
|
69
|
-
*/
|
|
70
|
-
export function hashReviewedBody(content) {
|
|
71
|
-
// Normalize line endings BEFORE stripping frontmatter: the delimiter regex
|
|
72
|
-
// is written with bare \n, so on a CRLF-saved document it would not match
|
|
73
|
-
// and the whole frontmatter block — reviewed-hash included — would be
|
|
74
|
-
// hashed as body, making every such review spuriously stale.
|
|
75
|
-
const normalized = content.replace(/\r\n/g, '\n');
|
|
76
|
-
const withoutFrontmatter = normalized.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
77
|
-
const lines = withoutFrontmatter.split('\n');
|
|
78
|
-
// A `#`-prefixed line inside a fenced code block is a shell comment, not a
|
|
79
|
-
// heading. Collapsing it would hand an editor a free, unhashed rewrite slot
|
|
80
|
-
// in every fenced example. The same mask the index reader and writer share.
|
|
81
|
-
const fenced = fencedLineMask(lines);
|
|
82
|
-
const body = lines
|
|
83
|
-
.map((line, i) => {
|
|
84
|
-
if (fenced[i])
|
|
85
|
-
return line;
|
|
86
|
-
const heading = /^(#{1,6})\s/.exec(line);
|
|
87
|
-
return heading ? heading[1] : line;
|
|
88
|
-
})
|
|
89
|
-
// Trailing whitespace is invisible in a diff and must not flip a review.
|
|
90
|
-
.map((line) => line.replace(/[ \t]+$/, ''))
|
|
91
|
-
.join('\n')
|
|
92
|
-
.trim();
|
|
93
|
-
return createHash('sha256').update(body, 'utf-8').digest('hex');
|
|
94
|
-
}
|
|
95
|
-
function hashMatches(recorded, actual) {
|
|
96
|
-
const want = recorded.trim().toLowerCase();
|
|
97
|
-
if (want.length < MIN_HASH_PREFIX || !HEX.test(want))
|
|
98
|
-
return false;
|
|
99
|
-
return actual.startsWith(want);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* The one-line provenance annotation for `lat section` and `lat search`, or
|
|
103
|
-
* null when the document says nothing about its provenance.
|
|
104
|
-
*
|
|
105
|
-
* A document with no `status` produces nothing at all. Most documents in most
|
|
106
|
-
* repositories have no status, and a line on every one of them would be noise
|
|
107
|
-
* that readers learn to skip — which would cost the warning its force on the
|
|
108
|
-
* documents that do carry one.
|
|
109
|
-
*/
|
|
110
|
-
export function provenanceNote(content) {
|
|
111
|
-
const { status, reviewedHash } = readProvenance(content);
|
|
112
|
-
if (status === undefined)
|
|
113
|
-
return null;
|
|
114
|
-
if (status === 'agent-extracted') {
|
|
115
|
-
return {
|
|
116
|
-
kind: 'unreviewed',
|
|
117
|
-
text: '[unreviewed -- written by an agent, not checked by a person]',
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if (status === 'human-reviewed') {
|
|
121
|
-
// No hash means an older tree that predates the field. Saying nothing is
|
|
122
|
-
// deliberate: an upgrade must not repaint an existing graph with warnings.
|
|
123
|
-
if (reviewedHash === undefined) {
|
|
124
|
-
return { kind: 'reviewed', text: '[human-reviewed]' };
|
|
125
|
-
}
|
|
126
|
-
if (hashMatches(reviewedHash, hashReviewedBody(content))) {
|
|
127
|
-
return { kind: 'reviewed', text: '[human-reviewed]' };
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
kind: 'stale',
|
|
131
|
-
text: '[stale review -- the text changed after a person checked it]',
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
// An unknown value is repository text and is quoted as such. `lat check
|
|
135
|
-
// status` reports it; the reader is told only that it means nothing here.
|
|
136
|
-
return {
|
|
137
|
-
kind: 'unreviewed',
|
|
138
|
-
text: `[unrecognized status ${quoteUntrusted(status, 40)} -- treat as unreviewed]`,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
/** Colourize a note for terminal output. */
|
|
142
|
-
export function formatProvenanceNote(note, s) {
|
|
143
|
-
if (note.kind === 'reviewed')
|
|
144
|
-
return s.green(note.text);
|
|
145
|
-
return s.yellow(note.text);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Report documents whose recorded review no longer describes their text.
|
|
149
|
-
*
|
|
150
|
-
* This is a static validation. It needs no history and no database, and it
|
|
151
|
-
* catches most of what a temporal graph would answer.
|
|
152
|
-
*/
|
|
153
|
-
export async function checkStatus(latticeDir, projectRoot = dirname(latticeDir)) {
|
|
154
|
-
const files = await listLatticeFiles(latticeDir);
|
|
155
|
-
const errors = [];
|
|
156
|
-
for (const file of files) {
|
|
157
|
-
const content = await readFile(file, 'utf-8');
|
|
158
|
-
const relPath = relative(process.cwd(), file);
|
|
159
|
-
const target = toPosix(relative(projectRoot, file)).replace(/\.md$/, '');
|
|
160
|
-
const { status, reviewedHash } = readProvenance(content);
|
|
161
|
-
if (status === undefined) {
|
|
162
|
-
if (reviewedHash !== undefined) {
|
|
163
|
-
errors.push({
|
|
164
|
-
file: relPath,
|
|
165
|
-
line: 1,
|
|
166
|
-
target,
|
|
167
|
-
message: `document records a reviewed-hash but no status — add "status: human-reviewed", or drop the hash`,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (!DOC_STATUSES.includes(status)) {
|
|
173
|
-
errors.push({
|
|
174
|
-
file: relPath,
|
|
175
|
-
line: 1,
|
|
176
|
-
target,
|
|
177
|
-
message: `document declares unknown status ${quoteUntrusted(status, 40)} — use one of: human-reviewed, agent-extracted`,
|
|
178
|
-
});
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
if (status === 'agent-extracted') {
|
|
182
|
-
if (reviewedHash !== undefined) {
|
|
183
|
-
errors.push({
|
|
184
|
-
file: relPath,
|
|
185
|
-
line: 1,
|
|
186
|
-
target,
|
|
187
|
-
message: `document is agent-extracted but records a reviewed-hash — a hash records that a person checked the text, so set "status: human-reviewed" or drop the hash`,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
// human-reviewed. No hash is not an error: existing trees must not turn
|
|
193
|
-
// red on upgrade. It simply buys no staleness detection.
|
|
194
|
-
if (reviewedHash === undefined)
|
|
195
|
-
continue;
|
|
196
|
-
const actual = hashReviewedBody(content);
|
|
197
|
-
const recorded = reviewedHash.trim().toLowerCase();
|
|
198
|
-
if (!HEX.test(recorded) || recorded.length < MIN_HASH_PREFIX) {
|
|
199
|
-
errors.push({
|
|
200
|
-
file: relPath,
|
|
201
|
-
line: 1,
|
|
202
|
-
target,
|
|
203
|
-
message: `reviewed-hash must be at least ${MIN_HASH_PREFIX} hex characters — record "reviewed-hash: ${actual}"`,
|
|
204
|
-
});
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
if (!actual.startsWith(recorded)) {
|
|
208
|
-
errors.push({
|
|
209
|
-
file: relPath,
|
|
210
|
-
line: 1,
|
|
211
|
-
target,
|
|
212
|
-
message: `stale review — the text changed after it was reviewed. Re-read it, then record "reviewed-hash: ${actual}"`,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return errors;
|
|
217
|
-
}
|
package/dist/src/cli/check.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { CmdContext, CmdResult } from '../context.js';
|
|
2
|
-
export type CheckError = {
|
|
3
|
-
file: string;
|
|
4
|
-
line: number;
|
|
5
|
-
target: string;
|
|
6
|
-
message: string;
|
|
7
|
-
};
|
|
8
|
-
/** Format an ambiguous-ref error as structured markdown-like text. */
|
|
9
|
-
export declare function ambiguousRefMessage(target: string, candidates: string[], suggested: string | null): string;
|
|
10
|
-
/** File counts grouped by extension (e.g. { ".ts": 5, ".py": 2 }). */
|
|
11
|
-
export type FileStats = Record<string, number>;
|
|
12
|
-
export type CheckResult = {
|
|
13
|
-
errors: CheckError[];
|
|
14
|
-
files: FileStats;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Try resolving a wiki link target as a source code reference.
|
|
18
|
-
* Returns null if the reference is valid, or an error message string.
|
|
19
|
-
*/
|
|
20
|
-
export declare function sourceRefError(target: string, projectRoot: string): Promise<string | null>;
|
|
21
|
-
export declare function checkMd(latticeDir: string, projectRoot?: string): Promise<CheckResult>;
|
|
22
|
-
export declare function checkLinks(latticeDir: string): Promise<CheckError[]>;
|
|
23
|
-
export declare function checkCodeRefs(latticeDir: string, projectRoot?: string): Promise<CheckResult>;
|
|
24
|
-
export type IndexError = {
|
|
25
|
-
dir: string;
|
|
26
|
-
message: string;
|
|
27
|
-
snippet?: string;
|
|
28
|
-
};
|
|
29
|
-
export type CheckIndexOptions = {
|
|
30
|
-
/**
|
|
31
|
-
* Generate/rewrite index files instead of reporting errors for them.
|
|
32
|
-
* Non-.md-file errors are still reported — --fix only ever writes markdown.
|
|
33
|
-
*/
|
|
34
|
-
fix?: boolean;
|
|
35
|
-
};
|
|
36
|
-
export declare function checkIndex(latticeDir: string, opts?: CheckIndexOptions): Promise<IndexError[]>;
|
|
37
|
-
export declare function checkSections(latticeDir: string, projectRoot?: string): Promise<CheckError[]>;
|
|
38
|
-
export declare function checkAllCommand(ctx: CmdContext, opts?: CheckIndexOptions): Promise<CmdResult>;
|
|
39
|
-
export declare function checkMdCommand(ctx: CmdContext): Promise<CmdResult>;
|
|
40
|
-
export declare function checkLinksCommand(ctx: CmdContext): Promise<CmdResult>;
|
|
41
|
-
export declare function checkCodeRefsCommand(ctx: CmdContext): Promise<CmdResult>;
|
|
42
|
-
export declare function checkIndexCommand(ctx: CmdContext, opts?: CheckIndexOptions): Promise<CmdResult>;
|
|
43
|
-
export declare function checkSectionsCommand(ctx: CmdContext): Promise<CmdResult>;
|
|
44
|
-
export declare function checkModeCommand(ctx: CmdContext): Promise<CmdResult>;
|
|
45
|
-
export declare function checkStatusCommand(ctx: CmdContext): Promise<CmdResult>;
|