sequant 2.4.0 → 2.6.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.
Files changed (61) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/README.md +125 -163
  4. package/dist/bin/cli.js +26 -3
  5. package/dist/dashboard/server.js +1 -0
  6. package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +2 -2
  7. package/dist/marketplace/external_plugins/sequant/README.md +6 -3
  8. package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +92 -0
  9. package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +18 -9
  10. package/dist/marketplace/external_plugins/sequant/hooks/relay-check.sh +107 -0
  11. package/dist/marketplace/external_plugins/sequant/skills/_shared/references/behavior-rule-detection.md +205 -0
  12. package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +21 -8
  13. package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +302 -86
  14. package/dist/marketplace/external_plugins/sequant/skills/assess/references/predicted-collision-detection.md +109 -0
  15. package/dist/marketplace/external_plugins/sequant/skills/docs/SKILL.md +141 -22
  16. package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +83 -78
  17. package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +377 -137
  18. package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +28 -0
  19. package/dist/marketplace/external_plugins/sequant/skills/merger/SKILL.md +621 -0
  20. package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +741 -232
  21. package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +47 -1
  22. package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +12 -6
  23. package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +217 -964
  24. package/dist/marketplace/external_plugins/sequant/skills/spec/references/parallel-groups.md +7 -0
  25. package/dist/marketplace/external_plugins/sequant/skills/spec/references/quality-checklist.md +75 -0
  26. package/dist/marketplace/external_plugins/sequant/skills/spec/references/recommended-workflow.md +4 -2
  27. package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +0 -27
  28. package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +24 -44
  29. package/dist/src/commands/ready-tui-adapter.d.ts +59 -0
  30. package/dist/src/commands/ready-tui-adapter.js +130 -0
  31. package/dist/src/commands/ready.d.ts +49 -0
  32. package/dist/src/commands/ready.js +243 -0
  33. package/dist/src/commands/run-flags.d.ts +31 -0
  34. package/dist/src/commands/run-flags.js +34 -0
  35. package/dist/src/commands/run.js +7 -1
  36. package/dist/src/commands/status.js +4 -0
  37. package/dist/src/lib/cli-ui/run-renderer.d.ts +7 -1
  38. package/dist/src/lib/cli-ui/run-renderer.js +28 -28
  39. package/dist/src/lib/settings.d.ts +34 -0
  40. package/dist/src/lib/settings.js +23 -1
  41. package/dist/src/lib/workflow/phase-executor.js +17 -2
  42. package/dist/src/lib/workflow/platforms/github.d.ts +6 -0
  43. package/dist/src/lib/workflow/platforms/github.js +17 -0
  44. package/dist/src/lib/workflow/ready-gate.d.ts +155 -0
  45. package/dist/src/lib/workflow/ready-gate.js +374 -0
  46. package/dist/src/lib/workflow/reconcile.js +6 -0
  47. package/dist/src/lib/workflow/state-schema.d.ts +3 -0
  48. package/dist/src/lib/workflow/state-schema.js +1 -0
  49. package/dist/src/lib/workflow/types.d.ts +27 -3
  50. package/dist/src/ui/tui/App.js +8 -2
  51. package/dist/src/ui/tui/IssueBox.js +3 -4
  52. package/dist/src/ui/tui/index.d.ts +13 -4
  53. package/dist/src/ui/tui/index.js +19 -5
  54. package/dist/src/ui/tui/row-cap.d.ts +51 -0
  55. package/dist/src/ui/tui/row-cap.js +76 -0
  56. package/dist/src/ui/tui/teardown.d.ts +20 -0
  57. package/dist/src/ui/tui/teardown.js +29 -0
  58. package/dist/src/ui/tui/theme.d.ts +3 -0
  59. package/dist/src/ui/tui/theme.js +3 -0
  60. package/package.json +19 -8
  61. package/templates/skills/qa/SKILL.md +5 -2
