@taj-special/dravix-code 1.1.23 → 1.1.24
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/index.js +1 -0
- package/dist/cli/repl.js +127 -147
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -265,6 +265,7 @@ async function main() {
|
|
|
265
265
|
console.log(colors.muted(' Project ') + W(path.basename(cwd)));
|
|
266
266
|
console.log(colors.muted(' Path ') + DIM(cwd));
|
|
267
267
|
console.log(DIM(' ' + '─'.repeat(45)));
|
|
268
|
+
console.log(colors.muted(' ') + C('Tab') + colors.muted(' path complete ') + C('@') + colors.muted(' file picker ') + C('Ctrl+C') + colors.muted(' cancel ') + C('/help') + colors.muted(' commands'));
|
|
268
269
|
process.stdout.write('\n');
|
|
269
270
|
await startRepl(cwd);
|
|
270
271
|
}
|
package/dist/cli/repl.js
CHANGED
|
@@ -10,7 +10,6 @@ import { printOpResult, printError, printInfo, colors } from '../utils/display.j
|
|
|
10
10
|
import { saveConversation, loadConversation, listConversations, generateTitle, generateId } from '../services/conversations.js';
|
|
11
11
|
import { getToken } from '../services/auth.js';
|
|
12
12
|
import { checkUsage, reportUsage, estimateTokens, usageBar, fmtNum, formatResetTime } from '../services/usage.js';
|
|
13
|
-
import { ChatLayout } from '../utils/layout.js';
|
|
14
13
|
let _serverWebDesignerSkill = '';
|
|
15
14
|
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
16
15
|
const SLASH_COMMANDS = [
|
|
@@ -835,14 +834,11 @@ async function askPermission(label, key, alwaysAllowed, noAlways, diffShown, pre
|
|
|
835
834
|
process.stdin.on('data', onData);
|
|
836
835
|
});
|
|
837
836
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
const C = chalk.hex('#818cf8');
|
|
844
|
-
layout.drawHint(HINT_TEXT(C));
|
|
845
|
-
layout.posInput(prompt);
|
|
837
|
+
async function readLine(prompt, cwd) {
|
|
838
|
+
let SEP = colors.dim(' ' + '─'.repeat(Math.max((process.stdout.columns ?? 80) - 4, 40)));
|
|
839
|
+
let sepVisualLen = 2 + Math.max((process.stdout.columns ?? 80) - 4, 40);
|
|
840
|
+
process.stdout.write('\n' + SEP + '\n' + prompt);
|
|
841
|
+
process.stdout.write('\r\n' + SEP + '\x1b[1A\r' + prompt);
|
|
846
842
|
return new Promise((resolve) => {
|
|
847
843
|
let prefix = '';
|
|
848
844
|
let pasteBlock = null;
|
|
@@ -870,25 +866,41 @@ async function readLine(prompt, cwd, layout) {
|
|
|
870
866
|
let tabDrawn = false;
|
|
871
867
|
let tabPreWord = ''; // prefix text before the tab-completed token
|
|
872
868
|
function onResize() {
|
|
873
|
-
|
|
869
|
+
const newCols = process.stdout.columns ?? 80;
|
|
870
|
+
const oldSepRows = Math.ceil(sepVisualLen / newCols);
|
|
871
|
+
SEP = colors.dim(' ' + '─'.repeat(Math.max(newCols - 4, 40)));
|
|
872
|
+
sepVisualLen = 2 + Math.max(newCols - 4, 40);
|
|
874
873
|
if (atMode) {
|
|
874
|
+
for (let i = 0; i < atBoxLines + 3; i++)
|
|
875
|
+
process.stdout.write('\x1b[1A');
|
|
876
|
+
process.stdout.write('\r\x1b[0J');
|
|
875
877
|
atDrawn = false;
|
|
876
878
|
atBoxLines = 0;
|
|
877
879
|
drawPicker();
|
|
878
880
|
}
|
|
879
881
|
else if (slashMode) {
|
|
882
|
+
for (let i = 0; i < slashBoxLines + 3; i++)
|
|
883
|
+
process.stdout.write('\x1b[1A');
|
|
884
|
+
process.stdout.write('\r\x1b[0J');
|
|
880
885
|
slashDrawn = false;
|
|
881
886
|
slashBoxLines = 0;
|
|
882
887
|
drawSlashPicker();
|
|
883
888
|
}
|
|
884
889
|
else if (tabMode) {
|
|
890
|
+
for (let i = 0; i < tabBoxLines + 3; i++)
|
|
891
|
+
process.stdout.write('\x1b[1A');
|
|
892
|
+
process.stdout.write('\r\x1b[0J');
|
|
885
893
|
tabDrawn = false;
|
|
886
894
|
tabBoxLines = 0;
|
|
887
895
|
drawTabPicker();
|
|
888
896
|
}
|
|
889
897
|
else {
|
|
898
|
+
process.stdout.write('\r\x1b[K');
|
|
899
|
+
process.stdout.write('\x1b[1B\x1b[2K\x1b[1A');
|
|
900
|
+
for (let i = 0; i < oldSepRows + 1; i++)
|
|
901
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
902
|
+
process.stdout.write('\n' + SEP + '\n');
|
|
890
903
|
redraw();
|
|
891
|
-
layout.drawHint(HINT_TEXT(C));
|
|
892
904
|
}
|
|
893
905
|
}
|
|
894
906
|
process.stdout.on('resize', onResize);
|
|
@@ -957,37 +969,35 @@ async function readLine(prompt, cwd, layout) {
|
|
|
957
969
|
// then \x1b[2A\x1b[2K to skip bot-sep and clear input
|
|
958
970
|
let atDrawn = false;
|
|
959
971
|
function drawPicker() {
|
|
972
|
+
if (atDrawn) {
|
|
973
|
+
for (let i = 0; i < atBoxLines; i++)
|
|
974
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
975
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
process.stdout.write('\r\x1b[K');
|
|
979
|
+
atDrawn = true;
|
|
980
|
+
}
|
|
981
|
+
atBoxLines = 0;
|
|
982
|
+
const inputLine = colors.primary(' › ') + chalk.white(prefix) +
|
|
983
|
+
(pasteBlock !== null ? colors.muted(`[paste: ${pasteCount} lines]`) + chalk.white(suffix) : '') +
|
|
984
|
+
chalk.hex('#818cf8')('@') + chalk.white(atQuery);
|
|
985
|
+
process.stdout.write(inputLine + '\r\n' + SEP + '\r\n');
|
|
986
|
+
const DW = Math.min(Math.max((process.stdout.columns ?? 80) - 6, 44), 72);
|
|
987
|
+
const IW = DW - 6;
|
|
960
988
|
const filtered = filterFiles(atQuery);
|
|
961
989
|
if (atSel >= filtered.length && filtered.length > 0)
|
|
962
990
|
atSel = filtered.length - 1;
|
|
963
991
|
const shown = filtered.slice(0, 10);
|
|
964
|
-
const DW = Math.min(Math.max(layout.cols - 6, 44), 72);
|
|
965
|
-
const IW = DW - 6;
|
|
966
|
-
const itemCount = Math.max(shown.length, 1);
|
|
967
|
-
atBoxLines = itemCount + 2; // header + items/no-match + footer
|
|
968
|
-
const totalRows = 2 + atBoxLines; // input preview + blank + box
|
|
969
|
-
const startRow = Math.max(layout.divRow - totalRows, 1);
|
|
970
|
-
process.stdout.write('\x1b7'); // save cursor at inputRow
|
|
971
|
-
// Input preview
|
|
972
|
-
const inputLine = colors.primary(' › ') + chalk.white(prefix) +
|
|
973
|
-
(pasteBlock !== null ? colors.muted(`[paste: ${pasteCount} lines]`) + chalk.white(suffix) : '') +
|
|
974
|
-
chalk.hex('#818cf8')('@') + chalk.white(atQuery);
|
|
975
|
-
process.stdout.write(`\x1b[${startRow};1H\x1b[2K${inputLine}`);
|
|
976
|
-
process.stdout.write(`\x1b[${startRow + 1};1H\x1b[2K`); // blank separator
|
|
977
|
-
let row = startRow + 2;
|
|
978
|
-
// Header
|
|
979
992
|
const qLabel = atQuery ? `@${atQuery}` : 'files';
|
|
980
993
|
const hDashes = Math.max(DW - 5 - qLabel.length, 1);
|
|
981
|
-
process.stdout.write(
|
|
982
|
-
|
|
983
|
-
row++;
|
|
984
|
-
// Items
|
|
994
|
+
process.stdout.write(colors.dim(' ╭─ ') + colors.primary(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮') + '\n');
|
|
995
|
+
atBoxLines++;
|
|
985
996
|
if (shown.length === 0) {
|
|
986
997
|
const msg = 'no matches';
|
|
987
998
|
const pad = ' '.repeat(Math.max(IW - msg.length, 0));
|
|
988
|
-
process.stdout.write(
|
|
989
|
-
|
|
990
|
-
row++;
|
|
999
|
+
process.stdout.write(colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│') + '\n');
|
|
1000
|
+
atBoxLines++;
|
|
991
1001
|
}
|
|
992
1002
|
else {
|
|
993
1003
|
for (let i = 0; i < shown.length; i++) {
|
|
@@ -1001,66 +1011,60 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1001
1011
|
: sel ? colors.primary.bold(clip) + pad
|
|
1002
1012
|
: isDir ? chalk.hex('#38bdf8')(clip) + pad
|
|
1003
1013
|
: chalk.hex('#94a3b8')(clip + pad);
|
|
1004
|
-
process.stdout.write(
|
|
1005
|
-
|
|
1006
|
-
row++;
|
|
1014
|
+
process.stdout.write(colors.dim(' │') + ` ${mark} ` + name + colors.dim('│') + '\n');
|
|
1015
|
+
atBoxLines++;
|
|
1007
1016
|
}
|
|
1008
1017
|
}
|
|
1009
|
-
// Footer
|
|
1010
1018
|
const hint = ' ↑↓ Enter Esc ';
|
|
1011
1019
|
const fInner = DW - 2 - hint.length;
|
|
1012
1020
|
const fLeft = Math.floor(fInner / 2);
|
|
1013
1021
|
const fRight = fInner - fLeft;
|
|
1014
|
-
process.stdout.write(
|
|
1015
|
-
|
|
1016
|
-
colors.muted(hint) +
|
|
1017
|
-
colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯'));
|
|
1018
|
-
atDrawn = true;
|
|
1019
|
-
process.stdout.write('\x1b8'); // restore cursor to inputRow
|
|
1022
|
+
process.stdout.write(colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) + colors.muted(hint) + colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯') + '\n');
|
|
1023
|
+
atBoxLines++;
|
|
1020
1024
|
}
|
|
1021
1025
|
function closePicker() {
|
|
1022
1026
|
if (atDrawn) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
process.stdout.write('\
|
|
1026
|
-
for (let r = startRow; r < layout.divRow; r++) {
|
|
1027
|
-
process.stdout.write(`\x1b[${r};1H\x1b[2K`);
|
|
1028
|
-
}
|
|
1029
|
-
process.stdout.write('\x1b8');
|
|
1027
|
+
for (let i = 0; i < atBoxLines; i++)
|
|
1028
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
1029
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1030
1030
|
atDrawn = false;
|
|
1031
1031
|
}
|
|
1032
|
+
else {
|
|
1033
|
+
process.stdout.write('\r\x1b[K');
|
|
1034
|
+
}
|
|
1032
1035
|
atBoxLines = 0;
|
|
1033
1036
|
atMode = false;
|
|
1034
1037
|
atQuery = '';
|
|
1035
1038
|
atSel = 0;
|
|
1036
1039
|
}
|
|
1037
1040
|
function drawSlashPicker() {
|
|
1041
|
+
if (slashDrawn) {
|
|
1042
|
+
for (let i = 0; i < slashBoxLines; i++)
|
|
1043
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
1044
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1045
|
+
}
|
|
1046
|
+
else {
|
|
1047
|
+
process.stdout.write('\r\x1b[K');
|
|
1048
|
+
slashDrawn = true;
|
|
1049
|
+
}
|
|
1050
|
+
slashBoxLines = 0;
|
|
1051
|
+
const inputLine = colors.primary(' › ') + colors.primary('/') + chalk.white(slashQuery);
|
|
1052
|
+
process.stdout.write(inputLine + '\r\n' + SEP + '\r\n');
|
|
1053
|
+
const DW = Math.min(Math.max((process.stdout.columns ?? 80) - 6, 44), 72);
|
|
1054
|
+
const nameW = 10;
|
|
1055
|
+
const descW = DW - nameW - 8;
|
|
1038
1056
|
const filtered = filterSlash(slashQuery);
|
|
1039
1057
|
if (slashSel >= filtered.length && filtered.length > 0)
|
|
1040
1058
|
slashSel = filtered.length - 1;
|
|
1041
|
-
const DW = Math.min(Math.max(layout.cols - 6, 44), 72);
|
|
1042
|
-
const nameW = 10;
|
|
1043
|
-
const descW = DW - nameW - 8;
|
|
1044
|
-
const itemCount = Math.max(filtered.length, 1);
|
|
1045
|
-
slashBoxLines = itemCount + 2;
|
|
1046
|
-
const totalRows = 2 + slashBoxLines;
|
|
1047
|
-
const startRow = Math.max(layout.divRow - totalRows, 1);
|
|
1048
|
-
process.stdout.write('\x1b7');
|
|
1049
|
-
const inputLine = colors.primary(' › ') + colors.primary('/') + chalk.white(slashQuery);
|
|
1050
|
-
process.stdout.write(`\x1b[${startRow};1H\x1b[2K${inputLine}`);
|
|
1051
|
-
process.stdout.write(`\x1b[${startRow + 1};1H\x1b[2K`);
|
|
1052
|
-
let row = startRow + 2;
|
|
1053
1059
|
const qLabel = slashQuery ? `/${slashQuery}` : 'commands';
|
|
1054
1060
|
const hDashes = Math.max(DW - 5 - qLabel.length, 1);
|
|
1055
|
-
process.stdout.write(
|
|
1056
|
-
|
|
1057
|
-
row++;
|
|
1061
|
+
process.stdout.write(colors.dim(' ╭─ ') + colors.primary(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮') + '\n');
|
|
1062
|
+
slashBoxLines++;
|
|
1058
1063
|
if (filtered.length === 0) {
|
|
1059
1064
|
const msg = 'no matching commands';
|
|
1060
1065
|
const pad = ' '.repeat(Math.max(DW - 4 - msg.length, 0));
|
|
1061
|
-
process.stdout.write(
|
|
1062
|
-
|
|
1063
|
-
row++;
|
|
1066
|
+
process.stdout.write(colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│') + '\n');
|
|
1067
|
+
slashBoxLines++;
|
|
1064
1068
|
}
|
|
1065
1069
|
else {
|
|
1066
1070
|
for (let i = 0; i < filtered.length; i++) {
|
|
@@ -1072,66 +1076,61 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1072
1076
|
const descPad = ' '.repeat(Math.max(descW - descStr.length, 0));
|
|
1073
1077
|
const namePaint = sel ? colors.primary.bold(nameStr) : chalk.hex('#818cf8')(nameStr);
|
|
1074
1078
|
const descPaint = sel ? colors.muted(descStr) : chalk.hex('#4b5563')(descStr);
|
|
1075
|
-
process.stdout.write(
|
|
1076
|
-
|
|
1077
|
-
row++;
|
|
1079
|
+
process.stdout.write(colors.dim(' │') + ` ${mark} ` + namePaint + ' ' + descPaint + descPad + colors.dim('│') + '\n');
|
|
1080
|
+
slashBoxLines++;
|
|
1078
1081
|
}
|
|
1079
1082
|
}
|
|
1080
1083
|
const hint = ' ↑↓ Enter Esc ';
|
|
1081
1084
|
const fInner = DW - 2 - hint.length;
|
|
1082
1085
|
const fLeft = Math.floor(fInner / 2);
|
|
1083
1086
|
const fRight = fInner - fLeft;
|
|
1084
|
-
process.stdout.write(
|
|
1085
|
-
|
|
1086
|
-
colors.muted(hint) +
|
|
1087
|
-
colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯'));
|
|
1088
|
-
slashDrawn = true;
|
|
1089
|
-
process.stdout.write('\x1b8');
|
|
1087
|
+
process.stdout.write(colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) + colors.muted(hint) + colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯') + '\n');
|
|
1088
|
+
slashBoxLines++;
|
|
1090
1089
|
}
|
|
1091
1090
|
function closeSlashPicker() {
|
|
1092
1091
|
if (slashDrawn) {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
process.stdout.write('\
|
|
1096
|
-
for (let r = startRow; r < layout.divRow; r++) {
|
|
1097
|
-
process.stdout.write(`\x1b[${r};1H\x1b[2K`);
|
|
1098
|
-
}
|
|
1099
|
-
process.stdout.write('\x1b8');
|
|
1092
|
+
for (let i = 0; i < slashBoxLines; i++)
|
|
1093
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
1094
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1100
1095
|
slashDrawn = false;
|
|
1101
1096
|
}
|
|
1097
|
+
else {
|
|
1098
|
+
process.stdout.write('\r\x1b[K');
|
|
1099
|
+
}
|
|
1102
1100
|
slashBoxLines = 0;
|
|
1103
1101
|
slashMode = false;
|
|
1104
1102
|
slashQuery = '';
|
|
1105
1103
|
slashSel = 0;
|
|
1106
1104
|
}
|
|
1107
1105
|
function drawTabPicker() {
|
|
1106
|
+
if (tabDrawn) {
|
|
1107
|
+
for (let i = 0; i < tabBoxLines; i++)
|
|
1108
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
1109
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
process.stdout.write('\r\x1b[K');
|
|
1113
|
+
tabDrawn = true;
|
|
1114
|
+
}
|
|
1115
|
+
tabBoxLines = 0;
|
|
1116
|
+
const TC = chalk.hex('#34d399');
|
|
1117
|
+
const inputLine = colors.primary(' › ') + chalk.white(tabPreWord) + TC(tabQuery);
|
|
1118
|
+
process.stdout.write(inputLine + '\r\n' + SEP + '\r\n');
|
|
1119
|
+
const DW = Math.min(Math.max((process.stdout.columns ?? 80) - 6, 44), 72);
|
|
1120
|
+
const IW = DW - 6;
|
|
1108
1121
|
const filtered = filterFiles(tabQuery);
|
|
1109
1122
|
if (tabSel >= filtered.length && filtered.length > 0)
|
|
1110
1123
|
tabSel = filtered.length - 1;
|
|
1111
1124
|
const shown = filtered.slice(0, 10);
|
|
1112
|
-
const DW = Math.min(Math.max(layout.cols - 6, 44), 72);
|
|
1113
|
-
const IW = DW - 6;
|
|
1114
|
-
const TC = chalk.hex('#34d399');
|
|
1115
|
-
const itemCount = Math.max(shown.length, 1);
|
|
1116
|
-
tabBoxLines = itemCount + 2;
|
|
1117
|
-
const totalRows = 2 + tabBoxLines;
|
|
1118
|
-
const startRow = Math.max(layout.divRow - totalRows, 1);
|
|
1119
|
-
process.stdout.write('\x1b7');
|
|
1120
|
-
const inputLine = colors.primary(' › ') + chalk.white(tabPreWord) + TC(tabQuery);
|
|
1121
|
-
process.stdout.write(`\x1b[${startRow};1H\x1b[2K${inputLine}`);
|
|
1122
|
-
process.stdout.write(`\x1b[${startRow + 1};1H\x1b[2K`);
|
|
1123
|
-
let row = startRow + 2;
|
|
1124
1125
|
const qLabel = tabQuery || 'tab complete';
|
|
1125
1126
|
const hDashes = Math.max(DW - 5 - qLabel.length, 1);
|
|
1126
|
-
process.stdout.write(
|
|
1127
|
-
|
|
1128
|
-
row++;
|
|
1127
|
+
process.stdout.write(colors.dim(' ╭─ ') + TC(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮') + '\n');
|
|
1128
|
+
tabBoxLines++;
|
|
1129
1129
|
if (shown.length === 0) {
|
|
1130
1130
|
const msg = 'no matches';
|
|
1131
1131
|
const pad = ' '.repeat(Math.max(IW - msg.length, 0));
|
|
1132
|
-
process.stdout.write(
|
|
1133
|
-
|
|
1134
|
-
row++;
|
|
1132
|
+
process.stdout.write(colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│') + '\n');
|
|
1133
|
+
tabBoxLines++;
|
|
1135
1134
|
}
|
|
1136
1135
|
else {
|
|
1137
1136
|
for (let i = 0; i < shown.length; i++) {
|
|
@@ -1144,33 +1143,27 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1144
1143
|
const name = sel ? TC.bold(clip) + pad
|
|
1145
1144
|
: isDir ? chalk.hex('#38bdf8')(clip) + pad
|
|
1146
1145
|
: chalk.hex('#94a3b8')(clip + pad);
|
|
1147
|
-
process.stdout.write(
|
|
1148
|
-
|
|
1149
|
-
row++;
|
|
1146
|
+
process.stdout.write(colors.dim(' │') + ` ${mark} ` + name + colors.dim('│') + '\n');
|
|
1147
|
+
tabBoxLines++;
|
|
1150
1148
|
}
|
|
1151
1149
|
}
|
|
1152
1150
|
const hint = ' Tab/↑↓ Enter Esc ';
|
|
1153
1151
|
const fInner = DW - 2 - hint.length;
|
|
1154
1152
|
const fLeft = Math.floor(fInner / 2);
|
|
1155
1153
|
const fRight = fInner - fLeft;
|
|
1156
|
-
process.stdout.write(
|
|
1157
|
-
|
|
1158
|
-
colors.muted(hint) +
|
|
1159
|
-
colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯'));
|
|
1160
|
-
tabDrawn = true;
|
|
1161
|
-
process.stdout.write('\x1b8');
|
|
1154
|
+
process.stdout.write(colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) + colors.muted(hint) + colors.dim('─'.repeat(Math.max(fRight, 0)) + '╯') + '\n');
|
|
1155
|
+
tabBoxLines++;
|
|
1162
1156
|
}
|
|
1163
1157
|
function closeTabPicker() {
|
|
1164
1158
|
if (tabDrawn) {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
process.stdout.write('\
|
|
1168
|
-
for (let r = startRow; r < layout.divRow; r++) {
|
|
1169
|
-
process.stdout.write(`\x1b[${r};1H\x1b[2K`);
|
|
1170
|
-
}
|
|
1171
|
-
process.stdout.write('\x1b8');
|
|
1159
|
+
for (let i = 0; i < tabBoxLines; i++)
|
|
1160
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
1161
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1172
1162
|
tabDrawn = false;
|
|
1173
1163
|
}
|
|
1164
|
+
else {
|
|
1165
|
+
process.stdout.write('\r\x1b[K');
|
|
1166
|
+
}
|
|
1174
1167
|
tabBoxLines = 0;
|
|
1175
1168
|
tabMode = false;
|
|
1176
1169
|
tabQuery = '';
|
|
@@ -1178,7 +1171,7 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1178
1171
|
tabPreWord = '';
|
|
1179
1172
|
}
|
|
1180
1173
|
function redraw() {
|
|
1181
|
-
const cols =
|
|
1174
|
+
const cols = process.stdout.columns ?? 80;
|
|
1182
1175
|
const maxLen = Math.max(cols - 6, 10);
|
|
1183
1176
|
let displayPre = prefix;
|
|
1184
1177
|
if (displayPre.length > maxLen)
|
|
@@ -1191,7 +1184,8 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1191
1184
|
else {
|
|
1192
1185
|
inp = colors.primary(' › ') + chalk.white(displayPre);
|
|
1193
1186
|
}
|
|
1194
|
-
process.stdout.write(
|
|
1187
|
+
process.stdout.write('\r\x1b[K' + inp);
|
|
1188
|
+
process.stdout.write('\r\n' + SEP + '\x1b[1A\r' + inp);
|
|
1195
1189
|
}
|
|
1196
1190
|
function submit() {
|
|
1197
1191
|
if (atMode)
|
|
@@ -1210,15 +1204,14 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1210
1204
|
const text = parts.join('\n');
|
|
1211
1205
|
const lns = parts.length > 0 ? parts : (text ? [text] : []);
|
|
1212
1206
|
cleanup();
|
|
1213
|
-
|
|
1214
|
-
|
|
1207
|
+
process.stdout.write('\r\x1b[K');
|
|
1208
|
+
process.stdout.write('\x1b[1B\x1b[2K');
|
|
1209
|
+
process.stdout.write('\x1b[2A\x1b[2K');
|
|
1215
1210
|
if (!text) {
|
|
1216
1211
|
resolve(null);
|
|
1217
1212
|
return;
|
|
1218
1213
|
}
|
|
1219
|
-
|
|
1220
|
-
layout.enterChat();
|
|
1221
|
-
const cols = layout.cols;
|
|
1214
|
+
const cols = process.stdout.columns ?? 80;
|
|
1222
1215
|
const msgBg = chalk.bgHex('#334155').hex('#f1f5f9');
|
|
1223
1216
|
const fillMsg = (raw) => (' > ' + raw + ' ').padEnd(cols);
|
|
1224
1217
|
if (pasteBlock !== null) {
|
|
@@ -1227,10 +1220,10 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1227
1220
|
`[${pasteCount} lines]`,
|
|
1228
1221
|
suffix.trim() ? suffix.trim() : '',
|
|
1229
1222
|
].filter(Boolean).join(' ');
|
|
1230
|
-
process.stdout.write(
|
|
1223
|
+
process.stdout.write(msgBg(fillMsg(disp)) + '\n');
|
|
1231
1224
|
}
|
|
1232
1225
|
else {
|
|
1233
|
-
process.stdout.write(
|
|
1226
|
+
process.stdout.write(msgBg(fillMsg(text)) + '\n');
|
|
1234
1227
|
}
|
|
1235
1228
|
resolve({ text, lines: lns });
|
|
1236
1229
|
}
|
|
@@ -1283,7 +1276,7 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1283
1276
|
resolve(null);
|
|
1284
1277
|
return;
|
|
1285
1278
|
}
|
|
1286
|
-
// Ctrl+L — clear
|
|
1279
|
+
// Ctrl+L — clear screen, redraw input
|
|
1287
1280
|
if (data === '\x0c') {
|
|
1288
1281
|
if (atMode)
|
|
1289
1282
|
closePicker();
|
|
@@ -1291,10 +1284,9 @@ async function readLine(prompt, cwd, layout) {
|
|
|
1291
1284
|
closeSlashPicker();
|
|
1292
1285
|
if (tabMode)
|
|
1293
1286
|
closeTabPicker();
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
layout.posInput(prompt);
|
|
1287
|
+
console.clear();
|
|
1288
|
+
process.stdout.write('\n' + SEP + '\n' + prompt);
|
|
1289
|
+
process.stdout.write('\r\n' + SEP + '\x1b[1A\r' + prompt);
|
|
1298
1290
|
return;
|
|
1299
1291
|
}
|
|
1300
1292
|
// ── @ picker mode ─────────────────────────────────────────
|
|
@@ -2176,10 +2168,6 @@ export async function startRepl(cwd) {
|
|
|
2176
2168
|
process.stdin.setRawMode(true);
|
|
2177
2169
|
process.stdin.resume();
|
|
2178
2170
|
process.stdin.setEncoding('utf8');
|
|
2179
|
-
// Initialize sticky-bottom layout (scroll region + fixed input bar)
|
|
2180
|
-
const layout = new ChatLayout();
|
|
2181
|
-
layout.init();
|
|
2182
|
-
process.on('exit', () => layout.cleanup());
|
|
2183
2171
|
// Sequential loop — queued input lets user type during AI stream
|
|
2184
2172
|
while (true) {
|
|
2185
2173
|
try {
|
|
@@ -2239,14 +2227,13 @@ export async function startRepl(cwd) {
|
|
|
2239
2227
|
const q = queuedResult;
|
|
2240
2228
|
queuedResult = null;
|
|
2241
2229
|
result = q;
|
|
2242
|
-
// Show queued message
|
|
2243
|
-
layout.enterChat();
|
|
2230
|
+
// Show queued message as if just submitted
|
|
2244
2231
|
const cols = process.stdout.columns ?? 80;
|
|
2245
2232
|
const msgBgQ = chalk.bgHex('#334155').hex('#f1f5f9');
|
|
2246
|
-
process.stdout.write(
|
|
2233
|
+
process.stdout.write(msgBgQ((' > ' + q.text + ' ').padEnd(cols)) + '\n');
|
|
2247
2234
|
}
|
|
2248
2235
|
else {
|
|
2249
|
-
result = await readLine(PROMPT, activeCwd
|
|
2236
|
+
result = await readLine(PROMPT, activeCwd);
|
|
2250
2237
|
}
|
|
2251
2238
|
if (!result)
|
|
2252
2239
|
continue;
|
|
@@ -2255,12 +2242,7 @@ export async function startRepl(cwd) {
|
|
|
2255
2242
|
lastUserLine = line;
|
|
2256
2243
|
// ── Slash commands ──────────────────────────────────────────
|
|
2257
2244
|
if (!skipInput && line.trim() === '/resume') {
|
|
2258
|
-
// Temporarily reset scroll region so picker can use full terminal with relative cursor movement
|
|
2259
|
-
process.stdout.write('\x1b[r');
|
|
2260
2245
|
const convId = await showConversationPicker();
|
|
2261
|
-
// Restore scroll region + fixed rows
|
|
2262
|
-
layout.resize();
|
|
2263
|
-
layout.enterChat();
|
|
2264
2246
|
if (convId) {
|
|
2265
2247
|
const conv = loadConversation(convId);
|
|
2266
2248
|
if (conv) {
|
|
@@ -2300,8 +2282,6 @@ export async function startRepl(cwd) {
|
|
|
2300
2282
|
if (lastUserLine)
|
|
2301
2283
|
queuedResult = { text: lastUserLine, lines: [lastUserLine] };
|
|
2302
2284
|
});
|
|
2303
|
-
// Re-establish scroll region after /clear (console.clear) or other commands
|
|
2304
|
-
layout.resize();
|
|
2305
2285
|
continue;
|
|
2306
2286
|
}
|
|
2307
2287
|
if (!skipInput) {
|