@hachej/boring-agent 0.1.27 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -134,6 +134,10 @@ declare function buildSnapshotRecipeHash(input: {
134
134
  }): string;
135
135
  declare function bakeSnapshotIfNeeded(opts: SnapshotBakeOptions): Promise<SnapshotBakeResult>;
136
136
 
137
+ /**
138
+ * uv setup for Python-family runtimes (e.g. Vercel `python3.13`), which already
139
+ * ship `pip` and usually `uv`. Verify-or-install via the on-PATH `uv`.
140
+ */
137
141
  declare const UV_SETUP_COMMANDS: readonly ["command -v uv >/dev/null 2>&1 || python3 -m pip install --upgrade uv", "uv --version"];
138
142
  type DeploymentSnapshotStatus = 'skipped' | 'cache-hit' | 'baked' | 'failed';
139
143
  interface DeploymentSnapshotRecipe {
@@ -1357,7 +1357,7 @@ function shellQuote(value) {
1357
1357
  function makeInstallCommand(binary, packages) {
1358
1358
  const quoted = packages.map(shellQuote).join(" ");
1359
1359
  if (binary === "dnf") {
1360
- return `dnf install -y ${quoted}`;
1360
+ return `sudo dnf install -y ${quoted}`;
1361
1361
  }
1362
1362
  return `python3 -m pip install ${quoted}`;
1363
1363
  }
@@ -1550,17 +1550,29 @@ async function bakeSnapshotIfNeeded(opts) {
1550
1550
  }
1551
1551
 
1552
1552
  // src/server/sandbox/snapshots/deploymentSnapshot.ts
1553
+ var VERCEL_UV_BIN = "/home/vercel-sandbox/.local/bin/uv";
1553
1554
  var UV_SETUP_COMMANDS = [
1554
1555
  "command -v uv >/dev/null 2>&1 || python3 -m pip install --upgrade uv",
1555
1556
  "uv --version"
1556
1557
  ];
1558
+ 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`,
1561
+ `${VERCEL_UV_BIN} --version`
1562
+ ];
1563
+ function isNodeFamilyRuntime(runtime) {
1564
+ return typeof runtime === "string" && /^node/i.test(runtime.trim());
1565
+ }
1566
+ function uvSetupCommandsForRuntime(runtime) {
1567
+ return isNodeFamilyRuntime(runtime) ? NODE_UV_SETUP_COMMANDS : UV_SETUP_COMMANDS;
1568
+ }
1557
1569
  function buildDeploymentSnapshotRecipe(opts = {}) {
1558
1570
  return {
1559
1571
  runtime: opts.runtime,
1560
1572
  systemPackages: opts.systemPackages,
1561
1573
  pythonPackages: opts.pythonPackages,
1562
1574
  setupCommands: [
1563
- ...opts.includeUv === false ? [] : UV_SETUP_COMMANDS,
1575
+ ...opts.includeUv === false ? [] : uvSetupCommandsForRuntime(opts.runtime),
1564
1576
  ...opts.setupCommands ?? []
1565
1577
  ]
1566
1578
  };
@@ -3150,6 +3162,17 @@ async function commandOutput2(adapter, command, args) {
3150
3162
  return result?.stdout?.trim() ?? "";
3151
3163
  }
3152
3164
  async function ensureUv(options) {
3165
+ const explicitUvBin = options.explicitUvBin?.trim();
3166
+ if (explicitUvBin) {
3167
+ try {
3168
+ return {
3169
+ uvBin: explicitUvBin,
3170
+ uvVersion: await commandOutput2(options.adapter, explicitUvBin, ["--version"]) || "uv unknown",
3171
+ installedWorkspaceUv: false
3172
+ };
3173
+ } catch {
3174
+ }
3175
+ }
3153
3176
  try {
3154
3177
  return {
3155
3178
  uvBin: "uv",
@@ -3619,7 +3642,11 @@ async function provisionWorkspaceRuntime(opts) {
3619
3642
  run: () => ensurePythonRuntime({
3620
3643
  adapter: opts.adapter,
3621
3644
  runtimeLayout: opts.runtimeLayout,
3622
- packages: pythonPackages
3645
+ packages: pythonPackages,
3646
+ // Provider-neutral seam: a deploy/provider (e.g. Vercel Node runtime) may
3647
+ // export the explicit uv path since it is not on the non-interactive exec
3648
+ // PATH. Unset for direct/local — they fall back to bare `uv`.
3649
+ explicitUvBin: getEnv("BORING_AGENT_UV_BIN")?.trim() || void 0
3623
3650
  })
3624
3651
  });
3625
3652
  const result = {
@@ -3739,20 +3766,26 @@ var LOCAL_SANDBOX_WORKSPACE_ROOT = "/workspace";
3739
3766
  function sourceToPath4(source) {
3740
3767
  return source instanceof URL ? fileURLToPath5(source) : source;
3741
3768
  }
3742
- async function assertExistingInsideWorkspace(root, relPath) {
3769
+ async function assertExistingInsideWorkspace(root, relPath, enforceSymlinkBoundary) {
3743
3770
  const absPath = validatePath(root, relPath);
3744
3771
  try {
3745
- await assertRealPathWithinWorkspace(root, absPath);
3772
+ if (enforceSymlinkBoundary) {
3773
+ await assertRealPathWithinWorkspace(root, absPath);
3774
+ } else {
3775
+ await lstat3(absPath);
3776
+ }
3746
3777
  return absPath;
3747
3778
  } catch (error) {
3748
3779
  if (error.code === "ENOENT") return null;
3749
3780
  throw error;
3750
3781
  }
3751
3782
  }
3752
- async function prepareWritablePath(root, relPath) {
3783
+ async function prepareWritablePath(root, relPath, enforceSymlinkBoundary) {
3753
3784
  const absPath = validatePath(root, relPath);
3754
3785
  await mkdir6(dirname9(absPath), { recursive: true });
3755
- await assertRealPathWithinWorkspace(root, dirname9(absPath));
3786
+ if (enforceSymlinkBoundary) {
3787
+ await assertRealPathWithinWorkspace(root, dirname9(absPath));
3788
+ }
3756
3789
  try {
3757
3790
  const targetStat = await lstat3(absPath);
3758
3791
  if (targetStat.isSymbolicLink()) {
@@ -3848,36 +3881,39 @@ async function copyExternalSourceIntoWorkspace(paths, sourcePath, opts) {
3848
3881
  });
3849
3882
  return `${LOCAL_SANDBOX_WORKSPACE_ROOT}/${relTarget}`;
3850
3883
  }
3851
- function createWorkspaceFs(workspaceRoot) {
3884
+ function createWorkspaceFs(workspaceRoot, opts) {
3885
+ const { enforceSymlinkBoundary } = opts;
3852
3886
  return {
3853
3887
  async exists(workspaceRelativePath) {
3854
- const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath);
3888
+ const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath, enforceSymlinkBoundary);
3855
3889
  if (!absPath) return false;
3856
3890
  await lstat3(absPath);
3857
3891
  return true;
3858
3892
  },
3859
3893
  async rm(workspaceRelativePath) {
3860
- const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath);
3894
+ const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath, enforceSymlinkBoundary);
3861
3895
  if (!absPath) return;
3862
3896
  await rm3(absPath, { recursive: true, force: true });
3863
3897
  },
3864
3898
  async mkdir(workspaceRelativePath) {
3865
3899
  const absPath = validatePath(workspaceRoot, workspaceRelativePath);
3866
3900
  await mkdir6(absPath, { recursive: true });
3867
- await assertRealPathWithinWorkspace(workspaceRoot, absPath);
3901
+ if (enforceSymlinkBoundary) {
3902
+ await assertRealPathWithinWorkspace(workspaceRoot, absPath);
3903
+ }
3868
3904
  },
3869
3905
  async writeText(workspaceRelativePath, content) {
3870
- const absPath = await prepareWritablePath(workspaceRoot, workspaceRelativePath);
3906
+ const absPath = await prepareWritablePath(workspaceRoot, workspaceRelativePath, enforceSymlinkBoundary);
3871
3907
  await writeFile5(absPath, content, "utf8");
3872
3908
  },
3873
3909
  async readText(workspaceRelativePath) {
3874
- const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath);
3910
+ const absPath = await assertExistingInsideWorkspace(workspaceRoot, workspaceRelativePath, enforceSymlinkBoundary);
3875
3911
  if (!absPath) return null;
3876
3912
  return await readFile6(absPath, "utf8");
3877
3913
  },
3878
3914
  async copyFromHost(hostSourcePath, workspaceRelativeTarget) {
3879
3915
  const sourcePath = sourceToPath4(hostSourcePath);
3880
- const absTarget = await prepareWritablePath(workspaceRoot, workspaceRelativeTarget);
3916
+ const absTarget = await prepareWritablePath(workspaceRoot, workspaceRelativeTarget, enforceSymlinkBoundary);
3881
3917
  const sourceStat = await stat7(sourcePath);
3882
3918
  await cp3(sourcePath, absTarget, {
3883
3919
  recursive: sourceStat.isDirectory(),
@@ -3896,7 +3932,7 @@ function createDirectProvisioningAdapter(paths, runner = spawnCommand) {
3896
3932
  async resolveInstallSource(source) {
3897
3933
  return sourceToPath4(source);
3898
3934
  },
3899
- workspaceFs: createWorkspaceFs(paths.workspaceRoot),
3935
+ workspaceFs: createWorkspaceFs(paths.workspaceRoot, { enforceSymlinkBoundary: false }),
3900
3936
  getRuntimeCacheRoot() {
3901
3937
  return paths.cache;
3902
3938
  }
@@ -3938,7 +3974,7 @@ function createLocalProvisioningAdapter(paths, runner = spawnCommand) {
3938
3974
  }
3939
3975
  return await copyExternalSourceIntoWorkspace(paths, realSource, opts);
3940
3976
  },
3941
- workspaceFs: createWorkspaceFs(paths.workspaceRoot),
3977
+ workspaceFs: createWorkspaceFs(paths.workspaceRoot, { enforceSymlinkBoundary: true }),
3942
3978
  getRuntimeCacheRoot() {
3943
3979
  return paths.cache;
3944
3980
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
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.27"
78
+ "@hachej/boring-ui-kit": "0.1.28"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@opentelemetry/api": "^1.9.1",