@hachej/boring-agent 0.1.0 → 0.1.5

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.
@@ -236,7 +236,7 @@ function useAgentChat(opts) {
236
236
  }, [sessionId, cacheKey, setMessages]);
237
237
  const messages = chat.messages;
238
238
  useEffect4(() => {
239
- if (!hydrated || !cacheKey) return;
239
+ if (!hydrated || !cacheKey || messages.length === 0) return;
240
240
  try {
241
241
  globalThis.localStorage?.setItem(cacheKey, JSON.stringify(messages));
242
242
  } catch {
@@ -180,8 +180,10 @@ function createDirectSandbox() {
180
180
  }
181
181
 
182
182
  // src/server/sandbox/bwrap/createBwrapSandbox.ts
183
+ import { access } from "fs/promises";
184
+ import { constants } from "fs";
183
185
  import { spawn as spawn2 } from "child_process";
184
- import { isAbsolute as isAbsolute2, relative, resolve, sep } from "path";
186
+ import { dirname, isAbsolute as isAbsolute2, join as join2, relative, resolve, sep } from "path";
185
187
 
186
188
  // src/server/sandbox/bwrap/buildBwrapArgs.ts
187
189
  import { isAbsolute } from "path";
@@ -250,9 +252,12 @@ function buildBwrapArgs(workspaceRoot, options) {
250
252
  SANDBOX_HOME,
251
253
  "--setenv",
252
254
  "HOME",
253
- SANDBOX_HOME,
254
- "--"
255
+ SANDBOX_HOME
255
256
  );
257
+ if (options?.postWorkspaceArgs) {
258
+ args.push(...options.postWorkspaceArgs);
259
+ }
260
+ args.push("--");
256
261
  return args;
257
262
  }
258
263
 
@@ -347,6 +352,26 @@ async function assertBwrapAvailable() {
347
352
  });
348
353
  });
349
354
  }
