agent-gauntlet 0.10.0 → 0.11.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 (71) hide show
  1. package/README.md +25 -23
  2. package/dist/index.js +9226 -0
  3. package/dist/index.js.map +65 -0
  4. package/dist/scripts/status.js +280 -0
  5. package/dist/scripts/status.js.map +10 -0
  6. package/package.json +22 -8
  7. package/src/built-in-reviews/code-quality.md +0 -25
  8. package/src/built-in-reviews/index.ts +0 -28
  9. package/src/bun-plugins.d.ts +0 -4
  10. package/src/cli-adapters/claude.ts +0 -327
  11. package/src/cli-adapters/codex.ts +0 -290
  12. package/src/cli-adapters/cursor.ts +0 -128
  13. package/src/cli-adapters/gemini.ts +0 -510
  14. package/src/cli-adapters/github-copilot.ts +0 -141
  15. package/src/cli-adapters/index.ts +0 -250
  16. package/src/cli-adapters/thinking-budget.ts +0 -23
  17. package/src/commands/check.ts +0 -311
  18. package/src/commands/ci/index.ts +0 -15
  19. package/src/commands/ci/init.ts +0 -96
  20. package/src/commands/ci/list-jobs.ts +0 -90
  21. package/src/commands/clean.ts +0 -54
  22. package/src/commands/detect.ts +0 -173
  23. package/src/commands/health.ts +0 -169
  24. package/src/commands/help.ts +0 -34
  25. package/src/commands/index.ts +0 -13
  26. package/src/commands/init.ts +0 -1878
  27. package/src/commands/list.ts +0 -33
  28. package/src/commands/review.ts +0 -311
  29. package/src/commands/run.ts +0 -29
  30. package/src/commands/shared.ts +0 -267
  31. package/src/commands/stop-hook.ts +0 -567
  32. package/src/commands/validate.ts +0 -20
  33. package/src/commands/wait-ci.ts +0 -518
  34. package/src/config/ci-loader.ts +0 -33
  35. package/src/config/ci-schema.ts +0 -28
  36. package/src/config/global.ts +0 -87
  37. package/src/config/loader.ts +0 -301
  38. package/src/config/schema.ts +0 -165
  39. package/src/config/stop-hook-config.ts +0 -130
  40. package/src/config/types.ts +0 -65
  41. package/src/config/validator.ts +0 -592
  42. package/src/core/change-detector.ts +0 -137
  43. package/src/core/diff-stats.ts +0 -442
  44. package/src/core/entry-point.ts +0 -190
  45. package/src/core/job.ts +0 -96
  46. package/src/core/run-executor.ts +0 -621
  47. package/src/core/runner.ts +0 -290
  48. package/src/gates/check.ts +0 -118
  49. package/src/gates/resolve-check-command.ts +0 -21
  50. package/src/gates/result.ts +0 -54
  51. package/src/gates/review.ts +0 -1333
  52. package/src/hooks/adapters/claude-stop-hook.ts +0 -99
  53. package/src/hooks/adapters/cursor-stop-hook.ts +0 -122
  54. package/src/hooks/adapters/types.ts +0 -94
  55. package/src/hooks/stop-hook-handler.ts +0 -748
  56. package/src/index.ts +0 -47
  57. package/src/output/app-logger.ts +0 -214
  58. package/src/output/console-log.ts +0 -168
  59. package/src/output/console.ts +0 -359
  60. package/src/output/logger.ts +0 -126
  61. package/src/output/sinks/console-sink.ts +0 -59
  62. package/src/output/sinks/file-sink.ts +0 -110
  63. package/src/scripts/status.ts +0 -433
  64. package/src/templates/workflow.yml +0 -79
  65. package/src/types/gauntlet-status.ts +0 -79
  66. package/src/utils/debug-log.ts +0 -392
  67. package/src/utils/diff-parser.ts +0 -103
  68. package/src/utils/execution-state.ts +0 -472
  69. package/src/utils/log-parser.ts +0 -696
  70. package/src/utils/sanitizer.ts +0 -3
  71. package/src/utils/session-ref.ts +0 -91
