Stop leaking host process.env into the remote Pi SSH probe (#5275)

## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - The Pi adapter runs the pi-coding-agent CLI against local, SSH, and
sandbox execution targets
> - The Test path's hello probe spreads the host's `process.env` into
the remote process env, including the macOS PATH
> - The leaked Mac PATH overrides the nvm-sourced PATH set up by
`buildSshSpawnTarget`, so on a Linux SSH target `node` resolves to
system Node 18 instead of nvm's Node 20+
> - pi-coding-agent v0.68 / pi-tui then crashes at
`pi-tui/dist/utils.js:27` with `SyntaxError: Invalid regular expression
flags` on the `/v` unicode-sets regex (a Node 20+ feature)
> - This pull request stops the leak — same fix as the opencode SSH
probe — by passing only user-configured adapter env to the probe when
the target is remote
> - The benefit is the Pi hello probe now passes end-to-end against an
SSH target without the Node version mismatch

## What Changed

- `packages/adapters/pi-local/src/server/test.ts` passes only the
user-configured adapter env (`normalizeEnv(env)`) to
`runAdapterExecutionTargetProcess` when the target is remote
- Local probes still get the full `runtimeEnv` so headless permission
injection keeps working

## Verification

- `pnpm vitest run --no-coverage --project
@paperclipai/adapter-pi-local`
- `pnpm typecheck` clean
- Manual: Pi hello probe goes from `pi_hello_probe_failed` (Node 18
regex error) to `pi_hello_probe_passed` against an SSH target

## Risks

Low risk — same pattern shipped for opencode-local and consistent with
claude-local / codex-local / gemini-local.

## Model Used

Claude Opus 4.7 (1M context)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable — pattern mirrors
sibling adapters
- [x] If this change affects the UI, I have included before/after
screenshots — N/A (no UI)
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
This commit is contained in:
Devin Foley
2026-05-05 08:00:23 -07:00
committed by GitHub
parent 028c5aa00a
commit 44c365dea3
+12 -1
View File
@@ -248,6 +248,17 @@ export async function testEnvironment(
args.push("--tools", "read");
if (extraArgs.length > 0) args.push(...extraArgs);
// For remote targets, do NOT spread the host process.env into the probe
// env: it leaks macOS-only PATH, HOME, TMPDIR, etc. into the remote shell.
// In particular the Mac PATH overrides the nvm-sourced PATH that
// buildSshSpawnTarget sets up, which on Linux SSH targets resolves `node`
// to /usr/bin/node (Node 18) instead of nvm's Node 22, causing pi-tui to
// crash with `Invalid regular expression flags` on its /v unicode regex.
// Match the pattern used by claude_local / codex_local / gemini_local /
// opencode_local probes: send only the user-configured adapter env across
// SSH. Local probes still get the full runtimeEnv.
const probeEnv = targetIsRemote ? normalizeEnv(env) : runtimeEnv;
try {
const probe = await runAdapterExecutionTargetProcess(
runId,
@@ -256,7 +267,7 @@ export async function testEnvironment(
args,
{
cwd,
env: runtimeEnv,
env: probeEnv,
timeoutSec: 60,
graceSec: 5,
onLog: async () => {},