vigiles 2.6.0 → 4.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +11 -2
- package/README.md +76 -129
- package/action.yml +144 -8
- package/dist/action-gate.d.ts +1 -1
- package/dist/action-gate.js +1 -1
- package/dist/adapter-conformance.d.ts +30 -0
- package/dist/adapter-conformance.js +153 -0
- package/dist/adapter-registry.d.ts +42 -0
- package/dist/adapter-registry.js +55 -0
- package/dist/adapter.d.ts +26 -0
- package/dist/adapter.js +16 -0
- package/dist/adapters/claude-code/adapter.d.ts +3 -0
- package/dist/adapters/claude-code/adapter.js +46 -0
- package/dist/{agent-result.d.ts → adapters/claude-code/agent-result.d.ts} +1 -1
- package/dist/adapters/claude-code/dialect.d.ts +13 -0
- package/dist/adapters/claude-code/dialect.js +51 -0
- package/dist/adapters/claude-code/egress-entry.d.ts +2 -0
- package/dist/adapters/claude-code/egress-entry.js +115 -0
- package/dist/adapters/claude-code/egress.d.ts +114 -0
- package/dist/adapters/claude-code/egress.js +276 -0
- package/dist/{eval-cache.d.ts → adapters/claude-code/eval-cache.d.ts} +1 -1
- package/dist/{eval-cache.js → adapters/claude-code/eval-cache.js} +1 -1
- package/dist/{eval.d.ts → adapters/claude-code/eval.d.ts} +28 -4
- package/dist/{eval.js → adapters/claude-code/eval.js} +61 -25
- package/dist/{harness-test.d.ts → adapters/claude-code/harness-test.d.ts} +33 -37
- package/dist/{harness-test.js → adapters/claude-code/harness-test.js} +124 -43
- package/dist/adapters/claude-code/hook-protocol.d.ts +10 -0
- package/dist/adapters/claude-code/hook-protocol.js +10 -0
- package/dist/adapters/claude-code/layout.d.ts +8 -0
- package/dist/adapters/claude-code/layout.js +18 -0
- package/dist/{mock-model.d.ts → adapters/claude-code/mock-model.d.ts} +2 -24
- package/dist/adapters/claude-code/model-mock.d.ts +11 -0
- package/dist/adapters/claude-code/model-mock.js +10 -0
- package/dist/adapters/claude-code/plugin-loader.d.ts +25 -0
- package/dist/adapters/claude-code/plugin-loader.js +19 -0
- package/dist/{run-hook.d.ts → adapters/claude-code/run-hook.d.ts} +50 -3
- package/dist/{run-hook.js → adapters/claude-code/run-hook.js} +178 -18
- package/dist/adapters/claude-code/run-scripts.d.ts +52 -0
- package/dist/adapters/claude-code/run-scripts.js +150 -0
- package/dist/adapters/claude-code/runtime.d.ts +16 -0
- package/dist/adapters/claude-code/runtime.js +39 -0
- package/dist/{sandbox.d.ts → adapters/claude-code/sandbox.d.ts} +10 -0
- package/dist/{sandbox.js → adapters/claude-code/sandbox.js} +5 -3
- package/dist/{skill-driver.d.ts → adapters/claude-code/skill-driver.d.ts} +1 -1
- package/dist/adapters/codex/adapter.d.ts +3 -0
- package/dist/adapters/codex/adapter.js +49 -0
- package/dist/adapters/codex/dialect.d.ts +10 -0
- package/dist/adapters/codex/dialect.js +30 -0
- package/dist/adapters/codex/driver.d.ts +20 -0
- package/dist/adapters/codex/driver.js +89 -0
- package/dist/adapters/codex/hook-protocol.d.ts +10 -0
- package/dist/adapters/codex/hook-protocol.js +18 -0
- package/dist/adapters/codex/layout.d.ts +16 -0
- package/dist/adapters/codex/layout.js +18 -0
- package/dist/adapters/codex/mock-model.d.ts +52 -0
- package/dist/adapters/codex/mock-model.js +210 -0
- package/dist/adapters/codex/model-mock.d.ts +11 -0
- package/dist/adapters/codex/model-mock.js +10 -0
- package/dist/adapters/codex/runtime.d.ts +38 -0
- package/dist/adapters/codex/runtime.js +62 -0
- package/dist/adapters/opencode/adapter.d.ts +3 -0
- package/dist/adapters/opencode/adapter.js +48 -0
- package/dist/adapters/opencode/dialect.d.ts +10 -0
- package/dist/adapters/opencode/dialect.js +36 -0
- package/dist/adapters/opencode/layout.d.ts +9 -0
- package/dist/adapters/opencode/layout.js +25 -0
- package/dist/adapters/opencode/model-mock.d.ts +10 -0
- package/dist/adapters/opencode/model-mock.js +10 -0
- package/dist/adapters/opencode/runtime.d.ts +9 -0
- package/dist/adapters/opencode/runtime.js +21 -0
- package/dist/claude-code.d.ts +8 -2
- package/dist/claude-code.js +8 -2
- package/dist/cli-flags.d.ts +22 -0
- package/dist/cli-flags.js +38 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +670 -245
- package/dist/codex.d.ts +20 -0
- package/dist/codex.js +36 -0
- package/dist/community-skills.d.ts +1 -1
- package/dist/community-skills.js +2 -2
- package/dist/core/adapter.d.ts +88 -0
- package/dist/core/adapter.js +3 -0
- package/dist/{compile.d.ts → core/compile.d.ts} +11 -2
- package/dist/{compile.js → core/compile.js} +68 -53
- package/dist/core/compose.d.ts +79 -0
- package/dist/core/compose.js +145 -0
- package/dist/core/dialect.d.ts +51 -0
- package/dist/core/dialect.js +3 -0
- package/dist/core/harness-driver.d.ts +134 -0
- package/dist/core/harness-driver.js +3 -0
- package/dist/core/hook-protocol.d.ts +28 -0
- package/dist/core/hook-protocol.js +3 -0
- package/dist/core/layout.d.ts +43 -0
- package/dist/core/layout.js +3 -0
- package/dist/core/model-mock.d.ts +27 -0
- package/dist/core/model-mock.js +3 -0
- package/dist/core/refs.d.ts +62 -0
- package/dist/{refs.js → core/refs.js} +49 -23
- package/dist/core/runtime.d.ts +38 -0
- package/dist/core/runtime.js +3 -0
- package/dist/{types.d.ts → core/types.d.ts} +29 -0
- package/dist/{validate.d.ts → core/validate.d.ts} +1 -1
- package/dist/{validate.js → core/validate.js} +41 -4
- package/dist/e2e.d.ts +19 -0
- package/dist/e2e.js +39 -0
- package/dist/harness-assert.d.ts +29 -14
- package/dist/harness-assert.js +37 -10
- package/dist/integration.d.ts +16 -0
- package/dist/integration.js +32 -0
- package/dist/leaderboard.d.ts +33 -0
- package/dist/leaderboard.js +107 -0
- package/dist/linting.d.ts +2 -2
- package/dist/linting.js +2 -2
- package/dist/plugin-loader.d.ts +6 -3
- package/dist/plugin-loader.js +101 -49
- package/dist/scan.d.ts +49 -0
- package/dist/scan.js +177 -0
- package/dist/setup-plan.d.ts +91 -0
- package/dist/setup-plan.js +160 -0
- package/dist/skill-test.d.ts +1 -1
- package/dist/skill-test.js +1 -1
- package/dist/test-coverage.d.ts +71 -0
- package/dist/test-coverage.js +228 -0
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +3 -3
- package/dist/unit.d.ts +17 -0
- package/dist/unit.js +36 -0
- package/hooks/refs-nudge.sh +24 -0
- package/package.json +30 -15
- package/skills/edit-spec/SKILL.md +131 -0
- package/skills/generate-rule/SKILL.md +64 -0
- package/skills/linter-docs/clippy.md +241 -0
- package/skills/linter-docs/eslint.md +384 -0
- package/skills/linter-docs/pylint.md +288 -0
- package/skills/linter-docs/rubocop.md +277 -0
- package/skills/linter-docs/ruff.md +187 -0
- package/skills/linter-docs/stylelint.md +247 -0
- package/skills/migrate-to-spec/SKILL.md +126 -0
- package/skills/strengthen/SKILL.md +168 -0
- package/skills/test-harness/SKILL.md +157 -0
- package/dist/action.d.ts +0 -7
- package/dist/action.js +0 -180
- package/dist/refs.d.ts +0 -44
- package/dist/run-scripts.d.ts +0 -20
- package/dist/run-scripts.js +0 -70
- /package/dist/{agent-result.js → adapters/claude-code/agent-result.js} +0 -0
- /package/dist/{agent-runtime.d.ts → adapters/claude-code/agent-runtime.d.ts} +0 -0
- /package/dist/{agent-runtime.js → adapters/claude-code/agent-runtime.js} +0 -0
- /package/dist/{egress-proxy.d.ts → adapters/claude-code/egress-proxy.d.ts} +0 -0
- /package/dist/{egress-proxy.js → adapters/claude-code/egress-proxy.js} +0 -0
- /package/dist/{eval-baseline.d.ts → adapters/claude-code/eval-baseline.d.ts} +0 -0
- /package/dist/{eval-baseline.js → adapters/claude-code/eval-baseline.js} +0 -0
- /package/dist/{judge.d.ts → adapters/claude-code/judge.d.ts} +0 -0
- /package/dist/{judge.js → adapters/claude-code/judge.js} +0 -0
- /package/dist/{mock-entry.d.ts → adapters/claude-code/mock-entry.d.ts} +0 -0
- /package/dist/{mock-entry.js → adapters/claude-code/mock-entry.js} +0 -0
- /package/dist/{mock-model.js → adapters/claude-code/mock-model.js} +0 -0
- /package/dist/{skill-driver.js → adapters/claude-code/skill-driver.js} +0 -0
- /package/dist/{skill-runtime.d.ts → adapters/claude-code/skill-runtime.d.ts} +0 -0
- /package/dist/{skill-runtime.js → adapters/claude-code/skill-runtime.js} +0 -0
- /package/dist/{stats.d.ts → adapters/claude-code/stats.d.ts} +0 -0
- /package/dist/{stats.js → adapters/claude-code/stats.js} +0 -0
- /package/dist/{compile-generator.d.ts → core/compile-generator.d.ts} +0 -0
- /package/dist/{compile-generator.js → core/compile-generator.js} +0 -0
- /package/dist/{coverage.d.ts → core/coverage.d.ts} +0 -0
- /package/dist/{coverage.js → core/coverage.js} +0 -0
- /package/dist/{doc-refs.d.ts → core/doc-refs.d.ts} +0 -0
- /package/dist/{doc-refs.js → core/doc-refs.js} +0 -0
- /package/dist/{evolve.d.ts → core/evolve.d.ts} +0 -0
- /package/dist/{evolve.js → core/evolve.js} +0 -0
- /package/dist/{frontmatter.d.ts → core/frontmatter.d.ts} +0 -0
- /package/dist/{frontmatter.js → core/frontmatter.js} +0 -0
- /package/dist/{generate-schema.d.ts → core/generate-schema.d.ts} +0 -0
- /package/dist/{generate-schema.js → core/generate-schema.js} +0 -0
- /package/dist/{generate-types.d.ts → core/generate-types.d.ts} +0 -0
- /package/dist/{generate-types.js → core/generate-types.js} +0 -0
- /package/dist/{hash.d.ts → core/hash.d.ts} +0 -0
- /package/dist/{hash.js → core/hash.js} +0 -0
- /package/dist/{inline.d.ts → core/inline.d.ts} +0 -0
- /package/dist/{inline.js → core/inline.js} +0 -0
- /package/dist/{integrity.d.ts → core/integrity.d.ts} +0 -0
- /package/dist/{integrity.js → core/integrity.js} +0 -0
- /package/dist/{linters.d.ts → core/linters.d.ts} +0 -0
- /package/dist/{linters.js → core/linters.js} +0 -0
- /package/dist/{mcp.d.ts → core/mcp.d.ts} +0 -0
- /package/dist/{mcp.js → core/mcp.js} +0 -0
- /package/dist/{orphans.d.ts → core/orphans.d.ts} +0 -0
- /package/dist/{orphans.js → core/orphans.js} +0 -0
- /package/dist/{proofs.d.ts → core/proofs.d.ts} +0 -0
- /package/dist/{proofs.js → core/proofs.js} +0 -0
- /package/dist/{session.d.ts → core/session.d.ts} +0 -0
- /package/dist/{session.js → core/session.js} +0 -0
- /package/dist/{sidecar.d.ts → core/sidecar.d.ts} +0 -0
- /package/dist/{sidecar.js → core/sidecar.js} +0 -0
- /package/dist/{spec.d.ts → core/spec.d.ts} +0 -0
- /package/dist/{spec.js → core/spec.js} +0 -0
- /package/dist/{symbols.d.ts → core/symbols.d.ts} +0 -0
- /package/dist/{symbols.js → core/symbols.js} +0 -0
- /package/dist/{test-utils.d.ts → core/test-utils.d.ts} +0 -0
- /package/dist/{test-utils.js → core/test-utils.js} +0 -0
- /package/dist/{types.js → core/types.js} +0 -0
- /package/{.claude-plugin/hooks → hooks}/post-edit.sh +0 -0
- /package/{.claude-plugin/hooks → hooks}/pre-edit.sh +0 -0
- /package/{.claude-plugin/hooks → hooks}/session-start.sh +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Stylelint — Reference
|
|
2
|
+
|
|
3
|
+
Shared linter reference for vigiles skills. Used by `strengthen` (find existing rules) and `pr-to-lint-rule` (write custom rules).
|
|
4
|
+
|
|
5
|
+
## Check Existing Plugins First
|
|
6
|
+
|
|
7
|
+
Before writing a custom rule, search these packages — the pattern may already be covered:
|
|
8
|
+
|
|
9
|
+
| Plugin | Scope | Key rules |
|
|
10
|
+
| ------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `stylelint-config-standard` | Standard CSS conventions | Extends `stylelint-config-recommended`, adds `declaration-block-no-redundant-longhand-properties`, `shorthand-property-no-redundant-values` |
|
|
12
|
+
| `stylelint-config-recommended` | Error prevention | `no-descending-specificity`, `no-duplicate-selectors`, `declaration-block-no-duplicate-properties` |
|
|
13
|
+
| `stylelint-order` | Property ordering | `order/properties-order`, `order/properties-alphabetical-order` — configurable sort orders |
|
|
14
|
+
| `stylelint-scss` | SCSS syntax | `scss/no-duplicate-mixins`, `scss/no-unused-private-members`, `scss/at-rule-no-unknown`, `scss/dollar-variable-pattern` |
|
|
15
|
+
| `stylelint-config-css-modules` | CSS Modules | Adjusts rules for `:global`, `:local`, `composes` syntax |
|
|
16
|
+
| `stylelint-config-tailwindcss` | Tailwind CSS | Allows Tailwind directives (`@tailwind`, `@apply`, `@screen`) |
|
|
17
|
+
| `stylelint-no-unsupported-browser-features` | Browser compat | Flags CSS features not supported by your browserslist targets |
|
|
18
|
+
| `stylelint-declaration-strict-value` | Value enforcement | Require variables/functions for specific properties (colors, fonts, z-index) |
|
|
19
|
+
| `stylelint-config-clean-order` | Property order | Opinionated property ordering (positioning → box model → typography → visual → misc) |
|
|
20
|
+
| `stylelint-config-prettier` | Prettier compat | Disables rules that conflict with Prettier (deprecated in Stylelint v15+) |
|
|
21
|
+
| `stylelint-a11y` | Accessibility | `a11y/no-outline-none`, `a11y/no-text-size-adjust`, `a11y/media-prefers-reduced-motion` |
|
|
22
|
+
|
|
23
|
+
**Tip:** Stylelint v15+ removed all stylistic rules (spacing, formatting). Use Prettier for formatting, Stylelint for correctness.
|
|
24
|
+
|
|
25
|
+
## Rule Anatomy
|
|
26
|
+
|
|
27
|
+
Every Stylelint rule is a function that receives options and returns a checker:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
const stylelint = require("stylelint");
|
|
31
|
+
|
|
32
|
+
const ruleName = "plugin/no-important";
|
|
33
|
+
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
34
|
+
rejected: "Unexpected !important — use utility classes instead.",
|
|
35
|
+
});
|
|
36
|
+
const meta = { url: "https://example.com/rules/no-important" };
|
|
37
|
+
|
|
38
|
+
/** @type {import('stylelint').Rule} */
|
|
39
|
+
const ruleFunction = (primary, secondary, context) => {
|
|
40
|
+
return (root, result) => {
|
|
41
|
+
const validOptions = stylelint.utils.validateOptions(result, ruleName, {
|
|
42
|
+
actual: primary,
|
|
43
|
+
possible: [true],
|
|
44
|
+
});
|
|
45
|
+
if (!validOptions) return;
|
|
46
|
+
|
|
47
|
+
root.walkDecls((decl) => {
|
|
48
|
+
if (decl.important) {
|
|
49
|
+
stylelint.utils.report({
|
|
50
|
+
message: messages.rejected,
|
|
51
|
+
node: decl,
|
|
52
|
+
result,
|
|
53
|
+
ruleName,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
ruleFunction.ruleName = ruleName;
|
|
61
|
+
ruleFunction.messages = messages;
|
|
62
|
+
ruleFunction.meta = meta;
|
|
63
|
+
|
|
64
|
+
module.exports = stylelint.createPlugin(ruleName, ruleFunction);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Key concepts
|
|
68
|
+
|
|
69
|
+
| Concept | Purpose | Notes |
|
|
70
|
+
| ----------------------------------- | ------------------------------------------ | --------------------------------------------------------- |
|
|
71
|
+
| `primary` | First option (usually `true` or a pattern) | What the user passes in config |
|
|
72
|
+
| `secondary` | Second option (usually an object) | Additional configuration |
|
|
73
|
+
| `context` | Execution context | Contains `fix` boolean for auto-fix mode |
|
|
74
|
+
| `root` | PostCSS AST root node | Entry point for walking the CSS tree |
|
|
75
|
+
| `result` | Results accumulator | Pass to `stylelint.utils.report()` |
|
|
76
|
+
| `stylelint.utils.report()` | Report a violation | Canonical way to report — handles severity, ignores, etc. |
|
|
77
|
+
| `stylelint.utils.validateOptions()` | Validate rule config | Returns false if config is invalid |
|
|
78
|
+
|
|
79
|
+
### PostCSS AST node types
|
|
80
|
+
|
|
81
|
+
| Node type | What it represents | Walker method | Example |
|
|
82
|
+
| ------------- | ----------------------- | --------------------- | --------------------------- |
|
|
83
|
+
| `Root` | Entire stylesheet | — | Top-level container |
|
|
84
|
+
| `Rule` | Selector + declarations | `root.walkRules()` | `.button { color: red }` |
|
|
85
|
+
| `Declaration` | Property: value pair | `root.walkDecls()` | `color: red` |
|
|
86
|
+
| `AtRule` | `@` rule | `root.walkAtRules()` | `@media (min-width: 768px)` |
|
|
87
|
+
| `Comment` | CSS comment | `root.walkComments()` | `/* comment */` |
|
|
88
|
+
|
|
89
|
+
Properties on `Declaration`: `decl.prop` (property name), `decl.value` (value string), `decl.important` (boolean).
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
### `.stylelintrc.json`
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"extends": ["stylelint-config-standard"],
|
|
98
|
+
"plugins": ["stylelint-order"],
|
|
99
|
+
"rules": {
|
|
100
|
+
"declaration-no-important": true,
|
|
101
|
+
"selector-max-specificity": "0,3,0",
|
|
102
|
+
"order/properties-alphabetical-order": true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `stylelint.config.js` (flat config)
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
module.exports = {
|
|
111
|
+
extends: ["stylelint-config-standard"],
|
|
112
|
+
rules: {
|
|
113
|
+
"declaration-no-important": true,
|
|
114
|
+
},
|
|
115
|
+
overrides: [
|
|
116
|
+
{
|
|
117
|
+
files: ["**/*.scss"],
|
|
118
|
+
extends: ["stylelint-config-standard-scss"],
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Key config concepts
|
|
125
|
+
|
|
126
|
+
- **`extends`** — inherit from shared configs (order matters — later overrides earlier)
|
|
127
|
+
- **`plugins`** — load additional rule packages
|
|
128
|
+
- **`rules`** — enable/disable/configure individual rules (`true`, `null`, or `[value, options]`)
|
|
129
|
+
- **`overrides`** — per-file rule configuration (like ESLint overrides)
|
|
130
|
+
|
|
131
|
+
## Testing Rules
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
const { lint } = require("stylelint");
|
|
135
|
+
|
|
136
|
+
async function testRule() {
|
|
137
|
+
const result = await lint({
|
|
138
|
+
code: "a { color: pink !important; }",
|
|
139
|
+
config: {
|
|
140
|
+
plugins: ["./plugin-no-important.js"],
|
|
141
|
+
rules: { "plugin/no-important": true },
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log(result.results[0].warnings);
|
|
146
|
+
// [{ rule: "plugin/no-important", text: "Unexpected !important...", line: 1, column: 19 }]
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
For plugin development, use `jest-preset-stylelint` or test via `lint()` directly.
|
|
151
|
+
|
|
152
|
+
**Testing best practices:**
|
|
153
|
+
|
|
154
|
+
1. **Test with `lint()` API** — canonical method, works with any test runner
|
|
155
|
+
2. **Test valid and invalid cases** — ensure no false positives
|
|
156
|
+
3. **Test with SCSS/Less** if the plugin should support preprocessor syntax
|
|
157
|
+
4. **Test `overrides`** — if the rule has options, test each configuration
|
|
158
|
+
|
|
159
|
+
### vigiles enforce() reference
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
enforce("stylelint/declaration-no-important", "Use utility classes instead.");
|
|
163
|
+
enforce(
|
|
164
|
+
"stylelint/selector-max-specificity",
|
|
165
|
+
"Keep specificity low for maintainability.",
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
vigiles loads Stylelint config via `createLinter` + `getConfigForFile`, checks if the rule value is not `null`.
|
|
170
|
+
|
|
171
|
+
## Edge Cases and Gotchas
|
|
172
|
+
|
|
173
|
+
### CSS-in-JS
|
|
174
|
+
|
|
175
|
+
Stylelint supports CSS-in-JS via custom syntaxes:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"overrides": [
|
|
180
|
+
{
|
|
181
|
+
"files": ["**/*.{js,jsx,ts,tsx}"],
|
|
182
|
+
"customSyntax": "@stylelint/postcss-css-in-js"
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Note: `@stylelint/postcss-css-in-js` is deprecated as of Stylelint v15. For styled-components / emotion, consider `postcss-styled-syntax` or lint extracted CSS instead.
|
|
189
|
+
|
|
190
|
+
### SCSS / Less
|
|
191
|
+
|
|
192
|
+
Use dedicated configs:
|
|
193
|
+
|
|
194
|
+
- SCSS: `stylelint-config-standard-scss` (includes `stylelint-scss` plugin)
|
|
195
|
+
- Less: `postcss-less` as `customSyntax`
|
|
196
|
+
|
|
197
|
+
SCSS nesting (`&-modifier`) and mixins may trigger false positives in standard rules. The SCSS config handles this.
|
|
198
|
+
|
|
199
|
+
### Prettier conflicts (v15+)
|
|
200
|
+
|
|
201
|
+
Stylelint v15 removed all stylistic rules. If upgrading from v14:
|
|
202
|
+
|
|
203
|
+
- Remove `stylelint-config-prettier` (no longer needed)
|
|
204
|
+
- Remove manual disables of formatting rules (`indentation`, `string-quotes`, etc.)
|
|
205
|
+
- Stylelint now handles correctness only; Prettier handles formatting
|
|
206
|
+
|
|
207
|
+
### Property order plugins
|
|
208
|
+
|
|
209
|
+
`stylelint-order` and `stylelint-config-clean-order` can conflict. Use one ordering strategy:
|
|
210
|
+
|
|
211
|
+
- Alphabetical: `order/properties-alphabetical-order`
|
|
212
|
+
- Grouped: `order/properties-order` with a custom group list
|
|
213
|
+
- Clean order: extend `stylelint-config-clean-order` (opinionated groups)
|
|
214
|
+
|
|
215
|
+
### `extends` order matters
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"extends": ["stylelint-config-standard", "stylelint-config-prettier"]
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Later configs override earlier ones. Put base configs first, overrides last.
|
|
224
|
+
|
|
225
|
+
### Monorepo considerations
|
|
226
|
+
|
|
227
|
+
- Stylelint resolves config from the file being linted, walking up directories
|
|
228
|
+
- Each package can have its own `.stylelintrc.json`
|
|
229
|
+
- vigiles checks Stylelint config via `createLinter({ cwd: basePath })` — in a monorepo, run from each package root
|
|
230
|
+
|
|
231
|
+
## Mapping PR Feedback to Rule Strategy
|
|
232
|
+
|
|
233
|
+
| PR comment pattern | Best approach |
|
|
234
|
+
| ---------------------------- | --------------------------------------------------------------------------------- |
|
|
235
|
+
| "Don't use !important" | `stylelint/declaration-no-important` — already exists |
|
|
236
|
+
| "Keep specificity low" | `stylelint/selector-max-specificity` with threshold |
|
|
237
|
+
| "Sort properties" | `stylelint-order` plugin — `order/properties-alphabetical-order` or custom groups |
|
|
238
|
+
| "Don't use ID selectors" | `stylelint/selector-max-id` — already exists |
|
|
239
|
+
| "Use variables for colors" | `stylelint-declaration-strict-value` plugin |
|
|
240
|
+
| "No vendor prefixes" | `stylelint/property-no-vendor-prefix`, `value-no-vendor-prefix` |
|
|
241
|
+
| "Don't nest too deep" | `stylelint/selector-max-compound-selectors` with threshold |
|
|
242
|
+
| "Use modern CSS" | `stylelint/declaration-property-value-no-unknown` + browserslist |
|
|
243
|
+
| "Remove empty blocks" | `stylelint/block-no-empty` — already exists |
|
|
244
|
+
| "Don't duplicate properties" | `stylelint/declaration-block-no-duplicate-properties` — already exists |
|
|
245
|
+
| "Use shorthand" | `stylelint/declaration-block-no-redundant-longhand-properties` — already exists |
|
|
246
|
+
| "Font naming convention" | `stylelint/font-family-name-quotes` — already exists |
|
|
247
|
+
| "No unknown @rules" | `stylelint/at-rule-no-unknown` (or `scss/at-rule-no-unknown` for SCSS) |
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-to-spec
|
|
3
|
+
description: Convert an existing hand-written CLAUDE.md into a typed .spec.ts file for incremental adoption
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: <path to CLAUDE.md, defaults to CLAUDE.md>
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Convert an existing hand-written CLAUDE.md (or AGENTS.md) into a typed `CLAUDE.md.spec.ts` file. This is the incremental adoption path — you keep your existing instruction file as the starting point and get type safety going forward.
|
|
9
|
+
|
|
10
|
+
> **Don't need full TypeScript?** A typed spec is the deepest commitment level. If the user only wants verified rules without a build step, point them at markdown mode first: inline `<!-- vigiles:enforce ... -->` comments (Level 0) or a `vigiles:` YAML frontmatter block with `vigiles generate-schema` for editor autocomplete (Level 1). Both are verified by `vigiles audit` with the same engine as a spec. See `docs/markdown-mode.md`. Migrate to a spec only when they want compiler-grade guarantees.
|
|
11
|
+
|
|
12
|
+
## Instructions
|
|
13
|
+
|
|
14
|
+
### Step 1: Read the Existing File
|
|
15
|
+
|
|
16
|
+
Read the target instruction file (default: `CLAUDE.md` in the repo root). If the user specified a path, use that.
|
|
17
|
+
|
|
18
|
+
Also check if vigiles is installed: look for `vigiles` in `package.json` devDependencies. If not, suggest:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -D vigiles
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Step 2: Parse the Structure
|
|
25
|
+
|
|
26
|
+
Identify these sections in the markdown:
|
|
27
|
+
|
|
28
|
+
- **Commands** — lines like `` `npm run build` — description `` or ``- `command` — description``
|
|
29
|
+
- **Key files** — lines like `` `src/foo.ts` — description `` listing important files
|
|
30
|
+
- **Rules** — `###` headings with `**Enforced by:**` or `**Guidance only**` annotations
|
|
31
|
+
- **Prose sections** — everything else (positioning, architecture, principles, etc.)
|
|
32
|
+
|
|
33
|
+
For each rule, classify it:
|
|
34
|
+
|
|
35
|
+
- Has `**Enforced by:** \`linter/rule\``→`enforce("linter/rule", "why")`
|
|
36
|
+
- Has `**Enforced by:** \`code-review\``or similar non-linter →`guidance("...")`
|
|
37
|
+
- Has `**Guidance only**` → `guidance("...")`
|
|
38
|
+
- Has no annotation → mark as TODO for the user to classify
|
|
39
|
+
|
|
40
|
+
### Step 3: Generate the Spec File
|
|
41
|
+
|
|
42
|
+
Create `CLAUDE.md.spec.ts` (or the appropriate name based on the source file) with this structure:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import {
|
|
46
|
+
claude,
|
|
47
|
+
enforce,
|
|
48
|
+
guidance,
|
|
49
|
+
check,
|
|
50
|
+
every,
|
|
51
|
+
file,
|
|
52
|
+
cmd,
|
|
53
|
+
ref,
|
|
54
|
+
instructions,
|
|
55
|
+
} from "vigiles/spec";
|
|
56
|
+
|
|
57
|
+
export default claude({
|
|
58
|
+
sections: {
|
|
59
|
+
// Prose sections here
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
keyFiles: {
|
|
63
|
+
// Key files here
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
commands: {
|
|
67
|
+
// Commands here
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
rules: {
|
|
71
|
+
// Rules here
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Important guidelines:**
|
|
77
|
+
|
|
78
|
+
- Use `file()` refs in sections where file paths appear in backticks — this enables stale reference detection
|
|
79
|
+
- Use `cmd()` refs for any `npm run` commands mentioned in sections
|
|
80
|
+
- Convert `**Enforced by:** \`code-review\``rules to`guidance()` — code review is not a mechanical enforcement
|
|
81
|
+
- For rules with no annotation, add a `// TODO: classify as enforce() or guidance()` comment
|
|
82
|
+
- Keep rule IDs as kebab-case versions of the heading text
|
|
83
|
+
- Preserve the `**Why:**` text as the second argument to `enforce()` or `guidance()`
|
|
84
|
+
- If sections reference other files or skills, use `ref()` for cross-references
|
|
85
|
+
|
|
86
|
+
### Step 4: Verify the Spec Compiles
|
|
87
|
+
|
|
88
|
+
Run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm run build
|
|
92
|
+
npx vigiles compile CLAUDE.md.spec.ts
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Compare the compiled output against the original file. Key differences are expected (formatting, section ordering), but all rules, commands, key files, and prose content should be preserved.
|
|
96
|
+
|
|
97
|
+
### Step 5: Present the Result
|
|
98
|
+
|
|
99
|
+
Show the user:
|
|
100
|
+
|
|
101
|
+
1. The generated spec file
|
|
102
|
+
2. How many rules were converted (enforce vs guidance vs TODO)
|
|
103
|
+
3. How many file/cmd refs were added for stale reference detection
|
|
104
|
+
4. The command to compile: `npx vigiles compile`
|
|
105
|
+
5. The command to verify: `npx vigiles check`
|
|
106
|
+
|
|
107
|
+
Ask if they want you to write the file. If yes, also suggest adding to `.gitignore` or updating CI to run `vigiles compile` and `vigiles check`.
|
|
108
|
+
|
|
109
|
+
### Step 6: Optional — Set Up CI
|
|
110
|
+
|
|
111
|
+
If the user wants CI integration, suggest adding to their GitHub Actions workflow:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
- name: Compile specs
|
|
115
|
+
run: npx vigiles compile
|
|
116
|
+
- name: Verify integrity
|
|
117
|
+
run: npx vigiles check
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Or using the vigiles GitHub Action:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
- uses: zernie/vigiles@main
|
|
124
|
+
with:
|
|
125
|
+
command: check
|
|
126
|
+
```
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: strengthen
|
|
3
|
+
description: Upgrade guidance() rules to enforce() by finding existing linter rules that match
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Scan spec files for `guidance()` rules and suggest `enforce()` replacements backed by real linter rules.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
### Step 0: Choose Mode
|
|
12
|
+
|
|
13
|
+
Ask the user:
|
|
14
|
+
|
|
15
|
+
> **Auto or interactive?**
|
|
16
|
+
>
|
|
17
|
+
> - **Auto** — I'll apply all safe changes (direct replacements where the rule is already enabled), commit, and show you the diff. Risky changes (require config edits or plugin installs) go in a summary for you to review.
|
|
18
|
+
> - **Interactive** — I'll present each suggestion and you pick which ones to apply.
|
|
19
|
+
|
|
20
|
+
Default to interactive if the user doesn't specify.
|
|
21
|
+
|
|
22
|
+
### Step 1: Discover What's Installed
|
|
23
|
+
|
|
24
|
+
Run `npx vigiles generate-types` to get the full list of enabled linter rules in the project. Read `.vigiles/generated.d.ts` to see every rule available across all detected linters.
|
|
25
|
+
|
|
26
|
+
Note which linter prefixes appear in the generated types (e.g., `EslintRule`, `RuffRule`). You'll only need reference docs for detected linters.
|
|
27
|
+
|
|
28
|
+
### Step 2: Find All Guidance Rules
|
|
29
|
+
|
|
30
|
+
Find all `.spec.ts` files in the project (`**/*.md.spec.ts`). For each file, identify every `guidance()` rule.
|
|
31
|
+
|
|
32
|
+
### Step 3: Match Against Generated Types (Fast Path)
|
|
33
|
+
|
|
34
|
+
For each guidance rule, check if an enabled rule in `.vigiles/generated.d.ts` directly matches. This is the fast, deterministic path — no doc reading needed.
|
|
35
|
+
|
|
36
|
+
Look for:
|
|
37
|
+
|
|
38
|
+
- **Exact rule name in text** — guidance says "no-console" and `no-console` is in EslintRule
|
|
39
|
+
- **Semantic match** — guidance says "don't use console.log" and `no-console` is available
|
|
40
|
+
- **Rule description match** — guidance says "unused variables" and `no-unused-vars` or `@typescript-eslint/no-unused-vars` is available
|
|
41
|
+
|
|
42
|
+
If a match is found and the rule is in the generated types (meaning it's already enabled), this is a **direct replacement** — no config changes needed.
|
|
43
|
+
|
|
44
|
+
### Step 4: Read Linter Docs (Slow Path)
|
|
45
|
+
|
|
46
|
+
For guidance rules that didn't match in Step 3, read the linter reference docs for the project's detected linters:
|
|
47
|
+
|
|
48
|
+
- ESLint → `../linter-docs/eslint.md`
|
|
49
|
+
- Stylelint → `../linter-docs/stylelint.md`
|
|
50
|
+
- Ruff → `../linter-docs/ruff.md`
|
|
51
|
+
- Pylint → `../linter-docs/pylint.md`
|
|
52
|
+
- RuboCop → `../linter-docs/rubocop.md`
|
|
53
|
+
- Clippy → `../linter-docs/clippy.md`
|
|
54
|
+
|
|
55
|
+
**Only read docs for linters the project actually uses.** Skip docs for linters with no rules in generated types.
|
|
56
|
+
|
|
57
|
+
Check the plugin tables and decision matrices. The guidance text may describe a pattern covered by:
|
|
58
|
+
|
|
59
|
+
- A plugin rule that's installed but not enabled
|
|
60
|
+
- A plugin that's not installed yet
|
|
61
|
+
- A `no-restricted-*` config pattern (see Step 4b)
|
|
62
|
+
|
|
63
|
+
### Step 4b: `no-restricted-*` Patterns
|
|
64
|
+
|
|
65
|
+
Many guidance rules can be enforced via built-in linter config without a custom rule. This is the most common strengthen pattern — "don't do X" maps to a restriction config.
|
|
66
|
+
|
|
67
|
+
**ESLint:**
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// "Don't import from internal modules"
|
|
71
|
+
"no-restricted-imports": ["error", {
|
|
72
|
+
patterns: [{ group: ["src/internal/*"], message: "Use the public API." }]
|
|
73
|
+
}],
|
|
74
|
+
|
|
75
|
+
// "Don't call console.log"
|
|
76
|
+
"no-restricted-syntax": ["error", {
|
|
77
|
+
selector: 'CallExpression[callee.object.name="console"]',
|
|
78
|
+
message: "Use the project logger."
|
|
79
|
+
}],
|
|
80
|
+
|
|
81
|
+
// "Don't use moment.js"
|
|
82
|
+
"no-restricted-imports": ["error", {
|
|
83
|
+
paths: [{ name: "moment", message: "Use dayjs instead." }]
|
|
84
|
+
}],
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Ruff:**
|
|
88
|
+
|
|
89
|
+
```toml
|
|
90
|
+
# "Don't use os.system"
|
|
91
|
+
[tool.ruff.lint.flake8-tidy-imports.banned-api]
|
|
92
|
+
"os.system".msg = "Use subprocess.run instead."
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**RuboCop:**
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
# "Don't use puts in production" — if Rails/Output doesn't fit
|
|
99
|
+
Custom/NoPuts:
|
|
100
|
+
Enabled: true
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
When suggesting a `no-restricted-*` change:
|
|
104
|
+
|
|
105
|
+
1. Show the exact config edit needed (which file, which section)
|
|
106
|
+
2. Show the `enforce()` rule that references it
|
|
107
|
+
3. Note that this changes linter config, not just the spec
|
|
108
|
+
|
|
109
|
+
### Step 5: Present Suggestions
|
|
110
|
+
|
|
111
|
+
Group the output into tiers:
|
|
112
|
+
|
|
113
|
+
**Tier 1: Direct replacements** (rule already enabled — zero risk)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Before
|
|
117
|
+
"no-console": guidance("Use structured logger instead of console.log"),
|
|
118
|
+
// After
|
|
119
|
+
"no-console": enforce("eslint/no-console", "Use structured logger instead of console.log"),
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Tier 2: Config-backed** (rule exists but needs config options)
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// Spec change:
|
|
126
|
+
"no-moment": enforce("eslint/no-restricted-imports", "Use dayjs instead of moment."),
|
|
127
|
+
|
|
128
|
+
// Config change needed (eslint.config.mjs):
|
|
129
|
+
"no-restricted-imports": ["error", {
|
|
130
|
+
paths: [{ name: "moment", message: "Use dayjs instead." }]
|
|
131
|
+
}],
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Tier 3: Plugin install needed**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
"cognitive-complexity": guidance("Keep functions simple")
|
|
138
|
+
→ Install eslint-plugin-sonarjs, enable sonarjs/cognitive-complexity
|
|
139
|
+
→ enforce("eslint/sonarjs/cognitive-complexity", "Keep functions simple")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Tier 4: No match** (stays as guidance, or candidate for `/pr-to-lint-rule`)
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
"research-first": guidance("Google unfamiliar APIs first.")
|
|
146
|
+
→ No linter rule can enforce this. Stays as guidance.
|
|
147
|
+
→ Want me to run /pr-to-lint-rule to create a custom rule?
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Step 6: Apply Changes
|
|
151
|
+
|
|
152
|
+
**In auto mode:**
|
|
153
|
+
|
|
154
|
+
1. Apply all Tier 1 changes (edit spec files, replace `guidance()` with `enforce()`)
|
|
155
|
+
2. Run `npm run build && npx vigiles compile` to verify each change compiles
|
|
156
|
+
3. If any compilation fails, revert that specific change and report the error
|
|
157
|
+
4. Commit all successful changes
|
|
158
|
+
5. Present Tier 2-4 as a summary for the user to review
|
|
159
|
+
|
|
160
|
+
**In interactive mode:**
|
|
161
|
+
|
|
162
|
+
1. Present all tiers
|
|
163
|
+
2. Ask the user which suggestions to apply
|
|
164
|
+
3. For approved Tier 2 changes: edit the linter config, then edit the spec
|
|
165
|
+
4. Run `npm run build && npx vigiles compile` to verify
|
|
166
|
+
5. If compilation fails, report the error and revert
|
|
167
|
+
|
|
168
|
+
**For Tier 4 (no match):** Ask the user if they want to run `/pr-to-lint-rule` for any of the unmatched rules to create custom rules.
|