@@ -20,7 +20,7 @@ export function IssueBox({ state, slot, width, now, }) {
20
20
  const displayPhaseN = activePhaseIndex >= 0 ? activePhaseIndex + 1 : doneCount;
21
21
  const total = state.phases.length;
22
22
  const headerTitle = truncateToWidth(`#${state.number} ${state.title}`, Math.max(10, innerWidth - 20));
23
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: border, paddingX: 1, marginBottom: 1, width: width, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: border, children: headerTitle }), _jsxs(Text, { color: DIVIDER_COLOR, children: ["phase ", displayPhaseN, "/", total, " \u2022", " ", _jsx(ElapsedTimer, { startedAt: state.startedAt })] })] }), _jsx(Divider, { width: innerWidth, borderColor: border }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "branch " }), _jsx(Text, { children: truncateToWidth(state.branch, innerWidth - 8) })] }), _jsx(PhaseProgression, { phases: state.phases, borderColor: border }), state.currentPhase?.logPath ? (_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "log " }), _jsx(Text, { children: truncateToWidth(state.currentPhase.logPath, innerWidth - 8) })] })) : null] }), _jsx(Divider, { width: innerWidth, borderColor: border }), _jsx(Box, { flexDirection: "column", children: state.currentPhase ? (_jsxs(_Fragment, { children: [_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "now " }), _jsx(Spinner, { color: border }), _jsxs(Text, { children: [" ", truncateToWidth(state.currentPhase.nowLine, innerWidth - 12)] })] }), _jsx(Box, { children: _jsxs(Text, { color: DIVIDER_COLOR, children: [" └ last activity ", formatSinceActivity(now, state.currentPhase.lastActivityAt)] }) })] })) : (_jsx(Text, { color: DIVIDER_COLOR, children: statusLine(state) })) })] }));
23
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: border, paddingX: 1, marginBottom: 1, width: width, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: border, children: headerTitle }), _jsxs(Text, { color: DIVIDER_COLOR, children: ["phase ", displayPhaseN, "/", total, " \u2022", " ", _jsx(ElapsedTimer, { startedAt: state.startedAt })] })] }), _jsx(Divider, { width: innerWidth }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "branch " }), _jsx(Text, { children: truncateToWidth(state.branch, innerWidth - 8) })] }), _jsx(PhaseProgression, { phases: state.phases, borderColor: border }), state.currentPhase?.logPath ? (_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "log " }), _jsx(Text, { children: truncateToWidth(state.currentPhase.logPath, innerWidth - 8) })] })) : null] }), _jsx(Divider, { width: innerWidth }), _jsx(Box, { flexDirection: "column", children: state.currentPhase ? (_jsxs(_Fragment, { children: [_jsxs(Box, { children: [_jsx(Text, { color: DIVIDER_COLOR, children: "now " }), _jsx(Spinner, { color: border }), _jsxs(Text, { children: [" ", truncateToWidth(state.currentPhase.nowLine, innerWidth - 12)] })] }), _jsx(Box, { children: _jsxs(Text, { color: DIVIDER_COLOR, children: [" └ last activity ", formatSinceActivity(now, state.currentPhase.lastActivityAt)] }) })] })) : (_jsx(Text, { color: DIVIDER_COLOR, children: statusLine(state) })) })] }));
24
24
  }
