sequant 2.2.0 → 2.4.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 +81 -5
- package/dist/bin/cli.js +140 -13
- package/dist/src/commands/abort.d.ts +36 -0
- package/dist/src/commands/abort.js +138 -0
- package/dist/src/commands/doctor.d.ts +25 -0
- package/dist/src/commands/doctor.js +36 -1
- package/dist/src/commands/locks.d.ts +67 -0
- package/dist/src/commands/locks.js +290 -0
- package/dist/src/commands/merge.js +11 -0
- package/dist/src/commands/prompt.d.ts +46 -0
- package/dist/src/commands/prompt.js +273 -0
- package/dist/src/commands/run-display.d.ts +11 -2
- package/dist/src/commands/run-display.js +62 -28
- package/dist/src/commands/run-progress.d.ts +42 -0
- package/dist/src/commands/run-progress.js +93 -0
- package/dist/src/commands/run.js +90 -18
- package/dist/src/commands/stats.d.ts +2 -0
- package/dist/src/commands/stats.js +94 -8
- package/dist/src/commands/status.js +12 -0
- package/dist/src/commands/watch.d.ts +18 -0
- package/dist/src/commands/watch.js +211 -0
- package/dist/src/lib/ac-linter.d.ts +1 -1
- package/dist/src/lib/ac-linter.js +81 -0
- package/dist/src/lib/assess-collision-detect.d.ts +91 -0
- package/dist/src/lib/assess-collision-detect.js +217 -0
- package/dist/src/lib/assess-comment-parser.d.ts +59 -1
- package/dist/src/lib/assess-comment-parser.js +124 -2
- package/dist/src/lib/cli-ui/format.d.ts +19 -0
- package/dist/src/lib/cli-ui/format.js +34 -0
- package/dist/src/lib/cli-ui/run-renderer-types.d.ts +220 -0
- package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
- package/dist/src/lib/cli-ui/run-renderer.d.ts +265 -0
- package/dist/src/lib/cli-ui/run-renderer.js +1390 -0
- package/dist/src/lib/cli-ui/scrollback-harness.d.ts +112 -0
- package/dist/src/lib/cli-ui/scrollback-harness.js +294 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
- package/dist/src/lib/locks/index.d.ts +7 -0
- package/dist/src/lib/locks/index.js +5 -0
- package/dist/src/lib/locks/lock-manager.d.ts +168 -0
- package/dist/src/lib/locks/lock-manager.js +433 -0
- package/dist/src/lib/locks/types.d.ts +59 -0
- package/dist/src/lib/locks/types.js +31 -0
- package/dist/src/lib/merge-check/types.js +1 -1
- package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
- package/dist/src/lib/qa/markdown-only-ci.js +74 -0
- package/dist/src/lib/relay/activation.d.ts +60 -0
- package/dist/src/lib/relay/activation.js +122 -0
- package/dist/src/lib/relay/archive.d.ts +34 -0
- package/dist/src/lib/relay/archive.js +112 -0
- package/dist/src/lib/relay/frame.d.ts +20 -0
- package/dist/src/lib/relay/frame.js +76 -0
- package/dist/src/lib/relay/index.d.ts +13 -0
- package/dist/src/lib/relay/index.js +13 -0
- package/dist/src/lib/relay/paths.d.ts +43 -0
- package/dist/src/lib/relay/paths.js +59 -0
- package/dist/src/lib/relay/pid.d.ts +34 -0
- package/dist/src/lib/relay/pid.js +72 -0
- package/dist/src/lib/relay/reader.d.ts +35 -0
- package/dist/src/lib/relay/reader.js +115 -0
- package/dist/src/lib/relay/types.d.ts +70 -0
- package/dist/src/lib/relay/types.js +85 -0
- package/dist/src/lib/relay/writer.d.ts +48 -0
- package/dist/src/lib/relay/writer.js +113 -0
- package/dist/src/lib/settings.d.ts +31 -1
- package/dist/src/lib/settings.js +18 -3
- package/dist/src/lib/version-check.d.ts +60 -5
- package/dist/src/lib/version-check.js +97 -9
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +274 -185
- package/dist/src/lib/workflow/config-resolver.js +4 -0
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +48 -1
- package/dist/src/lib/workflow/drivers/aider.d.ts +7 -1
- package/dist/src/lib/workflow/drivers/aider.js +9 -0
- package/dist/src/lib/workflow/drivers/claude-code.d.ts +17 -1
- package/dist/src/lib/workflow/drivers/claude-code.js +51 -2
- package/dist/src/lib/workflow/drivers/index.d.ts +1 -1
- package/dist/src/lib/workflow/event-emitter.d.ts +157 -0
- package/dist/src/lib/workflow/event-emitter.js +102 -0
- package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
- package/dist/src/lib/workflow/heartbeat.js +194 -0
- package/dist/src/lib/workflow/notice.d.ts +32 -0
- package/dist/src/lib/workflow/notice.js +38 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +58 -16
- package/dist/src/lib/workflow/phase-executor.js +244 -130
- package/dist/src/lib/workflow/phase-mapper.d.ts +27 -13
- package/dist/src/lib/workflow/phase-mapper.js +70 -51
- package/dist/src/lib/workflow/phase-registry.d.ts +127 -0
- package/dist/src/lib/workflow/phase-registry.js +233 -0
- package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
- package/dist/src/lib/workflow/platforms/github.js +20 -3
- package/dist/src/lib/workflow/pr-status.d.ts +18 -2
- package/dist/src/lib/workflow/pr-status.js +41 -9
- package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
- package/dist/src/lib/workflow/qa-stagnation.js +179 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts +5 -55
- package/dist/src/lib/workflow/run-orchestrator.d.ts +70 -1
- package/dist/src/lib/workflow/run-orchestrator.js +464 -25
- package/dist/src/lib/workflow/run-reflect.js +1 -1
- package/dist/src/lib/workflow/run-state.d.ts +71 -0
- package/dist/src/lib/workflow/run-state.js +14 -0
- package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
- package/dist/src/lib/workflow/state-cleanup.js +17 -5
- package/dist/src/lib/workflow/state-manager.d.ts +31 -2
- package/dist/src/lib/workflow/state-manager.js +64 -1
- package/dist/src/lib/workflow/state-schema.d.ts +82 -35
- package/dist/src/lib/workflow/state-schema.js +63 -4
- package/dist/src/lib/workflow/types.d.ts +139 -16
- package/dist/src/lib/workflow/types.js +18 -13
- package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
- package/dist/src/lib/workflow/worktree-manager.js +15 -6
- package/dist/src/mcp/tools/run.d.ts +44 -0
- package/dist/src/mcp/tools/run.js +104 -13
- package/dist/src/ui/tui/App.d.ts +14 -0
- package/dist/src/ui/tui/App.js +41 -0
- package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
- package/dist/src/ui/tui/ElapsedTimer.js +31 -0
- package/dist/src/ui/tui/Header.d.ts +6 -0
- package/dist/src/ui/tui/Header.js +15 -0
- package/dist/src/ui/tui/IssueBox.d.ts +16 -0
- package/dist/src/ui/tui/IssueBox.js +68 -0
- package/dist/src/ui/tui/Spinner.d.ts +9 -0
- package/dist/src/ui/tui/Spinner.js +18 -0
- package/dist/src/ui/tui/index.d.ts +15 -0
- package/dist/src/ui/tui/index.js +29 -0
- package/dist/src/ui/tui/theme.d.ts +29 -0
- package/dist/src/ui/tui/theme.js +52 -0
- package/dist/src/ui/tui/truncate.d.ts +11 -0
- package/dist/src/ui/tui/truncate.js +31 -0
- package/package.json +14 -6
- package/templates/agents/sequant-explorer.md +1 -0
- package/templates/agents/sequant-qa-checker.md +2 -1
- package/templates/agents/sequant-testgen.md +1 -0
- package/templates/hooks/post-tool.sh +92 -0
- package/templates/hooks/pre-tool.sh +18 -9
- package/templates/hooks/relay-check.sh +107 -0
- package/templates/relay/frame.txt +11 -0
- package/templates/scripts/cleanup-worktree.sh +25 -3
- package/templates/scripts/new-feature.sh +6 -0
- package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
- package/templates/skills/_shared/references/subagent-types.md +21 -8
- package/templates/skills/assess/SKILL.md +122 -68
- package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
- package/templates/skills/docs/SKILL.md +141 -22
- package/templates/skills/exec/SKILL.md +10 -8
- package/templates/skills/fullsolve/SKILL.md +79 -5
- package/templates/skills/loop/SKILL.md +28 -0
- package/templates/skills/merger/SKILL.md +621 -0
- package/templates/skills/qa/SKILL.md +727 -8
- package/templates/skills/setup/SKILL.md +12 -6
- package/templates/skills/spec/SKILL.md +52 -0
- package/templates/skills/spec/references/parallel-groups.md +7 -0
- package/templates/skills/spec/references/recommended-workflow.md +4 -2
- package/templates/skills/testgen/SKILL.md +24 -17
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime state snapshots for multi-issue dashboard rendering.
|
|
3
|
+
*
|
|
4
|
+
* Decouples the TUI from the orchestrator: `getSnapshot()` returns an
|
|
5
|
+
* immutable, plain-object view of current run state that can be safely
|
|
6
|
+
* read from a render loop without holding locks.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Format a coarse "now" line for a phase transition.
|
|
10
|
+
* Used as the M1 default when no finer activity signal exists.
|
|
11
|
+
*/
|
|
12
|
+
export function formatCoarseNowLine(phase) {
|
|
13
|
+
return `running ${phase}`;
|
|
14
|
+
}
|
|
@@ -58,9 +58,9 @@ export interface ReconcileOptions {
|
|
|
58
58
|
export interface ReconcileResult {
|
|
59
59
|
/** Whether reconciliation was successful */
|
|
60
60
|
success: boolean;
|
|
61
|
-
/** Issues
|
|
61
|
+
/** Issues advanced to `merged` (from `ready_for_merge`, `in_progress`, or `waiting_for_qa_gate`) */
|
|
62
62
|
advanced: number[];
|
|
63
|
-
/** Issues checked but
|
|
63
|
+
/** Issues checked but not yet merged (status unchanged) */
|
|
64
64
|
stillPending: number[];
|
|
65
65
|
/** Error message if failed */
|
|
66
66
|
error?: string;
|
|
@@ -68,10 +68,18 @@ export interface ReconcileResult {
|
|
|
68
68
|
/**
|
|
69
69
|
* Lightweight state reconciliation at run start
|
|
70
70
|
*
|
|
71
|
-
* Checks issues in `ready_for_merge`
|
|
72
|
-
* if their PRs are merged or their branches
|
|
71
|
+
* Checks issues in `ready_for_merge`, `in_progress`, or `waiting_for_qa_gate`
|
|
72
|
+
* state and advances them to `merged` if their PRs are merged or their branches
|
|
73
|
+
* are in main.
|
|
73
74
|
*
|
|
74
|
-
*
|
|
75
|
+
* Including `in_progress` covers the case where a PR was merged outside
|
|
76
|
+
* this sequant session (separate process, `gh pr merge`, web UI) — without
|
|
77
|
+
* it, the run command would re-execute already-merged issues. See #592.
|
|
78
|
+
*
|
|
79
|
+
* Including `waiting_for_qa_gate` covers the symmetric case where a PR
|
|
80
|
+
* awaiting human QA-gate approval is merged externally before the next
|
|
81
|
+
* sequant session — without it, `sequant run <N>` re-executes the QA phase
|
|
82
|
+
* against already-merged work. See #606.
|
|
75
83
|
*
|
|
76
84
|
* @param options - Reconciliation options
|
|
77
85
|
* @returns Result with lists of advanced and still-pending issues
|
|
@@ -188,10 +188,18 @@ export async function cleanupStaleEntries(options = {}) {
|
|
|
188
188
|
/**
|
|
189
189
|
* Lightweight state reconciliation at run start
|
|
190
190
|
*
|
|
191
|
-
* Checks issues in `ready_for_merge`
|
|
192
|
-
* if their PRs are merged or their branches
|
|
191
|
+
* Checks issues in `ready_for_merge`, `in_progress`, or `waiting_for_qa_gate`
|
|
192
|
+
* state and advances them to `merged` if their PRs are merged or their branches
|
|
193
|
+
* are in main.
|
|
193
194
|
*
|
|
194
|
-
*
|
|
195
|
+
* Including `in_progress` covers the case where a PR was merged outside
|
|
196
|
+
* this sequant session (separate process, `gh pr merge`, web UI) — without
|
|
197
|
+
* it, the run command would re-execute already-merged issues. See #592.
|
|
198
|
+
*
|
|
199
|
+
* Including `waiting_for_qa_gate` covers the symmetric case where a PR
|
|
200
|
+
* awaiting human QA-gate approval is merged externally before the next
|
|
201
|
+
* sequant session — without it, `sequant run <N>` re-executes the QA phase
|
|
202
|
+
* against already-merged work. See #606.
|
|
195
203
|
*
|
|
196
204
|
* @param options - Reconciliation options
|
|
197
205
|
* @returns Result with lists of advanced and still-pending issues
|
|
@@ -213,9 +221,13 @@ export async function reconcileStateAtStartup(options = {}) {
|
|
|
213
221
|
const state = await manager.getState();
|
|
214
222
|
const advanced = [];
|
|
215
223
|
const stillPending = [];
|
|
216
|
-
// Find issues in ready_for_merge state
|
|
224
|
+
// Find issues in ready_for_merge, in_progress, or waiting_for_qa_gate state.
|
|
225
|
+
// in_progress covers PRs merged outside this session (#592).
|
|
226
|
+
// waiting_for_qa_gate covers PRs merged before the next QA-gate run (#606).
|
|
217
227
|
for (const [issueNumStr, issueState] of Object.entries(state.issues)) {
|
|
218
|
-
if (issueState.status !== "ready_for_merge"
|
|
228
|
+
if (issueState.status !== "ready_for_merge" &&
|
|
229
|
+
issueState.status !== "in_progress" &&
|
|
230
|
+
issueState.status !== "waiting_for_qa_gate") {
|
|
219
231
|
continue;
|
|
220
232
|
}
|
|
221
233
|
const issueNum = parseInt(issueNumStr, 10);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* const state = await manager.getIssueState(42);
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
import { type WorkflowState, type IssueState, type Phase, type PhaseStatus, type IssueStatus, type PRInfo, type AcceptanceCriteria, type ACStatus } from "./state-schema.js";
|
|
23
|
+
import { type WorkflowState, type IssueState, type Phase, type PhaseStatus, type IssueStatus, type PRInfo, type AcceptanceCriteria, type ACStatus, type RelayState } from "./state-schema.js";
|
|
24
24
|
import type { ScopeAssessment } from "../scope/types.js";
|
|
25
25
|
export interface StateManagerOptions {
|
|
26
26
|
/** Path to state file (default: .sequant/state.json) */
|
|
@@ -130,9 +130,38 @@ export declare class StateManager {
|
|
|
130
130
|
*/
|
|
131
131
|
updateWorktreeInfo(issueNumber: number, worktree: string, branch: string): Promise<void>;
|
|
132
132
|
/**
|
|
133
|
-
* Update session ID for an issue (for resume)
|
|
133
|
+
* Update session ID for an issue (for resume).
|
|
134
|
+
*
|
|
135
|
+
* @deprecated Use {@link updateResumeHandle} (#674). This entry point only
|
|
136
|
+
* writes the legacy `sessionId` field — without an `originCwd`, the next
|
|
137
|
+
* phase's driver-owned `canResume()` fail-safe will decline resume, so the
|
|
138
|
+
* data is effectively inert. Retained for one release to keep callers from
|
|
139
|
+
* older sequant builds compiling.
|
|
134
140
|
*/
|
|
135
141
|
updateSessionId(issueNumber: number, sessionId: string): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Update the driver-tagged resume handle for an issue (#674).
|
|
144
|
+
*
|
|
145
|
+
* Writes both the new `resumeHandle` field and mirrors the token into
|
|
146
|
+
* the deprecated `sessionId` field so state files round-trip through
|
|
147
|
+
* older sequant readers for one release.
|
|
148
|
+
*/
|
|
149
|
+
updateResumeHandle(issueNumber: number, handle: {
|
|
150
|
+
driver: string;
|
|
151
|
+
token: string;
|
|
152
|
+
originCwd: string;
|
|
153
|
+
}): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Set or clear the relay state for an issue (#383).
|
|
156
|
+
*
|
|
157
|
+
* Pass `null` to remove the relay field entirely (deactivation). Pass an
|
|
158
|
+
* object to overwrite the current relay state (activation or refresh).
|
|
159
|
+
*/
|
|
160
|
+
setRelayState(issueNumber: number, relay: RelayState | null): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Increment the relay message counter. No-op when relay isn't active.
|
|
163
|
+
*/
|
|
164
|
+
incrementRelayMessageCount(issueNumber: number, delta?: number): Promise<void>;
|
|
136
165
|
/**
|
|
137
166
|
* Update loop iteration for an issue
|
|
138
167
|
*/
|
|
@@ -378,7 +378,13 @@ export class StateManager {
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
/**
|
|
381
|
-
* Update session ID for an issue (for resume)
|
|
381
|
+
* Update session ID for an issue (for resume).
|
|
382
|
+
*
|
|
383
|
+
* @deprecated Use {@link updateResumeHandle} (#674). This entry point only
|
|
384
|
+
* writes the legacy `sessionId` field — without an `originCwd`, the next
|
|
385
|
+
* phase's driver-owned `canResume()` fail-safe will decline resume, so the
|
|
386
|
+
* data is effectively inert. Retained for one release to keep callers from
|
|
387
|
+
* older sequant builds compiling.
|
|
382
388
|
*/
|
|
383
389
|
async updateSessionId(issueNumber, sessionId) {
|
|
384
390
|
await this.withLock(async () => {
|
|
@@ -392,6 +398,63 @@ export class StateManager {
|
|
|
392
398
|
await this.saveState(state);
|
|
393
399
|
});
|
|
394
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Update the driver-tagged resume handle for an issue (#674).
|
|
403
|
+
*
|
|
404
|
+
* Writes both the new `resumeHandle` field and mirrors the token into
|
|
405
|
+
* the deprecated `sessionId` field so state files round-trip through
|
|
406
|
+
* older sequant readers for one release.
|
|
407
|
+
*/
|
|
408
|
+
async updateResumeHandle(issueNumber, handle) {
|
|
409
|
+
await this.withLock(async () => {
|
|
410
|
+
const state = await this.getState();
|
|
411
|
+
const issueState = state.issues[String(issueNumber)];
|
|
412
|
+
if (!issueState) {
|
|
413
|
+
throw new Error(`Issue #${issueNumber} not found in state`);
|
|
414
|
+
}
|
|
415
|
+
issueState.resumeHandle = handle;
|
|
416
|
+
issueState.sessionId = handle.token;
|
|
417
|
+
issueState.lastActivity = new Date().toISOString();
|
|
418
|
+
await this.saveState(state);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Set or clear the relay state for an issue (#383).
|
|
423
|
+
*
|
|
424
|
+
* Pass `null` to remove the relay field entirely (deactivation). Pass an
|
|
425
|
+
* object to overwrite the current relay state (activation or refresh).
|
|
426
|
+
*/
|
|
427
|
+
async setRelayState(issueNumber, relay) {
|
|
428
|
+
await this.withLock(async () => {
|
|
429
|
+
const state = await this.getState();
|
|
430
|
+
const issueState = state.issues[String(issueNumber)];
|
|
431
|
+
if (!issueState) {
|
|
432
|
+
throw new Error(`Issue #${issueNumber} not found in state`);
|
|
433
|
+
}
|
|
434
|
+
if (relay === null) {
|
|
435
|
+
delete issueState.relay;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
issueState.relay = relay;
|
|
439
|
+
}
|
|
440
|
+
issueState.lastActivity = new Date().toISOString();
|
|
441
|
+
await this.saveState(state);
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Increment the relay message counter. No-op when relay isn't active.
|
|
446
|
+
*/
|
|
447
|
+
async incrementRelayMessageCount(issueNumber, delta = 1) {
|
|
448
|
+
await this.withLock(async () => {
|
|
449
|
+
const state = await this.getState();
|
|
450
|
+
const issueState = state.issues[String(issueNumber)];
|
|
451
|
+
if (!issueState || !issueState.relay)
|
|
452
|
+
return;
|
|
453
|
+
issueState.relay.messageCount += delta;
|
|
454
|
+
issueState.lastActivity = new Date().toISOString();
|
|
455
|
+
await this.saveState(state);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
395
458
|
/**
|
|
396
459
|
* Update loop iteration for an issue
|
|
397
460
|
*/
|
|
@@ -19,9 +19,14 @@
|
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { PhaseSchema } from "./types.js";
|
|
21
21
|
/**
|
|
22
|
-
* Workflow phases in order of execution
|
|
22
|
+
* Workflow phases in order of execution.
|
|
23
|
+
*
|
|
24
|
+
* Sourced from the phase registry — replaces the previous `PhaseSchema.options`
|
|
25
|
+
* literal that existed when `PhaseSchema` was a `z.enum`. Computed at module
|
|
26
|
+
* load (after `built-in-phases.ts` has run); insertion order is the canonical
|
|
27
|
+
* pipeline order.
|
|
23
28
|
*/
|
|
24
|
-
export declare const WORKFLOW_PHASES:
|
|
29
|
+
export declare const WORKFLOW_PHASES: readonly string[];
|
|
25
30
|
/**
|
|
26
31
|
* Phase status - tracks individual phase progress
|
|
27
32
|
*/
|
|
@@ -54,17 +59,7 @@ export type { Phase } from "./types.js";
|
|
|
54
59
|
* Embedded as HTML comments: `<!-- SEQUANT_PHASE: {...} -->`
|
|
55
60
|
*/
|
|
56
61
|
export declare const PhaseMarkerSchema: z.ZodObject<{
|
|
57
|
-
phase: z.
|
|
58
|
-
qa: "qa";
|
|
59
|
-
loop: "loop";
|
|
60
|
-
verify: "verify";
|
|
61
|
-
spec: "spec";
|
|
62
|
-
"security-review": "security-review";
|
|
63
|
-
exec: "exec";
|
|
64
|
-
testgen: "testgen";
|
|
65
|
-
test: "test";
|
|
66
|
-
merger: "merger";
|
|
67
|
-
}>;
|
|
62
|
+
phase: z.ZodString;
|
|
68
63
|
status: z.ZodEnum<{
|
|
69
64
|
pending: "pending";
|
|
70
65
|
skipped: "skipped";
|
|
@@ -186,6 +181,36 @@ export declare const AcceptanceCriteriaSchema: z.ZodObject<{
|
|
|
186
181
|
}, z.core.$strip>;
|
|
187
182
|
}, z.core.$strip>;
|
|
188
183
|
export type AcceptanceCriteria = z.infer<typeof AcceptanceCriteriaSchema>;
|
|
184
|
+
/**
|
|
185
|
+
* Single QA stagnation observation.
|
|
186
|
+
*
|
|
187
|
+
* Recorded when fullsolve detects a same-SHA same-verdict cycle so future
|
|
188
|
+
* runs can spot "we've been here before" without re-deriving it from comments.
|
|
189
|
+
*/
|
|
190
|
+
export declare const QAStagnationEntrySchema: z.ZodObject<{
|
|
191
|
+
sha: z.ZodString;
|
|
192
|
+
verdict: z.ZodString;
|
|
193
|
+
detectedAt: z.ZodString;
|
|
194
|
+
iteration: z.ZodNumber;
|
|
195
|
+
reason: z.ZodEnum<{
|
|
196
|
+
SAME_SHA_NO_PROGRESS: "SAME_SHA_NO_PROGRESS";
|
|
197
|
+
LOOP_NO_DIFF: "LOOP_NO_DIFF";
|
|
198
|
+
}>;
|
|
199
|
+
}, z.core.$strip>;
|
|
200
|
+
export type QAStagnationEntry = z.infer<typeof QAStagnationEntrySchema>;
|
|
201
|
+
/**
|
|
202
|
+
* Optional relay state for the interactive bidirectional channel (#383).
|
|
203
|
+
*
|
|
204
|
+
* Present when `sequant run` has activated the relay for an issue, absent
|
|
205
|
+
* otherwise. Legacy state files (no relay field) still parse successfully.
|
|
206
|
+
*/
|
|
207
|
+
export declare const RelayStateSchema: z.ZodObject<{
|
|
208
|
+
enabled: z.ZodBoolean;
|
|
209
|
+
pid: z.ZodNumber;
|
|
210
|
+
startedAt: z.ZodString;
|
|
211
|
+
messageCount: z.ZodNumber;
|
|
212
|
+
}, z.core.$strip>;
|
|
213
|
+
export type RelayState = z.infer<typeof RelayStateSchema>;
|
|
189
214
|
/**
|
|
190
215
|
* Complete state for a single issue
|
|
191
216
|
*/
|
|
@@ -203,17 +228,7 @@ export declare const IssueStateSchema: z.ZodObject<{
|
|
|
203
228
|
}>;
|
|
204
229
|
worktree: z.ZodOptional<z.ZodString>;
|
|
205
230
|
branch: z.ZodOptional<z.ZodString>;
|
|
206
|
-
currentPhase: z.ZodOptional<z.
|
|
207
|
-
qa: "qa";
|
|
208
|
-
loop: "loop";
|
|
209
|
-
verify: "verify";
|
|
210
|
-
spec: "spec";
|
|
211
|
-
"security-review": "security-review";
|
|
212
|
-
exec: "exec";
|
|
213
|
-
testgen: "testgen";
|
|
214
|
-
test: "test";
|
|
215
|
-
merger: "merger";
|
|
216
|
-
}>>;
|
|
231
|
+
currentPhase: z.ZodOptional<z.ZodString>;
|
|
217
232
|
phases: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
218
233
|
status: z.ZodEnum<{
|
|
219
234
|
pending: "pending";
|
|
@@ -301,7 +316,28 @@ export declare const IssueStateSchema: z.ZodObject<{
|
|
|
301
316
|
}, z.core.$strip>;
|
|
302
317
|
recommendation: z.ZodString;
|
|
303
318
|
}, z.core.$strip>>;
|
|
319
|
+
qaStagnation: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
320
|
+
sha: z.ZodString;
|
|
321
|
+
verdict: z.ZodString;
|
|
322
|
+
detectedAt: z.ZodString;
|
|
323
|
+
iteration: z.ZodNumber;
|
|
324
|
+
reason: z.ZodEnum<{
|
|
325
|
+
SAME_SHA_NO_PROGRESS: "SAME_SHA_NO_PROGRESS";
|
|
326
|
+
LOOP_NO_DIFF: "LOOP_NO_DIFF";
|
|
327
|
+
}>;
|
|
328
|
+
}, z.core.$strip>>>;
|
|
329
|
+
relay: z.ZodOptional<z.ZodObject<{
|
|
330
|
+
enabled: z.ZodBoolean;
|
|
331
|
+
pid: z.ZodNumber;
|
|
332
|
+
startedAt: z.ZodString;
|
|
333
|
+
messageCount: z.ZodNumber;
|
|
334
|
+
}, z.core.$strip>>;
|
|
304
335
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
336
|
+
resumeHandle: z.ZodOptional<z.ZodObject<{
|
|
337
|
+
driver: z.ZodString;
|
|
338
|
+
token: z.ZodString;
|
|
339
|
+
originCwd: z.ZodString;
|
|
340
|
+
}, z.core.$strip>>;
|
|
305
341
|
resolvedAt: z.ZodOptional<z.ZodString>;
|
|
306
342
|
lastActivity: z.ZodString;
|
|
307
343
|
createdAt: z.ZodString;
|
|
@@ -330,17 +366,7 @@ export declare const WorkflowStateSchema: z.ZodObject<{
|
|
|
330
366
|
}>;
|
|
331
367
|
worktree: z.ZodOptional<z.ZodString>;
|
|
332
368
|
branch: z.ZodOptional<z.ZodString>;
|
|
333
|
-
currentPhase: z.ZodOptional<z.
|
|
334
|
-
qa: "qa";
|
|
335
|
-
loop: "loop";
|
|
336
|
-
verify: "verify";
|
|
337
|
-
spec: "spec";
|
|
338
|
-
"security-review": "security-review";
|
|
339
|
-
exec: "exec";
|
|
340
|
-
testgen: "testgen";
|
|
341
|
-
test: "test";
|
|
342
|
-
merger: "merger";
|
|
343
|
-
}>>;
|
|
369
|
+
currentPhase: z.ZodOptional<z.ZodString>;
|
|
344
370
|
phases: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
345
371
|
status: z.ZodEnum<{
|
|
346
372
|
pending: "pending";
|
|
@@ -428,7 +454,28 @@ export declare const WorkflowStateSchema: z.ZodObject<{
|
|
|
428
454
|
}, z.core.$strip>;
|
|
429
455
|
recommendation: z.ZodString;
|
|
430
456
|
}, z.core.$strip>>;
|
|
457
|
+
qaStagnation: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
458
|
+
sha: z.ZodString;
|
|
459
|
+
verdict: z.ZodString;
|
|
460
|
+
detectedAt: z.ZodString;
|
|
461
|
+
iteration: z.ZodNumber;
|
|
462
|
+
reason: z.ZodEnum<{
|
|
463
|
+
SAME_SHA_NO_PROGRESS: "SAME_SHA_NO_PROGRESS";
|
|
464
|
+
LOOP_NO_DIFF: "LOOP_NO_DIFF";
|
|
465
|
+
}>;
|
|
466
|
+
}, z.core.$strip>>>;
|
|
467
|
+
relay: z.ZodOptional<z.ZodObject<{
|
|
468
|
+
enabled: z.ZodBoolean;
|
|
469
|
+
pid: z.ZodNumber;
|
|
470
|
+
startedAt: z.ZodString;
|
|
471
|
+
messageCount: z.ZodNumber;
|
|
472
|
+
}, z.core.$strip>>;
|
|
431
473
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
474
|
+
resumeHandle: z.ZodOptional<z.ZodObject<{
|
|
475
|
+
driver: z.ZodString;
|
|
476
|
+
token: z.ZodString;
|
|
477
|
+
originCwd: z.ZodString;
|
|
478
|
+
}, z.core.$strip>>;
|
|
432
479
|
resolvedAt: z.ZodOptional<z.ZodString>;
|
|
433
480
|
lastActivity: z.ZodString;
|
|
434
481
|
createdAt: z.ZodString;
|
|
@@ -19,10 +19,16 @@
|
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { ScopeAssessmentSchema } from "../scope/types.js";
|
|
21
21
|
import { PhaseSchema } from "./types.js";
|
|
22
|
+
import { getPhaseNames } from "./phase-registry.js";
|
|
22
23
|
/**
|
|
23
|
-
* Workflow phases in order of execution
|
|
24
|
+
* Workflow phases in order of execution.
|
|
25
|
+
*
|
|
26
|
+
* Sourced from the phase registry — replaces the previous `PhaseSchema.options`
|
|
27
|
+
* literal that existed when `PhaseSchema` was a `z.enum`. Computed at module
|
|
28
|
+
* load (after `built-in-phases.ts` has run); insertion order is the canonical
|
|
29
|
+
* pipeline order.
|
|
24
30
|
*/
|
|
25
|
-
export const WORKFLOW_PHASES =
|
|
31
|
+
export const WORKFLOW_PHASES = getPhaseNames();
|
|
26
32
|
/**
|
|
27
33
|
* Phase status - tracks individual phase progress
|
|
28
34
|
*/
|
|
@@ -31,7 +37,7 @@ export const PhaseStatusSchema = z.enum([
|
|
|
31
37
|
"in_progress", // Phase currently executing
|
|
32
38
|
"completed", // Phase finished successfully
|
|
33
39
|
"failed", // Phase finished with errors
|
|
34
|
-
"skipped", // Phase intentionally skipped (e.g.,
|
|
40
|
+
"skipped", // Phase intentionally skipped (e.g., prior phase marker already exists)
|
|
35
41
|
]);
|
|
36
42
|
/**
|
|
37
43
|
* Issue status - tracks overall issue progress
|
|
@@ -153,6 +159,36 @@ export const AcceptanceCriteriaSchema = z.object({
|
|
|
153
159
|
blocked: z.number().int().nonnegative(),
|
|
154
160
|
}),
|
|
155
161
|
});
|
|
162
|
+
/**
|
|
163
|
+
* Single QA stagnation observation.
|
|
164
|
+
*
|
|
165
|
+
* Recorded when fullsolve detects a same-SHA same-verdict cycle so future
|
|
166
|
+
* runs can spot "we've been here before" without re-deriving it from comments.
|
|
167
|
+
*/
|
|
168
|
+
export const QAStagnationEntrySchema = z.object({
|
|
169
|
+
/** HEAD SHA at the time of detection */
|
|
170
|
+
sha: z.string(),
|
|
171
|
+
/** QA verdict that repeated (e.g., AC_NOT_MET) */
|
|
172
|
+
verdict: z.string(),
|
|
173
|
+
/** ISO 8601 timestamp of detection */
|
|
174
|
+
detectedAt: z.string().datetime(),
|
|
175
|
+
/** QA loop iteration number where stagnation was detected */
|
|
176
|
+
iteration: z.number().int().nonnegative(),
|
|
177
|
+
/** Reason code: SAME_SHA_NO_PROGRESS or LOOP_NO_DIFF */
|
|
178
|
+
reason: z.enum(["SAME_SHA_NO_PROGRESS", "LOOP_NO_DIFF"]),
|
|
179
|
+
});
|
|
180
|
+
/**
|
|
181
|
+
* Optional relay state for the interactive bidirectional channel (#383).
|
|
182
|
+
*
|
|
183
|
+
* Present when `sequant run` has activated the relay for an issue, absent
|
|
184
|
+
* otherwise. Legacy state files (no relay field) still parse successfully.
|
|
185
|
+
*/
|
|
186
|
+
export const RelayStateSchema = z.object({
|
|
187
|
+
enabled: z.boolean(),
|
|
188
|
+
pid: z.number().int().positive(),
|
|
189
|
+
startedAt: z.string().datetime(),
|
|
190
|
+
messageCount: z.number().int().nonnegative(),
|
|
191
|
+
});
|
|
156
192
|
/**
|
|
157
193
|
* Complete state for a single issue
|
|
158
194
|
*/
|
|
@@ -179,8 +215,31 @@ export const IssueStateSchema = z.object({
|
|
|
179
215
|
acceptanceCriteria: AcceptanceCriteriaSchema.optional(),
|
|
180
216
|
/** Scope assessment result (if performed by /spec) */
|
|
181
217
|
scopeAssessment: ScopeAssessmentSchema.optional(),
|
|
182
|
-
/**
|
|
218
|
+
/** QA stagnation log: same-SHA same-verdict cycles detected during fullsolve */
|
|
219
|
+
qaStagnation: z.array(QAStagnationEntrySchema).optional(),
|
|
220
|
+
/** Relay state (#383); present when bidirectional relay is active */
|
|
221
|
+
relay: RelayStateSchema.optional(),
|
|
222
|
+
/**
|
|
223
|
+
* Claude session ID (for resume).
|
|
224
|
+
* @deprecated Use {@link resumeHandle} (#674). Retained as a read-path
|
|
225
|
+
* mirror of `resumeHandle.token` for one release so state files written by
|
|
226
|
+
* prior sequant builds load cleanly. Legacy entries (token without
|
|
227
|
+
* `originCwd`) intentionally do NOT resume — the driver-owned `canResume`
|
|
228
|
+
* fail-safe disables them.
|
|
229
|
+
*/
|
|
183
230
|
sessionId: z.string().optional(),
|
|
231
|
+
/**
|
|
232
|
+
* Driver-tagged resume handle (#674). Stores the driver name, the
|
|
233
|
+
* resume token, and the cwd the session was created in so the next phase
|
|
234
|
+
* can prove cwd-equality before reattaching.
|
|
235
|
+
*/
|
|
236
|
+
resumeHandle: z
|
|
237
|
+
.object({
|
|
238
|
+
driver: z.string(),
|
|
239
|
+
token: z.string(),
|
|
240
|
+
originCwd: z.string(),
|
|
241
|
+
})
|
|
242
|
+
.optional(),
|
|
184
243
|
/** When the issue transitioned to a terminal status (merged/abandoned/closed) */
|
|
185
244
|
resolvedAt: z.string().datetime().optional(),
|
|
186
245
|
/** Most recent activity timestamp */
|