@reifydb/shell 0.2.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.
package/dist/index.js ADDED
@@ -0,0 +1,1137 @@
1
+ // src/terminal/adapter.ts
2
+ import { Terminal } from "@xterm/xterm";
3
+ import { FitAddon } from "@xterm/addon-fit";
4
+ import "@xterm/xterm/css/xterm.css";
5
+
6
+ // src/terminal/theme.ts
7
+ var defaultTheme = {
8
+ background: "#1e1e2e",
9
+ foreground: "#cdd6f4",
10
+ cursor: "#f5e0dc",
11
+ cursorAccent: "#1e1e2e",
12
+ selectionBackground: "#45475a",
13
+ black: "#45475a",
14
+ red: "#f38ba8",
15
+ green: "#a6e3a1",
16
+ yellow: "#f9e2af",
17
+ blue: "#89b4fa",
18
+ magenta: "#f5c2e7",
19
+ cyan: "#94e2d5",
20
+ white: "#bac2de",
21
+ brightBlack: "#585b70",
22
+ brightRed: "#f38ba8",
23
+ brightGreen: "#a6e3a1",
24
+ brightYellow: "#f9e2af",
25
+ brightBlue: "#89b4fa",
26
+ brightMagenta: "#f5c2e7",
27
+ brightCyan: "#94e2d5",
28
+ brightWhite: "#a6adc8"
29
+ };
30
+ var COLORS = {
31
+ reset: "\x1B[0m",
32
+ bold: "\x1B[1m",
33
+ dim: "\x1B[2m",
34
+ italic: "\x1B[3m",
35
+ underline: "\x1B[4m",
36
+ // Foreground colors
37
+ black: "\x1B[30m",
38
+ red: "\x1B[31m",
39
+ green: "\x1B[32m",
40
+ yellow: "\x1B[33m",
41
+ blue: "\x1B[34m",
42
+ magenta: "\x1B[35m",
43
+ cyan: "\x1B[36m",
44
+ white: "\x1B[37m",
45
+ // Bright foreground colors
46
+ brightBlack: "\x1B[90m",
47
+ brightRed: "\x1B[91m",
48
+ brightGreen: "\x1B[92m",
49
+ brightYellow: "\x1B[93m",
50
+ brightBlue: "\x1B[94m",
51
+ brightMagenta: "\x1B[95m",
52
+ brightCyan: "\x1B[96m",
53
+ brightWhite: "\x1B[97m"
54
+ };
55
+
56
+ // src/terminal/adapter.ts
57
+ var TerminalAdapter = class {
58
+ terminal;
59
+ fitAddon;
60
+ keyHandler = null;
61
+ resizeObserver = null;
62
+ constructor(container, theme = defaultTheme) {
63
+ this.terminal = new Terminal({
64
+ theme,
65
+ fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace",
66
+ fontSize: 14,
67
+ lineHeight: 1.2,
68
+ cursorBlink: true,
69
+ cursorStyle: "block",
70
+ scrollback: 1e4,
71
+ allowProposedApi: true
72
+ });
73
+ this.fitAddon = new FitAddon();
74
+ this.terminal.loadAddon(this.fitAddon);
75
+ container.innerHTML = "";
76
+ this.terminal.open(container);
77
+ this.fitAddon.fit();
78
+ this.resizeObserver = new ResizeObserver(() => {
79
+ this.fitAddon.fit();
80
+ });
81
+ this.resizeObserver.observe(container);
82
+ this.terminal.onKey(({ key, domEvent }) => {
83
+ if (this.keyHandler) {
84
+ this.keyHandler(key, domEvent);
85
+ }
86
+ });
87
+ }
88
+ onKey(handler) {
89
+ this.keyHandler = handler;
90
+ }
91
+ write(text) {
92
+ this.terminal.write(text);
93
+ }
94
+ writeln(text) {
95
+ this.terminal.writeln(text);
96
+ }
97
+ clear() {
98
+ this.terminal.clear();
99
+ }
100
+ get cols() {
101
+ return this.terminal.cols;
102
+ }
103
+ get rows() {
104
+ return this.terminal.rows;
105
+ }
106
+ focus() {
107
+ this.terminal.focus();
108
+ }
109
+ dispose() {
110
+ if (this.resizeObserver) {
111
+ this.resizeObserver.disconnect();
112
+ this.resizeObserver = null;
113
+ }
114
+ this.terminal.dispose();
115
+ }
116
+ // ANSI escape code helpers - static for use without instance
117
+ static COLORS = COLORS;
118
+ // Cursor control helpers
119
+ static cursorUp(n = 1) {
120
+ return `\x1B[${n}A`;
121
+ }
122
+ static cursorDown(n = 1) {
123
+ return `\x1B[${n}B`;
124
+ }
125
+ static cursorForward(n = 1) {
126
+ return `\x1B[${n}C`;
127
+ }
128
+ static cursorBack(n = 1) {
129
+ return `\x1B[${n}D`;
130
+ }
131
+ static cursorPosition(row, col) {
132
+ return `\x1B[${row};${col}H`;
133
+ }
134
+ static clearLine() {
135
+ return "\x1B[2K";
136
+ }
137
+ static clearToEndOfLine() {
138
+ return "\x1B[K";
139
+ }
140
+ static clearScreen() {
141
+ return "\x1B[2J\x1B[3J\x1B[H";
142
+ }
143
+ static saveCursor() {
144
+ return "\x1B[s";
145
+ }
146
+ static restoreCursor() {
147
+ return "\x1B[u";
148
+ }
149
+ };
150
+
151
+ // src/input/line-editor.ts
152
+ var LineEditor = class {
153
+ buffer = "";
154
+ cursorPos = 0;
155
+ terminal;
156
+ constructor(terminal) {
157
+ this.terminal = terminal;
158
+ }
159
+ get value() {
160
+ return this.buffer;
161
+ }
162
+ get cursor() {
163
+ return this.cursorPos;
164
+ }
165
+ clear() {
166
+ this.buffer = "";
167
+ this.cursorPos = 0;
168
+ }
169
+ setValue(value) {
170
+ this.buffer = value;
171
+ this.cursorPos = value.length;
172
+ }
173
+ insert(char) {
174
+ this.buffer = this.buffer.slice(0, this.cursorPos) + char + this.buffer.slice(this.cursorPos);
175
+ this.cursorPos++;
176
+ }
177
+ backspace() {
178
+ if (this.cursorPos > 0) {
179
+ this.buffer = this.buffer.slice(0, this.cursorPos - 1) + this.buffer.slice(this.cursorPos);
180
+ this.cursorPos--;
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+ delete() {
186
+ if (this.cursorPos < this.buffer.length) {
187
+ this.buffer = this.buffer.slice(0, this.cursorPos) + this.buffer.slice(this.cursorPos + 1);
188
+ return true;
189
+ }
190
+ return false;
191
+ }
192
+ moveLeft() {
193
+ if (this.cursorPos > 0) {
194
+ this.cursorPos--;
195
+ this.terminal.write(TerminalAdapter.cursorBack());
196
+ return true;
197
+ }
198
+ return false;
199
+ }
200
+ moveRight() {
201
+ if (this.cursorPos < this.buffer.length) {
202
+ this.cursorPos++;
203
+ this.terminal.write(TerminalAdapter.cursorForward());
204
+ return true;
205
+ }
206
+ return false;
207
+ }
208
+ moveToStart() {
209
+ if (this.cursorPos > 0) {
210
+ this.terminal.write(TerminalAdapter.cursorBack(this.cursorPos));
211
+ this.cursorPos = 0;
212
+ }
213
+ }
214
+ moveToEnd() {
215
+ if (this.cursorPos < this.buffer.length) {
216
+ const distance = this.buffer.length - this.cursorPos;
217
+ this.terminal.write(TerminalAdapter.cursorForward(distance));
218
+ this.cursorPos = this.buffer.length;
219
+ }
220
+ }
221
+ moveWordLeft() {
222
+ if (this.cursorPos === 0) return;
223
+ let newPos = this.cursorPos - 1;
224
+ while (newPos > 0 && /\s/.test(this.buffer[newPos])) {
225
+ newPos--;
226
+ }
227
+ while (newPos > 0 && !/\s/.test(this.buffer[newPos - 1])) {
228
+ newPos--;
229
+ }
230
+ const distance = this.cursorPos - newPos;
231
+ if (distance > 0) {
232
+ this.terminal.write(TerminalAdapter.cursorBack(distance));
233
+ this.cursorPos = newPos;
234
+ }
235
+ }
236
+ moveWordRight() {
237
+ if (this.cursorPos >= this.buffer.length) return;
238
+ let newPos = this.cursorPos;
239
+ while (newPos < this.buffer.length && !/\s/.test(this.buffer[newPos])) {
240
+ newPos++;
241
+ }
242
+ while (newPos < this.buffer.length && /\s/.test(this.buffer[newPos])) {
243
+ newPos++;
244
+ }
245
+ const distance = newPos - this.cursorPos;
246
+ if (distance > 0) {
247
+ this.terminal.write(TerminalAdapter.cursorForward(distance));
248
+ this.cursorPos = newPos;
249
+ }
250
+ }
251
+ clearLine() {
252
+ this.buffer = "";
253
+ this.cursorPos = 0;
254
+ }
255
+ deleteToEnd() {
256
+ this.buffer = this.buffer.slice(0, this.cursorPos);
257
+ }
258
+ deleteToStart() {
259
+ this.buffer = this.buffer.slice(this.cursorPos);
260
+ this.cursorPos = 0;
261
+ }
262
+ deleteWord() {
263
+ if (this.cursorPos === 0) return;
264
+ let newPos = this.cursorPos - 1;
265
+ while (newPos > 0 && /\s/.test(this.buffer[newPos])) {
266
+ newPos--;
267
+ }
268
+ while (newPos > 0 && !/\s/.test(this.buffer[newPos - 1])) {
269
+ newPos--;
270
+ }
271
+ this.buffer = this.buffer.slice(0, newPos) + this.buffer.slice(this.cursorPos);
272
+ this.cursorPos = newPos;
273
+ }
274
+ // Called by shell to render the line with prompt
275
+ render(prompt) {
276
+ this.terminal.write(
277
+ "\r" + TerminalAdapter.clearToEndOfLine() + prompt + this.buffer
278
+ );
279
+ const cursorOffset = this.buffer.length - this.cursorPos;
280
+ if (cursorOffset > 0) {
281
+ this.terminal.write(TerminalAdapter.cursorBack(cursorOffset));
282
+ }
283
+ }
284
+ };
285
+
286
+ // src/input/history.ts
287
+ var DEFAULT_STORAGE_KEY = "reifydb-shell-history";
288
+ var MAX_HISTORY = 1e3;
289
+ var LocalStorageHistoryStorage = class {
290
+ key;
291
+ constructor(key = DEFAULT_STORAGE_KEY) {
292
+ this.key = key;
293
+ }
294
+ load() {
295
+ try {
296
+ const stored = localStorage.getItem(this.key);
297
+ if (stored) {
298
+ const parsed = JSON.parse(stored);
299
+ if (Array.isArray(parsed)) {
300
+ return parsed.filter((e) => typeof e === "string");
301
+ }
302
+ }
303
+ } catch {
304
+ }
305
+ return [];
306
+ }
307
+ save(entries) {
308
+ try {
309
+ localStorage.setItem(this.key, JSON.stringify(entries));
310
+ } catch {
311
+ }
312
+ }
313
+ };
314
+ var MemoryHistoryStorage = class {
315
+ entries = [];
316
+ load() {
317
+ return [...this.entries];
318
+ }
319
+ save(entries) {
320
+ this.entries = [...entries];
321
+ }
322
+ };
323
+ var CommandHistory = class {
324
+ entries = [];
325
+ position = -1;
326
+ savedInput = "";
327
+ storage;
328
+ constructor(storage, historyKey) {
329
+ this.storage = storage ?? new LocalStorageHistoryStorage(historyKey);
330
+ this.entries = this.storage.load();
331
+ }
332
+ add(command) {
333
+ const trimmed = command.trim();
334
+ if (!trimmed) return;
335
+ if (this.entries.length > 0 && this.entries[this.entries.length - 1] === trimmed) {
336
+ this.reset();
337
+ return;
338
+ }
339
+ this.entries.push(trimmed);
340
+ if (this.entries.length > MAX_HISTORY) {
341
+ this.entries = this.entries.slice(-MAX_HISTORY);
342
+ }
343
+ this.storage.save(this.entries);
344
+ this.reset();
345
+ }
346
+ previous(currentInput) {
347
+ if (this.entries.length === 0) return null;
348
+ if (this.position === -1) {
349
+ this.savedInput = currentInput;
350
+ this.position = this.entries.length;
351
+ }
352
+ if (this.position > 0) {
353
+ this.position--;
354
+ return this.entries[this.position];
355
+ }
356
+ return null;
357
+ }
358
+ next() {
359
+ if (this.position === -1) return null;
360
+ if (this.position < this.entries.length - 1) {
361
+ this.position++;
362
+ return this.entries[this.position];
363
+ }
364
+ if (this.position === this.entries.length - 1) {
365
+ this.position = -1;
366
+ return this.savedInput;
367
+ }
368
+ return null;
369
+ }
370
+ reset() {
371
+ this.position = -1;
372
+ this.savedInput = "";
373
+ }
374
+ getAll() {
375
+ return [...this.entries];
376
+ }
377
+ clear() {
378
+ this.entries = [];
379
+ this.position = -1;
380
+ this.savedInput = "";
381
+ this.storage.save(this.entries);
382
+ }
383
+ };
384
+
385
+ // src/input/multiline.ts
386
+ var MultilineBuffer = class {
387
+ lines = [];
388
+ get isEmpty() {
389
+ return this.lines.length === 0;
390
+ }
391
+ get content() {
392
+ return this.lines.join(" ");
393
+ }
394
+ addLine(line) {
395
+ this.lines.push(line);
396
+ }
397
+ clear() {
398
+ this.lines = [];
399
+ }
400
+ isComplete() {
401
+ const full = this.content.trim();
402
+ return full.endsWith(";");
403
+ }
404
+ static isStatementComplete(input) {
405
+ const trimmed = input.trim();
406
+ return trimmed.endsWith(";");
407
+ }
408
+ };
409
+
410
+ // src/commands/dot-commands.ts
411
+ var C = TerminalAdapter.COLORS;
412
+ async function handleDotCommand(input, context) {
413
+ const parts = input.trim().split(/\s+/);
414
+ const command = parts[0].toLowerCase();
415
+ const args = parts.slice(1);
416
+ switch (command) {
417
+ case ".help":
418
+ showHelp(context.terminal);
419
+ return { handled: true };
420
+ case ".quit":
421
+ case ".exit":
422
+ context.terminal.writeln(`${C.yellow}Goodbye!${C.reset}`);
423
+ context.terminal.writeln("");
424
+ return { handled: true, exit: true };
425
+ case ".clear":
426
+ context.clearScreen();
427
+ return { handled: true };
428
+ case ".mode":
429
+ handleMode(args, context);
430
+ return { handled: true };
431
+ case ".history":
432
+ showHistory(context);
433
+ return { handled: true };
434
+ case ".tables":
435
+ await showTables(context);
436
+ return { handled: true };
437
+ case ".schema":
438
+ await showSchema(args, context);
439
+ return { handled: true };
440
+ default:
441
+ if (command.startsWith(".")) {
442
+ context.terminal.writeln(
443
+ `${C.red}Unknown command: ${command}${C.reset}`
444
+ );
445
+ context.terminal.writeln(`Type ${C.cyan}.help${C.reset} for available commands.`);
446
+ return { handled: true };
447
+ }
448
+ return { handled: false };
449
+ }
450
+ }
451
+ function showHelp(terminal) {
452
+ terminal.writeln("");
453
+ terminal.writeln(`${C.bold}${C.cyan}Available commands:${C.reset}`);
454
+ terminal.writeln("");
455
+ terminal.writeln(` ${C.green}.help${C.reset} Show this help message`);
456
+ terminal.writeln(` ${C.green}.quit${C.reset}, ${C.green}.exit${C.reset} Exit message`);
457
+ terminal.writeln(` ${C.green}.clear${C.reset} Clear the screen`);
458
+ terminal.writeln(` ${C.green}.mode${C.reset} [mode] Set display mode (truncate|full)`);
459
+ terminal.writeln(` ${C.green}.history${C.reset} Show command history`);
460
+ terminal.writeln(` ${C.green}.tables${C.reset} List all tables`);
461
+ terminal.writeln(` ${C.green}.schema${C.reset} [table] Show table schema`);
462
+ terminal.writeln("");
463
+ terminal.writeln(`${C.bold}${C.cyan}Keyboard shortcuts:${C.reset}`);
464
+ terminal.writeln("");
465
+ terminal.writeln(` ${C.yellow}Left/Right${C.reset} Move cursor`);
466
+ terminal.writeln(` ${C.yellow}Ctrl+Left/Right${C.reset} Move by word`);
467
+ terminal.writeln(` ${C.yellow}Home/End${C.reset} Start/end of line`);
468
+ terminal.writeln(` ${C.yellow}Ctrl+A/E${C.reset} Start/end of line`);
469
+ terminal.writeln(` ${C.yellow}Ctrl+U${C.reset} Clear line`);
470
+ terminal.writeln(` ${C.yellow}Ctrl+W${C.reset} Delete word`);
471
+ terminal.writeln(` ${C.yellow}Up/Down${C.reset} Navigate history`);
472
+ terminal.writeln(` ${C.yellow}Ctrl+C${C.reset} Cancel input`);
473
+ terminal.writeln("");
474
+ terminal.writeln(`${C.dim}Statements must end with a semicolon (;)${C.reset}`);
475
+ terminal.writeln("");
476
+ }
477
+ function handleMode(args, context) {
478
+ const terminal = context.terminal;
479
+ if (args.length === 0) {
480
+ terminal.writeln(`Current display mode: ${C.cyan}${context.displayMode}${C.reset}`);
481
+ return;
482
+ }
483
+ const mode = args[0].toLowerCase();
484
+ if (mode === "truncate" || mode === "full") {
485
+ context.setDisplayMode(mode);
486
+ terminal.writeln(`Display mode set to: ${C.cyan}${mode}${C.reset}`);
487
+ } else {
488
+ terminal.writeln(
489
+ `${C.red}Unknown mode: ${mode}${C.reset}. Use 'truncate' or 'full'.`
490
+ );
491
+ }
492
+ }
493
+ function showHistory(context) {
494
+ const terminal = context.terminal;
495
+ const entries = context.history.getAll();
496
+ if (entries.length === 0) {
497
+ terminal.writeln(`${C.dim}No command history${C.reset}`);
498
+ return;
499
+ }
500
+ terminal.writeln("");
501
+ terminal.writeln(`${C.bold}${C.cyan}Command history:${C.reset}`);
502
+ terminal.writeln("");
503
+ const toShow = entries.slice(-20);
504
+ const startIdx = entries.length - toShow.length;
505
+ toShow.forEach((entry, i) => {
506
+ const num = String(startIdx + i + 1).padStart(4, " ");
507
+ terminal.writeln(`${C.dim}${num}${C.reset} ${entry}`);
508
+ });
509
+ if (entries.length > 20) {
510
+ terminal.writeln("");
511
+ terminal.writeln(`${C.dim}... and ${entries.length - 20} more entries${C.reset}`);
512
+ }
513
+ terminal.writeln("");
514
+ }
515
+ async function showTables(context) {
516
+ const terminal = context.terminal;
517
+ if (!context.executor.getTables) {
518
+ terminal.writeln(`${C.dim}.tables command not supported by this executor${C.reset}`);
519
+ return;
520
+ }
521
+ const tables = await context.executor.getTables();
522
+ if (tables.length === 0) {
523
+ terminal.writeln(`${C.dim}No tables found${C.reset}`);
524
+ return;
525
+ }
526
+ terminal.writeln("");
527
+ terminal.writeln(`${C.bold}${C.cyan}Tables:${C.reset}`);
528
+ terminal.writeln("");
529
+ tables.forEach((table) => {
530
+ terminal.writeln(` ${C.green}${table}${C.reset}`);
531
+ });
532
+ terminal.writeln("");
533
+ }
534
+ async function showSchema(args, context) {
535
+ const terminal = context.terminal;
536
+ if (!context.executor.getSchema) {
537
+ terminal.writeln(`${C.dim}.schema command not supported by this executor${C.reset}`);
538
+ return;
539
+ }
540
+ if (args.length === 0) {
541
+ terminal.writeln(`${C.red}Usage: .schema <table_name>${C.reset}`);
542
+ return;
543
+ }
544
+ const tableName = args[0];
545
+ const schema = await context.executor.getSchema(tableName);
546
+ if (schema) {
547
+ terminal.writeln("");
548
+ terminal.writeln(schema);
549
+ terminal.writeln("");
550
+ } else {
551
+ terminal.writeln(`${C.red}Table not found: ${tableName}${C.reset}`);
552
+ }
553
+ }
554
+
555
+ // src/output/table.ts
556
+ var TableRenderer = class {
557
+ data;
558
+ columns;
559
+ maxWidth;
560
+ truncate;
561
+ constructor(data, options = {}) {
562
+ this.data = data;
563
+ this.maxWidth = options.maxWidth ?? 120;
564
+ this.truncate = options.truncate ?? true;
565
+ this.columns = this.calculateColumns();
566
+ }
567
+ calculateColumns() {
568
+ if (this.data.length === 0) return [];
569
+ const columns = /* @__PURE__ */ new Map();
570
+ for (const row of this.data) {
571
+ for (const [key, value] of Object.entries(row)) {
572
+ const valueStr = this.formatValue(value);
573
+ const currentMax = columns.get(key) ?? key.length;
574
+ columns.set(key, Math.max(currentMax, valueStr.length));
575
+ }
576
+ }
577
+ return Array.from(columns.entries()).map(([name, width]) => ({
578
+ name,
579
+ width: Math.max(width, name.length)
580
+ }));
581
+ }
582
+ formatValue(value) {
583
+ if (value === null || value === void 0) {
584
+ return "null";
585
+ }
586
+ if (typeof value === "object") {
587
+ return JSON.stringify(value);
588
+ }
589
+ return String(value);
590
+ }
591
+ truncateString(str, maxLen) {
592
+ if (str.length <= maxLen) return str;
593
+ if (maxLen <= 3) return str.slice(0, maxLen);
594
+ return str.slice(0, maxLen - 3) + "...";
595
+ }
596
+ render() {
597
+ if (this.data.length === 0 || this.columns.length === 0) {
598
+ return ["(no results)"];
599
+ }
600
+ const lines = [];
601
+ let columnsToShow = this.columns;
602
+ let widths = this.columns.map((c) => c.width);
603
+ if (this.truncate) {
604
+ const result = this.fitColumns(this.maxWidth);
605
+ columnsToShow = result.columns;
606
+ widths = result.widths;
607
+ }
608
+ const separator = "+" + widths.map((w) => "-".repeat(w + 2)).join("+") + "+";
609
+ lines.push(separator);
610
+ const headerCells = columnsToShow.map(
611
+ (col, i) => this.padCenter(col.name, widths[i])
612
+ );
613
+ lines.push("| " + headerCells.join(" | ") + " |");
614
+ lines.push(separator);
615
+ for (const row of this.data) {
616
+ const cells = columnsToShow.map((col, i) => {
617
+ const value = this.formatValue(row[col.name]);
618
+ const truncated = this.truncate ? this.truncateString(value, widths[i]) : value;
619
+ return this.padRight(truncated, widths[i]);
620
+ });
621
+ lines.push("| " + cells.join(" | ") + " |");
622
+ }
623
+ lines.push(separator);
624
+ return lines;
625
+ }
626
+ fitColumns(maxWidth) {
627
+ const columns = [];
628
+ const widths = [];
629
+ let currentWidth = 1;
630
+ for (const col of this.columns) {
631
+ const colWidth = Math.min(col.width, 40);
632
+ const totalColWidth = colWidth + 3;
633
+ if (currentWidth + totalColWidth <= maxWidth) {
634
+ columns.push(col);
635
+ widths.push(colWidth);
636
+ currentWidth += totalColWidth;
637
+ } else {
638
+ break;
639
+ }
640
+ }
641
+ if (columns.length === 0 && this.columns.length > 0) {
642
+ const firstCol = this.columns[0];
643
+ const availableWidth = maxWidth - 4;
644
+ columns.push(firstCol);
645
+ widths.push(Math.max(availableWidth, 10));
646
+ }
647
+ return { columns, widths };
648
+ }
649
+ padCenter(str, width) {
650
+ const padding = width - str.length;
651
+ if (padding <= 0) return str.slice(0, width);
652
+ const left = Math.floor(padding / 2);
653
+ const right = padding - left;
654
+ return " ".repeat(left) + str + " ".repeat(right);
655
+ }
656
+ padRight(str, width) {
657
+ const padding = width - str.length;
658
+ if (padding <= 0) return str.slice(0, width);
659
+ return str + " ".repeat(padding);
660
+ }
661
+ };
662
+
663
+ // src/output/formatter.ts
664
+ var C2 = TerminalAdapter.COLORS;
665
+ var OutputFormatter = class {
666
+ terminal;
667
+ displayMode;
668
+ constructor(terminal, displayMode = "truncate") {
669
+ this.terminal = terminal;
670
+ this.displayMode = displayMode;
671
+ }
672
+ setDisplayMode(mode) {
673
+ this.displayMode = mode;
674
+ }
675
+ formatResult(result) {
676
+ if (!result.success) {
677
+ this.formatError(result.error ?? "Unknown error", result.executionTime);
678
+ return;
679
+ }
680
+ if (!result.data || result.data.length === 0) {
681
+ this.terminal.writeln("");
682
+ this.terminal.writeln(`${C2.dim}Query executed successfully. No rows returned.${C2.reset}`);
683
+ this.formatExecutionTime(result.executionTime);
684
+ return;
685
+ }
686
+ this.formatTable(result.data, result.executionTime);
687
+ }
688
+ formatTable(data, executionTime) {
689
+ const renderer = new TableRenderer(data, {
690
+ maxWidth: this.displayMode === "truncate" ? this.terminal.cols - 2 : void 0,
691
+ truncate: this.displayMode === "truncate"
692
+ });
693
+ const lines = renderer.render();
694
+ this.terminal.writeln("");
695
+ for (const line of lines) {
696
+ this.terminal.writeln(line);
697
+ }
698
+ const rowCount = data.length;
699
+ this.terminal.writeln("");
700
+ this.terminal.write(
701
+ `${C2.green}${rowCount} row${rowCount !== 1 ? "s" : ""}${C2.reset}`
702
+ );
703
+ this.formatExecutionTime(executionTime);
704
+ }
705
+ formatError(error, executionTime) {
706
+ this.terminal.writeln("");
707
+ this.terminal.writeln(`${C2.red}Error: ${error}${C2.reset}`);
708
+ this.formatExecutionTime(executionTime);
709
+ }
710
+ formatExecutionTime(ms) {
711
+ this.terminal.writeln(` ${C2.dim}(${ms}ms)${C2.reset}`);
712
+ }
713
+ };
714
+
715
+ // src/shell.ts
716
+ var C3 = COLORS;
717
+ var DEFAULT_PRIMARY_PROMPT = `${C3.cyan}reifydb${C3.reset}${C3.brightBlack}>${C3.reset} `;
718
+ var DEFAULT_CONTINUATION_PROMPT = `${C3.brightBlack} ...${C3.reset} `;
719
+ var DEFAULT_PRIMARY_PROMPT_LEN = 9;
720
+ var DEFAULT_CONTINUATION_PROMPT_LEN = 8;
721
+ var Shell = class {
722
+ terminal;
723
+ lineEditor;
724
+ history;
725
+ multiline;
726
+ executor;
727
+ formatter;
728
+ displayMode;
729
+ isExited = false;
730
+ // Configurable options
731
+ primaryPrompt;
732
+ primaryPromptLen;
733
+ continuationPrompt;
734
+ continuationPromptLen;
735
+ welcomeMessage;
736
+ onExit;
737
+ constructor(container, options) {
738
+ this.executor = options.executor;
739
+ this.displayMode = options.displayMode ?? "truncate";
740
+ this.welcomeMessage = options.welcomeMessage;
741
+ this.onExit = options.onExit;
742
+ this.primaryPrompt = options.prompt ?? DEFAULT_PRIMARY_PROMPT;
743
+ this.primaryPromptLen = options.promptLength ?? DEFAULT_PRIMARY_PROMPT_LEN;
744
+ this.continuationPrompt = options.continuationPrompt ?? DEFAULT_CONTINUATION_PROMPT;
745
+ this.continuationPromptLen = options.continuationPromptLength ?? DEFAULT_CONTINUATION_PROMPT_LEN;
746
+ this.terminal = new TerminalAdapter(container, options.theme);
747
+ this.lineEditor = new LineEditor(this.terminal);
748
+ this.history = new CommandHistory(options.historyStorage, options.historyKey);
749
+ this.multiline = new MultilineBuffer();
750
+ this.formatter = new OutputFormatter(this.terminal, this.displayMode);
751
+ this.setupKeyHandler();
752
+ }
753
+ start() {
754
+ this.showWelcomeBanner();
755
+ this.showPrompt();
756
+ this.terminal.focus();
757
+ }
758
+ dispose() {
759
+ this.isExited = true;
760
+ this.terminal.dispose();
761
+ }
762
+ showWelcomeBanner() {
763
+ if (this.welcomeMessage === void 0) {
764
+ this.terminal.writeln("");
765
+ this.terminal.writeln(`${C3.bold}${C3.cyan}ReifyDB Shell${C3.reset}`);
766
+ this.terminal.writeln("");
767
+ this.terminal.writeln(`Type ${C3.green}.help${C3.reset} for available commands`);
768
+ this.terminal.writeln(`Statements must end with a semicolon ${C3.yellow};${C3.reset}`);
769
+ this.terminal.writeln("");
770
+ return;
771
+ }
772
+ let lines;
773
+ if (typeof this.welcomeMessage === "function") {
774
+ lines = this.welcomeMessage();
775
+ } else if (Array.isArray(this.welcomeMessage)) {
776
+ lines = this.welcomeMessage;
777
+ } else {
778
+ lines = [this.welcomeMessage];
779
+ }
780
+ for (const line of lines) {
781
+ this.terminal.writeln(line);
782
+ }
783
+ }
784
+ showPrompt() {
785
+ const prompt = this.multiline.isEmpty ? this.primaryPrompt : this.continuationPrompt;
786
+ this.terminal.write(prompt);
787
+ }
788
+ getCurrentPromptLen() {
789
+ return this.multiline.isEmpty ? this.primaryPromptLen : this.continuationPromptLen;
790
+ }
791
+ setupKeyHandler() {
792
+ this.terminal.onKey((key, event) => {
793
+ if (this.isExited) return;
794
+ this.handleKey(key, event);
795
+ });
796
+ }
797
+ handleKey(key, event) {
798
+ const code = event.keyCode;
799
+ if (event.ctrlKey) {
800
+ switch (event.key.toLowerCase()) {
801
+ case "a":
802
+ event.preventDefault();
803
+ this.lineEditor.moveToStart();
804
+ return;
805
+ case "e":
806
+ event.preventDefault();
807
+ this.lineEditor.moveToEnd();
808
+ return;
809
+ case "u":
810
+ event.preventDefault();
811
+ this.lineEditor.clearLine();
812
+ this.redrawLine();
813
+ return;
814
+ case "w":
815
+ event.preventDefault();
816
+ this.lineEditor.deleteWord();
817
+ this.redrawLine();
818
+ return;
819
+ case "c":
820
+ event.preventDefault();
821
+ this.terminal.writeln("^C");
822
+ this.lineEditor.clear();
823
+ this.multiline.clear();
824
+ this.history.reset();
825
+ this.showPrompt();
826
+ return;
827
+ case "l":
828
+ event.preventDefault();
829
+ this.clearScreen();
830
+ return;
831
+ }
832
+ if (code === 37) {
833
+ event.preventDefault();
834
+ this.lineEditor.moveWordLeft();
835
+ return;
836
+ }
837
+ if (code === 39) {
838
+ event.preventDefault();
839
+ this.lineEditor.moveWordRight();
840
+ return;
841
+ }
842
+ return;
843
+ }
844
+ switch (code) {
845
+ case 13:
846
+ this.handleEnter();
847
+ return;
848
+ case 8:
849
+ if (this.lineEditor.backspace()) {
850
+ this.redrawLine();
851
+ }
852
+ return;
853
+ case 46:
854
+ if (this.lineEditor.delete()) {
855
+ this.redrawLine();
856
+ }
857
+ return;
858
+ case 37:
859
+ this.lineEditor.moveLeft();
860
+ return;
861
+ case 39:
862
+ this.lineEditor.moveRight();
863
+ return;
864
+ case 38:
865
+ this.navigateHistory("up");
866
+ return;
867
+ case 40:
868
+ this.navigateHistory("down");
869
+ return;
870
+ case 36:
871
+ this.lineEditor.moveToStart();
872
+ return;
873
+ case 35:
874
+ this.lineEditor.moveToEnd();
875
+ return;
876
+ case 9:
877
+ return;
878
+ case 27:
879
+ return;
880
+ }
881
+ if (key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey) {
882
+ this.lineEditor.insert(key);
883
+ this.redrawLine();
884
+ }
885
+ }
886
+ redrawLine() {
887
+ const prompt = this.multiline.isEmpty ? this.primaryPrompt : this.continuationPrompt;
888
+ this.lineEditor.render(prompt);
889
+ }
890
+ navigateHistory(direction) {
891
+ let entry;
892
+ if (direction === "up") {
893
+ entry = this.history.previous(this.lineEditor.value);
894
+ } else {
895
+ entry = this.history.next();
896
+ }
897
+ if (entry !== null) {
898
+ this.lineEditor.setValue(entry);
899
+ this.redrawLine();
900
+ }
901
+ }
902
+ async handleEnter() {
903
+ const line = this.lineEditor.value;
904
+ this.terminal.writeln("");
905
+ this.lineEditor.clear();
906
+ if (this.multiline.isEmpty && line.trim().startsWith(".")) {
907
+ this.history.add(line);
908
+ const result = await handleDotCommand(line, {
909
+ terminal: this.terminal,
910
+ executor: this.executor,
911
+ history: this.history,
912
+ displayMode: this.displayMode,
913
+ setDisplayMode: (mode) => {
914
+ this.displayMode = mode;
915
+ this.formatter.setDisplayMode(mode);
916
+ },
917
+ clearScreen: () => this.clearScreen()
918
+ });
919
+ if (result.exit) {
920
+ this.isExited = true;
921
+ if (this.onExit) {
922
+ this.onExit();
923
+ }
924
+ return;
925
+ }
926
+ this.showPrompt();
927
+ return;
928
+ }
929
+ this.multiline.addLine(line);
930
+ if (this.multiline.isComplete()) {
931
+ const statement = this.multiline.content;
932
+ this.multiline.clear();
933
+ this.history.add(statement);
934
+ this.history.reset();
935
+ const result = await this.executor.execute(statement);
936
+ this.formatter.formatResult(result);
937
+ }
938
+ this.showPrompt();
939
+ }
940
+ clearScreen() {
941
+ this.terminal.write(TerminalAdapter.clearScreen());
942
+ this.showPrompt();
943
+ this.terminal.write(this.lineEditor.value);
944
+ }
945
+ };
946
+
947
+ // src/executors/wasm-executor.ts
948
+ var WasmExecutor = class {
949
+ db;
950
+ constructor(db) {
951
+ this.db = db;
952
+ }
953
+ async execute(statement) {
954
+ const trimmed = statement.trim();
955
+ const query = trimmed.endsWith(";") ? trimmed.slice(0, -1).trim() : trimmed;
956
+ if (!query) {
957
+ return {
958
+ success: true,
959
+ data: [],
960
+ executionTime: 0
961
+ };
962
+ }
963
+ const startTime = performance.now();
964
+ try {
965
+ const results = await this.db.admin(query);
966
+ const endTime = performance.now();
967
+ return {
968
+ success: true,
969
+ data: Array.isArray(results) ? results : [],
970
+ executionTime: Math.round(endTime - startTime)
971
+ };
972
+ } catch (error) {
973
+ const endTime = performance.now();
974
+ return {
975
+ success: false,
976
+ error: error instanceof Error ? error.message : String(error),
977
+ executionTime: Math.round(endTime - startTime)
978
+ };
979
+ }
980
+ }
981
+ async getTables() {
982
+ try {
983
+ const result = await this.db.admin("FROM system.tables MAP { namespace, name }");
984
+ if (Array.isArray(result)) {
985
+ return result.map((row) => {
986
+ const ns = row.namespace;
987
+ const name = row.name;
988
+ return ns ? `${ns}.${name}` : name;
989
+ });
990
+ }
991
+ return [];
992
+ } catch {
993
+ return [];
994
+ }
995
+ }
996
+ async getSchema(tableName) {
997
+ try {
998
+ const result = await this.db.admin(
999
+ `FROM system.columns FILTER table = "${tableName}" MAP { name, type }`
1000
+ );
1001
+ if (Array.isArray(result) && result.length > 0) {
1002
+ const columns = result.map(
1003
+ (row) => ` ${row.name}: ${row.type}`
1004
+ ).join(",\n");
1005
+ return `${tableName} {
1006
+ ${columns}
1007
+ }`;
1008
+ }
1009
+ return null;
1010
+ } catch {
1011
+ return null;
1012
+ }
1013
+ }
1014
+ };
1015
+
1016
+ // src/executors/ws-executor.ts
1017
+ var WsExecutor = class {
1018
+ client;
1019
+ constructor(client) {
1020
+ this.client = client;
1021
+ }
1022
+ async execute(statement) {
1023
+ const trimmed = statement.trim();
1024
+ const query = trimmed.endsWith(";") ? trimmed.slice(0, -1).trim() : trimmed;
1025
+ if (!query) {
1026
+ return {
1027
+ success: true,
1028
+ data: [],
1029
+ executionTime: 0
1030
+ };
1031
+ }
1032
+ const startTime = performance.now();
1033
+ try {
1034
+ const frames = await this.client.admin(query, null, []);
1035
+ const endTime = performance.now();
1036
+ const results = frames[0] ?? [];
1037
+ const data = results.map((row) => {
1038
+ if (row && typeof row === "object") {
1039
+ const plainRow = {};
1040
+ for (const [key, value] of Object.entries(row)) {
1041
+ if (value && typeof value === "object" && typeof value.valueOf === "function") {
1042
+ plainRow[key] = value.valueOf();
1043
+ } else {
1044
+ plainRow[key] = value;
1045
+ }
1046
+ }
1047
+ return plainRow;
1048
+ }
1049
+ return row;
1050
+ });
1051
+ return {
1052
+ success: true,
1053
+ data,
1054
+ executionTime: Math.round(endTime - startTime)
1055
+ };
1056
+ } catch (error) {
1057
+ const endTime = performance.now();
1058
+ let errorMessage;
1059
+ if (error && typeof error === "object" && "diagnostic" in error) {
1060
+ const diagnostic = error.diagnostic;
1061
+ errorMessage = diagnostic.message;
1062
+ } else if (error instanceof Error) {
1063
+ errorMessage = error.message;
1064
+ } else {
1065
+ errorMessage = String(error);
1066
+ }
1067
+ return {
1068
+ success: false,
1069
+ error: errorMessage,
1070
+ executionTime: Math.round(endTime - startTime)
1071
+ };
1072
+ }
1073
+ }
1074
+ async getTables() {
1075
+ try {
1076
+ const frames = await this.client.admin(
1077
+ "FROM system.tables MAP { namespace, name }",
1078
+ null,
1079
+ []
1080
+ );
1081
+ const results = frames[0] ?? [];
1082
+ return results.map((row) => {
1083
+ const r = row;
1084
+ const ns = this.extractValue(r.namespace);
1085
+ const name = this.extractValue(r.name);
1086
+ return ns ? `${ns}.${name}` : name;
1087
+ });
1088
+ } catch {
1089
+ return [];
1090
+ }
1091
+ }
1092
+ async getSchema(tableName) {
1093
+ try {
1094
+ const frames = await this.client.admin(
1095
+ `FROM system.columns FILTER table = "${tableName}" MAP { name, type }`,
1096
+ null,
1097
+ []
1098
+ );
1099
+ const results = frames[0] ?? [];
1100
+ if (results.length > 0) {
1101
+ const columns = results.map((row) => {
1102
+ const r = row;
1103
+ return ` ${this.extractValue(r.name)}: ${this.extractValue(r.type)}`;
1104
+ }).join(",\n");
1105
+ return `${tableName} {
1106
+ ${columns}
1107
+ }`;
1108
+ }
1109
+ return null;
1110
+ } catch {
1111
+ return null;
1112
+ }
1113
+ }
1114
+ extractValue(value) {
1115
+ if (value && typeof value === "object" && typeof value.valueOf === "function") {
1116
+ return value.valueOf();
1117
+ }
1118
+ return value;
1119
+ }
1120
+ };
1121
+ export {
1122
+ COLORS,
1123
+ CommandHistory,
1124
+ LineEditor,
1125
+ LocalStorageHistoryStorage,
1126
+ MemoryHistoryStorage,
1127
+ MultilineBuffer,
1128
+ OutputFormatter,
1129
+ Shell,
1130
+ TableRenderer,
1131
+ TerminalAdapter,
1132
+ WasmExecutor,
1133
+ WsExecutor,
1134
+ defaultTheme,
1135
+ handleDotCommand
1136
+ };
1137
+ //# sourceMappingURL=index.js.map