@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.
Files changed (238) hide show
  1. package/README.md +1 -1
  2. package/dist/{batch-UAULUMGH.js → batch-KMGZMIAQ.js} +20 -19
  3. package/dist/build-NO4AWCYG.js +36 -0
  4. package/dist/calibrate-XQUG5XAK.js +41 -0
  5. package/dist/capture-5XE3ZMXK.js +38 -0
  6. package/dist/{check-YEOYBFST.js → check-HTNPLWOV.js} +19 -18
  7. package/dist/check-RJ45IBA6.js +34 -0
  8. package/dist/{check-VELUQAUW.js → check-W24BQNCT.js} +35 -34
  9. package/dist/{check-VELUQAUW.js.map → check-W24BQNCT.js.map} +1 -1
  10. package/dist/check-WFXSXICD.js +30 -0
  11. package/dist/{chunk-IGSHYP74.js → chunk-23P7KMJM.js} +4 -4
  12. package/dist/{chunk-HA6MQMOY.js → chunk-24J7TYPU.js} +6 -6
  13. package/dist/{chunk-PCS4VJBV.js → chunk-37QJLVS3.js} +9 -9
  14. package/dist/{chunk-4CK6ZSOK.js → chunk-3P6KCU36.js} +3 -3
  15. package/dist/{chunk-54F74XR3.js → chunk-5JBVFWVP.js} +19 -19
  16. package/dist/{chunk-B7XYNRJQ.js → chunk-6KIYVVKL.js} +2 -2
  17. package/dist/{chunk-J6IDQGJL.js → chunk-6TVH4FI7.js} +469 -85
  18. package/dist/chunk-6TVH4FI7.js.map +1 -0
  19. package/dist/{chunk-GDVZ5VII.js → chunk-7A452BPZ.js} +4 -4
  20. package/dist/{chunk-M42DZCOU.js → chunk-7FCLXEAQ.js} +2 -2
  21. package/dist/{chunk-2MJ62AYQ.js → chunk-7MCQHTQ5.js} +4 -3
  22. package/dist/chunk-7MCQHTQ5.js.map +1 -0
  23. package/dist/{chunk-LBSCW232.js → chunk-7NXPQKSB.js} +7 -7
  24. package/dist/{chunk-OPXWPJDA.js → chunk-A3TEDWBZ.js} +14 -14
  25. package/dist/{chunk-BBT6AVUG.js → chunk-BHHXU2D2.js} +2 -2
  26. package/dist/{chunk-D4N2V43Z.js → chunk-CEI2J42X.js} +13 -7
  27. package/dist/chunk-CEI2J42X.js.map +1 -0
  28. package/dist/{chunk-FQXWVS6J.js → chunk-CMMBWHT2.js} +9 -9
  29. package/dist/{chunk-EIFCP6CZ.js → chunk-CO47QJKZ.js} +2 -2
  30. package/dist/{chunk-2DRHT73U.js → chunk-CVZMKWZ5.js} +913 -1398
  31. package/dist/chunk-CVZMKWZ5.js.map +1 -0
  32. package/dist/{chunk-ADMEPUBT.js → chunk-CXWTNT2O.js} +3 -3
  33. package/dist/{chunk-LKP7QDFN.js → chunk-DAQTRAP5.js} +4 -4
  34. package/dist/chunk-DSWKBZWW.js +16 -0
  35. package/dist/chunk-DSWKBZWW.js.map +1 -0
  36. package/dist/{chunk-PWBH7DCQ.js → chunk-EESH6COU.js} +4 -4
  37. package/dist/{chunk-JPQDNYXH.js → chunk-EM67O2ET.js} +8 -2
  38. package/dist/chunk-EM67O2ET.js.map +1 -0
  39. package/dist/{chunk-HQR2ZBHW.js → chunk-I2XQRRP7.js} +36 -7
  40. package/dist/chunk-I2XQRRP7.js.map +1 -0
  41. package/dist/{chunk-NCPWXHDO.js → chunk-JEUFYSFQ.js} +4 -4
  42. package/dist/{chunk-2IR4T5PO.js → chunk-JJ4RSDSY.js} +2 -2
  43. package/dist/chunk-KCB5JCK4.js +2272 -0
  44. package/dist/chunk-KCB5JCK4.js.map +1 -0
  45. package/dist/{chunk-VSEBFHAY.js → chunk-KFKL4VTL.js} +11369 -10218
  46. package/dist/chunk-KFKL4VTL.js.map +1 -0
  47. package/dist/{chunk-PCQ7ELJH.js → chunk-L2TD7DZB.js} +109 -5
  48. package/dist/chunk-L2TD7DZB.js.map +1 -0
  49. package/dist/{chunk-WDWXAYVH.js → chunk-L3RLGGRK.js} +4 -4
  50. package/dist/{chunk-T7JAOYE5.js → chunk-L75CAZG4.js} +6 -6
  51. package/dist/{chunk-U7CTFN2J.js → chunk-MYRPMSOX.js} +7 -7
  52. package/dist/{chunk-Y6DOMTQD.js → chunk-NCF5NQV5.js} +27 -27
  53. package/dist/chunk-NCF5NQV5.js.map +1 -0
  54. package/dist/{chunk-WQWKYAAK.js → chunk-NUQF5F5J.js} +2 -2
  55. package/dist/{chunk-FUCPZVRY.js → chunk-OEN6FBUW.js} +2 -2
  56. package/dist/{chunk-FBMZJEB3.js → chunk-OKMTUAWO.js} +4 -4
  57. package/dist/{chunk-QLWC7MKD.js → chunk-OTJOBZJ5.js} +135 -135
  58. package/dist/chunk-OTJOBZJ5.js.map +1 -0
  59. package/dist/{chunk-R4WXQIOZ.js → chunk-PCEM5FOZ.js} +3 -3
  60. package/dist/{chunk-4D5IZSXM.js → chunk-PXNCRGUL.js} +3 -3
  61. package/dist/chunk-Q2QC5AZB.js +1868 -0
  62. package/dist/chunk-Q2QC5AZB.js.map +1 -0
  63. package/dist/{chunk-ODRPL3WB.js → chunk-Q3ODX5PF.js} +2 -2
  64. package/dist/{chunk-KGEQJ5CC.js → chunk-RRFFUWDL.js} +8 -8
  65. package/dist/{chunk-NSBXVPZL.js → chunk-S3XUYW5K.js} +17 -17
  66. package/dist/{chunk-LPIF5LIE.js → chunk-SAU2WQFC.js} +2 -2
  67. package/dist/{chunk-MSRU4D4P.js → chunk-SFLICIQV.js} +2 -2
  68. package/dist/{chunk-NGTVREIH.js → chunk-U6IHLEWT.js} +2 -2
  69. package/dist/{chunk-QCHVR4ZM.js → chunk-VM7VAFJW.js} +33 -7
  70. package/dist/chunk-VM7VAFJW.js.map +1 -0
  71. package/dist/{chunk-6HWBRZIN.js → chunk-VQYGLU4C.js} +252 -193
  72. package/dist/chunk-VQYGLU4C.js.map +1 -0
  73. package/dist/{chunk-2IAZEB45.js → chunk-WGMFDG6U.js} +229 -821
  74. package/dist/chunk-WGMFDG6U.js.map +1 -0
  75. package/dist/{chunk-GV56WGL2.js → chunk-WO4JYWZK.js} +1036 -883
  76. package/dist/chunk-WO4JYWZK.js.map +1 -0
  77. package/dist/chunk-XYRUDFKS.js +685 -0
  78. package/dist/chunk-XYRUDFKS.js.map +1 -0
  79. package/dist/{chunk-VQK4VHLF.js → chunk-YQV75FIL.js} +2 -2
  80. package/dist/chunk-YUTVAMWW.js +2 -0
  81. package/dist/{chunk-RLT5SEML.js → chunk-Z5MZCCTT.js} +6 -6
  82. package/dist/{chunk-BKVHX6FU.js → chunk-ZIRBFXDW.js} +5 -10
  83. package/dist/chunk-ZIRBFXDW.js.map +1 -0
  84. package/dist/{cli-O4ABTN4Z.js → cli-236TGVJG.js} +31 -30
  85. package/dist/{cli-O4ABTN4Z.js.map → cli-236TGVJG.js.map} +1 -1
  86. package/dist/{cli-3BTCK4AB.js → cli-3FAPJBEY.js} +27 -26
  87. package/dist/{cli-3BTCK4AB.js.map → cli-3FAPJBEY.js.map} +1 -1
  88. package/dist/{cli-JJMOVIKS.js → cli-BS43EVCD.js} +14 -14
  89. package/dist/{cli-RORDPAPE.js → cli-CMR4FYF6.js} +59 -38
  90. package/dist/cli-CMR4FYF6.js.map +1 -0
  91. package/dist/{cli-ONTC5PKT.js → cli-FX53PBQ3.js} +9 -9
  92. package/dist/{cli-6KZTHWGP.js → cli-IQNJLKSN.js} +37 -36
  93. package/dist/{cli-6KZTHWGP.js.map → cli-IQNJLKSN.js.map} +1 -1
  94. package/dist/{cli-4MF37HAQ.js → cli-KOMXVPXX.js} +26 -25
  95. package/dist/{cli-4MF37HAQ.js.map → cli-KOMXVPXX.js.map} +1 -1
  96. package/dist/{cli-I62SRH3R.js → cli-NGL63E53.js} +14 -13
  97. package/dist/{cli-DRMZBZLB.js → cli-QPGS2MR5.js} +43 -42
  98. package/dist/{cli-DRMZBZLB.js.map → cli-QPGS2MR5.js.map} +1 -1
  99. package/dist/{cli-VID7PJS3.js → cli-RKQX4TI3.js} +23 -22
  100. package/dist/{cli-VID7PJS3.js.map → cli-RKQX4TI3.js.map} +1 -1
  101. package/dist/{cli-VUKMWSSF.js → cli-WNEI5L7P.js} +4 -4
  102. package/dist/cli.js +19 -13
  103. package/dist/cli.js.map +1 -1
  104. package/dist/{config-XDA42RJL.js → config-JJW75SBX.js} +5 -5
  105. package/dist/docmeta.js +13 -12
  106. package/dist/docmeta.js.map +1 -1
  107. package/dist/github-4UR67MEN.js +35 -0
  108. package/dist/github-UPGKMVVF.js +30 -0
  109. package/dist/graph/runtime.d.ts +4 -1
  110. package/dist/graph/runtime.js +20 -9
  111. package/dist/graph/runtime.js.map +1 -1
  112. package/dist/{host-6GURH5HE.js → host-YSTYO5DX.js} +3 -3
  113. package/dist/index.d.ts +192 -26
  114. package/dist/index.js +129 -124
  115. package/dist/index.js.map +1 -1
  116. package/dist/{json-BXY44ED7.js → json-DQIELR36.js} +18 -17
  117. package/dist/labels-XSTJJMSG.js +73 -0
  118. package/dist/labels-XSTJJMSG.js.map +1 -0
  119. package/dist/lint-BLBGGOYM.js +34 -0
  120. package/dist/list-B3RRRWFQ.js +32 -0
  121. package/dist/list-ZFRT3JQH.js +35 -0
  122. package/dist/{page-EV7OUBAU.js → page-5ISEVJR5.js} +18 -16
  123. package/dist/{prepare-JHJDJB6I.js → prepare-KFXXG2CJ.js} +22 -21
  124. package/dist/{prepare-JHJDJB6I.js.map → prepare-KFXXG2CJ.js.map} +1 -1
  125. package/dist/{pretty-Q5Y2PA64.js → pretty-Y7CGQLAF.js} +18 -17
  126. package/dist/{pretty-SCRK66M5.js → pretty-ZISH3Q4F.js} +18 -17
  127. package/dist/{provider-527CO4DM.js → provider-LBX4IXGX.js} +3 -3
  128. package/dist/{release-3D5PK6M7.js → release-VV3UTKE5.js} +3 -3
  129. package/dist/{reporters-M6LJ2IYU.js → reporters-26H3N2KW.js} +3 -3
  130. package/dist/{reporters-A5ADKDYR.js → reporters-4STXJJE2.js} +16 -15
  131. package/dist/{reporters-RBYTASMI.js → reporters-74B4U2GZ.js} +7 -7
  132. package/dist/run-DVGTKM52.js +37 -0
  133. package/dist/{term-CQAGNG3Q.js → term-PLJEYJQV.js} +981 -141
  134. package/dist/term-PLJEYJQV.js.map +1 -0
  135. package/dist/validate-CJNFQHMD.js +19 -0
  136. package/package.json +3 -2
  137. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  138. package/shapes/graph/shapes-1.1.0.ttl +785 -0
  139. package/dist/build-QSPNK5AL.js +0 -35
  140. package/dist/calibrate-KXN4URPM.js +0 -40
  141. package/dist/capture-JHTSUPUC.js +0 -37
  142. package/dist/check-MDGXEUWL.js +0 -20
  143. package/dist/check-WOQRKNZK.js +0 -29
  144. package/dist/chunk-2DRHT73U.js.map +0 -1
  145. package/dist/chunk-2IAZEB45.js.map +0 -1
  146. package/dist/chunk-2MJ62AYQ.js.map +0 -1
  147. package/dist/chunk-4VBSTXN6.js +0 -392
  148. package/dist/chunk-4VBSTXN6.js.map +0 -1
  149. package/dist/chunk-6HWBRZIN.js.map +0 -1
  150. package/dist/chunk-BKVHX6FU.js.map +0 -1
  151. package/dist/chunk-D4N2V43Z.js.map +0 -1
  152. package/dist/chunk-EFW7CAG4.js +0 -387
  153. package/dist/chunk-EFW7CAG4.js.map +0 -1
  154. package/dist/chunk-GV56WGL2.js.map +0 -1
  155. package/dist/chunk-HQR2ZBHW.js.map +0 -1
  156. package/dist/chunk-J6IDQGJL.js.map +0 -1
  157. package/dist/chunk-JPQDNYXH.js.map +0 -1
  158. package/dist/chunk-JROBZ7JA.js +0 -818
  159. package/dist/chunk-JROBZ7JA.js.map +0 -1
  160. package/dist/chunk-PCQ7ELJH.js.map +0 -1
  161. package/dist/chunk-QCHVR4ZM.js.map +0 -1
  162. package/dist/chunk-QLWC7MKD.js.map +0 -1
  163. package/dist/chunk-TU2WUBVZ.js +0 -2
  164. package/dist/chunk-VSEBFHAY.js.map +0 -1
  165. package/dist/chunk-Y6DOMTQD.js.map +0 -1
  166. package/dist/cli-RORDPAPE.js.map +0 -1
  167. package/dist/github-RY3FRA6P.js +0 -29
  168. package/dist/github-YKQSH7FS.js +0 -34
  169. package/dist/lint-YJ2L22BW.js +0 -33
  170. package/dist/list-NSG24VVX.js +0 -31
  171. package/dist/list-V6EGCSHX.js +0 -34
  172. package/dist/run-BUE2DDXN.js +0 -36
  173. package/dist/term-CQAGNG3Q.js.map +0 -1
  174. package/dist/validate-ZBW44RHT.js +0 -18
  175. /package/dist/{batch-UAULUMGH.js.map → batch-KMGZMIAQ.js.map} +0 -0
  176. /package/dist/{build-QSPNK5AL.js.map → build-NO4AWCYG.js.map} +0 -0
  177. /package/dist/{calibrate-KXN4URPM.js.map → calibrate-XQUG5XAK.js.map} +0 -0
  178. /package/dist/{capture-JHTSUPUC.js.map → capture-5XE3ZMXK.js.map} +0 -0
  179. /package/dist/{check-MDGXEUWL.js.map → check-HTNPLWOV.js.map} +0 -0
  180. /package/dist/{check-WOQRKNZK.js.map → check-RJ45IBA6.js.map} +0 -0
  181. /package/dist/{check-YEOYBFST.js.map → check-WFXSXICD.js.map} +0 -0
  182. /package/dist/{chunk-IGSHYP74.js.map → chunk-23P7KMJM.js.map} +0 -0
  183. /package/dist/{chunk-HA6MQMOY.js.map → chunk-24J7TYPU.js.map} +0 -0
  184. /package/dist/{chunk-PCS4VJBV.js.map → chunk-37QJLVS3.js.map} +0 -0
  185. /package/dist/{chunk-4CK6ZSOK.js.map → chunk-3P6KCU36.js.map} +0 -0
  186. /package/dist/{chunk-54F74XR3.js.map → chunk-5JBVFWVP.js.map} +0 -0
  187. /package/dist/{chunk-B7XYNRJQ.js.map → chunk-6KIYVVKL.js.map} +0 -0
  188. /package/dist/{chunk-GDVZ5VII.js.map → chunk-7A452BPZ.js.map} +0 -0
  189. /package/dist/{chunk-M42DZCOU.js.map → chunk-7FCLXEAQ.js.map} +0 -0
  190. /package/dist/{chunk-LBSCW232.js.map → chunk-7NXPQKSB.js.map} +0 -0
  191. /package/dist/{chunk-OPXWPJDA.js.map → chunk-A3TEDWBZ.js.map} +0 -0
  192. /package/dist/{chunk-BBT6AVUG.js.map → chunk-BHHXU2D2.js.map} +0 -0
  193. /package/dist/{chunk-FQXWVS6J.js.map → chunk-CMMBWHT2.js.map} +0 -0
  194. /package/dist/{chunk-EIFCP6CZ.js.map → chunk-CO47QJKZ.js.map} +0 -0
  195. /package/dist/{chunk-ADMEPUBT.js.map → chunk-CXWTNT2O.js.map} +0 -0
  196. /package/dist/{chunk-LKP7QDFN.js.map → chunk-DAQTRAP5.js.map} +0 -0
  197. /package/dist/{chunk-PWBH7DCQ.js.map → chunk-EESH6COU.js.map} +0 -0
  198. /package/dist/{chunk-NCPWXHDO.js.map → chunk-JEUFYSFQ.js.map} +0 -0
  199. /package/dist/{chunk-2IR4T5PO.js.map → chunk-JJ4RSDSY.js.map} +0 -0
  200. /package/dist/{chunk-WDWXAYVH.js.map → chunk-L3RLGGRK.js.map} +0 -0
  201. /package/dist/{chunk-T7JAOYE5.js.map → chunk-L75CAZG4.js.map} +0 -0
  202. /package/dist/{chunk-U7CTFN2J.js.map → chunk-MYRPMSOX.js.map} +0 -0
  203. /package/dist/{chunk-WQWKYAAK.js.map → chunk-NUQF5F5J.js.map} +0 -0
  204. /package/dist/{chunk-FUCPZVRY.js.map → chunk-OEN6FBUW.js.map} +0 -0
  205. /package/dist/{chunk-FBMZJEB3.js.map → chunk-OKMTUAWO.js.map} +0 -0
  206. /package/dist/{chunk-R4WXQIOZ.js.map → chunk-PCEM5FOZ.js.map} +0 -0
  207. /package/dist/{chunk-4D5IZSXM.js.map → chunk-PXNCRGUL.js.map} +0 -0
  208. /package/dist/{chunk-ODRPL3WB.js.map → chunk-Q3ODX5PF.js.map} +0 -0
  209. /package/dist/{chunk-KGEQJ5CC.js.map → chunk-RRFFUWDL.js.map} +0 -0
  210. /package/dist/{chunk-NSBXVPZL.js.map → chunk-S3XUYW5K.js.map} +0 -0
  211. /package/dist/{chunk-LPIF5LIE.js.map → chunk-SAU2WQFC.js.map} +0 -0
  212. /package/dist/{chunk-MSRU4D4P.js.map → chunk-SFLICIQV.js.map} +0 -0
  213. /package/dist/{chunk-NGTVREIH.js.map → chunk-U6IHLEWT.js.map} +0 -0
  214. /package/dist/{chunk-VQK4VHLF.js.map → chunk-YQV75FIL.js.map} +0 -0
  215. /package/dist/{chunk-TU2WUBVZ.js.map → chunk-YUTVAMWW.js.map} +0 -0
  216. /package/dist/{chunk-RLT5SEML.js.map → chunk-Z5MZCCTT.js.map} +0 -0
  217. /package/dist/{cli-JJMOVIKS.js.map → cli-BS43EVCD.js.map} +0 -0
  218. /package/dist/{cli-ONTC5PKT.js.map → cli-FX53PBQ3.js.map} +0 -0
  219. /package/dist/{cli-I62SRH3R.js.map → cli-NGL63E53.js.map} +0 -0
  220. /package/dist/{cli-VUKMWSSF.js.map → cli-WNEI5L7P.js.map} +0 -0
  221. /package/dist/{config-XDA42RJL.js.map → config-JJW75SBX.js.map} +0 -0
  222. /package/dist/{github-RY3FRA6P.js.map → github-4UR67MEN.js.map} +0 -0
  223. /package/dist/{github-YKQSH7FS.js.map → github-UPGKMVVF.js.map} +0 -0
  224. /package/dist/{host-6GURH5HE.js.map → host-YSTYO5DX.js.map} +0 -0
  225. /package/dist/{json-BXY44ED7.js.map → json-DQIELR36.js.map} +0 -0
  226. /package/dist/{lint-YJ2L22BW.js.map → lint-BLBGGOYM.js.map} +0 -0
  227. /package/dist/{list-NSG24VVX.js.map → list-B3RRRWFQ.js.map} +0 -0
  228. /package/dist/{list-V6EGCSHX.js.map → list-ZFRT3JQH.js.map} +0 -0
  229. /package/dist/{page-EV7OUBAU.js.map → page-5ISEVJR5.js.map} +0 -0
  230. /package/dist/{pretty-Q5Y2PA64.js.map → pretty-Y7CGQLAF.js.map} +0 -0
  231. /package/dist/{pretty-SCRK66M5.js.map → pretty-ZISH3Q4F.js.map} +0 -0
  232. /package/dist/{provider-527CO4DM.js.map → provider-LBX4IXGX.js.map} +0 -0
  233. /package/dist/{release-3D5PK6M7.js.map → release-VV3UTKE5.js.map} +0 -0
  234. /package/dist/{reporters-A5ADKDYR.js.map → reporters-26H3N2KW.js.map} +0 -0
  235. /package/dist/{reporters-M6LJ2IYU.js.map → reporters-4STXJJE2.js.map} +0 -0
  236. /package/dist/{reporters-RBYTASMI.js.map → reporters-74B4U2GZ.js.map} +0 -0
  237. /package/dist/{run-BUE2DDXN.js.map → run-DVGTKM52.js.map} +0 -0
  238. /package/dist/{validate-ZBW44RHT.js.map → validate-CJNFQHMD.js.map} +0 -0
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ renderFindingsGithub
4
+ } from "./chunk-SAU2WQFC.js";
2
5
  import {
3
6
  renderFindingsJson,
4
7
  renderFormatsJson,
5
8
  renderGetJson,
6
9
  renderListJson
7
- } from "./chunk-MSRU4D4P.js";
10
+ } from "./chunk-SFLICIQV.js";
8
11
  import {
9
12
  renderFindingsPretty,
10
13
  renderFormatsPretty,
@@ -12,7 +15,7 @@ import {
12
15
  renderListPretty,
13
16
  renderValeWiring,
14
17
  renderWritePretty
15
- } from "./chunk-JPQDNYXH.js";
18
+ } from "./chunk-EM67O2ET.js";
16
19
  import {
17
20
  FINDING_FORMATS,
18
21
  JUNIT_CLASSNAME,
@@ -24,22 +27,25 @@ import {
24
27
  runCheck,
25
28
  summarize,
26
29
  toResults
27
- } from "./chunk-4VBSTXN6.js";
30
+ } from "./chunk-XYRUDFKS.js";
28
31
  import {
29
32
  LIST_FORMATS,
30
33
  runList
31
- } from "./chunk-B7XYNRJQ.js";
32
- import {
33
- renderFindingsGithub
34
- } from "./chunk-LPIF5LIE.js";
34
+ } from "./chunk-6KIYVVKL.js";
35
35
  import {
36
+ DEFAULT_CRAWL_MIN_PAGES,
37
+ DEFAULT_FILL_CACHE_DIR,
38
+ DEFAULT_FILL_CONFIDENCE,
36
39
  DEFAULT_LANGUAGE,
37
40
  DITA_HOLDS,
38
41
  DOCBOOK_HOLDS,
39
42
  LIST_HOLDS,
40
43
  MANIFEST_FORMAT,
44
+ SKOS,
45
+ SKOS_PROPERTIES,
41
46
  TBX_V3_NAMESPACE,
42
47
  TERM_FIELDS,
48
+ TERM_MATCH_FIELDS,
43
49
  TERM_READERS,
44
50
  TERM_RULES,
45
51
  TERM_WRITE_FORMATS,
@@ -70,52 +76,70 @@ import {
70
76
  resolveTermRun,
71
77
  rstEntry,
72
78
  sharedLanguage,
79
+ slugOf,
73
80
  tbxEntryLines,
74
81
  tbxInput,
75
82
  tbxSourceOf,
76
83
  valeConfigFor,
77
84
  xmlAttribute,
78
85
  xmlText
79
- } from "./chunk-J6IDQGJL.js";
80
- import "./chunk-77AINBYM.js";
86
+ } from "./chunk-6TVH4FI7.js";
81
87
  import "./chunk-IKEWBMCN.js";
