@cloudflare/sandbox 0.0.9 → 0.1.1

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/Dockerfile +1 -14
  3. package/container_src/handler/exec.ts +337 -0
  4. package/container_src/handler/file.ts +844 -0
  5. package/container_src/handler/git.ts +182 -0
  6. package/container_src/handler/ports.ts +314 -0
  7. package/container_src/handler/process.ts +640 -0
  8. package/container_src/index.ts +82 -2973
  9. package/container_src/types.ts +103 -0
  10. package/dist/chunk-6THNBO4S.js +46 -0
  11. package/dist/chunk-6THNBO4S.js.map +1 -0
  12. package/dist/chunk-6UAWTJ5S.js +85 -0
  13. package/dist/chunk-6UAWTJ5S.js.map +1 -0
  14. package/dist/chunk-G4XT4SP7.js +638 -0
  15. package/dist/chunk-G4XT4SP7.js.map +1 -0
  16. package/dist/chunk-ISFOIYQC.js +585 -0
  17. package/dist/chunk-ISFOIYQC.js.map +1 -0
  18. package/dist/chunk-NNGBXDMY.js +89 -0
  19. package/dist/chunk-NNGBXDMY.js.map +1 -0
  20. package/dist/client-Da-mLX4p.d.ts +210 -0
  21. package/dist/client.d.ts +2 -1
  22. package/dist/client.js +3 -37
  23. package/dist/index.d.ts +3 -1
  24. package/dist/index.js +13 -3
  25. package/dist/request-handler.d.ts +2 -1
  26. package/dist/request-handler.js +4 -2
  27. package/dist/sandbox.d.ts +2 -1
  28. package/dist/sandbox.js +4 -2
  29. package/dist/security.d.ts +30 -0
  30. package/dist/security.js +13 -0
  31. package/dist/security.js.map +1 -0
  32. package/dist/sse-parser.d.ts +28 -0
  33. package/dist/sse-parser.js +11 -0
  34. package/dist/sse-parser.js.map +1 -0
  35. package/dist/types.d.ts +284 -0
  36. package/dist/types.js +19 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +2 -7
  39. package/src/client.ts +235 -1286
  40. package/src/index.ts +6 -0
  41. package/src/request-handler.ts +69 -20
  42. package/src/sandbox.ts +463 -70
  43. package/src/security.ts +113 -0
  44. package/src/sse-parser.ts +147 -0
  45. package/src/types.ts +386 -0
  46. package/tsconfig.json +1 -1
  47. package/README.md +0 -65
  48. package/dist/chunk-4J5LQCCN.js +0 -1446
  49. package/dist/chunk-4J5LQCCN.js.map +0 -1
  50. package/dist/chunk-5SZ3RVJZ.js +0 -250
  51. package/dist/chunk-5SZ3RVJZ.js.map +0 -1
  52. package/dist/client-BuVjqV00.d.ts +0 -247
  53. package/tests/client.example.ts +0 -308
  54. package/tests/connection-test.ts +0 -81
  55. package/tests/simple-test.ts +0 -81
  56. package/tests/test1.ts +0 -281
  57. package/tests/test2.ts +0 -929
package/src/client.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import type { Sandbox } from "./index";
2
+ import type {
3
+ GetProcessLogsResponse,
4
+ GetProcessResponse,
5
+ ListProcessesResponse,
6
+ StartProcessRequest,
7
+ StartProcessResponse
8
+ } from "./types";
2
9
 
3
10
  interface ExecuteRequest {
4
11
  command: string;
5
- args?: string[];
6
12
  sessionId?: string;
7
- background?: boolean;
8
13
  }
9
14
 
