perf(plugin-daytona): opt-in no-profile fast path for default-PATH execs (#10352)

## Thinking Path

> - Paperclip is the control plane for autonomous AI companies
> - The Daytona adapter turns tasks into shell commands and manages
execution overhead
> - Many short-lived exec calls still pay for login-shell profile
sourcing even when the binary already resolves on the sandbox default
PATH
> - That extra startup work adds latency on the hot path for repeated
command execution
> - This pull request adds an opt-in fast path that skips profile
sourcing only when the caller explicitly requests it and the command
does not need shell initialization
> - The benefit is lower per-call latency for eligible commands without
changing the conservative default behavior for commands that need the
profile

## Linked Issues or Issue Description

This change does not reference a public GitHub issue. It follows the
same Daytona startup-speed work as merged PR #10335 and narrows the
execution path for eligible commands while keeping the default
login-shell behavior intact.

## What Changed

- Added an optional `noProfile` flag to
`PluginEnvironmentExecuteParams`.
- Refactored Daytona login-shell script assembly so the profile and nvm
sourcing block is omitted only on the explicit fast path.
- Preserved environment prefixing, `cd`, shell quoting,
`NONINTERACTIVE_GIT_ENV`, stdin handling, and `durationMs` behavior on
both paths.
- Added regression tests for the fast path omission, the preserved
execution parameters, and the default profile-sourcing path.

## Verification

- `pnpm --filter @paperclipai/sandbox-provider-daytona exec vitest run
src/plugin.test.ts`
- `pnpm --filter @paperclipai/plugin-sdk tsc --noEmit`
- Reverted the guard locally to confirm the two behavior tests fail
again, then restored the change.

## Risks

- If a caller opts into `noProfile` for a command that depends on shell
initialization, the command can fail to resolve its binary.
- The API comment and opt-in design keep that risk narrow; the default
path remains unchanged.

## Model Used

OpenAI GPT-5 (Codex tool-using coding agent)

## 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 searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Nicky Leach 2026-07-27 21:47:05 -07:00 committed by GitHub
parent 0ccba45e4d
commit 7797995038
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 193 additions and 20 deletions

View File

@ -17,7 +17,7 @@ const execFile = promisify(execFileCallback);
interface SpawnRunnerHandle {
runner: CommandManagedRuntimeRunner;
calls: Array<{ command: string; args?: string[]; cwd?: string; stdin?: string }>;
calls: Array<{ command: string; args?: string[]; cwd?: string; stdin?: string; noProfile?: boolean }>;
}
// A runner that actually executes the shell scripts (piping stdin through a real
@ -27,12 +27,18 @@ function makeSpawnRunner(options: {
supportsSingleStreamStdinProgress?: boolean;
maxStdoutBytes?: number;
} = {}): SpawnRunnerHandle {
const calls: Array<{ command: string; args?: string[]; cwd?: string; stdin?: string }> = [];
const calls: Array<{ command: string; args?: string[]; cwd?: string; stdin?: string; noProfile?: boolean }> = [];
const runner: CommandManagedRuntimeRunner = {
supportsSingleStreamStdinProgress: options.supportsSingleStreamStdinProgress,
execute: async (input) =>
await new Promise<RunProcessResult>((resolve) => {
calls.push({ command: input.command, args: input.args, cwd: input.cwd, stdin: input.stdin });
calls.push({
command: input.command,
args: input.args,
cwd: input.cwd,
stdin: input.stdin,
noProfile: input.noProfile,
});
const startedAt = new Date().toISOString();
const command =
input.command === "sh" ? "/bin/sh" : input.command === "bash" ? "/bin/bash" : input.command;
@ -147,6 +153,7 @@ describe("command managed runtime", () => {
env?: Record<string, string>;
stdin?: string;
timeoutMs?: number;
noProfile?: boolean;
}> = [];
const runner = {
execute: async (input: {
@ -156,6 +163,7 @@ describe("command managed runtime", () => {
env?: Record<string, string>;
stdin?: string;
timeoutMs?: number;
noProfile?: boolean;
}): Promise<RunProcessResult> => {
calls.push({ ...input });
const startedAt = new Date().toISOString();
@ -228,6 +236,7 @@ describe("command managed runtime", () => {
// The single-stream upload pipes the tarball through exactly one stdin-backed
// process (the speed fix); nothing else streams stdin.
expect(calls.filter((call) => call.stdin != null).length).toBe(1);
expect(calls.some((call) => call.noProfile === true)).toBe(true);
await mkdir(path.join(remoteWorkspaceDir, ".paperclip-runtime"), { recursive: true });
await writeFile(path.join(remoteWorkspaceDir, "README.md"), "remote workspace\n", "utf8");
@ -242,6 +251,7 @@ describe("command managed runtime", () => {
// Restore streams the download through `base64`/onLog (no stdin), so the only
// stdin-backed call remains the single upload from prepare.
expect(calls.filter((call) => call.stdin != null).length).toBe(1);
expect(calls.some((call) => call.noProfile === true)).toBe(true);
});
it("stages runtime assets without replacing or restoring an in-place workspace", async () => {
@ -298,6 +308,38 @@ describe("command managed runtime", () => {
);
});
it("keeps adapter detection on the profile-backed shell path", async () => {
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-runtime-detect-"));
cleanupDirs.push(rootDir);
const localWorkspaceDir = path.join(rootDir, "local-workspace");
const remoteWorkspaceDir = path.join(rootDir, "remote-workspace");
await mkdir(localWorkspaceDir, { recursive: true });
await mkdir(remoteWorkspaceDir, { recursive: true });
const { runner, calls } = makeSpawnRunner();
await prepareCommandManagedRuntime({
runner,
spec: {
remoteCwd: remoteWorkspaceDir,
timeoutMs: 30_000,
},
adapterKey: "claude",
workspaceLocalDir: localWorkspaceDir,
installCommand: "echo install",
detectCommand: "sh",
});
// The detection probe must be the first shell invocation and stay on the
// default profile-sourcing path (noProfile !== true) so a CLI provided by
// the login profile is discoverable before we decide whether to install.
expect(calls[0]?.noProfile).not.toBe(true);
expect(calls[0]?.args?.join(" ")).toContain("command -v 'sh'");
// Detection succeeds here, so the install command must be skipped entirely;
// the remaining calls are workspace staging, never the install command.
expect(calls.some((call) => call.args?.join(" ").includes("echo install"))).toBe(false);
});
it("runs setup commands from a stable root cwd when staging into a nested remote workspace dir", async () => {
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-runtime-nested-"));
cleanupDirs.push(rootDir);
@ -546,6 +588,15 @@ describe("command managed runtime", () => {
expect(untarIdx).toBeGreaterThan(uploadIdx);
expect(cmd1Idx).toBeGreaterThan(untarIdx);
expect(cmd2Idx).toBeGreaterThan(cmd1Idx);
// Fast path: the fixed internal transport helpers (tar upload + untar) ride
// the no-profile shell — they are trusted, fixed commands that never need a
// login-shell profile. The opaque post-upload commands stay profile-backed
// (noProfile !== true) so any env a caller-supplied command relies on is present.
expect(calls[uploadIdx]?.noProfile).toBe(true);
expect(calls[untarIdx]?.noProfile).toBe(true);
expect(calls[cmd1Idx]?.noProfile).not.toBe(true);
expect(calls[cmd2Idx]?.noProfile).not.toBe(true);
});
it("fallback syncIn stages mode-constrained files before chmod and rename", async () => {
@ -579,6 +630,11 @@ describe("command managed runtime", () => {
expect(scripts[3]).toContain(targetFile);
expect(scripts[4]).toContain("rm -rf");
expect(scripts[4]).toContain(targetFile + ".paperclip-syncin.");
// Fast path: the staged-write helpers (chmod + rename) are fixed internal
// commands, so they ride the no-profile shell alongside the upload/staging.
expect(calls[2]?.noProfile).toBe(true); // chmod
expect(calls[3]?.noProfile).toBe(true); // mv (rename into place)
});
it("fallback syncIn cleans up a staged file when chmod fails before rename", async () => {

View File

@ -50,6 +50,7 @@ export interface CommandManagedRuntimeRunner {
env?: Record<string, string>;
stdin?: string;
timeoutMs?: number;
noProfile?: boolean;
onLog?: (stream: "stdout" | "stderr", chunk: string) => Promise<void>;
onSpawn?: (meta: { pid: number; startedAt: string }) => Promise<void>;
}): Promise<RunProcessResult>;
@ -205,6 +206,7 @@ export function createCommandManagedRuntimeClient(input: {
opts: {
stdin?: string;
timeoutMs?: number;
noProfile?: boolean;
onLog?: (stream: "stdout" | "stderr", chunk: string) => Promise<void>;
} = {},
) => {
@ -214,6 +216,7 @@ export function createCommandManagedRuntimeClient(input: {
cwd: input.commandCwd,
stdin: opts.stdin,
timeoutMs: opts.timeoutMs ?? input.timeoutMs,
noProfile: opts.noProfile === true,
onLog: opts.onLog,
});
requireSuccessfulResult(result, script);
@ -222,7 +225,7 @@ export function createCommandManagedRuntimeClient(input: {
const client: SandboxManagedRuntimeClient = {
makeDir: async (remotePath) => {
await runShell(`mkdir -p ${shellQuote(remotePath)}`);
await runShell(`mkdir -p ${shellQuote(remotePath)}`, { noProfile: true });
},
writeFile: async (remotePath, bytes, options) => {
const buffer = toBuffer(bytes);
@ -249,7 +252,7 @@ export function createCommandManagedRuntimeClient(input: {
`mkdir -p ${shellQuote(remoteDir)} && ` +
`base64 -d > ${shellQuote(remoteTempPath)} && ` +
`mv -f ${shellQuote(remoteTempPath)} ${shellQuote(remotePath)}`,
{ stdin: body },
{ stdin: body, noProfile: true },
);
await options?.onProgress?.(total, total);
return;
@ -263,14 +266,15 @@ export function createCommandManagedRuntimeClient(input: {
await runShell(
`mkdir -p ${shellQuote(remoteDir)} && ` +
`rm -f ${shellQuote(remoteTempPath)} && : > ${shellQuote(remoteTempPath)}`,
{ noProfile: true },
);
for (let offset = 0; offset < total; offset += REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE) {
const end = Math.min(total, offset + REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE);
const chunk = buffer.subarray(offset, end).toString("base64");
await runShell(`base64 -d >> ${shellQuote(remoteTempPath)}`, { stdin: chunk });
await runShell(`base64 -d >> ${shellQuote(remoteTempPath)}`, { stdin: chunk, noProfile: true });
await options?.onProgress?.(end, total);
}
await runShell(`mv -f ${shellQuote(remoteTempPath)} ${shellQuote(remotePath)}`);
await runShell(`mv -f ${shellQuote(remoteTempPath)} ${shellQuote(remotePath)}`, { noProfile: true });
await options?.onProgress?.(total, total);
} finally {
await bestEffortRemoveRemotePath(client, remoteTempPath);
@ -280,7 +284,7 @@ export function createCommandManagedRuntimeClient(input: {
// Chunked reads intentionally query the remote size first, even without
// a progress sink, so each sandbox RPC stays bounded and truncation is
// detected without materializing the whole file as one stdout string.
const sizeResult = await runShell(`wc -c < ${shellQuote(remotePath)}`);
const sizeResult = await runShell(`wc -c < ${shellQuote(remotePath)}`, { noProfile: true });
const totalBytes = Number.parseInt(sizeResult.stdout.trim(), 10);
if (!Number.isFinite(totalBytes) || totalBytes < 0) {
throw new Error(`Could not determine remote file size for ${remotePath}`);
@ -299,6 +303,7 @@ export function createCommandManagedRuntimeClient(input: {
for (let chunkIndex = 0; decodedSoFar < totalBytes; chunkIndex++) {
const result = await runShell(
`dd if=${shellQuote(remotePath)} bs=${REMOTE_READ_CHUNK_BYTES} skip=${chunkIndex} count=1 2>/dev/null | base64`,
{ noProfile: true },
);
const chunk = Buffer.from(result.stdout.replace(/\s+/g, ""), "base64");
if (chunk.byteLength === 0) break;
@ -321,6 +326,7 @@ export function createCommandManagedRuntimeClient(input: {
`basename "$entry"; ` +
`done; ` +
`fi`,
{ noProfile: true },
);
return result.stdout
.split(/\r?\n/)
@ -334,6 +340,7 @@ export function createCommandManagedRuntimeClient(input: {
args: shellCommandArgs(`rm -rf ${shellQuote(remotePath)}`),
cwd: input.commandCwd,
timeoutMs: input.timeoutMs,
noProfile: true,
});
requireSuccessfulResult(result, `remove ${remotePath}`);
},
@ -343,6 +350,7 @@ export function createCommandManagedRuntimeClient(input: {
args: shellCommandArgs(command),
cwd: input.commandCwd,
timeoutMs: options.timeoutMs,
noProfile: options.noProfile === true,
});
requireSuccessfulResult(result, command);
},
@ -382,7 +390,7 @@ export function createCommandManagedRuntimeClient(input: {
await client.writeFile(remoteTarPath, bufferToArrayBuffer(tarBytes));
await client.run(
buildSyncInExtractDirectoryCommand({ remoteTarPath, targetDir: mapping.targetPath }),
{ timeoutMs: input.timeoutMs },
{ timeoutMs: input.timeoutMs, noProfile: true },
);
bytesTransferred += tarBytes.byteLength;
} else {
@ -395,11 +403,11 @@ export function createCommandManagedRuntimeClient(input: {
if (mapping.mode != null) {
await client.run(
buildSyncInChmodCommand({ mode: mapping.mode, targetPath: targetPathForWrite }),
{ timeoutMs: input.timeoutMs },
{ timeoutMs: input.timeoutMs, noProfile: true },
);
await client.run(
buildSyncInRenameCommand({ sourcePath: targetPathForWrite, targetPath: mapping.targetPath }),
{ timeoutMs: input.timeoutMs },
{ timeoutMs: input.timeoutMs, noProfile: true },
);
}
bytesTransferred += fileBytes.byteLength;

View File

@ -198,7 +198,7 @@ export interface SandboxManagedRuntimeClient {
): Promise<Buffer | Uint8Array | ArrayBuffer>;
listFiles(remotePath: string): Promise<string[]>;
remove(remotePath: string): Promise<void>;
run(command: string, options: { timeoutMs: number }): Promise<void>;
run(command: string, options: { timeoutMs: number; noProfile?: boolean }): Promise<void>;
/**
* Optional native inbound transfer. Present only when the sandbox provider
* advertises both `environmentSyncIn` and `environmentSyncOut`; otherwise the

View File

@ -1307,6 +1307,96 @@ describe("Daytona sandbox provider plugin", () => {
expect(result?.stderr).toMatch(/unreachable|credentials/i);
});
// ─── No-profile fast path (A2) ─────────────────────────────────────────────
// The opt-in `noProfile` flag sheds the ~600 ms login-shell profile/nvm
// sourcing for command classes whose binary resolves on the default PATH
// (file-sync `tar`/`base64`/`mkdir`/`mv`), while every other exec surface
// (env prefix, cwd, quoting, stdin, durationMs) is preserved byte-for-byte.
it("test_no_profile_fast_path_omits_profile_sourcing", async () => {
process.env.DAYTONA_API_KEY = "host-key";
const sandbox = createMockSandbox();
mockGet.mockResolvedValue(sandbox);
await plugin.definition.onEnvironmentExecute?.({
driverKey: "daytona",
companyId: "company-1",
environmentId: "env-1",
config: { timeoutMs: 300000, reuseLease: false },
lease: { providerLeaseId: "sandbox-123", metadata: {} },
command: "tar",
args: ["-xf", "/workspace/upload.tar", "-C", "/workspace"],
cwd: "/workspace",
noProfile: true,
timeoutMs: 1000,
});
const [command] = sandbox.process.executeCommand.mock.calls[0] as [string];
expect(command).not.toMatch(/\/etc\/profile/);
expect(command).not.toMatch(/nvm\.sh/);
expect(command).not.toMatch(/NVM_DIR/);
expect(command).not.toMatch(/\.bash_profile/);
});
it("test_no_profile_fast_path_preserves_env_cwd_and_duration", async () => {
process.env.DAYTONA_API_KEY = "host-key";
const sandbox = createMockSandbox();
sandbox.process.executeCommand.mockResolvedValue({
exitCode: 0,
result: "ok",
artifacts: { stdout: "ok" },
});
mockGet.mockResolvedValue(sandbox);
const result = await plugin.definition.onEnvironmentExecute?.({
driverKey: "daytona",
companyId: "company-1",
environmentId: "env-1",
config: { timeoutMs: 300000, reuseLease: false },
lease: { providerLeaseId: "sandbox-123", metadata: {} },
command: "base64",
args: ["-d"],
cwd: "/workspace",
env: { FOO: "bar" },
noProfile: true,
timeoutMs: 1000,
});
const [command] = sandbox.process.executeCommand.mock.calls[0] as [string];
// The full exec surface is preserved on the fast path — only profile sourcing
// is dropped. The command must still start with the `cd` (no profile lines
// ahead of it) and carry the env prefix and noninteractive git defaults.
expect(command).toMatch(/^cd '\/workspace' && env /);
expect(command).toMatch(/GIT_TERMINAL_PROMPT='0'/);
expect(command).toMatch(/FOO='bar' 'base64' '-d'$/);
expect(command).not.toMatch(/\/etc\/profile/);
// durationMs attribution is unchanged on the fast path.
expect(typeof (result!.metadata as Record<string, unknown>)?.durationMs).toBe("number");
});
it("test_default_path_still_sources_profile", async () => {
process.env.DAYTONA_API_KEY = "host-key";
const sandbox = createMockSandbox();
mockGet.mockResolvedValue(sandbox);
// No `noProfile` flag: the fail-safe default must still source the login
// profile so node-launching execs resolve their nvm/profile PATH.
await plugin.definition.onEnvironmentExecute?.({
driverKey: "daytona",
companyId: "company-1",
environmentId: "env-1",
config: { timeoutMs: 300000, reuseLease: false },
lease: { providerLeaseId: "sandbox-123", metadata: {} },
command: "node",
args: ["--version"],
cwd: "/workspace",
timeoutMs: 1000,
});
const [command] = sandbox.process.executeCommand.mock.calls[0] as [string];
expect(command).toMatch(/\/etc\/profile/);
expect(command).toMatch(/nvm\.sh/);
});
// ─── Per-lease started-sandbox handle cache ────────────────────────────────
// These prove the security conditions: single-fetch-per-lease, strict
// composite-key isolation (no cross-lease / cross-company / cross-env reuse),

View File

@ -666,6 +666,7 @@ function buildLoginShellScript(input: {
cwd?: string;
env?: Record<string, string>;
stdinPath?: string;
noProfile?: boolean;
}): string {
const callerEnv = input.env ?? {};
for (const key of Object.keys(callerEnv)) {
@ -689,15 +690,20 @@ function buildLoginShellScript(input: {
const finalLine = envArgs.length > 0
? `env ${envArgs.join(" ")} ${redirectedCommand}`
: redirectedCommand;
const profileSourcingLines = input.noProfile === true
? []
: [
'if [ -f /etc/profile ]; then . /etc/profile >/dev/null 2>&1 || true; fi',
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile" >/dev/null 2>&1 || true; fi',
// .bash_profile typically sources .bashrc itself; only source .bashrc
// directly when no .bash_profile exists to avoid double-running setup.
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile" >/dev/null 2>&1 || true; elif [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" >/dev/null 2>&1 || true; fi',
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile" >/dev/null 2>&1 || true; fi',
'export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"',
'[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" >/dev/null 2>&1 || true',
];
const lines = [
'if [ -f /etc/profile ]; then . /etc/profile >/dev/null 2>&1 || true; fi',
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile" >/dev/null 2>&1 || true; fi',
// .bash_profile typically sources .bashrc itself; only source .bashrc
// directly when no .bash_profile exists to avoid double-running setup.
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile" >/dev/null 2>&1 || true; elif [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" >/dev/null 2>&1 || true; fi',
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile" >/dev/null 2>&1 || true; fi',
'export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"',
'[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" >/dev/null 2>&1 || true',
...profileSourcingLines,
];
if (input.cwd) {
lines.push(`cd ${shellQuote(input.cwd)}`);
@ -1152,6 +1158,7 @@ async function executeOneShot(
cwd: params.cwd,
env: params.env,
stdinPath: stdinPath ?? undefined,
noProfile: params.noProfile === true,
});
// Pass cwd undefined: `buildLoginShellScript` already injects `cd` after

View File

@ -651,6 +651,8 @@ export interface PluginEnvironmentExecuteParams extends PluginEnvironmentDriverB
env?: Record<string, string>;
stdin?: string;
timeoutMs?: number;
/** Skip login-shell profile sourcing when the command already resolves on the sandbox default PATH. */
noProfile?: boolean;
}
export interface PluginEnvironmentExecuteResult {

View File

@ -2277,6 +2277,7 @@ describeEmbeddedPostgres("environmentRuntimeService", () => {
env: { FOO: "bar" },
stdin: "",
timeoutMs: 1000,
noProfile: true,
});
const destroyed = await runtimeWithPlugin.destroyRunLease({
environment,
@ -2331,6 +2332,7 @@ describeEmbeddedPostgres("environmentRuntimeService", () => {
args: ["ok"],
cwd: "/workspace/project",
env: { FOO: "bar" },
noProfile: true,
}), 31000);
expect(workerManager.call).toHaveBeenCalledWith(pluginId, "environmentDestroyLease", {
driverKey: "fake-plugin",

View File

@ -118,6 +118,7 @@ export async function resolveEnvironmentExecutionTarget(input: {
env: commandInput.env,
stdin: commandInput.stdin,
timeoutMs: commandInput.timeoutMs,
noProfile: commandInput.noProfile,
});
accumulateProviderDurations(result.metadata);
if (result.stdout) await commandInput.onLog?.("stdout", result.stdout);

View File

@ -188,6 +188,11 @@ export interface EnvironmentDriverExecuteInput extends EnvironmentDriverLeaseInp
env?: Record<string, string>;
stdin?: string;
timeoutMs?: number;
/**
* Skip login-shell profile sourcing for commands that already
* resolve on the sandbox default PATH.
*/
noProfile?: boolean;
}
export interface EnvironmentDriverSyncInput extends EnvironmentDriverLeaseInput {
@ -1278,6 +1283,7 @@ function createSandboxEnvironmentDriver(
env: input.env,
stdin: input.stdin,
timeoutMs: input.timeoutMs,
noProfile: input.noProfile === true,
}, resolvePluginExecuteRpcTimeoutMs({
requestedTimeoutMs: input.timeoutMs,
config: sanitizedConfig,
@ -1738,6 +1744,7 @@ function createPluginEnvironmentDriver(
env: input.env,
stdin: input.stdin,
timeoutMs: input.timeoutMs,
noProfile: input.noProfile === true,
},
});
},