browser-terminal-cli 1.0.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/README.md ADDED
@@ -0,0 +1,1130 @@
1
+ # Browser Terminal CLI
2
+
3
+ [![npm version](https://img.shields.io/npm/v/browser-terminal-cli.svg)](https://www.npmjs.com/package/browser-terminal-cli)
4
+ [![npm downloads](https://img.shields.io/npm/dm/browser-terminal-cli.svg)](https://www.npmjs.com/package/browser-terminal-cli)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Zero Dependencies](https://img.shields.io/badge/Dependencies-Zero-green.svg)](#)
8
+
9
+ A powerful, customizable, and lightweight terminal/CLI interface for browser-side JavaScript applications. Create beautiful command-line interfaces in your web apps with ease.
10
+
11
+ <p align="center">
12
+ <img src="https://raw.githubusercontent.com/yourusername/browser-terminal-cli/main/demo.gif" alt="Browser Terminal CLI Demo" width="700">
13
+ </p>
14
+
15
+ ## ✨ Features
16
+
17
+ - 🎨 **9 Built-in Themes** - Dracula, Monokai, Matrix, Ubuntu, Solarized, and more
18
+ - ⌨️ **Command History** - Navigate with arrow keys, persistent storage ready
19
+ - 📝 **Tab Completion** - Auto-complete command names
20
+ - 🔌 **Easy Command Registration** - Simple API for adding custom commands
21
+ - 🎯 **Full TypeScript Support** - Complete type definitions included
22
+ - 📦 **Zero Dependencies** - Lightweight (~15KB minified)
23
+ - ⚡ **Keyboard Shortcuts** - Ctrl+C, Ctrl+L, Ctrl+U support
24
+ - 📊 **Rich Output** - Tables, colors, styled text, HTML support
25
+ - 🎭 **Customizable** - Prompts, themes, fonts, cursor styles
26
+ - 🔄 **Async Commands** - Full Promise/async-await support
27
+ - 📱 **Responsive** - Works on desktop and mobile browsers
28
+
29
+ ## 📦 Installation
30
+
31
+ ### NPM
32
+
33
+ ```bash
34
+ npm install browser-terminal-cli
35
+ ```
36
+
37
+ ### Yarn
38
+
39
+ ```bash
40
+ yarn add browser-terminal-cli
41
+ ```
42
+
43
+ ### PNPM
44
+
45
+ ```bash
46
+ pnpm add browser-terminal-cli
47
+ ```
48
+
49
+ ### CDN
50
+
51
+ ```html
52
+ <!-- UMD Build -->
53
+ <script src="https://unpkg.com/browser-terminal-cli/dist/index.umd.js"></script>
54
+
55
+ <!-- ESM Build -->
56
+ <script type="module">
57
+ import { Terminal } from 'https://unpkg.com/browser-terminal-cli/dist/index.esm.js';
58
+ </script>
59
+ ```
60
+
61
+ ## 🚀 Quick Start
62
+
63
+ ### ES Modules
64
+
65
+ ```javascript
66
+ import { Terminal } from 'browser-terminal-cli';
67
+
68
+ const terminal = new Terminal({
69
+ container: '#terminal',
70
+ prompt: '❯ ',
71
+ welcomeMessage: 'Welcome! Type "help" for available commands.',
72
+ theme: 'dracula',
73
+ });
74
+
75
+ // Add a simple command
76
+ terminal.addCommand('hello', () => {
77
+ return 'Hello, World!';
78
+ }, 'Say hello');
79
+
80
+ // Add a command with arguments
81
+ terminal.addCommand('greet', ({ args }) => {
82
+ const name = args[0] || 'stranger';
83
+ return `Hello, ${name}!`;
84
+ }, 'Greet someone by name');
85
+ ```
86
+
87
+ ### HTML Setup
88
+
89
+ ```html
90
+ <!DOCTYPE html>
91
+ <html>
92
+ <head>
93
+ <style>
94
+ #terminal {
95
+ width: 800px;
96
+ height: 400px;
97
+ border-radius: 8px;
98
+ overflow: hidden;
99
+ }
100
+ </style>
101
+ </head>
102
+ <body>
103
+ <div id="terminal"></div>
104
+
105
+ <script type="module">
106
+ import { Terminal } from 'browser-terminal-cli';
107
+
108
+ const terminal = new Terminal({
109
+ container: '#terminal',
110
+ theme: 'monokai',
111
+ });
112
+ </script>
113
+ </body>
114
+ </html>
115
+ ```
116
+
117
+ ### UMD (Script Tag)
118
+
119
+ ```html
120
+ <script src="https://unpkg.com/browser-terminal-cli/dist/index.umd.js"></script>
121
+ <script>
122
+ const terminal = new BrowserTerminal.Terminal({
123
+ container: '#terminal',
124
+ });
125
+ </script>
126
+ ```
127
+
128
+ ## 📖 API Reference
129
+
130
+ ### Constructor Options
131
+
132
+ ```typescript
133
+ const terminal = new Terminal(options: TerminalOptions);
134
+ ```
135
+
136
+ | Option | Type | Default | Description |
137
+ |--------|------|---------|-------------|
138
+ | `container` | `HTMLElement \| string` | **required** | Container element or CSS selector |
139
+ | `prompt` | `string` | `'$ '` | Command prompt string |
140
+ | `welcomeMessage` | `string \| string[]` | `''` | Welcome message displayed on init |
141
+ | `theme` | `string \| TerminalTheme` | `'default'` | Theme name or custom theme object |
142
+ | `fontSize` | `number` | `14` | Font size in pixels |
143
+ | `fontFamily` | `string` | `'Cascadia Code', monospace` | Font family |
144
+ | `cursorStyle` | `'block' \| 'underline' \| 'bar'` | `'block'` | Cursor style |
145
+ | `cursorBlink` | `boolean` | `true` | Enable cursor blinking |
146
+ | `history` | `boolean` | `true` | Enable command history |
147
+ | `historySize` | `number` | `100` | Maximum history entries |
148
+ | `autoFocus` | `boolean` | `true` | Auto-focus terminal on init |
149
+ | `scrollback` | `number` | `1000` | Maximum output lines to keep |
150
+ | `tabSize` | `number` | `4` | Tab character width |
151
+
152
+ ### Output Methods
153
+
154
+ #### `write(text, options?)`
155
+
156
+ Write text without a newline.
157
+
158
+ ```javascript
159
+ terminal.write('Hello ');
160
+ terminal.write('World!');
161
+ // Output: Hello World!
162
+ ```
163
+
164
+ #### `writeln(text, options?)`
165
+
166
+ Write text with a newline.
167
+
168
+ ```javascript
169
+ terminal.writeln('Line 1');
170
+ terminal.writeln('Line 2');
171
+ ```
172
+
173
+ #### `writeError(text)`
174
+
175
+ Write error message (red color).
176
+
177
+ ```javascript
178
+ terminal.writeError('Something went wrong!');
179
+ ```
180
+
181
+ #### `writeSuccess(text)`
182
+
183
+ Write success message (green color).
184
+
185
+ ```javascript
186
+ terminal.writeSuccess('Operation completed!');
187
+ ```
188
+
189
+ #### `writeWarning(text)`
190
+
191
+ Write warning message (yellow color).
192
+
193
+ ```javascript
194
+ terminal.writeWarning('This is deprecated');
195
+ ```
196
+
197
+ #### `writeInfo(text)`
198
+
199
+ Write info message (blue color).
200
+
201
+ ```javascript
202
+ terminal.writeInfo('Tip: Use help for more commands');
203
+ ```
204
+
205
+ #### `writeTable(data, columns?)`
206
+
207
+ Write formatted table.
208
+
209
+ ```javascript
210
+ terminal.writeTable([
211
+ { name: 'John', age: 30, city: 'NYC' },
212
+ { name: 'Jane', age: 25, city: 'LA' },
213
+ { name: 'Bob', age: 35, city: 'Chicago' },
214
+ ]);
215
+
216
+ // Output:
217
+ // name | age | city
218
+ // -----+-----+--------
219
+ // John | 30 | NYC
220
+ // Jane | 25 | LA
221
+ // Bob | 35 | Chicago
222
+ ```
223
+
224
+ #### `clear()`
225
+
226
+ Clear all terminal output.
227
+
228
+ ```javascript
229
+ terminal.clear();
230
+ ```
231
+
232
+ ### Output Options
233
+
234
+ ```typescript
235
+ interface OutputOptions {
236
+ color?: string; // Text color (CSS color)
237
+ backgroundColor?: string; // Background color
238
+ bold?: boolean; // Bold text
239
+ italic?: boolean; // Italic text
240
+ underline?: boolean; // Underlined text
241
+ className?: string; // Custom CSS class
242
+ html?: boolean; // Parse as HTML
243
+ }
244
+ ```
245
+
246
+ **Examples:**
247
+
248
+ ```javascript
249
+ // Colored text
250
+ terminal.writeln('Error!', { color: '#ff5555' });
251
+ terminal.writeln('Success!', { color: 'rgb(80, 250, 123)' });
252
+
253
+ // Styled text
254
+ terminal.writeln('Important', { bold: true });
255
+ terminal.writeln('Emphasis', { italic: true });
256
+ terminal.writeln('Link', { underline: true, color: '#8be9fd' });
257
+
258
+ // Combined styles
259
+ terminal.writeln('Critical Error', {
260
+ color: '#ff5555',
261
+ bold: true,
262
+ backgroundColor: '#1a1a1a'
263
+ });
264
+
265
+ // HTML content
266
+ terminal.writeln('<strong>Bold</strong> and <em>italic</em>', { html: true });
267
+ terminal.writeln('<span style="color: red">Red text</span>', { html: true });
268
+
269
+ // Custom class
270
+ terminal.writeln('Custom styled', { className: 'my-custom-class' });
271
+ ```
272
+
273
+ ---
274
+
275
+ ### Command Registration
276
+
277
+ #### `addCommand(name, handler, description?)`
278
+
279
+ Simple command registration.
280
+
281
+ ```javascript
282
+ terminal.addCommand('time', () => {
283
+ return new Date().toLocaleTimeString();
284
+ }, 'Display current time');
285
+
286
+ terminal.addCommand('add', ({ args }) => {
287
+ const sum = args.reduce((a, b) => a + parseFloat(b), 0);
288
+ return `Sum: ${sum}`;
289
+ }, 'Add numbers together');
290
+ ```
291
+
292
+ #### `registerCommand(definition)`
293
+
294
+ Advanced command registration.
295
+
296
+ ```typescript
297
+ interface CommandDefinition {
298
+ name: string; // Command name
299
+ handler: CommandHandler; // Handler function
300
+ description?: string; // Help description
301
+ usage?: string; // Usage example
302
+ aliases?: string[]; // Alternative names
303
+ }
304
+ ```
305
+
306
+ ```javascript
307
+ terminal.registerCommand({
308
+ name: 'fetch',
309
+ description: 'Fetch data from a URL',
310
+ usage: 'fetch <url> [--json]',
311
+ aliases: ['get', 'request'],
312
+ handler: async ({ args, flags, terminal }) => {
313
+ const url = args[0];
314
+ if (!url) {
315
+ terminal.writeError('Usage: fetch <url>');
316
+ return;
317
+ }
318
+
319
+ try {
320
+ terminal.writeln(`Fetching ${url}...`);
321
+ const response = await fetch(url);
322
+ const data = flags.json
323
+ ? await response.json()
324
+ : await response.text();
325
+
326
+ return typeof data === 'object'
327
+ ? JSON.stringify(data, null, 2)
328
+ : data;
329
+ } catch (error) {
330
+ terminal.writeError(`Failed: ${error.message}`);
331
+ }
332
+ },
333
+ });
334
+ ```
335
+
336
+ #### `registerCommands(definitions[])`
337
+
338
+ Register multiple commands at once.
339
+
340
+ ```javascript
341
+ terminal.registerCommands([
342
+ {
343
+ name: 'start',
344
+ handler: () => 'Starting...',
345
+ description: 'Start the application',
346
+ },
347
+ {
348
+ name: 'stop',
349
+ handler: () => 'Stopping...',
350
+ description: 'Stop the application',
351
+ },
352
+ ]);
353
+ ```
354
+
355
+ #### `removeCommand(name)`
356
+
357
+ Remove a registered command.
358
+
359
+ ```javascript
360
+ terminal.removeCommand('hello');
361
+ ```
362
+
363
+ #### `hasCommand(name)`
364
+
365
+ Check if command exists.
366
+
367
+ ```javascript
368
+ if (terminal.hasCommand('deploy')) {
369
+ terminal.exec('deploy');
370
+ }
371
+ ```
372
+
373
+ #### `getCommands()`
374
+
375
+ Get all registered commands.
376
+
377
+ ```javascript
378
+ const commands = terminal.getCommands();
379
+ commands.forEach(cmd => {
380
+ console.log(cmd.name, cmd.description);
381
+ });
382
+ ```
383
+
384
+ ### Command Handler Context
385
+
386
+ ```typescript
387
+ interface CommandContext {
388
+ terminal: TerminalInterface; // Terminal instance
389
+ args: string[]; // Positional arguments
390
+ flags: Record<string, string | boolean>; // Parsed flags
391
+ rawInput: string; // Original input string
392
+ }
393
+ ```
394
+
395
+ **Example:**
396
+
397
+ ```javascript
398
+ terminal.addCommand('example', (context) => {
399
+ const { terminal, args, flags, rawInput } = context;
400
+
401
+ console.log('Raw input:', rawInput);
402
+ console.log('Arguments:', args);
403
+ console.log('Flags:', flags);
404
+
405
+ // Use terminal methods
406
+ terminal.writeln('Processing...');
407
+
408
+ if (flags.verbose) {
409
+ terminal.writeln('Verbose mode enabled');
410
+ }
411
+
412
+ return `Processed ${args.length} arguments`;
413
+ });
414
+
415
+ // Usage: example arg1 arg2 --verbose --output=file.txt
416
+ // args: ['arg1', 'arg2']
417
+ // flags: { verbose: true, output: 'file.txt' }
418
+ ```
419
+
420
+ ---
421
+
422
+ ### Control Methods
423
+
424
+ #### `focus()`
425
+
426
+ Focus the terminal input.
427
+
428
+ ```javascript
429
+ terminal.focus();
430
+ ```
431
+
432
+ #### `blur()`
433
+
434
+ Remove focus from terminal.
435
+
436
+ ```javascript
437
+ terminal.blur();
438
+ ```
439
+
440
+ #### `disable()`
441
+
442
+ Disable terminal input.
443
+
444
+ ```javascript
445
+ terminal.disable();
446
+ ```
447
+
448
+ #### `enable()`
449
+
450
+ Enable terminal input.
451
+
452
+ ```javascript
453
+ terminal.enable();
454
+ ```
455
+
456
+ #### `setPrompt(prompt)`
457
+
458
+ Change the command prompt.
459
+
460
+ ```javascript
461
+ terminal.setPrompt('>>> ');
462
+ terminal.setPrompt('user@host:~$ ');
463
+ terminal.setPrompt('🚀 ');
464
+ ```
465
+
466
+ #### `getPrompt()`
467
+
468
+ Get current prompt string.
469
+
470
+ ```javascript
471
+ const prompt = terminal.getPrompt(); // '$ '
472
+ ```
473
+
474
+ #### `setValue(value)`
475
+
476
+ Set the input field value.
477
+
478
+ ```javascript
479
+ terminal.setValue('echo hello');
480
+ ```
481
+
482
+ #### `getValue()`
483
+
484
+ Get current input value.
485
+
486
+ ```javascript
487
+ const input = terminal.getValue();
488
+ ```
489
+
490
+ #### `exec(command)`
491
+
492
+ Execute a command programmatically.
493
+
494
+ ```javascript
495
+ await terminal.exec('help');
496
+ await terminal.exec('clear');
497
+ await terminal.exec('echo Hello World');
498
+ ```
499
+
500
+ #### `destroy()`
501
+
502
+ Clean up and remove terminal.
503
+
504
+ ```javascript
505
+ terminal.destroy();
506
+ ```
507
+
508
+ ---
509
+
510
+ ### Theme Methods
511
+
512
+ #### `setTheme(theme)`
513
+
514
+ Change terminal theme.
515
+
516
+ ```javascript
517
+ // Use built-in theme
518
+ terminal.setTheme('dracula');
519
+ terminal.setTheme('matrix');
520
+
521
+ // Use custom theme
522
+ terminal.setTheme({
523
+ background: '#1a1a2e',
524
+ foreground: '#eaeaea',
525
+ cursor: '#00ff88',
526
+ selection: 'rgba(0, 255, 136, 0.3)',
527
+ black: '#000000',
528
+ red: '#ff5555',
529
+ green: '#00ff88',
530
+ yellow: '#ffff55',
531
+ blue: '#5555ff',
532
+ magenta: '#ff55ff',
533
+ cyan: '#55ffff',
534
+ white: '#ffffff',
535
+ });
536
+ ```
537
+
538
+ #### `getTheme()`
539
+
540
+ Get current theme object.
541
+
542
+ ```javascript
543
+ const theme = terminal.getTheme();
544
+ console.log(theme.background); // '#282a36'
545
+ ```
546
+
547
+ ### Available Themes
548
+
549
+ | Theme | Description |
550
+ |-------|-------------|
551
+ | `default` | Default dark theme |
552
+ | `dark` | GitHub dark inspired |
553
+ | `light` | Light theme |
554
+ | `matrix` | Matrix green on black |
555
+ | `ubuntu` | Ubuntu terminal colors |
556
+ | `monokai` | Monokai color scheme |
557
+ | `dracula` | Dracula theme |
558
+ | `solarized-dark` | Solarized dark |
559
+ | `solarized-light` | Solarized light |
560
+
561
+ ---
562
+
563
+ ### History Methods
564
+
565
+ #### `getHistory()`
566
+
567
+ Get command history array.
568
+
569
+ ```javascript
570
+ const history = terminal.getHistory();
571
+ // ['ls', 'cd documents', 'cat file.txt']
572
+ ```
573
+
574
+ #### `clearHistory()`
575
+
576
+ Clear command history.
577
+
578
+ ```javascript
579
+ terminal.clearHistory();
580
+ ```
581
+
582
+ #### `setHistory(history)`
583
+
584
+ Set command history (for persistence).
585
+
586
+ ```javascript
587
+ // Restore from localStorage
588
+ const saved = localStorage.getItem('terminal-history');
589
+ if (saved) {
590
+ terminal.setHistory(JSON.parse(saved));
591
+ }
592
+
593
+ // Save on command
594
+ terminal.on('command', () => {
595
+ localStorage.setItem('terminal-history',
596
+ JSON.stringify(terminal.getHistory())
597
+ );
598
+ });
599
+ ```
600
+
601
+ ---
602
+
603
+ ### Events
604
+
605
+ #### `on(event, callback)`
606
+
607
+ Subscribe to terminal events.
608
+
609
+ ```javascript
610
+ terminal.on('command', (command, args) => {
611
+ console.log('Executed:', command, args);
612
+ analytics.track('command', { command, args });
613
+ });
614
+
615
+ terminal.on('input', (value) => {
616
+ console.log('Input changed:', value);
617
+ });
618
+
619
+ terminal.on('clear', () => {
620
+ console.log('Terminal cleared');
621
+ });
622
+
623
+ terminal.on('ready', () => {
624
+ console.log('Terminal initialized');
625
+ });
626
+
627
+ terminal.on('key', (event) => {
628
+ if (event.key === 'Escape') {
629
+ terminal.blur();
630
+ }
631
+ });
632
+ ```
633
+
634
+ #### `off(event, callback)`
635
+
636
+ Unsubscribe from events.
637
+
638
+ ```javascript
639
+ const handler = (cmd) => console.log(cmd);
640
+ terminal.on('command', handler);
641
+ terminal.off('command', handler);
642
+ ```
643
+
644
+ ### Event Types
645
+
646
+ | Event | Callback Signature | Description |
647
+ |-------|-------------------|-------------|
648
+ | `command` | `(command: string, args: string[]) => void` | Command executed |
649
+ | `input` | `(value: string) => void` | Input value changed |
650
+ | `clear` | `() => void` | Terminal cleared |
651
+ | `ready` | `() => void` | Terminal initialized |
652
+ | `key` | `(event: KeyboardEvent) => void` | Key pressed |
653
+
654
+ ---
655
+
656
+ ### Built-in Commands
657
+
658
+ | Command | Description |
659
+ |---------|-------------|
660
+ | `help` | Show all available commands |
661
+ | `help <command>` | Show help for specific command |
662
+ | `clear` | Clear terminal screen |
663
+ | `history` | Show command history |
664
+ | `echo <text>` | Print text to terminal |
665
+
666
+ ---
667
+
668
+ ### Keyboard Shortcuts
669
+
670
+ | Shortcut | Action |
671
+ |----------|--------|
672
+ | `↑` Arrow Up | Previous command in history |
673
+ | `↓` Arrow Down | Next command in history |
674
+ | `Tab` | Auto-complete command name |
675
+ | `Ctrl + C` | Cancel current input |
676
+ | `Ctrl + L` | Clear terminal |
677
+ | `Ctrl + U` | Clear current line |
678
+ | `Enter` | Execute command |
679
+
680
+ ---
681
+
682
+ ## 🎨 Theming
683
+
684
+ ### Custom Theme Object
685
+
686
+ ```typescript
687
+ interface TerminalTheme {
688
+ background: string; // Background color
689
+ foreground: string; // Default text color
690
+ cursor: string; // Cursor color
691
+ cursorAccent?: string; // Cursor text color
692
+ selection?: string; // Selection background
693
+
694
+ // ANSI Colors
695
+ black?: string;
696
+ red?: string;
697
+ green?: string;
698
+ yellow?: string;
699
+ blue?: string;
700
+ magenta?: string;
701
+ cyan?: string;
702
+ white?: string;
703
+
704
+ // Bright ANSI Colors
705
+ brightBlack?: string;
706
+ brightRed?: string;
707
+ brightGreen?: string;
708
+ brightYellow?: string;
709
+ brightBlue?: string;
710
+ brightMagenta?: string;
711
+ brightCyan?: string;
712
+ brightWhite?: string;
713
+ }
714
+ ```
715
+
716
+ ### Theme Examples
717
+
718
+ ```javascript
719
+ // Cyberpunk theme
720
+ terminal.setTheme({
721
+ background: '#0a0a0f',
722
+ foreground: '#0ff',
723
+ cursor: '#f0f',
724
+ green: '#0f0',
725
+ red: '#f00',
726
+ yellow: '#ff0',
727
+ blue: '#00f',
728
+ magenta: '#f0f',
729
+ cyan: '#0ff',
730
+ });
731
+
732
+ // Nord theme
733
+ terminal.setTheme({
734
+ background: '#2e3440',
735
+ foreground: '#d8dee9',
736
+ cursor: '#d8dee9',
737
+ black: '#3b4252',
738
+ red: '#bf616a',
739
+ green: '#a3be8c',
740
+ yellow: '#ebcb8b',
741
+ blue: '#81a1c1',
742
+ magenta: '#b48ead',
743
+ cyan: '#88c0d0',
744
+ white: '#e5e9f0',
745
+ });
746
+ ```
747
+
748
+ ---
749
+
750
+ ## 💡 Examples
751
+
752
+ ### File System Simulation
753
+
754
+ ```javascript
755
+ const fs = {
756
+ '/': { type: 'dir', children: ['home', 'usr', 'var'] },
757
+ '/home': { type: 'dir', children: ['user'] },
758
+ '/home/user': { type: 'dir', children: ['documents', 'readme.txt'] },
759
+ '/home/user/readme.txt': { type: 'file', content: 'Hello World!' },
760
+ };
761
+
762
+ let cwd = '/home/user';
763
+
764
+ terminal.addCommand('pwd', () => cwd);
765
+
766
+ terminal.addCommand('ls', ({ args }) => {
767
+ const path = args[0] ? resolvePath(args[0]) : cwd;
768
+ const node = fs[path];
769
+ if (!node) return `ls: ${path}: No such file or directory`;
770
+ if (node.type === 'file') return path.split('/').pop();
771
+ return node.children.join(' ');
772
+ });
773
+
774
+ terminal.addCommand('cd', ({ args }) => {
775
+ const path = args[0] ? resolvePath(args[0]) : '/home/user';
776
+ if (!fs[path] || fs[path].type !== 'dir') {
777
+ return `cd: ${args[0]}: Not a directory`;
778
+ }
779
+ cwd = path;
780
+ terminal.setPrompt(`${cwd} $ `);
781
+ });
782
+
783
+ terminal.addCommand('cat', ({ args }) => {
784
+ const path = resolvePath(args[0]);
785
+ const node = fs[path];
786
+ if (!node) return `cat: ${args[0]}: No such file`;
787
+ if (node.type !== 'file') return `cat: ${args[0]}: Is a directory`;
788
+ return node.content;
789
+ });
790
+
791
+ function resolvePath(path) {
792
+ if (path.startsWith('/')) return path;
793
+ if (path === '..') return cwd.split('/').slice(0, -1).join('/') || '/';
794
+ return `${cwd}/${path}`.replace(/\/+/g, '/');
795
+ }
796
+ ```
797
+
798
+ ### Interactive Game
799
+
800
+ ```javascript
801
+ let gameState = {
802
+ score: 0,
803
+ level: 1,
804
+ target: randomTarget(),
805
+ };
806
+
807
+ function randomTarget() {
808
+ return Math.floor(Math.random() * 100) + 1;
809
+ }
810
+
811
+ terminal.registerCommand({
812
+ name: 'play',
813
+ description: 'Start the number guessing game',
814
+ handler: ({ terminal }) => {
815
+ gameState = { score: 0, level: 1, target: randomTarget() };
816
+ terminal.writeln('🎮 Number Guessing Game Started!');
817
+ terminal.writeln('Guess a number between 1-100');
818
+ terminal.writeln('Use: guess <number>');
819
+ },
820
+ });
821
+
822
+ terminal.registerCommand({
823
+ name: 'guess',
824
+ description: 'Guess the number',
825
+ usage: 'guess <number>',
826
+ handler: ({ args, terminal }) => {
827
+ const num = parseInt(args[0]);
828
+
829
+ if (isNaN(num)) {
830
+ return 'Please enter a valid number';
831
+ }
832
+
833
+ if (num === gameState.target) {
834
+ gameState.score += gameState.level * 10;
835
+ gameState.level++;
836
+ gameState.target = randomTarget();
837
+
838
+ terminal.writeSuccess(`🎉 Correct! Score: ${gameState.score}`);
839
+ terminal.writeln(`Level ${gameState.level} - New number generated`);
840
+ } else if (num < gameState.target) {
841
+ terminal.writeWarning('📈 Go higher!');
842
+ } else {
843
+ terminal.writeWarning('📉 Go lower!');
844
+ }
845
+ },
846
+ });
847
+
848
+ terminal.addCommand('score', () => {
849
+ return `Score: ${gameState.score} | Level: ${gameState.level}`;
850
+ });
851
+ ```
852
+
853
+ ### API Client
854
+
855
+ ```javascript
856
+ const API_BASE = 'https://jsonplaceholder.typicode.com';
857
+
858
+ terminal.registerCommand({
859
+ name: 'api',
860
+ description: 'Make API requests',
861
+ usage: 'api <endpoint> [--method=GET] [--body={}]',
862
+ handler: async ({ args, flags, terminal }) => {
863
+ const endpoint = args[0];
864
+ if (!endpoint) {
865
+ terminal.writeError('Usage: api <endpoint>');
866
+ return;
867
+ }
868
+
869
+ const method = flags.method || 'GET';
870
+ const url = `${API_BASE}${endpoint}`;
871
+
872
+ terminal.writeln(`${method} ${url}`, { color: '#8be9fd' });
873
+
874
+ try {
875
+ const options = { method };
876
+ if (flags.body) {
877
+ options.body = flags.body;
878
+ options.headers = { 'Content-Type': 'application/json' };
879
+ }
880
+
881
+ const response = await fetch(url, options);
882
+ const data = await response.json();
883
+
884
+ terminal.writeSuccess(`Status: ${response.status}`);
885
+ terminal.writeln(JSON.stringify(data, null, 2));
886
+ } catch (error) {
887
+ terminal.writeError(`Error: ${error.message}`);
888
+ }
889
+ },
890
+ });
891
+
892
+ // Usage:
893
+ // api /posts/1
894
+ // api /posts --method=POST --body={"title":"Hello"}
895
+ ```
896
+
897
+ ### Task Manager
898
+
899
+ ```javascript
900
+ const tasks = [];
901
+ let taskId = 1;
902
+
903
+ terminal.addCommand('add', ({ args }) => {
904
+ const text = args.join(' ');
905
+ if (!text) return 'Usage: add <task description>';
906
+
907
+ tasks.push({ id: taskId++, text, done: false });
908
+ return `✅ Added task #${taskId - 1}`;
909
+ });
910
+
911
+ terminal.addCommand('list', ({ terminal }) => {
912
+ if (tasks.length === 0) {
913
+ return '📭 No tasks';
914
+ }
915
+
916
+ tasks.forEach(task => {
917
+ const status = task.done ? '✅' : '⬜';
918
+ const style = task.done ? { color: '#6b7280' } : {};
919
+ terminal.writeln(`${status} #${task.id}: ${task.text}`, style);
920
+ });
921
+ });
922
+
923
+ terminal.addCommand('done', ({ args }) => {
924
+ const id = parseInt(args[0]);
925
+ const task = tasks.find(t => t.id === id);
926
+
927
+ if (!task) return `Task #${id} not found`;
928
+
929
+ task.done = true;
930
+ return `✅ Completed: ${task.text}`;
931
+ });
932
+
933
+ terminal.addCommand('remove', ({ args }) => {
934
+ const id = parseInt(args[0]);
935
+ const index = tasks.findIndex(t => t.id === id);
936
+
937
+ if (index === -1) return `Task #${id} not found`;
938
+
939
+ const [task] = tasks.splice(index, 1);
940
+ return `🗑️ Removed: ${task.text}`;
941
+ });
942
+ ```
943
+
944
+ ### Progress Animation
945
+
946
+ ```javascript
947
+ terminal.registerCommand({
948
+ name: 'download',
949
+ description: 'Simulate file download with progress',
950
+ handler: async ({ args, terminal }) => {
951
+ const filename = args[0] || 'file.zip';
952
+ const size = parseInt(args[1]) || 100;
953
+
954
+ terminal.writeln(`Downloading ${filename}...`);
955
+
956
+ for (let i = 0; i <= 100; i += 5) {
957
+ const filled = Math.floor(i / 5);
958
+ const empty = 20 - filled;
959
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
960
+ const mb = ((i / 100) * size).toFixed(1);
961
+
962
+ // Create/update progress line
963
+ process.stdout.write(`\r[${bar}] ${i}% (${mb}/${size} MB)`);
964
+
965
+ await new Promise(r => setTimeout(r, 100));
966
+ }
967
+
968
+ terminal.writeln('');
969
+ terminal.writeSuccess(`✅ Downloaded ${filename}`);
970
+ },
971
+ });
972
+ ```
973
+
974
+ ---
975
+
976
+ ## 🌐 Browser Support
977
+
978
+ | Browser | Version |
979
+ |---------|---------|
980
+ | Chrome | 60+ |
981
+ | Firefox | 55+ |
982
+ | Safari | 12+ |
983
+ | Edge | 79+ |
984
+ | Opera | 47+ |
985
+
986
+ ---
987
+
988
+ ## 📄 TypeScript
989
+
990
+ Full TypeScript support with exported types:
991
+
992
+ ```typescript
993
+ import {
994
+ Terminal,
995
+ TerminalOptions,
996
+ TerminalTheme,
997
+ CommandDefinition,
998
+ CommandHandler,
999
+ CommandContext,
1000
+ OutputOptions,
1001
+ ThemeName,
1002
+ } from 'browser-terminal-cli';
1003
+
1004
+ const options: TerminalOptions = {
1005
+ container: '#terminal',
1006
+ theme: 'dracula',
1007
+ };
1008
+
1009
+ const terminal = new Terminal(options);
1010
+
1011
+ const myCommand: CommandDefinition = {
1012
+ name: 'test',
1013
+ description: 'A test command',
1014
+ handler: (ctx: CommandContext): string => {
1015
+ return `Args: ${ctx.args.join(', ')}`;
1016
+ },
1017
+ };
1018
+
1019
+ terminal.registerCommand(myCommand);
1020
+ ```
1021
+
1022
+ ---
1023
+
1024
+ ## 🔧 Advanced Usage
1025
+
1026
+ ### Persisting History
1027
+
1028
+ ```javascript
1029
+ const HISTORY_KEY = 'terminal-history';
1030
+
1031
+ // Load history on init
1032
+ const terminal = new Terminal({
1033
+ container: '#terminal',
1034
+ });
1035
+
1036
+ const savedHistory = localStorage.getItem(HISTORY_KEY);
1037
+ if (savedHistory) {
1038
+ terminal.setHistory(JSON.parse(savedHistory));
1039
+ }
1040
+
1041
+ // Save history on each command
1042
+ terminal.on('command', () => {
1043
+ localStorage.setItem(HISTORY_KEY, JSON.stringify(terminal.getHistory()));
1044
+ });
1045
+ ```
1046
+
1047
+ ### Custom Autocomplete
1048
+
1049
+ ```javascript
1050
+ terminal.on('key', (e) => {
1051
+ if (e.key === 'Tab') {
1052
+ e.preventDefault();
1053
+
1054
+ const input = terminal.getValue();
1055
+ const suggestions = getAutocompleteSuggestions(input);
1056
+
1057
+ if (suggestions.length === 1) {
1058
+ terminal.setValue(suggestions[0] + ' ');
1059
+ } else if (suggestions.length > 1) {
1060
+ terminal.writeln('');
1061
+ terminal.writeln(suggestions.join(' '));
1062
+ }
1063
+ }
1064
+ });
1065
+
1066
+ function getAutocompleteSuggestions(input) {
1067
+ const files = ['readme.md', 'package.json', 'index.js'];
1068
+ return files.filter(f => f.startsWith(input.split(' ').pop()));
1069
+ }
1070
+ ```
1071
+
1072
+ ### Multiple Terminals
1073
+
1074
+ ```javascript
1075
+ const term1 = new Terminal({
1076
+ container: '#terminal-1',
1077
+ prompt: 'server1$ ',
1078
+ theme: 'dracula',
1079
+ });
1080
+
1081
+ const term2 = new Terminal({
1082
+ container: '#terminal-2',
1083
+ prompt: 'server2$ ',
1084
+ theme: 'monokai',
1085
+ });
1086
+
1087
+ // Sync commands between terminals
1088
+ term1.on('command', (cmd) => {
1089
+ term2.writeln(`[server1]: ${cmd}`, { color: '#888' });
1090
+ });
1091
+ ```
1092
+
1093
+ ---
1094
+
1095
+ ## 📝 License
1096
+
1097
+ MIT © [Adhi](https://github.com/liladhiee-web)
1098
+
1099
+ ---
1100
+
1101
+ ## 🤝 Contributing
1102
+
1103
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
1104
+
1105
+ 1. Fork the repository
1106
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
1107
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
1108
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
1109
+ 5. Open a Pull Request
1110
+
1111
+ ---
1112
+
1113
+ ## 🙏 Acknowledgments
1114
+
1115
+ - Inspired by [Xterm.js](https://xtermjs.org/)
1116
+ - Themes inspired by popular color schemes
1117
+ - Built with TypeScript and Rollup
1118
+
1119
+ ---
1120
+
1121
+ ## 📬 Support
1122
+
1123
+ - 📫 [Open an issue](https://github.com/liladhiee-web/browser-terminal-cli/issues)
1124
+ - 💬 [Discussions](https://github.com/liladhiee-web/browser-terminal-cli/discussions)
1125
+
1126
+ ---
1127
+
1128
+ <p align="center">
1129
+ Made with ❤️ for the web developer community
1130
+ </p>