@youdie006/prodex 0.27.1 → 0.27.2
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/dist/tui-run.js +63 -22
- package/package.json +1 -1
package/dist/tui-run.js
CHANGED
|
@@ -17,14 +17,54 @@ const ALT_SCREEN_OFF = `${ESC}[?1049l`;
|
|
|
17
17
|
const CLEAR_LINE = `${ESC}[2K\r`;
|
|
18
18
|
const HIDE_CURSOR = `${ESC}[?25l`;
|
|
19
19
|
const SHOW_CURSOR = `${ESC}[?25h`;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Keys are queued by one long-lived listener rather than a listener attached
|
|
22
|
+
* per read.
|
|
23
|
+
*
|
|
24
|
+
* Attaching on demand drops every key pressed while nothing is waiting - during
|
|
25
|
+
* a redraw, or across the seconds it takes to read the project list out of the
|
|
26
|
+
* browser. Measured by using it: the first key after the prompt vanished, so
|
|
27
|
+
* "4" (no project) was swallowed and the next key landed on the wrong row.
|
|
28
|
+
*/
|
|
29
|
+
class KeyQueue {
|
|
30
|
+
input;
|
|
31
|
+
pending = [];
|
|
32
|
+
waiting;
|
|
33
|
+
constructor(input) {
|
|
34
|
+
this.input = input;
|
|
35
|
+
this.input.on("keypress", this.onKey);
|
|
36
|
+
}
|
|
37
|
+
onKey = (_str, key) => {
|
|
38
|
+
const value = key ?? {};
|
|
39
|
+
if (this.waiting) {
|
|
40
|
+
const resolve = this.waiting;
|
|
41
|
+
this.waiting = undefined;
|
|
42
|
+
resolve(value);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.pending.push(value);
|
|
46
|
+
};
|
|
47
|
+
next() {
|
|
48
|
+
const buffered = this.pending.shift();
|
|
49
|
+
if (buffered)
|
|
50
|
+
return Promise.resolve(buffered);
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
this.waiting = resolve;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** Drop keys typed before a screen existed to receive them. */
|
|
56
|
+
drain() {
|
|
57
|
+
this.pending.length = 0;
|
|
58
|
+
}
|
|
59
|
+
dispose() {
|
|
60
|
+
this.input.off("keypress", this.onKey);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
let keys;
|
|
64
|
+
function readKey(_io) {
|
|
65
|
+
if (!keys)
|
|
66
|
+
throw new Error("The key reader is not running.");
|
|
67
|
+
return keys.next();
|
|
28
68
|
}
|
|
29
69
|
function isCancel(key) {
|
|
30
70
|
return (key.ctrl === true && key.name === "c") || key.name === "escape" || key.name === "q";
|
|
@@ -118,6 +158,7 @@ async function askLine(io, question) {
|
|
|
118
158
|
io.input.setRawMode?.(true);
|
|
119
159
|
readline.emitKeypressEvents(io.input);
|
|
120
160
|
io.input.resume();
|
|
161
|
+
keys?.drain();
|
|
121
162
|
return answer.trim();
|
|
122
163
|
}
|
|
123
164
|
const TOOL_CHOICES = [
|
|
@@ -134,24 +175,22 @@ export async function runInteractiveConsult(io, deps) {
|
|
|
134
175
|
readline.emitKeypressEvents(io.input);
|
|
135
176
|
io.input.setRawMode?.(true);
|
|
136
177
|
io.input.resume();
|
|
178
|
+
keys = new KeyQueue(io.input);
|
|
137
179
|
io.write(ALT_SCREEN_ON + HIDE_CURSOR);
|
|
138
180
|
let header = "";
|
|
139
181
|
try {
|
|
140
182
|
io.write(CLEAR);
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const prompt = await askLine(io, `${header}Ask ChatGPT Pro\n\n prompt: `);
|
|
183
|
+
// Gather the context WHILE the prompt is being typed. Reading the browser
|
|
184
|
+
// state takes a second or two, and doing it first left the screen blank for
|
|
185
|
+
// that long - anything typed into that gap was swallowed, prompt included.
|
|
186
|
+
const contextPromise = deps.describeContext?.().catch(() => []);
|
|
187
|
+
const prompt = await askLine(io, "Ask ChatGPT Pro\n\n prompt: ");
|
|
188
|
+
// The panel still leads every question that follows, which is where it
|
|
189
|
+
// earns its place: choosing a project and tools without knowing the browser
|
|
190
|
+
// is down wastes every answer given before the failure.
|
|
191
|
+
const rows = (await contextPromise) ?? [];
|
|
192
|
+
if (rows.length > 0)
|
|
193
|
+
header = `${renderContextPanel(rows, { color: colorEnabled(), width: terminalWidth() })}\n\n`;
|
|
155
194
|
if (prompt.length === 0) {
|
|
156
195
|
io.write("Nothing to ask.\n");
|
|
157
196
|
return 1;
|
|
@@ -246,6 +285,8 @@ export async function runInteractiveConsult(io, deps) {
|
|
|
246
285
|
}
|
|
247
286
|
}
|
|
248
287
|
finally {
|
|
288
|
+
keys?.dispose();
|
|
289
|
+
keys = undefined;
|
|
249
290
|
io.write(ALT_SCREEN_OFF + SHOW_CURSOR);
|
|
250
291
|
io.input.setRawMode?.(false);
|
|
251
292
|
io.input.pause();
|