@hawkeyexl/manni 4.5.0 → 4.7.0

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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/batch-U6S2JUUN.js +41 -0
  3. package/dist/build-4RN6WBCP.js +32 -0
  4. package/dist/calibrate-6VIZYR4L.js +36 -0
  5. package/dist/capture-DP3NXAZE.js +34 -0
  6. package/dist/{check-RQIIIURI.js → check-ERVNGKLC.js} +13 -14
  7. package/dist/check-IWHUPAZM.js +886 -0
  8. package/dist/check-IWHUPAZM.js.map +1 -0
  9. package/dist/{check-ESNS7ZBC.js → check-OAJWC3WD.js} +7 -5
  10. package/dist/check-STHXZIZO.js +26 -0
  11. package/dist/{chunk-TA42STP7.js → chunk-2ZWTSRE5.js} +4 -4
  12. package/dist/{chunk-F2OVHJNC.js → chunk-4Z2MN5FR.js} +11 -11
  13. package/dist/{chunk-HVFR66GQ.js → chunk-5UB47BEV.js} +3280 -283
  14. package/dist/chunk-5UB47BEV.js.map +1 -0
  15. package/dist/{chunk-TCC737IS.js → chunk-5VWDIWOH.js} +4 -4
  16. package/dist/{chunk-B7XUEQF3.js → chunk-6KKZXB2O.js} +7 -5
  17. package/dist/{chunk-B7XUEQF3.js.map → chunk-6KKZXB2O.js.map} +1 -1
  18. package/dist/{chunk-ELZ2IIOF.js → chunk-6URSCTTX.js} +2 -2
  19. package/dist/{chunk-K3U5F2QT.js → chunk-6VDBP5UV.js} +12 -12
  20. package/dist/chunk-7EL5LLKD.js +233 -0
  21. package/dist/chunk-7EL5LLKD.js.map +1 -0
  22. package/dist/{chunk-C3KI45RF.js → chunk-7XZ6INKO.js} +4 -4
  23. package/dist/{chunk-ZX43SRZR.js → chunk-AMEILOVV.js} +8 -6
  24. package/dist/{chunk-ZX43SRZR.js.map → chunk-AMEILOVV.js.map} +1 -1
  25. package/dist/{chunk-SNEHX4VE.js → chunk-B5CMM57M.js} +2 -2
  26. package/dist/chunk-BWCWTHYS.js +146 -0
  27. package/dist/chunk-BWCWTHYS.js.map +1 -0
  28. package/dist/{chunk-QLUMKWQQ.js → chunk-C2TJG5KV.js} +10 -6
  29. package/dist/{chunk-QLUMKWQQ.js.map → chunk-C2TJG5KV.js.map} +1 -1
  30. package/dist/{chunk-GAZFKZHM.js → chunk-CEVU3GFF.js} +6 -6
  31. package/dist/chunk-CI55ABCK.js +502 -0
  32. package/dist/chunk-CI55ABCK.js.map +1 -0
  33. package/dist/{chunk-QCBICNKC.js → chunk-CR3HZERW.js} +202 -54
  34. package/dist/chunk-CR3HZERW.js.map +1 -0
  35. package/dist/chunk-CU57HT2E.js +116 -0
  36. package/dist/chunk-CU57HT2E.js.map +1 -0
  37. package/dist/chunk-CWXZ2MRT.js +222 -0
  38. package/dist/chunk-CWXZ2MRT.js.map +1 -0
  39. package/dist/chunk-D2LBN44V.js +134 -0
  40. package/dist/chunk-D2LBN44V.js.map +1 -0
  41. package/dist/chunk-D6RO54QD.js +674 -0
  42. package/dist/chunk-D6RO54QD.js.map +1 -0
  43. package/dist/{chunk-52PDIZKV.js → chunk-ECVQNGTH.js} +3 -3
  44. package/dist/chunk-FQGLRJGX.js +174 -0
  45. package/dist/chunk-FQGLRJGX.js.map +1 -0
  46. package/dist/{chunk-NGK3N6F2.js → chunk-GCC52YZD.js} +3 -3
  47. package/dist/chunk-HX44GB4Z.js +30 -0
  48. package/dist/chunk-HX44GB4Z.js.map +1 -0
  49. package/dist/{chunk-NN4ASVTY.js → chunk-IIFADWWI.js} +4 -4
  50. package/dist/{chunk-OIZ3XMKB.js → chunk-IOL74S4J.js} +4 -4
  51. package/dist/{chunk-UK2I3ACY.js → chunk-IZBBXKMJ.js} +4 -4
  52. package/dist/{chunk-YA63PVWI.js → chunk-K52CS4KT.js} +12 -10
  53. package/dist/{chunk-YA63PVWI.js.map → chunk-K52CS4KT.js.map} +1 -1
  54. package/dist/{chunk-7OQAU4EA.js → chunk-LDKIIZDW.js} +16 -12
  55. package/dist/{chunk-7OQAU4EA.js.map → chunk-LDKIIZDW.js.map} +1 -1
  56. package/dist/{chunk-QY3DOZMS.js → chunk-LONRQBGV.js} +4 -4
  57. package/dist/{chunk-EL2BZTDL.js → chunk-LXJEAV2V.js} +13 -11
  58. package/dist/{chunk-EL2BZTDL.js.map → chunk-LXJEAV2V.js.map} +1 -1
  59. package/dist/{chunk-XWFNO5PO.js → chunk-MIBWI5H7.js} +3 -3
  60. package/dist/{chunk-527HHQPS.js → chunk-MSMB6XOS.js} +6 -4
  61. package/dist/{chunk-527HHQPS.js.map → chunk-MSMB6XOS.js.map} +1 -1
  62. package/dist/{chunk-C6HZ6C5T.js → chunk-NIFEEIGQ.js} +2 -2
  63. package/dist/{chunk-JQU7FHYH.js → chunk-NZ6TNSCU.js} +10 -10
  64. package/dist/{chunk-3R5Y3XOL.js → chunk-OOEMKOX6.js} +29 -591
  65. package/dist/chunk-OOEMKOX6.js.map +1 -0
  66. package/dist/{chunk-MZC62HPZ.js → chunk-PAOVVHQX.js} +2 -2
  67. package/dist/chunk-PNX43DYW.js +849 -0
  68. package/dist/chunk-PNX43DYW.js.map +1 -0
  69. package/dist/chunk-QCHVR4ZM.js +286 -0
  70. package/dist/chunk-QCHVR4ZM.js.map +1 -0
  71. package/dist/{chunk-SJO2FTPG.js → chunk-QP5X66TO.js} +73 -1304
  72. package/dist/chunk-QP5X66TO.js.map +1 -0
  73. package/dist/{chunk-HQFVJDEN.js → chunk-QQNPVW3J.js} +19 -19
  74. package/dist/chunk-TPVOOTMN.js +532 -0
  75. package/dist/chunk-TPVOOTMN.js.map +1 -0
  76. package/dist/{chunk-IA7BMIPE.js → chunk-UZKQSWHJ.js} +2 -2
  77. package/dist/chunk-WQWKYAAK.js +86 -0
  78. package/dist/chunk-WQWKYAAK.js.map +1 -0
  79. package/dist/{chunk-CP4ZM43V.js → chunk-WTEILBKC.js} +2 -2
  80. package/dist/{chunk-LJ2RDH3F.js → chunk-XG6PVB5S.js} +1 -23
  81. package/dist/chunk-XG6PVB5S.js.map +1 -0
  82. package/dist/{chunk-Q35YIDBV.js → chunk-XKBEHKWO.js} +29 -264
  83. package/dist/chunk-XKBEHKWO.js.map +1 -0
  84. package/dist/{chunk-BOIF2XGG.js → chunk-XXDXIIQ4.js} +2 -2
  85. package/dist/{chunk-6XTQDFGP.js → chunk-YSCZL4U5.js} +3 -3
  86. package/dist/{chunk-6XTQDFGP.js.map → chunk-YSCZL4U5.js.map} +1 -1
  87. package/dist/{chunk-7ZUCEMCY.js → chunk-ZEXGGGLW.js} +9 -11
  88. package/dist/{chunk-7ZUCEMCY.js.map → chunk-ZEXGGGLW.js.map} +1 -1
  89. package/dist/{chunk-DX32P2DT.js → chunk-ZKAKA54B.js} +2 -2
  90. package/dist/{chunk-TVIX653Q.js → chunk-ZKCNPKUO.js} +4 -4
  91. package/dist/{chunk-DE7JSWXV.js → chunk-ZNE25EAR.js} +8 -6
  92. package/dist/{chunk-DE7JSWXV.js.map → chunk-ZNE25EAR.js.map} +1 -1
  93. package/dist/{chunk-FLF6AECQ.js → chunk-ZPP75QWG.js} +17 -15
  94. package/dist/{chunk-FLF6AECQ.js.map → chunk-ZPP75QWG.js.map} +1 -1
  95. package/dist/{cli-PRZHQ3QB.js → cli-37SRAYNE.js} +14 -15
  96. package/dist/{cli-PRZHQ3QB.js.map → cli-37SRAYNE.js.map} +1 -1
  97. package/dist/{cli-TYGOHJOJ.js → cli-HXWYUKGJ.js} +225 -58
  98. package/dist/cli-HXWYUKGJ.js.map +1 -0
  99. package/dist/{cli-HUIMNJT6.js → cli-IRHPPUFJ.js} +19 -20
  100. package/dist/{cli-HUIMNJT6.js.map → cli-IRHPPUFJ.js.map} +1 -1
  101. package/dist/{cli-6PGVHP7Y.js → cli-KIID535Y.js} +17 -19
  102. package/dist/{cli-6PGVHP7Y.js.map → cli-KIID535Y.js.map} +1 -1
  103. package/dist/{cli-AAG3N4NB.js → cli-MTDGQIIV.js} +17 -18
  104. package/dist/{cli-AAG3N4NB.js.map → cli-MTDGQIIV.js.map} +1 -1
  105. package/dist/{cli-E3H6ZP4I.js → cli-NM6FZ54R.js} +5 -3
  106. package/dist/{cli-E3H6ZP4I.js.map → cli-NM6FZ54R.js.map} +1 -1
  107. package/dist/{cli-MHTYPVOD.js → cli-XIODOEUG.js} +113 -20
  108. package/dist/{cli-MHTYPVOD.js.map → cli-XIODOEUG.js.map} +1 -1
  109. package/dist/{cli-YW6VWBHX.js → cli-YL3IDR52.js} +10 -10
  110. package/dist/{cli-QKIJOXGW.js → cli-ZQUJYQBA.js} +17 -17
  111. package/dist/cli.js +11 -11
  112. package/dist/config-O6UBGEDK.js +26 -0
  113. package/dist/conformance-ALLPNGEQ.js +18 -0
  114. package/dist/docmeta.js +9 -9
  115. package/dist/github-UCYLM3DR.js +26 -0
  116. package/dist/github-VEJFO6JJ.js +31 -0
  117. package/dist/host-6GURH5HE.js +23 -0
  118. package/dist/index.d.ts +72 -4
  119. package/dist/index.js +176 -166
  120. package/dist/index.js.map +1 -1
  121. package/dist/{json-4DCKDGUV.js → json-6F52FSXZ.js} +12 -13
  122. package/dist/lint-X2GNINK6.js +29 -0
  123. package/dist/list-DP3O3CWB.js +30 -0
  124. package/dist/list-P77RZFZF.js +28 -0
  125. package/dist/{page-QEDB7EVU.js → page-WQCMBNRD.js} +11 -12
  126. package/dist/prepare-52QOK7M4.js +155 -0
  127. package/dist/prepare-52QOK7M4.js.map +1 -0
  128. package/dist/{pretty-SQX33UM2.js → pretty-5MMMNSWF.js} +13 -14
  129. package/dist/{pretty-5DGEBZSV.js → pretty-H4DQREMW.js} +12 -13
  130. package/dist/provider-AMGRDY6V.js +34 -0
  131. package/dist/release-CTYRHZL4.js +36 -0
  132. package/dist/release-CTYRHZL4.js.map +1 -0
  133. package/dist/{reporters-YELDDYJD.js → reporters-SU3VUKKX.js} +7 -5
  134. package/dist/{reporters-OHSI3RMV.js → reporters-WIHBEMPG.js} +11 -12
  135. package/dist/reporters-WIHBEMPG.js.map +1 -0
  136. package/dist/run-L2DWJ26K.js +32 -0
  137. package/dist/run-L2DWJ26K.js.map +1 -0
  138. package/dist/{term-2WMDZ4PY.js → term-PJIJQZNF.js} +16 -17
  139. package/dist/{term-2WMDZ4PY.js.map → term-PJIJQZNF.js.map} +1 -1
  140. package/dist/validate-XCDSPURG.js +17 -0
  141. package/dist/validate-XCDSPURG.js.map +1 -0
  142. package/package.json +2 -2
  143. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  144. package/plugin/manni/hooks/hooks.json +47 -0
  145. package/dist/batch-GOE3UXOD.js +0 -36
  146. package/dist/build-M7BMEHL2.js +0 -33
  147. package/dist/calibrate-6RRAILUY.js +0 -31
  148. package/dist/capture-RJPQ6B4N.js +0 -32
  149. package/dist/check-BQD64X3N.js +0 -27
  150. package/dist/chunk-3R5Y3XOL.js.map +0 -1
  151. package/dist/chunk-3YHAYXBC.js +0 -164
  152. package/dist/chunk-3YHAYXBC.js.map +0 -1
  153. package/dist/chunk-HVFR66GQ.js.map +0 -1
  154. package/dist/chunk-LJ2RDH3F.js.map +0 -1
  155. package/dist/chunk-NAZRLJAK.js +0 -3090
  156. package/dist/chunk-NAZRLJAK.js.map +0 -1
  157. package/dist/chunk-Q35YIDBV.js.map +0 -1
  158. package/dist/chunk-QCBICNKC.js.map +0 -1
  159. package/dist/chunk-SJO2FTPG.js.map +0 -1
  160. package/dist/chunk-TU2WUBVZ.js +0 -2
  161. package/dist/cli-TYGOHJOJ.js.map +0 -1
  162. package/dist/github-3WMSTNTK.js +0 -32
  163. package/dist/github-OXSJQ4PS.js +0 -27
  164. package/dist/lint-YDHVVZHT.js +0 -30
  165. package/dist/list-3ZO2NIYO.js +0 -31
  166. package/dist/list-EJH6VAOW.js +0 -29
  167. package/dist/run-IP6NZHAG.js +0 -33
  168. package/dist/validate-G6HH3YXL.js +0 -16
  169. /package/dist/{batch-GOE3UXOD.js.map → batch-U6S2JUUN.js.map} +0 -0
  170. /package/dist/{build-M7BMEHL2.js.map → build-4RN6WBCP.js.map} +0 -0
  171. /package/dist/{calibrate-6RRAILUY.js.map → calibrate-6VIZYR4L.js.map} +0 -0
  172. /package/dist/{capture-RJPQ6B4N.js.map → capture-DP3NXAZE.js.map} +0 -0
  173. /package/dist/{check-BQD64X3N.js.map → check-ERVNGKLC.js.map} +0 -0
  174. /package/dist/{check-ESNS7ZBC.js.map → check-OAJWC3WD.js.map} +0 -0
  175. /package/dist/{check-RQIIIURI.js.map → check-STHXZIZO.js.map} +0 -0
  176. /package/dist/{chunk-TA42STP7.js.map → chunk-2ZWTSRE5.js.map} +0 -0
  177. /package/dist/{chunk-F2OVHJNC.js.map → chunk-4Z2MN5FR.js.map} +0 -0
  178. /package/dist/{chunk-TCC737IS.js.map → chunk-5VWDIWOH.js.map} +0 -0
  179. /package/dist/{chunk-ELZ2IIOF.js.map → chunk-6URSCTTX.js.map} +0 -0
  180. /package/dist/{chunk-K3U5F2QT.js.map → chunk-6VDBP5UV.js.map} +0 -0
  181. /package/dist/{chunk-C3KI45RF.js.map → chunk-7XZ6INKO.js.map} +0 -0
  182. /package/dist/{chunk-SNEHX4VE.js.map → chunk-B5CMM57M.js.map} +0 -0
  183. /package/dist/{chunk-GAZFKZHM.js.map → chunk-CEVU3GFF.js.map} +0 -0
  184. /package/dist/{chunk-52PDIZKV.js.map → chunk-ECVQNGTH.js.map} +0 -0
  185. /package/dist/{chunk-NGK3N6F2.js.map → chunk-GCC52YZD.js.map} +0 -0
  186. /package/dist/{chunk-NN4ASVTY.js.map → chunk-IIFADWWI.js.map} +0 -0
  187. /package/dist/{chunk-OIZ3XMKB.js.map → chunk-IOL74S4J.js.map} +0 -0
  188. /package/dist/{chunk-UK2I3ACY.js.map → chunk-IZBBXKMJ.js.map} +0 -0
  189. /package/dist/{chunk-QY3DOZMS.js.map → chunk-LONRQBGV.js.map} +0 -0
  190. /package/dist/{chunk-XWFNO5PO.js.map → chunk-MIBWI5H7.js.map} +0 -0
  191. /package/dist/{chunk-C6HZ6C5T.js.map → chunk-NIFEEIGQ.js.map} +0 -0
  192. /package/dist/{chunk-JQU7FHYH.js.map → chunk-NZ6TNSCU.js.map} +0 -0
  193. /package/dist/{chunk-MZC62HPZ.js.map → chunk-PAOVVHQX.js.map} +0 -0
  194. /package/dist/{chunk-HQFVJDEN.js.map → chunk-QQNPVW3J.js.map} +0 -0
  195. /package/dist/{chunk-IA7BMIPE.js.map → chunk-UZKQSWHJ.js.map} +0 -0
  196. /package/dist/{chunk-CP4ZM43V.js.map → chunk-WTEILBKC.js.map} +0 -0
  197. /package/dist/{chunk-BOIF2XGG.js.map → chunk-XXDXIIQ4.js.map} +0 -0
  198. /package/dist/{chunk-DX32P2DT.js.map → chunk-ZKAKA54B.js.map} +0 -0
  199. /package/dist/{chunk-TVIX653Q.js.map → chunk-ZKCNPKUO.js.map} +0 -0
  200. /package/dist/{chunk-TU2WUBVZ.js.map → cli-YL3IDR52.js.map} +0 -0
  201. /package/dist/{cli-QKIJOXGW.js.map → cli-ZQUJYQBA.js.map} +0 -0
  202. /package/dist/{cli-YW6VWBHX.js.map → config-O6UBGEDK.js.map} +0 -0
  203. /package/dist/{github-3WMSTNTK.js.map → conformance-ALLPNGEQ.js.map} +0 -0
  204. /package/dist/{github-OXSJQ4PS.js.map → github-UCYLM3DR.js.map} +0 -0
  205. /package/dist/{json-4DCKDGUV.js.map → github-VEJFO6JJ.js.map} +0 -0
  206. /package/dist/{lint-YDHVVZHT.js.map → host-6GURH5HE.js.map} +0 -0
  207. /package/dist/{list-3ZO2NIYO.js.map → json-6F52FSXZ.js.map} +0 -0
  208. /package/dist/{list-EJH6VAOW.js.map → lint-X2GNINK6.js.map} +0 -0
  209. /package/dist/{page-QEDB7EVU.js.map → list-DP3O3CWB.js.map} +0 -0
  210. /package/dist/{pretty-5DGEBZSV.js.map → list-P77RZFZF.js.map} +0 -0
  211. /package/dist/{pretty-SQX33UM2.js.map → page-WQCMBNRD.js.map} +0 -0
  212. /package/dist/{reporters-OHSI3RMV.js.map → pretty-5MMMNSWF.js.map} +0 -0
  213. /package/dist/{reporters-YELDDYJD.js.map → pretty-H4DQREMW.js.map} +0 -0
  214. /package/dist/{run-IP6NZHAG.js.map → provider-AMGRDY6V.js.map} +0 -0
  215. /package/dist/{validate-G6HH3YXL.js.map → reporters-SU3VUKKX.js.map} +0 -0
