@stacknet/stacks 0.2.0 → 0.2.2
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/README.md +136 -0
- package/dist/{billing-eQZIWeNW.d.cts → billing-cj0eSVrp.d.cts} +59 -1
- package/dist/{billing-eQZIWeNW.d.ts → billing-cj0eSVrp.d.ts} +59 -1
- package/dist/clients/index.cjs +4 -4
- package/dist/clients/index.d.cts +24 -1
- package/dist/clients/index.d.ts +24 -1
- package/dist/clients/index.js +4 -4
- package/dist/index.cjs +7 -7
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -7
- package/dist/proxy/index.cjs +2 -2
- package/dist/proxy/index.js +2 -2
- package/dist/streaming/index.cjs +5 -5
- package/dist/streaming/index.js +5 -5
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +15 -13
- package/src/clients/agents.ts +0 -250
- package/src/clients/billing.ts +0 -197
- package/src/clients/coder.ts +0 -655
- package/src/clients/files.ts +0 -86
- package/src/clients/index.ts +0 -93
- package/src/clients/magma.ts +0 -299
- package/src/clients/mcp.ts +0 -208
- package/src/clients/network.ts +0 -118
- package/src/clients/points.ts +0 -403
- package/src/clients/skills.ts +0 -236
- package/src/clients/social.ts +0 -286
- package/src/clients/stack-management.ts +0 -279
- package/src/clients/task-network.ts +0 -303
- package/src/clients/user.ts +0 -84
- package/src/clients/widgets.ts +0 -171
- package/src/index.ts +0 -387
- package/src/managers/index.ts +0 -10
- package/src/managers/task-manager.ts +0 -332
- package/src/proxy/forwarder.ts +0 -235
- package/src/proxy/index.ts +0 -32
- package/src/proxy/route-handlers.ts +0 -1107
- package/src/streaming/component-stream.ts +0 -319
- package/src/streaming/index.ts +0 -21
- package/src/streaming/sse.ts +0 -266
- package/src/types/agent.ts +0 -108
- package/src/types/billing.ts +0 -121
- package/src/types/chat.ts +0 -58
- package/src/types/coder.ts +0 -345
- package/src/types/credential.ts +0 -111
- package/src/types/file.ts +0 -15
- package/src/types/imagination.ts +0 -50
- package/src/types/index.ts +0 -20
- package/src/types/mcp.ts +0 -35
- package/src/types/network.ts +0 -97
- package/src/types/points.ts +0 -250
- package/src/types/skill.ts +0 -107
- package/src/types/social.ts +0 -109
- package/src/types/stack.ts +0 -269
- package/src/types/task.ts +0 -41
- package/src/types/user.ts +0 -29
- package/src/types/widget.ts +0 -57
- package/src/utils/constants.ts +0 -26
- package/src/utils/errors.ts +0 -169
- package/src/utils/helpers.ts +0 -85
- package/src/utils/index.ts +0 -7
package/src/clients/coder.ts
DELETED
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Coder Client
|
|
3
|
-
* Client for interacting with the GeoffCoder AI coding agent API
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { DEFAULT_TASK_NETWORK_URL, JSON_HEADERS, SSE_HEADERS } from '../utils/constants';
|
|
7
|
-
import { StacksSDKError } from '../utils/errors';
|
|
8
|
-
import type {
|
|
9
|
-
CoderClientConfig,
|
|
10
|
-
CoderSession,
|
|
11
|
-
CoderSessionResponse,
|
|
12
|
-
CoderSessionsListResponse,
|
|
13
|
-
CoderExecuteRequest,
|
|
14
|
-
CoderExecuteResponse,
|
|
15
|
-
CoderStreamEvent,
|
|
16
|
-
CoderTool,
|
|
17
|
-
CoderToolsResponse,
|
|
18
|
-
CoderFileInfo,
|
|
19
|
-
CoderFileContent,
|
|
20
|
-
CoderFileWriteInput,
|
|
21
|
-
CoderFilesResponse,
|
|
22
|
-
CoderSearchResult,
|
|
23
|
-
CoderDiffInput,
|
|
24
|
-
CoderCommandInput,
|
|
25
|
-
CoderCommandResult,
|
|
26
|
-
CoderSandbox,
|
|
27
|
-
CoderSandboxCreateInput,
|
|
28
|
-
CoderSandboxResponse,
|
|
29
|
-
CoderSandboxExecInput,
|
|
30
|
-
CoderSandboxExecResult,
|
|
31
|
-
CoderToolResult,
|
|
32
|
-
} from '../types/coder';
|
|
33
|
-
|
|
34
|
-
export type { CoderClientConfig } from '../types/coder';
|
|
35
|
-
|
|
36
|
-
export class CoderClient {
|
|
37
|
-
private baseUrl: string;
|
|
38
|
-
private apiKey?: string;
|
|
39
|
-
private timeout: number;
|
|
40
|
-
private defaultModel: string;
|
|
41
|
-
private defaultMaxIterations: number;
|
|
42
|
-
|
|
43
|
-
constructor(config: CoderClientConfig = {}) {
|
|
44
|
-
this.baseUrl = config.baseUrl || DEFAULT_TASK_NETWORK_URL;
|
|
45
|
-
this.apiKey = config.apiKey;
|
|
46
|
-
this.timeout = config.timeout || 300000; // 5 minutes default
|
|
47
|
-
this.defaultModel = config.defaultModel || 'geoff-code-1:1';
|
|
48
|
-
this.defaultMaxIterations = config.defaultMaxIterations || 20;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private get coderUrl(): string {
|
|
52
|
-
return `${this.baseUrl}/coder`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private get headers(): HeadersInit {
|
|
56
|
-
const headers: HeadersInit = { ...JSON_HEADERS };
|
|
57
|
-
if (this.apiKey) {
|
|
58
|
-
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
|
59
|
-
}
|
|
60
|
-
return headers;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ============================================================================
|
|
64
|
-
// Session Management
|
|
65
|
-
// ============================================================================
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Create a new coder session
|
|
69
|
-
*/
|
|
70
|
-
async createSession(workingDirectory: string, sandboxConfig?: CoderSandboxCreateInput): Promise<CoderSession> {
|
|
71
|
-
const response = await fetch(`${this.coderUrl}/sessions`, {
|
|
72
|
-
method: 'POST',
|
|
73
|
-
headers: this.headers,
|
|
74
|
-
body: JSON.stringify({
|
|
75
|
-
workingDirectory,
|
|
76
|
-
sandbox: sandboxConfig,
|
|
77
|
-
}),
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
if (!response.ok) {
|
|
81
|
-
const data = await response.json().catch(() => ({}));
|
|
82
|
-
throw new StacksSDKError(
|
|
83
|
-
'bad_request:api',
|
|
84
|
-
data.error || `Failed to create coder session: ${response.statusText}`
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const result: CoderSessionResponse = await response.json();
|
|
89
|
-
return result.session;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Get a session by ID
|
|
94
|
-
*/
|
|
95
|
-
async getSession(sessionId: string): Promise<CoderSession> {
|
|
96
|
-
const response = await fetch(`${this.coderUrl}/sessions/${sessionId}`, {
|
|
97
|
-
headers: this.headers,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
throw new StacksSDKError(
|
|
102
|
-
response.status === 404 ? 'not_found:api' : 'bad_request:api',
|
|
103
|
-
`Failed to get coder session: ${response.statusText}`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const result: CoderSessionResponse = await response.json();
|
|
108
|
-
return result.session;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* List all sessions
|
|
113
|
-
*/
|
|
114
|
-
async listSessions(options: { status?: string; limit?: number } = {}): Promise<CoderSession[]> {
|
|
115
|
-
const params = new URLSearchParams();
|
|
116
|
-
if (options.status) params.set('status', options.status);
|
|
117
|
-
if (options.limit) params.set('limit', options.limit.toString());
|
|
118
|
-
|
|
119
|
-
const queryString = params.toString();
|
|
120
|
-
const url = `${this.coderUrl}/sessions${queryString ? `?${queryString}` : ''}`;
|
|
121
|
-
|
|
122
|
-
const response = await fetch(url, { headers: this.headers });
|
|
123
|
-
|
|
124
|
-
if (!response.ok) {
|
|
125
|
-
throw new StacksSDKError(
|
|
126
|
-
'bad_request:api',
|
|
127
|
-
`Failed to list coder sessions: ${response.statusText}`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const result: CoderSessionsListResponse = await response.json();
|
|
132
|
-
return result.sessions;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Abort a running session
|
|
137
|
-
*/
|
|
138
|
-
async abortSession(sessionId: string): Promise<CoderSession> {
|
|
139
|
-
const response = await fetch(`${this.coderUrl}/sessions/${sessionId}/abort`, {
|
|
140
|
-
method: 'POST',
|
|
141
|
-
headers: this.headers,
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
if (!response.ok) {
|
|
145
|
-
throw new StacksSDKError(
|
|
146
|
-
'bad_request:api',
|
|
147
|
-
`Failed to abort coder session: ${response.statusText}`
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const result: CoderSessionResponse = await response.json();
|
|
152
|
-
return result.session;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ============================================================================
|
|
156
|
-
// Execution
|
|
157
|
-
// ============================================================================
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Execute a coder prompt (non-streaming)
|
|
161
|
-
*/
|
|
162
|
-
async execute(request: CoderExecuteRequest): Promise<CoderExecuteResponse> {
|
|
163
|
-
const payload = {
|
|
164
|
-
prompt: request.prompt,
|
|
165
|
-
workingDirectory: request.workingDirectory,
|
|
166
|
-
maxIterations: request.maxIterations || this.defaultMaxIterations,
|
|
167
|
-
model: request.model || this.defaultModel,
|
|
168
|
-
maxTokens: request.maxTokens,
|
|
169
|
-
temperature: request.temperature,
|
|
170
|
-
sessionId: request.sessionId,
|
|
171
|
-
sandboxId: request.sandboxId,
|
|
172
|
-
sandbox: request.sandbox,
|
|
173
|
-
stream: false,
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
const response = await fetch(`${this.coderUrl}/execute`, {
|
|
177
|
-
method: 'POST',
|
|
178
|
-
headers: this.headers,
|
|
179
|
-
body: JSON.stringify(payload),
|
|
180
|
-
signal: AbortSignal.timeout(this.timeout),
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
if (!response.ok) {
|
|
184
|
-
const data = await response.json().catch(() => ({}));
|
|
185
|
-
throw new StacksSDKError(
|
|
186
|
-
'bad_request:api',
|
|
187
|
-
data.error || `Failed to execute coder: ${response.statusText}`
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return response.json();
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Execute a coder prompt with streaming
|
|
196
|
-
*/
|
|
197
|
-
async *executeStream(request: CoderExecuteRequest): AsyncGenerator<CoderStreamEvent, void, unknown> {
|
|
198
|
-
const payload = {
|
|
199
|
-
prompt: request.prompt,
|
|
200
|
-
workingDirectory: request.workingDirectory,
|
|
201
|
-
maxIterations: request.maxIterations || this.defaultMaxIterations,
|
|
202
|
-
model: request.model || this.defaultModel,
|
|
203
|
-
maxTokens: request.maxTokens,
|
|
204
|
-
temperature: request.temperature,
|
|
205
|
-
sessionId: request.sessionId,
|
|
206
|
-
sandboxId: request.sandboxId,
|
|
207
|
-
sandbox: request.sandbox,
|
|
208
|
-
stream: true,
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
// Use abort controller with longer timeout for SSE streams
|
|
212
|
-
const controller = new AbortController();
|
|
213
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
214
|
-
|
|
215
|
-
const response = await fetch(`${this.coderUrl}/execute`, {
|
|
216
|
-
method: 'POST',
|
|
217
|
-
headers: {
|
|
218
|
-
...this.headers,
|
|
219
|
-
'Accept': 'text/event-stream',
|
|
220
|
-
'Connection': 'keep-alive',
|
|
221
|
-
'Cache-Control': 'no-cache',
|
|
222
|
-
},
|
|
223
|
-
body: JSON.stringify(payload),
|
|
224
|
-
signal: controller.signal,
|
|
225
|
-
// @ts-ignore - undici-specific option for keep-alive
|
|
226
|
-
keepalive: true,
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
if (!response.ok) {
|
|
230
|
-
const data = await response.json().catch(() => ({}));
|
|
231
|
-
throw new StacksSDKError(
|
|
232
|
-
'bad_request:api',
|
|
233
|
-
data.error || `Failed to execute coder stream: ${response.statusText}`
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const reader = response.body?.getReader();
|
|
238
|
-
if (!reader) {
|
|
239
|
-
throw new StacksSDKError('bad_request:stream', 'No response body');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const decoder = new TextDecoder();
|
|
243
|
-
let buffer = '';
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
while (true) {
|
|
247
|
-
const { done, value } = await reader.read();
|
|
248
|
-
if (done) break;
|
|
249
|
-
|
|
250
|
-
buffer += decoder.decode(value, { stream: true });
|
|
251
|
-
const lines = buffer.split('\n');
|
|
252
|
-
buffer = lines.pop() || '';
|
|
253
|
-
|
|
254
|
-
for (const line of lines) {
|
|
255
|
-
if (line.startsWith('data: ')) {
|
|
256
|
-
const data = line.slice(6);
|
|
257
|
-
if (data === '[DONE]') return;
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const event: CoderStreamEvent = JSON.parse(data);
|
|
261
|
-
yield event;
|
|
262
|
-
} catch {
|
|
263
|
-
// Skip malformed JSON
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
} finally {
|
|
269
|
-
clearTimeout(timeoutId);
|
|
270
|
-
reader.releaseLock();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// ============================================================================
|
|
275
|
-
// Tool Operations (Direct tool calls without agentic loop)
|
|
276
|
-
// ============================================================================
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Get available coder tools
|
|
280
|
-
*/
|
|
281
|
-
async getTools(): Promise<CoderTool[]> {
|
|
282
|
-
const response = await fetch(`${this.coderUrl}/tools`, {
|
|
283
|
-
headers: this.headers,
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
if (!response.ok) {
|
|
287
|
-
throw new StacksSDKError(
|
|
288
|
-
'bad_request:api',
|
|
289
|
-
`Failed to get coder tools: ${response.statusText}`
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const result: CoderToolsResponse = await response.json();
|
|
294
|
-
return result.tools;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Execute a specific tool directly
|
|
299
|
-
*/
|
|
300
|
-
async callTool(
|
|
301
|
-
toolName: string,
|
|
302
|
-
args: Record<string, unknown>,
|
|
303
|
-
options: { sessionId?: string; sandboxId?: string } = {}
|
|
304
|
-
): Promise<CoderToolResult> {
|
|
305
|
-
const response = await fetch(`${this.coderUrl}/tools/${toolName}`, {
|
|
306
|
-
method: 'POST',
|
|
307
|
-
headers: this.headers,
|
|
308
|
-
body: JSON.stringify({
|
|
309
|
-
arguments: args,
|
|
310
|
-
sessionId: options.sessionId,
|
|
311
|
-
sandboxId: options.sandboxId,
|
|
312
|
-
}),
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
if (!response.ok) {
|
|
316
|
-
const data = await response.json().catch(() => ({}));
|
|
317
|
-
throw new StacksSDKError(
|
|
318
|
-
'bad_request:api',
|
|
319
|
-
data.error || `Failed to call tool ${toolName}: ${response.statusText}`
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return response.json();
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// ============================================================================
|
|
327
|
-
// File Operations
|
|
328
|
-
// ============================================================================
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Read a file
|
|
332
|
-
*/
|
|
333
|
-
async readFile(path: string, options: { sessionId?: string; sandboxId?: string } = {}): Promise<CoderFileContent> {
|
|
334
|
-
const params = new URLSearchParams({ path });
|
|
335
|
-
if (options.sessionId) params.set('sessionId', options.sessionId);
|
|
336
|
-
if (options.sandboxId) params.set('sandboxId', options.sandboxId);
|
|
337
|
-
|
|
338
|
-
const response = await fetch(`${this.coderUrl}/files/read?${params}`, {
|
|
339
|
-
headers: this.headers,
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
if (!response.ok) {
|
|
343
|
-
throw new StacksSDKError(
|
|
344
|
-
response.status === 404 ? 'not_found:api' : 'bad_request:api',
|
|
345
|
-
`Failed to read file: ${response.statusText}`
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return response.json();
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Write a file
|
|
354
|
-
*/
|
|
355
|
-
async writeFile(
|
|
356
|
-
input: CoderFileWriteInput,
|
|
357
|
-
options: { sessionId?: string; sandboxId?: string } = {}
|
|
358
|
-
): Promise<{ success: boolean; path: string }> {
|
|
359
|
-
const response = await fetch(`${this.coderUrl}/files/write`, {
|
|
360
|
-
method: 'POST',
|
|
361
|
-
headers: this.headers,
|
|
362
|
-
body: JSON.stringify({
|
|
363
|
-
...input,
|
|
364
|
-
sessionId: options.sessionId,
|
|
365
|
-
sandboxId: options.sandboxId,
|
|
366
|
-
}),
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
if (!response.ok) {
|
|
370
|
-
const data = await response.json().catch(() => ({}));
|
|
371
|
-
throw new StacksSDKError(
|
|
372
|
-
'bad_request:api',
|
|
373
|
-
data.error || `Failed to write file: ${response.statusText}`
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return response.json();
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* List files in a directory
|
|
382
|
-
*/
|
|
383
|
-
async listFiles(
|
|
384
|
-
path: string,
|
|
385
|
-
options: { recursive?: boolean; maxDepth?: number; sessionId?: string; sandboxId?: string } = {}
|
|
386
|
-
): Promise<CoderFileInfo[]> {
|
|
387
|
-
const params = new URLSearchParams({ path });
|
|
388
|
-
if (options.recursive) params.set('recursive', 'true');
|
|
389
|
-
if (options.maxDepth) params.set('maxDepth', options.maxDepth.toString());
|
|
390
|
-
if (options.sessionId) params.set('sessionId', options.sessionId);
|
|
391
|
-
if (options.sandboxId) params.set('sandboxId', options.sandboxId);
|
|
392
|
-
|
|
393
|
-
const response = await fetch(`${this.coderUrl}/files/list?${params}`, {
|
|
394
|
-
headers: this.headers,
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
if (!response.ok) {
|
|
398
|
-
throw new StacksSDKError(
|
|
399
|
-
'bad_request:api',
|
|
400
|
-
`Failed to list files: ${response.statusText}`
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const result: CoderFilesResponse = await response.json();
|
|
405
|
-
return result.files;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Search for patterns in files
|
|
410
|
-
*/
|
|
411
|
-
async searchFiles(
|
|
412
|
-
pattern: string,
|
|
413
|
-
options: { path?: string; filePattern?: string; sessionId?: string; sandboxId?: string } = {}
|
|
414
|
-
): Promise<CoderSearchResult[]> {
|
|
415
|
-
const params = new URLSearchParams({ pattern });
|
|
416
|
-
if (options.path) params.set('path', options.path);
|
|
417
|
-
if (options.filePattern) params.set('filePattern', options.filePattern);
|
|
418
|
-
if (options.sessionId) params.set('sessionId', options.sessionId);
|
|
419
|
-
if (options.sandboxId) params.set('sandboxId', options.sandboxId);
|
|
420
|
-
|
|
421
|
-
const response = await fetch(`${this.coderUrl}/files/search?${params}`, {
|
|
422
|
-
headers: this.headers,
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
if (!response.ok) {
|
|
426
|
-
throw new StacksSDKError(
|
|
427
|
-
'bad_request:api',
|
|
428
|
-
`Failed to search files: ${response.statusText}`
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const result: { results: CoderSearchResult[] } = await response.json();
|
|
433
|
-
return result.results;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* Apply a diff to a file
|
|
438
|
-
*/
|
|
439
|
-
async applyDiff(
|
|
440
|
-
input: CoderDiffInput,
|
|
441
|
-
options: { sessionId?: string; sandboxId?: string } = {}
|
|
442
|
-
): Promise<{ success: boolean; changes: number }> {
|
|
443
|
-
const response = await fetch(`${this.coderUrl}/files/diff`, {
|
|
444
|
-
method: 'POST',
|
|
445
|
-
headers: this.headers,
|
|
446
|
-
body: JSON.stringify({
|
|
447
|
-
...input,
|
|
448
|
-
sessionId: options.sessionId,
|
|
449
|
-
sandboxId: options.sandboxId,
|
|
450
|
-
}),
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
if (!response.ok) {
|
|
454
|
-
const data = await response.json().catch(() => ({}));
|
|
455
|
-
throw new StacksSDKError(
|
|
456
|
-
'bad_request:api',
|
|
457
|
-
data.error || `Failed to apply diff: ${response.statusText}`
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
return response.json();
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// ============================================================================
|
|
465
|
-
// Command Execution
|
|
466
|
-
// ============================================================================
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Execute a shell command
|
|
470
|
-
*/
|
|
471
|
-
async executeCommand(
|
|
472
|
-
input: CoderCommandInput,
|
|
473
|
-
options: { sessionId?: string; sandboxId?: string } = {}
|
|
474
|
-
): Promise<CoderCommandResult> {
|
|
475
|
-
const response = await fetch(`${this.coderUrl}/exec`, {
|
|
476
|
-
method: 'POST',
|
|
477
|
-
headers: this.headers,
|
|
478
|
-
body: JSON.stringify({
|
|
479
|
-
...input,
|
|
480
|
-
sessionId: options.sessionId,
|
|
481
|
-
sandboxId: options.sandboxId,
|
|
482
|
-
}),
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
if (!response.ok) {
|
|
486
|
-
const data = await response.json().catch(() => ({}));
|
|
487
|
-
throw new StacksSDKError(
|
|
488
|
-
'bad_request:api',
|
|
489
|
-
data.error || `Failed to execute command: ${response.statusText}`
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
return response.json();
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* Execute a command with streaming output
|
|
498
|
-
*/
|
|
499
|
-
async *executeCommandStream(
|
|
500
|
-
input: CoderCommandInput,
|
|
501
|
-
options: { sessionId?: string; sandboxId?: string } = {}
|
|
502
|
-
): AsyncGenerator<{ type: 'stdout' | 'stderr' | 'exit'; content: string; exitCode?: number }, void, unknown> {
|
|
503
|
-
const response = await fetch(`${this.coderUrl}/exec/stream`, {
|
|
504
|
-
method: 'POST',
|
|
505
|
-
headers: {
|
|
506
|
-
...this.headers,
|
|
507
|
-
'Accept': 'text/event-stream',
|
|
508
|
-
},
|
|
509
|
-
body: JSON.stringify({
|
|
510
|
-
...input,
|
|
511
|
-
sessionId: options.sessionId,
|
|
512
|
-
sandboxId: options.sandboxId,
|
|
513
|
-
}),
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
if (!response.ok) {
|
|
517
|
-
const data = await response.json().catch(() => ({}));
|
|
518
|
-
throw new StacksSDKError(
|
|
519
|
-
'bad_request:api',
|
|
520
|
-
data.error || `Failed to execute command stream: ${response.statusText}`
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const reader = response.body?.getReader();
|
|
525
|
-
if (!reader) {
|
|
526
|
-
throw new StacksSDKError('bad_request:stream', 'No response body');
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const decoder = new TextDecoder();
|
|
530
|
-
let buffer = '';
|
|
531
|
-
|
|
532
|
-
try {
|
|
533
|
-
while (true) {
|
|
534
|
-
const { done, value } = await reader.read();
|
|
535
|
-
if (done) break;
|
|
536
|
-
|
|
537
|
-
buffer += decoder.decode(value, { stream: true });
|
|
538
|
-
const lines = buffer.split('\n');
|
|
539
|
-
buffer = lines.pop() || '';
|
|
540
|
-
|
|
541
|
-
for (const line of lines) {
|
|
542
|
-
if (line.startsWith('data: ')) {
|
|
543
|
-
const data = line.slice(6);
|
|
544
|
-
if (data === '[DONE]') return;
|
|
545
|
-
|
|
546
|
-
try {
|
|
547
|
-
yield JSON.parse(data);
|
|
548
|
-
} catch {
|
|
549
|
-
// Skip malformed JSON
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
} finally {
|
|
555
|
-
reader.releaseLock();
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// ============================================================================
|
|
560
|
-
// Sandbox Management
|
|
561
|
-
// ============================================================================
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* Create a new sandbox
|
|
565
|
-
*/
|
|
566
|
-
async createSandbox(input: CoderSandboxCreateInput = {}): Promise<CoderSandbox> {
|
|
567
|
-
const response = await fetch(`${this.coderUrl}/sandbox`, {
|
|
568
|
-
method: 'POST',
|
|
569
|
-
headers: this.headers,
|
|
570
|
-
body: JSON.stringify(input),
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
if (!response.ok) {
|
|
574
|
-
const data = await response.json().catch(() => ({}));
|
|
575
|
-
throw new StacksSDKError(
|
|
576
|
-
'bad_request:api',
|
|
577
|
-
data.error || `Failed to create sandbox: ${response.statusText}`
|
|
578
|
-
);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const result: CoderSandboxResponse = await response.json();
|
|
582
|
-
return result.sandbox;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
/**
|
|
586
|
-
* Get sandbox status
|
|
587
|
-
*/
|
|
588
|
-
async getSandbox(sandboxId: string): Promise<CoderSandbox> {
|
|
589
|
-
const response = await fetch(`${this.coderUrl}/sandbox/${sandboxId}`, {
|
|
590
|
-
headers: this.headers,
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
if (!response.ok) {
|
|
594
|
-
throw new StacksSDKError(
|
|
595
|
-
response.status === 404 ? 'not_found:api' : 'bad_request:api',
|
|
596
|
-
`Failed to get sandbox: ${response.statusText}`
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
const result: CoderSandboxResponse = await response.json();
|
|
601
|
-
return result.sandbox;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Execute code in a sandbox
|
|
606
|
-
*/
|
|
607
|
-
async sandboxExec(sandboxId: string, input: CoderSandboxExecInput): Promise<CoderSandboxExecResult> {
|
|
608
|
-
const response = await fetch(`${this.coderUrl}/sandbox/${sandboxId}/exec`, {
|
|
609
|
-
method: 'POST',
|
|
610
|
-
headers: this.headers,
|
|
611
|
-
body: JSON.stringify(input),
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
if (!response.ok) {
|
|
615
|
-
const data = await response.json().catch(() => ({}));
|
|
616
|
-
throw new StacksSDKError(
|
|
617
|
-
'bad_request:api',
|
|
618
|
-
data.error || `Failed to execute in sandbox: ${response.statusText}`
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
return response.json();
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Destroy a sandbox
|
|
627
|
-
*/
|
|
628
|
-
async destroySandbox(sandboxId: string): Promise<{ success: boolean }> {
|
|
629
|
-
const response = await fetch(`${this.coderUrl}/sandbox/${sandboxId}`, {
|
|
630
|
-
method: 'DELETE',
|
|
631
|
-
headers: this.headers,
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
if (!response.ok) {
|
|
635
|
-
throw new StacksSDKError(
|
|
636
|
-
'bad_request:api',
|
|
637
|
-
`Failed to destroy sandbox: ${response.statusText}`
|
|
638
|
-
);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
return response.json();
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* Create a CoderClient instance
|
|
647
|
-
*/
|
|
648
|
-
export function createCoderClient(config: CoderClientConfig = {}): CoderClient {
|
|
649
|
-
return new CoderClient(config);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Default coder client instance
|
|
654
|
-
*/
|
|
655
|
-
export const coderClient = createCoderClient();
|