@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
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ TracevalsError
4
+ } from "./chunk-UKZNLVJW.js";
5
+ import {
6
+ noticeOnce
7
+ } from "./chunk-HX44GB4Z.js";
8
+ import {
9
+ assertKnownProvider,
10
+ assertLocalFlag,
11
+ assertModelHasProvider,
12
+ localNotice,
13
+ providerSpecFor,
14
+ resolveIdentity,
15
+ selectProvider
16
+ } from "./chunk-QCHVR4ZM.js";
17
+ import {
18
+ errorMessage
19
+ } from "./chunk-G3T47CFV.js";
20
+
21
+ // src/tracevals/judge/provider.ts
22
+ import {
23
+ makeProvider as makeInferenceProvider,
24
+ mockVerdict
25
+ } from "@hawkeyexl/inference";
26
+ var JEV = "jev";
27
+ var JEV_OUT_OF_LOOP = "jev answers decisions only, so it cannot extract rules or write verdicts. Use it as tracevals.conformance.hook.provider.";
28
+ var CONFIG_KEY = "tracevals.provider";
29
+ var toTracevalsError = (message) => new TracevalsError(message);
30
+ function selectProvider2(config, flags = {}, ev = {}) {
31
+ assertLocalFlag(flags, toTracevalsError);
32
+ return selectProvider(flags, [
33
+ {
34
+ ...ev.provider !== void 0 ? { provider: ev.provider } : {},
35
+ ...ev.model !== void 0 ? { model: ev.model } : {},
36
+ ...ev.origin !== void 0 ? { origin: ev.origin } : {}
37
+ },
38
+ ...configLevels(config)
39
+ ]);
40
+ }
41
+ function selectHookProvider(config) {
42
+ const hook = config.conformance?.hook;
43
+ return selectProvider({}, [
44
+ {
45
+ ...hook?.provider != null ? { provider: hook.provider } : {},
46
+ ...hook?.model != null ? { model: hook.model } : {},
47
+ origin: "tracevals.conformance.hook.provider"
48
+ },
49
+ ...configLevels(config)
50
+ ]);
51
+ }
52
+ function configLevels(config) {
53
+ return [
54
+ {
55
+ ...config.provider !== null ? { provider: config.provider } : {},
56
+ ...config.model !== null ? { model: config.model } : {},
57
+ origin: CONFIG_KEY
58
+ },
59
+ {
60
+ ...config.providers.provider !== void 0 ? { provider: config.providers.provider } : {},
61
+ ...config.providers.model !== void 0 ? { model: config.providers.model } : {},
62
+ origin: "providers.provider"
63
+ }
64
+ ];
65
+ }
66
+ function announceSelection(selection) {
67
+ const message = localNotice(selection);
68
+ if (message !== void 0) noticeOnce(message);
69
+ }
70
+ function assertProviderSelection(selection) {
71
+ if (selection.provider === JEV) throw new TracevalsError(JEV_OUT_OF_LOOP);
72
+ assertKnownProvider(selection.provider, toTracevalsError);
73
+ assertModelHasProvider(selection.provider, selection.model, CONFIG_KEY, toTracevalsError);
74
+ }
75
+ function providerSpecFor2(config, selection, options = {}) {
76
+ const spec = providerSpecFor(config.providers, selection);
77
+ switch (selection.provider) {
78
+ case "anthropic":
79
+ return { ...spec, anthropic: { toolName: "record_verdict" } };
80
+ case "openai":
81
+ return { ...spec, openai: { schemaName: "verdict" } };
82
+ case "llama-cpp":
83
+ return {
84
+ ...spec,
85
+ llamaCpp: { ...spec.llamaCpp, ...options.host ?? { host: "connect" } }
86
+ };
87
+ case "mock":
88
+ return {
89
+ ...spec,
90
+ mockResponses: options.mockResponses ?? [mockVerdict("pass", 0.95)]
91
+ };
92
+ default:
93
+ return spec;
94
+ }
95
+ }
96
+ async function resolveProviderIdentity(config, flags = {}, ev = {}) {
97
+ const selection = selectProvider2(config, flags, ev);
98
+ assertProviderSelection(selection);
99
+ return resolveSelectionIdentity(config, selection);
100
+ }
101
+ async function resolveSelectionIdentity(config, selection) {
102
+ const { provider, model } = selection;
103
+ assertKnownProvider(provider, toTracevalsError, { decisions: true });
104
+ assertModelHasProvider(provider, model, CONFIG_KEY, toTracevalsError);
105
+ announceSelection(selection);
106
+ return resolveIdentity(
107
+ providerSpecFor2(config, { provider, model: model ?? null }),
108
+ toTracevalsError
109
+ );
110
+ }
111
+ function constructProvider(config, identity, options = {}) {
112
+ if (identity.provider === JEV) {
113
+ const keyEnv = config.providers.jev?.apiKeyEnv ?? "TYPESAFE_API_KEY";
114
+ const key = process.env[keyEnv];
115
+ if (key === void 0 || key === "") {
116
+ throw new TracevalsError(`jev needs an API key in ${keyEnv}`);
117
+ }
118
+ }
119
+ try {
120
+ return makeInferenceProvider(providerSpecFor2(config, identity, options));
121
+ } catch (e) {
122
+ throw new TracevalsError(errorMessage(e));
123
+ }
124
+ }
125
+ async function makeJudgeProvider(config, flags = {}, ev = {}, options = {}) {
126
+ return constructProvider(
127
+ config,
128
+ await resolveProviderIdentity(config, flags, ev),
129
+ options
130
+ );
131
+ }
132
+
133
+ export {
134
+ JEV,
135
+ JEV_OUT_OF_LOOP,
136
+ selectProvider2 as selectProvider,
137
+ selectHookProvider,
138
+ announceSelection,
139
+ assertProviderSelection,
140
+ providerSpecFor2 as providerSpecFor,
141
+ resolveProviderIdentity,
142
+ resolveSelectionIdentity,
143
+ constructProvider,
144
+ makeJudgeProvider
145
+ };
146
+ //# sourceMappingURL=chunk-BWCWTHYS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tracevals/judge/provider.ts"],"sourcesContent":["/**\n * Choosing the provider and model, and building the shared inference\n * library's `ProviderSpec` for it.\n *\n * The providers themselves live in `@hawkeyexl/inference` (ADR 01006). The\n * names a provider may have, the two refusals, `--local`, the detection call,\n * the level-bound precedence and the mapping of the family's `providers:`\n * connection settings are `src/shared/providers.ts`, the same code\n * `manni meta fill` and `manni docevals` run. What stays here is what only\n * manni tracevals can decide: which levels it reads (a flag, an eval's own\n * `provider:`/`model:`, `tracevals.provider`/`model`, then the family's\n * `providers:`), and the judge-shaped options a verdict call wants.\n *\n * No model id is named in this file. A model the tool pinned would go stale\n * the week the provider shipped a better one, and would override the default\n * the library keeps current.\n */\nimport {\n makeProvider as makeInferenceProvider,\n mockVerdict,\n type InferenceProvider,\n type MockResponse,\n type ProviderName as ConcreteProvider,\n type ProviderSelector,\n type ProviderSpec,\n} from \"@hawkeyexl/inference\";\nimport { TracevalsError } from \"../types.js\";\nimport type { HostSetting } from \"../rules/host.js\";\nimport type { TracevalsConfig } from \"../core/config.js\";\nimport {\n assertKnownProvider,\n assertLocalFlag,\n assertModelHasProvider,\n localNotice,\n providerSpecFor as sharedProviderSpecFor,\n resolveIdentity,\n selectProvider as selectFromLevels,\n type ProviderChoice,\n type ProviderFlags,\n type ProviderSelection,\n} from \"../../shared/providers.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { noticeOnce } from \"../../shared/warn.js\";\n\nexport type { MockResponse, ProviderChoice, ProviderFlags, ProviderSelection };\n\n/** The decide-only provider (proposal 0079). */\nexport const JEV = \"jev\";\n\n/** Why jev cannot serve out of the loop, and where it goes instead. */\nexport const JEV_OUT_OF_LOOP =\n \"jev answers decisions only, so it cannot extract rules or write verdicts. Use it as tracevals.conformance.hook.provider.\";\n\n/** The key a tracevals user writes, named by the refusal a bare model gets. */\nconst CONFIG_KEY = \"tracevals.provider\";\n\nconst toTracevalsError = (message: string): Error => new TracevalsError(message);\n\n/** What a caller wants of the provider beyond which one it is. */\nexport interface JudgeProviderOptions {\n /**\n * Responses for the `mock` seam. The default is verdict-shaped, which suits\n * judging; callers with a different response schema (criteria proposals,\n * say) must supply their own. `mock` is accepted when named but never\n * offered, so nothing that lists providers mentions it.\n */\n mockResponses?: MockResponse[];\n /**\n * How a `llama-cpp` provider reaches the model host. Unset, it connects to\n * a running host and never starts one, which is every run by hand.\n */\n host?: HostSetting;\n}\n\n/**\n * The provider and model in force: a flag, then the eval's own choice, then\n * `tracevals.provider`/`model`, then the family's `providers.provider`/`model`,\n * then `auto`. A model is carried only to the provider its own level names, so\n * an eval that names a different provider takes that provider's default\n * instead of a model it cannot run (`selectProvider` in the shared module).\n *\n * `--local` runs llama-cpp over all of them. A `--provider` it contradicts is\n * refused here, so no path selects past it. `ev.origin` names the eval in the\n * notice for a provider `--local` replaced; the caller knows its artifact.\n */\nexport function selectProvider(\n config: TracevalsConfig,\n flags: ProviderFlags = {},\n ev: ProviderChoice = {},\n): ProviderSelection {\n assertLocalFlag(flags, toTracevalsError);\n return selectFromLevels(flags, [\n {\n ...(ev.provider !== undefined ? { provider: ev.provider } : {}),\n ...(ev.model !== undefined ? { model: ev.model } : {}),\n ...(ev.origin !== undefined ? { origin: ev.origin } : {}),\n },\n ...configLevels(config),\n ]);\n}\n\n/**\n * The judge inside a hook (proposal 0079, \"Two model roles\"):\n * `conformance.hook.provider`/`model`, then `tracevals.provider`/`model`, then\n * the family's `providers:`, then `auto`. No flag reaches it, because a hook\n * has no command line. A hook level naming only a model lends it to whichever\n * provider wins, as every level does.\n */\nexport function selectHookProvider(config: TracevalsConfig): ProviderSelection {\n const hook = config.conformance?.hook;\n return selectFromLevels({}, [\n {\n ...(hook?.provider != null ? { provider: hook.provider } : {}),\n ...(hook?.model != null ? { model: hook.model } : {}),\n origin: \"tracevals.conformance.hook.provider\",\n },\n ...configLevels(config),\n ]);\n}\n\n/** `tracevals.provider`/`model`, then the family's `providers:`. */\nfunction configLevels(config: TracevalsConfig): ProviderChoice[] {\n return [\n {\n ...(config.provider !== null ? { provider: config.provider } : {}),\n ...(config.model !== null ? { model: config.model } : {}),\n origin: CONFIG_KEY,\n },\n {\n ...(config.providers.provider !== undefined\n ? { provider: config.providers.provider }\n : {}),\n ...(config.providers.model !== undefined ? { model: config.providers.model } : {}),\n origin: \"providers.provider\",\n },\n ];\n}\n\n/**\n * Say what `--local` set aside, once per source. Called where a selection is\n * about to be used, never where it is only checked, so a run that sends\n * nothing to a model says nothing.\n */\nexport function announceSelection(selection: ProviderSelection): void {\n const message = localNotice(selection);\n if (message !== undefined) noticeOnce(message);\n}\n\n/**\n * Refuse a selection that cannot be right, with `manni meta fill`'s messages:\n * an unknown name, or a model under `auto`. Both are `TracevalsError`s, which\n * is what maps them to exit 2.\n */\nexport function assertProviderSelection(selection: ProviderSelection): void {\n // Every caller of this check generates: `run`'s and `calibrate`'s verdicts,\n // `fill`'s proposals, and rule extraction. Only the turn judge may decide.\n if (selection.provider === JEV) throw new TracevalsError(JEV_OUT_OF_LOOP);\n assertKnownProvider(selection.provider, toTracevalsError);\n assertModelHasProvider(selection.provider, selection.model, CONFIG_KEY, toTracevalsError);\n}\n\n/**\n * The spec for a selection, with the family's connection settings for the\n * provider it names, and under `auto` the settings detection reads.\n */\nexport function providerSpecFor(\n config: TracevalsConfig,\n selection: { provider: ProviderSelector; model: string | null },\n options: JudgeProviderOptions = {},\n): ProviderSpec {\n const spec = sharedProviderSpecFor(config.providers, selection);\n switch (selection.provider) {\n case \"anthropic\":\n // A verdict-shaped tool name steers the model better than a generic\n // one, and it is free to keep.\n return { ...spec, anthropic: { toolName: \"record_verdict\" } };\n case \"openai\":\n return { ...spec, openai: { schemaName: \"verdict\" } };\n case \"llama-cpp\":\n return {\n ...spec,\n llamaCpp: { ...spec.llamaCpp, ...(options.host ?? { host: \"connect\" }) },\n };\n case \"mock\":\n return {\n ...spec,\n mockResponses: options.mockResponses ?? [mockVerdict(\"pass\", 0.95)],\n };\n default:\n return spec;\n }\n}\n\n/**\n * The concrete provider and model, WITHOUT constructing the provider: cache\n * keys need it, and a fully cached run must not require an API key.\n *\n * Under `auto` this is where detection runs, exactly as `manni meta fill` runs\n * it, seeing the same connection settings. The model is the RESOLVED one (the\n * provider's default when none was named, a llama-cpp tier's concrete\n * weights), so a library default that changes changes every cache key built\n * from it.\n */\nexport async function resolveProviderIdentity(\n config: TracevalsConfig,\n flags: ProviderFlags = {},\n ev: ProviderChoice = {},\n): Promise<{ provider: ConcreteProvider; model: string }> {\n // Every caller of this generates, so jev is refused here as well as where\n // a command checks its selection up front.\n const selection = selectProvider(config, flags, ev);\n assertProviderSelection(selection);\n return resolveSelectionIdentity(config, selection);\n}\n\n/** `resolveProviderIdentity` for a selection already made. */\nexport async function resolveSelectionIdentity(\n config: TracevalsConfig,\n selection: ProviderSelection,\n): Promise<{ provider: ConcreteProvider; model: string }> {\n const { provider, model } = selection;\n // Generating callers refused jev in assertProviderSelection; reaching here\n // with it means the turn judge, which decides.\n assertKnownProvider(provider, toTracevalsError, { decisions: true });\n assertModelHasProvider(provider, model, CONFIG_KEY, toTracevalsError);\n announceSelection(selection);\n return resolveIdentity(\n providerSpecFor(config, { provider, model: model ?? null }),\n toTracevalsError,\n );\n}\n\n/** Construct a provider for an identity already resolved. */\nexport function constructProvider(\n config: TracevalsConfig,\n identity: { provider: ConcreteProvider; model: string },\n options: JudgeProviderOptions = {},\n): InferenceProvider {\n if (identity.provider === JEV) {\n // Checked here, so the message names the variable a user sets rather than\n // the library's wording for it.\n const keyEnv = config.providers.jev?.apiKeyEnv ?? \"TYPESAFE_API_KEY\";\n const key = process.env[keyEnv];\n if (key === undefined || key === \"\") {\n throw new TracevalsError(`jev needs an API key in ${keyEnv}`);\n }\n }\n try {\n return makeInferenceProvider(providerSpecFor(config, identity, options));\n } catch (e) {\n // The library raises its own InferenceError (a missing API key). It must\n // surface as a TracevalsError: `cli.ts`'s fail() maps only that to exit 2,\n // and letting a foreign error type through turns \"no API key configured\"\n // into an unhandled stack trace.\n throw new TracevalsError(errorMessage(e));\n }\n}\n\n/** Select, check, detect and construct: the provider a verb judges with. */\nexport async function makeJudgeProvider(\n config: TracevalsConfig,\n flags: ProviderFlags = {},\n ev: ProviderChoice = {},\n options: JudgeProviderOptions = {},\n): Promise<InferenceProvider> {\n return constructProvider(\n config,\n await resolveProviderIdentity(config, flags, ev),\n options,\n );\n}\n"],"mappings":"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","names":["selectProvider","providerSpecFor"]}
@@ -1,21 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  discoverArtifacts
4
- } from "./chunk-CP4ZM43V.js";
4
+ } from "./chunk-WTEILBKC.js";
5
5
  import {
6
6
  parseHookPayload,
7
7
  readStdin
8
8
  } from "./chunk-TZOYZK2E.js";