@@ -3,26 +3,26 @@ import {
3
3
  runAdd,
4
4
  runRemove,
5
5
  runUpdate
6
- } from "./chunk-7ZUCEMCY.js";
6
+ } from "./chunk-ZEXGGGLW.js";
7
7
  import {
8
8
  runCheck
9
- } from "./chunk-JQU7FHYH.js";
9
+ } from "./chunk-NZ6TNSCU.js";
10
10
  import {
11
11
  findingMessage,
12
12
  renderCheckGithub
13
- } from "./chunk-XWFNO5PO.js";
13
+ } from "./chunk-MIBWI5H7.js";
14
14
  import {
15
15
  renderCheckPretty,
16
16
  renderRemovePretty,
17
17
  renderUpdatePretty
18
- } from "./chunk-NGK3N6F2.js";
18
+ } from "./chunk-GCC52YZD.js";
19
19
  import {
20
20
  errorSite,
21
21
  shortCommit,
22
22
  shortLine,
23
23
  shortPin,
24
24
  shortSrc
25
- } from "./chunk-TA42STP7.js";
25
+ } from "./chunk-2ZWTSRE5.js";
26
26
  import {
27
27
  renderCheckJson,
28
28
  renderRemoveJson,
@@ -35,25 +35,21 @@ import {
35
35
  asCiteError,
36
36
  isCiteRule,
37
37
  spellSource
38
- } from "./chunk-UK2I3ACY.js";
38
+ } from "./chunk-IZBBXKMJ.js";
39
39
  import "./chunk-IKEWBMCN.js";
40
- import "./chunk-TU2WUBVZ.js";
41
- import "./chunk-TVIX653Q.js";
40
+ import "./chunk-ZKCNPKUO.js";
42
41
  import {
43
42
  terminalConfirm
44
- } from "./chunk-QCBICNKC.js";
45
- import "./chunk-3YHAYXBC.js";
43
+ } from "./chunk-CR3HZERW.js";
46
44
  import {
47
45
  collect,
48
46
  configOption,
49
47
  explicitFalse,
50
48
  readStdin,
51
49
  reportConfig,
52
- splitList
53
- } from "./chunk-NAZRLJAK.js";
54
- import {
50
+ splitList,
55
51
  splitPageArgument
56
- } from "./chunk-HVFR66GQ.js";
52
+ } from "./chunk-5UB47BEV.js";
57
53
  import {
58
54
  COMMON_FORMAT_LIST,
59
55
  OMITTED_WHEN_CLEAN,
@@ -63,10 +59,10 @@ import {
63
59
  isReportFormat,
64
60
  renderJunit,
65
61
  renderSarif
66
- } from "./chunk-TCC737IS.js";
62
+ } from "./chunk-5VWDIWOH.js";
67
63
  import {
68
64
  STDIN_TOKEN
69
- } from "./chunk-527HHQPS.js";
65
+ } from "./chunk-MSMB6XOS.js";
70
66
  import {
71
67
  fail
72
68
  } from "./chunk-YEUYKR62.js";
@@ -74,12 +70,14 @@ import {
74
70
  shouldColor
75
71
  } from "./chunk-RNVYGWIC.js";
76
72
  import "./chunk-MNH7QO4Z.js";
73
+ import "./chunk-XKBEHKWO.js";
77
74
  import {
78
75
  notice
79
- } from "./chunk-Q35YIDBV.js";
76
+ } from "./chunk-HX44GB4Z.js";
77
+ import "./chunk-QCHVR4ZM.js";
80
78
  import {
81
79
  package_default
82
- } from "./chunk-6XTQDFGP.js";
80
+ } from "./chunk-YSCZL4U5.js";
83
81
  import "./chunk-OWBRDNRZ.js";
84
82
  import "./chunk-G3T47CFV.js";
85
83
  import "./chunk-2H7UOFLK.js";
@@ -549,4 +547,4 @@ export {
549
547
  colorFor,
550
548
  splitPageArgument2 as splitPageArgument
551
549
  };
