coding-agents-sdk 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +242 -0
  2. package/dist/Agent-D8WkUilj.mjs +262 -0
  3. package/dist/SdkAgent-B47mJiIE.mjs +38 -0
  4. package/dist/adapters/claude-code-cli/index.d.mts +2 -0
  5. package/dist/adapters/claude-code-cli/index.mjs +490 -0
  6. package/dist/adapters/claude-code-sdk/index.d.mts +2 -0
  7. package/dist/adapters/claude-code-sdk/index.mjs +483 -0
  8. package/dist/adapters/codex-cli/index.d.mts +2 -0
  9. package/dist/adapters/codex-cli/index.mjs +626 -0
  10. package/dist/adapters/codex-sdk/index.d.mts +2 -0
  11. package/dist/adapters/codex-sdk/index.mjs +286 -0
  12. package/dist/adapters/gemini-cli/index.d.mts +2 -0
  13. package/dist/adapters/gemini-cli/index.mjs +292 -0
  14. package/dist/classify-error-pL6jeu4T.mjs +456 -0
  15. package/dist/container/index.d.mts +2 -0
  16. package/dist/container/index.mjs +24 -0
  17. package/dist/container-2UmPZ0CI.mjs +22 -0
  18. package/dist/container-CHxKIonn.mjs +440 -0
  19. package/dist/container-D2Z0ITDJ.mjs +22 -0
  20. package/dist/diff-De8d3MVb.mjs +333 -0
  21. package/dist/errors-BAmHDQu8.mjs +45 -0
  22. package/dist/events-nxuRbYIu.d.mts +239 -0
  23. package/dist/index-B3YqrgIp.d.mts +45 -0
  24. package/dist/index-ByAOGMUM.d.mts +224 -0
  25. package/dist/index-C3ZxLAd0.d.mts +315 -0
  26. package/dist/index-CFpNOmdA.d.mts +145 -0
  27. package/dist/index-dRVpEAr8.d.mts +39 -0
  28. package/dist/index-nzo1sBiK.d.mts +110 -0
  29. package/dist/index.d.mts +16 -0
  30. package/dist/index.mjs +61 -0
  31. package/dist/oci-DMZZQZ47.mjs +438 -0
  32. package/dist/schemas/index.d.mts +2 -0
  33. package/dist/schemas/index.mjs +2 -0
  34. package/dist/schemas-DwD4pwJB.mjs +96 -0
  35. package/dist/spawner-Bw9UBEGX.mjs +54 -0
  36. package/dist/structured-output-BHtr_zpz.mjs +19 -0
  37. package/dist/types-Cb_EXIEe.d.mts +177 -0
  38. package/dist/types-aNMD8h3x.mjs +19 -0
  39. package/dist/util-B4RQZkKr.mjs +77 -0
  40. package/package.json +86 -9
  41. package/index.js +0 -7
