agent-gauntlet 0.1.10 → 0.1.12

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 (55) hide show
  1. package/README.md +55 -87
  2. package/package.json +4 -2
  3. package/src/bun-plugins.d.ts +4 -0
  4. package/src/cli-adapters/claude.ts +139 -108
  5. package/src/cli-adapters/codex.ts +141 -117
  6. package/src/cli-adapters/cursor.ts +152 -0
  7. package/src/cli-adapters/gemini.ts +171 -139
  8. package/src/cli-adapters/github-copilot.ts +153 -0
  9. package/src/cli-adapters/index.ts +77 -48
  10. package/src/commands/check.test.ts +24 -20
  11. package/src/commands/check.ts +86 -59
  12. package/src/commands/ci/index.ts +15 -0
  13. package/src/commands/ci/init.ts +96 -0
  14. package/src/commands/ci/list-jobs.ts +78 -0
  15. package/src/commands/detect.test.ts +38 -32
  16. package/src/commands/detect.ts +89 -61
  17. package/src/commands/health.test.ts +67 -53
  18. package/src/commands/health.ts +167 -145
  19. package/src/commands/help.test.ts +37 -37
  20. package/src/commands/help.ts +31 -22
  21. package/src/commands/index.ts +10 -9
  22. package/src/commands/init.test.ts +120 -107
  23. package/src/commands/init.ts +514 -417
  24. package/src/commands/list.test.ts +87 -70
  25. package/src/commands/list.ts +28 -24
  26. package/src/commands/rerun.ts +157 -119
  27. package/src/commands/review.test.ts +26 -20
  28. package/src/commands/review.ts +86 -59
  29. package/src/commands/run.test.ts +22 -20
  30. package/src/commands/run.ts +85 -58
  31. package/src/commands/shared.ts +44 -35
  32. package/src/config/ci-loader.ts +33 -0
  33. package/src/config/ci-schema.ts +52 -0
  34. package/src/config/loader.test.ts +112 -90
  35. package/src/config/loader.ts +132 -123
  36. package/src/config/schema.ts +48 -47
  37. package/src/config/types.ts +28 -13
  38. package/src/config/validator.ts +521 -454
  39. package/src/core/change-detector.ts +122 -104
  40. package/src/core/entry-point.test.ts +60 -62
  41. package/src/core/entry-point.ts +120 -74
  42. package/src/core/job.ts +69 -59
  43. package/src/core/runner.ts +264 -230
  44. package/src/gates/check.ts +78 -69
  45. package/src/gates/result.ts +7 -7
  46. package/src/gates/review.test.ts +277 -138
  47. package/src/gates/review.ts +724 -561
  48. package/src/index.ts +18 -15
  49. package/src/output/console.ts +253 -214
  50. package/src/output/logger.ts +66 -52
  51. package/src/templates/run_gauntlet.template.md +18 -0
  52. package/src/templates/workflow.yml +77 -0
  53. package/src/utils/diff-parser.ts +64 -62
  54. package/src/utils/log-parser.ts +227 -206
  55. package/src/utils/sanitizer.ts +1 -1
@@ -1,31 +1,41 @@
1
- import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'bun:test';
2
- import { Command } from 'commander';
3
- import { registerListCommand } from './list.js';
4
- import fs from 'node:fs/promises';
5
- import path from 'node:path';
1
+ import {
2
+ afterAll,
3
+ afterEach,
4
+ beforeAll,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ it,
9
+ } from "bun:test";
10
+ import fs from "node:fs/promises";
11
+ import path from "node:path";
12
+ import { Command } from "commander";
13
+ import { registerListCommand } from "./list.js";
6
14
 
7
- const TEST_DIR = path.join(process.cwd(), 'test-list-' + Date.now());
8
- const GAUNTLET_DIR = path.join(TEST_DIR, '.gauntlet');
9
- const CHECKS_DIR = path.join(GAUNTLET_DIR, 'checks');
10
- const REVIEWS_DIR = path.join(GAUNTLET_DIR, 'reviews');
15
+ const TEST_DIR = path.join(process.cwd(), `test-list-${Date.now()}`);
16
+ const GAUNTLET_DIR = path.join(TEST_DIR, ".gauntlet");
17
+ const CHECKS_DIR = path.join(GAUNTLET_DIR, "checks");
18
+ const REVIEWS_DIR = path.join(GAUNTLET_DIR, "reviews");
11
19
 
