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,117 +1,130 @@
1
- import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll, mock } from 'bun:test';
2
- import { Command } from 'commander';
3
- import fs from 'node:fs/promises';
4
- import path from 'node:path';
1
+ import {
2
+ afterAll,
3
+ afterEach,
4
+ beforeAll,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ it,
9
+ mock,
10
+ } from "bun:test";
11
+ import fs from "node:fs/promises";
12
+ import path from "node:path";
13
+ import { Command } from "commander";
5
14
 
6
- const TEST_DIR = path.join(process.cwd(), 'test-init-' + Date.now());
15
+ const TEST_DIR = path.join(process.cwd(), `test-init-${Date.now()}`);
7
16
 
8
17
  // Mock adapters
9
18
  const mockAdapters = [
10
- {
11
- name: 'mock-cli-1',
12
- isAvailable: async () => true,
13
- getProjectCommandDir: () => '.mock1',
14
- getUserCommandDir: () => null,
15
- getCommandExtension: () => '.sh',
16
- canUseSymlink: () => false,
17
- transformCommand: (content: string) => content,
18
- },
19
- {
20
- name: 'mock-cli-2',
21
- isAvailable: async () => false, // Not available
22
- getProjectCommandDir: () => '.mock2',
23
- getUserCommandDir: () => null,
24
- getCommandExtension: () => '.sh',
25
- canUseSymlink: () => false,
26
- transformCommand: (content: string) => content,
27
- }
19
+ {
20
+ name: "mock-cli-1",
21
+ isAvailable: async () => true,
22
+ getProjectCommandDir: () => ".mock1",
23
+ getUserCommandDir: () => null,
24
+ getCommandExtension: () => ".sh",
25
+ canUseSymlink: () => false,
26
+ transformCommand: (content: string) => content,
27
+ },
28
+ {
29
+ name: "mock-cli-2",
30
+ isAvailable: async () => false, // Not available
31
+ getProjectCommandDir: () => ".mock2",
32
+ getUserCommandDir: () => null,
33
+ getCommandExtension: () => ".sh",
34
+ canUseSymlink: () => false,
35
+ transformCommand: (content: string) => content,
36
+ },
28
37
  ];
29
38
 
