sequant 1.4.0 → 1.5.1
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/README.md +29 -0
- package/dist/bin/cli.d.ts +0 -1
- package/dist/bin/cli.js +0 -1
- package/dist/src/commands/doctor.d.ts +1 -5
- package/dist/src/commands/doctor.js +1 -2
- package/dist/src/commands/init.d.ts +0 -1
- package/dist/src/commands/init.js +0 -3
- package/dist/src/commands/logs.d.ts +0 -1
- package/dist/src/commands/logs.js +0 -1
- package/dist/src/commands/run.d.ts +0 -1
- package/dist/src/commands/run.js +161 -97
- package/dist/src/commands/stats.d.ts +0 -1
- package/dist/src/commands/stats.js +0 -1
- package/dist/src/commands/status.d.ts +0 -1
- package/dist/src/commands/status.js +0 -1
- package/dist/src/commands/update.d.ts +0 -1
- package/dist/src/commands/update.js +0 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/lib/config.d.ts +0 -1
- package/dist/src/lib/config.js +0 -1
- package/dist/src/lib/fs.d.ts +0 -1
- package/dist/src/lib/fs.js +0 -1
- package/dist/src/lib/manifest.d.ts +0 -1
- package/dist/src/lib/manifest.js +0 -1
- package/dist/src/lib/settings.d.ts +26 -1
- package/dist/src/lib/settings.js +12 -1
- package/dist/src/lib/shutdown.d.ts +117 -0
- package/dist/src/lib/shutdown.js +173 -0
- package/dist/src/lib/stacks.d.ts +0 -1
- package/dist/src/lib/stacks.js +0 -1
- package/dist/src/lib/system.d.ts +0 -1
- package/dist/src/lib/system.js +0 -1
- package/dist/src/lib/templates.d.ts +0 -1
- package/dist/src/lib/templates.js +0 -1
- package/dist/src/lib/tty.d.ts +0 -1
- package/dist/src/lib/tty.js +0 -1
- package/dist/src/lib/wizard.d.ts +0 -1
- package/dist/src/lib/wizard.js +0 -1
- package/dist/src/lib/workflow/log-rotation.d.ts +0 -1
- package/dist/src/lib/workflow/log-rotation.js +0 -2
- package/dist/src/lib/workflow/log-writer.d.ts +0 -1
- package/dist/src/lib/workflow/log-writer.js +0 -1
- package/dist/src/lib/workflow/run-log-schema.d.ts +4 -5
- package/dist/src/lib/workflow/run-log-schema.js +0 -1
- package/dist/src/lib/workflow/types.d.ts +0 -1
- package/dist/src/lib/workflow/types.js +0 -1
- package/package.json +8 -2
- package/templates/skills/assess/SKILL.md +31 -0
- package/templates/skills/exec/SKILL.md +164 -15
- package/templates/skills/fullsolve/SKILL.md +61 -10
- package/templates/skills/loop/SKILL.md +48 -3
- package/templates/skills/spec/SKILL.md +97 -2
- package/dist/bin/cli.d.ts.map +0 -1
- package/dist/bin/cli.js.map +0 -1
- package/dist/src/commands/doctor.d.ts.map +0 -1
- package/dist/src/commands/doctor.js.map +0 -1
- package/dist/src/commands/doctor.test.d.ts +0 -2
- package/dist/src/commands/doctor.test.d.ts.map +0 -1
- package/dist/src/commands/doctor.test.js +0 -285
- package/dist/src/commands/doctor.test.js.map +0 -1
- package/dist/src/commands/init.d.ts.map +0 -1
- package/dist/src/commands/init.js.map +0 -1
- package/dist/src/commands/init.test.d.ts +0 -2
- package/dist/src/commands/init.test.d.ts.map +0 -1
- package/dist/src/commands/init.test.js +0 -313
- package/dist/src/commands/init.test.js.map +0 -1
- package/dist/src/commands/logs.d.ts.map +0 -1
- package/dist/src/commands/logs.js.map +0 -1
- package/dist/src/commands/run.d.ts.map +0 -1
- package/dist/src/commands/run.js.map +0 -1
- package/dist/src/commands/run.test.d.ts +0 -2
- package/dist/src/commands/run.test.d.ts.map +0 -1
- package/dist/src/commands/run.test.js +0 -320
- package/dist/src/commands/run.test.js.map +0 -1
- package/dist/src/commands/stats.d.ts.map +0 -1
- package/dist/src/commands/stats.js.map +0 -1
- package/dist/src/commands/stats.test.d.ts +0 -7
- package/dist/src/commands/stats.test.d.ts.map +0 -1
- package/dist/src/commands/stats.test.js +0 -218
- package/dist/src/commands/stats.test.js.map +0 -1
- package/dist/src/commands/status.d.ts.map +0 -1
- package/dist/src/commands/status.js.map +0 -1
- package/dist/src/commands/update.d.ts.map +0 -1
- package/dist/src/commands/update.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/lib/config.d.ts.map +0 -1
- package/dist/src/lib/config.js.map +0 -1
- package/dist/src/lib/fs.d.ts.map +0 -1
- package/dist/src/lib/fs.js.map +0 -1
- package/dist/src/lib/manifest.d.ts.map +0 -1
- package/dist/src/lib/manifest.js.map +0 -1
- package/dist/src/lib/settings.d.ts.map +0 -1
- package/dist/src/lib/settings.js.map +0 -1
- package/dist/src/lib/stacks.d.ts.map +0 -1
- package/dist/src/lib/stacks.js.map +0 -1
- package/dist/src/lib/stacks.test.d.ts +0 -2
- package/dist/src/lib/stacks.test.d.ts.map +0 -1
- package/dist/src/lib/stacks.test.js +0 -487
- package/dist/src/lib/stacks.test.js.map +0 -1
- package/dist/src/lib/system.d.ts.map +0 -1
- package/dist/src/lib/system.js.map +0 -1
- package/dist/src/lib/system.test.d.ts +0 -2
- package/dist/src/lib/system.test.d.ts.map +0 -1
- package/dist/src/lib/system.test.js +0 -107
- package/dist/src/lib/system.test.js.map +0 -1
- package/dist/src/lib/templates.d.ts.map +0 -1
- package/dist/src/lib/templates.js.map +0 -1
- package/dist/src/lib/tty.d.ts.map +0 -1
- package/dist/src/lib/tty.js.map +0 -1
- package/dist/src/lib/tty.test.d.ts +0 -2
- package/dist/src/lib/tty.test.d.ts.map +0 -1
- package/dist/src/lib/tty.test.js +0 -269
- package/dist/src/lib/tty.test.js.map +0 -1
- package/dist/src/lib/wizard.d.ts.map +0 -1
- package/dist/src/lib/wizard.js.map +0 -1
- package/dist/src/lib/wizard.test.d.ts +0 -2
- package/dist/src/lib/wizard.test.d.ts.map +0 -1
- package/dist/src/lib/wizard.test.js +0 -268
- package/dist/src/lib/wizard.test.js.map +0 -1
- package/dist/src/lib/workflow/cli-args.d.ts +0 -138
- package/dist/src/lib/workflow/cli-args.d.ts.map +0 -1
- package/dist/src/lib/workflow/cli-args.js +0 -210
- package/dist/src/lib/workflow/cli-args.js.map +0 -1
- package/dist/src/lib/workflow/execute-issues.d.ts +0 -42
- package/dist/src/lib/workflow/execute-issues.d.ts.map +0 -1
- package/dist/src/lib/workflow/execute-issues.js +0 -463
- package/dist/src/lib/workflow/execute-issues.js.map +0 -1
- package/dist/src/lib/workflow/log-rotation.d.ts.map +0 -1
- package/dist/src/lib/workflow/log-rotation.js.map +0 -1
- package/dist/src/lib/workflow/log-rotation.test.d.ts +0 -7
- package/dist/src/lib/workflow/log-rotation.test.d.ts.map +0 -1
- package/dist/src/lib/workflow/log-rotation.test.js +0 -248
- package/dist/src/lib/workflow/log-rotation.test.js.map +0 -1
- package/dist/src/lib/workflow/log-writer.d.ts.map +0 -1
- package/dist/src/lib/workflow/log-writer.js.map +0 -1
- package/dist/src/lib/workflow/log-writer.test.d.ts +0 -7
- package/dist/src/lib/workflow/log-writer.test.d.ts.map +0 -1
- package/dist/src/lib/workflow/log-writer.test.js +0 -454
- package/dist/src/lib/workflow/log-writer.test.js.map +0 -1
- package/dist/src/lib/workflow/logger.d.ts +0 -168
- package/dist/src/lib/workflow/logger.d.ts.map +0 -1
- package/dist/src/lib/workflow/logger.js +0 -249
- package/dist/src/lib/workflow/logger.js.map +0 -1
- package/dist/src/lib/workflow/run-log-schema.d.ts.map +0 -1
- package/dist/src/lib/workflow/run-log-schema.js.map +0 -1
- package/dist/src/lib/workflow/run-log-schema.test.d.ts +0 -2
- package/dist/src/lib/workflow/run-log-schema.test.d.ts.map +0 -1
- package/dist/src/lib/workflow/run-log-schema.test.js +0 -455
- package/dist/src/lib/workflow/run-log-schema.test.js.map +0 -1
- package/dist/src/lib/workflow/types.d.ts.map +0 -1
- package/dist/src/lib/workflow/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -311,10 +311,16 @@ Configure `sequant run` defaults in `.sequant/settings.json`:
|
|
|
311
311
|
"qualityLoop": false,
|
|
312
312
|
"maxIterations": 3,
|
|
313
313
|
"smartTests": true
|
|
314
|
+
},
|
|
315
|
+
"agents": {
|
|
316
|
+
"parallel": false,
|
|
317
|
+
"model": "haiku"
|
|
314
318
|
}
|
|
315
319
|
}
|
|
316
320
|
```
|
|
317
321
|
|
|
322
|
+
#### Run Settings
|
|
323
|
+
|
|
318
324
|
| Option | Default | Description |
|
|
319
325
|
|--------|---------|-------------|
|
|
320
326
|
| `logJson` | `true` | Enable JSON logging for run sessions |
|
|
@@ -326,6 +332,29 @@ Configure `sequant run` defaults in `.sequant/settings.json`:
|
|
|
326
332
|
| `maxIterations` | `3` | Max quality loop iterations |
|
|
327
333
|
| `smartTests` | `true` | Auto-detect test commands |
|
|
328
334
|
|
|
335
|
+
#### Agent Settings
|
|
336
|
+
|
|
337
|
+
| Option | Default | Description |
|
|
338
|
+
|--------|---------|-------------|
|
|
339
|
+
| `parallel` | `false` | Run sub-agents in parallel (faster but higher token usage) |
|
|
340
|
+
| `model` | `"haiku"` | Default model for sub-agents (`haiku`, `sonnet`, or `opus`) |
|
|
341
|
+
|
|
342
|
+
##### Cost vs Speed Trade-offs
|
|
343
|
+
|
|
344
|
+
Skills like `/qa`, `/merger`, and `/fullsolve` spawn sub-agents for quality checks. The `agents` settings control how these agents execute:
|
|
345
|
+
|
|
346
|
+
| Mode | Token Usage | Speed | Best For |
|
|
347
|
+
|------|-------------|-------|----------|
|
|
348
|
+
| Sequential (`parallel: false`) | 1x (baseline) | Slower | Limited API plans, cost-conscious users |
|
|
349
|
+
| Parallel (`parallel: true`) | ~2-3x | ~50% faster | Unlimited plans, batch operations |
|
|
350
|
+
|
|
351
|
+
**Override per invocation:**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
/qa 123 --parallel # Force parallel (faster)
|
|
355
|
+
/qa 123 --sequential # Force sequential (cheaper)
|
|
356
|
+
```
|
|
357
|
+
|
|
329
358
|
CLI flags override settings file values.
|
|
330
359
|
|
|
331
360
|
## Directory Structure
|
package/dist/bin/cli.d.ts
CHANGED
package/dist/bin/cli.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sequant doctor - Check installation health
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
export declare function doctorCommand(options: DoctorOptions): Promise<void>;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=doctor.d.ts.map
|
|
4
|
+
export declare function doctorCommand(): Promise<void>;
|
|
@@ -5,7 +5,7 @@ import chalk from "chalk";
|
|
|
5
5
|
import { fileExists, isExecutable } from "../lib/fs.js";
|
|
6
6
|
import { getManifest } from "../lib/manifest.js";
|
|
7
7
|
import { commandExists, isGhAuthenticated, isNativeWindows, isWSL, checkOptionalMcpServers, OPTIONAL_MCP_SERVERS, } from "../lib/system.js";
|
|
8
|
-
export async function doctorCommand(
|
|
8
|
+
export async function doctorCommand() {
|
|
9
9
|
console.log(chalk.blue("\n🔍 Running health checks...\n"));
|
|
10
10
|
const checks = [];
|
|
11
11
|
// Check 1: Manifest exists
|
|
@@ -277,4 +277,3 @@ export async function doctorCommand(options) {
|
|
|
277
277
|
console.log(chalk.green("\n✅ All checks passed!"));
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
|
-
//# sourceMappingURL=doctor.js.map
|
|
@@ -47,10 +47,8 @@ const GITIGNORE_ENTRIES = [
|
|
|
47
47
|
async function updateGitignore() {
|
|
48
48
|
const gitignorePath = ".gitignore";
|
|
49
49
|
let content = "";
|
|
50
|
-
let existed = false;
|
|
51
50
|
if (await fileExists(gitignorePath)) {
|
|
52
51
|
content = await readFile(gitignorePath);
|
|
53
|
-
existed = true;
|
|
54
52
|
// Check if already has .sequant/
|
|
55
53
|
if (content.includes(".sequant/")) {
|
|
56
54
|
return false; // Already configured
|
|
@@ -300,4 +298,3 @@ ${chalk.bold("Documentation:")}
|
|
|
300
298
|
https://github.com/admarble/sequant#readme
|
|
301
299
|
`));
|
|
302
300
|
}
|
|
303
|
-
//# sourceMappingURL=init.js.map
|
package/dist/src/commands/run.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getSettings } from "../lib/settings.js";
|
|
|
14
14
|
import { PM_CONFIG } from "../lib/stacks.js";
|
|
15
15
|
import { LogWriter, createPhaseLogFromTiming, } from "../lib/workflow/log-writer.js";
|
|
16
16
|
import { DEFAULT_PHASES, DEFAULT_CONFIG, } from "../lib/workflow/types.js";
|
|
17
|
+
import { ShutdownManager } from "../lib/shutdown.js";
|
|
17
18
|
/**
|
|
18
19
|
* Slugify a title for branch naming
|
|
19
20
|
*/
|
|
@@ -358,7 +359,7 @@ const ISOLATED_PHASES = ["exec", "test", "qa"];
|
|
|
358
359
|
/**
|
|
359
360
|
* Execute a single phase for an issue using Claude Agent SDK
|
|
360
361
|
*/
|
|
361
|
-
async function executePhase(issueNumber, phase, config, sessionId, worktreePath) {
|
|
362
|
+
async function executePhase(issueNumber, phase, config, sessionId, worktreePath, shutdownManager) {
|
|
362
363
|
const startTime = Date.now();
|
|
363
364
|
if (config.dryRun) {
|
|
364
365
|
// Dry run - just simulate
|
|
@@ -382,11 +383,24 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath)
|
|
|
382
383
|
const shouldUseWorktree = worktreePath && ISOLATED_PHASES.includes(phase);
|
|
383
384
|
const cwd = shouldUseWorktree ? worktreePath : process.cwd();
|
|
384
385
|
try {
|
|
386
|
+
// Check if shutdown is in progress
|
|
387
|
+
if (shutdownManager?.shuttingDown) {
|
|
388
|
+
return {
|
|
389
|
+
phase,
|
|
390
|
+
success: false,
|
|
391
|
+
durationSeconds: 0,
|
|
392
|
+
error: "Shutdown in progress",
|
|
393
|
+
};
|
|
394
|
+
}
|
|
385
395
|
// Create abort controller for timeout
|
|
386
396
|
const abortController = new AbortController();
|
|
387
397
|
const timeoutId = setTimeout(() => {
|
|
388
398
|
abortController.abort();
|
|
389
399
|
}, config.phaseTimeout * 1000);
|
|
400
|
+
// Register abort controller with shutdown manager for graceful shutdown
|
|
401
|
+
if (shutdownManager) {
|
|
402
|
+
shutdownManager.setAbortController(abortController);
|
|
403
|
+
}
|
|
390
404
|
let resultSessionId;
|
|
391
405
|
let resultMessage;
|
|
392
406
|
let lastError;
|
|
@@ -455,6 +469,10 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath)
|
|
|
455
469
|
}
|
|
456
470
|
}
|
|
457
471
|
clearTimeout(timeoutId);
|
|
472
|
+
// Clear abort controller from shutdown manager
|
|
473
|
+
if (shutdownManager) {
|
|
474
|
+
shutdownManager.clearAbortController();
|
|
475
|
+
}
|
|
458
476
|
const durationSeconds = (Date.now() - startTime) / 1000;
|
|
459
477
|
// Check result status
|
|
460
478
|
if (resultMessage) {
|
|
@@ -651,7 +669,7 @@ function hasUILabels(labels) {
|
|
|
651
669
|
* Determine phases to run based on options and issue labels
|
|
652
670
|
*/
|
|
653
671
|
function determinePhasesForIssue(basePhases, labels, options) {
|
|
654
|
-
|
|
672
|
+
const phases = [...basePhases];
|
|
655
673
|
// Add testgen phase after spec if requested
|
|
656
674
|
if (options.testgen && phases.includes("spec")) {
|
|
657
675
|
const specIndex = phases.indexOf("spec");
|
|
@@ -797,6 +815,15 @@ export async function runCommand(issues, options) {
|
|
|
797
815
|
});
|
|
798
816
|
await logWriter.initialize(runConfig);
|
|
799
817
|
}
|
|
818
|
+
// Initialize shutdown manager for graceful interruption handling
|
|
819
|
+
const shutdown = new ShutdownManager();
|
|
820
|
+
// Register log writer finalization as cleanup task
|
|
821
|
+
if (logWriter) {
|
|
822
|
+
const writer = logWriter; // Capture for closure
|
|
823
|
+
shutdown.registerCleanup("Finalize run logs", async () => {
|
|
824
|
+
await writer.finalize();
|
|
825
|
+
});
|
|
826
|
+
}
|
|
800
827
|
// Display configuration
|
|
801
828
|
console.log(chalk.gray(` Stack: ${manifest.stack}`));
|
|
802
829
|
if (autoDetectPhases) {
|
|
@@ -840,112 +867,149 @@ export async function runCommand(issues, options) {
|
|
|
840
867
|
title: issueInfoMap.get(num)?.title || `Issue #${num}`,
|
|
841
868
|
}));
|
|
842
869
|
worktreeMap = await ensureWorktrees(issueData, config.verbose, manifest.packageManager);
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
if (batchFailed && config.sequential) {
|
|
856
|
-
console.log(chalk.yellow(`\n ⚠️ Batch ${batchIdx + 1} failed, stopping batch execution`));
|
|
857
|
-
break;
|
|
870
|
+
// Register cleanup tasks for newly created worktrees (not pre-existing ones)
|
|
871
|
+
for (const [issueNum, worktree] of worktreeMap.entries()) {
|
|
872
|
+
if (!worktree.existed) {
|
|
873
|
+
shutdown.registerCleanup(`Cleanup worktree for #${issueNum}`, async () => {
|
|
874
|
+
// Remove worktree (leaves branch intact for recovery)
|
|
875
|
+
const result = spawnSync("git", ["worktree", "remove", "--force", worktree.path], {
|
|
876
|
+
stdio: "pipe",
|
|
877
|
+
});
|
|
878
|
+
if (result.status !== 0 && config.verbose) {
|
|
879
|
+
console.log(chalk.yellow(` Warning: Could not remove worktree ${worktree.path}`));
|
|
880
|
+
}
|
|
881
|
+
});
|
|
858
882
|
}
|
|
859
883
|
}
|
|
860
884
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
if (!result.success) {
|
|
880
|
-
console.log(chalk.yellow(`\n ⚠️ Issue #${issueNumber} failed, stopping sequential execution`));
|
|
881
|
-
break;
|
|
885
|
+
// Execute with graceful shutdown handling
|
|
886
|
+
const results = [];
|
|
887
|
+
let exitCode = 0;
|
|
888
|
+
try {
|
|
889
|
+
if (batches) {
|
|
890
|
+
// Batch execution: run batches sequentially, issues within batch based on mode
|
|
891
|
+
for (let batchIdx = 0; batchIdx < batches.length; batchIdx++) {
|
|
892
|
+
const batch = batches[batchIdx];
|
|
893
|
+
console.log(chalk.blue(`\n Batch ${batchIdx + 1}/${batches.length}: Issues ${batch.map((n) => `#${n}`).join(", ")}`));
|
|
894
|
+
const batchResults = await executeBatch(batch, config, logWriter, mergedOptions, issueInfoMap, worktreeMap, shutdown);
|
|
895
|
+
results.push(...batchResults);
|
|
896
|
+
// Check if batch failed and we should stop
|
|
897
|
+
const batchFailed = batchResults.some((r) => !r.success);
|
|
898
|
+
if (batchFailed && config.sequential) {
|
|
899
|
+
console.log(chalk.yellow(`\n ⚠️ Batch ${batchIdx + 1} failed, stopping batch execution`));
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
882
902
|
}
|
|
883
903
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
904
|
+
else if (config.sequential) {
|
|
905
|
+
// Sequential execution
|
|
906
|
+
for (const issueNumber of issueNumbers) {
|
|
907
|
+
const issueInfo = issueInfoMap.get(issueNumber) ?? {
|
|
908
|
+
title: `Issue #${issueNumber}`,
|
|
909
|
+
labels: [],
|
|
910
|
+
};
|
|
911
|
+
const worktreeInfo = worktreeMap.get(issueNumber);
|
|
912
|
+
// Start issue logging
|
|
913
|
+
if (logWriter) {
|
|
914
|
+
logWriter.startIssue(issueNumber, issueInfo.title, issueInfo.labels);
|
|
915
|
+
}
|
|
916
|
+
const result = await runIssueWithLogging(issueNumber, config, logWriter, issueInfo.labels, mergedOptions, worktreeInfo?.path, shutdown);
|
|
917
|
+
results.push(result);
|
|
918
|
+
// Complete issue logging
|
|
919
|
+
if (logWriter) {
|
|
920
|
+
logWriter.completeIssue();
|
|
921
|
+
}
|
|
922
|
+
// Check if shutdown was triggered
|
|
923
|
+
if (shutdown.shuttingDown) {
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
if (!result.success) {
|
|
927
|
+
console.log(chalk.yellow(`\n ⚠️ Issue #${issueNumber} failed, stopping sequential execution`));
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
897
930
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
//
|
|
901
|
-
|
|
902
|
-
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
// Parallel execution (for now, just run sequentially but don't stop on failure)
|
|
934
|
+
// TODO: Add proper parallel execution with listr2
|
|
935
|
+
for (const issueNumber of issueNumbers) {
|
|
936
|
+
// Check if shutdown was triggered
|
|
937
|
+
if (shutdown.shuttingDown) {
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
const issueInfo = issueInfoMap.get(issueNumber) ?? {
|
|
941
|
+
title: `Issue #${issueNumber}`,
|
|
942
|
+
labels: [],
|
|
943
|
+
};
|
|
944
|
+
const worktreeInfo = worktreeMap.get(issueNumber);
|
|
945
|
+
// Start issue logging
|
|
946
|
+
if (logWriter) {
|
|
947
|
+
logWriter.startIssue(issueNumber, issueInfo.title, issueInfo.labels);
|
|
948
|
+
}
|
|
949
|
+
const result = await runIssueWithLogging(issueNumber, config, logWriter, issueInfo.labels, mergedOptions, worktreeInfo?.path, shutdown);
|
|
950
|
+
results.push(result);
|
|
951
|
+
// Complete issue logging
|
|
952
|
+
if (logWriter) {
|
|
953
|
+
logWriter.completeIssue();
|
|
954
|
+
}
|
|
903
955
|
}
|
|
904
956
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
console.log("");
|
|
930
|
-
if (logPath) {
|
|
931
|
-
console.log(chalk.gray(` 📝 Log: ${logPath}`));
|
|
957
|
+
// Finalize log
|
|
958
|
+
let logPath = null;
|
|
959
|
+
if (logWriter) {
|
|
960
|
+
logPath = await logWriter.finalize();
|
|
961
|
+
}
|
|
962
|
+
// Summary
|
|
963
|
+
console.log(chalk.blue("\n" + "━".repeat(50)));
|
|
964
|
+
console.log(chalk.blue(" Summary"));
|
|
965
|
+
console.log(chalk.blue("━".repeat(50)));
|
|
966
|
+
const passed = results.filter((r) => r.success).length;
|
|
967
|
+
const failed = results.filter((r) => !r.success).length;
|
|
968
|
+
console.log(chalk.gray(`\n Results: ${chalk.green(`${passed} passed`)}, ${chalk.red(`${failed} failed`)}`));
|
|
969
|
+
for (const result of results) {
|
|
970
|
+
const status = result.success ? chalk.green("✓") : chalk.red("✗");
|
|
971
|
+
const duration = result.durationSeconds
|
|
972
|
+
? chalk.gray(` (${formatDuration(result.durationSeconds)})`)
|
|
973
|
+
: "";
|
|
974
|
+
const phases = result.phaseResults
|
|
975
|
+
.map((p) => (p.success ? chalk.green(p.phase) : chalk.red(p.phase)))
|
|
976
|
+
.join(" → ");
|
|
977
|
+
const loopInfo = result.loopTriggered ? chalk.yellow(" [loop]") : "";
|
|
978
|
+
console.log(` ${status} #${result.issueNumber}: ${phases}${loopInfo}${duration}`);
|
|
979
|
+
}
|
|
932
980
|
console.log("");
|
|
981
|
+
if (logPath) {
|
|
982
|
+
console.log(chalk.gray(` 📝 Log: ${logPath}`));
|
|
983
|
+
console.log("");
|
|
984
|
+
}
|
|
985
|
+
if (config.dryRun) {
|
|
986
|
+
console.log(chalk.yellow(" ℹ️ This was a dry run. Use without --dry-run to execute."));
|
|
987
|
+
console.log("");
|
|
988
|
+
}
|
|
989
|
+
// Set exit code if any failed
|
|
990
|
+
if (failed > 0 && !config.dryRun) {
|
|
991
|
+
exitCode = 1;
|
|
992
|
+
}
|
|
933
993
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
994
|
+
finally {
|
|
995
|
+
// Always dispose shutdown manager to clean up signal handlers
|
|
996
|
+
shutdown.dispose();
|
|
937
997
|
}
|
|
938
|
-
// Exit with error if any failed
|
|
939
|
-
if (
|
|
940
|
-
process.exit(
|
|
998
|
+
// Exit with error if any failed (outside try/finally so dispose() runs first)
|
|
999
|
+
if (exitCode !== 0) {
|
|
1000
|
+
process.exit(exitCode);
|
|
941
1001
|
}
|
|
942
1002
|
}
|
|
943
1003
|
/**
|
|
944
1004
|
* Execute a batch of issues
|
|
945
1005
|
*/
|
|
946
|
-
async function executeBatch(issueNumbers, config, logWriter, options, issueInfoMap, worktreeMap) {
|
|
1006
|
+
async function executeBatch(issueNumbers, config, logWriter, options, issueInfoMap, worktreeMap, shutdownManager) {
|
|
947
1007
|
const results = [];
|
|
948
1008
|
for (const issueNumber of issueNumbers) {
|
|
1009
|
+
// Check if shutdown was triggered
|
|
1010
|
+
if (shutdownManager?.shuttingDown) {
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
949
1013
|
const issueInfo = issueInfoMap.get(issueNumber) ?? {
|
|
950
1014
|
title: `Issue #${issueNumber}`,
|
|
951
1015
|
labels: [],
|
|
@@ -955,7 +1019,7 @@ async function executeBatch(issueNumbers, config, logWriter, options, issueInfoM
|
|
|
955
1019
|
if (logWriter) {
|
|
956
1020
|
logWriter.startIssue(issueNumber, issueInfo.title, issueInfo.labels);
|
|
957
1021
|
}
|
|
958
|
-
const result = await runIssueWithLogging(issueNumber, config, logWriter, issueInfo.labels, options, worktreeInfo?.path);
|
|
1022
|
+
const result = await runIssueWithLogging(issueNumber, config, logWriter, issueInfo.labels, options, worktreeInfo?.path, shutdownManager);
|
|
959
1023
|
results.push(result);
|
|
960
1024
|
// Complete issue logging
|
|
961
1025
|
if (logWriter) {
|
|
@@ -967,7 +1031,7 @@ async function executeBatch(issueNumbers, config, logWriter, options, issueInfoM
|
|
|
967
1031
|
/**
|
|
968
1032
|
* Execute all phases for a single issue with logging and quality loop
|
|
969
1033
|
*/
|
|
970
|
-
async function runIssueWithLogging(issueNumber, config, logWriter, labels, options, worktreePath) {
|
|
1034
|
+
async function runIssueWithLogging(issueNumber, config, logWriter, labels, options, worktreePath, shutdownManager) {
|
|
971
1035
|
const startTime = Date.now();
|
|
972
1036
|
const phaseResults = [];
|
|
973
1037
|
let loopTriggered = false;
|
|
@@ -995,7 +1059,8 @@ async function runIssueWithLogging(issueNumber, config, logWriter, labels, optio
|
|
|
995
1059
|
console.log(chalk.gray(` ⏳ spec...`));
|
|
996
1060
|
const specStartTime = new Date();
|
|
997
1061
|
// Note: spec runs in main repo (not worktree) for planning
|
|
998
|
-
const specResult = await executePhase(issueNumber, "spec", config, sessionId, worktreePath)
|
|
1062
|
+
const specResult = await executePhase(issueNumber, "spec", config, sessionId, worktreePath, // Will be ignored for spec (non-isolated phase)
|
|
1063
|
+
shutdownManager);
|
|
999
1064
|
const specEndTime = new Date();
|
|
1000
1065
|
if (specResult.sessionId) {
|
|
1001
1066
|
sessionId = specResult.sessionId;
|
|
@@ -1027,7 +1092,7 @@ async function runIssueWithLogging(issueNumber, config, logWriter, labels, optio
|
|
|
1027
1092
|
: "";
|
|
1028
1093
|
console.log(chalk.green(` ✓ spec${duration}`));
|
|
1029
1094
|
// Parse recommended workflow from spec output
|
|
1030
|
-
|
|
1095
|
+
const parsedWorkflow = specResult.output
|
|
1031
1096
|
? parseRecommendedWorkflow(specResult.output)
|
|
1032
1097
|
: null;
|
|
1033
1098
|
if (parsedWorkflow) {
|
|
@@ -1082,7 +1147,7 @@ async function runIssueWithLogging(issueNumber, config, logWriter, labels, optio
|
|
|
1082
1147
|
for (const phase of phases) {
|
|
1083
1148
|
console.log(chalk.gray(` ⏳ ${phase}...`));
|
|
1084
1149
|
const phaseStartTime = new Date();
|
|
1085
|
-
const result = await executePhase(issueNumber, phase, config, sessionId, worktreePath);
|
|
1150
|
+
const result = await executePhase(issueNumber, phase, config, sessionId, worktreePath, shutdownManager);
|
|
1086
1151
|
const phaseEndTime = new Date();
|
|
1087
1152
|
// Capture session ID for subsequent phases
|
|
1088
1153
|
if (result.sessionId) {
|
|
@@ -1110,7 +1175,7 @@ async function runIssueWithLogging(issueNumber, config, logWriter, labels, optio
|
|
|
1110
1175
|
// If quality loop enabled, run loop phase to fix issues
|
|
1111
1176
|
if (useQualityLoop && iteration < maxIterations) {
|
|
1112
1177
|
console.log(chalk.yellow(` Running /loop to fix issues...`));
|
|
1113
|
-
const loopResult = await executePhase(issueNumber, "loop", config, sessionId, worktreePath);
|
|
1178
|
+
const loopResult = await executePhase(issueNumber, "loop", config, sessionId, worktreePath, shutdownManager);
|
|
1114
1179
|
phaseResults.push(loopResult);
|
|
1115
1180
|
if (loopResult.sessionId) {
|
|
1116
1181
|
sessionId = loopResult.sessionId;
|
|
@@ -1150,4 +1215,3 @@ async function runIssueWithLogging(issueNumber, config, logWriter, labels, optio
|
|
|
1150
1215
|
loopTriggered,
|
|
1151
1216
|
};
|
|
1152
1217
|
}
|
|
1153
|
-
//# sourceMappingURL=run.js.map
|
package/dist/src/index.d.ts
CHANGED
|
@@ -14,4 +14,3 @@ export { copyTemplates, listTemplateFiles, getTemplateContent, processTemplate,
|
|
|
14
14
|
export type { StackConfig } from "./lib/stacks.js";
|
|
15
15
|
export type { Manifest } from "./lib/manifest.js";
|
|
16
16
|
export type { SequantConfig } from "./lib/config.js";
|
|
17
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.js
CHANGED
|
@@ -11,4 +11,3 @@ export { detectStack, getStackConfig, STACKS } from "./lib/stacks.js";
|
|
|
11
11
|
export { getManifest, createManifest, updateManifest } from "./lib/manifest.js";
|
|
12
12
|
export { getConfig, saveConfig } from "./lib/config.js";
|
|
13
13
|
export { copyTemplates, listTemplateFiles, getTemplateContent, processTemplate, } from "./lib/templates.js";
|
|
14
|
-
//# sourceMappingURL=index.js.map
|
package/dist/src/lib/config.d.ts
CHANGED
package/dist/src/lib/config.js
CHANGED
package/dist/src/lib/fs.d.ts
CHANGED
|
@@ -7,4 +7,3 @@ export declare function ensureDir(path: string): Promise<void>;
|
|
|
7
7
|
export declare function readFile(path: string): Promise<string>;
|
|
8
8
|
export declare function writeFile(path: string, content: string): Promise<void>;
|
|
9
9
|
export declare function getFileStats(path: string): Promise<import("fs").Stats>;
|
|
10
|
-
//# sourceMappingURL=fs.d.ts.map
|
package/dist/src/lib/fs.js
CHANGED
|
@@ -13,4 +13,3 @@ export interface Manifest {
|
|
|
13
13
|
export declare function getManifest(): Promise<Manifest | null>;
|
|
14
14
|
export declare function createManifest(stack: string, packageManager?: PackageManager): Promise<void>;
|
|
15
15
|
export declare function updateManifest(): Promise<void>;
|
|
16
|
-
//# sourceMappingURL=manifest.d.ts.map
|
package/dist/src/lib/manifest.js
CHANGED
|
@@ -25,6 +25,26 @@ export interface RotationSettings {
|
|
|
25
25
|
/** Maximum file count before rotation (default: 100) */
|
|
26
26
|
maxFiles: number;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Agent execution settings
|
|
30
|
+
*
|
|
31
|
+
* Controls how sub-agents are spawned in multi-issue skills.
|
|
32
|
+
* Affects token usage and execution speed.
|
|
33
|
+
*/
|
|
34
|
+
export interface AgentSettings {
|
|
35
|
+
/**
|
|
36
|
+
* Run agents in parallel (faster, higher token usage).
|
|
37
|
+
* When false, agents run sequentially (slower, lower token usage).
|
|
38
|
+
* Default: false (cost-optimized)
|
|
39
|
+
*/
|
|
40
|
+
parallel: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Default model for sub-agents.
|
|
43
|
+
* Options: "haiku" (cheapest), "sonnet" (balanced), "opus" (most capable)
|
|
44
|
+
* Default: "haiku"
|
|
45
|
+
*/
|
|
46
|
+
model: "haiku" | "sonnet" | "opus";
|
|
47
|
+
}
|
|
28
48
|
/**
|
|
29
49
|
* Run command settings
|
|
30
50
|
*/
|
|
@@ -56,11 +76,17 @@ export interface SequantSettings {
|
|
|
56
76
|
version: string;
|
|
57
77
|
/** Run command settings */
|
|
58
78
|
run: RunSettings;
|
|
79
|
+
/** Agent execution settings */
|
|
80
|
+
agents: AgentSettings;
|
|
59
81
|
}
|
|
60
82
|
/**
|
|
61
83
|
* Default rotation settings
|
|
62
84
|
*/
|
|
63
85
|
export declare const DEFAULT_ROTATION_SETTINGS: RotationSettings;
|
|
86
|
+
/**
|
|
87
|
+
* Default agent settings (cost-optimized)
|
|
88
|
+
*/
|
|
89
|
+
export declare const DEFAULT_AGENT_SETTINGS: AgentSettings;
|
|
64
90
|
/**
|
|
65
91
|
* Default settings
|
|
66
92
|
*/
|
|
@@ -83,4 +109,3 @@ export declare function settingsExist(): Promise<boolean>;
|
|
|
83
109
|
* Create default settings file
|
|
84
110
|
*/
|
|
85
111
|
export declare function createDefaultSettings(): Promise<void>;
|
|
86
|
-
//# sourceMappingURL=settings.d.ts.map
|