Skip to content

Feat/ts pty handler migration#126

Open
kartikloops wants to merge 36 commits into
The-OpenROAD-Project:feat/ts-migrationfrom
kartikloops:feat/ts-pty-handler-migration
Open

Feat/ts pty handler migration#126
kartikloops wants to merge 36 commits into
The-OpenROAD-Project:feat/ts-migrationfrom
kartikloops:feat/ts-pty-handler-migration

Conversation

@kartikloops

Copy link
Copy Markdown
Collaborator

Summary

Migrates the interactive PTY layer from Python to TypeScript — source and tests.

New source files

  • src/interactive/models.ts — session error hierarchy (SessionError, SessionTerminatedError, CommandBlockedError, PTYError)
  • src/interactive/buffer.ts — string-based circular buffer with mutex and async wait-for-data
  • src/interactive/pty_handler.ts — wraps node-pty, handles spawn, write, graceful termination, and event-driven output via onData/onExit
  • src/interactive/session.ts — session lifecycle (CREATING → ACTIVE → TERMINATED), writer task, input queue, output collection
  • src/core/models.tsSessionState enum and result interfaces

Tests

  • buffer.test.ts, pty_handler.test.ts, command_validation.test.ts, session.test.ts
  • 222 tests, all passing

Copilot AI review requested due to automatic review settings June 12, 2026 03:52
@kartikloops kartikloops changed the base branch from main to feat/ts-migration June 12, 2026 03:52
@kartikloops

Copy link
Copy Markdown
Collaborator Author

@luarss Pleas have a review when you get sometime

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the interactive PTY/session layer from Python to a new TypeScript implementation, introducing a TS-based PTY wrapper, buffered output collection, session lifecycle management, and accompanying Vitest coverage.

Changes:

  • Added a new interactive subsystem (PtyHandler, InteractiveSession, CircularBuffer) and error model hierarchy in TypeScript.
  • Introduced SessionState plus interactive result/info interfaces in src/core/models.ts.
  • Added comprehensive Vitest coverage for the new interactive components and updated ESLint config to better support the new code/tests.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
typescript/src/interactive/session.ts New InteractiveSession lifecycle, input queue writer loop, output collection + error detection.
typescript/src/interactive/pty_handler.ts New node-pty wrapper (spawn, write, exit handling, termination, cleanup, command validation).
typescript/src/interactive/models.ts New interactive error hierarchy (SessionError, PTYError, etc.).
typescript/src/interactive/buffer.ts New mutex-protected string chunk circular buffer with async wait-for-data.
typescript/src/core/models.ts New SessionState enum and interactive result/info interfaces.
typescript/eslint.config.ts Ignore coverage/** and enforce @typescript-eslint/no-unused-vars (with _ ignore patterns); relax return-type rule for tests.
typescript/tests/interactive/session.test.ts Tests for session lifecycle, writer loop behavior, output reads, and error detection.
typescript/tests/interactive/pty_handler.test.ts Tests for PTY spawn wiring, onData/onExit behavior, termination, waitForExit, and cleanup semantics.
typescript/tests/interactive/command_validation.test.ts Tests for allowlist + metacharacter/redirection blocking and Settings env parsing.
typescript/tests/interactive/buffer.test.ts Tests for buffer append/drain/eviction, waitForData, stats, and concurrency behavior.
.vscode/settings.json Workspace TS SDK path for consistent editor TypeScript usage.
plan.md Present in PR metadata (currently empty).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread typescript/src/interactive/pty_handler.ts Outdated
Comment thread typescript/src/interactive/session.ts Outdated
Comment thread typescript/src/interactive/pty_handler.ts
Comment thread typescript/src/interactive/pty_handler.ts
Comment thread typescript/src/interactive/pty_handler.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment thread typescript/src/interactive/buffer.ts
Comment thread typescript/src/interactive/pty_handler.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kartik Mittal <100078751+kartikloops@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Comment thread typescript/src/interactive/session.ts Outdated
Comment thread typescript/src/interactive/session.ts
Comment thread typescript/scripts/integration_check.ts
Comment thread typescript/scripts/integration_check.ts
Comment thread typescript/scripts/integration_check.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kartik Mittal <100078751+kartikloops@users.noreply.github.com>

@luarss luarss left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted some high priorities one to solve, please check @kartikloops

Comment thread .vscode/settings.json
@@ -0,0 +1,3 @@
{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, every contributor who opens the repo in VS Code gets TypeScript errors or the wrong type-checker, because VS Code defaults to its own bundled TypeScript version rather than the project's. This file pins VS Code to use the TypeScript installed in typescript/node_modules/, so everyone gets consistent IntelliSense and error highlighting that matches what tsc actually sees.

It ensures VS Code uses the same TypeScript the build does.

Comment thread typescript/src/interactive/session.ts
Comment thread typescript/src/interactive/pty_handler.ts Outdated
Comment thread typescript/src/interactive/session.ts
Comment thread typescript/src/interactive/buffer.ts
Comment thread typescript/src/interactive/session.ts
Comment thread typescript/src/interactive/buffer.ts Outdated
Comment thread typescript/src/interactive/session.ts Outdated
@kartikloops kartikloops requested a review from luarss June 13, 2026 16:34
logger.debug("PTY handler cleanup completed")


class MacOSPTYHandler(PTYHandler):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets avoid this for now - don't need to support macOS for a quick PoC.

const exited = await this.waitForExit(5000);
if (exited === null && this._alive) {
try {
this._ptyProcess.kill("SIGKILL");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

terminateProcess() sends SIGKILL and returns immediately without awaiting; cleanup() then disposes the exit listener before SIGKILL is acknowledged, permanently losing the real exit code.

When the process survives the 5-second SIGTERM window: SIGKILL is sent at line 162 and terminateProcess() returns without awaiting. cleanup() then calls this._exitDisposable?.dispose() (line 179), removing the onExit listener. When SIGKILL is eventually processed, the listener is gone — _exitCode stays null forever. Any pending waitForExit() callers receive null instead of the real exit code (e.g. 137).

`Command argument ${i} contains shell metacharacters which are not allowed: ${JSON.stringify(arg)}`,
);
}
if (arg.startsWith(">") || arg.startsWith("<")) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateCommand does not check for path traversal in arguments — openroad -script ../../etc/malicious.tcl passes all validation.

The argument loop (lines 43–55) checks for shell metacharacters and leading >/<, but never inspects arguments for .. sequences. ['openroad', '-script', '../../etc/malicious.tcl'] contains no flagged characters, so it passes all checks and OpenROAD executes the attacker-controlled Tcl script.

this._chunks.push(data);
this._totalSize += data.length;

while (this._totalSize > this.maxSize && this._chunks.length > 1) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A single append larger than maxSize is never evicted — the buffer permanently exceeds its capacity.

The eviction loop condition is this._chunks.length > 1. When a single large chunk is the only entry, _chunks.length === 1 and the loop never runs, leaving _totalSize above maxSize indefinitely.


const executable = command[0]!;

if (path.isAbsolute(executable)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python implementation accepts absolute path though. Why is there a divergence ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants