sequant 2.11.0 → 2.13.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +47 -3
- package/dist/dashboard/server.js +4 -0
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/.mcp.json +1 -1
- package/dist/marketplace/external_plugins/sequant/README.md +9 -0
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +331 -12
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +7 -18
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +5 -1
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +62 -8
- package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +187 -28
- package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +127 -23
- package/dist/marketplace/external_plugins/sequant/skills/merger/SKILL.md +130 -13
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +306 -8
- package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +79 -0
- package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +42 -20
- package/dist/marketplace/external_plugins/sequant/skills/spec/references/recommended-workflow.md +14 -1
- package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +23 -6
- package/dist/src/commands/doctor.js +20 -18
- package/dist/src/commands/ready.js +7 -1
- package/dist/src/commands/status.js +4 -0
- package/dist/src/lib/ac-linter.js +26 -0
- package/dist/src/lib/ac-parser.d.ts +40 -0
- package/dist/src/lib/ac-parser.js +202 -16
- package/dist/src/lib/markdown-fence.d.ts +24 -0
- package/dist/src/lib/markdown-fence.js +51 -0
- package/dist/src/lib/mcp-config.d.ts +24 -0
- package/dist/src/lib/mcp-config.js +51 -0
- package/dist/src/lib/scope/analyzer.d.ts +4 -0
- package/dist/src/lib/scope/analyzer.js +7 -1
- package/dist/src/lib/settings.d.ts +73 -14
- package/dist/src/lib/settings.js +45 -3
- package/dist/src/lib/system.d.ts +7 -3
- package/dist/src/lib/system.js +7 -3
- package/dist/src/lib/test-tautology-detector.js +50 -3
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +81 -6
- package/dist/src/lib/workflow/config-resolver.d.ts +30 -2
- package/dist/src/lib/workflow/config-resolver.js +59 -2
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +14 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +36 -4
- package/dist/src/lib/workflow/metrics-schema.d.ts +10 -1
- package/dist/src/lib/workflow/metrics-schema.js +13 -1
- package/dist/src/lib/workflow/metrics-writer.d.ts +3 -1
- package/dist/src/lib/workflow/mutation-marker.d.ts +86 -0
- package/dist/src/lib/workflow/mutation-marker.js +97 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +17 -0
- package/dist/src/lib/workflow/phase-executor.js +60 -6
- package/dist/src/lib/workflow/qa-gaps-marker.d.ts +38 -0
- package/dist/src/lib/workflow/qa-gaps-marker.js +66 -0
- package/dist/src/lib/workflow/ready-gate.d.ts +25 -1
- package/dist/src/lib/workflow/ready-gate.js +81 -11
- package/dist/src/lib/workflow/reconcile.js +4 -2
- package/dist/src/lib/workflow/run-log-schema.d.ts +120 -0
- package/dist/src/lib/workflow/run-log-schema.js +40 -0
- package/dist/src/lib/workflow/run-orchestrator.d.ts +18 -0
- package/dist/src/lib/workflow/run-orchestrator.js +38 -2
- package/dist/src/lib/workflow/state-cleanup.d.ts +4 -4
- package/dist/src/lib/workflow/state-cleanup.js +9 -5
- package/dist/src/lib/workflow/state-schema.d.ts +10 -1
- package/dist/src/lib/workflow/state-schema.js +13 -1
- package/dist/src/lib/workflow/types.d.ts +20 -0
- package/dist/src/mcp/tools/run.js +10 -1
- package/package.json +13 -12
- package/templates/hooks/pre-tool.sh +108 -17
- package/templates/memory/constitution.md +112 -45
- package/templates/skills/exec/SKILL.md +1 -1
- package/templates/skills/fullsolve/SKILL.md +62 -9
- package/templates/skills/loop/SKILL.md +71 -12
- package/templates/skills/merger/SKILL.md +32 -3
- package/templates/skills/qa/SKILL.md +247 -2
- package/templates/skills/spec/SKILL.md +11 -5
- package/templates/skills/test/SKILL.md +1 -1
|
@@ -129,6 +129,50 @@ export declare const ErrorContextSchema: z.ZodObject<{
|
|
|
129
129
|
isRetryable: z.ZodOptional<z.ZodBoolean>;
|
|
130
130
|
}, z.core.$strip>;
|
|
131
131
|
export type ErrorContext = z.infer<typeof ErrorContextSchema>;
|
|
132
|
+
/**
|
|
133
|
+
* Finite taxonomy for a single gap finding surfaced by `/qa` (#937).
|
|
134
|
+
*
|
|
135
|
+
* Replaces the lossy prose-scrape gap channel (`parseListSection` against
|
|
136
|
+
* `**Issues:**`/`**Gaps**` headers, which misses AC-table NOT_MET rows, §6d
|
|
137
|
+
* Adversarial Re-Read findings, and §5 Risk Assessment). `evidence` is
|
|
138
|
+
* required so a finding can't be speculative — see #608's 0%-action-rate
|
|
139
|
+
* result for open-ended "what might we be missing" findings.
|
|
140
|
+
*/
|
|
141
|
+
export declare const GapCategorySchema: z.ZodEnum<{
|
|
142
|
+
requirement_gap: "requirement_gap";
|
|
143
|
+
dependency_gap: "dependency_gap";
|
|
144
|
+
test_gap: "test_gap";
|
|
145
|
+
repository_gap: "repository_gap";
|
|
146
|
+
risk_gap: "risk_gap";
|
|
147
|
+
execution_gap: "execution_gap";
|
|
148
|
+
}>;
|
|
149
|
+
export type GapCategory = z.infer<typeof GapCategorySchema>;
|
|
150
|
+
export declare const GapActionSchema: z.ZodEnum<{
|
|
151
|
+
fix_now: "fix_now";
|
|
152
|
+
document: "document";
|
|
153
|
+
pause_for_human: "pause_for_human";
|
|
154
|
+
}>;
|
|
155
|
+
export type GapAction = z.infer<typeof GapActionSchema>;
|
|
156
|
+
export declare const GapFindingSchema: z.ZodObject<{
|
|
157
|
+
category: z.ZodEnum<{
|
|
158
|
+
requirement_gap: "requirement_gap";
|
|
159
|
+
dependency_gap: "dependency_gap";
|
|
160
|
+
test_gap: "test_gap";
|
|
161
|
+
repository_gap: "repository_gap";
|
|
162
|
+
risk_gap: "risk_gap";
|
|
163
|
+
execution_gap: "execution_gap";
|
|
164
|
+
}>;
|
|
165
|
+
evidence: z.ZodString;
|
|
166
|
+
description: z.ZodString;
|
|
167
|
+
recommendedAction: z.ZodEnum<{
|
|
168
|
+
fix_now: "fix_now";
|
|
169
|
+
document: "document";
|
|
170
|
+
pause_for_human: "pause_for_human";
|
|
171
|
+
}>;
|
|
172
|
+
affectedAcs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
173
|
+
nonGoal: z.ZodOptional<z.ZodBoolean>;
|
|
174
|
+
}, z.core.$strip>;
|
|
175
|
+
export type GapFinding = z.infer<typeof GapFindingSchema>;
|
|
132
176
|
/**
|
|
133
177
|
* Condensed QA verdict summary for structured log output (#434).
|
|
134
178
|
*
|
|
@@ -141,6 +185,25 @@ export declare const QaSummarySchema: z.ZodObject<{
|
|
|
141
185
|
acTotal: z.ZodNumber;
|
|
142
186
|
gaps: z.ZodArray<z.ZodString>;
|
|
143
187
|
suggestions: z.ZodArray<z.ZodString>;
|
|
188
|
+
findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
189
|
+
category: z.ZodEnum<{
|
|
190
|
+
requirement_gap: "requirement_gap";
|
|
191
|
+
dependency_gap: "dependency_gap";
|
|
192
|
+
test_gap: "test_gap";
|
|
193
|
+
repository_gap: "repository_gap";
|
|
194
|
+
risk_gap: "risk_gap";
|
|
195
|
+
execution_gap: "execution_gap";
|
|
196
|
+
}>;
|
|
197
|
+
evidence: z.ZodString;
|
|
198
|
+
description: z.ZodString;
|
|
199
|
+
recommendedAction: z.ZodEnum<{
|
|
200
|
+
fix_now: "fix_now";
|
|
201
|
+
document: "document";
|
|
202
|
+
pause_for_human: "pause_for_human";
|
|
203
|
+
}>;
|
|
204
|
+
affectedAcs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
205
|
+
nonGoal: z.ZodOptional<z.ZodBoolean>;
|
|
206
|
+
}, z.core.$strip>>>;
|
|
144
207
|
}, z.core.$strip>;
|
|
145
208
|
export type QaSummary = z.infer<typeof QaSummarySchema>;
|
|
146
209
|
/**
|
|
@@ -175,6 +238,25 @@ export declare const PhaseLogSchema: z.ZodObject<{
|
|
|
175
238
|
acTotal: z.ZodNumber;
|
|
176
239
|
gaps: z.ZodArray<z.ZodString>;
|
|
177
240
|
suggestions: z.ZodArray<z.ZodString>;
|
|
241
|
+
findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
242
|
+
category: z.ZodEnum<{
|
|
243
|
+
requirement_gap: "requirement_gap";
|
|
244
|
+
dependency_gap: "dependency_gap";
|
|
245
|
+
test_gap: "test_gap";
|
|
246
|
+
repository_gap: "repository_gap";
|
|
247
|
+
risk_gap: "risk_gap";
|
|
248
|
+
execution_gap: "execution_gap";
|
|
249
|
+
}>;
|
|
250
|
+
evidence: z.ZodString;
|
|
251
|
+
description: z.ZodString;
|
|
252
|
+
recommendedAction: z.ZodEnum<{
|
|
253
|
+
fix_now: "fix_now";
|
|
254
|
+
document: "document";
|
|
255
|
+
pause_for_human: "pause_for_human";
|
|
256
|
+
}>;
|
|
257
|
+
affectedAcs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
258
|
+
nonGoal: z.ZodOptional<z.ZodBoolean>;
|
|
259
|
+
}, z.core.$strip>>>;
|
|
178
260
|
}, z.core.$strip>>;
|
|
179
261
|
commitHash: z.ZodOptional<z.ZodString>;
|
|
180
262
|
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -255,6 +337,25 @@ export declare const IssueLogSchema: z.ZodObject<{
|
|
|
255
337
|
acTotal: z.ZodNumber;
|
|
256
338
|
gaps: z.ZodArray<z.ZodString>;
|
|
257
339
|
suggestions: z.ZodArray<z.ZodString>;
|
|
340
|
+
findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
341
|
+
category: z.ZodEnum<{
|
|
342
|
+
requirement_gap: "requirement_gap";
|
|
343
|
+
dependency_gap: "dependency_gap";
|
|
344
|
+
test_gap: "test_gap";
|
|
345
|
+
repository_gap: "repository_gap";
|
|
346
|
+
risk_gap: "risk_gap";
|
|
347
|
+
execution_gap: "execution_gap";
|
|
348
|
+
}>;
|
|
349
|
+
evidence: z.ZodString;
|
|
350
|
+
description: z.ZodString;
|
|
351
|
+
recommendedAction: z.ZodEnum<{
|
|
352
|
+
fix_now: "fix_now";
|
|
353
|
+
document: "document";
|
|
354
|
+
pause_for_human: "pause_for_human";
|
|
355
|
+
}>;
|
|
356
|
+
affectedAcs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
357
|
+
nonGoal: z.ZodOptional<z.ZodBoolean>;
|
|
358
|
+
}, z.core.$strip>>>;
|
|
258
359
|
}, z.core.$strip>>;
|
|
259
360
|
commitHash: z.ZodOptional<z.ZodString>;
|
|
260
361
|
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -390,6 +491,25 @@ export declare const RunLogSchema: z.ZodObject<{
|
|
|
390
491
|
acTotal: z.ZodNumber;
|
|
391
492
|
gaps: z.ZodArray<z.ZodString>;
|
|
392
493
|
suggestions: z.ZodArray<z.ZodString>;
|
|
494
|
+
findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
495
|
+
category: z.ZodEnum<{
|
|
496
|
+
requirement_gap: "requirement_gap";
|
|
497
|
+
dependency_gap: "dependency_gap";
|
|
498
|
+
test_gap: "test_gap";
|
|
499
|
+
repository_gap: "repository_gap";
|
|
500
|
+
risk_gap: "risk_gap";
|
|
501
|
+
execution_gap: "execution_gap";
|
|
502
|
+
}>;
|
|
503
|
+
evidence: z.ZodString;
|
|
504
|
+
description: z.ZodString;
|
|
505
|
+
recommendedAction: z.ZodEnum<{
|
|
506
|
+
fix_now: "fix_now";
|
|
507
|
+
document: "document";
|
|
508
|
+
pause_for_human: "pause_for_human";
|
|
509
|
+
}>;
|
|
510
|
+
affectedAcs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
511
|
+
nonGoal: z.ZodOptional<z.ZodBoolean>;
|
|
512
|
+
}, z.core.$strip>>>;
|
|
393
513
|
}, z.core.$strip>>;
|
|
394
514
|
commitHash: z.ZodOptional<z.ZodString>;
|
|
395
515
|
fileDiffStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -129,6 +129,39 @@ export const ErrorContextSchema = z.object({
|
|
|
129
129
|
/** Whether this error type is retryable (AC-9) */
|
|
130
130
|
isRetryable: z.boolean().optional(),
|
|
131
131
|
});
|
|
132
|
+
/**
|
|
133
|
+
* Finite taxonomy for a single gap finding surfaced by `/qa` (#937).
|
|
134
|
+
*
|
|
135
|
+
* Replaces the lossy prose-scrape gap channel (`parseListSection` against
|
|
136
|
+
* `**Issues:**`/`**Gaps**` headers, which misses AC-table NOT_MET rows, §6d
|
|
137
|
+
* Adversarial Re-Read findings, and §5 Risk Assessment). `evidence` is
|
|
138
|
+
* required so a finding can't be speculative — see #608's 0%-action-rate
|
|
139
|
+
* result for open-ended "what might we be missing" findings.
|
|
140
|
+
*/
|
|
141
|
+
export const GapCategorySchema = z.enum([
|
|
142
|
+
"requirement_gap",
|
|
143
|
+
"dependency_gap",
|
|
144
|
+
"test_gap",
|
|
145
|
+
"repository_gap",
|
|
146
|
+
"risk_gap",
|
|
147
|
+
"execution_gap",
|
|
148
|
+
]);
|
|
149
|
+
export const GapActionSchema = z.enum([
|
|
150
|
+
"fix_now",
|
|
151
|
+
"document",
|
|
152
|
+
"pause_for_human",
|
|
153
|
+
]);
|
|
154
|
+
export const GapFindingSchema = z.object({
|
|
155
|
+
category: GapCategorySchema,
|
|
156
|
+
/** Concrete observation grounding the finding — never speculation. */
|
|
157
|
+
evidence: z.string().min(1),
|
|
158
|
+
description: z.string().min(1),
|
|
159
|
+
recommendedAction: GapActionSchema,
|
|
160
|
+
/** ACs this finding relates to, e.g. ["AC-3"]. */
|
|
161
|
+
affectedAcs: z.array(z.string()).optional(),
|
|
162
|
+
/** True when the finding overlaps one of the issue's Non-Goals. */
|
|
163
|
+
nonGoal: z.boolean().optional(),
|
|
164
|
+
});
|
|
132
165
|
/**
|
|
133
166
|
* Condensed QA verdict summary for structured log output (#434).
|
|
134
167
|
*
|
|
@@ -145,6 +178,13 @@ export const QaSummarySchema = z.object({
|
|
|
145
178
|
gaps: z.array(z.string()),
|
|
146
179
|
/** List of improvement suggestions from QA */
|
|
147
180
|
suggestions: z.array(z.string()),
|
|
181
|
+
/**
|
|
182
|
+
* Structured gap findings parsed from the `SEQUANT_QA_GAPS` marker (#937).
|
|
183
|
+
* Present only when the marker was found and validated; `gaps` above
|
|
184
|
+
* always carries the union of marker + prose descriptions (dedupe'd) so
|
|
185
|
+
* marker-unaware consumers never regress.
|
|
186
|
+
*/
|
|
187
|
+
findings: z.array(GapFindingSchema).optional(),
|
|
148
188
|
});
|
|
149
189
|
/**
|
|
150
190
|
* Log entry for a single phase execution
|
|
@@ -16,6 +16,7 @@ import type { LockFile } from "../locks/index.js";
|
|
|
16
16
|
import { type ChainResumePlan } from "./chain-resume.js";
|
|
17
17
|
import { WorkflowEventEmitter } from "./event-emitter.js";
|
|
18
18
|
import type { SequantSettings } from "../settings.js";
|
|
19
|
+
import { type PhasePolicy } from "./config-resolver.js";
|
|
19
20
|
/**
|
|
20
21
|
* Build the stack-manifest line emitted into PR bodies under --stacked.
|
|
21
22
|
*
|
|
@@ -172,6 +173,23 @@ export interface RunResult {
|
|
|
172
173
|
*/
|
|
173
174
|
wallClockDurationSeconds: number;
|
|
174
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Merge per-phase `resolvedModel` from execution results into the static
|
|
178
|
+
* phasePolicies map before it is written to metrics (#975 AC-4).
|
|
179
|
+
*
|
|
180
|
+
* `config.phasePolicies` carries the model alias resolved at config time (e.g.
|
|
181
|
+
* `"sonnet"`). The concrete model ID only becomes known after execution, from
|
|
182
|
+
* the driver's `modelUsage` map. This function enriches each phase entry with
|
|
183
|
+
* that runtime-observed value so benchmark comparisons across roster changes
|
|
184
|
+
* (#916/#944) see the actual model dispatched, not just the alias.
|
|
185
|
+
*
|
|
186
|
+
* `requestedModel` (the pre-resolution role string, e.g. `"role:fast"`) flows
|
|
187
|
+
* through from `config.phasePolicies` unchanged — it is already set by
|
|
188
|
+
* `resolvePhasePolicies` for role references and absent for raw strings.
|
|
189
|
+
*
|
|
190
|
+
* @internal Exported for testing only.
|
|
191
|
+
*/
|
|
192
|
+
export declare function enrichPhasePoliciesFromResults(phasePolicies: Record<string, PhasePolicy> | undefined, results: IssueResult[]): Record<string, PhasePolicy> | undefined;
|
|
175
193
|
/**
|
|
176
194
|
* CLI-free workflow execution engine.
|
|
177
195
|
*
|
|
@@ -82,7 +82,7 @@ import { MetricsWriter } from "./metrics-writer.js";
|
|
|
82
82
|
import { WorkflowEventEmitter } from "./event-emitter.js";
|
|
83
83
|
import { determineOutcome } from "./metrics-schema.js";
|
|
84
84
|
import { getTokenUsageForRun } from "./token-utils.js";
|
|
85
|
-
import { resolveRunOptions, buildExecutionConfig } from "./config-resolver.js";
|
|
85
|
+
import { resolveRunOptions, buildExecutionConfig, } from "./config-resolver.js";
|
|
86
86
|
import { pipelineHasFailed } from "./status-derivation.js";
|
|
87
87
|
/**
|
|
88
88
|
* Build the stack-manifest line emitted into PR bodies under --stacked.
|
|
@@ -96,6 +96,40 @@ export function buildStackManifest(issueNumbers, currentIndex) {
|
|
|
96
96
|
const parts = issueNumbers.map((n, i) => i === currentIndex ? `#${n} (this)` : `#${n}`);
|
|
97
97
|
return `Part of stack: ${parts.join(" → ")}`;
|
|
98
98
|
}
|
|
99
|
+
// ── Metrics helpers ─────────────────────────────────────────────────────────
|
|
100
|
+
/**
|
|
101
|
+
* Merge per-phase `resolvedModel` from execution results into the static
|
|
102
|
+
* phasePolicies map before it is written to metrics (#975 AC-4).
|
|
103
|
+
*
|
|
104
|
+
* `config.phasePolicies` carries the model alias resolved at config time (e.g.
|
|
105
|
+
* `"sonnet"`). The concrete model ID only becomes known after execution, from
|
|
106
|
+
* the driver's `modelUsage` map. This function enriches each phase entry with
|
|
107
|
+
* that runtime-observed value so benchmark comparisons across roster changes
|
|
108
|
+
* (#916/#944) see the actual model dispatched, not just the alias.
|
|
109
|
+
*
|
|
110
|
+
* `requestedModel` (the pre-resolution role string, e.g. `"role:fast"`) flows
|
|
111
|
+
* through from `config.phasePolicies` unchanged — it is already set by
|
|
112
|
+
* `resolvePhasePolicies` for role references and absent for raw strings.
|
|
113
|
+
*
|
|
114
|
+
* @internal Exported for testing only.
|
|
115
|
+
*/
|
|
116
|
+
export function enrichPhasePoliciesFromResults(phasePolicies, results) {
|
|
117
|
+
const resolvedByPhase = new Map();
|
|
118
|
+
for (const result of results) {
|
|
119
|
+
for (const pr of result.phaseResults) {
|
|
120
|
+
if (pr.resolvedModel) {
|
|
121
|
+
resolvedByPhase.set(pr.phase, pr.resolvedModel);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (resolvedByPhase.size === 0)
|
|
126
|
+
return phasePolicies;
|
|
127
|
+
const enriched = { ...(phasePolicies ?? {}) };
|
|
128
|
+
for (const [phase, resolvedModel] of resolvedByPhase.entries()) {
|
|
129
|
+
enriched[phase] = { ...enriched[phase], resolvedModel };
|
|
130
|
+
}
|
|
131
|
+
return enriched;
|
|
132
|
+
}
|
|
99
133
|
// ── Orchestrator ────────────────────────────────────────────────────────────
|
|
100
134
|
/**
|
|
101
135
|
* CLI-free workflow execution engine.
|
|
@@ -1239,7 +1273,9 @@ export class RunOrchestrator {
|
|
|
1239
1273
|
flags: cliFlags,
|
|
1240
1274
|
failureCategory,
|
|
1241
1275
|
// #914: resolved per-phase model/effort, when any phase had one.
|
|
1242
|
-
|
|
1276
|
+
// #975: enriched with resolvedModel from execution (modelUsage) and
|
|
1277
|
+
// requestedModel already flows through from resolvePhasePolicies.
|
|
1278
|
+
phasePolicies: enrichPhasePoliciesFromResults(config.phasePolicies, results),
|
|
1243
1279
|
// #915: escalated tiers, when any phase execution escalated.
|
|
1244
1280
|
effortEscalations,
|
|
1245
1281
|
metrics: {
|
|
@@ -58,7 +58,7 @@ export interface ReconcileOptions {
|
|
|
58
58
|
export interface ReconcileResult {
|
|
59
59
|
/** Whether reconciliation was successful */
|
|
60
60
|
success: boolean;
|
|
61
|
-
/** Issues advanced to `merged` (from `ready_for_merge`, `in_progress`, or `
|
|
61
|
+
/** Issues advanced to `merged` (from `ready_for_merge`, `in_progress`, `waiting_for_qa_gate`, `waiting_for_human_merge`, or `awaiting_verification`) */
|
|
62
62
|
advanced: number[];
|
|
63
63
|
/** Issues checked but not yet merged (status unchanged) */
|
|
64
64
|
stillPending: number[];
|
|
@@ -68,9 +68,9 @@ export interface ReconcileResult {
|
|
|
68
68
|
/**
|
|
69
69
|
* Lightweight state reconciliation at run start
|
|
70
70
|
*
|
|
71
|
-
* Checks issues in `ready_for_merge`, `in_progress`,
|
|
72
|
-
*
|
|
73
|
-
* are in main.
|
|
71
|
+
* Checks issues in `ready_for_merge`, `in_progress`, `waiting_for_qa_gate`,
|
|
72
|
+
* `waiting_for_human_merge`, or `awaiting_verification` state and advances
|
|
73
|
+
* them to `merged` if their PRs are merged or their branches are in main.
|
|
74
74
|
*
|
|
75
75
|
* Including `in_progress` covers the case where a PR was merged outside
|
|
76
76
|
* this sequant session (separate process, `gh pr merge`, web UI) — without
|
|
@@ -188,9 +188,9 @@ export async function cleanupStaleEntries(options = {}) {
|
|
|
188
188
|
/**
|
|
189
189
|
* Lightweight state reconciliation at run start
|
|
190
190
|
*
|
|
191
|
-
* Checks issues in `ready_for_merge`, `in_progress`,
|
|
192
|
-
*
|
|
193
|
-
* are in main.
|
|
191
|
+
* Checks issues in `ready_for_merge`, `in_progress`, `waiting_for_qa_gate`,
|
|
192
|
+
* `waiting_for_human_merge`, or `awaiting_verification` state and advances
|
|
193
|
+
* them to `merged` if their PRs are merged or their branches are in main.
|
|
194
194
|
*
|
|
195
195
|
* Including `in_progress` covers the case where a PR was merged outside
|
|
196
196
|
* this sequant session (separate process, `gh pr merge`, web UI) — without
|
|
@@ -227,14 +227,18 @@ export async function reconcileStateAtStartup(options = {}) {
|
|
|
227
227
|
// waiting_for_human_merge covers #817's `--ready-gate` terminal: a gated
|
|
228
228
|
// issue never reaches ready_for_merge, so without it a gated issue whose PR
|
|
229
229
|
// a human then merged stayed here forever and never advanced to merged
|
|
230
|
-
// (#837).
|
|
230
|
+
// (#837). awaiting_verification covers the same shape for #972: the issue
|
|
231
|
+
// has an open PR pending human verification, and the human may verify and
|
|
232
|
+
// merge it directly instead of re-running qa first.
|
|
233
|
+
// Note this list is deliberately WIDER than `isCompletedIssueStatus`
|
|
231
234
|
// — it asks "might this have a merged PR?", not "is this done?", which is
|
|
232
235
|
// why in_progress belongs here but not there.
|
|
233
236
|
for (const [issueNumStr, issueState] of Object.entries(state.issues)) {
|
|
234
237
|
if (issueState.status !== "ready_for_merge" &&
|
|
235
238
|
issueState.status !== "in_progress" &&
|
|
236
239
|
issueState.status !== "waiting_for_qa_gate" &&
|
|
237
|
-
issueState.status !== "waiting_for_human_merge"
|
|
240
|
+
issueState.status !== "waiting_for_human_merge" &&
|
|
241
|
+
issueState.status !== "awaiting_verification") {
|
|
238
242
|
continue;
|
|
239
243
|
}
|
|
240
244
|
const issueNum = parseInt(issueNumStr, 10);
|
|
@@ -47,6 +47,7 @@ export declare const IssueStatusSchema: z.ZodEnum<{
|
|
|
47
47
|
not_started: "not_started";
|
|
48
48
|
waiting_for_qa_gate: "waiting_for_qa_gate";
|
|
49
49
|
waiting_for_human_merge: "waiting_for_human_merge";
|
|
50
|
+
awaiting_verification: "awaiting_verification";
|
|
50
51
|
ready_for_merge: "ready_for_merge";
|
|
51
52
|
blocked: "blocked";
|
|
52
53
|
abandoned: "abandoned";
|
|
@@ -72,6 +73,8 @@ export declare const PhaseMarkerSchema: z.ZodObject<{
|
|
|
72
73
|
pr: z.ZodOptional<z.ZodNumber>;
|
|
73
74
|
error: z.ZodOptional<z.ZodString>;
|
|
74
75
|
commitSHA: z.ZodOptional<z.ZodString>;
|
|
76
|
+
requestedModel: z.ZodOptional<z.ZodString>;
|
|
77
|
+
resolvedModel: z.ZodOptional<z.ZodString>;
|
|
75
78
|
}, z.core.$strip>;
|
|
76
79
|
export type PhaseMarker = z.infer<typeof PhaseMarkerSchema>;
|
|
77
80
|
/**
|
|
@@ -149,6 +152,7 @@ export declare const AcceptanceCriterionSchema: z.ZodObject<{
|
|
|
149
152
|
}>;
|
|
150
153
|
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
151
154
|
notes: z.ZodOptional<z.ZodString>;
|
|
155
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
152
156
|
}, z.core.$strip>;
|
|
153
157
|
export type AcceptanceCriterion = z.infer<typeof AcceptanceCriterionSchema>;
|
|
154
158
|
/**
|
|
@@ -172,6 +176,7 @@ export declare const AcceptanceCriteriaSchema: z.ZodObject<{
|
|
|
172
176
|
}>;
|
|
173
177
|
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
174
178
|
notes: z.ZodOptional<z.ZodString>;
|
|
179
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
175
180
|
}, z.core.$strip>>;
|
|
176
181
|
extractedAt: z.ZodString;
|
|
177
182
|
summary: z.ZodObject<{
|
|
@@ -233,6 +238,7 @@ export declare const IssueStateSchema: z.ZodObject<{
|
|
|
233
238
|
not_started: "not_started";
|
|
234
239
|
waiting_for_qa_gate: "waiting_for_qa_gate";
|
|
235
240
|
waiting_for_human_merge: "waiting_for_human_merge";
|
|
241
|
+
awaiting_verification: "awaiting_verification";
|
|
236
242
|
ready_for_merge: "ready_for_merge";
|
|
237
243
|
blocked: "blocked";
|
|
238
244
|
abandoned: "abandoned";
|
|
@@ -281,6 +287,7 @@ export declare const IssueStateSchema: z.ZodObject<{
|
|
|
281
287
|
}>;
|
|
282
288
|
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
283
289
|
notes: z.ZodOptional<z.ZodString>;
|
|
290
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
284
291
|
}, z.core.$strip>>;
|
|
285
292
|
extractedAt: z.ZodString;
|
|
286
293
|
summary: z.ZodObject<{
|
|
@@ -382,6 +389,7 @@ export declare const WorkflowStateSchema: z.ZodObject<{
|
|
|
382
389
|
not_started: "not_started";
|
|
383
390
|
waiting_for_qa_gate: "waiting_for_qa_gate";
|
|
384
391
|
waiting_for_human_merge: "waiting_for_human_merge";
|
|
392
|
+
awaiting_verification: "awaiting_verification";
|
|
385
393
|
ready_for_merge: "ready_for_merge";
|
|
386
394
|
blocked: "blocked";
|
|
387
395
|
abandoned: "abandoned";
|
|
@@ -430,6 +438,7 @@ export declare const WorkflowStateSchema: z.ZodObject<{
|
|
|
430
438
|
}>;
|
|
431
439
|
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
432
440
|
notes: z.ZodOptional<z.ZodString>;
|
|
441
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
433
442
|
}, z.core.$strip>>;
|
|
434
443
|
extractedAt: z.ZodString;
|
|
435
444
|
summary: z.ZodObject<{
|
|
@@ -538,7 +547,7 @@ export declare function createPhaseState(status?: PhaseStatus): PhaseState;
|
|
|
538
547
|
/**
|
|
539
548
|
* Create acceptance criterion
|
|
540
549
|
*/
|
|
541
|
-
export declare function createAcceptanceCriterion(id: string, description: string, verificationMethod?: ACVerificationMethod): AcceptanceCriterion;
|
|
550
|
+
export declare function createAcceptanceCriterion(id: string, description: string, verificationMethod?: ACVerificationMethod, evidence?: string): AcceptanceCriterion;
|
|
542
551
|
/**
|
|
543
552
|
* Create acceptance criteria tracking structure
|
|
544
553
|
*/
|
|
@@ -47,6 +47,7 @@ export const IssueStatusSchema = z.enum([
|
|
|
47
47
|
"in_progress", // Actively being worked on
|
|
48
48
|
"waiting_for_qa_gate", // QA completed, waiting for gate approval in chain mode
|
|
49
49
|
"waiting_for_human_merge", // `sequant ready` (#683) finished its A+ gate; awaiting human merge decision (never auto-merges)
|
|
50
|
+
"awaiting_verification", // QA returned NEEDS_VERIFICATION; human must execute ACs before QA re-run (#972)
|
|
50
51
|
"ready_for_merge", // All phases passed, PR ready for review
|
|
51
52
|
"merged", // PR merged, work complete
|
|
52
53
|
"blocked", // Waiting on external input or dependency
|
|
@@ -72,6 +73,10 @@ export const PhaseMarkerSchema = z.object({
|
|
|
72
73
|
error: z.string().optional(),
|
|
73
74
|
/** Git HEAD SHA at time of phase completion (used for incremental QA) */
|
|
74
75
|
commitSHA: z.string().optional(),
|
|
76
|
+
/** Role string or raw model string as configured for this phase (#975). */
|
|
77
|
+
requestedModel: z.string().optional(),
|
|
78
|
+
/** Concrete model ID from `modelUsage` after phase execution (#975). */
|
|
79
|
+
resolvedModel: z.string().optional(),
|
|
75
80
|
});
|
|
76
81
|
/**
|
|
77
82
|
* Individual phase state within an issue
|
|
@@ -149,6 +154,12 @@ export const AcceptanceCriterionSchema = z.object({
|
|
|
149
154
|
verifiedAt: z.string().datetime().optional(),
|
|
150
155
|
/** Additional notes about verification */
|
|
151
156
|
notes: z.string().optional(),
|
|
157
|
+
/**
|
|
158
|
+
* Explicit `Evidence:` clause declared on the AC line (#938). When present,
|
|
159
|
+
* this is what verificationMethod was resolved from instead of keyword
|
|
160
|
+
* inference — see `resolveVerificationMethod` in ac-parser.ts.
|
|
161
|
+
*/
|
|
162
|
+
evidence: z.string().optional(),
|
|
152
163
|
});
|
|
153
164
|
/**
|
|
154
165
|
* Acceptance criteria tracking for an issue
|
|
@@ -369,12 +380,13 @@ export function createPhaseState(status = "pending") {
|
|
|
369
380
|
/**
|
|
370
381
|
* Create acceptance criterion
|
|
371
382
|
*/
|
|
372
|
-
export function createAcceptanceCriterion(id, description, verificationMethod = "manual") {
|
|
383
|
+
export function createAcceptanceCriterion(id, description, verificationMethod = "manual", evidence) {
|
|
373
384
|
return {
|
|
374
385
|
id,
|
|
375
386
|
description,
|
|
376
387
|
verificationMethod,
|
|
377
388
|
status: "pending",
|
|
389
|
+
...(evidence !== undefined ? { evidence } : {}),
|
|
378
390
|
};
|
|
379
391
|
}
|
|
380
392
|
/**
|
|
@@ -83,6 +83,15 @@ export interface ExecutionConfig {
|
|
|
83
83
|
dryRun: boolean;
|
|
84
84
|
/** Enable MCP servers in headless mode (true by default, false if --no-mcp flag used) */
|
|
85
85
|
mcp: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Claude Desktop MCP server names explicitly opted in via
|
|
88
|
+
* `settings.run.mcpAllowlist` (#936). Both `ExecutionConfig` producers
|
|
89
|
+
* (`buildExecutionConfig`, `ready-gate.ts`'s `buildPhaseConfig`) read
|
|
90
|
+
* this from settings the same way, so it cannot drift between them the
|
|
91
|
+
* way #833's `phaseTimeout` once did. `phase-executor.ts` forwards it
|
|
92
|
+
* verbatim onto `AgentExecutionConfig.mcpAllowlist`.
|
|
93
|
+
*/
|
|
94
|
+
mcpAllowlist?: string[];
|
|
86
95
|
/**
|
|
87
96
|
* Enable automatic retry with MCP fallback.
|
|
88
97
|
* When true (default), failed phases are retried with MCP disabled.
|
|
@@ -278,6 +287,12 @@ export interface PhaseResult {
|
|
|
278
287
|
base: string;
|
|
279
288
|
escalated: string;
|
|
280
289
|
};
|
|
290
|
+
/**
|
|
291
|
+
* Concrete model ID from the SDK `modelUsage` map for this phase execution
|
|
292
|
+
* (#975). First key of `modelUsage` — records the actual model dispatched,
|
|
293
|
+
* distinct from the configured alias. Used to populate metrics `phasePolicies`.
|
|
294
|
+
*/
|
|
295
|
+
resolvedModel?: string;
|
|
281
296
|
}
|
|
282
297
|
/**
|
|
283
298
|
* Result of executing all phases for an issue
|
|
@@ -705,4 +720,9 @@ export interface IssueExecutionContext {
|
|
|
705
720
|
* around verbose Claude streaming.
|
|
706
721
|
*/
|
|
707
722
|
phasePauseHandle?: PhasePauseHandle;
|
|
723
|
+
/**
|
|
724
|
+
* @internal Test seam for the #964 qa-verdict comment post. Defaults to a
|
|
725
|
+
* real `GitHubProvider().postComment` when unset.
|
|
726
|
+
*/
|
|
727
|
+
postComment?: (issueNumber: number, body: string) => Promise<void>;
|
|
708
728
|
}
|
|
@@ -390,6 +390,12 @@ const runToolInputSchema = {
|
|
|
390
390
|
.boolean()
|
|
391
391
|
.optional()
|
|
392
392
|
.describe("Enable auto-retry on QA failure"),
|
|
393
|
+
force: z
|
|
394
|
+
.boolean()
|
|
395
|
+
.optional()
|
|
396
|
+
.describe("Re-run even if the issue is already in a completed state such as " +
|
|
397
|
+
"ready_for_merge (mirrors CLI --force). Not needed after a " +
|
|
398
|
+
"NEEDS_VERIFICATION verdict: awaiting_verification re-runs freely."),
|
|
393
399
|
agent: z
|
|
394
400
|
.string()
|
|
395
401
|
.optional()
|
|
@@ -410,7 +416,7 @@ export function registerRunTool(server) {
|
|
|
410
416
|
openWorldHint: true,
|
|
411
417
|
},
|
|
412
418
|
inputSchema: runToolInputSchema,
|
|
413
|
-
}, (async ({ issues, phases, qualityLoop, agent, }, extra) => {
|
|
419
|
+
}, (async ({ issues, phases, qualityLoop, force, agent, }, extra) => {
|
|
414
420
|
if (!issues || issues.length === 0) {
|
|
415
421
|
return {
|
|
416
422
|
content: [
|
|
@@ -435,6 +441,9 @@ export function registerRunTool(server) {
|
|
|
435
441
|
if (qualityLoop) {
|
|
436
442
|
args.push("--quality-loop");
|
|
437
443
|
}
|
|
444
|
+
if (force) {
|
|
445
|
+
args.push("--force");
|
|
446
|
+
}
|
|
438
447
|
if (agent) {
|
|
439
448
|
args.push("--agent", agent);
|
|
440
449
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sequant",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "AI coding agent orchestrator —
|
|
3
|
+
"version": "2.13.0",
|
|
4
|
+
"description": "AI coding agent orchestrator that proves its work — GitHub issues to merge-ready PRs with every acceptance criterion verified, isolated git worktrees, quality gates, an MCP server, and a human merge gate. Works with Claude Code or Aider.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"sequant": "dist/bin/cli.js"
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"typecheck:scripts": "tsc --noEmit -p tsconfig.scripts.json",
|
|
32
32
|
"lint:skill-calls": "npx tsx scripts/lint-skill-calls.ts",
|
|
33
33
|
"lint:skill-gates": "npx tsx scripts/lint-skill-gates.ts",
|
|
34
|
+
"lint:constitution-dod": "npx tsx scripts/check-constitution-dod.ts",
|
|
34
35
|
"lint:skill-sync": "npx tsx scripts/check-skill-sync.ts",
|
|
35
36
|
"prepare:marketplace": "npx tsx scripts/prepare-marketplace.ts",
|
|
36
37
|
"validate:marketplace": "npx tsx scripts/prepare-marketplace.ts --validate-only",
|
|
@@ -91,17 +92,17 @@
|
|
|
91
92
|
}
|
|
92
93
|
},
|
|
93
94
|
"dependencies": {
|
|
94
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
95
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.242",
|
|
95
96
|
"@hono/node-server": "^2.0.0",
|
|
96
97
|
"boxen": "^8.0.1",
|
|
97
|
-
"chalk": "^
|
|
98
|
+
"chalk": "^6.0.0",
|
|
98
99
|
"chokidar": "^5.0.0",
|
|
99
100
|
"cli-table3": "^0.6.5",
|
|
100
101
|
"commander": "^14.0.3",
|
|
101
102
|
"diff": "^9.0.0",
|
|
102
|
-
"hono": "^4.
|
|
103
|
+
"hono": "^4.13.4",
|
|
103
104
|
"ink": "^7.0.1",
|
|
104
|
-
"inquirer": "^14.0
|
|
105
|
+
"inquirer": "^14.1.0",
|
|
105
106
|
"log-update": "^7.0.1",
|
|
106
107
|
"open": "^11.0.0",
|
|
107
108
|
"ora": "^9.3.0",
|
|
@@ -114,16 +115,16 @@
|
|
|
114
115
|
"devDependencies": {
|
|
115
116
|
"@eslint/js": "^10.0.1",
|
|
116
117
|
"@types/inquirer": "^9.0.7",
|
|
117
|
-
"@types/node": "^26.0
|
|
118
|
+
"@types/node": "^26.3.0",
|
|
118
119
|
"@types/react": "^19.2.14",
|
|
119
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
120
|
-
"@typescript-eslint/parser": "^8.
|
|
121
|
-
"eslint": "^10.1
|
|
120
|
+
"@typescript-eslint/eslint-plugin": "^8.68.0",
|
|
121
|
+
"@typescript-eslint/parser": "^8.68.0",
|
|
122
|
+
"eslint": "^10.9.1",
|
|
122
123
|
"globals": "^17.0.0",
|
|
123
124
|
"ink-testing-library": "^4.0.0",
|
|
124
125
|
"tsx": "^4.19.2",
|
|
125
126
|
"typescript": "^6.0.2",
|
|
126
|
-
"typescript-eslint": "^8.
|
|
127
|
-
"vitest": "^4.1.
|
|
127
|
+
"typescript-eslint": "^8.68.0",
|
|
128
|
+
"vitest": "^4.1.11"
|
|
128
129
|
}
|
|
129
130
|
}
|