82
- import "./chunk-TU2WUBVZ.js";
83
- import "./chunk-LKP7QDFN.js";
88
+ import "./chunk-YUTVAMWW.js";
89
+ import "./chunk-DAQTRAP5.js";
84
90
  import {
85
- registerTermLabelSource
86
- } from "./chunk-6HWBRZIN.js";
87
- import "./chunk-M42DZCOU.js";
88
- import "./chunk-PCQ7ELJH.js";
91
+ DEFAULT_CHUNK_CHARS,
92
+ splitBody
93
+ } from "./chunk-VQYGLU4C.js";
89
94
  import {
90
- collect,
91
- readStdin,
92
- splitList
93
- } from "./chunk-GV56WGL2.js";
95
+ mergeMetaProvenance
96
+ } from "./chunk-7FCLXEAQ.js";
94
97
  import {
95
98
  OMITTED_WHEN_CLEAN,
96
99
  renderJunit,
97
100
  renderSarif
98
- } from "./chunk-D4N2V43Z.js";
101
+ } from "./chunk-CEI2J42X.js";
102
+ import "./chunk-L2TD7DZB.js";
103
+ import {
104
+ collect,
105
+ readStdin,
106
+ splitList
107
+ } from "./chunk-WO4JYWZK.js";
108
+ import "./chunk-DSWKBZWW.js";
99
109
  import {
100
110
  STDIN_TOKEN,
101
111
  extractorByName,
102
112
  extractorForExtension
103
- } from "./chunk-VSEBFHAY.js";
104
- import {
105
- fail
106
- } from "./chunk-YEUYKR62.js";
113
+ } from "./chunk-KFKL4VTL.js";
114
+ import "./chunk-77AINBYM.js";
115
+ import "./chunk-MNH7QO4Z.js";
107
116
  import {
108
117
  shouldColor
109
118
  } from "./chunk-RNVYGWIC.js";
