windows-development-sandbox 1.13.2 → 1.15.0

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 (153) hide show
  1. package/config.example.json +2 -1
  2. package/dist/app/features/defs.d.ts +1 -1
  3. package/dist/app/features/projects/projects.def.d.ts +1 -1
  4. package/dist/app/features/projects/projects.run.d.ts +1 -1
  5. package/dist/app/features/projects/projects.run.js +10 -2
  6. package/dist/app/features/sandbox/sandbox.def.js +3 -1
  7. package/dist/app/features/settings/categories.def.js +1 -0
  8. package/dist/app/features/storage/storage.run.js +1 -1
  9. package/dist/bin/agent-sandbox.js +2 -2
  10. package/dist/bin/{chunk-VENWSGX2.js → chunk-D7CM63BS.js} +2303 -1462
  11. package/dist/bin/{chunk-K4SU3MHJ.js → chunk-HTQT5SBY.js} +1 -1
  12. package/dist/bin/{chunk-IL7BXJF2.js → chunk-RQ4BWBYX.js} +1 -1
  13. package/dist/bin/claude-host.js +2 -2
  14. package/dist/bin/claude-sbx.js +2 -2
  15. package/dist/bin/codex-sbx.js +2 -2
  16. package/dist/bin/gemini-sbx.js +2 -2
  17. package/dist/bin/sandbox.js +2 -2
  18. package/dist/bin/sbx-hide.js +2 -2
  19. package/dist/bin/sbx-show.js +2 -2
  20. package/dist/cli/commands/launch/launch.js +1 -1
  21. package/dist/cli/commands/projects/here.js +2 -0
  22. package/dist/cli/commands/repair/checks/contained.js +1 -1
  23. package/dist/cli/services/health-service.js +15 -3
  24. package/dist/cli/services/projects-service.d.ts +8 -3
  25. package/dist/cli/services/projects-service.js +21 -4
  26. package/dist/core/config/defaults.js +1 -0
  27. package/dist/core/schema/config.d.ts +4 -0
  28. package/dist/core/schema/projects.d.ts +4 -0
  29. package/dist/core/schema/projects.js +3 -0
  30. package/dist/guest/boot/boot.js +8 -2
  31. package/dist/guest/daemon/daemon.js +3 -0
  32. package/dist/guest/daemon/live-folders.d.ts +48 -0
  33. package/dist/guest/daemon/live-folders.js +245 -0
  34. package/dist/guest/daemon/live.d.ts +4 -0
  35. package/dist/guest/daemon/live.js +57 -0
  36. package/dist/guest/daemon/sessions.d.ts +7 -0
  37. package/dist/guest/daemon/sessions.js +23 -2
  38. package/dist/guest/entries/daemon.js +5 -2
  39. package/dist/guest/runtime/csc.d.ts +1 -0
  40. package/dist/guest/runtime/csc.js +1 -0
  41. package/dist/guest/runtime/secrets.d.ts +5 -2
  42. package/dist/guest/runtime/secrets.js +12 -5
  43. package/dist/guest/sessions/pty-host.d.ts +10 -0
  44. package/dist/guest/sessions/pty-host.js +48 -3
  45. package/dist/host/channel/channel.js +1 -1
  46. package/dist/host/engines/hcs/live-folders.d.ts +117 -0
  47. package/dist/host/engines/hcs/live-folders.js +347 -0
  48. package/dist/host/engines/index.d.ts +1 -0
  49. package/dist/host/engines/index.js +1 -0
  50. package/dist/host/install/install-record.d.ts +1 -0
  51. package/dist/host/install/install-record.js +2 -0
  52. package/dist/host/launch/generate.js +8 -1
  53. package/dist/host/projects/join.d.ts +4 -0
  54. package/dist/host/projects/join.js +11 -3
  55. package/dist/host/projects/mapper.d.ts +34 -5
  56. package/dist/host/projects/mapper.js +88 -20
  57. package/dist/host/projects/registry.d.ts +2 -0
  58. package/dist/host/projects/registry.js +1 -1
  59. package/dist/host/sandbox/contained-deps.d.ts +2 -1
  60. package/dist/host/sandbox/contained-deps.js +6 -4
  61. package/dist/host/secrets/launch-secrets.js +2 -1
  62. package/dist/host/sharing/lifecycle.js +9 -1
  63. package/dist/host/storage/contained/contained-storage.js +13 -0
  64. package/dist/host/storage/contained/disk-port.d.ts +5 -0
  65. package/dist/host/storage/contained/helper-port.d.ts +72 -0
  66. package/dist/host/storage/contained/helper-port.js +162 -0
  67. package/dist/host/storage/contained/index.d.ts +1 -0
  68. package/dist/host/storage/contained/index.js +1 -0
  69. package/dist/host/web/bridge.d.ts +5 -0
  70. package/dist/host/web/bridge.js +11 -1
  71. package/dist/host/web/server.d.ts +2 -0
  72. package/dist/host/web/server.js +11 -1
  73. package/dist/runtime/agent.js +23 -0
  74. package/dist/runtime/daemon.js +523 -135
  75. package/dist/runtime/db.js +23 -0
  76. package/dist/runtime/main.js +221 -15
  77. package/dist/runtime/netproxy.js +23 -0
  78. package/dist/runtime/view.js +209 -12
  79. package/dist/selftest/channel.test.js +72 -1
  80. package/dist/selftest/contained.test.js +1 -37
  81. package/dist/selftest/hcs.test.js +5 -2
  82. package/dist/selftest/index.js +4 -0
  83. package/dist/selftest/install.test.js +11 -0
  84. package/dist/selftest/layout.test.js +1 -0
  85. package/dist/selftest/live-daemon.test.js +51 -1
  86. package/dist/selftest/live-folders.test.d.ts +2 -0
  87. package/dist/selftest/live-folders.test.js +588 -0
  88. package/dist/selftest/live-terminal.test.js +112 -4
  89. package/dist/selftest/projects.test.js +7 -7
  90. package/dist/selftest/storage-helper.test.d.ts +2 -0
  91. package/dist/selftest/storage-helper.test.js +493 -0
  92. package/dist/selftest/support/engine-golden.js +1 -0
  93. package/dist/selftest/support/fixtures.d.ts +1 -0
  94. package/dist/selftest/support/live.js +2 -0
  95. package/dist/selftest/support/vhdx.d.ts +14 -0
  96. package/dist/selftest/support/vhdx.js +72 -0
  97. package/dist/selftest/web.test.js +14 -2
  98. package/dist/shared/channel/index.d.ts +1 -0
  99. package/dist/shared/channel/index.js +1 -0
  100. package/dist/shared/channel/live.d.ts +53 -0
  101. package/dist/shared/channel/live.js +92 -0
  102. package/dist/shared/channel/run-dir.d.ts +11 -0
  103. package/dist/shared/channel/run-dir.js +20 -0
  104. package/dist/shared/channel/secrets.d.ts +1 -0
  105. package/dist/shared/channel/secrets.js +5 -0
  106. package/dist/shared/paths/projects.d.ts +6 -1
  107. package/dist/shared/paths/projects.js +21 -1
  108. package/dist/shared/pty/index.d.ts +3 -1
  109. package/dist/shared/pty/index.js +3 -1
  110. package/dist/shared/pty/key-gate.d.ts +24 -0
  111. package/dist/shared/pty/key-gate.js +45 -0
  112. package/dist/shared/pty/mouse-modes.d.ts +27 -0
  113. package/dist/shared/pty/mouse-modes.js +155 -0
  114. package/dist/shared/pty/terminal.d.ts +0 -5
  115. package/dist/shared/pty/terminal.js +51 -20
  116. package/dist/sync/watcher.js +10 -1
  117. package/dist/web/index.html +1 -1
  118. package/dist/web/{main-NBQ3LF4E.js → main-7DJZ2M27.js} +34 -34
  119. package/native/csharp/HcsHost/AssemblyInfo.cs +4 -4
  120. package/native/csharp/HcsHost/FolderAccess.cs +361 -0
  121. package/native/csharp/HcsHost/Hcs.cs +31 -3
  122. package/native/csharp/HcsHost/Program.cs +54 -6
  123. package/native/csharp/HcsHost/Share.cs +64 -11
  124. package/native/csharp/HcsHost/WsbGuard.cs +130 -0
  125. package/native/csharp/HcsHost/WsbShare.cs +295 -0
  126. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  127. package/native/csharp/StorageHelper/AssemblyInfo.cs +15 -0
  128. package/native/csharp/StorageHelper/Client.cs +297 -0
  129. package/native/csharp/StorageHelper/Log.cs +177 -0
  130. package/native/csharp/StorageHelper/MountRecords.cs +160 -0
  131. package/native/csharp/StorageHelper/Operations.cs +596 -0
  132. package/native/csharp/StorageHelper/Pins.cs +270 -0
  133. package/native/csharp/StorageHelper/Privileges.cs +78 -0
  134. package/native/csharp/StorageHelper/Program.cs +349 -0
  135. package/native/csharp/StorageHelper/Protocol.cs +107 -0
  136. package/native/csharp/StorageHelper/RateLimiter.cs +97 -0
  137. package/native/csharp/StorageHelper/Rules.cs +156 -0
  138. package/native/csharp/StorageHelper/Server.cs +656 -0
  139. package/native/csharp/StorageHelper/Settings.cs +297 -0
  140. package/native/csharp/StorageHelper/StorageService.cs +53 -0
  141. package/native/csharp/StorageHelper/UserSettings.cs +206 -0
  142. package/native/csharp/StorageHelper/Vhdx.cs +230 -0
  143. package/native/csharp/StorageHelper/VirtualDisk.cs +241 -0
  144. package/native/csharp/StorageHelper/Volumes.cs +379 -0
  145. package/native/csharp/StorageHelper/Watchdog.cs +128 -0
  146. package/native/csharp/StorageHelper/Win32.cs +250 -0
  147. package/native/scripts/contained-common.ps1 +4 -0
  148. package/native/scripts/hcs-live-share.ps1 +191 -0
  149. package/native/scripts/set-storage-helper.ps1 +203 -0
  150. package/package.json +1 -1
  151. package/sandbox/csharp/BindMount.cs +120 -0
  152. package/sandbox/csharp/PtyHost.cs +236 -1
  153. package/schemas/config.schema.json +8 -0
