Skip to content

Expose foreground process pid (tcgetpgrp on master fd) #913

@srid

Description

@srid

Feature

Expose tcgetpgrp(masterFd) from UnixTerminal as a foregroundPid accessor (number, or undefined when the call fails).

Why it's missing today

The native binding already calls tcgetpgrp(fd) internally to resolve the foreground process name — see src/unix/pty.cc pty_getproc darwin branch (line ~656) and linux branch (line ~614). The pgrp pid is computed and then thrown away — only kp.kp_proc.p_comm (or /proc/<pid>/cmdline) is returned to JS.

For a class of consumers — agent-aware terminal multiplexers, observability tooling, etc. — the name isn't enough because the foreground process is a script interpreter and the resolved name is something generic like node / python / ruby rather than the meaningful tool name. Having the pid lets the caller cross-reference its own state (e.g. session files on disk, IPC sockets) to identify what's actually running.

Concrete use case

kolu detects Claude Code sessions running in a kolu terminal. Claude writes ~/.claude/sessions/<pid>.json for every running instance. Today kolu has to walk ~/.claude/sessions/, then for each candidate pid read /proc/<pid>/fd/0 to check whether it shares a controlling tty with the kolu shell pid. That's:

  • O(sessions × terminals) per poll
  • Linux-only — /proc doesn't exist on macOS, so the feature is completely silent on darwin despite Claude Code being one of its primary platforms

With term.foregroundPid exposed, kolu can ask each terminal "who's in your foreground?" and look up ~/.claude/sessions/<fgpid>.json directly. One syscall per terminal, no platform branch, no /proc dependency.

Proposed API

Mirroring the fd / ptsName accessors added in #516:

class UnixTerminal extends Terminal {
  // existing
  get fd(): number;
  get ptsName(): string;

  // new
  get foregroundPid(): number | undefined;
}

undefined when tcgetpgrp(fd) === -1 (pty closed, EBADF, etc.).

Reference implementation

Working patch at juspay/node-pty@kolu/foreground-pid (~30 LOC, all in src/unix/pty.cc + src/unixTerminal.ts + src/native.d.ts):

  • New PtyGetForegroundPid(fd) Napi binding — calls tcgetpgrp(fd), returns Napi::Number or env.Undefined() on -1
  • New pty.foregroundPid export in init()
  • New accessor on UnixTerminal that wraps it

No new syscalls, no new dependencies. Cross-platform on Linux + macOS via tcgetpgrp(3) (POSIX). Not exposed on Windows since ConPTY has no equivalent concept — the accessor lives on UnixTerminal, not IPty.

Prior art

Same approach used by:

  • tmuxtcgetpgrp on the master fd
  • ghostty — see getProcessInfo with foreground_pid
  • htop — reads kp_eproc.e_tdev from kinfo_proc, same family of APIs

Happy to open a PR if this is something the maintainers would accept.

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