@hawkeyexl/manni 4.11.0 → 4.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{batch-UAULUMGH.js → batch-KMGZMIAQ.js} +20 -19
- package/dist/build-NO4AWCYG.js +36 -0
- package/dist/calibrate-XQUG5XAK.js +41 -0
- package/dist/capture-5XE3ZMXK.js +38 -0
- package/dist/{check-YEOYBFST.js → check-HTNPLWOV.js} +19 -18
- package/dist/check-RJ45IBA6.js +34 -0
- package/dist/{check-VELUQAUW.js → check-W24BQNCT.js} +35 -34
- package/dist/{check-VELUQAUW.js.map → check-W24BQNCT.js.map} +1 -1
- package/dist/check-WFXSXICD.js +30 -0
- package/dist/{chunk-IGSHYP74.js → chunk-23P7KMJM.js} +4 -4
- package/dist/{chunk-HA6MQMOY.js → chunk-24J7TYPU.js} +6 -6
- package/dist/{chunk-PCS4VJBV.js → chunk-37QJLVS3.js} +9 -9
- package/dist/{chunk-4CK6ZSOK.js → chunk-3P6KCU36.js} +3 -3
- package/dist/{chunk-54F74XR3.js → chunk-5JBVFWVP.js} +19 -19
- package/dist/{chunk-B7XYNRJQ.js → chunk-6KIYVVKL.js} +2 -2
- package/dist/{chunk-J6IDQGJL.js → chunk-6TVH4FI7.js} +469 -85
- package/dist/chunk-6TVH4FI7.js.map +1 -0
- package/dist/{chunk-GDVZ5VII.js → chunk-7A452BPZ.js} +4 -4
- package/dist/{chunk-M42DZCOU.js → chunk-7FCLXEAQ.js} +2 -2
- package/dist/{chunk-2MJ62AYQ.js → chunk-7MCQHTQ5.js} +4 -3
- package/dist/chunk-7MCQHTQ5.js.map +1 -0
- package/dist/{chunk-LBSCW232.js → chunk-7NXPQKSB.js} +7 -7
- package/dist/{chunk-OPXWPJDA.js → chunk-A3TEDWBZ.js} +14 -14
- package/dist/{chunk-BBT6AVUG.js → chunk-BHHXU2D2.js} +2 -2
- package/dist/{chunk-D4N2V43Z.js → chunk-CEI2J42X.js} +13 -7
- package/dist/chunk-CEI2J42X.js.map +1 -0
- package/dist/{chunk-FQXWVS6J.js → chunk-CMMBWHT2.js} +9 -9
- package/dist/{chunk-EIFCP6CZ.js → chunk-CO47QJKZ.js} +2 -2
- package/dist/{chunk-2DRHT73U.js → chunk-CVZMKWZ5.js} +913 -1398
- package/dist/chunk-CVZMKWZ5.js.map +1 -0
- package/dist/{chunk-ADMEPUBT.js → chunk-CXWTNT2O.js} +3 -3
- package/dist/{chunk-LKP7QDFN.js → chunk-DAQTRAP5.js} +4 -4
- package/dist/chunk-DSWKBZWW.js +16 -0
- package/dist/chunk-DSWKBZWW.js.map +1 -0
- package/dist/{chunk-PWBH7DCQ.js → chunk-EESH6COU.js} +4 -4
- package/dist/{chunk-JPQDNYXH.js → chunk-EM67O2ET.js} +8 -2
- package/dist/chunk-EM67O2ET.js.map +1 -0
- package/dist/{chunk-HQR2ZBHW.js → chunk-I2XQRRP7.js} +36 -7
- package/dist/chunk-I2XQRRP7.js.map +1 -0
- package/dist/{chunk-NCPWXHDO.js → chunk-JEUFYSFQ.js} +4 -4
- package/dist/{chunk-2IR4T5PO.js → chunk-JJ4RSDSY.js} +2 -2
- package/dist/chunk-KCB5JCK4.js +2272 -0
- package/dist/chunk-KCB5JCK4.js.map +1 -0
- package/dist/{chunk-VSEBFHAY.js → chunk-KFKL4VTL.js} +11369 -10218
- package/dist/chunk-KFKL4VTL.js.map +1 -0
- package/dist/{chunk-PCQ7ELJH.js → chunk-L2TD7DZB.js} +109 -5
- package/dist/chunk-L2TD7DZB.js.map +1 -0
- package/dist/{chunk-WDWXAYVH.js → chunk-L3RLGGRK.js} +4 -4
- package/dist/{chunk-T7JAOYE5.js → chunk-L75CAZG4.js} +6 -6
- package/dist/{chunk-U7CTFN2J.js → chunk-MYRPMSOX.js} +7 -7
- package/dist/{chunk-Y6DOMTQD.js → chunk-NCF5NQV5.js} +27 -27
- package/dist/chunk-NCF5NQV5.js.map +1 -0
- package/dist/{chunk-WQWKYAAK.js → chunk-NUQF5F5J.js} +2 -2
- package/dist/{chunk-FUCPZVRY.js → chunk-OEN6FBUW.js} +2 -2
- package/dist/{chunk-FBMZJEB3.js → chunk-OKMTUAWO.js} +4 -4
- package/dist/{chunk-QLWC7MKD.js → chunk-OTJOBZJ5.js} +135 -135
- package/dist/chunk-OTJOBZJ5.js.map +1 -0
- package/dist/{chunk-R4WXQIOZ.js → chunk-PCEM5FOZ.js} +3 -3
- package/dist/{chunk-4D5IZSXM.js → chunk-PXNCRGUL.js} +3 -3
- package/dist/chunk-Q2QC5AZB.js +1868 -0
- package/dist/chunk-Q2QC5AZB.js.map +1 -0
- package/dist/{chunk-ODRPL3WB.js → chunk-Q3ODX5PF.js} +2 -2
- package/dist/{chunk-KGEQJ5CC.js → chunk-RRFFUWDL.js} +8 -8
- package/dist/{chunk-NSBXVPZL.js → chunk-S3XUYW5K.js} +17 -17
- package/dist/{chunk-LPIF5LIE.js → chunk-SAU2WQFC.js} +2 -2
- package/dist/{chunk-MSRU4D4P.js → chunk-SFLICIQV.js} +2 -2
- package/dist/{chunk-NGTVREIH.js → chunk-U6IHLEWT.js} +2 -2
- package/dist/{chunk-QCHVR4ZM.js → chunk-VM7VAFJW.js} +33 -7
- package/dist/chunk-VM7VAFJW.js.map +1 -0
- package/dist/{chunk-6HWBRZIN.js → chunk-VQYGLU4C.js} +252 -193
- package/dist/chunk-VQYGLU4C.js.map +1 -0
- package/dist/{chunk-2IAZEB45.js → chunk-WGMFDG6U.js} +229 -821
- package/dist/chunk-WGMFDG6U.js.map +1 -0
- package/dist/{chunk-GV56WGL2.js → chunk-WO4JYWZK.js} +1036 -883
- package/dist/chunk-WO4JYWZK.js.map +1 -0
- package/dist/chunk-XYRUDFKS.js +685 -0
- package/dist/chunk-XYRUDFKS.js.map +1 -0
- package/dist/{chunk-VQK4VHLF.js → chunk-YQV75FIL.js} +2 -2
- package/dist/chunk-YUTVAMWW.js +2 -0
- package/dist/{chunk-RLT5SEML.js → chunk-Z5MZCCTT.js} +6 -6
- package/dist/{chunk-BKVHX6FU.js → chunk-ZIRBFXDW.js} +5 -10
- package/dist/chunk-ZIRBFXDW.js.map +1 -0
- package/dist/{cli-O4ABTN4Z.js → cli-236TGVJG.js} +31 -30
- package/dist/{cli-O4ABTN4Z.js.map → cli-236TGVJG.js.map} +1 -1
- package/dist/{cli-3BTCK4AB.js → cli-3FAPJBEY.js} +27 -26
- package/dist/{cli-3BTCK4AB.js.map → cli-3FAPJBEY.js.map} +1 -1
- package/dist/{cli-JJMOVIKS.js → cli-BS43EVCD.js} +14 -14
- package/dist/{cli-RORDPAPE.js → cli-CMR4FYF6.js} +59 -38
- package/dist/cli-CMR4FYF6.js.map +1 -0
- package/dist/{cli-ONTC5PKT.js → cli-FX53PBQ3.js} +9 -9
- package/dist/{cli-6KZTHWGP.js → cli-IQNJLKSN.js} +37 -36
- package/dist/{cli-6KZTHWGP.js.map → cli-IQNJLKSN.js.map} +1 -1
- package/dist/{cli-4MF37HAQ.js → cli-KOMXVPXX.js} +26 -25
- package/dist/{cli-4MF37HAQ.js.map → cli-KOMXVPXX.js.map} +1 -1
- package/dist/{cli-I62SRH3R.js → cli-NGL63E53.js} +14 -13
- package/dist/{cli-DRMZBZLB.js → cli-QPGS2MR5.js} +43 -42
- package/dist/{cli-DRMZBZLB.js.map → cli-QPGS2MR5.js.map} +1 -1
- package/dist/{cli-VID7PJS3.js → cli-RKQX4TI3.js} +23 -22
- package/dist/{cli-VID7PJS3.js.map → cli-RKQX4TI3.js.map} +1 -1
- package/dist/{cli-VUKMWSSF.js → cli-WNEI5L7P.js} +4 -4
- package/dist/cli.js +19 -13
- package/dist/cli.js.map +1 -1
- package/dist/{config-XDA42RJL.js → config-JJW75SBX.js} +5 -5
- package/dist/docmeta.js +13 -12
- package/dist/docmeta.js.map +1 -1
- package/dist/github-4UR67MEN.js +35 -0
- package/dist/github-UPGKMVVF.js +30 -0
- package/dist/graph/runtime.d.ts +4 -1
- package/dist/graph/runtime.js +20 -9
- package/dist/graph/runtime.js.map +1 -1
- package/dist/{host-6GURH5HE.js → host-YSTYO5DX.js} +3 -3
- package/dist/index.d.ts +192 -26
- package/dist/index.js +129 -124
- package/dist/index.js.map +1 -1
- package/dist/{json-BXY44ED7.js → json-DQIELR36.js} +18 -17
- package/dist/labels-XSTJJMSG.js +73 -0
- package/dist/labels-XSTJJMSG.js.map +1 -0
- package/dist/lint-BLBGGOYM.js +34 -0
- package/dist/list-B3RRRWFQ.js +32 -0
- package/dist/list-ZFRT3JQH.js +35 -0
- package/dist/{page-EV7OUBAU.js → page-5ISEVJR5.js} +18 -16
- package/dist/{prepare-JHJDJB6I.js → prepare-KFXXG2CJ.js} +22 -21
- package/dist/{prepare-JHJDJB6I.js.map → prepare-KFXXG2CJ.js.map} +1 -1
- package/dist/{pretty-Q5Y2PA64.js → pretty-Y7CGQLAF.js} +18 -17
- package/dist/{pretty-SCRK66M5.js → pretty-ZISH3Q4F.js} +18 -17
- package/dist/{provider-527CO4DM.js → provider-LBX4IXGX.js} +3 -3
- package/dist/{release-3D5PK6M7.js → release-VV3UTKE5.js} +3 -3
- package/dist/{reporters-M6LJ2IYU.js → reporters-26H3N2KW.js} +3 -3
- package/dist/{reporters-A5ADKDYR.js → reporters-4STXJJE2.js} +16 -15
- package/dist/{reporters-RBYTASMI.js → reporters-74B4U2GZ.js} +7 -7
- package/dist/run-DVGTKM52.js +37 -0
- package/dist/{term-CQAGNG3Q.js → term-PLJEYJQV.js} +981 -141
- package/dist/term-PLJEYJQV.js.map +1 -0
- package/dist/validate-CJNFQHMD.js +19 -0
- package/package.json +3 -2
- package/plugin/manni/.claude-plugin/plugin.json +1 -1
- package/shapes/graph/shapes-1.1.0.ttl +785 -0
- package/dist/build-QSPNK5AL.js +0 -35
- package/dist/calibrate-KXN4URPM.js +0 -40
- package/dist/capture-JHTSUPUC.js +0 -37
- package/dist/check-MDGXEUWL.js +0 -20
- package/dist/check-WOQRKNZK.js +0 -29
- package/dist/chunk-2DRHT73U.js.map +0 -1
- package/dist/chunk-2IAZEB45.js.map +0 -1
- package/dist/chunk-2MJ62AYQ.js.map +0 -1
- package/dist/chunk-4VBSTXN6.js +0 -392
- package/dist/chunk-4VBSTXN6.js.map +0 -1
- package/dist/chunk-6HWBRZIN.js.map +0 -1
- package/dist/chunk-BKVHX6FU.js.map +0 -1
- package/dist/chunk-D4N2V43Z.js.map +0 -1
- package/dist/chunk-EFW7CAG4.js +0 -387
- package/dist/chunk-EFW7CAG4.js.map +0 -1
- package/dist/chunk-GV56WGL2.js.map +0 -1
- package/dist/chunk-HQR2ZBHW.js.map +0 -1
- package/dist/chunk-J6IDQGJL.js.map +0 -1
- package/dist/chunk-JPQDNYXH.js.map +0 -1
- package/dist/chunk-JROBZ7JA.js +0 -818
- package/dist/chunk-JROBZ7JA.js.map +0 -1
- package/dist/chunk-PCQ7ELJH.js.map +0 -1
- package/dist/chunk-QCHVR4ZM.js.map +0 -1
- package/dist/chunk-QLWC7MKD.js.map +0 -1
- package/dist/chunk-TU2WUBVZ.js +0 -2
- package/dist/chunk-VSEBFHAY.js.map +0 -1
- package/dist/chunk-Y6DOMTQD.js.map +0 -1
- package/dist/cli-RORDPAPE.js.map +0 -1
- package/dist/github-RY3FRA6P.js +0 -29
- package/dist/github-YKQSH7FS.js +0 -34
- package/dist/lint-YJ2L22BW.js +0 -33
- package/dist/list-NSG24VVX.js +0 -31
- package/dist/list-V6EGCSHX.js +0 -34
- package/dist/run-BUE2DDXN.js +0 -36
- package/dist/term-CQAGNG3Q.js.map +0 -1
- package/dist/validate-ZBW44RHT.js +0 -18
- /package/dist/{batch-UAULUMGH.js.map → batch-KMGZMIAQ.js.map} +0 -0
- /package/dist/{build-QSPNK5AL.js.map → build-NO4AWCYG.js.map} +0 -0
- /package/dist/{calibrate-KXN4URPM.js.map → calibrate-XQUG5XAK.js.map} +0 -0
- /package/dist/{capture-JHTSUPUC.js.map → capture-5XE3ZMXK.js.map} +0 -0
- /package/dist/{check-MDGXEUWL.js.map → check-HTNPLWOV.js.map} +0 -0
- /package/dist/{check-WOQRKNZK.js.map → check-RJ45IBA6.js.map} +0 -0
- /package/dist/{check-YEOYBFST.js.map → check-WFXSXICD.js.map} +0 -0
- /package/dist/{chunk-IGSHYP74.js.map → chunk-23P7KMJM.js.map} +0 -0
- /package/dist/{chunk-HA6MQMOY.js.map → chunk-24J7TYPU.js.map} +0 -0
- /package/dist/{chunk-PCS4VJBV.js.map → chunk-37QJLVS3.js.map} +0 -0
- /package/dist/{chunk-4CK6ZSOK.js.map → chunk-3P6KCU36.js.map} +0 -0
- /package/dist/{chunk-54F74XR3.js.map → chunk-5JBVFWVP.js.map} +0 -0
- /package/dist/{chunk-B7XYNRJQ.js.map → chunk-6KIYVVKL.js.map} +0 -0
- /package/dist/{chunk-GDVZ5VII.js.map → chunk-7A452BPZ.js.map} +0 -0
- /package/dist/{chunk-M42DZCOU.js.map → chunk-7FCLXEAQ.js.map} +0 -0
- /package/dist/{chunk-LBSCW232.js.map → chunk-7NXPQKSB.js.map} +0 -0
- /package/dist/{chunk-OPXWPJDA.js.map → chunk-A3TEDWBZ.js.map} +0 -0
- /package/dist/{chunk-BBT6AVUG.js.map → chunk-BHHXU2D2.js.map} +0 -0
- /package/dist/{chunk-FQXWVS6J.js.map → chunk-CMMBWHT2.js.map} +0 -0
- /package/dist/{chunk-EIFCP6CZ.js.map → chunk-CO47QJKZ.js.map} +0 -0
- /package/dist/{chunk-ADMEPUBT.js.map → chunk-CXWTNT2O.js.map} +0 -0
- /package/dist/{chunk-LKP7QDFN.js.map → chunk-DAQTRAP5.js.map} +0 -0
- /package/dist/{chunk-PWBH7DCQ.js.map → chunk-EESH6COU.js.map} +0 -0
- /package/dist/{chunk-NCPWXHDO.js.map → chunk-JEUFYSFQ.js.map} +0 -0
- /package/dist/{chunk-2IR4T5PO.js.map → chunk-JJ4RSDSY.js.map} +0 -0
- /package/dist/{chunk-WDWXAYVH.js.map → chunk-L3RLGGRK.js.map} +0 -0
- /package/dist/{chunk-T7JAOYE5.js.map → chunk-L75CAZG4.js.map} +0 -0
- /package/dist/{chunk-U7CTFN2J.js.map → chunk-MYRPMSOX.js.map} +0 -0
- /package/dist/{chunk-WQWKYAAK.js.map → chunk-NUQF5F5J.js.map} +0 -0
- /package/dist/{chunk-FUCPZVRY.js.map → chunk-OEN6FBUW.js.map} +0 -0
- /package/dist/{chunk-FBMZJEB3.js.map → chunk-OKMTUAWO.js.map} +0 -0
- /package/dist/{chunk-R4WXQIOZ.js.map → chunk-PCEM5FOZ.js.map} +0 -0
- /package/dist/{chunk-4D5IZSXM.js.map → chunk-PXNCRGUL.js.map} +0 -0
- /package/dist/{chunk-ODRPL3WB.js.map → chunk-Q3ODX5PF.js.map} +0 -0
- /package/dist/{chunk-KGEQJ5CC.js.map → chunk-RRFFUWDL.js.map} +0 -0
- /package/dist/{chunk-NSBXVPZL.js.map → chunk-S3XUYW5K.js.map} +0 -0
- /package/dist/{chunk-LPIF5LIE.js.map → chunk-SAU2WQFC.js.map} +0 -0
- /package/dist/{chunk-MSRU4D4P.js.map → chunk-SFLICIQV.js.map} +0 -0
- /package/dist/{chunk-NGTVREIH.js.map → chunk-U6IHLEWT.js.map} +0 -0
- /package/dist/{chunk-VQK4VHLF.js.map → chunk-YQV75FIL.js.map} +0 -0
- /package/dist/{chunk-TU2WUBVZ.js.map → chunk-YUTVAMWW.js.map} +0 -0
- /package/dist/{chunk-RLT5SEML.js.map → chunk-Z5MZCCTT.js.map} +0 -0
- /package/dist/{cli-JJMOVIKS.js.map → cli-BS43EVCD.js.map} +0 -0
- /package/dist/{cli-ONTC5PKT.js.map → cli-FX53PBQ3.js.map} +0 -0
- /package/dist/{cli-I62SRH3R.js.map → cli-NGL63E53.js.map} +0 -0
- /package/dist/{cli-VUKMWSSF.js.map → cli-WNEI5L7P.js.map} +0 -0
- /package/dist/{config-XDA42RJL.js.map → config-JJW75SBX.js.map} +0 -0
- /package/dist/{github-RY3FRA6P.js.map → github-4UR67MEN.js.map} +0 -0
- /package/dist/{github-YKQSH7FS.js.map → github-UPGKMVVF.js.map} +0 -0
- /package/dist/{host-6GURH5HE.js.map → host-YSTYO5DX.js.map} +0 -0
- /package/dist/{json-BXY44ED7.js.map → json-DQIELR36.js.map} +0 -0
- /package/dist/{lint-YJ2L22BW.js.map → lint-BLBGGOYM.js.map} +0 -0
- /package/dist/{list-NSG24VVX.js.map → list-B3RRRWFQ.js.map} +0 -0
- /package/dist/{list-V6EGCSHX.js.map → list-ZFRT3JQH.js.map} +0 -0
- /package/dist/{page-EV7OUBAU.js.map → page-5ISEVJR5.js.map} +0 -0
- /package/dist/{pretty-Q5Y2PA64.js.map → pretty-Y7CGQLAF.js.map} +0 -0
- /package/dist/{pretty-SCRK66M5.js.map → pretty-ZISH3Q4F.js.map} +0 -0
- /package/dist/{provider-527CO4DM.js.map → provider-LBX4IXGX.js.map} +0 -0
- /package/dist/{release-3D5PK6M7.js.map → release-VV3UTKE5.js.map} +0 -0
- /package/dist/{reporters-A5ADKDYR.js.map → reporters-26H3N2KW.js.map} +0 -0
- /package/dist/{reporters-M6LJ2IYU.js.map → reporters-4STXJJE2.js.map} +0 -0
- /package/dist/{reporters-RBYTASMI.js.map → reporters-74B4U2GZ.js.map} +0 -0
- /package/dist/{run-BUE2DDXN.js.map → run-DVGTKM52.js.map} +0 -0
- /package/dist/{validate-ZBW44RHT.js.map → validate-CJNFQHMD.js.map} +0 -0
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
STDIN,
|
|
5
|
-
UNDETERMINED,
|
|
6
|
-
analyzeDoc,
|
|
7
|
-
assertInputFormat,
|
|
8
|
-
canonicalLanguageTag,
|
|
3
|
+
canonicalLanguage,
|
|
9
4
|
deriveGraph,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
emitLocalizations,
|
|
13
|
-
extractorFor,
|
|
14
|
-
formatOf,
|
|
15
|
-
isLanguageTag,
|
|
16
|
-
isSafeRelativePath,
|
|
17
|
-
mergePage,
|
|
18
|
-
metadataOf,
|
|
19
|
-
mintTreeSections,
|
|
20
|
-
openMetaView,
|
|
21
|
-
parseLocalizations,
|
|
22
|
-
parseTree,
|
|
23
|
-
resolveDocumentSet,
|
|
24
|
-
routesFrom,
|
|
25
|
-
searchIndexFilename,
|
|
26
|
-
vectorIndexFilename
|
|
27
|
-
} from "./chunk-2IAZEB45.js";
|
|
5
|
+
termIndex
|
|
6
|
+
} from "./chunk-WGMFDG6U.js";
|
|
28
7
|
import {
|
|
8
|
+
EmbedderUnavailableError,
|
|
9
|
+
GraphIndex,
|
|
10
|
+
bodyOf,
|
|
11
|
+
buildSearchIndex,
|
|
29
12
|
bundledShapesPath,
|
|
30
13
|
compactIri,
|
|
14
|
+
createLocalEmbedder,
|
|
15
|
+
createMockEmbedder,
|
|
16
|
+
createTrace,
|
|
17
|
+
documentsByLanguage,
|
|
18
|
+
emitSearchIndex,
|
|
19
|
+
encodeVectorIndex,
|
|
31
20
|
expandTerm,
|
|
21
|
+
exportSampleQuestions,
|
|
22
|
+
freshness,
|
|
32
23
|
loadGraph,
|
|
24
|
+
matchList,
|
|
25
|
+
partitionByLanguage,
|
|
33
26
|
storeToQuads,
|
|
34
27
|
validateGraph
|
|
35
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-KCB5JCK4.js";
|
|
36
29
|
import {
|
|
30
|
+
COPIED_SHARE,
|
|
37
31
|
COVERAGE_FIELDS,
|
|
38
|
-
DEFAULT_MODEL,
|
|
39
32
|
GRAPH_NOT_APPLICABLE_TO_VARIANT,
|
|
40
33
|
GRAPH_NOT_SOFTWARE_SUBJECT,
|
|
41
34
|
GraphError,
|
|
@@ -59,32 +52,65 @@ import {
|
|
|
59
52
|
IIRDS_SOURCE,
|
|
60
53
|
IIRDS_TITLE,
|
|
61
54
|
IIRDS_TOPIC,
|
|
55
|
+
LOCALIZATIONS_FILENAME,
|
|
62
56
|
NS,
|
|
63
57
|
PREFIXES,
|
|
64
58
|
RDF_TYPE,
|
|
65
59
|
SECTION_COVERAGE_FIELDS,
|
|
66
60
|
SOFTWARE_SUBJECT_IRIS,
|
|
61
|
+
STDIN,
|
|
67
62
|
STDIN_PATH,
|
|
63
|
+
UNIFORM_COVERAGE_FIELD_NAMES,
|
|
68
64
|
VCARD_NS,
|
|
69
65
|
VCARD_ORGANIZATION,
|
|
70
66
|
VCARD_ORGANIZATION_NAME,
|
|
67
|
+
analyzeDoc,
|
|
68
|
+
assertInputFormat,
|
|
71
69
|
byCodeUnit,
|
|
70
|
+
canonicalLanguageTag,
|
|
71
|
+
copiedPairs,
|
|
72
|
+
documentBase,
|
|
73
|
+
documentSetPatterns,
|
|
74
|
+
emitLocalizations,
|
|
75
|
+
extractorFor,
|
|
76
|
+
formatOf,
|
|
77
|
+
isLanguageTag,
|
|
78
|
+
isSafeRelativePath,
|
|
72
79
|
loadRunConfig,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
mergePage,
|
|
81
|
+
metadataOf,
|
|
82
|
+
openMetaView,
|
|
83
|
+
parseLocalizations,
|
|
84
|
+
questionKey,
|
|
85
|
+
readQuestionFile,
|
|
86
|
+
resolveDocumentSet,
|
|
87
|
+
routesFrom,
|
|
88
|
+
searchIndexFilename,
|
|
89
|
+
vectorIndexFilename
|
|
90
|
+
} from "./chunk-Q2QC5AZB.js";
|
|
91
|
+
import {
|
|
92
|
+
splitBody
|
|
93
|
+
} from "./chunk-VQYGLU4C.js";
|
|
76
94
|
import {
|
|
77
95
|
mergeMetaProvenance
|
|
78
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-7FCLXEAQ.js";
|
|
79
97
|
import {
|
|
98
|
+
findWindows,
|
|
80
99
|
isMissing,
|
|
100
|
+
lineSpec,
|
|
101
|
+
parseLines,
|
|
102
|
+
pinOfLines,
|
|
103
|
+
spellLines,
|
|
81
104
|
spliceManifestValue
|
|
82
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-WO4JYWZK.js";
|
|
106
|
+
import {
|
|
107
|
+
termLabelSource
|
|
108
|
+
} from "./chunk-DSWKBZWW.js";
|
|
83
109
|
import {
|
|
84
110
|
DocmetaError,
|
|
85
111
|
urlManifestMessage,
|
|
86
112
|
writeFileAtomic
|
|
87
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-KFKL4VTL.js";
|
|
88
114
|
import {
|
|
89
115
|
noticeOnce,
|
|
90
116
|
warn
|
|
@@ -94,18 +120,20 @@ import {
|
|
|
94
120
|
assertLocalFlag,
|
|
95
121
|
assertModelHasProvider,
|
|
96
122
|
localNotice,
|
|
123
|
+
noOfflineModel,
|
|
124
|
+
offlineIdentity,
|
|
97
125
|
providerSpecFor,
|
|
98
126
|
resolveIdentity,
|
|
99
127
|
selectProvider
|
|
100
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-VM7VAFJW.js";
|
|
101
129
|
import {
|
|
102
130
|
errorMessage
|
|
103
131
|
} from "./chunk-G3T47CFV.js";
|
|
104
132
|
|
|
105
133
|
// src/graph/commands/export.ts
|
|
106
134
|
import { createHash } from "node:crypto";
|
|
107
|
-
import { mkdirSync, readFileSync
|
|
108
|
-
import { dirname, join, resolve as
|
|
135
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
136
|
+
import { dirname, join, resolve as resolve2 } from "node:path";
|
|
109
137
|
|
|
110
138
|
// src/graph/core/emit-jsonld.ts
|
|
111
139
|
var XSD_STRING = `${NS.xsd}string`;
|
|
@@ -115,7 +143,17 @@ function renderValue(term) {
|
|
|
115
143
|
value: { "@id": term.value },
|
|
116
144
|
kind: 0,
|
|
117
145
|
primary: term.value,
|
|
118
|
-
datatype: ""
|
|
146
|
+
datatype: "",
|
|
147
|
+
language: ""
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (term.language) {
|
|
151
|
+
return {
|
|
152
|
+
value: { "@value": term.value, "@language": term.language },
|
|
153
|
+
kind: 1,
|
|
154
|
+
primary: term.value,
|
|
155
|
+
datatype: "",
|
|
156
|
+
language: term.language
|
|
119
157
|
};
|
|
120
158
|
}
|
|
121
159
|
if (term.datatype && term.datatype !== XSD_STRING) {
|
|
@@ -123,16 +161,17 @@ function renderValue(term) {
|
|
|
123
161
|
value: { "@value": term.value, "@type": compactIri(term.datatype) },
|
|
124
162
|
kind: 1,
|
|
125
163
|
primary: term.value,
|
|
126
|
-
datatype: term.datatype
|
|
164
|
+
datatype: term.datatype,
|
|
165
|
+
language: ""
|
|
127
166
|
};
|
|
128
167
|
}
|
|
129
|
-
return { value: term.value, kind: 1, primary: term.value, datatype: "" };
|
|
168
|
+
return { value: term.value, kind: 1, primary: term.value, datatype: "", language: "" };
|
|
130
169
|
}
|
|
131
170
|
function compareRendered(a, b) {
|
|
132
171
|
if (a.kind !== b.kind) return a.kind - b.kind;
|
|
133
172
|
const p = byCodeUnit(a.primary, b.primary);
|
|
134
173
|
if (p !== 0) return p;
|
|
135
|
-
return byCodeUnit(a.datatype, b.datatype);
|
|
174
|
+
return byCodeUnit(a.datatype, b.datatype) || byCodeUnit(a.language, b.language);
|
|
136
175
|
}
|
|
137
176
|
function collapse(values) {
|
|
138
177
|
const rendered = [...values].sort(compareRendered).map((v) => v.value);
|
|
@@ -200,7 +239,9 @@ function compareTerms(a, b) {
|
|
|
200
239
|
if (v !== 0) return v;
|
|
201
240
|
const da = a.kind === "literal" ? a.datatype ?? "" : "";
|
|
202
241
|
const db = b.kind === "literal" ? b.datatype ?? "" : "";
|
|
203
|
-
|
|
242
|
+
const la = a.kind === "literal" ? a.language ?? "" : "";
|
|
243
|
+
const lb = b.kind === "literal" ? b.language ?? "" : "";
|
|
244
|
+
return byCodeUnit(da, db) || byCodeUnit(la, lb);
|
|
204
245
|
}
|
|
205
246
|
function emitRdfXml(quads, prefixes) {
|
|
206
247
|
const sortedPrefixes = Object.entries(prefixes).sort(
|
|
@@ -241,6 +282,10 @@ function emitRdfXml(quads, prefixes) {
|
|
|
241
282
|
lines.push(
|
|
242
283
|
` <${qname} rdf:resource="${escapeAttr(term.value)}"/>`
|
|
243
284
|
);
|
|
285
|
+
} else if (term.language) {
|
|
286
|
+
lines.push(
|
|
287
|
+
` <${qname} xml:lang="${escapeAttr(term.language)}">${escapeText(term.value)}</${qname}>`
|
|
288
|
+
);
|
|
244
289
|
} else if (term.datatype && term.datatype !== XSD_STRING2) {
|
|
245
290
|
lines.push(
|
|
246
291
|
` <${qname} rdf:datatype="${escapeAttr(term.datatype)}">${escapeText(term.value)}</${qname}>`
|
|
@@ -275,17 +320,17 @@ function writeZip(entries) {
|
|
|
275
320
|
const locals = [];
|
|
276
321
|
const centrals = [];
|
|
277
322
|
let offset = 0;
|
|
278
|
-
for (const
|
|
279
|
-
if (escapesArchiveRoot(
|
|
323
|
+
for (const entry of entries) {
|
|
324
|
+
if (escapesArchiveRoot(entry.name)) {
|
|
280
325
|
throw new GraphError(
|
|
281
|
-
`Refusing ZIP entry "${
|
|
326
|
+
`Refusing ZIP entry "${entry.name}": an archive entry may not be absolute or climb above the archive root.`
|
|
282
327
|
);
|
|
283
328
|
}
|
|
284
|
-
const name = Buffer.from(
|
|
329
|
+
const name = Buffer.from(entry.name, "utf8");
|
|
285
330
|
const flags = name.some((b) => b > 127) ? 2048 : 0;
|
|
286
|
-
const method =
|
|
287
|
-
const stored =
|
|
288
|
-
const crc = crc32(
|
|
331
|
+
const method = entry.store ? 0 : 8;
|
|
332
|
+
const stored = entry.store ? entry.data : deflateRawSync(entry.data);
|
|
333
|
+
const crc = crc32(entry.data) >>> 0;
|
|
289
334
|
const local = Buffer.alloc(30);
|
|
290
335
|
local.writeUInt32LE(67324752, 0);
|
|
291
336
|
local.writeUInt16LE(VERSION, 4);
|
|
@@ -295,7 +340,7 @@ function writeZip(entries) {
|
|
|
295
340
|
local.writeUInt16LE(DOS_DATE, 12);
|
|
296
341
|
local.writeUInt32LE(crc, 14);
|
|
297
342
|
local.writeUInt32LE(stored.length, 18);
|
|
298
|
-
local.writeUInt32LE(
|
|
343
|
+
local.writeUInt32LE(entry.data.length, 22);
|
|
299
344
|
local.writeUInt16LE(name.length, 26);
|
|
300
345
|
local.writeUInt16LE(0, 28);
|
|
301
346
|
locals.push(local, name, stored);
|
|
@@ -309,7 +354,7 @@ function writeZip(entries) {
|
|
|
309
354
|
central.writeUInt16LE(DOS_DATE, 14);
|
|
310
355
|
central.writeUInt32LE(crc, 16);
|
|
311
356
|
central.writeUInt32LE(stored.length, 20);
|
|
312
|
-
central.writeUInt32LE(
|
|
357
|
+
central.writeUInt32LE(entry.data.length, 24);
|
|
313
358
|
central.writeUInt16LE(name.length, 28);
|
|
314
359
|
central.writeUInt16LE(0, 30);
|
|
315
360
|
central.writeUInt16LE(0, 32);
|
|
@@ -424,7 +469,9 @@ function projectPackage(store, opts, cwd) {
|
|
|
424
469
|
null
|
|
425
470
|
)) {
|
|
426
471
|
const o = q.object;
|
|
427
|
-
if (o.termType === "Literal") {
|
|
472
|
+
if (o.termType === "Literal" && o.language !== "") {
|
|
473
|
+
add(doc, pred, { kind: "literal", value: o.value, language: o.language });
|
|
474
|
+
} else if (o.termType === "Literal") {
|
|
428
475
|
const dt = o.datatype.value;
|
|
429
476
|
add(doc, pred, lit(o.value, dt !== XSD_STRING3 ? dt : void 0));
|
|
430
477
|
} else {
|
|
@@ -449,655 +496,8 @@ function projectPackage(store, opts, cwd) {
|
|
|
449
496
|
return { quads, prefixes, contentFiles, warnings };
|
|
450
497
|
}
|
|
451
498
|
|
|
452
|
-
// src/graph/core/search-index.ts
|
|
453
|
-
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
454
|
-
import { resolve as resolve2 } from "node:path";
|
|
455
|
-
|
|
456
|
-
// src/graph/runtime/resolve.ts
|
|
457
|
-
var GRAPH_PATH = `${NS.graph}path`;
|
|
458
|
-
var DCTERMS_TITLE = `${NS.dcterms}title`;
|
|
459
|
-
var DCTERMS_HAS_PART = `${NS.dcterms}hasPart`;
|
|
460
|
-
var GRAPH_LEVEL = `${NS.graph}level`;
|
|
461
|
-
var GRAPH_ORDER = `${NS.graph}order`;
|
|
462
|
-
function splitFragment(iri2) {
|
|
463
|
-
const hash = iri2.indexOf("#");
|
|
464
|
-
return hash < 0 ? { doc: iri2 } : { doc: iri2.slice(0, hash), fragment: iri2.slice(hash + 1) };
|
|
465
|
-
}
|
|
466
|
-
function fencedLines(lines) {
|
|
467
|
-
const mask = new Array(lines.length).fill(false);
|
|
468
|
-
let open;
|
|
469
|
-
for (const [i, line] of lines.entries()) {
|
|
470
|
-
const m = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
|
|
471
|
-
const delimiter = m?.[1];
|
|
472
|
-
const info = m?.[2];
|
|
473
|
-
const isFence = delimiter !== void 0 && info !== void 0;
|
|
474
|
-
if (open === void 0) {
|
|
475
|
-
if (isFence && !(delimiter.startsWith("`") && info.includes("`"))) {
|
|
476
|
-
open = delimiter;
|
|
477
|
-
mask[i] = true;
|
|
478
|
-
}
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
mask[i] = true;
|
|
482
|
-
if (isFence && delimiter[0] === open[0] && delimiter.length >= open.length && info.trim() === "") {
|
|
483
|
-
open = void 0;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
return mask;
|
|
487
|
-
}
|
|
488
|
-
var ATX = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?[ \t]*$/;
|
|
489
|
-
var SETEXT_UNDERLINE = /^ {0,3}(=+|-+)[ \t]*$/;
|
|
490
|
-
function isParagraphLine(line) {
|
|
491
|
-
if (line.trim() === "") return false;
|
|
492
|
-
if (ATX.test(line)) return false;
|
|
493
|
-
if (/^ {0,3}([-+*]|\d{1,9}[.)])([ \t]|$)/.test(line)) return false;
|
|
494
|
-
if (/^ {0,3}>/.test(line)) return false;
|
|
495
|
-
if (/^ {0,3}([-*_])([ \t]*\1){2,}[ \t]*$/.test(line)) return false;
|
|
496
|
-
return !/^ {4}/.test(line);
|
|
497
|
-
}
|
|
498
|
-
function frontmatterLength(lines) {
|
|
499
|
-
if (lines[0]?.trim() !== "---") return 0;
|
|
500
|
-
for (let i = 1; i < lines.length; i++) {
|
|
501
|
-
const line = lines[i]?.trim();
|
|
502
|
-
if (line === "---" || line === "...") return i + 1;
|
|
503
|
-
}
|
|
504
|
-
return 0;
|
|
505
|
-
}
|
|
506
|
-
function sourceHeadings(lines) {
|
|
507
|
-
const fenced = fencedLines(lines);
|
|
508
|
-
const skip = frontmatterLength(lines);
|
|
509
|
-
const headings = [];
|
|
510
|
-
let paragraph = -1;
|
|
511
|
-
for (const [i, line] of lines.entries()) {
|
|
512
|
-
if (i < skip || fenced[i]) {
|
|
513
|
-
paragraph = -1;
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
const atx = ATX.exec(line);
|
|
517
|
-
const hashes = atx?.[1];
|
|
518
|
-
if (hashes !== void 0) {
|
|
519
|
-
const text = (atx?.[2] ?? "").replace(/(^|[ \t]+)#+$/, "");
|
|
520
|
-
headings.push({ start: i, level: hashes.length, text });
|
|
521
|
-
paragraph = -1;
|
|
522
|
-
continue;
|
|
523
|
-
}
|
|
524
|
-
const underline = SETEXT_UNDERLINE.exec(line)?.[1];
|
|
525
|
-
if (underline !== void 0 && paragraph >= 0) {
|
|
526
|
-
headings.push({
|
|
527
|
-
start: paragraph,
|
|
528
|
-
level: underline.startsWith("=") ? 1 : 2,
|
|
529
|
-
text: lines.slice(paragraph, i).join("\n")
|
|
530
|
-
});
|
|
531
|
-
paragraph = -1;
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
if (isParagraphLine(line)) {
|
|
535
|
-
if (paragraph < 0) paragraph = i;
|
|
536
|
-
} else {
|
|
537
|
-
paragraph = -1;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
return headings;
|
|
541
|
-
}
|
|
542
|
-
var ENTITIES = {
|
|
543
|
-
amp: "&",
|
|
544
|
-
lt: "<",
|
|
545
|
-
gt: ">",
|
|
546
|
-
quot: '"',
|
|
547
|
-
apos: "'",
|
|
548
|
-
nbsp: "\xA0"
|
|
549
|
-
};
|
|
550
|
-
function decodeEntities(text) {
|
|
551
|
-
return text.replace(
|
|
552
|
-
/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi,
|
|
553
|
-
(whole, name) => {
|
|
554
|
-
if (name.startsWith("#")) {
|
|
555
|
-
const hex = name[1] === "x" || name[1] === "X";
|
|
556
|
-
const code = Number.parseInt(name.slice(hex ? 2 : 1), hex ? 16 : 10);
|
|
557
|
-
return Number.isNaN(code) || code > 1114111 ? whole : String.fromCodePoint(code);
|
|
558
|
-
}
|
|
559
|
-
return ENTITIES[name.toLowerCase()] ?? whole;
|
|
560
|
-
}
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
function headingKey(text) {
|
|
564
|
-
return text.replace(/[`*_~\\[\]]/g, "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
565
|
-
}
|
|
566
|
-
function stripInline(raw) {
|
|
567
|
-
return decodeEntities(
|
|
568
|
-
raw.replace(/!?\[([^\]]*)\]\((?:[^()]|\([^()]*\))*\)/g, "$1").replace(/!?\[([^\]]*)\]\[[^\]]*\]/g, "$1").replace(/<((?:https?|mailto):[^>\s]+)>/gi, "$1")
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
function documentSectionOrder(graph, docIri) {
|
|
572
|
-
const ordered = [];
|
|
573
|
-
const seen = /* @__PURE__ */ new Set();
|
|
574
|
-
const childrenOf = (iri2) => graph.out(iri2, DCTERMS_HAS_PART).map((e) => e.target).sort((a, b) => {
|
|
575
|
-
const oa = Number.parseInt(graph.literal(a, GRAPH_ORDER) ?? "", 10);
|
|
576
|
-
const ob = Number.parseInt(graph.literal(b, GRAPH_ORDER) ?? "", 10);
|
|
577
|
-
if (Number.isNaN(oa) || Number.isNaN(ob) || oa === ob) {
|
|
578
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
579
|
-
}
|
|
580
|
-
return oa - ob;
|
|
581
|
-
});
|
|
582
|
-
const walk = (iri2) => {
|
|
583
|
-
for (const child of childrenOf(iri2)) {
|
|
584
|
-
if (seen.has(child)) continue;
|
|
585
|
-
seen.add(child);
|
|
586
|
-
ordered.push(child);
|
|
587
|
-
walk(child);
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
walk(docIri);
|
|
591
|
-
return ordered;
|
|
592
|
-
}
|
|
593
|
-
function sectionOccurrences(graph, docIri) {
|
|
594
|
-
const occurrences = /* @__PURE__ */ new Map();
|
|
595
|
-
const counts = /* @__PURE__ */ new Map();
|
|
596
|
-
for (const section of documentSectionOrder(graph, docIri)) {
|
|
597
|
-
const rawTitle = graph.literal(section, DCTERMS_TITLE);
|
|
598
|
-
if (rawTitle === void 0) {
|
|
599
|
-
occurrences.set(section, 0);
|
|
600
|
-
continue;
|
|
601
|
-
}
|
|
602
|
-
const title = headingKey(rawTitle);
|
|
603
|
-
const level = graph.literal(section, GRAPH_LEVEL) ?? "";
|
|
604
|
-
let byLevel = counts.get(title);
|
|
605
|
-
if (!byLevel) {
|
|
606
|
-
byLevel = /* @__PURE__ */ new Map();
|
|
607
|
-
counts.set(title, byLevel);
|
|
608
|
-
}
|
|
609
|
-
const seen = byLevel.get(level) ?? 0;
|
|
610
|
-
occurrences.set(section, seen);
|
|
611
|
-
byLevel.set(level, seen + 1);
|
|
612
|
-
}
|
|
613
|
-
return occurrences;
|
|
614
|
-
}
|
|
615
|
-
function sectionOccurrence(graph, sectionIri) {
|
|
616
|
-
const { doc } = splitFragment(sectionIri);
|
|
617
|
-
return sectionOccurrences(graph, doc).get(sectionIri) ?? 0;
|
|
618
|
-
}
|
|
619
|
-
function documentPreamble(markdown) {
|
|
620
|
-
const lines = markdown.split(/\r?\n/);
|
|
621
|
-
const end = sourceHeadings(lines)[0]?.start ?? lines.length;
|
|
622
|
-
const text = lines.slice(0, end).join("\n").trim();
|
|
623
|
-
return text === "" ? void 0 : text;
|
|
624
|
-
}
|
|
625
|
-
function sliceSection(markdown, title, level, occurrence = 0) {
|
|
626
|
-
return slice(markdown, title, level, occurrence, false);
|
|
627
|
-
}
|
|
628
|
-
function sectionOwnText(markdown, title, level, occurrence = 0) {
|
|
629
|
-
return slice(markdown, title, level, occurrence, true);
|
|
630
|
-
}
|
|
631
|
-
function slice(markdown, title, level, occurrence, ownTextOnly) {
|
|
632
|
-
const lines = markdown.split(/\r?\n/);
|
|
633
|
-
const headings = sourceHeadings(lines);
|
|
634
|
-
const wanted = headingKey(title);
|
|
635
|
-
let remaining = occurrence;
|
|
636
|
-
let found = -1;
|
|
637
|
-
for (const [n, heading] of headings.entries()) {
|
|
638
|
-
if (level !== void 0 && heading.level !== level) continue;
|
|
639
|
-
if (headingKey(stripInline(heading.text)) !== wanted) continue;
|
|
640
|
-
if (remaining > 0) {
|
|
641
|
-
remaining -= 1;
|
|
642
|
-
continue;
|
|
643
|
-
}
|
|
644
|
-
found = n;
|
|
645
|
-
break;
|
|
646
|
-
}
|
|
647
|
-
const match = headings[found];
|
|
648
|
-
if (match === void 0) return void 0;
|
|
649
|
-
const next = headings.slice(found + 1).find((h) => ownTextOnly || h.level <= match.level);
|
|
650
|
-
const end = next?.start ?? lines.length;
|
|
651
|
-
return lines.slice(match.start, end).join("\n").trimEnd();
|
|
652
|
-
}
|
|
653
|
-
function createFetchResolver(graph, options = {}) {
|
|
654
|
-
const doFetch = options.fetch ?? ((url) => globalThis.fetch(url));
|
|
655
|
-
const toUrl = options.pathToUrl ?? ((path2) => `${options.baseUrl ?? ""}${path2}`);
|
|
656
|
-
const cache = /* @__PURE__ */ new Map();
|
|
657
|
-
const occurrenceCache = /* @__PURE__ */ new Map();
|
|
658
|
-
const occurrenceOf = (docIri, sectionIri) => {
|
|
659
|
-
let map = occurrenceCache.get(docIri);
|
|
660
|
-
if (!map) {
|
|
661
|
-
map = sectionOccurrences(graph, docIri);
|
|
662
|
-
occurrenceCache.set(docIri, map);
|
|
663
|
-
}
|
|
664
|
-
return map.get(sectionIri) ?? 0;
|
|
665
|
-
};
|
|
666
|
-
const fetchDoc = (url) => {
|
|
667
|
-
let pending = cache.get(url);
|
|
668
|
-
if (!pending) {
|
|
669
|
-
pending = doFetch(url).then((r) => r.ok ? r.text() : void 0).catch(() => void 0);
|
|
670
|
-
cache.set(url, pending);
|
|
671
|
-
}
|
|
672
|
-
return pending;
|
|
673
|
-
};
|
|
674
|
-
return {
|
|
675
|
-
async resolve(iri2) {
|
|
676
|
-
const { doc, fragment } = splitFragment(iri2);
|
|
677
|
-
const path2 = graph.literal(doc, GRAPH_PATH);
|
|
678
|
-
if (!path2) return void 0;
|
|
679
|
-
const sourceUrl = toUrl(path2);
|
|
680
|
-
const body = await fetchDoc(sourceUrl);
|
|
681
|
-
const title = graph.literal(iri2, DCTERMS_TITLE);
|
|
682
|
-
if (body === void 0) {
|
|
683
|
-
options.trace?.resolutions.push({
|
|
684
|
-
iri: iri2,
|
|
685
|
-
sourceUrl,
|
|
686
|
-
ok: false,
|
|
687
|
-
error: "fetch failed"
|
|
688
|
-
});
|
|
689
|
-
return void 0;
|
|
690
|
-
}
|
|
691
|
-
let text = body;
|
|
692
|
-
if (fragment) {
|
|
693
|
-
const levelText = graph.literal(iri2, GRAPH_LEVEL);
|
|
694
|
-
const level = levelText ? Number.parseInt(levelText, 10) : void 0;
|
|
695
|
-
const slice2 = title === void 0 ? void 0 : sliceSection(
|
|
696
|
-
body,
|
|
697
|
-
title,
|
|
698
|
-
Number.isNaN(level) ? void 0 : level,
|
|
699
|
-
occurrenceOf(doc, iri2)
|
|
700
|
-
);
|
|
701
|
-
if (slice2 === void 0) {
|
|
702
|
-
options.trace?.resolutions.push({
|
|
703
|
-
iri: iri2,
|
|
704
|
-
sourceUrl,
|
|
705
|
-
ok: false,
|
|
706
|
-
error: "section heading not found"
|
|
707
|
-
});
|
|
708
|
-
return void 0;
|
|
709
|
-
}
|
|
710
|
-
text = slice2;
|
|
711
|
-
}
|
|
712
|
-
options.trace?.resolutions.push({ iri: iri2, sourceUrl, ok: true });
|
|
713
|
-
return { iri: iri2, text, sourceUrl, title };
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// src/graph/core/search-index.ts
|
|
719
|
-
var GRAPH_DOCUMENT2 = `${NS.graph}Document`;
|
|
720
|
-
var GRAPH_SECTION = `${NS.graph}Section`;
|
|
721
|
-
var SKOS_CONCEPT = `${NS.skos}Concept`;
|
|
722
|
-
var GRAPH_PATH2 = `${NS.graph}path`;
|
|
723
|
-
var GRAPH_LEVEL2 = `${NS.graph}level`;
|
|
724
|
-
var DCTERMS_TITLE2 = `${NS.dcterms}title`;
|
|
725
|
-
var DCTERMS_DESCRIPTION = `${NS.dcterms}description`;
|
|
726
|
-
var SKOS_PREF_LABEL = `${NS.skos}prefLabel`;
|
|
727
|
-
var SKOS_ALT_LABEL = `${NS.skos}altLabel`;
|
|
728
|
-
var DCTERMS_LANGUAGE = `${NS.dcterms}language`;
|
|
729
|
-
function joinLabels(values) {
|
|
730
|
-
const seen = /* @__PURE__ */ new Map();
|
|
731
|
-
for (const v of values) {
|
|
732
|
-
const key = v.trim().toLowerCase();
|
|
733
|
-
if (key && !seen.has(key)) seen.set(key, v.trim());
|
|
734
|
-
}
|
|
735
|
-
const out = [...seen.values()].sort(byCodeUnit);
|
|
736
|
-
return out.length > 0 ? out.join(" ") : void 0;
|
|
737
|
-
}
|
|
738
|
-
var FRONTMATTER = /^---[ \t]*\r?\n(?:[\s\S]*?\r?\n)?(?:---|\.\.\.)[ \t]*(?:\r?\n|$)(?:\r?\n)*/;
|
|
739
|
-
function stripFrontmatter(markdown) {
|
|
740
|
-
return markdown.replace(FRONTMATTER, "");
|
|
741
|
-
}
|
|
742
|
-
function plainText(nodes) {
|
|
743
|
-
return nodes.map((n) => n.text.replace(/\r\n/g, "\n").trim()).filter((t) => t !== "");
|
|
744
|
-
}
|
|
745
|
-
function treeText(source, path2) {
|
|
746
|
-
const format = formatOf(path2);
|
|
747
|
-
if (format === "markdown" || format === "mdx") return void 0;
|
|
748
|
-
const minted = mintTreeSections(parseTree(source, path2, format).sections);
|
|
749
|
-
const sections = /* @__PURE__ */ new Map();
|
|
750
|
-
for (const [n, section] of minted.sections.entries()) {
|
|
751
|
-
const own = plainText(minted.owned[n] ?? []);
|
|
752
|
-
sections.set(section.slug, [section.title, ...own].join("\n\n"));
|
|
753
|
-
}
|
|
754
|
-
const lead = plainText(minted.unowned);
|
|
755
|
-
return { doc: lead.length > 0 ? lead.join("\n\n") : void 0, sections };
|
|
756
|
-
}
|
|
757
|
-
function entry(id, type, fields) {
|
|
758
|
-
const out = { id, type };
|
|
759
|
-
if (fields.title !== void 0) out.title = fields.title;
|
|
760
|
-
if (fields.labels !== void 0) out.labels = fields.labels;
|
|
761
|
-
if (fields.description !== void 0) out.description = fields.description;
|
|
762
|
-
if (fields.text !== void 0) out.text = fields.text;
|
|
763
|
-
return out;
|
|
764
|
-
}
|
|
765
|
-
function buildSearchIndex(graph, cwd, options = {}) {
|
|
766
|
-
const warnings = options.warnings ?? [];
|
|
767
|
-
const readDoc = options.readDoc ?? ((path2) => {
|
|
768
|
-
const abs = resolve2(cwd, path2);
|
|
769
|
-
return existsSync2(abs) ? readFileSync(abs, "utf8") : void 0;
|
|
770
|
-
});
|
|
771
|
-
const entries = [];
|
|
772
|
-
const sourceOf = /* @__PURE__ */ new Map();
|
|
773
|
-
const treeTextOf = /* @__PURE__ */ new Map();
|
|
774
|
-
const allSections = graph.instancesOf(GRAPH_SECTION);
|
|
775
|
-
const sectionsOf = /* @__PURE__ */ new Map();
|
|
776
|
-
for (const section of allSections) {
|
|
777
|
-
const hash = section.indexOf("#");
|
|
778
|
-
if (hash < 0) continue;
|
|
779
|
-
const doc = section.slice(0, hash);
|
|
780
|
-
const siblings = sectionsOf.get(doc);
|
|
781
|
-
if (siblings) siblings.push(section);
|
|
782
|
-
else sectionsOf.set(doc, [section]);
|
|
783
|
-
}
|
|
784
|
-
for (const doc of graph.instancesOf(GRAPH_DOCUMENT2)) {
|
|
785
|
-
const path2 = graph.literal(doc, GRAPH_PATH2);
|
|
786
|
-
const source = path2 === void 0 ? void 0 : readDoc(path2);
|
|
787
|
-
sourceOf.set(doc, source);
|
|
788
|
-
if (path2 !== void 0 && source === void 0) {
|
|
789
|
-
warnings.push(
|
|
790
|
-
`Source not found for ${path2} \u2014 indexed without body text.`
|
|
791
|
-
);
|
|
792
|
-
}
|
|
793
|
-
const tree = source === void 0 || path2 === void 0 ? void 0 : treeText(source, path2);
|
|
794
|
-
if (tree) treeTextOf.set(doc, tree);
|
|
795
|
-
const body = source === void 0 ? void 0 : stripFrontmatter(source).replace(/\r\n/g, "\n");
|
|
796
|
-
const text = tree ? tree.doc : body === void 0 ? void 0 : (sectionsOf.get(doc)?.length ?? 0) > 0 ? documentPreamble(body) : body;
|
|
797
|
-
entries.push(
|
|
798
|
-
entry(doc, compactIri(GRAPH_DOCUMENT2), {
|
|
799
|
-
title: graph.literal(doc, DCTERMS_TITLE2),
|
|
800
|
-
description: graph.literal(doc, DCTERMS_DESCRIPTION),
|
|
801
|
-
text
|
|
802
|
-
})
|
|
803
|
-
);
|
|
804
|
-
}
|
|
805
|
-
const occurrencesOf = /* @__PURE__ */ new Map();
|
|
806
|
-
for (const section of allSections) {
|
|
807
|
-
const hash = section.indexOf("#");
|
|
808
|
-
const doc = hash < 0 ? section : section.slice(0, hash);
|
|
809
|
-
const title = graph.literal(section, DCTERMS_TITLE2);
|
|
810
|
-
const source = sourceOf.get(doc);
|
|
811
|
-
const levelText = graph.literal(section, GRAPH_LEVEL2);
|
|
812
|
-
const parsed = levelText === void 0 ? NaN : Number.parseInt(levelText, 10);
|
|
813
|
-
const level = Number.isNaN(parsed) ? void 0 : parsed;
|
|
814
|
-
let occurrences = occurrencesOf.get(doc);
|
|
815
|
-
if (!occurrences) {
|
|
816
|
-
occurrences = sectionOccurrences(graph, doc);
|
|
817
|
-
occurrencesOf.set(doc, occurrences);
|
|
818
|
-
}
|
|
819
|
-
const tree = treeTextOf.get(doc);
|
|
820
|
-
const text = tree ? tree.sections.get(section.slice(hash + 1)) : source !== void 0 && title !== void 0 ? sectionOwnText(source, title, level, occurrences.get(section) ?? 0) : void 0;
|
|
821
|
-
entries.push(entry(section, compactIri(GRAPH_SECTION), { title, text }));
|
|
822
|
-
}
|
|
823
|
-
for (const concept of graph.instancesOf(SKOS_CONCEPT)) {
|
|
824
|
-
const pref = graph.literals(concept, SKOS_PREF_LABEL);
|
|
825
|
-
const alt = graph.literals(concept, SKOS_ALT_LABEL);
|
|
826
|
-
entries.push(
|
|
827
|
-
entry(concept, compactIri(SKOS_CONCEPT), {
|
|
828
|
-
title: pref[0],
|
|
829
|
-
labels: joinLabels([...pref, ...alt])
|
|
830
|
-
})
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
entries.sort((a, b) => byCodeUnit(a.id, b.id));
|
|
834
|
-
return { version: 1, entries };
|
|
835
|
-
}
|
|
836
|
-
function emitSearchIndex(doc) {
|
|
837
|
-
return `${JSON.stringify(doc, null, 2)}
|
|
838
|
-
`;
|
|
839
|
-
}
|
|
840
|
-
function partitionByLanguage(graph, index) {
|
|
841
|
-
const documentType = compactIri(GRAPH_DOCUMENT2);
|
|
842
|
-
const sectionType = compactIri(GRAPH_SECTION);
|
|
843
|
-
const languageOf = (entry2) => {
|
|
844
|
-
if (entry2.type !== documentType && entry2.type !== sectionType) {
|
|
845
|
-
return void 0;
|
|
846
|
-
}
|
|
847
|
-
const hash = entry2.id.indexOf("#");
|
|
848
|
-
const doc = hash === -1 ? entry2.id : entry2.id.slice(0, hash);
|
|
849
|
-
return languageOfDocument(graph, doc);
|
|
850
|
-
};
|
|
851
|
-
const out = /* @__PURE__ */ new Map();
|
|
852
|
-
const shared = [];
|
|
853
|
-
for (const entry2 of index.entries) {
|
|
854
|
-
const language = languageOf(entry2);
|
|
855
|
-
if (language === void 0) {
|
|
856
|
-
shared.push(entry2);
|
|
857
|
-
continue;
|
|
858
|
-
}
|
|
859
|
-
const bucket = out.get(language);
|
|
860
|
-
if (bucket) bucket.entries.push(entry2);
|
|
861
|
-
else out.set(language, { version: 1, entries: [entry2] });
|
|
862
|
-
}
|
|
863
|
-
if (out.size === 0 && shared.length > 0) {
|
|
864
|
-
out.set(UNDETERMINED, { version: 1, entries: [] });
|
|
865
|
-
}
|
|
866
|
-
for (const bucket of out.values()) {
|
|
867
|
-
bucket.entries.push(...shared);
|
|
868
|
-
bucket.entries.sort((a, b) => byCodeUnit(a.id, b.id));
|
|
869
|
-
}
|
|
870
|
-
return out;
|
|
871
|
-
}
|
|
872
|
-
function languageOfDocument(graph, doc) {
|
|
873
|
-
const tag = graph.literal(doc, DCTERMS_LANGUAGE);
|
|
874
|
-
return tag === void 0 ? UNDETERMINED : canonicalLanguageTag(tag);
|
|
875
|
-
}
|
|
876
|
-
function documentsByLanguage(graph) {
|
|
877
|
-
const out = /* @__PURE__ */ new Map();
|
|
878
|
-
for (const doc of graph.instancesOf(GRAPH_DOCUMENT2)) {
|
|
879
|
-
const language = languageOfDocument(graph, doc);
|
|
880
|
-
out.set(language, (out.get(language) ?? 0) + 1);
|
|
881
|
-
}
|
|
882
|
-
return out;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// src/graph/runtime/graph.ts
|
|
886
|
-
var XSD_STRING4 = "http://www.w3.org/2001/XMLSchema#string";
|
|
887
|
-
function compareValues(a, b) {
|
|
888
|
-
if (a.kind !== b.kind) return a.kind === "iri" ? -1 : 1;
|
|
889
|
-
const v = byCodeUnit(a.value, b.value);
|
|
890
|
-
if (v !== 0) return v;
|
|
891
|
-
const da = a.kind === "literal" ? a.datatype ?? "" : "";
|
|
892
|
-
const db = b.kind === "literal" ? b.datatype ?? "" : "";
|
|
893
|
-
return byCodeUnit(da, db);
|
|
894
|
-
}
|
|
895
|
-
var GraphIndex = class _GraphIndex {
|
|
896
|
-
nodes = /* @__PURE__ */ new Map();
|
|
897
|
-
/** subject → predicate → object IRIs (sorted). */
|
|
898
|
-
outbound = /* @__PURE__ */ new Map();
|
|
899
|
-
/** object → predicate → subject IRIs (sorted). */
|
|
900
|
-
inbound = /* @__PURE__ */ new Map();
|
|
901
|
-
/** class IRI → instance IRIs (sorted). */
|
|
902
|
-
byType = /* @__PURE__ */ new Map();
|
|
903
|
-
/** prefix → namespace, from the artifact's own `@context`. */
|
|
904
|
-
context;
|
|
905
|
-
constructor(context) {
|
|
906
|
-
this.context = context;
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Build from a `graph.jsonld` document — a JSON string or the parsed object.
|
|
910
|
-
* CURIE keys and `@type` values are expanded using the document's own
|
|
911
|
-
* `@context`, so the index is self-describing.
|
|
912
|
-
*/
|
|
913
|
-
static fromJsonLd(input) {
|
|
914
|
-
const doc = typeof input === "string" ? JSON.parse(input) : input;
|
|
915
|
-
const context = doc["@context"] ?? {};
|
|
916
|
-
const index = new _GraphIndex({ ...context });
|
|
917
|
-
for (const raw of doc["@graph"] ?? []) {
|
|
918
|
-
index.addJsonLdNode(raw);
|
|
919
|
-
}
|
|
920
|
-
index.finalize();
|
|
921
|
-
return index;
|
|
922
|
-
}
|
|
923
|
-
/** Build from dockg's internal quad shape (the Node/CLI path). */
|
|
924
|
-
static fromQuads(quads, context = {}) {
|
|
925
|
-
const index = new _GraphIndex({ ...context });
|
|
926
|
-
for (const q of quads) {
|
|
927
|
-
const o = q.o;
|
|
928
|
-
const value = o.kind === "iri" ? { kind: "iri", value: o.value } : o.datatype && o.datatype !== XSD_STRING4 ? { kind: "literal", value: o.value, datatype: o.datatype } : { kind: "literal", value: o.value };
|
|
929
|
-
index.addTriple(q.s, q.p, value);
|
|
930
|
-
}
|
|
931
|
-
index.finalize();
|
|
932
|
-
return index;
|
|
933
|
-
}
|
|
934
|
-
/** Expand a CURIE (`dcterms:title`) to a full IRI using `@context`. */
|
|
935
|
-
expand(term) {
|
|
936
|
-
const colon = term.indexOf(":");
|
|
937
|
-
if (colon <= 0) return term;
|
|
938
|
-
const ns = this.context[term.slice(0, colon)];
|
|
939
|
-
return ns ? `${ns}${term.slice(colon + 1)}` : term;
|
|
940
|
-
}
|
|
941
|
-
/** Compact a full IRI to a CURIE when a context namespace matches. */
|
|
942
|
-
compact(iri2) {
|
|
943
|
-
let best = iri2;
|
|
944
|
-
let bestNs = "";
|
|
945
|
-
for (const [prefix, ns] of Object.entries(this.context)) {
|
|
946
|
-
if (iri2.startsWith(ns) && iri2.length > ns.length && ns.length > bestNs.length) {
|
|
947
|
-
best = `${prefix}:${iri2.slice(ns.length)}`;
|
|
948
|
-
bestNs = ns;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
return best;
|
|
952
|
-
}
|
|
953
|
-
addJsonLdNode(raw) {
|
|
954
|
-
const id = typeof raw["@id"] === "string" ? this.expand(raw["@id"]) : "";
|
|
955
|
-
if (!id) return;
|
|
956
|
-
this.ensureNode(id);
|
|
957
|
-
const rawTypes = raw["@type"];
|
|
958
|
-
for (const t of toArray(rawTypes)) {
|
|
959
|
-
if (typeof t === "string") {
|
|
960
|
-
this.addTriple(id, RDF_TYPE, { kind: "iri", value: this.expand(t) });
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
for (const [key, rawValue] of Object.entries(raw)) {
|
|
964
|
-
if (key === "@id" || key === "@type") continue;
|
|
965
|
-
const predicate = this.expand(key);
|
|
966
|
-
for (const v of toArray(rawValue)) {
|
|
967
|
-
const value = this.toValue(v);
|
|
968
|
-
if (value) this.addTriple(id, predicate, value);
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
toValue(v) {
|
|
973
|
-
if (typeof v === "string") return { kind: "literal", value: v };
|
|
974
|
-
if (typeof v === "number" || typeof v === "boolean") {
|
|
975
|
-
return { kind: "literal", value: String(v) };
|
|
976
|
-
}
|
|
977
|
-
if (v && typeof v === "object") {
|
|
978
|
-
const o = v;
|
|
979
|
-
if (typeof o["@id"] === "string") {
|
|
980
|
-
return { kind: "iri", value: this.expand(o["@id"]) };
|
|
981
|
-
}
|
|
982
|
-
if (o["@value"] !== void 0) {
|
|
983
|
-
const raw = o["@value"];
|
|
984
|
-
const lexical = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
985
|
-
const dt = typeof o["@type"] === "string" ? this.expand(o["@type"]) : void 0;
|
|
986
|
-
return dt && dt !== XSD_STRING4 ? { kind: "literal", value: lexical, datatype: dt } : { kind: "literal", value: lexical };
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
return void 0;
|
|
990
|
-
}
|
|
991
|
-
ensureNode(id) {
|
|
992
|
-
let node = this.nodes.get(id);
|
|
993
|
-
if (!node) {
|
|
994
|
-
node = { id, types: [], props: /* @__PURE__ */ new Map() };
|
|
995
|
-
this.nodes.set(id, node);
|
|
996
|
-
}
|
|
997
|
-
return node;
|
|
998
|
-
}
|
|
999
|
-
addTriple(s, p, o) {
|
|
1000
|
-
const node = this.ensureNode(s);
|
|
1001
|
-
let values = node.props.get(p);
|
|
1002
|
-
if (!values) {
|
|
1003
|
-
values = [];
|
|
1004
|
-
node.props.set(p, values);
|
|
1005
|
-
}
|
|
1006
|
-
values.push(o);
|
|
1007
|
-
if (p === RDF_TYPE && o.kind === "iri") {
|
|
1008
|
-
node.types.push(o.value);
|
|
1009
|
-
const instances = this.byType.get(o.value);
|
|
1010
|
-
if (instances) instances.push(s);
|
|
1011
|
-
else this.byType.set(o.value, [s]);
|
|
1012
|
-
}
|
|
1013
|
-
if (o.kind === "iri") {
|
|
1014
|
-
addEdge(this.outbound, s, p, o.value);
|
|
1015
|
-
addEdge(this.inbound, o.value, p, s);
|
|
1016
|
-
this.ensureNode(o.value);
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
/** Sort every collection so traversal order is deterministic. */
|
|
1020
|
-
finalize() {
|
|
1021
|
-
for (const node of this.nodes.values()) {
|
|
1022
|
-
node.types.sort(byCodeUnit);
|
|
1023
|
-
for (const values of node.props.values()) values.sort(compareValues);
|
|
1024
|
-
}
|
|
1025
|
-
for (const instances of this.byType.values()) instances.sort(byCodeUnit);
|
|
1026
|
-
for (const map of [this.outbound, this.inbound]) {
|
|
1027
|
-
for (const preds of map.values()) {
|
|
1028
|
-
for (const targets of preds.values()) targets.sort(byCodeUnit);
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
/** Every node IRI, sorted. */
|
|
1033
|
-
ids() {
|
|
1034
|
-
return [...this.nodes.keys()].sort(byCodeUnit);
|
|
1035
|
-
}
|
|
1036
|
-
size() {
|
|
1037
|
-
return this.nodes.size;
|
|
1038
|
-
}
|
|
1039
|
-
node(iri2) {
|
|
1040
|
-
return this.nodes.get(iri2);
|
|
1041
|
-
}
|
|
1042
|
-
has(iri2) {
|
|
1043
|
-
return this.nodes.has(iri2);
|
|
1044
|
-
}
|
|
1045
|
-
/** Class IRIs of a node, sorted. */
|
|
1046
|
-
types(iri2) {
|
|
1047
|
-
return this.nodes.get(iri2)?.types ?? [];
|
|
1048
|
-
}
|
|
1049
|
-
/** Instances of a class, sorted. */
|
|
1050
|
-
instancesOf(classIri) {
|
|
1051
|
-
return this.byType.get(classIri) ?? [];
|
|
1052
|
-
}
|
|
1053
|
-
/** All values for a predicate, sorted. */
|
|
1054
|
-
values(iri2, predicate) {
|
|
1055
|
-
return this.nodes.get(iri2)?.props.get(predicate) ?? [];
|
|
1056
|
-
}
|
|
1057
|
-
/** Literal lexical forms for a predicate, sorted. */
|
|
1058
|
-
literals(iri2, predicate) {
|
|
1059
|
-
return this.values(iri2, predicate).filter((v) => v.kind === "literal").map((v) => v.value);
|
|
1060
|
-
}
|
|
1061
|
-
/** The first literal for a predicate, if any. */
|
|
1062
|
-
literal(iri2, predicate) {
|
|
1063
|
-
return this.literals(iri2, predicate)[0];
|
|
1064
|
-
}
|
|
1065
|
-
/** Outbound IRI targets: all predicates, or one. Sorted. */
|
|
1066
|
-
out(iri2, predicate) {
|
|
1067
|
-
return edges(this.outbound, iri2, predicate);
|
|
1068
|
-
}
|
|
1069
|
-
/** Inbound IRI sources (who points at this node). Sorted. */
|
|
1070
|
-
in(iri2, predicate) {
|
|
1071
|
-
return edges(this.inbound, iri2, predicate);
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
function addEdge(map, key, predicate, target) {
|
|
1075
|
-
let preds = map.get(key);
|
|
1076
|
-
if (!preds) {
|
|
1077
|
-
preds = /* @__PURE__ */ new Map();
|
|
1078
|
-
map.set(key, preds);
|
|
1079
|
-
}
|
|
1080
|
-
const targets = preds.get(predicate);
|
|
1081
|
-
if (targets) targets.push(target);
|
|
1082
|
-
else preds.set(predicate, [target]);
|
|
1083
|
-
}
|
|
1084
|
-
function edges(map, iri2, predicate) {
|
|
1085
|
-
const preds = map.get(iri2);
|
|
1086
|
-
if (!preds) return [];
|
|
1087
|
-
const out = [];
|
|
1088
|
-
const keys = predicate ? [predicate] : [...preds.keys()].sort(byCodeUnit);
|
|
1089
|
-
for (const p of keys) {
|
|
1090
|
-
for (const target of preds.get(p) ?? []) out.push({ predicate: p, target });
|
|
1091
|
-
}
|
|
1092
|
-
return out;
|
|
1093
|
-
}
|
|
1094
|
-
function toArray(v) {
|
|
1095
|
-
if (v === void 0 || v === null) return [];
|
|
1096
|
-
return Array.isArray(v) ? v : [v];
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
499
|
// src/graph/commands/export.ts
|
|
1100
|
-
var EXPORT_TARGETS = ["jsonld", "iirds", "search"];
|
|
500
|
+
var EXPORT_TARGETS = ["jsonld", "iirds", "search", "questions"];
|
|
1101
501
|
var EXTENSION = {
|
|
1102
502
|
jsonld: ".jsonld",
|
|
1103
503
|
iirds: ".iirds"
|
|
@@ -1110,7 +510,7 @@ function runJsonLd(cwd, graphPath, out) {
|
|
|
1110
510
|
const quads = storeToQuads(store);
|
|
1111
511
|
const serialized = emitJsonLd(quads);
|
|
1112
512
|
const nodes = new Set(quads.map((q) => q.s)).size;
|
|
1113
|
-
const outPath = out ?
|
|
513
|
+
const outPath = out ? resolve2(cwd, out) : withExtension(graphPath, EXTENSION.jsonld);
|
|
1114
514
|
mkdirSync(dirname(outPath), { recursive: true });
|
|
1115
515
|
writeFileSync(outPath, serialized, "utf8");
|
|
1116
516
|
return { outPath, format: "jsonld", nodes, warnings: [] };
|
|
@@ -1128,7 +528,7 @@ function runIirds(cwd, sources, graphPath, iirds, baseIri, out) {
|
|
|
1128
528
|
sources
|
|
1129
529
|
);
|
|
1130
530
|
const metadata = emitRdfXml(projection.quads, projection.prefixes);
|
|
1131
|
-
const content = [...projection.contentFiles].sort((a, b) => byCodeUnit(a.zipPath, b.zipPath)).map((f) => ({ name: f.zipPath, data:
|
|
531
|
+
const content = [...projection.contentFiles].sort((a, b) => byCodeUnit(a.zipPath, b.zipPath)).map((f) => ({ name: f.zipPath, data: readFileSync(f.absPath) }));
|
|
1132
532
|
const entries = [
|
|
1133
533
|
{
|
|
1134
534
|
name: "mimetype",
|
|
@@ -1138,7 +538,7 @@ function runIirds(cwd, sources, graphPath, iirds, baseIri, out) {
|
|
|
1138
538
|
{ name: "META-INF/metadata.rdf", data: Buffer.from(metadata, "utf8") },
|
|
1139
539
|
...content
|
|
1140
540
|
];
|
|
1141
|
-
const outPath = out ?
|
|
541
|
+
const outPath = out ? resolve2(cwd, out) : withExtension(graphPath, EXTENSION.iirds);
|
|
1142
542
|
mkdirSync(dirname(outPath), { recursive: true });
|
|
1143
543
|
writeFileSync(outPath, writeZip(entries));
|
|
1144
544
|
const nodes = new Set(projection.quads.map((q) => q.s)).size;
|
|
@@ -1157,7 +557,7 @@ function runSearchIndex(cwd, sources, graphPath, out) {
|
|
|
1157
557
|
const index = buildSearchIndex(graph, sources, { warnings });
|
|
1158
558
|
const byLanguage = partitionByLanguage(graph, index);
|
|
1159
559
|
const docCounts = documentsByLanguage(graph);
|
|
1160
|
-
const outDir = out ?
|
|
560
|
+
const outDir = out ? resolve2(cwd, out) : dirname(graphPath);
|
|
1161
561
|
mkdirSync(outDir, { recursive: true });
|
|
1162
562
|
const languages = [];
|
|
1163
563
|
for (const [language, doc] of byLanguage) {
|
|
@@ -1192,12 +592,24 @@ function runSearchIndex(cwd, sources, graphPath, out) {
|
|
|
1192
592
|
warnings
|
|
1193
593
|
};
|
|
1194
594
|
}
|
|
1195
|
-
function
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
595
|
+
async function runQuestions(cwd, sources, graphPath, config, source, out) {
|
|
596
|
+
const { lines, stale } = await exportSampleQuestions(
|
|
597
|
+
loadGraph(graphPath),
|
|
598
|
+
sources,
|
|
599
|
+
{ source, cwd },
|
|
600
|
+
config.questionFiles,
|
|
601
|
+
config.configDir
|
|
602
|
+
);
|
|
603
|
+
const outPath = out ? resolve2(cwd, out) : join(dirname(graphPath), "questions.jsonl");
|
|
604
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
605
|
+
writeFileSync(outPath, lines.map((l) => `${l}
|
|
606
|
+
`).join(""), "utf8");
|
|
607
|
+
const warnings = stale === 0 ? [] : [
|
|
608
|
+
stale === 1 ? "1 answer changed since it was pinned, so it is exported as it reads now, marked stale." : `${String(stale)} answers changed since they were pinned, so they are exported as they read now, marked stale.`
|
|
609
|
+
];
|
|
610
|
+
return { outPath, format: "questions", nodes: lines.length, warnings };
|
|
1199
611
|
}
|
|
1200
|
-
function
|
|
612
|
+
async function runExport(opts) {
|
|
1201
613
|
const cwd = opts.cwd ?? process.cwd();
|
|
1202
614
|
if (!EXPORT_TARGETS.includes(opts.format)) {
|
|
1203
615
|
throw new GraphError(
|
|
@@ -1211,12 +623,25 @@ function exportOnce(opts) {
|
|
|
1211
623
|
},
|
|
1212
624
|
cwd
|
|
1213
625
|
);
|
|
1214
|
-
const graphPath =
|
|
626
|
+
const graphPath = resolve2(cwd, opts.graph ?? config.out);
|
|
1215
627
|
const sources = documentBase(config, {}, cwd);
|
|
1216
628
|
if (opts.format === "jsonld") return runJsonLd(cwd, graphPath, opts.out);
|
|
1217
629
|
if (opts.format === "search") {
|
|
1218
630
|
return runSearchIndex(cwd, sources, graphPath, opts.out);
|
|
1219
631
|
}
|
|
632
|
+
if (opts.format === "questions") {
|
|
633
|
+
return runQuestions(
|
|
634
|
+
cwd,
|
|
635
|
+
sources,
|
|
636
|
+
graphPath,
|
|
637
|
+
config,
|
|
638
|
+
{
|
|
639
|
+
...opts.config === void 0 ? {} : { configPath: opts.config },
|
|
640
|
+
...opts.noConfig === void 0 ? {} : { noConfig: opts.noConfig }
|
|
641
|
+
},
|
|
642
|
+
opts.out
|
|
643
|
+
);
|
|
644
|
+
}
|
|
1220
645
|
return runIirds(
|
|
1221
646
|
cwd,
|
|
1222
647
|
sources,
|
|
@@ -1228,7 +653,7 @@ function exportOnce(opts) {
|
|
|
1228
653
|
}
|
|
1229
654
|
|
|
1230
655
|
// src/graph/commands/query.ts
|
|
1231
|
-
import { resolve as
|
|
656
|
+
import { resolve as resolve3 } from "node:path";
|
|
1232
657
|
import { DataFactory as DataFactory2 } from "n3";
|
|
1233
658
|
function runQuery(opts = {}) {
|
|
1234
659
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -1239,7 +664,7 @@ function runQuery(opts = {}) {
|
|
|
1239
664
|
},
|
|
1240
665
|
cwd
|
|
1241
666
|
);
|
|
1242
|
-
const store = loadGraph(
|
|
667
|
+
const store = loadGraph(resolve3(cwd, opts.graph ?? config.out));
|
|
1243
668
|
const s = opts.s ? DataFactory2.namedNode(expandTerm(opts.s)) : null;
|
|
1244
669
|
const p = opts.p ? DataFactory2.namedNode(expandTerm(opts.p)) : null;
|
|
1245
670
|
const oValue = opts.o ? expandTerm(opts.o) : null;
|
|
@@ -1253,12 +678,13 @@ function runQuery(opts = {}) {
|
|
|
1253
678
|
o: obj.termType === "Literal" ? {
|
|
1254
679
|
kind: "literal",
|
|
1255
680
|
value: obj.value,
|
|
1256
|
-
...obj.
|
|
681
|
+
...obj.language !== "" ? { language: obj.language } : {},
|
|
682
|
+
...obj.language === "" && obj.datatype.value !== "http://www.w3.org/2001/XMLSchema#string" ? { datatype: obj.datatype.value } : {}
|
|
1257
683
|
} : { kind: "iri", value: obj.value }
|
|
1258
684
|
});
|
|
1259
685
|
}
|
|
1260
686
|
matches.sort(
|
|
1261
|
-
(a, b) => byCodeUnit(a.s, b.s) || byCodeUnit(a.p, b.p) || byCodeUnit(a.o.kind, b.o.kind) || byCodeUnit(a.o.value, b.o.value)
|
|
687
|
+
(a, b) => byCodeUnit(a.s, b.s) || byCodeUnit(a.p, b.p) || byCodeUnit(a.o.kind, b.o.kind) || byCodeUnit(a.o.value, b.o.value) || byCodeUnit(a.o.language ?? "", b.o.language ?? "")
|
|
1262
688
|
);
|
|
1263
689
|
return { matches };
|
|
1264
690
|
}
|
|
@@ -1266,7 +692,7 @@ function renderQuery(result, format) {
|
|
|
1266
692
|
if (format === "json") return JSON.stringify(result, null, 2);
|
|
1267
693
|
if (result.matches.length === 0) return "No matches.";
|
|
1268
694
|
const lines = result.matches.map((m) => {
|
|
1269
|
-
const o = m.o.kind === "iri" ? `<${m.o.value}>` : `"${m.o.value}"${m.o.datatype ? `^^${compactIri(m.o.datatype)}` : ""}`;
|
|
695
|
+
const o = m.o.kind === "iri" ? `<${m.o.value}>` : `"${m.o.value}"${m.o.language ? `@${m.o.language}` : m.o.datatype ? `^^${compactIri(m.o.datatype)}` : ""}`;
|
|
1270
696
|
return `<${m.s}> ${compactIri(m.p)} ${o}`;
|
|
1271
697
|
});
|
|
1272
698
|
lines.push(`
|
|
@@ -1275,12 +701,20 @@ ${result.matches.length} match(es)`);
|
|
|
1275
701
|
}
|
|
1276
702
|
|
|
1277
703
|
// src/graph/commands/fill.ts
|
|
1278
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
704
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1279
705
|
import { readFile } from "node:fs/promises";
|
|
1280
706
|
import { resolve as resolve6 } from "node:path";
|
|
1281
707
|
|
|
1282
708
|
// src/graph/core/frontmatter-edit.ts
|
|
1283
|
-
import {
|
|
709
|
+
import {
|
|
710
|
+
Document,
|
|
711
|
+
YAMLMap,
|
|
712
|
+
YAMLSeq,
|
|
713
|
+
isCollection,
|
|
714
|
+
isMap,
|
|
715
|
+
parseDocument,
|
|
716
|
+
visit
|
|
717
|
+
} from "yaml";
|
|
1284
718
|
var GRAPH_KEY = "graph";
|
|
1285
719
|
function frontmatterKind(content) {
|
|
1286
720
|
const body = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
|
|
@@ -1354,7 +788,7 @@ function applyGraphFields(content, path2, values, options = {}) {
|
|
|
1354
788
|
});
|
|
1355
789
|
const graph2 = doc2.get("graph", true);
|
|
1356
790
|
if (isMap(graph2)) flowSeqs(graph2);
|
|
1357
|
-
let block = doc2.toString();
|
|
791
|
+
let block = doc2.toString({ lineWidth: 0 });
|
|
1358
792
|
if (eol === "\r\n") block = block.replace(/(?<!\r)\n/g, "\r\n");
|
|
1359
793
|
return {
|
|
1360
794
|
content: `---${eol}${block}---${eol}${eol}${content}`,
|
|
@@ -1384,10 +818,26 @@ function applyGraphFields(content, path2, values, options = {}) {
|
|
|
1384
818
|
if (applied.length === 0 && pageEntries.length === 0) {
|
|
1385
819
|
return { content, applied, skipped };
|
|
1386
820
|
}
|
|
1387
|
-
let newBlock = doc.toString(
|
|
821
|
+
let newBlock = doc.toString({
|
|
822
|
+
flowCollectionPadding: flowPadding(doc, split.block),
|
|
823
|
+
lineWidth: 0
|
|
824
|
+
});
|
|
1388
825
|
if (split.eol === "\r\n") newBlock = newBlock.replace(/(?<!\r)\n/g, "\r\n");
|
|
1389
826
|
return { content: split.open + newBlock + split.suffix, applied, skipped };
|
|
1390
827
|
}
|
|
828
|
+
function flowPadding(doc, block) {
|
|
829
|
+
let padded;
|
|
830
|
+
visit(doc, (_key, node) => {
|
|
831
|
+
if (!isCollection(node) || node.flow !== true || node.items.length === 0) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
if (!node.range) return;
|
|
835
|
+
const start = node.range[0];
|
|
836
|
+
padded = /^[[{][ \t]/.test(block.slice(start, start + 2));
|
|
837
|
+
return visit.BREAK;
|
|
838
|
+
});
|
|
839
|
+
return padded ?? true;
|
|
840
|
+
}
|
|
1391
841
|
function writable(values) {
|
|
1392
842
|
return Object.entries(values).filter(
|
|
1393
843
|
([, v]) => v !== void 0 && v !== null && !(Array.isArray(v) && v.length === 0)
|
|
@@ -1483,8 +933,8 @@ function existingGraphFields(content) {
|
|
|
1483
933
|
}
|
|
1484
934
|
|
|
1485
935
|
// src/graph/core/fill-guard.ts
|
|
1486
|
-
import { readFileSync as
|
|
1487
|
-
import { resolve as
|
|
936
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
937
|
+
import { resolve as resolve4 } from "node:path";
|
|
1488
938
|
import { DataFactory as DataFactory3, Store } from "n3";
|
|
1489
939
|
var GUARDED_FIELDS = [
|
|
1490
940
|
"label",
|
|
@@ -1510,7 +960,7 @@ function toStore(quads) {
|
|
|
1510
960
|
DataFactory3.namedNode(q.p),
|
|
1511
961
|
q.o.kind === "iri" ? DataFactory3.namedNode(q.o.value) : DataFactory3.literal(
|
|
1512
962
|
q.o.value,
|
|
1513
|
-
q.o.datatype ? DataFactory3.namedNode(q.o.datatype) : void 0
|
|
963
|
+
q.o.language ?? (q.o.datatype ? DataFactory3.namedNode(q.o.datatype) : void 0)
|
|
1514
964
|
)
|
|
1515
965
|
)
|
|
1516
966
|
);
|
|
@@ -1573,7 +1023,7 @@ var FillGuard = class _FillGuard {
|
|
|
1573
1023
|
guard.models.set(
|
|
1574
1024
|
path2,
|
|
1575
1025
|
analyzeDoc(
|
|
1576
|
-
inline.get(path2) ??
|
|
1026
|
+
inline.get(path2) ?? readFileSync2(resolve4(cwd, path2), "utf8"),
|
|
1577
1027
|
path2,
|
|
1578
1028
|
guard.allPaths,
|
|
1579
1029
|
inputs.has(path2) ? guard.analyzeOptions : byExtension
|
|
@@ -1722,6 +1172,7 @@ import { JsonCache, buildCacheKey, sha256 } from "@hawkeyexl/inference";
|
|
|
1722
1172
|
|
|
1723
1173
|
// src/graph/llm/prompt.ts
|
|
1724
1174
|
var PROMPT_VERSION = 4;
|
|
1175
|
+
var QUESTION_PROMPT_VERSION = 1;
|
|
1725
1176
|
var TOPIC_TYPES = [
|
|
1726
1177
|
"task",
|
|
1727
1178
|
"concept",
|
|
@@ -1917,6 +1368,73 @@ function buildUserPrompt(doc, body, fields, options = {}) {
|
|
|
1917
1368
|
body.slice(0, EXCERPT_CHARS)
|
|
1918
1369
|
].join("\n");
|
|
1919
1370
|
}
|
|
1371
|
+
var QUESTION_SYSTEM_PROMPT = [
|
|
1372
|
+
"You write and answer the questions a reader asks of a documentation page.",
|
|
1373
|
+
"Every answer is a passage quoted VERBATIM from the page text you are given:",
|
|
1374
|
+
"copy it exactly, as one contiguous run of the text, and quote no more than",
|
|
1375
|
+
"the passage that answers. Never paraphrase a quote.",
|
|
1376
|
+
"",
|
|
1377
|
+
"For each numbered question, quote the passage that answers it, or an empty",
|
|
1378
|
+
"string when no passage in this text does. Draft only as many new questions",
|
|
1379
|
+
"as asked. Ask them as a reader would, in a reader's own words rather than",
|
|
1380
|
+
"the page's, and only questions this text answers. For every pair and draft,",
|
|
1381
|
+
"give a `confidence` (0..1) that the quote answers the question. Score",
|
|
1382
|
+
"honestly and conservatively."
|
|
1383
|
+
].join("\n");
|
|
1384
|
+
function buildQuestionPrompt(request, chunk) {
|
|
1385
|
+
const concepts = request.concepts.map(
|
|
1386
|
+
(c) => c.altLabels.length > 0 ? `- ${c.label} (also: ${c.altLabels.join(", ")})` : `- ${c.label}`
|
|
1387
|
+
);
|
|
1388
|
+
return [
|
|
1389
|
+
`Path: ${request.path}`,
|
|
1390
|
+
`Title: ${request.title}`,
|
|
1391
|
+
...concepts.length > 0 ? ["", "Concepts this page is about:", ...concepts] : [],
|
|
1392
|
+
"",
|
|
1393
|
+
request.pair.length > 0 ? `Questions to pair, by number:
|
|
1394
|
+
${request.pair.map((q, i) => `${String(i + 1)}. ${q}`).join("\n")}` : "Questions to pair: none.",
|
|
1395
|
+
"",
|
|
1396
|
+
request.draft > 0 ? `Draft ${String(request.draft)} new question${request.draft === 1 ? "" : "s"}, each with the quote that answers it.` : "Draft no new questions.",
|
|
1397
|
+
"",
|
|
1398
|
+
"Page text:",
|
|
1399
|
+
chunk
|
|
1400
|
+
].join("\n");
|
|
1401
|
+
}
|
|
1402
|
+
function questionSchema(lenient = false) {
|
|
1403
|
+
const confidence = lenient ? {} : { type: "number", minimum: 0, maximum: 1 };
|
|
1404
|
+
const item = (properties, optional = []) => ({
|
|
1405
|
+
type: "object",
|
|
1406
|
+
additionalProperties: false,
|
|
1407
|
+
required: Object.keys(properties).filter((k) => !lenient || !optional.includes(k)),
|
|
1408
|
+
properties
|
|
1409
|
+
});
|
|
1410
|
+
return item(
|
|
1411
|
+
{
|
|
1412
|
+
pairs: {
|
|
1413
|
+
type: "array",
|
|
1414
|
+
items: item(
|
|
1415
|
+
{
|
|
1416
|
+
index: { type: "integer", minimum: 1, description: "The question's number." },
|
|
1417
|
+
quote: { type: "string", description: "The verbatim passage that answers it, or an empty string." },
|
|
1418
|
+
confidence
|
|
1419
|
+
},
|
|
1420
|
+
["confidence"]
|
|
1421
|
+
)
|
|
1422
|
+
},
|
|
1423
|
+
drafts: {
|
|
1424
|
+
type: "array",
|
|
1425
|
+
items: item(
|
|
1426
|
+
{
|
|
1427
|
+
question: { type: "string", minLength: 1, description: "A question a reader would ask." },
|
|
1428
|
+
quote: { type: "string", minLength: 1, description: "The verbatim passage that answers it." },
|
|
1429
|
+
confidence
|
|
1430
|
+
},
|
|
1431
|
+
["confidence"]
|
|
1432
|
+
)
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
["pairs", "drafts"]
|
|
1436
|
+
);
|
|
1437
|
+
}
|
|
1920
1438
|
|
|
1921
1439
|
// src/graph/llm/cache.ts
|
|
1922
1440
|
function cacheKey(provider, model, content, fields, sections = false) {
|
|
@@ -1933,6 +1451,16 @@ function cacheKey(provider, model, content, fields, sections = false) {
|
|
|
1933
1451
|
sections ? "sections" : "doc-only"
|
|
1934
1452
|
]);
|
|
1935
1453
|
}
|
|
1454
|
+
function questionCacheKey(provider, model, chunk, request) {
|
|
1455
|
+
return buildCacheKey([
|
|
1456
|
+
provider,
|
|
1457
|
+
model,
|
|
1458
|
+
`q${QUESTION_PROMPT_VERSION}`,
|
|
1459
|
+
sha256(chunk),
|
|
1460
|
+
"questions",
|
|
1461
|
+
sha256(JSON.stringify(request))
|
|
1462
|
+
]);
|
|
1463
|
+
}
|
|
1936
1464
|
var FillCache = class extends JsonCache {
|
|
1937
1465
|
constructor(dir, enabled = true) {
|
|
1938
1466
|
super(dir, enabled, "manni");
|
|
@@ -1960,8 +1488,8 @@ function selectProvider2(config, flags = {}) {
|
|
|
1960
1488
|
}
|
|
1961
1489
|
]);
|
|
1962
1490
|
}
|
|
1963
|
-
function announceSelection(selection) {
|
|
1964
|
-
const message = localNotice(selection);
|
|
1491
|
+
function announceSelection(selection, flags = {}) {
|
|
1492
|
+
const message = localNotice(selection, flags);
|
|
1965
1493
|
if (message !== void 0) noticeOnce(message);
|
|
1966
1494
|
}
|
|
1967
1495
|
function assertProviderSelection(selection) {
|
|
@@ -1976,16 +1504,19 @@ function assertProviderSelection(selection) {
|
|
|
1976
1504
|
function providerSpecFor2(config, selection) {
|
|
1977
1505
|
return providerSpecFor(config.providers, selection);
|
|
1978
1506
|
}
|
|
1979
|
-
|
|
1507
|
+
function selectedSpec(config, flags) {
|
|
1980
1508
|
const selection = selectProvider2(config, flags);
|
|
1981
1509
|
const { provider, model } = selection;
|
|
1982
1510
|
assertKnownProvider(provider, toGraphError);
|
|
1983
1511
|
assertModelHasProvider(provider, model, CONFIG_KEY, toGraphError);
|
|
1984
|
-
announceSelection(selection);
|
|
1985
|
-
return
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
);
|
|
1512
|
+
announceSelection(selection, flags);
|
|
1513
|
+
return providerSpecFor2(config, { provider, model: model ?? null });
|
|
1514
|
+
}
|
|
1515
|
+
async function resolveProviderIdentity(config, flags = {}) {
|
|
1516
|
+
return resolveIdentity(selectedSpec(config, flags), toGraphError);
|
|
1517
|
+
}
|
|
1518
|
+
async function resolveOfflineIdentity(config, flags) {
|
|
1519
|
+
return offlineIdentity(selectedSpec(config, flags), toGraphError);
|
|
1989
1520
|
}
|
|
1990
1521
|
function constructProvider(config, identity) {
|
|
1991
1522
|
try {
|
|
@@ -1998,33 +1529,408 @@ async function makeProvider(config, flags = {}) {
|
|
|
1998
1529
|
return constructProvider(config, await resolveProviderIdentity(config, flags));
|
|
1999
1530
|
}
|
|
2000
1531
|
|
|
2001
|
-
// src/graph/commands/fill.ts
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
"
|
|
2008
|
-
];
|
|
2009
|
-
function numberMap(v) {
|
|
2010
|
-
const out = {};
|
|
2011
|
-
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
2012
|
-
for (const [k, val] of Object.entries(v)) {
|
|
2013
|
-
if (typeof val === "number" && val >= 0 && val <= 1) out[k] = val;
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
return out;
|
|
1532
|
+
// src/graph/commands/fill-questions.ts
|
|
1533
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1534
|
+
import { resolve as resolve5 } from "node:path";
|
|
1535
|
+
import { isMap as isMap2, isSeq, parseDocument as parseDocument2 } from "yaml";
|
|
1536
|
+
var QUESTIONS_KEY = "sample-questions";
|
|
1537
|
+
function isRecord(value) {
|
|
1538
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2017
1539
|
}
|
|
2018
|
-
function
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
1540
|
+
function round2(n) {
|
|
1541
|
+
return Math.round(n * 100) / 100;
|
|
1542
|
+
}
|
|
1543
|
+
function score(value) {
|
|
1544
|
+
return typeof value === "number" && value >= 0 && value <= 1 ? value : 0;
|
|
1545
|
+
}
|
|
1546
|
+
function linesOf(pin) {
|
|
1547
|
+
const spec = pin.lines;
|
|
1548
|
+
return typeof spec === "number" || typeof spec === "string" ? parseLines(spec) : void 0;
|
|
1549
|
+
}
|
|
1550
|
+
function readProposal(value) {
|
|
1551
|
+
const list = (v) => Array.isArray(v) ? v.filter(isRecord) : [];
|
|
1552
|
+
return {
|
|
1553
|
+
pairs: list(value.pairs).flatMap(
|
|
1554
|
+
(p) => typeof p.index === "number" && typeof p.quote === "string" ? [{ index: p.index, quote: p.quote, confidence: score(p.confidence) }] : []
|
|
1555
|
+
),
|
|
1556
|
+
drafts: list(value.drafts).flatMap(
|
|
1557
|
+
(d) => typeof d.question === "string" && d.question.trim() !== "" && typeof d.quote === "string" ? [{ question: d.question.trim(), quote: d.quote, confidence: score(d.confidence) }] : []
|
|
1558
|
+
)
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
function locateQuote(body, quote) {
|
|
1562
|
+
const wanted = quote.replace(/\s+/gu, " ").trim();
|
|
1563
|
+
if (wanted === "") return void 0;
|
|
1564
|
+
const text = body.join("\n");
|
|
1565
|
+
let folded = "";
|
|
1566
|
+
const at = [];
|
|
1567
|
+
let space = false;
|
|
1568
|
+
for (let i = 0; i < text.length; i++) {
|
|
1569
|
+
const ch = text.charAt(i);
|
|
1570
|
+
if (/\s/u.test(ch)) {
|
|
1571
|
+
if (!space && folded !== "") {
|
|
1572
|
+
folded += " ";
|
|
1573
|
+
at.push(i);
|
|
1574
|
+
}
|
|
1575
|
+
space = true;
|
|
1576
|
+
} else {
|
|
1577
|
+
folded += ch;
|
|
1578
|
+
at.push(i);
|
|
1579
|
+
space = false;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
const found = folded.indexOf(wanted);
|
|
1583
|
+
if (found < 0) return void 0;
|
|
1584
|
+
const lineAt = (offset) => text.slice(0, offset).split("\n").length;
|
|
1585
|
+
const start = at[found];
|
|
1586
|
+
const end = at[found + wanted.length - 1];
|
|
1587
|
+
if (start === void 0 || end === void 0) return void 0;
|
|
1588
|
+
const twice = folded.indexOf(wanted, found + wanted.length) >= 0;
|
|
1589
|
+
return { start: lineAt(start), end: lineAt(end), ...twice ? { ambiguous: true } : {} };
|
|
1590
|
+
}
|
|
1591
|
+
function twiceWarning(path2, question, lines) {
|
|
1592
|
+
return `${path2}: the answer to "${question}" appears more than once, so ${spellLines(lines)} is pinned; check it is the right one.`;
|
|
1593
|
+
}
|
|
1594
|
+
function pinFor(body, lines) {
|
|
1595
|
+
return { lines: lineSpec(lines), integrity: pinOfLines(body, lines) };
|
|
1596
|
+
}
|
|
1597
|
+
function relocate(pins, before, after) {
|
|
1598
|
+
const delta = after.length - before.length;
|
|
1599
|
+
let moved = false;
|
|
1600
|
+
for (const pin of pins) {
|
|
1601
|
+
const lines = linesOf(pin);
|
|
1602
|
+
const integrity = pin.integrity;
|
|
1603
|
+
if (lines === void 0 || typeof integrity !== "string") continue;
|
|
1604
|
+
if (pinOfLines(after, lines) === integrity) continue;
|
|
1605
|
+
const length = lines.end - lines.start + 1;
|
|
1606
|
+
const around = lines.start + delta;
|
|
1607
|
+
const { starts } = findWindows(after, length, integrity, void 0, { around });
|
|
1608
|
+
const [first, ...rest] = starts;
|
|
1609
|
+
if (first === void 0) continue;
|
|
1610
|
+
const nearest = rest.reduce(
|
|
1611
|
+
(best, s) => Math.abs(s - around) < Math.abs(best - around) ? s : best,
|
|
1612
|
+
first
|
|
1613
|
+
);
|
|
1614
|
+
pin.lines = lineSpec({ start: nearest, end: nearest + length - 1 });
|
|
1615
|
+
moved = true;
|
|
1616
|
+
}
|
|
1617
|
+
return moved;
|
|
1618
|
+
}
|
|
1619
|
+
function settle(tracked) {
|
|
1620
|
+
return tracked.map(({ pin, ...outcome }) => {
|
|
1621
|
+
const lines = pin === void 0 ? void 0 : linesOf(pin);
|
|
1622
|
+
return lines === void 0 ? outcome : { ...outcome, lines: spellLines(lines) };
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
async function fillPageQuestions(input) {
|
|
1626
|
+
const { path: path2, format, content, settings, asker, known } = input;
|
|
1627
|
+
const { body } = bodyOf(content, format);
|
|
1628
|
+
const held = metadataOf(content, path2, format).data[QUESTIONS_KEY];
|
|
1629
|
+
const raw = Array.isArray(held) ? held : held === void 0 ? [] : [held];
|
|
1630
|
+
const tracked = [];
|
|
1631
|
+
const warnings = [];
|
|
1632
|
+
const items = [];
|
|
1633
|
+
const pins = [];
|
|
1634
|
+
const needs = [];
|
|
1635
|
+
let questions = 0;
|
|
1636
|
+
let changed = false;
|
|
1637
|
+
for (const value of raw) {
|
|
1638
|
+
if (typeof value === "string" && value !== "") {
|
|
1639
|
+
questions++;
|
|
1640
|
+
needs.push({ at: items.length, question: value, stale: /* @__PURE__ */ new Set() });
|
|
1641
|
+
items.push(value);
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
if (!isRecord(value) || typeof value.question !== "string" || value.question === "") {
|
|
1645
|
+
items.push(value);
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
questions++;
|
|
1649
|
+
const question = value.question;
|
|
1650
|
+
const answers = Array.isArray(value.answers) ? value.answers.map((a) => isRecord(a) ? { ...a } : a) : [];
|
|
1651
|
+
const item = { ...value };
|
|
1652
|
+
if (Array.isArray(value.answers)) item.answers = answers;
|
|
1653
|
+
const stale = /* @__PURE__ */ new Set();
|
|
1654
|
+
for (const answer of answers) {
|
|
1655
|
+
if (!isRecord(answer)) continue;
|
|
1656
|
+
const lines = linesOf(answer);
|
|
1657
|
+
if (lines === void 0) continue;
|
|
1658
|
+
const integrity = answer.integrity;
|
|
1659
|
+
if (typeof integrity !== "string") {
|
|
1660
|
+
const minted = pinOfLines(body, lines);
|
|
1661
|
+
if (minted === void 0) {
|
|
1662
|
+
stale.add(answer);
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
answer.integrity = minted;
|
|
1666
|
+
pins.push(answer);
|
|
1667
|
+
tracked.push({ action: "re-pinned", question, pin: answer });
|
|
1668
|
+
changed = true;
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1671
|
+
const fresh = freshness(body, { lines, integrity, reviewed: true });
|
|
1672
|
+
if (fresh.state === "changed") {
|
|
1673
|
+
stale.add(answer);
|
|
1674
|
+
continue;
|
|
1675
|
+
}
|
|
1676
|
+
pins.push(answer);
|
|
1677
|
+
const [range] = fresh.ranges;
|
|
1678
|
+
if (fresh.state === "moved" && range !== void 0) {
|
|
1679
|
+
answer.lines = lineSpec(range);
|
|
1680
|
+
tracked.push({ action: "re-pinned", question, from: spellLines(lines), pin: answer });
|
|
1681
|
+
changed = true;
|
|
1682
|
+
} else if (fresh.state === "ambiguous") {
|
|
1683
|
+
warnings.push(
|
|
1684
|
+
`${path2}: the answer to "${question}" moved, and ${matchList(fresh.ranges)}, so pin one of them by hand.`
|
|
1685
|
+
);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
if (answers.length === 0 || stale.size > 0) {
|
|
1689
|
+
needs.push({ at: items.length, question, stale });
|
|
1690
|
+
}
|
|
1691
|
+
items.push(item);
|
|
1692
|
+
}
|
|
1693
|
+
const draft = Math.max(0, settings.perPage - questions);
|
|
1694
|
+
let state = "complete";
|
|
1695
|
+
let skipped;
|
|
1696
|
+
if (needs.length > 0 || draft > 0) {
|
|
1697
|
+
const proposals = asker === void 0 ? "offline" : await ask(asker);
|
|
1698
|
+
if (typeof proposals === "string" || asker === void 0) {
|
|
1699
|
+
skipped = typeof proposals === "string" ? proposals : "offline";
|
|
1700
|
+
state = "skipped";
|
|
1701
|
+
} else {
|
|
1702
|
+
state = "unchanged";
|
|
1703
|
+
if (pair(proposals)) changed = true;
|
|
1704
|
+
if (drafts(proposals, asker)) changed = true;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
if (!changed) {
|
|
1708
|
+
return { content, outcomes: settle(tracked), state, ...skipped ? { skipped } : {}, warnings };
|
|
1709
|
+
}
|
|
1710
|
+
const write = () => writeGraphFields(content, path2, format, {}, { page: { [QUESTIONS_KEY]: items } }).content;
|
|
1711
|
+
let next = write();
|
|
1712
|
+
let before = body;
|
|
1713
|
+
for (let round = 0; ; round++) {
|
|
1714
|
+
const after = bodyOf(next, format).body;
|
|
1715
|
+
if (!relocate(pins, before, after)) break;
|
|
1716
|
+
if (round === 2) {
|
|
1717
|
+
next = write();
|
|
1718
|
+
warnings.push(`${path2}: the answer pins did not settle, so check their lines.`);
|
|
1719
|
+
break;
|
|
1720
|
+
}
|
|
1721
|
+
before = after;
|
|
1722
|
+
next = write();
|
|
1723
|
+
}
|
|
1724
|
+
return {
|
|
1725
|
+
content: next,
|
|
1726
|
+
outcomes: settle(tracked),
|
|
1727
|
+
state: "changed",
|
|
1728
|
+
...skipped ? { skipped } : {},
|
|
1729
|
+
warnings
|
|
1730
|
+
};
|
|
1731
|
+
async function ask(model) {
|
|
1732
|
+
const request = {
|
|
1733
|
+
path: path2,
|
|
1734
|
+
title: input.title,
|
|
1735
|
+
concepts: await input.concepts(),
|
|
1736
|
+
pair: needs.map((n) => n.question),
|
|
1737
|
+
draft
|
|
1738
|
+
};
|
|
1739
|
+
const out = [];
|
|
1740
|
+
for (const chunk of splitBody(body.join("\n"), settings.chunkChars)) {
|
|
1741
|
+
const answer = await model.ask(request, chunk);
|
|
1742
|
+
if (answer === void 0) return "turn budget";
|
|
1743
|
+
out.push(readProposal(answer));
|
|
1744
|
+
}
|
|
1745
|
+
return out;
|
|
1746
|
+
}
|
|
1747
|
+
function pair(proposals) {
|
|
1748
|
+
let wrote = false;
|
|
1749
|
+
for (const [n, need] of needs.entries()) {
|
|
1750
|
+
const action = need.stale.size > 0 ? "re-paired" : "paired";
|
|
1751
|
+
const question = need.question;
|
|
1752
|
+
const candidates = proposals.flatMap((p) => p.pairs.filter((c) => c.index === n + 1 && c.quote.trim() !== "")).sort((a, b) => b.confidence - a.confidence);
|
|
1753
|
+
if (candidates.length === 0) {
|
|
1754
|
+
tracked.push({ action: "not-paired", question, reason: "no passage answers it" });
|
|
1755
|
+
continue;
|
|
1756
|
+
}
|
|
1757
|
+
let found;
|
|
1758
|
+
for (const c of candidates) {
|
|
1759
|
+
const lines = locateQuote(body, c.quote);
|
|
1760
|
+
if (lines !== void 0) {
|
|
1761
|
+
if (lines.ambiguous) warnings.push(twiceWarning(path2, question, lines));
|
|
1762
|
+
found = { lines: { start: lines.start, end: lines.end }, confidence: c.confidence };
|
|
1763
|
+
break;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
if (found === void 0) {
|
|
1767
|
+
tracked.push({ action: "not-paired", question, reason: "answer not on page" });
|
|
1768
|
+
continue;
|
|
1769
|
+
}
|
|
1770
|
+
const confidence = round2(found.confidence);
|
|
1771
|
+
if (found.confidence < settings.confidenceThreshold) {
|
|
1772
|
+
tracked.push({ action: "not-paired", question, confidence, reason: "low confidence, not written" });
|
|
1773
|
+
continue;
|
|
1774
|
+
}
|
|
1775
|
+
const pin = { ...pinFor(body, found.lines), reviewed: false };
|
|
1776
|
+
pins.push(pin);
|
|
1777
|
+
const item = items[need.at];
|
|
1778
|
+
if (typeof item === "string") {
|
|
1779
|
+
items[need.at] = { question: item, answers: [pin] };
|
|
1780
|
+
} else if (isRecord(item)) {
|
|
1781
|
+
const kept = Array.isArray(item.answers) ? item.answers.filter((a) => !need.stale.has(a)) : [];
|
|
1782
|
+
item.answers = [...kept, pin];
|
|
1783
|
+
}
|
|
1784
|
+
tracked.push({ action, question, confidence, pin });
|
|
1785
|
+
wrote = true;
|
|
1786
|
+
}
|
|
1787
|
+
return wrote;
|
|
1788
|
+
}
|
|
1789
|
+
function drafts(proposals, model) {
|
|
1790
|
+
const pool = proposals.flatMap((p) => p.drafts).sort((a, b) => b.confidence - a.confidence);
|
|
1791
|
+
let accepted = 0;
|
|
1792
|
+
for (const d of pool) {
|
|
1793
|
+
if (accepted >= draft) break;
|
|
1794
|
+
const question = d.question;
|
|
1795
|
+
const confidence = round2(d.confidence);
|
|
1796
|
+
const located = locateQuote(body, d.quote);
|
|
1797
|
+
if (located === void 0) {
|
|
1798
|
+
tracked.push({ action: "dropped", question, reason: "answer not on page" });
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
if (located.ambiguous) warnings.push(twiceWarning(path2, question, located));
|
|
1802
|
+
const lines = { start: located.start, end: located.end };
|
|
1803
|
+
const key = questionKey(question);
|
|
1804
|
+
const asked = key === "" ? void 0 : known.get(key);
|
|
1805
|
+
if (asked !== void 0) {
|
|
1806
|
+
tracked.push({ action: "dropped", question, reason: `duplicate of ${asked}` });
|
|
1807
|
+
continue;
|
|
1808
|
+
}
|
|
1809
|
+
const copied = copiedPairs(question, body.slice(lines.start - 1, lines.end).join("\n"));
|
|
1810
|
+
if (copied && copied.copied / copied.of > COPIED_SHARE) {
|
|
1811
|
+
tracked.push({
|
|
1812
|
+
action: "dropped",
|
|
1813
|
+
question,
|
|
1814
|
+
reason: `copies its answer (${String(copied.copied)} of ${String(copied.of)} word pairs)`
|
|
1815
|
+
});
|
|
1816
|
+
continue;
|
|
1817
|
+
}
|
|
1818
|
+
if (d.confidence < settings.confidenceThreshold) {
|
|
1819
|
+
tracked.push({ action: "dropped", question, confidence, reason: "low confidence, not written" });
|
|
1820
|
+
continue;
|
|
1821
|
+
}
|
|
1822
|
+
const pin = pinFor(body, lines);
|
|
1823
|
+
pins.push(pin);
|
|
1824
|
+
items.push({
|
|
1825
|
+
question,
|
|
1826
|
+
answers: [pin],
|
|
1827
|
+
...settings.writeProvenance ? { "generated-by": model.generatedBy, confidence } : {},
|
|
1828
|
+
reviewed: false
|
|
1829
|
+
});
|
|
1830
|
+
if (key !== "") known.set(key, path2);
|
|
1831
|
+
tracked.push({ action: "drafted", question, confidence, pin });
|
|
1832
|
+
accepted++;
|
|
1833
|
+
}
|
|
1834
|
+
return accepted > 0;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
function questionsIn(content, path2, format) {
|
|
1838
|
+
const held = metadataOf(content, path2, format).data[QUESTIONS_KEY];
|
|
1839
|
+
const raw = Array.isArray(held) ? held : held === void 0 ? [] : [held];
|
|
1840
|
+
return raw.flatMap(
|
|
1841
|
+
(v) => typeof v === "string" ? [v] : isRecord(v) && typeof v.question === "string" ? [v.question] : []
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
function questionsInFile(abs, label) {
|
|
1845
|
+
return readQuestionFile(abs, label).map((q) => q.question);
|
|
1846
|
+
}
|
|
1847
|
+
function repinQuestionFile(abs, label, configDir, dryRun) {
|
|
1848
|
+
const text = existsSync2(abs) ? readFileSync3(abs, "utf8") : void 0;
|
|
1849
|
+
readQuestionFile(abs, label, text);
|
|
1850
|
+
const doc = parseDocument2(text ?? "");
|
|
1851
|
+
const outcomes = [];
|
|
1852
|
+
const warnings = [];
|
|
1853
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
1854
|
+
const bodyAt = (file) => {
|
|
1855
|
+
if (!bodies.has(file)) {
|
|
1856
|
+
const page = resolve5(configDir, file);
|
|
1857
|
+
bodies.set(
|
|
1858
|
+
file,
|
|
1859
|
+
existsSync2(page) ? bodyOf(readFileSync3(page, "utf8"), formatOf(file)).body : void 0
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
return bodies.get(file);
|
|
1863
|
+
};
|
|
1864
|
+
let changed = false;
|
|
1865
|
+
const seq = doc.contents;
|
|
1866
|
+
for (const node of isSeq(seq) ? seq.items : []) {
|
|
1867
|
+
if (!isMap2(node)) continue;
|
|
1868
|
+
const question = node.get("question");
|
|
1869
|
+
const answers = node.get("answers", true);
|
|
1870
|
+
if (typeof question !== "string" || !isSeq(answers)) continue;
|
|
1871
|
+
for (const answer of answers.items) {
|
|
1872
|
+
if (!isMap2(answer)) continue;
|
|
1873
|
+
const file = answer.get("file");
|
|
1874
|
+
const spec = answer.get("lines");
|
|
1875
|
+
const lines = typeof spec === "number" || typeof spec === "string" ? parseLines(spec) : void 0;
|
|
1876
|
+
if (typeof file !== "string" || lines === void 0) continue;
|
|
1877
|
+
const body = bodyAt(file);
|
|
1878
|
+
if (body === void 0) continue;
|
|
1879
|
+
const integrity = answer.get("integrity");
|
|
1880
|
+
if (typeof integrity !== "string") {
|
|
1881
|
+
const minted = pinOfLines(body, lines);
|
|
1882
|
+
if (minted === void 0) continue;
|
|
1883
|
+
answer.set("integrity", minted);
|
|
1884
|
+
outcomes.push({ action: "re-pinned", question, file, lines: spellLines(lines) });
|
|
1885
|
+
changed = true;
|
|
1886
|
+
continue;
|
|
1887
|
+
}
|
|
1888
|
+
const fresh = freshness(body, { lines, integrity, reviewed: true });
|
|
1889
|
+
if (fresh.state === "changed") continue;
|
|
1890
|
+
const [range] = fresh.ranges;
|
|
1891
|
+
if (fresh.state === "moved" && range !== void 0) {
|
|
1892
|
+
answer.set("lines", lineSpec(range));
|
|
1893
|
+
outcomes.push({ action: "re-pinned", question, file, from: spellLines(lines), lines: spellLines(range) });
|
|
1894
|
+
changed = true;
|
|
1895
|
+
} else if (fresh.state === "ambiguous") {
|
|
1896
|
+
warnings.push(
|
|
1897
|
+
`${label}: the answer to "${question}" in ${file} moved, and ${matchList(fresh.ranges)}, so pin one of them by hand.`
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
if (changed && !dryRun) writeFileSync2(abs, doc.toString(), "utf8");
|
|
1903
|
+
return { changed, outcomes, warnings };
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
// src/graph/commands/fill.ts
|
|
1907
|
+
var TURN_BUDGET_REASON = "turn budget";
|
|
1908
|
+
var OFFLINE_REASON = "offline";
|
|
1909
|
+
var RELATION_FIELDS = [
|
|
1910
|
+
"alt-labels",
|
|
1911
|
+
"broader",
|
|
1912
|
+
"narrower",
|
|
1913
|
+
"related-concepts"
|
|
1914
|
+
];
|
|
1915
|
+
function numberMap(v) {
|
|
1916
|
+
const out = {};
|
|
1917
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
1918
|
+
for (const [k, val] of Object.entries(v)) {
|
|
1919
|
+
if (typeof val === "number" && val >= 0 && val <= 1) out[k] = val;
|
|
2023
1920
|
}
|
|
2024
1921
|
}
|
|
2025
1922
|
return out;
|
|
2026
1923
|
}
|
|
2027
|
-
function
|
|
1924
|
+
function stringMap(v) {
|
|
1925
|
+
const out = {};
|
|
1926
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
1927
|
+
for (const [k, val] of Object.entries(v)) {
|
|
1928
|
+
if (typeof val === "string") out[k] = val;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
return out;
|
|
1932
|
+
}
|
|
1933
|
+
function round22(n) {
|
|
2028
1934
|
return Math.round(n * 100) / 100;
|
|
2029
1935
|
}
|
|
2030
1936
|
var META_PROVENANCE_KEY = "meta-provenance";
|
|
@@ -2042,10 +1948,12 @@ async function runFill(opts = {}) {
|
|
|
2042
1948
|
},
|
|
2043
1949
|
cwd
|
|
2044
1950
|
);
|
|
1951
|
+
const offline = opts.offline ?? config.fill.offline;
|
|
2045
1952
|
const flags = {
|
|
2046
1953
|
...opts.provider === void 0 ? {} : { provider: opts.provider },
|
|
2047
1954
|
...opts.model === void 0 ? {} : { model: opts.model },
|
|
2048
|
-
...opts.local === void 0 ? {} : { local: opts.local }
|
|
1955
|
+
...opts.local === void 0 ? {} : { local: opts.local },
|
|
1956
|
+
...offline ? { offline: true } : {}
|
|
2049
1957
|
};
|
|
2050
1958
|
const selection = selectProvider2(config, flags);
|
|
2051
1959
|
assertProviderSelection(selection);
|
|
@@ -2077,11 +1985,20 @@ async function runFill(opts = {}) {
|
|
|
2077
1985
|
};
|
|
2078
1986
|
let identity;
|
|
2079
1987
|
let construct;
|
|
2080
|
-
if (
|
|
1988
|
+
if (offline) {
|
|
1989
|
+
const local = await resolveOfflineIdentity(config, flags);
|
|
1990
|
+
const injected = opts.providerInstance;
|
|
1991
|
+
identity = local === void 0 || injected === void 0 ? local : { provider: injected.provider(), model: injected.modelName() };
|
|
1992
|
+
construct = () => {
|
|
1993
|
+
if (injected !== void 0) return injected;
|
|
1994
|
+
if (local === void 0) throw new GraphError(noOfflineModel("nothing was proposed"));
|
|
1995
|
+
return constructProvider(config, local);
|
|
1996
|
+
};
|
|
1997
|
+
} else if (opts.providerInstance) {
|
|
2081
1998
|
const injected = opts.providerInstance;
|
|
2082
1999
|
identity = { provider: injected.provider(), model: injected.modelName() };
|
|
2083
2000
|
construct = () => injected;
|
|
2084
|
-
announceSelection(selection);
|
|
2001
|
+
announceSelection(selection, flags);
|
|
2085
2002
|
} else {
|
|
2086
2003
|
const resolved = await resolveProviderIdentity(config, flags);
|
|
2087
2004
|
identity = resolved;
|
|
@@ -2089,7 +2006,11 @@ async function runFill(opts = {}) {
|
|
|
2089
2006
|
}
|
|
2090
2007
|
let provider;
|
|
2091
2008
|
const getProvider = () => provider ??= construct();
|
|
2092
|
-
const
|
|
2009
|
+
const configured = opts.fields ?? config.fill.fields;
|
|
2010
|
+
const withQuestions = configured.includes("sample-questions");
|
|
2011
|
+
const fields = configured.filter(
|
|
2012
|
+
(f) => f !== "sample-questions"
|
|
2013
|
+
);
|
|
2093
2014
|
const withSections = opts.sections ?? config.fill.sections;
|
|
2094
2015
|
const sectionFields = withSections ? fields.filter((f) => SECTION_FILL_FIELDS.includes(f)) : void 0;
|
|
2095
2016
|
const validateProposal = validatorFor(
|
|
@@ -2178,6 +2099,93 @@ async function runFill(opts = {}) {
|
|
|
2178
2099
|
);
|
|
2179
2100
|
}
|
|
2180
2101
|
}
|
|
2102
|
+
const questionSettings = {
|
|
2103
|
+
perPage: config.fill.questions.perPage,
|
|
2104
|
+
confidenceThreshold,
|
|
2105
|
+
chunkChars: opts.chunkChars ?? config.fill.chunkChars,
|
|
2106
|
+
writeProvenance: config.fill.writeProvenance
|
|
2107
|
+
};
|
|
2108
|
+
const known = /* @__PURE__ */ new Map();
|
|
2109
|
+
if (withQuestions) {
|
|
2110
|
+
const asked = [
|
|
2111
|
+
...[...mergedTexts].sort(([a], [b]) => byCodeUnit(a, b)),
|
|
2112
|
+
...stdinContent === void 0 ? [] : [[STDIN_PATH, stdinContent]]
|
|
2113
|
+
];
|
|
2114
|
+
for (const [path2, text] of asked) {
|
|
2115
|
+
for (const q of questionsIn(text, path2, formatOf(path2, formatFor(path2)))) {
|
|
2116
|
+
const key = questionKey(q);
|
|
2117
|
+
if (key !== "" && !known.has(key)) known.set(key, path2);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
for (const label of config.questionFiles) {
|
|
2121
|
+
for (const q of questionsInFile(resolve6(config.configDir, label), label)) {
|
|
2122
|
+
const key = questionKey(q);
|
|
2123
|
+
if (key !== "" && !known.has(key)) known.set(key, label);
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
const questionValidator = validatorFor(questionSchema(true));
|
|
2128
|
+
const questionRequestSchema = questionSchema();
|
|
2129
|
+
const asker = identity === void 0 ? void 0 : questionAsker(identity);
|
|
2130
|
+
function questionAsker(id) {
|
|
2131
|
+
return {
|
|
2132
|
+
generatedBy: `${id.provider}/${id.model}`,
|
|
2133
|
+
ask: async (request, chunk) => {
|
|
2134
|
+
const key = questionCacheKey(id.provider, id.model, chunk, request);
|
|
2135
|
+
const hit = cache.get(key);
|
|
2136
|
+
if (hit !== void 0 && questionValidator(hit)) return hit;
|
|
2137
|
+
if (maxTurns !== null && turnsUsed >= maxTurns) return void 0;
|
|
2138
|
+
turnsUsed++;
|
|
2139
|
+
const run = await completeValidatedJSON({
|
|
2140
|
+
provider: getProvider(),
|
|
2141
|
+
system: QUESTION_SYSTEM_PROMPT,
|
|
2142
|
+
user: buildQuestionPrompt(request, chunk),
|
|
2143
|
+
schema: questionRequestSchema,
|
|
2144
|
+
validate: questionValidator,
|
|
2145
|
+
temperature: config.fill.temperature
|
|
2146
|
+
});
|
|
2147
|
+
if (run.result === void 0) {
|
|
2148
|
+
throw new Error(run.error ?? "provider returned no questions");
|
|
2149
|
+
}
|
|
2150
|
+
cache.set(key, run.result);
|
|
2151
|
+
return run.result;
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
let terms;
|
|
2156
|
+
const termsOnce = () => terms ??= (async () => {
|
|
2157
|
+
const source = termLabelSource();
|
|
2158
|
+
if (!config.build.derive.includes("terms") || source === void 0) return void 0;
|
|
2159
|
+
try {
|
|
2160
|
+
return termIndex(
|
|
2161
|
+
await source({
|
|
2162
|
+
cwd,
|
|
2163
|
+
...opts.config === void 0 ? {} : { configPath: opts.config },
|
|
2164
|
+
...opts.noConfig === true ? { noConfig: true } : {}
|
|
2165
|
+
})
|
|
2166
|
+
);
|
|
2167
|
+
} catch {
|
|
2168
|
+
return void 0;
|
|
2169
|
+
}
|
|
2170
|
+
})();
|
|
2171
|
+
async function conceptsOf(data) {
|
|
2172
|
+
const strings = (v) => typeof v === "string" ? [v] : Array.isArray(v) ? v.filter((s) => typeof s === "string") : [];
|
|
2173
|
+
const block = data[GRAPH_KEY2];
|
|
2174
|
+
const graph = block !== null && typeof block === "object" && !Array.isArray(block) ? block : {};
|
|
2175
|
+
const out = /* @__PURE__ */ new Map();
|
|
2176
|
+
for (const label of strings(graph["label"])) out.set(label, strings(graph["alt-labels"]));
|
|
2177
|
+
const named = strings(graph["concepts"] ?? data["concepts"]);
|
|
2178
|
+
const index = named.length > 0 ? await termsOnce() : void 0;
|
|
2179
|
+
const language = typeof data["language"] === "string" ? canonicalLanguage(data["language"]) : void 0;
|
|
2180
|
+
for (const label of named) {
|
|
2181
|
+
const id = index?.resolve(label, language);
|
|
2182
|
+
const group = id === void 0 ? void 0 : index?.groups.get(id);
|
|
2183
|
+
const term = group?.find((t) => canonicalLanguage(t.language) === language) ?? group?.[0];
|
|
2184
|
+
if (term === void 0) out.set(label, out.get(label) ?? []);
|
|
2185
|
+
else out.set(term.label, [...term.altLabels ?? []]);
|
|
2186
|
+
}
|
|
2187
|
+
return [...out].map(([label, altLabels]) => ({ label, altLabels }));
|
|
2188
|
+
}
|
|
2181
2189
|
for (const path2 of files) {
|
|
2182
2190
|
const absPath = resolve6(base2, path2);
|
|
2183
2191
|
let content;
|
|
@@ -2189,7 +2197,7 @@ async function runFill(opts = {}) {
|
|
|
2189
2197
|
);
|
|
2190
2198
|
}
|
|
2191
2199
|
try {
|
|
2192
|
-
results.push(await
|
|
2200
|
+
results.push(await fillPage(path2, absPath, content));
|
|
2193
2201
|
} catch (e) {
|
|
2194
2202
|
results.push({
|
|
2195
2203
|
path: path2,
|
|
@@ -2204,7 +2212,7 @@ async function runFill(opts = {}) {
|
|
|
2204
2212
|
let stdinDocument;
|
|
2205
2213
|
if (stdinContent !== void 0) {
|
|
2206
2214
|
try {
|
|
2207
|
-
const result = await
|
|
2215
|
+
const result = await fillPage(STDIN_PATH, void 0, stdinContent);
|
|
2208
2216
|
results.push(result);
|
|
2209
2217
|
stdinDocument = result.filledContent ?? stdinContent;
|
|
2210
2218
|
Reflect.deleteProperty(result, "filledContent");
|
|
@@ -2219,6 +2227,32 @@ async function runFill(opts = {}) {
|
|
|
2219
2227
|
});
|
|
2220
2228
|
}
|
|
2221
2229
|
}
|
|
2230
|
+
if (withQuestions) {
|
|
2231
|
+
for (const label of config.questionFiles) {
|
|
2232
|
+
const repinned = repinQuestionFile(
|
|
2233
|
+
resolve6(config.configDir, label),
|
|
2234
|
+
label,
|
|
2235
|
+
config.configDir,
|
|
2236
|
+
opts.dryRun ?? false
|
|
2237
|
+
);
|
|
2238
|
+
warnings.push(...repinned.warnings);
|
|
2239
|
+
results.push({
|
|
2240
|
+
path: label,
|
|
2241
|
+
status: repinned.changed ? opts.dryRun ? "proposed" : "filled" : "complete",
|
|
2242
|
+
fields: repinned.changed ? [QUESTIONS_KEY] : [],
|
|
2243
|
+
preserved: [],
|
|
2244
|
+
cached: false,
|
|
2245
|
+
...repinned.outcomes.length > 0 ? { questions: repinned.outcomes } : {}
|
|
2246
|
+
});
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
if (offline && identity === void 0 && results.some((r) => r.reason === OFFLINE_REASON)) {
|
|
2250
|
+
warnings.push(
|
|
2251
|
+
noOfflineModel(
|
|
2252
|
+
withQuestions ? "only answer pins were updated, and nothing was drafted or proposed" : "nothing was proposed"
|
|
2253
|
+
)
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2222
2256
|
if (sectionsUnrecorded.length > 0) {
|
|
2223
2257
|
warnings.push(
|
|
2224
2258
|
"Section metadata was written but is NOT recorded in meta-provenance: /graph/sections is one of the three hand-curated pointers graph refuses, with /graph/revision-of and /graph/derived-from, so recording it would make `manni graph check` report an error. Review section values by hand \u2014 the review queue will not list them."
|
|
@@ -2233,6 +2267,45 @@ async function runFill(opts = {}) {
|
|
|
2233
2267
|
exitCode: hasErrors ? 1 : 0,
|
|
2234
2268
|
...stdinDocument === void 0 ? {} : { stdinDocument }
|
|
2235
2269
|
};
|
|
2270
|
+
async function fillPage(path2, absPath, content) {
|
|
2271
|
+
const { after, merged, ...result } = await fillOne(path2, absPath, content);
|
|
2272
|
+
if (!withQuestions) return result;
|
|
2273
|
+
const pageFormat = formatOf(path2, format);
|
|
2274
|
+
const data = metadataOf(merged ?? mergedTexts.get(path2) ?? content, path2, pageFormat).data;
|
|
2275
|
+
const pass = await fillPageQuestions({
|
|
2276
|
+
path: path2,
|
|
2277
|
+
format: pageFormat,
|
|
2278
|
+
content: after ?? content,
|
|
2279
|
+
title: typeof data["title"] === "string" ? data["title"] : path2,
|
|
2280
|
+
concepts: () => conceptsOf(data),
|
|
2281
|
+
settings: questionSettings,
|
|
2282
|
+
asker,
|
|
2283
|
+
known
|
|
2284
|
+
});
|
|
2285
|
+
warnings.push(...pass.warnings);
|
|
2286
|
+
const outcomes = pass.outcomes.length > 0 ? { questions: pass.outcomes } : {};
|
|
2287
|
+
if (pass.state === "changed") {
|
|
2288
|
+
if (!opts.dryRun) {
|
|
2289
|
+
if (absPath === void 0) result.filledContent = pass.content;
|
|
2290
|
+
else writeFileSync3(absPath, pass.content, "utf8");
|
|
2291
|
+
}
|
|
2292
|
+
return {
|
|
2293
|
+
...result,
|
|
2294
|
+
status: opts.dryRun ? "proposed" : "filled",
|
|
2295
|
+
fields: [...result.fields, QUESTIONS_KEY],
|
|
2296
|
+
...pass.skipped === void 0 ? {} : { reason: pass.skipped },
|
|
2297
|
+
...outcomes
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
const idle = result.status === "complete" || result.status === "nothing-proposed";
|
|
2301
|
+
if (idle && pass.state === "skipped") {
|
|
2302
|
+
return { ...result, status: "skipped", ...pass.skipped === void 0 ? {} : { reason: pass.skipped }, ...outcomes };
|
|
2303
|
+
}
|
|
2304
|
+
if (result.status === "complete" && pass.state === "unchanged") {
|
|
2305
|
+
return { ...result, status: "nothing-proposed", ...outcomes };
|
|
2306
|
+
}
|
|
2307
|
+
return { ...result, ...outcomes };
|
|
2308
|
+
}
|
|
2236
2309
|
async function fillOne(path2, absPath, content) {
|
|
2237
2310
|
const pageFormat = formatOf(path2, format);
|
|
2238
2311
|
if ((pageFormat === "markdown" || pageFormat === "mdx") && frontmatterKind(content) === "unsupported") {
|
|
@@ -2262,7 +2335,7 @@ async function runFill(opts = {}) {
|
|
|
2262
2335
|
heldGraph !== null && typeof heldGraph === "object" && !Array.isArray(heldGraph) ? Object.keys(heldGraph) : []
|
|
2263
2336
|
);
|
|
2264
2337
|
const missing = opts.force ? fields : fields.filter((f) => !present.has(f));
|
|
2265
|
-
if (missing.length === 0 && !withSections) {
|
|
2338
|
+
if (fields.length === 0 || missing.length === 0 && !withSections) {
|
|
2266
2339
|
return {
|
|
2267
2340
|
path: path2,
|
|
2268
2341
|
status: "complete",
|
|
@@ -2271,6 +2344,16 @@ async function runFill(opts = {}) {
|
|
|
2271
2344
|
cached: false
|
|
2272
2345
|
};
|
|
2273
2346
|
}
|
|
2347
|
+
if (identity === void 0) {
|
|
2348
|
+
return {
|
|
2349
|
+
path: path2,
|
|
2350
|
+
status: "skipped",
|
|
2351
|
+
reason: OFFLINE_REASON,
|
|
2352
|
+
fields: [],
|
|
2353
|
+
preserved: [],
|
|
2354
|
+
cached: false
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2274
2357
|
const key = cacheKey(
|
|
2275
2358
|
identity.provider,
|
|
2276
2359
|
identity.model,
|
|
@@ -2321,15 +2404,15 @@ async function runFill(opts = {}) {
|
|
|
2321
2404
|
const unknownSlugs = [];
|
|
2322
2405
|
if (withSections) {
|
|
2323
2406
|
const realSlugs = new Set(doc().sections.map((s) => s.slug));
|
|
2324
|
-
for (const
|
|
2325
|
-
const slug = typeof
|
|
2407
|
+
for (const entry of Array.isArray(proposal["sections"]) ? proposal["sections"] : []) {
|
|
2408
|
+
const slug = typeof entry["slug"] === "string" ? entry["slug"] : "";
|
|
2326
2409
|
if (!realSlugs.has(slug)) {
|
|
2327
2410
|
if (slug) unknownSlugs.push(slug);
|
|
2328
2411
|
continue;
|
|
2329
2412
|
}
|
|
2330
|
-
const entryConfidence = numberMap(
|
|
2331
|
-
const entryReasoning = stringMap(
|
|
2332
|
-
for (const [field, value] of Object.entries(
|
|
2413
|
+
const entryConfidence = numberMap(entry["confidence"]);
|
|
2414
|
+
const entryReasoning = stringMap(entry["reasoning"]);
|
|
2415
|
+
for (const [field, value] of Object.entries(entry)) {
|
|
2333
2416
|
if (!SECTION_FILL_FIELDS.includes(field)) continue;
|
|
2334
2417
|
if (!fields.includes(field)) continue;
|
|
2335
2418
|
const name = `sections.${slug}.${field}`;
|
|
@@ -2401,7 +2484,7 @@ async function runFill(opts = {}) {
|
|
|
2401
2484
|
const c = confidence[f];
|
|
2402
2485
|
return {
|
|
2403
2486
|
name,
|
|
2404
|
-
confidence: c === void 0 ? priorConfidence[name] ?? 0 :
|
|
2487
|
+
confidence: c === void 0 ? priorConfidence[name] ?? 0 : round22(c)
|
|
2405
2488
|
};
|
|
2406
2489
|
});
|
|
2407
2490
|
const unscored = recordable.map((f) => [f, graphPointer(f)]).filter(
|
|
@@ -2474,7 +2557,7 @@ async function runFill(opts = {}) {
|
|
|
2474
2557
|
}
|
|
2475
2558
|
const manifests = await spliceAll(manifestWrites);
|
|
2476
2559
|
if (!opts.dryRun && absPath !== void 0) {
|
|
2477
|
-
if (pageContent !== content)
|
|
2560
|
+
if (pageContent !== content) writeFileSync3(absPath, pageContent, "utf8");
|
|
2478
2561
|
for (const m of manifests) {
|
|
2479
2562
|
if (m.text !== m.before) {
|
|
2480
2563
|
await writeFileAtomic(m.absPath, m.text, { createParents: true });
|
|
@@ -2483,6 +2566,8 @@ async function runFill(opts = {}) {
|
|
|
2483
2566
|
}
|
|
2484
2567
|
guard?.commit(path2, applied.content);
|
|
2485
2568
|
return {
|
|
2569
|
+
after: pageContent,
|
|
2570
|
+
merged: applied.content,
|
|
2486
2571
|
path: path2,
|
|
2487
2572
|
status: opts.dryRun ? "proposed" : "filled",
|
|
2488
2573
|
fields: reportedFields,
|
|
@@ -2573,6 +2658,17 @@ async function openMetaViewPerPage(source, cwd, paths, base2, failures) {
|
|
|
2573
2658
|
return openMetaView(source, cwd, readable, base2);
|
|
2574
2659
|
}
|
|
2575
2660
|
}
|
|
2661
|
+
function questionLine(q) {
|
|
2662
|
+
const score2 = q.confidence === void 0 ? "" : ` (${q.confidence.toFixed(2)})`;
|
|
2663
|
+
let detail;
|
|
2664
|
+
if (q.reason !== void 0) {
|
|
2665
|
+
detail = `${q.reason}${q.reason.startsWith("low confidence") ? score2 : ""}`;
|
|
2666
|
+
} else {
|
|
2667
|
+
const where = `${q.file === void 0 ? "" : `${q.file} `}lines ${q.from ?? q.lines ?? ""}`;
|
|
2668
|
+
detail = q.action === "re-pinned" ? `${where}${q.from === void 0 || q.lines === void 0 ? "" : ` to ${q.lines}`}` : `${where}${score2}`;
|
|
2669
|
+
}
|
|
2670
|
+
return `${q.action.padEnd(11)}"${q.question}" ${detail}`;
|
|
2671
|
+
}
|
|
2576
2672
|
function renderFill(report, format) {
|
|
2577
2673
|
if (format === "json") {
|
|
2578
2674
|
return JSON.stringify({ ...report, stdinDocument: void 0 }, null, 2);
|
|
@@ -2608,6 +2704,7 @@ function renderFill(report, format) {
|
|
|
2608
2704
|
lines.push(`error ${r.path}: ${r.error ?? ""}`);
|
|
2609
2705
|
break;
|
|
2610
2706
|
}
|
|
2707
|
+
for (const q of r.questions ?? []) lines.push(` ${questionLine(q)}`);
|
|
2611
2708
|
}
|
|
2612
2709
|
if (report.maxTurns !== null && report.results.some((r) => r.status === "skipped")) {
|
|
2613
2710
|
lines.push(
|
|
@@ -2620,196 +2717,10 @@ function renderFill(report, format) {
|
|
|
2620
2717
|
|
|
2621
2718
|
// src/graph/commands/embed.ts
|
|
2622
2719
|
import { createHash as createHash2 } from "node:crypto";
|
|
2623
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as
|
|
2720
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2624
2721
|
import path, { dirname as dirname2, join as join2, resolve as resolve7 } from "node:path";
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
var MAGIC = new Uint8Array([77, 71, 82, 86]);
|
|
2628
|
-
var FORMAT_VERSION = 2;
|
|
2629
|
-
var HEADER_OFFSET = 12;
|
|
2630
|
-
var VectorIndexError = class extends Error {
|
|
2631
|
-
constructor(message) {
|
|
2632
|
-
super(message);
|
|
2633
|
-
this.name = "VectorIndexError";
|
|
2634
|
-
}
|
|
2635
|
-
};
|
|
2636
|
-
function normalize(vector) {
|
|
2637
|
-
let sum = 0;
|
|
2638
|
-
for (const value of vector) sum += value * value;
|
|
2639
|
-
if (sum === 0) return vector;
|
|
2640
|
-
const inv = 1 / Math.sqrt(sum);
|
|
2641
|
-
vector.set(vector.map((value) => value * inv));
|
|
2642
|
-
return vector;
|
|
2643
|
-
}
|
|
2644
|
-
function encodeVectorIndex(entries, meta) {
|
|
2645
|
-
const sorted = [...entries].sort((a, b) => byCodeUnit(a.id, b.id));
|
|
2646
|
-
const dims = sorted[0]?.vector.length ?? 0;
|
|
2647
|
-
for (const entry2 of sorted) {
|
|
2648
|
-
if (entry2.vector.length !== dims) {
|
|
2649
|
-
throw new VectorIndexError(
|
|
2650
|
-
`Inconsistent vector dimensions: ${entry2.id} has ${entry2.vector.length}, expected ${dims}.`
|
|
2651
|
-
);
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
const header = {
|
|
2655
|
-
model: meta.model,
|
|
2656
|
-
dtype: meta.dtype,
|
|
2657
|
-
dims,
|
|
2658
|
-
count: sorted.length,
|
|
2659
|
-
ids: sorted.map((e) => e.id),
|
|
2660
|
-
source: meta.source,
|
|
2661
|
-
language: meta.language
|
|
2662
|
-
};
|
|
2663
|
-
const headerBytes = new TextEncoder().encode(JSON.stringify(header));
|
|
2664
|
-
const payloadBytes = sorted.length * dims * 4;
|
|
2665
|
-
const out = new Uint8Array(HEADER_OFFSET + headerBytes.length + payloadBytes);
|
|
2666
|
-
const view = new DataView(out.buffer);
|
|
2667
|
-
out.set(MAGIC, 0);
|
|
2668
|
-
view.setUint32(4, FORMAT_VERSION, true);
|
|
2669
|
-
view.setUint32(8, headerBytes.length, true);
|
|
2670
|
-
out.set(headerBytes, HEADER_OFFSET);
|
|
2671
|
-
let offset = HEADER_OFFSET + headerBytes.length;
|
|
2672
|
-
for (const entry2 of sorted) {
|
|
2673
|
-
const vector = normalize(Float32Array.from(entry2.vector));
|
|
2674
|
-
for (const value of vector) {
|
|
2675
|
-
view.setFloat32(offset, value, true);
|
|
2676
|
-
offset += 4;
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
return out;
|
|
2680
|
-
}
|
|
2681
|
-
function decodeVectorIndex(bytes) {
|
|
2682
|
-
if (bytes.length < HEADER_OFFSET) {
|
|
2683
|
-
throw new VectorIndexError("Not a manni graph vector index: file is too short.");
|
|
2684
|
-
}
|
|
2685
|
-
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2686
|
-
if (!MAGIC.every((byte, i) => bytes[i] === byte)) {
|
|
2687
|
-
throw new VectorIndexError(
|
|
2688
|
-
"Not a manni graph vector index: bad magic \u2014 is this the right file?"
|
|
2689
|
-
);
|
|
2690
|
-
}
|
|
2691
|
-
const version = view.getUint32(4, true);
|
|
2692
|
-
if (version !== FORMAT_VERSION) {
|
|
2693
|
-
throw new VectorIndexError(
|
|
2694
|
-
`Unsupported vector index version ${version} (this build reads ${FORMAT_VERSION}) \u2014 re-run \`manni graph embed\`.`
|
|
2695
|
-
);
|
|
2696
|
-
}
|
|
2697
|
-
const headerLength = view.getUint32(8, true);
|
|
2698
|
-
if (HEADER_OFFSET + headerLength > bytes.length) {
|
|
2699
|
-
throw new VectorIndexError("Vector index is truncated: header overruns.");
|
|
2700
|
-
}
|
|
2701
|
-
let header;
|
|
2702
|
-
try {
|
|
2703
|
-
header = JSON.parse(
|
|
2704
|
-
new TextDecoder().decode(
|
|
2705
|
-
bytes.subarray(HEADER_OFFSET, HEADER_OFFSET + headerLength)
|
|
2706
|
-
)
|
|
2707
|
-
);
|
|
2708
|
-
} catch {
|
|
2709
|
-
throw new VectorIndexError("Vector index header is not valid JSON.");
|
|
2710
|
-
}
|
|
2711
|
-
if (!Array.isArray(header.ids) || typeof header.dims !== "number" || header.ids.length !== header.count) {
|
|
2712
|
-
throw new VectorIndexError("Vector index header is malformed.");
|
|
2713
|
-
}
|
|
2714
|
-
const start = HEADER_OFFSET + headerLength;
|
|
2715
|
-
const expected = header.count * header.dims * 4;
|
|
2716
|
-
if (bytes.length - start !== expected) {
|
|
2717
|
-
throw new VectorIndexError(
|
|
2718
|
-
`Vector index is truncated: expected ${expected} payload bytes, found ${bytes.length - start}.`
|
|
2719
|
-
);
|
|
2720
|
-
}
|
|
2721
|
-
const vectors = new Float32Array(header.count * header.dims);
|
|
2722
|
-
for (let i = 0; i < vectors.length; i++) {
|
|
2723
|
-
vectors[i] = view.getFloat32(start + i * 4, true);
|
|
2724
|
-
}
|
|
2725
|
-
return { header, vectors };
|
|
2726
|
-
}
|
|
2727
|
-
|
|
2728
|
-
// src/graph/embed/local.ts
|
|
2729
|
-
var EmbedderUnavailableError = class extends Error {
|
|
2730
|
-
constructor(detail) {
|
|
2731
|
-
super(
|
|
2732
|
-
`Local embeddings need @huggingface/transformers, which is an optional peer dependency.
|
|
2733
|
-
Install it: npm install @huggingface/transformers
|
|
2734
|
-
(${detail})`
|
|
2735
|
-
);
|
|
2736
|
-
this.name = "EmbedderUnavailableError";
|
|
2737
|
-
}
|
|
2738
|
-
};
|
|
2739
|
-
async function loadTransformers(injected) {
|
|
2740
|
-
if (injected) return injected;
|
|
2741
|
-
try {
|
|
2742
|
-
return await import("@huggingface/transformers");
|
|
2743
|
-
} catch (e) {
|
|
2744
|
-
throw new EmbedderUnavailableError(
|
|
2745
|
-
errorMessage(e)
|
|
2746
|
-
);
|
|
2747
|
-
}
|
|
2748
|
-
}
|
|
2749
|
-
async function createLocalEmbedder(options = {}) {
|
|
2750
|
-
const model = options.model ?? DEFAULT_MODEL;
|
|
2751
|
-
const dtype = options.dtype ?? "q8";
|
|
2752
|
-
const role = options.role ?? "passage";
|
|
2753
|
-
const profile = profileFor(model);
|
|
2754
|
-
const transformers = await loadTransformers(options.transformers);
|
|
2755
|
-
if (transformers.env?.backends?.onnx?.wasm) {
|
|
2756
|
-
transformers.env.backends.onnx.wasm.numThreads = 1;
|
|
2757
|
-
}
|
|
2758
|
-
const extractor = await transformers.pipeline("feature-extraction", model, {
|
|
2759
|
-
// No `device`: its accepted values are disjoint across platforms, so any
|
|
2760
|
-
// hardcoded choice throws on one of them (ADR 01025).
|
|
2761
|
-
...options.device === void 0 ? {} : { device: options.device },
|
|
2762
|
-
dtype
|
|
2763
|
-
});
|
|
2764
|
-
let dims = 0;
|
|
2765
|
-
return {
|
|
2766
|
-
model,
|
|
2767
|
-
dtype,
|
|
2768
|
-
get dims() {
|
|
2769
|
-
return dims;
|
|
2770
|
-
},
|
|
2771
|
-
async embed(text) {
|
|
2772
|
-
const output = await extractor(withPrefix(profile, role, text), {
|
|
2773
|
-
pooling: "mean",
|
|
2774
|
-
normalize: true
|
|
2775
|
-
});
|
|
2776
|
-
const data = Float32Array.from(output.data);
|
|
2777
|
-
dims = data.length;
|
|
2778
|
-
return data;
|
|
2779
|
-
}
|
|
2780
|
-
};
|
|
2781
|
-
}
|
|
2782
|
-
|
|
2783
|
-
// src/graph/embed/mock.ts
|
|
2784
|
-
function fnv1a(text, seed) {
|
|
2785
|
-
let hash = (2166136261 ^ seed) >>> 0;
|
|
2786
|
-
for (let i = 0; i < text.length; i++) {
|
|
2787
|
-
hash = (hash ^ text.charCodeAt(i)) >>> 0;
|
|
2788
|
-
hash = hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)) >>> 0;
|
|
2789
|
-
}
|
|
2790
|
-
return hash >>> 0;
|
|
2791
|
-
}
|
|
2792
|
-
function createMockEmbedder(options = {}) {
|
|
2793
|
-
const dims = options.dims ?? 8;
|
|
2794
|
-
const model = options.model ?? "mock";
|
|
2795
|
-
const dtype = options.dtype ?? "mock";
|
|
2796
|
-
return {
|
|
2797
|
-
model,
|
|
2798
|
-
dtype,
|
|
2799
|
-
dims,
|
|
2800
|
-
embed(text) {
|
|
2801
|
-
const vector = new Float32Array(dims);
|
|
2802
|
-
for (let i = 0; i < dims; i++) {
|
|
2803
|
-
vector[i] = fnv1a(text, i) / 4294967296 * 2 - 1;
|
|
2804
|
-
}
|
|
2805
|
-
return Promise.resolve(vector);
|
|
2806
|
-
}
|
|
2807
|
-
};
|
|
2808
|
-
}
|
|
2809
|
-
|
|
2810
|
-
// src/graph/commands/embed.ts
|
|
2811
|
-
function embedText(entry2) {
|
|
2812
|
-
return [entry2.title, entry2.labels, entry2.description, entry2.text].filter((part) => part !== void 0 && part !== "").join("\n\n");
|
|
2722
|
+
function embedText(entry) {
|
|
2723
|
+
return [entry.title, entry.labels, entry.description, entry.text].filter((part) => part !== void 0 && part !== "").join("\n\n");
|
|
2813
2724
|
}
|
|
2814
2725
|
function sha2562(text) {
|
|
2815
2726
|
return createHash2("sha256").update(text, "utf8").digest("hex");
|
|
@@ -2838,7 +2749,7 @@ var VectorCache = class {
|
|
|
2838
2749
|
set(key, vector) {
|
|
2839
2750
|
if (!this.enabled) return;
|
|
2840
2751
|
mkdirSync2(this.dir, { recursive: true });
|
|
2841
|
-
|
|
2752
|
+
writeFileSync4(this.path(key), JSON.stringify([...vector]), "utf8");
|
|
2842
2753
|
}
|
|
2843
2754
|
};
|
|
2844
2755
|
async function makeEmbedder(opts, model, dtype) {
|
|
@@ -2906,8 +2817,8 @@ async function runEmbed(opts = {}) {
|
|
|
2906
2817
|
};
|
|
2907
2818
|
const languages = [];
|
|
2908
2819
|
const updated = [];
|
|
2909
|
-
for (const
|
|
2910
|
-
const indexPath = join2(indexDir,
|
|
2820
|
+
for (const entry of manifest.languages) {
|
|
2821
|
+
const indexPath = join2(indexDir, entry.search.path);
|
|
2911
2822
|
if (!existsSync3(indexPath)) {
|
|
2912
2823
|
throw new GraphError(
|
|
2913
2824
|
`Search index not found: ${indexPath} \u2014 the manifest names it; re-run \`manni graph export search\`.`
|
|
@@ -2915,9 +2826,9 @@ async function runEmbed(opts = {}) {
|
|
|
2915
2826
|
}
|
|
2916
2827
|
const raw = readFileSync5(indexPath, "utf8");
|
|
2917
2828
|
const source = `sha256:${sha2562(raw)}`;
|
|
2918
|
-
if (
|
|
2829
|
+
if (entry.search.digest !== source) {
|
|
2919
2830
|
throw new GraphError(
|
|
2920
|
-
`Stale manifest: ${
|
|
2831
|
+
`Stale manifest: ${entry.search.path} does not match the digest recorded for "${entry.language}" \u2014 re-run \`manni graph export search\`.`
|
|
2921
2832
|
);
|
|
2922
2833
|
}
|
|
2923
2834
|
let parsed;
|
|
@@ -2934,7 +2845,7 @@ async function runEmbed(opts = {}) {
|
|
|
2934
2845
|
`Not a manni graph search index: ${indexPath} \u2014 expected an \`entries\` array.`
|
|
2935
2846
|
);
|
|
2936
2847
|
}
|
|
2937
|
-
const wanted = canonicalLanguageTag(
|
|
2848
|
+
const wanted = canonicalLanguageTag(entry.language);
|
|
2938
2849
|
const perLanguage = Object.entries(config.embed.byLanguage).find(
|
|
2939
2850
|
([tag]) => canonicalLanguageTag(tag) === wanted
|
|
2940
2851
|
)?.[1];
|
|
@@ -2960,21 +2871,21 @@ async function runEmbed(opts = {}) {
|
|
|
2960
2871
|
}
|
|
2961
2872
|
vectors.push({ id: item.id, vector });
|
|
2962
2873
|
}
|
|
2963
|
-
const filename = vectorIndexFilename(
|
|
2874
|
+
const filename = vectorIndexFilename(entry.language);
|
|
2964
2875
|
const outPath = join2(outDir, filename);
|
|
2965
2876
|
const manifestRelative = manifestRelativePath(indexDir, outPath);
|
|
2966
|
-
|
|
2877
|
+
writeFileSync4(
|
|
2967
2878
|
outPath,
|
|
2968
2879
|
encodeVectorIndex(vectors, {
|
|
2969
2880
|
model: identity.model,
|
|
2970
2881
|
dtype: identity.dtype,
|
|
2971
2882
|
source,
|
|
2972
|
-
language:
|
|
2883
|
+
language: entry.language
|
|
2973
2884
|
})
|
|
2974
2885
|
);
|
|
2975
2886
|
const dims = vectors[0]?.vector.length ?? 0;
|
|
2976
2887
|
languages.push({
|
|
2977
|
-
language:
|
|
2888
|
+
language: entry.language,
|
|
2978
2889
|
outPath,
|
|
2979
2890
|
model: identity.model,
|
|
2980
2891
|
dims,
|
|
@@ -2983,7 +2894,7 @@ async function runEmbed(opts = {}) {
|
|
|
2983
2894
|
total: vectors.length
|
|
2984
2895
|
});
|
|
2985
2896
|
updated.push({
|
|
2986
|
-
...
|
|
2897
|
+
...entry,
|
|
2987
2898
|
vectors: {
|
|
2988
2899
|
path: manifestRelative,
|
|
2989
2900
|
model: identity.model,
|
|
@@ -2993,7 +2904,7 @@ async function runEmbed(opts = {}) {
|
|
|
2993
2904
|
}
|
|
2994
2905
|
});
|
|
2995
2906
|
}
|
|
2996
|
-
|
|
2907
|
+
writeFileSync4(
|
|
2997
2908
|
manifestPath,
|
|
2998
2909
|
emitLocalizations({ version: 1, languages: updated }),
|
|
2999
2910
|
"utf8"
|
|
@@ -3022,397 +2933,8 @@ function renderEmbed(report, format) {
|
|
|
3022
2933
|
].join("\n");
|
|
3023
2934
|
}
|
|
3024
2935
|
|
|
3025
|
-
// src/graph/commands/search.ts
|
|
3026
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
3027
|
-
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
3028
|
-
import { dirname as dirname3, join as join3, resolve as resolve8 } from "node:path";
|
|
3029
|
-
|
|
3030
|
-
// src/graph/runtime/vector.ts
|
|
3031
|
-
var VectorMismatchError = class extends Error {
|
|
3032
|
-
reason;
|
|
3033
|
-
constructor(mismatch) {
|
|
3034
|
-
super(mismatch.detail);
|
|
3035
|
-
this.name = "VectorMismatchError";
|
|
3036
|
-
this.reason = mismatch.reason;
|
|
3037
|
-
}
|
|
3038
|
-
};
|
|
3039
|
-
async function searchIndexDigest2(raw) {
|
|
3040
|
-
const webCrypto = globalThis.crypto;
|
|
3041
|
-
const subtle = webCrypto?.subtle;
|
|
3042
|
-
if (!subtle) {
|
|
3043
|
-
throw new Error(
|
|
3044
|
-
"searchIndexDigest needs Web Crypto (globalThis.crypto.subtle), which is unavailable here \u2014 a page served over plain HTTP does not get it."
|
|
3045
|
-
);
|
|
3046
|
-
}
|
|
3047
|
-
const digest = await subtle.digest("SHA-256", new TextEncoder().encode(raw));
|
|
3048
|
-
const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3049
|
-
return `sha256:${hex}`;
|
|
3050
|
-
}
|
|
3051
|
-
function createVectorIndex(bytes) {
|
|
3052
|
-
const { header, vectors } = decodeVectorIndex(bytes);
|
|
3053
|
-
const { dims, ids } = header;
|
|
3054
|
-
return {
|
|
3055
|
-
model: header.model,
|
|
3056
|
-
dtype: header.dtype,
|
|
3057
|
-
dims,
|
|
3058
|
-
source: header.source,
|
|
3059
|
-
size: () => ids.length,
|
|
3060
|
-
idAt: (row) => ids[row],
|
|
3061
|
-
check(expected) {
|
|
3062
|
-
if (expected.model !== void 0 && expected.model !== header.model) {
|
|
3063
|
-
return {
|
|
3064
|
-
reason: "model",
|
|
3065
|
-
detail: `Vector index was built with ${header.model}, but the embedder is ${expected.model}. Re-run \`manni graph embed\`.`
|
|
3066
|
-
};
|
|
3067
|
-
}
|
|
3068
|
-
if (expected.dtype !== void 0 && expected.dtype !== header.dtype) {
|
|
3069
|
-
return {
|
|
3070
|
-
reason: "dtype",
|
|
3071
|
-
detail: `Vector index was built at dtype ${header.dtype}, but the embedder is at ${expected.dtype} \u2014 different weights are a different function. Re-run \`manni graph embed\`.`
|
|
3072
|
-
};
|
|
3073
|
-
}
|
|
3074
|
-
if (expected.dims !== void 0 && expected.dims !== dims) {
|
|
3075
|
-
return {
|
|
3076
|
-
reason: "dims",
|
|
3077
|
-
detail: `Vector index has ${dims} dimensions, but the embedder produces ${expected.dims}.`
|
|
3078
|
-
};
|
|
3079
|
-
}
|
|
3080
|
-
if (expected.source !== void 0 && expected.source !== header.source) {
|
|
3081
|
-
return {
|
|
3082
|
-
reason: "stale-source",
|
|
3083
|
-
detail: "Vector index was built from a different search index \u2014 the corpus changed. Re-run `manni graph embed`."
|
|
3084
|
-
};
|
|
3085
|
-
}
|
|
3086
|
-
return void 0;
|
|
3087
|
-
},
|
|
3088
|
-
search(query, options = {}) {
|
|
3089
|
-
if (dims === 0 || ids.length === 0) return [];
|
|
3090
|
-
if (query.length !== dims) {
|
|
3091
|
-
throw new VectorMismatchError({
|
|
3092
|
-
reason: "dims",
|
|
3093
|
-
detail: `Query vector has ${query.length} dimensions, but the index has ${dims}.`
|
|
3094
|
-
});
|
|
3095
|
-
}
|
|
3096
|
-
const limit = normalizeLimit(options.limit);
|
|
3097
|
-
if (limit === 0) return [];
|
|
3098
|
-
const minScore = options.minScore ?? 0;
|
|
3099
|
-
const q = normalize(Float32Array.from(query));
|
|
3100
|
-
const scored = [];
|
|
3101
|
-
for (const [row, iri2] of ids.entries()) {
|
|
3102
|
-
const stored = vectors.subarray(row * dims, (row + 1) * dims);
|
|
3103
|
-
let score = 0;
|
|
3104
|
-
for (const [i, value] of q.entries()) score += value * (stored[i] ?? 0);
|
|
3105
|
-
if (score >= minScore) {
|
|
3106
|
-
scored.push({ iri: iri2, score, via: "vector" });
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
scored.sort(
|
|
3110
|
-
(a, b) => a.score === b.score ? byCodeUnit(a.iri, b.iri) : b.score - a.score
|
|
3111
|
-
);
|
|
3112
|
-
return scored.slice(0, limit);
|
|
3113
|
-
}
|
|
3114
|
-
};
|
|
3115
|
-
}
|
|
3116
|
-
function normalizeLimit(limit) {
|
|
3117
|
-
return typeof limit === "number" && Number.isInteger(limit) && limit >= 0 ? limit : 10;
|
|
3118
|
-
}
|
|
3119
|
-
|
|
3120
|
-
// src/graph/runtime/trace.ts
|
|
3121
|
-
function createTrace() {
|
|
3122
|
-
return { entry: [], hops: [], exclusions: [], resolutions: [] };
|
|
3123
|
-
}
|
|
3124
|
-
function reachedNodes(trace) {
|
|
3125
|
-
const reached = /* @__PURE__ */ new Set();
|
|
3126
|
-
for (const e of trace.entry) reached.add(e.iri);
|
|
3127
|
-
for (const h of trace.hops) reached.add(h.to);
|
|
3128
|
-
return reached;
|
|
3129
|
-
}
|
|
3130
|
-
|
|
3131
|
-
// src/graph/runtime/entry.ts
|
|
3132
|
-
function rrfMerge(rankings, k = 60) {
|
|
3133
|
-
const fused = /* @__PURE__ */ new Map();
|
|
3134
|
-
for (const ranking of rankings) {
|
|
3135
|
-
ranking.forEach((candidate, i) => {
|
|
3136
|
-
const current = fused.get(candidate.iri) ?? {
|
|
3137
|
-
score: 0,
|
|
3138
|
-
vias: /* @__PURE__ */ new Set()
|
|
3139
|
-
};
|
|
3140
|
-
current.score += 1 / (k + i + 1);
|
|
3141
|
-
current.vias.add(candidate.via);
|
|
3142
|
-
fused.set(candidate.iri, current);
|
|
3143
|
-
});
|
|
3144
|
-
}
|
|
3145
|
-
return [...fused.entries()].map(([iri2, { score, vias }]) => {
|
|
3146
|
-
const [only] = vias;
|
|
3147
|
-
return {
|
|
3148
|
-
iri: iri2,
|
|
3149
|
-
score,
|
|
3150
|
-
via: vias.size === 1 && only !== void 0 ? only : "hybrid"
|
|
3151
|
-
};
|
|
3152
|
-
}).sort(
|
|
3153
|
-
(a, b) => a.score === b.score ? byCodeUnit(a.iri, b.iri) : b.score - a.score
|
|
3154
|
-
);
|
|
3155
|
-
}
|
|
3156
|
-
async function findEntry(query, options) {
|
|
3157
|
-
const trace = options.trace ?? createTrace();
|
|
3158
|
-
const limit = typeof options.limit === "number" && Number.isInteger(options.limit) && options.limit >= 0 ? options.limit : 10;
|
|
3159
|
-
const lexical = options.lexical.search(query, { limit });
|
|
3160
|
-
const embedder = options.embedder;
|
|
3161
|
-
const embed = embedder ? (q) => embedder.embed(q) : options.embedQuery;
|
|
3162
|
-
let vector = [];
|
|
3163
|
-
if (options.vectors && embed && query.trim() !== "") {
|
|
3164
|
-
const mismatch = options.vectors.check({
|
|
3165
|
-
...options.embedder ? { model: options.embedder.model, dtype: options.embedder.dtype } : {},
|
|
3166
|
-
// Staleness is checked whichever way the query is embedded — it is a
|
|
3167
|
-
// property of the corpus, not of the embedder, so even the unverified
|
|
3168
|
-
// `embedQuery` path gets it when the caller supplies a digest.
|
|
3169
|
-
...options.source === void 0 ? {} : { source: options.source }
|
|
3170
|
-
});
|
|
3171
|
-
if (mismatch) throw new VectorMismatchError(mismatch);
|
|
3172
|
-
const queryVector = await embed(query);
|
|
3173
|
-
vector = options.vectors.search(queryVector, { limit });
|
|
3174
|
-
}
|
|
3175
|
-
const rankings = vector.length > 0 ? [lexical, vector] : [lexical];
|
|
3176
|
-
const candidates = rrfMerge(rankings).slice(0, limit);
|
|
3177
|
-
for (const candidate of candidates) trace.entry.push(candidate);
|
|
3178
|
-
return { candidates, lexical, vector, trace };
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
// src/graph/runtime/lexical.ts
|
|
3182
|
-
import MiniSearch from "minisearch";
|
|
3183
|
-
function createLexicalIndex(input) {
|
|
3184
|
-
const doc = typeof input === "string" ? JSON.parse(input) : input;
|
|
3185
|
-
const entries = Array.isArray(doc?.entries) ? doc.entries : [];
|
|
3186
|
-
const mini = new MiniSearch({
|
|
3187
|
-
fields: ["title", "labels", "description", "text"],
|
|
3188
|
-
storeFields: ["id"],
|
|
3189
|
-
idField: "id",
|
|
3190
|
-
// Titles and labels are the strongest signal that a node *is* the subject;
|
|
3191
|
-
// body text is evidence it merely mentions it.
|
|
3192
|
-
searchOptions: {
|
|
3193
|
-
boost: { title: 3, labels: 2, description: 1.5 },
|
|
3194
|
-
prefix: true,
|
|
3195
|
-
fuzzy: 0.2
|
|
3196
|
-
}
|
|
3197
|
-
});
|
|
3198
|
-
mini.addAll(entries);
|
|
3199
|
-
const byIri = new Map(entries.map((e) => [e.id, e]));
|
|
3200
|
-
return {
|
|
3201
|
-
size: () => entries.length,
|
|
3202
|
-
entry: (iri2) => byIri.get(iri2),
|
|
3203
|
-
search(query, options = {}) {
|
|
3204
|
-
const trimmed = query.trim();
|
|
3205
|
-
if (trimmed === "") return [];
|
|
3206
|
-
const hits = mini.search(trimmed);
|
|
3207
|
-
hits.sort(
|
|
3208
|
-
(a, b) => a.score === b.score ? byCodeUnit(String(a.id), String(b.id)) : b.score - a.score
|
|
3209
|
-
);
|
|
3210
|
-
return hits.slice(0, options.limit ?? 10).map((h) => ({ iri: String(h.id), score: h.score, via: "lexical" }));
|
|
3211
|
-
}
|
|
3212
|
-
};
|
|
3213
|
-
}
|
|
3214
|
-
|
|
3215
|
-
// src/graph/commands/search.ts
|
|
3216
|
-
var SEARCH_MODES = ["lexical", "hybrid", "vector"];
|
|
3217
|
-
function loadSearchIndex(indexPath) {
|
|
3218
|
-
const raw = readFileSync6(indexPath, "utf8");
|
|
3219
|
-
let parsed;
|
|
3220
|
-
try {
|
|
3221
|
-
parsed = JSON.parse(raw);
|
|
3222
|
-
} catch (e) {
|
|
3223
|
-
throw new GraphError(
|
|
3224
|
-
`Failed to parse ${indexPath}: ${errorMessage(e)} \u2014 re-run \`manni graph export search\`.`
|
|
3225
|
-
);
|
|
3226
|
-
}
|
|
3227
|
-
const entries = parsed?.entries;
|
|
3228
|
-
if (!Array.isArray(entries)) {
|
|
3229
|
-
throw new GraphError(
|
|
3230
|
-
`Not a manni graph search index: ${indexPath} \u2014 expected an \`entries\` array; re-run \`manni graph export search\`.`
|
|
3231
|
-
);
|
|
3232
|
-
}
|
|
3233
|
-
return {
|
|
3234
|
-
doc: parsed,
|
|
3235
|
-
// Same recipe `manni graph embed` uses, so the two digests are comparable.
|
|
3236
|
-
source: `sha256:${createHash3("sha256").update(raw, "utf8").digest("hex")}`
|
|
3237
|
-
};
|
|
3238
|
-
}
|
|
3239
|
-
function resolveLocalization(indexDir, lang) {
|
|
3240
|
-
const manifestPath = join3(indexDir, LOCALIZATIONS_FILENAME);
|
|
3241
|
-
if (!existsSync4(manifestPath)) {
|
|
3242
|
-
throw new GraphError(
|
|
3243
|
-
`Localization manifest not found: ${manifestPath} \u2014 run \`manni graph export search\` first.`
|
|
3244
|
-
);
|
|
3245
|
-
}
|
|
3246
|
-
const manifest = parseLocalizations(readFileSync6(manifestPath, "utf8"));
|
|
3247
|
-
if (!manifest) {
|
|
3248
|
-
throw new GraphError(
|
|
3249
|
-
`Not a manni graph localization manifest: ${manifestPath} \u2014 re-run \`manni graph export search\`.`
|
|
3250
|
-
);
|
|
3251
|
-
}
|
|
3252
|
-
const available = manifest.languages.map((l) => l.language);
|
|
3253
|
-
if (lang !== void 0) {
|
|
3254
|
-
const wanted = canonicalLanguageTag(lang);
|
|
3255
|
-
const hit = manifest.languages.find(
|
|
3256
|
-
(l) => canonicalLanguageTag(l.language) === wanted
|
|
3257
|
-
);
|
|
3258
|
-
if (!hit) {
|
|
3259
|
-
throw new GraphError(
|
|
3260
|
-
`No index for language "${lang}" \u2014 this corpus has ${available.join(", ") || "none"}.`
|
|
3261
|
-
);
|
|
3262
|
-
}
|
|
3263
|
-
return hit;
|
|
3264
|
-
}
|
|
3265
|
-
const only = manifest.languages[0];
|
|
3266
|
-
if (!only) {
|
|
3267
|
-
throw new GraphError(
|
|
3268
|
-
`The localization manifest lists no languages: ${manifestPath} \u2014 re-run \`manni graph export search\`.`
|
|
3269
|
-
);
|
|
3270
|
-
}
|
|
3271
|
-
if (manifest.languages.length > 1) {
|
|
3272
|
-
throw new GraphError(
|
|
3273
|
-
`This corpus has more than one localization (${available.join(", ")}) \u2014 pass --lang to choose one.`
|
|
3274
|
-
);
|
|
3275
|
-
}
|
|
3276
|
-
return only;
|
|
3277
|
-
}
|
|
3278
|
-
async function runSearch(opts) {
|
|
3279
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
3280
|
-
const config = loadRunConfig(
|
|
3281
|
-
{
|
|
3282
|
-
...opts.config === void 0 ? {} : { configPath: opts.config },
|
|
3283
|
-
...opts.noConfig === void 0 ? {} : { noConfig: opts.noConfig }
|
|
3284
|
-
},
|
|
3285
|
-
cwd
|
|
3286
|
-
);
|
|
3287
|
-
const graphPath = resolve8(cwd, opts.graph ?? config.out);
|
|
3288
|
-
const indexDir = opts.index ? resolve8(cwd, opts.index) : dirname3(graphPath);
|
|
3289
|
-
const localization = resolveLocalization(indexDir, opts.lang);
|
|
3290
|
-
const indexPath = join3(indexDir, localization.search.path);
|
|
3291
|
-
if (!existsSync4(indexPath)) {
|
|
3292
|
-
throw new GraphError(
|
|
3293
|
-
`Search index not found: ${indexPath} \u2014 the manifest names it; re-run \`manni graph export search\`.`
|
|
3294
|
-
);
|
|
3295
|
-
}
|
|
3296
|
-
const { doc, source } = loadSearchIndex(indexPath);
|
|
3297
|
-
if (localization.search.digest !== source) {
|
|
3298
|
-
throw new GraphError(
|
|
3299
|
-
`Stale manifest: ${localization.search.path} does not match the digest recorded for "${localization.language}". Re-run \`manni graph export search\`.`
|
|
3300
|
-
);
|
|
3301
|
-
}
|
|
3302
|
-
const lexical = createLexicalIndex(doc);
|
|
3303
|
-
const explicitVectors = opts.vectors !== void 0 && opts.vectors !== "" ? opts.vectors : void 0;
|
|
3304
|
-
const wantsVector = opts.mode === "vector" || opts.mode === "hybrid" || explicitVectors !== void 0 && opts.mode !== "lexical";
|
|
3305
|
-
const vectorsPath = explicitVectors ? resolve8(cwd, explicitVectors) : localization.vectors ? resolve8(indexDir, localization.vectors.path) : void 0;
|
|
3306
|
-
let vectors;
|
|
3307
|
-
if (opts.mode !== "lexical" && vectorsPath !== void 0 && existsSync4(vectorsPath)) {
|
|
3308
|
-
try {
|
|
3309
|
-
vectors = createVectorIndex(readFileSync6(vectorsPath));
|
|
3310
|
-
} catch (e) {
|
|
3311
|
-
if (e instanceof VectorIndexError) {
|
|
3312
|
-
throw new GraphError(
|
|
3313
|
-
`${e.message} (${vectorsPath}) \u2014 re-run \`manni graph embed\`, or use \`--mode lexical\`.`
|
|
3314
|
-
);
|
|
3315
|
-
}
|
|
3316
|
-
throw e;
|
|
3317
|
-
}
|
|
3318
|
-
const stale = vectors.check({ source });
|
|
3319
|
-
if (stale && wantsVector) throw new GraphError(stale.detail);
|
|
3320
|
-
if (stale) {
|
|
3321
|
-
warn(`${stale.detail} Falling back to lexical.`);
|
|
3322
|
-
vectors = void 0;
|
|
3323
|
-
}
|
|
3324
|
-
} else if (wantsVector) {
|
|
3325
|
-
const named = vectorsPath ?? `no sidecar recorded for "${localization.language}"`;
|
|
3326
|
-
throw new GraphError(
|
|
3327
|
-
`Vector index not found: ${named} \u2014 run \`manni graph embed\` first, or use \`--mode lexical\`.`
|
|
3328
|
-
);
|
|
3329
|
-
}
|
|
3330
|
-
let embedder;
|
|
3331
|
-
if (vectors) {
|
|
3332
|
-
const requireEmbedder = opts.mode === "vector" || opts.mode === "hybrid";
|
|
3333
|
-
embedder = await resolveEmbedder(opts, vectors, requireEmbedder);
|
|
3334
|
-
}
|
|
3335
|
-
const entry2 = await findEntry(opts.query, {
|
|
3336
|
-
lexical,
|
|
3337
|
-
// Pass the embedder, not a bare function: findEntry then verifies it
|
|
3338
|
-
// against the index itself rather than trusting the CLI to have done so.
|
|
3339
|
-
...embedder && vectors ? { vectors, embedder } : {},
|
|
3340
|
-
limit: opts.limit
|
|
3341
|
-
}).catch((e) => {
|
|
3342
|
-
if (e instanceof VectorMismatchError) {
|
|
3343
|
-
throw new GraphError(`${e.message} Re-run \`manni graph embed\`.`);
|
|
3344
|
-
}
|
|
3345
|
-
throw e;
|
|
3346
|
-
});
|
|
3347
|
-
const decorate = (c) => {
|
|
3348
|
-
const found = lexical.entry(c.iri);
|
|
3349
|
-
return {
|
|
3350
|
-
iri: c.iri,
|
|
3351
|
-
score: c.score,
|
|
3352
|
-
via: c.via,
|
|
3353
|
-
...found?.type === void 0 ? {} : { type: found.type },
|
|
3354
|
-
...found?.title === void 0 ? {} : { title: found.title }
|
|
3355
|
-
};
|
|
3356
|
-
};
|
|
3357
|
-
const mode = opts.mode ?? (embedder && vectors ? "hybrid" : "lexical");
|
|
3358
|
-
const results = opts.mode === "vector" ? entry2.vector : entry2.candidates;
|
|
3359
|
-
if (opts.mode === "vector") {
|
|
3360
|
-
entry2.trace.entry.length = 0;
|
|
3361
|
-
entry2.trace.entry.push(...entry2.vector);
|
|
3362
|
-
}
|
|
3363
|
-
return {
|
|
3364
|
-
query: opts.query,
|
|
3365
|
-
mode,
|
|
3366
|
-
results: results.map(decorate),
|
|
3367
|
-
lexical: entry2.lexical.map(decorate),
|
|
3368
|
-
vector: entry2.vector.map(decorate),
|
|
3369
|
-
trace: entry2.trace
|
|
3370
|
-
};
|
|
3371
|
-
}
|
|
3372
|
-
async function resolveEmbedder(opts, vectors, required) {
|
|
3373
|
-
const { model, dtype } = vectors;
|
|
3374
|
-
try {
|
|
3375
|
-
const embedder = opts.embedder ?? (model === "mock" ? createMockEmbedder({ dtype }) : await createLocalEmbedder({ model, dtype, role: "query" }));
|
|
3376
|
-
const mismatch = vectors.check({
|
|
3377
|
-
model: embedder.model,
|
|
3378
|
-
dtype: embedder.dtype,
|
|
3379
|
-
// Defense in depth: a future model that changes output size without
|
|
3380
|
-
// changing its id would otherwise only surface deep inside search().
|
|
3381
|
-
...embedder.dims > 0 ? { dims: embedder.dims } : {}
|
|
3382
|
-
});
|
|
3383
|
-
if (mismatch) throw new GraphError(mismatch.detail);
|
|
3384
|
-
return embedder;
|
|
3385
|
-
} catch (e) {
|
|
3386
|
-
if (e instanceof GraphError) throw e;
|
|
3387
|
-
if (e instanceof EmbedderUnavailableError) {
|
|
3388
|
-
if (required) throw new GraphError(e.message);
|
|
3389
|
-
return void 0;
|
|
3390
|
-
}
|
|
3391
|
-
throw new GraphError(
|
|
3392
|
-
`Failed to load embedding model ${model}: ${errorMessage(e)}`
|
|
3393
|
-
);
|
|
3394
|
-
}
|
|
3395
|
-
}
|
|
3396
|
-
function renderSearch(report, format) {
|
|
3397
|
-
if (format === "json") return JSON.stringify(report, null, 2);
|
|
3398
|
-
const lines = [];
|
|
3399
|
-
for (const r of report.results) {
|
|
3400
|
-
const label = r.title ? ` \u2014 ${r.title}` : "";
|
|
3401
|
-
const type = r.type ? ` [${r.type}]` : "";
|
|
3402
|
-
lines.push(`${r.score.toFixed(4)} ${compactIri(r.iri)}${type}${label}`);
|
|
3403
|
-
}
|
|
3404
|
-
if (report.results.length === 0) {
|
|
3405
|
-
lines.push("(no matches)");
|
|
3406
|
-
}
|
|
3407
|
-
lines.push("");
|
|
3408
|
-
lines.push(
|
|
3409
|
-
`${report.results.length} result${report.results.length === 1 ? "" : "s"} (${report.mode})`
|
|
3410
|
-
);
|
|
3411
|
-
return lines.join("\n");
|
|
3412
|
-
}
|
|
3413
|
-
|
|
3414
2936
|
// src/graph/commands/stats.ts
|
|
3415
|
-
import { resolve as
|
|
2937
|
+
import { resolve as resolve8 } from "node:path";
|
|
3416
2938
|
import { DataFactory as DataFactory4 } from "n3";
|
|
3417
2939
|
function subjectsOfType(store, typeIri) {
|
|
3418
2940
|
return store.getQuads(null, DataFactory4.namedNode(RDF_TYPE), DataFactory4.namedNode(typeIri), null).map((q) => q.subject.value).sort();
|
|
@@ -3433,7 +2955,7 @@ function runStats(opts = {}) {
|
|
|
3433
2955
|
},
|
|
3434
2956
|
cwd
|
|
3435
2957
|
);
|
|
3436
|
-
const store = loadGraph(
|
|
2958
|
+
const store = loadGraph(resolve8(cwd, opts.graph ?? config.out));
|
|
3437
2959
|
const top = opts.top ?? 5;
|
|
3438
2960
|
const docIris = subjectsOfType(store, `${NS.graph}Document`);
|
|
3439
2961
|
const docSet = new Set(docIris);
|
|
@@ -3538,8 +3060,18 @@ function runStats(opts = {}) {
|
|
|
3538
3060
|
};
|
|
3539
3061
|
})
|
|
3540
3062
|
};
|
|
3063
|
+
const asked = /* @__PURE__ */ new Set();
|
|
3064
|
+
for (const q of store.getQuads(null, DataFactory4.namedNode(`${NS.graph}sampleQuestion`), null, null)) {
|
|
3065
|
+
if (!docSet.has(q.subject.value)) continue;
|
|
3066
|
+
for (const p of [`${NS.foaf}primaryTopic`, `${NS.dcterms}subject`]) {
|
|
3067
|
+
for (const t of store.getQuads(q.subject, DataFactory4.namedNode(p), null, null)) {
|
|
3068
|
+
asked.add(t.object.value);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
const conceptsWithoutQuestions = subjectsOfType(store, `${NS.skos}Concept`).filter((c) => !asked.has(c)).sort(byCodeUnit);
|
|
3541
3073
|
const uniform = opts.coverageThreshold;
|
|
3542
|
-
const thresholds = uniform != null ? Object.fromEntries(
|
|
3074
|
+
const thresholds = uniform != null ? Object.fromEntries(UNIFORM_COVERAGE_FIELD_NAMES.map((f) => [f, uniform])) : config.stats.coverageThreshold;
|
|
3543
3075
|
const coverageFindings = coverage.flatMap((c) => {
|
|
3544
3076
|
const threshold = thresholds[c.field];
|
|
3545
3077
|
if (threshold === void 0) return [];
|
|
@@ -3571,13 +3103,21 @@ function runStats(opts = {}) {
|
|
|
3571
3103
|
coverage,
|
|
3572
3104
|
sectionCoverage,
|
|
3573
3105
|
localization,
|
|
3106
|
+
conceptsWithoutQuestions,
|
|
3107
|
+
conceptLabels: Object.fromEntries(
|
|
3108
|
+
conceptsWithoutQuestions.map((c) => [c, conceptLabel(store, c)])
|
|
3109
|
+
),
|
|
3574
3110
|
coverageFindings,
|
|
3575
3111
|
exitCode: failed ? 1 : 0
|
|
3576
3112
|
};
|
|
3577
3113
|
}
|
|
3114
|
+
function conceptLabel(store, iri2) {
|
|
3115
|
+
const labels = store.getQuads(DataFactory4.namedNode(iri2), DataFactory4.namedNode(`${NS.skos}prefLabel`), null, null).map((q) => q.object.value).sort(byCodeUnit);
|
|
3116
|
+
return labels[0] ?? compactIri(iri2);
|
|
3117
|
+
}
|
|
3578
3118
|
function renderStats(report, format) {
|
|
3579
3119
|
if (format === "json") {
|
|
3580
|
-
const { exitCode: _exitCode, ...rest } = report;
|
|
3120
|
+
const { exitCode: _exitCode, conceptLabels: _labels, ...rest } = report;
|
|
3581
3121
|
return JSON.stringify(rest, null, 2);
|
|
3582
3122
|
}
|
|
3583
3123
|
const lines = [
|
|
@@ -3639,16 +3179,22 @@ function renderStats(report, format) {
|
|
|
3639
3179
|
}
|
|
3640
3180
|
lines.push(` no language: ${report.localization.unlabelled}`);
|
|
3641
3181
|
}
|
|
3182
|
+
if (report.concepts > 0) {
|
|
3183
|
+
const unasked = report.conceptsWithoutQuestions;
|
|
3184
|
+
lines.push("", `Concepts with no question (${String(unasked.length)}):`);
|
|
3185
|
+
for (const c of unasked) lines.push(` ${report.conceptLabels[c] ?? compactIri(c)}`);
|
|
3186
|
+
if (unasked.length === 0) lines.push(" (none)");
|
|
3187
|
+
}
|
|
3642
3188
|
return lines.join("\n");
|
|
3643
3189
|
}
|
|
3644
3190
|
|
|
3645
3191
|
// src/graph/commands/traverse.ts
|
|
3646
|
-
import { resolve as
|
|
3192
|
+
import { resolve as resolve9 } from "node:path";
|
|
3647
3193
|
|
|
3648
3194
|
// src/graph/runtime/traverse.ts
|
|
3649
|
-
var
|
|
3195
|
+
var DCTERMS_TITLE = `${NS.dcterms}title`;
|
|
3650
3196
|
var DCTERMS_REFERENCES = `${NS.dcterms}references`;
|
|
3651
|
-
var
|
|
3197
|
+
var DCTERMS_LANGUAGE = `${NS.dcterms}language`;
|
|
3652
3198
|
function documentOf(iri2) {
|
|
3653
3199
|
const hash = iri2.indexOf("#");
|
|
3654
3200
|
return hash === -1 ? iri2 : iri2.slice(0, hash);
|
|
@@ -3658,7 +3204,7 @@ function resolveVariant(graph, input) {
|
|
|
3658
3204
|
const wanted = input.toLowerCase();
|
|
3659
3205
|
const variants = graph.instancesOf(`${NS.iirds}ProductVariant`);
|
|
3660
3206
|
for (const v of variants) {
|
|
3661
|
-
if (graph.literal(v,
|
|
3207
|
+
if (graph.literal(v, DCTERMS_TITLE)?.toLowerCase() === wanted) return v;
|
|
3662
3208
|
}
|
|
3663
3209
|
for (const v of variants) {
|
|
3664
3210
|
if (v.slice(v.lastIndexOf("/") + 1).toLowerCase() === wanted) return v;
|
|
@@ -3680,7 +3226,7 @@ function scopeExclusion(graph, iri2, scope) {
|
|
|
3680
3226
|
"iri"
|
|
3681
3227
|
],
|
|
3682
3228
|
[scope.subjectIri, IIRDS_HAS_SUBJECT, GRAPH_NOT_SOFTWARE_SUBJECT, "iri"],
|
|
3683
|
-
[scope.language,
|
|
3229
|
+
[scope.language, DCTERMS_LANGUAGE, void 0, "literal"]
|
|
3684
3230
|
];
|
|
3685
3231
|
for (const [target, positive, negative, kind] of checks) {
|
|
3686
3232
|
if (!target) continue;
|
|
@@ -3688,7 +3234,7 @@ function scopeExclusion(graph, iri2, scope) {
|
|
|
3688
3234
|
const denied = graph.values(iri2, negative).some((v) => v.kind === kind && v.value === target);
|
|
3689
3235
|
if (denied) return { node: iri2, rule: negative, value: target };
|
|
3690
3236
|
}
|
|
3691
|
-
const subject = positive ===
|
|
3237
|
+
const subject = positive === DCTERMS_LANGUAGE ? documentOf(iri2) : iri2;
|
|
3692
3238
|
const claimed = graph.values(subject, positive);
|
|
3693
3239
|
if (claimed.length > 0) {
|
|
3694
3240
|
const matches = claimed.some(
|
|
@@ -3807,7 +3353,7 @@ function runTraverse(opts) {
|
|
|
3807
3353
|
},
|
|
3808
3354
|
cwd
|
|
3809
3355
|
);
|
|
3810
|
-
const store = loadGraph(
|
|
3356
|
+
const store = loadGraph(resolve9(cwd, opts.graph ?? config.out));
|
|
3811
3357
|
const quads = storeToQuads(store);
|
|
3812
3358
|
const graph = GraphIndex.fromQuads(quads, Object.fromEntries(PREFIXES));
|
|
3813
3359
|
const node = expandTerm(opts.node);
|
|
@@ -3897,19 +3443,6 @@ export {
|
|
|
3897
3443
|
emitRdfXml,
|
|
3898
3444
|
writeZip,
|
|
3899
3445
|
projectPackage,
|
|
3900
|
-
splitFragment,
|
|
3901
|
-
documentSectionOrder,
|
|
3902
|
-
sectionOccurrences,
|
|
3903
|
-
sectionOccurrence,
|
|
3904
|
-
documentPreamble,
|
|
3905
|
-
sliceSection,
|
|
3906
|
-
sectionOwnText,
|
|
3907
|
-
createFetchResolver,
|
|
3908
|
-
buildSearchIndex,
|
|
3909
|
-
emitSearchIndex,
|
|
3910
|
-
partitionByLanguage,
|
|
3911
|
-
documentsByLanguage,
|
|
3912
|
-
GraphIndex,
|
|
3913
3446
|
EXPORT_TARGETS,
|
|
3914
3447
|
runExport,
|
|
3915
3448
|
runQuery,
|
|
@@ -3926,27 +3459,9 @@ export {
|
|
|
3926
3459
|
makeProvider,
|
|
3927
3460
|
runFill,
|
|
3928
3461
|
renderFill,
|
|
3929
|
-
VectorIndexError,
|
|
3930
|
-
normalize,
|
|
3931
|
-
encodeVectorIndex,
|
|
3932
|
-
decodeVectorIndex,
|
|
3933
|
-
EmbedderUnavailableError,
|
|
3934
|
-
createLocalEmbedder,
|
|
3935
|
-
createMockEmbedder,
|
|
3936
3462
|
embedText,
|
|
3937
3463
|
runEmbed,
|
|
3938
3464
|
renderEmbed,
|
|
3939
|
-
VectorMismatchError,
|
|
3940
|
-
searchIndexDigest2 as searchIndexDigest,
|
|
3941
|
-
createVectorIndex,
|
|
3942
|
-
createTrace,
|
|
3943
|
-
reachedNodes,
|
|
3944
|
-
rrfMerge,
|
|
3945
|
-
findEntry,
|
|
3946
|
-
createLexicalIndex,
|
|
3947
|
-
SEARCH_MODES,
|
|
3948
|
-
runSearch,
|
|
3949
|
-
renderSearch,
|
|
3950
3465
|
runStats,
|
|
3951
3466
|
renderStats,
|
|
3952
3467
|
resolveVariant,
|
|
@@ -3958,4 +3473,4 @@ export {
|
|
|
3958
3473
|
runTraverse,
|
|
3959
3474
|
renderTraverse
|
|
3960
3475
|
};
|
|
3961
|
-
//# sourceMappingURL=chunk-
|
|
3476
|
+
//# sourceMappingURL=chunk-CVZMKWZ5.js.map
|