commit-cop 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +69 -7
  2. package/dist/brand.d.ts +4 -0
  3. package/dist/brand.d.ts.map +1 -0
  4. package/dist/brand.js +4 -0
  5. package/dist/brand.js.map +1 -0
  6. package/dist/checks/binaryFileCheck.js +2 -2
  7. package/dist/checks/binaryFileCheck.js.map +1 -1
  8. package/dist/checks/consoleLogCheck.d.ts.map +1 -1
  9. package/dist/checks/consoleLogCheck.js +2 -2
  10. package/dist/checks/consoleLogCheck.js.map +1 -1
  11. package/dist/checks/debuggerCheck.d.ts.map +1 -1
  12. package/dist/checks/debuggerCheck.js +2 -2
  13. package/dist/checks/debuggerCheck.js.map +1 -1
  14. package/dist/checks/envFileCheck.d.ts.map +1 -1
  15. package/dist/checks/envFileCheck.js +2 -2
  16. package/dist/checks/envFileCheck.js.map +1 -1
  17. package/dist/checks/focusedTestCheck.js +2 -2
  18. package/dist/checks/focusedTestCheck.js.map +1 -1
  19. package/dist/checks/generatedFolderCheck.js +2 -2
  20. package/dist/checks/generatedFolderCheck.js.map +1 -1
  21. package/dist/checks/junkFileCheck.d.ts.map +1 -1
  22. package/dist/checks/junkFileCheck.js +2 -2
  23. package/dist/checks/junkFileCheck.js.map +1 -1
  24. package/dist/checks/largeFileCheck.js +2 -2
  25. package/dist/checks/largeFileCheck.js.map +1 -1
  26. package/dist/checks/localHostCheck.js +2 -2
  27. package/dist/checks/localHostCheck.js.map +1 -1
  28. package/dist/checks/lockfileDriftCheck.d.ts.map +1 -1
  29. package/dist/checks/lockfileDriftCheck.js +4 -4
  30. package/dist/checks/lockfileDriftCheck.js.map +1 -1
  31. package/dist/checks/mergeConflictCheck.d.ts.map +1 -1
  32. package/dist/checks/mergeConflictCheck.js +2 -2
  33. package/dist/checks/mergeConflictCheck.js.map +1 -1
  34. package/dist/checks/secretCheck.js +19 -19
  35. package/dist/checks/secretCheck.js.map +1 -1
  36. package/dist/checks/sensitiveFilenameCheck.d.ts.map +1 -1
  37. package/dist/checks/sensitiveFilenameCheck.js +2 -2
  38. package/dist/checks/sensitiveFilenameCheck.js.map +1 -1
  39. package/dist/fix/debugCode.d.ts +3 -0
  40. package/dist/fix/debugCode.d.ts.map +1 -0
  41. package/dist/fix/debugCode.js +55 -0
  42. package/dist/fix/debugCode.js.map +1 -0
  43. package/dist/fix/focusedTests.d.ts +2 -0
  44. package/dist/fix/focusedTests.d.ts.map +1 -0
  45. package/dist/fix/focusedTests.js +22 -0
  46. package/dist/fix/focusedTests.js.map +1 -0
  47. package/dist/fix/gitignore.d.ts +2 -0
  48. package/dist/fix/gitignore.d.ts.map +1 -0
  49. package/dist/fix/gitignore.js +82 -0
  50. package/dist/fix/gitignore.js.map +1 -0
  51. package/dist/fix/junkFiles.d.ts +2 -0
  52. package/dist/fix/junkFiles.d.ts.map +1 -0
  53. package/dist/fix/junkFiles.js +14 -0
  54. package/dist/fix/junkFiles.js.map +1 -0
  55. package/dist/fix/lockfile.d.ts +2 -0
  56. package/dist/fix/lockfile.d.ts.map +1 -0
  57. package/dist/fix/lockfile.js +18 -0
  58. package/dist/fix/lockfile.js.map +1 -0
  59. package/dist/fix/matchers.d.ts +9 -0
  60. package/dist/fix/matchers.d.ts.map +1 -0
  61. package/dist/fix/matchers.js +118 -0
  62. package/dist/fix/matchers.js.map +1 -0
  63. package/dist/fix/runFix.d.ts +3 -0
  64. package/dist/fix/runFix.d.ts.map +1 -0
  65. package/dist/fix/runFix.js +82 -0
  66. package/dist/fix/runFix.js.map +1 -0
  67. package/dist/fix/unstage.d.ts +2 -0
  68. package/dist/fix/unstage.d.ts.map +1 -0
  69. package/dist/fix/unstage.js +22 -0
  70. package/dist/fix/unstage.js.map +1 -0
  71. package/dist/fix/utils.d.ts +4 -0
  72. package/dist/fix/utils.d.ts.map +1 -0
  73. package/dist/fix/utils.js +39 -0
  74. package/dist/fix/utils.js.map +1 -0
  75. package/dist/git.d.ts.map +1 -1
  76. package/dist/git.js +2 -1
  77. package/dist/git.js.map +1 -1
  78. package/dist/hook.d.ts +3 -0
  79. package/dist/hook.d.ts.map +1 -0
  80. package/dist/hook.js +79 -0
  81. package/dist/hook.js.map +1 -0
  82. package/dist/index.js +32 -21
  83. package/dist/index.js.map +1 -1
  84. package/dist/reporter.d.ts.map +1 -1
  85. package/dist/reporter.js +56 -26
  86. package/dist/reporter.js.map +1 -1
  87. package/dist/runScan.d.ts +2 -0
  88. package/dist/runScan.d.ts.map +1 -0
  89. package/dist/runScan.js +24 -0
  90. package/dist/runScan.js.map +1 -0
  91. package/dist/scanner.d.ts.map +1 -1
  92. package/dist/scanner.js +4 -1
  93. package/dist/scanner.js.map +1 -1
  94. package/dist/types.d.ts +4 -0
  95. package/dist/types.d.ts.map +1 -1
  96. package/package.json +4 -3
  97. package/src/brand.ts +3 -0
  98. package/src/checks/binaryFileCheck.ts +3 -3
  99. package/src/checks/consoleLogCheck.ts +3 -2
  100. package/src/checks/debuggerCheck.ts +3 -2
  101. package/src/checks/envFileCheck.ts +3 -2
  102. package/src/checks/focusedTestCheck.ts +2 -2
  103. package/src/checks/generatedFolderCheck.ts +2 -2
  104. package/src/checks/junkFileCheck.ts +3 -2
  105. package/src/checks/largeFileCheck.ts +2 -2
  106. package/src/checks/localHostCheck.ts +2 -2
  107. package/src/checks/lockfileDriftCheck.ts +6 -4
  108. package/src/checks/mergeConflictCheck.ts +3 -2
  109. package/src/checks/secretCheck.ts +19 -19
  110. package/src/checks/sensitiveFilenameCheck.ts +3 -2
  111. package/src/fix/debugCode.ts +74 -0
  112. package/src/fix/focusedTests.ts +26 -0
  113. package/src/fix/gitignore.ts +108 -0
  114. package/src/fix/junkFiles.ts +16 -0
  115. package/src/fix/lockfile.ts +23 -0
  116. package/src/fix/matchers.ts +141 -0
  117. package/src/fix/runFix.ts +96 -0
  118. package/src/fix/unstage.ts +25 -0
  119. package/src/fix/utils.ts +50 -0
  120. package/src/git.ts +2 -1
  121. package/src/hook.ts +98 -0
  122. package/src/index.ts +45 -27
  123. package/src/reporter.ts +70 -30
  124. package/src/runScan.ts +35 -0
  125. package/src/scanner.ts +4 -1
  126. package/src/types.ts +5 -0
  127. package/test.ts +5 -1
  128. package/testing.ts +3 -0
