agent-context-lint 0.1.0 → 0.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.
- package/README.md +26 -5
- package/action.yml +14 -0
- package/dist/cli.js +211 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +169 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +168 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ No existing tool does both structural validation (do referenced paths and script
|
|
|
28
28
|
|------|----------|----------------|
|
|
29
29
|
| `check:paths` | error | File/directory paths mentioned in context file that don't exist on disk |
|
|
30
30
|
| `check:scripts` | error | npm/pnpm/yarn/bun scripts referenced that aren't in package.json |
|
|
31
|
+
| `check:imports` | error | Relative import paths in code blocks that don't resolve to a file |
|
|
32
|
+
| `check:commands` | warning | Shell commands in bash code blocks not found on the system |
|
|
31
33
|
|
|
32
34
|
### Layer 2 — Semantic quality
|
|
33
35
|
|
|
@@ -55,15 +57,23 @@ Each file gets a **0–100 quality score** based on findings.
|
|
|
55
57
|
## CLI options
|
|
56
58
|
|
|
57
59
|
```
|
|
58
|
-
npx agent-context-lint
|
|
59
|
-
npx agent-context-lint CLAUDE.md
|
|
60
|
-
npx agent-context-lint --format json
|
|
61
|
-
npx agent-context-lint --json
|
|
62
|
-
npx agent-context-lint
|
|
60
|
+
npx agent-context-lint # auto-discover and lint all context files
|
|
61
|
+
npx agent-context-lint CLAUDE.md # lint a specific file
|
|
62
|
+
npx agent-context-lint --format json # machine-readable output for CI
|
|
63
|
+
npx agent-context-lint --json # shorthand for --format json
|
|
64
|
+
npx agent-context-lint --fix CLAUDE.md # auto-fix safe issues then lint
|
|
65
|
+
npx agent-context-lint -V # show version
|
|
63
66
|
```
|
|
64
67
|
|
|
65
68
|
Exit code 1 on any error (CI-compatible).
|
|
66
69
|
|
|
70
|
+
### `--fix`
|
|
71
|
+
|
|
72
|
+
Automatically fixes safe issues before linting:
|
|
73
|
+
- Trailing whitespace
|
|
74
|
+
- Multiple consecutive blank lines (collapsed to one)
|
|
75
|
+
- Missing trailing newline
|
|
76
|
+
|
|
67
77
|
## Configuration
|
|
68
78
|
|
|
69
79
|
Create `.agent-context-lint.json` in your project root, or add an `agentContextLint` key to `package.json`:
|
|
@@ -98,6 +108,17 @@ const fileResult = lintFile('./CLAUDE.md', process.cwd());
|
|
|
98
108
|
|
|
99
109
|
agent-context-lint combines both structural and semantic checks in a single tool.
|
|
100
110
|
|
|
111
|
+
## GitHub Action
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
- uses: mattschaller/agent-context-lint@v0
|
|
115
|
+
with:
|
|
116
|
+
files: 'CLAUDE.md AGENTS.md' # optional, auto-discovers if omitted
|
|
117
|
+
format: text # text (default) or json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Exits with code 1 on errors, making it suitable as a required status check.
|
|
121
|
+
|
|
101
122
|
## Contributing
|
|
102
123
|
|
|
103
124
|
Contributions welcome. Please open an issue first to discuss what you'd like to change.
|
package/action.yml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: agent-context-lint
|
|
2
|
+
description: Lint AI coding agent context files for staleness, broken paths, and semantic quality issues
|
|
3
|
+
inputs:
|
|
4
|
+
files:
|
|
5
|
+
description: Space-separated list of files to lint (default: auto-discover)
|
|
6
|
+
required: false
|
|
7
|
+
default: ''
|
|
8
|
+
format:
|
|
9
|
+
description: Output format (text or json)
|
|
10
|
+
required: false
|
|
11
|
+
default: text
|
|
12
|
+
runs:
|
|
13
|
+
using: node20
|
|
14
|
+
main: dist/cli.js
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { resolve as resolve5 } from "path";
|
|
5
|
+
|
|
6
|
+
// src/fixer.ts
|
|
7
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
8
|
+
function fixFile(filePath) {
|
|
9
|
+
const original = readFileSync(filePath, "utf-8");
|
|
10
|
+
const changes = [];
|
|
11
|
+
let content = original;
|
|
12
|
+
const lines = content.split("\n");
|
|
13
|
+
for (let i = 0; i < lines.length; i++) {
|
|
14
|
+
if (lines[i] !== lines[i].trimEnd()) {
|
|
15
|
+
changes.push({ line: i + 1, description: "Removed trailing whitespace" });
|
|
16
|
+
lines[i] = lines[i].trimEnd();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
content = lines.join("\n");
|
|
20
|
+
const collapsed = content.replace(/\n{3,}/g, (match, offset) => {
|
|
21
|
+
const before = content.slice(0, offset);
|
|
22
|
+
const lineNum = before.split("\n").length + 1;
|
|
23
|
+
changes.push({ line: lineNum, description: "Collapsed multiple blank lines" });
|
|
24
|
+
return "\n\n";
|
|
25
|
+
});
|
|
26
|
+
content = collapsed;
|
|
27
|
+
if (content.length > 0 && !content.endsWith("\n")) {
|
|
28
|
+
changes.push({
|
|
29
|
+
line: content.split("\n").length,
|
|
30
|
+
description: "Added trailing newline"
|
|
31
|
+
});
|
|
32
|
+
content += "\n";
|
|
33
|
+
}
|
|
34
|
+
const fixed = content !== original;
|
|
35
|
+
if (fixed) {
|
|
36
|
+
writeFileSync(filePath, content);
|
|
37
|
+
}
|
|
38
|
+
return { file: filePath, fixed, changes };
|
|
39
|
+
}
|
|
40
|
+
|
|
3
41
|
// src/index.ts
|
|
4
42
|
import { resolve as resolve4 } from "path";
|
|
5
43
|
|
|
6
44
|
// src/checkers.ts
|
|
7
|
-
import {
|
|
45
|
+
import { execFileSync } from "child_process";
|
|
46
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
8
47
|
import { dirname, resolve } from "path";
|
|
9
48
|
function checkPaths(parsed, filePath) {
|
|
10
49
|
const findings = [];
|
|
@@ -31,7 +70,7 @@ function checkScripts(parsed, filePath) {
|
|
|
31
70
|
let scripts = {};
|
|
32
71
|
if (existsSync(pkgPath)) {
|
|
33
72
|
try {
|
|
34
|
-
const pkg = JSON.parse(
|
|
73
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
35
74
|
scripts = pkg.scripts || {};
|
|
36
75
|
} catch {
|
|
37
76
|
return findings;
|
|
@@ -194,9 +233,137 @@ function checkContradictions(parsed, filePath) {
|
|
|
194
233
|
}
|
|
195
234
|
return findings;
|
|
196
235
|
}
|
|
236
|
+
var SHELL_BUILTINS = /* @__PURE__ */ new Set([
|
|
237
|
+
"cd",
|
|
238
|
+
"export",
|
|
239
|
+
"echo",
|
|
240
|
+
"source",
|
|
241
|
+
"set",
|
|
242
|
+
"unset",
|
|
243
|
+
"alias",
|
|
244
|
+
"unalias",
|
|
245
|
+
"type",
|
|
246
|
+
"readonly",
|
|
247
|
+
"declare",
|
|
248
|
+
"local",
|
|
249
|
+
"eval",
|
|
250
|
+
"exec",
|
|
251
|
+
"trap",
|
|
252
|
+
"return",
|
|
253
|
+
"exit",
|
|
254
|
+
"shift",
|
|
255
|
+
"wait",
|
|
256
|
+
"read",
|
|
257
|
+
"pushd",
|
|
258
|
+
"popd",
|
|
259
|
+
"dirs",
|
|
260
|
+
"ulimit",
|
|
261
|
+
"umask",
|
|
262
|
+
"getopts",
|
|
263
|
+
"hash",
|
|
264
|
+
"pwd",
|
|
265
|
+
"test",
|
|
266
|
+
"true",
|
|
267
|
+
"false",
|
|
268
|
+
"printf",
|
|
269
|
+
"let",
|
|
270
|
+
"if",
|
|
271
|
+
"then",
|
|
272
|
+
"else",
|
|
273
|
+
"fi",
|
|
274
|
+
"for",
|
|
275
|
+
"do",
|
|
276
|
+
"done",
|
|
277
|
+
"while",
|
|
278
|
+
"until",
|
|
279
|
+
"case",
|
|
280
|
+
"esac",
|
|
281
|
+
"in",
|
|
282
|
+
"function"
|
|
283
|
+
]);
|
|
284
|
+
var SHELL_LANGS = /* @__PURE__ */ new Set(["bash", "sh", "shell"]);
|
|
285
|
+
function checkCommands(parsed, filePath) {
|
|
286
|
+
const findings = [];
|
|
287
|
+
const cache = /* @__PURE__ */ new Map();
|
|
288
|
+
for (const block of parsed.codeBlocks) {
|
|
289
|
+
if (!SHELL_LANGS.has(block.lang)) continue;
|
|
290
|
+
const lines = block.content.split("\n");
|
|
291
|
+
for (let i = 0; i < lines.length; i++) {
|
|
292
|
+
let line = lines[i].trim();
|
|
293
|
+
if (!line || line.startsWith("#")) continue;
|
|
294
|
+
if (line.startsWith("$ ") || line.startsWith("> ")) {
|
|
295
|
+
line = line.slice(2).trim();
|
|
296
|
+
}
|
|
297
|
+
if (!line) continue;
|
|
298
|
+
const cmd = line.split(/\s/)[0];
|
|
299
|
+
if (!cmd || SHELL_BUILTINS.has(cmd)) continue;
|
|
300
|
+
if (/^[A-Z_]+=/.test(cmd)) continue;
|
|
301
|
+
if (!cache.has(cmd)) {
|
|
302
|
+
try {
|
|
303
|
+
execFileSync("which", [cmd], { stdio: "pipe" });
|
|
304
|
+
cache.set(cmd, true);
|
|
305
|
+
} catch {
|
|
306
|
+
cache.set(cmd, false);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (!cache.get(cmd)) {
|
|
310
|
+
findings.push({
|
|
311
|
+
file: filePath,
|
|
312
|
+
rule: "check:commands",
|
|
313
|
+
line: block.line + 1 + i,
|
|
314
|
+
column: 1,
|
|
315
|
+
severity: "warning",
|
|
316
|
+
message: `Command not found on system: "${cmd}"`
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return findings;
|
|
322
|
+
}
|
|
323
|
+
var JS_LANGS = /* @__PURE__ */ new Set(["ts", "js", "typescript", "javascript", "tsx", "jsx"]);
|
|
324
|
+
var IMPORT_FROM_RE = /(?:import\s+.*?\s+from\s+['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\))/g;
|
|
325
|
+
var EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cjs"];
|
|
326
|
+
function resolveModule(base, importPath) {
|
|
327
|
+
const resolved = resolve(base, importPath);
|
|
328
|
+
if (existsSync(resolved) && !resolved.endsWith("/")) return true;
|
|
329
|
+
for (const ext of EXTENSIONS) {
|
|
330
|
+
if (existsSync(resolved + ext)) return true;
|
|
331
|
+
}
|
|
332
|
+
for (const ext of EXTENSIONS) {
|
|
333
|
+
if (existsSync(resolve(resolved, "index" + ext))) return true;
|
|
334
|
+
}
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
function checkImports(parsed, filePath) {
|
|
338
|
+
const findings = [];
|
|
339
|
+
const baseDir = dirname(filePath);
|
|
340
|
+
for (const block of parsed.codeBlocks) {
|
|
341
|
+
if (!JS_LANGS.has(block.lang)) continue;
|
|
342
|
+
const lines = block.content.split("\n");
|
|
343
|
+
for (let i = 0; i < lines.length; i++) {
|
|
344
|
+
let match;
|
|
345
|
+
IMPORT_FROM_RE.lastIndex = 0;
|
|
346
|
+
while ((match = IMPORT_FROM_RE.exec(lines[i])) !== null) {
|
|
347
|
+
const importPath = match[1] || match[2];
|
|
348
|
+
if (!importPath.startsWith("./") && !importPath.startsWith("../")) continue;
|
|
349
|
+
if (!resolveModule(baseDir, importPath)) {
|
|
350
|
+
findings.push({
|
|
351
|
+
file: filePath,
|
|
352
|
+
rule: "check:imports",
|
|
353
|
+
line: block.line + 1 + i,
|
|
354
|
+
column: match.index + 1,
|
|
355
|
+
severity: "error",
|
|
356
|
+
message: `Import path does not resolve: "${importPath}"`
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return findings;
|
|
363
|
+
}
|
|
197
364
|
|
|
198
365
|
// src/config.ts
|
|
199
|
-
import { existsSync as existsSync2, readFileSync as
|
|
366
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
200
367
|
import { resolve as resolve2 } from "path";
|
|
201
368
|
|
|
202
369
|
// src/types.ts
|
|
@@ -234,7 +401,7 @@ function loadConfig(cwd) {
|
|
|
234
401
|
const configPath = resolve2(cwd, ".agent-context-lint.json");
|
|
235
402
|
if (existsSync2(configPath)) {
|
|
236
403
|
try {
|
|
237
|
-
const raw = JSON.parse(
|
|
404
|
+
const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
238
405
|
return mergeConfig(raw);
|
|
239
406
|
} catch {
|
|
240
407
|
}
|
|
@@ -242,7 +409,7 @@ function loadConfig(cwd) {
|
|
|
242
409
|
const pkgPath = resolve2(cwd, "package.json");
|
|
243
410
|
if (existsSync2(pkgPath)) {
|
|
244
411
|
try {
|
|
245
|
-
const pkg = JSON.parse(
|
|
412
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
246
413
|
if (pkg.agentContextLint) {
|
|
247
414
|
return mergeConfig(pkg.agentContextLint);
|
|
248
415
|
}
|
|
@@ -279,7 +446,7 @@ function discoverContextFiles(cwd) {
|
|
|
279
446
|
}
|
|
280
447
|
|
|
281
448
|
// src/parser.ts
|
|
282
|
-
import { readFileSync as
|
|
449
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
283
450
|
var PATH_PATTERN = /(?:^|\s|`)(\.?\.?\/[\w./@-]+[\w/@-])/g;
|
|
284
451
|
var COMMAND_PATTERN = /(?:npm|npx|pnpm|yarn|bun|bunx)\s+(?:run\s+)?[\w:@./-]+/g;
|
|
285
452
|
var HEADING_PATTERN = /^#{1,6}\s+(.+)$/;
|
|
@@ -287,7 +454,7 @@ var FENCED_BLOCK_START = /^```(\w*)/;
|
|
|
287
454
|
var FENCED_BLOCK_END = /^```\s*$/;
|
|
288
455
|
var INLINE_CODE_PATTERN = /`([^`]+)`/g;
|
|
289
456
|
function parseFile(filePath) {
|
|
290
|
-
const content =
|
|
457
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
291
458
|
const lines = content.split("\n");
|
|
292
459
|
const paths = [];
|
|
293
460
|
const commands = [];
|
|
@@ -422,7 +589,9 @@ function lintFile(filePath, cwd) {
|
|
|
422
589
|
...checkVague(parsed, filePath, config),
|
|
423
590
|
...checkRequiredSections(parsed, filePath, config),
|
|
424
591
|
...checkStaleDates(parsed, filePath, config),
|
|
425
|
-
...checkContradictions(parsed, filePath)
|
|
592
|
+
...checkContradictions(parsed, filePath),
|
|
593
|
+
...checkCommands(parsed, filePath),
|
|
594
|
+
...checkImports(parsed, filePath)
|
|
426
595
|
];
|
|
427
596
|
return {
|
|
428
597
|
file: filePath,
|
|
@@ -452,6 +621,17 @@ function lint(cwd, files) {
|
|
|
452
621
|
}
|
|
453
622
|
|
|
454
623
|
// src/cli.ts
|
|
624
|
+
function getGitHubActionInputs() {
|
|
625
|
+
if (process.env.GITHUB_ACTIONS !== "true") return null;
|
|
626
|
+
const files = (process.env.INPUT_FILES || "").split(/\s+/).filter(Boolean);
|
|
627
|
+
const format = process.env.INPUT_FORMAT === "json" ? "json" : "text";
|
|
628
|
+
return {
|
|
629
|
+
files,
|
|
630
|
+
format,
|
|
631
|
+
fix: false,
|
|
632
|
+
cwd: process.cwd()
|
|
633
|
+
};
|
|
634
|
+
}
|
|
455
635
|
function parseArgs(argv) {
|
|
456
636
|
const args = argv.slice(2);
|
|
457
637
|
const options = {
|
|
@@ -475,7 +655,7 @@ function parseArgs(argv) {
|
|
|
475
655
|
printHelp();
|
|
476
656
|
process.exit(0);
|
|
477
657
|
} else if (arg === "--version" || arg === "-V") {
|
|
478
|
-
console.log("0.1.
|
|
658
|
+
console.log("0.1.1");
|
|
479
659
|
process.exit(0);
|
|
480
660
|
} else if (!arg.startsWith("-")) {
|
|
481
661
|
options.files.push(arg);
|
|
@@ -491,11 +671,12 @@ function printHelp() {
|
|
|
491
671
|
npx agent-context-lint Auto-discover and lint all context files
|
|
492
672
|
npx agent-context-lint CLAUDE.md Lint a specific file
|
|
493
673
|
npx agent-context-lint --format json Machine-readable output for CI
|
|
674
|
+
npx agent-context-lint --fix CLAUDE.md Auto-fix safe issues then lint
|
|
494
675
|
|
|
495
676
|
Options:
|
|
496
677
|
--format <text|json> Output format (default: text)
|
|
497
678
|
--json Shorthand for --format json
|
|
498
|
-
--fix Auto-fix safe issues (
|
|
679
|
+
--fix Auto-fix safe issues (trailing whitespace, blank lines, trailing newline)
|
|
499
680
|
-V, --version Show version
|
|
500
681
|
-h, --help Show this help
|
|
501
682
|
|
|
@@ -505,10 +686,29 @@ function printHelp() {
|
|
|
505
686
|
|
|
506
687
|
Configuration:
|
|
507
688
|
.agent-context-lint.json or "agentContextLint" key in package.json
|
|
689
|
+
|
|
690
|
+
GitHub Action:
|
|
691
|
+
uses: mattschaller/agent-context-lint@v0
|
|
692
|
+
with:
|
|
693
|
+
files: 'CLAUDE.md AGENTS.md'
|
|
694
|
+
format: text
|
|
508
695
|
`);
|
|
509
696
|
}
|
|
510
697
|
function main() {
|
|
511
|
-
const options = parseArgs(process.argv);
|
|
698
|
+
const options = getGitHubActionInputs() || parseArgs(process.argv);
|
|
699
|
+
if (options.fix) {
|
|
700
|
+
const filesToFix = options.files.length > 0 ? options.files.map((f) => resolve5(options.cwd, f)) : [];
|
|
701
|
+
for (const file of filesToFix) {
|
|
702
|
+
const fixResult = fixFile(file);
|
|
703
|
+
if (fixResult.fixed) {
|
|
704
|
+
console.log(`Fixed ${file}:`);
|
|
705
|
+
for (const change of fixResult.changes) {
|
|
706
|
+
console.log(` line ${change.line}: ${change.description}`);
|
|
707
|
+
}
|
|
708
|
+
console.log();
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
512
712
|
const result = lint(
|
|
513
713
|
options.cwd,
|
|
514
714
|
options.files.length > 0 ? options.files : void 0
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/checkers.ts","../src/config.ts","../src/types.ts","../src/discovery.ts","../src/parser.ts","../src/scorer.ts","../src/reporter.ts","../src/cli.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport {\n checkContradictions,\n checkPaths,\n checkRequiredSections,\n checkScripts,\n checkStaleDates,\n checkTokenBudget,\n checkVague,\n} from './checkers.js';\nimport { loadConfig } from './config.js';\nimport { discoverContextFiles } from './discovery.js';\nimport { parseFile } from './parser.js';\nimport { computeScore } from './scorer.js';\nimport type { FileResult, LintFinding, LintResult } from './types.js';\n\nexport type { CLIOptions, Config, FileResult, LintFinding, LintResult } from './types.js';\nexport { discoverContextFiles } from './discovery.js';\nexport { parseFile } from './parser.js';\nexport { computeScore } from './scorer.js';\nexport { loadConfig } from './config.js';\nexport { formatJson, formatText } from './reporter.js';\n\nexport function lintFile(filePath: string, cwd: string): FileResult {\n const config = loadConfig(cwd);\n const parsed = parseFile(filePath);\n\n const findings: LintFinding[] = [\n ...checkPaths(parsed, filePath),\n ...checkScripts(parsed, filePath),\n ...checkTokenBudget(parsed, filePath, config),\n ...checkVague(parsed, filePath, config),\n ...checkRequiredSections(parsed, filePath, config),\n ...checkStaleDates(parsed, filePath, config),\n ...checkContradictions(parsed, filePath),\n ];\n\n return {\n file: filePath,\n findings,\n score: computeScore(findings),\n };\n}\n\nexport function lint(cwd: string, files?: string[]): LintResult {\n const targetFiles =\n files && files.length > 0\n ? files.map((f) => resolve(cwd, f))\n : discoverContextFiles(cwd);\n\n if (targetFiles.length === 0) {\n return { files: [], totalFindings: 0, errors: 0, warnings: 0 };\n }\n\n const results = targetFiles.map((f) => lintFile(f, cwd));\n\n const totalFindings = results.reduce(\n (sum, r) => sum + r.findings.length,\n 0,\n );\n const errors = results.reduce(\n (sum, r) => sum + r.findings.filter((f) => f.severity === 'error').length,\n 0,\n );\n const warnings = results.reduce(\n (sum, r) =>\n sum + r.findings.filter((f) => f.severity === 'warning').length,\n 0,\n );\n\n return { files: results, totalFindings, errors, warnings };\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { ParsedFile } from './parser.js';\nimport type { Config, LintFinding } from './types.js';\n\nexport function checkPaths(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const baseDir = dirname(filePath);\n\n for (const ref of parsed.paths) {\n const resolved = resolve(baseDir, ref.value);\n if (!existsSync(resolved)) {\n findings.push({\n file: filePath,\n rule: 'check:paths',\n line: ref.line,\n column: ref.column,\n severity: 'error',\n message: `Path does not exist: ${ref.value}`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkScripts(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const baseDir = dirname(filePath);\n const pkgPath = resolve(baseDir, 'package.json');\n\n let scripts: Record<string, string> = {};\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n scripts = pkg.scripts || {};\n } catch {\n // Invalid package.json — skip script checks\n return findings;\n }\n } else {\n // No package.json — skip script checks\n return findings;\n }\n\n for (const cmd of parsed.commands) {\n // Extract the script name from commands like \"npm run test\", \"pnpm build\"\n const match = /(?:npm|pnpm|yarn|bun)\\s+run\\s+([\\w:@./-]+)/.exec(cmd.value);\n const directMatch = /(?:npm|pnpm|yarn|bun)\\s+(test|start|build|lint)\\b/.exec(\n cmd.value,\n );\n\n const scriptName = match?.[1] || directMatch?.[1];\n if (scriptName && !(scriptName in scripts)) {\n findings.push({\n file: filePath,\n rule: 'check:scripts',\n line: cmd.line,\n column: cmd.column,\n severity: 'error',\n message: `Script not found in package.json: \"${scriptName}\"`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkTokenBudget(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n // Rough token estimate: ~4 chars per token for English text\n const estimatedTokens = Math.ceil(parsed.content.length / 4);\n\n if (estimatedTokens > config.tokenBudget.error) {\n findings.push({\n file: filePath,\n rule: 'check:token-budget',\n line: 1,\n column: 1,\n severity: 'error',\n message: `File is ~${estimatedTokens} tokens (limit: ${config.tokenBudget.error}). Consider splitting or condensing.`,\n });\n } else if (estimatedTokens > config.tokenBudget.warn) {\n findings.push({\n file: filePath,\n rule: 'check:token-budget',\n line: 1,\n column: 1,\n severity: 'warning',\n message: `File is ~${estimatedTokens} tokens (warn threshold: ${config.tokenBudget.warn}). Consider condensing.`,\n });\n }\n\n return findings;\n}\n\nexport function checkVague(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n for (let i = 0; i < parsed.lines.length; i++) {\n const line = parsed.lines[i].toLowerCase();\n for (const pattern of config.vaguePatterns) {\n if (line.includes(pattern.toLowerCase())) {\n findings.push({\n file: filePath,\n rule: 'check:vague',\n line: i + 1,\n column: line.indexOf(pattern.toLowerCase()) + 1,\n severity: 'warning',\n message: `Vague instruction: \"${pattern}\". Replace with specific, actionable guidance.`,\n });\n }\n }\n }\n\n return findings;\n}\n\nexport function checkRequiredSections(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const normalizedSections = parsed.sections.map((s) => s.toLowerCase());\n\n for (const required of config.requiredSections) {\n const found = normalizedSections.some(\n (s) => s.includes(required.toLowerCase()),\n );\n if (!found) {\n findings.push({\n file: filePath,\n rule: 'check:required-sections',\n line: 1,\n column: 1,\n severity: 'warning',\n message: `Missing recommended section: \"${required}\"`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkStaleDates(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const currentYear = new Date().getFullYear();\n const threshold = currentYear - config.staleDateYears;\n\n const yearPattern = /\\b(20[0-9]{2})\\b/g;\n\n for (let i = 0; i < parsed.lines.length; i++) {\n let match: RegExpExecArray | null;\n yearPattern.lastIndex = 0;\n while ((match = yearPattern.exec(parsed.lines[i])) !== null) {\n const year = parseInt(match[1], 10);\n if (year < threshold) {\n findings.push({\n file: filePath,\n rule: 'check:stale-dates',\n line: i + 1,\n column: match.index + 1,\n severity: 'warning',\n message: `Possibly stale year reference: ${year} (older than ${config.staleDateYears} years)`,\n });\n }\n }\n }\n\n return findings;\n}\n\nexport function checkContradictions(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n // Contradiction pairs: if both patterns appear, flag them\n const contradictionPairs: [RegExp, RegExp, string][] = [\n [\n /\\balways use (\\w+)/i,\n /\\bnever use (\\w+)/i,\n 'Contradictory \"always use\" and \"never use\" directives',\n ],\n [\n /\\bdo not (?:use|add|include) (comments|docstrings|type annotations)/i,\n /\\b(?:always|must) (?:add|include|write) \\1/i,\n 'Contradictory directives about adding/not adding',\n ],\n [\n /\\bprefer (\\w+) over (\\w+)/i,\n /\\bprefer \\2 over \\1/i,\n 'Contradictory preference directives',\n ],\n ];\n\n const lineTexts = parsed.lines;\n\n for (const [patternA, patternB, message] of contradictionPairs) {\n const matchesA: { line: number; match: RegExpExecArray }[] = [];\n const matchesB: { line: number; match: RegExpExecArray }[] = [];\n\n for (let i = 0; i < lineTexts.length; i++) {\n const lineText = lineTexts[i];\n const a = patternA.exec(lineText);\n if (a) matchesA.push({ line: i + 1, match: a });\n const b = patternB.exec(lineText);\n if (b) matchesB.push({ line: i + 1, match: b });\n }\n\n if (matchesA.length > 0 && matchesB.length > 0) {\n // Check if contradictions reference the same term\n for (const a of matchesA) {\n for (const b of matchesB) {\n if (\n a.match[1] &&\n b.match[1] &&\n a.match[1].toLowerCase() === b.match[1].toLowerCase()\n ) {\n findings.push({\n file: filePath,\n rule: 'check:contradictions',\n line: b.line,\n column: 1,\n severity: 'warning',\n message: `${message} (conflicts with line ${a.line})`,\n });\n }\n }\n }\n }\n }\n\n return findings;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { DEFAULT_CONFIG, type Config } from './types.js';\n\nexport function loadConfig(cwd: string): Config {\n // Try .agent-context-lint.json\n const configPath = resolve(cwd, '.agent-context-lint.json');\n if (existsSync(configPath)) {\n try {\n const raw = JSON.parse(readFileSync(configPath, 'utf-8'));\n return mergeConfig(raw);\n } catch {\n // Invalid config file — use defaults\n }\n }\n\n // Try package.json agentContextLint key\n const pkgPath = resolve(cwd, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n if (pkg.agentContextLint) {\n return mergeConfig(pkg.agentContextLint);\n }\n } catch {\n // Invalid package.json — use defaults\n }\n }\n\n return { ...DEFAULT_CONFIG };\n}\n\nfunction mergeConfig(overrides: Partial<Config>): Config {\n return {\n tokenBudget: {\n ...DEFAULT_CONFIG.tokenBudget,\n ...overrides.tokenBudget,\n },\n requiredSections:\n overrides.requiredSections ?? DEFAULT_CONFIG.requiredSections,\n staleDateYears: overrides.staleDateYears ?? DEFAULT_CONFIG.staleDateYears,\n vaguePatterns: overrides.vaguePatterns ?? DEFAULT_CONFIG.vaguePatterns,\n ignore: overrides.ignore ?? DEFAULT_CONFIG.ignore,\n };\n}\n","export interface LintFinding {\n file: string;\n rule: string;\n line: number;\n column: number;\n severity: 'error' | 'warning';\n message: string;\n}\n\nexport interface FileResult {\n file: string;\n findings: LintFinding[];\n score: number;\n}\n\nexport interface LintResult {\n files: FileResult[];\n totalFindings: number;\n errors: number;\n warnings: number;\n}\n\nexport interface CLIOptions {\n files: string[];\n format: 'text' | 'json';\n fix: boolean;\n cwd: string;\n}\n\nexport interface Config {\n tokenBudget: { warn: number; error: number };\n requiredSections: string[];\n staleDateYears: number;\n vaguePatterns: string[];\n ignore: string[];\n}\n\nexport const DEFAULT_CONFIG: Config = {\n tokenBudget: { warn: 2000, error: 5000 },\n requiredSections: ['Setup', 'Testing', 'Build'],\n staleDateYears: 2,\n vaguePatterns: [\n 'follow best practices',\n 'be careful',\n 'use good judgment',\n 'use common sense',\n 'as appropriate',\n 'when necessary',\n 'if needed',\n 'as needed',\n 'handle edge cases',\n 'write clean code',\n 'keep it simple',\n 'use proper',\n 'ensure quality',\n ],\n ignore: [],\n};\n\nexport const CONTEXT_FILE_NAMES = [\n 'CLAUDE.md',\n 'AGENTS.md',\n '.cursorrules',\n 'copilot-instructions.md',\n '.github/copilot-instructions.md',\n];\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { CONTEXT_FILE_NAMES } from './types.js';\n\nexport function discoverContextFiles(cwd: string): string[] {\n const found: string[] = [];\n for (const name of CONTEXT_FILE_NAMES) {\n const fullPath = resolve(cwd, name);\n if (existsSync(fullPath)) {\n found.push(fullPath);\n }\n }\n return found;\n}\n","import { readFileSync } from 'node:fs';\n\nexport interface ParsedFile {\n content: string;\n lines: string[];\n paths: PathReference[];\n commands: CommandReference[];\n sections: string[];\n codeBlocks: CodeBlock[];\n inlineCode: InlineCode[];\n}\n\nexport interface PathReference {\n value: string;\n line: number;\n column: number;\n}\n\nexport interface CommandReference {\n value: string;\n line: number;\n column: number;\n}\n\nexport interface CodeBlock {\n content: string;\n lang: string;\n line: number;\n}\n\nexport interface InlineCode {\n content: string;\n line: number;\n column: number;\n}\n\nconst PATH_PATTERN = /(?:^|\\s|`)(\\.?\\.?\\/[\\w./@-]+[\\w/@-])/g;\nconst COMMAND_PATTERN = /(?:npm|npx|pnpm|yarn|bun|bunx)\\s+(?:run\\s+)?[\\w:@./-]+/g;\nconst HEADING_PATTERN = /^#{1,6}\\s+(.+)$/;\nconst FENCED_BLOCK_START = /^```(\\w*)/;\nconst FENCED_BLOCK_END = /^```\\s*$/;\nconst INLINE_CODE_PATTERN = /`([^`]+)`/g;\n\nexport function parseFile(filePath: string): ParsedFile {\n const content = readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n');\n\n const paths: PathReference[] = [];\n const commands: CommandReference[] = [];\n const sections: string[] = [];\n const codeBlocks: CodeBlock[] = [];\n const inlineCode: InlineCode[] = [];\n\n let inCodeBlock = false;\n let codeBlockLang = '';\n let codeBlockContent = '';\n let codeBlockStart = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineNum = i + 1;\n\n // Track fenced code blocks\n if (!inCodeBlock) {\n const blockStart = FENCED_BLOCK_START.exec(line);\n if (blockStart && line.trimStart().startsWith('```')) {\n inCodeBlock = true;\n codeBlockLang = blockStart[1] || '';\n codeBlockContent = '';\n codeBlockStart = lineNum;\n continue;\n }\n } else {\n if (FENCED_BLOCK_END.test(line) && line.trimStart() === '```') {\n codeBlocks.push({\n content: codeBlockContent,\n lang: codeBlockLang,\n line: codeBlockStart,\n });\n inCodeBlock = false;\n continue;\n }\n codeBlockContent += (codeBlockContent ? '\\n' : '') + line;\n }\n\n // Extract headings as sections\n const headingMatch = HEADING_PATTERN.exec(line);\n if (headingMatch) {\n sections.push(headingMatch[1].trim());\n }\n\n // Extract paths from both inline code and plain text\n let pathMatch: RegExpExecArray | null;\n PATH_PATTERN.lastIndex = 0;\n while ((pathMatch = PATH_PATTERN.exec(line)) !== null) {\n const value = pathMatch[1];\n // Skip URLs\n if (value.includes('://')) continue;\n paths.push({\n value,\n line: lineNum,\n column: pathMatch.index + (pathMatch[0].length - value.length) + 1,\n });\n }\n\n // Extract npm/pnpm/yarn/bun commands\n let cmdMatch: RegExpExecArray | null;\n COMMAND_PATTERN.lastIndex = 0;\n while ((cmdMatch = COMMAND_PATTERN.exec(line)) !== null) {\n commands.push({\n value: cmdMatch[0],\n line: lineNum,\n column: cmdMatch.index + 1,\n });\n }\n\n // Extract inline code spans\n if (!inCodeBlock) {\n let inlineMatch: RegExpExecArray | null;\n INLINE_CODE_PATTERN.lastIndex = 0;\n while ((inlineMatch = INLINE_CODE_PATTERN.exec(line)) !== null) {\n inlineCode.push({\n content: inlineMatch[1],\n line: lineNum,\n column: inlineMatch.index + 2,\n });\n }\n }\n }\n\n return { content, lines, paths, commands, sections, codeBlocks, inlineCode };\n}\n","import type { LintFinding } from './types.js';\n\n/**\n * Computes a 0–100 quality score for a file based on its findings.\n *\n * Starts at 100 and deducts:\n * - 15 points per error\n * - 5 points per warning\n *\n * Minimum score is 0.\n */\nexport function computeScore(findings: LintFinding[]): number {\n let score = 100;\n for (const finding of findings) {\n if (finding.severity === 'error') {\n score -= 15;\n } else {\n score -= 5;\n }\n }\n return Math.max(0, score);\n}\n","import { relative } from 'node:path';\nimport type { LintResult } from './types.js';\n\nexport function formatText(result: LintResult, cwd: string): string {\n const lines: string[] = [];\n\n for (const file of result.files) {\n const relPath = relative(cwd, file.file);\n lines.push(`\\n ${relPath} (score: ${file.score}/100)`);\n\n if (file.findings.length === 0) {\n lines.push(' No issues found.');\n continue;\n }\n\n for (const f of file.findings) {\n const icon = f.severity === 'error' ? 'x' : '!';\n lines.push(\n ` ${f.line}:${f.column} ${icon} ${f.message} [${f.rule}]`,\n );\n }\n }\n\n lines.push('');\n lines.push(\n ` ${result.totalFindings} problems (${result.errors} errors, ${result.warnings} warnings)`,\n );\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function formatJson(result: LintResult, cwd: string): string {\n const output = {\n ...result,\n files: result.files.map((f) => ({\n ...f,\n file: relative(cwd, f.file),\n })),\n };\n return JSON.stringify(output, null, 2);\n}\n","import { lint } from './index.js';\nimport { formatJson, formatText } from './reporter.js';\nimport type { CLIOptions } from './types.js';\n\nfunction parseArgs(argv: string[]): CLIOptions {\n const args = argv.slice(2);\n const options: CLIOptions = {\n files: [],\n format: 'text',\n fix: false,\n cwd: process.cwd(),\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === '--format' && args[i + 1]) {\n const fmt = args[++i];\n if (fmt === 'json' || fmt === 'text') {\n options.format = fmt;\n }\n } else if (arg === '--json') {\n options.format = 'json';\n } else if (arg === '--fix') {\n options.fix = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg === '--version' || arg === '-V') {\n console.log('0.1.0');\n process.exit(0);\n } else if (!arg.startsWith('-')) {\n options.files.push(arg);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n agent-context-lint — Lint AI coding agent context files\n\n Usage:\n npx agent-context-lint Auto-discover and lint all context files\n npx agent-context-lint CLAUDE.md Lint a specific file\n npx agent-context-lint --format json Machine-readable output for CI\n\n Options:\n --format <text|json> Output format (default: text)\n --json Shorthand for --format json\n --fix Auto-fix safe issues (not yet implemented)\n -V, --version Show version\n -h, --help Show this help\n\n Context files detected:\n CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md,\n .github/copilot-instructions.md\n\n Configuration:\n .agent-context-lint.json or \"agentContextLint\" key in package.json\n`);\n}\n\nfunction main(): void {\n const options = parseArgs(process.argv);\n const result = lint(\n options.cwd,\n options.files.length > 0 ? options.files : undefined,\n );\n\n if (result.files.length === 0) {\n console.log('No context files found.');\n process.exit(0);\n }\n\n const output =\n options.format === 'json'\n ? formatJson(result, options.cwd)\n : formatText(result, options.cwd);\n\n console.log(output);\n process.exit(result.errors > 0 ? 1 : 0);\n}\n\nmain();\n"],"mappings":"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","names":["resolve","existsSync","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","resolve","resolve","existsSync","readFileSync","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/fixer.ts","../src/index.ts","../src/checkers.ts","../src/config.ts","../src/types.ts","../src/discovery.ts","../src/parser.ts","../src/scorer.ts","../src/reporter.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { fixFile } from './fixer.js';\nimport { lint } from './index.js';\nimport { formatJson, formatText } from './reporter.js';\nimport type { CLIOptions } from './types.js';\n\nfunction getGitHubActionInputs(): CLIOptions | null {\n if (process.env.GITHUB_ACTIONS !== 'true') return null;\n\n const files = (process.env.INPUT_FILES || '').split(/\\s+/).filter(Boolean);\n const format = process.env.INPUT_FORMAT === 'json' ? 'json' as const : 'text' as const;\n\n return {\n files,\n format,\n fix: false,\n cwd: process.cwd(),\n };\n}\n\nfunction parseArgs(argv: string[]): CLIOptions {\n const args = argv.slice(2);\n const options: CLIOptions = {\n files: [],\n format: 'text',\n fix: false,\n cwd: process.cwd(),\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === '--format' && args[i + 1]) {\n const fmt = args[++i];\n if (fmt === 'json' || fmt === 'text') {\n options.format = fmt;\n }\n } else if (arg === '--json') {\n options.format = 'json';\n } else if (arg === '--fix') {\n options.fix = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg === '--version' || arg === '-V') {\n console.log('0.1.1');\n process.exit(0);\n } else if (!arg.startsWith('-')) {\n options.files.push(arg);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n agent-context-lint — Lint AI coding agent context files\n\n Usage:\n npx agent-context-lint Auto-discover and lint all context files\n npx agent-context-lint CLAUDE.md Lint a specific file\n npx agent-context-lint --format json Machine-readable output for CI\n npx agent-context-lint --fix CLAUDE.md Auto-fix safe issues then lint\n\n Options:\n --format <text|json> Output format (default: text)\n --json Shorthand for --format json\n --fix Auto-fix safe issues (trailing whitespace, blank lines, trailing newline)\n -V, --version Show version\n -h, --help Show this help\n\n Context files detected:\n CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md,\n .github/copilot-instructions.md\n\n Configuration:\n .agent-context-lint.json or \"agentContextLint\" key in package.json\n\n GitHub Action:\n uses: mattschaller/agent-context-lint@v0\n with:\n files: 'CLAUDE.md AGENTS.md'\n format: text\n`);\n}\n\nfunction main(): void {\n const options = getGitHubActionInputs() || parseArgs(process.argv);\n\n // Run fix before lint if requested\n if (options.fix) {\n const filesToFix = options.files.length > 0\n ? options.files.map((f) => resolve(options.cwd, f))\n : [];\n\n for (const file of filesToFix) {\n const fixResult = fixFile(file);\n if (fixResult.fixed) {\n console.log(`Fixed ${file}:`);\n for (const change of fixResult.changes) {\n console.log(` line ${change.line}: ${change.description}`);\n }\n console.log();\n }\n }\n }\n\n const result = lint(\n options.cwd,\n options.files.length > 0 ? options.files : undefined,\n );\n\n if (result.files.length === 0) {\n console.log('No context files found.');\n process.exit(0);\n }\n\n const output =\n options.format === 'json'\n ? formatJson(result, options.cwd)\n : formatText(result, options.cwd);\n\n console.log(output);\n process.exit(result.errors > 0 ? 1 : 0);\n}\n\nmain();\n","import { readFileSync, writeFileSync } from 'node:fs';\n\nexport interface FixChange {\n line: number;\n description: string;\n}\n\nexport interface FixResult {\n file: string;\n fixed: boolean;\n changes: FixChange[];\n}\n\nexport function fixFile(filePath: string): FixResult {\n const original = readFileSync(filePath, 'utf-8');\n const changes: FixChange[] = [];\n let content = original;\n\n // Fix trailing whitespace on each line\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n if (lines[i] !== lines[i].trimEnd()) {\n changes.push({ line: i + 1, description: 'Removed trailing whitespace' });\n lines[i] = lines[i].trimEnd();\n }\n }\n content = lines.join('\\n');\n\n // Fix multiple consecutive blank lines → single blank line\n const collapsed = content.replace(/\\n{3,}/g, (match, offset) => {\n const before = content.slice(0, offset);\n const lineNum = before.split('\\n').length + 1;\n changes.push({ line: lineNum, description: 'Collapsed multiple blank lines' });\n return '\\n\\n';\n });\n content = collapsed;\n\n // Fix missing trailing newline\n if (content.length > 0 && !content.endsWith('\\n')) {\n changes.push({\n line: content.split('\\n').length,\n description: 'Added trailing newline',\n });\n content += '\\n';\n }\n\n const fixed = content !== original;\n if (fixed) {\n writeFileSync(filePath, content);\n }\n\n return { file: filePath, fixed, changes };\n}\n","import { resolve } from 'node:path';\nimport {\n checkCommands,\n checkContradictions,\n checkImports,\n checkPaths,\n checkRequiredSections,\n checkScripts,\n checkStaleDates,\n checkTokenBudget,\n checkVague,\n} from './checkers.js';\nimport { loadConfig } from './config.js';\nimport { discoverContextFiles } from './discovery.js';\nimport { parseFile } from './parser.js';\nimport { computeScore } from './scorer.js';\nimport type { FileResult, LintFinding, LintResult } from './types.js';\n\nexport type { CLIOptions, Config, FileResult, LintFinding, LintResult } from './types.js';\nexport { discoverContextFiles } from './discovery.js';\nexport { parseFile } from './parser.js';\nexport { computeScore } from './scorer.js';\nexport { loadConfig } from './config.js';\nexport { formatJson, formatText } from './reporter.js';\nexport { fixFile } from './fixer.js';\nexport type { FixResult, FixChange } from './fixer.js';\n\nexport function lintFile(filePath: string, cwd: string): FileResult {\n const config = loadConfig(cwd);\n const parsed = parseFile(filePath);\n\n const findings: LintFinding[] = [\n ...checkPaths(parsed, filePath),\n ...checkScripts(parsed, filePath),\n ...checkTokenBudget(parsed, filePath, config),\n ...checkVague(parsed, filePath, config),\n ...checkRequiredSections(parsed, filePath, config),\n ...checkStaleDates(parsed, filePath, config),\n ...checkContradictions(parsed, filePath),\n ...checkCommands(parsed, filePath),\n ...checkImports(parsed, filePath),\n ];\n\n return {\n file: filePath,\n findings,\n score: computeScore(findings),\n };\n}\n\nexport function lint(cwd: string, files?: string[]): LintResult {\n const targetFiles =\n files && files.length > 0\n ? files.map((f) => resolve(cwd, f))\n : discoverContextFiles(cwd);\n\n if (targetFiles.length === 0) {\n return { files: [], totalFindings: 0, errors: 0, warnings: 0 };\n }\n\n const results = targetFiles.map((f) => lintFile(f, cwd));\n\n const totalFindings = results.reduce(\n (sum, r) => sum + r.findings.length,\n 0,\n );\n const errors = results.reduce(\n (sum, r) => sum + r.findings.filter((f) => f.severity === 'error').length,\n 0,\n );\n const warnings = results.reduce(\n (sum, r) =>\n sum + r.findings.filter((f) => f.severity === 'warning').length,\n 0,\n );\n\n return { files: results, totalFindings, errors, warnings };\n}\n","import { execFileSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { ParsedFile } from './parser.js';\nimport type { Config, LintFinding } from './types.js';\n\nexport function checkPaths(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const baseDir = dirname(filePath);\n\n for (const ref of parsed.paths) {\n const resolved = resolve(baseDir, ref.value);\n if (!existsSync(resolved)) {\n findings.push({\n file: filePath,\n rule: 'check:paths',\n line: ref.line,\n column: ref.column,\n severity: 'error',\n message: `Path does not exist: ${ref.value}`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkScripts(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const baseDir = dirname(filePath);\n const pkgPath = resolve(baseDir, 'package.json');\n\n let scripts: Record<string, string> = {};\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n scripts = pkg.scripts || {};\n } catch {\n // Invalid package.json — skip script checks\n return findings;\n }\n } else {\n // No package.json — skip script checks\n return findings;\n }\n\n for (const cmd of parsed.commands) {\n // Extract the script name from commands like \"npm run test\", \"pnpm build\"\n const match = /(?:npm|pnpm|yarn|bun)\\s+run\\s+([\\w:@./-]+)/.exec(cmd.value);\n const directMatch = /(?:npm|pnpm|yarn|bun)\\s+(test|start|build|lint)\\b/.exec(\n cmd.value,\n );\n\n const scriptName = match?.[1] || directMatch?.[1];\n if (scriptName && !(scriptName in scripts)) {\n findings.push({\n file: filePath,\n rule: 'check:scripts',\n line: cmd.line,\n column: cmd.column,\n severity: 'error',\n message: `Script not found in package.json: \"${scriptName}\"`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkTokenBudget(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n // Rough token estimate: ~4 chars per token for English text\n const estimatedTokens = Math.ceil(parsed.content.length / 4);\n\n if (estimatedTokens > config.tokenBudget.error) {\n findings.push({\n file: filePath,\n rule: 'check:token-budget',\n line: 1,\n column: 1,\n severity: 'error',\n message: `File is ~${estimatedTokens} tokens (limit: ${config.tokenBudget.error}). Consider splitting or condensing.`,\n });\n } else if (estimatedTokens > config.tokenBudget.warn) {\n findings.push({\n file: filePath,\n rule: 'check:token-budget',\n line: 1,\n column: 1,\n severity: 'warning',\n message: `File is ~${estimatedTokens} tokens (warn threshold: ${config.tokenBudget.warn}). Consider condensing.`,\n });\n }\n\n return findings;\n}\n\nexport function checkVague(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n for (let i = 0; i < parsed.lines.length; i++) {\n const line = parsed.lines[i].toLowerCase();\n for (const pattern of config.vaguePatterns) {\n if (line.includes(pattern.toLowerCase())) {\n findings.push({\n file: filePath,\n rule: 'check:vague',\n line: i + 1,\n column: line.indexOf(pattern.toLowerCase()) + 1,\n severity: 'warning',\n message: `Vague instruction: \"${pattern}\". Replace with specific, actionable guidance.`,\n });\n }\n }\n }\n\n return findings;\n}\n\nexport function checkRequiredSections(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const normalizedSections = parsed.sections.map((s) => s.toLowerCase());\n\n for (const required of config.requiredSections) {\n const found = normalizedSections.some(\n (s) => s.includes(required.toLowerCase()),\n );\n if (!found) {\n findings.push({\n file: filePath,\n rule: 'check:required-sections',\n line: 1,\n column: 1,\n severity: 'warning',\n message: `Missing recommended section: \"${required}\"`,\n });\n }\n }\n\n return findings;\n}\n\nexport function checkStaleDates(\n parsed: ParsedFile,\n filePath: string,\n config: Config,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const currentYear = new Date().getFullYear();\n const threshold = currentYear - config.staleDateYears;\n\n const yearPattern = /\\b(20[0-9]{2})\\b/g;\n\n for (let i = 0; i < parsed.lines.length; i++) {\n let match: RegExpExecArray | null;\n yearPattern.lastIndex = 0;\n while ((match = yearPattern.exec(parsed.lines[i])) !== null) {\n const year = parseInt(match[1], 10);\n if (year < threshold) {\n findings.push({\n file: filePath,\n rule: 'check:stale-dates',\n line: i + 1,\n column: match.index + 1,\n severity: 'warning',\n message: `Possibly stale year reference: ${year} (older than ${config.staleDateYears} years)`,\n });\n }\n }\n }\n\n return findings;\n}\n\nexport function checkContradictions(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n // Contradiction pairs: if both patterns appear, flag them\n const contradictionPairs: [RegExp, RegExp, string][] = [\n [\n /\\balways use (\\w+)/i,\n /\\bnever use (\\w+)/i,\n 'Contradictory \"always use\" and \"never use\" directives',\n ],\n [\n /\\bdo not (?:use|add|include) (comments|docstrings|type annotations)/i,\n /\\b(?:always|must) (?:add|include|write) \\1/i,\n 'Contradictory directives about adding/not adding',\n ],\n [\n /\\bprefer (\\w+) over (\\w+)/i,\n /\\bprefer \\2 over \\1/i,\n 'Contradictory preference directives',\n ],\n ];\n\n const lineTexts = parsed.lines;\n\n for (const [patternA, patternB, message] of contradictionPairs) {\n const matchesA: { line: number; match: RegExpExecArray }[] = [];\n const matchesB: { line: number; match: RegExpExecArray }[] = [];\n\n for (let i = 0; i < lineTexts.length; i++) {\n const lineText = lineTexts[i];\n const a = patternA.exec(lineText);\n if (a) matchesA.push({ line: i + 1, match: a });\n const b = patternB.exec(lineText);\n if (b) matchesB.push({ line: i + 1, match: b });\n }\n\n if (matchesA.length > 0 && matchesB.length > 0) {\n // Check if contradictions reference the same term\n for (const a of matchesA) {\n for (const b of matchesB) {\n if (\n a.match[1] &&\n b.match[1] &&\n a.match[1].toLowerCase() === b.match[1].toLowerCase()\n ) {\n findings.push({\n file: filePath,\n rule: 'check:contradictions',\n line: b.line,\n column: 1,\n severity: 'warning',\n message: `${message} (conflicts with line ${a.line})`,\n });\n }\n }\n }\n }\n }\n\n return findings;\n}\n\nconst SHELL_BUILTINS = new Set([\n 'cd', 'export', 'echo', 'source', 'set', 'unset', 'alias', 'unalias',\n 'type', 'readonly', 'declare', 'local', 'eval', 'exec', 'trap',\n 'return', 'exit', 'shift', 'wait', 'read', 'pushd', 'popd', 'dirs',\n 'ulimit', 'umask', 'getopts', 'hash', 'pwd', 'test', 'true', 'false',\n 'printf', 'let', 'if', 'then', 'else', 'fi', 'for', 'do', 'done',\n 'while', 'until', 'case', 'esac', 'in', 'function',\n]);\n\nconst SHELL_LANGS = new Set(['bash', 'sh', 'shell']);\n\nexport function checkCommands(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const cache = new Map<string, boolean>();\n\n for (const block of parsed.codeBlocks) {\n if (!SHELL_LANGS.has(block.lang)) continue;\n\n const lines = block.content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n let line = lines[i].trim();\n if (!line || line.startsWith('#')) continue;\n // Strip prompt prefixes\n if (line.startsWith('$ ') || line.startsWith('> ')) {\n line = line.slice(2).trim();\n }\n if (!line) continue;\n\n const cmd = line.split(/\\s/)[0];\n if (!cmd || SHELL_BUILTINS.has(cmd)) continue;\n // Skip environment variable assignments\n if (/^[A-Z_]+=/.test(cmd)) continue;\n\n if (!cache.has(cmd)) {\n try {\n execFileSync('which', [cmd], { stdio: 'pipe' });\n cache.set(cmd, true);\n } catch {\n cache.set(cmd, false);\n }\n }\n\n if (!cache.get(cmd)) {\n findings.push({\n file: filePath,\n rule: 'check:commands',\n line: block.line + 1 + i,\n column: 1,\n severity: 'warning',\n message: `Command not found on system: \"${cmd}\"`,\n });\n }\n }\n }\n\n return findings;\n}\n\nconst JS_LANGS = new Set(['ts', 'js', 'typescript', 'javascript', 'tsx', 'jsx']);\nconst IMPORT_FROM_RE = /(?:import\\s+.*?\\s+from\\s+['\"]([^'\"]+)['\"]|require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\))/g;\nconst EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs', '.cjs'];\n\nfunction resolveModule(base: string, importPath: string): boolean {\n const resolved = resolve(base, importPath);\n\n // Exact match\n if (existsSync(resolved) && !resolved.endsWith('/')) return true;\n\n // Try extension fallbacks\n for (const ext of EXTENSIONS) {\n if (existsSync(resolved + ext)) return true;\n }\n\n // Try index files\n for (const ext of EXTENSIONS) {\n if (existsSync(resolve(resolved, 'index' + ext))) return true;\n }\n\n return false;\n}\n\nexport function checkImports(\n parsed: ParsedFile,\n filePath: string,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const baseDir = dirname(filePath);\n\n for (const block of parsed.codeBlocks) {\n if (!JS_LANGS.has(block.lang)) continue;\n\n const lines = block.content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n let match: RegExpExecArray | null;\n IMPORT_FROM_RE.lastIndex = 0;\n while ((match = IMPORT_FROM_RE.exec(lines[i])) !== null) {\n const importPath = match[1] || match[2];\n // Only check relative imports\n if (!importPath.startsWith('./') && !importPath.startsWith('../')) continue;\n\n if (!resolveModule(baseDir, importPath)) {\n findings.push({\n file: filePath,\n rule: 'check:imports',\n line: block.line + 1 + i,\n column: match.index + 1,\n severity: 'error',\n message: `Import path does not resolve: \"${importPath}\"`,\n });\n }\n }\n }\n }\n\n return findings;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { DEFAULT_CONFIG, type Config } from './types.js';\n\nexport function loadConfig(cwd: string): Config {\n // Try .agent-context-lint.json\n const configPath = resolve(cwd, '.agent-context-lint.json');\n if (existsSync(configPath)) {\n try {\n const raw = JSON.parse(readFileSync(configPath, 'utf-8'));\n return mergeConfig(raw);\n } catch {\n // Invalid config file — use defaults\n }\n }\n\n // Try package.json agentContextLint key\n const pkgPath = resolve(cwd, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n if (pkg.agentContextLint) {\n return mergeConfig(pkg.agentContextLint);\n }\n } catch {\n // Invalid package.json — use defaults\n }\n }\n\n return { ...DEFAULT_CONFIG };\n}\n\nfunction mergeConfig(overrides: Partial<Config>): Config {\n return {\n tokenBudget: {\n ...DEFAULT_CONFIG.tokenBudget,\n ...overrides.tokenBudget,\n },\n requiredSections:\n overrides.requiredSections ?? DEFAULT_CONFIG.requiredSections,\n staleDateYears: overrides.staleDateYears ?? DEFAULT_CONFIG.staleDateYears,\n vaguePatterns: overrides.vaguePatterns ?? DEFAULT_CONFIG.vaguePatterns,\n ignore: overrides.ignore ?? DEFAULT_CONFIG.ignore,\n };\n}\n","export interface LintFinding {\n file: string;\n rule: string;\n line: number;\n column: number;\n severity: 'error' | 'warning';\n message: string;\n}\n\nexport interface FileResult {\n file: string;\n findings: LintFinding[];\n score: number;\n}\n\nexport interface LintResult {\n files: FileResult[];\n totalFindings: number;\n errors: number;\n warnings: number;\n}\n\nexport interface CLIOptions {\n files: string[];\n format: 'text' | 'json';\n fix: boolean;\n cwd: string;\n}\n\nexport interface Config {\n tokenBudget: { warn: number; error: number };\n requiredSections: string[];\n staleDateYears: number;\n vaguePatterns: string[];\n ignore: string[];\n}\n\nexport const DEFAULT_CONFIG: Config = {\n tokenBudget: { warn: 2000, error: 5000 },\n requiredSections: ['Setup', 'Testing', 'Build'],\n staleDateYears: 2,\n vaguePatterns: [\n 'follow best practices',\n 'be careful',\n 'use good judgment',\n 'use common sense',\n 'as appropriate',\n 'when necessary',\n 'if needed',\n 'as needed',\n 'handle edge cases',\n 'write clean code',\n 'keep it simple',\n 'use proper',\n 'ensure quality',\n ],\n ignore: [],\n};\n\nexport const CONTEXT_FILE_NAMES = [\n 'CLAUDE.md',\n 'AGENTS.md',\n '.cursorrules',\n 'copilot-instructions.md',\n '.github/copilot-instructions.md',\n];\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { CONTEXT_FILE_NAMES } from './types.js';\n\nexport function discoverContextFiles(cwd: string): string[] {\n const found: string[] = [];\n for (const name of CONTEXT_FILE_NAMES) {\n const fullPath = resolve(cwd, name);\n if (existsSync(fullPath)) {\n found.push(fullPath);\n }\n }\n return found;\n}\n","import { readFileSync } from 'node:fs';\n\nexport interface ParsedFile {\n content: string;\n lines: string[];\n paths: PathReference[];\n commands: CommandReference[];\n sections: string[];\n codeBlocks: CodeBlock[];\n inlineCode: InlineCode[];\n}\n\nexport interface PathReference {\n value: string;\n line: number;\n column: number;\n}\n\nexport interface CommandReference {\n value: string;\n line: number;\n column: number;\n}\n\nexport interface CodeBlock {\n content: string;\n lang: string;\n line: number;\n}\n\nexport interface InlineCode {\n content: string;\n line: number;\n column: number;\n}\n\nconst PATH_PATTERN = /(?:^|\\s|`)(\\.?\\.?\\/[\\w./@-]+[\\w/@-])/g;\nconst COMMAND_PATTERN = /(?:npm|npx|pnpm|yarn|bun|bunx)\\s+(?:run\\s+)?[\\w:@./-]+/g;\nconst HEADING_PATTERN = /^#{1,6}\\s+(.+)$/;\nconst FENCED_BLOCK_START = /^```(\\w*)/;\nconst FENCED_BLOCK_END = /^```\\s*$/;\nconst INLINE_CODE_PATTERN = /`([^`]+)`/g;\n\nexport function parseFile(filePath: string): ParsedFile {\n const content = readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n');\n\n const paths: PathReference[] = [];\n const commands: CommandReference[] = [];\n const sections: string[] = [];\n const codeBlocks: CodeBlock[] = [];\n const inlineCode: InlineCode[] = [];\n\n let inCodeBlock = false;\n let codeBlockLang = '';\n let codeBlockContent = '';\n let codeBlockStart = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineNum = i + 1;\n\n // Track fenced code blocks\n if (!inCodeBlock) {\n const blockStart = FENCED_BLOCK_START.exec(line);\n if (blockStart && line.trimStart().startsWith('```')) {\n inCodeBlock = true;\n codeBlockLang = blockStart[1] || '';\n codeBlockContent = '';\n codeBlockStart = lineNum;\n continue;\n }\n } else {\n if (FENCED_BLOCK_END.test(line) && line.trimStart() === '```') {\n codeBlocks.push({\n content: codeBlockContent,\n lang: codeBlockLang,\n line: codeBlockStart,\n });\n inCodeBlock = false;\n continue;\n }\n codeBlockContent += (codeBlockContent ? '\\n' : '') + line;\n }\n\n // Extract headings as sections\n const headingMatch = HEADING_PATTERN.exec(line);\n if (headingMatch) {\n sections.push(headingMatch[1].trim());\n }\n\n // Extract paths from both inline code and plain text\n let pathMatch: RegExpExecArray | null;\n PATH_PATTERN.lastIndex = 0;\n while ((pathMatch = PATH_PATTERN.exec(line)) !== null) {\n const value = pathMatch[1];\n // Skip URLs\n if (value.includes('://')) continue;\n paths.push({\n value,\n line: lineNum,\n column: pathMatch.index + (pathMatch[0].length - value.length) + 1,\n });\n }\n\n // Extract npm/pnpm/yarn/bun commands\n let cmdMatch: RegExpExecArray | null;\n COMMAND_PATTERN.lastIndex = 0;\n while ((cmdMatch = COMMAND_PATTERN.exec(line)) !== null) {\n commands.push({\n value: cmdMatch[0],\n line: lineNum,\n column: cmdMatch.index + 1,\n });\n }\n\n // Extract inline code spans\n if (!inCodeBlock) {\n let inlineMatch: RegExpExecArray | null;\n INLINE_CODE_PATTERN.lastIndex = 0;\n while ((inlineMatch = INLINE_CODE_PATTERN.exec(line)) !== null) {\n inlineCode.push({\n content: inlineMatch[1],\n line: lineNum,\n column: inlineMatch.index + 2,\n });\n }\n }\n }\n\n return { content, lines, paths, commands, sections, codeBlocks, inlineCode };\n}\n","import type { LintFinding } from './types.js';\n\n/**\n * Computes a 0–100 quality score for a file based on its findings.\n *\n * Starts at 100 and deducts:\n * - 15 points per error\n * - 5 points per warning\n *\n * Minimum score is 0.\n */\nexport function computeScore(findings: LintFinding[]): number {\n let score = 100;\n for (const finding of findings) {\n if (finding.severity === 'error') {\n score -= 15;\n } else {\n score -= 5;\n }\n }\n return Math.max(0, score);\n}\n","import { relative } from 'node:path';\nimport type { LintResult } from './types.js';\n\nexport function formatText(result: LintResult, cwd: string): string {\n const lines: string[] = [];\n\n for (const file of result.files) {\n const relPath = relative(cwd, file.file);\n lines.push(`\\n ${relPath} (score: ${file.score}/100)`);\n\n if (file.findings.length === 0) {\n lines.push(' No issues found.');\n continue;\n }\n\n for (const f of file.findings) {\n const icon = f.severity === 'error' ? 'x' : '!';\n lines.push(\n ` ${f.line}:${f.column} ${icon} ${f.message} [${f.rule}]`,\n );\n }\n }\n\n lines.push('');\n lines.push(\n ` ${result.totalFindings} problems (${result.errors} errors, ${result.warnings} warnings)`,\n );\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function formatJson(result: LintResult, cwd: string): string {\n const output = {\n ...result,\n files: result.files.map((f) => ({\n ...f,\n file: relative(cwd, f.file),\n })),\n };\n return JSON.stringify(output, null, 2);\n}\n"],"mappings":"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","names":["resolve","resolve","readFileSync","existsSync","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","resolve","resolve","existsSync","readFileSync","resolve","resolve"]}
|