@openclaw/mxc-sandbox 2026.7.2-beta.5 → 2026.8.1-beta.2

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.
Files changed (124) hide show
  1. package/dist/index.js +39 -14
  2. package/dist/mxc-spawn-launcher.mjs +30 -17
  3. package/package.json +4 -4
  4. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/LICENSE.md +0 -0
  5. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/README.md +0 -0
  6. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/common.gypi +0 -0
  7. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/except.gypi +0 -0
  8. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/index.js +0 -0
  9. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/napi-inl.deprecated.h +0 -0
  10. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/napi-inl.h +0 -0
  11. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/napi.h +0 -0
  12. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/node_addon_api.gyp +0 -0
  13. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/node_api.gyp +0 -0
  14. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/noexcept.gypi +0 -0
  15. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/nothing.c +0 -0
  16. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/package-support.json +0 -0
  17. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/package.json +0 -0
  18. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/tools/README.md +0 -0
  19. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/tools/check-napi.js +0 -0
  20. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/tools/clang-format.js +0 -0
  21. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/tools/conversion.js +0 -0
  22. /package/node_modules/{node-addon-api → @microsoft/mxc-sdk/node_modules/node-addon-api}/tools/eslint-format.js +0 -0
  23. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/LICENSE +0 -0
  24. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/README.md +0 -0
  25. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/binding.gyp +0 -0
  26. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/conpty_console_list_agent.js +0 -0
  27. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/eventEmitter2.js +0 -0
  28. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/index.js +0 -0
  29. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/interfaces.js +0 -0
  30. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/shared/conout.js +0 -0
  31. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/terminal.js +0 -0
  32. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/types.js +0 -0
  33. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/unixTerminal.js +0 -0
  34. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/utils.js +0 -0
  35. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/windowsConoutConnection.js +0 -0
  36. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/windowsPtyAgent.js +0 -0
  37. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/windowsTerminal.js +0 -0
  38. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/lib/worker/conoutSocketWorker.js +0 -0
  39. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/package.json +0 -0
  40. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/darwin-arm64/pty.node +0 -0
  41. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/darwin-arm64/spawn-helper +0 -0
  42. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/darwin-x64/pty.node +0 -0
  43. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/darwin-x64/spawn-helper +0 -0
  44. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/linux-arm64/pty.node +0 -0
  45. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/linux-x64/pty.node +0 -0
  46. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  47. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  48. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty.node +0 -0
  49. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty.pdb +0 -0
  50. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  51. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
  52. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  53. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  54. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty.node +0 -0
  55. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty.pdb +0 -0
  56. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty_console_list.node +0 -0
  57. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
  58. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/scripts/post-install.js +0 -0
  59. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/scripts/prebuild.js +0 -0
  60. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/unix/pty.cc +0 -0
  61. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/unix/spawn-helper.cc +0 -0
  62. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/win/conpty.cc +0 -0
  63. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/win/conpty.h +0 -0
  64. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/win/conpty_console_list.cc +0 -0
  65. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/win/path_util.cc +0 -0
  66. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/src/win/path_util.h +0 -0
  67. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/third_party/conpty/1.25.260303002/win10-arm64/OpenConsole.exe +0 -0
  68. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/third_party/conpty/1.25.260303002/win10-arm64/conpty.dll +0 -0
  69. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/third_party/conpty/1.25.260303002/win10-x64/OpenConsole.exe +0 -0
  70. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/third_party/conpty/1.25.260303002/win10-x64/conpty.dll +0 -0
  71. /package/node_modules/{node-pty → @microsoft/mxc-sdk/node_modules/node-pty}/typings/node-pty.d.ts +0 -0
  72. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/LICENSE +0 -0
  73. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/README.md +0 -0
  74. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/bin/semver.js +0 -0
  75. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/classes/comparator.js +0 -0
  76. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/classes/index.js +0 -0
  77. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/classes/range.js +0 -0
  78. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/classes/semver.js +0 -0
  79. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/clean.js +0 -0
  80. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/cmp.js +0 -0
  81. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/coerce.js +0 -0
  82. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/compare-build.js +0 -0
  83. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/compare-loose.js +0 -0
  84. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/compare.js +0 -0
  85. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/diff.js +0 -0
  86. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/eq.js +0 -0
  87. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/gt.js +0 -0
  88. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/gte.js +0 -0
  89. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/inc.js +0 -0
  90. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/lt.js +0 -0
  91. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/lte.js +0 -0
  92. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/major.js +0 -0
  93. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/minor.js +0 -0
  94. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/neq.js +0 -0
  95. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/parse.js +0 -0
  96. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/patch.js +0 -0
  97. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/prerelease.js +0 -0
  98. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/rcompare.js +0 -0
  99. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/rsort.js +0 -0
  100. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/satisfies.js +0 -0
  101. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/sort.js +0 -0
  102. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/truncate.js +0 -0
  103. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/functions/valid.js +0 -0
  104. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/index.js +0 -0
  105. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/constants.js +0 -0
  106. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/debug.js +0 -0
  107. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/identifiers.js +0 -0
  108. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/lrucache.js +0 -0
  109. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/parse-options.js +0 -0
  110. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/internal/re.js +0 -0
  111. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/package.json +0 -0
  112. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/preload.js +0 -0
  113. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/range.bnf +0 -0
  114. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/gtr.js +0 -0
  115. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/intersects.js +0 -0
  116. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/ltr.js +0 -0
  117. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/max-satisfying.js +0 -0
  118. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/min-satisfying.js +0 -0
  119. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/min-version.js +0 -0
  120. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/outside.js +0 -0
  121. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/simplify.js +0 -0
  122. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/subset.js +0 -0
  123. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/to-comparators.js +0 -0
  124. /package/node_modules/{semver → @microsoft/mxc-sdk/node_modules/semver}/ranges/valid.js +0 -0
