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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +73 -0
- package/dist/bin/cli.js +94 -9
- package/dist/src/commands/doctor.d.ts +25 -0
- package/dist/src/commands/doctor.js +36 -1
- package/dist/src/commands/locks.d.ts +67 -0
- package/dist/src/commands/locks.js +290 -0
- package/dist/src/commands/merge.js +11 -0
- package/dist/src/commands/prompt.d.ts +39 -0
- package/dist/src/commands/prompt.js +179 -0
- package/dist/src/commands/run-display.d.ts +11 -2
- package/dist/src/commands/run-display.js +62 -28
- package/dist/src/commands/run-progress.d.ts +32 -0
- package/dist/src/commands/run-progress.js +76 -0
- package/dist/src/commands/run.js +80 -18
- package/dist/src/commands/stats.d.ts +2 -0
- package/dist/src/commands/stats.js +94 -8
- package/dist/src/commands/status.js +12 -0
- package/dist/src/commands/watch.d.ts +16 -0
- package/dist/src/commands/watch.js +147 -0
- package/dist/src/lib/ac-linter.d.ts +1 -1
- package/dist/src/lib/ac-linter.js +81 -0
- package/dist/src/lib/assess-collision-detect.d.ts +91 -0
- package/dist/src/lib/assess-collision-detect.js +217 -0
- package/dist/src/lib/assess-comment-parser.d.ts +59 -1
- package/dist/src/lib/assess-comment-parser.js +124 -2
- package/dist/src/lib/cli-ui/format.d.ts +19 -0
- package/dist/src/lib/cli-ui/format.js +34 -0
- package/dist/src/lib/cli-ui/run-renderer-types.d.ts +181 -0
- package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
- package/dist/src/lib/cli-ui/run-renderer.d.ts +239 -0
- package/dist/src/lib/cli-ui/run-renderer.js +1173 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
- package/dist/src/lib/locks/index.d.ts +7 -0
- package/dist/src/lib/locks/index.js +5 -0
- package/dist/src/lib/locks/lock-manager.d.ts +168 -0
- package/dist/src/lib/locks/lock-manager.js +433 -0
- package/dist/src/lib/locks/types.d.ts +59 -0
- package/dist/src/lib/locks/types.js +31 -0
- package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
- package/dist/src/lib/qa/markdown-only-ci.js +74 -0
- package/dist/src/lib/relay/activation.d.ts +60 -0
- package/dist/src/lib/relay/activation.js +122 -0
- package/dist/src/lib/relay/archive.d.ts +34 -0
- package/dist/src/lib/relay/archive.js +106 -0
- package/dist/src/lib/relay/frame.d.ts +20 -0
- package/dist/src/lib/relay/frame.js +76 -0
- package/dist/src/lib/relay/index.d.ts +13 -0
- package/dist/src/lib/relay/index.js +13 -0
- package/dist/src/lib/relay/paths.d.ts +43 -0
- package/dist/src/lib/relay/paths.js +59 -0
- package/dist/src/lib/relay/pid.d.ts +34 -0
- package/dist/src/lib/relay/pid.js +72 -0
- package/dist/src/lib/relay/reader.d.ts +35 -0
- package/dist/src/lib/relay/reader.js +115 -0
- package/dist/src/lib/relay/types.d.ts +68 -0
- package/dist/src/lib/relay/types.js +76 -0
- package/dist/src/lib/relay/writer.d.ts +48 -0
- package/dist/src/lib/relay/writer.js +113 -0
- package/dist/src/lib/settings.d.ts +31 -1
- package/dist/src/lib/settings.js +18 -3
- package/dist/src/lib/version-check.d.ts +60 -5
- package/dist/src/lib/version-check.js +97 -9
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +248 -175
- package/dist/src/lib/workflow/config-resolver.js +4 -0
- package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
- package/dist/src/lib/workflow/heartbeat.js +194 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +62 -8
- package/dist/src/lib/workflow/phase-executor.js +157 -16
- package/dist/src/lib/workflow/phase-mapper.d.ts +3 -2
- package/dist/src/lib/workflow/phase-mapper.js +17 -20
- package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
- package/dist/src/lib/workflow/platforms/github.js +20 -3
- package/dist/src/lib/workflow/pr-status.d.ts +18 -2
- package/dist/src/lib/workflow/pr-status.js +41 -9
- package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
- package/dist/src/lib/workflow/qa-stagnation.js +179 -0
- package/dist/src/lib/workflow/run-orchestrator.d.ts +39 -0
- package/dist/src/lib/workflow/run-orchestrator.js +340 -15
- package/dist/src/lib/workflow/run-reflect.js +1 -1
- package/dist/src/lib/workflow/run-state.d.ts +71 -0
- package/dist/src/lib/workflow/run-state.js +14 -0
- package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
- package/dist/src/lib/workflow/state-cleanup.js +17 -5
- package/dist/src/lib/workflow/state-manager.d.ts +12 -1
- package/dist/src/lib/workflow/state-manager.js +37 -0
- package/dist/src/lib/workflow/state-schema.d.ts +62 -0
- package/dist/src/lib/workflow/state-schema.js +35 -1
- package/dist/src/lib/workflow/types.d.ts +74 -1
- package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
- package/dist/src/lib/workflow/worktree-manager.js +15 -6
- package/dist/src/mcp/tools/run.d.ts +44 -0
- package/dist/src/mcp/tools/run.js +104 -13
- package/dist/src/ui/tui/App.d.ts +14 -0
- package/dist/src/ui/tui/App.js +41 -0
- package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
- package/dist/src/ui/tui/ElapsedTimer.js +31 -0
- package/dist/src/ui/tui/Header.d.ts +6 -0
- package/dist/src/ui/tui/Header.js +15 -0
- package/dist/src/ui/tui/IssueBox.d.ts +16 -0
- package/dist/src/ui/tui/IssueBox.js +68 -0
- package/dist/src/ui/tui/Spinner.d.ts +9 -0
- package/dist/src/ui/tui/Spinner.js +18 -0
- package/dist/src/ui/tui/index.d.ts +15 -0
- package/dist/src/ui/tui/index.js +29 -0
- package/dist/src/ui/tui/theme.d.ts +29 -0
- package/dist/src/ui/tui/theme.js +52 -0
- package/dist/src/ui/tui/truncate.d.ts +11 -0
- package/dist/src/ui/tui/truncate.js +31 -0
- package/package.json +10 -3
- package/templates/agents/sequant-explorer.md +1 -0
- package/templates/agents/sequant-qa-checker.md +2 -1
- package/templates/agents/sequant-testgen.md +1 -0
- package/templates/hooks/post-tool.sh +11 -0
- package/templates/hooks/pre-tool.sh +18 -9
- package/templates/hooks/relay-check.sh +107 -0
- package/templates/relay/frame.txt +11 -0
- package/templates/scripts/cleanup-worktree.sh +25 -3
- package/templates/scripts/new-feature.sh +6 -0
- package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
- package/templates/skills/_shared/references/subagent-types.md +21 -8
- package/templates/skills/assess/SKILL.md +103 -49
- package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
- package/templates/skills/docs/SKILL.md +141 -22
- package/templates/skills/exec/SKILL.md +10 -8
- package/templates/skills/fullsolve/SKILL.md +79 -5
- package/templates/skills/loop/SKILL.md +28 -0
- package/templates/skills/merger/SKILL.md +621 -0
- package/templates/skills/qa/SKILL.md +727 -8
- package/templates/skills/setup/SKILL.md +6 -0
- package/templates/skills/spec/SKILL.md +52 -0
- package/templates/skills/spec/references/parallel-groups.md +7 -0
- package/templates/skills/spec/references/recommended-workflow.md +4 -2
- 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,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 {};
|