agentbox-sdk 0.1.316 → 0.1.318

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.
@@ -2,7 +2,7 @@ import {
2
2
  Agent,
3
3
  agentboxRoot,
4
4
  getAgentLayout
5
- } from "../chunk-SCT2IJ4Q.js";
5
+ } from "../chunk-MDHCTHCY.js";
6
6
  import "../chunk-2DH5OVG4.js";
7
7
  import {
8
8
  AGENT_RESERVED_PORTS,
@@ -2571,6 +2571,7 @@ var ClaudeCodeAgentAdapter = class {
2571
2571
  };
2572
2572
 
2573
2573
  // src/agents/providers/codex.ts
2574
+ import crypto from "crypto";
2574
2575
  import path9 from "path";
2575
2576
 
2576
2577
  // src/agents/transports/app-server.ts
@@ -2797,6 +2798,61 @@ function codexConfigDir(options) {
2797
2798
  }
2798
2799
  var REMOTE_CODEX_APP_SERVER_PORT = 43181;
2799
2800
  var REMOTE_CODEX_APP_SERVER_ID = "shared-app-server";
2801
+ var CODEX_APP_SERVER_TOKEN_FILENAME = "codex-app-server-token";
2802
+ function defaultRemoteCodexTokenPath() {
2803
+ return path9.posix.join(
2804
+ agentboxRoot(AgentProvider.Codex, true),
2805
+ CODEX_APP_SERVER_TOKEN_FILENAME
2806
+ );
2807
+ }
2808
+ var codexAppServerTokenCache = /* @__PURE__ */ new WeakMap();
2809
+ async function readCodexAppServerTokenFile(sandbox, tokenFilePath) {
2810
+ const result = await sandbox.run(
2811
+ `if [ -f ${shellQuote(tokenFilePath)} ]; then cat ${shellQuote(tokenFilePath)}; fi`
2812
+ );
2813
+ if (result.exitCode !== 0) {
2814
+ return void 0;
2815
+ }
2816
+ const value = result.stdout.trim();
2817
+ return value.length > 0 ? value : void 0;
2818
+ }
2819
+ function resolveCodexAppServerToken(sandbox, tokenFilePath, create) {
2820
+ let cached = codexAppServerTokenCache.get(sandbox);
2821
+ if (!cached) {
2822
+ cached = (async () => {
2823
+ const existing = await readCodexAppServerTokenFile(
2824
+ sandbox,
2825
+ tokenFilePath
2826
+ );
2827
+ if (existing) {
2828
+ return existing;
2829
+ }
2830
+ if (create) {
2831
+ return crypto.randomBytes(32).toString("hex");
2832
+ }
2833
+ throw new Error(
2834
+ `Codex app-server token file is missing at ${tokenFilePath}. setup() must run before connecting to the codex app-server.`
2835
+ );
2836
+ })().catch((error) => {
2837
+ codexAppServerTokenCache.delete(sandbox);
2838
+ throw error;
2839
+ });
2840
+ codexAppServerTokenCache.set(sandbox, cached);
2841
+ }
2842
+ return cached;
2843
+ }
2844
+ function ensureCodexAppServerToken(sandbox, tokenFilePath) {
2845
+ return resolveCodexAppServerToken(sandbox, tokenFilePath, true);
2846
+ }
2847
+ function getCodexAppServerToken(sandbox, tokenFilePath = defaultRemoteCodexTokenPath()) {
2848
+ return resolveCodexAppServerToken(sandbox, tokenFilePath, false);
2849
+ }
2850
+ function withCodexAppServerAuthHeaders(base, token) {
2851
+ return {
2852
+ ...base,
2853
+ Authorization: `Bearer ${token}`
2854
+ };
2855
+ }
2800
2856
  function compactEnv(values) {
2801
2857
  return Object.fromEntries(
2802
2858
  Object.entries(values).filter(([, value]) => value !== void 0)
@@ -3131,9 +3187,10 @@ async function withCodexAppServer(request, body) {
3131
3187
  );
3132
3188
  }
3133
3189
  const previewUrl = await sandbox.getPreviewLink(REMOTE_CODEX_APP_SERVER_PORT);
3190
+ const token = await getCodexAppServerToken(sandbox);
3134
3191
  const transport = await connectJsonRpcWebSocket(
3135
3192
  toRemoteCodexWebSocketUrl(previewUrl),
3136
- { headers: sandbox.previewHeaders }
3193
+ { headers: withCodexAppServerAuthHeaders(sandbox.previewHeaders, token) }
3137
3194
  );
3138
3195
  const client = new JsonRpcLineClient(
3139
3196
  transport.source,
@@ -3219,7 +3276,19 @@ async function setupCodex(request) {
3219
3276
  ...sharedTarget.env,
3220
3277
  ...options.provider?.env ?? {}
3221
3278
  });
3222
- const { artifacts: serverArtifacts } = buildArtifactsFor(sharedTarget);
3279
+ const tokenFilePath = path9.posix.join(
3280
+ sharedTarget.layout.rootDir,
3281
+ CODEX_APP_SERVER_TOKEN_FILENAME
3282
+ );
3283
+ const appServerToken = await ensureCodexAppServerToken(
3284
+ sandbox,
3285
+ tokenFilePath
3286
+ );
3287
+ const { artifacts: baseServerArtifacts } = buildArtifactsFor(sharedTarget);
3288
+ const serverArtifacts = [
3289
+ ...baseServerArtifacts,
3290
+ { path: tokenFilePath, content: appServerToken }
3291
+ ];
3223
3292
  const { artifacts: skillArtifacts2, installCommands: installCommands2 } = await prepareSkillArtifacts(provider, options.skills, target2.layout);
3224
3293
  const enableRtk2 = options.enableRtk === true;
3225
3294
  const daemonInfo = {
@@ -3260,6 +3329,7 @@ async function setupCodex(request) {
3260
3329
  `mkdir -p ${shellQuote(sharedTarget.layout.rootDir)}`,
3261
3330
  `if curl -fsS http://127.0.0.1:${REMOTE_CODEX_APP_SERVER_PORT}/readyz >/dev/null 2>&1; then exit 0; fi`,
3262
3331
  `if [ -f ${shellQuote(pidFilePath)} ]; then kill "$(cat ${shellQuote(pidFilePath)})" >/dev/null 2>&1 || true; rm -f ${shellQuote(pidFilePath)}; fi`,
3332
+ `chmod 600 ${shellQuote(tokenFilePath)}`,
3263
3333
  `(${[
3264
3334
  `nohup ${[
3265
3335
  "env",
@@ -3268,7 +3338,15 @@ async function setupCodex(request) {
3268
3338
  [
3269
3339
  "app-server",
3270
3340
  "--listen",
3271
- `ws://0.0.0.0:${REMOTE_CODEX_APP_SERVER_PORT}`
3341
+ `ws://0.0.0.0:${REMOTE_CODEX_APP_SERVER_PORT}`,
3342
+ // Auth on non-loopback listeners is opt-in in codex; without
3343
+ // these flags the 0.0.0.0 app-server accepts unauthenticated
3344
+ // clients. Requires codex >= 0.133 (`--ws-auth` flag); older
3345
+ // pinned binaries will fail to launch on the unknown arg.
3346
+ "--ws-auth",
3347
+ "capability-token",
3348
+ "--ws-token-file",
3349
+ tokenFilePath
3272
3350
  ],
3273
3351
  options
3274
3352
  )
@@ -3343,9 +3421,10 @@ async function createRuntime(request, inputParts) {
3343
3421
  "getPreviewLink app-server",
3344
3422
  () => sandbox.getPreviewLink(REMOTE_CODEX_APP_SERVER_PORT)
3345
3423
  );
3424
+ const token = await getCodexAppServerToken(sandbox);
3346
3425
  const transport = await connectRemoteCodexAppServer(
3347
3426
  toRemoteCodexWebSocketUrl(previewUrl),
3348
- sandbox.previewHeaders
3427
+ withCodexAppServerAuthHeaders(sandbox.previewHeaders, token)
3349
3428
  );
3350
3429
  debugCodex("\u2605 codex transport established");
3351
3430
  return {
@@ -3790,12 +3869,74 @@ var CodexAgentAdapter = class {
3790
3869
  };
3791
3870
 
3792
3871
  // src/agents/providers/opencode.ts
3872
+ import { createHash as createHash2 } from "crypto";
3793
3873
  import path10 from "path";
3794
3874
  var SANDBOX_OPENCODE_PORT = 4096;
3795
3875
  var LOCAL_OPENCODE_PORT = 4096;
3796
3876
  var SANDBOX_OPENCODE_READY_TIMEOUT_MS = 9e4;
3797
3877
  var LOCAL_OPENCODE_READY_TIMEOUT_MS = 2e4;
3798
3878
  var SHARED_OPENCODE_TARGET_ID = "shared-opencode-server";
3879
+ var LLM_API_KEY_ENV_VARS = [
3880
+ "OPENROUTER_API_KEY",
3881
+ "OPENAI_API_KEY",
3882
+ "ANTHROPIC_API_KEY",
3883
+ "GOOGLE_GENERATIVE_AI_API_KEY",
3884
+ "GEMINI_API_KEY"
3885
+ ];
3886
+ function hashLlmApiKeys(env) {
3887
+ const hasher = createHash2("sha256");
3888
+ for (const key of LLM_API_KEY_ENV_VARS) {
3889
+ if (env?.[key] !== void 0) {
3890
+ hasher.update(`${key}=${env[key]}
3891
+ `);
3892
+ }
3893
+ }
3894
+ return hasher.digest("hex");
3895
+ }
3896
+ async function killLocalOpenCodeServer() {
3897
+ await time(debugOpencode, "kill local opencode server", async () => {
3898
+ const killer = spawnCommand({
3899
+ command: "sh",
3900
+ args: [
3901
+ "-c",
3902
+ `lsof -ti tcp:${LOCAL_OPENCODE_PORT} | xargs kill 2>/dev/null || true`
3903
+ ]
3904
+ });
3905
+ await killer.wait().catch(() => void 0);
3906
+ await waitFor(
3907
+ async () => {
3908
+ try {
3909
+ const res = await fetch(
3910
+ `http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`
3911
+ );
3912
+ return !res.ok;
3913
+ } catch {
3914
+ return true;
3915
+ }
3916
+ },
3917
+ { timeoutMs: 5e3, intervalMs: 200 }
3918
+ ).catch(() => void 0);
3919
+ });
3920
+ }
3921
+ async function killSandboxOpenCodeServer(sandbox, pidFilePath, cwd, port) {
3922
+ await time(debugOpencode, "kill sandbox opencode server", async () => {
3923
+ await sandbox.run(
3924
+ `kill -- -"$(cat ${shellQuote(pidFilePath)})" 2>/dev/null || kill "$(cat ${shellQuote(pidFilePath)})" 2>/dev/null || true`,
3925
+ { cwd, timeoutMs: 5e3 }
3926
+ ).catch(() => void 0);
3927
+ const deadline = Date.now() + 5e3;
3928
+ while (Date.now() < deadline) {
3929
+ const probe = await sandbox.run(
3930
+ `curl -fsS --max-time 2 http://127.0.0.1:${port}/global/health >/dev/null 2>&1`,
3931
+ { cwd, timeoutMs: 5e3 }
3932
+ );
3933
+ if (probe.exitCode !== 0) {
3934
+ return;
3935
+ }
3936
+ await sleep(200);
3937
+ }
3938
+ });
3939
+ }
3799
3940
  function toRawEvent3(runId, payload, type) {
3800
3941
  return {
3801
3942
  provider: AgentProvider.OpenCode,
@@ -3891,6 +4032,10 @@ function buildOpenCodeConfig(options, interactiveApproval) {
3891
4032
  const googleBaseUrl = options.env?.GOOGLE_BASE_URL;
3892
4033
  const openRouterBaseUrl = options.env?.OPENROUTER_BASE_URL;
3893
4034
  const openRouterPlugins = options.openRouterPlugins && options.openRouterPlugins.length > 0 ? options.openRouterPlugins : void 0;
4035
+ const openRouterExtraBody = {
4036
+ transforms: ["middle-out"],
4037
+ ...openRouterPlugins ? { plugins: openRouterPlugins } : {}
4038
+ };
3894
4039
  return {
3895
4040
  $schema: "https://opencode.ai/config.json",
3896
4041
  ...mcpConfig ? { mcp: mcpConfig } : {},
@@ -3899,7 +4044,7 @@ function buildOpenCodeConfig(options, interactiveApproval) {
3899
4044
  openrouter: {
3900
4045
  options: {
3901
4046
  baseURL: openRouterBaseUrl || "https://openrouter.ai/api/v1",
3902
- ...openRouterPlugins ? { plugins: openRouterPlugins } : {}
4047
+ extraBody: openRouterExtraBody
3903
4048
  }
3904
4049
  },
3905
4050
  ...googleBaseUrl ? { google: { options: { baseURL: googleBaseUrl } } } : {}
@@ -3949,7 +4094,10 @@ async function ensureSandboxOpenCodeServer(request) {
3949
4094
  artifacts: allArtifacts,
3950
4095
  installCommands,
3951
4096
  daemon: daemonInfo,
3952
- extras: [`enableRtk:${enableRtk}`]
4097
+ extras: [
4098
+ `enableRtk:${enableRtk}`,
4099
+ `apiKeys:${hashLlmApiKeys(options.env)}`
4100
+ ]
3953
4101
  });
3954
4102
  if (await preflightSetup(target, setupId, daemonInfo)) {
3955
4103
  debugOpencode("opencode setup() preflight hit \u2014 skipping");
@@ -3990,13 +4138,14 @@ async function ensureSandboxOpenCodeServer(request) {
3990
4138
  `disown 2>/dev/null || true`
3991
4139
  ].join(" ")})`
3992
4140
  ].join(" && ");
4141
+ await killSandboxOpenCodeServer(sandbox, pidFilePath, options.cwd, port);
3993
4142
  const launchResult = await time(
3994
4143
  debugOpencode,
3995
4144
  "spawn opencode serve",
3996
4145
  () => sandbox.run(launchCommand, {
3997
4146
  cwd: options.cwd,
3998
4147
  env: serveEnv,
3999
- timeoutMs: 1e4
4148
+ timeoutMs: 2e4
4000
4149
  })
4001
4150
  );
4002
4151
  if (launchResult.exitCode !== 0) {
@@ -4030,16 +4179,6 @@ async function ensureSandboxOpenCodeServer(request) {
4030
4179
  }
4031
4180
  async function ensureLocalOpenCodeServer(request) {
4032
4181
  const options = request.options;
4033
- try {
4034
- await waitForHttpReady(
4035
- `http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`,
4036
- { timeoutMs: 1e3 }
4037
- );
4038
- debugOpencode("local opencode server already running \u2014 reusing");
4039
- return;
4040
- } catch {
4041
- debugOpencode("local opencode server not running \u2014 cold-spawning");
4042
- }
4043
4182
  const plugins = assertHooksSupported(request.provider, options);
4044
4183
  assertCommandsSupported(request.provider, options.commands);
4045
4184
  const interactiveApproval = isInteractiveApproval(options);
@@ -4072,14 +4211,23 @@ async function ensureLocalOpenCodeServer(request) {
4072
4211
  content: JSON.stringify(openCodeConfig, null, 2)
4073
4212
  }
4074
4213
  ];
4214
+ const daemonInfo = {
4215
+ port: LOCAL_OPENCODE_PORT,
4216
+ healthPath: "/global/health"
4217
+ };
4075
4218
  const setupId = computeSetupId({
4076
4219
  artifacts: allArtifacts,
4077
- installCommands
4220
+ installCommands,
4221
+ daemon: daemonInfo,
4222
+ extras: [`apiKeys:${hashLlmApiKeys(options.env)}`]
4078
4223
  });
4079
- const preflightHit = await preflightSetup(target, setupId);
4080
- if (!preflightHit) {
4081
- await applyDifferentialSetup(target, allArtifacts, installCommands);
4224
+ if (await preflightSetup(target, setupId, daemonInfo)) {
4225
+ debugOpencode("local opencode server up-to-date \u2014 reusing");
4226
+ return;
4082
4227
  }
4228
+ debugOpencode("local opencode server drifted/absent \u2014 (re)spawning");
4229
+ await applyDifferentialSetup(target, allArtifacts, installCommands);
4230
+ await killLocalOpenCodeServer();
4083
4231
  spawnCommand({
4084
4232
  command: options.provider?.binary ?? "opencode",
4085
4233
  args: [
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  Agent,
3
3
  agentboxRoot,
4
4
  getAgentLayout
5
- } from "./chunk-SCT2IJ4Q.js";
5
+ } from "./chunk-MDHCTHCY.js";
6
6
  import {
7
7
  ProviderLogAssembler,
8
8
  createNormalizedEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbox-sdk",
3
- "version": "0.1.316",
3
+ "version": "0.1.318",
4
4
  "description": "Swappable coding agents and sandbox providers for Bun and TypeScript.",
5
5
  "license": "MIT",
6
6
  "repository": {