@bunny-agent/manager 0.9.28

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 (71) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +198 -0
  3. package/dist/__tests__/bunny-agent.test.d.ts +2 -0
  4. package/dist/__tests__/bunny-agent.test.d.ts.map +1 -0
  5. package/dist/__tests__/bunny-agent.test.js +274 -0
  6. package/dist/__tests__/bunny-agent.test.js.map +1 -0
  7. package/dist/__tests__/coding-run.test.d.ts +2 -0
  8. package/dist/__tests__/coding-run.test.d.ts.map +1 -0
  9. package/dist/__tests__/coding-run.test.js +27 -0
  10. package/dist/__tests__/coding-run.test.js.map +1 -0
  11. package/dist/__tests__/daemon-health.test.d.ts +2 -0
  12. package/dist/__tests__/daemon-health.test.d.ts.map +1 -0
  13. package/dist/__tests__/daemon-health.test.js +113 -0
  14. package/dist/__tests__/daemon-health.test.js.map +1 -0
  15. package/dist/__tests__/env.test.d.ts +2 -0
  16. package/dist/__tests__/env.test.d.ts.map +1 -0
  17. package/dist/__tests__/env.test.js +82 -0
  18. package/dist/__tests__/env.test.js.map +1 -0
  19. package/dist/__tests__/local-sandbox.test.d.ts +2 -0
  20. package/dist/__tests__/local-sandbox.test.d.ts.map +1 -0
  21. package/dist/__tests__/local-sandbox.test.js +274 -0
  22. package/dist/__tests__/local-sandbox.test.js.map +1 -0
  23. package/dist/__tests__/signal-integration.test.d.ts +2 -0
  24. package/dist/__tests__/signal-integration.test.d.ts.map +1 -0
  25. package/dist/__tests__/signal-integration.test.js +135 -0
  26. package/dist/__tests__/signal-integration.test.js.map +1 -0
  27. package/dist/__tests__/transcript.test.d.ts +2 -0
  28. package/dist/__tests__/transcript.test.d.ts.map +1 -0
  29. package/dist/__tests__/transcript.test.js +144 -0
  30. package/dist/__tests__/transcript.test.js.map +1 -0
  31. package/dist/__tests__/types.test.d.ts +2 -0
  32. package/dist/__tests__/types.test.d.ts.map +1 -0
  33. package/dist/__tests__/types.test.js +148 -0
  34. package/dist/__tests__/types.test.js.map +1 -0
  35. package/dist/bunny-agent.d.ts +50 -0
  36. package/dist/bunny-agent.d.ts.map +1 -0
  37. package/dist/bunny-agent.js +206 -0
  38. package/dist/bunny-agent.js.map +1 -0
  39. package/dist/coding-run.d.ts +40 -0
  40. package/dist/coding-run.d.ts.map +1 -0
  41. package/dist/coding-run.js +111 -0
  42. package/dist/coding-run.js.map +1 -0
  43. package/dist/constants.d.ts +7 -0
  44. package/dist/constants.d.ts.map +1 -0
  45. package/dist/constants.js +7 -0
  46. package/dist/constants.js.map +1 -0
  47. package/dist/daemon-health.d.ts +16 -0
  48. package/dist/daemon-health.d.ts.map +1 -0
  49. package/dist/daemon-health.js +66 -0
  50. package/dist/daemon-health.js.map +1 -0
  51. package/dist/env.d.ts +55 -0
  52. package/dist/env.d.ts.map +1 -0
  53. package/dist/env.js +113 -0
  54. package/dist/env.js.map +1 -0
  55. package/dist/index.d.ts +13 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +10 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/local-sandbox.d.ts +83 -0
  60. package/dist/local-sandbox.d.ts.map +1 -0
  61. package/dist/local-sandbox.js +364 -0
  62. package/dist/local-sandbox.js.map +1 -0
  63. package/dist/transcript.d.ts +112 -0
  64. package/dist/transcript.d.ts.map +1 -0
  65. package/dist/transcript.js +176 -0
  66. package/dist/transcript.js.map +1 -0
  67. package/dist/types.d.ts +249 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +2 -0
  70. package/dist/types.js.map +1 -0
  71. package/package.json +50 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * BunnyAgent - A sandboxed agent runtime that speaks AI SDK UI natively.
