sequant 1.15.2 → 1.15.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-plugin/plugin.json +1 -1
- package/dist/bin/cli.js +3 -0
- package/dist/src/commands/logs.js +15 -0
- package/dist/src/commands/run.d.ts +114 -1
- package/dist/src/commands/run.js +447 -23
- package/dist/src/commands/stats.js +48 -0
- package/dist/src/lib/scope/index.d.ts +1 -0
- package/dist/src/lib/scope/index.js +2 -0
- package/dist/src/lib/scope/settings-converter.d.ts +28 -0
- package/dist/src/lib/scope/settings-converter.js +53 -0
- package/dist/src/lib/settings.d.ts +45 -0
- package/dist/src/lib/settings.js +30 -0
- package/dist/src/lib/test-tautology-detector.d.ts +122 -0
- package/dist/src/lib/test-tautology-detector.js +488 -0
- package/dist/src/lib/workflow/git-diff-utils.d.ts +39 -0
- package/dist/src/lib/workflow/git-diff-utils.js +142 -0
- package/dist/src/lib/workflow/log-writer.d.ts +9 -2
- package/dist/src/lib/workflow/log-writer.js +9 -3
- package/dist/src/lib/workflow/metrics-schema.d.ts +9 -0
- package/dist/src/lib/workflow/metrics-schema.js +10 -1
- package/dist/src/lib/workflow/phase-detection.d.ts +3 -0
- package/dist/src/lib/workflow/phase-detection.js +27 -1
- package/dist/src/lib/workflow/qa-cache.d.ts +3 -1
- package/dist/src/lib/workflow/qa-cache.js +2 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts +86 -3
- package/dist/src/lib/workflow/run-log-schema.js +40 -2
- package/dist/src/lib/workflow/state-utils.d.ts +46 -0
- package/dist/src/lib/workflow/state-utils.js +167 -0
- package/dist/src/lib/workflow/token-utils.d.ts +92 -0
- package/dist/src/lib/workflow/token-utils.js +170 -0
- package/dist/src/lib/workflow/types.d.ts +6 -0
- package/dist/src/lib/workflow/types.js +1 -0
- package/package.json +1 -1
- package/templates/hooks/pre-tool.sh +4 -0
- package/templates/skills/assess/SKILL.md +1 -1
- package/templates/skills/exec/SKILL.md +5 -4
- package/templates/skills/improve/SKILL.md +37 -24
- package/templates/skills/loop/SKILL.md +3 -3
- package/templates/skills/qa/references/code-review-checklist.md +10 -11
- package/templates/skills/qa/scripts/quality-checks.sh +16 -0
- package/templates/skills/security-review/references/security-checklists.md +89 -36
- package/templates/skills/solve/SKILL.md +3 -1
- package/templates/skills/spec/SKILL.md +8 -4
|
@@ -24,6 +24,8 @@ export interface LogWriterOptions {
|
|
|
24
24
|
verbose?: boolean;
|
|
25
25
|
/** Log rotation settings */
|
|
26
26
|
rotation?: RotationSettings;
|
|
27
|
+
/** Git commit SHA at run start (AC-2) */
|
|
28
|
+
startCommit?: string;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Manages writing structured run logs to disk
|
|
@@ -35,6 +37,7 @@ export declare class LogWriter {
|
|
|
35
37
|
private writeToUserLogs;
|
|
36
38
|
private verbose;
|
|
37
39
|
private rotation;
|
|
40
|
+
private startCommit?;
|
|
38
41
|
constructor(options?: LogWriterOptions);
|
|
39
42
|
/**
|
|
40
43
|
* Initialize a new run log
|
|
@@ -65,9 +68,13 @@ export declare class LogWriter {
|
|
|
65
68
|
*
|
|
66
69
|
* Automatically rotates old logs if thresholds are exceeded.
|
|
67
70
|
*
|
|
71
|
+
* @param options - Optional finalization options
|
|
72
|
+
* @param options.endCommit - Git commit SHA at run end (AC-2)
|
|
68
73
|
* @returns Path to the written log file
|
|
69
74
|
*/
|
|
70
|
-
finalize(
|
|
75
|
+
finalize(options?: {
|
|
76
|
+
endCommit?: string;
|
|
77
|
+
}): Promise<string>;
|
|
71
78
|
/**
|
|
72
79
|
* Get the current run log (for inspection)
|
|
73
80
|
*/
|
|
@@ -85,4 +92,4 @@ export declare class LogWriter {
|
|
|
85
92
|
*
|
|
86
93
|
* Utility function for creating phase logs when you have start/end times.
|
|
87
94
|
*/
|
|
88
|
-
export declare function createPhaseLogFromTiming(phase: Phase, issueNumber: number, startTime: Date, endTime: Date, status: PhaseLog["status"], options?: Partial<Pick<PhaseLog, "error" | "iterations" | "filesModified" | "testsRun" | "testsPassed" | "verdict">>): PhaseLog;
|
|
95
|
+
export declare function createPhaseLogFromTiming(phase: Phase, issueNumber: number, startTime: Date, endTime: Date, status: PhaseLog["status"], options?: Partial<Pick<PhaseLog, "error" | "iterations" | "filesModified" | "testsRun" | "testsPassed" | "verdict" | "commitHash" | "fileDiffStats" | "cacheMetrics">>): PhaseLog;
|
|
@@ -28,11 +28,13 @@ export class LogWriter {
|
|
|
28
28
|
writeToUserLogs;
|
|
29
29
|
verbose;
|
|
30
30
|
rotation;
|
|
31
|
+
startCommit;
|
|
31
32
|
constructor(options = {}) {
|
|
32
33
|
this.logPath = options.logPath ?? LOG_PATHS.project;
|
|
33
34
|
this.writeToUserLogs = options.writeToUserLogs ?? false;
|
|
34
35
|
this.verbose = options.verbose ?? false;
|
|
35
36
|
this.rotation = options.rotation ?? DEFAULT_ROTATION_SETTINGS;
|
|
37
|
+
this.startCommit = options.startCommit;
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Initialize a new run log
|
|
@@ -40,7 +42,7 @@ export class LogWriter {
|
|
|
40
42
|
* @param config - Run configuration
|
|
41
43
|
*/
|
|
42
44
|
async initialize(config) {
|
|
43
|
-
this.runLog = createEmptyRunLog(config);
|
|
45
|
+
this.runLog = createEmptyRunLog(config, { startCommit: this.startCommit });
|
|
44
46
|
// Ensure log directory exists
|
|
45
47
|
await this.ensureLogDirectory(this.logPath);
|
|
46
48
|
if (this.writeToUserLogs) {
|
|
@@ -124,9 +126,11 @@ export class LogWriter {
|
|
|
124
126
|
*
|
|
125
127
|
* Automatically rotates old logs if thresholds are exceeded.
|
|
126
128
|
*
|
|
129
|
+
* @param options - Optional finalization options
|
|
130
|
+
* @param options.endCommit - Git commit SHA at run end (AC-2)
|
|
127
131
|
* @returns Path to the written log file
|
|
128
132
|
*/
|
|
129
|
-
async finalize() {
|
|
133
|
+
async finalize(options) {
|
|
130
134
|
if (!this.runLog) {
|
|
131
135
|
throw new Error("LogWriter not initialized.");
|
|
132
136
|
}
|
|
@@ -134,7 +138,9 @@ export class LogWriter {
|
|
|
134
138
|
if (this.currentIssue) {
|
|
135
139
|
this.completeIssue();
|
|
136
140
|
}
|
|
137
|
-
const finalLog = finalizeRunLog(this.runLog
|
|
141
|
+
const finalLog = finalizeRunLog(this.runLog, {
|
|
142
|
+
endCommit: options?.endCommit,
|
|
143
|
+
});
|
|
138
144
|
const filename = generateLogFilename(finalLog.runId, new Date(finalLog.startTime));
|
|
139
145
|
// Write to project logs
|
|
140
146
|
const projectPath = path.join(this.resolvePath(this.logPath), filename);
|
|
@@ -48,6 +48,9 @@ export declare const RunMetricsSchema: z.ZodObject<{
|
|
|
48
48
|
linesAdded: z.ZodNumber;
|
|
49
49
|
acceptanceCriteria: z.ZodNumber;
|
|
50
50
|
qaIterations: z.ZodNumber;
|
|
51
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
cacheTokens: z.ZodOptional<z.ZodNumber>;
|
|
51
54
|
}, z.core.$strip>;
|
|
52
55
|
export type RunMetrics = z.infer<typeof RunMetricsSchema>;
|
|
53
56
|
/**
|
|
@@ -86,6 +89,9 @@ export declare const MetricRunSchema: z.ZodObject<{
|
|
|
86
89
|
linesAdded: z.ZodNumber;
|
|
87
90
|
acceptanceCriteria: z.ZodNumber;
|
|
88
91
|
qaIterations: z.ZodNumber;
|
|
92
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
93
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
94
|
+
cacheTokens: z.ZodOptional<z.ZodNumber>;
|
|
89
95
|
}, z.core.$strip>;
|
|
90
96
|
}, z.core.$strip>;
|
|
91
97
|
export type MetricRun = z.infer<typeof MetricRunSchema>;
|
|
@@ -123,6 +129,9 @@ export declare const MetricsSchema: z.ZodObject<{
|
|
|
123
129
|
linesAdded: z.ZodNumber;
|
|
124
130
|
acceptanceCriteria: z.ZodNumber;
|
|
125
131
|
qaIterations: z.ZodNumber;
|
|
132
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
133
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
134
|
+
cacheTokens: z.ZodOptional<z.ZodNumber>;
|
|
126
135
|
}, z.core.$strip>;
|
|
127
136
|
}, z.core.$strip>>;
|
|
128
137
|
}, z.core.$strip>;
|
|
@@ -38,7 +38,7 @@ export const MetricPhaseSchema = z.enum([
|
|
|
38
38
|
* Note: No file paths or code content - only aggregate counts
|
|
39
39
|
*/
|
|
40
40
|
export const RunMetricsSchema = z.object({
|
|
41
|
-
/** Estimated tokens used (if available, 0 if not) */
|
|
41
|
+
/** Estimated tokens used (if available, 0 if not) - total of input + output */
|
|
42
42
|
tokensUsed: z.number().int().nonnegative(),
|
|
43
43
|
/** Number of files changed during the run */
|
|
44
44
|
filesChanged: z.number().int().nonnegative(),
|
|
@@ -48,6 +48,12 @@ export const RunMetricsSchema = z.object({
|
|
|
48
48
|
acceptanceCriteria: z.number().int().nonnegative(),
|
|
49
49
|
/** Number of QA iterations needed */
|
|
50
50
|
qaIterations: z.number().int().nonnegative(),
|
|
51
|
+
/** Input tokens used (AC-4 token breakdown) */
|
|
52
|
+
inputTokens: z.number().int().nonnegative().optional(),
|
|
53
|
+
/** Output tokens used (AC-4 token breakdown) */
|
|
54
|
+
outputTokens: z.number().int().nonnegative().optional(),
|
|
55
|
+
/** Cache tokens (creation + read) (AC-4 token breakdown) */
|
|
56
|
+
cacheTokens: z.number().int().nonnegative().optional(),
|
|
51
57
|
});
|
|
52
58
|
/**
|
|
53
59
|
* Single workflow run record
|
|
@@ -121,6 +127,9 @@ export function createMetricRun(options) {
|
|
|
121
127
|
linesAdded: options.metrics?.linesAdded ?? 0,
|
|
122
128
|
acceptanceCriteria: options.metrics?.acceptanceCriteria ?? 0,
|
|
123
129
|
qaIterations: options.metrics?.qaIterations ?? 0,
|
|
130
|
+
inputTokens: options.metrics?.inputTokens,
|
|
131
|
+
outputTokens: options.metrics?.outputTokens,
|
|
132
|
+
cacheTokens: options.metrics?.cacheTokens,
|
|
124
133
|
},
|
|
125
134
|
};
|
|
126
135
|
}
|
|
@@ -21,6 +21,9 @@ export declare function formatPhaseMarker(marker: PhaseMarker): string;
|
|
|
21
21
|
/**
|
|
22
22
|
* Parse all phase markers from a single comment body.
|
|
23
23
|
*
|
|
24
|
+
* Phase markers inside fenced code blocks (```...```) or inline code (`...`)
|
|
25
|
+
* are ignored to prevent false positives from documentation examples.
|
|
26
|
+
*
|
|
24
27
|
* @param commentBody - The full body text of a GitHub comment
|
|
25
28
|
* @returns Array of parsed phase markers (empty if none found)
|
|
26
29
|
*/
|
|
@@ -14,6 +14,27 @@ import { execSync } from "child_process";
|
|
|
14
14
|
import { PhaseMarkerSchema, WORKFLOW_PHASES, } from "./state-schema.js";
|
|
15
15
|
/** Regex to extract phase marker JSON from HTML comments */
|
|
16
16
|
const PHASE_MARKER_REGEX = /<!-- SEQUANT_PHASE: (\{[^}]+\}) -->/g;
|
|
17
|
+
/**
|
|
18
|
+
* Regex patterns for markdown code constructs that should be ignored.
|
|
19
|
+
* - Fenced code blocks: 3+ backticks or tildes (CommonMark spec)
|
|
20
|
+
* - Inline code: `...`
|
|
21
|
+
*/
|
|
22
|
+
const FENCED_CODE_BLOCK_REGEX = /`{3,}[\s\S]*?`{3,}|~{3,}[\s\S]*?~{3,}/g;
|
|
23
|
+
const INLINE_CODE_REGEX = /`[^`\n]+`/g;
|
|
24
|
+
/**
|
|
25
|
+
* Strip markdown code blocks and inline code from text.
|
|
26
|
+
* This prevents phase markers inside code examples from being parsed.
|
|
27
|
+
*
|
|
28
|
+
* @param text - The text to strip code from
|
|
29
|
+
* @returns Text with code blocks and inline code removed
|
|
30
|
+
*/
|
|
31
|
+
function stripMarkdownCode(text) {
|
|
32
|
+
// First remove fenced code blocks (multi-line)
|
|
33
|
+
let result = text.replace(FENCED_CODE_BLOCK_REGEX, "");
|
|
34
|
+
// Then remove inline code
|
|
35
|
+
result = result.replace(INLINE_CODE_REGEX, "");
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
17
38
|
/**
|
|
18
39
|
* Format a phase marker as an HTML comment string for embedding in GitHub comments.
|
|
19
40
|
*
|
|
@@ -26,15 +47,20 @@ export function formatPhaseMarker(marker) {
|
|
|
26
47
|
/**
|
|
27
48
|
* Parse all phase markers from a single comment body.
|
|
28
49
|
*
|
|
50
|
+
* Phase markers inside fenced code blocks (```...```) or inline code (`...`)
|
|
51
|
+
* are ignored to prevent false positives from documentation examples.
|
|
52
|
+
*
|
|
29
53
|
* @param commentBody - The full body text of a GitHub comment
|
|
30
54
|
* @returns Array of parsed phase markers (empty if none found)
|
|
31
55
|
*/
|
|
32
56
|
export function parsePhaseMarkers(commentBody) {
|
|
33
57
|
const markers = [];
|
|
58
|
+
// Strip code blocks before matching to avoid false positives
|
|
59
|
+
const strippedBody = stripMarkdownCode(commentBody);
|
|
34
60
|
// Reset regex state for reuse
|
|
35
61
|
PHASE_MARKER_REGEX.lastIndex = 0;
|
|
36
62
|
let match;
|
|
37
|
-
while ((match = PHASE_MARKER_REGEX.exec(
|
|
63
|
+
while ((match = PHASE_MARKER_REGEX.exec(strippedBody)) !== null) {
|
|
38
64
|
try {
|
|
39
65
|
const parsed = JSON.parse(match[1]);
|
|
40
66
|
const result = PhaseMarkerSchema.safeParse(parsed);
|
|
@@ -28,7 +28,7 @@ import { z } from "zod";
|
|
|
28
28
|
/**
|
|
29
29
|
* Check types that can be cached
|
|
30
30
|
*/
|
|
31
|
-
export declare const CHECK_TYPES: readonly ["type-safety", "deleted-tests", "scope", "size", "security", "semgrep", "build", "tests"];
|
|
31
|
+
export declare const CHECK_TYPES: readonly ["type-safety", "deleted-tests", "scope", "size", "security", "semgrep", "build", "tests", "test-quality"];
|
|
32
32
|
export type CheckType = (typeof CHECK_TYPES)[number];
|
|
33
33
|
/**
|
|
34
34
|
* Schema for a single cached check result
|
|
@@ -43,6 +43,7 @@ export declare const CachedCheckResultSchema: z.ZodObject<{
|
|
|
43
43
|
scope: "scope";
|
|
44
44
|
size: "size";
|
|
45
45
|
tests: "tests";
|
|
46
|
+
"test-quality": "test-quality";
|
|
46
47
|
}>;
|
|
47
48
|
diffHash: z.ZodString;
|
|
48
49
|
configHash: z.ZodString;
|
|
@@ -71,6 +72,7 @@ export declare const QACacheSchema: z.ZodObject<{
|
|
|
71
72
|
scope: "scope";
|
|
72
73
|
size: "size";
|
|
73
74
|
tests: "tests";
|
|
75
|
+
"test-quality": "test-quality";
|
|
74
76
|
}>;
|
|
75
77
|
diffHash: z.ZodString;
|
|
76
78
|
configHash: z.ZodString;
|
|
@@ -41,6 +41,7 @@ export const CHECK_TYPES = [
|
|
|
41
41
|
"semgrep",
|
|
42
42
|
"build",
|
|
43
43
|
"tests",
|
|
44
|
+
"test-quality",
|
|
44
45
|
];
|
|
45
46
|
/**
|
|
46
47
|
* Schema for a single cached check result
|
|
@@ -106,6 +107,7 @@ const CHECK_INVALIDATION_PATTERNS = {
|
|
|
106
107
|
semgrep: [/\.ts$/, /\.tsx$/, /\.js$/, /\.jsx$/, /semgrep.*\.ya?ml$/],
|
|
107
108
|
build: [/\.ts$/, /\.tsx$/, /\.js$/, /\.jsx$/, /tsconfig.*\.json$/],
|
|
108
109
|
tests: [/\.test\.[jt]sx?$/, /\.spec\.[jt]sx?$/, /jest\.config/],
|
|
110
|
+
"test-quality": [/\.test\.[jt]sx?$/, /\.spec\.[jt]sx?$/],
|
|
109
111
|
};
|
|
110
112
|
/**
|
|
111
113
|
* QA Cache Manager
|
|
@@ -58,6 +58,30 @@ export declare const QaVerdictSchema: z.ZodEnum<{
|
|
|
58
58
|
NEEDS_VERIFICATION: "NEEDS_VERIFICATION";
|
|
59
59
|
}>;
|
|
60
60
|
export type QaVerdict = z.infer<typeof QaVerdictSchema>;
|
|
61
|
+
/**
|
|
62
|
+
* File diff statistics for a single file (AC-3)
|
|
63
|
+
*/
|
|
64
|
+
export declare const FileDiffStatSchema: z.ZodObject<{
|
|
65
|
+
path: z.ZodString;
|
|
66
|
+
additions: z.ZodNumber;
|
|
67
|
+
deletions: z.ZodNumber;
|
|
68
|
+
status: z.ZodEnum<{
|
|
69
|
+
modified: "modified";
|
|
70
|
+
added: "added";
|
|
71
|
+
deleted: "deleted";
|
|
72
|
+
renamed: "renamed";
|
|
73
|
+
}>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
export type FileDiffStat = z.infer<typeof FileDiffStatSchema>;
|
|
76
|
+
/**
|
|
77
|
+
* Cache metrics for QA phase (AC-7)
|
|
78
|
+
*/
|
|
79
|
+
export declare const CacheMetricsSchema: z.ZodObject<{
|
|
80
|
+
hits: z.ZodNumber;
|
|
81
|
+
misses: z.ZodNumber;
|
|
82
|
+
skipped: z.ZodNumber;
|
|
83
|
+
}, z.core.$strip>;
|
|
84
|
+
export type CacheMetrics = z.infer<typeof CacheMetricsSchema>;
|
|
61
85
|
/**
|
|
62
86
|
* Log entry for a single phase execution
|
|
63
87
|
*/
|
|
@@ -92,6 +116,23 @@ export declare const PhaseLogSchema: z.ZodObject<{
|
|
|
92
116
|
AC_NOT_MET: "AC_NOT_MET";
|
|
93
117
|
NEEDS_VERIFICATION: "NEEDS_VERIFICATION";
|
|
94
118
|
}>>;
|
|
119
|
+
commitHash: z.ZodOptional<z.ZodString>;
|
|
120
|
+
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
121
|
+
path: z.ZodString;
|
|
122
|
+
additions: z.ZodNumber;
|
|
123
|
+
deletions: z.ZodNumber;
|
|
124
|
+
status: z.ZodEnum<{
|
|
125
|
+
modified: "modified";
|
|
126
|
+
added: "added";
|
|
127
|
+
deleted: "deleted";
|
|
128
|
+
renamed: "renamed";
|
|
129
|
+
}>;
|
|
130
|
+
}, z.core.$strip>>>;
|
|
131
|
+
cacheMetrics: z.ZodOptional<z.ZodObject<{
|
|
132
|
+
hits: z.ZodNumber;
|
|
133
|
+
misses: z.ZodNumber;
|
|
134
|
+
skipped: z.ZodNumber;
|
|
135
|
+
}, z.core.$strip>>;
|
|
95
136
|
}, z.core.$strip>;
|
|
96
137
|
export type PhaseLog = z.infer<typeof PhaseLogSchema>;
|
|
97
138
|
/**
|
|
@@ -137,6 +178,23 @@ export declare const IssueLogSchema: z.ZodObject<{
|
|
|
137
178
|
AC_NOT_MET: "AC_NOT_MET";
|
|
138
179
|
NEEDS_VERIFICATION: "NEEDS_VERIFICATION";
|
|
139
180
|
}>>;
|
|
181
|
+
commitHash: z.ZodOptional<z.ZodString>;
|
|
182
|
+
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
183
|
+
path: z.ZodString;
|
|
184
|
+
additions: z.ZodNumber;
|
|
185
|
+
deletions: z.ZodNumber;
|
|
186
|
+
status: z.ZodEnum<{
|
|
187
|
+
modified: "modified";
|
|
188
|
+
added: "added";
|
|
189
|
+
deleted: "deleted";
|
|
190
|
+
renamed: "renamed";
|
|
191
|
+
}>;
|
|
192
|
+
}, z.core.$strip>>>;
|
|
193
|
+
cacheMetrics: z.ZodOptional<z.ZodObject<{
|
|
194
|
+
hits: z.ZodNumber;
|
|
195
|
+
misses: z.ZodNumber;
|
|
196
|
+
skipped: z.ZodNumber;
|
|
197
|
+
}, z.core.$strip>>;
|
|
140
198
|
}, z.core.$strip>>;
|
|
141
199
|
totalDurationSeconds: z.ZodNumber;
|
|
142
200
|
}, z.core.$strip>;
|
|
@@ -237,6 +295,23 @@ export declare const RunLogSchema: z.ZodObject<{
|
|
|
237
295
|
AC_NOT_MET: "AC_NOT_MET";
|
|
238
296
|
NEEDS_VERIFICATION: "NEEDS_VERIFICATION";
|
|
239
297
|
}>>;
|
|
298
|
+
commitHash: z.ZodOptional<z.ZodString>;
|
|
299
|
+
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
300
|
+
path: z.ZodString;
|
|
301
|
+
additions: z.ZodNumber;
|
|
302
|
+
deletions: z.ZodNumber;
|
|
303
|
+
status: z.ZodEnum<{
|
|
304
|
+
modified: "modified";
|
|
305
|
+
added: "added";
|
|
306
|
+
deleted: "deleted";
|
|
307
|
+
renamed: "renamed";
|
|
308
|
+
}>;
|
|
309
|
+
}, z.core.$strip>>>;
|
|
310
|
+
cacheMetrics: z.ZodOptional<z.ZodObject<{
|
|
311
|
+
hits: z.ZodNumber;
|
|
312
|
+
misses: z.ZodNumber;
|
|
313
|
+
skipped: z.ZodNumber;
|
|
314
|
+
}, z.core.$strip>>;
|
|
240
315
|
}, z.core.$strip>>;
|
|
241
316
|
totalDurationSeconds: z.ZodNumber;
|
|
242
317
|
}, z.core.$strip>>;
|
|
@@ -246,6 +321,8 @@ export declare const RunLogSchema: z.ZodObject<{
|
|
|
246
321
|
failed: z.ZodNumber;
|
|
247
322
|
totalDurationSeconds: z.ZodNumber;
|
|
248
323
|
}, z.core.$strip>;
|
|
324
|
+
startCommit: z.ZodOptional<z.ZodString>;
|
|
325
|
+
endCommit: z.ZodOptional<z.ZodString>;
|
|
249
326
|
}, z.core.$strip>;
|
|
250
327
|
export type RunLog = z.infer<typeof RunLogSchema>;
|
|
251
328
|
/**
|
|
@@ -269,9 +346,12 @@ export declare function generateLogFilename(runId: string, startTime: Date): str
|
|
|
269
346
|
* Create an empty run log with initial values
|
|
270
347
|
*
|
|
271
348
|
* @param config - Run configuration
|
|
349
|
+
* @param options - Optional fields including startCommit
|
|
272
350
|
* @returns Initial RunLog structure
|
|
273
351
|
*/
|
|
274
|
-
export declare function createEmptyRunLog(config: RunConfig
|
|
352
|
+
export declare function createEmptyRunLog(config: RunConfig, options?: {
|
|
353
|
+
startCommit?: string;
|
|
354
|
+
}): Omit<RunLog, "endTime">;
|
|
275
355
|
/**
|
|
276
356
|
* Create a phase log entry
|
|
277
357
|
*
|
|
@@ -288,11 +368,14 @@ export declare function createPhaseLog(phase: Phase, issueNumber: number): Omit<
|
|
|
288
368
|
* @param options - Additional fields (error, filesModified, verdict, etc.)
|
|
289
369
|
* @returns Complete PhaseLog
|
|
290
370
|
*/
|
|
291
|
-
export declare function completePhaseLog(phaseLog: Omit<PhaseLog, "endTime" | "durationSeconds" | "status">, status: PhaseStatus, options?: Partial<Pick<PhaseLog, "error" | "iterations" | "filesModified" | "testsRun" | "testsPassed" | "verdict">>): PhaseLog;
|
|
371
|
+
export declare function completePhaseLog(phaseLog: Omit<PhaseLog, "endTime" | "durationSeconds" | "status">, status: PhaseStatus, options?: Partial<Pick<PhaseLog, "error" | "iterations" | "filesModified" | "testsRun" | "testsPassed" | "verdict" | "commitHash" | "fileDiffStats" | "cacheMetrics">>): PhaseLog;
|
|
292
372
|
/**
|
|
293
373
|
* Finalize a run log with summary statistics
|
|
294
374
|
*
|
|
295
375
|
* @param runLog - Partial run log
|
|
376
|
+
* @param options - Optional fields including endCommit
|
|
296
377
|
* @returns Complete RunLog with endTime and summary
|
|
297
378
|
*/
|
|
298
|
-
export declare function finalizeRunLog(runLog: Omit<RunLog, "endTime"
|
|
379
|
+
export declare function finalizeRunLog(runLog: Omit<RunLog, "endTime">, options?: {
|
|
380
|
+
endCommit?: string;
|
|
381
|
+
}): RunLog;
|
|
@@ -51,6 +51,30 @@ export const QaVerdictSchema = z.enum([
|
|
|
51
51
|
"AC_NOT_MET",
|
|
52
52
|
"NEEDS_VERIFICATION",
|
|
53
53
|
]);
|
|
54
|
+
/**
|
|
55
|
+
* File diff statistics for a single file (AC-3)
|
|
56
|
+
*/
|
|
57
|
+
export const FileDiffStatSchema = z.object({
|
|
58
|
+
/** File path relative to repository root */
|
|
59
|
+
path: z.string(),
|
|
60
|
+
/** Number of lines added */
|
|
61
|
+
additions: z.number().int().nonnegative(),
|
|
62
|
+
/** Number of lines deleted */
|
|
63
|
+
deletions: z.number().int().nonnegative(),
|
|
64
|
+
/** Change status */
|
|
65
|
+
status: z.enum(["added", "modified", "deleted", "renamed"]),
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* Cache metrics for QA phase (AC-7)
|
|
69
|
+
*/
|
|
70
|
+
export const CacheMetricsSchema = z.object({
|
|
71
|
+
/** Number of cache hits */
|
|
72
|
+
hits: z.number().int().nonnegative(),
|
|
73
|
+
/** Number of cache misses */
|
|
74
|
+
misses: z.number().int().nonnegative(),
|
|
75
|
+
/** Number of skipped checks */
|
|
76
|
+
skipped: z.number().int().nonnegative(),
|
|
77
|
+
});
|
|
54
78
|
/**
|
|
55
79
|
* Log entry for a single phase execution
|
|
56
80
|
*/
|
|
@@ -79,6 +103,12 @@ export const PhaseLogSchema = z.object({
|
|
|
79
103
|
testsPassed: z.number().int().nonnegative().optional(),
|
|
80
104
|
/** Parsed QA verdict (only for qa phase) */
|
|
81
105
|
verdict: QaVerdictSchema.optional(),
|
|
106
|
+
/** Git commit SHA after phase completes (AC-2) */
|
|
107
|
+
commitHash: z.string().optional(),
|
|
108
|
+
/** Per-file diff statistics (AC-3) */
|
|
109
|
+
fileDiffStats: z.array(FileDiffStatSchema).optional(),
|
|
110
|
+
/** Cache metrics for QA phase (AC-7) */
|
|
111
|
+
cacheMetrics: CacheMetricsSchema.optional(),
|
|
82
112
|
});
|
|
83
113
|
/**
|
|
84
114
|
* Complete execution record for a single issue
|
|
@@ -147,6 +177,10 @@ export const RunLogSchema = z.object({
|
|
|
147
177
|
issues: z.array(IssueLogSchema),
|
|
148
178
|
/** Summary statistics */
|
|
149
179
|
summary: RunSummarySchema,
|
|
180
|
+
/** Git commit SHA at run start (AC-2) */
|
|
181
|
+
startCommit: z.string().optional(),
|
|
182
|
+
/** Git commit SHA at run end (AC-2) */
|
|
183
|
+
endCommit: z.string().optional(),
|
|
150
184
|
});
|
|
151
185
|
/**
|
|
152
186
|
* Default log directory paths
|
|
@@ -172,9 +206,10 @@ export function generateLogFilename(runId, startTime) {
|
|
|
172
206
|
* Create an empty run log with initial values
|
|
173
207
|
*
|
|
174
208
|
* @param config - Run configuration
|
|
209
|
+
* @param options - Optional fields including startCommit
|
|
175
210
|
* @returns Initial RunLog structure
|
|
176
211
|
*/
|
|
177
|
-
export function createEmptyRunLog(config) {
|
|
212
|
+
export function createEmptyRunLog(config, options) {
|
|
178
213
|
const runId = randomUUID();
|
|
179
214
|
const startTime = new Date().toISOString();
|
|
180
215
|
return {
|
|
@@ -189,6 +224,7 @@ export function createEmptyRunLog(config) {
|
|
|
189
224
|
failed: 0,
|
|
190
225
|
totalDurationSeconds: 0,
|
|
191
226
|
},
|
|
227
|
+
startCommit: options?.startCommit,
|
|
192
228
|
};
|
|
193
229
|
}
|
|
194
230
|
/**
|
|
@@ -229,9 +265,10 @@ export function completePhaseLog(phaseLog, status, options) {
|
|
|
229
265
|
* Finalize a run log with summary statistics
|
|
230
266
|
*
|
|
231
267
|
* @param runLog - Partial run log
|
|
268
|
+
* @param options - Optional fields including endCommit
|
|
232
269
|
* @returns Complete RunLog with endTime and summary
|
|
233
270
|
*/
|
|
234
|
-
export function finalizeRunLog(runLog) {
|
|
271
|
+
export function finalizeRunLog(runLog, options) {
|
|
235
272
|
const endTime = new Date();
|
|
236
273
|
const startTime = new Date(runLog.startTime);
|
|
237
274
|
const totalDurationSeconds = (endTime.getTime() - startTime.getTime()) / 1000;
|
|
@@ -246,5 +283,6 @@ export function finalizeRunLog(runLog) {
|
|
|
246
283
|
failed,
|
|
247
284
|
totalDurationSeconds,
|
|
248
285
|
},
|
|
286
|
+
endCommit: options?.endCommit ?? runLog.endCommit,
|
|
249
287
|
};
|
|
250
288
|
}
|
|
@@ -128,3 +128,49 @@ export interface DiscoverResult {
|
|
|
128
128
|
* and returns information about worktrees not yet in the state file.
|
|
129
129
|
*/
|
|
130
130
|
export declare function discoverUntrackedWorktrees(options?: DiscoverOptions): Promise<DiscoverResult>;
|
|
131
|
+
export interface ReconcileOptions {
|
|
132
|
+
/** State file path (default: .sequant/state.json) */
|
|
133
|
+
statePath?: string;
|
|
134
|
+
/** Enable verbose logging */
|
|
135
|
+
verbose?: boolean;
|
|
136
|
+
}
|
|
137
|
+
export interface ReconcileResult {
|
|
138
|
+
/** Whether reconciliation was successful */
|
|
139
|
+
success: boolean;
|
|
140
|
+
/** Issues that were advanced from ready_for_merge to merged */
|
|
141
|
+
advanced: number[];
|
|
142
|
+
/** Issues checked but still ready_for_merge */
|
|
143
|
+
stillPending: number[];
|
|
144
|
+
/** Error message if failed */
|
|
145
|
+
error?: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if a branch has been merged into main using git
|
|
149
|
+
*
|
|
150
|
+
* @param branchName - The branch name to check (e.g., "feature/33-some-title")
|
|
151
|
+
* @returns true if the branch is merged into main, false otherwise
|
|
152
|
+
*/
|
|
153
|
+
export declare function isBranchMergedIntoMain(branchName: string): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Check if a feature branch for an issue is merged into main
|
|
156
|
+
*
|
|
157
|
+
* Tries multiple detection methods:
|
|
158
|
+
* 1. Check if branch exists and is merged via `git branch --merged main`
|
|
159
|
+
* 2. Check for merge commits mentioning the issue
|
|
160
|
+
*
|
|
161
|
+
* @param issueNumber - The issue number to check
|
|
162
|
+
* @returns true if the issue's work is merged into main
|
|
163
|
+
*/
|
|
164
|
+
export declare function isIssueMergedIntoMain(issueNumber: number): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Lightweight state reconciliation at run start
|
|
167
|
+
*
|
|
168
|
+
* Checks issues in `ready_for_merge` state and advances them to `merged`
|
|
169
|
+
* if their PRs are merged or their branches are in main.
|
|
170
|
+
*
|
|
171
|
+
* This prevents re-running already completed issues.
|
|
172
|
+
*
|
|
173
|
+
* @param options - Reconciliation options
|
|
174
|
+
* @returns Result with lists of advanced and still-pending issues
|
|
175
|
+
*/
|
|
176
|
+
export declare function reconcileStateAtStartup(options?: ReconcileOptions): Promise<ReconcileResult>;
|