@cloudflare/sandbox 0.0.0-dc66e8e → 0.0.0-e1fa354

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,15 @@ export class HttpClient {
520
481
  }
521
482
  }
522
483
 
523
-
524
484
  async deleteFile(
525
485
  path: string,
526
- sessionId?: string
486
+ sessionId: string
527
487
  ): Promise<DeleteFileResponse> {
528
488
  try {
529
- const targetSessionId = sessionId || this.sessionId;
530
-
531
489
  const response = await this.doFetch(`/api/delete`, {
532
490
  body: JSON.stringify({
533
491
  path,
534
- sessionId: targetSessionId,
492
+ sessionId,
535
493
  } as DeleteFileRequest),
536
494
  headers: {
537
495
  "Content-Type": "application/json",
@@ -550,7 +508,7 @@ export class HttpClient {
550
508
 
551
509
  const data: DeleteFileResponse = await response.json();
552
510
  console.log(
553
- `[HTTP Client] File deleted: ${path}, Success: ${data.success}`
511
+ `[HTTP Client] File deleted: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
554
512
  );
555
513
 
556
514
  return data;
@@ -560,20 +518,17 @@ export class HttpClient {
560
518
  }
561
519
  }
562
520
 
563
-
564
521
  async renameFile(
565
522
  oldPath: string,
566
523
  newPath: string,
567
- sessionId?: string
524
+ sessionId: string
568
525
  ): Promise<RenameFileResponse> {
569
526
  try {
570
- const targetSessionId = sessionId || this.sessionId;
571
-
572
527
  const response = await this.doFetch(`/api/rename`, {
573
528
  body: JSON.stringify({
574
529
  newPath,
575
530
  oldPath,
576
- sessionId: targetSessionId,
531
+ sessionId,
577
532
  } as RenameFileRequest),
578
533
  headers: {
579
534
  "Content-Type": "application/json",
@@ -592,7 +547,7 @@ export class HttpClient {
592
547
 
593
548
  const data: RenameFileResponse = await response.json();
594
549
  console.log(
595
- `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}`
550
+ `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
596
551
  );
597
552
 
598
553
  return data;
@@ -602,20 +557,17 @@ export class HttpClient {
602
557
  }
603
558
  }
604
559
 
605
-
606
560
  async moveFile(
607
561
  sourcePath: string,
608
562
  destinationPath: string,
609
- sessionId?: string
563
+ sessionId: string
610
564
  ): Promise<MoveFileResponse> {
611
565
  try {
612
- const targetSessionId = sessionId || this.sessionId;
613
-
614
566
  const response = await this.doFetch(`/api/move`, {
615
567
  body: JSON.stringify({
616
568
  destinationPath,
617
- sessionId: targetSessionId,
618
569
  sourcePath,
570
+ sessionId,
619
571
  } as MoveFileRequest),
620
572
  headers: {
621
573
  "Content-Type": "application/json",
@@ -634,7 +586,7 @@ export class HttpClient {
634
586
 
635
587
  const data: MoveFileResponse = await response.json();
636
588
  console.log(
637
- `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}`
589
+ `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
638
590
  );
639
591
 
640
592
  return data;
@@ -644,6 +596,47 @@ export class HttpClient {
644
596
  }
645
597
  }
646
598
 
599
+ async listFiles(
600
+ path: string,
601
+ sessionId: string,
602
+ options?: {
603
+ recursive?: boolean;
604
+ includeHidden?: boolean;
605
+ }
606
+ ): Promise<ListFilesResponse> {
607
+ try {
608
+ const response = await this.doFetch(`/api/list-files`, {
609
+ body: JSON.stringify({
610
+ path,
611
+ options,
612
+ sessionId,
613
+ } as ListFilesRequest),
614
+ headers: {
615
+ "Content-Type": "application/json",
616
+ },
617
+ method: "POST",
618
+ });
619
+
620
+ if (!response.ok) {
621
+ const errorData = (await response.json().catch(() => ({}))) as {
622
+ error?: string;
623
+ };
624
+ throw new Error(
625
+ errorData.error || `HTTP error! status: ${response.status}`
626
+ );
627
+ }
628
+
629
+ const data: ListFilesResponse = await response.json();
630
+ console.log(
631
+ `[HTTP Client] Listed ${data.files.length} files in: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
632
+ );
633
+
634
+ return data;
635
+ } catch (error) {
636
+ console.error("[HTTP Client] Error listing files:", error);
637
+ throw error;
638
+ }
639
+ }
647
640
 
648
641
  async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
649
642
  try {
@@ -670,7 +663,9 @@ export class HttpClient {
670
663
 
671
664
  const data: ExposePortResponse = await response.json();
672
665
  console.log(
673
- `[HTTP Client] Port exposed: ${port}${name ? ` (${name})` : ""}, Success: ${data.success}`
666
+ `[HTTP Client] Port exposed: ${port}${
667
+ name ? ` (${name})` : ""
668
+ }, Success: ${data.success}`
674
669
  );
675
670
 
676
671
  return data;
@@ -732,9 +727,7 @@ export class HttpClient {
732
727
  }
733
728
 
734
729
  const data: GetExposedPortsResponse = await response.json();
735
- console.log(
736
- `[HTTP Client] Got ${data.count} exposed ports`
737
- );
730
+ console.log(`[HTTP Client] Got ${data.count} exposed ports`);
738
731
 
739
732
  return data;
740
733
  } catch (error) {
@@ -765,48 +758,13 @@ export class HttpClient {
765
758
  }
766
759
  }
767
760
 
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
761
 
804
762
  // Process management methods
805
763
  async startProcess(
806
764
  command: string,
765
+ sessionId: string,
807
766
  options?: {
808
767
  processId?: string;
809
- sessionId?: string;
810
768
  timeout?: number;
811
769
  env?: Record<string, string>;
812
770
  cwd?: string;
@@ -815,15 +773,11 @@ export class HttpClient {
815
773
  }
816
774
  ): Promise<StartProcessResponse> {
817
775
  try {
818
- const targetSessionId = options?.sessionId || this.sessionId;
819
-
820
776
  const response = await this.doFetch("/api/process/start", {
821
777
  body: JSON.stringify({
822
778
  command,
823
- options: {
824
- ...options,
825
- sessionId: targetSessionId,
826
- },
779
+ sessionId,
780
+ options,
827
781
  } as StartProcessRequest),
828
782
  headers: {
829
783
  "Content-Type": "application/json",
@@ -852,9 +806,12 @@ export class HttpClient {
852
806
  }
853
807
  }
854
808
 
855
- async listProcesses(): Promise<ListProcessesResponse> {
809
+ async listProcesses(sessionId?: string): Promise<ListProcessesResponse> {
856
810
  try {
857
- const response = await this.doFetch("/api/process/list", {
811
+ const url = sessionId
812
+ ? `/api/process/list?session=${encodeURIComponent(sessionId)}`
813
+ : "/api/process/list";
814
+ const response = await this.doFetch(url, {
858
815
  headers: {
859
816
  "Content-Type": "application/json",
860
817
  },
@@ -871,9 +828,7 @@ export class HttpClient {
871
828
  }
872
829
 
873
830
  const data: ListProcessesResponse = await response.json();
874
- console.log(
875
- `[HTTP Client] Listed ${data.processes.length} processes`
876
- );
831
+ console.log(`[HTTP Client] Listed ${data.processes.length} processes`);
877
832
 
878
833
  return data;
879
834
  } catch (error) {
@@ -902,7 +857,9 @@ export class HttpClient {
902
857
 
903
858
  const data: GetProcessResponse = await response.json();
904
859
  console.log(
905
- `[HTTP Client] Got process ${processId}: ${data.process?.status || 'not found'}`
860
+ `[HTTP Client] Got process ${processId}: ${
861
+ data.process?.status || "not found"
862
+ }`
906
863
  );
907
864
 
908
865
  return data;
@@ -912,7 +869,9 @@ export class HttpClient {
912
869
  }
913
870
  }
914
871
 
915
- async killProcess(processId: string): Promise<{ success: boolean; message: string }> {
872
+ async killProcess(
873
+ processId: string
874
+ ): Promise<{ success: boolean; message: string }> {
916
875
  try {
917
876
  const response = await this.doFetch(`/api/process/${processId}`, {
918
877
  headers: {
@@ -930,10 +889,11 @@ export class HttpClient {
930
889
  );
931
890
  }
932
891
 
933
- const data = await response.json() as { success: boolean; message: string };
934
- console.log(
935
- `[HTTP Client] Killed process ${processId}`
936
- );
892
+ const data = (await response.json()) as {
893
+ success: boolean;
894
+ message: string;
895
+ };
896
+ console.log(`[HTTP Client] Killed process ${processId}`);
937
897
 
938
898
  return data;
939
899
  } catch (error) {
@@ -942,9 +902,16 @@ export class HttpClient {
942
902
  }
943
903
  }
944
904
 
945
- async killAllProcesses(): Promise<{ success: boolean; killedCount: number; message: string }> {
905
+ async killAllProcesses(sessionId?: string): Promise<{
906
+ success: boolean;
907
+ killedCount: number;
908
+ message: string;
909
+ }> {
946
910
  try {
947
- const response = await this.doFetch("/api/process/kill-all", {
911
+ const url = sessionId
912
+ ? `/api/process/kill-all?session=${encodeURIComponent(sessionId)}`
913
+ : "/api/process/kill-all";
914
+ const response = await this.doFetch(url, {
948
915
  headers: {
949
916
  "Content-Type": "application/json",
950
917
  },
@@ -960,10 +927,12 @@ export class HttpClient {
960
927
  );
961
928
  }
962
929
 
963
- const data = await response.json() as { success: boolean; killedCount: number; message: string };
964
- console.log(
965
- `[HTTP Client] Killed ${data.killedCount} processes`
966
- );
930
+ const data = (await response.json()) as {
931
+ success: boolean;
932
+ killedCount: number;
933
+ message: string;
934
+ };
935
+ console.log(`[HTTP Client] Killed ${data.killedCount} processes`);
967
936
 
968
937
  return data;
969
938
  } catch (error) {
@@ -991,9 +960,7 @@ export class HttpClient {
991
960
  }
992
961
 
993
962
  const data: GetProcessLogsResponse = await response.json();
994
- console.log(
995
- `[HTTP Client] Got logs for process ${processId}`
996
- );
963
+ console.log(`[HTTP Client] Got logs for process ${processId}`);
997
964
 
998
965
  return data;
999
966
  } catch (error) {
@@ -1002,14 +969,18 @@ export class HttpClient {
1002
969
  }
1003
970
  }
1004
971
 
1005
- async streamProcessLogs(processId: string): Promise<ReadableStream<Uint8Array>> {
972
+ async streamProcessLogs(
973
+ processId: string,
974
+ options?: { signal?: AbortSignal }
975
+ ): Promise<ReadableStream<Uint8Array>> {
1006
976
  try {
1007
977
  const response = await this.doFetch(`/api/process/${processId}/stream`, {
1008
978
  headers: {
1009
- "Accept": "text/event-stream",
979
+ Accept: "text/event-stream",
1010
980
  "Cache-Control": "no-cache",
1011
981
  },
1012
982
  method: "GET",
983
+ signal: options?.signal,
1013
984
  });
1014
985
 
1015
986
  if (!response.ok) {