Skip to content

Commit bb72193

Browse files
Propagate cwd and env options in executeCommand (#42)
* feat: add support for cwd and env vars in execute commands * Create wet-jars-double.md --------- Co-authored-by: Sunil Pai <[email protected]>
1 parent 598205f commit bb72193

File tree

5 files changed

+43
-28
lines changed

5 files changed

+43
-28
lines changed

.changeset/wet-jars-double.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/sandbox": patch
3+
---
4+
5+
Propagate `cwd` and `env` options in `executeCommand`

packages/sandbox/container_src/handler/exec.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { type SpawnOptions, spawn } from "node:child_process";
2-
import type { ExecuteRequest, SessionData } from "../types";
2+
import type { ExecuteOptions, ExecuteRequest, SessionData } from "../types";
33

44
function executeCommand(
55
sessions: Map<string, SessionData>,
66
command: string,
7-
sessionId?: string,
8-
background?: boolean
7+
options: ExecuteOptions,
98
): Promise<{
109
success: boolean;
1110
stdout: string;
@@ -16,14 +15,16 @@ function executeCommand(
1615
const spawnOptions: SpawnOptions = {
1716
shell: true,
1817
stdio: ["pipe", "pipe", "pipe"] as const,
19-
detached: background || false,
18+
detached: options.background || false,
19+
cwd: options.cwd,
20+
env: options.env ? { ...process.env, ...options.env } : process.env
2021
};
2122

2223
const child = spawn(command, spawnOptions);
2324

2425
// Store the process reference for cleanup if sessionId is provided
25-
if (sessionId && sessions.has(sessionId)) {
26-
const session = sessions.get(sessionId)!;
26+
if (options.sessionId && sessions.has(options.sessionId)) {
27+
const session = sessions.get(options.sessionId)!;
2728
session.activeProcess = child;
2829
}
2930

@@ -38,7 +39,7 @@ function executeCommand(
3839
stderr += data.toString();
3940
});
4041

41-
if (background) {
42+
if (options.background) {
4243
// For background processes, unref and return quickly
4344
child.unref();
4445

@@ -61,8 +62,8 @@ function executeCommand(
6162
// Normal synchronous execution
6263
child.on("close", (code) => {
6364
// Clear the active process reference
64-
if (sessionId && sessions.has(sessionId)) {
65-
const session = sessions.get(sessionId)!;
65+
if (options.sessionId && sessions.has(options.sessionId)) {
66+
const session = sessions.get(options.sessionId)!;
6667
session.activeProcess = null;
6768
}
6869

@@ -78,8 +79,8 @@ function executeCommand(
7879

7980
child.on("error", (error) => {
8081
// Clear the active process reference
81-
if (sessionId && sessions.has(sessionId)) {
82-
const session = sessions.get(sessionId)!;
82+
if (options.sessionId && sessions.has(options.sessionId)) {
83+
const session = sessions.get(options.sessionId)!;
8384
session.activeProcess = null;
8485
}
8586

@@ -96,7 +97,7 @@ export async function handleExecuteRequest(
9697
): Promise<Response> {
9798
try {
9899
const body = (await req.json()) as ExecuteRequest;
99-
const { command, sessionId, background } = body;
100+
const { command, sessionId, background, cwd, env } = body;
100101

101102
if (!command || typeof command !== "string") {
102103
return new Response(
@@ -115,7 +116,7 @@ export async function handleExecuteRequest(
115116

116117
console.log(`[Server] Executing command: ${command}`);
117118

118-
const result = await executeCommand(sessions, command, sessionId, background);
119+
const result = await executeCommand(sessions, command, { sessionId, background, cwd, env });
119120

120121
return new Response(
121122
JSON.stringify({

packages/sandbox/container_src/types.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ export interface StartProcessRequest {
3838
};
3939
}
4040

41-
export interface ExecuteRequest {
42-
command: string;
43-
sessionId?: string;
41+
export interface ExecuteOptions {
42+
sessionId?: string | null;
4443
background?: boolean;
44+
cwd?: string | URL;
45+
env?: Record<string, string>;
46+
}
47+
48+
export interface ExecuteRequest extends ExecuteOptions {
49+
command: string;
4550
}
4651

4752
export interface GitCheckoutRequest {

packages/sandbox/src/client.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
import type { ExecuteRequest } from "../container_src/types";
12
import type { Sandbox } from "./index";
23
import type {
4+
BaseExecOptions,
35
GetProcessLogsResponse,
46
GetProcessResponse,
57
ListProcessesResponse,
68
StartProcessRequest,
79
StartProcessResponse
810
} from "./types";
911

10-
interface ExecuteRequest {
11-
command: string;
12-
sessionId?: string;
13-
}
14-
1512
export interface ExecuteResponse {
1613
success: boolean;
1714
stdout: string;
@@ -255,16 +252,19 @@ export class HttpClient {
255252

256253
async execute(
257254
command: string,
258-
sessionId?: string
255+
options: Pick<BaseExecOptions, 'sessionId' | 'cwd' | 'env'>
259256
): Promise<ExecuteResponse> {
260257
try {
261-
const targetSessionId = sessionId || this.sessionId;
258+
const targetSessionId = options.sessionId || this.sessionId;
259+
const executeRequest = {
260+
command,
261+
sessionId: targetSessionId,
262+
cwd: options.cwd,
263+
env: options.env,
264+
} satisfies ExecuteRequest;
262265

263266
const response = await this.doFetch(`/api/execute`, {
264-
body: JSON.stringify({
265-
command,
266-
sessionId: targetSessionId,
267-
} as ExecuteRequest),
267+
body: JSON.stringify(executeRequest),
268268
headers: {
269269
"Content-Type": "application/json",
270270
},

packages/sandbox/src/sandbox.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,11 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
150150
// Regular execution
151151
const response = await this.client.execute(
152152
command,
153-
options?.sessionId
153+
{
154+
sessionId: options?.sessionId,
155+
cwd: options?.cwd,
156+
env: options?.env,
157+
}
154158
);
155159

156160
const duration = Date.now() - startTime;

0 commit comments

Comments
 (0)