110
- import "./chunk-MNH7QO4Z.js";
111
- import "./chunk-QLWC7MKD.js";
112
119
  import {
113
- notice
120
+ fail
121
+ } from "./chunk-YEUYKR62.js";
122
+ import "./chunk-OTJOBZJ5.js";
123
+ import {
124
+ notice,
125
+ warn
114
126
  } from "./chunk-HX44GB4Z.js";
115
- import "./chunk-QCHVR4ZM.js";
127
+ import {
128
+ DEFAULT_PROVIDER,
129
+ LOCAL_FLAG_HELP,
130
+ assertKnownProvider,
131
+ assertLocalFlag,
132
+ assertModelHasProvider,
133
+ localNotice,
134
+ noOfflineModel,
135
+ offlineIdentity,
136
+ providerSpecFor,
137
+ resolveIdentity,
138
+ selectProvider
139
+ } from "./chunk-VM7VAFJW.js";
116
140
  import {
117
141
  package_default
118
- } from "./chunk-2MJ62AYQ.js";
142
+ } from "./chunk-7MCQHTQ5.js";
119
143
  import "./chunk-OWBRDNRZ.js";
120
144
  import {
121
145
  errorMessage
@@ -125,6 +149,143 @@ import "./chunk-2H7UOFLK.js";
125
149
  // src/term/cli.ts
126
150
  import { Command } from "commander";
127
151
 
152
+ // src/term/commands/fill.ts
153
+ import { existsSync } from "node:fs";
154
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
155
+ import { dirname as dirname2, extname as extname2, join as join3, resolve as resolve2 } from "node:path";
156
+ import {
157
+ JsonCache,
158
+ buildCacheKey,
159
+ completeValidatedJSON,
160
+ makeProvider as makeInferenceProvider,
161
+ sha256,
162
+ validatorFor
163
+ } from "@hawkeyexl/inference";
164
+
165
+ // src/term/core/fill-plan.ts
166
+ import { dirname, extname } from "node:path";
167
+ function fold(value) {
168
+ return value.trim().toLowerCase();
169
+ }
170
+ function termIndex(terms) {
171
+ const index = /* @__PURE__ */ new Map();
172
+ const claim = (key, term) => {
173
+ if (!index.has(fold(key))) index.set(fold(key), term);
174
+ };
175
+ for (const term of terms) {
176
+ claim(term.record.label, term);
177
+ claim(term.id, term);
178
+ for (const alt of term.record["alt-labels"] ?? []) claim(alt, term);
179
+ }
180
+ return index;
181
+ }
182
+ function addUnique(list, value) {
183
+ if (!list.some((v) => fold(v) === fold(value))) list.push(value);
184
+ }
185
+ var EDGE_LISTS = { broader: "broader", narrower: "narrower", "related-concepts": "related" };
186
+ function namedConcepts(set) {
187
+ const alias = /* @__PURE__ */ new Map();
188
+ for (const block of set.blocks) {
189
+ for (const alt of block.altLabels ?? []) if (!alias.has(fold(alt))) alias.set(fold(alt), block.label);
190
+ }
191
+ const concepts = [];
192
+ const byKey = /* @__PURE__ */ new Map();
193
+ const named = (value, at2, language) => {
194
+ const label = alias.get(fold(value)) ?? value;
195
+ let concept = byKey.get(fold(label));
196
+ if (concept === void 0) {
197
+ concept = { label: label.trim(), from: [], altLabels: [], broader: [], narrower: [], related: [] };
198
+ concepts.push(concept);
199
+ byKey.set(fold(label), concept);
200
+ }
201
+ if (concept.language === void 0 && language !== void 0) concept.language = language;
202
+ if (!concept.from.some((f) => f.file === at2.file && f.line === at2.line)) concept.from.push(at2);
203
+ };
204
+ const at = (file, line) => line === void 0 ? { file } : { file, line };
205
+ for (const reference of set.references) {
206
+ named(reference.label, at(reference.file, reference.line), reference.language);
207
+ }
208
+ for (const block of set.blocks) {
209
+ for (const edge of block.edges) named(edge.value, at(block.file, edge.line ?? block.line), block.language);
210
+ }
211
+ for (const block of set.blocks) {
212
+ const concept = byKey.get(fold(block.label));
213
+ if (concept !== void 0) enrich(concept, block);
214
+ }
215
+ return concepts;
216
+ }
217
+ function enrich(concept, block) {
218
+ for (const alt of block.altLabels ?? []) if (fold(alt) !== fold(concept.label)) addUnique(concept.altLabels, alt);
219
+ for (const edge of block.edges) addUnique(concept[EDGE_LISTS[edge.field]], edge.value);
220
+ if (concept.definition === void 0 && block.definition !== void 0) concept.definition = block.definition;
221
+ }
222
+ function planFromMetadata(set) {
223
+ const index = termIndex(set.terms);
224
+ const create = namedConcepts(set).filter((concept) => !index.has(fold(concept.label)));
225
+ const carried2 = /* @__PURE__ */ new Map();
226
+ for (const block of set.blocks) {
227
+ const term = index.get(fold(block.label));
228
+ if (term !== void 0 && block.definition !== void 0 && !carried2.has(term)) carried2.set(term, block.definition);
229
+ }
230
+ const missing = set.terms.filter((t) => t.record.definition === void 0 && t.record.see === void 0).map((term) => {
231
+ const definition = carried2.get(term);
232
+ return definition === void 0 ? { term } : { term, carried: definition };
233
+ });
234
+ return { create, missing };
235
+ }
236
+ function sharedTermDirectory(terms) {
237
+ const dirs = new Set(
238
+ terms.filter((t) => t.location.construct === "page" && t.location.path !== void 0).map((t) => dirname(t.location.path ?? ""))
239
+ );
240
+ return dirs.size === 1 ? [...dirs][0] : void 0;
241
+ }
242
+ var FILL_PAGE_FORMATS = {
243
+ ".md": "markdown",
244
+ ".mdx": "mdx",
245
+ ".adoc": "asciidoc",
246
+ ".rst": "rst",
247
+ ".html": "html",
248
+ ".dita": "dita"
249
+ };
250
+ function mostCommon(extensions) {
251
+ const counts = /* @__PURE__ */ new Map();
252
+ for (const ext of extensions) if (ext in FILL_PAGE_FORMATS) counts.set(ext, (counts.get(ext) ?? 0) + 1);
253
+ let best;
254
+ for (const [ext, n] of counts) if (best === void 0 || n > (counts.get(best) ?? 0)) best = ext;
255
+ return best;
256
+ }
257
+ function pageExtension(terms, dir, pages) {
258
+ const inDir = terms.filter((t) => t.location.construct === "page" && t.location.path !== void 0).filter((t) => dirname(t.location.path ?? "") === dir).map((t) => extname(t.location.path ?? "").toLowerCase());
259
+ return mostCommon(inDir) ?? mostCommon(pages.map((p) => extname(p).toLowerCase())) ?? ".md";
260
+ }
261
+ function mergeFound(found) {
262
+ const out = [];
263
+ const byKey = /* @__PURE__ */ new Map();
264
+ for (const f of found) {
265
+ let c = byKey.get(fold(f.label));
266
+ if (c === void 0) {
267
+ c = { label: f.label.trim(), altLabels: [], from: [] };
268
+ out.push(c);
269
+ byKey.set(fold(f.label), c);
270
+ }
271
+ for (const alt of f.altLabels ?? []) if (fold(alt) !== fold(c.label)) addUnique(c.altLabels, alt);
272
+ if (c.language === void 0 && f.language !== void 0) c.language = f.language;
273
+ if (!c.from.some((at) => at.file === f.file)) c.from.push(f.line === void 0 ? { file: f.file } : { file: f.file, line: f.line });
274
+ if (f.confidence !== void 0 && (c.confidence === void 0 || f.confidence > c.confidence)) {
275
+ c.confidence = f.confidence;
276
+ if (f.definition !== void 0) c.definition = f.definition;
277
+ } else if (c.definition === void 0 && f.definition !== void 0) {
278
+ c.definition = f.definition;
279
+ }
280
+ }
281
+ return out;
282
+ }
283
+ function newCandidates(candidates, known, minPages) {
284
+ return candidates.filter(
285
+ (c) => c.from.length >= minPages && !known.has(fold(c.label)) && !c.altLabels.some((a) => known.has(fold(a)))
286
+ );
287
+ }
288
+
128
289
  // src/term/core/writers/documents.ts
129
290
  import { join } from "node:path";
130
291
 
@@ -515,92 +676,179 @@ var jsonWriter = {
515
676
  };
516
677
 
517
678
  // src/term/core/writers/skos.ts
518
- var HOLDS2 = [
519
- "label",
520
- "definition",
521
- "alt-labels",
522
- "hidden-labels",
523
- "broader",
524
- "narrower",
525
- "related-terms",
526
- "scope-note"
527
- ];
528
- var CONTEXT = {
529
- skos: "http://www.w3.org/2004/02/skos/core#",
679
+ import { DataFactory, Writer } from "n3";
680
+ var HOLDS2 = SKOS_PROPERTIES.map((p) => p.field);
681
+ var REDIRECT_HOLDS = ["label", "see"];
682
+ var RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
683
+ var PREFIXES = {
684
+ skos: SKOS,
530
685
  dcterms: "http://purl.org/dc/terms/"
531
686
  };
532
687
  var SCHEME_ID = "";
533
- function literal(term, value) {
534
- return term.language === void 0 ? value : { "@value": value, "@language": term.language };
688
+ var DESCRIPTION = "Generated by manni term write.";
689
+ var SINGLE = /* @__PURE__ */ new Set([
690
+ "skos:inScheme",
691
+ "skos:topConceptOf",
692
+ "skos:prefLabel",
693
+ "skos:definition",
694
+ "skos:scopeNote",
695
+ "skos:notation",
696
+ "dcterms:description"
697
+ ]);
698
+ function literal(term, text) {
699
+ return term.language === void 0 ? { text } : { text, language: term.language };
535
700
  }
536
701
  function resolve(terms, self, value) {
537
702
  const wanted = value.toLowerCase();
538
- const others = terms.filter((t) => t !== self);
703
+ const others = terms.filter((t) => t.id !== self);
539
704
  return others.find((t) => t.record.label.toLowerCase() === wanted) ?? others.find((t) => t.id.toLowerCase() === wanted);
540
705
  }
541
- function references(terms, self, values) {
542
- const ids = [];
543
- for (const value of values ?? []) {
544
- const target = resolve(terms, self, value);
545
- if (target !== void 0 && !ids.includes(target.id)) ids.push(target.id);
546
- }
547
- return ids.map((id) => ({ "@id": `#${id}` }));
706
+ function sameValue(a, b) {
707
+ if ("iri" in a) return "iri" in b && a.iri === b.iri;
708
+ return !("iri" in b) && a.text === b.text && a.language === b.language;
548
709
  }
549
- function concept(terms, term) {
550
- const { record } = term;
551
- const node = {
552
- "@id": `#${term.id}`,
553
- "@type": "skos:Concept",
554
- "skos:inScheme": { "@id": SCHEME_ID },
555
- "skos:prefLabel": literal(term, record.label)
556
- };
557
- if (record["alt-labels"] !== void 0) node["skos:altLabel"] = record["alt-labels"].map((v) => literal(term, v));
558
- if (record["hidden-labels"] !== void 0) {
559
- node["skos:hiddenLabel"] = record["hidden-labels"].map((v) => literal(term, v));
560
- }
561
- if (record.definition !== void 0) node["skos:definition"] = literal(term, record.definition);
562
- if (record["scope-note"] !== void 0) node["skos:scopeNote"] = literal(term, record["scope-note"]);
563
- const relations = [
564
- ["skos:broader", record.broader],
565
- ["skos:narrower", record.narrower],
566
- ["skos:related", record["related-terms"]]
567
- ];
568
- for (const [key, values] of relations) {
569
- const refs = references(terms, term, values);
570
- if (refs.length > 0) node[key] = refs;
571
- }
572
- return node;
710
+ function pushUnique(values, value) {
711
+ if (!values.some((v) => sameValue(v, value))) values.push(value);
573
712
  }
574
- var skosWriter = {
575
- format: "skos",
576
- shapes: ["file"],
577
- holds: (_shape) => HOLDS2,
578
- render(terms, target) {
579
- requireShape("skos", target, "file");
580
- const document = {
581
- "@context": CONTEXT,
582
- "@graph": [
583
- {
584
- "@id": SCHEME_ID,
585
- "@type": "skos:ConceptScheme",
586
- "dcterms:description": "Generated by manni term write."
587
- },
588
- ...terms.map((term) => concept(terms, term))
589
- ]
713
+ function graphOf(terms) {
714
+ const redirects = /* @__PURE__ */ new Map();
715
+ for (const term of terms) {
716
+ const target = term.record.see === void 0 ? void 0 : resolve(terms, term.id, term.record.see);
717
+ if (target !== void 0) redirects.set(term, target.id);
718
+ }
719
+ const concepts = terms.filter((t) => !redirects.has(t));
720
+ const conflicts = [];
721
+ const nodes = [];
722
+ const tops = [];
723
+ for (const group of conceptGroups(concepts)) {
724
+ const [first] = group;
725
+ if (first === void 0) continue;
726
+ const { id } = first;
727
+ const values = /* @__PURE__ */ new Map();
728
+ const add = (property, value) => {
729
+ const list = values.get(property) ?? [];
730
+ pushUnique(list, value);
731
+ values.set(property, list);
590
732
  };
591
- const content = `${JSON.stringify(document, null, 2)}
733
+ for (const { property, field, kind } of SKOS_PROPERTIES) {
734
+ const name = `skos:${property}`;
735
+ if (kind === "code") {
736
+ const merged = mergeFirst(id, group.map((t) => ({ [field]: t.record[field] })));
737
+ conflicts.push(...merged.conflicts);
738
+ const text = merged.merged[field];
739
+ if (typeof text === "string") add(name, { text });
740
+ continue;
741
+ }
742
+ for (const term of group) {
743
+ const raw = term.record[field];
744
+ const list = raw === void 0 ? [] : typeof raw === "string" ? [raw] : raw;
745
+ for (const value of list) {
746
+ if (kind === "iris") add(name, { iri: value });
747
+ else if (kind === "concepts") {
748
+ const target = resolve(terms, id, value);
749
+ if (target !== void 0) add(name, { iri: `#${target.id}` });
750
+ } else add(name, literal(term, value));
751
+ }
752
+ }
753
+ if (property === "altLabel") {
754
+ for (const [redirect, target] of redirects) if (target === id) add(name, literal(redirect, redirect.record.label));
755
+ }
756
+ }
757
+ const top = !values.has("skos:broader");
758
+ if (top) tops.push({ iri: `#${id}` });
759
+ nodes.push({
760
+ id: `#${id}`,
761
+ type: "skos:Concept",
762
+ properties: [
763
+ ["skos:inScheme", [{ iri: SCHEME_ID }]],
764
+ ...top ? [["skos:topConceptOf", [{ iri: SCHEME_ID }]]] : [],
765
+ ...SKOS_PROPERTIES.flatMap(({ property }) => {
766
+ const list = values.get(`skos:${property}`);
767
+ return list === void 0 ? [] : [[`skos:${property}`, list]];
768
+ })
769
+ ]
770
+ });
771
+ }
772
+ const scheme = {
773
+ id: SCHEME_ID,
774
+ type: "skos:ConceptScheme",
775
+ properties: [["dcterms:description", [{ text: DESCRIPTION }]], ...tops.length === 0 ? [] : [["skos:hasTopConcept", tops]]]
776
+ };
777
+ const dropped = terms.flatMap((t) => droppedFields([t], redirects.has(t) ? REDIRECT_HOLDS : HOLDS2));
778
+ return { nodes: [scheme, ...nodes], dropped, conflicts };
779
+ }
780
+ function jsonValue(value) {
781
+ if ("iri" in value) return { "@id": value.iri };
782
+ return value.language === void 0 ? value.text : { "@value": value.text, "@language": value.language };
783
+ }
784
+ function jsonLd(nodes) {
785
+ const graph = nodes.map((node) => {
786
+ const out = { "@id": node.id, "@type": node.type };
787
+ for (const [property, values] of node.properties) {
788
+ const [only] = values;
789
+ out[property] = SINGLE.has(property) && values.length === 1 && only !== void 0 ? jsonValue(only) : values.map(jsonValue);
790
+ }
791
+ return out;
792
+ });
793
+ return `${JSON.stringify({ "@context": PREFIXES, "@graph": graph }, null, 2)}
592
794
  `;
593
- return {
594
- files: [{ path: target.path, content }],
595
- removals: [],
596
- dropped: droppedFields(terms, HOLDS2),
597
- skipped: []
598
- };
795
+ }
796
+ function expand(name) {
797
+ const [prefix = "", local = ""] = name.split(":");
798
+ if (!Object.hasOwn(PREFIXES, prefix)) throw new Error(`skos writer: unknown prefix "${prefix}" in ${name}`);
799
+ return `${PREFIXES[prefix]}${local}`;
800
+ }
801
+ function turtle(nodes) {
802
+ const iri = (value) => DataFactory.namedNode(value);
803
+ const writer = new Writer({ prefixes: PREFIXES });
804
+ for (const node of nodes) {
805
+ const subject = iri(node.id);
806
+ writer.addQuad(DataFactory.quad(subject, iri(RDF_TYPE), iri(expand(node.type))));
807
+ for (const [property, values] of node.properties) {
808
+ for (const value of values) {
809
+ const object = "iri" in value ? iri(value.iri) : DataFactory.literal(value.text, value.language);
810
+ writer.addQuad(DataFactory.quad(subject, iri(expand(property)), object));
811
+ }
812
+ }
599
813
  }
600
- };
814
+ let content = "";
815
+ writer.end((_error, result) => {
816
+ content = result;
817
+ });
818
+ return content;
819
+ }
820
+ function skosWriterFor(format, serialize) {
821
+ return {
822
+ format,
823
+ shapes: ["file"],
824
+ holds: (_shape) => HOLDS2,
825
+ render(terms, target) {
826
+ requireShape(format, target, "file");
827
+ const { nodes, dropped, conflicts } = graphOf(terms);
828
+ return {
829
+ files: [{ path: target.path, content: serialize(nodes) }],
830
+ removals: [],
831
+ dropped,
832
+ skipped: [],
833
+ ...conflicts.length === 0 ? {} : { conflicts }
834
+ };
835
+ }
836
+ };
837
+ }
838
+ var skosWriter = skosWriterFor("skos", jsonLd);
839
+ var skosTtlWriter = skosWriterFor("skos-ttl", turtle);
601
840
 
602
841
  // src/term/core/writers/tbx.ts
603
- var NOT_HELD = ["abstract", "broader", "narrower", "related-terms", "see", "scope-note"];
842
+ var NOT_HELD = [
843
+ "abstract",
844
+ "broader",
845
+ "narrower",
846
+ "related-terms",
847
+ "see",
848
+ "scope-note",
849
+ "notation",
850
+ ...TERM_MATCH_FIELDS
851
+ ];
604
852
  var HOLDS3 = TERM_FIELDS.filter((field) => !NOT_HELD.includes(field));
605
853
  var LINGUIST_FIELDS = ["register", "reading", "reading-note", "grammatical-number", "transfer-comments"];
606
854
  var ENTRY_INDENT = " ";
@@ -902,11 +1150,514 @@ var valeWriter = {
902
1150
  };
903
1151
 
904
1152
  // src/term/core/writers/interchange.ts
905
- var INTERCHANGE_WRITERS = [tbxWriter, tbx3Writer, skosWriter, csvWriter, jsonWriter, valeWriter];
1153
+ var INTERCHANGE_WRITERS = [tbxWriter, tbx3Writer, skosWriter, skosTtlWriter, csvWriter, jsonWriter, valeWriter];
906
1154
 
907
1155
  // src/term/core/writers/index.ts
908
1156
  var TERM_WRITERS = [...DOCUMENT_WRITERS, ...INTERCHANGE_WRITERS];
909
1157
 
1158
+ // src/term/commands/fill.ts
1159
+ var FILL_FORMATS = ["pretty", "json"];
1160
+ var TURN_BUDGET_REASON = "turn budget";
1161
+ var PROMPT_VERSION = 1;
1162
+ var META_PROVENANCE_KEY = "meta-provenance";
1163
+ var DEFINITION_SYSTEM = [
1164
+ "You write glossary definitions for a documentation set's termbase.",
1165
+ "Define the term in one sentence, as the pages quoted use it.",
1166
+ "Give your confidence, from 0 to 1, that the definition is right for these pages.",
1167
+ "When the context is too thin to be sure, say so with a low confidence rather than guessing."
1168
+ ].join(" ");
1169
+ var DEFINITION_SCHEMA = {
1170
+ type: "object",
1171
+ additionalProperties: false,
1172
+ required: ["definition", "confidence"],
1173
+ properties: { definition: { type: "string" }, confidence: { type: "number" } }
1174
+ };
1175
+ var CRAWL_SYSTEM = [
1176
+ "You find the domain terms a documentation page uses: product concepts, technical terms and jargon a glossary should define.",
1177
+ "Leave out everyday words, people, and code identifiers.",
1178
+ "For each term give its label in singular form, any synonyms the page uses, a one-sentence definition from the page's context,",
1179
+ "and your confidence, from 0 to 1, that it belongs in a glossary and that the definition is right."
1180
+ ].join(" ");
1181
+ var CRAWL_SCHEMA = {
1182
+ type: "object",
1183
+ additionalProperties: false,
1184
+ required: ["terms"],
1185
+ properties: {
1186
+ terms: {
1187
+ type: "array",
1188
+ items: {
1189
+ type: "object",
1190
+ additionalProperties: false,
1191
+ required: ["label", "alt-labels", "definition", "confidence"],
1192
+ properties: {
1193
+ label: { type: "string" },
1194
+ "alt-labels": { type: "array", items: { type: "string" } },
1195
+ definition: { type: "string" },
1196
+ confidence: { type: "number" }
1197
+ }
1198
+ }
1199
+ }
1200
+ }
1201
+ };
1202
+ var validateDefinition = validatorFor(DEFINITION_SCHEMA);
1203
+ var validateCrawl = validatorFor(CRAWL_SCHEMA);
1204
+ function score(value) {
1205
+ return typeof value === "number" && value >= 0 && value <= 1 ? Math.round(value * 100) / 100 : 0;
1206
+ }
1207
+ function nonEmpty(value) {
1208
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
1209
+ }
1210
+ function strings(value) {
1211
+ return Array.isArray(value) ? value.map(nonEmpty).filter((v) => v !== void 0) : [];
1212
+ }
1213
+ function keywordsOf(value) {
1214
+ return typeof value === "string" ? strings([value]) : strings(value);
1215
+ }
1216
+ function wholeWord(label) {
1217
+ const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1218
+ return new RegExp(`(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`, "iu");
1219
+ }
1220
+ function lineOf(content, label) {
1221
+ const match = wholeWord(label).exec(content);
1222
+ return match === null ? void 0 : content.slice(0, match.index).split("\n").length;
1223
+ }
1224
+ function fromList(from, cwd) {
1225
+ return from.map((at) => {
1226
+ const file = displayPath(at.file, cwd);
1227
+ return at.line === void 0 ? file : `${file}:${String(at.line)}`;
1228
+ });
1229
+ }
1230
+ var toTermError = (message) => new TermError(message);
1231
+ async function resolveModel(opts, run) {
1232
+ const injected = (provider) => ({
1233
+ provider,
1234
+ identity: { provider: provider.provider(), model: provider.modelName() }
1235
+ });
1236
+ const offline = opts.offline === true;
1237
+ if (opts.providerInstance !== void 0 && !offline) return injected(opts.providerInstance);
1238
+ const flags = {
1239
+ ...opts.provider === void 0 ? {} : { provider: opts.provider },
1240
+ ...opts.model === void 0 ? {} : { model: opts.model },
1241
+ ...opts.local === true ? { local: true } : {},
1242
+ ...offline ? { offline: true } : {}
1243
+ };
1244
+ assertLocalFlag(flags, toTermError);
1245
+ const family = run.configFile?.providers ?? {};
1246
+ const selection = selectProvider(flags, [
1247
+ {
1248
+ ...run.config?.provider === void 0 ? {} : { provider: run.config.provider },
1249
+ ...run.config?.model === void 0 ? {} : { model: run.config.model },
1250
+ origin: "term.provider"
1251
+ },
1252
+ {
1253
+ ...family.provider === void 0 ? {} : { provider: family.provider },
1254
+ ...family.model === void 0 ? {} : { model: family.model },
1255
+ origin: "providers.provider"
1256
+ }
1257
+ ]);
1258
+ const { provider: name, model: chosen } = selection;
1259
+ assertKnownProvider(name, toTermError);
1260
+ assertModelHasProvider(name, chosen, "term.provider", toTermError);
1261
+ const named = [flags.provider, flags.model, run.config?.provider, run.config?.model, family.provider, family.model].some(
1262
+ (value) => value !== void 0 && value !== DEFAULT_PROVIDER
1263
+ );
1264
+ const notice2 = localNotice(selection, flags);
1265
+ if (notice2 !== void 0) opts.onNotice?.(notice2);
1266
+ try {
1267
+ const spec = providerSpecFor(family, { provider: name, model: chosen ?? null });
1268
+ const identity = offline ? await offlineIdentity(spec, toTermError) : await resolveIdentity(spec, toTermError);
1269
+ if (identity === void 0) return void 0;
1270
+ if (opts.providerInstance !== void 0) return injected(opts.providerInstance);
1271
+ return { provider: makeInferenceProvider(providerSpecFor(family, identity)), identity };
1272
+ } catch (error) {
1273
+ if (named) opts.onNotice?.(`the configured provider "${name}" could not run: ${errorMessage(error)}`);
1274
+ return void 0;
1275
+ }
1276
+ }
1277
+ async function runFill(opts) {
1278
+ const cwd = resolve2(opts.cwd ?? process.cwd());
1279
+ const run = await resolveTermRun({
1280
+ cwd,
1281
+ inputs: opts.inputs,
1282
+ ...opts.configPath === void 0 ? {} : { configPath: opts.configPath },
1283
+ ...opts.collection === void 0 ? {} : { collection: opts.collection }
1284
+ });
1285
+ const pages = [];
1286
+ const onPage = (input) => {
1287
+ const language = input.metadata["language"];
1288
+ const keywordsLine = input.lineFor("/keywords");
1289
+ pages.push({
1290
+ file: input.file,
1291
+ ...input.path === void 0 ? {} : { path: input.path },
1292
+ content: input.content,
1293
+ metadata: input.metadata,
1294
+ ...typeof language === "string" && language !== "" ? { language } : {},
1295
+ ...keywordsLine === void 0 ? {} : { keywordsLine }
1296
+ });
1297
+ };
1298
+ const set = await loadSet(run, { ...opts, cwd, allowEmpty: true, onPage });
1299
+ const fillConfig = run.config?.fill ?? {};
1300
+ const configDir = run.configDir ?? cwd;
1301
+ const threshold = opts.confidence ?? fillConfig.confidenceThreshold ?? DEFAULT_FILL_CONFIDENCE;
1302
+ const maxTurns = opts.maxTurns ?? fillConfig.maxTurns ?? null;
1303
+ const minPages = fillConfig.crawl?.minPages ?? DEFAULT_CRAWL_MIN_PAGES;
1304
+ const chunkChars = opts.chunkChars ?? DEFAULT_CHUNK_CHARS;
1305
+ const crawl = opts.crawl === true;
1306
+ const dryRun = opts.dryRun === true;
1307
+ const plan = planFromMetadata(set);
1308
+ const needsDir = crawl || plan.create.length > 0;
1309
+ const outDir = !needsDir ? void 0 : opts.out !== void 0 ? resolve2(cwd, opts.out) : fillConfig.out !== void 0 ? resolve2(configDir, fillConfig.out) : sharedTermDirectory(set.terms);
1310
+ if (needsDir && outDir === void 0) {
1311
+ throw new TermError("new term pages need a directory; pass -o or set term.fill.out.");
1312
+ }
1313
+ const ext = outDir === void 0 ? ".md" : pageExtension(set.terms, outDir, pages.map((p) => p.file));
1314
+ const format = FILL_PAGE_FORMATS[ext] ?? "markdown";
1315
+ const wantsModel = crawl || plan.create.some((c) => c.definition === void 0) || plan.missing.some((m) => m.carried === void 0);
1316
+ let model;
1317
+ if (wantsModel) {
1318
+ model = await resolveModel(opts, run);
1319
+ if (model === void 0) {
1320
+ if (crawl) {
1321
+ throw new TermError(
1322
+ opts.offline === true ? "--crawl needs a model, and none is available offline; drop --offline, or download a local model first." : "--crawl needs a model, and no provider is configured; pass --provider or set providers:."
1323
+ );
1324
+ }
1325
+ warn(
1326
+ opts.offline === true ? noOfflineModel("new terms have no definition") : "no model provider is configured, so new terms have no definition; pass --provider or --local."
1327
+ );
1328
+ }
1329
+ }
1330
+ const modelName = model === void 0 ? void 0 : `${model.identity.provider}/${model.identity.model}`;
1331
+ const cache = new JsonCache(
1332
+ resolve2(configDir, fillConfig.cacheDir ?? DEFAULT_FILL_CACHE_DIR),
1333
+ opts.noCache !== true,
1334
+ "manni"
1335
+ );
1336
+ let turns = 0;
1337
+ const ask = async (m, kind, system, user, schema, validate) => {
1338
+ const key = buildCacheKey([m.identity.provider, m.identity.model, `v${String(PROMPT_VERSION)}`, kind, sha256(user)]);
1339
+ const cached = cache.get(key);
1340
+ if (cached !== void 0 && validate(cached)) return cached;
1341
+ if (maxTurns !== null && turns >= maxTurns) return void 0;
1342
+ turns++;
1343
+ const answer = await completeValidatedJSON({ provider: m.provider, system, user, schema, validate });
1344
+ if (answer.result === void 0) throw new TermError(answer.error ?? "the model returned no answer.");
1345
+ cache.set(key, answer.result);
1346
+ return answer.result;
1347
+ };
1348
+ const pageByFile = new Map(pages.map((p) => [p.file, p]));
1349
+ const definitionPrompt = (label, language, record, from) => {
1350
+ const lines = [`Term: ${label}`];
1351
+ if (language !== void 0) lines.push(`Language: ${language}`);
1352
+ const lists = [
1353
+ ["Also called", record["alt-labels"]],
1354
+ ["Broader", record.broader],
1355
+ ["Narrower", record.narrower],
1356
+ ["Related", record["related-terms"]]
1357
+ ];
1358
+ for (const [name, values] of lists) if (values !== void 0 && values.length > 0) lines.push(`${name}: ${values.join(", ")}`);
1359
+ const files = [...new Set(from.map((f) => f.file))].slice(0, 3);
1360
+ for (const file of files) {
1361
+ const page = pageByFile.get(file);
1362
+ if (page === void 0) continue;
1363
+ lines.push("", `Page ${file}`);
1364
+ for (const key of ["title", "description"]) {
1365
+ const value = nonEmpty(page.metadata[key]);
1366
+ if (value !== void 0) lines.push(`${key}: ${value}`);
1367
+ }
1368
+ const word = wholeWord(label);
1369
+ const uses = page.content.split("\n").filter((line) => word.test(line)).slice(0, 3);
1370
+ for (const use of uses) lines.push(`> ${use.trim()}`);
1371
+ }
1372
+ return lines.join("\n");
1373
+ };
1374
+ const draft = async (label, language, record, from) => {
1375
+ if (model === void 0) return void 0;
1376
+ let answer;
1377
+ try {
1378
+ answer = await ask(model, "definition", DEFINITION_SYSTEM, definitionPrompt(label, language, record, from), DEFINITION_SCHEMA, validateDefinition);
1379
+ } catch (error) {
1380
+ return { skip: `model error: ${errorMessage(error)}` };
1381
+ }
1382
+ if (answer === void 0) return { skip: TURN_BUDGET_REASON };
1383
+ const definition = nonEmpty(answer["definition"]);
1384
+ const confidence = score(answer["confidence"]);
1385
+ if (definition === void 0) return { skip: "the model gave no definition" };
1386
+ return { status: confidence >= threshold ? "drafted" : "below-threshold", definition, confidence };
1387
+ };
1388
+ const entries2 = [];
1389
+ const writes = [];
1390
+ const planned = /* @__PURE__ */ new Set();
1391
+ const known = new Set(termIndex(set.terms).keys());
1392
+ const render = (term, provenance) => {
1393
+ const writer = TERM_WRITERS.find((w) => w.format === format);
1394
+ const target = { path: outDir ?? cwd, shape: "directory" };
1395
+ const content = writer?.render([term], target, { existing: /* @__PURE__ */ new Map() }).files[0]?.content;
1396
+ if (content === void 0) throw new TermError(`manni cannot write a ${format} term page.`);
1397
+ if (provenance === void 0 || model === void 0) return content;
1398
+ const merged = mergeMetaProvenance(
1399
+ void 0,
1400
+ model.identity.model,
1401
+ "fields",
1402
+ provenance.fields.map((name) => ({ name, confidence: provenance.confidence }))
1403
+ );
1404
+ const extractor = extractorForExtension(ext);
1405
+ if (merged === void 0 || extractor?.apply === void 0) return content;
1406
+ return extractor.apply(content, { [META_PROVENANCE_KEY]: merged.list }, { filePath: join3(target.path, `x${ext}`) });
1407
+ };
1408
+ const create = async (concept, source, definition) => {
1409
+ const id = slugOf(concept.label);
1410
+ const path = join3(outDir ?? cwd, `${id}${ext}`);
1411
+ const base = {
1412
+ file: displayPath(path, cwd),
1413
+ id,
1414
+ label: concept.label,
1415
+ ...concept.language === void 0 ? {} : { language: concept.language },
1416
+ source,
1417
+ from: fromList(concept.from, cwd)
1418
+ };
1419
+ if (planned.has(path) || existsSync(path)) {
1420
+ entries2.push({ action: "exists", ...base, definition: { status: "missing" } });
1421
+ return;
1422
+ }
1423
+ const record = { label: concept.label };
1424
+ const lists = [
1425
+ ["alt-labels", concept.altLabels],
1426
+ ["broader", concept.broader],
1427
+ ["narrower", concept.narrower],
1428
+ ["related-terms", concept.related]
1429
+ ];
1430
+ for (const [field, values] of lists) if (values !== void 0 && values.length > 0) record[field] = values;
1431
+ let status = "missing";
1432
+ let confidence;
1433
+ let fields;
1434
+ if (definition.carried !== void 0) {
1435
+ record.definition = definition.carried;
1436
+ status = "carried";
1437
+ } else {
1438
+ const got = definition.drafted ?? await draft(concept.label, concept.language, record, concept.from);
1439
+ if (got !== void 0 && "skip" in got) {
1440
+ entries2.push({ action: "skip", ...base, definition: { status: "missing" }, reason: got.skip });
1441
+ return;
1442
+ }
1443
+ if (got !== void 0) {
1444
+ confidence = got.confidence;
1445
+ const below = "status" in got ? got.status === "below-threshold" : got.confidence < threshold;
1446
+ if (below) {
1447
+ status = "below-threshold";
1448
+ } else {
1449
+ record.definition = got.definition;
1450
+ status = "drafted";
1451
+ fields = definition.fields ?? ["/definition"];
1452
+ }
1453
+ }
1454
+ }
1455
+ const term = {
1456
+ id,
1457
+ record,
1458
+ ...concept.language === void 0 ? {} : { language: concept.language },
1459
+ location: { file: base.file, path, construct: "page", line: 1, fieldLines: {} }
1460
+ };
1461
+ planned.add(path);
1462
+ known.add(fold(concept.label));
1463
+ for (const alt of concept.altLabels) known.add(fold(alt));
1464
+ writes.push({ path, content: render(term, fields === void 0 || confidence === void 0 ? void 0 : { fields, confidence }) });
1465
+ entries2.push({
1466
+ action: "create",
1467
+ ...base,
1468
+ definition: {
1469
+ status,
1470
+ ...confidence === void 0 ? {} : { confidence },
1471
+ ...modelName === void 0 || confidence === void 0 ? {} : { model: modelName }
1472
+ }
1473
+ });
1474
+ };
1475
+ for (const concept of plan.create) {
1476
+ await create(concept, "metadata", concept.definition === void 0 ? {} : { carried: concept.definition });
1477
+ }
1478
+ for (const { term, carried: carried2 } of plan.missing) {
1479
+ if (carried2 === void 0 && model === void 0) continue;
1480
+ const path = term.location.path;
1481
+ const base = {
1482
+ file: displayPath(term.location.file, cwd),
1483
+ id: term.id,
1484
+ label: term.record.label,
1485
+ ...term.language === void 0 ? {} : { language: term.language },
1486
+ source: "metadata",
1487
+ from: [`${displayPath(term.location.file, cwd)}:${String(term.location.line)}`]
1488
+ };
1489
+ if (term.location.construct !== "page" || path === void 0) {
1490
+ entries2.push({ action: "skip", ...base, definition: { status: "missing" }, reason: "not a term page" });
1491
+ continue;
1492
+ }
1493
+ let definition;
1494
+ let provenance;
1495
+ if (carried2 !== void 0) {
1496
+ definition = carried2;
1497
+ } else {
1498
+ const got = await draft(term.record.label, term.language, term.record, [{ file: term.location.file }]);
1499
+ if (got === void 0) continue;
1500
+ if ("skip" in got) {
1501
+ entries2.push({ action: "skip", ...base, definition: { status: "missing" }, reason: got.skip });
1502
+ continue;
1503
+ }
1504
+ if (got.status === "below-threshold") {
1505
+ entries2.push({
1506
+ action: "skip",
1507
+ ...base,
1508
+ definition: { status: "below-threshold", confidence: got.confidence, ...modelName === void 0 ? {} : { model: modelName } }
1509
+ });
1510
+ continue;
1511
+ }
1512
+ definition = got.definition;
1513
+ provenance = { confidence: got.confidence };
1514
+ }
1515
+ writes.push({ path, content: await fillInPlace(path, term.location.file, definition, provenance, model) });
1516
+ entries2.push({
1517
+ action: "fill",
1518
+ ...base,
1519
+ definition: provenance === void 0 ? { status: "carried" } : { status: "drafted", confidence: provenance.confidence, ...modelName === void 0 ? {} : { model: modelName } }
1520
+ });
1521
+ }
1522
+ if (crawl && model !== void 0) {
1523
+ const found = [];
1524
+ let spent = false;
1525
+ for (const page of pages) {
1526
+ const type = page.metadata["type"];
1527
+ if (type === "term" || type === "term-set") continue;
1528
+ for (const keyword of keywordsOf(page.metadata["keywords"])) {
1529
+ found.push({
1530
+ file: page.file,
1531
+ label: keyword,
1532
+ ...page.keywordsLine === void 0 ? {} : { line: page.keywordsLine },
1533
+ ...page.language === void 0 ? {} : { language: page.language }
1534
+ });
1535
+ }
1536
+ if (spent) continue;
1537
+ const chunks = splitBody(page.content, chunkChars);
1538
+ for (const [i, chunk] of chunks.entries()) {
1539
+ const user = `Page ${page.file}${chunks.length > 1 ? ` (part ${String(i + 1)} of ${String(chunks.length)})` : ""}
1540
+
1541
+ ${chunk}`;
1542
+ let answer;
1543
+ try {
1544
+ answer = await ask(model, "crawl", CRAWL_SYSTEM, user, CRAWL_SCHEMA, validateCrawl);
1545
+ } catch (error) {
1546
+ opts.onNotice?.(`${page.file}: the model could not read it: ${errorMessage(error)}`);
1547
+ continue;
1548
+ }
1549
+ if (answer === void 0) {
1550
+ spent = true;
1551
+ opts.onNotice?.(`--max-turns reached (${String(maxTurns)}); some pages were not crawled.`);
1552
+ break;
1553
+ }
1554
+ const terms = Array.isArray(answer["terms"]) ? answer["terms"] : [];
1555
+ for (const item of terms) {
1556
+ if (typeof item !== "object" || item === null) continue;
1557
+ const t = item;
1558
+ const label = nonEmpty(t["label"]);
1559
+ if (label === void 0) continue;
1560
+ const definition = nonEmpty(t["definition"]);
1561
+ const line = lineOf(page.content, label);
1562
+ found.push({
1563
+ file: page.file,
1564
+ label,
1565
+ altLabels: strings(t["alt-labels"]),
1566
+ ...definition === void 0 ? {} : { definition },
1567
+ confidence: score(t["confidence"]),
1568
+ ...line === void 0 ? {} : { line },
1569
+ ...page.language === void 0 ? {} : { language: page.language }
1570
+ });
1571
+ }
1572
+ }
1573
+ }
1574
+ for (const candidate of newCandidates(mergeFound(found), known, minPages)) {
1575
+ const concept = { label: candidate.label, from: candidate.from, altLabels: candidate.altLabels, ...candidate.language === void 0 ? {} : { language: candidate.language } };
1576
+ const fields = ["/label", ...candidate.altLabels.length > 0 ? ["/alt-labels"] : [], "/definition"];
1577
+ if (candidate.confidence === void 0 || candidate.definition === void 0) {
1578
+ const got = await draft(candidate.label, candidate.language, {}, candidate.from);
1579
+ if (got === void 0 || "skip" in got || got.status === "below-threshold") {
1580
+ entries2.push({
1581
+ action: "skip",
1582
+ file: displayPath(join3(outDir ?? cwd, `${slugOf(candidate.label)}${ext}`), cwd),
1583
+ id: slugOf(candidate.label),
1584
+ label: candidate.label,
1585
+ ...candidate.language === void 0 ? {} : { language: candidate.language },
1586
+ source: "crawl",
1587
+ from: fromList(candidate.from, cwd),
1588
+ ...got !== void 0 && "skip" in got ? { definition: { status: "missing" }, reason: got.skip } : {
1589
+ definition: {
1590
+ status: "below-threshold",
1591
+ ...got === void 0 ? {} : { confidence: got.confidence },
1592
+ ...modelName === void 0 ? {} : { model: modelName }
1593
+ }
1594
+ }
1595
+ });
1596
+ continue;
1597
+ }
1598
+ await create(concept, "crawl", { drafted: got, fields });
1599
+ continue;
1600
+ }
1601
+ if (candidate.confidence < threshold) {
1602
+ entries2.push({
1603
+ action: "skip",
1604
+ file: displayPath(join3(outDir ?? cwd, `${slugOf(candidate.label)}${ext}`), cwd),
1605
+ id: slugOf(candidate.label),
1606
+ label: candidate.label,
1607
+ ...candidate.language === void 0 ? {} : { language: candidate.language },
1608
+ source: "crawl",
1609
+ from: fromList(candidate.from, cwd),
1610
+ definition: { status: "below-threshold", confidence: candidate.confidence, ...modelName === void 0 ? {} : { model: modelName } }
1611
+ });
1612
+ continue;
1613
+ }
1614
+ await create(concept, "crawl", { drafted: { definition: candidate.definition, confidence: candidate.confidence }, fields });
1615
+ }
1616
+ }
1617
+ if (!dryRun) {
1618
+ for (const { path, content } of writes) {
1619
+ await mkdir(dirname2(path), { recursive: true });
1620
+ await writeFile(path, content, "utf8");
1621
+ }
1622
+ }
1623
+ const count = (action) => entries2.filter((e) => e.action === action).length;
1624
+ return {
1625
+ entries: entries2,
1626
+ summary: {
1627
+ created: count("create"),
1628
+ filled: count("fill"),
1629
+ skipped: count("skip"),
1630
+ withoutDefinition: entries2.filter(
1631
+ (e) => (e.action === "create" || e.action === "skip") && e.definition.status !== "drafted" && e.definition.status !== "carried"
1632
+ ).length,
1633
+ turns
1634
+ },
1635
+ dryRun,
1636
+ threshold
1637
+ };
1638
+ }
1639
+ async function fillInPlace(path, file, definition, provenance, model) {
1640
+ let content;
1641
+ try {
1642
+ content = await readFile(path, "utf8");
1643
+ } catch (error) {
1644
+ throw new TermError(`${file}: could not be read: ${errorMessage(error)}`);
1645
+ }
1646
+ const extractor = extractorForExtension(extname2(path)) ?? extractorByName("markdown");
1647
+ if (extractor?.apply === void 0) throw new TermError(`${file}: manni cannot write its metadata.`);
1648
+ const patch = { definition };
1649
+ if (provenance !== void 0 && model !== void 0) {
1650
+ const held = extractor.extract(content, path).data[META_PROVENANCE_KEY];
1651
+ const merged = mergeMetaProvenance(held, model.identity.model, "fields", [{ name: "/definition", confidence: provenance.confidence }]);
1652
+ if (merged !== void 0) patch[META_PROVENANCE_KEY] = merged.list;
1653
+ }
1654
+ try {
1655
+ return extractor.apply(content, patch, { filePath: path });
1656
+ } catch (error) {
1657
+ throw new TermError(`${file}: ${errorMessage(error)}`);
1658
+ }
1659
+ }
1660
+
910
1661
  // src/term/commands/formats.ts
911
1662
  var FORMATS_FORMATS = ["pretty", "json"];
912
1663
  var DOCUMENT_RENDERS = {
@@ -922,12 +1673,14 @@ var INTERCHANGE_LABELS = {
922
1673
  tbx: "TBX v2",
923
1674
  tbx3: "TBX v3",
924
1675
  skos: "JSON-LD",
1676
+ "skos-ttl": "Turtle",
925
1677
  vale: "style"
926
1678
  };
927
1679
  function rendered(writers, format, construct) {
928
1680
  return writers.some((writer) => {
929
1681
  const render = DOCUMENT_RENDERS[writer.format];
930
- if (render?.input !== format) return false;
1682
+ if (render === void 0) return writer.format === format;
1683
+ if (render.input !== format) return false;
931
1684
  return writer.shapes.some((shape) => render.shapes[shape] === construct);
932
1685
  });
933
1686
  }
@@ -1001,9 +1754,9 @@ async function runGet(opts) {
1001
1754
  }
1002
1755
 
1003
1756
  // src/term/core/lint.ts
1004
- import { mkdtemp, rm, writeFile } from "node:fs/promises";
1757
+ import { mkdtemp, rm, writeFile as writeFile2 } from "node:fs/promises";
1005
1758
  import { tmpdir } from "node:os";
1006
- import { join as join3 } from "node:path";
1759
+ import { join as join4 } from "node:path";
1007
1760
 
1008
1761
  // src/term/core/vale.ts
1009
1762
  import { execFile } from "node:child_process";
@@ -1191,9 +1944,9 @@ async function lintTermSet(set, opts = {}) {
1191
1944
  }
1192
1945
  if (files.length === 0) return [];
1193
1946
  const runVale = opts.runVale ?? runValeJson;
1194
- const dir = await mkdtemp(join3(tmpdir(), "manni-term-lint-"));
1947
+ const dir = await mkdtemp(join4(tmpdir(), "manni-term-lint-"));
1195
1948
  try {
1196
- for (const file of files) await writeFile(join3(dir, file.name), file.content, "utf8");
1949
+ for (const file of files) await writeFile2(join4(dir, file.name), file.content, "utf8");
1197
1950
  const alerts = await runVale([dir], { config: opts.valeConfig, cwd: opts.cwd });
1198
1951
  const findings = [];
1199
1952
  for (const [path, list] of Object.entries(alerts)) {
@@ -1243,9 +1996,9 @@ async function runLint(opts) {
1243
1996
  }
1244
1997
 
1245
1998
  // src/term/commands/write.ts
1246
- import { existsSync, statSync } from "node:fs";
1247
- import { lstat, mkdir, readdir, readFile, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
1248
- import { dirname, extname, join as join4, resolve as resolve2 } from "node:path";
1999
+ import { existsSync as existsSync2, statSync } from "node:fs";
2000
+ import { lstat, mkdir as mkdir2, readdir, readFile as readFile2, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
2001
+ import { dirname as dirname3, extname as extname3, join as join5, resolve as resolve3 } from "node:path";
1249
2002
  var SUGGESTED_SECTION = "*.md";
1250
2003
  var STYLE2 = "Terms";
1251
2004
  function writeFormats(writers = TERM_WRITERS) {
@@ -1267,11 +2020,11 @@ async function filesUnder(dir, into) {
1267
2020
  return;
1268
2021
  }
1269
2022
  for (const entry of entries2) {
1270
- const path = join4(dir, entry.name);
2023
+ const path = join5(dir, entry.name);
1271
2024
  if (entry.isDirectory()) await filesUnder(path, into);
1272
2025
  else if (entry.isFile()) {
1273
2026
  const { size } = await lstat(path);
1274
- into.set(path, size > MAX_EXISTING_FILE_BYTES ? "" : await readFile(path, "utf8"));
2027
+ into.set(path, size > MAX_EXISTING_FILE_BYTES ? "" : await readFile2(path, "utf8"));
1275
2028
  }
1276
2029
  }
1277
2030
  }
@@ -1279,8 +2032,8 @@ async function existingFor(target) {
1279
2032
  const existing = /* @__PURE__ */ new Map();
1280
2033
  if (target.shape === "directory") {
1281
2034
  await filesUnder(target.path, existing);
1282
- } else if (existsSync(target.path) && !isDirectory(target.path)) {
1283
- existing.set(target.path, await readFile(target.path, "utf8"));
2035
+ } else if (existsSync2(target.path) && !isDirectory(target.path)) {
2036
+ existing.set(target.path, await readFile2(target.path, "utf8"));
1284
2037
  }
1285
2038
  return existing;
1286
2039
  }
@@ -1299,23 +2052,23 @@ function droppedFrom(format, shape, readers) {
1299
2052
  async function applyChanges(files, removals, existing, cwd, write) {
1300
2053
  const changes = [];
1301
2054
  for (const file of files) {
1302
- const before = existing.get(file.path) ?? (existsSync(file.path) ? await readFile(file.path, "utf8") : void 0);
2055
+ const before = existing.get(file.path) ?? (existsSync2(file.path) ? await readFile2(file.path, "utf8") : void 0);
1303
2056
  if (before === file.content) continue;
1304
2057
  changes.push({ path: displayPath(file.path, cwd), action: before === void 0 ? "create" : "change" });
1305
2058
  if (write) {
1306
- await mkdir(dirname(file.path), { recursive: true });
1307
- await writeFile2(file.path, file.content, "utf8");
2059
+ await mkdir2(dirname3(file.path), { recursive: true });
2060
+ await writeFile3(file.path, file.content, "utf8");
1308
2061
  }
1309
2062
  }
1310
2063
  for (const path of removals) {
1311
- if (!existsSync(path)) continue;
2064
+ if (!existsSync2(path)) continue;
1312
2065
  changes.push({ path: displayPath(path, cwd), action: "remove" });
1313
2066
  if (write) await rm2(path, { force: true });
1314
2067
  }
1315
2068
  return changes;
1316
2069
  }
1317
2070
  async function runWrite(opts) {
1318
- const cwd = resolve2(opts.cwd ?? process.cwd());
2071
+ const cwd = resolve3(opts.cwd ?? process.cwd());
1319
2072
  const writers = opts.writers ?? TERM_WRITERS;
1320
2073
  const readers = opts.readers ?? TERM_READERS;
1321
2074
  const check = opts.check === true;
@@ -1343,19 +2096,19 @@ async function runWrite(opts) {
1343
2096
  "Vale found no config file. Set tools.vale.config in manni.config.yaml, or pass -o <styles directory>."
1344
2097
  );
1345
2098
  }
1346
- targetPath = resolve2(cwd, resolved.stylesPath);
2099
+ targetPath = resolve3(cwd, resolved.stylesPath);
1347
2100
  if (!Object.values(resolved.baseStyles).some((styles) => styles.includes(STYLE2))) {
1348
2101
  const first = Object.entries(resolved.baseStyles)[0];
1349
2102
  const [section, styles] = first ?? [SUGGESTED_SECTION, []];
1350
2103
  wiring = {
1351
- rootIni: displayPath(resolve2(cwd, resolved.rootIni), cwd),
2104
+ rootIni: displayPath(resolve3(cwd, resolved.rootIni), cwd),
1352
2105
  section,
1353
2106
  styles: [...styles, STYLE2],
1354
2107
  addSection: first === void 0
1355
2108
  };
1356
2109
  }
1357
2110
  } else {
1358
- targetPath = resolve2(cwd, opts.out);
2111
+ targetPath = resolve3(cwd, opts.out);
1359
2112
  }
1360
2113
  const shape = format === "vale" || /[\\/]$/.test(opts.out ?? "") || isDirectory(targetPath) ? "directory" : "file";
1361
2114
  const target = { path: targetPath, shape };
@@ -1368,7 +2121,7 @@ async function runWrite(opts) {
1368
2121
  throw error;
1369
2122
  }
1370
2123
  const changes = await applyChanges(render.files, render.removals, existing, cwd, !check && !dryRun);
1371
- const shown = format === "vale" ? displayPath(join4(targetPath, STYLE2), cwd) : opts.out ?? displayPath(targetPath, cwd);
2124
+ const shown = format === "vale" ? displayPath(join5(targetPath, STYLE2), cwd) : opts.out ?? displayPath(targetPath, cwd);
1372
2125
  return {
1373
2126
  mode: "render",
1374
2127
  format,
@@ -1395,7 +2148,7 @@ function inputFor(content, path, construct, file) {
1395
2148
  return { content, file, path, format: MANIFEST_FORMAT, metadata: {}, lineFor: () => void 0 };
1396
2149
  }
1397
2150
  if (construct === "tbx-entry") return tbxInput(content, file, path);
1398
- const extractor = extractorForExtension(extname(path));
2151
+ const extractor = extractorForExtension(extname3(path));
1399
2152
  if (extractor === void 0) throw new TermError(`${file}: no reader for its extension.`);
1400
2153
  return extractInput(content, file, path, extractor.name);
1401
2154
  }
@@ -1428,6 +2181,11 @@ async function writeInPlace(opts, check, dryRun) {
1428
2181
  if (path === void 0) {
1429
2182
  throw new TermError(`${term.location.file} has nowhere to write back to. Pass -f <format> -o <path>.`);
1430
2183
  }
2184
+ if (construct === "skos") {
2185
+ throw new TermError(
2186
+ `${displayPath(term.location.file, cwd)} is SKOS and is not rewritten in place; render it with -f skos or -f skos-ttl.`
2187
+ );
2188
+ }
1431
2189
  const reader = readerForConstruct(construct, readers);
1432
2190
  if (reader?.apply === void 0) {
1433
2191
  const name = reader?.label ?? construct;
@@ -1445,7 +2203,7 @@ async function writeInPlace(opts, check, dryRun) {
1445
2203
  for (const [path, { file, constructs }] of byPath) {
1446
2204
  let original;
1447
2205
  try {
1448
- original = await readFile(path, "utf8");
2206
+ original = await readFile2(path, "utf8");
1449
2207
  } catch (error) {
1450
2208
  throw new TermError(`${file}: could not be read: ${errorMessage(error)}`);
1451
2209
  }
@@ -1489,16 +2247,28 @@ function renderListCsv(terms) {
1489
2247
  var INFORMATION_URI = "https://hawkeyexl.github.io/manni/term/";
1490
2248
  var RULES_URI = "https://hawkeyexl.github.io/manni/term/reference/rules/";
1491
2249
  var RULE_DESCRIPTIONS = {
1492
- "undefined-term": "A page's concepts: names a label no entry claims as its preferred label.",
2250
+ "undefined-term": "A page's concepts: names no entry, by label, id or alt-label.",
1493
2251
  "duplicate-id": "Two entries share an id.",
1494
2252
  "label-collision": "Two entries claim the same preferred label, ignoring case.",
1495
2253
  "alt-label-collision": "An entry's alt-label is another entry's preferred label, ignoring case.",
1496
2254
  "dangling-reference": "A value of broader, narrower, related-terms or see names no entry, by label or by id.",
1497
2255
  "broader-cycle": "A chain of broader returns to where it started.",
1498
2256
  "see-not-empty": "An entry with see also carries a definition.",
2257
+ "missing-definition": "An entry has neither a definition nor see.",
2258
+ "conflicting-matches": "One IRI is listed under two of an entry's match kinds.",
1499
2259
  "asymmetric-hierarchy": "A names B as broader, and B omits A from narrower, or the reverse.",
2260
+ "alt-label-reference": "A page's concepts: names an entry by one of its alt-labels.",
1500
2261
  "abstract-too-long": "An abstract is longer than term.abstractMaxLength.",
1501
- "unused-term": "No page's concepts: names the entry's preferred label."
2262
+ "unused-term": "No page's concepts: names the entry.",
2263
+ "hierarchy-outside-termbase": "A page's graph: block gives a term a broader, narrower or related concept its own entry does not list.",
2264
+ "label-overlap": "A hidden-label or alt-label repeats one of the entry's own names, or a hidden-label is another entry's label or alt-label.",
2265
+ "asymmetric-related": "A names B in related-terms, and B omits A.",
2266
+ "related-in-hierarchy": "A related term is also broader or narrower than the entry, at any depth.",
2267
+ "ambiguous-alt-label": "Two entries share an alt-label, ignoring case.",
2268
+ "deprecated-label": "The entry's label is deprecated or superseded in its designations.",
2269
+ "related-siblings": "Two related terms share a broader term.",
2270
+ "orphan-term": "An entry has no broader, narrower or related term, in a termbase with a hierarchy.",
2271
+ "keyword-candidate": "A free keyword is on several pages and names no term."
1502
2272
  };
1503
2273
  var PROSE_PREFIX = `${RULE_ID_PREFIX}/prose/`;
1504
2274
  var FIELD_LABEL = new RegExp(`^(?:\\(root\\)|/(?:${TERM_FIELDS.join("|")})) `);
@@ -1535,21 +2305,53 @@ function renderFindingsJunit(report) {
1535
2305
  );
1536
2306
  }
1537
2307
 
1538
- // src/term/commands/labels.ts
1539
- async function termLabels(request) {
1540
- const run = await resolveTermRun({
1541
- cwd: request.cwd,
1542
- inputs: [],
1543
- ...request.configPath === void 0 ? {} : { configPath: request.configPath },
1544
- ...request.noConfig === true ? { noConfig: true } : {}
1545
- });
1546
- if (run.inputs.length === 0 && run.manifests.length === 0) return [];
1547
- const set = await loadSet(run, { inputs: [], allowEmpty: true });
1548
- return set.terms.map((term) => ({ label: term.record.label, id: term.id }));
2308
+ // src/term/reporters/fill.ts
2309
+ var DONE = { create: "created", fill: "filled", skip: "skipped", exists: "exists" };
2310
+ var WOULD = { create: "would create", fill: "would fill", skip: "skipped", exists: "exists" };
2311
+ function detail(entry, threshold) {
2312
+ if (entry.reason !== void 0) return entry.reason;
2313
+ const { status, confidence } = entry.definition;
2314
+ if (entry.action === "exists") return "the file is already there";
2315
+ switch (status) {
2316
+ case "carried":
2317
+ return "definition from graph: block";
2318
+ case "drafted":
2319
+ return `definition drafted (${(confidence ?? 0).toFixed(2)})`;
2320
+ case "below-threshold": {
2321
+ const under = `confidence ${(confidence ?? 0).toFixed(2)} is under ${String(threshold)}`;
2322
+ return entry.action === "create" ? `stub, ${under}` : under;
2323
+ }
2324
+ case "missing":
2325
+ return "stub, no definition";
2326
+ }
2327
+ }
2328
+ function renderFillPretty(report) {
2329
+ const words = report.dryRun ? WOULD : DONE;
2330
+ const actionWidth = Math.max(0, ...report.entries.map((e) => words[e.action].length));
2331
+ const fileWidth = Math.max(0, ...report.entries.map((e) => e.file.length)) + 3;
2332
+ const labelWidth = Math.max(0, ...report.entries.map((e) => e.label.length)) + 3;
2333
+ const lines = report.entries.map(
2334
+ (e) => `${words[e.action].padEnd(actionWidth)} ${e.file.padEnd(fileWidth)}${e.label.padEnd(labelWidth)}${detail(e, report.threshold)}`
2335
+ );
2336
+ const { created, filled, skipped, withoutDefinition } = report.summary;
2337
+ const skips = skipped > 0 ? `, ${String(skipped)} skipped` : "";
2338
+ lines.push(
2339
+ report.dryRun ? `${plural(created, "term")} would be created, ${String(filled)} would be filled, ${String(withoutDefinition)} left without a definition${skips}` : `${plural(created, "term")} created, ${String(filled)} filled, ${String(withoutDefinition)} left without a definition${skips}`
2340
+ );
2341
+ return lines.join("\n");
2342
+ }
2343
+ function renderFillJson(report) {
2344
+ return JSON.stringify({ entries: report.entries, summary: report.summary }, null, 2);
1549
2345
  }
1550
2346
 
1551
2347
  // src/term/cli.ts
1552
- registerTermLabelSource(termLabels);
2348
+ function numeric(name, value, min, max, integer = false) {
2349
+ if (value === void 0) return;
2350
+ if (!Number.isFinite(value) || value < min || value > max || integer && !Number.isInteger(value)) {
2351
+ const kind = integer ? "a whole number" : "a number";
2352
+ throw new TermError(`${name} must be ${kind} between ${String(min)} and ${String(max)}, got ${String(value)}.`);
2353
+ }
2354
+ }
1553
2355
  function colorFor(options) {
1554
2356
  return shouldColor({ noColor: !options.color, isTTY: process.stdout.isTTY });
1555
2357
  }
@@ -1574,11 +2376,11 @@ function print(text) {
1574
2376
  process.stdout.write(`${text}
1575
2377
  `);
1576
2378
  }
1577
- function renderFindings(report, format, options, references2) {
2379
+ function renderFindings(report, format, options, references) {
1578
2380
  let text;
1579
2381
  switch (format) {
1580
2382
  case "pretty":
1581
- text = renderFindingsPretty(report, { color: colorFor(options), references: references2 });
2383
+ text = renderFindingsPretty(report, { color: colorFor(options), references });
1582
2384
  break;
1583
2385
  case "json":
1584
2386
  text = renderFindingsJson(report);
@@ -1703,6 +2505,44 @@ function buildProgram() {
1703
2505
  fail(err);
1704
2506
  }
1705
2507
  });
2508
+ withInputs(
2509
+ program.command("fill").description("Create term pages for the concepts pages name, and draft missing definitions").argument("[paths...]", "files, directories, or globs to read (use - for stdin)")
2510
+ ).option("-o, --out <dir>", "directory for new term pages").option("--crawl", "also ask the model for terms that page bodies and keywords use").option("--offline", "no network egress: only a model already downloaded, never a remote provider").option("--provider <name>", "provider: auto (default), anthropic, openai, claude-cli, llama-cpp").option("--model <model>", "model override; needs a named provider, from here or config").option("--local", LOCAL_FLAG_HELP).option("--confidence <n>", "minimum confidence to write a definition (0-1)", parseFloat).option("--max-turns <n>", "stop after this many inference calls", parseFloat).option("--chunk-chars <n>", "characters of page per call under --crawl (default 12000)", parseFloat).option("--no-cache", "bypass the answer cache").option("--dry-run", "write nothing; print what would change").option("-f, --format <format>", `output: ${FILL_FORMATS.join(" | ")}`, "pretty").addHelpText(
2511
+ "after",
2512
+ [
2513
+ "",
2514
+ "Examples:",
2515
+ " manni term fill --offline --dry-run # what is missing, nothing sent",
2516
+ " manni term fill # pages and drafted definitions",
2517
+ " manni term fill --crawl -o docs/glossary/ # terms no metadata named",
2518
+ " manni term fill --dry-run -f json # for a script"
2519
+ ].join("\n")
2520
+ ).action(async (paths, options) => {
2521
+ try {
2522
+ const format = formatChoice(options.format, FILL_FORMATS);
2523
+ numeric("--confidence", options.confidence, 0, 1);
2524
+ numeric("--max-turns", options.maxTurns, 1, Number.MAX_SAFE_INTEGER, true);
2525
+ numeric("--chunk-chars", options.chunkChars, 1, Number.MAX_SAFE_INTEGER, true);
2526
+ const report = await runFill({
2527
+ ...await coreOptions(paths, options),
2528
+ ...options.out === void 0 ? {} : { out: options.out },
2529
+ ...options.crawl === true ? { crawl: true } : {},
2530
+ ...options.offline === true ? { offline: true } : {},
2531
+ ...options.provider === void 0 ? {} : { provider: options.provider },
2532
+ ...options.model === void 0 ? {} : { model: options.model },
2533
+ ...options.local === true ? { local: true } : {},
2534
+ ...options.confidence === void 0 ? {} : { confidence: options.confidence },
2535
+ ...options.maxTurns === void 0 ? {} : { maxTurns: options.maxTurns },
2536
+ ...options.chunkChars === void 0 ? {} : { chunkChars: options.chunkChars },
2537
+ ...options.cache ? {} : { noCache: true },
2538
+ ...options.dryRun === true ? { dryRun: true } : {}
2539
+ });
2540
+ print(format === "json" ? renderFillJson(report) : renderFillPretty(report));
2541
+ process.exitCode = 0;
2542
+ } catch (err) {
2543
+ fail(err);
2544
+ }
2545
+ });
1706
2546
  program.command("formats").description("List the constructs read and written, per format").option("-f, --format <format>", `output: ${FORMATS_FORMATS.join(" | ")}`, "pretty").action((options) => {
1707
2547
  try {
1708
2548
  const format = formatChoice(options.format, FORMATS_FORMATS);
@@ -1720,4 +2560,4 @@ export {
1720
2560
  TermError,
1721
2561
  buildProgram
1722
2562
  };
1723
- //# sourceMappingURL=term-CQAGNG3Q.js.map
2563
+ //# sourceMappingURL=term-PLJEYJQV.js.map