@@ -1245,13 +1245,13 @@ var require_lodash = __commonJS({
1245
1245
  }
1246
1246
  return true;
1247
1247
  }
1248
- function baseDelay(func, wait, args) {
1248
+ function baseDelay(func, wait2, args) {
1249
1249
  if (typeof func != "function") {
1250
1250
  throw new TypeError2(FUNC_ERROR_TEXT);
1251
1251
  }
1252
1252
  return setTimeout2(function() {
1253
1253
  func.apply(undefined2, args);
1254
- }, wait);
1254
+ }, wait2);
1255
1255
  }
1256
1256
  function baseDifference(array2, values2, iteratee2, comparator) {
1257
1257
  var index = -1, includes2 = arrayIncludes, isCommon = true, length = array2.length, result2 = [], valuesLength = values2.length;
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
1363
1363
  return isFunction(object2[key2]);
1364
1364
  });
1365
1365
  }
1366
- function baseGet(object2, path70) {
1367
- path70 = castPath(path70, object2);
1368
- var index = 0, length = path70.length;
1366
+ function baseGet(object2, path72) {
1367
+ path72 = castPath(path72, object2);
1368
+ var index = 0, length = path72.length;
1369
1369
  while (object2 != null && index < length) {
1370
- object2 = object2[toKey(path70[index++])];
1370
+ object2 = object2[toKey(path72[index++])];
1371
1371
  }
1372
1372
  return index && index == length ? object2 : undefined2;
1373
1373
  }
@@ -1431,10 +1431,10 @@ var require_lodash = __commonJS({
1431
1431
  });
1432
1432
  return accumulator;
1433
1433
  }
