@cloudflare/sandbox 0.0.0-8db6d29 → 0.0.0-9375c1e
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 +179 -0
- package/Dockerfile +99 -11
- 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 +434 -2739
- 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 +431 -1372
- package/src/errors.ts +218 -0
- package/src/index.ts +63 -128
- 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 +144 -0
- package/src/sandbox.ts +747 -0
- 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,36 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ExecuteRequest } from "../container_src/types";
|
|
2
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";
|
|
3
20
|
|
|
4
|
-
interface ExecuteRequest {
|
|
5
|
-
command: string;
|
|
6
|
-
args?: string[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ExecuteResponse {
|
|
10
|
-
success: boolean;
|
|
11
|
-
stdout: string;
|
|
12
|
-
stderr: string;
|
|
13
|
-
exitCode: number;
|
|
14
|
-
command: string;
|
|
15
|
-
args: string[];
|
|
16
|
-
timestamp: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface SessionResponse {
|
|
20
|
-
sessionId: string;
|
|
21
|
-
message: string;
|
|
22
|
-
timestamp: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface SessionListResponse {
|
|
26
|
-
sessions: Array<{
|
|
27
|
-
sessionId: string;
|
|
28
|
-
hasActiveProcess: boolean;
|
|
29
|
-
createdAt: string;
|
|
30
|
-
}>;
|
|
31
|
-
count: number;
|
|
32
|
-
timestamp: string;
|
|
33
|
-
}
|
|
34
21
|
|
|
35
22
|
interface CommandsResponse {
|
|
36
23
|
availableCommands: string[];
|
|
@@ -41,135 +28,103 @@ interface GitCheckoutRequest {
|
|
|
41
28
|
repoUrl: string;
|
|
42
29
|
branch?: string;
|
|
43
30
|
targetDir?: string;
|
|
44
|
-
sessionId
|
|
31
|
+
sessionId: string;
|
|
45
32
|
}
|
|
46
33
|
|
|
47
|
-
export interface GitCheckoutResponse {
|
|
48
|
-
success: boolean;
|
|
49
|
-
stdout: string;
|
|
50
|
-
stderr: string;
|
|
51
|
-
exitCode: number;
|
|
52
|
-
repoUrl: string;
|
|
53
|
-
branch: string;
|
|
54
|
-
targetDir: string;
|
|
55
|
-
timestamp: string;
|
|
56
|
-
}
|
|
57
34
|
|
|
58
35
|
interface MkdirRequest {
|
|
59
36
|
path: string;
|
|
60
37
|
recursive?: boolean;
|
|
61
|
-
sessionId
|
|
38
|
+
sessionId: string;
|
|
62
39
|
}
|
|
63
40
|
|
|
64
|
-
export interface MkdirResponse {
|
|
65
|
-
success: boolean;
|
|
66
|
-
stdout: string;
|
|
67
|
-
stderr: string;
|
|
68
|
-
exitCode: number;
|
|
69
|
-
path: string;
|
|
70
|
-
recursive: boolean;
|
|
71
|
-
timestamp: string;
|
|
72
|
-
}
|
|
73
41
|
|
|
74
42
|
interface WriteFileRequest {
|
|
75
43
|
path: string;
|
|
76
44
|
content: string;
|
|
77
45
|
encoding?: string;
|
|
78
|
-
sessionId
|
|
46
|
+
sessionId: string;
|
|
79
47
|
}
|
|
80
48
|
|
|
81
|
-
export interface WriteFileResponse {
|
|
82
|
-
success: boolean;
|
|
83
|
-
exitCode: number;
|
|
84
|
-
path: string;
|
|
85
|
-
timestamp: string;
|
|
86
|
-
}
|
|
87
49
|
|
|
88
50
|
interface ReadFileRequest {
|
|
89
51
|
path: string;
|
|
90
52
|
encoding?: string;
|
|
91
|
-
sessionId
|
|
53
|
+
sessionId: string;
|
|
92
54
|
}
|
|
93
55
|
|
|
94
|
-
export interface ReadFileResponse {
|
|
95
|
-
success: boolean;
|
|
96
|
-
exitCode: number;
|
|
97
|
-
path: string;
|
|
98
|
-
content: string;
|
|
99
|
-
timestamp: string;
|
|
100
|
-
}
|
|
101
56
|
|
|
102
57
|
interface DeleteFileRequest {
|
|
103
58
|
path: string;
|
|
104
|
-
sessionId
|
|
59
|
+
sessionId: string;
|
|
105
60
|
}
|
|
106
61
|
|
|
107
|
-
export interface DeleteFileResponse {
|
|
108
|
-
success: boolean;
|
|
109
|
-
exitCode: number;
|
|
110
|
-
path: string;
|
|
111
|
-
timestamp: string;
|
|
112
|
-
}
|
|
113
62
|
|
|
114
63
|
interface RenameFileRequest {
|
|
115
64
|
oldPath: string;
|
|
116
65
|
newPath: string;
|
|
117
|
-
sessionId
|
|
66
|
+
sessionId: string;
|
|
118
67
|
}
|
|
119
68
|
|
|
120
|
-
export interface RenameFileResponse {
|
|
121
|
-
success: boolean;
|
|
122
|
-
exitCode: number;
|
|
123
|
-
oldPath: string;
|
|
124
|
-
newPath: string;
|
|
125
|
-
timestamp: string;
|
|
126
|
-
}
|
|
127
69
|
|
|
128
70
|
interface MoveFileRequest {
|
|
129
71
|
sourcePath: string;
|
|
130
72
|
destinationPath: string;
|
|
131
|
-
sessionId
|
|
73
|
+
sessionId: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
interface ListFilesRequest {
|
|
78
|
+
path: string;
|
|
79
|
+
options?: {
|
|
80
|
+
recursive?: boolean;
|
|
81
|
+
includeHidden?: boolean;
|
|
82
|
+
};
|
|
83
|
+
sessionId: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
interface PreviewInfo {
|
|
88
|
+
url: string;
|
|
89
|
+
port: number;
|
|
90
|
+
name?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface ExposedPort extends PreviewInfo {
|
|
94
|
+
exposedAt: string;
|
|
95
|
+
timestamp: string;
|
|
132
96
|
}
|
|
133
97
|
|
|
134
|
-
|
|
98
|
+
interface ExposePortResponse {
|
|
135
99
|
success: boolean;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
100
|
+
port: number;
|
|
101
|
+
name?: string;
|
|
102
|
+
exposedAt: string;
|
|
139
103
|
timestamp: string;
|
|
140
104
|
}
|
|
141
105
|
|
|
142
|
-
interface
|
|
143
|
-
|
|
106
|
+
interface UnexposePortResponse {
|
|
107
|
+
success: boolean;
|
|
108
|
+
port: number;
|
|
144
109
|
timestamp: string;
|
|
145
110
|
}
|
|
146
111
|
|
|
147
|
-
interface
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
newPath?: string;
|
|
157
|
-
sourcePath?: string;
|
|
158
|
-
destinationPath?: string;
|
|
159
|
-
content?: string;
|
|
160
|
-
success?: boolean;
|
|
161
|
-
exitCode?: number;
|
|
162
|
-
stdout?: string;
|
|
163
|
-
stderr?: string;
|
|
164
|
-
error?: string;
|
|
165
|
-
timestamp?: string;
|
|
112
|
+
interface GetExposedPortsResponse {
|
|
113
|
+
ports: ExposedPort[];
|
|
114
|
+
count: number;
|
|
115
|
+
timestamp: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface PingResponse {
|
|
119
|
+
message: string;
|
|
120
|
+
timestamp: string;
|
|
166
121
|
}
|
|
167
122
|
|
|
168
123
|
interface HttpClientOptions {
|
|
169
124
|
stub?: Sandbox;
|
|
170
125
|
baseUrl?: string;
|
|
171
126
|
port?: number;
|
|
172
|
-
onCommandStart?: (command: string
|
|
127
|
+
onCommandStart?: (command: string) => void;
|
|
173
128
|
onOutput?: (
|
|
174
129
|
stream: "stdout" | "stderr",
|
|
175
130
|
data: string,
|
|
@@ -180,17 +135,14 @@ interface HttpClientOptions {
|
|
|
180
135
|
exitCode: number,
|
|
181
136
|
stdout: string,
|
|
182
137
|
stderr: string,
|
|
183
|
-
command: string
|
|
184
|
-
args: string[]
|
|
138
|
+
command: string
|
|
185
139
|
) => void;
|
|
186
|
-
onError?: (error: string, command?: string
|
|
187
|
-
onStreamEvent?: (event: StreamEvent) => void;
|
|
140
|
+
onError?: (error: string, command?: string) => void;
|
|
188
141
|
}
|
|
189
142
|
|
|
190
143
|
export class HttpClient {
|
|
191
144
|
private baseUrl: string;
|
|
192
145
|
private options: HttpClientOptions;
|
|
193
|
-
private sessionId: string | null = null;
|
|
194
146
|
|
|
195
147
|
constructor(options: HttpClientOptions = {}) {
|
|
196
148
|
this.options = {
|
|
@@ -199,11 +151,13 @@ export class HttpClient {
|
|
|
199
151
|
this.baseUrl = this.options.baseUrl!;
|
|
200
152
|
}
|
|
201
153
|
|
|
202
|
-
|
|
154
|
+
protected async doFetch(
|
|
203
155
|
path: string,
|
|
204
156
|
options?: RequestInit
|
|
205
157
|
): Promise<Response> {
|
|
206
|
-
const url = this.options.stub
|
|
158
|
+
const url = this.options.stub
|
|
159
|
+
? `http://localhost:${this.options.port}${path}`
|
|
160
|
+
: `${this.baseUrl}${path}`;
|
|
207
161
|
const method = options?.method || "GET";
|
|
208
162
|
|
|
209
163
|
console.log(`[HTTP Client] Making ${method} request to ${url}`);
|
|
@@ -212,15 +166,23 @@ export class HttpClient {
|
|
|
212
166
|
let response: Response;
|
|
213
167
|
|
|
214
168
|
if (this.options.stub) {
|
|
215
|
-
response = await this.options.stub.containerFetch(
|
|
169
|
+
response = await this.options.stub.containerFetch(
|
|
170
|
+
url,
|
|
171
|
+
options,
|
|
172
|
+
this.options.port
|
|
173
|
+
);
|
|
216
174
|
} else {
|
|
217
|
-
response = await fetch(
|
|
175
|
+
response = await fetch(url, options);
|
|
218
176
|
}
|
|
219
177
|
|
|
220
|
-
console.log(
|
|
178
|
+
console.log(
|
|
179
|
+
`[HTTP Client] Response: ${response.status} ${response.statusText}`
|
|
180
|
+
);
|
|
221
181
|
|
|
222
182
|
if (!response.ok) {
|
|
223
|
-
console.error(
|
|
183
|
+
console.error(
|
|
184
|
+
`[HTTP Client] Request failed: ${method} ${url} - ${response.status} ${response.statusText}`
|
|
185
|
+
);
|
|
224
186
|
}
|
|
225
187
|
|
|
226
188
|
return response;
|
|
@@ -229,121 +191,53 @@ export class HttpClient {
|
|
|
229
191
|
throw error;
|
|
230
192
|
}
|
|
231
193
|
}
|
|
232
|
-
// Public methods to set event handlers
|
|
233
|
-
setOnOutput(
|
|
234
|
-
handler: (
|
|
235
|
-
stream: "stdout" | "stderr",
|
|
236
|
-
data: string,
|
|
237
|
-
command: string
|
|
238
|
-
) => void
|
|
239
|
-
): void {
|
|
240
|
-
this.options.onOutput = handler;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
setOnCommandComplete(
|
|
244
|
-
handler: (
|
|
245
|
-
success: boolean,
|
|
246
|
-
exitCode: number,
|
|
247
|
-
stdout: string,
|
|
248
|
-
stderr: string,
|
|
249
|
-
command: string,
|
|
250
|
-
args: string[]
|
|
251
|
-
) => void
|
|
252
|
-
): void {
|
|
253
|
-
this.options.onCommandComplete = handler;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
setOnStreamEvent(handler: (event: StreamEvent) => void): void {
|
|
257
|
-
this.options.onStreamEvent = handler;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Public getter methods
|
|
261
|
-
getOnOutput():
|
|
262
|
-
| ((stream: "stdout" | "stderr", data: string, command: string) => void)
|
|
263
|
-
| undefined {
|
|
264
|
-
return this.options.onOutput;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
getOnCommandComplete():
|
|
268
|
-
| ((
|
|
269
|
-
success: boolean,
|
|
270
|
-
exitCode: number,
|
|
271
|
-
stdout: string,
|
|
272
|
-
stderr: string,
|
|
273
|
-
command: string,
|
|
274
|
-
args: string[]
|
|
275
|
-
) => void)
|
|
276
|
-
| undefined {
|
|
277
|
-
return this.options.onCommandComplete;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
getOnStreamEvent(): ((event: StreamEvent) => void) | undefined {
|
|
281
|
-
return this.options.onStreamEvent;
|
|
282
|
-
}
|
|
283
194
|
|
|
284
|
-
async createSession(
|
|
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 }> {
|
|
285
201
|
try {
|
|
286
202
|
const response = await this.doFetch(`/api/session/create`, {
|
|
287
|
-
headers: {
|
|
288
|
-
"Content-Type": "application/json",
|
|
289
|
-
},
|
|
290
203
|
method: "POST",
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
if (!response.ok) {
|
|
294
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const data: SessionResponse = await response.json();
|
|
298
|
-
this.sessionId = data.sessionId;
|
|
299
|
-
console.log(`[HTTP Client] Created session: ${this.sessionId}`);
|
|
300
|
-
return this.sessionId;
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.error("[HTTP Client] Error creating session:", error);
|
|
303
|
-
throw error;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async listSessions(): Promise<SessionListResponse> {
|
|
308
|
-
try {
|
|
309
|
-
const response = await this.doFetch(`/api/session/list`, {
|
|
310
204
|
headers: {
|
|
311
205
|
"Content-Type": "application/json",
|
|
312
206
|
},
|
|
313
|
-
|
|
207
|
+
body: JSON.stringify(options),
|
|
314
208
|
});
|
|
315
209
|
|
|
316
210
|
if (!response.ok) {
|
|
317
|
-
|
|
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
|
+
);
|
|
318
217
|
}
|
|
319
218
|
|
|
320
|
-
const data
|
|
321
|
-
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}`);
|
|
322
221
|
return data;
|
|
323
222
|
} catch (error) {
|
|
324
|
-
console.error("[HTTP Client] Error
|
|
223
|
+
console.error("[HTTP Client] Error creating session:", error);
|
|
325
224
|
throw error;
|
|
326
225
|
}
|
|
327
226
|
}
|
|
328
227
|
|
|
329
|
-
async
|
|
228
|
+
async exec(
|
|
229
|
+
sessionId: string,
|
|
330
230
|
command: string,
|
|
331
|
-
|
|
332
|
-
sessionId?: string
|
|
231
|
+
options?: Pick<BaseExecOptions, "cwd" | "env">
|
|
333
232
|
): Promise<ExecuteResponse> {
|
|
334
233
|
try {
|
|
335
|
-
|
|
336
|
-
|
|
234
|
+
// Always use session-specific endpoint
|
|
337
235
|
const response = await this.doFetch(`/api/execute`, {
|
|
338
|
-
|
|
339
|
-
args,
|
|
340
|
-
command,
|
|
341
|
-
sessionId: targetSessionId,
|
|
342
|
-
}),
|
|
236
|
+
method: "POST",
|
|
343
237
|
headers: {
|
|
344
238
|
"Content-Type": "application/json",
|
|
345
239
|
},
|
|
346
|
-
|
|
240
|
+
body: JSON.stringify({ id: sessionId, command }),
|
|
347
241
|
});
|
|
348
242
|
|
|
349
243
|
if (!response.ok) {
|
|
@@ -351,55 +245,57 @@ export class HttpClient {
|
|
|
351
245
|
error?: string;
|
|
352
246
|
};
|
|
353
247
|
throw new Error(
|
|
354
|
-
errorData.error || `
|
|
248
|
+
errorData.error || `Failed to execute in session: ${response.status}`
|
|
355
249
|
);
|
|
356
250
|
}
|
|
357
251
|
|
|
358
|
-
const data
|
|
252
|
+
const data = await response.json() as { stdout: string; stderr: string; exitCode: number; success: boolean };
|
|
359
253
|
console.log(
|
|
360
|
-
`[HTTP Client] Command executed
|
|
254
|
+
`[HTTP Client] Command executed in session ${sessionId}: ${command}`
|
|
361
255
|
);
|
|
256
|
+
|
|
257
|
+
// Convert to ExecuteResponse format for consistency
|
|
258
|
+
const executeResponse: ExecuteResponse = {
|
|
259
|
+
...data,
|
|
260
|
+
command,
|
|
261
|
+
timestamp: new Date().toISOString()
|
|
262
|
+
};
|
|
362
263
|
|
|
363
264
|
// Call the callback if provided
|
|
364
265
|
this.options.onCommandComplete?.(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
data.args
|
|
266
|
+
executeResponse.success,
|
|
267
|
+
executeResponse.exitCode,
|
|
268
|
+
executeResponse.stdout,
|
|
269
|
+
executeResponse.stderr,
|
|
270
|
+
executeResponse.command
|
|
371
271
|
);
|
|
372
272
|
|
|
373
|
-
return
|
|
273
|
+
return executeResponse;
|
|
374
274
|
} catch (error) {
|
|
375
|
-
console.error("[HTTP Client] Error executing
|
|
275
|
+
console.error("[HTTP Client] Error executing in session:", error);
|
|
376
276
|
this.options.onError?.(
|
|
377
277
|
error instanceof Error ? error.message : "Unknown error",
|
|
378
|
-
command
|
|
379
|
-
args
|
|
278
|
+
command
|
|
380
279
|
);
|
|
381
280
|
throw error;
|
|
382
281
|
}
|
|
383
282
|
}
|
|
384
283
|
|
|
385
|
-
async
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
): Promise<void> {
|
|
284
|
+
async execStream(
|
|
285
|
+
sessionId: string,
|
|
286
|
+
command: string
|
|
287
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
390
288
|
try {
|
|
391
|
-
|
|
392
|
-
|
|
289
|
+
// Always use session-specific streaming endpoint
|
|
393
290
|
const response = await this.doFetch(`/api/execute/stream`, {
|
|
394
|
-
|
|
395
|
-
args,
|
|
396
|
-
command,
|
|
397
|
-
sessionId: targetSessionId,
|
|
398
|
-
}),
|
|
291
|
+
method: "POST",
|
|
399
292
|
headers: {
|
|
400
293
|
"Content-Type": "application/json",
|
|
401
294
|
},
|
|
402
|
-
|
|
295
|
+
body: JSON.stringify({
|
|
296
|
+
id: sessionId,
|
|
297
|
+
command
|
|
298
|
+
}),
|
|
403
299
|
});
|
|
404
300
|
|
|
405
301
|
if (!response.ok) {
|
|
@@ -407,123 +303,38 @@ export class HttpClient {
|
|
|
407
303
|
error?: string;
|
|
408
304
|
};
|
|
409
305
|
throw new Error(
|
|
410
|
-
errorData.error || `
|
|
306
|
+
errorData.error || `Failed to stream execute in session: ${response.status}`
|
|
411
307
|
);
|
|
412
308
|
}
|
|
413
309
|
|
|
414
310
|
if (!response.body) {
|
|
415
|
-
throw new Error("No response body for streaming
|
|
311
|
+
throw new Error("No response body for streaming execution");
|
|
416
312
|
}
|
|
417
313
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
while (true) {
|
|
423
|
-
const { done, value } = await reader.read();
|
|
424
|
-
|
|
425
|
-
if (done) {
|
|
426
|
-
break;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
430
|
-
const lines = chunk.split("\n");
|
|
431
|
-
|
|
432
|
-
for (const line of lines) {
|
|
433
|
-
if (line.startsWith("data: ")) {
|
|
434
|
-
try {
|
|
435
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
436
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
437
|
-
|
|
438
|
-
console.log(`[HTTP Client] Stream event: ${event.type}`);
|
|
439
|
-
this.options.onStreamEvent?.(event);
|
|
440
|
-
|
|
441
|
-
switch (event.type) {
|
|
442
|
-
case "command_start":
|
|
443
|
-
console.log(
|
|
444
|
-
`[HTTP Client] Command started: ${
|
|
445
|
-
event.command
|
|
446
|
-
} ${event.args?.join(" ")}`
|
|
447
|
-
);
|
|
448
|
-
this.options.onCommandStart?.(
|
|
449
|
-
event.command!,
|
|
450
|
-
event.args || []
|
|
451
|
-
);
|
|
452
|
-
break;
|
|
453
|
-
|
|
454
|
-
case "output":
|
|
455
|
-
console.log(`[${event.stream}] ${event.data}`);
|
|
456
|
-
this.options.onOutput?.(
|
|
457
|
-
event.stream!,
|
|
458
|
-
event.data!,
|
|
459
|
-
event.command!
|
|
460
|
-
);
|
|
461
|
-
break;
|
|
462
|
-
|
|
463
|
-
case "command_complete":
|
|
464
|
-
console.log(
|
|
465
|
-
`[HTTP Client] Command completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
|
|
466
|
-
);
|
|
467
|
-
this.options.onCommandComplete?.(
|
|
468
|
-
event.success!,
|
|
469
|
-
event.exitCode!,
|
|
470
|
-
event.stdout!,
|
|
471
|
-
event.stderr!,
|
|
472
|
-
event.command!,
|
|
473
|
-
event.args || []
|
|
474
|
-
);
|
|
475
|
-
break;
|
|
476
|
-
|
|
477
|
-
case "error":
|
|
478
|
-
console.error(
|
|
479
|
-
`[HTTP Client] Command error: ${event.error}`
|
|
480
|
-
);
|
|
481
|
-
this.options.onError?.(
|
|
482
|
-
event.error!,
|
|
483
|
-
event.command,
|
|
484
|
-
event.args
|
|
485
|
-
);
|
|
486
|
-
break;
|
|
487
|
-
}
|
|
488
|
-
} catch (parseError) {
|
|
489
|
-
console.warn(
|
|
490
|
-
"[HTTP Client] Failed to parse stream event:",
|
|
491
|
-
parseError
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
} finally {
|
|
498
|
-
reader.releaseLock();
|
|
499
|
-
}
|
|
500
|
-
} catch (error) {
|
|
501
|
-
console.error("[HTTP Client] Error in streaming execution:", error);
|
|
502
|
-
this.options.onError?.(
|
|
503
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
504
|
-
command,
|
|
505
|
-
args
|
|
314
|
+
console.log(
|
|
315
|
+
`[HTTP Client] Started streaming command in session ${sessionId}: ${command}`
|
|
506
316
|
);
|
|
317
|
+
return response.body;
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error("[HTTP Client] Error streaming execute in session:", error);
|
|
507
320
|
throw error;
|
|
508
321
|
}
|
|
509
322
|
}
|
|
510
323
|
|
|
511
324
|
async gitCheckout(
|
|
512
325
|
repoUrl: string,
|
|
326
|
+
sessionId: string,
|
|
513
327
|
branch: string = "main",
|
|
514
|
-
targetDir?: string
|
|
515
|
-
sessionId?: string
|
|
328
|
+
targetDir?: string
|
|
516
329
|
): Promise<GitCheckoutResponse> {
|
|
517
330
|
try {
|
|
518
|
-
const targetSessionId = sessionId || this.sessionId;
|
|
519
|
-
|
|
520
331
|
const response = await this.doFetch(`/api/git/checkout`, {
|
|
521
332
|
body: JSON.stringify({
|
|
522
333
|
branch,
|
|
523
334
|
repoUrl,
|
|
524
|
-
sessionId: targetSessionId,
|
|
525
335
|
targetDir,
|
|
526
|
-
|
|
336
|
+
sessionId,
|
|
337
|
+
} as GitCheckoutRequest),
|
|
527
338
|
headers: {
|
|
528
339
|
"Content-Type": "application/json",
|
|
529
340
|
},
|
|
@@ -551,22 +362,18 @@ export class HttpClient {
|
|
|
551
362
|
}
|
|
552
363
|
}
|
|
553
364
|
|
|
554
|
-
async
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
): Promise<void> {
|
|
365
|
+
async mkdir(
|
|
366
|
+
path: string,
|
|
367
|
+
recursive: boolean = false,
|
|
368
|
+
sessionId: string
|
|
369
|
+
): Promise<MkdirResponse> {
|
|
560
370
|
try {
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
const response = await this.doFetch(`/api/git/checkout/stream`, {
|
|
371
|
+
const response = await this.doFetch(`/api/mkdir`, {
|
|
564
372
|
body: JSON.stringify({
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
sessionId
|
|
568
|
-
|
|
569
|
-
}),
|
|
373
|
+
path,
|
|
374
|
+
recursive,
|
|
375
|
+
sessionId,
|
|
376
|
+
} as MkdirRequest),
|
|
570
377
|
headers: {
|
|
571
378
|
"Content-Type": "application/json",
|
|
572
379
|
},
|
|
@@ -582,119 +389,32 @@ export class HttpClient {
|
|
|
582
389
|
);
|
|
583
390
|
}
|
|
584
391
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
392
|
+
const data: MkdirResponse = await response.json();
|
|
393
|
+
console.log(
|
|
394
|
+
`[HTTP Client] Directory created: ${path}, Success: ${data.success}, Recursive: ${data.recursive}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
395
|
+
);
|
|
588
396
|
|
|
589
|
-
|
|
590
|
-
const decoder = new TextDecoder();
|
|
591
|
-
|
|
592
|
-
try {
|
|
593
|
-
while (true) {
|
|
594
|
-
const { done, value } = await reader.read();
|
|
595
|
-
|
|
596
|
-
if (done) {
|
|
597
|
-
break;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
601
|
-
const lines = chunk.split("\n");
|
|
602
|
-
|
|
603
|
-
for (const line of lines) {
|
|
604
|
-
if (line.startsWith("data: ")) {
|
|
605
|
-
try {
|
|
606
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
607
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
608
|
-
|
|
609
|
-
console.log(
|
|
610
|
-
`[HTTP Client] Git checkout stream event: ${event.type}`
|
|
611
|
-
);
|
|
612
|
-
this.options.onStreamEvent?.(event);
|
|
613
|
-
|
|
614
|
-
switch (event.type) {
|
|
615
|
-
case "command_start":
|
|
616
|
-
console.log(
|
|
617
|
-
`[HTTP Client] Git checkout started: ${
|
|
618
|
-
event.command
|
|
619
|
-
} ${event.args?.join(" ")}`
|
|
620
|
-
);
|
|
621
|
-
this.options.onCommandStart?.(
|
|
622
|
-
event.command!,
|
|
623
|
-
event.args || []
|
|
624
|
-
);
|
|
625
|
-
break;
|
|
626
|
-
|
|
627
|
-
case "output":
|
|
628
|
-
console.log(`[${event.stream}] ${event.data}`);
|
|
629
|
-
this.options.onOutput?.(
|
|
630
|
-
event.stream!,
|
|
631
|
-
event.data!,
|
|
632
|
-
event.command!
|
|
633
|
-
);
|
|
634
|
-
break;
|
|
635
|
-
|
|
636
|
-
case "command_complete":
|
|
637
|
-
console.log(
|
|
638
|
-
`[HTTP Client] Git checkout completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
|
|
639
|
-
);
|
|
640
|
-
this.options.onCommandComplete?.(
|
|
641
|
-
event.success!,
|
|
642
|
-
event.exitCode!,
|
|
643
|
-
event.stdout!,
|
|
644
|
-
event.stderr!,
|
|
645
|
-
event.command!,
|
|
646
|
-
event.args || []
|
|
647
|
-
);
|
|
648
|
-
break;
|
|
649
|
-
|
|
650
|
-
case "error":
|
|
651
|
-
console.error(
|
|
652
|
-
`[HTTP Client] Git checkout error: ${event.error}`
|
|
653
|
-
);
|
|
654
|
-
this.options.onError?.(
|
|
655
|
-
event.error!,
|
|
656
|
-
event.command,
|
|
657
|
-
event.args
|
|
658
|
-
);
|
|
659
|
-
break;
|
|
660
|
-
}
|
|
661
|
-
} catch (parseError) {
|
|
662
|
-
console.warn(
|
|
663
|
-
"[HTTP Client] Failed to parse git checkout stream event:",
|
|
664
|
-
parseError
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
} finally {
|
|
671
|
-
reader.releaseLock();
|
|
672
|
-
}
|
|
397
|
+
return data;
|
|
673
398
|
} catch (error) {
|
|
674
|
-
console.error("[HTTP Client] Error
|
|
675
|
-
this.options.onError?.(
|
|
676
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
677
|
-
"git clone",
|
|
678
|
-
[branch, repoUrl, targetDir || ""]
|
|
679
|
-
);
|
|
399
|
+
console.error("[HTTP Client] Error creating directory:", error);
|
|
680
400
|
throw error;
|
|
681
401
|
}
|
|
682
402
|
}
|
|
683
403
|
|
|
684
|
-
async
|
|
404
|
+
async writeFile(
|
|
685
405
|
path: string,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
406
|
+
content: string,
|
|
407
|
+
encoding: string = "utf-8",
|
|
408
|
+
sessionId: string
|
|
409
|
+
): Promise<WriteFileResponse> {
|
|
689
410
|
try {
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
const response = await this.doFetch(`/api/mkdir`, {
|
|
411
|
+
const response = await this.doFetch(`/api/write`, {
|
|
693
412
|
body: JSON.stringify({
|
|
413
|
+
content,
|
|
414
|
+
encoding,
|
|
694
415
|
path,
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}),
|
|
416
|
+
sessionId,
|
|
417
|
+
} as WriteFileRequest),
|
|
698
418
|
headers: {
|
|
699
419
|
"Content-Type": "application/json",
|
|
700
420
|
},
|
|
@@ -710,32 +430,30 @@ export class HttpClient {
|
|
|
710
430
|
);
|
|
711
431
|
}
|
|
712
432
|
|
|
713
|
-
const data:
|
|
433
|
+
const data: WriteFileResponse = await response.json();
|
|
714
434
|
console.log(
|
|
715
|
-
`[HTTP Client]
|
|
435
|
+
`[HTTP Client] File written: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
716
436
|
);
|
|
717
437
|
|
|
718
438
|
return data;
|
|
719
439
|
} catch (error) {
|
|
720
|
-
console.error("[HTTP Client] Error
|
|
440
|
+
console.error("[HTTP Client] Error writing file:", error);
|
|
721
441
|
throw error;
|
|
722
442
|
}
|
|
723
443
|
}
|
|
724
444
|
|
|
725
|
-
async
|
|
445
|
+
async readFile(
|
|
726
446
|
path: string,
|
|
727
|
-
|
|
728
|
-
sessionId
|
|
729
|
-
): Promise<
|
|
447
|
+
encoding: string = "utf-8",
|
|
448
|
+
sessionId: string
|
|
449
|
+
): Promise<ReadFileResponse> {
|
|
730
450
|
try {
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
const response = await this.doFetch(`/api/mkdir/stream`, {
|
|
451
|
+
const response = await this.doFetch(`/api/read`, {
|
|
734
452
|
body: JSON.stringify({
|
|
453
|
+
encoding,
|
|
735
454
|
path,
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
}),
|
|
455
|
+
sessionId,
|
|
456
|
+
} as ReadFileRequest),
|
|
739
457
|
headers: {
|
|
740
458
|
"Content-Type": "application/json",
|
|
741
459
|
},
|
|
@@ -751,117 +469,28 @@ export class HttpClient {
|
|
|
751
469
|
);
|
|
752
470
|
}
|
|
753
471
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
472
|
+
const data: ReadFileResponse = await response.json();
|
|
473
|
+
console.log(
|
|
474
|
+
`[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
475
|
+
);
|
|
757
476
|
|
|
758
|
-
|
|
759
|
-
const decoder = new TextDecoder();
|
|
760
|
-
|
|
761
|
-
try {
|
|
762
|
-
while (true) {
|
|
763
|
-
const { done, value } = await reader.read();
|
|
764
|
-
|
|
765
|
-
if (done) {
|
|
766
|
-
break;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
770
|
-
const lines = chunk.split("\n");
|
|
771
|
-
|
|
772
|
-
for (const line of lines) {
|
|
773
|
-
if (line.startsWith("data: ")) {
|
|
774
|
-
try {
|
|
775
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
776
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
777
|
-
|
|
778
|
-
console.log(`[HTTP Client] Mkdir stream event: ${event.type}`);
|
|
779
|
-
this.options.onStreamEvent?.(event);
|
|
780
|
-
|
|
781
|
-
switch (event.type) {
|
|
782
|
-
case "command_start":
|
|
783
|
-
console.log(
|
|
784
|
-
`[HTTP Client] Mkdir started: ${
|
|
785
|
-
event.command
|
|
786
|
-
} ${event.args?.join(" ")}`
|
|
787
|
-
);
|
|
788
|
-
this.options.onCommandStart?.(
|
|
789
|
-
event.command!,
|
|
790
|
-
event.args || []
|
|
791
|
-
);
|
|
792
|
-
break;
|
|
793
|
-
|
|
794
|
-
case "output":
|
|
795
|
-
console.log(`[${event.stream}] ${event.data}`);
|
|
796
|
-
this.options.onOutput?.(
|
|
797
|
-
event.stream!,
|
|
798
|
-
event.data!,
|
|
799
|
-
event.command!
|
|
800
|
-
);
|
|
801
|
-
break;
|
|
802
|
-
|
|
803
|
-
case "command_complete":
|
|
804
|
-
console.log(
|
|
805
|
-
`[HTTP Client] Mkdir completed: ${event.command}, Success: ${event.success}, Exit code: ${event.exitCode}`
|
|
806
|
-
);
|
|
807
|
-
this.options.onCommandComplete?.(
|
|
808
|
-
event.success!,
|
|
809
|
-
event.exitCode!,
|
|
810
|
-
event.stdout!,
|
|
811
|
-
event.stderr!,
|
|
812
|
-
event.command!,
|
|
813
|
-
event.args || []
|
|
814
|
-
);
|
|
815
|
-
break;
|
|
816
|
-
|
|
817
|
-
case "error":
|
|
818
|
-
console.error(`[HTTP Client] Mkdir error: ${event.error}`);
|
|
819
|
-
this.options.onError?.(
|
|
820
|
-
event.error!,
|
|
821
|
-
event.command,
|
|
822
|
-
event.args
|
|
823
|
-
);
|
|
824
|
-
break;
|
|
825
|
-
}
|
|
826
|
-
} catch (parseError) {
|
|
827
|
-
console.warn(
|
|
828
|
-
"[HTTP Client] Failed to parse mkdir stream event:",
|
|
829
|
-
parseError
|
|
830
|
-
);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
} finally {
|
|
836
|
-
reader.releaseLock();
|
|
837
|
-
}
|
|
477
|
+
return data;
|
|
838
478
|
} catch (error) {
|
|
839
|
-
console.error("[HTTP Client] Error
|
|
840
|
-
this.options.onError?.(
|
|
841
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
842
|
-
"mkdir",
|
|
843
|
-
recursive ? ["-p", path] : [path]
|
|
844
|
-
);
|
|
479
|
+
console.error("[HTTP Client] Error reading file:", error);
|
|
845
480
|
throw error;
|
|
846
481
|
}
|
|
847
482
|
}
|
|
848
483
|
|
|
849
|
-
async
|
|
484
|
+
async deleteFile(
|
|
850
485
|
path: string,
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
sessionId?: string
|
|
854
|
-
): Promise<WriteFileResponse> {
|
|
486
|
+
sessionId: string
|
|
487
|
+
): Promise<DeleteFileResponse> {
|
|
855
488
|
try {
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
const response = await this.doFetch(`/api/write`, {
|
|
489
|
+
const response = await this.doFetch(`/api/delete`, {
|
|
859
490
|
body: JSON.stringify({
|
|
860
|
-
content,
|
|
861
|
-
encoding,
|
|
862
491
|
path,
|
|
863
|
-
sessionId
|
|
864
|
-
}),
|
|
492
|
+
sessionId,
|
|
493
|
+
} as DeleteFileRequest),
|
|
865
494
|
headers: {
|
|
866
495
|
"Content-Type": "application/json",
|
|
867
496
|
},
|
|
@@ -877,34 +506,30 @@ export class HttpClient {
|
|
|
877
506
|
);
|
|
878
507
|
}
|
|
879
508
|
|
|
880
|
-
const data:
|
|
509
|
+
const data: DeleteFileResponse = await response.json();
|
|
881
510
|
console.log(
|
|
882
|
-
`[HTTP Client] File
|
|
511
|
+
`[HTTP Client] File deleted: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
883
512
|
);
|
|
884
513
|
|
|
885
514
|
return data;
|
|
886
515
|
} catch (error) {
|
|
887
|
-
console.error("[HTTP Client] Error
|
|
516
|
+
console.error("[HTTP Client] Error deleting file:", error);
|
|
888
517
|
throw error;
|
|
889
518
|
}
|
|
890
519
|
}
|
|
891
520
|
|
|
892
|
-
async
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
): Promise<void> {
|
|
521
|
+
async renameFile(
|
|
522
|
+
oldPath: string,
|
|
523
|
+
newPath: string,
|
|
524
|
+
sessionId: string
|
|
525
|
+
): Promise<RenameFileResponse> {
|
|
898
526
|
try {
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
const response = await this.doFetch(`/api/write/stream`, {
|
|
527
|
+
const response = await this.doFetch(`/api/rename`, {
|
|
902
528
|
body: JSON.stringify({
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
}),
|
|
529
|
+
newPath,
|
|
530
|
+
oldPath,
|
|
531
|
+
sessionId,
|
|
532
|
+
} as RenameFileRequest),
|
|
908
533
|
headers: {
|
|
909
534
|
"Content-Type": "application/json",
|
|
910
535
|
},
|
|
@@ -920,114 +545,30 @@ export class HttpClient {
|
|
|
920
545
|
);
|
|
921
546
|
}
|
|
922
547
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
548
|
+
const data: RenameFileResponse = await response.json();
|
|
549
|
+
console.log(
|
|
550
|
+
`[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
551
|
+
);
|
|
926
552
|
|
|
927
|
-
|
|
928
|
-
const decoder = new TextDecoder();
|
|
929
|
-
|
|
930
|
-
try {
|
|
931
|
-
while (true) {
|
|
932
|
-
const { done, value } = await reader.read();
|
|
933
|
-
|
|
934
|
-
if (done) {
|
|
935
|
-
break;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
939
|
-
const lines = chunk.split("\n");
|
|
940
|
-
|
|
941
|
-
for (const line of lines) {
|
|
942
|
-
if (line.startsWith("data: ")) {
|
|
943
|
-
try {
|
|
944
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
945
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
946
|
-
|
|
947
|
-
console.log(
|
|
948
|
-
`[HTTP Client] Write file stream event: ${event.type}`
|
|
949
|
-
);
|
|
950
|
-
this.options.onStreamEvent?.(event);
|
|
951
|
-
|
|
952
|
-
switch (event.type) {
|
|
953
|
-
case "command_start":
|
|
954
|
-
console.log(
|
|
955
|
-
`[HTTP Client] Write file started: ${event.path}`
|
|
956
|
-
);
|
|
957
|
-
this.options.onCommandStart?.("write", [
|
|
958
|
-
path,
|
|
959
|
-
content,
|
|
960
|
-
encoding,
|
|
961
|
-
]);
|
|
962
|
-
break;
|
|
963
|
-
|
|
964
|
-
case "output":
|
|
965
|
-
console.log(`[output] ${event.message}`);
|
|
966
|
-
this.options.onOutput?.("stdout", event.message!, "write");
|
|
967
|
-
break;
|
|
968
|
-
|
|
969
|
-
case "command_complete":
|
|
970
|
-
console.log(
|
|
971
|
-
`[HTTP Client] Write file completed: ${event.path}, Success: ${event.success}`
|
|
972
|
-
);
|
|
973
|
-
this.options.onCommandComplete?.(
|
|
974
|
-
event.success!,
|
|
975
|
-
0,
|
|
976
|
-
"",
|
|
977
|
-
"",
|
|
978
|
-
"write",
|
|
979
|
-
[path, content, encoding]
|
|
980
|
-
);
|
|
981
|
-
break;
|
|
982
|
-
|
|
983
|
-
case "error":
|
|
984
|
-
console.error(
|
|
985
|
-
`[HTTP Client] Write file error: ${event.error}`
|
|
986
|
-
);
|
|
987
|
-
this.options.onError?.(event.error!, "write", [
|
|
988
|
-
path,
|
|
989
|
-
content,
|
|
990
|
-
encoding,
|
|
991
|
-
]);
|
|
992
|
-
break;
|
|
993
|
-
}
|
|
994
|
-
} catch (parseError) {
|
|
995
|
-
console.warn(
|
|
996
|
-
"[HTTP Client] Failed to parse write file stream event:",
|
|
997
|
-
parseError
|
|
998
|
-
);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
} finally {
|
|
1004
|
-
reader.releaseLock();
|
|
1005
|
-
}
|
|
553
|
+
return data;
|
|
1006
554
|
} catch (error) {
|
|
1007
|
-
console.error("[HTTP Client] Error
|
|
1008
|
-
this.options.onError?.(
|
|
1009
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1010
|
-
"write",
|
|
1011
|
-
[path, content, encoding]
|
|
1012
|
-
);
|
|
555
|
+
console.error("[HTTP Client] Error renaming file:", error);
|
|
1013
556
|
throw error;
|
|
1014
557
|
}
|
|
1015
558
|
}
|
|
1016
559
|
|
|
1017
|
-
async
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
sessionId
|
|
1021
|
-
): Promise<
|
|
560
|
+
async moveFile(
|
|
561
|
+
sourcePath: string,
|
|
562
|
+
destinationPath: string,
|
|
563
|
+
sessionId: string
|
|
564
|
+
): Promise<MoveFileResponse> {
|
|
1022
565
|
try {
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1025
|
-
const response = await this.doFetch(`/api/read`, {
|
|
566
|
+
const response = await this.doFetch(`/api/move`, {
|
|
1026
567
|
body: JSON.stringify({
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
sessionId
|
|
1030
|
-
}),
|
|
568
|
+
destinationPath,
|
|
569
|
+
sourcePath,
|
|
570
|
+
sessionId,
|
|
571
|
+
} as MoveFileRequest),
|
|
1031
572
|
headers: {
|
|
1032
573
|
"Content-Type": "application/json",
|
|
1033
574
|
},
|
|
@@ -1043,32 +584,33 @@ export class HttpClient {
|
|
|
1043
584
|
);
|
|
1044
585
|
}
|
|
1045
586
|
|
|
1046
|
-
const data:
|
|
587
|
+
const data: MoveFileResponse = await response.json();
|
|
1047
588
|
console.log(
|
|
1048
|
-
`[HTTP Client] File
|
|
589
|
+
`[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
1049
590
|
);
|
|
1050
591
|
|
|
1051
592
|
return data;
|
|
1052
593
|
} catch (error) {
|
|
1053
|
-
console.error("[HTTP Client] Error
|
|
594
|
+
console.error("[HTTP Client] Error moving file:", error);
|
|
1054
595
|
throw error;
|
|
1055
596
|
}
|
|
1056
597
|
}
|
|
1057
598
|
|
|
1058
|
-
async
|
|
599
|
+
async listFiles(
|
|
1059
600
|
path: string,
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
601
|
+
sessionId: string,
|
|
602
|
+
options?: {
|
|
603
|
+
recursive?: boolean;
|
|
604
|
+
includeHidden?: boolean;
|
|
605
|
+
}
|
|
606
|
+
): Promise<ListFilesResponse> {
|
|
1063
607
|
try {
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
const response = await this.doFetch(`/api/read/stream`, {
|
|
608
|
+
const response = await this.doFetch(`/api/list-files`, {
|
|
1067
609
|
body: JSON.stringify({
|
|
1068
|
-
encoding,
|
|
1069
610
|
path,
|
|
1070
|
-
|
|
1071
|
-
|
|
611
|
+
options,
|
|
612
|
+
sessionId,
|
|
613
|
+
} as ListFilesRequest),
|
|
1072
614
|
headers: {
|
|
1073
615
|
"Content-Type": "application/json",
|
|
1074
616
|
},
|
|
@@ -1084,105 +626,24 @@ export class HttpClient {
|
|
|
1084
626
|
);
|
|
1085
627
|
}
|
|
1086
628
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
629
|
+
const data: ListFilesResponse = await response.json();
|
|
630
|
+
console.log(
|
|
631
|
+
`[HTTP Client] Listed ${data.files.length} files in: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
632
|
+
);
|
|
1090
633
|
|
|
1091
|
-
|
|
1092
|
-
const decoder = new TextDecoder();
|
|
1093
|
-
|
|
1094
|
-
try {
|
|
1095
|
-
while (true) {
|
|
1096
|
-
const { done, value } = await reader.read();
|
|
1097
|
-
|
|
1098
|
-
if (done) {
|
|
1099
|
-
break;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1103
|
-
const lines = chunk.split("\n");
|
|
1104
|
-
|
|
1105
|
-
for (const line of lines) {
|
|
1106
|
-
if (line.startsWith("data: ")) {
|
|
1107
|
-
try {
|
|
1108
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
1109
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
1110
|
-
|
|
1111
|
-
console.log(
|
|
1112
|
-
`[HTTP Client] Read file stream event: ${event.type}`
|
|
1113
|
-
);
|
|
1114
|
-
this.options.onStreamEvent?.(event);
|
|
1115
|
-
|
|
1116
|
-
switch (event.type) {
|
|
1117
|
-
case "command_start":
|
|
1118
|
-
console.log(
|
|
1119
|
-
`[HTTP Client] Read file started: ${event.path}`
|
|
1120
|
-
);
|
|
1121
|
-
this.options.onCommandStart?.("read", [path, encoding]);
|
|
1122
|
-
break;
|
|
1123
|
-
|
|
1124
|
-
case "command_complete":
|
|
1125
|
-
console.log(
|
|
1126
|
-
`[HTTP Client] Read file completed: ${
|
|
1127
|
-
event.path
|
|
1128
|
-
}, Success: ${event.success}, Content length: ${
|
|
1129
|
-
event.content?.length || 0
|
|
1130
|
-
}`
|
|
1131
|
-
);
|
|
1132
|
-
this.options.onCommandComplete?.(
|
|
1133
|
-
event.success!,
|
|
1134
|
-
0,
|
|
1135
|
-
event.content || "",
|
|
1136
|
-
"",
|
|
1137
|
-
"read",
|
|
1138
|
-
[path, encoding]
|
|
1139
|
-
);
|
|
1140
|
-
break;
|
|
1141
|
-
|
|
1142
|
-
case "error":
|
|
1143
|
-
console.error(
|
|
1144
|
-
`[HTTP Client] Read file error: ${event.error}`
|
|
1145
|
-
);
|
|
1146
|
-
this.options.onError?.(event.error!, "read", [
|
|
1147
|
-
path,
|
|
1148
|
-
encoding,
|
|
1149
|
-
]);
|
|
1150
|
-
break;
|
|
1151
|
-
}
|
|
1152
|
-
} catch (parseError) {
|
|
1153
|
-
console.warn(
|
|
1154
|
-
"[HTTP Client] Failed to parse read file stream event:",
|
|
1155
|
-
parseError
|
|
1156
|
-
);
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
} finally {
|
|
1162
|
-
reader.releaseLock();
|
|
1163
|
-
}
|
|
634
|
+
return data;
|
|
1164
635
|
} catch (error) {
|
|
1165
|
-
console.error("[HTTP Client] Error
|
|
1166
|
-
this.options.onError?.(
|
|
1167
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1168
|
-
"read",
|
|
1169
|
-
[path, encoding]
|
|
1170
|
-
);
|
|
636
|
+
console.error("[HTTP Client] Error listing files:", error);
|
|
1171
637
|
throw error;
|
|
1172
638
|
}
|
|
1173
639
|
}
|
|
1174
640
|
|
|
1175
|
-
async
|
|
1176
|
-
path: string,
|
|
1177
|
-
sessionId?: string
|
|
1178
|
-
): Promise<DeleteFileResponse> {
|
|
641
|
+
async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
|
|
1179
642
|
try {
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
const response = await this.doFetch(`/api/delete`, {
|
|
643
|
+
const response = await this.doFetch(`/api/expose-port`, {
|
|
1183
644
|
body: JSON.stringify({
|
|
1184
|
-
|
|
1185
|
-
|
|
645
|
+
port,
|
|
646
|
+
name,
|
|
1186
647
|
}),
|
|
1187
648
|
headers: {
|
|
1188
649
|
"Content-Type": "application/json",
|
|
@@ -1194,36 +655,36 @@ export class HttpClient {
|
|
|
1194
655
|
const errorData = (await response.json().catch(() => ({}))) as {
|
|
1195
656
|
error?: string;
|
|
1196
657
|
};
|
|
658
|
+
console.log(errorData);
|
|
1197
659
|
throw new Error(
|
|
1198
660
|
errorData.error || `HTTP error! status: ${response.status}`
|
|
1199
661
|
);
|
|
1200
662
|
}
|
|
1201
663
|
|
|
1202
|
-
const data:
|
|
664
|
+
const data: ExposePortResponse = await response.json();
|
|
1203
665
|
console.log(
|
|
1204
|
-
`[HTTP Client]
|
|
666
|
+
`[HTTP Client] Port exposed: ${port}${
|
|
667
|
+
name ? ` (${name})` : ""
|
|
668
|
+
}, Success: ${data.success}`
|
|
1205
669
|
);
|
|
1206
670
|
|
|
1207
671
|
return data;
|
|
1208
672
|
} catch (error) {
|
|
1209
|
-
console.error("[HTTP Client] Error
|
|
673
|
+
console.error("[HTTP Client] Error exposing port:", error);
|
|
1210
674
|
throw error;
|
|
1211
675
|
}
|
|
1212
676
|
}
|
|
1213
677
|
|
|
1214
|
-
async
|
|
678
|
+
async unexposePort(port: number): Promise<UnexposePortResponse> {
|
|
1215
679
|
try {
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
const response = await this.doFetch(`/api/delete/stream`, {
|
|
680
|
+
const response = await this.doFetch(`/api/unexpose-port`, {
|
|
1219
681
|
body: JSON.stringify({
|
|
1220
|
-
|
|
1221
|
-
sessionId: targetSessionId,
|
|
682
|
+
port,
|
|
1222
683
|
}),
|
|
1223
684
|
headers: {
|
|
1224
685
|
"Content-Type": "application/json",
|
|
1225
686
|
},
|
|
1226
|
-
method: "
|
|
687
|
+
method: "DELETE",
|
|
1227
688
|
});
|
|
1228
689
|
|
|
1229
690
|
if (!response.ok) {
|
|
@@ -1235,101 +696,89 @@ export class HttpClient {
|
|
|
1235
696
|
);
|
|
1236
697
|
}
|
|
1237
698
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
699
|
+
const data: UnexposePortResponse = await response.json();
|
|
700
|
+
console.log(
|
|
701
|
+
`[HTTP Client] Port unexposed: ${port}, Success: ${data.success}`
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
return data;
|
|
705
|
+
} catch (error) {
|
|
706
|
+
console.error("[HTTP Client] Error unexposing port:", error);
|
|
707
|
+
throw error;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
async getExposedPorts(): Promise<GetExposedPortsResponse> {
|
|
712
|
+
try {
|
|
713
|
+
const response = await this.doFetch(`/api/exposed-ports`, {
|
|
714
|
+
headers: {
|
|
715
|
+
"Content-Type": "application/json",
|
|
716
|
+
},
|
|
717
|
+
method: "GET",
|
|
718
|
+
});
|
|
1241
719
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
if (done) {
|
|
1250
|
-
break;
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1254
|
-
const lines = chunk.split("\n");
|
|
1255
|
-
|
|
1256
|
-
for (const line of lines) {
|
|
1257
|
-
if (line.startsWith("data: ")) {
|
|
1258
|
-
try {
|
|
1259
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
1260
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
1261
|
-
|
|
1262
|
-
console.log(
|
|
1263
|
-
`[HTTP Client] Delete file stream event: ${event.type}`
|
|
1264
|
-
);
|
|
1265
|
-
this.options.onStreamEvent?.(event);
|
|
1266
|
-
|
|
1267
|
-
switch (event.type) {
|
|
1268
|
-
case "command_start":
|
|
1269
|
-
console.log(
|
|
1270
|
-
`[HTTP Client] Delete file started: ${event.path}`
|
|
1271
|
-
);
|
|
1272
|
-
this.options.onCommandStart?.("delete", [path]);
|
|
1273
|
-
break;
|
|
1274
|
-
|
|
1275
|
-
case "command_complete":
|
|
1276
|
-
console.log(
|
|
1277
|
-
`[HTTP Client] Delete file completed: ${event.path}, Success: ${event.success}`
|
|
1278
|
-
);
|
|
1279
|
-
this.options.onCommandComplete?.(
|
|
1280
|
-
event.success!,
|
|
1281
|
-
0,
|
|
1282
|
-
"",
|
|
1283
|
-
"",
|
|
1284
|
-
"delete",
|
|
1285
|
-
[path]
|
|
1286
|
-
);
|
|
1287
|
-
break;
|
|
1288
|
-
|
|
1289
|
-
case "error":
|
|
1290
|
-
console.error(
|
|
1291
|
-
`[HTTP Client] Delete file error: ${event.error}`
|
|
1292
|
-
);
|
|
1293
|
-
this.options.onError?.(event.error!, "delete", [path]);
|
|
1294
|
-
break;
|
|
1295
|
-
}
|
|
1296
|
-
} catch (parseError) {
|
|
1297
|
-
console.warn(
|
|
1298
|
-
"[HTTP Client] Failed to parse delete file stream event:",
|
|
1299
|
-
parseError
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
} finally {
|
|
1306
|
-
reader.releaseLock();
|
|
720
|
+
if (!response.ok) {
|
|
721
|
+
const errorData = (await response.json().catch(() => ({}))) as {
|
|
722
|
+
error?: string;
|
|
723
|
+
};
|
|
724
|
+
throw new Error(
|
|
725
|
+
errorData.error || `HTTP error! status: ${response.status}`
|
|
726
|
+
);
|
|
1307
727
|
}
|
|
728
|
+
|
|
729
|
+
const data: GetExposedPortsResponse = await response.json();
|
|
730
|
+
console.log(`[HTTP Client] Got ${data.count} exposed ports`);
|
|
731
|
+
|
|
732
|
+
return data;
|
|
1308
733
|
} catch (error) {
|
|
1309
|
-
console.error("[HTTP Client] Error
|
|
1310
|
-
this.options.onError?.(
|
|
1311
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1312
|
-
"delete",
|
|
1313
|
-
[path]
|
|
1314
|
-
);
|
|
734
|
+
console.error("[HTTP Client] Error getting exposed ports:", error);
|
|
1315
735
|
throw error;
|
|
1316
736
|
}
|
|
1317
737
|
}
|
|
1318
738
|
|
|
1319
|
-
async
|
|
1320
|
-
oldPath: string,
|
|
1321
|
-
newPath: string,
|
|
1322
|
-
sessionId?: string
|
|
1323
|
-
): Promise<RenameFileResponse> {
|
|
739
|
+
async ping(): Promise<string> {
|
|
1324
740
|
try {
|
|
1325
|
-
const
|
|
741
|
+
const response = await this.doFetch(`/api/ping`, {
|
|
742
|
+
headers: {
|
|
743
|
+
"Content-Type": "application/json",
|
|
744
|
+
},
|
|
745
|
+
method: "GET",
|
|
746
|
+
});
|
|
1326
747
|
|
|
1327
|
-
|
|
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", {
|
|
1328
777
|
body: JSON.stringify({
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
}),
|
|
778
|
+
command,
|
|
779
|
+
sessionId,
|
|
780
|
+
options,
|
|
781
|
+
} as StartProcessRequest),
|
|
1333
782
|
headers: {
|
|
1334
783
|
"Content-Type": "application/json",
|
|
1335
784
|
},
|
|
@@ -1345,36 +794,28 @@ export class HttpClient {
|
|
|
1345
794
|
);
|
|
1346
795
|
}
|
|
1347
796
|
|
|
1348
|
-
const data:
|
|
797
|
+
const data: StartProcessResponse = await response.json();
|
|
1349
798
|
console.log(
|
|
1350
|
-
`[HTTP Client]
|
|
799
|
+
`[HTTP Client] Process started: ${command}, ID: ${data.process.id}`
|
|
1351
800
|
);
|
|
1352
801
|
|
|
1353
802
|
return data;
|
|
1354
803
|
} catch (error) {
|
|
1355
|
-
console.error("[HTTP Client] Error
|
|
804
|
+
console.error("[HTTP Client] Error starting process:", error);
|
|
1356
805
|
throw error;
|
|
1357
806
|
}
|
|
1358
807
|
}
|
|
1359
808
|
|
|
1360
|
-
async
|
|
1361
|
-
oldPath: string,
|
|
1362
|
-
newPath: string,
|
|
1363
|
-
sessionId?: string
|
|
1364
|
-
): Promise<void> {
|
|
809
|
+
async listProcesses(sessionId?: string): Promise<ListProcessesResponse> {
|
|
1365
810
|
try {
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
newPath,
|
|
1371
|
-
oldPath,
|
|
1372
|
-
sessionId: targetSessionId,
|
|
1373
|
-
}),
|
|
811
|
+
const url = sessionId
|
|
812
|
+
? `/api/process/list?session=${encodeURIComponent(sessionId)}`
|
|
813
|
+
: "/api/process/list";
|
|
814
|
+
const response = await this.doFetch(url, {
|
|
1374
815
|
headers: {
|
|
1375
816
|
"Content-Type": "application/json",
|
|
1376
817
|
},
|
|
1377
|
-
method: "
|
|
818
|
+
method: "GET",
|
|
1378
819
|
});
|
|
1379
820
|
|
|
1380
821
|
if (!response.ok) {
|
|
@@ -1386,108 +827,23 @@ export class HttpClient {
|
|
|
1386
827
|
);
|
|
1387
828
|
}
|
|
1388
829
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}
|
|
830
|
+
const data: ListProcessesResponse = await response.json();
|
|
831
|
+
console.log(`[HTTP Client] Listed ${data.processes.length} processes`);
|
|
1392
832
|
|
|
1393
|
-
|
|
1394
|
-
const decoder = new TextDecoder();
|
|
1395
|
-
|
|
1396
|
-
try {
|
|
1397
|
-
while (true) {
|
|
1398
|
-
const { done, value } = await reader.read();
|
|
1399
|
-
|
|
1400
|
-
if (done) {
|
|
1401
|
-
break;
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1405
|
-
const lines = chunk.split("\n");
|
|
1406
|
-
|
|
1407
|
-
for (const line of lines) {
|
|
1408
|
-
if (line.startsWith("data: ")) {
|
|
1409
|
-
try {
|
|
1410
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
1411
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
1412
|
-
|
|
1413
|
-
console.log(
|
|
1414
|
-
`[HTTP Client] Rename file stream event: ${event.type}`
|
|
1415
|
-
);
|
|
1416
|
-
this.options.onStreamEvent?.(event);
|
|
1417
|
-
|
|
1418
|
-
switch (event.type) {
|
|
1419
|
-
case "command_start":
|
|
1420
|
-
console.log(
|
|
1421
|
-
`[HTTP Client] Rename file started: ${event.oldPath} -> ${event.newPath}`
|
|
1422
|
-
);
|
|
1423
|
-
this.options.onCommandStart?.("rename", [oldPath, newPath]);
|
|
1424
|
-
break;
|
|
1425
|
-
|
|
1426
|
-
case "command_complete":
|
|
1427
|
-
console.log(
|
|
1428
|
-
`[HTTP Client] Rename file completed: ${event.oldPath} -> ${event.newPath}, Success: ${event.success}`
|
|
1429
|
-
);
|
|
1430
|
-
this.options.onCommandComplete?.(
|
|
1431
|
-
event.success!,
|
|
1432
|
-
0,
|
|
1433
|
-
"",
|
|
1434
|
-
"",
|
|
1435
|
-
"rename",
|
|
1436
|
-
[oldPath, newPath]
|
|
1437
|
-
);
|
|
1438
|
-
break;
|
|
1439
|
-
|
|
1440
|
-
case "error":
|
|
1441
|
-
console.error(
|
|
1442
|
-
`[HTTP Client] Rename file error: ${event.error}`
|
|
1443
|
-
);
|
|
1444
|
-
this.options.onError?.(event.error!, "rename", [
|
|
1445
|
-
oldPath,
|
|
1446
|
-
newPath,
|
|
1447
|
-
]);
|
|
1448
|
-
break;
|
|
1449
|
-
}
|
|
1450
|
-
} catch (parseError) {
|
|
1451
|
-
console.warn(
|
|
1452
|
-
"[HTTP Client] Failed to parse rename file stream event:",
|
|
1453
|
-
parseError
|
|
1454
|
-
);
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
} finally {
|
|
1460
|
-
reader.releaseLock();
|
|
1461
|
-
}
|
|
833
|
+
return data;
|
|
1462
834
|
} catch (error) {
|
|
1463
|
-
console.error("[HTTP Client] Error
|
|
1464
|
-
this.options.onError?.(
|
|
1465
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1466
|
-
"rename",
|
|
1467
|
-
[oldPath, newPath]
|
|
1468
|
-
);
|
|
835
|
+
console.error("[HTTP Client] Error listing processes:", error);
|
|
1469
836
|
throw error;
|
|
1470
837
|
}
|
|
1471
838
|
}
|
|
1472
839
|
|
|
1473
|
-
async
|
|
1474
|
-
sourcePath: string,
|
|
1475
|
-
destinationPath: string,
|
|
1476
|
-
sessionId?: string
|
|
1477
|
-
): Promise<MoveFileResponse> {
|
|
840
|
+
async getProcess(processId: string): Promise<GetProcessResponse> {
|
|
1478
841
|
try {
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
const response = await this.doFetch(`/api/move`, {
|
|
1482
|
-
body: JSON.stringify({
|
|
1483
|
-
destinationPath,
|
|
1484
|
-
sessionId: targetSessionId,
|
|
1485
|
-
sourcePath,
|
|
1486
|
-
}),
|
|
842
|
+
const response = await this.doFetch(`/api/process/${processId}`, {
|
|
1487
843
|
headers: {
|
|
1488
844
|
"Content-Type": "application/json",
|
|
1489
845
|
},
|
|
1490
|
-
method: "
|
|
846
|
+
method: "GET",
|
|
1491
847
|
});
|
|
1492
848
|
|
|
1493
849
|
if (!response.ok) {
|
|
@@ -1499,36 +855,29 @@ export class HttpClient {
|
|
|
1499
855
|
);
|
|
1500
856
|
}
|
|
1501
857
|
|
|
1502
|
-
const data:
|
|
858
|
+
const data: GetProcessResponse = await response.json();
|
|
1503
859
|
console.log(
|
|
1504
|
-
`[HTTP Client]
|
|
860
|
+
`[HTTP Client] Got process ${processId}: ${
|
|
861
|
+
data.process?.status || "not found"
|
|
862
|
+
}`
|
|
1505
863
|
);
|
|
1506
864
|
|
|
1507
865
|
return data;
|
|
1508
866
|
} catch (error) {
|
|
1509
|
-
console.error("[HTTP Client] Error
|
|
867
|
+
console.error("[HTTP Client] Error getting process:", error);
|
|
1510
868
|
throw error;
|
|
1511
869
|
}
|
|
1512
870
|
}
|
|
1513
871
|
|
|
1514
|
-
async
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
sessionId?: string
|
|
1518
|
-
): Promise<void> {
|
|
872
|
+
async killProcess(
|
|
873
|
+
processId: string
|
|
874
|
+
): Promise<{ success: boolean; message: string }> {
|
|
1519
875
|
try {
|
|
1520
|
-
const
|
|
1521
|
-
|
|
1522
|
-
const response = await this.doFetch(`/api/move/stream`, {
|
|
1523
|
-
body: JSON.stringify({
|
|
1524
|
-
destinationPath,
|
|
1525
|
-
sessionId: targetSessionId,
|
|
1526
|
-
sourcePath,
|
|
1527
|
-
}),
|
|
876
|
+
const response = await this.doFetch(`/api/process/${processId}`, {
|
|
1528
877
|
headers: {
|
|
1529
878
|
"Content-Type": "application/json",
|
|
1530
879
|
},
|
|
1531
|
-
method: "
|
|
880
|
+
method: "DELETE",
|
|
1532
881
|
});
|
|
1533
882
|
|
|
1534
883
|
if (!response.ok) {
|
|
@@ -1540,118 +889,61 @@ export class HttpClient {
|
|
|
1540
889
|
);
|
|
1541
890
|
}
|
|
1542
891
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
892
|
+
const data = (await response.json()) as {
|
|
893
|
+
success: boolean;
|
|
894
|
+
message: string;
|
|
895
|
+
};
|
|
896
|
+
console.log(`[HTTP Client] Killed process ${processId}`);
|
|
1546
897
|
|
|
1547
|
-
|
|
1548
|
-
const decoder = new TextDecoder();
|
|
1549
|
-
|
|
1550
|
-
try {
|
|
1551
|
-
while (true) {
|
|
1552
|
-
const { done, value } = await reader.read();
|
|
1553
|
-
|
|
1554
|
-
if (done) {
|
|
1555
|
-
break;
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1559
|
-
const lines = chunk.split("\n");
|
|
1560
|
-
|
|
1561
|
-
for (const line of lines) {
|
|
1562
|
-
if (line.startsWith("data: ")) {
|
|
1563
|
-
try {
|
|
1564
|
-
const eventData = line.slice(6); // Remove 'data: ' prefix
|
|
1565
|
-
const event: StreamEvent = JSON.parse(eventData);
|
|
1566
|
-
|
|
1567
|
-
console.log(
|
|
1568
|
-
`[HTTP Client] Move file stream event: ${event.type}`
|
|
1569
|
-
);
|
|
1570
|
-
this.options.onStreamEvent?.(event);
|
|
1571
|
-
|
|
1572
|
-
switch (event.type) {
|
|
1573
|
-
case "command_start":
|
|
1574
|
-
console.log(
|
|
1575
|
-
`[HTTP Client] Move file started: ${event.sourcePath} -> ${event.destinationPath}`
|
|
1576
|
-
);
|
|
1577
|
-
this.options.onCommandStart?.("move", [
|
|
1578
|
-
sourcePath,
|
|
1579
|
-
destinationPath,
|
|
1580
|
-
]);
|
|
1581
|
-
break;
|
|
1582
|
-
|
|
1583
|
-
case "command_complete":
|
|
1584
|
-
console.log(
|
|
1585
|
-
`[HTTP Client] Move file completed: ${event.sourcePath} -> ${event.destinationPath}, Success: ${event.success}`
|
|
1586
|
-
);
|
|
1587
|
-
this.options.onCommandComplete?.(
|
|
1588
|
-
event.success!,
|
|
1589
|
-
0,
|
|
1590
|
-
"",
|
|
1591
|
-
"",
|
|
1592
|
-
"move",
|
|
1593
|
-
[sourcePath, destinationPath]
|
|
1594
|
-
);
|
|
1595
|
-
break;
|
|
1596
|
-
|
|
1597
|
-
case "error":
|
|
1598
|
-
console.error(
|
|
1599
|
-
`[HTTP Client] Move file error: ${event.error}`
|
|
1600
|
-
);
|
|
1601
|
-
this.options.onError?.(event.error!, "move", [
|
|
1602
|
-
sourcePath,
|
|
1603
|
-
destinationPath,
|
|
1604
|
-
]);
|
|
1605
|
-
break;
|
|
1606
|
-
}
|
|
1607
|
-
} catch (parseError) {
|
|
1608
|
-
console.warn(
|
|
1609
|
-
"[HTTP Client] Failed to parse move file stream event:",
|
|
1610
|
-
parseError
|
|
1611
|
-
);
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
} finally {
|
|
1617
|
-
reader.releaseLock();
|
|
1618
|
-
}
|
|
898
|
+
return data;
|
|
1619
899
|
} catch (error) {
|
|
1620
|
-
console.error("[HTTP Client] Error
|
|
1621
|
-
this.options.onError?.(
|
|
1622
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
1623
|
-
"move",
|
|
1624
|
-
[sourcePath, destinationPath]
|
|
1625
|
-
);
|
|
900
|
+
console.error("[HTTP Client] Error killing process:", error);
|
|
1626
901
|
throw error;
|
|
1627
902
|
}
|
|
1628
903
|
}
|
|
1629
904
|
|
|
1630
|
-
async
|
|
905
|
+
async killAllProcesses(sessionId?: string): Promise<{
|
|
906
|
+
success: boolean;
|
|
907
|
+
killedCount: number;
|
|
908
|
+
message: string;
|
|
909
|
+
}> {
|
|
1631
910
|
try {
|
|
1632
|
-
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, {
|
|
1633
915
|
headers: {
|
|
1634
916
|
"Content-Type": "application/json",
|
|
1635
917
|
},
|
|
1636
|
-
method: "
|
|
918
|
+
method: "DELETE",
|
|
1637
919
|
});
|
|
1638
920
|
|
|
1639
921
|
if (!response.ok) {
|
|
1640
|
-
|
|
922
|
+
const errorData = (await response.json().catch(() => ({}))) as {
|
|
923
|
+
error?: string;
|
|
924
|
+
};
|
|
925
|
+
throw new Error(
|
|
926
|
+
errorData.error || `HTTP error! status: ${response.status}`
|
|
927
|
+
);
|
|
1641
928
|
}
|
|
1642
929
|
|
|
1643
|
-
const data
|
|
1644
|
-
|
|
1645
|
-
|
|
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`);
|
|
936
|
+
|
|
937
|
+
return data;
|
|
1646
938
|
} catch (error) {
|
|
1647
|
-
console.error("[HTTP Client] Error
|
|
939
|
+
console.error("[HTTP Client] Error killing all processes:", error);
|
|
1648
940
|
throw error;
|
|
1649
941
|
}
|
|
1650
942
|
}
|
|
1651
943
|
|
|
1652
|
-
async
|
|
944
|
+
async getProcessLogs(processId: string): Promise<GetProcessLogsResponse> {
|
|
1653
945
|
try {
|
|
1654
|
-
const response = await
|
|
946
|
+
const response = await this.doFetch(`/api/process/${processId}/logs`, {
|
|
1655
947
|
headers: {
|
|
1656
948
|
"Content-Type": "application/json",
|
|
1657
949
|
},
|
|
@@ -1659,292 +951,59 @@ export class HttpClient {
|
|
|
1659
951
|
});
|
|
1660
952
|
|
|
1661
953
|
if (!response.ok) {
|
|
1662
|
-
|
|
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
|
+
);
|
|
1663
960
|
}
|
|
1664
961
|
|
|
1665
|
-
const data:
|
|
1666
|
-
console.log(
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
return data.availableCommands;
|
|
962
|
+
const data: GetProcessLogsResponse = await response.json();
|
|
963
|
+
console.log(`[HTTP Client] Got logs for process ${processId}`);
|
|
964
|
+
|
|
965
|
+
return data;
|
|
1670
966
|
} catch (error) {
|
|
1671
|
-
console.error("[HTTP Client] Error getting
|
|
967
|
+
console.error("[HTTP Client] Error getting process logs:", error);
|
|
1672
968
|
throw error;
|
|
1673
969
|
}
|
|
1674
970
|
}
|
|
1675
971
|
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
// Example usage and utility functions
|
|
1690
|
-
export function createClient(options?: HttpClientOptions): HttpClient {
|
|
1691
|
-
return new HttpClient(options);
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
// Convenience function for quick command execution
|
|
1695
|
-
export async function quickExecute(
|
|
1696
|
-
command: string,
|
|
1697
|
-
args: string[] = [],
|
|
1698
|
-
options?: HttpClientOptions
|
|
1699
|
-
): Promise<ExecuteResponse> {
|
|
1700
|
-
const client = createClient(options);
|
|
1701
|
-
await client.createSession();
|
|
1702
|
-
|
|
1703
|
-
try {
|
|
1704
|
-
return await client.execute(command, args);
|
|
1705
|
-
} finally {
|
|
1706
|
-
client.clearSession();
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
// Convenience function for quick streaming command execution
|
|
1711
|
-
export async function quickExecuteStream(
|
|
1712
|
-
command: string,
|
|
1713
|
-
args: string[] = [],
|
|
1714
|
-
options?: HttpClientOptions
|
|
1715
|
-
): Promise<void> {
|
|
1716
|
-
const client = createClient(options);
|
|
1717
|
-
await client.createSession();
|
|
1718
|
-
|
|
1719
|
-
try {
|
|
1720
|
-
await client.executeStream(command, args);
|
|
1721
|
-
} finally {
|
|
1722
|
-
client.clearSession();
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
// Convenience function for quick git checkout
|
|
1727
|
-
export async function quickGitCheckout(
|
|
1728
|
-
repoUrl: string,
|
|
1729
|
-
branch: string = "main",
|
|
1730
|
-
targetDir?: string,
|
|
1731
|
-
options?: HttpClientOptions
|
|
1732
|
-
): Promise<GitCheckoutResponse> {
|
|
1733
|
-
const client = createClient(options);
|
|
1734
|
-
await client.createSession();
|
|
1735
|
-
|
|
1736
|
-
try {
|
|
1737
|
-
return await client.gitCheckout(repoUrl, branch, targetDir);
|
|
1738
|
-
} finally {
|
|
1739
|
-
client.clearSession();
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
// Convenience function for quick directory creation
|
|
1744
|
-
export async function quickMkdir(
|
|
1745
|
-
path: string,
|
|
1746
|
-
recursive: boolean = false,
|
|
1747
|
-
options?: HttpClientOptions
|
|
1748
|
-
): Promise<MkdirResponse> {
|
|
1749
|
-
const client = createClient(options);
|
|
1750
|
-
await client.createSession();
|
|
1751
|
-
|
|
1752
|
-
try {
|
|
1753
|
-
return await client.mkdir(path, recursive);
|
|
1754
|
-
} finally {
|
|
1755
|
-
client.clearSession();
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
|
|
1759
|
-
// Convenience function for quick streaming git checkout
|
|
1760
|
-
export async function quickGitCheckoutStream(
|
|
1761
|
-
repoUrl: string,
|
|
1762
|
-
branch: string = "main",
|
|
1763
|
-
targetDir?: string,
|
|
1764
|
-
options?: HttpClientOptions
|
|
1765
|
-
): Promise<void> {
|
|
1766
|
-
const client = createClient(options);
|
|
1767
|
-
await client.createSession();
|
|
1768
|
-
|
|
1769
|
-
try {
|
|
1770
|
-
await client.gitCheckoutStream(repoUrl, branch, targetDir);
|
|
1771
|
-
} finally {
|
|
1772
|
-
client.clearSession();
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
// Convenience function for quick streaming directory creation
|
|
1777
|
-
export async function quickMkdirStream(
|
|
1778
|
-
path: string,
|
|
1779
|
-
recursive: boolean = false,
|
|
1780
|
-
options?: HttpClientOptions
|
|
1781
|
-
): Promise<void> {
|
|
1782
|
-
const client = createClient(options);
|
|
1783
|
-
await client.createSession();
|
|
1784
|
-
|
|
1785
|
-
try {
|
|
1786
|
-
await client.mkdirStream(path, recursive);
|
|
1787
|
-
} finally {
|
|
1788
|
-
client.clearSession();
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
// Convenience function for quick file writing
|
|
1793
|
-
export async function quickWriteFile(
|
|
1794
|
-
path: string,
|
|
1795
|
-
content: string,
|
|
1796
|
-
encoding: string = "utf-8",
|
|
1797
|
-
options?: HttpClientOptions
|
|
1798
|
-
): Promise<WriteFileResponse> {
|
|
1799
|
-
const client = createClient(options);
|
|
1800
|
-
await client.createSession();
|
|
1801
|
-
|
|
1802
|
-
try {
|
|
1803
|
-
return await client.writeFile(path, content, encoding);
|
|
1804
|
-
} finally {
|
|
1805
|
-
client.clearSession();
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
// Convenience function for quick streaming file writing
|
|
1810
|
-
export async function quickWriteFileStream(
|
|
1811
|
-
path: string,
|
|
1812
|
-
content: string,
|
|
1813
|
-
encoding: string = "utf-8",
|
|
1814
|
-
options?: HttpClientOptions
|
|
1815
|
-
): Promise<void> {
|
|
1816
|
-
const client = createClient(options);
|
|
1817
|
-
await client.createSession();
|
|
1818
|
-
|
|
1819
|
-
try {
|
|
1820
|
-
await client.writeFileStream(path, content, encoding);
|
|
1821
|
-
} finally {
|
|
1822
|
-
client.clearSession();
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
// Convenience function for quick file reading
|
|
1827
|
-
export async function quickReadFile(
|
|
1828
|
-
path: string,
|
|
1829
|
-
encoding: string = "utf-8",
|
|
1830
|
-
options?: HttpClientOptions
|
|
1831
|
-
): Promise<ReadFileResponse> {
|
|
1832
|
-
const client = createClient(options);
|
|
1833
|
-
await client.createSession();
|
|
1834
|
-
|
|
1835
|
-
try {
|
|
1836
|
-
return await client.readFile(path, encoding);
|
|
1837
|
-
} finally {
|
|
1838
|
-
client.clearSession();
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
// Convenience function for quick streaming file reading
|
|
1843
|
-
export async function quickReadFileStream(
|
|
1844
|
-
path: string,
|
|
1845
|
-
encoding: string = "utf-8",
|
|
1846
|
-
options?: HttpClientOptions
|
|
1847
|
-
): Promise<void> {
|
|
1848
|
-
const client = createClient(options);
|
|
1849
|
-
await client.createSession();
|
|
1850
|
-
|
|
1851
|
-
try {
|
|
1852
|
-
await client.readFileStream(path, encoding);
|
|
1853
|
-
} finally {
|
|
1854
|
-
client.clearSession();
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
// Convenience function for quick file deletion
|
|
1859
|
-
export async function quickDeleteFile(
|
|
1860
|
-
path: string,
|
|
1861
|
-
options?: HttpClientOptions
|
|
1862
|
-
): Promise<DeleteFileResponse> {
|
|
1863
|
-
const client = createClient(options);
|
|
1864
|
-
await client.createSession();
|
|
1865
|
-
|
|
1866
|
-
try {
|
|
1867
|
-
return await client.deleteFile(path);
|
|
1868
|
-
} finally {
|
|
1869
|
-
client.clearSession();
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
// Convenience function for quick streaming file deletion
|
|
1874
|
-
export async function quickDeleteFileStream(
|
|
1875
|
-
path: string,
|
|
1876
|
-
options?: HttpClientOptions
|
|
1877
|
-
): Promise<void> {
|
|
1878
|
-
const client = createClient(options);
|
|
1879
|
-
await client.createSession();
|
|
1880
|
-
|
|
1881
|
-
try {
|
|
1882
|
-
await client.deleteFileStream(path);
|
|
1883
|
-
} finally {
|
|
1884
|
-
client.clearSession();
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
972
|
+
async streamProcessLogs(
|
|
973
|
+
processId: string,
|
|
974
|
+
options?: { signal?: AbortSignal }
|
|
975
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
976
|
+
try {
|
|
977
|
+
const response = await this.doFetch(`/api/process/${processId}/stream`, {
|
|
978
|
+
headers: {
|
|
979
|
+
Accept: "text/event-stream",
|
|
980
|
+
"Cache-Control": "no-cache",
|
|
981
|
+
},
|
|
982
|
+
method: "GET",
|
|
983
|
+
signal: options?.signal,
|
|
984
|
+
});
|
|
1887
985
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
try {
|
|
1898
|
-
return await client.renameFile(oldPath, newPath);
|
|
1899
|
-
} finally {
|
|
1900
|
-
client.clearSession();
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
986
|
+
if (!response.ok) {
|
|
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
|
+
}
|
|
1903
994
|
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
newPath: string,
|
|
1908
|
-
options?: HttpClientOptions
|
|
1909
|
-
): Promise<void> {
|
|
1910
|
-
const client = createClient(options);
|
|
1911
|
-
await client.createSession();
|
|
1912
|
-
|
|
1913
|
-
try {
|
|
1914
|
-
await client.renameFileStream(oldPath, newPath);
|
|
1915
|
-
} finally {
|
|
1916
|
-
client.clearSession();
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
995
|
+
if (!response.body) {
|
|
996
|
+
throw new Error("No response body for streaming request");
|
|
997
|
+
}
|
|
1919
998
|
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
destinationPath: string,
|
|
1924
|
-
options?: HttpClientOptions
|
|
1925
|
-
): Promise<MoveFileResponse> {
|
|
1926
|
-
const client = createClient(options);
|
|
1927
|
-
await client.createSession();
|
|
1928
|
-
|
|
1929
|
-
try {
|
|
1930
|
-
return await client.moveFile(sourcePath, destinationPath);
|
|
1931
|
-
} finally {
|
|
1932
|
-
client.clearSession();
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
999
|
+
console.log(
|
|
1000
|
+
`[HTTP Client] Started streaming logs for process ${processId}`
|
|
1001
|
+
);
|
|
1935
1002
|
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
): Promise<void> {
|
|
1942
|
-
const client = createClient(options);
|
|
1943
|
-
await client.createSession();
|
|
1944
|
-
|
|
1945
|
-
try {
|
|
1946
|
-
await client.moveFileStream(sourcePath, destinationPath);
|
|
1947
|
-
} finally {
|
|
1948
|
-
client.clearSession();
|
|
1003
|
+
return response.body;
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
console.error("[HTTP Client] Error streaming process logs:", error);
|
|
1006
|
+
throw error;
|
|
1007
|
+
}
|
|
1949
1008
|
}
|
|
1950
1009
|
}
|