@tiens.nguyen/gonext-local-worker 1.0.231 → 1.0.233
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 +83 -19
- package/package.json +1 -1
package/gonext-repl.mjs
CHANGED
|
@@ -239,6 +239,13 @@ let slashSel = -1; // highlighted row in the current filtered list (-1 = none)
|
|
|
239
239
|
let slashNames = []; // command names in the current filtered list (for Enter → run)
|
|
240
240
|
let slashPrefix = ""; // the "/…" text the user typed (restored when ↑/↓ recall history)
|
|
241
241
|
rl.on("line", (l) => {
|
|
242
|
+
// A list picker owns the keyboard (its Enter resolves via the keypress handler) — never
|
|
243
|
+
// let that Enter submit a stray empty line into the command loop.
|
|
244
|
+
if (listPickerActive) {
|
|
245
|
+
rl.line = "";
|
|
246
|
+
rl.cursor = 0;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
242
249
|
// While a turn is running, IGNORE typed input entirely — no type-ahead, no queued
|
|
243
250
|
// next question. Only Ctrl+C (handled via SIGINT) does anything mid-turn. Clear the
|
|
244
251
|
// line buffer so nothing the user typed leaks into the next prompt.
|
|
@@ -300,6 +307,14 @@ function drawSlashHint(prefix, sel) {
|
|
|
300
307
|
}
|
|
301
308
|
if (process.stdin.isTTY) {
|
|
302
309
|
process.stdin.on("keypress", (_ch, key) => {
|
|
310
|
+
// An arrow-key list picker (/server) is up → ↑/↓ move the highlight, Enter chooses.
|
|
311
|
+
if (listPickerActive) {
|
|
312
|
+
onListKey(key);
|
|
313
|
+
rl.line = "";
|
|
314
|
+
rl.cursor = 0;
|
|
315
|
+
rl.historyIndex = -1;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
303
318
|
// A command-approval picker is up → arrow keys move the highlight, Enter chooses.
|
|
304
319
|
if (approvalActive) {
|
|
305
320
|
onApprovalKey(key);
|
|
@@ -665,29 +680,23 @@ async function chooseServer() {
|
|
|
665
680
|
console.log(dim(" No deployment servers yet — add them in the web app → Servers.\n"));
|
|
666
681
|
return;
|
|
667
682
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
servers.
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
console.log("");
|
|
683
|
+
// Arrow-key picker: ↑/↓ to move, Enter to choose (no number typing). The list ends with
|
|
684
|
+
// a "none" row to clear the selection. Pre-highlight the current pick if there is one.
|
|
685
|
+
const labels = servers.map((s) => `${s.name} (${s.user}@${s.host})`);
|
|
686
|
+
labels.push("none (clear selection)");
|
|
687
|
+
const activeIdx = servers.findIndex((s) => s.host === selectedServer?.host);
|
|
688
|
+
console.log(dim(" Choose a deployment server (↑/↓ then Enter):"));
|
|
689
|
+
const idx = await pickFromList(labels, activeIdx >= 0 ? activeIdx : 0);
|
|
690
|
+
if (idx < 0) {
|
|
691
|
+
console.log(dim(" (cancelled)\n"));
|
|
678
692
|
return;
|
|
679
693
|
}
|
|
680
|
-
|
|
681
|
-
|
|
694
|
+
if (idx === servers.length) {
|
|
695
|
+
// the trailing "none" row
|
|
682
696
|
selectedServer = null;
|
|
683
697
|
console.log(dim(" ✓ deployment server cleared.\n"));
|
|
684
698
|
return;
|
|
685
699
|
}
|
|
686
|
-
const idx = n - 1;
|
|
687
|
-
if (!Number.isInteger(idx) || idx < 0 || idx >= servers.length) {
|
|
688
|
-
console.log(red(" invalid choice.\n"));
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
700
|
const s = servers[idx];
|
|
692
701
|
selectedServer = { name: s.name, host: s.host, user: s.user };
|
|
693
702
|
console.log(green(` ✓ deploy target → ${s.name} (${s.user}@${s.host})`));
|
|
@@ -784,6 +793,59 @@ function approvalPrompt(command) {
|
|
|
784
793
|
};
|
|
785
794
|
});
|
|
786
795
|
}
|
|
796
|
+
// Generic arrow-key list picker (↑/↓ + Enter) — used by /server so you navigate instead
|
|
797
|
+
// of typing a number. Same mechanism as the Yes/No approval picker above, generalized to
|
|
798
|
+
// N rows. Returns the chosen index (or -1 on Esc/Ctrl+C). Works OUTSIDE a turn, so it also
|
|
799
|
+
// mutes readline echo/refresh (see the _writeToOutput/_refreshLine guards) via listPickerActive.
|
|
800
|
+
let listPickerActive = false;
|
|
801
|
+
let listSel = 0;
|
|
802
|
+
let listItems = [];
|
|
803
|
+
let listResolve = null;
|
|
804
|
+
function drawList(redraw) {
|
|
805
|
+
const n = listItems.length;
|
|
806
|
+
const body = listItems
|
|
807
|
+
.map((it, i) => "\x1b[K" + (i === listSel ? green("▸ " + it) : dim(" " + it)))
|
|
808
|
+
.join("\n");
|
|
809
|
+
process.stdout.write((redraw ? `\x1b[${n}A` : "") + body + "\n");
|
|
810
|
+
}
|
|
811
|
+
function finishList(index) {
|
|
812
|
+
if (!listPickerActive) return;
|
|
813
|
+
listPickerActive = false;
|
|
814
|
+
process.stdout.write(`\x1b[${listItems.length}A\x1b[J`); // wipe the list block
|
|
815
|
+
const r = listResolve;
|
|
816
|
+
listResolve = null;
|
|
817
|
+
listItems = [];
|
|
818
|
+
if (r) r(index);
|
|
819
|
+
}
|
|
820
|
+
function onListKey(key) {
|
|
821
|
+
if (!key) return;
|
|
822
|
+
const n = listItems.length;
|
|
823
|
+
if (key.name === "up") {
|
|
824
|
+
listSel = (listSel - 1 + n) % n;
|
|
825
|
+
drawList(true);
|
|
826
|
+
} else if (key.name === "down") {
|
|
827
|
+
listSel = (listSel + 1) % n;
|
|
828
|
+
drawList(true);
|
|
829
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
830
|
+
finishList(listSel);
|
|
831
|
+
} else if (key.name === "escape" || (key.ctrl && key.name === "c")) {
|
|
832
|
+
finishList(-1);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function pickFromList(items, initialSel = 0) {
|
|
836
|
+
return new Promise((resolve) => {
|
|
837
|
+
if (!process.stdin.isTTY || items.length === 0) {
|
|
838
|
+
resolve(-1);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
listItems = items;
|
|
842
|
+
listSel = Math.max(0, Math.min(initialSel, items.length - 1));
|
|
843
|
+
listResolve = resolve;
|
|
844
|
+
listPickerActive = true;
|
|
845
|
+
drawList(false);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
|
|
787
849
|
// Per-session coding-model override chosen via /model (empty = use the account default).
|
|
788
850
|
// Sent to /agent-ask as codingModelOverride; the API validates it against the whitelist.
|
|
789
851
|
let sessionCodingModel = "";
|
|
@@ -801,7 +863,7 @@ let selectedServer = null;
|
|
|
801
863
|
// writes to stdout directly, so it's unaffected — only readline's echo is swallowed.
|
|
802
864
|
const _origWriteToOutput = rl._writeToOutput ? rl._writeToOutput.bind(rl) : null;
|
|
803
865
|
rl._writeToOutput = (s) => {
|
|
804
|
-
if (following) return;
|
|
866
|
+
if (following || listPickerActive) return;
|
|
805
867
|
if (_origWriteToOutput) _origWriteToOutput(s);
|
|
806
868
|
else process.stdout.write(s);
|
|
807
869
|
};
|
|
@@ -811,7 +873,7 @@ rl._writeToOutput = (s) => {
|
|
|
811
873
|
// ZERO terminal output.
|
|
812
874
|
const _origRefreshLine = rl._refreshLine ? rl._refreshLine.bind(rl) : null;
|
|
813
875
|
rl._refreshLine = () => {
|
|
814
|
-
if (following) return;
|
|
876
|
+
if (following || listPickerActive) return;
|
|
815
877
|
if (_origRefreshLine) _origRefreshLine();
|
|
816
878
|
};
|
|
817
879
|
|
|
@@ -1377,6 +1439,8 @@ async function main() {
|
|
|
1377
1439
|
// the OS delivers a real SIGINT to the process. Attach the same handler to both —
|
|
1378
1440
|
// only one can ever fire for a given mode, so there's no double-handling.
|
|
1379
1441
|
const onInterrupt = () => {
|
|
1442
|
+
// Ctrl+C while a picker is up = cancel it.
|
|
1443
|
+
if (listPickerActive) finishList(-1);
|
|
1380
1444
|
// Ctrl+C while the approval picker is up = decline it (and fall through to also
|
|
1381
1445
|
// cancel the turn) — otherwise the poll loop stays blocked awaiting a choice.
|
|
1382
1446
|
if (approvalActive) finishApproval(false);
|
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.233",
|
|
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",
|