10
15
  export interface ExecuteResponse {
@@ -13,7 +18,6 @@ export interface ExecuteResponse {
13
18
  stderr: string;
14
19
  exitCode: number;
15
20
  command: string;
16
- args: string[];
17
21
  timestamp: string;
18
22
  }
19
23
 
@@ -176,32 +180,11 @@ interface PingResponse {
176
180
  timestamp: string;
177
181
  }
178
182
 
179
- interface StreamEvent {
180
- type: "command_start" | "output" | "command_complete" | "error";
181
- command?: string;
182
- args?: string[];
183
- stream?: "stdout" | "stderr";
184
- data?: string;
185
- message?: string;
186
- path?: string;
187
- oldPath?: string;
188
- newPath?: string;
189
- sourcePath?: string;
190
- destinationPath?: string;
191
- content?: string;
192
- success?: boolean;
193
- exitCode?: number;
194
- stdout?: string;
195
- stderr?: string;
196
- error?: string;
197
- timestamp?: string;
198
- }
199
-
200
183
  interface HttpClientOptions {
201
184
  stub?: Sandbox;
202
185
  baseUrl?: string;
203
186
  port?: number;
204
- onCommandStart?: (command: string, args: string[]) => void;
187
+ onCommandStart?: (command: string) => void;
205
188
  onOutput?: (
206
189
  stream: "stdout" | "stderr",
207
190
  data: string,
@@ -212,11 +195,9 @@ interface HttpClientOptions {
212
195
  exitCode: number,
213
196
  stdout: string,
214
197
  stderr: string,
215
- command: string,
216
- args: string[]
198
+ command: string
217
199
  ) => void;
218
- onError?: (error: string, command?: string, args?: string[]) => void;
219
- onStreamEvent?: (event: StreamEvent) => void;
200
+ onError?: (error: string, command?: string) => void;
220
201
  }
221
202
 
222
203
  export class HttpClient {
@@ -271,117 +252,17 @@ export class HttpClient {
271
252
  throw error;
272
253
  }
273
254
  }
274
- // Public methods to set event handlers
275
- setOnOutput(
276
- handler: (
277
- stream: "stdout" | "stderr",
278
- data: string,
279
- command: string
280
- ) => void
281
- ): void {
282
- this.options.onOutput = handler;
283
- }
284
-
285
- setOnCommandComplete(
286
- handler: (
287
- success: boolean,
288
- exitCode: number,
289
- stdout: string,
290
- stderr: string,
291
- command: string,
292
- args: string[]
293
- ) => void
294
- ): void {
295
- this.options.onCommandComplete = handler;
296
- }
297
-
298
- setOnStreamEvent(handler: (event: StreamEvent) => void): void {
299
- this.options.onStreamEvent = handler;
300
- }
301
-
302
- // Public getter methods
303
- getOnOutput():
304
- | ((stream: "stdout" | "stderr", data: string, command: string) => void)
305
- | undefined {
306
- return this.options.onOutput;
307
- }
308
-
309
- getOnCommandComplete():
310
- | ((
311
- success: boolean,
312
- exitCode: number,
313
- stdout: string,
314
- stderr: string,
315
- command: string,
316
- args: string[]
317
- ) => void)
318
- | undefined {
319
- return this.options.onCommandComplete;
320
- }
321
-
322
- getOnStreamEvent(): ((event: StreamEvent) => void) | undefined {
323
- return this.options.onStreamEvent;
324
- }
325
-
326
- async createSession(): Promise<string> {
327
- try {
328
- const response = await this.doFetch(`/api/session/create`, {
329
- headers: {
330
- "Content-Type": "application/json",
331
- },
332
- method: "POST",
333
- });
334
-
335
- if (!response.ok) {
336
- throw new Error(`HTTP error! status: ${response.status}`);
337
- }
338
-
339
- const data: SessionResponse = await response.json();
340
- this.sessionId = data.sessionId;
341
- console.log(`[HTTP Client] Created session: ${this.sessionId}`);
342
- return this.sessionId;
343
- } catch (error) {
344
- console.error("[HTTP Client] Error creating session:", error);
345
- throw error;
346
- }
347
- }
348
-
349
- async listSessions(): Promise<SessionListResponse> {
350
- try {
351
- const response = await this.doFetch(`/api/session/list`, {
352
- headers: {
353
- "Content-Type": "application/json",
354
- },
355
- method: "GET",
356
- });
357
-
358
- if (!response.ok) {
359
- throw new Error(`HTTP error! status: ${response.status}`);
360
- }
361
-
362
- const data: SessionListResponse = await response.json();
363
- console.log(`[HTTP Client] Listed ${data.count} sessions`);
364
- return data;
365
- } catch (error) {
366
- console.error("[HTTP Client] Error listing sessions:", error);
367
- throw error;
368
- }
369
- }
370
255
 
371
256
  async execute(
372
257
  command: string,
373
- args: string[] = [],
374
- sessionId?: string,
375
- background: boolean = false,
258
+ sessionId?: string
376
259
  ): Promise<ExecuteResponse> {
377
260
  try {
378
261
  const targetSessionId = sessionId || this.sessionId;
379
262
 
380
263
  const response = await this.doFetch(`/api/execute`, {
381
264
  body: JSON.stringify({
382
- args,
383
265
  command,
384
- background,
385
266
  sessionId: targetSessionId,
386
267
  } as ExecuteRequest),
387
268
  headers: {
@@ -410,8 +291,7 @@ export class HttpClient {
410
291
  data.exitCode,
411
292
  data.stdout,
412
293
  data.stderr,
413
- data.command,
414
- data.args
294
+ data.command
415
295
  );
416
296
 
417
297
  return data;
@@ -419,31 +299,28 @@ export class HttpClient {
419
299
  console.error("[HTTP Client] Error executing command:", error);
420
300
  this.options.onError?.(
421
301
  error instanceof Error ? error.message : "Unknown error",
422
- command,
423
- args
302
+ command
424
303
  );
425
304
  throw error;
426
305
  }
427
306
  }
428
307
 
429
- async executeStream(
308
+
309
+ async executeCommandStream(
430
310
  command: string,
431
- args: string[] = [],
432
- sessionId?: string,
433
- background: boolean = false
434
- ): Promise<void> {
311
+ sessionId?: string
312
+ ): Promise<ReadableStream<Uint8Array>> {
435
313
  try {
436
314
  const targetSessionId = sessionId || this.sessionId;
437
315
 
438
316
  const response = await this.doFetch(`/api/execute/stream`, {
439
317
  body: JSON.stringify({
440
- args,
441
318
  command,
442
- background,
443
319
  sessionId: targetSessionId,
444
320
  }),
445
321
  headers: {
446
322
  "Content-Type": "application/json",
323
+ "Accept": "text/event-stream",
447
324
  },
448
325
  method: "POST",
449
326
  });
@@ -461,94 +338,13 @@ export class HttpClient {
461
338
  throw new Error("No response body for streaming request");
462
339
  }
463
340
 
464
- const reader = response.body.getReader();
465
- const decoder = new TextDecoder();
466
-
467
- try {
468
- while (true) {
469
- const { done, value } = await reader.read();
470
-
471
- if (done) {
472
- break;
473
- }
474
-
475
- const chunk = decoder.decode(value, { stream: true });
476
- const lines = chunk.split("\n");
477
-
478
- for (const line of lines) {
479
- if (line.startsWith("data: ")) {
480
- try {
481
- const eventData = line.slice(6); // Remove 'data: ' prefix
482
- const event: StreamEvent = JSON.parse(eventData);
483
-
484
- console.log(`[HTTP Client] Stream event: ${event.type}`);
485
- this.options.onStreamEvent?.(event);
486
-
487
- switch (event.type) {
488
- case "command_start":
489
- console.log(
490
- `[HTTP Client] Command started: ${event.command
491
- } ${event.args?.join(" ")}`
492
- );
493
- this.options.onCommandStart?.(
494
- event.command!,
495
- event.args || []
496
- );
497
- break;
498
-
499
- case "output":
500
- console.log(`[${event.stream}] ${event.data}`);
501
- this.options.onOutput?.(
502
- event.stream!,
503
- event.data!,
504
- event.command!
505
- );
506
- break;
507
-
508
- case "command_complete":
509
- console.log(
510
- `[HTTP Client] Command completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
511
- );
512
- this.options.onCommandComplete?.(
513
- event.success!,
514
- event.exitCode!,
515
- event.stdout!,
516
- event.stderr!,
517
- event.command!,
518
- event.args || []
519
- );
520
- break;
521
-
522
- case "error":
523
- console.error(
524
- `[HTTP Client] Command error: ${event.error}`
525
- );
526
- this.options.onError?.(
527
- event.error!,
528
- event.command,
529
- event.args
530
- );
531
- break;
532
- }
533
- } catch (parseError) {
534
- console.warn(
535
- "[HTTP Client] Failed to parse stream event:",
536
- parseError
537
- );
538
- }
539
- }
540
- }
541
- }
542
- } finally {
543
- reader.releaseLock();
544
- }
545
- } catch (error) {
546
- console.error("[HTTP Client] Error in streaming execution:", error);
547
- this.options.onError?.(
548
- error instanceof Error ? error.message : "Unknown error",
549
- command,
550
- args
341
+ console.log(
342
+ `[HTTP Client] Started command stream: ${command}`
551
343
  );
344
+
345
+ return response.body;
346
+ } catch (error) {
347
+ console.error("[HTTP Client] Error in command stream:", error);
552
348
  throw error;
553
349
  }
554
350
  }
@@ -596,134 +392,6 @@ export class HttpClient {
596
392
  }
597
393
  }
598
394
 
599
- async gitCheckoutStream(
600
- repoUrl: string,
601
- branch: string = "main",
602
- targetDir?: string,
603
- sessionId?: string
604
- ): Promise<void> {
605
- try {
606
- const targetSessionId = sessionId || this.sessionId;
607
-
608
- const response = await this.doFetch(`/api/git/checkout/stream`, {
609
- body: JSON.stringify({
610
- branch,
611
- repoUrl,
612
- sessionId: targetSessionId,
613
- targetDir,
614
- }),
615
- headers: {
616
- "Content-Type": "application/json",
617
- },
618
- method: "POST",
619
- });
620
-
621
- if (!response.ok) {
622
- const errorData = (await response.json().catch(() => ({}))) as {
623
- error?: string;
624
- };
625
- throw new Error(
626
- errorData.error || `HTTP error! status: ${response.status}`
627
- );
628
- }
629
-
630
- if (!response.body) {
631
- throw new Error("No response body for streaming request");
632
- }
633
-
634
- const reader = response.body.getReader();
635
- const decoder = new TextDecoder();
636
-
637
- try {
638
- while (true) {
639
- const { done, value } = await reader.read();
640
-
641
- if (done) {
642
- break;
643
- }
644
-
645
- const chunk = decoder.decode(value, { stream: true });
646
- const lines = chunk.split("\n");
647
-
648
- for (const line of lines) {
649
- if (line.startsWith("data: ")) {
650
- try {
651
- const eventData = line.slice(6); // Remove 'data: ' prefix
652
- const event: StreamEvent = JSON.parse(eventData);
653
-
654
- console.log(
655
- `[HTTP Client] Git checkout stream event: ${event.type}`
656
- );
657
- this.options.onStreamEvent?.(event);
658
-
659
- switch (event.type) {
660
- case "command_start":
661
- console.log(
662
- `[HTTP Client] Git checkout started: ${event.command
663
- } ${event.args?.join(" ")}`
664
- );
665
- this.options.onCommandStart?.(
666
- event.command!,
667
- event.args || []
668
- );
669
- break;
670
-
671
- case "output":
672
- console.log(`[${event.stream}] ${event.data}`);
673
- this.options.onOutput?.(
674
- event.stream!,
675
- event.data!,
676
- event.command!
677
- );
678
- break;
679
-
680
- case "command_complete":
681
- console.log(
682
- `[HTTP Client] Git checkout completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
683
- );
684
- this.options.onCommandComplete?.(
685
- event.success!,
686
- event.exitCode!,
687
- event.stdout!,
688
- event.stderr!,
689
- event.command!,
690
- event.args || []
691
- );
692
- break;
693
-
694
- case "error":
695
- console.error(
696
- `[HTTP Client] Git checkout error: ${event.error}`
697
- );
698
- this.options.onError?.(
699
- event.error!,
700
- event.command,
701
- event.args
702
- );
703
- break;
704
- }
705
- } catch (parseError) {
706
- console.warn(
707
- "[HTTP Client] Failed to parse git checkout stream event:",
708
- parseError
709
- );
710
- }
711
- }
712
- }
713
- }
714
- } finally {
715
- reader.releaseLock();
716
- }
717
- } catch (error) {
718
- console.error("[HTTP Client] Error in streaming git checkout:", error);
719
- this.options.onError?.(
720
- error instanceof Error ? error.message : "Unknown error",
721
- "git clone",
722
- [branch, repoUrl, targetDir || ""]
723
- );
724
- throw error;
725
- }
726
- }
727
395
 
728
396
  async mkdir(
729
397
  path: string,
@@ -766,128 +434,6 @@ export class HttpClient {
766
434
  }
767
435
  }
768
436
 
769
- async mkdirStream(
770
- path: string,
771
- recursive: boolean = false,
772
- sessionId?: string
773
- ): Promise<void> {
774
- try {
775
- const targetSessionId = sessionId || this.sessionId;
776
-
777
- const response = await this.doFetch(`/api/mkdir/stream`, {
778
- body: JSON.stringify({
779
- path,
780
- recursive,
781
- sessionId: targetSessionId,
782
- } as MkdirRequest),
783
- headers: {
784
- "Content-Type": "application/json",
785
- },
786
- method: "POST",
787
- });
788
-
789
- if (!response.ok) {
790
- const errorData = (await response.json().catch(() => ({}))) as {
791
- error?: string;
792
- };
793
- throw new Error(
794
- errorData.error || `HTTP error! status: ${response.status}`
795
- );
796
- }
797
-
798
- if (!response.body) {
799
- throw new Error("No response body for streaming request");
800
- }
801
-
802
- const reader = response.body.getReader();
803
- const decoder = new TextDecoder();
804
-
805
- try {
806
- while (true) {
807
- const { done, value } = await reader.read();
808
-
809
- if (done) {
810
- break;
811
- }
812
-
813
- const chunk = decoder.decode(value, { stream: true });
814
- const lines = chunk.split("\n");
815
-
816
- for (const line of lines) {
817
- if (line.startsWith("data: ")) {
818
- try {
819
- const eventData = line.slice(6); // Remove 'data: ' prefix
820
- const event: StreamEvent = JSON.parse(eventData);
821
-
822
- console.log(`[HTTP Client] Mkdir stream event: ${event.type}`);
823
- this.options.onStreamEvent?.(event);
824
-
825
- switch (event.type) {
826
- case "command_start":
827
- console.log(
828
- `[HTTP Client] Mkdir started: ${event.command
829
- } ${event.args?.join(" ")}`
830
- );
831
- this.options.onCommandStart?.(
832
- event.command!,
833
- event.args || []
834
- );
835
- break;
836
-
837
- case "output":
838
- console.log(`[${event.stream}] ${event.data}`);
839
- this.options.onOutput?.(
840
- event.stream!,
841
- event.data!,
842
- event.command!
843
- );
844
- break;
845
-
846
- case "command_complete":
847
- console.log(
848
- `[HTTP Client] Mkdir completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
849
- );
850
- this.options.onCommandComplete?.(
851
- event.success!,
852
- event.exitCode!,
853
- event.stdout!,
854
- event.stderr!,
855
- event.command!,
856
- event.args || []
857
- );
858
- break;
859
-
860
- case "error":
861
- console.error(`[HTTP Client] Mkdir error: ${event.error}`);
862
- this.options.onError?.(
863
- event.error!,
864
- event.command,
865
- event.args
866
- );
867
- break;
868
- }
869
- } catch (parseError) {
870
- console.warn(
871
- "[HTTP Client] Failed to parse mkdir stream event:",
872
- parseError
873
- );
874
- }
875
- }
876
- }
877
- }
878
- } finally {
879
- reader.releaseLock();
880
- }
881
- } catch (error) {
882
- console.error("[HTTP Client] Error in streaming mkdir:", error);
883
- this.options.onError?.(
884
- error instanceof Error ? error.message : "Unknown error",
885
- "mkdir",
886
- recursive ? ["-p", path] : [path]
887
- );
888
- throw error;
889
- }
890
- }
891
437
 
892
438
  async writeFile(
893
439
  path: string,
@@ -932,130 +478,6 @@ export class HttpClient {
932
478
  }
933
479
  }
934
480
 
935
- async writeFileStream(
936
- path: string,
937
- content: string,
938
- encoding: string = "utf-8",
939
- sessionId?: string
940
- ): Promise<void> {
941
- try {
942
- const targetSessionId = sessionId || this.sessionId;
943
-
944
- const response = await this.doFetch(`/api/write/stream`, {
945
- body: JSON.stringify({
946
- content,
947
- encoding,
948
- path,
949
- sessionId: targetSessionId,
950
- } as WriteFileRequest),
951
- headers: {
952
- "Content-Type": "application/json",
953
- },
954
- method: "POST",
955
- });
956
-
957
- if (!response.ok) {
958
- const errorData = (await response.json().catch(() => ({}))) as {
959
- error?: string;
960
- };
961
- throw new Error(
962
- errorData.error || `HTTP error! status: ${response.status}`
963
- );
964
- }
965
-
966
- if (!response.body) {
967
- throw new Error("No response body for streaming request");
968
- }
969
-
970
- const reader = response.body.getReader();
971
- const decoder = new TextDecoder();
972
-
973
- try {
974
- while (true) {
975
- const { done, value } = await reader.read();
976
-
977
- if (done) {
978
- break;
979
- }
980
-
981
- const chunk = decoder.decode(value, { stream: true });
982
- const lines = chunk.split("\n");
983
-
984
- for (const line of lines) {
985
- if (line.startsWith("data: ")) {
986
- try {
987
- const eventData = line.slice(6); // Remove 'data: ' prefix
988
- const event: StreamEvent = JSON.parse(eventData);
989
-
990
- console.log(
991
- `[HTTP Client] Write file stream event: ${event.type}`
992
- );
993
- this.options.onStreamEvent?.(event);
994
-
995
- switch (event.type) {
996
- case "command_start":
997
- console.log(
998
- `[HTTP Client] Write file started: ${event.path}`
999
- );
1000
- this.options.onCommandStart?.("write", [
1001
- path,
1002
- content,
1003
- encoding,
1004
- ]);
1005
- break;
1006
-
1007
- case "output":
1008
- console.log(`[output] ${event.message}`);
1009
- this.options.onOutput?.("stdout", event.message!, "write");
1010
- break;
1011
-
1012
- case "command_complete":
1013
- console.log(
1014
- `[HTTP Client] Write file completed: ${event.path}, Success: ${event.success}`
1015
- );
1016
- this.options.onCommandComplete?.(
1017
- event.success!,
1018
- 0,
1019
- "",
1020
- "",
1021
- "write",
1022
- [path, content, encoding]
1023
- );
1024
- break;
1025
-
1026
- case "error":
1027
- console.error(
1028
- `[HTTP Client] Write file error: ${event.error}`
1029
- );
1030
- this.options.onError?.(event.error!, "write", [
1031
- path,
1032
- content,
1033
- encoding,
1034
- ]);
1035
- break;
1036
- }
1037
- } catch (parseError) {
1038
- console.warn(
1039
- "[HTTP Client] Failed to parse write file stream event:",
1040
- parseError
1041
- );
1042
- }
1043
- }
1044
- }
1045
- }
1046
- } finally {
1047
- reader.releaseLock();
1048
- }
1049
- } catch (error) {
1050
- console.error("[HTTP Client] Error in streaming write file:", error);
1051
- this.options.onError?.(
1052
- error instanceof Error ? error.message : "Unknown error",
1053
- "write",
1054
- [path, content, encoding]
1055
- );
1056
- throw error;
1057
- }
1058
- }
1059
481
 
1060
482
  async readFile(
1061
483
  path: string,
@@ -1098,120 +520,6 @@ export class HttpClient {
1098
520
  }
1099
521
  }
1100
522
 
1101
- async readFileStream(
1102
- path: string,
1103
- encoding: string = "utf-8",
1104
- sessionId?: string
1105
- ): Promise<void> {
1106
- try {
1107
- const targetSessionId = sessionId || this.sessionId;
1108
-
1109
- const response = await this.doFetch(`/api/read/stream`, {
1110
- body: JSON.stringify({
1111
- encoding,
1112
- path,
1113
- sessionId: targetSessionId,
1114
- } as ReadFileRequest),
1115
- headers: {
1116
- "Content-Type": "application/json",
1117
- },
1118
- method: "POST",
1119
- });
1120
-
1121
- if (!response.ok) {
1122
- const errorData = (await response.json().catch(() => ({}))) as {
1123
- error?: string;
1124
- };
1125
- throw new Error(
1126
- errorData.error || `HTTP error! status: ${response.status}`
1127
- );
1128
- }
1129
-
1130
- if (!response.body) {
1131
- throw new Error("No response body for streaming request");
1132
- }
1133
-
1134
- const reader = response.body.getReader();
1135
- const decoder = new TextDecoder();
1136
-
1137
- try {
1138
- while (true) {
1139
- const { done, value } = await reader.read();
1140
-
1141
- if (done) {
1142
- break;
1143
- }
1144
-
1145
- const chunk = decoder.decode(value, { stream: true });
1146
- const lines = chunk.split("\n");
1147
-
1148
- for (const line of lines) {
1149
- if (line.startsWith("data: ")) {
1150
- try {
1151
- const eventData = line.slice(6); // Remove 'data: ' prefix
1152
- const event: StreamEvent = JSON.parse(eventData);
1153
-
1154
- console.log(
1155
- `[HTTP Client] Read file stream event: ${event.type}`
1156
- );
1157
- this.options.onStreamEvent?.(event);
1158
-
1159
- switch (event.type) {
1160
- case "command_start":
1161
- console.log(
1162
- `[HTTP Client] Read file started: ${event.path}`
1163
- );
1164
- this.options.onCommandStart?.("read", [path, encoding]);
1165
- break;
1166
-
1167
- case "command_complete":
1168
- console.log(
1169
- `[HTTP Client] Read file completed: ${event.path
1170
- }, Success: ${event.success}, Content length: ${event.content?.length || 0
1171
- }`
1172
- );
1173
- this.options.onCommandComplete?.(
1174
- event.success!,
1175
- 0,
1176
- event.content || "",
1177
- "",
1178
- "read",
1179
- [path, encoding]
1180
- );
1181
- break;
1182
-
1183
- case "error":
1184
- console.error(
1185
- `[HTTP Client] Read file error: ${event.error}`
1186
- );
1187
- this.options.onError?.(event.error!, "read", [
1188
- path,
1189
- encoding,
1190
- ]);
1191
- break;
1192
- }
1193
- } catch (parseError) {
1194
- console.warn(
1195
- "[HTTP Client] Failed to parse read file stream event:",
1196
- parseError
1197
- );
1198
- }
1199
- }
1200
- }
1201
- }
1202
- } finally {
1203
- reader.releaseLock();
1204
- }
1205
- } catch (error) {
1206
- console.error("[HTTP Client] Error in streaming read file:", error);
1207
- this.options.onError?.(
1208
- error instanceof Error ? error.message : "Unknown error",
1209
- "read",
1210
- [path, encoding]
1211
- );
1212
- throw error;
1213
- }
1214
- }
1215
523
 
1216
524
  async deleteFile(
1217
525
  path: string,
@@ -1252,110 +560,6 @@ export class HttpClient {
1252
560
  }
1253
561
  }
1254
562
 
1255
- async deleteFileStream(path: string, sessionId?: string): Promise<void> {
1256
- try {
1257
- const targetSessionId = sessionId || this.sessionId;
1258
-
1259
- const response = await this.doFetch(`/api/delete/stream`, {
1260
- body: JSON.stringify({
1261
- path,
1262
- sessionId: targetSessionId,
1263
- } as DeleteFileRequest),
1264
- headers: {
1265
- "Content-Type": "application/json",
1266
- },
1267
- method: "POST",
1268
- });
1269
-
1270
- if (!response.ok) {
1271
- const errorData = (await response.json().catch(() => ({}))) as {
1272
- error?: string;
1273
- };
1274
- throw new Error(
1275
- errorData.error || `HTTP error! status: ${response.status}`
1276
- );
1277
- }
1278
-
1279
- if (!response.body) {
1280
- throw new Error("No response body for streaming request");
1281
- }
1282
-
1283
- const reader = response.body.getReader();
1284
- const decoder = new TextDecoder();
1285
-
1286
- try {
1287
- while (true) {
1288
- const { done, value } = await reader.read();
1289
-
1290
- if (done) {
1291
- break;
1292
- }
1293
-
1294
- const chunk = decoder.decode(value, { stream: true });
1295
- const lines = chunk.split("\n");
1296
-
1297
- for (const line of lines) {
1298
- if (line.startsWith("data: ")) {
1299
- try {
1300
- const eventData = line.slice(6); // Remove 'data: ' prefix
1301
- const event: StreamEvent = JSON.parse(eventData);
1302
-
1303
- console.log(
1304
- `[HTTP Client] Delete file stream event: ${event.type}`
1305
- );
1306
- this.options.onStreamEvent?.(event);
1307
-
1308
- switch (event.type) {
1309
- case "command_start":
1310
- console.log(
1311
- `[HTTP Client] Delete file started: ${event.path}`
1312
- );
1313
- this.options.onCommandStart?.("delete", [path]);
1314
- break;
1315
-
1316
- case "command_complete":
1317
- console.log(
1318
- `[HTTP Client] Delete file completed: ${event.path}, Success: ${event.success}`
1319
- );
1320
- this.options.onCommandComplete?.(
1321
- event.success!,
1322
- 0,
1323
- "",
1324
- "",
1325
- "delete",
1326
- [path]
1327
- );
1328
- break;
1329
-
1330
- case "error":
1331
- console.error(
1332
- `[HTTP Client] Delete file error: ${event.error}`
1333
- );
1334
- this.options.onError?.(event.error!, "delete", [path]);
1335
- break;
1336
- }
1337
- } catch (parseError) {
1338
- console.warn(
1339
- "[HTTP Client] Failed to parse delete file stream event:",
1340
- parseError
1341
- );
1342
- }
1343
- }
1344
- }
1345
- }
1346
- } finally {
1347
- reader.releaseLock();
1348
- }
1349
- } catch (error) {
1350
- console.error("[HTTP Client] Error in streaming delete file:", error);
1351
- this.options.onError?.(
1352
- error instanceof Error ? error.message : "Unknown error",
1353
- "delete",
1354
- [path]
1355
- );
1356
- throw error;
1357
- }
1358
- }
1359
563
 
1360
564
  async renameFile(
1361
565
  oldPath: string,
@@ -1398,118 +602,6 @@ export class HttpClient {
1398
602
  }
1399
603
  }
1400
604
 
1401
- async renameFileStream(
1402
- oldPath: string,
1403
- newPath: string,
1404
- sessionId?: string
1405
- ): Promise<void> {
1406
- try {
1407
- const targetSessionId = sessionId || this.sessionId;
1408
-
1409
- const response = await this.doFetch(`/api/rename/stream`, {
1410
- body: JSON.stringify({
1411
- newPath,
1412
- oldPath,
1413
- sessionId: targetSessionId,
1414
- } as RenameFileRequest),
1415
- headers: {
1416
- "Content-Type": "application/json",
1417
- },
1418
- method: "POST",
1419
- });
1420
-
1421
- if (!response.ok) {
1422
- const errorData = (await response.json().catch(() => ({}))) as {
1423
- error?: string;
1424
- };
1425
- throw new Error(
1426
- errorData.error || `HTTP error! status: ${response.status}`
1427
- );
1428
- }
1429
-
1430
- if (!response.body) {
1431
- throw new Error("No response body for streaming request");
1432
- }
1433
-
1434
- const reader = response.body.getReader();
1435
- const decoder = new TextDecoder();
1436
-
1437
- try {
1438
- while (true) {
1439
- const { done, value } = await reader.read();
1440
-
1441
- if (done) {
1442
- break;
1443
- }
1444
-
1445
- const chunk = decoder.decode(value, { stream: true });
1446
- const lines = chunk.split("\n");
1447
-
1448
- for (const line of lines) {
1449
- if (line.startsWith("data: ")) {
1450
- try {
1451
- const eventData = line.slice(6); // Remove 'data: ' prefix
1452
- const event: StreamEvent = JSON.parse(eventData);
1453
-
1454
- console.log(
1455
- `[HTTP Client] Rename file stream event: ${event.type}`
1456
- );
1457
- this.options.onStreamEvent?.(event);
1458
-
1459
- switch (event.type) {
1460
- case "command_start":
1461
- console.log(
1462
- `[HTTP Client] Rename file started: ${event.oldPath} -> ${event.newPath}`
1463
- );
1464
- this.options.onCommandStart?.("rename", [oldPath, newPath]);
1465
- break;
1466
-
1467
- case "command_complete":
1468
- console.log(
1469
- `[HTTP Client] Rename file completed: ${event.oldPath} -> ${event.newPath}, Success: ${event.success}`
1470
- );
1471
- this.options.onCommandComplete?.(
1472
- event.success!,
1473
- 0,
1474
- "",
1475
- "",
1476
- "rename",
1477
- [oldPath, newPath]
1478
- );
1479
- break;
1480
-
1481
- case "error":
1482
- console.error(
1483
- `[HTTP Client] Rename file error: ${event.error}`
1484
- );
1485
- this.options.onError?.(event.error!, "rename", [
1486
- oldPath,
1487
- newPath,
1488
- ]);
1489
- break;
1490
- }
1491
- } catch (parseError) {
1492
- console.warn(
1493
- "[HTTP Client] Failed to parse rename file stream event:",
1494
- parseError
1495
- );
1496
- }
1497
- }
1498
- }
1499
- }
1500
- } finally {
1501
- reader.releaseLock();
1502
- }
1503
- } catch (error) {
1504
- console.error("[HTTP Client] Error in streaming rename file:", error);
1505
- this.options.onError?.(
1506
- error instanceof Error ? error.message : "Unknown error",
1507
- "rename",
1508
- [oldPath, newPath]
1509
- );
1510
- throw error;
1511
- }
1512
- }
1513
605
 
1514
606
  async moveFile(
1515
607
  sourcePath: string,
@@ -1552,121 +644,6 @@ export class HttpClient {
1552
644
  }
1553
645
  }
1554
646
 
1555
- async moveFileStream(
1556
- sourcePath: string,
1557
- destinationPath: string,
1558
- sessionId?: string
1559
- ): Promise<void> {
1560
- try {
1561
- const targetSessionId = sessionId || this.sessionId;
1562
-
1563
- const response = await this.doFetch(`/api/move/stream`, {
1564
- body: JSON.stringify({
1565
- destinationPath,
1566
- sessionId: targetSessionId,
1567
- sourcePath,
1568
- } as MoveFileRequest),
1569
- headers: {
1570
- "Content-Type": "application/json",
1571
- },
1572
- method: "POST",
1573
- });
1574
-
1575
- if (!response.ok) {
1576
- const errorData = (await response.json().catch(() => ({}))) as {
1577
- error?: string;
1578
- };
1579
- throw new Error(
1580
- errorData.error || `HTTP error! status: ${response.status}`
1581
- );
1582
- }
1583
-
1584
- if (!response.body) {
1585
- throw new Error("No response body for streaming request");
1586
- }
1587
-
1588
- const reader = response.body.getReader();
1589
- const decoder = new TextDecoder();
1590
-
1591
- try {
1592
- while (true) {
1593
- const { done, value } = await reader.read();
1594
-
1595
- if (done) {
1596
- break;
1597
- }
1598
-
1599
- const chunk = decoder.decode(value, { stream: true });
1600
- const lines = chunk.split("\n");
1601
-
1602
- for (const line of lines) {
1603
- if (line.startsWith("data: ")) {
1604
- try {
1605
- const eventData = line.slice(6); // Remove 'data: ' prefix
1606
- const event: StreamEvent = JSON.parse(eventData);
1607
-
1608
- console.log(
1609
- `[HTTP Client] Move file stream event: ${event.type}`
1610
- );
1611
- this.options.onStreamEvent?.(event);
1612
-
1613
- switch (event.type) {
1614
- case "command_start":
1615
- console.log(
1616
- `[HTTP Client] Move file started: ${event.sourcePath} -> ${event.destinationPath}`
1617
- );
1618
- this.options.onCommandStart?.("move", [
1619
- sourcePath,
1620
- destinationPath,
1621
- ]);
1622
- break;
1623
-
1624
- case "command_complete":
1625
- console.log(
1626
- `[HTTP Client] Move file completed: ${event.sourcePath} -> ${event.destinationPath}, Success: ${event.success}`
1627
- );
1628
- this.options.onCommandComplete?.(
1629
- event.success!,
1630
- 0,
1631
- "",
1632
- "",
1633
- "move",
1634
- [sourcePath, destinationPath]
1635
- );
1636
- break;
1637
-
1638
- case "error":
1639
- console.error(
1640
- `[HTTP Client] Move file error: ${event.error}`
1641
- );
1642
- this.options.onError?.(event.error!, "move", [
1643
- sourcePath,
1644
- destinationPath,
1645
- ]);
1646
- break;
1647
- }
1648
- } catch (parseError) {
1649
- console.warn(
1650
- "[HTTP Client] Failed to parse move file stream event:",
1651
- parseError
1652
- );
1653
- }
1654
- }
1655
- }
1656
- }
1657
- } finally {
1658
- reader.releaseLock();
1659
- }
1660
- } catch (error) {
1661
- console.error("[HTTP Client] Error in streaming move file:", error);
1662
- this.options.onError?.(
1663
- error instanceof Error ? error.message : "Unknown error",
1664
- "move",
1665
- [sourcePath, destinationPath]
1666
- );
1667
- throw error;
1668
- }
1669
- }
1670
647
 
1671
648
  async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
1672
649
  try {
@@ -1823,267 +800,239 @@ export class HttpClient {
1823
800
  clearSession(): void {
1824
801
  this.sessionId = null;
1825
802
  }
1826
- }
1827
803
 
1828
- // Example usage and utility functions
1829
- export function createClient(options?: HttpClientOptions): HttpClient {
1830
- return new HttpClient(options);
1831
- }
804
+ // Process management methods
805
+ async startProcess(
806
+ command: string,
807
+ options?: {
808
+ processId?: string;
809
+ sessionId?: string;
810
+ timeout?: number;
811
+ env?: Record<string, string>;
812
+ cwd?: string;
813
+ encoding?: string;
814
+ autoCleanup?: boolean;
815
+ }
816
+ ): Promise<StartProcessResponse> {
817
+ try {
818
+ const targetSessionId = options?.sessionId || this.sessionId;
1832
819
 
1833
- // Convenience function for quick command execution
1834
- export async function quickExecute(
1835
- command: string,
1836
- args: string[] = [],
1837
- options?: HttpClientOptions
1838
- ): Promise<ExecuteResponse> {
1839
- const client = createClient(options);
1840
- await client.createSession();
1841
-
1842
- try {
1843
- return await client.execute(command, args);
1844
- } finally {
1845
- client.clearSession();
1846
- }
1847
- }
820
+ const response = await this.doFetch("/api/process/start", {
821
+ body: JSON.stringify({
822
+ command,
823
+ options: {
824
+ ...options,
825
+ sessionId: targetSessionId,
826
+ },
827
+ } as StartProcessRequest),
828
+ headers: {
829
+ "Content-Type": "application/json",
830
+ },
831
+ method: "POST",
832
+ });
1848
833
 
1849
- // Convenience function for quick streaming command execution
1850
- export async function quickExecuteStream(
1851
- command: string,
1852
- args: string[] = [],
1853
- options?: HttpClientOptions
1854
- ): Promise<void> {
1855
- const client = createClient(options);
1856
- await client.createSession();
1857
-
1858
- try {
1859
- await client.executeStream(command, args);
1860
- } finally {
1861
- client.clearSession();
1862
- }
1863
- }
834
+ if (!response.ok) {
835
+ const errorData = (await response.json().catch(() => ({}))) as {
836
+ error?: string;
837
+ };
838
+ throw new Error(
839
+ errorData.error || `HTTP error! status: ${response.status}`
840
+ );
841
+ }
1864
842
 
1865
- // Convenience function for quick git checkout
1866
- export async function quickGitCheckout(
1867
- repoUrl: string,
1868
- branch: string = "main",
1869
- targetDir?: string,
1870
- options?: HttpClientOptions
1871
- ): Promise<GitCheckoutResponse> {
1872
- const client = createClient(options);
1873
- await client.createSession();
1874
-
1875
- try {
1876
- return await client.gitCheckout(repoUrl, branch, targetDir);
1877
- } finally {
1878
- client.clearSession();
1879
- }
1880
- }
843
+ const data: StartProcessResponse = await response.json();
844
+ console.log(
845
+ `[HTTP Client] Process started: ${command}, ID: ${data.process.id}`
846
+ );
1881
847
 
1882
- // Convenience function for quick directory creation
1883
- export async function quickMkdir(
1884
- path: string,
1885
- recursive: boolean = false,
1886
- options?: HttpClientOptions
1887
- ): Promise<MkdirResponse> {
1888
- const client = createClient(options);
1889
- await client.createSession();
1890
-
1891
- try {
1892
- return await client.mkdir(path, recursive);
1893
- } finally {
1894
- client.clearSession();
848
+ return data;
849
+ } catch (error) {
850
+ console.error("[HTTP Client] Error starting process:", error);
851
+ throw error;
852
+ }
1895
853
  }
1896
- }
1897
854
 
1898
- // Convenience function for quick streaming git checkout
1899
- export async function quickGitCheckoutStream(
1900
- repoUrl: string,
1901
- branch: string = "main",
1902
- targetDir?: string,
1903
- options?: HttpClientOptions
1904
- ): Promise<void> {
1905
- const client = createClient(options);
1906
- await client.createSession();
1907
-
1908
- try {
1909
- await client.gitCheckoutStream(repoUrl, branch, targetDir);
1910
- } finally {
1911
- client.clearSession();
1912
- }
1913
- }
855
+ async listProcesses(): Promise<ListProcessesResponse> {
856
+ try {
857
+ const response = await this.doFetch("/api/process/list", {
858
+ headers: {
859
+ "Content-Type": "application/json",
860
+ },
861
+ method: "GET",
862
+ });
1914
863
 
1915
- // Convenience function for quick streaming directory creation
1916
- export async function quickMkdirStream(
1917
- path: string,
1918
- recursive: boolean = false,
1919
- options?: HttpClientOptions
1920
- ): Promise<void> {
1921
- const client = createClient(options);
1922
- await client.createSession();
1923
-
1924
- try {
1925
- await client.mkdirStream(path, recursive);
1926
- } finally {
1927
- client.clearSession();
1928
- }
1929
- }
864
+ if (!response.ok) {
865
+ const errorData = (await response.json().catch(() => ({}))) as {
866
+ error?: string;
867
+ };
868
+ throw new Error(
869
+ errorData.error || `HTTP error! status: ${response.status}`
870
+ );
871
+ }
1930
872
 
1931
- // Convenience function for quick file writing
1932
- export async function quickWriteFile(
1933
- path: string,
1934
- content: string,
1935
- encoding: string = "utf-8",
1936
- options?: HttpClientOptions
1937
- ): Promise<WriteFileResponse> {
1938
- const client = createClient(options);
1939
- await client.createSession();
1940
-
1941
- try {
1942
- return await client.writeFile(path, content, encoding);
1943
- } finally {
1944
- client.clearSession();
1945
- }
1946
- }
873
+ const data: ListProcessesResponse = await response.json();
874
+ console.log(
875
+ `[HTTP Client] Listed ${data.processes.length} processes`
876
+ );
1947
877
 
1948
- // Convenience function for quick streaming file writing
1949
- export async function quickWriteFileStream(
1950
- path: string,
1951
- content: string,
1952
- encoding: string = "utf-8",
1953
- options?: HttpClientOptions
1954
- ): Promise<void> {
1955
- const client = createClient(options);
1956
- await client.createSession();
1957
-
1958
- try {
1959
- await client.writeFileStream(path, content, encoding);
1960
- } finally {
1961
- client.clearSession();
878
+ return data;
879
+ } catch (error) {
880
+ console.error("[HTTP Client] Error listing processes:", error);
881
+ throw error;
882
+ }
1962
883
  }
1963
- }
1964
884
 
1965
- // Convenience function for quick file reading
1966
- export async function quickReadFile(
1967
- path: string,
1968
- encoding: string = "utf-8",
1969
- options?: HttpClientOptions
1970
- ): Promise<ReadFileResponse> {
1971
- const client = createClient(options);
1972
- await client.createSession();
1973
-
1974
- try {
1975
- return await client.readFile(path, encoding);
1976
- } finally {
1977
- client.clearSession();
1978
- }
1979
- }
885
+ async getProcess(processId: string): Promise<GetProcessResponse> {
886
+ try {
887
+ const response = await this.doFetch(`/api/process/${processId}`, {
888
+ headers: {
889
+ "Content-Type": "application/json",
890
+ },
891
+ method: "GET",
892
+ });
1980
893
 
1981
- // Convenience function for quick streaming file reading
1982
- export async function quickReadFileStream(
1983
- path: string,
1984
- encoding: string = "utf-8",
1985
- options?: HttpClientOptions
1986
- ): Promise<void> {
1987
- const client = createClient(options);
1988
- await client.createSession();
1989
-
1990
- try {
1991
- await client.readFileStream(path, encoding);
1992
- } finally {
1993
- client.clearSession();
1994
- }
1995
- }
894
+ if (!response.ok) {
895
+ const errorData = (await response.json().catch(() => ({}))) as {
896
+ error?: string;
897
+ };
898
+ throw new Error(
899
+ errorData.error || `HTTP error! status: ${response.status}`
900
+ );
901
+ }
1996
902
 
1997
- // Convenience function for quick file deletion
1998
- export async function quickDeleteFile(
1999
- path: string,
2000
- options?: HttpClientOptions
2001
- ): Promise<DeleteFileResponse> {
2002
- const client = createClient(options);
2003
- await client.createSession();
2004
-
2005
- try {
2006
- return await client.deleteFile(path);
2007
- } finally {
2008
- client.clearSession();
2009
- }
2010
- }
903
+ const data: GetProcessResponse = await response.json();
904
+ console.log(
905
+ `[HTTP Client] Got process ${processId}: ${data.process?.status || 'not found'}`
906
+ );
2011
907
 
2012
- // Convenience function for quick streaming file deletion
2013
- export async function quickDeleteFileStream(
2014
- path: string,
2015
- options?: HttpClientOptions
2016
- ): Promise<void> {
2017
- const client = createClient(options);
2018
- await client.createSession();
2019
-
2020
- try {
2021
- await client.deleteFileStream(path);
2022
- } finally {
2023
- client.clearSession();
908
+ return data;
909
+ } catch (error) {
910
+ console.error("[HTTP Client] Error getting process:", error);
911
+ throw error;
912
+ }
2024
913
  }
2025
- }
2026
914
 
2027
- // Convenience function for quick file renaming
2028
- export async function quickRenameFile(
2029
- oldPath: string,
2030
- newPath: string,
2031
- options?: HttpClientOptions
2032
- ): Promise<RenameFileResponse> {
2033
- const client = createClient(options);
2034
- await client.createSession();
2035
-
2036
- try {
2037
- return await client.renameFile(oldPath, newPath);
2038
- } finally {
2039
- client.clearSession();
915
+ async killProcess(processId: string): Promise<{ success: boolean; message: string }> {
916
+ try {
917
+ const response = await this.doFetch(`/api/process/${processId}`, {
918
+ headers: {
919
+ "Content-Type": "application/json",
920
+ },
921
+ method: "DELETE",
922
+ });
923
+
924
+ if (!response.ok) {
925
+ const errorData = (await response.json().catch(() => ({}))) as {
926
+ error?: string;
927
+ };
928
+ throw new Error(
929
+ errorData.error || `HTTP error! status: ${response.status}`
930
+ );
931
+ }
932
+
933
+ const data = await response.json() as { success: boolean; message: string };
934
+ console.log(
935
+ `[HTTP Client] Killed process ${processId}`
936
+ );
937
+
938
+ return data;
939
+ } catch (error) {
940
+ console.error("[HTTP Client] Error killing process:", error);
941
+ throw error;
942
+ }
2040
943
  }
2041
- }
2042
944
 
2043
- // Convenience function for quick streaming file renaming
2044
- export async function quickRenameFileStream(
2045
- oldPath: string,
2046
- newPath: string,
2047
- options?: HttpClientOptions
2048
- ): Promise<void> {
2049
- const client = createClient(options);
2050
- await client.createSession();
2051
-
2052
- try {
2053
- await client.renameFileStream(oldPath, newPath);
2054
- } finally {
2055
- client.clearSession();
945
+ async killAllProcesses(): Promise<{ success: boolean; killedCount: number; message: string }> {
946
+ try {
947
+ const response = await this.doFetch("/api/process/kill-all", {
948
+ headers: {
949
+ "Content-Type": "application/json",
950
+ },
951
+ method: "DELETE",
952
+ });
953
+
954
+ if (!response.ok) {
955
+ const errorData = (await response.json().catch(() => ({}))) as {
956
+ error?: string;
957
+ };
958
+ throw new Error(
959
+ errorData.error || `HTTP error! status: ${response.status}`
960
+ );
961
+ }
962
+
963
+ const data = await response.json() as { success: boolean; killedCount: number; message: string };
964
+ console.log(
965
+ `[HTTP Client] Killed ${data.killedCount} processes`
966
+ );
967
+
968
+ return data;
969
+ } catch (error) {
970
+ console.error("[HTTP Client] Error killing all processes:", error);
971
+ throw error;
972
+ }
2056
973
  }
2057
- }
2058
974
 
2059
- // Convenience function for quick file moving
2060
- export async function quickMoveFile(
2061
- sourcePath: string,
2062
- destinationPath: string,
2063
- options?: HttpClientOptions
2064
- ): Promise<MoveFileResponse> {
2065
- const client = createClient(options);
2066
- await client.createSession();
2067
-
2068
- try {
2069
- return await client.moveFile(sourcePath, destinationPath);
2070
- } finally {
2071
- client.clearSession();
975
+ async getProcessLogs(processId: string): Promise<GetProcessLogsResponse> {
976
+ try {
977
+ const response = await this.doFetch(`/api/process/${processId}/logs`, {
978
+ headers: {
979
+ "Content-Type": "application/json",
980
+ },
981
+ method: "GET",
982
+ });
983
+
984
+ if (!response.ok) {
985
+ const errorData = (await response.json().catch(() => ({}))) as {
986
+ error?: string;
987
+ };
988
+ throw new Error(
989
+ errorData.error || `HTTP error! status: ${response.status}`
990
+ );
991
+ }
992
+
993
+ const data: GetProcessLogsResponse = await response.json();
994
+ console.log(
995
+ `[HTTP Client] Got logs for process ${processId}`
996
+ );
997
+
998
+ return data;
999
+ } catch (error) {
1000
+ console.error("[HTTP Client] Error getting process logs:", error);
1001
+ throw error;
1002
+ }
2072
1003
  }
2073
- }
2074
1004
 
2075
- // Convenience function for quick streaming file moving
2076
- export async function quickMoveFileStream(
2077
- sourcePath: string,
2078
- destinationPath: string,
2079
- options?: HttpClientOptions
2080
- ): Promise<void> {
2081
- const client = createClient(options);
2082
- await client.createSession();
2083
-
2084
- try {
2085
- await client.moveFileStream(sourcePath, destinationPath);
2086
- } finally {
2087
- client.clearSession();
1005
+ async streamProcessLogs(processId: string): Promise<ReadableStream<Uint8Array>> {
1006
+ try {
1007
+ const response = await this.doFetch(`/api/process/${processId}/stream`, {
1008
+ headers: {
1009
+ "Accept": "text/event-stream",
1010
+ "Cache-Control": "no-cache",
1011
+ },
1012
+ method: "GET",
1013
+ });
1014
+
1015
+ if (!response.ok) {
1016
+ const errorData = (await response.json().catch(() => ({}))) as {
1017
+ error?: string;
1018
+ };
1019
+ throw new Error(
1020
+ errorData.error || `HTTP error! status: ${response.status}`
1021
+ );
1022
+ }
1023
+
1024
+ if (!response.body) {
1025
+ throw new Error("No response body for streaming request");
1026
+ }
1027
+
1028
+ console.log(
1029
+ `[HTTP Client] Started streaming logs for process ${processId}`
1030
+ );
1031
+
1032
+ return response.body;
1033
+ } catch (error) {
1034
+ console.error("[HTTP Client] Error streaming process logs:", error);
1035
+ throw error;
1036
+ }
2088
1037
  }
2089
1038
  }