sequant 2.2.0 → 2.4.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 (156) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +81 -5
  4. package/dist/bin/cli.js +140 -13
  5. package/dist/src/commands/abort.d.ts +36 -0
  6. package/dist/src/commands/abort.js +138 -0
  7. package/dist/src/commands/doctor.d.ts +25 -0
  8. package/dist/src/commands/doctor.js +36 -1
  9. package/dist/src/commands/locks.d.ts +67 -0
  10. package/dist/src/commands/locks.js +290 -0
  11. package/dist/src/commands/merge.js +11 -0
  12. package/dist/src/commands/prompt.d.ts +46 -0
  13. package/dist/src/commands/prompt.js +273 -0
  14. package/dist/src/commands/run-display.d.ts +11 -2
  15. package/dist/src/commands/run-display.js +62 -28
  16. package/dist/src/commands/run-progress.d.ts +42 -0
  17. package/dist/src/commands/run-progress.js +93 -0
  18. package/dist/src/commands/run.js +90 -18
  19. package/dist/src/commands/stats.d.ts +2 -0
  20. package/dist/src/commands/stats.js +94 -8
  21. package/dist/src/commands/status.js +12 -0
  22. package/dist/src/commands/watch.d.ts +18 -0
  23. package/dist/src/commands/watch.js +211 -0
  24. package/dist/src/lib/ac-linter.d.ts +1 -1
  25. package/dist/src/lib/ac-linter.js +81 -0
  26. package/dist/src/lib/assess-collision-detect.d.ts +91 -0
  27. package/dist/src/lib/assess-collision-detect.js +217 -0
  28. package/dist/src/lib/assess-comment-parser.d.ts +59 -1
  29. package/dist/src/lib/assess-comment-parser.js +124 -2
  30. package/dist/src/lib/cli-ui/format.d.ts +19 -0
  31. package/dist/src/lib/cli-ui/format.js +34 -0
  32. package/dist/src/lib/cli-ui/run-renderer-types.d.ts +220 -0
  33. package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
  34. package/dist/src/lib/cli-ui/run-renderer.d.ts +265 -0
  35. package/dist/src/lib/cli-ui/run-renderer.js +1390 -0
  36. package/dist/src/lib/cli-ui/scrollback-harness.d.ts +112 -0
  37. package/dist/src/lib/cli-ui/scrollback-harness.js +294 -0
  38. package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
  39. package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
  40. package/dist/src/lib/locks/index.d.ts +7 -0
  41. package/dist/src/lib/locks/index.js +5 -0
  42. package/dist/src/lib/locks/lock-manager.d.ts +168 -0
  43. package/dist/src/lib/locks/lock-manager.js +433 -0
  44. package/dist/src/lib/locks/types.d.ts +59 -0
  45. package/dist/src/lib/locks/types.js +31 -0
  46. package/dist/src/lib/merge-check/types.js +1 -1
  47. package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
  48. package/dist/src/lib/qa/markdown-only-ci.js +74 -0
  49. package/dist/src/lib/relay/activation.d.ts +60 -0
  50. package/dist/src/lib/relay/activation.js +122 -0
  51. package/dist/src/lib/relay/archive.d.ts +34 -0
  52. package/dist/src/lib/relay/archive.js +112 -0
  53. package/dist/src/lib/relay/frame.d.ts +20 -0
  54. package/dist/src/lib/relay/frame.js +76 -0
  55. package/dist/src/lib/relay/index.d.ts +13 -0
  56. package/dist/src/lib/relay/index.js +13 -0
  57. package/dist/src/lib/relay/paths.d.ts +43 -0
  58. package/dist/src/lib/relay/paths.js +59 -0
  59. package/dist/src/lib/relay/pid.d.ts +34 -0
  60. package/dist/src/lib/relay/pid.js +72 -0
  61. package/dist/src/lib/relay/reader.d.ts +35 -0
  62. package/dist/src/lib/relay/reader.js +115 -0
  63. package/dist/src/lib/relay/types.d.ts +70 -0
  64. package/dist/src/lib/relay/types.js +85 -0
  65. package/dist/src/lib/relay/writer.d.ts +48 -0
  66. package/dist/src/lib/relay/writer.js +113 -0
  67. package/dist/src/lib/settings.d.ts +31 -1
  68. package/dist/src/lib/settings.js +18 -3
  69. package/dist/src/lib/version-check.d.ts +60 -5
  70. package/dist/src/lib/version-check.js +97 -9
  71. package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
  72. package/dist/src/lib/workflow/batch-executor.js +274 -185
  73. package/dist/src/lib/workflow/config-resolver.js +4 -0
  74. package/dist/src/lib/workflow/drivers/agent-driver.d.ts +48 -1
  75. package/dist/src/lib/workflow/drivers/aider.d.ts +7 -1
  76. package/dist/src/lib/workflow/drivers/aider.js +9 -0
  77. package/dist/src/lib/workflow/drivers/claude-code.d.ts +17 -1
  78. package/dist/src/lib/workflow/drivers/claude-code.js +51 -2
  79. package/dist/src/lib/workflow/drivers/index.d.ts +1 -1
  80. package/dist/src/lib/workflow/event-emitter.d.ts +157 -0
  81. package/dist/src/lib/workflow/event-emitter.js +102 -0
  82. package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
  83. package/dist/src/lib/workflow/heartbeat.js +194 -0
  84. package/dist/src/lib/workflow/notice.d.ts +32 -0
  85. package/dist/src/lib/workflow/notice.js +38 -0
  86. package/dist/src/lib/workflow/phase-executor.d.ts +58 -16
  87. package/dist/src/lib/workflow/phase-executor.js +244 -130
  88. package/dist/src/lib/workflow/phase-mapper.d.ts +27 -13
  89. package/dist/src/lib/workflow/phase-mapper.js +70 -51
  90. package/dist/src/lib/workflow/phase-registry.d.ts +127 -0
  91. package/dist/src/lib/workflow/phase-registry.js +233 -0
  92. package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
  93. package/dist/src/lib/workflow/platforms/github.js +20 -3
  94. package/dist/src/lib/workflow/pr-status.d.ts +18 -2
  95. package/dist/src/lib/workflow/pr-status.js +41 -9
  96. package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
  97. package/dist/src/lib/workflow/qa-stagnation.js +179 -0
  98. package/dist/src/lib/workflow/run-log-schema.d.ts +5 -55
  99. package/dist/src/lib/workflow/run-orchestrator.d.ts +70 -1
  100. package/dist/src/lib/workflow/run-orchestrator.js +464 -25
  101. package/dist/src/lib/workflow/run-reflect.js +1 -1
  102. package/dist/src/lib/workflow/run-state.d.ts +71 -0
  103. package/dist/src/lib/workflow/run-state.js +14 -0
  104. package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
  105. package/dist/src/lib/workflow/state-cleanup.js +17 -5
  106. package/dist/src/lib/workflow/state-manager.d.ts +31 -2
  107. package/dist/src/lib/workflow/state-manager.js +64 -1
  108. package/dist/src/lib/workflow/state-schema.d.ts +82 -35
  109. package/dist/src/lib/workflow/state-schema.js +63 -4
  110. package/dist/src/lib/workflow/types.d.ts +139 -16
  111. package/dist/src/lib/workflow/types.js +18 -13
  112. package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
  113. package/dist/src/lib/workflow/worktree-manager.js +15 -6
  114. package/dist/src/mcp/tools/run.d.ts +44 -0
  115. package/dist/src/mcp/tools/run.js +104 -13
  116. package/dist/src/ui/tui/App.d.ts +14 -0
  117. package/dist/src/ui/tui/App.js +41 -0
  118. package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
  119. package/dist/src/ui/tui/ElapsedTimer.js +31 -0
  120. package/dist/src/ui/tui/Header.d.ts +6 -0
  121. package/dist/src/ui/tui/Header.js +15 -0
  122. package/dist/src/ui/tui/IssueBox.d.ts +16 -0
  123. package/dist/src/ui/tui/IssueBox.js +68 -0
  124. package/dist/src/ui/tui/Spinner.d.ts +9 -0
  125. package/dist/src/ui/tui/Spinner.js +18 -0
  126. package/dist/src/ui/tui/index.d.ts +15 -0
  127. package/dist/src/ui/tui/index.js +29 -0
  128. package/dist/src/ui/tui/theme.d.ts +29 -0
  129. package/dist/src/ui/tui/theme.js +52 -0
  130. package/dist/src/ui/tui/truncate.d.ts +11 -0
  131. package/dist/src/ui/tui/truncate.js +31 -0
  132. package/package.json +14 -6
  133. package/templates/agents/sequant-explorer.md +1 -0
  134. package/templates/agents/sequant-qa-checker.md +2 -1
  135. package/templates/agents/sequant-testgen.md +1 -0
  136. package/templates/hooks/post-tool.sh +92 -0
  137. package/templates/hooks/pre-tool.sh +18 -9
  138. package/templates/hooks/relay-check.sh +107 -0
  139. package/templates/relay/frame.txt +11 -0
  140. package/templates/scripts/cleanup-worktree.sh +25 -3
  141. package/templates/scripts/new-feature.sh +6 -0
  142. package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
  143. package/templates/skills/_shared/references/subagent-types.md +21 -8
  144. package/templates/skills/assess/SKILL.md +122 -68
  145. package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
  146. package/templates/skills/docs/SKILL.md +141 -22
  147. package/templates/skills/exec/SKILL.md +10 -8
  148. package/templates/skills/fullsolve/SKILL.md +79 -5
  149. package/templates/skills/loop/SKILL.md +28 -0
  150. package/templates/skills/merger/SKILL.md +621 -0
  151. package/templates/skills/qa/SKILL.md +727 -8
  152. package/templates/skills/setup/SKILL.md +12 -6
  153. package/templates/skills/spec/SKILL.md +52 -0
  154. package/templates/skills/spec/references/parallel-groups.md +7 -0
  155. package/templates/skills/spec/references/recommended-workflow.md +4 -2
  156. package/templates/skills/testgen/SKILL.md +24 -17
