sequant 1.12.0 → 1.13.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/README.md +10 -8
- package/dist/bin/cli.js +12 -9
- package/dist/src/commands/doctor.js +25 -20
- package/dist/src/commands/init.js +152 -65
- package/dist/src/commands/logs.js +7 -6
- package/dist/src/commands/run.d.ts +13 -1
- package/dist/src/commands/run.js +75 -12
- package/dist/src/commands/stats.js +67 -48
- package/dist/src/commands/status.js +30 -12
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +4 -0
- package/dist/src/lib/cli-ui.d.ts +196 -0
- package/dist/src/lib/cli-ui.js +544 -0
- package/dist/src/lib/content-analyzer.d.ts +89 -0
- package/dist/src/lib/content-analyzer.js +437 -0
- package/dist/src/lib/phase-signal.d.ts +94 -0
- package/dist/src/lib/phase-signal.js +171 -0
- package/dist/src/lib/solve-comment-parser.d.ts +84 -0
- package/dist/src/lib/solve-comment-parser.js +200 -0
- package/dist/src/lib/stack-config.d.ts +51 -0
- package/dist/src/lib/stack-config.js +77 -0
- package/dist/src/lib/stacks.d.ts +52 -0
- package/dist/src/lib/stacks.js +173 -0
- package/dist/src/lib/templates.d.ts +2 -0
- package/dist/src/lib/templates.js +5 -2
- package/dist/src/lib/upstream/assessment.d.ts +70 -0
- package/dist/src/lib/upstream/assessment.js +385 -0
- package/dist/src/lib/upstream/index.d.ts +11 -0
- package/dist/src/lib/upstream/index.js +14 -0
- package/dist/src/lib/upstream/issues.d.ts +38 -0
- package/dist/src/lib/upstream/issues.js +267 -0
- package/dist/src/lib/upstream/relevance.d.ts +50 -0
- package/dist/src/lib/upstream/relevance.js +209 -0
- package/dist/src/lib/upstream/report.d.ts +29 -0
- package/dist/src/lib/upstream/report.js +391 -0
- package/dist/src/lib/upstream/types.d.ts +207 -0
- package/dist/src/lib/upstream/types.js +5 -0
- package/dist/src/lib/workflow/log-writer.d.ts +1 -1
- package/dist/src/lib/workflow/metrics-schema.d.ts +3 -3
- package/dist/src/lib/workflow/qa-cache.d.ts +199 -0
- package/dist/src/lib/workflow/qa-cache.js +440 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts +34 -6
- package/dist/src/lib/workflow/run-log-schema.js +12 -1
- package/dist/src/lib/workflow/state-schema.d.ts +4 -4
- package/dist/src/lib/workflow/types.d.ts +4 -0
- package/package.json +6 -1
- package/templates/skills/qa/scripts/quality-checks.sh +509 -53
- package/templates/skills/spec/SKILL.md +107 -5
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ npx sequant stats # View local workflow analytics
|
|
|
194
194
|
npx sequant dashboard # Launch real-time workflow dashboard
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
See [Run Command Options](docs/run-command.md), [State Command](docs/state-command.md), and [Analytics](docs/analytics.md) for details.
|
|
197
|
+
See [Run Command Options](docs/reference/run-command.md), [State Command](docs/reference/state-command.md), and [Analytics](docs/reference/analytics.md) for details.
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
@@ -211,7 +211,7 @@ See [Run Command Options](docs/run-command.md), [State Command](docs/state-comma
|
|
|
211
211
|
}
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
See [Customization Guide](docs/customization.md) for all options.
|
|
214
|
+
See [Customization Guide](docs/guides/customization.md) for all options.
|
|
215
215
|
|
|
216
216
|
---
|
|
217
217
|
|
|
@@ -228,13 +228,15 @@ See [Customization Guide](docs/customization.md) for all options.
|
|
|
228
228
|
|
|
229
229
|
## Documentation
|
|
230
230
|
|
|
231
|
+
- [Quickstart](docs/guides/quickstart.md) — 5-minute guide
|
|
232
|
+
- [Complete Workflow](docs/guides/workflow.md) — Full workflow including post-QA patterns
|
|
231
233
|
- [Getting Started](docs/getting-started/installation.md)
|
|
232
|
-
- [What We've Built](docs/what-weve-built.md) — Comprehensive project overview
|
|
234
|
+
- [What We've Built](docs/internal/what-weve-built.md) — Comprehensive project overview
|
|
233
235
|
- [Workflow Concepts](docs/concepts/workflow-phases.md)
|
|
234
|
-
- [Run Command](docs/run-command.md)
|
|
235
|
-
- [
|
|
236
|
-
- [Customization](docs/customization.md)
|
|
237
|
-
- [Plugin Updates & Versioning](docs/plugin-updates.md)
|
|
236
|
+
- [Run Command](docs/reference/run-command.md)
|
|
237
|
+
- [Git Workflows](docs/guides/git-workflows.md)
|
|
238
|
+
- [Customization](docs/guides/customization.md)
|
|
239
|
+
- [Plugin Updates & Versioning](docs/internal/plugin-updates.md)
|
|
238
240
|
- [Troubleshooting](docs/troubleshooting.md)
|
|
239
241
|
|
|
240
242
|
Stack guides: [Next.js](docs/stacks/nextjs.md) · [Rust](docs/stacks/rust.md) · [Python](docs/stacks/python.md) · [Go](docs/stacks/go.md)
|
|
@@ -268,7 +270,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
|
268
270
|
|
|
269
271
|
### Telemetry
|
|
270
272
|
|
|
271
|
-
Sequant does not collect any usage telemetry. See [docs/telemetry.md](docs/telemetry.md) for details.
|
|
273
|
+
Sequant does not collect any usage telemetry. See [docs/reference/telemetry.md](docs/reference/telemetry.md) for details.
|
|
272
274
|
|
|
273
275
|
---
|
|
274
276
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -11,6 +11,8 @@ import { dirname, resolve } from "path";
|
|
|
11
11
|
import { readFileSync } from "fs";
|
|
12
12
|
import { initCommand } from "../src/commands/init.js";
|
|
13
13
|
import { isLocalNodeModulesInstall } from "../src/lib/version-check.js";
|
|
14
|
+
import { configureUI, banner } from "../src/lib/cli-ui.js";
|
|
15
|
+
import { isCI, isStdoutTTY } from "../src/lib/tty.js";
|
|
14
16
|
// Read version from package.json dynamically
|
|
15
17
|
// Works from both source (bin/) and compiled (dist/bin/) locations
|
|
16
18
|
function getVersion() {
|
|
@@ -46,6 +48,15 @@ const program = new Command();
|
|
|
46
48
|
if (process.argv.includes("--no-color")) {
|
|
47
49
|
process.env.FORCE_COLOR = "0";
|
|
48
50
|
}
|
|
51
|
+
// Configure UI early based on environment and flags
|
|
52
|
+
configureUI({
|
|
53
|
+
noColor: process.argv.includes("--no-color") || !!process.env.NO_COLOR,
|
|
54
|
+
jsonMode: process.argv.includes("--json"),
|
|
55
|
+
verbose: process.argv.includes("--verbose") || process.argv.includes("-v"),
|
|
56
|
+
isTTY: isStdoutTTY(),
|
|
57
|
+
isCI: isCI(),
|
|
58
|
+
minimal: process.env.SEQUANT_MINIMAL === "1",
|
|
59
|
+
});
|
|
49
60
|
// Warn if running from local node_modules (not npx cache or global)
|
|
50
61
|
// This helps users who accidentally have a stale local install
|
|
51
62
|
if (!process.argv.includes("--quiet") && isLocalNodeModulesInstall()) {
|
|
@@ -176,14 +187,6 @@ stateCmd
|
|
|
176
187
|
program.parse();
|
|
177
188
|
// Show help if no command provided
|
|
178
189
|
if (!process.argv.slice(2).length) {
|
|
179
|
-
console.log(
|
|
180
|
-
╔═══════════════════════════════════════════════════════════╗
|
|
181
|
-
║ ║
|
|
182
|
-
║ ${chalk.bold("Sequant")} - Quantize your development workflow ║
|
|
183
|
-
║ ║
|
|
184
|
-
║ Sequential AI phases with quality gates ║
|
|
185
|
-
║ ║
|
|
186
|
-
╚═══════════════════════════════════════════════════════════╝
|
|
187
|
-
`));
|
|
190
|
+
console.log(banner());
|
|
188
191
|
program.help();
|
|
189
192
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
|
+
import { ui, colors } from "../lib/cli-ui.js";
|
|
6
7
|
import { fileExists, isExecutable } from "../lib/fs.js";
|
|
7
8
|
import { getManifest } from "../lib/manifest.js";
|
|
8
9
|
import { commandExists, isGhAuthenticated, isNativeWindows, isWSL, checkOptionalMcpServers, getMcpServersConfig, OPTIONAL_MCP_SERVERS, } from "../lib/system.js";
|
|
@@ -67,7 +68,8 @@ export function checkClosedIssues() {
|
|
|
67
68
|
return missingCommitIssues;
|
|
68
69
|
}
|
|
69
70
|
export async function doctorCommand(options = {}) {
|
|
70
|
-
console.log(
|
|
71
|
+
console.log(ui.headerBox("SEQUANT HEALTH CHECK"));
|
|
72
|
+
console.log();
|
|
71
73
|
const checks = [];
|
|
72
74
|
// Track gh availability and auth for conditional checks later
|
|
73
75
|
let ghAvailable = false;
|
|
@@ -369,22 +371,22 @@ export async function doctorCommand(options = {}) {
|
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
373
|
}
|
|
372
|
-
// Display results
|
|
374
|
+
// Display results with status icons
|
|
373
375
|
let passCount = 0;
|
|
374
376
|
let warnCount = 0;
|
|
375
377
|
let failCount = 0;
|
|
376
378
|
for (const check of checks) {
|
|
377
|
-
const
|
|
378
|
-
?
|
|
379
|
+
const statusType = check.status === "pass"
|
|
380
|
+
? "success"
|
|
379
381
|
: check.status === "warn"
|
|
380
|
-
?
|
|
381
|
-
:
|
|
382
|
+
? "warning"
|
|
383
|
+
: "error";
|
|
382
384
|
const color = check.status === "pass"
|
|
383
|
-
?
|
|
385
|
+
? colors.success
|
|
384
386
|
: check.status === "warn"
|
|
385
|
-
?
|
|
386
|
-
:
|
|
387
|
-
console.log(
|
|
387
|
+
? colors.warning
|
|
388
|
+
: colors.error;
|
|
389
|
+
console.log(` ${ui.statusIcon(statusType)} ${chalk.bold(check.name)}: ${color(check.message)}`);
|
|
388
390
|
if (check.status === "pass")
|
|
389
391
|
passCount++;
|
|
390
392
|
else if (check.status === "warn")
|
|
@@ -392,21 +394,24 @@ export async function doctorCommand(options = {}) {
|
|
|
392
394
|
else
|
|
393
395
|
failCount++;
|
|
394
396
|
}
|
|
395
|
-
// Summary
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
console.log(chalk.yellow(` ⚠ Warnings: ${warnCount}`));
|
|
400
|
-
if (failCount > 0)
|
|
401
|
-
console.log(chalk.red(` ✗ Failed: ${failCount}`));
|
|
397
|
+
// Summary with boxed output
|
|
398
|
+
const totalChecks = passCount + warnCount + failCount;
|
|
399
|
+
let summaryTitle;
|
|
400
|
+
let summaryMessage;
|
|
402
401
|
if (failCount > 0) {
|
|
403
|
-
|
|
402
|
+
summaryTitle = `${failCount} check${failCount > 1 ? "s" : ""} failed`;
|
|
403
|
+
summaryMessage = `Passed: ${passCount}/${totalChecks}\nWarnings: ${warnCount}\nFailed: ${failCount}\n\nRun \`sequant init\` to fix issues.`;
|
|
404
|
+
console.log("\n" + ui.errorBox(summaryTitle, summaryMessage));
|
|
404
405
|
process.exit(1);
|
|
405
406
|
}
|
|
406
407
|
else if (warnCount > 0) {
|
|
407
|
-
|
|
408
|
+
summaryTitle = `All checks passed (${warnCount} warning${warnCount > 1 ? "s" : ""})`;
|
|
409
|
+
summaryMessage = `Passed: ${passCount}/${totalChecks}\nWarnings: ${warnCount}\n\nSequant should work correctly.`;
|
|
410
|
+
console.log("\n" + ui.warningBox(summaryTitle, summaryMessage));
|
|
408
411
|
}
|
|
409
412
|
else {
|
|
410
|
-
|
|
413
|
+
summaryTitle = `All ${totalChecks} checks passed!`;
|
|
414
|
+
summaryMessage = `Your Sequant installation is healthy.`;
|
|
415
|
+
console.log("\n" + ui.successBox(summaryTitle, summaryMessage));
|
|
411
416
|
}
|
|
412
417
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
|
-
import {
|
|
6
|
+
import { ui, colors } from "../lib/cli-ui.js";
|
|
7
|
+
import { detectStack, detectAllStacks, getStackConfig, detectPackageManager, getPackageManagerCommands, STACKS, } from "../lib/stacks.js";
|
|
7
8
|
import { copyTemplates } from "../lib/templates.js";
|
|
8
9
|
import { createManifest } from "../lib/manifest.js";
|
|
9
10
|
import { saveConfig } from "../lib/config.js";
|
|
@@ -12,6 +13,7 @@ import { fileExists, ensureDir, readFile, writeFile } from "../lib/fs.js";
|
|
|
12
13
|
import { commandExists, isGhAuthenticated, getInstallHint, } from "../lib/system.js";
|
|
13
14
|
import { shouldUseInteractiveMode, getNonInteractiveReason, } from "../lib/tty.js";
|
|
14
15
|
import { checkAllDependencies, displayDependencyStatus, runSetupWizard, shouldRunSetupWizard, } from "../lib/wizard.js";
|
|
16
|
+
import { saveStackConfig } from "../lib/stack-config.js";
|
|
15
17
|
/**
|
|
16
18
|
* Check prerequisites and display warnings
|
|
17
19
|
*/
|
|
@@ -66,7 +68,9 @@ function logDefault(label, value) {
|
|
|
66
68
|
console.log(chalk.blue(`📦 ${label}: ${value} (default)`));
|
|
67
69
|
}
|
|
68
70
|
export async function initCommand(options) {
|
|
69
|
-
|
|
71
|
+
// Show banner
|
|
72
|
+
console.log(ui.banner());
|
|
73
|
+
console.log(colors.success("\nInitializing Sequant...\n"));
|
|
70
74
|
// Determine if we should use interactive mode
|
|
71
75
|
const useInteractive = shouldUseInteractiveMode(options.interactive);
|
|
72
76
|
const skipPrompts = options.yes || !useInteractive;
|
|
@@ -139,54 +143,116 @@ export async function initCommand(options) {
|
|
|
139
143
|
}
|
|
140
144
|
// Detect or prompt for stack
|
|
141
145
|
let stack = options.stack;
|
|
146
|
+
let additionalStacks = [];
|
|
142
147
|
if (!stack) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
// Check for multi-stack project in interactive mode
|
|
149
|
+
const allDetectedStacks = !skipPrompts ? await detectAllStacks() : [];
|
|
150
|
+
if (allDetectedStacks.length > 1 && !skipPrompts) {
|
|
151
|
+
// Multi-stack project detected - show checkbox selection
|
|
152
|
+
console.log(chalk.blue(`\n🔍 Detected ${allDetectedStacks.length} stacks in this project:`));
|
|
153
|
+
for (const ds of allDetectedStacks) {
|
|
154
|
+
const location = ds.path ? ` (${ds.path}/)` : " (root)";
|
|
155
|
+
console.log(chalk.gray(` • ${STACKS[ds.stack]?.displayName || ds.stack}${location}`));
|
|
156
|
+
}
|
|
157
|
+
console.log();
|
|
158
|
+
// Multi-stack selection prompt
|
|
159
|
+
const { selectedStacks } = await inquirer.prompt([
|
|
150
160
|
{
|
|
151
|
-
type: "
|
|
152
|
-
name: "
|
|
153
|
-
message:
|
|
154
|
-
choices:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
type: "checkbox",
|
|
162
|
+
name: "selectedStacks",
|
|
163
|
+
message: "Select stacks to include in your constitution:",
|
|
164
|
+
choices: allDetectedStacks.map((ds) => ({
|
|
165
|
+
name: `${STACKS[ds.stack]?.displayName || ds.stack}${ds.path ? ` (${ds.path}/)` : " (root)"}`,
|
|
166
|
+
value: ds.stack,
|
|
167
|
+
checked: true, // Pre-select all detected stacks
|
|
168
|
+
})),
|
|
169
|
+
validate: (answer) => {
|
|
170
|
+
if (answer.length < 1) {
|
|
171
|
+
return "You must select at least one stack.";
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
},
|
|
158
175
|
},
|
|
159
176
|
]);
|
|
160
|
-
stack
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
177
|
+
// First selected stack is the primary
|
|
178
|
+
if (selectedStacks.length > 0) {
|
|
179
|
+
stack = selectedStacks[0];
|
|
180
|
+
additionalStacks = selectedStacks.slice(1);
|
|
181
|
+
}
|
|
182
|
+
// Confirm or change primary stack if multiple selected
|
|
183
|
+
if (selectedStacks.length > 1) {
|
|
184
|
+
const { primaryStack } = await inquirer.prompt([
|
|
185
|
+
{
|
|
186
|
+
type: "list",
|
|
187
|
+
name: "primaryStack",
|
|
188
|
+
message: "Which stack should be the primary? (determines dev URL and commands)",
|
|
189
|
+
choices: selectedStacks.map((s) => ({
|
|
190
|
+
name: STACKS[s]?.displayName || s,
|
|
191
|
+
value: s,
|
|
192
|
+
})),
|
|
193
|
+
},
|
|
194
|
+
]);
|
|
195
|
+
stack = primaryStack;
|
|
196
|
+
additionalStacks = selectedStacks.filter((s) => s !== primaryStack);
|
|
197
|
+
}
|
|
166
198
|
}
|
|
167
|
-
else
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
199
|
+
else {
|
|
200
|
+
// Single stack detection (original behavior)
|
|
201
|
+
const detected = await detectStack();
|
|
202
|
+
if (detected && skipPrompts) {
|
|
203
|
+
stack = detected;
|
|
204
|
+
logDefault("Detected stack", stack);
|
|
205
|
+
}
|
|
206
|
+
else if (detected && !skipPrompts) {
|
|
207
|
+
const { confirmedStack } = await inquirer.prompt([
|
|
208
|
+
{
|
|
209
|
+
type: "list",
|
|
210
|
+
name: "confirmedStack",
|
|
211
|
+
message: `Detected ${detected} project. Is this correct?`,
|
|
212
|
+
choices: [
|
|
213
|
+
{ name: `Yes, use ${detected}`, value: detected },
|
|
214
|
+
{ name: "No, let me choose", value: null },
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
]);
|
|
218
|
+
stack = confirmedStack;
|
|
219
|
+
}
|
|
220
|
+
if (!stack && skipPrompts) {
|
|
221
|
+
// No detection and skipping prompts: use generic as default
|
|
222
|
+
stack = "generic";
|
|
223
|
+
logDefault("Using stack", stack);
|
|
224
|
+
}
|
|
225
|
+
else if (!stack) {
|
|
226
|
+
const { selectedStack } = await inquirer.prompt([
|
|
227
|
+
{
|
|
228
|
+
type: "list",
|
|
229
|
+
name: "selectedStack",
|
|
230
|
+
message: "Select your project stack:",
|
|
231
|
+
choices: [
|
|
232
|
+
{ name: "Next.js / React", value: "nextjs" },
|
|
233
|
+
{ name: "Astro", value: "astro" },
|
|
234
|
+
{ name: "SvelteKit", value: "sveltekit" },
|
|
235
|
+
{ name: "Remix", value: "remix" },
|
|
236
|
+
{ name: "Nuxt", value: "nuxt" },
|
|
237
|
+
{ name: "Rust", value: "rust" },
|
|
238
|
+
{ name: "Python", value: "python" },
|
|
239
|
+
{ name: "Go", value: "go" },
|
|
240
|
+
{ name: "Generic (no stack-specific config)", value: "generic" },
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
]);
|
|
244
|
+
stack = selectedStack;
|
|
245
|
+
}
|
|
187
246
|
}
|
|
188
247
|
}
|
|
189
|
-
|
|
248
|
+
// Display selected stacks
|
|
249
|
+
if (additionalStacks.length > 0) {
|
|
250
|
+
console.log(chalk.blue(`\n📋 Primary Stack: ${stack}`));
|
|
251
|
+
console.log(chalk.blue(` Additional: ${additionalStacks.join(", ")}`));
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
console.log(chalk.blue(`\n📋 Stack: ${stack}`));
|
|
255
|
+
}
|
|
190
256
|
// Detect package manager
|
|
191
257
|
const packageManager = await detectPackageManager();
|
|
192
258
|
if (packageManager) {
|
|
@@ -236,21 +302,24 @@ export async function initCommand(options) {
|
|
|
236
302
|
return;
|
|
237
303
|
}
|
|
238
304
|
}
|
|
239
|
-
// Create directories
|
|
240
|
-
|
|
305
|
+
// Create directories with spinner
|
|
306
|
+
const dirSpinner = ui.spinner("Creating directories...");
|
|
307
|
+
dirSpinner.start();
|
|
241
308
|
await ensureDir(".claude/skills");
|
|
242
309
|
await ensureDir(".claude/hooks");
|
|
243
310
|
await ensureDir(".claude/memory");
|
|
244
311
|
await ensureDir(".claude/.sequant");
|
|
245
312
|
await ensureDir(".sequant/logs");
|
|
246
313
|
await ensureDir("scripts/dev");
|
|
314
|
+
dirSpinner.succeed("Created directories");
|
|
247
315
|
// Update .gitignore
|
|
248
316
|
const gitignoreUpdated = await updateGitignore();
|
|
249
317
|
if (gitignoreUpdated) {
|
|
250
|
-
|
|
318
|
+
ui.printStatus("success", "Updated .gitignore with Sequant entries");
|
|
251
319
|
}
|
|
252
320
|
// Save config with tokens
|
|
253
|
-
|
|
321
|
+
const configSpinner = ui.spinner("Saving configuration...");
|
|
322
|
+
configSpinner.start();
|
|
254
323
|
const pmConfig = packageManager
|
|
255
324
|
? getPackageManagerCommands(packageManager)
|
|
256
325
|
: getPackageManagerCommands("npm");
|
|
@@ -263,18 +332,33 @@ export async function initCommand(options) {
|
|
|
263
332
|
stack: stack,
|
|
264
333
|
initialized: new Date().toISOString(),
|
|
265
334
|
});
|
|
335
|
+
configSpinner.succeed("Saved configuration");
|
|
336
|
+
// Save multi-stack configuration if additional stacks selected
|
|
337
|
+
if (additionalStacks.length > 0) {
|
|
338
|
+
const stackConfig = {
|
|
339
|
+
primary: { name: stack },
|
|
340
|
+
additional: additionalStacks.map((name) => ({ name })),
|
|
341
|
+
};
|
|
342
|
+
await saveStackConfig(stackConfig);
|
|
343
|
+
console.log(chalk.blue("📋 Saved multi-stack configuration"));
|
|
344
|
+
}
|
|
266
345
|
// Create default settings
|
|
267
|
-
|
|
346
|
+
const settingsSpinner = ui.spinner("Creating default settings...");
|
|
347
|
+
settingsSpinner.start();
|
|
268
348
|
await createDefaultSettings();
|
|
349
|
+
settingsSpinner.succeed("Created default settings");
|
|
269
350
|
// Copy templates (with symlinks for scripts unless --no-symlinks)
|
|
270
|
-
|
|
351
|
+
const templatesSpinner = ui.spinner("Copying templates...");
|
|
352
|
+
templatesSpinner.start();
|
|
271
353
|
const { scriptsSymlinked, symlinkResults } = await copyTemplates(stack, tokens, {
|
|
272
354
|
noSymlinks: options.noSymlinks,
|
|
273
355
|
force: options.force,
|
|
356
|
+
additionalStacks,
|
|
274
357
|
});
|
|
358
|
+
templatesSpinner.succeed("Copied templates");
|
|
275
359
|
// Report symlink status
|
|
276
360
|
if (scriptsSymlinked) {
|
|
277
|
-
|
|
361
|
+
ui.printStatus("success", "Created symlinks for scripts/dev/");
|
|
278
362
|
}
|
|
279
363
|
else if (!options.noSymlinks && symlinkResults) {
|
|
280
364
|
// Some symlinks may have fallen back to copies
|
|
@@ -294,8 +378,10 @@ export async function initCommand(options) {
|
|
|
294
378
|
}
|
|
295
379
|
}
|
|
296
380
|
// Create manifest
|
|
297
|
-
|
|
381
|
+
const manifestSpinner = ui.spinner("Creating manifest...");
|
|
382
|
+
manifestSpinner.start();
|
|
298
383
|
await createManifest(stack, packageManager ?? undefined);
|
|
384
|
+
manifestSpinner.succeed("Created manifest");
|
|
299
385
|
// Build optional suggestions section
|
|
300
386
|
const optionalSuggestions = suggestions.filter((s) => s.startsWith("Optional"));
|
|
301
387
|
const optionalSection = optionalSuggestions.length > 0
|
|
@@ -306,19 +392,20 @@ export async function initCommand(options) {
|
|
|
306
392
|
const prereqReminder = hasRemainingIssues
|
|
307
393
|
? `\n${chalk.yellow("⚠️ Remember to install missing dependencies before using issue workflows.")}\n${chalk.gray(" Run 'sequant doctor' to verify your setup.\n")}`
|
|
308
394
|
: "";
|
|
309
|
-
// Success message
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
${chalk.bold("Next steps:")}
|
|
314
|
-
1. Review .claude/memory/constitution.md and customize for your project
|
|
315
|
-
2. Start using workflow commands in Claude Code:
|
|
395
|
+
// Success message with boxed output
|
|
396
|
+
const nextStepsContent = `${chalk.bold("Next steps:")}
|
|
397
|
+
1. Review .claude/memory/constitution.md
|
|
398
|
+
2. Start using workflow commands:
|
|
316
399
|
|
|
317
|
-
${chalk.cyan("/spec 123")}
|
|
318
|
-
${chalk.cyan("/exec 123")}
|
|
319
|
-
${chalk.cyan("/qa 123")}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
400
|
+
${chalk.cyan("/spec 123")} - Plan implementation
|
|
401
|
+
${chalk.cyan("/exec 123")} - Implement the feature
|
|
402
|
+
${chalk.cyan("/qa 123")} - Quality review`;
|
|
403
|
+
console.log("\n" + ui.successBox("Sequant initialized successfully!", nextStepsContent));
|
|
404
|
+
if (prereqReminder) {
|
|
405
|
+
console.log(prereqReminder);
|
|
406
|
+
}
|
|
407
|
+
if (optionalSection) {
|
|
408
|
+
console.log(optionalSection);
|
|
409
|
+
}
|
|
410
|
+
console.log(chalk.gray("\nDocumentation: https://github.com/admarble/sequant#readme\n"));
|
|
324
411
|
}
|
|
@@ -7,6 +7,7 @@ import chalk from "chalk";
|
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import * as os from "os";
|
|
10
|
+
import { ui, colors } from "../lib/cli-ui.js";
|
|
10
11
|
import { RunLogSchema, LOG_PATHS, } from "../lib/workflow/run-log-schema.js";
|
|
11
12
|
import { manualRotate, getLogStats, formatBytes, } from "../lib/workflow/log-rotation.js";
|
|
12
13
|
import { getSettings } from "../lib/settings.js";
|
|
@@ -177,17 +178,17 @@ export async function logsCommand(options) {
|
|
|
177
178
|
await handleRotation(logDir, options.dryRun ?? false);
|
|
178
179
|
return;
|
|
179
180
|
}
|
|
180
|
-
console.log(
|
|
181
|
-
console.log(
|
|
181
|
+
console.log(ui.headerBox("SEQUANT RUN LOGS"));
|
|
182
|
+
console.log(colors.muted(`\n Log directory: ${logDir}`));
|
|
182
183
|
// List log files
|
|
183
184
|
const logFiles = listLogFiles(logDir);
|
|
184
185
|
if (logFiles.length === 0) {
|
|
185
|
-
console.log(
|
|
186
|
-
console.log(
|
|
186
|
+
console.log(colors.warning("\n No logs found."));
|
|
187
|
+
console.log(colors.muted(" Run `npx sequant run <issues>` to generate logs."));
|
|
187
188
|
console.log("");
|
|
188
189
|
return;
|
|
189
190
|
}
|
|
190
|
-
console.log(
|
|
191
|
+
console.log(colors.muted(` Found ${logFiles.length} log file(s)\n`));
|
|
191
192
|
// Parse all logs
|
|
192
193
|
const logs = logFiles
|
|
193
194
|
.map((filename) => {
|
|
@@ -215,7 +216,7 @@ export async function logsCommand(options) {
|
|
|
215
216
|
displayLogSummary(log, filename);
|
|
216
217
|
}
|
|
217
218
|
// Summary
|
|
218
|
-
console.log(
|
|
219
|
+
console.log("\n" + ui.divider());
|
|
219
220
|
const totalPassed = filteredLogs.reduce((sum, { log }) => sum + log.summary.passed, 0);
|
|
220
221
|
const totalFailed = filteredLogs.reduce((sum, { log }) => sum + log.summary.failed, 0);
|
|
221
222
|
const totalDuration = filteredLogs.reduce((sum, { log }) => sum + log.summary.totalDurationSeconds, 0);
|
|
@@ -4,7 +4,19 @@
|
|
|
4
4
|
* Runs the Sequant workflow (/spec → /exec → /qa) for one or more issues
|
|
5
5
|
* using the Claude Agent SDK for proper skill invocation.
|
|
6
6
|
*/
|
|
7
|
-
import { Phase } from "../lib/workflow/types.js";
|
|
7
|
+
import { Phase, QaVerdict } from "../lib/workflow/types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Parse QA verdict from phase output
|
|
10
|
+
*
|
|
11
|
+
* Looks for verdict patterns in the QA output:
|
|
12
|
+
* - "### Verdict: READY_FOR_MERGE"
|
|
13
|
+
* - "**Verdict:** AC_NOT_MET"
|
|
14
|
+
* - "Verdict: AC_MET_BUT_NOT_A_PLUS"
|
|
15
|
+
*
|
|
16
|
+
* @param output - The captured output from QA phase
|
|
17
|
+
* @returns The parsed verdict or null if not found
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseQaVerdict(output: string): QaVerdict | null;
|
|
8
20
|
/**
|
|
9
21
|
* List all active worktrees with their branches
|
|
10
22
|
*/
|