@lousy-agents/agent-shell 5.14.10 → 5.15.1

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 (2) hide show
  1. package/dist/index.js +279 -123
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __rspack_createRequire } from "node:module";
3
3
  const __rspack_createRequire_require = __rspack_createRequire(import.meta.url);
4
4
  var __webpack_modules__ = ({
5
- 145(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
5
+ 341(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
6
6
 
7
7
  ;// CONCATENATED MODULE: external "node:child_process"
8
8
  const external_node_child_process_namespaceObject = __rspack_createRequire_require("node:child_process");
@@ -546,6 +546,191 @@ function guardedRmSync(params) {
546
546
  }), { verifyAfter: params.verifyAfter });
547
547
  }
548
548
 
549
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/deny-mutations.js
550
+
551
+
552
+
553
+
554
+ async function pathExists(filePath) {
555
+ try {
556
+ await promises_namespaceObject.lstat(filePath);
557
+ return true;
558
+ }
559
+ catch (err) {
560
+ if (!path_isNotFoundPathError(err)) {
561
+ throw err;
562
+ }
563
+ return false;
564
+ }
565
+ }
566
+ async function resolvePathViaExistingAncestor(targetPath) {
567
+ const normalized = external_node_path_namespaceObject.resolve(targetPath);
568
+ let cursor = normalized;
569
+ const missingSuffix = [];
570
+ while (external_node_path_namespaceObject.dirname(cursor) !== cursor && !(await pathExists(cursor))) {
571
+ missingSuffix.unshift(external_node_path_namespaceObject.basename(cursor));
572
+ cursor = external_node_path_namespaceObject.dirname(cursor);
573
+ }
574
+ if (!(await pathExists(cursor))) {
575
+ return normalized;
576
+ }
577
+ try {
578
+ const resolvedAncestor = external_node_path_namespaceObject.resolve(await promises_namespaceObject.realpath(cursor));
579
+ return missingSuffix.length === 0
580
+ ? resolvedAncestor
581
+ : external_node_path_namespaceObject.resolve(resolvedAncestor, ...missingSuffix);
582
+ }
583
+ catch {
584
+ return normalized;
585
+ }
586
+ }
587
+ async function comparablePaths(rawPath) {
588
+ path_assertNoNulPathInput(rawPath, "path contains a NUL byte");
589
+ const resolved = external_node_path_namespaceObject.resolve(rawPath);
590
+ return new Set([resolved, await resolvePathViaExistingAncestor(resolved)]);
591
+ }
592
+ function isSamePath(left, right) {
593
+ return path_isPathInside(left, right) && path_isPathInside(right, left);
594
+ }
595
+ function hasPolicyEntries(policy) {
596
+ return Boolean(policy?.paths?.length || policy?.prefixes?.length);
597
+ }
598
+ function policyPathEntries(entries) {
599
+ const paths = [];
600
+ for (const entry of entries ?? []) {
601
+ if (entry.length === 0) {
602
+ throw new errors_FsSafeError("invalid-path", "deny mutation paths must be non-empty");
603
+ }
604
+ path_assertNoNulPathInput(entry, "deny mutation path contains a NUL byte");
605
+ if (!external_node_path_namespaceObject.isAbsolute(entry)) {
606
+ throw new errors_FsSafeError("invalid-path", "deny mutation paths must be absolute");
607
+ }
608
+ paths.push(entry);
609
+ }
610
+ return paths;
611
+ }
612
+ async function assertMutationNotDenied(filePath, policy, options = {}) {
613
+ if (!hasPolicyEntries(policy)) {
614
+ return;
615
+ }
616
+ const targetPaths = await comparablePaths(filePath);
617
+ for (const deniedPath of policyPathEntries(policy.paths)) {
618
+ const deniedPaths = await comparablePaths(deniedPath);
619
+ for (const target of targetPaths) {
620
+ for (const denied of deniedPaths) {
621
+ if (isSamePath(denied, target) ||
622
+ (options.protectAncestors === true && path_isPathInside(target, denied))) {
623
+ throw new errors_FsSafeError("denied-path", "path is denied by denyMutations policy");
624
+ }
625
+ }
626
+ }
627
+ }
628
+ for (const deniedPrefix of policyPathEntries(policy.prefixes)) {
629
+ const deniedPaths = await comparablePaths(deniedPrefix);
630
+ for (const target of targetPaths) {
631
+ for (const denied of deniedPaths) {
632
+ if (path_isPathInside(denied, target) ||
633
+ (options.protectAncestors === true && path_isPathInside(target, denied))) {
634
+ throw new errors_FsSafeError("denied-path", "path is denied by denyMutations policy");
635
+ }
636
+ }
637
+ }
638
+ }
639
+ }
640
+ function mergeDenyMutationPolicies(defaultPolicy, callPolicy) {
641
+ if (!defaultPolicy) {
642
+ return callPolicy;
643
+ }
644
+ if (!callPolicy) {
645
+ return defaultPolicy;
646
+ }
647
+ return {
648
+ paths: [...(defaultPolicy.paths ?? []), ...(callPolicy.paths ?? [])],
649
+ prefixes: [...(defaultPolicy.prefixes ?? []), ...(callPolicy.prefixes ?? [])],
650
+ };
651
+ }
652
+
653
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/opened-realpath.js
654
+
655
+
656
+
657
+
658
+
659
+ async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
660
+ const handleStat = await handle.stat();
661
+ const fdCandidates = process.platform === "linux"
662
+ ? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`]
663
+ : process.platform === "win32"
664
+ ? []
665
+ : [`/dev/fd/${handle.fd}`];
666
+ for (const fdPath of fdCandidates) {
667
+ try {
668
+ const fdRealPath = await promises_namespaceObject.realpath(fdPath);
669
+ const fdRealStat = await promises_namespaceObject.stat(fdRealPath);
670
+ if (file_identity_sameFileIdentity(handleStat, fdRealStat)) {
671
+ return fdRealPath;
672
+ }
673
+ }
674
+ catch {
675
+ // try next fd path
676
+ }
677
+ }
678
+ try {
679
+ const ioRealPath = await promises_namespaceObject.realpath(ioPath);
680
+ const ioRealStat = await promises_namespaceObject.stat(ioRealPath);
681
+ if (file_identity_sameFileIdentity(handleStat, ioRealStat)) {
682
+ return ioRealPath;
683
+ }
684
+ }
685
+ catch (err) {
686
+ if (!path_isNotFoundPathError(err)) {
687
+ throw err;
688
+ }
689
+ }
690
+ const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
691
+ if (parentResolved) {
692
+ return parentResolved;
693
+ }
694
+ throw new errors_FsSafeError("path-mismatch", "unable to resolve opened file path");
695
+ }
696
+ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath) {
697
+ let parentReal;
698
+ try {
699
+ parentReal = await promises_namespaceObject.realpath(external_node_path_namespaceObject.dirname(ioPath));
700
+ }
701
+ catch (err) {
702
+ if (path_isNotFoundPathError(err)) {
703
+ return null;
704
+ }
705
+ throw err;
706
+ }
707
+ let entries;
708
+ try {
709
+ entries = await promises_namespaceObject.readdir(parentReal);
710
+ }
711
+ catch (err) {
712
+ if (path_isNotFoundPathError(err)) {
713
+ return null;
714
+ }
715
+ throw err;
716
+ }
717
+ for (const entry of entries.toSorted()) {
718
+ const candidatePath = external_node_path_namespaceObject.join(parentReal, entry);
719
+ try {
720
+ const candidateStat = await promises_namespaceObject.lstat(candidatePath);
721
+ if (candidateStat.isFile() && file_identity_sameFileIdentity(handleStat, candidateStat)) {
722
+ return await promises_namespaceObject.realpath(candidatePath);
723
+ }
724
+ }
725
+ catch (err) {
726
+ if (!path_isNotFoundPathError(err)) {
727
+ throw err;
728
+ }
729
+ }
730
+ }
731
+ return null;
732
+ }
733
+
549
734
  ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/pinned-python-config.js
550
735
  let overrideConfig = {};
551
736
  function parseMode(value) {
@@ -1390,7 +1575,7 @@ async function runPinnedWriteHelper(params) {
1390
1575
  relativeParentPath: params.relativeParentPath,
1391
1576
  });
1392
1577
  if (getFsSafePythonConfig().mode === "off") {
1393
- return await runPinnedWriteFallbackOrThrow(params);
1578
+ return await runPinnedWriteFallback(params);
1394
1579
  }
1395
1580
  if (params.input.kind === "stream") {
1396
1581
  try {
@@ -1398,7 +1583,7 @@ async function runPinnedWriteHelper(params) {
1398
1583
  }
1399
1584
  catch (error) {
1400
1585
  if (canFallbackFromPythonError(error)) {
1401
- return await runPinnedWriteFallbackOrThrow(params, error);
1586
+ return await runPinnedWriteFallback(params);
1402
1587
  }
1403
1588
  throw error;
1404
1589
  }
@@ -1422,7 +1607,7 @@ async function runPinnedWriteHelper(params) {
1422
1607
  }
1423
1608
  catch (error) {
1424
1609
  if (canFallbackFromPythonError(error)) {
1425
- return await runPinnedWriteFallbackOrThrow(params, error);
1610
+ return await runPinnedWriteFallback(params);
1426
1611
  }
1427
1612
  throw error;
1428
1613
  }
@@ -1449,12 +1634,6 @@ async function runPinnedCopyHelper(params) {
1449
1634
  },
1450
1635
  });
1451
1636
  }
1452
- async function runPinnedWriteFallbackOrThrow(params, cause) {
1453
- if (process.platform !== "win32") {
1454
- throw new errors_FsSafeError("helper-unavailable", "Python helper is required for pinned writes on this platform", { cause });
1455
- }
1456
- return await runPinnedWriteFallback(params);
1457
- }
1458
1637
  async function runPinnedWriteFallback(params) {
1459
1638
  const parentPath = params.relativeParentPath
1460
1639
  ? external_node_path_namespaceObject.join(params.rootPath, ...params.relativeParentPath.split("/"))
@@ -1577,7 +1756,7 @@ async function resolveRootPath(params) {
1577
1756
  const absolutePath = external_node_path_namespaceObject.resolve(params.absolutePath);
1578
1757
  const rootCanonicalPath = params.rootCanonicalPath
1579
1758
  ? external_node_path_namespaceObject.resolve(params.rootCanonicalPath)
1580
- : await resolvePathViaExistingAncestor(rootPath);
1759
+ : await root_path_resolvePathViaExistingAncestor(rootPath);
1581
1760
  const context = createBoundaryResolutionContext({
1582
1761
  resolveParams: params,
1583
1762
  rootPath,
@@ -1946,7 +2125,7 @@ async function resolveOutsideLexicalCanonicalPathAsync(params) {
1946
2125
  if (path_isPathInside(params.rootPath, params.absolutePath)) {
1947
2126
  return undefined;
1948
2127
  }
1949
- return await resolvePathViaExistingAncestor(params.absolutePath);
2128
+ return await root_path_resolvePathViaExistingAncestor(params.absolutePath);
1950
2129
  }
1951
2130
  function resolveOutsideLexicalCanonicalPathSync(params) {
1952
2131
  if (isPathInside(params.rootPath, params.absolutePath)) {
@@ -1993,11 +2172,11 @@ function buildResolvedRootPath(params) {
1993
2172
  kind: params.kind.kind,
1994
2173
  };
1995
2174
  }
1996
- async function resolvePathViaExistingAncestor(targetPath) {
2175
+ async function root_path_resolvePathViaExistingAncestor(targetPath) {
1997
2176
  const normalized = external_node_path_namespaceObject.resolve(targetPath);
1998
2177
  let cursor = normalized;
1999
2178
  const missingSuffix = [];
2000
- while (!isFilesystemRoot(cursor) && !(await pathExists(cursor))) {
2179
+ while (!isFilesystemRoot(cursor) && !(await root_path_pathExists(cursor))) {
2001
2180
  missingSuffix.unshift(external_node_path_namespaceObject.basename(cursor));
2002
2181
  const parent = external_node_path_namespaceObject.dirname(cursor);
2003
2182
  if (parent === cursor) {
@@ -2005,7 +2184,7 @@ async function resolvePathViaExistingAncestor(targetPath) {
2005
2184
  }
2006
2185
  cursor = parent;
2007
2186
  }
2008
- if (!(await pathExists(cursor))) {
2187
+ if (!(await root_path_pathExists(cursor))) {
2009
2188
  return normalized;
2010
2189
  }
2011
2190
  try {
@@ -2117,7 +2296,7 @@ function shortPath(value) {
2117
2296
  function isFilesystemRoot(candidate) {
2118
2297
  return external_node_path_namespaceObject.parse(candidate).root === candidate;
2119
2298
  }
2120
- async function pathExists(targetPath) {
2299
+ async function root_path_pathExists(targetPath) {
2121
2300
  try {
2122
2301
  await promises_namespaceObject.lstat(targetPath);
2123
2302
  return true;
@@ -2139,7 +2318,7 @@ async function resolveSymlinkHopPath(symlinkPath) {
2139
2318
  }
2140
2319
  const linkTarget = await promises_namespaceObject.readlink(symlinkPath);
2141
2320
  const linkAbsolute = external_node_path_namespaceObject.resolve(external_node_path_namespaceObject.dirname(symlinkPath), linkTarget);
2142
- return resolvePathViaExistingAncestor(linkAbsolute);
2321
+ return root_path_resolvePathViaExistingAncestor(linkAbsolute);
2143
2322
  }
2144
2323
  }
2145
2324
  function resolveSymlinkHopPathSync(symlinkPath) {
@@ -2208,6 +2387,23 @@ function path_policy_shortPath(value) {
2208
2387
  return value;
2209
2388
  }
2210
2389
 
2390
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/read-opened-file.js
2391
+
2392
+ async function read_opened_file_readOpenedFileSafely(params) {
2393
+ if (params.maxBytes !== undefined && params.opened.stat.size > params.maxBytes) {
2394
+ throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
2395
+ }
2396
+ const buffer = await params.opened.handle.readFile();
2397
+ if (params.maxBytes !== undefined && buffer.byteLength > params.maxBytes) {
2398
+ throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${buffer.byteLength})`);
2399
+ }
2400
+ return {
2401
+ buffer,
2402
+ realPath: params.opened.realPath,
2403
+ stat: params.opened.stat,
2404
+ };
2405
+ }
2406
+
2211
2407
  ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/path-stat.js
