vigiles 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +108 -131
  2. package/dist/cli.js +303 -161
  3. package/dist/compile.d.ts +1 -0
  4. package/dist/compile.js +22 -19
  5. package/dist/coverage.d.ts +56 -0
  6. package/dist/coverage.js +178 -0
  7. package/dist/doc-refs.d.ts +60 -0
  8. package/dist/doc-refs.js +246 -0
  9. package/dist/evolve.js +60 -125
  10. package/dist/frontmatter.d.ts +57 -0
  11. package/dist/frontmatter.js +190 -0
  12. package/dist/generate-schema.d.ts +51 -0
  13. package/dist/generate-schema.js +115 -0
  14. package/dist/generate-types.js +39 -1
  15. package/dist/hash.d.ts +8 -0
  16. package/dist/hash.js +16 -0
  17. package/dist/integrity.d.ts +29 -0
  18. package/dist/integrity.js +44 -0
  19. package/dist/linters.d.ts +5 -3
  20. package/dist/linters.js +116 -4
  21. package/dist/orphans.d.ts +52 -0
  22. package/dist/orphans.js +124 -0
  23. package/dist/proofs.js +22 -16
  24. package/dist/session.d.ts +97 -0
  25. package/dist/session.js +306 -0
  26. package/dist/sidecar.d.ts +35 -0
  27. package/dist/sidecar.js +102 -0
  28. package/dist/spec.d.ts +29 -9
  29. package/dist/spec.js +22 -4
  30. package/dist/test-utils.d.ts +8 -0
  31. package/dist/test-utils.js +41 -0
  32. package/dist/types.d.ts +34 -8
  33. package/dist/types.js +19 -0
  34. package/dist/validate.js +5 -3
  35. package/package.json +14 -2
  36. package/.claude/settings.json +0 -46
  37. package/.claude/settings.local.json +0 -8
  38. package/.github/workflows/ci.yml +0 -81
  39. package/.prettierignore +0 -1
  40. package/.vigiles/generated.d.ts +0 -205
  41. package/CLAUDE.md +0 -95
  42. package/CLAUDE.md.spec.ts +0 -142
  43. package/CONTRIBUTING.md +0 -121
  44. package/dist/action.d.ts.map +0 -1
  45. package/dist/action.js.map +0 -1
  46. package/dist/cli.d.ts.map +0 -1
  47. package/dist/cli.js.map +0 -1
  48. package/dist/cli.test.d.ts +0 -2
  49. package/dist/cli.test.d.ts.map +0 -1
  50. package/dist/cli.test.js +0 -650
  51. package/dist/cli.test.js.map +0 -1
  52. package/dist/compile.d.ts.map +0 -1
  53. package/dist/compile.js.map +0 -1
  54. package/dist/evolve.d.ts.map +0 -1
  55. package/dist/evolve.js.map +0 -1
  56. package/dist/freshness.d.ts +0 -67
  57. package/dist/freshness.d.ts.map +0 -1
  58. package/dist/freshness.js +0 -244
  59. package/dist/freshness.js.map +0 -1
  60. package/dist/freshness.test.d.ts +0 -2
  61. package/dist/freshness.test.d.ts.map +0 -1
  62. package/dist/freshness.test.js +0 -356
  63. package/dist/freshness.test.js.map +0 -1
  64. package/dist/generate-types.d.ts.map +0 -1
  65. package/dist/generate-types.js.map +0 -1
  66. package/dist/inline.d.ts.map +0 -1
  67. package/dist/inline.js.map +0 -1
  68. package/dist/inline.test.d.ts +0 -5
  69. package/dist/inline.test.d.ts.map +0 -1
  70. package/dist/inline.test.js +0 -152
  71. package/dist/inline.test.js.map +0 -1
  72. package/dist/linters.d.ts.map +0 -1
  73. package/dist/linters.js.map +0 -1
  74. package/dist/proofs.d.ts.map +0 -1
  75. package/dist/proofs.js.map +0 -1
  76. package/dist/proofs.test.d.ts +0 -9
  77. package/dist/proofs.test.d.ts.map +0 -1
  78. package/dist/proofs.test.js +0 -952
  79. package/dist/proofs.test.js.map +0 -1
  80. package/dist/spec.d.ts.map +0 -1
  81. package/dist/spec.js.map +0 -1
  82. package/dist/spec.test.d.ts +0 -2
  83. package/dist/spec.test.d.ts.map +0 -1
  84. package/dist/spec.test.js +0 -1222
  85. package/dist/spec.test.js.map +0 -1
  86. package/dist/types.d.ts.map +0 -1
  87. package/dist/types.js.map +0 -1
  88. package/dist/validate.d.ts.map +0 -1
  89. package/dist/validate.js.map +0 -1
  90. package/dist/validate.test.d.ts +0 -2
  91. package/dist/validate.test.d.ts.map +0 -1
  92. package/dist/validate.test.js +0 -531
  93. package/dist/validate.test.js.map +0 -1
  94. package/docs/agent-setup.md +0 -85
  95. package/docs/agent-workflows.md +0 -103
  96. package/docs/comparison.md +0 -71
  97. package/docs/freshness.md +0 -124
  98. package/docs/inline-mode.md +0 -119
  99. package/docs/linter-support.md +0 -166
  100. package/docs/spec-format.md +0 -194
  101. package/eslint.config.mjs +0 -79
  102. package/examples/CLAUDE.md +0 -54
  103. package/examples/CLAUDE.md.spec.ts +0 -65
  104. package/examples/SKILL.md +0 -50
  105. package/examples/SKILL.md.spec.ts +0 -57
  106. package/fixtures/example-project/CLAUDE.md +0 -11
  107. package/fixtures/example-project/package.json +0 -9
  108. package/fixtures/example-project/src/index.ts +0 -3
  109. package/fixtures/example-project/src/utils.test.ts +0 -2
  110. package/fixtures/example-project/src/utils.ts +0 -3
  111. package/logo.png +0 -0
  112. package/research/adoption-strategy.md +0 -111
  113. package/research/agent-integration.md +0 -145
  114. package/research/ai-code-quality.md +0 -197
  115. package/research/code-search-for-agents.md +0 -313
  116. package/research/competitive-landscape.md +0 -163
  117. package/research/doc-freshness.md +0 -516
  118. package/research/executable-specs.md +0 -368
  119. package/research/feature-ideas.md +0 -464
  120. package/research/formal-proofs-for-agents.md +0 -338
  121. package/research/fp-for-agent-harness.md +0 -150
  122. package/research/fp-for-deterministic-ai.md +0 -131
  123. package/research/self-evolving-specs.md +0 -298
  124. package/schemas/claude-md-strict.yml +0 -18
  125. package/schemas/claude-md.yml +0 -6
  126. package/schemas/skill-strict.yml +0 -12
  127. package/schemas/skill.yml +0 -5
  128. package/skills/audit-feedback-loop/SKILL.md +0 -76
  129. package/skills/edit-spec/SKILL.md +0 -131
  130. package/skills/enforce-rules-format/SKILL.md +0 -71
  131. package/skills/generate-logo/SKILL.md +0 -102
  132. package/skills/generate-rule/SKILL.md +0 -90
  133. package/skills/linter-docs/clippy.md +0 -241
  134. package/skills/linter-docs/eslint.md +0 -384
  135. package/skills/linter-docs/pylint.md +0 -288
  136. package/skills/linter-docs/rubocop.md +0 -277
  137. package/skills/linter-docs/ruff.md +0 -187
  138. package/skills/linter-docs/stylelint.md +0 -247
  139. package/skills/migrate-to-spec/SKILL.md +0 -124
  140. package/skills/pr-to-lint-rule/SKILL.md +0 -97
  141. package/skills/strengthen/SKILL.md +0 -168
  142. package/src/action.ts +0 -214
  143. package/src/cli.test.ts +0 -914
  144. package/src/cli.ts +0 -1631
  145. package/src/compile.ts +0 -691
  146. package/src/evolve.ts +0 -781
  147. package/src/freshness.test.ts +0 -449
  148. package/src/freshness.ts +0 -299
  149. package/src/generate-types.ts +0 -448
  150. package/src/inline.test.ts +0 -206
  151. package/src/inline.ts +0 -164
  152. package/src/linters.ts +0 -739
  153. package/src/proofs.test.ts +0 -1314
  154. package/src/proofs.ts +0 -849
  155. package/src/spec.test.ts +0 -1471
  156. package/src/spec.ts +0 -427
  157. package/src/types.ts +0 -117
  158. package/src/validate.test.ts +0 -701
  159. package/src/validate.ts +0 -381
  160. package/tsconfig.json +0 -23
