Skip to content

Feature Request: PTY support for ChildProcess API #82

@croustibat

Description

@croustibat

Summary

Add pseudo-terminal (PTY) support to the ChildProcess API to enable running interactive CLI/TUI applications within NativePHP desktop apps.

Current Behavior

The current ChildProcess implementation uses Electron's utilityProcess.fork() which spawns processes with stdio: 'pipe'. This works well for simple command-line tools that read/write plain text via stdin/stdout.

However, interactive TUI (Text User Interface) applications do not work because they require a pseudo-terminal (PTY) to:

  • Detect terminal dimensions (rows/columns)
  • Handle raw input mode (character-by-character instead of line-buffered)
  • Support ANSI escape sequences for cursor movement, colors, and screen manipulation
  • Respond to terminal resize events (SIGWINCH)

Use Case

We are building a NativePHP desktop app that needs to embed interactive CLI tools like:

  • Claude Code (claude CLI) - an AI coding assistant with a full TUI interface
  • Other TUI apps: htop, vim, lazygit, terminal-based REPLs, etc.

These tools detect that they are not connected to a TTY and either refuse to start in interactive mode or fall back to a degraded non-interactive mode with no output rendering.

Proposed Solution

Add an optional pty: true option to the ChildProcess API that uses a PTY instead of plain pipes. On the Node.js/Electron side, this could leverage:

  • node-pty - a mature library for spawning PTY processes in Node.js
  • Native PTY APIs via N-API addon

Example API

// Current (pipes only)
ChildProcess::start('claude', cwd: '/path/to/project');

// Proposed (with PTY support)
ChildProcess::start('claude', cwd: '/path/to/project', pty: true);

// Optional: resize support
ChildProcess::resize($alias, cols: 120, rows: 40);

Events

The existing event system (MessageReceived, ErrorReceived, ProcessExited) would continue to work. An additional event could be added for resize handling:

#[On('native:...\ChildProcess\ProcessResized')]
public function onResize(string $alias, int $cols, int $rows): void { }

Technical Details

The key change would be in the Electron-side childProcess.js helper:

// Current: uses stdio pipes
const proc = spawn(command, args, { stdio: 'pipe', cwd });

// With PTY: use node-pty
const pty = require('node-pty');
const proc = pty.spawn(command, args, { cwd, cols: 80, rows: 24 });

The rest of the event chain (stdout → notifyLaravelbroadcastToWindows → Livewire dispatch) would remain unchanged.

Environment

  • NativePHP Desktop v2
  • macOS (primary), but node-pty supports Windows and Linux as well
  • Electron (utilityProcess context)

Workaround

Currently there is no viable workaround for running interactive TUI applications through the ChildProcess API.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions