@iowarp/clio-coder 0.3.2 → 0.3.4

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 (259) hide show
  1. package/CHANGELOG.md +269 -458
  2. package/CONTRIBUTING.md +1 -1
  3. package/README.md +3 -3
  4. package/dist/{acp-BIYHVZIM.js → acp-S5R4RR5B.js} +7 -6
  5. package/dist/{agents-YT6SSRIT.js → agents-P6DMMVZY.js} +24 -21
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-2XCZLPKS.js} +12 -8
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-WMSVI4G2.js → chunk-2LZI5CAG.js} +133 -13
  10. package/dist/{chunk-OAO4GE4M.js → chunk-2TZWSW76.js} +2 -2
  11. package/dist/{chunk-OOJYHWRB.js → chunk-34475P3I.js} +2 -2
  12. package/dist/{chunk-WVO7V2QY.js → chunk-35MKKU5R.js} +4 -4
  13. package/dist/{chunk-LBNRH5WM.js → chunk-3HZ5RWN2.js} +5 -5
  14. package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
  15. package/dist/{chunk-MBS4V7ZP.js → chunk-4JUF2NNX.js} +7 -7
  16. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  17. package/dist/chunk-5M54SPOL.js +926 -0
  18. package/dist/{chunk-STBPMHSX.js → chunk-7RXG6QRZ.js} +51 -11
  19. package/dist/{chunk-77VKQEHF.js → chunk-A2GZF7DC.js} +5 -5
  20. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  21. package/dist/chunk-AOCYTWAV.js +449 -0
  22. package/dist/chunk-BEY543CS.js +258 -0
  23. package/dist/{chunk-6N5PTWMY.js → chunk-BP4OYD6A.js} +32 -13
  24. package/dist/chunk-BPGS2WCQ.js +612 -0
  25. package/dist/{chunk-J5HN4RYU.js → chunk-BRXQQJFP.js} +8 -8
  26. package/dist/chunk-CFGTUFWB.js +67 -0
  27. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  28. package/dist/{chunk-G2DE3C7R.js → chunk-EDRHSCIE.js} +4 -4
  29. package/dist/{chunk-4KLWL3UC.js → chunk-EFADSJET.js} +2 -2
  30. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  31. package/dist/chunk-FYYLNIL5.js +313 -0
  32. package/dist/{chunk-EPVUXGXG.js → chunk-HV5X7OR2.js} +14 -12
  33. package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
  34. package/dist/{chunk-IGLFWIYI.js → chunk-K6WL7QZT.js} +3 -3
  35. package/dist/chunk-K7VKOLQQ.js +15 -0
  36. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  37. package/dist/{chunk-V4RXGQ5Q.js → chunk-KRPY7NTG.js} +10 -7
  38. package/dist/chunk-LL4KHSZI.js +22 -0
  39. package/dist/{chunk-KJ5LWLOE.js → chunk-MEQ45TQ4.js} +15 -9
  40. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  41. package/dist/{chunk-AO4RKG4M.js → chunk-N4CZJQRK.js} +5 -5
  42. package/dist/{chunk-ARBGF5F7.js → chunk-NILBFAPG.js} +14 -8
  43. package/dist/chunk-OZNBF4L3.js +23 -0
  44. package/dist/{verify-G6V4D2G7.js → chunk-PCZJO5TI.js} +127 -42
  45. package/dist/chunk-QQK64KLB.js +1360 -0
  46. package/dist/{chunk-6EJV5X2W.js → chunk-QQL5RT5M.js} +979 -1619
  47. package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
  48. package/dist/{chunk-2EHAIA3X.js → chunk-RD5U66HV.js} +3 -3
  49. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  50. package/dist/{chunk-OQ33BKR3.js → chunk-TTNYS3EA.js} +3 -60
  51. package/dist/chunk-TW3WDMVS.js +677 -0
  52. package/dist/chunk-TZSKNMZG.js +434 -0
  53. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  54. package/dist/{chunk-7EYHLWU7.js → chunk-UZHIZC5S.js} +7 -7
  55. package/dist/{chunk-QTYWRVRA.js → chunk-VAWWTKDP.js} +8 -8
  56. package/dist/{chunk-X75S7HFS.js → chunk-VEZEGCGW.js} +214 -20
  57. package/dist/{chunk-OHHN2SO4.js → chunk-VMNQ6OZA.js} +98 -202
  58. package/dist/chunk-VSNATDE6.js +122 -0
  59. package/dist/chunk-W6GROXXM.js +69 -0
  60. package/dist/chunk-WPQLXFOZ.js +375 -0
  61. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  62. package/dist/{chunk-3ZXDFGR5.js → chunk-X6COSD2O.js} +5 -5
  63. package/dist/chunk-ZGVHUX3M.js +66 -0
  64. package/dist/{chunk-MAW544W2.js → chunk-ZWMF7253.js} +4 -4
  65. package/dist/{chunk-MQSRRFWA.js → chunk-ZYKPLLNQ.js} +563 -546
  66. package/dist/cli/index.js +27 -23
  67. package/dist/{clio-4LY5K2AC.js → clio-J5JIOIDS.js} +7 -6
  68. package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
  69. package/dist/{config-GTLUW2PR.js → config-OEBMIN2U.js} +37 -27
  70. package/dist/{configure-R6A64DHX.js → configure-PUQOSIXQ.js} +16 -13
  71. package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
  72. package/dist/{context-RW5HC47S.js → context-MGSE4Z2T.js} +33 -23
  73. package/dist/{context-JFZEJ7W5.js → context-URSXPBCK.js} +17 -9
  74. package/dist/{context-clear-6ZHBAZZT.js → context-clear-KDAJRNUK.js} +33 -23
  75. package/dist/context-working-set-SBKMPPI2.js +1552 -0
  76. package/dist/{dispatch-runner-VKBRCWQC.js → dispatch-runner-MSWN72NK.js} +43 -29
  77. package/dist/{doctor-KI767GSN.js → doctor-7BSE27PJ.js} +10 -10
  78. package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
  79. package/dist/{evidence-UA6AWDQQ.js → evidence-SR7WXB5B.js} +51 -23
  80. package/dist/{evolve-QNTFGV6Z.js → evolve-K7VE2CBX.js} +30 -20
  81. package/dist/{fleet-Q7UOMUSG.js → fleet-7XMJNQNF.js} +48 -38
  82. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
  83. package/dist/{init-WBB65ZHQ.js → init-JGNPAYXT.js} +41 -31
  84. package/dist/{memory-MD3O64RI.js → memory-4ALKDJ4Q.js} +32 -22
  85. package/dist/{models-BZU34YWD.js → models-ZMMLFJNN.js} +22 -19
  86. package/dist/{monitor-MEQA5C3I.js → monitor-2F3T5KHP.js} +55 -43
  87. package/dist/{orchestrator-CGFKEP27.js → orchestrator-ORHT43JB.js} +2507 -1896
  88. package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
  89. package/dist/{run-IV4Q6RLN.js → run-RF4WJGMT.js} +51 -41
  90. package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
  91. package/dist/{skills-LQEKRDTN.js → skills-PSACKC5Q.js} +2 -2
  92. package/dist/{skills-eval-3DC4HEWS.js → skills-eval-WJSI55RZ.js} +34 -24
  93. package/dist/{targets-C4SSGQOB.js → targets-PIIRAOYS.js} +23 -20
  94. package/dist/{terminal-lease-IT5JW2NR.js → terminal-lease-ULWXWNVY.js} +5 -4
  95. package/dist/{upgrade-7TT7SQ3G.js → upgrade-346TZ6AV.js} +18 -17
  96. package/dist/{usage-GV4PKT3M.js → usage-6KKXR32N.js} +34 -24
  97. package/dist/verifiers-4UUM6TEE.js +1214 -0
  98. package/dist/verify-X5HDROLA.js +25 -0
  99. package/dist/{wiki-generate-DQF6Z66B.js → wiki-generate-7STOCIFZ.js} +42 -31
  100. package/dist/worker/entry.js +33 -24
  101. package/docs/README.md +8 -7
  102. package/docs/acp.md +1 -1
  103. package/docs/alcf-provider.md +1 -1
  104. package/docs/architecture.md +2 -2
  105. package/docs/artifact-versions.md +1 -1
  106. package/docs/built-in-agents.md +1 -1
  107. package/docs/capacity-and-scheduling.md +1 -1
  108. package/docs/commands-and-modes.md +53 -21
  109. package/docs/config-knobs-audit.md +1 -2
  110. package/docs/configuration-and-targets.md +15 -1
  111. package/docs/context-engine.md +64 -12
  112. package/docs/context-working-set.md +194 -0
  113. package/docs/development-pipeline.md +1 -1
  114. package/docs/documentation-coverage.md +5 -5
  115. package/docs/documentation-guide.md +6 -5
  116. package/docs/environment-variables.md +2 -1
  117. package/docs/eval-runner.md +1 -1
  118. package/docs/evals-internal.md +14 -1
  119. package/docs/evidence-and-memory.md +74 -2
  120. package/docs/evolution.md +1 -1
  121. package/docs/exit-codes-and-output.md +1 -1
  122. package/docs/extensions-and-sharing.md +2 -2
  123. package/docs/fleet-dispatch.md +22 -7
  124. package/docs/glossary.md +21 -1
  125. package/docs/installation-and-lifecycle.md +6 -6
  126. package/docs/middleware-and-components.md +1 -1
  127. package/docs/model-catalog.md +7 -9
  128. package/docs/observability.md +4 -4
  129. package/docs/performance-methodology.md +2 -2
  130. package/docs/proactive-memory.md +1 -1
  131. package/docs/prompt-envelope-and-tools.md +4 -4
  132. package/docs/provider-adapter-cookbook.md +1 -1
  133. package/docs/release-cut-checklist.md +35 -35
  134. package/docs/safety-model.md +23 -4
  135. package/docs/scientific-validation.md +21 -3
  136. package/docs/session-lifecycle.md +3 -3
  137. package/docs/skills-marketplace.md +1 -1
  138. package/docs/tool-usage.md +79 -12
  139. package/docs/trace-store.md +1 -1
  140. package/docs/troubleshooting.md +1 -1
  141. package/docs/tui-design.md +2 -2
  142. package/docs/worker-dispatch-mechanics.md +11 -1
  143. package/package.json +8 -11
  144. package/skills/meta/clio-test/SKILL.md +20 -17
  145. package/skills/meta/clio-test/evals.md +3 -3
  146. package/skills/meta/clio-test/references/harness.md +35 -6
  147. package/skills/meta/clio-test/references/test-map.md +20 -10
  148. package/skills/registry.yaml +2 -2
  149. package/skills/skill-marketplace.json +1 -1
  150. package/src/cli/context-working-set.ts +513 -0
  151. package/src/cli/context.ts +8 -0
  152. package/src/cli/evidence.ts +20 -2
  153. package/src/cli/index.ts +4 -0
  154. package/src/cli/verifiers.ts +325 -0
  155. package/src/core/bash-exec.ts +39 -14
  156. package/src/core/bus-events.ts +19 -4
  157. package/src/core/config.ts +54 -0
  158. package/src/core/defaults.ts +50 -3
  159. package/src/core/git-commit-attribution.ts +46 -21
  160. package/src/core/verification-scripts.ts +6 -0
  161. package/src/domains/agents/builtins/verifier.md +3 -0
  162. package/src/domains/config/classify.ts +1 -0
  163. package/src/domains/config/keybindings.ts +3 -3
  164. package/src/domains/context/working-set/contract.ts +161 -0
  165. package/src/domains/context/working-set/defaults.ts +28 -0
  166. package/src/domains/context/working-set/engine.ts +203 -0
  167. package/src/domains/context/working-set/fold.ts +62 -0
  168. package/src/domains/context/working-set/horizon.ts +38 -0
  169. package/src/domains/context/working-set/marker.ts +103 -0
  170. package/src/domains/context/working-set/path-index.ts +436 -0
  171. package/src/domains/context/working-set/payload.ts +152 -0
  172. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  173. package/src/domains/context/working-set/policies/index.ts +21 -0
  174. package/src/domains/context/working-set/policies/structural.ts +160 -0
  175. package/src/domains/context/working-set/project.ts +132 -0
  176. package/src/domains/context/working-set/protect.ts +109 -0
  177. package/src/domains/context/working-set/recall.ts +177 -0
  178. package/src/domains/context/working-set/replay/controls.ts +112 -0
  179. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  180. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  181. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  182. package/src/domains/context/working-set/replay/report.ts +139 -0
  183. package/src/domains/context/working-set/replay/runner.ts +325 -0
  184. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  185. package/src/domains/context/working-set/replay/trace.ts +21 -0
  186. package/src/domains/context/working-set/visible.ts +54 -0
  187. package/src/domains/evidence/build.ts +112 -45
  188. package/src/domains/evidence/eval.ts +24 -7
  189. package/src/domains/evidence/index.ts +53 -0
  190. package/src/domains/evidence/ordering.ts +12 -0
  191. package/src/domains/evidence/run-trust.ts +221 -0
  192. package/src/domains/evidence/store.ts +46 -6
  193. package/src/domains/evidence/trust-status.ts +854 -0
  194. package/src/domains/evidence/types.ts +26 -0
  195. package/src/domains/middleware/memory-intervention.ts +3 -0
  196. package/src/domains/middleware/stalled-turn.ts +165 -4
  197. package/src/domains/safety/autonomy.ts +1 -1
  198. package/src/domains/safety/default-path-policy.ts +8 -0
  199. package/src/domains/safety/finish-contract.ts +4 -3
  200. package/src/domains/safety/policy-engine.ts +48 -6
  201. package/src/domains/session/compaction/compact.ts +23 -1
  202. package/src/domains/session/compaction/cut-point.ts +2 -0
  203. package/src/domains/session/compaction/tokens.ts +16 -1
  204. package/src/domains/session/context-ledger.ts +2 -0
  205. package/src/domains/session/entries.ts +107 -1
  206. package/src/domains/session/manager.ts +9 -2
  207. package/src/domains/session/migrations/index.ts +22 -3
  208. package/src/engine/acp/server.ts +3 -0
  209. package/src/engine/agent.ts +18 -1
  210. package/src/engine/session.ts +9 -3
  211. package/src/entry/orchestrator.ts +16 -4
  212. package/src/interactive/chat-loop-messages.ts +18 -6
  213. package/src/interactive/chat-panel.ts +571 -244
  214. package/src/interactive/chat-renderer.ts +79 -39
  215. package/src/interactive/context-meter.ts +10 -0
  216. package/src/interactive/context-overlay.ts +81 -6
  217. package/src/interactive/context-recall-command.ts +110 -0
  218. package/src/interactive/editor-submit.ts +26 -1
  219. package/src/interactive/footer/widgets.ts +22 -20
  220. package/src/interactive/footer-panel.ts +6 -1
  221. package/src/interactive/interactive-application.ts +2 -0
  222. package/src/interactive/interactive-event-projection.ts +12 -0
  223. package/src/interactive/interactive-slash-runtime.ts +49 -8
  224. package/src/interactive/model-session-replay.ts +21 -0
  225. package/src/interactive/overlay-general-openers.ts +6 -0
  226. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  227. package/src/interactive/overlays/ask-user.ts +146 -24
  228. package/src/interactive/renderers/tool-execution.ts +167 -56
  229. package/src/interactive/session-transcript.ts +2 -2
  230. package/src/interactive/slash-commands.ts +29 -2
  231. package/src/interactive/status/index.ts +12 -1
  232. package/src/interactive/status/reasoning.ts +87 -0
  233. package/src/interactive/status/summary.ts +13 -2
  234. package/src/interactive/transcript-detail.ts +120 -0
  235. package/src/interactive/turn-context.ts +238 -88
  236. package/src/interactive/turn-middleware.ts +6 -6
  237. package/src/tools/agent-tools.ts +11 -4
  238. package/src/tools/bash.ts +144 -82
  239. package/src/tools/builtin-tool-catalog.ts +18 -6
  240. package/src/tools/context/index.ts +105 -3
  241. package/src/tools/context/surface.ts +3 -2
  242. package/src/tools/core-bootstrap.ts +21 -0
  243. package/src/tools/dispatch-runner.ts +9 -7
  244. package/src/tools/monitor.ts +28 -20
  245. package/src/tools/presentation.ts +107 -0
  246. package/src/tools/registry.ts +65 -7
  247. package/src/tools/result-disposition.ts +550 -0
  248. package/src/tools/result-shaping.ts +262 -19
  249. package/src/tools/safe-exec.ts +2 -0
  250. package/src/tools/verify/authoring.ts +1119 -0
  251. package/src/tools/verify/catalog.ts +346 -0
  252. package/src/tools/verify/index.ts +13 -3
  253. package/src/tools/verify/scripts.ts +135 -37
  254. package/src/tools/verify/surface.ts +9 -5
  255. package/src/tools/worker-evidence.ts +35 -12
  256. package/dist/chunk-MNA4JGU4.js +0 -255
  257. package/dist/chunk-SRF2PJNW.js +0 -184
  258. package/dist/chunk-T6YILFSB.js +0 -80
  259. package/dist/chunk-VAKQQHWR.js +0 -434
