vigiles 2.0.0 → 2.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/README.md +182 -134
- package/dist/action-gate.d.ts +28 -0
- package/dist/action-gate.js +73 -0
- package/dist/cli.js +705 -230
- package/dist/community-skills.d.ts +22 -0
- package/dist/community-skills.js +86 -0
- package/dist/compile-generator.d.ts +48 -0
- package/dist/compile-generator.js +322 -0
- package/dist/compile.d.ts +4 -0
- package/dist/compile.js +239 -45
- package/dist/coverage.d.ts +56 -0
- package/dist/coverage.js +178 -0
- package/dist/doc-refs.d.ts +60 -0
- package/dist/doc-refs.js +246 -0
- package/dist/eval.d.ts +62 -0
- package/dist/eval.js +174 -0
- package/dist/evolve.js +60 -125
- package/dist/frontmatter.d.ts +75 -0
- package/dist/frontmatter.js +263 -0
- package/dist/generate-schema.d.ts +51 -0
- package/dist/generate-schema.js +125 -0
- package/dist/generate-types.js +39 -1
- package/dist/harness-test.d.ts +38 -0
- package/dist/harness-test.js +129 -0
- package/dist/hash.d.ts +8 -0
- package/dist/hash.js +16 -0
- package/dist/inline.d.ts +22 -4
- package/dist/inline.js +60 -13
- package/dist/integrity.d.ts +29 -0
- package/dist/integrity.js +44 -0
- package/dist/linters.d.ts +5 -3
- package/dist/linters.js +144 -4
- package/dist/mock-model.d.ts +31 -0
- package/dist/mock-model.js +189 -0
- package/dist/orphans.d.ts +52 -0
- package/dist/orphans.js +124 -0
- package/dist/proofs.js +22 -16
- package/dist/refs.d.ts +44 -0
- package/dist/refs.js +144 -0
- package/dist/session.d.ts +97 -0
- package/dist/session.js +306 -0
- package/dist/sidecar.d.ts +35 -0
- package/dist/sidecar.js +102 -0
- package/dist/skill-driver.d.ts +77 -0
- package/dist/skill-driver.js +76 -0
- package/dist/skill-runtime.d.ts +101 -0
- package/dist/skill-runtime.js +289 -0
- package/dist/skill-test.d.ts +47 -0
- package/dist/skill-test.js +77 -0
- package/dist/spec.d.ts +119 -13
- package/dist/spec.js +51 -4
- package/dist/symbols.d.ts +30 -0
- package/dist/symbols.js +142 -0
- package/dist/test-utils.d.ts +8 -0
- package/dist/test-utils.js +41 -0
- package/dist/types.d.ts +34 -8
- package/dist/types.js +19 -0
- package/dist/validate.js +5 -3
- package/package.json +26 -5
- package/.claude/settings.json +0 -46
- package/.claude/settings.local.json +0 -8
- package/.github/workflows/ci.yml +0 -81
- package/.prettierignore +0 -1
- package/.vigiles/generated.d.ts +0 -205
- package/CLAUDE.md +0 -95
- package/CLAUDE.md.spec.ts +0 -142
- package/CONTRIBUTING.md +0 -121
- package/dist/action.d.ts.map +0 -1
- package/dist/action.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cli.test.d.ts +0 -2
- package/dist/cli.test.d.ts.map +0 -1
- package/dist/cli.test.js +0 -650
- package/dist/cli.test.js.map +0 -1
- package/dist/compile.d.ts.map +0 -1
- package/dist/compile.js.map +0 -1
- package/dist/evolve.d.ts.map +0 -1
- package/dist/evolve.js.map +0 -1
- package/dist/freshness.d.ts +0 -67
- package/dist/freshness.d.ts.map +0 -1
- package/dist/freshness.js +0 -244
- package/dist/freshness.js.map +0 -1
- package/dist/freshness.test.d.ts +0 -2
- package/dist/freshness.test.d.ts.map +0 -1
- package/dist/freshness.test.js +0 -356
- package/dist/freshness.test.js.map +0 -1
- package/dist/generate-types.d.ts.map +0 -1
- package/dist/generate-types.js.map +0 -1
- package/dist/inline.d.ts.map +0 -1
- package/dist/inline.js.map +0 -1
- package/dist/inline.test.d.ts +0 -5
- package/dist/inline.test.d.ts.map +0 -1
- package/dist/inline.test.js +0 -152
- package/dist/inline.test.js.map +0 -1
- package/dist/linters.d.ts.map +0 -1
- package/dist/linters.js.map +0 -1
- package/dist/proofs.d.ts.map +0 -1
- package/dist/proofs.js.map +0 -1
- package/dist/proofs.test.d.ts +0 -9
- package/dist/proofs.test.d.ts.map +0 -1
- package/dist/proofs.test.js +0 -952
- package/dist/proofs.test.js.map +0 -1
- package/dist/spec.d.ts.map +0 -1
- package/dist/spec.js.map +0 -1
- package/dist/spec.test.d.ts +0 -2
- package/dist/spec.test.d.ts.map +0 -1
- package/dist/spec.test.js +0 -1222
- package/dist/spec.test.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js.map +0 -1
- package/dist/validate.test.d.ts +0 -2
- package/dist/validate.test.d.ts.map +0 -1
- package/dist/validate.test.js +0 -531
- package/dist/validate.test.js.map +0 -1
- package/docs/agent-setup.md +0 -85
- package/docs/agent-workflows.md +0 -103
- package/docs/comparison.md +0 -71
- package/docs/freshness.md +0 -124
- package/docs/inline-mode.md +0 -119
- package/docs/linter-support.md +0 -166
- package/docs/spec-format.md +0 -194
- package/eslint.config.mjs +0 -79
- package/examples/CLAUDE.md +0 -54
- package/examples/CLAUDE.md.spec.ts +0 -65
- package/examples/SKILL.md +0 -50
- package/examples/SKILL.md.spec.ts +0 -57
- package/fixtures/example-project/CLAUDE.md +0 -11
- package/fixtures/example-project/package.json +0 -9
- package/fixtures/example-project/src/index.ts +0 -3
- package/fixtures/example-project/src/utils.test.ts +0 -2
- package/fixtures/example-project/src/utils.ts +0 -3
- package/logo.png +0 -0
- package/research/adoption-strategy.md +0 -111
- package/research/agent-integration.md +0 -145
- package/research/ai-code-quality.md +0 -197
- package/research/code-search-for-agents.md +0 -313
- package/research/competitive-landscape.md +0 -163
- package/research/doc-freshness.md +0 -516
- package/research/executable-specs.md +0 -368
- package/research/feature-ideas.md +0 -464
- package/research/formal-proofs-for-agents.md +0 -338
- package/research/fp-for-agent-harness.md +0 -150
- package/research/fp-for-deterministic-ai.md +0 -131
- package/research/self-evolving-specs.md +0 -298
- package/schemas/claude-md-strict.yml +0 -18
- package/schemas/claude-md.yml +0 -6
- package/schemas/skill-strict.yml +0 -12
- package/schemas/skill.yml +0 -5
- package/skills/audit-feedback-loop/SKILL.md +0 -76
- package/skills/edit-spec/SKILL.md +0 -131
- package/skills/enforce-rules-format/SKILL.md +0 -71
- package/skills/generate-logo/SKILL.md +0 -102
- package/skills/generate-rule/SKILL.md +0 -90
- package/skills/linter-docs/clippy.md +0 -241
- package/skills/linter-docs/eslint.md +0 -384
- package/skills/linter-docs/pylint.md +0 -288
- package/skills/linter-docs/rubocop.md +0 -277
- package/skills/linter-docs/ruff.md +0 -187
- package/skills/linter-docs/stylelint.md +0 -247
- package/skills/migrate-to-spec/SKILL.md +0 -124
- package/skills/pr-to-lint-rule/SKILL.md +0 -97
- package/skills/strengthen/SKILL.md +0 -168
- package/src/action.ts +0 -214
- package/src/cli.test.ts +0 -914
- package/src/cli.ts +0 -1631
- package/src/compile.ts +0 -691
- package/src/evolve.ts +0 -781
- package/src/freshness.test.ts +0 -449
- package/src/freshness.ts +0 -299
- package/src/generate-types.ts +0 -448
- package/src/inline.test.ts +0 -206
- package/src/inline.ts +0 -164
- package/src/linters.ts +0 -739
- package/src/proofs.test.ts +0 -1314
- package/src/proofs.ts +0 -849
- package/src/spec.test.ts +0 -1471
- package/src/spec.ts +0 -427
- package/src/types.ts +0 -117
- package/src/validate.test.ts +0 -701
- package/src/validate.ts +0 -381
- package/tsconfig.json +0 -23
package/docs/spec-format.md
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# Spec Format Reference
|
|
2
|
-
|
|
3
|
-
vigiles specs are TypeScript files (`*.spec.ts`) that compile to markdown instruction files. The spec is the source of truth; the markdown is a build artifact.
|
|
4
|
-
|
|
5
|
-
## CLAUDE.md Specs
|
|
6
|
-
|
|
7
|
-
Use `claude()` to define a CLAUDE.md spec. Export it as the default export.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import { claude, enforce, guidance, file, cmd, ref, instructions } from "vigiles";
|
|
11
|
-
|
|
12
|
-
export default claude({
|
|
13
|
-
target: "CLAUDE.md", // or "AGENTS.md", or ["CLAUDE.md", "AGENTS.md"]
|
|
14
|
-
sections: { ... },
|
|
15
|
-
keyFiles: { ... },
|
|
16
|
-
commands: { ... },
|
|
17
|
-
rules: { ... },
|
|
18
|
-
maxSectionLines: 30, // optional: cap per-section line count
|
|
19
|
-
});
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### `target`
|
|
23
|
-
|
|
24
|
-
`string | string[]` -- Output filename(s). Defaults to `"CLAUDE.md"`. Also used as the `# Heading` in compiled output. Pass an array to compile one spec to multiple targets:
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
target: ["CLAUDE.md", "AGENTS.md"], // emits both from one spec
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### `sections`
|
|
31
|
-
|
|
32
|
-
`Record<string, string | InstructionFragment[]>` -- Named prose sections. Each key becomes a `## Heading` in the compiled output (first letter uppercased). Values are either plain strings or tagged templates via `instructions` with embedded `file()`, `cmd()`, and `ref()` references.
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
sections: {
|
|
36
|
-
architecture: `Two rule types: enforce() and guidance().`,
|
|
37
|
-
setup: instructions`See ${file("docs/setup.md")} and run ${cmd("npm install")}.`,
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### `keyFiles`
|
|
42
|
-
|
|
43
|
-
`Record<string, string>` -- File paths mapped to descriptions. Each path is verified via `existsSync` at compile time. Compiles to a bullet list under `## Key Files`.
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
keyFiles: {
|
|
47
|
-
"src/spec.ts": "Type system and builder functions",
|
|
48
|
-
"src/compile.ts": "Compiler: spec to markdown with SHA-256 hash",
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### `commands`
|
|
53
|
-
|
|
54
|
-
`Record<string, string>` -- Commands mapped to descriptions. `npm run <script>` and `npm <lifecycle>` commands are verified against `package.json` scripts at compile time. Compiles to a bullet list under `## Commands`.
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
commands: {
|
|
58
|
-
"npm run build": "Compile TypeScript to dist/",
|
|
59
|
-
"npm test": "Build and run all tests",
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### `rules`
|
|
64
|
-
|
|
65
|
-
`Record<string, Rule>` -- Rule ID mapped to an `enforce()` or `guidance()` rule. The ID is kebab-cased by convention and is converted to a Title Case `### Heading` in compiled output. See [Rule Types](#rule-types) below.
|
|
66
|
-
|
|
67
|
-
## SKILL.md Specs
|
|
68
|
-
|
|
69
|
-
Use `skill()` to define a SKILL.md spec. Compiles to markdown with YAML frontmatter.
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { skill, file, cmd, ref, instructions } from "vigiles";
|
|
73
|
-
|
|
74
|
-
export default skill({
|
|
75
|
-
name: "pr-to-lint-rule",
|
|
76
|
-
description: "Convert PR feedback into an automated lint rule",
|
|
77
|
-
argumentHint: "<description of recurring PR feedback>",
|
|
78
|
-
disableModelInvocation: true,
|
|
79
|
-
body: instructions`
|
|
80
|
-
Check ${file("eslint.config.ts")} for existing rules.
|
|
81
|
-
Run ${cmd("npm test")} to verify.
|
|
82
|
-
See ${ref("skills/other/SKILL.md")} for format.
|
|
83
|
-
`,
|
|
84
|
-
});
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
| Field | Type | Required | Description |
|
|
88
|
-
| ------------------------ | --------------------------------- | -------- | --------------------------------------------------- |
|
|
89
|
-
| `name` | `string` | yes | Skill name (used in YAML frontmatter) |
|
|
90
|
-
| `description` | `string` | yes | Short description (frontmatter) |
|
|
91
|
-
| `argumentHint` | `string` | no | Hint for the argument (frontmatter) |
|
|
92
|
-
| `disableModelInvocation` | `boolean` | no | Disable model invocation flag (frontmatter) |
|
|
93
|
-
| `body` | `string \| InstructionFragment[]` | yes | Instruction body -- plain string or tagged template |
|
|
94
|
-
|
|
95
|
-
## Reference Helpers
|
|
96
|
-
|
|
97
|
-
Reference helpers create branded types that the compiler validates at compile time.
|
|
98
|
-
|
|
99
|
-
### `file(path)`
|
|
100
|
-
|
|
101
|
-
Returns a `FileRef` containing a `VerifiedPath`. The path is verified to exist via `existsSync` at compile time. Compiles to a backtick path in markdown: `` `path/to/file.ts` ``.
|
|
102
|
-
|
|
103
|
-
### `cmd(command)`
|
|
104
|
-
|
|
105
|
-
Returns a `CmdRef` containing a `VerifiedCmd`. For npm commands, the script is verified against `package.json` at compile time. Compiles to a backtick command: `` `npm run build` ``.
|
|
106
|
-
|
|
107
|
-
### `ref(path)`
|
|
108
|
-
|
|
109
|
-
Returns a `SkillRef` containing a `VerifiedRef`. The path is verified to exist at compile time. Compiles to a markdown link: `[dirname](path)`.
|
|
110
|
-
|
|
111
|
-
### `instructions`
|
|
112
|
-
|
|
113
|
-
Tagged template literal that interleaves strings and refs. Use it for `sections` values in `claude()` or the `body` of `skill()`.
|
|
114
|
-
|
|
115
|
-
```ts
|
|
116
|
-
instructions`Check ${file("tsconfig.json")} then run ${cmd("npm test")}.`;
|
|
117
|
-
// Returns InstructionFragment[] -- the compiler renders and validates each ref.
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Rule Types
|
|
121
|
-
|
|
122
|
-
### `enforce(linterRule, why)`
|
|
123
|
-
|
|
124
|
-
Declares a rule delegated to an external linter. The `linterRule` accepts template literal types:
|
|
125
|
-
|
|
126
|
-
- `${BuiltinLinter}/${string}` where BuiltinLinter is `eslint`, `stylelint`, `ruff`, `clippy`, `pylint`, or `rubocop`
|
|
127
|
-
- `@${scope}/${rule}` for scoped ESLint plugins (e.g., `@typescript-eslint/no-explicit-any`)
|
|
128
|
-
|
|
129
|
-
At compile time, vigiles verifies the rule exists in the linter's catalog and is enabled in the project's config. Compiles to `**Enforced by:** ` followed by the linter rule in backticks.
|
|
130
|
-
|
|
131
|
-
```ts
|
|
132
|
-
rules: {
|
|
133
|
-
"no-console-log": enforce("eslint/no-console", "Use structured logger."),
|
|
134
|
-
"no-print": enforce("ruff/T201", "Use logging module."),
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### `guidance(text)`
|
|
139
|
-
|
|
140
|
-
Declares a prose-only rule with no mechanical enforcement. Guidance rules still participate in the monotonicity proof system: once a rule exists, it can be strengthened ( `guidance` → `enforce` ) but never weakened or removed without an explicit allowlist.
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
rules: {
|
|
144
|
-
"prefer-composition": guidance("Prefer composition over inheritance."),
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
Compiles to: `**Guidance only** -- <text>`.
|
|
149
|
-
|
|
150
|
-
## Branded Types
|
|
151
|
-
|
|
152
|
-
`VerifiedPath`, `VerifiedCmd`, and `VerifiedRef` are branded string types (`string & { readonly [__brand]: "..." }`). They distinguish compiler-verified references from raw strings.
|
|
153
|
-
|
|
154
|
-
- `file()` produces `FileRef` containing `VerifiedPath`
|
|
155
|
-
- `cmd()` produces `CmdRef` containing `VerifiedCmd`
|
|
156
|
-
- `ref()` produces `SkillRef` containing `VerifiedRef`
|
|
157
|
-
|
|
158
|
-
The compiler only accepts these branded types in path-sensitive positions. This prevents passing unverified strings where a verified reference is expected -- the TypeScript compiler catches the error at authoring time.
|
|
159
|
-
|
|
160
|
-
## Configuration
|
|
161
|
-
|
|
162
|
-
Create `vigiles.config.ts` with `defineConfig()`:
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
import { defineConfig } from "vigiles";
|
|
166
|
-
|
|
167
|
-
export default defineConfig({
|
|
168
|
-
specs: "**/*.spec.ts", // glob pattern for spec discovery (default: "**/*.spec.ts")
|
|
169
|
-
discover: true, // auto-discover linter rules for coverage reporting
|
|
170
|
-
maxRules: 50, // maximum rules per spec file
|
|
171
|
-
maxTokens: 2000, // maximum estimated tokens for compiled output (~4 chars/token)
|
|
172
|
-
});
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
| Option | Type | Description |
|
|
176
|
-
| ----------- | --------- | ------------------------------------------------------- |
|
|
177
|
-
| `specs` | `string` | Glob pattern to discover spec files |
|
|
178
|
-
| `discover` | `boolean` | Auto-discover linter rules for coverage reporting |
|
|
179
|
-
| `maxRules` | `number` | Compilation fails if a spec exceeds this rule count |
|
|
180
|
-
| `maxTokens` | `number` | Compilation fails if estimated tokens exceed this limit |
|
|
181
|
-
|
|
182
|
-
## Hash Verification
|
|
183
|
-
|
|
184
|
-
Every compiled file starts with a SHA-256 integrity hash comment:
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
<!-- vigiles:sha256:a1b2c3d4e5f67890 compiled from CLAUDE.md.spec.ts -->
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
The hash covers the full compiled content (excluding the hash line itself), truncated to 16 hex characters.
|
|
191
|
-
|
|
192
|
-
### `vigiles audit`
|
|
193
|
-
|
|
194
|
-
Verifies that each compiled file's hash matches its content, reports linter rule coverage gaps, and suggests guidance rules that could be upgraded to `enforce()`. If someone manually edits the markdown, the hash will no longer match, and `vigiles audit` reports the file as modified. This ensures the spec remains the source of truth.
|
package/eslint.config.mjs
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import eslint from "@eslint/js";
|
|
2
|
-
import tseslint from "@typescript-eslint/eslint-plugin";
|
|
3
|
-
import tsparser from "@typescript-eslint/parser";
|
|
4
|
-
import sonarjs from "eslint-plugin-sonarjs";
|
|
5
|
-
import globals from "globals";
|
|
6
|
-
|
|
7
|
-
export default [
|
|
8
|
-
{
|
|
9
|
-
ignores: ["dist/", "node_modules/"],
|
|
10
|
-
},
|
|
11
|
-
eslint.configs.recommended,
|
|
12
|
-
{
|
|
13
|
-
files: ["src/**/*.ts"],
|
|
14
|
-
languageOptions: {
|
|
15
|
-
parser: tsparser,
|
|
16
|
-
globals: {
|
|
17
|
-
...globals.node,
|
|
18
|
-
},
|
|
19
|
-
parserOptions: {
|
|
20
|
-
projectService: true,
|
|
21
|
-
tsconfigRootDir: import.meta.dirname,
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
plugins: {
|
|
25
|
-
"@typescript-eslint": tseslint,
|
|
26
|
-
sonarjs,
|
|
27
|
-
},
|
|
28
|
-
rules: {
|
|
29
|
-
...tseslint.configs["strict-type-checked"]?.rules,
|
|
30
|
-
// TypeScript handles these better than ESLint
|
|
31
|
-
"no-undef": "off",
|
|
32
|
-
"no-unused-vars": "off",
|
|
33
|
-
// Allow unused vars prefixed with _
|
|
34
|
-
"@typescript-eslint/no-unused-vars": [
|
|
35
|
-
"error",
|
|
36
|
-
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
37
|
-
],
|
|
38
|
-
// We use createRequire legitimately for linter detection
|
|
39
|
-
"@typescript-eslint/no-require-imports": "off",
|
|
40
|
-
// Relax some strict rules that are too noisy for this codebase
|
|
41
|
-
"@typescript-eslint/restrict-template-expressions": "off",
|
|
42
|
-
"@typescript-eslint/no-unnecessary-condition": "off",
|
|
43
|
-
// Ban non-null assertions — use proper narrowing instead
|
|
44
|
-
"@typescript-eslint/no-non-null-assertion": "error",
|
|
45
|
-
|
|
46
|
-
// --- Complexity rules ---
|
|
47
|
-
complexity: ["warn", { max: 15 }],
|
|
48
|
-
"max-depth": ["warn", { max: 4 }],
|
|
49
|
-
"max-lines-per-function": [
|
|
50
|
-
"warn",
|
|
51
|
-
{ max: 80, skipBlankLines: true, skipComments: true },
|
|
52
|
-
],
|
|
53
|
-
"max-params": ["warn", { max: 4 }],
|
|
54
|
-
|
|
55
|
-
// --- SonarJS ---
|
|
56
|
-
"sonarjs/cognitive-complexity": ["warn", 15],
|
|
57
|
-
"sonarjs/no-duplicate-string": ["warn", { threshold: 4 }],
|
|
58
|
-
"sonarjs/no-identical-functions": "warn",
|
|
59
|
-
"sonarjs/no-duplicated-branches": "warn",
|
|
60
|
-
"sonarjs/no-identical-conditions": "error",
|
|
61
|
-
"sonarjs/no-identical-expressions": "error",
|
|
62
|
-
"sonarjs/no-nested-conditional": "warn",
|
|
63
|
-
"sonarjs/nested-control-flow": ["warn", { maximumNestingLevel: 3 }],
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
// Test files: relax promise, assertion, and complexity rules
|
|
67
|
-
{
|
|
68
|
-
files: ["src/**/*.test.ts"],
|
|
69
|
-
rules: {
|
|
70
|
-
// node:test describe/it return promises that don't need to be awaited
|
|
71
|
-
"@typescript-eslint/no-floating-promises": "off",
|
|
72
|
-
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
|
73
|
-
// Tests are naturally longer and more repetitive
|
|
74
|
-
"max-lines-per-function": "off",
|
|
75
|
-
"sonarjs/no-duplicate-string": "off",
|
|
76
|
-
"sonarjs/no-identical-functions": "off",
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
];
|
package/examples/CLAUDE.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
<!-- vigiles:sha256:f683550dbdfab721 compiled from examples/CLAUDE.md.spec.ts -->
|
|
2
|
-
|
|
3
|
-
# CLAUDE.md
|
|
4
|
-
|
|
5
|
-
## Positioning
|
|
6
|
-
|
|
7
|
-
vigiles compiles `.spec.ts` files to instruction files (CLAUDE.md, AGENTS.md, or any markdown target). The spec is the source of truth. The markdown is a build artifact.
|
|
8
|
-
|
|
9
|
-
The linter cross-referencing engine is the core moat: `enforce("@typescript-eslint/no-floating-promises")` verifies the rule exists AND is enabled in your linter config. Same for ESLint, Ruff, Clippy, Pylint, RuboCop, and Stylelint.
|
|
10
|
-
|
|
11
|
-
`generate-types` is the second moat: scans all 6 linter APIs, package.json, and project files to emit a `.d.ts` with type unions. The TS compiler then PROVES references are valid at authoring time — typos become type errors, not runtime surprises.
|
|
12
|
-
|
|
13
|
-
## Architecture
|
|
14
|
-
|
|
15
|
-
Three rule types in specs: `enforce()` (delegated to external tool), `check()` (vigiles-owned filesystem assertion), `guidance()` (prose only).
|
|
16
|
-
|
|
17
|
-
Core modules: `src/spec.ts` (types + builders), `src/compile.ts` (compiler), `src/linters.ts` (6-linter cross-referencing engine), `src/generate-types.ts` (type generator).
|
|
18
|
-
|
|
19
|
-
## Key Files
|
|
20
|
-
|
|
21
|
-
- `src/spec.ts` — Type system and builder functions
|
|
22
|
-
- `src/compile.ts` — Compiler: spec → markdown with SHA-256 hash
|
|
23
|
-
- `src/linters.ts` — Linter cross-referencing engine (6 linters)
|
|
24
|
-
- `src/generate-types.ts` — Type generator: project state → .d.ts
|
|
25
|
-
- `src/cli.ts` — CLI: compile, check, init, generate-types, discover, adopt
|
|
26
|
-
|
|
27
|
-
## Commands
|
|
28
|
-
|
|
29
|
-
- `npm run build` — Compile TypeScript to dist/
|
|
30
|
-
- `npm test` — Build and run all tests
|
|
31
|
-
- `npm run fmt` — Format with prettier
|
|
32
|
-
- `npm run fmt:check` — Check formatting
|
|
33
|
-
|
|
34
|
-
## Rules
|
|
35
|
-
|
|
36
|
-
### Zero Config By Default
|
|
37
|
-
|
|
38
|
-
**Guidance only** — vigiles compile should work with just a .spec.ts file. Config exists only for overrides (maxRules, maxTokens, catalogOnly).
|
|
39
|
-
|
|
40
|
-
### Never Skip Tests
|
|
41
|
-
|
|
42
|
-
**Guidance only** — All tests must pass. If a test requires a CLI tool (pylint, rubocop, ruff, clippy), install the tool, don't skip the test.
|
|
43
|
-
|
|
44
|
-
### Dont Reimplement Linters
|
|
45
|
-
|
|
46
|
-
**Guidance only** — Architectural linting belongs in ast-grep/Dependency Cruiser/Steiger. Per-file code rules belong in ESLint/Ruff/Clippy. vigiles owns: compilation, linter cross-referencing, type generation, filesystem assertions, and stale reference detection.
|
|
47
|
-
|
|
48
|
-
### Format Before Commit
|
|
49
|
-
|
|
50
|
-
**Guidance only** — Run `npm run fmt:check` before committing. Inline code spans in markdown need surrounding spaces to render correctly.
|
|
51
|
-
|
|
52
|
-
### No Session Links
|
|
53
|
-
|
|
54
|
-
**Guidance only** — This is a public repo. Claude Code session URLs are private and must not appear in commits or PRs.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example: CLAUDE.md specification for the vigiles project itself.
|
|
3
|
-
*
|
|
4
|
-
* This is the source of truth. CLAUDE.md is a compiled build artifact.
|
|
5
|
-
* Run `vigiles compile` to generate CLAUDE.md from this spec.
|
|
6
|
-
*/
|
|
7
|
-
import { claude, guidance } from "../src/spec.js";
|
|
8
|
-
|
|
9
|
-
export default claude({
|
|
10
|
-
sections: {
|
|
11
|
-
positioning: `vigiles compiles \`.spec.ts\` files to instruction files (CLAUDE.md, AGENTS.md, or any markdown target). The spec is the source of truth. The markdown is a build artifact.
|
|
12
|
-
|
|
13
|
-
The linter cross-referencing engine is the core moat: \`enforce("@typescript-eslint/no-floating-promises")\` verifies the rule exists AND is enabled in your linter config. Same for ESLint, Ruff, Clippy, Pylint, RuboCop, and Stylelint.
|
|
14
|
-
|
|
15
|
-
\`generate-types\` is the second moat: scans all 6 linter APIs, package.json, and project files to emit a \`.d.ts\` with type unions. The TS compiler then PROVES references are valid at authoring time — typos become type errors, not runtime surprises.`,
|
|
16
|
-
|
|
17
|
-
architecture: `Three rule types in specs: \`enforce()\` (delegated to external tool), \`check()\` (vigiles-owned filesystem assertion), \`guidance()\` (prose only).
|
|
18
|
-
|
|
19
|
-
Core modules: \`src/spec.ts\` (types + builders), \`src/compile.ts\` (compiler), \`src/linters.ts\` (6-linter cross-referencing engine), \`src/generate-types.ts\` (type generator).`,
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
keyFiles: {
|
|
23
|
-
"src/spec.ts": "Type system and builder functions",
|
|
24
|
-
"src/compile.ts": "Compiler: spec → markdown with SHA-256 hash",
|
|
25
|
-
"src/linters.ts": "Linter cross-referencing engine (6 linters)",
|
|
26
|
-
"src/generate-types.ts": "Type generator: project state → .d.ts",
|
|
27
|
-
"src/cli.ts": "CLI: compile, check, init, generate-types, discover, adopt",
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
commands: {
|
|
31
|
-
"npm run build": "Compile TypeScript to dist/",
|
|
32
|
-
"npm test": "Build and run all tests",
|
|
33
|
-
"npm run fmt": "Format with prettier",
|
|
34
|
-
"npm run fmt:check": "Check formatting",
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
rules: {
|
|
38
|
-
"zero-config-by-default": guidance(
|
|
39
|
-
"vigiles compile should work with just a .spec.ts file. Config exists only for overrides (maxRules, maxTokens, catalogOnly).",
|
|
40
|
-
),
|
|
41
|
-
|
|
42
|
-
"never-skip-tests": guidance(
|
|
43
|
-
"All tests must pass. If a test requires a CLI tool (pylint, rubocop, ruff, clippy), install the tool, don't skip the test.",
|
|
44
|
-
),
|
|
45
|
-
|
|
46
|
-
"dont-reimplement-linters": guidance(
|
|
47
|
-
"Architectural linting belongs in ast-grep/Dependency Cruiser/Steiger. Per-file code rules belong in ESLint/Ruff/Clippy. vigiles owns: compilation, linter cross-referencing, type generation, filesystem assertions, and stale reference detection.",
|
|
48
|
-
),
|
|
49
|
-
|
|
50
|
-
"format-before-commit": guidance(
|
|
51
|
-
"Run `npm run fmt:check` before committing. Inline code spans in markdown need surrounding spaces to render correctly.",
|
|
52
|
-
),
|
|
53
|
-
|
|
54
|
-
"no-session-links": guidance(
|
|
55
|
-
"This is a public repo. Claude Code session URLs are private and must not appear in commits or PRs.",
|
|
56
|
-
),
|
|
57
|
-
|
|
58
|
-
// Example: check() rule (commented out because this is a demo spec,
|
|
59
|
-
// not the project's actual spec — see root CLAUDE.md.spec.ts)
|
|
60
|
-
// "test-file-pairing": check(
|
|
61
|
-
// every("src/**/!(*test|*spec).ts").has("{name}.test.ts"),
|
|
62
|
-
// "Every source module should have a corresponding test file.",
|
|
63
|
-
// ),
|
|
64
|
-
},
|
|
65
|
-
});
|
package/examples/SKILL.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<!-- vigiles:sha256:da271d5e41e8e90e compiled from examples/SKILL.md.spec.ts -->
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
name: pr-to-lint-rule
|
|
6
|
-
description: Convert a recurring PR review comment into an automated lint rule with tests and CLAUDE.md annotation
|
|
7
|
-
disable-model-invocation: true
|
|
8
|
-
argument-hint: <description of recurring PR feedback>
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
Convert a recurring PR review comment into an automated lint rule.
|
|
13
|
-
|
|
14
|
-
## Arguments
|
|
15
|
-
|
|
16
|
-
$ARGUMENTS — A natural language description of the pattern to enforce. Examples:
|
|
17
|
-
|
|
18
|
-
- "we keep telling people not to import directly from antd, use our design system barrel file instead"
|
|
19
|
-
- "people forget to use our custom logger instead of console.log"
|
|
20
|
-
- "don't use unwrap() in production code, use expect() or proper error handling"
|
|
21
|
-
- "API route handlers must use the withAuth wrapper"
|
|
22
|
-
|
|
23
|
-
## Instructions
|
|
24
|
-
|
|
25
|
-
You are generating an automated lint rule from a recurring code review pattern. Follow these steps:
|
|
26
|
-
|
|
27
|
-
### Step 1: Detect the Project Language and Toolchain
|
|
28
|
-
|
|
29
|
-
Look at the repository to determine:
|
|
30
|
-
|
|
31
|
-
- **Primary language** (JS/TS, Python, Rust, Go, Ruby, etc.)
|
|
32
|
-
- **Linter in use** (ESLint, Ruff, Clippy, golangci-lint, RuboCop, etc.)
|
|
33
|
-
- **Testing framework** (Vitest, Jest, pytest, cargo test, etc.)
|
|
34
|
-
- **Existing custom rules** (to match conventions)
|
|
35
|
-
|
|
36
|
-
**If the language or linter cannot be confidently detected**, **ask the user** which language and linter to target before generating anything.
|
|
37
|
-
|
|
38
|
-
### Step 2: Generate the Lint Rule
|
|
39
|
-
|
|
40
|
-
Based on the detected (or user-specified) language, generate the appropriate rule type.
|
|
41
|
-
|
|
42
|
-
For JavaScript/TypeScript, generate an ESLint rule using the AST visitor pattern with `meta` and `create(context)`.
|
|
43
|
-
|
|
44
|
-
### Step 3: Update `CLAUDE.md`
|
|
45
|
-
|
|
46
|
-
Add the annotation block. See [enforce-rules-format](skills/enforce-rules-format/SKILL.md) for the correct format.
|
|
47
|
-
|
|
48
|
-
### Step 4: Verify
|
|
49
|
-
|
|
50
|
-
Run `npm test` to ensure the new rule and tests pass.
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example: SKILL.md specification for the pr-to-lint-rule skill.
|
|
3
|
-
*
|
|
4
|
-
* This is the source of truth. SKILL.md is a compiled build artifact.
|
|
5
|
-
* Run `vigiles compile` to generate SKILL.md from this spec.
|
|
6
|
-
*/
|
|
7
|
-
import { skill, file, cmd, ref, instructions } from "../src/spec.js";
|
|
8
|
-
|
|
9
|
-
export default skill({
|
|
10
|
-
name: "pr-to-lint-rule",
|
|
11
|
-
description:
|
|
12
|
-
"Convert a recurring PR review comment into an automated lint rule with tests and CLAUDE.md annotation",
|
|
13
|
-
disableModelInvocation: true,
|
|
14
|
-
argumentHint: "<description of recurring PR feedback>",
|
|
15
|
-
|
|
16
|
-
body: instructions`
|
|
17
|
-
Convert a recurring PR review comment into an automated lint rule.
|
|
18
|
-
|
|
19
|
-
## Arguments
|
|
20
|
-
|
|
21
|
-
$ARGUMENTS — A natural language description of the pattern to enforce. Examples:
|
|
22
|
-
|
|
23
|
-
- "we keep telling people not to import directly from antd, use our design system barrel file instead"
|
|
24
|
-
- "people forget to use our custom logger instead of console.log"
|
|
25
|
-
- "don't use unwrap() in production code, use expect() or proper error handling"
|
|
26
|
-
- "API route handlers must use the withAuth wrapper"
|
|
27
|
-
|
|
28
|
-
## Instructions
|
|
29
|
-
|
|
30
|
-
You are generating an automated lint rule from a recurring code review pattern. Follow these steps:
|
|
31
|
-
|
|
32
|
-
### Step 1: Detect the Project Language and Toolchain
|
|
33
|
-
|
|
34
|
-
Look at the repository to determine:
|
|
35
|
-
|
|
36
|
-
- **Primary language** (JS/TS, Python, Rust, Go, Ruby, etc.)
|
|
37
|
-
- **Linter in use** (ESLint, Ruff, Clippy, golangci-lint, RuboCop, etc.)
|
|
38
|
-
- **Testing framework** (Vitest, Jest, pytest, cargo test, etc.)
|
|
39
|
-
- **Existing custom rules** (to match conventions)
|
|
40
|
-
|
|
41
|
-
**If the language or linter cannot be confidently detected**, **ask the user** which language and linter to target before generating anything.
|
|
42
|
-
|
|
43
|
-
### Step 2: Generate the Lint Rule
|
|
44
|
-
|
|
45
|
-
Based on the detected (or user-specified) language, generate the appropriate rule type.
|
|
46
|
-
|
|
47
|
-
For JavaScript/TypeScript, generate an ESLint rule using the AST visitor pattern with \`meta\` and \`create(context)\`.
|
|
48
|
-
|
|
49
|
-
### Step 3: Update ${file("CLAUDE.md")}
|
|
50
|
-
|
|
51
|
-
Add the annotation block. See ${ref("skills/enforce-rules-format/SKILL.md")} for the correct format.
|
|
52
|
-
|
|
53
|
-
### Step 4: Verify
|
|
54
|
-
|
|
55
|
-
Run ${cmd("npm test")} to ensure the new rule and tests pass.
|
|
56
|
-
`,
|
|
57
|
-
});
|
package/logo.png
DELETED
|
Binary file
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# vigiles Adoption Strategy
|
|
2
|
-
|
|
3
|
-
Goal: **`npx vigiles setup && npx skills add zernie/vigiles` works on first run with zero config. The agent starts editing specs automatically — no workflow change required. Start permissive, tighten over time.**
|
|
4
|
-
|
|
5
|
-
### Adoption Principles
|
|
6
|
-
|
|
7
|
-
1. **Works on first run.** Setup must succeed in any project without configuration. Auto-detect everything. Create reasonable defaults. Don't block on missing tools.
|
|
8
|
-
2. **Zero workflow change.** After plugin install, the agent edits specs instead of markdown. The user doesn't need to learn a new workflow — they say "update CLAUDE.md" and the plugin handles the redirect.
|
|
9
|
-
3. **Start permissive, tighten later.** First run creates `guidance()` rules (no enforcement). User upgrades to `enforce()` as they add linter rules. `require-spec: false` available for incremental migration.
|
|
10
|
-
4. **Every surface tells you the next step.** `vigiles check` says "run setup." The hook says "edit the spec." The wizard says "install the plugin." No dead ends.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Scope: What vigiles Does vs. Doesn't
|
|
15
|
-
|
|
16
|
-
vigiles compiles typed TypeScript specs to **markdown instruction files** (CLAUDE.md, AGENTS.md). It verifies linter rules, file paths, and commands at compile time. The compiled markdown is the artifact.
|
|
17
|
-
|
|
18
|
-
**vigiles handles:** CLAUDE.md (Claude Code), AGENTS.md (Codex, GitHub Copilot, any agent that reads AGENTS.md). These are both plain markdown — same compiler, same validation, different `target`.
|
|
19
|
-
|
|
20
|
-
**vigiles does NOT handle:** `.cursorrules`, `.copilot-instructions.md`, Windsurf format, or any non-markdown target. These have different structures. Use [rule-porter](https://github.com/nichochar/rule-porter) or [rulesync](https://github.com/dyoshikawa/rulesync) to convert compiled markdown to those formats. vigiles is the source; sync tools are the distribution layer.
|
|
21
|
-
|
|
22
|
-
**No symlinks needed.** AGENTS.md is a first-class target via `target: "AGENTS.md"` or `target: ["CLAUDE.md", "AGENTS.md"]`. The compiler outputs both from one spec.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## The Setup Wizard
|
|
27
|
-
|
|
28
|
-
`npx vigiles setup` is the single entry point. It does everything:
|
|
29
|
-
|
|
30
|
-
1. **Creates spec** — scaffolds `CLAUDE.md.spec.ts` (or `--target=AGENTS.md` variant)
|
|
31
|
-
2. **Generates types** — scans linters, package.json, project files → `.vigiles/generated.d.ts`
|
|
32
|
-
3. **Compiles** — spec → markdown with SHA-256 hash
|
|
33
|
-
4. **Adds CI step** — finds existing GHA workflow and appends `vigiles check` + `generate-types --check`
|
|
34
|
-
5. **Prompts plugin install** — prints `npx skills add zernie/vigiles` with explanation
|
|
35
|
-
|
|
36
|
-
After setup, the user edits the spec, runs `vigiles compile`, and commits. The plugin handles everything else automatically.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Adoption Levels
|
|
41
|
-
|
|
42
|
-
### Level 0: Discovery
|
|
43
|
-
|
|
44
|
-
User runs `npx vigiles check` on an existing repo. `require-spec` fires: "No spec file found. Run `npx vigiles setup`." First nudge.
|
|
45
|
-
|
|
46
|
-
### Level 1: Setup
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npx vigiles setup
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
One command. Creates spec, types, compiled markdown, CI step. The user has a working pipeline in under a minute.
|
|
53
|
-
|
|
54
|
-
### Level 2: Plugin
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
npx skills add zernie/vigiles
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Two hooks activate:
|
|
61
|
-
|
|
62
|
-
- **PreToolUse**: Blocks direct edits to compiled `.md` files. Agent gets redirected to `.spec.ts`.
|
|
63
|
-
- **PostToolUse**: Auto-runs `generate-types` on config changes, `compile` on spec changes.
|
|
64
|
-
|
|
65
|
-
### Level 3: Multi-Target
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
export default claude({
|
|
69
|
-
target: ["CLAUDE.md", "AGENTS.md"],
|
|
70
|
-
rules: { ... },
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
One spec, multiple outputs. For non-markdown formats, pipe through rule-porter.
|
|
75
|
-
|
|
76
|
-
### Level 4: Type Narrowing
|
|
77
|
-
|
|
78
|
-
Commit `.vigiles/generated.d.ts`. Now `enforce("eslint/no-consolee")` is a type error in the editor. Types narrow `enforce()`, `file()`, `cmd()` via declaration merging.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Pain Points (Updated)
|
|
83
|
-
|
|
84
|
-
| Pain Point | Status | Resolution |
|
|
85
|
-
| --------------------------------- | --------- | ----------------------------------------------- |
|
|
86
|
-
| Multi-step installation | Fixed | `vigiles setup` does everything |
|
|
87
|
-
| No CI integration from wizard | Fixed | Wizard auto-adds GHA step |
|
|
88
|
-
| Plugin not mentioned as important | Fixed | README and wizard both prompt it |
|
|
89
|
-
| Agent edits compiled .md directly | Fixed | PreToolUse hook blocks with redirect |
|
|
90
|
-
| Cursor/Windsurf support | Won't fix | Out of scope — use sync tools |
|
|
91
|
-
| Codex / AGENTS.md | Fixed | First-class target |
|
|
92
|
-
| No interactive mode for agents | Open | `vigiles setup` works non-interactively already |
|
|
93
|
-
|
|
94
|
-
## README Structure
|
|
95
|
-
|
|
96
|
-
The README should have:
|
|
97
|
-
|
|
98
|
-
1. **Hook** — one compelling sentence
|
|
99
|
-
2. **Problem** — realistic example of rot
|
|
100
|
-
3. **Fix** — the spec that catches it
|
|
101
|
-
4. **Quick Start** — `npx vigiles setup` (one command)
|
|
102
|
-
5. **Three Rule Types** — enforce/check/guidance
|
|
103
|
-
6. **Verified References** — file/cmd/ref
|
|
104
|
-
7. **Type-Safe Rule References** — generate-types + narrowing
|
|
105
|
-
8. **CLI** — reference for all commands
|
|
106
|
-
9. **GitHub Action** — CI snippet
|
|
107
|
-
10. **Plugin** — what it does, install command
|
|
108
|
-
11. **Output Targets** — CLAUDE.md, AGENTS.md, multi-target
|
|
109
|
-
12. **Related Tools** — sync tools for non-markdown formats
|
|
110
|
-
|
|
111
|
-
No separate installation steps. The wizard IS the installation.
|