eslint-plugin-ai-guard 1.2.1 → 1.2.3

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/index.js CHANGED
@@ -30,6 +30,154 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
+ // cli/utils/debug.ts
34
+ var debug_exports = {};
35
+ __export(debug_exports, {
36
+ debugLog: () => debugLog,
37
+ printCIDebug: () => printCIDebug,
38
+ printGitDebug: () => printGitDebug
39
+ });
40
+ function debugLog(message) {
41
+ process.stderr.write(`${DIM("[debug]")} ${message}
42
+ `);
43
+ }
44
+ function printGitDebug(result) {
45
+ const d = result.debugInfo;
46
+ process.stderr.write("\n");
47
+ process.stderr.write(`${LABEL(" Git Resolution Trace")}
48
+ `);
49
+ process.stderr.write(`${DIM(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
50
+ `);
51
+ process.stderr.write(` ${DIM("Mode:")} ${import_chalk4.default.white(result.mode)}
52
+ `);
53
+ if (d.resolvedBase) {
54
+ process.stderr.write(` ${DIM("Base branch:")} ${import_chalk4.default.white(d.resolvedBase)}
55
+ `);
56
+ } else {
57
+ process.stderr.write(` ${DIM("Base branch:")} ${import_chalk4.default.dim("(none \u2014 uncommitted mode)")}
58
+ `);
59
+ }
60
+ if (d.mergeBase) {
61
+ process.stderr.write(` ${DIM("Merge base:")} ${import_chalk4.default.white(d.mergeBase.slice(0, 12))}\u2026
62
+ `);
63
+ }
64
+ if (d.isShallowClone) {
65
+ process.stderr.write(` ${WARN} ${import_chalk4.default.yellow("Shallow clone detected")} \u2014 use fetch-depth: 0 in workflow
66
+ `);
67
+ }
68
+ if (d.isDetachedHead) {
69
+ process.stderr.write(` ${WARN} ${import_chalk4.default.yellow("Detached HEAD")} \u2014 branch context unavailable
70
+ `);
71
+ }
72
+ process.stderr.write("\n");
73
+ process.stderr.write(` ${DIM("Strategies attempted:")}
74
+ `);
75
+ for (const strategy of d.strategiesAttempted) {
76
+ const succeeded = strategy === d.strategySucceeded;
77
+ const icon = succeeded ? OK : ERR;
78
+ const label = succeeded ? import_chalk4.default.green(strategy) : import_chalk4.default.dim(strategy);
79
+ process.stderr.write(` ${icon} ${label}
80
+ `);
81
+ }
82
+ if (d.strategySucceeded) {
83
+ process.stderr.write(`
84
+ ${OK} ${import_chalk4.default.green("Succeeded:")} ${d.strategySucceeded}
85
+ `);
86
+ } else {
87
+ process.stderr.write(`
88
+ ${ERR} ${import_chalk4.default.red("All strategies failed")}
89
+ `);
90
+ }
91
+ process.stderr.write("\n");
92
+ process.stderr.write(` ${DIM("Files:")}
93
+ `);
94
+ process.stderr.write(` ${ARROW} Detected raw: ${import_chalk4.default.white(d.rawFileCount)}
95
+ `);
96
+ process.stderr.write(` ${ARROW} Kept: ${import_chalk4.default.green(result.files.length)}
97
+ `);
98
+ if (d.droppedByExtension > 0) {
99
+ process.stderr.write(` ${ARROW} Dropped (ext): ${import_chalk4.default.dim(d.droppedByExtension)}
100
+ `);
101
+ }
102
+ if (d.droppedByIgnore > 0) {
103
+ process.stderr.write(` ${ARROW} Dropped (ignored): ${import_chalk4.default.dim(d.droppedByIgnore)}
104
+ `);
105
+ }
106
+ if (d.droppedByWorkingDir > 0) {
107
+ process.stderr.write(` ${ARROW} Dropped (dir): ${import_chalk4.default.dim(d.droppedByWorkingDir)}
108
+ `);
109
+ }
110
+ if (d.droppedMissing > 0) {
111
+ process.stderr.write(` ${ARROW} Dropped (missing): ${import_chalk4.default.dim(d.droppedMissing)}
112
+ `);
113
+ }
114
+ if (result.zeroFilesReason) {
115
+ process.stderr.write("\n");
116
+ process.stderr.write(` ${WARN} ${import_chalk4.default.yellow("Zero files reason:")}
117
+ `);
118
+ process.stderr.write(` ${import_chalk4.default.dim(result.zeroFilesReason)}
119
+ `);
120
+ }
121
+ if (result.files.length > 0) {
122
+ process.stderr.write("\n");
123
+ process.stderr.write(` ${DIM("Changed files (first 20):")}
124
+ `);
125
+ for (const f of result.files.slice(0, 20)) {
126
+ process.stderr.write(` ${import_chalk4.default.dim("\xB7")} ${import_chalk4.default.white(f)}
127
+ `);
128
+ }
129
+ if (result.files.length > 20) {
130
+ process.stderr.write(` ${import_chalk4.default.dim(`\u2026 and ${result.files.length - 20} more`)}
131
+ `);
132
+ }
133
+ }
134
+ process.stderr.write("\n");
135
+ }
136
+ function printCIDebug(info) {
137
+ process.stderr.write("\n");
138
+ process.stderr.write(`${LABEL(" CI Environment")}
139
+ `);
140
+ process.stderr.write(`${DIM(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
141
+ `);
142
+ const env = (name, value) => {
143
+ const val = value ? import_chalk4.default.white(value) : import_chalk4.default.dim("(not set)");
144
+ process.stderr.write(` ${DIM(name.padEnd(26))} ${val}
145
+ `);
146
+ };
147
+ env("GITHUB_ACTIONS:", info.isGitHubActions ? "true" : "false");
148
+ env("GITHUB_BASE_REF:", info.githubBaseRef);
149
+ env("GITHUB_SHA:", info.githubSha);
150
+ env("GITHUB_REF:", info.githubRef);
151
+ env("GITHUB_REPOSITORY:", info.githubRepository);
152
+ env("GITHUB_WORKFLOW:", info.githubWorkflow);
153
+ env("GITHUB_RUN_ID:", info.githubRunId);
154
+ env("GITHUB_EVENT_NAME:", info.githubEventName);
155
+ process.stderr.write("\n");
156
+ env("GITHUB_STEP_SUMMARY:", info.githubStepSummary);
157
+ env("GITHUB_OUTPUT:", info.githubOutput);
158
+ process.stderr.write("\n");
159
+ env("Scan preset:", info.preset);
160
+ env("Fail on:", info.failOn);
161
+ env("Scan mode:", info.scanMode);
162
+ if (info.sarifOutputPath) {
163
+ env("SARIF output:", info.sarifOutputPath);
164
+ }
165
+ process.stderr.write("\n");
166
+ }
167
+ var import_chalk4, DIM, LABEL, OK, WARN, ERR, ARROW;
168
+ var init_debug = __esm({
169
+ "cli/utils/debug.ts"() {
170
+ "use strict";
171
+ import_chalk4 = __toESM(require("chalk"));
172
+ DIM = import_chalk4.default.dim;
173
+ LABEL = import_chalk4.default.cyan.bold;
174
+ OK = import_chalk4.default.green("\u2714");
175
+ WARN = import_chalk4.default.yellow("\u26A0");
176
+ ERR = import_chalk4.default.red("\u2716");
177
+ ARROW = import_chalk4.default.dim("\u2192");
178
+ }
179
+ });
180
+
33
181
  // cli/utils/config-manager.ts
34
182
  var config_manager_exports = {};
