windows-development-sandbox 1.1.0 → 1.4.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 (187) hide show
  1. package/README.md +3 -2
  2. package/config.example.json +38 -5
  3. package/dist/cli/args.d.ts +3 -0
  4. package/dist/cli/args.js +3 -1
  5. package/dist/cli/commands/accounts.js +2 -2
  6. package/dist/cli/commands/agent-commands.js +1 -1
  7. package/dist/cli/commands/context.js +2 -1
  8. package/dist/cli/commands/data/clean.js +6 -1
  9. package/dist/cli/commands/data/collect.js +3 -3
  10. package/dist/cli/commands/index.d.ts +1 -1
  11. package/dist/cli/commands/index.js +1 -1
  12. package/dist/cli/commands/launch.js +36 -3
  13. package/dist/cli/commands/maintenance.d.ts +2 -0
  14. package/dist/cli/commands/maintenance.js +35 -2
  15. package/dist/cli/commands/sessions.js +3 -3
  16. package/dist/cli/commands/user-config.js +1 -1
  17. package/dist/cli/index.js +6 -4
  18. package/dist/cli/manifest.js +5 -0
  19. package/dist/cli/menu/apps.d.ts +21 -0
  20. package/dist/cli/menu/apps.js +122 -0
  21. package/dist/cli/menu/command-form.d.ts +28 -0
  22. package/dist/cli/menu/command-form.js +219 -0
  23. package/dist/cli/menu/index.d.ts +26 -0
  24. package/dist/cli/menu/index.js +180 -0
  25. package/dist/cli/menu/settings/categories.d.ts +9 -0
  26. package/dist/cli/menu/settings/categories.js +28 -0
  27. package/dist/cli/menu/settings/config-file.d.ts +40 -0
  28. package/dist/cli/menu/settings/config-file.js +71 -0
  29. package/dist/cli/menu/settings/editors.d.ts +30 -0
  30. package/dist/cli/menu/settings/editors.js +305 -0
  31. package/dist/cli/menu/settings/index.d.ts +32 -0
  32. package/dist/cli/menu/settings/index.js +136 -0
  33. package/dist/cli/menu/settings/schema-node.d.ts +62 -0
  34. package/dist/cli/menu/settings/schema-node.js +104 -0
  35. package/dist/cli/{menu-multi.d.ts → menu/several.d.ts} +10 -2
  36. package/dist/cli/menu/several.js +102 -0
  37. package/dist/cli/tui/app.d.ts +39 -0
  38. package/dist/cli/tui/app.js +52 -0
  39. package/dist/cli/tui/dialogs.d.ts +57 -0
  40. package/dist/cli/tui/dialogs.js +162 -0
  41. package/dist/cli/tui/frame.d.ts +18 -0
  42. package/dist/cli/tui/frame.js +27 -0
  43. package/dist/cli/tui/index.d.ts +7 -0
  44. package/dist/cli/tui/index.js +8 -0
  45. package/dist/cli/tui/list-screen.d.ts +101 -0
  46. package/dist/cli/tui/list-screen.js +299 -0
  47. package/dist/cli/tui/terminal.d.ts +37 -0
  48. package/dist/cli/tui/terminal.js +89 -0
  49. package/dist/cli/tui/text.d.ts +20 -0
  50. package/dist/cli/tui/text.js +105 -0
  51. package/dist/cli/tui/theme.d.ts +45 -0
  52. package/dist/cli/tui/theme.js +30 -0
  53. package/dist/core/config.js +9 -6
  54. package/dist/core/local-config.d.ts +15 -0
  55. package/dist/core/local-config.js +63 -4
  56. package/dist/core/schema/apps.d.ts +40 -0
  57. package/dist/core/schema/apps.js +27 -0
  58. package/dist/core/schema/config.d.ts +66 -1
  59. package/dist/core/schema/config.js +18 -6
  60. package/dist/core/schema/profile.d.ts +5 -0
  61. package/dist/core/schema/profile.js +4 -2
  62. package/dist/core/schema/sandbox.d.ts +28 -0
  63. package/dist/core/schema/sandbox.js +28 -0
  64. package/dist/core/schema/toolchains.d.ts +3 -0
  65. package/dist/core/schema/toolchains.js +6 -1
  66. package/dist/core/types.d.ts +6 -0
  67. package/dist/core/util.d.ts +2 -0
  68. package/dist/core/util.js +2 -0
  69. package/dist/core/workspace.js +22 -5
  70. package/dist/guest/apps/index.d.ts +10 -0
  71. package/dist/guest/apps/index.js +206 -0
  72. package/dist/guest/apps/resolvers.d.ts +8 -0
  73. package/dist/guest/apps/resolvers.js +90 -0
  74. package/dist/guest/audit-parse.d.ts +7 -0
  75. package/dist/guest/audit-parse.js +24 -0
  76. package/dist/guest/audit.d.ts +4 -0
  77. package/dist/guest/audit.js +47 -0
  78. package/dist/guest/daemon/relays.d.ts +1 -0
  79. package/dist/guest/daemon/relays.js +18 -0
  80. package/dist/guest/daemon.js +4 -0
  81. package/dist/guest/env.d.ts +1 -0
  82. package/dist/guest/env.js +3 -1
  83. package/dist/guest/helpers.d.ts +1 -1
  84. package/dist/guest/main.js +15 -2
  85. package/dist/guest/netproxy.d.ts +1 -0
  86. package/dist/guest/netproxy.js +100 -0
  87. package/dist/guest/ptyhost.js +14 -4
  88. package/dist/guest/setup/claude.d.ts +0 -4
  89. package/dist/guest/setup/claude.js +48 -2
  90. package/dist/guest/setup/network.d.ts +9 -0
  91. package/dist/guest/setup/network.js +97 -4
  92. package/dist/guest/setup/user.js +4 -0
  93. package/dist/guest/toolchains/native/mesa.js +13 -3
  94. package/dist/guest/toolchains/plan.d.ts +3 -1
  95. package/dist/guest/toolchains/plan.js +53 -9
  96. package/dist/guest/toolchains/python.js +26 -2
  97. package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
  98. package/dist/guest/toolchains/vscode-profile.js +69 -0
  99. package/dist/guest/toolchains/vscode.d.ts +17 -0
  100. package/dist/guest/toolchains/vscode.js +87 -1
  101. package/dist/host/attach.js +2 -1
  102. package/dist/host/audit/collect.d.ts +34 -0
  103. package/dist/host/audit/collect.js +126 -0
  104. package/dist/host/audit/log.d.ts +46 -0
  105. package/dist/host/audit/log.js +143 -0
  106. package/dist/host/generate.d.ts +6 -0
  107. package/dist/host/generate.js +10 -0
  108. package/dist/host/launch/mappings.js +5 -1
  109. package/dist/host/launch/stage.js +1 -1
  110. package/dist/host/motw.d.ts +17 -0
  111. package/dist/host/motw.js +74 -0
  112. package/dist/host/platform.js +3 -0
  113. package/dist/host/port-forward.d.ts +8 -0
  114. package/dist/host/port-forward.js +37 -0
  115. package/dist/host/repo-guard.d.ts +10 -3
  116. package/dist/host/repo-guard.js +142 -14
  117. package/dist/host/stops.d.ts +67 -0
  118. package/dist/host/stops.js +126 -0
  119. package/dist/host/terminal.d.ts +8 -0
  120. package/dist/host/terminal.js +45 -1
  121. package/dist/host/workspace-view/index.d.ts +20 -0
  122. package/dist/host/workspace-view/index.js +53 -0
  123. package/dist/host/workspace-view/rules.d.ts +26 -0
  124. package/dist/host/workspace-view/rules.js +93 -0
  125. package/dist/host/workspace-view/view.d.ts +50 -0
  126. package/dist/host/workspace-view/view.js +281 -0
  127. package/dist/runtime/daemon.js +1319 -552
  128. package/dist/runtime/db.js +168 -13
  129. package/dist/runtime/main.js +2898 -608
  130. package/dist/runtime/netproxy.js +25936 -0
  131. package/dist/runtime/view.js +272 -23
  132. package/dist/selftest/audit.test.d.ts +2 -0
  133. package/dist/selftest/audit.test.js +57 -0
  134. package/dist/selftest/channel.test.js +7 -0
  135. package/dist/selftest/cli.test.js +47 -17
  136. package/dist/selftest/fixtures.d.ts +45 -0
  137. package/dist/selftest/fixtures.js +3 -1
  138. package/dist/selftest/generate.test.js +7 -2
  139. package/dist/selftest/index.js +5 -2
  140. package/dist/selftest/live-network.test.d.ts +2 -0
  141. package/dist/selftest/live-network.test.js +63 -0
  142. package/dist/selftest/local-config.test.js +16 -3
  143. package/dist/selftest/network.test.js +12 -0
  144. package/dist/selftest/projects.test.js +1 -1
  145. package/dist/selftest/repo-guard.test.js +59 -1
  146. package/dist/selftest/sync.test.js +50 -10
  147. package/dist/selftest/toolchains.test.js +30 -0
  148. package/dist/selftest/workspace-view.test.d.ts +2 -0
  149. package/dist/selftest/workspace-view.test.js +89 -0
  150. package/dist/shared/apps.d.ts +49 -0
  151. package/dist/shared/apps.js +114 -0
  152. package/dist/shared/netpolicy.d.ts +27 -0
  153. package/dist/shared/netpolicy.js +51 -0
  154. package/dist/shared/pty-client.d.ts +9 -4
  155. package/dist/shared/pty-client.js +139 -17
  156. package/dist/shared/rundir.d.ts +2 -0
  157. package/dist/shared/rundir.js +2 -0
  158. package/dist/shared/schema.d.ts +10 -0
  159. package/dist/shared/schema.js +2 -0
  160. package/dist/shared/system.d.ts +1 -0
  161. package/dist/shared/system.js +1 -0
  162. package/dist/sync/claude-mem.js +3 -2
  163. package/dist/sync/history.d.ts +6 -0
  164. package/dist/sync/history.js +26 -11
  165. package/dist/sync/watcher.js +78 -6
  166. package/package.json +2 -1
  167. package/sandbox/cargoshim.cs +56 -0
  168. package/sandbox/cpucap.cs +33 -0
  169. package/sandbox/cpucap.ps1 +4 -35
  170. package/sandbox/logon.cmd +6 -0
  171. package/sandbox/memlog.ps1 +34 -0
  172. package/sandbox/pagefile.cs +31 -0
  173. package/sandbox/pagefile.ps1 +21 -0
  174. package/sandbox/ptyhost.cs +105 -7
  175. package/schemas/config.schema.json +303 -2
  176. package/schemas/sandbox-config.schema.json +126 -12
  177. package/dist/cli/menu-multi.js +0 -82
  178. package/dist/cli/menu.d.ts +0 -14
  179. package/dist/cli/menu.js +0 -290
  180. package/dist/cli/settings/edit.d.ts +0 -13
  181. package/dist/cli/settings/edit.js +0 -19
  182. package/dist/cli/settings/index.d.ts +0 -8
  183. package/dist/cli/settings/index.js +0 -131
  184. package/dist/cli/settings/prompts.d.ts +0 -7
  185. package/dist/cli/settings/prompts.js +0 -48
  186. package/dist/cli/settings/schema.d.ts +0 -33
  187. package/dist/cli/settings/schema.js +0 -29
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
1363
1363
  return isFunction(object2[key]);
1364
1364
  });
1365
1365
  }