1434
- function baseInvoke(object2, path70, args) {
1435
- path70 = castPath(path70, object2);
1436
- object2 = parent(object2, path70);
1437
- var func = object2 == null ? object2 : object2[toKey(last(path70))];
1434
+ function baseInvoke(object2, path72, args) {
1435
+ path72 = castPath(path72, object2);
1436
+ object2 = parent(object2, path72);
1437
+ var func = object2 == null ? object2 : object2[toKey(last(path72))];
1438
1438
  return func == null ? undefined2 : apply(func, object2, args);
1439
1439
  }
1440
1440
  function baseIsArguments(value) {
@@ -1590,13 +1590,13 @@ var require_lodash = __commonJS({
1590
1590
  return object2 === source || baseIsMatch(object2, source, matchData);
1591
1591
  };
1592
1592
  }
1593
- function baseMatchesProperty(path70, srcValue) {
1594
- if (isKey(path70) && isStrictComparable(srcValue)) {
1595
- return matchesStrictComparable(toKey(path70), srcValue);
1593
+ function baseMatchesProperty(path72, srcValue) {
1594
+ if (isKey(path72) && isStrictComparable(srcValue)) {
1595
+ return matchesStrictComparable(toKey(path72), srcValue);
1596
1596
  }
1597
1597
  return function(object2) {
1598
- var objValue = get(object2, path70);
1599
- return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path70) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1598
+ var objValue = get(object2, path72);
1599
+ return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path72) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1600
1600
  };
1601
1601
  }
1602
1602
  function baseMerge(object2, source, srcIndex, customizer, stack) {
@@ -1693,23 +1693,23 @@ var require_lodash = __commonJS({
1693
1693
  });
1694
1694
  }
1695
1695
  function basePick(object2, paths) {
1696
- return basePickBy(object2, paths, function(value, path70) {
1697
- return hasIn(object2, path70);
1696
+ return basePickBy(object2, paths, function(value, path72) {
1697
+ return hasIn(object2, path72);
1698
1698
  });
1699
1699
  }
1700
1700
  function basePickBy(object2, paths, predicate) {
1701
1701
  var index = -1, length = paths.length, result2 = {};
1702
1702
  while (++index < length) {
1703
- var path70 = paths[index], value = baseGet(object2, path70);
1704
- if (predicate(value, path70)) {
1705
- baseSet(result2, castPath(path70, object2), value);
1703
+ var path72 = paths[index], value = baseGet(object2, path72);
1704
+ if (predicate(value, path72)) {
1705
+ baseSet(result2, castPath(path72, object2), value);
1706
1706
  }
1707
1707
  }
1708
1708
  return result2;
1709
1709
  }
1710
- function basePropertyDeep(path70) {
1710
+ function basePropertyDeep(path72) {
1711
1711
  return function(object2) {
1712
- return baseGet(object2, path70);
1712
+ return baseGet(object2, path72);
1713
1713
  };
1714
1714
  }
1715
1715
  function basePullAll(array2, values2, iteratee2, comparator) {
@@ -1783,14 +1783,14 @@ var require_lodash = __commonJS({
1783
1783
  var array2 = values(collection);
1784
1784
  return shuffleSelf(array2, baseClamp(n, 0, array2.length));
1785
1785
  }
1786
- function baseSet(object2, path70, value, customizer) {
1786
+ function baseSet(object2, path72, value, customizer) {
1787
1787
  if (!isObject2(object2)) {
1788
1788
  return object2;
1789
1789
  }
1790
- path70 = castPath(path70, object2);
1791
- var index = -1, length = path70.length, lastIndex = length - 1, nested = object2;
1790
+ path72 = castPath(path72, object2);
1791
+ var index = -1, length = path72.length, lastIndex = length - 1, nested = object2;
1792
1792
  while (nested != null && ++index < length) {
1793
- var key2 = toKey(path70[index]), newValue = value;
1793
+ var key2 = toKey(path72[index]), newValue = value;
1794
1794
  if (key2 === "__proto__" || key2 === "constructor" || key2 === "prototype") {
1795
1795
  return object2;
1796
1796
  }
@@ -1798,7 +1798,7 @@ var require_lodash = __commonJS({
1798
1798
  var objValue = nested[key2];
1799
1799
  newValue = customizer ? customizer(objValue, key2, nested) : undefined2;
1800
1800
  if (newValue === undefined2) {
1801
- newValue = isObject2(objValue) ? objValue : isIndex(path70[index + 1]) ? [] : {};
1801
+ newValue = isObject2(objValue) ? objValue : isIndex(path72[index + 1]) ? [] : {};
1802
1802
  }
1803
1803
  }
1804
1804
  assignValue(nested, key2, newValue);
@@ -1964,14 +1964,14 @@ var require_lodash = __commonJS({
1964
1964
  }
1965
1965
  return result2;
1966
1966
  }
1967
- function baseUnset(object2, path70) {
1968
- path70 = castPath(path70, object2);
1969
- var index = -1, length = path70.length;
1967
+ function baseUnset(object2, path72) {
1968
+ path72 = castPath(path72, object2);
1969
+ var index = -1, length = path72.length;
1970
1970
  if (!length) {
1971
1971
  return true;
1972
1972
  }
1973
1973
  while (++index < length) {
1974
- var key2 = toKey(path70[index]);
1974
+ var key2 = toKey(path72[index]);
1975
1975
  if (key2 === "__proto__" && !hasOwnProperty.call(object2, "__proto__")) {
1976
1976
  return false;
1977
1977
  }
@@ -1979,11 +1979,11 @@ var require_lodash = __commonJS({
1979
1979
  return false;
1980
1980
  }
1981
1981
  }
1982
- var obj = parent(object2, path70);
1983
- return obj == null || delete obj[toKey(last(path70))];
1982
+ var obj = parent(object2, path72);
1983
+ return obj == null || delete obj[toKey(last(path72))];
1984
1984
  }
1985
- function baseUpdate(object2, path70, updater, customizer) {
1986
- return baseSet(object2, path70, updater(baseGet(object2, path70)), customizer);
1985
+ function baseUpdate(object2, path72, updater, customizer) {
1986
+ return baseSet(object2, path72, updater(baseGet(object2, path72)), customizer);
1987
1987
  }
1988
1988
  function baseWhile(array2, predicate, isDrop, fromRight) {
1989
1989
  var length = array2.length, index = fromRight ? length : -1;
@@ -2866,11 +2866,11 @@ var require_lodash = __commonJS({
2866
2866
  var match = source.match(reWrapDetails);
2867
2867
  return match ? match[1].split(reSplitDetails) : [];
2868
2868
  }
2869
- function hasPath(object2, path70, hasFunc) {
2870
- path70 = castPath(path70, object2);
2871
- var index = -1, length = path70.length, result2 = false;
2869
+ function hasPath(object2, path72, hasFunc) {
2870
+ path72 = castPath(path72, object2);
2871
+ var index = -1, length = path72.length, result2 = false;
2872
2872
  while (++index < length) {
2873
- var key2 = toKey(path70[index]);
2873
+ var key2 = toKey(path72[index]);
2874
2874
  if (!(result2 = object2 != null && hasFunc(object2, key2))) {
2875
2875
  break;
2876
2876
  }
@@ -3072,8 +3072,8 @@ var require_lodash = __commonJS({
3072
3072
  return apply(func, this, otherArgs);
3073
3073
  };
3074
3074
  }
3075
- function parent(object2, path70) {
3076
- return path70.length < 2 ? object2 : baseGet(object2, baseSlice(path70, 0, -1));
3075
+ function parent(object2, path72) {
3076
+ return path72.length < 2 ? object2 : baseGet(object2, baseSlice(path72, 0, -1));
3077
3077
  }
3078
3078
  function reorder(array2, indexes) {
3079
3079
  var arrLength = array2.length, length = nativeMin(indexes.length, arrLength), oldArray = copyArray(array2);
@@ -3093,8 +3093,8 @@ var require_lodash = __commonJS({
3093
3093
  return object2[key2];
3094
3094
  }
3095
3095
  var setData = shortOut(baseSetData);
3096
- var setTimeout2 = ctxSetTimeout || function(func, wait) {
3097
- return root.setTimeout(func, wait);
3096
+ var setTimeout2 = ctxSetTimeout || function(func, wait2) {
3097
+ return root.setTimeout(func, wait2);
3098
3098
  };
3099
3099
  var setToString = shortOut(baseSetToString);
3100
3100
  function setWrapToString(wrapper, reference, bitmask) {
@@ -3708,10 +3708,10 @@ var require_lodash = __commonJS({
3708
3708
  }
3709
3709
  return isString(collection) ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1 : !!length && baseIndexOf(collection, value, fromIndex) > -1;
3710
3710
  }
3711
- var invokeMap = baseRest(function(collection, path70, args) {
3712
- var index = -1, isFunc = typeof path70 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3711
+ var invokeMap = baseRest(function(collection, path72, args) {
3712
+ var index = -1, isFunc = typeof path72 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3713
3713
  baseEach(collection, function(value) {
3714
- result2[++index] = isFunc ? apply(path70, value, args) : baseInvoke(value, path70, args);
3714
+ result2[++index] = isFunc ? apply(path72, value, args) : baseInvoke(value, path72, args);
3715
3715
  });
3716
3716
  return result2;
3717
3717
  });
@@ -3864,16 +3864,16 @@ var require_lodash = __commonJS({
3864
3864
  result2.placeholder = curryRight.placeholder;
3865
3865
  return result2;
3866
3866
  }
3867
- function debounce(func, wait, options) {
3867
+ function debounce(func, wait2, options) {
3868
3868
  var lastArgs, lastThis, maxWait, result2, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
3869
3869
  if (typeof func != "function") {
3870
3870
  throw new TypeError2(FUNC_ERROR_TEXT);
3871
3871
  }
3872
- wait = toNumber(wait) || 0;
3872
+ wait2 = toNumber(wait2) || 0;
3873
3873
  if (isObject2(options)) {
3874
3874
  leading = !!options.leading;
3875
3875
  maxing = "maxWait" in options;
3876
- maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
3876
+ maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait2) : maxWait;
3877
3877
  trailing = "trailing" in options ? !!options.trailing : trailing;
3878
3878
  }
3879
3879
  function invokeFunc(time3) {
@@ -3885,16 +3885,16 @@ var require_lodash = __commonJS({
3885
3885
  }
3886
3886
  function leadingEdge(time3) {
3887
3887
  lastInvokeTime = time3;
3888
- timerId = setTimeout2(timerExpired, wait);
3888
+ timerId = setTimeout2(timerExpired, wait2);
3889
3889
  return leading ? invokeFunc(time3) : result2;
3890
3890
  }
3891
3891
  function remainingWait(time3) {
3892
- var timeSinceLastCall = time3 - lastCallTime, timeSinceLastInvoke = time3 - lastInvokeTime, timeWaiting = wait - timeSinceLastCall;
3892
+ var timeSinceLastCall = time3 - lastCallTime, timeSinceLastInvoke = time3 - lastInvokeTime, timeWaiting = wait2 - timeSinceLastCall;
3893
3893
  return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
3894
3894
  }
3895
3895
  function shouldInvoke(time3) {
3896
3896
  var timeSinceLastCall = time3 - lastCallTime, timeSinceLastInvoke = time3 - lastInvokeTime;
3897
- return lastCallTime === undefined2 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
3897
+ return lastCallTime === undefined2 || timeSinceLastCall >= wait2 || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
3898
3898
  }
3899
3899
  function timerExpired() {
3900
3900
  var time3 = now2();
@@ -3932,12 +3932,12 @@ var require_lodash = __commonJS({
3932
3932
  }
3933
3933
  if (maxing) {
3934
3934
  clearTimeout2(timerId);
3935
- timerId = setTimeout2(timerExpired, wait);
3935
+ timerId = setTimeout2(timerExpired, wait2);
3936
3936
  return invokeFunc(lastCallTime);
3937
3937
  }
3938
3938
  }
3939
3939
  if (timerId === undefined2) {
3940
- timerId = setTimeout2(timerExpired, wait);
3940
+ timerId = setTimeout2(timerExpired, wait2);
3941
3941
  }
3942
3942
  return result2;
3943
3943
  }
@@ -3948,8 +3948,8 @@ var require_lodash = __commonJS({
3948
3948
  var defer = baseRest(function(func, args) {
3949
3949
  return baseDelay(func, 1, args);
3950
3950
  });
3951
- var delay = baseRest(function(func, wait, args) {
3952
- return baseDelay(func, toNumber(wait) || 0, args);
3951
+ var delay = baseRest(function(func, wait2, args) {
3952
+ return baseDelay(func, toNumber(wait2) || 0, args);
3953
3953
  });
3954
3954
  function flip(func) {
3955
3955
  return createWrap(func, WRAP_FLIP_FLAG);
@@ -4035,7 +4035,7 @@ var require_lodash = __commonJS({
4035
4035
  return apply(func, this, otherArgs);
4036
4036
  });
4037
4037
  }
4038
- function throttle(func, wait, options) {
4038
+ function throttle(func, wait2, options) {
4039
4039
  var leading = true, trailing = true;
4040
4040
  if (typeof func != "function") {
4041
4041
  throw new TypeError2(FUNC_ERROR_TEXT);
@@ -4044,9 +4044,9 @@ var require_lodash = __commonJS({
4044
4044
  leading = "leading" in options ? !!options.leading : leading;
4045
4045
  trailing = "trailing" in options ? !!options.trailing : trailing;
4046
4046
  }
4047
- return debounce(func, wait, {
4047
+ return debounce(func, wait2, {
4048
4048
  "leading": leading,
4049
- "maxWait": wait,
4049
+ "maxWait": wait2,
4050
4050
  "trailing": trailing
4051
4051
  });
4052
4052
  }
@@ -4363,15 +4363,15 @@ var require_lodash = __commonJS({
4363
4363
  function functionsIn(object2) {
4364
4364
  return object2 == null ? [] : baseFunctions(object2, keysIn(object2));
4365
4365
  }
4366
- function get(object2, path70, defaultValue) {
4367
- var result2 = object2 == null ? undefined2 : baseGet(object2, path70);
4366
+ function get(object2, path72, defaultValue) {
4367
+ var result2 = object2 == null ? undefined2 : baseGet(object2, path72);
4368
4368
  return result2 === undefined2 ? defaultValue : result2;
4369
4369
  }
4370
- function has(object2, path70) {
4371
- return object2 != null && hasPath(object2, path70, baseHas);
4370
+ function has(object2, path72) {
4371
+ return object2 != null && hasPath(object2, path72, baseHas);
4372
4372
  }
4373
- function hasIn(object2, path70) {
4374
- return object2 != null && hasPath(object2, path70, baseHasIn);
4373
+ function hasIn(object2, path72) {
4374
+ return object2 != null && hasPath(object2, path72, baseHasIn);
4375
4375
  }
4376
4376
  var invert = createInverter(function(result2, value, key2) {
4377
4377
  if (value != null && typeof value.toString != "function") {
@@ -4424,10 +4424,10 @@ var require_lodash = __commonJS({
4424
4424
  return result2;
4425
4425
  }
4426
4426
  var isDeep = false;
4427
- paths = arrayMap(paths, function(path70) {
4428
- path70 = castPath(path70, object2);
4429
- isDeep || (isDeep = path70.length > 1);
4430
- return path70;
4427
+ paths = arrayMap(paths, function(path72) {
4428
+ path72 = castPath(path72, object2);
4429
+ isDeep || (isDeep = path72.length > 1);
4430
+ return path72;
4431
4431
  });
4432
4432
  copyObject(object2, getAllKeysIn(object2), result2);
4433
4433
  if (isDeep) {
@@ -4453,19 +4453,19 @@ var require_lodash = __commonJS({
4453
4453
  return [prop];
4454
4454
  });
4455
4455
  predicate = getIteratee(predicate);
4456
- return basePickBy(object2, props, function(value, path70) {
4457
- return predicate(value, path70[0]);
4456
+ return basePickBy(object2, props, function(value, path72) {
4457
+ return predicate(value, path72[0]);
4458
4458
  });
4459
4459
  }
4460
- function result(object2, path70, defaultValue) {
4461
- path70 = castPath(path70, object2);
4462
- var index = -1, length = path70.length;
4460
+ function result(object2, path72, defaultValue) {
4461
+ path72 = castPath(path72, object2);
4462
+ var index = -1, length = path72.length;
4463
4463
  if (!length) {
4464
4464
  length = 1;
4465
4465
  object2 = undefined2;
4466
4466
  }
4467
4467
  while (++index < length) {
4468
- var value = object2 == null ? undefined2 : object2[toKey(path70[index])];
4468
+ var value = object2 == null ? undefined2 : object2[toKey(path72[index])];
4469
4469
  if (value === undefined2) {
4470
4470
  index = length;
4471
4471
  value = defaultValue;
@@ -4474,12 +4474,12 @@ var require_lodash = __commonJS({
4474
4474
  }
4475
4475
  return object2;
4476
4476
  }
4477
- function set2(object2, path70, value) {
4478
- return object2 == null ? object2 : baseSet(object2, path70, value);
4477
+ function set2(object2, path72, value) {
4478
+ return object2 == null ? object2 : baseSet(object2, path72, value);
4479
4479
  }
4480
- function setWith(object2, path70, value, customizer) {
4480
+ function setWith(object2, path72, value, customizer) {
4481
4481
  customizer = typeof customizer == "function" ? customizer : undefined2;
4482
- return object2 == null ? object2 : baseSet(object2, path70, value, customizer);
4482
+ return object2 == null ? object2 : baseSet(object2, path72, value, customizer);
4483
4483
  }
4484
4484
  var toPairs = createToPairs(keys);
4485
4485
  var toPairsIn = createToPairs(keysIn);
@@ -4501,15 +4501,15 @@ var require_lodash = __commonJS({
4501
4501
  });
4502
4502
  return accumulator;
4503
4503
  }
4504
- function unset(object2, path70) {
4505
- return object2 == null ? true : baseUnset(object2, path70);
4504
+ function unset(object2, path72) {
4505
+ return object2 == null ? true : baseUnset(object2, path72);
4506
4506
  }
4507
- function update(object2, path70, updater) {
4508
- return object2 == null ? object2 : baseUpdate(object2, path70, castFunction(updater));
4507
+ function update(object2, path72, updater) {
4508
+ return object2 == null ? object2 : baseUpdate(object2, path72, castFunction(updater));
4509
4509
  }
4510
- function updateWith(object2, path70, updater, customizer) {
4510
+ function updateWith(object2, path72, updater, customizer) {
4511
4511
  customizer = typeof customizer == "function" ? customizer : undefined2;
4512
- return object2 == null ? object2 : baseUpdate(object2, path70, castFunction(updater), customizer);
4512
+ return object2 == null ? object2 : baseUpdate(object2, path72, castFunction(updater), customizer);
4513
4513
  }
4514
4514
  function values(object2) {
4515
4515
  return object2 == null ? [] : baseValues(object2, keys(object2));
@@ -4895,17 +4895,17 @@ var require_lodash = __commonJS({
4895
4895
  function matches(source) {
4896
4896
  return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
4897
4897
  }
4898
- function matchesProperty(path70, srcValue) {
4899
- return baseMatchesProperty(path70, baseClone(srcValue, CLONE_DEEP_FLAG));
4898
+ function matchesProperty(path72, srcValue) {
4899
+ return baseMatchesProperty(path72, baseClone(srcValue, CLONE_DEEP_FLAG));
4900
4900
  }
4901
- var method = baseRest(function(path70, args) {
4901
+ var method = baseRest(function(path72, args) {
4902
4902
  return function(object2) {
4903
- return baseInvoke(object2, path70, args);
4903
+ return baseInvoke(object2, path72, args);
4904
4904
  };
4905
4905
  });
4906
4906
  var methodOf = baseRest(function(object2, args) {
4907
- return function(path70) {
4908
- return baseInvoke(object2, path70, args);
4907
+ return function(path72) {
4908
+ return baseInvoke(object2, path72, args);
4909
4909
  };
4910
4910
  });
4911
4911
  function mixin(object2, source, options) {
@@ -4952,12 +4952,12 @@ var require_lodash = __commonJS({
4952
4952
  var over = createOver(arrayMap);
4953
4953
  var overEvery = createOver(arrayEvery);
4954
4954
  var overSome = createOver(arraySome);
4955
- function property(path70) {
4956
- return isKey(path70) ? baseProperty(toKey(path70)) : basePropertyDeep(path70);
4955
+ function property(path72) {
4956
+ return isKey(path72) ? baseProperty(toKey(path72)) : basePropertyDeep(path72);
4957
4957
  }
4958
4958
  function propertyOf(object2) {
4959
- return function(path70) {
4960
- return object2 == null ? undefined2 : baseGet(object2, path70);
4959
+ return function(path72) {
4960
+ return object2 == null ? undefined2 : baseGet(object2, path72);
4961
4961
  };
4962
4962
  }
4963
4963
  var range = createRange();
@@ -5410,12 +5410,12 @@ var require_lodash = __commonJS({
5410
5410
  LazyWrapper.prototype.findLast = function(predicate) {
5411
5411
  return this.reverse().find(predicate);
5412
5412
  };
5413
- LazyWrapper.prototype.invokeMap = baseRest(function(path70, args) {
5414
- if (typeof path70 == "function") {
5413
+ LazyWrapper.prototype.invokeMap = baseRest(function(path72, args) {
5414
+ if (typeof path72 == "function") {
5415
5415
  return new LazyWrapper(this);
5416
5416
  }
5417
5417
  return this.map(function(value) {
5418
- return baseInvoke(value, path70, args);
5418
+ return baseInvoke(value, path72, args);
5419
5419
  });
5420
5420
  });
5421
5421
  LazyWrapper.prototype.reject = function(predicate) {
@@ -6366,10 +6366,10 @@ function mergeDefs(...defs) {
6366
6366
  function cloneDef(schema) {
6367
6367
  return mergeDefs(schema._zod.def);
6368
6368
  }
6369
- function getElementAtPath(obj, path70) {
6370
- if (!path70)
6369
+ function getElementAtPath(obj, path72) {
6370
+ if (!path72)
6371
6371
  return obj;
6372
- return path70.reduce((acc, key2) => acc?.[key2], obj);
6372
+ return path72.reduce((acc, key2) => acc?.[key2], obj);
6373
6373
  }
6374
6374
  function promiseAllObject(promisesObj) {
6375
6375
  const keys = Object.keys(promisesObj);
@@ -6709,11 +6709,11 @@ function explicitlyAborted(x, startIndex = 0) {
6709
6709
  }
6710
6710
  return false;
6711
6711
  }
6712
- function prefixIssues(path70, issues) {
6712
+ function prefixIssues(path72, issues) {
6713
6713
  return issues.map((iss) => {
6714
6714
  var _a3;
6715
6715
  (_a3 = iss).path ?? (_a3.path = []);
6716
- iss.path.unshift(path70);
6716
+ iss.path.unshift(path72);
6717
6717
  return iss;
6718
6718
  });
6719
6719
  }
@@ -7163,16 +7163,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
7163
7163
  }
7164
7164
  function formatError(error62, mapper = (issue2) => issue2.message) {
7165
7165
  const fieldErrors = { _errors: [] };
7166
- const processError = (error63, path70 = []) => {
7166
+ const processError = (error63, path72 = []) => {
7167
7167
  for (const issue2 of error63.issues) {
7168
7168
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7169
- issue2.errors.map((issues) => processError({ issues }, [...path70, ...issue2.path]));
7169
+ issue2.errors.map((issues) => processError({ issues }, [...path72, ...issue2.path]));
7170
7170
  } else if (issue2.code === "invalid_key") {
7171
- processError({ issues: issue2.issues }, [...path70, ...issue2.path]);
7171
+ processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
7172
7172
  } else if (issue2.code === "invalid_element") {
7173
- processError({ issues: issue2.issues }, [...path70, ...issue2.path]);
7173
+ processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
7174
7174
  } else {
7175
- const fullpath = [...path70, ...issue2.path];
7175
+ const fullpath = [...path72, ...issue2.path];
7176
7176
  if (fullpath.length === 0) {
7177
7177
  fieldErrors._errors.push(mapper(issue2));
7178
7178
  } else {
@@ -7211,17 +7211,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
7211
7211
  }
7212
7212
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
7213
7213
  const result = { errors: [] };
7214
- const processError = (error63, path70 = []) => {
7214
+ const processError = (error63, path72 = []) => {
7215
7215
  var _a3;
7216
7216
  for (const issue2 of error63.issues) {
7217
7217
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7218
- issue2.errors.map((issues) => processError({ issues }, [...path70, ...issue2.path]));
7218
+ issue2.errors.map((issues) => processError({ issues }, [...path72, ...issue2.path]));
7219
7219
  } else if (issue2.code === "invalid_key") {
7220
- processError({ issues: issue2.issues }, [...path70, ...issue2.path]);
7220
+ processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
7221
7221
  } else if (issue2.code === "invalid_element") {
7222
- processError({ issues: issue2.issues }, [...path70, ...issue2.path]);
7222
+ processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
7223
7223
  } else {
7224
- const fullpath = [...path70, ...issue2.path];
7224
+ const fullpath = [...path72, ...issue2.path];
7225
7225
  if (fullpath.length === 0) {
7226
7226
  result.errors.push(mapper(issue2));
7227
7227
  continue;
@@ -7260,8 +7260,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
7260
7260
  }
7261
7261
  function toDotPath(_path) {
7262
7262
  const segs = [];
7263
- const path70 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7264
- for (const seg of path70) {
7263
+ const path72 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7264
+ for (const seg of path72) {
7265
7265
  if (typeof seg === "number")
7266
7266
  segs.push(`[${seg}]`);
7267
7267
  else if (typeof seg === "symbol")
@@ -24363,13 +24363,13 @@ function resolveRef(ref, ctx) {
24363
24363
  if (!ref.startsWith("#")) {
24364
24364
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24365
24365
  }
24366
- const path70 = ref.slice(1).split("/").filter(Boolean);
24367
- if (path70.length === 0) {
24366
+ const path72 = ref.slice(1).split("/").filter(Boolean);
24367
+ if (path72.length === 0) {
24368
24368
  return ctx.rootSchema;
24369
24369
  }
24370
24370
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24371
- if (path70[0] === defsKey) {
24372
- const key2 = path70[1] === void 0 ? void 0 : decodeJSONPointerSegment(path70[1]);
24371
+ if (path72[0] === defsKey) {
24372
+ const key2 = path72[1] === void 0 ? void 0 : decodeJSONPointerSegment(path72[1]);
24373
24373
  if (!key2 || !ctx.defs[key2]) {
24374
24374
  throw new Error(`Reference not found: ${ref}`);
24375
24375
  }
@@ -26728,6 +26728,9 @@ var ProjectsSchema = external_exports.strictObject({
26728
26728
  ),
26729
26729
  wsbShare: external_exports.boolean().describe(
26730
26730
  "On Windows 11 24H2+ with the Windows Sandbox command line (wsb), add other folders to the running sandbox with `wsb share` (untested). Otherwise starting a project outside every root offers a restart."
26731
+ ),
26732
+ liveFolders: external_exports.enum(["off", "hcs"]).describe(
26733
+ 'ALPHA, UNTESTED ON A REAL PC: "hcs" adds a project folder to the running sandbox through the Host Compute Service where `wsb share` is missing (one administrator prompt per add or remove; always read-only in this alpha). If it fails, the sandbox may close: save your work first. Turn it on before the sandbox starts. "off" (default) offers a restart instead. The real-PC tests still to pass are in docs/design/hcs-live-folders.md ("Test plan").'
26731
26734
  )
26732
26735
  });
26733
26736
 
@@ -27338,8 +27341,16 @@ var RunDir = class {
27338
27341
  projectsDir;
27339
27342
  /** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
27340
27343
  auditDir;
27344
+ /**
27345
+ * Each running session's process tree, recorded by its ptyhost (guest only: the daemon ends what a ptyhost that was
27346
+ * itself ended left running).
27347
+ */
27348
+ treesDir;
27341
27349
  /** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
27342
27350
  secretsDir;
27351
+ /** Live folders (live.ts): signed host requests, and the daemon's replies. */
27352
+ liveDir;
27353
+ liveRepliesDir;
27343
27354
  constructor(dataDir2) {
27344
27355
  this.root = path7.join(dataDir2, "run");
27345
27356
  this.sandboxFile = path7.join(this.root, "sandbox.json");
@@ -27351,7 +27362,16 @@ var RunDir = class {
27351
27362
  this.sessionsDir = path7.join(this.root, "sessions");
27352
27363
  this.projectsDir = path7.join(this.root, "projects");
27353
27364
  this.auditDir = path7.join(this.root, "audit");
27365
+ this.treesDir = path7.join(this.root, "trees");
27354
27366
  this.secretsDir = path7.join(dataDir2, "secrets");
27367
+ this.liveDir = path7.join(this.root, "live");
27368
+ this.liveRepliesDir = path7.join(this.root, "live-replies");
27369
+ }
27370
+ liveFile(id) {
27371
+ return path7.join(this.liveDir, safeId(id) + ".json");
27372
+ }
27373
+ liveReplyFile(id) {
27374
+ return path7.join(this.liveRepliesDir, safeId(id) + ".json");
27355
27375
  }
27356
27376
  requestFile(id) {
27357
27377
  return path7.join(this.requestsDir, safeId(id) + ".json");
@@ -27362,6 +27382,9 @@ var RunDir = class {
27362
27382
  sessionFile(id) {
27363
27383
  return path7.join(this.sessionsDir, safeId(id) + ".json");
27364
27384
  }
27385
+ treeFile(id) {
27386
+ return path7.join(this.treesDir, safeId(id) + ".json");
27387
+ }
27365
27388
  projectFile(name) {
27366
27389
  return path7.join(this.projectsDir, safeId(name) + ".json");
27367
27390
  }
@@ -27946,7 +27969,9 @@ var SecretsFileSchema = external_exports.strictObject({
27946
27969
  /** The checked WireGuard config of vpn.provider wireguard-file (holds the private key). */
27947
27970
  wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
27948
27971
  /** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
27949
- githubToken: GithubTokenSchema.optional()
27972
+ githubToken: GithubTokenSchema.optional(),
27973
+ /** projects.liveFolders "hcs": this launch's key for signed live-folder requests (live.ts). */
27974
+ liveFoldersKey: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
27950
27975
  });
27951
27976
  var withEnvironment = (harness, environment) => environment ? { ...harness, environment: { ...harness.environment, ...environment } } : harness;
27952
27977
  function mergeRequestSecrets(request, secrets) {
@@ -27996,13 +28021,19 @@ function applyBootEnvironment(environment) {
27996
28021
  function adoptBootSecrets() {
27997
28022
  const text = process.env[BOOT_SECRETS_VARIABLE];
27998
28023
  delete process.env[BOOT_SECRETS_VARIABLE];
27999
- if (!text) return;
28024
+ if (!text) return void 0;
28000
28025
  try {
28001
- const parsed = SecretsFileSchema.pick({ harnessEnvironment: true }).safeParse(JSON.parse(text));
28002
- if (parsed.success) applyBootEnvironment(parsed.data.harnessEnvironment);
28026
+ const parsed = SecretsFileSchema.pick({ harnessEnvironment: true, liveFoldersKey: true }).safeParse(
28027
+ JSON.parse(text)
28028
+ );
28029
+ if (parsed.success) {
28030
+ applyBootEnvironment(parsed.data.harnessEnvironment);
28031
+ return parsed.data.liveFoldersKey;
28032
+ }
28003
28033
  } catch {
28004
- warn("The boot secrets given to the daemon were not valid.");
28005
28034
  }
28035
+ warn("The boot secrets given to the daemon were not valid.");
28036
+ return void 0;
28006
28037
  }
28007
28038
  function withRequestSecrets(req) {
28008
28039
  if (req.kind !== "session" && req.kind !== "project") return req;
@@ -28010,7 +28041,7 @@ function withRequestSecrets(req) {
28010
28041
  }
28011
28042
 
28012
28043
  // src/guest/daemon/daemon.ts
28013
- import fs55 from "node:fs";
28044
+ import fs57 from "node:fs";
28014
28045
 
28015
28046
  // src/guest/setup/claude-mem.ts
28016
28047
  import fs15 from "node:fs";
@@ -28208,15 +28239,15 @@ function agentPaths(toolsDir2, name, harness) {
28208
28239
  function agentCommand(name, harness) {
28209
28240
  return harness.npmBin ?? harness.uvBin ?? (harness.hostExecutable ?? name).replace(/\.exe$/i, "");
28210
28241
  }
28211
- function localStateEntries(agents2, stateDir2, localRoot2) {
28242
+ function localStateEntries(agents2, stateDir3, localRoot2) {
28212
28243
  return Object.entries(agents2).flatMap(
28213
28244
  ([agent, harness]) => Object.entries(harness.localState ?? {}).map(([env, folder]) => ({
28214
28245
  agent,
28215
28246
  env,
28216
- store: path20.join(stateDir2, agent, folder),
28247
+ store: path20.join(stateDir3, agent, folder),
28217
28248
  local: path20.join(localRoot2, agent, folder),
28218
28249
  processes: [agentCommand(agent, harness) + ".exe"],
28219
- legacy: path20.join(stateDir2, agent)
28250
+ legacy: path20.join(stateDir3, agent)
28220
28251
  }))
28221
28252
  );
28222
28253
  }
@@ -29981,7 +30012,8 @@ var SOURCES = {
29981
30012
  cargoshim: "CargoShim.cs",
29982
30013
  linkgate: "LinkGate.cs",
29983
30014
  pathsync: "PathSync.cs",
29984
- memgov: "MemGov.cs"
30015
+ memgov: "MemGov.cs",
30016
+ bindmount: "BindMount.cs"
29985
30017
  };
29986
30018
  function sourceOf(name) {
29987
30019
  return path42.join(launchDir, "sandbox", "csharp", SOURCES[name]);
@@ -32426,7 +32458,7 @@ function shellLaunch(asked, paths) {
32426
32458
  // src/guest/sessions/pty-host.ts
32427
32459
  import fs50 from "node:fs";
32428
32460
  import path65 from "node:path";
32429
- import { spawn as spawn6 } from "node:child_process";
32461
+ import { execFile, spawn as spawn6 } from "node:child_process";
32430
32462
  function ensurePtyHost() {
32431
32463
  return ensureCompiled("ptyhost");
32432
32464
  }
@@ -32458,7 +32490,12 @@ var conptyDll = () => {
32458
32490
  return session.provisioning.conpty?.enabled !== false && fs50.existsSync(dll) && fs50.existsSync(path65.join(toolsDir, "conpty", "OpenConsole.exe")) ? dll : null;
32459
32491
  };
32460
32492
  function startPtyHost(o) {
32461
- const env = { ...o.env, PTYHOST_BIND: o.remote ? "any" : "loopback" };
32493
+ fs50.mkdirSync(run.treesDir, { recursive: true });
32494
+ const env = {
32495
+ ...o.env,
32496
+ PTYHOST_BIND: o.remote ? "any" : "loopback",
32497
+ PTYHOST_TREE_FILE: run.treeFile(o.id)
32498
+ };
32462
32499
  delete env.PTYHOST_CONPTY;
32463
32500
  const dll = conptyDll();
32464
32501
  if (dll) env.PTYHOST_CONPTY = dll;
@@ -32468,6 +32505,29 @@ function startPtyHost(o) {
32468
32505
  { cwd: o.cwd, env, detached: true, stdio: "ignore", windowsHide: true }
32469
32506
  );
32470
32507
  }
32508
+ var END_TREE_MS = 3e4;
32509
+ function endLeftoverTree(id, exe = ensurePtyHost()) {
32510
+ const file3 = run.treeFile(id);
32511
+ if (!fs50.existsSync(file3)) return Promise.resolve(null);
32512
+ return new Promise((resolve2) => {
32513
+ execFile(exe, ["--end-tree", file3], { timeout: END_TREE_MS, windowsHide: true }, (error62, stdout) => {
32514
+ const code = error62 ? typeof error62.code === "number" ? error62.code : -1 : 0;
32515
+ if (code !== 3)
32516
+ try {
32517
+ fs50.rmSync(file3, { force: true });
32518
+ } catch {
32519
+ }
32520
+ resolve2(code === 0 ? stdout.trim().slice(0, 200) : code === 3 ? null : "could not end them (code " + code + ")");
32521
+ });
32522
+ });
32523
+ }
32524
+ function recordedTrees() {
32525
+ try {
32526
+ return fs50.readdirSync(run.treesDir).filter((n) => /^[A-Za-z0-9_-]{1,64}\.json$/.test(n)).map((n) => n.slice(0, -".json".length));
32527
+ } catch {
32528
+ return [];
32529
+ }
32530
+ }
32471
32531
 
32472
32532
  // src/guest/agents/agent-installer.ts
32473
32533
  import fs51 from "node:fs";
@@ -32797,7 +32857,23 @@ var SessionManager = class {
32797
32857
  }
32798
32858
  rootStarted(id, child, from) {
32799
32859
  if (child.pid) this.ptyHosts.set(id, { session: id, pid: child.pid, from });
32800
- child.once("exit", () => this.rootEnded(id));
32860
+ child.once("exit", () => {
32861
+ this.rootEnded(id);
32862
+ this.endLeftovers(id);
32863
+ });
32864
+ }
32865
+ /** What a session's ptyhost left running when it was itself ended (Task Manager, a crash) is ended now. */
32866
+ endLeftovers(id) {
32867
+ void endLeftoverTree(id).then((done) => {
32868
+ if (done) log("Session " + id + ": its session host was ended from outside; " + done + " it left running");
32869
+ }).catch((e) => warn("Ending what session " + id + " left running failed: " + errMsg(e)));
32870
+ }
32871
+ /**
32872
+ * At the daemon's start: trees recorded by session hosts that are gone (a daemon that ended with them) are ended
32873
+ * too. One whose session host still runs is left alone (ptyhost --end-tree checks).
32874
+ */
32875
+ sweepLeftovers() {
32876
+ for (const id of recordedTrees()) if (!this.live.has(id)) this.endLeftovers(id);
32801
32877
  }
32802
32878
  rootEnded(id) {
32803
32879
  const r = this.ptyHosts.get(id);
@@ -33446,6 +33522,315 @@ var Governor = class {
33446
33522
  };
33447
33523
  var governor = new Governor();
33448
33524
 
33525
+ // src/guest/daemon/live.ts
33526
+ import fs56 from "node:fs";
33527
+ import path71 from "node:path";
33528
+ import { spawnSync as spawnSync7 } from "node:child_process";
33529
+
33530
+ // src/guest/daemon/live-folders.ts
33531
+ import fs55 from "node:fs";
33532
+ import path70 from "node:path";
33533
+
33534
+ // src/shared/channel/live.ts
33535
+ import crypto5 from "node:crypto";
33536
+ var LIVE_SHARE_NAME = /^agentsbx-[0-9a-f]{8,32}$/;
33537
+ var LIVE_FOLDER_NAME = /^[a-z0-9][a-z0-9_-]{0,63}$/;
33538
+ var LIVE_KEY = /^[0-9a-f]{64}$/;
33539
+ var LIVE_TOKEN = /^[0-9a-f]{32}$/;
33540
+ var LIVE_MAX_AGE_MS = 2 * 60 * 1e3;
33541
+ var MAX_PAYLOAD = 4096;
33542
+ var LivePayloadSchema = external_exports.strictObject({
33543
+ v: external_exports.literal(1),
33544
+ /** canary: show the share, read token.txt, hide it again and reply with the token; map / unmap: the real folder. */
33545
+ kind: external_exports.enum(["canary", "map", "unmap"]),
33546
+ id: IdSchema,
33547
+ launchId: external_exports.string().min(1).max(64),
33548
+ share: external_exports.string().regex(LIVE_SHARE_NAME).optional(),
33549
+ folder: external_exports.string().regex(LIVE_FOLDER_NAME),
33550
+ readOnly: external_exports.boolean(),
33551
+ createdAt: external_exports.string().max(64)
33552
+ });
33553
+ var LiveEnvelopeSchema = external_exports.strictObject({
33554
+ payload: external_exports.string().min(2).max(MAX_PAYLOAD),
33555
+ mac: external_exports.string().regex(/^[0-9a-f]{64}$/)
33556
+ });
33557
+ var LiveReplySchema = external_exports.strictObject({
33558
+ id: IdSchema,
33559
+ ok: external_exports.boolean(),
33560
+ message: external_exports.string().max(1e3),
33561
+ token: external_exports.string().regex(LIVE_TOKEN).optional(),
33562
+ finishedAt: external_exports.string().max(64)
33563
+ });
33564
+ function mac3(key2, payload) {
33565
+ return crypto5.createHmac("sha256", Buffer.from(key2, "hex")).update(payload, "utf8").digest("hex");
33566
+ }
33567
+ function openLive(key2, envelope, o) {
33568
+ if (!key2 || !LIVE_KEY.test(key2))
33569
+ return { refused: "no live-folder key (live folders were off when the sandbox started)" };
33570
+ const env = LiveEnvelopeSchema.safeParse(envelope);
33571
+ if (!env.success) return { refused: "not a live-folder request" };
33572
+ const want = Buffer.from(mac3(key2, env.data.payload), "hex");
33573
+ const got = Buffer.from(env.data.mac, "hex");
33574
+ if (want.length !== got.length || !crypto5.timingSafeEqual(want, got))
33575
+ return { refused: "the signature does not match" };
33576
+ let json2;
33577
+ try {
33578
+ json2 = JSON.parse(env.data.payload);
33579
+ } catch {
33580
+ return { refused: "the signed payload is not JSON" };
33581
+ }
33582
+ const parsed = LivePayloadSchema.safeParse(json2);
33583
+ if (!parsed.success) return { refused: "the signed payload has the wrong shape" };
33584
+ const p = parsed.data;
33585
+ if (p.launchId !== o.launchId) return { refused: "it is for another launch" };
33586
+ const at = Date.parse(p.createdAt);
33587
+ if (!Number.isFinite(at) || Math.abs(o.now - at) > LIVE_MAX_AGE_MS) return { refused: "it is too old" };
33588
+ if (p.kind !== "unmap" && !p.share) return { refused: "it names no share" };
33589
+ return { payload: p };
33590
+ }
33591
+
33592
+ // src/guest/daemon/live-folders.ts
33593
+ var MAX_REQUEST_BYTES = 16 * 1024;
33594
+ var MAX_SEEN = 512;
33595
+ var EXIT_OK = 0;
33596
+ var EXIT_NO_SHARE = 3;
33597
+ var EXIT_NOT_MAPPED = 4;
33598
+ var StateSchema = external_exports.object({
33599
+ key: external_exports.string().regex(LIVE_KEY).nullable(),
33600
+ launchId: external_exports.string().max(64),
33601
+ seen: external_exports.array(external_exports.object({ id: external_exports.string().max(64), at: external_exports.number() })).max(MAX_SEEN),
33602
+ mappings: external_exports.array(
33603
+ external_exports.object({
33604
+ folder: external_exports.string().regex(LIVE_FOLDER_NAME),
33605
+ share: external_exports.string().regex(LIVE_SHARE_NAME),
33606
+ readOnly: external_exports.boolean()
33607
+ })
33608
+ ).max(256)
33609
+ });
33610
+ var wait = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
33611
+ var LiveFolderHandler = class {
33612
+ constructor(o) {
33613
+ this.o = o;
33614
+ }
33615
+ o;
33616
+ queue = Promise.resolve();
33617
+ now() {
33618
+ return (this.o.now ?? Date.now)();
33619
+ }
33620
+ log(line) {
33621
+ this.o.log?.(line);
33622
+ }
33623
+ read() {
33624
+ try {
33625
+ const text = fs55.readFileSync(this.o.stateFile, "utf8");
33626
+ const parsed = StateSchema.safeParse(JSON.parse(text));
33627
+ if (parsed.success && parsed.data.launchId === this.o.launchId) return parsed.data;
33628
+ } catch {
33629
+ }
33630
+ return { key: null, launchId: this.o.launchId, seen: [], mappings: [] };
33631
+ }
33632
+ save(state) {
33633
+ fs55.mkdirSync(path70.dirname(this.o.stateFile), { recursive: true });
33634
+ writeJsonAtomic(this.o.stateFile, state);
33635
+ }
33636
+ /** The key the boot handed over (from the one-shot secrets file). */
33637
+ setKey(key2) {
33638
+ if (!LIVE_KEY.test(key2)) return;
33639
+ this.save({ ...this.read(), key: key2 });
33640
+ }
33641
+ /** C:\Workspace\<name> from a checked name only. */
33642
+ folderPath(name) {
33643
+ if (!LIVE_FOLDER_NAME.test(name)) throw new Error("not a plain folder name");
33644
+ return path70.win32.join(this.o.workspaces ?? WORKSPACES_GUEST, name);
33645
+ }
33646
+ /** One pass over run\live: every file is claimed (deleted) at once; valid ones are handled one after another. */
33647
+ tick() {
33648
+ const dir = this.o.run.liveDir;
33649
+ let names;
33650
+ try {
33651
+ names = fs55.readdirSync(dir);
33652
+ } catch {
33653
+ return;
33654
+ }
33655
+ for (const name of names.slice(0, 64)) {
33656
+ if (name.endsWith(".tmp")) continue;
33657
+ const file3 = path70.join(dir, name);
33658
+ let envelope = null;
33659
+ try {
33660
+ const stat = fs55.lstatSync(file3);
33661
+ if (stat.isFile() && stat.size <= MAX_REQUEST_BYTES && /^[A-Za-z0-9_-]{1,64}\.json$/.test(name))
33662
+ envelope = JSON.parse(fs55.readFileSync(file3, "utf8"));
33663
+ } catch {
33664
+ envelope = null;
33665
+ } finally {
33666
+ try {
33667
+ fs55.rmSync(file3, { recursive: true, force: true });
33668
+ } catch {
33669
+ }
33670
+ }
33671
+ if (envelope === null) continue;
33672
+ this.queue = this.queue.then(() => this.handle(envelope)).catch((e) => this.log("live folder: " + errMsg(e)));
33673
+ }
33674
+ }
33675
+ /** Waits for what tick() queued (tests). */
33676
+ idle() {
33677
+ return this.queue;
33678
+ }
33679
+ async handle(envelope) {
33680
+ const state = this.read();
33681
+ const now2 = this.now();
33682
+ const opened = openLive(state.key, envelope, { launchId: this.o.launchId, now: now2 });
33683
+ if ("refused" in opened) {
33684
+ this.log("live folder request ignored: " + opened.refused);
33685
+ return;
33686
+ }
33687
+ const p = opened.payload;
33688
+ const seen = state.seen.filter((s) => now2 - s.at < 10 * 60 * 1e3);
33689
+ if (seen.some((s) => s.id === p.id)) {
33690
+ this.log("live folder request ignored: seen before (" + p.id + ")");
33691
+ return;
33692
+ }
33693
+ this.save({ ...state, seen: [...seen, { id: p.id, at: now2 }].slice(-MAX_SEEN) });
33694
+ let reply;
33695
+ try {
33696
+ reply = await this.act(p);
33697
+ } catch (e) {
33698
+ reply = { ok: false, message: errMsg(e).slice(0, 900) };
33699
+ }
33700
+ this.reply(p.id, reply);
33701
+ }
33702
+ reply(id, r) {
33703
+ try {
33704
+ fs55.mkdirSync(this.o.run.liveRepliesDir, { recursive: true });
33705
+ writeJsonAtomic(this.o.run.liveReplyFile(id), { id, ...r, finishedAt: new Date(this.now()).toISOString() });
33706
+ } catch (e) {
33707
+ this.log("live folder reply not written: " + errMsg(e));
33708
+ }
33709
+ }
33710
+ /** map with retries while the share is not there yet. */
33711
+ async mapWithRetry(folder, share, readOnly) {
33712
+ const tries = this.o.tries ?? 20;
33713
+ let code = EXIT_NO_SHARE;
33714
+ for (let i = 0; i < tries; i++) {
33715
+ code = this.o.bind.map(folder, share, readOnly);
33716
+ if (code !== EXIT_NO_SHARE) return code;
33717
+ await (this.o.sleep ?? wait)(500);
33718
+ }
33719
+ return code;
33720
+ }
33721
+ /** The folder must not exist yet: not as a folder, a file or a link. */
33722
+ assertFree(folder) {
33723
+ let exists2 = true;
33724
+ try {
33725
+ fs55.lstatSync(folder);
33726
+ } catch {
33727
+ exists2 = false;
33728
+ }
33729
+ if (exists2) throw new Error(folder + " exists already");
33730
+ const parent = path70.dirname(folder);
33731
+ fs55.mkdirSync(parent, { recursive: true });
33732
+ if (!fs55.lstatSync(parent).isDirectory()) throw new Error(parent + " is not a plain folder");
33733
+ }
33734
+ async act(p) {
33735
+ const folder = this.folderPath(p.folder);
33736
+ if (p.kind === "unmap") {
33737
+ const state2 = this.read();
33738
+ const known = state2.mappings.find((m) => m.folder === p.folder);
33739
+ if (!known) return { ok: false, message: "no live folder at " + folder };
33740
+ const code2 = this.o.bind.unmap(folder);
33741
+ if (code2 !== EXIT_OK || this.o.bind.mapped(folder) !== EXIT_NOT_MAPPED)
33742
+ return { ok: false, message: "the folder could not be hidden again (are files in it open?)" };
33743
+ const after = this.read();
33744
+ this.save({ ...after, mappings: after.mappings.filter((m) => m.folder !== p.folder) });
33745
+ return { ok: true, message: "hidden: " + folder };
33746
+ }
33747
+ const share = p.share ?? "";
33748
+ this.assertFree(folder);
33749
+ if (p.kind === "canary") {
33750
+ const code2 = await this.mapWithRetry(folder, share, true);
33751
+ if (code2 !== EXIT_OK) return { ok: false, message: "the test share could not be shown (" + code2 + ")" };
33752
+ try {
33753
+ const file3 = path70.join(folder, "token.txt");
33754
+ const stat = fs55.statSync(file3);
33755
+ const token = stat.size <= 64 ? fs55.readFileSync(file3, "utf8").trim() : "";
33756
+ return LIVE_TOKEN.test(token) ? { ok: true, message: "read the test share", token } : { ok: false, message: "the test share holds no token" };
33757
+ } finally {
33758
+ this.o.bind.unmap(folder);
33759
+ }
33760
+ }
33761
+ const code = await this.mapWithRetry(folder, share, p.readOnly);
33762
+ if (code !== EXIT_OK)
33763
+ return {
33764
+ ok: false,
33765
+ message: code === EXIT_NO_SHARE ? "the share did not reach the sandbox" : "the folder could not be shown (" + code + ")"
33766
+ };
33767
+ const state = this.read();
33768
+ this.save({
33769
+ ...state,
33770
+ mappings: [
33771
+ ...state.mappings.filter((m) => m.folder !== p.folder),
33772
+ { folder: p.folder, share, readOnly: p.readOnly }
33773
+ ]
33774
+ });
33775
+ return { ok: true, message: "shown at " + folder };
33776
+ }
33777
+ /** When the daemon starts: the recorded mappings this launch made, made again where they are gone. */
33778
+ reapply() {
33779
+ let done = 0;
33780
+ for (const m of this.read().mappings) {
33781
+ const folder = this.folderPath(m.folder);
33782
+ if (this.o.bind.mapped(folder) === EXIT_OK) continue;
33783
+ fs55.mkdirSync(path70.dirname(folder), { recursive: true });
33784
+ if (this.o.bind.map(folder, m.share, m.readOnly) === EXIT_OK) done++;
33785
+ else this.log("live folder " + folder + " could not be shown again");
33786
+ }
33787
+ return done;
33788
+ }
33789
+ };
33790
+
33791
+ // src/guest/daemon/live.ts
33792
+ var BIND_TIMEOUT_MS = 3e4;
33793
+ var testing = Boolean(process.env.AGENT_DAEMON_STATE_DIR || process.env.AGENT_LOCAL_DIR);
33794
+ var stateDir2 = process.env.AGENT_DAEMON_STATE_DIR ?? (process.env.AGENT_LOCAL_DIR ? path71.join(localDir, "daemon-state") : path71.join(process.env.ProgramData ?? "C:\\ProgramData", "AgentSandboxDaemon"));
33795
+ function bindMount(args) {
33796
+ const r = spawnSync7(ensureCompiled("bindmount"), args, {
33797
+ windowsHide: true,
33798
+ timeout: BIND_TIMEOUT_MS,
33799
+ encoding: "utf8"
33800
+ });
33801
+ return r.status ?? 1;
33802
+ }
33803
+ var realBind = {
33804
+ map: (folder, share, readOnly) => bindMount(["map", folder, share, ...readOnly ? [] : ["rw"]]),
33805
+ unmap: (folder) => bindMount(["unmap", folder]),
33806
+ mapped: (folder) => bindMount(["mapped", folder])
33807
+ };
33808
+ function protectStateDir() {
33809
+ fs56.mkdirSync(stateDir2, { recursive: true });
33810
+ if (!isWin || testMode || testing) return;
33811
+ spawnSync7(
33812
+ SYSTEM.icacls(),
33813
+ [stateDir2, "/inheritance:r", "/grant:r", "*S-1-5-32-544:(OI)(CI)F", "*S-1-5-18:(OI)(CI)F"],
33814
+ {
33815
+ windowsHide: true,
33816
+ timeout: BIND_TIMEOUT_MS
33817
+ }
33818
+ );
33819
+ }
33820
+ var liveFolders = new LiveFolderHandler({
33821
+ run,
33822
+ stateFile: path71.join(stateDir2, "live-folders.json"),
33823
+ launchId: session.launchId,
33824
+ bind: realBind,
33825
+ log: warn
33826
+ });
33827
+ function startLiveFolders(key2) {
33828
+ protectStateDir();
33829
+ if (key2) liveFolders.setKey(key2);
33830
+ const again = liveFolders.reapply();
33831
+ if (again) warn("Live folders: " + again + " shown again after the daemon restarted.");
33832
+ }
33833
+
33449
33834
  // src/guest/daemon/daemon.ts
33450
33835
  var POLL_MS = 400;
33451
33836
  var MEM_SAVE_MS = 12e4;
@@ -33464,14 +33849,15 @@ var Daemon = class {
33464
33849
  tick() {
33465
33850
  const { valid, invalid } = run.scanRequests();
33466
33851
  for (const file3 of invalid)
33467
- safely("removing an invalid request", () => fs55.rmSync(file3, { recursive: true, force: true }));
33852
+ safely("removing an invalid request", () => fs57.rmSync(file3, { recursive: true, force: true }));
33468
33853
  for (const req of valid) {
33469
- safely("claiming a request", () => fs55.rmSync(run.requestFile(req.id), { force: true }));
33854
+ safely("claiming a request", () => fs57.rmSync(run.requestFile(req.id), { force: true }));
33470
33855
  if (run.readSession(req.id)) continue;
33471
33856
  void Promise.resolve(this.handle(withRequestSecrets(req))).catch(
33472
33857
  (e) => respond(req.id, { ok: false, message: errMsg(e) })
33473
33858
  );
33474
33859
  }
33860
+ safely("live folders", () => liveFolders.tick());
33475
33861
  if (Date.now() - this.lastMemSave > MEM_SAVE_MS) {
33476
33862
  this.lastMemSave = Date.now();
33477
33863
  safely("claude-mem save", saveClaudeMem);
@@ -33501,10 +33887,12 @@ var Daemon = class {
33501
33887
  // src/guest/entries/daemon.ts
33502
33888
  process.on("uncaughtException", (e) => warn("daemon: unexpected error (continuing): " + (e.stack ?? errMsg(e))));
33503
33889
  process.on("unhandledRejection", (e) => warn("daemon: unexpected error (continuing): " + errMsg(e)));
33504
- adoptBootSecrets();
33890
+ var liveKey = adoptBootSecrets();
33505
33891
  log("Session daemon started (pid " + process.pid + ").");
33892
+ safely("live folders", () => startLiveFolders(liveKey));
33506
33893
  safely("port forwards", startRelays);
33507
33894
  safely("audit", () => startProcessCollector(() => sessions.roots()));
33895
+ safely("leftover processes", () => sessions.sweepLeftovers());
33508
33896
  safely("memory governor", () => governor.start());
33509
33897
  log("Memory governor: " + governor.describe());
33510
33898
  new Daemon().start();