windows-development-sandbox 1.1.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.sandbox-config.example.json +2 -1
  2. package/README.md +3 -2
  3. package/config.example.json +39 -5
  4. package/dist/cli/args.d.ts +3 -0
  5. package/dist/cli/args.js +3 -1
  6. package/dist/cli/boot-progress.d.ts +22 -0
  7. package/dist/cli/boot-progress.js +59 -0
  8. package/dist/cli/commands/accounts.js +2 -2
  9. package/dist/cli/commands/agent-commands.js +1 -1
  10. package/dist/cli/commands/context.js +2 -1
  11. package/dist/cli/commands/data/clean.js +6 -1
  12. package/dist/cli/commands/data/collect.js +3 -3
  13. package/dist/cli/commands/index.d.ts +1 -1
  14. package/dist/cli/commands/index.js +1 -1
  15. package/dist/cli/commands/launch.d.ts +5 -2
  16. package/dist/cli/commands/launch.js +113 -25
  17. package/dist/cli/commands/maintenance.d.ts +2 -0
  18. package/dist/cli/commands/maintenance.js +70 -4
  19. package/dist/cli/commands/project.d.ts +10 -6
  20. package/dist/cli/commands/project.js +42 -3
  21. package/dist/cli/commands/restart.js +17 -7
  22. package/dist/cli/commands/sessions.js +5 -4
  23. package/dist/cli/commands/user-config.js +1 -1
  24. package/dist/cli/index.js +6 -4
  25. package/dist/cli/manifest.js +6 -1
  26. package/dist/cli/menu/apps.d.ts +21 -0
  27. package/dist/cli/menu/apps.js +122 -0
  28. package/dist/cli/menu/command-form.d.ts +28 -0
  29. package/dist/cli/menu/command-form.js +219 -0
  30. package/dist/cli/menu/index.d.ts +26 -0
  31. package/dist/cli/menu/index.js +180 -0
  32. package/dist/cli/menu/settings/categories.d.ts +9 -0
  33. package/dist/cli/menu/settings/categories.js +28 -0
  34. package/dist/cli/menu/settings/config-file.d.ts +40 -0
  35. package/dist/cli/menu/settings/config-file.js +71 -0
  36. package/dist/cli/menu/settings/editors.d.ts +30 -0
  37. package/dist/cli/menu/settings/editors.js +305 -0
  38. package/dist/cli/menu/settings/index.d.ts +32 -0
  39. package/dist/cli/menu/settings/index.js +136 -0
  40. package/dist/cli/menu/settings/schema-node.d.ts +62 -0
  41. package/dist/cli/menu/settings/schema-node.js +104 -0
  42. package/dist/cli/{menu-multi.d.ts → menu/several.d.ts} +10 -2
  43. package/dist/cli/menu/several.js +102 -0
  44. package/dist/cli/progress.d.ts +15 -0
  45. package/dist/cli/progress.js +52 -0
  46. package/dist/cli/tui/app.d.ts +39 -0
  47. package/dist/cli/tui/app.js +52 -0
  48. package/dist/cli/tui/dialogs.d.ts +57 -0
  49. package/dist/cli/tui/dialogs.js +162 -0
  50. package/dist/cli/tui/frame.d.ts +18 -0
  51. package/dist/cli/tui/frame.js +27 -0
  52. package/dist/cli/tui/index.d.ts +7 -0
  53. package/dist/cli/tui/index.js +8 -0
  54. package/dist/cli/tui/list-screen.d.ts +101 -0
  55. package/dist/cli/tui/list-screen.js +299 -0
  56. package/dist/cli/tui/terminal.d.ts +37 -0
  57. package/dist/cli/tui/terminal.js +89 -0
  58. package/dist/cli/tui/text.d.ts +20 -0
  59. package/dist/cli/tui/text.js +105 -0
  60. package/dist/cli/tui/theme.d.ts +45 -0
  61. package/dist/cli/tui/theme.js +30 -0
  62. package/dist/core/config.js +10 -7
  63. package/dist/core/local-config.d.ts +31 -1
  64. package/dist/core/local-config.js +72 -7
  65. package/dist/core/project-policy.d.ts +50 -3
  66. package/dist/core/project-policy.js +90 -4
  67. package/dist/core/schema/apps.d.ts +40 -0
  68. package/dist/core/schema/apps.js +27 -0
  69. package/dist/core/schema/config.d.ts +69 -3
  70. package/dist/core/schema/config.js +18 -6
  71. package/dist/core/schema/profile.d.ts +5 -0
  72. package/dist/core/schema/profile.js +4 -2
  73. package/dist/core/schema/projects.d.ts +1 -0
  74. package/dist/core/schema/projects.js +1 -0
  75. package/dist/core/schema/sandbox.d.ts +29 -1
  76. package/dist/core/schema/sandbox.js +29 -1
  77. package/dist/core/schema/toolchains.d.ts +3 -0
  78. package/dist/core/schema/toolchains.js +6 -1
  79. package/dist/core/types.d.ts +24 -1
  80. package/dist/core/util.d.ts +2 -0
  81. package/dist/core/util.js +2 -0
  82. package/dist/core/workspace.d.ts +21 -4
  83. package/dist/core/workspace.js +99 -21
  84. package/dist/guest/apps/index.d.ts +10 -0
  85. package/dist/guest/apps/index.js +206 -0
  86. package/dist/guest/apps/resolvers.d.ts +8 -0
  87. package/dist/guest/apps/resolvers.js +90 -0
  88. package/dist/guest/audit-parse.d.ts +7 -0
  89. package/dist/guest/audit-parse.js +24 -0
  90. package/dist/guest/audit.d.ts +4 -0
  91. package/dist/guest/audit.js +47 -0
  92. package/dist/guest/daemon/relays.d.ts +1 -0
  93. package/dist/guest/daemon/relays.js +18 -0
  94. package/dist/guest/daemon.js +4 -0
  95. package/dist/guest/env.d.ts +7 -2
  96. package/dist/guest/env.js +17 -3
  97. package/dist/guest/helpers.d.ts +1 -1
  98. package/dist/guest/main.js +20 -3
  99. package/dist/guest/netproxy.d.ts +1 -0
  100. package/dist/guest/netproxy.js +100 -0
  101. package/dist/guest/ptyhost.js +14 -4
  102. package/dist/guest/setup/claude.d.ts +0 -4
  103. package/dist/guest/setup/claude.js +48 -2
  104. package/dist/guest/setup/network.d.ts +9 -0
  105. package/dist/guest/setup/network.js +97 -4
  106. package/dist/guest/setup/user.js +4 -0
  107. package/dist/guest/toolchains/index.js +29 -3
  108. package/dist/guest/toolchains/native/mesa.js +13 -3
  109. package/dist/guest/toolchains/plan.d.ts +3 -1
  110. package/dist/guest/toolchains/plan.js +53 -9
  111. package/dist/guest/toolchains/python.js +26 -2
  112. package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
  113. package/dist/guest/toolchains/vscode-profile.js +69 -0
  114. package/dist/guest/toolchains/vscode.d.ts +17 -0
  115. package/dist/guest/toolchains/vscode.js +87 -1
  116. package/dist/host/attach.js +2 -1
  117. package/dist/host/audit/collect.d.ts +34 -0
  118. package/dist/host/audit/collect.js +126 -0
  119. package/dist/host/audit/log.d.ts +46 -0
  120. package/dist/host/audit/log.js +143 -0
  121. package/dist/host/channel.d.ts +2 -2
  122. package/dist/host/channel.js +3 -2
  123. package/dist/host/generate.d.ts +7 -1
  124. package/dist/host/generate.js +23 -6
  125. package/dist/host/join.d.ts +7 -0
  126. package/dist/host/join.js +23 -9
  127. package/dist/host/launch/mappings.d.ts +7 -2
  128. package/dist/host/launch/mappings.js +68 -18
  129. package/dist/host/launch/projects.d.ts +2 -0
  130. package/dist/host/launch/projects.js +11 -5
  131. package/dist/host/launch/stage.js +1 -1
  132. package/dist/host/motw.d.ts +17 -0
  133. package/dist/host/motw.js +74 -0
  134. package/dist/host/platform.js +3 -0
  135. package/dist/host/port-forward.d.ts +8 -0
  136. package/dist/host/port-forward.js +37 -0
  137. package/dist/host/projects.d.ts +25 -2
  138. package/dist/host/projects.js +54 -5
  139. package/dist/host/repo-guard.d.ts +10 -3
  140. package/dist/host/repo-guard.js +142 -14
  141. package/dist/host/stops.d.ts +67 -0
  142. package/dist/host/stops.js +126 -0
  143. package/dist/host/terminal.d.ts +8 -0
  144. package/dist/host/terminal.js +45 -1
  145. package/dist/host/workspace-view/index.d.ts +20 -0
  146. package/dist/host/workspace-view/index.js +53 -0
  147. package/dist/host/workspace-view/rules.d.ts +26 -0
  148. package/dist/host/workspace-view/rules.js +93 -0
  149. package/dist/host/workspace-view/view.d.ts +50 -0
  150. package/dist/host/workspace-view/view.js +281 -0
  151. package/dist/runtime/daemon.js +1387 -558
  152. package/dist/runtime/db.js +199 -14
  153. package/dist/runtime/main.js +3082 -631
  154. package/dist/runtime/netproxy.js +25948 -0
  155. package/dist/runtime/view.js +531 -148
  156. package/dist/selftest/audit.test.d.ts +2 -0
  157. package/dist/selftest/audit.test.js +57 -0
  158. package/dist/selftest/channel.test.js +45 -2
  159. package/dist/selftest/cli.test.js +47 -17
  160. package/dist/selftest/fixtures.d.ts +47 -1
  161. package/dist/selftest/fixtures.js +3 -1
  162. package/dist/selftest/generate.test.js +7 -2
  163. package/dist/selftest/index.js +6 -2
  164. package/dist/selftest/live-network.test.d.ts +2 -0
  165. package/dist/selftest/live-network.test.js +63 -0
  166. package/dist/selftest/live-terminal.test.d.ts +2 -0
  167. package/dist/selftest/live-terminal.test.js +169 -0
  168. package/dist/selftest/local-config.test.js +42 -4
  169. package/dist/selftest/mirror.test.js +36 -7
  170. package/dist/selftest/network.test.js +12 -0
  171. package/dist/selftest/projects.test.js +77 -8
  172. package/dist/selftest/repo-guard.test.js +59 -1
  173. package/dist/selftest/sync.test.js +50 -10
  174. package/dist/selftest/toolchains.test.js +30 -0
  175. package/dist/selftest/workspace-view.test.d.ts +2 -0
  176. package/dist/selftest/workspace-view.test.js +89 -0
  177. package/dist/shared/apps.d.ts +49 -0
  178. package/dist/shared/apps.js +114 -0
  179. package/dist/shared/console-input.d.ts +11 -0
  180. package/dist/shared/console-input.js +61 -0
  181. package/dist/shared/download.d.ts +3 -0
  182. package/dist/shared/download.js +25 -2
  183. package/dist/shared/guest-paths.d.ts +27 -0
  184. package/dist/shared/guest-paths.js +68 -0
  185. package/dist/shared/netpolicy.d.ts +27 -0
  186. package/dist/shared/netpolicy.js +51 -0
  187. package/dist/shared/projects.d.ts +27 -4
  188. package/dist/shared/projects.js +72 -13
  189. package/dist/shared/pty-client.d.ts +26 -4
  190. package/dist/shared/pty-client.js +204 -25
  191. package/dist/shared/rundir.d.ts +2 -0
  192. package/dist/shared/rundir.js +2 -0
  193. package/dist/shared/schema.d.ts +34 -0
  194. package/dist/shared/schema.js +14 -0
  195. package/dist/shared/system.d.ts +1 -0
  196. package/dist/shared/system.js +1 -0
  197. package/dist/sync/claude-mem.js +3 -2
  198. package/dist/sync/history.d.ts +6 -0
  199. package/dist/sync/history.js +26 -11
  200. package/dist/sync/watcher.js +78 -6
  201. package/package.json +2 -1
  202. package/sandbox/cargoshim.cs +56 -0
  203. package/sandbox/cpucap.cs +33 -0
  204. package/sandbox/cpucap.ps1 +4 -35
  205. package/sandbox/logon.cmd +6 -0
  206. package/sandbox/memlog.ps1 +34 -0
  207. package/sandbox/pagefile.cs +31 -0
  208. package/sandbox/pagefile.ps1 +21 -0
  209. package/sandbox/ptyhost.cs +162 -7
  210. package/schemas/config.schema.json +318 -3
  211. package/schemas/sandbox-config.schema.json +129 -14
  212. package/dist/cli/menu-multi.js +0 -82
  213. package/dist/cli/menu.d.ts +0 -14
  214. package/dist/cli/menu.js +0 -290
  215. package/dist/cli/settings/edit.d.ts +0 -13
  216. package/dist/cli/settings/edit.js +0 -19
  217. package/dist/cli/settings/index.d.ts +0 -8
  218. package/dist/cli/settings/index.js +0 -131
  219. package/dist/cli/settings/prompts.d.ts +0 -7
  220. package/dist/cli/settings/prompts.js +0 -48
  221. package/dist/cli/settings/schema.d.ts +0 -33
  222. 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,15 +25310,17 @@ 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
25318
25320
  var GuestWorkspace = external_exports.union([external_exports.literal("auto"), external_exports.literal("mirror"), GuestPath]).describe('Where the workspace appears inside the sandbox. "auto" = C:\\Workspace\\<folder name>. "mirror" = the same path as on this PC, so absolute paths in configs and build caches match (another drive letter such as F: is a subst drive onto C:\\Mirror\\F); paths the sandbox reserves (C:\\Users\\..., C:\\Program Files\\...) fall back to "auto".');
25319
25321
  var Mapping = external_exports.strictObject({
25320
25322
  host: external_exports.string().min(1).describe("Folder on this PC (relative paths are relative to the config file)."),
25321
- guest: GuestPath.describe("Where it appears inside the sandbox, e.g. C:\\Assets, or on another drive letter (D: to Z:) such as F:\\SteamLibrary\\steamapps\\common\\Game: mapped to C:\\Mirror\\F\\... and shown as F: (subst) at boot."),
25323
+ guest: external_exports.string().min(1).max(1024).optional().describe("Where it appears inside the sandbox, e.g. C:\\Assets, or on another drive letter (D: to Z:) such as F:\\SteamLibrary\\steamapps\\common\\Game (shown as F: at boot). Leave it out to use the same path as on this PC (a folder inside the project stays where it is in the project). A path the sandbox cannot use (C:\\Windows\\..., C:\\Users\\..., one already in use) goes to C:\\Mapped\\<drive>\\<path> instead, and the launch says so."),
25322
25324
  readOnly: external_exports.boolean().describe("true = the agent can only read it."),
25323
25325
  optional: external_exports.boolean().optional().describe("true = skip it quietly when the host folder does not exist.")
25324
25326
  });
@@ -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."),
@@ -25438,6 +25608,7 @@ var Projects = external_exports.strictObject({
25438
25608
  roots: external_exports.array(external_exports.string().min(1)).describe('Folders whose subfolders are your projects (e.g. "F:\\\\Code"), mapped read/write at every start. Any project inside one, including ones you create later, opens in the running sandbox at once, without a restart. Every agent in the sandbox can see all of them.'),
25439
25609
  askToAddRoot: external_exports.boolean().describe("When you start a project whose parent folder is not a root yet, ask once whether to add it."),
25440
25610
  declinedRoots: external_exports.array(external_exports.string().min(1)).describe("Parent folders you said no to (not asked again)."),
25611
+ allowOutsideMappings: external_exports.union([external_exports.literal("ask"), external_exports.boolean()]).describe(`A project's .sandbox-config.json may map folders from outside the project (e.g. a game folder on another drive). "ask" = an interactive launch asks once per project and set of folders, and remembers your answer; true = always allowed (still listed when you approve the file); false = never (the launch stops and says which folders). Only your own settings decide this, never a project file.`),
25441
25612
  wsbShare: external_exports.boolean().describe("On Windows 11 24H2+ with the Windows Sandbox command line (wsb), add other folders to the running sandbox with `wsb share` (untested). Otherwise starting a project outside every root offers a restart.")
25442
25613
  });
25443
25614
 