12
- describe('List Command', () => {
13
- let program: Command;
14
- const originalConsoleLog = console.log;
15
- const originalConsoleError = console.error;
16
- const originalCwd = process.cwd();
17
- let logs: string[];
18
- let errors: string[];
20
+ describe("List Command", () => {
21
+ let program: Command;
22
+ const originalConsoleLog = console.log;
23
+ const originalConsoleError = console.error;
24
+ const originalCwd = process.cwd();
25
+ let logs: string[];
26
+ let errors: string[];
19
27
 
20
- beforeAll(async () => {
21
- // Setup test directory structure
22
- await fs.mkdir(TEST_DIR, { recursive: true });
23
- await fs.mkdir(GAUNTLET_DIR, { recursive: true });
24
- await fs.mkdir(CHECKS_DIR, { recursive: true });
25
- await fs.mkdir(REVIEWS_DIR, { recursive: true });
28
+ beforeAll(async () => {
29
+ // Setup test directory structure
30
+ await fs.mkdir(TEST_DIR, { recursive: true });
31
+ await fs.mkdir(GAUNTLET_DIR, { recursive: true });
32
+ await fs.mkdir(CHECKS_DIR, { recursive: true });
33
+ await fs.mkdir(REVIEWS_DIR, { recursive: true });
26
34
 
27
- // Write config.yml
28
- await fs.writeFile(path.join(GAUNTLET_DIR, 'config.yml'), `
35
+ // Write config.yml
36
+ await fs.writeFile(
37
+ path.join(GAUNTLET_DIR, "config.yml"),
38
+ `
29
39
  base_branch: origin/main
30
40
  log_dir: .gauntlet_logs
31
41
  cli:
@@ -38,67 +48,74 @@ entry_points:
38
48
  - lint
39
49
  reviews:
40
50
  - security
41
- `);
51
+ `,
52
+ );
42
53
 
43
- // Write check definition
44
- await fs.writeFile(path.join(CHECKS_DIR, 'lint.yml'), `
54
+ // Write check definition
55
+ await fs.writeFile(
56
+ path.join(CHECKS_DIR, "lint.yml"),
57
+ `
45
58
  name: lint
46
59
  command: npm run lint
47
60
  working_directory: .
48
- `);
61
+ `,
62
+ );
49
63
 
50
- // Write review definition
51
- await fs.writeFile(path.join(REVIEWS_DIR, 'security.md'), `---
64
+ // Write review definition
65
+ await fs.writeFile(
66
+ path.join(REVIEWS_DIR, "security.md"),
67
+ `---
52
68
  cli_preference:
53
69
  - gemini
54
70
  ---
55
71
 
56
72
  # Security Review
57
73
  Review for security.
58
- `);
59
- });
74
+ `,
75
+ );
76
+ });
60
77
 
61
- afterAll(async () => {
62
- await fs.rm(TEST_DIR, { recursive: true, force: true });
63
- });
78
+ afterAll(async () => {
79
+ await fs.rm(TEST_DIR, { recursive: true, force: true });
80
+ });
64
81
 
65
- beforeEach(() => {
66
- program = new Command();
67
- registerListCommand(program);
68
- logs = [];
69
- errors = [];
70
- console.log = (...args: any[]) => {
71
- logs.push(args.join(' '));
72
- };
73
- console.error = (...args: any[]) => {
74
- errors.push(args.join(' '));
75
- };
76
- process.chdir(TEST_DIR);
77
- });
82
+ beforeEach(() => {
83
+ program = new Command();
84
+ registerListCommand(program);
85
+ logs = [];
86
+ errors = [];
87
+ console.log = (...args: unknown[]) => {
88
+ logs.push(args.join(" "));
89
+ };
90
+ console.error = (...args: unknown[]) => {
91
+ errors.push(args.join(" "));
92
+ };
93
+ process.chdir(TEST_DIR);
94
+ });
78
95
 
79
- afterEach(() => {
80
- console.log = originalConsoleLog;
81
- console.error = originalConsoleError;
82
- process.chdir(originalCwd);
83
- });
96
+ afterEach(() => {
97
+ console.log = originalConsoleLog;
98
+ console.error = originalConsoleError;
99
+ process.chdir(originalCwd);
100
+ });
84
101
 
85
- it('should register the list command', () => {
86
- const listCmd = program.commands.find(cmd => cmd.name() === 'list');
87
- expect(listCmd).toBeDefined();
88
- expect(listCmd?.description()).toBe('List configured gates');
89
- });
102
+ it("should register the list command", () => {
103
+ const listCmd = program.commands.find((cmd) => cmd.name() === "list");
104
+ expect(listCmd).toBeDefined();
105
+ expect(listCmd?.description()).toBe("List configured gates");
106
+ });
90
107
 
91
- it('should list check gates, review gates, and entry points', async () => {
92
- const listCmd = program.commands.find(cmd => cmd.name() === 'list');
93
- await listCmd?.parseAsync(['list']);
108
+ it("should list check gates, review gates, and entry points", async () => {
109
+ const listCmd = program.commands.find((cmd) => cmd.name() === "list");
110
+ await listCmd?.parseAsync(["list"]);
94
111
 
95
- const output = logs.join('\n');
96
- expect(output).toContain('Check Gates:');
97
- expect(output).toContain('lint');
98
- expect(output).toContain('Review Gates:');
99
- expect(output).toContain('security');
100
- expect(output).toContain('gemini');
101
- expect(output).toContain('Entry Points:');
102
- expect(output).toContain('src/');
103
- });
112
+ const output = logs.join("\n");
113
+ expect(output).toContain("Check Gates:");
114
+ expect(output).toContain("lint");
115
+ expect(output).toContain("Review Gates:");
116
+ expect(output).toContain("security");
117
+ expect(output).toContain("gemini");
118
+ expect(output).toContain("Entry Points:");
119
+ expect(output).toContain("src/");
120
+ });
104
121
  });
@@ -1,29 +1,33 @@
1
- import type { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { loadConfig } from '../config/loader.js';
1
+ import chalk from "chalk";
2
+ import type { Command } from "commander";
3
+ import { loadConfig } from "../config/loader.js";
4
4
 
5
5
  export function registerListCommand(program: Command): void {
6
- program
7
- .command('list')
8
- .description('List configured gates')
9
- .action(async () => {
10
- try {
11
- const config = await loadConfig();
12
- console.log(chalk.bold('Check Gates:'));
13
- Object.values(config.checks).forEach(c => console.log(` - ${c.name}`));
14
-
15
- console.log(chalk.bold('\nReview Gates:'));
16
- Object.values(config.reviews).forEach(r => console.log(` - ${r.name} (Tools: ${r.cli_preference?.join(', ')})`));
6
+ program
7
+ .command("list")
8
+ .description("List configured gates")
9
+ .action(async () => {
10
+ try {
11
+ const config = await loadConfig();
12
+ console.log(chalk.bold("Check Gates:"));
13
+ Object.values(config.checks).forEach((c) => {
14
+ console.log(` - ${c.name}`);
15
+ });
17
16
 
18
- console.log(chalk.bold('\nEntry Points:'));
19
- config.project.entry_points.forEach(ep => {
20
- console.log(` - ${ep.path}`);
21
- if (ep.checks) console.log(` Checks: ${ep.checks.join(', ')}`);
22
- if (ep.reviews) console.log(` Reviews: ${ep.reviews.join(', ')}`);
23
- });
17
+ console.log(chalk.bold("\nReview Gates:"));
18
+ Object.values(config.reviews).forEach((r) => {
19
+ console.log(` - ${r.name} (Tools: ${r.cli_preference?.join(", ")})`);
20
+ });
24
21
 
25
- } catch (error: any) {
26
- console.error(chalk.red('Error:'), error.message);
27
- }
28
- });
22
+ console.log(chalk.bold("\nEntry Points:"));
23
+ config.project.entry_points.forEach((ep) => {
24
+ console.log(` - ${ep.path}`);
25
+ if (ep.checks) console.log(` Checks: ${ep.checks.join(", ")}`);
26
+ if (ep.reviews) console.log(` Reviews: ${ep.reviews.join(", ")}`);
27
+ });
28
+ } catch (error: unknown) {
29
+ const err = error as { message?: string };
30
+ console.error(chalk.red("Error:"), err.message);
31
+ }
32
+ });
29
33
  }
@@ -1,122 +1,160 @@
1
- import type { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { loadConfig } from '../config/loader.js';
4
- import { ChangeDetector } from '../core/change-detector.js';
5
- import { EntryPointExpander } from '../core/entry-point.js';
6
- import { JobGenerator } from '../core/job.js';
7
- import { Runner } from '../core/runner.js';
8
- import { Logger } from '../output/logger.js';
9
- import { ConsoleReporter } from '../output/console.js';
10
- import { findPreviousFailures, type GateFailures, type PreviousViolation } from '../utils/log-parser.js';
11
- import { rotateLogs } from './shared.js';
1
+ import chalk from "chalk";
2
+ import type { Command } from "commander";
3
+ import { loadConfig } from "../config/loader.js";
4
+ import { ChangeDetector } from "../core/change-detector.js";
5
+ import { EntryPointExpander } from "../core/entry-point.js";
6
+ import { JobGenerator } from "../core/job.js";
7
+ import { Runner } from "../core/runner.js";
8
+ import { ConsoleReporter } from "../output/console.js";
9
+ import { Logger } from "../output/logger.js";
10
+ import {
11
+ findPreviousFailures,
12
+ type PreviousViolation,
13
+ } from "../utils/log-parser.js";
14
+ import { rotateLogs } from "./shared.js";
12
15
 
13
16
  export function registerRerunCommand(program: Command): void {
14
- program
15
- .command('rerun')
16
- .description('Rerun gates (checks & reviews) with previous failures as context (defaults to uncommitted changes)')
17
- .option('-g, --gate <name>', 'Run specific gate only')
18
- .option('-c, --commit <sha>', 'Use diff for a specific commit (overrides default uncommitted mode)')
19
- .action(async (options) => {
20
- try {
21
- const config = await loadConfig();
22
-
23
- // Parse previous failures from log files (only for review gates)
24
- console.log(chalk.dim('Analyzing previous runs...'));
25
-
26
- // findPreviousFailures handles errors internally and returns empty array on failure
27
- const previousFailures = await findPreviousFailures(
28
- config.project.log_dir,
29
- options.gate
30
- );
31
-
32
- // Create a map: jobId -> (adapterName -> violations)
33
- const failuresMap = new Map<string, Map<string, PreviousViolation[]>>();
34
- for (const gateFailure of previousFailures) {
35
- const adapterMap = new Map<string, PreviousViolation[]>();
36
- for (const adapterFailure of gateFailure.adapterFailures) {
37
- adapterMap.set(adapterFailure.adapterName, adapterFailure.violations);
38
- }
39
- failuresMap.set(gateFailure.jobId, adapterMap);
40
- }
41
-
42
- if (previousFailures.length > 0) {
43
- const totalViolations = previousFailures.reduce(
44
- (sum, gf) => sum + gf.adapterFailures.reduce(
45
- (s, af) => s + af.violations.length, 0
46
- ), 0
47
- );
48
- console.log(chalk.yellow(
49
- `Found ${previousFailures.length} gate(s) with ${totalViolations} previous violation(s)`
50
- ));
51
- } else {
52
- console.log(chalk.dim('No previous failures found. Running as normal...'));
53
- }
54
-
55
- // Rotate logs before starting the new run
56
- await rotateLogs(config.project.log_dir);
57
-
58
- // Detect changes (default to uncommitted unless --commit is specified)
59
- // Note: Rerun defaults to uncommitted changes for faster iteration loops,
60
- // unlike 'run' which defaults to base_branch comparison.
61
- const changeOptions = {
62
- commit: options.commit,
63
- uncommitted: !options.commit // Default to uncommitted unless commit is specified
64
- };
65
-
66
- const changeDetector = new ChangeDetector(
67
- config.project.base_branch,
68
- changeOptions
69
- );
70
- const expander = new EntryPointExpander();
71
- const jobGen = new JobGenerator(config);
72
-
73
- const modeDesc = options.commit
74
- ? `commit ${options.commit}`
75
- : 'uncommitted changes';
76
- console.log(chalk.dim(`Detecting changes (${modeDesc})...`));
77
-
78
- const changes = await changeDetector.getChangedFiles();
79
-
80
- if (changes.length === 0) {
81
- console.log(chalk.green('No changes detected.'));
82
- process.exit(0);
83
- }
84
-
85
- console.log(chalk.dim(`Found ${changes.length} changed files.`));
86
-
87
- const entryPoints = await expander.expand(config.project.entry_points, changes);
88
- let jobs = jobGen.generateJobs(entryPoints);
89
-
90
- if (options.gate) {
91
- jobs = jobs.filter(j => j.name === options.gate);
92
- }
93
-
94
- if (jobs.length === 0) {
95
- console.log(chalk.yellow('No applicable gates for these changes.'));
96
- process.exit(0);
97
- }
98
-
99
- console.log(chalk.dim(`Running ${jobs.length} gates...`));
100
- if (previousFailures.length > 0) {
101
- console.log(chalk.dim('Previous failures will be injected as context for matching reviewers.'));
102
- }
103
-
104
- const logger = new Logger(config.project.log_dir);
105
- const reporter = new ConsoleReporter();
106
- const runner = new Runner(
107
- config,
108
- logger,
109
- reporter,
110
- failuresMap, // Pass previous failures map
111
- changeOptions // Pass change detection options
112
- );
113
-
114
- const success = await runner.run(jobs);
115
- process.exit(success ? 0 : 1);
116
-
117
- } catch (error: any) {
118
- console.error(chalk.red('Error:'), error.message);
119
- process.exit(1);
120
- }
121
- });
17
+ program
18
+ .command("rerun")
19
+ .description(
20
+ "Rerun gates (checks & reviews) with previous failures as context (defaults to uncommitted changes)",
21
+ )
22
+ .option(
23
+ "-b, --base-branch <branch>",
24
+ "Override base branch for change detection",
25
+ )
26
+ .option("-g, --gate <name>", "Run specific gate only")
27
+ .option(
28
+ "-c, --commit <sha>",
29
+ "Use diff for a specific commit (overrides default uncommitted mode)",
30
+ )
31
+ .action(async (options) => {
32
+ try {
33
+ const config = await loadConfig();
34
+
35
+ // Parse previous failures from log files (only for review gates)
36
+ console.log(chalk.dim("Analyzing previous runs..."));
37
+
38
+ // findPreviousFailures handles errors internally and returns empty array on failure
39
+ const previousFailures = await findPreviousFailures(
40
+ config.project.log_dir,
41
+ options.gate,
42
+ );
43
+
44
+ // Create a map: jobId -> (adapterName -> violations)
45
+ const failuresMap = new Map<string, Map<string, PreviousViolation[]>>();
46
+ for (const gateFailure of previousFailures) {
47
+ const adapterMap = new Map<string, PreviousViolation[]>();
48
+ for (const adapterFailure of gateFailure.adapterFailures) {
49
+ adapterMap.set(
50
+ adapterFailure.adapterName,
51
+ adapterFailure.violations,
52
+ );
53
+ }
54
+ failuresMap.set(gateFailure.jobId, adapterMap);
55
+ }
56
+
57
+ if (previousFailures.length > 0) {
58
+ const totalViolations = previousFailures.reduce(
59
+ (sum, gf) =>
60
+ sum +
61
+ gf.adapterFailures.reduce((s, af) => s + af.violations.length, 0),
62
+ 0,
63
+ );
64
+ console.log(
65
+ chalk.yellow(
66
+ `Found ${previousFailures.length} gate(s) with ${totalViolations} previous violation(s)`,
67
+ ),
68
+ );
69
+ } else {
70
+ console.log(
71
+ chalk.dim("No previous failures found. Running as normal..."),
72
+ );
73
+ }
74
+
75
+ // Rotate logs before starting the new run
76
+ await rotateLogs(config.project.log_dir);
77
+
78
+ // Determine effective base branch
79
+ // Priority: CLI override > CI env var > config
80
+ const effectiveBaseBranch =
81
+ options.baseBranch ||
82
+ (process.env.GITHUB_BASE_REF &&
83
+ (process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true")
84
+ ? process.env.GITHUB_BASE_REF
85
+ : null) ||
86
+ config.project.base_branch;
87
+
88
+ // Detect changes (default to uncommitted unless --commit is specified)
89
+ // Note: Rerun defaults to uncommitted changes for faster iteration loops,
90
+ // unlike 'run' which defaults to base_branch comparison.
91
+ const changeOptions = {
92
+ commit: options.commit,
93
+ uncommitted: !options.commit, // Default to uncommitted unless commit is specified
94
+ };
95
+
96
+ const changeDetector = new ChangeDetector(
97
+ effectiveBaseBranch,
98
+ changeOptions,
99
+ );
100
+ const expander = new EntryPointExpander();
101
+ const jobGen = new JobGenerator(config);
102
+
103
+ const modeDesc = options.commit
104
+ ? `commit ${options.commit}`
105
+ : "uncommitted changes";
106
+ console.log(chalk.dim(`Detecting changes (${modeDesc})...`));
107
+
108
+ const changes = await changeDetector.getChangedFiles();
109
+
110
+ if (changes.length === 0) {
111
+ console.log(chalk.green("No changes detected."));
112
+ process.exit(0);
113
+ }
114
+
115
+ console.log(chalk.dim(`Found ${changes.length} changed files.`));
116
+
117
+ const entryPoints = await expander.expand(
118
+ config.project.entry_points,
119
+ changes,
120
+ );
121
+ let jobs = jobGen.generateJobs(entryPoints);
122
+
123
+ if (options.gate) {
124
+ jobs = jobs.filter((j) => j.name === options.gate);
125
+ }
126
+
127
+ if (jobs.length === 0) {
128
+ console.log(chalk.yellow("No applicable gates for these changes."));
129
+ process.exit(0);
130
+ }
131
+
132
+ console.log(chalk.dim(`Running ${jobs.length} gates...`));
133
+ if (previousFailures.length > 0) {
134
+ console.log(
135
+ chalk.dim(
136
+ "Previous failures will be injected as context for matching reviewers.",
137
+ ),
138
+ );
139
+ }
140
+
141
+ const logger = new Logger(config.project.log_dir);
142
+ const reporter = new ConsoleReporter();
143
+ const runner = new Runner(
144
+ config,
145
+ logger,
146
+ reporter,
147
+ failuresMap, // Pass previous failures map
148
+ changeOptions, // Pass change detection options
149
+ effectiveBaseBranch, // Pass effective base branch
150
+ );
151
+
152
+ const success = await runner.run(jobs);
153
+ process.exit(success ? 0 : 1);
154
+ } catch (error: unknown) {
155
+ const err = error as { message?: string };
156
+ console.error(chalk.red("Error:"), err.message);
157
+ process.exit(1);
158
+ }
159
+ });
122
160
  }
@@ -1,25 +1,31 @@
1
- import { describe, it, expect, beforeEach } from 'bun:test';
2
- import { Command } from 'commander';
3
- import { registerReviewCommand } from './review.js';
1
+ import { beforeEach, describe, expect, it } from "bun:test";
2
+ import { Command } from "commander";
3
+ import { registerReviewCommand } from "./review.js";
4
4
 
5
- describe('Review Command', () => {
6
- let program: Command;
5
+ describe("Review Command", () => {
6
+ let program: Command;
7
7
 
8
- beforeEach(() => {
9
- program = new Command();
10
- registerReviewCommand(program);
11
- });
8
+ beforeEach(() => {
9
+ program = new Command();
10
+ registerReviewCommand(program);
11
+ });
12
12
 
13
- it('should register the review command', () => {
14
- const reviewCmd = program.commands.find(cmd => cmd.name() === 'review');
15
- expect(reviewCmd).toBeDefined();
16
- expect(reviewCmd?.description()).toBe('Run only applicable reviews for detected changes');
17
- });
13
+ it("should register the review command", () => {
14
+ const reviewCmd = program.commands.find((cmd) => cmd.name() === "review");
15
+ expect(reviewCmd).toBeDefined();
16
+ expect(reviewCmd?.description()).toBe(
17
+ "Run only applicable reviews for detected changes",
18
+ );
19
+ });
18
20
 
19
- it('should have correct options', () => {
20
- const reviewCmd = program.commands.find(cmd => cmd.name() === 'review');
21
- expect(reviewCmd?.options.some(opt => opt.long === '--gate')).toBe(true);
22
- expect(reviewCmd?.options.some(opt => opt.long === '--commit')).toBe(true);
23
- expect(reviewCmd?.options.some(opt => opt.long === '--uncommitted')).toBe(true);
24
- });
21
+ it("should have correct options", () => {
22
+ const reviewCmd = program.commands.find((cmd) => cmd.name() === "review");
23
+ expect(reviewCmd?.options.some((opt) => opt.long === "--gate")).toBe(true);
24
+ expect(reviewCmd?.options.some((opt) => opt.long === "--commit")).toBe(
25
+ true,
26
+ );
27
+ expect(reviewCmd?.options.some((opt) => opt.long === "--uncommitted")).toBe(
28
+ true,
29
+ );
30
+ });
25
31
  });