9
9
  import {
10
- MANIFEST_VERSION,
11
10
  hashFile,
12
- loadConfig,
13
- makeRedactor,
14
11
  manifestPathFor,
15
12
  relPosix,
16
13
  sha256Hex,
17
14
  writeManifest
18
- } from "./chunk-3R5Y3XOL.js";
15
+ } from "./chunk-OOEMKOX6.js";
16
+ import {
17
+ loadConfig
18
+ } from "./chunk-TPVOOTMN.js";
19
+ import {
20
+ MANIFEST_VERSION,
21
+ makeRedactor
22
+ } from "./chunk-CU57HT2E.js";
19
23
  import {
20
24
  TracevalsError
21
25
  } from "./chunk-UKZNLVJW.js";
@@ -208,4 +212,4 @@ export {
208
212
  runCapture,
209
213
  renderCapture
210
214
  };
211
- //# sourceMappingURL=chunk-QLUMKWQQ.js.map
215
+ //# sourceMappingURL=chunk-C2TJG5KV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tracevals/commands/capture.ts","../src/tracevals/capture/build.ts"],"sourcesContent":["/**\n * `manni tracevals capture` — record what the project's instruction artifacts\n * said, and at which commit, at the moment a session started (ADR 01024).\n *\n * **This is the one write path `run` never takes.** CLAUDE.md states that\n * evaluation is read-only, so the manifest is written by a separate,\n * explicitly-invoked command — the same shape as `fill`. `run` only ever reads\n * a manifest, and degrades cleanly when there is none.\n *\n * Designed to be wired to a `SessionStart` hook, which constrains it in two\n * ways that are not obvious:\n *\n * - **Nothing goes to stdout in hook mode.** Claude Code adds a\n * SessionStart hook's stdout to the model's context, so a report printed\n * there would be a side effect on the very session being observed. In hook\n * mode the report goes to stderr, where an exit-0 hook's output is a debug\n * line and nothing more.\n * - **The transcript is never read.** `transcript_path` is recorded as a\n * correlation key only. At SessionStart the file barely exists, and the\n * reference warns that it lags the conversation in any case.\n */\nimport { resolve } from \"node:path\";\nimport { loadConfig } from \"../core/config.js\";\nimport { buildManifest } from \"../capture/build.js\";\nimport { manifestPathFor, writeManifest } from \"../capture/manifest.js\";\nimport type { SessionManifest } from \"../capture/types.js\";\nimport { parseHookPayload, readStdin } from \"../capture/hook.js\";\nimport type { SummaryFormat } from \"../reporters/index.js\";\nimport { TracevalsError } from \"../types.js\";\n\nexport interface CaptureCommandOptions {\n /**\n * The hook payload. Undefined means \"read stdin\"; an empty string means\n * \"there was none\", which is the hand-run path.\n */\n stdin?: string;\n /** Overrides the payload's `cwd` as the project root to scan. */\n project?: string;\n /** Overrides the payload's `session_id`. */\n sessionId?: string;\n /** Write here instead of `<project>/<capture.dir>/<session-id>.json`. */\n out?: string;\n /** Directory holding manni.config.yaml; defaults to the project root. */\n configDir?: string;\n /** `-c/--config`: read this file instead of discovering one. */\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n format?: SummaryFormat;\n /**\n * Version recorded in the manifest. Passed in rather than read from\n * package.json here: this module is bundled into an unpredictable chunk\n * path, so any relative require of it resolves differently in dist than in\n * src. The CLI, which is not bundled away, supplies it.\n */\n version?: string;\n}\n\nexport interface CaptureCommandResult {\n manifest: SessionManifest;\n /** Where the manifest was written. */\n path: string;\n /** The report, wherever it is destined for. */\n rendered: string;\n /** What the caller should print to stdout — empty in hook mode. */\n stdout: string;\n /** What the caller should print to stderr — the report, in hook mode. */\n stderr: string;\n exitCode: number;\n}\n\nexport async function runCapture(\n options: CaptureCommandOptions = {},\n): Promise<CaptureCommandResult> {\n const raw = options.stdin ?? (await readStdin());\n const hookMode = raw.trim().length > 0;\n const payload = hookMode ? parseHookPayload(raw) : {};\n\n const sessionId = options.sessionId ?? payload.sessionId;\n if (sessionId === undefined) {\n // Without an id the manifest has no name and no join key, and writing one\n // under a guessed name would produce evidence nothing could ever find.\n throw new TracevalsError(\n \"no session id: pipe a Claude Code hook payload on stdin, or pass --session-id\",\n );\n }\n\n const root = resolve(options.project ?? payload.cwd ?? process.cwd());\n const config = await loadConfig(options.configDir ?? root, {\n ...(options.config === undefined ? {} : { configPath: options.config }),\n ...(options.noConfig === undefined ? {} : { noConfig: options.noConfig }),\n });\n\n const manifest = await buildManifest({\n sessionId,\n root,\n hookEvent: payload.hookEvent ?? \"manual\",\n ...(payload.reason !== undefined ? { reason: payload.reason } : {}),\n ...(payload.transcriptPath !== undefined\n ? { transcriptPath: payload.transcriptPath }\n : {}),\n config,\n redact: config.judge.redact,\n ...(options.version !== undefined ? { version: options.version } : {}),\n });\n\n const path =\n options.out ??\n manifestPathFor(resolve(root, config.capture.dir), sessionId);\n try {\n await writeManifest(path, manifest);\n } catch (err) {\n throw new TracevalsError(\n `could not write ${path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const rendered =\n options.format === \"json\"\n ? JSON.stringify({ path, manifest }, null, 2)\n : renderCapture(path, manifest);\n\n return {\n manifest,\n path,\n rendered,\n // The whole point of the split: a SessionStart hook's stdout becomes model\n // context, so hook mode writes none.\n stdout: hookMode ? \"\" : rendered,\n stderr: hookMode ? rendered : \"\",\n exitCode: 0,\n };\n}\n\nexport function renderCapture(\n path: string,\n manifest: SessionManifest,\n): string {\n const lines = [\n `Captured session ${manifest.sessionId}`,\n ` manifest ${path}`,\n ` artifacts ${manifest.artifacts.length} hashed`,\n ];\n if (manifest.git !== undefined) {\n lines.push(\n ` commit ${manifest.git.sha}${manifest.git.branch ? ` (${manifest.git.branch})` : \"\"}${\n manifest.git.dirty ? \" — working tree dirty\" : \"\"\n }`,\n );\n } else {\n lines.push(\" commit not a git repository, or git is unavailable\");\n }\n lines.push(` device ${manifest.device.id} (${manifest.device.platform})`);\n return lines.join(\"\\n\");\n}\n","/**\n * Building a session manifest (ADR 01024) — the producing half.\n *\n * Separate from `capture/manifest.ts` because this side reaches for\n * `discoverArtifacts`, which imports `artifacts/resolve.ts`, which consumes a\n * manifest. Producing and consuming therefore cannot share a module.\n */\nimport { spawn } from \"node:child_process\";\nimport { hostname, platform, userInfo } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { discoverArtifacts } from \"../artifacts/discover.js\";\nimport { makeRedactor, type Redactor } from \"../judge/redact.js\";\nimport { hashFile, relPosix, sha256Hex } from \"./manifest.js\";\nimport {\n MANIFEST_VERSION,\n type ManifestArtifact,\n type ManifestGit,\n type SessionManifest,\n} from \"./types.js\";\n\nexport interface BuildManifestOptions {\n sessionId: string;\n /** Project root to scan, and the base every artifact path is relative to. */\n root: string;\n hookEvent?: string;\n reason?: string;\n transcriptPath?: string;\n /** The resolved config section, recorded as provenance. */\n config?: unknown;\n /** `judge.redact` sources, applied to the manifest's free text (ADR 01020). */\n redact?: readonly string[];\n version?: string;\n /** Test seam: `false` skips shelling out to git. */\n git?: ManifestGit | false;\n}\n\n/**\n * Hash every instruction artifact the project holds, at the commit it holds\n * them at.\n *\n * The population is `discoverArtifacts`' — the same one `fill` authors against\n * — so capture and authoring never disagree about what an instruction artifact\n * is. That scope is **project-only** by its own design note, so a user-level or\n * plugin artifact is simply absent from the manifest, and its hash check at run\n * time degrades to the mtime heuristic rather than to a wrong answer.\n *\n * **Redaction covers the free text and never a join key.** `root`,\n * `transcriptPath`, `git.branch`, `reason` and the recorded `config` go through\n * the `judge.redact` redactor; `sessionId`, an artifact's `name` and `path`,\n * and every `sha256` do not. A redactor applied to a join key would turn an\n * exact check into a silent `skipped` — the one failure mode this whole feature\n * exists to remove — and those keys are the project's own vocabulary and its\n * repository-relative paths, not somewhere a credential lives. A secret in an\n * artifact path is a problem to fix in the path, the same call ADR 01020 makes\n * about a secret in a `SKILL.md`.\n */\nexport async function buildManifest(\n options: BuildManifestOptions,\n): Promise<SessionManifest> {\n const root = resolve(options.root);\n const redact = makeRedactor(options.redact ?? []);\n\n const discovered = await discoverArtifacts({ root });\n const artifacts: ManifestArtifact[] = [];\n for (const found of discovered.artifacts) {\n const rel = relPosix(root, found.artifact.path);\n if (rel === null) continue;\n const digest = await hashFile(found.artifact.path);\n // An artifact that cannot be read is one the manifest says nothing about,\n // which degrades to the mtime heuristic at run time. Never a crash.\n if (digest === null) continue;\n artifacts.push({\n name: found.artifact.name,\n type: found.artifact.type,\n path: rel,\n sha256: digest,\n bytes: Buffer.byteLength(found.artifact.content, \"utf-8\"),\n });\n }\n // Stable order, so two captures of an unchanged tree produce the same bytes.\n artifacts.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n\n const git =\n options.git === false ? undefined : (options.git ?? (await readGit(root)));\n\n return {\n version: MANIFEST_VERSION,\n sessionId: options.sessionId,\n capturedAt: new Date().toISOString(),\n hookEvent: options.hookEvent ?? \"manual\",\n ...(options.reason !== undefined ? { reason: redact(options.reason) } : {}),\n ...(options.transcriptPath !== undefined\n ? { transcriptPath: redact(options.transcriptPath) }\n : {}),\n root: redact(root),\n ...(git !== undefined\n ? {\n git: {\n sha: git.sha,\n ...(git.branch !== undefined ? { branch: redact(git.branch) } : {}),\n dirty: git.dirty,\n },\n }\n : {}),\n device: { id: deviceId(), platform: platform() },\n tool: { name: \"manni-tracevals\", version: options.version ?? \"unknown\" },\n artifacts,\n config: redactDeep(options.config ?? {}, redact),\n };\n}\n\n/**\n * A stable, opaque per-machine id. Not the hostname: \"was this captured here?\"\n * is the whole question, and answering it does not require shipping the name of\n * the machine into a file that travels with the repository.\n */\nexport function deviceId(): string {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n // A container with no passwd entry throws; the digest is still stable.\n }\n return sha256Hex(`${hostname()} ${user} ${platform()}`).slice(0, 16);\n}\n\n/**\n * Redact every string in a JSON-shaped value. Used for the recorded config\n * only — never for a join key.\n */\nexport function redactDeep(value: unknown, redact: Redactor): unknown {\n if (typeof value === \"string\") return redact(value);\n if (Array.isArray(value)) return value.map((v) => redactDeep(v, redact));\n if (value !== null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(value)) {\n out[key] = redactDeep(member, redact);\n }\n return out;\n }\n return value;\n}\n\n/**\n * What `git` says about `root`, or nothing. Every failure mode — git absent,\n * not a repository, a timeout — degrades to an absent block, because a manifest\n * without a SHA is still a manifest with hashes in it.\n */\nexport async function readGit(root: string): Promise<ManifestGit | undefined> {\n const sha = await git([\"rev-parse\", \"HEAD\"], root);\n if (sha === null || !/^[0-9a-f]{40}$/.test(sha)) return undefined;\n const branch = await git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], root);\n const status = await git(\n [\"status\", \"--porcelain\", \"--untracked-files=no\"],\n root,\n );\n return {\n sha,\n // Detached HEAD reports the literal \"HEAD\", which is not a branch name.\n ...(branch !== null && branch !== \"HEAD\" ? { branch } : {}),\n dirty: status !== null && status.length > 0,\n };\n}\n\n/** One `git` invocation, argv-only and bounded — the shape ADR 01011 uses. */\nfunction git(\n args: string[],\n cwd: string,\n timeoutMs = 5000,\n): Promise<string | null> {\n return new Promise((settle) => {\n let done = false;\n let child;\n try {\n // shell:false — nothing here is ever parsed as shell syntax.\n child = spawn(\"git\", args, { cwd, shell: false, windowsHide: true });\n } catch {\n settle(null);\n return;\n }\n // `finish` is declared below the timer because it clears it; the timer\n // callback only runs after both exist.\n const timer = setTimeout(() => {\n child.kill();\n finish(null);\n }, timeoutMs);\n const finish = (value: string | null): void => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n settle(value);\n };\n let out = \"\";\n child.stdout.on(\"data\", (d: Buffer) => {\n out += d.toString(\"utf-8\");\n });\n child.stderr.resume();\n child.on(\"error\", () => { finish(null); });\n child.on(\"close\", (code) => { finish(code === 0 ? out.trim() : null); });\n });\n}\n"],"mappings":"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","names":["resolve","git","resolve"]}
1
+ {"version":3,"sources":["../src/tracevals/commands/capture.ts","../src/tracevals/capture/build.ts"],"sourcesContent":["/**\n * `manni tracevals capture` — record what the project's instruction artifacts\n * said, and at which commit, at the moment a session started (ADR 01024).\n *\n * **This is the one write path `run` never takes.** CLAUDE.md states that\n * evaluation is read-only, so the manifest is written by a separate,\n * explicitly-invoked command — the same shape as `fill`. `run` only ever reads\n * a manifest, and degrades cleanly when there is none.\n *\n * Designed to be wired to a `SessionStart` hook, which constrains it in two\n * ways that are not obvious:\n *\n * - **Nothing goes to stdout in hook mode.** Claude Code adds a\n * SessionStart hook's stdout to the model's context, so a report printed\n * there would be a side effect on the very session being observed. In hook\n * mode the report goes to stderr, where an exit-0 hook's output is a debug\n * line and nothing more.\n * - **The transcript is never read.** `transcript_path` is recorded as a\n * correlation key only. At SessionStart the file barely exists, and the\n * reference warns that it lags the conversation in any case.\n */\nimport { resolve } from \"node:path\";\nimport { loadConfig } from \"../core/config.js\";\nimport { buildManifest } from \"../capture/build.js\";\nimport { manifestPathFor, writeManifest } from \"../capture/manifest.js\";\nimport type { SessionManifest } from \"../capture/types.js\";\nimport { parseHookPayload, readStdin } from \"../capture/hook.js\";\nimport type { SummaryFormat } from \"../reporters/index.js\";\nimport { TracevalsError } from \"../types.js\";\n\nexport interface CaptureCommandOptions {\n /**\n * The hook payload. Undefined means \"read stdin\"; an empty string means\n * \"there was none\", which is the hand-run path.\n */\n stdin?: string;\n /** Overrides the payload's `cwd` as the project root to scan. */\n project?: string;\n /** Overrides the payload's `session_id`. */\n sessionId?: string;\n /** Write here instead of `<project>/<capture.dir>/<session-id>.json`. */\n out?: string;\n /** Directory holding manni.config.yaml; defaults to the project root. */\n configDir?: string;\n /** `-c/--config`: read this file instead of discovering one. */\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n format?: SummaryFormat;\n /**\n * Version recorded in the manifest. Passed in rather than read from\n * package.json here: this module is bundled into an unpredictable chunk\n * path, so any relative require of it resolves differently in dist than in\n * src. The CLI, which is not bundled away, supplies it.\n */\n version?: string;\n}\n\nexport interface CaptureCommandResult {\n manifest: SessionManifest;\n /** Where the manifest was written. */\n path: string;\n /** The report, wherever it is destined for. */\n rendered: string;\n /** What the caller should print to stdout — empty in hook mode. */\n stdout: string;\n /** What the caller should print to stderr — the report, in hook mode. */\n stderr: string;\n exitCode: number;\n}\n\nexport async function runCapture(\n options: CaptureCommandOptions = {},\n): Promise<CaptureCommandResult> {\n const raw = options.stdin ?? (await readStdin());\n const hookMode = raw.trim().length > 0;\n const payload = hookMode ? parseHookPayload(raw) : {};\n\n const sessionId = options.sessionId ?? payload.sessionId;\n if (sessionId === undefined) {\n // Without an id the manifest has no name and no join key, and writing one\n // under a guessed name would produce evidence nothing could ever find.\n throw new TracevalsError(\n \"no session id: pipe a Claude Code hook payload on stdin, or pass --session-id\",\n );\n }\n\n const root = resolve(options.project ?? payload.cwd ?? process.cwd());\n const config = await loadConfig(options.configDir ?? root, {\n ...(options.config === undefined ? {} : { configPath: options.config }),\n ...(options.noConfig === undefined ? {} : { noConfig: options.noConfig }),\n });\n\n const manifest = await buildManifest({\n sessionId,\n root,\n hookEvent: payload.hookEvent ?? \"manual\",\n ...(payload.reason !== undefined ? { reason: payload.reason } : {}),\n ...(payload.transcriptPath !== undefined\n ? { transcriptPath: payload.transcriptPath }\n : {}),\n config,\n redact: config.judge.redact,\n ...(options.version !== undefined ? { version: options.version } : {}),\n });\n\n const path =\n options.out ??\n manifestPathFor(resolve(root, config.capture.dir), sessionId);\n try {\n await writeManifest(path, manifest);\n } catch (err) {\n throw new TracevalsError(\n `could not write ${path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const rendered =\n options.format === \"json\"\n ? JSON.stringify({ path, manifest }, null, 2)\n : renderCapture(path, manifest);\n\n return {\n manifest,\n path,\n rendered,\n // The whole point of the split: a SessionStart hook's stdout becomes model\n // context, so hook mode writes none.\n stdout: hookMode ? \"\" : rendered,\n stderr: hookMode ? rendered : \"\",\n exitCode: 0,\n };\n}\n\nexport function renderCapture(\n path: string,\n manifest: SessionManifest,\n): string {\n const lines = [\n `Captured session ${manifest.sessionId}`,\n ` manifest ${path}`,\n ` artifacts ${manifest.artifacts.length} hashed`,\n ];\n if (manifest.git !== undefined) {\n lines.push(\n ` commit ${manifest.git.sha}${manifest.git.branch ? ` (${manifest.git.branch})` : \"\"}${\n manifest.git.dirty ? \" — working tree dirty\" : \"\"\n }`,\n );\n } else {\n lines.push(\" commit not a git repository, or git is unavailable\");\n }\n lines.push(` device ${manifest.device.id} (${manifest.device.platform})`);\n return lines.join(\"\\n\");\n}\n","/**\n * Building a session manifest (ADR 01024) — the producing half.\n *\n * Separate from `capture/manifest.ts` because this side reaches for\n * `discoverArtifacts`, which imports `artifacts/resolve.ts`, which consumes a\n * manifest. Producing and consuming therefore cannot share a module.\n */\nimport { spawn } from \"node:child_process\";\nimport { hostname, platform, userInfo } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { discoverArtifacts } from \"../artifacts/discover.js\";\nimport { makeRedactor, type Redactor } from \"../judge/redact.js\";\nimport { hashFile, relPosix, sha256Hex } from \"./manifest.js\";\nimport {\n MANIFEST_VERSION,\n type ManifestArtifact,\n type ManifestGit,\n type SessionManifest,\n} from \"./types.js\";\n\nexport interface BuildManifestOptions {\n sessionId: string;\n /** Project root to scan, and the base every artifact path is relative to. */\n root: string;\n hookEvent?: string;\n reason?: string;\n transcriptPath?: string;\n /** The resolved config section, recorded as provenance. */\n config?: unknown;\n /** `judge.redact` sources, applied to the manifest's free text (ADR 01020). */\n redact?: readonly string[];\n version?: string;\n /** Test seam: `false` skips shelling out to git. */\n git?: ManifestGit | false;\n}\n\n/**\n * Hash every instruction artifact the project holds, at the commit it holds\n * them at.\n *\n * The population is `discoverArtifacts`' — the same one `fill` authors against\n * — so capture and authoring never disagree about what an instruction artifact\n * is. That scope is **project-only** by its own design note, so a user-level or\n * plugin artifact is simply absent from the manifest, and its hash check at run\n * time degrades to the mtime heuristic rather than to a wrong answer.\n *\n * **Redaction covers the free text and never a join key.** `root`,\n * `transcriptPath`, `git.branch`, `reason` and the recorded `config` go through\n * the `judge.redact` redactor; `sessionId`, an artifact's `name` and `path`,\n * and every `sha256` do not. A redactor applied to a join key would turn an\n * exact check into a silent `skipped` — the one failure mode this whole feature\n * exists to remove — and those keys are the project's own vocabulary and its\n * repository-relative paths, not somewhere a credential lives. A secret in an\n * artifact path is a problem to fix in the path, the same call ADR 01020 makes\n * about a secret in a `SKILL.md`.\n */\nexport async function buildManifest(\n options: BuildManifestOptions,\n): Promise<SessionManifest> {\n const root = resolve(options.root);\n const redact = makeRedactor(options.redact ?? []);\n\n const discovered = await discoverArtifacts({ root });\n const artifacts: ManifestArtifact[] = [];\n for (const found of discovered.artifacts) {\n const rel = relPosix(root, found.artifact.path);\n if (rel === null) continue;\n const digest = await hashFile(found.artifact.path);\n // An artifact that cannot be read is one the manifest says nothing about,\n // which degrades to the mtime heuristic at run time. Never a crash.\n if (digest === null) continue;\n artifacts.push({\n name: found.artifact.name,\n type: found.artifact.type,\n path: rel,\n sha256: digest,\n bytes: Buffer.byteLength(found.artifact.content, \"utf-8\"),\n });\n }\n // Stable order, so two captures of an unchanged tree produce the same bytes.\n artifacts.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n\n const git =\n options.git === false ? undefined : (options.git ?? (await readGit(root)));\n\n return {\n version: MANIFEST_VERSION,\n sessionId: options.sessionId,\n capturedAt: new Date().toISOString(),\n hookEvent: options.hookEvent ?? \"manual\",\n ...(options.reason !== undefined ? { reason: redact(options.reason) } : {}),\n ...(options.transcriptPath !== undefined\n ? { transcriptPath: redact(options.transcriptPath) }\n : {}),\n root: redact(root),\n ...(git !== undefined\n ? {\n git: {\n sha: git.sha,\n ...(git.branch !== undefined ? { branch: redact(git.branch) } : {}),\n dirty: git.dirty,\n },\n }\n : {}),\n device: { id: deviceId(), platform: platform() },\n tool: { name: \"manni-tracevals\", version: options.version ?? \"unknown\" },\n artifacts,\n config: redactDeep(options.config ?? {}, redact),\n };\n}\n\n/**\n * A stable, opaque per-machine id. Not the hostname: \"was this captured here?\"\n * is the whole question, and answering it does not require shipping the name of\n * the machine into a file that travels with the repository.\n */\nexport function deviceId(): string {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n // A container with no passwd entry throws; the digest is still stable.\n }\n return sha256Hex(`${hostname()} ${user} ${platform()}`).slice(0, 16);\n}\n\n/**\n * Redact every string in a JSON-shaped value. Used for the recorded config\n * only — never for a join key.\n */\nexport function redactDeep(value: unknown, redact: Redactor): unknown {\n if (typeof value === \"string\") return redact(value);\n if (Array.isArray(value)) return value.map((v) => redactDeep(v, redact));\n if (value !== null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(value)) {\n out[key] = redactDeep(member, redact);\n }\n return out;\n }\n return value;\n}\n\n/**\n * What `git` says about `root`, or nothing. Every failure mode — git absent,\n * not a repository, a timeout — degrades to an absent block, because a manifest\n * without a SHA is still a manifest with hashes in it.\n */\nexport async function readGit(root: string): Promise<ManifestGit | undefined> {\n const sha = await git([\"rev-parse\", \"HEAD\"], root);\n if (sha === null || !/^[0-9a-f]{40}$/.test(sha)) return undefined;\n const branch = await git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], root);\n const status = await git(\n [\"status\", \"--porcelain\", \"--untracked-files=no\"],\n root,\n );\n return {\n sha,\n // Detached HEAD reports the literal \"HEAD\", which is not a branch name.\n ...(branch !== null && branch !== \"HEAD\" ? { branch } : {}),\n dirty: status !== null && status.length > 0,\n };\n}\n\n/** One `git` invocation, argv-only and bounded — the shape ADR 01011 uses. */\nfunction git(\n args: string[],\n cwd: string,\n timeoutMs = 5000,\n): Promise<string | null> {\n return new Promise((settle) => {\n let done = false;\n let child;\n try {\n // shell:false — nothing here is ever parsed as shell syntax.\n child = spawn(\"git\", args, { cwd, shell: false, windowsHide: true });\n } catch {\n settle(null);\n return;\n }\n // `finish` is declared below the timer because it clears it; the timer\n // callback only runs after both exist.\n const timer = setTimeout(() => {\n child.kill();\n finish(null);\n }, timeoutMs);\n const finish = (value: string | null): void => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n settle(value);\n };\n let out = \"\";\n child.stdout.on(\"data\", (d: Buffer) => {\n out += d.toString(\"utf-8\");\n });\n child.stderr.resume();\n child.on(\"error\", () => { finish(null); });\n child.on(\"close\", (code) => { finish(code === 0 ? out.trim() : null); });\n });\n}\n"],"mappings":"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","names":["resolve","git","resolve"]}
@@ -22,7 +22,7 @@ import {
22
22
  updateConfigEval,
23
23
  updateManifestEval,
24
24
  updatePageEval
25
- } from "./chunk-YA63PVWI.js";
25
+ } from "./chunk-K52CS4KT.js";
26
26
  import {
27
27
  DEFAULT_CONFIG_FILENAME,
28
28
  assertRegisteredGraders,
@@ -41,10 +41,10 @@ import {
41
41
  sha256,
42
42
  splitBody,
43
43
  withExternalMetadata
44
- } from "./chunk-7OQAU4EA.js";
44
+ } from "./chunk-LDKIIZDW.js";
45
45
  import {
46
46
  isTurnBudgetSkip
47
- } from "./chunk-LJ2RDH3F.js";
47
+ } from "./chunk-XG6PVB5S.js";
48
48
  import {
49
49
  SUMMARY_FORMATS,
50
50
  parseFormat
@@ -57,13 +57,13 @@ import {
57
57
  } from "./chunk-77AINBYM.js";
58
58
  import {
59
59
  mergeMetaProvenance
60
- } from "./chunk-3YHAYXBC.js";
60
+ } from "./chunk-CR3HZERW.js";
61
61
  import {
62
62
  palette
63
63
  } from "./chunk-RNVYGWIC.js";
64
64
  import {
65
65
  warn
66
- } from "./chunk-Q35YIDBV.js";
66
+ } from "./chunk-HX44GB4Z.js";
67
67
  import {
68
68
  errorMessage
69
69
  } from "./chunk-G3T47CFV.js";
@@ -1284,4 +1284,4 @@ export {
1284
1284
  renderCalibration,
1285
1285
  runInit
1286
1286
  };
1287
- //# sourceMappingURL=chunk-GAZFKZHM.js.map
1287
+ //# sourceMappingURL=chunk-CEVU3GFF.js.map