aicp-claude-agent 0.1.0

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.
Files changed (54) hide show
  1. package/README.md +161 -0
  2. package/dist/claude/sdk.d.ts +34 -0
  3. package/dist/claude/sdk.d.ts.map +1 -0
  4. package/dist/claude/sdk.js +112 -0
  5. package/dist/claude/sdk.js.map +1 -0
  6. package/dist/commands/index.d.ts +10 -0
  7. package/dist/commands/index.d.ts.map +1 -0
  8. package/dist/commands/index.js +32 -0
  9. package/dist/commands/index.js.map +1 -0
  10. package/dist/commands/resume.d.ts +6 -0
  11. package/dist/commands/resume.d.ts.map +1 -0
  12. package/dist/commands/resume.js +75 -0
  13. package/dist/commands/resume.js.map +1 -0
  14. package/dist/config.d.ts +26 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +118 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/history.d.ts +9 -0
  19. package/dist/history.d.ts.map +1 -0
  20. package/dist/history.js +87 -0
  21. package/dist/history.js.map +1 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +53 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/main.d.ts +2 -0
  27. package/dist/main.d.ts.map +1 -0
  28. package/dist/main.js +344 -0
  29. package/dist/main.js.map +1 -0
  30. package/dist/setup.d.ts +2 -0
  31. package/dist/setup.d.ts.map +1 -0
  32. package/dist/setup.js +129 -0
  33. package/dist/setup.js.map +1 -0
  34. package/dist/terminal/prompt.d.ts +29 -0
  35. package/dist/terminal/prompt.d.ts.map +1 -0
  36. package/dist/terminal/prompt.js +764 -0
  37. package/dist/terminal/prompt.js.map +1 -0
  38. package/dist/terminal/spinner.d.ts +7 -0
  39. package/dist/terminal/spinner.d.ts.map +1 -0
  40. package/dist/terminal/spinner.js +114 -0
  41. package/dist/terminal/spinner.js.map +1 -0
  42. package/dist/types/protocol.d.ts +59 -0
  43. package/dist/types/protocol.d.ts.map +1 -0
  44. package/dist/types/protocol.js +4 -0
  45. package/dist/types/protocol.js.map +1 -0
  46. package/dist/update.d.ts +2 -0
  47. package/dist/update.d.ts.map +1 -0
  48. package/dist/update.js +65 -0
  49. package/dist/update.js.map +1 -0
  50. package/dist/websocket/client.d.ts +8 -0
  51. package/dist/websocket/client.d.ts.map +1 -0
  52. package/dist/websocket/client.js +120 -0
  53. package/dist/websocket/client.js.map +1 -0
  54. package/package.json +39 -0