35
183
  __export(config_manager_exports, {
@@ -53,14 +201,14 @@ __export(config_manager_exports, {
53
201
  });
54
202
  function backupConfig(configPath) {
55
203
  const backupPath = `${configPath}.bak`;
56
- import_fs6.default.copyFileSync(configPath, backupPath);
204
+ import_fs7.default.copyFileSync(configPath, backupPath);
57
205
  return backupPath;
58
206
  }
59
207
  function readConfig(configPath) {
60
- return import_fs6.default.readFileSync(configPath, "utf-8");
208
+ return import_fs7.default.readFileSync(configPath, "utf-8");
61
209
  }
62
210
  function writeConfig(configPath, content) {
63
- import_fs6.default.writeFileSync(configPath, content, "utf-8");
211
+ import_fs7.default.writeFileSync(configPath, content, "utf-8");
64
212
  }
65
213
  function generateFlatConfig(preset) {
66
214
  return `import aiGuard from 'eslint-plugin-ai-guard';
@@ -266,19 +414,19 @@ function addIgnoresToLegacyConfig(existing) {
266
414
  function getConfigFilePath(configType, cwd = process.cwd()) {
267
415
  switch (configType) {
268
416
  case "flat-js":
269
- return import_path5.default.join(cwd, "eslint.config.js");
417
+ return import_path6.default.join(cwd, "eslint.config.js");
270
418
  case "flat-mjs":
271
- return import_path5.default.join(cwd, "eslint.config.mjs");
419
+ return import_path6.default.join(cwd, "eslint.config.mjs");
272
420
  case "flat-cjs":
273
- return import_path5.default.join(cwd, "eslint.config.cjs");
421
+ return import_path6.default.join(cwd, "eslint.config.cjs");
274
422
  case "eslintrc-js":
275
- return import_path5.default.join(cwd, ".eslintrc.js");
423
+ return import_path6.default.join(cwd, ".eslintrc.js");
276
424
  case "eslintrc-cjs":
277
- return import_path5.default.join(cwd, ".eslintrc.cjs");
425
+ return import_path6.default.join(cwd, ".eslintrc.cjs");
278
426
  case "eslintrc-json":
279
- return import_path5.default.join(cwd, ".eslintrc.json");
427
+ return import_path6.default.join(cwd, ".eslintrc.json");
280
428
  default:
281
- return import_path5.default.join(cwd, ".eslintrc.js");
429
+ return import_path6.default.join(cwd, ".eslintrc.js");
282
430
  }
283
431
  }
284
432
  function validateFlatConfigText(content) {
@@ -313,12 +461,12 @@ function validateLegacyConfigText(content) {
313
461
  }
314
462
  return problems;
315
463
  }
316
- var import_fs6, import_path5, AI_GUARD_MARKER, DEFAULT_FLAT_IGNORES, DEFAULT_LEGACY_IGNORES;
464
+ var import_fs7, import_path6, AI_GUARD_MARKER, DEFAULT_FLAT_IGNORES, DEFAULT_LEGACY_IGNORES;
317
465
  var init_config_manager = __esm({
318
466
  "cli/utils/config-manager.ts"() {
319
467
  "use strict";
320
- import_fs6 = __toESM(require("fs"));
321
- import_path5 = __toESM(require("path"));
468
+ import_fs7 = __toESM(require("fs"));
469
+ import_path6 = __toESM(require("path"));
322
470
  AI_GUARD_MARKER = "eslint-plugin-ai-guard";
323
471
  DEFAULT_FLAT_IGNORES = [
324
472
  "node_modules/**",
@@ -341,10 +489,11 @@ var init_config_manager = __esm({
341
489
 
342
490
  // cli/index.ts
343
491
  var import_commander = require("commander");
344
- var import_fs11 = __toESM(require("fs"));
345
- var import_path13 = __toESM(require("path"));
492
+ var import_fs12 = __toESM(require("fs"));
493
+ var import_path14 = __toESM(require("path"));
346
494
 
347
495
  // cli/commands/run.ts
496
+ var import_fs4 = __toESM(require("fs"));
348
497
  var import_ora = __toESM(require("ora"));
349
498
  var import_chalk3 = __toESM(require("chalk"));
350
499
 
@@ -544,24 +693,46 @@ var log = {
544
693
 
545
694
  // cli/utils/eslint-runner.ts
546
695
  var ISSUE_CONFIDENCE = {
696
+ // HIGH — near-certain bugs: false positive rate <2% in real-world codebases
547
697
  "ai-guard/no-hardcoded-secret": "high",
698
+ // Literal credential string in source: almost always a mistake
548
699
  "ai-guard/no-eval-dynamic": "high",
700
+ // Dynamic eval: no legitimate modern use case
549
701
  "ai-guard/no-floating-promise": "high",
550
- "ai-guard/no-empty-catch": "high",
702
+ // Unhandled promise: async failures silently swallowed
703
+ // MEDIUM — likely bugs, but legitimate patterns exist
704
+ "ai-guard/no-empty-catch": "medium",
705
+ // CHANGED from high: empty catch is valid for optional ops (JSON.parse, feature detection)
551
706
  "ai-guard/no-sql-string-concat": "medium",
707
+ // SQL injection risk, but ORM template literals can FP
552
708
  "ai-guard/no-await-in-loop": "medium",
709
+ // Sequential await is often intentional (rate limiting, ordering)
553
710
  "ai-guard/require-auth-middleware": "medium",
711
+ // Context-blind: public routes are valid
554
712
  "ai-guard/require-authz-check": "medium",
713
+ // Context-blind: some resources are public
555
714
  "ai-guard/no-catch-log-rethrow": "medium",
715
+ // Log-then-rethrow is a known antipattern but sometimes intentional
556
716
  "ai-guard/no-catch-without-use": "medium",
717
+ // Unused catch param common in TS
557
718
  "ai-guard/no-unsafe-deserialize": "medium",
719
+ // JSON.parse is sometimes safe with trusted input
720
+ // LOW — possible improvement, high false-positive rate
558
721
  "ai-guard/no-async-array-callback": "low",
722
+ // Promise.all is better, but forEach async is not always a bug
559
723
  "ai-guard/no-dead-branch": "low",
724
+ // Static analysis of conditions is inherently imprecise
560
725
  "ai-guard/no-broad-exception": "low",
726
+ // Catching Error is common and sometimes correct
561
727
  "ai-guard/no-console-in-handler": "low",
728
+ // Stylistic: debug logs left in vs intentional logging
562
729
  "ai-guard/no-duplicate-logic-block": "low",
730
+ // May be coincidental similarity, not true duplication
731
+ // INFORMATIONAL — hints only, never fail CI
563
732
  "ai-guard/no-async-without-await": "informational",
733
+ // Framework patterns (Next.js RSC, etc.) make this very noisy
564
734
  "ai-guard/no-redundant-await": "informational"
735
+ // Explicit await in return is idiomatic in many codebases
565
736
  };
566
737
  var ISSUE_CATEGORY = {
567
738
  "ai-guard/no-floating-promise": "Async Reliability",
@@ -742,8 +913,8 @@ function classifyEcosystemType(msg) {
742
913
  return "foreign-rule";
743
914
  }
744
915
  async function loadPluginModuleFromCwd(cwd) {
745
- const { createRequire: createRequire2 } = await import("module");
746
- const requireFromCwd = createRequire2(import_path.default.join(cwd, "package.json"));
916
+ const { createRequire: createRequire3 } = await import("module");
917
+ const requireFromCwd = createRequire3(import_path.default.join(cwd, "package.json"));
747
918
  try {
748
919
  const resolved = requireFromCwd.resolve("eslint-plugin-ai-guard");
749
920
  return import((0, import_url.pathToFileURL)(resolved).href);
@@ -1034,6 +1205,30 @@ async function runEslint(options) {
1034
1205
  };
1035
1206
  }
1036
1207
 
1208
+ // cli/utils/version.ts
1209
+ var import_module = require("module");
1210
+ var import_url2 = require("url");
1211
+ var import_path2 = __toESM(require("path"));
1212
+ var import_meta = {};
1213
+ var _version;
1214
+ function readVersion() {
1215
+ try {
1216
+ const require_ = (0, import_module.createRequire)(import_meta.url);
1217
+ const pkgPath = import_path2.default.resolve(
1218
+ import_path2.default.dirname((0, import_url2.fileURLToPath)(import_meta.url)),
1219
+ "../../package.json"
1220
+ );
1221
+ const pkg = require_(pkgPath);
1222
+ if (pkg.version) return pkg.version;
1223
+ } catch {
1224
+ }
1225
+ if (typeof __PKG_VERSION__ !== "undefined") {
1226
+ return __PKG_VERSION__;
1227
+ }
1228
+ return "0.0.0";
1229
+ }
1230
+ var PKG_VERSION = _version ?? (_version = readVersion());
1231
+
1037
1232
  // cli/utils/sarif.ts
1038
1233
  var RULE_DOCS = {
1039
1234
  "ai-guard/no-empty-catch": { shortDesc: "Empty catch block silently swallows errors", tags: ["reliability"] },
@@ -1056,6 +1251,50 @@ var RULE_DOCS = {
1056
1251
  "ai-guard/no-dead-branch": { shortDesc: "Dead code branch that can never execute", tags: ["ai-patterns"] }
1057
1252
  };
1058
1253
  var BASE_DOCS_URL = "https://github.com/YashJadhav21/eslint-plugin-ai-guard/blob/main/docs/rules";
1254
+ function sanitizeSarifTags(tags) {
1255
+ return Array.from(
1256
+ new Set(
1257
+ tags.filter((t) => typeof t === "string" && t.trim().length > 0).map((t) => t.toLowerCase().trim().replace(/\s+/g, "-"))
1258
+ )
1259
+ );
1260
+ }
1261
+ function sanitizeSarifProperties(props) {
1262
+ return {
1263
+ tags: sanitizeSarifTags(props.tags),
1264
+ confidence: props.confidence ?? "low",
1265
+ category: props.category ?? "AI Patterns",
1266
+ "problem.severity": props.problemSeverity ?? "low"
1267
+ };
1268
+ }
1269
+ function sanitizeSarifRule(rule) {
1270
+ return {
1271
+ ...rule,
1272
+ shortDescription: {
1273
+ text: rule.shortDescription.text || `ai-guard rule: ${rule.id}`
1274
+ },
1275
+ fullDescription: rule.fullDescription?.text ? rule.fullDescription : { text: rule.shortDescription.text || `ai-guard rule: ${rule.id}` },
1276
+ properties: rule.properties ? {
1277
+ ...rule.properties,
1278
+ // Re-deduplicate tags at the rule level as a final safety net
1279
+ tags: rule.properties.tags ? sanitizeSarifTags(rule.properties.tags) : []
1280
+ } : void 0
1281
+ };
1282
+ }
1283
+ function sanitizeSarifLog(log2) {
1284
+ return {
1285
+ ...log2,
1286
+ runs: log2.runs.map((run) => ({
1287
+ ...run,
1288
+ tool: {
1289
+ ...run.tool,
1290
+ driver: {
1291
+ ...run.tool.driver,
1292
+ rules: run.tool.driver.rules.map(sanitizeSarifRule)
1293
+ }
1294
+ }
1295
+ }))
1296
+ };
1297
+ }
1059
1298
  function confidenceToSarifLevel(confidence) {
1060
1299
  switch (confidence) {
1061
1300
  case "high":
@@ -1117,6 +1356,8 @@ function buildRuleDescriptors(ruleIds) {
1117
1356
  const confidence = ISSUE_CONFIDENCE[id];
1118
1357
  const category = ISSUE_CATEGORY[id] ?? "AI Patterns";
1119
1358
  const remediation = ISSUE_REMEDIATION[id];
1359
+ const categorySlug = category.toLowerCase().replace(/\s+/g, "-");
1360
+ const rawTags = [...meta?.tags ?? ["ai-guard"], categorySlug];
1120
1361
  const helpMarkdown = [
1121
1362
  `**${meta?.shortDesc ?? shortName}**`,
1122
1363
  "",
@@ -1124,7 +1365,7 @@ function buildRuleDescriptors(ruleIds) {
1124
1365
  "",
1125
1366
  `[View rule documentation](${BASE_DOCS_URL}/${shortName}.md)`
1126
1367
  ].filter(Boolean).join("\n");
1127
- return {
1368
+ return sanitizeSarifRule({
1128
1369
  id,
1129
1370
  shortDescription: {
1130
1371
  text: meta?.shortDesc ?? `ai-guard rule: ${shortName}`
@@ -1140,13 +1381,13 @@ function buildRuleDescriptors(ruleIds) {
1140
1381
  defaultConfiguration: {
1141
1382
  level: confidenceToSarifLevel(confidence)
1142
1383
  },
1143
- properties: {
1144
- tags: [...meta?.tags ?? ["ai-guard"], category.toLowerCase().replace(/ /g, "-")],
1145
- confidence: confidence ?? "low",
1384
+ properties: sanitizeSarifProperties({
1385
+ tags: rawTags,
1386
+ confidence,
1146
1387
  category,
1147
- "problem.severity": confidenceToGitHubSeverity(confidence)
1148
- }
1149
- };
1388
+ problemSeverity: confidenceToGitHubSeverity(confidence)
1389
+ })
1390
+ });
1150
1391
  });
1151
1392
  }
1152
1393
  function buildSarifResult(issue, file) {
@@ -1183,7 +1424,7 @@ function buildSarifResult(issue, file) {
1183
1424
  }
1184
1425
  };
1185
1426
  }
1186
- function buildSarifLog(result, version = "1.3.0") {
1427
+ function buildSarifLog(result, version = PKG_VERSION) {
1187
1428
  const usedRuleIds = collectUsedRuleIds(result);
1188
1429
  const rules = buildRuleDescriptors(usedRuleIds);
1189
1430
  const sarifResults = [];
@@ -1192,7 +1433,7 @@ function buildSarifLog(result, version = "1.3.0") {
1192
1433
  sarifResults.push(buildSarifResult(issue, file));
1193
1434
  }
1194
1435
  }
1195
- return {
1436
+ const log2 = {
1196
1437
  $schema: "https://json.schemastore.org/sarif-2.1.0.json",
1197
1438
  version: "2.1.0",
1198
1439
  runs: [
@@ -1216,13 +1457,46 @@ function buildSarifLog(result, version = "1.3.0") {
1216
1457
  }
1217
1458
  ]
1218
1459
  };
1460
+ return sanitizeSarifLog(log2);
1219
1461
  }
1220
1462
  function sarifToJson(log2) {
1221
1463
  return JSON.stringify(log2, null, 2);
1222
1464
  }
1465
+ function buildSarifDebugInfo(result) {
1466
+ const usedRuleIds = collectUsedRuleIds(result);
1467
+ const rulesEmitted = usedRuleIds.map((id) => {
1468
+ const meta = RULE_DOCS[id];
1469
+ const confidence = ISSUE_CONFIDENCE[id];
1470
+ const category = ISSUE_CATEGORY[id] ?? "AI Patterns";
1471
+ const categorySlug = category.toLowerCase().replace(/\s+/g, "-");
1472
+ const rawTags = [...meta?.tags ?? ["ai-guard"], categorySlug];
1473
+ const sanitizedTags = sanitizeSarifTags(rawTags);
1474
+ return {
1475
+ id,
1476
+ rawTags,
1477
+ sanitizedTags,
1478
+ hasDuplicatesInRaw: rawTags.length !== new Set(rawTags).size,
1479
+ confidence: confidence ?? "low",
1480
+ category,
1481
+ level: confidenceToSarifLevel(confidence)
1482
+ };
1483
+ });
1484
+ return {
1485
+ rulesEmitted,
1486
+ totalResults: result.files.reduce((n, f) => n + f.issues.length, 0),
1487
+ version: PKG_VERSION
1488
+ };
1489
+ }
1223
1490
 
1224
1491
  // cli/utils/github-summary.ts
1225
1492
  var import_fs2 = __toESM(require("fs"));
1493
+ function warnEnvIssue(name, filePath, err) {
1494
+ const msg = err instanceof Error ? err.message : String(err);
1495
+ process.stderr.write(
1496
+ `[ai-guard] Warning: Could not write to ${name}=${filePath}: ${msg}
1497
+ `
1498
+ );
1499
+ }
1226
1500
  function escapeMarkdown(text) {
1227
1501
  return text.replace(/[|`*_[\]<>]/g, "\\$&");
1228
1502
  }
@@ -1413,8 +1687,9 @@ function writeGitHubSummary(result, options) {
1413
1687
  if (!summaryPath) return;
1414
1688
  try {
1415
1689
  const markdown = buildGitHubSummaryMarkdown(result, options);
1416
- import_fs2.default.appendFileSync(summaryPath, markdown + "\n");
1417
- } catch {
1690
+ import_fs2.default.appendFileSync(summaryPath, markdown + "\n", { encoding: "utf-8" });
1691
+ } catch (err) {
1692
+ warnEnvIssue("GITHUB_STEP_SUMMARY", summaryPath, err);
1418
1693
  }
1419
1694
  }
1420
1695
  function writeGitHubOutputs(result, sarifPath) {
@@ -1432,14 +1707,15 @@ function writeGitHubOutputs(result, sarifPath) {
1432
1707
  ...sarifPath ? [`sarif-file=${sarifPath}`] : []
1433
1708
  ];
1434
1709
  try {
1435
- import_fs2.default.appendFileSync(outputPath, outputs.join("\n") + "\n");
1436
- } catch {
1710
+ import_fs2.default.appendFileSync(outputPath, outputs.join("\n") + "\n", { encoding: "utf-8" });
1711
+ } catch (err) {
1712
+ warnEnvIssue("GITHUB_OUTPUT", outputPath, err);
1437
1713
  }
1438
1714
  }
1439
1715
 
1440
1716
  // cli/utils/git-diff.ts
1441
1717
  var import_child_process = require("child_process");
1442
- var import_path2 = __toESM(require("path"));
1718
+ var import_path3 = __toESM(require("path"));
1443
1719
  var import_fs3 = __toESM(require("fs"));
1444
1720
  var DEFAULT_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"];