552
- //# sourceMappingURL=cli-6PGVHP7Y.js.map
550
+ //# sourceMappingURL=cli-KIID535Y.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cite/cli.ts","../src/cite/reporters/sarif.ts","../src/cite/reporters/junit.ts"],"sourcesContent":["/**\n * The `cite` domain's commander program. Mounted by `src/cli.ts` under\n * `manni cite`; no entry point of its own. Grammar per proposal 0034: verbs are\n * `check`, `add`, `update`, `remove`; there is no default subcommand.\n *\n * Follows clig.dev as meta's does: primary output to stdout, diagnostics to\n * stderr, colour only on a TTY and never under `NO_COLOR`/`--no-color`, exit\n * `0` clean, `1` an error-severity finding, `2` operational/usage.\n */\nimport { Command, Option } from \"commander\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport {\n collect,\n configOption,\n explicitFalse,\n readStdin,\n reportConfig,\n splitList,\n} from \"../shared/cli-options.js\";\nimport { shouldColor } from \"../shared/color.js\";\nimport { splitPageArgument as splitSharedPageArgument } from \"../shared/pin.js\";\nimport { terminalConfirm } from \"../shared/prompt.js\";\nimport { fail } from \"../shared/run.js\";\nimport { notice } from \"../shared/warn.js\";\nimport {\n COMMON_FORMAT_LIST,\n OMITTED_WHEN_CLEAN,\n REPORT_FORMAT_LIST,\n STDIN_TOKEN,\n isMachineFormat,\n} from \"../meta/internal.js\";\nimport { REPORT_FORMATS, isReportFormat } from \"../meta/index.js\";\nimport { runAdd } from \"./commands/add.js\";\nimport { runCheck } from \"./commands/check.js\";\nimport { runRemove } from \"./commands/remove.js\";\nimport { runUpdate } from \"./commands/update.js\";\nimport { CiteError, asCiteError } from \"./errors.js\";\nimport { spellSource } from \"./core/range.js\";\nimport { shortCommit, shortLine, shortPin, shortSrc } from \"./core/spell.js\";\nimport { renderCheckGithub } from \"./reporters/github.js\";\nimport { renderCheckJson, renderRemoveJson, renderUpdateJson } from \"./reporters/json.js\";\nimport { renderCheckJunit } from \"./reporters/junit.js\";\nimport { renderCheckPretty, renderRemovePretty, renderUpdatePretty } from \"./reporters/pretty.js\";\nimport { renderCheckSarif } from \"./reporters/sarif.js\";\nimport type { AddResult, PageLines } from \"./types.js\";\n\nconst UPDATE_FORMATS = [\"pretty\", \"json\"] as const;\ntype UpdateFormat = (typeof UPDATE_FORMATS)[number];\n/** The same two `update` has: a removal is a write, and writes report alike. */\nconst REMOVE_FORMATS = UPDATE_FORMATS;\ntype RemoveFormat = UpdateFormat;\n\n/**\n * Whether `command`'s output gets colour: this domain's `--no-color` and\n * `NO_COLOR` turn it off, and otherwise only a TTY turns it on\n * (`shouldColor`). `isTTY` is passed uncoerced: Node leaves it undefined off\n * a terminal, never false, and `shouldColor` reads a missing one as \"not a\n * terminal\".\n */\nexport function colorFor(\n command: Command,\n isTTY: boolean | undefined,\n env?: NodeJS.ProcessEnv,\n): boolean {\n // commander maps --no-color to opts.color === false, on the command that\n // declares it.\n const noColor = colorOwner(command).opts().color === false;\n return shouldColor({ noColor, isTTY, env });\n}\n\n/**\n * The nearest command, this one or an ancestor, that declares `--no-color`:\n * the `cite` program, wherever it is mounted. Not the root: under the\n * umbrella that is `manni`, which has no `--no-color` of its own.\n */\nfunction colorOwner(command: Command): Command {\n for (let c: Command | null = command; c !== null; c = c.parent) {\n if (c.options.some((o) => o.long === \"--no-color\")) return c;\n }\n return command;\n}\n\nfunction isUpdateFormat(value: string): value is UpdateFormat {\n return (UPDATE_FORMATS as readonly string[]).includes(value);\n}\n\nfunction isRemoveFormat(value: string): value is RemoveFormat {\n return (REMOVE_FORMATS as readonly string[]).includes(value);\n}\n\n/**\n * Commander hands an `.action()` callback an untyped bag of option values, so\n * each subcommand declares the shape it actually reads. The `--no-<thing>`\n * flags are `boolean` and never `undefined`: commander supplies `true` when\n * the flag is absent, which is its default and not a choice, so only the\n * explicit `false` travels to the core (`explicitFalse`).\n */\ninterface InputCliOptions {\n /** `--collection <name>`, repeatable; commander's default value is `[]`. */\n collection: string[];\n /** `--ext <list>`; the command splits it. */\n ext?: string;\n /** `--exclude <glob>`, repeatable; commander's default value is `[]`. */\n exclude: string[];\n /** `--as <format>`: force an extractor. */\n as?: string;\n /**\n * `-c, --config <path>` and `--no-config` share one commander attribute:\n * `undefined` with neither flag, the path with `-c`, `false` with\n * `--no-config`. Split by `configOption`.\n */\n config?: string | boolean;\n allowEmpty?: boolean;\n /** `--no-gitignore`. */\n gitignore: boolean;\n /** `--root <dir>`: where `src:` paths resolve from. */\n root?: string;\n}\n\ninterface CheckCliOptions extends InputCliOptions {\n /** `-f, --format <format>`. Always a string: the declaration has a default. */\n format: string;\n quiet?: boolean;\n /**\n * `--baseline [path]` / `--no-baseline`, the same three-state split as\n * `config`: absent leaves the config in charge, a string names a file, `true`\n * is a bare `--baseline` (the default path), `false` is `--no-baseline`.\n */\n baseline?: string | boolean;\n /** `--write-baseline [path]`; `true` for the bare flag. */\n writeBaseline?: string | boolean;\n /** `--no-check-sources`. */\n checkSources: boolean;\n showDiff?: boolean;\n reveal?: boolean;\n}\n\ninterface AddCliOptions {\n id?: string;\n marker?: boolean;\n quote?: boolean;\n /** `--encrypt`. */\n encrypt?: boolean;\n /** `--no-commit-sha`. */\n commitSha: boolean;\n dryRun?: boolean;\n as?: string;\n root?: string;\n config?: string | boolean;\n}\n\ninterface RemoveCliOptions extends Omit<InputCliOptions, \"root\"> {\n /** `--only <id>`, repeatable; commander's default value is `[]`. */\n only: string[];\n dryRun?: boolean;\n format: string;\n}\n\ninterface UpdateCliOptions extends InputCliOptions {\n /** `--no-check-sources`: declared so the refusal names the flag rather than commander rejecting it. */\n checkSources: boolean;\n accept?: boolean;\n recommit?: boolean;\n /** `--only <id>`, repeatable; commander's default value is `[]`. */\n only: string[];\n dryRun?: boolean;\n format: string;\n}\n\n/**\n * Split `docs/limits.md:9` or `docs/limits.md:14-18` into the page and the\n * claim's lines, under cite's error contract. The parsing is the shared pin\n * engine's (`splitPageArgument` in `src/shared/pin.ts`).\n */\nexport function splitPageArgument(arg: string): { page: string; lines?: PageLines } {\n return asCiteError(() => splitSharedPageArgument(arg));\n}\n\n/** `line 9`, or `lines 14-18` for a range. */\nfunction spellAt(lines: PageLines, noun = \"line\"): string {\n return lines.start === lines.end\n ? `${noun} ${String(lines.start)}`\n : `${noun}s ${String(lines.start)}-${String(lines.end)}`;\n}\n\n/**\n * What `add` says on success. One sentence composed from the result: what was\n * added, where it went, and what each end is pinned to. Lines are the page's\n * own, after the write. The source is spelled as it was written to the page,\n * abbreviated when it is a ciphertext, and quoted with its first pinned line\n * where the result carries one.\n */\nexport function addMessage(result: AddResult): string {\n const { citation, claimLines } = result;\n const claim = citation.claim;\n const name = citation.id ?? (claim === undefined ? \"a bare pin\" : \"an entry\");\n const src = shortSrc(spellSource(citation.source));\n const commit = citation.source[\"commit-sha\"];\n const quoted = result.sourceLine === undefined ? \"\" : shortLine(result.sourceLine);\n const line = quoted === \"\" ? \"\" : ` \"${quoted}\"`;\n const pin = `${src}${line}, ${shortPin(citation.source.integrity)}, ${commit === undefined ? \"no commit\" : shortCommit(commit)}`;\n // Where it went: the page's own frontmatter, or the manifest that owns the\n // page's citations, at the line the entry now sits on.\n const where =\n result.manifest === undefined\n ? \"frontmatter\"\n : `${result.manifest.file}:${String(result.manifest.line)}`;\n const head = `${result.file}: added ${name} to ${where}`;\n\n if (result.markerLine !== undefined) {\n const at =\n claimLines === undefined ? \"\" : `, claim pinned at ${spellAt(claimLines)}`;\n const wrote = result.markerJoined === true ? \"joined the marker at line\" : \"marker at line\";\n const marked = `${head}; ${wrote} ${String(result.markerLine)}${at}`;\n if (claim === undefined) return marked;\n if (citation.quote === true) return `${marked} (a block that reproduces ${src})`;\n return `${marked} (${shortPin(claim.integrity)}; source ${pin})`;\n }\n if (claim === undefined || claimLines === undefined) {\n return `${head} (source ${pin})`;\n }\n if (citation.quote === true) {\n return `${head} (claim ${spellAt(claimLines, \"line\")}, a block that reproduces ${src})`;\n }\n return `${head} (claim at ${spellAt(claimLines)}, ${shortPin(claim.integrity)}; source ${pin})`;\n}\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"cite\")\n .description(\n \"Track citations from doc claims to source lines and check them for drift.\",\n )\n .version(pkg.version, \"-V, --version\")\n .option(\"--no-color\", \"disable colored output\")\n // A pointer, not the whole help screen: the message that precedes it\n // already names the offending flag.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before the `.command()` calls below. `copyInheritedSettings`\n // copies `_exitCallback` by value at subcommand-creation time, so an\n // `exitOverride()` installed afterwards leaves every subcommand still\n // calling `process.exit(1)`.\n .exitOverride();\n\n program\n .command(\"check\")\n .description(\"Check every citation in the given pages against its source\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to check (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\n \"-f, --format <format>\",\n `output: ${REPORT_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"-q, --quiet\", \"in pretty output, hide current citations and clean files\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"check files .gitignore covers\")\n // No `defaultValue` and no `.preset()`, for the reasons meta's validate\n // gives: a bare flag must stay distinguishable from a typed path.\n .addOption(\n new Option(\n \"--baseline [path]\",\n \"compare against a baseline; fail only on findings not in it\",\n ),\n )\n .addOption(\n new Option(\n \"--write-baseline [path]\",\n \"record current findings as the baseline, then exit 0\",\n ),\n )\n .option(\"--no-baseline\", \"ignore a baseline configured by `baseline:`\")\n .option(\"--no-check-sources\", \"page-side rules only; every source status is skipped\")\n .option(\n \"--root <dir>\",\n \"directory src: paths resolve from (default: cite.root from config, else the git root, else the current directory)\",\n )\n .option(\"--show-diff\", \"in pretty output, print the diff and commit subjects for changed\")\n .option(\"--reveal\", \"in pretty output, print the decrypted path beside an encrypted source\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite check docs/ # walk a directory\",\n \" manni cite check --collection guides # one configured collection\",\n ' manni cite check \"docs/**/*.md\" -f github # CI annotations',\n \" manni cite check --show-diff docs/limits.md # see what changed\",\n \" manni cite check --baseline # fail only on new findings\",\n \" cat page.md | manni cite check - --as markdown\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: CheckCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isReportFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${REPORT_FORMAT_LIST}.`,\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const stdinContent = paths.includes(STDIN_TOKEN) ? await readStdin() : undefined;\n const cwd = process.cwd();\n\n const run = await runCheck({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(!isMachineFormat(format), cwd),\n stdinContent,\n // `undefined` rather than `false` when absent, so config still wins.\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n baseline: options.baseline,\n writeBaseline: options.writeBaseline,\n checkSources: explicitFalse(options.checkSources),\n // Only so the run can say git is not there to give diffs; the diffs\n // themselves are the pretty reporter's.\n showDiff: options.showDiff ? true : undefined,\n root: options.root,\n });\n\n let text: string;\n switch (format) {\n case \"pretty\":\n text = renderCheckPretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n quiet: Boolean(options.quiet),\n showDiff: Boolean(options.showDiff),\n reveal: Boolean(options.reveal),\n });\n break;\n case \"json\":\n text = renderCheckJson(run);\n break;\n case \"github\":\n text = renderCheckGithub(run);\n break;\n case \"sarif\":\n text = renderCheckSarif(run, { onNotice: notice });\n break;\n case \"junit\":\n text = renderCheckJunit(run);\n break;\n }\n // Only `github` may say nothing on a clean run; every other format\n // owes its envelope even when empty.\n if (text.length > 0 || !OMITTED_WHEN_CLEAN.has(format)) {\n process.stdout.write(`${text}\\n`);\n }\n // `failed` counts files with an unbaselined error-severity finding;\n // warnings never move it.\n process.exitCode = run.summary.failed > 0 ? 1 : 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"add\")\n .description(\"Mint a citation for a source range and write it to a page\")\n .argument(\n \"<page>\",\n \"the page to cite from, with the claim's lines: page:L or page:L1-L2 (use - for stdin, with --as)\",\n )\n .argument(\n \"<src>\",\n \"path, path:L or path:L1-L2 relative to --root, or an encrypted ~source with the same line forms\",\n )\n .option(\"--id <id>\", \"kebab-case id, unique on the page; required with --marker\")\n .option(\"--marker\", \"write a cite <id> marker above the paragraph holding the page lines and pin the text it anchors\")\n .option(\"--quote\", \"the page lines are a fenced block that reproduces the source\")\n .option(\n \"--encrypt\",\n \"write source.file encrypted, with an hmac-sha256- pin; with no key, offer to create one (an available key encrypts without the flag)\",\n )\n .option(\"--no-commit-sha\", \"do not record HEAD\")\n .option(\"--dry-run\", \"print the diff; write nothing\")\n .option(\"--as <format>\", \"force the page format\")\n .option(\"--root <dir>\", \"directory source paths resolve from (as check)\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite add docs/limits.md:9 lib/limits.ts:2 --id fetch-timeout\",\n \" manni cite add docs/limits.md:30 lib/limits.ts:8-12 --id timeouts --marker\",\n \" manni cite add docs/limits.md:14-18 lib/limits.ts:1-3 --quote\",\n \" manni cite add docs/limits.md lib/limits.ts --dry-run\",\n \" cat page.md | manni cite add -:9 lib/limits.ts:2 --as markdown > out.md\",\n ].join(\"\\n\"),\n )\n .action(async (pageArgument: string, src: string, options: AddCliOptions) => {\n try {\n const { page, lines } = splitPageArgument(pageArgument);\n const usingStdin = page === STDIN_TOKEN;\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n const cwd = process.cwd();\n\n const result = await runAdd({\n page,\n pageLines: lines,\n src,\n id: options.id,\n marker: options.marker ? true : undefined,\n quote: options.quote ? true : undefined,\n // `undefined` when absent, so the key decides: an available one\n // encrypts without the flag.\n encrypt: options.encrypt ? true : undefined,\n commitSha: explicitFalse(options.commitSha),\n dryRun,\n as: options.as,\n ...configOption(options.config),\n // With `-` the page owns stdout; so does the diff under --dry-run.\n onConfigLoaded: reportConfig(!usingStdin && !dryRun, cwd),\n stdinContent,\n root: options.root,\n onNotice: notice,\n // Only on a terminal: off one, a missing key is a refusal, not a\n // question nobody can answer. With `-` stdin is the page, so no\n // question is put either.\n confirm: terminalConfirm(),\n });\n\n const message = addMessage(result);\n // A dry run prints every diff the write would make: the page's, and\n // the manifest's when the entry goes there.\n const diffs = [result.diff, result.manifest?.diff ?? \"\"].filter((d) => d.length > 0);\n if (usingStdin) {\n // The rewritten page owns stdout; everything else is a diagnostic.\n process.stdout.write(result.content);\n if (dryRun) for (const diff of diffs) process.stderr.write(`${diff}\\n`);\n process.stderr.write(`${message}\\n`);\n } else if (dryRun) {\n for (const diff of diffs) process.stdout.write(`${diff}\\n`);\n process.stderr.write(`${message}\\n`);\n } else {\n process.stdout.write(`${message}\\n`);\n }\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"update\")\n .description(\"Rewrite moved citations in place; with --accept, re-mint changed ones\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to update (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"update files .gitignore covers\")\n .option(\"--no-check-sources\", \"refused: update needs the sources\")\n .option(\"--root <dir>\", \"directory src: paths resolve from (as check)\")\n .option(\"--accept\", \"re-mint changed and never-true entries at HEAD; prints old and new pins\")\n .option(\n \"--recommit\",\n \"re-record commit-sha where the recorded commit does not contain the pinned lines, or is outside HEAD's history\",\n )\n .option(\"--only <id>\", \"limit to entries with this id; repeatable\", collect, [])\n .option(\"--dry-run\", \"print the diffs; write nothing\")\n .option(\n \"-f, --format <format>\",\n `output: ${UPDATE_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite update docs/ # rewrite moved entries\",\n \" manni cite update --accept --only fetch-timeout docs/limits.md\",\n \" manni cite update --dry-run docs/ # see the diffs first\",\n \" manni cite update --recommit docs/ # repair unsupported commit-sha\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: UpdateCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isUpdateFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`,\n );\n }\n if (!options.checkSources) {\n throw new CiteError(\n \"update needs the sources: drop --no-check-sources (or `checkSources: false`).\",\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const usingStdin = paths.includes(STDIN_TOKEN);\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n // With `-` the rewritten page owns stdout, as it does for `add -`; a\n // dry run prints the diffs instead, so the report keeps stdout.\n const pageToStdout = usingStdin && !dryRun;\n const cwd = process.cwd();\n\n const run = await runUpdate({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(format === \"pretty\" && !pageToStdout, cwd),\n stdinContent,\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n root: options.root,\n accept: options.accept ? true : undefined,\n recommit: options.recommit ? true : undefined,\n only: options.only.length > 0 ? options.only : undefined,\n dryRun,\n });\n\n const text =\n format === \"json\"\n ? renderUpdateJson(run)\n : renderUpdatePretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n // The diffs are the point of a dry run; a real run prints\n // what it rewrote and leaves the file to say the rest.\n showDiff: dryRun,\n });\n const stdinPage = pageToStdout ? run.pages.find((page) => page.content !== undefined) : undefined;\n if (stdinPage?.content !== undefined) {\n process.stdout.write(stdinPage.content);\n process.stderr.write(`${text}\\n`);\n } else {\n process.stdout.write(`${text}\\n`);\n }\n // Exit 1 when something was skipped with an error-severity finding:\n // work left undone, `fill`'s precedent.\n process.exitCode = run.exitCode;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"remove\")\n .description(\"Remove the named citations from the given pages, markers and all\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to remove from (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"remove from files .gitignore covers\")\n .option(\n \"--only <id>\",\n \"the entry to remove, by id or by pointer (/citations/N); required, and repeatable\",\n collect,\n [],\n )\n .option(\"--dry-run\", \"print the diffs and the report; write nothing\")\n .option(\n \"-f, --format <format>\",\n `output: ${REMOVE_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite remove docs/limits.md --only fetch-timeout\",\n \" manni cite remove docs/ --only fetch-timeout --only retries --dry-run\",\n \" manni cite remove --collection site --only /citations/3 -f json\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: RemoveCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isRemoveFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`,\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const usingStdin = paths.includes(STDIN_TOKEN);\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n // With `-` the rewritten page owns stdout, exactly as on `update -`.\n const pageToStdout = usingStdin && !dryRun;\n const cwd = process.cwd();\n\n const run = await runRemove({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(format === \"pretty\" && !pageToStdout, cwd),\n stdinContent,\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n only: options.only,\n dryRun,\n });\n\n const text =\n format === \"json\"\n ? renderRemoveJson(run)\n : renderRemovePretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n // The diffs are the point of a dry run; a real run prints\n // what it removed and leaves the file to say the rest.\n showDiff: dryRun,\n dryRun,\n });\n const stdinPage = pageToStdout ? run.pages.find((page) => page.content !== undefined) : undefined;\n if (stdinPage?.content !== undefined) {\n process.stdout.write(stdinPage.content);\n process.stderr.write(`${text}\\n`);\n } else {\n process.stdout.write(`${text}\\n`);\n }\n // Everything named was removed, or previewed: there is no exit 1.\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n return program;\n}\n","/**\n * SARIF for `check`. Meta's renderer builds the envelope, the\n * repository-relative uris and the fingerprints the baseline shares, from the\n * adapted results. What it cannot know is what a cite rule is: it describes\n * every rule as a schema keyword, links meta's fix page, and prefixes each\n * message with the JSON Pointer of the entry, `(root)` for a finding about no\n * entry. This renderer replaces those three with the cite rule's own\n * description, a link to its row of the citations reference, and the message\n * the github annotation carries, which names the citation the pointer only\n * numbered. A message is no part of a fingerprint, so the baseline is\n * unaffected.\n */\nimport { renderSarif, type ValidationResult } from \"../../meta/index.js\";\nimport { errorSite } from \"../core/adapt.js\";\nimport { RULE_ID_PREFIX, isCiteRule } from \"../core/severity.js\";\nimport type { CheckRun, CiteRule } from \"../types.js\";\nimport { findingMessage } from \"./github.js\";\n\nconst INFORMATION_URI = \"https://hawkeyexl.github.io/manni/cite/\";\n\n/** The citations reference, whose rule tables anchor each row by rule name. */\nconst RULES_URI = \"https://hawkeyexl.github.io/manni/cite/reference/citations/\";\n\n/** What each rule is, as the citations reference's tables say it. */\nconst RULE_DESCRIPTIONS: Readonly<Record<CiteRule, string>> = {\n \"source-moved\": \"The cited source lines moved to one other place in the file.\",\n \"source-moved-ambiguous\": \"The cited source lines now match at several places in the file.\",\n \"source-changed\": \"The cited source lines changed since the citation pinned them.\",\n \"source-never-true\": \"The pin never matched the source at the recorded commit.\",\n \"source-missing\": \"The cited source file is not tracked under the root, or cannot be decrypted.\",\n \"claim-moved\": \"The cited sentence moved to other lines of the page.\",\n \"claim-moved-ambiguous\": \"The cited sentence now appears at several places on the page.\",\n \"claim-reanchored\": \"The cited sentence's words are unchanged since the claim's baseline, and only its layout moved.\",\n \"claim-changed\": \"The cited sentence was edited since the citation pinned it.\",\n \"marker-orphan\": \"A marker names an id no citation has.\",\n \"marker-invalid\": \"A marker is malformed, or the page has too many markers.\",\n \"marker-repeated\": \"Two markers name the same citation id.\",\n \"marker-misplaced\": \"A marker line sits inside the paragraph it anchors, and splits it.\",\n \"anchor-invalid\": \"A citation's anchor cannot work.\",\n \"entry-invalid\": \"A citation entry is malformed.\",\n \"quote-drift\": \"A quoted block no longer reproduces its source.\",\n};\n\n/**\n * The label meta's reporters put before a message: `(root) ` for a finding\n * about no entry, `/citations/N ` for one about an entry. Nothing else ever\n * opens a cite finding's adapted message.\n */\nexport const ENTRY_LABEL = /^(?:\\(root\\)|\\/citations\\/\\d+) /;\n\nexport interface SarifRule {\n id: string;\n shortDescription: { text: string };\n helpUri?: string;\n}\n\n/** As much of meta's SARIF as this renderer and its tests read back. */\nexport interface SarifLog {\n runs: {\n tool: { driver: { informationUri: string; rules: SarifRule[] } };\n results: { ruleId: string; message: { text: string } }[];\n }[];\n}\n\n/**\n * The adapted results with each message rewritten as the github annotation\n * says it. An error is paired with its finding by rule, entry, line and\n * message, as the baseline split pairs them; the baseline has already\n * dropped the errors it forgives.\n */\nexport function withFindingMessages(run: CheckRun): ValidationResult[] {\n return run.results.map((result) => {\n const page = run.pages.find((p) => p.file === result.file);\n if (page === undefined) return result;\n const errors = result.errors.map((error) => {\n const finding = page.findings.find(\n (f) =>\n f.rule === error.keyword &&\n (f.index === undefined ? \"\" : `/citations/${String(f.index)}`) === error.instancePath &&\n f.message === error.message &&\n (errorSite(f).line ?? null) === (error.line ?? null),\n );\n return finding === undefined ? error : { ...error, message: findingMessage(finding) };\n });\n return { ...result, errors };\n });\n}\n\n/** A rule as the citation tool describes it. */\nfunction describe(rule: SarifRule): SarifRule {\n const name = rule.id.slice(RULE_ID_PREFIX.length + 1);\n if (!isCiteRule(name)) return rule;\n return { id: rule.id, shortDescription: { text: RULE_DESCRIPTIONS[name] }, helpUri: `${RULES_URI}#${name}` };\n}\n\nexport function renderCheckSarif(run: CheckRun, opts: { onNotice?: (message: string) => void } = {}): string {\n const log = JSON.parse(\n renderSarif(withFindingMessages(run), {\n frame: run.frame,\n ...(opts.onNotice === undefined ? {} : { onNotice: opts.onNotice }),\n }),\n ) as SarifLog;\n for (const sarifRun of log.runs) {\n sarifRun.tool.driver.informationUri = INFORMATION_URI;\n sarifRun.tool.driver.rules = sarifRun.tool.driver.rules.map(describe);\n for (const result of sarifRun.results) result.message.text = result.message.text.replace(ENTRY_LABEL, \"\");\n }\n return JSON.stringify(log, null, 2);\n}\n","/**\n * JUnit for `check`: meta's renderer over the adapted results, under the\n * `manni.cite` classname, with each failure's message the one the github\n * annotation carries.\n * Meta's renderer opens every message with the entry's JSON Pointer, `(root)`\n * for a finding about no entry, which says nothing about a citation. The\n * failure's `type` is already the rule id.\n */\nimport { renderJunit } from \"../../meta/index.js\";\nimport type { CheckRun } from \"../types.js\";\nimport { ENTRY_LABEL, withFindingMessages } from \"./sarif.js\";\n\n/** JUnit `classname` for the citation tool's findings. */\nexport const JUNIT_CLASSNAME = \"manni.cite\";\n\n/** A `message=\"` attribute's opening label. The value is escaped, so `message=\"` opens nothing else. */\nconst MESSAGE_LABEL = new RegExp(`message=\"${ENTRY_LABEL.source.replace(/^\\^/, \"\")}`, \"g\");\n\nexport function renderCheckJunit(run: CheckRun): string {\n return renderJunit(withFindingMessages(run), { frame: run.frame, classname: JUNIT_CLASSNAME }).replace(\n MESSAGE_LABEL,\n 'message=\"',\n );\n}\n"],"mappings":"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","names":["splitPageArgument"]}
1
+ {"version":3,"sources":["../src/cite/cli.ts","../src/cite/reporters/sarif.ts","../src/cite/reporters/junit.ts"],"sourcesContent":["/**\n * The `cite` domain's commander program. Mounted by `src/cli.ts` under\n * `manni cite`; no entry point of its own. Grammar per proposal 0034: verbs are\n * `check`, `add`, `update`, `remove`; there is no default subcommand.\n *\n * Follows clig.dev as meta's does: primary output to stdout, diagnostics to\n * stderr, colour only on a TTY and never under `NO_COLOR`/`--no-color`, exit\n * `0` clean, `1` an error-severity finding, `2` operational/usage.\n */\nimport { Command, Option } from \"commander\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport {\n collect,\n configOption,\n explicitFalse,\n readStdin,\n reportConfig,\n splitList,\n} from \"../shared/cli-options.js\";\nimport { shouldColor } from \"../shared/color.js\";\nimport { splitPageArgument as splitSharedPageArgument } from \"../shared/pin.js\";\nimport { terminalConfirm } from \"../shared/prompt.js\";\nimport { fail } from \"../shared/run.js\";\nimport { notice } from \"../shared/warn.js\";\nimport {\n COMMON_FORMAT_LIST,\n OMITTED_WHEN_CLEAN,\n REPORT_FORMAT_LIST,\n STDIN_TOKEN,\n isMachineFormat,\n} from \"../meta/internal.js\";\nimport { REPORT_FORMATS, isReportFormat } from \"../meta/index.js\";\nimport { runAdd } from \"./commands/add.js\";\nimport { runCheck } from \"./commands/check.js\";\nimport { runRemove } from \"./commands/remove.js\";\nimport { runUpdate } from \"./commands/update.js\";\nimport { CiteError, asCiteError } from \"./errors.js\";\nimport { spellSource } from \"./core/range.js\";\nimport { shortCommit, shortLine, shortPin, shortSrc } from \"./core/spell.js\";\nimport { renderCheckGithub } from \"./reporters/github.js\";\nimport { renderCheckJson, renderRemoveJson, renderUpdateJson } from \"./reporters/json.js\";\nimport { renderCheckJunit } from \"./reporters/junit.js\";\nimport { renderCheckPretty, renderRemovePretty, renderUpdatePretty } from \"./reporters/pretty.js\";\nimport { renderCheckSarif } from \"./reporters/sarif.js\";\nimport type { AddResult, PageLines } from \"./types.js\";\n\nconst UPDATE_FORMATS = [\"pretty\", \"json\"] as const;\ntype UpdateFormat = (typeof UPDATE_FORMATS)[number];\n/** The same two `update` has: a removal is a write, and writes report alike. */\nconst REMOVE_FORMATS = UPDATE_FORMATS;\ntype RemoveFormat = UpdateFormat;\n\n/**\n * Whether `command`'s output gets colour: this domain's `--no-color` and\n * `NO_COLOR` turn it off, and otherwise only a TTY turns it on\n * (`shouldColor`). `isTTY` is passed uncoerced: Node leaves it undefined off\n * a terminal, never false, and `shouldColor` reads a missing one as \"not a\n * terminal\".\n */\nexport function colorFor(\n command: Command,\n isTTY: boolean | undefined,\n env?: NodeJS.ProcessEnv,\n): boolean {\n // commander maps --no-color to opts.color === false, on the command that\n // declares it.\n const noColor = colorOwner(command).opts().color === false;\n return shouldColor({ noColor, isTTY, env });\n}\n\n/**\n * The nearest command, this one or an ancestor, that declares `--no-color`:\n * the `cite` program, wherever it is mounted. Not the root: under the\n * umbrella that is `manni`, which has no `--no-color` of its own.\n */\nfunction colorOwner(command: Command): Command {\n for (let c: Command | null = command; c !== null; c = c.parent) {\n if (c.options.some((o) => o.long === \"--no-color\")) return c;\n }\n return command;\n}\n\nfunction isUpdateFormat(value: string): value is UpdateFormat {\n return (UPDATE_FORMATS as readonly string[]).includes(value);\n}\n\nfunction isRemoveFormat(value: string): value is RemoveFormat {\n return (REMOVE_FORMATS as readonly string[]).includes(value);\n}\n\n/**\n * Commander hands an `.action()` callback an untyped bag of option values, so\n * each subcommand declares the shape it actually reads. The `--no-<thing>`\n * flags are `boolean` and never `undefined`: commander supplies `true` when\n * the flag is absent, which is its default and not a choice, so only the\n * explicit `false` travels to the core (`explicitFalse`).\n */\ninterface InputCliOptions {\n /** `--collection <name>`, repeatable; commander's default value is `[]`. */\n collection: string[];\n /** `--ext <list>`; the command splits it. */\n ext?: string;\n /** `--exclude <glob>`, repeatable; commander's default value is `[]`. */\n exclude: string[];\n /** `--as <format>`: force an extractor. */\n as?: string;\n /**\n * `-c, --config <path>` and `--no-config` share one commander attribute:\n * `undefined` with neither flag, the path with `-c`, `false` with\n * `--no-config`. Split by `configOption`.\n */\n config?: string | boolean;\n allowEmpty?: boolean;\n /** `--no-gitignore`. */\n gitignore: boolean;\n /** `--root <dir>`: where `src:` paths resolve from. */\n root?: string;\n}\n\ninterface CheckCliOptions extends InputCliOptions {\n /** `-f, --format <format>`. Always a string: the declaration has a default. */\n format: string;\n quiet?: boolean;\n /**\n * `--baseline [path]` / `--no-baseline`, the same three-state split as\n * `config`: absent leaves the config in charge, a string names a file, `true`\n * is a bare `--baseline` (the default path), `false` is `--no-baseline`.\n */\n baseline?: string | boolean;\n /** `--write-baseline [path]`; `true` for the bare flag. */\n writeBaseline?: string | boolean;\n /** `--no-check-sources`. */\n checkSources: boolean;\n showDiff?: boolean;\n reveal?: boolean;\n}\n\ninterface AddCliOptions {\n id?: string;\n marker?: boolean;\n quote?: boolean;\n /** `--encrypt`. */\n encrypt?: boolean;\n /** `--no-commit-sha`. */\n commitSha: boolean;\n dryRun?: boolean;\n as?: string;\n root?: string;\n config?: string | boolean;\n}\n\ninterface RemoveCliOptions extends Omit<InputCliOptions, \"root\"> {\n /** `--only <id>`, repeatable; commander's default value is `[]`. */\n only: string[];\n dryRun?: boolean;\n format: string;\n}\n\ninterface UpdateCliOptions extends InputCliOptions {\n /** `--no-check-sources`: declared so the refusal names the flag rather than commander rejecting it. */\n checkSources: boolean;\n accept?: boolean;\n recommit?: boolean;\n /** `--only <id>`, repeatable; commander's default value is `[]`. */\n only: string[];\n dryRun?: boolean;\n format: string;\n}\n\n/**\n * Split `docs/limits.md:9` or `docs/limits.md:14-18` into the page and the\n * claim's lines, under cite's error contract. The parsing is the shared pin\n * engine's (`splitPageArgument` in `src/shared/pin.ts`).\n */\nexport function splitPageArgument(arg: string): { page: string; lines?: PageLines } {\n return asCiteError(() => splitSharedPageArgument(arg));\n}\n\n/** `line 9`, or `lines 14-18` for a range. */\nfunction spellAt(lines: PageLines, noun = \"line\"): string {\n return lines.start === lines.end\n ? `${noun} ${String(lines.start)}`\n : `${noun}s ${String(lines.start)}-${String(lines.end)}`;\n}\n\n/**\n * What `add` says on success. One sentence composed from the result: what was\n * added, where it went, and what each end is pinned to. Lines are the page's\n * own, after the write. The source is spelled as it was written to the page,\n * abbreviated when it is a ciphertext, and quoted with its first pinned line\n * where the result carries one.\n */\nexport function addMessage(result: AddResult): string {\n const { citation, claimLines } = result;\n const claim = citation.claim;\n const name = citation.id ?? (claim === undefined ? \"a bare pin\" : \"an entry\");\n const src = shortSrc(spellSource(citation.source));\n const commit = citation.source[\"commit-sha\"];\n const quoted = result.sourceLine === undefined ? \"\" : shortLine(result.sourceLine);\n const line = quoted === \"\" ? \"\" : ` \"${quoted}\"`;\n const pin = `${src}${line}, ${shortPin(citation.source.integrity)}, ${commit === undefined ? \"no commit\" : shortCommit(commit)}`;\n // Where it went: the page's own frontmatter, or the manifest that owns the\n // page's citations, at the line the entry now sits on.\n const where =\n result.manifest === undefined\n ? \"frontmatter\"\n : `${result.manifest.file}:${String(result.manifest.line)}`;\n const head = `${result.file}: added ${name} to ${where}`;\n\n if (result.markerLine !== undefined) {\n const at =\n claimLines === undefined ? \"\" : `, claim pinned at ${spellAt(claimLines)}`;\n const wrote = result.markerJoined === true ? \"joined the marker at line\" : \"marker at line\";\n const marked = `${head}; ${wrote} ${String(result.markerLine)}${at}`;\n if (claim === undefined) return marked;\n if (citation.quote === true) return `${marked} (a block that reproduces ${src})`;\n return `${marked} (${shortPin(claim.integrity)}; source ${pin})`;\n }\n if (claim === undefined || claimLines === undefined) {\n return `${head} (source ${pin})`;\n }\n if (citation.quote === true) {\n return `${head} (claim ${spellAt(claimLines, \"line\")}, a block that reproduces ${src})`;\n }\n return `${head} (claim at ${spellAt(claimLines)}, ${shortPin(claim.integrity)}; source ${pin})`;\n}\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"cite\")\n .description(\n \"Track citations from doc claims to source lines and check them for drift.\",\n )\n .version(pkg.version, \"-V, --version\")\n .option(\"--no-color\", \"disable colored output\")\n // A pointer, not the whole help screen: the message that precedes it\n // already names the offending flag.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before the `.command()` calls below. `copyInheritedSettings`\n // copies `_exitCallback` by value at subcommand-creation time, so an\n // `exitOverride()` installed afterwards leaves every subcommand still\n // calling `process.exit(1)`.\n .exitOverride();\n\n program\n .command(\"check\")\n .description(\"Check every citation in the given pages against its source\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to check (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\n \"-f, --format <format>\",\n `output: ${REPORT_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"-q, --quiet\", \"in pretty output, hide current citations and clean files\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"check files .gitignore covers\")\n // No `defaultValue` and no `.preset()`, for the reasons meta's validate\n // gives: a bare flag must stay distinguishable from a typed path.\n .addOption(\n new Option(\n \"--baseline [path]\",\n \"compare against a baseline; fail only on findings not in it\",\n ),\n )\n .addOption(\n new Option(\n \"--write-baseline [path]\",\n \"record current findings as the baseline, then exit 0\",\n ),\n )\n .option(\"--no-baseline\", \"ignore a baseline configured by `baseline:`\")\n .option(\"--no-check-sources\", \"page-side rules only; every source status is skipped\")\n .option(\n \"--root <dir>\",\n \"directory src: paths resolve from (default: cite.root from config, else the git root, else the current directory)\",\n )\n .option(\"--show-diff\", \"in pretty output, print the diff and commit subjects for changed\")\n .option(\"--reveal\", \"in pretty output, print the decrypted path beside an encrypted source\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite check docs/ # walk a directory\",\n \" manni cite check --collection guides # one configured collection\",\n ' manni cite check \"docs/**/*.md\" -f github # CI annotations',\n \" manni cite check --show-diff docs/limits.md # see what changed\",\n \" manni cite check --baseline # fail only on new findings\",\n \" cat page.md | manni cite check - --as markdown\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: CheckCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isReportFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${REPORT_FORMAT_LIST}.`,\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const stdinContent = paths.includes(STDIN_TOKEN) ? await readStdin() : undefined;\n const cwd = process.cwd();\n\n const run = await runCheck({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(!isMachineFormat(format), cwd),\n stdinContent,\n // `undefined` rather than `false` when absent, so config still wins.\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n baseline: options.baseline,\n writeBaseline: options.writeBaseline,\n checkSources: explicitFalse(options.checkSources),\n // Only so the run can say git is not there to give diffs; the diffs\n // themselves are the pretty reporter's.\n showDiff: options.showDiff ? true : undefined,\n root: options.root,\n });\n\n let text: string;\n switch (format) {\n case \"pretty\":\n text = renderCheckPretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n quiet: Boolean(options.quiet),\n showDiff: Boolean(options.showDiff),\n reveal: Boolean(options.reveal),\n });\n break;\n case \"json\":\n text = renderCheckJson(run);\n break;\n case \"github\":\n text = renderCheckGithub(run);\n break;\n case \"sarif\":\n text = renderCheckSarif(run, { onNotice: notice });\n break;\n case \"junit\":\n text = renderCheckJunit(run);\n break;\n }\n // Only `github` may say nothing on a clean run; every other format\n // owes its envelope even when empty.\n if (text.length > 0 || !OMITTED_WHEN_CLEAN.has(format)) {\n process.stdout.write(`${text}\\n`);\n }\n // `failed` counts files with an unbaselined error-severity finding;\n // warnings never move it.\n process.exitCode = run.summary.failed > 0 ? 1 : 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"add\")\n .description(\"Mint a citation for a source range and write it to a page\")\n .argument(\n \"<page>\",\n \"the page to cite from, with the claim's lines: page:L or page:L1-L2 (use - for stdin, with --as)\",\n )\n .argument(\n \"<src>\",\n \"path, path:L or path:L1-L2 relative to --root, or an encrypted ~source with the same line forms\",\n )\n .option(\"--id <id>\", \"kebab-case id, unique on the page; required with --marker\")\n .option(\"--marker\", \"write a cite <id> marker above the paragraph holding the page lines and pin the text it anchors\")\n .option(\"--quote\", \"the page lines are a fenced block that reproduces the source\")\n .option(\n \"--encrypt\",\n \"write source.file encrypted, with an hmac-sha256- pin; with no key, offer to create one (an available key encrypts without the flag)\",\n )\n .option(\"--no-commit-sha\", \"do not record HEAD\")\n .option(\"--dry-run\", \"print the diff; write nothing\")\n .option(\"--as <format>\", \"force the page format\")\n .option(\"--root <dir>\", \"directory source paths resolve from (as check)\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite add docs/limits.md:9 lib/limits.ts:2 --id fetch-timeout\",\n \" manni cite add docs/limits.md:30 lib/limits.ts:8-12 --id timeouts --marker\",\n \" manni cite add docs/limits.md:14-18 lib/limits.ts:1-3 --quote\",\n \" manni cite add docs/limits.md lib/limits.ts --dry-run\",\n \" cat page.md | manni cite add -:9 lib/limits.ts:2 --as markdown > out.md\",\n ].join(\"\\n\"),\n )\n .action(async (pageArgument: string, src: string, options: AddCliOptions) => {\n try {\n const { page, lines } = splitPageArgument(pageArgument);\n const usingStdin = page === STDIN_TOKEN;\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n const cwd = process.cwd();\n\n const result = await runAdd({\n page,\n pageLines: lines,\n src,\n id: options.id,\n marker: options.marker ? true : undefined,\n quote: options.quote ? true : undefined,\n // `undefined` when absent, so the key decides: an available one\n // encrypts without the flag.\n encrypt: options.encrypt ? true : undefined,\n commitSha: explicitFalse(options.commitSha),\n dryRun,\n as: options.as,\n ...configOption(options.config),\n // With `-` the page owns stdout; so does the diff under --dry-run.\n onConfigLoaded: reportConfig(!usingStdin && !dryRun, cwd),\n stdinContent,\n root: options.root,\n onNotice: notice,\n // Only on a terminal: off one, a missing key is a refusal, not a\n // question nobody can answer. With `-` stdin is the page, so no\n // question is put either.\n confirm: terminalConfirm(),\n });\n\n const message = addMessage(result);\n // A dry run prints every diff the write would make: the page's, and\n // the manifest's when the entry goes there.\n const diffs = [result.diff, result.manifest?.diff ?? \"\"].filter((d) => d.length > 0);\n if (usingStdin) {\n // The rewritten page owns stdout; everything else is a diagnostic.\n process.stdout.write(result.content);\n if (dryRun) for (const diff of diffs) process.stderr.write(`${diff}\\n`);\n process.stderr.write(`${message}\\n`);\n } else if (dryRun) {\n for (const diff of diffs) process.stdout.write(`${diff}\\n`);\n process.stderr.write(`${message}\\n`);\n } else {\n process.stdout.write(`${message}\\n`);\n }\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"update\")\n .description(\"Rewrite moved citations in place; with --accept, re-mint changed ones\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to update (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"update files .gitignore covers\")\n .option(\"--no-check-sources\", \"refused: update needs the sources\")\n .option(\"--root <dir>\", \"directory src: paths resolve from (as check)\")\n .option(\"--accept\", \"re-mint changed and never-true entries at HEAD; prints old and new pins\")\n .option(\n \"--recommit\",\n \"re-record commit-sha where the recorded commit does not contain the pinned lines, or is outside HEAD's history\",\n )\n .option(\"--only <id>\", \"limit to entries with this id; repeatable\", collect, [])\n .option(\"--dry-run\", \"print the diffs; write nothing\")\n .option(\n \"-f, --format <format>\",\n `output: ${UPDATE_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite update docs/ # rewrite moved entries\",\n \" manni cite update --accept --only fetch-timeout docs/limits.md\",\n \" manni cite update --dry-run docs/ # see the diffs first\",\n \" manni cite update --recommit docs/ # repair unsupported commit-sha\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: UpdateCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isUpdateFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`,\n );\n }\n if (!options.checkSources) {\n throw new CiteError(\n \"update needs the sources: drop --no-check-sources (or `checkSources: false`).\",\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const usingStdin = paths.includes(STDIN_TOKEN);\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n // With `-` the rewritten page owns stdout, as it does for `add -`; a\n // dry run prints the diffs instead, so the report keeps stdout.\n const pageToStdout = usingStdin && !dryRun;\n const cwd = process.cwd();\n\n const run = await runUpdate({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(format === \"pretty\" && !pageToStdout, cwd),\n stdinContent,\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n root: options.root,\n accept: options.accept ? true : undefined,\n recommit: options.recommit ? true : undefined,\n only: options.only.length > 0 ? options.only : undefined,\n dryRun,\n });\n\n const text =\n format === \"json\"\n ? renderUpdateJson(run)\n : renderUpdatePretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n // The diffs are the point of a dry run; a real run prints\n // what it rewrote and leaves the file to say the rest.\n showDiff: dryRun,\n });\n const stdinPage = pageToStdout ? run.pages.find((page) => page.content !== undefined) : undefined;\n if (stdinPage?.content !== undefined) {\n process.stdout.write(stdinPage.content);\n process.stderr.write(`${text}\\n`);\n } else {\n process.stdout.write(`${text}\\n`);\n }\n // Exit 1 when something was skipped with an error-severity finding:\n // work left undone, `fill`'s precedent.\n process.exitCode = run.exitCode;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"remove\")\n .description(\"Remove the named citations from the given pages, markers and all\")\n .argument(\n \"[paths...]\",\n \"files, directories, or globs to remove from (use - for stdin)\",\n )\n .option(\n \"--collection <name>\",\n \"configured collection to run over; repeatable\",\n collect,\n [],\n )\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"remove from files .gitignore covers\")\n .option(\n \"--only <id>\",\n \"the entry to remove, by id or by pointer (/citations/N); required, and repeatable\",\n collect,\n [],\n )\n .option(\"--dry-run\", \"print the diffs and the report; write nothing\")\n .option(\n \"-f, --format <format>\",\n `output: ${REMOVE_FORMATS.join(\" | \")}`,\n \"pretty\",\n )\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni cite remove docs/limits.md --only fetch-timeout\",\n \" manni cite remove docs/ --only fetch-timeout --only retries --dry-run\",\n \" manni cite remove --collection site --only /citations/3 -f json\",\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: RemoveCliOptions, command: Command) => {\n try {\n const format = options.format;\n if (!isRemoveFormat(format)) {\n throw new CiteError(\n `Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`,\n );\n }\n const exts = options.ext ? splitList(options.ext) : undefined;\n const usingStdin = paths.includes(STDIN_TOKEN);\n const stdinContent = usingStdin ? await readStdin() : undefined;\n const dryRun = Boolean(options.dryRun);\n // With `-` the rewritten page owns stdout, exactly as on `update -`.\n const pageToStdout = usingStdin && !dryRun;\n const cwd = process.cwd();\n\n const run = await runRemove({\n inputs: paths,\n collection: options.collection,\n exts,\n exclude: options.exclude,\n as: options.as,\n ...configOption(options.config),\n onConfigLoaded: reportConfig(format === \"pretty\" && !pageToStdout, cwd),\n stdinContent,\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n onNotice: notice,\n only: options.only,\n dryRun,\n });\n\n const text =\n format === \"json\"\n ? renderRemoveJson(run)\n : renderRemovePretty(run, {\n color: colorFor(command, process.stdout.isTTY),\n // The diffs are the point of a dry run; a real run prints\n // what it removed and leaves the file to say the rest.\n showDiff: dryRun,\n dryRun,\n });\n const stdinPage = pageToStdout ? run.pages.find((page) => page.content !== undefined) : undefined;\n if (stdinPage?.content !== undefined) {\n process.stdout.write(stdinPage.content);\n process.stderr.write(`${text}\\n`);\n } else {\n process.stdout.write(`${text}\\n`);\n }\n // Everything named was removed, or previewed: there is no exit 1.\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n return program;\n}\n","/**\n * SARIF for `check`. Meta's renderer builds the envelope, the\n * repository-relative uris and the fingerprints the baseline shares, from the\n * adapted results. What it cannot know is what a cite rule is: it describes\n * every rule as a schema keyword, links meta's fix page, and prefixes each\n * message with the JSON Pointer of the entry, `(root)` for a finding about no\n * entry. This renderer replaces those three with the cite rule's own\n * description, a link to its row of the citations reference, and the message\n * the github annotation carries, which names the citation the pointer only\n * numbered. A message is no part of a fingerprint, so the baseline is\n * unaffected.\n */\nimport { renderSarif, type ValidationResult } from \"../../meta/index.js\";\nimport { errorSite } from \"../core/adapt.js\";\nimport { RULE_ID_PREFIX, isCiteRule } from \"../core/severity.js\";\nimport type { CheckRun, CiteRule } from \"../types.js\";\nimport { findingMessage } from \"./github.js\";\n\nconst INFORMATION_URI = \"https://hawkeyexl.github.io/manni/cite/\";\n\n/** The citations reference, whose rule tables anchor each row by rule name. */\nconst RULES_URI = \"https://hawkeyexl.github.io/manni/cite/reference/citations/\";\n\n/** What each rule is, as the citations reference's tables say it. */\nconst RULE_DESCRIPTIONS: Readonly<Record<CiteRule, string>> = {\n \"source-moved\": \"The cited source lines moved to one other place in the file.\",\n \"source-moved-ambiguous\": \"The cited source lines now match at several places in the file.\",\n \"source-changed\": \"The cited source lines changed since the citation pinned them.\",\n \"source-never-true\": \"The pin never matched the source at the recorded commit.\",\n \"source-missing\": \"The cited source file is not tracked under the root, or cannot be decrypted.\",\n \"claim-moved\": \"The cited sentence moved to other lines of the page.\",\n \"claim-moved-ambiguous\": \"The cited sentence now appears at several places on the page.\",\n \"claim-reanchored\": \"The cited sentence's words are unchanged since the claim's baseline, and only its layout moved.\",\n \"claim-changed\": \"The cited sentence was edited since the citation pinned it.\",\n \"marker-orphan\": \"A marker names an id no citation has.\",\n \"marker-invalid\": \"A marker is malformed, or the page has too many markers.\",\n \"marker-repeated\": \"Two markers name the same citation id.\",\n \"marker-misplaced\": \"A marker line sits inside the paragraph it anchors, and splits it.\",\n \"anchor-invalid\": \"A citation's anchor cannot work.\",\n \"entry-invalid\": \"A citation entry is malformed.\",\n \"quote-drift\": \"A quoted block no longer reproduces its source.\",\n};\n\n/**\n * The label meta's reporters put before a message: `(root) ` for a finding\n * about no entry, `/citations/N ` for one about an entry. Nothing else ever\n * opens a cite finding's adapted message.\n */\nexport const ENTRY_LABEL = /^(?:\\(root\\)|\\/citations\\/\\d+) /;\n\nexport interface SarifRule {\n id: string;\n shortDescription: { text: string };\n helpUri?: string;\n}\n\n/** As much of meta's SARIF as this renderer and its tests read back. */\nexport interface SarifLog {\n runs: {\n tool: { driver: { informationUri: string; rules: SarifRule[] } };\n results: { ruleId: string; message: { text: string } }[];\n }[];\n}\n\n/**\n * The adapted results with each message rewritten as the github annotation\n * says it. An error is paired with its finding by rule, entry, line and\n * message, as the baseline split pairs them; the baseline has already\n * dropped the errors it forgives.\n */\nexport function withFindingMessages(run: CheckRun): ValidationResult[] {\n return run.results.map((result) => {\n const page = run.pages.find((p) => p.file === result.file);\n if (page === undefined) return result;\n const errors = result.errors.map((error) => {\n const finding = page.findings.find(\n (f) =>\n f.rule === error.keyword &&\n (f.index === undefined ? \"\" : `/citations/${String(f.index)}`) === error.instancePath &&\n f.message === error.message &&\n (errorSite(f).line ?? null) === (error.line ?? null),\n );\n return finding === undefined ? error : { ...error, message: findingMessage(finding) };\n });\n return { ...result, errors };\n });\n}\n\n/** A rule as the citation tool describes it. */\nfunction describe(rule: SarifRule): SarifRule {\n const name = rule.id.slice(RULE_ID_PREFIX.length + 1);\n if (!isCiteRule(name)) return rule;\n return { id: rule.id, shortDescription: { text: RULE_DESCRIPTIONS[name] }, helpUri: `${RULES_URI}#${name}` };\n}\n\nexport function renderCheckSarif(run: CheckRun, opts: { onNotice?: (message: string) => void } = {}): string {\n const log = JSON.parse(\n renderSarif(withFindingMessages(run), {\n frame: run.frame,\n ...(opts.onNotice === undefined ? {} : { onNotice: opts.onNotice }),\n }),\n ) as SarifLog;\n for (const sarifRun of log.runs) {\n sarifRun.tool.driver.informationUri = INFORMATION_URI;\n sarifRun.tool.driver.rules = sarifRun.tool.driver.rules.map(describe);\n for (const result of sarifRun.results) result.message.text = result.message.text.replace(ENTRY_LABEL, \"\");\n }\n return JSON.stringify(log, null, 2);\n}\n","/**\n * JUnit for `check`: meta's renderer over the adapted results, under the\n * `manni.cite` classname, with each failure's message the one the github\n * annotation carries.\n * Meta's renderer opens every message with the entry's JSON Pointer, `(root)`\n * for a finding about no entry, which says nothing about a citation. The\n * failure's `type` is already the rule id.\n */\nimport { renderJunit } from \"../../meta/index.js\";\nimport type { CheckRun } from \"../types.js\";\nimport { ENTRY_LABEL, withFindingMessages } from \"./sarif.js\";\n\n/** JUnit `classname` for the citation tool's findings. */\nexport const JUNIT_CLASSNAME = \"manni.cite\";\n\n/** A `message=\"` attribute's opening label. The value is escaped, so `message=\"` opens nothing else. */\nconst MESSAGE_LABEL = new RegExp(`message=\"${ENTRY_LABEL.source.replace(/^\\^/, \"\")}`, \"g\");\n\nexport function renderCheckJunit(run: CheckRun): string {\n return renderJunit(withFindingMessages(run), { frame: run.frame, classname: JUNIT_CLASSNAME }).replace(\n MESSAGE_LABEL,\n 'message=\"',\n );\n}\n"],"mappings":"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","names":["splitPageArgument"]}
@@ -3,30 +3,27 @@ import {
3
3
  KeyError,
4
4
  runKeyRotate,
5
5
  runKeySet
6
- } from "./chunk-F2OVHJNC.js";
7
- import "./chunk-7ZUCEMCY.js";
8
- import "./chunk-JQU7FHYH.js";
9
- import "./chunk-XWFNO5PO.js";
10
- import "./chunk-NGK3N6F2.js";
11
- import "./chunk-TA42STP7.js";
6
+ } from "./chunk-4Z2MN5FR.js";
7
+ import "./chunk-ZEXGGGLW.js";
8
+ import "./chunk-NZ6TNSCU.js";
9
+ import "./chunk-MIBWI5H7.js";
10
+ import "./chunk-GCC52YZD.js";
11
+ import "./chunk-2ZWTSRE5.js";
12
12
  import "./chunk-PCE7QHXJ.js";