@@ -0,0 +1,764 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeAbove = writeAbove;
4
+ exports.updateAbove = updateAbove;
5
+ exports.clearAbove = clearAbove;
6
+ exports.printBanner = printBanner;
7
+ exports.printStatus = printStatus;
8
+ exports.printInfo = printInfo;
9
+ exports.printError = printError;
10
+ exports.printDivider = printDivider;
11
+ exports.wrapText = wrapText;
12
+ exports.stylePastePlaceholders = stylePastePlaceholders;
13
+ exports.formatStatusBar = formatStatusBar;
14
+ exports.createPrompt = createPrompt;
15
+ const history_1 = require("../history");
16
+ // ─── ANSI helpers ────────────────────────────────────────────────
17
+ const DIM = '\x1b[2m';
18
+ const RESET = '\x1b[0m';
19
+ const BOLD = '\x1b[1m';
20
+ const PINK = '\x1b[38;5;205m';
21
+ const GRAY = '\x1b[38;5;240m';
22
+ const INFO = '\x1b[38;5;245m';
23
+ const WHITE = '\x1b[37m';
24
+ const CYAN = '\x1b[36m';
25
+ const LINE_CHAR = '─';
26
+ const PROMPT_CHAR = '❯';
27
+ const BASE_PROMPT_LINES = 4; // top divider, input, bottom divider, status
28
+ const PASTE_FOLD_THRESHOLD = 4; // fold pasted blocks with this many or more lines
29
+ // ─── Terminal dimensions ────────────────────────────────────────
30
+ function termWidth() {
31
+ return process.stdout.columns || 80;
32
+ }
33
+ function termHeight() {
34
+ return process.stdout.rows || 24;
35
+ }
36
+ function hrLine() {
37
+ return `\x1b[38;5;60m${LINE_CHAR.repeat(termWidth())}${RESET}`;
38
+ }
39
+ // ─── Pinned prompt state ────────────────────────────────────────
40
+ let promptActive = false;
41
+ let currentStatus = '';
42
+ let extraLines = 0; // number of continuation lines (grows the prompt area)
43
+ function promptHeight() {
44
+ return BASE_PROMPT_LINES + extraLines;
45
+ }
46
+ // ─── writeAbove — insert text into scrollback above the prompt ──
47
+ function writeAbove(text) {
48
+ const wrapped = wrapText(text);
49
+ if (!promptActive) {
50
+ for (const wl of wrapped)
51
+ process.stdout.write(wl + '\n');
52
+ return;
53
+ }
54
+ const rows = termHeight();
55
+ const scrollBottom = rows - promptHeight();
56
+ for (const wl of wrapped) {
57
+ process.stdout.write('\x1b[s' +
58
+ `\x1b[1;${scrollBottom}r` +
59
+ `\x1b[${scrollBottom};1H` +
60
+ '\n' +
61
+ `\x1b[${scrollBottom};1H` +
62
+ '\x1b[2K' +
63
+ wl +
64
+ `\x1b[1;${rows}r` +
65
+ '\x1b[u');
66
+ }
67
+ }
68
+ // ─── updateAbove — overwrite the last scrollback line in-place ───
69
+ function updateAbove(text) {
70
+ // Only show what fits on one line — truncate the rest.
71
+ // Full wrapping happens when the line is finalized via writeAbove.
72
+ if (visibleLength(text) > termWidth()) {
73
+ const wrapped = wrapText(text);
74
+ text = wrapped[0];
75
+ }
76
+ if (!promptActive) {
77
+ process.stdout.write(`\r\x1b[2K${text}`);
78
+ return;
79
+ }
80
+ const rows = termHeight();
81
+ const scrollBottom = rows - promptHeight();
82
+ process.stdout.write('\x1b[s' +
83
+ `\x1b[${scrollBottom};1H` +
84
+ '\x1b[2K' +
85
+ text +
86
+ '\x1b[u');
87
+ }
88
+ // ─── clearAbove — clear the last scrollback line ────────────────
89
+ function clearAbove() {
90
+ if (!promptActive) {
91
+ process.stdout.write('\r\x1b[2K');
92
+ return;
93
+ }
94
+ const rows = termHeight();
95
+ const scrollBottom = rows - promptHeight();
96
+ process.stdout.write('\x1b[s' +
97
+ `\x1b[${scrollBottom};1H` +
98
+ '\x1b[2K' +
99
+ '\x1b[u');
100
+ }
101
+ // ─── Public print helpers (route through writeAbove) ────────────
102
+ function printBanner() {
103
+ writeAbove(hrLine());
104
+ writeAbove(`${BOLD}${CYAN} AICP Agent${RESET}`);
105
+ writeAbove(hrLine());
106
+ writeAbove('');
107
+ }
108
+ function printStatus(text) {
109
+ writeAbove(`${PINK} ${text}${RESET}`);
110
+ }
111
+ function printInfo(text) {
112
+ writeAbove(`${INFO} ${text}${RESET}`);
113
+ }
114
+ function printError(text) {
115
+ writeAbove(`\x1b[31m ${text}${RESET}`);
116
+ }
117
+ function printDivider() {
118
+ writeAbove(hrLine());
119
+ }
120
+ // ─── Word wrap helper ───────────────────────────────────────────
121
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
122
+ function visibleLength(str) {
123
+ return str.replace(ANSI_RE, '').length;
124
+ }
125
+ function wrapText(text) {
126
+ const width = termWidth();
127
+ if (visibleLength(text) <= width)
128
+ return [text];
129
+ // Walk the string tracking visible character count
130
+ const result = [];
131
+ let remaining = text;
132
+ while (visibleLength(remaining) > width) {
133
+ // Find the byte index where visible chars reach width
134
+ let visCount = 0;
135
+ let cutIdx = 0;
136
+ let lastSpace = -1;
137
+ for (let i = 0; i < remaining.length; i++) {
138
+ // Skip ANSI sequences
139
+ if (remaining[i] === '\x1b' && remaining[i + 1] === '[') {
140
+ let j = i + 2;
141
+ while (j < remaining.length && ((remaining[j] >= '0' && remaining[j] <= '9') || remaining[j] === ';'))
142
+ j++;
143
+ if (j < remaining.length && remaining[j] === 'm') {
144
+ i = j; // skip to end of sequence (loop will i++)
145
+ continue;
146
+ }
147
+ }
148
+ if (remaining[i] === ' ')
149
+ lastSpace = i;
150
+ visCount++;
151
+ if (visCount >= width) {
152
+ cutIdx = i + 1;
153
+ break;
154
+ }
155
+ }
156
+ // Prefer breaking at a space
157
+ let breakAt = (lastSpace > 0) ? lastSpace : cutIdx;
158
+ result.push(remaining.slice(0, breakAt));
159
+ remaining = remaining.slice(breakAt).replace(/^ /, '');
160
+ }
161
+ if (remaining)
162
+ result.push(remaining);
163
+ return result;
164
+ }
165
+ // ─── Paste placeholder styling ──────────────────────────────────
166
+ function stylePastePlaceholders(text) {
167
+ return text.replace(/\[Pasted text #\d+ \+\d+ lines?\]/g, match => `\x1b[38;5;117m${match}${RESET}`);
168
+ }
169
+ // ─── Status bar formatting ──────────────────────────────────────
170
+ function formatStatusBar(left, right) {
171
+ const width = termWidth();
172
+ const gap = Math.max(1, width - left.length - right.length);
173
+ return `${PINK} ${left}${' '.repeat(gap)}${right} ${RESET}`;
174
+ }
175
+ function createPrompt(opts) {
176
+ let submitHandler = null;
177
+ let closeHandler = null;
178
+ let sigintHandler = null;
179
+ currentStatus = opts?.statusLine || '';
180
+ // ── Input state ──
181
+ let line = ''; // current active line being edited
182
+ let cursor = 0; // cursor position within active line
183
+ const lines = []; // previous continuation lines
184
+ let activeLineIdx = 0; // which line is being edited (lines.length = current input)
185
+ let closed = false;
186
+ let pasting = false; // true between bracketed paste start/end sequences
187
+ // ── Paste folding state ──
188
+ let pasteBuffering = false; // true while buffering paste content
189
+ let pasteBuffer = ''; // accumulates raw paste content
190
+ const pasteBlocks = [];
191
+ let pasteCounter = 0; // sequential paste block numbering, resets on submit
192
+ // ── History navigation state ──
193
+ let historyIndex = -1; // -1 = current input, 0..N-1 = history (0=oldest)
194
+ let savedInput = ''; // stash current input when browsing history
195
+ // For rl.question() compatibility
196
+ let questionCb = null;
197
+ let questionPromptText = '';
198
+ // ── Drawing helpers ──
199
+ function currentPromptStr() {
200
+ if (questionCb)
201
+ return questionPromptText;
202
+ return `${BOLD}${WHITE}${PROMPT_CHAR}${RESET} `;
203
+ }
204
+ function promptVisualLen() {
205
+ if (questionCb)
206
+ return questionPromptText.replace(/\x1b\[[0-9;]*m/g, '').length;
207
+ return 2; // "❯ "
208
+ }
209
+ // Get all editable lines as a flat array (line inserted at activeLineIdx)
210
+ function allLines() {
211
+ const result = [...lines];
212
+ result.splice(activeLineIdx, 0, line);
213
+ return result;
214
+ }
215
+ // Switch editing focus to a different line
216
+ function switchToLine(newIdx) {
217
+ const all = allLines();
218
+ activeLineIdx = newIdx;
219
+ line = all[newIdx];
220
+ cursor = Math.min(cursor, line.length);
221
+ lines.length = 0;
222
+ for (let i = 0; i < all.length; i++) {
223
+ if (i !== newIdx)
224
+ lines.push(all[i]);
225
+ }
226
+ }
227
+ // Load text into the prompt (for history navigation)
228
+ function loadIntoPrompt(text) {
229
+ const inputLines = text.split('\n');
230
+ lines.length = 0;
231
+ if (inputLines.length === 1) {
232
+ line = inputLines[0];
233
+ cursor = line.length;
234
+ activeLineIdx = 0;
235
+ extraLines = 0;
236
+ }
237
+ else {
238
+ activeLineIdx = inputLines.length - 1;
239
+ line = inputLines[activeLineIdx];
240
+ cursor = line.length;
241
+ for (let i = 0; i < inputLines.length; i++) {
242
+ if (i !== activeLineIdx)
243
+ lines.push(inputLines[i]);
244
+ }
245
+ extraLines = lines.length;
246
+ // Make room for extra lines
247
+ const rows = termHeight();
248
+ const scrollBottom = rows - promptHeight();
249
+ if (extraLines > 0) {
250
+ process.stdout.write(`\x1b[1;${scrollBottom}r` +
251
+ `\x1b[${scrollBottom};1H` +
252
+ '\n'.repeat(extraLines) +
253
+ `\x1b[1;${rows}r`);
254
+ }
255
+ }
256
+ pasteBlocks.length = 0;
257
+ pasteCounter = 0;
258
+ drawPromptArea();
259
+ }
260
+ // Get all lines with paste placeholders expanded to their full content
261
+ function allLinesExpanded() {
262
+ const display = allLines();
263
+ const result = [];
264
+ for (const displayLine of display) {
265
+ let expanded = displayLine;
266
+ expanded = expanded.replace(/\[Pasted text #(\d+) \+\d+ lines?\]/g, (_match, idStr) => {
267
+ const id = parseInt(idStr, 10);
268
+ const block = pasteBlocks.find(b => b.id === id);
269
+ return block ? block.content : _match;
270
+ });
271
+ result.push(...expanded.split('\n'));
272
+ }
273
+ return result;
274
+ }
275
+ // Process buffered paste content — fold large pastes into placeholder
276
+ function processPasteBuffer() {
277
+ if (!pasteBuffer)
278
+ return;
279
+ const normalized = pasteBuffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
280
+ const pastedLines = normalized.split('\n');
281
+ if (pastedLines.length > 1 && pastedLines[pastedLines.length - 1] === '')
282
+ pastedLines.pop();
283
+ if (pastedLines.length >= PASTE_FOLD_THRESHOLD) {
284
+ pasteCounter++;
285
+ const id = pasteCounter;
286
+ const content = pastedLines.join('\n');
287
+ pasteBlocks.push({ id, content });
288
+ const placeholder = `[Pasted text #${id} +${pastedLines.length} lines]`;
289
+ line = line.slice(0, cursor) + placeholder + line.slice(cursor);
290
+ cursor += placeholder.length;
291
+ drawActiveLine();
292
+ }
293
+ else {
294
+ // Small paste — insert normally
295
+ for (const ch of normalized) {
296
+ if (ch === '\n') {
297
+ handleContinuation();
298
+ }
299
+ else {
300
+ line = line.slice(0, cursor) + ch + line.slice(cursor);
301
+ cursor++;
302
+ }
303
+ }
304
+ drawPromptArea();
305
+ }
306
+ pasteBuffer = '';
307
+ }
308
+ // Draw the entire prompt area: top divider, all lines, bottom divider, status
309
+ function drawPromptArea() {
310
+ const rows = termHeight();
311
+ const height = promptHeight();
312
+ const topRow = rows - height + 1;
313
+ const all = allLines();
314
+ let seq = '';
315
+ // Top divider
316
+ seq += `\x1b[${topRow};1H\x1b[2K` + hrLine();
317
+ // All editable lines
318
+ for (let i = 0; i < all.length; i++) {
319
+ const row = topRow + 1 + i;
320
+ const isActive = i === activeLineIdx;
321
+ const prefix = isActive ? `${BOLD}${WHITE}${PROMPT_CHAR}${RESET} ` : ' ';
322
+ seq += `\x1b[${row};1H\x1b[2K` + prefix + stylePastePlaceholders(all[i]);
323
+ }
324
+ // Bottom divider
325
+ seq += `\x1b[${rows - 1};1H\x1b[2K` + hrLine();
326
+ // Status
327
+ seq += `\x1b[${rows};1H\x1b[2K${PINK} ${currentStatus}${RESET}`;
328
+ // Position cursor on active line
329
+ const activeRow = topRow + 1 + activeLineIdx;
330
+ const col = 2 + cursor + 1; // prefix is always 2 visible chars
331
+ seq += `\x1b[${activeRow};${col}H`;
332
+ process.stdout.write(seq);
333
+ }
334
+ // Redraw just the active line and position cursor
335
+ function drawActiveLine() {
336
+ const rows = termHeight();
337
+ const height = promptHeight();
338
+ const topRow = rows - height + 1;
339
+ const activeRow = topRow + 1 + activeLineIdx;
340
+ const prefix = `${BOLD}${WHITE}${PROMPT_CHAR}${RESET} `;
341
+ const col = 2 + cursor + 1;
342
+ process.stdout.write(`\x1b[${activeRow};1H\x1b[2K` +
343
+ prefix + stylePastePlaceholders(line) +
344
+ `\x1b[${activeRow};${col}H`);
345
+ }
346
+ function drawStatusLine() {
347
+ const rows = termHeight();
348
+ // Save/restore cursor so we don't disrupt input position
349
+ process.stdout.write('\x1b[s' +
350
+ `\x1b[${rows};1H\x1b[2K${PINK} ${currentStatus}${RESET}` +
351
+ '\x1b[u');
352
+ }
353
+ // ── Activate ──
354
+ function activate() {
355
+ promptActive = true;
356
+ extraLines = 0;
357
+ // Make room at the bottom
358
+ process.stdout.write('\n'.repeat(BASE_PROMPT_LINES));
359
+ // Draw the 4-line area
360
+ drawPromptArea();
361
+ // Enable raw mode + bracketed paste
362
+ if (process.stdin.isTTY) {
363
+ process.stdin.setRawMode(true);
364
+ }
365
+ process.stdout.write('\x1b[?2004h'); // enable bracketed paste mode
366
+ process.stdin.resume();
367
+ process.stdin.on('data', onKeypress);
368
+ }
369
+ // ── Multiline continuation ──
370
+ // The prompt area grows: top divider moves up, new line added between dividers
371
+ function handleContinuation() {
372
+ // Merge current line back, insert new empty line after it
373
+ const all = allLines();
374
+ all.splice(activeLineIdx + 1, 0, '');
375
+ activeLineIdx = activeLineIdx + 1;
376
+ line = '';
377
+ cursor = 0;
378
+ lines.length = 0;
379
+ for (let i = 0; i < all.length; i++) {
380
+ if (i !== activeLineIdx)
381
+ lines.push(all[i]);
382
+ }
383
+ extraLines = lines.length; // lines.length = total - 1 = extra lines beyond the 1 in BASE
384
+ // We need one more row for the prompt area — scroll scrollback up by 1
385
+ const rows = termHeight();
386
+ const scrollBottom = rows - promptHeight();
387
+ // Use scroll region to push scrollback up, making room for the taller prompt
388
+ process.stdout.write(`\x1b[1;${scrollBottom + 1}r` + // scroll region includes the row we're claiming
389
+ `\x1b[${scrollBottom + 1};1H` + // move to bottom of region
390
+ '\n' + // scroll up
391
+ `\x1b[1;${rows}r` // reset scroll region
392
+ );
393
+ // Redraw the entire prompt area at new size
394
+ drawPromptArea();
395
+ }
396
+ // ── Keypress handler ──
397
+ function onKeypress(data) {
398
+ if (closed)
399
+ return;
400
+ const str = data.toString('utf8');
401
+ for (let i = 0; i < str.length; i++) {
402
+ const ch = str[i];
403
+ const code = str.charCodeAt(i);
404
+ // ESC sequence
405
+ if (ch === '\x1b' && i + 1 < str.length) {
406
+ if (str[i + 1] === '[' && i + 2 < str.length) {
407
+ let j = i + 2;
408
+ let params = '';
409
+ while (j < str.length && (str[j] >= '0' && str[j] <= '9' || str[j] === ';')) {
410
+ params += str[j];
411
+ j++;
412
+ }
413
+ const terminator = j < str.length ? str[j] : '';
414
+ // Bracketed paste: \x1b[200~ (start) and \x1b[201~ (end)
415
+ if (terminator === '~' && params === '200') {
416
+ pasting = true;
417
+ pasteBuffering = true;
418
+ pasteBuffer = '';
419
+ i = j;
420
+ continue;
421
+ }
422
+ if (terminator === '~' && params === '201') {
423
+ pasting = false;
424
+ if (pasteBuffering) {
425
+ pasteBuffering = false;
426
+ processPasteBuffer();
427
+ }
428
+ i = j;
429
+ continue;
430
+ }
431
+ // CSI u: \x1b[keycode;modifiers u (Shift+Enter = \x1b[13;2u)
432
+ if (terminator === 'u') {
433
+ const keycode = parseInt(params.split(';')[0], 10);
434
+ if (keycode === 13)
435
+ handleContinuation();
436
+ i = j;
437
+ continue;
438
+ }
439
+ // Arrow keys, Home, End
440
+ if (terminator === 'C') {
441
+ if (cursor < line.length)
442
+ cursor++;
443
+ drawActiveLine();
444
+ }
445
+ else if (terminator === 'D') {
446
+ if (cursor > 0)
447
+ cursor--;
448
+ drawActiveLine();
449
+ }
450
+ else if (terminator === 'A') {
451
+ // Up arrow — navigate to previous line (or history at top)
452
+ if (activeLineIdx > 0) {
453
+ switchToLine(activeLineIdx - 1);
454
+ drawPromptArea();
455
+ }
456
+ else {
457
+ // History navigation — go to older entry
458
+ const len = (0, history_1.historyLength)();
459
+ if (len > 0) {
460
+ let newIdx = historyIndex;
461
+ if (historyIndex === -1) {
462
+ savedInput = allLines().join('\n');
463
+ newIdx = len - 1; // most recent
464
+ }
465
+ else if (historyIndex > 0) {
466
+ newIdx = historyIndex - 1;
467
+ }
468
+ if (newIdx !== historyIndex) {
469
+ historyIndex = newIdx;
470
+ // Clear extra lines before loading history
471
+ if (extraLines > 0) {
472
+ const rows = termHeight();
473
+ const oldTopRow = rows - promptHeight() + 1;
474
+ const newTopRow = rows - BASE_PROMPT_LINES + 1;
475
+ for (let r = oldTopRow; r < newTopRow; r++) {
476
+ process.stdout.write(`\x1b[${r};1H\x1b[2K`);
477
+ }
478
+ extraLines = 0;
479
+ lines.length = 0;
480
+ }
481
+ const text = (0, history_1.getHistoryDisplay)(historyIndex);
482
+ if (text)
483
+ loadIntoPrompt(text);
484
+ }
485
+ }
486
+ }
487
+ }
488
+ else if (terminator === 'B') {
489
+ // Down arrow — navigate to next line (or history at bottom)
490
+ const totalLines = lines.length + 1;
491
+ if (activeLineIdx < totalLines - 1) {
492
+ switchToLine(activeLineIdx + 1);
493
+ drawPromptArea();
494
+ }
495
+ else if (historyIndex >= 0) {
496
+ // History navigation — go to newer entry or back to current input
497
+ const len = (0, history_1.historyLength)();
498
+ if (historyIndex < len - 1) {
499
+ historyIndex++;
500
+ // Clear extra lines before loading
501
+ if (extraLines > 0) {
502
+ const rows = termHeight();
503
+ const oldTopRow = rows - promptHeight() + 1;
504
+ const newTopRow = rows - BASE_PROMPT_LINES + 1;
505
+ for (let r = oldTopRow; r < newTopRow; r++) {
506
+ process.stdout.write(`\x1b[${r};1H\x1b[2K`);
507
+ }
508
+ extraLines = 0;
509
+ lines.length = 0;
510
+ }
511
+ const text = (0, history_1.getHistoryDisplay)(historyIndex);
512
+ if (text)
513
+ loadIntoPrompt(text);
514
+ }
515
+ else {
516
+ // Back to current input
517
+ historyIndex = -1;
518
+ if (extraLines > 0) {
519
+ const rows = termHeight();
520
+ const oldTopRow = rows - promptHeight() + 1;
521
+ const newTopRow = rows - BASE_PROMPT_LINES + 1;
522
+ for (let r = oldTopRow; r < newTopRow; r++) {
523
+ process.stdout.write(`\x1b[${r};1H\x1b[2K`);
524
+ }
525
+ extraLines = 0;
526
+ lines.length = 0;
527
+ }
528
+ loadIntoPrompt(savedInput);
529
+ savedInput = '';
530
+ }
531
+ }
532
+ }
533
+ else if (terminator === '~' && params === '3') {
534
+ // Delete key — forward delete
535
+ if (cursor < line.length) {
536
+ line = line.slice(0, cursor) + line.slice(cursor + 1);
537
+ drawActiveLine();
538
+ }
539
+ else {
540
+ // At EOL — merge next line into current
541
+ const totalLines = lines.length + 1;
542
+ if (activeLineIdx < totalLines - 1) {
543
+ const all = allLines();
544
+ line += all[activeLineIdx + 1];
545
+ all.splice(activeLineIdx + 1, 1);
546
+ lines.length = 0;
547
+ for (let li = 0; li < all.length; li++) {
548
+ if (li !== activeLineIdx)
549
+ lines.push(all[li]);
550
+ }
551
+ const rows = termHeight();
552
+ const oldTopRow = rows - promptHeight() + 1;
553
+ extraLines = lines.length;
554
+ process.stdout.write(`\x1b[${oldTopRow};1H\x1b[2K`);
555
+ drawPromptArea();
556
+ }
557
+ }
558
+ }
559
+ else if (terminator === 'H') {
560
+ cursor = 0;
561
+ drawActiveLine();
562
+ }
563
+ else if (terminator === 'F') {
564
+ cursor = line.length;
565
+ drawActiveLine();
566
+ }
567
+ i = j;
568
+ continue;
569
+ }
570
+ i += 1;
571
+ continue;
572
+ }
573
+ // Buffer paste content instead of processing immediately
574
+ if (pasteBuffering) {
575
+ pasteBuffer += ch;
576
+ continue;
577
+ }
578
+ // Ctrl+C
579
+ if (code === 3) {
580
+ if (sigintHandler)
581
+ sigintHandler();
582
+ continue;
583
+ }
584
+ // Ctrl+D
585
+ if (code === 4) {
586
+ if (line.length === 0 && lines.length === 0) {
587
+ if (closeHandler)
588
+ closeHandler();
589
+ }
590
+ continue;
591
+ }
592
+ // Enter
593
+ if (ch === '\r' || ch === '\n') {
594
+ if (line.endsWith('\\')) {
595
+ line = line.slice(0, -1);
596
+ handleContinuation();
597
+ continue;
598
+ }
599
+ const displayInput = allLines().join('\n');
600
+ const fullInput = pasteBlocks.length > 0 ? allLinesExpanded().join('\n') : displayInput;
601
+ // Save to history (skip empty and question prompts)
602
+ if (!questionCb && fullInput.trim()) {
603
+ (0, history_1.addHistory)(fullInput, displayInput);
604
+ }
605
+ // Clear released prompt area rows before shrinking
606
+ if (extraLines > 0) {
607
+ const rows = termHeight();
608
+ const oldTopRow = rows - promptHeight() + 1;
609
+ const newTopRow = rows - BASE_PROMPT_LINES + 1;
610
+ for (let r = oldTopRow; r < newTopRow; r++) {
611
+ process.stdout.write(`\x1b[${r};1H\x1b[2K`);
612
+ }
613
+ }
614
+ lines.length = 0;
615
+ line = '';
616
+ cursor = 0;
617
+ activeLineIdx = 0;
618
+ extraLines = 0;
619
+ pasteBlocks.length = 0;
620
+ pasteCounter = 0;
621
+ historyIndex = -1;
622
+ savedInput = '';
623
+ // Redraw prompt area at base size
624
+ drawPromptArea();
625
+ if (questionCb) {
626
+ const cb = questionCb;
627
+ questionCb = null;
628
+ cb(fullInput);
629
+ }
630
+ else if (submitHandler) {
631
+ submitHandler(fullInput, displayInput);
632
+ }
633
+ continue;
634
+ }
635
+ // Backspace
636
+ if (code === 127 || code === 8) {
637
+ if (cursor > 0) {
638
+ line = line.slice(0, cursor - 1) + line.slice(cursor);
639
+ cursor--;
640
+ drawActiveLine();
641
+ }
642
+ else if (activeLineIdx > 0) {
643
+ // At start of line — merge into previous line (unwrap)
644
+ const all = allLines();
645
+ const prevContent = all[activeLineIdx - 1];
646
+ all[activeLineIdx - 1] = prevContent + all[activeLineIdx];
647
+ all.splice(activeLineIdx, 1);
648
+ activeLineIdx--;
649
+ line = all[activeLineIdx];
650
+ cursor = prevContent.length;
651
+ lines.length = 0;
652
+ for (let li = 0; li < all.length; li++) {
653
+ if (li !== activeLineIdx)
654
+ lines.push(all[li]);
655
+ }
656
+ const rows = termHeight();
657
+ const oldTopRow = rows - promptHeight() + 1;
658
+ extraLines = lines.length;
659
+ process.stdout.write(`\x1b[${oldTopRow};1H\x1b[2K`);
660
+ drawPromptArea();
661
+ }
662
+ continue;
663
+ }
664
+ // Ctrl+A — home
665
+ if (code === 1) {
666
+ cursor = 0;
667
+ drawActiveLine();
668
+ continue;
669
+ }
670
+ // Ctrl+E — end
671
+ if (code === 5) {
672
+ cursor = line.length;
673
+ drawActiveLine();
674
+ continue;
675
+ }
676
+ // Ctrl+K — kill to end
677
+ if (code === 11) {
678
+ line = line.slice(0, cursor);
679
+ drawActiveLine();
680
+ continue;
681
+ }
682
+ // Ctrl+U — kill to start
683
+ if (code === 21) {
684
+ line = line.slice(cursor);
685
+ cursor = 0;
686
+ drawActiveLine();
687
+ continue;
688
+ }
689
+ // Ctrl+W — delete word back
690
+ if (code === 23) {
691
+ const before = line.slice(0, cursor);
692
+ const trimmed = before.replace(/\s*\S+\s*$/, '');
693
+ line = trimmed + line.slice(cursor);
694
+ cursor = trimmed.length;
695
+ drawActiveLine();
696
+ continue;
697
+ }
698
+ // Tab — ignore
699
+ if (code === 9)
700
+ continue;
701
+ // Printable character
702
+ if (code >= 32) {
703
+ line = line.slice(0, cursor) + ch + line.slice(cursor);
704
+ cursor++;
705
+ drawActiveLine();
706
+ }
707
+ }
708
+ }
709
+ // ── Resize handler ──
710
+ process.stdout.on('resize', () => {
711
+ if (!promptActive)
712
+ return;
713
+ drawPromptArea();
714
+ });
715
+ // ── question() for rl compatibility ──
716
+ function question(prompt, cb) {
717
+ questionPromptText = prompt;
718
+ questionCb = cb;
719
+ drawActiveLine();
720
+ }
721
+ return {
722
+ rl: { question },
723
+ onSubmit(handler) { submitHandler = handler; },
724
+ onClose(handler) { closeHandler = handler; },
725
+ onSigint(handler) { sigintHandler = handler; },
726
+ setStatus(text) {
727
+ currentStatus = text;
728
+ if (promptActive)
729
+ drawStatusLine();
730
+ },
731
+ updateStatus(text) { currentStatus = text; },
732
+ writeAbove,
733
+ prompt() {
734
+ if (!promptActive) {
735
+ activate();
736
+ }
737
+ else {
738
+ line = '';
739
+ cursor = 0;
740
+ activeLineIdx = 0;
741
+ extraLines = 0;
742
+ lines.length = 0;
743
+ pasteBlocks.length = 0;
744
+ pasteCounter = 0;
745
+ historyIndex = -1;
746
+ savedInput = '';
747
+ drawPromptArea();
748
+ }
749
+ },
750
+ close() {
751
+ closed = true;
752
+ promptActive = false;
753
+ extraLines = 0;
754
+ process.stdout.write('\x1b[?2004l'); // disable bracketed paste mode
755
+ process.stdin.removeListener('data', onKeypress);
756
+ if (process.stdin.isTTY) {
757
+ process.stdin.setRawMode(false);
758
+ }
759
+ const rows = termHeight();
760
+ process.stdout.write(`\x1b[${rows};1H\n`);
761
+ },
762
+ };
763
+ }
764
+ //# sourceMappingURL=prompt.js.map