package/dist/index.js CHANGED
@@ -1,30 +1,41 @@
1
1
  #!/usr/bin/env node
2
+ import { CLI_NAME, PRODUCT_NAME, TAGLINE } from "./brand.js";
2
3
  import { Command } from "commander";
3
- import { getStagedFiles } from "./git.js";
4
- import { runChecks } from "./scanner.js";
5
- import { printReport } from "./reporter.js";
4
+ import { runWipFix } from "./fix/runFix.js";
5
+ import { installHook, uninstallHook } from "./hook.js";
6
+ import { runScan } from "./runScan.js";
6
7
  const program = new Command();
7
8
  program
8
- .name("commit-cop")
9
- .description("Pre-commit safety checker for staged files")
9
+ .name(CLI_NAME)
10
+ .description(`${PRODUCT_NAME} ${TAGLINE}`);
11
+ program
12
+ .command("scan", { isDefault: true })
13
+ .description("Scan staged files for risky commits")
10
14
  .option("--strict", "Treat warnings as errors")
15
+ .option("--allow-console-log", "Skip console.log warnings (for projects that keep console.log on purpose)")
11
16
  .action(async (options) => {
12
- const stagedFiles = getStagedFiles();
13
- if (stagedFiles.length === 0) {
14
- console.log("No staged files found.");
15
- return;
16
- }
17
- const findings = await runChecks({
18
- stagedFiles,
19
- strict: Boolean(options.strict),
20
- });
21
- printReport(findings, stagedFiles.length);
22
- const hasErrors = findings.some((finding) => finding.severity === "error");
23
- const hasWarnings = findings.some((finding) => finding.severity === "warning");
24
- if (hasErrors || (options.strict && hasWarnings)) {
25
- process.exit(1);
26
- }
27
- process.exit(0);
17
+ const exitCode = await runScan(Boolean(options.strict), Boolean(options.allowConsoleLog));
18
+ process.exit(exitCode);
19
+ });
20
+ program
21
+ .command("wip-fix")
22
+ .description("Apply common repo fixes matching commit-cop checks (.gitignore, debug code, unstaging, etc.)")
23
+ .option("--fix-console-log", "Also remove standalone console.log lines from staged files (debugger lines are always removed)")
24
+ .action((options) => {
25
+ runWipFix({ fixConsoleLog: Boolean(options.fixConsoleLog) });
26
+ });
27
+ program
28
+ .command("install")
29
+ .description("Install a Git pre-commit hook that runs Commit Cop on every commit")
30
+ .option("--strict", "Treat warnings as errors in the hook")
31
+ .action((options) => {
32
+ installHook(Boolean(options.strict));
33
+ });
34
+ program
35
+ .command("uninstall")
36
+ .description("Remove the Commit Cop pre-commit hook")
37
+ .action(() => {
38
+ uninstallHook();
28
39
  });
