sequant 1.15.1 → 1.15.2
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 +4 -4
- package/.claude-plugin/plugin.json +3 -3
- package/README.md +3 -3
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/run.js +66 -8
- package/dist/src/lib/upstream/issues.js +5 -5
- package/dist/src/lib/workflow/run-log-schema.d.ts +4 -0
- package/dist/src/lib/workflow/run-log-schema.js +4 -0
- package/package.json +4 -4
- package/templates/skills/qa/SKILL.md +66 -1
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"name": "sequant",
|
|
4
4
|
"description": "Sequant plugin marketplace - structured workflow system for Claude Code",
|
|
5
5
|
"owner": {
|
|
6
|
-
"name": "
|
|
7
|
-
"email": "
|
|
6
|
+
"name": "sequant-io",
|
|
7
|
+
"email": "hello@sequant.io"
|
|
8
8
|
},
|
|
9
9
|
"plugins": [
|
|
10
10
|
{
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"description": "Structured workflow system for Claude Code - GitHub issue resolution with spec, exec, test, and QA phases. Includes 16 skills for planning, implementation, testing, code review, and quality assurance.",
|
|
13
13
|
"version": "1.13.0",
|
|
14
14
|
"author": {
|
|
15
|
-
"name": "
|
|
16
|
-
"email": "
|
|
15
|
+
"name": "sequant-io",
|
|
16
|
+
"email": "hello@sequant.io"
|
|
17
17
|
},
|
|
18
18
|
"source": "./",
|
|
19
19
|
"category": "workflow"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sequant",
|
|
3
3
|
"description": "Structured workflow system for Claude Code - GitHub issue resolution with spec, exec, test, and QA phases",
|
|
4
|
-
"version": "1.15.
|
|
4
|
+
"version": "1.15.2",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
7
|
-
"email": "
|
|
6
|
+
"name": "sequant-io",
|
|
7
|
+
"email": "hello@sequant.io"
|
|
8
8
|
}
|
|
9
9
|
}
|
package/README.md
CHANGED
|
@@ -238,9 +238,9 @@ Stack guides: [Next.js](docs/stacks/nextjs.md) · [Rust](docs/stacks/rust.md) ·
|
|
|
238
238
|
|
|
239
239
|
### Reporting Issues
|
|
240
240
|
|
|
241
|
-
- **Bug reports:** [Bug template](https://github.com/
|
|
242
|
-
- **Feature requests:** [Feature template](https://github.com/
|
|
243
|
-
- **Questions:** [GitHub Discussions](https://github.com/
|
|
241
|
+
- **Bug reports:** [Bug template](https://github.com/sequant-io/sequant/issues/new?template=bug.yml)
|
|
242
|
+
- **Feature requests:** [Feature template](https://github.com/sequant-io/sequant/issues/new?template=feature.yml)
|
|
243
|
+
- **Questions:** [GitHub Discussions](https://github.com/sequant-io/sequant/discussions)
|
|
244
244
|
|
|
245
245
|
### Using `/improve` for Feedback
|
|
246
246
|
|
|
@@ -407,5 +407,5 @@ export async function initCommand(options) {
|
|
|
407
407
|
if (optionalSection) {
|
|
408
408
|
console.log(optionalSection);
|
|
409
409
|
}
|
|
410
|
-
console.log(chalk.gray("\nDocumentation: https://github.com/
|
|
410
|
+
console.log(chalk.gray("\nDocumentation: https://github.com/sequant-io/sequant#readme\n"));
|
|
411
411
|
}
|
package/dist/src/commands/run.js
CHANGED
|
@@ -201,6 +201,47 @@ async function ensureWorktree(issueNumber, title, verbose, packageManager, baseB
|
|
|
201
201
|
if (verbose) {
|
|
202
202
|
console.log(chalk.gray(` 📂 Reusing existing worktree: ${existingPath}`));
|
|
203
203
|
}
|
|
204
|
+
// In chain mode, rebase existing worktree onto previous chain link
|
|
205
|
+
if (chainMode && baseBranch) {
|
|
206
|
+
if (verbose) {
|
|
207
|
+
console.log(chalk.gray(` 🔄 Rebasing existing worktree onto chain base (${baseBranch})...`));
|
|
208
|
+
}
|
|
209
|
+
const rebaseResult = spawnSync("git", ["-C", existingPath, "rebase", baseBranch], { stdio: "pipe" });
|
|
210
|
+
if (rebaseResult.status !== 0) {
|
|
211
|
+
const rebaseError = rebaseResult.stderr.toString();
|
|
212
|
+
// Check if it's a conflict
|
|
213
|
+
if (rebaseError.includes("CONFLICT") ||
|
|
214
|
+
rebaseError.includes("could not apply")) {
|
|
215
|
+
console.log(chalk.yellow(` ⚠️ Rebase conflict detected. Aborting rebase and keeping original branch state.`));
|
|
216
|
+
console.log(chalk.yellow(` ℹ️ Branch ${branch} is not properly chained. Manual rebase may be required.`));
|
|
217
|
+
// Abort the rebase to restore branch state
|
|
218
|
+
spawnSync("git", ["-C", existingPath, "rebase", "--abort"], {
|
|
219
|
+
stdio: "pipe",
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
console.log(chalk.yellow(` ⚠️ Rebase failed: ${rebaseError.trim()}`));
|
|
224
|
+
console.log(chalk.yellow(` ℹ️ Continuing with branch in its original state.`));
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
issue: issueNumber,
|
|
228
|
+
path: existingPath,
|
|
229
|
+
branch,
|
|
230
|
+
existed: true,
|
|
231
|
+
rebased: false,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (verbose) {
|
|
235
|
+
console.log(chalk.green(` ✅ Existing worktree rebased onto ${baseBranch}`));
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
issue: issueNumber,
|
|
239
|
+
path: existingPath,
|
|
240
|
+
branch,
|
|
241
|
+
existed: true,
|
|
242
|
+
rebased: true,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
204
245
|
return {
|
|
205
246
|
issue: issueNumber,
|
|
206
247
|
path: existingPath,
|
|
@@ -444,9 +485,7 @@ export function createCheckpointCommit(worktreePath, issueNumber, verbose) {
|
|
|
444
485
|
const commitMessage = `checkpoint(#${issueNumber}): QA passed
|
|
445
486
|
|
|
446
487
|
This is an automatic checkpoint commit created after issue #${issueNumber}
|
|
447
|
-
passed QA in chain mode. It serves as a recovery point if later issues fail
|
|
448
|
-
|
|
449
|
-
Co-Authored-By: Sequant <noreply@sequant.dev>`;
|
|
488
|
+
passed QA in chain mode. It serves as a recovery point if later issues fail.`;
|
|
450
489
|
const commitResult = spawnSync("git", ["-C", worktreePath, "commit", "-m", commitMessage], { stdio: "pipe" });
|
|
451
490
|
if (commitResult.status !== 0) {
|
|
452
491
|
const error = commitResult.stderr.toString();
|
|
@@ -671,6 +710,11 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
671
710
|
// Get MCP servers config if enabled
|
|
672
711
|
// Reads from Claude Desktop config and passes to SDK for headless MCP support
|
|
673
712
|
const mcpServers = config.mcp ? getMcpServersConfig() : undefined;
|
|
713
|
+
// Track whether we're actively streaming verbose output
|
|
714
|
+
// Pausing spinner once per streaming session prevents truncation from rapid pause/resume cycles
|
|
715
|
+
// (Issue #283: ora's stop() clears the current line, which can truncate output when
|
|
716
|
+
// pause/resume is called for every chunk in rapid succession)
|
|
717
|
+
let verboseStreamingActive = false;
|
|
674
718
|
const queryInstance = query({
|
|
675
719
|
prompt,
|
|
676
720
|
options: {
|
|
@@ -693,10 +737,14 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
693
737
|
// Capture stderr for debugging (helps diagnose early exit failures)
|
|
694
738
|
stderr: (data) => {
|
|
695
739
|
capturedStderr += data;
|
|
740
|
+
// Write stderr in verbose mode
|
|
696
741
|
if (config.verbose) {
|
|
697
|
-
spinner
|
|
742
|
+
// Pause spinner once to avoid truncation (Issue #283)
|
|
743
|
+
if (!verboseStreamingActive) {
|
|
744
|
+
spinner?.pause();
|
|
745
|
+
verboseStreamingActive = true;
|
|
746
|
+
}
|
|
698
747
|
process.stderr.write(chalk.red(data));
|
|
699
|
-
spinner?.resume();
|
|
700
748
|
}
|
|
701
749
|
},
|
|
702
750
|
},
|
|
@@ -719,10 +767,13 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
719
767
|
capturedOutput += textContent;
|
|
720
768
|
// Show streaming output in verbose mode
|
|
721
769
|
if (config.verbose) {
|
|
722
|
-
// Pause spinner
|
|
723
|
-
|
|
770
|
+
// Pause spinner once at start of streaming to avoid truncation
|
|
771
|
+
// (Issue #283: repeated pause/resume causes ora to clear lines between chunks)
|
|
772
|
+
if (!verboseStreamingActive) {
|
|
773
|
+
spinner?.pause();
|
|
774
|
+
verboseStreamingActive = true;
|
|
775
|
+
}
|
|
724
776
|
process.stdout.write(chalk.gray(textContent));
|
|
725
|
-
spinner?.resume();
|
|
726
777
|
}
|
|
727
778
|
}
|
|
728
779
|
}
|
|
@@ -731,6 +782,11 @@ async function executePhase(issueNumber, phase, config, sessionId, worktreePath,
|
|
|
731
782
|
resultMessage = message;
|
|
732
783
|
}
|
|
733
784
|
}
|
|
785
|
+
// Resume spinner after streaming completes (if we paused it)
|
|
786
|
+
if (verboseStreamingActive) {
|
|
787
|
+
spinner?.resume();
|
|
788
|
+
verboseStreamingActive = false;
|
|
789
|
+
}
|
|
734
790
|
clearTimeout(timeoutId);
|
|
735
791
|
// Clear abort controller from shutdown manager
|
|
736
792
|
if (shutdownManager) {
|
|
@@ -1190,6 +1246,8 @@ export async function runCommand(issues, options) {
|
|
|
1190
1246
|
sequential: config.sequential,
|
|
1191
1247
|
qualityLoop: config.qualityLoop,
|
|
1192
1248
|
maxIterations: config.maxIterations,
|
|
1249
|
+
chain: mergedOptions.chain,
|
|
1250
|
+
qaGate: mergedOptions.qaGate,
|
|
1193
1251
|
};
|
|
1194
1252
|
logWriter = new LogWriter({
|
|
1195
1253
|
logPath: mergedOptions.logPath ?? settings.run.logPath,
|
|
@@ -57,7 +57,7 @@ async function execCommand(command, args) {
|
|
|
57
57
|
/**
|
|
58
58
|
* Check if a similar upstream issue already exists
|
|
59
59
|
*/
|
|
60
|
-
export async function checkForDuplicate(title, owner = "
|
|
60
|
+
export async function checkForDuplicate(title, owner = "sequant-io", repo = "sequant") {
|
|
61
61
|
try {
|
|
62
62
|
validateRepoParams(owner, repo);
|
|
63
63
|
// Search for existing upstream issues with similar title
|
|
@@ -152,7 +152,7 @@ export function isSimilarTitle(title1, title2) {
|
|
|
152
152
|
* Create a GitHub issue using a temporary file for the body
|
|
153
153
|
* This avoids any shell escaping issues with complex markdown content
|
|
154
154
|
*/
|
|
155
|
-
export async function createIssue(params, owner = "
|
|
155
|
+
export async function createIssue(params, owner = "sequant-io", repo = "sequant") {
|
|
156
156
|
validateRepoParams(owner, repo);
|
|
157
157
|
// Write body to a temp file to avoid any escaping issues
|
|
158
158
|
const tempFile = join(tmpdir(), `gh-issue-body-${Date.now()}.md`);
|
|
@@ -193,7 +193,7 @@ export async function createIssue(params, owner = "admarble", repo = "sequant")
|
|
|
193
193
|
/**
|
|
194
194
|
* Add a comment to an existing issue
|
|
195
195
|
*/
|
|
196
|
-
export async function addIssueComment(issueNumber, comment, owner = "
|
|
196
|
+
export async function addIssueComment(issueNumber, comment, owner = "sequant-io", repo = "sequant") {
|
|
197
197
|
validateRepoParams(owner, repo);
|
|
198
198
|
// Validate issue number
|
|
199
199
|
if (!Number.isInteger(issueNumber) || issueNumber < 1) {
|
|
@@ -226,7 +226,7 @@ export async function addIssueComment(issueNumber, comment, owner = "admarble",
|
|
|
226
226
|
/**
|
|
227
227
|
* Create or link an issue for a finding
|
|
228
228
|
*/
|
|
229
|
-
export async function createOrLinkFinding(finding, version, assessmentIssueNumber, dryRun = false, owner = "
|
|
229
|
+
export async function createOrLinkFinding(finding, version, assessmentIssueNumber, dryRun = false, owner = "sequant-io", repo = "sequant") {
|
|
230
230
|
// Generate issue content
|
|
231
231
|
const issueContent = generateFindingIssue(finding, version, assessmentIssueNumber);
|
|
232
232
|
// Check for duplicate
|
|
@@ -254,7 +254,7 @@ export async function createOrLinkFinding(finding, version, assessmentIssueNumbe
|
|
|
254
254
|
/**
|
|
255
255
|
* Create the assessment summary issue
|
|
256
256
|
*/
|
|
257
|
-
export async function createAssessmentIssue(title, body, dryRun = false, owner = "
|
|
257
|
+
export async function createAssessmentIssue(title, body, dryRun = false, owner = "sequant-io", repo = "sequant") {
|
|
258
258
|
if (dryRun) {
|
|
259
259
|
return undefined;
|
|
260
260
|
}
|
|
@@ -157,6 +157,8 @@ export declare const RunConfigSchema: z.ZodObject<{
|
|
|
157
157
|
sequential: z.ZodBoolean;
|
|
158
158
|
qualityLoop: z.ZodBoolean;
|
|
159
159
|
maxIterations: z.ZodNumber;
|
|
160
|
+
chain: z.ZodOptional<z.ZodBoolean>;
|
|
161
|
+
qaGate: z.ZodOptional<z.ZodBoolean>;
|
|
160
162
|
}, z.core.$strip>;
|
|
161
163
|
export type RunConfig = z.infer<typeof RunConfigSchema>;
|
|
162
164
|
/**
|
|
@@ -192,6 +194,8 @@ export declare const RunLogSchema: z.ZodObject<{
|
|
|
192
194
|
sequential: z.ZodBoolean;
|
|
193
195
|
qualityLoop: z.ZodBoolean;
|
|
194
196
|
maxIterations: z.ZodNumber;
|
|
197
|
+
chain: z.ZodOptional<z.ZodBoolean>;
|
|
198
|
+
qaGate: z.ZodOptional<z.ZodBoolean>;
|
|
195
199
|
}, z.core.$strip>;
|
|
196
200
|
issues: z.ZodArray<z.ZodObject<{
|
|
197
201
|
issueNumber: z.ZodNumber;
|
|
@@ -109,6 +109,10 @@ export const RunConfigSchema = z.object({
|
|
|
109
109
|
qualityLoop: z.boolean(),
|
|
110
110
|
/** Maximum iterations for fix loops */
|
|
111
111
|
maxIterations: z.number().int().positive(),
|
|
112
|
+
/** Whether chain mode was enabled (each issue branches from previous) */
|
|
113
|
+
chain: z.boolean().optional(),
|
|
114
|
+
/** Whether QA gate was enabled (chain pauses if QA fails) */
|
|
115
|
+
qaGate: z.boolean().optional(),
|
|
112
116
|
});
|
|
113
117
|
/**
|
|
114
118
|
* Summary statistics for a run
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sequant",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.2",
|
|
4
4
|
"description": "Quantize your development workflow - Sequential AI phases with quality gates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"repository": {
|
|
47
47
|
"type": "git",
|
|
48
|
-
"url": "git+https://github.com/
|
|
48
|
+
"url": "git+https://github.com/sequant-io/sequant.git"
|
|
49
49
|
},
|
|
50
50
|
"bugs": {
|
|
51
|
-
"url": "https://github.com/
|
|
51
|
+
"url": "https://github.com/sequant-io/sequant/issues"
|
|
52
52
|
},
|
|
53
|
-
"homepage": "https://github.com/
|
|
53
|
+
"homepage": "https://github.com/sequant-io/sequant#readme",
|
|
54
54
|
"engines": {
|
|
55
55
|
"node": ">=18.0.0"
|
|
56
56
|
},
|
|
@@ -369,7 +369,7 @@ fi
|
|
|
369
369
|
|
|
370
370
|
**If no verification evidence exists:**
|
|
371
371
|
1. Prompt: "Script changes detected but no execution verification found. Run `/verify <issue> --command \"<test command>\"` before READY_FOR_MERGE verdict."
|
|
372
|
-
2. Do NOT give `READY_FOR_MERGE` verdict until verification is complete
|
|
372
|
+
2. Do NOT give `READY_FOR_MERGE` verdict until verification is complete (unless an approved override applies — see Section 9a)
|
|
373
373
|
3. Verdict should be `AC_MET_BUT_NOT_A_PLUS` with note about missing verification
|
|
374
374
|
|
|
375
375
|
**Why this matters:**
|
|
@@ -389,6 +389,59 @@ fi
|
|
|
389
389
|
/qa 558 # Re-run, now sees verification, can give READY_FOR_MERGE
|
|
390
390
|
```
|
|
391
391
|
|
|
392
|
+
### 9a. Script Verification Override
|
|
393
|
+
|
|
394
|
+
In some cases, `/verify` execution can be safely skipped when script changes are purely cosmetic or have no runtime impact. **Overrides require explicit justification and risk assessment.**
|
|
395
|
+
|
|
396
|
+
**Override Format (REQUIRED when skipping /verify):**
|
|
397
|
+
|
|
398
|
+
```markdown
|
|
399
|
+
### Script Verification Override
|
|
400
|
+
|
|
401
|
+
**Requirement:** `/verify` before READY_FOR_MERGE
|
|
402
|
+
**Override:** Yes
|
|
403
|
+
**Justification:** [One of the approved categories below]
|
|
404
|
+
**Risk Assessment:** [None/Low/Medium]
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Approved Override Categories:**
|
|
408
|
+
|
|
409
|
+
| Category | Example | Risk |
|
|
410
|
+
|----------|---------|------|
|
|
411
|
+
| Syntax-only refactor | `catch (error)` → `catch` | None |
|
|
412
|
+
| Comment/documentation changes | Adding JSDoc, updating comments | None |
|
|
413
|
+
| Type annotation additions | Adding `: string`, `: number` | None |
|
|
414
|
+
| Import reorganization | Sorting imports, removing unused | None |
|
|
415
|
+
| Variable rename (no logic change) | `foo` → `bar` with no behavioral change | Low |
|
|
416
|
+
| Dead code removal | Removing unreachable branches | Low |
|
|
417
|
+
|
|
418
|
+
**NOT Approved for Override (always require /verify):**
|
|
419
|
+
|
|
420
|
+
| Category | Example | Why |
|
|
421
|
+
|----------|---------|-----|
|
|
422
|
+
| Logic changes | Modified conditionals, new branches | Runtime behavior changes |
|
|
423
|
+
| New functionality | Added functions, new exports | Must verify execution |
|
|
424
|
+
| Dependency changes | Updated imports from new packages | May affect runtime |
|
|
425
|
+
| Error handling changes | Modified catch blocks, new try/catch | Failure paths change |
|
|
426
|
+
| Configuration changes | Modified env vars, config parsing | Environment-dependent |
|
|
427
|
+
|
|
428
|
+
**Risk Assessment Definitions:**
|
|
429
|
+
|
|
430
|
+
| Level | Meaning | Criteria |
|
|
431
|
+
|-------|---------|----------|
|
|
432
|
+
| **None** | Zero runtime impact | Change is invisible at runtime (comments, types, syntax) |
|
|
433
|
+
| **Low** | Negligible runtime impact | Change is cosmetic (rename, dead code) with no logical effect |
|
|
434
|
+
| **Medium** | Possible runtime impact | Change touches executable code but appears safe — **should NOT be overridden** |
|
|
435
|
+
|
|
436
|
+
**Override Decision Flow:**
|
|
437
|
+
|
|
438
|
+
1. Check if change matches an approved category → If no, `/verify` is required
|
|
439
|
+
2. Assess risk level → If Medium or higher, `/verify` is required
|
|
440
|
+
3. Document override using the format above in the QA output
|
|
441
|
+
4. Include override in the GitHub issue comment for audit trail
|
|
442
|
+
|
|
443
|
+
**CRITICAL:** When in doubt, run `/verify`. Overrides are for clear-cut cases only. If you need to argue that a change is safe, it probably needs verification.
|
|
444
|
+
|
|
392
445
|
---
|
|
393
446
|
|
|
394
447
|
## Output Verification
|
|
@@ -399,6 +452,7 @@ fi
|
|
|
399
452
|
- [ ] **Verdict** - One of: READY_FOR_MERGE, AC_MET_BUT_NOT_A_PLUS, AC_NOT_MET
|
|
400
453
|
- [ ] **Quality Metrics** - Type issues, deleted tests, files changed, additions/deletions
|
|
401
454
|
- [ ] **Code Review Findings** - Strengths, issues, suggestions
|
|
455
|
+
- [ ] **Script Verification Override** - Included if scripts/CLI modified AND /verify was skipped (with justification and risk assessment)
|
|
402
456
|
- [ ] **Documentation Check** - README/docs updated if feature adds new functionality
|
|
403
457
|
- [ ] **Next Steps** - Clear, actionable recommendations
|
|
404
458
|
|
|
@@ -447,6 +501,17 @@ You MUST include these sections:
|
|
|
447
501
|
|
|
448
502
|
---
|
|
449
503
|
|
|
504
|
+
### Script Verification Override
|
|
505
|
+
|
|
506
|
+
[Include if scripts/CLI modified AND /verify was skipped, otherwise omit this section]
|
|
507
|
+
|
|
508
|
+
**Requirement:** `/verify` before READY_FOR_MERGE
|
|
509
|
+
**Override:** Yes
|
|
510
|
+
**Justification:** [Approved category from Section 9a]
|
|
511
|
+
**Risk Assessment:** [None/Low/Medium]
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
450
515
|
### Verdict: [READY_FOR_MERGE | AC_MET_BUT_NOT_A_PLUS | AC_NOT_MET]
|
|
451
516
|
|
|
452
517
|
[Explanation of verdict]
|