package/src/index.ts DELETED
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { Command } from "commander";
3
- import packageJson from "../package.json" with { type: "json" };
4
- import {
5
- registerCheckCommand,
6
- registerCICommand,
7
- registerCleanCommand,
8
- registerDetectCommand,
9
- registerHealthCommand,
10
- registerHelpCommand,
11
- registerInitCommand,
12
- registerListCommand,
13
- registerReviewCommand,
14
- registerRunCommand,
15
- registerStopHookCommand,
16
- registerValidateCommand,
17
- registerWaitCICommand,
18
- } from "./commands/index.js";
19
-
20
- const program = new Command();
21
-
22
- program
23
- .name("agent-gauntlet")
24
- .description("AI-assisted quality gates")
25
- .version(packageJson.version);
26
-
27
- // Register all commands
28
- registerRunCommand(program);
29
- registerCheckCommand(program);
30
- registerCICommand(program);
31
- registerCleanCommand(program);
32
- registerReviewCommand(program);
33
- registerDetectCommand(program);
34
- registerListCommand(program);
35
- registerHealthCommand(program);
36
- registerInitCommand(program);
37
- registerValidateCommand(program);
38
- registerStopHookCommand(program);
39
- registerWaitCICommand(program);
40
- registerHelpCommand(program);
41
-
42
- // Default action: help
43
- if (process.argv.length < 3) {
44
- process.argv.push("help");
45
- }
46
-
47
- program.parse(process.argv);
@@ -1,214 +0,0 @@
1
- import fs from "node:fs";
2
- import fsPromises from "node:fs/promises";
3
- import path from "node:path";
4
- import {
5
- configure,
6
- getLogger,
7
- type LogRecord,
8
- type Logger as LogTapeLogger,
9
- } from "@logtape/logtape";
10
- import { createConsoleSink } from "./sinks/console-sink.js";
11
-
12
- /**
13
- * Logger modes that determine sink configuration:
14
- * - "interactive": Console output to stderr (file capture via console-log.ts)
15
- * - "stop-hook": NO console output (JSON protocol on stdout must be clean)
16
- * - "ci": Console output to stderr
17
- */
18
- export type LoggerMode = "interactive" | "stop-hook" | "ci";
19
-
20
- /**
21
- * Log level options.
22
- */
23
- export type LogLevel = "debug" | "info" | "warning" | "error";
24
-
25
- /**
26
- * App logger configuration options.
27
- */
28
- export interface AppLoggerConfig {
29
- mode: LoggerMode;
30
- logDir?: string;
31
- level?: LogLevel;
32
- debugLog?: {
33
- enabled: boolean;
34
- maxSizeMb?: number;
35
- };
36
- }
37
-
38
- // Global state for cleanup (file descriptor for debug log, configuration flag)
39
- let debugLogFd: number | null = null;
40
- let isConfigured = false;
41
-
42
- /**
43
- * Safely serialize a value, handling circular references.
44
- */
45
- function safeStringify(value: unknown): string {
46
- try {
47
- return JSON.stringify(value);
48
- } catch {
49
- return "[Unserializable]";
50
- }
51
- }
52
-
53
- /**
54
- * Create a debug log sink that writes to .debug.log file.
55
- * Format matches existing DebugLogger: [ISO_TIMESTAMP] message
56
- */
57
- function createDebugLogSink(logDir: string): (record: LogRecord) => void {
58
- const debugLogPath = path.join(logDir, ".debug.log");
59
-
60
- // Open file for append
61
- debugLogFd = fs.openSync(
62
- debugLogPath,
63
- fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_APPEND,
64
- );
65
-
66
- return (record: LogRecord) => {
67
- if (debugLogFd === null) return;
68
-
69
- const timestamp = new Date(record.timestamp).toISOString();
70
- const level = record.level.toUpperCase();
71
- const category = record.category.join(".");
72
- const message = record.message
73
- .map((part) => (typeof part === "string" ? part : safeStringify(part)))
74
- .join("");
75
-
76
- const line = `[${timestamp}] ${level} [${category}] ${message}\n`;
77
-
78
- try {
79
- fs.writeSync(debugLogFd, line);
80
- } catch {
81
- // Suppress write errors
82
- }
83
- };
84
- }
85
-
86
- /**
87
- * Initialize the application logger with LogTape.
88
- *
89
- * IMPORTANT: In stop-hook mode, NO console output is generated.
90
- * stdout must remain clean for the JSON protocol response.
91
- * File logging is handled separately by console-log.ts which captures stderr.
92
- *
93
- * @param config - Logger configuration
94
- * @returns Promise that resolves when logger is configured
95
- */
96
- export async function initLogger(config: AppLoggerConfig): Promise<void> {
97
- // Reset if already configured
98
- if (isConfigured) {
99
- await resetLogger();
100
- }
101
-
102
- const { mode, level = "info", logDir, debugLog } = config;
103
-
104
- // Ensure log directory exists if we need it for debug log
105
- if (logDir && debugLog?.enabled) {
106
- await fsPromises.mkdir(logDir, { recursive: true });
107
- }
108
-
109
- // Build sink configuration
110
- const sinks: Record<string, (record: LogRecord) => void> = {};
111
- const activeSinks: string[] = [];
112
-
113
- // Console sink (only for interactive and ci modes)
114
- // Outputs to stderr, which gets captured by console-log.ts
115
- if (mode !== "stop-hook") {
116
- sinks.console = createConsoleSink();
117
- activeSinks.push("console");
118
- }
119
-
120
- // Debug log sink (writes directly to .debug.log)
121
- if (logDir && debugLog?.enabled) {
122
- sinks.debugLog = createDebugLogSink(logDir);
123
- activeSinks.push("debugLog");
124
- }
125
-
126
- // Configure LogTape (reset: true needed if LogTape was previously configured)
127
- // IMPORTANT: Configure the meta logger to suppress its default stdout output.
128
- // Without this, LogTape writes "LogTape loggers are configured..." to stdout,
129
- // which breaks the stop-hook JSON protocol.
130
- try {
131
- await configure({
132
- sinks,
133
- loggers: [
134
- {
135
- category: ["gauntlet"],
136
- lowestLevel: level,
137
- sinks: activeSinks,
138
- },
139
- {
140
- // Suppress LogTape's internal meta logger (writes to stdout by default)
141
- category: ["logtape", "meta"],
142
- lowestLevel: "fatal",
143
- sinks: [],
144
- },
145
- ],
146
- reset: true,
147
- });
148
- isConfigured = true;
149
- } catch (error) {
150
- // Close debug log fd if initialization fails to prevent leaks
151
- if (debugLogFd !== null) {
152
- try {
153
- fs.closeSync(debugLogFd);
154
- } catch {
155
- // Ignore close errors
156
- }
157
- debugLogFd = null;
158
- }
159
- throw error;
160
- }
161
- }
162
-
163
- /**
164
- * Reset the logger configuration and close file handles.
165
- */
166
- export async function resetLogger(): Promise<void> {
167
- if (debugLogFd !== null) {
168
- try {
169
- fs.closeSync(debugLogFd);
170
- } catch {
171
- // Ignore close errors
172
- }
173
- debugLogFd = null;
174
- }
175
-
176
- // Reset LogTape configuration (reset: true required after initial configure)
177
- // Also suppress meta logger to avoid stdout pollution
178
- await configure({
179
- sinks: {},
180
- loggers: [
181
- {
182
- category: ["logtape", "meta"],
183
- lowestLevel: "fatal",
184
- sinks: [],
185
- },
186
- ],
187
- reset: true,
188
- });
189
- isConfigured = false;
190
- }
191
-
192
- /**
193
- * Get the root application logger.
194
- */
195
- export function getAppLogger(): LogTapeLogger {
196
- return getLogger(["gauntlet"]);
197
- }
198
-
199
- /**
200
- * Get a child logger for a specific category.
201
- * Categories are hierarchical, e.g., ["gauntlet", "runner"] or ["gauntlet", "gate", "check"]
202
- *
203
- * @param category - The category path (after "gauntlet" prefix)
204
- */
205
- export function getCategoryLogger(...category: string[]): LogTapeLogger {
206
- return getLogger(["gauntlet", ...category]);
207
- }
208
-
209
- /**
210
- * Check if the logger has been configured.
211
- */
212
- export function isLoggerConfigured(): boolean {
213
- return isConfigured;
214
- }
@@ -1,168 +0,0 @@
1
- import fs from "node:fs";
2
- import fsPromises from "node:fs/promises";
3
- import path from "node:path";
4
- import { inspect } from "node:util";
5
-
6
- // biome-ignore lint/suspicious/noControlCharactersInRegex: Required for ANSI escape code stripping
7
- const ANSI_REGEX = /\x1b\[[0-9;]*m/g;
8
-
9
- function stripAnsi(text: string): string {
10
- return text.replace(ANSI_REGEX, "");
11
- }
12
-
13
- function formatArgs(args: unknown[]): string {
14
- return args
15
- .map((a) => (typeof a === "string" ? a : inspect(a, { depth: 4 })))
16
- .join(" ");
17
- }
18
-
19
- function openLogFileExclusive(
20
- logDir: string,
21
- runNum: number,
22
- ): { fd: number; logPath: string } {
23
- const logPath = path.join(logDir, `console.${runNum}.log`);
24
- try {
25
- const fd = fs.openSync(
26
- logPath,
27
- fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL,
28
- );
29
- return { fd, logPath };
30
- } catch (e: unknown) {
31
- const error = e as { code?: string };
32
- if (error.code === "EEXIST") {
33
- // If file exists, something is wrong with our numbering logic
34
- // Log warning and try incrementing as fallback
35
- console.error(`Warning: console.${runNum}.log already exists`);
36
- return openLogFileFallback(logDir, runNum + 1);
37
- }
38
- throw e;
39
- }
40
- }
41
-
42
- function openLogFileFallback(
43
- logDir: string,
44
- startNum: number,
45
- ): { fd: number; logPath: string } {
46
- let runNum = startNum;
47
- for (let attempts = 0; attempts < 100; attempts++) {
48
- const logPath = path.join(logDir, `console.${runNum}.log`);
49
- try {
50
- const fd = fs.openSync(
51
- logPath,
52
- fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL,
53
- );
54
- return { fd, logPath };
55
- } catch (e: unknown) {
56
- const error = e as { code?: string };
57
- if (error.code === "EEXIST") {
58
- runNum++;
59
- continue;
60
- }
61
- throw e;
62
- }
63
- }
64
- throw new Error("Failed to create console log file after 100 attempts");
65
- }
66
-
67
- export interface ConsoleLogHandle {
68
- /** Restore original console functions */
69
- restore: () => void;
70
- /** Write directly to the log file without terminal output */
71
- writeToLogOnly: (text: string) => void;
72
- }
73
-
74
- /**
75
- * Start console logging with unified run numbering.
76
- * @param logDir The directory to write logs to
77
- * @param runNumber The run number from Logger (ensures console.N.log matches check.N.log)
78
- */
79
- export async function startConsoleLog(
80
- logDir: string,
81
- runNumber: number,
82
- ): Promise<ConsoleLogHandle> {
83
- await fsPromises.mkdir(logDir, { recursive: true });
84
- const { fd } = openLogFileExclusive(logDir, runNumber);
85
-
86
- try {
87
- const originalLog = console.log;
88
- const originalError = console.error;
89
- const originalWarn = console.warn;
90
- const originalStdoutWrite = process.stdout.write.bind(process.stdout);
91
- const originalStderrWrite = process.stderr.write.bind(process.stderr);
92
-
93
- let isClosed = false;
94
-
95
- function writeToLog(text: string): void {
96
- if (isClosed) return;
97
- try {
98
- fs.writeSync(fd, stripAnsi(text));
99
- } catch {
100
- // Suppress logging failures to prevent crashing the application
101
- }
102
- }
103
-
104
- // Only patch console methods in bun (bun's console.log bypasses stdout.write)
105
- // In Node.js, console.log goes through stdout.write, so patching both would cause double logging
106
- const isBun = typeof globalThis.Bun !== "undefined";
107
- if (isBun) {
108
- console.log = (...args: unknown[]) => {
109
- writeToLog(`${formatArgs(args)}\n`);
110
- originalLog(...args);
111
- };
112
-
113
- console.error = (...args: unknown[]) => {
114
- writeToLog(`${formatArgs(args)}\n`);
115
- originalError(...args);
116
- };
117
-
118
- console.warn = (...args: unknown[]) => {
119
- writeToLog(`${formatArgs(args)}\n`);
120
- originalWarn(...args);
121
- };
122
- }
123
-
124
- process.stdout.write = ((
125
- chunk: string | Uint8Array,
126
- ...args: unknown[]
127
- ): boolean => {
128
- const text =
129
- typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
130
- writeToLog(text);
131
- return originalStdoutWrite(chunk, ...(args as []));
132
- }) as typeof process.stdout.write;
133
-
134
- process.stderr.write = ((
135
- chunk: string | Uint8Array,
136
- ...args: unknown[]
137
- ): boolean => {
138
- const text =
139
- typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
140
- writeToLog(text);
141
- return originalStderrWrite(chunk, ...(args as []));
142
- }) as typeof process.stderr.write;
143
-
144
- return {
145
- restore: () => {
146
- isClosed = true;
147
- if (isBun) {
148
- console.log = originalLog;
149
- console.error = originalError;
150
- console.warn = originalWarn;
151
- }
152
- process.stdout.write = originalStdoutWrite;
153
- process.stderr.write = originalStderrWrite;
154
- try {
155
- fs.closeSync(fd);
156
- } catch {
157
- // Ignore close errors
158
- }
159
- },
160
- writeToLogOnly: (text: string) => {
161
- writeToLog(text);
162
- },
163
- };
164
- } catch (error) {
165
- fs.closeSync(fd);
166
- throw error;
167
- }
168
- }