@hachej/boring-agent 0.1.80 → 0.1.82

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.
@@ -3,16 +3,18 @@ import {
3
3
  AgentDeploymentValidationError,
4
4
  OpaqueRefSchema,
5
5
  Sha256DigestSchema,
6
+ canonicalStringify,
6
7
  createAgentAssetDigest,
7
8
  createAgentDefinitionDigest,
8
9
  createAgentDeploymentDigest,
10
+ sha256Bytes,
9
11
  validateAgentDefinition,
10
12
  validateAgentDeployment,
11
13
  validateTool
12
- } from "./chunk-CUF7ELFO.js";
14
+ } from "./chunk-WODTQBXR.js";
13
15
  import {
14
16
  createAgentRuntimeBridge
15
- } from "./chunk-BNZIE26N.js";
17
+ } from "./chunk-TNN3LPXE.js";
16
18
  import {
17
19
  sessionStreamPath
18
20
  } from "./chunk-WSQ5QNIY.js";
@@ -27,7 +29,7 @@ import {
27
29
  StopReceiptSchema,
28
30
  extractToolUiMetadata,
29
31
  sanitizeToolUiMetadata2 as sanitizeToolUiMetadata
30
- } from "./chunk-UJQXCOHR.js";
32
+ } from "./chunk-DC3S7SZG.js";
31
33
  import {
32
34
  createLogger,
33
35
  createPiCodingAgentHarness,
@@ -38,7 +40,7 @@ import {
38
40
  registerConfiguredModelProviders,
39
41
  setEnvDefault,
40
42
  withPiHarnessDefaults
41
- } from "./chunk-N4ES6PVX.js";
43
+ } from "./chunk-5NAN3TAR.js";
42
44
  import {
43
45
  safeCapture
44
46
  } from "./chunk-AQBXNPMD.js";
@@ -46,7 +48,7 @@ import {
46
48
  AgentDefinitionErrorCode,
47
49
  AgentDeploymentErrorCode,
48
50
  ErrorCode
49
- } from "./chunk-CCNXYCD5.js";
51
+ } from "./chunk-PG2WOJ22.js";
50
52
 
51
53
  // src/server/sandbox/direct/createDirectSandbox.ts
52
54
  import { spawn } from "child_process";