25
25
  function statusLine(state) {
26
26
  switch (state.status) {
@@ -34,9 +34,8 @@ function statusLine(state) {
34
34
  return "failed";
35
35
  }
36
36
  }
37
- function Divider({ width, borderColor, }) {
38
- const mid = "─".repeat(Math.max(0, width - 2));
39
- return (_jsxs(Text, { children: [_jsx(Text, { color: borderColor, children: "\u251C" }), _jsx(Text, { color: DIVIDER_COLOR, children: mid }), _jsx(Text, { color: borderColor, children: "\u2524" })] }));
37
+ function Divider({ width }) {
38
+ return _jsx(Text, { color: DIVIDER_COLOR, children: "─".repeat(Math.max(0, width)) });
40
39
  }
41
40
  function PhaseProgression({ phases, borderColor, }) {
42
41
  return (_jsxs(Box, { flexWrap: "wrap", children: [_jsx(Text, { color: DIVIDER_COLOR, children: "phases " }), phases.map((p, i) => {
@@ -1,15 +1,24 @@
1
1
  /**
2
2
  * Experimental multi-issue TUI entry point.
3
3
  *
4
- * Mounts an `ink` app that polls `RunOrchestrator.getSnapshot()` at 10 Hz.
5
- * Unmounts when the orchestrator reports `done` so the shell returns
4
+ * Mounts an `ink` app that polls a snapshot provider's `getSnapshot()` at
5
+ * 10 Hz. Unmounts when the snapshot reports `done` so the shell returns
6
6
  * cleanly. Only safe to call when `process.stdout.isTTY` is true.
7
+ *
8
+ * The provider is structural (`{ getSnapshot(): RunSnapshot }`) so any source
9
+ * of run state can drive the TUI — `RunOrchestrator` for `sequant run`, or the
10
+ * single-issue adapter `sequant ready` owns (#699). The TUI only ever reads
11
+ * `getSnapshot()`, never the orchestrator's batch lifecycle.
7
12
  */
8
- import type { RunOrchestrator } from "../../lib/workflow/run-orchestrator.js";
13
+ import type { RunSnapshot } from "../../lib/workflow/run-state.js";
14
+ /** Minimal structural contract the TUI needs from its state source. */
15
+ export interface SnapshotProvider {
16
+ getSnapshot(): RunSnapshot;
17
+ }
9
18
  export interface TuiHandle {
10
19
  /** Promise that resolves when the TUI unmounts. */
11
20
  done: Promise<void>;
12
21
  /** Force-unmount (e.g., on SIGINT fallback). */
13
22
  unmount: () => void;
14
23
  }
15
- export declare function renderTui(orchestrator: RunOrchestrator): TuiHandle;
24
+ export declare function renderTui(provider: SnapshotProvider): TuiHandle;
@@ -1,25 +1,39 @@
1
1
  /**
2
2
  * Experimental multi-issue TUI entry point.
3
3
  *
4
- * Mounts an `ink` app that polls `RunOrchestrator.getSnapshot()` at 10 Hz.
5
- * Unmounts when the orchestrator reports `done` so the shell returns
4
+ * Mounts an `ink` app that polls a snapshot provider's `getSnapshot()` at
5
+ * 10 Hz. Unmounts when the snapshot reports `done` so the shell returns
6
6
  * cleanly. Only safe to call when `process.stdout.isTTY` is true.
7
+ *
8
+ * The provider is structural (`{ getSnapshot(): RunSnapshot }`) so any source
9
+ * of run state can drive the TUI — `RunOrchestrator` for `sequant run`, or the
10
+ * single-issue adapter `sequant ready` owns (#699). The TUI only ever reads
11
+ * `getSnapshot()`, never the orchestrator's batch lifecycle.
7
12
  */
8
13
  import { createElement } from "react";
9
14
  import { render } from "ink";
10
15
  import { App } from "./App.js";
11
- export function renderTui(orchestrator) {
16
+ import { composeTeardownSummary } from "./teardown.js";
17
+ export function renderTui(provider) {
12
18
  let resolveDone;
13
19
  const done = new Promise((resolve) => {
14
20
  resolveDone = resolve;
15
21
  });
16
22
  const instance = render(createElement(App, {
17
- getSnapshot: () => orchestrator.getSnapshot(),
23
+ getSnapshot: () => provider.getSnapshot(),
18
24
  onDone: () => {
19
25
  instance.unmount();
20
26
  },
21
27
  }), { exitOnCtrlC: false });
22
- instance.waitUntilExit().then(() => resolveDone());
28
+ instance.waitUntilExit().then(() => {
29
+ // #699 AC-5: ink leaves no per-issue history on unmount, so write a durable
30
+ // `✔/✘` transcript from the final snapshot into scrollback. Runs before
31
+ // `done` resolves so the caller's own report (e.g. `ready`'s) prints after.
32
+ const summary = composeTeardownSummary(provider.getSnapshot());
33
+ if (summary)
34
+ process.stdout.write(summary + "\n");
35
+ resolveDone();
36
+ });
23
37
  return {
24
38
  done,
25
39
  unmount: () => {
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Row cap + frame-height clamp for the Ink TUI (#699 AC-4).
3
+ *
4
+ * Parity with the plain renderer's #624 behavior (`run-renderer.ts`
5
+ * `applyRowCap` / `effectiveRowCap`): N issues must never render more boxes
6
+ * than the terminal can hold. Keep every active (queued/running) issue, fill
7
+ * the remaining slots with the most-recently-completed issues, and roll older
8
+ * completed issues into a single `✔ N done` summary line.
9
+ *
10
+ * The TUI difference is vertical density: each plain-grid issue is ~3 lines,
11
+ * but a full Ink box is ~9–11 lines (round border + 3 cells + 2 dividers +
12
+ * bottom margin). `LINES_PER_BOX` is sized accordingly so the dynamic cap
13
+ * reflects how many boxes actually fit.
14
+ */
15
+ import type { IssueRuntimeState } from "../../lib/workflow/run-state.js";
16
+ /** Static row cap (matches the plain renderer's default). */
17
+ export declare const DEFAULT_TUI_ROW_CAP = 10;
18
+ /**
19
+ * Approximate height of one rendered Ink box, in terminal rows: round border
20
+ * top/bottom (2) + header (1) + two dividers (2) + context cell (~3) +
21
+ * activity cell (~2) + bottom margin (1) ≈ 11.
22
+ */
23
+ export declare const TUI_LINES_PER_BOX = 11;
24
+ /**
25
+ * Effective cap: the smaller of the static cap and a dynamic terminal-height
26
+ * ceiling. Mirrors `run-renderer.ts` `effectiveRowCap`, but with a box-height
27
+ * `linesPerBox` rather than the plain grid's 3.
28
+ *
29
+ * When `rows` is unknown (no TTY size), trust the static cap directly rather
30
+ * than guessing a height — the same "don't over-clamp" intent as the plain
31
+ * renderer's tall default, without picking an arbitrary fallback row count.
32
+ *
33
+ * @internal Exported for testing.
34
+ */
35
+ export declare function effectiveTuiRowCap(rows: number | undefined, staticCap?: number, linesPerBox?: number): number;
36
+ export interface VisibleSelection {
37
+ /** Boxes to render, in order: active issues first, then recent done. */
38
+ visible: IssueRuntimeState[];
39
+ /** Older completed issues collapsed into the `✔ N done` summary (0 if none). */
40
+ rolledUpDoneCount: number;
41
+ }
42
+ /**
43
+ * Select which issue boxes to render so the frame never exceeds the terminal
44
+ * height. Parity with `run-renderer.ts` `applyRowCap`.
45
+ *
46
+ * - Under the cap → render everything, no rollup.
47
+ * - Over the cap → keep all active issues; fill remaining slots (minus one
48
+ * reserved for the rollup line) with the most-recently-completed issues;
49
+ * the rest roll up into `rolledUpDoneCount`.
50
+ */
51
+ export declare function selectVisibleIssues(issues: IssueRuntimeState[], rows: number | undefined, staticCap?: number, linesPerBox?: number): VisibleSelection;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Row cap + frame-height clamp for the Ink TUI (#699 AC-4).
3
+ *
4
+ * Parity with the plain renderer's #624 behavior (`run-renderer.ts`
5
+ * `applyRowCap` / `effectiveRowCap`): N issues must never render more boxes
6
+ * than the terminal can hold. Keep every active (queued/running) issue, fill
7
+ * the remaining slots with the most-recently-completed issues, and roll older
8
+ * completed issues into a single `✔ N done` summary line.
9
+ *
10
+ * The TUI difference is vertical density: each plain-grid issue is ~3 lines,
11
+ * but a full Ink box is ~9–11 lines (round border + 3 cells + 2 dividers +
12
+ * bottom margin). `LINES_PER_BOX` is sized accordingly so the dynamic cap
13
+ * reflects how many boxes actually fit.
14
+ */
15
+ /** Static row cap (matches the plain renderer's default). */
16
+ export const DEFAULT_TUI_ROW_CAP = 10;
17
+ /**
18
+ * Approximate height of one rendered Ink box, in terminal rows: round border
19
+ * top/bottom (2) + header (1) + two dividers (2) + context cell (~3) +
20
+ * activity cell (~2) + bottom margin (1) ≈ 11.
21
+ */
22
+ export const TUI_LINES_PER_BOX = 11;
23
+ /**
24
+ * Fixed vertical overhead outside the issue boxes: the Header block plus the
25
+ * rolled-up `✔ N done` summary line.
26
+ */
27
+ const FIXED_OVERHEAD = 4;
28
+ /** A queued or running issue is "active"; passed/failed are terminal. */
29
+ function isActive(issue) {
30
+ return issue.status === "queued" || issue.status === "running";
31
+ }
32
+ /**
33
+ * Effective cap: the smaller of the static cap and a dynamic terminal-height
34
+ * ceiling. Mirrors `run-renderer.ts` `effectiveRowCap`, but with a box-height
35
+ * `linesPerBox` rather than the plain grid's 3.
36
+ *
37
+ * When `rows` is unknown (no TTY size), trust the static cap directly rather
38
+ * than guessing a height — the same "don't over-clamp" intent as the plain
39
+ * renderer's tall default, without picking an arbitrary fallback row count.
40
+ *
41
+ * @internal Exported for testing.
42
+ */
43
+ export function effectiveTuiRowCap(rows, staticCap = DEFAULT_TUI_ROW_CAP, linesPerBox = TUI_LINES_PER_BOX) {
44
+ if (!rows || rows <= 0)
45
+ return staticCap;
46
+ const dynamicCap = Math.max(1, Math.floor((rows - FIXED_OVERHEAD) / Math.max(1, linesPerBox)));
47
+ return Math.min(staticCap, dynamicCap);
48
+ }
49
+ /**
50
+ * Select which issue boxes to render so the frame never exceeds the terminal
51
+ * height. Parity with `run-renderer.ts` `applyRowCap`.
52
+ *
53
+ * - Under the cap → render everything, no rollup.
54
+ * - Over the cap → keep all active issues; fill remaining slots (minus one
55
+ * reserved for the rollup line) with the most-recently-completed issues;
56
+ * the rest roll up into `rolledUpDoneCount`.
57
+ */
58
+ export function selectVisibleIssues(issues, rows, staticCap = DEFAULT_TUI_ROW_CAP, linesPerBox = TUI_LINES_PER_BOX) {
59
+ const cap = effectiveTuiRowCap(rows, staticCap, linesPerBox);
60
+ if (issues.length <= cap) {
61
+ return { visible: issues, rolledUpDoneCount: 0 };
62
+ }
63
+ const active = issues.filter(isActive);
64
+ const done = issues
65
+ .filter((i) => !isActive(i))
66
+ .sort((a, b) => (b.completedAt?.getTime() ?? 0) - (a.completedAt?.getTime() ?? 0));
67
+ // Reserve one slot for the rollup line; the rest go to visible boxes.
68
+ const visibleSlots = Math.max(1, cap - 1);
69
+ const remainingForDone = Math.max(0, visibleSlots - active.length);
70
+ const visibleDone = done.slice(0, remainingForDone);
71
+ const rolledUpDoneCount = done.length - visibleDone.length;
72
+ return {
73
+ visible: [...active, ...visibleDone],
74
+ rolledUpDoneCount,
75
+ };
76
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Durable teardown summary for the Ink TUI (#699 AC-5).
3
+ *
4
+ * Ink repaints a live region in place; unlike the plain renderer it appends no
5
+ * per-issue `✔/✘` history when it unmounts. So on teardown we compose a compact
6
+ * transcript line per issue from the final snapshot and write it to stdout
7
+ * (outside ink's managed region) so a completed run leaves a record in
8
+ * scrollback. Emitting it here in the shared entry point means both `run` and
9
+ * `sequant ready` inherit it.
10
+ */
11
+ import type { RunSnapshot } from "../../lib/workflow/run-state.js";
12
+ /**
13
+ * Compose the durable teardown summary from a final snapshot.
14
+ *
15
+ * Returns a newline-joined block of one line per issue, or an empty string when
16
+ * there are no issues (nothing to record).
17
+ *
18
+ * @internal Exported for testing.
19
+ */
20
+ export declare function composeTeardownSummary(snapshot: RunSnapshot): string;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Durable teardown summary for the Ink TUI (#699 AC-5).
3
+ *
4
+ * Ink repaints a live region in place; unlike the plain renderer it appends no
5
+ * per-issue `✔/✘` history when it unmounts. So on teardown we compose a compact
6
+ * transcript line per issue from the final snapshot and write it to stdout
7
+ * (outside ink's managed region) so a completed run leaves a record in
8
+ * scrollback. Emitting it here in the shared entry point means both `run` and
9
+ * `sequant ready` inherit it.
10
+ */
11
+ /** One transcript line per issue, e.g. `✔ #699 Upgrade ready to the Ink TUI`. */
12
+ function issueLine(issue) {
13
+ const glyph = issue.status === "failed" ? "✘" : "✔";
14
+ const title = issue.title ? ` ${issue.title}` : "";
15
+ return `${glyph} #${issue.number}${title}`;
16
+ }
17
+ /**
18
+ * Compose the durable teardown summary from a final snapshot.
19
+ *
20
+ * Returns a newline-joined block of one line per issue, or an empty string when
21
+ * there are no issues (nothing to record).
22
+ *
23
+ * @internal Exported for testing.
24
+ */
25
+ export function composeTeardownSummary(snapshot) {
26
+ if (!snapshot.issues.length)
27
+ return "";
28
+ return snapshot.issues.map(issueLine).join("\n");
29
+ }
@@ -11,6 +11,9 @@ export declare const BORDER_ROTATION: readonly ["cyan", "magenta", "blue", "yell
11
11
  export type BorderColor = (typeof BORDER_ROTATION)[number] | "green" | "red" | "gray";
12
12
  /** Gray used for horizontal dividers inside each box. */
13
13
  export declare const DIVIDER_COLOR: "gray";
14
+ /** Green used for the rolled-up `✔ N done` summary line (#699, parity with the
15
+ * plain renderer's #624 rollup). */
16
+ export declare const ROLLUP_COLOR: "green";
14
17
  /**
15
18
  * Pick the border color for an issue.
16
19
  * Failed / passed states win over rotation; otherwise rotate by slot.
@@ -9,6 +9,9 @@
9
9
  export const BORDER_ROTATION = ["cyan", "magenta", "blue", "yellow"];
10
10
  /** Gray used for horizontal dividers inside each box. */
11
11
  export const DIVIDER_COLOR = "gray";
12
+ /** Green used for the rolled-up `✔ N done` summary line (#699, parity with the
13
+ * plain renderer's #624 rollup). */
14
+ export const ROLLUP_COLOR = "green";
12
15
  /**
13
16
  * Pick the border color for an issue.
14
17
  * Failed / passed states win over rotation; otherwise rotate by slot.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sequant",
3
- "version": "2.4.0",
4
- "description": "Quantize your development workflow - Sequential AI phases with quality gates",
3
+ "version": "2.6.0",
4
+ "description": "AI coding agent orchestrator resolve GitHub issues end-to-end with isolated git worktrees, quality gates, and an MCP server. Works with Claude Code or Aider.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "sequant": "dist/bin/cli.js"
@@ -34,26 +34,37 @@
34
34
  "prepublishOnly": "npm run build"
35
35
  },
36
36
  "keywords": [
37
- "ai",
38
37
  "claude",
39
38
  "claude-code",
39
+ "claude-code-plugin",
40
40
  "aider",
41
41
  "mcp",
42
+ "mcp-server",
42
43
  "cli",
44
+ "headless",
45
+ "ci",
43
46
  "workflow",
44
47
  "automation",
48
+ "parallel",
45
49
  "coding-agent",
46
- "agent",
50
+ "ai-coding-agent",
51
+ "agent-orchestrator",
52
+ "autonomous-agent",
53
+ "agentic",
47
54
  "github",
48
55
  "github-issues",
56
+ "pull-request",
57
+ "issue-resolution",
58
+ "spec-driven",
59
+ "acceptance-criteria",
60
+ "human-in-the-loop",
61
+ "code-review",
49
62
  "quality-gates",
50
63
  "code-quality",
51
64
  "orchestrator",
65
+ "git-worktree",
52
66
  "developer-tools",
53
- "anthropic",
54
- "llm",
55
- "ai-coding",
56
- "copilot"
67
+ "ai-coding"
57
68
  ],
58
69
  "author": "Sequant Contributors",
59
70
  "license": "MIT",
@@ -48,6 +48,7 @@ When running as part of an orchestrated workflow (e.g., `sequant run` or `/fulls
48
48
  | `SEQUANT_PHASE` | Current phase in the workflow | `qa` |
49
49
  | `SEQUANT_ISSUE` | Issue number being processed | `123` |
50
50
  | `SEQUANT_WORKTREE` | Path to the feature worktree | `/path/to/worktrees/feature/...` |
51
+ | `SEQUANT_FULL_QA` | Force full-weight (standalone) QA pre-flight even under an orchestrator (#683) | `1` |
51
52
 
52
53
  **Behavior when orchestrated (SEQUANT_ORCHESTRATOR is set):**
53
54
 
@@ -57,6 +58,8 @@ When running as part of an orchestrated workflow (e.g., `sequant run` or `/fulls
57
58
  4. **Reduce GitHub comment frequency** - Defer updates to orchestrator
58
59
  5. **Trust git state** - Orchestrator verified branch status
59
60
 
61
+ > **Full-weight override (`SEQUANT_FULL_QA=1`, #683).** When this flag is set (e.g. by `sequant ready`), do NOT take the git-state shortcuts above. Run the **standalone** pre-flight sync check, the stale-branch detection, and the process-state inspection (uncommitted work, divergent/zero-commit branches) even though `SEQUANT_ORCHESTRATOR` is set — this is the deliberate fresh full-weight pass that catches the no-implementation / divergent-branch class. The other orchestrated behaviors (skip issue fetch, reduced GitHub comments) still apply.
62
+
60
63
  **Behavior when standalone (SEQUANT_ORCHESTRATOR is NOT set):**
61
64
 
62
65
  - Perform pre-flight sync check
@@ -230,7 +233,7 @@ If the cache is corrupted or unreadable:
230
233
 
231
234
  ### Pre-flight Sync Check
232
235
 
233
- **Skip this section if `SEQUANT_ORCHESTRATOR` is set** - the orchestrator has already verified sync status.
236
+ **Skip this section if `SEQUANT_ORCHESTRATOR` is set** (the orchestrator has already verified sync status) — **unless `SEQUANT_FULL_QA=1`**, in which case run this check even under an orchestrator (#683).
234
237
 
235
238
  Before starting QA (standalone mode), verify the local branch is in sync with remote:
236
239
 
@@ -251,7 +254,7 @@ git pull origin main # Or merge origin/main if pull fails
251
254
 
252
255
  ### Stale Branch Detection
253
256
 
254
- **Skip this section if `SEQUANT_ORCHESTRATOR` is set** - the orchestrator handles branch freshness checks.
257
+ **Skip this section if `SEQUANT_ORCHESTRATOR` is set** (the orchestrator handles branch freshness checks) — **unless `SEQUANT_FULL_QA=1`**, in which case run the branch-freshness check even under an orchestrator (#683).
255
258
 
256
259
  **Purpose:** Detect when the feature branch is significantly behind main, which can lead to:
257
260
  - QA cycles wasted reviewing code that won't cleanly merge