@@ -0,0 +1,1214 @@
1
+ import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
+ import {
3
+ discoverDeclaredChecksAtRoot,
4
+ verifyTool
5
+ } from "./chunk-PCZJO5TI.js";
6
+ import "./chunk-NILBFAPG.js";
7
+ import {
8
+ PROJECT_VERIFIER_CATALOG_CAPS,
9
+ PROJECT_VERIFIER_CATALOG_RELATIVE_PATH,
10
+ PROJECT_VERIFIER_CATALOG_VERSION,
11
+ compareCodepoints,
12
+ loadProjectVerifierCatalog,
13
+ parseProjectVerifierCatalogText
14
+ } from "./chunk-FYYLNIL5.js";
15
+ import {
16
+ isVerificationScriptName
17
+ } from "./chunk-UL3WSD3F.js";
18
+ import "./chunk-VG7TBQIY.js";
19
+ import "./chunk-OQE5J4C6.js";
20
+ import "./chunk-ECH6PKUQ.js";
21
+ import "./chunk-6XLNIQDB.js";
22
+ import "./chunk-5B2AEOW5.js";
23
+ import "./chunk-CGKSTWHD.js";
24
+ import {
25
+ printError,
26
+ printOk
27
+ } from "./chunk-ED4KHGC3.js";
28
+ import "./chunk-5TSRNF4G.js";
29
+ import {
30
+ SAFE_EXEC_DEFAULT_TIMEOUT_MS,
31
+ resolveSafeCwd
32
+ } from "./chunk-VEZEGCGW.js";
33
+ import "./chunk-FQ4SKYE4.js";
34
+ import "./chunk-FCSXB6T2.js";
35
+ import {
36
+ require_dist
37
+ } from "./chunk-APJ265NV.js";
38
+ import "./chunk-YXLYO42X.js";
39
+ import "./chunk-BNAZZHFG.js";
40
+ import "./chunk-6EJMN2Y3.js";
41
+ import {
42
+ __toESM,
43
+ init_esm_shims
44
+ } from "./chunk-3R73A4XB.js";
45
+
46
+ // src/cli/verifiers.ts
47
+ init_esm_shims();
48
+
49
+ // src/tools/verify/authoring.ts
50
+ init_esm_shims();
51
+ var import_yaml = __toESM(require_dist(), 1);
52
+ import { randomUUID } from "node:crypto";
53
+ import {
54
+ existsSync,
55
+ mkdirSync,
56
+ readFileSync,
57
+ realpathSync,
58
+ renameSync,
59
+ rmSync,
60
+ statSync,
61
+ writeFileSync
62
+ } from "node:fs";
63
+ import path from "node:path";
64
+ var DECLARED_FILE_CAP_BYTES = 1024 * 1024;
65
+ var VALIDATION_CONTRACT_PATHS = [
66
+ ".clio-coder/validation.yaml",
67
+ ".clio-coder/validation.yml",
68
+ "validation.yaml",
69
+ "validation.yml"
70
+ ];
71
+ function manualEntryInstruction() {
72
+ return 'No unambiguous declared command was found. Add one explicitly with `clio-coder verifiers add --id <id> --description <text> --command \'["executable","arg"]\'`; `--command` is an exact JSON argv array. Review the preview, then rerun with `--yes`.';
73
+ }
74
+ function cloneCheck(check) {
75
+ return {
76
+ ...check,
77
+ command: [...check.command],
78
+ tags: [...check.tags],
79
+ provenance: { ...check.provenance }
80
+ };
81
+ }
82
+ function relativePath(workspaceRoot, filePath) {
83
+ const relative = path.relative(workspaceRoot, filePath);
84
+ return relative.length === 0 ? "." : relative.split(path.sep).join("/");
85
+ }
86
+ function regularFileText(filePath, workspaceRoot) {
87
+ if (!existsSync(filePath)) return null;
88
+ try {
89
+ const realRoot = realpathSync(workspaceRoot);
90
+ const realFilePath = realpathSync(filePath);
91
+ resolveSafeCwd(realFilePath, realRoot);
92
+ const stats = statSync(realFilePath);
93
+ if (!stats.isFile()) return new Error("path is not a regular file");
94
+ if (stats.size > DECLARED_FILE_CAP_BYTES) {
95
+ return new Error(`file exceeds the ${DECLARED_FILE_CAP_BYTES}-byte discovery cap`);
96
+ }
97
+ return readFileSync(realFilePath, "utf8");
98
+ } catch (error) {
99
+ return error instanceof Error ? error : new Error(String(error));
100
+ }
101
+ }
102
+ function slug(value, fallback) {
103
+ const normalized = value.toLowerCase().replace(/[^a-z0-9._:-]+/gu, "-").replace(/^[^a-z0-9]+/u, "").replace(/[-.:]+$/u, "");
104
+ return normalized.length > 0 ? normalized : fallback;
105
+ }
106
+ function boundedId(base, suffix = "") {
107
+ const cap = PROJECT_VERIFIER_CATALOG_CAPS.idBytes - Buffer.byteLength(suffix, "utf8");
108
+ let result = "";
109
+ for (const character of base) {
110
+ if (Buffer.byteLength(result + character, "utf8") > cap) break;
111
+ result += character;
112
+ }
113
+ result = result.replace(/[-.:]+$/u, "");
114
+ return `${result.length > 0 ? result : "check"}${suffix}`;
115
+ }
116
+ function deterministicVerifierId(preferredId, occupied) {
117
+ const base = boundedId(slug(preferredId, "check"));
118
+ if (!occupied.has(base) && base !== "frontend") return base;
119
+ for (let index = 2; index <= PROJECT_VERIFIER_CATALOG_CAPS.checks + 2; index += 1) {
120
+ const suffix = `-${index}`;
121
+ const candidate = boundedId(base, suffix);
122
+ if (!occupied.has(candidate) && candidate !== "frontend") return candidate;
123
+ }
124
+ throw new Error(`cannot allocate a deterministic ID for '${preferredId}' within the catalog cap`);
125
+ }
126
+ function rawProposalSort(left, right) {
127
+ return compareCodepoints(left.provenance.path, right.provenance.path) || compareCodepoints(left.provenance.detail, right.provenance.detail) || compareCodepoints(left.preferredId, right.preferredId) || compareCodepoints(JSON.stringify(left.command), JSON.stringify(right.command));
128
+ }
129
+ function checkIdentity(check) {
130
+ return JSON.stringify([check.cwd, check.command]);
131
+ }
132
+ function sourceProvenance(workspaceRoot, check) {
133
+ if (check.source.kind === "package.json") {
134
+ return {
135
+ kind: "package-script",
136
+ path: relativePath(workspaceRoot, check.source.path),
137
+ detail: `package.json script '${check.id}'`,
138
+ authority: "project-declared"
139
+ };
140
+ }
141
+ return {
142
+ kind: "project-catalog",
143
+ path: PROJECT_VERIFIER_CATALOG_RELATIVE_PATH,
144
+ detail: `existing catalog check '${check.id}'`,
145
+ authority: "project-declared"
146
+ };
147
+ }
148
+ function projectedCheck(workspaceRoot, check) {
149
+ return {
150
+ id: check.id,
151
+ description: check.description,
152
+ command: [...check.command],
153
+ cwd: check.cwd,
154
+ timeoutMs: check.timeoutMs,
155
+ tags: [...check.tags],
156
+ provenance: sourceProvenance(workspaceRoot, check),
157
+ state: check.source.kind === "package.json" ? "active" : "existing",
158
+ ...check.source.kind === "package.json" ? {} : { catalogId: check.id }
159
+ };
160
+ }
161
+ function cargoProposals(workspaceRoot, diagnostics) {
162
+ const relative = "Cargo.toml";
163
+ const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
164
+ if (text === null) return [];
165
+ if (text instanceof Error) {
166
+ diagnostics.push(`${relative}: ${text.message}; Cargo discovery skipped.`);
167
+ return [];
168
+ }
169
+ const workspace = /^\s*\[workspace(?:\]|\.)/mu.test(text);
170
+ const packageManifest = /^\s*\[package\]/mu.test(text);
171
+ if (!workspace && !packageManifest) {
172
+ diagnostics.push(`${relative}: no [package] or [workspace] declaration was found; Cargo discovery skipped.`);
173
+ return [];
174
+ }
175
+ return [
176
+ {
177
+ preferredId: "cargo-test",
178
+ description: workspace ? "Run the Cargo workspace tests" : "Run the Cargo package tests",
179
+ command: workspace ? ["cargo", "test", "--workspace"] : ["cargo", "test"],
180
+ cwd: ".",
181
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
182
+ tags: ["rust", "test"],
183
+ provenance: {
184
+ kind: "cargo",
185
+ path: relative,
186
+ detail: workspace ? "Cargo [workspace] manifest" : "Cargo package manifest",
187
+ authority: "toolchain-defined"
188
+ }
189
+ }
190
+ ];
191
+ }
192
+ function cmakeProposals(workspaceRoot, diagnostics) {
193
+ const relative = "CMakePresets.json";
194
+ const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
195
+ if (text === null) return [];
196
+ if (text instanceof Error) {
197
+ diagnostics.push(`${relative}: ${text.message}; CMake preset discovery skipped.`);
198
+ return [];
199
+ }
200
+ let parsed;
201
+ try {
202
+ parsed = JSON.parse(text);
203
+ } catch (error) {
204
+ diagnostics.push(`${relative}: invalid JSON (${error instanceof Error ? error.message : String(error)}).`);
205
+ return [];
206
+ }
207
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
208
+ diagnostics.push(`${relative}: root is not an object; CMake preset discovery skipped.`);
209
+ return [];
210
+ }
211
+ const record = parsed;
212
+ const proposals = [];
213
+ for (const [field, executable, args, label, tag] of [
214
+ ["testPresets", "ctest", ["--preset"], "test", "test"],
215
+ ["buildPresets", "cmake", ["--build", "--preset"], "build", "build"]
216
+ ]) {
217
+ const presets = record[field];
218
+ if (!Array.isArray(presets)) continue;
219
+ for (const preset of presets) {
220
+ if (preset === null || typeof preset !== "object" || Array.isArray(preset)) continue;
221
+ const value = preset;
222
+ if (value.hidden === true || typeof value.name !== "string" || value.name.length === 0) continue;
223
+ const name = value.name;
224
+ proposals.push({
225
+ preferredId: `cmake-${label}-${slug(name, "preset")}`,
226
+ description: `Run CMake ${label} preset '${name}'`,
227
+ command: [executable, ...args, name],
228
+ cwd: ".",
229
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
230
+ tags: ["cmake", tag],
231
+ provenance: {
232
+ kind: "cmake-preset",
233
+ path: relative,
234
+ detail: `${field} entry '${name}'`,
235
+ authority: "toolchain-defined"
236
+ }
237
+ });
238
+ }
239
+ }
240
+ if (proposals.length === 0) diagnostics.push(`${relative}: no visible buildPresets or testPresets were declared.`);
241
+ return proposals;
242
+ }
243
+ function tomlSections(text) {
244
+ const sections = /* @__PURE__ */ new Map();
245
+ let active = "";
246
+ for (const line of text.split(/\r?\n/u)) {
247
+ const header = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/u.exec(line);
248
+ if (header?.[1] !== void 0) {
249
+ active = header[1].trim();
250
+ if (!sections.has(active)) sections.set(active, []);
251
+ continue;
252
+ }
253
+ if (active.length > 0) sections.get(active)?.push(line);
254
+ }
255
+ return sections;
256
+ }
257
+ function declaredScriptName(line) {
258
+ const match = /^\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_.:-]+))\s*=\s*(?:"[^"]+"|'[^']+')\s*(?:#.*)?$/u.exec(line);
259
+ return match?.[1] ?? match?.[2] ?? match?.[3] ?? null;
260
+ }
261
+ function pythonProposals(workspaceRoot, diagnostics) {
262
+ const proposals = [];
263
+ const pyprojectPath = "pyproject.toml";
264
+ const pyproject = regularFileText(path.join(workspaceRoot, pyprojectPath), workspaceRoot);
265
+ if (pyproject instanceof Error) diagnostics.push(`${pyprojectPath}: ${pyproject.message}; Python discovery skipped.`);
266
+ if (typeof pyproject === "string") {
267
+ const sections = tomlSections(pyproject);
268
+ for (const [section, module, id, description, tags2] of [
269
+ ["tool.pytest.ini_options", "pytest", "python-pytest", "Run the declared pytest suite", ["python", "test"]],
270
+ ["tool.tox", "tox", "python-tox", "Run the declared tox environments", ["python", "test"]],
271
+ ["tool.nox", "nox", "python-nox", "Run the declared nox sessions", ["python", "test"]]
272
+ ]) {
273
+ if (!sections.has(section)) continue;
274
+ proposals.push({
275
+ preferredId: id,
276
+ description,
277
+ command: ["python", "-m", module],
278
+ cwd: ".",
279
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
280
+ tags: [...tags2],
281
+ provenance: {
282
+ kind: "python-runner",
283
+ path: pyprojectPath,
284
+ detail: `[${section}]`,
285
+ authority: "toolchain-defined"
286
+ }
287
+ });
288
+ }
289
+ for (const section of ["project.scripts", "tool.poetry.scripts"]) {
290
+ for (const line of sections.get(section) ?? []) {
291
+ const name = declaredScriptName(line);
292
+ if (name === null || !isVerificationScriptName(name)) continue;
293
+ proposals.push({
294
+ preferredId: `python-${slug(name, "check")}`,
295
+ description: `Run declared Python entry point '${name}'`,
296
+ command: [name],
297
+ cwd: ".",
298
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
299
+ tags: [slug(name.split(/[:.-]/u)[0] ?? "python", "python"), "python"],
300
+ provenance: {
301
+ kind: "python-runner",
302
+ path: pyprojectPath,
303
+ detail: `[${section}] entry '${name}'`,
304
+ authority: "project-declared"
305
+ }
306
+ });
307
+ }
308
+ }
309
+ }
310
+ for (const [relative, marker, module, id, description] of [
311
+ ["pytest.ini", null, "pytest", "python-pytest", "Run the declared pytest suite"],
312
+ ["tox.ini", null, "tox", "python-tox", "Run the declared tox environments"],
313
+ ["noxfile.py", null, "nox", "python-nox", "Run the declared nox sessions"],
314
+ ["setup.cfg", /^\s*\[tool:pytest\]/mu, "pytest", "python-pytest", "Run the declared pytest suite"]
315
+ ]) {
316
+ const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
317
+ if (text === null) continue;
318
+ if (text instanceof Error) {
319
+ diagnostics.push(`${relative}: ${text.message}; Python discovery skipped.`);
320
+ continue;
321
+ }
322
+ if (marker !== null && !marker.test(text)) continue;
323
+ proposals.push({
324
+ preferredId: id,
325
+ description,
326
+ command: ["python", "-m", module],
327
+ cwd: ".",
328
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
329
+ tags: ["python", "test"],
330
+ provenance: {
331
+ kind: "python-runner",
332
+ path: relative,
333
+ detail: `${module} configuration file`,
334
+ authority: "toolchain-defined"
335
+ }
336
+ });
337
+ }
338
+ return proposals;
339
+ }
340
+ function goProposals(workspaceRoot, diagnostics) {
341
+ const relative = "go.mod";
342
+ const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
343
+ if (text === null) return [];
344
+ if (text instanceof Error) {
345
+ diagnostics.push(`${relative}: ${text.message}; Go discovery skipped.`);
346
+ return [];
347
+ }
348
+ if (!/^\s*module\s+\S+/mu.test(text)) {
349
+ diagnostics.push(`${relative}: no module directive was found; Go discovery skipped.`);
350
+ return [];
351
+ }
352
+ return [
353
+ {
354
+ preferredId: "go-test",
355
+ description: "Run all Go module tests",
356
+ command: ["go", "test", "./..."],
357
+ cwd: ".",
358
+ timeoutMs: SAFE_EXEC_DEFAULT_TIMEOUT_MS,
359
+ tags: ["go", "test"],
360
+ provenance: {
361
+ kind: "go-module",
362
+ path: relative,
363
+ detail: "Go module directive",
364
+ authority: "toolchain-defined"
365
+ }
366
+ }
367
+ ];
368
+ }
369
+ function shellLikeArgv(command) {
370
+ const argv = [];
371
+ let token = "";
372
+ let quote = null;
373
+ let tokenStarted = false;
374
+ for (let index = 0; index < command.length; index += 1) {
375
+ const character = command[index] ?? "";
376
+ if (quote === "single") {
377
+ if (character === "'") quote = null;
378
+ else token += character;
379
+ tokenStarted = true;
380
+ continue;
381
+ }
382
+ if (quote === "double") {
383
+ if (character === '"') {
384
+ quote = null;
385
+ continue;
386
+ }
387
+ if (character === "\\") {
388
+ const next = command[index + 1];
389
+ if (next === void 0) return new Error("trailing escape");
390
+ token += next;
391
+ index += 1;
392
+ } else if (character === "$" || character === "`") {
393
+ return new Error(`shell expansion '${character}' is ambiguous`);
394
+ } else {
395
+ token += character;
396
+ }
397
+ tokenStarted = true;
398
+ continue;
399
+ }
400
+ if (/\s/u.test(character)) {
401
+ if (tokenStarted) {
402
+ argv.push(token);
403
+ token = "";
404
+ tokenStarted = false;
405
+ }
406
+ continue;
407
+ }
408
+ if (character === "'") {
409
+ quote = "single";
410
+ tokenStarted = true;
411
+ continue;
412
+ }
413
+ if (character === '"') {
414
+ quote = "double";
415
+ tokenStarted = true;
416
+ continue;
417
+ }
418
+ if (character === "\\") {
419
+ const next = command[index + 1];
420
+ if (next === void 0) return new Error("trailing escape");
421
+ token += next;
422
+ tokenStarted = true;
423
+ index += 1;
424
+ continue;
425
+ }
426
+ if ("|&;<>()`$\n\r".includes(character)) {
427
+ return new Error(`shell operator or expansion '${character}' is ambiguous`);
428
+ }
429
+ token += character;
430
+ tokenStarted = true;
431
+ }
432
+ if (quote !== null) return new Error(`unterminated ${quote}-quoted argument`);
433
+ if (tokenStarted) argv.push(token);
434
+ if (argv.length === 0) return new Error("empty command");
435
+ if ((argv[0] ?? "").includes("=")) return new Error("environment assignments are not argv executables");
436
+ return argv;
437
+ }
438
+ function validatorArgv(value) {
439
+ if (typeof value === "string") return shellLikeArgv(value);
440
+ if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== "string" || entry.length === 0)) {
441
+ return new Error("validator must be a command string or a non-empty argv string array");
442
+ }
443
+ return [...value];
444
+ }
445
+ function validationPreferredId(argv) {
446
+ const executable = path.basename(argv[0] ?? "check").replace(/\.[^.]+$/u, "");
447
+ const script = argv.find((entry, index) => index > 0 && /\.(?:py|js|mjs|sh)$/u.test(entry));
448
+ const subject = script === void 0 ? executable : path.basename(script).replace(/\.[^.]+$/u, "");
449
+ return `validation-${slug(subject, "check")}`;
450
+ }
451
+ function validationContractProposals(workspaceRoot, diagnostics) {
452
+ const proposals = [];
453
+ for (const relative of VALIDATION_CONTRACT_PATHS) {
454
+ const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
455
+ if (text === null) continue;
456
+ if (text instanceof Error) {
457
+ diagnostics.push(`${relative}: ${text.message}; validation command discovery skipped.`);
458
+ continue;
459
+ }
460
+ const document = (0, import_yaml.parseDocument)(text, { prettyErrors: false, strict: true, uniqueKeys: true });
461
+ if (document.errors.length > 0) {
462
+ diagnostics.push(`${relative}: invalid YAML; validation command discovery skipped.`);
463
+ continue;
464
+ }
465
+ let parsed;
466
+ try {
467
+ parsed = document.toJS({ maxAliasCount: 0 });
468
+ } catch (error) {
469
+ diagnostics.push(`${relative}: invalid YAML (${error instanceof Error ? error.message : String(error)}).`);
470
+ continue;
471
+ }
472
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) continue;
473
+ const validators = parsed.validators;
474
+ if (!Array.isArray(validators)) continue;
475
+ for (const [index, validator] of validators.entries()) {
476
+ const record = validator !== null && typeof validator === "object" && !Array.isArray(validator) ? validator : null;
477
+ if (record !== null) {
478
+ const typedFields = [
479
+ ["id", (value) => typeof value === "string"],
480
+ ["description", (value) => typeof value === "string"],
481
+ ["cwd", (value) => typeof value === "string"],
482
+ ["timeoutMs", (value) => typeof value === "number"],
483
+ ["tags", (value) => Array.isArray(value) && value.every((tag) => typeof tag === "string")]
484
+ ];
485
+ const invalidField = typedFields.find(([field, valid]) => Object.hasOwn(record, field) && !valid(record[field]));
486
+ if (invalidField !== void 0) {
487
+ diagnostics.push(
488
+ `${relative}: validators[${index}].${String(invalidField[0])} has an ambiguous type; use manual argv entry.`
489
+ );
490
+ continue;
491
+ }
492
+ }
493
+ const commandValue = record === null ? validator : record.command;
494
+ const argv = validatorArgv(commandValue);
495
+ if (argv instanceof Error) {
496
+ diagnostics.push(`${relative}: validators[${index}] is ambiguous (${argv.message}); use manual argv entry.`);
497
+ continue;
498
+ }
499
+ const declaredId = typeof record?.id === "string" ? record.id : validationPreferredId(argv);
500
+ const description = typeof record?.description === "string" ? record.description : `Run validation contract command ${JSON.stringify(argv)}`;
501
+ const cwd = typeof record?.cwd === "string" ? record.cwd : ".";
502
+ const timeoutMs = typeof record?.timeoutMs === "number" ? record.timeoutMs : SAFE_EXEC_DEFAULT_TIMEOUT_MS;
503
+ const tags2 = Array.isArray(record?.tags) ? record.tags.filter((tag) => typeof tag === "string") : [];
504
+ proposals.push({
505
+ preferredId: declaredId,
506
+ description,
507
+ command: argv,
508
+ cwd,
509
+ timeoutMs,
510
+ tags: tags2.length > 0 ? tags2 : ["scientific", "validation"],
511
+ provenance: {
512
+ kind: "validation-contract",
513
+ path: relative,
514
+ detail: `validators[${index}]`,
515
+ authority: "project-declared"
516
+ }
517
+ });
518
+ }
519
+ }
520
+ if (existsSync(path.join(workspaceRoot, "VALIDATION.md"))) {
521
+ diagnostics.push(
522
+ "VALIDATION.md is advisory prose; enter an exact argv vector manually instead of inferring a command."
523
+ );
524
+ }
525
+ return proposals;
526
+ }
527
+ function deduplicatedRawProposals(proposals, diagnostics) {
528
+ const seen = /* @__PURE__ */ new Map();
529
+ for (const proposal of proposals.sort(rawProposalSort)) {
530
+ const identity = checkIdentity(proposal);
531
+ const prior = seen.get(identity);
532
+ if (prior !== void 0) {
533
+ diagnostics.push(
534
+ `${proposal.provenance.path} (${proposal.provenance.detail}) repeats ${prior.provenance.path} (${prior.provenance.detail}); one proposal was kept.`
535
+ );
536
+ continue;
537
+ }
538
+ seen.set(identity, proposal);
539
+ }
540
+ return [...seen.values()];
541
+ }
542
+ function discoverVerifierAuthoring(workspaceRoot = process.cwd()) {
543
+ const manualEntry = manualEntryInstruction();
544
+ const productionDiscovery = discoverDeclaredChecksAtRoot(workspaceRoot, void 0);
545
+ if (!productionDiscovery.ok) {
546
+ return {
547
+ ok: false,
548
+ reason: `Cannot author over the existing verifier authority: ${productionDiscovery.reason}`,
549
+ manualEntry
550
+ };
551
+ }
552
+ const activeChecks = [];
553
+ const existingChecks = [];
554
+ for (const source of productionDiscovery.sources) {
555
+ for (const check of source.checks) {
556
+ const projected = projectedCheck(workspaceRoot, check);
557
+ if (projected.state === "active") activeChecks.push(projected);
558
+ else existingChecks.push(projected);
559
+ }
560
+ }
561
+ activeChecks.sort((left, right) => compareCodepoints(left.id, right.id));
562
+ existingChecks.sort((left, right) => compareCodepoints(left.id, right.id));
563
+ const diagnostics = [];
564
+ const raw = deduplicatedRawProposals(
565
+ [
566
+ ...cargoProposals(workspaceRoot, diagnostics),
567
+ ...cmakeProposals(workspaceRoot, diagnostics),
568
+ ...pythonProposals(workspaceRoot, diagnostics),
569
+ ...goProposals(workspaceRoot, diagnostics),
570
+ ...validationContractProposals(workspaceRoot, diagnostics)
571
+ ],
572
+ diagnostics
573
+ );
574
+ const occupied = new Set([...activeChecks, ...existingChecks].map((check) => check.id));
575
+ const represented = new Map(existingChecks.map((check) => [checkIdentity(check), check.id]));
576
+ const proposals = [];
577
+ for (const proposal of raw) {
578
+ const priorId = represented.get(checkIdentity(proposal));
579
+ if (priorId !== void 0) {
580
+ diagnostics.push(
581
+ `${proposal.provenance.path} (${proposal.provenance.detail}) is already represented by catalog check '${priorId}'.`
582
+ );
583
+ continue;
584
+ }
585
+ const normalizedId = boundedId(slug(proposal.preferredId, "check"));
586
+ const id = deterministicVerifierId(proposal.preferredId, occupied);
587
+ if (normalizedId !== proposal.preferredId) {
588
+ diagnostics.push(`Proposed ID '${proposal.preferredId}' was normalized to '${normalizedId}'.`);
589
+ }
590
+ if (id !== normalizedId) {
591
+ diagnostics.push(`Proposed ID '${normalizedId}' collides with declared authority; using '${id}'.`);
592
+ }
593
+ occupied.add(id);
594
+ represented.set(checkIdentity(proposal), id);
595
+ proposals.push({
596
+ id,
597
+ description: proposal.description,
598
+ command: [...proposal.command],
599
+ cwd: proposal.cwd,
600
+ timeoutMs: proposal.timeoutMs,
601
+ tags: [...proposal.tags],
602
+ provenance: { ...proposal.provenance },
603
+ state: "proposed"
604
+ });
605
+ }
606
+ proposals.sort((left, right) => compareCodepoints(left.id, right.id));
607
+ if (activeChecks.length === 0 && existingChecks.length === 0 && proposals.length === 0) {
608
+ diagnostics.push(
609
+ "No package verification script, supported toolchain declaration, or exact validation command was found."
610
+ );
611
+ }
612
+ const catalogPath = path.join(workspaceRoot, PROJECT_VERIFIER_CATALOG_RELATIVE_PATH);
613
+ const catalogText = regularFileText(catalogPath, workspaceRoot);
614
+ return {
615
+ ok: true,
616
+ workspaceRoot,
617
+ catalogPath,
618
+ activeChecks,
619
+ existingChecks,
620
+ proposals,
621
+ diagnostics,
622
+ manualEntry,
623
+ ...typeof catalogText === "string" ? { catalogText } : {}
624
+ };
625
+ }
626
+ function createVerifierDraft(discovery, options = {}) {
627
+ return {
628
+ workspaceRoot: discovery.workspaceRoot,
629
+ catalogPath: discovery.catalogPath,
630
+ activeChecks: discovery.activeChecks.map(cloneCheck),
631
+ checks: [...discovery.existingChecks, ...options.includeProposals === false ? [] : discovery.proposals].map(cloneCheck).sort((left, right) => compareCodepoints(left.id, right.id)),
632
+ diagnostics: [...discovery.diagnostics],
633
+ manualEntry: discovery.manualEntry,
634
+ ...discovery.catalogText === void 0 ? {} : { catalogText: discovery.catalogText }
635
+ };
636
+ }
637
+ function catalogEntry({ id, description, command, cwd, timeoutMs, tags: tags2 }) {
638
+ return { id, description, command: [...command], cwd, timeoutMs, tags: [...tags2] };
639
+ }
640
+ function serializeVerifierDraft(draft) {
641
+ const checks = [...draft.checks].sort((left, right) => compareCodepoints(left.id, right.id));
642
+ const document = draft.catalogText === void 0 ? null : (0, import_yaml.parseDocument)(draft.catalogText);
643
+ const sequence = document?.get("checks");
644
+ if (document === null || !(0, import_yaml.isSeq)(sequence)) {
645
+ return (0, import_yaml.stringify)({ version: PROJECT_VERIFIER_CATALOG_VERSION, checks: checks.map(catalogEntry) }, { lineWidth: 0 });
646
+ }
647
+ const nodes = /* @__PURE__ */ new Map();
648
+ for (const node of sequence.items) if ((0, import_yaml.isMap)(node)) nodes.set(node.get("id"), node);
649
+ const kept = /* @__PURE__ */ new Set();
650
+ const appended = [];
651
+ let changed = false;
652
+ for (const check of checks) {
653
+ const entry = catalogEntry(check);
654
+ const node = nodes.get(check.catalogId ?? check.id);
655
+ if (node === void 0) {
656
+ appended.push(document.createNode(entry));
657
+ continue;
658
+ }
659
+ kept.add(node);
660
+ const current = node.toJSON();
661
+ for (const [field, value] of Object.entries(entry)) {
662
+ if (JSON.stringify(current[field]) === JSON.stringify(value)) continue;
663
+ node.set(field, value);
664
+ changed = true;
665
+ }
666
+ }
667
+ if (!changed && appended.length === 0 && kept.size === sequence.items.length) return draft.catalogText;
668
+ sequence.items = [...sequence.items.filter((node) => (0, import_yaml.isMap)(node) && kept.has(node)), ...appended];
669
+ return document.toString({ lineWidth: 0 });
670
+ }
671
+ function validateVerifierDraft(draft) {
672
+ const text = serializeVerifierDraft(draft);
673
+ const parsed = parseProjectVerifierCatalogText(text, draft.workspaceRoot, draft.catalogPath);
674
+ if (!parsed.ok) return { ok: false, reason: parsed.reason, text };
675
+ const activeId = new Map(draft.activeChecks.map((check) => [check.id, check]));
676
+ for (const check of parsed.source?.checks ?? []) {
677
+ const collision = activeId.get(check.id);
678
+ if (collision !== void 0) {
679
+ return {
680
+ ok: false,
681
+ reason: `duplicate declared check id '${check.id}' from ${collision.provenance.kind} (${collision.provenance.path}) and project-catalog (${PROJECT_VERIFIER_CATALOG_RELATIVE_PATH})`,
682
+ text
683
+ };
684
+ }
685
+ }
686
+ const byId = new Map(draft.checks.map((check) => [check.id, check]));
687
+ const checks = (parsed.source?.checks ?? []).map((check) => {
688
+ const original = byId.get(check.id);
689
+ return {
690
+ id: check.id,
691
+ description: check.description,
692
+ command: [...check.command],
693
+ cwd: check.cwd,
694
+ timeoutMs: check.timeoutMs,
695
+ tags: [...check.tags],
696
+ provenance: original?.provenance ?? {
697
+ kind: "manual-entry",
698
+ path: PROJECT_VERIFIER_CATALOG_RELATIVE_PATH,
699
+ detail: `manual check '${check.id}'`,
700
+ authority: "project-declared"
701
+ },
702
+ state: original?.state ?? "manual",
703
+ ...original?.catalogId === void 0 ? {} : { catalogId: original.catalogId }
704
+ };
705
+ });
706
+ return { ok: true, text, checks };
707
+ }
708
+ function cloneDraft(draft) {
709
+ return {
710
+ ...draft,
711
+ activeChecks: draft.activeChecks.map(cloneCheck),
712
+ checks: draft.checks.map(cloneCheck),
713
+ diagnostics: [...draft.diagnostics]
714
+ };
715
+ }
716
+ function reviseVerifierDraft(draft, revisions) {
717
+ const next = cloneDraft(draft);
718
+ const diagnostics = [];
719
+ for (const revision of revisions) {
720
+ if (revision.kind === "add") {
721
+ if (next.checks.some((check2) => check2.id === revision.check.id)) {
722
+ return { ok: false, draft, reason: `Cannot add '${revision.check.id}': that ID already exists.` };
723
+ }
724
+ if (next.activeChecks.some((check2) => check2.id === revision.check.id)) {
725
+ return { ok: false, draft, reason: `Cannot add '${revision.check.id}': it collides with an active package check.` };
726
+ }
727
+ next.checks.push({
728
+ ...revision.check,
729
+ command: [...revision.check.command],
730
+ tags: [...revision.check.tags],
731
+ provenance: revision.provenance ?? {
732
+ kind: "manual-entry",
733
+ path: PROJECT_VERIFIER_CATALOG_RELATIVE_PATH,
734
+ detail: `manual check '${revision.check.id}'`,
735
+ authority: "project-declared"
736
+ },
737
+ state: "manual"
738
+ });
739
+ diagnostics.push(`Added check '${revision.check.id}'.`);
740
+ continue;
741
+ }
742
+ const index = next.checks.findIndex((check2) => check2.id === revision.id);
743
+ if (index === -1) return { ok: false, draft, reason: `Check '${revision.id}' does not exist.` };
744
+ const check = next.checks[index];
745
+ if (check === void 0) return { ok: false, draft, reason: `Check '${revision.id}' does not exist.` };
746
+ if (revision.kind === "remove") {
747
+ next.checks.splice(index, 1);
748
+ diagnostics.push(`Removed check '${revision.id}'; its command is no longer executable through the catalog.`);
749
+ continue;
750
+ }
751
+ if (revision.kind === "rename") {
752
+ if (next.checks.some((candidate, candidateIndex) => candidateIndex !== index && candidate.id === revision.newId)) {
753
+ return {
754
+ ok: false,
755
+ draft,
756
+ reason: `Cannot rename '${revision.id}' to '${revision.newId}': that ID already exists.`
757
+ };
758
+ }
759
+ if (next.activeChecks.some((candidate) => candidate.id === revision.newId)) {
760
+ return {
761
+ ok: false,
762
+ draft,
763
+ reason: `Cannot rename '${revision.id}' to '${revision.newId}': it collides with an active package check.`
764
+ };
765
+ }
766
+ check.id = revision.newId;
767
+ diagnostics.push(`Renamed check '${revision.id}' to '${revision.newId}'.`);
768
+ continue;
769
+ }
770
+ if (revision.changes.description !== void 0) check.description = revision.changes.description;
771
+ if (revision.changes.command !== void 0) check.command = [...revision.changes.command];
772
+ if (revision.changes.cwd !== void 0) check.cwd = revision.changes.cwd;
773
+ if (revision.changes.timeoutMs !== void 0) check.timeoutMs = revision.changes.timeoutMs;
774
+ if (revision.changes.tags !== void 0) check.tags = [...revision.changes.tags];
775
+ diagnostics.push(`Edited check '${revision.id}' without changing its deterministic ID.`);
776
+ }
777
+ next.checks.sort((left, right) => compareCodepoints(left.id, right.id));
778
+ const validation = validateVerifierDraft(next);
779
+ if (!validation.ok) return { ok: false, draft, reason: validation.reason };
780
+ next.checks = validation.checks;
781
+ next.diagnostics.push(...diagnostics);
782
+ return { ok: true, draft: next, diagnostics };
783
+ }
784
+ function authorityDescription(check) {
785
+ if (check.state === "active") {
786
+ return "active package-script authority; verify runs npm with the declared script name and may accept explicit extra argv";
787
+ }
788
+ return `exact catalog authority after confirmation; verify fixes argv, cwd, and timeout through safe-exec (proposal origin: ${check.provenance.authority})`;
789
+ }
790
+ function renderCheck(check, destinationPath) {
791
+ return [
792
+ `- ${check.id}`,
793
+ ` path: ${check.state === "active" ? check.provenance.path : destinationPath}`,
794
+ ` source: ${check.provenance.path} (${check.provenance.detail}; ${check.provenance.authority})`,
795
+ ` argv: ${JSON.stringify(check.command)}`,
796
+ ` cwd: ${check.cwd}`,
797
+ ` timeoutMs: ${check.timeoutMs}`,
798
+ ` tags: ${JSON.stringify(check.tags)}`,
799
+ ` effective execution authority: ${authorityDescription(check)}`
800
+ ];
801
+ }
802
+ function previewVerifierDraft(draft, options = {}) {
803
+ const validation = validateVerifierDraft(draft);
804
+ const lines = [
805
+ "Project verifier authority preview",
806
+ `Catalog path: ${draft.catalogPath}`,
807
+ `Schema validation: ${validation.ok ? "accepted by the production catalog parser" : `rejected (${validation.reason})`}`
808
+ ];
809
+ if (draft.activeChecks.length > 0) {
810
+ lines.push("", "Already executable package checks (not duplicated into the catalog):");
811
+ for (const check of draft.activeChecks) lines.push(...renderCheck(check, draft.catalogPath));
812
+ }
813
+ lines.push("", "Catalog checks after confirmation:");
814
+ if (draft.checks.length === 0) lines.push("(none)");
815
+ else for (const check of draft.checks) lines.push(...renderCheck(check, draft.catalogPath));
816
+ if (draft.diagnostics.length > 0) {
817
+ lines.push("", "Diagnostics:");
818
+ for (const diagnostic of draft.diagnostics) lines.push(`- ${diagnostic}`);
819
+ }
820
+ if (draft.checks.length === 0) {
821
+ lines.push(
822
+ "",
823
+ draft.activeChecks.length === 0 ? draft.manualEntry : "No catalog checks are proposed; the package checks above are already executable without a catalog entry."
824
+ );
825
+ }
826
+ if (options.confirmed !== true) {
827
+ lines.push("", "Preview only: no file has been written and no check has been executed.");
828
+ }
829
+ return lines.join("\n");
830
+ }
831
+ function writeValidatedDraft(draft, validation) {
832
+ const directory = path.dirname(draft.catalogPath);
833
+ mkdirSync(directory, { recursive: true });
834
+ const realRoot = realpathSync(draft.workspaceRoot);
835
+ const realDirectory = realpathSync(directory);
836
+ resolveSafeCwd(realDirectory, realRoot);
837
+ const realCatalogPath = path.join(realDirectory, path.basename(draft.catalogPath));
838
+ const temporaryPath = path.join(
839
+ realDirectory,
840
+ `.${path.basename(draft.catalogPath)}.${process.pid}.${randomUUID()}.tmp`
841
+ );
842
+ try {
843
+ writeFileSync(temporaryPath, validation.text, { encoding: "utf8", flag: "wx", mode: 420 });
844
+ renameSync(temporaryPath, realCatalogPath);
845
+ } catch (error) {
846
+ rmSync(temporaryPath, { force: true });
847
+ throw error;
848
+ }
849
+ }
850
+ async function runVerifierAuthoringWorkflow(options) {
851
+ const workspaceRoot = options.workspaceRoot ?? process.cwd();
852
+ const discovery = discoverVerifierAuthoring(workspaceRoot);
853
+ if (!discovery.ok) return { status: "invalid", reason: discovery.reason, wrote: false };
854
+ let draft = createVerifierDraft(
855
+ discovery,
856
+ options.includeProposals === void 0 ? {} : { includeProposals: options.includeProposals }
857
+ );
858
+ if (options.initialRevisions !== void 0 && options.initialRevisions.length > 0) {
859
+ const revised = reviseVerifierDraft(draft, options.initialRevisions);
860
+ if (!revised.ok) return { status: "invalid", reason: revised.reason, wrote: false };
861
+ draft = revised.draft;
862
+ }
863
+ for (let revision = 0; revision <= PROJECT_VERIFIER_CATALOG_CAPS.checks; revision += 1) {
864
+ const validation = validateVerifierDraft(draft);
865
+ const preview = previewVerifierDraft(draft, { confirmed: options.confirmed === true });
866
+ const decision = await options.decide({ draft: cloneDraft(draft), preview, validation, revision });
867
+ if (decision.kind === "reject") {
868
+ return { status: "rejected", wrote: false, preview, diagnostics: [...draft.diagnostics] };
869
+ }
870
+ if (decision.kind === "revise") {
871
+ const revised = reviseVerifierDraft(draft, decision.revisions);
872
+ if (!revised.ok) {
873
+ draft.diagnostics.push(`Revision rejected: ${revised.reason}`);
874
+ continue;
875
+ }
876
+ draft = revised.draft;
877
+ continue;
878
+ }
879
+ if (!validation.ok) return { status: "invalid", reason: validation.reason, wrote: false, preview };
880
+ const authorizedPreview = previewVerifierDraft(draft, { confirmed: true });
881
+ try {
882
+ writeValidatedDraft(draft, validation);
883
+ } catch (error) {
884
+ return {
885
+ status: "invalid",
886
+ reason: `Could not write ${draft.catalogPath}: ${error instanceof Error ? error.message : String(error)}`,
887
+ wrote: false,
888
+ preview: authorizedPreview
889
+ };
890
+ }
891
+ const loaded = discoverDeclaredChecksAtRoot(workspaceRoot, void 0);
892
+ if (!loaded.ok) {
893
+ return {
894
+ status: "invalid",
895
+ reason: `Catalog was written but production discovery rejected it: ${loaded.reason}`,
896
+ wrote: true,
897
+ path: draft.catalogPath,
898
+ preview: authorizedPreview
899
+ };
900
+ }
901
+ const dryRuns = [];
902
+ const runCheck = options.runCheck ?? ((id) => verifyTool.run({ check: id }));
903
+ for (const id of decision.dryRunCheckIds ?? []) {
904
+ dryRuns.push({ id, result: await runCheck(id) });
905
+ }
906
+ return {
907
+ status: "written",
908
+ wrote: true,
909
+ path: draft.catalogPath,
910
+ preview: authorizedPreview,
911
+ diagnostics: [...draft.diagnostics],
912
+ dryRuns
913
+ };
914
+ }
915
+ return {
916
+ status: "invalid",
917
+ reason: `Revision limit of ${PROJECT_VERIFIER_CATALOG_CAPS.checks} exceeded without an operator decision.`,
918
+ wrote: false
919
+ };
920
+ }
921
+
922
+ // src/cli/verifiers.ts
923
+ var HELP = `Project verifier authoring
924
+
925
+ Usage:
926
+ clio-coder verifiers discover
927
+ clio-coder verifiers author [--exclude <id>] [--rename <old>=<new>] [--dry-run <id>] [--yes]
928
+ clio-coder verifiers validate
929
+ clio-coder verifiers dry-run <id>
930
+ clio-coder verifiers add --id <id> --description <text> --command <json-argv> [fields] [--yes]
931
+ clio-coder verifiers edit <id> [--description <text>] [--command <json-argv>] [fields] [--yes]
932
+ clio-coder verifiers rename <old> <new> [--yes]
933
+ clio-coder verifiers remove <id> [--yes]
934
+
935
+ Fields:
936
+ --cwd <path> repository-relative working directory (default .)
937
+ --timeout-ms <number> bounded timeout in milliseconds (default 120000)
938
+ --tags <a,b> comma-separated catalog tags
939
+
940
+ Discovery and every preview are read-only. Mutating commands write only with
941
+ --yes after printing the exact argv, cwd, timeout, tags, source provenance, and
942
+ effective execution authority. dry-run invokes the production verify path.
943
+ `;
944
+ var VALUE_OPTIONS = /* @__PURE__ */ new Set([
945
+ "--id",
946
+ "--description",
947
+ "--command",
948
+ "--cwd",
949
+ "--timeout-ms",
950
+ "--tags",
951
+ "--exclude",
952
+ "--rename",
953
+ "--dry-run"
954
+ ]);
955
+ function parseAuthoringArgs(argv) {
956
+ const positional = [];
957
+ const values = /* @__PURE__ */ new Map();
958
+ let yes = false;
959
+ let help = false;
960
+ for (let index = 0; index < argv.length; index += 1) {
961
+ const arg = argv[index];
962
+ if (arg === "--yes") {
963
+ yes = true;
964
+ continue;
965
+ }
966
+ if (arg === "--help" || arg === "-h") {
967
+ help = true;
968
+ continue;
969
+ }
970
+ if (arg?.startsWith("--") === true) {
971
+ if (!VALUE_OPTIONS.has(arg)) return { yes, help, positional, values, error: `unknown option: ${arg}` };
972
+ const value = argv[index + 1];
973
+ if (value === void 0 || value.startsWith("--")) {
974
+ return { yes, help, positional, values, error: `${arg} requires a value` };
975
+ }
976
+ const prior = values.get(arg) ?? [];
977
+ prior.push(value);
978
+ values.set(arg, prior);
979
+ index += 1;
980
+ continue;
981
+ }
982
+ if (arg !== void 0) positional.push(arg);
983
+ }
984
+ return { yes, help, positional, values };
985
+ }
986
+ function oneValue(parsed, option) {
987
+ return parsed.values.get(option)?.at(-1);
988
+ }
989
+ function parseCommand(value) {
990
+ if (value === void 0) return new Error("--command is required and must be a JSON argv array");
991
+ let parsed;
992
+ try {
993
+ parsed = JSON.parse(value);
994
+ } catch (error) {
995
+ return new Error(`--command must be valid JSON: ${error instanceof Error ? error.message : String(error)}`);
996
+ }
997
+ if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some((entry) => typeof entry !== "string")) {
998
+ return new Error("--command must be a non-empty JSON string array");
999
+ }
1000
+ return parsed;
1001
+ }
1002
+ function parseTimeout(value) {
1003
+ if (value === void 0) return SAFE_EXEC_DEFAULT_TIMEOUT_MS;
1004
+ const parsed = Number(value);
1005
+ if (!Number.isInteger(parsed) || parsed <= 0) return new Error("--timeout-ms must be a positive integer");
1006
+ return parsed;
1007
+ }
1008
+ function tags(value) {
1009
+ return value === void 0 ? [] : value.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
1010
+ }
1011
+ function requiredValue(parsed, option) {
1012
+ const value = oneValue(parsed, option);
1013
+ return value === void 0 || value.length === 0 ? new Error(`${option} is required`) : value;
1014
+ }
1015
+ function authorRevisions(parsed) {
1016
+ const revisions = [];
1017
+ for (const id of parsed.values.get("--exclude") ?? []) revisions.push({ kind: "remove", id });
1018
+ for (const rename of parsed.values.get("--rename") ?? []) {
1019
+ const separator = rename.indexOf("=");
1020
+ if (separator <= 0 || separator === rename.length - 1) {
1021
+ return new Error("--rename must use <old>=<new>");
1022
+ }
1023
+ revisions.push({ kind: "rename", id: rename.slice(0, separator), newId: rename.slice(separator + 1) });
1024
+ }
1025
+ return revisions;
1026
+ }
1027
+ function addRevision(parsed) {
1028
+ const id = requiredValue(parsed, "--id");
1029
+ if (id instanceof Error) return id;
1030
+ const description = requiredValue(parsed, "--description");
1031
+ if (description instanceof Error) return description;
1032
+ const command = parseCommand(oneValue(parsed, "--command"));
1033
+ if (command instanceof Error) return command;
1034
+ const timeoutMs = parseTimeout(oneValue(parsed, "--timeout-ms"));
1035
+ if (timeoutMs instanceof Error) return timeoutMs;
1036
+ return {
1037
+ kind: "add",
1038
+ check: {
1039
+ id,
1040
+ description,
1041
+ command,
1042
+ cwd: oneValue(parsed, "--cwd") ?? ".",
1043
+ timeoutMs,
1044
+ tags: tags(oneValue(parsed, "--tags"))
1045
+ }
1046
+ };
1047
+ }
1048
+ function editRevision(parsed) {
1049
+ const id = parsed.positional[1];
1050
+ if (id === void 0) return new Error("edit requires a check ID");
1051
+ const changes = {};
1052
+ const description = oneValue(parsed, "--description");
1053
+ if (description !== void 0) changes.description = description;
1054
+ const commandValue = oneValue(parsed, "--command");
1055
+ if (commandValue !== void 0) {
1056
+ const command = parseCommand(commandValue);
1057
+ if (command instanceof Error) return command;
1058
+ changes.command = command;
1059
+ }
1060
+ const cwd = oneValue(parsed, "--cwd");
1061
+ if (cwd !== void 0) changes.cwd = cwd;
1062
+ const timeoutValue = oneValue(parsed, "--timeout-ms");
1063
+ if (timeoutValue !== void 0) {
1064
+ const timeoutMs = parseTimeout(timeoutValue);
1065
+ if (timeoutMs instanceof Error) return timeoutMs;
1066
+ changes.timeoutMs = timeoutMs;
1067
+ }
1068
+ const tagValue = oneValue(parsed, "--tags");
1069
+ if (tagValue !== void 0) changes.tags = tags(tagValue);
1070
+ if (Object.keys(changes).length === 0) return new Error("edit requires at least one changed field");
1071
+ return { kind: "edit", id, changes };
1072
+ }
1073
+ function mutationRevision(parsed) {
1074
+ const command = parsed.positional[0];
1075
+ if (command === "add") return addRevision(parsed);
1076
+ if (command === "edit") return editRevision(parsed);
1077
+ if (command === "rename") {
1078
+ const id = parsed.positional[1];
1079
+ const newId = parsed.positional[2];
1080
+ if (id === void 0 || newId === void 0) return new Error("rename requires <old> and <new> IDs");
1081
+ return { kind: "rename", id, newId };
1082
+ }
1083
+ if (command === "remove") {
1084
+ const id = parsed.positional[1];
1085
+ if (id === void 0) return new Error("remove requires a check ID");
1086
+ return { kind: "remove", id };
1087
+ }
1088
+ return new Error(`unknown verifiers command: ${command ?? "(none)"}`);
1089
+ }
1090
+ function printDryRun(id, result) {
1091
+ if (result.kind === "error") {
1092
+ printError(`dry-run '${id}' failed: ${result.message}`);
1093
+ return 1;
1094
+ }
1095
+ process.stdout.write(`Dry run '${id}':
1096
+ ${result.output}${result.output.endsWith("\n") ? "" : "\n"}`);
1097
+ return 0;
1098
+ }
1099
+ async function executeWorkflow(parsed, options) {
1100
+ let printedPreview = false;
1101
+ const dryRunCheckIds = parsed.values.get("--dry-run") ?? [];
1102
+ const result = await runVerifierAuthoringWorkflow({
1103
+ includeProposals: options.includeProposals,
1104
+ initialRevisions: options.revisions,
1105
+ confirmed: parsed.yes,
1106
+ decide(context) {
1107
+ process.stdout.write(`${context.preview}
1108
+ `);
1109
+ printedPreview = true;
1110
+ if (!parsed.yes || context.draft.checks.length === 0 && options.revisions.length === 0) {
1111
+ return { kind: "reject" };
1112
+ }
1113
+ return { kind: "confirm", dryRunCheckIds };
1114
+ }
1115
+ });
1116
+ if (result.status === "invalid") {
1117
+ if (!printedPreview && result.preview !== void 0) process.stdout.write(`${result.preview}
1118
+ `);
1119
+ printError(result.reason);
1120
+ if (result.wrote && result.path !== void 0) {
1121
+ process.stderr.write(` ${result.path} was written; repair or remove it before running a check.
1122
+ `);
1123
+ }
1124
+ return 1;
1125
+ }
1126
+ if (result.status === "rejected") {
1127
+ if (!parsed.yes) {
1128
+ process.stdout.write("Review complete. Nothing changed; rerun the same command with --yes to write this preview.\n");
1129
+ } else {
1130
+ process.stdout.write(
1131
+ "Nothing changed because the preview contains no catalog checks. Package checks remain active; unsupported commands can be added with `clio-coder verifiers add`.\n"
1132
+ );
1133
+ }
1134
+ return 0;
1135
+ }
1136
+ printOk(`wrote ${result.path}; production parser accepted the catalog`);
1137
+ let code = 0;
1138
+ for (const dryRun of result.dryRuns) code = Math.max(code, printDryRun(dryRun.id, dryRun.result));
1139
+ return code;
1140
+ }
1141
+ async function discoverCommand() {
1142
+ const discovery = discoverVerifierAuthoring();
1143
+ if (!discovery.ok) {
1144
+ printError(discovery.reason);
1145
+ process.stderr.write(`${discovery.manualEntry}
1146
+ `);
1147
+ return 1;
1148
+ }
1149
+ process.stdout.write(`${previewVerifierDraft(createVerifierDraft(discovery))}
1150
+ `);
1151
+ return 0;
1152
+ }
1153
+ function validateCommand() {
1154
+ const loaded = loadProjectVerifierCatalog(process.cwd());
1155
+ if (!loaded.ok) {
1156
+ printError(`production catalog parser rejected ${loaded.reason}`);
1157
+ return 1;
1158
+ }
1159
+ if (loaded.source === null) {
1160
+ process.stdout.write(`No ${PROJECT_VERIFIER_CATALOG_RELATIVE_PATH} exists. Run \`clio-coder verifiers author\`.
1161
+ `);
1162
+ return 0;
1163
+ }
1164
+ printOk(
1165
+ `production catalog parser accepted ${PROJECT_VERIFIER_CATALOG_RELATIVE_PATH} (${loaded.source.checks.length} check${loaded.source.checks.length === 1 ? "" : "s"})`
1166
+ );
1167
+ return 0;
1168
+ }
1169
+ async function runVerifiersCommand(argv) {
1170
+ const parsed = parseAuthoringArgs(argv);
1171
+ if (parsed.error !== void 0) {
1172
+ printError(parsed.error);
1173
+ process.stderr.write(HELP);
1174
+ return 2;
1175
+ }
1176
+ if (parsed.help || parsed.positional.length === 0) {
1177
+ process.stdout.write(HELP);
1178
+ return 0;
1179
+ }
1180
+ const command = parsed.positional[0];
1181
+ if (command === "discover") return discoverCommand();
1182
+ if (command === "validate") return validateCommand();
1183
+ if (command === "dry-run") {
1184
+ const id = parsed.positional[1];
1185
+ if (id === void 0) {
1186
+ printError("dry-run requires a check ID");
1187
+ return 2;
1188
+ }
1189
+ return printDryRun(id, await verifyTool.run({ check: id }));
1190
+ }
1191
+ if (command === "author") {
1192
+ const revisions = authorRevisions(parsed);
1193
+ if (revisions instanceof Error) {
1194
+ printError(revisions.message);
1195
+ return 2;
1196
+ }
1197
+ return executeWorkflow(parsed, { includeProposals: true, revisions });
1198
+ }
1199
+ if (["add", "edit", "rename", "remove"].includes(command ?? "")) {
1200
+ const revision = mutationRevision(parsed);
1201
+ if (revision instanceof Error) {
1202
+ printError(revision.message);
1203
+ return 2;
1204
+ }
1205
+ return executeWorkflow(parsed, { includeProposals: false, revisions: [revision] });
1206
+ }
1207
+ printError(`unknown verifiers command: ${command}`);
1208
+ process.stderr.write(HELP);
1209
+ return 2;
1210
+ }
1211
+ export {
1212
+ runVerifiersCommand
1213
+ };
1214
+ //# sourceMappingURL=verifiers-4UUM6TEE.js.map