vigiles 2.6.0 → 3.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/plugin.json +9 -0
- package/README.md +74 -129
- package/action.yml +143 -7
- 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.js +406 -206
- 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 +51 -0
- package/dist/setup-plan.js +85 -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/audit-feedback-loop/SKILL.md +76 -0
- package/skills/edit-spec/SKILL.md +131 -0
- package/skills/enforce-rules-format/SKILL.md +71 -0
- package/skills/generate-logo/SKILL.md +103 -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/pr-to-lint-rule/SKILL.md +97 -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,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edit-spec
|
|
3
|
+
description: Edit a vigiles spec file to update instruction files (CLAUDE.md, AGENTS.md)
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: <what to change — e.g., "add a rule about error handling" or "update the testing section">
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Edit a `.spec.ts` file to update the project's instruction files. The spec is the source of truth — CLAUDE.md and AGENTS.md are compiled build artifacts that must not be edited directly.
|
|
9
|
+
|
|
10
|
+
## Arguments
|
|
11
|
+
|
|
12
|
+
$ARGUMENTS — What the user wants to change. Examples:
|
|
13
|
+
|
|
14
|
+
- "add a rule about always using the custom logger"
|
|
15
|
+
- "update the architecture section"
|
|
16
|
+
- "add src/services/auth.ts to key files"
|
|
17
|
+
- "add npm run lint to commands"
|
|
18
|
+
- "change the testing guidance"
|
|
19
|
+
|
|
20
|
+
## Instructions
|
|
21
|
+
|
|
22
|
+
### Step 1: Find the Spec
|
|
23
|
+
|
|
24
|
+
Look for spec files in the repo root:
|
|
25
|
+
|
|
26
|
+
- `CLAUDE.md.spec.ts` — source for CLAUDE.md
|
|
27
|
+
- `AGENTS.md.spec.ts` — source for AGENTS.md
|
|
28
|
+
- Any `*.spec.ts` matching instruction files
|
|
29
|
+
|
|
30
|
+
If no spec exists, suggest: `npx vigiles setup`
|
|
31
|
+
|
|
32
|
+
### Step 2: Read and Understand the Spec
|
|
33
|
+
|
|
34
|
+
Read the spec file. It's a TypeScript file that exports a `claude()` call with these fields:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { claude, enforce, guidance, check, every } from "vigiles/spec";
|
|
38
|
+
|
|
39
|
+
export default claude({
|
|
40
|
+
// Optional: output target (defaults to "CLAUDE.md")
|
|
41
|
+
target: "CLAUDE.md",
|
|
42
|
+
// or multi-target:
|
|
43
|
+
// target: ["CLAUDE.md", "AGENTS.md"],
|
|
44
|
+
|
|
45
|
+
// Prose sections — become ## headings in compiled output
|
|
46
|
+
sections: {
|
|
47
|
+
positioning: "What this project does...",
|
|
48
|
+
architecture: "How the codebase is structured...",
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// File paths verified to exist at compile time
|
|
52
|
+
keyFiles: {
|
|
53
|
+
"src/index.ts": "Main entry point",
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
// Commands verified against package.json
|
|
57
|
+
commands: {
|
|
58
|
+
"npm run build": "Compile the project",
|
|
59
|
+
"npm test": "Run all tests",
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Rules — three types
|
|
63
|
+
rules: {
|
|
64
|
+
// enforce() — backed by a linter rule, verified to exist AND be enabled
|
|
65
|
+
"no-any": enforce(
|
|
66
|
+
"@typescript-eslint/no-explicit-any",
|
|
67
|
+
"Use unknown and narrow with type guards.",
|
|
68
|
+
),
|
|
69
|
+
|
|
70
|
+
// check() — filesystem assertion run by vigiles
|
|
71
|
+
"test-pairing": check(
|
|
72
|
+
every("src/**/*.service.ts").has("{name}.test.ts"),
|
|
73
|
+
"Every service must have tests.",
|
|
74
|
+
),
|
|
75
|
+
|
|
76
|
+
// guidance() — prose only, no enforcement
|
|
77
|
+
"research-first": guidance("Google unfamiliar APIs before implementing."),
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Step 3: Make the Changes
|
|
83
|
+
|
|
84
|
+
Based on what the user asked for:
|
|
85
|
+
|
|
86
|
+
**Adding a rule:**
|
|
87
|
+
|
|
88
|
+
- Determine the type: `enforce()` if a linter rule exists, `check()` for filesystem conventions, `guidance()` for prose-only
|
|
89
|
+
- For `enforce()`: find the actual linter rule name (e.g., `eslint/no-console`, `@typescript-eslint/no-explicit-any`, `ruff/T201`)
|
|
90
|
+
- Add to the `rules` object with a descriptive key
|
|
91
|
+
|
|
92
|
+
**Updating a section:**
|
|
93
|
+
|
|
94
|
+
- Edit the string in `sections`. Sections are plain strings or tagged template literals with `file()`, `cmd()`, `ref()` for verified references
|
|
95
|
+
- Do NOT add `#` or `##` headers inside sections — they break the document structure
|
|
96
|
+
|
|
97
|
+
**Adding a key file or command:**
|
|
98
|
+
|
|
99
|
+
- Add to `keyFiles` or `commands`. The compiler verifies these exist at compile time
|
|
100
|
+
- For commands: must match a script in `package.json`
|
|
101
|
+
- For key files: must exist on disk
|
|
102
|
+
|
|
103
|
+
### Step 4: Compile
|
|
104
|
+
|
|
105
|
+
After editing the spec, run:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npx vigiles compile
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
This regenerates the compiled instruction file(s). Review the output for any errors:
|
|
112
|
+
|
|
113
|
+
- `stale-file` — a key file path doesn't exist
|
|
114
|
+
- `stale-command` — a command isn't in package.json
|
|
115
|
+
- `invalid-rule` — a linter rule doesn't exist or is disabled
|
|
116
|
+
- `section-has-header` — a section contains `#` headers (break into separate named sections)
|
|
117
|
+
|
|
118
|
+
### Step 5: Verify
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npx vigiles check
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
If the PostToolUse hook is installed (via `npx skills add zernie/vigiles`), compilation happens automatically after you save the spec.
|
|
125
|
+
|
|
126
|
+
## Important
|
|
127
|
+
|
|
128
|
+
- **Never edit CLAUDE.md or AGENTS.md directly** — they have a vigiles hash comment and are build artifacts
|
|
129
|
+
- **The spec is TypeScript** — you get type checking, autocomplete, and verified references
|
|
130
|
+
- **`enforce()` rules are verified** — the compiler checks the rule exists AND is enabled in your linter config
|
|
131
|
+
- **Sections must not contain `#` or `##` headers** — use separate named sections instead
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: enforce-rules-format
|
|
3
|
+
description: Validate that all rules have proper enforcement classification (enforce/check/guidance)
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Validate that every rule in the project's instruction files has a proper enforcement classification, and fix any that are missing.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
### Step 1: Detect Format
|
|
12
|
+
|
|
13
|
+
Check which format the project uses:
|
|
14
|
+
|
|
15
|
+
**v2 (spec-based):** Look for `CLAUDE.md.spec.ts` or any `*.spec.ts` files. If found, this is a v2 project — rules must use `enforce()`, `check()`, or `guidance()`.
|
|
16
|
+
|
|
17
|
+
**v1 (hand-written):** Look for `CLAUDE.md`, `AGENTS.md`, `.cursorrules`. If found without a spec file, this is a v1 project — rules need `**Enforced by:**` or `**Guidance only**` annotations.
|
|
18
|
+
|
|
19
|
+
### Step 2: Validate
|
|
20
|
+
|
|
21
|
+
**For v2 specs:**
|
|
22
|
+
|
|
23
|
+
The TypeScript type system already prevents unannotated rules — you can't create a rule without calling `enforce()`, `check()`, or `guidance()`. So focus on:
|
|
24
|
+
|
|
25
|
+
1. Do `enforce()` rules reference real linter rules? Run `npx vigiles compile` to check.
|
|
26
|
+
2. Are there guidance rules that COULD be `enforce()`? Check linter configs for matching rules.
|
|
27
|
+
3. Are there `check()` assertions that could be delegated to a linter? Suggest `enforce()` instead.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx vigiles compile
|
|
31
|
+
npx vigiles discover
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**For v1 hand-written files:**
|
|
35
|
+
|
|
36
|
+
Scan for `###` headings. Each must have one of:
|
|
37
|
+
|
|
38
|
+
- `**Enforced by:** \`linter/rule-name\``
|
|
39
|
+
- `**Guidance only** — reason`
|
|
40
|
+
- `<!-- vigiles-disable -->`
|
|
41
|
+
|
|
42
|
+
Report missing annotations with a summary table.
|
|
43
|
+
|
|
44
|
+
### Step 3: Fix Issues
|
|
45
|
+
|
|
46
|
+
For each issue found:
|
|
47
|
+
|
|
48
|
+
1. Check the project's linter configuration for matching rules
|
|
49
|
+
2. Suggest `enforce("linter/rule")` (v2) or `**Enforced by:** \`linter/rule\`` (v1)
|
|
50
|
+
3. If no linter rule exists, suggest `guidance()` (v2) or `**Guidance only**` (v1)
|
|
51
|
+
4. **Ask the user** before making changes
|
|
52
|
+
|
|
53
|
+
### Step 4: Suggest Migration
|
|
54
|
+
|
|
55
|
+
If the project uses v1 format, suggest migrating to v2 specs for type safety:
|
|
56
|
+
|
|
57
|
+
> Your rules could benefit from type-safe specs. Run the `migrate-to-spec` skill to convert your CLAUDE.md to a typed .spec.ts file.
|
|
58
|
+
|
|
59
|
+
### Step 5: Verify
|
|
60
|
+
|
|
61
|
+
Run the appropriate command:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# v2
|
|
65
|
+
npx vigiles compile && npx vigiles check
|
|
66
|
+
|
|
67
|
+
# validate
|
|
68
|
+
npx vigiles check
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Report the validation result.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: generate-logo
|
|
3
|
+
description: Generate or iterate on the vigiles logo using ImageRouter API
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Generate Logo
|
|
7
|
+
|
|
8
|
+
Generate logo variations for vigiles using the ImageRouter API (imagerouter.io).
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
Get an API key from https://imagerouter.io/api-keys. Pass it as an argument or set `IMAGEROUTER_API_KEY` env var. Do NOT commit the key.
|
|
13
|
+
|
|
14
|
+
## API
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Endpoint: https://api.imagerouter.io/v1/openai/images/generations
|
|
18
|
+
Auth: Bearer token in Authorization header
|
|
19
|
+
Method: POST, Content-Type: application/json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Request body
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"prompt": "...",
|
|
27
|
+
"model": "google/nano-banana-2",
|
|
28
|
+
"quality": "high",
|
|
29
|
+
"size": "1024x1024",
|
|
30
|
+
"response_format": "url",
|
|
31
|
+
"output_format": "png"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Available models (image generation)
|
|
36
|
+
|
|
37
|
+
List models: `GET https://api.imagerouter.io/v1/models`
|
|
38
|
+
|
|
39
|
+
Known good models:
|
|
40
|
+
|
|
41
|
+
- `google/nano-banana-2` — best quality, $0.07/image
|
|
42
|
+
- `google/nano-banana-2:free` — free tier
|
|
43
|
+
- `openai/gpt-image-1` — OpenAI's image model
|
|
44
|
+
- `black-forest-labs/FLUX-1.1-pro` — FLUX pro
|
|
45
|
+
|
|
46
|
+
### Response
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"created": 1775430873,
|
|
51
|
+
"data": [{ "url": "https://storage.imagerouter.io/..." }],
|
|
52
|
+
"cost": 0.069,
|
|
53
|
+
"latency": 27627
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Download the image from the URL in `data[0].url`.
|
|
58
|
+
|
|
59
|
+
## Current logo
|
|
60
|
+
|
|
61
|
+
The current logo (`logo.png`) is v6: overlapping translucent flame petals on dark background, amber-orange palette. Generated with `google/nano-banana-2`.
|
|
62
|
+
|
|
63
|
+
### Prompt that produced it
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
A premium, refined logo icon for a developer tool called vigiles that compiles
|
|
67
|
+
typed TypeScript specs to AI instruction files. Inspired by OpenAI geometric aesthetic and Apple
|
|
68
|
+
minimalism. A single abstract geometric shape: an upward-pointing flame composed
|
|
69
|
+
of 3 overlapping translucent rounded shapes, creating depth through overlap —
|
|
70
|
+
similar to how the OpenAI logo uses overlapping curves. Warm amber to deep orange
|
|
71
|
+
color palette. Black background. No text. No letters. Pure abstract mark. Clean
|
|
72
|
+
enough to be an app icon. Luxurious, premium, modern tech company feel.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Design principles
|
|
76
|
+
|
|
77
|
+
- **Flame/torch motif** — vigiles were Rome's night watchmen who carried torches
|
|
78
|
+
- **Amber/orange palette** — matches GitHub Action branding color
|
|
79
|
+
- **No text in the icon** — must work at 16px favicon size
|
|
80
|
+
- **Dark background variant** for README, light/transparent variant for npm
|
|
81
|
+
|
|
82
|
+
## Example curl
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
curl 'https://api.imagerouter.io/v1/openai/images/generations' \
|
|
86
|
+
-H "Authorization: Bearer $IMAGEROUTER_API_KEY" \
|
|
87
|
+
-H 'Content-Type: application/json' \
|
|
88
|
+
-d '{
|
|
89
|
+
"prompt": "YOUR PROMPT HERE",
|
|
90
|
+
"model": "google/nano-banana-2",
|
|
91
|
+
"quality": "high",
|
|
92
|
+
"size": "1024x1024",
|
|
93
|
+
"response_format": "url",
|
|
94
|
+
"output_format": "png"
|
|
95
|
+
}'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Workflow
|
|
99
|
+
|
|
100
|
+
1. Generate variations with different prompts
|
|
101
|
+
2. Save as `logo-v*.png` (gitignored)
|
|
102
|
+
3. Pick the best, copy to `logo.png`
|
|
103
|
+
4. Commit `logo.png` only
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!-- vigiles:sha256:a9df2c1748576753 compiled from skills/generate-rule/SKILL.md.spec.ts -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
name: generate-rule
|
|
6
|
+
description: Add a new enforce(), check(), or guidance() rule to an existing spec file
|
|
7
|
+
disable-model-invocation: true
|
|
8
|
+
argument-hint: <rule>
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Arguments
|
|
13
|
+
|
|
14
|
+
- `$1` **rule** — natural-language description of what the rule should enforce, e.g. "no console.log in production code"
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
### Step 1
|
|
19
|
+
|
|
20
|
+
**Find the spec file.** Look for `CLAUDE.md.spec.ts` in the repo root. If it doesn't exist:
|
|
21
|
+
|
|
22
|
+
- If there's a hand-written `CLAUDE.md`, suggest running the `migrate-to-spec` skill first.
|
|
23
|
+
- If there's no `CLAUDE.md` either, suggest `npx vigiles init` to scaffold one.
|
|
24
|
+
|
|
25
|
+
### Step 2
|
|
26
|
+
|
|
27
|
+
**Classify the rule** from the description ($1):
|
|
28
|
+
|
|
29
|
+
- **enforce()** — if a linter rule can back it. Check the project's linter configs (ESLint, Ruff, Clippy, Pylint, RuboCop, Stylelint) for a matching rule; also consider an architectural tool (ast-grep, Dependency Cruiser, Steiger). If uncertain whether a rule exists, **ask the user** rather than guessing.
|
|
30
|
+
- **check()** — if it's a filesystem structural convention ("every X needs a Y"). Only for file-pairing; never for code content.
|
|
31
|
+
- **guidance()** — if it can't be mechanically enforced (subjective conventions, process rules, migration context).
|
|
32
|
+
|
|
33
|
+
### Step 3
|
|
34
|
+
|
|
35
|
+
**Generate the rule.** Create an entry with a kebab-case ID derived from the description. Examples:
|
|
36
|
+
|
|
37
|
+
"no-console": enforce("eslint/no-console", "Use structured logger for observability."),
|
|
38
|
+
|
|
39
|
+
"controller-tests": check(
|
|
40
|
+
every("src/**/*.controller.ts").has("{name}.controller.test.ts"),
|
|
41
|
+
"Every controller must have a co-located test file.",
|
|
42
|
+
),
|
|
43
|
+
|
|
44
|
+
"research-before-implementing": guidance(
|
|
45
|
+
"Google unfamiliar APIs before implementing.",
|
|
46
|
+
),
|
|
47
|
+
|
|
48
|
+
### Step 4
|
|
49
|
+
|
|
50
|
+
**Add it to the spec.** Read the existing spec file and add the new rule to the `rules` object, preserving alphabetical ordering if the existing rules are alphabetical. Import any new builders needed (e.g. `check` and `every` for the first `check()` rule).
|
|
51
|
+
|
|
52
|
+
### Step 5
|
|
53
|
+
|
|
54
|
+
**Compile and verify.** Build and recompile; if compilation fails (e.g. the linter rule doesn't exist), report the error and suggest alternatives. Show the user the updated spec and the compiled `CLAUDE.md` diff.
|
|
55
|
+
|
|
56
|
+
**Gate** — run the project's build command (retry up to 2×); do not proceed until it passes.
|
|
57
|
+
|
|
58
|
+
<!-- vigiles:gate role:build retry:2 -->
|
|
59
|
+
|
|
60
|
+
## Result
|
|
61
|
+
|
|
62
|
+
This skill is complete when the project's build command passes.
|
|
63
|
+
|
|
64
|
+
<!-- vigiles:result role:build -->
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Clippy — Reference
|
|
2
|
+
|
|
3
|
+
Shared linter reference for vigiles skills. Used by `strengthen` (find existing rules) and `pr-to-lint-rule` (write custom lints).
|
|
4
|
+
|
|
5
|
+
## Check Existing Lints First
|
|
6
|
+
|
|
7
|
+
Before writing a custom lint, search these lint groups — the pattern may already be covered:
|
|
8
|
+
|
|
9
|
+
| Lint group | Scope | Key lints to know |
|
|
10
|
+
| ------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
11
|
+
| `correctness` | Code that is outright wrong or will panic | `uninit_assumed_init`, `wrong_self_convention`, `nonsensical_open_options`, `mistyped_literal_suffixes`, `transmuting_null`, `undropped_manually_drops` |
|
|
12
|
+
| `suspicious` | Code that is very likely a bug | `suspicious_else_formatting`, `suspicious_unary_op_formatting`, `suspicious_op_assign_impl`, `blanket_clippy_restriction_lints`, `almost_complete_range` |
|
|
13
|
+
| `style` | Idiomatic Rust style violations | `needless_return`, `redundant_closure`, `match_bool`, `single_match`, `collapsible_if`, `len_zero`, `manual_map`, `if_let_mutex` |
|
|
14
|
+
| `complexity` | Code that can be simplified | `unnecessary_cast`, `needless_borrow`, `redundant_clone`, `type_complexity`, `manual_strip`, `option_map_unit_fn`, `useless_conversion` |
|
|
15
|
+
| `perf` | Code that can be made faster | `large_enum_variant`, `box_collection`, `redundant_allocation`, `manual_memcpy`, `iter_nth`, `unnecessary_to_owned`, `needless_collect` |
|
|
16
|
+
| `pedantic` | Stricter lints, off by default | `unwrap_used`, `expect_used`, `cast_possible_truncation`, `cast_sign_loss`, `missing_errors_doc`, `missing_panics_doc`, `doc_markdown`, `must_use_candidate` |
|
|
17
|
+
| `restriction` | Lints for specific project policies, off by default | `print_stdout`, `print_stderr`, `dbg_macro`, `unimplemented`, `todo`, `unwrap_used`, `expect_used`, `mem_forget`, `shadow_reuse`, `float_arithmetic` |
|
|
18
|
+
| `nursery` | Experimental lints, may have false positives | `missing_const_for_fn`, `cognitive_complexity`, `use_self`, `option_if_let_else`, `redundant_pub_crate`, `significant_drop_tightening` |
|
|
19
|
+
| `cargo` | Cargo manifest issues | `multiple_crate_versions`, `wildcard_dependencies`, `negative_feature_names`, `redundant_feature_names` |
|
|
20
|
+
|
|
21
|
+
**Tip:** Run `cargo clippy --warn clippy::pedantic` on your codebase to see what pedantic catches before manually hunting for rules. The full lint list is at <https://rust-lang.github.io/rust-clippy/stable/>.
|
|
22
|
+
|
|
23
|
+
## Lint Configuration
|
|
24
|
+
|
|
25
|
+
### Cargo.toml `[lints.clippy]` section (recommended)
|
|
26
|
+
|
|
27
|
+
The modern way to configure Clippy project-wide. Checked into version control, applies to every `cargo clippy` invocation:
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
# Cargo.toml
|
|
31
|
+
[lints.clippy]
|
|
32
|
+
# Enable entire groups
|
|
33
|
+
pedantic = "warn"
|
|
34
|
+
nursery = "warn"
|
|
35
|
+
|
|
36
|
+
# Override individual lints
|
|
37
|
+
unwrap_used = "deny"
|
|
38
|
+
expect_used = "warn"
|
|
39
|
+
cast_possible_truncation = "allow"
|
|
40
|
+
|
|
41
|
+
# Restriction lints — opt-in individually
|
|
42
|
+
print_stdout = "warn"
|
|
43
|
+
dbg_macro = "deny"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This replaces the older `#![warn(clippy::pedantic)]` crate-level attribute approach. vigiles reads `Cargo.toml` for `enforce()` verification.
|
|
47
|
+
|
|
48
|
+
### Inline attributes
|
|
49
|
+
|
|
50
|
+
Use `#[allow]`, `#[warn]`, and `#[deny]` for per-item overrides:
|
|
51
|
+
|
|
52
|
+
```rust
|
|
53
|
+
// Suppress a lint on a single function
|
|
54
|
+
#[allow(clippy::too_many_arguments)]
|
|
55
|
+
fn create_widget(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32) { /* ... */ }
|
|
56
|
+
|
|
57
|
+
// Escalate a lint to a hard error for a module
|
|
58
|
+
#[deny(clippy::unwrap_used)]
|
|
59
|
+
mod payment_processing {
|
|
60
|
+
// Any .unwrap() in this module fails compilation
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Warn on a lint for a specific impl block
|
|
64
|
+
#[warn(clippy::cast_possible_truncation)]
|
|
65
|
+
impl Converter {
|
|
66
|
+
fn to_u32(&self, val: u64) -> u32 { val as u32 }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Attribute precedence (highest to lowest): `#[forbid]` > `#[deny]` > `#[warn]` > `#[allow]`. `#[forbid]` cannot be overridden by inner attributes — use it for security-critical lints.
|
|
71
|
+
|
|
72
|
+
### `clippy.toml` / `.clippy.toml`
|
|
73
|
+
|
|
74
|
+
Project-level configuration for lint thresholds and behavior:
|
|
75
|
+
|
|
76
|
+
```toml
|
|
77
|
+
# clippy.toml
|
|
78
|
+
too-many-arguments-threshold = 10
|
|
79
|
+
type-complexity-threshold = 500
|
|
80
|
+
cognitive-complexity-threshold = 30
|
|
81
|
+
single-char-binding-names-threshold = 4
|
|
82
|
+
msrv = "1.70.0"
|
|
83
|
+
|
|
84
|
+
# Disallow certain types
|
|
85
|
+
disallowed-types = [
|
|
86
|
+
{ path = "std::collections::HashMap", reason = "Use indexmap::IndexMap for deterministic iteration" },
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
# Disallow certain methods
|
|
90
|
+
disallowed-methods = [
|
|
91
|
+
{ path = "std::env::var", reason = "Use config::get() for environment access" },
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
# Disallow certain macros
|
|
95
|
+
disallowed-macros = [
|
|
96
|
+
{ path = "std::println", reason = "Use tracing::info! instead" },
|
|
97
|
+
]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`disallowed-types`, `disallowed-methods`, and `disallowed-macros` are particularly powerful — they let you ban specific APIs project-wide with custom error messages, no custom lint needed.
|
|
101
|
+
|
|
102
|
+
## Custom Lints
|
|
103
|
+
|
|
104
|
+
### dylint — custom Clippy-style lints
|
|
105
|
+
|
|
106
|
+
[dylint](https://github.com/trailofbits/dylint) loads lint libraries as dynamic libraries, giving you the same compiler internals that Clippy uses:
|
|
107
|
+
|
|
108
|
+
```rust
|
|
109
|
+
// my_lint/src/lib.rs
|
|
110
|
+
use clippy_utils::diagnostics::span_lint_and_help;
|
|
111
|
+
use rustc_lint::{LateContext, LateLintPass, LintArray, LintPass};
|
|
112
|
+
use rustc_session::{declare_lint, declare_lint_pass};
|
|
113
|
+
|
|
114
|
+
declare_lint! {
|
|
115
|
+
/// Disallow direct database calls outside the `db` module.
|
|
116
|
+
pub NO_DIRECT_DB_CALL,
|
|
117
|
+
Warn,
|
|
118
|
+
"direct database calls should go through the db module"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
declare_lint_pass!(NoDirectDbCall => [NO_DIRECT_DB_CALL]);
|
|
122
|
+
|
|
123
|
+
impl<'tcx> LateLintPass<'tcx> for NoDirectDbCall {
|
|
124
|
+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'_>) {
|
|
125
|
+
if is_direct_db_call(cx, expr) {
|
|
126
|
+
span_lint_and_help(
|
|
127
|
+
cx,
|
|
128
|
+
NO_DIRECT_DB_CALL,
|
|
129
|
+
expr.span,
|
|
130
|
+
"direct database calls are not allowed here",
|
|
131
|
+
None,
|
|
132
|
+
"use the repository pattern — import from `crate::db` instead",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**When to use dylint vs existing Clippy lints:**
|
|
140
|
+
|
|
141
|
+
| Situation | Use |
|
|
142
|
+
| ----------------------------------------- | ------------------------------------------- |
|
|
143
|
+
| Ban a specific function/type/macro | `clippy.toml` `disallowed-*` — zero code |
|
|
144
|
+
| Enforce naming or style convention | Existing Clippy pedantic/style lints |
|
|
145
|
+
| Detect a pattern needing type information | dylint — access to rustc type checker |
|
|
146
|
+
| Enforce architectural boundaries | dylint or `cargo-deny` for dependency rules |
|
|
147
|
+
| One-off "don't use X" in a single crate | `#[deny(clippy::...)]` attribute |
|
|
148
|
+
|
|
149
|
+
**dylint tradeoffs:**
|
|
150
|
+
|
|
151
|
+
- Tied to a specific Rust nightly version (compiler internals are unstable)
|
|
152
|
+
- Requires maintaining a separate crate with `rustc_private` dependencies
|
|
153
|
+
- `clippy_utils` provides helper functions but its API changes between releases
|
|
154
|
+
- Build times increase since the lint library compiles against `rustc` internals
|
|
155
|
+
|
|
156
|
+
For vigiles, reference dylint lints via: `enforce("clippy/no_direct_db_call", "Use the repository pattern.")` — the lint name maps to the `declare_lint!` identifier (snake_case).
|
|
157
|
+
|
|
158
|
+
## Edge Cases and Gotchas
|
|
159
|
+
|
|
160
|
+
### False positives from macros
|
|
161
|
+
|
|
162
|
+
Clippy lints operate on the expanded AST. Macros can trigger false positives because the expanded code looks different from what the author wrote:
|
|
163
|
+
|
|
164
|
+
```rust
|
|
165
|
+
// This macro expansion may trigger `clippy::redundant_clone`
|
|
166
|
+
// even though the clone is structurally necessary in the macro output
|
|
167
|
+
my_derive_macro! {
|
|
168
|
+
struct Foo { bar: String }
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Workarounds:
|
|
173
|
+
|
|
174
|
+
- `#[allow(clippy::...)]` on the macro invocation site
|
|
175
|
+
- Add `#[automatically_derived]` in proc-macro output — Clippy skips many lints for derived code
|
|
176
|
+
- File an issue upstream if the false positive is in a common macro pattern
|
|
177
|
+
|
|
178
|
+
### Nightly-only lints
|
|
179
|
+
|
|
180
|
+
Some Clippy lints require nightly Rust because they depend on unstable compiler features. The `nursery` group is the most common source. If you enable `nursery` lints in CI:
|
|
181
|
+
|
|
182
|
+
- Pin a specific nightly version: `rust-toolchain.toml` with `channel = "nightly-2025-01-15"`
|
|
183
|
+
- Expect breakage on nightly updates — nursery lints can be renamed, removed, or change behavior
|
|
184
|
+
- Never `#[deny]` nursery lints — use `#[warn]` so they don't block builds when behavior changes
|
|
185
|
+
|
|
186
|
+
### `allow` vs `warn` on groups
|
|
187
|
+
|
|
188
|
+
Enabling a group and then allowing individual lints works top-down:
|
|
189
|
+
|
|
190
|
+
```toml
|
|
191
|
+
# Cargo.toml
|
|
192
|
+
[lints.clippy]
|
|
193
|
+
pedantic = "warn" # Enable all pedantic lints
|
|
194
|
+
module_name_repetitions = "allow" # But suppress this one
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The reverse does NOT work — you cannot `allow` a group and then `warn` an individual lint from it. The group-level `allow` takes precedence. Always enable groups first, then suppress specific lints.
|
|
198
|
+
|
|
199
|
+
### Interaction with `#[must_use]`
|
|
200
|
+
|
|
201
|
+
Clippy's `must_use_candidate` lint (pedantic) suggests adding `#[must_use]` to functions that return values. This interacts with other lints:
|
|
202
|
+
|
|
203
|
+
- Once `#[must_use]` is added, callers who ignore the return value get `unused_must_use` (a rustc warning, not Clippy)
|
|
204
|
+
- `let _ = foo()` silences `unused_must_use` but triggers `let_underscore_must_use` (Clippy restriction)
|
|
205
|
+
- `drop(foo())` silences both but may trigger `drop_non_drop` if the type doesn't implement `Drop`
|
|
206
|
+
|
|
207
|
+
Recommendation: Enable `must_use_candidate` globally, but only `#[deny(unused_must_use)]` in modules where ignoring results is dangerous (I/O, error handling).
|
|
208
|
+
|
|
209
|
+
### Unsafe code linting
|
|
210
|
+
|
|
211
|
+
Clippy provides several lints for `unsafe` code, but they have limitations:
|
|
212
|
+
|
|
213
|
+
- `undocumented_unsafe_blocks` (restriction) — requires a `// SAFETY:` comment above every `unsafe` block. Enable this project-wide.
|
|
214
|
+
- `unsafe_derive_deserialize` (pedantic) — warns when `Deserialize` is derived on types with unsafe invariants
|
|
215
|
+
- `multiple_unsafe_ops_per_block` (restriction) — each `unsafe` block should contain exactly one unsafe operation for precise `// SAFETY:` documentation
|
|
216
|
+
|
|
217
|
+
These lints do NOT verify that safety invariants are actually upheld — they only enforce documentation conventions. Use `cargo miri test` and `#[cfg(miri)]` for runtime verification of unsafe code.
|
|
218
|
+
|
|
219
|
+
### MSRV-aware lints
|
|
220
|
+
|
|
221
|
+
Clippy respects the `msrv` field in `clippy.toml`. Some lints suggest replacements that require newer Rust versions. If you set `msrv = "1.65.0"`, Clippy won't suggest `let-else` (stabilized in 1.65) but will suppress suggestions for features from 1.66+. Always set this to match your `rust-version` in `Cargo.toml`.
|
|
222
|
+
|
|
223
|
+
## Mapping PR Feedback to Lint Strategy
|
|
224
|
+
|
|
225
|
+
| PR comment pattern | Best approach |
|
|
226
|
+
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
227
|
+
| "Don't use `.unwrap()`" | `enforce("clippy/unwrap_used", "Use expect() with context or propagate with ?.")` — pedantic, enable project-wide |
|
|
228
|
+
| "Don't call this function" | `clippy.toml` `disallowed-methods` — zero custom code, includes custom error message |
|
|
229
|
+
| "Don't use this type" | `clippy.toml` `disallowed-types` — same approach, works for `HashMap`, `Mutex`, etc. |
|
|
230
|
+
| "Don't use `println!`" | `enforce("clippy/print_stdout", "Use tracing macros.")` — restriction lint, opt-in |
|
|
231
|
+
| "Add error context" | Not Clippy — use `#[deny(clippy::unwrap_used)]` + guidance for `anyhow`/`thiserror` patterns |
|
|
232
|
+
| "This clone is unnecessary" | `enforce("clippy/redundant_clone", "Remove the unnecessary clone.")` — already in complexity group |
|
|
233
|
+
| "Use `Self` in impl blocks" | `enforce("clippy/use_self", "Use Self instead of repeating the type name.")` — nursery lint |
|
|
234
|
+
| "Document safety invariants" | `enforce("clippy/undocumented_unsafe_blocks", "Add a // SAFETY: comment.")` — restriction lint |
|
|
235
|
+
| "Too many function parameters" | `enforce("clippy/too_many_arguments", "Refactor into a config struct.")` — already in complexity group |
|
|
236
|
+
| "Wildcard deps in Cargo.toml" | `enforce("clippy/wildcard_dependencies", "Pin dependency versions.")` — cargo group |
|
|
237
|
+
| "Every public fn needs error docs" | `enforce("clippy/missing_errors_doc", "Document the errors this function can return.")` — pedantic |
|
|
238
|
+
| "Avoid `as` casts" | `enforce("clippy/cast_possible_truncation", "Use try_from() or explicit checked conversion.")` — pedantic |
|
|
239
|
+
| "Don't leave `todo!()` in code" | `enforce("clippy/todo", "Replace todo!() with an implementation or file an issue.")` — restriction lint |
|
|
240
|
+
| "Use the builder pattern" | Not Clippy — use vigiles `guidance()` for architectural patterns |
|
|
241
|
+
| "Enforce import boundaries between modules" | Not Clippy — use `cargo-deny` for crate-level boundaries or dylint for module-level enforcement |
|