@@ -186,7 +188,7 @@ function createDirectSandbox(opts = {}) {
186
188
  const maxOutputBytes = opts2?.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
187
189
  const workspaceRoot = runtimeContext.runtimeCwd;
188
190
  const cwd = opts2?.cwd ?? workspaceRoot;
189
- return await new Promise((resolve12, reject) => {
191
+ return await new Promise((resolve13, reject) => {
190
192
  const child = spawn(cmd, {
191
193
  cwd,
192
194
  env: withWorkspacePythonEnv({ workspaceRoot, env: opts2?.env, preserveHostHome: true }),
@@ -215,7 +217,7 @@ function createDirectSandbox(opts = {}) {
215
217
  if (settled) return;
216
218
  settled = true;
217
219
  cleanup();
218
- resolve12({
220
+ resolve13({
219
221
  stdout: new Uint8Array(Buffer.concat(stdoutChunks)),
220
222
  stderr: new Uint8Array(Buffer.concat(stderrChunks)),
221
223
  exitCode: typeof exitCode === "number" ? exitCode : timedOut ? 124 : 1,
@@ -564,9 +566,9 @@ function createNodeWatcher(root) {
564
566
  }
565
567
  startFsw();
566
568
  if (fsw) {
567
- await new Promise((resolve12) => {
568
- fsw.once("ready", resolve12);
569
- fsw.once("error", () => resolve12());
569
+ await new Promise((resolve13) => {
570
+ fsw.once("ready", resolve13);
571
+ fsw.once("error", () => resolve13());
570
572
  });
571
573
  }
572
574
  if (closed) return { ok: false, reason: "closed" };
@@ -975,7 +977,7 @@ function createBwrapSandbox(opts = {}) {
975
977
  ...withSandboxCwd(baseArgs, sandboxCwd),
976
978
  ...buildCommandArgs(cmd, sandboxOptions.resourceLimits)
977
979
  ];
978
- return await new Promise((resolve12, reject) => {
980
+ return await new Promise((resolve13, reject) => {
979
981
  const child = spawn2("bwrap", args, {
980
982
  env: {
981
983
  ...withWorkspacePythonEnv({ workspaceRoot, env: opts2?.env, sandboxRoot: SANDBOX_HOME2 }),
@@ -1005,7 +1007,7 @@ function createBwrapSandbox(opts = {}) {
1005
1007
  if (settled) return;
1006
1008
  settled = true;
1007
1009
  cleanup();
1008
- resolve12({
1010
+ resolve13({
1009
1011
  stdout: new Uint8Array(Buffer.concat(stdoutChunks)),
1010
1012
  stderr: new Uint8Array(Buffer.concat(stderrChunks)),
1011
1013
  exitCode: typeof exitCode === "number" ? exitCode : timedOut ? 124 : 1,
@@ -2295,7 +2297,8 @@ function createRemoteWorkerModeAdapter(opts = {}) {
2295
2297
  }
2296
2298
 
2297
2299
  // src/server/http/routes/file.ts
2298
- import { dirname as dirname5, extname as extname2, relative as relative4 } from "path/posix";
2300
+ import { dirname as dirname5, extname as extname2, relative as relative5 } from "path/posix";
2301
+ import { getAgentDir } from "@mariozechner/pi-coding-agent";
2299
2302
 
2300
2303
  // src/server/http/middleware.ts
2301
2304
  var ERROR_CODE_AUTH_REQUIRED = "auth_required";
@@ -2568,13 +2571,33 @@ function buildFileRecordsResult(args) {
2568
2571
 
2569
2572
  // src/server/http/readonlySkillFiles.ts
2570
2573
  import { readFile as readFile4, stat as stat4 } from "fs/promises";
2574
+ import { isAbsolute as isAbsolute4, relative as relative4, resolve as resolve5 } from "path";
2571
2575
  function isReadonlySkillFilePath(path4) {
2572
2576
  if (!path4.startsWith("/")) return false;
2573
2577
  if (path4.includes("\0")) return false;
2574
2578
  if (!path4.endsWith("/SKILL.md")) return false;
2579
+ if (path4.split("/").some((segment) => segment === "..")) return false;
2575
2580
  return path4.includes("/.pi/agent/") && path4.includes("/skills/");
2576
2581
  }
2577
- async function readReadonlySkillFile(path4) {
2582
+ function isLexicallyInside(root, resolvedPath) {
2583
+ if (!root) return false;
2584
+ const rel = relative4(resolve5(root), resolvedPath);
2585
+ return !rel.startsWith("..") && !isAbsolute4(rel);
2586
+ }
2587
+ async function assertReadonlySkillFileConfined(path4, allowedRoots) {
2588
+ const resolved = resolve5(path4);
2589
+ const lexicalRoot = allowedRoots.find((root) => isLexicallyInside(root, resolved));
2590
+ if (!lexicalRoot) {
2591
+ throw Object.assign(new Error("read-only skill file escapes allowed roots"), {
2592
+ statusCode: 403,
2593
+ reason: "path-escape",
2594
+ requestedPath: path4
2595
+ });
2596
+ }
2597
+ await assertRealPathWithinWorkspace(lexicalRoot, resolved);
2598
+ }
2599
+ async function readReadonlySkillFile(path4, allowedRoots) {
2600
+ await assertReadonlySkillFileConfined(path4, allowedRoots);
2578
2601
  const [content, fsStat] = await Promise.all([
2579
2602
  readFile4(path4, "utf-8"),
2580
2603
  stat4(path4)
@@ -2588,7 +2611,8 @@ async function readReadonlySkillFile(path4) {
2588
2611
  }
2589
2612
  };
2590
2613
  }
2591
- async function statReadonlySkillFile(path4) {
2614
+ async function statReadonlySkillFile(path4, allowedRoots) {
2615
+ await assertReadonlySkillFileConfined(path4, allowedRoots);
2592
2616
  const fsStat = await stat4(path4);
2593
2617
  return {
2594
2618
  kind: fsStat.isDirectory() ? "directory" : "file",
@@ -2681,6 +2705,9 @@ function classifyError(err, reply, subject) {
2681
2705
  function requestedFilesystem(value) {
2682
2706
  return typeof value === "string" && value.length > 0 ? value : USER_FILESYSTEM_ID;
2683
2707
  }
2708
+ function readonlySkillRoots(workspace) {
2709
+ return [workspace.root, getAgentDir()];
2710
+ }
2684
2711
  function sendNotFoundOrDenied(reply) {
2685
2712
  return reply.code(404).send({
2686
2713
  error: { code: ERROR_CODE_NOT_FOUND_OR_DENIED, message: "not found or denied" }
@@ -2752,7 +2779,7 @@ function basenameForUpload(filename) {
2752
2779
  function markdownUrlFor(sourcePath, assetPath) {
2753
2780
  if (!sourcePath) return assetPath;
2754
2781
  const fromDir = dirname5(sourcePath.replace(/\\/g, "/"));
2755
- const rel = relative4(fromDir === "." ? "" : fromDir, assetPath);
2782
+ const rel = relative5(fromDir === "." ? "" : fromDir, assetPath);
2756
2783
  return rel && !rel.startsWith(".") ? rel : rel || assetPath;
2757
2784
  }
2758
2785
  function contentTypeForPath(path4) {
@@ -2905,8 +2932,9 @@ function fileRoutes(app, opts, done) {
2905
2932
  }
2906
2933
  }
2907
2934
  try {
2935
+ const workspace = await resolveWorkspace(request);
2908
2936
  if (isReadonlySkillFilePath(path4)) {
2909
- const { content: content2, stat: stat14 } = await readReadonlySkillFile(path4);
2937
+ const { content: content2, stat: stat14 } = await readReadonlySkillFile(path4, readonlySkillRoots(workspace));
2910
2938
  if (stat14.kind !== "file") {
2911
2939
  return reply.code(400).send({
2912
2940
  error: { code: ERROR_CODE_VALIDATION_ERROR, message: "path is not a file", field: "path" }
@@ -2914,7 +2942,6 @@ function fileRoutes(app, opts, done) {
2914
2942
  }
2915
2943
  return { content: content2, mtimeMs: stat14.mtimeMs };
2916
2944
  }
2917
- const workspace = await resolveWorkspace(request);
2918
2945
  if (workspace.readFileWithStat) {
2919
2946
  const { content: content2, stat: stat14 } = await workspace.readFileWithStat(path4);
2920
2947
  return { content: content2, mtimeMs: stat14.kind === "file" ? stat14.mtimeMs : void 0, access: "readwrite" };
@@ -3184,10 +3211,10 @@ function fileRoutes(app, opts, done) {
3184
3211
  }
3185
3212
  }
3186
3213
  try {
3214
+ const workspace = await resolveWorkspace(request);
3187
3215
  if (isReadonlySkillFilePath(path4)) {
3188
- return await statReadonlySkillFile(path4);
3216
+ return await statReadonlySkillFile(path4, readonlySkillRoots(workspace));
3189
3217
  }
3190
- const workspace = await resolveWorkspace(request);
3191
3218
  const stat13 = await workspace.stat(path4);
3192
3219
  return stat13;
3193
3220
  } catch (err) {
@@ -3201,7 +3228,7 @@ function fileRoutes(app, opts, done) {
3201
3228
  import { createHash as createHash3 } from "crypto";
3202
3229
  import { constants as constants2 } from "fs";
3203
3230
  import { access as access2, chmod as chmod3, cp, mkdir as mkdir4, readdir as readdir3, readFile as readFile5, realpath as realpath2, stat as stat5, writeFile as writeFile4 } from "fs/promises";
3204
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join4, relative as relative5, resolve as resolve5 } from "path";
3231
+ import { dirname as dirname6, isAbsolute as isAbsolute5, join as join4, relative as relative6, resolve as resolve6 } from "path";
3205
3232
  import { fileURLToPath } from "url";
3206
3233
  import { execFile } from "child_process";
3207
3234
  import { promisify } from "util";
@@ -3310,10 +3337,10 @@ function resolveTemplateTarget(workspaceRoot, target) {
3310
3337
  if (rawTarget.length === 0 || rawTarget.includes("\0") || rawTarget.includes("\\") || rawTarget.startsWith("/") || rawTarget.startsWith("//") || /^[A-Za-z]:[\\/]/.test(rawTarget) || rawTarget.split("/").includes("..")) {
3311
3338
  throw new Error(`Unsafe runtime template target: ${JSON.stringify(rawTarget)}. Template targets must be relative paths inside the workspace.`);
3312
3339
  }
3313
- const root = resolve5(workspaceRoot);
3314
- const resolved = resolve5(root, rawTarget);
3315
- const rel = relative5(root, resolved);
3316
- if (rel.startsWith("..") || isAbsolute4(rel)) {
3340
+ const root = resolve6(workspaceRoot);
3341
+ const resolved = resolve6(root, rawTarget);
3342
+ const rel = relative6(root, resolved);
3343
+ if (rel.startsWith("..") || isAbsolute5(rel)) {
3317
3344
  throw new Error(`Unsafe runtime template target: ${JSON.stringify(rawTarget)} resolves outside the workspace.`);
3318
3345
  }
3319
3346
  return resolved;
@@ -3338,7 +3365,7 @@ function nodePackageTarget(workspaceRoot, packageName) {
3338
3365
  }
3339
3366
  async function copyIfExists(source, target) {
3340
3367
  if (!await exists(source)) return false;
3341
- if (resolve5(source) === resolve5(target)) return true;
3368
+ if (resolve6(source) === resolve6(target)) return true;
3342
3369
  if (await exists(target) && await realpath2(source) === await realpath2(target)) return true;
3343
3370
  await cp(source, target, {
3344
3371
  recursive: true,
@@ -3899,7 +3926,7 @@ function createVercelSandboxWorkspace(sandbox, workspaceOpts = {}) {
3899
3926
  // src/server/workspace/provisioning/packArtifact.ts
3900
3927
  import { execFile as execFile2 } from "child_process";
3901
3928
  import { mkdir as mkdir5, mkdtemp, rename as rename4 } from "fs/promises";
3902
- import { dirname as dirname7, isAbsolute as isAbsolute5, join as join5 } from "path";
3929
+ import { dirname as dirname7, isAbsolute as isAbsolute6, join as join5 } from "path";
3903
3930
  import { tmpdir } from "os";
3904
3931
  import { fileURLToPath as fileURLToPath2 } from "url";
3905
3932
  import { promisify as promisify2 } from "util";
@@ -3944,7 +3971,7 @@ async function packProvisioningArtifact(request) {
3944
3971
  ], { maxBuffer: 1024 * 1024 * 20 });
3945
3972
  const packedName = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
3946
3973
  if (!packedName) throw new Error(`pnpm pack produced no artifact for ${sourcePath}`);
3947
- const packedPath = isAbsolute5(packedName) ? packedName : join5(dirname7(request.outputPath), packedName);
3974
+ const packedPath = isAbsolute6(packedName) ? packedName : join5(dirname7(request.outputPath), packedName);
3948
3975
  await rename4(packedPath, request.outputPath);
3949
3976
  return;
3950
3977
  }
@@ -4074,7 +4101,7 @@ function createPythonRuntimeFingerprint(input) {
4074
4101
  }
4075
4102
 
4076
4103
  // src/server/workspace/provisioning/node.ts
4077
- import { join as join6, relative as relative6, sep as sep3 } from "path";
4104
+ import { join as join6, relative as relative7, sep as sep3 } from "path";
4078
4105
  var NODE_RUNTIME_REL = ".boring-agent/node";
4079
4106
  var NODE_PACKAGE_JSON_REL = `${NODE_RUNTIME_REL}/package.json`;
4080
4107
  var NODE_FINGERPRINT_REL = `${NODE_RUNTIME_REL}/.fingerprint`;
@@ -4119,7 +4146,7 @@ function expectedNodeOutputs(paths, packages) {
4119
4146
  ];
4120
4147
  }
4121
4148
  function toWorkspaceRel(paths, absolutePath) {
4122
- return relative6(paths.workspaceRoot, absolutePath).split(sep3).join("/");
4149
+ return relative7(paths.workspaceRoot, absolutePath).split(sep3).join("/");
4123
4150
  }
4124
4151
  async function shouldInstallNodeRuntime(options) {
4125
4152
  const currentFingerprint = (await options.adapter.workspaceFs.readText(NODE_FINGERPRINT_REL))?.trim();
@@ -4205,7 +4232,7 @@ async function ensureNodeRuntime(options) {
4205
4232
  }
4206
4233
 
4207
4234
  // src/server/workspace/provisioning/python.ts
4208
- import { dirname as dirname9, join as join7, relative as relative7, sep as sep4 } from "path";
4235
+ import { dirname as dirname9, join as join7, relative as relative8, sep as sep4 } from "path";
4209
4236
  import { fileURLToPath as fileURLToPath3 } from "url";
4210
4237
  var VENV_REL = ".boring-agent/venv";
4211
4238
  var VENV_FINGERPRINT_REL = `${VENV_REL}/.fingerprint`;
@@ -4298,7 +4325,7 @@ function collectPythonEnv(packages) {
4298
4325
  return env;
4299
4326
  }
4300
4327
  function toWorkspaceRel2(paths, absolutePath) {
4301
- return relative7(paths.workspaceRoot, absolutePath).split(sep4).join("/");
4328
+ return relative8(paths.workspaceRoot, absolutePath).split(sep4).join("/");
4302
4329
  }
4303
4330
  async function shouldInstallPythonRuntime(options) {
4304
4331
  const currentFingerprint = (await options.adapter.workspaceFs.readText(VENV_FINGERPRINT_REL))?.trim();
@@ -4764,7 +4791,7 @@ async function copyTemplate(templatePath, workspaceRoot) {
4764
4791
  // src/server/runtime/modes/provisioningAdapter.ts
4765
4792
  import { spawn as spawn3 } from "child_process";
4766
4793
  import { cp as cp3, lstat as lstat3, mkdir as mkdir7, readFile as readFile7, realpath as realpath3, rm as rm3, stat as stat8, writeFile as writeFile5 } from "fs/promises";
4767
- import { dirname as dirname10, isAbsolute as isAbsolute6, relative as relative8, resolve as resolve6, sep as sep5 } from "path";
4794
+ import { dirname as dirname10, isAbsolute as isAbsolute7, relative as relative9, resolve as resolve7, sep as sep5 } from "path";
4768
4795
  import { fileURLToPath as fileURLToPath6 } from "url";
4769
4796
  var LOCAL_SANDBOX_WORKSPACE_ROOT = "/workspace";
4770
4797
  function sourceToPath4(source) {
@@ -4852,8 +4879,8 @@ function defaultExecOptions(paths, opts) {
4852
4879
  };
4853
4880
  }
4854
4881
  function mapWorkspacePathToLocalSandbox(paths, value) {
4855
- const absolute = isAbsolute6(value) ? value : resolve6(paths.workspaceRoot, value);
4856
- const relPath = relative8(paths.workspaceRoot, absolute);
4882
+ const absolute = isAbsolute7(value) ? value : resolve7(paths.workspaceRoot, value);
4883
+ const relPath = relative9(paths.workspaceRoot, absolute);
4857
4884
  if (relPath === "") return LOCAL_SANDBOX_WORKSPACE_ROOT;
4858
4885
  if (relPath === ".." || relPath.startsWith(`..${sep5}`)) return value;
4859
4886
  return `${LOCAL_SANDBOX_WORKSPACE_ROOT}/${relPath.split(sep5).join("/")}`;
@@ -4957,9 +4984,9 @@ function createLocalProvisioningAdapter(paths, runner = spawnCommand) {
4957
4984
  const hostPath = sourceToPath4(source);
4958
4985
  const realWorkspaceRoot = await realpath3(paths.workspaceRoot);
4959
4986
  const realSource = await realpath3(hostPath);
4960
- const relPath = relative8(realWorkspaceRoot, realSource);
4987
+ const relPath = relative9(realWorkspaceRoot, realSource);
4961
4988
  if (relPath === "") return LOCAL_SANDBOX_WORKSPACE_ROOT;
4962
- if (!relPath.startsWith("..") && !isAbsolute6(relPath)) {
4989
+ if (!relPath.startsWith("..") && !isAbsolute7(relPath)) {
4963
4990
  return `${LOCAL_SANDBOX_WORKSPACE_ROOT}/${relPath.split(sep5).join("/")}`;
4964
4991
  }
4965
4992
  return await resolveArtifactInstallSource({
@@ -5248,11 +5275,11 @@ async function buildTarGz(files) {
5248
5275
  }
5249
5276
  chunks.push(Buffer.alloc(1024));
5250
5277
  const tarBuffer = Buffer.concat(chunks);
5251
- return new Promise((resolve12, reject) => {
5278
+ return new Promise((resolve13, reject) => {
5252
5279
  const gzip = createGzip({ level: 6 });
5253
5280
  const gzChunks = [];
5254
5281
  gzip.on("data", (chunk) => gzChunks.push(chunk));
5255
- gzip.on("end", () => resolve12(Buffer.concat(gzChunks)));
5282
+ gzip.on("end", () => resolve13(Buffer.concat(gzChunks)));
5256
5283
  gzip.on("error", reject);
5257
5284
  Readable.from(tarBuffer).pipe(gzip);
5258
5285
  });
@@ -7612,11 +7639,11 @@ function bindingDisposedError() {
7612
7639
  });
7613
7640
  }
7614
7641
  function deferred() {
7615
- let resolve12;
7642
+ let resolve13;
7616
7643
  const promise = new Promise((nextResolve) => {
7617
- resolve12 = () => nextResolve();
7644
+ resolve13 = () => nextResolve();
7618
7645
  });
7619
- return { promise, resolve: resolve12 };
7646
+ return { promise, resolve: resolve13 };
7620
7647
  }
7621
7648
 
7622
7649
  // src/server/pi-chat/harnessPiChatService.ts
@@ -8290,13 +8317,13 @@ function promptCancelledError() {
8290
8317
  });
8291
8318
  }
8292
8319
  function deferred2() {
8293
- let resolve12;
8320
+ let resolve13;
8294
8321
  let reject;
8295
8322
  const promise = new Promise((nextResolve, nextReject) => {
8296
- resolve12 = nextResolve;
8323
+ resolve13 = nextResolve;
8297
8324
  reject = nextReject;
8298
8325
  });
8299
- return { promise, resolve: resolve12, reject };
8326
+ return { promise, resolve: resolve13, reject };
8300
8327
  }
8301
8328
  function rejectedReasons(results) {
8302
8329
  return results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
@@ -8457,7 +8484,7 @@ function createAgentRuntimeBridge2(config, options = {}) {
8457
8484
  });
8458
8485
  }
8459
8486
  async function createRuntime(config, options) {
8460
- const harnessFactory = config.harnessFactory ?? (await import("./createHarness-EEA63XRC.js")).createPiCodingAgentHarness;
8487
+ const harnessFactory = config.harnessFactory ?? (await import("./createHarness-TGBJZISM.js")).createPiCodingAgentHarness;
8461
8488
  const harnessInput = {
8462
8489
  tools: config.tools ?? [],
8463
8490
  cwd: config.workdir ?? DEFAULT_WORKDIR,
@@ -8497,7 +8524,7 @@ function stableAgentError(code, message) {
8497
8524
  // src/server/agentDefinition/compileAgentDirectory.ts
8498
8525
  import { constants as constants4 } from "fs";
8499
8526
  import { open as open2, realpath as realpath4, stat as stat10 } from "fs/promises";
8500
- import { isAbsolute as isAbsolute7, relative as relative9, resolve as resolve7, sep as sep6 } from "path";
8527
+ import { isAbsolute as isAbsolute8, relative as relative10, resolve as resolve8, sep as sep6 } from "path";
8501
8528
  var AGENT_MANIFEST = "agent.json";
8502
8529
  var AGENT_INSTRUCTIONS = "instructions.md";
8503
8530
  var AgentDirectoryCompilerError = class extends Error {
@@ -8516,8 +8543,8 @@ function isNotFound(error) {
8516
8543
  return error?.code === "ENOENT";
8517
8544
  }
8518
8545
  function isInsideRoot(root, target) {
8519
- const pathFromRoot = relative9(root, target);
8520
- return pathFromRoot === "" || pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep6}`) && !isAbsolute7(pathFromRoot);
8546
+ const pathFromRoot = relative10(root, target);
8547
+ return pathFromRoot === "" || pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep6}`) && !isAbsolute8(pathFromRoot);
8521
8548
  }
8522
8549
  async function resolveAgentRoot(directory) {
8523
8550
  if (typeof directory !== "string" || directory.length === 0) {
@@ -8530,7 +8557,7 @@ async function resolveAgentRoot(directory) {
8530
8557
  }
8531
8558
  let root;
8532
8559
  try {
8533
- root = await realpath4(resolve7(directory));
8560
+ root = await realpath4(resolve8(directory));
8534
8561
  } catch (error) {
8535
8562
  throw new AgentDirectoryCompilerError({
8536
8563
  code: isNotFound(error) ? ErrorCode.enum.PATH_NOT_FOUND : ErrorCode.enum.CONFIG_INVALID,
@@ -8567,7 +8594,7 @@ async function readContainedFile({
8567
8594
  field,
8568
8595
  kind
8569
8596
  }) {
8570
- const candidate = resolve7(root, path4);
8597
+ const candidate = resolve8(root, path4);
8571
8598
  if (!isInsideRoot(root, candidate)) {
8572
8599
  throw new AgentDirectoryCompilerError({
8573
8600
  code: ErrorCode.enum.PATH_SYMLINK_ESCAPE,
@@ -8717,6 +8744,22 @@ var AuthorizedAgentDeploymentBindingSchema = z.object({
8717
8744
  workspaceCompositionDigest: Sha256DigestSchema
8718
8745
  });
8719
8746
  var RESOLVED_AGENT_DIGEST_DOMAIN = "boring-agent/resolved-agent:v1";
8747
+ var ResolvedAgentDigestInputSchema = z.object({
8748
+ workspaceId: OpaqueRefSchema,
8749
+ defaultDeploymentId: OpaqueRefSchema,
8750
+ workspaceCompositionDigest: Sha256DigestSchema,
8751
+ definitionDigest: Sha256DigestSchema,
8752
+ deploymentDigest: Sha256DigestSchema
8753
+ }).strict();
8754
+ async function createResolvedAgentDigest(input) {
8755
+ const parsed = ResolvedAgentDigestInputSchema.safeParse(input);
8756
+ if (!parsed.success) {
8757
+ const field = parsed.error.issues[0]?.path[0];
8758
+ const digestField = typeof field === "string" ? field : "workspaceId";
8759
+ throw invalidDeployment(digestField, `${digestField} is invalid`);
8760
+ }
8761
+ return createAgentAssetDigest(canonicalStringify({ domain: RESOLVED_AGENT_DIGEST_DOMAIN, ...parsed.data }));
8762
+ }
8720
8763
  function invalidDefinition(field, message) {
8721
8764
  return new AgentDefinitionValidationError({
8722
8765
  code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
@@ -8791,14 +8834,13 @@ async function resolveAgentDeployment(bundle, deployment, authorizedBinding) {
8791
8834
  "instructionsRef must name an included verified asset"
8792
8835
  );
8793
8836
  }
8794
- const resolvedDigest = await createAgentAssetDigest(JSON.stringify({
8795
- domain: RESOLVED_AGENT_DIGEST_DOMAIN,
8837
+ const resolvedDigest = await createResolvedAgentDigest({
8796
8838
  workspaceId: binding.workspaceId,
8797
8839
  defaultDeploymentId: binding.defaultDeploymentId,
8798
8840
  workspaceCompositionDigest: binding.workspaceCompositionDigest,
8799
8841
  definitionDigest,
8800
8842
  deploymentDigest
8801
- }));
8843
+ });
8802
8844
  const workspace = Object.freeze({
8803
8845
  workspaceId: binding.workspaceId,
8804
8846
  defaultDeploymentId: binding.defaultDeploymentId,
@@ -8830,7 +8872,7 @@ async function resolveAgentDeployment(bundle, deployment, authorizedBinding) {
8830
8872
  }
8831
8873
 
8832
8874
  // src/server/mcp/managedAgentDelegate.ts
8833
- import { createHash as createHash6, randomUUID } from "crypto";
8875
+ import { randomUUID } from "crypto";
8834
8876
  var MANAGED_AGENT_MCP_ORIGIN_SURFACE = "mcp-managed-agent";
8835
8877
  var MANAGED_AGENT_MCP_DELIVERY_RULE = "M1 DELIVERY v0: delegate_task returns bounded final assistant text and at most one complete authorized inline Markdown artifact; no artifact paths, truncation, or share-link delivery.";
8836
8878
  var MAX_FINAL_ASSISTANT_TEXT_BYTES = 96 * 1024;
@@ -9326,7 +9368,7 @@ async function resolveMarkdownArtifact(candidate, workspace) {
9326
9368
  validateMarkdownContent(content);
9327
9369
  const artifact = {
9328
9370
  content,
9329
- sha256: sha256(bytes),
9371
+ sha256: await sha256Bytes(bytes),
9330
9372
  byteSize,
9331
9373
  mediaType: MARKDOWN_MEDIA_TYPE,
9332
9374
  ...candidate.title ? { title: candidate.title } : {}
@@ -9419,9 +9461,6 @@ function validateMarkdownContent(content) {
9419
9461
  function sameStat(left, right) {
9420
9462
  return left.kind === right.kind && left.size === right.size && left.mtimeMs === right.mtimeMs;
9421
9463
  }
9422
- function sha256(bytes) {
9423
- return `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
9424
- }
9425
9464
  function safeDecodeArtifactPath(path4) {
9426
9465
  try {
9427
9466
  return decodeURIComponent(path4);
@@ -9586,13 +9625,13 @@ function resultTool(result) {
9586
9625
  };
9587
9626
  }
9588
9627
  function deferred3() {
9589
- let resolve12;
9628
+ let resolve13;
9590
9629
  let reject;
9591
9630
  const promise = new Promise((res, rej) => {
9592
- resolve12 = res;
9631
+ resolve13 = res;
9593
9632
  reject = rej;
9594
9633
  });
9595
- return { promise, resolve: resolve12, reject };
9634
+ return { promise, resolve: resolve13, reject };
9596
9635
  }
9597
9636
  function errorTool(error) {
9598
9637
  const safe = safeError(error);
@@ -9659,7 +9698,7 @@ function withRuntimeEnvContributions(runtimeBundle, baseContext, contributions,
9659
9698
 
9660
9699
  // src/server/harness/pi-coding-agent/pluginLoader.ts
9661
9700
  import { readdir as readdir7, stat as stat11, readFile as readFile10 } from "fs/promises";
9662
- import { join as join10, extname as extname3, resolve as resolve8, sep as sep7, relative as relative10 } from "path";
9701
+ import { join as join10, extname as extname3, resolve as resolve9, sep as sep7, relative as relative11 } from "path";
9663
9702
  import { homedir as homedir3 } from "os";
9664
9703
  import { pathToFileURL as pathToFileURL2 } from "url";
9665
9704
  var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs"]);
@@ -9729,12 +9768,12 @@ async function loadNpmPlugin(pkgDir, importFn) {
9729
9768
  if (!await fileExists(pkgJsonPath)) return [];
9730
9769
  const pkgJson = JSON.parse(await readFile10(pkgJsonPath, "utf-8"));
9731
9770
  const main = pkgJson.main ?? "index.js";
9732
- const resolvedMain = resolve8(pkgDir, main);
9733
- const resolvedPkgDir = resolve8(pkgDir);
9771
+ const resolvedMain = resolve9(pkgDir, main);
9772
+ const resolvedPkgDir = resolve9(pkgDir);
9734
9773
  if (resolvedMain !== resolvedPkgDir && !resolvedMain.startsWith(resolvedPkgDir + sep7)) {
9735
9774
  return [];
9736
9775
  }
9737
- const relPath = relative10(resolvedPkgDir, resolvedMain);
9776
+ const relPath = relative11(resolvedPkgDir, resolvedMain);
9738
9777
  if (relPath.startsWith("..")) {
9739
9778
  return [];
9740
9779
  }
@@ -9819,7 +9858,7 @@ import {
9819
9858
  // src/server/tools/operations/bound.ts
9820
9859
  import { constants as constants5 } from "fs";
9821
9860
  import { access as access4, lstat as lstat4, mkdir as mkdir11, readFile as readFile11, readdir as readdir8, readlink, realpath as realpath5, stat as stat12, writeFile as writeFile6 } from "fs/promises";
9822
- import { dirname as dirname11, isAbsolute as isAbsolute8, join as join11, relative as relative11, resolve as resolve9 } from "path";
9861
+ import { dirname as dirname11, isAbsolute as isAbsolute9, join as join11, relative as relative12, resolve as resolve10 } from "path";
9823
9862
  function toPosixPath(value) {
9824
9863
  return value.split("\\").join("/");
9825
9864
  }
@@ -9875,8 +9914,8 @@ async function walkMatches(root, current, pattern, ignore, limit, out) {
9875
9914
  const entries = await readdir8(current, { withFileTypes: true });
9876
9915
  for (const entry of entries) {
9877
9916
  if (out.length >= limit) return;
9878
- const absolutePath = resolve9(current, entry.name);
9879
- const relativePath = toPosixPath(relative11(root, absolutePath));
9917
+ const absolutePath = resolve10(current, entry.name);
9918
+ const relativePath = toPosixPath(relative12(root, absolutePath));
9880
9919
  if (entry.isDirectory() && shouldSkipDir(relativePath, ignore)) continue;
9881
9920
  if (matchesGlob(relativePath, pattern)) {
9882
9921
  out.push(absolutePath);
@@ -9900,16 +9939,16 @@ async function findNearestExistingAncestor(absPath) {
9900
9939
  }
9901
9940
  }
9902
9941
  async function assertWithinWorkspace(workspaceRoot, absPath) {
9903
- const realRoot = await realpath5(resolve9(workspaceRoot));
9942
+ const realRoot = await realpath5(resolve10(workspaceRoot));
9904
9943
  try {
9905
9944
  const s = await lstat4(absPath);
9906
9945
  if (s.isSymbolicLink()) {
9907
9946
  const target = await readlink(absPath);
9908
- const resolvedTarget = resolve9(dirname11(absPath), target);
9947
+ const resolvedTarget = resolve10(dirname11(absPath), target);
9909
9948
  const nearestAncestor = await findNearestExistingAncestor(resolvedTarget);
9910
9949
  const realAncestor = await realpath5(nearestAncestor);
9911
- const rel2 = relative11(realRoot, realAncestor);
9912
- if (rel2.startsWith("..") || isAbsolute8(rel2)) {
9950
+ const rel2 = relative12(realRoot, realAncestor);
9951
+ if (rel2.startsWith("..") || isAbsolute9(rel2)) {
9913
9952
  throw new Error(`path "${absPath}" is outside workspace`);
9914
9953
  }
9915
9954
  return;
@@ -9929,16 +9968,16 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
9929
9968
  if (code === "ENOENT") {
9930
9969
  const nearestAncestor = await findNearestExistingAncestor(dirname11(absPath));
9931
9970
  const realAncestor = await realpath5(nearestAncestor);
9932
- const rel2 = relative11(realRoot, realAncestor);
9933
- if (rel2.startsWith("..") || isAbsolute8(rel2)) {
9971
+ const rel2 = relative12(realRoot, realAncestor);
9972
+ if (rel2.startsWith("..") || isAbsolute9(rel2)) {
9934
9973
  throw new Error(`path "${absPath}" is outside workspace`);
9935
9974
  }
9936
9975
  return;
9937
9976
  }
9938
9977
  throw err;
9939
9978
  }
9940
- const rel = relative11(realRoot, realCandidate);
9941
- if (rel.startsWith("..") || isAbsolute8(rel)) {
9979
+ const rel = relative12(realRoot, realCandidate);
9980
+ if (rel.startsWith("..") || isAbsolute9(rel)) {
9942
9981
  throw new Error(`path "${absPath}" is outside workspace`);
9943
9982
  }
9944
9983
  }
@@ -9956,9 +9995,9 @@ function boundFs(workspaceRoot, opts = {}) {
9956
9995
  };
9957
9996
  const toRuntimePath = (absolutePath) => {
9958
9997
  if (!shouldMapRuntimeRoot || !runtimeRoot) return absolutePath;
9959
- const rel = relative11(workspaceRoot, absolutePath);
9998
+ const rel = relative12(workspaceRoot, absolutePath);
9960
9999
  if (rel === "") return runtimeRoot;
9961
- if (rel.startsWith("..") || isAbsolute8(rel)) return absolutePath;
10000
+ if (rel.startsWith("..") || isAbsolute9(rel)) return absolutePath;
9962
10001
  return `${runtimeRoot}/${toPosixPath(rel)}`;
9963
10002
  };
9964
10003
  const read = {
@@ -10070,7 +10109,7 @@ import {
10070
10109
  } from "@mariozechner/pi-coding-agent";
10071
10110
 
10072
10111
  // src/server/tools/operations/remoteWorkspace.ts
10073
- import { isAbsolute as isAbsolute9, relative as relative12 } from "path";
10112
+ import { isAbsolute as isAbsolute10, relative as relative13 } from "path";
10074
10113
  function unique(values) {
10075
10114
  return Array.from(new Set(values));
10076
10115
  }
@@ -10078,11 +10117,11 @@ function rootsFor(workspace, opts = {}) {
10078
10117
  return unique([workspace.root, ...opts.rootAliases ?? []]);
10079
10118
  }
10080
10119
  function isOutsideWorkspaceRel(rel) {
10081
- return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute9(rel);
10120
+ return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute10(rel);
10082
10121
  }
10083
10122
  function toRelPath(workspace, absolutePath, opts = {}) {
10084
10123
  for (const root of rootsFor(workspace, opts)) {
10085
- const rel = relative12(root, absolutePath);
10124
+ const rel = relative13(root, absolutePath);
10086
10125
  if (!isOutsideWorkspaceRel(rel)) return rel;
10087
10126
  }
10088
10127
  const skillMarker = "/.agents/skills/";
@@ -10249,7 +10288,7 @@ import {
10249
10288
  truncateHead,
10250
10289
  truncateLine
10251
10290
  } from "@mariozechner/pi-coding-agent";
10252
- import { resolve as resolve10, relative as relative13 } from "path";
10291
+ import { resolve as resolve11, relative as relative14 } from "path";
10253
10292
 
10254
10293
  // src/server/catalog/tools/_shared.ts
10255
10294
  function makeError(message) {
@@ -10352,15 +10391,15 @@ function isOutsideWorkspace(rel) {
10352
10391
  return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || rel.startsWith("/");
10353
10392
  }
10354
10393
  function isUnderRoot(root, path4) {
10355
- const rel = relative13(root, path4);
10394
+ const rel = relative14(root, path4);
10356
10395
  return !isOutsideWorkspace(rel);
10357
10396
  }
10358
10397
  function normalizeSearchPath(rawPath, workspaceRoot, pathOptions) {
10359
10398
  const path4 = optionalStringParam(rawPath) ?? ".";
10360
10399
  if (!workspaceRoot) return { ok: true, path: pathOptions?.toRemotePath?.(path4) ?? path4 };
10361
10400
  if (!path4.startsWith("/")) {
10362
- const resolved = resolve10(workspaceRoot, path4);
10363
- const rel = relative13(workspaceRoot, resolved);
10401
+ const resolved = resolve11(workspaceRoot, path4);
10402
+ const rel = relative14(workspaceRoot, resolved);
10364
10403
  if (isOutsideWorkspace(rel)) return { ok: false, message: `path "${path4}" is outside workspace` };
10365
10404
  return { ok: true, path: path4 };
10366
10405
  }
@@ -11706,16 +11745,16 @@ function modelsRoutes(app, opts, done) {
11706
11745
  }
11707
11746
 
11708
11747
  // src/server/http/routes/skills.ts
11709
- import { isAbsolute as isAbsolute10, relative as relative14, resolve as resolve11, sep as sep8 } from "path";
11748
+ import { isAbsolute as isAbsolute11, relative as relative15, resolve as resolve12, sep as sep8 } from "path";
11710
11749
  import {
11711
11750
  DefaultPackageManager,
11712
- getAgentDir,
11751
+ getAgentDir as getAgentDir2,
11713
11752
  loadSkills
11714
11753
  } from "@mariozechner/pi-coding-agent";
11715
11754
  var CACHE_TTL_MS2 = 3e4;
11716
11755
  function pathForWorkspaceEditor(workspaceRoot, filePath) {
11717
- const pathWithinWorkspace = relative14(resolve11(workspaceRoot), resolve11(filePath));
11718
- if (pathWithinWorkspace === "" || pathWithinWorkspace === ".." || pathWithinWorkspace.startsWith(`..${sep8}`) || isAbsolute10(pathWithinWorkspace)) {
11756
+ const pathWithinWorkspace = relative15(resolve12(workspaceRoot), resolve12(filePath));
11757
+ if (pathWithinWorkspace === "" || pathWithinWorkspace === ".." || pathWithinWorkspace.startsWith(`..${sep8}`) || isAbsolute11(pathWithinWorkspace)) {
11719
11758
  return filePath;
11720
11759
  }
11721
11760
  return pathWithinWorkspace.split(sep8).join("/");
@@ -11723,7 +11762,9 @@ function pathForWorkspaceEditor(workspaceRoot, filePath) {
11723
11762
  function skillsRoutes(app, opts, done) {
11724
11763
  const cached = /* @__PURE__ */ new Map();
11725
11764
  async function resolveSkillsForRequest(request, refresh = false) {
11726
- const workspaceRoot = opts.getWorkspaceRoot ? await opts.getWorkspaceRoot(request) : opts.workspaceRoot;
11765
+ const workspace = opts.getWorkspace ? await opts.getWorkspace(request) : opts.workspace;
11766
+ if (!workspace) throw new Error("skills route requires workspace or getWorkspace");
11767
+ const workspaceRoot = workspace.root;
11727
11768
  const additionalSkillPaths = opts.getAdditionalSkillPaths ? await opts.getAdditionalSkillPaths(request) : opts.additionalSkillPaths;
11728
11769
  const piPackages = opts.getPiPackages ? await opts.getPiPackages(request) : opts.piPackages;
11729
11770
  const noSkills = (opts.getNoSkills ? await opts.getNoSkills(request) : opts.noSkills) ?? withPiHarnessDefaults().noSkills;
@@ -11734,7 +11775,7 @@ function skillsRoutes(app, opts, done) {
11734
11775
  }
11735
11776
  const cachedEntry = cached.get(cacheKey);
11736
11777
  if (!refresh && cachedEntry && cachedEntry.expiresAt > now) return cachedEntry;
11737
- const agentDir = getAgentDir();
11778
+ const agentDir = getAgentDir2();
11738
11779
  const packageSkillPaths = noSkills ? [] : await (async () => {
11739
11780
  const settingsManager = createResourceSettingsManager(
11740
11781
  workspaceRoot,
@@ -12489,7 +12530,7 @@ function searchRoutes(app, opts, done) {
12489
12530
  }
12490
12531
 
12491
12532
  // src/server/git/gitFileUrl.ts
12492
- import { dirname as dirname12, relative as relative15 } from "path";
12533
+ import { dirname as dirname12, relative as relative16 } from "path";
12493
12534
  import { execFile as execFile3 } from "child_process";
12494
12535
  import { promisify as promisify3 } from "util";
12495
12536
 
@@ -12572,7 +12613,7 @@ async function resolveGitFileUrl(workspaceRoot, path4) {
12572
12613
  commitSha = null;
12573
12614
  }
12574
12615
  }
12575
- const repoRelativePath = relative15(repoRoot, absolutePath).replace(/\\/g, "/");
12616
+ const repoRelativePath = relative16(repoRoot, absolutePath).replace(/\\/g, "/");
12576
12617
  const url = buildGitFileUrl({ remoteUrl, repoRelativePath, branch, commitSha });
12577
12618
  if (!url) {
12578
12619
  return disabled("Only GitHub SSH/HTTPS remotes are supported right now.");
@@ -12598,8 +12639,8 @@ function requirePath(value, reply) {
12598
12639
  }
12599
12640
  function gitRoutes(app, opts, done) {
12600
12641
  async function resolveWorkspaceRoot(request) {
12601
- if (opts.getWorkspaceRoot) return await opts.getWorkspaceRoot(request);
12602
- return request.workspaceRoot;
12642
+ const workspace = opts.getWorkspace ? await opts.getWorkspace(request) : opts.workspace;
12643
+ return workspace === void 0 ? void 0 : getNodeWorkspaceHostRoot(workspace);
12603
12644
  }
12604
12645
  app.get("/api/v1/git/file-url", async (request, reply) => {
12605
12646
  const query = request.query;
@@ -13038,6 +13079,8 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
13038
13079
  requestId: request.id
13039
13080
  });
13040
13081
  } : void 0;
13082
+ const gitStorageRoot = getOptionalRuntimeBundleStorageRoot(runtimeBundle);
13083
+ const gitWorkspace = gitStorageRoot === void 0 ? runtimeBundle.workspace : createNodeWorkspace(gitStorageRoot);
13041
13084
  return {
13042
13085
  runtimeMode: resolvedMode,
13043
13086
  capabilities: { tools: toolNames(tools) },
@@ -13061,12 +13104,12 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
13061
13104
  // File search shares the same bound implementation as the model tool.
13062
13105
  search: { fileSearch: runtimeBundle.fileSearch },
13063
13106
  // Git metadata resolves against host storage, not a sandbox-internal cwd.
13064
- git: { getWorkspaceRoot: () => getOptionalRuntimeBundleStorageRoot(runtimeBundle) }
13107
+ git: { workspace: gitWorkspace }
13065
13108
  },
13066
13109
  chat: { service: agentRuntime.service },
13067
13110
  systemPrompt: { harness },
13068
13111
  skills: {
13069
- workspaceRoot,
13112
+ workspace: createNodeWorkspace(workspaceRoot),
13070
13113
  additionalSkillPaths: runtimePi.additionalSkillPaths,
13071
13114
  piPackages: runtimePi.packages,
13072
13115
  noSkills: runtimePi.noSkills,
@@ -13277,20 +13320,20 @@ function createRuntimeBindingLifecycle(options) {
13277
13320
  const requestLeaseLifetimes = /* @__PURE__ */ new WeakMap();
13278
13321
  let admissionTail = Promise.resolve();
13279
13322
  let resolveEntryChange;
13280
- let entryChange = new Promise((resolve12) => {
13281
- resolveEntryChange = resolve12;
13323
+ let entryChange = new Promise((resolve13) => {
13324
+ resolveEntryChange = resolve13;
13282
13325
  });
13283
13326
  function notifyEntryChange() {
13284
13327
  resolveEntryChange();
13285
- entryChange = new Promise((resolve12) => {
13286
- resolveEntryChange = resolve12;
13328
+ entryChange = new Promise((resolve13) => {
13329
+ resolveEntryChange = resolve13;
13287
13330
  });
13288
13331
  }
13289
13332
  async function withAdmissionLock(operation) {
13290
13333
  const previous = admissionTail;
13291
13334
  let release;
13292
- admissionTail = new Promise((resolve12) => {
13293
- release = resolve12;
13335
+ admissionTail = new Promise((resolve13) => {
13336
+ release = resolve13;
13294
13337
  });
13295
13338
  await previous;
13296
13339
  try {
@@ -13390,8 +13433,8 @@ function createRuntimeBindingLifecycle(options) {
13390
13433
  }
13391
13434
  function waitForLeases(entry) {
13392
13435
  if (entry.activeLeases === 0) return Promise.resolve();
13393
- entry.leaseDrainPromise ??= new Promise((resolve12) => {
13394
- entry.resolveLeaseDrain = resolve12;
13436
+ entry.leaseDrainPromise ??= new Promise((resolve13) => {
13437
+ entry.resolveLeaseDrain = resolve13;
13395
13438
  });
13396
13439
  return entry.leaseDrainPromise;
13397
13440
  }
@@ -14285,6 +14328,9 @@ var registerAgentRoutes = async (app, opts) => {
14285
14328
  try {
14286
14329
  workspaceId = (await opts.getWorkspaceId(request)).trim();
14287
14330
  } catch (error) {
14331
+ if (typeof error === "object" && error !== null && "status" in error && error.status === 421 && "code" in error && error.code === ErrorCode.enum.D1_HOST_SCOPE_VIOLATION) {
14332
+ throw error;
14333
+ }
14288
14334
  const statusCode = typeof error?.statusCode === "number" ? error.statusCode : 400;
14289
14335
  const message = statusCode >= 500 ? "workspace scope failed" : error instanceof Error ? error.message : "workspace id is required";
14290
14336
  return reply.code(statusCode).send({
@@ -14331,7 +14377,11 @@ var registerAgentRoutes = async (app, opts) => {
14331
14377
  getFileSearch: async (request) => (await getBindingForRequest(request)).runtimeBundle.fileSearch
14332
14378
  });
14333
14379
  await app.register(gitRoutes, {
14334
- getWorkspaceRoot: async (request) => getOptionalRuntimeBundleStorageRoot((await getBindingForRequest(request)).runtimeBundle)
14380
+ getWorkspace: async (request) => {
14381
+ const runtimeBundle = (await getBindingForRequest(request)).runtimeBundle;
14382
+ const storageRoot = getOptionalRuntimeBundleStorageRoot(runtimeBundle);
14383
+ return storageRoot === void 0 ? runtimeBundle.workspace : createNodeWorkspace(storageRoot);
14384
+ }
14335
14385
  });
14336
14386
  await app.register(piChatRoutes, {
14337
14387
  getService: async (request) => {
@@ -14347,7 +14397,7 @@ var registerAgentRoutes = async (app, opts) => {
14347
14397
  filterModels: opts.filterModels
14348
14398
  });
14349
14399
  await app.register(skillsRoutes, {
14350
- workspaceRoot,
14400
+ workspace: staticBinding ? createNodeWorkspace(workspaceRoot) : void 0,
14351
14401
  additionalSkillPaths: [
14352
14402
  ...staticBinding?.runtimeProvisioning?.skillPaths ?? [],
14353
14403
  ...opts.pi?.additionalSkillPaths ?? []
@@ -14356,7 +14406,7 @@ var registerAgentRoutes = async (app, opts) => {
14356
14406
  // Undefined is fine: skillsRoutes resolves it through the canonical
14357
14407
  // harness policy (withPiHarnessDefaults), same as the factory above.
14358
14408
  noSkills: opts.pi?.noSkills,
14359
- getWorkspaceRoot: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).root,
14409
+ getWorkspace: staticBinding ? void 0 : async (request) => createNodeWorkspace((await getSkillsScopeForRequest(request)).root),
14360
14410
  getAdditionalSkillPaths: staticBinding && !hasRuntimeProvisioningInput ? void 0 : async (request) => {
14361
14411
  const scope = await getSkillsScopeForRequest(request);
14362
14412
  if (!hasRuntimeProvisioningInput) return scope.pi.additionalSkillPaths;
@@ -14488,6 +14538,7 @@ export {
14488
14538
  createAgent,
14489
14539
  AgentDirectoryCompilerError,
14490
14540
  compileAgentDirectory,
14541
+ createResolvedAgentDigest,
14491
14542
  resolveAgentDeployment,
14492
14543
  MANAGED_AGENT_MCP_ORIGIN_SURFACE,
14493
14544
  MANAGED_AGENT_MCP_DELIVERY_RULE,