29
40
  program.parse();
30
41
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;QAC/B,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;KAChC,CAAC,CAAC;IAEH,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAC/B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAC5C,CAAC;IAEF,IAAI,SAAS,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,GAAG,YAAY,MAAM,OAAO,EAAE,CAAC,CAAC;AAE/C,OAAO;KACJ,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACpC,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CACL,qBAAqB,EACrB,2EAA2E,CAC5E;KACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EACvB,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CACjC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CACV,8FAA8F,CAC/F;KACA,MAAM,CACL,mBAAmB,EACnB,gGAAgG,CACjG;KACA,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,SAAS,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,oEAAoE,CAAC;KACjF,MAAM,CAAC,UAAU,EAAE,sCAAsC,CAAC;KAC1D,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,GAAG,EAAE;IACX,aAAa,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,QA+BpE"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,YAAY,CAAC;AAyDpD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,QA4BpE"}
package/dist/reporter.js CHANGED
@@ -1,38 +1,68 @@
1
+ import { PRODUCT_NAME } from "./brand.js";
1
2
  import chalk from "chalk";
2
- export function printReport(findings, scannedCount) {
3
- console.log(chalk.bold("\nCommitClean Report\n"));
4
- console.log(`Scanned ${scannedCount} staged file(s).\n`);
5
- const errors = findings.filter((f) => f.severity === "error");
6
- const warnings = findings.filter((f) => f.severity === "warning");
7
- console.log(chalk.red(`Errors: ${errors.length}`));
8
- console.log(chalk.yellow(`Warnings: ${warnings.length}`));
3
+ const WIDTH = 52;
4
+ function line(char = "─") {
5
+ return chalk.dim(char.repeat(WIDTH));
6
+ }
7
+ function printHeader(title) {
8
+ console.log("");
9
+ console.log(line("═"));
10
+ console.log(chalk.bold(` ${title}`));
11
+ console.log(line("═"));
12
+ }
13
+ function printSection(title, color) {
14
+ console.log("");
15
+ console.log(line());
16
+ console.log(color(chalk.bold(` ${title}`)));
17
+ console.log(line());
18
+ console.log("");
19
+ }
20
+ function printSummary(scannedCount, errors, warnings) {
9
21
  console.log("");
22
+ console.log(chalk.dim(` Scanned ${scannedCount} staged file(s)`));
23
+ console.log(` ${chalk.red(`Errors: ${errors}`)}${chalk.dim(" │ ")}${chalk.yellow(`Warnings: ${warnings}`)}`);
24
+ }
25
+ function printFinding(finding, index) {
26
+ const location = finding.line
27
+ ? `${finding.file}:${finding.line}`
28
+ : finding.file;
29
+ const checkLabel = chalk.dim(`[${finding.checkName}]`);
30
+ console.log(chalk.bold(` ${index}.`) + ` ${checkLabel}`);
31
+ console.log(` ${chalk.cyan(location)}`);
32
+ console.log(` ${finding.message}`);
33
+ if (finding.suggestion) {
34
+ console.log(chalk.gray(` → ${finding.suggestion}`));
35
+ }
36
+ console.log("");
37
+ }
38
+ function printFindings(findings, severity) {
39
+ const filtered = findings.filter((finding) => finding.severity === severity);
40
+ filtered.forEach((finding, index) => {
41
+ printFinding(finding, index + 1);
42
+ });
43
+ }
44
+ export function printReport(findings, scannedCount) {
45
+ const errors = findings.filter((finding) => finding.severity === "error");
46
+ const warnings = findings.filter((finding) => finding.severity === "warning");
47
+ printHeader(`${PRODUCT_NAME} Report`);
48
+ printSummary(scannedCount, errors.length, warnings.length);
10
49
  if (findings.length === 0) {
11
- console.log(chalk.green("✅ No issues found. Commit looks clean.\n"));
50
+ console.log("");
51
+ console.log(chalk.green(" ✅ All clear — no issues found in staged files."));
52
+ console.log("");
53
+ console.log(line("═"));
54
+ console.log("");
12
55
  return;
13
56
  }
14
57
  if (errors.length > 0) {
15
- console.log(chalk.red.bold("❌ Errors"));
16
- for (const finding of errors) {
17
- printFinding(finding);
18
- }
58
+ printSection(`ERRORS (${errors.length})`, chalk.red);
59
+ printFindings(findings, "error");
19
60
  }
20
61
  if (warnings.length > 0) {
21
- console.log(chalk.yellow.bold("\n⚠️ Warnings"));
22
- for (const finding of warnings) {
23
- printFinding(finding);
24
- }
62
+ printSection(`WARNINGS (${warnings.length})`, chalk.yellow);
63
+ printFindings(findings, "warning");
25
64
  }
65
+ console.log(line("═"));
26
66
  console.log("");
27
67
  }
28
- function printFinding(finding) {
29
- const location = finding.line
30
- ? `${finding.file}:${finding.line}`
31
- : finding.file;
32
- console.log(`- ${chalk.bold(location)}`);
33
- console.log(` ${finding.message}`);
34
- if (finding.suggestion) {
35
- console.log(chalk.gray(` Fix: ${finding.suggestion}`));
36
- }
37
- }
38
68
  //# sourceMappingURL=reporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,UAAU,WAAW,CAAC,QAAmB,EAAE,YAAoB;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,WAAW,YAAY,oBAAoB,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACxC,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;YAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;QAChD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,OAAgB;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI;QAC3B,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE;QACnC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAEjB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEpC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runScan(strict?: boolean, allowConsoleLog?: boolean): Promise<number>;
2
+ //# sourceMappingURL=runScan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runScan.d.ts","sourceRoot":"","sources":["../src/runScan.ts"],"names":[],"mappings":"AAKA,wBAAsB,OAAO,CAC3B,MAAM,UAAQ,EACd,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CA0BjB"}
@@ -0,0 +1,24 @@
1
+ import { PRODUCT_NAME } from "./brand.js";
2
+ import { getStagedFiles } from "./git.js";
3
+ import { runChecks } from "./scanner.js";
4
+ import { printReport } from "./reporter.js";
5
+ export async function runScan(strict = false, allowConsoleLog = false) {
6
+ const stagedFiles = getStagedFiles();
7
+ if (stagedFiles.length === 0) {
8
+ console.log(`${PRODUCT_NAME}: No staged files found.`);
9
+ return 0;
10
+ }
11
+ const findings = await runChecks({
12
+ stagedFiles,
13
+ strict,
14
+ allowConsoleLog,
15
+ });
16
+ printReport(findings, stagedFiles.length);
17
+ const hasErrors = findings.some((finding) => finding.severity === "error");
18
+ const hasWarnings = findings.some((finding) => finding.severity === "warning");
19
+ if (hasErrors || (strict && hasWarnings)) {
20
+ return 1;
21
+ }
22
+ return 0;
23
+ }
24
+ //# sourceMappingURL=runScan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runScan.js","sourceRoot":"","sources":["../src/runScan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAM,GAAG,KAAK,EACd,eAAe,GAAG,KAAK;IAEvB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,YAAY,0BAA0B,CAAC,CAAC;QACvD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;QAC/B,WAAW;QACX,MAAM;QACN,eAAe;KAChB,CAAC,CAAC;IAEH,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAC/B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAC5C,CAAC;IAEF,IAAI,SAAS,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA+BxD,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CASzE"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA+BxD,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAYzE"}
package/dist/scanner.js CHANGED
@@ -28,7 +28,10 @@ const checks = [
28
28
  ];
29
29
  export async function runChecks(context) {
30
30
  const allFindings = [];
31
- for (const check of checks) {
31
+ const activeChecks = context.allowConsoleLog
32
+ ? checks.filter((check) => check !== consoleLogCheck)
33
+ : checks;
34
+ for (const check of activeChecks) {
32
35
  const findings = await check.run(context);
33
36
  allFindings.push(...findings);
34
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,GAAG;IACb,kBAAkB;IAClB,YAAY;IACZ,sBAAsB;IACtB,oBAAoB;IACpB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,cAAc;IACd,aAAa;IACb,kBAAkB;IAClB,cAAc;IACd,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAqB;IACnD,MAAM,WAAW,GAAc,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,GAAG;IACb,kBAAkB;IAClB,YAAY;IACZ,sBAAsB;IACtB,oBAAoB;IACpB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,cAAc;IACd,aAAa;IACb,kBAAkB;IAClB,cAAc;IACd,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAqB;IACnD,MAAM,WAAW,GAAc,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe;QAC1C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,eAAe,CAAC;QACrD,CAAC,CAAC,MAAM,CAAC;IAEX,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -10,6 +10,10 @@ export type Finding = {
10
10
  export type CheckContext = {
11
11
  stagedFiles: string[];
12
12
  strict: boolean;
13
+ allowConsoleLog?: boolean;
14
+ };
15
+ export type WipFixOptions = {
16
+ fixConsoleLog?: boolean;
13
17
  };
14
18
  export type Check = {
15
19
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACpD,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACpD,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "commit-cop",
3
- "version": "1.0.1",
4
- "description": "A pre-commit safety checker that scans staged files for risky commits.",
3
+ "version": "1.1.1",
4
+ "description": "Commit Cop — a pre-commit safety checker that scans staged files for risky commits.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "commit-cop": "./dist/index.js"
@@ -10,7 +10,8 @@
10
10
  "dev": "tsx src/index.ts",
11
11
  "build": "tsc",
12
12
  "start": "node dist/index.js",
13
- "commit-cop": "tsx src/index.ts"
13
+ "commit-cop": "tsx src/index.ts",
14
+ "demo:setup": "node scripts/setup-demo.mjs"
14
15
  },
15
16
  "repository": {
16
17
  "type": "git",
package/src/brand.ts ADDED
@@ -0,0 +1,3 @@
1
+ export const PRODUCT_NAME = "Commit Cop";
2
+ export const CLI_NAME = "commit-cop";
3
+ export const TAGLINE = "Catch bad commits before they hit GitHub";
@@ -52,9 +52,9 @@ export const binaryFileCheck: Check = {
52
52
  severity: "warning",
53
53
  checkName: this.name,
54
54
  file,
55
- message: "Binary or non-text file is staged.",
56
- suggestion:
57
- "Remove it from the commit or store it outside Git (e.g. Git LFS).",
55
+ message:
56
+ "Binary file detected — archives, executables, and media don't belong in source control.",
57
+ suggestion: "Remove it from the commit or store it with Git LFS.",
58
58
  });
59
59
  }
60
60
  }
@@ -27,8 +27,9 @@ export const consoleLogCheck: Check = {
27
27
  checkName: this.name,
28
28
  file,
29
29
  line: index + 1,
30
- message: "console.log found in staged code.",
31
- suggestion: "Remove debug logs before committing.",
30
+ message:
31
+ "Debug log left in code — easy to miss and clutters production output.",
32
+ suggestion: "Delete the console.log before committing.",
32
33
  });
33
34
  }
34
35
  });
