vigiles 38.2.0 → 39.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 (102) hide show
  1. package/dist/adapters/claude-code/event-capability.js +24 -8
  2. package/dist/adapters/claude-code/hook-protocol.js +2 -1
  3. package/dist/adapters/codex/hook-protocol.js +2 -1
  4. package/dist/cli-flag-check.d.ts +36 -0
  5. package/dist/cli-flag-check.js +72 -1
  6. package/dist/cli-main.d.ts +2 -2
  7. package/dist/cli-main.js +548 -379
  8. package/dist/core/bash-effects.d.ts +0 -57
  9. package/dist/core/bash-effects.js +0 -147
  10. package/dist/core/compile-generator.d.ts +6 -6
  11. package/dist/core/compile-generator.js +4 -4
  12. package/dist/core/compile.d.ts +72 -8
  13. package/dist/core/compile.js +276 -133
  14. package/dist/core/config-schema.d.ts +40 -10
  15. package/dist/core/config-schema.js +139 -16
  16. package/dist/core/coverage.d.ts +16 -0
  17. package/dist/core/coverage.js +22 -0
  18. package/dist/core/doc-refs.d.ts +3 -2
  19. package/dist/core/doc-refs.js +2 -2
  20. package/dist/core/enforce-marker.d.ts +28 -0
  21. package/dist/core/enforce-marker.js +34 -0
  22. package/dist/core/eslint-inventory.d.ts +96 -0
  23. package/dist/core/eslint-inventory.js +251 -0
  24. package/dist/core/event-capability.d.ts +5 -1
  25. package/dist/core/frame.d.ts +43 -2
  26. package/dist/core/frame.js +85 -2
  27. package/dist/core/generate-schema.d.ts +3 -2
  28. package/dist/core/generate-schema.js +2 -2
  29. package/dist/core/generate-types.d.ts +11 -2
  30. package/dist/core/generate-types.js +12 -5
  31. package/dist/core/hook-command.d.ts +172 -0
  32. package/dist/core/hook-command.js +277 -0
  33. package/dist/core/hook-delivery.d.ts +133 -0
  34. package/dist/core/hook-delivery.js +150 -0
  35. package/dist/core/hook-paths.d.ts +14 -0
  36. package/dist/core/hook-paths.js +22 -0
  37. package/dist/core/hook-program.d.ts +4 -4
  38. package/dist/core/hook-program.js +13 -25
  39. package/dist/core/hook-state.d.ts +1 -1
  40. package/dist/core/hook-state.js +1 -1
  41. package/dist/core/instruction-remedies.d.ts +35 -0
  42. package/dist/core/instruction-remedies.js +70 -1
  43. package/dist/core/integrity-header.d.ts +54 -0
  44. package/dist/core/integrity-header.js +90 -0
  45. package/dist/core/integrity.d.ts +1 -25
  46. package/dist/core/integrity.js +16 -74
  47. package/dist/core/linter-adapter.d.ts +27 -3
  48. package/dist/core/linters.d.ts +8 -1
  49. package/dist/core/linters.js +116 -81
  50. package/dist/core/orphans.d.ts +3 -5
  51. package/dist/core/orphans.js +9 -10
  52. package/dist/core/presets.d.ts +19 -7
  53. package/dist/core/presets.js +19 -6
  54. package/dist/core/rule-catalog.d.ts +11 -12
  55. package/dist/core/rule-catalog.js +25 -94
  56. package/dist/core/rule-meta.d.ts +12 -0
  57. package/dist/core/rule-meta.js +47 -10
  58. package/dist/core/source-refs.d.ts +3 -23
  59. package/dist/core/source-refs.js +3 -27
  60. package/dist/core/test-utils.d.ts +13 -0
  61. package/dist/core/test-utils.js +40 -1
  62. package/dist/core/types.d.ts +18 -26
  63. package/dist/core/validate.d.ts +1 -2
  64. package/dist/core/validate.js +60 -47
  65. package/dist/coverage-evidence.js +2 -3
  66. package/dist/deprecated-key-files.d.ts +6 -0
  67. package/dist/deprecated-key-files.js +7 -6
  68. package/dist/exclude.d.ts +3 -1
  69. package/dist/exclude.js +9 -33
  70. package/dist/harness-assert.d.ts +18 -0
  71. package/dist/harness-assert.js +38 -0
  72. package/dist/hook-check-install.js +15 -6
  73. package/dist/hook-check.d.ts +1 -3
  74. package/dist/hook-check.js +3 -5
  75. package/dist/hook-install.d.ts +7 -41
  76. package/dist/hook-install.js +29 -96
  77. package/dist/hook-runtime.js +2 -1
  78. package/dist/load-hook.d.ts +3 -2
  79. package/dist/load-hook.js +28 -6
  80. package/dist/overrides.d.ts +25 -0
  81. package/dist/overrides.js +51 -0
  82. package/dist/plugin-loader.d.ts +23 -0
  83. package/dist/plugin-loader.js +42 -12
  84. package/dist/root-globs.d.ts +9 -0
  85. package/dist/root-globs.js +48 -0
  86. package/dist/rule-routing.js +6 -3
  87. package/dist/run-hook.d.ts +26 -2
  88. package/dist/run-hook.js +48 -12
  89. package/dist/scan-core.d.ts +96 -20
  90. package/dist/scan-core.js +171 -176
  91. package/dist/scan-files.d.ts +0 -8
  92. package/dist/scan-files.js +78 -20
  93. package/dist/scan.d.ts +12 -12
  94. package/dist/scan.js +33 -10
  95. package/dist/setup-plan.d.ts +15 -9
  96. package/dist/setup-plan.js +26 -18
  97. package/dist/test-coverage.d.ts +3 -8
  98. package/dist/test-coverage.js +6 -6
  99. package/dist/test.d.ts +1 -1
  100. package/dist/vigilesrc.schema.json +1329 -118
  101. package/package.json +1 -1
  102. package/skills/adopt-spec/SKILL.md +2 -1