3
+ *
4
+ * Represents one persistent agent instance with:
5
+ * - An isolated sandbox
6
+ * - A dedicated filesystem volume
7
+ * - Direct passthrough of AI SDK UI messages
8
+ */
9
+ export class BunnyAgent {
10
+ sandbox;
11
+ runner;
12
+ env;
13
+ handle = null;
14
+ constructor(options) {
15
+ this.sandbox = options.sandbox;
16
+ this.runner = options.runner;
17
+ this.env = options.env ?? {};
18
+ }
19
+ /**
20
+ * Attach to the sandbox if not already attached
21
+ */
22
+ async ensureAttached() {
23
+ if (!this.handle) {
24
+ this.handle = await this.sandbox.attach();
25
+ }
26
+ return this.handle;
27
+ }
28
+ /**
29
+ * Build the CLI command to execute
30
+ */
31
+ buildCommand(input) {
32
+ // Get runner command from sandbox, or use default "bunny-agent run"
33
+ const cmd = this.sandbox.getRunnerCommand?.() ?? [
34
+ "bunny-agent",
35
+ "run",
36
+ ];
37
+ // Add --runner when runnerType is set (so CLI uses pi/codex/gemini/opencode instead of default claude)
38
+ const runnerType = this.runner.runnerType ?? "claude";
39
+ cmd.push("--runner", runnerType);
40
+ // Add model
41
+ cmd.push("--model", this.runner.model);
42
+ // Add workspace path
43
+ const workspacePath = input.workspace?.path ?? "/workspace";
44
+ cmd.push("--cwd", workspacePath);
45
+ // Add optional system prompt
46
+ if (this.runner.systemPrompt) {
47
+ cmd.push("--system-prompt", this.runner.systemPrompt);
48
+ }
49
+ // Add optional skill paths (for pi runner)
50
+ if (this.runner.skillPaths && this.runner.skillPaths.length > 0) {
51
+ for (const skillPath of this.runner.skillPaths) {
52
+ cmd.push("--skill-path", skillPath);
53
+ }
54
+ }
55
+ // Add optional max turns
56
+ if (this.runner.maxTurns !== undefined) {
57
+ cmd.push("--max-turns", String(this.runner.maxTurns));
58
+ }
59
+ // Add optional allowed tools
60
+ if (this.runner.allowedTools) {
61
+ cmd.push("--allowed-tools", this.runner.allowedTools.join(","));
62
+ }
63
+ if (this.runner.yolo) {
64
+ cmd.push("--yolo");
65
+ }
66
+ // Add resume parameter for multi-turn conversation
67
+ if (input.resume) {
68
+ cmd.push("--resume", input.resume);
69
+ }
70
+ // runner-cli always outputs AI SDK stream; --output-format is no longer accepted
71
+ // Add separator and user input
72
+ cmd.push("--");
73
+ // Get the last user message as input
74
+ const lastUserMessage = input.messages
75
+ .filter((m) => m.role === "user")
76
+ .pop();
77
+ if (lastUserMessage) {
78
+ cmd.push(typeof lastUserMessage.content === "string"
79
+ ? lastUserMessage.content
80
+ : JSON.stringify(lastUserMessage.content));
81
+ }
82
+ return cmd;
83
+ }
84
+ /**
85
+ * Stream a task through the agent.
86
+ *
87
+ * This method:
88
+ * 1. Attaches to the sandbox
89
+ * 2. Executes the CLI runner inside the sandbox
90
+ * 3. Returns a ReadableStream of AI SDK UI messages from stdout
91
+ *
92
+ * The server NEVER parses or modifies the stream.
93
+ *
94
+ * @param input - Stream input including messages and optional transcript writer
95
+ * @returns ReadableStream of AI SDK UI messages
96
+ */
97
+ async stream(input) {
98
+ const handle = await this.ensureAttached();
99
+ // Use sandbox's actual workdir after attach (for isolated sandboxes)
100
+ const actualWorkdir = handle.getWorkdir();
101
+ const inputWithWorkdir = {
102
+ ...input,
103
+ workspace: {
104
+ ...input.workspace,
105
+ path: actualWorkdir,
106
+ },
107
+ };
108
+ const command = this.buildCommand(inputWithWorkdir);
109
+ const workspacePath = actualWorkdir;
110
+ const transcriptWriter = input.transcriptWriter;
111
+ const signal = input.signal;
112
+ // Check if signal is already aborted
113
+ if (signal?.aborted) {
114
+ throw new Error("Operation was aborted");
115
+ }
116
+ // Write start entry if transcript is enabled
117
+ if (transcriptWriter) {
118
+ await transcriptWriter.write({
119
+ timestamp: new Date().toISOString(),
120
+ type: "start",
121
+ metadata: {
122
+ command: command.join(" "),
123
+ workspace: workspacePath,
124
+ runner: this.runner,
125
+ },
126
+ });
127
+ }
128
+ // Execute the command and get stdout as an async iterable
129
+ const stdout = handle.exec(command, {
130
+ cwd: workspacePath,
131
+ env: this.env,
132
+ signal,
133
+ });
134
+ // Create a ReadableStream that passes through the stdout chunks
135
+ // and optionally writes to transcript
136
+ return new ReadableStream({
137
+ async start(controller) {
138
+ let controllerClosed = false;
139
+ try {
140
+ for await (const chunk of stdout) {
141
+ // Write to transcript if enabled
142
+ if (transcriptWriter) {
143
+ const text = new TextDecoder().decode(chunk);
144
+ await transcriptWriter.write({
145
+ timestamp: new Date().toISOString(),
146
+ type: "chunk",
147
+ data: Buffer.from(chunk).toString("base64"),
148
+ text,
149
+ });
150
+ }
151
+ // Passthrough to response
152
+ controller.enqueue(chunk);
153
+ }
154
+ // Write end entry if transcript is enabled
155
+ if (transcriptWriter) {
156
+ await transcriptWriter.write({
157
+ timestamp: new Date().toISOString(),
158
+ type: "end",
159
+ });
160
+ }
161
+ controller.close();
162
+ controllerClosed = true;
163
+ }
164
+ catch (error) {
165
+ if (error instanceof Error && error.name === "AbortError") {
166
+ // Normal abort operation - log appropriately
167
+ console.log("[BunnyAgent] Operation aborted by user");
168
+ }
169
+ else {
170
+ // Other errors
171
+ const errorMessage = error instanceof Error ? error.message : String(error);
172
+ console.error("[BunnyAgent] Error:", errorMessage);
173
+ if (transcriptWriter) {
174
+ await transcriptWriter.write({
175
+ timestamp: new Date().toISOString(),
176
+ type: "error",
177
+ text: errorMessage,
178
+ });
179
+ }
180
+ }
181
+ // Only call controller.error if controller hasn't been closed yet
182
+ if (!controllerClosed) {
183
+ controller.error(error);
184
+ }
185
+ }
186
+ },
187
+ });
188
+ }
189
+ /**
190
+ * Upload files to the agent's workspace
191
+ */
192
+ async uploadFiles(files, targetDir = "/workspace") {
193
+ const handle = await this.ensureAttached();
194
+ await handle.upload(files, targetDir);
195
+ }
196
+ /**
197
+ * Destroy the sandbox and release resources
198
+ */
199
+ async destroy() {
200
+ if (this.handle) {
201
+ await this.handle.destroy();
202
+ this.handle = null;
203
+ }
204
+ }
205
+ }
206
+ //# sourceMappingURL=bunny-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bunny-agent.js","sourceRoot":"","sources":["../src/bunny-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { BunnyAgentCodingRunBody, ExecOptions, SandboxHandle } from "./types.js";
2
+ /** Temp directory for the coding-run JSON uploaded before `curl`. */
3
+ export declare const SANDBOX_CODING_RUN_TMP_DIR = "/tmp";
4
+ export interface DaemonCodingRunExecParams {
5
+ url: string;
6
+ reqPath: string;
7
+ }
8
+ /**
9
+ * One remote shell script: register cleanup on EXIT/INT/TERM, run curl, then exit with curl's status.
10
+ * Improves odds the request JSON file is removed even if the caller’s best-effort `rm` after a failed `exec`
11
+ * never runs. Not absolute: SIGKILL, host crash, or rm failure can still leave the file.
12
+ */
13
+ export declare function buildCodingRunShellScript(daemonBaseUrl: string, reqPath: string): string;
14
+ /**
15
+ * Build argv for `curl` POST to bunny-agent-daemon `/api/coding/run`.
16
+ *
17
+ * Always passes `--fail` so HTTP 4xx/5xx produce a non-zero exit and stderr.
18
+ * Runner credentials belong in the JSON body `env`, not headers.
19
+ */
20
+ export declare function buildDefaultDaemonCodingRunExecCommand(params: DaemonCodingRunExecParams): string[];
21
+ export declare function buildDefaultCodingRunExec(daemonBaseUrl: string, reqPath: string): string[];
22
+ /**
23
+ * Default daemon LLM proxy: write the JSON body into the sandbox under
24
+ * {@link SANDBOX_CODING_RUN_TMP_DIR}, then stream `curl -N POST …/api/coding/run`
25
+ * stdout, then `rm` the file. Requires `curl` in the sandbox image.
26
+ *
27
+ * A temp file is intentional: it can be removed from disk after the request.
28
+ * The curl step runs under `sh -c` with `trap 'rm -f "$REQ"' EXIT INT TERM` so cleanup is tied to
29
+ * that shell. A hard kill (`SIGKILL`), sandbox loss, or `rm` failure can still leave the file — not a cryptographic guarantee.
30
+ * Embedding the body in the remote shell command (e.g. base64) often survives
31
+ * in platform command history and cannot be deleted like a file.
32
+ *
33
+ * Runner credentials belong in {@link BunnyAgentCodingRunBody.env} on `body`.
34
+ * {@link ExecOptions.env} is not used for the POST JSON.
35
+ *
36
+ * Errors from `upload` / `exec` propagate to the caller unchanged. If `exec` throws after a successful
37
+ * `upload`, a `catch` path schedules best-effort `rm` without awaiting (the remote `trap` may not have run yet).
38
+ */
39
+ export declare function streamCodingRunFromSandbox(handle: SandboxHandle, daemonBaseUrl: string, body: BunnyAgentCodingRunBody, opts?: ExecOptions): AsyncIterable<Uint8Array>;
40
+ //# sourceMappingURL=coding-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coding-run.d.ts","sourceRoot":"","sources":["../src/coding-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,WAAW,EACX,aAAa,EACd,MAAM,YAAY,CAAC;AAIpB,qEAAqE;AACrE,eAAO,MAAM,0BAA0B,SAAS,CAAC;AAEjD,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAgBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,MAAM,CAUR;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CACpD,MAAM,EAAE,yBAAyB,GAChC,MAAM,EAAE,CAcV;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CAKV;AAsBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAuB,0BAA0B,CAC/C,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,uBAAuB,EAC7B,IAAI,CAAC,EAAE,WAAW,GACjB,aAAa,CAAC,UAAU,CAAC,CA0B3B"}
@@ -0,0 +1,111 @@
1
+ // NOTE: daemon health probing moved to `@bunny-agent/sandbox-sandock`.
2
+ /** Temp directory for the coding-run JSON uploaded before `curl`. */
3
+ export const SANDBOX_CODING_RUN_TMP_DIR = "/tmp";
4
+ function joinSandboxPath(workdir, name) {
5
+ const w = workdir.replace(/\/+$/, "");
6
+ return `${w}/${name}`.replace(/\/+/g, "/");
7
+ }
8
+ function normalizeDaemonBaseUrl(daemonBaseUrl) {
9
+ return daemonBaseUrl.replace(/\/$/, "");
10
+ }
11
+ /** POSIX sh single-quoted literal (for safe embedding in `sh -c`). */
12
+ function shellSingleQuote(value) {
13
+ return `'${value.replace(/'/g, `'\\''`)}'`;
14
+ }
15
+ /**
16
+ * One remote shell script: register cleanup on EXIT/INT/TERM, run curl, then exit with curl's status.
17
+ * Improves odds the request JSON file is removed even if the caller’s best-effort `rm` after a failed `exec`
18
+ * never runs. Not absolute: SIGKILL, host crash, or rm failure can still leave the file.
19
+ */
20
+ export function buildCodingRunShellScript(daemonBaseUrl, reqPath) {
21
+ const url = `${normalizeDaemonBaseUrl(daemonBaseUrl)}/api/coding/run`;
22
+ return (`REQ=${shellSingleQuote(reqPath)}` +
23
+ `; trap 'rm -f "$REQ"' EXIT INT TERM` +
24
+ `; curl --fail -sS -N -X POST ${shellSingleQuote(url)}` +
25
+ ` -H ${shellSingleQuote("Content-Type: application/json")}` +
26
+ ` --data-binary @"$REQ"` +
27
+ `; exit $?`);
28
+ }
29
+ /**
30
+ * Build argv for `curl` POST to bunny-agent-daemon `/api/coding/run`.
31
+ *
32
+ * Always passes `--fail` so HTTP 4xx/5xx produce a non-zero exit and stderr.
33
+ * Runner credentials belong in the JSON body `env`, not headers.
34
+ */
35
+ export function buildDefaultDaemonCodingRunExecCommand(params) {
36
+ return [
37
+ "curl",
38
+ "--fail",
39
+ "-sS",
40
+ "-N",
41
+ "-X",
42
+ "POST",
43
+ params.url,
44
+ "-H",
45
+ "Content-Type: application/json",
46
+ "--data-binary",
47
+ `@${params.reqPath}`,
48
+ ];
49
+ }
50
+ export function buildDefaultCodingRunExec(daemonBaseUrl, reqPath) {
51
+ return buildDefaultDaemonCodingRunExecCommand({
52
+ url: `${normalizeDaemonBaseUrl(daemonBaseUrl)}/api/coding/run`,
53
+ reqPath,
54
+ });
55
+ }
56
+ /**
57
+ * Best-effort remove request JSON; does not await the background task (shell trap also cleans on normal curl exit).
58
+ * {@link SandboxHandle.exec} is a lazy async iterable: the command does not run until the iterator is consumed.
59
+ */
60
+ function scheduleRemoveCodingRunRequestFile(handle, reqPath, execOpts) {
61
+ void (async () => {
62
+ try {
63
+ for await (const _ of handle.exec(["/bin/rm", "-f", reqPath], execOpts)) {
64
+ // pull chunks until the process exits (required for exec to complete)
65
+ }
66
+ }
67
+ catch {
68
+ // ignore — cleanup must not mask the original error
69
+ }
70
+ })();
71
+ }
72
+ /**
73
+ * Default daemon LLM proxy: write the JSON body into the sandbox under
74
+ * {@link SANDBOX_CODING_RUN_TMP_DIR}, then stream `curl -N POST …/api/coding/run`
75
+ * stdout, then `rm` the file. Requires `curl` in the sandbox image.
76
+ *
77
+ * A temp file is intentional: it can be removed from disk after the request.
78
+ * The curl step runs under `sh -c` with `trap 'rm -f "$REQ"' EXIT INT TERM` so cleanup is tied to
79
+ * that shell. A hard kill (`SIGKILL`), sandbox loss, or `rm` failure can still leave the file — not a cryptographic guarantee.
80
+ * Embedding the body in the remote shell command (e.g. base64) often survives
81
+ * in platform command history and cannot be deleted like a file.
82
+ *
83
+ * Runner credentials belong in {@link BunnyAgentCodingRunBody.env} on `body`.
84
+ * {@link ExecOptions.env} is not used for the POST JSON.
85
+ *
86
+ * Errors from `upload` / `exec` propagate to the caller unchanged. If `exec` throws after a successful
87
+ * `upload`, a `catch` path schedules best-effort `rm` without awaiting (the remote `trap` may not have run yet).
88
+ */
89
+ export async function* streamCodingRunFromSandbox(handle, daemonBaseUrl, body, opts) {
90
+ const workdir = opts?.cwd ?? handle.getWorkdir();
91
+ const tmpDir = SANDBOX_CODING_RUN_TMP_DIR;
92
+ const { cwd: optCwd, signal, timeout } = opts ?? {};
93
+ const execBase = {
94
+ cwd: optCwd ?? workdir,
95
+ signal,
96
+ timeout,
97
+ };
98
+ const reqName = `.bunny-agent-coding-req-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.json`;
99
+ const payload = new TextEncoder().encode(JSON.stringify(body));
100
+ const reqPath = joinSandboxPath(tmpDir, reqName);
101
+ await handle.upload([{ path: reqName, content: payload }], tmpDir);
102
+ const shellScript = buildCodingRunShellScript(daemonBaseUrl, reqPath);
103
+ try {
104
+ yield* handle.exec(["/bin/sh", "-c", shellScript], execBase);
105
+ }
106
+ catch (err) {
107
+ scheduleRemoveCodingRunRequestFile(handle, reqPath, execBase);
108
+ throw err;
109
+ }
110
+ }
111
+ //# sourceMappingURL=coding-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coding-run.js","sourceRoot":"","sources":["../src/coding-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Default bunny-agent-daemon base URL inside the BunnyAgent Docker image / local
3
+ * daemon (`http://127.0.0.1:3080`). Pass as `daemonUrl` with a `sandbox` when
4
+ * streaming coding runs via `streamCodingRunFromSandbox`.
5
+ */
6
+ export declare const DEFAULT_BUNNY_AGENT_DAEMON_URL = "http://127.0.0.1:3080";
7
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,0BAA0B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Default bunny-agent-daemon base URL inside the BunnyAgent Docker image / local
3
+ * daemon (`http://127.0.0.1:3080`). Pass as `daemonUrl` with a `sandbox` when
4
+ * streaming coding runs via `streamCodingRunFromSandbox`.
5
+ */
6
+ export const DEFAULT_BUNNY_AGENT_DAEMON_URL = "http://127.0.0.1:3080";
7
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ExecOptions, SandboxHandle } from "./types.js";
2
+ export type IsBunnyAgentDaemonHealthyOptions = ExecOptions & {
3
+ /** Default 1 — avoid retry storms on every SDK stream. */
4
+ maxAttempts?: number;
5
+ /** Delay between attempts (default 0). */
6
+ delayMs?: number;
7
+ };
8
+ /**
9
+ * Runs `curl` against `<base>/healthz` inside the sandbox via the handle's `exec` method.
10
+ * Returns true only when the HTTP status line is **200** (`-w '%{http_code}'`).
11
+ *
12
+ * Defaults: **one attempt**, **~4s** budget, and curl `--connect-timeout` / `--max-time` so the
13
+ * command cannot hang much longer than `timeout` even if the adapter is loose.
14
+ */
15
+ export declare function isBunnyAgentDaemonHealthy(handle: SandboxHandle, daemonBaseUrl: string, opts?: IsBunnyAgentDaemonHealthyOptions): Promise<boolean>;
16
+ //# sourceMappingURL=daemon-health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-health.d.ts","sourceRoot":"","sources":["../src/daemon-health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAsB7D,MAAM,MAAM,gCAAgC,GAAG,WAAW,GAAG;IAC3D,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAKF;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,gCAAgC,GACtC,OAAO,CAAC,OAAO,CAAC,CAiDlB"}
@@ -0,0 +1,66 @@
1
+ const HEALTHZ_PATH = "/healthz";
2
+ function daemonHealthzUrl(daemonBaseUrl) {
3
+ const normalized = daemonBaseUrl.replace(/\/$/, "");
4
+ const withoutHealthz = normalized.replace(/\/healthz$/i, "");
5
+ return `${withoutHealthz}${HEALTHZ_PATH}`;
6
+ }
7
+ async function collectExecUtf8(iterable) {
8
+ const decoder = new TextDecoder();
9
+ let out = "";
10
+ for await (const chunk of iterable) {
11
+ out += decoder.decode(chunk, { stream: true });
12
+ }
13
+ out += decoder.decode();
14
+ return out;
15
+ }
16
+ /** Default exec + curl wall clock for one health probe (ms). */
17
+ const DEFAULT_DAEMON_HEALTH_TIMEOUT_MS = 4000;
18
+ /**
19
+ * Runs `curl` against `<base>/healthz` inside the sandbox via the handle's `exec` method.
20
+ * Returns true only when the HTTP status line is **200** (`-w '%{http_code}'`).
21
+ *
22
+ * Defaults: **one attempt**, **~4s** budget, and curl `--connect-timeout` / `--max-time` so the
23
+ * command cannot hang much longer than `timeout` even if the adapter is loose.
24
+ */
25
+ export async function isBunnyAgentDaemonHealthy(handle, daemonBaseUrl, opts) {
26
+ const healthzUrl = daemonHealthzUrl(daemonBaseUrl);
27
+ const maxAttempts = Math.max(1, opts?.maxAttempts ?? 1);
28
+ const delayMs = Math.max(0, opts?.delayMs ?? 0);
29
+ const timeout = Math.min(30_000, Math.max(500, opts?.timeout ?? DEFAULT_DAEMON_HEALTH_TIMEOUT_MS));
30
+ const cwd = opts?.cwd ?? handle.getWorkdir();
31
+ const maxTimeSec = Math.max(1, Math.ceil(timeout / 1000));
32
+ const connectTimeoutSec = Math.min(maxTimeSec, 5);
33
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
34
+ try {
35
+ const text = await collectExecUtf8(handle.exec([
36
+ "curl",
37
+ "-sS",
38
+ "-o",
39
+ "/dev/null",
40
+ "-w",
41
+ "%{http_code}",
42
+ "--connect-timeout",
43
+ String(connectTimeoutSec),
44
+ "--max-time",
45
+ String(maxTimeSec),
46
+ healthzUrl,
47
+ ], {
48
+ cwd,
49
+ timeout,
50
+ signal: opts?.signal,
51
+ env: opts?.env,
52
+ }));
53
+ if (text.trim() === "200") {
54
+ return true;
55
+ }
56
+ }
57
+ catch {
58
+ // Connection failure, spawn error, timeout, abort, etc.
59
+ }
60
+ if (attempt < maxAttempts && delayMs > 0) {
61
+ await new Promise((r) => setTimeout(r, delayMs));
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+ //# sourceMappingURL=daemon-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-health.js","sourceRoot":"","sources":["../src/daemon-health.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Build a sanitised env record for spawning a runner child process.
3
+ *
4
+ * Responsibilities:
5
+ * 1. Differentiate env by runner type (Claude vs Pi vs others).
6
+ * 2. Claude: map Anthropic/Bedrock/LiteLLM credentials.
7
+ * 3. Pi: map OpenAI/Gemini/Anthropic credentials and base URLs.
8
+ * 4. Strip host-only vars (e.g. CLAUDE_CODE_SSE_PORT) that would make the SDK
9
+ * connect to the parent Claude Code instead of calling the API directly.
10
+ */
11
+ export type RunnerType = "claude" | "pi" | "codex" | "gemini" | "opencode";
12
+ export interface RunnerEnvParams {
13
+ /**
14
+ * Runner type so env applies only the vars that runner needs.
15
+ * Defaults to "claude" when omitted for backward compatibility.
16
+ */
17
+ runnerType?: RunnerType;
18
+ /** Claude / Anthropic */
19
+ ANTHROPIC_API_KEY?: string;
20
+ ANTHROPIC_BASE_URL?: string;
21
+ AWS_BEARER_TOKEN_BEDROCK?: string;
22
+ ANTHROPIC_AUTH_TOKEN?: string;
23
+ LITELLM_MASTER_KEY?: string;
24
+ ANTHROPIC_BEDROCK_BASE_URL?: string;
25
+ CLAUDE_CODE_USE_BEDROCK?: string;
26
+ CLAUDE_CODE_SKIP_BEDROCK_AUTH?: string;
27
+ /** Pi / Codex: OpenAI and Google */
28
+ OPENAI_API_KEY?: string;
29
+ OPENAI_BASE_URL?: string;
30
+ GEMINI_API_KEY?: string;
31
+ GEMINI_BASE_URL?: string;
32
+ /** Web search (cross-runner) */
33
+ BRAVE_API_KEY?: string;
34
+ TAVILY_API_KEY?: string;
35
+ /** image generation */
36
+ IMAGE_GENERATION_MODEL?: string;
37
+ /**
38
+ * Base env to merge in (lowest priority).
39
+ * Typically `process.env` for local sandbox, or extra vars from the request.
40
+ * Null/undefined values and parent Claude Code keys (CLAUDE_CODE_SSE_PORT
41
+ * etc.) are automatically stripped.
42
+ */
43
+ inherit?: Record<string, string | undefined | null>;
44
+ }
45
+ /**
46
+ * Build the env record that should be passed to a runner child process.
47
+ *
48
+ * Applies inherit (stripped) first, then runner-specific credential vars.
49
+ * Unknown runner types default to Claude for backward compatibility.
50
+ *
51
+ * @param params - Credential / proxy configuration and runner type.
52
+ * @returns A plain `Record<string, string>` safe for child process env.
53
+ */
54
+ export declare function buildRunnerEnv(params: RunnerEnvParams): Record<string, string>;
55
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,yBAAyB;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,oCAAoC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;CACrD;AAiGD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB"}