1366
- function baseGet(object2, path49) {
1367
- path49 = castPath(path49, object2);
1368
- var index = 0, length = path49.length;
1366
+ function baseGet(object2, path53) {
1367
+ path53 = castPath(path53, object2);
1368
+ var index = 0, length = path53.length;
1369
1369
  while (object2 != null && index < length) {
1370
- object2 = object2[toKey(path49[index++])];
1370
+ object2 = object2[toKey(path53[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, path49, args) {
1435
- path49 = castPath(path49, object2);
1436
- object2 = parent(object2, path49);
1437
- var func = object2 == null ? object2 : object2[toKey(last(path49))];
1434
+ function baseInvoke(object2, path53, args) {
1435
+ path53 = castPath(path53, object2);
1436
+ object2 = parent(object2, path53);
1437
+ var func = object2 == null ? object2 : object2[toKey(last(path53))];
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(path49, srcValue) {
1594
- if (isKey(path49) && isStrictComparable(srcValue)) {
1595
- return matchesStrictComparable(toKey(path49), srcValue);
1593
+ function baseMatchesProperty(path53, srcValue) {
1594
+ if (isKey(path53) && isStrictComparable(srcValue)) {
1595
+ return matchesStrictComparable(toKey(path53), srcValue);
1596
1596
  }
1597
1597
  return function(object2) {
1598
- var objValue = get(object2, path49);
1599
- return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path49) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1598
+ var objValue = get(object2, path53);
1599
+ return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path53) : 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, path49) {
1697
- return hasIn(object2, path49);
1696
+ return basePickBy(object2, paths, function(value, path53) {
1697
+ return hasIn(object2, path53);
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 path49 = paths[index], value = baseGet(object2, path49);
1704
- if (predicate(value, path49)) {
1705
- baseSet(result2, castPath(path49, object2), value);
1703
+ var path53 = paths[index], value = baseGet(object2, path53);
1704
+ if (predicate(value, path53)) {
1705
+ baseSet(result2, castPath(path53, object2), value);
1706
1706
  }
1707
1707
  }
1708
1708
  return result2;
1709
1709
  }
1710
- function basePropertyDeep(path49) {
1710
+ function basePropertyDeep(path53) {
1711
1711
  return function(object2) {
1712
- return baseGet(object2, path49);
1712
+ return baseGet(object2, path53);
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, path49, value, customizer) {
1786
+ function baseSet(object2, path53, value, customizer) {
1787
1787
  if (!isObject2(object2)) {
1788
1788
  return object2;
1789
1789
  }
1790
- path49 = castPath(path49, object2);
1791
- var index = -1, length = path49.length, lastIndex = length - 1, nested = object2;
1790
+ path53 = castPath(path53, object2);
1791
+ var index = -1, length = path53.length, lastIndex = length - 1, nested = object2;
1792
1792
  while (nested != null && ++index < length) {
1793
- var key = toKey(path49[index]), newValue = value;
1793
+ var key = toKey(path53[index]), newValue = value;
1794
1794
  if (key === "__proto__" || key === "constructor" || key === "prototype") {
1795
1795
  return object2;
1796
1796
  }
@@ -1798,7 +1798,7 @@ var require_lodash = __commonJS({
1798
1798
  var objValue = nested[key];
1799
1799
  newValue = customizer ? customizer(objValue, key, nested) : undefined2;
1800
1800
  if (newValue === undefined2) {
1801
- newValue = isObject2(objValue) ? objValue : isIndex(path49[index + 1]) ? [] : {};
1801
+ newValue = isObject2(objValue) ? objValue : isIndex(path53[index + 1]) ? [] : {};
1802
1802
  }
1803
1803
  }
1804
1804
  assignValue(nested, key, newValue);
@@ -1964,14 +1964,14 @@ var require_lodash = __commonJS({
1964
1964
  }
1965
1965
  return result2;
1966
1966
  }
1967
- function baseUnset(object2, path49) {
1968
- path49 = castPath(path49, object2);
1969
- var index = -1, length = path49.length;
1967
+ function baseUnset(object2, path53) {
1968
+ path53 = castPath(path53, object2);
1969
+ var index = -1, length = path53.length;
1970
1970
  if (!length) {
1971
1971
  return true;
1972
1972
  }
1973
1973
  while (++index < length) {
1974
- var key = toKey(path49[index]);
1974
+ var key = toKey(path53[index]);
1975
1975
  if (key === "__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, path49);
1983
- return obj == null || delete obj[toKey(last(path49))];
1982
+ var obj = parent(object2, path53);
1983
+ return obj == null || delete obj[toKey(last(path53))];
1984
1984
  }
1985
- function baseUpdate(object2, path49, updater, customizer) {
1986
- return baseSet(object2, path49, updater(baseGet(object2, path49)), customizer);
1985
+ function baseUpdate(object2, path53, updater, customizer) {
1986
+ return baseSet(object2, path53, updater(baseGet(object2, path53)), 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, path49, hasFunc) {
2870
- path49 = castPath(path49, object2);
2871
- var index = -1, length = path49.length, result2 = false;
2869
+ function hasPath(object2, path53, hasFunc) {
2870
+ path53 = castPath(path53, object2);
2871
+ var index = -1, length = path53.length, result2 = false;
2872
2872
  while (++index < length) {
2873
- var key = toKey(path49[index]);
2873
+ var key = toKey(path53[index]);
2874
2874
  if (!(result2 = object2 != null && hasFunc(object2, key))) {
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, path49) {
3076
- return path49.length < 2 ? object2 : baseGet(object2, baseSlice(path49, 0, -1));
3075
+ function parent(object2, path53) {
3076
+ return path53.length < 2 ? object2 : baseGet(object2, baseSlice(path53, 0, -1));
3077
3077
  }
3078
3078
  function reorder(array2, indexes) {
3079
3079
  var arrLength = array2.length, length = nativeMin(indexes.length, arrLength), oldArray = copyArray(array2);
@@ -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, path49, args) {
3712
- var index = -1, isFunc = typeof path49 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3711
+ var invokeMap = baseRest(function(collection, path53, args) {
3712
+ var index = -1, isFunc = typeof path53 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3713
3713
  baseEach(collection, function(value) {
3714
- result2[++index] = isFunc ? apply(path49, value, args) : baseInvoke(value, path49, args);
3714
+ result2[++index] = isFunc ? apply(path53, value, args) : baseInvoke(value, path53, args);
3715
3715
  });
3716
3716
  return result2;
3717
3717
  });
@@ -4175,7 +4175,7 @@ var require_lodash = __commonJS({
4175
4175
  customizer = typeof customizer == "function" ? customizer : undefined2;
4176
4176
  return baseIsMatch(object2, source, getMatchData(source), customizer);
4177
4177
  }
4178
- function isNaN(value) {
4178
+ function isNaN2(value) {
4179
4179
  return isNumber(value) && value != +value;
4180
4180
  }
4181
4181
  function isNative(value) {
@@ -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, path49, defaultValue) {
4367
- var result2 = object2 == null ? undefined2 : baseGet(object2, path49);
4366
+ function get(object2, path53, defaultValue) {
4367
+ var result2 = object2 == null ? undefined2 : baseGet(object2, path53);
4368
4368
  return result2 === undefined2 ? defaultValue : result2;
4369
4369
  }
4370
- function has(object2, path49) {
4371
- return object2 != null && hasPath(object2, path49, baseHas);
4370
+ function has(object2, path53) {
4371
+ return object2 != null && hasPath(object2, path53, baseHas);
4372
4372
  }
4373
- function hasIn(object2, path49) {
4374
- return object2 != null && hasPath(object2, path49, baseHasIn);
4373
+ function hasIn(object2, path53) {
4374
+ return object2 != null && hasPath(object2, path53, baseHasIn);
4375
4375
  }
4376
4376
  var invert = createInverter(function(result2, value, key) {
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(path49) {
4428
- path49 = castPath(path49, object2);
4429
- isDeep || (isDeep = path49.length > 1);
4430
- return path49;
4427
+ paths = arrayMap(paths, function(path53) {
4428
+ path53 = castPath(path53, object2);
4429
+ isDeep || (isDeep = path53.length > 1);
4430
+ return path53;
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, path49) {
4457
- return predicate(value, path49[0]);
4456
+ return basePickBy(object2, props, function(value, path53) {
4457
+ return predicate(value, path53[0]);
4458
4458
  });
4459
4459
  }
4460
- function result(object2, path49, defaultValue) {
4461
- path49 = castPath(path49, object2);
4462
- var index = -1, length = path49.length;
4460
+ function result(object2, path53, defaultValue) {
4461
+ path53 = castPath(path53, object2);
4462
+ var index = -1, length = path53.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(path49[index])];
4468
+ var value = object2 == null ? undefined2 : object2[toKey(path53[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, path49, value) {
4478
- return object2 == null ? object2 : baseSet(object2, path49, value);
4477
+ function set2(object2, path53, value) {
4478
+ return object2 == null ? object2 : baseSet(object2, path53, value);
4479
4479
  }
4480
- function setWith(object2, path49, value, customizer) {
4480
+ function setWith(object2, path53, value, customizer) {
4481
4481
  customizer = typeof customizer == "function" ? customizer : undefined2;
4482
- return object2 == null ? object2 : baseSet(object2, path49, value, customizer);
4482
+ return object2 == null ? object2 : baseSet(object2, path53, 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, path49) {
4505
- return object2 == null ? true : baseUnset(object2, path49);
4504
+ function unset(object2, path53) {
4505
+ return object2 == null ? true : baseUnset(object2, path53);
4506
4506
  }
4507
- function update(object2, path49, updater) {
4508
- return object2 == null ? object2 : baseUpdate(object2, path49, castFunction(updater));
4507
+ function update(object2, path53, updater) {
4508
+ return object2 == null ? object2 : baseUpdate(object2, path53, castFunction(updater));
4509
4509
  }
4510
- function updateWith(object2, path49, updater, customizer) {
4510
+ function updateWith(object2, path53, updater, customizer) {
4511
4511
  customizer = typeof customizer == "function" ? customizer : undefined2;
4512
- return object2 == null ? object2 : baseUpdate(object2, path49, castFunction(updater), customizer);
4512
+ return object2 == null ? object2 : baseUpdate(object2, path53, 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(path49, srcValue) {
4899
- return baseMatchesProperty(path49, baseClone(srcValue, CLONE_DEEP_FLAG));
4898
+ function matchesProperty(path53, srcValue) {
4899
+ return baseMatchesProperty(path53, baseClone(srcValue, CLONE_DEEP_FLAG));
4900
4900
  }
4901
- var method = baseRest(function(path49, args) {
4901
+ var method = baseRest(function(path53, args) {
4902
4902
  return function(object2) {
4903
- return baseInvoke(object2, path49, args);
4903
+ return baseInvoke(object2, path53, args);
4904
4904
  };
4905
4905
  });
4906
4906
  var methodOf = baseRest(function(object2, args) {
4907
- return function(path49) {
4908
- return baseInvoke(object2, path49, args);
4907
+ return function(path53) {
4908
+ return baseInvoke(object2, path53, 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(path49) {
4956
- return isKey(path49) ? baseProperty(toKey(path49)) : basePropertyDeep(path49);
4955
+ function property(path53) {
4956
+ return isKey(path53) ? baseProperty(toKey(path53)) : basePropertyDeep(path53);
4957
4957
  }
4958
4958
  function propertyOf(object2) {
4959
- return function(path49) {
4960
- return object2 == null ? undefined2 : baseGet(object2, path49);
4959
+ return function(path53) {
4960
+ return object2 == null ? undefined2 : baseGet(object2, path53);
4961
4961
  };
4962
4962
  }
4963
4963
  var range = createRange();
@@ -5257,7 +5257,7 @@ var require_lodash = __commonJS({
5257
5257
  lodash.isMap = isMap;
5258
5258
  lodash.isMatch = isMatch;
5259
5259
  lodash.isMatchWith = isMatchWith;
5260
- lodash.isNaN = isNaN;
5260
+ lodash.isNaN = isNaN2;
5261
5261
  lodash.isNative = isNative;
5262
5262
  lodash.isNil = isNil;
5263
5263
  lodash.isNull = isNull;
@@ -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(path49, args) {
5414
- if (typeof path49 == "function") {
5413
+ LazyWrapper.prototype.invokeMap = baseRest(function(path53, args) {
5414
+ if (typeof path53 == "function") {
5415
5415
  return new LazyWrapper(this);
5416
5416
  }
5417
5417
  return this.map(function(value) {
5418
- return baseInvoke(value, path49, args);
5418
+ return baseInvoke(value, path53, args);
5419
5419
  });
5420
5420
  });
5421
5421
  LazyWrapper.prototype.reject = function(predicate) {
@@ -5532,7 +5532,7 @@ var require_lodash = __commonJS({
5532
5532
  });
5533
5533
 
5534
5534
  // src/guest/daemon.ts
5535
- import fs33 from "node:fs";
5535
+ import fs36 from "node:fs";
5536
5536
 
5537
5537
  // src/shared/rundir.ts
5538
5538
  import fs2 from "node:fs";
@@ -6354,10 +6354,10 @@ function mergeDefs(...defs) {
6354
6354
  function cloneDef(schema) {
6355
6355
  return mergeDefs(schema._zod.def);
6356
6356
  }
6357
- function getElementAtPath(obj, path49) {
6358
- if (!path49)
6357
+ function getElementAtPath(obj, path53) {
6358
+ if (!path53)
6359
6359
  return obj;
6360
- return path49.reduce((acc, key) => acc?.[key], obj);
6360
+ return path53.reduce((acc, key) => acc?.[key], obj);
6361
6361
  }
6362
6362
  function promiseAllObject(promisesObj) {
6363
6363
  const keys = Object.keys(promisesObj);
@@ -6697,11 +6697,11 @@ function explicitlyAborted(x, startIndex = 0) {
6697
6697
  }
6698
6698
  return false;
6699
6699
  }
6700
- function prefixIssues(path49, issues) {
6700
+ function prefixIssues(path53, issues) {
6701
6701
  return issues.map((iss) => {
6702
6702
  var _a3;
6703
6703
  (_a3 = iss).path ?? (_a3.path = []);
6704
- iss.path.unshift(path49);
6704
+ iss.path.unshift(path53);
6705
6705
  return iss;
6706
6706
  });
6707
6707
  }
@@ -7151,16 +7151,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
7151
7151
  }
7152
7152
  function formatError(error62, mapper = (issue2) => issue2.message) {
7153
7153
  const fieldErrors = { _errors: [] };
7154
- const processError = (error63, path49 = []) => {
7154
+ const processError = (error63, path53 = []) => {
7155
7155
  for (const issue2 of error63.issues) {
7156
7156
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7157
- issue2.errors.map((issues) => processError({ issues }, [...path49, ...issue2.path]));
7157
+ issue2.errors.map((issues) => processError({ issues }, [...path53, ...issue2.path]));
7158
7158
  } else if (issue2.code === "invalid_key") {
7159
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
7159
+ processError({ issues: issue2.issues }, [...path53, ...issue2.path]);
7160
7160
  } else if (issue2.code === "invalid_element") {
7161
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
7161
+ processError({ issues: issue2.issues }, [...path53, ...issue2.path]);
7162
7162
  } else {
7163
- const fullpath = [...path49, ...issue2.path];
7163
+ const fullpath = [...path53, ...issue2.path];
7164
7164
  if (fullpath.length === 0) {
7165
7165
  fieldErrors._errors.push(mapper(issue2));
7166
7166
  } else {
@@ -7199,17 +7199,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
7199
7199
  }
7200
7200
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
7201
7201
  const result = { errors: [] };
7202
- const processError = (error63, path49 = []) => {
7202
+ const processError = (error63, path53 = []) => {
7203
7203
  var _a3;
7204
7204
  for (const issue2 of error63.issues) {
7205
7205
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7206
- issue2.errors.map((issues) => processError({ issues }, [...path49, ...issue2.path]));
7206
+ issue2.errors.map((issues) => processError({ issues }, [...path53, ...issue2.path]));
7207
7207
  } else if (issue2.code === "invalid_key") {
7208
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
7208
+ processError({ issues: issue2.issues }, [...path53, ...issue2.path]);
7209
7209
  } else if (issue2.code === "invalid_element") {
7210
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
7210
+ processError({ issues: issue2.issues }, [...path53, ...issue2.path]);
7211
7211
  } else {
7212
- const fullpath = [...path49, ...issue2.path];
7212
+ const fullpath = [...path53, ...issue2.path];
7213
7213
  if (fullpath.length === 0) {
7214
7214
  result.errors.push(mapper(issue2));
7215
7215
  continue;
@@ -7248,8 +7248,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
7248
7248
  }
7249
7249
  function toDotPath(_path) {
7250
7250
  const segs = [];
7251
- const path49 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7252
- for (const seg of path49) {
7251
+ const path53 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7252
+ for (const seg of path53) {
7253
7253
  if (typeof seg === "number")
7254
7254
  segs.push(`[${seg}]`);
7255
7255
  else if (typeof seg === "symbol")
@@ -7383,18 +7383,18 @@ var validateAsync = async (schema, value, _ctx) => {
7383
7383
  return result.issues.length === 0;
7384
7384
  };
7385
7385
  var _encode = (_Err) => {
7386
- const parse3 = _parse(_Err);
7386
+ const parse5 = _parse(_Err);
7387
7387
  const fn = (schema, value, _ctx, _params) => {
7388
7388
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
7389
- return parse3(schema, value, ctx, finalizeParams(fn, _params));
7389
+ return parse5(schema, value, ctx, finalizeParams(fn, _params));
7390
7390
  };
7391
7391
  return fn;
7392
7392
  };
7393
7393
  var encode = /* @__PURE__ */ _encode($ZodRealError);
7394
7394
  var _decode = (_Err) => {
7395
- const parse3 = _parse(_Err);
7395
+ const parse5 = _parse(_Err);
7396
7396
  const fn = (schema, value, _ctx, _params) => {
7397
- return parse3(schema, value, _ctx, finalizeParams(fn, _params));
7397
+ return parse5(schema, value, _ctx, finalizeParams(fn, _params));
7398
7398
  };
7399
7399
  return fn;
7400
7400
  };
@@ -9048,14 +9048,14 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
9048
9048
  const shape = zod.def.shape;
9049
9049
  const propValues = {};
9050
9050
  for (const key in shape) {
9051
- const field = shape[key]._zod;
9052
- if (field.values) {
9051
+ const field2 = shape[key]._zod;
9052
+ if (field2.values) {
9053
9053
  if (!Object.prototype.hasOwnProperty.call(propValues, key)) {
9054
9054
  assignProp(propValues, key, /* @__PURE__ */ new Set());
9055
9055
  }
9056
- for (const v of field.values)
9056
+ for (const v of field2.values)
9057
9057
  propValues[key].add(v);
9058
- if (field.optin !== void 0)
9058
+ if (field2.optin !== void 0)
9059
9059
  propValues[key].add(void 0);
9060
9060
  }
9061
9061
  }
@@ -10564,7 +10564,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
10564
10564
  var NONE = 0;
10565
10565
  var ASSUMED = 1;
10566
10566
  var PROVEN = 2;
10567
- function isRecursive(inst, stack, resolve) {
10567
+ function isRecursive(inst, stack, resolve2) {
10568
10568
  const cached2 = recursive.get(inst);
10569
10569
  if (cached2 !== void 0)
10570
10570
  return cached2 ? PROVEN : NONE;
@@ -10574,7 +10574,7 @@ function isRecursive(inst, stack, resolve) {
10574
10574
  let result = NONE;
10575
10575
  const check2 = (child) => {
10576
10576
  if (result !== PROVEN && child?._zod) {
10577
- const answer = isRecursive(child, stack, resolve);
10577
+ const answer = isRecursive(child, stack, resolve2);
10578
10578
  if (answer > result)
10579
10579
  result = answer;
10580
10580
  }
@@ -10585,7 +10585,7 @@ function isRecursive(inst, stack, resolve) {
10585
10585
  const desc = Object.getOwnPropertyDescriptor(sh, key);
10586
10586
  if (spread && !desc.enumerable)
10587
10587
  continue;
10588
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE;
10588
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve2) : NONE;
10589
10589
  if (child > answer)
10590
10590
  answer = child;
10591
10591
  }
@@ -10649,7 +10649,7 @@ function isRecursive(inst, stack, resolve) {
10649
10649
  break;
10650
10650
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
10651
10651
  case "lazy": {
10652
- const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : void 0);
10652
+ const inner = def._cachedInner ?? (resolve2 ? inst._zod.innerType : void 0);
10653
10653
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
10654
10654
  break;
10655
10655
  }
@@ -18759,8 +18759,8 @@ function generateMultipleOfCheck(doc, ctx, def, accessor) {
18759
18759
  }
18760
18760
  }
18761
18761
  function generateNumberFormatCheck(doc, def, accessor) {
18762
- const format = def.format;
18763
- switch (format) {
18762
+ const format2 = def.format;
18763
+ switch (format2) {
18764
18764
  case "safeint":
18765
18765
  doc.write(`if (!Number.isSafeInteger(${accessor})) return INVALID;`);
18766
18766
  break;
@@ -18777,16 +18777,16 @@ function generateNumberFormatCheck(doc, def, accessor) {
18777
18777
  doc.write(`if (!Number.isFinite(${accessor})) return INVALID;`);
18778
18778
  break;
18779
18779
  default: {
18780
- void format;
18781
- throw new ZodCompileUnsupportedError(`number format ${format}`);
18780
+ void format2;
18781
+ throw new ZodCompileUnsupportedError(`number format ${format2}`);
18782
18782
  }
18783
18783
  }
18784
18784
  }
18785
18785
  function generateBigIntFormatCheck(doc, def, accessor) {
18786
- const format = def.format;
18787
- if (!format)
18786
+ const format2 = def.format;
18787
+ if (!format2)
18788
18788
  return;
18789
- switch (format) {
18789
+ switch (format2) {
18790
18790
  case "int64":
18791
18791
  doc.write(`if (${accessor} < -9223372036854775808n || ${accessor} > 9223372036854775807n) return INVALID;`);
18792
18792
  break;
@@ -18794,8 +18794,8 @@ function generateBigIntFormatCheck(doc, def, accessor) {
18794
18794
  doc.write(`if (${accessor} < 0n || ${accessor} > 18446744073709551615n) return INVALID;`);
18795
18795
  break;
18796
18796
  default: {
18797
- void format;
18798
- throw new ZodCompileUnsupportedError(`bigint format ${format}`);
18797
+ void format2;
18798
+ throw new ZodCompileUnsupportedError(`bigint format ${format2}`);
18799
18799
  }
18800
18800
  }
18801
18801
  }
@@ -18976,8 +18976,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
18976
18976
  doc.write(`if (!${patternConst}.test(${accessor})) return INVALID;`);
18977
18977
  return accessor;
18978
18978
  }
18979
- const format = def.format;
18980
- switch (format) {
18979
+ const format2 = def.format;
18980
+ switch (format2) {
18981
18981
  case "regex":
18982
18982
  throw new ZodCompileUnsupportedError("regex format without a pattern");
18983
18983
  case "lowercase":
@@ -19000,8 +19000,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
19000
19000
  break;
19001
19001
  }
19002
19002
  default: {
19003
- void format;
19004
- throw new ZodCompileUnsupportedError(`string format ${format}`);
19003
+ void format2;
19004
+ throw new ZodCompileUnsupportedError(`string format ${format2}`);
19005
19005
  }
19006
19006
  }
19007
19007
  return accessor;
@@ -21084,12 +21084,12 @@ function _stringbool(Classes, _params) {
21084
21084
  return codec2;
21085
21085
  }
21086
21086
  // @__NO_SIDE_EFFECTS__
21087
- function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
21087
+ function _stringFormat(Class2, format2, fnOrRegex, _params = {}) {
21088
21088
  const params = normalizeParams(_params);
21089
21089
  const def = {
21090
21090
  check: "string_format",
21091
21091
  type: "string",
21092
- format,
21092
+ format: format2,
21093
21093
  fn: typeof fnOrRegex === "function" ? fnOrRegex : (val) => fnOrRegex.test(val),
21094
21094
  ...params
21095
21095
  };
@@ -21655,9 +21655,9 @@ var addPattern = (agg, pattern) => {
21655
21655
  var intersectMime = (agg, mime) => {
21656
21656
  agg.mime = agg.mime ? agg.mime.filter((m) => mime.includes(m)) : [...mime];
21657
21657
  };
21658
- var setFormat = (agg, format) => {
21659
- agg.format = format;
21660
- if (format.includes("int"))
21658
+ var setFormat = (agg, format2) => {
21659
+ agg.format = format2;
21660
+ if (format2.includes("int"))
21661
21661
  agg.isInt = true;
21662
21662
  };
21663
21663
  var minContributor = (agg, def) => narrowMin(agg, "minimum", def.minimum);
@@ -21735,16 +21735,16 @@ var exactPattern = (p) => exactPatterns.get(p) ?? p;
21735
21735
  var stringProcessor = (schema, ctx, _json, _params) => {
21736
21736
  const json2 = _json;
21737
21737
  json2.type = "string";
21738
- const { minimum, maximum, format, patterns, contentEncoding, laxFormat } = aggregateChecks(schema);
21738
+ const { minimum, maximum, format: format2, patterns, contentEncoding, laxFormat } = aggregateChecks(schema);
21739
21739
  if (typeof minimum === "number")
21740
21740
  json2.minLength = minimum;
21741
21741
  if (typeof maximum === "number")
21742
21742
  json2.maxLength = maximum;
21743
- if (format) {
21744
- json2.format = formatMap[format] ?? format;
21743
+ if (format2) {
21744
+ json2.format = formatMap[format2] ?? format2;
21745
21745
  if (json2.format === "")
21746
21746
  delete json2.format;
21747
- if (format === "time" || laxFormat) {
21747
+ if (format2 === "time" || laxFormat) {
21748
21748
  delete json2.format;
21749
21749
  }
21750
21750
  }
@@ -21983,8 +21983,8 @@ var objectProcessor = (schema, ctx, _json, params) => {
21983
21983
  }
21984
21984
  const requiredKeys = [];
21985
21985
  for (const key of Object.keys(shape)) {
21986
- const field = def.shape[key];
21987
- if (ctx.io === "input" ? inputOptin(field) === void 0 : field._zod.optout === void 0) {
21986
+ const field2 = def.shape[key];
21987
+ if (ctx.io === "input" ? inputOptin(field2) === void 0 : field2._zod.optout === void 0) {
21988
21988
  requiredKeys.push(key);
21989
21989
  }
21990
21990
  }
@@ -22122,7 +22122,7 @@ function stringifyKeyNames(bySchema, json2, visited) {
22122
22122
  const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
22123
22123
  if (!numericType && !values?.some((v) => typeof v === "number"))
22124
22124
  return json2;
22125
- const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json2;
22125
+ const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format: format2, id, ...rest } = json2;
22126
22126
  if (rest.enum)
22127
22127
  rest.enum = rest.enum.map((v) => typeof v === "number" ? String(v) : v);
22128
22128
  else if (typeof rest.const === "number")
@@ -23258,8 +23258,8 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
23258
23258
  $ZodCustomStringFormat.init(inst, def);
23259
23259
  ZodStringFormat.init(inst, def);
23260
23260
  });
23261
- function stringFormat(format, fnOrRegex, _params = {}) {
23262
- return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
23261
+ function stringFormat(format2, fnOrRegex, _params = {}) {
23262
+ return _stringFormat(ZodCustomStringFormat, format2, fnOrRegex, _params);
23263
23263
  }
23264
23264
  function hostname2(_params) {
23265
23265
  return _stringFormat(ZodCustomStringFormat, "hostname", hostname, _params);
@@ -23272,11 +23272,11 @@ function currencyCode2(_params) {
23272
23272
  }
23273
23273
  function hash(alg, params) {
23274
23274
  const enc = params?.enc ?? "hex";
23275
- const format = `${alg}_${enc}`;
23276
- const regex = regexes_exports[format];
23275
+ const format2 = `${alg}_${enc}`;
23276
+ const regex = regexes_exports[format2];
23277
23277
  if (!regex)
23278
- throw new Error(`Unrecognized hash format: ${format}`);
23279
- return _stringFormat(ZodCustomStringFormat, format, regex, params);
23278
+ throw new Error(`Unrecognized hash format: ${format2}`);
23279
+ return _stringFormat(ZodCustomStringFormat, format2, regex, params);
23280
23280
  }
23281
23281
  var ZodNumber = /* @__PURE__ */ $constructor(
23282
23282
  "ZodNumber",
@@ -24351,13 +24351,13 @@ function resolveRef(ref, ctx) {
24351
24351
  if (!ref.startsWith("#")) {
24352
24352
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24353
24353
  }
24354
- const path49 = ref.slice(1).split("/").filter(Boolean);
24355
- if (path49.length === 0) {
24354
+ const path53 = ref.slice(1).split("/").filter(Boolean);
24355
+ if (path53.length === 0) {
24356
24356
  return ctx.rootSchema;
24357
24357
  }
24358
24358
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24359
- if (path49[0] === defsKey) {
24360
- const key = path49[1] === void 0 ? void 0 : decodeJSONPointerSegment(path49[1]);
24359
+ if (path53[0] === defsKey) {
24360
+ const key = path53[1] === void 0 ? void 0 : decodeJSONPointerSegment(path53[1]);
24361
24361
  if (!key || !ctx.defs[key]) {
24362
24362
  throw new Error(`Reference not found: ${ref}`);
24363
24363
  }
@@ -24641,58 +24641,58 @@ function convertBaseSchema(schema, ctx) {
24641
24641
  case "string": {
24642
24642
  let stringSchema = z.string();
24643
24643
  if (schema.format) {
24644
- const format = schema.format;
24645
- if (format === "email") {
24644
+ const format2 = schema.format;
24645
+ if (format2 === "email") {
24646
24646
  stringSchema = stringSchema.check(z.email());
24647
- } else if (format === "uri" || format === "uri-reference") {
24647
+ } else if (format2 === "uri" || format2 === "uri-reference") {
24648
24648
  stringSchema = stringSchema.check(z.url());
24649
- } else if (format === "uuid" || format === "guid") {
24649
+ } else if (format2 === "uuid" || format2 === "guid") {
24650
24650
  stringSchema = stringSchema.check(z.uuid());
24651
- } else if (format === "date-time") {
24651
+ } else if (format2 === "date-time") {
24652
24652
  stringSchema = stringSchema.check(z.iso.datetime({ offset: true }));
24653
- } else if (format === "date") {
24653
+ } else if (format2 === "date") {
24654
24654
  stringSchema = stringSchema.check(z.iso.date());
24655
- } else if (format === "time") {
24655
+ } else if (format2 === "time") {
24656
24656
  stringSchema = stringSchema.check(z.regex(fullTime));
24657
- } else if (format === "duration") {
24657
+ } else if (format2 === "duration") {
24658
24658
  stringSchema = stringSchema.check(z.iso.duration());
24659
- } else if (format === "hostname") {
24659
+ } else if (format2 === "hostname") {
24660
24660
  stringSchema = stringSchema.check(z.hostname());
24661
- } else if (format === "ipv4") {
24661
+ } else if (format2 === "ipv4") {
24662
24662
  stringSchema = stringSchema.check(z.ipv4());
24663
- } else if (format === "ipv6") {
24663
+ } else if (format2 === "ipv6") {
24664
24664
  stringSchema = stringSchema.check(z.ipv6());
24665
- } else if (format === "mac") {
24665
+ } else if (format2 === "mac") {
24666
24666
  stringSchema = stringSchema.check(z.mac());
24667
- } else if (format === "cidr") {
24667
+ } else if (format2 === "cidr") {
24668
24668
  stringSchema = stringSchema.check(z.cidrv4());
24669
- } else if (format === "cidr-v6") {
24669
+ } else if (format2 === "cidr-v6") {
24670
24670
  stringSchema = stringSchema.check(z.cidrv6());
24671
- } else if (format === "base64") {
24671
+ } else if (format2 === "base64") {
24672
24672
  stringSchema = stringSchema.check(z.base64());
24673
- } else if (format === "base64url") {
24673
+ } else if (format2 === "base64url") {
24674
24674
  stringSchema = stringSchema.check(z.base64url());
24675
- } else if (format === "e164") {
24675
+ } else if (format2 === "e164") {
24676
24676
  stringSchema = stringSchema.check(z.e164());
24677
- } else if (format === "credit_card") {
24677
+ } else if (format2 === "credit_card") {
24678
24678
  stringSchema = stringSchema.check(z.creditCard());
24679
- } else if (format === "iban") {
24679
+ } else if (format2 === "iban") {
24680
24680
  stringSchema = stringSchema.check(z.iban());
24681
- } else if (format === "jwt") {
24681
+ } else if (format2 === "jwt") {
24682
24682
  stringSchema = stringSchema.check(z.jwt());
24683
- } else if (format === "emoji") {
24683
+ } else if (format2 === "emoji") {
24684
24684
  stringSchema = stringSchema.check(z.emoji());
24685
- } else if (format === "nanoid") {
24685
+ } else if (format2 === "nanoid") {
24686
24686
  stringSchema = stringSchema.check(z.nanoid());
24687
- } else if (format === "cuid") {
24687
+ } else if (format2 === "cuid") {
24688
24688
  stringSchema = stringSchema.check(z.cuid());
24689
- } else if (format === "cuid2") {
24689
+ } else if (format2 === "cuid2") {
24690
24690
  stringSchema = stringSchema.check(z.cuid2());
24691
- } else if (format === "ulid") {
24691
+ } else if (format2 === "ulid") {
24692
24692
  stringSchema = stringSchema.check(z.ulid());
24693
- } else if (format === "xid") {
24693
+ } else if (format2 === "xid") {
24694
24694
  stringSchema = stringSchema.check(z.xid());
24695
- } else if (format === "ksuid") {
24695
+ } else if (format2 === "ksuid") {
24696
24696
  stringSchema = stringSchema.check(z.ksuid());
24697
24697
  }
24698
24698
  }
@@ -25310,8 +25310,10 @@ var ClaudeProfile = external_exports.strictObject({
25310
25310
  globalStateFile: external_exports.string().describe('Your .claude.json, or "auto". Empty string = do not copy.'),
25311
25311
  copyCredentials: external_exports.boolean().describe("Copy your Claude LOGIN into the sandbox. Prefer sandbox account instead."),
25312
25312
  overwrite: external_exports.boolean().describe("Refresh these settings from this PC on every launch."),
25313
- syncHistory: external_exports.boolean().describe("Bring all conversation history in, and sync new history back (path-translated)."),
25314
- syncClaudeMem: external_exports.boolean().describe("Bring claude-mem data in, and its database back when the sandbox closes.")
25313
+ syncHistory: external_exports.boolean().describe("Bring conversation history in, and sync new history back (path-translated)."),
25314
+ historyScope: external_exports.enum(["project", "all"]).describe(`Which history comes in: "project" = only the projects in this sandbox (other projects' conversations, file backups and prompts stay on this PC), "all" = everything. Only this sandbox's projects ever sync back.`),
25315
+ syncClaudeMem: external_exports.boolean().describe("Bring claude-mem data into the sandbox (its settings and backups stay on this PC)."),
25316
+ syncClaudeMemBack: external_exports.boolean().describe("Also copy claude-mem's database back to this PC when the sandbox closes. Off by default: what is in it is loaded into every Claude session on this PC, so a compromised agent could plant instructions there.")
25315
25317
  });
25316
25318
 
25317
25319
  // src/core/schema/sandbox.ts
@@ -25327,6 +25329,7 @@ var Sandbox = external_exports.strictObject({
25327
25329
  maxMemoryMb: external_exports.number().int().positive().describe('Upper limit for memoryMb "auto".'),
25328
25330
  maxMemoryPercent: external_exports.number().int().min(10).max(100).describe(`memoryMb "auto" never takes more than this share of this PC's total RAM (percent).`),
25329
25331
  cpuLimit: external_exports.union([external_exports.literal("none"), external_exports.number().int().min(5).max(100)]).describe(`Most of this PC's CPU the sandbox may use, in percent (5-100), e.g. 50 keeps half free for you; "none" = no cap (Windows Sandbox would take every processor). Covers everything this tool starts in the sandbox (agents, installs, builds, its terminal).`),
25332
+ pageFileMb: external_exports.number().int().min(0).max(262144).describe(`Size of the sandbox's paging file in MB, created at full size when it starts so it never grows while builds run (8 GB of its disk always stays free). Windows Sandbox starts with about 1 GB: parallel builds then fail with "The paging file is too small", and Windows grows the file under load. 0 = leave Windows' own.`),
25330
25333
  reserveHostMb: external_exports.number().int().nonnegative().describe('RAM always left for this PC when memoryMb is "auto".'),
25331
25334
  vGpu: external_exports.boolean().describe("Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface."),
25332
25335
  networking: external_exports.boolean().describe("Internet access. false is the only hard network isolation Windows Sandbox offers."),
@@ -25335,7 +25338,33 @@ var Sandbox = external_exports.strictObject({
25335
25338
  videoInput: external_exports.boolean().describe("Camera access."),
25336
25339
  printerRedirection: external_exports.boolean().describe("Printers from this PC."),
25337
25340
  protectedClient: external_exports.boolean().describe("Run the sandbox window in Protected Client mode (recommended)."),
25338
- headless: external_exports.boolean().describe("Hide the sandbox window (sbx-show brings it back). A headless sandbox shuts down when its last session ends.")
25341
+ headless: external_exports.boolean().describe("Hide the sandbox window (sbx-show brings it back). A headless sandbox shuts down when its last session ends."),
25342
+ keepAwake: external_exports.boolean().describe("Keep this PC from sleeping while a sandbox runs, so agents left working overnight keep going (the screen may still turn off; closing a laptop lid still sleeps it).")
25343
+ });
25344
+ var Port2 = external_exports.number().int().min(1).max(65535);
25345
+ var HostEntry = external_exports.string().max(253).regex(/^(@developer|(\*\.)?([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+)$/, "a host name like example.com, *.example.com, or @developer");
25346
+ var Network = external_exports.strictObject({
25347
+ blockPrivateRanges: external_exports.boolean().describe("Block your LAN (10/8, 172.16/12, 192.168/16, SMB) from inside the sandbox."),
25348
+ allowOnly: external_exports.array(HostEntry).describe("Only these hosts can be reached once the sandbox is set up (tools still download first). *.example.com covers its subdomains; @developer adds package registries, GitHub, toolchain downloads and the AI providers. Programs go through a proxy in the sandbox (HTTP_PROXY); anything else is blocked by its firewall. Empty = no limit."),
25349
+ blockHosts: external_exports.array(external_exports.string().max(253).regex(/^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/, "a host name like telemetry.example.com")).describe("Never reachable from the sandbox, e.g. production servers or telemetry (each exact name; the sandbox's hosts file sends them nowhere)."),
25350
+ forwardPorts: external_exports.array(external_exports.strictObject({
25351
+ pc: Port2.describe("The port on this PC (localhost only)."),
25352
+ sandbox: Port2.describe("The port inside the sandbox (a server there may listen on localhost only).")
25353
+ })).describe("Reach servers in the sandbox from this PC: http://localhost:<pc> here goes to <sandbox> inside, while it runs. Nothing else on your network can use them."),
25354
+ dns: external_exports.array(external_exports.string().regex(/^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address like 1.1.1.1")).describe("DNS servers for the sandbox instead of your network's, e.g. 1.1.1.1 and 9.9.9.9."),
25355
+ proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").describe("An HTTP proxy the sandbox uses to reach the internet (HTTP_PROXY / HTTPS_PROXY for everything in it), e.g. http://proxy.corp:8080. Empty = none.")
25356
+ });
25357
+ var Audit = external_exports.strictObject({
25358
+ enabled: external_exports.boolean().describe("Keep an audit log on this PC of what happened in your sandboxes: programs started (with their command lines), files changed in the project, sessions, and what the repo guard caught. The sandbox cannot change it. Read it with sandbox audit."),
25359
+ days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
25360
+ maxMb: external_exports.number().int().min(5).max(5e3).describe("Most space the audit log may take, in MB (older days go first). Days before today are compressed."),
25361
+ processes: external_exports.boolean().describe("Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."),
25362
+ files: external_exports.boolean().describe("Record the files changed in the project while the sandbox runs.")
25363
+ });
25364
+ var WorkspaceFilter = external_exports.strictObject({
25365
+ enabled: external_exports.boolean().describe("Keep what your .gitignore lists (.env files, node_modules, build output ...) out of the sandbox. The sandbox works on a copy of the project without those files, kept in step with it both ways within about a second; what it creates that is ignored (its own node_modules, builds) stays in the sandbox. Git works as usual. Off = the project folder itself is mapped."),
25366
+ exclude: external_exports.array(external_exports.string().max(500)).describe("Also keep these out, as .gitignore patterns, e.g. secrets/, *.pem, data/private/."),
25367
+ include: external_exports.array(external_exports.string().max(500)).describe("Let these in although .gitignore lists them, e.g. .env.example, data/fixtures/.")
25339
25368
  });
25340
25369
  var Git = external_exports.strictObject({ enabled: external_exports.boolean().describe("Provide Git for Windows (and Git Bash, which Claude Code needs)."), access: GitAccess });
25341
25370
  var Provisioning = external_exports.strictObject({
@@ -25343,7 +25372,8 @@ var Provisioning = external_exports.strictObject({
25343
25372
  fallbackToInstall: external_exports.boolean().describe("Download anything that cannot be copied from this PC."),
25344
25373
  refresh: external_exports.boolean().describe("Re-copy / re-download everything on the next launch."),
25345
25374
  git: Git,
25346
- terminal: toggle("Windows Terminal as the sandbox window (downloaded once).")
25375
+ terminal: toggle("Windows Terminal as the sandbox window (downloaded once)."),
25376
+ conpty: toggle("Agent sessions use Microsoft's newer pseudo console (conpty.dll, downloaded once) instead of the one built into Windows: no garbled screen after resizing, real scrollback for the mouse wheel. Off = the one built into Windows.")
25347
25377
  });
25348
25378
  var Downloads = external_exports.strictObject({
25349
25379
  requireChecksum: external_exports.boolean().describe("Refuse any toolchain, database or tool download that has no published checksum (SHA-256/SHA-512) to verify it against. false = allow those, as before. Downloads that do have a published checksum are always verified. A project's .sandbox-config.json can only turn this on.")
@@ -25427,10 +25457,150 @@ var Toolchains = external_exports.strictObject({
25427
25457
  enabled: external_exports.boolean().describe("Mesa 3D (llvmpipe): OpenGL 4.5 in software for games and apps when there is no GPU (sandbox.vGpu off). Copy opengl32.dll and libgallium_wgl.dll from %MESA_DIR% next to the program's .exe."),
25428
25458
  vulkan: external_exports.boolean().describe("Also software Vulkan 1.4 (Mesa lavapipe) with the Khronos loader, registered for every program; for wgpu set WGPU_BACKEND=vulkan.")
25429
25459
  }),
25430
- vscode: toggle("Portable VS Code inside the sandbox (code on PATH, desktop shortcut); its settings and extensions persist."),
25460
+ vscode: external_exports.strictObject({
25461
+ enabled: external_exports.boolean().describe("Portable VS Code inside the sandbox (code on PATH, desktop shortcut); its settings and extensions persist."),
25462
+ setup: external_exports.boolean().describe("Point VS Code at the sandbox's own tools (JDK, Python, Go, compilers, .NET, Git, PowerShell 7 and Git Bash terminals) and install the language extensions for the toolchains in use."),
25463
+ recommended: external_exports.boolean().describe("Also install the extensions a project recommends in its .vscode/extensions.json."),
25464
+ extensions: external_exports.array(external_exports.string().regex(/^[\w-]+\.[\w-]+$/, "publisher.name, e.g. eamodio.gitlens")).describe("More extensions to install in every sandbox, e.g. eamodio.gitlens, ms-azuretools.vscode-docker.")
25465
+ }),
25431
25466
  environment: external_exports.record(external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "letters, digits and _ only"), external_exports.string()).describe('Extra environment variables for the agent and every terminal, e.g. registry mirrors: {"NPM_CONFIG_REGISTRY": "https://...", "PIP_INDEX_URL": "https://..."}.')
25432
25467
  });
25433
25468
 
25469
+ // src/shared/apps.ts
25470
+ var gh = (github, asset) => ({ github, asset });
25471
+ var APPS = [
25472
+ // ---- editors
25473
+ { id: "vscode", name: "Visual Studio Code", category: "editors", about: "Code editor with debugging, set up for the sandbox's languages.", size: "150 MB", source: { resolve: "setting" }, exe: "Code.exe", setting: "toolchains.vscode.enabled" },
25474
+ { id: "windows-terminal", name: "Windows Terminal", category: "utilities", about: "The sandbox window: tabs, panes, PowerShell 7 profile.", size: "40 MB", source: { resolve: "setting" }, exe: "WindowsTerminal.exe", setting: "provisioning.terminal.enabled" },
25475
+ { id: "notepadpp", name: "Notepad++", category: "editors", about: "Fast text and code editor.", size: "8 MB", source: gh("notepad-plus-plus/notepad-plus-plus", "^npp\\.[\\d.]+\\.portable\\.x64\\.zip$"), exe: "notepad++.exe" },
25476
+ { id: "sublime", name: "Sublime Text", category: "editors", about: "Fast code editor (paid licence, free to evaluate).", size: "28 MB", source: { resolve: "sublime" }, exe: "sublime_text.exe" },
25477
+ { id: "neovim", name: "Neovim", category: "editors", about: "Terminal text editor (nvim).", size: "12 MB", source: gh("neovim/neovim", "^nvim-win64\\.zip$"), exe: "nvim.exe", cli: true },
25478
+ // ---- database clients
25479
+ { id: "dbeaver", name: "DBeaver Community", category: "databases", about: "Universal database client: PostgreSQL, MySQL, SQLite, SQL Server and more.", size: "120 MB", source: gh("dbeaver/dbeaver", "^dbeaver-ce-[\\d.]+-windows-x86_64\\.zip$"), exe: "dbeaver.exe" },
25480
+ { id: "pgadmin", name: "pgAdmin 4", category: "databases", about: "The PostgreSQL admin GUI (from the PostgreSQL binaries zip).", size: "330 MB", source: { resolve: "pgadmin" }, exe: "pgAdmin4.exe" },
25481
+ { id: "heidisql", name: "HeidiSQL", category: "databases", about: "Light client for MySQL, MariaDB, PostgreSQL and SQL Server.", size: "28 MB", source: gh("HeidiSQL/HeidiSQL", "^HeidiSQL_[\\d.]+_64_Portable\\.zip$"), exe: "heidisql.exe" },
25482
+ { id: "sqlitebrowser", name: "DB Browser for SQLite", category: "databases", about: "Open, browse and edit SQLite files.", size: "21 MB", source: gh("sqlitebrowser/sqlitebrowser", "^DB\\.Browser\\.for\\.SQLite-v?[\\d.]+-win64\\.zip$"), exe: "DB Browser for SQLite.exe" },
25483
+ { id: "compass", name: "MongoDB Compass", category: "databases", about: "The MongoDB GUI.", size: "220 MB", source: gh("mongodb-js/compass", "^mongodb-compass-[\\d.]+-win32-x64\\.zip$"), exe: "MongoDBCompass.exe" },
25484
+ { id: "redisinsight", name: "Redis Insight", category: "databases", about: "The Redis GUI.", size: "110 MB", source: gh("redis/RedisInsight", "^Redis-Insight-win-installer\\.exe$"), unpack: "nsis", exe: "Redis Insight.exe", needs: ["7zip"] },
25485
+ { id: "dbgate", name: "DbGate", category: "databases", about: "Database manager for SQL and NoSQL databases.", size: "180 MB", source: gh("dbgate/dbgate", "^dbgate-[\\d.]+-win_x64\\.zip$"), exe: "DbGate.exe" },
25486
+ { id: "beekeeper", name: "Beekeeper Studio", category: "databases", about: "SQL editor and database manager.", size: "245 MB", source: gh("beekeeper-studio/beekeeper-studio", "^Beekeeper-Studio-[\\d.]+-portable\\.exe$"), unpack: "nsis", exe: "Beekeeper Studio.exe", needs: ["7zip"] },
25487
+ { id: "dynamodb-admin", name: "dynamodb-admin", category: "databases", about: "Web GUI for DynamoDB Local: run dynamodb-admin, then open http://localhost:8001.", size: "5 MB", source: { npm: "dynamodb-admin" }, exe: "dynamodb-admin.cmd", cli: true },
25488
+ // ---- API clients
25489
+ { id: "bruno", name: "Bruno", category: "api", about: "Offline, git-friendly API client (collections are files in your repo).", size: "175 MB", source: gh("usebruno/bruno", "^bruno_[\\d.]+_x64_win\\.zip$"), exe: "Bruno.exe" },
25490
+ { id: "insomnia", name: "Insomnia", category: "api", about: "REST, GraphQL and gRPC client.", size: "590 MB", source: gh("Kong/insomnia", "^insomnia-[\\d.]+-full\\.nupkg$"), exe: "Insomnia.exe" },
25491
+ // ---- git
25492
+ { id: "sourcegit", name: "SourceGit", category: "git", about: "Fast open-source Git GUI.", size: "26 MB", source: gh("sourcegit-scm/sourcegit", "^sourcegit_[\\d.]+\\.win-x64\\.zip$"), exe: "SourceGit.exe" },
25493
+ { id: "githubdesktop", name: "GitHub Desktop", category: "git", about: 'Simple Git GUI from GitHub. It has its own git, so it needs provisioning.git.access "full".', size: "300 MB", source: gh("desktop/desktop", "^GitHubDesktop-[\\d.]+-x64-full\\.nupkg$"), exe: "GitHubDesktop.exe", fullGitOnly: true },
25494
+ { id: "lazygit", name: "lazygit", category: "git", about: "Git in the terminal.", size: "7 MB", source: gh("jesseduffield/lazygit", "^lazygit_[\\d.]+_windows_x86_64\\.zip$"), exe: "lazygit.exe", cli: true },
25495
+ // ---- utilities
25496
+ { id: "7zip", name: "7-Zip", category: "utilities", about: "Archive manager (7z, zip, rar, tar ...). Also unpacks installers for other apps.", size: "2 MB", source: { resolve: "7zip" }, exe: "7zFM.exe" },
25497
+ { id: "winmerge", name: "WinMerge", category: "utilities", about: "Compare and merge files and folders.", size: "23 MB", source: gh("WinMerge/winmerge", "^winmerge-[\\d.]+-x64-exe\\.zip$"), exe: "WinMergeU.exe" },
25498
+ { id: "everything", name: "Everything", category: "utilities", about: "Finds files by name instantly.", size: "2 MB", source: { resolve: "everything" }, exe: "Everything.exe" },
25499
+ { id: "sysinternals", name: "Sysinternals Suite", category: "utilities", about: "Process Explorer, Process Monitor, Autoruns, TCPView and more (on PATH).", size: "200 MB", source: { url: "https://download.sysinternals.com/files/SysinternalsSuite.zip" }, exe: "procexp64.exe" },
25500
+ { id: "imhex", name: "ImHex", category: "utilities", about: "Hex editor for reverse engineering and binary formats.", size: "80 MB", source: gh("WerWolv/ImHex", "^imhex-[\\d.]+-Windows-Portable-NoGPU-x86_64\\.zip$"), exe: "imhex-gui.exe" },
25501
+ // ---- browsers
25502
+ { id: "chrome", name: "Chrome for Testing", category: "browsers", about: "Chrome build made for automated tests (with chromedriver on PATH).", size: "170 MB", source: { resolve: "chrome" }, exe: "chrome.exe" },
25503
+ { id: "firefox", name: "Firefox", category: "browsers", about: "Firefox for testing.", size: "75 MB", source: { resolve: "firefox" }, unpack: "nsis", exe: "firefox.exe", needs: ["7zip"] },
25504
+ // ---- game development
25505
+ { id: "godot", name: "Godot", category: "gamedev", about: "Open-source 2D and 3D game engine.", size: "80 MB", source: gh("godotengine/godot", "^Godot_v[\\d.]+-stable_win64\\.exe\\.zip$"), exe: "/^Godot_v[\\d.]+-stable_win64\\.exe$/", needs: ["mesa"] },
25506
+ { id: "blender", name: "Blender", category: "gamedev", about: "3D modelling, animation and rendering.", size: "400 MB", source: { resolve: "blender" }, exe: "blender.exe", needs: ["mesa"] },
25507
+ { id: "love", name: "L\xD6VE", category: "gamedev", about: "Lua framework for 2D games.", size: "4 MB", source: gh("love2d/love", "^love-[\\d.]+-win64\\.zip$"), exe: "love.exe", needs: ["mesa"] },
25508
+ { id: "defold", name: "Defold", category: "gamedev", about: "Free 2D/3D game engine and editor.", size: "330 MB", source: gh("defold/defold", "^Defold-x86_64-win32\\.zip$"), exe: "Defold.exe", needs: ["mesa"] },
25509
+ { id: "pixelorama", name: "Pixelorama", category: "gamedev", about: "Pixel-art and sprite editor.", size: "40 MB", source: gh("Orama-Interactive/Pixelorama", "^Pixelorama-Windows-64bit\\.zip$"), exe: "Pixelorama.exe", needs: ["mesa"] },
25510
+ { id: "tiled", name: "Tiled", category: "gamedev", about: "Tile map editor.", size: "22 MB", source: gh("mapeditor/tiled", "^Tiled-[\\d.]+_Windows-10\\+_x86_64\\.msi$"), unpack: "msi", exe: "tiled.exe" },
25511
+ // ---- cloud
25512
+ { id: "kubectl", name: "kubectl", category: "cloud", about: "Kubernetes command line.", size: "60 MB", source: { resolve: "kubectl" }, unpack: "file", exe: "kubectl.exe", cli: true },
25513
+ { id: "helm", name: "Helm", category: "cloud", about: "Kubernetes package manager.", size: "20 MB", source: { resolve: "helm" }, exe: "helm.exe", cli: true },
25514
+ { id: "k9s", name: "k9s", category: "cloud", about: "Kubernetes cluster UI in the terminal.", size: "40 MB", source: gh("derailed/k9s", "^k9s_Windows_amd64\\.zip$"), exe: "k9s.exe", cli: true },
25515
+ { id: "terraform", name: "Terraform", category: "cloud", about: "Infrastructure as code.", size: "30 MB", source: { resolve: "terraform" }, exe: "terraform.exe", cli: true },
25516
+ { id: "azure-cli", name: "Azure CLI", category: "cloud", about: "Manage Azure (az).", size: "90 MB", source: { url: "https://aka.ms/installazurecliwindowszipx64" }, exe: "az.cmd", cli: true },
25517
+ { id: "gcloud", name: "Google Cloud CLI", category: "cloud", about: "Manage Google Cloud (gcloud, gsutil, bq).", size: "120 MB", source: { url: "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-windows-x86_64-bundled-python.zip" }, exe: "gcloud.cmd", cli: true },
25518
+ { id: "aws-cli", name: "AWS CLI", category: "cloud", about: "Manage AWS (aws).", size: "50 MB", source: { url: "https://awscli.amazonaws.com/AWSCLIV2.msi" }, unpack: "msi", exe: "aws.exe", cli: true },
25519
+ // ---- diagrams and docs
25520
+ { id: "drawio", name: "draw.io", category: "diagrams", about: "Diagram editor (flowcharts, architecture, UML).", size: "170 MB", source: gh("jgraph/drawio-desktop", "^draw\\.io-[\\d.]+-windows\\.zip$"), exe: "draw.io.exe" },
25521
+ { id: "pandoc", name: "Pandoc", category: "diagrams", about: "Convert documents between Markdown, HTML, Word, PDF ...", size: "35 MB", source: gh("jgm/pandoc", "^pandoc-[\\d.]+-windows-x86_64\\.zip$"), exe: "pandoc.exe", cli: true },
25522
+ // ---- network
25523
+ { id: "mitmproxy", name: "mitmproxy", category: "network", about: "Intercepting HTTPS proxy (mitmweb opens a web UI).", size: "90 MB", source: { resolve: "mitmproxy" }, exe: "mitmweb.exe", cli: true },
25524
+ { id: "xh", name: "xh", category: "network", about: "Friendly HTTP requests from the terminal (like HTTPie).", size: "5 MB", source: gh("ducaale/xh", "^xh-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "xh.exe", cli: true },
25525
+ { id: "grpcurl", name: "grpcurl", category: "network", about: "curl for gRPC servers.", size: "10 MB", source: gh("fullstorydev/grpcurl", "^grpcurl_[\\d.]+_windows_x86_64\\.zip$"), exe: "grpcurl.exe", cli: true },
25526
+ { id: "k6", name: "k6", category: "network", about: "Load testing with JavaScript scripts.", size: "30 MB", source: gh("grafana/k6", "^k6-v[\\d.]+-windows-amd64\\.zip$"), exe: "k6.exe", cli: true },
25527
+ // ---- command-line tools
25528
+ { id: "jq", name: "jq", category: "cli", about: "Query and reshape JSON.", size: "1 MB", source: gh("jqlang/jq", "^jq-windows-amd64\\.exe$"), unpack: "file", exe: "jq.exe", cli: true },
25529
+ { id: "yq", name: "yq", category: "cli", about: "Query and edit YAML, JSON, XML and TOML.", size: "10 MB", source: gh("mikefarah/yq", "^yq_windows_amd64\\.exe$"), unpack: "file", exe: "yq.exe", cli: true },
25530
+ { id: "ripgrep", name: "ripgrep", category: "cli", about: "Very fast recursive search (rg).", size: "2 MB", source: gh("BurntSushi/ripgrep", "^ripgrep-[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "rg.exe", cli: true },
25531
+ { id: "fd", name: "fd", category: "cli", about: "Fast, friendly alternative to find.", size: "2 MB", source: gh("sharkdp/fd", "^fd-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "fd.exe", cli: true },
25532
+ { id: "bat", name: "bat", category: "cli", about: "cat with syntax highlighting and git changes.", size: "3 MB", source: gh("sharkdp/bat", "^bat-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "bat.exe", cli: true },
25533
+ { id: "fzf", name: "fzf", category: "cli", about: "Fuzzy finder for the terminal.", size: "2 MB", source: gh("junegunn/fzf", "^fzf-[\\d.]+-windows_amd64\\.zip$"), exe: "fzf.exe", cli: true },
25534
+ { id: "delta", name: "delta", category: "cli", about: "Readable git diffs with syntax highlighting.", size: "3 MB", source: gh("dandavison/delta", "^delta-[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "delta.exe", cli: true },
25535
+ { id: "just", name: "just", category: "cli", about: "Command runner (a simpler make for project tasks).", size: "2 MB", source: gh("casey/just", "^just-[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "just.exe", cli: true },
25536
+ { id: "hyperfine", name: "hyperfine", category: "cli", about: "Benchmark commands.", size: "1 MB", source: gh("sharkdp/hyperfine", "^hyperfine-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "hyperfine.exe", cli: true },
25537
+ { id: "watchexec", name: "watchexec", category: "cli", about: "Run a command when files change.", size: "5 MB", source: gh("watchexec/watchexec", "^watchexec-[\\d.]+-x86_64-pc-windows-msvc\\.zip$"), exe: "watchexec.exe", cli: true },
25538
+ { id: "protoc", name: "protoc", category: "cli", about: "Protocol Buffers compiler.", size: "3 MB", source: gh("protocolbuffers/protobuf", "^protoc-[\\d.]+-win64\\.zip$"), exe: "protoc.exe", cli: true },
25539
+ { id: "ninja", name: "Ninja", category: "cli", about: "Small, fast build system (CMake's favourite generator).", size: "1 MB", source: gh("ninja-build/ninja", "^ninja-win\\.zip$"), exe: "ninja.exe", cli: true },
25540
+ { id: "ffmpeg", name: "FFmpeg", category: "cli", about: "Convert and process audio and video.", size: "200 MB", source: gh("BtbN/FFmpeg-Builds", "^ffmpeg-master-latest-win64-gpl\\.zip$"), exe: "ffmpeg.exe", cli: true },
25541
+ { id: "sqlite", name: "SQLite tools", category: "cli", about: "sqlite3 command-line shell.", size: "5 MB", source: { resolve: "sqlite" }, exe: "sqlite3.exe", cli: true },
25542
+ { id: "shellcheck", name: "ShellCheck", category: "cli", about: "Finds bugs in shell scripts.", size: "10 MB", source: gh("koalaman/shellcheck", "^shellcheck-v[\\d.]+\\.zip$"), exe: "shellcheck.exe", cli: true },
25543
+ { id: "gitleaks", name: "Gitleaks", category: "cli", about: "Finds secrets committed to git.", size: "8 MB", source: gh("gitleaks/gitleaks", "^gitleaks_[\\d.]+_windows_x64\\.zip$"), exe: "gitleaks.exe", cli: true }
25544
+ ];
25545
+ var appById = (id) => APPS.find((a) => a.id === id);
25546
+ var exeMatcher = (exe) => {
25547
+ const regex = /^\/(.+)\/$/.exec(exe);
25548
+ if (regex) {
25549
+ const r = new RegExp(regex[1], "i");
25550
+ return (name) => r.test(name);
25551
+ }
25552
+ return (name) => name.toLowerCase() === exe.toLowerCase();
25553
+ };
25554
+ var customEntry = (id, app) => ({
25555
+ id: "custom/" + id,
25556
+ name: app.name,
25557
+ category: "utilities",
25558
+ about: "Your own program.",
25559
+ size: "?",
25560
+ source: app.github && app.asset ? { github: app.github, asset: app.asset } : { url: app.url },
25561
+ unpack: app.unpack,
25562
+ exe: app.exe,
25563
+ cli: app.cli
25564
+ });
25565
+ var appsToInstall = (apps, gitAccess) => {
25566
+ const chosen = apps.install.flatMap((id) => {
25567
+ const e = appById(id);
25568
+ return e && !e.setting ? [e] : [];
25569
+ });
25570
+ const skipped = chosen.filter((e) => e.fullGitOnly && gitAccess !== "full").map((e) => e.name + ' (needs provisioning.git.access "full")');
25571
+ const allowed = [...chosen.filter((e) => !(e.fullGitOnly && gitAccess !== "full")), ...Object.entries(apps.custom).map(([id, app]) => customEntry(id, app))];
25572
+ const needs7zip = allowed.some((e) => e.needs?.includes("7zip") || e.unpack === "nsis") && !allowed.some((e) => e.id === "7zip");
25573
+ return { entries: [...needs7zip ? [appById("7zip")] : [], ...allowed], skipped };
25574
+ };
25575
+ var appsNeedMesa = (apps) => Boolean(apps?.install.some((id) => appById(id)?.needs?.includes("mesa")));
25576
+
25577
+ // src/core/schema/apps.ts
25578
+ var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
25579
+ var AppId = external_exports.enum(CATALOGUE_IDS);
25580
+ var CustomAppId = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
25581
+ var compiles = (pattern) => {
25582
+ try {
25583
+ new RegExp(pattern);
25584
+ return true;
25585
+ } catch {
25586
+ return false;
25587
+ }
25588
+ };
25589
+ var CustomApp = external_exports.strictObject({
25590
+ name: external_exports.string().min(1).max(80).describe('The name on the desktop shortcut, e.g. "My Tool".'),
25591
+ github: external_exports.string().regex(/^[\w.-]+\/[\w.-]+$/, "owner/repo, e.g. sharkdp/bat").optional().describe("GitHub repository (owner/repo): the file comes from its latest release."),
25592
+ asset: external_exports.string().max(200).refine(compiles, "not a valid pattern").optional().describe("With github: a pattern (regular expression) matching the release file, e.g. windows.*x64\\.zip$"),
25593
+ url: external_exports.string().url().startsWith("https://", "https:// only").optional().describe("Or a direct https:// download link (zip, 7z, exe or msi)."),
25594
+ sha256: external_exports.string().regex(/^[0-9a-fA-F]{64}$/, "64 hex characters").optional().describe("SHA-256 of the download (GitHub releases usually publish one; then this is not needed)."),
25595
+ unpack: external_exports.enum(["archive", "file", "nsis", "msi"]).optional().describe("archive (zip, 7z, tar: the default), file (a single .exe), nsis (an installer 7-Zip can open) or msi."),
25596
+ exe: external_exports.string().min(1).max(200).describe("The program to start (found anywhere in the download), e.g. mytool.exe."),
25597
+ cli: external_exports.boolean().optional().describe("A command-line tool: its folder goes on PATH instead of getting a desktop shortcut.")
25598
+ }).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, { message: "give github + asset, or url (not both)" });
25599
+ var Apps = external_exports.strictObject({
25600
+ install: external_exports.array(AppId).describe("Apps from the catalogue to install in every sandbox (the Apps screen in the menu lists them by category). Each is downloaded once and kept."),
25601
+ custom: external_exports.record(CustomAppId, CustomApp).describe("Programs of your own: a GitHub release or a download link, and the program to start. Installed like the catalogue apps.")
25602
+ });
25603
+
25434
25604
  // src/core/schema/projects.ts
25435
25605
  var Projects = external_exports.strictObject({
25436
25606
  all: external_exports.boolean().describe("Map every project you have started before (and every folder in your roots) at every start, except those in exclude, so all of them open in the running sandbox without a restart. Every agent in the sandbox can then see all of them. Each one is still only set up when you first use it."),
@@ -25447,14 +25617,18 @@ var Config = external_exports.strictObject({
25447
25617
  defaultHarness: Name.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
25448
25618
  guestWorkspace: GuestWorkspace,
25449
25619
  readOnly: external_exports.boolean().describe("Map the workspace read-only."),
25620
+ workspaceFilter: WorkspaceFilter,
25621
+ audit: Audit,
25450
25622
  mappings: external_exports.array(Mapping).describe("Extra folders from this PC."),
25451
25623
  sandbox: Sandbox,
25452
25624
  storage: external_exports.strictObject({
25453
25625
  root: external_exports.string().min(1).describe("Where everything is kept on this PC (tools, databases, logins, launches)."),
25454
25626
  persistAgentState: external_exports.boolean().describe("Keep agent logins and history between sandboxes."),
25455
- dataName: Name.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces.")
25627
+ dataName: Name.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces."),
25628
+ markSandboxFiles: external_exports.boolean().describe(`Programs and scripts (.exe, .ps1, .bat, .cmd, .msi, .lnk ...) that appear or change in your project while a sandbox runs get Windows' "downloaded from the internet" mark, so SmartScreen and PowerShell ask before they run on this PC.`),
25629
+ warnDataGb: external_exports.number().min(0).describe("Say at launch when the persisted data (tools, databases, logins) is bigger than this many GB; 0 = never. sandbox data shows what takes the space.")
25456
25630
  }),
25457
- network: external_exports.strictObject({ blockPrivateRanges: external_exports.boolean().describe("Block your LAN (10/8, 172.16/12, 192.168/16, SMB) from inside the sandbox.") }),
25631
+ network: Network,
25458
25632
  provisioning: Provisioning,
25459
25633
  downloads: Downloads,
25460
25634
  toolchains: Toolchains,
@@ -25463,6 +25637,7 @@ var Config = external_exports.strictObject({
25463
25637
  agentCommands: AgentCommands,
25464
25638
  secrets: Secrets,
25465
25639
  personalization: toggle("Copy your desktop look (theme, accent, taskbar, wallpaper, ...) into the sandbox."),
25640
+ apps: Apps,
25466
25641
  claudeProfile: ClaudeProfile,
25467
25642
  harnesses: external_exports.record(Name, Harness).describe("Agents that can run in the sandbox."),
25468
25643
  hooks: external_exports.strictObject({ failFast: external_exports.boolean().describe("Stop when a hook script fails.") }),
@@ -25473,10 +25648,14 @@ var LocalOverrides = external_exports.strictObject({
25473
25648
  harness: Name.describe("Agent for this project."),
25474
25649
  guestWorkspace: GuestWorkspace,
25475
25650
  readOnly: external_exports.boolean().describe("Map this project read-only."),
25476
- mappings: external_exports.array(Mapping).describe("Extra folders (relative to this file)."),
25651
+ // A project may turn the filter on and keep more out, never let ignored files in.
25652
+ workspaceFilter: WorkspaceFilter.pick({ enabled: true, exclude: true }).partial(),
25653
+ mappings: external_exports.array(Mapping).describe("Extra folders inside this project (relative to this file), e.g. a read-only data folder at another place in the sandbox."),
25477
25654
  scripts: Strings.describe("Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent."),
25478
- sandbox: Sandbox.omit({ cpuLimit: true }).partial(),
25479
- network: external_exports.strictObject({ blockPrivateRanges: external_exports.boolean() }).partial(),
25655
+ // This PC's resources are yours to share: CPU and paging file (this PC's disk) are not a project's to set.
25656
+ sandbox: Sandbox.omit({ cpuLimit: true, pageFileMb: true }).partial(),
25657
+ // A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
25658
+ network: Network.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
25480
25659
  provisioning: Provisioning.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: Git.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
25481
25660
  downloads: Downloads.partial(),
25482
25661
  // Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
@@ -25487,7 +25666,9 @@ var LocalOverrides = external_exports.strictObject({
25487
25666
  databases: external_exports.strictObject(import_lodash.default.mapValues(Databases.shape, (shape) => shape.partial())).partial(),
25488
25667
  attach: Attach.partial(),
25489
25668
  personalization: toggle("Copy your desktop look into the sandbox.").partial(),
25490
- claudeProfile: ClaudeProfile.pick({ enabled: true, include: true, overwrite: true, copyCredentials: true, syncHistory: true, syncClaudeMem: true }).partial(),
25669
+ // Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add them.
25670
+ apps: Apps.pick({ install: true }).partial(),
25671
+ claudeProfile: ClaudeProfile.pick({ enabled: true, overwrite: true, copyCredentials: true, syncHistory: true, syncClaudeMem: true }).partial(),
25491
25672
  hooks: external_exports.strictObject({ failFast: external_exports.boolean() }).partial()
25492
25673
  }).partial();
25493
25674
 
@@ -25507,7 +25688,9 @@ var SandboxStatus = external_exports.object({
25507
25688
  updatedAt: Time,
25508
25689
  workspaceHost: Text(),
25509
25690
  guestWorkspace: Text(),
25510
- headless: external_exports.boolean()
25691
+ headless: external_exports.boolean(),
25692
+ /** The sandbox's IPv4 addresses (for network.forwardPorts; the host only uses ones on its Hyper-V network). */
25693
+ addresses: external_exports.array(external_exports.string().max(45)).max(8).optional()
25511
25694
  });
25512
25695
  var Version = external_exports.strictObject({ spec: Text(128), source: Text(256) });
25513
25696
  var DatabasePlan = external_exports.strictObject({
@@ -25615,6 +25798,8 @@ var runPaths = (dataDir2) => {
25615
25798
  responses: path2.join(run2, "responses"),
25616
25799
  sessions: path2.join(run2, "sessions"),
25617
25800
  projects: path2.join(run2, "projects"),
25801
+ /** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
25802
+ audit: path2.join(run2, "audit"),
25618
25803
  request: file3("requests"),
25619
25804
  response: file3("responses"),
25620
25805
  session: file3("sessions"),
@@ -25674,7 +25859,7 @@ var now = () => (/* @__PURE__ */ new Date()).toISOString();
25674
25859
 
25675
25860
  // src/guest/setup/claude.ts
25676
25861
  import fs6 from "node:fs";
25677
- import os3 from "node:os";
25862
+ import os4 from "node:os";
25678
25863
  import path7 from "node:path";
25679
25864
 
25680
25865
  // src/shared/safe-remove.ts
@@ -25738,6 +25923,7 @@ var safeRemove = (target, root) => {
25738
25923
 
25739
25924
  // src/guest/env.ts
25740
25925
  import fs5 from "node:fs";
25926
+ import os3 from "node:os";
25741
25927
  import path6 from "node:path";
25742
25928
  import { spawnSync } from "node:child_process";
25743
25929
 
@@ -25765,7 +25951,8 @@ var SYSTEM = {
25765
25951
  ipconfig: () => system32("ipconfig.exe"),
25766
25952
  robocopy: () => system32("Robocopy.exe"),
25767
25953
  shutdown: () => system32("shutdown.exe"),
25768
- dism: () => system32("Dism.exe")
25954
+ dism: () => system32("Dism.exe"),
25955
+ msiexec: () => system32("msiexec.exe")
25769
25956
  };
25770
25957
 
25771
25958
  // src/shared/download.ts
@@ -25823,10 +26010,10 @@ var download = async (url2, destination, expected = null) => {
25823
26010
  fs4.rmSync(partial2, { force: true });
25824
26011
  }
25825
26012
  };
25826
- var spawnAsync = (file3, args, options = {}) => new Promise((resolve, reject) => {
26013
+ var spawnAsync = (file3, args, options = {}) => new Promise((resolve2, reject) => {
25827
26014
  const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...options });
25828
26015
  child.once("error", reject);
25829
- child.once("close", (code) => resolve(code ?? -1));
26016
+ child.once("close", (code) => resolve2(code ?? -1));
25830
26017
  });
25831
26018
  var toAsset = (asset) => ({ url: asset.browser_download_url, name: asset.name, sha256: asset.digest?.startsWith("sha256:") ? asset.digest.slice(7) : null });
25832
26019
  var githubAsset = async (repo, pattern, searchOlder = false) => {
@@ -25965,8 +26152,9 @@ var setSandboxStatus = (phase, message) => {
25965
26152
  warn("Could not update sandbox status: " + errMsg(e));
25966
26153
  }
25967
26154
  };
26155
+ var ownAddresses = () => Object.values(os3.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
25968
26156
  var writeJsonAtomicChecked = (phase, message) => {
25969
- writeJsonAtomic(run.sandbox, { launchId: session.launchId, phase, message, updatedAt: now(), workspaceHost: session.workspaceHost, guestWorkspace: workspace, headless: session.headless });
26157
+ writeJsonAtomic(run.sandbox, { launchId: session.launchId, phase, message, updatedAt: now(), workspaceHost: session.workspaceHost, guestWorkspace: workspace, headless: session.headless, addresses: ownAddresses() });
25970
26158
  };
25971
26159
  var exec = (file3, args, options = {}) => {
25972
26160
  const result = spawnSync(file3, args, { stdio: "inherit", windowsHide: true, ...options });
@@ -26008,7 +26196,7 @@ var copyNode = (from, to) => {
26008
26196
  };
26009
26197
 
26010
26198
  // src/guest/setup/claude.ts
26011
- var claudeMemPaths = { store: path7.join(stateDir, "claude-mem"), local: path7.join(os3.homedir(), ".claude-mem") };
26199
+ var claudeMemPaths = { store: path7.join(stateDir, "claude-mem"), local: path7.join(os4.homedir(), ".claude-mem") };
26012
26200
  var claudeMemEnabled = () => session.claudeProfile.syncClaudeMem && !dryRun;
26013
26201
  var databaseFingerprint = (dir) => {
26014
26202
  const parts = [];
@@ -26026,11 +26214,39 @@ var databaseFingerprint = (dir) => {
26026
26214
  return parts.sort().join("|");
26027
26215
  };
26028
26216
  var lastSaved = null;
26217
+ var SQLITE_HEADER = "SQLite format 3\0";
26218
+ var looksLikeSqlite = (file3) => {
26219
+ if (!exists(file3)) return true;
26220
+ const fd = fs6.openSync(file3, "r");
26221
+ try {
26222
+ const head = Buffer.alloc(16);
26223
+ return fs6.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
26224
+ } finally {
26225
+ fs6.closeSync(fd);
26226
+ }
26227
+ };
26228
+ var MAX_BACKUPS = 3;
26229
+ var BACKUP_EVERY_MS = 6 * 3600 * 1e3;
26230
+ var keepBackup = (previous, dir) => {
26231
+ if (!exists(previous)) return;
26232
+ const backups = exists(dir) ? fs6.readdirSync(dir).filter((n) => /^\d{13}$/.test(n)).sort() : [];
26233
+ const newest = Number(backups[backups.length - 1] ?? 0);
26234
+ if (Date.now() - newest < BACKUP_EVERY_MS) {
26235
+ fs6.rmSync(previous, { recursive: true, force: true });
26236
+ return;
26237
+ }
26238
+ fs6.renameSync(previous, path7.join(mkdirp(dir), String(Date.now())));
26239
+ for (const old of [...backups, String(Date.now())].slice(0, -MAX_BACKUPS)) fs6.rmSync(path7.join(dir, old), { recursive: true, force: true });
26240
+ };
26029
26241
  var saveClaudeMem = () => {
26030
26242
  if (!claudeMemEnabled() || !exists(claudeMemPaths.local)) return;
26031
26243
  const { store: store2, local } = claudeMemPaths;
26032
26244
  const fingerprint = databaseFingerprint(local);
26033
26245
  if (fingerprint === lastSaved && exists(store2)) return;
26246
+ if (!looksLikeSqlite(path7.join(local, "claude-mem.db"))) {
26247
+ warn("claude-mem: the local database does not look valid, so it was not saved over the stored copy (" + local + ").");
26248
+ return;
26249
+ }
26034
26250
  const incoming = store2 + ".incoming";
26035
26251
  const previous = store2 + ".previous";
26036
26252
  fs6.rmSync(incoming, { recursive: true, force: true });
@@ -26043,7 +26259,7 @@ var saveClaudeMem = () => {
26043
26259
  if (exists(previous)) fs6.renameSync(previous, store2);
26044
26260
  throw e;
26045
26261
  }
26046
- fs6.rmSync(previous, { recursive: true, force: true });
26262
+ keepBackup(previous, store2 + ".backups");
26047
26263
  lastSaved = fingerprint;
26048
26264
  };
26049
26265
 
@@ -26051,8 +26267,8 @@ var saveClaudeMem = () => {
26051
26267
  import { spawn as spawn5 } from "node:child_process";
26052
26268
 
26053
26269
  // src/guest/daemon/project.ts
26054
- import fs30 from "node:fs";
26055
- import path44 from "node:path";
26270
+ import fs32 from "node:fs";
26271
+ import path45 from "node:path";
26056
26272
 
26057
26273
  // src/shared/projects.ts
26058
26274
  import path8 from "node:path";
@@ -26387,11 +26603,11 @@ var remembered = () => Object.fromEntries(Object.entries(readState(resolvedFile(
26387
26603
  var FRESH_MS = 24 * 60 * 60 * 1e3;
26388
26604
  var offline = false;
26389
26605
  var networkError = (e) => /fetch failed|timed? ?out|aborted|ENOTFOUND|EAI_AGAIN|ECONN|ENETUNREACH|EHOSTUNREACH|HTTP 5\d\d|socket/i.test(errMsg(e) + " " + String(e?.cause ?? ""));
26390
- var resolveCached = async (key, resolve) => {
26606
+ var resolveCached = async (key, resolve2) => {
26391
26607
  const cached2 = remembered()[key];
26392
26608
  if (cached2 && (offline || !session.provisioning.refresh && Date.now() - cached2.at < FRESH_MS)) return cached2.value;
26393
26609
  try {
26394
- const value = await resolve();
26610
+ const value = await resolve2();
26395
26611
  fs10.mkdirSync(toolsDir, { recursive: true });
26396
26612
  writeJsonAtomic(resolvedFile(), { ...remembered(), [key]: { value, at: Date.now() } });
26397
26613
  return value;
@@ -26445,11 +26661,11 @@ var workspaceEntries = () => {
26445
26661
  return found;
26446
26662
  };
26447
26663
  var wanted = (setting, toolchain) => setting === "auto" ? projectUses(workspaceEntries(), MARKERS[toolchain] ?? []) : setting;
26448
- var versionFromFiles = (files, parse3 = (t) => specFromVersionFile(t)) => {
26664
+ var versionFromFiles = (files, parse5 = (t) => specFromVersionFile(t)) => {
26449
26665
  for (const name of files) {
26450
26666
  const file3 = path14.join(projectWorkspace(), name);
26451
26667
  if (!exists(file3)) continue;
26452
- const spec = parse3(fs10.readFileSync(file3, "utf8"), name);
26668
+ const spec = parse5(fs10.readFileSync(file3, "utf8"), name);
26453
26669
  if (spec) return { spec, source: name };
26454
26670
  }
26455
26671
  return null;
@@ -26472,16 +26688,280 @@ var installOnce = async (env, group, packages, install) => {
26472
26688
  };
26473
26689
 
26474
26690
  // src/guest/toolchains/plan.ts
26475
- import path43 from "node:path";
26691
+ import fs31 from "node:fs";
26692
+ import os8 from "node:os";
26693
+ import path44 from "node:path";
26694
+
26695
+ // src/guest/apps/index.ts
26696
+ import fs11 from "node:fs";
26697
+ import os5 from "node:os";
26698
+ import path15 from "node:path";
26699
+
26700
+ // src/guest/apps/resolvers.ts
26701
+ var sumFor = (sums, file3) => sums.split(/\r?\n/).map((l) => /^([0-9a-f]{64})\s+\*?(.+)$/i.exec(l.trim())).find((m) => m && m[2].trim().endsWith(file3))?.[1].toLowerCase() ?? null;
26702
+ var firstHash = (text) => /\b([0-9a-f]{64})\b/i.exec(text)?.[1].toLowerCase() ?? null;
26703
+ var stripV = (tag) => tag.replace(/^v/, "");
26704
+ var RESOLVERS = {
26705
+ sublime: async () => {
26706
+ const { latest_version: build } = await fetchJson("https://www.sublimetext.com/updates/4/stable_update_check");
26707
+ return { url: "https://download.sublimetext.com/sublime_text_build_" + build + "_x64.zip", fileName: "sublime_text_" + build + ".zip" };
26708
+ },
26709
+ pgadmin: async () => {
26710
+ const versions = (await fetchJson("https://www.postgresql.org/versions.json")).filter((v) => v.supported);
26711
+ const current = versions.find((v) => v.current) ?? versions[versions.length - 1];
26712
+ const exact = current.major + "." + current.latestMinor;
26713
+ return { url: "https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip", fileName: "postgresql-" + exact + ".zip", members: ["pgsql/pgAdmin 4"] };
26714
+ },
26715
+ everything: async () => {
26716
+ const page = await fetchText("https://www.voidtools.com/downloads/");
26717
+ const version2 = /Everything-([\d.]+)\.x64\.zip/.exec(page)?.[1];
26718
+ if (!version2) throw new Error("could not find the Everything download on voidtools.com");
26719
+ const file3 = "Everything-" + version2 + ".x64.zip";
26720
+ const sums = await fetchText("https://www.voidtools.com/Everything-" + version2 + ".sha256").catch(() => "");
26721
+ return { url: "https://www.voidtools.com/" + file3, fileName: file3, sha256: sumFor(sums, file3) };
26722
+ },
26723
+ chrome: async () => {
26724
+ const data = await fetchJson("https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json");
26725
+ const hit = data.channels.Stable.downloads.chrome.find((d) => d.platform === "win64");
26726
+ if (!hit) throw new Error("no win64 Chrome for Testing build listed");
26727
+ return { url: hit.url, fileName: "chrome-win64.zip" };
26728
+ },
26729
+ firefox: async () => {
26730
+ const { LATEST_FIREFOX_VERSION: v } = await fetchJson("https://product-details.mozilla.org/1.0/firefox_versions.json");
26731
+ const base = "https://archive.mozilla.org/pub/firefox/releases/" + v + "/";
26732
+ const sums = await fetchText(base + "SHA256SUMS");
26733
+ return { url: base + "win64/en-US/Firefox%20Setup%20" + v + ".exe", fileName: "firefox-setup-" + v + ".exe", sha256: sumFor(sums, "win64/en-US/Firefox Setup " + v + ".exe") };
26734
+ },
26735
+ blender: async () => {
26736
+ const releases = await fetchText("https://download.blender.org/release/");
26737
+ const series = [...releases.matchAll(/href="Blender(\d+)\.(\d+)\/"/g)].map((m) => [Number(m[1]), Number(m[2])]).sort((a, b) => a[0] - b[0] || a[1] - b[1]).pop();
26738
+ if (!series) throw new Error("could not list Blender releases");
26739
+ const folder = "https://download.blender.org/release/Blender" + series[0] + "." + series[1] + "/";
26740
+ const listing = await fetchText(folder);
26741
+ const files = [...listing.matchAll(/href="(blender-([\d.]+)-windows-x64\.zip)"/g)].map((m) => ({ file: m[1], v: m[2].split(".").map(Number) }));
26742
+ const latest = files.sort((a, b) => a.v[2] - b.v[2]).pop();
26743
+ if (!latest) throw new Error("no Windows build in " + folder);
26744
+ const sums = await fetchText(folder + "blender-" + latest.v.join(".") + ".sha256").catch(() => "");
26745
+ return { url: folder + latest.file, fileName: latest.file, sha256: sumFor(sums, latest.file) };
26746
+ },
26747
+ kubectl: async () => {
26748
+ const v = (await fetchText("https://dl.k8s.io/release/stable.txt")).trim();
26749
+ const url2 = "https://dl.k8s.io/release/" + v + "/bin/windows/amd64/kubectl.exe";
26750
+ return { url: url2, fileName: "kubectl.exe", sha256: firstHash(await fetchText(url2 + ".sha256")) };
26751
+ },
26752
+ helm: async () => {
26753
+ const v = await latestGithubTag("helm/helm");
26754
+ const url2 = "https://get.helm.sh/helm-" + v + "-windows-amd64.zip";
26755
+ return { url: url2, fileName: "helm-" + v + ".zip", sha256: firstHash(await fetchText(url2 + ".sha256sum")) };
26756
+ },
26757
+ terraform: async () => {
26758
+ const { current_version: v } = await fetchJson("https://checkpoint-api.hashicorp.com/v1/check/terraform");
26759
+ const base = "https://releases.hashicorp.com/terraform/" + v + "/";
26760
+ const file3 = "terraform_" + v + "_windows_amd64.zip";
26761
+ return { url: base + file3, fileName: file3, sha256: sumFor(await fetchText(base + "terraform_" + v + "_SHA256SUMS"), file3) };
26762
+ },
26763
+ mitmproxy: async () => {
26764
+ const v = stripV(await latestGithubTag("mitmproxy/mitmproxy"));
26765
+ return { url: "https://downloads.mitmproxy.org/" + v + "/mitmproxy-" + v + "-windows-x86_64.zip", fileName: "mitmproxy-" + v + ".zip" };
26766
+ },
26767
+ sqlite: async () => {
26768
+ const page = await fetchText("https://sqlite.org/download.html");
26769
+ const file3 = /PRODUCT,[^,]+,(\d{4}\/sqlite-tools-win-x64-\d+\.zip),/.exec(page)?.[1];
26770
+ if (!file3) throw new Error("could not find the sqlite tools download on sqlite.org");
26771
+ return { url: "https://sqlite.org/" + file3, fileName: file3.split("/")[1] };
26772
+ },
26773
+ "7zip": async () => {
26774
+ const asset = await githubAsset("ip7z/7zip", /^7z\d+-x64\.exe$/);
26775
+ return { url: asset.url, fileName: asset.name, sha256: asset.sha256 };
26776
+ }
26777
+ };
26778
+
26779
+ // src/guest/apps/index.ts
26780
+ var MARKER = ".agent-sandbox-app";
26781
+ var PARALLEL = 3;
26782
+ var sevenZip = () => tool("apps", "7zip", "7z.exe");
26783
+ var resolve = async (entry) => {
26784
+ const s = entry.source;
26785
+ if ("github" in s) {
26786
+ const a = await githubAsset(s.github, new RegExp(s.asset), true);
26787
+ return { url: a.url, fileName: a.name, sha256: a.sha256 };
26788
+ }
26789
+ if ("url" in s) {
26790
+ const name = decodeURIComponent(new URL(s.url).pathname.split("/").pop() || entry.id);
26791
+ return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip" };
26792
+ }
26793
+ if ("resolve" in s && RESOLVERS[s.resolve]) return RESOLVERS[s.resolve]();
26794
+ throw new Error("no download source for " + entry.name);
26795
+ };
26796
+ var findExe = (root, exe) => {
26797
+ const match = exeMatcher(exe);
26798
+ let queue = [root];
26799
+ let seen = 0;
26800
+ for (let depth = 0; depth < 7 && queue.length; depth++) {
26801
+ const next = [];
26802
+ for (const dir of queue) {
26803
+ let entries2;
26804
+ try {
26805
+ entries2 = fs11.readdirSync(dir, { withFileTypes: true });
26806
+ } catch {
26807
+ continue;
26808
+ }
26809
+ const hit = entries2.find((e) => e.isFile() && match(e.name));
26810
+ if (hit) return path15.join(dir, hit.name);
26811
+ next.push(...entries2.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path15.join(dir, e.name)));
26812
+ if ((seen += entries2.length) > 5e4) return null;
26813
+ }
26814
+ queue = next;
26815
+ }
26816
+ return null;
26817
+ };
26818
+ var installApp = async (entry, dest) => {
26819
+ const work = stagingFolder(dest);
26820
+ const out = path15.join(work, "out");
26821
+ try {
26822
+ if ("npm" in entry.source) {
26823
+ const npmCli = path15.join(path15.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
26824
+ log("Installing " + entry.name + " (npm) ...");
26825
+ await execAsync(process.execPath, [npmCli, "install", "--prefix", mkdirp(out), "--no-audit", "--no-fund", "--loglevel=error", entry.source.npm]);
26826
+ } else {
26827
+ const d = await resolve(entry);
26828
+ log("Downloading " + entry.name + " (" + d.fileName + ", ~" + entry.size + " once) ...");
26829
+ const file3 = path15.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
26830
+ await download(d.url, file3, { sha256: d.sha256 ?? null });
26831
+ await unpack(entry, file3, out, d);
26832
+ }
26833
+ fs11.writeFileSync(path15.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
26834
+ moveIntoPlace(out, dest);
26835
+ } finally {
26836
+ safeRemove(work, path15.dirname(work));
26837
+ }
26838
+ };
26839
+ var unpack = async (entry, file3, out, d) => {
26840
+ if (entry.id === "7zip") {
26841
+ const sevenZr = path15.join(path15.dirname(file3), "7zr.exe");
26842
+ const zr = await githubAsset("ip7z/7zip", /^7zr\.exe$/);
26843
+ await download(zr.url, sevenZr, zr.sha256);
26844
+ await execAsync(sevenZr, ["x", "-y", "-o" + out, file3], { stdio: "ignore" });
26845
+ return;
26846
+ }
26847
+ switch (entry.unpack ?? "archive") {
26848
+ case "file": {
26849
+ mkdirp(out);
26850
+ fs11.renameSync(file3, path15.join(out, /^\//.test(entry.exe) ? path15.basename(file3) : entry.exe));
26851
+ return;
26852
+ }
26853
+ case "nsis": {
26854
+ if (!exists(sevenZip())) throw new Error("7-Zip is needed to unpack " + entry.name + " and could not be installed");
26855
+ const raw = path15.join(path15.dirname(out), "raw");
26856
+ await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
26857
+ const inner = findExe(raw, "/^app-64\\.7z$/");
26858
+ if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
26859
+ else fs11.renameSync(raw, out);
26860
+ return;
26861
+ }
26862
+ case "msi": {
26863
+ mkdirp(out);
26864
+ await execAsync(SYSTEM.msiexec(), ["/a", file3, "/qn", "TARGETDIR=" + out], { stdio: "ignore" });
26865
+ return;
26866
+ }
26867
+ default:
26868
+ await extractArchive(file3, out, d.members);
26869
+ }
26870
+ };
26871
+ var afterInstall = async (entry, exe) => {
26872
+ const dir = path15.dirname(exe);
26873
+ if (entry.needs?.includes("mesa")) {
26874
+ const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
26875
+ for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
26876
+ if (exists(path15.join(mesa, dll)) && !exists(path15.join(dir, dll))) fs11.copyFileSync(path15.join(mesa, dll), path15.join(dir, dll));
26877
+ }
26878
+ }
26879
+ if (entry.id === "godot" && !exists(path15.join(dir, "._sc_"))) fs11.writeFileSync(path15.join(dir, "._sc_"), "");
26880
+ if (entry.id === "sublime") mkdirp(path15.join(dir, "Data"));
26881
+ if (entry.id === "sysinternals") {
26882
+ for (const name of ["Process Explorer", "Process Monitor", "Autoruns", "TCPView", "PsExec", "PsList", "PsKill", "Handle", "ListDLLs", "Sigcheck", "Strings", "VMMap", "RAMMap", "DebugView", "Disk2vhd", "Du", "ZoomIt"]) {
26883
+ await execAsync(SYSTEM.reg(), ["add", "HKCU\\Software\\Sysinternals\\" + name, "/v", "EulaAccepted", "/t", "REG_DWORD", "/d", "1", "/f"], { stdio: "ignore" }).catch(() => void 0);
26884
+ }
26885
+ }
26886
+ };
26887
+ var shortcuts = (apps) => {
26888
+ if (!apps.length) return;
26889
+ const q = (s) => "'" + s.replace(/'/g, "''") + "'";
26890
+ const desktop = path15.join(os5.homedir(), "Desktop");
26891
+ const start = path15.join(process.env.APPDATA ?? path15.join(os5.homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Sandbox apps");
26892
+ const lines = ["$w = New-Object -ComObject WScript.Shell", "New-Item -ItemType Directory -Force -Path " + q(start) + " | Out-Null"];
26893
+ for (const app of apps) {
26894
+ for (const folder of [desktop, start]) {
26895
+ const name = app.name.replace(/[\\/:*?"<>|]/g, "");
26896
+ lines.push("$s = $w.CreateShortcut(" + q(path15.join(folder, name + ".lnk")) + "); $s.TargetPath = " + q(app.exe) + "; $s.WorkingDirectory = " + q(path15.dirname(app.exe)) + "; $s.Save()");
26897
+ }
26898
+ }
26899
+ powershell(lines.join("\n"));
26900
+ };
26901
+ var setupApps = async (env, apps, o) => {
26902
+ const { entries: entries2, skipped } = appsToInstall(apps, o.gitAccess);
26903
+ for (const s of skipped) env.summary.push("app skipped: " + s);
26904
+ if (dryRun) {
26905
+ log("(dry run) would install apps: " + entries2.map((e) => e.name).join(", "));
26906
+ return;
26907
+ }
26908
+ const gui = [];
26909
+ const installed2 = [];
26910
+ const one = async (entry) => {
26911
+ try {
26912
+ const dest = tool("apps", ...entry.id.split("/"));
26913
+ if (!exists(path15.join(dest, MARKER)) || o.refresh) await installApp(entry, dest);
26914
+ const exe = findExe(dest, entry.exe);
26915
+ if (!exe) throw new Error(entry.exe + " not found in the download");
26916
+ await afterInstall(entry, exe);
26917
+ if (entry.cli || entry.id === "sysinternals") env.prepend.push(path15.dirname(exe));
26918
+ if (!entry.cli) gui.push({ name: entry.name, exe });
26919
+ installed2.push(entry.name);
26920
+ } catch (e) {
26921
+ warn(entry.name + " could not be installed and is skipped; the other apps are not affected. Reason: " + errMsg(e));
26922
+ env.summary.push(entry.name + ": FAILED");
26923
+ }
26924
+ };
26925
+ const [first, rest] = entries2[0]?.id === "7zip" ? [[entries2[0]], entries2.slice(1)] : [[], entries2];
26926
+ for (const e of first) await one(e);
26927
+ const queue = [...rest];
26928
+ await Promise.all(Array.from({ length: Math.min(PARALLEL, queue.length) }, async () => {
26929
+ for (let e = queue.shift(); e; e = queue.shift()) await one(e);
26930
+ }));
26931
+ try {
26932
+ shortcuts(gui);
26933
+ } catch (e) {
26934
+ warn("App shortcuts could not be created: " + errMsg(e));
26935
+ }
26936
+ if (installed2.length) env.summary.push("apps: " + installed2.join(", ") + " (shortcuts on the desktop and in Start > Sandbox apps)");
26937
+ };
26938
+
26939
+ // src/guest/helpers.ts
26940
+ import fs12 from "node:fs";
26941
+ import os6 from "node:os";
26942
+ import path16 from "node:path";
26943
+ import crypto2 from "node:crypto";
26944
+ import { spawnSync as spawnSync3 } from "node:child_process";
26945
+ var CSC = path16.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
26946
+ var sourceHash = (name) => crypto2.createHash("sha256").update(fs12.readFileSync(path16.join(launchDir, "sandbox", name + ".cs"))).digest("hex").slice(0, 12);
26947
+ var ensureCompiled = (name) => {
26948
+ const exe = path16.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
26949
+ if (exists(exe)) return exe;
26950
+ if (!exists(CSC)) throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
26951
+ mkdirp(path16.dirname(exe));
26952
+ const result = spawnSync3(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, path16.join(launchDir, "sandbox", name + ".cs")], { encoding: "utf8", windowsHide: true });
26953
+ if (result.status !== 0) throw new Error("Compiling " + name + " failed: " + ((result.stdout ?? "") + (result.stderr ?? "")).trim().slice(0, 1500));
26954
+ return exe;
26955
+ };
26476
26956
 
26477
26957
  // src/guest/toolchains/databases/dynamodb.ts
26478
- import fs13 from "node:fs";
26479
- import path17 from "node:path";
26958
+ import fs15 from "node:fs";
26959
+ import path19 from "node:path";
26480
26960
  import { spawn as spawn3 } from "node:child_process";
26481
26961
 
26482
26962
  // src/guest/toolchains/java.ts
26483
- import fs11 from "node:fs";
26484
- import path15 from "node:path";
26963
+ import fs13 from "node:fs";
26964
+ import path17 from "node:path";
26485
26965
  var ADOPTIUM = "https://api.adoptium.net/v3";
26486
26966
  var MAVEN = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/";
26487
26967
  var temurin = async (major) => {
@@ -26500,19 +26980,19 @@ var setupJdk = async (env, config2) => {
26500
26980
  const { major, source } = await javaMajor(config2);
26501
26981
  const release = await resolveCached("java:" + major, async () => (await temurin(major)).release_name);
26502
26982
  const home = tool("java", release.replace(/[^A-Za-z0-9.-]/g, "_"));
26503
- if (!exists(path15.join(home, "bin", "java.exe"))) {
26983
+ if (!exists(path17.join(home, "bin", "java.exe"))) {
26504
26984
  const asset = await temurin(major);
26505
26985
  log("Downloading Java " + release + " (JDK, ~200 MB once) ...");
26506
26986
  await installArchive(asset.binary.package.link, home, { sha256: asset.binary.package.checksum, locate: "release", fileName: asset.binary.package.name });
26507
26987
  }
26508
26988
  env.vars.JAVA_HOME = home;
26509
- env.prepend.push(path15.join(home, "bin"));
26989
+ env.prepend.push(path17.join(home, "bin"));
26510
26990
  env.summary.push("java: " + release + " (Temurin, from " + source + ")");
26511
26991
  };
26512
26992
  var ensureJdk = async () => {
26513
26993
  const root = tool("java");
26514
- const installed2 = exists(root) ? fs11.readdirSync(root).filter((d) => exists(path15.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
26515
- if (installed2.length) return path15.join(root, installed2[0]);
26994
+ const installed2 = exists(root) ? fs13.readdirSync(root).filter((d) => exists(path17.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
26995
+ if (installed2.length) return path17.join(root, installed2[0]);
26516
26996
  const scratch = emptyEnv();
26517
26997
  await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
26518
26998
  return scratch.vars.JAVA_HOME;
@@ -26523,29 +27003,29 @@ var setupMaven = async (env) => {
26523
27003
  return pickPackageVersion(versions, "3") ?? Promise.reject(new Error("No Maven 3 release found"));
26524
27004
  });
26525
27005
  const home = tool("maven", version2);
26526
- if (!exists(path15.join(home, "bin", "mvn.cmd"))) {
27006
+ if (!exists(path17.join(home, "bin", "mvn.cmd"))) {
26527
27007
  const url2 = MAVEN + version2 + "/apache-maven-" + version2 + "-bin.zip";
26528
27008
  log("Downloading Maven " + version2 + " (~10 MB once) ...");
26529
27009
  await installArchive(url2, home, { sha512: (await fetchText(url2 + ".sha512")).trim().split(/\s+/)[0], locate: "LICENSE" });
26530
27010
  }
26531
27011
  const repo = tool("maven-repository");
26532
27012
  Object.assign(env.vars, { MAVEN_HOME: home, M2_HOME: home, MAVEN_OPTS: "-Dmaven.repo.local=" + repo });
26533
- env.prepend.push(path15.join(home, "bin"));
27013
+ env.prepend.push(path17.join(home, "bin"));
26534
27014
  env.summary.push("maven: " + version2);
26535
27015
  };
26536
27016
  var setupGradle = async (env) => {
26537
27017
  const current = await fetchJson("https://services.gradle.org/versions/current").catch(() => null);
26538
27018
  const version2 = await resolveCached("gradle", async () => current?.version ?? Promise.reject(new Error("Gradle version lookup failed")));
26539
27019
  const home = tool("gradle", version2);
26540
- if (!exists(path15.join(home, "bin", "gradle.bat"))) {
27020
+ if (!exists(path17.join(home, "bin", "gradle.bat"))) {
26541
27021
  if (!current || current.version !== version2) throw new Error("Gradle " + version2 + " is not installed and cannot be downloaded right now");
26542
27022
  log("Downloading Gradle " + version2 + " (~130 MB once) ...");
26543
27023
  await installArchive(current.downloadUrl, home, { sha256: (await fetchText(current.checksumUrl)).trim(), locate: "LICENSE", fileName: "gradle-" + version2 + ".zip" });
26544
27024
  }
26545
27025
  const userHome = tool("gradle-home");
26546
- fs11.mkdirSync(userHome, { recursive: true });
27026
+ fs13.mkdirSync(userHome, { recursive: true });
26547
27027
  Object.assign(env.vars, { GRADLE_HOME: home, GRADLE_USER_HOME: userHome, GRADLE_OPTS: "-Dorg.gradle.vfs.watch=false" });
26548
- env.prepend.push(path15.join(home, "bin"));
27028
+ env.prepend.push(path17.join(home, "bin"));
26549
27029
  env.summary.push("gradle: " + version2);
26550
27030
  };
26551
27031
  var setupJava = async (env, config2) => {
@@ -26564,20 +27044,20 @@ var setupJava = async (env, config2) => {
26564
27044
 
26565
27045
  // src/guest/ports.ts
26566
27046
  import net from "node:net";
26567
- var freePort = () => new Promise((resolve, reject) => {
27047
+ var freePort = () => new Promise((resolve2, reject) => {
26568
27048
  const server = net.createServer();
26569
27049
  server.once("error", reject);
26570
27050
  server.listen(0, "127.0.0.1", () => {
26571
27051
  const { port } = server.address();
26572
- server.close(() => resolve(port));
27052
+ server.close(() => resolve2(port));
26573
27053
  });
26574
27054
  });
26575
- var portOpen = (port) => new Promise((resolve) => {
27055
+ var portOpen = (port) => new Promise((resolve2) => {
26576
27056
  const socket = net.connect({ host: "127.0.0.1", port }, () => {
26577
27057
  socket.destroy();
26578
- resolve(true);
27058
+ resolve2(true);
26579
27059
  });
26580
- socket.once("error", () => resolve(false));
27060
+ socket.once("error", () => resolve2(false));
26581
27061
  });
26582
27062
  var waitForPort = async (port, seconds) => {
26583
27063
  for (const end = Date.now() + seconds * 1e3; Date.now() < end; ) {
@@ -26588,26 +27068,26 @@ var waitForPort = async (port, seconds) => {
26588
27068
  };
26589
27069
 
26590
27070
  // src/guest/toolchains/databases/server.ts
26591
- import fs12 from "node:fs";
26592
- import path16 from "node:path";
27071
+ import fs14 from "node:fs";
27072
+ import path18 from "node:path";
26593
27073
  import { spawn as spawn2 } from "node:child_process";
26594
- var dataFor = (name) => path16.join(dataDir, "databases", name);
27074
+ var dataFor = (name) => path18.join(dataDir, "databases", name);
26595
27075
  var startServer = async (name, exe, args, port) => {
26596
27076
  if (await portOpen(port)) throw new Error("port " + port + " is already in use (change databases." + name + ".port)");
26597
- const logFile2 = path16.join(logsDir, name + ".log");
26598
- const out = fs12.openSync(logFile2, "a");
27077
+ const logFile2 = path18.join(logsDir, name + ".log");
27078
+ const out = fs14.openSync(logFile2, "a");
26599
27079
  spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
26600
- fs12.closeSync(out);
27080
+ fs14.closeSync(out);
26601
27081
  if (!await waitForPort(port, 60)) throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
26602
27082
  };
26603
27083
  var clearStaleLocks = async (dir, files, port) => {
26604
27084
  if (await portOpen(port)) return;
26605
- for (const f of files) fs12.rmSync(path16.join(dir, f), { force: true });
27085
+ for (const f of files) fs14.rmSync(path18.join(dir, f), { force: true });
26606
27086
  };
26607
27087
  var createOnce = async (data, marker, create) => {
26608
- if (exists(path16.join(data, marker))) return;
27088
+ if (exists(path18.join(data, marker))) return;
26609
27089
  const existed = exists(data);
26610
- mkdirp(path16.dirname(data));
27090
+ mkdirp(path18.dirname(data));
26611
27091
  try {
26612
27092
  await create();
26613
27093
  } catch (e) {
@@ -26624,40 +27104,40 @@ var createOnce = async (data, marker, create) => {
26624
27104
  // src/guest/toolchains/databases/dynamodb.ts
26625
27105
  var DYNAMO_ZIP = "https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_latest.zip";
26626
27106
  var setupDynamo = async (env, plan2) => {
26627
- const java = path17.join(await ensureJdk(), "bin", "java.exe");
27107
+ const java = path19.join(await ensureJdk(), "bin", "java.exe");
26628
27108
  const home = tool("dynamodb-local");
26629
- if (!exists(path17.join(home, "DynamoDBLocal.jar"))) {
27109
+ if (!exists(path19.join(home, "DynamoDBLocal.jar"))) {
26630
27110
  log("Downloading DynamoDB Local (~60 MB once) ...");
26631
27111
  const sha256 = (await fetchText(DYNAMO_ZIP + ".sha256")).trim().split(/\s+/)[0];
26632
27112
  await installArchive(DYNAMO_ZIP, home, { sha256, locate: "DynamoDBLocal.jar", fileName: "dynamodb_local.zip" });
26633
27113
  }
26634
27114
  const data = mkdirp(dataFor("dynamodb"));
26635
- await startServer("dynamodb", java, ["-Djava.library.path=" + path17.join(home, "DynamoDBLocal_lib"), "-jar", path17.join(home, "DynamoDBLocal.jar"), "-sharedDb", "-dbPath", data, "-port", String(plan2.port)], plan2.port);
27115
+ await startServer("dynamodb", java, ["-Djava.library.path=" + path19.join(home, "DynamoDBLocal_lib"), "-jar", path19.join(home, "DynamoDBLocal.jar"), "-sharedDb", "-dbPath", data, "-port", String(plan2.port)], plan2.port);
26636
27116
  const endpoint = "http://localhost:" + plan2.port;
26637
27117
  const aws = { AWS_ENDPOINT_URL_DYNAMODB: endpoint, DYNAMO_ENDPOINT: endpoint, AWS_ACCESS_KEY_ID: "local", AWS_SECRET_ACCESS_KEY: "local", AWS_REGION: "us-east-1", AWS_DEFAULT_REGION: "us-east-1" };
26638
27118
  Object.assign(env.vars, aws);
26639
27119
  env.summary.push("dynamodb (DynamoDB Local): " + endpoint + " (AWS SDKs use it automatically via AWS_ENDPOINT_URL_DYNAMODB; dummy credentials)");
26640
27120
  if (!plan2.adminPort) return;
26641
27121
  const prefix = tool("dynamodb-admin");
26642
- const script = path17.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
27122
+ const script = path19.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
26643
27123
  if (!exists(script)) {
26644
27124
  log("Installing dynamodb-admin, the DynamoDB web UI (~20 MB once) ...");
26645
- const npmCli = path17.join(path17.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
27125
+ const npmCli = path19.join(path19.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
26646
27126
  await execAsync(process.execPath, [npmCli, "install", "--global", "--prefix", prefix, "dynamodb-admin", "--no-fund", "--no-audit"], { stdio: "ignore" });
26647
27127
  }
26648
27128
  if (await portOpen(plan2.adminPort)) {
26649
27129
  env.summary.push("dynamodb-admin: NOT started, port " + plan2.adminPort + " is in use (change databases.dynamodb.adminPort)");
26650
27130
  return;
26651
27131
  }
26652
- const out = fs13.openSync(path17.join(logsDir, "dynamodb-admin.log"), "a");
27132
+ const out = fs15.openSync(path19.join(logsDir, "dynamodb-admin.log"), "a");
26653
27133
  spawn3(process.execPath, [script, "--port", String(plan2.adminPort), "--dynamo-endpoint", endpoint, "--skip-default-credentials"], { detached: true, stdio: ["ignore", out, out], windowsHide: true, env: { ...process.env, ...aws } }).unref();
26654
- fs13.closeSync(out);
26655
- if (!await waitForPort(plan2.adminPort, 30)) throw new Error("dynamodb-admin did not start; see " + path17.join(logsDir, "dynamodb-admin.log"));
27134
+ fs15.closeSync(out);
27135
+ if (!await waitForPort(plan2.adminPort, 30)) throw new Error("dynamodb-admin did not start; see " + path19.join(logsDir, "dynamodb-admin.log"));
26656
27136
  env.summary.push("dynamodb-admin: http://localhost:" + plan2.adminPort + " (browse and edit tables in the sandbox's browser)");
26657
27137
  };
26658
27138
 
26659
27139
  // src/guest/toolchains/databases/mongodb.ts
26660
- import path18 from "node:path";
27140
+ import path20 from "node:path";
26661
27141
  var setupMongo = async (env, plan2) => {
26662
27142
  const find = async () => {
26663
27143
  const { versions } = await fetchJson("https://downloads.mongodb.org/full.json");
@@ -26668,24 +27148,24 @@ var setupMongo = async (env, plan2) => {
26668
27148
  };
26669
27149
  const version2 = await resolveCached("mongodb:" + plan2.version, async () => (await find()).version);
26670
27150
  const home = tool("mongodb", version2);
26671
- if (!exists(path18.join(home, "bin", "mongod.exe"))) {
27151
+ if (!exists(path20.join(home, "bin", "mongod.exe"))) {
26672
27152
  const { archive } = await find();
26673
27153
  log("Downloading MongoDB " + version2 + " (~400 MB once) ...");
26674
27154
  await installArchive(archive.url, home, { sha256: archive.sha256, locate: "mongod.exe", up: 1 });
26675
27155
  }
26676
27156
  const shell = tool("mongosh");
26677
- if (!exists(path18.join(shell, "mongosh.exe"))) {
27157
+ if (!exists(path20.join(shell, "mongosh.exe"))) {
26678
27158
  await installFromGithub("mongodb-js/mongosh", /^mongosh-[\d.]+-win32-x64\.zip$/, { dest: shell, what: "mongosh, the MongoDB shell (~50 MB once)", locate: "mongosh.exe" });
26679
27159
  }
26680
27160
  const data = mkdirp(dataFor("mongodb"));
26681
27161
  await clearStaleLocks(data, ["mongod.lock"], plan2.port);
26682
- await startServer("mongodb", path18.join(home, "bin", "mongod.exe"), ["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)], plan2.port);
26683
- env.prepend.push(path18.join(home, "bin"), shell);
27162
+ await startServer("mongodb", path20.join(home, "bin", "mongod.exe"), ["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)], plan2.port);
27163
+ env.prepend.push(path20.join(home, "bin"), shell);
26684
27164
  env.summary.push("mongodb " + version2 + ": mongodb://127.0.0.1:" + plan2.port + " (mongosh on PATH)");
26685
27165
  };
26686
27166
 
26687
27167
  // src/guest/toolchains/databases/mysql.ts
26688
- import path19 from "node:path";
27168
+ import path21 from "node:path";
26689
27169
  var MARIA = "https://downloads.mariadb.org/rest-api/mariadb/";
26690
27170
  var setupMysql = async (env, plan2) => {
26691
27171
  const series = await resolveCached("mariadb:" + plan2.version, async () => {
@@ -26701,8 +27181,8 @@ var setupMysql = async (env, plan2) => {
26701
27181
  };
26702
27182
  const version2 = await resolveCached("mariadb-version:" + series, async () => (await latest()).version);
26703
27183
  const home = tool("mariadb", version2);
26704
- const bin = path19.join(home, "bin");
26705
- if (!exists(path19.join(bin, "mariadbd.exe"))) {
27184
+ const bin = path21.join(home, "bin");
27185
+ if (!exists(path21.join(bin, "mariadbd.exe"))) {
26706
27186
  const { zip } = await latest();
26707
27187
  log("Downloading MariaDB " + version2 + " (~90 MB once) ...");
26708
27188
  await installArchive(zip.file_download_url.replace(/^http:/, "https:"), home, { sha256: zip.checksum?.sha256sum ?? null, locate: "mariadbd.exe", up: 1, fileName: zip.file_name });
@@ -26710,16 +27190,16 @@ var setupMysql = async (env, plan2) => {
26710
27190
  const data = dataFor("mariadb");
26711
27191
  await createOnce(data, "mysql", async () => {
26712
27192
  log("Creating the MariaDB database (first start) ...");
26713
- await execAsync(path19.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], { stdio: "ignore" });
27193
+ await execAsync(path21.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], { stdio: "ignore" });
26714
27194
  });
26715
- await startServer("mysql", path19.join(bin, "mariadbd.exe"), ["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"], plan2.port);
27195
+ await startServer("mysql", path21.join(bin, "mariadbd.exe"), ["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"], plan2.port);
26716
27196
  Object.assign(env.vars, { MYSQL_HOST: "127.0.0.1", MYSQL_TCP_PORT: String(plan2.port) });
26717
27197
  env.prepend.push(bin);
26718
27198
  env.summary.push("mysql (MariaDB " + version2 + "): 127.0.0.1:" + plan2.port + ", user root, no password (mysql://root@127.0.0.1:" + plan2.port + ")");
26719
27199
  };
26720
27200
 
26721
27201
  // src/guest/toolchains/databases/postgres.ts
26722
- import path20 from "node:path";
27202
+ import path22 from "node:path";
26723
27203
  var postgresData = (version2) => dataFor("postgres-" + version2.split(".")[0]);
26724
27204
  var setupPostgres = async (env, plan2) => {
26725
27205
  const exact = await resolveCached("postgres:" + plan2.version, async () => {
@@ -26728,8 +27208,8 @@ var setupPostgres = async (env, plan2) => {
26728
27208
  return hit ? hit.major + "." + hit.latestMinor : Promise.reject(new Error("No supported PostgreSQL " + plan2.version));
26729
27209
  });
26730
27210
  const home = tool("postgres", exact);
26731
- const bin = path20.join(home, "bin");
26732
- if (!exists(path20.join(bin, "pg_ctl.exe"))) {
27211
+ const bin = path22.join(home, "bin");
27212
+ if (!exists(path22.join(bin, "pg_ctl.exe"))) {
26733
27213
  log("Downloading PostgreSQL " + exact + " (~330 MB once) ...");
26734
27214
  await installArchive("https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip", home, {
26735
27215
  locate: "pg_ctl.exe",
@@ -26741,25 +27221,25 @@ var setupPostgres = async (env, plan2) => {
26741
27221
  const data = postgresData(exact);
26742
27222
  await createOnce(data, "PG_VERSION", async () => {
26743
27223
  log("Creating the PostgreSQL database (first start) ...");
26744
- await execAsync(path20.join(bin, "initdb.exe"), ["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"], { stdio: "ignore" });
27224
+ await execAsync(path22.join(bin, "initdb.exe"), ["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"], { stdio: "ignore" });
26745
27225
  });
26746
27226
  if (await portOpen(plan2.port)) throw new Error("port " + plan2.port + " is already in use (change databases.postgres.port)");
26747
27227
  await clearStaleLocks(data, ["postmaster.pid"], plan2.port);
26748
- await execAsync(path20.join(bin, "pg_ctl.exe"), ["start", "-D", data, "-w", "-t", "60", "-l", path20.join(logsDir, "postgres.log"), "-o", "-p " + plan2.port + " -c listen_addresses=localhost"], { stdio: "ignore" });
27228
+ await execAsync(path22.join(bin, "pg_ctl.exe"), ["start", "-D", data, "-w", "-t", "60", "-l", path22.join(logsDir, "postgres.log"), "-o", "-p " + plan2.port + " -c listen_addresses=localhost"], { stdio: "ignore" });
26749
27229
  Object.assign(env.vars, { PGHOST: "localhost", PGPORT: String(plan2.port), PGUSER: "postgres" });
26750
27230
  env.prepend.push(bin);
26751
27231
  env.summary.push("postgres " + exact + ": localhost:" + plan2.port + ", user postgres, no password (postgres://postgres@localhost:" + plan2.port + "/postgres)");
26752
27232
  };
26753
27233
 
26754
27234
  // src/guest/toolchains/databases/redis.ts
26755
- import path21 from "node:path";
27235
+ import path23 from "node:path";
26756
27236
  var setupRedis = async (env, plan2) => {
26757
27237
  const home = tool("redis");
26758
- if (!exists(path21.join(home, "redis-server.exe"))) {
27238
+ if (!exists(path23.join(home, "redis-server.exe"))) {
26759
27239
  await installFromGithub("redis-windows/redis-windows", /^Redis-[\d.]+-Windows-x64-msys2\.zip$/, { dest: home, what: (a) => "Redis (" + a.name + ", ~10 MB once)", locate: "redis-server.exe" });
26760
27240
  }
26761
27241
  const data = mkdirp(dataFor("redis"));
26762
- await startServer("redis", path21.join(home, "redis-server.exe"), ["--port", String(plan2.port), "--bind", "127.0.0.1", "--dir", data.replace(/\\/g, "/"), "--appendonly", "yes"], plan2.port);
27242
+ await startServer("redis", path23.join(home, "redis-server.exe"), ["--port", String(plan2.port), "--bind", "127.0.0.1", "--dir", data.replace(/\\/g, "/"), "--appendonly", "yes"], plan2.port);
26763
27243
  env.prepend.push(home);
26764
27244
  env.summary.push("redis: redis://127.0.0.1:" + plan2.port + " (redis-cli on PATH)");
26765
27245
  };
@@ -26784,28 +27264,8 @@ var setupDatabase = async (env, plan2) => {
26784
27264
  };
26785
27265
 
26786
27266
  // src/guest/toolchains/git.ts
26787
- import fs15 from "node:fs";
26788
- import path23 from "node:path";
26789
-
26790
- // src/guest/helpers.ts
26791
- import fs14 from "node:fs";
26792
- import os4 from "node:os";
26793
- import path22 from "node:path";
26794
- import crypto2 from "node:crypto";
26795
- import { spawnSync as spawnSync3 } from "node:child_process";
26796
- var CSC = path22.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
26797
- var sourceHash = (name) => crypto2.createHash("sha256").update(fs14.readFileSync(path22.join(launchDir, "sandbox", name + ".cs"))).digest("hex").slice(0, 12);
26798
- var ensureCompiled = (name) => {
26799
- const exe = path22.join(os4.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
26800
- if (exists(exe)) return exe;
26801
- if (!exists(CSC)) throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
26802
- mkdirp(path22.dirname(exe));
26803
- const result = spawnSync3(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, path22.join(launchDir, "sandbox", name + ".cs")], { encoding: "utf8", windowsHide: true });
26804
- if (result.status !== 0) throw new Error("Compiling " + name + " failed: " + ((result.stdout ?? "") + (result.stderr ?? "")).trim().slice(0, 1500));
26805
- return exe;
26806
- };
26807
-
26808
- // src/guest/toolchains/git.ts
27267
+ import fs16 from "node:fs";
27268
+ import path24 from "node:path";
26809
27269
  var BLOCKED_HOOKS = ["pre-commit", "commit-msg", "pre-merge-commit", "pre-push", "pre-rebase", "pre-applypatch", "applypatch-msg"];
26810
27270
  var posix = (p) => p.replace(/\\/g, "/");
26811
27271
  var installPortableGit = async (root) => {
@@ -26816,50 +27276,50 @@ var installPortableGit = async (root) => {
26816
27276
  await download(asset.url, sfx, asset.sha256);
26817
27277
  await execAsync(sfx, ["-o" + root, "-y"], { stdio: "ignore" });
26818
27278
  } finally {
26819
- fs15.rmSync(sfx, { force: true });
27279
+ fs16.rmSync(sfx, { force: true });
26820
27280
  }
26821
27281
  };
26822
27282
  var installGuard = (env, access, realGit) => {
26823
27283
  const dir = mkdirp(tool("gitguard"));
26824
- const guard = path23.join(launchDir, "runtime", "gitguard.js");
26825
- if (duringSession() && (exists(path23.join(dir, "git.exe")) || exists(path23.join(dir, "git.cmd")))) {
27284
+ const guard = path24.join(launchDir, "runtime", "gitguard.js");
27285
+ if (duringSession() && (exists(path24.join(dir, "git.exe")) || exists(path24.join(dir, "git.cmd")))) {
26826
27286
  } else try {
26827
- fs15.copyFileSync(ensureCompiled("gitshim"), path23.join(dir, "git.exe"));
26828
- fs15.rmSync(path23.join(dir, "git.cmd"), { force: true });
27287
+ fs16.copyFileSync(ensureCompiled("gitshim"), path24.join(dir, "git.exe"));
27288
+ fs16.rmSync(path24.join(dir, "git.cmd"), { force: true });
26829
27289
  } catch (e) {
26830
27290
  warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
26831
- fs15.writeFileSync(path23.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
27291
+ fs16.writeFileSync(path24.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
26832
27292
  }
26833
- fs15.writeFileSync(path23.join(dir, "bashenv.sh"), 'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n');
27293
+ fs16.writeFileSync(path24.join(dir, "bashenv.sh"), 'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n');
26834
27294
  env.prepend.unshift(dir);
26835
27295
  Object.assign(env.vars, {
26836
27296
  AGENT_GIT_ACCESS: access,
26837
27297
  AGENT_REAL_GIT: access === "readonly" ? realGit : "",
26838
27298
  AGENT_GUARD_NODE: process.execPath,
26839
27299
  AGENT_GUARD_SCRIPT: guard,
26840
- BASH_ENV: posix(path23.join(dir, "bashenv.sh"))
27300
+ BASH_ENV: posix(path24.join(dir, "bashenv.sh"))
26841
27301
  });
26842
27302
  if (access === "readonly") {
26843
- const hooks = mkdirp(path23.join(dir, "hooks"));
26844
- for (const hook of BLOCKED_HOOKS) fs15.writeFileSync(path23.join(hooks, hook), '#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n');
27303
+ const hooks = mkdirp(path24.join(dir, "hooks"));
27304
+ for (const hook of BLOCKED_HOOKS) fs16.writeFileSync(path24.join(hooks, hook), '#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n');
26845
27305
  Object.assign(env.vars, { GIT_CONFIG_COUNT: "1", GIT_CONFIG_KEY_0: "core.hooksPath", GIT_CONFIG_VALUE_0: posix(hooks) });
26846
27306
  } else {
26847
- env.vars.GIT_DIR = path23.join(dataDir, "git-disabled");
27307
+ env.vars.GIT_DIR = path24.join(dataDir, "git-disabled");
26848
27308
  }
26849
27309
  };
26850
27310
  var pointAtOwnCertificates = (root) => {
26851
- const config2 = path23.join(root, "etc", "gitconfig");
26852
- const bundle = path23.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
27311
+ const config2 = path24.join(root, "etc", "gitconfig");
27312
+ const bundle = path24.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
26853
27313
  if (!exists(config2) || !exists(bundle)) return;
26854
- const text = fs15.readFileSync(config2, "utf8");
27314
+ const text = fs16.readFileSync(config2, "utf8");
26855
27315
  const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key) => key + posix(bundle));
26856
- if (fixed !== text) fs15.writeFileSync(config2, fixed);
27316
+ if (fixed !== text) fs16.writeFileSync(config2, fixed);
26857
27317
  };
26858
27318
  var setupGit = async (env, hostCopy, refresh, access) => {
26859
27319
  const root = tool("git");
26860
- const bash = path23.join(root, "bin", "bash.exe");
26861
- const gitExe = path23.join(root, "cmd", "git.exe");
26862
- const hostGit = path23.join(hostToolsDir, "git");
27320
+ const bash = path24.join(root, "bin", "bash.exe");
27321
+ const gitExe = path24.join(root, "cmd", "git.exe");
27322
+ const hostGit = path24.join(hostToolsDir, "git");
26863
27323
  if (exists(root) && !exists(bash)) {
26864
27324
  log("Replacing the old MinGit (no bash) with full Git for Windows.");
26865
27325
  safeRemove(root, toolsDir);
@@ -26871,11 +27331,11 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26871
27331
  }
26872
27332
  const work = stagingFolder(root);
26873
27333
  try {
26874
- if (hostCopy && exists(path23.join(hostGit, "bin", "bash.exe"))) {
27334
+ if (hostCopy && exists(path24.join(hostGit, "bin", "bash.exe"))) {
26875
27335
  log("Copying Git for Windows from this PC ...");
26876
27336
  robocopy(hostGit, work);
26877
27337
  } else await installPortableGit(work);
26878
- if (!exists(path23.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
27338
+ if (!exists(path24.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
26879
27339
  moveIntoPlace(work, root);
26880
27340
  } finally {
26881
27341
  safeRemove(work, toolsDir);
@@ -26884,10 +27344,10 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26884
27344
  if (!exists(bash)) throw new Error("bash.exe missing after installing Git");
26885
27345
  pointAtOwnCertificates(root);
26886
27346
  env.vars.CLAUDE_CODE_GIT_BASH_PATH = bash;
26887
- env.append.push(path23.join(root, "usr", "bin"));
27347
+ env.append.push(path24.join(root, "usr", "bin"));
26888
27348
  const version2 = execOutput(gitExe, ["--version"]).replace(/^git version /, "");
26889
27349
  if (access === "full") {
26890
- env.prepend.push(path23.join(root, "cmd"));
27350
+ env.prepend.push(path24.join(root, "cmd"));
26891
27351
  env.summary.push("git: " + version2);
26892
27352
  return;
26893
27353
  }
@@ -26896,8 +27356,8 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26896
27356
  };
26897
27357
 
26898
27358
  // src/guest/toolchains/go.ts
26899
- import fs16 from "node:fs";
26900
- import path24 from "node:path";
27359
+ import fs17 from "node:fs";
27360
+ import path25 from "node:path";
26901
27361
  var findRelease = async (spec) => pickGoRelease(await fetchJson("https://go.dev/dl/?mode=json&include=all"), spec) ?? Promise.reject(new Error('No Go release matches "' + spec + '"'));
26902
27362
  var setupGo = async (env, config2) => {
26903
27363
  if (dryRun) {
@@ -26906,7 +27366,7 @@ var setupGo = async (env, config2) => {
26906
27366
  }
26907
27367
  const version2 = await resolveCached("go:" + config2.version, async () => (await findRelease(config2.version)).version);
26908
27368
  const root = tool("go", version2);
26909
- if (!exists(path24.join(root, "bin", "go.exe"))) {
27369
+ if (!exists(path25.join(root, "bin", "go.exe"))) {
26910
27370
  const goArch = arch === "arm64" ? "arm64" : "amd64";
26911
27371
  const file3 = (await findRelease(version2)).files.find((f) => f.os === "windows" && f.arch === goArch && f.kind === "archive");
26912
27372
  if (!file3) throw new Error(version2 + " has no Windows " + goArch + " zip");
@@ -26914,18 +27374,18 @@ var setupGo = async (env, config2) => {
26914
27374
  await installArchive("https://go.dev/dl/" + file3.filename, root, { sha256: file3.sha256, locate: "VERSION", fileName: file3.filename });
26915
27375
  }
26916
27376
  const GOPATH = tool("go-path");
26917
- const vars = { GOROOT: root, GOPATH, GOBIN: path24.join(GOPATH, "bin"), GOMODCACHE: path24.join(GOPATH, "pkg", "mod"), GOCACHE: tool("go-cache"), GOTOOLCHAIN: "auto", GOTELEMETRY: "off" };
26918
- fs16.mkdirSync(vars.GOBIN, { recursive: true });
27377
+ const vars = { GOROOT: root, GOPATH, GOBIN: path25.join(GOPATH, "bin"), GOMODCACHE: path25.join(GOPATH, "pkg", "mod"), GOCACHE: tool("go-cache"), GOTOOLCHAIN: "auto", GOTELEMETRY: "off" };
27378
+ fs17.mkdirSync(vars.GOBIN, { recursive: true });
26919
27379
  Object.assign(env.vars, vars);
26920
- env.prepend.push(path24.join(root, "bin"), vars.GOBIN);
26921
- const go = path24.join(root, "bin", "go.exe");
27380
+ env.prepend.push(path25.join(root, "bin"), vars.GOBIN);
27381
+ const go = path25.join(root, "bin", "go.exe");
26922
27382
  env.summary.push("go: " + versionOf(go, ["version"]));
26923
27383
  await installOnce(env, "go", config2.tools, (pkg) => execAsync(go, ["install", pkg.includes("@") ? pkg : pkg + "@latest"], { env: { ...process.env, ...vars } }));
26924
27384
  };
26925
27385
 
26926
27386
  // src/guest/toolchains/cli.ts
26927
- import fs17 from "node:fs";
26928
- import path26 from "node:path";
27387
+ import fs18 from "node:fs";
27388
+ import path27 from "node:path";
26929
27389
 
26930
27390
  // src/guest/toolchains/catalogue.ts
26931
27391
  var pwshAsset = (arch2) => arch2 === "arm64" ? /^PowerShell-\d+\.\d+\.\d+-win-arm64\.zip$/ : /^PowerShell-\d+\.\d+\.\d+-win-x64\.zip$/;
@@ -26950,14 +27410,14 @@ var decideCli = (settings, ctx) => {
26950
27410
  };
26951
27411
 
26952
27412
  // src/guest/toolchains/runtimes.ts
26953
- import path25 from "node:path";
27413
+ import path26 from "node:path";
26954
27414
  var setupSingleExe = async (env, name, repo, pattern, exeName, dir, options = {}) => {
26955
27415
  if (dryRun) {
26956
27416
  log("(dry run) would provision " + name);
26957
27417
  return;
26958
27418
  }
26959
- const bin = options.subdir ? path25.join(dir, options.subdir) : dir;
26960
- const exe = path25.join(bin, exeName);
27419
+ const bin = options.subdir ? path26.join(dir, options.subdir) : dir;
27420
+ const exe = path26.join(bin, exeName);
26961
27421
  if (!exists(exe) || options.refresh) {
26962
27422
  const size = options.size ? ", ~" + options.size : "";
26963
27423
  await installFromGithub(repo, pattern, { dest: dir, what: (a) => name + " (" + a.name + size + " once)", ...options.subdir ? {} : { locate: exeName } });
@@ -26968,7 +27428,7 @@ var setupSingleExe = async (env, name, repo, pattern, exeName, dir, options = {}
26968
27428
  };
26969
27429
  var setupBun = async (env) => {
26970
27430
  await setupSingleExe(env, "bun", "oven-sh/bun", arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/, "bun.exe", tool("bun", "bin"), { size: "35 MB" });
26971
- Object.assign(env.vars, { BUN_INSTALL: tool("bun"), BUN_INSTALL_CACHE_DIR: path25.join(localDir, "bun-cache"), BUN_TMPDIR: path25.join(localDir, "bun-tmp") });
27431
+ Object.assign(env.vars, { BUN_INSTALL: tool("bun"), BUN_INSTALL_CACHE_DIR: path26.join(localDir, "bun-cache"), BUN_TMPDIR: path26.join(localDir, "bun-tmp") });
26972
27432
  };
26973
27433
  var setupDeno = async (env) => {
26974
27434
  await setupSingleExe(env, "deno", "denoland/deno", arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/, "deno.exe", tool("deno", "bin"), { size: "40 MB" });
@@ -26982,7 +27442,7 @@ var setupUv = async (env) => {
26982
27442
  };
26983
27443
 
26984
27444
  // src/guest/toolchains/cli.ts
26985
- var ghConfigDir = () => path26.join(stateDir, "gh");
27445
+ var ghConfigDir = () => path27.join(stateDir, "gh");
26986
27446
  var toolVars = {
26987
27447
  gh: () => ({ GH_CONFIG_DIR: mkdirp(ghConfigDir()), GH_NO_UPDATE_NOTIFIER: "1", GH_NO_EXTENSION_UPDATE_NOTIFIER: "1" })
26988
27448
  };
@@ -26992,16 +27452,16 @@ var shimOpenssl = (env) => {
26992
27452
  return;
26993
27453
  }
26994
27454
  const shims = mkdirp(tool("shims"));
26995
- fs17.copyFileSync(ensureCompiled("openssl"), path26.join(shims, "openssl.exe"));
26996
- fs17.rmSync(path26.join(shims, "openssl.cmd"), { force: true });
27455
+ fs18.copyFileSync(ensureCompiled("openssl"), path27.join(shims, "openssl.exe"));
27456
+ fs18.rmSync(path27.join(shims, "openssl.cmd"), { force: true });
26997
27457
  env.prepend.push(shims);
26998
27458
  env.summary.push("openssl: Git for Windows' copy");
26999
27459
  };
27000
27460
  var setupCli = async (env, settings, gitAccess, refresh = false) => {
27001
- const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path26.join(projectWorkspace(), ".github")) });
27461
+ const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path27.join(projectWorkspace(), ".github")) });
27002
27462
  if (settings.gh && !decisions.gh.on) {
27003
27463
  env.summary.push("gh: off (" + decisions.gh.reason + ")");
27004
- if (exists(path26.join(ghConfigDir(), "hosts.yml"))) warn('gh is off (git access is not "full"), but an earlier gh login is still stored in ' + ghConfigDir() + " and readable by the agent. Run `gh auth logout` in a full-access sandbox, or delete that folder.");
27464
+ if (exists(path27.join(ghConfigDir(), "hosts.yml"))) warn('gh is off (git access is not "full"), but an earlier gh login is still stored in ' + ghConfigDir() + " and readable by the agent. Run `gh auth logout` in a full-access sandbox, or delete that folder.");
27005
27465
  }
27006
27466
  if (dryRun) {
27007
27467
  log("(dry run) would provision CLI tools: " + Object.entries(decisions).filter(([, d]) => d.on).map(([n]) => n).join(", "));
@@ -27029,11 +27489,11 @@ var setupCli = async (env, settings, gitAccess, refresh = false) => {
27029
27489
  };
27030
27490
 
27031
27491
  // src/guest/toolchains/managers.ts
27032
- import fs18 from "node:fs";
27033
- import path27 from "node:path";
27492
+ import fs19 from "node:fs";
27493
+ import path28 from "node:path";
27034
27494
  var voltaPins = () => {
27035
27495
  try {
27036
- const pkg = JSON.parse(fs18.readFileSync(path27.join(projectWorkspace(), "package.json"), "utf8").replace(/^/, ""));
27496
+ const pkg = JSON.parse(fs19.readFileSync(path28.join(projectWorkspace(), "package.json"), "utf8").replace(/^/, ""));
27037
27497
  return Object.fromEntries(Object.entries(pkg.volta ?? {}).filter((e) => ["node", "npm", "yarn", "pnpm"].includes(e[0]) && typeof e[1] === "string"));
27038
27498
  } catch {
27039
27499
  return {};
@@ -27047,22 +27507,22 @@ var setupVolta = async (env) => {
27047
27507
  return;
27048
27508
  }
27049
27509
  const dir = tool("volta");
27050
- if (!exists(path27.join(dir, "volta.exe"))) {
27510
+ if (!exists(path28.join(dir, "volta.exe"))) {
27051
27511
  const pattern = arch === "arm64" ? /^volta-[\d.]+-windows-arm64\.zip$/ : /^volta-[\d.]+-windows\.zip$/;
27052
27512
  await installFromGithub("volta-cli/volta", pattern, { dest: dir, what: "Volta (~15 MB once)", locate: "volta.exe" });
27053
27513
  }
27054
27514
  for (const shim3 of ["node", "npm", "npx", "pnpm", "pnpx", "yarn", "yarnpkg"]) {
27055
- const target = path27.join(dir, shim3 + ".exe");
27056
- if (!exists(target)) fs18.copyFileSync(path27.join(dir, "volta-shim.exe"), target);
27515
+ const target = path28.join(dir, shim3 + ".exe");
27516
+ if (!exists(target)) fs19.copyFileSync(path28.join(dir, "volta-shim.exe"), target);
27057
27517
  }
27058
27518
  const home = mkdirp(tool("volta-home"));
27059
- const shims = mkdirp(path27.join(home, "bin"));
27519
+ const shims = mkdirp(path28.join(home, "bin"));
27060
27520
  const vars = { VOLTA_HOME: home, VOLTA_FEATURE_PNPM: "1" };
27061
27521
  Object.assign(env.vars, vars);
27062
27522
  const pins = voltaPins();
27063
27523
  if (Object.keys(pins).length) env.prepend.push(dir, shims);
27064
27524
  else env.append.push(dir, shims);
27065
- const volta = path27.join(dir, "volta.exe");
27525
+ const volta = path28.join(dir, "volta.exe");
27066
27526
  for (const [toolName, version2] of Object.entries(pins)) {
27067
27527
  try {
27068
27528
  await execAsync(volta, ["install", toolName + "@" + version2], { env: { ...process.env, ...vars }, cwd: projectWorkspace(), stdio: "ignore" });
@@ -27080,22 +27540,22 @@ var setupPyenv = async (env) => {
27080
27540
  return;
27081
27541
  }
27082
27542
  const root = tool("pyenv", "pyenv-win");
27083
- if (!exists(path27.join(root, "bin", "pyenv.bat"))) {
27543
+ if (!exists(path28.join(root, "bin", "pyenv.bat"))) {
27084
27544
  const tag = await resolveCached("pyenv-win", () => latestGithubTag("pyenv-win/pyenv-win"));
27085
27545
  log("Downloading pyenv-win " + tag + " (~5 MB once) ...");
27086
27546
  await installArchive("https://github.com/pyenv-win/pyenv-win/archive/refs/tags/" + encodeURIComponent(tag) + ".zip", root, { locate: "pyenv.bat", up: 1, fileName: "pyenv-win.zip" });
27087
27547
  }
27088
- const home = root + path27.sep;
27548
+ const home = root + path28.sep;
27089
27549
  Object.assign(env.vars, { PYENV: home, PYENV_ROOT: home, PYENV_HOME: home });
27090
- env.append.push(path27.join(root, "bin"), path27.join(root, "shims"));
27550
+ env.append.push(path28.join(root, "bin"), path28.join(root, "shims"));
27091
27551
  env.summary.push("pyenv-win: pyenv install <version> / pyenv local <version> (versions persist)");
27092
27552
  };
27093
27553
 
27094
27554
  // src/guest/toolchains/native/cpp.ts
27095
- import path28 from "node:path";
27555
+ import path29 from "node:path";
27096
27556
  var setupCpp = async (env, config2) => {
27097
27557
  const bin = tool("mingw", "mingw64", "bin");
27098
- const gcc = path28.join(bin, "gcc.exe");
27558
+ const gcc = path29.join(bin, "gcc.exe");
27099
27559
  if (dryRun) {
27100
27560
  log("(dry run) would provision MinGW-w64 GCC");
27101
27561
  return;
@@ -27107,27 +27567,27 @@ var setupCpp = async (env, config2) => {
27107
27567
  if (!exists(gcc)) throw new Error("gcc.exe missing after installing MinGW");
27108
27568
  env.append.unshift(bin);
27109
27569
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gcc;
27110
- const cmake = versionOf(path28.join(bin, "cmake.exe"));
27570
+ const cmake = versionOf(path29.join(bin, "cmake.exe"));
27111
27571
  if (cmakeTooOld(cmake)) warn("The bundled CMake " + cmake + " is older than " + CMAKE_FLOOR + ", which many projects need; set toolchains.cpp.enabled to refresh it, or install a newer CMake into C:\\AgentData\\tools\\bin.");
27112
27572
  env.summary.push("gcc: " + versionOf(gcc) + " (MinGW-w64, with cmake " + cmake + ", ninja, premake5)");
27113
27573
  if (config2.flexBison) await setupFlexBison(env);
27114
27574
  };
27115
27575
  var setupFlexBison = async (env) => {
27116
27576
  const dir = tool("winflexbison");
27117
- if (!exists(path28.join(dir, "win_bison.exe"))) {
27577
+ if (!exists(path29.join(dir, "win_bison.exe"))) {
27118
27578
  await installFromGithub("lexxmark/winflexbison", /^win_flex_bison-[\d.]+\.zip$/, { dest: dir, what: "win_flex / win_bison (~1 MB once)", locate: "win_bison.exe" });
27119
27579
  }
27120
27580
  env.append.push(dir);
27121
- env.summary.push("win_flex/win_bison: " + versionOf(path28.join(dir, "win_bison.exe")));
27581
+ env.summary.push("win_flex/win_bison: " + versionOf(path29.join(dir, "win_bison.exe")));
27122
27582
  };
27123
27583
 
27124
27584
  // src/guest/toolchains/native/dotnet.ts
27125
- import fs19 from "node:fs";
27126
- import path29 from "node:path";
27585
+ import fs20 from "node:fs";
27586
+ import path30 from "node:path";
27127
27587
  var DotnetMarker = external_exports.record(external_exports.string(), external_exports.boolean());
27128
27588
  var setupDotnet = async (env, config2, refresh) => {
27129
27589
  const root = tool("dotnet");
27130
- const marker = path29.join(root, ".agent-sandbox-installed.json");
27590
+ const marker = path30.join(root, ".agent-sandbox-installed.json");
27131
27591
  const script = tool("dotnet-install.ps1");
27132
27592
  if (dryRun) {
27133
27593
  log("(dry run) would provision .NET SDK channels " + config2.channels.join(", "));
@@ -27135,10 +27595,10 @@ var setupDotnet = async (env, config2, refresh) => {
27135
27595
  }
27136
27596
  const recorded = DotnetMarker.safeParse(exists(marker) && !refresh ? readJsonFile(marker) : {});
27137
27597
  const done = recorded.success ? recorded.data : {};
27138
- const globalJson = path29.join(projectWorkspace(), "global.json");
27598
+ const globalJson = path30.join(projectWorkspace(), "global.json");
27139
27599
  const installs = [
27140
27600
  ...config2.channels.map((c) => ["channel:" + c, ["-Channel", c]]),
27141
- ...exists(globalJson) ? [["global.json:" + fs19.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]] : []
27601
+ ...exists(globalJson) ? [["global.json:" + fs20.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]] : []
27142
27602
  ];
27143
27603
  for (const [key, args] of installs.filter(([k]) => !done[k])) {
27144
27604
  await downloadFile("https://dot.net/v1/dotnet-install.ps1", script);
@@ -27149,10 +27609,10 @@ var setupDotnet = async (env, config2, refresh) => {
27149
27609
  }
27150
27610
  const home = mkdirp(tool("dotnet-home"));
27151
27611
  Object.assign(env.vars, { DOTNET_ROOT: root, DOTNET_CLI_HOME: home, DOTNET_CLI_TELEMETRY_OPTOUT: "1", DOTNET_NOLOGO: "1", DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1", NUGET_PACKAGES: tool("nuget", "packages") });
27152
- env.prepend.push(root, path29.join(home, ".dotnet", "tools"));
27153
- env.summary.push("dotnet: " + execOutput(path29.join(root, "dotnet.exe"), ["--list-sdks"]).split(/\r?\n/).map((l) => l.split(" ")[0]).filter(Boolean).join(", "));
27154
- const dotnet = path29.join(root, "dotnet.exe");
27155
- const dotnetEnv = { env: { ...process.env, ...env.vars, PATH: root + path29.delimiter + (process.env.PATH ?? "") } };
27612
+ env.prepend.push(root, path30.join(home, ".dotnet", "tools"));
27613
+ env.summary.push("dotnet: " + execOutput(path30.join(root, "dotnet.exe"), ["--list-sdks"]).split(/\r?\n/).map((l) => l.split(" ")[0]).filter(Boolean).join(", "));
27614
+ const dotnet = path30.join(root, "dotnet.exe");
27615
+ const dotnetEnv = { env: { ...process.env, ...env.vars, PATH: root + path30.delimiter + (process.env.PATH ?? "") } };
27156
27616
  await installOnce(env, "dotnet workload", config2.workloads, (w) => execAsync(dotnet, ["workload", "install", w, "--skip-manifest-update"], dotnetEnv));
27157
27617
  await installOnce(env, "dotnet tool", config2.tools, (t) => execAsync(dotnet, ["tool", "install", "--global", t], dotnetEnv));
27158
27618
  await setupFrameworkReferences(env, config2.frameworkTargets);
@@ -27163,7 +27623,7 @@ var setupFrameworkReferences = async (env, targets) => {
27163
27623
  const root = tool("netfx-references");
27164
27624
  for (const target of targets) {
27165
27625
  const id = "microsoft.netframework.referenceassemblies." + target.toLowerCase();
27166
- const marker = path29.join(root, ".installed-" + target.toLowerCase());
27626
+ const marker = path30.join(root, ".installed-" + target.toLowerCase());
27167
27627
  if (exists(marker)) continue;
27168
27628
  const staging = tool("netfx-references-" + target.toLowerCase());
27169
27629
  try {
@@ -27172,17 +27632,17 @@ var setupFrameworkReferences = async (env, targets) => {
27172
27632
  if (!version2) throw new Error("no stable version of " + id);
27173
27633
  log("Downloading the .NET Framework " + target + " reference assemblies (~30 MB once) ...");
27174
27634
  await installArchive("https://api.nuget.org/v3-flatcontainer/" + id + "/" + version2 + "/" + id + "." + version2 + ".nupkg", staging, { fileName: id + ".zip" });
27175
- fs19.cpSync(path29.join(staging, "build", ".NETFramework"), path29.join(root, ".NETFramework"), { recursive: true });
27176
- fs19.writeFileSync(marker, version2);
27635
+ fs20.cpSync(path30.join(staging, "build", ".NETFramework"), path30.join(root, ".NETFramework"), { recursive: true });
27636
+ fs20.writeFileSync(marker, version2);
27177
27637
  } catch (e) {
27178
27638
  warn(".NET Framework " + target + " reference assemblies could not be installed (projects targeting it will not build): " + errMsg(e));
27179
27639
  } finally {
27180
27640
  safeRemove(staging, dataDir);
27181
27641
  }
27182
27642
  }
27183
- if (!exists(path29.join(root, ".NETFramework"))) return;
27184
- env.vars.TargetFrameworkRootPath = root + path29.sep;
27185
- env.summary.push(".NET Framework targeting: " + fs19.readdirSync(path29.join(root, ".NETFramework")).join(", "));
27643
+ if (!exists(path30.join(root, ".NETFramework"))) return;
27644
+ env.vars.TargetFrameworkRootPath = root + path30.sep;
27645
+ env.summary.push(".NET Framework targeting: " + fs20.readdirSync(path30.join(root, ".NETFramework")).join(", "));
27186
27646
  };
27187
27647
  var setupNetFx35 = async (env) => {
27188
27648
  if (execOutput(SYSTEM.reg(), ["query", "HKLM\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5", "/v", "Install"]).includes("0x1")) {
@@ -27200,15 +27660,15 @@ var setupNetFx35 = async (env) => {
27200
27660
  };
27201
27661
 
27202
27662
  // src/guest/toolchains/native/mesa.ts
27203
- import path30 from "node:path";
27663
+ import path31 from "node:path";
27204
27664
  var setupMesa = async (env, config2) => {
27205
27665
  if (dryRun) {
27206
27666
  log("(dry run) would provision Mesa 3D");
27207
27667
  return;
27208
27668
  }
27209
27669
  const root = tool("mesa");
27210
- const dir = path30.join(root, arch === "arm64" ? "arm64" : "x64");
27211
- if (!exists(path30.join(dir, "opengl32.dll"))) {
27670
+ const dir = path31.join(root, arch === "arm64" ? "arm64" : "x64");
27671
+ if (!exists(path31.join(dir, "opengl32.dll"))) {
27212
27672
  await installFromGithub("pal1000/mesa-dist-win", /^mesa3d-[\d.]+-release-msvc\.7z$/, { dest: root, what: "Mesa 3D for software OpenGL (~100 MB once)", locate: "opengl32.dll", up: 1 });
27213
27673
  }
27214
27674
  Object.assign(env.vars, { MESA_DIR: dir, GALLIUM_DRIVER: "llvmpipe" });
@@ -27217,54 +27677,59 @@ var setupMesa = async (env, config2) => {
27217
27677
  };
27218
27678
  var VULKAN_RUNTIME = "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime-components.zip";
27219
27679
  var setupLavapipe = async (env, mesaDir) => {
27220
- const icd = path30.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
27221
- if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path30.basename(icd) + ")");
27680
+ const icd = path31.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
27681
+ if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path31.basename(icd) + ")");
27222
27682
  const dir = tool("vulkan");
27223
- if (!exists(path30.join(dir, "vulkan-1.dll"))) {
27683
+ if (!exists(path31.join(dir, "vulkan-1.dll"))) {
27224
27684
  log("Downloading the Vulkan loader (~10 MB once) ...");
27225
27685
  await installArchive(VULKAN_RUNTIME, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
27226
27686
  }
27227
- await execAsync(SYSTEM.reg(), ["add", "HKLM\\SOFTWARE\\Khronos\\Vulkan\\Drivers", "/v", icd, "/t", "REG_DWORD", "/d", "0", "/f"], { stdio: "ignore" });
27687
+ const register = (file3) => execAsync(SYSTEM.reg(), ["add", "HKLM\\SOFTWARE\\Khronos\\Vulkan\\Drivers", "/v", file3, "/t", "REG_DWORD", "/d", "0", "/f"], { stdio: "ignore" });
27688
+ await register(icd);
27689
+ const dozen = path31.join(mesaDir, arch === "arm64" ? "dzn_icd.aarch64.json" : "dzn_icd.x86_64.json");
27690
+ const gpu = hasGpu();
27691
+ if (gpu && exists(dozen)) await register(dozen);
27228
27692
  env.prepend.push(dir);
27229
- env.summary.push("vulkan: lavapipe (software Vulkan 1.4 on the CPU), vulkaninfo on PATH; WGPU_BACKEND=vulkan for wgpu");
27693
+ env.summary.push("vulkan: " + (gpu && exists(dozen) ? "Dozen (Vulkan on the GPU via Direct3D 12) and " : "") + "lavapipe (software Vulkan 1.4 on the CPU), vulkaninfo on PATH; WGPU_BACKEND=vulkan for wgpu");
27230
27694
  };
27695
+ var hasGpu = () => execOutput(SYSTEM.powershell(), ["-NoProfile", "-NonInteractive", "-Command", "(Get-CimInstance Win32_VideoController).Name"], { timeout: 3e4 }).split(/\r?\n/).map((n) => n.trim()).some((n) => n && !/^Microsoft (Remote Display|Basic (Render|Display))/i.test(n));
27231
27696
 
27232
27697
  // src/guest/toolchains/native/msvc/index.ts
27233
- import fs23 from "node:fs";
27234
- import path34 from "node:path";
27698
+ import fs24 from "node:fs";
27699
+ import path35 from "node:path";
27235
27700
 
27236
27701
  // src/guest/toolchains/native/msvc/environment.ts
27237
- import fs21 from "node:fs";
27238
- import path32 from "node:path";
27702
+ import fs22 from "node:fs";
27703
+ import path33 from "node:path";
27239
27704
 
27240
27705
  // src/guest/toolchains/native/msvc/tree.ts
27241
- import fs20 from "node:fs";
27242
- import path31 from "node:path";
27706
+ import fs21 from "node:fs";
27707
+ import path32 from "node:path";
27243
27708
  var ROOT = tool("msvc");
27244
- var MARKER = path31.join(ROOT, ".installed.json");
27245
- var msvcTools = (msvc, ...parts) => path31.join(ROOT, "VC", "Tools", "MSVC", msvc, ...parts);
27709
+ var MARKER2 = path32.join(ROOT, ".installed.json");
27710
+ var msvcTools = (msvc, ...parts) => path32.join(ROOT, "VC", "Tools", "MSVC", msvc, ...parts);
27246
27711
  var hostBin = (msvc, ...parts) => msvcTools(msvc, "bin", "Hostx64", "x64", ...parts);
27247
27712
  var hasCompiler = (msvc) => exists(hostBin(msvc, "cl.exe"));
27248
27713
  var Installed = external_exports.object({ msvc: external_exports.string().min(1), sdk: external_exports.string().min(1), want: external_exports.string() });
27249
27714
  var readInstalled = () => {
27250
27715
  try {
27251
- return Installed.safeParse(JSON.parse(fs20.readFileSync(MARKER, "utf8"))).data ?? null;
27716
+ return Installed.safeParse(JSON.parse(fs21.readFileSync(MARKER2, "utf8"))).data ?? null;
27252
27717
  } catch {
27253
27718
  return null;
27254
27719
  }
27255
27720
  };
27256
27721
 
27257
27722
  // src/guest/toolchains/native/msvc/environment.ts
27258
- var VSWHERE_DIR = path32.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Microsoft Visual Studio", "Installer");
27723
+ var VSWHERE_DIR = path33.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Microsoft Visual Studio", "Installer");
27259
27724
  var vcvars = (root, msvc, sdk) => {
27260
- const vc = path32.join(root, "VC", "Tools", "MSVC", msvc);
27261
- const kits = path32.join(root, "Windows Kits", "10");
27262
- const inc = (...p) => path32.join(kits, "Include", sdk, ...p);
27263
- const lib = (...p) => path32.join(kits, "Lib", sdk, ...p);
27725
+ const vc = path33.join(root, "VC", "Tools", "MSVC", msvc);
27726
+ const kits = path33.join(root, "Windows Kits", "10");
27727
+ const inc = (...p) => path33.join(kits, "Include", sdk, ...p);
27728
+ const lib = (...p) => path33.join(kits, "Lib", sdk, ...p);
27264
27729
  return {
27265
27730
  vars: {
27266
27731
  VSINSTALLDIR: root + "\\",
27267
- VCINSTALLDIR: path32.join(root, "VC") + "\\",
27732
+ VCINSTALLDIR: path33.join(root, "VC") + "\\",
27268
27733
  VCToolsInstallDir: vc + "\\",
27269
27734
  VCToolsVersion: msvc,
27270
27735
  VisualStudioVersion: "17.0",
@@ -27276,15 +27741,15 @@ var vcvars = (root, msvc, sdk) => {
27276
27741
  VSCMD_ARG_HOST_ARCH: "x64",
27277
27742
  VSCMD_ARG_TGT_ARCH: "x64",
27278
27743
  Platform: "x64",
27279
- INCLUDE: [path32.join(vc, "include"), inc("ucrt"), inc("shared"), inc("um"), inc("winrt"), inc("cppwinrt")].join(";"),
27280
- LIB: [path32.join(vc, "lib", "x64"), lib("ucrt", "x64"), lib("um", "x64")].join(";"),
27281
- LIBPATH: [path32.join(vc, "lib", "x64"), path32.join(vc, "lib", "x86", "store", "references")].join(";")
27744
+ INCLUDE: [path33.join(vc, "include"), inc("ucrt"), inc("shared"), inc("um"), inc("winrt"), inc("cppwinrt")].join(";"),
27745
+ LIB: [path33.join(vc, "lib", "x64"), lib("ucrt", "x64"), lib("um", "x64")].join(";"),
27746
+ LIBPATH: [path33.join(vc, "lib", "x64"), path33.join(vc, "lib", "x86", "store", "references")].join(";")
27282
27747
  },
27283
- path: [path32.join(vc, "bin", "Hostx64", "x64"), path32.join(kits, "bin", sdk, "x64")]
27748
+ path: [path33.join(vc, "bin", "Hostx64", "x64"), path33.join(kits, "bin", sdk, "x64")]
27284
27749
  };
27285
27750
  };
27286
27751
  var writeVcvars = (env) => {
27287
- const dir = mkdirp(path32.join(ROOT, "VC", "Auxiliary", "Build"));
27752
+ const dir = mkdirp(path33.join(ROOT, "VC", "Auxiliary", "Build"));
27288
27753
  const lines = [
27289
27754
  "@echo off",
27290
27755
  "rem Written by Windows Development Sandbox for its portable MSVC (host x64, target x64).",
@@ -27292,26 +27757,26 @@ var writeVcvars = (env) => {
27292
27757
  'set "PATH=' + env.path.join(";") + ';%PATH%"',
27293
27758
  "exit /b 0"
27294
27759
  ];
27295
- fs21.writeFileSync(path32.join(dir, "vcvars64.bat"), lines.join("\r\n") + "\r\n");
27296
- fs21.writeFileSync(path32.join(dir, "vcvarsall.bat"), ["@echo off", "rem Only x64 (amd64) is installed.", 'call "%~dp0vcvars64.bat"', "exit /b %errorlevel%"].join("\r\n") + "\r\n");
27760
+ fs22.writeFileSync(path33.join(dir, "vcvars64.bat"), lines.join("\r\n") + "\r\n");
27761
+ fs22.writeFileSync(path33.join(dir, "vcvarsall.bat"), ["@echo off", "rem Only x64 (amd64) is installed.", 'call "%~dp0vcvars64.bat"', "exit /b %errorlevel%"].join("\r\n") + "\r\n");
27297
27762
  };
27298
27763
  var installVswhere = (msvc) => {
27299
27764
  mkdirp(VSWHERE_DIR);
27300
- fs21.copyFileSync(ensureCompiled("vswhere"), path32.join(VSWHERE_DIR, "vswhere.exe"));
27765
+ fs22.copyFileSync(ensureCompiled("vswhere"), path33.join(VSWHERE_DIR, "vswhere.exe"));
27301
27766
  const [major, minor] = msvc.split(".").slice(2);
27302
- fs21.writeFileSync(path32.join(VSWHERE_DIR, "vswhere.json"), JSON.stringify({ installationPath: ROOT, installationVersion: "17." + (minor ?? "0") + ".0." + (major ?? "0") }));
27767
+ fs22.writeFileSync(path33.join(VSWHERE_DIR, "vswhere.json"), JSON.stringify({ installationPath: ROOT, installationVersion: "17." + (minor ?? "0") + ".0." + (major ?? "0") }));
27303
27768
  };
27304
27769
  var removeTelemetry = (msvc) => {
27305
27770
  try {
27306
- fs21.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
27771
+ fs22.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
27307
27772
  } catch (e) {
27308
27773
  warn("Could not remove MSVC's telemetry helper (vctip.exe); it may keep tools\\msvc locked: " + errMsg(e));
27309
27774
  }
27310
27775
  };
27311
27776
 
27312
27777
  // src/guest/toolchains/native/msvc/packages.ts
27313
- import fs22 from "node:fs";
27314
- import path33 from "node:path";
27778
+ import fs23 from "node:fs";
27779
+ import path34 from "node:path";
27315
27780
  var CHANNEL = "https://aka.ms/vs/17/release/channel";
27316
27781
  var MANIFEST_DAY_MS = 24 * 60 * 60 * 1e3;
27317
27782
  var MSVC_PARTS = ["tools.hostx64.targetx64.base", "tools.hostx64.targetx64.res.base", "crt.headers.base", "crt.x64.desktop.base", "crt.x64.store.base", "crt.source.base", "asan.headers.base", "pgo.headers.base"];
@@ -27328,10 +27793,10 @@ var SDK_MSIS = [
27328
27793
  "Windows SDK Desktop Tools x64-x86_en-us.msi"
27329
27794
  ];
27330
27795
  var manifest = async () => {
27331
- const cached2 = path33.join(ROOT, ".manifest.json");
27332
- if (exists(cached2) && Date.now() - fs22.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
27796
+ const cached2 = path34.join(ROOT, ".manifest.json");
27797
+ if (exists(cached2) && Date.now() - fs23.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
27333
27798
  try {
27334
- return JSON.parse(fs22.readFileSync(cached2, "utf8"));
27799
+ return JSON.parse(fs23.readFileSync(cached2, "utf8"));
27335
27800
  } catch {
27336
27801
  }
27337
27802
  }
@@ -27340,26 +27805,26 @@ var manifest = async () => {
27340
27805
  if (!item) throw new Error("the Visual Studio channel has no package manifest");
27341
27806
  mkdirp(ROOT);
27342
27807
  await download(item.url, cached2);
27343
- return JSON.parse(fs22.readFileSync(cached2, "utf8"));
27808
+ return JSON.parse(fs23.readFileSync(cached2, "utf8"));
27344
27809
  };
27345
27810
  var unpackVsix = async (vsix, work) => {
27346
- const out = mkdirp(path33.join(work, "vsix-" + path33.basename(vsix)));
27811
+ const out = mkdirp(path34.join(work, "vsix-" + path34.basename(vsix)));
27347
27812
  await extractArchive(vsix, out, ["Contents"]);
27348
- const decode3 = (dir) => {
27349
- for (const entry of fs22.readdirSync(dir, { withFileTypes: true })) {
27350
- const from = path33.join(dir, entry.name);
27813
+ const decode4 = (dir) => {
27814
+ for (const entry of fs23.readdirSync(dir, { withFileTypes: true })) {
27815
+ const from = path34.join(dir, entry.name);
27351
27816
  let name = entry.name;
27352
27817
  try {
27353
27818
  if (name.includes("%")) name = decodeURIComponent(name);
27354
27819
  } catch {
27355
27820
  }
27356
- const to = path33.join(dir, name);
27357
- if (to !== from) fs22.renameSync(from, to);
27358
- if (entry.isDirectory()) decode3(to);
27821
+ const to = path34.join(dir, name);
27822
+ if (to !== from) fs23.renameSync(from, to);
27823
+ if (entry.isDirectory()) decode4(to);
27359
27824
  }
27360
27825
  };
27361
- decode3(out);
27362
- fs22.cpSync(path33.join(out, "Contents"), ROOT, { recursive: true, force: true });
27826
+ decode4(out);
27827
+ fs23.cpSync(path34.join(out, "Contents"), ROOT, { recursive: true, force: true });
27363
27828
  safeRemove(out, work);
27364
27829
  };
27365
27830
  var unpackMsi = async (msi) => {
@@ -27367,8 +27832,8 @@ var unpackMsi = async (msi) => {
27367
27832
  try {
27368
27833
  await execAsync(system32("msiexec.exe"), ["/a", msi, "/quiet", "/qn", "TARGETDIR=" + ROOT, "/l*v", logFile2], { stdio: "ignore" });
27369
27834
  } catch (e) {
27370
- const lines = exists(logFile2) ? fs22.readFileSync(logFile2, "utf16le").split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(" | ") : "";
27371
- throw new Error(path33.basename(msi) + " did not unpack: " + (e instanceof Error ? e.message : String(e)) + (lines ? " (" + lines.slice(0, 600) + ")" : ""));
27835
+ const lines = exists(logFile2) ? fs23.readFileSync(logFile2, "utf16le").split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(" | ") : "";
27836
+ throw new Error(path34.basename(msi) + " did not unpack: " + (e instanceof Error ? e.message : String(e)) + (lines ? " (" + lines.slice(0, 600) + ")" : ""));
27372
27837
  }
27373
27838
  };
27374
27839
  var catalogue = (m) => {
@@ -27380,13 +27845,13 @@ var catalogue = (m) => {
27380
27845
  };
27381
27846
  };
27382
27847
  var payloadFetcher = (work) => async (p) => {
27383
- const file3 = path33.join(work, path33.basename(p.fileName.replace(/\\/g, "/")));
27848
+ const file3 = path34.join(work, path34.basename(p.fileName.replace(/\\/g, "/")));
27384
27849
  if (!exists(file3)) await download(p.url, file3, p.sha256);
27385
27850
  return file3;
27386
27851
  };
27387
27852
  var unpackedToolset = () => {
27388
- const toolsRoot = path33.join(ROOT, "VC", "Tools", "MSVC");
27389
- return fs22.readdirSync(toolsRoot).filter((d) => exists(hostBin(d, "cl.exe"))).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).pop();
27853
+ const toolsRoot = path34.join(ROOT, "VC", "Tools", "MSVC");
27854
+ return fs23.readdirSync(toolsRoot).filter((d) => exists(hostBin(d, "cl.exe"))).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).pop();
27390
27855
  };
27391
27856
  var installPackages = async (config2) => {
27392
27857
  const { ids, pick: pick2 } = catalogue(await manifest());
@@ -27394,7 +27859,7 @@ var installPackages = async (config2) => {
27394
27859
  if (!version2) throw new Error("no MSVC " + config2.msvcVersion + " in the Visual Studio manifest");
27395
27860
  const sdk = pickWindowsSdk(ids, config2.sdkVersion);
27396
27861
  if (!sdk) throw new Error("no Windows SDK " + config2.sdkVersion + " in the Visual Studio manifest");
27397
- const work = mkdirp(path33.join(ROOT, ".download"));
27862
+ const work = mkdirp(path34.join(ROOT, ".download"));
27398
27863
  const fetchPayload = payloadFetcher(work);
27399
27864
  log("Downloading the MSVC " + version2 + " compiler and C/C++ libraries ...");
27400
27865
  for (const part of MSVC_PARTS) {
@@ -27413,16 +27878,16 @@ var installPackages = async (config2) => {
27413
27878
  if (!p) throw new Error("the Windows SDK package has no " + name);
27414
27879
  const file3 = await fetchPayload(p);
27415
27880
  msis.push(file3);
27416
- for (const cab of msiCabs(fs22.readFileSync(file3))) {
27881
+ for (const cab of msiCabs(fs23.readFileSync(file3))) {
27417
27882
  const c = payload(cab);
27418
27883
  if (c) await fetchPayload(c);
27419
27884
  }
27420
27885
  }
27421
27886
  log("Unpacking the Windows SDK (a few minutes) ...");
27422
27887
  for (const msi of msis) await unpackMsi(msi);
27423
- for (const name of fs22.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith(".msi"))) fs22.rmSync(path33.join(ROOT, name), { force: true });
27888
+ for (const name of fs23.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith(".msi"))) fs23.rmSync(path34.join(ROOT, name), { force: true });
27424
27889
  safeRemove(work, ROOT);
27425
- const sdkVersion = fs22.readdirSync(path33.join(ROOT, "Windows Kits", "10", "Include")).filter((d) => d.startsWith("10.0." + sdk.build)).sort().pop();
27890
+ const sdkVersion = fs23.readdirSync(path34.join(ROOT, "Windows Kits", "10", "Include")).filter((d) => d.startsWith("10.0." + sdk.build)).sort().pop();
27426
27891
  if (!sdkVersion) throw new Error("the Windows SDK did not unpack (no Include\\10.0." + sdk.build + ".*)");
27427
27892
  const toolset = unpackedToolset();
27428
27893
  if (!toolset) throw new Error("MSVC " + version2 + " did not unpack (no cl.exe under VC\\Tools\\MSVC)");
@@ -27436,7 +27901,7 @@ var installedMsvcEnv = () => {
27436
27901
  };
27437
27902
  var clearTree = () => {
27438
27903
  if (!exists(ROOT)) return;
27439
- for (const name of fs23.readdirSync(ROOT).filter((n) => n !== ".manifest.json" && n !== ".download")) safeRemove(path34.join(ROOT, name), ROOT);
27904
+ for (const name of fs24.readdirSync(ROOT).filter((n) => n !== ".manifest.json" && n !== ".download")) safeRemove(path35.join(ROOT, name), ROOT);
27440
27905
  };
27441
27906
  var setupMsvc = async (env, config2) => {
27442
27907
  if (!config2.acceptLicense) {
@@ -27452,7 +27917,7 @@ var setupMsvc = async (env, config2) => {
27452
27917
  log("Installing MSVC and the Windows SDK (~1-2 GB, once; licence accepted in toolchains.msvc.acceptLicense) ...");
27453
27918
  clearTree();
27454
27919
  done = { ...await installPackages(config2), want };
27455
- writeJsonAtomic(MARKER, done);
27920
+ writeJsonAtomic(MARKER2, done);
27456
27921
  }
27457
27922
  removeTelemetry(done.msvc);
27458
27923
  const vc = vcvars(ROOT, done.msvc, done.sdk);
@@ -27464,20 +27929,20 @@ var setupMsvc = async (env, config2) => {
27464
27929
  };
27465
27930
 
27466
27931
  // src/guest/toolchains/native/rust.ts
27467
- import path36 from "node:path";
27932
+ import path37 from "node:path";
27468
27933
 
27469
27934
  // src/guest/toolchains/native/binstall.ts
27470
- import fs24 from "node:fs";
27471
- import path35 from "node:path";
27935
+ import fs25 from "node:fs";
27936
+ import path36 from "node:path";
27472
27937
  var ensureBinstall = async (cargoBin) => {
27473
- const target = path35.join(cargoBin, "cargo-binstall.exe");
27938
+ const target = path36.join(cargoBin, "cargo-binstall.exe");
27474
27939
  if (exists(target)) return true;
27475
27940
  try {
27476
27941
  const dir = tool("cargo-binstall");
27477
- if (!exists(path35.join(dir, "cargo-binstall.exe"))) {
27942
+ if (!exists(path36.join(dir, "cargo-binstall.exe"))) {
27478
27943
  await installFromGithub("cargo-bins/cargo-binstall", binstallAsset(arch), { dest: dir, what: "cargo-binstall for prebuilt Rust tools (~10 MB once)", locate: "cargo-binstall.exe" });
27479
27944
  }
27480
- fs24.copyFileSync(path35.join(dir, "cargo-binstall.exe"), target);
27945
+ fs25.copyFileSync(path36.join(dir, "cargo-binstall.exe"), target);
27481
27946
  return true;
27482
27947
  } catch (e) {
27483
27948
  warn("cargo-binstall unavailable, compiling crates with cargo install instead: " + errMsg(e));
@@ -27485,11 +27950,11 @@ var ensureBinstall = async (cargoBin) => {
27485
27950
  }
27486
27951
  };
27487
27952
  var crateInstaller = (cargoHome, cargoEnv) => {
27488
- const cargo = path35.join(cargoHome, "bin", "cargo.exe");
27953
+ const cargo = path36.join(cargoHome, "bin", "cargo.exe");
27489
27954
  let binstall = null;
27490
27955
  const binstallEnv = { ...cargoEnv, env: { ...cargoEnv.env ?? process.env, BINSTALL_DISABLE_TELEMETRY: "true" } };
27491
27956
  return async (crate) => {
27492
- binstall ??= ensureBinstall(path35.join(cargoHome, "bin"));
27957
+ binstall ??= ensureBinstall(path36.join(cargoHome, "bin"));
27493
27958
  if (await binstall) {
27494
27959
  try {
27495
27960
  await execAsync(cargo, ["binstall", "--no-confirm", "--locked", "--disable-strategies", "compile", crate], binstallEnv);
@@ -27507,7 +27972,7 @@ var setupRust = async (env, config2, refresh) => {
27507
27972
  const RUSTUP_HOME = tool("rust", "rustup");
27508
27973
  const CARGO_HOME = tool("rust", "cargo");
27509
27974
  const rustEnv = { env: { ...process.env, RUSTUP_HOME, CARGO_HOME } };
27510
- const rustup = path36.join(CARGO_HOME, "bin", "rustup.exe");
27975
+ const rustup = path37.join(CARGO_HOME, "bin", "rustup.exe");
27511
27976
  if (dryRun) {
27512
27977
  log("(dry run) would provision Rust " + config2.toolchain + " (" + config2.host + ")");
27513
27978
  return;
@@ -27524,35 +27989,35 @@ var setupRust = async (env, config2, refresh) => {
27524
27989
  if (refresh) await execAsync(rustup, ["update"], rustEnv);
27525
27990
  }
27526
27991
  Object.assign(env.vars, { RUSTUP_HOME, CARGO_HOME });
27527
- env.prepend.push(path36.join(CARGO_HOME, "bin"));
27528
- env.summary.push("rust: " + versionOf(path36.join(CARGO_HOME, "bin", "rustc.exe"), ["--version"], rustEnv) + " [" + config2.host + "]");
27992
+ env.prepend.push(path37.join(CARGO_HOME, "bin"));
27993
+ env.summary.push("rust: " + versionOf(path37.join(CARGO_HOME, "bin", "rustc.exe"), ["--version"], rustEnv) + " [" + config2.host + "]");
27529
27994
  const toolchainKey = "rustup@" + config2.toolchain;
27530
27995
  await installOnce(env, toolchainKey + " components", config2.components, (c) => execAsync(rustup, ["component", "add", c], rustEnv));
27531
27996
  await installOnce(env, toolchainKey + " targets", config2.targets, (t) => execAsync(rustup, ["target", "add", t], rustEnv));
27532
27997
  const msvc = config2.host.endsWith("-msvc") ? installedMsvcEnv() : null;
27533
27998
  const mingw = tool("mingw", "mingw64", "bin");
27534
- const cargoEnv = msvc ? { env: { ...rustEnv.env, ...msvc.vars, PATH: [path36.join(CARGO_HOME, "bin"), ...msvc.path, process.env.PATH ?? ""].join(path36.delimiter) } } : { env: { ...rustEnv.env, CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: path36.join(mingw, "gcc.exe"), PATH: [path36.join(CARGO_HOME, "bin"), mingw, process.env.PATH ?? ""].join(path36.delimiter) } };
27999
+ const cargoEnv = msvc ? { env: { ...rustEnv.env, ...msvc.vars, PATH: [path37.join(CARGO_HOME, "bin"), ...msvc.path, process.env.PATH ?? ""].join(path37.delimiter) } } : { env: { ...rustEnv.env, CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: path37.join(mingw, "gcc.exe"), PATH: [path37.join(CARGO_HOME, "bin"), mingw, process.env.PATH ?? ""].join(path37.delimiter) } };
27535
28000
  await installOnce(env, "cargo", config2.crates, crateInstaller(CARGO_HOME, cargoEnv));
27536
28001
  };
27537
28002
 
27538
28003
  // src/guest/toolchains/node.ts
27539
- import fs25 from "node:fs";
27540
- import path37 from "node:path";
28004
+ import fs26 from "node:fs";
28005
+ import path38 from "node:path";
27541
28006
  import { spawn as spawn4 } from "node:child_process";
27542
28007
  var NVM_HOME = tool("nvm");
27543
- var NVM_SYMLINK = path37.join(localDir, "nodejs");
27544
- var HOST_NVM = path37.join(hostToolsDir, "nvm");
28008
+ var NVM_SYMLINK = path38.join(localDir, "nodejs");
28009
+ var HOST_NVM = path38.join(hostToolsDir, "nvm");
27545
28010
  var HOST_VERSIONS_MAX = 3;
27546
- var hostNvmVersions = () => exists(HOST_NVM) ? fs25.readdirSync(HOST_NVM).filter((d) => /^v\d+\.\d+\.\d+$/.test(d) && exists(path37.join(HOST_NVM, d, "node.exe"))).map((d) => d.slice(1)) : [];
28011
+ var hostNvmVersions = () => exists(HOST_NVM) ? fs26.readdirSync(HOST_NVM).filter((d) => /^v\d+\.\d+\.\d+$/.test(d) && exists(path38.join(HOST_NVM, d, "node.exe"))).map((d) => d.slice(1)) : [];
27547
28012
  var resolveNode = (spec) => resolveCached("node:" + spec, async () => {
27548
28013
  const exact = spec.replace(/^v/, "");
27549
28014
  if (/^\d+\.\d+\.\d+$/.test(exact)) return exact;
27550
28015
  const releases = await fetchJson("https://nodejs.org/dist/index.json");
27551
28016
  return pickNodeVersion(releases, spec) ?? Promise.reject(new Error('No Node.js release matches "' + spec + '"'));
27552
28017
  });
27553
- var NVM_TEMP = path37.join(NVM_HOME, ".tmp");
27554
- var nvm = (args) => new Promise((resolve) => {
27555
- const child = spawn4(path37.join(NVM_HOME, "nvm.exe"), args, { windowsHide: true, env: { ...process.env, NVM_HOME, NVM_SYMLINK, TEMP: NVM_TEMP, TMP: NVM_TEMP } });
28018
+ var NVM_TEMP = path38.join(NVM_HOME, ".tmp");
28019
+ var nvm = (args) => new Promise((resolve2) => {
28020
+ const child = spawn4(path38.join(NVM_HOME, "nvm.exe"), args, { windowsHide: true, env: { ...process.env, NVM_HOME, NVM_SYMLINK, TEMP: NVM_TEMP, TMP: NVM_TEMP } });
27556
28021
  let out = "";
27557
28022
  child.stdout.on("data", (d) => {
27558
28023
  out += d.toString();
@@ -27560,16 +28025,16 @@ var nvm = (args) => new Promise((resolve) => {
27560
28025
  child.stderr.on("data", (d) => {
27561
28026
  out += d.toString();
27562
28027
  });
27563
- child.once("error", (e) => resolve(out + e.message));
27564
- child.once("close", () => resolve(out));
28028
+ child.once("error", (e) => resolve2(out + e.message));
28029
+ child.once("close", () => resolve2(out));
27565
28030
  });
27566
28031
  var ensureNvm = async () => {
27567
- if (exists(path37.join(NVM_HOME, "nvm.exe"))) return;
27568
- if (exists(path37.join(HOST_NVM, "nvm.exe"))) {
28032
+ if (exists(path38.join(NVM_HOME, "nvm.exe"))) return;
28033
+ if (exists(path38.join(HOST_NVM, "nvm.exe"))) {
27569
28034
  log("Copying nvm from this PC ...");
27570
28035
  mkdirp(NVM_HOME);
27571
- const files = fs25.readdirSync(HOST_NVM).filter((f) => /\.(exe|cmd|vbs)$/i.test(f)).sort((a, b) => Number(a.toLowerCase() === "nvm.exe") - Number(b.toLowerCase() === "nvm.exe"));
27572
- for (const file3 of files) fs25.copyFileSync(path37.join(HOST_NVM, file3), path37.join(NVM_HOME, file3));
28036
+ const files = fs26.readdirSync(HOST_NVM).filter((f) => /\.(exe|cmd|vbs)$/i.test(f)).sort((a, b) => Number(a.toLowerCase() === "nvm.exe") - Number(b.toLowerCase() === "nvm.exe"));
28037
+ for (const file3 of files) fs26.copyFileSync(path38.join(HOST_NVM, file3), path38.join(NVM_HOME, file3));
27573
28038
  return;
27574
28039
  }
27575
28040
  const asset = await githubAsset("coreybutler/nvm-windows", /^nvm-noinstall\.zip$/, true);
@@ -27577,10 +28042,10 @@ var ensureNvm = async () => {
27577
28042
  await installArchive(asset.url, NVM_HOME, { sha256: asset.sha256, locate: "nvm.exe", fileName: asset.name });
27578
28043
  };
27579
28044
  var installNodeVersion = async (version2) => {
27580
- const dir = path37.join(NVM_HOME, "v" + version2);
27581
- const fromHost = path37.join(HOST_NVM, "v" + version2);
27582
- if (exists(path37.join(dir, "node.exe"))) return;
27583
- if (exists(path37.join(fromHost, "node.exe"))) {
28045
+ const dir = path38.join(NVM_HOME, "v" + version2);
28046
+ const fromHost = path38.join(HOST_NVM, "v" + version2);
28047
+ if (exists(path38.join(dir, "node.exe"))) return;
28048
+ if (exists(path38.join(fromHost, "node.exe"))) {
27584
28049
  log("Copying Node " + version2 + " from this PC's nvm (without global packages) ...");
27585
28050
  copyNode(fromHost, dir);
27586
28051
  return;
@@ -27593,13 +28058,13 @@ var installNodeVersion = async (version2) => {
27593
28058
  } finally {
27594
28059
  safeRemove(NVM_TEMP, NVM_HOME);
27595
28060
  }
27596
- if (!exists(path37.join(dir, "node.exe"))) throw new Error("nvm install " + version2 + " failed: " + out.trim().split("\n").slice(-2).join(" "));
28061
+ if (!exists(path38.join(dir, "node.exe"))) throw new Error("nvm install " + version2 + " failed: " + out.trim().split("\n").slice(-2).join(" "));
27597
28062
  };
27598
28063
  var activate = async (version2) => {
27599
28064
  await nvm(["use", version2]);
27600
- if (exists(path37.join(NVM_SYMLINK, "node.exe"))) return;
27601
- fs25.rmSync(NVM_SYMLINK, { recursive: true, force: true });
27602
- fs25.symlinkSync(path37.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
28065
+ if (exists(path38.join(NVM_SYMLINK, "node.exe"))) return;
28066
+ fs26.rmSync(NVM_SYMLINK, { recursive: true, force: true });
28067
+ fs26.symlinkSync(path38.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
27603
28068
  };
27604
28069
  var setupNode = async (env, versions, config2) => {
27605
28070
  if (dryRun) {
@@ -27607,7 +28072,7 @@ var setupNode = async (env, versions, config2) => {
27607
28072
  return;
27608
28073
  }
27609
28074
  await ensureNvm();
27610
- fs25.writeFileSync(path37.join(NVM_HOME, "settings.txt"), ["root: " + NVM_HOME, "path: " + NVM_SYMLINK, "arch: " + (arch === "arm64" ? "arm64" : "64"), "proxy: none", ""].join("\r\n"));
28075
+ fs26.writeFileSync(path38.join(NVM_HOME, "settings.txt"), ["root: " + NVM_HOME, "path: " + NVM_SYMLINK, "arch: " + (arch === "arm64" ? "arm64" : "64"), "proxy: none", ""].join("\r\n"));
27611
28076
  mkdirp(localDir);
27612
28077
  for (const extra of versions.nodeExtra) {
27613
28078
  try {
@@ -27626,7 +28091,7 @@ var setupNode = async (env, versions, config2) => {
27626
28091
  }
27627
28092
  }
27628
28093
  Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK });
27629
- if (duringSession()) env.prepend.push(path37.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
28094
+ if (duringSession()) env.prepend.push(path38.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
27630
28095
  else {
27631
28096
  await activate(main);
27632
28097
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
@@ -27635,10 +28100,10 @@ var setupNode = async (env, versions, config2) => {
27635
28100
  await packageManagers(env, config2, main);
27636
28101
  };
27637
28102
  var packageManagers = async (env, config2, version2) => {
27638
- const dir = path37.join(NVM_HOME, "v" + version2);
27639
- const nodeEnv = { ...process.env, PATH: dir + path37.delimiter + (process.env.PATH ?? "") };
27640
- const npm = (args) => execAsync(path37.join(dir, "node.exe"), [path37.join(dir, "node_modules", "npm", "bin", "npm-cli.js"), ...args], { env: nodeEnv, stdio: "ignore" });
27641
- const corepackJs = path37.join(dir, "node_modules", "corepack", "dist", "corepack.js");
28103
+ const dir = path38.join(NVM_HOME, "v" + version2);
28104
+ const nodeEnv = { ...process.env, PATH: dir + path38.delimiter + (process.env.PATH ?? "") };
28105
+ const npm = (args) => execAsync(path38.join(dir, "node.exe"), [path38.join(dir, "node_modules", "npm", "bin", "npm-cli.js"), ...args], { env: nodeEnv, stdio: "ignore" });
28106
+ const corepackJs = path38.join(dir, "node_modules", "corepack", "dist", "corepack.js");
27642
28107
  const extra = config2.corepack && !exists(corepackJs) ? ["corepack"] : [];
27643
28108
  await installOnce(env, "npm@" + version2, [...extra, ...config2.globalPackages], (pkg) => npm(["install", "--global", pkg, "--no-fund", "--no-audit"]));
27644
28109
  if (!config2.corepack) return;
@@ -27648,7 +28113,7 @@ var packageManagers = async (env, config2, version2) => {
27648
28113
  return;
27649
28114
  }
27650
28115
  try {
27651
- await execAsync(path37.join(dir, "node.exe"), [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"], { env: nodeEnv, stdio: "ignore" });
28116
+ await execAsync(path38.join(dir, "node.exe"), [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"], { env: nodeEnv, stdio: "ignore" });
27652
28117
  env.summary.push('pnpm, yarn: via corepack (package.json "packageManager" picks the version)');
27653
28118
  } catch (e) {
27654
28119
  warn("corepack enable failed: " + errMsg(e));
@@ -27663,31 +28128,48 @@ var setupPwsh = async (env, refresh = false) => {
27663
28128
  };
27664
28129
 
27665
28130
  // src/guest/toolchains/python.ts
27666
- import fs26 from "node:fs";
27667
- import path38 from "node:path";
28131
+ import fs27 from "node:fs";
28132
+ import path39 from "node:path";
27668
28133
  var installPython = async (pkg, spec) => {
27669
28134
  const version2 = await resolveCached(pkg + ":" + spec, async () => {
27670
28135
  const { versions } = await fetchJson("https://api.nuget.org/v3-flatcontainer/" + pkg + "/index.json");
27671
28136
  return pickPackageVersion(versions, spec) ?? Promise.reject(new Error("No " + pkg + ' release matches "' + spec + '"'));
27672
28137
  });
27673
28138
  const dir = tool("python", pkg + "-" + version2);
27674
- const exe = path38.join(dir, "python.exe");
28139
+ const exe = path39.join(dir, "python.exe");
27675
28140
  if (!exists(exe)) {
27676
28141
  log("Downloading Python " + version2 + (pkg === "python2" ? " (Python 2, " : " (") + "~30 MB once) ...");
27677
28142
  await installArchive("https://api.nuget.org/v3-flatcontainer/" + pkg + "/" + version2 + "/" + pkg + "." + version2 + ".nupkg", dir, { locate: "python.exe", fileName: pkg + "." + version2 + ".zip" });
27678
28143
  }
27679
- if (!exists(path38.join(dir, "Scripts", "pip.exe")) && !exists(path38.join(dir, "Scripts", "pip2.exe"))) await execAsync(exe, ["-m", "ensurepip", "--default-pip"], { stdio: "ignore" });
28144
+ if (!exists(path39.join(dir, "Scripts", "pip.exe")) && !exists(path39.join(dir, "Scripts", "pip2.exe"))) await execAsync(exe, ["-m", "ensurepip", "--default-pip"], { stdio: "ignore" });
27680
28145
  return dir;
27681
28146
  };
27682
- var shimDir = (dir) => duringSession() ? tool("shims", path38.basename(dir)) : tool("shims");
28147
+ var shimDir = (dir) => duringSession() ? tool("shims", path39.basename(dir)) : tool("shims");
27683
28148
  var shim = (folder, name, command) => {
27684
- fs26.writeFileSync(path38.join(mkdirp(folder), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
28149
+ fs27.writeFileSync(path39.join(mkdirp(folder), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
27685
28150
  };
27686
28151
  var shimPair = (folder, version2, dir) => {
27687
- const python = '"' + path38.join(dir, "python.exe") + '"';
28152
+ const python = '"' + path39.join(dir, "python.exe") + '"';
27688
28153
  shim(folder, "python" + version2, python);
27689
28154
  shim(folder, "pip" + version2, python + " -m pip");
27690
28155
  };
28156
+ var pyLauncher = (folder, py3, py2) => {
28157
+ const script = path39.join(mkdirp(folder), "py-launcher.py");
28158
+ fs27.writeFileSync(script, [
28159
+ "import subprocess, sys",
28160
+ "PY3, PY2 = " + JSON.stringify(path39.join(py3, "python.exe")) + ", " + JSON.stringify(py2 ? path39.join(py2, "python.exe") : null),
28161
+ "args = sys.argv[1:]",
28162
+ "exe = PY3",
28163
+ "if args and args[0].startswith('-2'):",
28164
+ ' if not PY2: sys.exit("py: Python 2 is not installed (toolchains.python.python2)")',
28165
+ " exe, args = PY2, args[1:]",
28166
+ "elif args and (args[0] == '-3' or args[0].startswith('-3.') or args[0].startswith('-3-')):",
28167
+ " args = args[1:]",
28168
+ "sys.exit(subprocess.call([exe] + args))",
28169
+ ""
28170
+ ].join("\n"));
28171
+ shim(folder, "py", '"' + path39.join(py3, "python.exe") + '" "' + script + '"');
28172
+ };
27691
28173
  var setupPython = async (env, config2, versions) => {
27692
28174
  if (dryRun) {
27693
28175
  log("(dry run) would provision Python " + versions.python.spec + (config2.python2 ? " and Python 2.7" : ""));
@@ -27696,22 +28178,26 @@ var setupPython = async (env, config2, versions) => {
27696
28178
  const py3 = await installPython("python", versions.python.spec);
27697
28179
  const shims = shimDir(py3);
27698
28180
  shimPair(shims, "3", py3);
27699
- env.prepend.push(py3, path38.join(py3, "Scripts"), shims);
28181
+ env.prepend.push(py3, path39.join(py3, "Scripts"), shims);
27700
28182
  env.vars.PYTHONIOENCODING = "utf-8";
27701
- env.summary.push("python: " + path38.basename(py3).replace("python-", "") + " (from " + versions.python.source + ")");
27702
- if (!config2.python2) return;
28183
+ env.summary.push("python: " + path39.basename(py3).replace("python-", "") + " (from " + versions.python.source + "; py works too)");
28184
+ if (!config2.python2) {
28185
+ pyLauncher(shims, py3, null);
28186
+ return;
28187
+ }
27703
28188
  const py2 = await installPython("python2", "2.7");
27704
28189
  shimPair(shims, "2", py2);
27705
- env.summary.push("python2: " + path38.basename(py2).replace("python2-", ""));
28190
+ pyLauncher(shims, py3, py2);
28191
+ env.summary.push("python2: " + path39.basename(py2).replace("python2-", ""));
27706
28192
  };
27707
28193
 
27708
28194
  // src/guest/toolchains/scripting/php.ts
27709
- import fs28 from "node:fs";
27710
- import path40 from "node:path";
28195
+ import fs29 from "node:fs";
28196
+ import path41 from "node:path";
27711
28197
 
27712
28198
  // src/guest/toolchains/scripting/vcruntime.ts
27713
- import fs27 from "node:fs";
27714
- import path39 from "node:path";
28199
+ import fs28 from "node:fs";
28200
+ import path40 from "node:path";
27715
28201
  var VC_REDIST = "https://aka.ms/vs/17/release/vc_redist.x64.exe";
27716
28202
  var MICROSOFT_SIGNER = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
27717
28203
  var OK_EXIT_CODES = [0, 1638, 3010];
@@ -27726,8 +28212,8 @@ var setupVcRuntime = async (env, summary = true) => {
27726
28212
  log("(dry run) would install the Visual C++ runtime");
27727
28213
  return false;
27728
28214
  }
27729
- const system322 = path39.join(process.env.WINDIR ?? "C:\\Windows", "System32");
27730
- const missing = !exists(path39.join(system322, "vcruntime140.dll")) || !exists(path39.join(system322, "msvcp140.dll"));
28215
+ const system322 = path40.join(process.env.WINDIR ?? "C:\\Windows", "System32");
28216
+ const missing = !exists(path40.join(system322, "vcruntime140.dll")) || !exists(path40.join(system322, "msvcp140.dll"));
27731
28217
  if (missing) {
27732
28218
  const installer = tool("vcredist", "vc_redist.x64.exe");
27733
28219
  if (!exists(installer)) {
@@ -27735,12 +28221,12 @@ var setupVcRuntime = async (env, summary = true) => {
27735
28221
  await downloadFile(VC_REDIST, installer);
27736
28222
  }
27737
28223
  if (signerOf(installer) !== MICROSOFT_SIGNER) {
27738
- fs27.rmSync(installer, { force: true });
28224
+ fs28.rmSync(installer, { force: true });
27739
28225
  throw new Error("vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)");
27740
28226
  }
27741
28227
  log("Installing the Visual C++ runtime ...");
27742
28228
  const code = await spawnAsync(installer, ["/install", "/quiet", "/norestart"]);
27743
- if (!OK_EXIT_CODES.includes(code ?? -1) || !exists(path39.join(system322, "vcruntime140.dll"))) throw new Error("the Visual C++ runtime installer failed (exit " + code + ")");
28229
+ if (!OK_EXIT_CODES.includes(code ?? -1) || !exists(path40.join(system322, "vcruntime140.dll"))) throw new Error("the Visual C++ runtime installer failed (exit " + code + ")");
27744
28230
  }
27745
28231
  if (summary) env.summary.push("vc++ runtime: installed");
27746
28232
  return missing;
@@ -27758,15 +28244,15 @@ var phpBuild = async (spec) => {
27758
28244
  return { version: release.version, ...build.zip };
27759
28245
  };
27760
28246
  var writePhpIni = (home) => {
27761
- const ini = path40.join(home, "php.ini");
27762
- if (exists(ini) || !exists(path40.join(home, "php.ini-development"))) return;
27763
- let text = fs28.readFileSync(path40.join(home, "php.ini-development"), "utf8").replace(/^;\s*extension_dir\s*=\s*"ext"/m, 'extension_dir = "' + path40.join(home, "ext") + '"');
27764
- for (const ext of PHP_EXTENSIONS.filter((e) => exists(path40.join(home, "ext", "php_" + e + ".dll")))) text = text.replace(new RegExp("^;(extension=" + ext + ")\\s*$", "m"), "$1");
27765
- fs28.writeFileSync(ini + ".tmp", text);
27766
- fs28.renameSync(ini + ".tmp", ini);
28247
+ const ini = path41.join(home, "php.ini");
28248
+ if (exists(ini) || !exists(path41.join(home, "php.ini-development"))) return;
28249
+ let text = fs29.readFileSync(path41.join(home, "php.ini-development"), "utf8").replace(/^;\s*extension_dir\s*=\s*"ext"/m, 'extension_dir = "' + path41.join(home, "ext") + '"');
28250
+ for (const ext of PHP_EXTENSIONS.filter((e) => exists(path41.join(home, "ext", "php_" + e + ".dll")))) text = text.replace(new RegExp("^;(extension=" + ext + ")\\s*$", "m"), "$1");
28251
+ fs29.writeFileSync(ini + ".tmp", text);
28252
+ fs29.renameSync(ini + ".tmp", ini);
27767
28253
  };
27768
28254
  var shim2 = (env, name, command) => {
27769
- fs28.writeFileSync(path40.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
28255
+ fs29.writeFileSync(path41.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
27770
28256
  env.prepend.push(tool("shims"));
27771
28257
  };
27772
28258
  var setupComposer = async (env, php) => {
@@ -27778,7 +28264,7 @@ var setupComposer = async (env, php) => {
27778
28264
  }
27779
28265
  const composerHome = tool("composer-home");
27780
28266
  env.vars.COMPOSER_HOME = composerHome;
27781
- env.prepend.push(path40.join(composerHome, "vendor", "bin"));
28267
+ env.prepend.push(path41.join(composerHome, "vendor", "bin"));
27782
28268
  shim2(env, "composer", '"' + php + '" "' + phar + '"');
27783
28269
  env.summary.push("composer: " + (/\d+\.\d+\.\d+/.exec(execOutput(php, [phar, "--version", "--no-ansi"]))?.[0] ?? "installed"));
27784
28270
  };
@@ -27791,7 +28277,7 @@ var setupPhp = async (env, config2) => {
27791
28277
  await setupVcRuntime(env, false);
27792
28278
  const version2 = await resolveCached("php:" + wantedSpec.spec, async () => (await phpBuild(wantedSpec.spec)).version);
27793
28279
  const home = tool("php", version2);
27794
- if (!exists(path40.join(home, "php.exe"))) {
28280
+ if (!exists(path41.join(home, "php.exe"))) {
27795
28281
  const build = await phpBuild(version2);
27796
28282
  log("Downloading PHP " + version2 + " (~30 MB once) ...");
27797
28283
  await installArchive("https://windows.php.net/downloads/releases/" + build.path, home, { sha256: build.sha256, locate: "php.exe", fileName: build.path });
@@ -27799,11 +28285,11 @@ var setupPhp = async (env, config2) => {
27799
28285
  writePhpIni(home);
27800
28286
  env.prepend.push(home);
27801
28287
  env.summary.push("php: " + version2 + " (from " + wantedSpec.source + ")");
27802
- if (config2.composer) await setupComposer(env, path40.join(home, "php.exe"));
28288
+ if (config2.composer) await setupComposer(env, path41.join(home, "php.exe"));
27803
28289
  };
27804
28290
 
27805
28291
  // src/guest/toolchains/scripting/ruby.ts
27806
- import path41 from "node:path";
28292
+ import path42 from "node:path";
27807
28293
  var RUBY_ASSET = /^rubyinstaller-(\d+\.\d+\.\d+)-(\d+)-x64\.7z$/;
27808
28294
  var buildNumber = (asset) => Number(RUBY_ASSET.exec(asset.name)?.[2] ?? 0);
27809
28295
  var rubyBuilds = async () => {
@@ -27826,7 +28312,7 @@ var setupRuby = async (env, config2) => {
27826
28312
  }
27827
28313
  const version2 = await resolveCached("ruby:" + wantedSpec.spec, async () => pickPackageVersion([...(await rubyBuilds()).keys()], wantedSpec.spec) ?? Promise.reject(new Error('No RubyInstaller build matches "' + wantedSpec.spec + '"')));
27828
28314
  const home = tool("ruby", version2);
27829
- if (!exists(path41.join(home, "bin", "ruby.exe"))) {
28315
+ if (!exists(path42.join(home, "bin", "ruby.exe"))) {
27830
28316
  const asset = (await rubyBuilds()).get(version2);
27831
28317
  if (!asset) throw new Error("RubyInstaller " + version2 + " is no longer published");
27832
28318
  log("Downloading Ruby " + version2 + " (~100 MB once) ...");
@@ -27834,26 +28320,202 @@ var setupRuby = async (env, config2) => {
27834
28320
  }
27835
28321
  const gems = tool("ruby-gems", version2.split(".").slice(0, 2).join("."));
27836
28322
  Object.assign(env.vars, { GEM_HOME: gems, BUNDLE_USER_HOME: tool("bundle-home") });
27837
- env.prepend.push(path41.join(home, "bin"), path41.join(gems, "bin"));
27838
- env.summary.push("ruby: " + versionOf(path41.join(home, "bin", "ruby.exe")) + " (from " + wantedSpec.source + "; gems with C extensions need MSYS2, not included)");
27839
- const gem = path41.join(home, "bin", "gem.cmd");
28323
+ env.prepend.push(path42.join(home, "bin"), path42.join(gems, "bin"));
28324
+ env.summary.push("ruby: " + versionOf(path42.join(home, "bin", "ruby.exe")) + " (from " + wantedSpec.source + "; gems with C extensions need MSYS2, not included)");
28325
+ const gem = path42.join(home, "bin", "gem.cmd");
27840
28326
  await installOnce(env, "gem@" + version2, config2.gems, (pkg) => execAsync(SYSTEM.cmd(), ["/d", "/c", gem, "install", pkg, "--no-document"], { env: { ...process.env, GEM_HOME: gems } }));
27841
28327
  };
27842
28328
 
27843
28329
  // src/guest/toolchains/vscode.ts
27844
- import fs29 from "node:fs";
27845
- import os5 from "node:os";
27846
- import path42 from "node:path";
28330
+ import fs30 from "node:fs";
28331
+ import os7 from "node:os";
28332
+ import path43 from "node:path";
28333
+
28334
+ // node_modules/jsonc-parser/lib/esm/impl/scanner.js
28335
+ var CharacterCodes;
28336
+ (function(CharacterCodes2) {
28337
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
28338
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
28339
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
28340
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
28341
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
28342
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
28343
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
28344
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
28345
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
28346
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
28347
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
28348
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
28349
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
28350
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
28351
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
28352
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
28353
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
28354
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
28355
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
28356
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
28357
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
28358
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
28359
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
28360
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
28361
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
28362
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
28363
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
28364
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
28365
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
28366
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
28367
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
28368
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
28369
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
28370
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
28371
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
28372
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
28373
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
28374
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
28375
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
28376
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
28377
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
28378
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
28379
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
28380
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
28381
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
28382
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
28383
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
28384
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
28385
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
28386
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
28387
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
28388
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
28389
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
28390
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
28391
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
28392
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
28393
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
28394
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
28395
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
28396
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
28397
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
28398
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
28399
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
28400
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
28401
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
28402
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
28403
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
28404
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
28405
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
28406
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
28407
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
28408
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
28409
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
28410
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
28411
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
28412
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
28413
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
28414
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
28415
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
28416
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
28417
+ })(CharacterCodes || (CharacterCodes = {}));
28418
+
28419
+ // node_modules/jsonc-parser/lib/esm/impl/string-intern.js
28420
+ var cachedSpaces = new Array(20).fill(0).map((_2, index) => {
28421
+ return " ".repeat(index);
28422
+ });
28423
+ var maxCachedValues = 200;
28424
+ var cachedBreakLinesWithSpaces = {
28425
+ " ": {
28426
+ "\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28427
+ return "\n" + " ".repeat(index);
28428
+ }),
28429
+ "\r": new Array(maxCachedValues).fill(0).map((_2, index) => {
28430
+ return "\r" + " ".repeat(index);
28431
+ }),
28432
+ "\r\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28433
+ return "\r\n" + " ".repeat(index);
28434
+ })
28435
+ },
28436
+ " ": {
28437
+ "\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28438
+ return "\n" + " ".repeat(index);
28439
+ }),
28440
+ "\r": new Array(maxCachedValues).fill(0).map((_2, index) => {
28441
+ return "\r" + " ".repeat(index);
28442
+ }),
28443
+ "\r\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28444
+ return "\r\n" + " ".repeat(index);
28445
+ })
28446
+ }
28447
+ };
28448
+
28449
+ // node_modules/jsonc-parser/lib/esm/impl/parser.js
28450
+ var ParseOptions;
28451
+ (function(ParseOptions2) {
28452
+ ParseOptions2.DEFAULT = {
28453
+ allowTrailingComma: false
28454
+ };
28455
+ })(ParseOptions || (ParseOptions = {}));
28456
+
28457
+ // node_modules/jsonc-parser/lib/esm/main.js
28458
+ var ScanError;
28459
+ (function(ScanError2) {
28460
+ ScanError2[ScanError2["None"] = 0] = "None";
28461
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
28462
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
28463
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
28464
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
28465
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
28466
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
28467
+ })(ScanError || (ScanError = {}));
28468
+ var SyntaxKind;
28469
+ (function(SyntaxKind2) {
28470
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
28471
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
28472
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
28473
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
28474
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
28475
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
28476
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
28477
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
28478
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
28479
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
28480
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
28481
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
28482
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
28483
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
28484
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
28485
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
28486
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
28487
+ })(SyntaxKind || (SyntaxKind = {}));
28488
+ var ParseErrorCode;
28489
+ (function(ParseErrorCode2) {
28490
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
28491
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
28492
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
28493
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
28494
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
28495
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
28496
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
28497
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
28498
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
28499
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
28500
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
28501
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
28502
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
28503
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
28504
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
28505
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
28506
+ })(ParseErrorCode || (ParseErrorCode = {}));
28507
+
28508
+ // src/guest/toolchains/vscode.ts
27847
28509
  var VERSION_MARKER = ".agent-sandbox-version";
27848
28510
  var desktopShortcut = (exe) => {
27849
28511
  if (!isWin) return;
27850
- const link = path42.join(os5.homedir(), "Desktop", "Visual Studio Code.lnk");
28512
+ const link = path43.join(os7.homedir(), "Desktop", "Visual Studio Code.lnk");
27851
28513
  const q = (s) => "'" + s.replace(/'/g, "''") + "'";
27852
28514
  powershell("$s = (New-Object -ComObject WScript.Shell).CreateShortcut(" + q(link) + "); $s.TargetPath = " + q(exe) + "; $s.Arguments = " + q('"' + (process.env.AGENT_WORKSPACE ?? "") + '"') + "; $s.Save()");
27853
28515
  };
27854
28516
  var setupVscode = async (env, refresh) => {
27855
28517
  const root = tool("vscode");
27856
- const exe = path42.join(root, "Code.exe");
28518
+ const exe = path43.join(root, "Code.exe");
27857
28519
  if (dryRun) {
27858
28520
  log("(dry run) would provision VS Code");
27859
28521
  return;
@@ -27861,27 +28523,27 @@ var setupVscode = async (env, refresh) => {
27861
28523
  if (!exists(exe) || refresh) {
27862
28524
  const release = await fetchJson("https://update.code.visualstudio.com/api/update/win32-" + (arch === "arm64" ? "arm64" : "x64") + "-archive/stable/latest");
27863
28525
  log("Downloading VS Code " + release.productVersion + " (~150 MB once) ...");
27864
- const keep = path42.join(root, "data");
28526
+ const keep = path43.join(root, "data");
27865
28527
  const parked = root + "-data";
27866
28528
  if (exists(keep)) {
27867
- fs29.rmSync(parked, { recursive: true, force: true });
27868
- fs29.renameSync(keep, parked);
28529
+ fs30.rmSync(parked, { recursive: true, force: true });
28530
+ fs30.renameSync(keep, parked);
27869
28531
  }
27870
28532
  try {
27871
28533
  await installArchive(release.url, root, { sha256: release.sha256hash, locate: "Code.exe", fileName: "vscode.zip" });
27872
- fs29.writeFileSync(path42.join(root, VERSION_MARKER), release.productVersion);
28534
+ fs30.writeFileSync(path43.join(root, VERSION_MARKER), release.productVersion);
27873
28535
  } finally {
27874
28536
  if (exists(parked)) {
27875
28537
  mkdirp(root);
27876
- fs29.rmSync(keep, { recursive: true, force: true });
27877
- fs29.renameSync(parked, keep);
28538
+ fs30.rmSync(keep, { recursive: true, force: true });
28539
+ fs30.renameSync(parked, keep);
27878
28540
  }
27879
28541
  }
27880
28542
  }
27881
- mkdirp(path42.join(root, "data"));
27882
- env.prepend.push(path42.join(root, "bin"));
28543
+ mkdirp(path43.join(root, "data"));
28544
+ env.prepend.push(path43.join(root, "bin"));
27883
28545
  desktopShortcut(exe);
27884
- const version2 = exists(path42.join(root, VERSION_MARKER)) ? fs29.readFileSync(path42.join(root, VERSION_MARKER), "utf8").trim() : "installed";
28546
+ const version2 = exists(path43.join(root, VERSION_MARKER)) ? fs30.readFileSync(path43.join(root, VERSION_MARKER), "utf8").trim() : "installed";
27885
28547
  env.summary.push("vscode: " + version2 + " (portable; run code . or use the desktop shortcut)");
27886
28548
  };
27887
28549
 
@@ -27892,14 +28554,34 @@ var setupPythonTools = async (env, tools) => {
27892
28554
  await installOnce(env, "uv tool", tools, (pkg) => execAsync(uv, ["tool", "install", pkg], { env: { ...process.env, ...uvVars() } }));
27893
28555
  };
27894
28556
  var cargoTarget = (targetDir) => {
27895
- if (targetDir === "shared") return null;
27896
- if (targetDir === "separate") return path43.join(projectWorkspace(), "target", "sandbox");
27897
- if (targetDir === "local") return path43.join(localDir, "cargo-target");
28557
+ if (targetDir === "shared" || targetDir === "separate") return null;
28558
+ if (targetDir === "local") return path44.join(localDir, "cargo-target");
27898
28559
  return targetDir;
27899
28560
  };
28561
+ var cargoShim = (env, rust) => {
28562
+ const real = path44.join(tool("rust", "cargo", "bin"), "cargo.exe");
28563
+ if (rust.targetDir !== "separate" || !exists(real)) return;
28564
+ const dir = mkdirp(tool("shims", "cargo"));
28565
+ fs31.copyFileSync(ensureCompiled("cargoshim"), path44.join(dir, "cargo.exe"));
28566
+ env.prepend.unshift(dir);
28567
+ env.vars.AGENT_REAL_CARGO = real;
28568
+ };
28569
+ var cargoDefaults = (host) => {
28570
+ const file3 = tool("rust", "cargo", "config.toml");
28571
+ if (exists(file3) || !exists(path44.dirname(file3))) return;
28572
+ const jobs = Math.max(2, Math.min(4, Math.floor(os8.cpus().length / 4)));
28573
+ const gnu = host.endsWith("-gnu");
28574
+ fs31.writeFileSync(file3, [
28575
+ "# Written by windows-development-sandbox once; edit freely, it is never overwritten.",
28576
+ "[build]",
28577
+ "jobs = " + jobs,
28578
+ "",
28579
+ ...gnu ? ["[profile.dev]", 'debug = "line-tables-only"', "", "[profile.test]", 'debug = "line-tables-only"', ""] : []
28580
+ ].join("\n"));
28581
+ };
27900
28582
  var rustCaches = (rust) => {
27901
28583
  const target = cargoTarget(rust.targetDir);
27902
- return { ...target ? { CARGO_TARGET_DIR: target } : {}, ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path43.join(dataDir, "cache", "sccache") } };
28584
+ return { ...target ? { CARGO_TARGET_DIR: target } : {}, ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path44.join(dataDir, "cache", "sccache") } };
27903
28585
  };
27904
28586
  var rustHost = (config2) => {
27905
28587
  if (config2.rust.host !== "auto") return config2.rust.host;
@@ -27907,6 +28589,7 @@ var rustHost = (config2) => {
27907
28589
  return cpu + (wanted(config2.msvc.enabled, "msvc") ? "-pc-windows-msvc" : "-pc-windows-gnu");
27908
28590
  };
27909
28591
  var plan = (config2, versions, o) => {
28592
+ const apps = Boolean(o.apps && (o.apps.install.length || Object.keys(o.apps.custom).length));
27910
28593
  const java = wanted(config2.java.enabled, "java");
27911
28594
  const python = wanted(config2.python.enabled, "python");
27912
28595
  return [
@@ -27926,6 +28609,10 @@ var plan = (config2, versions, o) => {
27926
28609
  run: async (env) => {
27927
28610
  await setupRust(env, { ...config2.rust, host: rustHost(config2) }, o.refresh);
27928
28611
  Object.assign(env.vars, rustCaches(config2.rust));
28612
+ if (!dryRun) {
28613
+ cargoDefaults(rustHost(config2));
28614
+ cargoShim(env, config2.rust);
28615
+ }
27929
28616
  }
27930
28617
  },
27931
28618
  { name: ".NET", on: wanted(config2.dotnet.enabled, "dotnet"), run: (env) => setupDotnet(env, config2.dotnet, o.refresh) },
@@ -27933,7 +28620,8 @@ var plan = (config2, versions, o) => {
27933
28620
  { name: "Java", on: java, run: (env) => setupJava(env, config2.java) },
27934
28621
  { name: "Ruby", on: wanted(config2.ruby.enabled, "ruby"), run: (env) => setupRuby(env, config2.ruby) },
27935
28622
  // PHP installs the Visual C++ runtime itself: one installer at a time.
27936
- { name: "Visual C++ runtime", on: config2.vcRuntime.enabled, shared: true, run: async (env) => {
28623
+ // Many apps (bat, delta, Neovim, most GUIs, your own programs) are built against it too.
28624
+ { name: "Visual C++ runtime", on: config2.vcRuntime.enabled || apps, shared: true, run: async (env) => {
27937
28625
  await setupVcRuntime(env);
27938
28626
  } },
27939
28627
  { name: "PHP", on: wanted(config2.php.enabled, "php"), after: ["Visual C++ runtime"], run: (env) => setupPhp(env, config2.php) },
@@ -27943,8 +28631,10 @@ var plan = (config2, versions, o) => {
27943
28631
  { name: "PowerShell 7", on: wanted(config2.pwsh.enabled, "pwsh"), run: (env) => setupPwsh(env, o.refresh) },
27944
28632
  // The openssl tool comes from Git's install: after Git.
27945
28633
  { name: "CLI tools", on: Object.values(config2.cli).some((v) => v !== false), after: ["Git"], run: (env) => setupCli(env, config2.cli, o.gitAccess, o.refresh) },
27946
- { name: "Mesa 3D", on: config2.mesa.enabled, shared: true, run: (env) => setupMesa(env, config2.mesa) },
28634
+ { name: "Mesa 3D", on: config2.mesa.enabled || appsNeedMesa(o.apps), shared: true, run: (env) => setupMesa(env, config2.mesa) },
27947
28635
  { name: "VS Code", on: config2.vscode.enabled, shared: true, run: (env) => setupVscode(env, o.refresh) },
28636
+ // Desktop apps and extra tools (apps.install / apps.custom); games and 3D apps copy Mesa's OpenGL next to them.
28637
+ { name: "Apps", on: apps, shared: true, after: ["Mesa 3D", "Visual C++ runtime"], run: (env) => setupApps(env, o.apps, { gitAccess: o.gitAccess, refresh: o.refresh }) },
27948
28638
  { name: "Python tools", on: python && config2.python.tools.length > 0, after: ["Python", "uv"], run: (env) => setupPythonTools(env, config2.python.tools) },
27949
28639
  // DynamoDB Local runs on Java: the Java step installs the JDK first instead of racing it.
27950
28640
  // One server per database in the sandbox: a project that joins later shares the one the boot started.
@@ -27953,7 +28643,7 @@ var plan = (config2, versions, o) => {
27953
28643
  };
27954
28644
 
27955
28645
  // src/guest/toolchains/index.ts
27956
- var PARALLEL = 4;
28646
+ var PARALLEL2 = 4;
27957
28647
  var locks = /* @__PURE__ */ new Map();
27958
28648
  var lockKey = (name) => name.split(" ")[0].toLowerCase();
27959
28649
  var exclusive = async (name, work) => {
@@ -27992,7 +28682,7 @@ var runSteps = async (steps, o) => {
27992
28682
  done++;
27993
28683
  return;
27994
28684
  }
27995
- while (running.size >= PARALLEL) await new Promise((r) => waiting.push(r));
28685
+ while (running.size >= PARALLEL2) await new Promise((r) => waiting.push(r));
27996
28686
  running.add(s.name);
27997
28687
  report();
27998
28688
  try {
@@ -28031,14 +28721,14 @@ var provisionedFor = (cwd) => [...ready.values()].filter((p) => isWithin(p.spec.
28031
28721
  var provisionedProjects = () => [...ready.values()];
28032
28722
  var cmdSet = (env, names) => names.filter((n) => env[n] !== void 0 && !/[\r\n]/.test(String(env[n]))).map((n) => '@set "' + n + "=" + String(env[n]).replace(/%/g, "%%") + '"');
28033
28723
  var writeShell = (spec, env, names) => {
28034
- const dir = mkdirp(path44.join(localDir, "projects", spec.name));
28035
- fs30.writeFileSync(path44.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
28036
- fs30.writeFileSync(path44.join(dir, "shell.cmd"), ['@call "' + path44.join(dir, "env.cmd") + '"', '@cd /d "' + spec.workspace + '"', "@title " + spec.name, ""].join("\r\n"));
28037
- const bin = mkdirp(path44.join(localDir, "bin"));
28038
- fs30.writeFileSync(path44.join(bin, "sbx-shell.cmd"), [
28039
- '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path44.join(localDir, "projects") + '" & exit /b 2)',
28040
- '@if not exist "' + path44.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
28041
- '@cmd /k ""' + path44.join(localDir, "projects") + '\\%~1\\shell.cmd""',
28724
+ const dir = mkdirp(path45.join(localDir, "projects", spec.name));
28725
+ fs32.writeFileSync(path45.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
28726
+ fs32.writeFileSync(path45.join(dir, "shell.cmd"), ['@call "' + path45.join(dir, "env.cmd") + '"', '@cd /d "' + spec.workspace + '"', "@title " + spec.name, ""].join("\r\n"));
28727
+ const bin = mkdirp(path45.join(localDir, "bin"));
28728
+ fs32.writeFileSync(path45.join(bin, "sbx-shell.cmd"), [
28729
+ '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path45.join(localDir, "projects") + '" & exit /b 2)',
28730
+ '@if not exist "' + path45.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
28731
+ '@cmd /k ""' + path45.join(localDir, "projects") + '\\%~1\\shell.cmd""',
28042
28732
  ""
28043
28733
  ].join("\r\n"));
28044
28734
  };
@@ -28077,10 +28767,10 @@ var provision = async (spec, say) => {
28077
28767
  saveProjectStatus(spec.name, spec.workspace, "provisioning", m, spec.databases, []);
28078
28768
  say(m);
28079
28769
  }, reuse: boot?.steps }));
28080
- tools.prepend.push(path44.join(localDir, "bin"));
28770
+ tools.prepend.push(path45.join(localDir, "bin"));
28081
28771
  const env = agentEnv(tools, { workspace: spec.workspace, project: spec.name, base });
28082
- const specFile = path44.join(mkdirp(path44.join(localDir, "projects", spec.name)), "project.json");
28083
- fs30.writeFileSync(specFile, JSON.stringify(spec));
28772
+ const specFile = path45.join(mkdirp(path45.join(localDir, "projects", spec.name)), "project.json");
28773
+ fs32.writeFileSync(specFile, JSON.stringify(spec));
28084
28774
  env.AGENT_PROJECT_FILE = specFile;
28085
28775
  addMachineEnvironment(tools.vars, [...tools.prepend, ...tools.append], true);
28086
28776
  try {
@@ -28154,14 +28844,83 @@ var execCommand = (req) => {
28154
28844
  });
28155
28845
  };
28156
28846
 
28847
+ // src/guest/daemon/relays.ts
28848
+ import net2 from "node:net";
28849
+
28850
+ // src/shared/netpolicy.ts
28851
+ var relayPort = (index) => 38100 + index;
28852
+
28853
+ // src/guest/daemon/relays.ts
28854
+ var startRelays = () => {
28855
+ (session.network.forwardPorts ?? []).forEach((f, i) => {
28856
+ const server = net2.createServer((client) => {
28857
+ const target = net2.connect(f.sandbox, "127.0.0.1");
28858
+ client.pipe(target).pipe(client);
28859
+ target.on("error", () => client.destroy());
28860
+ client.on("error", () => target.destroy());
28861
+ });
28862
+ server.on("error", (e) => warn("Port forward " + f.pc + " -> " + f.sandbox + " could not start: " + errMsg(e)));
28863
+ server.listen(relayPort(i), "0.0.0.0", () => log("Port forward: the PC's localhost:" + f.pc + " reaches localhost:" + f.sandbox + " here."));
28864
+ });
28865
+ };
28866
+
28867
+ // src/guest/audit.ts
28868
+ import fs33 from "node:fs";
28869
+ import path47 from "node:path";
28870
+ import { spawnSync as spawnSync4 } from "node:child_process";
28871
+
28872
+ // src/guest/audit-parse.ts
28873
+ import path46 from "node:path";
28874
+ var NOISE = /* @__PURE__ */ new Set(["conhost.exe", "svchost.exe", "backgroundtaskhost.exe", "runtimebroker.exe", "wmiprvse.exe", "dllhost.exe", "searchprotocolhost.exe", "searchfilterhost.exe", "taskhostw.exe", "sppsvc.exe", "wermgr.exe", "consent.exe", "smartscreen.exe", "mpcmdrun.exe", "compattelrunner.exe", "wevtutil.exe", "audiodg.exe", "ctfmon.exe", "sihost.exe", "werfault.exe", "msmpeng.exe", "nissrv.exe", "usoclient.exe", "musnotification.exe"]);
28875
+ var decode3 = (s) => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
28876
+ var field = (event, name) => decode3(new RegExp("<Data Name='" + name + "'>([^<]*)</Data>").exec(event)?.[1] ?? "");
28877
+ var parseProcessEvents = (xml) => {
28878
+ const lines = [];
28879
+ let last = 0;
28880
+ for (const event of xml.split("</Event>")) {
28881
+ const id = Number(/<EventRecordID>(\d+)<\/EventRecordID>/.exec(event)?.[1] ?? 0);
28882
+ if (!id) continue;
28883
+ last = Math.max(last, id);
28884
+ const program = field(event, "NewProcessName");
28885
+ if (!program || NOISE.has(path46.win32.basename(program).toLowerCase())) continue;
28886
+ const t = /SystemTime='([^']+)'/.exec(event)?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
28887
+ lines.push(JSON.stringify({ t, k: "proc", p: program.slice(0, 1024), c: field(event, "CommandLine").slice(0, 2e3), pp: field(event, "ParentProcessName").slice(0, 1024) }));
28888
+ }
28889
+ return { lines, last };
28890
+ };
28891
+
28892
+ // src/guest/audit.ts
28893
+ var MAX_PER_PASS = 2e3;
28894
+ var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
28895
+ var wevtutil = () => path47.join(process.env.WINDIR ?? "C:\\Windows", "System32", "wevtutil.exe");
28896
+ var newestRecord = () => {
28897
+ const r = spawnSync4(wevtutil(), ["qe", "Security", "/q:*[System[(EventID=4688)]]", "/f:xml", "/c:1", "/rd:true"], { encoding: "utf8", windowsHide: true });
28898
+ return parseProcessEvents(r.stdout ?? "").last;
28899
+ };
28900
+ var startProcessCollector = () => {
28901
+ if (!auditOn()) return;
28902
+ let last = newestRecord();
28903
+ const pass = () => {
28904
+ try {
28905
+ const r = spawnSync4(wevtutil(), ["qe", "Security", "/q:*[System[(EventID=4688) and (EventRecordID>" + last + ")]]", "/f:xml", "/c:" + MAX_PER_PASS], { encoding: "utf8", windowsHide: true, maxBuffer: 64 * 1024 * 1024 });
28906
+ const { lines, last: newest } = parseProcessEvents(r.stdout ?? "");
28907
+ if (newest) last = newest;
28908
+ if (lines.length) fs33.writeFileSync(path47.join(mkdirp(run.audit), Date.now() + "-" + process.pid + ".jsonl"), lines.join("\n") + "\n");
28909
+ } catch (e) {
28910
+ warn("audit: " + errMsg(e));
28911
+ }
28912
+ };
28913
+ setInterval(pass, 15e3).unref?.();
28914
+ };
28915
+
28157
28916
  // src/guest/daemon/session.ts
28158
- import path48 from "node:path";
28917
+ import path52 from "node:path";
28159
28918
  import crypto3 from "node:crypto";
28160
28919
  import { spawn as spawn7 } from "node:child_process";
28161
28920
 
28162
28921
  // src/shared/pty-client.ts
28163
- import net2 from "node:net";
28164
- var FrameType = { Hello: 1, Input: 2, Resize: 3, Restart: 4, Ping: 5, Output: 16, Exit: 17, Error: 18, Restarting: 19, Status: 20 };
28922
+ import net3 from "node:net";
28923
+ var FrameType = { Hello: 1, Input: 2, Resize: 3, Restart: 4, Ping: 5, Output: 16, Exit: 17, Error: 18, Restarting: 19, Status: 20, Console: 21 };
28165
28924
  var HelloFlag = { ControlOnly: 1, Query: 2 };
28166
28925
  var encodeFrame = (type, payload = Buffer.alloc(0)) => {
28167
28926
  const header = Buffer.alloc(5);
@@ -28178,8 +28937,8 @@ var helloFrame = (token, cols, rows, flags = 0) => {
28178
28937
  };
28179
28938
  var MAX_FRAME_BYTES = 1 << 20;
28180
28939
  var connectOnce = (host, port, timeoutMs) => {
28181
- return new Promise((resolve, reject) => {
28182
- const socket = net2.connect({ host, port });
28940
+ return new Promise((resolve2, reject) => {
28941
+ const socket = net3.connect({ host, port });
28183
28942
  const timer = setTimeout(() => {
28184
28943
  socket.destroy();
28185
28944
  reject(new Error("timed out connecting to " + host + ":" + port));
@@ -28187,7 +28946,7 @@ var connectOnce = (host, port, timeoutMs) => {
28187
28946
  socket.once("connect", () => {
28188
28947
  clearTimeout(timer);
28189
28948
  socket.setNoDelay(true);
28190
- resolve(socket);
28949
+ resolve2(socket);
28191
28950
  });
28192
28951
  socket.once("error", (e) => {
28193
28952
  clearTimeout(timer);
@@ -28208,11 +28967,11 @@ var connect = async (endpoint, timeoutMs = 3e3) => {
28208
28967
  };
28209
28968
  var sendControl = async (endpoint, type) => {
28210
28969
  const socket = await connect(endpoint);
28211
- await new Promise((resolve) => socket.end(Buffer.concat([helloFrame(endpoint.token, 80, 24, HelloFlag.ControlOnly), encodeFrame(type)]), resolve));
28970
+ await new Promise((resolve2) => socket.end(Buffer.concat([helloFrame(endpoint.token, 80, 24, HelloFlag.ControlOnly), encodeFrame(type)]), resolve2));
28212
28971
  };
28213
28972
 
28214
28973
  // src/guest/cmdline.ts
28215
- import path45 from "node:path";
28974
+ import path48 from "node:path";
28216
28975
  var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
28217
28976
  var quoteArg = (arg) => arg !== "" && !/[\s"]/.test(arg) ? arg : quoted(arg);
28218
28977
  var cmdArgs = (args) => {
@@ -28223,11 +28982,11 @@ var cmdArgs = (args) => {
28223
28982
  return !inQuotes && /[&|<>^]/.test(c) ? "^^^" + c : c;
28224
28983
  }).join("");
28225
28984
  };
28226
- var commandLine = (file3, args) => path45.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
28985
+ var commandLine = (file3, args) => path48.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
28227
28986
 
28228
28987
  // src/guest/ptyhost.ts
28229
- import fs31 from "node:fs";
28230
- import path46 from "node:path";
28988
+ import fs34 from "node:fs";
28989
+ import path49 from "node:path";
28231
28990
  import { spawn as spawn6 } from "node:child_process";
28232
28991
  var ensurePtyHost = () => ensureCompiled("ptyhost");
28233
28992
  var waitForPtyHost = async (child, port, timeoutMs) => {
@@ -28243,33 +29002,37 @@ var waitForPtyHost = async (child, port, timeoutMs) => {
28243
29002
  }
28244
29003
  throw new Error("the session host did not start listening on port " + port);
28245
29004
  };
28246
- var ptyHostLog = (id) => path46.join(logsDir, "ptyhost-" + id + ".log");
29005
+ var ptyHostLog = (id) => path49.join(logsDir, "ptyhost-" + id + ".log");
28247
29006
  var ptyHostLogTail = (id, lines = 12) => {
28248
29007
  try {
28249
- return fs31.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
29008
+ return fs34.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
28250
29009
  } catch {
28251
29010
  return "";
28252
29011
  }
28253
29012
  };
28254
- var startPtyHost = (o) => spawn6(o.exe, [String(o.port), o.token, String(o.cols), String(o.rows), ptyHostLog(o.id), o.command, o.restartCommand], {
28255
- cwd: o.cwd,
28256
- env: { ...o.env, PTYHOST_BIND: o.remote ? "any" : "loopback" },
28257
- detached: true,
28258
- stdio: "ignore",
28259
- windowsHide: true
28260
- });
29013
+ var conptyDll = () => {
29014
+ const dll = path49.join(toolsDir, "conpty", "conpty.dll");
29015
+ return session.provisioning.conpty?.enabled !== false && fs34.existsSync(dll) && fs34.existsSync(path49.join(toolsDir, "conpty", "OpenConsole.exe")) ? dll : null;
29016
+ };
29017
+ var startPtyHost = (o) => {
29018
+ const env = { ...o.env, PTYHOST_BIND: o.remote ? "any" : "loopback" };
29019
+ delete env.PTYHOST_CONPTY;
29020
+ const dll = conptyDll();
29021
+ if (dll) env.PTYHOST_CONPTY = dll;
29022
+ return spawn6(o.exe, [String(o.port), o.token, String(o.cols), String(o.rows), ptyHostLog(o.id), o.command, o.restartCommand], { cwd: o.cwd, env, detached: true, stdio: "ignore", windowsHide: true });
29023
+ };
28261
29024
 
28262
29025
  // src/guest/setup/agents.ts
28263
- import fs32 from "node:fs";
28264
- import path47 from "node:path";
29026
+ import fs35 from "node:fs";
29027
+ import path50 from "node:path";
28265
29028
  var harnessPaths = (name, harness) => {
28266
- const dir = path47.join(toolsDir, "agents", name);
29029
+ const dir = path50.join(toolsDir, "agents", name);
28267
29030
  const exe = harness.hostExecutable ?? (harness.uvBin ? harness.uvBin + ".exe" : null);
28268
- return { dir, exe: exe ? path47.join(dir, exe) : null, cmd: harness.npmBin ? path47.join(dir, harness.npmBin + ".cmd") : null };
29031
+ return { dir, exe: exe ? path50.join(dir, exe) : null, cmd: harness.npmBin ? path50.join(dir, harness.npmBin + ".cmd") : null };
28269
29032
  };
28270
29033
  var installViaNpm = async (name, harness, dir, env) => {
28271
29034
  if (!harness.npmPackage) throw new Error("No npmPackage configured for " + name + " and no host executable was available.");
28272
- const npmCli = path47.join(path47.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
29035
+ const npmCli = path50.join(path50.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28273
29036
  const args = [npmCli, "install", "--global", "--prefix", dir, harness.npmPackage, "--no-fund", "--no-audit"];
28274
29037
  log("Installing " + harness.npmPackage + " (this can take a minute)...");
28275
29038
  if (dryRun) {
@@ -28280,7 +29043,7 @@ var installViaNpm = async (name, harness, dir, env) => {
28280
29043
  await execAsync(process.execPath, args, { env });
28281
29044
  };
28282
29045
  var installViaUv = async (name, harness, dir, env) => {
28283
- const uv = path47.join(toolsDir, "uv", "uv.exe");
29046
+ const uv = path50.join(toolsDir, "uv", "uv.exe");
28284
29047
  log("Installing " + harness.uvPackage + " with uv (this can take a minute)...");
28285
29048
  if (dryRun) {
28286
29049
  log("(dry run) uv tool install " + harness.uvPackage);
@@ -28306,9 +29069,9 @@ var installHarness = async (name, harness, env, refresh) => {
28306
29069
  }
28307
29070
  mkdirp(p.dir);
28308
29071
  if (session.provisioning.copyFromHost && harness.hostExecutable && name === session.harnessName) {
28309
- const source = path47.join(hostToolsDir, "agents", name, harness.hostExecutable);
29072
+ const source = path50.join(hostToolsDir, "agents", name, harness.hostExecutable);
28310
29073
  if (exists(source) && p.exe) {
28311
- fs32.copyFileSync(source, p.exe);
29074
+ fs35.copyFileSync(source, p.exe);
28312
29075
  log("Copied " + name + " from this PC: " + source);
28313
29076
  return;
28314
29077
  }
@@ -28327,11 +29090,13 @@ var resolveLaunch = (name, harness) => {
28327
29090
  };
28328
29091
 
28329
29092
  // src/guest/setup/network.ts
28330
- import os6 from "node:os";
28331
- var guestAddresses = () => Object.values(os6.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address);
29093
+ import os9 from "node:os";
29094
+ import path51 from "node:path";
29095
+ var HOSTS_FILE = path51.join(process.env.WINDIR ?? "C:\\Windows", "System32", "drivers", "etc", "hosts");
29096
+ var guestAddresses = () => Object.values(os9.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address);
28332
29097
 
28333
29098
  // src/guest/daemon/shutdown.ts
28334
- import { spawnSync as spawnSync4 } from "node:child_process";
29099
+ import { spawnSync as spawnSync5 } from "node:child_process";
28335
29100
  var maybeShutdown = () => {
28336
29101
  if (!session.headless || !isWin) return;
28337
29102
  const idle = () => live.size === 0 && pending.starting === 0 && scanRequests(dataDir).valid.length === 0;
@@ -28340,14 +29105,14 @@ var maybeShutdown = () => {
28340
29105
  if (!idle()) return;
28341
29106
  log("Headless sandbox has no sessions left; shutting down.");
28342
29107
  safely("claude-mem save", saveClaudeMem);
28343
- spawnSync4(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
29108
+ spawnSync5(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
28344
29109
  }, 15e3);
28345
29110
  };
28346
29111
 
28347
29112
  // src/guest/daemon/session.ts
28348
29113
  var terminalTab = (id, title, cwd) => {
28349
- const view = [process.execPath, path48.join(path48.dirname(process.argv[1]), "view.js"), id];
28350
- const wt = path48.join(toolsDir, "terminal", "wt.exe");
29114
+ const view = [process.execPath, path52.join(path52.dirname(process.argv[1]), "view.js"), id];
29115
+ const wt = path52.join(toolsDir, "terminal", "wt.exe");
28351
29116
  if (exists(wt)) spawn7(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
28352
29117
  else spawn7(SYSTEM.cmd(), ["/d", "/c", "start", title, ...view], { detached: true, stdio: "ignore", cwd }).unref();
28353
29118
  };
@@ -28392,7 +29157,7 @@ var launchPtyHost = async (req, remote, env, say) => {
28392
29157
  await waitForPtyHost(child, port, 15e3);
28393
29158
  } catch (e) {
28394
29159
  const tail = ptyHostLogTail(req.id);
28395
- throw new Error(errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path48.join(dataDir, "logs", "ptyhost-" + req.id + ".log"));
29160
+ throw new Error(errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path52.join(dataDir, "logs", "ptyhost-" + req.id + ".log"));
28396
29161
  }
28397
29162
  return { child, port, token };
28398
29163
  };
@@ -28414,7 +29179,7 @@ var startSession = async (req) => {
28414
29179
  saveStatus(status);
28415
29180
  };
28416
29181
  pending.starting++;
28417
- if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1") safely("terminal tab", () => terminalTab(req.id, req.harness + " " + path48.basename(req.cwd), req.cwd));
29182
+ if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1") safely("terminal tab", () => terminalTab(req.id, req.harness + " " + path52.basename(req.cwd), req.cwd));
28418
29183
  try {
28419
29184
  const place = await placeFor(req, say);
28420
29185
  const remote = session.networking && session.attach.enabled;
@@ -28470,9 +29235,9 @@ var handle = (req) => {
28470
29235
  };
28471
29236
  var tick = () => {
28472
29237
  const { valid, invalid } = scanRequests(dataDir);
28473
- for (const file3 of invalid) safely("removing an invalid request", () => fs33.rmSync(file3, { recursive: true, force: true }));
29238
+ for (const file3 of invalid) safely("removing an invalid request", () => fs36.rmSync(file3, { recursive: true, force: true }));
28474
29239
  for (const req of valid) {
28475
- safely("claiming a request", () => fs33.rmSync(run.request(req.id), { force: true }));
29240
+ safely("claiming a request", () => fs36.rmSync(run.request(req.id), { force: true }));
28476
29241
  if (readSession(dataDir, req.id)) continue;
28477
29242
  void Promise.resolve(handle(req)).catch((e) => respond(req.id, { ok: false, message: errMsg(e) }));
28478
29243
  }
@@ -28491,4 +29256,6 @@ var loop = () => {
28491
29256
  }
28492
29257
  };
28493
29258
  log("Session daemon started (pid " + process.pid + ").");
29259
+ safely("port forwards", startRelays);
29260
+ safely("audit", startProcessCollector);
28494
29261
  loop();