@tiens.nguyen/gonext-local-worker 1.0.306 → 1.0.307
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/gonext-repl.mjs +74 -37
- package/package.json +1 -1
package/gonext-repl.mjs
CHANGED
|
@@ -297,15 +297,14 @@ rl.on("line", (l) => {
|
|
|
297
297
|
// command's own output doesn't print over/under a stale hint block. If a menu item was
|
|
298
298
|
// highlighted (↑/↓), RUN that command instead of the raw typed line.
|
|
299
299
|
let submitted = l;
|
|
300
|
-
if (
|
|
300
|
+
if (slashOverlayActive) {
|
|
301
|
+
// A highlighted menu item (↑/↓) RUNS that command instead of the raw typed line.
|
|
301
302
|
if (slashSel >= 0 && slashNames[slashSel]) submitted = slashNames[slashSel];
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
303
|
+
closeSlashOverlay(); // wipe the menu, re-enable readline, restore history
|
|
304
|
+
// readline's own newline echo was suppressed during the overlay — emit it so the
|
|
305
|
+
// command's output starts on a fresh line, not over the ">> …" input line (#109).
|
|
306
|
+
process.stdout.write("\r\n");
|
|
306
307
|
}
|
|
307
|
-
// Overlay is gone — restore readline history so ↑/↓ recall past tasks again (bug #109).
|
|
308
|
-
slashRestoreHistory();
|
|
309
308
|
const clean = stripAnsiEscapes(submitted);
|
|
310
309
|
if (_lineWaiter) {
|
|
311
310
|
const w = _lineWaiter;
|
|
@@ -324,7 +323,6 @@ rl.on("line", (l) => {
|
|
|
324
323
|
// runs the highlighted command, and it DISAPPEARS when you clear the slash — no permanent
|
|
325
324
|
// scrollback copies. Relative cursor moves so it survives terminal scrolling.
|
|
326
325
|
// (slashSel / slashNames / slashPrefix are declared above, near rl.on("line").)
|
|
327
|
-
const inputCol = () => 4 + rl.cursor; // ">> " is 3 cols; content starts at col 4 (1-based)
|
|
328
326
|
// While the slash-hint overlay is open, EMPTY readline's history so ↑/↓ don't recall a
|
|
329
327
|
// history entry and trigger readline's OWN line-refresh — that refresh fought our overlay
|
|
330
328
|
// and reprinted the whole ">> /" + hint block on every arrow press (bug #109). With no
|
|
@@ -345,32 +343,62 @@ function slashRestoreHistory() {
|
|
|
345
343
|
rl.historyIndex = -1;
|
|
346
344
|
}
|
|
347
345
|
}
|
|
348
|
-
|
|
349
|
-
|
|
346
|
+
// While the overlay is active WE own all terminal drawing: readline's own echo +
|
|
347
|
+
// line-refresh are no-op'd (see slashOverlayActive in _writeToOutput/_refreshLine
|
|
348
|
+
// below), exactly like the /server + approval pickers. That's what makes the redraw
|
|
349
|
+
// stable — readline can't clearScreenDown over our menu or fight our cursor (bug #109,
|
|
350
|
+
// which the earlier relative-cursor overlay hit whenever readline refreshed or the
|
|
351
|
+
// menu was near the bottom of the screen and scrolled).
|
|
352
|
+
let slashOverlayActive = false;
|
|
353
|
+
|
|
354
|
+
// Redraw the input line (">> " + typed text) AND the command menu below it, fully
|
|
355
|
+
// in place. On first activation we scroll N blank rows into existence below the input
|
|
356
|
+
// line then return to it, so every later redraw writes into that reserved space
|
|
357
|
+
// WITHOUT scrolling — which keeps the save/restore-cursor (ESC 7 / ESC 8) anchor valid.
|
|
358
|
+
function renderSlashOverlay(sel) {
|
|
359
|
+
const line = rl.line;
|
|
360
|
+
const cmds = filteredCommands(line);
|
|
361
|
+
slashNames = cmds.map((c) => c.name);
|
|
362
|
+
if (sel >= cmds.length) sel = cmds.length - 1;
|
|
363
|
+
slashSel = sel;
|
|
364
|
+
slashPrefix = line;
|
|
365
|
+
const menu = hintRows(cmds, sel);
|
|
366
|
+
const n = menu.length;
|
|
367
|
+
|
|
368
|
+
if (!slashOverlayActive) {
|
|
369
|
+
slashOverlayActive = true;
|
|
370
|
+
slashNeutralizeHistory();
|
|
371
|
+
process.stdout.write("\n".repeat(n) + `\x1b[${n}A`); // reserve n rows, back to input
|
|
372
|
+
slashHintRows = n;
|
|
373
|
+
} else if (n !== slashHintRows) {
|
|
374
|
+
// The filtered list changed size: clear the old menu, re-reserve.
|
|
375
|
+
process.stdout.write("\x1b7\n\x1b[J\x1b8");
|
|
376
|
+
process.stdout.write("\n".repeat(n) + `\x1b[${n}A`);
|
|
377
|
+
slashHintRows = n;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Input line (carriage-return, clear, prompt + typed), then the menu below, anchored
|
|
381
|
+
// by ESC 7 (save at end of input) / ESC 8 (restore) so the caret ends on the input.
|
|
382
|
+
let out = "\r\x1b[2K" + PROMPT + line + "\x1b7";
|
|
383
|
+
for (const r of menu) out += "\n\x1b[2K" + r;
|
|
384
|
+
out += "\x1b8";
|
|
385
|
+
process.stdout.write(out);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Close the overlay: erase the menu below, keep the typed input line, hand drawing back
|
|
389
|
+
// to readline. Callers that changed the line to a non-slash value should refresh after.
|
|
390
|
+
function closeSlashOverlay() {
|
|
391
|
+
if (!slashOverlayActive) {
|
|
350
392
|
slashRestoreHistory();
|
|
351
393
|
return;
|
|
352
394
|
}
|
|
353
|
-
process.stdout.write("\n\x1b[J"
|
|
395
|
+
process.stdout.write("\x1b7\n\x1b[J\x1b8"); // save, wipe below, restore to input line
|
|
396
|
+
slashOverlayActive = false;
|
|
354
397
|
slashHintRows = 0;
|
|
355
398
|
slashSel = -1;
|
|
356
399
|
slashNames = [];
|
|
357
400
|
slashRestoreHistory();
|
|
358
401
|
}
|
|
359
|
-
function drawSlashHint(prefix, sel) {
|
|
360
|
-
slashNeutralizeHistory();
|
|
361
|
-
const cmds = filteredCommands(prefix);
|
|
362
|
-
slashNames = cmds.map((c) => c.name);
|
|
363
|
-
if (sel >= cmds.length) sel = cmds.length - 1;
|
|
364
|
-
slashSel = sel;
|
|
365
|
-
const rows = hintRows(cmds, sel);
|
|
366
|
-
const body = rows.map((r) => "\x1b[K" + r).join("\n");
|
|
367
|
-
let out = "";
|
|
368
|
-
if (slashHintRows > 0) out += "\n\x1b[J\x1b[1A"; // wipe previous block, back to input row
|
|
369
|
-
out += "\n" + body; // draw below the input line
|
|
370
|
-
out += `\x1b[${rows.length}A\x1b[${inputCol()}G`; // back up to input line + column
|
|
371
|
-
process.stdout.write(out);
|
|
372
|
-
slashHintRows = rows.length;
|
|
373
|
-
}
|
|
374
402
|
if (process.stdin.isTTY) {
|
|
375
403
|
process.stdin.on("keypress", (_ch, key) => {
|
|
376
404
|
// An arrow-key list picker (/server) is up → ↑/↓ move the highlight, Enter chooses.
|
|
@@ -397,24 +425,27 @@ if (process.stdin.isTTY) {
|
|
|
397
425
|
}
|
|
398
426
|
// Enter is handled by rl.on("line") — don't redraw the hint on the way out.
|
|
399
427
|
if (key && (key.name === "return" || key.name === "enter")) return;
|
|
400
|
-
// ↑/↓ while the menu is up = move the highlight IN PLACE.
|
|
401
|
-
// (
|
|
402
|
-
//
|
|
403
|
-
if (
|
|
428
|
+
// ↑/↓ while the menu is up = move the highlight IN PLACE. readline drawing is
|
|
429
|
+
// suppressed (slashOverlayActive) and history neutralized, so its own ↑/↓ do
|
|
430
|
+
// nothing — we just move the selection and re-render the overlay (bug #109).
|
|
431
|
+
if (slashOverlayActive && key && (key.name === "up" || key.name === "down")) {
|
|
404
432
|
rl.historyIndex = -1;
|
|
405
433
|
const n = slashNames.length;
|
|
406
434
|
if (n > 0) {
|
|
407
435
|
slashSel =
|
|
408
436
|
key.name === "down" ? (slashSel + 1 + n) % n : (slashSel - 1 + n) % n;
|
|
409
437
|
}
|
|
410
|
-
|
|
438
|
+
renderSlashOverlay(slashSel);
|
|
411
439
|
return;
|
|
412
440
|
}
|
|
413
441
|
if (rl.line.startsWith("/")) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
} else {
|
|
417
|
-
|
|
442
|
+
// Typing narrows the list and resets the selection to none.
|
|
443
|
+
renderSlashOverlay(-1);
|
|
444
|
+
} else if (slashOverlayActive) {
|
|
445
|
+
// The line no longer starts with "/" (e.g. backspaced the slash away): tear down
|
|
446
|
+
// the overlay and let readline redraw the now-normal line.
|
|
447
|
+
closeSlashOverlay();
|
|
448
|
+
rl._refreshLine();
|
|
418
449
|
}
|
|
419
450
|
});
|
|
420
451
|
}
|
|
@@ -1115,7 +1146,9 @@ let globalOutputTokens = 0;
|
|
|
1115
1146
|
// writes to stdout directly, so it's unaffected — only readline's echo is swallowed.
|
|
1116
1147
|
const _origWriteToOutput = rl._writeToOutput ? rl._writeToOutput.bind(rl) : null;
|
|
1117
1148
|
rl._writeToOutput = (s) => {
|
|
1118
|
-
|
|
1149
|
+
// slashOverlayActive: the slash-command overlay owns drawing (input line + menu), so
|
|
1150
|
+
// readline's own echo must be swallowed or it fights the overlay (bug #109).
|
|
1151
|
+
if (following || listPickerActive || slashOverlayActive) return;
|
|
1119
1152
|
if (_origWriteToOutput) _origWriteToOutput(s);
|
|
1120
1153
|
else process.stdout.write(s);
|
|
1121
1154
|
};
|
|
@@ -1125,7 +1158,9 @@ rl._writeToOutput = (s) => {
|
|
|
1125
1158
|
// ZERO terminal output.
|
|
1126
1159
|
const _origRefreshLine = rl._refreshLine ? rl._refreshLine.bind(rl) : null;
|
|
1127
1160
|
rl._refreshLine = () => {
|
|
1128
|
-
|
|
1161
|
+
// Suppress readline's line refresh (which does clearScreenDown → would wipe our menu)
|
|
1162
|
+
// while the slash overlay owns the screen. We redraw the input line ourselves (#109).
|
|
1163
|
+
if (following || listPickerActive || slashOverlayActive) return;
|
|
1129
1164
|
if (_origRefreshLine) _origRefreshLine();
|
|
1130
1165
|
};
|
|
1131
1166
|
|
|
@@ -2004,6 +2039,8 @@ async function main() {
|
|
|
2004
2039
|
process.stdout.write(red("\n^C "));
|
|
2005
2040
|
}
|
|
2006
2041
|
} else {
|
|
2042
|
+
// Ctrl+C at a prompt with the slash overlay open = dismiss the overlay first (#109).
|
|
2043
|
+
if (slashOverlayActive) closeSlashOverlay();
|
|
2007
2044
|
process.stdout.write(dim("\n(/exit to quit)\n"));
|
|
2008
2045
|
// Discard anything half-typed (Ctrl-C at a prompt means "never mind") and
|
|
2009
2046
|
// redraw through readline so its cursor tracking stays right.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiens.nguyen/gonext-local-worker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.307",
|
|
4
4
|
"description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|