vigiles 28.0.0 → 29.0.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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter-registry.d.ts +39 -0
  3. package/dist/adapter-registry.js +45 -0
  4. package/dist/adapter.d.ts +8 -0
  5. package/dist/adapter.js +10 -1
  6. package/dist/adapters/claude-code/adapter.js +6 -0
  7. package/dist/adapters/claude-code/layout.d.ts +5 -0
  8. package/dist/adapters/claude-code/plugin-loader.d.ts +10 -1
  9. package/dist/adapters/claude-code/plugin-loader.js +10 -1
  10. package/dist/adapters/codex/adapter.js +6 -0
  11. package/dist/adapters/codex/layout.d.ts +51 -5
  12. package/dist/adapters/codex/layout.js +13 -4
  13. package/dist/adapters/opencode/adapter.js +6 -0
  14. package/dist/audit-report.template.html +1 -1
  15. package/dist/audit-score.d.ts +7 -0
  16. package/dist/audit-score.js +49 -2
  17. package/dist/cli-main.js +82 -20
  18. package/dist/core/adapter.d.ts +23 -0
  19. package/dist/core/compile.js +11 -1
  20. package/dist/core/config-schema.d.ts +244 -0
  21. package/dist/core/config-schema.js +452 -0
  22. package/dist/core/refs.js +10 -1
  23. package/dist/core/surface-discovery.d.ts +270 -0
  24. package/dist/core/surface-discovery.js +425 -0
  25. package/dist/core/surface-scopes.d.ts +38 -1
  26. package/dist/core/surface-scopes.js +73 -1
  27. package/dist/core/symbols.d.ts +24 -2
  28. package/dist/core/symbols.js +66 -18
  29. package/dist/core/types.d.ts +36 -107
  30. package/dist/core/validate.d.ts +36 -22
  31. package/dist/core/validate.js +88 -176
  32. package/dist/exclude.d.ts +20 -0
  33. package/dist/exclude.js +11 -1
  34. package/dist/layout-registry.d.ts +14 -0
  35. package/dist/layout-registry.js +40 -0
  36. package/dist/plugin-loader.d.ts +49 -1
  37. package/dist/plugin-loader.js +120 -14
  38. package/dist/scan-core.d.ts +19 -0
  39. package/dist/scan-core.js +30 -0
  40. package/dist/scan-files.js +15 -5
  41. package/dist/scan.d.ts +63 -0
  42. package/dist/scan.js +68 -12
  43. package/dist/score-core.js +8 -0
  44. package/dist/setup-plan.d.ts +2 -1
  45. package/dist/setup-plan.js +7 -2
  46. package/dist/surface-discovery-fs.d.ts +12 -0
  47. package/dist/surface-discovery-fs.js +108 -0
  48. package/dist/vigilesrc.schema.json +1689 -0
  49. package/package.json +10 -6
package/dist/cli-main.js CHANGED
@@ -34,6 +34,7 @@ const setup_plan_js_1 = require("./setup-plan.js");
34
34
  const types_js_1 = require("./core/types.js");
35
35
  const test_coverage_js_1 = require("./test-coverage.js");
36
36
  const scan_js_1 = require("./scan.js");
37
+ const surface_discovery_js_1 = require("./core/surface-discovery.js");
37
38
  const scan_trigger_suggest_js_1 = require("./scan-trigger-suggest.js");
38
39
  const dialect_drift_js_1 = require("./dialect-drift.js");
39
40
  const skill_reachability_js_1 = require("./skill-reachability.js");
