agent-context-lint 0.1.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/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/cli.js +525 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +493 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +461 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +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":";;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,eAAe;AAI1B,SAAS,WACd,QACA,UACe;AACf,QAAM,WAA0B,CAAC;AACjC,QAAM,UAAU,QAAQ,QAAQ;AAEhC,aAAW,OAAO,OAAO,OAAO;AAC9B,UAAM,WAAW,QAAQ,SAAS,IAAI,KAAK;AAC3C,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,IAAI;AAAA,QACV,QAAQ,IAAI;AAAA,QACZ,UAAU;AAAA,QACV,SAAS,wBAAwB,IAAI,KAAK;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,aACd,QACA,UACe;AACf,QAAM,WAA0B,CAAC;AACjC,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,UAAU,QAAQ,SAAS,cAAc;AAE/C,MAAI,UAAkC,CAAC;AACvC,MAAI,WAAW,OAAO,GAAG;AACvB,QAAI;AACF,YAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AACrD,gBAAU,IAAI,WAAW,CAAC;AAAA,IAC5B,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF,OAAO;AAEL,WAAO;AAAA,EACT;AAEA,aAAW,OAAO,OAAO,UAAU;AAEjC,UAAM,QAAQ,6CAA6C,KAAK,IAAI,KAAK;AACzE,UAAM,cAAc,oDAAoD;AAAA,MACtE,IAAI;AAAA,IACN;AAEA,UAAM,aAAa,QAAQ,CAAC,KAAK,cAAc,CAAC;AAChD,QAAI,cAAc,EAAE,cAAc,UAAU;AAC1C,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,IAAI;AAAA,QACV,QAAQ,IAAI;AAAA,QACZ,UAAU;AAAA,QACV,SAAS,sCAAsC,UAAU;AAAA,MAC3D,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,iBACd,QACA,UACA,QACe;AACf,QAAM,WAA0B,CAAC;AAGjC,QAAM,kBAAkB,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC;AAE3D,MAAI,kBAAkB,OAAO,YAAY,OAAO;AAC9C,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS,YAAY,eAAe,mBAAmB,OAAO,YAAY,KAAK;AAAA,IACjF,CAAC;AAAA,EACH,WAAW,kBAAkB,OAAO,YAAY,MAAM;AACpD,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS,YAAY,eAAe,4BAA4B,OAAO,YAAY,IAAI;AAAA,IACzF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,SAAS,WACd,QACA,UACA,QACe;AACf,QAAM,WAA0B,CAAC;AAEjC,WAAS,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AAC5C,UAAM,OAAO,OAAO,MAAM,CAAC,EAAE,YAAY;AACzC,eAAW,WAAW,OAAO,eAAe;AAC1C,UAAI,KAAK,SAAS,QAAQ,YAAY,CAAC,GAAG;AACxC,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM,IAAI;AAAA,UACV,QAAQ,KAAK,QAAQ,QAAQ,YAAY,CAAC,IAAI;AAAA,UAC9C,UAAU;AAAA,UACV,SAAS,uBAAuB,OAAO;AAAA,QACzC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,sBACd,QACA,UACA,QACe;AACf,QAAM,WAA0B,CAAC;AACjC,QAAM,qBAAqB,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAErE,aAAW,YAAY,OAAO,kBAAkB;AAC9C,UAAM,QAAQ,mBAAmB;AAAA,MAC/B,CAAC,MAAM,EAAE,SAAS,SAAS,YAAY,CAAC;AAAA,IAC1C;AACA,QAAI,CAAC,OAAO;AACV,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SAAS,iCAAiC,QAAQ;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,gBACd,QACA,UACA,QACe;AACf,QAAM,WAA0B,CAAC;AACjC,QAAM,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC3C,QAAM,YAAY,cAAc,OAAO;AAEvC,QAAM,cAAc;AAEpB,WAAS,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AAC5C,QAAI;AACJ,gBAAY,YAAY;AACxB,YAAQ,QAAQ,YAAY,KAAK,OAAO,MAAM,CAAC,CAAC,OAAO,MAAM;AAC3D,YAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAClC,UAAI,OAAO,WAAW;AACpB,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM,IAAI;AAAA,UACV,QAAQ,MAAM,QAAQ;AAAA,UACtB,UAAU;AAAA,UACV,SAAS,kCAAkC,IAAI,gBAAgB,OAAO,cAAc;AAAA,QACtF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,oBACd,QACA,UACe;AACf,QAAM,WAA0B,CAAC;AAGjC,QAAM,qBAAiD;AAAA,IACrD;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,OAAO;AAEzB,aAAW,CAAC,UAAU,UAAU,OAAO,KAAK,oBAAoB;AAC9D,UAAM,WAAuD,CAAC;AAC9D,UAAM,WAAuD,CAAC;AAE9D,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,YAAM,WAAW,UAAU,CAAC;AAC5B,YAAM,IAAI,SAAS,KAAK,QAAQ;AAChC,UAAI,EAAG,UAAS,KAAK,EAAE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;AAC9C,YAAM,IAAI,SAAS,KAAK,QAAQ;AAChC,UAAI,EAAG,UAAS,KAAK,EAAE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;AAAA,IAChD;AAEA,QAAI,SAAS,SAAS,KAAK,SAAS,SAAS,GAAG;AAE9C,iBAAW,KAAK,UAAU;AACxB,mBAAW,KAAK,UAAU;AACxB,cACE,EAAE,MAAM,CAAC,KACT,EAAE,MAAM,CAAC,KACT,EAAE,MAAM,CAAC,EAAE,YAAY,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GACpD;AACA,qBAAS,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM,EAAE;AAAA,cACR,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,SAAS,GAAG,OAAO,yBAAyB,EAAE,IAAI;AAAA,YACpD,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC/PA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,WAAAC,gBAAe;;;ACoCjB,IAAM,iBAAyB;AAAA,EACpC,aAAa,EAAE,MAAM,KAAM,OAAO,IAAK;AAAA,EACvC,kBAAkB,CAAC,SAAS,WAAW,OAAO;AAAA,EAC9C,gBAAgB;AAAA,EAChB,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ,CAAC;AACX;AAEO,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AD7DO,SAAS,WAAW,KAAqB;AAE9C,QAAM,aAAaC,SAAQ,KAAK,0BAA0B;AAC1D,MAAIC,YAAW,UAAU,GAAG;AAC1B,QAAI;AACF,YAAM,MAAM,KAAK,MAAMC,cAAa,YAAY,OAAO,CAAC;AACxD,aAAO,YAAY,GAAG;AAAA,IACxB,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,UAAUF,SAAQ,KAAK,cAAc;AAC3C,MAAIC,YAAW,OAAO,GAAG;AACvB,QAAI;AACF,YAAM,MAAM,KAAK,MAAMC,cAAa,SAAS,OAAO,CAAC;AACrD,UAAI,IAAI,kBAAkB;AACxB,eAAO,YAAY,IAAI,gBAAgB;AAAA,MACzC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe;AAC7B;AAEA,SAAS,YAAY,WAAoC;AACvD,SAAO;AAAA,IACL,aAAa;AAAA,MACX,GAAG,eAAe;AAAA,MAClB,GAAG,UAAU;AAAA,IACf;AAAA,IACA,kBACE,UAAU,oBAAoB,eAAe;AAAA,IAC/C,gBAAgB,UAAU,kBAAkB,eAAe;AAAA,IAC3D,eAAe,UAAU,iBAAiB,eAAe;AAAA,IACzD,QAAQ,UAAU,UAAU,eAAe;AAAA,EAC7C;AACF;;;AE5CA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AAGjB,SAAS,qBAAqB,KAAuB;AAC1D,QAAM,QAAkB,CAAC;AACzB,aAAW,QAAQ,oBAAoB;AACrC,UAAM,WAAWC,SAAQ,KAAK,IAAI;AAClC,QAAIC,YAAW,QAAQ,GAAG;AACxB,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AACT;;;ACbA,SAAS,gBAAAC,qBAAoB;AAoC7B,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAErB,SAAS,UAAU,UAA8B;AACtD,QAAM,UAAUA,cAAa,UAAU,OAAO;AAC9C,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAEhC,QAAM,QAAyB,CAAC;AAChC,QAAM,WAA+B,CAAC;AACtC,QAAM,WAAqB,CAAC;AAC5B,QAAM,aAA0B,CAAC;AACjC,QAAM,aAA2B,CAAC;AAElC,MAAI,cAAc;AAClB,MAAI,gBAAgB;AACpB,MAAI,mBAAmB;AACvB,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,UAAU,IAAI;AAGpB,QAAI,CAAC,aAAa;AAChB,YAAM,aAAa,mBAAmB,KAAK,IAAI;AAC/C,UAAI,cAAc,KAAK,UAAU,EAAE,WAAW,KAAK,GAAG;AACpD,sBAAc;AACd,wBAAgB,WAAW,CAAC,KAAK;AACjC,2BAAmB;AACnB,yBAAiB;AACjB;AAAA,MACF;AAAA,IACF,OAAO;AACL,UAAI,iBAAiB,KAAK,IAAI,KAAK,KAAK,UAAU,MAAM,OAAO;AAC7D,mBAAW,KAAK;AAAA,UACd,SAAS;AAAA,UACT,MAAM;AAAA,UACN,MAAM;AAAA,QACR,CAAC;AACD,sBAAc;AACd;AAAA,MACF;AACA,2BAAqB,mBAAmB,OAAO,MAAM;AAAA,IACvD;AAGA,UAAM,eAAe,gBAAgB,KAAK,IAAI;AAC9C,QAAI,cAAc;AAChB,eAAS,KAAK,aAAa,CAAC,EAAE,KAAK,CAAC;AAAA,IACtC;AAGA,QAAI;AACJ,iBAAa,YAAY;AACzB,YAAQ,YAAY,aAAa,KAAK,IAAI,OAAO,MAAM;AACrD,YAAM,QAAQ,UAAU,CAAC;AAEzB,UAAI,MAAM,SAAS,KAAK,EAAG;AAC3B,YAAM,KAAK;AAAA,QACT;AAAA,QACA,MAAM;AAAA,QACN,QAAQ,UAAU,SAAS,UAAU,CAAC,EAAE,SAAS,MAAM,UAAU;AAAA,MACnE,CAAC;AAAA,IACH;AAGA,QAAI;AACJ,oBAAgB,YAAY;AAC5B,YAAQ,WAAW,gBAAgB,KAAK,IAAI,OAAO,MAAM;AACvD,eAAS,KAAK;AAAA,QACZ,OAAO,SAAS,CAAC;AAAA,QACjB,MAAM;AAAA,QACN,QAAQ,SAAS,QAAQ;AAAA,MAC3B,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,aAAa;AAChB,UAAI;AACJ,0BAAoB,YAAY;AAChC,cAAQ,cAAc,oBAAoB,KAAK,IAAI,OAAO,MAAM;AAC9D,mBAAW,KAAK;AAAA,UACd,SAAS,YAAY,CAAC;AAAA,UACtB,MAAM;AAAA,UACN,QAAQ,YAAY,QAAQ;AAAA,QAC9B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,OAAO,OAAO,UAAU,UAAU,YAAY,WAAW;AAC7E;;;ACxHO,SAAS,aAAa,UAAiC;AAC5D,MAAI,QAAQ;AACZ,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,aAAa,SAAS;AAChC,eAAS;AAAA,IACX,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO,KAAK,IAAI,GAAG,KAAK;AAC1B;;;ACrBA,SAAS,gBAAgB;AAGlB,SAAS,WAAW,QAAoB,KAAqB;AAClE,QAAM,QAAkB,CAAC;AAEzB,aAAW,QAAQ,OAAO,OAAO;AAC/B,UAAM,UAAU,SAAS,KAAK,KAAK,IAAI;AACvC,UAAM,KAAK;AAAA,IAAO,OAAO,aAAa,KAAK,KAAK,OAAO;AAEvD,QAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,YAAM,KAAK,sBAAsB;AACjC;AAAA,IACF;AAEA,eAAW,KAAK,KAAK,UAAU;AAC7B,YAAM,OAAO,EAAE,aAAa,UAAU,MAAM;AAC5C,YAAM;AAAA,QACJ,OAAO,EAAE,IAAI,IAAI,EAAE,MAAM,KAAK,IAAI,IAAI,EAAE,OAAO,MAAM,EAAE,IAAI;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,EAAE;AACb,QAAM;AAAA,IACJ,KAAK,OAAO,aAAa,cAAc,OAAO,MAAM,YAAY,OAAO,QAAQ;AAAA,EACjF;AACA,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,WAAW,QAAoB,KAAqB;AAClE,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,OAAO,OAAO,MAAM,IAAI,CAAC,OAAO;AAAA,MAC9B,GAAG;AAAA,MACH,MAAM,SAAS,KAAK,EAAE,IAAI;AAAA,IAC5B,EAAE;AAAA,EACJ;AACA,SAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AACvC;;;APlBO,SAAS,SAAS,UAAkB,KAAyB;AAClE,QAAM,SAAS,WAAW,GAAG;AAC7B,QAAM,SAAS,UAAU,QAAQ;AAEjC,QAAM,WAA0B;AAAA,IAC9B,GAAG,WAAW,QAAQ,QAAQ;AAAA,IAC9B,GAAG,aAAa,QAAQ,QAAQ;AAAA,IAChC,GAAG,iBAAiB,QAAQ,UAAU,MAAM;AAAA,IAC5C,GAAG,WAAW,QAAQ,UAAU,MAAM;AAAA,IACtC,GAAG,sBAAsB,QAAQ,UAAU,MAAM;AAAA,IACjD,GAAG,gBAAgB,QAAQ,UAAU,MAAM;AAAA,IAC3C,GAAG,oBAAoB,QAAQ,QAAQ;AAAA,EACzC;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,OAAO,aAAa,QAAQ;AAAA,EAC9B;AACF;AAEO,SAAS,KAAK,KAAa,OAA8B;AAC9D,QAAM,cACJ,SAAS,MAAM,SAAS,IACpB,MAAM,IAAI,CAAC,MAAMC,SAAQ,KAAK,CAAC,CAAC,IAChC,qBAAqB,GAAG;AAE9B,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,EAAE,OAAO,CAAC,GAAG,eAAe,GAAG,QAAQ,GAAG,UAAU,EAAE;AAAA,EAC/D;AAEA,QAAM,UAAU,YAAY,IAAI,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAEvD,QAAM,gBAAgB,QAAQ;AAAA,IAC5B,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS;AAAA,IAC7B;AAAA,EACF;AACA,QAAM,SAAS,QAAQ;AAAA,IACrB,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AAAA,IACnE;AAAA,EACF;AACA,QAAM,WAAW,QAAQ;AAAA,IACvB,CAAC,KAAK,MACJ,MAAM,EAAE,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,EAAE;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,SAAS,eAAe,QAAQ,SAAS;AAC3D;;;AQnEA,SAAS,UAAU,MAA4B;AAC7C,QAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAM,UAAsB;AAAA,IAC1B,OAAO,CAAC;AAAA,IACR,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,KAAK,QAAQ,IAAI;AAAA,EACnB;AAEA,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,cAAc,KAAK,IAAI,CAAC,GAAG;AACrC,YAAM,MAAM,KAAK,EAAE,CAAC;AACpB,UAAI,QAAQ,UAAU,QAAQ,QAAQ;AACpC,gBAAQ,SAAS;AAAA,MACnB;AAAA,IACF,WAAW,QAAQ,UAAU;AAC3B,cAAQ,SAAS;AAAA,IACnB,WAAW,QAAQ,SAAS;AAC1B,cAAQ,MAAM;AAAA,IAChB,WAAW,QAAQ,YAAY,QAAQ,MAAM;AAC3C,gBAAU;AACV,cAAQ,KAAK,CAAC;AAAA,IAChB,WAAW,QAAQ,eAAe,QAAQ,MAAM;AAC9C,cAAQ,IAAI,OAAO;AACnB,cAAQ,KAAK,CAAC;AAAA,IAChB,WAAW,CAAC,IAAI,WAAW,GAAG,GAAG;AAC/B,cAAQ,MAAM,KAAK,GAAG;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAqBb;AACD;AAEA,SAAS,OAAa;AACpB,QAAM,UAAU,UAAU,QAAQ,IAAI;AACtC,QAAM,SAAS;AAAA,IACb,QAAQ;AAAA,IACR,QAAQ,MAAM,SAAS,IAAI,QAAQ,QAAQ;AAAA,EAC7C;AAEA,MAAI,OAAO,MAAM,WAAW,GAAG;AAC7B,YAAQ,IAAI,yBAAyB;AACrC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SACJ,QAAQ,WAAW,SACf,WAAW,QAAQ,QAAQ,GAAG,IAC9B,WAAW,QAAQ,QAAQ,GAAG;AAEpC,UAAQ,IAAI,MAAM;AAClB,UAAQ,KAAK,OAAO,SAAS,IAAI,IAAI,CAAC;AACxC;AAEA,KAAK;","names":["resolve","existsSync","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","resolve","resolve","existsSync","readFileSync","resolve"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
computeScore: () => computeScore,
|
|
24
|
+
discoverContextFiles: () => discoverContextFiles,
|
|
25
|
+
formatJson: () => formatJson,
|
|
26
|
+
formatText: () => formatText,
|
|
27
|
+
lint: () => lint,
|
|
28
|
+
lintFile: () => lintFile,
|
|
29
|
+
loadConfig: () => loadConfig,
|
|
30
|
+
parseFile: () => parseFile
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
var import_node_path5 = require("path");
|
|
34
|
+
|
|
35
|
+
// src/checkers.ts
|
|
36
|
+
var import_node_fs = require("fs");
|
|
37
|
+
var import_node_path = require("path");
|
|
38
|
+
function checkPaths(parsed, filePath) {
|
|
39
|
+
const findings = [];
|
|
40
|
+
const baseDir = (0, import_node_path.dirname)(filePath);
|
|
41
|
+
for (const ref of parsed.paths) {
|
|
42
|
+
const resolved = (0, import_node_path.resolve)(baseDir, ref.value);
|
|
43
|
+
if (!(0, import_node_fs.existsSync)(resolved)) {
|
|
44
|
+
findings.push({
|
|
45
|
+
file: filePath,
|
|
46
|
+
rule: "check:paths",
|
|
47
|
+
line: ref.line,
|
|
48
|
+
column: ref.column,
|
|
49
|
+
severity: "error",
|
|
50
|
+
message: `Path does not exist: ${ref.value}`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return findings;
|
|
55
|
+
}
|
|
56
|
+
function checkScripts(parsed, filePath) {
|
|
57
|
+
const findings = [];
|
|
58
|
+
const baseDir = (0, import_node_path.dirname)(filePath);
|
|
59
|
+
const pkgPath = (0, import_node_path.resolve)(baseDir, "package.json");
|
|
60
|
+
let scripts = {};
|
|
61
|
+
if ((0, import_node_fs.existsSync)(pkgPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
|
|
64
|
+
scripts = pkg.scripts || {};
|
|
65
|
+
} catch {
|
|
66
|
+
return findings;
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
return findings;
|
|
70
|
+
}
|
|
71
|
+
for (const cmd of parsed.commands) {
|
|
72
|
+
const match = /(?:npm|pnpm|yarn|bun)\s+run\s+([\w:@./-]+)/.exec(cmd.value);
|
|
73
|
+
const directMatch = /(?:npm|pnpm|yarn|bun)\s+(test|start|build|lint)\b/.exec(
|
|
74
|
+
cmd.value
|
|
75
|
+
);
|
|
76
|
+
const scriptName = match?.[1] || directMatch?.[1];
|
|
77
|
+
if (scriptName && !(scriptName in scripts)) {
|
|
78
|
+
findings.push({
|
|
79
|
+
file: filePath,
|
|
80
|
+
rule: "check:scripts",
|
|
81
|
+
line: cmd.line,
|
|
82
|
+
column: cmd.column,
|
|
83
|
+
severity: "error",
|
|
84
|
+
message: `Script not found in package.json: "${scriptName}"`
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return findings;
|
|
89
|
+
}
|
|
90
|
+
function checkTokenBudget(parsed, filePath, config) {
|
|
91
|
+
const findings = [];
|
|
92
|
+
const estimatedTokens = Math.ceil(parsed.content.length / 4);
|
|
93
|
+
if (estimatedTokens > config.tokenBudget.error) {
|
|
94
|
+
findings.push({
|
|
95
|
+
file: filePath,
|
|
96
|
+
rule: "check:token-budget",
|
|
97
|
+
line: 1,
|
|
98
|
+
column: 1,
|
|
99
|
+
severity: "error",
|
|
100
|
+
message: `File is ~${estimatedTokens} tokens (limit: ${config.tokenBudget.error}). Consider splitting or condensing.`
|
|
101
|
+
});
|
|
102
|
+
} else if (estimatedTokens > config.tokenBudget.warn) {
|
|
103
|
+
findings.push({
|
|
104
|
+
file: filePath,
|
|
105
|
+
rule: "check:token-budget",
|
|
106
|
+
line: 1,
|
|
107
|
+
column: 1,
|
|
108
|
+
severity: "warning",
|
|
109
|
+
message: `File is ~${estimatedTokens} tokens (warn threshold: ${config.tokenBudget.warn}). Consider condensing.`
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return findings;
|
|
113
|
+
}
|
|
114
|
+
function checkVague(parsed, filePath, config) {
|
|
115
|
+
const findings = [];
|
|
116
|
+
for (let i = 0; i < parsed.lines.length; i++) {
|
|
117
|
+
const line = parsed.lines[i].toLowerCase();
|
|
118
|
+
for (const pattern of config.vaguePatterns) {
|
|
119
|
+
if (line.includes(pattern.toLowerCase())) {
|
|
120
|
+
findings.push({
|
|
121
|
+
file: filePath,
|
|
122
|
+
rule: "check:vague",
|
|
123
|
+
line: i + 1,
|
|
124
|
+
column: line.indexOf(pattern.toLowerCase()) + 1,
|
|
125
|
+
severity: "warning",
|
|
126
|
+
message: `Vague instruction: "${pattern}". Replace with specific, actionable guidance.`
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return findings;
|
|
132
|
+
}
|
|
133
|
+
function checkRequiredSections(parsed, filePath, config) {
|
|
134
|
+
const findings = [];
|
|
135
|
+
const normalizedSections = parsed.sections.map((s) => s.toLowerCase());
|
|
136
|
+
for (const required of config.requiredSections) {
|
|
137
|
+
const found = normalizedSections.some(
|
|
138
|
+
(s) => s.includes(required.toLowerCase())
|
|
139
|
+
);
|
|
140
|
+
if (!found) {
|
|
141
|
+
findings.push({
|
|
142
|
+
file: filePath,
|
|
143
|
+
rule: "check:required-sections",
|
|
144
|
+
line: 1,
|
|
145
|
+
column: 1,
|
|
146
|
+
severity: "warning",
|
|
147
|
+
message: `Missing recommended section: "${required}"`
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return findings;
|
|
152
|
+
}
|
|
153
|
+
function checkStaleDates(parsed, filePath, config) {
|
|
154
|
+
const findings = [];
|
|
155
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
156
|
+
const threshold = currentYear - config.staleDateYears;
|
|
157
|
+
const yearPattern = /\b(20[0-9]{2})\b/g;
|
|
158
|
+
for (let i = 0; i < parsed.lines.length; i++) {
|
|
159
|
+
let match;
|
|
160
|
+
yearPattern.lastIndex = 0;
|
|
161
|
+
while ((match = yearPattern.exec(parsed.lines[i])) !== null) {
|
|
162
|
+
const year = parseInt(match[1], 10);
|
|
163
|
+
if (year < threshold) {
|
|
164
|
+
findings.push({
|
|
165
|
+
file: filePath,
|
|
166
|
+
rule: "check:stale-dates",
|
|
167
|
+
line: i + 1,
|
|
168
|
+
column: match.index + 1,
|
|
169
|
+
severity: "warning",
|
|
170
|
+
message: `Possibly stale year reference: ${year} (older than ${config.staleDateYears} years)`
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return findings;
|
|
176
|
+
}
|
|
177
|
+
function checkContradictions(parsed, filePath) {
|
|
178
|
+
const findings = [];
|
|
179
|
+
const contradictionPairs = [
|
|
180
|
+
[
|
|
181
|
+
/\balways use (\w+)/i,
|
|
182
|
+
/\bnever use (\w+)/i,
|
|
183
|
+
'Contradictory "always use" and "never use" directives'
|
|
184
|
+
],
|
|
185
|
+
[
|
|
186
|
+
/\bdo not (?:use|add|include) (comments|docstrings|type annotations)/i,
|
|
187
|
+
/\b(?:always|must) (?:add|include|write) \1/i,
|
|
188
|
+
"Contradictory directives about adding/not adding"
|
|
189
|
+
],
|
|
190
|
+
[
|
|
191
|
+
/\bprefer (\w+) over (\w+)/i,
|
|
192
|
+
/\bprefer \2 over \1/i,
|
|
193
|
+
"Contradictory preference directives"
|
|
194
|
+
]
|
|
195
|
+
];
|
|
196
|
+
const lineTexts = parsed.lines;
|
|
197
|
+
for (const [patternA, patternB, message] of contradictionPairs) {
|
|
198
|
+
const matchesA = [];
|
|
199
|
+
const matchesB = [];
|
|
200
|
+
for (let i = 0; i < lineTexts.length; i++) {
|
|
201
|
+
const lineText = lineTexts[i];
|
|
202
|
+
const a = patternA.exec(lineText);
|
|
203
|
+
if (a) matchesA.push({ line: i + 1, match: a });
|
|
204
|
+
const b = patternB.exec(lineText);
|
|
205
|
+
if (b) matchesB.push({ line: i + 1, match: b });
|
|
206
|
+
}
|
|
207
|
+
if (matchesA.length > 0 && matchesB.length > 0) {
|
|
208
|
+
for (const a of matchesA) {
|
|
209
|
+
for (const b of matchesB) {
|
|
210
|
+
if (a.match[1] && b.match[1] && a.match[1].toLowerCase() === b.match[1].toLowerCase()) {
|
|
211
|
+
findings.push({
|
|
212
|
+
file: filePath,
|
|
213
|
+
rule: "check:contradictions",
|
|
214
|
+
line: b.line,
|
|
215
|
+
column: 1,
|
|
216
|
+
severity: "warning",
|
|
217
|
+
message: `${message} (conflicts with line ${a.line})`
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return findings;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/config.ts
|
|
228
|
+
var import_node_fs2 = require("fs");
|
|
229
|
+
var import_node_path2 = require("path");
|
|
230
|
+
|
|
231
|
+
// src/types.ts
|
|
232
|
+
var DEFAULT_CONFIG = {
|
|
233
|
+
tokenBudget: { warn: 2e3, error: 5e3 },
|
|
234
|
+
requiredSections: ["Setup", "Testing", "Build"],
|
|
235
|
+
staleDateYears: 2,
|
|
236
|
+
vaguePatterns: [
|
|
237
|
+
"follow best practices",
|
|
238
|
+
"be careful",
|
|
239
|
+
"use good judgment",
|
|
240
|
+
"use common sense",
|
|
241
|
+
"as appropriate",
|
|
242
|
+
"when necessary",
|
|
243
|
+
"if needed",
|
|
244
|
+
"as needed",
|
|
245
|
+
"handle edge cases",
|
|
246
|
+
"write clean code",
|
|
247
|
+
"keep it simple",
|
|
248
|
+
"use proper",
|
|
249
|
+
"ensure quality"
|
|
250
|
+
],
|
|
251
|
+
ignore: []
|
|
252
|
+
};
|
|
253
|
+
var CONTEXT_FILE_NAMES = [
|
|
254
|
+
"CLAUDE.md",
|
|
255
|
+
"AGENTS.md",
|
|
256
|
+
".cursorrules",
|
|
257
|
+
"copilot-instructions.md",
|
|
258
|
+
".github/copilot-instructions.md"
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
// src/config.ts
|
|
262
|
+
function loadConfig(cwd) {
|
|
263
|
+
const configPath = (0, import_node_path2.resolve)(cwd, ".agent-context-lint.json");
|
|
264
|
+
if ((0, import_node_fs2.existsSync)(configPath)) {
|
|
265
|
+
try {
|
|
266
|
+
const raw = JSON.parse((0, import_node_fs2.readFileSync)(configPath, "utf-8"));
|
|
267
|
+
return mergeConfig(raw);
|
|
268
|
+
} catch {
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const pkgPath = (0, import_node_path2.resolve)(cwd, "package.json");
|
|
272
|
+
if ((0, import_node_fs2.existsSync)(pkgPath)) {
|
|
273
|
+
try {
|
|
274
|
+
const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf-8"));
|
|
275
|
+
if (pkg.agentContextLint) {
|
|
276
|
+
return mergeConfig(pkg.agentContextLint);
|
|
277
|
+
}
|
|
278
|
+
} catch {
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return { ...DEFAULT_CONFIG };
|
|
282
|
+
}
|
|
283
|
+
function mergeConfig(overrides) {
|
|
284
|
+
return {
|
|
285
|
+
tokenBudget: {
|
|
286
|
+
...DEFAULT_CONFIG.tokenBudget,
|
|
287
|
+
...overrides.tokenBudget
|
|
288
|
+
},
|
|
289
|
+
requiredSections: overrides.requiredSections ?? DEFAULT_CONFIG.requiredSections,
|
|
290
|
+
staleDateYears: overrides.staleDateYears ?? DEFAULT_CONFIG.staleDateYears,
|
|
291
|
+
vaguePatterns: overrides.vaguePatterns ?? DEFAULT_CONFIG.vaguePatterns,
|
|
292
|
+
ignore: overrides.ignore ?? DEFAULT_CONFIG.ignore
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/discovery.ts
|
|
297
|
+
var import_node_fs3 = require("fs");
|
|
298
|
+
var import_node_path3 = require("path");
|
|
299
|
+
function discoverContextFiles(cwd) {
|
|
300
|
+
const found = [];
|
|
301
|
+
for (const name of CONTEXT_FILE_NAMES) {
|
|
302
|
+
const fullPath = (0, import_node_path3.resolve)(cwd, name);
|
|
303
|
+
if ((0, import_node_fs3.existsSync)(fullPath)) {
|
|
304
|
+
found.push(fullPath);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return found;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/parser.ts
|
|
311
|
+
var import_node_fs4 = require("fs");
|
|
312
|
+
var PATH_PATTERN = /(?:^|\s|`)(\.?\.?\/[\w./@-]+[\w/@-])/g;
|
|
313
|
+
var COMMAND_PATTERN = /(?:npm|npx|pnpm|yarn|bun|bunx)\s+(?:run\s+)?[\w:@./-]+/g;
|
|
314
|
+
var HEADING_PATTERN = /^#{1,6}\s+(.+)$/;
|
|
315
|
+
var FENCED_BLOCK_START = /^```(\w*)/;
|
|
316
|
+
var FENCED_BLOCK_END = /^```\s*$/;
|
|
317
|
+
var INLINE_CODE_PATTERN = /`([^`]+)`/g;
|
|
318
|
+
function parseFile(filePath) {
|
|
319
|
+
const content = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
|
|
320
|
+
const lines = content.split("\n");
|
|
321
|
+
const paths = [];
|
|
322
|
+
const commands = [];
|
|
323
|
+
const sections = [];
|
|
324
|
+
const codeBlocks = [];
|
|
325
|
+
const inlineCode = [];
|
|
326
|
+
let inCodeBlock = false;
|
|
327
|
+
let codeBlockLang = "";
|
|
328
|
+
let codeBlockContent = "";
|
|
329
|
+
let codeBlockStart = 0;
|
|
330
|
+
for (let i = 0; i < lines.length; i++) {
|
|
331
|
+
const line = lines[i];
|
|
332
|
+
const lineNum = i + 1;
|
|
333
|
+
if (!inCodeBlock) {
|
|
334
|
+
const blockStart = FENCED_BLOCK_START.exec(line);
|
|
335
|
+
if (blockStart && line.trimStart().startsWith("```")) {
|
|
336
|
+
inCodeBlock = true;
|
|
337
|
+
codeBlockLang = blockStart[1] || "";
|
|
338
|
+
codeBlockContent = "";
|
|
339
|
+
codeBlockStart = lineNum;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
if (FENCED_BLOCK_END.test(line) && line.trimStart() === "```") {
|
|
344
|
+
codeBlocks.push({
|
|
345
|
+
content: codeBlockContent,
|
|
346
|
+
lang: codeBlockLang,
|
|
347
|
+
line: codeBlockStart
|
|
348
|
+
});
|
|
349
|
+
inCodeBlock = false;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
codeBlockContent += (codeBlockContent ? "\n" : "") + line;
|
|
353
|
+
}
|
|
354
|
+
const headingMatch = HEADING_PATTERN.exec(line);
|
|
355
|
+
if (headingMatch) {
|
|
356
|
+
sections.push(headingMatch[1].trim());
|
|
357
|
+
}
|
|
358
|
+
let pathMatch;
|
|
359
|
+
PATH_PATTERN.lastIndex = 0;
|
|
360
|
+
while ((pathMatch = PATH_PATTERN.exec(line)) !== null) {
|
|
361
|
+
const value = pathMatch[1];
|
|
362
|
+
if (value.includes("://")) continue;
|
|
363
|
+
paths.push({
|
|
364
|
+
value,
|
|
365
|
+
line: lineNum,
|
|
366
|
+
column: pathMatch.index + (pathMatch[0].length - value.length) + 1
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
let cmdMatch;
|
|
370
|
+
COMMAND_PATTERN.lastIndex = 0;
|
|
371
|
+
while ((cmdMatch = COMMAND_PATTERN.exec(line)) !== null) {
|
|
372
|
+
commands.push({
|
|
373
|
+
value: cmdMatch[0],
|
|
374
|
+
line: lineNum,
|
|
375
|
+
column: cmdMatch.index + 1
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
if (!inCodeBlock) {
|
|
379
|
+
let inlineMatch;
|
|
380
|
+
INLINE_CODE_PATTERN.lastIndex = 0;
|
|
381
|
+
while ((inlineMatch = INLINE_CODE_PATTERN.exec(line)) !== null) {
|
|
382
|
+
inlineCode.push({
|
|
383
|
+
content: inlineMatch[1],
|
|
384
|
+
line: lineNum,
|
|
385
|
+
column: inlineMatch.index + 2
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return { content, lines, paths, commands, sections, codeBlocks, inlineCode };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/scorer.ts
|
|
394
|
+
function computeScore(findings) {
|
|
395
|
+
let score = 100;
|
|
396
|
+
for (const finding of findings) {
|
|
397
|
+
if (finding.severity === "error") {
|
|
398
|
+
score -= 15;
|
|
399
|
+
} else {
|
|
400
|
+
score -= 5;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return Math.max(0, score);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/reporter.ts
|
|
407
|
+
var import_node_path4 = require("path");
|
|
408
|
+
function formatText(result, cwd) {
|
|
409
|
+
const lines = [];
|
|
410
|
+
for (const file of result.files) {
|
|
411
|
+
const relPath = (0, import_node_path4.relative)(cwd, file.file);
|
|
412
|
+
lines.push(`
|
|
413
|
+
${relPath} (score: ${file.score}/100)`);
|
|
414
|
+
if (file.findings.length === 0) {
|
|
415
|
+
lines.push(" No issues found.");
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
for (const f of file.findings) {
|
|
419
|
+
const icon = f.severity === "error" ? "x" : "!";
|
|
420
|
+
lines.push(
|
|
421
|
+
` ${f.line}:${f.column} ${icon} ${f.message} [${f.rule}]`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
lines.push("");
|
|
426
|
+
lines.push(
|
|
427
|
+
` ${result.totalFindings} problems (${result.errors} errors, ${result.warnings} warnings)`
|
|
428
|
+
);
|
|
429
|
+
lines.push("");
|
|
430
|
+
return lines.join("\n");
|
|
431
|
+
}
|
|
432
|
+
function formatJson(result, cwd) {
|
|
433
|
+
const output = {
|
|
434
|
+
...result,
|
|
435
|
+
files: result.files.map((f) => ({
|
|
436
|
+
...f,
|
|
437
|
+
file: (0, import_node_path4.relative)(cwd, f.file)
|
|
438
|
+
}))
|
|
439
|
+
};
|
|
440
|
+
return JSON.stringify(output, null, 2);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/index.ts
|
|
444
|
+
function lintFile(filePath, cwd) {
|
|
445
|
+
const config = loadConfig(cwd);
|
|
446
|
+
const parsed = parseFile(filePath);
|
|
447
|
+
const findings = [
|
|
448
|
+
...checkPaths(parsed, filePath),
|
|
449
|
+
...checkScripts(parsed, filePath),
|
|
450
|
+
...checkTokenBudget(parsed, filePath, config),
|
|
451
|
+
...checkVague(parsed, filePath, config),
|
|
452
|
+
...checkRequiredSections(parsed, filePath, config),
|
|
453
|
+
...checkStaleDates(parsed, filePath, config),
|
|
454
|
+
...checkContradictions(parsed, filePath)
|
|
455
|
+
];
|
|
456
|
+
return {
|
|
457
|
+
file: filePath,
|
|
458
|
+
findings,
|
|
459
|
+
score: computeScore(findings)
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function lint(cwd, files) {
|
|
463
|
+
const targetFiles = files && files.length > 0 ? files.map((f) => (0, import_node_path5.resolve)(cwd, f)) : discoverContextFiles(cwd);
|
|
464
|
+
if (targetFiles.length === 0) {
|
|
465
|
+
return { files: [], totalFindings: 0, errors: 0, warnings: 0 };
|
|
466
|
+
}
|
|
467
|
+
const results = targetFiles.map((f) => lintFile(f, cwd));
|
|
468
|
+
const totalFindings = results.reduce(
|
|
469
|
+
(sum, r) => sum + r.findings.length,
|
|
470
|
+
0
|
|
471
|
+
);
|
|
472
|
+
const errors = results.reduce(
|
|
473
|
+
(sum, r) => sum + r.findings.filter((f) => f.severity === "error").length,
|
|
474
|
+
0
|
|
475
|
+
);
|
|
476
|
+
const warnings = results.reduce(
|
|
477
|
+
(sum, r) => sum + r.findings.filter((f) => f.severity === "warning").length,
|
|
478
|
+
0
|
|
479
|
+
);
|
|
480
|
+
return { files: results, totalFindings, errors, warnings };
|
|
481
|
+
}
|
|
482
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
483
|
+
0 && (module.exports = {
|
|
484
|
+
computeScore,
|
|
485
|
+
discoverContextFiles,
|
|
486
|
+
formatJson,
|
|
487
|
+
formatText,
|
|
488
|
+
lint,
|
|
489
|
+
lintFile,
|
|
490
|
+
loadConfig,
|
|
491
|
+
parseFile
|
|
492
|
+
});
|
|
493
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"],"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"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_path"]}
|