@madarco/agentbox 0.8.0 → 0.9.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.
- package/dist/{_cloud-attach-T727ZPRV.js → _cloud-attach-ZXBCNWJX.js} +4 -4
- package/dist/{chunk-67N47KUS.js → chunk-BXQMIEHC.js} +106 -31
- package/dist/chunk-BXQMIEHC.js.map +1 -0
- package/dist/{chunk-FODMEHD3.js → chunk-GU5LW4B5.js} +341 -25
- package/dist/chunk-GU5LW4B5.js.map +1 -0
- package/dist/{chunk-BGK32PZE.js → chunk-KL36BRN4.js} +2 -2
- package/dist/chunk-KL36BRN4.js.map +1 -0
- package/dist/chunk-MTVI44DW.js +662 -0
- package/dist/chunk-MTVI44DW.js.map +1 -0
- package/dist/{chunk-6OZDFNBF.js → chunk-NCJP5MTN.js} +201 -44
- package/dist/chunk-NCJP5MTN.js.map +1 -0
- package/dist/{dist-LOZBWMBF.js → dist-32EZBYG4.js} +9 -3
- package/dist/{dist-L4LCG5SJ.js → dist-CX5CGVEB.js} +4 -4
- package/dist/{dist-ZODPD2I6.js → dist-GDHP34ZK.js} +8 -10
- package/dist/dist-GDHP34ZK.js.map +1 -0
- package/dist/dist-XML54CNB.js +849 -0
- package/dist/dist-XML54CNB.js.map +1 -0
- package/dist/index.js +636 -340
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-CL4CWXQA-ME4HSKDE.js → prepared-state-CL4CWXQA-H5THETIM.js} +2 -2
- package/package.json +7 -5
- package/runtime/docker/packages/ctl/dist/bin.cjs +98 -29
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +15 -1
- package/runtime/hetzner/agentbox-vnc-start +15 -1
- package/runtime/hetzner/ctl.cjs +98 -29
- package/runtime/relay/bin.cjs +229 -37
- package/runtime/vercel/agentbox-checkpoint-cleanup +52 -0
- package/runtime/vercel/agentbox-codex-hooks.json +68 -0
- package/runtime/vercel/agentbox-open +28 -0
- package/runtime/vercel/agentbox-setup-skill.md +196 -0
- package/runtime/vercel/agentbox-vnc-start +91 -0
- package/runtime/vercel/claude-managed-settings.json +115 -0
- package/runtime/vercel/ctl.cjs +23466 -0
- package/runtime/vercel/custom-system-CLAUDE.md +50 -0
- package/runtime/vercel/gh-shim +263 -0
- package/runtime/vercel/git-shim +131 -0
- package/runtime/vercel/scripts/provision.sh +274 -0
- package/dist/chunk-67N47KUS.js.map +0 -1
- package/dist/chunk-6OZDFNBF.js.map +0 -1
- package/dist/chunk-BGK32PZE.js.map +0 -1
- package/dist/chunk-FODMEHD3.js.map +0 -1
- package/dist/dist-ZODPD2I6.js.map +0 -1
- /package/dist/{_cloud-attach-T727ZPRV.js.map → _cloud-attach-ZXBCNWJX.js.map} +0 -0
- /package/dist/{dist-LOZBWMBF.js.map → dist-32EZBYG4.js.map} +0 -0
- /package/dist/{dist-L4LCG5SJ.js.map → dist-CX5CGVEB.js.map} +0 -0
- /package/dist/{prepared-state-CL4CWXQA-ME4HSKDE.js.map → prepared-state-CL4CWXQA-H5THETIM.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/sandbox-vercel/src/env-loader.ts","../../../packages/sandbox-vercel/src/sbx-cli.ts","../../../packages/sandbox-vercel/src/credentials.ts","../../../packages/sandbox-vercel/src/cli-store.ts","../../../packages/sandbox-vercel/src/sdk.ts","../../../packages/sandbox-vercel/src/vercel-rest.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\n\n/**\n * Vercel env auto-loader. The `@vercel/sandbox` SDK reads `VERCEL_OIDC_TOKEN`\n * from `process.env`; for the access-token path we read `VERCEL_TOKEN` +\n * `VERCEL_TEAM_ID` + `VERCEL_PROJECT_ID` and thread them into every SDK call as\n * explicit `Credentials`. We pull all of these in from `~/.agentbox/secrets.env`\n * (written by `agentbox vercel login`) so the SDK Just Works after a one-time\n * login — exactly the daytona/hetzner model.\n *\n * Lookup order (first wins; process.env is never overwritten):\n * 1. `process.env` (already set in the shell).\n * 2. `~/.agentbox/secrets.env` — written by `agentbox vercel login`.\n *\n * Project-level `.env` / `.env.local` are intentionally NOT consulted: those\n * files belong to the app code being developed, and a `VERCEL_*` value there\n * (e.g. a `vercel env pull` OIDC token, or the app's own deploy token) is meant\n * for in-box code, not for the host CLI to harvest and provision sandboxes with.\n * Put host credentials in `~/.agentbox/secrets.env` (or the shell env).\n *\n * Only Vercel-prefixed keys are imported; the rest of the file is left alone.\n * Idempotent and side-effect-free after the first call.\n */\nconst VERCEL_KEYS = [\n 'VERCEL_OIDC_TOKEN',\n 'VERCEL_TOKEN',\n 'VERCEL_TEAM_ID',\n 'VERCEL_PROJECT_ID',\n // Marker for CLI-login mode (`agentbox vercel login` → `sandbox login`). The\n // access token is NOT stored here — it's read live from the Vercel CLI store;\n // only this marker + team/project ids are persisted.\n 'VERCEL_AUTH_SOURCE',\n] as const;\n\nlet loaded = false;\n\nexport function ensureVercelEnvLoaded(): void {\n if (loaded) return;\n loaded = true;\n importVercelFromFile(resolve(homedir(), '.agentbox', 'secrets.env'), VERCEL_KEYS);\n}\n\n/**\n * Force a re-read of `~/.agentbox/secrets.env`. Used by the interactive\n * `agentbox vercel login` flow after it persists the credential trio, so the\n * same process can pick it up without a restart.\n */\nexport function reloadVercelEnv(): void {\n loaded = false;\n ensureVercelEnvLoaded();\n}\n\nfunction importVercelFromFile(path: string, keys: readonly string[]): void {\n if (!existsSync(path)) return;\n let body: string;\n try {\n body = readFileSync(path, 'utf8');\n } catch {\n return;\n }\n const parsed = parseEnvFile(body);\n for (const key of keys) {\n if (process.env[key] !== undefined) continue;\n const value = parsed[key];\n if (typeof value === 'string') {\n process.env[key] = value;\n }\n }\n}\n\n/**\n * Minimal `.env` parser: handles `KEY=value`, `KEY=\"value\"`, `KEY='value'`,\n * `export KEY=value`, blank lines, and `#` comments. No variable\n * interpolation — predictable over feature-complete (matches the daytona\n * loader's behavior).\n */\nexport function parseEnvFile(body: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const rawLine of body.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (line.length === 0 || line.startsWith('#')) continue;\n const stripped = line.startsWith('export ') ? line.slice('export '.length) : line;\n const eq = stripped.indexOf('=');\n if (eq <= 0) continue;\n const key = stripped.slice(0, eq).trim();\n let value = stripped.slice(eq + 1).trim();\n if (\n value.length >= 2 &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n out[key] = value;\n }\n return out;\n}\n","/**\n * Driver for the official Vercel Sandbox CLI (`sandbox` / `sbx`, installed via\n * `npm i -g sandbox`). AgentBox's CLI-login auth mode uses it for two things:\n * - `loginSbx` — run `sandbox login` interactively so the user completes\n * the browser OAuth and the CLI writes its own credential store.\n * - `refreshSbxToken` — run a cheap read command (`sandbox list`) which makes\n * the CLI lazily refresh its access token from its stored refresh token\n * when the token is stale. Verified non-interactive: a stale token is\n * refreshed without opening a browser.\n *\n * Mirrors the probe/install patterns in sandbox-docker/src/portless.ts: execa\n * with `reject:false` for never-throw probes, spawnSync with inherited stdio for\n * the interactive login.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { execa } from 'execa';\n\n/**\n * Binaries the Sandbox CLI installs. `sbx` is the short alias; we prefer it but\n * fall back to `sandbox`. Pinned here so a future rename is a one-line fix.\n */\nconst SBX_BINS = ['sbx', 'sandbox'] as const;\n\nexport interface SbxState {\n /** A Sandbox CLI binary resolved on PATH and answered `--version`. */\n installed: boolean;\n /** The binary name that answered (`sbx` or `sandbox`), when installed. */\n bin?: string;\n /** Version string, when installed. */\n version?: string;\n}\n\nlet cached: SbxState | null = null;\n\n/**\n * Probe the host for the Sandbox CLI. Cached per-process (install state can't\n * change mid-command); `resetSbxCache` clears it after an install or for tests.\n */\nexport async function detectSbx(): Promise<SbxState> {\n if (cached !== null) return cached;\n for (const bin of SBX_BINS) {\n try {\n const r = await execa(bin, ['--version'], { reject: false });\n if (r.exitCode === 0) {\n cached = { installed: true, bin, version: (r.stdout ?? '').trim() || undefined };\n return cached;\n }\n } catch {\n // try the next bin name\n }\n }\n cached = { installed: false };\n return cached;\n}\n\n/** Drop the per-process probe cache so the next `detectSbx()` re-probes. */\nexport function resetSbxCache(): void {\n cached = null;\n}\n\n/** Command the user should run to install the Sandbox CLI. */\nexport function installSbxHint(): string {\n return 'npm install -g sandbox';\n}\n\n/** Install the Sandbox CLI globally (`npm install -g sandbox`). Never throws. */\nexport async function installSbx(): Promise<boolean> {\n try {\n const r = await execa('npm', ['install', '-g', 'sandbox'], { reject: false });\n return r.exitCode === 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Run `sandbox login` with inherited stdio so the user sees the CLI's own\n * browser-OAuth output and can interact with it. Blocking, like the interactive\n * agent launch path. Returns the exit status (0 = success).\n */\nexport function loginSbx(bin: string): number {\n const r = spawnSync(bin, ['login'], { stdio: 'inherit' });\n return r.status ?? 1;\n}\n\n/**\n * Trigger the CLI's lazy token refresh by running a cheap read command. The CLI\n * refreshes its access token from the stored refresh token when the token is\n * stale and leaves a still-valid token untouched, so this is safe to call\n * eagerly. Non-interactive (stdin from /dev/null); returns true on exit 0.\n */\nexport async function refreshSbxToken(bin: string): Promise<boolean> {\n try {\n const r = await execa(bin, ['list'], {\n reject: false,\n timeout: 30_000,\n stdin: 'ignore',\n });\n return r.exitCode === 0;\n } catch {\n return false;\n }\n}\n","import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, resolve } from 'node:path';\nimport {\n confirm,\n isCancel,\n intro,\n log,\n note,\n outro,\n password,\n select,\n spinner,\n text,\n} from '@clack/prompts';\nimport { ensureVercelEnvLoaded, reloadVercelEnv } from './env-loader.js';\nimport { hasUsableCredentials } from './sdk.js';\nimport { cliStorePaths, isNearExpiry, readCliAuth, readCliCurrentTeam } from './cli-store.js';\nimport { detectSbx, installSbx, installSbxHint, loginSbx, resetSbxCache } from './sbx-cli.js';\nimport { createProject, getUser, listProjects, type VercelProject } from './vercel-rest.js';\n\nconst DASHBOARD_TOKENS_URL = 'https://vercel.com/account/settings/tokens';\n\n/**\n * Keys we manage in `~/.agentbox/secrets.env`. On reconfigure we strip prior\n * values for these before appending so the file never accumulates duplicates.\n * `VERCEL_AUTH_SOURCE` is the CLI-login marker; the access token itself is never\n * stored here in that mode (it's read live from the Vercel CLI store).\n */\nconst MANAGED_KEYS = [\n 'VERCEL_OIDC_TOKEN',\n 'VERCEL_TOKEN',\n 'VERCEL_TEAM_ID',\n 'VERCEL_PROJECT_ID',\n 'VERCEL_AUTH_SOURCE',\n] as const;\n\nexport interface EnsureVercelCredentialsOptions {\n /** Re-prompt even when valid credentials are already present (`agentbox vercel login`). */\n force?: boolean;\n}\n\n/**\n * First-run interactive setup for Vercel credentials. The access-token path\n * persists a `VERCEL_TOKEN` trio to `~/.agentbox/secrets.env` (the canonical\n * store, matching daytona/hetzner). OIDC is also supported, but the token must\n * be present in the shell env or in `~/.agentbox/secrets.env` — agentbox does\n * NOT harvest `.env.local` (that file belongs to the app being developed).\n *\n * No-op when credentials are already configured. Silent no-op when stdin isn't\n * a TTY so scripted/CI callers get the SDK's \"not configured\" error instead of\n * a hung prompt.\n */\nexport async function ensureVercelCredentials(\n opts: EnsureVercelCredentialsOptions = {},\n): Promise<void> {\n ensureVercelEnvLoaded();\n\n if (!opts.force && hasUsableCredentials()) return;\n if (!process.stdin.isTTY) return;\n\n intro('Vercel setup');\n note(\n `AgentBox needs Vercel credentials to provision sandboxes.\\n` +\n `Sign in with Vercel (recommended): drives the Vercel \\`sandbox\\` CLI through a browser login, then reads the token from the CLI's own store and keeps it fresh — no token to paste.\\n` +\n `Access token (best for CI / headless): personal access token + team id + project id, saved to \\`~/.agentbox/secrets.env\\`.\\n` +\n `OIDC (short interactive work): export VERCEL_OIDC_TOKEN in your shell or add it to \\`~/.agentbox/secrets.env\\` (dev token expires ~12h, no headless refresh).`,\n 'Credentials required',\n );\n\n const mode = await select({\n message: 'How do you want to authenticate?',\n options: [\n { value: 'cli', label: 'Sign in with Vercel (browser) — recommended for interactive use' },\n { value: 'token', label: 'Access token (VERCEL_TOKEN + team + project) — best for CI / headless' },\n { value: 'oidc', label: 'OIDC token (VERCEL_OIDC_TOKEN in env / secrets.env) — short interactive work' },\n ],\n initialValue: 'cli',\n });\n if (isCancel(mode)) {\n log.warn('Vercel setup cancelled — re-run `agentbox vercel login` when ready.');\n return;\n }\n\n if (mode === 'cli') {\n await runCliLogin();\n return;\n }\n\n if (mode === 'oidc') {\n note(\n `Get an OIDC token with \\`vercel link\\` then \\`vercel env pull\\`, then make it visible to AgentBox by either:\\n` +\n ` export VERCEL_OIDC_TOKEN=<token> # in this shell\\n` +\n ` echo \"VERCEL_OIDC_TOKEN=<token>\" >> ~/.agentbox/secrets.env\\n` +\n `Re-do every ~12h; the dev token expires. AgentBox does not harvest .env.local.`,\n 'OIDC setup',\n );\n // Re-read in case the user already added the token to secrets.env.\n reloadVercelEnv();\n if (process.env.VERCEL_OIDC_TOKEN) {\n log.success('Found VERCEL_OIDC_TOKEN — Vercel is configured.');\n await ensureSbxInstalled();\n outro('Setup complete.');\n } else {\n log.warn('No VERCEL_OIDC_TOKEN found yet — set it as above, then re-run `agentbox vercel login`.');\n }\n return;\n }\n\n const creds = await promptForTokenTrio();\n if (creds === null) return;\n persistCredentials(creds);\n log.success(`Vercel credentials saved to ${secretsPath()}`);\n await ensureSbxInstalled();\n outro('Setup complete.');\n}\n\ninterface TokenTrio {\n token: string;\n teamId: string;\n projectId: string;\n}\n\nasync function promptForTokenTrio(): Promise<TokenTrio | null> {\n const openIt = await confirm({\n message: `Open ${DASHBOARD_TOKENS_URL} to create a token?`,\n initialValue: true,\n });\n if (isCancel(openIt)) return null;\n if (openIt) openDashboard();\n\n const token = await password({\n message: 'Paste your Vercel access token',\n validate: (v) => (v && v.trim().length > 0 ? undefined : 'Cannot be empty'),\n });\n if (isCancel(token)) {\n log.warn('Vercel setup cancelled.');\n return null;\n }\n const teamId = await text({\n message: 'Team ID (team settings → General)',\n placeholder: 'team_...',\n validate: (v) => (v && v.trim().length > 0 ? undefined : 'Cannot be empty'),\n });\n if (isCancel(teamId)) {\n log.warn('Vercel setup cancelled.');\n return null;\n }\n const projectId = await text({\n message: 'Project ID (project settings → General)',\n placeholder: 'prj_...',\n validate: (v) => (v && v.trim().length > 0 ? undefined : 'Cannot be empty'),\n });\n if (isCancel(projectId)) {\n log.warn('Vercel setup cancelled.');\n return null;\n }\n return { token: token.trim(), teamId: teamId.trim(), projectId: projectId.trim() };\n}\n\nfunction persistCredentials(creds: TokenTrio): void {\n writeManaged({\n VERCEL_TOKEN: creds.token,\n VERCEL_TEAM_ID: creds.teamId,\n VERCEL_PROJECT_ID: creds.projectId,\n });\n}\n\n/**\n * Persist the CLI-login marker + cached stable ids. The access token is\n * deliberately omitted — it's read live from the Vercel CLI store on each call\n * and refreshed there, so the only thing we cache is the team/project scope.\n */\nfunction persistCliCredentials(ids: { teamId: string; projectId: string }): void {\n writeManaged({\n VERCEL_AUTH_SOURCE: 'cli',\n VERCEL_TEAM_ID: ids.teamId,\n VERCEL_PROJECT_ID: ids.projectId,\n });\n}\n\n/**\n * Atomically rewrite the managed Vercel keys in `~/.agentbox/secrets.env`:\n * strip every prior value for a `MANAGED_KEYS` entry, then append exactly the\n * keys in `record` (mode 0600, temp-file + rename). Also mirrors the record\n * into `process.env` (and clears the other managed keys there) so the current\n * run uses the new values immediately.\n */\nfunction writeManaged(record: Record<string, string>): void {\n for (const k of MANAGED_KEYS) delete process.env[k];\n for (const [k, v] of Object.entries(record)) process.env[k] = v;\n\n const path = secretsPath();\n mkdirSync(dirname(path), { recursive: true });\n\n let existing = '';\n if (existsSync(path)) {\n try {\n existing = readFileSync(path, 'utf8');\n } catch {\n existing = '';\n }\n }\n const kept = existing\n .split(/\\r?\\n/)\n .filter((line) => {\n const stripped = line.startsWith('export ') ? line.slice('export '.length) : line;\n const eq = stripped.indexOf('=');\n if (eq <= 0) return true;\n const key = stripped.slice(0, eq).trim();\n return !(MANAGED_KEYS as readonly string[]).includes(key);\n })\n .join('\\n')\n .replace(/\\s+$/u, '');\n\n const lines = Object.entries(record).map(([k, v]) => `${k}=${v}`);\n const body = (kept ? `${kept}\\n` : '') + lines.join('\\n') + '\\n';\n\n const tmp = `${path}.tmp`;\n writeFileSync(tmp, body, { mode: 0o600 });\n try {\n chmodSync(tmp, 0o600);\n } catch {\n // chmod best-effort; writeFileSync mode already covers most filesystems.\n }\n renameSync(tmp, path);\n try {\n chmodSync(path, 0o600);\n } catch {\n // ignore — already attempted above\n }\n}\n\n/**\n * The full CLI-login flow: make sure the Vercel `sandbox` CLI is installed (offer\n * to install it), run its browser OAuth, harvest the team id from the CLI store,\n * let the user pick a project to scope sandboxes to, and persist the marker +\n * ids. The access token is never stored — `resolveCredentials` reads it live.\n */\n/**\n * Make sure the Vercel `sandbox` CLI is on PATH, offering to install it. Every\n * login mode ensures it because interactive attach (`agentbox shell|claude|\n * codex|opencode` on a vercel box) drives `sbx exec` for a real PTY. Returns the\n * resolved bin, or null if absent / declined / install failed (callers warn).\n */\nasync function ensureSbxInstalled(): Promise<{ bin: string } | null> {\n let det = await detectSbx();\n if (!det.installed) {\n const doInstall = await confirm({\n message: `The Vercel sandbox CLI (needed for interactive attach) isn't installed. Install it now? (${installSbxHint()})`,\n initialValue: true,\n });\n if (isCancel(doInstall) || !doInstall) {\n log.warn(\n `Install it with \\`${installSbxHint()}\\` to use \\`agentbox shell|claude|codex|opencode\\` on Vercel boxes.`,\n );\n return null;\n }\n const sp = spinner();\n sp.start('Installing the Vercel sandbox CLI…');\n const ok = await installSbx();\n resetSbxCache();\n det = await detectSbx();\n if (!ok || !det.installed || !det.bin) {\n sp.stop('Install failed.');\n log.warn(`Could not install the sandbox CLI — run \\`${installSbxHint()}\\` manually.`);\n return null;\n }\n sp.stop(`Installed sandbox CLI${det.version ? ` ${det.version}` : ''}.`);\n }\n return det.bin ? { bin: det.bin } : null;\n}\n\nasync function runCliLogin(): Promise<void> {\n const det = await ensureSbxInstalled();\n if (!det) {\n log.warn('The Vercel sandbox CLI is required to sign in this way — install it, then re-run `agentbox vercel login`.');\n return;\n }\n\n note('A browser window will open to sign in to Vercel.', 'Vercel sign-in');\n const status = loginSbx(det.bin);\n if (status !== 0) {\n log.warn('Vercel sign-in did not complete — re-run `agentbox vercel login` to try again.');\n return;\n }\n\n const harvested = harvestCliCredentials();\n if (!harvested) {\n log.warn('Sign-in finished but no credentials were found in the Vercel CLI store. Try again.');\n return;\n }\n\n // Validate the token early so a bad/expired session fails here, not mid-op.\n try {\n await getUser(harvested.token);\n } catch (err) {\n log.warn(\n `The Vercel session looks invalid (${err instanceof Error ? err.message : String(err)}). ` +\n 'Re-run `agentbox vercel login`.',\n );\n return;\n }\n\n const projectId = await resolveProjectId(harvested.token, harvested.teamId);\n if (projectId === null) {\n log.warn('No project selected — re-run `agentbox vercel login` to finish setup.');\n return;\n }\n\n persistCliCredentials({ teamId: harvested.teamId, projectId });\n reloadVercelEnv();\n log.success(`Signed in with Vercel — credentials managed by the sandbox CLI (saved scope to ${secretsPath()}).`);\n outro('Setup complete.');\n}\n\n/**\n * Read the live token + team id from the Vercel CLI store. teamId prefers an\n * already-cached `VERCEL_TEAM_ID` (e.g. from a prior login) and falls back to\n * the CLI's `currentTeam`. Null when the CLI isn't logged in.\n */\nfunction harvestCliCredentials(): { token: string; teamId: string } | null {\n const auth = readCliAuth();\n if (!auth) return null;\n const teamId = process.env.VERCEL_TEAM_ID ?? readCliCurrentTeam();\n if (!teamId) return null;\n return { token: auth.token, teamId };\n}\n\n/**\n * Pick the Vercel project sandboxes run under. Lists the team's projects in a\n * clack select (pre-selecting an existing `agentbox` / sandbox-default project),\n * plus a \"create a new project\" entry. Returns the project id, or null if the\n * user cancelled. Non-interactive callers reuse/create an `agentbox` project.\n */\nasync function resolveProjectId(token: string, teamId: string): Promise<string | null> {\n let projects: VercelProject[] = [];\n const sp = spinner();\n sp.start('Loading your Vercel projects…');\n try {\n projects = await listProjects(token, teamId);\n sp.stop(`Found ${projects.length} project${projects.length === 1 ? '' : 's'}.`);\n } catch (err) {\n sp.stop('Could not list projects.');\n log.warn(`Failed to list Vercel projects: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n\n const CREATE = '__create__';\n const preferred =\n projects.find((p) => p.name === 'agentbox') ??\n projects.find((p) => p.name === 'vercel-sandbox-default-project');\n const choice = await select({\n message: 'Which Vercel project should sandboxes run under?',\n options: [\n ...projects.map((p) => ({ value: p.id, label: p.name })),\n { value: CREATE, label: 'Create a new project…' },\n ],\n initialValue: preferred ? preferred.id : CREATE,\n });\n if (isCancel(choice)) return null;\n\n if (choice !== CREATE) return choice;\n\n const name = await text({\n message: 'New project name',\n placeholder: 'agentbox',\n defaultValue: 'agentbox',\n validate: (v) => (v && v.trim().length > 0 ? undefined : 'Cannot be empty'),\n });\n if (isCancel(name)) return null;\n try {\n const created = await createProject(token, teamId, name.trim() || 'agentbox');\n return created.id;\n } catch (err) {\n log.warn(`Could not create the project: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\nfunction openDashboard(): void {\n // Lazy import keeps node:child_process out of the module's load cost.\n import('node:child_process')\n .then(({ spawnSync }) => {\n const r = spawnSync('open', [DASHBOARD_TOKENS_URL], { stdio: 'ignore' });\n if (r.status !== 0) {\n log.warn(`Could not auto-open the browser — visit ${DASHBOARD_TOKENS_URL} manually.`);\n }\n })\n .catch(() => {\n log.warn(`Could not auto-open the browser — visit ${DASHBOARD_TOKENS_URL} manually.`);\n });\n}\n\nexport function secretsPath(): string {\n return resolve(homedir(), '.agentbox', 'secrets.env');\n}\n\nexport interface VercelCredStatus {\n /** Which auth mode is configured. */\n auth: 'oidc' | 'cli' | 'token' | 'none';\n /** Legacy alias kept for callers that branch on OIDC. */\n oidc: boolean;\n token?: string;\n teamId?: string;\n projectId?: string;\n source: 'env' | 'secrets.env' | 'cli-store' | 'none';\n /**\n * CLI mode only: details about the live Vercel CLI session. Whether the\n * `sandbox` CLI is *installed* needs an async probe (`detectSbx`) and is not\n * reported here — the status printer probes it separately.\n */\n cli?: {\n /** A logged-in session was found in the CLI store. */\n loggedIn: boolean;\n /** Unix seconds the live access token expires at, when known. */\n expiresAt?: number;\n /** True when the token is at/near expiry (a refresh would fire). */\n nearExpiry?: boolean;\n /** Path to the CLI's `auth.json`. */\n authPath: string;\n };\n}\n\nexport function readVercelCredStatus(): VercelCredStatus {\n const shellHad = !!process.env.VERCEL_OIDC_TOKEN || !!process.env.VERCEL_TOKEN;\n ensureVercelEnvLoaded();\n const oidc = !!process.env.VERCEL_OIDC_TOKEN;\n const teamId = process.env.VERCEL_TEAM_ID;\n const projectId = process.env.VERCEL_PROJECT_ID;\n\n if (oidc) {\n return { auth: 'oidc', oidc: true, teamId, projectId, source: shellHad ? 'env' : 'secrets.env' };\n }\n\n if (process.env.VERCEL_AUTH_SOURCE === 'cli') {\n const auth = readCliAuth();\n return {\n auth: 'cli',\n oidc: false,\n token: auth?.token,\n teamId,\n projectId,\n source: 'cli-store',\n cli: {\n loggedIn: !!auth,\n expiresAt: auth?.expiresAt,\n nearExpiry: auth ? isNearExpiry(auth) : undefined,\n authPath: cliStorePaths().authPath,\n },\n };\n }\n\n const token = process.env.VERCEL_TOKEN;\n if (!token) return { auth: 'none', oidc: false, source: 'none' };\n return {\n auth: 'token',\n oidc: false,\n token,\n teamId,\n projectId,\n source: shellHad ? 'env' : 'secrets.env',\n };\n}\n\nexport function maskKey(value: string): string {\n if (value.length <= 8) return '*'.repeat(value.length);\n return `${value.slice(0, 4)}…${'*'.repeat(8)}${value.slice(-4)}`;\n}\n","/**\n * Reader for the Vercel CLI's own credential store — written by `sandbox login`\n * / `vercel login` (the `sandbox`/`sbx` CLI and `vercel` CLI share one store).\n *\n * AgentBox's \"CLI-login\" auth mode (see credentials.ts) drives that CLI for the\n * browser OAuth, then reads the resulting OAuth access token live from here on\n * every SDK call rather than copying it into `secrets.env`: the token is a\n * short-lived, opaque `vca_…` access token that the CLI refreshes lazily from\n * its stored refresh token, so the CLI store is the single self-refreshing\n * source of truth. We only cache the stable bits (team/project id + a marker)\n * in `secrets.env`.\n *\n * Pure FS + path logic — no clack, no execa — so it stays trivially testable.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/** The shape of the CLI's `auth.json` (only the fields we consume). */\nexport interface VercelCliAuth {\n /** Opaque OAuth access token (`vca_…`). NOT a JWT — expiry is `expiresAt`. */\n token: string;\n /** Unix seconds. Absent on some CLI versions → treated as near-expiry. */\n expiresAt?: number;\n /** Present but unused by us; the CLI uses it to self-refresh `token`. */\n refreshToken?: string;\n}\n\n/**\n * Resolve the `com.vercel.cli` data directory the way the CLI itself does\n * (xdg-app-paths-style), per platform:\n * - macOS: ~/Library/Application Support/com.vercel.cli\n * - Windows: %APPDATA%\\com.vercel.cli\n * - else: $XDG_DATA_HOME/com.vercel.cli (default ~/.local/share/...)\n *\n * `AGENTBOX_VERCEL_CLI_DIR` overrides outright — for tests and the rare install\n * that relocates the store.\n */\nexport function vercelCliDir(): string {\n const override = process.env.AGENTBOX_VERCEL_CLI_DIR;\n if (override && override.trim().length > 0) return override.trim();\n\n const name = 'com.vercel.cli';\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', name);\n }\n if (process.platform === 'win32') {\n const appData = process.env.APPDATA;\n if (appData && appData.trim().length > 0) return join(appData, name);\n return join(homedir(), 'AppData', 'Roaming', name);\n }\n const xdg = process.env.XDG_DATA_HOME;\n const base = xdg && xdg.trim().length > 0 ? xdg.trim() : join(homedir(), '.local', 'share');\n return join(base, name);\n}\n\n/** Absolute paths to the CLI store files, for status/diagnostics. */\nexport function cliStorePaths(): { authPath: string; configPath: string } {\n const dir = vercelCliDir();\n return { authPath: join(dir, 'auth.json'), configPath: join(dir, 'config.json') };\n}\n\nfunction readJson(path: string): unknown {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Read the live access token from the CLI store. Returns null when the store is\n * missing / unparseable / has no token (CLI never logged in, or logged out) so\n * callers can surface a clear \"run `agentbox vercel login`\" error.\n */\nexport function readCliAuth(): VercelCliAuth | null {\n const raw = readJson(cliStorePaths().authPath) as Record<string, unknown> | null;\n if (!raw || typeof raw.token !== 'string' || raw.token.length === 0) return null;\n return {\n token: raw.token,\n expiresAt: typeof raw.expiresAt === 'number' ? raw.expiresAt : undefined,\n refreshToken: typeof raw.refreshToken === 'string' ? raw.refreshToken : undefined,\n };\n}\n\n/** Read the CLI's currently-selected team (`config.json` `currentTeam`). */\nexport function readCliCurrentTeam(): string | null {\n const raw = readJson(cliStorePaths().configPath) as Record<string, unknown> | null;\n return raw && typeof raw.currentTeam === 'string' && raw.currentTeam.length > 0\n ? raw.currentTeam\n : null;\n}\n\n/**\n * Whether the access token is at/near expiry and should be refreshed before\n * use. A missing `expiresAt` is treated as near-expiry so we always probe a\n * refresh rather than ship a token of unknown age. `skewSec` is the safety\n * window: refresh if the token expires within that many seconds.\n */\nexport function isNearExpiry(auth: VercelCliAuth, skewSec = 120): boolean {\n if (auth.expiresAt === undefined) return true;\n return auth.expiresAt * 1000 < Date.now() + skewSec * 1000;\n}\n","/**\n * Thin loader around `@vercel/sandbox`. Resolves the auth credentials once and\n * threads them into every SDK call.\n *\n * Three auth modes (in precedence order):\n * - OIDC: `VERCEL_OIDC_TOKEN` in env → decode the JWT for owner/project and\n * pass `{ token, teamId, projectId }` explicitly.\n * - CLI-login: `VERCEL_AUTH_SOURCE=cli` → read the live OAuth access token\n * from the Vercel CLI's own store (`auth.json`) and the cached team/project\n * ids from `secrets.env`. The token is never copied to `secrets.env`; the\n * CLI store is the self-refreshing source of truth. `ensureFreshCredentials`\n * refreshes it (via the `sbx` CLI) before use when it's near expiry.\n * - Access token: `VERCEL_TOKEN` + `VERCEL_TEAM_ID` + `VERCEL_PROJECT_ID` →\n * passed explicitly as `{ token, teamId, projectId }` on each call, since\n * the SDK does NOT read those from env automatically.\n */\n\nimport { ensureVercelEnvLoaded } from './env-loader.js';\nimport { isNearExpiry, readCliAuth, readCliCurrentTeam } from './cli-store.js';\nimport { detectSbx, refreshSbxToken } from './sbx-cli.js';\n\nexport interface VercelCredentials {\n token: string;\n teamId: string;\n projectId: string;\n}\n\n/**\n * Resolve the credentials to thread into SDK calls. Throws when nothing is\n * configured (or an OIDC token has expired) so callers get a clear, actionable\n * error instead of an opaque SDK auth failure.\n *\n * For OIDC we do NOT return `{}` and let the SDK read the env var: the SDK's\n * env-OIDC path (`@vercel/oidc`) tries to *refresh* the token via the Vercel\n * CLI's `.vercel/project.json` + cached auth, which an agentbox box doesn't\n * have, so it fails with \"Could not get credentials from OIDC context\". Instead\n * we decode the OIDC JWT — which embeds `owner_id` (teamId) and `project_id` —\n * and pass `{ token, teamId, projectId }` explicitly, which uses the SDK's\n * direct-credentials path (the OIDC token is itself a valid API bearer).\n */\nexport function resolveCredentials(): VercelCredentials {\n ensureVercelEnvLoaded();\n const oidc = process.env.VERCEL_OIDC_TOKEN;\n if (oidc) {\n const claims = decodeOidcClaims(oidc);\n if (!claims) {\n throw new Error(\n 'VERCEL_OIDC_TOKEN is set but could not be decoded (not a valid Vercel OIDC JWT). ' +\n 'Re-run `vercel env pull`, or use the VERCEL_TOKEN + VERCEL_TEAM_ID + VERCEL_PROJECT_ID trio.',\n );\n }\n if (claims.exp !== undefined && claims.exp * 1000 < Date.now()) {\n throw new Error(\n 'VERCEL_OIDC_TOKEN has expired (Vercel dev OIDC tokens last ~12h). ' +\n 'Re-run `vercel env pull` to refresh it, then retry.',\n );\n }\n return { token: oidc, teamId: claims.teamId, projectId: claims.projectId };\n }\n if (process.env.VERCEL_AUTH_SOURCE === 'cli') {\n const auth = readCliAuth();\n if (!auth) {\n throw new Error(\n 'Vercel CLI session not found — run `agentbox vercel login` (or `sbx login`) to sign in again.',\n );\n }\n const teamId = process.env.VERCEL_TEAM_ID ?? readCliCurrentTeam() ?? undefined;\n const projectId = process.env.VERCEL_PROJECT_ID;\n if (!teamId || !projectId) {\n throw new Error(\n 'Vercel CLI auth is missing the team/project id — re-run `agentbox vercel login`.',\n );\n }\n // Live token straight from the CLI store; nothing cached on disk.\n return { token: auth.token, teamId, projectId };\n }\n const token = process.env.VERCEL_TOKEN;\n const teamId = process.env.VERCEL_TEAM_ID;\n const projectId = process.env.VERCEL_PROJECT_ID;\n if (token && teamId && projectId) return { token, teamId, projectId };\n throw new Error(\n 'Vercel credentials not configured.\\n' +\n 'Either run `vercel link && vercel env pull` to get a VERCEL_OIDC_TOKEN, ' +\n 'or set VERCEL_TOKEN + VERCEL_TEAM_ID + VERCEL_PROJECT_ID ' +\n '(see `agentbox vercel login`).',\n );\n}\n\ninterface OidcClaims {\n teamId: string;\n projectId: string;\n exp?: number;\n}\n\n/** Decode the `owner_id`/`project_id`/`exp` claims from a Vercel OIDC JWT. */\nfunction decodeOidcClaims(token: string): OidcClaims | null {\n const parts = token.split('.');\n if (parts.length < 2 || !parts[1]) return null;\n try {\n const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8')) as {\n owner_id?: unknown;\n project_id?: unknown;\n exp?: unknown;\n };\n if (typeof payload.owner_id !== 'string' || typeof payload.project_id !== 'string') return null;\n return {\n teamId: payload.owner_id,\n projectId: payload.project_id,\n exp: typeof payload.exp === 'number' ? payload.exp : undefined,\n };\n } catch {\n return null;\n }\n}\n\n/** True when any auth mode is configured. Used by the credential gate. */\nexport function hasUsableCredentials(): boolean {\n ensureVercelEnvLoaded();\n if (process.env.VERCEL_OIDC_TOKEN) return true;\n if (\n process.env.VERCEL_AUTH_SOURCE === 'cli' &&\n process.env.VERCEL_TEAM_ID &&\n process.env.VERCEL_PROJECT_ID &&\n readCliAuth()\n ) {\n return true;\n }\n return Boolean(\n process.env.VERCEL_TOKEN && process.env.VERCEL_TEAM_ID && process.env.VERCEL_PROJECT_ID,\n );\n}\n\n/**\n * Refresh the CLI-login access token before use when it's near expiry. No-op\n * for the OIDC and access-token modes (nothing to refresh). For CLI mode: if the\n * live token in the CLI store is within the safety window, run a cheap `sbx`\n * read command, which makes the CLI rotate its own token from the stored refresh\n * token, then re-read `secrets.env`. Throws an actionable error when the CLI is\n * gone or the refresh fails (e.g. the refresh token itself expired).\n *\n * Call this once at the top of each backend operation, BEFORE the (sync)\n * `resolveCredentials()` reads the token. An in-process single-flight collapses\n * concurrent ops onto one refresh; cross-process races are harmless (the CLI\n * writes its store atomically and a fresh-token refresh is a no-op).\n */\nlet inflightRefresh: Promise<void> | null = null;\n\nexport function ensureFreshCredentials(): Promise<void> {\n ensureVercelEnvLoaded();\n if (process.env.VERCEL_AUTH_SOURCE !== 'cli') return Promise.resolve();\n if (inflightRefresh) return inflightRefresh;\n inflightRefresh = refreshCliToken().finally(() => {\n inflightRefresh = null;\n });\n return inflightRefresh;\n}\n\nasync function refreshCliToken(): Promise<void> {\n const auth = readCliAuth();\n if (!auth) return; // resolveCredentials() will throw the clear \"logged out\" error\n if (!isNearExpiry(auth)) return; // still valid — no work\n\n const det = await detectSbx();\n if (!det.installed || !det.bin) {\n throw new Error(\n 'Vercel access token is near expiry and the `sandbox` CLI is no longer installed — ' +\n 'reinstall it (`npm install -g sandbox`) or run `agentbox vercel login`.',\n );\n }\n const ok = await refreshSbxToken(det.bin);\n if (!ok) {\n throw new Error(\n 'Vercel token refresh failed — run `agentbox vercel login` (the refresh token may have expired).',\n );\n }\n // The token lives in the CLI store, not secrets.env — refreshSbxToken rotated\n // auth.json in place, so the next readCliAuth() returns the fresh token.\n const fresh = readCliAuth();\n if (!fresh || isNearExpiry(fresh, 0)) {\n throw new Error(\n 'Vercel token is still stale after a refresh attempt — run `agentbox vercel login`.',\n );\n }\n}\n\n// Re-export the SDK surface we use so the rest of the package imports from one\n// place (and tests can mock `./sdk.js` instead of the package).\nexport { Sandbox, Snapshot } from '@vercel/sandbox';\nexport type { Sandbox as SandboxType } from '@vercel/sandbox';\n","/**\n * Minimal Vercel REST helpers used by the CLI-login auth flow. The Sandbox SDK\n * requires a projectId on every call, but the OAuth access token harvested from\n * the CLI is team-scoped with no project — so after login we list the team's\n * projects (and optionally create one) to resolve a project to scope sandboxes\n * to. Plain `fetch`; no SDK. Each call takes the harvested `(token, teamId)`.\n */\n\nconst API = 'https://api.vercel.com';\n\nexport interface VercelProject {\n id: string;\n name: string;\n}\n\nclass VercelApiError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = 'VercelApiError';\n }\n}\n\nasync function api(\n token: string,\n path: string,\n init?: { method?: string; body?: unknown },\n): Promise<unknown> {\n const res = await fetch(`${API}${path}`, {\n method: init?.method ?? 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n ...(init?.body ? { 'Content-Type': 'application/json' } : {}),\n },\n body: init?.body ? JSON.stringify(init.body) : undefined,\n });\n const text = await res.text();\n let json: unknown = null;\n try {\n json = text ? JSON.parse(text) : null;\n } catch {\n json = null;\n }\n if (!res.ok) {\n const detail =\n (json as { error?: { message?: string } } | null)?.error?.message ??\n text ??\n res.statusText;\n throw new VercelApiError(res.status, `Vercel API ${res.status}: ${detail}`);\n }\n return json;\n}\n\n/** Validate the token and return the authenticated user (probe / status). */\nexport async function getUser(token: string): Promise<{ id: string; username?: string }> {\n const json = (await api(token, '/v2/user')) as {\n user?: { id: string; username?: string };\n };\n const user = json.user;\n if (!user?.id) throw new Error('Vercel /v2/user returned no user');\n return user;\n}\n\n/** List the team's projects (id + name). Paginates up to `limit` (default 100). */\nexport async function listProjects(\n token: string,\n teamId: string,\n limit = 100,\n): Promise<VercelProject[]> {\n const json = (await api(\n token,\n `/v9/projects?teamId=${encodeURIComponent(teamId)}&limit=${limit}`,\n )) as { projects?: Array<{ id: string; name: string }> };\n return (json.projects ?? []).map((p) => ({ id: p.id, name: p.name }));\n}\n\n/**\n * Create a project under the team. On a 409 (name already taken) re-list and\n * return the existing project of that name, so the caller treats create as\n * idempotent.\n */\nexport async function createProject(\n token: string,\n teamId: string,\n name: string,\n): Promise<VercelProject> {\n try {\n const json = (await api(token, `/v9/projects?teamId=${encodeURIComponent(teamId)}`, {\n method: 'POST',\n body: { name },\n })) as { id: string; name: string };\n return { id: json.id, name: json.name };\n } catch (err) {\n if (err instanceof VercelApiError && err.status === 409) {\n const existing = (await listProjects(token, teamId)).find((p) => p.name === name);\n if (existing) return existing;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","resolve","teamId","projectId","text","spawnSync"]}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
recordBox,
|
|
20
20
|
removeBoxRecord,
|
|
21
21
|
writePreparedDockerState
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-KL36BRN4.js";
|
|
23
23
|
|
|
24
24
|
// ../../packages/sandbox-docker/dist/index.js
|
|
25
25
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
@@ -736,6 +736,7 @@ var BUILT_IN_DEFAULTS = {
|
|
|
736
736
|
defaultCheckpointDocker: "",
|
|
737
737
|
defaultCheckpointDaytona: "",
|
|
738
738
|
defaultCheckpointHetzner: "",
|
|
739
|
+
defaultCheckpointVercel: "",
|
|
739
740
|
withPlaywright: false,
|
|
740
741
|
withEnv: false,
|
|
741
742
|
vnc: true,
|
|
@@ -748,7 +749,10 @@ var BUILT_IN_DEFAULTS = {
|
|
|
748
749
|
cpus: 0,
|
|
749
750
|
pidsLimit: 0,
|
|
750
751
|
disk: "",
|
|
751
|
-
bundleDepth: void 0
|
|
752
|
+
bundleDepth: void 0,
|
|
753
|
+
vercelVcpus: 2,
|
|
754
|
+
vercelTimeoutMs: 27e5,
|
|
755
|
+
vercelNetworkPolicy: ""
|
|
752
756
|
},
|
|
753
757
|
checkpoint: {
|
|
754
758
|
maxLayers: 3
|
|
@@ -799,7 +803,12 @@ var BUILT_IN_DEFAULTS = {
|
|
|
799
803
|
},
|
|
800
804
|
queue: {
|
|
801
805
|
enabled: true,
|
|
802
|
-
maxConcurrent: 5
|
|
806
|
+
maxConcurrent: 5,
|
|
807
|
+
maxWorking: 0,
|
|
808
|
+
idleGraceSeconds: 15
|
|
809
|
+
},
|
|
810
|
+
cloud: {
|
|
811
|
+
useCurrentBranch: false
|
|
803
812
|
},
|
|
804
813
|
maintenance: {
|
|
805
814
|
pruneProjectConfigs: true,
|
|
@@ -810,8 +819,8 @@ var KEY_REGISTRY = [
|
|
|
810
819
|
{
|
|
811
820
|
key: "box.provider",
|
|
812
821
|
type: "enum",
|
|
813
|
-
enumValues: ["docker", "daytona", "hetzner"],
|
|
814
|
-
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes,
|
|
822
|
+
enumValues: ["docker", "daytona", "hetzner", "vercel"],
|
|
823
|
+
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes, Hetzner Cloud VPSes, or Vercel Sandboxes."
|
|
815
824
|
},
|
|
816
825
|
{
|
|
817
826
|
key: "box.hostSnapshot",
|
|
@@ -841,6 +850,12 @@ var KEY_REGISTRY = [
|
|
|
841
850
|
description: "Per-provider override of `box.defaultCheckpoint` for hetzner. Wins over the global when set; set via `agentbox checkpoint set-default --provider hetzner`.",
|
|
842
851
|
advanced: true
|
|
843
852
|
},
|
|
853
|
+
{
|
|
854
|
+
key: "box.defaultCheckpointVercel",
|
|
855
|
+
type: "string",
|
|
856
|
+
description: "Per-provider override of `box.defaultCheckpoint` for vercel. Wins over the global when set; set via `agentbox checkpoint set-default --provider vercel`.",
|
|
857
|
+
advanced: true
|
|
858
|
+
},
|
|
844
859
|
{
|
|
845
860
|
key: "checkpoint.maxLayers",
|
|
846
861
|
type: "int",
|
|
@@ -914,6 +929,21 @@ var KEY_REGISTRY = [
|
|
|
914
929
|
type: "int",
|
|
915
930
|
description: "Cap git bundle history shipped to cloud sandboxes (daytona, hetzner). 0 = full history. Unset = adaptive default (last 200 commits; re-bundle at 100 if the bundle exceeds 20 MB). Ignored for docker (which bind-mounts .git/)."
|
|
916
931
|
},
|
|
932
|
+
{
|
|
933
|
+
key: "box.vercelVcpus",
|
|
934
|
+
type: "int",
|
|
935
|
+
description: "vCPUs for new --provider vercel boxes (Vercel couples RAM at 2048 MB/vCPU). Default 2. Vercel only accepts specific counts (e.g. 1, 2, 4, 8) \u2014 an unsupported value fails create with a 400. Vercel-only; ignored by other providers."
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
key: "box.vercelTimeoutMs",
|
|
939
|
+
type: "int",
|
|
940
|
+
description: "Max session length (ms) for new --provider vercel boxes before the VM auto-snapshots; persistent mode auto-resumes on the next call. Default 2700000 (45 min, the Hobby ceiling). Vercel-only."
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
key: "box.vercelNetworkPolicy",
|
|
944
|
+
type: "string",
|
|
945
|
+
description: "Egress lock for new --provider vercel boxes: 'allow-all' (default, unset), 'deny-all', or a comma-separated domain allowlist (e.g. 'github.com,*.npmjs.org') that denies everything else. Vercel-only; ignored by other providers."
|
|
946
|
+
},
|
|
917
947
|
{
|
|
918
948
|
key: "claude.sessionName",
|
|
919
949
|
type: "string",
|
|
@@ -1031,6 +1061,21 @@ var KEY_REGISTRY = [
|
|
|
1031
1061
|
type: "int",
|
|
1032
1062
|
description: "Max number of simultaneously-running boxes (across providers) before background `-i` jobs queue up instead of starting immediately. Per-invocation override: `--max-running <n>`."
|
|
1033
1063
|
},
|
|
1064
|
+
{
|
|
1065
|
+
key: "queue.maxWorking",
|
|
1066
|
+
type: "int",
|
|
1067
|
+
description: "Max agents actively working/thinking (quota-consuming) at once before background `-i` jobs queue. 0 = disabled (use the queue.maxConcurrent running-box gate). Counts all boxes, foreground + queued. Per-invocation override: `--max-working <n>`."
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
key: "queue.idleGraceSeconds",
|
|
1071
|
+
type: "int",
|
|
1072
|
+
description: "Seconds an agent must stay non-working before it frees its working slot (debounce against brief idle flaps between turns). Only used when queue.maxWorking > 0."
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
key: "cloud.useCurrentBranch",
|
|
1076
|
+
type: "bool",
|
|
1077
|
+
description: "On cloud providers (daytona/hetzner), start new boxes on the host's current branch instead of forking a new agentbox/<box-name> branch. Overridden by an explicit --use-branch / --from-branch."
|
|
1078
|
+
},
|
|
1034
1079
|
{
|
|
1035
1080
|
key: "maintenance.pruneProjectConfigs",
|
|
1036
1081
|
type: "bool",
|
|
@@ -1386,7 +1431,7 @@ function writeLeaf(obj, branch, leaf, value) {
|
|
|
1386
1431
|
b[leaf] = value;
|
|
1387
1432
|
}
|
|
1388
1433
|
function resolveDefaultCheckpoint(cfg, provider) {
|
|
1389
|
-
const perProvider = provider === "daytona" ? cfg.box.defaultCheckpointDaytona : provider === "hetzner" ? cfg.box.defaultCheckpointHetzner : cfg.box.defaultCheckpointDocker;
|
|
1434
|
+
const perProvider = provider === "daytona" ? cfg.box.defaultCheckpointDaytona : provider === "hetzner" ? cfg.box.defaultCheckpointHetzner : provider === "vercel" ? cfg.box.defaultCheckpointVercel : cfg.box.defaultCheckpointDocker;
|
|
1390
1435
|
if (perProvider && perProvider.length > 0) return perProvider;
|
|
1391
1436
|
return cfg.box.defaultCheckpoint;
|
|
1392
1437
|
}
|
|
@@ -1394,6 +1439,7 @@ function defaultCheckpointConfigKey(provider) {
|
|
|
1394
1439
|
if (provider === "docker") return "box.defaultCheckpointDocker";
|
|
1395
1440
|
if (provider === "daytona") return "box.defaultCheckpointDaytona";
|
|
1396
1441
|
if (provider === "hetzner") return "box.defaultCheckpointHetzner";
|
|
1442
|
+
if (provider === "vercel") return "box.defaultCheckpointVercel";
|
|
1397
1443
|
return "box.defaultCheckpoint";
|
|
1398
1444
|
}
|
|
1399
1445
|
async function setConfigValue(scope, key, value, cwd, opts = {}) {
|
|
@@ -1676,6 +1722,15 @@ var GH_PR_OPS = [
|
|
|
1676
1722
|
"close",
|
|
1677
1723
|
"reopen"
|
|
1678
1724
|
];
|
|
1725
|
+
function injectPrCreateHead(op, branch, args) {
|
|
1726
|
+
if (op !== "create") return args;
|
|
1727
|
+
if (!branch || branch === "HEAD") return args;
|
|
1728
|
+
if (hasHeadArg(args)) return args;
|
|
1729
|
+
return ["--head", branch, ...args];
|
|
1730
|
+
}
|
|
1731
|
+
function hasHeadArg(args) {
|
|
1732
|
+
return args.some((a) => a === "--head" || a.startsWith("--head=") || a.startsWith("-H"));
|
|
1733
|
+
}
|
|
1679
1734
|
var MAX_BODY_BYTES = 1024 * 1024;
|
|
1680
1735
|
var QUEUE_DIR = join3(STATE_DIR, "queue");
|
|
1681
1736
|
async function loadQueueConfig() {
|
|
@@ -1688,7 +1743,9 @@ async function loadQueueConfig() {
|
|
|
1688
1743
|
const q = global.queue ?? {};
|
|
1689
1744
|
return {
|
|
1690
1745
|
enabled: q.enabled ?? d.enabled,
|
|
1691
|
-
maxConcurrent: q.maxConcurrent ?? d.maxConcurrent
|
|
1746
|
+
maxConcurrent: q.maxConcurrent ?? d.maxConcurrent,
|
|
1747
|
+
maxWorking: q.maxWorking ?? d.maxWorking,
|
|
1748
|
+
idleGraceMs: (q.idleGraceSeconds ?? d.idleGraceSeconds) * 1e3
|
|
1692
1749
|
};
|
|
1693
1750
|
}
|
|
1694
1751
|
async function writeJob(job) {
|
|
@@ -3671,6 +3728,22 @@ async function pullClaudeExtras(spec, opts) {
|
|
|
3671
3728
|
return { newItems, mergedRegistries };
|
|
3672
3729
|
}
|
|
3673
3730
|
var CREDENTIALS_BACKUP_FILE = join32(STATE_DIR, "claude-credentials.json");
|
|
3731
|
+
var CODEX_CREDENTIALS_BACKUP_FILE = join32(STATE_DIR, "codex-credentials.json");
|
|
3732
|
+
var OPENCODE_CREDENTIALS_BACKUP_FILE = join32(STATE_DIR, "opencode-credentials.json");
|
|
3733
|
+
function isRealAgentCredential(agent, text) {
|
|
3734
|
+
let parsed;
|
|
3735
|
+
try {
|
|
3736
|
+
parsed = JSON.parse(text);
|
|
3737
|
+
} catch {
|
|
3738
|
+
return false;
|
|
3739
|
+
}
|
|
3740
|
+
if (typeof parsed !== "object" || parsed === null) return false;
|
|
3741
|
+
if (agent === "claude") {
|
|
3742
|
+
const rt = parsed.claudeAiOauth?.refreshToken;
|
|
3743
|
+
return typeof rt === "string" && rt.length > 0;
|
|
3744
|
+
}
|
|
3745
|
+
return Object.keys(parsed).length > 0;
|
|
3746
|
+
}
|
|
3674
3747
|
async function hostBackupHasCredentials(path = CREDENTIALS_BACKUP_FILE) {
|
|
3675
3748
|
try {
|
|
3676
3749
|
const parsed = JSON.parse(await readFile32(path, "utf8"));
|
|
@@ -4571,23 +4644,10 @@ async function seedWorkspace(opts) {
|
|
|
4571
4644
|
const main = r.repo.hostMainRepo;
|
|
4572
4645
|
const wt = r.gitWorktreePath;
|
|
4573
4646
|
const baseRef = r.repo.kind === "root" ? opts.fromBranch ?? "HEAD" : "HEAD";
|
|
4647
|
+
const addArgs = r.reuseBranch ? ["worktree", "add", wt, r.branch] : ["worktree", "add", "-b", r.branch, wt, baseRef];
|
|
4574
4648
|
const add = await execa7(
|
|
4575
4649
|
"docker",
|
|
4576
|
-
[
|
|
4577
|
-
"exec",
|
|
4578
|
-
"--user",
|
|
4579
|
-
"vscode",
|
|
4580
|
-
opts.container,
|
|
4581
|
-
"git",
|
|
4582
|
-
"-C",
|
|
4583
|
-
main,
|
|
4584
|
-
"worktree",
|
|
4585
|
-
"add",
|
|
4586
|
-
"-b",
|
|
4587
|
-
r.branch,
|
|
4588
|
-
wt,
|
|
4589
|
-
baseRef
|
|
4590
|
-
],
|
|
4650
|
+
["exec", "--user", "vscode", opts.container, "git", "-C", main, ...addArgs],
|
|
4591
4651
|
{ reject: false }
|
|
4592
4652
|
);
|
|
4593
4653
|
if (add.exitCode !== 0) {
|
|
@@ -5306,25 +5366,72 @@ async function ensureRelay(opts = {}) {
|
|
|
5306
5366
|
await removeContainer(RELAY_CONTAINER_NAME);
|
|
5307
5367
|
log(`removed legacy relay container ${RELAY_CONTAINER_NAME}`);
|
|
5308
5368
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5369
|
+
const health = await fetchHealthz(500);
|
|
5370
|
+
if (health !== null) {
|
|
5371
|
+
if (health.cliEntry !== false) {
|
|
5372
|
+
return ENDPOINT;
|
|
5373
|
+
}
|
|
5374
|
+
log("relay is alive but lacks AGENTBOX_CLI_ENTRY (cp/download/checkpoint would fail) \u2014 reclaiming");
|
|
5375
|
+
await reclaimRelay(health.pid, log);
|
|
5376
|
+
} else {
|
|
5377
|
+
const existingPid = await readPidFile();
|
|
5378
|
+
if (existingPid !== null && await processAlive(existingPid)) {
|
|
5379
|
+
for (let i = 0; i < 10; i++) {
|
|
5380
|
+
if (await pingHealthz(300)) return ENDPOINT;
|
|
5381
|
+
await delay2(200);
|
|
5382
|
+
}
|
|
5383
|
+
log(`relay pid ${String(existingPid)} alive but /healthz unresponsive \u2014 proceeding anyway`);
|
|
5384
|
+
return ENDPOINT;
|
|
5385
|
+
}
|
|
5386
|
+
if (existingPid !== null) {
|
|
5387
|
+
await unlink2(PID_FILE).catch(() => {
|
|
5388
|
+
});
|
|
5317
5389
|
}
|
|
5318
|
-
log(`relay pid ${String(existingPid)} alive but /healthz unresponsive \u2014 proceeding anyway`);
|
|
5319
|
-
return ENDPOINT;
|
|
5320
|
-
}
|
|
5321
|
-
if (existingPid !== null) {
|
|
5322
|
-
await unlink2(PID_FILE).catch(() => {
|
|
5323
|
-
});
|
|
5324
5390
|
}
|
|
5325
5391
|
const relayBin = resolveRelayBin();
|
|
5326
|
-
const logFd = openSync(LOG_FILE, "a");
|
|
5327
5392
|
const cliEntry = resolveCliEntry();
|
|
5393
|
+
if (cliEntry === null) {
|
|
5394
|
+
throw new Error(
|
|
5395
|
+
"cannot start the host relay: agentbox CLI entry not found (is the build complete / dist present?). Set AGENTBOX_CLI_ENTRY to override."
|
|
5396
|
+
);
|
|
5397
|
+
}
|
|
5398
|
+
return spawnRelay(relayBin, cliEntry, log);
|
|
5399
|
+
}
|
|
5400
|
+
async function reclaimRelay(reportedPid, log) {
|
|
5401
|
+
const pidFromFile = await readPidFile();
|
|
5402
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5403
|
+
for (const pid of [reportedPid, pidFromFile]) {
|
|
5404
|
+
if (typeof pid !== "number" || pid <= 0 || seen.has(pid)) continue;
|
|
5405
|
+
seen.add(pid);
|
|
5406
|
+
if (!await processAlive(pid)) continue;
|
|
5407
|
+
log(`stopping crippled relay pid ${String(pid)}`);
|
|
5408
|
+
await killPid(pid);
|
|
5409
|
+
}
|
|
5410
|
+
await unlink2(PID_FILE).catch(() => {
|
|
5411
|
+
});
|
|
5412
|
+
if (await pingHealthz(300)) {
|
|
5413
|
+
throw new Error(
|
|
5414
|
+
`a relay without AGENTBOX_CLI_ENTRY is still listening on :${String(PORT)} and could not be stopped (reported pid ${String(reportedPid ?? "unknown")}); kill it manually and retry`
|
|
5415
|
+
);
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
async function killPid(pid) {
|
|
5419
|
+
try {
|
|
5420
|
+
process.kill(pid, "SIGTERM");
|
|
5421
|
+
} catch {
|
|
5422
|
+
return;
|
|
5423
|
+
}
|
|
5424
|
+
for (let i = 0; i < 20; i++) {
|
|
5425
|
+
if (!await processAlive(pid)) return;
|
|
5426
|
+
await delay2(100);
|
|
5427
|
+
}
|
|
5428
|
+
try {
|
|
5429
|
+
process.kill(pid, "SIGKILL");
|
|
5430
|
+
} catch {
|
|
5431
|
+
}
|
|
5432
|
+
}
|
|
5433
|
+
async function spawnRelay(relayBin, cliEntry, log) {
|
|
5434
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
5328
5435
|
const child = spawn(
|
|
5329
5436
|
process.execPath,
|
|
5330
5437
|
[relayBin, "serve", "--port", String(PORT), "--host", "0.0.0.0"],
|
|
@@ -5333,7 +5440,7 @@ async function ensureRelay(opts = {}) {
|
|
|
5333
5440
|
stdio: ["ignore", logFd, logFd],
|
|
5334
5441
|
env: {
|
|
5335
5442
|
...process.env,
|
|
5336
|
-
|
|
5443
|
+
AGENTBOX_CLI_ENTRY: cliEntry
|
|
5337
5444
|
}
|
|
5338
5445
|
}
|
|
5339
5446
|
);
|
|
@@ -5465,7 +5572,13 @@ function fetchHealthz(timeoutMs) {
|
|
|
5465
5572
|
try {
|
|
5466
5573
|
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
5467
5574
|
if (typeof parsed.ok === "boolean" && typeof parsed.boxes === "number" && typeof parsed.events === "number") {
|
|
5468
|
-
resolveP({
|
|
5575
|
+
resolveP({
|
|
5576
|
+
ok: parsed.ok,
|
|
5577
|
+
boxes: parsed.boxes,
|
|
5578
|
+
events: parsed.events,
|
|
5579
|
+
pid: typeof parsed.pid === "number" ? parsed.pid : void 0,
|
|
5580
|
+
cliEntry: typeof parsed.cliEntry === "boolean" ? parsed.cliEntry : void 0
|
|
5581
|
+
});
|
|
5469
5582
|
} else {
|
|
5470
5583
|
resolveP(null);
|
|
5471
5584
|
}
|
|
@@ -5944,9 +6057,33 @@ async function createBox(opts) {
|
|
|
5944
6057
|
);
|
|
5945
6058
|
}
|
|
5946
6059
|
for (const r of repos) {
|
|
6060
|
+
const containerPath = r.kind === "root" ? "/workspace" : `/workspace/${r.relPathFromWorkspace}`;
|
|
6061
|
+
const reuseBranch = r.kind === "root" && opts.useBranch !== void 0;
|
|
6062
|
+
if (reuseBranch) {
|
|
6063
|
+
const branch2 = opts.useBranch;
|
|
6064
|
+
const gitWorktreePath2 = gitWorktreePathFor(branch2);
|
|
6065
|
+
repoCarryOvers.push({
|
|
6066
|
+
repo: r,
|
|
6067
|
+
containerPath,
|
|
6068
|
+
gitWorktreePath: gitWorktreePath2,
|
|
6069
|
+
branch: branch2,
|
|
6070
|
+
stashSha: null,
|
|
6071
|
+
untrackedNul: "",
|
|
6072
|
+
hostSource: r.hostMainRepo,
|
|
6073
|
+
reuseBranch: true
|
|
6074
|
+
});
|
|
6075
|
+
gitWorktreeRecords.push({
|
|
6076
|
+
kind: r.kind,
|
|
6077
|
+
hostMainRepo: r.hostMainRepo,
|
|
6078
|
+
containerPath,
|
|
6079
|
+
gitWorktreePath: gitWorktreePath2,
|
|
6080
|
+
branch: branch2,
|
|
6081
|
+
relPathFromWorkspace: r.relPathFromWorkspace
|
|
6082
|
+
});
|
|
6083
|
+
continue;
|
|
6084
|
+
}
|
|
5947
6085
|
const branchBase = r.kind === "root" ? `agentbox/${name}` : `agentbox/${name}--${r.relPathFromWorkspace.replace(/[^A-Za-z0-9._-]+/g, "_")}`;
|
|
5948
6086
|
const branch = await pickFreshBranch(r.hostMainRepo, branchBase);
|
|
5949
|
-
const containerPath = r.kind === "root" ? "/workspace" : `/workspace/${r.relPathFromWorkspace}`;
|
|
5950
6087
|
const gitWorktreePath = gitWorktreePathFor(branch);
|
|
5951
6088
|
const carry = await collectRepoCarryOver(r, branch, containerPath, gitWorktreePath);
|
|
5952
6089
|
repoCarryOvers.push(carry);
|
|
@@ -6191,9 +6328,18 @@ async function createBox(opts) {
|
|
|
6191
6328
|
});
|
|
6192
6329
|
log("seeded /workspace from in-container git worktree(s)");
|
|
6193
6330
|
} catch (err) {
|
|
6194
|
-
|
|
6195
|
-
`seedWorkspace failed
|
|
6196
|
-
|
|
6331
|
+
if (opts.useBranch !== void 0) {
|
|
6332
|
+
log(`seedWorkspace failed for --use-branch ${opts.useBranch}; cleaning up the box`);
|
|
6333
|
+
await execa13("docker", ["rm", "-f", containerName], { reject: false });
|
|
6334
|
+
for (const w of gitWorktreeRecords) {
|
|
6335
|
+
await removeInBoxWorktree({
|
|
6336
|
+
hostMainRepo: w.hostMainRepo,
|
|
6337
|
+
gitWorktreePath: w.gitWorktreePath
|
|
6338
|
+
});
|
|
6339
|
+
}
|
|
6340
|
+
} else {
|
|
6341
|
+
log(`seedWorkspace failed; leaving ${containerName} running so you can inspect it`);
|
|
6342
|
+
}
|
|
6197
6343
|
throw err;
|
|
6198
6344
|
}
|
|
6199
6345
|
} else {
|
|
@@ -7427,6 +7573,7 @@ var dockerProvider = {
|
|
|
7427
7573
|
useSnapshot: po.useSnapshot ?? false,
|
|
7428
7574
|
checkpointRef: req.checkpointRef,
|
|
7429
7575
|
fromBranch: req.fromBranch,
|
|
7576
|
+
useBranch: req.useBranch,
|
|
7430
7577
|
image: req.image,
|
|
7431
7578
|
onLog: req.onLog,
|
|
7432
7579
|
claudeConfig: po.claudeConfig,
|
|
@@ -7783,6 +7930,9 @@ async function stageCodexStaticForUpload(opts = {}) {
|
|
|
7783
7930
|
}
|
|
7784
7931
|
}
|
|
7785
7932
|
async function stageCodexCredentialsForUpload(opts = {}) {
|
|
7933
|
+
if (await pathExists7(CODEX_CREDENTIALS_BACKUP_FILE)) {
|
|
7934
|
+
return stageSingleFileTarball("codex-creds", CODEX_CREDENTIALS_BACKUP_FILE, "auth.json");
|
|
7935
|
+
}
|
|
7786
7936
|
const hostHome = opts.hostHome ?? homedir11();
|
|
7787
7937
|
const hostAuth = join14(hostHome, ".codex", "auth.json");
|
|
7788
7938
|
if (!await pathExists7(hostAuth)) return emptyResult([CODEX_KEYCHAIN_WARNING]);
|
|
@@ -7847,6 +7997,9 @@ async function stageOpencodeStaticForUpload(opts = {}) {
|
|
|
7847
7997
|
}
|
|
7848
7998
|
}
|
|
7849
7999
|
async function stageOpencodeCredentialsForUpload(opts = {}) {
|
|
8000
|
+
if (await pathExists7(OPENCODE_CREDENTIALS_BACKUP_FILE)) {
|
|
8001
|
+
return stageSingleFileTarball("opencode-creds", OPENCODE_CREDENTIALS_BACKUP_FILE, "auth.json");
|
|
8002
|
+
}
|
|
7850
8003
|
const hostHome = opts.hostHome ?? homedir11();
|
|
7851
8004
|
const hostAuth = join14(hostHome, ".local", "share", "opencode", "auth.json");
|
|
7852
8005
|
if (!await pathExists7(hostAuth)) return emptyResult();
|
|
@@ -7908,6 +8061,7 @@ export {
|
|
|
7908
8061
|
RELAY_IMAGE_REF,
|
|
7909
8062
|
hashRpcParams,
|
|
7910
8063
|
GH_PR_OPS,
|
|
8064
|
+
injectPrCreateHead,
|
|
7911
8065
|
loadQueueConfig,
|
|
7912
8066
|
writeJob,
|
|
7913
8067
|
readJob,
|
|
@@ -7966,6 +8120,9 @@ export {
|
|
|
7966
8120
|
claudeSessionInfo,
|
|
7967
8121
|
pullClaudeExtras,
|
|
7968
8122
|
CREDENTIALS_BACKUP_FILE,
|
|
8123
|
+
CODEX_CREDENTIALS_BACKUP_FILE,
|
|
8124
|
+
OPENCODE_CREDENTIALS_BACKUP_FILE,
|
|
8125
|
+
isRealAgentCredential,
|
|
7969
8126
|
hostBackupHasCredentials,
|
|
7970
8127
|
parseSyncResult,
|
|
7971
8128
|
syncClaudeCredentials,
|
|
@@ -8111,4 +8268,4 @@ export {
|
|
|
8111
8268
|
browserSessionActive,
|
|
8112
8269
|
ensureBoxBrowser
|
|
8113
8270
|
};
|
|
8114
|
-
//# sourceMappingURL=chunk-
|
|
8271
|
+
//# sourceMappingURL=chunk-NCJP5MTN.js.map
|