@@ -20,8 +20,9 @@ export const debuggerCheck: Check = {
20
20
  checkName: this.name,
21
21
  file,
22
22
  line: index + 1,
23
- message: "debugger statement found in staged code.",
24
- suggestion: "Remove debugger statements before committing.",
23
+ message:
24
+ "debugger statement left in code — pauses execution and breaks CI/headless runs.",
25
+ suggestion: "Delete the debugger statement before committing.",
25
26
  });
26
27
  }
27
28
  });
@@ -14,8 +14,9 @@ export const envFileCheck: Check = {
14
14
  severity: "error",
15
15
  checkName: this.name,
16
16
  file,
17
- message: "Environment file is staged and may contain secrets.",
18
- suggestion: `Run: git restore --staged ${file}`,
17
+ message:
18
+ ".env file detected these often hold API keys, passwords, and tokens.",
19
+ suggestion: `Unstage it: git restore --staged ${file}`,
19
20
  });
20
21
  }
21
22
  }
@@ -28,8 +28,8 @@ export const focusedTestCheck: Check = {
28
28
  checkName: this.name,
29
29
  file,
30
30
  line: index + 1,
31
- message: `${pattern} found. This may skip the rest of the test suite.`,
32
- suggestion: `Replace ${pattern} with the normal test function.`,
31
+ message: `${pattern} detected only that test will run, hiding failures in the rest of the suite.`,
32
+ suggestion: `Change ${pattern} back to ${pattern.replace(".only", "")}.`,
33
33
  });
34
34
  }
35
35
  }
@@ -34,8 +34,8 @@ export const generatedFolderCheck: Check = {
34
34
  severity: "error",
35
35
  checkName: this.name,
36
36
  file,
37
- message: `${matchedFolder} is staged but is usually generated and should not be committed.`,
38
- suggestion: `Add ${matchedFolder} to .gitignore and run: git restore --staged ${file}`,
37
+ message: `Generated folder (${matchedFolder}) auto-built files bloat the repo and cause merge pain.`,
38
+ suggestion: `Add ${matchedFolder} to .gitignore, then: git restore --staged ${file}`,
39
39
  });
40
40
  }
41
41
  }
@@ -28,8 +28,9 @@ export const junkFileCheck: Check = {
28
28
  severity: "warning",
29
29
  checkName: this.name,
30
30
  file,
31
- message: "OS or editor junk file is staged.",
32
- suggestion: `Run: git restore --staged ${file}`,
31
+ message:
32
+ "OS or editor junk file — adds noise and has no place in the repo.",
33
+ suggestion: `Unstage it: git restore --staged ${file}`,
33
34
  });
34
35
  }
35
36
  }
@@ -20,8 +20,8 @@ export const largeFileCheck: Check = {
20
20
  severity: "warning",
21
21
  checkName: this.name,
22
22
  file,
23
- message: `Large file staged: ${sizeMb.toFixed(2)} MB.`,
24
- suggestion: "Consider removing this file from Git or using Git LFS.",
23
+ message: `Large file (${sizeMb.toFixed(2)} MB) — slows clones and may hit GitHub's size limits.`,
24
+ suggestion: "Remove it from Git or use Git LFS for big assets.",
25
25
  });