@@ -225,61 +225,4 @@ export declare function leafCommandsNormalized(command: string): NormalizedLeaf[
225
225
  * Parse failure → `[]`.
226
226
  */
227
227
  export declare function leafArgvSource(command: string): string[][];
228
- /**
229
- * Every word of every simple command in `command` that could name a FILE, with
230
- * inline PROGRAM TEXT removed — the primitive behind "does this hook's script
231
- * exist?".
232
- *
233
- * 🔴 WHY A FOURTH EXTRACTOR, stated against the three that already exist,
234
- * because "there is already one that returns words" is exactly the reasoning
235
- * that produced the bug this replaces.
236
- *
237
- * - `leafCommands` drops every word it cannot reduce to a LITERAL, so
238
- * `${CLAUDE_PLUGIN_ROOT}/hooks/x.sh` — the standard spelling of a hook path —
239
- * disappears entirely. Unusable for a file question.
240
- * - `leafCommandsNormalized` basenames the head, so `./hooks/x.sh` becomes
241
- * `x.sh` and no resolver can find it.
242
- * - `leafArgvSource` keeps the spelling but answers a DIFFERENT question:
243
- * "which leaves unconditionally RUN". It drops the right-hand side of `&&`
244
- * by design, so `cd "$ROOT" && node hooks/x.mjs` yields no script. For
245
- * coverage attribution that abstention is correct; for "must this file
246
- * exist?" it is a miss, because a conditionally-run script still has to be
247
- * on disk.
248
- *
249
- * So this walks EVERY simple command, keeps every word at source level, and
250
- * subtracts only the words that are provably not paths.
251
- *
252
- * 🔴 WHAT IT SUBTRACTS, and the defect that motivated it. The hook scanner used
253
- * to run a regex over the raw command STRING. Against the standard portable
254
- * plugin idiom —
255
- *
256
- * node -e "(async()=>{…await import(…join(root,'hooks','always-on.mjs'))…})()"
257
- *
258
- * — it grabbed a character run ending at `.mjs` and reported the hook's script
259
- * as `import(require(node:url).pathToFileURL(require(node:path).join(root,hooks,always-on.mjs`,
260
- * MISSING. `hooks/always-on.mjs` was 1,766 bytes on disk. Nine such findings
261
- * across the 32-repo corpus, contributing to two `F/0` grades. Inside a shell
262
- * parse the argument of `-e` is not a word the shell will ever resolve to a
263
- * file, so it is not returned.
264
- *
265
- * ⚠️ HOW MUCH OF THAT THE FLAG TABLE ACTUALLY DID, measured rather than
266
- * assumed: none of it, on that corpus. Mutating the `-e`/`-c` subtraction OFF
267
- * and re-auditing all three affected repos still yields ZERO false hook-script
268
- * findings, because both real payloads are single words that either contain
269
- * whitespace or do not end in a script extension, and the caller anchors its
270
- * match to a whole word. The table is kept because it is the difference
271
- * between a function whose contract ("words that could name a file") is true
272
- * and one whose contract is merely true-so-far: without it a JavaScript
273
- * program is handed to every caller as a candidate filename, and the next
274
- * caller inherits the bug. Recorded here so nobody reads a corpus number back
275
- * onto the wrong mechanism.
276
- *
277
- * Words beginning with `-` are dropped as flags: a flag is not a path, and the
278
- * one caller anchors its match to a whole word anyway.
279
- *
280
- * Returns `null` — not `[]` — when the text does not parse as shell, so a
281
- * caller can tell "no file operands" from "no analysis", and cannot silently
282
- * treat the second as the first.
283
- */
284
- export declare function commandWords(command: string): string[] | null;
285
228
  //# sourceMappingURL=bash-effects.d.ts.map
@@ -31,7 +31,6 @@ exports.leafCommands = leafCommands;
31
31
  exports.stripWrappers = stripWrappers;
32
32
  exports.leafCommandsNormalized = leafCommandsNormalized;
33
33
  exports.leafArgvSource = leafArgvSource;
34
- exports.commandWords = commandWords;
35
34
  /**
36
35
  * The parser is loaded ON FIRST PARSE, not at module load — `sh()` memoizes it.
37
36
  *
@@ -1164,150 +1163,4 @@ function normalizeCallExpr(node, redirs) {
1164
1163
  chdir: stripped.chdir,
1165
1164
  };
1166
1165
  }
1167
- // ===========================================================================
1168
- // FILE-OPERAND extraction (the reference question, not the effect question)
1169
- // ===========================================================================
1170
- /**
1171
- * Interpreters, and the flags after which the NEXT word is a PROGRAM rather
1172
- * than a path. `node -e "<js>"`, `python -c "<py>"`, `perl -E "<pl>"`.
1173
- *
1174
- * Keyed by the head's basename, so `/usr/local/bin/node` and `node` behave the
1175
- * same.
1176
- */
1177
- const INLINE_PROGRAM_FLAGS = new Map([
1178
- ["node", ["-e", "--eval", "-p", "--print"]],
1179
- ["nodejs", ["-e", "--eval", "-p", "--print"]],
1180
- ["bun", ["-e", "--eval", "-p", "--print"]],
1181
- ["deno", ["-e", "--eval", "-p", "--print"]],
1182
- ["python", ["-c"]],
1183
- ["python2", ["-c"]],
1184
- ["python3", ["-c"]],
1185
- ["ruby", ["-e"]],
1186
- ["perl", ["-e", "-E"]],
1187
- ["php", ["-r"]],
1188
- ]);
1189
- /**
1190
- * Shells, whose `-c` argument is a nested SHELL program. Not program text to be
1191
- * discarded — program text to be PARSED, so `bash -c 'exec "$ROOT/hooks/x.sh"'`
1192
- * still yields its script.
1193
- */
1194
- const SHELL_HEADS = new Set([
1195
- "sh",
1196
- "bash",
1197
- "zsh",
1198
- "dash",
1199
- "ksh",
1200
- "ash",
1201
- "busybox",
1202
- ]);
1203
- /** Guard against a pathological `sh -c 'sh -c "sh -c …"'` nest. */
1204
- const MAX_SHELL_NESTING = 3;
1205
- /**
1206
- * Every word of every simple command in `command` that could name a FILE, with
1207
- * inline PROGRAM TEXT removed — the primitive behind "does this hook's script
1208
- * exist?".
1209
- *
1210
- * 🔴 WHY A FOURTH EXTRACTOR, stated against the three that already exist,
1211
- * because "there is already one that returns words" is exactly the reasoning
1212
- * that produced the bug this replaces.
1213
- *
1214
- * - `leafCommands` drops every word it cannot reduce to a LITERAL, so
1215
- * `${CLAUDE_PLUGIN_ROOT}/hooks/x.sh` — the standard spelling of a hook path —
1216
- * disappears entirely. Unusable for a file question.
1217
- * - `leafCommandsNormalized` basenames the head, so `./hooks/x.sh` becomes
1218
- * `x.sh` and no resolver can find it.
1219
- * - `leafArgvSource` keeps the spelling but answers a DIFFERENT question:
1220
- * "which leaves unconditionally RUN". It drops the right-hand side of `&&`
1221
- * by design, so `cd "$ROOT" && node hooks/x.mjs` yields no script. For
1222
- * coverage attribution that abstention is correct; for "must this file
1223
- * exist?" it is a miss, because a conditionally-run script still has to be
1224
- * on disk.
1225
- *
1226
- * So this walks EVERY simple command, keeps every word at source level, and
1227
- * subtracts only the words that are provably not paths.
1228
- *
1229
- * 🔴 WHAT IT SUBTRACTS, and the defect that motivated it. The hook scanner used
1230
- * to run a regex over the raw command STRING. Against the standard portable
1231
- * plugin idiom —
1232
- *
1233
- * node -e "(async()=>{…await import(…join(root,'hooks','always-on.mjs'))…})()"
1234
- *
1235
- * — it grabbed a character run ending at `.mjs` and reported the hook's script
1236
- * as `import(require(node:url).pathToFileURL(require(node:path).join(root,hooks,always-on.mjs`,
1237
- * MISSING. `hooks/always-on.mjs` was 1,766 bytes on disk. Nine such findings
1238
- * across the 32-repo corpus, contributing to two `F/0` grades. Inside a shell
1239
- * parse the argument of `-e` is not a word the shell will ever resolve to a
1240
- * file, so it is not returned.
1241
- *
1242
- * ⚠️ HOW MUCH OF THAT THE FLAG TABLE ACTUALLY DID, measured rather than
1243
- * assumed: none of it, on that corpus. Mutating the `-e`/`-c` subtraction OFF
1244
- * and re-auditing all three affected repos still yields ZERO false hook-script
1245
- * findings, because both real payloads are single words that either contain
1246
- * whitespace or do not end in a script extension, and the caller anchors its
1247
- * match to a whole word. The table is kept because it is the difference
1248
- * between a function whose contract ("words that could name a file") is true
1249
- * and one whose contract is merely true-so-far: without it a JavaScript
1250
- * program is handed to every caller as a candidate filename, and the next
1251
- * caller inherits the bug. Recorded here so nobody reads a corpus number back
1252
- * onto the wrong mechanism.
1253
- *
1254
- * Words beginning with `-` are dropped as flags: a flag is not a path, and the
1255
- * one caller anchors its match to a whole word anyway.
1256
- *
1257
- * Returns `null` — not `[]` — when the text does not parse as shell, so a
1258
- * caller can tell "no file operands" from "no analysis", and cannot silently
1259
- * treat the second as the first.
1260
- */
1261
- function commandWords(command) {
1262
- return commandWordsAt(command, 0);
1263
- }
1264
- function commandWordsAt(command, depth) {
1265
- let file;
1266
- try {
1267
- file = sh().syntax.NewParser().Parse(command, "cmd.sh");
1268
- }
1269
- catch {
1270
- return null;
1271
- }
1272
- const out = [];
1273
- sh().syntax.Walk(file, (node) => {
1274
- if (sh().syntax.NodeType(node) === "CallExpr" && node.Args?.length)
1275
- fileOperandsOf(node.Args, depth, out);
1276
- return true;
1277
- });
1278
- return out;
1279
- }
1280
- /**
1281
- * The file-operand words of ONE simple command, appended to `out`.
1282
- *
1283
- * Wrappers are resolved through with the same table `leafArgvSource` uses (it
1284
- * keys on the BASENAME head, and wrappers only ever drop words off the FRONT,
1285
- * so a count maps the result back onto the original spellings — not a second
1286
- * copy of the rule). Flags never name a file, so they are dropped; the word
1287
- * AFTER an inline-program flag is dropped with them, and the word after a
1288
- * shell's `-c` is parsed as shell instead.
1289
- */
1290
- function fileOperandsOf(args, depth, out) {
1291
- const raw = args.map((w) => sourceParts(w.Parts) ?? "");
1292
- const probe = [normalizeHead(raw[0] ?? ""), ...raw.slice(1)];
1293
- const argv = raw.slice(probe.length - stripWrappers(probe).argv.length);
1294
- const head = normalizeHead(argv[0] ?? "");
1295
- const programFlags = INLINE_PROGRAM_FLAGS.get(head);
1296
- const nestsShell = SHELL_HEADS.has(head) && depth < MAX_SHELL_NESTING;
1297
- for (let i = 0; i < argv.length; i++) {
1298
- const w = argv[i] ?? "";
1299
- if (w === "")
1300
- continue;
1301
- if (!w.startsWith("-")) {
1302
- out.push(w);
1303
- continue;
1304
- }
1305
- if (nestsShell && w === "-c") {
1306
- out.push(...(commandWordsAt(argv[++i] ?? "", depth + 1) ?? []));
1307
- }
1308
- else if (programFlags?.includes(w)) {
1309
- i++; // the program text — not a word any shell resolves to a file
1310
- }
1311
- }
1312
- }
1313
1166
  //# sourceMappingURL=bash-effects.js.map
@@ -48,16 +48,16 @@ export interface CompileGeneratorSkillResult {
48
48
  * function* () { … })` — to a full SKILL.md (frontmatter + body + integrity
49
49
  * hash), verifying gate references. This is the CLI entry for generator skills.
50
50
  */
51
- export declare function compileGeneratorSkill(source: string, options?: {
52
- basePath?: string;
53
- specFile?: string;
51
+ export declare function compileGeneratorSkill(source: string, options: {
52
+ readonly basePath: string;
53
+ readonly specFile?: string;
54
54
  }): CompileGeneratorSkillResult;
55
55
  /**
56
56
  * Compile a generator's SOURCE text to SKILL.md markdown + verified-ref
57
57
  * errors. `frontmatter` (name/description/…) is prepended verbatim if given.
58
58
  */
59
- export declare function compileGenerator(source: string, options?: {
60
- basePath?: string;
61
- frontmatter?: string;
59
+ export declare function compileGenerator(source: string, options: {
60
+ readonly basePath: string;
61
+ readonly frontmatter?: string;
62
62
  }): CompileGeneratorResult;
63
63
  //# sourceMappingURL=compile-generator.d.ts.map
@@ -263,8 +263,8 @@ function extractMeta(obj) {
263
263
  * function* () { … })` — to a full SKILL.md (frontmatter + body + integrity
264
264
  * hash), verifying gate references. This is the CLI entry for generator skills.
265
265
  */
266
- function compileGeneratorSkill(source, options = {}) {
267
- const basePath = options.basePath ?? process.cwd();
266
+ function compileGeneratorSkill(source, options) {
267
+ const basePath = options.basePath;
268
268
  const specFile = options.specFile ?? "SKILL.md.spec.ts";
269
269
  const sf = typescript_1.default.createSourceFile("s.ts", source, typescript_1.default.ScriptTarget.Latest, true);
270
270
  const call = findGenSkillCall(sf);
@@ -309,8 +309,8 @@ function compileGeneratorSkill(source, options = {}) {
309
309
  * Compile a generator's SOURCE text to SKILL.md markdown + verified-ref
310
310
  * errors. `frontmatter` (name/description/…) is prepended verbatim if given.
311
311
  */
312
- function compileGenerator(source, options = {}) {
313
- const basePath = options.basePath ?? process.cwd();
312
+ function compileGenerator(source, options) {
313
+ const basePath = options.basePath;
314
314
  const sf = typescript_1.default.createSourceFile("skill.ts", source, typescript_1.default.ScriptTarget.Latest, true);
315
315
  const gen = findGenerator(sf);
316
316
  if (!gen?.body) {
@@ -66,6 +66,46 @@ export declare function validateCommandRef(command: string, basePath: string): C
66
66
  export declare function validateSymbolRef(file: string, name: string, basePath: string): Promise<CompileError | null>;
67
67
  export declare function validateDirRef(dirPath: string, basePath: string): CompileError | null;
68
68
  export declare function validateGlobRef(pattern: string, basePath: string): CompileError | null;
69
+ /**
70
+ * Why an `enforce()` reference was NOT verified. Separate members, not one
71
+ * "unknown", because the compile output turns each into a different instruction
72
+ * (make-the-distinction-a-type): a switch someone turned off is fixed by turning
73
+ * it on, an unset rule by setting it, an unreadable config by fixing the probe.
74
+ */
75
+ export type UnverifiedReason =
76
+ /** `enforce(…, { verify: false })` on this rule. */
77
+ "verify-false"
78
+ /** `verifyLinters: false` for the whole compile. */
79
+ | "verification-off"
80
+ /** `linterModes[<linter>] === false`. */
81
+ | "linter-off"
82
+ /** catalog-only: the rule exists, the config was not read. */
83
+ | "config-not-read"
84
+ /** the whole config was read and no block sets the rule. */
85
+ | "not-configured"
86
+ /** the rule exists; whether the config switches it on could not be read. */
87
+ | "enabled-unknown"
88
+ /** the rule does not exist (a compile error as well). */
89
+ | "not-found"
90
+ /** the config switches the rule off (a compile error as well). */
91
+ | "disabled";
92
+ /** What `compile` established about one `enforce()` reference. */
93
+ export type EnforceVerdict = {
94
+ readonly kind: "verified";
95
+ } | {
96
+ readonly kind: "unverified";
97
+ readonly reason: UnverifiedReason;
98
+ };
99
+ /** One `enforce()` reference and its verdict, in spec order. */
100
+ export interface EnforceVerdictEntry {
101
+ readonly ref: string;
102
+ readonly verdict: EnforceVerdict;
103
+ }
104
+ /**
105
+ * The sentence the compile prints for an unverified reference: what happened
106
+ * and the one thing that turns it into "Enforced by".
107
+ */
108
+ export declare function unverifiedAdvice(ref: string, reason: UnverifiedReason): string;
69
109
  export interface CompileClaudeResult {
70
110
  markdown: string;
71
111
  errors: CompileError[];
@@ -86,10 +126,28 @@ export interface CompileClaudeResult {
86
126
  */
87
127
  budgetFindings: CompileError[];
88
128
  linterResults: LinterCheckResult[];
129
+ /**
130
+ * One entry per `enforce()` rule, in spec order: rendered "**Enforced by:**"
131
+ * exactly when `verdict.kind === "verified"`, "**Claimed (unverified):**"
132
+ * otherwise. The CLI's "N linter-verified" count is the verified entries.
133
+ */
134
+ enforceVerdicts: EnforceVerdictEntry[];
89
135
  /** Estimated token count of compiled output (~4 chars/token). */
90
136
  tokens: number;
91
137
  /** All targets from the spec (for multi-target compilation). */
92
138
  targets: string[];
139
+ /**
140
+ * Each target's file: its repo-relative path (a secondary target is named
141
+ * from the primary's directory) and its markdown, rendered for THAT path so
142
+ * every link resolves from where the file sits. The first is the primary,
143
+ * whose markdown is `markdown`.
144
+ */
145
+ outputs: CompiledOutput[];
146
+ }
147
+ /** One file a multi-target compile writes. */
148
+ export interface CompiledOutput {
149
+ readonly path: string;
150
+ readonly markdown: string;
93
151
  }
94
152
  export interface CompileClaudeOptions {
95
153
  /**
@@ -107,7 +165,8 @@ export interface CompileClaudeOptions {
107
165
  maxSectionChars?: number;
108
166
  /** Character budget for the whole rendered Rules section (0 disables). */
109
167
  maxRulesChars?: number;
110
- basePath?: string;
168
+ /** The repo root every reference resolves against. Required: no cwd fallback. */
169
+ readonly basePath: string;
111
170
  specFile?: string;
112
171
  /** Injected harness dialect; its instructionTargets[0] is the default target. */
113
172
  dialect?: HarnessDialect;
@@ -166,13 +225,15 @@ export declare const DEFAULT_MAX_SECTION_CHARS = 15000;
166
225
  * budget, which leaves the other half for everything else the file carries.
167
226
  */
168
227
  export declare const DEFAULT_MAX_RULES_CHARS = 20000;
228
+ /** The compile options that decide how an `enforce()` reference is verified. */
229
+ type LinterVerifyOptions = Pick<CompileClaudeOptions, "verifyLinters" | "linterModes" | "catalogOnly" | "linters">;
169
230
  /**
170
231
  * Compile a ClaudeSpec into markdown.
171
232
  *
172
233
  * Returns the compiled markdown, validation errors, and linter check results.
173
234
  * The markdown is generated even if there are errors (with warnings).
174
235
  */
175
- export declare function compileClaude(spec: ClaudeSpec, options?: CompileClaudeOptions): Promise<CompileClaudeResult>;
236
+ export declare function compileClaude(spec: ClaudeSpec, options: Readonly<CompileClaudeOptions>): Promise<CompileClaudeResult>;
176
237
  export interface CompileSkillResult {
177
238
  /**
178
239
  * The stamped artifact — present ONLY when `errors` is empty. `null` is what
@@ -187,13 +248,14 @@ export interface CompileSkillResult {
187
248
  /**
188
249
  * Compile a SkillSpec into SKILL.md markdown with YAML frontmatter.
189
250
  */
190
- export declare function compileSkill(spec: SkillSpec, options?: {
191
- basePath?: string;
251
+ export declare function compileSkill(spec: SkillSpec, options: Readonly<{
252
+ /** The repo root every reference resolves against. Required: no cwd fallback. */
253
+ readonly basePath: string;
192
254
  specFile?: string;
193
255
  /** The harness dialect — supplies `skillFrontmatterKeys`. Omitting it emits
194
256
  * every key the compiler can render, so existing callers are unchanged. */
195
257
  dialect?: HarnessDialect;
196
- }): Promise<CompileSkillResult>;
258
+ }>): Promise<CompileSkillResult>;
197
259
  export interface CompileAgentResult {
198
260
  /**
199
261
  * The stamped artifact — present ONLY when `errors` is empty. `null` is what
@@ -210,13 +272,14 @@ export interface CompileAgentResult {
210
272
  * Verifies the tool contract and the body's references; the marks the body
211
273
  * carries (`vigiles:symbol`, file/cmd refs) are the same ones `lint` re-checks.
212
274
  */
213
- export declare function compileAgent(spec: AgentSpec, options: {
214
- basePath?: string;
275
+ export declare function compileAgent(spec: AgentSpec, options: Readonly<{
276
+ /** The repo root every reference resolves against. Required: no cwd fallback. */
277
+ basePath: string;
215
278
  specFile?: string;
216
279
  /** The harness dialect to verify the tool contract against (required — the
217
280
  * core defines no default dialect; the adapter/composition root injects it). */
218
281
  dialect: HarnessDialect;
219
- }): Promise<CompileAgentResult>;
282
+ } & LinterVerifyOptions>): Promise<CompileAgentResult>;
220
283
  export interface CompileRailwayOptions {
221
284
  /** Names of compiled agents, to resolve `delegate` targets. Skipped if omitted. */
222
285
  knownAgents?: readonly string[];
@@ -261,4 +324,5 @@ export interface AdoptResult {
261
324
  * Returns the diff so users can see what was manually changed.
262
325
  */
263
326
  export declare function adoptDiff(filePath: string, spec: ClaudeSpec | SkillSpec | AgentSpec, basePath: string, dialect: HarnessDialect): Promise<AdoptResult>;
327
+ export {};
264
328
  //# sourceMappingURL=compile.d.ts.map