package/dist/index.js CHANGED
@@ -12,8 +12,9 @@ import fs, { lstatSync, mkdtempSync, readFileSync, realpathSync, rmSync, statSyn
12
12
  import { createHash, randomBytes } from "node:crypto";
13
13
  import { runCommandBuffered } from "openclaw/plugin-sdk/process-runtime";
14
14
  import { removePathWithinRoot, root } from "openclaw/plugin-sdk/file-access-runtime";
15
- import { isPathInside } from "openclaw/plugin-sdk/security-runtime";
15
+ import { FsSafeError, isPathInside } from "openclaw/plugin-sdk/security-runtime";
16
16
  import { fileURLToPath } from "node:url";
17
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
17
18
  import { execFileSync } from "node:child_process";
18
19
  //#region extensions/mxc/src/config.ts
19
20
  const MXC_CONTAINMENTS = ["process", "processcontainer"];
@@ -183,10 +184,10 @@ function createMxcFsBridge(params) {
183
184
  var MxcFsBridge = class {
184
185
  constructor(sandbox) {
185
186
  this.sandbox = sandbox;
186
- this.defaultContainerRoot = path.resolve(this.sandbox.containerWorkdir);
187
- this.protectedSkillMounts = resolveMxcProtectedSkillMounts$1(this.sandbox);
188
- this.workspaceMounts = resolveWorkspaceMounts(this.sandbox);
189
187
  this.resolveRenameTargets = createWritableRenameTargetResolver((target) => this.resolveTarget(target), (target, action) => this.ensureWritable(target, action));
188
+ this.defaultContainerRoot = path.resolve(sandbox.containerWorkdir);
189
+ this.protectedSkillMounts = resolveMxcProtectedSkillMounts$1(sandbox);
190
+ this.workspaceMounts = resolveWorkspaceMounts(sandbox);
190
191
  }
191
192
  resolvePath(params) {
192
193
  const target = this.resolveTarget(params);
@@ -198,7 +199,10 @@ var MxcFsBridge = class {
198
199
  }
199
200
  async readFile(params) {
200
201
  const target = this.resolveTarget(params);
201
- return await (await root(target.mount.hostRoot)).readBytes(target.mountRelativePath, { hardlinks: "reject" });
202
+ return await (await root(target.mount.hostRoot)).readBytes(target.mountRelativePath, {
203
+ hardlinks: "reject",
204
+ ...params.maxBytes === void 0 ? {} : { maxBytes: params.maxBytes }
205
+ });
202
206
  }
203
207
  async writeFile(params) {
204
208
  const target = this.resolveTarget(params);
@@ -206,6 +210,18 @@ var MxcFsBridge = class {
206
210
  const buffer = Buffer.isBuffer(params.data) ? params.data : Buffer.from(params.data, params.encoding ?? "utf8");
207
211
  await (await root(target.mount.hostRoot)).write(target.mountRelativePath, buffer, { mkdir: params.mkdir !== false });
208
212
  }
213
+ async createFileExclusive(params) {
214
+ const target = this.resolveTarget(params);
215
+ this.ensureWritable(target, "create files");
216
+ const buffer = Buffer.isBuffer(params.data) ? params.data : Buffer.from(params.data, params.encoding ?? "utf8");
217
+ try {
218
+ await (await root(target.mount.hostRoot)).create(target.mountRelativePath, buffer, { mkdir: params.mkdir !== false });
219
+ return "created";
220
+ } catch (error) {
221
+ if (error instanceof FsSafeError && error.code === "already-exists") return "exists";
222
+ throw error;
223
+ }
224
+ }
209
225
  async mkdirp(params) {
210
226
  const target = this.resolveTarget(params);
211
227
  this.ensureWritable(target, "create directories");
@@ -914,7 +930,7 @@ function assertConfiguredPathExists(pathValue, source) {
914
930
  } catch (err) {
915
931
  if (isNodeError$1(err)) {
916
932
  if (err.code === "ENOENT") throw new Error(`Sandbox policy path ${pathValue} configured by ${source} does not exist on the host. Create the path or update the policy file.`, { cause: err });
917
- throw new Error(`Sandbox policy path ${pathValue} configured by ${source} is not accessible on the host: ${formatError(err)}`, { cause: err });
933
+ throw new Error(`Sandbox policy path ${pathValue} configured by ${source} is not accessible on the host: ${formatErrorMessage(err)}`, { cause: err });
918
934
  }
919
935
  throw err;
920
936
  }
@@ -927,7 +943,7 @@ function assertPositiveFiniteNumber(value, label) {
927
943
  }
928
944
  function policyFileError(policyPath, err) {
929
945
  if (isNodeError$1(err) && err.code === "ENOENT") return new Error(`Configured sandbox policy file ${policyPath} does not exist. Remove it from mxcPolicyPaths or create the file.`, { cause: err });
930
- return new Error(`Failed to load sandbox policy file at ${policyPath}: ${formatError(err)}`, { cause: err instanceof Error ? err : void 0 });
946
+ return new Error(`Failed to load sandbox policy file at ${policyPath}: ${formatErrorMessage(err)}`, { cause: err instanceof Error ? err : void 0 });
931
947
  }
932
948
  function formatSandboxPolicyIssue(sourceLabel, issue) {
933
949
  if (!issue) return `Sandbox policy at ${sourceLabel} is invalid.`;
@@ -950,10 +966,6 @@ function formatIssuePath(pathSegments) {
950
966
  }
951
967
  return label;
952
968
  }
953
- function formatError(err) {
954
- if (err instanceof Error && err.message) return err.message;
955
- return String(err);
956
- }
957
969
  function isNodeError$1(err) {
958
970
  return err instanceof Error && "code" in err;
959
971
  }
@@ -1011,7 +1023,7 @@ function resolveWorkdirInsideWorkspace(workspaceDir, workdir) {
1011
1023
  try {
1012
1024
  if (statSync(candidate).isDirectory()) return candidate;
1013
1025
  } catch (err) {
1014
- if (isNodeError(err) && err.code === "ENOENT") throw new Error(`MXC sandbox workdir ${workdir} does not exist.`, { cause: err });
1026
+ if (isMissingPathError(err)) throw new Error(`MXC sandbox workdir ${workdir} does not exist.`, { cause: err });
1015
1027
  throw err;
1016
1028
  }
1017
1029
  throw new Error(`MXC sandbox workdir ${workdir} is not a directory.`);
@@ -1020,7 +1032,7 @@ function realpathForExistingPath(value, label) {
1020
1032
  try {
1021
1033
  return realpathSync(path.resolve(value));
1022
1034
  } catch (err) {
1023
- if (isNodeError(err) && err.code === "ENOENT") throw new Error(`MXC ${label} ${value} does not exist.`, { cause: err });
1035
+ if (isMissingPathError(err)) throw new Error(`MXC ${label} ${value} does not exist.`, { cause: err });
1024
1036
  throw err;
1025
1037
  }
1026
1038
  }
@@ -1029,7 +1041,7 @@ function realpathForPotentialPath(value) {
1029
1041
  try {
1030
1042
  return realpathSync(resolved);
1031
1043
  } catch (err) {
1032
- if (!isNodeError(err) || err.code !== "ENOENT") throw err;
1044
+ if (!isMissingPathError(err)) throw err;
1033
1045
  const parent = path.dirname(resolved);
1034
1046
  if (parent === resolved) throw new Error(`MXC sandbox workdir ${value} does not exist.`, { cause: err });
1035
1047
  return path.join(realpathForPotentialPath(parent), path.basename(resolved));
@@ -1038,6 +1050,9 @@ function realpathForPotentialPath(value) {
1038
1050
  function isNodeError(err) {
1039
1051
  return err instanceof Error && "code" in err;
1040
1052
  }
1053
+ function isMissingPathError(err) {
1054
+ return isNodeError(err) && (err.code === "ENOENT" || err.code === "ENOTDIR");
1055
+ }
1041
1056
  function buildMxcLauncherOptions(config, usePty) {
1042
1057
  const options = {
1043
1058
  debug: config.debug ?? false,
@@ -1072,6 +1087,15 @@ function createMxcSandboxBackendHandle(params) {
1072
1087
  runtimeId: params.runtimeId,
1073
1088
  runtimeLabel: params.runtimeId,
1074
1089
  workdir: params.workdir,
1090
+ workdirValidation: "backend",
1091
+ async validateWorkdir(workdir) {
1092
+ try {
1093
+ return resolveWorkdirInsideWorkspace(params.workdir, workdir);
1094
+ } catch (err) {
1095
+ if (err instanceof Error && err.message.startsWith("MXC sandbox workdir")) return null;
1096
+ throw err;
1097
+ }
1098
+ },
1075
1099
  capabilities: {},
1076
1100
  async buildExecSpec({ command, workdir, env, usePty }) {
1077
1101
  const effectiveWorkdir = resolveWorkdirInsideWorkspace(params.workdir, workdir ?? params.workdir);
@@ -1210,6 +1234,7 @@ const mxcSandboxBackendManager = {
1210
1234
  //#endregion
1211
1235
  //#region extensions/mxc/src/mxc-backend-factory.ts
1212
1236
  function sanitizeRuntimeId(value) {
1237
+ if (/:workspace:[a-f0-9]{32}$/i.test(value.trim())) return `openclaw-mxc-workspace-${createHash("sha256").update(value).digest("hex").slice(0, 32)}`;
1213
1238
  const slug = value.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
1214
1239
  const hash = createHash("sha256").update(value).digest("hex").slice(0, 8);
1215
1240
  return `openclaw-mxc-${slug || "sandbox"}-${hash}`;
@@ -35,9 +35,9 @@ export function forwardSignals(spawned, options = {}) {
35
35
  if (exitTimer) {
36
36
  return;
37
37
  }
38
- const setTimeoutFn = options.setTimeout ?? setTimeout;
38
+ const setTimeoutFn = options.setTimeout?.bind(undefined) ?? setTimeout;
39
39
  exitTimer = setTimeoutFn(() => {
40
- const exit = options.exit ?? process.exit;
40
+ const exit = options.exit?.bind(undefined) ?? ((code) => process.exit(code));
41
41
  exit(signalExitCode(signal));
42
42
  }, exitGraceMs);
43
43
  exitTimer?.unref?.();
@@ -86,11 +86,37 @@ function bridgeChildProcess(child) {
86
86
 
87
87
  export function exitOnChildProcessClose(child, options = {}) {
88
88
  child.on("close", (exitCode, signal) => {
89
- const exit = options.exit ?? process.exit;
89
+ const exit = options.exit?.bind(undefined) ?? ((code) => process.exit(code));
90
90
  exit(typeof exitCode === "number" ? exitCode : signalExitCode(signal));
91
91
  });
92
92
  }
93
93
 
94
+ function attachPtyProcess(spawned) {
95
+ bridgeStdio(spawned);
96
+ forwardSignals(spawned);
97
+ spawned.onExit(({ exitCode, signal }) => {
98
+ process.exit(typeof exitCode === "number" ? exitCode : signalExitCode(signal));
99
+ });
100
+ }
101
+
102
+ function attachChildProcess(spawned) {
103
+ bridgeChildProcess(spawned);
104
+ forwardSignals(spawned);
105
+ exitOnChildProcessClose(spawned);
106
+ }
107
+
108
+ export async function launchSandbox(spawnSandboxFromConfig, config, options, bridges = {}) {
109
+ // Normalize sync and Promise-returning SDK implementations before selecting an I/O bridge.
110
+ const spawned = await spawnSandboxFromConfig(config, options ?? {});
111
+
112
+ if (typeof spawned.onData === "function") {
113
+ (bridges.pty ?? attachPtyProcess)(spawned);
114
+ return;
115
+ }
116
+
117
+ (bridges.child ?? attachChildProcess)(spawned);
118
+ }
119
+
94
120
  const SIGNAL_NUMBERS = new Map([
95
121
  ["SIGHUP", 1],
96
122
  ["SIGINT", 2],
@@ -123,20 +149,7 @@ export async function main() {
123
149
  try {
124
150
  const { config, options } = decodePayload(process.argv.slice(2));
125
151
  const { spawnSandboxFromConfig } = await import("@microsoft/mxc-sdk");
126
- const spawned = await spawnSandboxFromConfig(config, options ?? {});
127
-
128
- if (typeof spawned.onData === "function") {
129
- bridgeStdio(spawned);
130
- forwardSignals(spawned);
131
- spawned.onExit(({ exitCode, signal }) => {
132
- process.exit(typeof exitCode === "number" ? exitCode : signalExitCode(signal));
133
- });
134
- return;
135
- }
136
-
137
- bridgeChildProcess(spawned);
138
- forwardSignals(spawned);
139
- exitOnChildProcessClose(spawned);
152
+ await launchSandbox(spawnSandboxFromConfig, config, options);
140
153
  } catch (error) {
141
154
  process.stderr.write(`${formatErrorStack(error)}\n`);
142
155
  process.exit(127);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/mxc-sandbox",
3
- "version": "2026.7.2-beta.5",
3
+ "version": "2026.8.1-beta.2",
4
4
  "description": "OpenClaw MXC sandbox execution plugin for MXC-capable hosts",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,10 +21,10 @@
21
21
  "minHostVersion": ">=2026.6.11"
22
22
  },
23
23
  "compat": {
24
- "pluginApi": ">=2026.7.2-beta.5"
24
+ "pluginApi": ">=2026.8.1-beta.2"
25
25
  },
26
26
  "build": {
27
- "openclawVersion": "2026.7.2-beta.5",
27
+ "openclawVersion": "2026.8.1-beta.2",
28
28
  "bundledDist": false,
29
29
  "staticAssets": [
30
30
  {
@@ -47,7 +47,7 @@
47
47
  "README.md"
48
48
  ],
49
49
  "peerDependencies": {
50
- "openclaw": ">=2026.7.2-beta.5"
50
+ "openclaw": ">=2026.8.1-beta.2"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "openclaw": {