2212
2408
  function pathStatFromStats(stat) {
2213
2409
  return {
@@ -2535,6 +2731,10 @@ async function serializePathWrite(key, run) {
2535
2731
 
2536
2732
 
2537
2733
 
2734
+
2735
+
2736
+
2737
+
2538
2738
 
2539
2739
 
2540
2740
 
@@ -2733,6 +2933,7 @@ class RootHandle {
2733
2933
  mkdir: this.defaults.mkdir,
2734
2934
  mode: this.defaults.mode,
2735
2935
  ...options,
2936
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2736
2937
  append: writeMode === "append",
2737
2938
  truncateExisting: writeMode === "replace",
2738
2939
  });
@@ -2744,18 +2945,29 @@ class RootHandle {
2744
2945
  mkdir: this.defaults.mkdir,
2745
2946
  mode: this.defaults.mode,
2746
2947
  ...options,
2948
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2747
2949
  });
2748
2950
  }
2749
- async remove(relativePath) {
2951
+ async remove(relativePath, options = {}) {
2750
2952
  assertValidRootRelativePath(relativePath);
2751
- await removePathInRoot(this.context, relativePath);
2953
+ await removePathInRoot(this.context, {
2954
+ relativePath,
2955
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2956
+ });
2752
2957
  }
2753
- async mkdir(relativePath) {
2958
+ async mkdir(relativePath, options = {}) {
2754
2959
  assertValidRootRelativePath(relativePath);
2755
- await mkdirPathInRoot(this.context, { relativePath });
2960
+ await mkdirPathInRoot(this.context, {
2961
+ relativePath,
2962
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2963
+ });
2756
2964
  }
2757
- async ensureRoot() {
2758
- await mkdirPathInRoot(this.context, { relativePath: "", allowRoot: true });
2965
+ async ensureRoot(options = {}) {
2966
+ await mkdirPathInRoot(this.context, {
2967
+ relativePath: "",
2968
+ allowRoot: true,
2969
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2970
+ });
2759
2971
  }
2760
2972
  async write(relativePath, data, options = {}) {
2761
2973
  await writeFileInRoot(this.context, {
@@ -2764,6 +2976,7 @@ class RootHandle {
2764
2976
  mkdir: this.defaults.mkdir,
2765
2977
  mode: this.defaults.mode,
2766
2978
  ...options,
2979
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2767
2980
  });
2768
2981
  }
2769
2982
  async create(relativePath, data, options = {}) {
@@ -2773,6 +2986,7 @@ class RootHandle {
2773
2986
  mkdir: this.defaults.mkdir,
2774
2987
  mode: this.defaults.mode,
2775
2988
  ...options,
2989
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2776
2990
  overwrite: false,
2777
2991
  });
2778
2992
  }
@@ -2795,6 +3009,7 @@ class RootHandle {
2795
3009
  mkdir: this.defaults.mkdir,
2796
3010
  mode: this.defaults.mode,
2797
3011
  ...options,
3012
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
2798
3013
  });
2799
3014
  }
2800
3015
  async exists(relativePath) {
@@ -2838,6 +3053,12 @@ class RootHandle {
2838
3053
  async move(fromRelative, toRelative, options = {}) {
2839
3054
  assertValidRootRelativePath(fromRelative);
2840
3055
  assertValidRootRelativePath(toRelative);
3056
+ const denyMutations = mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations);
3057
+ await assertMoveMutationAllowed(this.context, {
3058
+ fromRelative,
3059
+ toRelative,
3060
+ denyMutations,
3061
+ });
2841
3062
  try {
2842
3063
  await runPinnedHelper("rename", this.rootReal, {
2843
3064
  from: fromRelative,
@@ -2849,6 +3070,7 @@ class RootHandle {
2849
3070
  if (canFallbackFromPythonError(error)) {
2850
3071
  await movePathFallback(this.context, {
2851
3072
  fromRelative,
3073
+ denyMutations,
2852
3074
  overwrite: options.overwrite ?? false,
2853
3075
  toRelative,
2854
3076
  });
@@ -2897,7 +3119,7 @@ async function openFileInRoot(root, params) {
2897
3119
  async function readFileInRoot(root, params) {
2898
3120
  const opened = await openFileInRoot(root, params);
2899
3121
  try {
2900
- return await readOpenedFileSafely({ opened, maxBytes: params.maxBytes });
3122
+ return await read_opened_file_readOpenedFileSafely({ opened, maxBytes: params.maxBytes });
2901
3123
  }
2902
3124
  finally {
2903
3125
  await opened.handle.close().catch(() => { });
@@ -2930,20 +3152,6 @@ async function openLocalFileSafely(params) {
2930
3152
  assertNoNulPathInput(params.filePath, "file path contains a NUL byte");
2931
3153
  return await openVerifiedLocalFile(params.filePath);
2932
3154
  }
2933
- async function readOpenedFileSafely(params) {
2934
- if (params.maxBytes !== undefined && params.opened.stat.size > params.maxBytes) {
2935
- throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
2936
- }
2937
- const buffer = await params.opened.handle.readFile();
2938
- if (params.maxBytes !== undefined && buffer.byteLength > params.maxBytes) {
2939
- throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${buffer.byteLength})`);
2940
- }
2941
- return {
2942
- buffer,
2943
- realPath: params.opened.realPath,
2944
- stat: params.opened.stat,
2945
- };
2946
- }
2947
3155
  function emitWriteBoundaryWarning(reason) {
2948
3156
  logWarn(`security: fs-safe write boundary warning (${reason})`);
2949
3157
  }
@@ -2984,82 +3192,9 @@ async function verifyAtomicWriteResult(params) {
2984
3192
  await opened.handle.close().catch(() => { });
2985
3193
  }
2986
3194
  }
2987
- async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
2988
- const handleStat = await handle.stat();
2989
- const fdCandidates = process.platform === "linux"
2990
- ? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`]
2991
- : process.platform === "win32"
2992
- ? []
2993
- : [`/dev/fd/${handle.fd}`];
2994
- for (const fdPath of fdCandidates) {
2995
- try {
2996
- const fdRealPath = await promises_namespaceObject.realpath(fdPath);
2997
- const fdRealStat = await promises_namespaceObject.stat(fdRealPath);
2998
- if (file_identity_sameFileIdentity(handleStat, fdRealStat)) {
2999
- return fdRealPath;
3000
- }
3001
- }
3002
- catch {
3003
- // try next fd path
3004
- }
3005
- }
3006
- try {
3007
- const ioRealPath = await promises_namespaceObject.realpath(ioPath);
3008
- const ioRealStat = await promises_namespaceObject.stat(ioRealPath);
3009
- if (file_identity_sameFileIdentity(handleStat, ioRealStat)) {
3010
- return ioRealPath;
3011
- }
3012
- }
3013
- catch (err) {
3014
- if (!path_isNotFoundPathError(err)) {
3015
- throw err;
3016
- }
3017
- }
3018
- const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
3019
- if (parentResolved) {
3020
- return parentResolved;
3021
- }
3022
- throw new errors_FsSafeError("path-mismatch", "unable to resolve opened file path");
3023
- }
3024
- async function resolveOpenedFileRealPathFromParent(handleStat, ioPath) {
3025
- let parentReal;
3026
- try {
3027
- parentReal = await promises_namespaceObject.realpath(external_node_path_namespaceObject.dirname(ioPath));
3028
- }
3029
- catch (err) {
3030
- if (path_isNotFoundPathError(err)) {
3031
- return null;
3032
- }
3033
- throw err;
3034
- }
3035
- let entries;
3036
- try {
3037
- entries = await promises_namespaceObject.readdir(parentReal);
3038
- }
3039
- catch (err) {
3040
- if (path_isNotFoundPathError(err)) {
3041
- return null;
3042
- }
3043
- throw err;
3044
- }
3045
- for (const entry of entries.toSorted()) {
3046
- const candidatePath = external_node_path_namespaceObject.join(parentReal, entry);
3047
- try {
3048
- const candidateStat = await promises_namespaceObject.lstat(candidatePath);
3049
- if (candidateStat.isFile() && file_identity_sameFileIdentity(handleStat, candidateStat)) {
3050
- return await promises_namespaceObject.realpath(candidatePath);
3051
- }
3052
- }
3053
- catch (err) {
3054
- if (!path_isNotFoundPathError(err)) {
3055
- throw err;
3056
- }
3057
- }
3058
- }
3059
- return null;
3060
- }
3061
3195
  async function openWritableFileInRoot(root, params) {
3062
3196
  const { rootReal, rootWithSep, resolved } = await resolvePathInRoot(root, params.relativePath);
3197
+ await assertMutationNotDenied(resolved, params.denyMutations);
3063
3198
  try {
3064
3199
  await assertNoPathAliasEscape({
3065
3200
  absolutePath: resolved,
@@ -3186,6 +3321,7 @@ async function appendFileInRoot(root, params) {
3186
3321
  relativePath: params.relativePath,
3187
3322
  mkdir: params.mkdir,
3188
3323
  mode: params.mode,
3324
+ denyMutations: params.denyMutations,
3189
3325
  truncateExisting: false,
3190
3326
  append: true,
3191
3327
  });
@@ -3213,8 +3349,8 @@ async function appendFileInRoot(root, params) {
3213
3349
  await target.handle.close().catch(() => { });
3214
3350
  }
3215
3351
  }
3216
- async function removePathInRoot(root, relativePath) {
3217
- const resolved = await resolvePinnedRemovePathInRoot(root, relativePath);
3352
+ async function removePathInRoot(root, params) {
3353
+ const resolved = await resolvePinnedRemovePathInRoot(root, params.relativePath, params.denyMutations);
3218
3354
  if (process.platform === "win32") {
3219
3355
  await removePathFallback(resolved);
3220
3356
  return;
@@ -3262,7 +3398,7 @@ async function writeFileInRoot(root, params) {
3262
3398
  });
3263
3399
  return;
3264
3400
  }
3265
- const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode);
3401
+ const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode, params.denyMutations);
3266
3402
  await serializePathWrite(pinned.targetPath, async () => {
3267
3403
  let identity;
3268
3404
  try {
@@ -3318,7 +3454,7 @@ async function copyFileInRoot(root, params) {
3318
3454
  });
3319
3455
  return;
3320
3456
  }
3321
- const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode);
3457
+ const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode, params.denyMutations);
3322
3458
  await serializePathWrite(pinned.targetPath, async () => {
3323
3459
  let identity;
3324
3460
  try {
@@ -3362,8 +3498,9 @@ async function copyFileInRoot(root, params) {
3362
3498
  await source.handle.close().catch(() => { });
3363
3499
  }
3364
3500
  }
3365
- async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode) {
3501
+ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode, denyMutations) {
3366
3502
  const { rootReal, rootWithSep, resolved } = await resolvePathInRoot(root, relativePath);
3503
+ await assertMutationNotDenied(resolved, denyMutations);
3367
3504
  try {
3368
3505
  await assertNoPathAliasEscape({
3369
3506
  absolutePath: resolved,
@@ -3420,12 +3557,16 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode)
3420
3557
  async function resolvePinnedPathInRoot(root, params) {
3421
3558
  return await resolvePinnedOperationPathInRoot(root, {
3422
3559
  allowRoot: params.allowRoot,
3560
+ denyMutations: params.denyMutations,
3561
+ protectDenyMutationAncestors: false,
3423
3562
  relativePath: params.relativePath,
3424
3563
  policy: PATH_ALIAS_POLICIES.strict,
3425
3564
  });
3426
3565
  }
3427
- async function resolvePinnedRemovePathInRoot(root, relativePath) {
3566
+ async function resolvePinnedRemovePathInRoot(root, relativePath, denyMutations) {
3428
3567
  return await resolvePinnedOperationPathInRoot(root, {
3568
+ denyMutations,
3569
+ protectDenyMutationAncestors: true,
3429
3570
  relativePath,
3430
3571
  policy: PATH_ALIAS_POLICIES.unlinkTarget,
3431
3572
  });
@@ -3437,6 +3578,7 @@ async function resolvePinnedOperationPathInRoot(root, params) {
3437
3578
  });
3438
3579
  const relativeResolved = external_node_path_namespaceObject.relative(resolved.rootReal, resolved.canonicalPath);
3439
3580
  if ((relativeResolved === "" || relativeResolved === ".") && params.allowRoot === true) {
3581
+ await assertMutationNotDenied(resolved.canonicalPath, params.denyMutations);
3440
3582
  return { rootReal: resolved.rootReal, resolved: resolved.canonicalPath, relativePosix: "" };
3441
3583
  }
3442
3584
  const firstSegment = relativeResolved.split(external_node_path_namespaceObject.sep)[0];
@@ -3450,6 +3592,9 @@ async function resolvePinnedOperationPathInRoot(root, params) {
3450
3592
  if (!path_isPathInside(resolved.rootWithSep, resolved.canonicalPath)) {
3451
3593
  throw new errors_FsSafeError("outside-workspace", "file is outside workspace root");
3452
3594
  }
3595
+ await assertMutationNotDenied(resolved.canonicalPath, params.denyMutations, {
3596
+ protectAncestors: params.protectDenyMutationAncestors,
3597
+ });
3453
3598
  return { rootReal: resolved.rootReal, resolved: resolved.canonicalPath, relativePosix };
3454
3599
  }
3455
3600
  async function resolvePinnedRootPathInRoot(root, params) {
@@ -3527,13 +3672,21 @@ async function listPathFallback(root, relativePath, withFileTypes) {
3527
3672
  throw error;
3528
3673
  }
3529
3674
  }
3675
+ async function assertMoveMutationAllowed(root, params) {
3676
+ const source = await resolvePathInRoot(root, params.fromRelative);
3677
+ await assertMutationNotDenied(source.resolved, params.denyMutations, { protectAncestors: true });
3678
+ const target = await resolvePathInRoot(root, params.toRelative);
3679
+ await assertMutationNotDenied(target.resolved, params.denyMutations, { protectAncestors: true });
3680
+ }
3530
3681
  async function movePathFallback(root, params) {
3531
3682
  const source = await resolvePathInRoot(root, params.fromRelative);
3683
+ await assertMutationNotDenied(source.resolved, params.denyMutations, { protectAncestors: true });
3532
3684
  await resolvePinnedRootPathInRoot(root, {
3533
3685
  relativePath: params.fromRelative,
3534
3686
  policy: PATH_ALIAS_POLICIES.strict,
3535
3687
  });
3536
3688
  const target = await resolvePathInRoot(root, params.toRelative);
3689
+ await assertMutationNotDenied(target.resolved, params.denyMutations, { protectAncestors: true });
3537
3690
  await resolvePinnedRootPathInRoot(root, {
3538
3691
  relativePath: params.toRelative,
3539
3692
  policy: PATH_ALIAS_POLICIES.unlinkTarget,
@@ -3617,6 +3770,7 @@ async function writeFileFallback(root, params) {
3617
3770
  relativePath: params.relativePath,
3618
3771
  mkdir: params.mkdir,
3619
3772
  mode: params.mode,
3773
+ denyMutations: params.denyMutations,
3620
3774
  truncateExisting: false,
3621
3775
  });
3622
3776
  const destinationPath = target.realPath;
@@ -3662,6 +3816,7 @@ async function writeFileFallback(root, params) {
3662
3816
  }
3663
3817
  async function writeMissingFileFallback(root, params) {
3664
3818
  const { rootReal, resolved } = await resolvePathInRoot(root, params.relativePath);
3819
+ await assertMutationNotDenied(resolved, params.denyMutations);
3665
3820
  try {
3666
3821
  await assertNoPathAliasEscape({
3667
3822
  absolutePath: resolved,
@@ -3735,6 +3890,7 @@ async function copyFileFallback(root, params, source) {
3735
3890
  relativePath: params.relativePath,
3736
3891
  mkdir: params.mkdir,
3737
3892
  mode: params.mode,
3893
+ denyMutations: params.denyMutations,
3738
3894
  truncateExisting: false,
3739
3895
  });
3740
3896
  const destinationPath = target.realPath;
@@ -12366,7 +12522,7 @@ async function emitScriptEndEvent(options, deps) {
12366
12522
  const capturedEnv = captureEnv(options.env);
12367
12523
  const tags = captureTags(options.env);
12368
12524
  const event = {
12369
- v: SCHEMA_VERSION,
12525
+ v: (/* inlined export .SCHEMA_VERSION */1),
12370
12526
  session_id: sessionId,
12371
12527
  event: "script_end",
12372
12528
  command: options.command,
@@ -12395,7 +12551,7 @@ async function emitShimErrorEvent(options, deps) {
12395
12551
  const capturedEnv = captureEnv(options.env);
12396
12552
  const tags = captureTags(options.env);
12397
12553
  const event = {
12398
- v: SCHEMA_VERSION,
12554
+ v: (/* inlined export .SCHEMA_VERSION */1),
12399
12555
  session_id: sessionId,
12400
12556
  event: "shim_error",
12401
12557
  command: options.command,
@@ -12416,7 +12572,7 @@ async function emitPolicyDecisionEvent(options, deps) {
12416
12572
  const capturedEnv = captureEnv(options.env);
12417
12573
  const tags = captureTags(options.env);
12418
12574
  const event = {
12419
- v: SCHEMA_VERSION,
12575
+ v: (/* inlined export .SCHEMA_VERSION */1),
12420
12576
  session_id: sessionId,
12421
12577
  event: "policy_decision",
12422
12578
  command: options.command,
@@ -12439,7 +12595,7 @@ async function emitToolUseEvent(options, deps) {
12439
12595
  const capturedEnv = captureEnv(options.env);
12440
12596
  const tags = captureTags(options.env);
12441
12597
  const event = {
12442
- v: SCHEMA_VERSION,
12598
+ v: (/* inlined export .SCHEMA_VERSION */1),
12443
12599
  session_id: sessionId,
12444
12600
  event: "tool_use",
12445
12601
  tool_name: options.tool_name,
@@ -14896,4 +15052,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
14896
15052
  // module factories are used so entry inlining is disabled
14897
15053
  // startup
14898
15054
  // Load entry module and return exports
14899
- var __webpack_exports__ = __webpack_require__(145);
15055
+ var __webpack_exports__ = __webpack_require__(341);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lousy-agents/agent-shell",
3
- "version": "5.14.10",
3
+ "version": "5.15.1",
4
4
  "description": "A flight recorder for npm script execution",
5
5
  "type": "module",
6
6
  "repository": {
@@ -36,11 +36,11 @@
36
36
  "build": "rspack build --config rspack.config.ts && chmod +x dist/index.js"
37
37
  },
38
38
  "dependencies": {
39
- "@openclaw/fs-safe": "0.2.6",
39
+ "@openclaw/fs-safe": "0.3.0",
40
40
  "zod": "4.4.3"
41
41
  },
42
42
  "peerDependencies": {
43
- "@github/copilot-sdk": "0.3.0"
43
+ "@github/copilot-sdk": "1.0.0"
44
44
  },
45
45
  "peerDependenciesMeta": {
46
46
  "@github/copilot-sdk": {