355
+ async function dirAccessible(path4) {
356
+ try {
357
+ await access(path4, constants.F_OK);
358
+ return true;
359
+ } catch {
360
+ return false;
361
+ }
362
+ }
363
+ async function buildGlobalToolMounts(workspaceRoot) {
364
+ const globalRoot = dirname(workspaceRoot);
365
+ if (globalRoot === workspaceRoot) return [];
366
+ const args = [];
367
+ if (await dirAccessible(join2(globalRoot, ".boring-agent"))) {
368
+ args.push("--ro-bind", join2(globalRoot, ".boring-agent"), `${SANDBOX_HOME2}/.boring-agent`);
369
+ }
370
+ if (await dirAccessible(join2(globalRoot, ".venv"))) {
371
+ args.push("--ro-bind", join2(globalRoot, ".venv"), `${SANDBOX_HOME2}/.venv`);
372
+ }
373
+ return args;
374
+ }
350
375
  function createBwrapSandbox() {
351
376
  let workspace = null;
352
377
  return {
@@ -367,7 +392,8 @@ function createBwrapSandbox() {
367
392
  const maxOutputBytes = opts?.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES2;
368
393
  const workspaceRoot = workspace.root;
369
394
  const sandboxCwd = computeSandboxCwd(workspaceRoot, opts?.cwd);
370
- const baseArgs = buildBwrapArgs(workspaceRoot);
395
+ const postWorkspaceArgs = await buildGlobalToolMounts(workspaceRoot);
396
+ const baseArgs = buildBwrapArgs(workspaceRoot, { postWorkspaceArgs });
371
397
  const args = [
372
398
  ...withSandboxCwd(baseArgs, sandboxCwd),
373
399
  "bash",
@@ -1182,12 +1208,12 @@ async function prepareVercelDeploymentSnapshot(opts) {
1182
1208
 
1183
1209
  // src/server/workspace/createNodeWorkspace.ts
1184
1210
  import { lstat as lstat2, mkdir as mkdir3, readdir, readFile as readFile3, rename as rename3, rmdir, stat as stat2, unlink as unlink3, writeFile as writeFile3 } from "fs/promises";
1185
- import { dirname as dirname2, relative as relative3, sep as sep2 } from "path";
1211
+ import { dirname as dirname3, relative as relative3, sep as sep2 } from "path";
1186
1212
  import chokidar from "chokidar";
1187
1213
 
1188
1214
  // src/server/workspace/paths.ts
1189
1215
  import { lstat, realpath, stat } from "fs/promises";
1190
- import { dirname, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve2 } from "path";
1216
+ import { dirname as dirname2, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve2 } from "path";
1191
1217
  function createPathValidationError(reason, requestedPath, message) {
1192
1218
  return Object.assign(new Error(message), {
1193
1219
  statusCode: 400,
@@ -1247,7 +1273,7 @@ async function ensureExistingWorkspacePath(workspaceRoot, relPath) {
1247
1273
  }
1248
1274
  async function ensureWritableWorkspacePath(workspaceRoot, relPath) {
1249
1275
  const absPath = validatePath(workspaceRoot, relPath);
1250
- const parentPath = dirname(absPath);
1276
+ const parentPath = dirname2(absPath);
1251
1277
  await stat(parentPath);
1252
1278
  await assertRealPathWithinWorkspace(workspaceRoot, parentPath);
1253
1279
  try {
@@ -1419,7 +1445,7 @@ function createNodeWorkspace(root) {
1419
1445
  } catch (error) {
1420
1446
  const code = error.code;
1421
1447
  if (code !== "ENOENT") throw error;
1422
- const parent = dirname2(existingAncestor);
1448
+ const parent = dirname3(existingAncestor);
1423
1449
  if (parent === existingAncestor) throw error;
1424
1450
  existingAncestor = parent;
1425
1451
  }
@@ -1438,9 +1464,9 @@ function createNodeWorkspace(root) {
1438
1464
 
1439
1465
  // src/server/workspace/provisionRuntime.ts
1440
1466
  import { createHash as createHash3 } from "crypto";
1441
- import { constants } from "fs";
1442
- import { access, chmod as chmod3, cp, mkdir as mkdir4, readdir as readdir2, readFile as readFile4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
1443
- import { dirname as dirname3, join as join2, resolve as resolve3 } from "path";
1467
+ import { constants as constants2 } from "fs";
1468
+ import { access as access2, chmod as chmod3, cp, mkdir as mkdir4, readdir as readdir2, readFile as readFile4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
1469
+ import { dirname as dirname4, join as join3, resolve as resolve3 } from "path";
1444
1470
  import { fileURLToPath } from "url";
1445
1471
  import { execFile } from "child_process";
1446
1472
  import { promisify } from "util";
@@ -1451,7 +1477,7 @@ function toPath(value) {
1451
1477
  }
1452
1478
  async function exists(path4) {
1453
1479
  try {
1454
- await access(path4, constants.F_OK);
1480
+ await access2(path4, constants2.F_OK);
1455
1481
  return true;
1456
1482
  } catch {
1457
1483
  return false;
@@ -1480,7 +1506,7 @@ async function hashPath(path4, hash) {
1480
1506
  for (const entry of entries) {
1481
1507
  hash.update(`dir:${entry}
1482
1508
  `);
1483
- await hashPath(join2(path4, entry), hash);
1509
+ await hashPath(join3(path4, entry), hash);
1484
1510
  }
1485
1511
  return;
1486
1512
  }
@@ -1507,7 +1533,7 @@ async function fingerprint(contributions) {
1507
1533
  `);
1508
1534
  hash.update(JSON.stringify(spec.extraLibs ?? []));
1509
1535
  hash.update(JSON.stringify(Object.fromEntries(Object.entries(spec.env ?? {}).map(([k, v]) => [k, String(v)]))));
1510
- if (await exists(projectFile)) await hashPath(dirname3(projectFile), hash);
1536
+ if (await exists(projectFile)) await hashPath(dirname4(projectFile), hash);
1511
1537
  }
1512
1538
  }
1513
1539
  return `sha256:${hash.digest("hex")}`;
@@ -1536,14 +1562,14 @@ async function seedTemplates(workspaceRoot, contributions) {
1536
1562
  }
1537
1563
  async function ensurePython(workspaceRoot, specs) {
1538
1564
  if (specs.length === 0) return;
1539
- const venvPython = join2(workspaceRoot, ".venv", "bin", "python");
1565
+ const venvPython = join3(workspaceRoot, ".venv", "bin", "python");
1540
1566
  const uv = await commandExists("uv");
1541
1567
  if (!await exists(venvPython)) {
1542
1568
  if (uv) await run("uv", ["venv", ".venv"], workspaceRoot);
1543
1569
  else await run("/usr/bin/python3", ["-m", "venv", ".venv"], workspaceRoot);
1544
1570
  }
1545
1571
  for (const spec of specs) {
1546
- const projectDir = dirname3(toPath(spec.projectFile));
1572
+ const projectDir = dirname4(toPath(spec.projectFile));
1547
1573
  if (uv) {
1548
1574
  await run("uv", ["pip", "install", "--python", venvPython, projectDir], workspaceRoot);
1549
1575
  if (spec.extraLibs?.length) {
@@ -1569,12 +1595,12 @@ function assertEnvKey(key) {
1569
1595
  }
1570
1596
  async function isRuntimeMaterialized(workspaceRoot, contributions) {
1571
1597
  const hasPython = contributions.some(({ provisioning }) => (provisioning.python ?? []).length > 0);
1572
- if (hasPython && !await exists(join2(workspaceRoot, ".venv", "bin", "python"))) return false;
1598
+ if (hasPython && !await exists(join3(workspaceRoot, ".venv", "bin", "python"))) return false;
1573
1599
  return true;
1574
1600
  }
1575
1601
  async function writeShims(workspaceRoot, env) {
1576
- const shimDir = join2(workspaceRoot, ".boring-agent", "bin");
1577
- const venvBin = join2(workspaceRoot, ".venv", "bin");
1602
+ const shimDir = join3(workspaceRoot, ".boring-agent", "bin");
1603
+ const venvBin = join3(workspaceRoot, ".venv", "bin");
1578
1604
  await mkdir4(shimDir, { recursive: true });
1579
1605
  const exports = Object.entries(env).map(([key, value]) => {
1580
1606
  assertEnvKey(key);
@@ -1588,21 +1614,21 @@ export BORING_AGENT_WORKSPACE_ROOT="$WORKSPACE_ROOT"
1588
1614
  ${exports}
1589
1615
  VENV_BIN="$WORKSPACE_ROOT/.venv/bin"
1590
1616
  `;
1591
- await writeExecutable(join2(shimDir, "python"), `${base}exec "$VENV_BIN/python" "$@"
1617
+ await writeExecutable(join3(shimDir, "python"), `${base}exec "$VENV_BIN/python" "$@"
1592
1618
  `);
1593
- await writeExecutable(join2(shimDir, "python3"), `${base}exec "$VENV_BIN/python" "$@"
1619
+ await writeExecutable(join3(shimDir, "python3"), `${base}exec "$VENV_BIN/python" "$@"
1594
1620
  `);
1595
- await writeExecutable(join2(shimDir, "pip"), `${base}exec "$VENV_BIN/python" -m pip "$@"
1621
+ await writeExecutable(join3(shimDir, "pip"), `${base}exec "$VENV_BIN/python" -m pip "$@"
1596
1622
  `);
1597
- await writeExecutable(join2(shimDir, "pip3"), `${base}exec "$VENV_BIN/python" -m pip "$@"
1623
+ await writeExecutable(join3(shimDir, "pip3"), `${base}exec "$VENV_BIN/python" -m pip "$@"
1598
1624
  `);
1599
1625
  if (await exists(venvBin)) {
1600
1626
  for (const entry of await readdir2(venvBin)) {
1601
1627
  if (["python", "python3", "pip", "pip3"].includes(entry)) continue;
1602
- const full = join2(venvBin, entry);
1628
+ const full = join3(venvBin, entry);
1603
1629
  const info = await stat3(full).catch(() => null);
1604
1630
  if (!info?.isFile()) continue;
1605
- await writeExecutable(join2(shimDir, entry), `${base}TARGET="$VENV_BIN"/${bashSingleQuote(entry)}
1631
+ await writeExecutable(join3(shimDir, entry), `${base}TARGET="$VENV_BIN"/${bashSingleQuote(entry)}
1606
1632
  SHEBANG="$(head -n 1 "$TARGET" 2>/dev/null || true)"
1607
1633
  case "$SHEBANG" in
1608
1634
  *python*) exec "$VENV_BIN/python" "$TARGET" "$@" ;;
@@ -1625,8 +1651,8 @@ async function provisionRuntimeWorkspace({
1625
1651
  await mkdir4(workspaceRoot, { recursive: true });
1626
1652
  const env = collectEnv(active);
1627
1653
  const hash = await fingerprint(active);
1628
- const markerPath = join2(workspaceRoot, ".boring-agent", "provisioning.json");
1629
- const binDir = join2(workspaceRoot, ".boring-agent", "bin");
1654
+ const markerPath = join3(workspaceRoot, ".boring-agent", "provisioning.json");
1655
+ const binDir = join3(workspaceRoot, ".boring-agent", "bin");
1630
1656
  if (!force && await exists(markerPath)) {
1631
1657
  try {
1632
1658
  const marker = JSON.parse(await readFile4(markerPath, "utf8"));
@@ -1640,7 +1666,7 @@ async function provisionRuntimeWorkspace({
1640
1666
  await seedTemplates(workspaceRoot, active);
1641
1667
  await ensurePython(workspaceRoot, active.flatMap(({ provisioning }) => provisioning.python ?? []));
1642
1668
  const actualBinDir = await writeShims(workspaceRoot, env);
1643
- await mkdir4(dirname3(markerPath), { recursive: true });
1669
+ await mkdir4(dirname4(markerPath), { recursive: true });
1644
1670
  await writeFile4(markerPath, JSON.stringify({ v: PROVISIONING_VERSION, fingerprint: hash }, null, 2), "utf8");
1645
1671
  return { fingerprint: hash, changed: true, env, binDir: actualBinDir };
1646
1672
  }
@@ -2011,7 +2037,7 @@ function createServerFileSearch(workspace, sandbox) {
2011
2037
 
2012
2038
  // src/server/workspace/provision.ts
2013
2039
  import { cp as cp2, mkdir as mkdir5, stat as stat4, writeFile as writeFile5 } from "fs/promises";
2014
- import { dirname as dirname4, join as join3 } from "path";
2040
+ import { dirname as dirname5, join as join4 } from "path";
2015
2041
  var PROVISION_MARKER_REL_PATH = ".boring-agent/provisioned";
2016
2042
  async function fileExists(targetPath) {
2017
2043
  try {
@@ -2026,7 +2052,7 @@ async function fileExists(targetPath) {
2026
2052
  }
2027
2053
  async function copyTemplate(templatePath, workspaceRoot) {
2028
2054
  if (!templatePath) return;
2029
- const markerPath = join3(workspaceRoot, PROVISION_MARKER_REL_PATH);
2055
+ const markerPath = join4(workspaceRoot, PROVISION_MARKER_REL_PATH);
2030
2056
  if (await fileExists(markerPath)) return;
2031
2057
  try {
2032
2058
  await cp2(templatePath, workspaceRoot, {
@@ -2040,7 +2066,7 @@ async function copyTemplate(templatePath, workspaceRoot) {
2040
2066
  { cause: error }
2041
2067
  );
2042
2068
  }
2043
- await mkdir5(dirname4(markerPath), { recursive: true });
2069
+ await mkdir5(dirname5(markerPath), { recursive: true });
2044
2070
  await writeFile5(markerPath, (/* @__PURE__ */ new Date()).toISOString(), "utf-8");
2045
2071
  }
2046
2072
 
@@ -2792,7 +2818,7 @@ import {
2792
2818
  utimes
2793
2819
  } from "fs/promises";
2794
2820
  import { readFileSync, readdirSync } from "fs";
2795
- import { join as join4 } from "path";
2821
+ import { join as join5 } from "path";
2796
2822
  import { homedir as homedir3 } from "os";
2797
2823
  import {
2798
2824
  parseSessionEntries,
@@ -2801,7 +2827,7 @@ import {
2801
2827
  } from "@mariozechner/pi-coding-agent";
2802
2828
  function defaultSessionDir(cwd) {
2803
2829
  const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
2804
- return join4(homedir3(), ".pi", "agent", "sessions", safePath);
2830
+ return join5(homedir3(), ".pi", "agent", "sessions", safePath);
2805
2831
  }
2806
2832
  var SAFE_ID = /^[a-zA-Z0-9_-]+$/;
2807
2833
  var PiSessionStore = class {
@@ -2815,7 +2841,7 @@ var PiSessionStore = class {
2815
2841
  const files = await readdir4(this.sessionDir).catch(() => []);
2816
2842
  const jsonlFiles = files.filter((f) => f.endsWith(".jsonl"));
2817
2843
  const summaries = await Promise.all(
2818
- jsonlFiles.map((f) => this.summarizeFile(join4(this.sessionDir, f)))
2844
+ jsonlFiles.map((f) => this.summarizeFile(join5(this.sessionDir, f)))
2819
2845
  );
2820
2846
  return summaries.filter((s) => s !== null).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
2821
2847
  }
@@ -2841,7 +2867,7 @@ var PiSessionStore = class {
2841
2867
  };
2842
2868
  lines.push(JSON.stringify(infoEntry));
2843
2869
  }
2844
- const filepath = join4(this.sessionDir, `${id}.jsonl`);
2870
+ const filepath = join5(this.sessionDir, `${id}.jsonl`);
2845
2871
  await writeFile6(filepath, lines.join("\n") + "\n", "utf-8");
2846
2872
  return {
2847
2873
  id,
@@ -2898,7 +2924,7 @@ var PiSessionStore = class {
2898
2924
  loadPiSessionFileSync(sessionId) {
2899
2925
  if (!SAFE_ID.test(sessionId)) return null;
2900
2926
  try {
2901
- const direct = join4(this.sessionDir, `${sessionId}.jsonl`);
2927
+ const direct = join5(this.sessionDir, `${sessionId}.jsonl`);
2902
2928
  let content;
2903
2929
  try {
2904
2930
  content = readFileSync(direct, "utf-8");
@@ -2907,7 +2933,7 @@ var PiSessionStore = class {
2907
2933
  (f) => f.endsWith(`_${sessionId}.jsonl`) || f === `${sessionId}.jsonl`
2908
2934
  );
2909
2935
  if (files.length === 0) return null;
2910
- content = readFileSync(join4(this.sessionDir, files[0]), "utf-8");
2936
+ content = readFileSync(join5(this.sessionDir, files[0]), "utf-8");
2911
2937
  }
2912
2938
  const entries = safeParseEntries(content);
2913
2939
  let piFilePath = null;
@@ -2975,7 +3001,7 @@ var PiSessionStore = class {
2975
3001
  if (!SAFE_ID.test(sessionId)) {
2976
3002
  throw new Error(`Session not found: ${sessionId}`);
2977
3003
  }
2978
- const direct = join4(this.sessionDir, `${sessionId}.jsonl`);
3004
+ const direct = join5(this.sessionDir, `${sessionId}.jsonl`);
2979
3005
  try {
2980
3006
  await fsStat(direct);
2981
3007
  return direct;
@@ -2986,7 +3012,7 @@ var PiSessionStore = class {
2986
3012
  (f) => f.endsWith(`_${sessionId}.jsonl`) || f === `${sessionId}.jsonl`
2987
3013
  );
2988
3014
  if (!match) throw new Error(`Session not found: ${sessionId}`);
2989
- return join4(this.sessionDir, match);
3015
+ return join5(this.sessionDir, match);
2990
3016
  }
2991
3017
  async summarizeFile(filepath) {
2992
3018
  try {
@@ -3913,11 +3939,11 @@ function createPiCodingAgentHarness(opts) {
3913
3939
 
3914
3940
  // src/server/harness/pi-coding-agent/pluginLoader.ts
3915
3941
  import { readdir as readdir5, stat as stat5, readFile as readFile7 } from "fs/promises";
3916
- import { join as join5, extname, resolve as resolve4, sep as sep3 } from "path";
3942
+ import { join as join6, extname, resolve as resolve4, sep as sep3 } from "path";
3917
3943
  import { homedir as homedir4 } from "os";
3918
3944
  import { pathToFileURL } from "url";
3919
3945
  var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs"]);
3920
- var GLOBAL_DIR = join5(homedir4(), ".pi", "agent", "extensions");
3946
+ var GLOBAL_DIR = join6(homedir4(), ".pi", "agent", "extensions");
3921
3947
  var LOCAL_DIR = ".pi/extensions";
3922
3948
  var EXTENSIONS_JSON = ".pi/extensions.json";
3923
3949
  async function dirExists(path4) {
@@ -3939,7 +3965,7 @@ async function fileExists2(path4) {
3939
3965
  async function discoverFromDir(dir, source) {
3940
3966
  if (!await dirExists(dir)) return [];
3941
3967
  const entries = await readdir5(dir);
3942
- return entries.filter((e) => VALID_EXTENSIONS.has(extname(e))).map((e) => ({ path: join5(dir, e), source }));
3968
+ return entries.filter((e) => VALID_EXTENSIONS.has(extname(e))).map((e) => ({ path: join6(dir, e), source }));
3943
3969
  }
3944
3970
  function extractTools(mod) {
3945
3971
  const tools = [];
@@ -3969,17 +3995,17 @@ async function loadModule(filePath, importFn) {
3969
3995
  return extractTools(mod);
3970
3996
  }
3971
3997
  async function discoverNpmPlugins(cwd) {
3972
- const nodeModulesDir = join5(cwd, "node_modules");
3998
+ const nodeModulesDir = join6(cwd, "node_modules");
3973
3999
  if (!await dirExists(nodeModulesDir)) return [];
3974
4000
  try {
3975
4001
  const entries = await readdir5(nodeModulesDir);
3976
- return entries.filter((e) => e.startsWith("pi-plugin-")).map((e) => join5(nodeModulesDir, e));
4002
+ return entries.filter((e) => e.startsWith("pi-plugin-")).map((e) => join6(nodeModulesDir, e));
3977
4003
  } catch {
3978
4004
  return [];
3979
4005
  }
3980
4006
  }
3981
4007
  async function loadNpmPlugin(pkgDir, importFn) {
3982
- const pkgJsonPath = join5(pkgDir, "package.json");
4008
+ const pkgJsonPath = join6(pkgDir, "package.json");
3983
4009
  if (!await fileExists2(pkgJsonPath)) return [];
3984
4010
  const pkgJson = JSON.parse(await readFile7(pkgJsonPath, "utf-8"));
3985
4011
  const main = pkgJson.main ?? "index.js";
@@ -3991,7 +4017,7 @@ async function loadNpmPlugin(pkgDir, importFn) {
3991
4017
  return loadModule(resolvedMain, importFn);
3992
4018
  }
3993
4019
  async function loadExtensionsJson(cwd) {
3994
- const configPath = join5(cwd, EXTENSIONS_JSON);
4020
+ const configPath = join6(cwd, EXTENSIONS_JSON);
3995
4021
  if (!await fileExists2(configPath)) return null;
3996
4022
  try {
3997
4023
  const raw = await readFile7(configPath, "utf-8");
@@ -4009,7 +4035,7 @@ async function loadPlugins(options) {
4009
4035
  const globals = await discoverFromDir(GLOBAL_DIR, "global");
4010
4036
  candidates.push(...globals);
4011
4037
  }
4012
- const localDir = join5(options.cwd, LOCAL_DIR);
4038
+ const localDir = join6(options.cwd, LOCAL_DIR);
4013
4039
  const locals = await discoverFromDir(localDir, "local");
4014
4040
  candidates.push(...locals);
4015
4041
  const npmDirs = await discoverNpmPlugins(options.cwd);
@@ -4019,7 +4045,7 @@ async function loadPlugins(options) {
4019
4045
  const config = await loadExtensionsJson(options.cwd);
4020
4046
  if (config?.npm) {
4021
4047
  for (const pkg of config.npm) {
4022
- const pkgDir = join5(options.cwd, "node_modules", pkg);
4048
+ const pkgDir = join6(options.cwd, "node_modules", pkg);
4023
4049
  if (await dirExists(pkgDir)) {
4024
4050
  const already = candidates.some((c) => c.path === pkgDir);
4025
4051
  if (!already) {
@@ -4067,9 +4093,9 @@ import {
4067
4093
  } from "@mariozechner/pi-coding-agent";
4068
4094
 
4069
4095
  // src/server/tools/operations/bound.ts
4070
- import { constants as constants2 } from "fs";
4071
- import { access as access2, lstat as lstat3, mkdir as mkdir9, readFile as readFile8, readdir as readdir6, readlink, realpath as realpath2, stat as stat6, writeFile as writeFile7 } from "fs/promises";
4072
- import { dirname as dirname5, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve5 } from "path";
4096
+ import { constants as constants3 } from "fs";
4097
+ import { access as access3, lstat as lstat3, mkdir as mkdir9, readFile as readFile8, readdir as readdir6, readlink, realpath as realpath2, stat as stat6, writeFile as writeFile7 } from "fs/promises";
4098
+ import { dirname as dirname6, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve5 } from "path";
4073
4099
  function toPosixPath(value) {
4074
4100
  return value.split("\\").join("/");
4075
4101
  }
@@ -4143,7 +4169,7 @@ async function findNearestExistingAncestor(absPath) {
4143
4169
  await stat6(current);
4144
4170
  return current;
4145
4171
  } catch {
4146
- const parent = dirname5(current);
4172
+ const parent = dirname6(current);
4147
4173
  if (parent === current) return current;
4148
4174
  current = parent;
4149
4175
  }
@@ -4155,7 +4181,7 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
4155
4181
  const s = await lstat3(absPath);
4156
4182
  if (s.isSymbolicLink()) {
4157
4183
  const target = await readlink(absPath);
4158
- const resolvedTarget = resolve5(dirname5(absPath), target);
4184
+ const resolvedTarget = resolve5(dirname6(absPath), target);
4159
4185
  const nearestAncestor = await findNearestExistingAncestor(resolvedTarget);
4160
4186
  const realAncestor = await realpath2(nearestAncestor);
4161
4187
  const rel2 = relative4(realRoot, realAncestor);
@@ -4177,7 +4203,7 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
4177
4203
  } catch (err) {
4178
4204
  const code = err.code;
4179
4205
  if (code === "ENOENT") {
4180
- const nearestAncestor = await findNearestExistingAncestor(dirname5(absPath));
4206
+ const nearestAncestor = await findNearestExistingAncestor(dirname6(absPath));
4181
4207
  const realAncestor = await realpath2(nearestAncestor);
4182
4208
  const rel2 = relative4(realRoot, realAncestor);
4183
4209
  if (rel2.startsWith("..") || isAbsolute4(rel2)) {
@@ -4200,13 +4226,13 @@ function boundFs(workspaceRoot) {
4200
4226
  },
4201
4227
  async access(absolutePath) {
4202
4228
  await assertWithinWorkspace(workspaceRoot, absolutePath);
4203
- await access2(absolutePath, constants2.R_OK);
4229
+ await access3(absolutePath, constants3.R_OK);
4204
4230
  }
4205
4231
  };
4206
4232
  const write = {
4207
4233
  async writeFile(absolutePath, content) {
4208
4234
  await assertWithinWorkspace(workspaceRoot, absolutePath);
4209
- await mkdir9(dirname5(absolutePath), { recursive: true });
4235
+ await mkdir9(dirname6(absolutePath), { recursive: true });
4210
4236
  await writeFile7(absolutePath, content);
4211
4237
  },
4212
4238
  async mkdir(dir) {
@@ -4225,7 +4251,7 @@ function boundFs(workspaceRoot) {
4225
4251
  },
4226
4252
  async access(absolutePath) {
4227
4253
  await assertWithinWorkspace(workspaceRoot, absolutePath);
4228
- await access2(absolutePath, constants2.R_OK | constants2.W_OK);
4254
+ await access3(absolutePath, constants3.R_OK | constants3.W_OK);
4229
4255
  }
4230
4256
  };
4231
4257
  const find = {
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.0",
3
+ "version": "0.1.5",
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.",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/hachej/boring-ui.git"
9
+ "url": "https://github.com/hachej/boring-ui"
10
10
  },
11
11
  "homepage": "https://github.com/hachej/boring-ui",
12
12
  "exports": {
@@ -74,7 +74,7 @@
74
74
  "use-stick-to-bottom": "^1.1.3",
75
75
  "yaml": "^2.8.3",
76
76
  "zod": "^3.25.76",
77
- "@hachej/boring-ui-kit": "0.1.0"
77
+ "@hachej/boring-ui-kit": "0.1.5"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@opentelemetry/api": "^1.9.1",