[GH-ISSUE #548] Windows: processScenarioSchema requires POSIX paths, making process capture unusable #281

Closed
opened 2026-10-15 18:23:24 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @whft on GitHub (Oct 5, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/548

Summary

processScenarioSchema hard-requires POSIX absolute paths with .startsWith("/"). On Windows no scenario can be expressed at all, so capture_process_scenario and compare_process_captures are unusable there — regardless of configuration, permissions, or dependencies.

This is separate from, and additional to, the missing @lydell/node-pty-win32-x64 binary (which I confirmed is the only other blocker, and which I resolved locally — see below).

Root cause

src/domain/processScenario.ts:115:

export const processScenarioSchema = z
  .object({
    executable: z.string().startsWith("/"),
    arguments: z.array(z.string()).default([]),
    working_directory: z.string().startsWith("/"),
    ...
    filesystem_roots: z.array(z.string().startsWith("/")).default([]),

Three fields require a leading /. A Windows path such as C:\Program Files\nodejs\node.exe fails validation unconditionally, so the CLI reports:

error: Process command failed
category: invalid_input
message: "Process scenario is invalid. Check its required fields and limits, then try again."

The message is unhelpful because nothing in it hints that the path syntax is the problem.

Minimal proof

Two scenarios differing only in path style, same command:

POSIX-style — passes validation, then fails at execution:

{ "executable": "/usr/bin/node", "working_directory": "/tmp" }
error: Process command failed
code: unreadable_output
category: execution_failure

Windows path — rejected at validation:

{ "executable": "C:\\Program Files\\nodejs\\node.exe", "working_directory": "C:\\tools" }
error: Process command failed
category: invalid_input
message: "Process scenario is invalid. Check its required fields and limits, then try then try again."

Validation is the only difference. Once the path satisfies .startsWith("/") the request proceeds all the way to execution.

I also bisected the optional fields: terminal, checkpoints, normalization, inherit_environment, timeout_ms, settle_ms, network_access and bare arguments are all rejected while the path is Windows-style, and none of them changes the outcome. Only the path syntax matters.

Suggested fix

Accept a platform-appropriate absolute path. src/config/permissions.ts already does this correctly elsewhere with isAbsolute, so the codebase has a precedent:

import { isAbsolute } from "node:path";

const absolutePath = z.string().refine(isAbsolute, {
  message: "Path must be absolute",
});

export const processScenarioSchema = z.object({
  executable: absolutePath,
  working_directory: absolutePath,
  ...
  filesystem_roots: z.array(absolutePath).default([]),

If you would rather keep rejecting ambiguous input, the refinement message should at least name the constraint, e.g. "Path must be an absolute path for this platform (for example C:\\... on Windows)", so the failure is actionable instead of pointing at "required fields and limits".

Note the rest of the schema is already platform-neutral (network_access, terminal, checkpoints, limits all use platform-agnostic shapes), which makes the three startsWith("/") calls look like an oversight rather than a deliberate boundary.

The other blocker is real but separately fixable

@lydell/node-pty@1.1.0 declares @lydell/node-pty-win32-x64 as an optionalDependency, and npm silently skipped installing it, so the package ships with windowsTerminal.js but no native binary. I confirmed this is the whole story on the dependency side by installing the published @lydell/node-pty-win32-x64@1.1.0 manually:

node-pty loaded: true
exit code: 0
saw REA_PTY_OK: true
raw: "\u001b[2J\u001b[m\u001b[HREA_PTY_OK\r\n\u001b]0;C:\\Windows\\System32\\cmd.exe\u0007\u001b[?25h"

So a PTY works fine on Windows x64 once the optional dependency is present. With that fixed, the only remaining blocker for process capture is the schema above.

Two suggestions there:

  1. The optional dependency failing to install is silent. requireBinary() has a helpful error message for exactly this case, but nothing surfaces it unless the code path is actually reached — so the failure looks like "unsupported platform" rather than "npm skipped an optional dep". A doctor check that loads node-pty and reports the missing platform package would make this self-diagnosing.
  2. verify:* CI presumably runs on a platform where the optional dep resolves, which is likely why this was never noticed.

Impact

  • capture_process_scenario — unusable on Windows
  • compare_process_captures — unusable on Windows (same schema)
  • anything else that consumes processScenarioSchema

This is notable because process capture is one of the few REA features that is inherently cross-platform — ConPTY works, node-pty works, and nothing about it is macOS- or Linux-specific once the binary is present.

Environment

REA 3.2.1, Windows 11 x64, Node v24.19.0. Verified against a manually installed @lydell/node-pty-win32-x64@1.1.0.

Originally created by @whft on GitHub (Oct 5, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/548 ## Summary `processScenarioSchema` hard-requires POSIX absolute paths with `.startsWith("/")`. On Windows no scenario can be expressed at all, so `capture_process_scenario` and `compare_process_captures` are unusable there — regardless of configuration, permissions, or dependencies. This is separate from, and additional to, the missing `@lydell/node-pty-win32-x64` binary (which I confirmed is the *only* other blocker, and which I resolved locally — see below). ## Root cause `src/domain/processScenario.ts:115`: ```ts export const processScenarioSchema = z .object({ executable: z.string().startsWith("/"), arguments: z.array(z.string()).default([]), working_directory: z.string().startsWith("/"), ... filesystem_roots: z.array(z.string().startsWith("/")).default([]), ``` Three fields require a leading `/`. A Windows path such as `C:\Program Files\nodejs\node.exe` fails validation unconditionally, so the CLI reports: ``` error: Process command failed category: invalid_input message: "Process scenario is invalid. Check its required fields and limits, then try again." ``` The message is unhelpful because nothing in it hints that the path *syntax* is the problem. ## Minimal proof Two scenarios differing only in path style, same command: **POSIX-style — passes validation, then fails at execution:** ```json { "executable": "/usr/bin/node", "working_directory": "/tmp" } ``` ``` error: Process command failed code: unreadable_output category: execution_failure ``` **Windows path — rejected at validation:** ```json { "executable": "C:\\Program Files\\nodejs\\node.exe", "working_directory": "C:\\tools" } ``` ``` error: Process command failed category: invalid_input message: "Process scenario is invalid. Check its required fields and limits, then try then try again." ``` Validation is the *only* difference. Once the path satisfies `.startsWith("/")` the request proceeds all the way to execution. I also bisected the optional fields: `terminal`, `checkpoints`, `normalization`, `inherit_environment`, `timeout_ms`, `settle_ms`, `network_access` and bare `arguments` are all rejected while the path is Windows-style, and none of them changes the outcome. Only the path syntax matters. ## Suggested fix Accept a platform-appropriate absolute path. `src/config/permissions.ts` already does this correctly elsewhere with `isAbsolute`, so the codebase has a precedent: ```ts import { isAbsolute } from "node:path"; const absolutePath = z.string().refine(isAbsolute, { message: "Path must be absolute", }); export const processScenarioSchema = z.object({ executable: absolutePath, working_directory: absolutePath, ... filesystem_roots: z.array(absolutePath).default([]), ``` If you would rather keep rejecting ambiguous input, the refinement message should at least name the constraint, e.g. `"Path must be an absolute path for this platform (for example C:\\... on Windows)"`, so the failure is actionable instead of pointing at "required fields and limits". Note the rest of the schema is already platform-neutral (`network_access`, `terminal`, `checkpoints`, `limits` all use platform-agnostic shapes), which makes the three `startsWith("/")` calls look like an oversight rather than a deliberate boundary. ## The other blocker is real but separately fixable `@lydell/node-pty@1.1.0` declares `@lydell/node-pty-win32-x64` as an **optionalDependency**, and npm silently skipped installing it, so the package ships with `windowsTerminal.js` but no native binary. I confirmed this is the whole story on the dependency side by installing the published `@lydell/node-pty-win32-x64@1.1.0` manually: ``` node-pty loaded: true exit code: 0 saw REA_PTY_OK: true raw: "\u001b[2J\u001b[m\u001b[HREA_PTY_OK\r\n\u001b]0;C:\\Windows\\System32\\cmd.exe\u0007\u001b[?25h" ``` So a PTY works fine on Windows x64 once the optional dependency is present. With that fixed, the *only* remaining blocker for process capture is the schema above. Two suggestions there: 1. The optional dependency failing to install is silent. `requireBinary()` has a helpful error message for exactly this case, but nothing surfaces it unless the code path is actually reached — so the failure looks like "unsupported platform" rather than "npm skipped an optional dep". A `doctor` check that loads `node-pty` and reports the missing platform package would make this self-diagnosing. 2. `verify:*` CI presumably runs on a platform where the optional dep resolves, which is likely why this was never noticed. ## Impact - `capture_process_scenario` — unusable on Windows - `compare_process_captures` — unusable on Windows (same schema) - anything else that consumes `processScenarioSchema` This is notable because process capture is one of the few REA features that is inherently cross-platform — ConPTY works, node-pty works, and nothing about it is macOS- or Linux-specific once the binary is present. ## Environment REA 3.2.1, Windows 11 x64, Node v24.19.0. Verified against a manually installed `@lydell/node-pty-win32-x64@1.1.0`.
bsakaguchi 2026-10-15 18:23:24 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#281
No description provided.