26
26
  }
27
27
  }
@@ -27,8 +27,8 @@ export const localHostCheck: Check = {
27
27
  checkName: this.name,
28
28
  file,
29
29
  line: index + 1,
30
- message: `Hardcoded local URL found: ${pattern}`,
31
- suggestion: "Use an environment variable instead of a hardcoded localhost URL.",
30
+ message: `Hardcoded local URL (${pattern}) — won't work in production or for teammates.`,
31
+ suggestion: "Move the URL to an environment variable (e.g. process.env.API_URL).",
32
32
  });
33
33
  }
34
34
  }
@@ -18,8 +18,9 @@ export const lockfileDriftCheck: Check = {
18
18
  severity: "warning",
19
19
  checkName: this.name,
20
20
  file: "package.json",
21
- message: "package.json is staged but package-lock.json is not.",
22
- suggestion: "Run npm install and stage package-lock.json.",
21
+ message:
22
+ "package.json changed without its lockfile — teammates may get different dependency versions.",
23
+ suggestion: "Run npm install, then stage package-lock.json.",
23
24
  });
24
25
  }
25
26
 
@@ -28,8 +29,9 @@ export const lockfileDriftCheck: Check = {
28
29
  severity: "warning",
29
30
  checkName: this.name,
30
31
  file: "package-lock.json",
31
- message: "package-lock.json is staged but package.json is not.",
32
- suggestion: "Stage package.json or unstage the lockfile.",
32
+ message:
33
+ "Lockfile changed without package.json the lockfile may not match your declared dependencies.",
34
+ suggestion: "Stage package.json too, or unstage package-lock.json.",
33
35
  });
