nightralph 0.0.8 → 0.0.10
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/README.md +10 -1
- package/dist/demo-display.js +298 -0
- package/dist/display.js +280 -0
- package/dist/display.js.map +7 -0
- package/dist/index.js +6 -2
- package/dist/index.js.map +2 -2
- package/dist/meta.json +49 -8
- package/dist/orchestrator.js +158 -58
- package/dist/orchestrator.js.map +2 -2
- package/dist/src/display.d.ts +69 -0
- package/dist/src/display.d.ts.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/orchestrator.d.ts +11 -2
- package/dist/src/orchestrator.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -141,7 +141,8 @@ Flags:
|
|
|
141
141
|
| `-X` | no | -- | Stop on merge conflict instead of re-spawning |
|
|
142
142
|
| `--timeout` | no | `300` | Kill agent after N seconds |
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
|
|
145
|
+
**Notes**:
|
|
145
146
|
|
|
146
147
|
* When `--spec <name>` is omitted, the CLI looks for
|
|
147
148
|
`.scratch/<feature>/issues/` directories. If multiple features exist,
|
|
@@ -213,9 +214,17 @@ This is expected to run for a long time, like overnight.
|
|
|
213
214
|
|
|
214
215
|
### Mac OS
|
|
215
216
|
|
|
217
|
+
#### Claude
|
|
218
|
+
|
|
216
219
|
```sh
|
|
217
220
|
caffeinate -i npx nightralph claude -m claude-opus-4-6
|
|
218
221
|
```
|
|
219
222
|
|
|
223
|
+
##### Run with `pi` and an OpenRouter model
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
caffeinate -i npx nightralph pi -m openrouter/z-ai/glm-5.3-flash
|
|
227
|
+
```
|
|
228
|
+
|
|
220
229
|
That command will prevent your machine from sleeping, but the display can still
|
|
221
230
|
go dark.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// src/display.ts
|
|
2
|
+
var ESC = "\x1B[";
|
|
3
|
+
var ansi = {
|
|
4
|
+
cursorUp(n) {
|
|
5
|
+
return `${ESC}${n}A`;
|
|
6
|
+
},
|
|
7
|
+
cursorTo(col) {
|
|
8
|
+
return `${ESC}${col}G`;
|
|
9
|
+
},
|
|
10
|
+
eraseLine() {
|
|
11
|
+
return `${ESC}2K`;
|
|
12
|
+
},
|
|
13
|
+
eraseLines(n) {
|
|
14
|
+
let out = "";
|
|
15
|
+
for (let i = 0; i < n; i++) {
|
|
16
|
+
out += ansi.eraseLine();
|
|
17
|
+
if (i < n - 1) out += ansi.cursorUp(1);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
},
|
|
21
|
+
cursorHide() {
|
|
22
|
+
return `${ESC}?25l`;
|
|
23
|
+
},
|
|
24
|
+
cursorShow() {
|
|
25
|
+
return `${ESC}?25h`;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var color = {
|
|
29
|
+
green(text) {
|
|
30
|
+
return `${ESC}32m${text}${ESC}0m`;
|
|
31
|
+
},
|
|
32
|
+
yellow(text) {
|
|
33
|
+
return `${ESC}33m${text}${ESC}0m`;
|
|
34
|
+
},
|
|
35
|
+
red(text) {
|
|
36
|
+
return `${ESC}31m${text}${ESC}0m`;
|
|
37
|
+
},
|
|
38
|
+
dim(text) {
|
|
39
|
+
return `${ESC}2m${text}${ESC}0m`;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var FILLED_DOT = "\u25CF";
|
|
43
|
+
var EMPTY_DOT = "\u25CB";
|
|
44
|
+
function renderDot(status) {
|
|
45
|
+
switch (status) {
|
|
46
|
+
case "pending":
|
|
47
|
+
return color.dim(EMPTY_DOT);
|
|
48
|
+
case "in-progress":
|
|
49
|
+
return color.yellow(FILLED_DOT);
|
|
50
|
+
case "done":
|
|
51
|
+
return color.green(FILLED_DOT);
|
|
52
|
+
case "failed":
|
|
53
|
+
return color.red(FILLED_DOT);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var StatusDisplay = class {
|
|
57
|
+
wave = null;
|
|
58
|
+
messages = [];
|
|
59
|
+
renderedLines = 0;
|
|
60
|
+
config;
|
|
61
|
+
viewportStart = 0;
|
|
62
|
+
resizeListener = null;
|
|
63
|
+
signalHandler = null;
|
|
64
|
+
constructor(config) {
|
|
65
|
+
this.config = {
|
|
66
|
+
messageLines: config?.messageLines ?? 10,
|
|
67
|
+
stream: config?.stream ?? process.stdout
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
getAvailableRows() {
|
|
71
|
+
const termHeight = this.config.stream.rows ?? 24;
|
|
72
|
+
const overhead = 2 + this.config.messageLines;
|
|
73
|
+
const available = termHeight - overhead;
|
|
74
|
+
return Math.max(1, available);
|
|
75
|
+
}
|
|
76
|
+
startWave(waveNum, totalWaves, tickets2) {
|
|
77
|
+
this.wave = {
|
|
78
|
+
waveNum,
|
|
79
|
+
totalWaves,
|
|
80
|
+
tickets: tickets2.map((t) => ({
|
|
81
|
+
...t,
|
|
82
|
+
status: "pending"
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
this.messages = [];
|
|
86
|
+
this.viewportStart = 0;
|
|
87
|
+
this.config.stream.write(ansi.cursorHide());
|
|
88
|
+
if (this.config.stream.isTTY) {
|
|
89
|
+
if (this.resizeListener) {
|
|
90
|
+
this.config.stream.removeListener(
|
|
91
|
+
"resize",
|
|
92
|
+
this.resizeListener
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
this.resizeListener = () => this.render();
|
|
96
|
+
this.config.stream.on(
|
|
97
|
+
"resize",
|
|
98
|
+
this.resizeListener
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (this.signalHandler) {
|
|
102
|
+
process.removeListener("SIGINT", this.signalHandler);
|
|
103
|
+
process.removeListener("SIGTERM", this.signalHandler);
|
|
104
|
+
}
|
|
105
|
+
this.signalHandler = () => this.cleanup();
|
|
106
|
+
process.on("SIGINT", this.signalHandler);
|
|
107
|
+
process.on("SIGTERM", this.signalHandler);
|
|
108
|
+
this.render();
|
|
109
|
+
}
|
|
110
|
+
setTicketStatus(num, status) {
|
|
111
|
+
if (!this.wave) return;
|
|
112
|
+
const ticket = this.wave.tickets.find((t) => t.num === num);
|
|
113
|
+
if (ticket) {
|
|
114
|
+
ticket.status = status;
|
|
115
|
+
if (status === "in-progress") {
|
|
116
|
+
const ticketIndex = this.wave.tickets.indexOf(ticket);
|
|
117
|
+
const availableRows = this.getAvailableRows();
|
|
118
|
+
const totalTickets = this.wave.tickets.length;
|
|
119
|
+
if (ticketIndex < this.viewportStart) {
|
|
120
|
+
this.viewportStart = ticketIndex;
|
|
121
|
+
} else if (ticketIndex >= this.viewportStart + availableRows) {
|
|
122
|
+
this.viewportStart = ticketIndex - availableRows + 3;
|
|
123
|
+
}
|
|
124
|
+
this.viewportStart = Math.max(
|
|
125
|
+
0,
|
|
126
|
+
Math.min(
|
|
127
|
+
this.viewportStart,
|
|
128
|
+
totalTickets - 1
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
this.render();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
log(message) {
|
|
136
|
+
this.messages.push(message);
|
|
137
|
+
if (this.messages.length > this.config.messageLines) {
|
|
138
|
+
this.messages.shift();
|
|
139
|
+
}
|
|
140
|
+
this.render();
|
|
141
|
+
}
|
|
142
|
+
cleanup() {
|
|
143
|
+
if (this.resizeListener && this.config.stream.isTTY) {
|
|
144
|
+
this.config.stream.removeListener("resize", this.resizeListener);
|
|
145
|
+
}
|
|
146
|
+
if (this.signalHandler) {
|
|
147
|
+
process.removeListener("SIGINT", this.signalHandler);
|
|
148
|
+
process.removeListener("SIGTERM", this.signalHandler);
|
|
149
|
+
}
|
|
150
|
+
this.config.stream.write(ansi.cursorShow());
|
|
151
|
+
}
|
|
152
|
+
render() {
|
|
153
|
+
if (!this.wave) return;
|
|
154
|
+
let output = "";
|
|
155
|
+
if (this.renderedLines > 0) {
|
|
156
|
+
output += ansi.eraseLines(this.renderedLines + 1);
|
|
157
|
+
}
|
|
158
|
+
const completed = this.wave.tickets.filter(
|
|
159
|
+
(t) => t.status === "done"
|
|
160
|
+
).length;
|
|
161
|
+
const total = this.wave.tickets.length;
|
|
162
|
+
const pct = total === 0 ? 0 : Math.round(completed / total * 100);
|
|
163
|
+
output += `Wave ${this.wave.waveNum}/${this.wave.totalWaves} -- ${pct}% complete
|
|
164
|
+
`;
|
|
165
|
+
const availableRows = this.getAvailableRows();
|
|
166
|
+
const tickets2 = this.wave.tickets;
|
|
167
|
+
let renderedTicketCount = 0;
|
|
168
|
+
if (tickets2.length <= availableRows) {
|
|
169
|
+
for (const ticket of tickets2) {
|
|
170
|
+
const dot = renderDot(ticket.status);
|
|
171
|
+
output += `${dot} ${ticket.filename}
|
|
172
|
+
`;
|
|
173
|
+
}
|
|
174
|
+
renderedTicketCount = tickets2.length;
|
|
175
|
+
} else {
|
|
176
|
+
this.viewportStart = Math.max(
|
|
177
|
+
0,
|
|
178
|
+
Math.min(
|
|
179
|
+
this.viewportStart,
|
|
180
|
+
tickets2.length - 1
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
let hasMoreAbove = this.viewportStart > 0;
|
|
184
|
+
let tentativeCount = availableRows - (hasMoreAbove ? 1 : 0);
|
|
185
|
+
let hasMoreBelow = this.viewportStart + tentativeCount < tickets2.length;
|
|
186
|
+
let ticketsToShow = Math.max(
|
|
187
|
+
0,
|
|
188
|
+
tentativeCount - (hasMoreBelow ? 1 : 0)
|
|
189
|
+
);
|
|
190
|
+
const maxStart = Math.max(
|
|
191
|
+
0,
|
|
192
|
+
tickets2.length - Math.max(1, ticketsToShow)
|
|
193
|
+
);
|
|
194
|
+
if (this.viewportStart > maxStart) {
|
|
195
|
+
this.viewportStart = maxStart;
|
|
196
|
+
hasMoreAbove = this.viewportStart > 0;
|
|
197
|
+
tentativeCount = availableRows - (hasMoreAbove ? 1 : 0);
|
|
198
|
+
hasMoreBelow = this.viewportStart + tentativeCount < tickets2.length;
|
|
199
|
+
ticketsToShow = Math.max(
|
|
200
|
+
0,
|
|
201
|
+
tentativeCount - (hasMoreBelow ? 1 : 0)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if (hasMoreAbove) {
|
|
205
|
+
const moreCount = this.viewportStart;
|
|
206
|
+
output += ` ... ${moreCount} more above
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
const visibleTickets = tickets2.slice(
|
|
210
|
+
this.viewportStart,
|
|
211
|
+
this.viewportStart + ticketsToShow
|
|
212
|
+
);
|
|
213
|
+
for (const ticket of visibleTickets) {
|
|
214
|
+
const dot = renderDot(ticket.status);
|
|
215
|
+
output += `${dot} ${ticket.filename}
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
if (hasMoreBelow) {
|
|
219
|
+
const moreCount = tickets2.length - (this.viewportStart + ticketsToShow);
|
|
220
|
+
output += ` ... ${moreCount} more below
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
renderedTicketCount = (hasMoreAbove ? 1 : 0) + visibleTickets.length + (hasMoreBelow ? 1 : 0);
|
|
224
|
+
}
|
|
225
|
+
output += "-".repeat(50) + "\n";
|
|
226
|
+
const msgLines = Math.max(
|
|
227
|
+
0,
|
|
228
|
+
this.config.messageLines - this.messages.length
|
|
229
|
+
);
|
|
230
|
+
for (const msg of this.messages) {
|
|
231
|
+
output += `${msg}
|
|
232
|
+
`;
|
|
233
|
+
}
|
|
234
|
+
for (let i = 0; i < msgLines; i++) {
|
|
235
|
+
output += "\n";
|
|
236
|
+
}
|
|
237
|
+
this.renderedLines = 2 + renderedTicketCount + this.config.messageLines;
|
|
238
|
+
this.config.stream.write(output);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// demo-display.ts
|
|
243
|
+
function sleep(ms) {
|
|
244
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
245
|
+
}
|
|
246
|
+
var tickets = [
|
|
247
|
+
{ num: 1, filename: "001-add-login-page.md" },
|
|
248
|
+
{ num: 2, filename: "002-fix-header-alignment.md" },
|
|
249
|
+
{ num: 3, filename: "003-refactor-auth-module.md" },
|
|
250
|
+
{ num: 4, filename: "004-update-dependencies.md" },
|
|
251
|
+
{ num: 5, filename: "005-add-dark-mode.md" },
|
|
252
|
+
{ num: 6, filename: "006-improve-error-messages.md" },
|
|
253
|
+
{ num: 7, filename: "007-add-search-feature.md" },
|
|
254
|
+
{ num: 8, filename: "008-optimize-queries.md" }
|
|
255
|
+
];
|
|
256
|
+
async function main() {
|
|
257
|
+
const display = new StatusDisplay();
|
|
258
|
+
const wave1 = tickets.slice(0, 4);
|
|
259
|
+
display.startWave(1, 3, wave1);
|
|
260
|
+
display.log("Starting wave 1...");
|
|
261
|
+
for (const t of wave1) {
|
|
262
|
+
await sleep(600);
|
|
263
|
+
display.setTicketStatus(t.num, "in-progress");
|
|
264
|
+
display.log(`Agent working on ${t.filename}`);
|
|
265
|
+
await sleep(1200);
|
|
266
|
+
const status = t.num === 3 ? "failed" : "done";
|
|
267
|
+
display.setTicketStatus(t.num, status);
|
|
268
|
+
display.log(
|
|
269
|
+
status === "done" ? `Completed ${t.filename}` : `Failed ${t.filename}`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
await sleep(1e3);
|
|
273
|
+
const wave2 = tickets.slice(4, 7);
|
|
274
|
+
display.startWave(2, 3, wave2);
|
|
275
|
+
display.log("Starting wave 2...");
|
|
276
|
+
for (const t of wave2) {
|
|
277
|
+
await sleep(600);
|
|
278
|
+
display.setTicketStatus(t.num, "in-progress");
|
|
279
|
+
display.log(`Agent working on ${t.filename}`);
|
|
280
|
+
await sleep(1e3);
|
|
281
|
+
display.setTicketStatus(t.num, "done");
|
|
282
|
+
display.log(`Completed ${t.filename}`);
|
|
283
|
+
}
|
|
284
|
+
await sleep(1e3);
|
|
285
|
+
const wave3 = tickets.slice(7);
|
|
286
|
+
display.startWave(3, 3, wave3);
|
|
287
|
+
display.log("Starting wave 3...");
|
|
288
|
+
await sleep(600);
|
|
289
|
+
display.setTicketStatus(8, "in-progress");
|
|
290
|
+
display.log("Agent working on 008-optimize-queries.md");
|
|
291
|
+
await sleep(1500);
|
|
292
|
+
display.setTicketStatus(8, "done");
|
|
293
|
+
display.log("Completed 008-optimize-queries.md");
|
|
294
|
+
await sleep(800);
|
|
295
|
+
display.cleanup();
|
|
296
|
+
console.log("\nDemo complete.");
|
|
297
|
+
}
|
|
298
|
+
main();
|
package/dist/display.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
const ESC = "\x1B[";
|
|
4
|
+
const ansi = {
|
|
5
|
+
cursorUp(n) {
|
|
6
|
+
return `${ESC}${n}A`;
|
|
7
|
+
},
|
|
8
|
+
cursorTo(col) {
|
|
9
|
+
return `${ESC}${col}G`;
|
|
10
|
+
},
|
|
11
|
+
eraseLine() {
|
|
12
|
+
return `${ESC}2K`;
|
|
13
|
+
},
|
|
14
|
+
eraseLines(n) {
|
|
15
|
+
let out = "";
|
|
16
|
+
for (let i = 0; i < n; i++) {
|
|
17
|
+
out += ansi.eraseLine();
|
|
18
|
+
if (i < n - 1) out += ansi.cursorUp(1);
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
},
|
|
22
|
+
cursorHide() {
|
|
23
|
+
return `${ESC}?25l`;
|
|
24
|
+
},
|
|
25
|
+
cursorShow() {
|
|
26
|
+
return `${ESC}?25h`;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const color = {
|
|
30
|
+
green(text) {
|
|
31
|
+
return `${ESC}32m${text}${ESC}0m`;
|
|
32
|
+
},
|
|
33
|
+
yellow(text) {
|
|
34
|
+
return `${ESC}33m${text}${ESC}0m`;
|
|
35
|
+
},
|
|
36
|
+
red(text) {
|
|
37
|
+
return `${ESC}31m${text}${ESC}0m`;
|
|
38
|
+
},
|
|
39
|
+
dim(text) {
|
|
40
|
+
return `${ESC}2m${text}${ESC}0m`;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const FILLED_DOT = "\u25CF";
|
|
44
|
+
const EMPTY_DOT = "\u25CB";
|
|
45
|
+
function renderDot(status) {
|
|
46
|
+
switch (status) {
|
|
47
|
+
case "pending":
|
|
48
|
+
return color.dim(EMPTY_DOT);
|
|
49
|
+
case "in-progress":
|
|
50
|
+
return color.yellow(FILLED_DOT);
|
|
51
|
+
case "done":
|
|
52
|
+
return color.green(FILLED_DOT);
|
|
53
|
+
case "failed":
|
|
54
|
+
return color.red(FILLED_DOT);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
__name(renderDot, "renderDot");
|
|
58
|
+
class StatusDisplay {
|
|
59
|
+
static {
|
|
60
|
+
__name(this, "StatusDisplay");
|
|
61
|
+
}
|
|
62
|
+
wave = null;
|
|
63
|
+
messages = [];
|
|
64
|
+
renderedLines = 0;
|
|
65
|
+
config;
|
|
66
|
+
viewportStart = 0;
|
|
67
|
+
resizeListener = null;
|
|
68
|
+
signalHandler = null;
|
|
69
|
+
constructor(config) {
|
|
70
|
+
this.config = {
|
|
71
|
+
messageLines: config?.messageLines ?? 10,
|
|
72
|
+
stream: config?.stream ?? process.stdout
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
getAvailableRows() {
|
|
76
|
+
const termHeight = this.config.stream.rows ?? 24;
|
|
77
|
+
const overhead = 2 + this.config.messageLines;
|
|
78
|
+
const available = termHeight - overhead;
|
|
79
|
+
return Math.max(1, available);
|
|
80
|
+
}
|
|
81
|
+
startWave(waveNum, totalWaves, tickets) {
|
|
82
|
+
this.wave = {
|
|
83
|
+
waveNum,
|
|
84
|
+
totalWaves,
|
|
85
|
+
tickets: tickets.map((t) => ({
|
|
86
|
+
...t,
|
|
87
|
+
status: "pending"
|
|
88
|
+
}))
|
|
89
|
+
};
|
|
90
|
+
this.messages = [];
|
|
91
|
+
this.viewportStart = 0;
|
|
92
|
+
this.config.stream.write(ansi.cursorHide());
|
|
93
|
+
if (this.config.stream.isTTY) {
|
|
94
|
+
if (this.resizeListener) {
|
|
95
|
+
this.config.stream.removeListener(
|
|
96
|
+
"resize",
|
|
97
|
+
this.resizeListener
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
this.resizeListener = () => this.render();
|
|
101
|
+
this.config.stream.on(
|
|
102
|
+
"resize",
|
|
103
|
+
this.resizeListener
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (this.signalHandler) {
|
|
107
|
+
process.removeListener("SIGINT", this.signalHandler);
|
|
108
|
+
process.removeListener("SIGTERM", this.signalHandler);
|
|
109
|
+
}
|
|
110
|
+
this.signalHandler = () => this.cleanup();
|
|
111
|
+
process.on("SIGINT", this.signalHandler);
|
|
112
|
+
process.on("SIGTERM", this.signalHandler);
|
|
113
|
+
this.render();
|
|
114
|
+
}
|
|
115
|
+
setTicketStatus(num, status) {
|
|
116
|
+
if (!this.wave) return;
|
|
117
|
+
const ticket = this.wave.tickets.find((t) => t.num === num);
|
|
118
|
+
if (ticket) {
|
|
119
|
+
ticket.status = status;
|
|
120
|
+
if (status === "in-progress") {
|
|
121
|
+
const ticketIndex = this.wave.tickets.indexOf(ticket);
|
|
122
|
+
const availableRows = this.getAvailableRows();
|
|
123
|
+
const totalTickets = this.wave.tickets.length;
|
|
124
|
+
if (ticketIndex < this.viewportStart) {
|
|
125
|
+
this.viewportStart = ticketIndex;
|
|
126
|
+
} else if (ticketIndex >= this.viewportStart + availableRows) {
|
|
127
|
+
this.viewportStart = ticketIndex - availableRows + 3;
|
|
128
|
+
}
|
|
129
|
+
this.viewportStart = Math.max(
|
|
130
|
+
0,
|
|
131
|
+
Math.min(
|
|
132
|
+
this.viewportStart,
|
|
133
|
+
totalTickets - 1
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
this.render();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
log(message) {
|
|
141
|
+
this.messages.push(message);
|
|
142
|
+
if (this.messages.length > this.config.messageLines) {
|
|
143
|
+
this.messages.shift();
|
|
144
|
+
}
|
|
145
|
+
this.render();
|
|
146
|
+
}
|
|
147
|
+
cleanup() {
|
|
148
|
+
if (this.resizeListener && this.config.stream.isTTY) {
|
|
149
|
+
this.config.stream.removeListener("resize", this.resizeListener);
|
|
150
|
+
}
|
|
151
|
+
if (this.signalHandler) {
|
|
152
|
+
process.removeListener("SIGINT", this.signalHandler);
|
|
153
|
+
process.removeListener("SIGTERM", this.signalHandler);
|
|
154
|
+
}
|
|
155
|
+
this.config.stream.write(ansi.cursorShow());
|
|
156
|
+
}
|
|
157
|
+
render() {
|
|
158
|
+
if (!this.wave) return;
|
|
159
|
+
let output = "";
|
|
160
|
+
if (this.renderedLines > 0) {
|
|
161
|
+
output += ansi.eraseLines(this.renderedLines + 1);
|
|
162
|
+
}
|
|
163
|
+
const completed = this.wave.tickets.filter(
|
|
164
|
+
(t) => t.status === "done"
|
|
165
|
+
).length;
|
|
166
|
+
const total = this.wave.tickets.length;
|
|
167
|
+
const pct = total === 0 ? 0 : Math.round(completed / total * 100);
|
|
168
|
+
output += `Wave ${this.wave.waveNum}/${this.wave.totalWaves} -- ${pct}% complete
|
|
169
|
+
`;
|
|
170
|
+
const availableRows = this.getAvailableRows();
|
|
171
|
+
const tickets = this.wave.tickets;
|
|
172
|
+
let renderedTicketCount = 0;
|
|
173
|
+
if (tickets.length <= availableRows) {
|
|
174
|
+
for (const ticket of tickets) {
|
|
175
|
+
const dot = renderDot(ticket.status);
|
|
176
|
+
output += `${dot} ${ticket.filename}
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
179
|
+
renderedTicketCount = tickets.length;
|
|
180
|
+
} else {
|
|
181
|
+
this.viewportStart = Math.max(
|
|
182
|
+
0,
|
|
183
|
+
Math.min(
|
|
184
|
+
this.viewportStart,
|
|
185
|
+
tickets.length - 1
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
let hasMoreAbove = this.viewportStart > 0;
|
|
189
|
+
let tentativeCount = availableRows - (hasMoreAbove ? 1 : 0);
|
|
190
|
+
let hasMoreBelow = this.viewportStart + tentativeCount < tickets.length;
|
|
191
|
+
let ticketsToShow = Math.max(
|
|
192
|
+
0,
|
|
193
|
+
tentativeCount - (hasMoreBelow ? 1 : 0)
|
|
194
|
+
);
|
|
195
|
+
const maxStart = Math.max(
|
|
196
|
+
0,
|
|
197
|
+
tickets.length - Math.max(1, ticketsToShow)
|
|
198
|
+
);
|
|
199
|
+
if (this.viewportStart > maxStart) {
|
|
200
|
+
this.viewportStart = maxStart;
|
|
201
|
+
hasMoreAbove = this.viewportStart > 0;
|
|
202
|
+
tentativeCount = availableRows - (hasMoreAbove ? 1 : 0);
|
|
203
|
+
hasMoreBelow = this.viewportStart + tentativeCount < tickets.length;
|
|
204
|
+
ticketsToShow = Math.max(
|
|
205
|
+
0,
|
|
206
|
+
tentativeCount - (hasMoreBelow ? 1 : 0)
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (hasMoreAbove) {
|
|
210
|
+
const moreCount = this.viewportStart;
|
|
211
|
+
output += ` ... ${moreCount} more above
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
const visibleTickets = tickets.slice(
|
|
215
|
+
this.viewportStart,
|
|
216
|
+
this.viewportStart + ticketsToShow
|
|
217
|
+
);
|
|
218
|
+
for (const ticket of visibleTickets) {
|
|
219
|
+
const dot = renderDot(ticket.status);
|
|
220
|
+
output += `${dot} ${ticket.filename}
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
if (hasMoreBelow) {
|
|
224
|
+
const moreCount = tickets.length - (this.viewportStart + ticketsToShow);
|
|
225
|
+
output += ` ... ${moreCount} more below
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
renderedTicketCount = (hasMoreAbove ? 1 : 0) + visibleTickets.length + (hasMoreBelow ? 1 : 0);
|
|
229
|
+
}
|
|
230
|
+
output += "-".repeat(50) + "\n";
|
|
231
|
+
const msgLines = Math.max(
|
|
232
|
+
0,
|
|
233
|
+
this.config.messageLines - this.messages.length
|
|
234
|
+
);
|
|
235
|
+
for (const msg of this.messages) {
|
|
236
|
+
output += `${msg}
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
for (let i = 0; i < msgLines; i++) {
|
|
240
|
+
output += "\n";
|
|
241
|
+
}
|
|
242
|
+
this.renderedLines = 2 + renderedTicketCount + this.config.messageLines;
|
|
243
|
+
this.config.stream.write(output);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
class PlainDisplay {
|
|
247
|
+
static {
|
|
248
|
+
__name(this, "PlainDisplay");
|
|
249
|
+
}
|
|
250
|
+
startWave(waveNum, _totalWaves, tickets) {
|
|
251
|
+
console.log(
|
|
252
|
+
`
|
|
253
|
+
Wave ${waveNum}: ` + tickets.map((t) => t.filename).join(", ")
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
setTicketStatus(_num, _status) {
|
|
257
|
+
}
|
|
258
|
+
log(message) {
|
|
259
|
+
console.log(message);
|
|
260
|
+
}
|
|
261
|
+
cleanup() {
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function createDisplay(stream) {
|
|
265
|
+
const s = stream ?? process.stdout;
|
|
266
|
+
if (s.isTTY) {
|
|
267
|
+
return new StatusDisplay({ stream: s });
|
|
268
|
+
}
|
|
269
|
+
return new PlainDisplay();
|
|
270
|
+
}
|
|
271
|
+
__name(createDisplay, "createDisplay");
|
|
272
|
+
export {
|
|
273
|
+
PlainDisplay,
|
|
274
|
+
StatusDisplay,
|
|
275
|
+
ansi,
|
|
276
|
+
color,
|
|
277
|
+
createDisplay,
|
|
278
|
+
renderDot
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/display.ts"],
|
|
4
|
+
"sourcesContent": ["export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'done'\n | 'failed'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\n}\n\nexport type DisplayConfig = {\n readonly messageLines:number\n readonly stream:NodeJS.WriteStream\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>\n ):void\n setTicketStatus(num:number, status:TicketStatus):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n private signalHandler:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n messageLines:config?.messageLines ?? 10,\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + this.config.messageLines\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{ num:number; filename:string }>>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n // Register signal handler to restore cursor on interruption\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.signalHandler = () => this.cleanup()\n process.on('SIGINT', this.signalHandler)\n process.on('SIGTERM', this.signalHandler)\n\n this.render()\n }\n\n setTicketStatus (num:number, status:TicketStatus):void {\n if (!this.wave) return\n\n const ticket = this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex =\n this.wave.tickets.indexOf(ticket)\n const availableRows =\n this.getAvailableRows()\n const totalTickets =\n this.wave.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (\n ticketIndex >=\n this.viewportStart + availableRows\n ) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart =\n ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n totalTickets - 1,\n ),\n )\n }\n\n this.render()\n }\n }\n\n log (message:string):void {\n this.messages.push(message)\n if (this.messages.length > this.config.messageLines) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n // Remove signal handlers\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output +=\n ansi.eraseLines(this.renderedLines + 1)\n }\n\n const completed = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const total = this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} -- ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets = this.wave.tickets\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n output += `${dot} ${ticket.filename}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n ticketsToShow = Math.max(\n 0,\n tentativeCount -\n (hasMoreBelow ? 1 : 0),\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n output += `${dot} ${ticket.filename}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount =\n tickets.length -\n (this.viewportStart + ticketsToShow)\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(50) + '\\n'\n\n const msgLines = Math.max(\n 0,\n this.config.messageLines - this.messages.length,\n )\n for (const msg of this.messages) {\n output += `${msg}\\n`\n }\n for (let i = 0; i < msgLines; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + this.config.messageLines\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>\n ):void {\n console.log(\n `\\nWave ${waveNum}: ` +\n tickets.map(t => t.filename).join(', ')\n )\n }\n\n setTicketStatus (\n _num:number,\n _status:TicketStatus\n ):void {\n // no-op: plain mode reports via log()\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (\n stream?:NodeJS.WriteStream\n):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n return new PlainDisplay()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
runWaves,
|
|
15
15
|
runWavesIsolated
|
|
16
16
|
} from "./orchestrator.js";
|
|
17
|
+
import { createDisplay } from "./display.js";
|
|
17
18
|
import {
|
|
18
19
|
findFeatureDirs,
|
|
19
20
|
resolveIssuesDir,
|
|
@@ -178,6 +179,7 @@ async function runExecute(argv) {
|
|
|
178
179
|
}
|
|
179
180
|
return;
|
|
180
181
|
}
|
|
182
|
+
const display = createDisplay();
|
|
181
183
|
let result;
|
|
182
184
|
if (isGitRepo()) {
|
|
183
185
|
result = await runWavesIsolated({
|
|
@@ -188,7 +190,8 @@ async function runExecute(argv) {
|
|
|
188
190
|
timeout,
|
|
189
191
|
logsDir,
|
|
190
192
|
featureName,
|
|
191
|
-
conflictStrategy
|
|
193
|
+
conflictStrategy,
|
|
194
|
+
display
|
|
192
195
|
});
|
|
193
196
|
} else {
|
|
194
197
|
result = await runWaves(
|
|
@@ -197,7 +200,8 @@ async function runExecute(argv) {
|
|
|
197
200
|
argv.provider,
|
|
198
201
|
argv.model ?? null,
|
|
199
202
|
timeout,
|
|
200
|
-
logsDir
|
|
203
|
+
logsDir,
|
|
204
|
+
display
|
|
201
205
|
);
|
|
202
206
|
}
|
|
203
207
|
if (!result.allDone) {
|