agentbox-sdk 0.1.322 → 0.1.400
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/dist/agents/index.d.ts +19 -2
- package/dist/agents/index.js +1 -1
- package/dist/{chunk-ZK5PDWOI.js → chunk-KFMFNBVC.js} +320 -28
- package/dist/{chunk-T4AS2WEF.js → chunk-TUBBWIOM.js} +56 -8
- package/dist/events/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/sandboxes/index.js +1 -1
- package/dist/{types-DG4J_zMT.d.ts → types-vOsvzkcO.d.ts} +28 -0
- package/package.json +1 -1
package/dist/agents/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, a3 as RawAgentEvent, b as AgentAttachRequest, y as AttachedRun, aa as SetupLayout } from '../types-
|
|
2
|
-
export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as OpenRouterPlugin, a5 as RepoSkillConfig, ac as TextPart, ag as UserContent, ah as UserContentPart } from '../types-
|
|
1
|
+
import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, a3 as RawAgentEvent, b as AgentAttachRequest, y as AttachedRun, aa as SetupLayout } from '../types-vOsvzkcO.js';
|
|
2
|
+
export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as OpenRouterPlugin, a5 as RepoSkillConfig, ac as TextPart, ag as UserContent, ah as UserContentPart } from '../types-vOsvzkcO.js';
|
|
3
3
|
import { S as Sandbox } from '../Sandbox-DcKAU-E3.js';
|
|
4
4
|
export { AgentProvider } from '../enums.js';
|
|
5
5
|
import 'e2b';
|
|
@@ -42,6 +42,23 @@ declare class Agent<P extends AgentProviderName = AgentProviderName> {
|
|
|
42
42
|
* work.
|
|
43
43
|
*/
|
|
44
44
|
setup(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Stop the long-lived provider CLI server booted by {@link Agent.setup}
|
|
47
|
+
* (claude-code relay daemon, codex app-server, opencode `serve`).
|
|
48
|
+
*
|
|
49
|
+
* agentbox NEVER kills a running server on its own — not on run
|
|
50
|
+
* completion, not on `abort()`, and not when {@link Agent.setup} detects
|
|
51
|
+
* a changed config/credential set. This method is the single, explicit,
|
|
52
|
+
* developer-driven teardown. Call it to free a server's resources, or to
|
|
53
|
+
* apply a changed config: after `killServer()` the next {@link setup}
|
|
54
|
+
* cold-starts a fresh server with the new configuration.
|
|
55
|
+
*
|
|
56
|
+
* Best-effort and idempotent: a no-op when no server is running, or when
|
|
57
|
+
* the provider has no shared server for the current mode (host-mode
|
|
58
|
+
* claude-code runs the SDK in-process; local codex spawns a fresh
|
|
59
|
+
* app-server per run, torn down with the run).
|
|
60
|
+
*/
|
|
61
|
+
killServer(): Promise<void>;
|
|
45
62
|
stream(runConfig: AgentRunConfig): AgentRun;
|
|
46
63
|
run(runConfig: AgentRunConfig): Promise<AgentResult>;
|
|
47
64
|
rawEvents(runConfig: AgentRunConfig): AsyncIterable<RawAgentEvent>;
|
package/dist/agents/index.js
CHANGED
|
@@ -583,6 +583,9 @@ function buildClaudeHookSettings(hooks) {
|
|
|
583
583
|
}
|
|
584
584
|
return { hooks };
|
|
585
585
|
}
|
|
586
|
+
function buildClaudeWorkflowSettings(ultracode) {
|
|
587
|
+
return ultracode ? { enableWorkflows: true, ultracode: true } : {};
|
|
588
|
+
}
|
|
586
589
|
function buildCodexHooksFile(hooks) {
|
|
587
590
|
if (!hasHookEntries(hooks)) {
|
|
588
591
|
return void 0;
|
|
@@ -1228,13 +1231,14 @@ async function preflightSetup(target, setupId, daemon) {
|
|
|
1228
1231
|
];
|
|
1229
1232
|
if (daemon) {
|
|
1230
1233
|
const url = `http://127.0.0.1:${daemon.port}${daemon.healthPath}`;
|
|
1234
|
+
const auth = daemon.curlAuthArg ? `${daemon.curlAuthArg} ` : "";
|
|
1231
1235
|
if (daemon.expectedVersionMatch) {
|
|
1232
1236
|
checks.push(
|
|
1233
|
-
`curl -fsS --max-time 2 ${shellQuote(url)} 2>/dev/null | grep -q ${shellQuote(daemon.expectedVersionMatch)}`
|
|
1237
|
+
`curl -fsS --max-time 2 ${auth}${shellQuote(url)} 2>/dev/null | grep -q ${shellQuote(daemon.expectedVersionMatch)}`
|
|
1234
1238
|
);
|
|
1235
1239
|
} else {
|
|
1236
1240
|
checks.push(
|
|
1237
|
-
`curl -fsS --max-time 2 ${shellQuote(url)} >/dev/null 2>&1`
|
|
1241
|
+
`curl -fsS --max-time 2 ${auth}${shellQuote(url)} >/dev/null 2>&1`
|
|
1238
1242
|
);
|
|
1239
1243
|
}
|
|
1240
1244
|
}
|
|
@@ -1513,6 +1517,46 @@ function buildCodexSubagentArtifacts(subAgents, layout) {
|
|
|
1513
1517
|
};
|
|
1514
1518
|
}
|
|
1515
1519
|
|
|
1520
|
+
// src/agents/config/capability-token.ts
|
|
1521
|
+
import crypto from "crypto";
|
|
1522
|
+
var tokenCache = /* @__PURE__ */ new WeakMap();
|
|
1523
|
+
async function readCapabilityTokenFile(sandbox, tokenFilePath) {
|
|
1524
|
+
const result = await sandbox.run(
|
|
1525
|
+
`if [ -f ${shellQuote(tokenFilePath)} ]; then cat ${shellQuote(tokenFilePath)}; fi`
|
|
1526
|
+
);
|
|
1527
|
+
if (result.exitCode !== 0) return void 0;
|
|
1528
|
+
const value = result.stdout.trim();
|
|
1529
|
+
return value.length > 0 ? value : void 0;
|
|
1530
|
+
}
|
|
1531
|
+
function resolveCapabilityToken(sandbox, tokenFilePath, create) {
|
|
1532
|
+
let byPath = tokenCache.get(sandbox);
|
|
1533
|
+
if (!byPath) {
|
|
1534
|
+
byPath = /* @__PURE__ */ new Map();
|
|
1535
|
+
tokenCache.set(sandbox, byPath);
|
|
1536
|
+
}
|
|
1537
|
+
const map = byPath;
|
|
1538
|
+
let cached = map.get(tokenFilePath);
|
|
1539
|
+
if (!cached) {
|
|
1540
|
+
const pending = (async () => {
|
|
1541
|
+
const existing = await readCapabilityTokenFile(sandbox, tokenFilePath);
|
|
1542
|
+
if (existing) return existing;
|
|
1543
|
+
if (create) return crypto.randomBytes(32).toString("hex");
|
|
1544
|
+
throw new Error(
|
|
1545
|
+
`Capability token file is missing at ${tokenFilePath}. setup() must run before connecting to this sandbox server.`
|
|
1546
|
+
);
|
|
1547
|
+
})().catch((error) => {
|
|
1548
|
+
map.delete(tokenFilePath);
|
|
1549
|
+
throw error;
|
|
1550
|
+
});
|
|
1551
|
+
map.set(tokenFilePath, pending);
|
|
1552
|
+
cached = pending;
|
|
1553
|
+
}
|
|
1554
|
+
return cached;
|
|
1555
|
+
}
|
|
1556
|
+
function withBearerToken(base, token) {
|
|
1557
|
+
return { ...base, Authorization: `Bearer ${token}` };
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1516
1560
|
// src/agents/cost.ts
|
|
1517
1561
|
function addIfNumber(target, key, value) {
|
|
1518
1562
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -1643,11 +1687,12 @@ function extractOpenCodeCostData(events) {
|
|
|
1643
1687
|
}
|
|
1644
1688
|
|
|
1645
1689
|
// src/agents/providers/claude-code.ts
|
|
1646
|
-
var DAEMON_PROTOCOL_VERSION = "
|
|
1690
|
+
var DAEMON_PROTOCOL_VERSION = "3";
|
|
1647
1691
|
var DAEMON_PORT = 43180;
|
|
1648
1692
|
var DAEMON_PATH = "/tmp/agentbox/claude-code/daemon.mjs";
|
|
1649
1693
|
var DAEMON_LOG_PATH = "/tmp/agentbox/claude-code/daemon.log";
|
|
1650
1694
|
var DAEMON_PID_PATH = "/tmp/agentbox/claude-code/daemon.pid";
|
|
1695
|
+
var DAEMON_TOKEN_PATH = "/tmp/agentbox/claude-code/daemon-token";
|
|
1651
1696
|
var DAEMON_READY_TIMEOUT_MS = 3e4;
|
|
1652
1697
|
var DAEMON_READY_POLL_INTERVAL_MS = 250;
|
|
1653
1698
|
function claudeConfigDir(options) {
|
|
@@ -1672,6 +1717,7 @@ function buildClaudeQueryOptions(params) {
|
|
|
1672
1717
|
extraArgs["append-system-prompt"] = run.systemPrompt;
|
|
1673
1718
|
}
|
|
1674
1719
|
const includeHookEvents = provider?.includeHookEvents ?? false;
|
|
1720
|
+
const effort = provider?.ultracode ? "xhigh" : run.reasoning;
|
|
1675
1721
|
return {
|
|
1676
1722
|
cwd: params.cwd ?? params.request.options.cwd,
|
|
1677
1723
|
env: params.env,
|
|
@@ -1684,7 +1730,7 @@ function buildClaudeQueryOptions(params) {
|
|
|
1684
1730
|
thinking: { type: "adaptive", display: "summarized" },
|
|
1685
1731
|
...provider?.additionalDirectories?.length ? { additionalDirectories: provider.additionalDirectories } : {},
|
|
1686
1732
|
...run.model ? { model: run.model } : {},
|
|
1687
|
-
...
|
|
1733
|
+
...effort ? { effort } : {},
|
|
1688
1734
|
...provider?.permissionMode ? { permissionMode: provider.permissionMode } : {},
|
|
1689
1735
|
...provider?.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
|
|
1690
1736
|
...provider?.allowedTools?.length ? { allowedTools: provider.allowedTools } : {},
|
|
@@ -1741,11 +1787,30 @@ function createClaudeCodeDaemonScript() {
|
|
|
1741
1787
|
const version = JSON.stringify(DAEMON_PROTOCOL_VERSION);
|
|
1742
1788
|
return `import http from "node:http";
|
|
1743
1789
|
import { execSync } from "node:child_process";
|
|
1744
|
-
import { existsSync } from "node:fs";
|
|
1790
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
1791
|
+
import { timingSafeEqual } from "node:crypto";
|
|
1745
1792
|
import { query, getSessionInfo } from "@anthropic-ai/claude-agent-sdk";
|
|
1746
1793
|
|
|
1747
1794
|
const VERSION = ${version};
|
|
1748
1795
|
const port = Number(process.argv[2] ?? "${DAEMON_PORT}");
|
|
1796
|
+
// Capability token: every route except the loopback /__version probe
|
|
1797
|
+
// requires \`Authorization: Bearer <token>\`. Loaded once at boot from the
|
|
1798
|
+
// 0600 file the host writes alongside this script. Fails closed (rejects
|
|
1799
|
+
// all run-control requests) when the file is missing or empty.
|
|
1800
|
+
const tokenFilePath = process.argv[3] ?? "";
|
|
1801
|
+
let AUTH_TOKEN = "";
|
|
1802
|
+
try { if (tokenFilePath) AUTH_TOKEN = readFileSync(tokenFilePath, "utf8").trim(); } catch {}
|
|
1803
|
+
|
|
1804
|
+
function isAuthorized(req) {
|
|
1805
|
+
if (!AUTH_TOKEN) return false;
|
|
1806
|
+
const header = req.headers["authorization"] || "";
|
|
1807
|
+
const presented = header.startsWith("Bearer ") ? header.slice(7) : "";
|
|
1808
|
+
if (!presented) return false;
|
|
1809
|
+
const a = Buffer.from(presented);
|
|
1810
|
+
const b = Buffer.from(AUTH_TOKEN);
|
|
1811
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1749
1814
|
const liveRuns = new Map();
|
|
1750
1815
|
|
|
1751
1816
|
// The SDK's default spawn does \`existsSync(pathToClaudeCodeExecutable)\`
|
|
@@ -1982,6 +2047,14 @@ const server = http.createServer((req, res) => {
|
|
|
1982
2047
|
res.end(VERSION);
|
|
1983
2048
|
return;
|
|
1984
2049
|
}
|
|
2050
|
+
// Capability-token gate for every run-control route. The /__version probe
|
|
2051
|
+
// above stays open: it carries no secret and the host probes it over
|
|
2052
|
+
// loopback (no bearer) to detect daemon liveness/version.
|
|
2053
|
+
if (!isAuthorized(req)) {
|
|
2054
|
+
res.writeHead(401, { "content-type": "text/plain" });
|
|
2055
|
+
res.end("unauthorized");
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
1985
2058
|
const url = req.url ?? "";
|
|
1986
2059
|
let m;
|
|
1987
2060
|
if (req.method === "POST" && (m = url.match(/^\\/runs\\/([^/]+)\\/start$/))) {
|
|
@@ -2052,6 +2125,11 @@ async function ensureClaudeCodeDaemonUncached(options, env) {
|
|
|
2052
2125
|
);
|
|
2053
2126
|
return;
|
|
2054
2127
|
}
|
|
2128
|
+
const daemonToken = await resolveCapabilityToken(
|
|
2129
|
+
sandbox,
|
|
2130
|
+
DAEMON_TOKEN_PATH,
|
|
2131
|
+
true
|
|
2132
|
+
);
|
|
2055
2133
|
const daemonDir = path8.posix.dirname(DAEMON_PATH);
|
|
2056
2134
|
const daemonNodeModules = `${daemonDir}/node_modules/@anthropic-ai`;
|
|
2057
2135
|
const launchCommand = [
|
|
@@ -2059,13 +2137,18 @@ async function ensureClaudeCodeDaemonUncached(options, env) {
|
|
|
2059
2137
|
`if [ -z "$NPM_ROOT" ] || [ ! -d "$NPM_ROOT/@anthropic-ai/claude-agent-sdk" ]; then echo "claude-code daemon launch: @anthropic-ai/claude-agent-sdk not found under $NPM_ROOT" >&2; exit 1; fi`,
|
|
2060
2138
|
`mkdir -p ${shellQuote(daemonNodeModules)}`,
|
|
2061
2139
|
`ln -sfn "$NPM_ROOT/@anthropic-ai/claude-agent-sdk" ${shellQuote(daemonNodeModules + "/claude-agent-sdk")}`,
|
|
2140
|
+
// The base uploadAndRun only chmods execute-bit artifacts, so the 0600
|
|
2141
|
+
// tarball mode is dropped on Daytona (and other non-Modal providers).
|
|
2142
|
+
// Tighten the just-written token file explicitly — matching codex —
|
|
2143
|
+
// so the bearer is never group/world-readable inside the sandbox.
|
|
2144
|
+
`chmod 600 ${shellQuote(DAEMON_TOKEN_PATH)}`,
|
|
2062
2145
|
`if [ -f ${shellQuote(DAEMON_PID_PATH)} ]; then kill -TERM "$(cat ${shellQuote(DAEMON_PID_PATH)})" 2>/dev/null || true; fi`,
|
|
2063
2146
|
`(fuser -k -n tcp ${DAEMON_PORT} 2>/dev/null || true)`,
|
|
2064
2147
|
// Brief grace so the kernel releases the port before the new
|
|
2065
2148
|
// daemon's listen() — only matters on warm-sandbox respawns;
|
|
2066
2149
|
// adds 200ms otherwise.
|
|
2067
2150
|
`sleep 0.2`,
|
|
2068
|
-
`(nohup node ${shellQuote(DAEMON_PATH)} ${DAEMON_PORT} > ${shellQuote(DAEMON_LOG_PATH)} 2>&1 & echo $! > ${shellQuote(DAEMON_PID_PATH)})`
|
|
2151
|
+
`(nohup node ${shellQuote(DAEMON_PATH)} ${DAEMON_PORT} ${shellQuote(DAEMON_TOKEN_PATH)} > ${shellQuote(DAEMON_LOG_PATH)} 2>&1 & echo $! > ${shellQuote(DAEMON_PID_PATH)})`
|
|
2069
2152
|
].join(" && ");
|
|
2070
2153
|
const launch = await time(
|
|
2071
2154
|
debugRelay,
|
|
@@ -2076,6 +2159,11 @@ async function ensureClaudeCodeDaemonUncached(options, env) {
|
|
|
2076
2159
|
path: DAEMON_PATH,
|
|
2077
2160
|
content: createClaudeCodeDaemonScript(),
|
|
2078
2161
|
mode: 420
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
path: DAEMON_TOKEN_PATH,
|
|
2165
|
+
content: daemonToken,
|
|
2166
|
+
mode: 384
|
|
2079
2167
|
}
|
|
2080
2168
|
],
|
|
2081
2169
|
launchCommand,
|
|
@@ -2171,6 +2259,10 @@ async function daemonBaseUrl(sandbox) {
|
|
|
2171
2259
|
const url = await sandbox.getPreviewLink(DAEMON_PORT);
|
|
2172
2260
|
return url.replace(/\/$/, "");
|
|
2173
2261
|
}
|
|
2262
|
+
async function daemonAuthHeaders(sandbox) {
|
|
2263
|
+
const token = await resolveCapabilityToken(sandbox, DAEMON_TOKEN_PATH, false);
|
|
2264
|
+
return withBearerToken(sandbox.previewHeaders, token);
|
|
2265
|
+
}
|
|
2174
2266
|
var ClaudeCodeAgentAdapter = class {
|
|
2175
2267
|
/**
|
|
2176
2268
|
* Sandbox-side preparation. Uploads `.claude/` artifacts and ensures
|
|
@@ -2181,6 +2273,24 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2181
2273
|
* match what we'd produce, we skip the artifact upload AND the daemon
|
|
2182
2274
|
* boot entirely.
|
|
2183
2275
|
*/
|
|
2276
|
+
/**
|
|
2277
|
+
* Explicit, developer-invoked teardown of the in-sandbox claude-code
|
|
2278
|
+
* relay daemon (see {@link AgentProviderAdapter.killServer}). agentbox
|
|
2279
|
+
* never calls this on its own. Best-effort and idempotent: a no-op when
|
|
2280
|
+
* the daemon isn't running or no sandbox is configured. After it returns
|
|
2281
|
+
* the next `setup()` re-spawns the daemon (its `/__version` probe fails).
|
|
2282
|
+
*/
|
|
2283
|
+
async killServer(request) {
|
|
2284
|
+
const sandbox = request.options.sandbox;
|
|
2285
|
+
if (!sandbox) return;
|
|
2286
|
+
await sandbox.run(
|
|
2287
|
+
[
|
|
2288
|
+
`if [ -f ${shellQuote(DAEMON_PID_PATH)} ]; then kill -TERM "$(cat ${shellQuote(DAEMON_PID_PATH)})" 2>/dev/null || true; rm -f ${shellQuote(DAEMON_PID_PATH)}; fi`,
|
|
2289
|
+
`fuser -k -n tcp ${DAEMON_PORT} 2>/dev/null || true`
|
|
2290
|
+
].join("; "),
|
|
2291
|
+
{ cwd: request.options.cwd, timeoutMs: 1e4 }
|
|
2292
|
+
).catch(() => void 0);
|
|
2293
|
+
}
|
|
2184
2294
|
async setup(request) {
|
|
2185
2295
|
await time(debugClaude, "claude-code setup()", async () => {
|
|
2186
2296
|
const options = request.options;
|
|
@@ -2205,12 +2315,19 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2205
2315
|
() => prepareSkillArtifacts(provider, options.skills, target.layout)
|
|
2206
2316
|
);
|
|
2207
2317
|
const hookSettings = buildClaudeHookSettings(hooks) ?? {};
|
|
2318
|
+
const workflowSettings = buildClaudeWorkflowSettings(
|
|
2319
|
+
options.provider?.ultracode
|
|
2320
|
+
);
|
|
2321
|
+
const claudeSettings = { ...hookSettings, ...workflowSettings };
|
|
2208
2322
|
const mcpConfigJson = buildClaudeMcpConfig(options.mcps) ?? JSON.stringify({ mcpServers: {} }, null, 2);
|
|
2209
2323
|
const artifacts = [
|
|
2210
2324
|
...skillArtifacts,
|
|
2211
2325
|
...buildClaudeCommandArtifacts(options.commands, target.layout),
|
|
2212
2326
|
...buildClaudeSubagentArtifacts(options.subAgents, target.layout),
|
|
2213
|
-
{
|
|
2327
|
+
{
|
|
2328
|
+
path: settingsPath,
|
|
2329
|
+
content: JSON.stringify(claudeSettings, null, 2)
|
|
2330
|
+
},
|
|
2214
2331
|
{ path: mcpConfigPath, content: mcpConfigJson }
|
|
2215
2332
|
];
|
|
2216
2333
|
const enableRtk = options.enableRtk === true;
|
|
@@ -2279,6 +2396,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2279
2396
|
"getPreviewLink daemon",
|
|
2280
2397
|
() => daemonBaseUrl(sandbox)
|
|
2281
2398
|
);
|
|
2399
|
+
const authHeaders = await daemonAuthHeaders(sandbox);
|
|
2282
2400
|
const startUrl = `${baseUrl}/runs/${encodeURIComponent(request.runId)}/start`;
|
|
2283
2401
|
const sdkOptions = buildClaudeQueryOptions({
|
|
2284
2402
|
request,
|
|
@@ -2310,7 +2428,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2310
2428
|
try {
|
|
2311
2429
|
await fetch(
|
|
2312
2430
|
`${baseUrl}/runs/${encodeURIComponent(request.runId)}/abort`,
|
|
2313
|
-
{ method: "POST", headers:
|
|
2431
|
+
{ method: "POST", headers: authHeaders }
|
|
2314
2432
|
);
|
|
2315
2433
|
} catch {
|
|
2316
2434
|
}
|
|
@@ -2327,7 +2445,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2327
2445
|
method: "POST",
|
|
2328
2446
|
headers: {
|
|
2329
2447
|
"content-type": "application/json",
|
|
2330
|
-
...
|
|
2448
|
+
...authHeaders
|
|
2331
2449
|
},
|
|
2332
2450
|
body: JSON.stringify({ content: mapped })
|
|
2333
2451
|
}
|
|
@@ -2342,7 +2460,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2342
2460
|
signal: fetchAbort.signal,
|
|
2343
2461
|
headers: {
|
|
2344
2462
|
"content-type": "application/json",
|
|
2345
|
-
...
|
|
2463
|
+
...authHeaders
|
|
2346
2464
|
},
|
|
2347
2465
|
body: JSON.stringify(requestBody)
|
|
2348
2466
|
})
|
|
@@ -2570,6 +2688,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2570
2688
|
*/
|
|
2571
2689
|
async attachAbort(request) {
|
|
2572
2690
|
const baseUrl = await daemonBaseUrl(request.sandbox);
|
|
2691
|
+
const authHeaders = await daemonAuthHeaders(request.sandbox);
|
|
2573
2692
|
const controller = new AbortController();
|
|
2574
2693
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
2575
2694
|
try {
|
|
@@ -2578,7 +2697,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2578
2697
|
{
|
|
2579
2698
|
method: "POST",
|
|
2580
2699
|
signal: controller.signal,
|
|
2581
|
-
headers:
|
|
2700
|
+
headers: authHeaders
|
|
2582
2701
|
}
|
|
2583
2702
|
).catch((error) => {
|
|
2584
2703
|
debugClaude("attachAbort POST failed: %o", error);
|
|
@@ -2595,6 +2714,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2595
2714
|
*/
|
|
2596
2715
|
async attachSendMessage(request, content) {
|
|
2597
2716
|
const baseUrl = await daemonBaseUrl(request.sandbox);
|
|
2717
|
+
const authHeaders = await daemonAuthHeaders(request.sandbox);
|
|
2598
2718
|
const inputParts = await validateProviderUserInput(
|
|
2599
2719
|
AgentProvider.ClaudeCode,
|
|
2600
2720
|
content
|
|
@@ -2606,7 +2726,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2606
2726
|
method: "POST",
|
|
2607
2727
|
headers: {
|
|
2608
2728
|
"content-type": "application/json",
|
|
2609
|
-
...
|
|
2729
|
+
...authHeaders
|
|
2610
2730
|
},
|
|
2611
2731
|
body: JSON.stringify({ content: mapped })
|
|
2612
2732
|
}
|
|
@@ -2620,7 +2740,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2620
2740
|
};
|
|
2621
2741
|
|
|
2622
2742
|
// src/agents/providers/codex.ts
|
|
2623
|
-
import
|
|
2743
|
+
import crypto2 from "crypto";
|
|
2624
2744
|
import path9 from "path";
|
|
2625
2745
|
|
|
2626
2746
|
// src/agents/transports/app-server.ts
|
|
@@ -2877,7 +2997,7 @@ function resolveCodexAppServerToken(sandbox, tokenFilePath, create) {
|
|
|
2877
2997
|
return existing;
|
|
2878
2998
|
}
|
|
2879
2999
|
if (create) {
|
|
2880
|
-
return
|
|
3000
|
+
return crypto2.randomBytes(32).toString("hex");
|
|
2881
3001
|
}
|
|
2882
3002
|
throw new Error(
|
|
2883
3003
|
`Codex app-server token file is missing at ${tokenFilePath}. setup() must run before connecting to the codex app-server.`
|
|
@@ -3573,10 +3693,34 @@ async function buildCodexInputItems(options, inputParts) {
|
|
|
3573
3693
|
);
|
|
3574
3694
|
return inputItems;
|
|
3575
3695
|
}
|
|
3696
|
+
async function killCodexAppServer(request) {
|
|
3697
|
+
const { options } = request;
|
|
3698
|
+
const sandbox = options.sandbox;
|
|
3699
|
+
if (!sandbox) return;
|
|
3700
|
+
const sharedTarget = await createSetupTarget(
|
|
3701
|
+
request.provider,
|
|
3702
|
+
REMOTE_CODEX_APP_SERVER_ID,
|
|
3703
|
+
options
|
|
3704
|
+
);
|
|
3705
|
+
const pidFilePath = path9.posix.join(
|
|
3706
|
+
sharedTarget.layout.rootDir,
|
|
3707
|
+
"codex-app-server.pid"
|
|
3708
|
+
);
|
|
3709
|
+
await sandbox.run(
|
|
3710
|
+
[
|
|
3711
|
+
`if [ -f ${shellQuote(pidFilePath)} ]; then kill "$(cat ${shellQuote(pidFilePath)})" 2>/dev/null || true; rm -f ${shellQuote(pidFilePath)}; fi`,
|
|
3712
|
+
`fuser -k -n tcp ${REMOTE_CODEX_APP_SERVER_PORT} 2>/dev/null || true`
|
|
3713
|
+
].join("; "),
|
|
3714
|
+
{ cwd: options.cwd, timeoutMs: 1e4 }
|
|
3715
|
+
).catch(() => void 0);
|
|
3716
|
+
}
|
|
3576
3717
|
var CodexAgentAdapter = class {
|
|
3577
3718
|
async setup(request) {
|
|
3578
3719
|
await setupCodex(request);
|
|
3579
3720
|
}
|
|
3721
|
+
async killServer(request) {
|
|
3722
|
+
await killCodexAppServer(request);
|
|
3723
|
+
}
|
|
3580
3724
|
async execute(request, sink) {
|
|
3581
3725
|
const executeStartedAt = Date.now();
|
|
3582
3726
|
debugCodex("execute() start runId=%s", request.runId);
|
|
@@ -3925,6 +4069,37 @@ var LOCAL_OPENCODE_PORT = 4096;
|
|
|
3925
4069
|
var SANDBOX_OPENCODE_READY_TIMEOUT_MS = 9e4;
|
|
3926
4070
|
var LOCAL_OPENCODE_READY_TIMEOUT_MS = 2e4;
|
|
3927
4071
|
var SHARED_OPENCODE_TARGET_ID = "shared-opencode-server";
|
|
4072
|
+
var OPENCODE_AUTH_USERNAME = "opencode";
|
|
4073
|
+
function opencodeServerTokenPath() {
|
|
4074
|
+
return path10.posix.join(
|
|
4075
|
+
agentboxRoot(AgentProvider.OpenCode, true),
|
|
4076
|
+
"opencode-auth-token"
|
|
4077
|
+
);
|
|
4078
|
+
}
|
|
4079
|
+
function opencodeCurlAuthArg() {
|
|
4080
|
+
return `-u "opencode:$(cat ${shellQuote(opencodeServerTokenPath())} 2>/dev/null)"`;
|
|
4081
|
+
}
|
|
4082
|
+
function opencodeHealthCurl(port) {
|
|
4083
|
+
return `curl -fsS --max-time 2 ${opencodeCurlAuthArg()} http://127.0.0.1:${port}/global/health >/dev/null 2>&1`;
|
|
4084
|
+
}
|
|
4085
|
+
async function isSandboxOpenCodeServerAuthEnforced(sandbox, cwd, port) {
|
|
4086
|
+
const probe = await sandbox.run(
|
|
4087
|
+
`test "$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 http://127.0.0.1:${port}/global/health)" = "401"`,
|
|
4088
|
+
{ cwd, timeoutMs: 5e3 }
|
|
4089
|
+
).catch(() => void 0);
|
|
4090
|
+
return probe?.exitCode === 0;
|
|
4091
|
+
}
|
|
4092
|
+
async function opencodeAuthHeaders(sandbox) {
|
|
4093
|
+
const token = await resolveCapabilityToken(
|
|
4094
|
+
sandbox,
|
|
4095
|
+
opencodeServerTokenPath(),
|
|
4096
|
+
false
|
|
4097
|
+
);
|
|
4098
|
+
const basic = Buffer.from(`${OPENCODE_AUTH_USERNAME}:${token}`).toString(
|
|
4099
|
+
"base64"
|
|
4100
|
+
);
|
|
4101
|
+
return { ...sandbox.previewHeaders, Authorization: `Basic ${basic}` };
|
|
4102
|
+
}
|
|
3928
4103
|
var LLM_API_KEY_ENV_VARS = [
|
|
3929
4104
|
"OPENROUTER_API_KEY",
|
|
3930
4105
|
"OPENAI_API_KEY",
|
|
@@ -3975,10 +4150,10 @@ async function killSandboxOpenCodeServer(sandbox, pidFilePath, cwd, port) {
|
|
|
3975
4150
|
).catch(() => void 0);
|
|
3976
4151
|
const deadline = Date.now() + 5e3;
|
|
3977
4152
|
while (Date.now() < deadline) {
|
|
3978
|
-
const probe = await sandbox.run(
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
);
|
|
4153
|
+
const probe = await sandbox.run(opencodeHealthCurl(port), {
|
|
4154
|
+
cwd,
|
|
4155
|
+
timeoutMs: 5e3
|
|
4156
|
+
});
|
|
3982
4157
|
if (probe.exitCode !== 0) {
|
|
3983
4158
|
return;
|
|
3984
4159
|
}
|
|
@@ -4118,6 +4293,12 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
4118
4293
|
SHARED_OPENCODE_TARGET_ID,
|
|
4119
4294
|
options
|
|
4120
4295
|
);
|
|
4296
|
+
const serverTokenPath = opencodeServerTokenPath();
|
|
4297
|
+
const serverToken = await resolveCapabilityToken(
|
|
4298
|
+
sandbox,
|
|
4299
|
+
serverTokenPath,
|
|
4300
|
+
true
|
|
4301
|
+
);
|
|
4121
4302
|
const { artifacts: skillArtifacts, installCommands } = await prepareSkillArtifacts(
|
|
4122
4303
|
request.provider,
|
|
4123
4304
|
options.skills,
|
|
@@ -4135,10 +4316,18 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
4135
4316
|
{
|
|
4136
4317
|
path: configPath,
|
|
4137
4318
|
content: JSON.stringify(openCodeConfig, null, 2)
|
|
4319
|
+
},
|
|
4320
|
+
{
|
|
4321
|
+
path: serverTokenPath,
|
|
4322
|
+
content: serverToken
|
|
4138
4323
|
}
|
|
4139
4324
|
];
|
|
4140
4325
|
const enableRtk = options.enableRtk === true;
|
|
4141
|
-
const daemonInfo = {
|
|
4326
|
+
const daemonInfo = {
|
|
4327
|
+
port,
|
|
4328
|
+
healthPath: "/global/health",
|
|
4329
|
+
curlAuthArg: opencodeCurlAuthArg()
|
|
4330
|
+
};
|
|
4142
4331
|
const setupId = computeSetupId({
|
|
4143
4332
|
artifacts: allArtifacts,
|
|
4144
4333
|
installCommands,
|
|
@@ -4152,6 +4341,17 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
4152
4341
|
debugOpencode("opencode setup() preflight hit \u2014 skipping");
|
|
4153
4342
|
return;
|
|
4154
4343
|
}
|
|
4344
|
+
if (await isSandboxOpenCodeServerHealthy(sandbox, options.cwd, port)) {
|
|
4345
|
+
if (await isSandboxOpenCodeServerAuthEnforced(sandbox, options.cwd, port)) {
|
|
4346
|
+
debugOpencode(
|
|
4347
|
+
"opencode server already running but setup drifted \u2014 reusing it without restart; call agent.killServer() to apply the new config"
|
|
4348
|
+
);
|
|
4349
|
+
return;
|
|
4350
|
+
}
|
|
4351
|
+
debugOpencode(
|
|
4352
|
+
"opencode server running without capability auth \u2014 restarting to enforce it"
|
|
4353
|
+
);
|
|
4354
|
+
}
|
|
4155
4355
|
const commonEnv = {
|
|
4156
4356
|
OPENCODE_CONFIG: configPath,
|
|
4157
4357
|
OPENCODE_CONFIG_DIR: target.layout.opencodeDir,
|
|
@@ -4170,9 +4370,18 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
4170
4370
|
target.layout.rootDir,
|
|
4171
4371
|
"opencode-serve.log"
|
|
4172
4372
|
);
|
|
4173
|
-
const serveEnv = {
|
|
4373
|
+
const serveEnv = {
|
|
4374
|
+
...options.env ?? {},
|
|
4375
|
+
...commonEnv,
|
|
4376
|
+
// Native opencode HTTP basic auth. The host presents this token on
|
|
4377
|
+
// every request (see opencodeAuthHeaders); the in-sandbox health probes
|
|
4378
|
+
// present it too (see opencodeHealthCurl).
|
|
4379
|
+
OPENCODE_SERVER_USERNAME: OPENCODE_AUTH_USERNAME,
|
|
4380
|
+
OPENCODE_SERVER_PASSWORD: serverToken
|
|
4381
|
+
};
|
|
4174
4382
|
const launchCommand = [
|
|
4175
4383
|
`mkdir -p ${shellQuote(target.layout.rootDir)}`,
|
|
4384
|
+
`chmod 600 ${shellQuote(serverTokenPath)} 2>/dev/null || true`,
|
|
4176
4385
|
`(${[
|
|
4177
4386
|
`setsid nohup ${[
|
|
4178
4387
|
binary,
|
|
@@ -4215,10 +4424,10 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
4215
4424
|
);
|
|
4216
4425
|
}
|
|
4217
4426
|
while (Date.now() < readyDeadline) {
|
|
4218
|
-
const probe = await sandbox.run(
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
);
|
|
4427
|
+
const probe = await sandbox.run(opencodeHealthCurl(port), {
|
|
4428
|
+
cwd: options.cwd,
|
|
4429
|
+
timeoutMs: 5e3
|
|
4430
|
+
});
|
|
4222
4431
|
if (probe.exitCode === 0) {
|
|
4223
4432
|
debugOpencode("ready on attempt %d", attempt);
|
|
4224
4433
|
return true;
|
|
@@ -4260,6 +4469,18 @@ opencode log:
|
|
|
4260
4469
|
${lastLog}` : "")
|
|
4261
4470
|
);
|
|
4262
4471
|
}
|
|
4472
|
+
if (!await isSandboxOpenCodeServerAuthEnforced(sandbox, options.cwd, port)) {
|
|
4473
|
+
await killSandboxOpenCodeServer(
|
|
4474
|
+
sandbox,
|
|
4475
|
+
pidFilePath,
|
|
4476
|
+
options.cwd,
|
|
4477
|
+
port
|
|
4478
|
+
).catch(() => void 0);
|
|
4479
|
+
await target.cleanup().catch(() => void 0);
|
|
4480
|
+
throw new Error(
|
|
4481
|
+
"OpenCode server started but is not enforcing the capability token (OPENCODE_SERVER_PASSWORD ignored). Upgrade opencode-ai to a version that supports server authentication."
|
|
4482
|
+
);
|
|
4483
|
+
}
|
|
4263
4484
|
await markSetupComplete(target, setupId);
|
|
4264
4485
|
});
|
|
4265
4486
|
}
|
|
@@ -4311,7 +4532,13 @@ async function ensureLocalOpenCodeServer(request) {
|
|
|
4311
4532
|
debugOpencode("local opencode server up-to-date \u2014 reusing");
|
|
4312
4533
|
return;
|
|
4313
4534
|
}
|
|
4314
|
-
|
|
4535
|
+
if (await isLocalOpenCodeServerHealthy()) {
|
|
4536
|
+
debugOpencode(
|
|
4537
|
+
"local opencode server already running but setup drifted \u2014 reusing it without restart; call agent.killServer() to apply the new config"
|
|
4538
|
+
);
|
|
4539
|
+
return;
|
|
4540
|
+
}
|
|
4541
|
+
debugOpencode("local opencode server absent \u2014 spawning");
|
|
4315
4542
|
await applyDifferentialSetup(target, allArtifacts, installCommands);
|
|
4316
4543
|
await killLocalOpenCodeServer();
|
|
4317
4544
|
spawnCommand({
|
|
@@ -4344,13 +4571,49 @@ async function setupOpenCode(request) {
|
|
|
4344
4571
|
}
|
|
4345
4572
|
await ensureLocalOpenCodeServer(request);
|
|
4346
4573
|
}
|
|
4574
|
+
async function isSandboxOpenCodeServerHealthy(sandbox, cwd, port) {
|
|
4575
|
+
const probe = await sandbox.run(opencodeHealthCurl(port), { cwd, timeoutMs: 5e3 }).catch(() => void 0);
|
|
4576
|
+
return probe?.exitCode === 0;
|
|
4577
|
+
}
|
|
4578
|
+
async function isLocalOpenCodeServerHealthy() {
|
|
4579
|
+
try {
|
|
4580
|
+
const res = await fetch(
|
|
4581
|
+
`http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`
|
|
4582
|
+
);
|
|
4583
|
+
return res.ok;
|
|
4584
|
+
} catch {
|
|
4585
|
+
return false;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
async function killOpenCodeServer(request) {
|
|
4589
|
+
const { options } = request;
|
|
4590
|
+
if (options.sandbox) {
|
|
4591
|
+
const target = await createSetupTarget(
|
|
4592
|
+
request.provider,
|
|
4593
|
+
SHARED_OPENCODE_TARGET_ID,
|
|
4594
|
+
options
|
|
4595
|
+
);
|
|
4596
|
+
const pidFilePath = path10.posix.join(
|
|
4597
|
+
target.layout.rootDir,
|
|
4598
|
+
"opencode-serve.pid"
|
|
4599
|
+
);
|
|
4600
|
+
await killSandboxOpenCodeServer(
|
|
4601
|
+
options.sandbox,
|
|
4602
|
+
pidFilePath,
|
|
4603
|
+
options.cwd,
|
|
4604
|
+
SANDBOX_OPENCODE_PORT
|
|
4605
|
+
);
|
|
4606
|
+
return;
|
|
4607
|
+
}
|
|
4608
|
+
await killLocalOpenCodeServer();
|
|
4609
|
+
}
|
|
4347
4610
|
async function buildOpenCodeRuntime(options) {
|
|
4348
4611
|
if (options.sandbox) {
|
|
4349
4612
|
const sandbox = options.sandbox;
|
|
4350
4613
|
const baseUrl2 = (await sandbox.getPreviewLink(SANDBOX_OPENCODE_PORT)).replace(/\/$/, "");
|
|
4351
4614
|
return {
|
|
4352
4615
|
baseUrl: baseUrl2,
|
|
4353
|
-
previewHeaders: sandbox
|
|
4616
|
+
previewHeaders: await opencodeAuthHeaders(sandbox),
|
|
4354
4617
|
raw: { baseUrl: baseUrl2, port: SANDBOX_OPENCODE_PORT }
|
|
4355
4618
|
};
|
|
4356
4619
|
}
|
|
@@ -4365,6 +4628,9 @@ var OpenCodeAgentAdapter = class {
|
|
|
4365
4628
|
async setup(request) {
|
|
4366
4629
|
await setupOpenCode(request);
|
|
4367
4630
|
}
|
|
4631
|
+
async killServer(request) {
|
|
4632
|
+
await killOpenCodeServer(request);
|
|
4633
|
+
}
|
|
4368
4634
|
async execute(request, sink) {
|
|
4369
4635
|
const executeStartedAt = Date.now();
|
|
4370
4636
|
debugOpencode("execute() start runId=%s", request.runId);
|
|
@@ -4881,6 +5147,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
4881
5147
|
);
|
|
4882
5148
|
}
|
|
4883
5149
|
const baseUrl = (await request.sandbox.getPreviewLink(SANDBOX_OPENCODE_PORT)).replace(/\/$/, "");
|
|
5150
|
+
const authHeaders = await opencodeAuthHeaders(request.sandbox);
|
|
4884
5151
|
const controller = new AbortController();
|
|
4885
5152
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
4886
5153
|
try {
|
|
@@ -4889,7 +5156,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
4889
5156
|
signal: controller.signal,
|
|
4890
5157
|
headers: {
|
|
4891
5158
|
"content-type": "application/json",
|
|
4892
|
-
...
|
|
5159
|
+
...authHeaders
|
|
4893
5160
|
}
|
|
4894
5161
|
}).catch((error) => {
|
|
4895
5162
|
debugOpencode(
|
|
@@ -4920,12 +5187,13 @@ var OpenCodeAgentAdapter = class {
|
|
|
4920
5187
|
content
|
|
4921
5188
|
);
|
|
4922
5189
|
const parts = mapToOpenCodeParts(inputParts);
|
|
5190
|
+
const authHeaders = await opencodeAuthHeaders(request.sandbox);
|
|
4923
5191
|
const url = `${baseUrl}/session/${request.sessionId}/prompt_async`;
|
|
4924
5192
|
const response = await fetch(url, {
|
|
4925
5193
|
method: "POST",
|
|
4926
5194
|
headers: {
|
|
4927
5195
|
"content-type": "application/json",
|
|
4928
|
-
...
|
|
5196
|
+
...authHeaders
|
|
4929
5197
|
},
|
|
4930
5198
|
body: JSON.stringify({
|
|
4931
5199
|
agent: openCodeAgentSlug(void 0),
|
|
@@ -5353,6 +5621,30 @@ var Agent = class {
|
|
|
5353
5621
|
throw error;
|
|
5354
5622
|
}
|
|
5355
5623
|
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Stop the long-lived provider CLI server booted by {@link Agent.setup}
|
|
5626
|
+
* (claude-code relay daemon, codex app-server, opencode `serve`).
|
|
5627
|
+
*
|
|
5628
|
+
* agentbox NEVER kills a running server on its own — not on run
|
|
5629
|
+
* completion, not on `abort()`, and not when {@link Agent.setup} detects
|
|
5630
|
+
* a changed config/credential set. This method is the single, explicit,
|
|
5631
|
+
* developer-driven teardown. Call it to free a server's resources, or to
|
|
5632
|
+
* apply a changed config: after `killServer()` the next {@link setup}
|
|
5633
|
+
* cold-starts a fresh server with the new configuration.
|
|
5634
|
+
*
|
|
5635
|
+
* Best-effort and idempotent: a no-op when no server is running, or when
|
|
5636
|
+
* the provider has no shared server for the current mode (host-mode
|
|
5637
|
+
* claude-code runs the SDK in-process; local codex spawns a fresh
|
|
5638
|
+
* app-server per run, torn down with the run).
|
|
5639
|
+
*/
|
|
5640
|
+
async killServer() {
|
|
5641
|
+
debugAgent("killServer() provider=%s", this.provider);
|
|
5642
|
+
await this.adapter.killServer({
|
|
5643
|
+
provider: this.provider,
|
|
5644
|
+
options: this.options
|
|
5645
|
+
});
|
|
5646
|
+
this.setupPromise = void 0;
|
|
5647
|
+
}
|
|
5356
5648
|
stream(runConfig) {
|
|
5357
5649
|
if (runConfig.resumeSessionId && runConfig.forkSessionId) {
|
|
5358
5650
|
throw new Error(
|
|
@@ -251,6 +251,20 @@ function resolveSandboxResources(resources) {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
// src/sandboxes/providers/daytona.ts
|
|
254
|
+
var STARTABLE_STATES = /* @__PURE__ */ new Set(["stopped", "archived"]);
|
|
255
|
+
var TERMINAL_STATES = /* @__PURE__ */ new Set([
|
|
256
|
+
"error",
|
|
257
|
+
"build_failed",
|
|
258
|
+
"destroyed",
|
|
259
|
+
"destroying"
|
|
260
|
+
]);
|
|
261
|
+
var ATTACH_SETTLE_TIMEOUT_MS = 12e4;
|
|
262
|
+
var ATTACH_POLL_INTERVAL_MS = 2e3;
|
|
263
|
+
function isStateChangeInProgressError(err) {
|
|
264
|
+
const e = err;
|
|
265
|
+
if (!e) return false;
|
|
266
|
+
return e.statusCode === 409 || e.name === "DaytonaConflictError" || /state change in progress/i.test(e.message ?? "");
|
|
267
|
+
}
|
|
254
268
|
var DaytonaSandboxAdapter = class extends SandboxAdapter {
|
|
255
269
|
client;
|
|
256
270
|
sandbox;
|
|
@@ -292,20 +306,54 @@ var DaytonaSandboxAdapter = class extends SandboxAdapter {
|
|
|
292
306
|
throw new Error(`Daytona sandbox ${id} not found`);
|
|
293
307
|
}
|
|
294
308
|
this.sandbox = existing;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
309
|
+
this.isWarmFlag = existing.state === "started";
|
|
310
|
+
await this.ensureStarted(existing);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Bring a sandbox to the `started` state, tolerating in-flight transitions.
|
|
314
|
+
*
|
|
315
|
+
* `start()` only works from a resting state (`stopped`/`archived`); calling
|
|
316
|
+
* it while the sandbox is creating/starting/restoring/snapshotting/etc. — or
|
|
317
|
+
* racing another caller that's already starting it — makes Daytona 409 with
|
|
318
|
+
* "Sandbox state change in progress". So we poll: start from a resting
|
|
319
|
+
* state, wait out a transition, fail fast on a terminal state, and treat a
|
|
320
|
+
* 409 as "someone else is mid-transition" and keep waiting.
|
|
321
|
+
*/
|
|
322
|
+
async ensureStarted(sandbox) {
|
|
323
|
+
let current = sandbox;
|
|
324
|
+
const deadline = Date.now() + ATTACH_SETTLE_TIMEOUT_MS;
|
|
325
|
+
for (; ; ) {
|
|
326
|
+
const state = current.state ?? "unknown";
|
|
327
|
+
if (state === "started") return;
|
|
328
|
+
if (TERMINAL_STATES.has(state)) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`Daytona sandbox ${current.id} is in a terminal state: ${state}`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
if (STARTABLE_STATES.has(state)) {
|
|
334
|
+
try {
|
|
335
|
+
await current.start();
|
|
336
|
+
return;
|
|
337
|
+
} catch (err) {
|
|
338
|
+
if (!isStateChangeInProgressError(err)) throw err;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (Date.now() >= deadline) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`Timed out waiting for Daytona sandbox ${current.id} to start (state=${state})`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
await sleep(ATTACH_POLL_INTERVAL_MS);
|
|
347
|
+
current = await this.client.get(current.id);
|
|
348
|
+
this.sandbox = current;
|
|
299
349
|
}
|
|
300
|
-
this.isWarmFlag = isWarm;
|
|
301
350
|
}
|
|
302
351
|
async provision() {
|
|
303
352
|
const existing = await this.findMatchingSandbox();
|
|
304
353
|
if (existing) {
|
|
305
354
|
this.sandbox = existing;
|
|
306
|
-
|
|
307
|
-
await
|
|
308
|
-
this.isWarmFlag = isWarm;
|
|
355
|
+
this.isWarmFlag = existing.state === "started";
|
|
356
|
+
await this.ensureStarted(existing);
|
|
309
357
|
return;
|
|
310
358
|
}
|
|
311
359
|
const labels = this.getLabels();
|
package/dist/events/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AISDKEvent, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, a1 as PermissionRequestedEvent, a2 as PermissionResolvedEvent, a3 as RawAgentEvent, a4 as ReasoningDeltaEvent, a6 as RunCancelledEvent, a7 as RunCompletedEvent, a8 as RunErrorEvent, a9 as RunStartedEvent, ab as TextDeltaEvent, ad as ToolCallCompletedEvent, ae as ToolCallDeltaEvent, af as ToolCallStartedEvent, ai as createNormalizedEvent, aj as normalizeRawAgentEvent, ak as toAISDKEvent, al as toAISDKStream } from '../types-
|
|
1
|
+
export { A as AISDKEvent, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, a1 as PermissionRequestedEvent, a2 as PermissionResolvedEvent, a3 as RawAgentEvent, a4 as ReasoningDeltaEvent, a6 as RunCancelledEvent, a7 as RunCompletedEvent, a8 as RunErrorEvent, a9 as RunStartedEvent, ab as TextDeltaEvent, ad as ToolCallCompletedEvent, ae as ToolCallDeltaEvent, af as ToolCallStartedEvent, ai as createNormalizedEvent, aj as normalizeRawAgentEvent, ak as toAISDKEvent, al as toAISDKStream } from '../types-vOsvzkcO.js';
|
|
2
2
|
import { AgentProvider } from '../enums.js';
|
|
3
3
|
import '../Sandbox-DcKAU-E3.js';
|
|
4
4
|
import 'e2b';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AttachedRun, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as OpenRouterPlugin, a1 as PermissionRequestedEvent, a2 as PermissionResolvedEvent, a3 as RawAgentEvent, a4 as ReasoningDeltaEvent, a5 as RepoSkillConfig, a6 as RunCancelledEvent, a7 as RunCompletedEvent, a8 as RunErrorEvent, a9 as RunStartedEvent, aa as SetupLayout, ab as TextDeltaEvent, ac as TextPart, ad as ToolCallCompletedEvent, ae as ToolCallDeltaEvent, af as ToolCallStartedEvent, ag as UserContent, ah as UserContentPart, ai as createNormalizedEvent, aj as normalizeRawAgentEvent, ak as toAISDKEvent, al as toAISDKStream } from './types-
|
|
1
|
+
export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AttachedRun, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as OpenRouterPlugin, a1 as PermissionRequestedEvent, a2 as PermissionResolvedEvent, a3 as RawAgentEvent, a4 as ReasoningDeltaEvent, a5 as RepoSkillConfig, a6 as RunCancelledEvent, a7 as RunCompletedEvent, a8 as RunErrorEvent, a9 as RunStartedEvent, aa as SetupLayout, ab as TextDeltaEvent, ac as TextPart, ad as ToolCallCompletedEvent, ae as ToolCallDeltaEvent, af as ToolCallStartedEvent, ag as UserContent, ah as UserContentPart, ai as createNormalizedEvent, aj as normalizeRawAgentEvent, ak as toAISDKEvent, al as toAISDKStream } from './types-vOsvzkcO.js';
|
|
2
2
|
export { AGENT_RESERVED_PORTS, Agent, agentboxRoot, collectAllAgentReservedPorts, getAgentLayout } from './agents/index.js';
|
|
3
3
|
export { A as AsyncCommandHandle, C as CommandEvent, a as CommandOptions, b as CommandResult, D as DaytonaProviderOptions, c as DaytonaSandboxOptions, E as E2bProviderOptions, d as E2bSandboxOptions, G as GitCloneOptions, L as LocalDockerProviderOptions, e as LocalDockerSandboxOptions, M as ModalProviderOptions, f as ModalSandboxOptions, S as Sandbox, g as SandboxDescriptor, h as SandboxListOptions, i as SandboxOptions, j as SandboxOptionsBase, k as SandboxOptionsMap, l as SandboxProviderName, m as SandboxRaw, n as SandboxRawMap, o as SandboxResourceSpec, T as TarballEntry, V as VercelGitSource, p as VercelProviderOptions, q as VercelSandboxOptions } from './Sandbox-DcKAU-E3.js';
|
|
4
4
|
export { SandboxAdapter, buildGitCloneCommand } from './sandboxes/index.js';
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
Agent,
|
|
3
3
|
agentboxRoot,
|
|
4
4
|
getAgentLayout
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KFMFNBVC.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderLogAssembler,
|
|
8
8
|
createNormalizedEvent,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
Sandbox,
|
|
15
15
|
SandboxAdapter,
|
|
16
16
|
buildGitCloneCommand
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TUBBWIOM.js";
|
|
18
18
|
import {
|
|
19
19
|
AGENT_RESERVED_PORTS,
|
|
20
20
|
collectAllAgentReservedPorts
|
package/dist/sandboxes/index.js
CHANGED
|
@@ -418,6 +418,18 @@ interface ClaudeCodeProviderOptions {
|
|
|
418
418
|
* silence them when hook noise drowns out the rest of the event stream.
|
|
419
419
|
*/
|
|
420
420
|
includeHookEvents?: boolean;
|
|
421
|
+
/**
|
|
422
|
+
* Enable "ultracode" for claude-code runs: xhigh reasoning effort plus
|
|
423
|
+
* standing dynamic-workflow orchestration (the built-in `Workflow` tool).
|
|
424
|
+
*
|
|
425
|
+
* When `true`, agentbox writes `enableWorkflows: true` + `ultracode: true`
|
|
426
|
+
* into the managed `settings.json` and forces `effort: "xhigh"` on the query.
|
|
427
|
+
*
|
|
428
|
+
* Requires an xhigh-capable model (e.g. Opus) and a recent runtime — the
|
|
429
|
+
* Workflows feature shipped around Claude Code 2.1.154 / Agent SDK 0.3.149.
|
|
430
|
+
* On older CLIs the settings keys are simply ignored.
|
|
431
|
+
*/
|
|
432
|
+
ultracode?: boolean;
|
|
421
433
|
}
|
|
422
434
|
interface CodexAgentOptions extends AgentOptionsBase {
|
|
423
435
|
provider?: CodexProviderOptions;
|
|
@@ -599,6 +611,22 @@ interface AgentProviderAdapter<P extends AgentProviderName = AgentProviderName>
|
|
|
599
611
|
* is already listening.
|
|
600
612
|
*/
|
|
601
613
|
setup(request: AgentSetupRequest<P>): Promise<void>;
|
|
614
|
+
/**
|
|
615
|
+
* Stop the long-lived provider CLI server that {@link setup} boots
|
|
616
|
+
* (claude-code relay daemon, codex app-server, opencode `serve`).
|
|
617
|
+
*
|
|
618
|
+
* agentbox NEVER calls this on its own — not on run completion, not on
|
|
619
|
+
* abort, and not when {@link setup} sees a changed config/credential
|
|
620
|
+
* set. It exists purely so a developer can explicitly tear a server
|
|
621
|
+
* down (to reclaim resources, or to force the changed config to apply
|
|
622
|
+
* on the next cold {@link setup}).
|
|
623
|
+
*
|
|
624
|
+
* Best-effort and idempotent: a no-op when nothing is running, or when
|
|
625
|
+
* the provider has no shared server for the current mode (host-mode
|
|
626
|
+
* claude-code runs the SDK in-process; local codex spawns a fresh
|
|
627
|
+
* app-server per run).
|
|
628
|
+
*/
|
|
629
|
+
killServer(request: AgentSetupRequest<P>): Promise<void>;
|
|
602
630
|
execute(request: AgentExecutionRequest<P>, sink: AgentRunSink): Promise<() => Promise<void> | void>;
|
|
603
631
|
/**
|
|
604
632
|
* Stateless abort. Dial the in-sandbox provider server, issue the
|