@kevinrabun/judges 3.42.0 → 3.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +56 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/assign-findings.d.ts +37 -0
  6. package/dist/commands/assign-findings.d.ts.map +1 -0
  7. package/dist/commands/assign-findings.js +178 -0
  8. package/dist/commands/assign-findings.js.map +1 -0
  9. package/dist/commands/ci-template.d.ts +15 -0
  10. package/dist/commands/ci-template.d.ts.map +1 -0
  11. package/dist/commands/ci-template.js +212 -0
  12. package/dist/commands/ci-template.js.map +1 -0
  13. package/dist/commands/false-negatives.d.ts +35 -0
  14. package/dist/commands/false-negatives.d.ts.map +1 -0
  15. package/dist/commands/false-negatives.js +166 -0
  16. package/dist/commands/false-negatives.js.map +1 -0
  17. package/dist/commands/hook-install.d.ts +22 -0
  18. package/dist/commands/hook-install.d.ts.map +1 -0
  19. package/dist/commands/hook-install.js +143 -0
  20. package/dist/commands/hook-install.js.map +1 -0
  21. package/dist/commands/policy-audit.d.ts +53 -0
  22. package/dist/commands/policy-audit.d.ts.map +1 -0
  23. package/dist/commands/policy-audit.js +161 -0
  24. package/dist/commands/policy-audit.js.map +1 -0
  25. package/dist/commands/regression-alert.d.ts +32 -0
  26. package/dist/commands/regression-alert.d.ts.map +1 -0
  27. package/dist/commands/regression-alert.js +216 -0
  28. package/dist/commands/regression-alert.js.map +1 -0
  29. package/dist/commands/remediation.d.ts +21 -0
  30. package/dist/commands/remediation.d.ts.map +1 -0
  31. package/dist/commands/remediation.js +257 -0
  32. package/dist/commands/remediation.js.map +1 -0
  33. package/dist/commands/sla-track.d.ts +57 -0
  34. package/dist/commands/sla-track.d.ts.map +1 -0
  35. package/dist/commands/sla-track.js +269 -0
  36. package/dist/commands/sla-track.js.map +1 -0
  37. package/dist/commands/ticket-sync.d.ts +26 -0
  38. package/dist/commands/ticket-sync.d.ts.map +1 -0
  39. package/dist/commands/ticket-sync.js +236 -0
  40. package/dist/commands/ticket-sync.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CI templates — generate ready-to-use CI/CD pipeline configs for
