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.
- package/README.md +25 -23
- package/dist/index.js +9226 -0
- package/dist/index.js.map +65 -0
- package/dist/scripts/status.js +280 -0
- package/dist/scripts/status.js.map +10 -0
- package/package.json +22 -8
- package/src/built-in-reviews/code-quality.md +0 -25
- package/src/built-in-reviews/index.ts +0 -28
- package/src/bun-plugins.d.ts +0 -4
- package/src/cli-adapters/claude.ts +0 -327
- package/src/cli-adapters/codex.ts +0 -290
- package/src/cli-adapters/cursor.ts +0 -128
- package/src/cli-adapters/gemini.ts +0 -510
- package/src/cli-adapters/github-copilot.ts +0 -141
- package/src/cli-adapters/index.ts +0 -250
- package/src/cli-adapters/thinking-budget.ts +0 -23
- package/src/commands/check.ts +0 -311
- package/src/commands/ci/index.ts +0 -15
- package/src/commands/ci/init.ts +0 -96
- package/src/commands/ci/list-jobs.ts +0 -90
- package/src/commands/clean.ts +0 -54
- package/src/commands/detect.ts +0 -173
- package/src/commands/health.ts +0 -169
- package/src/commands/help.ts +0 -34
- package/src/commands/index.ts +0 -13
- package/src/commands/init.ts +0 -1878
- package/src/commands/list.ts +0 -33
- package/src/commands/review.ts +0 -311
- package/src/commands/run.ts +0 -29
- package/src/commands/shared.ts +0 -267
- package/src/commands/stop-hook.ts +0 -567
- package/src/commands/validate.ts +0 -20
- package/src/commands/wait-ci.ts +0 -518
- package/src/config/ci-loader.ts +0 -33
- package/src/config/ci-schema.ts +0 -28
- package/src/config/global.ts +0 -87
- package/src/config/loader.ts +0 -301
- package/src/config/schema.ts +0 -165
- package/src/config/stop-hook-config.ts +0 -130
- package/src/config/types.ts +0 -65
- package/src/config/validator.ts +0 -592
- package/src/core/change-detector.ts +0 -137
- package/src/core/diff-stats.ts +0 -442
- package/src/core/entry-point.ts +0 -190
- package/src/core/job.ts +0 -96
- package/src/core/run-executor.ts +0 -621
- package/src/core/runner.ts +0 -290
- package/src/gates/check.ts +0 -118
- package/src/gates/resolve-check-command.ts +0 -21
- package/src/gates/result.ts +0 -54
- package/src/gates/review.ts +0 -1333
- package/src/hooks/adapters/claude-stop-hook.ts +0 -99
- package/src/hooks/adapters/cursor-stop-hook.ts +0 -122
- package/src/hooks/adapters/types.ts +0 -94
- package/src/hooks/stop-hook-handler.ts +0 -748
- package/src/index.ts +0 -47
- package/src/output/app-logger.ts +0 -214
- package/src/output/console-log.ts +0 -168
- package/src/output/console.ts +0 -359
- package/src/output/logger.ts +0 -126
- package/src/output/sinks/console-sink.ts +0 -59
- package/src/output/sinks/file-sink.ts +0 -110
- package/src/scripts/status.ts +0 -433
- package/src/templates/workflow.yml +0 -79
- package/src/types/gauntlet-status.ts +0 -79
- package/src/utils/debug-log.ts +0 -392
- package/src/utils/diff-parser.ts +0 -103
- package/src/utils/execution-state.ts +0 -472
- package/src/utils/log-parser.ts +0 -696
- package/src/utils/sanitizer.ts +0 -3
- package/src/utils/session-ref.ts +0 -91
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
StopHookAdapter,
|
|
3
|
-
StopHookContext,
|
|
4
|
-
StopHookResult,
|
|
5
|
-
} from "./types.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Claude Code hook response format.
|
|
9
|
-
*/
|
|
10
|
-
interface ClaudeHookResponse {
|
|
11
|
-
decision: "block" | "approve";
|
|
12
|
-
reason?: string;
|
|
13
|
-
stopReason: string;
|
|
14
|
-
systemMessage?: string;
|
|
15
|
-
status: string;
|
|
16
|
-
message: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Adapter for Claude Code stop hook protocol.
|
|
21
|
-
*
|
|
22
|
-
* Claude Code protocol:
|
|
23
|
-
* - Input: { cwd, stop_hook_active, session_id, transcript_path, hook_event_name, permission_mode }
|
|
24
|
-
* - Output: { decision: "block"|"approve", reason?, stopReason, systemMessage?, status, message }
|
|
25
|
-
* - Block mechanism: decision: "block" with reason (fed back to Claude as prompt)
|
|
26
|
-
* - Allow mechanism: decision: "approve"
|
|
27
|
-
*/
|
|
28
|
-
export class ClaudeStopHookAdapter implements StopHookAdapter {
|
|
29
|
-
name = "claude";
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Detect if this adapter should handle the given input.
|
|
33
|
-
* Claude Code doesn't send cursor_version, so we detect by absence.
|
|
34
|
-
*/
|
|
35
|
-
detect(raw: Record<string, unknown>): boolean {
|
|
36
|
-
// Claude Code doesn't send cursor_version
|
|
37
|
-
return !("cursor_version" in raw);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Parse Claude Code input into normalized context.
|
|
42
|
-
*/
|
|
43
|
-
parseInput(raw: Record<string, unknown>): StopHookContext {
|
|
44
|
-
return {
|
|
45
|
-
cwd: (raw.cwd as string) ?? process.cwd(),
|
|
46
|
-
isNestedHook: raw.stop_hook_active === true,
|
|
47
|
-
sessionId: raw.session_id as string | undefined,
|
|
48
|
-
rawInput: raw,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get the block reason for a given result based on status.
|
|
54
|
-
*/
|
|
55
|
-
private getBlockReason(result: StopHookResult): string | undefined {
|
|
56
|
-
const reasonMap: Record<string, string | undefined> = {
|
|
57
|
-
failed: result.instructions,
|
|
58
|
-
pr_push_required: result.pushPRReason,
|
|
59
|
-
ci_failed: result.ciFixReason,
|
|
60
|
-
ci_pending: result.ciPendingReason,
|
|
61
|
-
};
|
|
62
|
-
return reasonMap[result.status];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Format handler result into Claude Code protocol output.
|
|
67
|
-
*/
|
|
68
|
-
formatOutput(result: StopHookResult): string {
|
|
69
|
-
const blockReason = this.getBlockReason(result);
|
|
70
|
-
const stopReason =
|
|
71
|
-
result.shouldBlock && blockReason ? blockReason : result.message;
|
|
72
|
-
|
|
73
|
-
const response: ClaudeHookResponse = {
|
|
74
|
-
decision: result.shouldBlock ? "block" : "approve",
|
|
75
|
-
stopReason,
|
|
76
|
-
systemMessage: result.message,
|
|
77
|
-
status: result.status,
|
|
78
|
-
message: result.message,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
if (result.shouldBlock && blockReason) {
|
|
82
|
-
response.reason = blockReason;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return JSON.stringify(response);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Check if execution should be skipped based on Claude-specific conditions.
|
|
90
|
-
* Note: stop_hook_active from stdin is currently disabled in the main entry point
|
|
91
|
-
* because Claude Code sends it after blocking twice, but we need to re-run.
|
|
92
|
-
*/
|
|
93
|
-
shouldSkipExecution(_ctx: StopHookContext): StopHookResult | null {
|
|
94
|
-
// The isNestedHook check is handled at the entry point level
|
|
95
|
-
// via the marker file mechanism, not here.
|
|
96
|
-
// This method is available for future protocol-specific skip conditions.
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
StopHookAdapter,
|
|
3
|
-
StopHookContext,
|
|
4
|
-
StopHookResult,
|
|
5
|
-
} from "./types.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Cursor hook response format.
|
|
9
|
-
* - Empty object {} = allow stop (no feedback)
|
|
10
|
-
* - { systemMessage: "..." } = allow stop with user-visible message
|
|
11
|
-
* - { followup_message: "..." } = block stop and continue with message
|
|
12
|
-
*/
|
|
13
|
-
interface CursorHookResponse {
|
|
14
|
-
followup_message?: string;
|
|
15
|
-
systemMessage?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Default maximum loop count before allowing stop.
|
|
20
|
-
* Cursor has built-in loop_limit (default 5, configurable in hooks.json),
|
|
21
|
-
* but we provide defense-in-depth with our own check.
|
|
22
|
-
*/
|
|
23
|
-
const DEFAULT_MAX_LOOPS = 10;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Adapter for Cursor IDE stop hook protocol.
|
|
27
|
-
*
|
|
28
|
-
* Cursor protocol:
|
|
29
|
-
* - Input: { status, loop_count, cursor_version, workspace_roots, conversation_id, ... }
|
|
30
|
-
* - Output: { followup_message?: "..." } or {}
|
|
31
|
-
* - Block mechanism: { followup_message: "instructions" } - continues agent with message
|
|
32
|
-
* - Allow mechanism: {} (empty object) - allows stop
|
|
33
|
-
* - Loop prevention: loop_count field (Cursor has built-in loop_limit)
|
|
34
|
-
*/
|
|
35
|
-
export class CursorStopHookAdapter implements StopHookAdapter {
|
|
36
|
-
name = "cursor";
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Maximum loop count before forcing stop.
|
|
40
|
-
* Can be configured via hooks.json loop_limit.
|
|
41
|
-
*/
|
|
42
|
-
private maxLoops: number;
|
|
43
|
-
|
|
44
|
-
constructor(maxLoops: number = DEFAULT_MAX_LOOPS) {
|
|
45
|
-
this.maxLoops = maxLoops;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Detect if this adapter should handle the given input.
|
|
50
|
-
* Cursor sends cursor_version in hook input.
|
|
51
|
-
*/
|
|
52
|
-
detect(raw: Record<string, unknown>): boolean {
|
|
53
|
-
return "cursor_version" in raw;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Parse Cursor input into normalized context.
|
|
58
|
-
*/
|
|
59
|
-
parseInput(raw: Record<string, unknown>): StopHookContext {
|
|
60
|
-
const workspaceRoots = raw.workspace_roots;
|
|
61
|
-
const loopCount = raw.loop_count as number | undefined;
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
cwd:
|
|
65
|
-
(Array.isArray(workspaceRoots) ? workspaceRoots[0] : null) ??
|
|
66
|
-
process.cwd(),
|
|
67
|
-
isNestedHook: false, // Cursor uses loop_count instead of nested hook flag
|
|
68
|
-
loopCount,
|
|
69
|
-
sessionId: raw.conversation_id as string | undefined,
|
|
70
|
-
rawInput: raw,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Get the block message for a given result based on status.
|
|
76
|
-
*/
|
|
77
|
-
private getBlockMessage(result: StopHookResult): string {
|
|
78
|
-
const messageMap: Record<string, string | undefined> = {
|
|
79
|
-
failed: result.instructions,
|
|
80
|
-
pr_push_required: result.pushPRReason,
|
|
81
|
-
ci_failed: result.ciFixReason,
|
|
82
|
-
ci_pending: result.ciPendingReason,
|
|
83
|
-
};
|
|
84
|
-
return messageMap[result.status] || result.message;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Format handler result into Cursor protocol output.
|
|
89
|
-
*/
|
|
90
|
-
formatOutput(result: StopHookResult): string {
|
|
91
|
-
if (result.shouldBlock) {
|
|
92
|
-
const response: CursorHookResponse = {
|
|
93
|
-
followup_message: this.getBlockMessage(result),
|
|
94
|
-
};
|
|
95
|
-
return JSON.stringify(response);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Include systemMessage for user feedback even when not blocking
|
|
99
|
-
const response: CursorHookResponse = {
|
|
100
|
-
systemMessage: result.message,
|
|
101
|
-
};
|
|
102
|
-
return JSON.stringify(response);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Check if execution should be skipped based on Cursor-specific conditions.
|
|
107
|
-
* Returns early if loop_count exceeds threshold.
|
|
108
|
-
*/
|
|
109
|
-
shouldSkipExecution(ctx: StopHookContext): StopHookResult | null {
|
|
110
|
-
// Cursor has built-in loop_limit (default 5), but we can check here too
|
|
111
|
-
// for defense-in-depth
|
|
112
|
-
if (ctx.loopCount !== undefined && ctx.loopCount >= this.maxLoops) {
|
|
113
|
-
return {
|
|
114
|
-
status: "retry_limit_exceeded",
|
|
115
|
-
shouldBlock: false,
|
|
116
|
-
message:
|
|
117
|
-
"Loop limit reached — run `agent-gauntlet clean` to archive and continue.",
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import type { GauntletStatus, RunResult } from "../../types/gauntlet-status.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Protocol-agnostic context passed from adapter to handler.
|
|
5
|
-
* Contains normalized fields from either Claude Code or Cursor input.
|
|
6
|
-
*/
|
|
7
|
-
export interface StopHookContext {
|
|
8
|
-
/** Working directory for the project */
|
|
9
|
-
cwd: string;
|
|
10
|
-
/** True if this is a nested hook invocation (Claude: stop_hook_active, Cursor: high loop_count) */
|
|
11
|
-
isNestedHook: boolean;
|
|
12
|
-
/** Cursor-specific: current loop iteration count */
|
|
13
|
-
loopCount?: number;
|
|
14
|
-
/** Session/conversation identifier for logging */
|
|
15
|
-
sessionId?: string;
|
|
16
|
-
/** Original parsed JSON input for diagnostics */
|
|
17
|
-
rawInput: Record<string, unknown>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Protocol-agnostic result from handler to adapter.
|
|
22
|
-
* Contains all information needed to format protocol-specific output.
|
|
23
|
-
*/
|
|
24
|
-
export interface StopHookResult {
|
|
25
|
-
/** Machine-readable status code */
|
|
26
|
-
status: GauntletStatus;
|
|
27
|
-
/** Whether the stop should be blocked */
|
|
28
|
-
shouldBlock: boolean;
|
|
29
|
-
/** Fix instructions when blocking due to failed gates */
|
|
30
|
-
instructions?: string;
|
|
31
|
-
/** PR push instructions when blocking due to pr_push_required */
|
|
32
|
-
pushPRReason?: string;
|
|
33
|
-
/** CI fix instructions when blocking due to ci_failed */
|
|
34
|
-
ciFixReason?: string;
|
|
35
|
-
/** CI pending instructions when blocking due to ci_pending */
|
|
36
|
-
ciPendingReason?: string;
|
|
37
|
-
/** Human-friendly status message */
|
|
38
|
-
message: string;
|
|
39
|
-
/** Interval minutes (when status is interval_not_elapsed) */
|
|
40
|
-
intervalMinutes?: number;
|
|
41
|
-
/** Individual gate results for detailed failure information */
|
|
42
|
-
gateResults?: RunResult["gateResults"];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Result from PR status check.
|
|
47
|
-
*/
|
|
48
|
-
export interface PRStatusResult {
|
|
49
|
-
/** Whether a PR exists for the current branch */
|
|
50
|
-
prExists: boolean;
|
|
51
|
-
/** Whether the PR is up to date with local HEAD */
|
|
52
|
-
upToDate: boolean;
|
|
53
|
-
/** Error message if check failed (graceful degradation) */
|
|
54
|
-
error?: string;
|
|
55
|
-
/** PR number if it exists */
|
|
56
|
-
prNumber?: number;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Adapter interface for protocol-specific stop hook handling.
|
|
61
|
-
* Each adapter handles input parsing, output formatting, and protocol-specific behavior.
|
|
62
|
-
*/
|
|
63
|
-
export interface StopHookAdapter {
|
|
64
|
-
/** Human-readable name for logging */
|
|
65
|
-
name: string;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Detect if this adapter should handle the given input.
|
|
69
|
-
* @param raw Parsed JSON from stdin
|
|
70
|
-
* @returns true if this adapter should handle the input
|
|
71
|
-
*/
|
|
72
|
-
detect(raw: Record<string, unknown>): boolean;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Parse protocol-specific input into normalized context.
|
|
76
|
-
* @param raw Parsed JSON from stdin
|
|
77
|
-
* @returns Normalized context for the handler
|
|
78
|
-
*/
|
|
79
|
-
parseInput(raw: Record<string, unknown>): StopHookContext;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Format handler result into protocol-specific output.
|
|
83
|
-
* @param result Handler result
|
|
84
|
-
* @returns JSON string to output to stdout
|
|
85
|
-
*/
|
|
86
|
-
formatOutput(result: StopHookResult): string;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Check if execution should be skipped based on protocol-specific conditions.
|
|
90
|
-
* @param ctx Parsed context
|
|
91
|
-
* @returns Result to output immediately, or null to continue execution
|
|
92
|
-
*/
|
|
93
|
-
shouldSkipExecution(ctx: StopHookContext): StopHookResult | null;
|
|
94
|
-
}
|