vigiles 38.0.0 → 38.2.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.
- package/dist/adapters/claude-code/dialect.js +5 -1
- package/dist/audit-report.d.ts +8 -0
- package/dist/audit-report.js +12 -3
- package/dist/cli-main.d.ts +7 -0
- package/dist/cli-main.js +53 -10
- package/dist/core/CLAUDE.md.spec.js +0 -4
- package/dist/core/compile.js +15 -9
- package/dist/core/config-schema.d.ts +6 -1
- package/dist/core/config-schema.js +36 -2
- package/dist/core/instruction-baseline.d.ts +26 -0
- package/dist/core/instruction-baseline.js +45 -1
- package/dist/core/instruction-remedies.d.ts +13 -0
- package/dist/core/instruction-remedies.js +24 -0
- package/dist/core/instruction-weight.d.ts +6 -1
- package/dist/core/keyfiles-source.d.ts +9 -0
- package/dist/core/keyfiles-source.js +88 -0
- package/dist/core/keyfiles.d.ts +64 -0
- package/dist/core/keyfiles.js +93 -0
- package/dist/core/orphans.js +1 -1
- package/dist/core/rule-meta.js +9 -0
- package/dist/core/session.d.ts +7 -0
- package/dist/core/session.js +8 -0
- package/dist/core/spec.d.ts +14 -1
- package/dist/core/types.d.ts +26 -1
- package/dist/deprecated-key-files.d.ts +35 -0
- package/dist/deprecated-key-files.js +62 -0
- package/dist/instruction-weight-ratchet.d.ts +17 -4
- package/dist/instruction-weight-ratchet.js +71 -22
- package/dist/research-index.d.ts +6 -6
- package/dist/research-index.js +6 -6
- package/dist/scan.d.ts +21 -0
- package/dist/scan.js +29 -2
- package/dist/setup-plan.d.ts +1 -1
- package/dist/setup-plan.js +3 -0
- package/dist/vigilesrc.schema.json +86 -0
- package/hooks/pre-edit.sh +1 -1
- package/package.json +1 -1
- package/skills/adopt-spec/SKILL.md +7 -12
- package/skills/edit-spec/SKILL.md +32 -25
package/dist/research-index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Research-index completeness — the deterministic FLOOR keeping the `research/`
|
|
3
3
|
* corpus and its index (`research/CLAUDE.md.spec.ts`) in sync. The spec's
|
|
4
|
-
* `
|
|
5
|
-
* already verifies the OTHER direction (every
|
|
6
|
-
* `vigiles compile` fails), so the only open gap is a doc that was ADDED but
|
|
4
|
+
* `file()` references are the AGENT-FACING index of every research doc; the
|
|
5
|
+
* compiler already verifies the OTHER direction (every referenced path EXISTS,
|
|
6
|
+
* else `vigiles compile` fails), so the only open gap is a doc that was ADDED but
|
|
7
7
|
* never indexed. This check closes it: every `research/*.md` (except the
|
|
8
8
|
* human-facing `README.md`) must appear in the index, or the dogfood test fails.
|
|
9
9
|
*
|
|
@@ -17,13 +17,13 @@ export declare const INDEX_EXEMPT: readonly ["README.md"];
|
|
|
17
17
|
/**
|
|
18
18
|
* Research doc basenames (e.g. `roadmap.md`) NOT referenced anywhere in
|
|
19
19
|
* `indexContent`. A doc counts as indexed if its repo-relative path
|
|
20
|
-
* (`research/<name>.md`) appears in the index — the exact form
|
|
21
|
-
*
|
|
20
|
+
* (`research/<name>.md`) appears in the index — the exact form a `file()`
|
|
21
|
+
* reference takes. Exempt docs (the README) are never flagged.
|
|
22
22
|
*/
|
|
23
23
|
export declare function unindexedResearchDocs(docFilenames: readonly string[], indexContent: string, exempt?: readonly string[]): string[];
|
|
24
24
|
/**
|
|
25
25
|
* Index entries pointing at a `research/<name>.md` that no longer exists on
|
|
26
|
-
* disk. The compiler catches this at compile time (a missing `
|
|
26
|
+
* disk. The compiler catches this at compile time (a missing `file()` path is
|
|
27
27
|
* a compile error), so this is a belt-and-suspenders reader for a test that
|
|
28
28
|
* wants to assert it directly without invoking the compiler.
|
|
29
29
|
*/
|
package/dist/research-index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Research-index completeness — the deterministic FLOOR keeping the `research/`
|
|
4
4
|
* corpus and its index (`research/CLAUDE.md.spec.ts`) in sync. The spec's
|
|
5
|
-
* `
|
|
6
|
-
* already verifies the OTHER direction (every
|
|
7
|
-
* `vigiles compile` fails), so the only open gap is a doc that was ADDED but
|
|
5
|
+
* `file()` references are the AGENT-FACING index of every research doc; the
|
|
6
|
+
* compiler already verifies the OTHER direction (every referenced path EXISTS,
|
|
7
|
+
* else `vigiles compile` fails), so the only open gap is a doc that was ADDED but
|
|
8
8
|
* never indexed. This check closes it: every `research/*.md` (except the
|
|
9
9
|
* human-facing `README.md`) must appear in the index, or the dogfood test fails.
|
|
10
10
|
*
|
|
@@ -22,15 +22,15 @@ exports.INDEX_EXEMPT = ["README.md"];
|
|
|
22
22
|
/**
|
|
23
23
|
* Research doc basenames (e.g. `roadmap.md`) NOT referenced anywhere in
|
|
24
24
|
* `indexContent`. A doc counts as indexed if its repo-relative path
|
|
25
|
-
* (`research/<name>.md`) appears in the index — the exact form
|
|
26
|
-
*
|
|
25
|
+
* (`research/<name>.md`) appears in the index — the exact form a `file()`
|
|
26
|
+
* reference takes. Exempt docs (the README) are never flagged.
|
|
27
27
|
*/
|
|
28
28
|
function unindexedResearchDocs(docFilenames, indexContent, exempt = exports.INDEX_EXEMPT) {
|
|
29
29
|
return docFilenames.filter((name) => !exempt.includes(name) && !indexContent.includes(`research/${name}`));
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Index entries pointing at a `research/<name>.md` that no longer exists on
|
|
33
|
-
* disk. The compiler catches this at compile time (a missing `
|
|
33
|
+
* disk. The compiler catches this at compile time (a missing `file()` path is
|
|
34
34
|
* a compile error), so this is a belt-and-suspenders reader for a test that
|
|
35
35
|
* wants to assert it directly without invoking the compiler.
|
|
36
36
|
*/
|
package/dist/scan.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type PluginLayout } from "./core/layout.js";
|
|
15
15
|
import type { ExcludeSet } from "./exclude.js";
|
|
16
|
+
import type { DeprecatedKeyFilesFinding } from "./deprecated-key-files.js";
|
|
16
17
|
import type { HarnessDialect } from "./core/dialect.js";
|
|
17
18
|
import type { ToolIssue } from "./core/tool-contract.js";
|
|
18
19
|
import { type HookEventIssue } from "./core/hook-events.js";
|
|
@@ -329,6 +330,19 @@ export interface ScanReport {
|
|
|
329
330
|
* on day one is switched off on day one.
|
|
330
331
|
*/
|
|
331
332
|
readonly instructionWeight: InstructionWeight | null;
|
|
333
|
+
/**
|
|
334
|
+
* Instruction specs still using the deprecated `keyFiles` — the
|
|
335
|
+
* `deprecated-key-files` rule's own detector (`findDeprecatedKeyFiles`),
|
|
336
|
+
* handed in through `opts` by `audit`, so `lint` and `audit` cannot
|
|
337
|
+
* disagree. Advisory: printed with its fix, never scored.
|
|
338
|
+
*
|
|
339
|
+
* ABSENT when there are none, never `[]`, for the parity reason
|
|
340
|
+
* `coverageCaveats` gives. ⚠️ The browser twin produces none: it would need the
|
|
341
|
+
* TypeScript parser in the site bundle, and the demo does not fetch spec
|
|
342
|
+
* sources. No vendored parity fixture carries a spec, so the gate stays
|
|
343
|
+
* byte-identical; a spec added to one would show this gap as a parity diff.
|
|
344
|
+
*/
|
|
345
|
+
readonly deprecatedKeyFiles?: readonly DeprecatedKeyFilesFinding[];
|
|
332
346
|
/** Skills/agents whose `---` block isn't valid YAML — informational (may still load via salvage). */
|
|
333
347
|
readonly malformedFrontmatter: readonly FrontmatterParseIssue[];
|
|
334
348
|
readonly warnings: readonly string[];
|
|
@@ -444,6 +458,13 @@ export declare function scanPlugin(dir: string, layout: PluginLayout, dialect: H
|
|
|
444
458
|
* context `overBundles` builds, so a new checker cannot forget it).
|
|
445
459
|
*/
|
|
446
460
|
excludes?: ExcludeSet;
|
|
461
|
+
/**
|
|
462
|
+
* The `deprecated-key-files` findings for this directory, from the rule's
|
|
463
|
+
* own detector (`findDeprecatedKeyFiles`), computed by the composition root
|
|
464
|
+
* — the one place allowed to walk the repository and read specs. `audit`
|
|
465
|
+
* passes them; every other caller leaves the field off the report.
|
|
466
|
+
*/
|
|
467
|
+
deprecatedKeyFiles?: readonly DeprecatedKeyFilesFinding[];
|
|
447
468
|
/**
|
|
448
469
|
* The repo's `.vigilesrc.json#harnesses`, resolved — every declared harness
|
|
449
470
|
* with its own layout, dialect and roots, IN DECLARATION ORDER.
|
package/dist/scan.js
CHANGED
|
@@ -55,6 +55,7 @@ const plugin_loader_js_2 = require("./plugin-loader.js");
|
|
|
55
55
|
const score_core_js_1 = require("./score-core.js");
|
|
56
56
|
const skill_refs_js_1 = require("./skill-refs.js");
|
|
57
57
|
const layout_js_1 = require("./core/layout.js");
|
|
58
|
+
const keyfiles_js_1 = require("./core/keyfiles.js");
|
|
58
59
|
const hook_events_js_1 = require("./core/hook-events.js");
|
|
59
60
|
const mcp_config_js_1 = require("./core/mcp-config.js");
|
|
60
61
|
const agent_plugins_js_1 = require("./core/agent-plugins.js");
|
|
@@ -357,6 +358,7 @@ function scanPlugin(dir, layout, dialect, opts = {}) {
|
|
|
357
358
|
evaluable: coverage.total,
|
|
358
359
|
coverageEvidence: (0, test_coverage_js_1.coverageEvidenceCounts)(coverage),
|
|
359
360
|
...(caveats.length > 0 ? { coverageCaveats: caveats } : {}),
|
|
361
|
+
...deprecatedKeyFilesField(opts.deprecatedKeyFiles),
|
|
360
362
|
ownTestSignal: ownTestSignalOnDisk(dir),
|
|
361
363
|
puritySummary,
|
|
362
364
|
};
|
|
@@ -656,6 +658,32 @@ function instructionWeightLines(w) {
|
|
|
656
658
|
...tail,
|
|
657
659
|
];
|
|
658
660
|
}
|
|
661
|
+
/** The scan field, present only when some spec still uses `keyFiles`. */
|
|
662
|
+
function deprecatedKeyFilesField(found) {
|
|
663
|
+
return found && found.length > 0 ? { deprecatedKeyFiles: found } : {};
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* The audit's `deprecated-key-files` section: one line per spec with what it
|
|
667
|
+
* costs, then the fix once. Next to the instruction weight, because that is
|
|
668
|
+
* the number the field inflates.
|
|
669
|
+
*/
|
|
670
|
+
function deprecatedKeyFilesLines(r) {
|
|
671
|
+
const found = r.deprecatedKeyFiles ?? [];
|
|
672
|
+
if (found.length === 0)
|
|
673
|
+
return [];
|
|
674
|
+
return section("Deprecated `keyFiles`", [
|
|
675
|
+
...found.map((f) => ` ⚠ ${f.path}: ${(0, keyfiles_js_1.keyFilesCost)(f)}`),
|
|
676
|
+
` → ${(0, keyfiles_js_1.keyFilesFix)(found.map((f) => (0, keyfiles_js_1.instructionFileOfSpec)(f.path)))}.`,
|
|
677
|
+
` ${keyfiles_js_1.KEYFILES_DOCS_URL} [deprecated-key-files]`,
|
|
678
|
+
], found.length);
|
|
679
|
+
}
|
|
680
|
+
/** What the instruction file costs: its always-loaded weight, then any deprecated `keyFiles` inflating it. */
|
|
681
|
+
function instructionCostLines(r) {
|
|
682
|
+
const weight = r.instructionWeight
|
|
683
|
+
? [...instructionWeightLines(r.instructionWeight), ""]
|
|
684
|
+
: [];
|
|
685
|
+
return [...weight, ...deprecatedKeyFilesLines(r)];
|
|
686
|
+
}
|
|
659
687
|
/** The commands and output-style lines of a scan's facts; a harness without styles says so. */
|
|
660
688
|
function inventoryFacts(r) {
|
|
661
689
|
const commands = r.commands > 0 ? [`Commands: ${String(r.commands)}`] : [];
|
|
@@ -676,8 +704,7 @@ function formatScanReport(r) {
|
|
|
676
704
|
}
|
|
677
705
|
// Right under the instruction file, because that is the line a reader is
|
|
678
706
|
// already looking at when they wonder what it costs.
|
|
679
|
-
|
|
680
|
-
out.push(...instructionWeightLines(r.instructionWeight), ""); // prettier-ignore
|
|
707
|
+
out.push(...instructionCostLines(r));
|
|
681
708
|
out.push(...section("Skills", r.skills.map(skillLine)));
|
|
682
709
|
out.push(...section("Agents", r.agents.flatMap(agentLines), r.agents.length));
|
|
683
710
|
const hookMark = {
|
package/dist/setup-plan.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export declare const WORKFLOW_RULES: readonly ["require-instructions-spec", "unt
|
|
|
116
116
|
* keep their own default severities. Named for the group taxonomy
|
|
117
117
|
* (research/install-enforcement-dx.md).
|
|
118
118
|
*/
|
|
119
|
-
export declare const NUDGE_RULES: readonly ["skill-description-budget", "frontmatter-valid", "skill-frontmatter", "prefer-compiled-hooks", "unmarked-refs", "lethal-trifecta", "skill-resource-resolves", "skill-missing-fence", "plugin-dir-layout", "delegation-trifecta", "hook-block-ineffective", "hook-matcher", "doc-refs"];
|
|
119
|
+
export declare const NUDGE_RULES: readonly ["skill-description-budget", "frontmatter-valid", "skill-frontmatter", "prefer-compiled-hooks", "unmarked-refs", "lethal-trifecta", "skill-resource-resolves", "skill-missing-fence", "plugin-dir-layout", "delegation-trifecta", "hook-block-ineffective", "hook-matcher", "doc-refs", "deprecated-key-files"];
|
|
120
120
|
/**
|
|
121
121
|
* Pure config-merge for what `vigiles init` writes to `.vigilesrc.json`: record
|
|
122
122
|
* the harnesses if absent, gate the structural rules by EXTENDING the
|
package/dist/setup-plan.js
CHANGED
|
@@ -119,6 +119,9 @@ exports.NUDGE_RULES = [
|
|
|
119
119
|
// 2 582 markdown files, because a fence in prose is a drawing of config rather
|
|
120
120
|
// than config. See docs/rules/doc-refs.md.
|
|
121
121
|
"doc-refs",
|
|
122
|
+
// A deprecation notice: it must never gate, or upgrading vigiles would turn a
|
|
123
|
+
// consumer's CI red — the very thing the one-major window exists to avoid.
|
|
124
|
+
"deprecated-key-files",
|
|
122
125
|
];
|
|
123
126
|
/**
|
|
124
127
|
* Pure config-merge for what `vigiles init` writes to `.vigilesrc.json`: record
|
|
@@ -1749,6 +1749,92 @@
|
|
|
1749
1749
|
]
|
|
1750
1750
|
},
|
|
1751
1751
|
"instruction-weight": {
|
|
1752
|
+
"anyOf": [
|
|
1753
|
+
{
|
|
1754
|
+
"anyOf": [
|
|
1755
|
+
{
|
|
1756
|
+
"type": "string",
|
|
1757
|
+
"const": "warn"
|
|
1758
|
+
},
|
|
1759
|
+
{
|
|
1760
|
+
"type": "string",
|
|
1761
|
+
"const": "error"
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
"type": "boolean",
|
|
1765
|
+
"const": false
|
|
1766
|
+
},
|
|
1767
|
+
{
|
|
1768
|
+
"type": "string",
|
|
1769
|
+
"const": "off"
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
"type": "number",
|
|
1773
|
+
"const": 0
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
"type": "number",
|
|
1777
|
+
"const": 1
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
"type": "number",
|
|
1781
|
+
"const": 2
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
"type": "boolean",
|
|
1785
|
+
"const": true
|
|
1786
|
+
}
|
|
1787
|
+
]
|
|
1788
|
+
},
|
|
1789
|
+
{
|
|
1790
|
+
"type": "array",
|
|
1791
|
+
"prefixItems": [
|
|
1792
|
+
{
|
|
1793
|
+
"type": "string",
|
|
1794
|
+
"const": "warn"
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
"type": "object",
|
|
1798
|
+
"properties": {
|
|
1799
|
+
"max": {
|
|
1800
|
+
"type": "integer",
|
|
1801
|
+
"exclusiveMinimum": 0,
|
|
1802
|
+
"maximum": 9007199254740991
|
|
1803
|
+
}
|
|
1804
|
+
},
|
|
1805
|
+
"additionalProperties": false
|
|
1806
|
+
}
|
|
1807
|
+
],
|
|
1808
|
+
"items": false,
|
|
1809
|
+
"minItems": 2,
|
|
1810
|
+
"maxItems": 2
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
"type": "array",
|
|
1814
|
+
"prefixItems": [
|
|
1815
|
+
{
|
|
1816
|
+
"type": "string",
|
|
1817
|
+
"const": "error"
|
|
1818
|
+
},
|
|
1819
|
+
{
|
|
1820
|
+
"type": "object",
|
|
1821
|
+
"properties": {
|
|
1822
|
+
"max": {
|
|
1823
|
+
"type": "integer",
|
|
1824
|
+
"exclusiveMinimum": 0,
|
|
1825
|
+
"maximum": 9007199254740991
|
|
1826
|
+
}
|
|
1827
|
+
},
|
|
1828
|
+
"additionalProperties": false
|
|
1829
|
+
}
|
|
1830
|
+
],
|
|
1831
|
+
"items": false,
|
|
1832
|
+
"minItems": 2,
|
|
1833
|
+
"maxItems": 2
|
|
1834
|
+
}
|
|
1835
|
+
]
|
|
1836
|
+
},
|
|
1837
|
+
"deprecated-key-files": {
|
|
1752
1838
|
"anyOf": [
|
|
1753
1839
|
{
|
|
1754
1840
|
"type": "string",
|
package/hooks/pre-edit.sh
CHANGED
|
@@ -30,7 +30,7 @@ BLOCKED: ${FILE} is a compiled build artifact — do not edit it directly.
|
|
|
30
30
|
|
|
31
31
|
Instead:
|
|
32
32
|
1. Read ${SPEC_FILE} to understand the spec structure
|
|
33
|
-
2. Edit ${SPEC_FILE} to make your changes (add/modify rules, sections,
|
|
33
|
+
2. Edit ${SPEC_FILE} to make your changes (add/modify rules, sections, commands)
|
|
34
34
|
3. Run: npx vigiles compile
|
|
35
35
|
4. The compiled ${FILE} will be regenerated automatically
|
|
36
36
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "38.
|
|
3
|
+
"version": "38.2.0",
|
|
4
4
|
"description": "Audit, test and measure the harness your AI agent runs on — grade your CLAUDE.md / AGENTS.md, skills, subagents and hooks, run them against a scripted model, and measure whether they actually fire.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -11,7 +11,7 @@ Start a typed `CLAUDE.md.spec.ts` from an existing hand-written CLAUDE.md (or AG
|
|
|
11
11
|
|
|
12
12
|
Adoption is the **safe, faithful on-ramp — never an upgrade in disguise.** These are non-negotiable:
|
|
13
13
|
|
|
14
|
-
- **Faithful.** Preserve every rule, command,
|
|
14
|
+
- **Faithful.** Preserve every rule, command, and prose section as-is. Invent nothing — the spec must compile back to ~the user's existing file. The one exception is a file map ("Key Files"): never emit the deprecated `keyFiles` field — see the guideline under Step 3.
|
|
15
15
|
- **Non-destructive.** Never edit the original `CLAUDE.md` / `AGENTS.md`. Only write the new `.spec.ts`. Never auto-`compile` over the file — switching it to spec-managed is a separate, explicit step the user runs with a diff to review.
|
|
16
16
|
- **Don't escalate enforcement.** Keep `guidance()` as `guidance()`. Upgrading to `enforce()` has a cost (config/plugins, possible false positives) and is a separate opt-in step — the `strengthen` skill. Adoption is **not** turning on strict / `workflow` gating.
|
|
17
17
|
- **Reversible.** `vigiles eject <file>` hands the file back as plain hand-owned markdown anytime — it's never a one-way door. Tell the user this.
|
|
@@ -35,7 +35,7 @@ npm install -D vigiles
|
|
|
35
35
|
Identify these sections in the markdown:
|
|
36
36
|
|
|
37
37
|
- **Commands** — lines like `` `npm run build` — description `` or ``- `command` — description``
|
|
38
|
-
- **Key
|
|
38
|
+
- **A file map ("Key Files")** — lines like `` `src/foo.ts` — description `` listing important files. Never becomes `keyFiles` (deprecated); see the guideline under Step 3
|
|
39
39
|
- **Rules** — `###` headings with `**Enforced by:**` or `**Guidance only**` annotations
|
|
40
40
|
- **Prose sections** — everything else (positioning, architecture, principles, etc.)
|
|
41
41
|
|
|
@@ -66,15 +66,9 @@ export default claude({
|
|
|
66
66
|
// Prose sections here
|
|
67
67
|
},
|
|
68
68
|
|
|
69
|
-
keyFiles
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// summary: how the file works belongs in its own header comment, which is
|
|
73
|
-
// read when someone opens it. This file is loaded on every request, so a
|
|
74
|
-
// paragraph here is paid for every turn. Prune a stale neighbour whenever
|
|
75
|
-
// you add one; `vigiles audit` prints the running total as
|
|
76
|
-
// `Always-loaded instructions`.
|
|
77
|
-
},
|
|
69
|
+
// No `keyFiles`: the field is deprecated (removed next major). A "Key Files"
|
|
70
|
+
// list in the original file is NOT carried over as a map — see the
|
|
71
|
+
// guideline below.
|
|
78
72
|
|
|
79
73
|
commands: {
|
|
80
74
|
// Commands here
|
|
@@ -89,6 +83,7 @@ export default claude({
|
|
|
89
83
|
**Important guidelines:**
|
|
90
84
|
|
|
91
85
|
- Use `file()` refs in sections where file paths appear in backticks — this enables stale reference detection
|
|
86
|
+
- 🔴 **Never emit `keyFiles`.** The field is deprecated and removed in the next major (`vigiles lint` warns as `deprecated-key-files`). For a "Key Files" / file-map section in the original, apply the migration recipe (`docs/rules/deprecated-key-files.md` in the vigiles repository) and show the user, per entry, where it goes — the first that fits: (1) the file's header, the docs or the path already say it (or the path no longer exists) → delete it; (2) a fact about that one file → that file's header comment; (3) a rule for working in one folder → that folder's nested `CLAUDE.md` (its own `<folder>/CLAUDE.md.spec.ts`); (4) nothing else would lead an agent to the file → a one-line `file()` pointer in the section where the decision that needs it is written. Where each entry goes is the user's call; that the map does not become `keyFiles` is not. Until they decide, carry the list over as a plain prose section so adoption stays faithful
|
|
92
87
|
- Use `cmd()` refs for any `npm run` commands mentioned in sections
|
|
93
88
|
- Convert `**Enforced by:** \`code-review\``rules to`guidance()` — code review is not a mechanical enforcement
|
|
94
89
|
- For rules with no annotation, add a `// TODO: classify as enforce() or guidance()` comment
|
|
@@ -105,7 +100,7 @@ npm run build
|
|
|
105
100
|
npx vigiles compile CLAUDE.md.spec.ts
|
|
106
101
|
```
|
|
107
102
|
|
|
108
|
-
Compare the compiled output against the original file. Key differences are expected (formatting, section ordering), but all rules, commands,
|
|
103
|
+
Compare the compiled output against the original file. Key differences are expected (formatting, section ordering), but all rules, commands, and prose content should be preserved (a file map is the exception — see the `keyFiles` guideline above).
|
|
109
104
|
|
|
110
105
|
### Step 5: Present the Result
|
|
111
106
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: edit-spec
|
|
3
3
|
allowed-tools: Read, Edit, Write, Glob, Grep, Bash
|
|
4
|
-
description: Edit a vigiles .spec.ts to change a compiled instruction file (CLAUDE.md / AGENTS.md) — add, modify, or remove a rule, section, command, or key file. Use whenever you need to change a CLAUDE.md/AGENTS.md that carries a vigiles hash (edit the spec, never the artifact), including adding a new enforce()/check()/guidance() rule.
|
|
4
|
+
description: Edit a vigiles .spec.ts to change a compiled instruction file (CLAUDE.md / AGENTS.md) — add, modify, or remove a rule, section, command, or file pointer (including a request to add a "key file" — the keyFiles field is deprecated). Use whenever you need to change a CLAUDE.md/AGENTS.md that carries a vigiles hash (edit the spec, never the artifact), including adding a new enforce()/check()/guidance() rule.
|
|
5
5
|
argument-hint: <what to change — e.g., "add a rule about error handling" or "update the testing section">
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ $ARGUMENTS — What the user wants to change. Examples:
|
|
|
13
13
|
|
|
14
14
|
- "add a rule about always using the custom logger"
|
|
15
15
|
- "update the architecture section"
|
|
16
|
-
- "
|
|
16
|
+
- "point the auth rule at src/services/auth.ts"
|
|
17
17
|
- "add npm run lint to commands"
|
|
18
18
|
- "change the testing guidance"
|
|
19
19
|
|
|
@@ -49,10 +49,7 @@ export default claude({
|
|
|
49
49
|
architecture: "How the codebase is structured...",
|
|
50
50
|
},
|
|
51
51
|
|
|
52
|
-
//
|
|
53
|
-
keyFiles: {
|
|
54
|
-
"src/index.ts": "Main entry point",
|
|
55
|
-
},
|
|
52
|
+
// (No `keyFiles` — deprecated; see "A pointer to a file" in Step 3.)
|
|
56
53
|
|
|
57
54
|
// Commands verified against package.json
|
|
58
55
|
commands: {
|
|
@@ -106,24 +103,34 @@ Based on what the user asked for:
|
|
|
106
103
|
- Edit the string in `sections`. Sections are plain strings or tagged template literals with `file()`, `cmd()`, `ref()` for verified references
|
|
107
104
|
- Do NOT add `#` or `##` headers inside sections — they break the document structure
|
|
108
105
|
|
|
109
|
-
**Adding a
|
|
110
|
-
|
|
111
|
-
- Add to `
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
file
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
**Adding a command:**
|
|
107
|
+
|
|
108
|
+
- Add to `commands`. The compiler verifies it against `package.json` scripts.
|
|
109
|
+
- Keep the description to one line (aim for 120 characters, never exceed ~200):
|
|
110
|
+
the instruction file is loaded on EVERY request.
|
|
111
|
+
|
|
112
|
+
**A pointer to a file (what used to be a "key file"):**
|
|
113
|
+
|
|
114
|
+
- 🔴 **Never add a `keyFiles` entry — not one, not even to a spec that already
|
|
115
|
+
has the field.** It is deprecated (`vigiles lint` reports it as
|
|
116
|
+
`deprecated-key-files`) and removed in the next major: it compiles a file
|
|
117
|
+
map into the instruction file loaded on every request, and the agent finds
|
|
118
|
+
files itself.
|
|
119
|
+
- Asked to add a file? Place it by the first of these that fits, and say why:
|
|
120
|
+
1. the file's own header, the docs or the path already say it → add nothing;
|
|
121
|
+
2. a fact about that one file → write it in **the file's header comment**;
|
|
122
|
+
3. a rule an agent must follow while working in one folder → that folder's
|
|
123
|
+
**nested `CLAUDE.md`** (its own `<folder>/CLAUDE.md.spec.ts`, compiled);
|
|
124
|
+
4. only if nothing else would lead an agent there → a **one-line pointer**,
|
|
125
|
+
`${file("src/services/auth.ts")}` inside a `prose` section where the
|
|
126
|
+
decision that needs it is written — compile verifies it exists, exactly
|
|
127
|
+
as it verified a `keyFiles` path. (`guidance()` takes a plain string, so a
|
|
128
|
+
path typed there is not verified.)
|
|
129
|
+
- **Opened a spec that still has `keyFiles`?** Propose removing it, in the same
|
|
130
|
+
reply: go through the entries with the same four steps (the full recipe is
|
|
131
|
+
`docs/rules/deprecated-key-files.md` in the vigiles repository; a path that
|
|
132
|
+
no longer exists is deleted) and show, per entry, where it goes and why.
|
|
133
|
+
Where each entry goes is the user's call; apply it once they confirm.
|
|
127
134
|
|
|
128
135
|
### Step 4: Compile
|
|
129
136
|
|
|
@@ -135,7 +142,7 @@ npx vigiles compile
|
|
|
135
142
|
|
|
136
143
|
This regenerates the compiled instruction file(s). Review the output for any errors:
|
|
137
144
|
|
|
138
|
-
- `stale-file` — a
|
|
145
|
+
- `stale-file` — a `file()` (or deprecated `keyFiles`) path doesn't exist
|
|
139
146
|
- `stale-command` — a command isn't in package.json
|
|
140
147
|
- `invalid-rule` — a linter rule doesn't exist or is disabled
|
|
141
148
|
- `section-has-header` — a section contains `#` headers (break into separate named sections)
|