sequant 2.2.0 → 2.3.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 (137) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +73 -0
  4. package/dist/bin/cli.js +94 -9
  5. package/dist/src/commands/doctor.d.ts +25 -0
  6. package/dist/src/commands/doctor.js +36 -1
  7. package/dist/src/commands/locks.d.ts +67 -0
  8. package/dist/src/commands/locks.js +290 -0
  9. package/dist/src/commands/merge.js +11 -0
  10. package/dist/src/commands/prompt.d.ts +39 -0
  11. package/dist/src/commands/prompt.js +179 -0
  12. package/dist/src/commands/run-display.d.ts +11 -2
  13. package/dist/src/commands/run-display.js +62 -28
  14. package/dist/src/commands/run-progress.d.ts +32 -0
  15. package/dist/src/commands/run-progress.js +76 -0
  16. package/dist/src/commands/run.js +80 -18
  17. package/dist/src/commands/stats.d.ts +2 -0
  18. package/dist/src/commands/stats.js +94 -8
  19. package/dist/src/commands/status.js +12 -0
  20. package/dist/src/commands/watch.d.ts +16 -0
  21. package/dist/src/commands/watch.js +147 -0
  22. package/dist/src/lib/ac-linter.d.ts +1 -1
  23. package/dist/src/lib/ac-linter.js +81 -0
  24. package/dist/src/lib/assess-collision-detect.d.ts +91 -0
  25. package/dist/src/lib/assess-collision-detect.js +217 -0
  26. package/dist/src/lib/assess-comment-parser.d.ts +59 -1
  27. package/dist/src/lib/assess-comment-parser.js +124 -2
  28. package/dist/src/lib/cli-ui/format.d.ts +19 -0
  29. package/dist/src/lib/cli-ui/format.js +34 -0
  30. package/dist/src/lib/cli-ui/run-renderer-types.d.ts +181 -0
  31. package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
  32. package/dist/src/lib/cli-ui/run-renderer.d.ts +239 -0
  33. package/dist/src/lib/cli-ui/run-renderer.js +1173 -0
  34. package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
  35. package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
  36. package/dist/src/lib/locks/index.d.ts +7 -0
  37. package/dist/src/lib/locks/index.js +5 -0
  38. package/dist/src/lib/locks/lock-manager.d.ts +168 -0
  39. package/dist/src/lib/locks/lock-manager.js +433 -0
  40. package/dist/src/lib/locks/types.d.ts +59 -0
  41. package/dist/src/lib/locks/types.js +31 -0
  42. package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
  43. package/dist/src/lib/qa/markdown-only-ci.js +74 -0
  44. package/dist/src/lib/relay/activation.d.ts +60 -0
  45. package/dist/src/lib/relay/activation.js +122 -0
  46. package/dist/src/lib/relay/archive.d.ts +34 -0
  47. package/dist/src/lib/relay/archive.js +106 -0
  48. package/dist/src/lib/relay/frame.d.ts +20 -0
  49. package/dist/src/lib/relay/frame.js +76 -0
  50. package/dist/src/lib/relay/index.d.ts +13 -0
  51. package/dist/src/lib/relay/index.js +13 -0
  52. package/dist/src/lib/relay/paths.d.ts +43 -0
  53. package/dist/src/lib/relay/paths.js +59 -0
  54. package/dist/src/lib/relay/pid.d.ts +34 -0
  55. package/dist/src/lib/relay/pid.js +72 -0
  56. package/dist/src/lib/relay/reader.d.ts +35 -0
  57. package/dist/src/lib/relay/reader.js +115 -0
  58. package/dist/src/lib/relay/types.d.ts +68 -0
  59. package/dist/src/lib/relay/types.js +76 -0
  60. package/dist/src/lib/relay/writer.d.ts +48 -0
  61. package/dist/src/lib/relay/writer.js +113 -0
  62. package/dist/src/lib/settings.d.ts +31 -1
  63. package/dist/src/lib/settings.js +18 -3
  64. package/dist/src/lib/version-check.d.ts +60 -5
  65. package/dist/src/lib/version-check.js +97 -9
  66. package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
  67. package/dist/src/lib/workflow/batch-executor.js +248 -175
  68. package/dist/src/lib/workflow/config-resolver.js +4 -0
  69. package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
  70. package/dist/src/lib/workflow/heartbeat.js +194 -0
  71. package/dist/src/lib/workflow/phase-executor.d.ts +62 -8
  72. package/dist/src/lib/workflow/phase-executor.js +157 -16
  73. package/dist/src/lib/workflow/phase-mapper.d.ts +3 -2
  74. package/dist/src/lib/workflow/phase-mapper.js +17 -20
  75. package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
  76. package/dist/src/lib/workflow/platforms/github.js +20 -3
  77. package/dist/src/lib/workflow/pr-status.d.ts +18 -2
  78. package/dist/src/lib/workflow/pr-status.js +41 -9
  79. package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
  80. package/dist/src/lib/workflow/qa-stagnation.js +179 -0
  81. package/dist/src/lib/workflow/run-orchestrator.d.ts +39 -0
  82. package/dist/src/lib/workflow/run-orchestrator.js +340 -15
  83. package/dist/src/lib/workflow/run-reflect.js +1 -1
  84. package/dist/src/lib/workflow/run-state.d.ts +71 -0
  85. package/dist/src/lib/workflow/run-state.js +14 -0
  86. package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
  87. package/dist/src/lib/workflow/state-cleanup.js +17 -5
  88. package/dist/src/lib/workflow/state-manager.d.ts +12 -1
  89. package/dist/src/lib/workflow/state-manager.js +37 -0
  90. package/dist/src/lib/workflow/state-schema.d.ts +62 -0
  91. package/dist/src/lib/workflow/state-schema.js +35 -1
  92. package/dist/src/lib/workflow/types.d.ts +74 -1
  93. package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
  94. package/dist/src/lib/workflow/worktree-manager.js +15 -6
  95. package/dist/src/mcp/tools/run.d.ts +44 -0
  96. package/dist/src/mcp/tools/run.js +104 -13
  97. package/dist/src/ui/tui/App.d.ts +14 -0
  98. package/dist/src/ui/tui/App.js +41 -0
  99. package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
  100. package/dist/src/ui/tui/ElapsedTimer.js +31 -0
  101. package/dist/src/ui/tui/Header.d.ts +6 -0
  102. package/dist/src/ui/tui/Header.js +15 -0
  103. package/dist/src/ui/tui/IssueBox.d.ts +16 -0
  104. package/dist/src/ui/tui/IssueBox.js +68 -0
  105. package/dist/src/ui/tui/Spinner.d.ts +9 -0
  106. package/dist/src/ui/tui/Spinner.js +18 -0
  107. package/dist/src/ui/tui/index.d.ts +15 -0
  108. package/dist/src/ui/tui/index.js +29 -0
  109. package/dist/src/ui/tui/theme.d.ts +29 -0
  110. package/dist/src/ui/tui/theme.js +52 -0
  111. package/dist/src/ui/tui/truncate.d.ts +11 -0
  112. package/dist/src/ui/tui/truncate.js +31 -0
  113. package/package.json +10 -3
  114. package/templates/agents/sequant-explorer.md +1 -0
  115. package/templates/agents/sequant-qa-checker.md +2 -1
  116. package/templates/agents/sequant-testgen.md +1 -0
  117. package/templates/hooks/post-tool.sh +11 -0
  118. package/templates/hooks/pre-tool.sh +18 -9
  119. package/templates/hooks/relay-check.sh +107 -0
  120. package/templates/relay/frame.txt +11 -0
  121. package/templates/scripts/cleanup-worktree.sh +25 -3
  122. package/templates/scripts/new-feature.sh +6 -0
  123. package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
  124. package/templates/skills/_shared/references/subagent-types.md +21 -8
  125. package/templates/skills/assess/SKILL.md +103 -49
  126. package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
  127. package/templates/skills/docs/SKILL.md +141 -22
  128. package/templates/skills/exec/SKILL.md +10 -8
  129. package/templates/skills/fullsolve/SKILL.md +79 -5
  130. package/templates/skills/loop/SKILL.md +28 -0
  131. package/templates/skills/merger/SKILL.md +621 -0
  132. package/templates/skills/qa/SKILL.md +727 -8
  133. package/templates/skills/setup/SKILL.md +6 -0
  134. package/templates/skills/spec/SKILL.md +52 -0
  135. package/templates/skills/spec/references/parallel-groups.md +7 -0
  136. package/templates/skills/spec/references/recommended-workflow.md +4 -2
  137. package/templates/skills/testgen/SKILL.md +24 -17
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Types shared between RunRenderer modes (TTY, non-TTY, orchestrator).
3
+ *
4
+ * The renderer is event-driven: a `ProgressEvent` flows in and the renderer
5
+ * decides whether to update the live zone, append an event line, or both.
6
+ */
7
+ export type ProgressEventKind = "start" | "complete" | "failed";
8
+ /** Raw event from batch-executor `emitProgressLine` / `onProgress` callbacks. */
9
+ export interface ProgressEvent {
10
+ issue: number;
11
+ phase: string;
12
+ event: ProgressEventKind;
13
+ durationSeconds?: number;
14
+ error?: string;
15
+ /**
16
+ * Quality-loop iteration (1-based). Set on the `loop` phase event and on
17
+ * retried phase events (exec, qa, ...) once the outer loop iterates past 1.
18
+ * Surfaced in the events log as `(attempt N/M)` and in the live-zone status
19
+ * cell as `loop N/M` (#624 Item 3).
20
+ */
21
+ iteration?: number;
22
+ }
23
+ /** Per-phase status tracked inside the renderer state machine. */
24
+ export interface PhaseState {
25
+ name: string;
26
+ status: "pending" | "running" | "done" | "failed";
27
+ startedAt?: number;
28
+ durationMs?: number;
29
+ /** Loop iteration label (e.g. "loop 2/3"). */
30
+ loopIteration?: number;
31
+ /**
32
+ * #624 Item 4: normalized signature of the most recent failure for THIS
33
+ * phase (ANSI-stripped, lowercased, first 80 chars, trimmed). Per-phase so
34
+ * "same failure as attempt N" never references a different phase's attempt.
35
+ */
36
+ lastFailureSignature?: string;
37
+ /**
38
+ * #624 Item 4: 1-based attempt number for this phase when
39
+ * `lastFailureSignature` was first observed. Referenced in the abbreviated
40
+ * form `(attempt N/M, same failure as attempt K)`.
41
+ */
42
+ firstAttemptForSignature?: number;
43
+ }
44
+ /** Per-issue status tracked inside the renderer state machine. */
45
+ export interface IssueState {
46
+ issueNumber: number;
47
+ title?: string;
48
+ worktreePath?: string;
49
+ branch?: string;
50
+ status: "queued" | "running" | "done" | "failed";
51
+ phases: PhaseState[];
52
+ currentPhase?: string;
53
+ startedAt?: number;
54
+ completedAt?: number;
55
+ prNumber?: number;
56
+ prUrl?: string;
57
+ /** Optional sub-status line (e.g. "claude streaming · editing src/cli.ts"). */
58
+ subStatus?: string;
59
+ /** Last QA verdict / error reason for failed issues. */
60
+ failureReason?: string;
61
+ /**
62
+ * AC-23: auto-detect mode — render `Phase: detecting…` until spec finishes
63
+ * and the resolved plan is known.
64
+ */
65
+ autoDetect?: boolean;
66
+ }
67
+ /** Initial registration payload — fed at runner start so queued rows render. */
68
+ export interface IssueRegistration {
69
+ issueNumber: number;
70
+ title?: string;
71
+ worktreePath?: string;
72
+ branch?: string;
73
+ /**
74
+ * AC-23: when true, the issue runs in auto-detect mode. The renderer shows
75
+ * `Phase: detecting…` while spec is running (before the resolved phase plan
76
+ * is known) and switches to the normal phase header once spec completes.
77
+ */
78
+ autoDetect?: boolean;
79
+ }
80
+ /** Per-issue summary fields used by the final summary table. */
81
+ export interface IssueSummary {
82
+ issueNumber: number;
83
+ success: boolean;
84
+ durationSeconds?: number;
85
+ phases: Array<{
86
+ name: string;
87
+ success: boolean;
88
+ }>;
89
+ loopTriggered?: boolean;
90
+ prNumber?: number;
91
+ prUrl?: string;
92
+ failureReason?: string;
93
+ qaVerdict?: string;
94
+ unmetCount?: number;
95
+ }
96
+ /** Inputs needed to render the final summary block. */
97
+ export interface SummaryRenderInput {
98
+ issues: IssueSummary[];
99
+ totalDurationSeconds?: number;
100
+ logPath?: string | null;
101
+ dryRun?: boolean;
102
+ }
103
+ /** Public renderer interface — all modes implement this. */
104
+ export interface RunRenderer {
105
+ /** Register an issue so it shows as `queued` before the first phase event. */
106
+ registerIssue(reg: IssueRegistration): void;
107
+ /** Feed a progress event from batch-executor. */
108
+ onEvent(event: ProgressEvent): void;
109
+ /** Mark an issue as completed with PR info. Called by orchestrator. */
110
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
111
+ /** Pause live updates so verbose streaming can write through. */
112
+ pause(): void;
113
+ /** Resume live updates after streaming ends. */
114
+ resume(): void;
115
+ /** Render the final summary block. */
116
+ renderSummary(input: SummaryRenderInput): void;
117
+ /** Tear down timers, cursor state, signal listeners. */
118
+ dispose(): void;
119
+ }
120
+ /**
121
+ * Options shared by every renderer mode. Most are optional; defaults match
122
+ * production behaviour (real stdout, real timers, real signals).
123
+ */
124
+ export interface RenderOptions {
125
+ /** Override stdout writer. Defaults to `process.stdout.write`. */
126
+ stdoutWrite?: (s: string) => void;
127
+ /** Override stderr writer. Defaults to `process.stderr.write`. */
128
+ stderrWrite?: (s: string) => void;
129
+ /** Override clock. Defaults to `Date.now`. */
130
+ now?: () => number;
131
+ /** Override "wall clock" used for non-TTY timestamps. Defaults to `() => new Date()`. */
132
+ wallClock?: () => Date;
133
+ /** Override TTY detection. Defaults to `process.stdout.isTTY`. */
134
+ isTTY?: boolean;
135
+ /** Override terminal column count. Defaults to `process.stdout.columns`. */
136
+ columns?: number;
137
+ /** Disable color output (NO_COLOR). */
138
+ noColor?: boolean;
139
+ /** Heartbeat tick interval for the live zone (ms). Defaults to 1000. */
140
+ liveTickMs?: number;
141
+ /** Idle heartbeat interval for non-TTY mode (ms). Defaults to 60_000. */
142
+ nonTtyHeartbeatMs?: number;
143
+ /** Don't subscribe to SIGWINCH (used in tests). */
144
+ noSignalListeners?: boolean;
145
+ /**
146
+ * AC-26: when a running phase has been active for longer than this many ms
147
+ * with no completion event, the status header flips to `⚠ stalled · …`.
148
+ * Defaults to half the phase timeout when wired from settings; effectively
149
+ * disabled (10× the default heartbeat) when omitted.
150
+ */
151
+ stallThresholdMs?: number;
152
+ /**
153
+ * AC-28: cap visible per-issue rows in the multi-issue live grid. When the
154
+ * total issue count exceeds this, the oldest done rows roll up into a
155
+ * single `✔ {N} done` summary row at the top. Defaults to 10.
156
+ */
157
+ multiIssueRowCap?: number;
158
+ /**
159
+ * #624 Item 1: terminal row count. The TTY live zone caps its frame height
160
+ * at `max(8, rows - 5)` so `log-update` never deals with a frame taller than
161
+ * the terminal — otherwise it loses cursor tracking and appends fresh frames
162
+ * instead of replacing them. Defaults to `process.stdout.rows` or 24.
163
+ */
164
+ rows?: number;
165
+ /**
166
+ * #624 Item 3 / D2: total allowed quality-loop iterations. Used by every
167
+ * retry-suffix site (`(attempt N/M)` / `loop N/M`) so the M denominator
168
+ * tracks the configured maximum instead of being hardcoded. Defaults to 3.
169
+ */
170
+ maxLoopIterations?: number;
171
+ /**
172
+ * When true, `renderSummary` is rendered even if no issues were registered.
173
+ * Default: false (matches existing displaySummary behaviour).
174
+ */
175
+ alwaysRenderSummary?: boolean;
176
+ }
177
+ /**
178
+ * Mode the renderer should run in. Auto-detected by `createRunRenderer` from
179
+ * env + TTY, but explicit selection is supported for tests.
180
+ */
181
+ export type RendererMode = "tty" | "non-tty" | "orchestrator";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Types shared between RunRenderer modes (TTY, non-TTY, orchestrator).
3
+ *
4
+ * The renderer is event-driven: a `ProgressEvent` flows in and the renderer
5
+ * decides whether to update the live zone, append an event line, or both.
6
+ */
7
+ export {};
@@ -0,0 +1,239 @@
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 { IssueRegistration, IssueState, ProgressEvent, RenderOptions, RendererMode, RunRenderer, SummaryRenderInput } from "./run-renderer-types.js";
17
+ /**
18
+ * #624 Item 4: normalized failure signature for dedup decisions.
19
+ *
20
+ * Strips ANSI escape sequences, lowercases, trims whitespace, and truncates to
21
+ * the first 80 visible chars. The plan deliberately chose a length-bounded
22
+ * prefix over a crypto hash so debugging can match signatures by eye.
23
+ */
24
+ export declare function failureSignature(error: string | undefined): string;
25
+ /**
26
+ * #624 Item 3 / Derived AC-D2: shared suffix builder used by all three retry
27
+ * sites (NonTTY events log, TTY events log, TTY status header). Centralizes
28
+ * the `(attempt N/M)` / `loop N/M` literals so they cannot drift between paths.
29
+ *
30
+ * `kind` selects the surface:
31
+ * - "events" → events-log line: leading space + parentheses
32
+ * - "header" → status cell: leading space, no parentheses
33
+ *
34
+ * Returns the empty string when the attempt counter does not apply
35
+ * (no iteration, iteration === 1, or non-positive).
36
+ */
37
+ export declare function formatRetrySuffix(iteration: number | undefined, maxIterations: number, kind: "events" | "header"): string;
38
+ declare abstract class BaseRenderer implements RunRenderer {
39
+ protected readonly issues: Map<number, IssueState>;
40
+ protected readonly stdoutWrite: (s: string) => void;
41
+ protected readonly stderrWrite: (s: string) => void;
42
+ protected readonly now: () => number;
43
+ protected readonly wallClock: () => Date;
44
+ protected readonly noColor: boolean;
45
+ protected readonly runStartedAt: number;
46
+ protected paused: boolean;
47
+ protected disposed: boolean;
48
+ constructor(options: RenderOptions);
49
+ registerIssue(reg: IssueRegistration): void;
50
+ onEvent(event: ProgressEvent): void;
51
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
52
+ pause(): void;
53
+ resume(): void;
54
+ abstract renderSummary(input: SummaryRenderInput): void;
55
+ dispose(): void;
56
+ protected applyEvent(state: IssueState, event: ProgressEvent): void;
57
+ /** Mark an issue done after PR is recorded — derived from phase completion. */
58
+ protected maybeMarkIssueDone(state: IssueState): void;
59
+ protected afterEvent(_event: ProgressEvent, state: IssueState): void;
60
+ protected afterStateChange(): void;
61
+ protected onPause(): void;
62
+ protected onResume(): void;
63
+ protected onDispose(): void;
64
+ }
65
+ /**
66
+ * No-op renderer used when `SEQUANT_ORCHESTRATOR` is set.
67
+ *
68
+ * The orchestrator (e.g. MCP server) consumes `emitProgressLine` JSON from
69
+ * batch-executor directly. Rendering anything else from the CLI would be
70
+ * double-emission. We still track state so `renderSummary` could be useful
71
+ * if explicitly invoked, but neither stdout nor stderr is touched.
72
+ */
73
+ export declare class OrchestratorRenderer extends BaseRenderer {
74
+ renderSummary(): void;
75
+ }
76
+ export declare class NonTTYRenderer extends BaseRenderer {
77
+ private heartbeatTimer;
78
+ private readonly heartbeatMs;
79
+ private readonly columnsOverride?;
80
+ private readonly maxLoopIterations;
81
+ private lastEventAt;
82
+ constructor(options: RenderOptions);
83
+ private getColumns;
84
+ private startHeartbeat;
85
+ /** Test hook: drive a heartbeat without waiting on real timers. */
86
+ tickHeartbeatNow(): void;
87
+ private tickHeartbeat;
88
+ protected afterEvent(event: ProgressEvent, state: IssueState): void;
89
+ private emitEventLine;
90
+ /** Append a single `\n`-terminated line with `[HH:MM:SS]` prefix. */
91
+ private emitLine;
92
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
93
+ renderSummary(input: SummaryRenderInput): void;
94
+ protected onDispose(): void;
95
+ }
96
+ /**
97
+ * #624 Derived AC-D1: test-only observability for the log-update stub. Tests
98
+ * can read `replacementCount` and `lastFrame` to verify the frame is *replaced*
99
+ * on each redraw rather than appended — the foundational guarantee that Items
100
+ * 1 and 2 rely on.
101
+ *
102
+ * `clearCalls` / `doneCalls` (added in the hardening pass) let AC-2.2 verify
103
+ * the renderer actually invokes `logUpdate.clear()` + `logUpdate.done()` during
104
+ * `renderSummary` teardown — not just that the stub's local `lastFrame` was
105
+ * reset.
106
+ */
107
+ export interface TTYTestStub {
108
+ /** Number of times the live frame was replaced (not the initial write). */
109
+ readonly replacementCount: number;
110
+ /** The most recent live frame text passed to log-update. */
111
+ readonly lastFrame: string;
112
+ /** Number of times `logUpdate.clear()` was invoked. */
113
+ readonly clearCalls: number;
114
+ /** Number of times `logUpdate.done()` was invoked. */
115
+ readonly doneCalls: number;
116
+ }
117
+ export declare class TTYRenderer extends BaseRenderer {
118
+ private readonly liveTickMs;
119
+ private liveTimer;
120
+ private spinnerFrame;
121
+ private readonly columnsOverride?;
122
+ private readonly rowsOverride?;
123
+ private readonly noSignalListeners;
124
+ private readonly stallThresholdMs;
125
+ private readonly multiIssueRowCap;
126
+ private readonly maxLoopIterations;
127
+ private readonly logUpdateImpl;
128
+ private readonly logUpdateClear;
129
+ private readonly logUpdateDone;
130
+ private resizeListener;
131
+ private banner;
132
+ private readonly _testStub;
133
+ constructor(options: RenderOptions);
134
+ /**
135
+ * #624 Derived AC-D1: expose the test-only log-update stub. Returns `null`
136
+ * when not in test mode (production renders go through real `log-update`).
137
+ */
138
+ getTestStub(): TTYTestStub | null;
139
+ private startLiveTimer;
140
+ private installSignalListeners;
141
+ /** Test hook: drive a tick without waiting on real timers. */
142
+ tickNow(): void;
143
+ private tick;
144
+ protected afterEvent(event: ProgressEvent, state: IssueState): void;
145
+ protected afterStateChange(): void;
146
+ /** Set a banner that renders above the live grid (e.g. worktree-loss). */
147
+ setBanner(text: string | null): void;
148
+ private appendEventLine;
149
+ setPullRequest(issue: number, prNumber: number, prUrl: string): void;
150
+ renderSummary(input: SummaryRenderInput): void;
151
+ protected onPause(): void;
152
+ protected onResume(): void;
153
+ protected onDispose(): void;
154
+ private getColumns;
155
+ /**
156
+ * #624 Item 1: terminal row count, with a safe default for piped / detached
157
+ * stdout where `process.stdout.rows` is undefined.
158
+ */
159
+ private getRows;
160
+ /**
161
+ * #624 Item 1: hard ceiling on live-zone height. The cap is
162
+ * `max(8, rows - 5)`, dropping to `max(8, rows - 7)` when a banner is active
163
+ * so the banner + a few separator rows still fit. The floor of 8 prevents
164
+ * the live zone from collapsing on tiny terminals.
165
+ */
166
+ private getMaxLiveRows;
167
+ private redraw;
168
+ /** Public for tests — render the live zone to a string without emitting. */
169
+ renderLiveFrame(columns?: number): string;
170
+ /**
171
+ * #624 Item 1 (AC-1.1): hard ceiling on rendered frame height. The interior
172
+ * `applyRowCap` already collapses excess issues into the rollup row, but the
173
+ * frame can still drift over the cap if many issues have multi-line status
174
+ * cells (sub-status + phase sequence). This is the belt-and-braces clamp
175
+ * that guarantees `log-update` never sees a frame taller than the terminal.
176
+ *
177
+ * Always engages — when `rows` isn't explicitly provided, `getRows()` returns
178
+ * `DEFAULT_TERMINAL_ROWS` (100) so the cap is generous but never disengaged.
179
+ */
180
+ private clampFrameHeight;
181
+ private renderNarrowFrame;
182
+ private renderSingleIssueFrame;
183
+ private renderMultiIssueFrame;
184
+ /**
185
+ * AC-28 + #624 Item 1: enforce the per-frame issue row cap, derived from
186
+ * the smaller of `multiIssueRowCap` (static config) and a dynamic ceiling
187
+ * computed from terminal height. The dynamic ceiling reserves ~3 lines per
188
+ * issue (status header + sub-status + separator) and a fixed overhead for
189
+ * the frame header, blank lines, grid borders, and the rollup line.
190
+ *
191
+ * If the cap is not exceeded, returns all issues unchanged. Otherwise: keep
192
+ * all non-done rows, then fill remaining slots with the most recently
193
+ * completed done rows; older done rows roll up into a single summary entry.
194
+ */
195
+ private applyRowCap;
196
+ /**
197
+ * #624 Item 1 (AC-1.1): smaller of the configured static cap and the
198
+ * dynamic terminal-height-derived cap. Each issue row takes roughly 3 grid
199
+ * lines (header, sub-status, separator); the fixed overhead covers the
200
+ * frame title, blank lines, grid borders, and the rollup row.
201
+ *
202
+ * Always engages — when `rows` isn't explicitly provided, `getRows()` returns
203
+ * `DEFAULT_TERMINAL_ROWS` (100) which produces a dynamic cap of ~30, well
204
+ * above the static `multiIssueRowCap` default of 10, so the static cap stays
205
+ * in charge for normal-height terminals.
206
+ */
207
+ private effectiveRowCap;
208
+ private statusHeader;
209
+ private statusSubLines;
210
+ private statusCellLines;
211
+ private runHeader;
212
+ private rollupLine;
213
+ private drawKeyValueTable;
214
+ private drawIssueGrid;
215
+ }
216
+ export interface CreateRendererOptions extends RenderOptions {
217
+ /** Force a specific mode (otherwise auto-detected from env + TTY). */
218
+ mode?: RendererMode;
219
+ }
220
+ /**
221
+ * Create a `RunRenderer` matching the current execution context.
222
+ *
223
+ * Detection order:
224
+ * 1. Explicit `mode` override.
225
+ * 2. `SEQUANT_ORCHESTRATOR` env var → orchestrator (no-op).
226
+ * 3. `process.stdout.isTTY` (or `options.isTTY`) → TTY renderer.
227
+ * 4. Otherwise → non-TTY renderer.
228
+ */
229
+ export declare function createRunRenderer(options?: CreateRendererOptions): RunRenderer;
230
+ /**
231
+ * Public summary helper — used by the legacy displaySummary path so callers
232
+ * that bypass the renderer still get the new grid layout.
233
+ */
234
+ export declare function renderRunSummary(input: SummaryRenderInput, options?: {
235
+ stdoutWrite?: (s: string) => void;
236
+ noColor?: boolean;
237
+ columns?: number;
238
+ }): void;
239
+ export {};