13
13
  import "./chunk-77AINBYM.js";
14
- import "./chunk-UK2I3ACY.js";
14
+ import "./chunk-IZBBXKMJ.js";
15
15
  import "./chunk-IKEWBMCN.js";
16
- import "./chunk-TU2WUBVZ.js";
17
- import "./chunk-TVIX653Q.js";
18
- import "./chunk-QCBICNKC.js";
19
- import "./chunk-3YHAYXBC.js";
16
+ import "./chunk-ZKCNPKUO.js";
17
+ import "./chunk-CR3HZERW.js";
20
18
  import {
21
19
  collect,
22
20
  explicitFalse,
23
21
  splitList
24
- } from "./chunk-NAZRLJAK.js";
25
- import "./chunk-HVFR66GQ.js";
22
+ } from "./chunk-5UB47BEV.js";
26
23
  import {
27
24
  COMMON_FORMAT_LIST
28
- } from "./chunk-TCC737IS.js";
29
- import "./chunk-527HHQPS.js";
25
+ } from "./chunk-5VWDIWOH.js";
26
+ import "./chunk-MSMB6XOS.js";
30
27
  import {
31
28
  fail
32
29
  } from "./chunk-YEUYKR62.js";
@@ -35,12 +32,14 @@ import {
35
32
  shouldColor
36
33
  } from "./chunk-RNVYGWIC.js";
