@hachej/boring-agent 0.1.81 → 0.1.83

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-S2HYQYJP.js";
14
+ } from "./chunk-WODTQBXR.js";
13
15
  import {
14
16
  createAgentRuntimeBridge
15
- } from "./chunk-2AVRA73A.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-3RSYCAHO.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-24VL7G32.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-YV6D7GCQ.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-4VZW2XEV.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,
@@ -8731,7 +8758,7 @@ async function createResolvedAgentDigest(input) {
8731
8758
  const digestField = typeof field === "string" ? field : "workspaceId";
8732
8759
  throw invalidDeployment(digestField, `${digestField} is invalid`);
8733
8760
  }
8734
- return createAgentAssetDigest(JSON.stringify({ domain: RESOLVED_AGENT_DIGEST_DOMAIN, ...parsed.data }));
8761
+ return createAgentAssetDigest(canonicalStringify({ domain: RESOLVED_AGENT_DIGEST_DOMAIN, ...parsed.data }));
8735
8762
  }
8736
8763
  function invalidDefinition(field, message) {
8737
8764
  return new AgentDefinitionValidationError({
@@ -8845,7 +8872,7 @@ async function resolveAgentDeployment(bundle, deployment, authorizedBinding) {
8845
8872
  }
8846
8873
 
8847
8874
  // src/server/mcp/managedAgentDelegate.ts
8848
- import { createHash as createHash6, randomUUID } from "crypto";
8875
+ import { randomUUID } from "crypto";
8849
8876
  var MANAGED_AGENT_MCP_ORIGIN_SURFACE = "mcp-managed-agent";
8850
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.";
8851
8878
  var MAX_FINAL_ASSISTANT_TEXT_BYTES = 96 * 1024;
@@ -9341,7 +9368,7 @@ async function resolveMarkdownArtifact(candidate, workspace) {
9341
9368
  validateMarkdownContent(content);
9342
9369
  const artifact = {
9343
9370
  content,
9344
- sha256: sha256(bytes),
9371
+ sha256: await sha256Bytes(bytes),
9345
9372
  byteSize,
9346
9373
  mediaType: MARKDOWN_MEDIA_TYPE,
9347
9374
  ...candidate.title ? { title: candidate.title } : {}
@@ -9434,9 +9461,6 @@ function validateMarkdownContent(content) {
9434
9461
  function sameStat(left, right) {
9435
9462
  return left.kind === right.kind && left.size === right.size && left.mtimeMs === right.mtimeMs;
9436
9463
  }
9437
- function sha256(bytes) {
9438
- return `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
9439
- }
9440
9464
  function safeDecodeArtifactPath(path4) {
9441
9465
  try {
9442
9466
  return decodeURIComponent(path4);
@@ -9601,13 +9625,13 @@ function resultTool(result) {
9601
9625
  };
9602
9626
  }
9603
9627
  function deferred3() {
9604
- let resolve12;
9628
+ let resolve13;
9605
9629
  let reject;
9606
9630
  const promise = new Promise((res, rej) => {
9607
- resolve12 = res;
9631
+ resolve13 = res;
9608
9632
  reject = rej;
9609
9633
  });
9610
- return { promise, resolve: resolve12, reject };
9634
+ return { promise, resolve: resolve13, reject };
9611
9635
  }
9612
9636
  function errorTool(error) {
9613
9637
  const safe = safeError(error);
@@ -9674,7 +9698,7 @@ function withRuntimeEnvContributions(runtimeBundle, baseContext, contributions,
9674
9698
 
9675
9699
  // src/server/harness/pi-coding-agent/pluginLoader.ts
9676
9700
  import { readdir as readdir7, stat as stat11, readFile as readFile10 } from "fs/promises";
9677
- 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";
9678
9702
  import { homedir as homedir3 } from "os";
9679
9703
  import { pathToFileURL as pathToFileURL2 } from "url";
9680
9704
  var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs"]);
@@ -9744,12 +9768,12 @@ async function loadNpmPlugin(pkgDir, importFn) {
9744
9768
  if (!await fileExists(pkgJsonPath)) return [];
9745
9769
  const pkgJson = JSON.parse(await readFile10(pkgJsonPath, "utf-8"));
9746
9770
  const main = pkgJson.main ?? "index.js";
9747
- const resolvedMain = resolve8(pkgDir, main);
9748
- const resolvedPkgDir = resolve8(pkgDir);
9771
+ const resolvedMain = resolve9(pkgDir, main);
9772
+ const resolvedPkgDir = resolve9(pkgDir);
9749
9773
  if (resolvedMain !== resolvedPkgDir && !resolvedMain.startsWith(resolvedPkgDir + sep7)) {
9750
9774
  return [];
9751
9775
  }
9752
- const relPath = relative10(resolvedPkgDir, resolvedMain);
9776
+ const relPath = relative11(resolvedPkgDir, resolvedMain);
9753
9777
  if (relPath.startsWith("..")) {
9754
9778
  return [];
9755
9779
  }
@@ -9834,7 +9858,7 @@ import {
9834
9858
  // src/server/tools/operations/bound.ts
9835
9859
  import { constants as constants5 } from "fs";
9836
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";
9837
- 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";
9838
9862
  function toPosixPath(value) {
9839
9863
  return value.split("\\").join("/");
9840
9864
  }
@@ -9890,8 +9914,8 @@ async function walkMatches(root, current, pattern, ignore, limit, out) {
9890
9914
  const entries = await readdir8(current, { withFileTypes: true });
9891
9915
  for (const entry of entries) {
9892
9916
  if (out.length >= limit) return;
9893
- const absolutePath = resolve9(current, entry.name);
9894
- const relativePath = toPosixPath(relative11(root, absolutePath));
9917
+ const absolutePath = resolve10(current, entry.name);
9918
+ const relativePath = toPosixPath(relative12(root, absolutePath));
9895
9919
  if (entry.isDirectory() && shouldSkipDir(relativePath, ignore)) continue;
9896
9920
  if (matchesGlob(relativePath, pattern)) {
9897
9921
  out.push(absolutePath);
@@ -9915,16 +9939,16 @@ async function findNearestExistingAncestor(absPath) {
9915
9939
  }
9916
9940
  }
9917
9941
  async function assertWithinWorkspace(workspaceRoot, absPath) {
9918
- const realRoot = await realpath5(resolve9(workspaceRoot));
9942
+ const realRoot = await realpath5(resolve10(workspaceRoot));
9919
9943
  try {
9920
9944
  const s = await lstat4(absPath);
9921
9945
  if (s.isSymbolicLink()) {
9922
9946
  const target = await readlink(absPath);
9923
- const resolvedTarget = resolve9(dirname11(absPath), target);
9947
+ const resolvedTarget = resolve10(dirname11(absPath), target);
9924
9948
  const nearestAncestor = await findNearestExistingAncestor(resolvedTarget);
9925
9949
  const realAncestor = await realpath5(nearestAncestor);
9926
- const rel2 = relative11(realRoot, realAncestor);
9927
- if (rel2.startsWith("..") || isAbsolute8(rel2)) {
9950
+ const rel2 = relative12(realRoot, realAncestor);
9951
+ if (rel2.startsWith("..") || isAbsolute9(rel2)) {
9928
9952
  throw new Error(`path "${absPath}" is outside workspace`);
9929
9953
  }
9930
9954
  return;
@@ -9944,16 +9968,16 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
9944
9968
  if (code === "ENOENT") {
9945
9969
  const nearestAncestor = await findNearestExistingAncestor(dirname11(absPath));
9946
9970
  const realAncestor = await realpath5(nearestAncestor);
9947
- const rel2 = relative11(realRoot, realAncestor);
9948
- if (rel2.startsWith("..") || isAbsolute8(rel2)) {
9971
+ const rel2 = relative12(realRoot, realAncestor);
9972
+ if (rel2.startsWith("..") || isAbsolute9(rel2)) {
9949
9973
  throw new Error(`path "${absPath}" is outside workspace`);
9950
9974
  }
9951
9975
  return;
9952
9976
  }
9953
9977
  throw err;
9954
9978
  }
9955
- const rel = relative11(realRoot, realCandidate);
9956
- if (rel.startsWith("..") || isAbsolute8(rel)) {
9979
+ const rel = relative12(realRoot, realCandidate);
9980
+ if (rel.startsWith("..") || isAbsolute9(rel)) {
9957
9981
  throw new Error(`path "${absPath}" is outside workspace`);
9958
9982
  }
9959
9983
  }
@@ -9971,9 +9995,9 @@ function boundFs(workspaceRoot, opts = {}) {
9971
9995
  };
9972
9996
  const toRuntimePath = (absolutePath) => {
9973
9997
  if (!shouldMapRuntimeRoot || !runtimeRoot) return absolutePath;
9974
- const rel = relative11(workspaceRoot, absolutePath);
9998
+ const rel = relative12(workspaceRoot, absolutePath);
9975
9999
  if (rel === "") return runtimeRoot;
9976
- if (rel.startsWith("..") || isAbsolute8(rel)) return absolutePath;
10000
+ if (rel.startsWith("..") || isAbsolute9(rel)) return absolutePath;
9977
10001
  return `${runtimeRoot}/${toPosixPath(rel)}`;
9978
10002
  };
9979
10003
  const read = {
@@ -10085,7 +10109,7 @@ import {
10085
10109
  } from "@mariozechner/pi-coding-agent";
10086
10110
 
10087
10111
  // src/server/tools/operations/remoteWorkspace.ts
10088
- import { isAbsolute as isAbsolute9, relative as relative12 } from "path";
10112
+ import { isAbsolute as isAbsolute10, relative as relative13 } from "path";
10089
10113
  function unique(values) {
10090
10114
  return Array.from(new Set(values));
10091
10115
  }
@@ -10093,11 +10117,11 @@ function rootsFor(workspace, opts = {}) {
10093
10117
  return unique([workspace.root, ...opts.rootAliases ?? []]);
10094
10118
  }
10095
10119
  function isOutsideWorkspaceRel(rel) {
10096
- return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute9(rel);
10120
+ return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute10(rel);
10097
10121
  }
10098
10122
  function toRelPath(workspace, absolutePath, opts = {}) {
10099
10123
  for (const root of rootsFor(workspace, opts)) {
10100
- const rel = relative12(root, absolutePath);
10124
+ const rel = relative13(root, absolutePath);
10101
10125
  if (!isOutsideWorkspaceRel(rel)) return rel;
10102
10126
  }
10103
10127
  const skillMarker = "/.agents/skills/";
@@ -10264,7 +10288,7 @@ import {
10264
10288
  truncateHead,
10265
10289
  truncateLine
10266
10290
  } from "@mariozechner/pi-coding-agent";
10267
- import { resolve as resolve10, relative as relative13 } from "path";
10291
+ import { resolve as resolve11, relative as relative14 } from "path";
10268
10292
 
10269
10293
  // src/server/catalog/tools/_shared.ts
10270
10294
  function makeError(message) {
@@ -10367,15 +10391,15 @@ function isOutsideWorkspace(rel) {
10367
10391
  return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || rel.startsWith("/");
10368
10392
  }
10369
10393
  function isUnderRoot(root, path4) {
10370
- const rel = relative13(root, path4);
10394
+ const rel = relative14(root, path4);
10371
10395
  return !isOutsideWorkspace(rel);
10372
10396
  }
10373
10397
  function normalizeSearchPath(rawPath, workspaceRoot, pathOptions) {
10374
10398
  const path4 = optionalStringParam(rawPath) ?? ".";
10375
10399
  if (!workspaceRoot) return { ok: true, path: pathOptions?.toRemotePath?.(path4) ?? path4 };
10376
10400
  if (!path4.startsWith("/")) {
10377
- const resolved = resolve10(workspaceRoot, path4);
10378
- const rel = relative13(workspaceRoot, resolved);
10401
+ const resolved = resolve11(workspaceRoot, path4);
10402
+ const rel = relative14(workspaceRoot, resolved);
10379
10403
  if (isOutsideWorkspace(rel)) return { ok: false, message: `path "${path4}" is outside workspace` };
10380
10404
  return { ok: true, path: path4 };
10381
10405
  }
@@ -11721,16 +11745,16 @@ function modelsRoutes(app, opts, done) {
11721
11745
  }
11722
11746
 
11723
11747
  // src/server/http/routes/skills.ts
11724
- 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";
11725
11749
  import {
11726
11750
  DefaultPackageManager,
11727
- getAgentDir,
11751
+ getAgentDir as getAgentDir2,
11728
11752
  loadSkills
11729
11753
  } from "@mariozechner/pi-coding-agent";
11730
11754
  var CACHE_TTL_MS2 = 3e4;
11731
11755
  function pathForWorkspaceEditor(workspaceRoot, filePath) {
11732
- const pathWithinWorkspace = relative14(resolve11(workspaceRoot), resolve11(filePath));
11733
- 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)) {
11734
11758
  return filePath;
11735
11759
  }
11736
11760
  return pathWithinWorkspace.split(sep8).join("/");
@@ -11751,7 +11775,7 @@ function skillsRoutes(app, opts, done) {
11751
11775
  }
11752
11776
  const cachedEntry = cached.get(cacheKey);
11753
11777
  if (!refresh && cachedEntry && cachedEntry.expiresAt > now) return cachedEntry;
11754
- const agentDir = getAgentDir();
11778
+ const agentDir = getAgentDir2();
11755
11779
  const packageSkillPaths = noSkills ? [] : await (async () => {
11756
11780
  const settingsManager = createResourceSettingsManager(
11757
11781
  workspaceRoot,
@@ -12506,7 +12530,7 @@ function searchRoutes(app, opts, done) {
12506
12530
  }
12507
12531
 
12508
12532
  // src/server/git/gitFileUrl.ts
12509
- import { dirname as dirname12, relative as relative15 } from "path";
12533
+ import { dirname as dirname12, relative as relative16 } from "path";
12510
12534
  import { execFile as execFile3 } from "child_process";
12511
12535
  import { promisify as promisify3 } from "util";
12512
12536
 
@@ -12589,7 +12613,7 @@ async function resolveGitFileUrl(workspaceRoot, path4) {
12589
12613
  commitSha = null;
12590
12614
  }
12591
12615
  }
12592
- const repoRelativePath = relative15(repoRoot, absolutePath).replace(/\\/g, "/");
12616
+ const repoRelativePath = relative16(repoRoot, absolutePath).replace(/\\/g, "/");
12593
12617
  const url = buildGitFileUrl({ remoteUrl, repoRelativePath, branch, commitSha });
12594
12618
  if (!url) {
12595
12619
  return disabled("Only GitHub SSH/HTTPS remotes are supported right now.");
@@ -13296,20 +13320,20 @@ function createRuntimeBindingLifecycle(options) {
13296
13320
  const requestLeaseLifetimes = /* @__PURE__ */ new WeakMap();
13297
13321
  let admissionTail = Promise.resolve();
13298
13322
  let resolveEntryChange;
13299
- let entryChange = new Promise((resolve12) => {
13300
- resolveEntryChange = resolve12;
13323
+ let entryChange = new Promise((resolve13) => {
13324
+ resolveEntryChange = resolve13;
13301
13325
  });
13302
13326
  function notifyEntryChange() {
13303
13327
  resolveEntryChange();
13304
- entryChange = new Promise((resolve12) => {
13305
- resolveEntryChange = resolve12;
13328
+ entryChange = new Promise((resolve13) => {
13329
+ resolveEntryChange = resolve13;
13306
13330
  });
13307
13331
  }
13308
13332
  async function withAdmissionLock(operation) {
13309
13333
  const previous = admissionTail;
13310
13334
  let release;
13311
- admissionTail = new Promise((resolve12) => {
13312
- release = resolve12;
13335
+ admissionTail = new Promise((resolve13) => {
13336
+ release = resolve13;
13313
13337
  });
13314
13338
  await previous;
13315
13339
  try {
@@ -13409,8 +13433,8 @@ function createRuntimeBindingLifecycle(options) {
13409
13433
  }
13410
13434
  function waitForLeases(entry) {
13411
13435
  if (entry.activeLeases === 0) return Promise.resolve();
13412
- entry.leaseDrainPromise ??= new Promise((resolve12) => {
13413
- entry.resolveLeaseDrain = resolve12;
13436
+ entry.leaseDrainPromise ??= new Promise((resolve13) => {
13437
+ entry.resolveLeaseDrain = resolve13;
13414
13438
  });
13415
13439
  return entry.leaseDrainPromise;
13416
13440
  }
@@ -14304,6 +14328,9 @@ var registerAgentRoutes = async (app, opts) => {
14304
14328
  try {
14305
14329
  workspaceId = (await opts.getWorkspaceId(request)).trim();
14306
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
+ }
14307
14334
  const statusCode = typeof error?.statusCode === "number" ? error.statusCode : 400;
14308
14335
  const message = statusCode >= 500 ? "workspace scope failed" : error instanceof Error ? error.message : "workspace id is required";
14309
14336
  return reply.code(statusCode).send({