@cloudflare/sandbox 0.0.0-ab0979d → 0.0.0-af082ab

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/client.ts CHANGED
@@ -1,41 +1,23 @@
1
+ import type { ExecuteRequest } from "../container_src/types";
1
2
  import type { Sandbox } from "./index";
2
3
  import type {
4
+ BaseExecOptions,
5
+ DeleteFileResponse,
6
+ ExecuteResponse,
3
7
  GetProcessLogsResponse,
4
8
  GetProcessResponse,
9
+ GitCheckoutResponse,
10
+ ListFilesResponse,
5
11
  ListProcessesResponse,
12
+ MkdirResponse,
13
+ MoveFileResponse,
14
+ ReadFileResponse,
15
+ RenameFileResponse,
6
16
  StartProcessRequest,
7
- StartProcessResponse
17
+ StartProcessResponse,
18
+ WriteFileResponse,
8
19
  } from "./types";
9
20
 
10
- interface ExecuteRequest {
11
- command: string;
12
- sessionId?: string;
13
- }
14
-
15
- export interface ExecuteResponse {
16
- success: boolean;
17
- stdout: string;
18
- stderr: string;
19
- exitCode: number;
20
- command: string;
21
- timestamp: string;
22
- }
23
-
24
- interface SessionResponse {
25
- sessionId: string;
26
- message: string;
27
- timestamp: string;
28
- }
29
-
30
- interface SessionListResponse {
31
- sessions: Array<{
32
- sessionId: string;
33
- hasActiveProcess: boolean;
34
- createdAt: string;
35
- }>;
36
- count: number;
37
- timestamp: string;
38
- }
39
21
 
40
22
  interface CommandsResponse {
41
23
  availableCommands: string[];
@@ -46,104 +28,62 @@ interface GitCheckoutRequest {
46
28
  repoUrl: string;
47
29
  branch?: string;
48
30
  targetDir?: string;
49
- sessionId?: string;
31
+ sessionId: string;
50
32
  }
51
33
 
52
- export interface GitCheckoutResponse {
53
- success: boolean;
54
- stdout: string;
55
- stderr: string;
56
- exitCode: number;
57
- repoUrl: string;
58
- branch: string;
59
- targetDir: string;
60
- timestamp: string;
61
- }
62
34
 
63
35
  interface MkdirRequest {
64
36
  path: string;
65
37
  recursive?: boolean;
66
- sessionId?: string;
38
+ sessionId: string;
67
39
  }
68
40
 
69
- export interface MkdirResponse {
70
- success: boolean;
71
- stdout: string;
72
- stderr: string;
73
- exitCode: number;
74
- path: string;
75
- recursive: boolean;
76
- timestamp: string;
77
- }
78
41
 
79
42
  interface WriteFileRequest {
80
43
  path: string;
81
44
  content: string;
82
45
  encoding?: string;
83
- sessionId?: string;
46
+ sessionId: string;
84
47
  }
85
48
 
86
- export interface WriteFileResponse {
87
- success: boolean;
88
- exitCode: number;
89
- path: string;
90
- timestamp: string;
91
- }
92
49
 
93
50
  interface ReadFileRequest {
94
51
  path: string;
95
52
  encoding?: string;
96
- sessionId?: string;
53
+ sessionId: string;
97
54
  }
98
55
 
99
- export interface ReadFileResponse {
100
- success: boolean;
101
- exitCode: number;
102
- path: string;
103
- content: string;
104
- timestamp: string;
105
- }
106
56
 
107
57
  interface DeleteFileRequest {
108
58
  path: string;
109
- sessionId?: string;
59
+ sessionId: string;
110
60
  }
111
61
 
112
- export interface DeleteFileResponse {
113
- success: boolean;
114
- exitCode: number;
115
- path: string;
116
- timestamp: string;
117
- }
118
62
 
119
63
  interface RenameFileRequest {
120
64
  oldPath: string;
121
65
  newPath: string;
122
- sessionId?: string;
66
+ sessionId: string;
123
67
  }
124
68
 
125
- export interface RenameFileResponse {
126
- success: boolean;
127
- exitCode: number;
128
- oldPath: string;
129
- newPath: string;
130
- timestamp: string;
131
- }
132
69
 
133
70
  interface MoveFileRequest {
134
71
  sourcePath: string;
135
72
  destinationPath: string;
136
- sessionId?: string;
73
+ sessionId: string;
137
74
  }
138
75
 
139
- export interface MoveFileResponse {
140
- success: boolean;
141
- exitCode: number;
142
- sourcePath: string;
143
- destinationPath: string;
144
- timestamp: string;
76
+
77
+ interface ListFilesRequest {
78
+ path: string;
79
+ options?: {
80
+ recursive?: boolean;
81
+ includeHidden?: boolean;
82
+ };
83
+ sessionId: string;
145
84
  }
146
85
 
86
+
147
87
  interface PreviewInfo {
148
88
  url: string;
149
89
  port: number;
@@ -203,7 +143,6 @@ interface HttpClientOptions {
203
143
  export class HttpClient {
204
144
  private baseUrl: string;
205
145
  private options: HttpClientOptions;
206
- private sessionId: string | null = null;
207
146
 
208
147
  constructor(options: HttpClientOptions = {}) {
209
148
  this.options = {
@@ -212,7 +151,7 @@ export class HttpClient {
212
151
  this.baseUrl = this.options.baseUrl!;
213
152
  }
214
153
 
215
- private async doFetch(
154
+ protected async doFetch(
216
155
  path: string,
217
156
  options?: RequestInit
218
157
  ): Promise<Response> {
@@ -253,22 +192,52 @@ export class HttpClient {
253
192
  }
254
193
  }
255
194
 
256
- async execute(
195
+ async createSession(options: {
196
+ id: string;
197
+ env?: Record<string, string>;
198
+ cwd?: string;
199
+ isolation?: boolean;
200
+ }): Promise<{ success: boolean; id: string; message: string }> {
201
+ try {
202
+ const response = await this.doFetch(`/api/session/create`, {
203
+ method: "POST",
204
+ headers: {
205
+ "Content-Type": "application/json",
206
+ },
207
+ body: JSON.stringify(options),
208
+ });
209
+
210
+ if (!response.ok) {
211
+ const errorData = (await response.json().catch(() => ({}))) as {
212
+ error?: string;
213
+ };
214
+ throw new Error(
215
+ errorData.error || `Failed to create session: ${response.status}`
216
+ );
217
+ }
218
+
219
+ const data = await response.json() as { success: boolean; id: string; message: string };
220
+ console.log(`[HTTP Client] Session created: ${options.id}`);
221
+ return data;
222
+ } catch (error) {
223
+ console.error("[HTTP Client] Error creating session:", error);
224
+ throw error;
225
+ }
226
+ }
227
+
228
+ async exec(
229
+ sessionId: string,
257
230
  command: string,
258
- sessionId?: string
231
+ options?: Pick<BaseExecOptions, "cwd" | "env">
259
232
  ): Promise<ExecuteResponse> {
260
233
  try {
261
- const targetSessionId = sessionId || this.sessionId;
262
-
234
+ // Always use session-specific endpoint
263
235
  const response = await this.doFetch(`/api/execute`, {
264
- body: JSON.stringify({
265
- command,
266
- sessionId: targetSessionId,
267
- } as ExecuteRequest),
236
+ method: "POST",
268
237
  headers: {
269
238
  "Content-Type": "application/json",
270
239
  },
271
- method: "POST",
240
+ body: JSON.stringify({ id: sessionId, command }),
272
241
  });
273
242
 
274
243
  if (!response.ok) {
@@ -276,27 +245,34 @@ export class HttpClient {
276
245
  error?: string;
277
246
  };
278
247
  throw new Error(
279
- errorData.error || `HTTP error! status: ${response.status}`
248
+ errorData.error || `Failed to execute in session: ${response.status}`
280
249
  );
281
250
  }
282
251
 
283
- const data: ExecuteResponse = await response.json();
252
+ const data = await response.json() as { stdout: string; stderr: string; exitCode: number; success: boolean };
284
253
  console.log(
285
- `[HTTP Client] Command executed: ${command}, Success: ${data.success}`
254
+ `[HTTP Client] Command executed in session ${sessionId}: ${command}`
286
255
  );
256
+
257
+ // Convert to ExecuteResponse format for consistency
258
+ const executeResponse: ExecuteResponse = {
259
+ ...data,
260
+ command,
261
+ timestamp: new Date().toISOString()
262
+ };
287
263
 
288
264
  // Call the callback if provided
289
265
  this.options.onCommandComplete?.(
290
- data.success,
291
- data.exitCode,
292
- data.stdout,
293
- data.stderr,
294
- data.command
266
+ executeResponse.success,
267
+ executeResponse.exitCode,
268
+ executeResponse.stdout,
269
+ executeResponse.stderr,
270
+ executeResponse.command
295
271
  );
296
272
 
297
- return data;
273
+ return executeResponse;
298
274
  } catch (error) {
299
- console.error("[HTTP Client] Error executing command:", error);
275
+ console.error("[HTTP Client] Error executing in session:", error);
300
276
  this.options.onError?.(
301
277
  error instanceof Error ? error.message : "Unknown error",
302
278
  command
@@ -305,24 +281,21 @@ export class HttpClient {
305
281
  }
306
282
  }
307
283
 
308
-
309
- async executeCommandStream(
310
- command: string,
311
- sessionId?: string
284
+ async execStream(
285
+ sessionId: string,
286
+ command: string
312
287
  ): Promise<ReadableStream<Uint8Array>> {
313
288
  try {
314
- const targetSessionId = sessionId || this.sessionId;
315
-
289
+ // Always use session-specific streaming endpoint
316
290
  const response = await this.doFetch(`/api/execute/stream`, {
317
- body: JSON.stringify({
318
- command,
319
- sessionId: targetSessionId,
320
- }),
291
+ method: "POST",
321
292
  headers: {
322
293
  "Content-Type": "application/json",
323
- "Accept": "text/event-stream",
324
294
  },
325
- method: "POST",
295
+ body: JSON.stringify({
296
+ id: sessionId,
297
+ command
298
+ }),
326
299
  });
327
300
 
328
301
  if (!response.ok) {
@@ -330,40 +303,37 @@ export class HttpClient {
330
303
  error?: string;
331
304
  };
332
305
  throw new Error(
333
- errorData.error || `HTTP error! status: ${response.status}`
306
+ errorData.error || `Failed to stream execute in session: ${response.status}`
334
307
  );
335
308
  }
336
309
 
337
310
  if (!response.body) {
338
- throw new Error("No response body for streaming request");
311
+ throw new Error("No response body for streaming execution");
339
312
  }
340
313
 
341
314
  console.log(
342
- `[HTTP Client] Started command stream: ${command}`
315
+ `[HTTP Client] Started streaming command in session ${sessionId}: ${command}`
343
316
  );
344
-
345
317
  return response.body;
346
318
  } catch (error) {
347
- console.error("[HTTP Client] Error in command stream:", error);
319
+ console.error("[HTTP Client] Error streaming execute in session:", error);
348
320
  throw error;
349
321
  }
350
322
  }
351
323
 
352
324
  async gitCheckout(
353
325
  repoUrl: string,
326
+ sessionId: string,
354
327
  branch: string = "main",
355
- targetDir?: string,
356
- sessionId?: string
328
+ targetDir?: string
357
329
  ): Promise<GitCheckoutResponse> {
358
330
  try {
359
- const targetSessionId = sessionId || this.sessionId;
360
-
361
331
  const response = await this.doFetch(`/api/git/checkout`, {
362
332
  body: JSON.stringify({
363
333
  branch,
364
334
  repoUrl,
365
- sessionId: targetSessionId,
366
335
  targetDir,
336
+ sessionId,
367
337
  } as GitCheckoutRequest),
368
338
  headers: {
369
339
  "Content-Type": "application/json",
@@ -392,20 +362,17 @@ export class HttpClient {
392
362
  }
393
363
  }
394
364
 
395
-
396
365
  async mkdir(
397
366
  path: string,
398
367
  recursive: boolean = false,
399
- sessionId?: string
368
+ sessionId: string
400
369
  ): Promise<MkdirResponse> {
401
370
  try {
402
- const targetSessionId = sessionId || this.sessionId;
403
-
404
371
  const response = await this.doFetch(`/api/mkdir`, {
405
372
  body: JSON.stringify({
406
373
  path,
407
374
  recursive,
408
- sessionId: targetSessionId,
375
+ sessionId,
409
376
  } as MkdirRequest),
410
377
  headers: {
411
378
  "Content-Type": "application/json",
@@ -424,7 +391,7 @@ export class HttpClient {
424
391
 
425
392
  const data: MkdirResponse = await response.json();
426
393
  console.log(
427
- `[HTTP Client] Directory created: ${path}, Success: ${data.success}, Recursive: ${data.recursive}`
394
+ `[HTTP Client] Directory created: ${path}, Success: ${data.success}, Recursive: ${data.recursive}${sessionId ? ` in session: ${sessionId}` : ''}`
428
395
  );
429
396
 
430
397
  return data;
@@ -434,22 +401,19 @@ export class HttpClient {
434
401
  }
435
402
  }
436
403
 
437
-
438
404
  async writeFile(
439
405
  path: string,
440
406
  content: string,
441
407
  encoding: string = "utf-8",
442
- sessionId?: string
408
+ sessionId: string
443
409
  ): Promise<WriteFileResponse> {
444
410
  try {
445
- const targetSessionId = sessionId || this.sessionId;
446
-
447
411
  const response = await this.doFetch(`/api/write`, {
448
412
  body: JSON.stringify({
449
413
  content,
450
414
  encoding,
451
415
  path,
452
- sessionId: targetSessionId,
416
+ sessionId,
453
417
  } as WriteFileRequest),
454
418
  headers: {
455
419
  "Content-Type": "application/json",
@@ -468,7 +432,7 @@ export class HttpClient {
468
432
 
469
433
  const data: WriteFileResponse = await response.json();
470
434
  console.log(
471
- `[HTTP Client] File written: ${path}, Success: ${data.success}`
435
+ `[HTTP Client] File written: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
472
436
  );
473
437
 
474
438
  return data;
@@ -478,20 +442,17 @@ export class HttpClient {
478
442
  }
479
443
  }
480
444
 
481
-
482
445
  async readFile(
483
446
  path: string,
484
447
  encoding: string = "utf-8",
485
- sessionId?: string
448
+ sessionId: string
486
449
  ): Promise<ReadFileResponse> {
487
450
  try {
488
- const targetSessionId = sessionId || this.sessionId;
489
-
490
451
  const response = await this.doFetch(`/api/read`, {
491
452
  body: JSON.stringify({
492
453
  encoding,
493
454
  path,
494
- sessionId: targetSessionId,
455
+ sessionId,
495
456
  } as ReadFileRequest),
496
457
  headers: {
497
458
  "Content-Type": "application/json",
@@ -510,7 +471,7 @@ export class HttpClient {
510
471
 
511
472
  const data: ReadFileResponse = await response.json();
512
473
  console.log(
513
- `[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}`
474
+ `[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}${sessionId ? ` in session: ${sessionId}` : ''}`
514
475
  );
515
476
 
516
477
  return data;
@@ -520,18 +481,54 @@ export class HttpClient {
520
481
  }
521
482
  }
522
483
 
484
+ async readFileStream(
485
+ path: string,
486
+ sessionId: string
487
+ ): Promise<ReadableStream<Uint8Array>> {
488
+ try {
489
+ const response = await this.doFetch(`/api/read/stream`, {
490
+ method: "POST",
491
+ headers: {
492
+ "Content-Type": "application/json",
493
+ },
494
+ body: JSON.stringify({
495
+ path,
496
+ sessionId,
497
+ } as ReadFileRequest),
498
+ });
499
+
500
+ if (!response.ok) {
501
+ const errorData = (await response.json().catch(() => ({}))) as {
502
+ error?: string;
503
+ };
504
+ throw new Error(
505
+ errorData.error || `HTTP error! status: ${response.status}`
506
+ );
507
+ }
508
+
509
+ if (!response.body) {
510
+ throw new Error("No response body for file streaming");
511
+ }
512
+
513
+ console.log(
514
+ `[HTTP Client] Started streaming file: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`
515
+ );
516
+ return response.body;
517
+ } catch (error) {
518
+ console.error("[HTTP Client] Error streaming file:", error);
519
+ throw error;
520
+ }
521
+ }
523
522
 
524
523
  async deleteFile(
525
524
  path: string,
526
- sessionId?: string
525
+ sessionId: string
527
526
  ): Promise<DeleteFileResponse> {
528
527
  try {
529
- const targetSessionId = sessionId || this.sessionId;
530
-
531
528
  const response = await this.doFetch(`/api/delete`, {
532
529
  body: JSON.stringify({
533
530
  path,
534
- sessionId: targetSessionId,
531
+ sessionId,
535
532
  } as DeleteFileRequest),
536
533
  headers: {
537
534
  "Content-Type": "application/json",
@@ -550,7 +547,7 @@ export class HttpClient {
550
547
 
551
548
  const data: DeleteFileResponse = await response.json();
552
549
  console.log(
553
- `[HTTP Client] File deleted: ${path}, Success: ${data.success}`
550
+ `[HTTP Client] File deleted: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
554
551
  );
555
552
 
556
553
  return data;
@@ -560,20 +557,17 @@ export class HttpClient {
560
557
  }
561
558
  }
562
559
 
563
-
564
560
  async renameFile(
565
561
  oldPath: string,
566
562
  newPath: string,
567
- sessionId?: string
563
+ sessionId: string
568
564
  ): Promise<RenameFileResponse> {
569
565
  try {
570
- const targetSessionId = sessionId || this.sessionId;
571
-
572
566
  const response = await this.doFetch(`/api/rename`, {
573
567
  body: JSON.stringify({
574
568
  newPath,
575
569
  oldPath,
576
- sessionId: targetSessionId,
570
+ sessionId,
577
571
  } as RenameFileRequest),
578
572
  headers: {
579
573
  "Content-Type": "application/json",
@@ -592,7 +586,7 @@ export class HttpClient {
592
586
 
593
587
  const data: RenameFileResponse = await response.json();
594
588
  console.log(
595
- `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}`
589
+ `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
596
590
  );
597
591
 
598
592
  return data;
@@ -602,20 +596,17 @@ export class HttpClient {
602
596
  }
603
597
  }
604
598
 
605
-
606
599
  async moveFile(
607
600
  sourcePath: string,
608
601
  destinationPath: string,
609
- sessionId?: string
602
+ sessionId: string
610
603
  ): Promise<MoveFileResponse> {
611
604
  try {
612
- const targetSessionId = sessionId || this.sessionId;
613
-
614
605
  const response = await this.doFetch(`/api/move`, {
615
606
  body: JSON.stringify({
616
607
  destinationPath,
617
- sessionId: targetSessionId,
618
608
  sourcePath,
609
+ sessionId,
619
610
  } as MoveFileRequest),
620
611
  headers: {
621
612
  "Content-Type": "application/json",
@@ -634,7 +625,7 @@ export class HttpClient {
634
625
 
635
626
  const data: MoveFileResponse = await response.json();
636
627
  console.log(
637
- `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}`
628
+ `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
638
629
  );
639
630
 
640
631
  return data;
@@ -644,6 +635,47 @@ export class HttpClient {
644
635
  }
645
636
  }
646
637
 
638
+ async listFiles(
639
+ path: string,
640
+ sessionId: string,
641
+ options?: {
642
+ recursive?: boolean;
643
+ includeHidden?: boolean;
644
+ }
645
+ ): Promise<ListFilesResponse> {
646
+ try {
647
+ const response = await this.doFetch(`/api/list-files`, {
648
+ body: JSON.stringify({
649
+ path,
650
+ options,
651
+ sessionId,
652
+ } as ListFilesRequest),
653
+ headers: {
654
+ "Content-Type": "application/json",
655
+ },
656
+ method: "POST",
657
+ });
658
+
659
+ if (!response.ok) {
660
+ const errorData = (await response.json().catch(() => ({}))) as {
661
+ error?: string;
662
+ };
663
+ throw new Error(
664
+ errorData.error || `HTTP error! status: ${response.status}`
665
+ );
666
+ }
667
+
668
+ const data: ListFilesResponse = await response.json();
669
+ console.log(
670
+ `[HTTP Client] Listed ${data.files.length} files in: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
671
+ );
672
+
673
+ return data;
674
+ } catch (error) {
675
+ console.error("[HTTP Client] Error listing files:", error);
676
+ throw error;
677
+ }
678
+ }
647
679
 
648
680
  async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
649
681
  try {
@@ -670,7 +702,9 @@ export class HttpClient {
670
702
 
671
703
  const data: ExposePortResponse = await response.json();
672
704
  console.log(
673
- `[HTTP Client] Port exposed: ${port}${name ? ` (${name})` : ""}, Success: ${data.success}`
705
+ `[HTTP Client] Port exposed: ${port}${
706
+ name ? ` (${name})` : ""
707
+ }, Success: ${data.success}`
674
708
  );
675
709
 
676
710
  return data;
@@ -732,9 +766,7 @@ export class HttpClient {
732
766
  }
733
767
 
734
768
  const data: GetExposedPortsResponse = await response.json();
735
- console.log(
736
- `[HTTP Client] Got ${data.count} exposed ports`
737
- );
769
+ console.log(`[HTTP Client] Got ${data.count} exposed ports`);
738
770
 
739
771
  return data;
740
772
  } catch (error) {
@@ -765,48 +797,13 @@ export class HttpClient {
765
797
  }
766
798
  }
767
799
 
768
- async getCommands(): Promise<string[]> {
769
- try {
770
- const response = await fetch(`${this.baseUrl}/api/commands`, {
771
- headers: {
772
- "Content-Type": "application/json",
773
- },
774
- method: "GET",
775
- });
776
-
777
- if (!response.ok) {
778
- throw new Error(`HTTP error! status: ${response.status}`);
779
- }
780
-
781
- const data: CommandsResponse = await response.json();
782
- console.log(
783
- `[HTTP Client] Available commands: ${data.availableCommands.length}`
784
- );
785
- return data.availableCommands;
786
- } catch (error) {
787
- console.error("[HTTP Client] Error getting commands:", error);
788
- throw error;
789
- }
790
- }
791
-
792
- getSessionId(): string | null {
793
- return this.sessionId;
794
- }
795
-
796
- setSessionId(sessionId: string): void {
797
- this.sessionId = sessionId;
798
- }
799
-
800
- clearSession(): void {
801
- this.sessionId = null;
802
- }
803
800
 
804
801
  // Process management methods
805
802
  async startProcess(
806
803
  command: string,
804
+ sessionId: string,
807
805
  options?: {
808
806
  processId?: string;
809
- sessionId?: string;
810
807
  timeout?: number;
811
808
  env?: Record<string, string>;
812
809
  cwd?: string;
@@ -815,15 +812,11 @@ export class HttpClient {
815
812
  }
816
813
  ): Promise<StartProcessResponse> {
817
814
  try {
818
- const targetSessionId = options?.sessionId || this.sessionId;
819
-
820
815
  const response = await this.doFetch("/api/process/start", {
821
816
  body: JSON.stringify({
822
817
  command,
823
- options: {
824
- ...options,
825
- sessionId: targetSessionId,
826
- },
818
+ sessionId,
819
+ options,
827
820
  } as StartProcessRequest),
828
821
  headers: {
829
822
  "Content-Type": "application/json",
@@ -852,9 +845,12 @@ export class HttpClient {
852
845
  }
853
846
  }
854
847
 
855
- async listProcesses(): Promise<ListProcessesResponse> {
848
+ async listProcesses(sessionId?: string): Promise<ListProcessesResponse> {
856
849
  try {
857
- const response = await this.doFetch("/api/process/list", {
850
+ const url = sessionId
851
+ ? `/api/process/list?session=${encodeURIComponent(sessionId)}`
852
+ : "/api/process/list";
853
+ const response = await this.doFetch(url, {
858
854
  headers: {
859
855
  "Content-Type": "application/json",
860
856
  },
@@ -871,9 +867,7 @@ export class HttpClient {
871
867
  }
872
868
 
873
869
  const data: ListProcessesResponse = await response.json();
874
- console.log(
875
- `[HTTP Client] Listed ${data.processes.length} processes`
876
- );
870
+ console.log(`[HTTP Client] Listed ${data.processes.length} processes`);
877
871
 
878
872
  return data;
879
873
  } catch (error) {
@@ -902,7 +896,9 @@ export class HttpClient {
902
896
 
903
897
  const data: GetProcessResponse = await response.json();
904
898
  console.log(
905
- `[HTTP Client] Got process ${processId}: ${data.process?.status || 'not found'}`
899
+ `[HTTP Client] Got process ${processId}: ${
900
+ data.process?.status || "not found"
901
+ }`
906
902
  );
907
903
 
908
904
  return data;
@@ -912,7 +908,9 @@ export class HttpClient {
912
908
  }
913
909
  }
914
910
 
915
- async killProcess(processId: string): Promise<{ success: boolean; message: string }> {
911
+ async killProcess(
912
+ processId: string
913
+ ): Promise<{ success: boolean; message: string }> {
916
914
  try {
917
915
  const response = await this.doFetch(`/api/process/${processId}`, {
918
916
  headers: {
@@ -930,10 +928,11 @@ export class HttpClient {
930
928
  );
931
929
  }
932
930
 
933
- const data = await response.json() as { success: boolean; message: string };
934
- console.log(
935
- `[HTTP Client] Killed process ${processId}`
936
- );
931
+ const data = (await response.json()) as {
932
+ success: boolean;
933
+ message: string;
934
+ };
935
+ console.log(`[HTTP Client] Killed process ${processId}`);
937
936
 
938
937
  return data;
939
938
  } catch (error) {
@@ -942,9 +941,16 @@ export class HttpClient {
942
941
  }
943
942
  }
944
943
 
945
- async killAllProcesses(): Promise<{ success: boolean; killedCount: number; message: string }> {
944
+ async killAllProcesses(sessionId?: string): Promise<{
945
+ success: boolean;
946
+ killedCount: number;
947
+ message: string;
948
+ }> {
946
949
  try {
947
- const response = await this.doFetch("/api/process/kill-all", {
950
+ const url = sessionId
951
+ ? `/api/process/kill-all?session=${encodeURIComponent(sessionId)}`
952
+ : "/api/process/kill-all";
953
+ const response = await this.doFetch(url, {
948
954
  headers: {
949
955
  "Content-Type": "application/json",
950
956
  },
@@ -960,10 +966,12 @@ export class HttpClient {
960
966
  );
961
967
  }
962
968
 
963
- const data = await response.json() as { success: boolean; killedCount: number; message: string };
964
- console.log(
965
- `[HTTP Client] Killed ${data.killedCount} processes`
966
- );
969
+ const data = (await response.json()) as {
970
+ success: boolean;
971
+ killedCount: number;
972
+ message: string;
973
+ };
974
+ console.log(`[HTTP Client] Killed ${data.killedCount} processes`);
967
975
 
968
976
  return data;
969
977
  } catch (error) {
@@ -991,9 +999,7 @@ export class HttpClient {
991
999
  }
992
1000
 
993
1001
  const data: GetProcessLogsResponse = await response.json();
994
- console.log(
995
- `[HTTP Client] Got logs for process ${processId}`
996
- );
1002
+ console.log(`[HTTP Client] Got logs for process ${processId}`);
997
1003
 
998
1004
  return data;
999
1005
  } catch (error) {
@@ -1002,14 +1008,18 @@ export class HttpClient {
1002
1008
  }
1003
1009
  }
1004
1010
 
1005
- async streamProcessLogs(processId: string): Promise<ReadableStream<Uint8Array>> {
1011
+ async streamProcessLogs(
1012
+ processId: string,
1013
+ options?: { signal?: AbortSignal }
1014
+ ): Promise<ReadableStream<Uint8Array>> {
1006
1015
  try {
1007
1016
  const response = await this.doFetch(`/api/process/${processId}/stream`, {
1008
1017
  headers: {
1009
- "Accept": "text/event-stream",
1018
+ Accept: "text/event-stream",
1010
1019
  "Cache-Control": "no-cache",
1011
1020
  },
1012
1021
  method: "GET",
1022
+ signal: options?.signal,
1013
1023
  });
1014
1024
 
1015
1025
  if (!response.ok) {