package/src/validate.ts DELETED
@@ -1,381 +0,0 @@
1
- import { readFileSync, lstatSync, existsSync } from "node:fs";
2
- import { globSync } from "glob";
3
- import { resolve, basename as pathBasename } from "node:path";
4
- import { cosmiconfigSync } from "cosmiconfig";
5
-
6
- import { hasInlineRules } from "./inline.js";
7
-
8
- import type {
9
- ParsedRule,
10
- ValidationError,
11
- ValidationResult,
12
- ReadResult,
13
- FileResult,
14
- ValidatePathsResult,
15
- RulesConfig,
16
- VigilesConfig,
17
- MarkerType,
18
- ParseOptions,
19
- ValidateOptions,
20
- ValidatePathsOptions,
21
- ReadOptions,
22
- } from "./types.js";
23
-
24
- // Re-export all types for consumers
25
- export type {
26
- ParsedRule,
27
- ValidationError,
28
- ValidationResult,
29
- ReadResult,
30
- FileResult,
31
- ValidatePathsResult,
32
- RulesConfig,
33
- VigilesConfig,
34
- MarkerType,
35
- ParseOptions,
36
- ValidateOptions,
37
- ValidatePathsOptions,
38
- ReadOptions,
39
- };
40
-
41
- // ---------------------------------------------------------------------------
42
- // Constants & regex
43
- // ---------------------------------------------------------------------------
44
-
45
- const GUIDANCE_RE = /\*\*Guidance only\*\*/;
46
- const DISABLE_RE = /<!--\s*vigiles-disable\s*-->/;
47
- const RULE_HEADER_RE = /^###\s+(.+)$/;
48
- const CHECKBOX_RE = /^- \[([ xX])\]\s+(.+)$/;
49
-
50
- const VALID_MARKERS: readonly MarkerType[] = ["headings", "checkboxes"];
51
-
52
- // ---------------------------------------------------------------------------
53
- // Default config
54
- // ---------------------------------------------------------------------------
55
-
56
- const DEFAULT_FILES: string[] = ["CLAUDE.md"];
57
-
58
- const DEFAULT_RULES: Required<RulesConfig> = {
59
- "require-spec": "warn",
60
- "require-skill-spec": "warn",
61
- freshness: "warn",
62
- };
63
-
64
- const DEFAULT_CONFIG: VigilesConfig = {
65
- ruleMarkers: ["headings", "checkboxes"],
66
- rules: DEFAULT_RULES,
67
- files: DEFAULT_FILES,
68
- };
69
-
70
- // ---------------------------------------------------------------------------
71
- // Instruction file discovery
72
- // ---------------------------------------------------------------------------
73
-
74
- export function findInstructionFiles(
75
- cwd: string = process.cwd(),
76
- configFiles?: string[],
77
- ): string[] {
78
- const candidates = configFiles ?? DEFAULT_FILES;
79
- return candidates.filter((f) => existsSync(resolve(cwd, f)));
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Config loading
84
- // ---------------------------------------------------------------------------
85
-
86
- export function loadConfig(): VigilesConfig {
87
- try {
88
- const explorer = cosmiconfigSync("vigiles", {
89
- searchPlaces: [".vigilesrc.json"],
90
- mergeSearchPlaces: false,
91
- });
92
- const result = explorer.search();
93
- if (!result?.config) return { ...DEFAULT_CONFIG };
94
-
95
- const userConfig = result.config as Partial<VigilesConfig> & {
96
- rules?: Partial<RulesConfig>;
97
- };
98
-
99
- const config: VigilesConfig = {
100
- ...DEFAULT_CONFIG,
101
- ...userConfig,
102
- rules: { ...DEFAULT_RULES, ...userConfig.rules },
103
- files: Array.isArray(userConfig.files) ? userConfig.files : DEFAULT_FILES,
104
- };
105
-
106
- if (
107
- !Array.isArray(config.ruleMarkers) ||
108
- !config.ruleMarkers.every((m): m is MarkerType =>
109
- (VALID_MARKERS as readonly string[]).includes(m),
110
- )
111
- ) {
112
- console.warn(
113
- `Invalid ruleMarkers in config: ${JSON.stringify(config.ruleMarkers)}. Using default.`,
114
- );
115
- config.ruleMarkers = [...DEFAULT_CONFIG.ruleMarkers];
116
- }
117
-
118
- return config;
119
- } catch {
120
- return { ...DEFAULT_CONFIG };
121
- }
122
- }
123
-
124
- // ---------------------------------------------------------------------------
125
- // Parsing
126
- // ---------------------------------------------------------------------------
127
-
128
- export function parseRules(
129
- content: string,
130
- { ruleMarkers }: ParseOptions = {},
131
- ): ParsedRule[] {
132
- const markers = ruleMarkers ?? DEFAULT_CONFIG.ruleMarkers;
133
- const lines = content.split("\n");
134
- const rules: ParsedRule[] = [];
135
-
136
- let currentRule: ParsedRule | null = null;
137
-
138
- for (let i = 0; i < lines.length; i++) {
139
- const line = lines[i];
140
- const headerMatch = markers.includes("headings")
141
- ? line.match(RULE_HEADER_RE)
142
- : null;
143
- const checkboxMatch = markers.includes("checkboxes")
144
- ? line.match(CHECKBOX_RE)
145
- : null;
146
-
147
- if (headerMatch ?? checkboxMatch) {
148
- if (currentRule) {
149
- rules.push(currentRule);
150
- }
151
- const title = headerMatch
152
- ? headerMatch[1].trim()
153
- : (checkboxMatch as RegExpMatchArray)[2].trim();
154
- currentRule = {
155
- title,
156
- line: i + 1,
157
- enforcement: "missing",
158
- enforcedBy: null,
159
- };
160
- continue;
161
- }
162
-
163
- if (!currentRule || currentRule.enforcement !== "missing") continue;
164
-
165
- const enforcedMatch = line.match(/\*\*Enforced by:\*\*\s*`([^`]+)`/);
166
- if (enforcedMatch) {
167
- currentRule.enforcement = "enforced";
168
- currentRule.enforcedBy = enforcedMatch[1] ?? null;
169
- continue;
170
- }
171
-
172
- if (GUIDANCE_RE.test(line)) {
173
- currentRule.enforcement = "guidance";
174
- continue;
175
- }
176
-
177
- if (DISABLE_RE.test(line)) {
178
- currentRule.enforcement = "disabled";
179
- continue;
180
- }
181
- }
182
-
183
- if (currentRule) {
184
- rules.push(currentRule);
185
- }
186
-
187
- return rules;
188
- }
189
-
190
- // ---------------------------------------------------------------------------
191
- // Core validation
192
- // ---------------------------------------------------------------------------
193
-
194
- export function validate(
195
- content: string,
196
- { ruleMarkers, rules: rulesConfig, filePath }: ValidateOptions = {},
197
- ): ValidationResult {
198
- const activeRules = rulesConfig ?? DEFAULT_RULES;
199
- const parsedRules = parseRules(content, { ruleMarkers });
200
- const enforced = parsedRules.filter(
201
- (r) => r.enforcement === "enforced",
202
- ).length;
203
- const guidanceOnly = parsedRules.filter(
204
- (r) => r.enforcement === "guidance",
205
- ).length;
206
- const disabled = parsedRules.filter(
207
- (r) => r.enforcement === "disabled",
208
- ).length;
209
- const missingCount = parsedRules.filter(
210
- (r) => r.enforcement === "missing",
211
- ).length;
212
-
213
- const errors: ValidationError[] = [];
214
- const warnings: ValidationError[] = [];
215
- const disableComment = /<!--\s*vigiles-disable\s+require-spec\s*-->/;
216
-
217
- if (filePath) {
218
- const basename = pathBasename(filePath);
219
- const isInstruction = basename === "CLAUDE.md" || basename === "AGENTS.md";
220
- const isSkill = basename === "SKILL.md";
221
-
222
- // --- require-spec (CLAUDE.md / AGENTS.md) ---
223
- const specSeverity = activeRules["require-spec"];
224
- if (specSeverity && isInstruction && !disableComment.test(content)) {
225
- const specPath = filePath + ".spec.ts";
226
- // Inline mode counts as a spec — any parseable
227
- // `<!-- vigiles:enforce ... -->` comment means the file is
228
- // verified on `vigiles audit` even without a .spec.ts sibling.
229
- // Delegate to the real parser so a malformed marker can't
230
- // satisfy require-spec with a rule that audit can't verify.
231
- const hasInline = hasInlineRules(content);
232
- if (!existsSync(specPath) && !hasInline) {
233
- const msg: ValidationError = {
234
- rule: "require-spec",
235
- message: `No spec file found for "${filePath}". Expected "${specPath}". Run \`npx vigiles init --target=${filePath}\` to create one, add inline \`<!-- vigiles:enforce ... -->\` comments, or disable with <!-- vigiles-disable require-spec -->.`,
236
- line: 1,
237
- };
238
- if (specSeverity === "error") {
239
- errors.push(msg);
240
- } else {
241
- warnings.push(msg);
242
- }
243
- }
244
- }
245
-
246
- // --- require-skill-spec (SKILL.md) ---
247
- const skillSeverity = activeRules["require-skill-spec"];
248
- if (skillSeverity && isSkill && !disableComment.test(content)) {
249
- const specPath = filePath + ".spec.ts";
250
- if (!existsSync(specPath)) {
251
- const msg: ValidationError = {
252
- rule: "require-skill-spec",
253
- message: `No spec file found for "${filePath}". Expected "${specPath}".`,
254
- line: 1,
255
- };
256
- if (skillSeverity === "error") {
257
- errors.push(msg);
258
- } else {
259
- warnings.push(msg);
260
- }
261
- }
262
- }
263
- }
264
-
265
- return {
266
- rules: parsedRules,
267
- enforced,
268
- guidanceOnly,
269
- disabled,
270
- missing: missingCount,
271
- total: parsedRules.length,
272
- errors,
273
- warnings,
274
- valid: errors.length === 0,
275
- };
276
- }
277
-
278
- // ---------------------------------------------------------------------------
279
- // File reading
280
- // ---------------------------------------------------------------------------
281
-
282
- export function readInstructionFile(
283
- filePath: string,
284
- options: ReadOptions = {},
285
- ): ReadResult {
286
- try {
287
- const stat = lstatSync(filePath);
288
- if (stat.isSymbolicLink() && !options.followSymlinks) {
289
- return {
290
- content: null,
291
- skipped: true,
292
- reason: `${filePath} is a symlink (use --follow-symlinks to include)`,
293
- };
294
- }
295
- } catch {
296
- return {
297
- content: null,
298
- skipped: false,
299
- reason: `File not found: ${filePath}`,
300
- };
301
- }
302
-
303
- try {
304
- return {
305
- content: readFileSync(filePath, "utf-8"),
306
- skipped: false,
307
- reason: null,
308
- };
309
- } catch {
310
- return {
311
- content: null,
312
- skipped: false,
313
- reason: `Could not read: ${filePath}`,
314
- };
315
- }
316
- }
317
-
318
- // ---------------------------------------------------------------------------
319
- // Glob expansion
320
- // ---------------------------------------------------------------------------
321
-
322
- export function expandGlobs(patterns: string[]): string[] {
323
- const GLOB_CHARS = /[*?{[]/;
324
- const paths: string[] = [];
325
-
326
- for (const pattern of patterns) {
327
- if (GLOB_CHARS.test(pattern)) {
328
- const matches = globSync(pattern, { cwd: process.cwd() });
329
- for (const match of matches.sort()) {
330
- paths.push(resolve(match));
331
- }
332
- } else {
333
- paths.push(pattern);
334
- }
335
- }
336
-
337
- return paths;
338
- }
339
-
340
- // ---------------------------------------------------------------------------
341
- // Multi-file validation
342
- // ---------------------------------------------------------------------------
343
-
344
- export function validatePaths(
345
- paths: string[],
346
- {
347
- followSymlinks = false,
348
- ruleMarkers,
349
- rules: rulesConfig,
350
- }: ValidatePathsOptions = {},
351
- ): ValidatePathsResult {
352
- const fileResults: FileResult[] = [];
353
- let allValid = true;
354
-
355
- for (const filePath of paths) {
356
- const { content, skipped, reason } = readInstructionFile(filePath, {
357
- followSymlinks,
358
- });
359
-
360
- if (skipped || content === null) {
361
- fileResults.push({
362
- path: filePath,
363
- skipped,
364
- reason,
365
- result: null,
366
- });
367
- if (!skipped) allValid = false;
368
- continue;
369
- }
370
-
371
- const result = validate(content, {
372
- ruleMarkers,
373
- rules: rulesConfig,
374
- filePath,
375
- });
376
- fileResults.push({ path: filePath, skipped: false, reason: null, result });
377
- if (!result.valid) allValid = false;
378
- }
379
-
380
- return { fileResults, valid: allValid };
381
- }
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "Node16",
5
- "moduleResolution": "Node16",
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "declaration": true,
9
- "declarationMap": true,
10
- "sourceMap": true,
11
- "strict": true,
12
- "noUncheckedIndexedAccess": false,
13
- "noUnusedLocals": true,
14
- "noUnusedParameters": true,
15
- "exactOptionalPropertyTypes": false,
16
- "forceConsistentCasingInFileNames": true,
17
- "skipLibCheck": true,
18
- "esModuleInterop": true,
19
- "resolveJsonModule": true
20
- },
21
- "include": ["src/**/*.ts"],
22
- "exclude": ["node_modules", "dist"]
23
- }