1445
1721
  var IGNORE_PREFIXES = [
@@ -1466,7 +1742,8 @@ function runGit(args, cwd) {
1466
1742
  return (0, import_child_process.execSync)(`git ${args}`, {
1467
1743
  cwd,
1468
1744
  encoding: "utf-8",
1469
- stdio: ["pipe", "pipe", "pipe"]
1745
+ stdio: ["pipe", "pipe", "pipe"],
1746
+ timeout: 15e3
1470
1747
  }).trim();
1471
1748
  } catch {
1472
1749
  return null;
@@ -1475,35 +1752,103 @@ function runGit(args, cwd) {
1475
1752
  function isGitAvailable(cwd) {
1476
1753
  return runGit("rev-parse --is-inside-work-tree", cwd) === "true";
1477
1754
  }
1478
- function filterFiles(rawFiles, extensions, workingDirectory, cwd) {
1479
- let dropped = 0;
1755
+ function isShallowClone(cwd) {
1756
+ return runGit("rev-parse --is-shallow-repository", cwd) === "true";
1757
+ }
1758
+ function isDetachedHead(cwd) {
1759
+ const result = runGit("symbolic-ref --quiet HEAD", cwd);
1760
+ return result === null;
1761
+ }
1762
+ function normalizeBranchName(ref) {
1763
+ return ref.replace(/^origin\//, "").trim();
1764
+ }
1765
+ function tryPrDiff(branch, cwd, debugInfo) {
1766
+ const rawBranch = normalizeBranchName(branch);
1767
+ {
1768
+ const strategy = `merge-base HEAD origin/${rawBranch}`;
1769
+ debugInfo.strategiesAttempted.push(strategy);
1770
+ const mergeBase = runGit(`merge-base HEAD origin/${rawBranch}`, cwd);
1771
+ if (mergeBase) {
1772
+ debugInfo.mergeBase = mergeBase;
1773
+ const out = runGit(`diff --name-only --diff-filter=ACMRT ${mergeBase}`, cwd);
1774
+ if (out !== null) {
1775
+ debugInfo.strategySucceeded = strategy;
1776
+ return { output: out, strategy, mergeBase };
1777
+ }
1778
+ }
1779
+ }
1780
+ {
1781
+ const strategy = `merge-base HEAD ${rawBranch}`;
1782
+ debugInfo.strategiesAttempted.push(strategy);
1783
+ const mergeBase = runGit(`merge-base HEAD ${rawBranch}`, cwd);
1784
+ if (mergeBase) {
1785
+ if (!debugInfo.mergeBase) debugInfo.mergeBase = mergeBase;
1786
+ const out = runGit(`diff --name-only --diff-filter=ACMRT ${mergeBase}`, cwd);
1787
+ if (out !== null) {
1788
+ debugInfo.strategySucceeded = strategy;
1789
+ return { output: out, strategy, mergeBase };
1790
+ }
1791
+ }
1792
+ }
1793
+ {
1794
+ const strategy = `diff origin/${rawBranch}...HEAD`;
1795
+ debugInfo.strategiesAttempted.push(strategy);
1796
+ const out = runGit(`diff --name-only --diff-filter=ACMRT origin/${rawBranch}...HEAD`, cwd);
1797
+ if (out !== null) {
1798
+ debugInfo.strategySucceeded = strategy;
1799
+ return { output: out, strategy };
1800
+ }
1801
+ }
1802
+ {
1803
+ const strategy = `diff ${rawBranch}...HEAD`;
1804
+ debugInfo.strategiesAttempted.push(strategy);
1805
+ const out = runGit(`diff --name-only --diff-filter=ACMRT ${rawBranch}...HEAD`, cwd);
1806
+ if (out !== null) {
1807
+ debugInfo.strategySucceeded = strategy;
1808
+ return { output: out, strategy };
1809
+ }
1810
+ }
1811
+ {
1812
+ const strategy = "diff HEAD~1 (shallow fallback)";
1813
+ debugInfo.strategiesAttempted.push(strategy);
1814
+ const out = runGit("diff --name-only --diff-filter=ACMRT HEAD~1", cwd);
1815
+ if (out !== null) {
1816
+ debugInfo.strategySucceeded = strategy;
1817
+ return { output: out, strategy };
1818
+ }
1819
+ }
1820
+ debugInfo.strategySucceeded = null;
1821
+ return null;
1822
+ }
1823
+ function filterFiles(rawFiles, extensions, workingDirectory, cwd, debugInfo) {
1480
1824
  const kept = [];
1481
1825
  for (const rel of rawFiles) {
1482
- const ext = import_path2.default.extname(rel).toLowerCase();
1826
+ const normalized = rel.replace(/\\/g, "/").trim();
1827
+ if (!normalized) continue;
1828
+ const ext = import_path3.default.extname(normalized).toLowerCase();
1483
1829
  if (!extensions.includes(ext)) {
1484
- dropped++;
1830
+ debugInfo.droppedByExtension++;
1485
1831
  continue;
1486
1832
  }
1487
- const normalized = rel.replace(/\\/g, "/");
1488
1833
  if (IGNORE_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
1489
- dropped++;
1834
+ debugInfo.droppedByIgnore++;
1490
1835
  continue;
1491
1836
  }
1492
1837
  if (workingDirectory) {
1493
1838
  const wdNorm = workingDirectory.replace(/\\/g, "/").replace(/\/$/, "");
1494
1839
  if (!normalized.startsWith(wdNorm + "/") && normalized !== wdNorm) {
1495
- dropped++;
1840
+ debugInfo.droppedByWorkingDir++;
1496
1841
  continue;
1497
1842
  }
1498
1843
  }
1499
- const abs = import_path2.default.resolve(cwd, rel);
1844
+ const abs = import_path3.default.resolve(cwd, normalized);
1500
1845
  if (!import_fs3.default.existsSync(abs)) {
1501
- dropped++;
1846
+ debugInfo.droppedMissing++;
1502
1847
  continue;
1503
1848
  }
1504
1849
  kept.push(abs);
1505
1850
  }
1506
- return { kept, dropped };
1851
+ return kept;
1507
1852
  }
1508
1853
  function parseFileList(output) {
1509
1854
  return output.split("\n").map((f) => f.trim()).filter(Boolean);
@@ -1514,46 +1859,96 @@ function getChangedFiles(options = {}) {
1514
1859
  base,
1515
1860
  cwd = process.cwd(),
1516
1861
  extensions = DEFAULT_EXTENSIONS,
1517
- workingDirectory
1862
+ workingDirectory,
1863
+ debug = false
1518
1864
  } = options;
1519
- const effectiveBase = base ?? process.env.GITHUB_BASE_REF ? `origin/${process.env.GITHUB_BASE_REF ?? ""}` : void 0;
1865
+ const debugInfo = {
1866
+ strategiesAttempted: [],
1867
+ strategySucceeded: null,
1868
+ isShallowClone: false,
1869
+ isDetachedHead: false,
1870
+ rawFileCount: 0,
1871
+ droppedByExtension: 0,
1872
+ droppedByIgnore: 0,
1873
+ droppedMissing: 0,
1874
+ droppedByWorkingDir: 0
1875
+ };
1520
1876
  if (!isGitAvailable(cwd)) {
1521
- return { files: [], mode: "fallback", totalDetected: 0, filteredOut: 0 };
1877
+ return {
1878
+ files: [],
1879
+ mode: "fallback",
1880
+ totalDetected: 0,
1881
+ filteredOut: 0,
1882
+ debugInfo,
1883
+ zeroFilesReason: "Git is not available in this directory. Run inside a git repository."
1884
+ };
1522
1885
  }
1886
+ debugInfo.isShallowClone = isShallowClone(cwd);
1887
+ debugInfo.isDetachedHead = isDetachedHead(cwd);
1888
+ const envBase = process.env.GITHUB_BASE_REF ? normalizeBranchName(process.env.GITHUB_BASE_REF) : void 0;
1889
+ const resolvedBranch = base ? normalizeBranchName(base) : envBase;
1890
+ debugInfo.resolvedBase = resolvedBranch;
1523
1891
  let rawOutput = null;
1524
1892
  let mode;
1525
1893
  let usedBase;
1526
- if (effectiveBase && !staged) {
1527
- const mergeBase = runGit(`merge-base HEAD ${effectiveBase}`, cwd);
1528
- if (mergeBase) {
1529
- rawOutput = runGit(`diff --name-only --diff-filter=ACMRT ${mergeBase}...HEAD`, cwd);
1530
- }
1894
+ let zeroFilesReason;
1895
+ if (staged) {
1896
+ rawOutput = runGit("diff --name-only --cached --diff-filter=ACMRT", cwd);
1897
+ mode = "staged";
1898
+ debugInfo.strategiesAttempted.push("git diff --cached");
1899
+ if (rawOutput !== null) debugInfo.strategySucceeded = "git diff --cached";
1531
1900
  if (!rawOutput) {
1532
- rawOutput = runGit(`diff --name-only --diff-filter=ACMRT ${effectiveBase}`, cwd);
1901
+ zeroFilesReason = "No staged files found. Run `git add <files>` before using --staged.";
1533
1902
  }
1903
+ } else if (resolvedBranch) {
1534
1904
  mode = "pr-diff";
1535
- usedBase = effectiveBase;
1536
- } else if (staged) {
1537
- rawOutput = runGit("diff --name-only --cached --diff-filter=ACMRT", cwd);
1538
- mode = "staged";
1905
+ usedBase = resolvedBranch;
1906
+ const diffResult = tryPrDiff(resolvedBranch, cwd, debugInfo);
1907
+ if (diffResult) {
1908
+ rawOutput = diffResult.output;
1909
+ } else {
1910
+ const shallow = debugInfo.isShallowClone ? " Shallow clone detected \u2014 try fetch-depth: 0 in your workflow." : "";
1911
+ const detached = debugInfo.isDetachedHead ? " HEAD is detached \u2014 ensure checkout fetches the branch." : "";
1912
+ zeroFilesReason = `PR diff failed against "${resolvedBranch}". Tried: ${debugInfo.strategiesAttempted.join(", ")}.${shallow}${detached} Run with --debug-git for full diagnosis.`;
1913
+ }
1539
1914
  } else {
1915
+ mode = "uncommitted";
1540
1916
  const staged_ = runGit("diff --name-only --cached --diff-filter=ACMRT", cwd) ?? "";
1541
1917
  const unstaged = runGit("diff --name-only --diff-filter=ACMRT", cwd) ?? "";
1918
+ debugInfo.strategiesAttempted.push("git diff --cached", "git diff (unstaged)");
1542
1919
  const combined = /* @__PURE__ */ new Set([...parseFileList(staged_), ...parseFileList(unstaged)]);
1543
1920
  rawOutput = [...combined].join("\n");
1544
- mode = "uncommitted";
1921
+ if (rawOutput) debugInfo.strategySucceeded = "uncommitted changes";
1922
+ if (!rawOutput) {
1923
+ zeroFilesReason = "No uncommitted changes found. Use --pr to scan PR changes, or --staged for staged files.";
1924
+ }
1545
1925
  }
1546
1926
  if (!rawOutput) {
1547
- return { files: [], mode, base: usedBase, totalDetected: 0, filteredOut: 0 };
1927
+ return {
1928
+ files: [],
1929
+ mode,
1930
+ base: usedBase,
1931
+ totalDetected: 0,
1932
+ filteredOut: 0,
1933
+ debugInfo,
1934
+ zeroFilesReason
1935
+ };
1548
1936
  }
1549
1937
  const rawFiles = parseFileList(rawOutput);
1550
- const { kept, dropped } = filterFiles(rawFiles, extensions, workingDirectory, cwd);
1938
+ debugInfo.rawFileCount = rawFiles.length;
1939
+ const kept = filterFiles(rawFiles, extensions, workingDirectory, cwd, debugInfo);
1940
+ const dropped = debugInfo.droppedByExtension + debugInfo.droppedByIgnore + debugInfo.droppedByWorkingDir + debugInfo.droppedMissing;
1941
+ if (kept.length === 0 && rawFiles.length > 0) {
1942
+ zeroFilesReason = `${rawFiles.length} changed file${rawFiles.length !== 1 ? "s" : ""} detected but all filtered out. Extension filter: ${debugInfo.droppedByExtension}, ignored paths: ${debugInfo.droppedByIgnore}, missing from disk: ${debugInfo.droppedMissing}.`;
1943
+ }
1551
1944
  return {
1552
1945
  files: kept,
1553
1946
  mode,
1554
1947
  base: usedBase,
1555
1948
  totalDetected: rawFiles.length,
1556
- filteredOut: dropped
1949
+ filteredOut: dropped,
1950
+ debugInfo,
1951
+ zeroFilesReason: kept.length === 0 ? zeroFilesReason : void 0
1557
1952
  };
1558
1953
  }
1559
1954
  function isGitHubActions() {
@@ -1569,7 +1964,7 @@ function registerRunCommand(program2) {
1569
1964
  "--max-warnings <n>",
1570
1965
  "Fail with exit code 1 if warnings exceed this count",
1571
1966
  (value) => Number.parseInt(value, 10)
1572
- ).option("--verbose", "Show all issues \u2014 disable grouping of repeated warnings").option("--quiet", "Only show errors \u2014 suppress warnings and informational hints").option("--debug-timing", "Print per-phase timing diagnostics").action(async (opts) => {
1967
+ ).option("--verbose", "Show all issues \u2014 disable grouping of repeated warnings").option("--quiet", "Only show errors \u2014 suppress warnings and informational hints").option("--debug-timing", "Print per-phase timing diagnostics").option("--debug-sarif", "Print SARIF tag normalization trace \u2014 diagnose duplicate-tag schema issues").option("--sarif-output <file>", "Write SARIF to this file instead of stdout").action(async (opts) => {
1573
1968
  if (opts.maxWarnings !== void 0 && (!Number.isInteger(opts.maxWarnings) || opts.maxWarnings < 0)) {
1574
1969
  log.blank();
1575
1970
  log.error("--max-warnings must be a non-negative integer.");
@@ -1621,9 +2016,36 @@ function registerRunCommand(program2) {
1621
2016
  writeGitHubSummary(result, { preset, scanMode: "full" });
1622
2017
  writeGitHubOutputs(result);
1623
2018
  }
1624
- if (opts.sarif) {
2019
+ if (opts.sarif || opts.sarifOutput) {
1625
2020
  const sarifLog = buildSarifLog(result);
1626
- console.log(sarifToJson(sarifLog));
2021
+ const sarifJson = sarifToJson(sarifLog);
2022
+ if (opts.debugSarif) {
2023
+ const debugInfo = buildSarifDebugInfo(result);
2024
+ process.stderr.write("\n[debug-sarif] SARIF Tag Normalization Trace\n");
2025
+ process.stderr.write("[debug-sarif] \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
2026
+ for (const r of debugInfo.rulesEmitted) {
2027
+ process.stderr.write(`[debug-sarif] ${r.id}
2028
+ `);
2029
+ process.stderr.write(`[debug-sarif] raw: ${JSON.stringify(r.rawTags)}
2030
+ `);
2031
+ process.stderr.write(`[debug-sarif] sanitized: ${JSON.stringify(r.sanitizedTags)}
2032
+ `);
2033
+ if (r.hasDuplicatesInRaw) {
2034
+ process.stderr.write(`[debug-sarif] \u26A0 had duplicates \u2014 deduplicated
2035
+ `);
2036
+ }
2037
+ }
2038
+ process.stderr.write("\n");
2039
+ }
2040
+ if (opts.sarifOutput) {
2041
+ import_fs4.default.writeFileSync(opts.sarifOutput, sarifJson, "utf-8");
2042
+ if (opts.debugSarif) {
2043
+ process.stderr.write(`[debug-sarif] SARIF written to: ${opts.sarifOutput}
2044
+ `);
2045
+ }
2046
+ } else {
2047
+ console.log(sarifJson);
2048
+ }
1627
2049
  process.exit(resolveExitCode(result, opts.failOn ?? "errors", opts.maxWarnings));
1628
2050
  return;
1629
2051
  }
@@ -1957,32 +2379,58 @@ function resolveExitCode(result, failOn, maxWarnings) {
1957
2379
  }
1958
2380
 
1959
2381
  // cli/commands/changed.ts
1960
- var import_path3 = __toESM(require("path"));
1961
- var import_fs4 = __toESM(require("fs"));
2382
+ var import_path4 = __toESM(require("path"));
2383
+ var import_fs5 = __toESM(require("fs"));
1962
2384
  var import_ora2 = __toESM(require("ora"));
1963
- var import_chalk4 = __toESM(require("chalk"));
2385
+ var import_chalk5 = __toESM(require("chalk"));
1964
2386
  function registerChangedCommand(program2) {
1965
- program2.command("changed").description("Scan only changed files in the current PR or working tree (fastest CI mode)").option("--pr", "Scan files changed vs base branch (auto-detects GITHUB_BASE_REF in CI)").option("--staged", "Scan only staged (git add'd) files").option("--base <branch>", "Base branch to diff against (e.g. main, origin/main)").option("--path <dir>", "Root path / working directory for scanning", ".").option("--strict", "Use the strict rule preset (all rules at error)").option("--security", "Use the security-only rule preset").option("--fail-on <level>", "Fail CI on: high | medium | any | none", "high").option("--json", "Output results as JSON").option("--sarif", "Output results as SARIF 2.1.0 (for GitHub Code Scanning)").option("--sarif-output <file>", "Write SARIF to file instead of stdout").option("--github-summary", "Write GitHub step summary (auto-enabled in GitHub Actions)").option(
2387
+ program2.command("changed").description("Scan only changed files in the current PR or working tree (fastest CI mode)").option("--pr", "Scan files changed vs base branch (auto-detects GITHUB_BASE_REF in CI)").option("--staged", "Scan only staged (git add'd) files").option("--base <branch>", "Base branch to diff against (raw name: main, develop \u2014 not origin/main)").option("--path <dir>", "Root path / working directory for scanning", ".").option("--strict", "Use the strict rule preset (all rules at error)").option("--security", "Use the security-only rule preset").option("--fail-on <level>", "Fail CI on: high | medium | any | errors | none", "high").option("--json", "Output results as JSON").option("--sarif", "Output results as SARIF 2.1.0 (for GitHub Code Scanning)").option("--sarif-output <file>", "Write SARIF to this file path").option("--sarif-stdout", "Force SARIF to stdout even in CI (overrides auto-file behavior)").option("--github-summary", "Write GitHub step summary (auto-enabled in GitHub Actions)").option(
1966
2388
  "--max-warnings <n>",
1967
2389
  "Fail if warnings exceed this count",
1968
2390
  (v) => Number.parseInt(v, 10)
1969
- ).option("--verbose", "Expand all findings (disable grouping)").option("--quiet", "Show errors only").option("--debug-timing", "Print per-phase timing diagnostics").action(async (opts) => {
2391
+ ).option("--verbose", "Expand all findings (disable grouping)").option("--quiet", "Show errors only").option("--debug-timing", "Print per-phase timing diagnostics").option("--debug-git", "Print full git resolution trace (useful for diagnosing zero-file issues)").option("--debug-ci", "Print CI environment state (GITHUB_* vars, SARIF path, summary path)").action(async (opts) => {
1970
2392
  const preset = opts.strict ? "strict" : opts.security ? "security" : "recommended";
1971
2393
  const inCI = isGitHubActions();
1972
2394
  const baseRef = opts.base ?? (opts.pr || inCI ? getGitHubBaseRef() : void 0);
2395
+ const sarifToFile = opts.sarif && !opts.sarifStdout && (opts.sarifOutput || inCI);
2396
+ const resolvedSarifPath = opts.sarifOutput ?? (sarifToFile ? "ai-guard-results.sarif" : void 0);
1973
2397
  if (!opts.json && !opts.sarif) {
1974
2398
  log.banner("AI GUARD");
1975
2399
  }
2400
+ if (opts.debugCi) {
2401
+ const { printCIDebug: printCIDebug2 } = await Promise.resolve().then(() => (init_debug(), debug_exports));
2402
+ printCIDebug2({
2403
+ isGitHubActions: inCI,
2404
+ githubBaseRef: process.env.GITHUB_BASE_REF,
2405
+ githubSha: process.env.GITHUB_SHA,
2406
+ githubRef: process.env.GITHUB_REF,
2407
+ githubRepository: process.env.GITHUB_REPOSITORY,
2408
+ githubWorkflow: process.env.GITHUB_WORKFLOW,
2409
+ githubRunId: process.env.GITHUB_RUN_ID,
2410
+ githubEventName: process.env.GITHUB_EVENT_NAME,
2411
+ githubStepSummary: process.env.GITHUB_STEP_SUMMARY,
2412
+ githubOutput: process.env.GITHUB_OUTPUT,
2413
+ sarifOutputPath: resolvedSarifPath,
2414
+ preset,
2415
+ failOn: opts.failOn,
2416
+ scanMode: opts.staged ? "staged" : baseRef ? "pr-diff" : "uncommitted"
2417
+ });
2418
+ }
1976
2419
  const cwd = process.cwd();
1977
- const resolvedPath = import_path3.default.resolve(opts.path);
2420
+ const resolvedPath = import_path4.default.resolve(opts.path);
1978
2421
  const workingDirectory = opts.path !== "." ? opts.path : void 0;
1979
- const spinner = opts.json || opts.sarif ? null : (0, import_ora2.default)({ text: import_chalk4.default.dim("Detecting changed files\u2026"), color: "cyan" }).start();
2422
+ const spinner = opts.json || opts.sarif ? null : (0, import_ora2.default)({ text: import_chalk5.default.dim("Detecting changed files\u2026"), color: "cyan" }).start();
1980
2423
  const changedResult = getChangedFiles({
1981
2424
  staged: opts.staged ?? false,
1982
- base: baseRef ? `origin/${baseRef}` : opts.base,
2425
+ base: baseRef,
1983
2426
  cwd,
1984
- workingDirectory
2427
+ workingDirectory,
2428
+ debug: opts.debugGit
1985
2429
  });
2430
+ if (opts.debugGit) {
2431
+ const { printGitDebug: printGitDebug2 } = await Promise.resolve().then(() => (init_debug(), debug_exports));
2432
+ printGitDebug2(changedResult);
2433
+ }
1986
2434
  if (changedResult.files.length === 0) {
1987
2435
  spinner?.stop();
1988
2436
  if (changedResult.mode === "fallback") {
@@ -1995,18 +2443,25 @@ function registerChangedCommand(program2) {
1995
2443
  targetPath: resolvedPath.toString(),
1996
2444
  debugTiming: opts.debugTiming
1997
2445
  });
1998
- handleResults(result2, opts, preset, "full", 0, inCI);
2446
+ handleResults(result2, opts, preset, "full", 0, inCI, resolvedSarifPath);
1999
2447
  return;
2000
2448
  }
2001
2449
  if (!opts.json && !opts.sarif) {
2002
2450
  log.blank();
2003
- log.print(` ${import_chalk4.default.green("\u2714")} No changed JS/TS files detected \u2014 nothing to scan`);
2451
+ log.print(` ${import_chalk5.default.yellow("\u26A0")} No changed JS/TS files detected \u2014 nothing to scan`);
2452
+ if (changedResult.zeroFilesReason) {
2453
+ log.print(import_chalk5.default.dim(` ${changedResult.zeroFilesReason}`));
2454
+ }
2004
2455
  if (changedResult.filteredOut > 0) {
2005
- log.print(import_chalk4.default.dim(` (${changedResult.filteredOut} changed file${changedResult.filteredOut !== 1 ? "s" : ""} skipped \u2014 not JS/TS)`));
2456
+ log.print(import_chalk5.default.dim(` (${changedResult.filteredOut} file${changedResult.filteredOut !== 1 ? "s" : ""} filtered out)`));
2457
+ }
2458
+ if (!opts.debugGit) {
2459
+ log.print(import_chalk5.default.dim(" Run with --debug-git for full git resolution trace."));
2006
2460
  }
2007
2461
  log.blank();
2008
2462
  } else if (opts.json) {
2009
2463
  console.log(JSON.stringify({
2464
+ version: PKG_VERSION,
2010
2465
  preset,
2011
2466
  scanMode: changedResult.mode,
2012
2467
  changedFiles: 0,
@@ -2014,6 +2469,8 @@ function registerChangedCommand(program2) {
2014
2469
  totalIssues: 0,
2015
2470
  totalErrors: 0,
2016
2471
  totalWarnings: 0,
2472
+ zeroFilesReason: changedResult.zeroFilesReason,
2473
+ debugInfo: opts.debugGit ? changedResult.debugInfo : void 0,
2017
2474
  signalSummary: { high: 0, medium: 0, low: 0, informational: 0, ecosystemIssues: 0, parserErrors: 0 }
2018
2475
  }, null, 2));
2019
2476
  }
@@ -2021,7 +2478,7 @@ function registerChangedCommand(program2) {
2021
2478
  return;
2022
2479
  }
2023
2480
  if (spinner) {
2024
- spinner.text = import_chalk4.default.dim(`Scanning ${changedResult.files.length} changed file${changedResult.files.length !== 1 ? "s" : ""}\u2026`);
2481
+ spinner.text = import_chalk5.default.dim(`Scanning ${changedResult.files.length} changed file${changedResult.files.length !== 1 ? "s" : ""}\u2026`);
2025
2482
  }
2026
2483
  const result = await runEslint({
2027
2484
  preset,
@@ -2030,10 +2487,11 @@ function registerChangedCommand(program2) {
2030
2487
  debugTiming: opts.debugTiming
2031
2488
  });
2032
2489
  spinner?.stop();
2033
- handleResults(result, opts, preset, changedResult.mode === "pr-diff" ? "changed" : changedResult.mode === "staged" ? "staged" : "changed", changedResult.files.length, inCI);
2490
+ const scanMode = changedResult.mode === "staged" ? "staged" : "changed";
2491
+ handleResults(result, opts, preset, scanMode, changedResult.files.length, inCI, resolvedSarifPath);
2034
2492
  });
2035
2493
  }
2036
- function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI) {
2494
+ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI, resolvedSarifPath) {
2037
2495
  if (inCI || opts.githubSummary) {
2038
2496
  writeGitHubSummary(result, { preset, scanMode, changedFilesCount });
2039
2497
  writeGitHubOutputs(result, opts.sarifOutput);
@@ -2042,8 +2500,8 @@ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI)
2042
2500
  if (opts.sarif) {
2043
2501
  const sarifLog = buildSarifLog(result);
2044
2502
  const sarifJson = sarifToJson(sarifLog);
2045
- if (opts.sarifOutput) {
2046
- import_fs4.default.writeFileSync(opts.sarifOutput, sarifJson, "utf-8");
2503
+ if (resolvedSarifPath) {
2504
+ import_fs5.default.writeFileSync(resolvedSarifPath, sarifJson, "utf-8");
2047
2505
  } else {
2048
2506
  console.log(sarifJson);
2049
2507
  }
@@ -2053,7 +2511,7 @@ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI)
2053
2511
  if (opts.json) {
2054
2512
  const signalSummary = buildSignalSummary(result);
2055
2513
  const jsonOutput = {
2056
- version: "1.3.0",
2514
+ version: PKG_VERSION,
2057
2515
  preset,
2058
2516
  scanMode,
2059
2517
  scannedPath: opts.path,
@@ -2115,7 +2573,7 @@ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI)
2115
2573
  log.category(icon, cat, categoryErrors[cat] ?? 0, categoryWarnings[cat] ?? 0);
2116
2574
  }
2117
2575
  log.blank();
2118
- log.print(` ${import_chalk4.default.bold("Total:")} ${formatIssueCount(result.totalErrors, result.totalWarnings)}`);
2576
+ log.print(` ${import_chalk5.default.bold("Total:")} ${formatIssueCount(result.totalErrors, result.totalWarnings)}`);
2119
2577
  log.blank();
2120
2578
  if (actionableFiles.length > 0) {
2121
2579
  log.section("Issues by File");
@@ -2126,18 +2584,18 @@ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI)
2126
2584
  if (totalInfoCount > 0 && !quiet) {
2127
2585
  if (verbose) {
2128
2586
  log.section("Informational Hints");
2129
- log.print(import_chalk4.default.dim(" Stylistic hints with higher false-positive rate \u2014 review before acting."));
2587
+ log.print(import_chalk5.default.dim(" Stylistic hints with higher false-positive rate \u2014 review before acting."));
2130
2588
  log.blank();
2131
2589
  renderIssuesByFile({ ...result, files: informationalFiles }, true, false);
2132
2590
  } else {
2133
2591
  log.blank();
2134
- log.print(` ${import_chalk4.default.gray("\u25B8")} ${import_chalk4.default.gray(`${totalInfoCount} informational hint${totalInfoCount !== 1 ? "s" : ""} \u2014 run with ${import_chalk4.default.cyan("--verbose")} to expand`)}`);
2592
+ log.print(` ${import_chalk5.default.gray("\u25B8")} ${import_chalk5.default.gray(`${totalInfoCount} informational hint${totalInfoCount !== 1 ? "s" : ""} \u2014 run with ${import_chalk5.default.cyan("--verbose")} to expand`)}`);
2135
2593
  }
2136
2594
  }
2137
2595
  }
2138
2596
  if (result.ecosystemIssues.length > 0) {
2139
2597
  log.ecosystemSection("ESLint Config Issues");
2140
- log.print(import_chalk4.default.dim(" These issues come from your project's ESLint config, not from ai-guard."));
2598
+ log.print(import_chalk5.default.dim(" These issues come from your project's ESLint config, not from ai-guard."));
2141
2599
  log.blank();
2142
2600
  const seen = /* @__PURE__ */ new Map();
2143
2601
  for (const issue of result.ecosystemIssues) {
@@ -2158,11 +2616,11 @@ function handleResults(result, opts, preset, scanMode, changedFilesCount, inCI)
2158
2616
  log.blank();
2159
2617
  log.section("Next Steps");
2160
2618
  if (result.totalIssues > 0) {
2161
- log.info(`Run ${import_chalk4.default.cyan("ai-guard baseline")} to save these issues and track only new ones`);
2162
- log.info(`Run ${import_chalk4.default.cyan("ai-guard report")} to generate a shareable HTML report`);
2619
+ log.info(`Run ${import_chalk5.default.cyan("ai-guard baseline")} to save these issues and track only new ones`);
2620
+ log.info(`Run ${import_chalk5.default.cyan("ai-guard report")} to generate a shareable HTML report`);
2163
2621
  }
2164
2622
  if (result.ecosystemIssues.length > 0) {
2165
- log.info(`Run ${import_chalk4.default.cyan("ai-guard doctor")} to diagnose ESLint config issues`);
2623
+ log.info(`Run ${import_chalk5.default.cyan("ai-guard doctor")} to diagnose ESLint config issues`);
2166
2624
  }
2167
2625
  log.blank();
2168
2626
  process.exit(getFailOnExitCode(result, opts.failOn, opts.maxWarnings));
@@ -2172,14 +2630,14 @@ function getFailOnExitCode(result, failOn, maxWarnings) {
2172
2630
  }
2173
2631
 
2174
2632
  // cli/commands/init.ts
2175
- var import_chalk5 = __toESM(require("chalk"));
2176
- var import_path6 = __toESM(require("path"));
2177
- var import_fs7 = __toESM(require("fs"));
2633
+ var import_chalk6 = __toESM(require("chalk"));
2634
+ var import_path7 = __toESM(require("path"));
2635
+ var import_fs8 = __toESM(require("fs"));
2178
2636
 
2179
2637
  // cli/utils/detector.ts
2180
- var import_fs5 = __toESM(require("fs"));
2181
- var import_path4 = __toESM(require("path"));
2182
- var import_module = require("module");
2638
+ var import_fs6 = __toESM(require("fs"));
2639
+ var import_path5 = __toESM(require("path"));
2640
+ var import_module2 = require("module");
2183
2641
  var FLAT_CONFIG_FILES = [
2184
2642
  { file: "eslint.config.js", type: "flat-js" },
2185
2643
  { file: "eslint.config.mjs", type: "flat-mjs" },
@@ -2195,11 +2653,11 @@ var LEGACY_CONFIG_FILES = [
2195
2653
  var ALL_CONFIG_FILES = [...FLAT_CONFIG_FILES, ...LEGACY_CONFIG_FILES];
2196
2654
  function isPackageInstalled(pkgName, cwd = process.cwd()) {
2197
2655
  try {
2198
- const pkgPath = import_path4.default.join(cwd, "node_modules", pkgName, "package.json");
2199
- if (import_fs5.default.existsSync(pkgPath)) {
2656
+ const pkgPath = import_path5.default.join(cwd, "node_modules", pkgName, "package.json");
2657
+ if (import_fs6.default.existsSync(pkgPath)) {
2200
2658
  return true;
2201
2659
  }
2202
- const req = (0, import_module.createRequire)(import_path4.default.join(cwd, "package.json"));
2660
+ const req = (0, import_module2.createRequire)(import_path5.default.join(cwd, "package.json"));
2203
2661
  req.resolve(`${pkgName}/package.json`);
2204
2662
  return true;
2205
2663
  } catch {
@@ -2208,9 +2666,9 @@ function isPackageInstalled(pkgName, cwd = process.cwd()) {
2208
2666
  }
2209
2667
  function getPackageVersion(pkgName, cwd = process.cwd()) {
2210
2668
  try {
2211
- const pkgPath = import_path4.default.join(cwd, "node_modules", pkgName, "package.json");
2212
- const resolvedPath = import_fs5.default.existsSync(pkgPath) ? pkgPath : (0, import_module.createRequire)(import_path4.default.join(cwd, "package.json")).resolve(`${pkgName}/package.json`);
2213
- const raw = import_fs5.default.readFileSync(resolvedPath, "utf-8");
2669
+ const pkgPath = import_path5.default.join(cwd, "node_modules", pkgName, "package.json");
2670
+ const resolvedPath = import_fs6.default.existsSync(pkgPath) ? pkgPath : (0, import_module2.createRequire)(import_path5.default.join(cwd, "package.json")).resolve(`${pkgName}/package.json`);
2671
+ const raw = import_fs6.default.readFileSync(resolvedPath, "utf-8");
2214
2672
  const json = JSON.parse(raw);
2215
2673
  return json.version ?? null;
2216
2674
  } catch {
@@ -2226,8 +2684,8 @@ function detectConfigType(cwd = process.cwd()) {
2226
2684
  const found = [];
2227
2685
  let first = null;
2228
2686
  for (const { file, type } of ALL_CONFIG_FILES) {
2229
- const fullPath = import_path4.default.join(cwd, file);
2230
- if (import_fs5.default.existsSync(fullPath)) {
2687
+ const fullPath = import_path5.default.join(cwd, file);
2688
+ if (import_fs6.default.existsSync(fullPath)) {
2231
2689
  found.push(fullPath);
2232
2690
  if (!first) first = { type, path: fullPath };
2233
2691
  }
@@ -2250,7 +2708,7 @@ function requiresFlatConfig(eslintMajor) {
2250
2708
  function detectNukeIgnore(configPath) {
2251
2709
  if (!configPath) return false;
2252
2710
  try {
2253
- const content = import_fs5.default.readFileSync(configPath, "utf-8");
2711
+ const content = import_fs6.default.readFileSync(configPath, "utf-8");
2254
2712
  return content.includes('"**/*"') || content.includes("'**/*'");
2255
2713
  } catch {
2256
2714
  return false;
@@ -2306,7 +2764,7 @@ async function verifyConfigLoads(configPath, cwd) {
2306
2764
  overrideConfigFile: configPath
2307
2765
  });
2308
2766
  await eslint.lintText("", {
2309
- filePath: import_path6.default.join(cwd, "_ai_guard_probe_.js")
2767
+ filePath: import_path7.default.join(cwd, "_ai_guard_probe_.js")
2310
2768
  });
2311
2769
  return null;
2312
2770
  } catch (err) {
@@ -2324,7 +2782,7 @@ function registerInitCommand(program2) {
2324
2782
  const isDryRun = opts.dryRun === true;
2325
2783
  log.banner("AI GUARD INIT");
2326
2784
  if (isDryRun) {
2327
- log.print(` ${import_chalk5.default.yellow("\u2691 DRY RUN \u2014 no files will be written")}`);
2785
+ log.print(` ${import_chalk6.default.yellow("\u2691 DRY RUN \u2014 no files will be written")}`);
2328
2786
  log.blank();
2329
2787
  }
2330
2788
  log.info("Detecting your project setup\u2026");
@@ -2342,7 +2800,7 @@ function registerInitCommand(program2) {
2342
2800
  log.warn("eslint-plugin-ai-guard not found");
2343
2801
  }
2344
2802
  if (env.configType !== "none") {
2345
- log.success(`ESLint config found: ${import_chalk5.default.white(import_path6.default.relative(cwd, env.configPath ?? env.configType))}`);
2803
+ log.success(`ESLint config found: ${import_chalk6.default.white(import_path7.default.relative(cwd, env.configPath ?? env.configType))}`);
2346
2804
  } else {
2347
2805
  log.info("No ESLint config found \u2014 will generate one");
2348
2806
  }
@@ -2351,9 +2809,9 @@ function registerInitCommand(program2) {
2351
2809
  log.blank();
2352
2810
  log.warn("Conflicting configs detected:");
2353
2811
  for (const p of env.allConfigPaths) {
2354
- log.print(` ${import_chalk5.default.yellow("\u2192")} ${import_chalk5.default.white(import_path6.default.relative(cwd, p))}`);
2812
+ log.print(` ${import_chalk6.default.yellow("\u2192")} ${import_chalk6.default.white(import_path7.default.relative(cwd, p))}`);
2355
2813
  }
2356
- log.print(` ${import_chalk5.default.gray("Multiple config formats found \u2014 this can cause unpredictable behavior.")}`);
2814
+ log.print(` ${import_chalk6.default.gray("Multiple config formats found \u2014 this can cause unpredictable behavior.")}`);
2357
2815
  }
2358
2816
  log.blank();
2359
2817
  const toInstall = [];
@@ -2364,22 +2822,22 @@ function registerInitCommand(program2) {
2364
2822
  log.warn("The following packages are not installed:");
2365
2823
  log.blank();
2366
2824
  for (const pkg of toInstall) {
2367
- log.print(` ${import_chalk5.default.yellow("\u2192")} ${import_chalk5.default.white(pkg)}`);
2825
+ log.print(` ${import_chalk6.default.yellow("\u2192")} ${import_chalk6.default.white(pkg)}`);
2368
2826
  }
2369
2827
  log.blank();
2370
- log.print(` ${import_chalk5.default.bold("Run this first:")}`);
2828
+ log.print(` ${import_chalk6.default.bold("Run this first:")}`);
2371
2829
  log.blank();
2372
- log.print(` ${import_chalk5.default.cyan(`npm install --save-dev ${toInstall.join(" ")}`)}`);
2830
+ log.print(` ${import_chalk6.default.cyan(`npm install --save-dev ${toInstall.join(" ")}`)}`);
2373
2831
  log.blank();
2374
- log.print(` Then re-run ${import_chalk5.default.cyan("ai-guard init")} to complete setup.`);
2832
+ log.print(` Then re-run ${import_chalk6.default.cyan("ai-guard init")} to complete setup.`);
2375
2833
  log.blank();
2376
2834
  process.exit(1);
2377
2835
  return;
2378
2836
  }
2379
2837
  try {
2380
- const { createRequire: createRequire2 } = await import("module");
2838
+ const { createRequire: createRequire3 } = await import("module");
2381
2839
  const { pathToFileURL: pathToFileURL2 } = await import("url");
2382
- const req = createRequire2(import_path6.default.join(cwd, "_probe.js"));
2840
+ const req = createRequire3(import_path7.default.join(cwd, "_probe.js"));
2383
2841
  const resolvedPath = req.resolve("eslint-plugin-ai-guard");
2384
2842
  const aiGuard = await import(pathToFileURL2(resolvedPath).href);
2385
2843
  const plugin = aiGuard.default || aiGuard;
@@ -2398,9 +2856,9 @@ function registerInitCommand(program2) {
2398
2856
  if (eslintNeedsFlat && existingIsLegacy) {
2399
2857
  log.section("Config Migration Required");
2400
2858
  log.warn(`ESLint v${env.eslintMajor} requires flat config, but a legacy config was found:`);
2401
- log.print(` ${import_chalk5.default.white(import_path6.default.relative(cwd, env.configPath))}`);
2859
+ log.print(` ${import_chalk6.default.white(import_path7.default.relative(cwd, env.configPath))}`);
2402
2860
  log.blank();
2403
- log.print(` ${import_chalk5.default.bold("ai-guard will create a new flat config.")}`);
2861
+ log.print(` ${import_chalk6.default.bold("ai-guard will create a new flat config.")}`);
2404
2862
  log.blank();
2405
2863
  }
2406
2864
  log.section(`Configuring ESLint${isDryRun ? " (dry run)" : ""}`);
@@ -2410,34 +2868,34 @@ function registerInitCommand(program2) {
2410
2868
  const raw = readConfig(env.configPath);
2411
2869
  const { content: fixed, changed } = removeNukeIgnore(raw);
2412
2870
  if (changed) {
2413
- log.warn(`Removed "**/*" ignore pattern from ${import_path6.default.relative(cwd, env.configPath)}`);
2871
+ log.warn(`Removed "**/*" ignore pattern from ${import_path7.default.relative(cwd, env.configPath)}`);
2414
2872
  if (!isDryRun) {
2415
2873
  backupConfig(env.configPath);
2416
2874
  writeConfig(env.configPath, fixed);
2417
2875
  log.success("Ignore pattern fixed");
2418
2876
  } else {
2419
- log.print(` ${import_chalk5.default.gray("[dry-run] would remove nuke-ignore from existing config")}`);
2877
+ log.print(` ${import_chalk6.default.gray("[dry-run] would remove nuke-ignore from existing config")}`);
2420
2878
  }
2421
2879
  }
2422
2880
  }
2423
2881
  if (env.configType === "none" || eslintNeedsFlat && existingIsLegacy) {
2424
2882
  const targetName = useFlat ? "eslint.config.mjs" : ".eslintrc.js";
2425
- finalConfigPath = import_path6.default.join(cwd, targetName);
2883
+ finalConfigPath = import_path7.default.join(cwd, targetName);
2426
2884
  const content2 = useFlat ? generateFlatConfig(preset) : generateLegacyConfig(preset);
2427
2885
  if (isDryRun) {
2428
- log.print(` ${import_chalk5.default.gray(`[dry-run] would create: ${targetName}`)}`);
2886
+ log.print(` ${import_chalk6.default.gray(`[dry-run] would create: ${targetName}`)}`);
2429
2887
  log.blank();
2430
- log.print(import_chalk5.default.gray("\u2500\u2500\u2500 Preview \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2888
+ log.print(import_chalk6.default.gray("\u2500\u2500\u2500 Preview \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2431
2889
  log.blank();
2432
2890
  for (const line of content2.split("\n")) {
2433
- log.print(import_chalk5.default.gray(` ${line}`));
2891
+ log.print(import_chalk6.default.gray(` ${line}`));
2434
2892
  }
2435
2893
  log.blank();
2436
2894
  } else {
2437
2895
  writeConfig(finalConfigPath, content2);
2438
- log.success(`Created ${import_chalk5.default.white(targetName)}`);
2439
- log.info(` Preset: ${import_chalk5.default.cyan(preset)}`);
2440
- log.info(` Format: ${import_chalk5.default.cyan(useFlat ? "ESLint v9 flat config (eslint.config.mjs)" : "ESLint v8 legacy config (.eslintrc.js)")}`);
2896
+ log.success(`Created ${import_chalk6.default.white(targetName)}`);
2897
+ log.info(` Preset: ${import_chalk6.default.cyan(preset)}`);
2898
+ log.info(` Format: ${import_chalk6.default.cyan(useFlat ? "ESLint v9 flat config (eslint.config.mjs)" : "ESLint v8 legacy config (.eslintrc.js)")}`);
2441
2899
  configWritten = true;
2442
2900
  }
2443
2901
  } else if (useFlat && existingIsFlat) {
@@ -2450,15 +2908,15 @@ function registerInitCommand(program2) {
2450
2908
  finalConfigPath = env.configPath;
2451
2909
  } else if (isDryRun) {
2452
2910
  finalConfigPath = env.configPath;
2453
- log.print(` ${import_chalk5.default.gray(`[dry-run] would patch: ${import_path6.default.relative(cwd, env.configPath)}`)}`);
2911
+ log.print(` ${import_chalk6.default.gray(`[dry-run] would patch: ${import_path7.default.relative(cwd, env.configPath)}`)}`);
2454
2912
  } else {
2455
2913
  const bak = backupConfig(env.configPath);
2456
- log.info(`Backed up \u2192 ${import_chalk5.default.gray(import_path6.default.relative(cwd, bak))}`);
2914
+ log.info(`Backed up \u2192 ${import_chalk6.default.gray(import_path7.default.relative(cwd, bak))}`);
2457
2915
  writeConfig(env.configPath, patched);
2458
2916
  if (isInvalid) {
2459
- log.success(`Detected invalid ai-guard config \u2014 repairing ${import_chalk5.default.white(import_path6.default.relative(cwd, env.configPath))}`);
2917
+ log.success(`Detected invalid ai-guard config \u2014 repairing ${import_chalk6.default.white(import_path7.default.relative(cwd, env.configPath))}`);
2460
2918
  } else {
2461
- log.success(`Patched ${import_chalk5.default.white(import_path6.default.relative(cwd, env.configPath))}`);
2919
+ log.success(`Patched ${import_chalk6.default.white(import_path7.default.relative(cwd, env.configPath))}`);
2462
2920
  }
2463
2921
  finalConfigPath = env.configPath;
2464
2922
  configWritten = true;
@@ -2471,12 +2929,12 @@ function registerInitCommand(program2) {
2471
2929
  finalConfigPath = env.configPath;
2472
2930
  } else if (isDryRun) {
2473
2931
  finalConfigPath = env.configPath;
2474
- log.print(` ${import_chalk5.default.gray(`[dry-run] would patch: ${import_path6.default.relative(cwd, env.configPath)}`)}`);
2932
+ log.print(` ${import_chalk6.default.gray(`[dry-run] would patch: ${import_path7.default.relative(cwd, env.configPath)}`)}`);
2475
2933
  } else {
2476
2934
  const bak = backupConfig(env.configPath);
2477
- log.info(`Backed up \u2192 ${import_chalk5.default.gray(import_path6.default.relative(cwd, bak))}`);
2935
+ log.info(`Backed up \u2192 ${import_chalk6.default.gray(import_path7.default.relative(cwd, bak))}`);
2478
2936
  writeConfig(env.configPath, patched);
2479
- log.success(`Patched ${import_chalk5.default.white(import_path6.default.relative(cwd, env.configPath))}`);
2937
+ log.success(`Patched ${import_chalk6.default.white(import_path7.default.relative(cwd, env.configPath))}`);
2480
2938
  finalConfigPath = env.configPath;
2481
2939
  configWritten = true;
2482
2940
  }
@@ -2485,18 +2943,18 @@ function registerInitCommand(program2) {
2485
2943
  const legacyConfigs = env.allConfigPaths.filter((p) => !p.includes("eslint.config."));
2486
2944
  let cleanedUp = false;
2487
2945
  for (const p of legacyConfigs) {
2488
- if (import_fs7.default.existsSync(p)) {
2946
+ if (import_fs8.default.existsSync(p)) {
2489
2947
  if (!isDryRun) {
2490
2948
  try {
2491
- import_fs7.default.renameSync(p, `${p}.bak`);
2949
+ import_fs8.default.renameSync(p, `${p}.bak`);
2492
2950
  cleanedUp = true;
2493
2951
  } catch (err) {
2494
2952
  const reason = err instanceof Error ? err.message : String(err);
2495
- log.warn(`Could not back up ${import_path6.default.relative(cwd, p)}: ${reason}`);
2953
+ log.warn(`Could not back up ${import_path7.default.relative(cwd, p)}: ${reason}`);
2496
2954
  }
2497
2955
  } else {
2498
2956
  cleanedUp = true;
2499
- log.print(` ${import_chalk5.default.gray(`[dry-run] would rename ${import_path6.default.relative(cwd, p)} to ${import_path6.default.basename(p)}.bak`)}`);
2957
+ log.print(` ${import_chalk6.default.gray(`[dry-run] would rename ${import_path7.default.relative(cwd, p)} to ${import_path7.default.basename(p)}.bak`)}`);
2500
2958
  }
2501
2959
  }
2502
2960
  }
@@ -2506,19 +2964,19 @@ function registerInitCommand(program2) {
2506
2964
  }
2507
2965
  if (isDryRun) {
2508
2966
  log.blank();
2509
- log.print(` ${import_chalk5.default.yellow("Dry run complete \u2014 no files written.")}`);
2510
- log.print(` Re-run without ${import_chalk5.default.cyan("--dry-run")} to apply.`);
2967
+ log.print(` ${import_chalk6.default.yellow("Dry run complete \u2014 no files written.")}`);
2968
+ log.print(` Re-run without ${import_chalk6.default.cyan("--dry-run")} to apply.`);
2511
2969
  log.blank();
2512
2970
  process.exit(0);
2513
2971
  return;
2514
2972
  }
2515
2973
  log.blank();
2516
2974
  log.section("Validation");
2517
- if (!import_fs7.default.existsSync(finalConfigPath)) {
2518
- log.error(`Config file not found after write: ${import_path6.default.relative(cwd, finalConfigPath)}`);
2975
+ if (!import_fs8.default.existsSync(finalConfigPath)) {
2976
+ log.error(`Config file not found after write: ${import_path7.default.relative(cwd, finalConfigPath)}`);
2519
2977
  log.blank();
2520
- log.print(` ${import_chalk5.default.bold("Problem:")} File write may have failed.`);
2521
- log.print(` ${import_chalk5.default.bold("Fix:")} Check disk space and file permissions, then re-run.`);
2978
+ log.print(` ${import_chalk6.default.bold("Problem:")} File write may have failed.`);
2979
+ log.print(` ${import_chalk6.default.bold("Fix:")} Check disk space and file permissions, then re-run.`);
2522
2980
  log.blank();
2523
2981
  process.exit(1);
2524
2982
  return;
@@ -2528,36 +2986,36 @@ function registerInitCommand(program2) {
2528
2986
  if (validationErrors.length > 0) {
2529
2987
  log.warn("Config validation found issues:");
2530
2988
  for (const e of validationErrors) {
2531
- log.print(` ${import_chalk5.default.red("\u2716")} ${e}`);
2989
+ log.print(` ${import_chalk6.default.red("\u2716")} ${e}`);
2532
2990
  }
2533
2991
  } else {
2534
- log.success(`Config structure valid: ${import_chalk5.default.white(import_path6.default.relative(cwd, finalConfigPath))}`);
2992
+ log.success(`Config structure valid: ${import_chalk6.default.white(import_path7.default.relative(cwd, finalConfigPath))}`);
2535
2993
  }
2536
2994
  log.info("Verifying ESLint can load the config\u2026");
2537
2995
  const loadError = await verifyConfigLoads(finalConfigPath, cwd);
2538
2996
  if (loadError !== null) {
2539
2997
  log.blank();
2540
2998
  if (loadError.kind === "module-not-found") {
2541
- log.warn(`Could not verify: module not found: ${import_chalk5.default.yellow(loadError.pkg)}`);
2999
+ log.warn(`Could not verify: module not found: ${import_chalk6.default.yellow(loadError.pkg)}`);
2542
3000
  log.blank();
2543
- log.print(` ${import_chalk5.default.bold("Install the missing package:")}`);
2544
- log.print(` ${import_chalk5.default.cyan(`npm install --save-dev ${loadError.pkg}`)}`);
2545
- log.print(` Then run ${import_chalk5.default.cyan("ai-guard doctor")} to confirm.`);
3001
+ log.print(` ${import_chalk6.default.bold("Install the missing package:")}`);
3002
+ log.print(` ${import_chalk6.default.cyan(`npm install --save-dev ${loadError.pkg}`)}`);
3003
+ log.print(` Then run ${import_chalk6.default.cyan("ai-guard doctor")} to confirm.`);
2546
3004
  log.blank();
2547
3005
  } else {
2548
3006
  log.error("ESLint failed to load the generated config.");
2549
3007
  log.blank();
2550
- log.print(` ${import_chalk5.default.bold("Problem:")}`);
2551
- log.print(` ${import_chalk5.default.red(loadError.message)}`);
3008
+ log.print(` ${import_chalk6.default.bold("Problem:")}`);
3009
+ log.print(` ${import_chalk6.default.red(loadError.message)}`);
2552
3010
  if (loadError.kind === "unknown") {
2553
3011
  log.blank();
2554
- log.print(` ${import_chalk5.default.yellow("Generated config may be using incorrect plugin structure.")}`);
3012
+ log.print(` ${import_chalk6.default.yellow("Generated config may be using incorrect plugin structure.")}`);
2555
3013
  }
2556
3014
  log.blank();
2557
- log.print(` ${import_chalk5.default.bold("Fix:")}`);
2558
- log.print(` 1. Check the syntax in ${import_chalk5.default.cyan(import_path6.default.relative(cwd, finalConfigPath))}`);
2559
- log.print(` 2. Make sure ${import_chalk5.default.cyan("eslint-plugin-ai-guard")} is installed`);
2560
- log.print(` 3. Run ${import_chalk5.default.cyan("ai-guard doctor")} for full diagnostics`);
3015
+ log.print(` ${import_chalk6.default.bold("Fix:")}`);
3016
+ log.print(` 1. Check the syntax in ${import_chalk6.default.cyan(import_path7.default.relative(cwd, finalConfigPath))}`);
3017
+ log.print(` 2. Make sure ${import_chalk6.default.cyan("eslint-plugin-ai-guard")} is installed`);
3018
+ log.print(` 3. Run ${import_chalk6.default.cyan("ai-guard doctor")} for full diagnostics`);
2561
3019
  log.blank();
2562
3020
  process.exit(1);
2563
3021
  return;
@@ -2571,34 +3029,34 @@ function registerInitCommand(program2) {
2571
3029
  let cleanedUpInfo = false;
2572
3030
  if (eslintNeedsFlat) {
2573
3031
  const legacyConfigs = env.allConfigPaths.filter((p) => !p.includes("eslint.config."));
2574
- cleanedUpInfo = legacyConfigs.some((p) => import_fs7.default.existsSync(`${p}.bak`) && !import_fs7.default.existsSync(p));
3032
+ cleanedUpInfo = legacyConfigs.some((p) => import_fs8.default.existsSync(`${p}.bak`) && !import_fs8.default.existsSync(p));
2575
3033
  }
2576
3034
  const lingeringConflicts = env.hasConflictingConfigs && !eslintNeedsFlat && !cleanedUpInfo;
2577
3035
  if (loadError === null && !lingeringConflicts) {
2578
- log.print(` ${import_chalk5.default.green("\u2714")} ${import_chalk5.default.bold.green("Configuration validated successfully")}`);
3036
+ log.print(` ${import_chalk6.default.green("\u2714")} ${import_chalk6.default.bold.green("Configuration validated successfully")}`);
2579
3037
  }
2580
- log.print(` ${import_chalk5.default.green("\u2714")} ${import_chalk5.default.bold("ESLint config:")} ${import_chalk5.default.cyan(import_path6.default.relative(cwd, finalConfigPath))}`);
2581
- log.print(` ${import_chalk5.default.green("\u2714")} ${import_chalk5.default.bold("Mode:")} ${import_chalk5.default.cyan(useFlat ? `Flat config (ESLint v${env.eslintMajor ?? 9})` : `Legacy config (ESLint v${env.eslintMajor ?? 8})`)}`);
2582
- log.print(` ${import_chalk5.default.green("\u2714")} ${import_chalk5.default.bold("Preset:")} ${import_chalk5.default.cyan(preset)}`);
3038
+ log.print(` ${import_chalk6.default.green("\u2714")} ${import_chalk6.default.bold("ESLint config:")} ${import_chalk6.default.cyan(import_path7.default.relative(cwd, finalConfigPath))}`);
3039
+ log.print(` ${import_chalk6.default.green("\u2714")} ${import_chalk6.default.bold("Mode:")} ${import_chalk6.default.cyan(useFlat ? `Flat config (ESLint v${env.eslintMajor ?? 9})` : `Legacy config (ESLint v${env.eslintMajor ?? 8})`)}`);
3040
+ log.print(` ${import_chalk6.default.green("\u2714")} ${import_chalk6.default.bold("Preset:")} ${import_chalk6.default.cyan(preset)}`);
2583
3041
  log.blank();
2584
- log.info(`Run ${import_chalk5.default.cyan("npx eslint .")} \u2192 lint with your editor integration`);
2585
- log.info(`Run ${import_chalk5.default.cyan("ai-guard run")} \u2192 zero-config scan`);
2586
- log.info(`Run ${import_chalk5.default.cyan("ai-guard doctor")} \u2192 verify the full setup`);
2587
- log.info(`Run ${import_chalk5.default.cyan("ai-guard baseline")} \u2192 save baseline, track only new issues`);
3042
+ log.info(`Run ${import_chalk6.default.cyan("npx eslint .")} \u2192 lint with your editor integration`);
3043
+ log.info(`Run ${import_chalk6.default.cyan("ai-guard run")} \u2192 zero-config scan`);
3044
+ log.info(`Run ${import_chalk6.default.cyan("ai-guard doctor")} \u2192 verify the full setup`);
3045
+ log.info(`Run ${import_chalk6.default.cyan("ai-guard baseline")} \u2192 save baseline, track only new issues`);
2588
3046
  log.blank();
2589
3047
  });
2590
3048
  }
2591
3049
 
2592
3050
  // cli/commands/doctor.ts
2593
- var import_chalk6 = __toESM(require("chalk"));
2594
- var import_path7 = __toESM(require("path"));
3051
+ var import_chalk7 = __toESM(require("chalk"));
3052
+ var import_path8 = __toESM(require("path"));
2595
3053
  init_config_manager();
2596
- var import_meta = {};
3054
+ var import_meta2 = {};
2597
3055
  async function probeConfigLoad(configPath, cwd) {
2598
3056
  try {
2599
3057
  const { ESLint } = await import("eslint");
2600
3058
  const eslint = new ESLint({ cwd, overrideConfigFile: configPath });
2601
- await eslint.lintText("", { filePath: import_path7.default.join(cwd, "_probe_.js") });
3059
+ await eslint.lintText("", { filePath: import_path8.default.join(cwd, "_probe_.js") });
2602
3060
  return { ok: true, error: null };
2603
3061
  } catch (err) {
2604
3062
  const msg = err instanceof Error ? err.message : String(err);
@@ -2633,7 +3091,7 @@ function registerDoctorCommand(program2) {
2633
3091
  checks.push({
2634
3092
  label: "ESLint config present",
2635
3093
  pass: hasConfig,
2636
- detail: hasConfig ? `${import_path7.default.relative(cwd, env.configPath ?? "")} (${env.configType})` : "No eslint.config.* or .eslintrc.* found",
3094
+ detail: hasConfig ? `${import_path8.default.relative(cwd, env.configPath ?? "")} (${env.configType})` : "No eslint.config.* or .eslintrc.* found",
2637
3095
  fix: hasConfig ? void 0 : "ai-guard init",
2638
3096
  note: hasConfig ? void 0 : "This will generate the correct config format for your ESLint version"
2639
3097
  });
@@ -2665,7 +3123,7 @@ function registerDoctorCommand(program2) {
2665
3123
  checks.push({
2666
3124
  label: "Plugin wired in config",
2667
3125
  pass: pluginWired && !isInvalidConfig,
2668
- detail: readError ? `Could not read config: ${readError}` : isInvalidConfig ? "Invalid ai-guard config detected (wrong export usage)" : pluginWired ? "eslint-plugin-ai-guard referenced in config" : `Config exists but ai-guard plugin not found in ${import_path7.default.relative(cwd, env.configPath)}`,
3126
+ detail: readError ? `Could not read config: ${readError}` : isInvalidConfig ? "Invalid ai-guard config detected (wrong export usage)" : pluginWired ? "eslint-plugin-ai-guard referenced in config" : `Config exists but ai-guard plugin not found in ${import_path8.default.relative(cwd, env.configPath)}`,
2669
3127
  fix: isInvalidConfig || !pluginWired && !readError ? "ai-guard init (will patch/repair your existing config)" : void 0
2670
3128
  });
2671
3129
  }
@@ -2673,7 +3131,7 @@ function registerDoctorCommand(program2) {
2673
3131
  label: "No conflicting config files",
2674
3132
  pass: !env.hasConflictingConfigs,
2675
3133
  detail: env.hasConflictingConfigs ? `Conflicting config detected:
2676
- ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}`).join("\n")}` : "Only one config format detected",
3134
+ ${env.allConfigPaths.map((p) => ` ${import_path8.default.relative(cwd, p)}`).join("\n")}` : "Only one config format detected",
2677
3135
  fix: env.hasConflictingConfigs ? "Remove or backup legacy config" : void 0,
2678
3136
  note: env.hasConflictingConfigs ? "ESLint v9 silently ignores .eslintrc.* when a flat config exists. This can cause confusion." : void 0
2679
3137
  });
@@ -2700,7 +3158,7 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2700
3158
  label: "ESLint config loads without errors",
2701
3159
  pass: probe.ok,
2702
3160
  detail: probe.ok ? "ESLint loaded config successfully" : probe.error ?? "Unknown error",
2703
- fix: probe.ok ? void 0 : `Check syntax in ${import_path7.default.relative(cwd, env.configPath)}`,
3161
+ fix: probe.ok ? void 0 : `Check syntax in ${import_path8.default.relative(cwd, env.configPath)}`,
2704
3162
  note: probe.ok ? void 0 : "Run: ai-guard init --dry-run to preview a fresh config"
2705
3163
  });
2706
3164
  }
@@ -2708,8 +3166,8 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2708
3166
  let utilsOk = false;
2709
3167
  let utilsVersion = null;
2710
3168
  try {
2711
- const { createRequire: createRequire2 } = await import("module");
2712
- const req = createRequire2(import_path7.default.join(cwd, "package.json"));
3169
+ const { createRequire: createRequire3 } = await import("module");
3170
+ const req = createRequire3(import_path8.default.join(cwd, "package.json"));
2713
3171
  const pkgPath = req.resolve("@typescript-eslint/utils/package.json");
2714
3172
  const pkg = JSON.parse(
2715
3173
  (await import("fs")).readFileSync(pkgPath, "utf-8")
@@ -2720,10 +3178,10 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2720
3178
  }
2721
3179
  if (!utilsOk) {
2722
3180
  try {
2723
- const selfDir = import_path7.default.dirname(
2724
- new URL(import_meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")
3181
+ const selfDir = import_path8.default.dirname(
3182
+ new URL(import_meta2.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")
2725
3183
  );
2726
- const pkgPath = import_path7.default.join(selfDir, "../../node_modules/@typescript-eslint/utils/package.json");
3184
+ const pkgPath = import_path8.default.join(selfDir, "../../node_modules/@typescript-eslint/utils/package.json");
2727
3185
  if ((await import("fs")).existsSync(pkgPath)) {
2728
3186
  utilsOk = true;
2729
3187
  }
@@ -2742,8 +3200,8 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2742
3200
  let parserOk = false;
2743
3201
  let parserVersion = null;
2744
3202
  try {
2745
- const { createRequire: createRequire2 } = await import("module");
2746
- const req = createRequire2(import_path7.default.join(cwd, "package.json"));
3203
+ const { createRequire: createRequire3 } = await import("module");
3204
+ const req = createRequire3(import_path8.default.join(cwd, "package.json"));
2747
3205
  const pkgPath = req.resolve("@typescript-eslint/parser/package.json");
2748
3206
  const pkg = JSON.parse(
2749
3207
  (await import("fs")).readFileSync(pkgPath, "utf-8")
@@ -2774,17 +3232,17 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2774
3232
  log.section("Diagnostics");
2775
3233
  let allPassed = true;
2776
3234
  for (const check of checks) {
2777
- const icon = check.pass ? import_chalk6.default.green("\u2714") : import_chalk6.default.red("\u2716");
2778
- const label = check.pass ? import_chalk6.default.white(check.label) : import_chalk6.default.red.bold(check.label);
3235
+ const icon = check.pass ? import_chalk7.default.green("\u2714") : import_chalk7.default.red("\u2716");
3236
+ const label = check.pass ? import_chalk7.default.white(check.label) : import_chalk7.default.red.bold(check.label);
2779
3237
  log.print(` ${icon} ${label}`);
2780
- log.print(` ${import_chalk6.default.gray(check.detail)}`);
3238
+ log.print(` ${import_chalk7.default.gray(check.detail)}`);
2781
3239
  if (!check.pass) {
2782
3240
  allPassed = false;
2783
3241
  if (check.fix) {
2784
- log.print(` ${import_chalk6.default.cyan("\u2192 Fix:")} ${import_chalk6.default.yellow(check.fix)}`);
3242
+ log.print(` ${import_chalk7.default.cyan("\u2192 Fix:")} ${import_chalk7.default.yellow(check.fix)}`);
2785
3243
  }
2786
3244
  if (check.note) {
2787
- log.print(` ${import_chalk6.default.gray(check.note)}`);
3245
+ log.print(` ${import_chalk7.default.gray(check.note)}`);
2788
3246
  }
2789
3247
  }
2790
3248
  log.blank();
@@ -2792,10 +3250,10 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2792
3250
  log.divider();
2793
3251
  log.blank();
2794
3252
  if (allPassed) {
2795
- log.print(` ${import_chalk6.default.green("\u2714")} ${import_chalk6.default.bold.green("All checks passed! Your setup is correct.")}`);
3253
+ log.print(` ${import_chalk7.default.green("\u2714")} ${import_chalk7.default.bold.green("All checks passed! Your setup is correct.")}`);
2796
3254
  log.blank();
2797
- log.info(`Run ${import_chalk6.default.cyan("ai-guard run")} to start scanning.`);
2798
- log.info(`Run ${import_chalk6.default.cyan("npx eslint .")} to lint with ESLint directly.`);
3255
+ log.info(`Run ${import_chalk7.default.cyan("ai-guard run")} to start scanning.`);
3256
+ log.info(`Run ${import_chalk7.default.cyan("npx eslint .")} to lint with ESLint directly.`);
2799
3257
  } else {
2800
3258
  log.error("Some checks failed. Follow the fixes above.");
2801
3259
  log.blank();
@@ -2810,15 +3268,15 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2810
3268
  );
2811
3269
  if (pluginMissing) {
2812
3270
  log.print(
2813
- ` Install missing packages first, then re-run ${import_chalk6.default.cyan("ai-guard doctor")}.`
3271
+ ` Install missing packages first, then re-run ${import_chalk7.default.cyan("ai-guard doctor")}.`
2814
3272
  );
2815
3273
  } else if (configMissing || configFormatMismatch) {
2816
3274
  log.print(
2817
- ` Run ${import_chalk6.default.cyan("ai-guard init")} to generate the correct config for your ESLint version.`
3275
+ ` Run ${import_chalk7.default.cyan("ai-guard init")} to generate the correct config for your ESLint version.`
2818
3276
  );
2819
3277
  } else {
2820
3278
  log.print(
2821
- ` Run ${import_chalk6.default.cyan("ai-guard init --dry-run")} to preview what would change.`
3279
+ ` Run ${import_chalk7.default.cyan("ai-guard init --dry-run")} to preview what would change.`
2822
3280
  );
2823
3281
  }
2824
3282
  }
@@ -2829,9 +3287,9 @@ ${env.allConfigPaths.map((p) => ` ${import_path7.default.relative(cwd, p)}
2829
3287
 
2830
3288
  // cli/commands/preset.ts
2831
3289
  var import_prompts = require("@inquirer/prompts");
2832
- var import_chalk7 = __toESM(require("chalk"));
3290
+ var import_chalk8 = __toESM(require("chalk"));
2833
3291
  init_config_manager();
2834
- var import_path8 = __toESM(require("path"));
3292
+ var import_path9 = __toESM(require("path"));
2835
3293
  function registerPresetCommand(program2) {
2836
3294
  program2.command("preset").description("Interactively select and apply an ai-guard preset to your ESLint config").action(async () => {
2837
3295
  const cwd = process.cwd();
@@ -2841,32 +3299,32 @@ function registerPresetCommand(program2) {
2841
3299
  message: "Choose a preset:",
2842
3300
  choices: [
2843
3301
  {
2844
- name: `${import_chalk7.default.green("recommended")} \u2014 balanced defaults, low noise. Best starting point.`,
3302
+ name: `${import_chalk8.default.green("recommended")} \u2014 balanced defaults, low noise. Best starting point.`,
2845
3303
  value: "recommended"
2846
3304
  },
2847
3305
  {
2848
- name: `${import_chalk7.default.yellow("strict")} \u2014 all rules at error. For mature codebases.`,
3306
+ name: `${import_chalk8.default.yellow("strict")} \u2014 all rules at error. For mature codebases.`,
2849
3307
  value: "strict"
2850
3308
  },
2851
3309
  {
2852
- name: `${import_chalk7.default.red("security")} \u2014 security rules only. For AppSec teams.`,
3310
+ name: `${import_chalk8.default.red("security")} \u2014 security rules only. For AppSec teams.`,
2853
3311
  value: "security"
2854
3312
  }
2855
3313
  ]
2856
3314
  });
2857
3315
  log.blank();
2858
- log.info(`Applying preset: ${import_chalk7.default.cyan(preset)}`);
3316
+ log.info(`Applying preset: ${import_chalk8.default.cyan(preset)}`);
2859
3317
  const env = detect(cwd);
2860
3318
  const useFlat = env.eslintMajor !== null && env.eslintMajor >= 9 || isFlat(env.configType);
2861
3319
  if (env.configType === "none") {
2862
- const configPath = useFlat ? import_path8.default.join(cwd, "eslint.config.mjs") : import_path8.default.join(cwd, ".eslintrc.js");
3320
+ const configPath = useFlat ? import_path9.default.join(cwd, "eslint.config.mjs") : import_path9.default.join(cwd, ".eslintrc.js");
2863
3321
  const content = useFlat ? generateFlatConfig(preset) : generateLegacyConfig(preset);
2864
3322
  writeConfig(configPath, content);
2865
- log.success(`Created ${import_chalk7.default.white(import_path8.default.relative(cwd, configPath))} with ${import_chalk7.default.cyan(preset)} preset`);
3323
+ log.success(`Created ${import_chalk8.default.white(import_path9.default.relative(cwd, configPath))} with ${import_chalk8.default.cyan(preset)} preset`);
2866
3324
  } else {
2867
3325
  const configPath = env.configPath;
2868
3326
  const backupPath = backupConfig(configPath);
2869
- log.info(`Backed up \u2192 ${import_chalk7.default.gray(import_path8.default.relative(cwd, backupPath))}`);
3327
+ log.info(`Backed up \u2192 ${import_chalk8.default.gray(import_path9.default.relative(cwd, backupPath))}`);
2870
3328
  const existing = readConfig(configPath);
2871
3329
  const withPlugin = isFlat(env.configType) ? patchFlatConfig(existing, preset) : patchLegacyConfig(existing, preset);
2872
3330
  const patched = isFlat(env.configType) ? switchFlatPreset(withPlugin, preset) : switchLegacyPreset(withPlugin, preset);
@@ -2874,47 +3332,47 @@ function registerPresetCommand(program2) {
2874
3332
  log.warn("No preset changes needed. Config already matches selected preset.");
2875
3333
  } else {
2876
3334
  writeConfig(configPath, patched);
2877
- log.success(`Updated ${import_chalk7.default.white(import_path8.default.relative(cwd, configPath))} to ${import_chalk7.default.cyan(preset)} preset`);
3335
+ log.success(`Updated ${import_chalk8.default.white(import_path9.default.relative(cwd, configPath))} to ${import_chalk8.default.cyan(preset)} preset`);
2878
3336
  }
2879
3337
  }
2880
3338
  log.blank();
2881
3339
  log.section("Preset Details");
2882
3340
  const presetDetails = {
2883
3341
  recommended: [
2884
- { rule: "no-empty-catch", level: import_chalk7.default.red("error") },
2885
- { rule: "no-floating-promise", level: import_chalk7.default.red("error") },
2886
- { rule: "no-hardcoded-secret", level: import_chalk7.default.red("error") },
2887
- { rule: "no-eval-dynamic", level: import_chalk7.default.red("error") },
2888
- { rule: "no-broad-exception", level: import_chalk7.default.yellow("warn") },
2889
- { rule: "no-async-array-callback", level: import_chalk7.default.yellow("warn") },
2890
- { rule: "no-await-in-loop", level: import_chalk7.default.yellow("warn") },
2891
- { rule: "+ 5 more\u2026", level: import_chalk7.default.gray("warn") }
3342
+ { rule: "no-empty-catch", level: import_chalk8.default.red("error") },
3343
+ { rule: "no-floating-promise", level: import_chalk8.default.red("error") },
3344
+ { rule: "no-hardcoded-secret", level: import_chalk8.default.red("error") },
3345
+ { rule: "no-eval-dynamic", level: import_chalk8.default.red("error") },
3346
+ { rule: "no-broad-exception", level: import_chalk8.default.yellow("warn") },
3347
+ { rule: "no-async-array-callback", level: import_chalk8.default.yellow("warn") },
3348
+ { rule: "no-await-in-loop", level: import_chalk8.default.yellow("warn") },
3349
+ { rule: "+ 5 more\u2026", level: import_chalk8.default.gray("warn") }
2892
3350
  ],
2893
3351
  strict: [
2894
- { rule: "All 17 rules", level: import_chalk7.default.red("error") }
3352
+ { rule: "All 17 rules", level: import_chalk8.default.red("error") }
2895
3353
  ],
2896
3354
  security: [
2897
- { rule: "no-hardcoded-secret", level: import_chalk7.default.red("error") },
2898
- { rule: "no-eval-dynamic", level: import_chalk7.default.red("error") },
2899
- { rule: "no-sql-string-concat", level: import_chalk7.default.red("error") },
2900
- { rule: "no-unsafe-deserialize", level: import_chalk7.default.yellow("warn") },
2901
- { rule: "require-auth-middleware", level: import_chalk7.default.yellow("warn") },
2902
- { rule: "require-authz-check", level: import_chalk7.default.yellow("warn") }
3355
+ { rule: "no-hardcoded-secret", level: import_chalk8.default.red("error") },
3356
+ { rule: "no-eval-dynamic", level: import_chalk8.default.red("error") },
3357
+ { rule: "no-sql-string-concat", level: import_chalk8.default.red("error") },
3358
+ { rule: "no-unsafe-deserialize", level: import_chalk8.default.yellow("warn") },
3359
+ { rule: "require-auth-middleware", level: import_chalk8.default.yellow("warn") },
3360
+ { rule: "require-authz-check", level: import_chalk8.default.yellow("warn") }
2903
3361
  ]
2904
3362
  };
2905
3363
  for (const { rule, level } of presetDetails[preset]) {
2906
- log.print(` ${import_chalk7.default.gray("\u2022")} ${import_chalk7.default.white(rule).padEnd(32)}${level}`);
3364
+ log.print(` ${import_chalk8.default.gray("\u2022")} ${import_chalk8.default.white(rule).padEnd(32)}${level}`);
2907
3365
  }
2908
3366
  log.blank();
2909
- log.info(`Run ${import_chalk7.default.cyan("ai-guard run")} to see results with the new preset.`);
3367
+ log.info(`Run ${import_chalk8.default.cyan("ai-guard run")} to see results with the new preset.`);
2910
3368
  log.blank();
2911
3369
  });
2912
3370
  }
2913
3371
 
2914
3372
  // cli/commands/ignore.ts
2915
- var import_chalk8 = __toESM(require("chalk"));
3373
+ var import_chalk9 = __toESM(require("chalk"));
2916
3374
  init_config_manager();
2917
- var import_path9 = __toESM(require("path"));
3375
+ var import_path10 = __toESM(require("path"));
2918
3376
  var DEFAULT_IGNORES = [
2919
3377
  ".next/",
2920
3378
  "dist/",
@@ -2930,40 +3388,40 @@ function registerIgnoreCommand(program2) {
2930
3388
  log.blank();
2931
3389
  log.section("Default Ignores");
2932
3390
  for (const p of DEFAULT_IGNORES) {
2933
- log.print(` ${import_chalk8.default.gray("\u2022")} ${import_chalk8.default.yellow(p)}`);
3391
+ log.print(` ${import_chalk9.default.gray("\u2022")} ${import_chalk9.default.yellow(p)}`);
2934
3392
  }
2935
3393
  log.blank();
2936
3394
  const env = detect(cwd);
2937
3395
  if (env.configType === "none") {
2938
3396
  const useFlat = env.eslintMajor !== null && env.eslintMajor >= 9;
2939
- const configPath = useFlat ? import_path9.default.join(cwd, "eslint.config.mjs") : import_path9.default.join(cwd, ".eslintrc.js");
3397
+ const configPath = useFlat ? import_path10.default.join(cwd, "eslint.config.mjs") : import_path10.default.join(cwd, ".eslintrc.js");
2940
3398
  const content = useFlat ? generateFlatConfig("recommended") : generateLegacyConfig("recommended");
2941
3399
  writeConfig(configPath, content);
2942
- log.success(`No config found \u2014 generated ${import_chalk8.default.white(import_path9.default.relative(cwd, configPath))} with ignores included`);
3400
+ log.success(`No config found \u2014 generated ${import_chalk9.default.white(import_path10.default.relative(cwd, configPath))} with ignores included`);
2943
3401
  } else {
2944
3402
  const configPath = env.configPath;
2945
3403
  const backupPath = backupConfig(configPath);
2946
- log.info(`Backed up \u2192 ${import_chalk8.default.gray(import_path9.default.relative(cwd, backupPath))}`);
3404
+ log.info(`Backed up \u2192 ${import_chalk9.default.gray(import_path10.default.relative(cwd, backupPath))}`);
2947
3405
  const existing = readConfig(configPath);
2948
3406
  const patched = isFlat(env.configType) ? addIgnoresToFlatConfig(existing) : addIgnoresToLegacyConfig(existing);
2949
3407
  if (patched === existing) {
2950
3408
  log.warn("Ignore patterns already present in config \u2014 no changes made.");
2951
3409
  } else {
2952
3410
  writeConfig(configPath, patched);
2953
- log.success(`Patched ${import_chalk8.default.white(import_path9.default.relative(cwd, configPath))} with ignore patterns`);
3411
+ log.success(`Patched ${import_chalk9.default.white(import_path10.default.relative(cwd, configPath))} with ignore patterns`);
2954
3412
  }
2955
3413
  }
2956
3414
  log.blank();
2957
3415
  log.info("Noisy directories will now be skipped in all future ESLint runs.");
2958
- log.info(`Run ${import_chalk8.default.cyan("ai-guard run")} to verify cleaner results.`);
3416
+ log.info(`Run ${import_chalk9.default.cyan("ai-guard run")} to verify cleaner results.`);
2959
3417
  log.blank();
2960
3418
  });
2961
3419
  }
2962
3420
 
2963
3421
  // cli/commands/baseline.ts
2964
- var import_fs8 = __toESM(require("fs"));
2965
- var import_path10 = __toESM(require("path"));
2966
- var import_chalk9 = __toESM(require("chalk"));
3422
+ var import_fs9 = __toESM(require("fs"));
3423
+ var import_path11 = __toESM(require("path"));
3424
+ var import_chalk10 = __toESM(require("chalk"));
2967
3425
  var import_ora3 = __toESM(require("ora"));
2968
3426
  var BASELINE_FILE = ".ai-guard-baseline.json";
2969
3427
  function saveBaseline(result, preset, mode, cwd) {
@@ -2983,15 +3441,15 @@ function saveBaseline(result, preset, mode, cwd) {
2983
3441
  totalIssues: result.totalIssues,
2984
3442
  entries
2985
3443
  };
2986
- const baselinePath = import_path10.default.join(cwd, BASELINE_FILE);
2987
- import_fs8.default.writeFileSync(baselinePath, JSON.stringify(baseline, null, 2), "utf-8");
3444
+ const baselinePath = import_path11.default.join(cwd, BASELINE_FILE);
3445
+ import_fs9.default.writeFileSync(baselinePath, JSON.stringify(baseline, null, 2), "utf-8");
2988
3446
  return baselinePath;
2989
3447
  }
2990
3448
  function loadBaseline(cwd) {
2991
- const baselinePath = import_path10.default.join(cwd, BASELINE_FILE);
2992
- if (!import_fs8.default.existsSync(baselinePath)) return null;
3449
+ const baselinePath = import_path11.default.join(cwd, BASELINE_FILE);
3450
+ if (!import_fs9.default.existsSync(baselinePath)) return null;
2993
3451
  try {
2994
- const raw = import_fs8.default.readFileSync(baselinePath, "utf-8");
3452
+ const raw = import_fs9.default.readFileSync(baselinePath, "utf-8");
2995
3453
  return JSON.parse(raw);
2996
3454
  } catch {
2997
3455
  return null;
@@ -3075,28 +3533,28 @@ function registerBaselineCommand(program2) {
3075
3533
  }
3076
3534
  const baselinePath = saveBaseline(result, preset, mode, cwd);
3077
3535
  log.success(
3078
- `Baseline saved \u2192 ${import_chalk9.default.white(import_path10.default.relative(cwd, baselinePath))}`
3536
+ `Baseline saved \u2192 ${import_chalk10.default.white(import_path11.default.relative(cwd, baselinePath))}`
3079
3537
  );
3080
3538
  log.info(` ${result.totalIssues} issues recorded (${result.totalErrors} errors, ${result.totalWarnings} warnings)`);
3081
- log.info(` Preset: ${import_chalk9.default.cyan(preset)}`);
3082
- log.info(` Mode: ${import_chalk9.default.cyan(mode)}`);
3539
+ log.info(` Preset: ${import_chalk10.default.cyan(preset)}`);
3540
+ log.info(` Mode: ${import_chalk10.default.cyan(mode)}`);
3083
3541
  log.blank();
3084
- log.info("Future runs of " + import_chalk9.default.cyan("ai-guard baseline --check") + " will show only NEW issues.");
3085
- log.info("Add " + import_chalk9.default.white(BASELINE_FILE) + " to your git repository to share baseline with your team.");
3542
+ log.info("Future runs of " + import_chalk10.default.cyan("ai-guard baseline --check") + " will show only NEW issues.");
3543
+ log.info("Add " + import_chalk10.default.white(BASELINE_FILE) + " to your git repository to share baseline with your team.");
3086
3544
  log.blank();
3087
3545
  return;
3088
3546
  }
3089
3547
  if (doCheck) {
3090
3548
  if (!existingBaseline) {
3091
- log.error(`No baseline found at ${import_chalk9.default.white(BASELINE_FILE)}`);
3092
- log.info(`Run ${import_chalk9.default.cyan("ai-guard baseline --save")} first to create one.`);
3549
+ log.error(`No baseline found at ${import_chalk10.default.white(BASELINE_FILE)}`);
3550
+ log.info(`Run ${import_chalk10.default.cyan("ai-guard baseline --save")} first to create one.`);
3093
3551
  process.exit(1);
3094
3552
  }
3095
3553
  const baselineDate = new Date(existingBaseline.createdAt).toLocaleString();
3096
- log.info(`Baseline from: ${import_chalk9.default.gray(baselineDate)}`);
3097
- log.info(`Baseline preset: ${import_chalk9.default.cyan(existingBaseline.preset)}`);
3098
- log.info(`Baseline mode: ${import_chalk9.default.cyan(existingBaseline.mode ?? "strict")}`);
3099
- log.info(`Baseline issues: ${import_chalk9.default.gray(existingBaseline.totalIssues)}`);
3554
+ log.info(`Baseline from: ${import_chalk10.default.gray(baselineDate)}`);
3555
+ log.info(`Baseline preset: ${import_chalk10.default.cyan(existingBaseline.preset)}`);
3556
+ log.info(`Baseline mode: ${import_chalk10.default.cyan(existingBaseline.mode ?? "strict")}`);
3557
+ log.info(`Baseline issues: ${import_chalk10.default.gray(existingBaseline.totalIssues)}`);
3100
3558
  log.blank();
3101
3559
  const spinner = (0, import_ora3.default)({ text: "Scanning for new issues\u2026", color: "cyan" }).start();
3102
3560
  let result;
@@ -3121,7 +3579,7 @@ function registerBaselineCommand(program2) {
3121
3579
  return;
3122
3580
  }
3123
3581
  log.print(
3124
- import_chalk9.default.bold.red(` \u2716 ${newResult.totalIssues} new issue${newResult.totalIssues !== 1 ? "s" : ""} since baseline`)
3582
+ import_chalk10.default.bold.red(` \u2716 ${newResult.totalIssues} new issue${newResult.totalIssues !== 1 ? "s" : ""} since baseline`)
3125
3583
  );
3126
3584
  log.blank();
3127
3585
  if (newResult.ruleBreakdown.size > 0) {
@@ -3137,7 +3595,7 @@ function registerBaselineCommand(program2) {
3137
3595
  log.blank();
3138
3596
  for (const file of newResult.files) {
3139
3597
  log.print(
3140
- ` ${import_chalk9.default.bold.white(file.filePath)} ` + import_chalk9.default.gray(`(${file.issues.length} new)`)
3598
+ ` ${import_chalk10.default.bold.white(file.filePath)} ` + import_chalk10.default.gray(`(${file.issues.length} new)`)
3141
3599
  );
3142
3600
  for (const issue of file.issues) {
3143
3601
  log.issue(issue.message, issue.severity, issue.line, issue.column);
@@ -3150,7 +3608,7 @@ function registerBaselineCommand(program2) {
3150
3608
  log.error(
3151
3609
  `${newResult.totalIssues} new issue${newResult.totalIssues !== 1 ? "s" : ""} introduced since baseline.`
3152
3610
  );
3153
- log.info(`Run ${import_chalk9.default.cyan("ai-guard baseline --save")} to update the baseline after fixing them.`);
3611
+ log.info(`Run ${import_chalk10.default.cyan("ai-guard baseline --save")} to update the baseline after fixing them.`);
3154
3612
  log.blank();
3155
3613
  process.exit(1);
3156
3614
  }
@@ -3158,9 +3616,9 @@ function registerBaselineCommand(program2) {
3158
3616
  }
3159
3617
 
3160
3618
  // cli/commands/init-context.ts
3161
- var import_fs9 = __toESM(require("fs"));
3162
- var import_path11 = __toESM(require("path"));
3163
- var import_chalk10 = __toESM(require("chalk"));
3619
+ var import_fs10 = __toESM(require("fs"));
3620
+ var import_path12 = __toESM(require("path"));
3621
+ var import_chalk11 = __toESM(require("chalk"));
3164
3622
  var import_prompts2 = require("@inquirer/prompts");
3165
3623
  var RULE_CATEGORIES = {
3166
3624
  "error-handling": [
@@ -3523,23 +3981,23 @@ var AGENTS = [
3523
3981
  {
3524
3982
  id: "copilot",
3525
3983
  label: "GitHub Copilot",
3526
- filePath: import_path11.default.join(".github", "copilot-instructions.md"),
3984
+ filePath: import_path12.default.join(".github", "copilot-instructions.md"),
3527
3985
  generate: generateCopilotFile
3528
3986
  }
3529
3987
  ];
3530
3988
  function getPackageVersion2(cwd) {
3531
3989
  try {
3532
- const pkgPath = import_path11.default.join(cwd, "node_modules", "eslint-plugin-ai-guard", "package.json");
3533
- if (import_fs9.default.existsSync(pkgPath)) {
3534
- const pkg = JSON.parse(import_fs9.default.readFileSync(pkgPath, "utf-8"));
3990
+ const pkgPath = import_path12.default.join(cwd, "node_modules", "eslint-plugin-ai-guard", "package.json");
3991
+ if (import_fs10.default.existsSync(pkgPath)) {
3992
+ const pkg = JSON.parse(import_fs10.default.readFileSync(pkgPath, "utf-8"));
3535
3993
  if (pkg.version) return pkg.version;
3536
3994
  }
3537
3995
  } catch {
3538
3996
  }
3539
3997
  try {
3540
- const pkgPath = import_path11.default.join(cwd, "package.json");
3541
- if (import_fs9.default.existsSync(pkgPath)) {
3542
- const pkg = JSON.parse(import_fs9.default.readFileSync(pkgPath, "utf-8"));
3998
+ const pkgPath = import_path12.default.join(cwd, "package.json");
3999
+ if (import_fs10.default.existsSync(pkgPath)) {
4000
+ const pkg = JSON.parse(import_fs10.default.readFileSync(pkgPath, "utf-8"));
3543
4001
  if (pkg.version) return pkg.version;
3544
4002
  }
3545
4003
  } catch {
@@ -3568,7 +4026,7 @@ function registerInitContextCommand(program2) {
3568
4026
  const isForce = opts.force === true;
3569
4027
  log.banner("AI GUARD INIT-CONTEXT");
3570
4028
  if (isDryRun) {
3571
- log.print(` ${import_chalk10.default.yellow("\u2691 DRY RUN \u2014 no files will be written")}`);
4029
+ log.print(` ${import_chalk11.default.yellow("\u2691 DRY RUN \u2014 no files will be written")}`);
3572
4030
  log.blank();
3573
4031
  }
3574
4032
  let selectedAgents;
@@ -3601,13 +4059,13 @@ function registerInitContextCommand(program2) {
3601
4059
  selectedAgents = AGENTS.filter((a) => selected.includes(a.id));
3602
4060
  }
3603
4061
  }
3604
- log.info(`Categories: ${import_chalk10.default.cyan(categories.join(", "))}`);
3605
- log.info(`Version: ${import_chalk10.default.cyan(version)}`);
4062
+ log.info(`Categories: ${import_chalk11.default.cyan(categories.join(", "))}`);
4063
+ log.info(`Version: ${import_chalk11.default.cyan(version)}`);
3606
4064
  log.blank();
3607
4065
  const results = [];
3608
4066
  for (const agent of selectedAgents) {
3609
- const fullPath = import_path11.default.join(cwd, agent.filePath);
3610
- const exists = import_fs9.default.existsSync(fullPath);
4067
+ const fullPath = import_path12.default.join(cwd, agent.filePath);
4068
+ const exists = import_fs10.default.existsSync(fullPath);
3611
4069
  if (exists && !isForce && !isDryRun) {
3612
4070
  const overwrite = await (0, import_prompts2.confirm)({
3613
4071
  message: `${agent.filePath} already exists. Overwrite?`,
@@ -3621,41 +4079,41 @@ function registerInitContextCommand(program2) {
3621
4079
  const content = agent.generate(version, categories);
3622
4080
  if (isDryRun) {
3623
4081
  log.section(`Preview: ${agent.filePath}`);
3624
- log.print(import_chalk10.default.gray("\u2500".repeat(60)));
4082
+ log.print(import_chalk11.default.gray("\u2500".repeat(60)));
3625
4083
  for (const line of content.split("\n").slice(0, 20)) {
3626
- log.print(import_chalk10.default.gray(` ${line}`));
4084
+ log.print(import_chalk11.default.gray(` ${line}`));
3627
4085
  }
3628
- log.print(import_chalk10.default.gray(" ... (truncated)"));
3629
- log.print(import_chalk10.default.gray("\u2500".repeat(60)));
4086
+ log.print(import_chalk11.default.gray(" ... (truncated)"));
4087
+ log.print(import_chalk11.default.gray("\u2500".repeat(60)));
3630
4088
  log.blank();
3631
4089
  results.push({ file: agent.filePath, status: "dry-run" });
3632
4090
  continue;
3633
4091
  }
3634
- const parentDir = import_path11.default.dirname(fullPath);
3635
- if (!import_fs9.default.existsSync(parentDir)) {
3636
- import_fs9.default.mkdirSync(parentDir, { recursive: true });
4092
+ const parentDir = import_path12.default.dirname(fullPath);
4093
+ if (!import_fs10.default.existsSync(parentDir)) {
4094
+ import_fs10.default.mkdirSync(parentDir, { recursive: true });
3637
4095
  }
3638
- import_fs9.default.writeFileSync(fullPath, content, "utf-8");
4096
+ import_fs10.default.writeFileSync(fullPath, content, "utf-8");
3639
4097
  results.push({ file: agent.filePath, status: "created" });
3640
4098
  }
3641
4099
  log.section("Summary");
3642
4100
  for (const result of results) {
3643
4101
  switch (result.status) {
3644
4102
  case "created":
3645
- log.print(` ${import_chalk10.default.green("\u2705")} Created ${import_chalk10.default.white(result.file)}`);
4103
+ log.print(` ${import_chalk11.default.green("\u2705")} Created ${import_chalk11.default.white(result.file)}`);
3646
4104
  break;
3647
4105
  case "skipped":
3648
- log.print(` ${import_chalk10.default.yellow("\u23ED")} Skipped ${import_chalk10.default.white(result.file)} ${import_chalk10.default.gray("(already exists \u2014 use --force to overwrite)")}`);
4106
+ log.print(` ${import_chalk11.default.yellow("\u23ED")} Skipped ${import_chalk11.default.white(result.file)} ${import_chalk11.default.gray("(already exists \u2014 use --force to overwrite)")}`);
3649
4107
  break;
3650
4108
  case "dry-run":
3651
- log.print(` ${import_chalk10.default.cyan("\u{1F4DD}")} Would create ${import_chalk10.default.white(result.file)}`);
4109
+ log.print(` ${import_chalk11.default.cyan("\u{1F4DD}")} Would create ${import_chalk11.default.white(result.file)}`);
3652
4110
  break;
3653
4111
  }
3654
4112
  }
3655
4113
  log.blank();
3656
4114
  if (isDryRun) {
3657
4115
  log.info("Dry run complete \u2014 no files were written.");
3658
- log.info(`Re-run without ${import_chalk10.default.cyan("--dry-run")} to apply.`);
4116
+ log.info(`Re-run without ${import_chalk11.default.cyan("--dry-run")} to apply.`);
3659
4117
  } else {
3660
4118
  const createdCount = results.filter((r) => r.status === "created").length;
3661
4119
  if (createdCount > 0) {
@@ -3669,8 +4127,8 @@ function registerInitContextCommand(program2) {
3669
4127
  }
3670
4128
 
3671
4129
  // cli/commands/report.ts
3672
- var import_fs10 = __toESM(require("fs"));
3673
- var import_path12 = __toESM(require("path"));
4130
+ var import_fs11 = __toESM(require("fs"));
4131
+ var import_path13 = __toESM(require("path"));
3674
4132
  var import_ora4 = __toESM(require("ora"));
3675
4133
  var RULE_META = {
3676
4134
  "ai-guard/no-empty-catch": { description: "Empty catch blocks silently swallow errors", category: "Reliability" },
@@ -3694,28 +4152,28 @@ var RULE_META = {
3694
4152
  };
3695
4153
  function getProjectName(cwd) {
3696
4154
  try {
3697
- const pkgPath = import_path12.default.join(cwd, "package.json");
3698
- if (import_fs10.default.existsSync(pkgPath)) {
3699
- const pkg = JSON.parse(import_fs10.default.readFileSync(pkgPath, "utf-8"));
4155
+ const pkgPath = import_path13.default.join(cwd, "package.json");
4156
+ if (import_fs11.default.existsSync(pkgPath)) {
4157
+ const pkg = JSON.parse(import_fs11.default.readFileSync(pkgPath, "utf-8"));
3700
4158
  if (pkg.name) return pkg.name;
3701
4159
  }
3702
4160
  } catch {
3703
4161
  }
3704
- return import_path12.default.basename(cwd);
4162
+ return import_path13.default.basename(cwd);
3705
4163
  }
3706
4164
  function getPluginVersion(cwd) {
3707
4165
  try {
3708
- const pkgPath = import_path12.default.resolve(__dirname, "../../package.json");
3709
- if (import_fs10.default.existsSync(pkgPath)) {
3710
- const pkg = JSON.parse(import_fs10.default.readFileSync(pkgPath, "utf-8"));
4166
+ const pkgPath = import_path13.default.resolve(__dirname, "../../package.json");
4167
+ if (import_fs11.default.existsSync(pkgPath)) {
4168
+ const pkg = JSON.parse(import_fs11.default.readFileSync(pkgPath, "utf-8"));
3711
4169
  if (pkg.version) return pkg.version;
3712
4170
  }
3713
4171
  } catch {
3714
4172
  }
3715
4173
  try {
3716
- const pkgPath = import_path12.default.join(cwd, "node_modules", "eslint-plugin-ai-guard", "package.json");
3717
- if (import_fs10.default.existsSync(pkgPath)) {
3718
- const pkg = JSON.parse(import_fs10.default.readFileSync(pkgPath, "utf-8"));
4174
+ const pkgPath = import_path13.default.join(cwd, "node_modules", "eslint-plugin-ai-guard", "package.json");
4175
+ if (import_fs11.default.existsSync(pkgPath)) {
4176
+ const pkg = JSON.parse(import_fs11.default.readFileSync(pkgPath, "utf-8"));
3719
4177
  if (pkg.version) return pkg.version;
3720
4178
  }
3721
4179
  } catch {
@@ -4092,8 +4550,8 @@ function registerReportCommand(program2) {
4092
4550
  log.banner("AI GUARD REPORT");
4093
4551
  log.blank();
4094
4552
  const html = generateHtml(reportData);
4095
- const outputPath = import_path12.default.resolve(cwd, opts.output);
4096
- import_fs10.default.writeFileSync(outputPath, html, "utf-8");
4553
+ const outputPath = import_path13.default.resolve(cwd, opts.output);
4554
+ import_fs11.default.writeFileSync(outputPath, html, "utf-8");
4097
4555
  log.success(`Report saved: ${opts.output}`);
4098
4556
  log.info(
4099
4557
  `Score: ${reportData.score}/100 \xB7 ${reportData.totalErrors} errors \xB7 ${reportData.totalWarnings} warnings`
@@ -4126,8 +4584,8 @@ function registerReportCommand(program2) {
4126
4584
  // cli/index.ts
4127
4585
  function getVersion() {
4128
4586
  try {
4129
- const pkgPath = import_path13.default.resolve(__dirname, "../../package.json");
4130
- const raw = import_fs11.default.readFileSync(pkgPath, "utf-8");
4587
+ const pkgPath = import_path14.default.resolve(__dirname, "../../package.json");
4588
+ const raw = import_fs12.default.readFileSync(pkgPath, "utf-8");
4131
4589
  const pkg = JSON.parse(raw);
4132
4590
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
4133
4591
  } catch {