sequant 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +6 -1
  2. package/dist/bin/cli.js +55 -2
  3. package/dist/dashboard/server.d.ts +37 -0
  4. package/dist/dashboard/server.js +968 -0
  5. package/dist/src/commands/dashboard.d.ts +25 -0
  6. package/dist/src/commands/dashboard.js +44 -0
  7. package/dist/src/commands/doctor.d.ts +18 -1
  8. package/dist/src/commands/doctor.js +105 -2
  9. package/dist/src/commands/init.d.ts +1 -0
  10. package/dist/src/commands/init.js +26 -2
  11. package/dist/src/commands/run.d.ts +20 -0
  12. package/dist/src/commands/run.js +202 -7
  13. package/dist/src/commands/state.d.ts +60 -0
  14. package/dist/src/commands/state.js +267 -0
  15. package/dist/src/commands/stats.d.ts +3 -2
  16. package/dist/src/commands/stats.js +246 -38
  17. package/dist/src/commands/status.d.ts +2 -0
  18. package/dist/src/commands/status.js +28 -3
  19. package/dist/src/lib/ac-parser.d.ts +61 -0
  20. package/dist/src/lib/ac-parser.js +156 -0
  21. package/dist/src/lib/fs.d.ts +19 -0
  22. package/dist/src/lib/fs.js +58 -1
  23. package/dist/src/lib/settings.d.ts +7 -0
  24. package/dist/src/lib/settings.js +1 -0
  25. package/dist/src/lib/system.d.ts +19 -0
  26. package/dist/src/lib/system.js +26 -0
  27. package/dist/src/lib/templates.d.ts +34 -1
  28. package/dist/src/lib/templates.js +109 -5
  29. package/dist/src/lib/workflow/metrics-schema.d.ts +153 -0
  30. package/dist/src/lib/workflow/metrics-schema.js +138 -0
  31. package/dist/src/lib/workflow/metrics-writer.d.ts +102 -0
  32. package/dist/src/lib/workflow/metrics-writer.js +189 -0
  33. package/dist/src/lib/workflow/state-manager.d.ts +18 -1
  34. package/dist/src/lib/workflow/state-manager.js +61 -1
  35. package/dist/src/lib/workflow/state-schema.d.ts +152 -1
  36. package/dist/src/lib/workflow/state-schema.js +99 -0
  37. package/dist/src/lib/workflow/state-utils.d.ts +67 -3
  38. package/dist/src/lib/workflow/state-utils.js +289 -8
  39. package/dist/src/lib/workflow/types.d.ts +2 -0
  40. package/dist/src/lib/workflow/types.js +1 -0
  41. package/package.json +5 -1
@@ -20,7 +20,7 @@ import { z } from "zod";
20
20
  /**
21
21
  * Workflow phases in order of execution
22
22
  */
23
- export declare const WORKFLOW_PHASES: readonly ["spec", "security-review", "exec", "testgen", "test", "qa", "loop"];
23
+ export declare const WORKFLOW_PHASES: readonly ["spec", "security-review", "exec", "testgen", "test", "verify", "qa", "loop", "merger"];
24
24
  /**
25
25
  * Phase status - tracks individual phase progress
26
26
  */
