sequant 2.1.1 → 2.2.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/dist/bin/cli.js +1 -0
- package/dist/src/commands/init.d.ts +1 -0
- package/dist/src/commands/init.js +122 -3
- package/dist/src/commands/run-compat.d.ts +14 -0
- package/dist/src/commands/run-compat.js +12 -0
- package/dist/src/commands/run-display.d.ts +17 -0
- package/dist/src/commands/run-display.js +116 -0
- package/dist/src/commands/run.d.ts +4 -26
- package/dist/src/commands/run.js +47 -772
- package/dist/src/commands/status.js +24 -1
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +9 -0
- package/dist/src/lib/errors.d.ts +93 -0
- package/dist/src/lib/errors.js +97 -0
- package/dist/src/lib/settings.d.ts +236 -0
- package/dist/src/lib/settings.js +482 -37
- package/dist/src/lib/skill-version.d.ts +19 -0
- package/dist/src/lib/skill-version.js +68 -0
- package/dist/src/lib/templates.d.ts +1 -0
- package/dist/src/lib/templates.js +1 -1
- package/dist/src/lib/workflow/batch-executor.js +13 -5
- package/dist/src/lib/workflow/config-resolver.d.ts +50 -0
- package/dist/src/lib/workflow/config-resolver.js +167 -0
- package/dist/src/lib/workflow/error-classifier.d.ts +17 -7
- package/dist/src/lib/workflow/error-classifier.js +113 -15
- package/dist/src/lib/workflow/phase-executor.d.ts +31 -0
- package/dist/src/lib/workflow/phase-executor.js +143 -48
- package/dist/src/lib/workflow/run-log-schema.d.ts +12 -0
- package/dist/src/lib/workflow/run-log-schema.js +7 -1
- package/dist/src/lib/workflow/run-orchestrator.d.ts +161 -0
- package/dist/src/lib/workflow/run-orchestrator.js +510 -0
- package/dist/src/lib/workflow/worktree-manager.d.ts +4 -3
- package/dist/src/lib/workflow/worktree-manager.js +61 -11
- package/package.json +1 -1
- package/templates/skills/assess/SKILL.md +239 -77
- package/templates/skills/exec/SKILL.md +7 -68
- package/templates/skills/fullsolve/SKILL.md +303 -137
- package/templates/skills/qa/SKILL.md +42 -46
- package/templates/skills/qa/scripts/quality-checks.sh +47 -1
- package/templates/skills/spec/SKILL.md +183 -982
- package/templates/skills/spec/references/quality-checklist.md +75 -0
- package/templates/skills/test/SKILL.md +0 -27
- package/templates/skills/testgen/SKILL.md +0 -27
|
@@ -11,6 +11,8 @@ import chalk from "chalk";
|
|
|
11
11
|
import { execSync } from "child_process";
|
|
12
12
|
import { readAgentsMd } from "../agents-md.js";
|
|
13
13
|
import { getDriver } from "./drivers/index.js";
|
|
14
|
+
import { classifyError } from "./error-classifier.js";
|
|
15
|
+
import { ApiError } from "../errors.js";
|
|
14
16
|
/**
|
|
15
17
|
* Natural language prompts for each phase.
|
|
16
18
|
* Claude Code invokes the corresponding skills via natural language.
|
|
@@ -216,6 +218,131 @@ export function formatDuration(seconds) {
|
|
|
216
218
|
const secs = seconds % 60;
|
|
217
219
|
return `${mins}m ${secs.toFixed(0)}s`;
|
|
218
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Check whether the exec phase produced any changes in the worktree.
|
|
223
|
+
* Returns true if HEAD has commits unique to it relative to origin/main
|
|
224
|
+
* OR uncommitted work is present.
|
|
225
|
+
*
|
|
226
|
+
* Uses `git rev-list --count origin/main..HEAD` (commits reachable from HEAD
|
|
227
|
+
* but not origin/main) instead of `git diff origin/main..HEAD`, because the
|
|
228
|
+
* two-dot diff also fires in reverse when origin/main has advanced past HEAD
|
|
229
|
+
* — on stale branches that would falsely report "has commits" even when the
|
|
230
|
+
* exec phase produced nothing, reintroducing the bug #534 is fixing.
|
|
231
|
+
*
|
|
232
|
+
* Fails open (returns true) on git errors — a missing origin ref is better
|
|
233
|
+
* diagnosed as a real zero-diff run than as a false phase failure.
|
|
234
|
+
*
|
|
235
|
+
* @internal Exported for testing only.
|
|
236
|
+
*/
|
|
237
|
+
export function hasExecChanges(cwd) {
|
|
238
|
+
let commitsAhead;
|
|
239
|
+
try {
|
|
240
|
+
const count = execSync("git rev-list --count origin/main..HEAD", {
|
|
241
|
+
cwd,
|
|
242
|
+
stdio: "pipe",
|
|
243
|
+
})
|
|
244
|
+
.toString()
|
|
245
|
+
.trim();
|
|
246
|
+
commitsAhead = Number.parseInt(count, 10) > 0;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
if (commitsAhead)
|
|
252
|
+
return true;
|
|
253
|
+
try {
|
|
254
|
+
const porcelain = execSync("git status --porcelain", { cwd, stdio: "pipe" })
|
|
255
|
+
.toString()
|
|
256
|
+
.trim();
|
|
257
|
+
return porcelain.length > 0;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Map a successful AgentPhaseResult to a PhaseResult, applying phase-specific
|
|
265
|
+
* guards that catch agent sessions which returned success without producing
|
|
266
|
+
* usable work (#534):
|
|
267
|
+
*
|
|
268
|
+
* - `qa`: fails when no parseable verdict is found (empty or malformed output).
|
|
269
|
+
* - `exec`: fails when no commits and no uncommitted changes exist.
|
|
270
|
+
*
|
|
271
|
+
* @internal Exported for testing only.
|
|
272
|
+
*/
|
|
273
|
+
export function mapAgentSuccessToPhaseResult(phase, agentResult, durationSeconds, cwd) {
|
|
274
|
+
const tails = {
|
|
275
|
+
stderrTail: agentResult.stderrTail,
|
|
276
|
+
stdoutTail: agentResult.stdoutTail,
|
|
277
|
+
exitCode: agentResult.exitCode,
|
|
278
|
+
};
|
|
279
|
+
if (phase === "qa") {
|
|
280
|
+
const verdict = agentResult.output
|
|
281
|
+
? parseQaVerdict(agentResult.output)
|
|
282
|
+
: null;
|
|
283
|
+
const summary = agentResult.output
|
|
284
|
+
? (parseQaSummary(agentResult.output) ?? undefined)
|
|
285
|
+
: undefined;
|
|
286
|
+
if (verdict &&
|
|
287
|
+
verdict !== "READY_FOR_MERGE" &&
|
|
288
|
+
verdict !== "NEEDS_VERIFICATION") {
|
|
289
|
+
return {
|
|
290
|
+
phase,
|
|
291
|
+
success: false,
|
|
292
|
+
durationSeconds,
|
|
293
|
+
error: `QA verdict: ${verdict}`,
|
|
294
|
+
sessionId: agentResult.sessionId,
|
|
295
|
+
output: agentResult.output,
|
|
296
|
+
verdict,
|
|
297
|
+
summary,
|
|
298
|
+
...tails,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (!verdict) {
|
|
302
|
+
// #534: a null verdict (empty or unparseable output) is not success.
|
|
303
|
+
return {
|
|
304
|
+
phase,
|
|
305
|
+
success: false,
|
|
306
|
+
durationSeconds,
|
|
307
|
+
error: "QA completed without a parseable verdict",
|
|
308
|
+
sessionId: agentResult.sessionId,
|
|
309
|
+
output: agentResult.output,
|
|
310
|
+
summary,
|
|
311
|
+
...tails,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
phase,
|
|
316
|
+
success: true,
|
|
317
|
+
durationSeconds,
|
|
318
|
+
sessionId: agentResult.sessionId,
|
|
319
|
+
output: agentResult.output,
|
|
320
|
+
verdict,
|
|
321
|
+
summary,
|
|
322
|
+
...tails,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (phase === "exec" && !hasExecChanges(cwd)) {
|
|
326
|
+
// #534: an exec phase that produced nothing is not success.
|
|
327
|
+
return {
|
|
328
|
+
phase,
|
|
329
|
+
success: false,
|
|
330
|
+
durationSeconds,
|
|
331
|
+
error: "exec produced no changes (no commits, no uncommitted work)",
|
|
332
|
+
sessionId: agentResult.sessionId,
|
|
333
|
+
output: agentResult.output,
|
|
334
|
+
...tails,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
phase,
|
|
339
|
+
success: true,
|
|
340
|
+
durationSeconds,
|
|
341
|
+
sessionId: agentResult.sessionId,
|
|
342
|
+
output: agentResult.output,
|
|
343
|
+
...tails,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
219
346
|
/**
|
|
220
347
|
* Get the prompt for a phase with the issue number substituted.
|
|
221
348
|
* Selects self-contained prompts for non-Claude agents.
|
|
@@ -388,52 +515,8 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
388
515
|
shutdownManager.removeAbortController(abortController);
|
|
389
516
|
}
|
|
390
517
|
const durationSeconds = (Date.now() - startTime) / 1000;
|
|
391
|
-
// Map AgentPhaseResult to PhaseResult
|
|
392
|
-
const tails = {
|
|
393
|
-
stderrTail: agentResult.stderrTail,
|
|
394
|
-
stdoutTail: agentResult.stdoutTail,
|
|
395
|
-
exitCode: agentResult.exitCode,
|
|
396
|
-
};
|
|
397
518
|
if (agentResult.success) {
|
|
398
|
-
|
|
399
|
-
// Agent "success" just means the execution completed — we need to parse the verdict
|
|
400
|
-
if (phase === "qa" && agentResult.output) {
|
|
401
|
-
const verdict = parseQaVerdict(agentResult.output);
|
|
402
|
-
const summary = parseQaSummary(agentResult.output) ?? undefined;
|
|
403
|
-
if (verdict &&
|
|
404
|
-
verdict !== "READY_FOR_MERGE" &&
|
|
405
|
-
verdict !== "NEEDS_VERIFICATION") {
|
|
406
|
-
return {
|
|
407
|
-
phase,
|
|
408
|
-
success: false,
|
|
409
|
-
durationSeconds,
|
|
410
|
-
error: `QA verdict: ${verdict}`,
|
|
411
|
-
sessionId: agentResult.sessionId,
|
|
412
|
-
output: agentResult.output,
|
|
413
|
-
verdict,
|
|
414
|
-
summary,
|
|
415
|
-
...tails,
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
return {
|
|
419
|
-
phase,
|
|
420
|
-
success: true,
|
|
421
|
-
durationSeconds,
|
|
422
|
-
sessionId: agentResult.sessionId,
|
|
423
|
-
output: agentResult.output,
|
|
424
|
-
verdict: verdict ?? undefined,
|
|
425
|
-
summary,
|
|
426
|
-
...tails,
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
return {
|
|
430
|
-
phase,
|
|
431
|
-
success: true,
|
|
432
|
-
durationSeconds,
|
|
433
|
-
sessionId: agentResult.sessionId,
|
|
434
|
-
output: agentResult.output,
|
|
435
|
-
...tails,
|
|
436
|
-
};
|
|
519
|
+
return mapAgentSuccessToPhaseResult(phase, agentResult, durationSeconds, cwd);
|
|
437
520
|
}
|
|
438
521
|
return {
|
|
439
522
|
phase,
|
|
@@ -441,7 +524,9 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
441
524
|
durationSeconds,
|
|
442
525
|
error: agentResult.error,
|
|
443
526
|
sessionId: agentResult.sessionId,
|
|
444
|
-
|
|
527
|
+
stderrTail: agentResult.stderrTail,
|
|
528
|
+
stdoutTail: agentResult.stdoutTail,
|
|
529
|
+
exitCode: agentResult.exitCode,
|
|
445
530
|
};
|
|
446
531
|
}
|
|
447
532
|
/**
|
|
@@ -490,9 +575,19 @@ delayFn = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
|
490
575
|
return lastResult;
|
|
491
576
|
}
|
|
492
577
|
// Genuine failure (took long enough to be real work) → skip cold-start retries.
|
|
493
|
-
//
|
|
494
|
-
//
|
|
578
|
+
// Use error classification (AC-9): if the error is retryable (e.g., API
|
|
579
|
+
// rate limit, transient 503), allow one more attempt even for genuine failures.
|
|
495
580
|
if (duration >= COLD_START_THRESHOLD_SECONDS) {
|
|
581
|
+
const typedError = classifyError(lastResult.stderrTail ?? [], lastResult.exitCode);
|
|
582
|
+
if (typedError.isRetryable && attempt < COLD_START_MAX_RETRIES) {
|
|
583
|
+
if (config.verbose) {
|
|
584
|
+
const label = typedError instanceof ApiError
|
|
585
|
+
? `API error (status ${typedError.metadata.statusCode ?? "unknown"})`
|
|
586
|
+
: typedError.name;
|
|
587
|
+
console.log(chalk.yellow(`\n ⟳ Retryable error: ${label}, retrying... (attempt ${attempt + 2}/${COLD_START_MAX_RETRIES + 1})`));
|
|
588
|
+
}
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
496
591
|
if (phase === "spec") {
|
|
497
592
|
break;
|
|
498
593
|
}
|
|
@@ -90,6 +90,9 @@ export declare const ErrorContextSchema: z.ZodObject<{
|
|
|
90
90
|
hook_failure: "hook_failure";
|
|
91
91
|
build_error: "build_error";
|
|
92
92
|
}>;
|
|
93
|
+
errorType: z.ZodOptional<z.ZodString>;
|
|
94
|
+
errorMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
95
|
+
isRetryable: z.ZodOptional<z.ZodBoolean>;
|
|
93
96
|
}, z.core.$strip>;
|
|
94
97
|
export type ErrorContext = z.infer<typeof ErrorContextSchema>;
|
|
95
98
|
/**
|
|
@@ -177,6 +180,9 @@ export declare const PhaseLogSchema: z.ZodObject<{
|
|
|
177
180
|
hook_failure: "hook_failure";
|
|
178
181
|
build_error: "build_error";
|
|
179
182
|
}>;
|
|
183
|
+
errorType: z.ZodOptional<z.ZodString>;
|
|
184
|
+
errorMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
185
|
+
isRetryable: z.ZodOptional<z.ZodBoolean>;
|
|
180
186
|
}, z.core.$strip>>;
|
|
181
187
|
}, z.core.$strip>;
|
|
182
188
|
export type PhaseLog = z.infer<typeof PhaseLogSchema>;
|
|
@@ -260,6 +266,9 @@ export declare const IssueLogSchema: z.ZodObject<{
|
|
|
260
266
|
hook_failure: "hook_failure";
|
|
261
267
|
build_error: "build_error";
|
|
262
268
|
}>;
|
|
269
|
+
errorType: z.ZodOptional<z.ZodString>;
|
|
270
|
+
errorMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
271
|
+
isRetryable: z.ZodOptional<z.ZodBoolean>;
|
|
263
272
|
}, z.core.$strip>>;
|
|
264
273
|
}, z.core.$strip>>;
|
|
265
274
|
totalDurationSeconds: z.ZodNumber;
|
|
@@ -404,6 +413,9 @@ export declare const RunLogSchema: z.ZodObject<{
|
|
|
404
413
|
hook_failure: "hook_failure";
|
|
405
414
|
build_error: "build_error";
|
|
406
415
|
}>;
|
|
416
|
+
errorType: z.ZodOptional<z.ZodString>;
|
|
417
|
+
errorMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
418
|
+
isRetryable: z.ZodOptional<z.ZodBoolean>;
|
|
407
419
|
}, z.core.$strip>>;
|
|
408
420
|
}, z.core.$strip>>;
|
|
409
421
|
totalDurationSeconds: z.ZodNumber;
|
|
@@ -79,7 +79,7 @@ export const ErrorContextSchema = z.object({
|
|
|
79
79
|
stdoutTail: z.array(z.string()),
|
|
80
80
|
/** Process exit code */
|
|
81
81
|
exitCode: z.number().int().optional(),
|
|
82
|
-
/** Classified error category */
|
|
82
|
+
/** Classified error category (legacy, kept for backwards compatibility) */
|
|
83
83
|
category: z.enum([
|
|
84
84
|
"context_overflow",
|
|
85
85
|
"api_error",
|
|
@@ -88,6 +88,12 @@ export const ErrorContextSchema = z.object({
|
|
|
88
88
|
"timeout",
|
|
89
89
|
"unknown",
|
|
90
90
|
]),
|
|
91
|
+
/** Typed error class name (AC-8), e.g. "ApiError", "BuildError" */
|
|
92
|
+
errorType: z.string().optional(),
|
|
93
|
+
/** Structured error metadata (AC-8) */
|
|
94
|
+
errorMetadata: z.record(z.string(), z.unknown()).optional(),
|
|
95
|
+
/** Whether this error type is retryable (AC-9) */
|
|
96
|
+
isRetryable: z.boolean().optional(),
|
|
91
97
|
});
|
|
92
98
|
/**
|
|
93
99
|
* Condensed QA verdict summary for structured log output (#434).
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunOrchestrator — CLI-free execution engine for sequant workflows.
|
|
3
|
+
*
|
|
4
|
+
* Owns the full lifecycle: config → issue discovery → dispatch → results.
|
|
5
|
+
* Importable and usable without Commander.js or CLI context.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { ExecutionConfig, IssueResult, RunOptions, ProgressCallback } from "./types.js";
|
|
10
|
+
import type { WorktreeInfo } from "./worktree-manager.js";
|
|
11
|
+
import { LogWriter } from "./log-writer.js";
|
|
12
|
+
import { StateManager } from "./state-manager.js";
|
|
13
|
+
import { ShutdownManager } from "../shutdown.js";
|
|
14
|
+
import type { SequantSettings } from "../settings.js";
|
|
15
|
+
/**
|
|
16
|
+
* Injectable services for RunOrchestrator.
|
|
17
|
+
* All optional — orchestrator degrades gracefully when services are absent.
|
|
18
|
+
*/
|
|
19
|
+
export interface OrchestratorServices {
|
|
20
|
+
logWriter?: LogWriter | null;
|
|
21
|
+
stateManager?: StateManager | null;
|
|
22
|
+
shutdownManager?: ShutdownManager;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* CLI-free configuration for RunOrchestrator.
|
|
26
|
+
* No Commander.js types leak into this interface.
|
|
27
|
+
*/
|
|
28
|
+
export interface OrchestratorConfig {
|
|
29
|
+
/** Execution settings (phases, timeouts, mode flags) */
|
|
30
|
+
config: ExecutionConfig;
|
|
31
|
+
/** Merged run options (post-resolution, no raw CLI types) */
|
|
32
|
+
options: RunOptions;
|
|
33
|
+
/** Issue metadata keyed by issue number */
|
|
34
|
+
issueInfoMap: Map<number, {
|
|
35
|
+
title: string;
|
|
36
|
+
labels: string[];
|
|
37
|
+
}>;
|
|
38
|
+
/** Worktree paths keyed by issue number */
|
|
39
|
+
worktreeMap: Map<number, WorktreeInfo>;
|
|
40
|
+
/** Injectable services */
|
|
41
|
+
services: OrchestratorServices;
|
|
42
|
+
/** Package manager name (e.g. "npm", "pnpm") */
|
|
43
|
+
packageManager?: string;
|
|
44
|
+
/** Base branch for rebase/PR targets */
|
|
45
|
+
baseBranch?: string;
|
|
46
|
+
/** Per-phase progress callback (parallel mode) */
|
|
47
|
+
onProgress?: ProgressCallback;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* High-level init config for full lifecycle execution.
|
|
51
|
+
* Used by RunOrchestrator.run() — the entry point for programmatic callers.
|
|
52
|
+
*/
|
|
53
|
+
export interface RunInit {
|
|
54
|
+
/** Raw CLI options (pre-merge) */
|
|
55
|
+
options: RunOptions;
|
|
56
|
+
/** Resolved settings */
|
|
57
|
+
settings: SequantSettings;
|
|
58
|
+
/** Manifest metadata */
|
|
59
|
+
manifest: {
|
|
60
|
+
stack: string;
|
|
61
|
+
packageManager: string;
|
|
62
|
+
};
|
|
63
|
+
/** Explicit base branch override */
|
|
64
|
+
baseBranch?: string;
|
|
65
|
+
/** Per-phase progress callback */
|
|
66
|
+
onProgress?: ProgressCallback;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Pure result of config resolution — no side effects, no services.
|
|
70
|
+
* Produced by `RunOrchestrator.resolveConfig()` and consumed by both
|
|
71
|
+
* `run()` (internally) and the CLI (for pre-run display).
|
|
72
|
+
*/
|
|
73
|
+
export interface ResolvedRun {
|
|
74
|
+
/** Post-merge run options (defaults < settings < env < explicit) */
|
|
75
|
+
mergedOptions: RunOptions;
|
|
76
|
+
/** Execution config derived from mergedOptions */
|
|
77
|
+
config: ExecutionConfig;
|
|
78
|
+
/** Parsed + dep-sorted issue numbers (pre-state-guard) */
|
|
79
|
+
issueNumbers: number[];
|
|
80
|
+
/** Resolved batches if --batch specified, else null */
|
|
81
|
+
batches: number[][] | null;
|
|
82
|
+
/** Resolved base branch (CLI → settings → auto-detect → "main") */
|
|
83
|
+
baseBranch: string;
|
|
84
|
+
/** Stack from manifest */
|
|
85
|
+
stack: string;
|
|
86
|
+
/** True when phases will be auto-detected from issue labels */
|
|
87
|
+
autoDetectPhases: boolean;
|
|
88
|
+
/** True when worktree isolation is enabled */
|
|
89
|
+
worktreeIsolationEnabled: boolean;
|
|
90
|
+
/** True when JSON logging will be initialized */
|
|
91
|
+
logEnabled: boolean;
|
|
92
|
+
/** True when state tracking will be enabled */
|
|
93
|
+
stateEnabled: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Structured result of a full orchestrator run.
|
|
97
|
+
*/
|
|
98
|
+
export interface RunResult {
|
|
99
|
+
/** Per-issue results */
|
|
100
|
+
results: IssueResult[];
|
|
101
|
+
/** Log file path (if logging enabled) */
|
|
102
|
+
logPath: string | null;
|
|
103
|
+
/** Non-zero if any issue failed */
|
|
104
|
+
exitCode: number;
|
|
105
|
+
/** Worktree map (for summary display) */
|
|
106
|
+
worktreeMap: Map<number, WorktreeInfo>;
|
|
107
|
+
/** Issue info map (for summary display) */
|
|
108
|
+
issueInfoMap: Map<number, {
|
|
109
|
+
title: string;
|
|
110
|
+
labels: string[];
|
|
111
|
+
}>;
|
|
112
|
+
/** Resolved execution config */
|
|
113
|
+
config: ExecutionConfig;
|
|
114
|
+
/** Resolved merged options */
|
|
115
|
+
mergedOptions: RunOptions;
|
|
116
|
+
/** Log writer (for reflection access) */
|
|
117
|
+
logWriter: LogWriter | null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* CLI-free workflow execution engine.
|
|
121
|
+
*
|
|
122
|
+
* Two usage modes:
|
|
123
|
+
* 1. Full lifecycle: `RunOrchestrator.run(init, issueNumbers)` — handles
|
|
124
|
+
* services, worktrees, state guard, execution, and metrics.
|
|
125
|
+
* 2. Low-level: `new RunOrchestrator(config).execute(issueNumbers)` — caller
|
|
126
|
+
* manages setup/teardown.
|
|
127
|
+
*/
|
|
128
|
+
export declare class RunOrchestrator {
|
|
129
|
+
private readonly cfg;
|
|
130
|
+
constructor(config: OrchestratorConfig);
|
|
131
|
+
/**
|
|
132
|
+
* Pure config resolution — no side effects.
|
|
133
|
+
*
|
|
134
|
+
* Produces a `ResolvedRun` containing merged options, execution config,
|
|
135
|
+
* parsed/sorted issue numbers, base branch, and display-only flags. Safe
|
|
136
|
+
* to call for preview purposes (e.g. CLI config display before run).
|
|
137
|
+
*
|
|
138
|
+
* `run()` uses this internally to avoid duplicating resolution logic.
|
|
139
|
+
*/
|
|
140
|
+
static resolveConfig(init: RunInit, issueArgs: string[], batches?: number[][] | null): ResolvedRun;
|
|
141
|
+
/**
|
|
142
|
+
* Full lifecycle execution — the primary entry point for programmatic use.
|
|
143
|
+
*
|
|
144
|
+
* Handles: config resolution → services setup → state guard →
|
|
145
|
+
* issue discovery → worktree creation → execution → metrics → cleanup.
|
|
146
|
+
*/
|
|
147
|
+
static run(init: RunInit, issueArgs: string[], batches?: number[][] | null): Promise<RunResult>;
|
|
148
|
+
/**
|
|
149
|
+
* Execute workflow for the given issue numbers.
|
|
150
|
+
* Returns one IssueResult per issue.
|
|
151
|
+
*/
|
|
152
|
+
execute(issueNumbers: number[]): Promise<IssueResult[]>;
|
|
153
|
+
private validate;
|
|
154
|
+
private buildBatchContext;
|
|
155
|
+
private executeSequential;
|
|
156
|
+
private executeParallel;
|
|
157
|
+
private executeOneIssue;
|
|
158
|
+
private static recordMetrics;
|
|
159
|
+
}
|
|
160
|
+
/** Log a non-fatal warning: one-line summary always, detail in verbose. */
|
|
161
|
+
export declare function logNonFatalWarning(message: string, error: unknown, verbose: boolean): void;
|