unguard 0.16.0 → 0.16.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/dist/cli.js CHANGED
@@ -38,10 +38,15 @@ async function main(argv) {
38
38
  concurrency: { type: "string" },
39
39
  "no-baseline": { type: "boolean", default: false },
40
40
  "no-cache": { type: "boolean", default: false },
41
+ version: { type: "boolean", short: "v", default: false },
41
42
  help: { type: "boolean", short: "h", default: false }
42
43
  },
43
44
  allowPositionals: true
44
45
  });
46
+ if (values.version) {
47
+ console.log(readVersion());
48
+ return 0;
49
+ }
45
50
  if (values.help) {
46
51
  printHelp();
47
52
  return 0;
@@ -200,6 +205,11 @@ function printErrorAndFail(err) {
200
205
  console.error(pc.red(message));
201
206
  return 1;
202
207
  }
208
+ function readVersion() {
209
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
210
+ const version = pkg.version;
211
+ return typeof version === "string" ? version : "unknown";
212
+ }
203
213
  function printHelp() {
204
214
  console.log(`unguard: data-shape static analyzer
205
215
 
@@ -231,6 +241,7 @@ Options:
231
241
  --concurrency <n> Worker threads for tsconfig groups (default: auto, 1 disables)
232
242
  --no-baseline Ignore unguard.baseline.json for this scan
233
243
  --no-cache Disable on-disk diagnostic cache (node_modules/.cache/unguard)
244
+ -v, --version Print version and exit
234
245
  -h, --help Show this help
235
246
 
236
247
  Exit codes:
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport pc from \"picocolors\";\nimport { executeScan, type FailOn, type RulePolicyEntry, type RulePolicySeverity, type Severity } from \"./engine.ts\";\nimport { BASELINE_FILENAME, buildBaseline, loadBaseline, writeBaseline, type BaselineData } from \"./scan/baseline.ts\";\nimport { isFailOn, isRulePolicySeverity, isSeverity, toRulePolicyEntries } from \"./scan/config.ts\";\nimport { computeExitCode } from \"./scan/policy.ts\";\nimport type { RulePolicy, RuleOverride } from \"./scan/types.ts\";\nimport type { Diagnostic } from \"./rules/types.ts\";\n\ninterface UnguardConfig {\n paths?: string[];\n ignore?: string[];\n rules?: RulePolicy;\n overrides?: RuleOverride[];\n failOn?: FailOn;\n severity?: Severity[];\n concurrency?: number;\n cache?: boolean;\n}\n\nconst COMMANDS = new Set([\"scan\", \"audit\", \"baseline\"]);\n\n// @unguard unused-export CLI entry point\nexport async function main(argv: string[]): Promise<number> {\n const rawArgs = argv.slice(2);\n const first = rawArgs[0];\n const command = first !== undefined && COMMANDS.has(first) ? first : \"scan\";\n const userArgs = first !== undefined && COMMANDS.has(first) ? rawArgs.slice(1) : rawArgs;\n\n const { values, positionals: cliPaths } = parseArgs({\n args: userArgs,\n options: {\n strict: { type: \"boolean\", default: false },\n filter: { type: \"string\" },\n fix: { type: \"boolean\", default: false },\n format: { type: \"string\", default: \"grouped\" },\n severity: { type: \"string\", multiple: true, default: [] },\n ignore: { type: \"string\", multiple: true, default: [] },\n rule: { type: \"string\", multiple: true, default: [] },\n config: { type: \"string\" },\n \"fail-on\": { type: \"string\" },\n concurrency: { type: \"string\" },\n \"no-baseline\": { type: \"boolean\", default: false },\n \"no-cache\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n allowPositionals: true,\n });\n\n if (values.help) {\n printHelp();\n return 0;\n }\n\n if (values.format !== \"grouped\" && values.format !== \"flat\" && values.format !== \"json\") {\n console.error(pc.red(`Invalid --format value \"${values.format}\". Use grouped, flat, or json.`));\n return 1;\n }\n\n let config: UnguardConfig | null = null;\n try {\n const configPath = findConfigPath(values.config);\n config = configPath ? loadConfig(configPath) : null;\n } catch (err) {\n return printErrorAndFail(err);\n }\n\n const rulePolicyResult = parseRulePolicyArgs(values.rule);\n if (!rulePolicyResult.ok) {\n console.error(pc.red(rulePolicyResult.message));\n return 1;\n }\n\n const severityFiltersResult = parseSeverityFilters(values.severity);\n if (!severityFiltersResult.ok) {\n console.error(pc.red(severityFiltersResult.message));\n return 1;\n }\n\n // Only an explicit --fail-on makes audit exit nonzero; config failOn\n // applies to scan only.\n const failOnResult = command === \"audit\"\n ? resolveFailOn(values[\"fail-on\"], \"none\")\n : resolveFailOn(values[\"fail-on\"], \"info\", config?.failOn);\n if (!failOnResult.ok) {\n console.error(pc.red(failOnResult.message));\n return 1;\n }\n\n const concurrencyResult = resolveConcurrency(values.concurrency, config?.concurrency);\n if (!concurrencyResult.ok) {\n console.error(pc.red(concurrencyResult.message));\n return 1;\n }\n\n const paths = cliPaths.length > 0 ? cliPaths : config?.paths ?? [];\n const ignore = [...(config?.ignore ?? []), ...values.ignore];\n const rulePolicy = [\n ...toRulePolicyEntries(config?.rules),\n ...rulePolicyResult.value,\n ];\n\n const cacheEnabled = values[\"no-cache\"] ? false : config?.cache ?? true;\n\n // The baseline subcommand regenerates the file, so the existing one must\n // not suppress anything during its scan.\n let baseline: BaselineData | null = null;\n if (command === \"scan\" && !values[\"no-baseline\"]) {\n try {\n baseline = loadBaseline(process.cwd());\n } catch (err) {\n return printErrorAndFail(err);\n }\n }\n\n const execution = await executeScan({\n paths,\n mode: command === \"audit\" ? \"audit\" : \"scan\",\n strict: values.strict,\n rules: values.filter ? [values.filter] : undefined,\n ignore: ignore.length > 0 ? ignore : undefined,\n rulePolicy: rulePolicy.length > 0 ? rulePolicy : undefined,\n overrides: config?.overrides,\n showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value : config?.severity,\n failOn: failOnResult.value,\n concurrency: concurrencyResult.value,\n cache: cacheEnabled,\n baseline: baseline ?? undefined,\n });\n\n if (command === \"baseline\") {\n const data = buildBaseline(execution.visibleDiagnostics, process.cwd());\n writeBaseline(data, process.cwd());\n console.log(\n `Baseline written to ${BASELINE_FILENAME}: ${plural(execution.visibleDiagnostics.length, \"known issue\")} across ${plural(Object.keys(data.rules).length, \"file\")}.`,\n );\n return 0;\n }\n\n let diagnostics = execution.visibleDiagnostics;\n let exitCode = execution.exitCode;\n let fixedCount = 0;\n let fixedFileCount = 0;\n\n if (values.fix) {\n const result = applyFixes(diagnostics);\n fixedCount = result.applied;\n fixedFileCount = result.fileCount;\n diagnostics = diagnostics.filter((d) => !result.fixed.has(d));\n exitCode = computeExitCode(diagnostics, failOnResult.value);\n }\n\n if (values.format === \"json\") {\n console.log(JSON.stringify(buildJsonReport(diagnostics, execution.fileCount, exitCode, values.fix ? fixedCount : null), null, 2));\n return exitCode;\n }\n\n if (baseline !== null) {\n console.log(pc.dim(`Using ${BASELINE_FILENAME} (run \"unguard baseline\" to regenerate, --no-baseline to ignore)`));\n }\n if (values.fix && fixedCount > 0) {\n console.log(pc.green(`Applied ${fixedCount} fix${fixedCount === 1 ? \"\" : \"es\"} in ${fixedFileCount} file${fixedFileCount === 1 ? \"\" : \"s\"}. Re-run unguard to verify.`));\n }\n\n if (diagnostics.length === 0) {\n console.log(pc.green(`No issues found in ${plural(execution.fileCount, \"file\")}.`));\n return exitCode;\n }\n\n if (values.format === \"flat\") {\n printDiagnosticsFlat(diagnostics);\n } else {\n printDiagnostics(diagnostics);\n }\n printSummary(diagnostics, execution.fileCount);\n\n return exitCode;\n}\n\ninterface JsonDiagnostic {\n file: string;\n line: number;\n column: number;\n severity: Severity;\n ruleId: string;\n message: string;\n annotation?: string;\n fixable: boolean;\n}\n\nfunction buildJsonReport(\n diagnostics: Diagnostic[],\n fileCount: number,\n exitCode: number,\n fixedCount: number | null,\n): { diagnostics: JsonDiagnostic[]; fileCount: number; exitCode: number; fixedCount?: number } {\n return {\n diagnostics: diagnostics.map((d) => ({\n file: d.file,\n line: d.line,\n column: d.column,\n severity: d.severity,\n ruleId: d.ruleId,\n message: d.message,\n ...(d.annotation !== undefined ? { annotation: d.annotation } : {}),\n fixable: d.fix !== undefined,\n })),\n fileCount,\n exitCode,\n ...(fixedCount !== null ? { fixedCount } : {}),\n };\n}\n\n/**\n * Apply fix edits, last-to-first per file so earlier offsets stay valid.\n * Overlapping edits in one pass are skipped — the re-run picks them up.\n */\nfunction applyFixes(diagnostics: Diagnostic[]): { applied: number; fileCount: number; fixed: Set<Diagnostic> } {\n const byFile = groupByFile(diagnostics.filter((d) => d.fix !== undefined));\n\n const fixed = new Set<Diagnostic>();\n for (const [file, fileDiagnostics] of byFile) {\n const ordered = [...fileDiagnostics].sort((a, b) => (b.fix?.start ?? 0) - (a.fix?.start ?? 0));\n let content = readFileSync(file, \"utf8\");\n let lastAppliedStart = Number.POSITIVE_INFINITY;\n for (const diagnostic of ordered) {\n const fix = diagnostic.fix;\n if (fix === undefined) continue;\n if (fix.end > lastAppliedStart) continue;\n content = content.slice(0, fix.start) + fix.text + content.slice(fix.end);\n lastAppliedStart = fix.start;\n fixed.add(diagnostic);\n }\n writeFileSync(file, content, \"utf8\");\n }\n\n return { applied: fixed.size, fileCount: byFile.size, fixed };\n}\n\nfunction groupByFile(diagnostics: Diagnostic[]): Map<string, Diagnostic[]> {\n const byFile = new Map<string, Diagnostic[]>();\n for (const diagnostic of diagnostics) {\n let list = byFile.get(diagnostic.file);\n if (list === undefined) {\n list = [];\n byFile.set(diagnostic.file, list);\n }\n list.push(diagnostic);\n }\n return byFile;\n}\n\n/** Surface a failure as output + exit code 1 instead of a thrown error. */\nfunction printErrorAndFail(err: unknown): number {\n const message = err instanceof Error ? err.message : String(err);\n console.error(pc.red(message));\n return 1;\n}\n\nfunction printHelp() {\n console.log(`unguard: data-shape static analyzer\n\nUsage:\n unguard scan [paths...] [options]\n unguard audit [paths...] [options]\n unguard baseline [paths...] [options]\n unguard [paths...] [options]\n\nCommands:\n scan Run proven rules: every finding demands a fix (default)\n audit Run heuristic rules: findings surface for review, exit\n code is 0 unless --fail-on is passed explicitly\n baseline Record current issues in unguard.baseline.json; later\n scans suppress a (file, rule) group until its count\n grows past the recorded number\n\nOptions:\n --config <path> Path to unguard config file (defaults to ./unguard.config.json)\n --strict Treat all diagnostics as errors\n --filter <rule> Run only the specified rule (in either command)\n --fix Apply available auto-fixes, then report what remains\n --rule <sel=sev> Override rule severity (supports id, *, category:<name>,\n tag:<name>, confidence:<proven|heuristic>)\n --ignore <glob> Ignore path glob. Repeatable.\n --severity <levels> Filter output by severity (comma-separated and/or repeatable)\n --fail-on <level> Exit threshold: none, error, warning, info (default: info)\n --format <mode> Output format: grouped (default), flat, or json\n --concurrency <n> Worker threads for tsconfig groups (default: auto, 1 disables)\n --no-baseline Ignore unguard.baseline.json for this scan\n --no-cache Disable on-disk diagnostic cache (node_modules/.cache/unguard)\n -h, --help Show this help\n\nExit codes:\n 0 Clean, or does not meet --fail-on threshold\n 1 Meets threshold without errors\n 2 Meets threshold with at least one error\n\nExamples:\n unguard scan src\n unguard audit src\n unguard scan src --fix\n unguard scan src --format=json\n unguard baseline src\n unguard scan src --rule duplicate-*=warning\n unguard scan src --rule category:cross-file=warning\n unguard scan src --rule tag:safety=error\n unguard scan src --severity=error,warning\n unguard scan src --fail-on=error`);\n}\n\nfunction printDiagnostics(diagnostics: Diagnostic[]) {\n const byFile = groupByFile(diagnostics);\n\n const cwd = `${process.cwd()}/`;\n const cwdBase = process.cwd();\n\n // \" \" + location column + \" \" + severity column + \" \"\n const prefixWidth = 2 + 10 + 1 + 7 + 2;\n const columns = process.stdout.columns;\n const wrapWidth = columns !== undefined && columns > prefixWidth + 20 ? columns - prefixWidth : null;\n\n for (const [file, fileDiagnostics] of byFile) {\n const rel = relative(cwdBase, file);\n console.log(pc.underline(rel));\n\n for (const diagnostic of fileDiagnostics) {\n const loc = `${diagnostic.line}:${diagnostic.column}`;\n const sev = diagnostic.severity === \"error\"\n ? pc.red(\"error\".padEnd(7))\n : diagnostic.severity === \"warning\"\n ? pc.yellow(\"warning\")\n : pc.blue(\"info\".padEnd(7));\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n const head = ` ${pc.dim(loc.padEnd(10))} ${sev} `;\n const rule = pc.dim(diagnostic.ruleId);\n const annotation = diagnostic.annotation !== undefined ? ` ${pc.cyan(diagnostic.annotation)}` : \"\";\n\n if (wrapWidth === null) {\n console.log(`${head}${msg} ${rule}${annotation}`);\n continue;\n }\n\n const lines = wrapWords(msg, wrapWidth);\n const tailWidth = diagnostic.ruleId.length + (diagnostic.annotation !== undefined ? 2 + diagnostic.annotation.length : 0);\n const last = lines.length - 1;\n const tailFits = (lines[last]?.length ?? 0) + 2 + tailWidth <= wrapWidth;\n const indent = \" \".repeat(prefixWidth);\n for (let i = 0; i < lines.length; i++) {\n const start = i === 0 ? head : indent;\n const tail = i === last && tailFits ? ` ${rule}${annotation}` : \"\";\n console.log(`${start}${lines[i]}${tail}`);\n }\n if (!tailFits) console.log(`${indent}${rule}${annotation}`);\n }\n\n console.log();\n }\n}\n\n/** Greedy word wrap; words longer than the width get their own line unbroken. */\nfunction wrapWords(text: string, width: number): string[] {\n const lines: string[] = [];\n let line = \"\";\n for (const word of text.split(\" \")) {\n if (line === \"\") {\n line = word;\n } else if (line.length + 1 + word.length > width) {\n lines.push(line);\n line = word;\n } else {\n line += ` ${word}`;\n }\n }\n if (line !== \"\") lines.push(line);\n return lines;\n}\n\nfunction printDiagnosticsFlat(diagnostics: Diagnostic[]) {\n const cwdBase = process.cwd();\n const cwd = `${cwdBase}/`;\n\n for (const diagnostic of diagnostics) {\n const rel = relative(cwdBase, diagnostic.file);\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n console.log(`${rel}:${diagnostic.line}:${diagnostic.column} ${diagnostic.severity} [${diagnostic.ruleId}] ${msg}`);\n }\n}\n\nfunction printSummary(diagnostics: Diagnostic[], fileCount: number) {\n const counts = new Map<string, number>();\n for (const diagnostic of diagnostics) {\n const prev = counts.get(diagnostic.ruleId);\n counts.set(diagnostic.ruleId, (prev === undefined ? 0 : prev) + 1);\n }\n\n const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);\n const maxRule = Math.max(...sorted.map(([rule]) => rule.length));\n\n console.log(pc.bold(\"Summary\"));\n for (const [rule, count] of sorted) {\n console.log(` ${rule.padEnd(maxRule)} ${pc.bold(String(count))}`);\n }\n\n console.log(\n `\\n${pc.bold(String(diagnostics.length))} issue${diagnostics.length === 1 ? \"\" : \"s\"} in ${plural(fileCount, \"file\")}.`,\n );\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction parseSeverityFilters(values: string[]): { ok: true; value: Severity[] } | { ok: false; message: string } {\n const levels = splitCsv(values);\n const parsed: Severity[] = [];\n for (const value of levels) {\n if (!isSeverity(value)) {\n return { ok: false, message: `Invalid --severity value \"${value}\". Use error, warning, info.` };\n }\n parsed.push(value);\n }\n return { ok: true, value: parsed };\n}\n\nfunction parseRulePolicyArgs(values: string[]): { ok: true; value: RulePolicyEntry[] } | { ok: false; message: string } {\n const entries: RulePolicyEntry[] = [];\n\n for (const arg of values) {\n const separator = resolveRuleSeparator(arg);\n if (separator === null) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Use <selector>=<off|info|warning|error>.` };\n }\n\n const selector = arg.slice(0, separator).trim();\n const severity = arg.slice(separator + 1).trim();\n if (!selector) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Rule selector is required.` };\n }\n if (!isRulePolicySeverity(severity)) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Severity must be off, info, warning, or error.` };\n }\n\n entries.push({ selector, severity });\n }\n\n return { ok: true, value: entries };\n}\n\nfunction resolveRuleSeparator(value: string): number | null {\n const equalIndex = value.indexOf(\"=\");\n if (equalIndex >= 0) return equalIndex;\n const colonIndex = value.lastIndexOf(\":\");\n if (colonIndex <= 0) return null;\n return colonIndex;\n}\n\nfunction splitCsv(values: string[]): string[] {\n return values\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n}\n\nfunction findConfigPath(cliValue: string | undefined): string | null {\n if (cliValue) {\n const explicitPath = resolve(process.cwd(), cliValue);\n if (!existsSync(explicitPath)) throw new Error(`Config file not found: ${cliValue}`);\n return explicitPath;\n }\n\n const candidates = [\"unguard.config.json\", \".unguardrc.json\"];\n for (const candidate of candidates) {\n const candidatePath = resolve(process.cwd(), candidate);\n if (existsSync(candidatePath)) return candidatePath;\n }\n return null;\n}\n\nfunction loadConfig(path: string): UnguardConfig {\n const text = readFileSync(path, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Invalid JSON in ${basename(path)}: ${message}`);\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid config in ${basename(path)}: expected a JSON object.`);\n }\n\n const raw = parsed as Record<string, unknown>;\n const config: UnguardConfig = {};\n\n if (raw.paths !== undefined) {\n if (!isStringArray(raw.paths)) throw new Error(`Invalid config in ${basename(path)}: \"paths\" must be a string array.`);\n config.paths = raw.paths;\n }\n\n if (raw.ignore !== undefined) {\n if (!isStringArray(raw.ignore)) throw new Error(`Invalid config in ${basename(path)}: \"ignore\" must be a string array.`);\n config.ignore = raw.ignore;\n }\n\n if (raw.failOn !== undefined) {\n if (typeof raw.failOn !== \"string\" || !isFailOn(raw.failOn)) {\n throw new Error(`Invalid config in ${basename(path)}: \"failOn\" must be one of none, error, warning, info.`);\n }\n config.failOn = raw.failOn;\n }\n\n if (raw.severity !== undefined) {\n if (!isStringArray(raw.severity) || !raw.severity.every(isSeverity)) {\n throw new Error(`Invalid config in ${basename(path)}: \"severity\" must be an array of error, warning, info.`);\n }\n config.severity = raw.severity;\n }\n\n if (raw.concurrency !== undefined) {\n if (typeof raw.concurrency !== \"number\" || !Number.isInteger(raw.concurrency) || raw.concurrency < 1) {\n throw new Error(`Invalid config in ${basename(path)}: \"concurrency\" must be a positive integer.`);\n }\n config.concurrency = raw.concurrency;\n }\n\n if (raw.cache !== undefined) {\n if (typeof raw.cache !== \"boolean\") {\n throw new Error(`Invalid config in ${basename(path)}: \"cache\" must be a boolean.`);\n }\n config.cache = raw.cache;\n }\n\n if (raw.rules !== undefined) {\n config.rules = parseRulesObject(raw.rules, `\"rules\"`, basename(path));\n }\n\n if (raw.overrides !== undefined) {\n if (!Array.isArray(raw.overrides)) {\n throw new Error(`Invalid config in ${basename(path)}: \"overrides\" must be an array.`);\n }\n config.overrides = raw.overrides.map((entry: unknown, index) => {\n if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) {\n throw new Error(`Invalid config in ${basename(path)}: overrides[${index}] must be an object.`);\n }\n const override = entry as Record<string, unknown>;\n if (!isStringArray(override.files) || override.files.length === 0) {\n throw new Error(`Invalid config in ${basename(path)}: overrides[${index}].files must be a non-empty string array.`);\n }\n return {\n files: override.files,\n rules: parseRulesObject(override.rules, `overrides[${index}].rules`, basename(path)),\n };\n });\n }\n\n return config;\n}\n\nfunction parseRulesObject(value: unknown, label: string, configName: string): Record<string, RulePolicySeverity> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(`Invalid config in ${configName}: ${label} must be an object.`);\n }\n\n const rules: Record<string, RulePolicySeverity> = {};\n for (const [selector, severity] of Object.entries(value as Record<string, unknown>)) {\n if (typeof severity !== \"string\" || !isRulePolicySeverity(severity)) {\n throw new Error(`Invalid config in ${configName}: rule \"${selector}\" in ${label} must be off, info, warning, or error.`);\n }\n rules[selector] = severity;\n }\n return rules;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction resolveFailOn(\n cliValue: string | undefined,\n fallback: FailOn,\n configValue?: FailOn,\n): { ok: true; value: FailOn } | { ok: false; message: string } {\n const selected = cliValue ?? configValue ?? fallback;\n if (!isFailOn(selected)) {\n return { ok: false, message: `Invalid --fail-on value \"${selected}\". Use none, error, warning, or info.` };\n }\n return { ok: true, value: selected };\n}\n\nfunction resolveConcurrency(\n cliValue: string | undefined,\n configValue: number | undefined,\n): { ok: true; value: number | undefined } | { ok: false; message: string } {\n if (cliValue !== undefined) {\n const parsed = Number(cliValue);\n if (!Number.isInteger(parsed) || parsed < 1) {\n return { ok: false, message: `Invalid --concurrency value \"${cliValue}\". Use a positive integer.` };\n }\n return { ok: true, value: parsed };\n }\n if (configValue !== undefined) {\n if (!Number.isInteger(configValue) || configValue < 1) {\n return { ok: false, message: \"Invalid concurrency in config: must be a positive integer.\" };\n }\n return { ok: true, value: configValue };\n }\n return { ok: true, value: undefined };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport pc from \"picocolors\";\nimport { executeScan, type FailOn, type RulePolicyEntry, type RulePolicySeverity, type Severity } from \"./engine.ts\";\nimport { BASELINE_FILENAME, buildBaseline, loadBaseline, writeBaseline, type BaselineData } from \"./scan/baseline.ts\";\nimport { isFailOn, isRulePolicySeverity, isSeverity, toRulePolicyEntries } from \"./scan/config.ts\";\nimport { computeExitCode } from \"./scan/policy.ts\";\nimport type { RulePolicy, RuleOverride } from \"./scan/types.ts\";\nimport type { Diagnostic } from \"./rules/types.ts\";\n\ninterface UnguardConfig {\n paths?: string[];\n ignore?: string[];\n rules?: RulePolicy;\n overrides?: RuleOverride[];\n failOn?: FailOn;\n severity?: Severity[];\n concurrency?: number;\n cache?: boolean;\n}\n\nconst COMMANDS = new Set([\"scan\", \"audit\", \"baseline\"]);\n\n// @unguard unused-export CLI entry point\nexport async function main(argv: string[]): Promise<number> {\n const rawArgs = argv.slice(2);\n const first = rawArgs[0];\n const command = first !== undefined && COMMANDS.has(first) ? first : \"scan\";\n const userArgs = first !== undefined && COMMANDS.has(first) ? rawArgs.slice(1) : rawArgs;\n\n const { values, positionals: cliPaths } = parseArgs({\n args: userArgs,\n options: {\n strict: { type: \"boolean\", default: false },\n filter: { type: \"string\" },\n fix: { type: \"boolean\", default: false },\n format: { type: \"string\", default: \"grouped\" },\n severity: { type: \"string\", multiple: true, default: [] },\n ignore: { type: \"string\", multiple: true, default: [] },\n rule: { type: \"string\", multiple: true, default: [] },\n config: { type: \"string\" },\n \"fail-on\": { type: \"string\" },\n concurrency: { type: \"string\" },\n \"no-baseline\": { type: \"boolean\", default: false },\n \"no-cache\": { type: \"boolean\", default: false },\n version: { type: \"boolean\", short: \"v\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n allowPositionals: true,\n });\n\n if (values.version) {\n console.log(readVersion());\n return 0;\n }\n\n if (values.help) {\n printHelp();\n return 0;\n }\n\n if (values.format !== \"grouped\" && values.format !== \"flat\" && values.format !== \"json\") {\n console.error(pc.red(`Invalid --format value \"${values.format}\". Use grouped, flat, or json.`));\n return 1;\n }\n\n let config: UnguardConfig | null = null;\n try {\n const configPath = findConfigPath(values.config);\n config = configPath ? loadConfig(configPath) : null;\n } catch (err) {\n return printErrorAndFail(err);\n }\n\n const rulePolicyResult = parseRulePolicyArgs(values.rule);\n if (!rulePolicyResult.ok) {\n console.error(pc.red(rulePolicyResult.message));\n return 1;\n }\n\n const severityFiltersResult = parseSeverityFilters(values.severity);\n if (!severityFiltersResult.ok) {\n console.error(pc.red(severityFiltersResult.message));\n return 1;\n }\n\n // Only an explicit --fail-on makes audit exit nonzero; config failOn\n // applies to scan only.\n const failOnResult = command === \"audit\"\n ? resolveFailOn(values[\"fail-on\"], \"none\")\n : resolveFailOn(values[\"fail-on\"], \"info\", config?.failOn);\n if (!failOnResult.ok) {\n console.error(pc.red(failOnResult.message));\n return 1;\n }\n\n const concurrencyResult = resolveConcurrency(values.concurrency, config?.concurrency);\n if (!concurrencyResult.ok) {\n console.error(pc.red(concurrencyResult.message));\n return 1;\n }\n\n const paths = cliPaths.length > 0 ? cliPaths : config?.paths ?? [];\n const ignore = [...(config?.ignore ?? []), ...values.ignore];\n const rulePolicy = [\n ...toRulePolicyEntries(config?.rules),\n ...rulePolicyResult.value,\n ];\n\n const cacheEnabled = values[\"no-cache\"] ? false : config?.cache ?? true;\n\n // The baseline subcommand regenerates the file, so the existing one must\n // not suppress anything during its scan.\n let baseline: BaselineData | null = null;\n if (command === \"scan\" && !values[\"no-baseline\"]) {\n try {\n baseline = loadBaseline(process.cwd());\n } catch (err) {\n return printErrorAndFail(err);\n }\n }\n\n const execution = await executeScan({\n paths,\n mode: command === \"audit\" ? \"audit\" : \"scan\",\n strict: values.strict,\n rules: values.filter ? [values.filter] : undefined,\n ignore: ignore.length > 0 ? ignore : undefined,\n rulePolicy: rulePolicy.length > 0 ? rulePolicy : undefined,\n overrides: config?.overrides,\n showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value : config?.severity,\n failOn: failOnResult.value,\n concurrency: concurrencyResult.value,\n cache: cacheEnabled,\n baseline: baseline ?? undefined,\n });\n\n if (command === \"baseline\") {\n const data = buildBaseline(execution.visibleDiagnostics, process.cwd());\n writeBaseline(data, process.cwd());\n console.log(\n `Baseline written to ${BASELINE_FILENAME}: ${plural(execution.visibleDiagnostics.length, \"known issue\")} across ${plural(Object.keys(data.rules).length, \"file\")}.`,\n );\n return 0;\n }\n\n let diagnostics = execution.visibleDiagnostics;\n let exitCode = execution.exitCode;\n let fixedCount = 0;\n let fixedFileCount = 0;\n\n if (values.fix) {\n const result = applyFixes(diagnostics);\n fixedCount = result.applied;\n fixedFileCount = result.fileCount;\n diagnostics = diagnostics.filter((d) => !result.fixed.has(d));\n exitCode = computeExitCode(diagnostics, failOnResult.value);\n }\n\n if (values.format === \"json\") {\n console.log(JSON.stringify(buildJsonReport(diagnostics, execution.fileCount, exitCode, values.fix ? fixedCount : null), null, 2));\n return exitCode;\n }\n\n if (baseline !== null) {\n console.log(pc.dim(`Using ${BASELINE_FILENAME} (run \"unguard baseline\" to regenerate, --no-baseline to ignore)`));\n }\n if (values.fix && fixedCount > 0) {\n console.log(pc.green(`Applied ${fixedCount} fix${fixedCount === 1 ? \"\" : \"es\"} in ${fixedFileCount} file${fixedFileCount === 1 ? \"\" : \"s\"}. Re-run unguard to verify.`));\n }\n\n if (diagnostics.length === 0) {\n console.log(pc.green(`No issues found in ${plural(execution.fileCount, \"file\")}.`));\n return exitCode;\n }\n\n if (values.format === \"flat\") {\n printDiagnosticsFlat(diagnostics);\n } else {\n printDiagnostics(diagnostics);\n }\n printSummary(diagnostics, execution.fileCount);\n\n return exitCode;\n}\n\ninterface JsonDiagnostic {\n file: string;\n line: number;\n column: number;\n severity: Severity;\n ruleId: string;\n message: string;\n annotation?: string;\n fixable: boolean;\n}\n\nfunction buildJsonReport(\n diagnostics: Diagnostic[],\n fileCount: number,\n exitCode: number,\n fixedCount: number | null,\n): { diagnostics: JsonDiagnostic[]; fileCount: number; exitCode: number; fixedCount?: number } {\n return {\n diagnostics: diagnostics.map((d) => ({\n file: d.file,\n line: d.line,\n column: d.column,\n severity: d.severity,\n ruleId: d.ruleId,\n message: d.message,\n ...(d.annotation !== undefined ? { annotation: d.annotation } : {}),\n fixable: d.fix !== undefined,\n })),\n fileCount,\n exitCode,\n ...(fixedCount !== null ? { fixedCount } : {}),\n };\n}\n\n/**\n * Apply fix edits, last-to-first per file so earlier offsets stay valid.\n * Overlapping edits in one pass are skipped — the re-run picks them up.\n */\nfunction applyFixes(diagnostics: Diagnostic[]): { applied: number; fileCount: number; fixed: Set<Diagnostic> } {\n const byFile = groupByFile(diagnostics.filter((d) => d.fix !== undefined));\n\n const fixed = new Set<Diagnostic>();\n for (const [file, fileDiagnostics] of byFile) {\n const ordered = [...fileDiagnostics].sort((a, b) => (b.fix?.start ?? 0) - (a.fix?.start ?? 0));\n let content = readFileSync(file, \"utf8\");\n let lastAppliedStart = Number.POSITIVE_INFINITY;\n for (const diagnostic of ordered) {\n const fix = diagnostic.fix;\n if (fix === undefined) continue;\n if (fix.end > lastAppliedStart) continue;\n content = content.slice(0, fix.start) + fix.text + content.slice(fix.end);\n lastAppliedStart = fix.start;\n fixed.add(diagnostic);\n }\n writeFileSync(file, content, \"utf8\");\n }\n\n return { applied: fixed.size, fileCount: byFile.size, fixed };\n}\n\nfunction groupByFile(diagnostics: Diagnostic[]): Map<string, Diagnostic[]> {\n const byFile = new Map<string, Diagnostic[]>();\n for (const diagnostic of diagnostics) {\n let list = byFile.get(diagnostic.file);\n if (list === undefined) {\n list = [];\n byFile.set(diagnostic.file, list);\n }\n list.push(diagnostic);\n }\n return byFile;\n}\n\n/** Surface a failure as output + exit code 1 instead of a thrown error. */\nfunction printErrorAndFail(err: unknown): number {\n const message = err instanceof Error ? err.message : String(err);\n console.error(pc.red(message));\n return 1;\n}\n\nfunction readVersion(): string {\n const pkg = JSON.parse(readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"));\n const version: unknown = pkg.version;\n return typeof version === \"string\" ? version : \"unknown\";\n}\n\nfunction printHelp() {\n console.log(`unguard: data-shape static analyzer\n\nUsage:\n unguard scan [paths...] [options]\n unguard audit [paths...] [options]\n unguard baseline [paths...] [options]\n unguard [paths...] [options]\n\nCommands:\n scan Run proven rules: every finding demands a fix (default)\n audit Run heuristic rules: findings surface for review, exit\n code is 0 unless --fail-on is passed explicitly\n baseline Record current issues in unguard.baseline.json; later\n scans suppress a (file, rule) group until its count\n grows past the recorded number\n\nOptions:\n --config <path> Path to unguard config file (defaults to ./unguard.config.json)\n --strict Treat all diagnostics as errors\n --filter <rule> Run only the specified rule (in either command)\n --fix Apply available auto-fixes, then report what remains\n --rule <sel=sev> Override rule severity (supports id, *, category:<name>,\n tag:<name>, confidence:<proven|heuristic>)\n --ignore <glob> Ignore path glob. Repeatable.\n --severity <levels> Filter output by severity (comma-separated and/or repeatable)\n --fail-on <level> Exit threshold: none, error, warning, info (default: info)\n --format <mode> Output format: grouped (default), flat, or json\n --concurrency <n> Worker threads for tsconfig groups (default: auto, 1 disables)\n --no-baseline Ignore unguard.baseline.json for this scan\n --no-cache Disable on-disk diagnostic cache (node_modules/.cache/unguard)\n -v, --version Print version and exit\n -h, --help Show this help\n\nExit codes:\n 0 Clean, or does not meet --fail-on threshold\n 1 Meets threshold without errors\n 2 Meets threshold with at least one error\n\nExamples:\n unguard scan src\n unguard audit src\n unguard scan src --fix\n unguard scan src --format=json\n unguard baseline src\n unguard scan src --rule duplicate-*=warning\n unguard scan src --rule category:cross-file=warning\n unguard scan src --rule tag:safety=error\n unguard scan src --severity=error,warning\n unguard scan src --fail-on=error`);\n}\n\nfunction printDiagnostics(diagnostics: Diagnostic[]) {\n const byFile = groupByFile(diagnostics);\n\n const cwd = `${process.cwd()}/`;\n const cwdBase = process.cwd();\n\n // \" \" + location column + \" \" + severity column + \" \"\n const prefixWidth = 2 + 10 + 1 + 7 + 2;\n const columns = process.stdout.columns;\n const wrapWidth = columns !== undefined && columns > prefixWidth + 20 ? columns - prefixWidth : null;\n\n for (const [file, fileDiagnostics] of byFile) {\n const rel = relative(cwdBase, file);\n console.log(pc.underline(rel));\n\n for (const diagnostic of fileDiagnostics) {\n const loc = `${diagnostic.line}:${diagnostic.column}`;\n const sev = diagnostic.severity === \"error\"\n ? pc.red(\"error\".padEnd(7))\n : diagnostic.severity === \"warning\"\n ? pc.yellow(\"warning\")\n : pc.blue(\"info\".padEnd(7));\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n const head = ` ${pc.dim(loc.padEnd(10))} ${sev} `;\n const rule = pc.dim(diagnostic.ruleId);\n const annotation = diagnostic.annotation !== undefined ? ` ${pc.cyan(diagnostic.annotation)}` : \"\";\n\n if (wrapWidth === null) {\n console.log(`${head}${msg} ${rule}${annotation}`);\n continue;\n }\n\n const lines = wrapWords(msg, wrapWidth);\n const tailWidth = diagnostic.ruleId.length + (diagnostic.annotation !== undefined ? 2 + diagnostic.annotation.length : 0);\n const last = lines.length - 1;\n const tailFits = (lines[last]?.length ?? 0) + 2 + tailWidth <= wrapWidth;\n const indent = \" \".repeat(prefixWidth);\n for (let i = 0; i < lines.length; i++) {\n const start = i === 0 ? head : indent;\n const tail = i === last && tailFits ? ` ${rule}${annotation}` : \"\";\n console.log(`${start}${lines[i]}${tail}`);\n }\n if (!tailFits) console.log(`${indent}${rule}${annotation}`);\n }\n\n console.log();\n }\n}\n\n/** Greedy word wrap; words longer than the width get their own line unbroken. */\nfunction wrapWords(text: string, width: number): string[] {\n const lines: string[] = [];\n let line = \"\";\n for (const word of text.split(\" \")) {\n if (line === \"\") {\n line = word;\n } else if (line.length + 1 + word.length > width) {\n lines.push(line);\n line = word;\n } else {\n line += ` ${word}`;\n }\n }\n if (line !== \"\") lines.push(line);\n return lines;\n}\n\nfunction printDiagnosticsFlat(diagnostics: Diagnostic[]) {\n const cwdBase = process.cwd();\n const cwd = `${cwdBase}/`;\n\n for (const diagnostic of diagnostics) {\n const rel = relative(cwdBase, diagnostic.file);\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n console.log(`${rel}:${diagnostic.line}:${diagnostic.column} ${diagnostic.severity} [${diagnostic.ruleId}] ${msg}`);\n }\n}\n\nfunction printSummary(diagnostics: Diagnostic[], fileCount: number) {\n const counts = new Map<string, number>();\n for (const diagnostic of diagnostics) {\n const prev = counts.get(diagnostic.ruleId);\n counts.set(diagnostic.ruleId, (prev === undefined ? 0 : prev) + 1);\n }\n\n const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);\n const maxRule = Math.max(...sorted.map(([rule]) => rule.length));\n\n console.log(pc.bold(\"Summary\"));\n for (const [rule, count] of sorted) {\n console.log(` ${rule.padEnd(maxRule)} ${pc.bold(String(count))}`);\n }\n\n console.log(\n `\\n${pc.bold(String(diagnostics.length))} issue${diagnostics.length === 1 ? \"\" : \"s\"} in ${plural(fileCount, \"file\")}.`,\n );\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction parseSeverityFilters(values: string[]): { ok: true; value: Severity[] } | { ok: false; message: string } {\n const levels = splitCsv(values);\n const parsed: Severity[] = [];\n for (const value of levels) {\n if (!isSeverity(value)) {\n return { ok: false, message: `Invalid --severity value \"${value}\". Use error, warning, info.` };\n }\n parsed.push(value);\n }\n return { ok: true, value: parsed };\n}\n\nfunction parseRulePolicyArgs(values: string[]): { ok: true; value: RulePolicyEntry[] } | { ok: false; message: string } {\n const entries: RulePolicyEntry[] = [];\n\n for (const arg of values) {\n const separator = resolveRuleSeparator(arg);\n if (separator === null) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Use <selector>=<off|info|warning|error>.` };\n }\n\n const selector = arg.slice(0, separator).trim();\n const severity = arg.slice(separator + 1).trim();\n if (!selector) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Rule selector is required.` };\n }\n if (!isRulePolicySeverity(severity)) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Severity must be off, info, warning, or error.` };\n }\n\n entries.push({ selector, severity });\n }\n\n return { ok: true, value: entries };\n}\n\nfunction resolveRuleSeparator(value: string): number | null {\n const equalIndex = value.indexOf(\"=\");\n if (equalIndex >= 0) return equalIndex;\n const colonIndex = value.lastIndexOf(\":\");\n if (colonIndex <= 0) return null;\n return colonIndex;\n}\n\nfunction splitCsv(values: string[]): string[] {\n return values\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n}\n\nfunction findConfigPath(cliValue: string | undefined): string | null {\n if (cliValue) {\n const explicitPath = resolve(process.cwd(), cliValue);\n if (!existsSync(explicitPath)) throw new Error(`Config file not found: ${cliValue}`);\n return explicitPath;\n }\n\n const candidates = [\"unguard.config.json\", \".unguardrc.json\"];\n for (const candidate of candidates) {\n const candidatePath = resolve(process.cwd(), candidate);\n if (existsSync(candidatePath)) return candidatePath;\n }\n return null;\n}\n\nfunction loadConfig(path: string): UnguardConfig {\n const text = readFileSync(path, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Invalid JSON in ${basename(path)}: ${message}`);\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid config in ${basename(path)}: expected a JSON object.`);\n }\n\n const raw = parsed as Record<string, unknown>;\n const config: UnguardConfig = {};\n\n if (raw.paths !== undefined) {\n if (!isStringArray(raw.paths)) throw new Error(`Invalid config in ${basename(path)}: \"paths\" must be a string array.`);\n config.paths = raw.paths;\n }\n\n if (raw.ignore !== undefined) {\n if (!isStringArray(raw.ignore)) throw new Error(`Invalid config in ${basename(path)}: \"ignore\" must be a string array.`);\n config.ignore = raw.ignore;\n }\n\n if (raw.failOn !== undefined) {\n if (typeof raw.failOn !== \"string\" || !isFailOn(raw.failOn)) {\n throw new Error(`Invalid config in ${basename(path)}: \"failOn\" must be one of none, error, warning, info.`);\n }\n config.failOn = raw.failOn;\n }\n\n if (raw.severity !== undefined) {\n if (!isStringArray(raw.severity) || !raw.severity.every(isSeverity)) {\n throw new Error(`Invalid config in ${basename(path)}: \"severity\" must be an array of error, warning, info.`);\n }\n config.severity = raw.severity;\n }\n\n if (raw.concurrency !== undefined) {\n if (typeof raw.concurrency !== \"number\" || !Number.isInteger(raw.concurrency) || raw.concurrency < 1) {\n throw new Error(`Invalid config in ${basename(path)}: \"concurrency\" must be a positive integer.`);\n }\n config.concurrency = raw.concurrency;\n }\n\n if (raw.cache !== undefined) {\n if (typeof raw.cache !== \"boolean\") {\n throw new Error(`Invalid config in ${basename(path)}: \"cache\" must be a boolean.`);\n }\n config.cache = raw.cache;\n }\n\n if (raw.rules !== undefined) {\n config.rules = parseRulesObject(raw.rules, `\"rules\"`, basename(path));\n }\n\n if (raw.overrides !== undefined) {\n if (!Array.isArray(raw.overrides)) {\n throw new Error(`Invalid config in ${basename(path)}: \"overrides\" must be an array.`);\n }\n config.overrides = raw.overrides.map((entry: unknown, index) => {\n if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) {\n throw new Error(`Invalid config in ${basename(path)}: overrides[${index}] must be an object.`);\n }\n const override = entry as Record<string, unknown>;\n if (!isStringArray(override.files) || override.files.length === 0) {\n throw new Error(`Invalid config in ${basename(path)}: overrides[${index}].files must be a non-empty string array.`);\n }\n return {\n files: override.files,\n rules: parseRulesObject(override.rules, `overrides[${index}].rules`, basename(path)),\n };\n });\n }\n\n return config;\n}\n\nfunction parseRulesObject(value: unknown, label: string, configName: string): Record<string, RulePolicySeverity> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(`Invalid config in ${configName}: ${label} must be an object.`);\n }\n\n const rules: Record<string, RulePolicySeverity> = {};\n for (const [selector, severity] of Object.entries(value as Record<string, unknown>)) {\n if (typeof severity !== \"string\" || !isRulePolicySeverity(severity)) {\n throw new Error(`Invalid config in ${configName}: rule \"${selector}\" in ${label} must be off, info, warning, or error.`);\n }\n rules[selector] = severity;\n }\n return rules;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction resolveFailOn(\n cliValue: string | undefined,\n fallback: FailOn,\n configValue?: FailOn,\n): { ok: true; value: FailOn } | { ok: false; message: string } {\n const selected = cliValue ?? configValue ?? fallback;\n if (!isFailOn(selected)) {\n return { ok: false, message: `Invalid --fail-on value \"${selected}\". Use none, error, warning, or info.` };\n }\n return { ok: true, value: selected };\n}\n\nfunction resolveConcurrency(\n cliValue: string | undefined,\n configValue: number | undefined,\n): { ok: true; value: number | undefined } | { ok: false; message: string } {\n if (cliValue !== undefined) {\n const parsed = Number(cliValue);\n if (!Number.isInteger(parsed) || parsed < 1) {\n return { ok: false, message: `Invalid --concurrency value \"${cliValue}\". Use a positive integer.` };\n }\n return { ok: true, value: parsed };\n }\n if (configValue !== undefined) {\n if (!Number.isInteger(configValue) || configValue < 1) {\n return { ok: false, message: \"Invalid concurrency in config: must be a positive integer.\" };\n }\n return { ok: true, value: configValue };\n }\n return { ok: true, value: undefined };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unguard",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Detect overdefensive AI-generated code",
5
5
  "author": "Seva Maltsev <me@seva.dev> (https://seva.dev)",
6
6
  "license": "MIT",