@@ -0,0 +1,440 @@
1
+ import { t as formatError } from "./util-B4RQZkKr.mjs";
2
+ import { n as ContainerDiffError, o as ContainerNotRunningError, r as ContainerDisposedError, s as ContainerStartError, t as ContainerCreateError } from "./errors-BAmHDQu8.mjs";
3
+ import { n as createWorkdirDiffApi, r as shellEscape } from "./diff-De8d3MVb.mjs";
4
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
5
+ import { basename, dirname, join, posix } from "node:path";
6
+ import { CommandExitError, FileType, Sandbox } from "e2b";
7
+ //#region src/container/e2b/helpers.ts
8
+ const buildCommandLine = (command, args) => [command, ...args].map(shellEscape).join(" ");
9
+ const resolveRuntimeUser = (config) => config.user;
10
+ const resolveRuntimeEnv = (config, env) => {
11
+ const merged = {
12
+ ...config.env,
13
+ ...env
14
+ };
15
+ return Object.keys(merged).length > 0 ? merged : void 0;
16
+ };
17
+ const resolveRuntimeCwd = (config, cwd) => cwd ?? config.workdir;
18
+ //#endregion
19
+ //#region src/container/e2b/spawner.ts
20
+ const encoder = new TextEncoder();
21
+ const toError = (error) => error instanceof Error ? error : new Error(String(error));
22
+ const normalizeSignal = (signal) => typeof signal === "string" ? signal : "SIGKILL";
23
+ const normalizeStdio = (options, index) => {
24
+ const value = options?.stdio?.[index];
25
+ if (value === "ignore" || value === "inherit" || value === "pipe") return value;
26
+ return value === void 0 ? "pipe" : "ignore";
27
+ };
28
+ const createByteQueue = () => {
29
+ const chunks = [];
30
+ const waiters = [];
31
+ let ended = false;
32
+ let error;
33
+ const flush = () => {
34
+ while (waiters.length > 0 && chunks.length > 0) waiters.shift().resolve({
35
+ done: false,
36
+ value: chunks.shift()
37
+ });
38
+ if (error) {
39
+ while (waiters.length > 0) waiters.shift().reject(error);
40
+ return;
41
+ }
42
+ if (ended) while (waiters.length > 0) waiters.shift().resolve({
43
+ done: true,
44
+ value: void 0
45
+ });
46
+ };
47
+ return {
48
+ iterable: { async *[Symbol.asyncIterator]() {
49
+ while (true) {
50
+ if (chunks.length > 0) {
51
+ yield chunks.shift();
52
+ continue;
53
+ }
54
+ if (error) throw toError(error);
55
+ if (ended) return;
56
+ const result = await new Promise((resolve, reject) => {
57
+ waiters.push({
58
+ resolve,
59
+ reject
60
+ });
61
+ });
62
+ if (result.done) return;
63
+ yield result.value;
64
+ }
65
+ } },
66
+ push(text) {
67
+ if (text.length === 0 || ended || error) return;
68
+ chunks.push(encoder.encode(text));
69
+ flush();
70
+ },
71
+ end() {
72
+ if (ended || error) return;
73
+ ended = true;
74
+ flush();
75
+ },
76
+ fail(reason) {
77
+ if (ended || error) return;
78
+ error = reason;
79
+ flush();
80
+ }
81
+ };
82
+ };
83
+ const createE2BSpawner = (sandbox, config) => ({ spawn: (command, args, options = {}) => {
84
+ const stdinMode = normalizeStdio(options, 0);
85
+ const stdoutMode = normalizeStdio(options, 1);
86
+ const stderrMode = normalizeStdio(options, 2);
87
+ const stdoutQueue = stdoutMode === "pipe" ? createByteQueue() : void 0;
88
+ const stderrQueue = stderrMode === "pipe" ? createByteQueue() : void 0;
89
+ let waitSignal = null;
90
+ const commandOptions = {
91
+ background: true,
92
+ stdin: stdinMode === "pipe",
93
+ cwd: resolveRuntimeCwd(config, options.cwd),
94
+ envs: resolveRuntimeEnv(config, options.env),
95
+ user: resolveRuntimeUser(config),
96
+ requestTimeoutMs: config.requestTimeoutMs,
97
+ onStdout: (data) => {
98
+ if (stdoutMode === "inherit") {
99
+ process.stdout.write(data);
100
+ return;
101
+ }
102
+ stdoutQueue?.push(data);
103
+ },
104
+ onStderr: (data) => {
105
+ if (stderrMode === "inherit") {
106
+ process.stderr.write(data);
107
+ return;
108
+ }
109
+ stderrQueue?.push(data);
110
+ }
111
+ };
112
+ const commandHandlePromise = sandbox.commands.run(buildCommandLine(command, args), commandOptions);
113
+ commandHandlePromise.catch((error) => {
114
+ stdoutQueue?.fail(error);
115
+ stderrQueue?.fail(error);
116
+ });
117
+ const wait = async () => {
118
+ try {
119
+ const result = await (await commandHandlePromise).wait();
120
+ stdoutQueue?.end();
121
+ stderrQueue?.end();
122
+ if (waitSignal) return {
123
+ exitCode: null,
124
+ signal: waitSignal
125
+ };
126
+ return {
127
+ exitCode: result.exitCode,
128
+ signal: null
129
+ };
130
+ } catch (error) {
131
+ stdoutQueue?.end();
132
+ stderrQueue?.end();
133
+ if (error instanceof CommandExitError) {
134
+ if (waitSignal) return {
135
+ exitCode: null,
136
+ signal: waitSignal
137
+ };
138
+ return {
139
+ exitCode: error.exitCode,
140
+ signal: null
141
+ };
142
+ }
143
+ throw error;
144
+ }
145
+ };
146
+ return {
147
+ stdout: stdoutQueue?.iterable ?? null,
148
+ stderr: stderrQueue?.iterable ?? null,
149
+ stdin: stdinMode === "pipe" ? {
150
+ write: (chunk) => {
151
+ commandHandlePromise.then((handle) => {
152
+ sandbox.commands.sendStdin(handle.pid, chunk, { requestTimeoutMs: config.requestTimeoutMs });
153
+ }).catch(() => {});
154
+ },
155
+ end: () => {
156
+ commandHandlePromise.then((handle) => {
157
+ sandbox.commands.closeStdin(handle.pid, { requestTimeoutMs: config.requestTimeoutMs });
158
+ }).catch(() => {});
159
+ }
160
+ } : null,
161
+ kill: (signal) => {
162
+ waitSignal = normalizeSignal(signal);
163
+ commandHandlePromise.then((handle) => handle.kill()).catch(() => {});
164
+ },
165
+ wait
166
+ };
167
+ } });
168
+ //#endregion
169
+ //#region src/container/e2b/container.ts
170
+ const resolveConnectionOptions = (config) => ({
171
+ apiKey: config.apiKey,
172
+ accessToken: config.accessToken,
173
+ domain: config.domain,
174
+ requestTimeoutMs: config.requestTimeoutMs,
175
+ headers: config.headers
176
+ });
177
+ const isConnectConfig = (config) => {
178
+ return "sandboxId" in config && typeof config.sandboxId === "string";
179
+ };
180
+ const resolveCreateOptions = (config) => {
181
+ const connection = resolveConnectionOptions(config);
182
+ if (isConnectConfig(config)) return connection;
183
+ return {
184
+ ...connection,
185
+ envs: config.env,
186
+ timeoutMs: config.timeoutMs,
187
+ metadata: config.metadata,
188
+ secure: config.secure,
189
+ allowInternetAccess: config.allowInternetAccess,
190
+ network: config.network,
191
+ lifecycle: config.lifecycle
192
+ };
193
+ };
194
+ const ensureWorkdir = async (sandbox, config) => {
195
+ await sandbox.files.makeDir(config.workdir, { user: resolveRuntimeUser(config) });
196
+ };
197
+ const isAbortError = (error) => {
198
+ return error instanceof Error && error.name === "AbortError";
199
+ };
200
+ const toArrayBuffer = (value) => Uint8Array.from(value).buffer;
201
+ const sandboxBasename = (path) => {
202
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
203
+ return posix.basename(normalized);
204
+ };
205
+ const getLocalEntry = async (path) => {
206
+ try {
207
+ return await stat(path);
208
+ } catch (error) {
209
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
210
+ throw error;
211
+ }
212
+ };
213
+ const getSandboxEntry = async (sandbox, path, user) => {
214
+ if (!await sandbox.files.exists(path, { user })) return;
215
+ return sandbox.files.getInfo(path, { user });
216
+ };
217
+ const resolveSandboxCopyTarget = async (sandbox, sourcePath, requestedTarget, user) => {
218
+ if ((await getSandboxEntry(sandbox, requestedTarget, user))?.type === FileType.DIR) return posix.join(requestedTarget, basename(sourcePath));
219
+ return requestedTarget;
220
+ };
221
+ const resolveLocalCopyTarget = async (sourcePath, requestedTarget) => {
222
+ if ((await getLocalEntry(requestedTarget))?.isDirectory()) return join(requestedTarget, sandboxBasename(sourcePath));
223
+ return requestedTarget;
224
+ };
225
+ const copyLocalPathToSandbox = async (sandbox, sourcePath, targetPath, user) => {
226
+ const entry = await stat(sourcePath);
227
+ if (entry.isDirectory()) {
228
+ await sandbox.files.makeDir(targetPath, { user });
229
+ const children = await readdir(sourcePath);
230
+ await Promise.all(children.map((child) => copyLocalPathToSandbox(sandbox, join(sourcePath, child), posix.join(targetPath, child), user)));
231
+ return;
232
+ }
233
+ if (!entry.isFile()) throw new Error(`Unsupported local filesystem entry at ${sourcePath}.`);
234
+ const data = await readFile(sourcePath);
235
+ await sandbox.files.write(targetPath, toArrayBuffer(data), { user });
236
+ };
237
+ const copySandboxPathToLocal = async (sandbox, sourcePath, targetPath, user) => {
238
+ if ((await sandbox.files.getInfo(sourcePath, { user })).type === FileType.DIR) {
239
+ await mkdir(targetPath, { recursive: true });
240
+ const children = await sandbox.files.list(sourcePath, { user });
241
+ await Promise.all(children.map((child) => copySandboxPathToLocal(sandbox, child.path, join(targetPath, child.name), user)));
242
+ return;
243
+ }
244
+ const data = await sandbox.files.read(sourcePath, {
245
+ format: "bytes",
246
+ user
247
+ });
248
+ await mkdir(dirname(targetPath), { recursive: true });
249
+ await writeFile(targetPath, data);
250
+ };
251
+ const createSandbox = async (config) => {
252
+ if (isConnectConfig(config)) return Sandbox.connect(config.sandboxId, resolveConnectionOptions(config));
253
+ const createOptions = resolveCreateOptions(config);
254
+ if (config.template) return Sandbox.create(config.template, createOptions);
255
+ return Sandbox.create(createOptions);
256
+ };
257
+ const reconnectSandbox = async (sandbox, config) => sandbox.connect(resolveConnectionOptions(config));
258
+ const waitForExec = async (handle, options) => {
259
+ const abortSignal = options.signal;
260
+ if (abortSignal?.aborted) {
261
+ const reason = abortSignal.reason;
262
+ throw reason instanceof Error ? reason : new DOMException("The operation was aborted.", "AbortError");
263
+ }
264
+ let aborted = false;
265
+ const abortHandler = () => {
266
+ aborted = true;
267
+ handle.kill();
268
+ };
269
+ abortSignal?.addEventListener("abort", abortHandler, { once: true });
270
+ try {
271
+ const result = await handle.wait();
272
+ if (aborted) throw new DOMException("The operation was aborted.", "AbortError");
273
+ return {
274
+ exitCode: result.exitCode,
275
+ stdout: result.stdout,
276
+ stderr: result.stderr
277
+ };
278
+ } catch (error) {
279
+ if (aborted || isAbortError(error)) throw new DOMException("The operation was aborted.", "AbortError");
280
+ if (error instanceof CommandExitError) return {
281
+ exitCode: error.exitCode,
282
+ stdout: error.stdout,
283
+ stderr: error.stderr
284
+ };
285
+ throw error;
286
+ } finally {
287
+ abortSignal?.removeEventListener("abort", abortHandler);
288
+ }
289
+ };
290
+ const createE2BContainer = async (config) => {
291
+ let sandbox;
292
+ try {
293
+ sandbox = await createSandbox(config);
294
+ await ensureWorkdir(sandbox, config);
295
+ } catch (error) {
296
+ throw new ContainerCreateError(`E2B create failed: ${formatError(error)}`);
297
+ }
298
+ const runtimeName = config.name ?? sandbox.sandboxId;
299
+ let status = "running";
300
+ let spawner = createE2BSpawner(sandbox, config);
301
+ const diffOwner = {};
302
+ const assertNotDisposed = () => {
303
+ if (status === "disposed") throw new ContainerDisposedError();
304
+ };
305
+ const assertRunning = () => {
306
+ assertNotDisposed();
307
+ if (status !== "running") throw new ContainerNotRunningError();
308
+ };
309
+ const diffApi = createWorkdirDiffApi({
310
+ owner: diffOwner,
311
+ workdir: config.workdir,
312
+ materialize: async (cwd, targetDir) => {
313
+ assertRunning();
314
+ const user = resolveRuntimeUser(config);
315
+ const entry = await getSandboxEntry(sandbox, cwd, user);
316
+ if (!entry) throw new ContainerDiffError(`Target path does not exist: ${cwd}`);
317
+ if (entry.type !== FileType.DIR) throw new ContainerDiffError(`Target path is not a directory: ${cwd}`);
318
+ await mkdir(targetDir, { recursive: true });
319
+ for (const child of await sandbox.files.list(cwd, { user })) await copySandboxPathToLocal(sandbox, child.path, join(targetDir, child.name), user);
320
+ }
321
+ });
322
+ const container = {
323
+ get type() {
324
+ return "e2b";
325
+ },
326
+ get id() {
327
+ return sandbox.sandboxId;
328
+ },
329
+ get name() {
330
+ return runtimeName;
331
+ },
332
+ get config() {
333
+ return config;
334
+ },
335
+ get status() {
336
+ return status;
337
+ },
338
+ get workdir() {
339
+ return config.workdir;
340
+ },
341
+ get spawner() {
342
+ return spawner;
343
+ },
344
+ async start() {
345
+ assertNotDisposed();
346
+ if (status === "running") return;
347
+ try {
348
+ sandbox = await reconnectSandbox(sandbox, config);
349
+ await ensureWorkdir(sandbox, config);
350
+ spawner = createE2BSpawner(sandbox, config);
351
+ status = "running";
352
+ } catch (error) {
353
+ throw new ContainerStartError(`E2B start failed: ${formatError(error)}`);
354
+ }
355
+ },
356
+ async stop() {
357
+ assertNotDisposed();
358
+ if (status !== "running") return;
359
+ await sandbox.pause({ requestTimeoutMs: config.requestTimeoutMs });
360
+ status = "stopped";
361
+ },
362
+ async dispose() {
363
+ if (status === "disposed") return;
364
+ try {
365
+ await sandbox.kill({ requestTimeoutMs: config.requestTimeoutMs });
366
+ } catch {}
367
+ await diffApi.disposeSnapshots().catch(() => {});
368
+ status = "disposed";
369
+ },
370
+ async exec(command, args, options = {}) {
371
+ assertRunning();
372
+ const commandOptions = {
373
+ background: true,
374
+ cwd: resolveRuntimeCwd(config, options.cwd),
375
+ envs: resolveRuntimeEnv(config, options.env),
376
+ user: resolveRuntimeUser(config),
377
+ timeoutMs: options.timeoutMs,
378
+ requestTimeoutMs: config.requestTimeoutMs
379
+ };
380
+ return waitForExec(await sandbox.commands.run(buildCommandLine(command, args), commandOptions), options);
381
+ },
382
+ async copyTo(hostPath, containerPath) {
383
+ assertRunning();
384
+ const targetPath = await resolveSandboxCopyTarget(sandbox, hostPath, containerPath, resolveRuntimeUser(config));
385
+ await copyLocalPathToSandbox(sandbox, hostPath, targetPath, resolveRuntimeUser(config));
386
+ },
387
+ async copyFrom(containerPath, hostPath) {
388
+ assertRunning();
389
+ const targetPath = await resolveLocalCopyTarget(containerPath, hostPath);
390
+ await copySandboxPathToLocal(sandbox, containerPath, targetPath, resolveRuntimeUser(config));
391
+ },
392
+ async writeFile(path, content) {
393
+ assertRunning();
394
+ await sandbox.files.write(path, typeof content === "string" ? content : toArrayBuffer(content), { user: resolveRuntimeUser(config) });
395
+ },
396
+ async readFile(path) {
397
+ assertRunning();
398
+ return sandbox.files.read(path, {
399
+ format: "text",
400
+ user: resolveRuntimeUser(config)
401
+ });
402
+ },
403
+ async fileExists(path) {
404
+ assertRunning();
405
+ return sandbox.files.exists(path, { user: resolveRuntimeUser(config) });
406
+ },
407
+ async mkdir(path) {
408
+ assertRunning();
409
+ await sandbox.files.makeDir(path, { user: resolveRuntimeUser(config) });
410
+ },
411
+ async execShell(script, options = {}) {
412
+ return container.exec("sh", ["-c", script], options);
413
+ },
414
+ async logs() {
415
+ return "";
416
+ },
417
+ async syncStatus() {
418
+ return status;
419
+ },
420
+ async snapshotWorkdir(options = {}) {
421
+ return diffApi.snapshotWorkdir(options);
422
+ },
423
+ async diffWorkdir(snapshot) {
424
+ return diffApi.diffWorkdir(snapshot);
425
+ },
426
+ async releaseWorkdirSnapshot(snapshot) {
427
+ return diffApi.releaseWorkdirSnapshot(snapshot);
428
+ },
429
+ getHost(port) {
430
+ assertRunning();
431
+ return sandbox.getHost(port);
432
+ },
433
+ [Symbol.asyncDispose]() {
434
+ return container.dispose();
435
+ }
436
+ };
437
+ return container;
438
+ };
439
+ //#endregion
440
+ export { createE2BContainer };
@@ -0,0 +1,22 @@
1
+ import { n as resolveOciImage, t as createOciContainer } from "./oci-DMZZQZ47.mjs";
2
+ //#region src/container/podman/container.ts
3
+ const createPodmanContainer = async (config) => {
4
+ const binary = config.binary ?? "podman";
5
+ const image = await resolveOciImage(binary, config);
6
+ return createOciContainer("podman", {
7
+ binary,
8
+ containerName: config.name,
9
+ workdir: config.workdir,
10
+ user: config.user,
11
+ network: config.network,
12
+ platform: config.platform,
13
+ env: config.env,
14
+ ports: config.ports,
15
+ mounts: config.mounts,
16
+ extraArgs: config.extraArgs,
17
+ image,
18
+ builtImage: config.build !== void 0 && !config.build.tag
19
+ }, config);
20
+ };
21
+ //#endregion
22
+ export { createPodmanContainer };