@@ -0,0 +1,265 @@
1
+ /**
2
+ * RunRenderer — single coordinator for all `sequant run` stdout output.
3
+ *
4
+ * Replaces the dual-output regression where `PhaseSpinner` (legacy, #244) and
5
+ * the parallel-mode `▸/✔` lines (#458) both wrote to stdout for single-issue
6
+ * runs and produced overwritten / missing-duration lines.
7
+ *
8
+ * Three modes implement the same `RunRenderer` interface:
9
+ * - TTYRenderer: live grid (top, redrawn ~1Hz) + events log (below)
10
+ * - NonTTYRenderer: append-only `[HH:MM:SS]` events + 60s heartbeat
11
+ * - OrchestratorRenderer: no-op when SEQUANT_ORCHESTRATOR is set so MCP's
12
+ * `emitProgressLine` JSON is the only stdout
13
+ *
14
+ * See issue #618.
15
+ */
16
+ import type { PhasePauseHandle } from "../workflow/types.js";
17
+ import type { IssueRegistration, IssueState, ProgressEvent, RenderOptions, RendererMode, RunRenderer, SummaryRenderInput } from "./run-renderer-types.js";
18
+ /**
19
+ * #624 Item 4: normalized failure signature for dedup decisions.
20
+ *
21
+ * Strips ANSI escape sequences, lowercases, trims whitespace, and truncates to
22
+ * the first 80 visible chars. The plan deliberately chose a length-bounded
23
+ * prefix over a crypto hash so debugging can match signatures by eye.
24
+ */
25
+ export declare function failureSignature(error: string | undefined): string;
26
+ /**
27
+ * #624 Item 3 / Derived AC-D2: shared suffix builder used by all three retry
28
+ * sites (NonTTY events log, TTY events log, TTY status header). Centralizes
29
+ * the `(attempt N/M)` / `loop N/M` literals so they cannot drift between paths.
30
+ *
31
+ * `kind` selects the surface:
32
+ * - "events" → events-log line: leading space + parentheses
33
+ * - "header" → status cell: leading space, no parentheses
34
+ *
35
+ * Returns the empty string when the attempt counter does not apply
36
+ * (no iteration, iteration === 1, or non-positive).
37
+ */
38
+ export declare function formatRetrySuffix(iteration: number | undefined, maxIterations: number, kind: "events" | "header"): string;
39
+ declare abstract class BaseRenderer implements RunRenderer, PhasePauseHandle {
40
+ protected readonly issues: Map<number, IssueState>;
41
+ protected readonly stdoutWrite: (s: string) => void;
42
+ protected readonly stderrWrite: (s: string) => void;
43
+ protected readonly now: () => number;
44
+ protected readonly wallClock: () => Date;
45
+ protected readonly noColor: boolean;
46
+ protected readonly runStartedAt: number;
47
+ protected paused: boolean;
48
+ protected disposed: boolean;
49
+ constructor(options: RenderOptions);
50
+ registerIssue(reg: IssueRegistration): void;
51
+ setPhasePlan(issue: number, phases: string[]): void;
52
+ onEvent(event: ProgressEvent): void;
53
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
54
+ pause(): void;
55
+ resume(): void;
56
+ /**
57
+ * #647 AC-3: default notice path — just write to the renderer's stdout
58
+ * channel. NonTTYRenderer keeps this default (no live zone to manage).
59
+ * TTYRenderer overrides to clear the live zone before writing so
60
+ * log-update's cursor model stays consistent with the actual terminal.
61
+ */
62
+ appendNotice(message: string): void;
63
+ abstract renderSummary(input: SummaryRenderInput): void;
64
+ dispose(): void;
65
+ protected applyEvent(state: IssueState, event: ProgressEvent): void;
66
+ /** Mark an issue done after PR is recorded — derived from phase completion. */
67
+ protected maybeMarkIssueDone(state: IssueState): void;
68
+ protected afterEvent(_event: ProgressEvent, state: IssueState): void;
69
+ protected afterStateChange(): void;
70
+ protected onPause(): void;
71
+ protected onResume(): void;
72
+ protected onDispose(): void;
73
+ }
74
+ /**
75
+ * No-op renderer used when `SEQUANT_ORCHESTRATOR` is set.
76
+ *
77
+ * The orchestrator (e.g. MCP server) consumes `emitProgressLine` JSON from
78
+ * batch-executor directly. Rendering anything else from the CLI would be
79
+ * double-emission. We still track state so `renderSummary` could be useful
80
+ * if explicitly invoked, but neither stdout nor stderr is touched.
81
+ */
82
+ export declare class OrchestratorRenderer extends BaseRenderer {
83
+ renderSummary(): void;
84
+ }
85
+ export declare class NonTTYRenderer extends BaseRenderer {
86
+ private heartbeatTimer;
87
+ private readonly heartbeatMs;
88
+ private readonly columnsOverride?;
89
+ private readonly maxLoopIterations;
90
+ private lastEventAt;
91
+ constructor(options: RenderOptions);
92
+ private getColumns;
93
+ private startHeartbeat;
94
+ /** Test hook: drive a heartbeat without waiting on real timers. */
95
+ tickHeartbeatNow(): void;
96
+ private tickHeartbeat;
97
+ protected afterEvent(event: ProgressEvent, state: IssueState): void;
98
+ private emitEventLine;
99
+ /** Append a single `\n`-terminated line with `[HH:MM:SS]` prefix. */
100
+ private emitLine;
101
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
102
+ renderSummary(input: SummaryRenderInput): void;
103
+ protected onDispose(): void;
104
+ }
105
+ /**
106
+ * #624 Derived AC-D1: test-only observability for the log-update stub. Tests
107
+ * can read `replacementCount` and `lastFrame` to verify the frame is *replaced*
108
+ * on each redraw rather than appended — the foundational guarantee that Items
109
+ * 1 and 2 rely on.
110
+ *
111
+ * `clearCalls` / `doneCalls` (added in the hardening pass) let AC-2.2 verify
112
+ * the renderer actually invokes `logUpdate.clear()` + `logUpdate.done()` during
113
+ * `renderSummary` teardown — not just that the stub's local `lastFrame` was
114
+ * reset.
115
+ */
116
+ export interface TTYTestStub {
117
+ /** Number of times the live frame was replaced (not the initial write). */
118
+ readonly replacementCount: number;
119
+ /** The most recent live frame text passed to log-update. */
120
+ readonly lastFrame: string;
121
+ /** Number of times `logUpdate.clear()` was invoked. */
122
+ readonly clearCalls: number;
123
+ /** Number of times `logUpdate.done()` was invoked. */
124
+ readonly doneCalls: number;
125
+ }
126
+ export declare class TTYRenderer extends BaseRenderer {
127
+ private readonly liveTickMs;
128
+ private liveTimer;
129
+ private spinnerFrame;
130
+ private readonly columnsOverride?;
131
+ private readonly rowsOverride?;
132
+ private readonly noSignalListeners;
133
+ private readonly stallThresholdMs;
134
+ private readonly multiIssueRowCap;
135
+ private readonly maxLoopIterations;
136
+ private readonly logUpdateImpl;
137
+ private readonly logUpdateClear;
138
+ private readonly logUpdateDone;
139
+ private resizeListener;
140
+ private banner;
141
+ private readonly _testStub;
142
+ constructor(options: RenderOptions);
143
+ /**
144
+ * #624 Derived AC-D1: expose the test-only log-update stub. Returns `null`
145
+ * when not in test mode (production renders go through real `log-update`).
146
+ *
147
+ * #647 AC-D3 warning: this stub does NOT model `log-update`'s ANSI cursor
148
+ * or scrollback semantics. Tests that assert on `stub.lastFrame` only see
149
+ * the most recent frame, not whether earlier frames remained stranded in
150
+ * scrollback. Header-count / duplicate-header assertions MUST use
151
+ * `scrollback-harness.ts` (real `createLogUpdate` + VirtualTerminal),
152
+ * otherwise they will pass green even when the production rendering is
153
+ * broken — see #624 for the precedent.
154
+ */
155
+ getTestStub(): TTYTestStub | null;
156
+ private startLiveTimer;
157
+ private installSignalListeners;
158
+ /** Test hook: drive a tick without waiting on real timers. */
159
+ tickNow(): void;
160
+ private tick;
161
+ protected afterEvent(event: ProgressEvent, state: IssueState): void;
162
+ protected afterStateChange(): void;
163
+ /** Set a banner that renders above the live grid (e.g. worktree-loss). */
164
+ setBanner(text: string | null): void;
165
+ private appendEventLine;
166
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
167
+ renderSummary(input: SummaryRenderInput): void;
168
+ protected onPause(): void;
169
+ protected onResume(): void;
170
+ /**
171
+ * #647 AC-3: TTYRenderer override. Writes the notice above the live zone
172
+ * the same way `appendEventLine` does (clear → write → redraw), so
173
+ * log-update's `previousLineCount` stays consistent with the actual
174
+ * terminal state. If the renderer is already paused (e.g., during
175
+ * verbose subprocess streaming), skip the clear/redraw and just write;
176
+ * the eventual `resume()` will redraw cleanly.
177
+ */
178
+ appendNotice(message: string): void;
179
+ protected onDispose(): void;
180
+ private getColumns;
181
+ /**
182
+ * #624 Item 1: terminal row count, with a safe default for piped / detached
183
+ * stdout where `process.stdout.rows` is undefined.
184
+ */
185
+ private getRows;
186
+ /**
187
+ * #624 Item 1: hard ceiling on live-zone height. The cap is
188
+ * `max(8, rows - 5)`, dropping to `max(8, rows - 7)` when a banner is active
189
+ * so the banner + a few separator rows still fit. The floor of 8 prevents
190
+ * the live zone from collapsing on tiny terminals.
191
+ */
192
+ private getMaxLiveRows;
193
+ private redraw;
194
+ /** Public for tests — render the live zone to a string without emitting. */
195
+ renderLiveFrame(columns?: number): string;
196
+ /**
197
+ * #624 Item 1 (AC-1.1): hard ceiling on rendered frame height. The interior
198
+ * `applyRowCap` already collapses excess issues into the rollup row, but the
199
+ * frame can still drift over the cap if many issues have multi-line status
200
+ * cells (sub-status + phase sequence). This is the belt-and-braces clamp
201
+ * that guarantees `log-update` never sees a frame taller than the terminal.
202
+ *
203
+ * Always engages — when `rows` isn't explicitly provided, `getRows()` returns
204
+ * `DEFAULT_TERMINAL_ROWS` (100) so the cap is generous but never disengaged.
205
+ */
206
+ private clampFrameHeight;
207
+ private renderNarrowFrame;
208
+ private renderSingleIssueFrame;
209
+ private renderMultiIssueFrame;
210
+ /**
211
+ * AC-28 + #624 Item 1: enforce the per-frame issue row cap, derived from
212
+ * the smaller of `multiIssueRowCap` (static config) and a dynamic ceiling
213
+ * computed from terminal height. The dynamic ceiling reserves ~3 lines per
214
+ * issue (status header + sub-status + separator) and a fixed overhead for
215
+ * the frame header, blank lines, grid borders, and the rollup line.
216
+ *
217
+ * If the cap is not exceeded, returns all issues unchanged. Otherwise: keep
218
+ * all non-done rows, then fill remaining slots with the most recently
219
+ * completed done rows; older done rows roll up into a single summary entry.
220
+ */
221
+ private applyRowCap;
222
+ /**
223
+ * #624 Item 1 (AC-1.1): smaller of the configured static cap and the
224
+ * dynamic terminal-height-derived cap. Each issue row takes roughly 3 grid
225
+ * lines (header, sub-status, separator); the fixed overhead covers the
226
+ * frame title, blank lines, grid borders, and the rollup row.
227
+ *
228
+ * Always engages — when `rows` isn't explicitly provided, `getRows()` returns
229
+ * `DEFAULT_TERMINAL_ROWS` (100) which produces a dynamic cap of ~30, well
230
+ * above the static `multiIssueRowCap` default of 10, so the static cap stays
231
+ * in charge for normal-height terminals.
232
+ */
233
+ private effectiveRowCap;
234
+ private statusHeader;
235
+ private statusSubLines;
236
+ private statusCellLines;
237
+ private runHeader;
238
+ private rollupLine;
239
+ private drawKeyValueTable;
240
+ private drawIssueGrid;
241
+ }
242
+ export interface CreateRendererOptions extends RenderOptions {
243
+ /** Force a specific mode (otherwise auto-detected from env + TTY). */
244
+ mode?: RendererMode;
245
+ }
246
+ /**
247
+ * Create a `RunRenderer` matching the current execution context.
248
+ *
249
+ * Detection order:
250
+ * 1. Explicit `mode` override.
251
+ * 2. `SEQUANT_ORCHESTRATOR` env var → orchestrator (no-op).
252
+ * 3. `process.stdout.isTTY` (or `options.isTTY`) → TTY renderer.
253
+ * 4. Otherwise → non-TTY renderer.
254
+ */
255
+ export declare function createRunRenderer(options?: CreateRendererOptions): RunRenderer;
256
+ /**
257
+ * Public summary helper — used by the legacy displaySummary path so callers
258
+ * that bypass the renderer still get the new grid layout.
259
+ */
260
+ export declare function renderRunSummary(input: SummaryRenderInput, options?: {
261
+ stdoutWrite?: (s: string) => void;
262
+ noColor?: boolean;
263
+ columns?: number;
264
+ }): void;
265
+ export {};