3
+ * GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines,
4
+ * and CircleCI. Eliminates manual YAML authoring for teams adopting Judges.
5
+ */
6
+ export interface CiTemplate {
7
+ id: string;
8
+ name: string;
9
+ file: string;
10
+ content: string;
11
+ }
12
+ export declare function getTemplate(id: string): CiTemplate | undefined;
13
+ export declare function listTemplates(): CiTemplate[];
14
+ export declare function runCiTemplate(argv: string[]): void;
15
+ //# sourceMappingURL=ci-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-template.d.ts","sourceRoot":"","sources":["../../src/commands/ci-template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA8HH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE9D;AAED,wBAAgB,aAAa,IAAI,UAAU,EAAE,CAE5C;AAgBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiElD"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * CI templates — generate ready-to-use CI/CD pipeline configs for
3
+ * GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines,
4
+ * and CircleCI. Eliminates manual YAML authoring for teams adopting Judges.
5
+ */
6
+ // ─── Templates ──────────────────────────────────────────────────────────────
7
+ const GITHUB_ACTIONS = `# .github/workflows/judges.yml
8
+ name: Judges Code Review
9
+ on:
10
+ pull_request:
11
+ types: [opened, synchronize]
12
+
13
+ permissions:
14
+ contents: read
15
+ pull-requests: write
16
+ security-events: write
17
+
18
+ jobs:
19
+ judges:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: "20"
26
+ - run: npm install -g @kevinrabun/judges
27
+ - name: Run Judges evaluation
28
+ run: |
29
+ judges eval --file "src/**/*.ts" --format sarif --fail-on-findings > judges.sarif
30
+ continue-on-error: true
31
+ - name: Upload SARIF
32
+ if: always()
33
+ run: judges upload --file judges.sarif
34
+ env:
35
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
36
+ - name: Post PR summary
37
+ if: always()
38
+ run: judges pr-summary --sarif judges.sarif --pr \${{ github.event.pull_request.number }}
39
+ env:
40
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
41
+ `;
42
+ const GITLAB_CI = `# .gitlab-ci.yml
43
+ judges-review:
44
+ image: node:20
45
+ stage: test
46
+ script:
47
+ - npm install -g @kevinrabun/judges
48
+ - judges eval --file "src/**/*.ts" --format sarif > judges.sarif
49
+ - judges eval --file "src/**/*.ts" --format codeclimate > codeclimate.json
50
+ artifacts:
51
+ reports:
52
+ sast: judges.sarif
53
+ codequality: codeclimate.json
54
+ rules:
55
+ - if: $CI_MERGE_REQUEST_IID
56
+ `;
57
+ const AZURE_PIPELINES = `# azure-pipelines.yml
58
+ trigger:
59
+ - main
60
+
61
+ pool:
62
+ vmImage: "ubuntu-latest"
63
+
64
+ steps:
65
+ - task: NodeTool@0
66
+ inputs:
67
+ versionSpec: "20.x"
68
+
69
+ - script: npm install -g @kevinrabun/judges
70
+ displayName: "Install Judges"
71
+
72
+ - script: judges eval --file "src/**/*.ts" --format sarif > judges.sarif
73
+ displayName: "Run Judges evaluation"
74
+
75
+ - task: PublishBuildArtifacts@1
76
+ inputs:
77
+ PathtoPublish: judges.sarif
78
+ ArtifactName: judges-results
79
+ condition: always()
80
+ `;
81
+ const BITBUCKET_PIPELINES = `# bitbucket-pipelines.yml
82
+ image: node:20
83
+
84
+ pipelines:
85
+ pull-requests:
86
+ "**":
87
+ - step:
88
+ name: Judges Code Review
89
+ caches:
90
+ - node
91
+ script:
92
+ - npm install -g @kevinrabun/judges
93
+ - judges eval --file "src/**/*.ts" --format json > judges-results.json
94
+ - judges eval --file "src/**/*.ts" --format text
95
+ artifacts:
96
+ - judges-results.json
97
+ `;
98
+ const CIRCLECI = `# .circleci/config.yml
99
+ version: 2.1
100
+
101
+ jobs:
102
+ judges-review:
103
+ docker:
104
+ - image: cimg/node:20.0
105
+ steps:
106
+ - checkout
107
+ - run:
108
+ name: Install Judges
109
+ command: npm install -g @kevinrabun/judges
110
+ - run:
111
+ name: Run evaluation
112
+ command: judges eval --file "src/**/*.ts" --format sarif > judges.sarif
113
+ - store_artifacts:
114
+ path: judges.sarif
115
+ destination: judges-results
116
+
117
+ workflows:
118
+ review:
119
+ jobs:
120
+ - judges-review
121
+ `;
122
+ const TEMPLATES = [
123
+ { id: "github", name: "GitHub Actions", file: ".github/workflows/judges.yml", content: GITHUB_ACTIONS },
124
+ { id: "gitlab", name: "GitLab CI", file: ".gitlab-ci.yml", content: GITLAB_CI },
125
+ { id: "azure", name: "Azure Pipelines", file: "azure-pipelines.yml", content: AZURE_PIPELINES },
126
+ { id: "bitbucket", name: "Bitbucket Pipelines", file: "bitbucket-pipelines.yml", content: BITBUCKET_PIPELINES },
127
+ { id: "circleci", name: "CircleCI", file: ".circleci/config.yml", content: CIRCLECI },
128
+ ];
129
+ export function getTemplate(id) {
130
+ return TEMPLATES.find((t) => t.id === id);
131
+ }
132
+ export function listTemplates() {
133
+ return TEMPLATES;
134
+ }
135
+ // ─── Auto-Detect Platform ──────────────────────────────────────────────────
136
+ function detectPlatform() {
137
+ const { existsSync } = require("fs");
138
+ if (existsSync(".github"))
139
+ return "github";
140
+ if (existsSync(".gitlab-ci.yml"))
141
+ return "gitlab";
142
+ if (existsSync("azure-pipelines.yml"))
143
+ return "azure";
144
+ if (existsSync("bitbucket-pipelines.yml"))
145
+ return "bitbucket";
146
+ if (existsSync(".circleci"))
147
+ return "circleci";
148
+ return undefined;
149
+ }
150
+ // ─── CLI ────────────────────────────────────────────────────────────────────
151
+ export function runCiTemplate(argv) {
152
+ if (argv.includes("--help") || argv.includes("-h")) {
153
+ console.log(`
154
+ judges ci-template — Generate CI/CD pipeline config for Judges
155
+
156
+ Usage:
157
+ judges ci-template --platform github Generate GitHub Actions workflow
158
+ judges ci-template --platform gitlab Generate GitLab CI config
159
+ judges ci-template --platform azure Generate Azure Pipelines config
160
+ judges ci-template --platform bitbucket Generate Bitbucket Pipelines config
161
+ judges ci-template --platform circleci Generate CircleCI config
162
+ judges ci-template --list List available templates
163
+ judges ci-template --auto Auto-detect platform
164
+
165
+ Options:
166
+ --platform <id> CI platform (github, gitlab, azure, bitbucket, circleci)
167
+ --write Write to the appropriate file location
168
+ --list List all available templates
169
+ --auto Auto-detect platform from repo structure
170
+ --help, -h Show this help
171
+ `);
172
+ return;
173
+ }
174
+ if (argv.includes("--list")) {
175
+ console.log("\n Available CI Templates:\n");
176
+ for (const t of TEMPLATES) {
177
+ console.log(` ${t.id.padEnd(12)} ${t.name.padEnd(25)} → ${t.file}`);
178
+ }
179
+ console.log("");
180
+ return;
181
+ }
182
+ let platform = argv.find((_a, i) => argv[i - 1] === "--platform");
183
+ if (argv.includes("--auto")) {
184
+ platform = detectPlatform();
185
+ if (!platform) {
186
+ console.error("Error: could not auto-detect CI platform");
187
+ process.exit(1);
188
+ }
189
+ console.log(` Auto-detected platform: ${platform}`);
190
+ }
191
+ if (!platform) {
192
+ console.error("Error: --platform <id> required. Use --list to see options.");
193
+ process.exit(1);
194
+ }
195
+ const template = getTemplate(platform);
196
+ if (!template) {
197
+ console.error(`Error: unknown platform "${platform}". Use --list to see options.`);
198
+ process.exit(1);
199
+ }
200
+ if (argv.includes("--write")) {
201
+ const { writeFileSync, mkdirSync } = require("fs");
202
+ const { dirname } = require("path");
203
+ const dir = dirname(template.file);
204
+ if (dir !== ".")
205
+ mkdirSync(dir, { recursive: true });
206
+ writeFileSync(template.file, template.content, "utf-8");
207
+ console.log(` ✅ Written ${template.file}`);
208
+ return;
209
+ }
210
+ console.log(template.content);
211
+ }
212
+ //# sourceMappingURL=ci-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-template.js","sourceRoot":"","sources":["../../src/commands/ci-template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * False-negative report — collect and analyze cases where Judges
3
+ * missed a real vulnerability or bug that was later found manually.
4
+ *
5
+ * Builds a local feedback database (.judges-false-negatives.json)
6
+ * that helps teams understand blind spots and request new rules.
7
+ */
8
+ export interface FalseNegativeEntry {
9
+ id: string;
10
+ timestamp: string;
11
+ file: string;
12
+ line?: number;
13
+ category: string;
14
+ description: string;
15
+ severity: string;
16
+ expectedRule?: string;
17
+ language: string;
18
+ codeSnippet?: string;
19
+ reportedBy?: string;
20
+ status: "open" | "rule-added" | "wont-fix" | "duplicate";
21
+ }
22
+ export interface FalseNegativeDb {
23
+ entries: FalseNegativeEntry[];
24
+ version: string;
25
+ }
26
+ export declare function addFalseNegative(entry: Omit<FalseNegativeEntry, "id" | "timestamp" | "status">): FalseNegativeEntry;
27
+ export declare function getFalseNegativeStats(db: FalseNegativeDb): {
28
+ total: number;
29
+ open: number;
30
+ byCategory: Record<string, number>;
31
+ bySeverity: Record<string, number>;
32
+ byLanguage: Record<string, number>;
33
+ };
34
+ export declare function runFalseNegativeReport(argv: string[]): void;
35
+ //# sourceMappingURL=false-negatives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"false-negatives.d.ts","sourceRoot":"","sources":["../../src/commands/false-negatives.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAuBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,GAAG,QAAQ,CAAC,GAAG,kBAAkB,CAcnH;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,eAAe,GAAG;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAaA;AAID,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2G3D"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * False-negative report — collect and analyze cases where Judges
3
+ * missed a real vulnerability or bug that was later found manually.
4
+ *
5
+ * Builds a local feedback database (.judges-false-negatives.json)
6
+ * that helps teams understand blind spots and request new rules.
7
+ */
8
+ import { createHash } from "crypto";
9
+ // ─── Database ───────────────────────────────────────────────────────────────
10
+ const DB_FILE = ".judges-false-negatives.json";
11
+ function loadDb() {
12
+ const { readFileSync, existsSync } = require("fs");
13
+ if (existsSync(DB_FILE)) {
14
+ try {
15
+ return JSON.parse(readFileSync(DB_FILE, "utf-8"));
16
+ }
17
+ catch {
18
+ /* corrupt */
19
+ }
20
+ }
21
+ return { entries: [], version: "1.0" };
22
+ }
23
+ function saveDb(db) {
24
+ const { writeFileSync } = require("fs");
25
+ writeFileSync(DB_FILE, JSON.stringify(db, null, 2), "utf-8");
26
+ }
27
+ export function addFalseNegative(entry) {
28
+ const db = loadDb();
29
+ const fn = {
30
+ ...entry,
31
+ id: createHash("sha256")
32
+ .update(Date.now().toString() + entry.file + entry.description)
33
+ .digest("hex")
34
+ .slice(0, 10),
35
+ timestamp: new Date().toISOString(),
36
+ status: "open",
37
+ };
38
+ db.entries.push(fn);
39
+ saveDb(db);
40
+ return fn;
41
+ }
42
+ export function getFalseNegativeStats(db) {
43
+ const open = db.entries.filter((e) => e.status === "open").length;
44
+ const byCategory = {};
45
+ const bySeverity = {};
46
+ const byLanguage = {};
47
+ for (const e of db.entries) {
48
+ byCategory[e.category] = (byCategory[e.category] || 0) + 1;
49
+ bySeverity[e.severity] = (bySeverity[e.severity] || 0) + 1;
50
+ byLanguage[e.language] = (byLanguage[e.language] || 0) + 1;
51
+ }
52
+ return { total: db.entries.length, open, byCategory, bySeverity, byLanguage };
53
+ }
54
+ // ─── CLI ────────────────────────────────────────────────────────────────────
55
+ export function runFalseNegativeReport(argv) {
56
+ if (argv.includes("--help") || argv.includes("-h")) {
57
+ console.log(`
58
+ judges false-negatives — Report and track missed vulnerabilities
59
+
60
+ Usage:
61
+ judges false-negatives Show report
62
+ judges false-negatives --add --file src/app.ts \\
63
+ --line 42 --category injection --severity high \\
64
+ --description "SQL injection via user input" Add a missed finding
65
+ judges false-negatives --resolve <id> Mark as resolved
66
+
67
+ Options:
68
+ --add Add a new false-negative report
69
+ --file <path> File where the issue was found
70
+ --line <n> Line number
71
+ --category <cat> Category (injection, auth, crypto, xss, etc.)
72
+ --severity <level> Severity (critical, high, medium, low)
73
+ --description <text> Description of what was missed
74
+ --language <lang> Language (auto-detected from file)
75
+ --resolve <id> Mark entry as resolved
76
+ --format json JSON output
77
+ --help, -h Show this help
78
+
79
+ This builds a local feedback database that helps identify blind spots
80
+ in the current rule set, informing future rule development.
81
+ `);
82
+ return;
83
+ }
84
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
85
+ if (argv.includes("--add")) {
86
+ const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
87
+ const lineStr = argv.find((_a, i) => argv[i - 1] === "--line");
88
+ const category = argv.find((_a, i) => argv[i - 1] === "--category") || "unknown";
89
+ const severity = argv.find((_a, i) => argv[i - 1] === "--severity") || "medium";
90
+ const description = argv.find((_a, i) => argv[i - 1] === "--description") || "";
91
+ const language = argv.find((_a, i) => argv[i - 1] === "--language") || detectLanguage(file);
92
+ if (!file || !description) {
93
+ console.error("Error: --file and --description required");
94
+ process.exit(1);
95
+ }
96
+ const entry = addFalseNegative({
97
+ file,
98
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
99
+ category,
100
+ severity,
101
+ description,
102
+ language,
103
+ });
104
+ console.log(` ✅ Added false-negative report: ${entry.id}`);
105
+ return;
106
+ }
107
+ const resolveId = argv.find((_a, i) => argv[i - 1] === "--resolve");
108
+ if (resolveId) {
109
+ const db = loadDb();
110
+ const entry = db.entries.find((e) => e.id === resolveId);
111
+ if (!entry) {
112
+ console.error(`Error: entry ${resolveId} not found`);
113
+ process.exit(1);
114
+ }
115
+ entry.status = "rule-added";
116
+ saveDb(db);
117
+ console.log(` ✅ Resolved: ${resolveId}`);
118
+ return;
119
+ }
120
+ // Show report
121
+ const db = loadDb();
122
+ if (db.entries.length === 0) {
123
+ console.log("\n No false-negative reports. Use --add to report a missed finding.\n");
124
+ return;
125
+ }
126
+ const stats = getFalseNegativeStats(db);
127
+ if (format === "json") {
128
+ console.log(JSON.stringify({ stats, entries: db.entries }, null, 2));
129
+ return;
130
+ }
131
+ console.log(`\n False-Negative Analysis\n`);
132
+ console.log(` Total: ${stats.total} | Open: ${stats.open}\n`);
133
+ console.log(" By Category:");
134
+ for (const [cat, count] of Object.entries(stats.byCategory).sort((a, b) => b[1] - a[1])) {
135
+ console.log(` ${cat.padEnd(20)} ${count}`);
136
+ }
137
+ console.log("\n By Severity:");
138
+ for (const [sev, count] of Object.entries(stats.bySeverity).sort((a, b) => b[1] - a[1])) {
139
+ console.log(` ${sev.padEnd(20)} ${count}`);
140
+ }
141
+ console.log("\n Recent entries:");
142
+ for (const e of db.entries.slice(-10)) {
143
+ const status = e.status === "open" ? "🔴" : "✅";
144
+ console.log(` ${status} ${e.id} ${e.severity.padEnd(8)} ${e.category.padEnd(15)} ${e.description.slice(0, 50)}`);
145
+ }
146
+ console.log("");
147
+ }
148
+ function detectLanguage(file) {
149
+ const { extname } = require("path");
150
+ const ext = extname(file).toLowerCase();
151
+ const map = {
152
+ ".ts": "typescript",
153
+ ".tsx": "typescript",
154
+ ".js": "javascript",
155
+ ".jsx": "javascript",
156
+ ".py": "python",
157
+ ".go": "go",
158
+ ".rs": "rust",
159
+ ".java": "java",
160
+ ".cs": "csharp",
161
+ ".rb": "ruby",
162
+ ".php": "php",
163
+ };
164
+ return map[ext] || "unknown";
165
+ }
166
+ //# sourceMappingURL=false-negatives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"false-negatives.js","sourceRoot":"","sources":["../../src/commands/false-negatives.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Hook install — install and configure git hooks for pre-commit
3
+ * and pre-push evaluation with Judges.
4
+ *
5
+ * Supports husky, simple-git-hooks, and direct .git/hooks installation.
6
+ */
7
+ export interface HookConfig {
8
+ /** Hook type: pre-commit or pre-push */
9
+ hook: "pre-commit" | "pre-push";
10
+ /** Only evaluate staged files */
11
+ stagedOnly: boolean;
12
+ /** Fail on findings of this severity or higher */
13
+ failSeverity: string;
14
+ /** Timeout in seconds */
15
+ timeout: number;
16
+ /** Run in parallel */
17
+ parallel: boolean;
18
+ /** Use smart judge selection */
19
+ smartSelect: boolean;
20
+ }
21
+ export declare function runHookInstall(argv: string[]): void;
22
+ //# sourceMappingURL=hook-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-install.d.ts","sourceRoot":"","sources":["../../src/commands/hook-install.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,UAAU;IACzB,wCAAwC;IACxC,IAAI,EAAE,YAAY,GAAG,UAAU,CAAC;IAChC,iCAAiC;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,gCAAgC;IAChC,WAAW,EAAE,OAAO,CAAC;CACtB;AAoFD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoEnD"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Hook install — install and configure git hooks for pre-commit
3
+ * and pre-push evaluation with Judges.
4
+ *
5
+ * Supports husky, simple-git-hooks, and direct .git/hooks installation.
6
+ */
7
+ // ─── Hook Scripts ───────────────────────────────────────────────────────────
8
+ function generateHookScript(config) {
9
+ const flags = [];
10
+ if (config.stagedOnly)
11
+ flags.push("--staged-only");
12
+ if (config.failSeverity !== "info")
13
+ flags.push(`--min-severity ${config.failSeverity}`);
14
+ flags.push("--fail-on-findings");
15
+ flags.push("--summary");
16
+ return `#!/bin/sh
17
+ # Judges ${config.hook} hook
18
+ # Auto-generated by: judges hook-install
19
+
20
+ # Skip if JUDGES_SKIP_HOOK is set
21
+ if [ -n "$JUDGES_SKIP_HOOK" ]; then
22
+ echo "Judges: hook skipped (JUDGES_SKIP_HOOK is set)"
23
+ exit 0
24
+ fi
25
+
26
+ # Timeout protection (${config.timeout}s)
27
+ timeout_cmd=""
28
+ if command -v timeout > /dev/null 2>&1; then
29
+ timeout_cmd="timeout ${config.timeout}"
30
+ fi
31
+
32
+ echo "🔍 Judges: evaluating..."
33
+ $timeout_cmd npx judges eval ${flags.join(" ")} 2>&1
34
+ exit_code=$?
35
+
36
+ if [ $exit_code -ne 0 ] && [ $exit_code -ne 124 ]; then
37
+ echo ""
38
+ echo "❌ Judges: findings detected. Fix or skip with JUDGES_SKIP_HOOK=1"
39
+ exit 1
40
+ fi
41
+
42
+ if [ $exit_code -eq 124 ]; then
43
+ echo "⚠️ Judges: evaluation timed out (${config.timeout}s). Proceeding."
44
+ fi
45
+ `;
46
+ }
47
+ // ─── Installation Methods ───────────────────────────────────────────────────
48
+ function installDirect(hookType, script) {
49
+ const { writeFileSync, mkdirSync, chmodSync, existsSync } = require("fs");
50
+ const { join } = require("path");
51
+ const hooksDir = join(".git", "hooks");
52
+ if (!existsSync(".git")) {
53
+ console.error("Error: not a git repository");
54
+ return false;
55
+ }
56
+ mkdirSync(hooksDir, { recursive: true });
57
+ const hookPath = join(hooksDir, hookType);
58
+ writeFileSync(hookPath, script, { mode: 0o755 });
59
+ try {
60
+ chmodSync(hookPath, 0o755);
61
+ }
62
+ catch {
63
+ /* Windows */
64
+ }
65
+ console.log(` ✅ Installed ${hookPath}`);
66
+ return true;
67
+ }
68
+ function installHusky(hookType, script) {
69
+ const { existsSync, writeFileSync, mkdirSync } = require("fs");
70
+ const { join } = require("path");
71
+ if (!existsSync(".husky")) {
72
+ console.log(" Husky directory not found. Creating .husky/");
73
+ mkdirSync(".husky", { recursive: true });
74
+ }
75
+ const hookPath = join(".husky", hookType);
76
+ writeFileSync(hookPath, script, { mode: 0o755 });
77
+ console.log(` ✅ Installed ${hookPath} (husky)`);
78
+ return true;
79
+ }
80
+ // ─── CLI ────────────────────────────────────────────────────────────────────
81
+ export function runHookInstall(argv) {
82
+ if (argv.includes("--help") || argv.includes("-h")) {
83
+ console.log(`
84
+ judges hook-install — Install git hooks for automatic code review
85
+
86
+ Usage:
87
+ judges hook-install Install pre-commit hook
88
+ judges hook-install --hook pre-push Install pre-push hook
89
+ judges hook-install --method husky Use husky for hook management
90
+
91
+ Options:
92
+ --hook <type> Hook type: pre-commit (default) or pre-push
93
+ --method <method> Installation: direct (default), husky
94
+ --severity <level> Fail on findings of this severity+ (default: high)
95
+ --timeout <seconds> Timeout in seconds (default: 60)
96
+ --no-staged-only Evaluate all files, not just staged
97
+ --uninstall Remove the hook
98
+ --show Show current hook script without installing
99
+ --help, -h Show this help
100
+
101
+ Environment:
102
+ JUDGES_SKIP_HOOK=1 Skip the hook for a single commit
103
+ `);
104
+ return;
105
+ }
106
+ const hookType = (argv.find((_a, i) => argv[i - 1] === "--hook") || "pre-commit");
107
+ const method = argv.find((_a, i) => argv[i - 1] === "--method") || "direct";
108
+ const severity = argv.find((_a, i) => argv[i - 1] === "--severity") || "high";
109
+ const timeoutStr = argv.find((_a, i) => argv[i - 1] === "--timeout");
110
+ const timeout = timeoutStr ? parseInt(timeoutStr, 10) : 60;
111
+ if (argv.includes("--uninstall")) {
112
+ const { unlinkSync, existsSync } = require("fs");
113
+ const { join } = require("path");
114
+ const paths = [join(".git", "hooks", hookType), join(".husky", hookType)];
115
+ for (const p of paths) {
116
+ if (existsSync(p)) {
117
+ unlinkSync(p);
118
+ console.log(` ✅ Removed ${p}`);
119
+ }
120
+ }
121
+ return;
122
+ }
123
+ const config = {
124
+ hook: hookType,
125
+ stagedOnly: !argv.includes("--no-staged-only"),
126
+ failSeverity: severity,
127
+ timeout,
128
+ parallel: true,
129
+ smartSelect: true,
130
+ };
131
+ const script = generateHookScript(config);
132
+ if (argv.includes("--show")) {
133
+ console.log(script);
134
+ return;
135
+ }
136
+ if (method === "husky") {
137
+ installHusky(hookType, script);
138
+ }
139
+ else {
140
+ installDirect(hookType, script);
141
+ }
142
+ }
143
+ //# sourceMappingURL=hook-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-install.js","sourceRoot":"","sources":["../../src/commands/hook-install.ts"],"names":[],"mappings":"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"}