@cloudflare/sandbox 0.0.0-f5fcd52 → 0.0.0-fb3c9c2
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/CHANGELOG.md +137 -0
- package/Dockerfile +47 -36
- package/README.md +805 -24
- package/container_src/bun.lock +122 -0
- package/container_src/circuit-breaker.ts +121 -0
- package/container_src/control-process.ts +784 -0
- package/container_src/handler/exec.ts +185 -0
- package/container_src/handler/file.ts +406 -0
- package/container_src/handler/git.ts +130 -0
- package/container_src/handler/ports.ts +314 -0
- package/container_src/handler/process.ts +568 -0
- package/container_src/handler/session.ts +92 -0
- package/container_src/index.ts +411 -3006
- package/container_src/isolation.ts +1038 -0
- package/container_src/jupyter-server.ts +579 -0
- package/container_src/jupyter-service.ts +461 -0
- package/container_src/jupyter_config.py +48 -0
- package/container_src/mime-processor.ts +255 -0
- package/container_src/package.json +9 -0
- package/container_src/shell-escape.ts +42 -0
- package/container_src/startup.sh +84 -0
- package/container_src/types.ts +131 -0
- package/package.json +5 -9
- package/src/client.ts +333 -1413
- package/src/errors.ts +218 -0
- package/src/index.ts +60 -10
- package/src/interpreter-types.ts +383 -0
- package/src/interpreter.ts +150 -0
- package/src/jupyter-client.ts +349 -0
- package/src/request-handler.ts +69 -20
- package/src/sandbox.ts +594 -105
- package/src/security.ts +113 -0
- package/src/sse-parser.ts +147 -0
- package/src/types.ts +502 -0
- package/tsconfig.json +1 -1
- package/tests/client.example.ts +0 -308
- package/tests/connection-test.ts +0 -81
- package/tests/simple-test.ts +0 -81
- package/tests/test1.ts +0 -281
- package/tests/test2.ts +0 -929
package/src/client.ts
CHANGED
|
@@ -1,37 +1,23 @@
|
|
|
1
|
+
import type { ExecuteRequest } from "../container_src/types";
|
|
1
2
|
import type { Sandbox } from "./index";
|
|
3
|
+
import type {
|
|
4
|
+
BaseExecOptions,
|
|
5
|
+
DeleteFileResponse,
|
|
6
|
+
ExecuteResponse,
|
|
7
|
+
GetProcessLogsResponse,
|
|
8
|
+
GetProcessResponse,
|
|
9
|
+
GitCheckoutResponse,
|
|
10
|
+
ListFilesResponse,
|
|
11
|
+
ListProcessesResponse,
|
|
12
|
+
MkdirResponse,
|
|
13
|
+
MoveFileResponse,
|
|
14
|
+
ReadFileResponse,
|
|
15
|
+
RenameFileResponse,
|
|
16
|
+
StartProcessRequest,
|
|
17
|
+
StartProcessResponse,
|
|
18
|
+
WriteFileResponse,
|
|
19
|
+
} from "./types";
|
|
2
20
|
|
|
3
|
-
interface ExecuteRequest {
|
|
4
|
-
command: string;
|
|
5
|
-
args?: string[];
|
|
6
|
-
sessionId?: string;
|
|
7
|
-
background?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface ExecuteResponse {
|
|
11
|
-
success: boolean;
|
|
12
|
-
stdout: string;
|
|
13
|
-
stderr: string;
|
|
14
|
-
exitCode: number;
|
|
15
|
-
command: string;
|
|
16
|
-
args: string[];
|
|
17
|
-
timestamp: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface SessionResponse {
|
|
21
|
-
sessionId: string;
|
|
22
|
-
message: string;
|
|
23
|
-
timestamp: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface SessionListResponse {
|
|
27
|
-
sessions: Array<{
|
|
28
|
-
sessionId: string;
|
|
29
|
-
hasActiveProcess: boolean;
|
|
30
|
-
createdAt: string;
|
|
31
|
-
}>;
|
|
32
|
-
count: number;
|
|
33
|
-
timestamp: string;
|
|
34
|
-
}
|
|
35
21
|
|
|
36
22
|
interface CommandsResponse {
|
|
37
23
|
availableCommands: string[];
|
|
@@ -42,104 +28,62 @@ interface GitCheckoutRequest {
|
|
|
42
28
|
repoUrl: string;
|
|
43
29
|
branch?: string;
|
|
44
30
|
targetDir?: string;
|
|
45
|
-
sessionId
|
|
31
|
+
sessionId: string;
|
|
46
32
|
}
|
|
47
33
|
|
|
48
|
-
export interface GitCheckoutResponse {
|
|
49
|
-
success: boolean;
|
|
50
|
-
stdout: string;
|
|
51
|
-
stderr: string;
|
|
52
|
-
exitCode: number;
|
|
53
|
-
repoUrl: string;
|
|
54
|
-
branch: string;
|
|
55
|
-
targetDir: string;
|
|
56
|
-
timestamp: string;
|
|
57
|
-
}
|
|
58
34
|
|
|
59
35
|
interface MkdirRequest {
|
|
60
36
|
path: string;
|
|
61
37
|
recursive?: boolean;
|
|
62
|
-
sessionId
|
|
38
|
+
sessionId: string;
|
|
63
39
|
}
|
|
64
40
|
|
|
65
|
-
export interface MkdirResponse {
|
|
66
|
-
success: boolean;
|
|
67
|
-
stdout: string;
|
|
68
|
-
stderr: string;
|
|
69
|
-
exitCode: number;
|
|
70
|
-
path: string;
|
|
71
|
-
recursive: boolean;
|
|
72
|
-
timestamp: string;
|
|
73
|
-
}
|
|
74
41
|
|
|
75
42
|
interface WriteFileRequest {
|
|
76
43
|
path: string;
|
|
77
44
|
content: string;
|
|
78
45
|
encoding?: string;
|
|
79
|
-
sessionId
|
|
46
|
+
sessionId: string;
|
|
80
47
|
}
|
|
81
48
|
|
|
82
|
-
export interface WriteFileResponse {
|
|
83
|
-
success: boolean;
|
|
84
|
-
exitCode: number;
|
|
85
|
-
path: string;
|
|
86
|
-
timestamp: string;
|
|
87
|
-
}
|
|
88
49
|
|
|
89
50
|
interface ReadFileRequest {
|
|
90
51
|
path: string;
|
|
91
52
|
encoding?: string;
|
|
92
|
-
sessionId
|
|
53
|
+
sessionId: string;
|
|
93
54
|
}
|
|
94
55
|
|
|
95
|
-
export interface ReadFileResponse {
|
|
96
|
-
success: boolean;
|
|
97
|
-
exitCode: number;
|
|
98
|
-
path: string;
|
|
99
|
-
content: string;
|
|
100
|
-
timestamp: string;
|
|
101
|
-
}
|
|
102
56
|
|
|
103
57
|
interface DeleteFileRequest {
|
|
104
58
|
path: string;
|
|
105
|
-
sessionId
|
|
59
|
+
sessionId: string;
|
|
106
60
|
}
|
|
107
61
|
|
|
108
|
-
export interface DeleteFileResponse {
|
|
109
|
-
success: boolean;
|
|
110
|
-
exitCode: number;
|
|
111
|
-
path: string;
|
|
112
|
-
timestamp: string;
|
|
113
|
-
}
|
|
114
62
|
|
|
115
63
|
interface RenameFileRequest {
|
|
116
64
|
oldPath: string;
|
|
117
65
|
newPath: string;
|
|
118
|
-
sessionId
|
|
66
|
+
sessionId: string;
|
|
119
67
|
}
|
|
120
68
|
|
|
121
|
-
export interface RenameFileResponse {
|
|
122
|
-
success: boolean;
|
|
123
|
-
exitCode: number;
|
|
124
|
-
oldPath: string;
|
|
125
|
-
newPath: string;
|
|
126
|
-
timestamp: string;
|
|
127
|
-
}
|
|
128
69
|
|
|
129
70
|
interface MoveFileRequest {
|
|
130
71
|
sourcePath: string;
|
|
131
72
|
destinationPath: string;
|
|
132
|
-
sessionId
|
|
73
|
+
sessionId: string;
|
|
133
74
|
}
|
|
134
75
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
76
|
+
|
|
77
|
+
interface ListFilesRequest {
|
|
78
|
+
path: string;
|
|
79
|
+
options?: {
|
|
80
|
+
recursive?: boolean;
|
|
81
|
+
includeHidden?: boolean;
|
|
82
|
+
};
|
|
83
|
+
sessionId: string;
|
|
141
84
|
}
|
|
142
85
|
|
|
86
|
+
|
|
143
87
|
interface PreviewInfo {
|
|
144
88
|
url: string;
|
|
145
89
|
port: number;
|
|
@@ -176,32 +120,11 @@ interface PingResponse {
|
|
|
176
120
|
timestamp: string;
|
|
177
121
|
}
|
|
178
122
|
|
|
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
123
|
interface HttpClientOptions {
|
|
201
124
|
stub?: Sandbox;
|
|
202
125
|
baseUrl?: string;
|
|
203
126
|
port?: number;
|
|
204
|
-
onCommandStart?: (command: string
|
|
127
|
+
onCommandStart?: (command: string) => void;
|
|
205
128
|
onOutput?: (
|
|
206
129
|
stream: "stdout" | "stderr",
|
|
207
130
|
data: string,
|
|
@@ -212,17 +135,14 @@ interface HttpClientOptions {
|
|
|
212
135
|
exitCode: number,
|
|
213
136
|
stdout: string,
|
|
214
137
|
stderr: string,
|
|
215
|
-
command: string
|
|
216
|
-
args: string[]
|
|
138
|
+
command: string
|
|
217
139
|
) => void;
|
|
218
|
-
onError?: (error: string, command?: string
|
|
219
|
-
onStreamEvent?: (event: StreamEvent) => void;
|
|
140
|
+
onError?: (error: string, command?: string) => void;
|
|
220
141
|
}
|
|
221
142
|
|
|
222
143
|
export class HttpClient {
|
|
223
144
|
private baseUrl: string;
|
|
224
145
|
private options: HttpClientOptions;
|
|
225
|
-
private sessionId: string | null = null;
|
|
226
146
|
|
|
227
147
|
constructor(options: HttpClientOptions = {}) {
|
|
228
148
|
this.options = {
|
|
@@ -231,7 +151,7 @@ export class HttpClient {
|
|
|
231
151
|
this.baseUrl = this.options.baseUrl!;
|
|
232
152
|
}
|
|
233
153
|
|
|
234
|
-
|
|
154
|
+
protected async doFetch(
|
|
235
155
|
path: string,
|
|
236
156
|
options?: RequestInit
|
|
237
157
|
): Promise<Response> {
|
|
@@ -271,123 +191,53 @@ export class HttpClient {
|
|
|
271
191
|
throw error;
|
|
272
192
|
}
|
|
273
193
|
}
|
|
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
194
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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> {
|
|
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 }> {
|
|
327
201
|
try {
|
|
328
202
|
const response = await this.doFetch(`/api/session/create`, {
|
|
329
|
-
headers: {
|
|
330
|
-
"Content-Type": "application/json",
|
|
331
|
-
},
|
|
332
203
|
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
204
|
headers: {
|
|
353
205
|
"Content-Type": "application/json",
|
|
354
206
|
},
|
|
355
|
-
|
|
207
|
+
body: JSON.stringify(options),
|
|
356
208
|
});
|
|
357
209
|
|
|
358
210
|
if (!response.ok) {
|
|
359
|
-
|
|
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
|
+
);
|
|
360
217
|
}
|
|
361
218
|
|
|
362
|
-
const data
|
|
363
|
-
console.log(`[HTTP Client]
|
|
219
|
+
const data = await response.json() as { success: boolean; id: string; message: string };
|
|
220
|
+
console.log(`[HTTP Client] Session created: ${options.id}`);
|
|
364
221
|
return data;
|
|
365
222
|
} catch (error) {
|
|
366
|
-
console.error("[HTTP Client] Error
|
|
223
|
+
console.error("[HTTP Client] Error creating session:", error);
|
|
367
224
|
throw error;
|
|
368
225
|
}
|
|
369
226
|
}
|
|
370
227
|
|
|
371
|
-
async
|
|
228
|
+
async exec(
|
|
229
|
+
sessionId: string,
|
|
372
230
|
command: string,
|
|
373
|
-
|
|
374
|
-
sessionId?: string,
|
|
375
|
-
background: boolean = false,
|
|
231
|
+
options?: Pick<BaseExecOptions, "cwd" | "env">
|
|
376
232
|
): Promise<ExecuteResponse> {
|
|
377
233
|
try {
|
|
378
|
-
|
|
379
|
-
|
|
234
|
+
// Always use session-specific endpoint
|
|
380
235
|
const response = await this.doFetch(`/api/execute`, {
|
|
381
|
-
|
|
382
|
-
args,
|
|
383
|
-
command,
|
|
384
|
-
background,
|
|
385
|
-
sessionId: targetSessionId,
|
|
386
|
-
} as ExecuteRequest),
|
|
236
|
+
method: "POST",
|
|
387
237
|
headers: {
|
|
388
238
|
"Content-Type": "application/json",
|
|
389
239
|
},
|
|
390
|
-
|
|
240
|
+
body: JSON.stringify({ id: sessionId, command }),
|
|
391
241
|
});
|
|
392
242
|
|
|
393
243
|
if (!response.ok) {
|
|
@@ -395,57 +245,57 @@ export class HttpClient {
|
|
|
395
245
|
error?: string;
|
|
396
246
|
};
|
|
397
247
|
throw new Error(
|
|
398
|
-
errorData.error || `
|
|
248
|
+
errorData.error || `Failed to execute in session: ${response.status}`
|
|
399
249
|
);
|
|
400
250
|
}
|
|
401
251
|
|
|
402
|
-
const data
|
|
252
|
+
const data = await response.json() as { stdout: string; stderr: string; exitCode: number; success: boolean };
|
|
403
253
|
console.log(
|
|
404
|
-
`[HTTP Client] Command executed
|
|
254
|
+
`[HTTP Client] Command executed in session ${sessionId}: ${command}`
|
|
405
255
|
);
|
|
256
|
+
|
|
257
|
+
// Convert to ExecuteResponse format for consistency
|
|
258
|
+
const executeResponse: ExecuteResponse = {
|
|
259
|
+
...data,
|
|
260
|
+
command,
|
|
261
|
+
timestamp: new Date().toISOString()
|
|
262
|
+
};
|
|
406
263
|
|
|
407
264
|
// Call the callback if provided
|
|
408
265
|
this.options.onCommandComplete?.(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
data.args
|
|
266
|
+
executeResponse.success,
|
|
267
|
+
executeResponse.exitCode,
|
|
268
|
+
executeResponse.stdout,
|
|
269
|
+
executeResponse.stderr,
|
|
270
|
+
executeResponse.command
|
|
415
271
|
);
|
|
416
272
|
|
|
417
|
-
return
|
|
273
|
+
return executeResponse;
|
|
418
274
|
} catch (error) {
|
|
419
|
-
console.error("[HTTP Client] Error executing
|
|
275
|
+
console.error("[HTTP Client] Error executing in session:", error);
|
|
420
276
|
this.options.onError?.(
|
|
421
277
|
error instanceof Error ? error.message : "Unknown error",
|
|
422
|
-
command
|
|
423
|
-
args
|
|
278
|
+
command
|
|
424
279
|
);
|
|
425
280
|
throw error;
|
|
426
281
|
}
|
|
427
282
|
}
|
|
428
283
|
|
|
429
|
-
async
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
background: boolean = false
|
|
434
|
-
): Promise<void> {
|
|
284
|
+
async execStream(
|
|
285
|
+
sessionId: string,
|
|
286
|
+
command: string
|
|
287
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
435
288
|
try {
|
|
436
|
-
|
|
437
|
-
|
|
289
|
+
// Always use session-specific streaming endpoint
|
|
438
290
|
const response = await this.doFetch(`/api/execute/stream`, {
|
|
439
|
-
|
|
440
|
-
args,
|
|
441
|
-
command,
|
|
442
|
-
background,
|
|
443
|
-
sessionId: targetSessionId,
|
|
444
|
-
}),
|
|
291
|
+
method: "POST",
|
|
445
292
|
headers: {
|
|
446
293
|
"Content-Type": "application/json",
|
|
447
294
|
},
|
|
448
|
-
|
|
295
|
+
body: JSON.stringify({
|
|
296
|
+
id: sessionId,
|
|
297
|
+
command
|
|
298
|
+
}),
|
|
449
299
|
});
|
|
450
300
|
|
|
451
301
|
if (!response.ok) {
|
|
@@ -453,121 +303,37 @@ export class HttpClient {
|
|
|
453
303
|
error?: string;
|
|
454
304
|
};
|
|
455
305
|
throw new Error(
|
|
456
|
-
errorData.error || `
|
|
306
|
+
errorData.error || `Failed to stream execute in session: ${response.status}`
|
|
457
307
|
);
|
|
458
308
|
}
|
|
459
309
|
|
|
460
310
|
if (!response.body) {
|
|
461
|
-
throw new Error("No response body for streaming
|
|
311
|
+
throw new Error("No response body for streaming execution");
|
|
462
312
|
}
|
|
463
313
|
|
|
464
|
-
|
|
465
|
-
|
|
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
|
|
314
|
+
console.log(
|
|
315
|
+
`[HTTP Client] Started streaming command in session ${sessionId}: ${command}`
|
|
551
316
|
);
|
|
317
|
+
return response.body;
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error("[HTTP Client] Error streaming execute in session:", error);
|
|
552
320
|
throw error;
|
|
553
321
|
}
|
|
554
322
|
}
|
|
555
323
|
|
|
556
324
|
async gitCheckout(
|
|
557
325
|
repoUrl: string,
|
|
326
|
+
sessionId: string,
|
|
558
327
|
branch: string = "main",
|
|
559
|
-
targetDir?: string
|
|
560
|
-
sessionId?: string
|
|
328
|
+
targetDir?: string
|
|
561
329
|
): Promise<GitCheckoutResponse> {
|
|
562
330
|
try {
|
|
563
|
-
const targetSessionId = sessionId || this.sessionId;
|
|
564
|
-
|
|
565
331
|
const response = await this.doFetch(`/api/git/checkout`, {
|
|
566
332
|
body: JSON.stringify({
|
|
567
333
|
branch,
|
|
568
334
|
repoUrl,
|
|
569
|
-
sessionId: targetSessionId,
|
|
570
335
|
targetDir,
|
|
336
|
+
sessionId,
|
|
571
337
|
} as GitCheckoutRequest),
|
|
572
338
|
headers: {
|
|
573
339
|
"Content-Type": "application/json",
|
|
@@ -596,148 +362,17 @@ export class HttpClient {
|
|
|
596
362
|
}
|
|
597
363
|
}
|
|
598
364
|
|
|
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
|
-
|
|
728
365
|
async mkdir(
|
|
729
366
|
path: string,
|
|
730
367
|
recursive: boolean = false,
|
|
731
|
-
sessionId
|
|
368
|
+
sessionId: string
|
|
732
369
|
): Promise<MkdirResponse> {
|
|
733
370
|
try {
|
|
734
|
-
const targetSessionId = sessionId || this.sessionId;
|
|
735
|
-
|
|
736
371
|
const response = await this.doFetch(`/api/mkdir`, {
|
|
737
372
|
body: JSON.stringify({
|
|
738
373
|
path,
|
|
739
374
|
recursive,
|
|
740
|
-
sessionId
|
|
375
|
+
sessionId,
|
|
741
376
|
} as MkdirRequest),
|
|
742
377
|
headers: {
|
|
743
378
|
"Content-Type": "application/json",
|
|
@@ -756,7 +391,7 @@ export class HttpClient {
|
|
|
756
391
|
|
|
757
392
|
const data: MkdirResponse = await response.json();
|
|
758
393
|
console.log(
|
|
759
|
-
`[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}` : ''}`
|
|
760
395
|
);
|
|
761
396
|
|
|
762
397
|
return data;
|
|
@@ -766,20 +401,20 @@ export class HttpClient {
|
|
|
766
401
|
}
|
|
767
402
|
}
|
|
768
403
|
|
|
769
|
-
async
|
|
404
|
+
async writeFile(
|
|
770
405
|
path: string,
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
406
|
+
content: string,
|
|
407
|
+
encoding: string = "utf-8",
|
|
408
|
+
sessionId: string
|
|
409
|
+
): Promise<WriteFileResponse> {
|
|
774
410
|
try {
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
const response = await this.doFetch(`/api/mkdir/stream`, {
|
|
411
|
+
const response = await this.doFetch(`/api/write`, {
|
|
778
412
|
body: JSON.stringify({
|
|
413
|
+
content,
|
|
414
|
+
encoding,
|
|
779
415
|
path,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
} as MkdirRequest),
|
|
416
|
+
sessionId,
|
|
417
|
+
} as WriteFileRequest),
|
|
783
418
|
headers: {
|
|
784
419
|
"Content-Type": "application/json",
|
|
785
420
|
},
|
|
@@ -795,116 +430,30 @@ export class HttpClient {
|
|
|
795
430
|
);
|
|
796
431
|
}
|
|
797
432
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
433
|
+
const data: WriteFileResponse = await response.json();
|
|
434
|
+
console.log(
|
|
435
|
+
`[HTTP Client] File written: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
436
|
+
);
|
|
801
437
|
|
|
802
|
-
|
|
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
|
-
}
|
|
438
|
+
return data;
|
|
881
439
|
} catch (error) {
|
|
882
|
-
console.error("[HTTP Client] Error
|
|
883
|
-
this.options.onError?.(
|
|
884
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
885
|
-
"mkdir",
|
|
886
|
-
recursive ? ["-p", path] : [path]
|
|
887
|
-
);
|
|
440
|
+
console.error("[HTTP Client] Error writing file:", error);
|
|
888
441
|
throw error;
|
|
889
442
|
}
|
|
890
443
|
}
|
|
891
444
|
|
|
892
|
-
async
|
|
445
|
+
async readFile(
|
|
893
446
|
path: string,
|
|
894
|
-
content: string,
|
|
895
447
|
encoding: string = "utf-8",
|
|
896
|
-
sessionId
|
|
897
|
-
): Promise<
|
|
448
|
+
sessionId: string
|
|
449
|
+
): Promise<ReadFileResponse> {
|
|
898
450
|
try {
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
const response = await this.doFetch(`/api/write`, {
|
|
451
|
+
const response = await this.doFetch(`/api/read`, {
|
|
902
452
|
body: JSON.stringify({
|
|
903
|
-
content,
|
|
904
453
|
encoding,
|
|
905
454
|
path,
|
|
906
|
-
sessionId
|
|
907
|
-
} as
|
|
455
|
+
sessionId,
|
|
456
|
+
} as ReadFileRequest),
|
|
908
457
|
headers: {
|
|
909
458
|
"Content-Type": "application/json",
|
|
910
459
|
},
|
|
@@ -920,34 +469,28 @@ export class HttpClient {
|
|
|
920
469
|
);
|
|
921
470
|
}
|
|
922
471
|
|
|
923
|
-
const data:
|
|
472
|
+
const data: ReadFileResponse = await response.json();
|
|
924
473
|
console.log(
|
|
925
|
-
`[HTTP Client] File
|
|
474
|
+
`[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
926
475
|
);
|
|
927
476
|
|
|
928
477
|
return data;
|
|
929
478
|
} catch (error) {
|
|
930
|
-
console.error("[HTTP Client] Error
|
|
479
|
+
console.error("[HTTP Client] Error reading file:", error);
|
|
931
480
|
throw error;
|
|
932
481
|
}
|
|
933
482
|
}
|
|
934
483
|
|
|
935
|
-
async
|
|
484
|
+
async deleteFile(
|
|
936
485
|
path: string,
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
sessionId?: string
|
|
940
|
-
): Promise<void> {
|
|
486
|
+
sessionId: string
|
|
487
|
+
): Promise<DeleteFileResponse> {
|
|
941
488
|
try {
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
const response = await this.doFetch(`/api/write/stream`, {
|
|
489
|
+
const response = await this.doFetch(`/api/delete`, {
|
|
945
490
|
body: JSON.stringify({
|
|
946
|
-
content,
|
|
947
|
-
encoding,
|
|
948
491
|
path,
|
|
949
|
-
sessionId
|
|
950
|
-
} as
|
|
492
|
+
sessionId,
|
|
493
|
+
} as DeleteFileRequest),
|
|
951
494
|
headers: {
|
|
952
495
|
"Content-Type": "application/json",
|
|
953
496
|
},
|
|
@@ -963,114 +506,30 @@ export class HttpClient {
|
|
|
963
506
|
);
|
|
964
507
|
}
|
|
965
508
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
509
|
+
const data: DeleteFileResponse = await response.json();
|
|
510
|
+
console.log(
|
|
511
|
+
`[HTTP Client] File deleted: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
512
|
+
);
|
|
969
513
|
|
|
970
|
-
|
|
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
|
-
}
|
|
514
|
+
return data;
|
|
1049
515
|
} catch (error) {
|
|
1050
|
-
console.error("[HTTP Client] Error
|
|
1051
|
-
this.options.onError?.(
|
|
1052
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1053
|
-
"write",
|
|
1054
|
-
[path, content, encoding]
|
|
1055
|
-
);
|
|
516
|
+
console.error("[HTTP Client] Error deleting file:", error);
|
|
1056
517
|
throw error;
|
|
1057
518
|
}
|
|
1058
519
|
}
|
|
1059
520
|
|
|
1060
|
-
async
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
sessionId
|
|
1064
|
-
): Promise<
|
|
521
|
+
async renameFile(
|
|
522
|
+
oldPath: string,
|
|
523
|
+
newPath: string,
|
|
524
|
+
sessionId: string
|
|
525
|
+
): Promise<RenameFileResponse> {
|
|
1065
526
|
try {
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
const response = await this.doFetch(`/api/read`, {
|
|
527
|
+
const response = await this.doFetch(`/api/rename`, {
|
|
1069
528
|
body: JSON.stringify({
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
sessionId
|
|
1073
|
-
} as
|
|
529
|
+
newPath,
|
|
530
|
+
oldPath,
|
|
531
|
+
sessionId,
|
|
532
|
+
} as RenameFileRequest),
|
|
1074
533
|
headers: {
|
|
1075
534
|
"Content-Type": "application/json",
|
|
1076
535
|
},
|
|
@@ -1086,32 +545,30 @@ export class HttpClient {
|
|
|
1086
545
|
);
|
|
1087
546
|
}
|
|
1088
547
|
|
|
1089
|
-
const data:
|
|
548
|
+
const data: RenameFileResponse = await response.json();
|
|
1090
549
|
console.log(
|
|
1091
|
-
`[HTTP Client] File
|
|
550
|
+
`[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
1092
551
|
);
|
|
1093
552
|
|
|
1094
553
|
return data;
|
|
1095
554
|
} catch (error) {
|
|
1096
|
-
console.error("[HTTP Client] Error
|
|
555
|
+
console.error("[HTTP Client] Error renaming file:", error);
|
|
1097
556
|
throw error;
|
|
1098
557
|
}
|
|
1099
558
|
}
|
|
1100
559
|
|
|
1101
|
-
async
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
sessionId
|
|
1105
|
-
): Promise<
|
|
560
|
+
async moveFile(
|
|
561
|
+
sourcePath: string,
|
|
562
|
+
destinationPath: string,
|
|
563
|
+
sessionId: string
|
|
564
|
+
): Promise<MoveFileResponse> {
|
|
1106
565
|
try {
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1109
|
-
const response = await this.doFetch(`/api/read/stream`, {
|
|
566
|
+
const response = await this.doFetch(`/api/move`, {
|
|
1110
567
|
body: JSON.stringify({
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
sessionId
|
|
1114
|
-
} as
|
|
568
|
+
destinationPath,
|
|
569
|
+
sourcePath,
|
|
570
|
+
sessionId,
|
|
571
|
+
} as MoveFileRequest),
|
|
1115
572
|
headers: {
|
|
1116
573
|
"Content-Type": "application/json",
|
|
1117
574
|
},
|
|
@@ -1127,104 +584,33 @@ export class HttpClient {
|
|
|
1127
584
|
);
|
|
1128
585
|
}
|
|
1129
586
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
587
|
+
const data: MoveFileResponse = await response.json();
|
|
588
|
+
console.log(
|
|
589
|
+
`[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
590
|
+
);
|
|
1133
591
|
|
|
1134
|
-
|
|
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
|
-
}
|
|
592
|
+
return data;
|
|
1205
593
|
} catch (error) {
|
|
1206
|
-
console.error("[HTTP Client] Error
|
|
1207
|
-
this.options.onError?.(
|
|
1208
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1209
|
-
"read",
|
|
1210
|
-
[path, encoding]
|
|
1211
|
-
);
|
|
594
|
+
console.error("[HTTP Client] Error moving file:", error);
|
|
1212
595
|
throw error;
|
|
1213
596
|
}
|
|
1214
597
|
}
|
|
1215
598
|
|
|
1216
|
-
async
|
|
599
|
+
async listFiles(
|
|
1217
600
|
path: string,
|
|
1218
|
-
sessionId
|
|
1219
|
-
|
|
601
|
+
sessionId: string,
|
|
602
|
+
options?: {
|
|
603
|
+
recursive?: boolean;
|
|
604
|
+
includeHidden?: boolean;
|
|
605
|
+
}
|
|
606
|
+
): Promise<ListFilesResponse> {
|
|
1220
607
|
try {
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
const response = await this.doFetch(`/api/delete`, {
|
|
608
|
+
const response = await this.doFetch(`/api/list-files`, {
|
|
1224
609
|
body: JSON.stringify({
|
|
1225
610
|
path,
|
|
1226
|
-
|
|
1227
|
-
|
|
611
|
+
options,
|
|
612
|
+
sessionId,
|
|
613
|
+
} as ListFilesRequest),
|
|
1228
614
|
headers: {
|
|
1229
615
|
"Content-Type": "application/json",
|
|
1230
616
|
},
|
|
@@ -1240,27 +626,25 @@ export class HttpClient {
|
|
|
1240
626
|
);
|
|
1241
627
|
}
|
|
1242
628
|
|
|
1243
|
-
const data:
|
|
629
|
+
const data: ListFilesResponse = await response.json();
|
|
1244
630
|
console.log(
|
|
1245
|
-
`[HTTP Client]
|
|
631
|
+
`[HTTP Client] Listed ${data.files.length} files in: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
1246
632
|
);
|
|
1247
633
|
|
|
1248
634
|
return data;
|
|
1249
635
|
} catch (error) {
|
|
1250
|
-
console.error("[HTTP Client] Error
|
|
636
|
+
console.error("[HTTP Client] Error listing files:", error);
|
|
1251
637
|
throw error;
|
|
1252
638
|
}
|
|
1253
639
|
}
|
|
1254
640
|
|
|
1255
|
-
async
|
|
641
|
+
async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
|
|
1256
642
|
try {
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
const response = await this.doFetch(`/api/delete/stream`, {
|
|
643
|
+
const response = await this.doFetch(`/api/expose-port`, {
|
|
1260
644
|
body: JSON.stringify({
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
}
|
|
645
|
+
port,
|
|
646
|
+
name,
|
|
647
|
+
}),
|
|
1264
648
|
headers: {
|
|
1265
649
|
"Content-Type": "application/json",
|
|
1266
650
|
},
|
|
@@ -1271,110 +655,36 @@ export class HttpClient {
|
|
|
1271
655
|
const errorData = (await response.json().catch(() => ({}))) as {
|
|
1272
656
|
error?: string;
|
|
1273
657
|
};
|
|
658
|
+
console.log(errorData);
|
|
1274
659
|
throw new Error(
|
|
1275
660
|
errorData.error || `HTTP error! status: ${response.status}`
|
|
1276
661
|
);
|
|
1277
662
|
}
|
|
1278
663
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
664
|
+
const data: ExposePortResponse = await response.json();
|
|
665
|
+
console.log(
|
|
666
|
+
`[HTTP Client] Port exposed: ${port}${
|
|
667
|
+
name ? ` (${name})` : ""
|
|
668
|
+
}, Success: ${data.success}`
|
|
669
|
+
);
|
|
1282
670
|
|
|
1283
|
-
|
|
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
|
-
}
|
|
671
|
+
return data;
|
|
1349
672
|
} catch (error) {
|
|
1350
|
-
console.error("[HTTP Client] Error
|
|
1351
|
-
this.options.onError?.(
|
|
1352
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1353
|
-
"delete",
|
|
1354
|
-
[path]
|
|
1355
|
-
);
|
|
673
|
+
console.error("[HTTP Client] Error exposing port:", error);
|
|
1356
674
|
throw error;
|
|
1357
675
|
}
|
|
1358
676
|
}
|
|
1359
677
|
|
|
1360
|
-
async
|
|
1361
|
-
oldPath: string,
|
|
1362
|
-
newPath: string,
|
|
1363
|
-
sessionId?: string
|
|
1364
|
-
): Promise<RenameFileResponse> {
|
|
678
|
+
async unexposePort(port: number): Promise<UnexposePortResponse> {
|
|
1365
679
|
try {
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1368
|
-
const response = await this.doFetch(`/api/rename`, {
|
|
680
|
+
const response = await this.doFetch(`/api/unexpose-port`, {
|
|
1369
681
|
body: JSON.stringify({
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
sessionId: targetSessionId,
|
|
1373
|
-
} as RenameFileRequest),
|
|
682
|
+
port,
|
|
683
|
+
}),
|
|
1374
684
|
headers: {
|
|
1375
685
|
"Content-Type": "application/json",
|
|
1376
686
|
},
|
|
1377
|
-
method: "
|
|
687
|
+
method: "DELETE",
|
|
1378
688
|
});
|
|
1379
689
|
|
|
1380
690
|
if (!response.ok) {
|
|
@@ -1386,36 +696,25 @@ export class HttpClient {
|
|
|
1386
696
|
);
|
|
1387
697
|
}
|
|
1388
698
|
|
|
1389
|
-
const data:
|
|
699
|
+
const data: UnexposePortResponse = await response.json();
|
|
1390
700
|
console.log(
|
|
1391
|
-
`[HTTP Client]
|
|
701
|
+
`[HTTP Client] Port unexposed: ${port}, Success: ${data.success}`
|
|
1392
702
|
);
|
|
1393
703
|
|
|
1394
704
|
return data;
|
|
1395
705
|
} catch (error) {
|
|
1396
|
-
console.error("[HTTP Client] Error
|
|
706
|
+
console.error("[HTTP Client] Error unexposing port:", error);
|
|
1397
707
|
throw error;
|
|
1398
708
|
}
|
|
1399
709
|
}
|
|
1400
710
|
|
|
1401
|
-
async
|
|
1402
|
-
oldPath: string,
|
|
1403
|
-
newPath: string,
|
|
1404
|
-
sessionId?: string
|
|
1405
|
-
): Promise<void> {
|
|
711
|
+
async getExposedPorts(): Promise<GetExposedPortsResponse> {
|
|
1406
712
|
try {
|
|
1407
|
-
const
|
|
1408
|
-
|
|
1409
|
-
const response = await this.doFetch(`/api/rename/stream`, {
|
|
1410
|
-
body: JSON.stringify({
|
|
1411
|
-
newPath,
|
|
1412
|
-
oldPath,
|
|
1413
|
-
sessionId: targetSessionId,
|
|
1414
|
-
} as RenameFileRequest),
|
|
713
|
+
const response = await this.doFetch(`/api/exposed-ports`, {
|
|
1415
714
|
headers: {
|
|
1416
715
|
"Content-Type": "application/json",
|
|
1417
716
|
},
|
|
1418
|
-
method: "
|
|
717
|
+
method: "GET",
|
|
1419
718
|
});
|
|
1420
719
|
|
|
1421
720
|
if (!response.ok) {
|
|
@@ -1427,104 +726,59 @@ export class HttpClient {
|
|
|
1427
726
|
);
|
|
1428
727
|
}
|
|
1429
728
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
729
|
+
const data: GetExposedPortsResponse = await response.json();
|
|
730
|
+
console.log(`[HTTP Client] Got ${data.count} exposed ports`);
|
|
1433
731
|
|
|
1434
|
-
|
|
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
|
-
}
|
|
732
|
+
return data;
|
|
1503
733
|
} catch (error) {
|
|
1504
|
-
console.error("[HTTP Client] Error
|
|
1505
|
-
this.options.onError?.(
|
|
1506
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1507
|
-
"rename",
|
|
1508
|
-
[oldPath, newPath]
|
|
1509
|
-
);
|
|
734
|
+
console.error("[HTTP Client] Error getting exposed ports:", error);
|
|
1510
735
|
throw error;
|
|
1511
736
|
}
|
|
1512
737
|
}
|
|
1513
738
|
|
|
1514
|
-
async
|
|
1515
|
-
sourcePath: string,
|
|
1516
|
-
destinationPath: string,
|
|
1517
|
-
sessionId?: string
|
|
1518
|
-
): Promise<MoveFileResponse> {
|
|
739
|
+
async ping(): Promise<string> {
|
|
1519
740
|
try {
|
|
1520
|
-
const
|
|
741
|
+
const response = await this.doFetch(`/api/ping`, {
|
|
742
|
+
headers: {
|
|
743
|
+
"Content-Type": "application/json",
|
|
744
|
+
},
|
|
745
|
+
method: "GET",
|
|
746
|
+
});
|
|
1521
747
|
|
|
1522
|
-
|
|
748
|
+
if (!response.ok) {
|
|
749
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
const data: PingResponse = await response.json();
|
|
753
|
+
console.log(`[HTTP Client] Ping response: ${data.message}`);
|
|
754
|
+
return data.timestamp;
|
|
755
|
+
} catch (error) {
|
|
756
|
+
console.error("[HTTP Client] Error pinging server:", error);
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
// Process management methods
|
|
763
|
+
async startProcess(
|
|
764
|
+
command: string,
|
|
765
|
+
sessionId: string,
|
|
766
|
+
options?: {
|
|
767
|
+
processId?: string;
|
|
768
|
+
timeout?: number;
|
|
769
|
+
env?: Record<string, string>;
|
|
770
|
+
cwd?: string;
|
|
771
|
+
encoding?: string;
|
|
772
|
+
autoCleanup?: boolean;
|
|
773
|
+
}
|
|
774
|
+
): Promise<StartProcessResponse> {
|
|
775
|
+
try {
|
|
776
|
+
const response = await this.doFetch("/api/process/start", {
|
|
1523
777
|
body: JSON.stringify({
|
|
1524
|
-
|
|
1525
|
-
sessionId
|
|
1526
|
-
|
|
1527
|
-
} as
|
|
778
|
+
command,
|
|
779
|
+
sessionId,
|
|
780
|
+
options,
|
|
781
|
+
} as StartProcessRequest),
|
|
1528
782
|
headers: {
|
|
1529
783
|
"Content-Type": "application/json",
|
|
1530
784
|
},
|
|
@@ -1540,36 +794,28 @@ export class HttpClient {
|
|
|
1540
794
|
);
|
|
1541
795
|
}
|
|
1542
796
|
|
|
1543
|
-
const data:
|
|
797
|
+
const data: StartProcessResponse = await response.json();
|
|
1544
798
|
console.log(
|
|
1545
|
-
`[HTTP Client]
|
|
799
|
+
`[HTTP Client] Process started: ${command}, ID: ${data.process.id}`
|
|
1546
800
|
);
|
|
1547
801
|
|
|
1548
802
|
return data;
|
|
1549
803
|
} catch (error) {
|
|
1550
|
-
console.error("[HTTP Client] Error
|
|
804
|
+
console.error("[HTTP Client] Error starting process:", error);
|
|
1551
805
|
throw error;
|
|
1552
806
|
}
|
|
1553
807
|
}
|
|
1554
808
|
|
|
1555
|
-
async
|
|
1556
|
-
sourcePath: string,
|
|
1557
|
-
destinationPath: string,
|
|
1558
|
-
sessionId?: string
|
|
1559
|
-
): Promise<void> {
|
|
809
|
+
async listProcesses(sessionId?: string): Promise<ListProcessesResponse> {
|
|
1560
810
|
try {
|
|
1561
|
-
const
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
destinationPath,
|
|
1566
|
-
sessionId: targetSessionId,
|
|
1567
|
-
sourcePath,
|
|
1568
|
-
} as MoveFileRequest),
|
|
811
|
+
const url = sessionId
|
|
812
|
+
? `/api/process/list?session=${encodeURIComponent(sessionId)}`
|
|
813
|
+
: "/api/process/list";
|
|
814
|
+
const response = await this.doFetch(url, {
|
|
1569
815
|
headers: {
|
|
1570
816
|
"Content-Type": "application/json",
|
|
1571
817
|
},
|
|
1572
|
-
method: "
|
|
818
|
+
method: "GET",
|
|
1573
819
|
});
|
|
1574
820
|
|
|
1575
821
|
if (!response.ok) {
|
|
@@ -1581,134 +827,53 @@ export class HttpClient {
|
|
|
1581
827
|
);
|
|
1582
828
|
}
|
|
1583
829
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
}
|
|
830
|
+
const data: ListProcessesResponse = await response.json();
|
|
831
|
+
console.log(`[HTTP Client] Listed ${data.processes.length} processes`);
|
|
1587
832
|
|
|
1588
|
-
|
|
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
|
-
}
|
|
833
|
+
return data;
|
|
1660
834
|
} catch (error) {
|
|
1661
|
-
console.error("[HTTP Client] Error
|
|
1662
|
-
this.options.onError?.(
|
|
1663
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1664
|
-
"move",
|
|
1665
|
-
[sourcePath, destinationPath]
|
|
1666
|
-
);
|
|
835
|
+
console.error("[HTTP Client] Error listing processes:", error);
|
|
1667
836
|
throw error;
|
|
1668
837
|
}
|
|
1669
838
|
}
|
|
1670
839
|
|
|
1671
|
-
async
|
|
840
|
+
async getProcess(processId: string): Promise<GetProcessResponse> {
|
|
1672
841
|
try {
|
|
1673
|
-
const response = await this.doFetch(`/api/
|
|
1674
|
-
body: JSON.stringify({
|
|
1675
|
-
port,
|
|
1676
|
-
name,
|
|
1677
|
-
}),
|
|
842
|
+
const response = await this.doFetch(`/api/process/${processId}`, {
|
|
1678
843
|
headers: {
|
|
1679
844
|
"Content-Type": "application/json",
|
|
1680
845
|
},
|
|
1681
|
-
method: "
|
|
846
|
+
method: "GET",
|
|
1682
847
|
});
|
|
1683
848
|
|
|
1684
849
|
if (!response.ok) {
|
|
1685
850
|
const errorData = (await response.json().catch(() => ({}))) as {
|
|
1686
851
|
error?: string;
|
|
1687
852
|
};
|
|
1688
|
-
console.log(errorData);
|
|
1689
853
|
throw new Error(
|
|
1690
854
|
errorData.error || `HTTP error! status: ${response.status}`
|
|
1691
855
|
);
|
|
1692
856
|
}
|
|
1693
857
|
|
|
1694
|
-
const data:
|
|
858
|
+
const data: GetProcessResponse = await response.json();
|
|
1695
859
|
console.log(
|
|
1696
|
-
`[HTTP Client]
|
|
860
|
+
`[HTTP Client] Got process ${processId}: ${
|
|
861
|
+
data.process?.status || "not found"
|
|
862
|
+
}`
|
|
1697
863
|
);
|
|
1698
864
|
|
|
1699
865
|
return data;
|
|
1700
866
|
} catch (error) {
|
|
1701
|
-
console.error("[HTTP Client] Error
|
|
867
|
+
console.error("[HTTP Client] Error getting process:", error);
|
|
1702
868
|
throw error;
|
|
1703
869
|
}
|
|
1704
870
|
}
|
|
1705
871
|
|
|
1706
|
-
async
|
|
872
|
+
async killProcess(
|
|
873
|
+
processId: string
|
|
874
|
+
): Promise<{ success: boolean; message: string }> {
|
|
1707
875
|
try {
|
|
1708
|
-
const response = await this.doFetch(`/api/
|
|
1709
|
-
body: JSON.stringify({
|
|
1710
|
-
port,
|
|
1711
|
-
}),
|
|
876
|
+
const response = await this.doFetch(`/api/process/${processId}`, {
|
|
1712
877
|
headers: {
|
|
1713
878
|
"Content-Type": "application/json",
|
|
1714
879
|
},
|
|
@@ -1724,25 +889,33 @@ export class HttpClient {
|
|
|
1724
889
|
);
|
|
1725
890
|
}
|
|
1726
891
|
|
|
1727
|
-
const data
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
892
|
+
const data = (await response.json()) as {
|
|
893
|
+
success: boolean;
|
|
894
|
+
message: string;
|
|
895
|
+
};
|
|
896
|
+
console.log(`[HTTP Client] Killed process ${processId}`);
|
|
1731
897
|
|
|
1732
898
|
return data;
|
|
1733
899
|
} catch (error) {
|
|
1734
|
-
console.error("[HTTP Client] Error
|
|
900
|
+
console.error("[HTTP Client] Error killing process:", error);
|
|
1735
901
|
throw error;
|
|
1736
902
|
}
|
|
1737
903
|
}
|
|
1738
904
|
|
|
1739
|
-
async
|
|
905
|
+
async killAllProcesses(sessionId?: string): Promise<{
|
|
906
|
+
success: boolean;
|
|
907
|
+
killedCount: number;
|
|
908
|
+
message: string;
|
|
909
|
+
}> {
|
|
1740
910
|
try {
|
|
1741
|
-
const
|
|
911
|
+
const url = sessionId
|
|
912
|
+
? `/api/process/kill-all?session=${encodeURIComponent(sessionId)}`
|
|
913
|
+
: "/api/process/kill-all";
|
|
914
|
+
const response = await this.doFetch(url, {
|
|
1742
915
|
headers: {
|
|
1743
916
|
"Content-Type": "application/json",
|
|
1744
917
|
},
|
|
1745
|
-
method: "
|
|
918
|
+
method: "DELETE",
|
|
1746
919
|
});
|
|
1747
920
|
|
|
1748
921
|
if (!response.ok) {
|
|
@@ -1754,21 +927,23 @@ export class HttpClient {
|
|
|
1754
927
|
);
|
|
1755
928
|
}
|
|
1756
929
|
|
|
1757
|
-
const data
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
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`);
|
|
1761
936
|
|
|
1762
937
|
return data;
|
|
1763
938
|
} catch (error) {
|
|
1764
|
-
console.error("[HTTP Client] Error
|
|
939
|
+
console.error("[HTTP Client] Error killing all processes:", error);
|
|
1765
940
|
throw error;
|
|
1766
941
|
}
|
|
1767
942
|
}
|
|
1768
943
|
|
|
1769
|
-
async
|
|
944
|
+
async getProcessLogs(processId: string): Promise<GetProcessLogsResponse> {
|
|
1770
945
|
try {
|
|
1771
|
-
const response = await this.doFetch(`/api/
|
|
946
|
+
const response = await this.doFetch(`/api/process/${processId}/logs`, {
|
|
1772
947
|
headers: {
|
|
1773
948
|
"Content-Type": "application/json",
|
|
1774
949
|
},
|
|
@@ -1776,314 +951,59 @@ export class HttpClient {
|
|
|
1776
951
|
});
|
|
1777
952
|
|
|
1778
953
|
if (!response.ok) {
|
|
1779
|
-
|
|
954
|
+
const errorData = (await response.json().catch(() => ({}))) as {
|
|
955
|
+
error?: string;
|
|
956
|
+
};
|
|
957
|
+
throw new Error(
|
|
958
|
+
errorData.error || `HTTP error! status: ${response.status}`
|
|
959
|
+
);
|
|
1780
960
|
}
|
|
1781
961
|
|
|
1782
|
-
const data:
|
|
1783
|
-
console.log(`[HTTP Client]
|
|
1784
|
-
|
|
962
|
+
const data: GetProcessLogsResponse = await response.json();
|
|
963
|
+
console.log(`[HTTP Client] Got logs for process ${processId}`);
|
|
964
|
+
|
|
965
|
+
return data;
|
|
1785
966
|
} catch (error) {
|
|
1786
|
-
console.error("[HTTP Client] Error
|
|
967
|
+
console.error("[HTTP Client] Error getting process logs:", error);
|
|
1787
968
|
throw error;
|
|
1788
969
|
}
|
|
1789
970
|
}
|
|
1790
971
|
|
|
1791
|
-
async
|
|
972
|
+
async streamProcessLogs(
|
|
973
|
+
processId: string,
|
|
974
|
+
options?: { signal?: AbortSignal }
|
|
975
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
1792
976
|
try {
|
|
1793
|
-
const response = await
|
|
977
|
+
const response = await this.doFetch(`/api/process/${processId}/stream`, {
|
|
1794
978
|
headers: {
|
|
1795
|
-
|
|
979
|
+
Accept: "text/event-stream",
|
|
980
|
+
"Cache-Control": "no-cache",
|
|
1796
981
|
},
|
|
1797
982
|
method: "GET",
|
|
983
|
+
signal: options?.signal,
|
|
1798
984
|
});
|
|
1799
985
|
|
|
1800
986
|
if (!response.ok) {
|
|
1801
|
-
|
|
987
|
+
const errorData = (await response.json().catch(() => ({}))) as {
|
|
988
|
+
error?: string;
|
|
989
|
+
};
|
|
990
|
+
throw new Error(
|
|
991
|
+
errorData.error || `HTTP error! status: ${response.status}`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if (!response.body) {
|
|
996
|
+
throw new Error("No response body for streaming request");
|
|
1802
997
|
}
|
|
1803
998
|
|
|
1804
|
-
const data: CommandsResponse = await response.json();
|
|
1805
999
|
console.log(
|
|
1806
|
-
`[HTTP Client]
|
|
1000
|
+
`[HTTP Client] Started streaming logs for process ${processId}`
|
|
1807
1001
|
);
|
|
1808
|
-
|
|
1002
|
+
|
|
1003
|
+
return response.body;
|
|
1809
1004
|
} catch (error) {
|
|
1810
|
-
console.error("[HTTP Client] Error
|
|
1005
|
+
console.error("[HTTP Client] Error streaming process logs:", error);
|
|
1811
1006
|
throw error;
|
|
1812
1007
|
}
|
|
1813
1008
|
}
|
|
1814
|
-
|
|
1815
|
-
getSessionId(): string | null {
|
|
1816
|
-
return this.sessionId;
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
setSessionId(sessionId: string): void {
|
|
1820
|
-
this.sessionId = sessionId;
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
|
-
clearSession(): void {
|
|
1824
|
-
this.sessionId = null;
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
// Example usage and utility functions
|
|
1829
|
-
export function createClient(options?: HttpClientOptions): HttpClient {
|
|
1830
|
-
return new HttpClient(options);
|
|
1831
|
-
}
|
|
1832
|
-
|
|
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
|
-
}
|
|
1848
|
-
|
|
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
|
-
}
|
|
1864
|
-
|
|
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
|
-
}
|
|
1881
|
-
|
|
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();
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
|
|
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
|
-
}
|
|
1914
|
-
|
|
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
|
-
}
|
|
1930
|
-
|
|
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
|
-
}
|
|
1947
|
-
|
|
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();
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
|
|
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
|
-
}
|
|
1980
|
-
|
|
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
|
-
}
|
|
1996
|
-
|
|
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
|
-
}
|
|
2011
|
-
|
|
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();
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
|
|
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();
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
|
|
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();
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
|
|
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();
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
|
|
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();
|
|
2088
|
-
}
|
|
2089
1009
|
}
|