@arvorco/relentless 0.3.1 → 0.4.3
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/.claude/commands/relentless.convert.md +25 -0
- package/.claude/skills/analyze/SKILL.md +113 -40
- package/.claude/skills/analyze/templates/analysis-report.md +138 -0
- package/.claude/skills/checklist/SKILL.md +144 -51
- package/.claude/skills/checklist/templates/checklist.md +43 -11
- package/.claude/skills/clarify/SKILL.md +70 -11
- package/.claude/skills/constitution/SKILL.md +61 -3
- package/.claude/skills/constitution/templates/constitution.md +241 -160
- package/.claude/skills/constitution/templates/prompt.md +150 -20
- package/.claude/skills/convert/SKILL.md +248 -0
- package/.claude/skills/implement/SKILL.md +82 -34
- package/.claude/skills/plan/SKILL.md +139 -27
- package/.claude/skills/plan/templates/plan.md +92 -9
- package/.claude/skills/specify/SKILL.md +112 -20
- package/.claude/skills/specify/templates/spec.md +40 -5
- package/.claude/skills/tasks/SKILL.md +76 -1
- package/.claude/skills/tasks/templates/tasks.md +5 -4
- package/CHANGELOG.md +84 -1
- package/MANUAL.md +40 -0
- package/README.md +268 -13
- package/bin/relentless.ts +292 -5
- package/package.json +2 -2
- package/relentless/config.json +45 -1
- package/relentless/constitution.md +41 -19
- package/relentless/prompt.md +142 -72
- package/src/agents/amp.ts +53 -13
- package/src/agents/claude.ts +70 -15
- package/src/agents/codex.ts +73 -14
- package/src/agents/droid.ts +68 -14
- package/src/agents/exec.ts +96 -0
- package/src/agents/gemini.ts +59 -16
- package/src/agents/opencode.ts +188 -9
- package/src/cli/fallback-order.ts +210 -0
- package/src/cli/index.ts +63 -0
- package/src/cli/mode-flag.ts +198 -0
- package/src/cli/review-flags.ts +192 -0
- package/src/config/loader.ts +16 -1
- package/src/config/schema.ts +157 -2
- package/src/execution/runner.ts +144 -21
- package/src/init/scaffolder.ts +285 -25
- package/src/prd/parser.ts +111 -6
- package/src/prd/types.ts +136 -0
- package/src/review/index.ts +92 -0
- package/src/review/prompt.ts +293 -0
- package/src/review/runner.ts +337 -0
- package/src/review/tasks/docs.ts +529 -0
- package/src/review/tasks/index.ts +80 -0
- package/src/review/tasks/lint.ts +436 -0
- package/src/review/tasks/quality.ts +760 -0
- package/src/review/tasks/security.ts +452 -0
- package/src/review/tasks/test.ts +456 -0
- package/src/review/tasks/typecheck.ts +323 -0
- package/src/review/types.ts +139 -0
- package/src/routing/cascade.ts +310 -0
- package/src/routing/classifier.ts +338 -0
- package/src/routing/estimate.ts +270 -0
- package/src/routing/fallback.ts +512 -0
- package/src/routing/index.ts +124 -0
- package/src/routing/registry.ts +501 -0
- package/src/routing/report.ts +570 -0
- package/src/routing/router.ts +287 -0
- package/src/tui/App.tsx +2 -0
- package/src/tui/TUIRunner.tsx +103 -8
- package/src/tui/components/CurrentStory.tsx +23 -1
- package/src/tui/hooks/useTUI.ts +1 -0
- package/src/tui/types.ts +9 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typecheck Micro-Task
|
|
3
|
+
*
|
|
4
|
+
* Runs `bun run typecheck` in the project's working directory,
|
|
5
|
+
* parses TypeScript errors, and generates fix tasks.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Parses TypeScript compiler errors with file, line, column, code, message
|
|
9
|
+
* - Groups errors by file for efficient fixing
|
|
10
|
+
* - Generates fix tasks with priority "high"
|
|
11
|
+
* - Strips ANSI color codes from output
|
|
12
|
+
* - Tracks warnings separately (doesn't generate fix tasks)
|
|
13
|
+
* - Provides summary for 100+ errors
|
|
14
|
+
* - Reports tsconfig.json configuration errors
|
|
15
|
+
*
|
|
16
|
+
* @module src/review/tasks/typecheck
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { ReviewTaskResult, FixTask } from "../types";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A parsed TypeScript error
|
|
23
|
+
*/
|
|
24
|
+
export interface TypecheckError {
|
|
25
|
+
/** File path relative to project root */
|
|
26
|
+
file: string;
|
|
27
|
+
/** Line number (1-based) */
|
|
28
|
+
line: number;
|
|
29
|
+
/** Column number (1-based, optional) */
|
|
30
|
+
column?: number;
|
|
31
|
+
/** TypeScript error code (e.g., "TS2339") */
|
|
32
|
+
code: string;
|
|
33
|
+
/** Error message text */
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Extended result type for typecheck micro-task
|
|
39
|
+
*/
|
|
40
|
+
export interface TypecheckResult extends ReviewTaskResult {
|
|
41
|
+
/** The command that was executed */
|
|
42
|
+
command: string;
|
|
43
|
+
/** Warning count (not included in fix tasks) */
|
|
44
|
+
warningCount?: number;
|
|
45
|
+
/** Summary for paginated results (when 100+ errors) */
|
|
46
|
+
summary?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Options for running typecheck
|
|
51
|
+
*/
|
|
52
|
+
export interface TypecheckOptions {
|
|
53
|
+
/** Working directory for the command */
|
|
54
|
+
cwd?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Strip ANSI color codes from a string
|
|
59
|
+
*
|
|
60
|
+
* @param str - Input string potentially containing ANSI codes
|
|
61
|
+
* @returns Clean string without ANSI codes
|
|
62
|
+
*/
|
|
63
|
+
export function stripAnsiCodes(str: string): string {
|
|
64
|
+
// eslint-disable-next-line no-control-regex
|
|
65
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parse TypeScript compiler output into structured errors
|
|
70
|
+
*
|
|
71
|
+
* Handles multiple output formats:
|
|
72
|
+
* - Standard tsc format: `file(line,col): error TSxxxx: message`
|
|
73
|
+
* - Colon-separated format: `file:line:col - error TSxxxx: message`
|
|
74
|
+
* - Bun typecheck format (arrow style)
|
|
75
|
+
*
|
|
76
|
+
* @param output - Raw compiler output (stdout)
|
|
77
|
+
* @returns Array of parsed errors (excludes warnings)
|
|
78
|
+
*/
|
|
79
|
+
export function parseTypecheckOutput(output: string): TypecheckError[] {
|
|
80
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
81
|
+
const errors: TypecheckError[] = [];
|
|
82
|
+
|
|
83
|
+
// Split into lines and process each
|
|
84
|
+
const lines = cleanOutput.split("\n");
|
|
85
|
+
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
// Skip warning lines
|
|
88
|
+
if (line.includes("warning TS") || line.includes("warning:")) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Pattern 1: Standard tsc format - file(line,col): error TSxxxx: message
|
|
93
|
+
const stdMatch = line.match(
|
|
94
|
+
/^(.+?)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)$/
|
|
95
|
+
);
|
|
96
|
+
if (stdMatch) {
|
|
97
|
+
errors.push({
|
|
98
|
+
file: stdMatch[1],
|
|
99
|
+
line: parseInt(stdMatch[2], 10),
|
|
100
|
+
column: parseInt(stdMatch[3], 10),
|
|
101
|
+
code: stdMatch[4],
|
|
102
|
+
message: stdMatch[5],
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Pattern 1b: Without column - file(line): error TSxxxx: message
|
|
108
|
+
const noColMatch = line.match(
|
|
109
|
+
/^(.+?)\((\d+)\):\s*error\s+(TS\d+):\s*(.+)$/
|
|
110
|
+
);
|
|
111
|
+
if (noColMatch) {
|
|
112
|
+
errors.push({
|
|
113
|
+
file: noColMatch[1],
|
|
114
|
+
line: parseInt(noColMatch[2], 10),
|
|
115
|
+
code: noColMatch[3],
|
|
116
|
+
message: noColMatch[4],
|
|
117
|
+
});
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Pattern 2: Colon-separated format - file:line:col - error TSxxxx: message
|
|
122
|
+
const colonMatch = line.match(
|
|
123
|
+
/^(.+?):(\d+):(\d+)\s+-\s*error\s+(TS\d+):\s*(.+)$/
|
|
124
|
+
);
|
|
125
|
+
if (colonMatch) {
|
|
126
|
+
errors.push({
|
|
127
|
+
file: colonMatch[1],
|
|
128
|
+
line: parseInt(colonMatch[2], 10),
|
|
129
|
+
column: parseInt(colonMatch[3], 10),
|
|
130
|
+
code: colonMatch[4],
|
|
131
|
+
message: colonMatch[5],
|
|
132
|
+
});
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return errors;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parse warnings from TypeScript compiler output
|
|
142
|
+
*
|
|
143
|
+
* @param output - Raw compiler output
|
|
144
|
+
* @returns Number of warnings found
|
|
145
|
+
*/
|
|
146
|
+
function parseWarningCount(output: string): number {
|
|
147
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
148
|
+
const lines = cleanOutput.split("\n");
|
|
149
|
+
let count = 0;
|
|
150
|
+
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
if (line.includes("warning TS") || line.includes("warning:")) {
|
|
153
|
+
count++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return count;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Group errors by file path
|
|
162
|
+
*
|
|
163
|
+
* @param errors - Array of parsed errors
|
|
164
|
+
* @returns Record mapping file paths to their errors
|
|
165
|
+
*/
|
|
166
|
+
export function groupErrorsByFile(
|
|
167
|
+
errors: TypecheckError[]
|
|
168
|
+
): Record<string, TypecheckError[]> {
|
|
169
|
+
const grouped: Record<string, TypecheckError[]> = {};
|
|
170
|
+
|
|
171
|
+
for (const error of errors) {
|
|
172
|
+
if (!grouped[error.file]) {
|
|
173
|
+
grouped[error.file] = [];
|
|
174
|
+
}
|
|
175
|
+
grouped[error.file].push(error);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return grouped;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a fix task from a TypeScript error
|
|
183
|
+
*
|
|
184
|
+
* @param error - The parsed TypeScript error
|
|
185
|
+
* @returns A fix task for the review system
|
|
186
|
+
*/
|
|
187
|
+
function createFixTask(error: TypecheckError): FixTask {
|
|
188
|
+
const lineInfo = error.column
|
|
189
|
+
? `at line ${error.line}, column ${error.column}`
|
|
190
|
+
: `at line ${error.line}`;
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
type: "typecheck_fix",
|
|
194
|
+
file: error.file,
|
|
195
|
+
line: error.line,
|
|
196
|
+
column: error.column,
|
|
197
|
+
description: `Fix TypeScript error ${error.code} in ${error.file} ${lineInfo}: ${error.message}`,
|
|
198
|
+
priority: "high",
|
|
199
|
+
code: error.code,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Run the typecheck micro-task
|
|
205
|
+
*
|
|
206
|
+
* Executes `bun run typecheck` in the specified working directory,
|
|
207
|
+
* parses the output, and generates fix tasks for any errors found.
|
|
208
|
+
*
|
|
209
|
+
* @param options - Options including working directory
|
|
210
|
+
* @returns TypecheckResult with success status, errors, and fix tasks
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const result = await runTypecheck({ cwd: "/path/to/project" });
|
|
215
|
+
* if (!result.success) {
|
|
216
|
+
* console.log(`${result.errorCount} errors found`);
|
|
217
|
+
* result.fixTasks.forEach(task => console.log(task.description));
|
|
218
|
+
* }
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export async function runTypecheck(
|
|
222
|
+
options: TypecheckOptions = {}
|
|
223
|
+
): Promise<TypecheckResult> {
|
|
224
|
+
const cwd = options.cwd || process.cwd();
|
|
225
|
+
const command = "bun run typecheck";
|
|
226
|
+
const startTime = Date.now();
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
// Spawn the typecheck process
|
|
230
|
+
const proc = Bun.spawn(["bun", "run", "typecheck"], {
|
|
231
|
+
cwd,
|
|
232
|
+
stdout: "pipe",
|
|
233
|
+
stderr: "pipe",
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Wait for completion
|
|
237
|
+
const exitCode = await proc.exited;
|
|
238
|
+
const stdout = await proc.stdout.text();
|
|
239
|
+
const stderr = await proc.stderr.text();
|
|
240
|
+
const duration = Date.now() - startTime;
|
|
241
|
+
|
|
242
|
+
// Check for tsconfig.json errors
|
|
243
|
+
if (
|
|
244
|
+
stderr.includes("tsconfig.json") ||
|
|
245
|
+
stderr.includes("Could not find") ||
|
|
246
|
+
stderr.includes("Cannot find")
|
|
247
|
+
) {
|
|
248
|
+
return {
|
|
249
|
+
taskType: "typecheck",
|
|
250
|
+
success: false,
|
|
251
|
+
errorCount: 1,
|
|
252
|
+
warningCount: 0,
|
|
253
|
+
fixTasks: [],
|
|
254
|
+
duration,
|
|
255
|
+
command,
|
|
256
|
+
error: `Configuration error: ${stderr.includes("tsconfig") ? "tsconfig.json not found or invalid" : stderr}`,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Parse errors from output (check both stdout and stderr)
|
|
261
|
+
const combinedOutput = stdout + "\n" + stderr;
|
|
262
|
+
const errors = parseTypecheckOutput(combinedOutput);
|
|
263
|
+
const warningCount = parseWarningCount(combinedOutput);
|
|
264
|
+
|
|
265
|
+
// Generate fix tasks for each error
|
|
266
|
+
const fixTasks = errors.map(createFixTask);
|
|
267
|
+
|
|
268
|
+
// Create summary for large error counts
|
|
269
|
+
let summary: string | undefined;
|
|
270
|
+
if (errors.length >= 100) {
|
|
271
|
+
const grouped = groupErrorsByFile(errors);
|
|
272
|
+
const fileCount = Object.keys(grouped).length;
|
|
273
|
+
summary = `Found ${errors.length} TypeScript errors across ${fileCount} files. Top files with errors: ${Object.entries(grouped)
|
|
274
|
+
.sort((a, b) => b[1].length - a[1].length)
|
|
275
|
+
.slice(0, 5)
|
|
276
|
+
.map(([file, errs]) => `${file} (${errs.length})`)
|
|
277
|
+
.join(", ")}`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check for general command failure (stderr has content but no parsed errors)
|
|
281
|
+
if (exitCode !== 0 && errors.length === 0 && stderr.trim()) {
|
|
282
|
+
return {
|
|
283
|
+
taskType: "typecheck",
|
|
284
|
+
success: false,
|
|
285
|
+
errorCount: 1,
|
|
286
|
+
warningCount: 0,
|
|
287
|
+
fixTasks: [],
|
|
288
|
+
duration,
|
|
289
|
+
command,
|
|
290
|
+
error: stderr.trim(),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Success if no errors (warnings are OK)
|
|
295
|
+
const success = errors.length === 0 && exitCode === 0;
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
taskType: "typecheck",
|
|
299
|
+
success,
|
|
300
|
+
errorCount: errors.length,
|
|
301
|
+
warningCount,
|
|
302
|
+
fixTasks,
|
|
303
|
+
duration,
|
|
304
|
+
command,
|
|
305
|
+
summary,
|
|
306
|
+
};
|
|
307
|
+
} catch (error) {
|
|
308
|
+
const duration = Date.now() - startTime;
|
|
309
|
+
const errorMessage =
|
|
310
|
+
error instanceof Error ? error.message : String(error);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
taskType: "typecheck",
|
|
314
|
+
success: false,
|
|
315
|
+
errorCount: 1,
|
|
316
|
+
warningCount: 0,
|
|
317
|
+
fixTasks: [],
|
|
318
|
+
duration,
|
|
319
|
+
command,
|
|
320
|
+
error: `Command execution failed: ${errorMessage}`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and interfaces for the Review module
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core types used by the review runner
|
|
5
|
+
* and all micro-task implementations.
|
|
6
|
+
*
|
|
7
|
+
* @module src/review/types
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Priority levels for fix tasks
|
|
14
|
+
* - critical: Security vulnerabilities, data corruption risks
|
|
15
|
+
* - high: TypeScript errors, failing tests
|
|
16
|
+
* - medium: Lint warnings, code quality issues
|
|
17
|
+
* - low: Documentation, style suggestions
|
|
18
|
+
*/
|
|
19
|
+
export const FixTaskPrioritySchema = z.enum(["critical", "high", "medium", "low"]);
|
|
20
|
+
export type FixTaskPriority = z.infer<typeof FixTaskPrioritySchema>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fix task types corresponding to review micro-tasks
|
|
24
|
+
*/
|
|
25
|
+
export const FixTaskTypeSchema = z.enum([
|
|
26
|
+
"typecheck_fix",
|
|
27
|
+
"lint_fix",
|
|
28
|
+
"test_fix",
|
|
29
|
+
"security_fix",
|
|
30
|
+
"quality_fix",
|
|
31
|
+
"docs_fix",
|
|
32
|
+
]);
|
|
33
|
+
export type FixTaskType = z.infer<typeof FixTaskTypeSchema>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A fix task queued from a review micro-task
|
|
37
|
+
*
|
|
38
|
+
* Fix tasks are generated when micro-tasks find issues
|
|
39
|
+
* and are queued to progress.txt for subsequent processing.
|
|
40
|
+
*/
|
|
41
|
+
export const FixTaskSchema = z.object({
|
|
42
|
+
/** Type of fix task, corresponds to the micro-task that generated it */
|
|
43
|
+
type: FixTaskTypeSchema,
|
|
44
|
+
/** File path relative to project root */
|
|
45
|
+
file: z.string(),
|
|
46
|
+
/** Line number where the issue was found (optional) */
|
|
47
|
+
line: z.number().int().positive().optional(),
|
|
48
|
+
/** Column number (optional) */
|
|
49
|
+
column: z.number().int().positive().optional(),
|
|
50
|
+
/** Human-readable description of the issue and fix needed */
|
|
51
|
+
description: z.string(),
|
|
52
|
+
/** Priority level for ordering fix tasks */
|
|
53
|
+
priority: FixTaskPrioritySchema,
|
|
54
|
+
/** Specific rule or error code (optional, e.g., ESLint rule) */
|
|
55
|
+
rule: z.string().optional(),
|
|
56
|
+
/** Error code (optional, e.g., TS2339) */
|
|
57
|
+
code: z.string().optional(),
|
|
58
|
+
});
|
|
59
|
+
export type FixTask = z.infer<typeof FixTaskSchema>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Result from running a single micro-task
|
|
63
|
+
*/
|
|
64
|
+
export const ReviewTaskResultSchema = z.object({
|
|
65
|
+
/** Type of micro-task that was run */
|
|
66
|
+
taskType: z.enum(["typecheck", "lint", "test", "security", "quality", "docs"]),
|
|
67
|
+
/** Whether the task passed (no blocking issues) */
|
|
68
|
+
success: z.boolean(),
|
|
69
|
+
/** Number of errors/issues found */
|
|
70
|
+
errorCount: z.number().int().min(0),
|
|
71
|
+
/** Warning count (non-blocking) */
|
|
72
|
+
warningCount: z.number().int().min(0).optional(),
|
|
73
|
+
/** Fix tasks generated for issues found */
|
|
74
|
+
fixTasks: z.array(FixTaskSchema),
|
|
75
|
+
/** Duration in milliseconds */
|
|
76
|
+
duration: z.number().min(0),
|
|
77
|
+
/** Error message if task threw an exception */
|
|
78
|
+
error: z.string().optional(),
|
|
79
|
+
/** Number of retry attempts used */
|
|
80
|
+
retryAttempts: z.number().int().min(0).optional(),
|
|
81
|
+
});
|
|
82
|
+
export type ReviewTaskResult = z.infer<typeof ReviewTaskResultSchema>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Summary of the complete review phase
|
|
86
|
+
*/
|
|
87
|
+
export const ReviewSummarySchema = z.object({
|
|
88
|
+
/** Total number of micro-tasks run */
|
|
89
|
+
tasksRun: z.number().int().min(0),
|
|
90
|
+
/** Number of tasks that passed */
|
|
91
|
+
tasksPassed: z.number().int().min(0),
|
|
92
|
+
/** Number of tasks that failed */
|
|
93
|
+
tasksFailed: z.number().int().min(0),
|
|
94
|
+
/** Total fix tasks generated across all micro-tasks */
|
|
95
|
+
fixTasksGenerated: z.number().int().min(0),
|
|
96
|
+
/** Total duration of review phase in milliseconds */
|
|
97
|
+
totalDuration: z.number().min(0),
|
|
98
|
+
/** Estimated cost before running (based on mode and task count) */
|
|
99
|
+
estimatedCost: z.number().min(0),
|
|
100
|
+
/** Actual cost after running (based on model usage) */
|
|
101
|
+
actualCost: z.number().min(0),
|
|
102
|
+
/** Individual results for each micro-task */
|
|
103
|
+
results: z.array(ReviewTaskResultSchema),
|
|
104
|
+
/** Whether review was stopped early due to stopOnFailure */
|
|
105
|
+
stoppedEarly: z.boolean().optional(),
|
|
106
|
+
});
|
|
107
|
+
export type ReviewSummary = z.infer<typeof ReviewSummarySchema>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Options for controlling review execution
|
|
111
|
+
*/
|
|
112
|
+
export const ReviewOptionsSchema = z.object({
|
|
113
|
+
/** Stop on first failure instead of continuing */
|
|
114
|
+
stopOnFailure: z.boolean().default(false),
|
|
115
|
+
/** Mode override (defaults to config.defaultMode) */
|
|
116
|
+
mode: z.enum(["free", "cheap", "good", "genius"]).default("good"),
|
|
117
|
+
/** Micro-tasks to skip */
|
|
118
|
+
skipTasks: z.array(z.enum(["typecheck", "lint", "test", "security", "quality", "docs"])).optional(),
|
|
119
|
+
/** Custom handlers for testing (overrides default implementations) */
|
|
120
|
+
handlers: z.record(z.string(), z.any()).optional(),
|
|
121
|
+
/** Custom logger function */
|
|
122
|
+
logger: z.function().args(z.string()).returns(z.unknown()).optional(),
|
|
123
|
+
/** Callback when model is selected for review */
|
|
124
|
+
onModelSelected: z.function().args(z.string()).returns(z.unknown()).optional(),
|
|
125
|
+
});
|
|
126
|
+
export type ReviewOptions = z.infer<typeof ReviewOptionsSchema>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Handler function for a micro-task
|
|
130
|
+
*
|
|
131
|
+
* Each micro-task (typecheck, lint, test, etc.) implements this interface.
|
|
132
|
+
* The handler runs in a fresh process/context with no shared state.
|
|
133
|
+
*/
|
|
134
|
+
export type MicroTaskHandler = () => Promise<ReviewTaskResult>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Registry of micro-task handlers
|
|
138
|
+
*/
|
|
139
|
+
export type MicroTaskHandlerRegistry = Record<string, MicroTaskHandler>;
|