@hachej/boring-agent 0.1.29 → 0.1.31

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.
@@ -17,6 +17,11 @@ function getEnv(name) {
17
17
  function getEnvSnapshot() {
18
18
  return { ...process.env };
19
19
  }
20
+ function setEnvDefault(name, value) {
21
+ if (process.env[name] !== void 0) return false;
22
+ process.env[name] = value;
23
+ return true;
24
+ }
20
25
 
21
26
  // src/server/workspace/runtimeLayout.ts
22
27
  import { mkdirSync, writeFileSync } from "fs";
@@ -1556,8 +1561,7 @@ var UV_SETUP_COMMANDS = [
1556
1561
  "uv --version"
1557
1562
  ];
1558
1563
  var NODE_UV_SETUP_COMMANDS = [
1559
- "command -v pip3 >/dev/null 2>&1 || sudo dnf install -y python3-pip",
1560
- `[ -x ${VERCEL_UV_BIN} ] || python3 -m pip install --user --upgrade uv`,
1564
+ `[ -x ${VERCEL_UV_BIN} ] || curl -LsSf https://astral.sh/uv/install.sh | sh`,
1561
1565
  `${VERCEL_UV_BIN} --version`
1562
1566
  ];
1563
1567
  function isNodeFamilyRuntime(runtime) {
@@ -3165,11 +3169,13 @@ async function ensureUv(options) {
3165
3169
  const explicitUvBin = options.explicitUvBin?.trim();
3166
3170
  if (explicitUvBin) {
3167
3171
  try {
3168
- return {
3169
- uvBin: explicitUvBin,
3170
- uvVersion: await commandOutput2(options.adapter, explicitUvBin, ["--version"]) || "uv unknown",
3171
- installedWorkspaceUv: false
3172
- };
3172
+ const uvVersion = await commandOutput2(options.adapter, explicitUvBin, ["--version"]) || "uv unknown";
3173
+ try {
3174
+ await options.adapter.exec("mkdir", ["-p", options.runtimeLayout.uvBin], { cwd: options.runtimeLayout.workspaceRoot });
3175
+ await options.adapter.exec("ln", ["-sf", explicitUvBin, join6(options.runtimeLayout.uvBin, "uv")], { cwd: options.runtimeLayout.workspaceRoot });
3176
+ } catch {
3177
+ }
3178
+ return { uvBin: explicitUvBin, uvVersion, installedWorkspaceUv: false };
3173
3179
  } catch {
3174
3180
  }
3175
3181
  }
@@ -3248,6 +3254,7 @@ async function shouldInstallPythonRuntime(options) {
3248
3254
  return true;
3249
3255
  }
3250
3256
  for (const output of options.expectedOutputs) {
3257
+ if (output === options.runtimeLayout.venvPython) continue;
3251
3258
  if (!await options.adapter.workspaceFs.exists(toWorkspaceRel2(options.runtimeLayout, output))) return true;
3252
3259
  }
3253
3260
  return false;
@@ -4373,6 +4380,13 @@ function createDefaultVercelClient(auth, opts = {}) {
4373
4380
  }
4374
4381
  };
4375
4382
  }
4383
+ function buildWorkspaceRootSetupScript(remoteRoot, workspaceRoot) {
4384
+ return [
4385
+ `if [ -L ${workspaceRoot} ]; then rm -f ${workspaceRoot}; fi`,
4386
+ `mkdir -p ${remoteRoot}`,
4387
+ `if [ ${remoteRoot} != ${workspaceRoot} ]; then ln -sfn ${remoteRoot} ${workspaceRoot} 2>/dev/null || true; fi`
4388
+ ].join("; ");
4389
+ }
4376
4390
  async function ensureVercelWorkspaceRoot(sandbox) {
4377
4391
  let rootCreated = false;
4378
4392
  if (sandbox.fs?.mkdir) {
@@ -4391,12 +4405,23 @@ async function ensureVercelWorkspaceRoot(sandbox) {
4391
4405
  }
4392
4406
  const result = await sandbox.runCommand({
4393
4407
  cmd: "sh",
4394
- args: ["-c", `mkdir -p ${VERCEL_SANDBOX_REMOTE_ROOT} && (ln -sfn ${VERCEL_SANDBOX_REMOTE_ROOT} ${VERCEL_SANDBOX_WORKSPACE_ROOT} 2>/dev/null || true)`]
4408
+ args: ["-c", buildWorkspaceRootSetupScript(VERCEL_SANDBOX_REMOTE_ROOT, VERCEL_SANDBOX_WORKSPACE_ROOT)]
4395
4409
  });
4396
4410
  if ((result.exitCode ?? 1) !== 0) {
4397
4411
  throw new Error(`failed to initialize ${VERCEL_SANDBOX_REMOTE_ROOT} (exit ${result.exitCode ?? "unknown"})`);
4398
4412
  }
4399
4413
  }
4414
+ async function ensureVercelRuntimePrimitives(sandbox, runtime) {
4415
+ if (!sandbox.runCommand) return;
4416
+ const script = uvSetupCommandsForRuntime(runtime).join(" && ");
4417
+ const result = await sandbox.runCommand({ cmd: "sh", args: ["-c", script] });
4418
+ if ((result.exitCode ?? 1) !== 0) {
4419
+ throw new Error(`runtime bootstrap (uv) failed (exit ${result.exitCode ?? "unknown"})`);
4420
+ }
4421
+ if (isNodeFamilyRuntime(runtime)) {
4422
+ setEnvDefault("BORING_AGENT_UV_BIN", VERCEL_UV_BIN);
4423
+ }
4424
+ }
4400
4425
  async function seedTemplateIntoVercelWorkspace(workspace, templatePath, logger) {
4401
4426
  const files = await collectFiles(templatePath);
4402
4427
  const hash = computeTemplateHash(files);
@@ -4554,6 +4579,14 @@ async function ensureVercelProvisioningParts(options) {
4554
4579
  await ensureVercelWorkspaceRoot(sandboxHandle);
4555
4580
  }
4556
4581
  });
4582
+ await runSandboxSetupStep({
4583
+ telemetry,
4584
+ ctx: options.ctx,
4585
+ phase: "runtime-bootstrap",
4586
+ run: async () => {
4587
+ await ensureVercelRuntimePrimitives(sandboxHandle, runtime);
4588
+ }
4589
+ });
4557
4590
  const workspace = createVercelSandboxWorkspace(sandboxHandle);
4558
4591
  const workspaceFs = createVercelWorkspaceFs({ workspace, sandbox: sandboxHandle });
4559
4592
  const sandbox = createVercelSandboxExec(sandboxHandle);
@@ -5858,8 +5891,16 @@ var WORKSPACE_PATHS_GUIDELINE = [
5858
5891
  "- For `find`/`grep`/`ls`: omit the `path` argument to search from the workspace root. Pass `path` only when you need to restrict to a subdirectory, and only as a workspace-relative path.",
5859
5892
  "- For `read`/`edit`/`write`: pass workspace-relative paths only."
5860
5893
  ].join("\n");
5894
+ var PYTHON_RUNTIME_GUIDELINE = [
5895
+ "## Python runtime",
5896
+ "",
5897
+ "- Python 3 and the Astral `uv` package manager are available on PATH.",
5898
+ "- Run scripts with `python3`.",
5899
+ "- Install/manage packages with `uv pip install <pkg>` (fast; targets the workspace venv at `.boring-agent/venv`). `uv` is the canonical package manager here \u2014 don't assume only `pip`.",
5900
+ "- Create venvs with `uv venv` if needed."
5901
+ ].join("\n");
5861
5902
  function composeSystemPromptAppend(hostAppend) {
5862
- return [WORKSPACE_PATHS_GUIDELINE, hostAppend?.trim()].filter(Boolean).join("\n\n");
5903
+ return [WORKSPACE_PATHS_GUIDELINE, PYTHON_RUNTIME_GUIDELINE, hostAppend?.trim()].filter(Boolean).join("\n\n");
5863
5904
  }
5864
5905
  function buildDynamicPromptExtension(source) {
5865
5906
  return (pi) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Pane-embeddable coding agent. Ships direct/local/vercel-sandbox execution modes behind one interface.",
@@ -75,7 +75,7 @@
75
75
  "use-stick-to-bottom": "^1.1.3",
76
76
  "yaml": "^2.8.3",
77
77
  "zod": "^3.25.76",
78
- "@hachej/boring-ui-kit": "0.1.29"
78
+ "@hachej/boring-ui-kit": "0.1.31"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@opentelemetry/api": "^1.9.1",