34
36
  }
35
37
 
@@ -25,9 +25,10 @@ export const mergeConflictCheck: Check = {
25
25
  checkName: this.name,
26
26
  file,
27
27
  line: index + 1,
28
- message: "Merge conflict marker found in staged file.",
28
+ message:
29
+ "Unresolved merge conflict — this file won't run correctly until fixed.",
29
30
  suggestion:
30
- "Resolve the conflict, remove the markers, and restage the file.",
31
+ "Resolve the conflict, remove the <<<<<<< / ======= / >>>>>>> markers, then restage.",
31
32
  });
32
33
  return;
33
34
  }
@@ -6,21 +6,21 @@ import {
6
6
  shouldSkipContentScan,
7
7
  } from "./utils.js";
8
8
 
9
- const secretPatterns = [
10
- /OPENAI_API_KEY\s*=/i,
11
- /DATABASE_URL\s*=/i,
12
- /JWT_SECRET\s*=/i,
13
- /AUTH_SECRET\s*=/i,
14
- /PRIVATE_KEY\s*=/i,
15
- /SECRET_KEY\s*=/i,
16
- /sk-[A-Za-z0-9_-]{20,}/,
17
- /ghp_[A-Za-z0-9]{36,}/,
18
- /github_pat_[A-Za-z0-9_]+/,
19
- /AKIA[0-9A-Z]{16}/,
20
- /sk_live_[A-Za-z0-9]+/,
21
- /AIza[0-9A-Za-z_-]{35}/,
22
- /hooks\.slack\.com\/services\//,
23
- /password\s*=\s*['"][^'"]{8,}['"]/i,
9
+ const secretRules: { pattern: RegExp; label: string }[] = [
10
+ { pattern: /OPENAI_API_KEY\s*=/i, label: "OpenAI API key" },
11
+ { pattern: /DATABASE_URL\s*=/i, label: "database connection string" },
12
+ { pattern: /JWT_SECRET\s*=/i, label: "JWT secret" },
13
+ { pattern: /AUTH_SECRET\s*=/i, label: "auth secret" },
14
+ { pattern: /PRIVATE_KEY\s*=/i, label: "private key" },
15
+ { pattern: /SECRET_KEY\s*=/i, label: "secret key" },
16
+ { pattern: /sk-[A-Za-z0-9_-]{20,}/, label: "API key" },
17
+ { pattern: /ghp_[A-Za-z0-9]{36,}/, label: "GitHub personal access token" },
18
+ { pattern: /github_pat_[A-Za-z0-9_]+/, label: "GitHub personal access token" },
19
+ { pattern: /AKIA[0-9A-Z]{16}/, label: "AWS access key" },
20
+ { pattern: /sk_live_[A-Za-z0-9]+/, label: "Stripe live secret key" },
21
+ { pattern: /AIza[0-9A-Za-z_-]{35}/, label: "Google API key" },
22
+ { pattern: /hooks\.slack\.com\/services\//, label: "Slack webhook URL" },
23
+ { pattern: /password\s*=\s*['"][^'"]{8,}['"]/i, label: "hardcoded password" },
24
24
  ];
25
25
 
26
26
  export const secretCheck: Check = {
@@ -38,16 +38,16 @@ export const secretCheck: Check = {
38
38
  lines.forEach((line, index) => {
39
39
  if (isCommentLine(line) || isPlaceholderValue(line)) return;
40
40
 
41
- for (const pattern of secretPatterns) {
42
- if (pattern.test(line)) {
41
+ for (const rule of secretRules) {
42
+ if (rule.pattern.test(line)) {
43
43
  findings.push({
44
44
  severity: "error",
45
45
  checkName: this.name,
46
46
  file,
47
47
  line: index + 1,
48
- message: "Possible secret found in staged file.",
48
+ message: `Possible ${rule.label} credentials pushed to GitHub can be scraped instantly.`,
49
49
  suggestion:
50
- "Remove the secret and rotate it if it was already pushed.",
50
+ "Remove it from the code, unstage the file, and rotate the credential if it was ever pushed.",
51
51
  });
52
52
  return;
53
53
  }
@@ -39,8 +39,9 @@ export const sensitiveFilenameCheck: Check = {
39
39
  severity: "error",
40
40
  checkName: this.name,
41
41
  file,
42
- message: "Sensitive credential file is staged.",
43
- suggestion: `Run: git restore --staged ${file}`,
42
+ message:
43
+ "Credential or key file detected — private keys and auth config should not be in Git.",
44
+ suggestion: `Unstage it: git restore --staged ${file}`,
44
45
  });
45
46
  }
46
47
  }
@@ -0,0 +1,74 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { isCodeFile } from "../checks/utils.js";
4
+ import { getStagedFiles } from "../git.js";
5
+ import type { WipFixOptions } from "../types.js";
6
+
7
+ const CONSOLE_LOG_LINE = /^\s*console\.log\([^)]*\);?\s*$/;
8
+ const DEBUGGER_LINE = /^\s*debugger;?\s*$/;
9
+
10
+ function stripDebugLines(
11
+ content: string,
12
+ options: { removeConsoleLog: boolean; removeDebugger: boolean }
13
+ ): { updated: string; removed: number } {
14
+ const lines = content.split("\n");
15
+ const kept: string[] = [];
16
+ let removed = 0;
17
+
18
+ for (const line of lines) {
19
+ const isConsoleLog = CONSOLE_LOG_LINE.test(line);
20
+ const isDebugger = DEBUGGER_LINE.test(line);
21
+
22
+ if (
23
+ (options.removeConsoleLog && isConsoleLog) ||
24
+ (options.removeDebugger && isDebugger)
25
+ ) {
26
+ removed += 1;
27
+ continue;
28
+ }
29
+ kept.push(line);
30
+ }
31
+
32
+ return { updated: kept.join("\n"), removed };
33
+ }
34
+
35
+ export function fixDebugCode(
36
+ cwd = process.cwd(),
37
+ options: WipFixOptions = {}
38
+ ): string[] {
39
+ const removeConsoleLog = Boolean(options.fixConsoleLog);
40
+ const removeDebugger = true;
41
+
42
+ if (!removeConsoleLog && !removeDebugger) {
43
+ return [];
44
+ }
45
+
46
+ let stagedFiles: string[];
47
+
48
+ try {
49
+ stagedFiles = getStagedFiles();
50
+ } catch {
51
+ return [];
52
+ }
53
+
54
+ const fixed: string[] = [];
55
+
56
+ for (const file of stagedFiles) {
57
+ if (!isCodeFile(file)) continue;
58
+
59
+ const absolutePath = path.resolve(cwd, file);
60
+ if (!fs.existsSync(absolutePath)) continue;
61
+
62
+ const content = fs.readFileSync(absolutePath, "utf-8");
63
+ const { updated, removed } = stripDebugLines(content, {
64
+ removeConsoleLog,
65
+ removeDebugger,
66
+ });
67
+ if (removed === 0) continue;
68
+
69
+ fs.writeFileSync(absolutePath, updated, "utf-8");
70
+ fixed.push(file);
71
+ }
72
+
73
+ return fixed;
74
+ }