sequant 2.0.1 → 2.1.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 +2 -1
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/.mcp.json +6 -0
- package/dist/marketplace/external_plugins/sequant/README.md +58 -8
- package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +19 -8
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +36 -49
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +158 -48
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +354 -352
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +1155 -33
- package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +35 -4
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +2157 -104
- package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +386 -0
- package/dist/marketplace/external_plugins/sequant/skills/solve/SKILL.md +38 -664
- package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +505 -120
- package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +246 -1
- package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +138 -1
- package/dist/src/commands/dashboard.js +1 -1
- package/dist/src/commands/doctor.js +1 -1
- package/dist/src/commands/init.js +10 -10
- package/dist/src/commands/logs.js +1 -1
- package/dist/src/commands/run.js +49 -39
- package/dist/src/commands/state.js +3 -3
- package/dist/src/commands/status.js +5 -5
- package/dist/src/commands/sync.js +8 -8
- package/dist/src/commands/update.js +16 -16
- package/dist/src/lib/cli-ui.js +20 -19
- package/dist/src/lib/merge-check/index.js +2 -2
- package/dist/src/lib/settings.d.ts +8 -0
- package/dist/src/lib/settings.js +1 -0
- package/dist/src/lib/shutdown.js +1 -1
- package/dist/src/lib/templates.js +2 -0
- package/dist/src/lib/wizard.js +6 -4
- package/dist/src/lib/workflow/batch-executor.js +1 -1
- package/dist/src/lib/workflow/log-writer.js +6 -6
- package/dist/src/lib/workflow/metrics-writer.js +5 -3
- package/dist/src/lib/workflow/phase-executor.js +5 -1
- package/dist/src/lib/workflow/platforms/github.js +5 -1
- package/dist/src/lib/workflow/state-cleanup.js +1 -1
- package/dist/src/lib/workflow/state-manager.js +15 -13
- package/dist/src/lib/workflow/state-rebuild.js +2 -2
- package/dist/src/lib/workflow/types.d.ts +11 -0
- package/dist/src/lib/workflow/worktree-manager.js +40 -41
- package/dist/src/lib/worktree-isolation.d.ts +130 -0
- package/dist/src/lib/worktree-isolation.js +310 -0
- package/package.json +8 -8
- package/templates/agents/sequant-explorer.md +23 -0
- package/templates/agents/sequant-implementer.md +18 -0
- package/templates/agents/sequant-qa-checker.md +24 -0
- package/templates/agents/sequant-testgen.md +25 -0
- package/templates/scripts/cleanup-worktree.sh +18 -0
- package/templates/skills/_shared/references/subagent-types.md +158 -48
- package/templates/skills/exec/SKILL.md +72 -6
- package/templates/skills/qa/SKILL.md +8 -217
- package/templates/skills/spec/SKILL.md +446 -120
- package/templates/skills/testgen/SKILL.md +138 -1
package/dist/src/commands/run.js
CHANGED
|
@@ -109,7 +109,7 @@ export async function runCommand(issues, options) {
|
|
|
109
109
|
try {
|
|
110
110
|
const versionResult = await checkVersionCached();
|
|
111
111
|
if (versionResult.isOutdated && versionResult.latestVersion) {
|
|
112
|
-
console.log(chalk.yellow(`
|
|
112
|
+
console.log(chalk.yellow(` ! ${getVersionWarning(versionResult.currentVersion, versionResult.latestVersion, versionResult.isLocalInstall)}`));
|
|
113
113
|
console.log("");
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -138,6 +138,8 @@ export async function runCommand(issues, options) {
|
|
|
138
138
|
qualityLoop: normalizedOptions.qualityLoop ?? settings.run.qualityLoop,
|
|
139
139
|
maxIterations: normalizedOptions.maxIterations ?? settings.run.maxIterations,
|
|
140
140
|
noSmartTests: normalizedOptions.noSmartTests ?? !settings.run.smartTests,
|
|
141
|
+
// Agent settings (from agents section, not run section)
|
|
142
|
+
isolateParallel: normalizedOptions.isolateParallel ?? settings.agents.isolateParallel,
|
|
141
143
|
// Env overrides
|
|
142
144
|
...envConfig,
|
|
143
145
|
// CLI explicit options override all
|
|
@@ -182,7 +184,7 @@ export async function runCommand(issues, options) {
|
|
|
182
184
|
}
|
|
183
185
|
// Warn about long chains
|
|
184
186
|
if (issueNumbers.length > 5) {
|
|
185
|
-
console.log(chalk.yellow(`
|
|
187
|
+
console.log(chalk.yellow(` ! Warning: Chain has ${issueNumbers.length} issues (recommended max: 5)`));
|
|
186
188
|
console.log(chalk.yellow(" Long chains increase merge complexity and review difficulty."));
|
|
187
189
|
console.log(chalk.yellow(" Consider breaking into smaller chains or using batch mode."));
|
|
188
190
|
console.log("");
|
|
@@ -242,6 +244,7 @@ export async function runCommand(issues, options) {
|
|
|
242
244
|
retry: retryEnabled,
|
|
243
245
|
agent: mergedOptions.agent ?? settings.run.agent,
|
|
244
246
|
aiderSettings: settings.run.aider,
|
|
247
|
+
isolateParallel: mergedOptions.isolateParallel,
|
|
245
248
|
};
|
|
246
249
|
// Propagate verbose mode to UI config so spinners use text-only mode.
|
|
247
250
|
// This prevents animated spinner control characters from colliding with
|
|
@@ -276,7 +279,7 @@ export async function runCommand(issues, options) {
|
|
|
276
279
|
// Log initialization failure is non-fatal - warn and continue without logging
|
|
277
280
|
// Common causes: permissions issues, disk full, invalid path
|
|
278
281
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
279
|
-
console.log(chalk.yellow(`
|
|
282
|
+
console.log(chalk.yellow(` ! Log initialization failed, continuing without logging: ${errorMessage}`));
|
|
280
283
|
logWriter = null;
|
|
281
284
|
}
|
|
282
285
|
}
|
|
@@ -295,37 +298,38 @@ export async function runCommand(issues, options) {
|
|
|
295
298
|
await writer.finalize();
|
|
296
299
|
});
|
|
297
300
|
}
|
|
298
|
-
// Display configuration
|
|
299
|
-
|
|
301
|
+
// Display configuration (columnar alignment)
|
|
302
|
+
const pad = (label) => label.padEnd(15);
|
|
303
|
+
console.log(chalk.gray(` ${pad("Stack")}${manifest.stack}`));
|
|
300
304
|
if (autoDetectPhases) {
|
|
301
|
-
console.log(chalk.gray(` Phases
|
|
305
|
+
console.log(chalk.gray(` ${pad("Phases")}auto-detect from labels`));
|
|
302
306
|
}
|
|
303
307
|
else {
|
|
304
|
-
console.log(chalk.gray(` Phases
|
|
308
|
+
console.log(chalk.gray(` ${pad("Phases")}${config.phases.join(" \u2192 ")}`));
|
|
305
309
|
}
|
|
306
|
-
console.log(chalk.gray(` Mode
|
|
310
|
+
console.log(chalk.gray(` ${pad("Mode")}${config.sequential ? "sequential (stop-on-failure)" : `parallel (concurrency: ${config.concurrency})`}`));
|
|
307
311
|
if (config.qualityLoop) {
|
|
308
|
-
console.log(chalk.gray(` Quality loop
|
|
312
|
+
console.log(chalk.gray(` ${pad("Quality loop")}enabled (max ${config.maxIterations} iterations)`));
|
|
309
313
|
}
|
|
310
314
|
if (mergedOptions.testgen) {
|
|
311
|
-
console.log(chalk.gray(` Testgen
|
|
315
|
+
console.log(chalk.gray(` ${pad("Testgen")}enabled`));
|
|
312
316
|
}
|
|
313
317
|
if (config.noSmartTests) {
|
|
314
|
-
console.log(chalk.gray(` Smart tests
|
|
318
|
+
console.log(chalk.gray(` ${pad("Smart tests")}disabled`));
|
|
315
319
|
}
|
|
316
320
|
if (config.dryRun) {
|
|
317
|
-
console.log(chalk.yellow(`
|
|
321
|
+
console.log(chalk.yellow(` ${pad("!")}DRY RUN - no actual execution`));
|
|
318
322
|
}
|
|
319
323
|
if (logWriter) {
|
|
320
|
-
console.log(chalk.gray(` Logging
|
|
324
|
+
console.log(chalk.gray(` ${pad("Logging")}JSON (run ${logWriter.getRunId()?.slice(0, 8)}...)`));
|
|
321
325
|
}
|
|
322
326
|
if (stateManager) {
|
|
323
|
-
console.log(chalk.gray(` State
|
|
327
|
+
console.log(chalk.gray(` ${pad("State")}enabled`));
|
|
324
328
|
}
|
|
325
329
|
if (mergedOptions.force) {
|
|
326
|
-
console.log(chalk.yellow(` Force
|
|
330
|
+
console.log(chalk.yellow(` ${pad("Force")}enabled (bypass state guard)`));
|
|
327
331
|
}
|
|
328
|
-
console.log(chalk.gray(` Issues
|
|
332
|
+
console.log(chalk.gray(` ${pad("Issues")}${issueNumbers.map((n) => `#${n}`).join(", ")}`));
|
|
329
333
|
// ============================================================================
|
|
330
334
|
// Pre-flight State Guard (#305)
|
|
331
335
|
// ============================================================================
|
|
@@ -341,7 +345,7 @@ export async function runCommand(issues, options) {
|
|
|
341
345
|
}
|
|
342
346
|
catch (error) {
|
|
343
347
|
// AC-8: Graceful degradation - don't block execution on reconciliation failure
|
|
344
|
-
logNonFatalWarning(`
|
|
348
|
+
logNonFatalWarning(` ! State reconciliation failed, continuing...`, error, config.verbose);
|
|
345
349
|
}
|
|
346
350
|
}
|
|
347
351
|
// AC-1 & AC-2: Pre-flight state guard - skip completed issues unless --force
|
|
@@ -355,7 +359,7 @@ export async function runCommand(issues, options) {
|
|
|
355
359
|
(issueState.status === "ready_for_merge" ||
|
|
356
360
|
issueState.status === "merged")) {
|
|
357
361
|
skippedIssues.push(issueNumber);
|
|
358
|
-
console.log(chalk.yellow(`
|
|
362
|
+
console.log(chalk.yellow(` ! #${issueNumber}: already ${issueState.status} — skipping (use --force to re-run)`));
|
|
359
363
|
}
|
|
360
364
|
else {
|
|
361
365
|
activeIssues.push(issueNumber);
|
|
@@ -363,7 +367,7 @@ export async function runCommand(issues, options) {
|
|
|
363
367
|
}
|
|
364
368
|
catch (error) {
|
|
365
369
|
// AC-8: Graceful degradation - if state check fails, include the issue
|
|
366
|
-
logNonFatalWarning(`
|
|
370
|
+
logNonFatalWarning(` ! State lookup failed for #${issueNumber}, including anyway...`, error, config.verbose);
|
|
367
371
|
activeIssues.push(issueNumber);
|
|
368
372
|
}
|
|
369
373
|
}
|
|
@@ -451,7 +455,7 @@ export async function runCommand(issues, options) {
|
|
|
451
455
|
// Check if batch failed and we should stop
|
|
452
456
|
const batchFailed = batchResults.some((r) => !r.success);
|
|
453
457
|
if (batchFailed && config.sequential) {
|
|
454
|
-
console.log(chalk.yellow(`\n
|
|
458
|
+
console.log(chalk.yellow(`\n ! Batch ${batchIdx + 1} failed, stopping batch execution`));
|
|
455
459
|
break;
|
|
456
460
|
}
|
|
457
461
|
}
|
|
@@ -495,7 +499,7 @@ export async function runCommand(issues, options) {
|
|
|
495
499
|
}
|
|
496
500
|
}
|
|
497
501
|
const chainInfo = mergedOptions.chain ? " (chain stopped)" : "";
|
|
498
|
-
console.log(chalk.yellow(`\n
|
|
502
|
+
console.log(chalk.yellow(`\n ! Issue #${issueNumber} failed, stopping sequential execution${chainInfo}`));
|
|
499
503
|
break;
|
|
500
504
|
}
|
|
501
505
|
}
|
|
@@ -512,12 +516,12 @@ export async function runCommand(issues, options) {
|
|
|
512
516
|
const parts = issueNumbers.map((num) => {
|
|
513
517
|
const info = issueStatus.get(num);
|
|
514
518
|
if (info.state === "done")
|
|
515
|
-
return colors.success(`#${num}
|
|
519
|
+
return colors.success(`#${num} \u2714`);
|
|
516
520
|
if (info.state === "failed")
|
|
517
|
-
return colors.error(`#${num}
|
|
518
|
-
return colors.
|
|
521
|
+
return colors.error(`#${num} \u2716`);
|
|
522
|
+
return colors.muted(`#${num} \u00B7`);
|
|
519
523
|
});
|
|
520
|
-
return `
|
|
524
|
+
return ` ${parts.join(" ")}`;
|
|
521
525
|
};
|
|
522
526
|
const updateProgress = (completedIssue) => {
|
|
523
527
|
if (mergedOptions.quiet)
|
|
@@ -533,7 +537,7 @@ export async function runCommand(issues, options) {
|
|
|
533
537
|
? ` (${formatElapsedTime(info.durationSeconds)})`
|
|
534
538
|
: "";
|
|
535
539
|
if (info.state === "done") {
|
|
536
|
-
const line = ` ${colors.success("
|
|
540
|
+
const line = ` ${colors.success("\u2714")} #${completedIssue} completed${duration}`;
|
|
537
541
|
if (process.stdout.isTTY) {
|
|
538
542
|
// Move to a new line before printing the summary, then re-render progress
|
|
539
543
|
process.stdout.write(`\n${line}\n${renderProgressLine()}`);
|
|
@@ -544,7 +548,7 @@ export async function runCommand(issues, options) {
|
|
|
544
548
|
}
|
|
545
549
|
else {
|
|
546
550
|
const errorSuffix = info.error ? `: ${info.error}` : "";
|
|
547
|
-
const line = ` ${colors.error("
|
|
551
|
+
const line = ` ${colors.error("\u2716")} #${completedIssue} failed${duration}${errorSuffix}`;
|
|
548
552
|
if (process.stdout.isTTY) {
|
|
549
553
|
process.stdout.write(`\n${line}\n${renderProgressLine()}`);
|
|
550
554
|
}
|
|
@@ -556,31 +560,37 @@ export async function runCommand(issues, options) {
|
|
|
556
560
|
};
|
|
557
561
|
// Per-phase progress callback for parallel mode (AC-1, AC-3)
|
|
558
562
|
const parallelStartTime = Date.now();
|
|
563
|
+
let lastPhaseEventTime = Date.now();
|
|
559
564
|
const onPhaseProgress = (issue, phase, event, extra) => {
|
|
560
565
|
if (mergedOptions.quiet)
|
|
561
566
|
return;
|
|
567
|
+
lastPhaseEventTime = Date.now();
|
|
562
568
|
let line;
|
|
563
569
|
if (event === "start") {
|
|
564
|
-
line = ` ${colors.
|
|
570
|
+
line = ` ${colors.running("\u25B8")} #${issue} ${phase}`;
|
|
565
571
|
}
|
|
566
572
|
else if (event === "complete") {
|
|
567
573
|
const dur = extra?.durationSeconds != null
|
|
568
|
-
? `
|
|
574
|
+
? ` ${formatElapsedTime(extra.durationSeconds)}`
|
|
569
575
|
: "";
|
|
570
|
-
line = ` ${colors.success("
|
|
576
|
+
line = ` ${colors.success("\u2714")} #${issue} ${phase}${dur}`;
|
|
571
577
|
}
|
|
572
578
|
else {
|
|
573
|
-
line = ` ${colors.error("
|
|
579
|
+
line = ` ${colors.error("\u2716")} #${issue} ${phase}`;
|
|
574
580
|
}
|
|
575
581
|
console.log(line);
|
|
576
582
|
};
|
|
577
|
-
//
|
|
578
|
-
const HEARTBEAT_INTERVAL_MS =
|
|
583
|
+
// 5-minute heartbeat timer, suppressed when phase events occur within window
|
|
584
|
+
const HEARTBEAT_INTERVAL_MS = 300_000;
|
|
585
|
+
const HEARTBEAT_SUPPRESS_MS = 60_000;
|
|
579
586
|
const heartbeatTimer = setInterval(() => {
|
|
580
587
|
if (mergedOptions.quiet)
|
|
581
588
|
return;
|
|
589
|
+
// Suppress if a phase event occurred recently
|
|
590
|
+
if (Date.now() - lastPhaseEventTime < HEARTBEAT_SUPPRESS_MS)
|
|
591
|
+
return;
|
|
582
592
|
const elapsedSec = Math.round((Date.now() - parallelStartTime) / 1000);
|
|
583
|
-
console.log(` ${colors.
|
|
593
|
+
console.log(` ${colors.muted(`Still running... (${formatElapsedTime(elapsedSec)} elapsed)`)}`);
|
|
584
594
|
}, HEARTBEAT_INTERVAL_MS);
|
|
585
595
|
updateProgress();
|
|
586
596
|
const settledResults = await Promise.allSettled(issueNumbers.map((issueNumber) => limit(async () => {
|
|
@@ -719,19 +729,19 @@ export async function runCommand(issues, options) {
|
|
|
719
729
|
},
|
|
720
730
|
});
|
|
721
731
|
if (config.verbose) {
|
|
722
|
-
console.log(chalk.gray(`
|
|
732
|
+
console.log(chalk.gray(` Metrics recorded to .sequant/metrics.json`));
|
|
723
733
|
}
|
|
724
734
|
}
|
|
725
735
|
catch (metricsError) {
|
|
726
736
|
// Metrics recording errors shouldn't stop execution
|
|
727
|
-
logNonFatalWarning(`
|
|
737
|
+
logNonFatalWarning(` ! Metrics recording failed, continuing...`, metricsError, config.verbose);
|
|
728
738
|
}
|
|
729
739
|
}
|
|
730
740
|
// Summary
|
|
731
741
|
console.log("\n" + ui.divider());
|
|
732
742
|
console.log(colors.info(" Summary"));
|
|
733
743
|
console.log(ui.divider());
|
|
734
|
-
console.log(
|
|
744
|
+
console.log(`\n ${colors.success(`${passed} passed`)} ${colors.muted("\u00B7")} ${colors.error(`${failed} failed`)}`);
|
|
735
745
|
for (const result of results) {
|
|
736
746
|
const status = result.success
|
|
737
747
|
? ui.statusIcon("success")
|
|
@@ -750,7 +760,7 @@ export async function runCommand(issues, options) {
|
|
|
750
760
|
}
|
|
751
761
|
console.log("");
|
|
752
762
|
if (logPath) {
|
|
753
|
-
console.log(colors.muted(`
|
|
763
|
+
console.log(colors.muted(` Log: ${logPath}`));
|
|
754
764
|
console.log("");
|
|
755
765
|
}
|
|
756
766
|
// Reflection analysis (--reflect flag)
|
|
@@ -772,7 +782,7 @@ export async function runCommand(issues, options) {
|
|
|
772
782
|
}
|
|
773
783
|
// Suggest merge checks for multi-issue batches
|
|
774
784
|
if (results.length > 1 && passed > 0 && !config.dryRun) {
|
|
775
|
-
console.log(colors.muted("
|
|
785
|
+
console.log(colors.muted(" Tip: Verify batch integration before merging:"));
|
|
776
786
|
console.log(colors.muted(" sequant merge --check"));
|
|
777
787
|
console.log("");
|
|
778
788
|
}
|
|
@@ -19,7 +19,7 @@ import { createIssueState } from "../lib/workflow/state-schema.js";
|
|
|
19
19
|
*/
|
|
20
20
|
export async function stateInitCommand(options = {}) {
|
|
21
21
|
if (!options.json) {
|
|
22
|
-
console.log(chalk.bold("\
|
|
22
|
+
console.log(chalk.bold("\nDiscovering untracked worktrees...\n"));
|
|
23
23
|
}
|
|
24
24
|
const discoverOptions = {
|
|
25
25
|
verbose: options.verbose && !options.json,
|
|
@@ -86,7 +86,7 @@ export async function stateInitCommand(options = {}) {
|
|
|
86
86
|
*/
|
|
87
87
|
export async function stateRebuildCommand(options = {}) {
|
|
88
88
|
if (!options.json) {
|
|
89
|
-
console.log(chalk.bold("\
|
|
89
|
+
console.log(chalk.bold("\nRebuilding state from scratch...\n"));
|
|
90
90
|
if (!options.force) {
|
|
91
91
|
console.log(chalk.yellow("⚠ This will replace the existing state file. Use --force to proceed.\n"));
|
|
92
92
|
return;
|
|
@@ -257,7 +257,7 @@ export async function stateCommand(subcommand, options = {}) {
|
|
|
257
257
|
case "clean":
|
|
258
258
|
return stateCleanCommand(options);
|
|
259
259
|
default:
|
|
260
|
-
console.log(chalk.bold("\
|
|
260
|
+
console.log(chalk.bold("\nsequant state - Manage workflow state\n"));
|
|
261
261
|
console.log("Available subcommands:");
|
|
262
262
|
console.log(chalk.gray(" init Populate state for untracked worktrees"));
|
|
263
263
|
console.log(chalk.gray(" rebuild Recreate state from logs + worktrees"));
|
|
@@ -21,7 +21,7 @@ async function runReconciliation(stateManager, options) {
|
|
|
21
21
|
if (!options.json) {
|
|
22
22
|
// Show reconciliation warnings
|
|
23
23
|
if (result.warnings.length > 0) {
|
|
24
|
-
console.log(chalk.yellow("\n
|
|
24
|
+
console.log(chalk.yellow("\n ! Drift detected:"));
|
|
25
25
|
for (const w of result.warnings) {
|
|
26
26
|
console.log(chalk.yellow(` #${w.issueNumber}: ${w.description}`));
|
|
27
27
|
}
|
|
@@ -33,7 +33,7 @@ async function runReconciliation(stateManager, options) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
if (!result.githubReachable && !options.offline) {
|
|
36
|
-
console.log(chalk.yellow("\n
|
|
36
|
+
console.log(chalk.yellow("\n ! GitHub unreachable — showing cached data. Use --offline to suppress this warning."));
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
return result;
|
|
@@ -331,7 +331,7 @@ async function displayIssueState(options) {
|
|
|
331
331
|
console.log(JSON.stringify(jsonData, null, 2));
|
|
332
332
|
}
|
|
333
333
|
else if (issueState) {
|
|
334
|
-
console.log(chalk.bold(`\
|
|
334
|
+
console.log(chalk.bold(`\nIssue #${options.issue} State\n`));
|
|
335
335
|
console.log(formatIssueState(issueState));
|
|
336
336
|
const hint = getNextActionHint(issueState);
|
|
337
337
|
if (hint) {
|
|
@@ -364,7 +364,7 @@ async function displayIssueState(options) {
|
|
|
364
364
|
}, null, 2));
|
|
365
365
|
}
|
|
366
366
|
else {
|
|
367
|
-
console.log(chalk.bold("\
|
|
367
|
+
console.log(chalk.bold("\nWorkflow State\n"));
|
|
368
368
|
displayIssueSummary(issues);
|
|
369
369
|
// Last synced footer
|
|
370
370
|
const syncedAgo = formatRelativeTime(reconcileResult.lastSynced);
|
|
@@ -387,7 +387,7 @@ async function displayIssueState(options) {
|
|
|
387
387
|
*/
|
|
388
388
|
async function handleRebuild(options) {
|
|
389
389
|
if (!options.json) {
|
|
390
|
-
console.log(chalk.bold("\
|
|
390
|
+
console.log(chalk.bold("\nRebuilding state from logs...\n"));
|
|
391
391
|
}
|
|
392
392
|
const result = await rebuildStateFromLogs({ verbose: !options.json });
|
|
393
393
|
if (options.json) {
|
|
@@ -49,8 +49,8 @@ async function updateSkillsVersion() {
|
|
|
49
49
|
export async function syncCommand(options = {}) {
|
|
50
50
|
const { force = false, quiet = false } = options;
|
|
51
51
|
if (!quiet) {
|
|
52
|
-
console.log(chalk.blue("\
|
|
53
|
-
console.log(chalk.yellow("
|
|
52
|
+
console.log(chalk.blue("\nSyncing templates...\n"));
|
|
53
|
+
console.log(chalk.yellow("Note: For seamless auto-updates, install sequant as a Claude Code plugin:\n" +
|
|
54
54
|
" /plugin install sequant@claude-plugin-directory\n" +
|
|
55
55
|
" Plugin users get auto-updates without running sync manually.\n"));
|
|
56
56
|
}
|
|
@@ -71,7 +71,7 @@ export async function syncCommand(options = {}) {
|
|
|
71
71
|
// Check if sync is needed
|
|
72
72
|
if (!force && skillsVersion === packageVersion) {
|
|
73
73
|
if (!quiet) {
|
|
74
|
-
console.log(chalk.green("
|
|
74
|
+
console.log(chalk.green("✔ Skills are already up to date!"));
|
|
75
75
|
}
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
@@ -83,7 +83,7 @@ export async function syncCommand(options = {}) {
|
|
|
83
83
|
force: true, // Always overwrite when syncing
|
|
84
84
|
};
|
|
85
85
|
if (!quiet) {
|
|
86
|
-
console.log(chalk.blue("
|
|
86
|
+
console.log(chalk.blue("Copying templates..."));
|
|
87
87
|
}
|
|
88
88
|
await copyTemplates(manifest.stack, tokens, copyOptions);
|
|
89
89
|
// Update version markers
|
|
@@ -103,17 +103,17 @@ export async function syncCommand(options = {}) {
|
|
|
103
103
|
});
|
|
104
104
|
await writeAgentsMd(agentsMdContent);
|
|
105
105
|
if (!quiet) {
|
|
106
|
-
console.log(chalk.blue("
|
|
106
|
+
console.log(chalk.blue("Regenerated AGENTS.md"));
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
catch {
|
|
110
110
|
if (!quiet) {
|
|
111
|
-
console.log(chalk.yellow("
|
|
111
|
+
console.log(chalk.yellow("! Could not regenerate AGENTS.md (non-blocking)"));
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
if (!quiet) {
|
|
116
|
-
console.log(chalk.green(`\n
|
|
116
|
+
console.log(chalk.green(`\n✔ Synced to v${packageVersion}`));
|
|
117
117
|
console.log(chalk.gray("\nSkills, hooks, and memory files have been updated."));
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -123,7 +123,7 @@ export async function syncCommand(options = {}) {
|
|
|
123
123
|
export async function checkAndWarnSkillsOutdated() {
|
|
124
124
|
const { outdated, currentVersion, packageVersion } = await areSkillsOutdated();
|
|
125
125
|
if (outdated) {
|
|
126
|
-
console.log(chalk.yellow(`\n
|
|
126
|
+
console.log(chalk.yellow(`\n! Skills are outdated (${currentVersion || "unknown"} → ${packageVersion})`));
|
|
127
127
|
console.log(chalk.yellow(" Run: npx sequant sync\n"));
|
|
128
128
|
return true;
|
|
129
129
|
}
|
|
@@ -11,8 +11,8 @@ import { getConfig, saveConfig } from "../lib/config.js";
|
|
|
11
11
|
import { getStackConfig, PM_CONFIG, getPackageManagerCommands, } from "../lib/stacks.js";
|
|
12
12
|
import { readFile, writeFile, fileExists } from "../lib/fs.js";
|
|
13
13
|
export async function updateCommand(options) {
|
|
14
|
-
console.log(chalk.blue("\
|
|
15
|
-
console.log(chalk.yellow("
|
|
14
|
+
console.log(chalk.blue("\nChecking for updates...\n"));
|
|
15
|
+
console.log(chalk.yellow("Note: For seamless auto-updates, install sequant as a Claude Code plugin:\n" +
|
|
16
16
|
" /plugin install sequant@claude-plugin-directory\n" +
|
|
17
17
|
" Plugin users get auto-updates without running update manually.\n"));
|
|
18
18
|
// Check if initialized
|
|
@@ -31,7 +31,7 @@ export async function updateCommand(options) {
|
|
|
31
31
|
const manifestNum = mMajor * 10000 + mMinor * 100 + mPatch;
|
|
32
32
|
const packageNum = pMajor * 10000 + pMinor * 100 + pPatch;
|
|
33
33
|
if (packageNum < manifestNum) {
|
|
34
|
-
console.log(chalk.yellow(
|
|
34
|
+
console.log(chalk.yellow(`! Warning: You're running an older CLI version (${packageVersion}) than installed (${manifest.version}).`));
|
|
35
35
|
console.log(chalk.yellow(` Run with: npx sequant@latest update\n`));
|
|
36
36
|
}
|
|
37
37
|
// Get config with tokens (or migrate legacy installs)
|
|
@@ -47,12 +47,12 @@ export async function updateCommand(options) {
|
|
|
47
47
|
tokens.PM_RUN = pmConfig.run;
|
|
48
48
|
config.tokens = tokens;
|
|
49
49
|
await saveConfig(config);
|
|
50
|
-
console.log(chalk.blue(
|
|
50
|
+
console.log(chalk.blue(`Added PM_RUN token: ${tokens.PM_RUN}\n`));
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
54
|
// First-time config setup
|
|
55
|
-
console.log(chalk.blue("
|
|
55
|
+
console.log(chalk.blue("Setting up configuration (one-time setup)\n"));
|
|
56
56
|
const stackConfig = getStackConfig(manifest.stack);
|
|
57
57
|
const defaultDevUrl = stackConfig.devUrl;
|
|
58
58
|
// Get package manager run command
|
|
@@ -60,7 +60,7 @@ export async function updateCommand(options) {
|
|
|
60
60
|
const pmConfig = getPackageManagerCommands(pm);
|
|
61
61
|
if (options.force) {
|
|
62
62
|
tokens = { DEV_URL: defaultDevUrl, PM_RUN: pmConfig.run };
|
|
63
|
-
console.log(chalk.blue(
|
|
63
|
+
console.log(chalk.blue(`Using default dev URL: ${defaultDevUrl}`));
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
66
|
const { inputDevUrl } = await inquirer.prompt([
|
|
@@ -80,7 +80,7 @@ export async function updateCommand(options) {
|
|
|
80
80
|
initialized: manifest.installedAt,
|
|
81
81
|
};
|
|
82
82
|
await saveConfig(config);
|
|
83
|
-
console.log(chalk.green("
|
|
83
|
+
console.log(chalk.green("✔ Configuration saved\n"));
|
|
84
84
|
}
|
|
85
85
|
// Get list of template files
|
|
86
86
|
const templateFiles = await listTemplateFiles();
|
|
@@ -130,12 +130,12 @@ export async function updateCommand(options) {
|
|
|
130
130
|
const unchangedFiles = changes.filter((c) => c.status === "unchanged");
|
|
131
131
|
const localOverrides = changes.filter((c) => c.status === "local-override");
|
|
132
132
|
console.log(chalk.bold("Summary:"));
|
|
133
|
-
console.log(chalk.green(`
|
|
134
|
-
console.log(chalk.yellow(`
|
|
133
|
+
console.log(chalk.green(` New files: ${newFiles.length}`));
|
|
134
|
+
console.log(chalk.yellow(` Modified: ${modifiedFiles.length}`));
|
|
135
135
|
console.log(chalk.gray(` ✓ Unchanged: ${unchangedFiles.length}`));
|
|
136
|
-
console.log(chalk.blue(`
|
|
136
|
+
console.log(chalk.blue(` Local overrides: ${localOverrides.length}`));
|
|
137
137
|
if (newFiles.length === 0 && modifiedFiles.length === 0) {
|
|
138
|
-
console.log(chalk.green("\n
|
|
138
|
+
console.log(chalk.green("\n✔ Everything is up to date!"));
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
// Show changes
|
|
@@ -174,7 +174,7 @@ export async function updateCommand(options) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
// Apply updates
|
|
177
|
-
console.log(chalk.blue("\
|
|
177
|
+
console.log(chalk.blue("\nApplying updates..."));
|
|
178
178
|
let updated = 0;
|
|
179
179
|
// Build complete variables for template processing
|
|
180
180
|
const stackConfig = getStackConfig(manifest.stack);
|
|
@@ -194,24 +194,24 @@ export async function updateCommand(options) {
|
|
|
194
194
|
}
|
|
195
195
|
// Update manifest
|
|
196
196
|
await updateManifest();
|
|
197
|
-
console.log(chalk.green(`\n
|
|
197
|
+
console.log(chalk.green(`\n✔ Updated ${updated} files`));
|
|
198
198
|
// Check if package.json was updated and run install
|
|
199
199
|
const packageJsonUpdated = [...newFiles, ...modifiedFiles].some((f) => f.path === "package.json" || f.path.endsWith("/package.json"));
|
|
200
200
|
if (packageJsonUpdated) {
|
|
201
201
|
// Use detected package manager or default to npm
|
|
202
202
|
const pm = manifest.packageManager || "npm";
|
|
203
203
|
const pmConfig = PM_CONFIG[pm];
|
|
204
|
-
console.log(chalk.blue(`\
|
|
204
|
+
console.log(chalk.blue(`\npackage.json updated, running ${pmConfig.install}...`));
|
|
205
205
|
const [cmd, ...args] = pmConfig.install.split(" ");
|
|
206
206
|
const result = spawnSync(cmd, args, {
|
|
207
207
|
stdio: "inherit",
|
|
208
208
|
shell: true,
|
|
209
209
|
});
|
|
210
210
|
if (result.status === 0) {
|
|
211
|
-
console.log(chalk.green("
|
|
211
|
+
console.log(chalk.green("✔ Dependencies installed"));
|
|
212
212
|
}
|
|
213
213
|
else {
|
|
214
|
-
console.log(chalk.yellow(
|
|
214
|
+
console.log(chalk.yellow(`! ${pmConfig.install} failed - run manually`));
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
}
|
package/dist/src/lib/cli-ui.js
CHANGED
|
@@ -155,7 +155,7 @@ class TextSpinner {
|
|
|
155
155
|
this.text = text;
|
|
156
156
|
this.isSpinning = true;
|
|
157
157
|
if (!config.jsonMode) {
|
|
158
|
-
console.log(getColor(chalk.cyan)(`\
|
|
158
|
+
console.log(getColor(chalk.cyan)(`\u25B8 ${this.text}`));
|
|
159
159
|
}
|
|
160
160
|
return this;
|
|
161
161
|
}
|
|
@@ -164,7 +164,7 @@ class TextSpinner {
|
|
|
164
164
|
this.text = text;
|
|
165
165
|
this.isSpinning = false;
|
|
166
166
|
if (!config.jsonMode) {
|
|
167
|
-
console.log(getColor(chalk.green)(`\
|
|
167
|
+
console.log(getColor(chalk.green)(`\u2714 ${this.text}`));
|
|
168
168
|
}
|
|
169
169
|
return this;
|
|
170
170
|
}
|
|
@@ -173,7 +173,7 @@ class TextSpinner {
|
|
|
173
173
|
this.text = text;
|
|
174
174
|
this.isSpinning = false;
|
|
175
175
|
if (!config.jsonMode) {
|
|
176
|
-
console.log(getColor(chalk.red)(`\
|
|
176
|
+
console.log(getColor(chalk.red)(`\u2716 ${this.text}`));
|
|
177
177
|
}
|
|
178
178
|
return this;
|
|
179
179
|
}
|
|
@@ -182,7 +182,7 @@ class TextSpinner {
|
|
|
182
182
|
this.text = text;
|
|
183
183
|
this.isSpinning = false;
|
|
184
184
|
if (!config.jsonMode) {
|
|
185
|
-
console.log(getColor(chalk.yellow)(
|
|
185
|
+
console.log(getColor(chalk.yellow)(`! ${this.text}`));
|
|
186
186
|
}
|
|
187
187
|
return this;
|
|
188
188
|
}
|
|
@@ -301,29 +301,30 @@ export function box(content, style = "default") {
|
|
|
301
301
|
* Create a success box with title and message
|
|
302
302
|
*/
|
|
303
303
|
export function successBox(title, message) {
|
|
304
|
-
const content = `${getColor(chalk.green.bold)(
|
|
304
|
+
const content = `${getColor(chalk.green.bold)(title)}\n\n${message}`;
|
|
305
305
|
return box(content, "success");
|
|
306
306
|
}
|
|
307
307
|
/**
|
|
308
308
|
* Create an error box with title and message
|
|
309
309
|
*/
|
|
310
310
|
export function errorBox(title, message) {
|
|
311
|
-
const content = `${getColor(chalk.red.bold)(
|
|
311
|
+
const content = `${getColor(chalk.red.bold)(title)}\n\n${message}`;
|
|
312
312
|
return box(content, "error");
|
|
313
313
|
}
|
|
314
314
|
/**
|
|
315
315
|
* Create a warning box with title and message
|
|
316
316
|
*/
|
|
317
317
|
export function warningBox(title, message) {
|
|
318
|
-
const content = `${getColor(chalk.yellow.bold)(
|
|
318
|
+
const content = `${getColor(chalk.yellow.bold)(title)}\n\n${message}`;
|
|
319
319
|
return box(content, "warning");
|
|
320
320
|
}
|
|
321
321
|
/**
|
|
322
322
|
* Create a header box
|
|
323
323
|
*/
|
|
324
324
|
export function headerBox(title) {
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
if (config.jsonMode)
|
|
326
|
+
return "";
|
|
327
|
+
return getColor(chalk.bold)(title);
|
|
327
328
|
}
|
|
328
329
|
/**
|
|
329
330
|
* Create a formatted table
|
|
@@ -424,15 +425,15 @@ export function statusIcon(type) {
|
|
|
424
425
|
}
|
|
425
426
|
switch (type) {
|
|
426
427
|
case "success":
|
|
427
|
-
return chalk.green("\
|
|
428
|
+
return chalk.green("\u2714");
|
|
428
429
|
case "error":
|
|
429
|
-
return chalk.red("\
|
|
430
|
+
return chalk.red("\u2716");
|
|
430
431
|
case "warning":
|
|
431
|
-
return chalk.yellow("
|
|
432
|
+
return chalk.yellow("!");
|
|
432
433
|
case "pending":
|
|
433
|
-
return chalk.gray("\
|
|
434
|
+
return chalk.gray("\u00B7");
|
|
434
435
|
case "running":
|
|
435
|
-
return chalk.cyan("\
|
|
436
|
+
return chalk.cyan("\u25B8");
|
|
436
437
|
}
|
|
437
438
|
}
|
|
438
439
|
/**
|
|
@@ -452,7 +453,7 @@ export function printStatus(type, message) {
|
|
|
452
453
|
export function divider(width = 50) {
|
|
453
454
|
if (config.jsonMode)
|
|
454
455
|
return "";
|
|
455
|
-
const char = isLegacyWindows() ? "-" : "\
|
|
456
|
+
const char = isLegacyWindows() ? "-" : "\u2500";
|
|
456
457
|
const line = char.repeat(width);
|
|
457
458
|
return config.noColor ? line : chalk.gray(line);
|
|
458
459
|
}
|
|
@@ -474,15 +475,15 @@ export function phaseProgress(phases) {
|
|
|
474
475
|
const icons = phases.map((phase) => {
|
|
475
476
|
switch (phase.status) {
|
|
476
477
|
case "success":
|
|
477
|
-
return config.noColor ? "[OK]" : chalk.green("\
|
|
478
|
+
return config.noColor ? "[OK]" : chalk.green("\u2714");
|
|
478
479
|
case "failure":
|
|
479
|
-
return config.noColor ? "[X]" : chalk.red("\
|
|
480
|
+
return config.noColor ? "[X]" : chalk.red("\u2716");
|
|
480
481
|
case "running":
|
|
481
|
-
return config.noColor ? "[..]" : chalk.cyan("\
|
|
482
|
+
return config.noColor ? "[..]" : chalk.cyan("\u25B8");
|
|
482
483
|
case "skipped":
|
|
483
484
|
return config.noColor ? "[-]" : chalk.gray("-");
|
|
484
485
|
default:
|
|
485
|
-
return config.noColor ? "[ ]" : chalk.gray("\
|
|
486
|
+
return config.noColor ? "[ ]" : chalk.gray("\u00B7");
|
|
486
487
|
}
|
|
487
488
|
});
|
|
488
489
|
const labels = phases.map((phase) => phase.name.charAt(0).toUpperCase());
|
|
@@ -106,7 +106,7 @@ export function resolveBranches(issueNumbers, repoRoot, runLog) {
|
|
|
106
106
|
}
|
|
107
107
|
// Get modified files from the branch
|
|
108
108
|
const worktreePath = worktreePaths.get(branch);
|
|
109
|
-
let filesModified
|
|
109
|
+
let filesModified;
|
|
110
110
|
if (worktreePath) {
|
|
111
111
|
// Use worktree for diff
|
|
112
112
|
const diffStats = getGitDiffStats(worktreePath);
|
|
@@ -172,7 +172,7 @@ export function getChecksToRun(options) {
|
|
|
172
172
|
*/
|
|
173
173
|
export async function runMergeChecks(issueNumbers, options, repoRoot) {
|
|
174
174
|
const logDir = resolveLogDir();
|
|
175
|
-
let runLog
|
|
175
|
+
let runLog;
|
|
176
176
|
// Auto-detect issues from most recent run log if none specified
|
|
177
177
|
if (issueNumbers.length === 0) {
|
|
178
178
|
runLog = findMostRecentLog(logDir);
|
|
@@ -44,6 +44,14 @@ export interface AgentSettings {
|
|
|
44
44
|
* Default: "haiku"
|
|
45
45
|
*/
|
|
46
46
|
model: "haiku" | "sonnet" | "opus";
|
|
47
|
+
/**
|
|
48
|
+
* Isolate parallel agent groups in separate worktrees.
|
|
49
|
+
* When true, each agent in a parallel group gets its own sub-worktree,
|
|
50
|
+
* eliminating file conflicts structurally. Changes are merged back
|
|
51
|
+
* into the issue worktree after all agents complete.
|
|
52
|
+
* Default: false (opt-in for v1)
|
|
53
|
+
*/
|
|
54
|
+
isolateParallel: boolean;
|
|
47
55
|
}
|
|
48
56
|
/**
|
|
49
57
|
* Aider-specific settings for the aider agent driver.
|