37
34
  import "./chunk-MNH7QO4Z.js";
35
+ import "./chunk-XKBEHKWO.js";
38
36
  import {
39
37
  notice
40
- } from "./chunk-Q35YIDBV.js";
38
+ } from "./chunk-HX44GB4Z.js";
39
+ import "./chunk-QCHVR4ZM.js";
41
40
  import {
42
41
  package_default
43
- } from "./chunk-6XTQDFGP.js";
42
+ } from "./chunk-YSCZL4U5.js";
44
43
  import "./chunk-OWBRDNRZ.js";
45
44
  import "./chunk-G3T47CFV.js";
46
45
  import "./chunk-2H7UOFLK.js";
@@ -229,4 +228,4 @@ function buildProgram() {
229
228
  export {
230
229
  buildProgram
231
230
  };
232
- //# sourceMappingURL=cli-AAG3N4NB.js.map
231
+ //# sourceMappingURL=cli-MTDGQIIV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/key/cli.ts","../src/key/reporters/json.ts","../src/key/reporters/pretty.ts"],"sourcesContent":["/**\n * The `key` domain's commander program. Mounted by `src/cli.ts` under\n * `manni key`; no entry point of its own. Proposal 0045 extends 0034's\n * grammar: a domain is a tool, or a family resource with verbs. `key` is the\n * second kind, with two verbs, `set` and `rotate`, and no default subcommand.\n *\n * clig.dev as every tool has it: the report to stdout, diagnostics to stderr,\n * colour only on a TTY and never under `NO_COLOR`/`--no-color`, exit `0` done,\n * `1` a value that could not be re-encrypted, `2` operational/usage. Nothing\n * this program prints is ever a key.\n */\nimport { Command } from \"commander\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport { collect, explicitFalse, splitList } from \"../shared/cli-options.js\";\nimport { shouldColor } from \"../shared/color.js\";\nimport { fail } from \"../shared/run.js\";\nimport { notice } from \"../shared/warn.js\";\nimport { COMMON_FORMAT_LIST } from \"../meta/internal.js\";\nimport { runKeyRotate } from \"./commands/rotate.js\";\nimport { runKeySet } from \"./commands/set.js\";\nimport { KeyError } from \"./errors.js\";\nimport { renderRotateJson } from \"./reporters/json.js\";\nimport { BASELINE_NOTICE, renderRotatePretty, setMessage } from \"./reporters/pretty.js\";\n\nconst ROTATE_FORMATS = [\"pretty\", \"json\"] as const;\ntype RotateFormat = (typeof ROTATE_FORMATS)[number];\n\nfunction isRotateFormat(value: string): value is RotateFormat {\n return (ROTATE_FORMATS as readonly string[]).includes(value);\n}\n\n/** What commander hands `set`'s action. */\ninterface SetCliOptions {\n /** `-c, --config <path>`. */\n config?: string;\n dryRun?: boolean;\n}\n\n/**\n * What commander hands `rotate`'s action. The `--no-<thing>` flags are\n * `boolean` and never `undefined`: commander supplies `true` when the flag is\n * absent, so only the explicit `false` travels to the core (`explicitFalse`).\n */\ninterface RotateCliOptions {\n to?: string;\n /** `--collection <name>`, repeatable; commander's default value is `[]`. */\n collection: string[];\n /** `--ext <list>`; the command splits it. */\n ext?: string;\n /** `--exclude <glob>`, repeatable; commander's default value is `[]`. */\n exclude: string[];\n as?: string;\n config?: string;\n allowEmpty?: boolean;\n /** `--no-gitignore`. */\n gitignore: boolean;\n root?: string;\n dryRun?: boolean;\n /** `-f, --format <format>`. Always a string: the declaration has a default. */\n format: string;\n}\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"key\")\n .description(\"Set and rotate the family key that encrypted values are encrypted with.\")\n .version(pkg.version, \"-V, --version\")\n .option(\"--no-color\", \"disable colored output\")\n // A pointer, not the whole help screen: the message that precedes it\n // already names the offending flag.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before the `.command()` calls below. `copyInheritedSettings`\n // copies `_exitCallback` by value at subcommand-creation time, so an\n // `exitOverride()` installed afterwards leaves every subcommand still\n // calling `process.exit(1)`.\n .exitOverride();\n\n /** This domain's `--no-color`, wherever the domain is mounted. */\n const color = (): boolean =>\n shouldColor({ noColor: program.opts().color === false, isTTY: process.stdout.isTTY });\n\n program\n .command(\"set\")\n .description(\"Write the family encryption key to manni.config.yaml; generate one when no value is given\")\n .argument(\"[value]\", \"the key, at least 32 hex or base64url characters (default: 64 random hex)\")\n .option(\n \"-c, --config <path>\",\n \"the config file to write (default: the nearest manni.config.yaml, else a new one at the git root)\",\n )\n .option(\"--dry-run\", \"say what would be written; write nothing\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni key set # generate 256 bits into manni.config.yaml\",\n \" manni key set --dry-run # name the file, write nothing\",\n \" manni key set -c ops/manni.config.yaml 0123456789abcdef0123456789abcdef\",\n ].join(\"\\n\"),\n )\n .action(async (value: string | undefined, options: SetCliOptions) => {\n try {\n const result = await runKeySet({\n value,\n configPath: options.config,\n dryRun: Boolean(options.dryRun),\n onNotice: notice,\n });\n process.stdout.write(`${setMessage(result)}\\n`);\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"rotate\")\n .description(\"Re-encrypt every encrypted value under a new key, then write the key\")\n .argument(\"[paths...]\", \"files, directories, or globs (default: every collection)\")\n .option(\n \"--to <value>\",\n \"the new key (default: 64 random hex); required for a narrowed run and a key from MANNI_ENCRYPTION_KEY\",\n )\n .option(\"--collection <name>\", \"configured collection to run over; repeatable\", collect, [])\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"include files .gitignore covers\")\n .option(\n \"--root <dir>\",\n \"directory cited sources resolve from (default: cite.root from config, else the git root)\",\n )\n .option(\"--dry-run\", \"print what would change; write nothing\")\n .option(\"-f, --format <format>\", `output: ${ROTATE_FORMATS.join(\" | \")}`, \"pretty\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni key rotate # every collection, then the key\",\n \" manni key rotate --dry-run # see every change first\",\n ' manni key rotate --collection site --to \"$NEW_KEY\" # part of the family',\n ' MANNI_ENCRYPTION_KEY=… manni key rotate --to \"$NEW_KEY\"',\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: RotateCliOptions) => {\n try {\n const format = options.format;\n if (!isRotateFormat(format)) {\n throw new KeyError(`Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`);\n }\n const result = await runKeyRotate({\n inputs: paths,\n collection: options.collection,\n to: options.to,\n exts: options.ext ? splitList(options.ext) : undefined,\n exclude: options.exclude,\n as: options.as,\n configPath: options.config,\n // `undefined` rather than `false` when absent.\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n root: options.root,\n dryRun: Boolean(options.dryRun),\n onNotice: notice,\n });\n if (format === \"json\") {\n process.stdout.write(`${renderRotateJson(result)}\\n`);\n // stdout is the JSON's; the notice is a diagnostic.\n if (result.baselineStale) notice(BASELINE_NOTICE);\n } else {\n process.stdout.write(`${renderRotatePretty(result, { color: color() })}\\n`);\n }\n process.exitCode = result.exitCode;\n } catch (err) {\n fail(err);\n }\n });\n\n return program;\n}\n","/**\n * JSON output for `key rotate`: every page and every local external-metadata\n * manifest with something encrypted in it, each value's full ciphertext\n * before and after, and the counts. The key is never in it.\n */\nimport type { KeyRotateResult } from \"../types.js\";\n\nexport function renderRotateJson(result: KeyRotateResult): string {\n return JSON.stringify(\n {\n pages: result.pages,\n manifests: result.manifests,\n reencrypted: result.reencrypted,\n skipped: result.skipped,\n keyWritten: result.keyWritten,\n },\n null,\n 2,\n );\n}\n","/**\n * Pretty output for `key set` and `key rotate`. A ciphertext is shown as `~`\n * and its first four characters, then `…`, with a citation's line suffix\n * after it: `~AQx7…`, `~AQm4…:2`. The full values are in `-f json`; the key\n * is in neither. Colour via `shouldColor`; never under `--no-color`/`NO_COLOR`.\n */\nimport { palette } from \"../../shared/color.js\";\nimport type { KeyRotateResult, KeySetResult, RotatedValue, SkippedValue } from \"../types.js\";\n\nexport interface PrettyOptions {\n color: boolean;\n}\n\n/** Said at the end of a writing rotation when a citation baseline exists. */\nexport const BASELINE_NOTICE =\n \"The citation baseline fingerprints id-less encrypted citations by their pin; re-record it with `manni cite check --write-baseline`.\";\n\nconst NARROWED =\n \"Key not written: this run covered part of the family. Finish with a whole run under the same key: `manni key rotate --to <the same value>`.\";\nconst FROM_ENV =\n \"Key not written: it comes from MANNI_ENCRYPTION_KEY. Update the secret to the value you passed.\";\n\nconst plural = (n: number, one: string, many = `${one}s`): string =>\n `${String(n)} ${n === 1 ? one : many}`;\n\n/** What `set` says: the file, never the key. */\nexport function setMessage(result: KeySetResult): string {\n return result.dryRun\n ? `Would write encryptionKey to ${result.source}.`\n : `Encryption key written to ${result.source}.`;\n}\n\n/** `~AQx7…`, and a citation's line suffix after it: `~AQm4…:2`. */\nexport function shortCiphertext(value: string): string {\n // base64url has no `:`, so the first one starts the line suffix.\n const colon = value.indexOf(\":\");\n const token = colon === -1 ? value : value.slice(0, colon);\n const suffix = colon === -1 ? \"\" : value.slice(colon);\n return `${token.slice(0, 5)}…${suffix}`;\n}\n\n/** A metadata value by its pointer; a citation by its id, else where it sits. */\nfunction nameOf(row: RotatedValue | SkippedValue): string {\n if (row.kind === \"metadata\") return row.pointer;\n if (row.id !== undefined) return row.id;\n if (row.index !== undefined) return `/citations/${String(row.index)}`;\n return `line ${String(row.line ?? 0)}`;\n}\n\nfunction closing(result: KeyRotateResult): string | undefined {\n switch (result.outcome) {\n case \"written\":\n return result.configSource === undefined\n ? undefined\n : `Encryption key written to ${result.configSource}.`;\n case \"finished\":\n // Said before the counts: the key was written by the run that stopped.\n return undefined;\n case \"narrowed\":\n return NARROWED;\n case \"env\":\n return FROM_ENV;\n case \"skipped\":\n return result.skipped === 1\n ? \"Key not written: 1 value could not be re-encrypted. Fix it and rotate again.\"\n : `Key not written: ${String(result.skipped)} values could not be re-encrypted. Fix them and rotate again.`;\n case \"dry-run\":\n return \"Dry run: nothing written.\";\n }\n}\n\nexport function renderRotatePretty(result: KeyRotateResult, opts: PrettyOptions): string {\n const c = palette(opts.color);\n const lines: string[] = [];\n for (const page of result.pages) {\n for (const row of page.rewritten) {\n // A metadata value has no line suffix; two spaces keep its arrow in the\n // column a `:L` suffix would take.\n const gap = row.kind === \"metadata\" ? \" \" : \" \";\n lines.push(\n `${page.file}: ${nameOf(row)} ${c.dim(shortCiphertext(row.from))}${gap}-> ${shortCiphertext(row.to)}`,\n );\n }\n for (const row of page.skipped) {\n lines.push(`${page.file}: ${nameOf(row)} ${c.red(\"skipped:\")} ${row.message}`);\n }\n }\n // A manifest value is named by the entry it belongs to and the pointer\n // inside it, so one line says which document's private half moved.\n for (const manifest of result.manifests) {\n for (const row of manifest.rewritten) {\n lines.push(\n `${manifest.file}: ${row.entry}${row.pointer} ${c.dim(shortCiphertext(row.from))} -> ${shortCiphertext(row.to)}`,\n );\n }\n for (const row of manifest.skipped) {\n lines.push(\n `${manifest.file}: ${row.entry}${row.pointer} ${c.red(\"skipped:\")} ${row.message}`,\n );\n }\n }\n if (result.outcome === \"finished\" && result.configSource !== undefined) {\n lines.push(`Finished the interrupted rotation in ${result.configSource}.`);\n }\n const files =\n result.pages.filter((page) => page.rewritten.length > 0).length +\n result.manifests.filter((manifest) => manifest.rewritten.length > 0).length;\n lines.push(\n `${plural(result.reencrypted, \"value\")} re-encrypted in ${plural(files, \"file\")}, ${String(result.skipped)} skipped`,\n );\n const last = closing(result);\n if (last !== undefined) lines.push(result.outcome === \"skipped\" ? c.red(last) : last);\n if (result.baselineStale) lines.push(BASELINE_NOTICE);\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/key/cli.ts","../src/key/reporters/json.ts","../src/key/reporters/pretty.ts"],"sourcesContent":["/**\n * The `key` domain's commander program. Mounted by `src/cli.ts` under\n * `manni key`; no entry point of its own. Proposal 0045 extends 0034's\n * grammar: a domain is a tool, or a family resource with verbs. `key` is the\n * second kind, with two verbs, `set` and `rotate`, and no default subcommand.\n *\n * clig.dev as every tool has it: the report to stdout, diagnostics to stderr,\n * colour only on a TTY and never under `NO_COLOR`/`--no-color`, exit `0` done,\n * `1` a value that could not be re-encrypted, `2` operational/usage. Nothing\n * this program prints is ever a key.\n */\nimport { Command } from \"commander\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport { collect, explicitFalse, splitList } from \"../shared/cli-options.js\";\nimport { shouldColor } from \"../shared/color.js\";\nimport { fail } from \"../shared/run.js\";\nimport { notice } from \"../shared/warn.js\";\nimport { COMMON_FORMAT_LIST } from \"../meta/internal.js\";\nimport { runKeyRotate } from \"./commands/rotate.js\";\nimport { runKeySet } from \"./commands/set.js\";\nimport { KeyError } from \"./errors.js\";\nimport { renderRotateJson } from \"./reporters/json.js\";\nimport { BASELINE_NOTICE, renderRotatePretty, setMessage } from \"./reporters/pretty.js\";\n\nconst ROTATE_FORMATS = [\"pretty\", \"json\"] as const;\ntype RotateFormat = (typeof ROTATE_FORMATS)[number];\n\nfunction isRotateFormat(value: string): value is RotateFormat {\n return (ROTATE_FORMATS as readonly string[]).includes(value);\n}\n\n/** What commander hands `set`'s action. */\ninterface SetCliOptions {\n /** `-c, --config <path>`. */\n config?: string;\n dryRun?: boolean;\n}\n\n/**\n * What commander hands `rotate`'s action. The `--no-<thing>` flags are\n * `boolean` and never `undefined`: commander supplies `true` when the flag is\n * absent, so only the explicit `false` travels to the core (`explicitFalse`).\n */\ninterface RotateCliOptions {\n to?: string;\n /** `--collection <name>`, repeatable; commander's default value is `[]`. */\n collection: string[];\n /** `--ext <list>`; the command splits it. */\n ext?: string;\n /** `--exclude <glob>`, repeatable; commander's default value is `[]`. */\n exclude: string[];\n as?: string;\n config?: string;\n allowEmpty?: boolean;\n /** `--no-gitignore`. */\n gitignore: boolean;\n root?: string;\n dryRun?: boolean;\n /** `-f, --format <format>`. Always a string: the declaration has a default. */\n format: string;\n}\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"key\")\n .description(\"Set and rotate the family key that encrypted values are encrypted with.\")\n .version(pkg.version, \"-V, --version\")\n .option(\"--no-color\", \"disable colored output\")\n // A pointer, not the whole help screen: the message that precedes it\n // already names the offending flag.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before the `.command()` calls below. `copyInheritedSettings`\n // copies `_exitCallback` by value at subcommand-creation time, so an\n // `exitOverride()` installed afterwards leaves every subcommand still\n // calling `process.exit(1)`.\n .exitOverride();\n\n /** This domain's `--no-color`, wherever the domain is mounted. */\n const color = (): boolean =>\n shouldColor({ noColor: program.opts().color === false, isTTY: process.stdout.isTTY });\n\n program\n .command(\"set\")\n .description(\"Write the family encryption key to manni.config.yaml; generate one when no value is given\")\n .argument(\"[value]\", \"the key, at least 32 hex or base64url characters (default: 64 random hex)\")\n .option(\n \"-c, --config <path>\",\n \"the config file to write (default: the nearest manni.config.yaml, else a new one at the git root)\",\n )\n .option(\"--dry-run\", \"say what would be written; write nothing\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni key set # generate 256 bits into manni.config.yaml\",\n \" manni key set --dry-run # name the file, write nothing\",\n \" manni key set -c ops/manni.config.yaml 0123456789abcdef0123456789abcdef\",\n ].join(\"\\n\"),\n )\n .action(async (value: string | undefined, options: SetCliOptions) => {\n try {\n const result = await runKeySet({\n value,\n configPath: options.config,\n dryRun: Boolean(options.dryRun),\n onNotice: notice,\n });\n process.stdout.write(`${setMessage(result)}\\n`);\n process.exitCode = 0;\n } catch (err) {\n fail(err);\n }\n });\n\n program\n .command(\"rotate\")\n .description(\"Re-encrypt every encrypted value under a new key, then write the key\")\n .argument(\"[paths...]\", \"files, directories, or globs (default: every collection)\")\n .option(\n \"--to <value>\",\n \"the new key (default: 64 random hex); required for a narrowed run and a key from MANNI_ENCRYPTION_KEY\",\n )\n .option(\"--collection <name>\", \"configured collection to run over; repeatable\", collect, [])\n .option(\"--ext <list>\", \"comma-separated extensions for directory walks\")\n .option(\"--exclude <glob>\", \"glob to exclude; repeatable\", collect, [])\n .option(\"--as <format>\", \"force an input format for every input\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--allow-empty\", \"treat zero matched files as success\")\n .option(\"--no-gitignore\", \"include files .gitignore covers\")\n .option(\n \"--root <dir>\",\n \"directory cited sources resolve from (default: cite.root from config, else the git root)\",\n )\n .option(\"--dry-run\", \"print what would change; write nothing\")\n .option(\"-f, --format <format>\", `output: ${ROTATE_FORMATS.join(\" | \")}`, \"pretty\")\n .addHelpText(\n \"after\",\n [\n \"\",\n \"Examples:\",\n \" manni key rotate # every collection, then the key\",\n \" manni key rotate --dry-run # see every change first\",\n ' manni key rotate --collection site --to \"$NEW_KEY\" # part of the family',\n ' MANNI_ENCRYPTION_KEY=… manni key rotate --to \"$NEW_KEY\"',\n ].join(\"\\n\"),\n )\n .action(async (paths: string[], options: RotateCliOptions) => {\n try {\n const format = options.format;\n if (!isRotateFormat(format)) {\n throw new KeyError(`Unknown --format \"${format}\". Use ${COMMON_FORMAT_LIST}.`);\n }\n const result = await runKeyRotate({\n inputs: paths,\n collection: options.collection,\n to: options.to,\n exts: options.ext ? splitList(options.ext) : undefined,\n exclude: options.exclude,\n as: options.as,\n configPath: options.config,\n // `undefined` rather than `false` when absent.\n allowEmpty: options.allowEmpty ? true : undefined,\n respectGitignore: explicitFalse(options.gitignore),\n root: options.root,\n dryRun: Boolean(options.dryRun),\n onNotice: notice,\n });\n if (format === \"json\") {\n process.stdout.write(`${renderRotateJson(result)}\\n`);\n // stdout is the JSON's; the notice is a diagnostic.\n if (result.baselineStale) notice(BASELINE_NOTICE);\n } else {\n process.stdout.write(`${renderRotatePretty(result, { color: color() })}\\n`);\n }\n process.exitCode = result.exitCode;\n } catch (err) {\n fail(err);\n }\n });\n\n return program;\n}\n","/**\n * JSON output for `key rotate`: every page and every local external-metadata\n * manifest with something encrypted in it, each value's full ciphertext\n * before and after, and the counts. The key is never in it.\n */\nimport type { KeyRotateResult } from \"../types.js\";\n\nexport function renderRotateJson(result: KeyRotateResult): string {\n return JSON.stringify(\n {\n pages: result.pages,\n manifests: result.manifests,\n reencrypted: result.reencrypted,\n skipped: result.skipped,\n keyWritten: result.keyWritten,\n },\n null,\n 2,\n );\n}\n","/**\n * Pretty output for `key set` and `key rotate`. A ciphertext is shown as `~`\n * and its first four characters, then `…`, with a citation's line suffix\n * after it: `~AQx7…`, `~AQm4…:2`. The full values are in `-f json`; the key\n * is in neither. Colour via `shouldColor`; never under `--no-color`/`NO_COLOR`.\n */\nimport { palette } from \"../../shared/color.js\";\nimport type { KeyRotateResult, KeySetResult, RotatedValue, SkippedValue } from \"../types.js\";\n\nexport interface PrettyOptions {\n color: boolean;\n}\n\n/** Said at the end of a writing rotation when a citation baseline exists. */\nexport const BASELINE_NOTICE =\n \"The citation baseline fingerprints id-less encrypted citations by their pin; re-record it with `manni cite check --write-baseline`.\";\n\nconst NARROWED =\n \"Key not written: this run covered part of the family. Finish with a whole run under the same key: `manni key rotate --to <the same value>`.\";\nconst FROM_ENV =\n \"Key not written: it comes from MANNI_ENCRYPTION_KEY. Update the secret to the value you passed.\";\n\nconst plural = (n: number, one: string, many = `${one}s`): string =>\n `${String(n)} ${n === 1 ? one : many}`;\n\n/** What `set` says: the file, never the key. */\nexport function setMessage(result: KeySetResult): string {\n return result.dryRun\n ? `Would write encryptionKey to ${result.source}.`\n : `Encryption key written to ${result.source}.`;\n}\n\n/** `~AQx7…`, and a citation's line suffix after it: `~AQm4…:2`. */\nexport function shortCiphertext(value: string): string {\n // base64url has no `:`, so the first one starts the line suffix.\n const colon = value.indexOf(\":\");\n const token = colon === -1 ? value : value.slice(0, colon);\n const suffix = colon === -1 ? \"\" : value.slice(colon);\n return `${token.slice(0, 5)}…${suffix}`;\n}\n\n/** A metadata value by its pointer; a citation by its id, else where it sits. */\nfunction nameOf(row: RotatedValue | SkippedValue): string {\n if (row.kind === \"metadata\") return row.pointer;\n if (row.id !== undefined) return row.id;\n if (row.index !== undefined) return `/citations/${String(row.index)}`;\n return `line ${String(row.line ?? 0)}`;\n}\n\nfunction closing(result: KeyRotateResult): string | undefined {\n switch (result.outcome) {\n case \"written\":\n return result.configSource === undefined\n ? undefined\n : `Encryption key written to ${result.configSource}.`;\n case \"finished\":\n // Said before the counts: the key was written by the run that stopped.\n return undefined;\n case \"narrowed\":\n return NARROWED;\n case \"env\":\n return FROM_ENV;\n case \"skipped\":\n return result.skipped === 1\n ? \"Key not written: 1 value could not be re-encrypted. Fix it and rotate again.\"\n : `Key not written: ${String(result.skipped)} values could not be re-encrypted. Fix them and rotate again.`;\n case \"dry-run\":\n return \"Dry run: nothing written.\";\n }\n}\n\nexport function renderRotatePretty(result: KeyRotateResult, opts: PrettyOptions): string {\n const c = palette(opts.color);\n const lines: string[] = [];\n for (const page of result.pages) {\n for (const row of page.rewritten) {\n // A metadata value has no line suffix; two spaces keep its arrow in the\n // column a `:L` suffix would take.\n const gap = row.kind === \"metadata\" ? \" \" : \" \";\n lines.push(\n `${page.file}: ${nameOf(row)} ${c.dim(shortCiphertext(row.from))}${gap}-> ${shortCiphertext(row.to)}`,\n );\n }\n for (const row of page.skipped) {\n lines.push(`${page.file}: ${nameOf(row)} ${c.red(\"skipped:\")} ${row.message}`);\n }\n }\n // A manifest value is named by the entry it belongs to and the pointer\n // inside it, so one line says which document's private half moved.\n for (const manifest of result.manifests) {\n for (const row of manifest.rewritten) {\n lines.push(\n `${manifest.file}: ${row.entry}${row.pointer} ${c.dim(shortCiphertext(row.from))} -> ${shortCiphertext(row.to)}`,\n );\n }\n for (const row of manifest.skipped) {\n lines.push(\n `${manifest.file}: ${row.entry}${row.pointer} ${c.red(\"skipped:\")} ${row.message}`,\n );\n }\n }\n if (result.outcome === \"finished\" && result.configSource !== undefined) {\n lines.push(`Finished the interrupted rotation in ${result.configSource}.`);\n }\n const files =\n result.pages.filter((page) => page.rewritten.length > 0).length +\n result.manifests.filter((manifest) => manifest.rewritten.length > 0).length;\n lines.push(\n `${plural(result.reencrypted, \"value\")} re-encrypted in ${plural(files, \"file\")}, ${String(result.skipped)} skipped`,\n );\n const last = closing(result);\n if (last !== undefined) lines.push(result.outcome === \"skipped\" ? c.red(last) : last);\n if (result.baselineStale) lines.push(BASELINE_NOTICE);\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
@@ -22,10 +22,12 @@ import {
22
22
  matchesFileGlob,
23
23
  readConfigFile,
24
24
  selectCollections
25
- } from "./chunk-Q35YIDBV.js";
25
+ } from "./chunk-XKBEHKWO.js";
26
+ import "./chunk-HX44GB4Z.js";
27
+ import "./chunk-QCHVR4ZM.js";
26
28
  import {
27
29
  package_default
28
- } from "./chunk-6XTQDFGP.js";
30
+ } from "./chunk-YSCZL4U5.js";
29
31
  import {
30
32
  programName
31
33
  } from "./chunk-OWBRDNRZ.js";
@@ -1200,4 +1202,4 @@ export {
1200
1202
  resolveCrawl,
1201
1203
  resolveMaxPages
1202
1204
  };
1203
- //# sourceMappingURL=cli-E3H6ZP4I.js.map
1205
+ //# sourceMappingURL=cli-NM6FZ54R.js.map