nightralph 0.0.9 → 0.0.11
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 +8 -0
- package/dist/display.js +1 -1
- package/dist/display.js.map +1 -1
- package/dist/index.js +1933 -26
- package/dist/index.js.map +4 -4
- package/dist/meta.json +251 -237
- package/package.json +2 -2
- package/dist/demo-display.js +0 -298
package/dist/demo-display.js
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
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 ?? 4,
|
|
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();
|