@@ -25447,14 +25618,18 @@ var Config = external_exports.strictObject({
25447
25618
  defaultHarness: Name.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
25448
25619
  guestWorkspace: GuestWorkspace,
25449
25620
  readOnly: external_exports.boolean().describe("Map the workspace read-only."),
25621
+ workspaceFilter: WorkspaceFilter,
25622
+ audit: Audit,
25450
25623
  mappings: external_exports.array(Mapping).describe("Extra folders from this PC."),
25451
25624
  sandbox: Sandbox,
25452
25625
  storage: external_exports.strictObject({
25453
25626
  root: external_exports.string().min(1).describe("Where everything is kept on this PC (tools, databases, logins, launches)."),
25454
25627
  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.")
25628
+ dataName: Name.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces."),
25629
+ 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.`),
25630
+ 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
25631
  }),
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.") }),
25632
+ network: Network,
25458
25633
  provisioning: Provisioning,
25459
25634
  downloads: Downloads,
25460
25635
  toolchains: Toolchains,
@@ -25463,6 +25638,7 @@ var Config = external_exports.strictObject({
25463
25638
  agentCommands: AgentCommands,
25464
25639
  secrets: Secrets,
25465
25640
  personalization: toggle("Copy your desktop look (theme, accent, taskbar, wallpaper, ...) into the sandbox."),
25641
+ apps: Apps,
25466
25642
  claudeProfile: ClaudeProfile,
25467
25643
  harnesses: external_exports.record(Name, Harness).describe("Agents that can run in the sandbox."),
25468
25644
  hooks: external_exports.strictObject({ failFast: external_exports.boolean().describe("Stop when a hook script fails.") }),
@@ -25473,10 +25649,14 @@ var LocalOverrides = external_exports.strictObject({
25473
25649
  harness: Name.describe("Agent for this project."),
25474
25650
  guestWorkspace: GuestWorkspace,
25475
25651
  readOnly: external_exports.boolean().describe("Map this project read-only."),
25476
- mappings: external_exports.array(Mapping).describe("Extra folders (relative to this file)."),
25652
+ // A project may turn the filter on and keep more out, never let ignored files in.
25653
+ workspaceFilter: WorkspaceFilter.pick({ enabled: true, exclude: true }).partial(),
25654
+ mappings: external_exports.array(Mapping).describe("Extra folders (relative paths are relative to this file), e.g. a read-only data folder at another place in the sandbox. Folders outside the project are used only as your projects.allowOutsideMappings setting allows (by default you are asked once)."),
25477
25655
  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(),
25656
+ // This PC's resources are yours to share: CPU and paging file (this PC's disk) are not a project's to set.
25657
+ sandbox: Sandbox.omit({ cpuLimit: true, pageFileMb: true }).partial(),
25658
+ // A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
25659
+ network: Network.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
25480
25660
  provisioning: Provisioning.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: Git.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
25481
25661
  downloads: Downloads.partial(),
25482
25662
  // Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
@@ -25487,7 +25667,9 @@ var LocalOverrides = external_exports.strictObject({
25487
25667
  databases: external_exports.strictObject(import_lodash.default.mapValues(Databases.shape, (shape) => shape.partial())).partial(),
25488
25668
  attach: Attach.partial(),
25489
25669
  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(),
25670
+ // Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add them.
25671
+ apps: Apps.pick({ install: true }).partial(),
25672
+ claudeProfile: ClaudeProfile.pick({ enabled: true, overwrite: true, copyCredentials: true, syncHistory: true, syncClaudeMem: true }).partial(),
25491
25673
  hooks: external_exports.strictObject({ failFast: external_exports.boolean() }).partial()
25492
25674
  }).partial();
25493
25675
 
@@ -25500,6 +25682,15 @@ var AttachEndpoint = external_exports.strictObject({
25500
25682
  port: external_exports.number().int().min(1024).max(65535),
25501
25683
  token: Text(256)
25502
25684
  });
25685
+ var BootProgress = external_exports.strictObject({
25686
+ step: external_exports.number().int().min(1).max(32),
25687
+ steps: external_exports.number().int().min(1).max(32),
25688
+ title: Text(120),
25689
+ /** Being set up now; percent while it downloads (when the size is known). */
25690
+ active: external_exports.array(external_exports.strictObject({ name: Text(64), percent: external_exports.number().int().min(0).max(100).optional() })).max(8),
25691
+ done: external_exports.number().int().min(0).max(1e3),
25692
+ total: external_exports.number().int().min(0).max(1e3)
25693
+ });
25503
25694
  var SandboxStatus = external_exports.object({
25504
25695
  launchId: Text(64),
25505
25696
  phase: external_exports.enum(["booting", "provisioning", "ready", "failed"]),
@@ -25507,7 +25698,11 @@ var SandboxStatus = external_exports.object({
25507
25698
  updatedAt: Time,
25508
25699
  workspaceHost: Text(),
25509
25700
  guestWorkspace: Text(),
25510
- headless: external_exports.boolean()
25701
+ headless: external_exports.boolean(),
25702
+ /** The sandbox's IPv4 addresses (for network.forwardPorts; the host only uses ones on its Hyper-V network). */
25703
+ addresses: external_exports.array(external_exports.string().max(45)).max(8).optional(),
25704
+ /** A malformed progress is dropped, never the status (the phase still counts). */
25705
+ progress: BootProgress.optional().catch(void 0)
25511
25706
  });
25512
25707
  var Version = external_exports.strictObject({ spec: Text(128), source: Text(256) });
25513
25708
  var DatabasePlan = external_exports.strictObject({
@@ -25615,6 +25810,8 @@ var runPaths = (dataDir2) => {
25615
25810
  responses: path2.join(run2, "responses"),
25616
25811
  sessions: path2.join(run2, "sessions"),
25617
25812
  projects: path2.join(run2, "projects"),
25813
+ /** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
25814
+ audit: path2.join(run2, "audit"),
25618
25815
  request: file3("requests"),
25619
25816
  response: file3("responses"),
25620
25817
  session: file3("sessions"),
@@ -25674,7 +25871,7 @@ var now = () => (/* @__PURE__ */ new Date()).toISOString();
25674
25871
 
25675
25872
  // src/guest/setup/claude.ts
25676
25873
  import fs6 from "node:fs";
25677
- import os3 from "node:os";
25874
+ import os4 from "node:os";
25678
25875
  import path7 from "node:path";
25679
25876
 
25680
25877
  // src/shared/safe-remove.ts
@@ -25738,6 +25935,7 @@ var safeRemove = (target, root) => {
25738
25935
 
25739
25936
  // src/guest/env.ts
25740
25937
  import fs5 from "node:fs";
25938
+ import os3 from "node:os";
25741
25939
  import path6 from "node:path";
25742
25940
  import { spawnSync } from "node:child_process";
25743
25941
 
@@ -25765,7 +25963,8 @@ var SYSTEM = {
25765
25963
  ipconfig: () => system32("ipconfig.exe"),
25766
25964
  robocopy: () => system32("Robocopy.exe"),
25767
25965
  shutdown: () => system32("shutdown.exe"),
25768
- dism: () => system32("Dism.exe")
25966
+ dism: () => system32("Dism.exe"),
25967
+ msiexec: () => system32("msiexec.exe")
25769
25968
  };
25770
25969
 
25771
25970
  // src/shared/download.ts
@@ -25797,6 +25996,10 @@ var checksumRequired = false;
25797
25996
  var setChecksumRequired = (on) => {
25798
25997
  checksumRequired = on;
25799
25998
  };
25999
+ var downloadWatcher = null;
26000
+ var watchDownloads = (watcher) => {
26001
+ downloadWatcher = watcher;
26002
+ };
25800
26003
  var download = async (url2, destination, expected = null) => {
25801
26004
  const sums = typeof expected === "string" || expected === null ? { sha256: expected } : expected;
25802
26005
  if (checksumRequired && !sums.sha256?.trim() && !sums.sha512?.trim()) {
@@ -25809,8 +26012,25 @@ var download = async (url2, destination, expected = null) => {
25809
26012
  const want = sums[kind]?.trim().toLowerCase();
25810
26013
  return want ? [{ want, hash: crypto.createHash(kind) }] : [];
25811
26014
  });
26015
+ const size = Number(response.headers.get("content-length")) || 0;
26016
+ const report = size > 0 ? downloadWatcher?.() ?? null : null;
26017
+ let received = 0;
26018
+ let tenth = 0;
26019
+ let reportedAt = Date.now();
25812
26020
  const tap = new Transform({ transform(chunk, _encoding, done) {
25813
26021
  for (const c of checks) c.hash.update(chunk);
26022
+ if (report) {
26023
+ received += chunk.length;
26024
+ const now2 = Math.floor(received * 10 / size);
26025
+ if (now2 !== tenth || Date.now() - reportedAt > 5e3) {
26026
+ tenth = now2;
26027
+ reportedAt = Date.now();
26028
+ try {
26029
+ report(Math.min(1, received / size));
26030
+ } catch {
26031
+ }
26032
+ }
26033
+ }
25814
26034
  done(null, chunk);
25815
26035
  } });
25816
26036
  const partial2 = destination + ".part";
@@ -25823,10 +26043,10 @@ var download = async (url2, destination, expected = null) => {
25823
26043
  fs4.rmSync(partial2, { force: true });
25824
26044
  }
25825
26045
  };
25826
- var spawnAsync = (file3, args, options = {}) => new Promise((resolve, reject) => {
26046
+ var spawnAsync = (file3, args, options = {}) => new Promise((resolve2, reject) => {
25827
26047
  const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...options });
25828
26048
  child.once("error", reject);
25829
- child.once("close", (code) => resolve(code ?? -1));
26049
+ child.once("close", (code) => resolve2(code ?? -1));
25830
26050
  });
25831
26051
  var toAsset = (asset) => ({ url: asset.browser_download_url, name: asset.name, sha256: asset.digest?.startsWith("sha256:") ? asset.digest.slice(7) : null });
25832
26052
  var githubAsset = async (repo, pattern, searchOlder = false) => {
@@ -25958,15 +26178,25 @@ var mkdirp = (p) => {
25958
26178
  fs5.mkdirSync(p, { recursive: true });
25959
26179
  return p;
25960
26180
  };
25961
- var setSandboxStatus = (phase, message) => {
26181
+ var progress;
26182
+ var setSandboxStatus = (phase, message, update) => {
25962
26183
  try {
26184
+ if (update) progress = fitProgress({ step: 1, steps: 1, title: "", active: [], done: 0, total: 0, ...progress, ...update });
25963
26185
  writeJsonAtomicChecked(phase, message);
25964
26186
  } catch (e) {
25965
26187
  warn("Could not update sandbox status: " + errMsg(e));
25966
26188
  }
25967
26189
  };
26190
+ var fitProgress = (p) => ({
26191
+ ...p,
26192
+ title: p.title.slice(0, 120),
26193
+ done: Math.min(p.done, 1e3),
26194
+ total: Math.min(p.total, 1e3),
26195
+ active: p.active.slice(0, 8).map((a) => ({ name: a.name.slice(0, 64), ...a.percent === void 0 ? {} : { percent: Math.max(0, Math.min(100, Math.round(a.percent))) } }))
26196
+ });
26197
+ var ownAddresses = () => Object.values(os3.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
25968
26198
  var writeJsonAtomicChecked = (phase, message) => {
25969
- writeJsonAtomic(run.sandbox, { launchId: session.launchId, phase, message, updatedAt: now(), workspaceHost: session.workspaceHost, guestWorkspace: workspace, headless: session.headless });
26199
+ writeJsonAtomic(run.sandbox, { launchId: session.launchId, phase, message, updatedAt: now(), workspaceHost: session.workspaceHost, guestWorkspace: workspace, headless: session.headless, addresses: ownAddresses(), ...progress ? { progress } : {} });
25970
26200
  };
25971
26201
  var exec = (file3, args, options = {}) => {
25972
26202
  const result = spawnSync(file3, args, { stdio: "inherit", windowsHide: true, ...options });
@@ -26008,7 +26238,7 @@ var copyNode = (from, to) => {
26008
26238
  };
26009
26239
 
26010
26240
  // src/guest/setup/claude.ts
26011
- var claudeMemPaths = { store: path7.join(stateDir, "claude-mem"), local: path7.join(os3.homedir(), ".claude-mem") };
26241
+ var claudeMemPaths = { store: path7.join(stateDir, "claude-mem"), local: path7.join(os4.homedir(), ".claude-mem") };
26012
26242
  var claudeMemEnabled = () => session.claudeProfile.syncClaudeMem && !dryRun;
26013
26243
  var databaseFingerprint = (dir) => {
26014
26244
  const parts = [];
@@ -26026,11 +26256,39 @@ var databaseFingerprint = (dir) => {
26026
26256
  return parts.sort().join("|");
26027
26257
  };
26028
26258
  var lastSaved = null;
26259
+ var SQLITE_HEADER = "SQLite format 3\0";
26260
+ var looksLikeSqlite = (file3) => {
26261
+ if (!exists(file3)) return true;
26262
+ const fd = fs6.openSync(file3, "r");
26263
+ try {
26264
+ const head = Buffer.alloc(16);
26265
+ return fs6.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
26266
+ } finally {
26267
+ fs6.closeSync(fd);
26268
+ }
26269
+ };
26270
+ var MAX_BACKUPS = 3;
26271
+ var BACKUP_EVERY_MS = 6 * 3600 * 1e3;
26272
+ var keepBackup = (previous, dir) => {
26273
+ if (!exists(previous)) return;
26274
+ const backups = exists(dir) ? fs6.readdirSync(dir).filter((n) => /^\d{13}$/.test(n)).sort() : [];
26275
+ const newest = Number(backups[backups.length - 1] ?? 0);
26276
+ if (Date.now() - newest < BACKUP_EVERY_MS) {
26277
+ fs6.rmSync(previous, { recursive: true, force: true });
26278
+ return;
26279
+ }
26280
+ fs6.renameSync(previous, path7.join(mkdirp(dir), String(Date.now())));
26281
+ for (const old of [...backups, String(Date.now())].slice(0, -MAX_BACKUPS)) fs6.rmSync(path7.join(dir, old), { recursive: true, force: true });
26282
+ };
26029
26283
  var saveClaudeMem = () => {
26030
26284
  if (!claudeMemEnabled() || !exists(claudeMemPaths.local)) return;
26031
26285
  const { store: store2, local } = claudeMemPaths;
26032
26286
  const fingerprint = databaseFingerprint(local);
26033
26287
  if (fingerprint === lastSaved && exists(store2)) return;
26288
+ if (!looksLikeSqlite(path7.join(local, "claude-mem.db"))) {
26289
+ warn("claude-mem: the local database does not look valid, so it was not saved over the stored copy (" + local + ").");
26290
+ return;
26291
+ }
26034
26292
  const incoming = store2 + ".incoming";
26035
26293
  const previous = store2 + ".previous";
26036
26294
  fs6.rmSync(incoming, { recursive: true, force: true });
@@ -26043,7 +26301,7 @@ var saveClaudeMem = () => {
26043
26301
  if (exists(previous)) fs6.renameSync(previous, store2);
26044
26302
  throw e;
26045
26303
  }
26046
- fs6.rmSync(previous, { recursive: true, force: true });
26304
+ keepBackup(previous, store2 + ".backups");
26047
26305
  lastSaved = fingerprint;
26048
26306
  };
26049
26307
 
@@ -26051,12 +26309,13 @@ var saveClaudeMem = () => {
26051
26309
  import { spawn as spawn5 } from "node:child_process";
26052
26310
 
26053
26311
  // src/guest/daemon/project.ts
26054
- import fs30 from "node:fs";
26055
- import path44 from "node:path";
26312
+ import fs32 from "node:fs";
26313
+ import path45 from "node:path";
26056
26314
 
26057
26315
  // src/shared/projects.ts
26058
26316
  import path8 from "node:path";
26059
26317
  var PROJECTS_GUEST = "C:\\Projects";
26318
+ var WORKSPACES_GUEST = "C:\\Workspace";
26060
26319
  var norm2 = (p) => path8.win32.resolve(p).replace(/[\\/]+$/, "").toLowerCase();
26061
26320
  var isWithin = (parent, child) => {
26062
26321
  const a = norm2(parent);
@@ -26070,7 +26329,7 @@ var hubName = (hostDir, taken) => {
26070
26329
  for (let i = 2; ; i++) if (!used.has((base + "-" + i).toLowerCase())) return base + "-" + i;
26071
26330
  };
26072
26331
  var isBelow = (parent, child) => isWithin(parent, child) && norm2(parent) !== norm2(child);
26073
- var insideProjects = (guestDir, roots = [], projectsDir = PROJECTS_GUEST) => isBelow(projectsDir, guestDir) || roots.some((r) => isWithin(r, guestDir));
26332
+ var insideProjects = (guestDir, roots = [], projectsDir = PROJECTS_GUEST) => isBelow(projectsDir, guestDir) || isBelow(WORKSPACES_GUEST, guestDir) || roots.some((r) => isWithin(r, guestDir));
26074
26333
 
26075
26334
  // src/guest/daemon/state.ts
26076
26335
  import path9 from "node:path";
@@ -26294,6 +26553,9 @@ var runHooksAsync = async (stage, env, target) => {
26294
26553
  }
26295
26554
  };
26296
26555
 
26556
+ // src/guest/toolchains/index.ts
26557
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
26558
+
26297
26559
  // src/guest/toolchains/common.ts
26298
26560
  import fs10 from "node:fs";
26299
26561
  import path14 from "node:path";
@@ -26387,11 +26649,11 @@ var remembered = () => Object.fromEntries(Object.entries(readState(resolvedFile(
26387
26649
  var FRESH_MS = 24 * 60 * 60 * 1e3;
26388
26650
  var offline = false;
26389
26651
  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) => {
26652
+ var resolveCached = async (key, resolve2) => {
26391
26653
  const cached2 = remembered()[key];
26392
26654
  if (cached2 && (offline || !session.provisioning.refresh && Date.now() - cached2.at < FRESH_MS)) return cached2.value;
26393
26655
  try {
26394
- const value = await resolve();
26656
+ const value = await resolve2();
26395
26657
  fs10.mkdirSync(toolsDir, { recursive: true });
26396
26658
  writeJsonAtomic(resolvedFile(), { ...remembered(), [key]: { value, at: Date.now() } });
26397
26659
  return value;
@@ -26445,11 +26707,11 @@ var workspaceEntries = () => {
26445
26707
  return found;
26446
26708
  };
26447
26709
  var wanted = (setting, toolchain) => setting === "auto" ? projectUses(workspaceEntries(), MARKERS[toolchain] ?? []) : setting;
26448
- var versionFromFiles = (files, parse3 = (t) => specFromVersionFile(t)) => {
26710
+ var versionFromFiles = (files, parse5 = (t) => specFromVersionFile(t)) => {
26449
26711
  for (const name of files) {
26450
26712
  const file3 = path14.join(projectWorkspace(), name);
26451
26713
  if (!exists(file3)) continue;
26452
- const spec = parse3(fs10.readFileSync(file3, "utf8"), name);
26714
+ const spec = parse5(fs10.readFileSync(file3, "utf8"), name);
26453
26715
  if (spec) return { spec, source: name };
26454
26716
  }
26455
26717
  return null;
@@ -26472,16 +26734,280 @@ var installOnce = async (env, group, packages, install) => {
26472
26734
  };
26473
26735
 
26474
26736
  // src/guest/toolchains/plan.ts
26475
- import path43 from "node:path";
26737
+ import fs31 from "node:fs";
26738
+ import os8 from "node:os";
26739
+ import path44 from "node:path";
26740
+
26741
+ // src/guest/apps/index.ts
26742
+ import fs11 from "node:fs";
26743
+ import os5 from "node:os";
26744
+ import path15 from "node:path";
26745
+
26746
+ // src/guest/apps/resolvers.ts
26747
+ 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;
26748
+ var firstHash = (text) => /\b([0-9a-f]{64})\b/i.exec(text)?.[1].toLowerCase() ?? null;
26749
+ var stripV = (tag) => tag.replace(/^v/, "");
26750
+ var RESOLVERS = {
26751
+ sublime: async () => {
26752
+ const { latest_version: build } = await fetchJson("https://www.sublimetext.com/updates/4/stable_update_check");
26753
+ return { url: "https://download.sublimetext.com/sublime_text_build_" + build + "_x64.zip", fileName: "sublime_text_" + build + ".zip" };
26754
+ },
26755
+ pgadmin: async () => {
26756
+ const versions = (await fetchJson("https://www.postgresql.org/versions.json")).filter((v) => v.supported);
26757
+ const current = versions.find((v) => v.current) ?? versions[versions.length - 1];
26758
+ const exact = current.major + "." + current.latestMinor;
26759
+ return { url: "https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip", fileName: "postgresql-" + exact + ".zip", members: ["pgsql/pgAdmin 4"] };
26760
+ },
26761
+ everything: async () => {
26762
+ const page = await fetchText("https://www.voidtools.com/downloads/");
26763
+ const version2 = /Everything-([\d.]+)\.x64\.zip/.exec(page)?.[1];
26764
+ if (!version2) throw new Error("could not find the Everything download on voidtools.com");
26765
+ const file3 = "Everything-" + version2 + ".x64.zip";
26766
+ const sums = await fetchText("https://www.voidtools.com/Everything-" + version2 + ".sha256").catch(() => "");
26767
+ return { url: "https://www.voidtools.com/" + file3, fileName: file3, sha256: sumFor(sums, file3) };
26768
+ },
26769
+ chrome: async () => {
26770
+ const data = await fetchJson("https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json");
26771
+ const hit = data.channels.Stable.downloads.chrome.find((d) => d.platform === "win64");
26772
+ if (!hit) throw new Error("no win64 Chrome for Testing build listed");
26773
+ return { url: hit.url, fileName: "chrome-win64.zip" };
26774
+ },
26775
+ firefox: async () => {
26776
+ const { LATEST_FIREFOX_VERSION: v } = await fetchJson("https://product-details.mozilla.org/1.0/firefox_versions.json");
26777
+ const base = "https://archive.mozilla.org/pub/firefox/releases/" + v + "/";
26778
+ const sums = await fetchText(base + "SHA256SUMS");
26779
+ 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") };
26780
+ },
26781
+ blender: async () => {
26782
+ const releases = await fetchText("https://download.blender.org/release/");
26783
+ 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();
26784
+ if (!series) throw new Error("could not list Blender releases");
26785
+ const folder = "https://download.blender.org/release/Blender" + series[0] + "." + series[1] + "/";
26786
+ const listing = await fetchText(folder);
26787
+ const files = [...listing.matchAll(/href="(blender-([\d.]+)-windows-x64\.zip)"/g)].map((m) => ({ file: m[1], v: m[2].split(".").map(Number) }));
26788
+ const latest = files.sort((a, b) => a.v[2] - b.v[2]).pop();
26789
+ if (!latest) throw new Error("no Windows build in " + folder);
26790
+ const sums = await fetchText(folder + "blender-" + latest.v.join(".") + ".sha256").catch(() => "");
26791
+ return { url: folder + latest.file, fileName: latest.file, sha256: sumFor(sums, latest.file) };
26792
+ },
26793
+ kubectl: async () => {
26794
+ const v = (await fetchText("https://dl.k8s.io/release/stable.txt")).trim();
26795
+ const url2 = "https://dl.k8s.io/release/" + v + "/bin/windows/amd64/kubectl.exe";
26796
+ return { url: url2, fileName: "kubectl.exe", sha256: firstHash(await fetchText(url2 + ".sha256")) };
26797
+ },
26798
+ helm: async () => {
26799
+ const v = await latestGithubTag("helm/helm");
26800
+ const url2 = "https://get.helm.sh/helm-" + v + "-windows-amd64.zip";
26801
+ return { url: url2, fileName: "helm-" + v + ".zip", sha256: firstHash(await fetchText(url2 + ".sha256sum")) };
26802
+ },
26803
+ terraform: async () => {
26804
+ const { current_version: v } = await fetchJson("https://checkpoint-api.hashicorp.com/v1/check/terraform");
26805
+ const base = "https://releases.hashicorp.com/terraform/" + v + "/";
26806
+ const file3 = "terraform_" + v + "_windows_amd64.zip";
26807
+ return { url: base + file3, fileName: file3, sha256: sumFor(await fetchText(base + "terraform_" + v + "_SHA256SUMS"), file3) };
26808
+ },
26809
+ mitmproxy: async () => {
26810
+ const v = stripV(await latestGithubTag("mitmproxy/mitmproxy"));
26811
+ return { url: "https://downloads.mitmproxy.org/" + v + "/mitmproxy-" + v + "-windows-x86_64.zip", fileName: "mitmproxy-" + v + ".zip" };
26812
+ },
26813
+ sqlite: async () => {
26814
+ const page = await fetchText("https://sqlite.org/download.html");
26815
+ const file3 = /PRODUCT,[^,]+,(\d{4}\/sqlite-tools-win-x64-\d+\.zip),/.exec(page)?.[1];
26816
+ if (!file3) throw new Error("could not find the sqlite tools download on sqlite.org");
26817
+ return { url: "https://sqlite.org/" + file3, fileName: file3.split("/")[1] };
26818
+ },
26819
+ "7zip": async () => {
26820
+ const asset = await githubAsset("ip7z/7zip", /^7z\d+-x64\.exe$/);
26821
+ return { url: asset.url, fileName: asset.name, sha256: asset.sha256 };
26822
+ }
26823
+ };
26824
+
26825
+ // src/guest/apps/index.ts
26826
+ var MARKER = ".agent-sandbox-app";
26827
+ var PARALLEL = 3;
26828
+ var sevenZip = () => tool("apps", "7zip", "7z.exe");
26829
+ var resolve = async (entry) => {
26830
+ const s = entry.source;
26831
+ if ("github" in s) {
26832
+ const a = await githubAsset(s.github, new RegExp(s.asset), true);
26833
+ return { url: a.url, fileName: a.name, sha256: a.sha256 };
26834
+ }
26835
+ if ("url" in s) {
26836
+ const name = decodeURIComponent(new URL(s.url).pathname.split("/").pop() || entry.id);
26837
+ return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip" };
26838
+ }
26839
+ if ("resolve" in s && RESOLVERS[s.resolve]) return RESOLVERS[s.resolve]();
26840
+ throw new Error("no download source for " + entry.name);
26841
+ };
26842
+ var findExe = (root, exe) => {
26843
+ const match = exeMatcher(exe);
26844
+ let queue = [root];
26845
+ let seen = 0;
26846
+ for (let depth = 0; depth < 7 && queue.length; depth++) {
26847
+ const next = [];
26848
+ for (const dir of queue) {
26849
+ let entries2;
26850
+ try {
26851
+ entries2 = fs11.readdirSync(dir, { withFileTypes: true });
26852
+ } catch {
26853
+ continue;
26854
+ }
26855
+ const hit = entries2.find((e) => e.isFile() && match(e.name));
26856
+ if (hit) return path15.join(dir, hit.name);
26857
+ next.push(...entries2.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path15.join(dir, e.name)));
26858
+ if ((seen += entries2.length) > 5e4) return null;
26859
+ }
26860
+ queue = next;
26861
+ }
26862
+ return null;
26863
+ };
26864
+ var installApp = async (entry, dest) => {
26865
+ const work = stagingFolder(dest);
26866
+ const out = path15.join(work, "out");
26867
+ try {
26868
+ if ("npm" in entry.source) {
26869
+ const npmCli = path15.join(path15.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
26870
+ log("Installing " + entry.name + " (npm) ...");
26871
+ await execAsync(process.execPath, [npmCli, "install", "--prefix", mkdirp(out), "--no-audit", "--no-fund", "--loglevel=error", entry.source.npm]);
26872
+ } else {
26873
+ const d = await resolve(entry);
26874
+ log("Downloading " + entry.name + " (" + d.fileName + ", ~" + entry.size + " once) ...");
26875
+ const file3 = path15.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
26876
+ await download(d.url, file3, { sha256: d.sha256 ?? null });
26877
+ await unpack(entry, file3, out, d);
26878
+ }
26879
+ fs11.writeFileSync(path15.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
26880
+ moveIntoPlace(out, dest);
26881
+ } finally {
26882
+ safeRemove(work, path15.dirname(work));
26883
+ }
26884
+ };
26885
+ var unpack = async (entry, file3, out, d) => {
26886
+ if (entry.id === "7zip") {
26887
+ const sevenZr = path15.join(path15.dirname(file3), "7zr.exe");
26888
+ const zr = await githubAsset("ip7z/7zip", /^7zr\.exe$/);
26889
+ await download(zr.url, sevenZr, zr.sha256);
26890
+ await execAsync(sevenZr, ["x", "-y", "-o" + out, file3], { stdio: "ignore" });
26891
+ return;
26892
+ }
26893
+ switch (entry.unpack ?? "archive") {
26894
+ case "file": {
26895
+ mkdirp(out);
26896
+ fs11.renameSync(file3, path15.join(out, /^\//.test(entry.exe) ? path15.basename(file3) : entry.exe));
26897
+ return;
26898
+ }
26899
+ case "nsis": {
26900
+ if (!exists(sevenZip())) throw new Error("7-Zip is needed to unpack " + entry.name + " and could not be installed");
26901
+ const raw = path15.join(path15.dirname(out), "raw");
26902
+ await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
26903
+ const inner = findExe(raw, "/^app-64\\.7z$/");
26904
+ if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
26905
+ else fs11.renameSync(raw, out);
26906
+ return;
26907
+ }
26908
+ case "msi": {
26909
+ mkdirp(out);
26910
+ await execAsync(SYSTEM.msiexec(), ["/a", file3, "/qn", "TARGETDIR=" + out], { stdio: "ignore" });
26911
+ return;
26912
+ }
26913
+ default:
26914
+ await extractArchive(file3, out, d.members);
26915
+ }
26916
+ };
26917
+ var afterInstall = async (entry, exe) => {
26918
+ const dir = path15.dirname(exe);
26919
+ if (entry.needs?.includes("mesa")) {
26920
+ const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
26921
+ for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
26922
+ if (exists(path15.join(mesa, dll)) && !exists(path15.join(dir, dll))) fs11.copyFileSync(path15.join(mesa, dll), path15.join(dir, dll));
26923
+ }
26924
+ }
26925
+ if (entry.id === "godot" && !exists(path15.join(dir, "._sc_"))) fs11.writeFileSync(path15.join(dir, "._sc_"), "");
26926
+ if (entry.id === "sublime") mkdirp(path15.join(dir, "Data"));
26927
+ if (entry.id === "sysinternals") {
26928
+ for (const name of ["Process Explorer", "Process Monitor", "Autoruns", "TCPView", "PsExec", "PsList", "PsKill", "Handle", "ListDLLs", "Sigcheck", "Strings", "VMMap", "RAMMap", "DebugView", "Disk2vhd", "Du", "ZoomIt"]) {
26929
+ await execAsync(SYSTEM.reg(), ["add", "HKCU\\Software\\Sysinternals\\" + name, "/v", "EulaAccepted", "/t", "REG_DWORD", "/d", "1", "/f"], { stdio: "ignore" }).catch(() => void 0);
26930
+ }
26931
+ }
26932
+ };
26933
+ var shortcuts = (apps) => {
26934
+ if (!apps.length) return;
26935
+ const q = (s) => "'" + s.replace(/'/g, "''") + "'";
26936
+ const desktop = path15.join(os5.homedir(), "Desktop");
26937
+ const start = path15.join(process.env.APPDATA ?? path15.join(os5.homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Sandbox apps");
26938
+ const lines = ["$w = New-Object -ComObject WScript.Shell", "New-Item -ItemType Directory -Force -Path " + q(start) + " | Out-Null"];
26939
+ for (const app of apps) {
26940
+ for (const folder of [desktop, start]) {
26941
+ const name = app.name.replace(/[\\/:*?"<>|]/g, "");
26942
+ 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()");
26943
+ }
26944
+ }
26945
+ powershell(lines.join("\n"));
26946
+ };
26947
+ var setupApps = async (env, apps, o) => {
26948
+ const { entries: entries2, skipped } = appsToInstall(apps, o.gitAccess);
26949
+ for (const s of skipped) env.summary.push("app skipped: " + s);
26950
+ if (dryRun) {
26951
+ log("(dry run) would install apps: " + entries2.map((e) => e.name).join(", "));
26952
+ return;
26953
+ }
26954
+ const gui = [];
26955
+ const installed2 = [];
26956
+ const one = async (entry) => {
26957
+ try {
26958
+ const dest = tool("apps", ...entry.id.split("/"));
26959
+ if (!exists(path15.join(dest, MARKER)) || o.refresh) await installApp(entry, dest);
26960
+ const exe = findExe(dest, entry.exe);
26961
+ if (!exe) throw new Error(entry.exe + " not found in the download");
26962
+ await afterInstall(entry, exe);
26963
+ if (entry.cli || entry.id === "sysinternals") env.prepend.push(path15.dirname(exe));
26964
+ if (!entry.cli) gui.push({ name: entry.name, exe });
26965
+ installed2.push(entry.name);
26966
+ } catch (e) {
26967
+ warn(entry.name + " could not be installed and is skipped; the other apps are not affected. Reason: " + errMsg(e));
26968
+ env.summary.push(entry.name + ": FAILED");
26969
+ }
26970
+ };
26971
+ const [first, rest] = entries2[0]?.id === "7zip" ? [[entries2[0]], entries2.slice(1)] : [[], entries2];
26972
+ for (const e of first) await one(e);
26973
+ const queue = [...rest];
26974
+ await Promise.all(Array.from({ length: Math.min(PARALLEL, queue.length) }, async () => {
26975
+ for (let e = queue.shift(); e; e = queue.shift()) await one(e);
26976
+ }));
26977
+ try {
26978
+ shortcuts(gui);
26979
+ } catch (e) {
26980
+ warn("App shortcuts could not be created: " + errMsg(e));
26981
+ }
26982
+ if (installed2.length) env.summary.push("apps: " + installed2.join(", ") + " (shortcuts on the desktop and in Start > Sandbox apps)");
26983
+ };
26984
+
26985
+ // src/guest/helpers.ts
26986
+ import fs12 from "node:fs";
26987
+ import os6 from "node:os";
26988
+ import path16 from "node:path";
26989
+ import crypto2 from "node:crypto";
26990
+ import { spawnSync as spawnSync3 } from "node:child_process";
26991
+ var CSC = path16.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
26992
+ var sourceHash = (name) => crypto2.createHash("sha256").update(fs12.readFileSync(path16.join(launchDir, "sandbox", name + ".cs"))).digest("hex").slice(0, 12);
26993
+ var ensureCompiled = (name) => {
26994
+ const exe = path16.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
26995
+ if (exists(exe)) return exe;
26996
+ if (!exists(CSC)) throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
26997
+ mkdirp(path16.dirname(exe));
26998
+ const result = spawnSync3(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, path16.join(launchDir, "sandbox", name + ".cs")], { encoding: "utf8", windowsHide: true });
26999
+ if (result.status !== 0) throw new Error("Compiling " + name + " failed: " + ((result.stdout ?? "") + (result.stderr ?? "")).trim().slice(0, 1500));
27000
+ return exe;
27001
+ };
26476
27002
 
26477
27003
  // src/guest/toolchains/databases/dynamodb.ts
26478
- import fs13 from "node:fs";
26479
- import path17 from "node:path";
27004
+ import fs15 from "node:fs";
27005
+ import path19 from "node:path";
26480
27006
  import { spawn as spawn3 } from "node:child_process";
26481
27007
 
26482
27008
  // src/guest/toolchains/java.ts
26483
- import fs11 from "node:fs";
26484
- import path15 from "node:path";
27009
+ import fs13 from "node:fs";
27010
+ import path17 from "node:path";
26485
27011
  var ADOPTIUM = "https://api.adoptium.net/v3";
26486
27012
  var MAVEN = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/";
26487
27013
  var temurin = async (major) => {
@@ -26500,19 +27026,19 @@ var setupJdk = async (env, config2) => {
26500
27026
  const { major, source } = await javaMajor(config2);
26501
27027
  const release = await resolveCached("java:" + major, async () => (await temurin(major)).release_name);
26502
27028
  const home = tool("java", release.replace(/[^A-Za-z0-9.-]/g, "_"));
26503
- if (!exists(path15.join(home, "bin", "java.exe"))) {
27029
+ if (!exists(path17.join(home, "bin", "java.exe"))) {
26504
27030
  const asset = await temurin(major);
26505
27031
  log("Downloading Java " + release + " (JDK, ~200 MB once) ...");
26506
27032
  await installArchive(asset.binary.package.link, home, { sha256: asset.binary.package.checksum, locate: "release", fileName: asset.binary.package.name });
26507
27033
  }
26508
27034
  env.vars.JAVA_HOME = home;
26509
- env.prepend.push(path15.join(home, "bin"));
27035
+ env.prepend.push(path17.join(home, "bin"));
26510
27036
  env.summary.push("java: " + release + " (Temurin, from " + source + ")");
26511
27037
  };
26512
27038
  var ensureJdk = async () => {
26513
27039
  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]);
27040
+ 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 })) : [];
27041
+ if (installed2.length) return path17.join(root, installed2[0]);
26516
27042
  const scratch = emptyEnv();
26517
27043
  await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
26518
27044
  return scratch.vars.JAVA_HOME;
@@ -26523,29 +27049,29 @@ var setupMaven = async (env) => {
26523
27049
  return pickPackageVersion(versions, "3") ?? Promise.reject(new Error("No Maven 3 release found"));
26524
27050
  });
26525
27051
  const home = tool("maven", version2);
26526
- if (!exists(path15.join(home, "bin", "mvn.cmd"))) {
27052
+ if (!exists(path17.join(home, "bin", "mvn.cmd"))) {
26527
27053
  const url2 = MAVEN + version2 + "/apache-maven-" + version2 + "-bin.zip";
26528
27054
  log("Downloading Maven " + version2 + " (~10 MB once) ...");
26529
27055
  await installArchive(url2, home, { sha512: (await fetchText(url2 + ".sha512")).trim().split(/\s+/)[0], locate: "LICENSE" });
26530
27056
  }
26531
27057
  const repo = tool("maven-repository");
26532
27058
  Object.assign(env.vars, { MAVEN_HOME: home, M2_HOME: home, MAVEN_OPTS: "-Dmaven.repo.local=" + repo });
26533
- env.prepend.push(path15.join(home, "bin"));
27059
+ env.prepend.push(path17.join(home, "bin"));
26534
27060
  env.summary.push("maven: " + version2);
26535
27061
  };
26536
27062
  var setupGradle = async (env) => {
26537
27063
  const current = await fetchJson("https://services.gradle.org/versions/current").catch(() => null);
26538
27064
  const version2 = await resolveCached("gradle", async () => current?.version ?? Promise.reject(new Error("Gradle version lookup failed")));
26539
27065
  const home = tool("gradle", version2);
26540
- if (!exists(path15.join(home, "bin", "gradle.bat"))) {
27066
+ if (!exists(path17.join(home, "bin", "gradle.bat"))) {
26541
27067
  if (!current || current.version !== version2) throw new Error("Gradle " + version2 + " is not installed and cannot be downloaded right now");
26542
27068
  log("Downloading Gradle " + version2 + " (~130 MB once) ...");
26543
27069
  await installArchive(current.downloadUrl, home, { sha256: (await fetchText(current.checksumUrl)).trim(), locate: "LICENSE", fileName: "gradle-" + version2 + ".zip" });
26544
27070
  }
26545
27071
  const userHome = tool("gradle-home");
26546
- fs11.mkdirSync(userHome, { recursive: true });
27072
+ fs13.mkdirSync(userHome, { recursive: true });
26547
27073
  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"));
27074
+ env.prepend.push(path17.join(home, "bin"));
26549
27075
  env.summary.push("gradle: " + version2);
26550
27076
  };
26551
27077
  var setupJava = async (env, config2) => {
@@ -26564,20 +27090,20 @@ var setupJava = async (env, config2) => {
26564
27090
 
26565
27091
  // src/guest/ports.ts
26566
27092
  import net from "node:net";
26567
- var freePort = () => new Promise((resolve, reject) => {
27093
+ var freePort = () => new Promise((resolve2, reject) => {
26568
27094
  const server = net.createServer();
26569
27095
  server.once("error", reject);
26570
27096
  server.listen(0, "127.0.0.1", () => {
26571
27097
  const { port } = server.address();
26572
- server.close(() => resolve(port));
27098
+ server.close(() => resolve2(port));
26573
27099
  });
26574
27100
  });
26575
- var portOpen = (port) => new Promise((resolve) => {
27101
+ var portOpen = (port) => new Promise((resolve2) => {
26576
27102
  const socket = net.connect({ host: "127.0.0.1", port }, () => {
26577
27103
  socket.destroy();
26578
- resolve(true);
27104
+ resolve2(true);
26579
27105
  });
26580
- socket.once("error", () => resolve(false));
27106
+ socket.once("error", () => resolve2(false));
26581
27107
  });
26582
27108
  var waitForPort = async (port, seconds) => {
26583
27109
  for (const end = Date.now() + seconds * 1e3; Date.now() < end; ) {
@@ -26588,26 +27114,26 @@ var waitForPort = async (port, seconds) => {
26588
27114
  };
26589
27115
 
26590
27116
  // src/guest/toolchains/databases/server.ts
26591
- import fs12 from "node:fs";
26592
- import path16 from "node:path";
27117
+ import fs14 from "node:fs";
27118
+ import path18 from "node:path";
26593
27119
  import { spawn as spawn2 } from "node:child_process";
26594
- var dataFor = (name) => path16.join(dataDir, "databases", name);
27120
+ var dataFor = (name) => path18.join(dataDir, "databases", name);
26595
27121
  var startServer = async (name, exe, args, port) => {
26596
27122
  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");
27123
+ const logFile2 = path18.join(logsDir, name + ".log");
27124
+ const out = fs14.openSync(logFile2, "a");
26599
27125
  spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
26600
- fs12.closeSync(out);
27126
+ fs14.closeSync(out);
26601
27127
  if (!await waitForPort(port, 60)) throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
26602
27128
  };
26603
27129
  var clearStaleLocks = async (dir, files, port) => {
26604
27130
  if (await portOpen(port)) return;
26605
- for (const f of files) fs12.rmSync(path16.join(dir, f), { force: true });
27131
+ for (const f of files) fs14.rmSync(path18.join(dir, f), { force: true });
26606
27132
  };
26607
27133
  var createOnce = async (data, marker, create) => {
26608
- if (exists(path16.join(data, marker))) return;
27134
+ if (exists(path18.join(data, marker))) return;
26609
27135
  const existed = exists(data);
26610
- mkdirp(path16.dirname(data));
27136
+ mkdirp(path18.dirname(data));
26611
27137
  try {
26612
27138
  await create();
26613
27139
  } catch (e) {
@@ -26624,40 +27150,40 @@ var createOnce = async (data, marker, create) => {
26624
27150
  // src/guest/toolchains/databases/dynamodb.ts
26625
27151
  var DYNAMO_ZIP = "https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_latest.zip";
26626
27152
  var setupDynamo = async (env, plan2) => {
26627
- const java = path17.join(await ensureJdk(), "bin", "java.exe");
27153
+ const java = path19.join(await ensureJdk(), "bin", "java.exe");
26628
27154
  const home = tool("dynamodb-local");
26629
- if (!exists(path17.join(home, "DynamoDBLocal.jar"))) {
27155
+ if (!exists(path19.join(home, "DynamoDBLocal.jar"))) {
26630
27156
  log("Downloading DynamoDB Local (~60 MB once) ...");
26631
27157
  const sha256 = (await fetchText(DYNAMO_ZIP + ".sha256")).trim().split(/\s+/)[0];
26632
27158
  await installArchive(DYNAMO_ZIP, home, { sha256, locate: "DynamoDBLocal.jar", fileName: "dynamodb_local.zip" });
26633
27159
  }
26634
27160
  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);
27161
+ 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
27162
  const endpoint = "http://localhost:" + plan2.port;
26637
27163
  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
27164
  Object.assign(env.vars, aws);
26639
27165
  env.summary.push("dynamodb (DynamoDB Local): " + endpoint + " (AWS SDKs use it automatically via AWS_ENDPOINT_URL_DYNAMODB; dummy credentials)");
26640
27166
  if (!plan2.adminPort) return;
26641
27167
  const prefix = tool("dynamodb-admin");
26642
- const script = path17.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
27168
+ const script = path19.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
26643
27169
  if (!exists(script)) {
26644
27170
  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");
27171
+ const npmCli = path19.join(path19.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
26646
27172
  await execAsync(process.execPath, [npmCli, "install", "--global", "--prefix", prefix, "dynamodb-admin", "--no-fund", "--no-audit"], { stdio: "ignore" });
26647
27173
  }
26648
27174
  if (await portOpen(plan2.adminPort)) {
26649
27175
  env.summary.push("dynamodb-admin: NOT started, port " + plan2.adminPort + " is in use (change databases.dynamodb.adminPort)");
26650
27176
  return;
26651
27177
  }
26652
- const out = fs13.openSync(path17.join(logsDir, "dynamodb-admin.log"), "a");
27178
+ const out = fs15.openSync(path19.join(logsDir, "dynamodb-admin.log"), "a");
26653
27179
  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"));
27180
+ fs15.closeSync(out);
27181
+ if (!await waitForPort(plan2.adminPort, 30)) throw new Error("dynamodb-admin did not start; see " + path19.join(logsDir, "dynamodb-admin.log"));
26656
27182
  env.summary.push("dynamodb-admin: http://localhost:" + plan2.adminPort + " (browse and edit tables in the sandbox's browser)");
26657
27183
  };
26658
27184
 
26659
27185
  // src/guest/toolchains/databases/mongodb.ts
26660
- import path18 from "node:path";
27186
+ import path20 from "node:path";
26661
27187
  var setupMongo = async (env, plan2) => {
26662
27188
  const find = async () => {
26663
27189
  const { versions } = await fetchJson("https://downloads.mongodb.org/full.json");
@@ -26668,24 +27194,24 @@ var setupMongo = async (env, plan2) => {
26668
27194
  };
26669
27195
  const version2 = await resolveCached("mongodb:" + plan2.version, async () => (await find()).version);
26670
27196
  const home = tool("mongodb", version2);
26671
- if (!exists(path18.join(home, "bin", "mongod.exe"))) {
27197
+ if (!exists(path20.join(home, "bin", "mongod.exe"))) {
26672
27198
  const { archive } = await find();
26673
27199
  log("Downloading MongoDB " + version2 + " (~400 MB once) ...");
26674
27200
  await installArchive(archive.url, home, { sha256: archive.sha256, locate: "mongod.exe", up: 1 });
26675
27201
  }
26676
27202
  const shell = tool("mongosh");
26677
- if (!exists(path18.join(shell, "mongosh.exe"))) {
27203
+ if (!exists(path20.join(shell, "mongosh.exe"))) {
26678
27204
  await installFromGithub("mongodb-js/mongosh", /^mongosh-[\d.]+-win32-x64\.zip$/, { dest: shell, what: "mongosh, the MongoDB shell (~50 MB once)", locate: "mongosh.exe" });
26679
27205
  }
26680
27206
  const data = mkdirp(dataFor("mongodb"));
26681
27207
  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);
27208
+ await startServer("mongodb", path20.join(home, "bin", "mongod.exe"), ["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)], plan2.port);
27209
+ env.prepend.push(path20.join(home, "bin"), shell);
26684
27210
  env.summary.push("mongodb " + version2 + ": mongodb://127.0.0.1:" + plan2.port + " (mongosh on PATH)");
26685
27211
  };
26686
27212
 
26687
27213
  // src/guest/toolchains/databases/mysql.ts
26688
- import path19 from "node:path";
27214
+ import path21 from "node:path";
26689
27215
  var MARIA = "https://downloads.mariadb.org/rest-api/mariadb/";
26690
27216
  var setupMysql = async (env, plan2) => {
26691
27217
  const series = await resolveCached("mariadb:" + plan2.version, async () => {
@@ -26701,8 +27227,8 @@ var setupMysql = async (env, plan2) => {
26701
27227
  };
26702
27228
  const version2 = await resolveCached("mariadb-version:" + series, async () => (await latest()).version);
26703
27229
  const home = tool("mariadb", version2);
26704
- const bin = path19.join(home, "bin");
26705
- if (!exists(path19.join(bin, "mariadbd.exe"))) {
27230
+ const bin = path21.join(home, "bin");
27231
+ if (!exists(path21.join(bin, "mariadbd.exe"))) {
26706
27232
  const { zip } = await latest();
26707
27233
  log("Downloading MariaDB " + version2 + " (~90 MB once) ...");
26708
27234
  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 +27236,16 @@ var setupMysql = async (env, plan2) => {
26710
27236
  const data = dataFor("mariadb");
26711
27237
  await createOnce(data, "mysql", async () => {
26712
27238
  log("Creating the MariaDB database (first start) ...");
26713
- await execAsync(path19.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], { stdio: "ignore" });
27239
+ await execAsync(path21.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], { stdio: "ignore" });
26714
27240
  });
26715
- await startServer("mysql", path19.join(bin, "mariadbd.exe"), ["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"], plan2.port);
27241
+ await startServer("mysql", path21.join(bin, "mariadbd.exe"), ["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"], plan2.port);
26716
27242
  Object.assign(env.vars, { MYSQL_HOST: "127.0.0.1", MYSQL_TCP_PORT: String(plan2.port) });
26717
27243
  env.prepend.push(bin);
26718
27244
  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
27245
  };
26720
27246
 
26721
27247
  // src/guest/toolchains/databases/postgres.ts
26722
- import path20 from "node:path";
27248
+ import path22 from "node:path";
26723
27249
  var postgresData = (version2) => dataFor("postgres-" + version2.split(".")[0]);
26724
27250
  var setupPostgres = async (env, plan2) => {
26725
27251
  const exact = await resolveCached("postgres:" + plan2.version, async () => {
@@ -26728,8 +27254,8 @@ var setupPostgres = async (env, plan2) => {
26728
27254
  return hit ? hit.major + "." + hit.latestMinor : Promise.reject(new Error("No supported PostgreSQL " + plan2.version));
26729
27255
  });
26730
27256
  const home = tool("postgres", exact);
26731
- const bin = path20.join(home, "bin");
26732
- if (!exists(path20.join(bin, "pg_ctl.exe"))) {
27257
+ const bin = path22.join(home, "bin");
27258
+ if (!exists(path22.join(bin, "pg_ctl.exe"))) {
26733
27259
  log("Downloading PostgreSQL " + exact + " (~330 MB once) ...");
26734
27260
  await installArchive("https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip", home, {
26735
27261
  locate: "pg_ctl.exe",
@@ -26741,25 +27267,25 @@ var setupPostgres = async (env, plan2) => {
26741
27267
  const data = postgresData(exact);
26742
27268
  await createOnce(data, "PG_VERSION", async () => {
26743
27269
  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" });
27270
+ await execAsync(path22.join(bin, "initdb.exe"), ["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"], { stdio: "ignore" });
26745
27271
  });
26746
27272
  if (await portOpen(plan2.port)) throw new Error("port " + plan2.port + " is already in use (change databases.postgres.port)");
26747
27273
  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" });
27274
+ 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
27275
  Object.assign(env.vars, { PGHOST: "localhost", PGPORT: String(plan2.port), PGUSER: "postgres" });
26750
27276
  env.prepend.push(bin);
26751
27277
  env.summary.push("postgres " + exact + ": localhost:" + plan2.port + ", user postgres, no password (postgres://postgres@localhost:" + plan2.port + "/postgres)");
26752
27278
  };
26753
27279
 
26754
27280
  // src/guest/toolchains/databases/redis.ts
26755
- import path21 from "node:path";
27281
+ import path23 from "node:path";
26756
27282
  var setupRedis = async (env, plan2) => {
26757
27283
  const home = tool("redis");
26758
- if (!exists(path21.join(home, "redis-server.exe"))) {
27284
+ if (!exists(path23.join(home, "redis-server.exe"))) {
26759
27285
  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
27286
  }
26761
27287
  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);
27288
+ 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
27289
  env.prepend.push(home);
26764
27290
  env.summary.push("redis: redis://127.0.0.1:" + plan2.port + " (redis-cli on PATH)");
26765
27291
  };
@@ -26784,28 +27310,8 @@ var setupDatabase = async (env, plan2) => {
26784
27310
  };
26785
27311
 
26786
27312
  // 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
27313
+ import fs16 from "node:fs";
27314
+ import path24 from "node:path";
26809
27315
  var BLOCKED_HOOKS = ["pre-commit", "commit-msg", "pre-merge-commit", "pre-push", "pre-rebase", "pre-applypatch", "applypatch-msg"];
26810
27316
  var posix = (p) => p.replace(/\\/g, "/");
26811
27317
  var installPortableGit = async (root) => {
@@ -26816,50 +27322,50 @@ var installPortableGit = async (root) => {
26816
27322
  await download(asset.url, sfx, asset.sha256);
26817
27323
  await execAsync(sfx, ["-o" + root, "-y"], { stdio: "ignore" });
26818
27324
  } finally {
26819
- fs15.rmSync(sfx, { force: true });
27325
+ fs16.rmSync(sfx, { force: true });
26820
27326
  }
26821
27327
  };
26822
27328
  var installGuard = (env, access, realGit) => {
26823
27329
  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")))) {
27330
+ const guard = path24.join(launchDir, "runtime", "gitguard.js");
27331
+ if (duringSession() && (exists(path24.join(dir, "git.exe")) || exists(path24.join(dir, "git.cmd")))) {
26826
27332
  } else try {
26827
- fs15.copyFileSync(ensureCompiled("gitshim"), path23.join(dir, "git.exe"));
26828
- fs15.rmSync(path23.join(dir, "git.cmd"), { force: true });
27333
+ fs16.copyFileSync(ensureCompiled("gitshim"), path24.join(dir, "git.exe"));
27334
+ fs16.rmSync(path24.join(dir, "git.cmd"), { force: true });
26829
27335
  } catch (e) {
26830
27336
  warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
26831
- fs15.writeFileSync(path23.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
27337
+ fs16.writeFileSync(path24.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
26832
27338
  }
26833
- fs15.writeFileSync(path23.join(dir, "bashenv.sh"), 'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n');
27339
+ fs16.writeFileSync(path24.join(dir, "bashenv.sh"), 'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n');
26834
27340
  env.prepend.unshift(dir);
26835
27341
  Object.assign(env.vars, {
26836
27342
  AGENT_GIT_ACCESS: access,
26837
27343
  AGENT_REAL_GIT: access === "readonly" ? realGit : "",
26838
27344
  AGENT_GUARD_NODE: process.execPath,
26839
27345
  AGENT_GUARD_SCRIPT: guard,
26840
- BASH_ENV: posix(path23.join(dir, "bashenv.sh"))
27346
+ BASH_ENV: posix(path24.join(dir, "bashenv.sh"))
26841
27347
  });
26842
27348
  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');
27349
+ const hooks = mkdirp(path24.join(dir, "hooks"));
27350
+ 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
27351
  Object.assign(env.vars, { GIT_CONFIG_COUNT: "1", GIT_CONFIG_KEY_0: "core.hooksPath", GIT_CONFIG_VALUE_0: posix(hooks) });
26846
27352
  } else {
26847
- env.vars.GIT_DIR = path23.join(dataDir, "git-disabled");
27353
+ env.vars.GIT_DIR = path24.join(dataDir, "git-disabled");
26848
27354
  }
26849
27355
  };
26850
27356
  var pointAtOwnCertificates = (root) => {
26851
- const config2 = path23.join(root, "etc", "gitconfig");
26852
- const bundle = path23.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
27357
+ const config2 = path24.join(root, "etc", "gitconfig");
27358
+ const bundle = path24.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
26853
27359
  if (!exists(config2) || !exists(bundle)) return;
26854
- const text = fs15.readFileSync(config2, "utf8");
27360
+ const text = fs16.readFileSync(config2, "utf8");
26855
27361
  const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key) => key + posix(bundle));
26856
- if (fixed !== text) fs15.writeFileSync(config2, fixed);
27362
+ if (fixed !== text) fs16.writeFileSync(config2, fixed);
26857
27363
  };
26858
27364
  var setupGit = async (env, hostCopy, refresh, access) => {
26859
27365
  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");
27366
+ const bash = path24.join(root, "bin", "bash.exe");
27367
+ const gitExe = path24.join(root, "cmd", "git.exe");
27368
+ const hostGit = path24.join(hostToolsDir, "git");
26863
27369
  if (exists(root) && !exists(bash)) {
26864
27370
  log("Replacing the old MinGit (no bash) with full Git for Windows.");
26865
27371
  safeRemove(root, toolsDir);
@@ -26871,11 +27377,11 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26871
27377
  }
26872
27378
  const work = stagingFolder(root);
26873
27379
  try {
26874
- if (hostCopy && exists(path23.join(hostGit, "bin", "bash.exe"))) {
27380
+ if (hostCopy && exists(path24.join(hostGit, "bin", "bash.exe"))) {
26875
27381
  log("Copying Git for Windows from this PC ...");
26876
27382
  robocopy(hostGit, work);
26877
27383
  } else await installPortableGit(work);
26878
- if (!exists(path23.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
27384
+ if (!exists(path24.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
26879
27385
  moveIntoPlace(work, root);
26880
27386
  } finally {
26881
27387
  safeRemove(work, toolsDir);
@@ -26884,10 +27390,10 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26884
27390
  if (!exists(bash)) throw new Error("bash.exe missing after installing Git");
26885
27391
  pointAtOwnCertificates(root);
26886
27392
  env.vars.CLAUDE_CODE_GIT_BASH_PATH = bash;
26887
- env.append.push(path23.join(root, "usr", "bin"));
27393
+ env.append.push(path24.join(root, "usr", "bin"));
26888
27394
  const version2 = execOutput(gitExe, ["--version"]).replace(/^git version /, "");
26889
27395
  if (access === "full") {
26890
- env.prepend.push(path23.join(root, "cmd"));
27396
+ env.prepend.push(path24.join(root, "cmd"));
26891
27397
  env.summary.push("git: " + version2);
26892
27398
  return;
26893
27399
  }
@@ -26896,8 +27402,8 @@ var setupGit = async (env, hostCopy, refresh, access) => {
26896
27402
  };
26897
27403
 
26898
27404
  // src/guest/toolchains/go.ts
26899
- import fs16 from "node:fs";
26900
- import path24 from "node:path";
27405
+ import fs17 from "node:fs";
27406
+ import path25 from "node:path";
26901
27407
  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
27408
  var setupGo = async (env, config2) => {
26903
27409
  if (dryRun) {
@@ -26906,7 +27412,7 @@ var setupGo = async (env, config2) => {
26906
27412
  }
26907
27413
  const version2 = await resolveCached("go:" + config2.version, async () => (await findRelease(config2.version)).version);
26908
27414
  const root = tool("go", version2);
26909
- if (!exists(path24.join(root, "bin", "go.exe"))) {
27415
+ if (!exists(path25.join(root, "bin", "go.exe"))) {
26910
27416
  const goArch = arch === "arm64" ? "arm64" : "amd64";
26911
27417
  const file3 = (await findRelease(version2)).files.find((f) => f.os === "windows" && f.arch === goArch && f.kind === "archive");
26912
27418
  if (!file3) throw new Error(version2 + " has no Windows " + goArch + " zip");
@@ -26914,18 +27420,18 @@ var setupGo = async (env, config2) => {
26914
27420
  await installArchive("https://go.dev/dl/" + file3.filename, root, { sha256: file3.sha256, locate: "VERSION", fileName: file3.filename });
26915
27421
  }
26916
27422
  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 });
27423
+ const vars = { GOROOT: root, GOPATH, GOBIN: path25.join(GOPATH, "bin"), GOMODCACHE: path25.join(GOPATH, "pkg", "mod"), GOCACHE: tool("go-cache"), GOTOOLCHAIN: "auto", GOTELEMETRY: "off" };
27424
+ fs17.mkdirSync(vars.GOBIN, { recursive: true });
26919
27425
  Object.assign(env.vars, vars);
26920
- env.prepend.push(path24.join(root, "bin"), vars.GOBIN);
26921
- const go = path24.join(root, "bin", "go.exe");
27426
+ env.prepend.push(path25.join(root, "bin"), vars.GOBIN);
27427
+ const go = path25.join(root, "bin", "go.exe");
26922
27428
  env.summary.push("go: " + versionOf(go, ["version"]));
26923
27429
  await installOnce(env, "go", config2.tools, (pkg) => execAsync(go, ["install", pkg.includes("@") ? pkg : pkg + "@latest"], { env: { ...process.env, ...vars } }));
26924
27430
  };
26925
27431
 
26926
27432
  // src/guest/toolchains/cli.ts
26927
- import fs17 from "node:fs";
26928
- import path26 from "node:path";
27433
+ import fs18 from "node:fs";
27434
+ import path27 from "node:path";
26929
27435
 
26930
27436
  // src/guest/toolchains/catalogue.ts
26931
27437
  var pwshAsset = (arch2) => arch2 === "arm64" ? /^PowerShell-\d+\.\d+\.\d+-win-arm64\.zip$/ : /^PowerShell-\d+\.\d+\.\d+-win-x64\.zip$/;
@@ -26950,14 +27456,14 @@ var decideCli = (settings, ctx) => {
26950
27456
  };
26951
27457
 
26952
27458
  // src/guest/toolchains/runtimes.ts
26953
- import path25 from "node:path";
27459
+ import path26 from "node:path";
26954
27460
  var setupSingleExe = async (env, name, repo, pattern, exeName, dir, options = {}) => {
26955
27461
  if (dryRun) {
26956
27462
  log("(dry run) would provision " + name);
26957
27463
  return;
26958
27464
  }
26959
- const bin = options.subdir ? path25.join(dir, options.subdir) : dir;
26960
- const exe = path25.join(bin, exeName);
27465
+ const bin = options.subdir ? path26.join(dir, options.subdir) : dir;
27466
+ const exe = path26.join(bin, exeName);
26961
27467
  if (!exists(exe) || options.refresh) {
26962
27468
  const size = options.size ? ", ~" + options.size : "";
26963
27469
  await installFromGithub(repo, pattern, { dest: dir, what: (a) => name + " (" + a.name + size + " once)", ...options.subdir ? {} : { locate: exeName } });
@@ -26968,7 +27474,7 @@ var setupSingleExe = async (env, name, repo, pattern, exeName, dir, options = {}
26968
27474
  };
26969
27475
  var setupBun = async (env) => {
26970
27476
  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") });
27477
+ 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
27478
  };
26973
27479
  var setupDeno = async (env) => {
26974
27480
  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 +27488,7 @@ var setupUv = async (env) => {
26982
27488
  };
26983
27489
 
26984
27490
  // src/guest/toolchains/cli.ts
26985
- var ghConfigDir = () => path26.join(stateDir, "gh");
27491
+ var ghConfigDir = () => path27.join(stateDir, "gh");
26986
27492
  var toolVars = {
26987
27493
  gh: () => ({ GH_CONFIG_DIR: mkdirp(ghConfigDir()), GH_NO_UPDATE_NOTIFIER: "1", GH_NO_EXTENSION_UPDATE_NOTIFIER: "1" })
26988
27494
  };
@@ -26992,16 +27498,16 @@ var shimOpenssl = (env) => {
26992
27498
  return;
26993
27499
  }
26994
27500
  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 });
27501
+ fs18.copyFileSync(ensureCompiled("openssl"), path27.join(shims, "openssl.exe"));
27502
+ fs18.rmSync(path27.join(shims, "openssl.cmd"), { force: true });
26997
27503
  env.prepend.push(shims);
26998
27504
  env.summary.push("openssl: Git for Windows' copy");
26999
27505
  };
27000
27506
  var setupCli = async (env, settings, gitAccess, refresh = false) => {
27001
- const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path26.join(projectWorkspace(), ".github")) });
27507
+ const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path27.join(projectWorkspace(), ".github")) });
27002
27508
  if (settings.gh && !decisions.gh.on) {
27003
27509
  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.");
27510
+ 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
27511
  }
27006
27512
  if (dryRun) {
27007
27513
  log("(dry run) would provision CLI tools: " + Object.entries(decisions).filter(([, d]) => d.on).map(([n]) => n).join(", "));
@@ -27029,11 +27535,11 @@ var setupCli = async (env, settings, gitAccess, refresh = false) => {
27029
27535
  };
27030
27536
 
27031
27537
  // src/guest/toolchains/managers.ts
27032
- import fs18 from "node:fs";
27033
- import path27 from "node:path";
27538
+ import fs19 from "node:fs";
27539
+ import path28 from "node:path";
27034
27540
  var voltaPins = () => {
27035
27541
  try {
27036
- const pkg = JSON.parse(fs18.readFileSync(path27.join(projectWorkspace(), "package.json"), "utf8").replace(/^/, ""));
27542
+ const pkg = JSON.parse(fs19.readFileSync(path28.join(projectWorkspace(), "package.json"), "utf8").replace(/^/, ""));
27037
27543
  return Object.fromEntries(Object.entries(pkg.volta ?? {}).filter((e) => ["node", "npm", "yarn", "pnpm"].includes(e[0]) && typeof e[1] === "string"));
27038
27544
  } catch {
27039
27545
  return {};
@@ -27047,22 +27553,22 @@ var setupVolta = async (env) => {
27047
27553
  return;
27048
27554
  }
27049
27555
  const dir = tool("volta");
27050
- if (!exists(path27.join(dir, "volta.exe"))) {
27556
+ if (!exists(path28.join(dir, "volta.exe"))) {
27051
27557
  const pattern = arch === "arm64" ? /^volta-[\d.]+-windows-arm64\.zip$/ : /^volta-[\d.]+-windows\.zip$/;
27052
27558
  await installFromGithub("volta-cli/volta", pattern, { dest: dir, what: "Volta (~15 MB once)", locate: "volta.exe" });
27053
27559
  }
27054
27560
  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);
27561
+ const target = path28.join(dir, shim3 + ".exe");
27562
+ if (!exists(target)) fs19.copyFileSync(path28.join(dir, "volta-shim.exe"), target);
27057
27563
  }
27058
27564
  const home = mkdirp(tool("volta-home"));
27059
- const shims = mkdirp(path27.join(home, "bin"));
27565
+ const shims = mkdirp(path28.join(home, "bin"));
27060
27566
  const vars = { VOLTA_HOME: home, VOLTA_FEATURE_PNPM: "1" };
27061
27567
  Object.assign(env.vars, vars);
27062
27568
  const pins = voltaPins();
27063
27569
  if (Object.keys(pins).length) env.prepend.push(dir, shims);
27064
27570
  else env.append.push(dir, shims);
27065
- const volta = path27.join(dir, "volta.exe");
27571
+ const volta = path28.join(dir, "volta.exe");
27066
27572
  for (const [toolName, version2] of Object.entries(pins)) {
27067
27573
  try {
27068
27574
  await execAsync(volta, ["install", toolName + "@" + version2], { env: { ...process.env, ...vars }, cwd: projectWorkspace(), stdio: "ignore" });
@@ -27080,22 +27586,22 @@ var setupPyenv = async (env) => {
27080
27586
  return;
27081
27587
  }
27082
27588
  const root = tool("pyenv", "pyenv-win");
27083
- if (!exists(path27.join(root, "bin", "pyenv.bat"))) {
27589
+ if (!exists(path28.join(root, "bin", "pyenv.bat"))) {
27084
27590
  const tag = await resolveCached("pyenv-win", () => latestGithubTag("pyenv-win/pyenv-win"));
27085
27591
  log("Downloading pyenv-win " + tag + " (~5 MB once) ...");
27086
27592
  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
27593
  }
27088
- const home = root + path27.sep;
27594
+ const home = root + path28.sep;
27089
27595
  Object.assign(env.vars, { PYENV: home, PYENV_ROOT: home, PYENV_HOME: home });
27090
- env.append.push(path27.join(root, "bin"), path27.join(root, "shims"));
27596
+ env.append.push(path28.join(root, "bin"), path28.join(root, "shims"));
27091
27597
  env.summary.push("pyenv-win: pyenv install <version> / pyenv local <version> (versions persist)");
27092
27598
  };
27093
27599
 
27094
27600
  // src/guest/toolchains/native/cpp.ts
27095
- import path28 from "node:path";
27601
+ import path29 from "node:path";
27096
27602
  var setupCpp = async (env, config2) => {
27097
27603
  const bin = tool("mingw", "mingw64", "bin");
27098
- const gcc = path28.join(bin, "gcc.exe");
27604
+ const gcc = path29.join(bin, "gcc.exe");
27099
27605
  if (dryRun) {
27100
27606
  log("(dry run) would provision MinGW-w64 GCC");
27101
27607
  return;
@@ -27107,27 +27613,27 @@ var setupCpp = async (env, config2) => {
27107
27613
  if (!exists(gcc)) throw new Error("gcc.exe missing after installing MinGW");
27108
27614
  env.append.unshift(bin);
27109
27615
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gcc;
27110
- const cmake = versionOf(path28.join(bin, "cmake.exe"));
27616
+ const cmake = versionOf(path29.join(bin, "cmake.exe"));
27111
27617
  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
27618
  env.summary.push("gcc: " + versionOf(gcc) + " (MinGW-w64, with cmake " + cmake + ", ninja, premake5)");
27113
27619
  if (config2.flexBison) await setupFlexBison(env);
27114
27620
  };
27115
27621
  var setupFlexBison = async (env) => {
27116
27622
  const dir = tool("winflexbison");
27117
- if (!exists(path28.join(dir, "win_bison.exe"))) {
27623
+ if (!exists(path29.join(dir, "win_bison.exe"))) {
27118
27624
  await installFromGithub("lexxmark/winflexbison", /^win_flex_bison-[\d.]+\.zip$/, { dest: dir, what: "win_flex / win_bison (~1 MB once)", locate: "win_bison.exe" });
27119
27625
  }
27120
27626
  env.append.push(dir);
27121
- env.summary.push("win_flex/win_bison: " + versionOf(path28.join(dir, "win_bison.exe")));
27627
+ env.summary.push("win_flex/win_bison: " + versionOf(path29.join(dir, "win_bison.exe")));
27122
27628
  };
27123
27629
 
27124
27630
  // src/guest/toolchains/native/dotnet.ts
27125
- import fs19 from "node:fs";
27126
- import path29 from "node:path";
27631
+ import fs20 from "node:fs";
27632
+ import path30 from "node:path";
27127
27633
  var DotnetMarker = external_exports.record(external_exports.string(), external_exports.boolean());
27128
27634
  var setupDotnet = async (env, config2, refresh) => {
27129
27635
  const root = tool("dotnet");
27130
- const marker = path29.join(root, ".agent-sandbox-installed.json");
27636
+ const marker = path30.join(root, ".agent-sandbox-installed.json");
27131
27637
  const script = tool("dotnet-install.ps1");
27132
27638
  if (dryRun) {
27133
27639
  log("(dry run) would provision .NET SDK channels " + config2.channels.join(", "));
@@ -27135,10 +27641,10 @@ var setupDotnet = async (env, config2, refresh) => {
27135
27641
  }
27136
27642
  const recorded = DotnetMarker.safeParse(exists(marker) && !refresh ? readJsonFile(marker) : {});
27137
27643
  const done = recorded.success ? recorded.data : {};
27138
- const globalJson = path29.join(projectWorkspace(), "global.json");
27644
+ const globalJson = path30.join(projectWorkspace(), "global.json");
27139
27645
  const installs = [
27140
27646
  ...config2.channels.map((c) => ["channel:" + c, ["-Channel", c]]),
27141
- ...exists(globalJson) ? [["global.json:" + fs19.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]] : []
27647
+ ...exists(globalJson) ? [["global.json:" + fs20.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]] : []
27142
27648
  ];
27143
27649
  for (const [key, args] of installs.filter(([k]) => !done[k])) {
27144
27650
  await downloadFile("https://dot.net/v1/dotnet-install.ps1", script);
@@ -27149,10 +27655,10 @@ var setupDotnet = async (env, config2, refresh) => {
27149
27655
  }
27150
27656
  const home = mkdirp(tool("dotnet-home"));
27151
27657
  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 ?? "") } };
27658
+ env.prepend.push(root, path30.join(home, ".dotnet", "tools"));
27659
+ env.summary.push("dotnet: " + execOutput(path30.join(root, "dotnet.exe"), ["--list-sdks"]).split(/\r?\n/).map((l) => l.split(" ")[0]).filter(Boolean).join(", "));
27660
+ const dotnet = path30.join(root, "dotnet.exe");
27661
+ const dotnetEnv = { env: { ...process.env, ...env.vars, PATH: root + path30.delimiter + (process.env.PATH ?? "") } };
27156
27662
  await installOnce(env, "dotnet workload", config2.workloads, (w) => execAsync(dotnet, ["workload", "install", w, "--skip-manifest-update"], dotnetEnv));
27157
27663
  await installOnce(env, "dotnet tool", config2.tools, (t) => execAsync(dotnet, ["tool", "install", "--global", t], dotnetEnv));
27158
27664
  await setupFrameworkReferences(env, config2.frameworkTargets);
@@ -27163,7 +27669,7 @@ var setupFrameworkReferences = async (env, targets) => {
27163
27669
  const root = tool("netfx-references");
27164
27670
  for (const target of targets) {
27165
27671
  const id = "microsoft.netframework.referenceassemblies." + target.toLowerCase();
27166
- const marker = path29.join(root, ".installed-" + target.toLowerCase());
27672
+ const marker = path30.join(root, ".installed-" + target.toLowerCase());
27167
27673
  if (exists(marker)) continue;
27168
27674
  const staging = tool("netfx-references-" + target.toLowerCase());
27169
27675
  try {
@@ -27172,17 +27678,17 @@ var setupFrameworkReferences = async (env, targets) => {
27172
27678
  if (!version2) throw new Error("no stable version of " + id);
27173
27679
  log("Downloading the .NET Framework " + target + " reference assemblies (~30 MB once) ...");
27174
27680
  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);
27681
+ fs20.cpSync(path30.join(staging, "build", ".NETFramework"), path30.join(root, ".NETFramework"), { recursive: true });
27682
+ fs20.writeFileSync(marker, version2);
27177
27683
  } catch (e) {
27178
27684
  warn(".NET Framework " + target + " reference assemblies could not be installed (projects targeting it will not build): " + errMsg(e));
27179
27685
  } finally {
27180
27686
  safeRemove(staging, dataDir);
27181
27687
  }
27182
27688
  }
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(", "));
27689
+ if (!exists(path30.join(root, ".NETFramework"))) return;
27690
+ env.vars.TargetFrameworkRootPath = root + path30.sep;
27691
+ env.summary.push(".NET Framework targeting: " + fs20.readdirSync(path30.join(root, ".NETFramework")).join(", "));
27186
27692
  };
27187
27693
  var setupNetFx35 = async (env) => {
27188
27694
  if (execOutput(SYSTEM.reg(), ["query", "HKLM\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5", "/v", "Install"]).includes("0x1")) {
@@ -27200,15 +27706,15 @@ var setupNetFx35 = async (env) => {
27200
27706
  };
27201
27707
 
27202
27708
  // src/guest/toolchains/native/mesa.ts
27203
- import path30 from "node:path";
27709
+ import path31 from "node:path";
27204
27710
  var setupMesa = async (env, config2) => {
27205
27711
  if (dryRun) {
27206
27712
  log("(dry run) would provision Mesa 3D");
27207
27713
  return;
27208
27714
  }
27209
27715
  const root = tool("mesa");
27210
- const dir = path30.join(root, arch === "arm64" ? "arm64" : "x64");
27211
- if (!exists(path30.join(dir, "opengl32.dll"))) {
27716
+ const dir = path31.join(root, arch === "arm64" ? "arm64" : "x64");
27717
+ if (!exists(path31.join(dir, "opengl32.dll"))) {
27212
27718
  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
27719
  }
27214
27720
  Object.assign(env.vars, { MESA_DIR: dir, GALLIUM_DRIVER: "llvmpipe" });
@@ -27217,54 +27723,59 @@ var setupMesa = async (env, config2) => {
27217
27723
  };
27218
27724
  var VULKAN_RUNTIME = "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime-components.zip";
27219
27725
  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) + ")");
27726
+ const icd = path31.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
27727
+ if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path31.basename(icd) + ")");
27222
27728
  const dir = tool("vulkan");
27223
- if (!exists(path30.join(dir, "vulkan-1.dll"))) {
27729
+ if (!exists(path31.join(dir, "vulkan-1.dll"))) {
27224
27730
  log("Downloading the Vulkan loader (~10 MB once) ...");
27225
27731
  await installArchive(VULKAN_RUNTIME, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
27226
27732
  }
27227
- await execAsync(SYSTEM.reg(), ["add", "HKLM\\SOFTWARE\\Khronos\\Vulkan\\Drivers", "/v", icd, "/t", "REG_DWORD", "/d", "0", "/f"], { stdio: "ignore" });
27733
+ const register = (file3) => execAsync(SYSTEM.reg(), ["add", "HKLM\\SOFTWARE\\Khronos\\Vulkan\\Drivers", "/v", file3, "/t", "REG_DWORD", "/d", "0", "/f"], { stdio: "ignore" });
27734
+ await register(icd);
27735
+ const dozen = path31.join(mesaDir, arch === "arm64" ? "dzn_icd.aarch64.json" : "dzn_icd.x86_64.json");
27736
+ const gpu = hasGpu();
27737
+ if (gpu && exists(dozen)) await register(dozen);
27228
27738
  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");
27739
+ 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
27740
  };
27741
+ 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
27742
 
27232
27743
  // src/guest/toolchains/native/msvc/index.ts
27233
- import fs23 from "node:fs";
27234
- import path34 from "node:path";
27744
+ import fs24 from "node:fs";
27745
+ import path35 from "node:path";
27235
27746
 
27236
27747
  // src/guest/toolchains/native/msvc/environment.ts
27237
- import fs21 from "node:fs";
27238
- import path32 from "node:path";
27748
+ import fs22 from "node:fs";
27749
+ import path33 from "node:path";
27239
27750
 
27240
27751
  // src/guest/toolchains/native/msvc/tree.ts
27241
- import fs20 from "node:fs";
27242
- import path31 from "node:path";
27752
+ import fs21 from "node:fs";
27753
+ import path32 from "node:path";
27243
27754
  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);
27755
+ var MARKER2 = path32.join(ROOT, ".installed.json");
27756
+ var msvcTools = (msvc, ...parts) => path32.join(ROOT, "VC", "Tools", "MSVC", msvc, ...parts);
27246
27757
  var hostBin = (msvc, ...parts) => msvcTools(msvc, "bin", "Hostx64", "x64", ...parts);
27247
27758
  var hasCompiler = (msvc) => exists(hostBin(msvc, "cl.exe"));
27248
27759
  var Installed = external_exports.object({ msvc: external_exports.string().min(1), sdk: external_exports.string().min(1), want: external_exports.string() });
27249
27760
  var readInstalled = () => {
27250
27761
  try {
27251
- return Installed.safeParse(JSON.parse(fs20.readFileSync(MARKER, "utf8"))).data ?? null;
27762
+ return Installed.safeParse(JSON.parse(fs21.readFileSync(MARKER2, "utf8"))).data ?? null;
27252
27763
  } catch {
27253
27764
  return null;
27254
27765
  }
27255
27766
  };
27256
27767
 
27257
27768
  // 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");
27769
+ var VSWHERE_DIR = path33.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Microsoft Visual Studio", "Installer");
27259
27770
  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);
27771
+ const vc = path33.join(root, "VC", "Tools", "MSVC", msvc);
27772
+ const kits = path33.join(root, "Windows Kits", "10");
27773
+ const inc = (...p) => path33.join(kits, "Include", sdk, ...p);
27774
+ const lib = (...p) => path33.join(kits, "Lib", sdk, ...p);
27264
27775
  return {
27265
27776
  vars: {
27266
27777
  VSINSTALLDIR: root + "\\",
27267
- VCINSTALLDIR: path32.join(root, "VC") + "\\",
27778
+ VCINSTALLDIR: path33.join(root, "VC") + "\\",
27268
27779
  VCToolsInstallDir: vc + "\\",
27269
27780
  VCToolsVersion: msvc,
27270
27781
  VisualStudioVersion: "17.0",
@@ -27276,15 +27787,15 @@ var vcvars = (root, msvc, sdk) => {
27276
27787
  VSCMD_ARG_HOST_ARCH: "x64",
27277
27788
  VSCMD_ARG_TGT_ARCH: "x64",
27278
27789
  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(";")
27790
+ INCLUDE: [path33.join(vc, "include"), inc("ucrt"), inc("shared"), inc("um"), inc("winrt"), inc("cppwinrt")].join(";"),
27791
+ LIB: [path33.join(vc, "lib", "x64"), lib("ucrt", "x64"), lib("um", "x64")].join(";"),
27792
+ LIBPATH: [path33.join(vc, "lib", "x64"), path33.join(vc, "lib", "x86", "store", "references")].join(";")
27282
27793
  },
27283
- path: [path32.join(vc, "bin", "Hostx64", "x64"), path32.join(kits, "bin", sdk, "x64")]
27794
+ path: [path33.join(vc, "bin", "Hostx64", "x64"), path33.join(kits, "bin", sdk, "x64")]
27284
27795
  };
27285
27796
  };
27286
27797
  var writeVcvars = (env) => {
27287
- const dir = mkdirp(path32.join(ROOT, "VC", "Auxiliary", "Build"));
27798
+ const dir = mkdirp(path33.join(ROOT, "VC", "Auxiliary", "Build"));
27288
27799
  const lines = [
27289
27800
  "@echo off",
27290
27801
  "rem Written by Windows Development Sandbox for its portable MSVC (host x64, target x64).",
@@ -27292,26 +27803,26 @@ var writeVcvars = (env) => {
27292
27803
  'set "PATH=' + env.path.join(";") + ';%PATH%"',
27293
27804
  "exit /b 0"
27294
27805
  ];
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");
27806
+ fs22.writeFileSync(path33.join(dir, "vcvars64.bat"), lines.join("\r\n") + "\r\n");
27807
+ 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
27808
  };
27298
27809
  var installVswhere = (msvc) => {
27299
27810
  mkdirp(VSWHERE_DIR);
27300
- fs21.copyFileSync(ensureCompiled("vswhere"), path32.join(VSWHERE_DIR, "vswhere.exe"));
27811
+ fs22.copyFileSync(ensureCompiled("vswhere"), path33.join(VSWHERE_DIR, "vswhere.exe"));
27301
27812
  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") }));
27813
+ fs22.writeFileSync(path33.join(VSWHERE_DIR, "vswhere.json"), JSON.stringify({ installationPath: ROOT, installationVersion: "17." + (minor ?? "0") + ".0." + (major ?? "0") }));
27303
27814
  };
27304
27815
  var removeTelemetry = (msvc) => {
27305
27816
  try {
27306
- fs21.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
27817
+ fs22.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
27307
27818
  } catch (e) {
27308
27819
  warn("Could not remove MSVC's telemetry helper (vctip.exe); it may keep tools\\msvc locked: " + errMsg(e));
27309
27820
  }
27310
27821
  };
27311
27822
 
27312
27823
  // src/guest/toolchains/native/msvc/packages.ts
27313
- import fs22 from "node:fs";
27314
- import path33 from "node:path";
27824
+ import fs23 from "node:fs";
27825
+ import path34 from "node:path";
27315
27826
  var CHANNEL = "https://aka.ms/vs/17/release/channel";
27316
27827
  var MANIFEST_DAY_MS = 24 * 60 * 60 * 1e3;
27317
27828
  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 +27839,10 @@ var SDK_MSIS = [
27328
27839
  "Windows SDK Desktop Tools x64-x86_en-us.msi"
27329
27840
  ];
27330
27841
  var manifest = async () => {
27331
- const cached2 = path33.join(ROOT, ".manifest.json");
27332
- if (exists(cached2) && Date.now() - fs22.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
27842
+ const cached2 = path34.join(ROOT, ".manifest.json");
27843
+ if (exists(cached2) && Date.now() - fs23.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
27333
27844
  try {
27334
- return JSON.parse(fs22.readFileSync(cached2, "utf8"));
27845
+ return JSON.parse(fs23.readFileSync(cached2, "utf8"));
27335
27846
  } catch {
27336
27847
  }
27337
27848
  }
@@ -27340,26 +27851,26 @@ var manifest = async () => {
27340
27851
  if (!item) throw new Error("the Visual Studio channel has no package manifest");
27341
27852
  mkdirp(ROOT);
27342
27853
  await download(item.url, cached2);
27343
- return JSON.parse(fs22.readFileSync(cached2, "utf8"));
27854
+ return JSON.parse(fs23.readFileSync(cached2, "utf8"));
27344
27855
  };
27345
27856
  var unpackVsix = async (vsix, work) => {
27346
- const out = mkdirp(path33.join(work, "vsix-" + path33.basename(vsix)));
27857
+ const out = mkdirp(path34.join(work, "vsix-" + path34.basename(vsix)));
27347
27858
  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);
27859
+ const decode4 = (dir) => {
27860
+ for (const entry of fs23.readdirSync(dir, { withFileTypes: true })) {
27861
+ const from = path34.join(dir, entry.name);
27351
27862
  let name = entry.name;
27352
27863
  try {
27353
27864
  if (name.includes("%")) name = decodeURIComponent(name);
27354
27865
  } catch {
27355
27866
  }
27356
- const to = path33.join(dir, name);
27357
- if (to !== from) fs22.renameSync(from, to);
27358
- if (entry.isDirectory()) decode3(to);
27867
+ const to = path34.join(dir, name);
27868
+ if (to !== from) fs23.renameSync(from, to);
27869
+ if (entry.isDirectory()) decode4(to);
27359
27870
  }
27360
27871
  };
27361
- decode3(out);
27362
- fs22.cpSync(path33.join(out, "Contents"), ROOT, { recursive: true, force: true });
27872
+ decode4(out);
27873
+ fs23.cpSync(path34.join(out, "Contents"), ROOT, { recursive: true, force: true });
27363
27874
  safeRemove(out, work);
27364
27875
  };
27365
27876
  var unpackMsi = async (msi) => {
@@ -27367,8 +27878,8 @@ var unpackMsi = async (msi) => {
27367
27878
  try {
27368
27879
  await execAsync(system32("msiexec.exe"), ["/a", msi, "/quiet", "/qn", "TARGETDIR=" + ROOT, "/l*v", logFile2], { stdio: "ignore" });
27369
27880
  } 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) + ")" : ""));
27881
+ const lines = exists(logFile2) ? fs23.readFileSync(logFile2, "utf16le").split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(" | ") : "";
27882
+ throw new Error(path34.basename(msi) + " did not unpack: " + (e instanceof Error ? e.message : String(e)) + (lines ? " (" + lines.slice(0, 600) + ")" : ""));
27372
27883
  }
27373
27884
  };
27374
27885
  var catalogue = (m) => {
@@ -27380,13 +27891,13 @@ var catalogue = (m) => {
27380
27891
  };
27381
27892
  };
27382
27893
  var payloadFetcher = (work) => async (p) => {
27383
- const file3 = path33.join(work, path33.basename(p.fileName.replace(/\\/g, "/")));
27894
+ const file3 = path34.join(work, path34.basename(p.fileName.replace(/\\/g, "/")));
27384
27895
  if (!exists(file3)) await download(p.url, file3, p.sha256);
27385
27896
  return file3;
27386
27897
  };
27387
27898
  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();
27899
+ const toolsRoot = path34.join(ROOT, "VC", "Tools", "MSVC");
27900
+ return fs23.readdirSync(toolsRoot).filter((d) => exists(hostBin(d, "cl.exe"))).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).pop();
27390
27901
  };
27391
27902
  var installPackages = async (config2) => {
27392
27903
  const { ids, pick: pick2 } = catalogue(await manifest());
@@ -27394,7 +27905,7 @@ var installPackages = async (config2) => {
27394
27905
  if (!version2) throw new Error("no MSVC " + config2.msvcVersion + " in the Visual Studio manifest");
27395
27906
  const sdk = pickWindowsSdk(ids, config2.sdkVersion);
27396
27907
  if (!sdk) throw new Error("no Windows SDK " + config2.sdkVersion + " in the Visual Studio manifest");
27397
- const work = mkdirp(path33.join(ROOT, ".download"));
27908
+ const work = mkdirp(path34.join(ROOT, ".download"));
27398
27909
  const fetchPayload = payloadFetcher(work);
27399
27910
  log("Downloading the MSVC " + version2 + " compiler and C/C++ libraries ...");
27400
27911
  for (const part of MSVC_PARTS) {
@@ -27413,16 +27924,16 @@ var installPackages = async (config2) => {
27413
27924
  if (!p) throw new Error("the Windows SDK package has no " + name);
27414
27925
  const file3 = await fetchPayload(p);
27415
27926
  msis.push(file3);
27416
- for (const cab of msiCabs(fs22.readFileSync(file3))) {
27927
+ for (const cab of msiCabs(fs23.readFileSync(file3))) {
27417
27928
  const c = payload(cab);
27418
27929
  if (c) await fetchPayload(c);
27419
27930
  }
27420
27931
  }
27421
27932
  log("Unpacking the Windows SDK (a few minutes) ...");
27422
27933
  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 });
27934
+ for (const name of fs23.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith(".msi"))) fs23.rmSync(path34.join(ROOT, name), { force: true });
27424
27935
  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();
27936
+ const sdkVersion = fs23.readdirSync(path34.join(ROOT, "Windows Kits", "10", "Include")).filter((d) => d.startsWith("10.0." + sdk.build)).sort().pop();
27426
27937
  if (!sdkVersion) throw new Error("the Windows SDK did not unpack (no Include\\10.0." + sdk.build + ".*)");
27427
27938
  const toolset = unpackedToolset();
27428
27939
  if (!toolset) throw new Error("MSVC " + version2 + " did not unpack (no cl.exe under VC\\Tools\\MSVC)");
@@ -27436,7 +27947,7 @@ var installedMsvcEnv = () => {
27436
27947
  };
27437
27948
  var clearTree = () => {
27438
27949
  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);
27950
+ for (const name of fs24.readdirSync(ROOT).filter((n) => n !== ".manifest.json" && n !== ".download")) safeRemove(path35.join(ROOT, name), ROOT);
27440
27951
  };
27441
27952
  var setupMsvc = async (env, config2) => {
27442
27953
  if (!config2.acceptLicense) {
@@ -27452,7 +27963,7 @@ var setupMsvc = async (env, config2) => {
27452
27963
  log("Installing MSVC and the Windows SDK (~1-2 GB, once; licence accepted in toolchains.msvc.acceptLicense) ...");
27453
27964
  clearTree();
27454
27965
  done = { ...await installPackages(config2), want };
27455
- writeJsonAtomic(MARKER, done);
27966
+ writeJsonAtomic(MARKER2, done);
27456
27967
  }
27457
27968
  removeTelemetry(done.msvc);
27458
27969
  const vc = vcvars(ROOT, done.msvc, done.sdk);
@@ -27464,20 +27975,20 @@ var setupMsvc = async (env, config2) => {
27464
27975
  };
27465
27976
 
27466
27977
  // src/guest/toolchains/native/rust.ts
27467
- import path36 from "node:path";
27978
+ import path37 from "node:path";
27468
27979
 
27469
27980
  // src/guest/toolchains/native/binstall.ts
27470
- import fs24 from "node:fs";
27471
- import path35 from "node:path";
27981
+ import fs25 from "node:fs";
27982
+ import path36 from "node:path";
27472
27983
  var ensureBinstall = async (cargoBin) => {
27473
- const target = path35.join(cargoBin, "cargo-binstall.exe");
27984
+ const target = path36.join(cargoBin, "cargo-binstall.exe");
27474
27985
  if (exists(target)) return true;
27475
27986
  try {
27476
27987
  const dir = tool("cargo-binstall");
27477
- if (!exists(path35.join(dir, "cargo-binstall.exe"))) {
27988
+ if (!exists(path36.join(dir, "cargo-binstall.exe"))) {
27478
27989
  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
27990
  }
27480
- fs24.copyFileSync(path35.join(dir, "cargo-binstall.exe"), target);
27991
+ fs25.copyFileSync(path36.join(dir, "cargo-binstall.exe"), target);
27481
27992
  return true;
27482
27993
  } catch (e) {
27483
27994
  warn("cargo-binstall unavailable, compiling crates with cargo install instead: " + errMsg(e));
@@ -27485,11 +27996,11 @@ var ensureBinstall = async (cargoBin) => {
27485
27996
  }
27486
27997
  };
27487
27998
  var crateInstaller = (cargoHome, cargoEnv) => {
27488
- const cargo = path35.join(cargoHome, "bin", "cargo.exe");
27999
+ const cargo = path36.join(cargoHome, "bin", "cargo.exe");
27489
28000
  let binstall = null;
27490
28001
  const binstallEnv = { ...cargoEnv, env: { ...cargoEnv.env ?? process.env, BINSTALL_DISABLE_TELEMETRY: "true" } };
27491
28002
  return async (crate) => {
27492
- binstall ??= ensureBinstall(path35.join(cargoHome, "bin"));
28003
+ binstall ??= ensureBinstall(path36.join(cargoHome, "bin"));
27493
28004
  if (await binstall) {
27494
28005
  try {
27495
28006
  await execAsync(cargo, ["binstall", "--no-confirm", "--locked", "--disable-strategies", "compile", crate], binstallEnv);
@@ -27507,7 +28018,7 @@ var setupRust = async (env, config2, refresh) => {
27507
28018
  const RUSTUP_HOME = tool("rust", "rustup");
27508
28019
  const CARGO_HOME = tool("rust", "cargo");
27509
28020
  const rustEnv = { env: { ...process.env, RUSTUP_HOME, CARGO_HOME } };
27510
- const rustup = path36.join(CARGO_HOME, "bin", "rustup.exe");
28021
+ const rustup = path37.join(CARGO_HOME, "bin", "rustup.exe");
27511
28022
  if (dryRun) {
27512
28023
  log("(dry run) would provision Rust " + config2.toolchain + " (" + config2.host + ")");
27513
28024
  return;
@@ -27524,35 +28035,35 @@ var setupRust = async (env, config2, refresh) => {
27524
28035
  if (refresh) await execAsync(rustup, ["update"], rustEnv);
27525
28036
  }
27526
28037
  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 + "]");
28038
+ env.prepend.push(path37.join(CARGO_HOME, "bin"));
28039
+ env.summary.push("rust: " + versionOf(path37.join(CARGO_HOME, "bin", "rustc.exe"), ["--version"], rustEnv) + " [" + config2.host + "]");
27529
28040
  const toolchainKey = "rustup@" + config2.toolchain;
27530
28041
  await installOnce(env, toolchainKey + " components", config2.components, (c) => execAsync(rustup, ["component", "add", c], rustEnv));
27531
28042
  await installOnce(env, toolchainKey + " targets", config2.targets, (t) => execAsync(rustup, ["target", "add", t], rustEnv));
27532
28043
  const msvc = config2.host.endsWith("-msvc") ? installedMsvcEnv() : null;
27533
28044
  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) } };
28045
+ 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
28046
  await installOnce(env, "cargo", config2.crates, crateInstaller(CARGO_HOME, cargoEnv));
27536
28047
  };
27537
28048
 
27538
28049
  // src/guest/toolchains/node.ts
27539
- import fs25 from "node:fs";
27540
- import path37 from "node:path";
28050
+ import fs26 from "node:fs";
28051
+ import path38 from "node:path";
27541
28052
  import { spawn as spawn4 } from "node:child_process";
27542
28053
  var NVM_HOME = tool("nvm");
27543
- var NVM_SYMLINK = path37.join(localDir, "nodejs");
27544
- var HOST_NVM = path37.join(hostToolsDir, "nvm");
28054
+ var NVM_SYMLINK = path38.join(localDir, "nodejs");
28055
+ var HOST_NVM = path38.join(hostToolsDir, "nvm");
27545
28056
  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)) : [];
28057
+ 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
28058
  var resolveNode = (spec) => resolveCached("node:" + spec, async () => {
27548
28059
  const exact = spec.replace(/^v/, "");
27549
28060
  if (/^\d+\.\d+\.\d+$/.test(exact)) return exact;
27550
28061
  const releases = await fetchJson("https://nodejs.org/dist/index.json");
27551
28062
  return pickNodeVersion(releases, spec) ?? Promise.reject(new Error('No Node.js release matches "' + spec + '"'));
27552
28063
  });
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 } });
28064
+ var NVM_TEMP = path38.join(NVM_HOME, ".tmp");
28065
+ var nvm = (args) => new Promise((resolve2) => {
28066
+ 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
28067
  let out = "";
27557
28068
  child.stdout.on("data", (d) => {
27558
28069
  out += d.toString();
@@ -27560,16 +28071,16 @@ var nvm = (args) => new Promise((resolve) => {
27560
28071
  child.stderr.on("data", (d) => {
27561
28072
  out += d.toString();
27562
28073
  });
27563
- child.once("error", (e) => resolve(out + e.message));
27564
- child.once("close", () => resolve(out));
28074
+ child.once("error", (e) => resolve2(out + e.message));
28075
+ child.once("close", () => resolve2(out));
27565
28076
  });
27566
28077
  var ensureNvm = async () => {
27567
- if (exists(path37.join(NVM_HOME, "nvm.exe"))) return;
27568
- if (exists(path37.join(HOST_NVM, "nvm.exe"))) {
28078
+ if (exists(path38.join(NVM_HOME, "nvm.exe"))) return;
28079
+ if (exists(path38.join(HOST_NVM, "nvm.exe"))) {
27569
28080
  log("Copying nvm from this PC ...");
27570
28081
  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));
28082
+ 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"));
28083
+ for (const file3 of files) fs26.copyFileSync(path38.join(HOST_NVM, file3), path38.join(NVM_HOME, file3));
27573
28084
  return;
27574
28085
  }
27575
28086
  const asset = await githubAsset("coreybutler/nvm-windows", /^nvm-noinstall\.zip$/, true);
@@ -27577,10 +28088,10 @@ var ensureNvm = async () => {
27577
28088
  await installArchive(asset.url, NVM_HOME, { sha256: asset.sha256, locate: "nvm.exe", fileName: asset.name });
27578
28089
  };
27579
28090
  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"))) {
28091
+ const dir = path38.join(NVM_HOME, "v" + version2);
28092
+ const fromHost = path38.join(HOST_NVM, "v" + version2);
28093
+ if (exists(path38.join(dir, "node.exe"))) return;
28094
+ if (exists(path38.join(fromHost, "node.exe"))) {
27584
28095
  log("Copying Node " + version2 + " from this PC's nvm (without global packages) ...");
27585
28096
  copyNode(fromHost, dir);
27586
28097
  return;
@@ -27593,13 +28104,13 @@ var installNodeVersion = async (version2) => {
27593
28104
  } finally {
27594
28105
  safeRemove(NVM_TEMP, NVM_HOME);
27595
28106
  }
27596
- if (!exists(path37.join(dir, "node.exe"))) throw new Error("nvm install " + version2 + " failed: " + out.trim().split("\n").slice(-2).join(" "));
28107
+ if (!exists(path38.join(dir, "node.exe"))) throw new Error("nvm install " + version2 + " failed: " + out.trim().split("\n").slice(-2).join(" "));
27597
28108
  };
27598
28109
  var activate = async (version2) => {
27599
28110
  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");
28111
+ if (exists(path38.join(NVM_SYMLINK, "node.exe"))) return;
28112
+ fs26.rmSync(NVM_SYMLINK, { recursive: true, force: true });
28113
+ fs26.symlinkSync(path38.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
27603
28114
  };
27604
28115
  var setupNode = async (env, versions, config2) => {
27605
28116
  if (dryRun) {
@@ -27607,7 +28118,7 @@ var setupNode = async (env, versions, config2) => {
27607
28118
  return;
27608
28119
  }
27609
28120
  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"));
28121
+ 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
28122
  mkdirp(localDir);
27612
28123
  for (const extra of versions.nodeExtra) {
27613
28124
  try {
@@ -27626,7 +28137,7 @@ var setupNode = async (env, versions, config2) => {
27626
28137
  }
27627
28138
  }
27628
28139
  Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK });
27629
- if (duringSession()) env.prepend.push(path37.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
28140
+ if (duringSession()) env.prepend.push(path38.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
27630
28141
  else {
27631
28142
  await activate(main);
27632
28143
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
@@ -27635,10 +28146,10 @@ var setupNode = async (env, versions, config2) => {
27635
28146
  await packageManagers(env, config2, main);
27636
28147
  };
27637
28148
  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");
28149
+ const dir = path38.join(NVM_HOME, "v" + version2);
28150
+ const nodeEnv = { ...process.env, PATH: dir + path38.delimiter + (process.env.PATH ?? "") };
28151
+ const npm = (args) => execAsync(path38.join(dir, "node.exe"), [path38.join(dir, "node_modules", "npm", "bin", "npm-cli.js"), ...args], { env: nodeEnv, stdio: "ignore" });
28152
+ const corepackJs = path38.join(dir, "node_modules", "corepack", "dist", "corepack.js");
27642
28153
  const extra = config2.corepack && !exists(corepackJs) ? ["corepack"] : [];
27643
28154
  await installOnce(env, "npm@" + version2, [...extra, ...config2.globalPackages], (pkg) => npm(["install", "--global", pkg, "--no-fund", "--no-audit"]));
27644
28155
  if (!config2.corepack) return;
@@ -27648,7 +28159,7 @@ var packageManagers = async (env, config2, version2) => {
27648
28159
  return;
27649
28160
  }
27650
28161
  try {
27651
- await execAsync(path37.join(dir, "node.exe"), [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"], { env: nodeEnv, stdio: "ignore" });
28162
+ await execAsync(path38.join(dir, "node.exe"), [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"], { env: nodeEnv, stdio: "ignore" });
27652
28163
  env.summary.push('pnpm, yarn: via corepack (package.json "packageManager" picks the version)');
27653
28164
  } catch (e) {
27654
28165
  warn("corepack enable failed: " + errMsg(e));
@@ -27663,31 +28174,48 @@ var setupPwsh = async (env, refresh = false) => {
27663
28174
  };
27664
28175
 
27665
28176
  // src/guest/toolchains/python.ts
27666
- import fs26 from "node:fs";
27667
- import path38 from "node:path";
28177
+ import fs27 from "node:fs";
28178
+ import path39 from "node:path";
27668
28179
  var installPython = async (pkg, spec) => {
27669
28180
  const version2 = await resolveCached(pkg + ":" + spec, async () => {
27670
28181
  const { versions } = await fetchJson("https://api.nuget.org/v3-flatcontainer/" + pkg + "/index.json");
27671
28182
  return pickPackageVersion(versions, spec) ?? Promise.reject(new Error("No " + pkg + ' release matches "' + spec + '"'));
27672
28183
  });
27673
28184
  const dir = tool("python", pkg + "-" + version2);
27674
- const exe = path38.join(dir, "python.exe");
28185
+ const exe = path39.join(dir, "python.exe");
27675
28186
  if (!exists(exe)) {
27676
28187
  log("Downloading Python " + version2 + (pkg === "python2" ? " (Python 2, " : " (") + "~30 MB once) ...");
27677
28188
  await installArchive("https://api.nuget.org/v3-flatcontainer/" + pkg + "/" + version2 + "/" + pkg + "." + version2 + ".nupkg", dir, { locate: "python.exe", fileName: pkg + "." + version2 + ".zip" });
27678
28189
  }
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" });
28190
+ 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
28191
  return dir;
27681
28192
  };
27682
- var shimDir = (dir) => duringSession() ? tool("shims", path38.basename(dir)) : tool("shims");
28193
+ var shimDir = (dir) => duringSession() ? tool("shims", path39.basename(dir)) : tool("shims");
27683
28194
  var shim = (folder, name, command) => {
27684
- fs26.writeFileSync(path38.join(mkdirp(folder), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
28195
+ fs27.writeFileSync(path39.join(mkdirp(folder), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
27685
28196
  };
27686
28197
  var shimPair = (folder, version2, dir) => {
27687
- const python = '"' + path38.join(dir, "python.exe") + '"';
28198
+ const python = '"' + path39.join(dir, "python.exe") + '"';
27688
28199
  shim(folder, "python" + version2, python);
27689
28200
  shim(folder, "pip" + version2, python + " -m pip");
27690
28201
  };
28202
+ var pyLauncher = (folder, py3, py2) => {
28203
+ const script = path39.join(mkdirp(folder), "py-launcher.py");
28204
+ fs27.writeFileSync(script, [
28205
+ "import subprocess, sys",
28206
+ "PY3, PY2 = " + JSON.stringify(path39.join(py3, "python.exe")) + ", " + JSON.stringify(py2 ? path39.join(py2, "python.exe") : null),
28207
+ "args = sys.argv[1:]",
28208
+ "exe = PY3",
28209
+ "if args and args[0].startswith('-2'):",
28210
+ ' if not PY2: sys.exit("py: Python 2 is not installed (toolchains.python.python2)")',
28211
+ " exe, args = PY2, args[1:]",
28212
+ "elif args and (args[0] == '-3' or args[0].startswith('-3.') or args[0].startswith('-3-')):",
28213
+ " args = args[1:]",
28214
+ "sys.exit(subprocess.call([exe] + args))",
28215
+ ""
28216
+ ].join("\n"));
28217
+ shim(folder, "py", '"' + path39.join(py3, "python.exe") + '" "' + script + '"');
28218
+ };
27691
28219
  var setupPython = async (env, config2, versions) => {
27692
28220
  if (dryRun) {
27693
28221
  log("(dry run) would provision Python " + versions.python.spec + (config2.python2 ? " and Python 2.7" : ""));
@@ -27696,22 +28224,26 @@ var setupPython = async (env, config2, versions) => {
27696
28224
  const py3 = await installPython("python", versions.python.spec);
27697
28225
  const shims = shimDir(py3);
27698
28226
  shimPair(shims, "3", py3);
27699
- env.prepend.push(py3, path38.join(py3, "Scripts"), shims);
28227
+ env.prepend.push(py3, path39.join(py3, "Scripts"), shims);
27700
28228
  env.vars.PYTHONIOENCODING = "utf-8";
27701
- env.summary.push("python: " + path38.basename(py3).replace("python-", "") + " (from " + versions.python.source + ")");
27702
- if (!config2.python2) return;
28229
+ env.summary.push("python: " + path39.basename(py3).replace("python-", "") + " (from " + versions.python.source + "; py works too)");
28230
+ if (!config2.python2) {
28231
+ pyLauncher(shims, py3, null);
28232
+ return;
28233
+ }
27703
28234
  const py2 = await installPython("python2", "2.7");
27704
28235
  shimPair(shims, "2", py2);
27705
- env.summary.push("python2: " + path38.basename(py2).replace("python2-", ""));
28236
+ pyLauncher(shims, py3, py2);
28237
+ env.summary.push("python2: " + path39.basename(py2).replace("python2-", ""));
27706
28238
  };
27707
28239
 
27708
28240
  // src/guest/toolchains/scripting/php.ts
27709
- import fs28 from "node:fs";
27710
- import path40 from "node:path";
28241
+ import fs29 from "node:fs";
28242
+ import path41 from "node:path";
27711
28243
 
27712
28244
  // src/guest/toolchains/scripting/vcruntime.ts
27713
- import fs27 from "node:fs";
27714
- import path39 from "node:path";
28245
+ import fs28 from "node:fs";
28246
+ import path40 from "node:path";
27715
28247
  var VC_REDIST = "https://aka.ms/vs/17/release/vc_redist.x64.exe";
27716
28248
  var MICROSOFT_SIGNER = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
27717
28249
  var OK_EXIT_CODES = [0, 1638, 3010];
@@ -27726,8 +28258,8 @@ var setupVcRuntime = async (env, summary = true) => {
27726
28258
  log("(dry run) would install the Visual C++ runtime");
27727
28259
  return false;
27728
28260
  }
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"));
28261
+ const system322 = path40.join(process.env.WINDIR ?? "C:\\Windows", "System32");
28262
+ const missing = !exists(path40.join(system322, "vcruntime140.dll")) || !exists(path40.join(system322, "msvcp140.dll"));
27731
28263
  if (missing) {
27732
28264
  const installer = tool("vcredist", "vc_redist.x64.exe");
27733
28265
  if (!exists(installer)) {
@@ -27735,12 +28267,12 @@ var setupVcRuntime = async (env, summary = true) => {
27735
28267
  await downloadFile(VC_REDIST, installer);
27736
28268
  }
27737
28269
  if (signerOf(installer) !== MICROSOFT_SIGNER) {
27738
- fs27.rmSync(installer, { force: true });
28270
+ fs28.rmSync(installer, { force: true });
27739
28271
  throw new Error("vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)");
27740
28272
  }
27741
28273
  log("Installing the Visual C++ runtime ...");
27742
28274
  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 + ")");
28275
+ 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
28276
  }
27745
28277
  if (summary) env.summary.push("vc++ runtime: installed");
27746
28278
  return missing;
@@ -27758,15 +28290,15 @@ var phpBuild = async (spec) => {
27758
28290
  return { version: release.version, ...build.zip };
27759
28291
  };
27760
28292
  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);
28293
+ const ini = path41.join(home, "php.ini");
28294
+ if (exists(ini) || !exists(path41.join(home, "php.ini-development"))) return;
28295
+ 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") + '"');
28296
+ 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");
28297
+ fs29.writeFileSync(ini + ".tmp", text);
28298
+ fs29.renameSync(ini + ".tmp", ini);
27767
28299
  };
27768
28300
  var shim2 = (env, name, command) => {
27769
- fs28.writeFileSync(path40.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
28301
+ fs29.writeFileSync(path41.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
27770
28302
  env.prepend.push(tool("shims"));
27771
28303
  };
27772
28304
  var setupComposer = async (env, php) => {
@@ -27778,7 +28310,7 @@ var setupComposer = async (env, php) => {
27778
28310
  }
27779
28311
  const composerHome = tool("composer-home");
27780
28312
  env.vars.COMPOSER_HOME = composerHome;
27781
- env.prepend.push(path40.join(composerHome, "vendor", "bin"));
28313
+ env.prepend.push(path41.join(composerHome, "vendor", "bin"));
27782
28314
  shim2(env, "composer", '"' + php + '" "' + phar + '"');
27783
28315
  env.summary.push("composer: " + (/\d+\.\d+\.\d+/.exec(execOutput(php, [phar, "--version", "--no-ansi"]))?.[0] ?? "installed"));
27784
28316
  };
@@ -27791,7 +28323,7 @@ var setupPhp = async (env, config2) => {
27791
28323
  await setupVcRuntime(env, false);
27792
28324
  const version2 = await resolveCached("php:" + wantedSpec.spec, async () => (await phpBuild(wantedSpec.spec)).version);
27793
28325
  const home = tool("php", version2);
27794
- if (!exists(path40.join(home, "php.exe"))) {
28326
+ if (!exists(path41.join(home, "php.exe"))) {
27795
28327
  const build = await phpBuild(version2);
27796
28328
  log("Downloading PHP " + version2 + " (~30 MB once) ...");
27797
28329
  await installArchive("https://windows.php.net/downloads/releases/" + build.path, home, { sha256: build.sha256, locate: "php.exe", fileName: build.path });
@@ -27799,11 +28331,11 @@ var setupPhp = async (env, config2) => {
27799
28331
  writePhpIni(home);
27800
28332
  env.prepend.push(home);
27801
28333
  env.summary.push("php: " + version2 + " (from " + wantedSpec.source + ")");
27802
- if (config2.composer) await setupComposer(env, path40.join(home, "php.exe"));
28334
+ if (config2.composer) await setupComposer(env, path41.join(home, "php.exe"));
27803
28335
  };
27804
28336
 
27805
28337
  // src/guest/toolchains/scripting/ruby.ts
27806
- import path41 from "node:path";
28338
+ import path42 from "node:path";
27807
28339
  var RUBY_ASSET = /^rubyinstaller-(\d+\.\d+\.\d+)-(\d+)-x64\.7z$/;
27808
28340
  var buildNumber = (asset) => Number(RUBY_ASSET.exec(asset.name)?.[2] ?? 0);
27809
28341
  var rubyBuilds = async () => {
@@ -27826,7 +28358,7 @@ var setupRuby = async (env, config2) => {
27826
28358
  }
27827
28359
  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
28360
  const home = tool("ruby", version2);
27829
- if (!exists(path41.join(home, "bin", "ruby.exe"))) {
28361
+ if (!exists(path42.join(home, "bin", "ruby.exe"))) {
27830
28362
  const asset = (await rubyBuilds()).get(version2);
27831
28363
  if (!asset) throw new Error("RubyInstaller " + version2 + " is no longer published");
27832
28364
  log("Downloading Ruby " + version2 + " (~100 MB once) ...");
@@ -27834,26 +28366,202 @@ var setupRuby = async (env, config2) => {
27834
28366
  }
27835
28367
  const gems = tool("ruby-gems", version2.split(".").slice(0, 2).join("."));
27836
28368
  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");
28369
+ env.prepend.push(path42.join(home, "bin"), path42.join(gems, "bin"));
28370
+ env.summary.push("ruby: " + versionOf(path42.join(home, "bin", "ruby.exe")) + " (from " + wantedSpec.source + "; gems with C extensions need MSYS2, not included)");
28371
+ const gem = path42.join(home, "bin", "gem.cmd");
27840
28372
  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
28373
  };
27842
28374
 
27843
28375
  // src/guest/toolchains/vscode.ts
27844
- import fs29 from "node:fs";
27845
- import os5 from "node:os";
27846
- import path42 from "node:path";
28376
+ import fs30 from "node:fs";
28377
+ import os7 from "node:os";
28378
+ import path43 from "node:path";
28379
+
28380
+ // node_modules/jsonc-parser/lib/esm/impl/scanner.js
28381
+ var CharacterCodes;
28382
+ (function(CharacterCodes2) {
28383
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
28384
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
28385
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
28386
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
28387
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
28388
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
28389
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
28390
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
28391
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
28392
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
28393
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
28394
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
28395
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
28396
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
28397
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
28398
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
28399
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
28400
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
28401
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
28402
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
28403
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
28404
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
28405
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
28406
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
28407
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
28408
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
28409
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
28410
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
28411
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
28412
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
28413
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
28414
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
28415
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
28416
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
28417
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
28418
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
28419
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
28420
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
28421
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
28422
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
28423
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
28424
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
28425
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
28426
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
28427
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
28428
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
28429
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
28430
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
28431
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
28432
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
28433
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
28434
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
28435
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
28436
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
28437
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
28438
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
28439
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
28440
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
28441
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
28442
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
28443
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
28444
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
28445
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
28446
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
28447
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
28448
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
28449
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
28450
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
28451
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
28452
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
28453
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
28454
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
28455
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
28456
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
28457
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
28458
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
28459
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
28460
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
28461
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
28462
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
28463
+ })(CharacterCodes || (CharacterCodes = {}));
28464
+
28465
+ // node_modules/jsonc-parser/lib/esm/impl/string-intern.js
28466
+ var cachedSpaces = new Array(20).fill(0).map((_2, index) => {
28467
+ return " ".repeat(index);
28468
+ });
28469
+ var maxCachedValues = 200;
28470
+ var cachedBreakLinesWithSpaces = {
28471
+ " ": {
28472
+ "\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28473
+ return "\n" + " ".repeat(index);
28474
+ }),
28475
+ "\r": new Array(maxCachedValues).fill(0).map((_2, index) => {
28476
+ return "\r" + " ".repeat(index);
28477
+ }),
28478
+ "\r\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28479
+ return "\r\n" + " ".repeat(index);
28480
+ })
28481
+ },
28482
+ " ": {
28483
+ "\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28484
+ return "\n" + " ".repeat(index);
28485
+ }),
28486
+ "\r": new Array(maxCachedValues).fill(0).map((_2, index) => {
28487
+ return "\r" + " ".repeat(index);
28488
+ }),
28489
+ "\r\n": new Array(maxCachedValues).fill(0).map((_2, index) => {
28490
+ return "\r\n" + " ".repeat(index);
28491
+ })
28492
+ }
28493
+ };
28494
+
28495
+ // node_modules/jsonc-parser/lib/esm/impl/parser.js
28496
+ var ParseOptions;
28497
+ (function(ParseOptions2) {
28498
+ ParseOptions2.DEFAULT = {
28499
+ allowTrailingComma: false
28500
+ };
28501
+ })(ParseOptions || (ParseOptions = {}));
28502
+
28503
+ // node_modules/jsonc-parser/lib/esm/main.js
28504
+ var ScanError;
28505
+ (function(ScanError2) {
28506
+ ScanError2[ScanError2["None"] = 0] = "None";
28507
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
28508
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
28509
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
28510
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
28511
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
28512
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
28513
+ })(ScanError || (ScanError = {}));
28514
+ var SyntaxKind;
28515
+ (function(SyntaxKind2) {
28516
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
28517
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
28518
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
28519
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
28520
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
28521
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
28522
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
28523
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
28524
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
28525
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
28526
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
28527
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
28528
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
28529
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
28530
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
28531
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
28532
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
28533
+ })(SyntaxKind || (SyntaxKind = {}));
28534
+ var ParseErrorCode;
28535
+ (function(ParseErrorCode2) {
28536
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
28537
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
28538
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
28539
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
28540
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
28541
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
28542
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
28543
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
28544
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
28545
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
28546
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
28547
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
28548
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
28549
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
28550
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
28551
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
28552
+ })(ParseErrorCode || (ParseErrorCode = {}));
28553
+
28554
+ // src/guest/toolchains/vscode.ts
27847
28555
  var VERSION_MARKER = ".agent-sandbox-version";
27848
28556
  var desktopShortcut = (exe) => {
27849
28557
  if (!isWin) return;
27850
- const link = path42.join(os5.homedir(), "Desktop", "Visual Studio Code.lnk");
28558
+ const link = path43.join(os7.homedir(), "Desktop", "Visual Studio Code.lnk");
27851
28559
  const q = (s) => "'" + s.replace(/'/g, "''") + "'";
27852
28560
  powershell("$s = (New-Object -ComObject WScript.Shell).CreateShortcut(" + q(link) + "); $s.TargetPath = " + q(exe) + "; $s.Arguments = " + q('"' + (process.env.AGENT_WORKSPACE ?? "") + '"') + "; $s.Save()");
27853
28561
  };
27854
28562
  var setupVscode = async (env, refresh) => {
27855
28563
  const root = tool("vscode");
27856
- const exe = path42.join(root, "Code.exe");
28564
+ const exe = path43.join(root, "Code.exe");
27857
28565
  if (dryRun) {
27858
28566
  log("(dry run) would provision VS Code");
27859
28567
  return;
@@ -27861,27 +28569,27 @@ var setupVscode = async (env, refresh) => {
27861
28569
  if (!exists(exe) || refresh) {
27862
28570
  const release = await fetchJson("https://update.code.visualstudio.com/api/update/win32-" + (arch === "arm64" ? "arm64" : "x64") + "-archive/stable/latest");
27863
28571
  log("Downloading VS Code " + release.productVersion + " (~150 MB once) ...");
27864
- const keep = path42.join(root, "data");
28572
+ const keep = path43.join(root, "data");
27865
28573
  const parked = root + "-data";
27866
28574
  if (exists(keep)) {
27867
- fs29.rmSync(parked, { recursive: true, force: true });
27868
- fs29.renameSync(keep, parked);
28575
+ fs30.rmSync(parked, { recursive: true, force: true });
28576
+ fs30.renameSync(keep, parked);
27869
28577
  }
27870
28578
  try {
27871
28579
  await installArchive(release.url, root, { sha256: release.sha256hash, locate: "Code.exe", fileName: "vscode.zip" });
27872
- fs29.writeFileSync(path42.join(root, VERSION_MARKER), release.productVersion);
28580
+ fs30.writeFileSync(path43.join(root, VERSION_MARKER), release.productVersion);
27873
28581
  } finally {
27874
28582
  if (exists(parked)) {
27875
28583
  mkdirp(root);
27876
- fs29.rmSync(keep, { recursive: true, force: true });
27877
- fs29.renameSync(parked, keep);
28584
+ fs30.rmSync(keep, { recursive: true, force: true });
28585
+ fs30.renameSync(parked, keep);
27878
28586
  }
27879
28587
  }
27880
28588
  }
27881
- mkdirp(path42.join(root, "data"));
27882
- env.prepend.push(path42.join(root, "bin"));
28589
+ mkdirp(path43.join(root, "data"));
28590
+ env.prepend.push(path43.join(root, "bin"));
27883
28591
  desktopShortcut(exe);
27884
- const version2 = exists(path42.join(root, VERSION_MARKER)) ? fs29.readFileSync(path42.join(root, VERSION_MARKER), "utf8").trim() : "installed";
28592
+ const version2 = exists(path43.join(root, VERSION_MARKER)) ? fs30.readFileSync(path43.join(root, VERSION_MARKER), "utf8").trim() : "installed";
27885
28593
  env.summary.push("vscode: " + version2 + " (portable; run code . or use the desktop shortcut)");
27886
28594
  };
27887
28595
 
@@ -27892,14 +28600,34 @@ var setupPythonTools = async (env, tools) => {
27892
28600
  await installOnce(env, "uv tool", tools, (pkg) => execAsync(uv, ["tool", "install", pkg], { env: { ...process.env, ...uvVars() } }));
27893
28601
  };
27894
28602
  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");
28603
+ if (targetDir === "shared" || targetDir === "separate") return null;
28604
+ if (targetDir === "local") return path44.join(localDir, "cargo-target");
27898
28605
  return targetDir;
27899
28606
  };
28607
+ var cargoShim = (env, rust) => {
28608
+ const real = path44.join(tool("rust", "cargo", "bin"), "cargo.exe");
28609
+ if (rust.targetDir !== "separate" || !exists(real)) return;
28610
+ const dir = mkdirp(tool("shims", "cargo"));
28611
+ fs31.copyFileSync(ensureCompiled("cargoshim"), path44.join(dir, "cargo.exe"));
28612
+ env.prepend.unshift(dir);
28613
+ env.vars.AGENT_REAL_CARGO = real;
28614
+ };
28615
+ var cargoDefaults = (host) => {
28616
+ const file3 = tool("rust", "cargo", "config.toml");
28617
+ if (exists(file3) || !exists(path44.dirname(file3))) return;
28618
+ const jobs = Math.max(2, Math.min(4, Math.floor(os8.cpus().length / 4)));
28619
+ const gnu = host.endsWith("-gnu");
28620
+ fs31.writeFileSync(file3, [
28621
+ "# Written by windows-development-sandbox once; edit freely, it is never overwritten.",
28622
+ "[build]",
28623
+ "jobs = " + jobs,
28624
+ "",
28625
+ ...gnu ? ["[profile.dev]", 'debug = "line-tables-only"', "", "[profile.test]", 'debug = "line-tables-only"', ""] : []
28626
+ ].join("\n"));
28627
+ };
27900
28628
  var rustCaches = (rust) => {
27901
28629
  const target = cargoTarget(rust.targetDir);
27902
- return { ...target ? { CARGO_TARGET_DIR: target } : {}, ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path43.join(dataDir, "cache", "sccache") } };
28630
+ return { ...target ? { CARGO_TARGET_DIR: target } : {}, ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path44.join(dataDir, "cache", "sccache") } };
27903
28631
  };
27904
28632
  var rustHost = (config2) => {
27905
28633
  if (config2.rust.host !== "auto") return config2.rust.host;
@@ -27907,6 +28635,7 @@ var rustHost = (config2) => {
27907
28635
  return cpu + (wanted(config2.msvc.enabled, "msvc") ? "-pc-windows-msvc" : "-pc-windows-gnu");
27908
28636
  };
27909
28637
  var plan = (config2, versions, o) => {
28638
+ const apps = Boolean(o.apps && (o.apps.install.length || Object.keys(o.apps.custom).length));
27910
28639
  const java = wanted(config2.java.enabled, "java");
27911
28640
  const python = wanted(config2.python.enabled, "python");
27912
28641
  return [
@@ -27926,6 +28655,10 @@ var plan = (config2, versions, o) => {
27926
28655
  run: async (env) => {
27927
28656
  await setupRust(env, { ...config2.rust, host: rustHost(config2) }, o.refresh);
27928
28657
  Object.assign(env.vars, rustCaches(config2.rust));
28658
+ if (!dryRun) {
28659
+ cargoDefaults(rustHost(config2));
28660
+ cargoShim(env, config2.rust);
28661
+ }
27929
28662
  }
27930
28663
  },
27931
28664
  { name: ".NET", on: wanted(config2.dotnet.enabled, "dotnet"), run: (env) => setupDotnet(env, config2.dotnet, o.refresh) },
@@ -27933,7 +28666,8 @@ var plan = (config2, versions, o) => {
27933
28666
  { name: "Java", on: java, run: (env) => setupJava(env, config2.java) },
27934
28667
  { name: "Ruby", on: wanted(config2.ruby.enabled, "ruby"), run: (env) => setupRuby(env, config2.ruby) },
27935
28668
  // 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) => {
28669
+ // Many apps (bat, delta, Neovim, most GUIs, your own programs) are built against it too.
28670
+ { name: "Visual C++ runtime", on: config2.vcRuntime.enabled || apps, shared: true, run: async (env) => {
27937
28671
  await setupVcRuntime(env);
27938
28672
  } },
27939
28673
  { name: "PHP", on: wanted(config2.php.enabled, "php"), after: ["Visual C++ runtime"], run: (env) => setupPhp(env, config2.php) },
@@ -27943,8 +28677,10 @@ var plan = (config2, versions, o) => {
27943
28677
  { name: "PowerShell 7", on: wanted(config2.pwsh.enabled, "pwsh"), run: (env) => setupPwsh(env, o.refresh) },
27944
28678
  // The openssl tool comes from Git's install: after Git.
27945
28679
  { 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) },
28680
+ { name: "Mesa 3D", on: config2.mesa.enabled || appsNeedMesa(o.apps), shared: true, run: (env) => setupMesa(env, config2.mesa) },
27947
28681
  { name: "VS Code", on: config2.vscode.enabled, shared: true, run: (env) => setupVscode(env, o.refresh) },
28682
+ // Desktop apps and extra tools (apps.install / apps.custom); games and 3D apps copy Mesa's OpenGL next to them.
28683
+ { 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
28684
  { name: "Python tools", on: python && config2.python.tools.length > 0, after: ["Python", "uv"], run: (env) => setupPythonTools(env, config2.python.tools) },
27949
28685
  // DynamoDB Local runs on Java: the Java step installs the JDK first instead of racing it.
27950
28686
  // One server per database in the sandbox: a project that joins later shares the one the boot started.
@@ -27953,7 +28689,8 @@ var plan = (config2, versions, o) => {
27953
28689
  };
27954
28690
 
27955
28691
  // src/guest/toolchains/index.ts
27956
- var PARALLEL = 4;
28692
+ var PARALLEL2 = 4;
28693
+ var currentStep = new AsyncLocalStorage2();
27957
28694
  var locks = /* @__PURE__ */ new Map();
27958
28695
  var lockKey = (name) => name.split(" ")[0].toLowerCase();
27959
28696
  var exclusive = async (name, work) => {
@@ -27979,10 +28716,19 @@ var runSteps = async (steps, o) => {
27979
28716
  const running = /* @__PURE__ */ new Set();
27980
28717
  const waiting = [];
27981
28718
  let done = 0;
27982
- const say = o.report ?? ((message) => setSandboxStatus("provisioning", message));
28719
+ const percent = /* @__PURE__ */ new Map();
28720
+ const active = () => [...running].map((name) => ({ name, ...percent.has(name) ? { percent: percent.get(name) } : {} }));
28721
+ const say = o.report ?? ((message) => setSandboxStatus("provisioning", message, { active: active(), done, total: steps.length }));
27983
28722
  const report = () => {
27984
28723
  if (running.size) say("Installing " + [...running].join(", ") + " (" + done + " of " + steps.length + " done)");
27985
28724
  };
28725
+ if (!o.report) watchDownloads(() => {
28726
+ const name = currentStep.getStore();
28727
+ return name ? (fraction) => {
28728
+ percent.set(name, Math.round(fraction * 100));
28729
+ report();
28730
+ } : null;
28731
+ });
27986
28732
  for (const s of steps) {
27987
28733
  finished.set(s.name, (async () => {
27988
28734
  await Promise.all((s.after ?? []).map((name) => finished.get(name)));
@@ -27992,20 +28738,26 @@ var runSteps = async (steps, o) => {
27992
28738
  done++;
27993
28739
  return;
27994
28740
  }
27995
- while (running.size >= PARALLEL) await new Promise((r) => waiting.push(r));
28741
+ while (running.size >= PARALLEL2) await new Promise((r) => waiting.push(r));
27996
28742
  running.add(s.name);
27997
28743
  report();
27998
28744
  try {
27999
- await exclusive(s.name, () => step(s.name, envs.get(s.name), async () => s.run(envs.get(s.name))));
28745
+ await currentStep.run(s.name, () => exclusive(s.name, () => step(s.name, envs.get(s.name), async () => s.run(envs.get(s.name)))));
28000
28746
  } finally {
28001
28747
  running.delete(s.name);
28748
+ percent.delete(s.name);
28002
28749
  done++;
28003
28750
  report();
28004
28751
  waiting.shift()?.();
28005
28752
  }
28006
28753
  })());
28007
28754
  }
28008
- await Promise.all(finished.values());
28755
+ try {
28756
+ await Promise.all(finished.values());
28757
+ } finally {
28758
+ if (!o.report) watchDownloads(null);
28759
+ }
28760
+ if (!o.report) setSandboxStatus("provisioning", "Set up " + steps.length + " toolchains and databases", { active: [], done, total: steps.length });
28009
28761
  return envs;
28010
28762
  };
28011
28763
  var setupToolchains = async (config2, versions, options, run2 = {}) => {
@@ -28031,14 +28783,14 @@ var provisionedFor = (cwd) => [...ready.values()].filter((p) => isWithin(p.spec.
28031
28783
  var provisionedProjects = () => [...ready.values()];
28032
28784
  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
28785
  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""',
28786
+ const dir = mkdirp(path45.join(localDir, "projects", spec.name));
28787
+ fs32.writeFileSync(path45.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
28788
+ fs32.writeFileSync(path45.join(dir, "shell.cmd"), ['@call "' + path45.join(dir, "env.cmd") + '"', '@cd /d "' + spec.workspace + '"', "@title " + spec.name, ""].join("\r\n"));
28789
+ const bin = mkdirp(path45.join(localDir, "bin"));
28790
+ fs32.writeFileSync(path45.join(bin, "sbx-shell.cmd"), [
28791
+ '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path45.join(localDir, "projects") + '" & exit /b 2)',
28792
+ '@if not exist "' + path45.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
28793
+ '@cmd /k ""' + path45.join(localDir, "projects") + '\\%~1\\shell.cmd""',
28042
28794
  ""
28043
28795
  ].join("\r\n"));
28044
28796
  };
@@ -28077,10 +28829,10 @@ var provision = async (spec, say) => {
28077
28829
  saveProjectStatus(spec.name, spec.workspace, "provisioning", m, spec.databases, []);
28078
28830
  say(m);
28079
28831
  }, reuse: boot?.steps }));
28080
- tools.prepend.push(path44.join(localDir, "bin"));
28832
+ tools.prepend.push(path45.join(localDir, "bin"));
28081
28833
  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));
28834
+ const specFile = path45.join(mkdirp(path45.join(localDir, "projects", spec.name)), "project.json");
28835
+ fs32.writeFileSync(specFile, JSON.stringify(spec));
28084
28836
  env.AGENT_PROJECT_FILE = specFile;
28085
28837
  addMachineEnvironment(tools.vars, [...tools.prepend, ...tools.append], true);
28086
28838
  try {
@@ -28154,14 +28906,83 @@ var execCommand = (req) => {
28154
28906
  });
28155
28907
  };
28156
28908
 
28909
+ // src/guest/daemon/relays.ts
28910
+ import net2 from "node:net";
28911
+
28912
+ // src/shared/netpolicy.ts
28913
+ var relayPort = (index) => 38100 + index;
28914
+
28915
+ // src/guest/daemon/relays.ts
28916
+ var startRelays = () => {
28917
+ (session.network.forwardPorts ?? []).forEach((f, i) => {
28918
+ const server = net2.createServer((client) => {
28919
+ const target = net2.connect(f.sandbox, "127.0.0.1");
28920
+ client.pipe(target).pipe(client);
28921
+ target.on("error", () => client.destroy());
28922
+ client.on("error", () => target.destroy());
28923
+ });
28924
+ server.on("error", (e) => warn("Port forward " + f.pc + " -> " + f.sandbox + " could not start: " + errMsg(e)));
28925
+ server.listen(relayPort(i), "0.0.0.0", () => log("Port forward: the PC's localhost:" + f.pc + " reaches localhost:" + f.sandbox + " here."));
28926
+ });
28927
+ };
28928
+
28929
+ // src/guest/audit.ts
28930
+ import fs33 from "node:fs";
28931
+ import path47 from "node:path";
28932
+ import { spawnSync as spawnSync4 } from "node:child_process";
28933
+
28934
+ // src/guest/audit-parse.ts
28935
+ import path46 from "node:path";
28936
+ 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"]);
28937
+ var decode3 = (s) => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
28938
+ var field = (event, name) => decode3(new RegExp("<Data Name='" + name + "'>([^<]*)</Data>").exec(event)?.[1] ?? "");
28939
+ var parseProcessEvents = (xml) => {
28940
+ const lines = [];
28941
+ let last = 0;
28942
+ for (const event of xml.split("</Event>")) {
28943
+ const id = Number(/<EventRecordID>(\d+)<\/EventRecordID>/.exec(event)?.[1] ?? 0);
28944
+ if (!id) continue;
28945
+ last = Math.max(last, id);
28946
+ const program = field(event, "NewProcessName");
28947
+ if (!program || NOISE.has(path46.win32.basename(program).toLowerCase())) continue;
28948
+ const t = /SystemTime='([^']+)'/.exec(event)?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
28949
+ 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) }));
28950
+ }
28951
+ return { lines, last };
28952
+ };
28953
+
28954
+ // src/guest/audit.ts
28955
+ var MAX_PER_PASS = 2e3;
28956
+ var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
28957
+ var wevtutil = () => path47.join(process.env.WINDIR ?? "C:\\Windows", "System32", "wevtutil.exe");
28958
+ var newestRecord = () => {
28959
+ const r = spawnSync4(wevtutil(), ["qe", "Security", "/q:*[System[(EventID=4688)]]", "/f:xml", "/c:1", "/rd:true"], { encoding: "utf8", windowsHide: true });
28960
+ return parseProcessEvents(r.stdout ?? "").last;
28961
+ };
28962
+ var startProcessCollector = () => {
28963
+ if (!auditOn()) return;
28964
+ let last = newestRecord();
28965
+ const pass = () => {
28966
+ try {
28967
+ 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 });
28968
+ const { lines, last: newest } = parseProcessEvents(r.stdout ?? "");
28969
+ if (newest) last = newest;
28970
+ if (lines.length) fs33.writeFileSync(path47.join(mkdirp(run.audit), Date.now() + "-" + process.pid + ".jsonl"), lines.join("\n") + "\n");
28971
+ } catch (e) {
28972
+ warn("audit: " + errMsg(e));
28973
+ }
28974
+ };
28975
+ setInterval(pass, 15e3).unref?.();
28976
+ };
28977
+
28157
28978
  // src/guest/daemon/session.ts
28158
- import path48 from "node:path";
28979
+ import path52 from "node:path";
28159
28980
  import crypto3 from "node:crypto";
28160
28981
  import { spawn as spawn7 } from "node:child_process";
28161
28982
 
28162
28983
  // 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 };
28984
+ import net3 from "node:net";
28985
+ 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
28986
  var HelloFlag = { ControlOnly: 1, Query: 2 };
28166
28987
  var encodeFrame = (type, payload = Buffer.alloc(0)) => {
28167
28988
  const header = Buffer.alloc(5);
@@ -28178,8 +28999,8 @@ var helloFrame = (token, cols, rows, flags = 0) => {
28178
28999
  };
28179
29000
  var MAX_FRAME_BYTES = 1 << 20;
28180
29001
  var connectOnce = (host, port, timeoutMs) => {
28181
- return new Promise((resolve, reject) => {
28182
- const socket = net2.connect({ host, port });
29002
+ return new Promise((resolve2, reject) => {
29003
+ const socket = net3.connect({ host, port });
28183
29004
  const timer = setTimeout(() => {
28184
29005
  socket.destroy();
28185
29006
  reject(new Error("timed out connecting to " + host + ":" + port));
@@ -28187,7 +29008,7 @@ var connectOnce = (host, port, timeoutMs) => {
28187
29008
  socket.once("connect", () => {
28188
29009
  clearTimeout(timer);
28189
29010
  socket.setNoDelay(true);
28190
- resolve(socket);
29011
+ resolve2(socket);
28191
29012
  });
28192
29013
  socket.once("error", (e) => {
28193
29014
  clearTimeout(timer);
@@ -28208,11 +29029,11 @@ var connect = async (endpoint, timeoutMs = 3e3) => {
28208
29029
  };
28209
29030
  var sendControl = async (endpoint, type) => {
28210
29031
  const socket = await connect(endpoint);
28211
- await new Promise((resolve) => socket.end(Buffer.concat([helloFrame(endpoint.token, 80, 24, HelloFlag.ControlOnly), encodeFrame(type)]), resolve));
29032
+ await new Promise((resolve2) => socket.end(Buffer.concat([helloFrame(endpoint.token, 80, 24, HelloFlag.ControlOnly), encodeFrame(type)]), resolve2));
28212
29033
  };
28213
29034
 
28214
29035
  // src/guest/cmdline.ts
28215
- import path45 from "node:path";
29036
+ import path48 from "node:path";
28216
29037
  var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
28217
29038
  var quoteArg = (arg) => arg !== "" && !/[\s"]/.test(arg) ? arg : quoted(arg);
28218
29039
  var cmdArgs = (args) => {
@@ -28223,11 +29044,11 @@ var cmdArgs = (args) => {
28223
29044
  return !inQuotes && /[&|<>^]/.test(c) ? "^^^" + c : c;
28224
29045
  }).join("");
28225
29046
  };
28226
- var commandLine = (file3, args) => path45.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
29047
+ var commandLine = (file3, args) => path48.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
28227
29048
 
28228
29049
  // src/guest/ptyhost.ts
28229
- import fs31 from "node:fs";
28230
- import path46 from "node:path";
29050
+ import fs34 from "node:fs";
29051
+ import path49 from "node:path";
28231
29052
  import { spawn as spawn6 } from "node:child_process";
28232
29053
  var ensurePtyHost = () => ensureCompiled("ptyhost");
28233
29054
  var waitForPtyHost = async (child, port, timeoutMs) => {
@@ -28243,33 +29064,37 @@ var waitForPtyHost = async (child, port, timeoutMs) => {
28243
29064
  }
28244
29065
  throw new Error("the session host did not start listening on port " + port);
28245
29066
  };
28246
- var ptyHostLog = (id) => path46.join(logsDir, "ptyhost-" + id + ".log");
29067
+ var ptyHostLog = (id) => path49.join(logsDir, "ptyhost-" + id + ".log");
28247
29068
  var ptyHostLogTail = (id, lines = 12) => {
28248
29069
  try {
28249
- return fs31.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
29070
+ return fs34.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
28250
29071
  } catch {
28251
29072
  return "";
28252
29073
  }
28253
29074
  };
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
- });
29075
+ var conptyDll = () => {
29076
+ const dll = path49.join(toolsDir, "conpty", "conpty.dll");
29077
+ return session.provisioning.conpty?.enabled !== false && fs34.existsSync(dll) && fs34.existsSync(path49.join(toolsDir, "conpty", "OpenConsole.exe")) ? dll : null;
29078
+ };
29079
+ var startPtyHost = (o) => {
29080
+ const env = { ...o.env, PTYHOST_BIND: o.remote ? "any" : "loopback" };
29081
+ delete env.PTYHOST_CONPTY;
29082
+ const dll = conptyDll();
29083
+ if (dll) env.PTYHOST_CONPTY = dll;
29084
+ 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 });
29085
+ };
28261
29086
 
28262
29087
  // src/guest/setup/agents.ts
28263
- import fs32 from "node:fs";
28264
- import path47 from "node:path";
29088
+ import fs35 from "node:fs";
29089
+ import path50 from "node:path";
28265
29090
  var harnessPaths = (name, harness) => {
28266
- const dir = path47.join(toolsDir, "agents", name);
29091
+ const dir = path50.join(toolsDir, "agents", name);
28267
29092
  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 };
29093
+ return { dir, exe: exe ? path50.join(dir, exe) : null, cmd: harness.npmBin ? path50.join(dir, harness.npmBin + ".cmd") : null };
28269
29094
  };
28270
29095
  var installViaNpm = async (name, harness, dir, env) => {
28271
29096
  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");
29097
+ const npmCli = path50.join(path50.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28273
29098
  const args = [npmCli, "install", "--global", "--prefix", dir, harness.npmPackage, "--no-fund", "--no-audit"];
28274
29099
  log("Installing " + harness.npmPackage + " (this can take a minute)...");
28275
29100
  if (dryRun) {
@@ -28280,7 +29105,7 @@ var installViaNpm = async (name, harness, dir, env) => {
28280
29105
  await execAsync(process.execPath, args, { env });
28281
29106
  };
28282
29107
  var installViaUv = async (name, harness, dir, env) => {
28283
- const uv = path47.join(toolsDir, "uv", "uv.exe");
29108
+ const uv = path50.join(toolsDir, "uv", "uv.exe");
28284
29109
  log("Installing " + harness.uvPackage + " with uv (this can take a minute)...");
28285
29110
  if (dryRun) {
28286
29111
  log("(dry run) uv tool install " + harness.uvPackage);
@@ -28306,9 +29131,9 @@ var installHarness = async (name, harness, env, refresh) => {
28306
29131
  }
28307
29132
  mkdirp(p.dir);
28308
29133
  if (session.provisioning.copyFromHost && harness.hostExecutable && name === session.harnessName) {
28309
- const source = path47.join(hostToolsDir, "agents", name, harness.hostExecutable);
29134
+ const source = path50.join(hostToolsDir, "agents", name, harness.hostExecutable);
28310
29135
  if (exists(source) && p.exe) {
28311
- fs32.copyFileSync(source, p.exe);
29136
+ fs35.copyFileSync(source, p.exe);
28312
29137
  log("Copied " + name + " from this PC: " + source);
28313
29138
  return;
28314
29139
  }
@@ -28327,11 +29152,13 @@ var resolveLaunch = (name, harness) => {
28327
29152
  };
28328
29153
 
28329
29154
  // 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);
29155
+ import os9 from "node:os";
29156
+ import path51 from "node:path";
29157
+ var HOSTS_FILE = path51.join(process.env.WINDIR ?? "C:\\Windows", "System32", "drivers", "etc", "hosts");
29158
+ var guestAddresses = () => Object.values(os9.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address);
28332
29159
 
28333
29160
  // src/guest/daemon/shutdown.ts
28334
- import { spawnSync as spawnSync4 } from "node:child_process";
29161
+ import { spawnSync as spawnSync5 } from "node:child_process";
28335
29162
  var maybeShutdown = () => {
28336
29163
  if (!session.headless || !isWin) return;
28337
29164
  const idle = () => live.size === 0 && pending.starting === 0 && scanRequests(dataDir).valid.length === 0;
@@ -28340,14 +29167,14 @@ var maybeShutdown = () => {
28340
29167
  if (!idle()) return;
28341
29168
  log("Headless sandbox has no sessions left; shutting down.");
28342
29169
  safely("claude-mem save", saveClaudeMem);
28343
- spawnSync4(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
29170
+ spawnSync5(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
28344
29171
  }, 15e3);
28345
29172
  };
28346
29173
 
28347
29174
  // src/guest/daemon/session.ts
28348
29175
  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");
29176
+ const view = [process.execPath, path52.join(path52.dirname(process.argv[1]), "view.js"), id];
29177
+ const wt = path52.join(toolsDir, "terminal", "wt.exe");
28351
29178
  if (exists(wt)) spawn7(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
28352
29179
  else spawn7(SYSTEM.cmd(), ["/d", "/c", "start", title, ...view], { detached: true, stdio: "ignore", cwd }).unref();
28353
29180
  };
@@ -28392,7 +29219,7 @@ var launchPtyHost = async (req, remote, env, say) => {
28392
29219
  await waitForPtyHost(child, port, 15e3);
28393
29220
  } catch (e) {
28394
29221
  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"));
29222
+ throw new Error(errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path52.join(dataDir, "logs", "ptyhost-" + req.id + ".log"));
28396
29223
  }
28397
29224
  return { child, port, token };
28398
29225
  };
@@ -28414,7 +29241,7 @@ var startSession = async (req) => {
28414
29241
  saveStatus(status);
28415
29242
  };
28416
29243
  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));
29244
+ 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
29245
  try {
28419
29246
  const place = await placeFor(req, say);
28420
29247
  const remote = session.networking && session.attach.enabled;
@@ -28470,9 +29297,9 @@ var handle = (req) => {
28470
29297
  };
28471
29298
  var tick = () => {
28472
29299
  const { valid, invalid } = scanRequests(dataDir);
28473
- for (const file3 of invalid) safely("removing an invalid request", () => fs33.rmSync(file3, { recursive: true, force: true }));
29300
+ for (const file3 of invalid) safely("removing an invalid request", () => fs36.rmSync(file3, { recursive: true, force: true }));
28474
29301
  for (const req of valid) {
28475
- safely("claiming a request", () => fs33.rmSync(run.request(req.id), { force: true }));
29302
+ safely("claiming a request", () => fs36.rmSync(run.request(req.id), { force: true }));
28476
29303
  if (readSession(dataDir, req.id)) continue;
28477
29304
  void Promise.resolve(handle(req)).catch((e) => respond(req.id, { ok: false, message: errMsg(e) }));
28478
29305
  }
@@ -28491,4 +29318,6 @@ var loop = () => {
28491
29318
  }
28492
29319
  };
28493
29320
  log("Session daemon started (pid " + process.pid + ").");
29321
+ safely("port forwards", startRelays);
29322
+ safely("audit", startProcessCollector);
28494
29323
  loop();