30
- mock.module('../cli-adapters/index.js', () => ({
31
- getAllAdapters: () => mockAdapters,
32
- getProjectCommandAdapters: () => mockAdapters,
33
- getUserCommandAdapters: () => [],
39
+ mock.module("../cli-adapters/index.js", () => ({
40
+ getAllAdapters: () => mockAdapters,
41
+ getProjectCommandAdapters: () => mockAdapters,
42
+ getUserCommandAdapters: () => [],
43
+ getAdapter: (name: string) => mockAdapters.find((a) => a.name === name),
44
+ getValidCLITools: () => mockAdapters.map((a) => a.name),
34
45
  }));
35
46
 
36
47
  // Import after mocking
37
- const { registerInitCommand } = await import('./init.js');
38
-
39
- describe('Init Command', () => {
40
- let program: Command;
41
- const originalConsoleLog = console.log;
42
- const originalCwd = process.cwd();
43
- let logs: string[];
44
-
45
- beforeAll(async () => {
46
- await fs.mkdir(TEST_DIR, { recursive: true });
47
- });
48
-
49
- afterAll(async () => {
50
- await fs.rm(TEST_DIR, { recursive: true, force: true });
51
- });
52
-
53
- beforeEach(() => {
54
- program = new Command();
55
- registerInitCommand(program);
56
- logs = [];
57
- console.log = (...args: any[]) => {
58
- logs.push(args.join(' '));
59
- };
60
- process.chdir(TEST_DIR);
61
- });
62
-
63
- afterEach(() => {
64
- console.log = originalConsoleLog;
65
- process.chdir(originalCwd);
66
- // Cleanup any created .gauntlet directory
67
- return fs.rm(path.join(TEST_DIR, '.gauntlet'), { recursive: true, force: true }).catch(() => {});
68
- });
69
-
70
- it('should register the init command', () => {
71
- const initCmd = program.commands.find(cmd => cmd.name() === 'init');
72
- expect(initCmd).toBeDefined();
73
- expect(initCmd?.description()).toBe('Initialize .gauntlet configuration');
74
- expect(initCmd?.options.some(opt => opt.long === '--yes')).toBe(true);
75
- });
76
-
77
- it('should create .gauntlet directory structure with --yes flag', async () => {
78
- // We expect it to use the available mock-cli-1
79
- await program.parseAsync(['node', 'test', 'init', '--yes']);
80
-
81
- // Check that files were created
82
- const gauntletDir = path.join(TEST_DIR, '.gauntlet');
83
- const configFile = path.join(gauntletDir, 'config.yml');
84
- const reviewsDir = path.join(gauntletDir, 'reviews');
85
- const checksDir = path.join(gauntletDir, 'checks');
86
- const runGauntletFile = path.join(gauntletDir, 'run_gauntlet.md');
87
-
88
- expect(await fs.stat(gauntletDir)).toBeDefined();
89
- expect(await fs.stat(configFile)).toBeDefined();
90
- expect(await fs.stat(reviewsDir)).toBeDefined();
91
- expect(await fs.stat(checksDir)).toBeDefined();
92
- expect(await fs.stat(runGauntletFile)).toBeDefined();
93
-
94
- // Verify config content
95
- const configContent = await fs.readFile(configFile, 'utf-8');
96
- expect(configContent).toContain('base_branch');
97
- expect(configContent).toContain('log_dir');
98
- expect(configContent).toContain('mock-cli-1'); // Should be present
99
- expect(configContent).not.toContain('mock-cli-2'); // Should not be present (unavailable)
100
-
101
- // Verify review file content
102
- const reviewFile = path.join(reviewsDir, 'code-quality.md');
103
- const reviewContent = await fs.readFile(reviewFile, 'utf-8');
104
- expect(reviewContent).toContain('mock-cli-1');
105
- });
106
-
107
- it('should not create directory if .gauntlet already exists', async () => {
108
- // Create .gauntlet directory first
109
- const gauntletDir = path.join(TEST_DIR, '.gauntlet');
110
- await fs.mkdir(gauntletDir, { recursive: true });
111
-
112
- await program.parseAsync(['node', 'test', 'init', '--yes']);
113
-
114
- const output = logs.join('\n');
115
- expect(output).toContain('.gauntlet directory already exists');
116
- });
48
+ const { registerInitCommand } = await import("./init.js");
49
+
50
+ describe("Init Command", () => {
51
+ let program: Command;
52
+ const originalConsoleLog = console.log;
53
+ const originalCwd = process.cwd();
54
+ let logs: string[];
55
+
56
+ beforeAll(async () => {
57
+ await fs.mkdir(TEST_DIR, { recursive: true });
58
+ });
59
+
60
+ afterAll(async () => {
61
+ await fs.rm(TEST_DIR, { recursive: true, force: true });
62
+ });
63
+
64
+ beforeEach(() => {
65
+ program = new Command();
66
+ registerInitCommand(program);
67
+ logs = [];
68
+ console.log = (...args: unknown[]) => {
69
+ logs.push(args.join(" "));
70
+ };
71
+ process.chdir(TEST_DIR);
72
+ });
73
+
74
+ afterEach(() => {
75
+ console.log = originalConsoleLog;
76
+ process.chdir(originalCwd);
77
+ // Cleanup any created .gauntlet directory
78
+ return fs
79
+ .rm(path.join(TEST_DIR, ".gauntlet"), { recursive: true, force: true })
80
+ .catch(() => {});
81
+ });
82
+
83
+ it("should register the init command", () => {
84
+ const initCmd = program.commands.find((cmd) => cmd.name() === "init");
85
+ expect(initCmd).toBeDefined();
86
+ expect(initCmd?.description()).toBe("Initialize .gauntlet configuration");
87
+ expect(initCmd?.options.some((opt) => opt.long === "--yes")).toBe(true);
88
+ });
89
+
90
+ it("should create .gauntlet directory structure with --yes flag", async () => {
91
+ // We expect it to use the available mock-cli-1
92
+ await program.parseAsync(["node", "test", "init", "--yes"]);
93
+
94
+ // Check that files were created
95
+ const gauntletDir = path.join(TEST_DIR, ".gauntlet");
96
+ const configFile = path.join(gauntletDir, "config.yml");
97
+ const reviewsDir = path.join(gauntletDir, "reviews");
98
+ const checksDir = path.join(gauntletDir, "checks");
99
+ const runGauntletFile = path.join(gauntletDir, "run_gauntlet.md");
100
+
101
+ expect(await fs.stat(gauntletDir)).toBeDefined();
102
+ expect(await fs.stat(configFile)).toBeDefined();
103
+ expect(await fs.stat(reviewsDir)).toBeDefined();
104
+ expect(await fs.stat(checksDir)).toBeDefined();
105
+ expect(await fs.stat(runGauntletFile)).toBeDefined();
106
+
107
+ // Verify config content
108
+ const configContent = await fs.readFile(configFile, "utf-8");
109
+ expect(configContent).toContain("base_branch");
110
+ expect(configContent).toContain("log_dir");
111
+ expect(configContent).toContain("mock-cli-1"); // Should be present
112
+ expect(configContent).not.toContain("mock-cli-2"); // Should not be present (unavailable)
113
+
114
+ // Verify review file content
115
+ const reviewFile = path.join(reviewsDir, "code-quality.md");
116
+ const reviewContent = await fs.readFile(reviewFile, "utf-8");
117
+ expect(reviewContent).toContain("mock-cli-1");
118
+ });
119
+
120
+ it("should not create directory if .gauntlet already exists", async () => {
121
+ // Create .gauntlet directory first
122
+ const gauntletDir = path.join(TEST_DIR, ".gauntlet");
123
+ await fs.mkdir(gauntletDir, { recursive: true });
124
+
125
+ await program.parseAsync(["node", "test", "init", "--yes"]);
126
+
127
+ const output = logs.join("\n");
128
+ expect(output).toContain(".gauntlet directory already exists");
129
+ });
117
130
  });