@@ -38,6 +38,7 @@ export type PhaseStatus = z.infer<typeof PhaseStatusSchema>;
38
38
  export declare const IssueStatusSchema: z.ZodEnum<{
39
39
  in_progress: "in_progress";
40
40
  not_started: "not_started";
41
+ waiting_for_qa_gate: "waiting_for_qa_gate";
41
42
  ready_for_merge: "ready_for_merge";
42
43
  merged: "merged";
43
44
  blocked: "blocked";
@@ -49,12 +50,14 @@ export type IssueStatus = z.infer<typeof IssueStatusSchema>;
49
50
  */
50
51
  export declare const PhaseSchema: z.ZodEnum<{
51
52
  loop: "loop";
53
+ verify: "verify";
52
54
  spec: "spec";
53
55
  exec: "exec";
54
56
  qa: "qa";
55
57
  "security-review": "security-review";
56
58
  testgen: "testgen";
57
59
  test: "test";
60
+ merger: "merger";
58
61
  }>;
59
62
  export type Phase = z.infer<typeof PhaseSchema>;
60
63
  /**
@@ -91,6 +94,80 @@ export declare const LoopStateSchema: z.ZodObject<{
91
94
  maxIterations: z.ZodNumber;
92
95
  }, z.core.$strip>;
93
96
  export type LoopState = z.infer<typeof LoopStateSchema>;
97
+ /**
98
+ * Acceptance criteria verification status
99
+ */
100
+ export declare const ACStatusSchema: z.ZodEnum<{
101
+ pending: "pending";
102
+ blocked: "blocked";
103
+ met: "met";
104
+ not_met: "not_met";
105
+ }>;
106
+ export type ACStatus = z.infer<typeof ACStatusSchema>;
107
+ /**
108
+ * Acceptance criteria verification method
109
+ */
110
+ export declare const ACVerificationMethodSchema: z.ZodEnum<{
111
+ unit_test: "unit_test";
112
+ integration_test: "integration_test";
113
+ browser_test: "browser_test";
114
+ manual: "manual";
115
+ }>;
116
+ export type ACVerificationMethod = z.infer<typeof ACVerificationMethodSchema>;
117
+ /**
118
+ * Individual acceptance criterion state
119
+ */
120
+ export declare const AcceptanceCriterionSchema: z.ZodObject<{
121
+ id: z.ZodString;
122
+ description: z.ZodString;
123
+ verificationMethod: z.ZodEnum<{
124
+ unit_test: "unit_test";
125
+ integration_test: "integration_test";
126
+ browser_test: "browser_test";
127
+ manual: "manual";
128
+ }>;
129
+ status: z.ZodEnum<{
130
+ pending: "pending";
131
+ blocked: "blocked";
132
+ met: "met";
133
+ not_met: "not_met";
134
+ }>;
135
+ verifiedAt: z.ZodOptional<z.ZodString>;
136
+ notes: z.ZodOptional<z.ZodString>;
137
+ }, z.core.$strip>;
138
+ export type AcceptanceCriterion = z.infer<typeof AcceptanceCriterionSchema>;
139
+ /**
140
+ * Acceptance criteria tracking for an issue
141
+ */
142
+ export declare const AcceptanceCriteriaSchema: z.ZodObject<{
143
+ items: z.ZodArray<z.ZodObject<{
144
+ id: z.ZodString;
145
+ description: z.ZodString;
146
+ verificationMethod: z.ZodEnum<{
147
+ unit_test: "unit_test";
148
+ integration_test: "integration_test";
149
+ browser_test: "browser_test";
150
+ manual: "manual";
151
+ }>;
152
+ status: z.ZodEnum<{
153
+ pending: "pending";
154
+ blocked: "blocked";
155
+ met: "met";
156
+ not_met: "not_met";
157
+ }>;
158
+ verifiedAt: z.ZodOptional<z.ZodString>;
159
+ notes: z.ZodOptional<z.ZodString>;
160
+ }, z.core.$strip>>;
161
+ extractedAt: z.ZodString;
162
+ summary: z.ZodObject<{
163
+ total: z.ZodNumber;
164
+ met: z.ZodNumber;
165
+ notMet: z.ZodNumber;
166
+ pending: z.ZodNumber;
167
+ blocked: z.ZodNumber;
168
+ }, z.core.$strip>;
169
+ }, z.core.$strip>;
170
+ export type AcceptanceCriteria = z.infer<typeof AcceptanceCriteriaSchema>;
94
171
  /**
95
172
  * Complete state for a single issue
96
173
  */
@@ -100,6 +177,7 @@ export declare const IssueStateSchema: z.ZodObject<{
100
177
  status: z.ZodEnum<{
101
178
  in_progress: "in_progress";
102
179
  not_started: "not_started";
180
+ waiting_for_qa_gate: "waiting_for_qa_gate";
103
181
  ready_for_merge: "ready_for_merge";
104
182
  merged: "merged";
105
183
  blocked: "blocked";
@@ -109,12 +187,14 @@ export declare const IssueStateSchema: z.ZodObject<{
109
187
  branch: z.ZodOptional<z.ZodString>;
110
188
  currentPhase: z.ZodOptional<z.ZodEnum<{
111
189
  loop: "loop";
190
+ verify: "verify";
112
191
  spec: "spec";
113
192
  exec: "exec";
114
193
  qa: "qa";
115
194
  "security-review": "security-review";
116
195
  testgen: "testgen";
117
196
  test: "test";
197
+ merger: "merger";
118
198
  }>>;
119
199
  phases: z.ZodRecord<z.ZodString, z.ZodObject<{
120
200
  status: z.ZodEnum<{
@@ -138,6 +218,34 @@ export declare const IssueStateSchema: z.ZodObject<{
138
218
  iteration: z.ZodNumber;
139
219
  maxIterations: z.ZodNumber;
140
220
  }, z.core.$strip>>;
221
+ acceptanceCriteria: z.ZodOptional<z.ZodObject<{
222
+ items: z.ZodArray<z.ZodObject<{
223
+ id: z.ZodString;
224
+ description: z.ZodString;
225
+ verificationMethod: z.ZodEnum<{
226
+ unit_test: "unit_test";
227
+ integration_test: "integration_test";
228
+ browser_test: "browser_test";
229
+ manual: "manual";
230
+ }>;
231
+ status: z.ZodEnum<{
232
+ pending: "pending";
233
+ blocked: "blocked";
234
+ met: "met";
235
+ not_met: "not_met";
236
+ }>;
237
+ verifiedAt: z.ZodOptional<z.ZodString>;
238
+ notes: z.ZodOptional<z.ZodString>;
239
+ }, z.core.$strip>>;
240
+ extractedAt: z.ZodString;
241
+ summary: z.ZodObject<{
242
+ total: z.ZodNumber;
243
+ met: z.ZodNumber;
244
+ notMet: z.ZodNumber;
245
+ pending: z.ZodNumber;
246
+ blocked: z.ZodNumber;
247
+ }, z.core.$strip>;
248
+ }, z.core.$strip>>;
141
249
  sessionId: z.ZodOptional<z.ZodString>;
142
250
  lastActivity: z.ZodString;
143
251
  createdAt: z.ZodString;
@@ -157,6 +265,7 @@ export declare const WorkflowStateSchema: z.ZodObject<{
157
265
  status: z.ZodEnum<{
158
266
  in_progress: "in_progress";
159
267
  not_started: "not_started";
268
+ waiting_for_qa_gate: "waiting_for_qa_gate";
160
269
  ready_for_merge: "ready_for_merge";
161
270
  merged: "merged";
162
271
  blocked: "blocked";
@@ -166,12 +275,14 @@ export declare const WorkflowStateSchema: z.ZodObject<{
166
275
  branch: z.ZodOptional<z.ZodString>;
167
276
  currentPhase: z.ZodOptional<z.ZodEnum<{
168
277
  loop: "loop";
278
+ verify: "verify";
169
279
  spec: "spec";
170
280
  exec: "exec";
171
281
  qa: "qa";
172
282
  "security-review": "security-review";
173
283
  testgen: "testgen";
174
284
  test: "test";
285
+ merger: "merger";
175
286
  }>>;
176
287
  phases: z.ZodRecord<z.ZodString, z.ZodObject<{
177
288
  status: z.ZodEnum<{
@@ -195,6 +306,34 @@ export declare const WorkflowStateSchema: z.ZodObject<{
195
306
  iteration: z.ZodNumber;
196
307
  maxIterations: z.ZodNumber;
197
308
  }, z.core.$strip>>;
309
+ acceptanceCriteria: z.ZodOptional<z.ZodObject<{
310
+ items: z.ZodArray<z.ZodObject<{
311
+ id: z.ZodString;
312
+ description: z.ZodString;
313
+ verificationMethod: z.ZodEnum<{
314
+ unit_test: "unit_test";
315
+ integration_test: "integration_test";
316
+ browser_test: "browser_test";
317
+ manual: "manual";
318
+ }>;
319
+ status: z.ZodEnum<{
320
+ pending: "pending";
321
+ blocked: "blocked";
322
+ met: "met";
323
+ not_met: "not_met";
324
+ }>;
325
+ verifiedAt: z.ZodOptional<z.ZodString>;
326
+ notes: z.ZodOptional<z.ZodString>;
327
+ }, z.core.$strip>>;
328
+ extractedAt: z.ZodString;
329
+ summary: z.ZodObject<{
330
+ total: z.ZodNumber;
331
+ met: z.ZodNumber;
332
+ notMet: z.ZodNumber;
333
+ pending: z.ZodNumber;
334
+ blocked: z.ZodNumber;
335
+ }, z.core.$strip>;
336
+ }, z.core.$strip>>;
198
337
  sessionId: z.ZodOptional<z.ZodString>;
199
338
  lastActivity: z.ZodString;
200
339
  createdAt: z.ZodString;
@@ -222,3 +361,15 @@ export declare function createIssueState(issueNumber: number, title: string, opt
222
361
  * Create initial phase state
223
362
  */
224
363
  export declare function createPhaseState(status?: PhaseStatus): PhaseState;
364
+ /**
365
+ * Create acceptance criterion
366
+ */
367
+ export declare function createAcceptanceCriterion(id: string, description: string, verificationMethod?: ACVerificationMethod): AcceptanceCriterion;
368
+ /**
369
+ * Create acceptance criteria tracking structure
370
+ */
371
+ export declare function createAcceptanceCriteria(items: AcceptanceCriterion[]): AcceptanceCriteria;
372
+ /**
373
+ * Update acceptance criteria summary based on item statuses
374
+ */
375
+ export declare function updateAcceptanceCriteriaSummary(ac: AcceptanceCriteria): AcceptanceCriteria;
@@ -26,8 +26,10 @@ export const WORKFLOW_PHASES = [
26
26
  "exec",
27
27
  "testgen",
28
28
  "test",
29
+ "verify",
29
30
  "qa",
30
31
  "loop",
32
+ "merger",
31
33
  ];
32
34
  /**
33
35
  * Phase status - tracks individual phase progress
@@ -45,6 +47,7 @@ export const PhaseStatusSchema = z.enum([
45
47
  export const IssueStatusSchema = z.enum([
46
48
  "not_started", // Issue tracked but no work begun
47
49
  "in_progress", // Actively being worked on
50
+ "waiting_for_qa_gate", // QA completed, waiting for gate approval in chain mode
48
51
  "ready_for_merge", // All phases passed, PR ready for review
49
52
  "merged", // PR merged, work complete
50
53
  "blocked", // Waiting on external input or dependency
@@ -59,8 +62,10 @@ export const PhaseSchema = z.enum([
59
62
  "exec",
60
63
  "testgen",
61
64
  "test",
65
+ "verify",
62
66
  "qa",
63
67
  "loop",
68
+ "merger",
64
69
  ]);
65
70
  /**
66
71
  * Individual phase state within an issue
@@ -97,6 +102,58 @@ export const LoopStateSchema = z.object({
97
102
  /** Maximum iterations allowed */
98
103
  maxIterations: z.number().int().positive(),
99
104
  });
105
+ /**
106
+ * Acceptance criteria verification status
107
+ */
108
+ export const ACStatusSchema = z.enum([
109
+ "pending", // Not yet verified
110
+ "met", // Verified as satisfied
111
+ "not_met", // Verified as not satisfied
112
+ "blocked", // Cannot verify due to external dependency
113
+ ]);
114
+ /**
115
+ * Acceptance criteria verification method
116
+ */
117
+ export const ACVerificationMethodSchema = z.enum([
118
+ "unit_test",
119
+ "integration_test",
120
+ "browser_test",
121
+ "manual",
122
+ ]);
123
+ /**
124
+ * Individual acceptance criterion state
125
+ */
126
+ export const AcceptanceCriterionSchema = z.object({
127
+ /** AC identifier (e.g., "A1", "B2") */
128
+ id: z.string(),
129
+ /** Description of the acceptance criterion */
130
+ description: z.string(),
131
+ /** How this AC should be verified */
132
+ verificationMethod: ACVerificationMethodSchema,
133
+ /** Current verification status */
134
+ status: ACStatusSchema,
135
+ /** When the AC was last verified */
136
+ verifiedAt: z.string().datetime().optional(),
137
+ /** Additional notes about verification */
138
+ notes: z.string().optional(),
139
+ });
140
+ /**
141
+ * Acceptance criteria tracking for an issue
142
+ */
143
+ export const AcceptanceCriteriaSchema = z.object({
144
+ /** List of acceptance criteria */
145
+ items: z.array(AcceptanceCriterionSchema),
146
+ /** When the AC list was extracted from the issue */
147
+ extractedAt: z.string().datetime(),
148
+ /** Summary counts for quick access */
149
+ summary: z.object({
150
+ total: z.number().int().nonnegative(),
151
+ met: z.number().int().nonnegative(),
152
+ notMet: z.number().int().nonnegative(),
153
+ pending: z.number().int().nonnegative(),
154
+ blocked: z.number().int().nonnegative(),
155
+ }),
156
+ });
100
157
  /**
101
158
  * Complete state for a single issue
102
159
  */
@@ -119,6 +176,8 @@ export const IssueStateSchema = z.object({
119
176
  pr: PRInfoSchema.optional(),
120
177
  /** Quality loop state (if loop enabled) */
121
178
  loop: LoopStateSchema.optional(),
179
+ /** Acceptance criteria tracking (if extracted by /spec) */
180
+ acceptanceCriteria: AcceptanceCriteriaSchema.optional(),
122
181
  /** Claude session ID (for resume) */
123
182
  sessionId: z.string().optional(),
124
183
  /** Most recent activity timestamp */
@@ -188,3 +247,43 @@ export function createPhaseState(status = "pending") {
188
247
  }
189
248
  return { status };
190
249
  }
250
+ /**
251
+ * Create acceptance criterion
252
+ */
253
+ export function createAcceptanceCriterion(id, description, verificationMethod = "manual") {
254
+ return {
255
+ id,
256
+ description,
257
+ verificationMethod,
258
+ status: "pending",
259
+ };
260
+ }
261
+ /**
262
+ * Create acceptance criteria tracking structure
263
+ */
264
+ export function createAcceptanceCriteria(items) {
265
+ return {
266
+ items,
267
+ extractedAt: new Date().toISOString(),
268
+ summary: {
269
+ total: items.length,
270
+ met: 0,
271
+ notMet: 0,
272
+ pending: items.length,
273
+ blocked: 0,
274
+ },
275
+ };
276
+ }
277
+ /**
278
+ * Update acceptance criteria summary based on item statuses
279
+ */
280
+ export function updateAcceptanceCriteriaSummary(ac) {
281
+ const summary = {
282
+ total: ac.items.length,
283
+ met: ac.items.filter((i) => i.status === "met").length,
284
+ notMet: ac.items.filter((i) => i.status === "not_met").length,
285
+ pending: ac.items.filter((i) => i.status === "pending").length,
286
+ blocked: ac.items.filter((i) => i.status === "blocked").length,
287
+ };
288
+ return { ...ac, summary };
289
+ }
@@ -12,6 +12,18 @@
12
12
  * const result = await cleanupStaleEntries({ dryRun: true });
13
13
  * ```
14
14
  */
15
+ import { type Phase } from "./state-schema.js";
16
+ /**
17
+ * PR merge status from GitHub
18
+ */
19
+ export type PRMergeStatus = "MERGED" | "CLOSED" | "OPEN" | null;
20
+ /**
21
+ * Check the merge status of a PR using the gh CLI
22
+ *
23
+ * @param prNumber - The PR number to check
24
+ * @returns "MERGED" | "CLOSED" | "OPEN" | null (null if PR not found or gh unavailable)
25
+ */
26
+ export declare function checkPRMergeStatus(prNumber: number): PRMergeStatus;
15
27
  export interface RebuildOptions {
16
28
  /** Log directory path (default: .sequant/logs) */
17
29
  logPath?: string;
@@ -46,21 +58,73 @@ export interface CleanupOptions {
46
58
  verbose?: boolean;
47
59
  /** Remove issues older than this many days */
48
60
  maxAgeDays?: number;
61
+ /** Remove all orphaned entries (both merged and abandoned) in one step */
62
+ removeAll?: boolean;
49
63
  }
50
64
  export interface CleanupResult {
51
65
  /** Whether cleanup was successful */
52
66
  success: boolean;
53
67
  /** Issues that were removed or would be removed */
54
68
  removed: number[];
55
- /** Issues that were marked as orphaned */
69
+ /** Issues that were marked as orphaned (abandoned) */
56
70
  orphaned: number[];
71
+ /** Issues detected as merged PRs */
72
+ merged: number[];
57
73
  /** Error message if failed */
58
74
  error?: string;
59
75
  }
60
76
  /**
61
77
  * Clean up stale and orphaned entries from workflow state
62
78
  *
63
- * - Removes issues with non-existent worktrees (orphaned)
64
- * - Optionally removes old merged/abandoned issues
79
+ * - Checks GitHub to detect if associated PR was merged
80
+ * - Orphaned entries with merged PRs get status "merged" and are removed automatically
81
+ * - Orphaned entries without merged PRs get status "abandoned" (kept for review)
82
+ * - Use removeAll to remove both merged and abandoned orphaned entries in one step
83
+ * - Use maxAgeDays to remove old merged/abandoned issues
65
84
  */
66
85
  export declare function cleanupStaleEntries(options?: CleanupOptions): Promise<CleanupResult>;
86
+ export interface DiscoverOptions {
87
+ /** State file path (default: .sequant/state.json) */
88
+ statePath?: string;
89
+ /** Enable verbose logging */
90
+ verbose?: boolean;
91
+ }
92
+ export interface DiscoveredWorktree {
93
+ /** Issue number extracted from branch name */
94
+ issueNumber: number;
95
+ /** Issue title (fetched from GitHub or placeholder) */
96
+ title: string;
97
+ /** Full path to the worktree */
98
+ worktreePath: string;
99
+ /** Branch name */
100
+ branch: string;
101
+ /** Inferred current phase from logs (if available) */
102
+ inferredPhase?: Phase;
103
+ }
104
+ export interface SkippedWorktree {
105
+ /** Path to the worktree */
106
+ path: string;
107
+ /** Reason it was skipped */
108
+ reason: string;
109
+ }
110
+ export interface DiscoverResult {
111
+ /** Whether discovery was successful */
112
+ success: boolean;
113
+ /** Number of worktrees scanned */
114
+ worktreesScanned: number;
115
+ /** Number of worktrees already tracked */
116
+ alreadyTracked: number;
117
+ /** Discovered worktrees not yet in state */
118
+ discovered: DiscoveredWorktree[];
119
+ /** Worktrees that were skipped (not matching pattern, etc.) */
120
+ skipped: SkippedWorktree[];
121
+ /** Error message if failed */
122
+ error?: string;
123
+ }
124
+ /**
125
+ * Discover worktrees that are not yet tracked in state
126
+ *
127
+ * Scans all git worktrees, identifies those with issue-related branch names,
128
+ * and returns information about worktrees not yet in the state file.
129
+ */
130
+ export declare function discoverUntrackedWorktrees(options?: DiscoverOptions): Promise<DiscoverResult>;