@@ -553,7 +554,7 @@ async function compile(specPaths, config, excludes, opts = {}) {
553
554
  // dialect pick and the mirror from it — no re-parsing, no cwd-sniffing in the
554
555
  // helpers. A loud notice (never a silent guess) on a multi-harness or
555
556
  // ambiguous-detection pick.
556
- const declaredHarnesses = (0, adapter_registry_js_1.normalizeHarnessList)(config.harness);
557
+ const declaredHarnesses = (0, adapter_registry_js_1.declaredHarnessNames)(config.harnesses);
557
558
  const selection = (0, adapter_registry_js_1.resolveHarnessSelection)({
558
559
  root: process.cwd(),
559
560
  flag: opts.harnessFlag,
@@ -1466,7 +1467,7 @@ async function runLint(restArgs, flags, excludes, config) {
1466
1467
  const lintSelection = (0, adapter_registry_js_1.resolveHarnessSelection)({
1467
1468
  root: scanRoot,
1468
1469
  flag: harnessFlag,
1469
- configHarness: (0, adapter_registry_js_1.normalizeHarnessList)(config?.harness),
1470
+ configHarness: (0, adapter_registry_js_1.declaredHarnessNames)(config?.harnesses),
1470
1471
  });
1471
1472
  const adapter = lintSelection.adapter;
1472
1473
  // šŸ”“ WHICH ROOTS GET SCORED, and saying so either way (#185).
@@ -3363,7 +3364,7 @@ async function setup(args) {
3363
3364
  // Detect project. An existing `.vigilesrc.json` `harness` (from a prior init /
3364
3365
  // a hand-authored config) wins over auto-detection (dogfood I3).
3365
3366
  const detected = detectProject();
3366
- const harnesses = resolveHarnesses(parsed, detected, (0, validate_js_1.loadConfig)().harness);
3367
+ const harnesses = resolveHarnesses(parsed, detected, (0, adapter_registry_js_1.declaredHarnessNames)((0, validate_js_1.loadConfig)().harnesses));
3367
3368
  printDetection(detected, harnesses);
3368
3369
  // Files actually written, accumulated for an honest commit hint.
3369
3370
  const written = [];
@@ -3436,15 +3437,15 @@ async function setup(args) {
3436
3437
  console.log("\nℹ Ran the standard setup. Already have a harness, or not a JS/Python repo, and want only the CI integrity gate (nothing installed)? Re-run `npx vigiles init --ci-only`.");
3437
3438
  }
3438
3439
  }
3439
- /** Canonical, de-duplicated harness list → a config value (string when one). */
3440
- function harnessConfigValue(harnesses) {
3441
- const canon = [...new Set(harnesses.map(adapter_registry_js_1.normalizeHarnessName))];
3442
- return canon.length === 1 ? canon[0] : canon;
3440
+ /** Canonical, de-duplicated harness names — the keys `harnesses` gets. */
3441
+ function harnessConfigKeys(harnesses) {
3442
+ return [...new Set(harnesses.map(adapter_registry_js_1.normalizeHarnessName))];
3443
3443
  }
3444
3444
  /**
3445
3445
  * Merge the resolved harness(es) (and strict rule severities) into
3446
- * `.vigilesrc.json` without clobbering existing keys — an existing `harness`
3447
- * stays, a missing one is added, a malformed file is left untouched.
3446
+ * `.vigilesrc.json` without clobbering existing keys — an existing
3447
+ * `harnesses` block stays, a missing one is added, a malformed file is left
3448
+ * untouched.
3448
3449
  */
3449
3450
  function writeProjectConfig(opts) {
3450
3451
  const configPath = (0, node_path_1.resolve)(process.cwd(), ".vigilesrc.json");
@@ -3459,7 +3460,7 @@ function writeProjectConfig(opts) {
3459
3460
  }
3460
3461
  }
3461
3462
  const merged = (0, setup_plan_js_1.mergeProjectConfig)(existing, {
3462
- harness: harnessConfigValue(opts.harnesses),
3463
+ harnesses: harnessConfigKeys(opts.harnesses),
3463
3464
  strict: opts.strict,
3464
3465
  reportOnly: opts.reportOnly,
3465
3466
  lint: opts.lint,
@@ -3524,7 +3525,7 @@ function harnessLayoutFor(root, config, flag) {
3524
3525
  return (0, adapter_registry_js_1.resolveHarnessSelection)({
3525
3526
  root,
3526
3527
  flag,
3527
- configHarness: (0, adapter_registry_js_1.normalizeHarnessList)(config?.harness),
3528
+ configHarness: (0, adapter_registry_js_1.declaredHarnessNames)(config?.harnesses),
3528
3529
  }).adapter.layout;
3529
3530
  }
3530
3531
  catch {
@@ -4391,7 +4392,7 @@ function flagValue(args, name) {
4391
4392
  * Resolve the adapter for a COMMAND, honouring the full precedence: `--harness=`
4392
4393
  * flag → `.vigilesrc.json` `harness` → auto-detect (dogfood A/I3). This is the
4393
4394
  * ONE resolution path a command may use — resolving via the raw auto-detect
4394
- * alone silently ignores config.harness, which is the exact bug this closes.
4395
+ * alone silently ignores `.vigilesrc.json#harnesses`, which is the exact bug this closes.
4395
4396
  * A dogfood test (src/cli-harness-resolution.test.ts) asserts cli.ts routes all
4396
4397
  * command harness resolution through here, so a future command can't regress.
4397
4398
  */
@@ -4399,7 +4400,7 @@ function resolveCommandHarness(dir, harnessFlag) {
4399
4400
  return (0, adapter_registry_js_1.resolveHarnessSelection)({
4400
4401
  root: dir,
4401
4402
  flag: harnessFlag,
4402
- configHarness: (0, adapter_registry_js_1.normalizeHarnessList)((0, validate_js_1.loadConfig)().harness),
4403
+ configHarness: (0, adapter_registry_js_1.declaredHarnessNames)((0, validate_js_1.loadConfig)().harnesses),
4403
4404
  });
4404
4405
  }
4405
4406
  async function handleMeasure(restArgs, args) {
@@ -5690,7 +5691,11 @@ function evalLockNudgeHookCommand() {
5690
5691
  // second gate saying the same thing is a branch no test can distinguish from
5691
5692
  // its absence (measured — the mutation passed), i.e. the dead-fragment class
5692
5693
  // this same change removed from the runner table.
5693
- const config = (0, validate_js_1.loadConfig)(cwd);
5694
+ // `onInvalid: "warn"` — a HOOK RAIL. This is a fresh process inside somebody's
5695
+ // editing session, and a malformed `.vigilesrc.json` must not turn a JSON typo
5696
+ // into a failed edit: the nudge not firing is the cheaper failure. The verbs
5697
+ // throw on the same config; what is CHECKED is identical.
5698
+ const config = (0, validate_js_1.loadConfig)(cwd, { onInvalid: "warn" });
5694
5699
  const { options } = untestedRules(config);
5695
5700
  // šŸ”“ THE SAME LAYOUT `vigiles lint` RESOLVES, for the same reason as the config
5696
5701
  // above. This used to pass `basePath` alone, so the detector fell back to the
@@ -5756,7 +5761,8 @@ function refsHookCommand() {
5756
5761
  // Root first: the config read below is anchored on it, and reading the config
5757
5762
  // from the process's directory is how a disabled rule comes back to life.
5758
5763
  const cwd = runtimeRoot(eventRoot(raw));
5759
- const severity = (0, types_js_1.ruleSeverity)((0, validate_js_1.loadConfig)(cwd).rules["unmarked-refs"]);
5764
+ // A hook rail — see `evalLockNudgeHookCommand` for why it warns, not throws.
5765
+ const severity = (0, types_js_1.ruleSeverity)((0, validate_js_1.loadConfig)(cwd, { onInvalid: "warn" }).rules["unmarked-refs"]);
5760
5766
  if (severity === false)
5761
5767
  return;
5762
5768
  const target = (0, node_path_1.relative)(cwd, (0, node_path_1.resolve)(cwd, file)) || file;
@@ -5930,7 +5936,7 @@ async function installHookFile(file, adapter, registeredProviders = []) {
5930
5936
  * harness-neutral, so when a repo targets both harnesses the SAME hook is merged
5931
5937
  * into `.claude/settings.json` AND `.codex/config.toml` (each in its native
5932
5938
  * format, with per-harness warnings) — never just the first. The harness set is
5933
- * resolved from the `--harness=` flag, else `config.harness`, else auto-detect.
5939
+ * resolved from the `--harness=` flag, else `.vigilesrc.json#harnesses`, else auto-detect.
5934
5940
  * Returns false if any hook failed to compile for any harness.
5935
5941
  */
5936
5942
  async function installHooks(hookFiles, harnessFlag, configHarness) {
@@ -6450,7 +6456,8 @@ async function main() {
6450
6456
  if (specs.length > 0)
6451
6457
  valid =
6452
6458
  (await compile(specs, config, excludes, { harnessFlag })) && valid;
6453
- valid = (await installHooks(hooks, harnessFlag, config.harness)) && valid;
6459
+ valid =
6460
+ (await installHooks(hooks, harnessFlag, (0, adapter_registry_js_1.declaredHarnessNames)(config.harnesses))) && valid;
6454
6461
  // Keep an existing whole-harness registry in sync (cheap, opt-in) so the
6455
6462
  // user never hand-runs `generate-harness`. Skipped when no harness.gen.ts.
6456
6463
  if (specs.length > 0)
@@ -6578,19 +6585,74 @@ async function main() {
6578
6585
  const harnessFlag = harnessFlagFrom(args);
6579
6586
  // Honor the SAME precedence as lint/compile (dogfood A): --harness= flag,
6580
6587
  // else the `.vigilesrc.json` `harness` key, else auto-detect. Previously
6581
- // audit auto-detected and IGNORED config.harness, so a repo that
6582
- // config-declares `"harness": "codex"` but carries a CLAUDE.md was still
6588
+ // audit auto-detected and IGNORED the declared harnesses, so a repo
6589
+ // that config-declares `"harnesses": {"codex": {}}` but carries a CLAUDE.md was still
6583
6590
  // scanned as Claude Code. `resolveHarnessSelection` also carries the
6584
6591
  // ambiguity/multi-target `notice` so the warning stays consistent.
6585
6592
  const selection = (0, adapter_registry_js_1.resolveHarnessSelection)({
6586
6593
  root,
6587
6594
  flag: harnessFlag,
6588
- configHarness: (0, adapter_registry_js_1.normalizeHarnessList)(config.harness),
6595
+ configHarness: (0, adapter_registry_js_1.declaredHarnessNames)(config.harnesses),
6589
6596
  });
6590
6597
  const adapter = selection.adapter;
6598
+ // EVERY declared harness, each with the roots declared under it — the
6599
+ // list the scan reads WHOLE. The flag still wins (an explicit override
6600
+ // is singular, and the user typed it), and a repo with no declaration
6601
+ // scans under the one detected adapter exactly as before.
6602
+ //
6603
+ // The PRIMARY is `adapter`, so the report is still labelled and
6604
+ // dialect-checked by one harness; the list is what stops the OTHER
6605
+ // declared harness's skills and instruction file from being invisible.
6606
+ const scanHarnesses = harnessFlag === undefined || harnessFlag === ""
6607
+ ? (0, adapter_registry_js_1.resolveDeclaredHarnesses)(root, config.harnesses)
6608
+ .map((d) => ({
6609
+ layout: d.adapter.layout,
6610
+ dialect: d.adapter.dialect,
6611
+ roots: d.roots,
6612
+ }))
6613
+ // The primary first, whatever order the object was written in:
6614
+ // `resolveHarnessSelection` already decided which harness this
6615
+ // report is FOR, and the scan's first entry is the one that
6616
+ // supplies the dialect. Two different answers to "which is
6617
+ // primary" is the bug this change exists to remove.
6618
+ .sort((a, b) => a.layout.name === adapter.layout.name
6619
+ ? -1
6620
+ : b.layout.name === adapter.layout.name
6621
+ ? 1
6622
+ : 0)
6623
+ : [];
6624
+ // A declared root under a harness that reads no surface there is
6625
+ // REFUSED, not ignored. It is the one silent state the nested shape
6626
+ // would otherwise keep: the line changes nothing, and saying nothing is
6627
+ // the tool agreeing with a belief that is false.
6628
+ const badRoots = (0, surface_discovery_js_1.unresolvedDeclaredRoots)(scanHarnesses.map((h) => ({
6629
+ harness: h.layout.name,
6630
+ layout: h.layout,
6631
+ roots: h.roots,
6632
+ })), (rel) => {
6633
+ const abs = (0, node_path_1.resolve)(root, rel);
6634
+ return ((0, node_fs_1.lstatSync)(abs, { throwIfNoEntry: false })?.isDirectory() === true);
6635
+ });
6636
+ if (badRoots.length > 0) {
6637
+ for (const msg of badRoots)
6638
+ console.error(`āœ— ${msg}`);
6639
+ process.exitCode = 2;
6640
+ return;
6641
+ }
6591
6642
  const report = (0, scan_js_1.scanPlugin)(targets[0], adapter.layout, adapter.dialect, {
6592
6643
  sharedDirs: config.sharedDirs,
6593
6644
  sharedDirsRoot: sharedDirsRootFor(targets[0]),
6645
+ // `.vigilesrc.json#exclude` reaches surface DISCOVERY, not just the
6646
+ // instruction file. Measured 2026-09-21 before this line existed: a repo
6647
+ // with `{"exclude": [".claude"]}` and one skill at `.claude/skills/demo`
6648
+ // still printed `Skills (1): āœ“ demo` and docked Safety to 90 for it — the
6649
+ // grade was computed over a tree the user had told the tool to ignore.
6650
+ excludes,
6651
+ // The repo owner's answer to "N skills no harness reads": these are
6652
+ // mine, grade them — each root under the harness whose layout reads
6653
+ // it, so no array order decides which half of the repo is seen.
6654
+ // `exclude` still wins over it; the walk drops an excluded path first.
6655
+ harnesses: scanHarnesses,
6594
6656
  });
6595
6657
  if (!json) {
6596
6658
  console.log(`Detected harness: ${adapter.name}`);
@@ -115,5 +115,28 @@ export interface HarnessAdapter {
115
115
  * `AGENTS.md` that many harnesses share) regardless of registration order.
116
116
  */
117
117
  detect(root: string): number;
118
+ /**
119
+ * Is this repo-relative path one THIS harness reads — "is it mine?"
120
+ *
121
+ * šŸ”“ THE POINT OF THIS METHOD IS WHAT IT CANNOT DO. It takes a path and
122
+ * returns a boolean: no root, no filesystem, no enumeration. An adapter can
123
+ * therefore LABEL a surface the domain already found and nothing else —
124
+ * **registering a new adapter cannot make vigiles read more in anyone's
125
+ * repository.** The rejected alternative was each adapter DECLARING roots for
126
+ * the audit to walk, which inverts that: shipping a Cursor adapter would start
127
+ * reading `.cursor/rules` in every user's repo, and a surface no adapter
128
+ * declared would stay invisible. Discovery is the domain's job
129
+ * (`core/surface-discovery.ts`); a claim is an adapter's. See
130
+ * `research/audit-harness-dx.md` §9.
131
+ *
132
+ * The consequence the audit reports: a surface NO registered adapter claims is
133
+ * a FINDING, not silence — measured on a real repo whose 37 skills under
134
+ * `.ai/` graded A (100/100) precisely because nothing read them (#240).
135
+ *
136
+ * Every shipped adapter implements this as `layoutClaims(<its layout>, path)`,
137
+ * so a layout that moves takes its claim with it and the two cannot drift.
138
+ * Override it only for a location the `PluginLayout` fields cannot express.
139
+ */
140
+ claims(path: string): boolean;
118
141
  }
119
142
  //# sourceMappingURL=adapter.d.ts.map
@@ -172,13 +172,23 @@ function validateSymbolRef(file, name, basePath) {
172
172
  path: file,
173
173
  };
174
174
  }
175
- if ((0, symbols_js_1.langForFile)(file) === null) {
175
+ const support = (0, symbols_js_1.langForFile)(file);
176
+ if (support.kind === "unsupported") {
176
177
  return {
177
178
  type: "stale-ref",
178
179
  message: `Unsupported language for symbol check: "${file}"`,
179
180
  path: file,
180
181
  };
181
182
  }
183
+ if (support.kind === "grammar-missing") {
184
+ // The language is parseable by this tool; the optional grammar is absent in THIS install.
185
+ // Distinct wording on purpose — see the union's docblock in core/symbols.ts.
186
+ return {
187
+ type: "stale-ref",
188
+ message: `Symbol not checked: the ${support.id} grammar is not installed (npm i -D ${support.pkg})`,
189
+ path: file,
190
+ };
191
+ }
182
192
  if (!(0, symbols_js_1.fileDefinesSymbol)(full, name)) {
183
193
  return {
184
194
  type: "stale-ref",
@@ -0,0 +1,244 @@
1
+ /**
2
+ * `.vigilesrc.json`, AS A SCHEMA — the one place the config's shape, its
3
+ * defaults and its error messages live.
4
+ *
5
+ * šŸ”“ WHY A SCHEMA AND NOT THE HAND-WRITTEN CHECKS IT REPLACED. `loadConfig` used
6
+ * to coerce the keys it happened to remember (`asStringArray` on three of them),
7
+ * spread everything else through untouched, and say nothing at all about a key
8
+ * it had never heard of. MEASURED on this repo's own CLI before the change:
9
+ *
10
+ * ```
11
+ * $ echo '{"surfaceRootz":[".ai"]}' > .vigilesrc.json && vigiles audit .
12
+ * (no complaint about the unknown key — exit 0)
13
+ * ```
14
+ *
15
+ * A key the tool does not read is a line the user believes is working. That is
16
+ * the product's own subject — a passing signal standing in for work nobody did —
17
+ * happening inside the tool, so the shape is now DECLARED and anything outside
18
+ * it is named out loud.
19
+ *
20
+ * THE TYPE IS DERIVED FROM THIS, not written beside it: `VigilesConfig` is
21
+ * `z.infer<typeof vigilesConfigSchema>` (see `./types.ts`), so a field cannot
22
+ * exist in the type and not in the validator, which is how `surfaceRoots` ended
23
+ * up documented in `docs/cli.md` for a week after it stopped being read.
24
+ *
25
+ * DEFAULTS LIVE HERE TOO, and that is what makes the derivation exact. Every key
26
+ * the loaded config is guaranteed to carry (`rules`, `files`, `ruleMarkers`)
27
+ * carries a Zod `.default(...)`, and Zod's inferred OUTPUT type for a defaulted
28
+ * field is non-optional — so `z.infer` reproduces the old
29
+ * `rules: Required<RulesConfig>` exactly, rather than approximating it. Parsing
30
+ * `{}` yields byte-for-byte the old `DEFAULT_CONFIG`.
31
+ *
32
+ * āš ļø ZOD COSTS ~45 ms TO IMPORT (measured, Zod 4.6.5), AND IT IS IMPORTED
33
+ * NORMALLY — `src/core/validate.ts` has a top-level `import`, not a deferred
34
+ * `require`. The deferral was tried and is recorded there rather than here,
35
+ * because the reason it was dropped is a property of the two worlds this code
36
+ * runs in, not of this file. What matters here: the genuinely hot rail — a
37
+ * compiled hook's decision, `vigiles hook-runtime run-program`, one fresh
38
+ * process per matching tool call — never loads the verb barrel and therefore
39
+ * never loads this module (`src/cli.ts` branches first;
40
+ * `src/hook-runtime-graph.test.ts` fails the day that stops being true). The
41
+ * rails that DO load the barrel already pay ~316 ms of Node startup and ~85
42
+ * requires, against which 45 ms is ~13%.
43
+ */
44
+ import { z } from "zod";
45
+ /** The rule names, for the "did you mean" on an unknown one. */
46
+ export declare const RULE_NAMES: readonly string[];
47
+ /**
48
+ * ONE harness's entry in {@link vigilesConfigSchema}'s `harnesses`.
49
+ *
50
+ * `.strict()` is load-bearing here specifically: the whole reason this key
51
+ * exists is that a declaration which reaches nothing used to be silent, and
52
+ * `{"claude-code": {"root": ".ai"}}` (singular, no `s`) reaches nothing.
53
+ */
54
+ declare const harnessDeclarationSchema: z.ZodObject<{
55
+ roots: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
56
+ }, z.core.$strict>;
57
+ /** The harness keys' value shape, exported so `types.ts` can derive the type. */
58
+ export type HarnessDeclarationShape = z.infer<typeof harnessDeclarationSchema>;
59
+ /**
60
+ * The whole of `.vigilesrc.json`.
61
+ *
62
+ * `.strict()` at the top level is the check that did not exist: an unrecognized
63
+ * key is now a named error with a suggestion, where it used to be spread into
64
+ * the config object and never read.
65
+ */
66
+ export declare const vigilesConfigSchema: z.ZodObject<{
67
+ ruleMarkers: z.ZodDefault<z.ZodArray<z.ZodEnum<{
68
+ headings: "headings";
69
+ checkboxes: "checkboxes";
70
+ }>>>;
71
+ rules: z.ZodPrefault<z.ZodObject<{
72
+ "spec-refs": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
73
+ "orphan-docs": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
74
+ "duplicate-rules": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
75
+ "require-instructions-spec": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
76
+ "require-skill-spec": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
77
+ integrity: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
78
+ coverage: z.ZodDefault<z.ZodUnion<readonly [z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>, z.ZodTuple<[z.ZodLiteral<"warn">, z.ZodObject<{
79
+ linterRules: z.ZodOptional<z.ZodNumber>;
80
+ scripts: z.ZodOptional<z.ZodNumber>;
81
+ }, z.core.$strict>], null>, z.ZodTuple<[z.ZodLiteral<"error">, z.ZodObject<{
82
+ linterRules: z.ZodOptional<z.ZodNumber>;
83
+ scripts: z.ZodOptional<z.ZodNumber>;
84
+ }, z.core.$strict>], null>]>>;
85
+ "untested-skill": z.ZodDefault<z.ZodUnion<readonly [z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>, z.ZodTuple<[z.ZodLiteral<"warn">, z.ZodObject<{
86
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
87
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
88
+ testExtension: z.ZodOptional<z.ZodString>;
89
+ }, z.core.$strict>], null>, z.ZodTuple<[z.ZodLiteral<"error">, z.ZodObject<{
90
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
91
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
92
+ testExtension: z.ZodOptional<z.ZodString>;
93
+ }, z.core.$strict>], null>]>>;
94
+ "untested-subagent": z.ZodDefault<z.ZodUnion<readonly [z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>, z.ZodTuple<[z.ZodLiteral<"warn">, z.ZodObject<{
95
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
96
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
97
+ testExtension: z.ZodOptional<z.ZodString>;
98
+ }, z.core.$strict>], null>, z.ZodTuple<[z.ZodLiteral<"error">, z.ZodObject<{
99
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
100
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
101
+ testExtension: z.ZodOptional<z.ZodString>;
102
+ }, z.core.$strict>], null>]>>;
103
+ "untested-hook": z.ZodDefault<z.ZodUnion<readonly [z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>, z.ZodTuple<[z.ZodLiteral<"warn">, z.ZodObject<{
104
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
105
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
106
+ testExtension: z.ZodOptional<z.ZodString>;
107
+ }, z.core.$strict>], null>, z.ZodTuple<[z.ZodLiteral<"error">, z.ZodObject<{
108
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
109
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
110
+ testExtension: z.ZodOptional<z.ZodString>;
111
+ }, z.core.$strict>], null>]>>;
112
+ "unmarked-refs": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
113
+ "subagent-tool-contract": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
114
+ "hook-events": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
115
+ "subagent-frontmatter": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
116
+ "mcp-config": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
117
+ "skill-frontmatter": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
118
+ "mcp-tool-resolves": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
119
+ "hook-script-exists": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
120
+ "prefer-compiled-hooks": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
121
+ "disallowed-tools-contract": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
122
+ "description-overlap": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
123
+ "skill-description-budget": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
124
+ "frontmatter-valid": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
125
+ "mcp-hook-target-resolves": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
126
+ "lethal-trifecta": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
127
+ "skill-resource-resolves": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
128
+ "skill-missing-fence": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
129
+ "plugin-dir-layout": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
130
+ "delegation-trifecta": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
131
+ "hook-block-ineffective": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
132
+ "hook-matcher": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
133
+ "doc-refs": z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodLiteral<"warn">, z.ZodLiteral<"error">, z.ZodLiteral<false>, z.ZodLiteral<"off">, z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<true>]>, z.ZodTransform<false | "warn" | "error", boolean | 0 | 1 | 2 | "off" | "warn" | "error">>>;
134
+ }, z.core.$strict>>;
135
+ files: z.ZodDefault<z.ZodArray<z.ZodString>>;
136
+ maxRules: z.ZodOptional<z.ZodNumber>;
137
+ maxTokens: z.ZodOptional<z.ZodNumber>;
138
+ maxSectionLines: z.ZodOptional<z.ZodNumber>;
139
+ catalogOnly: z.ZodOptional<z.ZodBoolean>;
140
+ linters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
141
+ rulesDir: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
142
+ }, z.core.$strict>>>;
143
+ bundles: z.ZodOptional<z.ZodEnum<{
144
+ root: "root";
145
+ all: "all";
146
+ }>>;
147
+ orphans: z.ZodOptional<z.ZodObject<{
148
+ include: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
149
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
150
+ }, z.core.$strict>>;
151
+ exclude: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
152
+ sharedDirs: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
153
+ harnesses: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
154
+ roots: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<readonly string[], string | string[]>>>;
155
+ }, z.core.$strict>>>;
156
+ audit: z.ZodOptional<z.ZodObject<{
157
+ measure: z.ZodOptional<z.ZodBoolean>;
158
+ }, z.core.$strict>>;
159
+ eval: z.ZodOptional<z.ZodObject<{
160
+ apiVersion: z.ZodOptional<z.ZodNumber>;
161
+ }, z.core.$strict>>;
162
+ nudge: z.ZodOptional<z.ZodLiteral<"dismissed">>;
163
+ $schema: z.ZodOptional<z.ZodString>;
164
+ }, z.core.$strict>;
165
+ /**
166
+ * A `.vigilesrc.json` that cannot be honoured as written.
167
+ *
168
+ * šŸ”“ IT HAS ITS OWN CLASS BECAUSE THE READER CATCHES EVERYTHING ELSE. A missing
169
+ * file, an unreadable one and malformed JSON all mean "use the defaults", which
170
+ * is right — and a file that IS readable and says something we refuse must not
171
+ * join them, or the user's declaration vanishes into the defaults and the run
172
+ * looks clean. A distinct class is what lets the CLI print it as a config error
173
+ * and a hook rail downgrade it to a warning, from one throw site.
174
+ */
175
+ export declare class VigilesConfigError extends Error {
176
+ readonly name = "VigilesConfigError";
177
+ }
178
+ /**
179
+ * The whole config, AS THE SCHEMA DEFINES IT — `VigilesConfig` is this.
180
+ *
181
+ * Exported from here and re-exported (type-only, so no runtime cycle) by
182
+ * `./types.ts`, which every consumer already imports. The derivation is the
183
+ * point: a key cannot be in the type and absent from the validator.
184
+ */
185
+ export type VigilesConfigShape = z.infer<typeof vigilesConfigSchema>;
186
+ /**
187
+ * The two keys `harnesses` replaced, and the sentence each one gets (#240).
188
+ *
189
+ * They are listed here rather than left to `.strict()`'s "Unrecognized key"
190
+ * because the reader of that message is someone whose config USED to work: they
191
+ * need the new spelling, not the news that the old one is unknown. `.strict()`
192
+ * would tell them the truth in the least useful possible way.
193
+ */
194
+ export declare const REPLACED_KEYS: ReadonlyArray<{
195
+ readonly key: string;
196
+ readonly was: string;
197
+ readonly now: string;
198
+ }>;
199
+ /** The message a config written in the replaced shape gets. */
200
+ export declare function replacedKeyMessage(present: ReadonlyArray<(typeof REPLACED_KEYS)[number]>): string;
201
+ /**
202
+ * Turn a Zod failure into the lines a human acts on — ONE per real problem.
203
+ *
204
+ * šŸ”“ THE FORMATTER IS THE POINT, because the library's own message is worse than
205
+ * what it replaced on the two things that matter. Measured on Zod 4.6.5 against
206
+ * this schema:
207
+ *
208
+ * ```
209
+ * {"rules":{"spec-refs":"errr"}}
210
+ * -> invalid_union, EIGHT branch errors: expected "warn" / "error" / false /
211
+ * "off" / 0 / 1 / 2 / true — one line per union member, none of them the
212
+ * sentence "these are the values this key takes"
213
+ * {"harnessez":{}}
214
+ * -> Unrecognized key: "harnessez" (names the culprit, suggests nothing)
215
+ * ```
216
+ *
217
+ * The first is CASCADE NOISE: a union failure is one problem, not eight, and
218
+ * printing the branches makes the schema's internals the user's problem. The
219
+ * second is the regression we refuse to ship — the line it would replace is
220
+ * `āœ— Unknown harness "claud-code". Known: claude-code, codex.`, which names the
221
+ * candidates AND the near-miss. So a union collapses to one line listing what
222
+ * the key accepts, and an unknown key carries the candidate list plus a
223
+ * distance-bounded "did you mean".
224
+ */
225
+ export declare function formatConfigIssues(issues: readonly ConfigIssue[]): string[];
226
+ /**
227
+ * The shape of a Zod issue this formatter reads — structural, not imported.
228
+ *
229
+ * Zod's own `$ZodIssue` union is exhaustive over every code the library can
230
+ * emit, and switching on it would make adding a schema construct a compile
231
+ * error in a message formatter that has a perfectly good default branch. The
232
+ * fields below are the ones read; everything else falls through to `message`.
233
+ */
234
+ export interface ConfigIssue {
235
+ readonly code?: string;
236
+ readonly path?: readonly PropertyKey[];
237
+ readonly message?: string;
238
+ readonly keys?: readonly string[];
239
+ readonly expected?: string;
240
+ readonly values?: readonly unknown[];
241
+ readonly errors?: ReadonlyArray<readonly ConfigIssue[]>;
242
+ }
243
+ export {};
244
+ //# sourceMappingURL=config-schema.d.ts.map