@taj-special/dravix-code 1.1.22 → 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/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
- const HINT_TEXT = (C) => colors.muted(' ') + C('Tab') + colors.muted(' path complete ') +
839
- C('@') + colors.muted(' file picker ') +
840
- C('Ctrl+C') + colors.muted(' cancel ') +
841
- C('/help') + colors.muted(' commands');
842
- async function readLine(prompt, cwd, layout) {
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
- layout.resize();
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(`\x1b[${row};1H\x1b[2K` +
982
- colors.dim(' ╭─ ') + colors.primary(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮'));
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(`\x1b[${row};1H\x1b[2K` +
989
- colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1005
- colors.dim(' │') + ` ${mark} ` + name + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1015
- colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) +
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
- const totalRows = 2 + atBoxLines;
1024
- const startRow = Math.max(layout.divRow - totalRows, 1);
1025
- process.stdout.write('\x1b7');
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(`\x1b[${row};1H\x1b[2K` +
1056
- colors.dim(' ╭─ ') + colors.primary(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮'));
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(`\x1b[${row};1H\x1b[2K` +
1062
- colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1076
- colors.dim(' │') + ` ${mark} ` + namePaint + ' ' + descPaint + descPad + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1085
- colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) +
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
- const totalRows = 2 + slashBoxLines;
1094
- const startRow = Math.max(layout.divRow - totalRows, 1);
1095
- process.stdout.write('\x1b7');
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(`\x1b[${row};1H\x1b[2K` +
1127
- colors.dim(' ╭─ ') + TC(qLabel) + colors.dim(' ' + '─'.repeat(hDashes) + '╮'));
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(`\x1b[${row};1H\x1b[2K` +
1133
- colors.dim(' │') + ' ' + colors.muted(msg) + pad + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1148
- colors.dim(' │') + ` ${mark} ` + name + colors.dim('│'));
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(`\x1b[${row};1H\x1b[2K` +
1157
- colors.dim(' ╰' + '─'.repeat(Math.max(fLeft, 0))) +
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
- const totalRows = 2 + tabBoxLines;
1166
- const startRow = Math.max(layout.divRow - totalRows, 1);
1167
- process.stdout.write('\x1b7');
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 = layout.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(`\x1b[${layout.inputRow};1H\x1b[2K${inp}`);
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
- // Clear the fixed input area
1214
- layout.clearInput();
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
- // Move into the chat scroll region and print the user message
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('\n' + msgBg(fillMsg(disp)) + '\n');
1223
+ process.stdout.write(msgBg(fillMsg(disp)) + '\n');
1231
1224
  }
1232
1225
  else {
1233
- process.stdout.write('\n' + msgBg(fillMsg(text)) + '\n');
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 chat area, reinit layout
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
- layout.clearScrollRegion();
1295
- layout.redrawDivider();
1296
- layout.drawHint(HINT_TEXT(C));
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 {
@@ -2245,7 +2233,7 @@ export async function startRepl(cwd) {
2245
2233
  process.stdout.write(msgBgQ((' > ' + q.text + ' ').padEnd(cols)) + '\n');
2246
2234
  }
2247
2235
  else {
2248
- result = await readLine(PROMPT, activeCwd, layout);
2236
+ result = await readLine(PROMPT, activeCwd);
2249
2237
  }
2250
2238
  if (!result)
2251
2239
  continue;
@@ -52,6 +52,7 @@ export class ChatLayout {
52
52
  this.redrawDivider();
53
53
  process.stdout.write(`\x1b[${this.inputRow};1H\x1b[2K`);
54
54
  process.stdout.write(`\x1b[${this.hintRow};1H\x1b[2K`);
55
+ process.stdout.write(`\x1b[${this.inputRow};1H`);
55
56
  }
56
57
  /** Clear all chat lines in the scroll region. */
57
58
  clearScrollRegion() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taj-special/dravix-code",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "AI-powered coding assistant CLI — Dravix Code",
5
5
  "type": "module",
6
6
  "bin": {