swarm-code 0.1.21 → 0.1.22

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.
@@ -44,51 +44,93 @@ export function readTextInput(_prompt) {
44
44
  process.stdin.setRawMode(true);
45
45
  process.stdin.resume();
46
46
  process.stdin.setEncoding("utf-8");
47
- // How many rows below the top border the cursor sits after drawBox()
47
+ // Tracks cursor position relative to top border after each drawBox()
48
48
  let cursorRowFromTop = 0;
49
- let hasDrawn = false;
50
- function drawBox() {
51
- const out = process.stderr;
52
- const promptVisibleLen = 2; // "❯ "
53
- if (hasDrawn) {
54
- // Move cursor from its current position back to the top border row
55
- if (cursorRowFromTop > 0) {
56
- out.write(`\x1b[${cursorRowFromTop}A`);
57
- }
58
- out.write("\x1b[0G"); // go to column 0
59
- out.write("\x1b[J"); // erase from cursor to end of screen
60
- }
61
- hasDrawn = true;
62
- // Top border — thin dim line
63
- const topLine = `${BORDER_COLOR}${"─".repeat(w)}${RESET}`;
64
- out.write(`${topLine}\n`);
65
- // Content rows — dark background, full width
49
+ let prevTotalRows = 0;
50
+ function buildRows() {
51
+ const promptVisibleLen = 2;
52
+ const rows = [];
53
+ // Top border
54
+ rows.push(`${BORDER_COLOR}${"─".repeat(w)}${RESET}`);
55
+ // Content rows
66
56
  const promptChar = `${ACCENT_COLOR}❯${RESET} `;
67
57
  for (let i = 0; i < linesBuf.length; i++) {
68
58
  const lineText = linesBuf[i];
69
59
  const prefix = i === 0 ? promptChar : `${dim("·")} `;
70
- // How much space for text content
71
60
  const contentWidth = w - promptVisibleLen;
72
- // Truncate display if line is too long
73
61
  const displayText = lineText.length > contentWidth ? lineText.slice(0, contentWidth - 1) + "…" : lineText;
74
62
  const padding = Math.max(0, contentWidth - displayText.length);
75
- out.write(`${BG_DARK}${prefix}${displayText}${" ".repeat(padding)}${RESET}\n`);
63
+ rows.push(`${BG_DARK}${prefix}${displayText}${" ".repeat(padding)}${RESET}`);
64
+ }
65
+ // Bottom border
66
+ rows.push(`${ACCENT_COLOR}${"─".repeat(w)}${RESET}`);
67
+ // Hints — pad to full width so it fully overwrites old content
68
+ const hintsText = " enter submit esc exit";
69
+ const hintsPad = Math.max(0, w - hintsText.length);
70
+ rows.push(`${dim(hintsText)}${" ".repeat(hintsPad)}`);
71
+ return rows;
72
+ }
73
+ function drawBox() {
74
+ const out = process.stderr;
75
+ const promptVisibleLen = 2;
76
+ const rows = buildRows();
77
+ const totalRows = rows.length;
78
+ if (prevTotalRows > 0) {
79
+ // ── Redraw: overwrite rows in place (no \n, no scrolling) ──
80
+ // Move cursor to top border row
81
+ if (cursorRowFromTop > 0) {
82
+ out.write(`\x1b[${cursorRowFromTop}A`);
83
+ }
84
+ out.write("\r");
85
+ // Overwrite each row in place
86
+ const commonRows = Math.min(totalRows, prevTotalRows);
87
+ for (let i = 0; i < commonRows; i++) {
88
+ out.write(`\x1b[2K${rows[i]}`);
89
+ if (i < commonRows - 1) {
90
+ out.write("\x1b[1B\r"); // cursor down 1 (no scroll), start of line
91
+ }
92
+ }
93
+ if (totalRows > prevTotalRows) {
94
+ // More rows than before (multi-line paste) — append with \n
95
+ for (let i = commonRows; i < totalRows; i++) {
96
+ out.write(`\n\x1b[2K${rows[i]}`);
97
+ }
98
+ }
99
+ else if (prevTotalRows > totalRows) {
100
+ // Fewer rows than before — erase leftover old rows
101
+ for (let i = totalRows; i < prevTotalRows; i++) {
102
+ out.write("\x1b[1B\r\x1b[2K");
103
+ }
104
+ // Move back to last new row
105
+ const extra = prevTotalRows - totalRows;
106
+ if (extra > 0)
107
+ out.write(`\x1b[${extra}A`);
108
+ }
109
+ // Cursor is now on the last row (hints).
110
+ }
111
+ else {
112
+ // ── Initial draw: use \n between rows, no trailing \n ──
113
+ for (let i = 0; i < totalRows; i++) {
114
+ if (i > 0)
115
+ out.write("\n");
116
+ out.write(rows[i]);
117
+ }
118
+ // Cursor is on the hints line (last row).
76
119
  }
77
- // Bottom border — accent colored
78
- const bottomLine = `${ACCENT_COLOR}${"─".repeat(w)}${RESET}`;
79
- out.write(`${bottomLine}\n`);
80
- // Hints
81
- out.write(`${dim(" enter submit esc exit")}\n`);
82
- // Position cursor inside the text area
83
- // We're at the bottom (after hints). Move up to the correct content row.
84
- const currentLineIdx = linesBuf.length - 1; // cursor is always on last line
85
- const rowsFromBottom = 2 + (linesBuf.length - 1 - currentLineIdx); // hints + bottom border + lines below cursor
86
- out.write(`\x1b[${rowsFromBottom}A`);
87
- // Move to correct column: prefix width + cursor position
120
+ prevTotalRows = totalRows;
121
+ // Position cursor at the active content row
122
+ // Cursor is currently on the hints line (last row = index totalRows-1).
123
+ // Content cursor is on row (1 + currentLineIdx).
124
+ const currentLineIdx = linesBuf.length - 1;
125
+ const targetRow = 1 + currentLineIdx;
126
+ const hintsRow = totalRows - 1;
127
+ const rowsUp = hintsRow - targetRow;
128
+ if (rowsUp > 0)
129
+ out.write(`\x1b[${rowsUp}A`);
130
+ // Set column
88
131
  const col = promptVisibleLen + cursorPos + 1;
89
132
  out.write(`\x1b[${col}G`);
90
- // Track where cursor ended up (row 0 = top border)
91
- cursorRowFromTop = 1 + currentLineIdx;
133
+ cursorRowFromTop = targetRow;
92
134
  }
93
135
  // Initial draw
94
136
  process.stderr.write(HIDE_CURSOR);
@@ -203,12 +245,11 @@ export function readTextInput(_prompt) {
203
245
  if (origRawMode !== undefined) {
204
246
  process.stdin.setRawMode(origRawMode);
205
247
  }
206
- // Move cursor to top of box and clear everything
248
+ // Move cursor to top of box
207
249
  if (cursorRowFromTop > 0) {
208
250
  process.stderr.write(`\x1b[${cursorRowFromTop}A`);
209
251
  }
210
- process.stderr.write("\x1b[0G");
211
- process.stderr.write("\x1b[J"); // erase to end of screen
252
+ process.stderr.write("\r\x1b[J"); // erase from here to end of screen
212
253
  // Write the submitted text as a clean line (so it's visible in scrollback)
213
254
  const fullText = linesBuf.join("\n").trim();
214
255
  if (fullText) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarm-code",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Open-source swarm-native coding agent orchestrator — spawns parallel coding agents in isolated git worktrees, built on RLM (arXiv:2512.24601)",
5
5
  "type": "module",
6
6
  "bin": {