@oxecli/oxe 1.0.64 → 1.0.66
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/cli.js +5 -4
- package/dist/ui.js +37 -11
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -466,7 +466,10 @@ export class CLI {
|
|
|
466
466
|
this.story[this.story.length - 1]["type"] === "user") {
|
|
467
467
|
this.story.pop();
|
|
468
468
|
}
|
|
469
|
-
|
|
469
|
+
// Exit cleanly on: a second Ctrl+C, or a first Ctrl+C while idle
|
|
470
|
+
// (no active query). Only an in-flight query's first Ctrl+C keeps
|
|
471
|
+
// running so the agent can be interrupted without a stray key exiting.
|
|
472
|
+
if (this.interruptPending || !wasActive) {
|
|
470
473
|
this.saveSession(engine);
|
|
471
474
|
await engine.cleanupStoredResponses();
|
|
472
475
|
process.stdout.write("\nClosing terminal session. Goodbye!\n\n");
|
|
@@ -474,9 +477,7 @@ export class CLI {
|
|
|
474
477
|
}
|
|
475
478
|
this.interruptPending = true;
|
|
476
479
|
process.stdout.write("\n");
|
|
477
|
-
process.stdout.write(
|
|
478
|
-
? "\x1b[2mInterrupted agent. Press Ctrl+C again to exit, or type a new prompt.\x1b[0m\n"
|
|
479
|
-
: "\x1b[2mNo active query. Press Ctrl+C again to exit.\x1b[0m\n");
|
|
480
|
+
process.stdout.write("\x1b[2mInterrupted agent. Press Ctrl+C again to exit, or type a new prompt.\x1b[0m\n");
|
|
480
481
|
continue;
|
|
481
482
|
}
|
|
482
483
|
throw err;
|
package/dist/ui.js
CHANGED
|
@@ -902,10 +902,37 @@ export function renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor
|
|
|
902
902
|
const totalRows = body.length + 2;
|
|
903
903
|
return { frame, cursorRow, cursorCol, totalRows };
|
|
904
904
|
}
|
|
905
|
+
/**
|
|
906
|
+
* Generic CSI Shift+Enter detection. The modifier encoding used by CSI-u,
|
|
907
|
+
* legacy and kitty/modifyOtherKeys is a bitmask + 1, where Shift is bit0
|
|
908
|
+
* (so modifier 2 = shift, 4 = shift+alt, 6 = shift+ctrl, ...). Enter has
|
|
909
|
+
* key code 13. Handles:
|
|
910
|
+
* CSI-u / legacy: ESC [ 13 ; M u and ESC [ 13 ; M ~
|
|
911
|
+
* modifyOtherKeys: ESC [ 27 ; M ; 13 ~
|
|
912
|
+
* application: ESC O M
|
|
913
|
+
*/
|
|
914
|
+
function csiShiftEnter(seq) {
|
|
915
|
+
if (seq === "\x1bOM")
|
|
916
|
+
return true;
|
|
917
|
+
// modifyOtherKeys: ESC [ 27 ; M ; 13 ~
|
|
918
|
+
const mod = seq.match(/^\x1b\[27;(\d+);13[~_]$/);
|
|
919
|
+
if (mod) {
|
|
920
|
+
const m = parseInt(mod[1], 10);
|
|
921
|
+
return Number.isInteger(m) && ((m - 1) & 1) === 1;
|
|
922
|
+
}
|
|
923
|
+
// CSI-u / legacy: ESC [ 13 ; M u (or ~ or _)
|
|
924
|
+
const csi = seq.match(/^\x1b\[13;(\d+)[~u_]$/);
|
|
925
|
+
if (csi) {
|
|
926
|
+
const m = parseInt(csi[1], 10);
|
|
927
|
+
return Number.isInteger(m) && ((m - 1) & 1) === 1;
|
|
928
|
+
}
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
905
931
|
export function isShiftEnterKey(str, key) {
|
|
906
932
|
if (!key)
|
|
907
933
|
return false;
|
|
908
934
|
const seq = key.sequence || str || "";
|
|
935
|
+
// Shift modifier reported by readline on a return/enter/linefeed key.
|
|
909
936
|
if (key.shift &&
|
|
910
937
|
(key.name === "return" ||
|
|
911
938
|
key.name === "enter" ||
|
|
@@ -914,13 +941,8 @@ export function isShiftEnterKey(str, key) {
|
|
|
914
941
|
seq === "\n")) {
|
|
915
942
|
return true;
|
|
916
943
|
}
|
|
917
|
-
if (seq
|
|
918
|
-
seq === "\x1b[13;2~" ||
|
|
919
|
-
seq === "\x1b[13;2_" ||
|
|
920
|
-
seq === "\x1b[27;2;13~" ||
|
|
921
|
-
seq === "\x1bOM") {
|
|
944
|
+
if (csiShiftEnter(seq))
|
|
922
945
|
return true;
|
|
923
|
-
}
|
|
924
946
|
return false;
|
|
925
947
|
}
|
|
926
948
|
export const isNewlineKey = isShiftEnterKey;
|
|
@@ -973,6 +995,9 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
973
995
|
if (process.stdin.isTTY) {
|
|
974
996
|
process.stdin.setRawMode(true);
|
|
975
997
|
process.stdout.write("\x1b[?2004h");
|
|
998
|
+
// Enable CSI-u "disambiguate" (flags=1) so a terminal that supports it
|
|
999
|
+
// reports Shift+Enter as a distinct `ESC [ 13 ; 2 u` code instead of
|
|
1000
|
+
// collapsing it into a plain Enter.
|
|
976
1001
|
process.stdout.write("\x1b[>1u");
|
|
977
1002
|
}
|
|
978
1003
|
process.stdin.resume();
|
|
@@ -1003,6 +1028,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1003
1028
|
clearBox();
|
|
1004
1029
|
process.stdin.removeListener("keypress", onKeypress);
|
|
1005
1030
|
process.stdin.pause();
|
|
1031
|
+
showCursor();
|
|
1006
1032
|
if (isErr)
|
|
1007
1033
|
reject(value);
|
|
1008
1034
|
else
|
|
@@ -1319,17 +1345,17 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1319
1345
|
const onKeypress = (str, key) => {
|
|
1320
1346
|
// Reassemble a modifier-prefixed CSI sequence that readline splits up,
|
|
1321
1347
|
// e.g. Shift+Enter arriving as `\x1b[27;2;` + "1" + "3" + "~".
|
|
1322
|
-
if (key?.sequence === "\x1b[27;2;") {
|
|
1323
|
-
modSeq =
|
|
1348
|
+
if (key?.sequence === "\x1b[27;" || key?.sequence === "\x1b[27;2;") {
|
|
1349
|
+
modSeq = key.sequence;
|
|
1324
1350
|
return;
|
|
1325
1351
|
}
|
|
1326
1352
|
if (modSeq) {
|
|
1327
1353
|
modSeq += str || key?.sequence || "";
|
|
1328
|
-
if (modSeq.endsWith("~")) {
|
|
1354
|
+
if (/[~u_]/.test(modSeq.slice(-1)) || modSeq.endsWith("~")) {
|
|
1329
1355
|
const full = modSeq;
|
|
1330
1356
|
modSeq = "";
|
|
1331
|
-
// `\x1b[27;2;13~`
|
|
1332
|
-
if (full
|
|
1357
|
+
// e.g. `\x1b[27;2;13~` = Shift+Enter.
|
|
1358
|
+
if (csiShiftEnter(full)) {
|
|
1333
1359
|
insert("\n");
|
|
1334
1360
|
repaint();
|
|
1335
1361
|
}
|