lunel-cli 0.1.6 → 0.1.7

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 (2) hide show
  1. package/dist/index.js +49 -152
  2. package/package.json +1 -2
package/dist/index.js CHANGED
@@ -8,9 +8,8 @@ import * as path from "path";
8
8
  import * as os from "os";
9
9
  import { spawn, execSync } from "child_process";
10
10
  import { createServer } from "net";
11
- import * as pty from "node-pty";
12
11
  const PROXY_URL = process.env.LUNEL_PROXY_URL || "https://gateway.lunel.dev";
13
- const VERSION = "0.1.4";
12
+ const VERSION = "0.1.6";
14
13
  // Root directory - sandbox all file operations to this
15
14
  const ROOT_DIR = process.cwd();
16
15
  const terminals = new Map();
@@ -481,9 +480,8 @@ async function handleGitDiscard(payload) {
481
480
  // ============================================================================
482
481
  let dataChannel = null;
483
482
  function handleTerminalSpawn(payload) {
484
- // Determine shell - prefer user's shell, fallback to common defaults
485
- let shell = payload.shell || process.env.SHELL;
486
- // Validate and find a working shell
483
+ // Find a working shell
484
+ let shell = payload.shell || process.env.SHELL || '';
487
485
  const possibleShells = os.platform() === 'win32'
488
486
  ? ['powershell.exe', 'cmd.exe']
489
487
  : [shell, '/bin/zsh', '/bin/bash', '/bin/sh'].filter(Boolean);
@@ -492,152 +490,64 @@ function handleTerminalSpawn(payload) {
492
490
  if (!candidate)
493
491
  continue;
494
492
  try {
495
- if (os.platform() === 'win32') {
496
- // On Windows, just use the shell name
497
- shell = candidate;
498
- break;
499
- }
500
- else {
501
- // On Unix, check if file exists and is executable
493
+ if (os.platform() !== 'win32') {
502
494
  execSync(`test -x "${candidate}"`, { stdio: 'ignore' });
503
- shell = candidate;
504
- break;
505
495
  }
496
+ shell = candidate;
497
+ break;
506
498
  }
507
499
  catch {
508
- // Try next shell
500
+ // Try next
509
501
  }
510
502
  }
511
503
  if (!shell) {
512
504
  throw Object.assign(new Error('No valid shell found'), { code: 'ENOSHELL' });
513
505
  }
514
- const cols = payload.cols || 80;
515
- const rows = payload.rows || 24;
516
506
  const terminalId = `term-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
517
- // Filter out undefined values from env
507
+ // Clean environment
518
508
  const cleanEnv = {};
519
509
  for (const [key, value] of Object.entries(process.env)) {
520
510
  if (value !== undefined) {
521
511
  cleanEnv[key] = value;
522
512
  }
523
513
  }
524
- cleanEnv['TERM'] = 'xterm-256color';
525
- // Try PTY first, fallback to regular spawn if PTY fails (e.g., Node 24 compatibility)
526
- let ptyProcess = null;
527
- let fallbackProc = null;
528
- try {
529
- ptyProcess = pty.spawn(shell, [], {
530
- name: 'xterm-256color',
531
- cols,
532
- rows,
533
- cwd: ROOT_DIR,
534
- env: cleanEnv,
535
- });
536
- }
537
- catch (ptyErr) {
538
- console.warn('PTY spawn failed, falling back to regular spawn:', ptyErr.message);
539
- // Fallback to regular child_process spawn
540
- fallbackProc = spawn(shell, [], {
541
- cwd: ROOT_DIR,
542
- env: cleanEnv,
543
- stdio: ['pipe', 'pipe', 'pipe'],
544
- });
545
- }
546
- if (ptyProcess) {
547
- terminals.set(terminalId, {
548
- pty: ptyProcess,
549
- cols,
550
- rows,
551
- });
552
- // Stream output to app via data channel
553
- ptyProcess.onData((data) => {
554
- if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
555
- const msg = {
556
- v: 1,
557
- id: `evt-${Date.now()}`,
558
- ns: "terminal",
559
- action: "output",
560
- payload: { terminalId, data },
561
- };
562
- dataChannel.send(JSON.stringify(msg));
563
- }
564
- });
565
- ptyProcess.onExit(({ exitCode }) => {
566
- terminals.delete(terminalId);
567
- if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
568
- const msg = {
569
- v: 1,
570
- id: `evt-${Date.now()}`,
571
- ns: "terminal",
572
- action: "exit",
573
- payload: { terminalId, code: exitCode },
574
- };
575
- dataChannel.send(JSON.stringify(msg));
576
- }
577
- });
578
- }
579
- else if (fallbackProc) {
580
- // Store fallback process with a wrapper that mimics PTY interface
581
- const wrapperPty = {
582
- write: (data) => fallbackProc.stdin?.write(data),
583
- resize: (_cols, _rows) => { },
584
- kill: (signal) => fallbackProc.kill(signal),
585
- pid: fallbackProc.pid || 0,
586
- cols,
587
- rows,
588
- process: shell,
589
- handleFlowControl: false,
590
- onData: (cb) => {
591
- fallbackProc.stdout?.on('data', (d) => cb(d.toString()));
592
- fallbackProc.stderr?.on('data', (d) => cb(d.toString()));
593
- return { dispose: () => { } };
594
- },
595
- onExit: (cb) => {
596
- fallbackProc.on('close', (code) => cb({ exitCode: code || 0 }));
597
- return { dispose: () => { } };
598
- },
599
- clear: () => { },
600
- pause: () => { },
601
- resume: () => { },
602
- };
603
- terminals.set(terminalId, {
604
- pty: wrapperPty,
605
- cols,
606
- rows,
607
- });
608
- // Stream output
609
- const sendOutput = (data) => {
610
- if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
611
- const msg = {
612
- v: 1,
613
- id: `evt-${Date.now()}`,
614
- ns: "terminal",
615
- action: "output",
616
- payload: { terminalId, data: data.toString() },
617
- };
618
- dataChannel.send(JSON.stringify(msg));
619
- }
620
- };
621
- fallbackProc.stdout?.on('data', sendOutput);
622
- fallbackProc.stderr?.on('data', sendOutput);
623
- fallbackProc.on('close', (code) => {
624
- terminals.delete(terminalId);
625
- if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
626
- const msg = {
627
- v: 1,
628
- id: `evt-${Date.now()}`,
629
- ns: "terminal",
630
- action: "exit",
631
- payload: { terminalId, code: code || 0 },
632
- };
633
- dataChannel.send(JSON.stringify(msg));
634
- }
635
- });
636
- }
637
- else {
638
- throw Object.assign(new Error('Failed to spawn terminal'), { code: 'ESPAWN' });
639
- }
640
- return { terminalId };
514
+ cleanEnv['TERM'] = 'dumb'; // Simple terminal - no escape codes
515
+ // Spawn shell process
516
+ const proc = spawn(shell, ['-i'], {
517
+ cwd: ROOT_DIR,
518
+ env: cleanEnv,
519
+ stdio: ['pipe', 'pipe', 'pipe'],
520
+ });
521
+ terminals.set(terminalId, { proc, shell });
522
+ // Stream output to app
523
+ const sendOutput = (data) => {
524
+ if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
525
+ const msg = {
526
+ v: 1,
527
+ id: `evt-${Date.now()}`,
528
+ ns: "terminal",
529
+ action: "output",
530
+ payload: { terminalId, data: data.toString() },
531
+ };
532
+ dataChannel.send(JSON.stringify(msg));
533
+ }
534
+ };
535
+ proc.stdout?.on('data', sendOutput);
536
+ proc.stderr?.on('data', sendOutput);
537
+ proc.on('close', (code) => {
538
+ terminals.delete(terminalId);
539
+ if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
540
+ const msg = {
541
+ v: 1,
542
+ id: `evt-${Date.now()}`,
543
+ ns: "terminal",
544
+ action: "exit",
545
+ payload: { terminalId, code: code || 0 },
546
+ };
547
+ dataChannel.send(JSON.stringify(msg));
548
+ }
549
+ });
550
+ return { terminalId, shell };
641
551
  }
642
552
  function handleTerminalWrite(payload) {
643
553
  const terminalId = payload.terminalId;
@@ -649,24 +559,11 @@ function handleTerminalWrite(payload) {
649
559
  const session = terminals.get(terminalId);
650
560
  if (!session)
651
561
  throw Object.assign(new Error("Terminal not found"), { code: "ENOTERM" });
652
- session.pty.write(data);
562
+ session.proc.stdin?.write(data);
653
563
  return {};
654
564
  }
655
565
  function handleTerminalResize(payload) {
656
- const terminalId = payload.terminalId;
657
- const cols = payload.cols;
658
- const rows = payload.rows;
659
- if (!terminalId)
660
- throw Object.assign(new Error("terminalId is required"), { code: "EINVAL" });
661
- if (!cols || !rows)
662
- throw Object.assign(new Error("cols and rows are required"), { code: "EINVAL" });
663
- const session = terminals.get(terminalId);
664
- if (!session)
665
- throw Object.assign(new Error("Terminal not found"), { code: "ENOTERM" });
666
- // Resize PTY
667
- session.pty.resize(cols, rows);
668
- session.cols = cols;
669
- session.rows = rows;
566
+ // No-op for simple terminal - resize not supported without PTY
670
567
  return {};
671
568
  }
672
569
  function handleTerminalKill(payload) {
@@ -676,7 +573,7 @@ function handleTerminalKill(payload) {
676
573
  const session = terminals.get(terminalId);
677
574
  if (!session)
678
575
  throw Object.assign(new Error("Terminal not found"), { code: "ENOTERM" });
679
- session.pty.kill();
576
+ session.proc.kill();
680
577
  terminals.delete(terminalId);
681
578
  return {};
682
579
  }
@@ -1473,7 +1370,7 @@ function connectWebSocket(code) {
1473
1370
  console.log("\nShutting down...");
1474
1371
  // Kill all terminals
1475
1372
  for (const [id, session] of terminals) {
1476
- session.pty.kill();
1373
+ session.proc.kill();
1477
1374
  }
1478
1375
  terminals.clear();
1479
1376
  // Kill all managed processes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",
@@ -26,7 +26,6 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "ignore": "^6.0.2",
29
- "node-pty": "^1.0.0",
30
29
  "qrcode-terminal": "^0.12.0",
31
30
  "ws": "^8.18.0"
32
31
  },